从DM9000驱动看platform device与driver的关系

快乐虾

http://blog.csdn.net/lights_joy/

[email protected]

本文适用于

ADSP-BF561

uclinux-2008r1.5-rc3 (smp patch)

Visual DSP++ 5.0(update 5)

欢迎转载,但请保留作者信息

内核中的platform driver机制需要将设备本身的资源注册进内核,由内核统一管理,在驱动程序中使用这些资源时通过platform device提供的标准接口进行申请并使用。这样可以提高驱动和资源管理的独立性。本文的目的就是希望弄清楚platform devicedriver之间的关系。

1.1 相关数据结构

1.1.1 device

这个结构体定义为:

struct device {

struct klist klist_children;

struct klist_node knode_parent; /* node in sibling list */

struct klist_node knode_driver;

struct klist_node knode_bus;

struct device *parent;

struct kobject kobj;

char bus_id[BUS_ID_SIZE]; /* position on parent bus */

struct device_type *type;

unsigned is_registered:1;

unsigned uevent_suppress:1;

struct device_attribute uevent_attr;

struct device_attribute *devt_attr;

struct semaphore sem; /* semaphore to synchronize calls to

* its driver.

*/

struct bus_type * bus; /* type of bus device is on */

struct device_driver *driver; /* which driver has allocated this

device */

void *driver_data; /* data private to the driver */

void *platform_data; /* Platform specific data, device

core doesn't touch it */

struct dev_pm_info power;

#ifdef CONFIG_NUMA

int numa_node; /* NUMA node this device is close to */

#endif

u64 *dma_mask; /* dma mask (if dma'able device) */

u64 coherent_dma_mask;/* Like dma_mask, but for

alloc_coherent mappings as

not all hardware supports

64 bit addresses for consistent

allocations such descriptors. */

struct list_head dma_pools; /* dma pools (if dma'ble) */

struct dma_coherent_mem *dma_mem; /* internal for coherent mem

override */

/* arch specific additions */

struct dev_archdata archdata;

spinlock_t devres_lock;

struct list_head devres_head;

/* class_device migration path */

struct list_head node;

struct class *class;

dev_t devt; /* dev_t, creates the sysfs "dev" */

struct attribute_group **groups; /* optional groups */

void (*release)(struct device * dev);

};

这个结构体有点复杂,不过我们暂时用不了这么多。

1.1.2 resource

这个结构体定义为:

/*

* Resources are tree-like, allowing

* nesting etc..

*/

struct resource {

resource_size_t start;

resource_size_t end;

const char *name;

unsigned long flags;

struct resource *parent, *sibling, *child;

};

在这个结构体中,startend的意义将根据flags中指定的资源类型进行解释。内核对资源进行了分类,一共有四种类型:

#define IORESOURCE_IO 0x00000100 /* Resource type */

#define IORESOURCE_MEM 0x00000200

#define IORESOURCE_IRQ 0x00000400

#define IORESOURCE_DMA 0x00000800

对于DM9000来说,其定义的资源如下:

static struct resource dm9000_bfin_resources[] = {

{

.start = 0x2C000000,

.end = 0x2C000000 + 0x7F,

.flags = IORESOURCE_MEM,

}, {

.start = IRQ_PF10,

.end = IRQ_PF10,

.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,

},

};

也就是说,它定义了两种类型的资源。从这里也可以看出resource结构体里面的name成员没有太大的用处。

1.1.3 platform_device

这个结构体定义为:

struct platform_device {

const char * name;

u32 id;

struct device dev;

u32 num_resources;

struct resource * resource;

};

它对device加了一层包装,添加了resource的内容。看看DM9000的定义:

static struct platform_device dm9000_bfin_device = {

.name = "dm9000",

.id = -1,

.num_resources = ARRAY_SIZE(dm9000_bfin_resources),

.resource = dm9000_bfin_resources,

};

注意这里的name

1.1.4 device_driver

这个结构体定义为:

