zoukankan      html  css  js  c++  java
  • 字符设备驱动的组成

    1.在字符设备驱动模块加载函数中应该实现设备号的申请和cdev 的注册,而在卸载函数中应实现设备号的释放和cdev 的注销。

    1//设备结构体
    2 struct xxx_dev_t
    3 {
    4 struct cdev cdev;
    5 ...
    6 } xxx_dev;
    7 //设备驱动模块加载函数
    8 static int _ _init xxx_init(void)
    9 {
    10 ...
    11 cdev_init(&xxx_dev.cdev, &xxx_fops); //初始化cdev
    12 xxx_dev.cdev.owner = THIS_MODULE;
    13 //获取字符设备号
    14 if (xxx_major)
    15 {
    16 register_chrdev_region(xxx_dev_no, 1, DEV_NAME);
    17 }
    18 else
    19 {
    20 alloc_chrdev_region(&xxx_dev_no, 0, 1, DEV_NAME);
    21 }
    22
    23 ret = cdev_add(&xxx_dev.cdev, xxx_dev_no, 1); //注册设备
    24 ...
    25 }
    26 /*设备驱动模块卸载函数*/
    27 static void _ _exit xxx_exit(void)
    28 {
    29 unregister_chrdev_region(xxx_dev_no, 1); //释放占用的设备号
    30 cdev_del(&xxx_dev.cdev); //注销设备
    31 ...
    32 }

    2.file_operations 结构体中成员函数是字符设备驱动与内核的接口,是用户空间对Linux 进行系统调用最终的落实者。大多数字符设备驱动会实现read()、write()和ioctl()函数。

    1 struct file_operations xxx_fops =
    2 {
    3 .owner = THIS_MODULE,
    4 .read = xxx_read,
    5 .write = xxx_write,
    6 .ioctl = xxx_ioctl,
    7 ...
    8 };

    下面将基于虚拟的 globalmem 设备进行字符设备驱动。globalmem 意味着“全局内存”,在globalmem 字符设备驱动中会分配一片大小为GLOBALMEM_ SIZE的内存空
    间,并在驱动中提供针对该片内存的读写、控制和定位函数,以供用户空间的进程能通过Linux 系统调用访问这片内存。

      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<linux/slab.h>
     10 #include<linux/kdev_t.h>
     11 #include<linux/device.h>
     12 #include <asm/io.h>
     13 #include<asm/system.h>
     14 #include<asm/uaccess.h>
     15 
     16 #define GLOBALMEM_SIZE 0x1000
     17 #define MEM_CLEAR 0x1
     18 #define GLOBALMEM_MAJOR 254  /*预设的globalmem 的主设备号*/
     19 
     20 static int globalmem_major = GLOBALMEM_MAJOR;
     21 /*globalmem 设备结构体*/
     22 struct globalmem_dev
     23 {
     24     struct cdev cdev;
     25     unsigned char mem[GLOBALMEM_SIZE];
     26 };
     27 struct globalmem_dev *globalmem_devp; /*设备结构体指针*/
     28 /*文件打开函数*/
     29 int globalmem_open(struct inode *inode, struct file *filp)
     30 {
     31     filp->private_data = globalmem_devp;/*将设备结构体指针赋值给文件私有数据指针*/
     32     return 0;
     33 }
     34 /*文件释放函数*/
     35 int globalmem_release(struct inode *inode, struct file *filp)
     36 {
     37     return 0;
     38 }
     39 /* ioctl 设备控制函数 */
     40 static int globalmem_ioctl(struct inode *inodep, struct file *filp, unsigned int cmd, unsigned long arg)
     41 {
     42     struct globalmem_dev *dev = filp->private_data;/*获得设备结构体指针*/
     43     switch (cmd)
     44     {
     45         case MEM_CLEAR:
     46             memset(dev->mem, 0, GLOBALMEM_SIZE);
     47             printk(KERN_INFO "globalmem is set to zero
    ");
     48         break;
     49         default:return - EINVAL;
     50     }
     51     return 0;
     52 }
     53 /*读函数*/
     54 static ssize_t globalmem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
     55 {
     56     unsigned long p = *ppos;
     57     unsigned int count = size;
     58     int ret = 0;
     59     struct globalmem_dev *dev = filp->private_data;
     60     if (p >= GLOBALMEM_SIZE)
     61         return count ? - ENXIO: 0;
     62     if (count > GLOBALMEM_SIZE - p)
     63         count = GLOBALMEM_SIZE - p;
     64     /*内核空间→用户空间*/
     65     if (copy_to_user(buf, (void*)(dev->mem + p), count))
     66     {
     67         ret = - EFAULT;
     68     }
     69     else
     70     {
     71         *ppos += count;
     72         ret = count;
     73         printk(KERN_INFO "read %d bytes(s) from %d
    ",count,p);
     74     }
     75     return ret;
     76 }
     77 /*写函数*/
     78 static ssize_t globalmem_write(struct file *filp, const char __user *buf,size_t size, loff_t *ppos)
     79 {
     80     unsigned long p = *ppos;
     81     unsigned int count = size;
     82     int ret = 0;
     83     struct globalmem_dev *dev = filp->private_data;
     84     if (p >= GLOBALMEM_SIZE)
     85         return count ? - ENXIO: 0;
     86     if (count > GLOBALMEM_SIZE - p)
     87         count = GLOBALMEM_SIZE - p;
     88     /*用户空间→内核空间*/
     89    if (copy_from_user(dev->mem + p, buf, count))
     90     {
     91         ret = - EFAULT;
     92     }
     93     else
     94     {
     95         *ppos += count;
     96         ret = count;
     97         printk(KERN_INFO "written %d bytes(s) from %d
    ", count, p);
     98     }
     99     return ret;
    100 }
    101 /* seek 文件定位函数 */
    102  static loff_t globalmem_llseek(struct file *filp,loff_t offset,int orig)
    103 {
    104     loff_t ret = 0;
    105     switch(orig)
    106     {
    107         case 0:   /*相对文件开始位置偏移*/
    108             if(offset < 0)
    109             {
    110                 ret = -EINVAL;//
    111                 break;
    112             }
    113             if((unsigned int)offset > GLOBALMEM_SIZE)
    114             {
    115                 ret = -EINVAL;
    116                 break;
    117             }
    118             filp->f_pos = (unsigned int)offset;
    119             ret = filp->f_pos;
    120             break;
    121         case 1:    /*相对文件当前位置偏移*/
    122             if((filp->f_pos + offset) > GLOBALMEM_SIZE)
    123             {
    124                 ret = -EINVAL;
    125                 break;
    126             }
    127             if((filp->f_pos + offset) < 0)
    128             {
    129                 ret = -EINVAL;
    130                 break;
    131             }
    132             filp->f_pos +=offset;
    133             ret = filp->f_pos;
    134             break;
    135         default:
    136             ret = -EINVAL;
    137             break;
    138     }
    139     return ret;
    140 }
    141 /*文件操作结构体*/
    142 static const struct file_operations globalmem_fops=
    143 {
    144     .owner = THIS_MODULE,
    145     .llseek = globalmem_llseek,
    146     .read = globalmem_read,
    147     .write = globalmem_write,
    148     .ioctl = globalmem_ioctl,
    149     .open = globalmem_open,
    150     .release = globalmem_release,
    151 };
    152 /*初始化并注册cdev*/
    153 static void globalmem_setup_cdev(struct globalmem_dev *dev,int index)
    154 {
    155     int err,devno = MKDEV(globalmem_major,index);
    156     cdev_init(&dev->cdev,&globalmem_fops);
    157     dev->cdev.owner = THIS_MODULE;
    158     err = cdev_add(&dev->cdev,devno,1);
    159     if(err)
    160         printk(KERN_INFO"error %d ading globalmem %d",err,index);
    161 }
    162 /*设备驱动模块加载函数*/
    163 int globalmem_init(void)
    164 {
    165     int result;
    166     dev_t devno = MKDEV(globalmem_major,0);
    167     if(globalmem_major)  /* 申请设备号*/
    168     {
    169         result = register_chrdev_region(devno,1,"globalmem");
    170         printk("register_chrdev_region
    ");
    171     }
    172     else   /* 动态申请设备号 */
    173     {
    174         result = alloc_chrdev_region(&devno,0,1,"globalmem");
    175         globalmem_major = MAJOR(devno);
    176         printk("alloc_chrdev_region
    ");
    177     }
    178     if(result < 0)
    179         return result;
    180      /* 动态申请设备结构体的内存*/
    181     globalmem_devp = kmalloc(sizeof(struct globalmem_dev),GFP_KERNEL);
    182     if(!globalmem_devp)
    183     {
    184         result = -ENOMEM;//no memory
    185         goto fail_malloc;
    186     }
    187     memset(globalmem_devp,0,sizeof(struct globalmem_dev));
    188     globalmem_setup_cdev(globalmem_devp,0);
    189     printk("init ok..
    ");
    190     return 0;
    191 fail_malloc:
    192     unregister_chrdev_region(devno,1);
    193     return result;
    194 }
    195 /*模块卸载函数*/
    196 void globalmem_exit(void)
    197 {
    198     cdev_del(&globalmem_devp->cdev);   /*注销cdev*/
    199     kfree(globalmem_devp);
    200     unregister_chrdev_region(MKDEV(globalmem_major,0),1); /*释放设备号*/
    201     printk("exit..
    ");
    202 }
    203 MODULE_AUTHOR("Huang");
    204 MODULE_LICENSE("Dual BSD/GPL");
    205 
    206 module_param(globalmem_major, int, S_IRUGO);/*内核模块通过module_param()来传递参数*/
    207 module_init(globalmem_init);
    208 module_exit(globalmem_exit);

    Makefile:

     1 ifneq ($(KERNELRELEASE),)
     2     obj-m:= globalmem.o
     3 else
     4     PWD:=$(shell pwd)
     5     KVER?=$(shell uname -r)
     6     KERNELDIR:= /usr/src/linux-2.6.32.2     //编译好的内核
     7 default:
     8     make -C $(KERNELDIR) M=$(PWD) modules
     9 endif
    10 clean:
    11     rm-f *.ko *.mod.c *.mod.o *.o

    运行 insmod globalmem.ko 命令加载模块,通过 lsmod 命令,发现globalmem 模块已被加载。再通过 cat /proc/devices 命令查看,发现多出了主设备号为254的globalmem字符设备驱动。

  • 相关阅读:
    Appium+unittest+PageObject实例
    monkeyrunner简单用法
    Mac电脑修改系统文件夹的权限
    UIImage剪切
    LLDB 打印 frame
    打开qq在线聊天
    获取当地时间
    微信支付SDK使用心得
    获取当前星期几
    UIView相对于屏幕的frame
  • 原文地址:https://www.cnblogs.com/ht-beyond/p/4313927.html
Copyright © 2011-2022 走看看