国嵌内核驱动进阶班-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\n", 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\n", 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\n", 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!\n");
14         return -1;
15     }
16
17     /*写入设备*/
18     strcpy(Buf,"memdev is char dev!");
19     printf("Write BUF: %s\n",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\n",Buf);
11
12     /*打开设备文件*/
13     fp = fopen("/dev/memdev0","r+");
14     if (fp == NULL)
15     {
16         printf("Open memdev0 Error!\n");
17         return -1;
18     }
19
20     /*清除Buf*/
21     strcpy(Buf,"Buf is NULL!");
22     printf("Read BUF1: %s\n",Buf);
23
24     /*读出数据*/
25     fread(Buf, sizeof(Buf), 1, fp);
26
27     /*检测结果*/
28     printf("Read BUF2: %s\n",Buf);
29
30     fclose(fp);
31
32     return 0;
33
34 }
时间: 2024-10-19 08:27:52

国嵌内核驱动进阶班-7-4(Poll设备方法)的相关文章

国嵌内核驱动进阶班-7-1(Ioctl设备控制)

ioctl 控制设备 除了读写设备之外,其他功能的实现需要ioctl.如串口的波特率的设定. 用户空间: ioctl的应用 api int ioctl(int fd, unsigned long cmd, ...) fd 文件描述符 cmd 发送的命令 ...依赖cmd命令 内核空间 api int (*ioctl)(struct inode *inode, struct file *flip, unsigned int cmd, unsigned long arg) inode 文件的物理信息

国嵌内核驱动进阶班-7-3(阻塞型字符设备驱动)

为什么阻塞? 在阻塞方式下,写没有足够的空间或读时候没有数据. ※ 阻塞方式是文件读写的默认方式.没有空间或者读时没有数据返回错误. ※残留问题: 驱动程序中全局变量 在不同进程间是共享的吗? 阻塞型设备驱动程序 驱动代码: 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_N

国嵌内核驱动进阶班-7-1(Ioctl设备控制)--- 测试代码

驱动内容: 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/cde

国嵌内核驱动进阶班-7-5(自动创建设备文件)

linux 2.6.13 开始,devfs不存在,udev取代devfs. udev(mdev)存在应用层,可以实现设备文件的自动创建和删除. 过程: 驱动代码调用class_create创建一个class,再为每个设备调用class_create创建对应的设备. ※ 自动创建设备文件需要udev的支持 struct class *myclass =  class_create(THIS_MODULE, "mydriver"); device_create(myclass,NULL,

国嵌内核驱动进阶班-7-2(内核等待队列)

定义和初期化 定义等待队列 wait_queue_head_t myqueue; 初始化等待队列 init_waitqueue_head(&myqueue) 定义并初始化等待队列 DECLARE_WAIT_QUEUE_HEAD(myqueue) 睡眠 条件睡眠 当condition为真时,立即执行: wait_event(queue, condition) 当condition为假时,进入TASK_UNINTERRUPTIBLE: wait_event_interruptible(queue,

Linux内核驱动--mmap设备方法【原创】

mmap系统调用(功能) void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset) 内存映射函数mmap , 负责把文件内容映射到进程的虚拟内存空间,通过对这段内存的读取和修改,来实现对文件的读取和修改,而不需要再调用read, write等操作. addr:        指定映射的起始地址,通常设为NULL, 由系统指定. len:          映射到内存的文件长度 prot:     

[国嵌攻略][155][I2C用户态驱动设计]

用户态驱动模型 用户态驱动模型首先是一个应用程序,其次是在这个用户程序中通过内核调用来驱动设备. IIC通用驱动代码 IIC通用驱动程序的代码在/drivers/i2c/i2c-dev.c中.一次读操作或者一次写操作就是一条消息. EEPROM用户态驱动 IIC通用设备对应/dev/i2c-0设备文件. 1.打开通用设备驱动 2.构造写数据到eeprom的消息 3.使用ioctl写入数据 4.构造从eeprom读数据的消息 5.使用ioctl读出数据 6.关闭设备 配置IIC驱动 make me

[国嵌攻略][117][LED驱动程序设计]

LED程序设计 1.编写内核模块 2.搭建字符驱动框架 3.实现设备方法 头文件 <linux/io.h> writel() leddev.h //设备命令 #define LED_MAGIC 'L' //LED幻数 #define LED_ON _IO(LED_MAGIC, 0) //打开LED #define LED_OFF _IO(LED_MAGIC, 1) //关闭LED leddev.c /***********************************************

linux内核驱动模型

linux内核驱动模型,以2.6.32内核为例.(一边写一边看的,有点乱.) 1.以内核对象为基础.用kobject表示,相当于其它对象的基类,是构建linux驱动模型的关键.具有相同类型的内核对象构成内核对象集,用kset表示,内核对象集也包含自己的内核对象,从而组成层次化的结构.2.用sysfs文件系统导出到用户空间.内核中的所有内核对象组织成树状,以对象属性为叶子.通过sysfs文件系统,将用户空间对文件的读写操作转化为对内核对象属性的显示和保存方法.从而导出内核对象信息,并提供配置接口.