ARM amba总线驱动(转)

1).总线的注册
/*
* Primecells are part of the Advanced Microcontroller Bus Architecture,
* so we call the bus "amba".
*/
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,
};
static int __init amba_init(void)
{
    return bus_register(&amba_bustype);
}
完整的bus_type结构如下:
struct bus_type {
    const char        * name;
    struct subsystem    subsys;
    struct kset        drivers;
    struct kset        devices;
    struct klist        klist_devices;
    struct klist        klist_drivers;
    struct blocking_notifier_head bus_notifier;
    struct bus_attribute    * bus_attrs;
    struct device_attribute    * dev_attrs;
    struct driver_attribute    * drv_attrs;
    int        (*match)(struct device * dev, struct device_driver * drv);
    int        (*uevent)(struct device *dev, char **envp,
                int num_envp, char *buffer, int buffer_size);
    int        (*probe)(struct device * dev);
    int        (*remove)(struct device * dev);
    void        (*shutdown)(struct device * dev);
    int (*suspend)(struct device * dev, pm_message_t state);
    int (*suspend_late)(struct device * dev, pm_message_t state);
    int (*resume_early)(struct device * dev);
    int (*resume)(struct device * dev);
};
我们看到,amba bus的注册结构中少了一般都会有的probe函数,当这个函数存在时,通用bus系统会调用这个函数,而这个函数又会调用设备的probe函数,否则,通用bus系统就会直接调用设备的probe函数。
2).设备驱动的注册函数.
/**
*    amba_driver_register - register an AMBA device driver
*    @drv: amba device driver structure
*
*    Register an AMBA device driver with the Linux device model
*    core. If devices pre-exist, the drivers probe function will
*    be called.
*/
int amba_driver_register(struct amba_driver *drv)
{
    drv->drv.bus = &amba_bustype;
#define SETFN(fn)    if (drv->fn) drv->drv.fn = amba_##fn
    SETFN(probe);
    SETFN(remove);
    SETFN(shutdown);
    return driver_register(&drv->drv);
}
当一个设备想要注册进这个amba总线时,它就会调用以初始化好了的amba_driver结构调用amba_driver_register()这个驱动注册函数。而下一步这个函数就会调用通用的驱动注册函数driver_register。
这个函数对其他函数的调用路径如下:
driver_register -> bus_add_driver -> driver_attach -> __driver_attach(对每个设备) -> driver_probe_device -> drv->bus->match(dev, drv)(检查这个设备是否与新注册的驱动匹配) ->    really_probe -> dev->bus->probe(dev)(如果存在) (否则) -> drv->probe(dev)
而且我们还可以看到,传递给驱动probe的参数,是一个具体的设备。这个结构是设备注册的时候已经分配好的了。
3)设备的注册
当往系统插入一个新的设备时,他就会调用amba_device_register函数,这个过程跟驱动注册的过程差不多。
总线维护两个队列,一个用于设备,一个用于驱动。当一个新的设备加入是,这个设备结构会链进设备队列。而当一个驱动加入是,它就会加入驱动队列。而且,无论是设备还是驱动,当有插入操作是,它都会遍历另一个队列,寻找相应的驱动或设备,如果找到匹配的, 就会就行drv->device = dev, dev->driver=drv操作,这个某个设备就和某个驱动关联了起来。这就是说这个驱动就可以用了。
amba设备的结构:
#define AMBA_NR_IRQS    2
struct amba_device {
    struct device        dev;
    struct resource        res;
    u64            dma_mask;
    unsigned int        periphid;
    unsigned int        irq[AMBA_NR_IRQS];
};
/**
*    amba_device_register - register an AMBA device
*    @dev: AMBA device to register
*    @parent: parent memory resource
*
*    Setup the AMBA device, reading the cell ID if present.
*    Claim the resource, and register the AMBA device with
*    the Linux device manager.
*/
int amba_device_register(struct amba_device *dev, struct resource *parent)
{
    u32 pid, cid;
    void __iomem *tmp;
    int i, ret;
    dev->dev.release = amba_device_release;
    dev->dev.bus = &amba_bustype;
    dev->dev.dma_mask = &dev->dma_mask;
    dev->res.name = dev->dev.bus_id;
    if (!dev->dev.coherent_dma_mask && dev->dma_mask)
        dev_warn(&dev->dev, "coherent dma mask is unset\n");
    ##申请资源
    ret = request_resource(parent, &dev->res);
    if (ret)
        goto err_out;
    ##将物理地址映射到虚拟地址空间,是内核可见
    tmp = ioremap(dev->res.start, SZ_4K);
    if (!tmp) {
        ret = -ENOMEM;
        goto err_release;
    }
    for (pid = 0, i = 0; i periphid = pid;
    if (!dev->periphid) {
        ret = -ENODEV;
        goto err_release;
    }
    ##注册设备,类似于驱动注册
    ret = device_register(&dev->dev);
    if (ret)
        goto err_release;
    if (dev->irq[0] != NO_IRQ)
        ret = device_create_file(&dev->dev, &dev_attr_irq0);
    if (ret == 0 && dev->irq[1] != NO_IRQ)
        ret = device_create_file(&dev->dev, &dev_attr_irq1);
    if (ret == 0)
        return ret;
    device_unregister(&dev->dev);
err_release:
    release_resource(&dev->res);
err_out:
    return ret;
}
对于设备,还会提供如下函数,用于申请一块可用的io内存
/**
*    amba_request_regions - request all mem regions associated with device
*    @dev: amba_device structure for device
*    @name: name, or NULL to use driver name
*/
int amba_request_regions(struct amba_device *dev, const char *name)
{
    int ret = 0;
    if (!name)
        name = dev->dev.driver->name;
    if (!request_mem_region(dev->res.start, SZ_4K, name))
        ret = -EBUSY;
    return ret;
}


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/78225/showart_1226970.html

转自:http://linux.chinaunix.net/techdoc/develop/2008/09/27/1034828.shtml

你可能感兴趣的:(linux相关)