驱动模型

来源:互联网 发布:工业3.0是什么知乎 编辑:程序博客网 时间:2024/06/16 00:03
#include <linux/init.h>#include <linux/module.h>#include <linux/fs.h>#include <linux/cdev.h>#include <linux/uaccess.h>//设备结构体 struct xxx_dev_t{     struct cdev cdev;     ...}xxx_dev;/*打开*/int xxx_open(struct inode *inode, struct file *filp){   /******************************************************************************************   struct inode被内核用来代表一个文件,注意和struct file的 区别,struct inode代表文件,   struct file代表打开的文件;同一个文件可以被打开好多次,所以可以对应很多struct file,   但是只对应一个struct inode。   ******************************************************************************************/   ... } int xxx_release(struct inode *inode, struct file *filp){   //release释放相当于close   ...}/* 读设备*/ ssize_t  xxx_read(struct  file  *filp,  char  __user  *buf,  size_t  count, loff_t*f_pos) {     ...       copy_to_user(buf,  ...,  ...); /*******************************************************************************************************1、设备驱动的读写函数中,filp是文件结构体指针,buf是用户空间内存的地址,该地址在内核空间不能直接读写,   count是要读写的字节数,f_pos是读写的位置相对于文件       开头的偏移。     2、由于内核空间与用户空间的内存不能直接互访,因此借助函数 copy_from_user()完成用户空间到内核空间的复制,函数 copy_to_user()完成内核空间到用户空间的复制。     copy_from_user()和copy_to_user()的原型如下所示:    unsigned  long  copy_from_user(void  *to,  const  void  _ _user  *from,  unsigned long count);     unsigned  long  copy_to_user(void  _ _user  *to,  const  void  *from,  unsigned long count);**********************************************************************************************************/    ... }/* 写设备*/ssize_t  xxx_write(struct  file  *filp,  const  char  __user  *buf,  size_t count, loff_t *f_pos) { /**************************************************************************************************//filp:与字符设备文件关联的file结构指针, 由内核创建。//buff : 从设备读取到的数据,需要保存到的位置。由read系统调用提供该参数。//count: 请求传输的数据量,由read系统调用提供该参数。//offp: 文件的读写位置,由内核从file结构中取出后,传递进来。/*buff参数是来源于用户空间的指针,这类指针都不能被内核代码直接引用,必须使用专门的函数: int copy_from_user(void *to, const void __user *from, int n) int copy_to_user(void __user *to, const void *from, int n)*/************************************************************************************/   ...     copy_from_user(..., buf, ...);       ...  } /* ioctl函数 */int  xxx_ioctl(struct  inode  *inode,  struct  file  *filp,  unsigned  int cmd, unsigned long arg) {     ...        switch (cmd)     {                case XXX_CMD1:                     ...                     break;           case XXX_CMD2:                     ...                         break;           default:     /* 不能支持的命令 */                     return  - ENOTTY;      }        return 0;   }struct file_operations    xxx_fops = {       .owner = THIS_MODULE,     .open = xxx_open,    .release = xxx_release,    .read = xxx_read,     .write = xxx_write,     .ioctl = xxx_ioctl,       ... };  //设备驱动模块加载函数 static int __init xxx_init(void) { /**********************************************************************分配cdev:cdev变量的定义可以采用静态和动态两种办法静态分配:struct cdev mdev;动态分配: struct cdev *pdev = cdev_alloc();初始化cdev:struct cdev的初始化使用cdev_init函数来完成。cdev_init(struct cdev *cdev, const struct file_operations *fops)参数:cdev: 待初始化的cdev结构fops: 设备对应的操作函数集注册cdev:字符设备的注册使用cdev_add函数来完成。cdev_add(struct cdev *p, dev_t dev, unsigned count)参数:p: 待添加到内核的字符设备结构dev: 设备号count: 该类设备的设备个数***********************************************************************/    ...      cdev_init(&xxx_dev.cdev, &xxx_fops);      //初始化cdev     xxx_dev.cdev.owner = THIS_MODULE;        if (xxx_major)    //获取字符设备号     {           register_chrdev_region(xxx_dev_no, 1, DEV_NAME);     }    else     {          alloc_chrdev_region(&xxx_dev_no, 0, 1, DEV_NAME); }     ret = cdev_add(&xxx_dev.cdev, xxx_dev_no, 1); //注册设备    ...     }  /*设备驱动模块卸载函数*/ static void __exit xxx_exit(void) {      unregister_chrdev_region(xxx_dev_no, 1); //释放占用的设备号     cdev_del(&xxx_dev.cdev); //注销设备     ...  }module_init(xxx_init);module_exit(xxx_exit);MODULE_AUTHOR("XXXX");MODULE_LICENSE("GPL");//许可证