學習驅動一定要掌握驅動的模型,platform總線在內核中用的非常頻繁,還有一個是Input輸入子系統,platform總線的好處是,inux從2.6起就加入了一套新的驅動管理和注冊的機制platform平臺總線,是一條虛擬的總線,設備用platform_device表示,驅動用platform_driver進行注冊。于傳統的bus/device/driver機制相比,platform由內核進行統一管理,在驅動中使用資源,提高了代碼的安全性和可移植性。當硬件部分的時序變了或者芯片替換了,我們只需要修改硬件部分的代碼,還有一部分代碼是屬于內核的穩定部分是不用修改的,這就是一種通用的接口。
~~~
1、定義一個platform_device,并注冊 ? ? ?/* 硬件部分 */
2、定義一個platform_driver,并注冊 ? ?/* 穩定部分 */
~~~
~~~
bus_dev_drv模型
dev:(屬于不穩定的部分)
platform_device_register(&led_dev);
static struct resource led_resource[] = {
platform_device_unregister(&led_dev);
static struct resource led_resource[] = {
? ? [0] = {
? ? ? ? .start = 0x56000010, ? ? ? ? ? //gpio_con gpio_dat兩個寄存器占八個字節
? ? ? ? .end ? = 0x56000010 + 8 - 1,//所以需要映射長八個字節
? ? ? ? .flags = IORESOURCE_MEM,
? ? },
? ? [1] = {
? ? ? ? .start ?= 8,
? ? ? ? .end ? = 8,
? ? ? ? .flags = IORESOURCE_IRQ,
? ? }
};
static void led_release(struct device * dev)
{
}
static struct platform_device led_dev = {
.name ? ? ? ? = "myled",
.id ? ? ? = -1,
.num_resources ? ?= ARRAY_SIZE(led_resource),
.resource ? ? = led_resource,
.dev = {?
.release = led_release,?
},
};
drv:(穩定的部分)
struct platform_driver led_drv = {
.probe ?= led_probe,
.remove ?= led_remove,
.driver ?= {
.name = "myled",
}
};
platform_driver_register(&led_drv);
platform_driver_unregister(&led_drv);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);//這兩個函數用開獲取資源
~~~
tips:在這里這個結構體里面的name必須和dev里面的name一致,只有相同的時候才會調用led_probe其他的跟寫普通的字符設備驅動是不變的
這里建講解一個小的技巧,當映射多個連續的地址時候,我們定義成結構體,映射成結構體的地址
~~~
struct s3c_ts_regs {
unsigned long adccon;
unsigned long adctsc;
unsigned long adcdly;
unsigned long adcdat0;
unsigned long adcdat1;
unsigned long adcupdn;
};
~~~
struct s3c_ts_regs ???*s3c_ts_regs; ? /* 定義結構體指針,結構體成員必須是4字節對齊 */
s3c_ts_regs = ioremap(0x58000000, sizeof(struct s3c_ts_regs));