Linux设备驱动模型摘抄(2)

我们通过Linux设备驱动模型摘抄(1)已经知道了Linux设备驱动的基本架构,但是这种介绍是比较抽象的,至少到目前为止,我们仍然不清楚struct device, struct device_driver, struct class和struct bus_type等等这些基本的结构体是如何和一个真正的设备发生关系的,下面我们就尝试来回答这个问题。
   我们以driver/serial/amba_pl011.c中的serial console驱动为例来说明这个问题(unregister的问题不予考虑):
   module_init(pl011_init)->pl011_init(void)->uart_register_driver(&amba_reg);
                                                                       ->amba_driver_register(&pl011_driver);
我们先来看看uart_register_driver(&amba_reg)这个函数的执行情况,相关信息如下:
struct uart_driver {
        struct module        *owner;
        const char              *driver_name;
        const char              *dev_name;
        int                          major;
        int                          minor;
        int                          nr;
        struct console       *cons;

        /*
         * these are private; the low level driver should not
         * touch these; they should be initialised to NULL
         */
        struct uart_state       *state;
        struct tty_driver       *tty_driver;
};
static struct uart_driver amba_reg = {
        .owner                  = THIS_MODULE,
        .driver_name            = "ttyAMA",
        .dev_name               = "ttyAMA",
        .major                  = SERIAL_AMBA_MAJOR,
        .minor                  = SERIAL_AMBA_MINOR,
        .nr                     = UART_NR,
        .cons                   = AMBA_CONSOLE,
};
int uart_register_driver(struct uart_driver *drv)
{
        struct tty_driver *normal = NULL;
        int i, retval;

        BUG_ON(drv->state);

        /*
         * Maybe we should be using a slab cache for this, especially if
         * we have a large number of ports to handle.
         */
        drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);
        retval = -ENOMEM;
        if (!drv->state)
                goto out;

        normal = alloc_tty_driver(drv->nr);
        if (!normal)
                goto out;

        drv->tty_driver = normal;
        normal->owner           = drv->owner;
        normal->driver_name     = drv->driver_name;
        normal->name            = drv->dev_name;
        normal->major           = drv->major;
        normal->minor_start     = drv->minor;
        normal->type            = TTY_DRIVER_TYPE_SERIAL;
        normal->subtype         = SERIAL_TYPE_NORMAL;
        normal->init_termios    = tty_std_termios;
        normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
        normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 9600;
        normal->flags           = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
        normal->driver_state    = drv;
        tty_set_operations(normal, &uart_ops);

        /*
         * Initialise the UART state(s).
         */
        for (i = 0; i < drv->nr; i++) {
                struct uart_state *state = drv->state + i;

                state->close_delay     = 500;   /* .5 seconds */
                state->closing_wait    = 30000; /* 30 seconds */

                mutex_init(&state->mutex);
        }

        retval = tty_register_driver(normal);
out:
        if (retval < 0) {
                put_tty_driver(normal);
                kfree(drv->state);
        }
        return retval;
}
综上所述,tty_register_driver应该是最关键的函数, 如下:
tty_register_driver(struct tty_driver *driver)->
tty_register_device(struct tty_driver *driver, unsigned index, struct device *device) ->
device_create(tty_class, device, dev, name);
而device_create的原型是
struct device *device_create(struct class *class, struct device *parent, dev_t devt, const char *fmt, ...)
对比一下,就可以发现到了device_create的时候,uart这个protocol已经被屏蔽掉了,而产生了一个叫做tty_class的(struct class)代表了包括uart在内的一系列设备,dev_t则表示在sysfs中的位置。我们可以认为这一步最终产生了/sys/devices/XXX和/sys/class/XXX这2个目录。

下面我们再来分析amba_driver_register(&pl011_driver)的执行情况:
   struct amba_driver {
        struct device_driver    drv;
        int                     (*probe)(struct amba_device *, void *);
        int                     (*remove)(struct amba_device *);
        void                    (*shutdown)(struct amba_device *);
        int                     (*suspend)(struct amba_device *, pm_message_t);
        int                     (*resume)(struct amba_device *);
        struct amba_id          *id_table;
};
   static struct amba_driver pl011_driver = {
        .drv = {
                .name   = "uart-pl011",
        },
        .id_table       = pl011_ids,
        .probe          = pl011_probe,
        .remove         = pl011_remove,
};
static struct bus_type amba_bustype = {
        .name           = "amba",
        .dev_attrs      = amba_dev_attrs,
        .match          = amba_match,
        .uevent         = amba_uevent,
        .suspend        = amba_suspend,
        .resume         = amba_resume,
};
int amba_driver_register(struct amba_driver *drv)
{
        drv->drv.bus = &amba_bustype;   //struct bus_type

#define SETFN(fn)       if (drv->fn) drv->drv.fn = amba_##fn
        SETFN(probe);                 //amba_probe, 应该是默认值
        SETFN(remove);              //amba_remove, 应该是默认值
        SETFN(shutdown);          //amba_shutdown, 应该是默认值

        return driver_register(&drv->drv);
}
    分析到了这里,就到了driver_register这个函数,我们再来分析。
int driver_register(struct device_driver *drv)
{
        int ret;

        if ((drv->bus->probe && drv->probe) ||
            (drv->bus->remove && drv->remove) ||
            (drv->bus->shutdown && drv->shutdown))
                printk(KERN_WARNING "Driver '%s' needs updating - please use "
                        "bus_type methods/n", drv->name);
        ret = bus_add_driver(drv);
        if (ret)
                return ret;
        ret = driver_add_groups(drv, drv->groups);
        if (ret)
                bus_remove_driver(drv);
        return ret;
}
   我们从这里也可以看出来,到了dirver_register的时候,也没有具体的设备的信息,比较重要的2个函数是:
   bus_add_driver和driver_add_groups
   bus_add_driver:   Add a driver to the bus
   driver_add_groups->sysfs_create_group 目前没有功能(linux-2.6.25)
   我们可以认为,这一步最终产生了/sys/bus/XXX目录


   对于一个设备来说,/sys/bus/, /sys/devices/, /sys/class这3个目录足够了,加载驱动的过程也就是把一个物理上的设备放到/sys/bus/, /sys/devices/, /sys/class/这3个目录的某个确定的位置。

你可能感兴趣的:(linux,struct,Module,table,null,Class)