1. Linux2.6内核引入总线、设备、驱动模型来描述各种总线(PCI、USB、I2C、SPI)与外围设备及其驱动之间的关系。
2. 在Linux内核中,总线用bus_type结构来描述,定义于文件:include/linux/Device.h
struct bus_type { const char *name; struct bus_attribute *bus_attrs; struct device_attribute *dev_attrs; struct driver_attribute *drv_attrs; int (*match)(struct device *dev, struct device_driver *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 (*suspend)(struct device *dev, pm_message_t state); int (*suspend_late)(struct device *dev, pm_message_t state); int (*resume_early)(struct device *dev); int (*resume)(struct device *dev); struct dev_pm_ops *pm; struct bus_type_private *p; };
① name:总线名字,如PCI
② bus_attrs:总线属性
③ match:当一个新设备或者新驱动被添加到这个总线时,该函数被调用。用于判断指定的驱动程序是否能处理指定的设备。若可以,则返回非零。
④ uevent:
⑤ probe:
⑥ remove:
(1) 总线的注册:int us_register(struct bus_type *bus)(若注册成功,新的总线将被添加进系统,可在/sys/bus 下看到相应的目录)
(2) 总线的注销:void bus_unregister(struct bus_type *bus)
3. 在Linux内核中, 驱动由device_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; };
① probe:
② remove:
(1)驱动的注册:int driver_register(struct device_driver *drv)
(2)驱动的注销:void driver_unregister(struct device_driver *drv)
4. 在Linux内核中, 设备由struct device结构描述
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); };
(1)设备的注册:int device_register(struct device *dev)
(2)设备的注销:void device_unregister(struct device *dev)
5. 简单示例
(1)Bus.c
#include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/device.h> MODULE_LICENSE("GPL"); int my_match(struct device *dev, struct device_driver *drv) { printk("Bus: my_match\n"); return !strncmp(dev->kobj.name, drv->name, strlen(drv->name)); } int my_remove(struct device *dev) { printk("Bus: Device %s removed from bus\n", dev->init_name); } struct bus_type my_bus_type = { .name = "my_bus", .match = my_match, .remove = my_remove, }; EXPORT_SYMBOL(my_bus_type); int my_bus_init(void) { int ret; ret = bus_register(&my_bus_type); return ret; } void my_bus_exit(void) { bus_unregister(&my_bus_type); } module_init(my_bus_init); module_exit(my_bus_exit);
(2)Device.c
#include <linux/device.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> MODULE_LICENSE("GPL"); extern struct bus_type my_bus_type; void my_release(struct device *dev) { printk("Device: Device %s's release function\n", dev->init_name); } struct device my_dev = { .init_name = "my_dev", .bus = &my_bus_type, .release = my_release, }; int my_device_init(void) { int ret; ret = device_register(&my_dev); return ret; } void my_device_exit(void) { device_unregister(&my_dev); } module_init(my_device_init); module_exit(my_device_exit);
(3)Driver.c
#include <linux/device.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> MODULE_LICENSE("GPL"); extern struct bus_type my_bus_type; int my_probe(struct device *dev) { printk("Driver: driver found the device it can handle!\n"); return 0; } struct device_driver my_driver = { .name = "my_dev", .bus = &my_bus_type, .probe = my_probe, }; int my_driver_init(void) { int ret; ret = driver_register(&my_driver); return ret; } void my_driver_exit(void) { driver_unregister(&my_driver); } module_init(my_driver_init); module_exit(my_driver_exit);