Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1256353
  • 博文数量: 160
  • 博客积分: 4132
  • 博客等级: 中校
  • 技术积分: 2086
  • 用 户 组: 普通用户
  • 注册时间: 2010-11-06 21:56
文章分类

全部博文(160)

文章存档

2012年(25)

2011年(120)

2010年(15)

分类: LINUX

2011-08-23 21:20:26



转自:
清悠我心:%E6%B8%85%E6%82%A0%E6%88%91%E5%BF%83/home)
mini2440_buttons.c
  1. #include <linux/module.h>

  2. #include <linux/kernel.h>

  3. #include <linux/fs.h>

  4. #include <linux/init.h>

  5. #include <linux/delay.h>

  6. #include <linux/poll.h>

  7. #include <linux/irq.h>

  8. #include <asm/irq.h>

  9. #include <linux/interrupt.h>

  10. #include <asm/uaccess.h>

  11. #include <mach/regs-gpio.h>

  12. #include <mach/hardware.h>

  13. #include <linux/platform_device.h>

  14. #include <linux/cdev.h>

  15. #include <linux/miscdevice.h>

  16. #include <linux/sched.h>

  17. #include <linux/gpio.h>

  18. #define DEVICE_NAME "buttons" //设备名称

  19.  

  20. /*定义中断所用的结构体*/

  21. struct button_irq_desc

  22.  {

  23. int irq; //按键对应的中断号

  24. int pin; //按键所对应的GPIO 端口

  25. int pin_setting; //按键对应的引脚描述,实际并未用到,保留

  26. int number; //定义键值,以传递给应用层/用户态

  27. char *name; //每个按键的名称

  28. };

  29.  

  30. /*结构体实体定义*/

  31. static struct button_irq_desc button_irqs [] =

  32. {

  33. {IRQ_EINT8 , S3C2410_GPG(0) , S3C2410_GPG0_EINT8 , 0, "KEY0"},

  34. {IRQ_EINT11, S3C2410_GPG(3) , S3C2410_GPG3_EINT11 , 1, "KEY1"},

  35. {IRQ_EINT13, S3C2410_GPG(5) , S3C2410_GPG5_EINT13 , 2, "KEY2"},

  36. {IRQ_EINT14, S3C2410_GPG(6) , S3C2410_GPG6_EINT14 , 3, "KEY3"},

  37. {IRQ_EINT15, S3C2410_GPG(7) , S3C2410_GPG7_EINT15 , 4, "KEY4"},

  38. {IRQ_EINT19, S3C2410_GPG(11), S3C2410_GPG11_EINT19, 5, "KEY5"},

  39. };

  40. /*开发板上按键的状态变量,注意这里是’0’,对应的ASCII 码为30*/

  41.  

  42.  

  43. static volatile char key_values [] = {'0', '0', '0', '0', '0', '0'};

  44. /*因为本驱动是基于中断方式的,在此创建一个等待队列,以配合中断函数使用;当有按键按下并读取到键值时,将会唤醒此队列,并设置中断标志,以便能通过 read 函数判断和读取键值传递到用户态;当没有按键按下时,系统并不*/

  45. /*会轮询按键状态,以节省时钟资源*/

  46. static DECLARE_WAIT_QUEUE_HEAD(button_waitq);

  47. /*中断标识变量,配合上面的队列使用,中断服务程序会把它设置为1,read 函数会把它清零*/

  48. static volatile int ev_press = 0;

  49. /*本按键驱动的中断服务程序*/

  50.  

  51. static irqreturn_t buttons_interrupt(int irq, void *dev_id)

  52. {

  53. struct button_irq_desc *button_irqs = (struct button_irq_desc *)dev_id;

  54. int down;

  55. // udelay(0);

  56. /*获取被按下的按键状态*/

  57. down = !s3c2410_gpio_getpin(button_irqs->pin);

  58. /*状态改变,按键被按下,从这句可以看出,当按键没有被按下的时候,寄存器的值为1(上拉),但按键被按下的时候,寄存器对应的值为0*/

  59. if (down != (key_values[button_irqs->number] & 1)) { // Changed

  60. /*如果key1 被按下,则key_value[0]就变为’1’,对应的ASCII 码为31*/

  61. key_values[button_irqs->number] = '0' + down;

  62. ev_press = 1; /*设置中断标志为1*/

  63. wake_up_interruptible(&button_waitq); /*唤醒等待队列*/

  64.        }

  65.     return IRQ_RETVAL(IRQ_HANDLED);

  66. }

  67. /**在应用程序执行open(“/dev/buttons”,…)时会调用到此函数,在这里,它的作用主要是注册6 个按键的中断。

  68. *所用的中断类型是IRQ_TYPE_EDGE_BOTH,也就是双沿触发,在上升沿和下降沿均会产生中断,这样做

  69. **是为了更加有效地判断按键状态

  70. */

  71.  

  72. static int s3c24xx_buttons_open(struct inode *inode, struct file *file)

  73. {

  74. int i;

  75. int err = 0;

  76. for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++)

  77.         {

  78. if (button_irqs[i].irq < 0)

  79. {

  80.     continue;

  81. }

  82. /*注册中断函数*/

  83. err = request_irq(button_irqs[i].irq, buttons_interrupt, IRQ_TYPE_EDGE_BOTH,

  84. button_irqs[i].name, (void *)&button_irqs[i]);

  85. if (err)

  86. break;

  87. }

  88.       if (err)

  89.       {

  90. /*如果出错,释放已经注册的中断,并返回*/

  91. i--;

  92. for (; i >= 0; i--)

  93.        {

  94. if (button_irqs[i].irq < 0)

  95.                {

  96. continue;

  97.       }

  98. disable_irq(button_irqs[i].irq);

  99. free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);

  100. }

  101.       return -EBUSY;

  102.     }

  103. /*注册成功,则中断队列标记为1,表示可以通过read 读取*/

  104. ev_press = 1;

  105. /*正常返回*/

  106. return 0;

  107. }

  108. /*

  109. *此函数对应应用程序的系统调用close(fd)函数,在此,它的主要作用是当关闭设备时释放6 个按键的中断*处理函数

  110. */

  111. static int s3c24xx_buttons_close(struct inode *inode, struct file *file)

  112. {

  113. int i;

  114. for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++)

  115. {

  116. if (button_irqs[i].irq < 0)

  117. {

  118.       continue;

  119. }

  120. /*释放中断号,并注销中断处理函数*/

  121. free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);

  122. }

  123. return 0;

  124. }

  125. /*

  126. *对应应用程序的read(fd,…)函数,主要用来向用户空间传递键值

  127. */

  128. static int s3c24xx_buttons_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)

  129. {

  130. unsigned long err;

  131. if (!ev_press)

  132.          {

  133. if (filp->f_flags & O_NONBLOCK)

  134.            /*当中断标识为0 时,并且该设备是以非阻塞方式打开时,返回*/

  135. return -EAGAIN;

  136.      else

  137. /*当中断标识为0 时,并且该设备是以阻塞方式打开时,进入休眠状态,等待被唤醒*/

  138. wait_event_interruptible(button_waitq, ev_press);

  139. }

  140. /*把中断标识清零*/

  141. ev_press = 0;

  142. /*一组键值被传递到用户空间*/

  143. err = copy_to_user(buff, (const void *)key_values, min(sizeof(key_values), count));

  144.  

  145. return err ? -EFAULT : min(sizeof(key_values), count);

  146. }

  147. static unsigned int s3c24xx_buttons_poll( struct file *file, struct poll_table_struct *wait)

  148. {

  149. unsigned int mask = 0;

  150. /*把调用poll 或者select 的进程挂入队列,以便被驱动程序唤醒*/

  151. poll_wait(file, &button_waitq, wait);

  152. if (ev_press)

  153.      mask |= POLLIN | POLLRDNORM;

  154. return mask;

  155. }

  156. /*设备操作集*/

  157. static struct file_operations dev_fops = {

  158. .owner = THIS_MODULE,

  159. .open = s3c24xx_buttons_open,

  160. .release = s3c24xx_buttons_close,

  161. .read = s3c24xx_buttons_read,

  162. .poll = s3c24xx_buttons_poll,

  163. };

  164. static struct miscdevice misc = {

  165. .minor = MISC_DYNAMIC_MINOR,

  166. .name = DEVICE_NAME,

  167. .fops = &dev_fops,

  168. };

  169. /*设备初始化,主要是注册设备*/

  170. static int __init dev_init(void)

  171. {

  172. int ret;

  173. /*把按键设备注册为misc 设备,其设备号是自动分配的*/

  174. ret = misc_register(&misc);

  175. printk (DEVICE_NAME"\tinitialized\n");

  176. return ret;

  177.  

  178. }

  179. /*注销设备*/

  180. static void __exit dev_exit(void)

  181. {

  182. misc_deregister(&misc);

  183. }

  184. module_init(dev_init); //模块初始化,仅当使用insmod/podprobe 命令加载时有用,如果设备不是通过模块方式加载,此处将不会被调用

  185. module_exit(dev_exit); //卸载模块,当该设备通过模块方式加载后,可以通过rmmod 命令卸载,将调用此函数

  186. MODULE_LICENSE("GPL");//版权信息

  187. MODULE_AUTHOR("FriendlyARM Inc.");

