Download presentation
Presentation is loading. Please wait.
1
Linux设备驱动 (基于Linux2.6.xx内核)
2
总线、设备和驱动程序 总线是处理器与一个或多个设备之间的通 道。在设备模型中,所有的设备都是通过总线
相连的。设备将被挂在总线上。在注册此种总 线类型的驱动程序后,它将用于管理挂在此类 型总线上的设备。 以Luxun9项目中所用到的设备及其驱动程 序为例。总体框图如下所示:
4
总线 以Luxun9项目所用到的总线为例,它所使用的是虚 拟平台总线,代码如下所示:
struct bus_type platform_bus_type = { .name = "platform", .match = platform_match, .suspend = platform_suspend, .resume = platform_resume, }; 只有非常少的bus_type成员变量需要初始化,其他 的大多数都由设备模型核心所控制。
5
对于新的总线,我们要调用bus_register()函数进行注册。
以Luxun9项目所用到的总线为例,代码如下所示: ret = bus_register(&platform_bus_type); if(ret) { return ret //失败 } 如果调用成功,新的总线子系统将加入到系统中, 可以在/sys/bus目录下看到它所对应的目录是 /sys/bus/platform 。然后,我们可以向这个总 线添加设备。
6
设备 例如:在luxun9项目中所用到的Linux2.6.14内核中 常用的注册和注销函数是:
int device_register(struct device *dev); void device_unregister(struct device *dev); 实际上,一个实际的总线是一个设备,也必须被单 独注册。当然,我们也可以注册虚拟总线。 例如:在luxun9项目中所用到的Linux2.6.14内核中 注册了这样的一个虚拟总线,代码如下所示:
7
struct device platform_bus = {
.bus_id = "platform", }; device_register(&platform_bus); 完成这个调用后,我们可以在/sys/devices目录 中看到它(/sys/devices/platform),任何添加 到该总线的设备都会在/sys/devices/platform/ 显示。
8
设备结构的嵌入 device结构包含了设备模型核心用来模拟系统的信 息。然而,大多数子系统记录了它们所拥有的设备的所
道。
9
例如:在luxun9项目中所用到的Linux2.6.14内核中
有这样一个结构体,代码如下所示: struct platform_device { const char * name; u32 id; struct device dev; u32 num_resources; struct resource * resource; }; 用它定义了一个USB设备结构体,代码如下所示:
10
static struct platform_device s1r72xxx_device = {
.name = "s1r72v17", .id = -1, .dev = { .platform_data = (void*)NULL, .dma_mask = &s1r72xxx_dma_mask, .coherent_dma_mask = 0xffffffff, }, .num_resources = ARRAY_SIZE(s1r72xxx_resources), .resource = s1r72xxx_resources, };
11
然后通过下面的代码注册设备,将设备挂在虚拟总
线platform_bus上,总线类型为platform_bus_type。 platform_add_devices(luxun_devices, ARRAY_SIZE(luxun_devices)); luxun_devices是一个platform_device类型的指针 数组,定义如下所示: static struct platform_device *luxun_devices[] __initdata = { &s1r72xxx_device, &keybd_device, &d13733fb_device };
12
platform_add_devices()函数原型是:
int platform_add_devices(struct platform_device **devs, int num) { int i, ret = 0; for (i = 0; i < num; i++) { ret = platform_device_register(devs[i]); if (ret) { while (--i >= 0) platform_device_unregister(devs[i]); break; } return ret;
13
设备驱动程序 以luxun9 USB Controller Driver 为例,其中定 义了这样一个驱动程序结构体,代码如下所示:
static struct device_driver s1r72xxx_usbcd_driver ={ .name = driver_name, //"s1r72v17" .bus = &platform_bus_type, .probe = s1r72xxx_usbc_probe, .remove = __exit_p(s1r72xxx_usbc_remove), .shutdown= s1r72xxx_usbc_shutdown, .suspend = s1r72xxx_usbc_suspend, .resume = s1r72xxx_usbc_resume, };
14
驱动程序注册 驱动程序的注册注销函数如下所示:
int driver_register(struct device_driver *drv); void driver_unregister(struct device_driver *drv); 在luxun9 USB Controller Driver 中通过下面的代码注 册了一个USB驱动程序: iRetval = driver_register(&s1r72xxx_usbcd_driver);
15
driver_register()函数原型代码如下所示:
int driver_register(struct device_driver * drv) { klist_init(&drv->klist_devices, klist_devices_get, klist_devices_put); init_completion(&drv->unloaded); return bus_add_driver(drv); } 前面两个函数完成一些锁的初始化工作,最后的 bus_add_driver()函数用于向总线上添加驱动程 序。
16
在bus_add_driver()函数中会调用driver_attach()
函数,它的原型如下面代码所示: void driver_attach(struct device_driver * drv) { bus_for_each_dev(drv->bus, NULL, drv, __driver_attach); } 该函数调用bus_for_each_dev函数遍历platform_bus_type 类型总线上的所有设备。NULL表示从与该总线类型相关的 设备链表的头开始搜索设备。将每一个设备结构体dev和驱 动程序结构体drv作为参数传递给__driver_attach()函 数,在这个函数中,将调用platform_bus_type总线类型中 的匹配函数match(),在这个函数只是比较设备和驱动程序 的名字。如果匹配成功,则会调用驱动程序结构体中注册 的probe()函数。
Similar presentations