分类: LINUX
2016-11-21 22:34:28
platform总线-------linux2.6内核加入的一种虚拟总线。由两部分组成:
platform_device和platform_driver
platform总线----好处
platform 驱动与传统的设备驱动模型相比,优势在于platform机制将设备本身的资源注册进内核,由内核统一管理,在驱动程序使用这些资源的时使用统一的借口,提高了程序的可移植性。
platform机制开发底层设备驱动的流程:
1--定义platform_device
2--注册platform_device
3--定义platform_driver
4--注册platform_driver
平台设备描述-----
struct platform_device {
const char * name;设备名
int id;设备编号,配合设备名使用
struct device dev;
u32 num_resources;
struct resource * resource;设备资源
};
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 */
unsigned uevent_suppress:1;
const char *init_name; /* initial name of the device */
struct device_type *type;
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 device_dma_parameters *dma_parms;
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;
dev_t devt; /* dev_t, creates the sysfs "dev" */
spinlock_t devres_lock;
struct list_head devres_head;
struct klist_node knode_class;
struct class *class;
struct attribute_group **groups; /* optional groups */
void (*release)(struct device *dev);
};
struct device
{
/* The linked-list pointer. */
struct device *next;
/* The this device's descriptor, as mapped into the Guest. */
struct lguest_device_desc *desc;
/* The name of this device, for --verbose. */
const char *name;
/* If handle_input is set, it wants to be called when this file
* descriptor is ready. */
int fd;
bool (*handle_input)(int fd, struct device *me);
/* Any queues attached to this device */
struct virtqueue *vq;
/* Handle status being finalized (ie. feature bits stable). */
void (*ready)(struct device *me);
/* Device-specific data. */
void *priv;
};
平台设备分配-----
struct platform_device *platform_device_alloc(const char *name,int id)
参数---
name---设备名
id--设备id一般为-1
平台设备注册-----
int platform_device_add(struct platform_device *pdev)
设备资源描述
struct resource {
resource_size_t start;资源的起始物理地址
resource_size_t end;资源的结束物理地址
const char *name;资源的名称
unsigned long flags;资源的类型,比如MEM,IO,IRQ类型
struct resource *parent, *sibling, *child;资源链表指针
};
设备资源一例
static struct resource s3c_wdt_resource1=
{
.start=0x44100000,
.end=0x44200000,
.flags=IORESOURACE_MEM,设备基地址信息
}
static struct resource s3c_wdt_resource2=
{
.start=20,
.end=20,
.flags=IORESOURACE_IRQ,设备使用的中断号。
}
获取资源
struct resource *platform_get_resource(struct platform_device *dev,unsigned int type,unsigned int num)
参数:
dev--资源所属设备
type--获取的资源类型
num--获取的资源序号
例子
platform_get_resource(pdev,IORESOURACE_IRQ,0)
获取中断号
平台驱动描述---
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;
};
struct device_driver {
const char *name;
struct bus_type *bus;
struct module *owner;
const char *mod_name; /* used for built-in modules */
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);
struct attribute_group **groups;
struct dev_pm_ops *pm;
struct driver_private *p;
};
平台驱动注册----
int platform_driver_register(struct platform_driver *)
重要----在平台驱动注册的时候,因为平台驱动的描述里有struct device_driver driver;,
它首先给driver赋值一个内核定义好的总线。然后调用driver的注册函数,在这个注册函数里,它会把这个driver添加到总线上,调用driver_add函数。在这个函数中,调用函数driver_attach,bus_for_each_dev,最终调用总线的match(dev, drv)函数,若match成功,会接着调用driver的probe函数。这就是probe函数的调用时机。
上面提到的内核定义好的总线即平台总线,它也有平台总线的match函数,在这个函数里是通过平台设备的名字和平台驱动的名字来匹配的。
注意----在一般的设备模型中是通过设备的bus_id设备的唯一的编号,和驱动的名字来匹配的。在这个设备模型中,struct device 无name成员。
device----
#include
#include
#include
#include
#include
#include
MODULE_AUTHOR("David Xie");
MODULE_LICENSE("Dual BSD/GPL");
static struct platform_device *my_device;
static int __init my_device_init(void)
{
int ret = 0;
/* 分配结构 */
my_device = platform_device_alloc("my_dev", -1);
/*注册设备*/
ret = platform_device_add(my_device);
/*注册失败,释放相关内存*/
if (ret)
platform_device_put(my_device);
return ret;
}
static void my_device_exit(void)
{
platform_device_unregister(my_device);
}
module_init(my_device_init);
module_exit(my_device_exit);
driver----
#include
#include
#include
#include
#include
#include
MODULE_AUTHOR("David Xie");
MODULE_LICENSE("Dual BSD/GPL");
static int my_probe(struct device *dev)
{
printk("Driver found device which my driver can handle!\n");
return 0;
}
static int my_remove(struct device *dev)
{
printk("Driver found device unpluged!\n");
return 0;
}
static struct platform_driver my_driver = {
.probe = my_probe,
.remove = my_remove,
.driver = {
.owner = THIS_MODULE,
.name = "my_dev",
},
};
static int __init my_driver_init(void)
{
/*注册平台驱动*/
return platform_driver_register(&my_driver);
}
static void my_driver_exit(void)
{
platform_driver_unregister(&my_driver);
}
module_init(my_driver_init);
module_exit(my_driver_exit);
总结----------三个重要的
platform_device
platform_driver
resource