没有时间把一件事情做好,却有时间把一件事情反复做!
全部博文(191)
分类: 嵌入式
2014-03-26 15:36:27
为了适用要求越来越高的硬件设备需求,linux2.6内核提供了一种全新的内核设备模型。
设备模型三元素:总线、设备、驱动;
第一节:总线
总线是处理器与设备之间的通道,所有的设备通过总线相连;总线由bus_type定义(位于
1 struct bus_type {
2 const char *name;
3 struct bus_attribute *bus_attrs;
4 struct device_attribute *dev_attrs;
5 struct driver_attribute *drv_attrs;
6
7 int (*match)(struct device *dev, struct device_driver *drv);
8 int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
9 int (*probe)(struct device *dev);
10 int (*remove)(struct device *dev);
11 void (*shutdown)(struct device *dev);
12
13 int (*suspend)(struct device *dev, pm_message_t state);
14 int (*resume)(struct device *dev);
15
16 const struct dev_pm_ops *pm;
17 device
18 struct subsys_private *p;
19 };
bus_type结构体中重要的方法:
match:当一个新设备或驱动被添加到这条总线时,该方法被调用。用来判断制定的驱动程序是否能够处理指定的设备。若可以,返回非零值。
uevent:为用户空间产生热插拔事件之前,这个方法允许总线添加环境变量;
bus_attribute: 总线属性,这个结构体如下
1 struct bus_attribute {
2 struct attribute attr;
3 ssize_t (*show)(struct bus_type *bus, char *buf);
4 ssize_t (*store)(struct bus_type *bus, const char *buf, size_t count);
5 };
总线属性的操作方法:
int bus_create_file(struct bus_type *bus,struct bus_attribute *attr) //创建属性
void bus_remove_file(struct bus_type*bus, struct bus_attribute *attr) //删除属性
总线的常用操作函数:
int bus_register(struct bus_type * bus) //总线的注册
void bus_unregister(struct bus_type *bus) //总线的删除
第二节:设备
linux每个设备又结构体devices来定义(位于linux/device.h),如下:
1 struct device { 2 struct device *parent; 3 4 struct device_private *p; 5 6 struct kobject kobj; 7 const char *init_name; /* initial name of the device */ 8 struct device_type *type; 9 10 struct mutex mutex; /* mutex to synchronize calls to 11 * its driver. 12 */ 13 14 struct bus_type *bus; /* type of bus device is on */ 15 struct device_driver *driver; /* which driver has allocated this 16 device */ 17 void *platform_data; /* Platform specific data, device 18 core doesn't touch it */ 19 struct dev_pm_info power; 20 21 #ifdef CONFIG_NUMA 22 int numa_node; /* NUMA node this device is close to */ 23 #endif 24 u64 *dma_mask; /* dma mask (if dma'able device) */ 25 u64 coherent_dma_mask;/* Like dma_mask, but for 26 alloc_coherent mappings as 27 not all hardware supports 28 64 bit addresses for consistent 29 allocations such descriptors. */ 30 31 struct device_dma_parameters *dma_parms; 32 33 struct list_head dma_pools; /* dma pools (if dma'ble) */ 34 35 struct dma_coherent_mem *dma_mem; /* internal for coherent mem 36 override */ 37 /* arch specific additions */ 38 struct dev_archdata archdata; 39 #ifdef CONFIG_OF 40 struct device_node *of_node; 41 #endif 42 43 dev_t devt; /* dev_t, creates the sysfs "dev" */ 44 45 spinlock_t devres_lock; 46 struct list_head devres_head; 47 48 struct klist_node knode_class; 49 struct class *class; 50 const struct attribute_group **groups; /* optional groups */ 51 52 void (*release)(struct device *dev); 53 };
设备属性由struct device_attribute描述:
1 struct device_attribute { 2 struct attribute attr; 3 ssize_t (*show)(struct device *dev, struct device_attribute *attr, 4 char *buf); 5 ssize_t (*store)(struct device *dev, struct device_attribute *attr, 6 const char *buf, size_t count); 7 };
设备属性的常用操作方法:
int device_create_file(struct device *device, struct device_attribute * entry) //创建属性
void device_remove_file(struct device * dev, struct device_attribute * attr) //删除属性
设备的常用操作函数:
int device_register(struct device *dev) //注册一个设备;
void device_unregister(struct device *dev) //注销设备
注意:一条总线也是个设备,也必须按设备注册;
第三节:驱动
驱动程序由struct device_driver描述,代码如下:
1 struct device_driver { 2 const char *name; 3 struct bus_type *bus; 4 5 struct module *owner; 6 const char *mod_name; /* used for built-in modules */ 7 8 bool suppress_bind_attrs; /* disables bind/unbind via sysfs */ 9 10 #if defined(CONFIG_OF) 11 const struct of_device_id *of_match_table; 12 #endif 13 14 int (*probe) (struct device *dev); 15 int (*remove) (struct device *dev); 16 void (*shutdown) (struct device *dev); 17 int (*suspend) (struct device *dev, pm_message_t state); 18 int (*resume) (struct device *dev); 19 const struct attribute_group **groups; 20 21 const struct dev_pm_ops *pm; 22 23 struct driver_private *p; 24 };
驱动属性使用struct driver_attribute来描述,如下:
1 struct driver_attribute { 2 struct attribute attr; 3 ssize_t (*show)(struct device_driver *driver, char *buf); 4 ssize_t (*store)(struct device_driver *driver, const char *buf, 5 size_t count); 6 };
驱动属性的常用操作方法:
int driver_create_file(struct device_driver * drv,struct driver_attribute * attr) //创建属性
void driver_remove_file(struct device_driver * drv,struct driver_attribute * attr) /删除属性
驱动常用的操作函数:
int driver_register(struct device_driver *drv) //注册驱动
void driver_unregister(struct device_driver *drv) //注销驱动
实例分析:
至此,已经介绍完设备模型的基本结构,下面以一个实例分析三者之间的关系:
bus.c 在sysfs/bus下创建一个总线目录my_bus
1 #include2 #include 3 #include 4 #include 5 #include string.h> 6 7 MODULE_AUTHOR("David Xie"); 8 MODULE_LICENSE("Dual BSD/GPL"); 9 10 static char *Version = "$Revision: 1.9 $"; 11 12 /*比较设备的bus_id与驱动的名字是否匹配,匹配一致则在insmod驱动 时候调用probe函数*/ 13 14 static int my_match(struct device *dev, struct device_driver *driver) 15 { 16 return !strncmp(dev->bus_id, driver->name, strlen(driver->name)); 17 } 18 19 static void my_bus_release(struct device *dev) 20 { 21 printk(KERN_DEBUG "my bus release\n"); 22 } 23 24 struct bus_type my_bus_type = { 25 .name = "my_bus", 26 .match = my_match, 27 }; 28 29 struct device my_bus = { 30 .bus_id = "my_bus0", 31 .release = my_bus_release 32 }; 33 34 35 /*符号导出 36 * Export a simple attribute. 37 */ 38 EXPORT_SYMBOL(my_bus); 39 EXPORT_SYMBOL(my_bus_type); 40 41 static ssize_t show_bus_version(struct bus_type *bus, char *buf) 42 { 43 return snprintf(buf, PAGE_SIZE, "%s\n", Version); 44 } 45 46 static BUS_ATTR(version, S_IRUGO, show_bus_version, NULL); 47 48 49 static int __init my_bus_init(void) 50 { 51 int ret; 52 53 /*注册总线*/ 54 ret = bus_register(&my_bus_type); 55 if (ret) 56 return ret; 57 58 /*创建属性文件*/ 59 if (bus_create_file(&my_bus_type, &bus_attr_version)) 60 printk(KERN_NOTICE "Fail to create version attribute!\n"); 61 62 /*注册总线设备,设备是挂在my_bus总线上的,怎么做的呢?看device.c*/ 63 ret = device_register(&my_bus); 64 if (ret) 65 printk(KERN_NOTICE "Fail to register device:my_bus!\n"); 66 67 return ret; 68 } 69 70 static void my_bus_exit(void) 71 { 72 device_unregister(&my_bus); 73 bus_unregister(&my_bus_type); 74 } 75 76 module_init(my_bus_init); 77 module_exit(my_bus_exit);
device.c 在sysfs/bus/my_bus/devices目录下创建一个设备my_dev
这里my_dev是一个连接文件,它连接到sysfs/devices/my_bus0/my_dev
1 #include2 #include 3 #include 4 #include 5 #include string.h> 6 7 MODULE_AUTHOR("David Xie"); 8 MODULE_LICENSE("Dual BSD/GPL"); 9 10 extern struct device my_bus; 11 extern struct bus_type my_bus_type; 12 13 /* Why need this ?*/ 14 static void my_dev_release(struct device *dev) 15 { 16 17 } 18 19 struct device my_dev = { 20 .bus = &my_bus_type, 21 .parent = &my_bus, 22 .release = my_dev_release, 23 }; 24 25 /* 26 * Export a simple attribute. 27 */ 28 static ssize_t mydev_show(struct device *dev,struct device_attribute *attr, char *buf) 29 { 30 return sprintf(buf, "%s\n", "This is my device!"); 31 } 32 33 static DEVICE_ATTR(dev, S_IRUGO, mydev_show, NULL); 34 35 static int __init my_device_init(void) 36 { 37 int ret = 0; 38 39 /* 初始化设备 */ 40 strncpy(my_dev.bus_id, "my_dev", BUS_ID_SIZE); 41 42 /*注册设备*/ 43 device_register(&my_dev); 44 45 /*创建属性文件*/ 46 device_create_file(&my_dev, &dev_attr_dev); 47 48 return ret; 49 50 } 51 52 static void my_device_exit(void) 53 { 54 device_unregister(&my_dev); 55 } 56 57 module_init(my_device_init); 58 module_exit(my_device_exit);
driver.c 当加载驱动时候,会在总线上找到它能够处理的设备
1 #include2 #include 3 #include 4 #include 5 #include string.h> 6 7 MODULE_AUTHOR("David Xie"); 8 MODULE_LICENSE("Dual BSD/GPL"); 9 10 extern struct bus_type my_bus_type; 11 12 static int my_probe(struct device *dev) 13 { 14 printk("Driver found device which my driver can handle!\n"); 15 return 0; 16 } 17 18 static int my_remove(struct device *dev) 19 { 20 printk("Driver found device unpluged!\n"); 21 return 0; 22 } 23 24 struct device_driver my_driver = { 25 .name = "my_dev", 26 .bus = &my_bus_type, /*指明这个驱动程序是属于my_bus_type这条总线上的设备*/ 27 .probe = my_probe, /*在my_bus_type总线上找到它能够处理的设备,就调用my_probe;删除设备调用my_remove*/ 28 .remove = my_remove, 29 /*能够处理的设备? 30 1、什么时候驱动程序从总线找能够处理的设备;答:驱动注册时候 31 2、凭什么说能够处理呢?(或者说标准是什么);答:驱动与设备都是属于总线上的,利用总线的结构bus_type中match函数 32 */ 33 }; 34 35 /* 36 * Export a simple attribute. 37 */ 38 static ssize_t mydriver_show(struct device_driver *driver, char *buf) 39 { 40 return sprintf(buf, "%s\n", "This is my driver!"); 41 } 42 43 static DRIVER_ATTR(drv, S_IRUGO, mydriver_show, NULL); 44 45 static int __init my_driver_init(void) 46 { 47 int ret = 0; 48 49 /*注册驱动*/ 50 driver_register(&my_driver); 51 52 /*创建属性文件*/ 53 driver_create_file(&my_driver, &driver_attr_drv); 54 55 return ret; 56 57 } 58 59 static void my_driver_exit(void) 60 { 61 driver_unregister(&my_driver); 62 } 63 64 module_init(my_driver_init); 65 module_exit(my_driver_exit);
注意:无论是先加载驱动还是设备,都会调用probe这个函数。好比先插u盘,在启动系统 与启动系统后再插u盘,系统一样能够支持。