IMX257 linux设备驱动之Cdev结构

发布时间:2024-08-15  

一、CDEV结构

  1. /*  

  2. *内核源码位置  

  3. *linux2.6.38/include/linux/cdev.h  

  4. */  

  5.     

  6. struct cdev {  

  7.     struct kobject kobj;  

  8.     struct module *owner;   //一般初始化为:THIS_MODULE  

  9.     const struct file_operations *ops;   

  10. //字符设备用到的例外一个重要的结构体file_operations,cdev初始化时与之绑定  

  11.     struct list_head list;  

  12.     dev_t dev;  //主设备号24位 与次设备号8位,dev_t为32位整形  

  13.     unsigned int count;  

  14. };

 

二、file_operation 结构

  1. /* 

  2. ~/include/linux/fs.h 

  3. */  

  4.     

  5. struct file_operations {  

  6.     struct module *owner;  

  7.     loff_t (*llseek) (struct file *, loff_t, int);  

  8.     ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);  

  9.     ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);  

  10.     ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);  

  11.     ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);  

  12.     int (*readdir) (struct file *, void *, filldir_t);  

  13.     unsigned int (*poll) (struct file *, struct poll_table_struct *);  

  14.     long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);  

  15.     long (*compat_ioctl) (struct file *, unsigned int, unsigned long);  

  16.     int (*mmap) (struct file *, struct vm_area_struct *);  

  17.     int (*open) (struct inode *, struct file *);  

  18.     int (*flush) (struct file *, fl_owner_t id);  

  19.     int (*release) (struct inode *, struct file *);  

  20.     int (*fsync) (struct file *, int datasync);  

  21.     int (*aio_fsync) (struct kiocb *, int datasync);  

  22.     int (*fasync) (int, struct file *, int);  

  23.     int (*lock) (struct file *, int, struct file_lock *);  

  24.     ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);  

  25.     unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);  

  26.     int (*check_flags)(int);  

  27.     int (*flock) (struct file *, int, struct file_lock *);  

  28.     ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);  

  29.     ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);  

  30.     int (*setlease)(struct file *, long, struct file_lock **);  

  31.     long (*fallocate)(struct file *file, int mode, loff_t offset,  

  32.               loff_t len);  

  33. };  

 

三、为cdev申请内存

接下来,我们就需要为cdev申请内存,然后再通过cdev_init 函数将cdev与file_operation结构体联系起来,

  1. void cdev_init(struct cdev *cdev, const struct file_operations *fops)  

  2. {  

  3.     memset(cdev, 0, sizeof *cdev);  

  4.     INIT_LIST_HEAD(&cdev->list);  

  5.     kobject_init(&cdev->kobj, &ktype_cdev_default);  

  6.     cdev->ops = fops;  

  7. }  

 

最后通过cdev_add函数,将cdev添加到内核中

  1. int cdev_add(struct cdev *p, dev_t dev, unsigned count)  

  2. {  

  3.     p->dev = dev;  

  4.     p->count = count;  

  5.     return kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p);  

  6. }  

 

四、实例解析

1.自定义一个cdev结构体

如图所示,上述代码中,先自定义一个简单的cdev结构体key_dev,然后再实例化key_device, 接下来就定义一个我们接下来要操作的数组key_buff[MEM_SIZE],MEM_SIZE为自定义的内存的大小。

 

2.在init函数中初始化cdev结构体

当我们的应用程序调用open函数打开设备时,

在init函数中初始化cdev结构体,为cdev结构体开辟内存,连接cdev与fops结构体,注册cdev进入内核

 

3.一旦注册入内核,我们就可以开始使用了

当我们的应用程序打开设备时,在open函数中将filp的private_data赋值为我们所分配的key_device的结构体

 

4.释放cdev内存

当我们不用驱动时自然就要释放我们刚刚开辟的内存。

如图所示,首先删除cdev结构体,然后再使用kfree来释放cdev释放申请的内存

 

5.编译与测试

 

 

如图所示,我们在应用程序中先使用write函数往数组中写入'hello,Lover雪儿'的字符串,然后再使用read函数读取内容,但是,必须注意一点,在每次read后者write前,必须先使用lseek函数中重定位指针。

