matrix6_kbd_m6x6.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:5k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. #include <linux/config.h>
  2. #include <linux/module.h>
  3. #include <linux/kernel.h>
  4. #include <linux/init.h>
  5. #include <linux/miscdevice.h>
  6. #include <linux/sched.h>
  7. #include <linux/delay.h>
  8. #include <linux/poll.h>
  9. #include <linux/spinlock.h>
  10. #include <linux/irq.h>
  11. #include <linux/delay.h>
  12. #include <asm/hardware.h>
  13. #define DEVICE_NAME "kbd_m6x6"
  14. #define BUTTON_MAJOR 233
  15. static int irq_col_tab[] = { IRQ_EINT16, IRQ_EINT19, IRQ_EINT14, IRQ_EINT15, IRQ_EINT11, IRQ_EINT13 };
  16. #define COL_NUM ( (sizeof irq_col_tab) / sizeof (irq_col_tab[0]) )
  17. static unsigned gpio_col_tab[] = {GPIO_G8, GPIO_G11, GPIO_G6, GPIO_G7, GPIO_G3, GPIO_G5};
  18. static unsigned gpio_row_tab[] = { GPIO_B1, GPIO_B0, GPIO_F4, GPIO_F0, GPIO_F6, GPIO_F5 };
  19. #define ROW_NUM ( sizeof gpio_row_tab / sizeof (gpio_row_tab[0]) )
  20. static int ready = 0;
  21. static int key_value = 0, last_value = 0;
  22. static DECLARE_WAIT_QUEUE_HEAD(buttons_wait);
  23. static int waitting_down_tab[] = {1, 1, 1, 1, 1, 1};
  24. static void buttons_irq(int irq, void *dev_id, struct pt_regs *reg)
  25. {
  26. int i;
  27. int col_no = -1, row_no = -1;
  28. unsigned long flags;
  29. local_irq_save(flags);
  30. for (i = 0; i < COL_NUM; i++) {
  31. if (irq_col_tab[i] == irq) {
  32. col_no = i;
  33. break;
  34. }
  35. }
  36. if (col_no < 0) {
  37. goto EXIT;
  38. }
  39. if (waitting_down_tab[col_no]) {
  40. for (i = 0; i < COL_NUM; i++) {
  41. set_gpio_ctrl(gpio_col_tab[i] | GPIO_PULLUP_DIS | GPIO_MODE_IN);
  42. }
  43. udelay(300);
  44. for (i = 0; i < ROW_NUM; i++) {
  45. int r;
  46. write_gpio_bit(gpio_row_tab[i], 1);
  47. udelay(300);
  48. r = read_gpio_bit(gpio_col_tab[col_no]);
  49. write_gpio_bit(gpio_row_tab[i], 0);
  50. if (r) { // found
  51. row_no = i;
  52. break;
  53. }
  54. }
  55. udelay(300);
  56. for (i = 0; i < COL_NUM; i++) {
  57. set_gpio_ctrl(gpio_col_tab[i] | GPIO_PULLUP_DIS | GPIO_MODE_ALT0);
  58. }
  59. if (col_no < 0 || row_no < 0) {
  60. goto EXIT;
  61. }
  62. key_value = row_no * 6 + col_no + 1;
  63. } else {
  64. key_value = last_value | 0x80;
  65. }
  66. waitting_down_tab[col_no] = !waitting_down_tab[col_no];
  67. set_external_irq(irq, waitting_down_tab[col_no]? EXT_LOWLEVEL: EXT_HIGHLEVEL, GPIO_PULLUP_DIS);
  68. udelay(300);
  69. ready = 1;
  70. wake_up_interruptible(&buttons_wait);
  71. EXIT:
  72. restore_flags(flags);
  73. }
  74. static void buttons_io_port_init(void)
  75. {
  76. int i;
  77. for (i = 0; i < ROW_NUM; i ++) {
  78. unsigned gpio = gpio_row_tab[i];
  79. set_gpio_ctrl(gpio | GPIO_PULLUP_DIS | GPIO_MODE_OUT);
  80. write_gpio_bit(gpio, 0);
  81. }
  82. }
  83. static int matrix4_buttons_read(struct file * file, char * buffer, size_t count, loff_t *ppos)
  84. {
  85. static int key;
  86. int repeat = key == key_value;
  87. key == key_value;
  88.         if (!ready)
  89.                 return -EAGAIN;
  90.         if (count != sizeof key_value)
  91.                 return -EINVAL;
  92. if (repeat) {
  93. return -EAGAIN;
  94. }
  95.         copy_to_user(buffer, &key_value, sizeof key_value);
  96. last_value = key_value;
  97.         ready = 0;
  98.         return sizeof key_value;
  99. }
  100. static unsigned int matrix4_buttons_select(
  101.         struct file *file,
  102.         struct poll_table_struct *wait)
  103. {
  104.         if (ready)
  105.                 return 1;
  106.         poll_wait(file, &buttons_wait, wait);
  107.         return 0;
  108. }
  109. static int matrix4_buttons_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
  110. {
  111. switch(cmd) {
  112. default:
  113. return -EINVAL;
  114. }
  115. }
  116. static struct file_operations matrix4_buttons_fops = {
  117. owner: THIS_MODULE,
  118. ioctl:  matrix4_buttons_ioctl,
  119. poll: matrix4_buttons_select,
  120. read: matrix4_buttons_read,
  121. };
  122. static int request_irqs(void)
  123. {
  124. int i;
  125. for (i = 0; i < COL_NUM; i++) {
  126. int irq = irq_col_tab[i];
  127. int ret = request_irq(irq, &buttons_irq, SA_INTERRUPT, DEVICE_NAME, &buttons_irq);
  128. if (ret) {
  129. unregister_chrdev(BUTTON_MAJOR, DEVICE_NAME);
  130. printk(DEVICE_NAME " can't request irq %dn", irq);
  131. return ret;
  132. }
  133. }
  134. }
  135. static void free_irqs(void)
  136. {
  137. int i;
  138. for (i = 0; i < COL_NUM; i++) {
  139. int irq = irq_col_tab[i];
  140. free_irq(irq, buttons_irq);
  141. }
  142. }
  143. static devfs_handle_t devfs_handle;
  144. static int __init matrix4_buttons_init(void)
  145. {
  146. int ret;
  147. int i;
  148. ready = 0;
  149. ret = register_chrdev(BUTTON_MAJOR, DEVICE_NAME, &matrix4_buttons_fops);
  150. if (ret < 0) {
  151.   printk(DEVICE_NAME " can't register major numbern");
  152.   return ret;
  153. }
  154. buttons_io_port_init();
  155. for (i = 0; i < COL_NUM; i++) {
  156. int irq = irq_col_tab[i];
  157. set_external_irq(irq, EXT_LOWLEVEL, GPIO_PULLUP_DIS);
  158. }
  159. ret = request_irqs();
  160. if (ret) {
  161. return ret;
  162. }
  163. devfs_handle = devfs_register(NULL, DEVICE_NAME, DEVFS_FL_DEFAULT,
  164. BUTTON_MAJOR, 0, S_IFCHR | S_IRUSR | S_IWUSR, &matrix4_buttons_fops, NULL);
  165. return 0;
  166. }
  167. static void __exit matrix4_buttons_exit(void)
  168. {
  169. devfs_unregister(devfs_handle);
  170. free_irqs();
  171. unregister_chrdev(BUTTON_MAJOR, DEVICE_NAME);
  172. }
  173. module_init(matrix4_buttons_init);
  174. module_exit(matrix4_buttons_exit);
  175. MODULE_LICENSE("GPL");