zoukankan      html  css  js  c++  java
  • 国嵌内核驱动进阶班-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 }
  • 相关阅读:
    R语言对苏格兰独立民意调查的Meta分析
    R语言中固定与随机效应Meta分析
    Comet OJ
    luoguP6070 [MdOI2020] Decrease 贪心+二维差分
    luoguP6071 [MdOI2020] Treequery DFS序+主席树
    AT2064 [AGC005F] Many Easy Problems 容斥+NTT
    BZOJ 4650: [Noi2016]优秀的拆分 后缀自动机+启发式合并+线段树合并
    BZOJ 1498: [NOI2006]神奇的口袋 性质分析+高精度
    BZOJ 1819: [JSOI]Word Query电子字典 搜索+trie
    robotframework 随机选中下拉框中的值
  • 原文地址:https://www.cnblogs.com/renhl/p/4550689.html
Copyright © 2011-2022 走看看