14_字符设备另一种写法
文章目录
1、字符设备框架对比
之前的字符设备驱动框架:
缺点:
修改后的框架:
修改后:程序按照主设备号、次设备号来打开设备,这样同一个主设备号下可以对应多个file_operation结构体,对应多个次设备号。
2、新的字符设备驱动程序编写
2.1、在hello.c中
2.1.1、确定主设备号
/* 1. 分配主设备号 */
static int major;
2.1.5、定义测试所用的open函数
static int hello_open(struct inode *inode, struct file *file)
{
printk("hello_open\n");
return 0;
}
static int hello2_open(struct inode *inode, struct file *file)
{
printk("hello2_open\n");
return 0;
}
2.1.2、构造file_operations
static struct file_operations hello_fops = {
.owner = THIS_MODULE,
.open = hello_open,
};
static struct file_operations hello2_fops = {
.owner = THIS_MODULE,
.open = hello2_open,
};
2.1.3、告诉内核
#define HELLO_CNT 2
/* 3.1 定义一个cdev结构体 */
static struct cdev hello_cdev;
static struct cdev hello2_cdev;
/* 4.1 定义一个类 */
static struct class *cls;
/* 在入口函数中告诉内核 */
static int hello_init(void)
{
dev_t devid;
/* 3. 告诉内核 */
#if 0
/* 以前是这样
* (major, 0), (major, 1), ...(major, 255)都对应hello_fops
*/
major = register_chrdev(0, "hello", &hello_fops);
#else
/* 3.2 分配主次设备号 */
if(major) { /* 若自己指定主设备号 */
/* 参一:主设备号
* 参二:次设备号开始的下标
*/
devid = MKDEV(major, 0);
/* (major, 0~1)对应hello_fops, (major, 2~255)d都不对应hello_fops
* 参二:次设备号个数
*/
register_chrdev_region(devid, HELLO_CNT, "hello");
} else { /* 若由系统自动分配主设备号 */
/* (major, 0~1)对应hello_fops, (major, 2~255)d都不对应hello_fops
* 参二:次设备号开始的下标
* 参三:次设备号个数
*/
alloc_chrdev_region(&devid, 0, HELLO_CNT, "hello");
major = MAJOR(devid);
}
/* 3.3 初始化cdev,绑定fops结构体 */
cdev_init(&hello_cdev, &hello_fops);
/* 3.4 注册cdev */
cdev_add(&hello_cdev, devid, HELLO_CNT);
/* 3.5 分配第二个fops对应设备的次设备号 */
devid = MKDEV(major, 2);
/* (major, 2)对应hello2_fops, (major, 0、1;3~255)都不对应hello2_fops
* 注册第二个fops对应的设备
*/
register_chrdev_region(devid, 1, "hello2");
/* 初始化cdev,绑定第二个fops结构体 */
cdev_init(&hello2_cdev, &hello2_fops);
/* 注册第二个cdev */
cdev_add(&hello2_cdev, devid, 1);
#endif
cls = class_create(THIS_MODULE, "hello");
class_device_create(cls, NULL, MKDEV(major, 0), NULL, "hello0"); /* /dev/hello0 */
class_device_create(cls, NULL, MKDEV(major, 1), NULL, "hello1"); /* /dev/hello1 */
class_device_create(cls, NULL, MKDEV(major, 2), NULL, "hello2"); /* /dev/hello2 */
class_device_create(cls, NULL, MKDEV(major, 3), NULL, "hello3"); /* /dev/hello2 */
return 0;
}
2.1.4、在出口函数hello_exit中
static void hello_exit(void)
{
/* 删除类下面的设备 */
class_device_destroy(cls, MKDEV(major, 0));
class_device_destroy(cls, MKDEV(major, 1));
class_device_destroy(cls, MKDEV(major, 2));
class_device_destroy(cls, MKDEV(major, 3));
/* 删除类 */
class_destroy(cls);
/* 卸载cdev */
cdev_del(&hello_cdev);
/* 删除创建的区域 */
unregister_chrdev_region(MKDEV(major, 0), HELLO_CNT);
cdev_del(&hello2_cdev);
unregister_chrdev_region(MKDEV(major, 2), 1);
}
2.2、在hello_test中
/* hello_test <dev> */
void print_usage(char *file)
{
printf("%s <dev>\n", file);
}
int main(int argc, char **argv)
{
int fd;
if(argc != 2)
{
print_usage(argv[0]);
return 0;
}
fd = open(argv[1], O_RDWR);
if(fd < 0)
printf("can't open %s\n", argv[1]);
else
printf("can open %s\n", argv[1]);
return 0;
}
2.3、修饰
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
3、测试
1th:
测试驱动程序
2th:
加上测试程序hello_test
打开hello0、1、2都能打开,都有对应的file_operations结构体;
打不开hello3,缺少对应的file_operations结构体。