简介

  1. 4.19.19

最近正在学习按键的驱动。除了

  • 轮询
  • 定时
  • poll机制
    • 这个机制其实和selet函数有关,关于select以前使用过,在IO多路复用或者检测字符设备文件有数据输入的时候。
    • select 最终也是调用的poll函数
  • 定时机制
  • 异步通知的方式

IO多路复用-select - IO多路复用的代码。我们使用slect输入了一串的fd。文件描述符。select会根据这些描述符调用其对应的poll函数。

  1. # include/linux/fs.h
  2. struct file_operations {
  3. __poll_t (*poll) (struct file *, struct poll_table_struct *);
  4. }
  5. typedef struct poll_table_struct {
  6. poll_queue_proc _qproc;
  7. __poll_t _key;
  8. } poll_table;

代码

  1. #include <linux/module.h>
  2. #include <linux/poll.h>
  3. #include <linux/fs.h>
  4. #include <linux/errno.h>
  5. #include <linux/miscdevice.h>
  6. #include <linux/kernel.h>
  7. #include <linux/major.h>
  8. #include <linux/mutex.h>
  9. #include <linux/proc_fs.h>
  10. #include <linux/seq_file.h>
  11. #include <linux/stat.h>
  12. #include <linux/init.h>
  13. #include <linux/device.h>
  14. #include <linux/tty.h>
  15. #include <linux/kmod.h>
  16. #include <linux/gfp.h>
  17. #include <linux/gpio/consumer.h>
  18. #include <linux/platform_device.h>
  19. #include <linux/of_gpio.h>
  20. #include <linux/of_irq.h>
  21. #include <linux/interrupt.h>
  22. #include <linux/irq.h>
  23. #include <linux/slab.h>
  24. struct gpio_key{
  25. int gpio;
  26. struct gpio_desc *gpiod;
  27. int flag;
  28. int irq;
  29. } ;
  30. static struct gpio_key *gpio_keys_array;
  31. /* 主设备号 */
  32. static int major = 0;
  33. static struct class *gpio_key_class;
  34. /* 环形缓冲区 */
  35. #define BUF_LEN 128
  36. static int g_keys[BUF_LEN];
  37. static int r, w;
  38. #define NEXT_POS(x) ((x+1) % BUF_LEN)
  39. static int is_key_buf_empty(void)
  40. {
  41. return (r == w);
  42. }
  43. static int is_key_buf_full(void)
  44. {
  45. return (r == NEXT_POS(w));
  46. }
  47. static void put_key(int key)
  48. {
  49. if (!is_key_buf_full())
  50. {
  51. g_keys[w] = key;
  52. w = NEXT_POS(w);
  53. }
  54. }
  55. static int get_key(void)
  56. {
  57. int key = 0;
  58. if (!is_key_buf_empty())
  59. {
  60. key = g_keys[r];
  61. r = NEXT_POS(r);
  62. }
  63. return key;
  64. }
  65. static DECLARE_WAIT_QUEUE_HEAD(gpio_key_wait);
  66. /* 实现对应的open/read/write等函数,填入file_operations结构体 */
  67. static ssize_t gpio_key_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
  68. {
  69. //printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
  70. int err;
  71. int key;
  72. wait_event_interruptible(gpio_key_wait, !is_key_buf_empty());
  73. key = get_key();
  74. err = copy_to_user(buf, &key, 4);
  75. return 4;
  76. }
  77. static unsigned int gpio_key_drv_poll(struct file *fp, poll_table * wait)
  78. {
  79. printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
  80. poll_wait(fp, &gpio_key_wait, wait);
  81. return is_key_buf_empty() ? 0 : POLLIN | POLLRDNORM;
  82. }
  83. /* 定义自己的file_operations结构体 */
  84. static struct file_operations gpio_key_drv = {
  85. .owner = THIS_MODULE,
  86. .read = gpio_key_drv_read,
  87. .poll = gpio_key_drv_poll,
  88. };
  89. static irqreturn_t gpio_key_isr(int irq, void *dev_id)
  90. {
  91. struct gpio_key *gpio_key = dev_id;
  92. int val;
  93. int key;
  94. val = gpiod_get_value(gpio_key->gpiod);
  95. printk("key %d %d\n", gpio_key->gpio, val);
  96. key = (gpio_key->gpio << 8) | val;
  97. put_key(key);
  98. wake_up_interruptible(&gpio_key_wait);
  99. return IRQ_HANDLED;
  100. }
  101. /* 1. 从platform_device获得GPIO
  102. * 2. gpio=>irq
  103. * 3. request_irq
  104. */
  105. static int gpio_key_probe(struct platform_device *pdev) /*匹配到平台数据了*/
  106. {
  107. int err;
  108. struct device_node *node = pdev->dev.of_node;
  109. int count;
  110. int i;
  111. enum of_gpio_flags flag;
  112. printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
  113. count = of_gpio_count(node); # 根据平台数据得到对应的GPIO数量
  114. if (!count)
  115. {
  116. printk("%s %s line %d, there isn't any gpio available\n", __FILE__, __FUNCTION__, __LINE__);
  117. return -1;
  118. }
  119. // 分配数据
  120. gpio_keys_array = kzalloc(sizeof(struct gpio_key) * count, GFP_KERNEL);
  121. for (i = 0; i < count; i++)
  122. {
  123. gpio_keys_array[i].gpio = of_get_gpio_flags(node, i, &flag);
  124. if (gpio_keys_array[i].gpio < 0)
  125. {
  126. printk("%s %s line %d, of_get_gpio_flags fail\n", __FILE__, __FUNCTION__, __LINE__);
  127. return -1;
  128. }
  129. # 这个需要去深入分析gpio子系统就能明白了,这里无需多讲
  130. gpio_keys_array[i].gpiod = gpio_to_desc(gpio_keys_array[i].gpio);
  131. gpio_keys_array[i].flag = flag & OF_GPIO_ACTIVE_LOW;
  132. gpio_keys_array[i].irq = gpio_to_irq(gpio_keys_array[i].gpio);
  133. }
  134. for (i = 0; i < count; i++)
  135. {
  136. # 申请中断
  137. err = request_irq(gpio_keys_array[i].irq, gpio_key_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "gpio_key", &gpio_keys_array[i]);
  138. }
  139. /* 注册file_operations */
  140. major = register_chrdev(0, "gpio_key", &gpio_key_drv); /* /dev/gpio_key */
  141. // 新创建一个类
  142. // 光宇
  143. gpio_key_class = class_create(THIS_MODULE, "gpio_key_class");
  144. if (IS_ERR(gpio_key_class)) {
  145. printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
  146. unregister_chrdev(major, "gpio_key");
  147. return PTR_ERR(gpio_key_class);
  148. }
  149. /*创建设备文件*/
  150. device_create(gpio_key_class, NULL, MKDEV(major, 0), NULL, "gpio_key"); /* /dev/gpio_key */
  151. return 0;
  152. }
  153. static int gpio_key_remove(struct platform_device *pdev)
  154. {
  155. //int err;
  156. struct device_node *node = pdev->dev.of_node;
  157. int count;
  158. int i;
  159. device_destroy(gpio_key_class, MKDEV(major, 0));
  160. class_destroy(gpio_key_class);
  161. unregister_chrdev(major, "gpio_key");
  162. count = of_gpio_count(node);
  163. for (i = 0; i < count; i++)
  164. {
  165. free_irq(gpio_keys_array[i].irq, &gpio_keys_array[i]);
  166. }
  167. kfree(gpio_keys_array);
  168. return 0;
  169. }
  170. static const struct of_device_id ask100_keys[] = {
  171. { .compatible = "tset,gpio_key" },
  172. { },
  173. };
  174. /* 1. 定义platform_driver */
  175. static struct platform_driver gpio_keys_driver = {
  176. .probe = gpio_key_probe,
  177. .remove = gpio_key_remove,
  178. .driver = {
  179. .name = "gpio_key", #
  180. .of_match_table = ask100_keys, # 匹配设备树里面的 compatible
  181. },
  182. };
  183. /* 2. 在入口函数注册platform_driver */
  184. static int __init gpio_key_init(void)
  185. {
  186. int err;
  187. printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
  188. err = platform_driver_register(&gpio_keys_driver); # 注册一个平台设备
  189. return err;
  190. }
  191. /* 3. 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数
  192. * 卸载platform_driver
  193. */
  194. static void __exit gpio_key_exit(void)
  195. {
  196. printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
  197. platform_driver_unregister(&gpio_keys_driver);
  198. }
  199. /* 7. 其他完善:提供设备信息,自动创建设备节点 */
  200. module_init(gpio_key_init);
  201. module_exit(gpio_key_exit);
  202. MODULE_LICENSE("GPL");
  203. MODULE_AUTHOR("zhouchengzhu <1073355312@qq.com>");
  204. MODULE_DESCRIPTION("A Poll test demo");
  205. MODULE_VERSION("0.1.0");

