[Tinyx-devel] [PATCH] Device subsystem improvements.
Status: Planning
Brought to you by:
davidcohen
From: David C. <da...@gm...> - 2007-12-11 23:09:24
|
This patch updates the device subsystem: - implements the register_* on device.c - code cleanups on device.h - adding ioctl on bus Signed-off-by: David Cohen <da...@gm...> --- include/tinyx/device.h | 27 ++++++++++----- kernel/device.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 104 insertions(+), 12 deletions(-) diff --git a/include/tinyx/device.h b/include/tinyx/device.h index b5de65a..2916925 100644 --- a/include/tinyx/device.h +++ b/include/tinyx/device.h @@ -1,6 +1,8 @@ #ifndef __TINYX_DEVICE_H #define __TINYX_DEVICE_H +#include <tinyx/list.h> + struct bus_type; struct device_driver; struct device; @@ -22,26 +24,33 @@ struct resource { }; struct bus_type { - struct list_head *head; - const char *name; - int id; + struct list_head queue; + unsigned int type; void *private_data; int (*probe) (struct bus_type *bus); int (*remove) (struct bus_type *bus); - int (*match) (struct device *dev, struct device_driver *drv); + int (*match) (struct bus_type *bus, + struct device *dev, struct device_driver *drv); - void (*writeb) (struct device *dev, unsigned char val, unsigned long addr); - void (*writew) (struct device *dev, unsigned int val, unsigned long addr); - void (*writel) (struct device *dev, unsigned long val, unsigned long addr); + /* These write* and read* exists in order to avoid if's + * inside critial buses. */ + void (*writeb) (struct device *dev, + unsigned char val, unsigned long addr); + void (*writew) (struct device *dev, + unsigned int val, unsigned long addr); + void (*writel) (struct device *dev, + unsigned long val, unsigned long addr); unsigned char (*readb) (struct device *dev, unsigned long addr); unsigned int (*readw) (struct device *dev, unsigned long addr); unsigned long (*readl) (struct device *dev, unsigned long addr); + + void (*ioctl) (struct device *dev, void *data, int type); }; struct device_driver { - struct list_head *head; + struct list_head queue; const char *name; int (*probe) (struct device *dev); @@ -49,7 +58,7 @@ struct device_driver { }; struct device { - struct list_head *head; + struct list_head queue; const char *name; int id; struct device_driver *drv; diff --git a/kernel/device.c b/kernel/device.c index 0b11433..a7baeb1 100644 --- a/kernel/device.c +++ b/kernel/device.c @@ -1,16 +1,99 @@ #include <tinyx/device.h> +#include <tinyx/list.h> +#include <tinyx/libc/string.h> + +DECLARE_LIST_HEAD(bus_list); +DECLARE_LIST_HEAD(driver_list); +DECLARE_LIST_HEAD(device_list); + +static void *match_device_driver(struct device *dev, struct device_driver *drv) +{ + struct list_head *list; + struct list_head *entry; + void *item; + int ret; + + if (!dev) + list = &device_list; + else + list = &driver_list; + + list_for_each(list, entry) { + if (!dev) { + item = list_entry(entry, struct device, queue); + ret = strcmp(((struct device *)item)->name, drv->name); + } else { + item = list_entry(entry, struct device_driver, queue); + ret = strcmp(dev->name, + ((struct device_driver *)item)->name); + } + if (!ret) + break; + else + item = NULL; + } + + return item; +} int register_bus_type(struct bus_type *bus) { - return 0; + int ret = 0; + + if (bus == NULL) + return -ENODEV; + + if (bus->probe) + ret = bus->probe(bus); + if (!ret) + list_add_tail(&bus_list, &bus->queue); + + return ret; } int register_device_driver(struct device_driver *drv) { - return 0; + int ret = 0; + struct device *dev; + + if (drv == NULL) + return -ENODEV; + + dev = match_device_driver(NULL, drv); + if (dev) { + if (dev->bus->match) + ret = dev->bus->match(dev->bus, dev, drv); + if (!ret && drv->probe) + ret = drv->probe(dev); + } + + if (!ret) + list_add_tail(&driver_list, &drv->queue); + + return ret; } int register_device(struct device *dev, struct bus_type *bus) { - return 0; + int ret = 0; + struct device_driver *drv; + + if (dev == NULL) + return -ENODEV; + + dev->bus = bus; + drv = match_device_driver(dev, NULL); + if (drv) { + if (bus->match) + ret = bus->match(bus, dev, drv); + if (!ret && drv->probe) + ret = drv->probe(dev); + } + + if (!ret) + list_add_tail(&device_list, &dev->queue); + else + dev->bus = NULL; + + return ret; } -- 1.5.3.5 |