目录
platform总线、设备、驱动
Linux2.6以后的设备驱动模型中,需要关注总线设备和驱动这三个实体,总线将设备和驱动绑定,在系统注册一个设备的时候,总线会去匹配驱动,注册驱动的时候,总线回去匹配相应的设备,匹配工作由总线完成
L
inux中有一种总线叫做platform总线,相应的设备称作platform_device,相应的驱动称作platform_driver,所谓的“platform_device”并不是与字符设备、块设备和网络设备并列的概念,而是Linux 系统提供的一种附加手段,例如,在S3C2410 处理器中,把内部集成的I2C、IIS、RTC、看门狗等都归纳为平台设备,而它们本身就是字符设备。
platform设备
platform_device结构体如下所示:
struct platform_device {
const char * name;
int id;
struct device dev;
u32 num_resources;
struct resource * resource;
const struct platform_device_id *id_entry;
/* MFD cell pointer */
struct mfd_cell *mfd_cell;
/* arch specific additions */
struct pdev_archdata archdata;
};
linux2.6ARM平台而言,对platform_device的定义通常在bsp的板文件中定义在板文件中,将platform_device归纳为一个数组,最终通过函数platform_add_devices将设备添加到系统中。函数原型如下所示
int platform_add_devices(struct platform_device **devs, int num)
函数的第一个参数为平台设备数组的指针,第二个参数为平台设备的数量。
linux3.x之后的版本中,人们更倾向于在设备树中添加平台设备
假设我们定义一个platform_device如下所示:
#define PIN_BASE 32
#define CHIPSELECT_2 0x30000000
#define PIN_PC11 (PIN_BASE + 0x40 + 11)
#define GPIO_PF9 9
#define CH_SPI 5
#define DATA_FLAG 5
static struct resource globalmem_resoure[] = {
[0] = {
.start = CHIPSELECT_2,
.end = CHIPSELECT_2 + 3,
.flags = IORESOURCE_MEM
},
[1] = {
.start = CHIPSELECT_2 + 0x44,
.end = CHIPSELECT_2 + 0xFF,
.flags = IORESOURCE_MEM
},
[2] = {
.start = PIN_PC11,
.end = PIN_PC11,
.flags = IORESOURCE_IRQ
| IORESOURCE_IRQ_LOWEDGE | IORESOURCE_IRQ_HIGHEDGE,
},
[3] = {
.start = GPIO_PF9,
.end = GPIO_PF9,
.flags = IORESOURCE_IO,
},
[4] = {
.start = CH_SPI,
.end = CH_SPI,
.flags = IORESOURCE_DMA,
},
};
struct plat_platform {
unsigned long iobase; /* io base address */
unsigned int irq; /* interrupt number */
unsigned int clk; /* UART clock rate */
int flags; /* UPF_* flags */
};
#define PORT(base, int) \
{ \
.iobase = base, \
.irq = int, \
.clk = 1843200, \
.flags = DATA_FLAG, \
}
static struct plat_platform platform_data[] = {
PORT(0x3F8, 4),
PORT(0x2F8, 3),
PORT(0x3E8, 4),
PORT(0x2E8, 3),
{ },
};
static struct platform_device platform_uart_device2 = {
.name = "globalfifo",
.id = -1,
.resource = globalmem_resoure,
.num_resources = ARRAY_SIZE(globalmem_resoure),
.dev = {
.platform_data = platform_data,
}
};
#define PA_IIC1 0xEC20F000
#define IRQ_IIC1 ((5) + 32)
static struct resource i2c_resource[] = {
[0] = {
.start = PA_IIC1,
.end = PA_IIC1 + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_IIC1,
.end = IRQ_IIC1,
.flags = IORESOURCE_IRQ,
},
};
struct platform_device device_i2c1 = {
.name = "s3c2410-i2c",
.id = -1,
.num_resources = ARRAY_SIZE(i2c_resource),
.resource = i2c_resource,
};
#define PA_USBDEV (0x15200140)
#define SZ_USBDEV SZ_1M
#define IRQ_USBD 18
static struct resource usbgadget_resource[] = {
[0] = {
.start = PA_USBDEV,
.end = PA_USBDEV + SZ_USBDEV - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_USBD,
.end = IRQ_USBD,
.flags = IORESOURCE_IRQ,
}
};
struct platform_device device_usbgadget = {
.name = "s3c2410-usbgadget",
.id = -1,
.num_resources = ARRAY_SIZE(usbgadget_resource),
.resource = usbgadget_resource,
};
struct platform_device *globaofifo_device[3] = {
&platform_uart_device2,
&device_i2c1,
&device_usbgadget,
};
EXPORT_SYMBOL(globaofifo_device);
通过下面的函数将设备添加到系统中
ret = platform_add_devices(globaofifo_device, 3);
platform总线
每一个总线都有一个bus_type的实例,platform为platform_bus_type,其中最重的成员为match函数,这个函数为设备和驱动的匹配函数,即前面提过的宗献中用于匹配设备和驱动的函数match
struct bus_type platform_bus_type = {
.name = "platform",
.dev_attrs = platform_dev_attrs,
.match = platform_match,
.uevent = platform_uevent,
.pm = &platform_dev_pm_ops,
};
match主要完成一项工作,就是匹配platform_device和platform_driver,当platform_device和platform_driver匹配成功之后,会调用platform_drivber的probe函数,大部分驱动的初始化工作都是在probe函数中执行。匹配方式有四种:
- 基于设备树的风格匹配
- 基于ACPI的风格匹配
- 匹配id表,即platform_device设备名是否出现在platform_driver的id表中
- 匹配platform_device设备名和驱动的名字
static int platform_match(struct device *dev, struct device_driver *drv)
{
struct platform_device *pdev = to_platform_device(dev);
struct platform_driver *pdrv = to_platform_driver(drv);
/* When driver_override is set, only bind to the matching driver */
if (pdev->driver_override)
return !strcmp(pdev->driver_override, drv->name);
/* Attempt an OF style match first */
if (of_driver_match_device(dev, drv))
return 1;
/* Then try ACPI style match */
if (acpi_driver_match_device(dev, drv))
return 1;
/* Then try to match against the id table */
if (pdrv->id_table)
return platform_match_id(pdrv->id_table, pdev) != NULL;
/* fall-back to driver name match */
return (strcmp(pdev->name, drv->name) == 0);
}
platform驱动
platform_driver结构体如下所示,主要函数为probe和remove函数,一个device_driver实例,和platform_driver地位对等的i2c_driver、spi_driver中都包含了device_driver结构体实例成员,他描述了各种总线在驱动意义上的一些共性
struct platform_driver {
int (*probe)(struct platform_device *);
int (*remove)(struct platform_device *);
void (*shutdown)(struct platform_device *);
int (*suspend)(struct platform_device *, pm_message_t state);
int (*resume)(struct platform_device *);
struct device_driver driver;
const struct platform_device_id *id_table;
};
platform的
匹配id表
驱动代码如下所示
static int globalfifo_probe(struct platform_device *pdev)
{
int ret;
struct resource *res_mem[2];
struct resource *res_irq;
struct resource *res_io;
struct resource *res_dma;
struct plat_platform *platform_data;
ret = misc_register(&zt_misc);
globalmem_devp = kzalloc(sizeof(struct globalmem_dev), GFP_KERNEL);
mutex_init(&globalmem_devp->mutex);
return 0;
fail_malloc:
misc_deregister(&zt_misc);
return ret;
}
static int globalfifo_remove(struct platform_device *pdev)
{
misc_deregister(&zt_misc);
kfree(globalmem_devp);
return 0;
}
static struct platform_device_id platform_device_ids[] = {
{
.name = "globalfifo",
},
{}
};
static struct platform_driver globaofifo_driver = {
.driver = {
.name = "globalfifozhang",
.owner = THIS_MODULE,
},
.probe = globalfifo_probe,
.remove = globalfifo_remove,
.id_table = platform_device_ids,
};
static int __init platform_init(void)
{
return platform_driver_register(&globaofifo_driver);
}
static void __exit platform_exit(void)
{
platform_driver_unregister(&globaofifo_driver);
}
module_init(platform_init);
module_exit(platform_exit);
MODULE_LICENSE("GPL");
platform的
匹配platform_device设备名和驱动的名字
驱动代码如下所示
static int globalfifo_probe(struct platform_device *pdev)
{
int ret;
struct resource *res_mem[2];
struct resource *res_irq;
struct resource *res_io;
struct resource *res_dma;
struct plat_platform *platform_data;
ret = misc_register(&zt_misc);
globalmem_devp = kzalloc(sizeof(struct globalmem_dev), GFP_KERNEL);
if (!globalmem_devp) {
ret = -ENOMEM;
goto fail_malloc;
}
mutex_init(&globalmem_devp->mutex);
return 0;
fail_malloc:
misc_deregister(&zt_misc);
return ret;
}
static int globalfifo_remove(struct platform_device *pdev)
{
misc_deregister(&zt_misc);
kfree(globalmem_devp);
return 0;
}
static struct platform_driver globaofifo_driver = {
.driver = {
.name = "globalfifo",//驱动名字
.owner = THIS_MODULE,
},
.probe = globalfifo_probe,
.remove = globalfifo_remove,
};
static int __init platform_init(void)
{
return platform_driver_register(&globaofifo_driver);
}
static void __exit platform_exit(void)
{
platform_driver_unregister(&globaofifo_driver);
}
module_init(platform_init);
module_exit(platform_exit);
MODULE_LICENSE("GPL");
下一篇:platform设备资源与数据:
https://blog.csdn.net/qq_37600027/article/details/100803447