Linux设备驱动开发 - 字符设备驱动

发布时间:2024-09-20  

struct cdev结构体:


1 struct cdev {

2     struct kobject kobj; /* 内嵌的kobject对象 */

3     struct module *owner; /* 所属模块 */

4     const struct file_operations *ops; /* 文件操作结构体 */

5     struct list_head list;

6     dev_t dev; /* 设备号 */

7     unsigned int count;

8 };


struct file_operations原形:


 1 struct file_operations {

 2 struct module *owner;

 3 loff_t (*llseek) (struct file *, loff_t, int);

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

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

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

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

 8 int (*readdir) (struct file *, void *, filldir_t);

 9 unsigned int (*poll) (struct file *, struct poll_table_struct *);

10 long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);

11 long (*compat_ioctl) (struct file *, unsigned int, unsigned long);

12 int (*mmap) (struct file *, struct vm_area_struct *);

13 int (*open) (struct inode *, struct file *);

14 int (*flush) (struct file *, fl_owner_t id);

15 int (*release) (struct inode *, struct file *);

16 int (*fsync) (struct file *, int datasync);

17 int (*aio_fsync) (struct kiocb *, int datasync);

18 int (*fasync) (int, struct file *, int);

19 int (*lock) (struct file *, int, struct file_lock *);

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

21 unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);

22 int (*check_flags)(int);

23 int (*flock) (struct file *, int, struct file_lock *);

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

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

26 int (*setlease)(struct file *, long, struct file_lock **);

27 long (*fallocate)(struct file *file, int mode, loff_t offset,loff_t len);

28 };


file_operations里面的函数会在用户空间执行文件操作时被调用。

read()函数在用户空间执行设备文件读时调用,write()函数在用户空间执行设备文件写时调用,open()函数在用户空间执行设备文件打开时调用。

release()函数在用户空间执行close()时调用。

unlocked_ioctl()在用户空间与之对应的函数为ioctl()函数。

poll()函数用于轮询操作,用户空间与之对应的函数为select()函数。


在设备驱动模块加载函数中要完成的主要工作是对字符设备进行初始化和注册。



字符设备初始化函数:


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

 


字符设备注册函数:


1 int register_chrdev_region(dev_t from, unsigned count, const char *name);

2 int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name);

register_chrdev_region()函数用于已知设备号的情况,from为要注册的设备号,count为需要注册的设备的个数,name为设备名。

alloc_chrdev_region()函数注册可以不提供设备号,系统自动分配一个设备号并保存在参数dev中,baseminor为注册设备的起始设备号,count和name参数跟register_chrdev_region()函数一样。


注册完成后需调用cdev_add()函数将字符设备添加到系统中。


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

参数p为cdev结构体,dev为设备驱动号,count表示要添加的个数。


在设备驱动模块卸载函数中需对字符设备进行注销并释放设备号。



注销字符设备:


1 void cdev_del(struct cdev *p);

需要传进来的参数为字符设备cdev结构体。


 


释放设备号:


1 void unregister_chrdev_region(dev_t from, unsigned count);

from为要释放的字符设备号,count为要释放的个数。


用户空间和内核进行数据的传递需要借助两个函数:


1 copy_to_user(to ,from ,n); //给用户空间拷贝数据

2 copy_from_user(to ,from ,n); //拷贝用户空间的数据到内核

从from拷贝n个字节到to


字符设备驱动模板:


 1 struct cdev xxxx_cdev;

 2 dev_t xxx_devno;

 3 

 4 static int xxx_open(struct inode *node, struct file *filep)

 5 {

 6     int ret = 0;

 7     ...

 8     

 9     return ret;

10 }

11 

12 static ssize_t xxx_read(struct file *filep, char __user *buffer, size_t offset, loff_t *ppos)

13 {

14     ...

15     copy_to_user(buffer,...,...);    //给用户空间拷贝数据

16     ...

17 }

18 

19 static ssize_t xxx_write(struct file *filep, char __user *buffer, size_t offset, loff_t *ppos)

20 {

21     ...

22     copy_from_user(...,buffer,...);  //拷贝用户空间的数据到内核

23     ...

24 }

25 

26 static struct file_operations xxx_fops = 

27 {

28     .open = xxx_open,

29     .write = xxx_write,

30     .read = xxx_read,

31     ...

32 }

33 

34 static int __init xxx_init(void)

35 {

36     ...

37     /* cdev初始化 */

38     cdev_init(&xxx_cdev, &xxx_fops);

39     

40     /* 注册字符设备驱动 */

41     alloc_chrdev_region(&xxx_devno,0,1,DEV_NAME);

42     cdev_add(&xxx_cdev,xxx_devno,1);

43     ...

44 }

45 

46 static void __exit xxx_exit(void)

47 {

48     ...

49     /* 注销设备驱动 */

50     cdev_del(&xxx_cdev);

51     

52     /* 释放设备号 */

53     unregister_chrdev_region(xxx_devno,1);

54     ...

55 }

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

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

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

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

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

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

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

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