附上驱动程序源代码:

  1 #include

  2 #include

  3 #include

  4 #include

  5 #include

  6 #include

  7 #include

  8 #include

  9 #include

 10 #include

 11 #include

 12 #include

 13 

 14 #define DEVICE_NAME    'cdev'

 15 #define Driver_NAME 'key_cdev'

 16 

 17 #define KEY_MAJOR 220

 18 #define KEY_MINOR 0

 19 #define COMMAND1 1

 20 #define COMMAND2 2

 21 #define MEM_SIZE 256

 22 

 23 struct key_dev {

 24         struct cdev cdev;

 25 };

 26 struct key_dev *key_device;

 27 static unsigned char key_buff[MEM_SIZE];

 28 

 29 //auto to create device node

 30 static struct class *drv_class = NULL;

 31 static struct class_device *drv_class_dev = NULL;

 32 

 33 static int key_open(struct inode *inode,struct file *filp){

 34     filp->private_data = key_device;

 35     return 0;

 36 }

 37 

 38 static int key_release(struct inode* inode,struct file *filp){

 39     return 0;

 40 }

 41 

 42 static ssize_t key_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos){

 43     ssize_t ret = 0;

 44     loff_t pos = *f_pos;

 45     if(pos > MEM_SIZE)    //如果文件指针偏移超出文件大小

 46         return ret = 0;

 47     if(count > (MEM_SIZE - pos))

 48         count = 256 - pos;    //若内存不足,则写到内存满的位置

 49     pos += count;

 50     //读出数据

 51     if(copy_to_user(buf,key_buff + *f_pos,count)){

 52         return ret = -EFAULT;

 53     }

 54     *f_pos = pos;

 55     return count;

 56 }

 57 

 58 static ssize_t key_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos){

 59     ssize_t ret = -ENOMEM;

 60     loff_t pos = *f_pos;        //获取当前文件指针偏移

 61     if(pos > MEM_SIZE)    //如果文件指针偏移超出文件大小

 62         return ret;

 63     if(count > (MEM_SIZE - pos))

 64         count = 256 - pos;    //若内存不足,则写到内存满的位置

 65     pos += count;

 66     //从fops处开始写入数据

 67     if(copy_from_user(key_buff + *f_pos,buf,count)){

 68         ret = -EFAULT;

 69         return ret;

 70     }

 71     *f_pos = pos;

 72     return count;

 73 }

 74 

 75 static int key_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){

 76     switch(cmd){

 77         case COMMAND1: printk('<0>ncommand 1 n'); break;

 78         case COMMAND2: printk('<0>ncommand 2 n'); break;

 79         default: printk('<0>command default n'); break;

 80     }

 81     return 0;

 82 }

 83 

 84 static loff_t key_llseek(struct file *filp, loff_t off, int whence){

 85     loff_t pos;

 86     pos = filp->f_pos;    //获取文件指针当前位置

 87     switch(whence){

 88         case 0: pos = off;    break;    //重定位到文件开头

文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

相关文章

    与 fasync 函数的功能类似,只是aio_fsync是异步刷新待处理的数据。 2. 字符设备驱动开发 学习裸机或者STM32的时候关于驱动的开发就是初始化相应的外设寄存器,在Linux驱动开发......
    Linux内核LED驱动来理解字符设备驱动开发流程;开发环境 环境说明 详细信息 备注信息 操作系统 Ubunut 18.04.3 LTS 开发板 S3C2440(JZ2440......
    Linux设备驱动开发 - LCD设备驱动分析;一、S3C6410 LCD驱动裸机代码 LCD控制器初始化:  1 unsigned long VideoBuffer[LCD_LOW......
    用层调用,跟linux设备驱动体系类似,这样做的好处在于能统一设备,管你是什么设备,万千接口,你在我这里就是一个总线接口,从而简化应用层的逻辑处理。如下图所示: 之前做了很多linux驱动开发......
    ARM9系列嵌入式处理器S3C2410系统中LCD驱动开发;  本文以三星公司ARM9内核芯片S3C2410的LCD接口为基础,介绍了在Linux平台上开发嵌入式LCD驱动......
    移植作为参考。   参考文献   [1] 李方军,金炜东.嵌入式Linux网络驱动程序的研究与实现[J].现代电子技术,2005(16):20-30.   [2] 宋宝华.Linux设备驱动开发......
    I/O 管理层要说明一下:设备驱动框架层提供了一些接口留给设备驱动开发者去实现,只在做驱动移植的时候需要,作为普通用户,只需要关心 I/O 管理层即可,rt-thread......
    Linux设备驱动开发 - 混杂设备驱动;混杂设备共享一个主设备号MISC_MAJOR(10),次设备号不同。 混杂设备本质上仍然是一个字符设备,所以混杂设备的操作跟字符设备基本相同。 在字符设备......
    。   USB驱动开发依据主从关系的:也就是把USB口这一端作为主设备,也即开发板,USB设备作为从设备,主设备上具备有一个USB控制器来进行设置,   USB驱动开发......
    Linux Platform devices 平台设备驱动;platform平台设备驱动是基于设备总线驱动模型的,它只不过是将 device 进一步封装成为 platform_device,将......

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>