Smart210学习记录-------Linux设备驱动结构

发布者:mu22最新更新时间:2025-01-22 来源: cnblogs关键字:Smart210  Linux 手机看文章 扫描二维码
随时随地手机看文章

cdev结构体

 

1 struct cdev {
2 struct kobject kobj; /* 内嵌的 kobject 对象 */
3 struct module *owner; /*所属模块*/
4 struct file_operations *ops; /*文件操作结构体*/
5 struct list_head list;

6    dev_t dev;           /*设备号*/

7 unsigned int count; 
8 }; 


1.struct file_operations {

2 struct module *owner;

3 /* 拥有该结构的模块的指针,一般为 THIS_MODULES */

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

5 /* 用来修改文件当前的读写位置 */

6 ssize_t(*read)(struct file *, char _ _user *, size_t, loff_t*);

7 /* 从设备中同步读取数据 */

8 ssize_t(*write)(struct file *, const char _ _user *, size_t, loff_t*);

9 /* 向设备发送数据*/

10 ssize_t(*aio_read)(struct kiocb *, char _ _user *, size_t, loff_t);

11 /* 初始化一个异步的读取操作*/

12 ssize_t(*aio_write)(struct kiocb *, const char _ _user *, size_t, loff_t);

13 /* 初始化一个异步的写入操作*/

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

15 /* 仅用于读取目录,对于设备文件,该字段为 NULL */

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

17 /* 轮询函数,判断目前是否可以进行非阻塞的读取或写入*/

18 int(*ioctl)(struct inode *, struct file *, unsigned int, unsigned long);

19 /* 执行设备 I/O 控制命令*/

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

21 /* 不使用 BLK 的文件系统,将使用此种函数指针代替 ioctl */

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

23 /* 在 64 位系统上,32 位的 ioctl 调用,将使用此函数指针代替*/

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

25 /* 用于请求将设备内存映射到进程地址空间*/

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

27 /* 打开 */

28 int(*flush)(struct file*);

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

30 /* 关闭*/

31 int (*fsync) (struct file *, struct dentry *, int datasync);

32 /* 刷新待处理的数据*/

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

34 /* 异步 fsync */

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

36 /* 通知设备 FASYNC 标志发生变化*/

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

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

39 /* 通常为 NULL */

40 unsigned long(*get_unmapped_area)(struct file *,unsigned long, unsigned long,

41 unsigned long, unsigned long);

42 /* 在当前进程地址空间找到一个未映射的内存段 */

43 int(*check_flags)(int);

44 /* 允许模块检查传递给 fcntl(F_SETEL...)调用的标志 */

45 int(*dir_notify)(struct file *filp, unsigned long arg);

46 /* 对文件系统有效,驱动程序不必实现*/

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

48 ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t,

49 unsigned int); /* 由 VFS 调用,将管道数据粘接到文件 */

50 ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t,

51 unsigned int); /* 由 VFS 调用,将文件数据粘接到管道 */

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

53 };


Linux 2.6 内核提供了一组函数用于操作 cdev 结构体:

void cdev_init(struct cdev *, struct file_operations *); 用于初始化 cdev 的成员,并建立 cdev 和 file_operations 之间的连接

struct cdev *cdev_alloc(void); cdev_alloc()函数用于动态申请一个 cdev 内存

void cdev_put(struct cdev *p);

int cdev_add(struct cdev *, dev_t, unsigned); cdev_add()函数和 cdev_del()函数分别向系统添加和删除一个 cdev,完成字符设备的注册和注

销。对 cdev_add()的调用通常发生在字符设备驱动模块加载函数中,而对 cdev_del()函数的调用则

通常发生在字符设备驱动模块卸载函数中。

void cdev_del(struct cdev *);


cdev 结构体的 dev_t 成员定义了设备号,为 32 位,其中 12 位主设备号,20 位次设备号。使

用下列宏可以从 dev_t 获得主设备号和次设备号:

MAJOR(dev_t dev)

MINOR(dev_t dev)

而使用下列宏则可以通过主设备号和次设备号生成 dev_t:

MKDEV(int major, int minor)


分配和释放设备号

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

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


void unregister_chrdev_region(dev_t from, unsigned count);


Linux字符设备的组成


