平台设备驱动的使用
1、声明平台设备 struct platform_device p_dev;
2、注册平台设备 platform_device_add(&p_dev)
3、注销平台设备 platform_device_unregister(&p_dev);
1、平台设备,通过struct platform_device 来进行描述。
struct platform_device {
const char * name; //平台设备的名称
int id;//设备的ID,当ID=-1的时候,表示设备名称只有一个,否则表示设备编号
struct device dev;
u32 num_resources;
struct resource * resource;
struct platform_device_id *id_entry;
};
2、其中platform_device内包含两个重要的结构体,一个是struct device 该结构体描述设备相关的信息设备之间的层次关系以及设备与总线驱动的关系。
struct device {
struct device *parent;//指向父设备节点
struct device_private *p;//描述的是klist,struct klist是对struct list_head的扩展,在此它的作用是连接设备列表中的孩子列表。Struct klist_node表示它的兄弟节点。
struct kobject kobj;
const char *init_name; /* initial name of the device */
struct device_type *type; /*device_type结构表示设备的类型。一个设备类或者总线可以包含不同类型的设备,例如“分区”和“磁盘” , “鼠标”和“事件” 。device_type就可以标识某个设备类型和该设备的特有信息,它就等同于kobject结构中的kobj_type一样。如果name数据成员被指定,那么uevent成员函数就会把它包含在DEVTYPE变量中。*/
struct semaphore sem; /* 该信号量用于同步其驱动 */
struct bus_type *bus; /*设备所在的总线,指向所连接的总线 */
struct device_driver *driver; /* 管理该设备的驱动 */
void *driver_data; /* 设备的私有数据指针*/
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屏蔽字。*/
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)聚集的DMA缓冲池 */
struct dma_coherent_mem *dma_mem; /* 设备一致性DMA的屏蔽字
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);释放设备描述符的回调函数。
};
3、通过struct resource结构体来描述
struct resource {
resource_size_t start;
resource_size_t end ;//资源起始的和结束的物理地址
const char *name;//资源的名称
unsigned long flags;;//资源的类型,比如MEM,IO,IRQ类型
struct resource *parent, *sibling, *child;;//资源链表的指针
};
4、platform_device的使用
1)声明该结构体struct platform_device *my_buttons_dev;
//给该结构体分配空间和初始化。传入的参数为设备名字和设备ID,当ID=-1的时候表明该设备名称唯一
my_buttons_dev = platform_device_alloc("my_buttons", -1);
声明平台设备的资源struct resource
static struct resource key_resource[]=
{
[0] = {
.start = IRQ_EINT1,
.end = IRQ_EINT1,
.flags = IORESOURCE_IRQ,
},
[1] = {
.start = IRQ_EINT2,
.end = IRQ_EINT2,
.flags = IORESOURCE_IRQ,
},
};
//使用下面函数将该资源添加到平台设备里面去,使用该函数,会为 platform_device 中的resource结构体指针分配空间并且赋值
//参数为 (struct platform_device *pdev,struct resource *res, unsigned int num)
platform_device_add_resources(my_buttons_dev,key_resource,6);
3)//向系统注册该设备
ret = platform_device_add(my_buttons_dev);
if(ret)
platform_device_put(my_buttons_dev);
并且在退出函数里面将该平台设备注销
void platform_device_unregister(struct platform_device *pdev)
平台驱动使用
平台设备驱动最重要的是:struct platform_driver 结构体
1)struct platform_driver {
//probe函数当找到相对应的硬件设备的时候将会调用
//相对应的函数进行
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; //设备驱动,定义在include/linux/device.h中
struct platform_device_id *id_table;
};
2)声明一个struct platform_driver对象然后对其初始化
struct platform_driver my_buttons_drv = {
.probe = my_plat_probe,//对应设备的探测驱动
.remove = my_plat_remove,
.driver = {
.owner = THIS_MODULE,
.name = "my_buttons",//与设备的名字一致和platform_device相关联起来
},
};
向系统注册这个平台驱动
ret = platform_driver_register(&my_buttons_drv);
当模块卸载的时候注销该驱动:
platform_driver_unregister(&my_buttons_drv);
平台设备驱动中探测设备函数,如果探测成功,向系统注册一个字符设备或者混杂设备,向用户空间提供一个操作设备的接口。
static int my_plat_probe(struct platform_device *dev)
{
int ret,i;
struct resource *plat_resource;
struct platform_device *pdev = dev;
printk("my platform dirver find my platfrom device.\n");
for(i=0; i<6; i++){
plat_resource = platform_get_resource(pdev,IORESOURCE_IRQ,i);
if(plat_resource == NULL)
return -ENOENT;
buttons_irq[i] = plat_resource->start;
}
ret = misc_register(&misc);
if(ret)
return ret;
return 0;
}