前言:对于博客,由于能力有限,很多问题都是自己的学习过程和笔记,现在还没有能力说下自己的独特见解;
前面的几个博客都记录了自己对Linux设备驱动的基础知识,但是现实中的Linux驱动不是那个样子的,要复杂的多些。简单的驱动是device 和driver 一对一的结合,但是现实中一种驱动driver可能够被多个device使用,总不能给一个设备单独写一个独特的driver吧,Linux驱动架构出现了platform平台,一般称为虚拟总线。platform就是把device和driver联系起来,实现驱动的重复使用。platform不是一个具体的实物总线,它是虚拟的用来管理设备和多功能的匹配关系的,这点理解很重要。
一、 了解两个结构体:
(1)struct platform_device ,更好的来管理(RTC,LCD等设备);包含struct devicedev;
(2)struct platform_drivver, 更好的管理设备驱动,包含设备驱动结构体struct device_driver driver;
上面的两个结构体是对简单的驱动 device 和driver的更好的封装,增加了更多的属性信息。
注意:platform_driver地位对等的i2c_driver、spi_driver、usb_driver、pci_driver中都包含了device_driver结构体实例成员。它其实描述了各种xxx_driver(xxx是总线名)在驱动意义上的一些共性;
二、Linux的platform把不同的设备和驱动附在了一起,但是要实现特性设备的驱动,是通过1struct bus_type platform_bus_type 的成员match()函数实现的,match函数的功能是实现通过设备树、ACPI、匹配ID表、设备名和驱动的名字四种匹配方法;
三、具体的使用platform_device是在板级支持包BSP文件中注册,int platform_add_devices(struct platform_device **devs, int num);实际上是调用了platform_device_register()函数来注册平台设备。linux3.x之后可以使用设备树注册设备。
四、使用虚拟总线实现设备驱动程序:
我们以globalfifo为例:
(1)probe函数:
static int globalfifo_probe(struct platform_device *pdev)
{
int ret;
dev_t devno = MKDEV(globalfifo_major, 0);
if (globalfifo_major)
ret = register_chrdev_region(devno, 1, "globalfifo");
else {
ret = alloc_chrdev_region(&devno, 0, 1, "globalfifo");
globalfifo_major = MAJOR(devno);
}
if (ret < 0)
return ret;
globalfifo_devp = devm_kzalloc(&pdev->dev, sizeof(*globalfifo_devp),GFP_KERNEL);
if (!globalfifo_devp) {
ret = -ENOMEM;
goto fail_malloc;
}
globalfifo_setup_cdev(globalfifo_devp, 0);
mutex_init(&globalfifo_devp->mutex);
init_waitqueue_head(&globalfifo_devp->r_wait);
init_waitqueue_head(&globalfifo_devp->w_wait);
return 0;
fail_malloc:
unregister_chrdev_region(devno, 1);
return ret;
}
(2)remove函数
static int globalfifo_remove(struct platform_device *pdev)
{
cdev_del(&globalfifo_devp->cdev);
unregister_chrdev_region(MKDEV(globalfifo_major, 0), 1);
return 0;
}
(3)platform_driver实现:
static struct platform_driver globalfifo_driver = {
.driver = {
.name = "globalfifo",
.owner = THIS_MODULE,
},
.probe = globalfifo_probe,
.remove = globalfifo_remove,
};
module_platform_driver(globalfifo_driver);
(4)platform_device的实现(注意,这个在BSP的平台文件中实现)
static struct platform_device globalfifo_device = {
.name = "globalfifo",
3 .id = -1,
};
(5)module_platform_driver()宏所定义的模块加载和卸载函数仅仅通过platform_driver_register()、platform_driver_unregister()函数进行platform_driver的注册与注销。