个人网站谢谢,排名seo公司,为什么网站之有首页被收录,黄冈网站建设收费plattorm是为了驱动的分离与分层而提出来的一种框架#xff0c;其驱动的具体实现还是需要字符设备驱动、块设备驱动或网络设备驱动。
对于一个完整的驱动程序#xff0c;必须提供“有设备树”和“无设备树”两种匹配方法。 1、总线
Linux系统内核使用bus_type结构体表示总线…plattorm是为了驱动的分离与分层而提出来的一种框架其驱动的具体实现还是需要字符设备驱动、块设备驱动或网络设备驱动。
对于一个完整的驱动程序必须提供“有设备树”和“无设备树”两种匹配方法。 1、总线
Linux系统内核使用bus_type结构体表示总线需要包含“#include linux/device.h”结构体如下
struct bus_type { const char *name; const char *dev_name; struct device *dev_root; const struct attribute_group **bus_groups; const struct attribute_group **dev_groups; const struct attribute_group **drv_groups; int (*match)(struct device *dev, struct device_driver *drv);
//dev是设备drv是驱动根据“注册的驱动”查找相应的设备 int (*uevent)(struct device *dev, struct kobj_uevent_env *env); int (*probe)(struct device *dev); int (*remove)(struct device *dev); void (*shutdown)(struct device *dev); int (*online)(struct device *dev); int (*offline)(struct device *dev); int (*suspend)(struct device *dev, pm_message_t state); int (*resume)(struct device *dev); int (*num_vf)(struct device *dev); int (*dma_configure)(struct device *dev); const struct dev_pm_ops *pm; const struct iommu_ops *iommu_ops; struct subsys_private *p; struct lock_class_key lock_key; bool need_parent_lock;
}; 2、platform总线
platform_bus_type是platform平台总线它是bus_type的一个具体实例需要包含“#include linux/platform_device.h”platform总线定义如下:
struct bus_type platform_bus_type { .name platform, .dev_groups platform_dev_groups, .match platform_match, .uevent platform_uevent, .dma_configure platform_dma_configure, .pm platform_dev_pm_ops,
}; #include linux/of_device.h
static int platform_match(struct device *dev,struct device_driver *drv)
{
struct platform_device *pdev to_platform_device(dev);
struct platform_driver *pdrv to_platform_driver(drv); /*When driver_override is set,only bind to the matching driver*/
if (pdev-driver_override)//当设置driver_override时只绑定到匹配的驱动程序
return !strcmp(pdev-driver_override, drv-name); /* Attempt an OF style match first */
if (of_driver_match_device(dev, drv))
//第1种匹配方式OF类型的匹配就是设备树采用的匹配方式
return 1; /* Then try ACPI style match */
if (acpi_driver_match_device(dev, drv)) //第2种匹配方式ACPI匹配方式
return 1; /* Then try to match against the id table */
if (pdrv-id_table)//第3种匹配方式id_table匹配
return platform_match_id(pdrv-id_table, pdev) ! NULL; /* fall-back to driver name match */
return (strcmp(pdev-name, drv-name) 0);
/*
第4种匹配方式如果第3种匹配方式的id_table不存在就直接比较驱动和设备的name 字段看看是不是相等如果相等的话就匹配成功。
*/
} 3、platform驱动
对于一个完整的驱动程序必须提供有设备树和无设备树两种匹配方法。
platform_driver结构体表示“platform驱动”需要包含“#include linux/platform_device.h”结构体如下
struct platform_driver { int (*probe)(struct platform_device *);
/*probe()函数当“驱动”与“设备”匹配成功以后probe()函数就会执行*/ int (*remove)(struct platform_device *); void (*shutdown)(struct platform_device *); int (*suspend)(struct platform_device *, pm_message_t state); int (*resume)(struct platform_device *); struct device_driver driver; const struct platform_device_id *id_table;
/*id_table是个表(也就是数组)每个元素的类型为platfomm_device_id*/ bool prevent_deferred_probe;
}; platfomm_device_id结构体如下
struct platform_device_id { char name[PLATFORM_NAME_SIZE]; kernel_ulong_t driver_data;
}; device_driver结构体需要包含“#include linux/device.h”如下
struct device_driver { const char *name; struct bus_type *bus; struct module *owner; const char *mod_name; /* used for built-in modules */ bool suppress_bind_attrs; /* disables bind/unbind via sysfs */ enum probe_type probe_type; const struct of_device_id *of_match_table;
/*of_match_table是采用设备树时驱动使用的匹配表同样是数组每个匹配项都为of_device_id结构体类型*/ const struct acpi_device_id *acpi_match_table; 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); const struct attribute_group **groups; const struct attribute_group **dev_groups; const struct dev_pm_ops *pm; void (*coredump) (struct device *dev); struct driver_private *p;
}; 使用of_device_id结构体需要包含“#include linux/mod_devicetable.h”结构体如下
struct of_device_id { char name[32]; char type[32]; char compatible[128];
/*
对于设备树而言就是通过设备节点的 compatible 属性值和of_match_table中每个项目的 compatible成员变量进行比较如果有相等的就表示设备和此驱动匹配成功
*/ const void *data;
}; int platform_driver_register (struct platform_driver *driver)
//向Linux内核注册一个platform驱动
//driver:要注册的 platform 驱动
//返回值:负数失败0成功 void platform_driver_unregister(struct platform_driver *drv)
//卸载一个platform驱动
//drv要卸载的platform驱动 4、platform驱动框架举例
/* 设备结构体 */
struct xxx_dev{
dev_t devid; /*声明32位变量devid用来给保存设备号*/
int major; /*主设备号*/
int minor; /*次设备号*/
struct cdev cdev; /*字符设备结构变量cdev */ struct class *class; /*类*/
struct device *device; /*设备*/ atomic_t lock; /*原子变量*/
struct fasync_struct *async_queue;
/* fasync_struct结构体即“异步通知”结构体 */
}; struct xxx_dev xxxdev; /* 定义个设备结构体变量 */
static int xxx_open(struct inode *inode, struct file *filp)
{ /* 函数具体内容 */ return 0;
} static ssize_t xxx_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{ /* 函数具体内容 */ return 0;
} /*字符设备驱动操作集*/
static struct file_operations xxx_fops { .owner THIS_MODULE, .open xxx_open, .write xxx_write,
}; /*platform驱动的probe函数
驱动与设备匹配成功以后此函数就会执行
*/
static int xxx_probe(struct platform_device *dev)
{ ...... cdev_init(xxxdev.cdev, xxx_fops); /* 注册字符设备驱动 */ /* 函数具体内容 */ return 0;
} static int xxx_remove(struct platform_device *dev)
{ ..... cdev_del(xxxdev.cdev);/* 删除cdev */ /* 函数具体内容 */ return 0;
} /*对于一个完整的驱动程序必须提供有设备树和无设备树两种匹配方法*/
/* 匹配列表 */
static const struct of_device_id xxx_of_match[] { { .compatible xxx-gpio }, { /* Sentinel */ }
}; /*platform平台驱动结构体*/
static struct platform_driver xxx_driver { .driver { .name xxx,//用于传统的驱动与设备匹配 .of_match_table xxx_of_match, //用于设备树下的驱动与设备检査 }, .probe xxx_probe, .remove xxx_remove,
}; /* 驱动模块加载 */
static int __init xxxdriver_init(void)
{ return platform_driver_register(xxx_driver); //向Linux内核注册一个platform驱动
} /* 驱动模块卸载 */
static void __exit xxxdriver_exit(void)
{ platform_driver_unregister(xxx_driver); //卸载一个platform驱动
} module_init(xxxdriver_init);
module_exit(xxxdriver_exit);
MODULE_LICENSE(GPL);
MODULE_AUTHOR(zgq); 5、platform设备
platform_device结构体需要包含“#include linux/device.h”如下
struct platform_device { const char *name;
//设备名字要和platform驱动的name字段相同这样设备和驱动才能匹配 int id; bool id_auto; struct device dev; u64 platform_dma_mask; u32 num_resources; //资源数量 struct resource *resource;//表示资源也是设备信息 const struct platform_device_id *id_entry; char *driver_override; /* Driver name to force a match */ /* MFD cell pointer */ struct mfd_cell *mfd_cell; /* arch specific additions */ struct pdev_archdata archdata;
}; resource结构体需要包含“#include linux/ioport.h”如下
struct resource { resource_size_t start; //资源的起始信息若为内存资源则表示内存的起始地址 resource_size_t end; //资源的终止信息若为内存资源则表示内存的终止地址 const char *name; //资源的名字 unsigned long flags; //资源的內型 unsigned long desc; // struct resource *parent, *sibling, *child;
}; 资源內型
#define IORESOURCE_BITS 0x000000ff /* Bus-specific bits */ #define IORESOURCE_TYPE_BITS 0x00001f00 /* Resource type */
#define IORESOURCE_IO 0x00000100 /*IO口的资源,PCI/ISA I/O ports */
#define IORESOURCE_MEM 0x00000200 //内存地址
#define IORESOURCE_REG 0x00000300 /* Register offsets */
#define IORESOURCE_IRQ 0x00000400 //中断号
#define IORESOURCE_DMA 0x00000800 //DMA通道号
#define IORESOURCE_BUS 0x00001000 //总线号 #define IORESOURCE_PREFETCH 0x00002000 /* No side effects */
#define IORESOURCE_READONLY 0x00004000
#define IORESOURCE_CACHEABLE 0x00008000
#define IORESOURCE_RANGELENGTH 0x00010000
#define IORESOURCE_SHADOWABLE 0x00020000 int platform_device_register(struct platform_device *pdev)
/*在linux不支持设备树时需要采用手动方式将“platform设备信息”注册到Linux内核*/
//pdev要注册的platform设备。
//返回值:负数失败0成功。 void platform_device_unregister(struct platform_device *pdev)
//在linux不支持设备树时需要手动注销掉相应的“platform设备”
//pdev要注销的platform设备。 6、platform设备框架举例
/* 寄存器地址定义*/
#define PERIPH1_REGISTER_BASE (0X20000000) /* 外设1寄存器首地址 */
#define PERIPH2_REGISTER_BASE (0X020E0068) /* 外设2寄存器首地址 */
#define REGISTER_LENGTH 4 /* 设备资源 */ static struct resource xxx_resources[] { [0] { .start PERIPH1_REGISTER_BASE,//设备外设1起始地址 .end (PERIPH1_REGISTER_BASE REGISTER_LENGTH - 1), //设备外设1终止地址 .flags IORESOURCE_MEM, //资源內型内存地址 }, [1] { .start PERIPH2_REGISTER_BASE, //设备外设2起始地址 .end (PERIPH2_REGISTER_BASE REGISTER_LENGTH - 1), //设备外设2终止地址 .flags IORESOURCE_MEM, //资源內型内存地址 },
}; /* platform设备结构体 */
static struct platform_device xxxdevice { .name xxx-gpio, //必须保证和驱动中的名字一致 .id -1, .num_resources ARRAY_SIZE(xxx_resources), //数组xxx_resources[]的大小ARRAY_SIZE()用来计算数组元素的个数 .resource xxx_resources,//数组xxx_resources[]
}; /* 设备模块加载 */
static int __init xxxdevice_init(void)
{ return platform_device_register(xxxdevice);
//在linux不支持设备树时需要将“platform设备信息”注册到Linux内核
} /* 设备模块注销 */
static void __exit xxx_resourcesdevice_exit(void)
{ platform_device_unregister(xxxdevice); //注销掉相应的“platform设备” //pdevxxxdevice要注销的platform设备。
} module_init(xxxdevice_init);
module_exit(xxxdevice_exit);
MODULE_LICENSE(GPL);
MODULE_AUTHOR(zgq);