和传统的驱动一样,platform机制也分为三个步骤:
1、总线注册阶段:
内核启动初始化时的main.c文件中的kernel_init()→do_basic_setup()→driver_init()→platform_bus_init()→bus_register(&platform_bus_type),注册了一条platform总线(虚拟总线,platform_bus)。
2、添加设备阶段:
设备注册的时候Platform_device_register()→platform_device_add()→(pdev→dev.bus = &platform_bus_type)→device_add(),就这样把设备给挂到虚拟的总线上。
3、驱动注册阶段:
Platform_driver_register()→driver_register()→bus_add_driver()→driver_attach()→bus_for_each_dev(), 对在每个挂在虚拟的platform bus的设备作__driver_attach()→driver_probe_device(),判断drv→bus→match()是渗镇悔否执行成功,此时通过指针执行platform_match→strncmp(pdev→name , drv→name , BUS_ID_SIZE),如果相符就调用really_probe(实际就是执行相应设备的platform_driver→probe(platform_device)。)开始真正的探测,如果probe成功,则绑定设备到该驱动。
从上面可以看出,platform机制最后还是调用了bus_register() , device_add() , driver_register()这三个关键的函数。
下面看几个结构体:
[cpp] view plain copy
struct platform_device (/丛正include/linux/Platform_device.h)
{
const char * name
int id
struct device dev
u32 num_resources
struct resource * resource
}
Platform_device结构体描述了一个platform结构的设备,在其中包含了一般设备的结构体struct device dev设备的资源结构体struct resource * resource还有设备的名字const char * name。(注意,这个名字一定要和后面platform_driver.driver àname相同,原因会在后面说明。)
该结构旅局体中最重要的就是resource结构,这也是之所以引入platform机制的原因。
[cpp] view plain copy
struct resource( /include/linux/ioport.h)
{
resource_size_t start
resource_size_t end
const char *name
unsigned long flags
struct resource *parent, *sibling, *child
}
其中 flags位表示该资源的类型,start和end分别表示该资源的起始地址和结束地址(/include/linux/Platform_device.h):
[cpp] view plain copy
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 (*suspend_late)(struct platform_device *, pm_message_t state)
int (*resume_early)(struct platform_device *)
int (*resume)(struct platform_device *)
struct device_driver driver
}
Platform_driver结构体描述了一个platform结构的驱动。其中除了一些函数指针外,还有一个一般驱动的device_driver结构。
名字要一致的原因:
上面说的驱动在注册的时候会调用函数bus_for_each_dev(), 对在每个挂在虚拟的platform bus的设备作__driver_attach()→driver_probe_device(),在此函数中会对dev和drv做初步的匹配,调用的是drv->bus->match所指向的函数。platform_driver_register函数中drv->driver.bus = &platform_bus_type,所以drv->bus->match就为platform_bus_type→match,为platform_match函数,该函数如下:
[cpp] view plain copy
static int platform_match(struct device * dev, struct device_driver * drv)
{
struct platform_device *pdev = container_of(dev, struct platform_device, dev)
return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0)
}
是比较dev和drv的name,相同则会进入really_probe()函数,从而进入自己写的probe函数做进一步的匹配。所以dev→name和driver→drv→name在初始化时一定要填一样的。
不同类型的驱动,其match函数是不一样的,这个platform的驱动,比较的是dev和drv的名字,还记得usb类驱动里的match吗?它比较的是Product ID和Vendor ID。
个人总结Platform机制的好处:
1、提供platform_bus_type类型的总线,把那些不是总线型的soc设备都添加到这条虚拟总线上。使得,总线——设备——驱动的模式可以得到普及。
2、提供platform_device和platform_driver类型的数据结构,将传统的device和driver数据结构嵌入其中,并且加入resource成员,以便于和Open Firmware这种动态传递设备资源的新型bootloader和kernel 接轨。
者轿衡你所指的spidev.c是SPI的用户模式设备接口的驱动,可以通过应用程序去 *** 作/dev/spidev*达到与硬件设备的SPI通信,对于 *** 作SPI NOR FLASH,更多是注册为MTD设备,详细可参考drivers/mtd/device/m25p80.c,里面已经有相关实现。但无论如何,前提是你的内核里已经有SPI控帆轮制器的驱动,否则如何通信呢。代码一般在drivers/spi/里。首做
那是应该是给spi设备驱动范本吧,可以籍此写自己的spi设备驱动,没有设备节点就自己创建个嘛。或者在驱动中添加创建设备节点的函数。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)