Chinaunix首页 | 论坛 | 博客
  • 博客访问: 253277
  • 博文数量: 90
  • 博客积分: 2775
  • 博客等级: 少校
  • 技术积分: 645
  • 用 户 组: 普通用户
  • 注册时间: 2009-06-13 17:04
文章分类

全部博文(90)

文章存档

2015年(30)

2013年(4)

2012年(4)

2011年(12)

2010年(4)

2009年(36)

我的朋友

分类: LINUX

2009-06-27 14:15:01

Linux驱动分析


总的来说,linux 2.6以后的内核,其驱动部分,可以分为三大主要部分,分别为,1.linux 驱动模型,2.linux 设备,3.linux 驱动 1.linux 驱动模型的相应数据结构,主要包括,底层的,用来组成/sys/文件系统的,kobject, kset,subsystem.和上层用来抽象设备,驱动,总线的,device,device_driver,bus.等 等。   

接下来,我们主要分析,linux 是如何建立驱动模型的。在
init.c:
/** *    driver_init - initialize driver model.
* *    Call the driver model init functions to initialize their
*    subsystems. Called early from init/main.c.
*/
void __init driver_init(void){   
/* These are the core pieces */   
devices_init();   
buses_init();   
classes_init();   
firmware_init();   
/* These are also core pieces, but must come after the    
* core core pieces.     */ 
 
platform_bus_init();   
system_bus_init();   
cpu_dev_init();   
attribute_container_init();}

2.linux 设备 为例在2.6内核中将每个设备的资源用结构platform_device来描述,该结构体定义在kernel\include\linux\platform_device.h中,
 struct platform_device
{ const char * name;
u32   id;
struct device dev;
u32   num_resources;
struct resource * resource; };
该结构一个重要的元素是resource,该元素存入了最为重要的设备资源信息,定义在kernel\include\linux\ioport.h中,
struct resource {
const char *name;
unsigned long start, end;
unsigned long flags;
struct resource *parent, *sibling, *child; };
下面举个例子来说明一下: 在kernel\arch\arm\mach-pxa\pxa27x.c定义了
tatic struct resource pxa27x_ohci_resources[] = {
[0] = {    .start   = 0x4C000000,   
.end     = 0x4C00ff6f,   
.flags   = IORESOURCE_MEM, },
 [1] = {    .start   = IRQ_USBH1,   
.end     = IRQ_USBH1,   
.flags   = IORESOURCE_IRQ, }, };
这里定义了两组resource,它描述了一个usb host设备的资源,第1组描述了这个usb host设备所占用的 总线地址范围,IORESOURCE_MEM表示第1组描述的是内存类型的资源信息,第2组描述了这个usb host设备 的中断号,IORESOURCE_IRQ表示第2组描述的是中断资源信息。设备驱动会根据flags来获取相应的资源信息。 有了resource信息,就可以定义platform_device了:
static struct platform_device ohci_device =
{ .name   = "pxa27x-ohci",
.id   = -1,
.dev   = {  
 .dma_mask = &pxa27x_dmamask,   
.coherent_dma_mask = 0xffffffff, },
 .num_resources   = ARRAY_SIZE(pxa27x_ohci_resources),
 .resource        = pxa27x_ohci_resources, };
 有了platform_device就可以调用函数platform_add_devices向系统中添加该设备了,这里的实现是 static int __init pxa27x_init(void) { return platform_add_devices(devices, ARRAY_SIZE(devices)); }




platform_add_devices 的情景分析

platform_add_devices=>device_register(&pdev->dev);

                      device_register=>device_add(dev);
                         
                                       device_add=>bus_add_device(dev);



接下来,我们详细看一下 bus_add_device 这个函数

        list_add_tail(&dev->bus_list, &dev->bus->devices.list);
        device_attach(dev);
        up_write(&dev->bus->subsys.rwsem);
        device_add_attrs(bus, dev);
        sysfs_create_link(&bus->devices.kobj, &dev->kobj, dev->bus_id);

bus_add_device=>device_attach
    if (dev->driver) {
        device_bind_driver(dev);
        return 1;
    }

    if (bus->match) {
        list_for_each(entry, &bus->drivers.list) {
            struct device_driver * drv = to_drv(entry);
            error = driver_probe_device(drv, dev);
            if (!error)
                /* success, driver matched */
                return 1;
            if (error != -ENODEV && error != -ENXIO)
                /* driver matched but the probe failed */
                printk(KERN_WARNING
                    "%s: probe of %s failed with error %d\n",
                    drv->name, dev->bus_id, error);
        }
    }

device_attach=>device_bind_driver:

   
   list_add_tail(&dev->driver_list, &dev->driver->devices);
    sysfs_create_link(&dev->driver->kobj, &dev->kobj,
              kobject_name(&dev->kobj));
    sysfs_create_link(&dev->kobj, &dev->driver->kobj, "driver");

我以 platform device serial_8250 为例 说明一下两个 sysfs_create_link 函数,反映在 sysfs文件系统上实质现象。


steven@steven-laptop:/sys/bus/platform/drivers/serial8250$ ls -l
total 0
--w------- 1 root root 4096 2009-06-29 00:08 bind
lrwxrwxrwx 1 root root    0 2009-06-29 00:08 serial8250 -> ../../../../devices/platform/serial8250
--w------- 1 root root 4096 2009-06-29 00:08 uevent
--w------- 1 root root 4096 2009-06-29 00:08 unbind
steven@steven-laptop:/sys/bus/platform/drivers/serial8250$ cd /sys/devices/platform/serial8250/
steven@steven-laptop:/sys/devices/platform/serial8250$ ls
driver  modalias  power  subsystem  tty  uevent
steven@steven-laptop:/sys/devices/platform/serial8250$ ls -l
total 0
lrwxrwxrwx 1 root root    0 2009-06-29 00:13 driver -> ../../../bus/platform/drivers/serial8250
-r--r--r-- 1 root root 4096 2009-06-29 00:13 modalias
drwxr-xr-x 2 root root    0 2009-06-29 00:13 power
lrwxrwxrwx 1 root root    0 2009-06-29 00:13 subsystem -> ../../../bus/platform
drwxr-xr-x 6 root root    0 2009-06-29 00:13 tty
-rw-r--r-- 1 root root 4096 2009-06-29 00:13 uevent
steven@steven-laptop:/sys/devices/platform/serial8250$



steven@steven-laptop:/sys/bus/platform/devices$ ls -l
total 0
lrwxrwxrwx 1 root root 0 2009-07-04 23:32 eisa.0 -> ../../../devices/platform/eisa.0
lrwxrwxrwx 1 root root 0 2009-07-04 23:32 i8042 -> ../../../devices/platform/i8042
lrwxrwxrwx 1 root root 0 2009-07-04 23:32 iTCO_wdt -> ../../../devices/platform/iTCO_wdt
lrwxrwxrwx 1 root root 0 2009-07-04 23:32 pcspkr -> ../../../devices/platform/pcspkr
lrwxrwxrwx 1 root root 0 2009-07-04 23:32 serial8250 -> ../../../devices/platform/serial8250



这里的pxa27x_init必须在设备驱动加载之前被调用,可以把它放到 subsys_initcall(pxa27x_init);

关于 subsys_initcall 参考 说说subsys_initcall3.linux 驱动
阅读(837) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~