调用过程

参考Linux之poll机制分析

  1. app:poll
  2. kernel:sys_poll
  3. do_sys_poll
  4. # do_sys_poll
  5. root@zhou 00:33:50 ~/1/1/Linux-4.9.88 # grep -nrw "do_sys_poll" --include="*.c"
  6. fs/select.c:884:int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds,
  • 分析do_sys_poll ```c int do_sys_poll(struct pollfd __user ufds, unsigned int nfds,struct timespec64 end_time) poll_initwait(&table);
    1. # 关于 __pollwait 这个 poll_queue_proc 数据以后再分析
    2. init_poll_funcptr(&pwq->pt, __pollwait); // pwq->pt->_qproc = __pollwait # 惠帝
    3. #
    fdcount = do_poll(head, &table, end_time);

static int do_poll(struct poll_list list, struct poll_wqueues wait, struct timespec64 *end_time) for (;;)

  1. # 执行对应文件的poll函数
  2. do_pollfd(pfd, pt, &can_busy_loop,busy_flag)
  3. # 超时标志被设置好以后或者count非0,退出
  4. if (count || timed_out)
  5. break;
  6. # 在这里让出控制权。
  7. if (!poll_schedule_timeout(wait, TASK_INTERRUPTIBLE, to, slack))
  8. timed_out = 1;
  1. <a name="7teKu"></a>
  2. ### 分析
  3. poll_initwait 初始化 __pollwait ,这个属于回调函数,然后 do_poll 调用文件f_op的poll函数。
  4. <a name="1WkLO"></a>
  5. #### __pollwait 回调函数
  6. ```c
  7. static void __pollwait(struct file *filp, wait_queue_head_t *wait_address,
  8. poll_table *p)
  9. entry->wait_address = wait_address;

关于等待队列的操作,参考我以前写的等待队列深入理解

小结

poll 函数想要理解还是需要深入理解等待队列。但是和等待队列的使用有一点不同的是,当poll_wait将当前进程加入等待队列以后,并且没有立即释放控制权,

参考资料