1.實作子產品加載函數
a.申請主裝置号
register_chrdev(major,name,file_operations);
b.建立字元裝置cdev,注冊字元裝置
cdev_alloc cdev_init cdev_add
c.建立裝置檔案
class_create device_create
d.注冊中斷
ret =request_irq(中斷号,...,...,...,...);
e.映射
虛拟位址=ioremap(實體位址,大小)
f.初始化(初始化等待隊列頭,初始化tasklet,初始化工作隊列)
...
2.實作子產品解除安裝函數
3.建構file_operations結構體變量
4.實作操作硬體的方法
xxx_open xxx_write xxx_read
為了提高驅動的可移植性,減少驅動開發周期,最好将跟硬體/平台相關的東西分離出來,以便增強驅動的可移植性
中斷号,實體位址----->歸為裝置資源
最好将裝置資源與裝置驅動分離開來
平台裝置驅動機制
platform_device platform_driver
裝置資源(裝置) <------> 裝置驅動
裝置總線驅動模型:以對象的思想來實作的
每一個裝置對應唯一的一個驅動
每個驅動則可能服務多個裝置
系統中有很多總線:1)實際的實體總線(如:i2c總線,usb總線,SDIO總線,SPI總線...)
2)虛拟總線(隻有一條:平台總線)
/*1.在系統用來表示一個裝置*/
struct device {
struct device_driver *driver; //裝置驅動
struct bus_type *bus; //所屬總線
struct device *parent; //父裝置
dev_t devt; //裝置号
void *platform_data; //私有資料
....
}
/*2.在系統中用來表示裝置驅動*/
struct device_driver {
const char *name; //驅動名字
struct bus_type *bus; //所屬總線
struct module *owner; //擁有者
int (*probe) (struct device *dev); //probe函數
/*3.在系統中用來表示總線*/
struct bus_type {
const char *name; //總線名字
/*mach函數,比對函數,每條總線裡面都會有自己的
*mach,但不同總線的mach的比對方法可能會不同
*/
int (*match)(struct device *dev, struct device_driver *drv);
/*當裝置與驅動比對成功的時候,便會調用probe函數
*不過,一般總線中不會實作probe函數,在比對成功
*的時候,會直接調用裝置驅動中的probe函數
int (*probe)(struct device *dev);
int (*remove)(struct device *dev);
/*1.總線注冊*/
int bus_register(struct bus_type *bus)
void bus_unregister(struct bus_type *bus)
/*2.裝置注冊*/
int device_register(struct device *dev)
void device_unregister(struct device *dev)
/*3.裝置驅動注冊*/
int driver_register(struct device_driver *drv)
void driver_unregister(struct device_driver *drv)
借助于裝置總線驅動模型,虛拟出一條總線,用來實作裝置資源與裝置驅動的比對
===============================================
平台裝置驅動機制采用了:分離的思想,對象的思想
分離的思想:裝置資源與裝置驅動分離開
/*1.平台裝置結構體*/
struct platform_device {
const char * name; //名字
int id;
struct device dev; //裝置結構體
u32 num_resources; //資源數量
struct resource * resource; //裝置資源
const struct platform_device_id *id_entry;
/* arch specific additions */
struct pdev_archdata archdata;
};
/*2.平台驅動結構體*/
struct platform_driver {
int (*probe)(struct platform_device *); //probe函數
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;
/*3.虛拟總線:平台總線結構體*/
struct bus_type platform_bus_type = {
.name = "platform", //總線名字
.dev_attrs = platform_dev_attrs,
.match = platform_match, //比對函數
.uevent = platform_uevent,
.pm = &platform_dev_pm_ops,
/*4.資源結構體*/
struct resource {
resource_size_t start; //起始
resource_size_t end; //結束
const char *name; //名字
unsigned long flags; //标号
struct resource *parent, *sibling, *child;
//平台裝置驅動機制中如何來實作裝置與驅動的比對
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);
/* match against the id table first :可能支援多個裝置*/
if (pdrv->id_table)
return platform_match_id(pdrv->id_table, pdev) != NULL;
/*平台裝置裡面的名字,與裝置驅動裡面的名字比對*/
return (strcmp(pdev->name, drv->name) == 0);
/*核心啟動時的第一個C語言入口函數*/
start_kernel //init/main.c
rest_init
/*建立一個核心線程*/
kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
kernel_init
do_basic_setup //init/main.c
driver_init
platform_bus_init
/*1.注冊平台總線*/
bus_register(&platform_bus_type);
/*1.注冊平台裝置*/
int platform_device_register(struct platform_device *pdev)
void platform_device_unregister(struct platform_device *pdev)
/*2.注冊平台驅動*/
int platform_driver_register(struct platform_driver *drv)
void platform_driver_unregister(struct platform_driver *drv)
/*3.擷取平台資源*/
platform_get_resource(struct platform_device * dev, unsigned int type, unsigned int num)
@成鵬緻遠([email protected])
本文轉自張昺華-sky部落格園部落格,原文連結:http://www.cnblogs.com/sky-heaven/p/5066557.html,如需轉載請自行聯系原作者