1  /* 设备结构体 

2  struct xxx_dev_t { 

3      struct cdev cdev; 

4    ... 

5  } xxx_dev; 

6  /* 设备驱动模块加载函数 

7  static int _ _init xxx_init(void) 

8  { 

9    ... 

10   cdev_init(&xxx_dev.cdev, &xxx_fops); /* 初始化 cdev */ 

11   xxx_dev.cdev.owner = THIS_MODULE; 

12   /* 获取字符设备号*/ 

13   if (xxx_major) { 

14       register_chrdev_region(xxx_dev_no, 1, DEV_NAME); 

15   } else { 

16       alloc_chrdev_region(&xxx_dev_no, 0, 1, DEV_NAME); 

17   } 

18    

19   ret = cdev_add(&xxx_dev.cdev, xxx_dev_no, 1); /* 注册设备*/ 

20   ... 

21 } 

22 /*设备驱动模块卸载函数*/ 

23 static void _ _exit xxx_exit(void) 

24 { 

25    unregister_chrdev_region(xxx_dev_no, 1); /* 释放占用的设备号*/ 

26    cdev_del(&xxx_dev.cdev); /* 注销设备*/ 

27   ... 

28 } 

29 module_init(xxx_init);

30 module_exit(xxx_exit);


字符设备驱动的 file_operations 结构体中成员函数


1   /* 读设备*/ 

2   ssize_t xxx_read(struct file *filp, char __user *buf, size_t count, 

3       loff_t*f_pos) 

4   { 

5       ... 

6       copy_to_user(buf, ..., ...); 

7       ... 

8   } 

9   /* 写设备*/ 

10  ssize_t xxx_write(struct file *filp, const char __user *buf, size_t count, 

11      loff_t *f_pos) 

12  { 

13      ... 

14      copy_from_user(..., buf, ...); 

15      ... 

16  } 

17  /* ioctl 函数 */ 

18  int xxx_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, 

19      unsigned long arg) 

20  { 

21      ... 

22      switch (cmd) { 

23      case XXX_CMD1: 

24            ... 

25            break; 

26      case XXX_CMD2: 

27            ... 

28            break; 

29      default: 

30            /* 不能支持的命令 */ 

31            return  - ENOTTY; 

32      } 

33      return 0; 

34  } 


设备驱动的读函数中,filp 是文件结构体指针,buf 是用户空间内存的地址,该地址在内核空

间不能直接读写,count 是要读的字节数,f_pos 是读的位置相对于文件开头的偏移。

写函数同理

由于内核空间与用户空间的内存不能直接互访,因此借助了函数 copy_from_user()完成用户空间

到内核空间的拷贝,以及copy_to_user()完成内核空间到用户空间的拷贝,见代码第6行和第14行。

完成内核空间和用户空间内存拷贝的 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);

上述函数均返回不能被复制的字节数,因此,如果完全复制成功,返回值为 0。


在字符设备驱动中,需要定义一个 file_operations 的实例,并将具体设备驱动的函数赋值给

file_operations 的成员,例如:

1 struct file_operations xxx_fops = {

2 .owner = THIS_MODULE,

3 .read = xxx_read,

4 .write = xxx_write,

5 .ioctl = xxx_ioctl,

6 ...

7  }


关键字:Smart210  Linux 引用地址:Smart210学习记录-------Linux设备驱动结构

上一篇:Smart210---LED驱动
下一篇:Smart210学习记录-------文件操作

推荐阅读最新更新时间:2026-03-25 11:47

