summaryrefslogtreecommitdiffstats
path: root/lib/driver.c
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2007-07-05 18:02:12 +0200
committerSascha Hauer <sha@octopus.labnet.pengutronix.de>2007-07-05 18:02:12 +0200
commit4a660c08776809ee08b1d0d62fbaf023080d03ae (patch)
treefe960131e7fbd051ca3d258ae3b7000ab3f90a3e /lib/driver.c
parent24e7509199bc627546fb213158ca04c891c04bc1 (diff)
downloadbarebox-4a660c08776809ee08b1d0d62fbaf023080d03ae.tar.gz
barebox-4a660c08776809ee08b1d0d62fbaf023080d03ae.tar.xz
svn_rev_639
Diffstat (limited to 'lib/driver.c')
-rw-r--r--lib/driver.c333
1 files changed, 333 insertions, 0 deletions
diff --git a/lib/driver.c b/lib/driver.c
new file mode 100644
index 0000000000..227d06ff6b
--- /dev/null
+++ b/lib/driver.c
@@ -0,0 +1,333 @@
+#include <common.h>
+#include <command.h>
+#include <driver.h>
+#include <malloc.h>
+#include <linux/ctype.h>
+#include <errno.h>
+#include <fs.h>
+
+static struct device_d *first_device = NULL;
+static struct driver_d *first_driver = NULL;
+
+struct device_d *get_first_device(void)
+{
+ return first_device;
+}
+
+struct device_d *get_device_by_id(const char *_id)
+{
+ struct device_d *d;
+ char *id, *colon;
+
+ /* FIXME: is this still needed? */
+ id = strdup(_id);
+ if ((colon = strchr(id, ':')))
+ *colon = 0;
+
+ d = first_device;
+
+ while(d) {
+ if(!strcmp(id, d->id))
+ break;
+ d = d->next;
+ }
+
+ free(id);
+ return d;
+}
+
+int get_free_deviceid(char *id, char *id_template)
+{
+ int i = 0;
+
+ while (1) {
+ sprintf(id, "%s%d", id_template, i);
+ if (!get_device_by_id(id))
+ return 0;
+ i++;
+ };
+
+ return -1;
+}
+
+static int match(struct driver_d *drv, struct device_d *dev)
+{
+ if (strcmp(dev->name, drv->name))
+ return -1;
+ if (dev->type != drv->type)
+ return -1;
+ if(drv->probe(dev))
+ return -1;
+
+ dev->driver = drv;
+
+ return 0;
+}
+
+int register_device(struct device_d *new_device)
+{
+ struct driver_d *drv;
+ struct device_d *dev;
+
+ dev = first_device;
+
+ if(*new_device->id && get_device_by_id(new_device->id)) {
+ printf("device %s already exists\n", new_device->id);
+ return -EINVAL;
+ }
+// printf("register_device: %s\n",new_device->name);
+
+ if(!dev) {
+ first_device = new_device;
+ dev = first_device;
+ } else {
+ while(dev->next)
+ dev = dev->next;
+ }
+
+ dev->next = new_device;
+ new_device->next = 0;
+
+ drv = first_driver;
+
+ while(drv) {
+ if (!match(drv, new_device))
+ break;
+ drv = drv->next;
+ }
+
+ return 0;
+}
+
+void unregister_device(struct device_d *old_dev)
+{
+ struct device_d *dev;
+// printf("unregister_device: %s\n",old_dev->name);
+
+ dev = first_device;
+
+ while (dev) {
+ if (!strcmp(dev->next->name, old_dev->name)) {
+ if (old_dev->driver)
+ old_dev->driver->remove(old_dev);
+ dev->next = old_dev->next;
+ return;
+ }
+ dev = dev->next;
+ }
+}
+
+struct driver_d *get_driver_by_name(const char *name)
+{
+ struct driver_d *d;
+
+ d = first_driver;
+
+ while(d) {
+ if(!strcmp(name, d->name))
+ break;
+ d = d->next;
+ }
+
+ return d;
+}
+
+static void noinfo(struct device_d *dev)
+{
+ printf("no info available for %s\n", dev->id);
+}
+
+static void noshortinfo(struct device_d *dev)
+{
+}
+
+int register_driver(struct driver_d *new_driver)
+{
+ struct driver_d *drv;
+ struct device_d *dev = NULL;
+
+ drv = first_driver;
+
+// printf("register_driver: %s\n",new_driver->name);
+
+ if(!drv) {
+ first_driver = new_driver;
+ drv = first_driver;
+ } else {
+ while(drv->next)
+ drv = drv->next;
+ }
+
+ drv->next = new_driver;
+ new_driver->next = 0;
+
+ if (!new_driver->info)
+ new_driver->info = noinfo;
+ if (!new_driver->shortinfo)
+ new_driver->shortinfo = noshortinfo;
+
+ dev = first_device;
+ while (dev) {
+ match(new_driver, dev);
+ dev = dev->next;
+ }
+
+ return 0;
+}
+
+static char devicename_from_spec_str_buf[PATH_MAX];
+
+char *deviceid_from_spec_str(const char *str, char **endp)
+{
+ char *buf = devicename_from_spec_str_buf;
+ const char *end;
+ int i = 0;
+
+ if (isdigit(*str)) {
+ /* No device name given, use default driver mem */
+ sprintf(buf, "mem");
+ end = str;
+ } else {
+ /* OK, we have a device name, parse it */
+ while (*str) {
+ if (*str == ':') {
+ str++;
+ buf[i] = 0;
+ break;
+ }
+
+ buf[i++] = *str++;
+ buf[i] = 0;
+ if (i == MAX_DRIVER_NAME)
+ return NULL;
+ }
+ end = str;
+ }
+
+ if (endp)
+ *endp = (char *)end;
+
+ return buf;
+}
+
+/* Get a device struct from the beginning of the string. Default to mem if no
+ * device is given, return NULL if a unknown device is given.
+ * If endp is not NULL, this function stores a pointer to the first character
+ * after the device name in *endp.
+ */
+struct device_d *device_from_spec_str(const char *str, char **endp)
+{
+ char *name;
+ name = deviceid_from_spec_str(str, endp);
+ return get_device_by_id(name);
+}
+
+/* Get devices from their type.
+ * If last is NULL the first device of this type is given.
+ * If last is not NULL, the next device of this type starting
+ * from last is given.
+ */
+struct device_d *get_device_by_type(ulong type, struct device_d *last)
+{
+ struct device_d *dev;
+
+ if (!last)
+ dev = first_device;
+ else
+ dev = last->next;
+
+ while (dev) {
+ if (dev->type == type)
+ return dev;
+ dev = dev->next;
+ }
+
+ return NULL;
+}
+
+ssize_t dev_read(struct device_d *dev, void *buf, size_t count, unsigned long offset, ulong flags)
+{
+ if (dev->driver->read)
+ return dev->driver->read(dev, buf, count, offset, flags);
+ errno = -ENOSYS;
+ return -ENOSYS;
+}
+
+ssize_t dev_write(struct device_d *dev, const void *buf, size_t count, unsigned long offset, ulong flags)
+{
+ if (dev->driver->write)
+ return dev->driver->write(dev, buf, count, offset, flags);
+ errno = -ENOSYS;
+ return -ENOSYS;
+}
+
+ssize_t dev_erase(struct device_d *dev, size_t count, unsigned long offset)
+{
+ if (dev->driver->erase)
+ return dev->driver->erase(dev, count, offset);
+ errno = -ENOSYS;
+ return -ENOSYS;
+}
+
+int dummy_probe(struct device_d *dev)
+{
+ return 0;
+}
+
+int do_devinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ struct device_d *dev = first_device;
+ struct driver_d *drv = first_driver;
+ struct param_d *param;
+
+ if (argc == 1) {
+ printf("devices:\n");
+
+ while(dev) {
+ printf("%10s: base=0x%08x size=0x%08x (driver %s)\n",
+ dev->id, dev->map_base, dev->size, dev->driver ? dev->driver->name : "none");
+ dev = dev->next;
+ }
+
+ printf("drivers:\n");
+ while(drv) {
+ printf("%10s\n",drv->name);
+ drv = drv->next;
+ }
+ } else {
+ struct device_d *dev = get_device_by_id(argv[1]);
+
+ if (!dev) {
+ printf("no such device: %s\n",argv[1]);
+ return -1;
+ }
+
+ if (dev->driver)
+ dev->driver->info(dev);
+
+ param = dev->param;
+
+ printf("%s\n", param ? "Parameters:" : "no parameters available");
+
+ while (param) {
+ printf("%16s = %s\n", param->name, param->value);
+ param = param->next;
+ }
+
+ }
+
+ return 0;
+}
+
+static __maybe_unused char cmd_devinfo_help[] =
+"Usage: devinfo [DEVICE]\n"
+"If called without arguments devinfo shows a summary about known devices and\n"
+"drivers. If called with a device id as argument devinfo shows more detailed\n"
+"informations about this device and its parameters.\n";
+
+U_BOOT_CMD_START(devinfo)
+ .maxargs = 2,
+ .cmd = do_devinfo,
+ .usage = "display info about devices and drivers",
+ U_BOOT_CMD_HELP(cmd_devinfo_help)
+U_BOOT_CMD_END