国嵌内核驱动进阶班-7-4(Poll设备方法)

Poll 与系统select调用相对应

int select(int nfds, fd_set *readfds, fd_set *writefds,
  fd_set *exceptfds, struct timeval *timeout)

 


Poll设备方法完成流程:

1. 使用poll_wait将等待队列添加到poll_table中

2. 返回描述设备的可读可写的设备掩码。

※ 掩码有:

POLLIN

设备可读

POLLRDNORM

数据可读

POLLOUT

设备可写

POLLWRNORM

数据可写


内核代码:

do_select()实现阻塞。


  1 #include <linux/module.h>
  2 #include <linux/types.h>
  3 #include <linux/fs.h>
  4 #include <linux/errno.h>
  5 #include <linux/mm.h>
  6 #include <linux/sched.h>
  7 #include <linux/init.h>
  8 #include <linux/cdev.h>
  9 #include <asm/io.h>
 10 #include <linux/slab.h>
 11 #include <asm/uaccess.h>
 12 
 13 #include <linux/poll.h>
 14 #include "memdev.h"
 15 
 16 static int mem_major = MEMDEV_MAJOR;
 17 bool have_data = false; /*表明设备有足够数据可供读*/
 18 
 19 module_param(mem_major, int, S_IRUGO);
 20 
 21 struct mem_dev *mem_devp; /*设备结构体指针*/
 22 
 23 struct cdev cdev; 
 24 
 25 /*文件打开函数*/
 26 int mem_open(struct inode *inode, struct file *filp)
 27 {
 28     struct mem_dev *dev;
 29     
 30     /*获取次设备号*/
 31     int num = MINOR(inode->i_rdev);
 32 
 33     if (num >= MEMDEV_NR_DEVS) 
 34             return -ENODEV;
 35     dev = &mem_devp[num];
 36     
 37     /*将设备描述结构指针赋值给文件私有数据指针*/
 38     filp->private_data = dev;
 39     
 40     return 0; 
 41 }
 42 
 43 /*文件释放函数*/
 44 int mem_release(struct inode *inode, struct file *filp)
 45 {
 46   return 0;
 47 }
 48 
 49 /*读函数*/
 50 static ssize_t mem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
 51 {
 52   unsigned long p =  *ppos;
 53   unsigned int count = size;
 54   int ret = 0;
 55   struct mem_dev *dev = filp->private_data; /*获得设备结构体指针*/
 56 
 57   /*判断读位置是否有效*/
 58   if (p >= MEMDEV_SIZE)
 59     return 0;
 60   if (count > MEMDEV_SIZE - p)
 61     count = MEMDEV_SIZE - p;
 62     
 63   while (!have_data) /* 没有数据可读,考虑为什么不用if,而用while */
 64   {
 65         if (filp->f_flags & O_NONBLOCK)
 66             return -EAGAIN;
 67     
 68     wait_event_interruptible(dev->inq,have_data);
 69   }
 70 
 71   /*读数据到用户空间*/
 72   if (copy_to_user(buf, (void*)(dev->data + p), count))
 73   {
 74     ret =  - EFAULT;
 75   }
 76   else
 77   {
 78     *ppos += count;
 79     ret = count;
 80    
 81     printk(KERN_INFO "read %d bytes(s) from %ld
", count, p);
 82   }
 83   
 84   have_data = false; /* 表明不再有数据可读 */
 85   /* 唤醒写进程 */
 86   return ret;
 87 }
 88 
 89 /*写函数*/
 90 static ssize_t mem_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
 91 {
 92   unsigned long p =  *ppos;
 93   unsigned int count = size;
 94   int ret = 0;
 95   struct mem_dev *dev = filp->private_data; /*获得设备结构体指针*/
 96   
 97   /*分析和获取有效的写长度*/
 98   if (p >= MEMDEV_SIZE)
 99     return 0;
100   if (count > MEMDEV_SIZE - p)
101     count = MEMDEV_SIZE - p;
102 
103   /*从用户空间写入数据*/
104   if (copy_from_user(dev->data + p, buf, count))
105     ret =  - EFAULT;
106   else
107   {
108     *ppos += count;
109     ret = count;
110     
111     printk(KERN_INFO "written %d bytes(s) from %ld
", count, p);
112   }
113   
114   have_data = true; /* 有新的数据可读 */
115     
116     /* 唤醒读进程 */
117     wake_up(&(dev->inq));
118 
119   return ret;
120 }
121 
122 /* seek文件定位函数 */
123 static loff_t mem_llseek(struct file *filp, loff_t offset, int whence)
124 { 
125     loff_t newpos;
126 
127     switch(whence) {
128       case 0: /* SEEK_SET */
129         newpos = offset;
130         break;
131 
132       case 1: /* SEEK_CUR */
133         newpos = filp->f_pos + offset;
134         break;
135 
136       case 2: /* SEEK_END */
137         newpos = MEMDEV_SIZE -1 + offset;
138         break;
139 
140       default: /* can't happen */
141         return -EINVAL;
142     }
143     if ((newpos<0) || (newpos>MEMDEV_SIZE))
144         return -EINVAL;
145         
146     filp->f_pos = newpos;
147     return newpos;
148 
149 }
150 unsigned int mem_poll(struct file *filp, poll_table *wait)
151 {
152     unsigned int mask = 0;
153     struct mem_dev  *dev = filp->private_data; 
154  
155     printk(KERN_INFO "@@@@ mytest mem_poll() have_data = %d
", have_data);
156 
157    /*将等待队列添加到poll_table */
158     if (have_data)         
159     {
160         poll_wait(filp, &dev->inq,  wait);
161         mask |= POLLIN | POLLRDNORM;  /* readable */
162     }
163     
164     return mask;
165 }
166 
167 
168 /*文件操作结构体*/
169 static const struct file_operations mem_fops =
170 {
171   .owner = THIS_MODULE,
172   .llseek = mem_llseek,
173   .read = mem_read,
174   .write = mem_write,
175   .open = mem_open,
176   .release = mem_release,
177   .poll = mem_poll,
178 };
179 
180 /*设备驱动模块加载函数*/
181 static int memdev_init(void)
182 {
183   int result;
184   int i;
185 
186   dev_t devno = MKDEV(mem_major, 0);
187 
188   /* 静态申请设备号*/
189   if (mem_major)
190     result = register_chrdev_region(devno, 2, "memdev");
191   else  /* 动态分配设备号 */
192   {
193     result = alloc_chrdev_region(&devno, 0, 2, "memdev");
194     mem_major = MAJOR(devno);
195   }  
196   
197   if (result < 0)
198     return result;
199 
200   /*初始化cdev结构*/
201   cdev_init(&cdev, &mem_fops);
202   cdev.owner = THIS_MODULE;
203   cdev.ops = &mem_fops;
204   
205   /* 注册字符设备 */
206   cdev_add(&cdev, MKDEV(mem_major, 0), MEMDEV_NR_DEVS);
207    
208   /* 为设备描述结构分配内存*/
209   mem_devp = kmalloc(MEMDEV_NR_DEVS * sizeof(struct mem_dev), GFP_KERNEL);
210   if (!mem_devp)    /*申请失败*/
211   {
212     result =  - ENOMEM;
213     goto fail_malloc;
214   }
215   memset(mem_devp, 0, sizeof(struct mem_dev));
216   
217   /*为设备分配内存*/
218   for (i=0; i < MEMDEV_NR_DEVS; i++) 
219   {
220         mem_devp[i].size = MEMDEV_SIZE;
221         mem_devp[i].data = kmalloc(MEMDEV_SIZE, GFP_KERNEL);
222         memset(mem_devp[i].data, 0, MEMDEV_SIZE);
223   
224       /*初始化等待队列*/
225      init_waitqueue_head(&(mem_devp[i].inq));
226      //init_waitqueue_head(&(mem_devp[i].outq));
227   }
228    
229   return 0;
230 
231   fail_malloc: 
232   unregister_chrdev_region(devno, 1);
233   
234   return result;
235 }
236 
237 /*模块卸载函数*/
238 static void memdev_exit(void)
239 {
240   cdev_del(&cdev);   /*注销设备*/
241   kfree(mem_devp);     /*释放设备结构体内存*/
242   unregister_chrdev_region(MKDEV(mem_major, 0), 2); /*释放设备号*/
243 }
244 
245 MODULE_AUTHOR("David Xie");
246 MODULE_LICENSE("GPL");
247 
248 module_init(memdev_init);
249 module_exit(memdev_exit);
 1 #ifndef _MEMDEV_H_
 2 #define _MEMDEV_H_
 3 
 4 #ifndef MEMDEV_MAJOR
 5 #define MEMDEV_MAJOR 0   /*预设的mem的主设备号*/
 6 #endif
 7 
 8 #ifndef MEMDEV_NR_DEVS
 9 #define MEMDEV_NR_DEVS 2    /*设备数*/
10 #endif
11 
12 #ifndef MEMDEV_SIZE
13 #define MEMDEV_SIZE 4096
14 #endif
15 
16 /*mem设备描述结构体*/
17 struct mem_dev                                     
18 {                                                        
19   char *data;                      
20   unsigned long size; 
21   wait_queue_head_t inq;  
22 };
23 
24 #endif /* _MEMDEV_H_ */
 1 ifneq ($(KERNELRELEASE),)
 2 
 3 obj-m := memdev.o
 4 
 5 else
 6     
 7 KDIR := /home/rpi/RpiLinux
 8 all:
 9     make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=/home/rpi/RpiTools/arm-bcm2708/arm-bcm2708hardfp-linux-gnueabi/bin/arm-bcm2708hardfp-linux-gnueabi-
10 
11 clean:
12     rm -f *.ko *.o *.mod.o *.mod.c *.symvers  modul*
13 
14 endif

测试代码:

 1 #include <stdio.h>
 2 
 3 int main()
 4 {
 5     FILE *fp = NULL;
 6     char Buf[128];
 7     
 8     
 9     /*打开设备文件*/
10     fp = fopen("/dev/memdev0","r+");
11     if (fp == NULL)
12     {
13         printf("Open Dev memdev0 Error!
");
14         return -1;
15     }
16     
17     /*写入设备*/
18     strcpy(Buf,"memdev is char dev!");
19     printf("Write BUF: %s
",Buf);
20     fwrite(Buf, sizeof(Buf), 1, fp);
21     
22     sleep(5);
23     fclose(fp);
24     
25     return 0;    
26 
27 }
 1 #include <stdio.h>
 2 
 3 int main()
 4 {
 5     FILE *fp = NULL;
 6     char Buf[128];
 7     
 8     /*初始化Buf*/
 9     strcpy(Buf,"memdev is char dev!");
10     printf("BUF: %s
",Buf);
11     
12     /*打开设备文件*/
13     fp = fopen("/dev/memdev0","r+");
14     if (fp == NULL)
15     {
16         printf("Open memdev0 Error!
");
17         return -1;
18     }
19     
20     /*清除Buf*/
21     strcpy(Buf,"Buf is NULL!");
22     printf("Read BUF1: %s
",Buf);
23     
24     /*读出数据*/
25     fread(Buf, sizeof(Buf), 1, fp);
26     
27     /*检测结果*/
28     printf("Read BUF2: %s
",Buf);
29     
30     fclose(fp);
31     
32     return 0;    
33 
34 }
原文地址:https://www.cnblogs.com/renhl/p/4550689.html