Linux驅動2_總線設備(一)
// 參考 Linux設備驅動程序(lld3) // 實現一個簡單的虛擬總線 simple bus // simple_bus_type為總線類型 // simple_bus為總線設備 // // simple.c 實現 #include "simple.h" // 增加設備引用計數 static struct simple_device *simple_dev_get(struct simple_device *dev) { if (dev) get_device(&dev->device); return dev; } // 遞減設備引用計數 static void simple_dev_put(struct simple_device *dev) { if (dev) put_device(&dev->device); } // 匹配設備/驅動 // 當有新設備或新驅動添加到總線時,判斷是否匹配 // 調用路徑:核心設備子係統-> static int simple_device_match(struct device *dev, struct device_driver *drv) { struct simple_device *sim_dev = to_simple_device(dev); struct simple_driver *sim_drv = to_simple_driver(drv); struct simple_class_id *ids = sim_drv->classes; if (ids) while (ids->class_id != SIMPLE_CLASS_END) { if (ids->class_id == sim_dev->class_id.class_id) return 1; ids++; } return 0; } // 添加設備/驅動 // 當simple_device_match返回true,說明device和driver匹配,通過 // 調用probe調用驅動的probe函數,初始化設備 // 調用路徑:核心設備子係統-> static int simple_device_probe(struct device *dev) { int ret = 0; struct simple_device *sim_dev; struct simple_driver *sim_drv; sim_dev = to_simple_device(dev); sim_drv = to_simple_driver(dev->driver); simple_dev_get(sim_dev); if (sim_drv->probe) ret = sim_drv->probe(sim_dev); if (ret) simple_dev_put(sim_dev); return ret; } // 熱插拔設備 // 總線上設備被熱插拔 // 調用路徑:核心設備子係統-> static int simple_device_remove(struct device *dev) { struct simple_device *sim_dev = to_simple_device(dev); struct simple_driver *sim_drv = to_simple_driver(dev->driver); if (sim_drv) { if (sim_drv->remove) { sim_drv->remove(sim_dev); } } simple_dev_put(sim_dev); return 0; } // 獲取設備class id static ssize_t simple_device_show_class_id(struct device *dev, struct device_attribute *attr, char *buf) { struct simple_device *sim_dev = to_simple_device(dev); sprintf(buf, "0x%x\n", sim_dev->class_id.class_id); return strlen(buf) + 1; } // simple bus 設備屬性 struct device_attribute simple_device_attrs[] = { __ATTR(class_id, S_IRUGO, simple_device_show_class_id, NULL), __ATTR_NULL }; // simple bus 總線類型 struct bus_type simple_bus_type = { .name = "simple", .match = simple_device_match, .probe = simple_device_probe, .remove = simple_device_remove, .dev_attrs = simple_device_attrs }; static void simple_bus_release(struct device *dev) { return; } // simple bus 總線設備 struct simple_bus simple_bus; // simple bus 模塊初始化 static int __init simple_init(void) { int ret; /* create /sys/bus/simple.*/ if ((ret = bus_register(&simple_bus_type)) < 0) { printk(KERN_ALERT "[SIMPLE] bus_register failed.\n"); goto err_bus_register; } simple_bus.dev.release = simple_bus_release; //simple_bus.dev.parent為null,表示為該總線的頂層設備 dev_set_name(&simple_bus.dev, "simple"); /* create /sys/devices/simple.*/ if ((ret = device_register(&simple_bus.dev))) { printk(KERN_ALERT "[SIMPLE] device_register failed.\n"); goto err_dev_register; } return ret; err_dev_register: bus_unregister(&simple_bus_type); err_bus_register: return ret; } // simple bus 模塊卸載 static void __exit simple_exit(void) { device_unregister(&simple_bus.dev); bus_unregister(&simple_bus_type); } static void simple_device_release(struct device *dev) { return; } // 注冊設備 // 向simple bus注冊設備 int simple_register_device(struct simple_device *dev) { dev_set_name(&dev->device, dev->name); //設備類型為實現的simple_bus_type dev->device.bus = &simple_bus_type; //掛載的總線為simple_bus dev->device.parent = &simple_bus.dev; dev->device.release = simple_device_release; return device_register(&dev->device); } EXPORT_SYMBOL(simple_register_device); // 注銷設備 // 從simple bus注銷設備 void simple_unregister_device(struct simple_device *dev) { /* * device_unregister will do in two parts, first, remove it from all the subsystems with device_del(), * then decrement the reference count via put_device(). If that is the final reference count, * the device will be cleaned up via device_release() above. Otherwise, the structure will stick * around until the final reference to the device is dropped. */ device_unregister(&dev->device); } EXPORT_SYMBOL(simple_unregister_device); // 注冊驅動 // 向simple bus注冊驅動 int simple_register_driver(struct simple_driver *drv) { int ret = 0; drv->driver.name= drv->name; drv->driver.bus = &simple_bus_type; ret = driver_register(&drv->driver); return ret; } EXPORT_SYMBOL(simple_register_driver); // 注銷驅動 // 從simple bus注銷驅動 void simple_unregister_driver(struct simple_driver *drv) { driver_unregister(&drv->driver); } EXPORT_SYMBOL(simple_unregister_driver); module_init(simple_init); module_exit(simple_exit); MODULE_LICENSE("GPL");
// simple.h,類型聲明 #include <linux/init.h> #include <linux/module.h> #include <linux/device.h> #ifndef _SIMPLE_BUS_H_ #define _SIMPLE_BUS_H_ #define to_simple_device(dev) container_of(dev, struct simple_device, device) #define to_simple_driver(drv) container_of(drv, struct simple_driver, driver) #define SIMPLE_CLASS_END 0xffff struct simple_class_id { u16 class_id; }; struct simple_device { char *name; struct device device; struct simple_class_id class_id; }; struct simple_driver { char *name; struct device_driver driver; struct simple_class_id *classes; int (*probe) (struct simple_device *dev); /*Device removed (NULL if not a hot-plug capable driver) */ int (*remove) (struct simple_device *dev); }; struct simple_bus { struct device dev; }; extern int simple_register_device(struct simple_device *dev); extern void simple_unregister_device(struct simple_device *dev); extern int simple_register_driver(struct simple_driver *drv); extern void simple_unregister_driver(struct simple_driver *drv); #endif
最後更新:2017-04-03 12:54:06