Chinaunix首页 | 论坛 | 博客
  • 博客访问: 465402
  • 博文数量: 191
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 172
  • 用 户 组: 普通用户
  • 注册时间: 2013-10-31 14:35
个人简介

没有时间把一件事情做好,却有时间把一件事情反复做!

文章分类

全部博文(191)

文章存档

2016年(2)

2015年(74)

2014年(111)

2013年(4)

我的朋友

分类: 嵌入式

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 #include   2 #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 #include   2 #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 #include   2 #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盘,系统一样能够支持。

阅读(546) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~