将其编译进内核。

下面是测试应用程序btn-test.c:

  1. #include <stdio.h>

  2. #include <stdlib.h>

  3. #include <unistd.h>

  4. #include <sys/ioctl.h>

  5. #include <sys/types.h>

  6. #include <sys/stat.h>

  7. #include <fcntl.h>

  8. #include <sys/select.h>

  9. #include <sys/time.h>

  10. #include <errno.h>

  11. int main(void)

  12. {

  13. int buttons_fd;

  14. char buttons[6] = {'0', '0', '0', '0', '0', '0'}; //定义按键值变量,对于驱动函数中的key_values 数组

  15. /*打开按键设备/dev/buttons*/

  16. buttons_fd = open("/dev/buttons", 0);

  17. if (buttons_fd < 0)

  18. {

  19. /*打开失败则退出*/

  20. perror("open device buttons");

  21. exit(1);

  22. }

  23. /*永读按键并打印键值和状态*/

  24. for (;;)

  25. {

  26. char current_buttons[6];

  27. int count_of_changed_key;

  28. int i;

  29. /*使用read 函数读取一组按键值(6 个)*/

  30. if (read(buttons_fd, current_buttons, sizeof current_buttons) != sizeof current_buttons)

  31.        {

  32. perror("read buttons:");

  33. exit(1);

  34.        }

  35. /*逐个分析读取到的按键值*/

  36. for (i = 0, count_of_changed_key = 0; i < sizeof buttons / sizeof buttons[0]; i++) {

  37. if (buttons[i] != current_buttons[i])

  38.         {

  39. buttons[i] = current_buttons[i];

  40. /*打印按键值,并标明按键按下/抬起的状态*/

  41. printf("%skey %d is %s", count_of_changed_key? ", ": "", i+1, buttons[i] == '0' ? "up" :

  42. "down");

  43. count_of_changed_key++;

  44.        }

  45. }

  46. if (count_of_changed_key)

  47. {

  48.          printf("\n");

  49. }

  50. }

  51. /*关闭按键设备文件*/

  52. close(buttons_fd);

  53. return 0;

  54. }


在源代码所在的命令行输入命令:

#arm-linux-gcc –o btn-test btn-test.c

这样就生成了btn-test 可执行二进制文件,使用优盘或者网络工具( 比如ftp)把它复制到开发板中,并修改该文件的属性为可执行文件,然后运行它以测试,结果如图所示: 









阅读(1441) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~