struct device_driver {

const char * name;

struct bus_type * bus;

struct kobject kobj;

struct klist klist_devices;

struct klist_node knode_bus;

struct module * owner;

const char * mod_name; /* used for built-in modules */

struct module_kobject * mkobj;

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 (*resume) (struct device * dev);

};

1.1.5 platform_driver

这个结构体定义为:

struct platform_driver {

int (*probe)(struct platform_device *);

int (*remove)(struct platform_device *);

void (*shutdown)(struct platform_device *);

int (*suspend)(struct platform_device *, pm_message_t state);

int (*suspend_late)(struct platform_device *, pm_message_t state);

int (*resume_early)(struct platform_device *);

int (*resume)(struct platform_device *);

struct device_driver driver;

};

它在device_driver的基础上封装了几个操作函数。

1.1.6 bus_type

这个结构体定义为:

struct bus_type {

const char * name;

struct module * owner;

struct kset 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;

struct bus_attribute drivers_autoprobe_attr;

struct bus_attribute drivers_probe_attr;

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);

unsigned int drivers_autoprobe:1;

};

1.2 资源注册

arch/blackfin/mach-bf561/boards/ezkit.c中有这样的代码:

static int __init ezkit_init(void)

{

int ret;

printk(KERN_INFO "%s(): registering device resources\n", __func__);

ret = platform_add_devices(ezkit_devices, ARRAY_SIZE(ezkit_devices));

if (ret < 0)

return ret;

return 0;

}

arch_initcall(ezkit_init);

这里使用了arch_initcall来对ezkit_init函数进行调用次序的限制,而驱动的加载通常是使用module_init进行限制的,因此ezkit_init函数将先于驱动加载。

在这里ezkit_devices的定义为:

static struct platform_device *ezkit_devices[] __initdata = {

&dm9000_bfin_device,

…………

};

1.2.1 platform_add_devices

这个函数比较简单:

/**

* platform_add_devices - add a numbers of platform devices

* @devs: array of platform devices to add

* @num: number of platform devices in array

*/

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;

}

为这个数组中的每个元素调用platform_device_register,如果出错则注销此前注册的所有platform device

1.2.2 platform_device_register

这个函数的实现为:

/**

* platform_device_register - add a platform-level device

* @pdev: platform device we're adding

*

*/

int platform_device_register(struct platform_device * pdev)

{

device_initialize(&pdev->dev);

return platform_device_add(pdev);

}

也比较简单,先调用device_initialize初始化platform_device::dev,这里仅仅是对device结构体的成员赋初值,略过它不做分析。接下来的关键是platform_device_add

1.2.3 platform_device_add

这个函数定义为:

/**

* platform_device_add - add a platform device to device hierarchy

* @pdev: platform device we're adding

*

* This is part 2 of platform_device_register(), though may be called

* separately _iff_ pdev was allocated by platform_device_alloc().

*/

int platform_device_add(struct platform_device *pdev)

{

int i, ret = 0;

if (!pdev)

return -EINVAL;

if (!pdev->dev.parent)

pdev->dev.parent = &platform_bus;

pdev->dev.bus = &platform_bus_type;

if (pdev->id != -1)

snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%u", pdev->name, pdev->id);

else

strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE);

for (i = 0; i < pdev->num_resources; i++) {

struct resource *p, *r = &pdev->resource[i];

if (r->name == NULL)

r->name = pdev->dev.bus_id;

p = r->parent;

if (!p) {

if (r->flags & IORESOURCE_MEM)

p = &iomem_resource;

else if (r->flags & IORESOURCE_IO)

p = &ioport_resource;

}

if (p && insert_resource(p, r)) {

printk(KERN_ERR

"%s: failed to claim resource %d\n",

pdev->dev.bus_id, i);

ret = -EBUSY;

goto failed;

}

}

pr_debug("Registering platform device '%s'. Parent at %s\n",

pdev->dev.bus_id, pdev->dev.parent->bus_id);

ret = device_add(&pdev->dev);

if (ret == 0)

<

你可能感兴趣的:(数据结构,Blog)