Smart210学习记录-------Linux设备驱动结构
cdev结构体 1 struct cdev { 2 struct kobject kobj; /* 内嵌的 kobject 对象 */ 3 struct module *owner; /*所属模块*/ 4 struct file_operations *ops; /*文件操作结构体*/ 5 struct list_head list; 6 dev_t dev; /*设备号*/ 7 unsigned int count; 8 }; 1.struct file_operations { 2 struct module *owner; 3 /* 拥有该结构的模块的指针,一般为 THIS_MODULES */ 4 l
[单片机]
<font color='red'>Smart210</font>学习记录-------<font color='red'>Linux</font><font color='red'>设备驱动</font><font color='red'>结构</font>
IMX257 linux设备驱动之Cdev结构
一、CDEV结构 /* *内核源码位置 *linux2.6.38/include/linux/cdev.h */ struct cdev { struct kobject kobj; struct module *owner; //一般初始化为:THIS_MODULE const struct file_operations *ops; //字符设备用到的例外一个重要的结构体file_operations,cdev初始化时与之绑定 struct list_head list; dev_t dev; //主设备号24位 与次设备号8位,dev_t为32
[单片机]
IMX257 <font color='red'>linux</font><font color='red'>设备驱动</font>之Cdev<font color='red'>结构</font>
Smart210学习记录-------linux内核模块
Linux 驱动工程师需要牢固地掌握 Linux 内核的编译方法以为嵌入式系统构建可运行的 Linux 操作系统映像。在编译 LDD6410 的内核时,需要配置内核,可以使用下面命令中的 一个: #make config(基于文本的最为传统的配置界面,不推荐使用) #make menuconfig(基于文本菜单的配置界面) #make xconfig(要求 QT 被安装) #make gconfig(要求 GTK+被安装) 在配置Linux 2.6内核所使用的make config、make menuconfig、make xconfig和make gconfig这 4 种方式中,最值得推荐的是 make menuconfig,它
[单片机]
Smart210学习记录-----linux定时器
1.内核定时器:   Linux 内核所提供的用于操作定时器的数据结构和函数如下: (1) timer_list   在 Linux 内核中,timer_list 结构体的一个实例对应一个定时器   1 struct timer_list { 2        struct list_head entry; /* 定时器列表 */ 3       unsigned long expires; /*定时器到期时间*/ 4        void (*function)(unsigned long); /* 定时器处理函数 */ 5       unsigned long data; /* 作为参数被传入定
[单片机]
Smart210学习记录-------内存初始化
br br br br br br DMC0_PRECHCONFIG = 0xFF000000; DMC0_PWRDNCONFIG = 0xFFFF00FF; DMC0_TIMINGAREF = 0x00000618; DMC0_TIMINGROW = 0x28233287; DMC0_TIMINGDATA = 0x23240304; DMC0_TIMINGPOWER = 0x09C80232; DMC0_PHYSTSTUS0 = 0x4;//11 PHY DLL is locked DMC0_DIRECTCMD = 0x07000000; DMC0_DIRECTCMD = 0x01000000;//所有板
[单片机]
Smart210学习记录-------文件操作
一.linux文件操作(只能在linux系统上用) 创建: int creat(const char* filename, mode_t mode) filename 表示要创建的文件名,mode表示对该文件的读写权限 int umask(int newmask) 调用将 umask 设置为 newmask,然后返回旧的 umask,它只影响读、写和执行权限 S_IRUSR 用户可以读 S_IWUSR 用户可以写 S_IXUSR 用户可以执行 。。。等等 除了可以通过上述宏进行“或”逻辑产生标志以外,我们也可以自己用数字来表示,Linux 用 5 个数字来表示文件的各种权限:第一位表示设置用户 ID;第二位表示设置组 ID;第三位
[单片机]
[smart210] Nand Flash K9F4G08U0B 的配置与读写控制(一)
平台:smart210 CPU:s5pv210 目标:控制核心板上的Nand Flash,对其进行读写操作,本文为基本配置篇 知识储备:从tiny210v2核心板上我们发现,nand flash的型号是K9F4G08U0B,根据nand flash的命名规则,我们不难发现这是一块4Gbits大小的单位地址存储x8bits的SLC nand flash存储器,存储空间换算过来就是512M x 8 bits 。在相似型号K9F4G08U0A的datasheet中发现这种型号的flash具有4096个Blocks,每个Block有64个Pages,每个Pages有2048Bytes的数据,综合起来就是 4096*64*2048 *8bi
[单片机]
[<font color='red'>smart210</font>] Nand Flash K9F4G08U0B 的配置与读写控制(一)
[smart210] Nand Flash K9F4G08U0B 的配置与读写控制(二)
平台:smart210 CPU:s5pv210 目标:控制核心板上的Nand Flash,对其进行读写操作,本文为上文续篇,主要实现的是对nand flash进行读/写与块擦除操作 void nand_init(void) { // 1. config nandflash controller NFCONF = (TACLS 12)|(TWRPH0 8)|(TWRPH1 4)|(0 3)|(0 2)|(1 1)|(0 0); NFCONT = (0 18)|(0 17)|(0 16)|(0 10)|(0 9)|(0 8)|(0 7)|(0 6)|(0x3 1)|(1 0); // 2. config
[单片机]
[<font color='red'>smart210</font>] Nand Flash K9F4G08U0B 的配置与读写控制(二)
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved