总线设备驱动简述
- 因此很多时候我们不需要去为每个设备都写一个驱动,很多设备的驱动方式都是一样的,显然驱动是可以共用一套的。为了尽可能解决设备之前的兼容问题,Linux 之后又引入了基于 platform 驱动模型,该驱动模型将设备抽象为总线上的节点。
- platform 模型又称为总线驱动模型,该模型将整个驱动主要分为三个部分,即总线、驱动、设备。这三个部分是独立的,也就是即使没有相应的驱动,设备也可以被加载,但可能无法正常工作,同理,即使总线不存在,驱动也可能存在。
- 总线相当于胶水,驱动和设备相当于两个独立的物体,总线会设备和驱动粘合在一起,从而实现驱动和设备的绑定。Platform 驱动模型最大的好处就是可以让一个驱动可以与多个设备绑定,也就是多个设备可以共用一个驱动。

设备和驱动注册(未引入 dts)
static struct resource led_resource[] =
{
[0] = {
.start = 0x01c20891,
.end = 0x01c20893,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 0x01c20894,
.end = 0x01c20897,
.flags = IORESOURCE_MEM,
},
[2] = {
.start = 0x01c208A0,
.end = 0x01c208A3,
.flags = IORESOURCE_MEM,
},
[3] = {
.start = 0x01c20891,
.end = 0x01c20893,
.flags = IORESOURCE_MEM,
},
};
static void led_release(struct device* dev)
{
}
static struct platform_device led_dev =
{
.name = "led",
.id = -1;
.num_resources = ARRRAY_SIZE(led_resource);
.resource=led_resource,
.dev = {
.release=led_release,
},
}
static int led_dev_init(void)
{
platform_device_register(&led_dev);
return 0;
}
static void led_dev_exit(void)
{
platform_device_unregister(&led_dev);
}
module(led_dev_init);
module_exit(led_dev_exit);
MODULE_LICENSE("GPL");
static struct platform_driver led_driver =
{
.probe=led_probe,
.remove=led_remove,
.driver = {
.name="led",
},
}
static int __init led_init(void)
{
ret = platform_driver_register(&led_driver);
return ret;
}
static void __exit led_exit(void)
{
platform_driver_unregister(&led_driver);
}
static dev_t led_dev_num;
static struct cdev* led_dev;
static struct class* led_class;
static struct device* led0;
size_t* gpioe_cfg0;
size_t* gpioe_cfg1;
size_t* gpioe_data;
size_t* gpioe_pul0;
static struct file_operations led_ops = {
.owner=THIS_MODULE,
.open=led_open,
.read=led_read,
.write=led_write,
.release=led_close,
};
static int led_probe(struct platform_device* pdev)
{
struct resource* res;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
gpioe_cfg0 = ioremap(res->start,(res->end - res->start)+1);
alloc_chrdev_region(&led_dev_num, 0, 1, "led");
led_dev->owner = THIS_MODULE;
led_dev->ops = &led_ops;
cdev_add(led_dev, led_dev_num, 1)
led_class = class_create(THIS_MODULE,"led_class");
led0 = device_create(led_class, NULL, led_dev_num, NULL, "led0");
return 0;
}
static int led_remove(struct platform_device* pdev)
{
cdev_del(led_dev);
unregister_chrdev_region(led_dev_num,1);
device_destroy(led_class, led_dev_num);
class_destroy(led_class);
iounmap(gpioe_cfg0);
return 0;
}
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
设备和驱动注册(引入 dts)
- 内核自动将设备数上的设备节点(devicenode)–》平台设备(platform_device)
led@0x01c20800{
compatible="lite200,led"
reg = < 0x01C20890 0x04
0x01C20894 0x04
0x01C208A0 0x04
0x01C208AC 0x04 >;
status = "okay";
}
static struct platform_driver led_driver =
{
.probe = led_probe,
.remove = led_remove,
.driver = {
.name = "led",
.of_match_table = led_match_table,
},
.id_table = led_device_ids,
};
static int led_probe(struct platform_device* pdev)
{
struct resource* res;
int ret;
led_dev = cdev_alloc();
ret = alloc_chrdev_region(&led_dev_num, 0, 1, "led");
led_dev->owner = THIS_MODULE;
led_dev->ops = &led_ops;
cdev_add(led_dev, led_dev_num, 1);
led_class = class_create(THIS_MODULE, "led_class");
led0 = device_create(led_class, NULL, led_dev_num, NULL, "led0");
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
gpioe_cfg0 = ioremap(res->start, (res->end - res->start) + 1);
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
gpioe_cfg1 = ioremap(res->start, (res->end - res->start) + 1);
res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
gpioe_data = ioremap(res->start, (res->end - res->start) + 1);
res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
gpioe_pul0 = ioremap(res->start, (res->end - res->start) + 1)
return 0;
}
static struct of_device_id led_match_table[] = {
{".compatible = lite200,led",},
};
static struct platform_device_id led_device_ids[] = {
{.name="led",},
};
static int led_remove(struct platform_device* pdev)
{
iounmap(gpioe_cfg0);
iounmap(gpioe_cfg1);
iounmap(gpioe_data);
iounmap(gpioe_pul0);
cdev_del(led_dev);
unregister_chrdev_region(led_dev_num, 1);
device_destroy(led_class, led_dev_num);
class_destroy(led_class);
return 0;
}
static struct file_operations led_ops = {
.owner = THIS_MODULE,
.open = led_open,
.read = led_read,
.write = led_write,
.release = led_close,
};
static int led_open(struct inode* inode, struct file* file) {
*((volatile size_t*)gpioe_cfg1) &= ~(7 << 16);
*((volatile size_t*)gpioe_cfg1) |= (1 << 16);
*((volatile size_t*)gpioe_pul0) &= ~(3 << 16);
*((volatile size_t*)gpioe_pul0) |= (1 << 12);
printk(KERN_DEBUG"open led!!!\n");
return 0;
}
static int led_close(struct inode* inode, struct file* filp) {
printk(KERN_DEBUG"close led!!!\n");
return 0;
}
static int led_read(struct file* filp, char __user* buff, size_t count, loff_t* offp) {
int ret;
size_t status = *((volatile size_t*)gpioe_data);
ret = copy_to_user(buff, &status, 4);
if (ret < 0)
printk(KERN_DEBUG"read error!!!\n");
else
printk(KERN_DEBUG"read led ok!!!\n");
return 0;
}
static int led_write(struct file* filp, const char __user* buff, size_t count, loff_t
* offp) {
int ret;
size_t status;
ret = copy_from_user(&status, buff, 4);
if (ret < 0)
printk(KERN_DEBUG"write error!!!\n");
else
printk(KERN_DEBUG"write led ok!!!\n");
*((volatile size_t*)gpioe_data) &= ~(1 << 12);
if (status)
*((volatile size_t*)gpioe_data) |= (1 << 12);
return 0;
}
static int led_driver_init(void)
{
platform_driver_register(&led_driver);
return 0;
}
static void led_driver_exit(void)
{
platform_driver_unregister(&led_driver);
}
module_init(led_driver_init);
module_exit(led_driver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("1477153217@qq.com");
MODULE_VERSION("0.1");
MODULE_DESCRIPTION("led_driver");
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
杂项字符设备msic
- 有些设备可能并不属于字符设备、块设备、网络设备这三种,而是类似于字符设备
- Linux 内核提供了一个新的设备类型,也就是 miscdevice。一般称该类型为杂项设备,
- 但其实该设备广泛上说还是属于字符设备,只是该设备使用的结构体不是 cdev,而是 miscdevice 结构体。
- 所有的 misc 设备的主设备号都是 10,因此这样我们不需要自己指定主设备号了
- 在misc_register 函数中已经对设备进行了动态分配,同时调用了 class_create 和 device_create 实现了设备节点的自动创建。
- 其 misc_deregister 函数也是一样,其内部已经实现了设备节点的注销。
static struct miscdevice misc_led_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "miscled",
.fops = &miec_led_fops,
}
static int misc_led_close(struct inode* inode, struct file* filp)
{
printk(KERN_DEBUG"close led!!\n");
return 0;
}
static int misc_led_read(struct file* filp, char __user* buff, size_t count, loff_t* offp)
{
int ret;
size_t status = *((volatile size_t*)gpioe_data);
ret = copy_to_user(buff, &status, 4);
if (ret < 0)
printk(KERN_DEBUG"read error!!!\n");
else
printk(KERN_DEBUG"read led ok!!!\n");
return 0;
}
static int misc_led_write(struct file* filp, const char __user* buff, size_t count,loff_t* offp)
{
int ret;
size_t status;
ret = copy_from_user(&status, buff, 4);
if (ret < 4)
printk(KERN_DEBUG"read error!!!\n");
else
printk(KERN_DEBUG"read led ok!!!\n");
*((volatile size_t*)gpioe_data) &= ~(1 << 12);
if(status)
*((volatile size_t*)gpioe_data) &= (1 << 12);
return 0;
}
static struct file_operations misc_led_ops = {
.owner = THIS_MODULE,
.open = misc_led_open,
.read = misc_led_read,
.write = misc_led_write,
.release = misc_led_close,
};
static int misc_led_probe(struct platform_device* pdev)
{
struct resource* res;
int ret;
misc_register(&misc_led_dev);
res = platform_get_resource(pdev,IORESOURCE_MEM,0);
gpioe_cfg0 = ioremap(res->start,(res->end - res->start)+1);
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
gpioe_cfg1 = ioremap(res->start, (res->end - res->start) + 1);
res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
gpioe_data = ioremap(res->start, (res->end - res->start) + 1);
res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
gpioe_pul0 = ioremap(res->start, (res->end - res->start) + 1);
return 0;
}
static int misc_led_remove(struct platform_device* pdev)
{
iounmap(gpioe_cfg0);
iounmap(gpioe_cfg1);
iounmap(gpioe_data);
iounmap(gpioe_pul0);
misc_deregister(&misc_led_dev);
return 0;
}
static struct of_device_id misc_led_match_table[] = {
{.compatible = "lite200,misc_led",}
};
static struct platform_device_id misc_led_device_ids[] = {
{.name="misc_led",},
};
static struct platform_driver misc_led_driver = {
.probe = misc_led_probe,
.remove = misc_led_remove,
.driver = {
.name = "misc_led",
.of_match_table = misc_led_match_table,
},
.id_table = misc_led_device_ids,
};
static int misc_led_driver_init(void)
{
platform_driver_register(&misc_led_driver);
return 0;
}
static void misc_led_driver_exit(void) {
platform_driver_unregister(&misc_led_driver);
}
module_init(misc_led_driver_init);
module_exit(misc_led_driver_exit);\
MODULE_LICENSE("GPL");
MODULE_AUTHOR("1477153217@qq.com");
MODULE_VERSION("0.1");
MODULE_DESCRIPTION("misc_led_driver");
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109