华清远见嵌入式学习——day33字符设备驱动接口

【1】复习

    字符设备框架:
    
        1. cdev结构体
        
        2. 编写
        
            [1]. 申请/注册设备号
            
                alloc_chrdev_region
                                        --->>>  unregister_chrdev_region
                register_chrdev_region
                
            [2]. 分配cdev结构体
            
                cdev_alloc
                
            [3]. cdev初始化
                
                cdev_init
                
            [4]. 添加到内核
            
                cdev_add    --->>>   cdev_del
        

    open的系统调用过程
    
        open --(设备文件)设备号-->>>  demo_open
        
    应用层的open()返回文件描述符fd(非负整数)
    
    xxx.c --->>> gcc xxx.c --->>> a.out  --->>> ./a.out --->>> 进程
    
    struct task_struct{
        
        pid_t pid;
        struct files_struct *files;
    }; 
    
    struct files_struct {
        struct file *fd_array[NR_OPEN_DEFAULT];
    }
    
    
    struct file{
        const struct file_operations    *f_op  //从inode结构体中获取的
    }
    
    
    inode结构体 --->>> 创建文件的时候创建(mknod --->>> major minor)
    
    
    fs/open.c
    
    SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
    
    --->>> o_sys_open(AT_FDCWD, filename, flags, mode);
    
        --->>> do_filp_open(dfd, tmp, &op, lookup);
        
            --->>> path_openat(dfd, pathname, &nd, op, flags | LOOKUP_RCU);

                --->>> do_last(nd, &path, op, pathname)
                
                    --->>> nameidata_to_filp(nd);
                    
                        --->>> __dentry_open(nd->path.dentry, nd->path.mnt, filp,                                               
                                NULL, cred);
                                
                                --->>>  if (!open && f->f_op)
                                            open = f->f_op->open;
                                --->>>   if (open) {                                                                                                 
                                            error = (*open)(inode, f);    

【一】、创建设备文件

    通过udev(应用层的守护进程)创建  --->>>  通过内核提供的函数创建设备文件
    
    1. class_create
    
       /****************************************************
        *功能:在/sys/class目录下创建目录文件(以name命名)
        *参数:
        *            @owner        THIS_MODULE
        *            @name          目录名字
        *返回值:成功返回struct class *结构体指针,失败
        *         返回ERR_PTR,long IS_ERR(const void *ptr)
        ***************************************************/
        class_create(owner, name)
        void class_destroy(struct class *cls)
        
    2. device_crete
    
       /*****************************************************************************
        *功能:在/sys/class/name目录下创建链接文件
        *参数: 
        *            @class   struct class *结构体指针
        *            @parent  NULL
        *            @devt     设备号 
        *            @drvdata 私有数据
        *            @fmt     格式化内容
        *            @...     不定参数
        *返回值:成功返回struct device *结构体指针,失败
        *         返回ERR_PTR,long IS_ERR(const void *ptr)
        ****************************************************************************/
        struct device *device_create(struct class *class, struct device *parent,
                 dev_t devt, void *drvdata, const char *fmt, ...)
        void device_destroy(struct class *class, dev_t devt)
    
    
【二】、字符设备驱动接口 ———— read & write & ioctl

    应用层:
    
    ssize_t read(int fd, void *buf, size_t count);
    
    
    --->>> 驱动 fops -> read
    
    ssize_t xxx_name(struct file *filp, char *buf , size_t size, loff_t *off)
    {
        
    }
    
    ssize_t write(int fd, const void *buf, size_t count);
    
    ssize_t xxx_name(struct file *filp, const char *buf, size_t, loff_t *);
    
    copy_to_user&copy_from_user
    
    /**************************************************************
     *功能:从内核空间拷贝数据到用户空间 
     *参数:
     *            @to       用户空间地址
     *            @from      内核空间地址
     *            @n        拷贝的个数
     *返回值:成功返回0,失败返回非0
     *************************************************************/
     int copy_to_user(void __user *to, const void *from, int n)
    
    /**************************************************************
     *功能:从用户空间拷贝数据到内核空间
     *参数: 
     *            @to        内核空间地址
     *            @from      用户空间地址
     *            @n        拷贝的个数
     *返回值:成功返回0,失败返回非0
     *************************************************************/
     int copy_from_user(void *to, const void __user *from, int n)
    
    
     #include <sys/ioctl.h>

       ioctl - control device
       
    
       int ioctl(int fd, int request, ...);
       
       long demo_ioctl(struct file *filp, unsigned int cmd, unsigned long xxxx)
       {
            
            return 0;
       }

      ioctl命令码生成:

        # define _IOC_NONE    0U
        # define _IOC_WRITE    1U
        # define _IOC_READ    2U
        
        dir  size type  nr    
        方向 大小 类型  编号
        
        #define _IO(type,nr)        _IOC(_IOC_NONE,(type),(nr),0)
        #define _IOR(type,nr,size)    _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))
        #define _IOW(type,nr,size)    _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
        #define _IOWR(type,nr,size)    _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
       
       #define _IOC(dir,type,nr,size)             \
            (((dir)  << 30) |         \
            ((type) << 8)  |         \
            ((nr)   << 0)   |         \
            ((size) << 16))
       
       
       #define _IOC_DIR(cmd)
       #define _IOC_TYPE(cmd)        
       #define _IOC_NR(cmd)        
       #define _IOC_SIZE(cmd)        
       

【三】、GPIO操作  ---  LED

   /*******************************************************************
    *功能:将物理地址映射成虚拟地址
    *参数:
    *            @offset  物理地址
    *            @size     映射的大小
    *返回值:返回映射后的虚拟地址
    *******************************************************************/
    void __iomem *ioremap(phys_addr_t offset, unsigned long size)
    
    void iounmap(void __iomem *addr)  //虚拟地址
    
    
    xxx_ioremap()
    {
        
    }
    
    xxx_iounmap()
    {
        
    }
    
    led_init()
    {
    
    }
    
    led_on()
    {
    
    }
    
    led_off()
    {
        
    }


【1】作业

    1. 区分一对多(一个驱动程序对应多个同类设备)情况下,到底应用层操作的是哪个设备
    
        提示:通过设备号的次设备号区分
        
    2. struct mydata{
            int a;
            int b;
       };
       
       应用层: 
       
       struct mydata aaa = {
            .a = 10,
            .b = 20
       };
       
       ioclt(fd,11,&aaa);
       
       --->>> demo_ioctl{
                
                printk("a:%d,b:%d\n",...);
              }

    3. led驱动


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值