首页 > 代码库 > 06 字符设备---静态注册

06 字符设备---静态注册

一、字符设备结构体

技术分享
 1 /* #include <linux/cdev.h> */
 2 struct cdev {
 3     struct kobject kobj;
 4     struct module *owner;
 5     const struct file_operations *ops;
 6     struct list_head list;
 7     dev_t dev;
 8     unsigned int count;
 9 };
10 
11 /* #include <linux/fs.h> */
12 struct file_operations {
13     struct module *owner;
14     loff_t (*llseek) (struct file *, loff_t, int);
15     ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
16     ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
17     ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
18     ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
19     ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
20     ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
21     int (*iterate) (struct file *, struct dir_context *);
22     unsigned int (*poll) (struct file *, struct poll_table_struct *);
23     long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
24     long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
25     int (*mmap) (struct file *, struct vm_area_struct *);
26     int (*open) (struct inode *, struct file *);
27     int (*flush) (struct file *, fl_owner_t id);
28     int (*release) (struct inode *, struct file *);
29     int (*fsync) (struct file *, loff_t, loff_t, int datasync);
30     int (*aio_fsync) (struct kiocb *, int datasync);
31     int (*fasync) (int, struct file *, int);
32     int (*lock) (struct file *, int, struct file_lock *);
33     ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
34     unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
35     int (*check_flags)(int);
36     int (*flock) (struct file *, int, struct file_lock *);
37     ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
38     ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
39     int (*setlease)(struct file *, long, struct file_lock **, void **);
40     long (*fallocate)(struct file *file, int mode, loff_t offset, loff_t len);
41     int (*show_fdinfo)(struct seq_file *m, struct file *f);
42 };
View Code

二、字符设备驱动流程

xxx_init():

1. 分配一个struct cdev结构体,静态或者动态

2. 注册设备号

3. 初始化struct cdev

4. 添加字符设备到操作系统中

xxx_exit():

1. 删除字符设备

2. 注销设备号

三、例子

1. 字符设备驱动

技术分享
  1 #include <linux/init.h>
  2 #include <linux/module.h>
  3 #include <linux/cdev.h>
  4 #include <linux/fs.h>
  5 
  6 #define MAJOR_NUM 233
  7 
  8 // 定义结构体类型
  9 struct char_device
 10 {
 11     struct cdev cdev;
 12 };
 13 
 14 // 定义字符设备对象
 15 struct char_device char_device;
 16 
 17 int char_device_open(struct inode *inode, struct file *file)
 18 {
 19     printk("char_device_open\n");
 20     return 0;
 21 }
 22 
 23 int char_device_release(struct inode *inode, struct file *file)
 24 {
 25     printk("char_device_release\n");
 26     return 0;
 27 }
 28 
 29 ssize_t char_device_read(struct file *file, char __user *ubuf, size_t size, loff_t *offset)
 30 {
 31     printk("char_device_read\n");
 32     return 0;
 33 }
 34 
 35 ssize_t char_device_write(struct file *file, const char __user *ubuf, size_t size, loff_t *offset)
 36 {
 37     printk("char_device_write\n");
 38     return size;
 39 }
 40 
 41 struct file_operations fops = {
 42     .owner = THIS_MODULE,
 43     .open = char_device_open,
 44     .release = char_device_release,
 45     .read = char_device_read,
 46     .write = char_device_write,
 47 };
 48 
 49 static int char_device_init(void)
 50 {
 51     int ret = 0;
 52     dev_t dev_num = 0;
 53 
 54     // 设备号
 55     dev_num = MKDEV(MAJOR_NUM, 0);
 56 
 57     // 注册设备号
 58     ret = register_chrdev_region(dev_num, 1, "char_device");
 59     if (ret != 0)
 60     {
 61         printk("register_chrdev_region error\n");
 62         goto err_register_chrdev_region;
 63     }
 64 
 65     // 初始化struct cdev
 66     cdev_init(&(char_device.cdev), &fops);
 67 
 68     // 添加字符设备
 69     ret = cdev_add(&(char_device.cdev), dev_num, 1);
 70     if (ret != 0)
 71     {
 72         printk("cdev_add error\n");
 73         goto err_cdev_add;
 74     }
 75 
 76     printk("char_device_init\n");
 77     return 0;
 78 
 79 err_cdev_add:
 80     // 注销设备号
 81     unregister_chrdev_region(dev_num, 1);
 82 
 83 err_register_chrdev_region:
 84     return ret;
 85 }
 86 
 87 static void char_device_exit(void)
 88 {
 89     dev_t dev_num = MKDEV(MAJOR_NUM, 0);
 90 
 91     // 删除字符设备
 92     cdev_del(&(char_device.cdev));
 93 
 94     // 注销设备号
 95     unregister_chrdev_region(dev_num, 1);
 96 
 97     printk("char_device_exit\n");
 98     return;
 99 }
100 
101 module_init(char_device_init);
102 module_exit(char_device_exit);
103 
104 MODULE_LICENSE("GPL");
105 MODULE_AUTHOR("GNB");
char_device.c

2. Makefile

技术分享
 1 KERNEL_DIR = /lib/modules/$(shell uname -r)/build
 2 PWD = $(shell pwd)
 3 
 4 ifneq ($(KERNELRELEASE),)
 5 
 6 obj-m := char_device.o
 7 
 8 else
 9 
10 .PHONY:default clean
11 
12 default:
13     $(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules
14 
15 clean:
16     $(MAKE) -C $(KERNEL_DIR) M=$(PWD) clean
17 
18 endif
Makefile

四、测试

(1)加载模块

sudo insmod mydev.ko

(2)创建设备节点并且指定权限

sudo mknod /dev/char_device c 233 0

sudo chmod 666 /dev/char_device

(3)测试字符设备

cat /dev/char_device      【读设备】

echo "test" > /dev/char_device 【写设备】

06 字符设备---静态注册