11.LED驱动程序设计(1)-字符设备控制

    xiaoxiao2021-03-26  13

    1.设备控制理论

    1.1 作用

    大部分驱 动程 序除了需要提供 读写设备 的 能 力 外, 还需要具 备 控制设备的 能 力 。 比如:  改变波特率 

    1.2 应用程序接口

    在用 户空间 ,使用ioctl 系统调 用来控制设备, 原型如下: int ioctl(int fd,unsigned long cmd,...) fd: 要 要 控制的设备 文 件 描 述符 cmd:  发送给 设备的控制 命令 …:  第3个 个 参数是可选 的 参数 , 存 在 与否是依赖于 控制 命令(第 第 2 个 个数 参数 )。

    1.3 设备驱动方法

    当 应用程 序 使用ioctl 系统调 用 时 , 驱 动程 序 将 由如下函数 来 响 应: 1: 2.6.36  之前 的内 核 long (*ioctl) (struct inode* node ,struct file* filp, unsigned int cmd,unsigned long arg) 2 :2.6.36 之后 的内 核 long (*unlocked_ioctl) (struct file *filp, unsigned int cmd, unsigned long arg) 参数cmd:  通过 应用 函数ioctl 传递下 来的 命令

    2.设备控制实现

    2.1 定义命令

    命令 从其 实质而言就是一 个 整数,  但为了让这 个 整数具 备 更好 的可读性 ,我们 通常会把这 个 整数分为几 个 段 : 类 型(8位) , 序号 ,参数传送 方向 , 参数 长度 。

    ? Type(类 类型 型/幻 幻数 数): 表 表 明 这是 属 于 哪 个设备的 命令 。 ? Number( 序号) ,用来 区 分 同 一 设备的不 同 命令 ? Direction: : 参数传送 的 方向 , 可能 的 值是 是 _IOC_NONE(没 没 有数 据 传输 输), _IOC_READ, _IOC_WRITE (向 设备 写 入 参数 ) ? Size: :  参数 长度

    Linux 系统提供了下 面的 宏 来 帮助 定义命令: ? _IO(type,nr) :不 带 参数 的 命令 ? _IOR(type,nr,datatype) :从设备 中 读参数 的 命令 ? _IOW(type,nr,datatype): : 向 设备 写 入 参数 的 命令 例 : #define MEM_MAGIC ‘m’ // 定义 幻 数 #define MEM_SET _IOW(MEM_MAGIC, 0, int)

    2.2 实现设备方法

    unlocked_ioctl 函数 的 实现通常是 根据 命令 执行 的 一 个switch 语句 。 但是 , 当命令号 不 能 匹配 任何 一 个设备所支持 的 命令时 , 返回-EINVAL. 编 程 模 型 : Switch cmd Case  命令A: : // 执行A对 对 应的 操 作 Case  命令B: : // 执行B对 对 应的 操 作 Default: // return -EINVAL

    3.自己动手写驱动

    3.1 memdev.c

    #include <linux/module.h> #include <linux/types.h> #include <linux/fs.h> #include <linux/errno.h> #include <linux/init.h> #include <linux/cdev.h> #include <asm/uaccess.h> #include <linux/slab.h> #include "memdev.h" int dev1_registers[5]; int dev2_registers[5]; struct cdev cdev;  dev_t devno; /*文件打开函数*/ int mem_open(struct inode *inode, struct file *filp) {          /*获取次设备号*/     int num = MINOR(inode->i_rdev);          if (num==0)         filp->private_data = dev1_registers;     else if(num == 1)         filp->private_data = dev2_registers;     else         return -ENODEV;  //无效的次设备号          return 0;  } /*文件释放函数*/ int mem_release(struct inode *inode, struct file *filp) {   return 0; } /*读函数*/ static ssize_t mem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos) {   unsigned long p =  *ppos;   unsigned int count = size;   int ret = 0;   int *register_addr = filp->private_data; /*获取设备的寄存器基地址*/   /*判断读位置是否有效*/   if (p >= 5*sizeof(int))     return 0;   if (count > 5*sizeof(int) - p)     count = 5*sizeof(int) - p;   /*读数据到用户空间*/   if (copy_to_user(buf, register_addr+p, count))   {     ret = -EFAULT;   }   else   {     *ppos += count;     ret = count;   }   return ret; } /*写函数*/ static ssize_t mem_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos) {   unsigned long p =  *ppos;   unsigned int count = size;   int ret = 0;   int *register_addr = filp->private_data; /*获取设备的寄存器地址*/      /*分析和获取有效的写长度*/   if (p >= 5*sizeof(int))     return 0;   if (count > 5*sizeof(int) - p)     count = 5*sizeof(int) - p;        /*从用户空间写入数据*/   if (copy_from_user(register_addr + p, buf, count))     ret = -EFAULT;   else   {     *ppos += count;     ret = count;   }   return ret; } /* seek文件定位函数 */ static loff_t mem_llseek(struct file *filp, loff_t offset, int whence) {      loff_t newpos;     switch(whence) {       case SEEK_SET:          newpos = offset;         break;       case SEEK_CUR:          newpos = filp->f_pos + offset;         break;       case SEEK_END:          newpos = 5*sizeof(int)-1 + offset;         break;       default:          return -EINVAL;     }     if ((newpos<0) || (newpos>5*sizeof(int)))     return -EINVAL;         filp->f_pos = newpos;     return newpos; } long mem_ioctl(struct file * filp, unsigned int cmd, unsigned long arg) { switch (cmd) { case MEM_RESTART: printk("restart device \n"); return 0; case MEM_SET: printk("arg is %d\n",arg); return 0; default: return -EINVAL; } } /*文件操作结构体*/ static const struct file_operations mem_fops = {   .llseek = mem_llseek,   .read = mem_read,   .write = mem_write,   .open = mem_open,   .release = mem_release,   .unlocked_ioctl = mem_ioctl; }; /*设备驱动模块加载函数*/ static int memdev_init(void) {   /*初始化cdev结构*/   cdev_init(&cdev, &mem_fops);      /* 注册字符设备 */   alloc_chrdev_region(&devno, 0, 2, "memdev");   cdev_add(&cdev, devno, 2); } /*模块卸载函数*/ static void memdev_exit(void) {   cdev_del(&cdev);   /*注销设备*/   unregister_chrdev_region(devno, 2); /*释放设备号*/ } MODULE_LICENSE("GPL"); module_init(memdev_init); module_exit(memdev_exit);

    3.2 memdev.h

    #define MEM_MAGIC 'm' #define MEM_RESTART _IO(MEM_MAGIC,0) #define MEM_SET     _IOW(MEM_MAGIC,1,int)

    3.3 mem_ctl.c

    #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/ioctl.h> #include "memdev.h" int main() { int fd; fd = open("/dev/memdev0",O_RDWR); ioctl(fd,MEM_SET,115200); ioctl(fd,MEM_RESTART); return 0; } 253 memdev mknod /dev/memdev0 c 253 0
    转载请注明原文地址: https://ju.6miu.com/read-450256.html

    最新回复(0)