menu: simplify usage for clients
[barebox-mini2440.git] / lib / driver.c
blobb60074511fae60b56348abd1fc1c736a2af84fbf
1 /*
2 * driver.c - barebox driver model
4 * Copyright (c) 2007 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
6 * See file CREDITS for list of people who contributed to this
7 * project.
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2
11 * as published by the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 /**
24 * @file
25 * @brief barebox's driver model, and devinfo command
28 #include <common.h>
29 #include <command.h>
30 #include <driver.h>
31 #include <malloc.h>
32 #include <linux/ctype.h>
33 #include <errno.h>
34 #include <fs.h>
35 #include <linux/list.h>
37 LIST_HEAD(device_list);
38 EXPORT_SYMBOL(device_list);
40 LIST_HEAD(driver_list);
41 EXPORT_SYMBOL(driver_list);
43 static LIST_HEAD(active);
45 struct device_d *get_device_by_name(const char *name)
47 struct device_d *dev;
48 char devname[MAX_DRIVER_NAME + 3];
50 for_each_device(dev) {
51 sprintf(devname, "%s%d", dev->name, dev->id);
52 if(!strcmp(name, devname))
53 return dev;
56 return NULL;
59 int get_free_deviceid(const char *name_template)
61 int i = 0;
62 char name[MAX_DRIVER_NAME + 3];
64 while (1) {
65 sprintf(name, "%s%d", name_template, i);
66 if (!get_device_by_name(name))
67 return i;
68 i++;
72 static int match(struct driver_d *drv, struct device_d *dev)
74 if (dev->driver)
75 return -1;
77 dev->driver = drv;
79 if (dev->bus != drv->bus)
80 goto err_out;
81 if (dev->bus->match(dev, drv))
82 goto err_out;
83 if (dev->bus->probe(dev))
84 goto err_out;
86 list_add(&dev->active, &active);
88 return 0;
89 err_out:
90 dev->driver = NULL;
91 return -1;
94 int register_device(struct device_d *new_device)
96 struct driver_d *drv;
98 new_device->id = get_free_deviceid(new_device->name);
100 debug ("register_device: %s\n",new_device->name);
102 if (!new_device->bus) {
103 // dev_err(new_device, "no bus type associated. Needs fixup\n");
104 new_device->bus = &platform_bus;
107 list_add_tail(&new_device->list, &device_list);
108 INIT_LIST_HEAD(&new_device->children);
109 INIT_LIST_HEAD(&new_device->cdevs);
110 INIT_LIST_HEAD(&new_device->parameters);
112 for_each_driver(drv) {
113 if (!match(drv, new_device))
114 break;
117 return 0;
119 EXPORT_SYMBOL(register_device);
121 int unregister_device(struct device_d *old_dev)
123 debug("unregister_device: %s:%s\n",old_dev->name, old_dev->id);
125 if (!list_empty(&old_dev->children)) {
126 errno = -EBUSY;
127 return errno;
130 if (old_dev->driver)
131 old_dev->bus->remove(old_dev);
133 list_del(&old_dev->list);
135 /* remove device from parents child list */
136 if (old_dev->parent)
137 list_del(&old_dev->sibling);
139 return 0;
141 EXPORT_SYMBOL(unregister_device);
143 int dev_add_child(struct device_d *dev, struct device_d *child)
145 child->parent = dev;
147 list_add_tail(&child->sibling, &dev->children);
149 return 0;
151 EXPORT_SYMBOL(dev_add_child);
153 struct driver_d *get_driver_by_name(const char *name)
155 struct driver_d *drv;
157 for_each_driver(drv) {
158 if(!strcmp(name, drv->name))
159 return drv;
162 return NULL;
165 static void noinfo(struct device_d *dev)
167 printf("no info available for %s\n", dev->name);
170 static void noshortinfo(struct device_d *dev)
174 int register_driver(struct driver_d *drv)
176 struct device_d *dev = NULL;
178 debug("register_driver: %s\n", drv->name);
180 if (!drv->bus) {
181 // pr_err("driver %s has no bus type associated. Needs fixup\n", drv->name);
182 drv->bus = &platform_bus;
185 list_add_tail(&drv->list, &driver_list);
187 if (!drv->info)
188 drv->info = noinfo;
189 if (!drv->shortinfo)
190 drv->shortinfo = noshortinfo;
192 for_each_device(dev)
193 match(drv, dev);
195 return 0;
197 EXPORT_SYMBOL(register_driver);
199 int dev_protect(struct device_d *dev, size_t count, unsigned long offset, int prot)
201 printf("%s: currently broken\n", __func__);
202 return -EINVAL;
205 int generic_memmap_ro(struct cdev *cdev, void **map, int flags)
207 if (!cdev->dev)
208 return -EINVAL;
210 if (flags & PROT_WRITE)
211 return -EACCES;
212 *map = (void *)cdev->dev->map_base;
213 return 0;
216 int generic_memmap_rw(struct cdev *cdev, void **map, int flags)
218 if (!cdev->dev)
219 return -EINVAL;
221 *map = (void *)cdev->dev->map_base;
222 return 0;
225 int dummy_probe(struct device_d *dev)
227 return 0;
229 EXPORT_SYMBOL(dummy_probe);
231 static int do_devinfo_subtree(struct device_d *dev, int depth, char edge)
233 struct device_d *child;
234 struct cdev *cdev;
235 int i;
237 for (i = 0; i < depth; i++)
238 printf("| ");
240 printf("%c----%s%d", edge, dev->name, dev->id);
241 if (!list_empty(&dev->cdevs)) {
242 printf(" (");
243 list_for_each_entry(cdev, &dev->cdevs, devices_list) {
244 printf("%s", cdev->name);
245 if (!list_is_last(&cdev->devices_list, &dev->cdevs))
246 printf(", ");
248 printf(")");
250 printf("\n");
252 if (!list_empty(&dev->children)) {
253 device_for_each_child(dev, child) {
254 do_devinfo_subtree(child, depth + 1,
255 list_is_last(&child->sibling,
256 &dev->children) ? '`' : '|');
260 return 0;
263 const char *dev_id(const struct device_d *dev)
265 static char buf[sizeof(unsigned long) * 2];
267 sprintf(buf, "%s%d", dev->name, dev->id);
269 return buf;
272 void devices_shutdown(void)
274 struct device_d *dev;
276 list_for_each_entry(dev, &active, active) {
277 if (dev->driver->remove)
278 dev->driver->remove(dev);
282 #ifdef CONFIG_CMD_DEVINFO
284 static int do_devinfo(struct command *cmdtp, int argc, char *argv[])
286 struct device_d *dev;
287 struct driver_d *drv;
288 struct param_d *param;
290 if (argc == 1) {
291 printf("devices:\n");
293 for_each_device(dev) {
294 if (!dev->parent)
295 do_devinfo_subtree(dev, 0, '|');
298 printf("\ndrivers:\n");
299 for_each_driver(drv)
300 printf("%10s\n",drv->name);
301 } else {
302 struct device_d *dev = get_device_by_name(argv[1]);
304 if (!dev) {
305 printf("no such device: %s\n",argv[1]);
306 return -1;
309 printf("base : 0x%08x\nsize : 0x%08x\ndriver: %s\n\n",
310 dev->map_base, dev->size,
311 dev->driver ?
312 dev->driver->name : "none");
314 if (dev->driver)
315 dev->driver->info(dev);
317 printf("%s\n", list_empty(&dev->parameters) ?
318 "no parameters available" : "Parameters:");
320 list_for_each_entry(param, &dev->parameters, list)
321 printf("%16s = %s\n", param->name, param->value);
324 return 0;
327 static const __maybe_unused char cmd_devinfo_help[] =
328 "Usage: devinfo [DEVICE]\n"
329 "If called without arguments devinfo shows a summary about known devices and\n"
330 "drivers. If called with a device path as argument devinfo shows more detailed\n"
331 "information about this device and its parameters.\n";
333 BAREBOX_CMD_START(devinfo)
334 .cmd = do_devinfo,
335 .usage = "display info about devices and drivers",
336 BAREBOX_CMD_HELP(cmd_devinfo_help)
337 BAREBOX_CMD_END
339 #endif
342 * @page devinfo_command devinfo
344 * Usage is: devinfo /dev/\<device>
346 * If called without arguments devinfo shows a summary about known devices and
347 * drivers. If called with a device path as argument devinfo shows more
348 * detailed information about this device and its parameters.
350 * Example from an MPC5200 based system:
351 @verbatim
352 barebox:/ devinfo /dev/eth0
353 base : 0x1002b000
354 size : 0x00000000
355 driver: fec_mpc5xxx
357 no info available for eth0
358 Parameters:
359 ipaddr = 192.168.23.197
360 ethaddr = 80:81:82:83:84:86
361 gateway = 192.168.23.1
362 netmask = 255.255.255.0
363 serverip = 192.168.23.2
364 @endverbatim