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

    测试结果:

  • 相关阅读:
    主机的IOPS需求转换成硬盘实际IOPS负载
    IT安全运维职责
    IT应用运维职责
    存储RAID 选择策略
    交换机接口下错包计数,哪些是属于物理链路(包括本端设备和对端设备硬件问题)引起的
    华为交换机SNMP配置
    c# 位与运算符&简单实现复选框功能【实际应用】
    centos7 安装谷歌浏览器教程
    centos7下 Consul安装
    .netcore3.1 获取请求头header中认证信息并调用其它接口
  • 原文地址:https://www.cnblogs.com/renhl/p/4550601.html
Copyright © 2011-2022 走看看