puppy居
puppy居士
posts - 41,comments - 27,trackbacks - 0
amba总线驱动
   R.wen


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 < 4; i++)
        pid |= (readl(tmp + 0xfe0 + 4 * i) & 255) << (i * 8);
    for (cid = 0, i = 0; i < 4; i++)
        cid |= (readl(tmp + 0xff0 + 4 * i) & 255) << (i * 8);

    iounmap(tmp);

    if (cid == 0xb105f00d)
        dev->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;
}
posted on 2008-08-20 11:26 puppy 阅读(557) 评论(0)  编辑 收藏 引用
只有注册用户登录后才能发表评论。