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---LED驅動
下一篇:Smart210學習記錄-------文件操作
推薦閱讀最新更新時間:2025-04-17 21:28

設計資源 培訓 開發板 精華推薦
- BU4845 4.5V低壓檢測器典型應用電路
- 用于計量的 2V 差分放大器
- LT3095EUDD 5 至 20V 輸入電壓和 5V 和 12V 輸出 SEPIC 穩壓器的典型應用電路
- NCP6324GEVB,基于 NCP6324C 3MHz、2A 高效、低紋波、可調輸出電壓、同步降壓轉換器的評估板
- LT1172CT、-28/1.25A 負升壓穩壓器的典型應用
- RSO-2415D ±15V、34mA輸出DC/DC轉換器的典型應用電路
- LTC3624IDD-5 5V 輸出電壓、2A 同步降壓型穩壓器的典型應用,具有 1MHz、突發模式操作
- ADAU1702,評估板是獨立的 28 位/56 位音頻 DSP,可處理所有系統處理
- CN3163-太陽能-鋰電池充電板
- AP1084 5V低壓降正可調穩壓器典型應用