source: mainline/uspace/srv/devman/devman.c@ 957cfa58

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 957cfa58 was 957cfa58, checked in by Lenka Trochtova <trochtova.lenka@…>, 15 years ago

devman - use hash table to lookup device according to its handle.

  • Property mode set to 100644
File size: 21.6 KB
Line 
1/*
2 * Copyright (c) 2010 Lenka Trochtova
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup devman
30 * @{
31 */
32
33#include <errno.h>
34#include <fcntl.h>
35#include <sys/stat.h>
36#include <ipc/driver.h>
37#include <ipc/devman.h>
38
39#include "devman.h"
40
41// hash table operations
42
43static hash_index_t devices_hash(unsigned long key[])
44{
45 return key[0] % DEVICE_BUCKETS;
46}
47
48static int devman_devices_compare(unsigned long key[], hash_count_t keys, link_t *item)
49{
50 node_t *dev = hash_table_get_instance(item, node_t, devman_link);
51 return (dev->handle == (device_handle_t) key[0]);
52}
53
54static int devmap_devices_compare(unsigned long key[], hash_count_t keys, link_t *item)
55{
56 node_t *dev = hash_table_get_instance(item, node_t, devmap_link);
57 return (dev->devmap_handle == (dev_handle_t) key[0]);
58}
59
60static void devices_remove_callback(link_t *item)
61{
62}
63
64static hash_table_operations_t devman_devices_ops = {
65 .hash = devices_hash,
66 .compare = devman_devices_compare,
67 .remove_callback = devices_remove_callback
68};
69
70static hash_table_operations_t devmap_devices_ops = {
71 .hash = devices_hash,
72 .compare = devmap_devices_compare,
73 .remove_callback = devices_remove_callback
74};
75
76/** Allocate and initialize a new driver structure.
77 *
78 * @return driver structure.
79 */
80driver_t * create_driver()
81{
82 driver_t *res = malloc(sizeof(driver_t));
83 if(res != NULL) {
84 init_driver(res);
85 }
86 return res;
87}
88
89/** Add a driver to the list of drivers.
90 *
91 * @param drivers_list the list of drivers.
92 * @param drv the driver's structure.
93 */
94void add_driver(driver_list_t *drivers_list, driver_t *drv)
95{
96 fibril_mutex_lock(&drivers_list->drivers_mutex);
97 list_prepend(&drv->drivers, &drivers_list->drivers);
98 fibril_mutex_unlock(&drivers_list->drivers_mutex);
99
100 printf(NAME": the '%s' driver was added to the list of available drivers.\n", drv->name);
101}
102
103/** Read match id at the specified position of a string and set
104 * the position in the string to the first character following the id.
105 *
106 * @param buf the position in the input string.
107 *
108 * @return the match id.
109 */
110char * read_match_id(char **buf)
111{
112 char *res = NULL;
113 size_t len = get_nonspace_len(*buf);
114 if (len > 0) {
115 res = malloc(len + 1);
116 if (res != NULL) {
117 str_ncpy(res, len + 1, *buf, len);
118 *buf += len;
119 }
120 }
121 return res;
122}
123
124/**
125 * Read match ids and associated match scores from a string.
126 *
127 * Each match score in the string is followed by its match id.
128 * The match ids and match scores are separated by whitespaces.
129 * Neither match ids nor match scores can contain whitespaces.
130 *
131 * @param buf the string from which the match ids are read.
132 * @param ids the list of match ids into which the match ids and scores are added.
133 *
134 * @return true if at least one match id and associated match score was successfully read, false otherwise.
135 */
136bool parse_match_ids(char *buf, match_id_list_t *ids)
137{
138 int score = 0;
139 char *id = NULL;
140 int ids_read = 0;
141
142 while (true) {
143 // skip spaces
144 if (!skip_spaces(&buf)) {
145 break;
146 }
147 // read score
148 score = strtoul(buf, &buf, 10);
149
150 // skip spaces
151 if (!skip_spaces(&buf)) {
152 break;
153 }
154
155 // read id
156 if (NULL == (id = read_match_id(&buf))) {
157 break;
158 }
159
160 // create new match_id structure
161 match_id_t *mid = create_match_id();
162 mid->id = id;
163 mid->score = score;
164
165 /// add it to the list
166 add_match_id(ids, mid);
167
168 ids_read++;
169 }
170
171 return ids_read > 0;
172}
173
174/**
175 * Read match ids and associated match scores from a file.
176 *
177 * Each match score in the file is followed by its match id.
178 * The match ids and match scores are separated by whitespaces.
179 * Neither match ids nor match scores can contain whitespaces.
180 *
181 * @param buf the path to the file from which the match ids are read.
182 * @param ids the list of match ids into which the match ids and scores are added.
183 *
184 * @return true if at least one match id and associated match score was successfully read, false otherwise.
185 */
186bool read_match_ids(const char *conf_path, match_id_list_t *ids)
187{
188 printf(NAME ": read_match_ids conf_path = %s.\n", conf_path);
189
190 bool suc = false;
191 char *buf = NULL;
192 bool opened = false;
193 int fd;
194 size_t len = 0;
195
196 fd = open(conf_path, O_RDONLY);
197 if (fd < 0) {
198 printf(NAME ": unable to open %s\n", conf_path);
199 goto cleanup;
200 }
201 opened = true;
202
203 len = lseek(fd, 0, SEEK_END);
204 lseek(fd, 0, SEEK_SET);
205 if (len == 0) {
206 printf(NAME ": configuration file '%s' is empty.\n", conf_path);
207 goto cleanup;
208 }
209
210 buf = malloc(len + 1);
211 if (buf == NULL) {
212 printf(NAME ": memory allocation failed when parsing file '%s'.\n", conf_path);
213 goto cleanup;
214 }
215
216 if (0 >= read(fd, buf, len)) {
217 printf(NAME ": unable to read file '%s'.\n", conf_path);
218 goto cleanup;
219 }
220 buf[len] = 0;
221
222 suc = parse_match_ids(buf, ids);
223
224cleanup:
225
226 free(buf);
227
228 if(opened) {
229 close(fd);
230 }
231
232 return suc;
233}
234
235/**
236 * Get information about a driver.
237 *
238 * Each driver has its own directory in the base directory.
239 * The name of the driver's directory is the same as the name of the driver.
240 * The driver's directory contains driver's binary (named as the driver without extension)
241 * and the configuration file with match ids for device-to-driver matching
242 * (named as the driver with a special extension).
243 *
244 * This function searches for the driver's directory and containing configuration files.
245 * If all the files needed are found, they are parsed and
246 * the information about the driver is stored to the driver's structure.
247 *
248 * @param base_path the base directory, in which we look for driver's subdirectory.
249 * @param name the name of the driver.
250 * @param drv the driver structure to fill information in.
251 *
252 * @return true on success, false otherwise.
253 */
254bool get_driver_info(const char *base_path, const char *name, driver_t *drv)
255{
256 printf(NAME ": get_driver_info base_path = %s, name = %s.\n", base_path, name);
257
258 assert(base_path != NULL && name != NULL && drv != NULL);
259
260 bool suc = false;
261 char *match_path = NULL;
262 size_t name_size = 0;
263
264 // read the list of match ids from the driver's configuration file
265 if (NULL == (match_path = get_abs_path(base_path, name, MATCH_EXT))) {
266 goto cleanup;
267 }
268
269 if (!read_match_ids(match_path, &drv->match_ids)) {
270 goto cleanup;
271 }
272
273 // allocate and fill driver's name
274 name_size = str_size(name)+1;
275 drv->name = malloc(name_size);
276 if (!drv->name) {
277 goto cleanup;
278 }
279 str_cpy(drv->name, name_size, name);
280
281 // initialize path with driver's binary
282 if (NULL == (drv->binary_path = get_abs_path(base_path, name, ""))) {
283 goto cleanup;
284 }
285
286 // check whether the driver's binary exists
287 struct stat s;
288 if (stat(drv->binary_path, &s) == ENOENT) {
289 printf(NAME ": driver not found at path %s.", drv->binary_path);
290 goto cleanup;
291 }
292
293 suc = true;
294
295cleanup:
296
297 if (!suc) {
298 free(drv->binary_path);
299 free(drv->name);
300 // set the driver structure to the default state
301 init_driver(drv);
302 }
303
304 free(match_path);
305
306 return suc;
307}
308
309/** Lookup drivers in the directory.
310 *
311 * @param drivers_list the list of available drivers.
312 * @param dir_path the path to the directory where we search for drivers.
313 *
314 * @return number of drivers which were found.
315 */
316int lookup_available_drivers(driver_list_t *drivers_list, const char *dir_path)
317{
318 printf(NAME ": lookup_available_drivers, dir = %s \n", dir_path);
319
320 int drv_cnt = 0;
321 DIR *dir = NULL;
322 struct dirent *diren;
323
324 dir = opendir(dir_path);
325
326 if (dir != NULL) {
327 driver_t *drv = create_driver();
328 while ((diren = readdir(dir))) {
329 if (get_driver_info(dir_path, diren->d_name, drv)) {
330 add_driver(drivers_list, drv);
331 drv_cnt++;
332 drv = create_driver();
333 }
334 }
335 delete_driver(drv);
336 closedir(dir);
337 }
338
339 return drv_cnt;
340}
341
342/** Create root device node in the device tree.
343 *
344 * @param tree the device tree.
345 * @return true on success, false otherwise.
346 */
347bool create_root_node(dev_tree_t *tree)
348{
349 printf(NAME ": create_root_node\n");
350 node_t *node = create_dev_node();
351 if (node) {
352 insert_dev_node(tree, node, clone_string(""), NULL);
353 match_id_t *id = create_match_id();
354 id->id = clone_string("root");
355 id->score = 100;
356 add_match_id(&node->match_ids, id);
357 tree->root_node = node;
358 }
359 return node != NULL;
360}
361
362/** Lookup the best matching driver for the specified device in the list of drivers.
363 *
364 * A match between a device and a driver is found
365 * if one of the driver's match ids match one of the device's match ids.
366 * The score of the match is the product of the driver's and device's score associated with the matching id.
367 * The best matching driver for a device is the driver
368 * with the highest score of the match between the device and the driver.
369 *
370 * @param drivers_list the list of drivers, where we look for the driver suitable for handling the device.
371 * @param node the device node structure of the device.
372 *
373 * @return the best matching driver or NULL if no matching driver is found.
374 */
375driver_t * find_best_match_driver(driver_list_t *drivers_list, node_t *node)
376{
377 //printf(NAME ": find_best_match_driver for device '%s' \n", node->pathname);
378 driver_t *best_drv = NULL, *drv = NULL;
379 int best_score = 0, score = 0;
380
381 fibril_mutex_lock(&drivers_list->drivers_mutex);
382
383 link_t *link = drivers_list->drivers.next;
384 while (link != &drivers_list->drivers) {
385 drv = list_get_instance(link, driver_t, drivers);
386 score = get_match_score(drv, node);
387 if (score > best_score) {
388 best_score = score;
389 best_drv = drv;
390 }
391 link = link->next;
392 }
393
394 fibril_mutex_unlock(&drivers_list->drivers_mutex);
395
396 return best_drv;
397}
398
399/**
400 * Assign a driver to a device.
401 *
402 * @param node the device's node in the device tree.
403 * @param drv the driver.
404 */
405void attach_driver(node_t *node, driver_t *drv)
406{
407 printf(NAME ": attach_driver %s to device %s\n", drv->name, node->pathname);
408
409 fibril_mutex_lock(&drv->driver_mutex);
410
411 node->drv = drv;
412 list_append(&node->driver_devices, &drv->devices);
413
414 fibril_mutex_unlock(&drv->driver_mutex);
415}
416
417/** Start a driver.
418 *
419 * The driver's mutex is assumed to be locked.
420 *
421 * @param drv the driver's structure.
422 * @return true if the driver's task is successfully spawned, false otherwise.
423 */
424bool start_driver(driver_t *drv)
425{
426 printf(NAME ": start_driver '%s'\n", drv->name);
427
428 const char *argv[2];
429
430 argv[0] = drv->name;
431 argv[1] = NULL;
432
433 int err;
434 if (!task_spawn(drv->binary_path, argv, &err)) {
435 printf(NAME ": error spawning %s, errno = %d\n", drv->name, err);
436 return false;
437 }
438
439 drv->state = DRIVER_STARTING;
440 return true;
441}
442
443/** Find device driver in the list of device drivers.
444 *
445 * @param drv_list the list of device drivers.
446 * @param drv_name the name of the device driver which is searched.
447 * @return the device driver of the specified name, if it is in the list, NULL otherwise.
448 */
449driver_t * find_driver(driver_list_t *drv_list, const char *drv_name)
450{
451 driver_t *res = NULL;
452
453 fibril_mutex_lock(&drv_list->drivers_mutex);
454
455 driver_t *drv = NULL;
456 link_t *link = drv_list->drivers.next;
457 while (link != &drv_list->drivers) {
458 drv = list_get_instance(link, driver_t, drivers);
459 if (0 == str_cmp(drv->name, drv_name)) {
460 res = drv;
461 break;
462 }
463 link = link->next;
464 }
465
466 fibril_mutex_unlock(&drv_list->drivers_mutex);
467
468 return res;
469}
470
471/** Remember the driver's phone.
472 * @param driver the driver.
473 * @param phone the phone to the driver.
474 */
475void set_driver_phone(driver_t *driver, ipcarg_t phone)
476{
477 fibril_mutex_lock(&driver->driver_mutex);
478 assert(DRIVER_STARTING == driver->state);
479 driver->phone = phone;
480 fibril_mutex_unlock(&driver->driver_mutex);
481}
482
483/**
484 * Notify driver about the devices to which it was assigned.
485 *
486 * The driver's mutex must be locked.
487 *
488 * @param driver the driver to which the devices are passed.
489 */
490static void pass_devices_to_driver(driver_t *driver)
491{
492 printf(NAME ": pass_devices_to_driver\n");
493 node_t *dev;
494 link_t *link;
495
496 int phone = ipc_connect_me_to(driver->phone, DRIVER_DEVMAN, 0, 0);
497
498 if (0 < phone) {
499
500 link = driver->devices.next;
501 while (link != &driver->devices) {
502 dev = list_get_instance(link, node_t, driver_devices);
503 add_device(phone, driver, dev);
504 link = link->next;
505 }
506
507 ipc_hangup(phone);
508 }
509}
510
511/** Finish the initialization of a driver after it has succesfully started
512 * and after it has registered itself by the device manager.
513 *
514 * Pass devices formerly matched to the driver to the driver and remember the driver is running and fully functional now.
515 *
516 * @param driver the driver which registered itself as running by the device manager.
517 */
518void initialize_running_driver(driver_t *driver)
519{
520 printf(NAME ": initialize_running_driver\n");
521 fibril_mutex_lock(&driver->driver_mutex);
522
523 // pass devices which have been already assigned to the driver to the driver
524 pass_devices_to_driver(driver);
525
526 // change driver's state to running
527 driver->state = DRIVER_RUNNING;
528
529 fibril_mutex_unlock(&driver->driver_mutex);
530}
531
532/** Pass a device to running driver.
533 *
534 * @param drv the driver's structure.
535 * @param node the device's node in the device tree.
536 */
537void add_device(int phone, driver_t *drv, node_t *node)
538{
539 printf(NAME ": add_device\n");
540
541 ipcarg_t rc;
542 ipc_call_t answer;
543
544 // send the device to the driver
545 aid_t req = async_send_1(phone, DRIVER_ADD_DEVICE, node->handle, &answer);
546
547 // send the device's name to the driver
548 rc = async_data_write_start(phone, node->name, str_size(node->name) + 1);
549 if (rc != EOK) {
550 // TODO handle error
551 }
552
553 // wait for answer from the driver
554 async_wait_for(req, &rc);
555 switch(rc) {
556 case EOK:
557 node->state = DEVICE_USABLE;
558 break;
559 case ENOENT:
560 node->state = DEVICE_NOT_PRESENT;
561 break;
562 default:
563 node->state = DEVICE_INVALID;
564 }
565
566 return;
567}
568
569/**
570 * Find suitable driver for a device and assign the driver to it.
571 *
572 * @param node the device node of the device in the device tree.
573 * @param drivers_list the list of available drivers.
574 *
575 * @return true if the suitable driver is found and successfully assigned to the device, false otherwise.
576 */
577bool assign_driver(node_t *node, driver_list_t *drivers_list)
578{
579 //printf(NAME ": assign_driver\n");
580
581 // find the driver which is the most suitable for handling this device
582 driver_t *drv = find_best_match_driver(drivers_list, node);
583 if (NULL == drv) {
584 printf(NAME ": no driver found for device '%s'.\n", node->pathname);
585 return false;
586 }
587
588 // attach the driver to the device
589 attach_driver(node, drv);
590
591 if (DRIVER_NOT_STARTED == drv->state) {
592 // start driver
593 start_driver(drv);
594 }
595
596 if (DRIVER_RUNNING == drv->state) {
597 // notify driver about new device
598 int phone = ipc_connect_me_to(drv->phone, DRIVER_DEVMAN, 0, 0);
599 if (phone > 0) {
600 add_device(phone, drv, node);
601 ipc_hangup(phone);
602 }
603 }
604
605 return true;
606}
607
608/**
609 * Initialize the device tree.
610 *
611 * Create root device node of the tree and assign driver to it.
612 *
613 * @param tree the device tree.
614 * @param the list of available drivers.
615 * @return true on success, false otherwise.
616 */
617bool init_device_tree(dev_tree_t *tree, driver_list_t *drivers_list)
618{
619 printf(NAME ": init_device_tree.\n");
620
621 tree->current_handle = 0;
622
623 hash_table_create(&tree->devman_devices, DEVICE_BUCKETS, 1, &devman_devices_ops);
624 hash_table_create(&tree->devmap_devices, DEVICE_BUCKETS, 1, &devmap_devices_ops);
625
626 fibril_rwlock_initialize(&tree->rwlock);
627
628 // create root node and add it to the device tree
629 if (!create_root_node(tree)) {
630 return false;
631 }
632
633 // find suitable driver and start it
634 return assign_driver(tree->root_node, drivers_list);
635}
636
637/** Create and set device's full path in device tree.
638 *
639 * @param node the device's device node.
640 * @param parent the parent device node.
641 * @return true on success, false otherwise (insufficient resources etc.).
642 */
643static bool set_dev_path(node_t *node, node_t *parent)
644{
645 assert(NULL != node->name);
646
647 size_t pathsize = (str_size(node->name) + 1);
648 if (NULL != parent) {
649 pathsize += str_size(parent->pathname) + 1;
650 }
651
652 if (NULL == (node->pathname = (char *)malloc(pathsize))) {
653 printf(NAME ": failed to allocate device path.\n");
654 return false;
655 }
656
657 if (NULL != parent) {
658 str_cpy(node->pathname, pathsize, parent->pathname);
659 str_append(node->pathname, pathsize, "/");
660 str_append(node->pathname, pathsize, node->name);
661 } else {
662 str_cpy(node->pathname, pathsize, node->name);
663 }
664
665 return true;
666}
667
668/** Insert new device into device tree.
669 *
670 * The device tree's rwlock should be already held exclusively when calling this function.
671 *
672 * @param tree the device tree.
673 * @param node the newly added device node.
674 * @param dev_name the name of the newly added device.
675 * @param parent the parent device node.
676 * @return true on success, false otherwise (insufficient resources etc.).
677 */
678bool insert_dev_node(dev_tree_t *tree, node_t *node, char *dev_name, node_t *parent)
679{
680 // printf(NAME ": insert_dev_node\n");
681
682 assert(NULL != node && NULL != tree && NULL != dev_name);
683
684 node->name = dev_name;
685 if (!set_dev_path(node, parent)) {
686 fibril_rwlock_write_unlock(&tree->rwlock);
687 return false;
688 }
689
690 // add the node to the handle-to-node map
691 node->handle = ++tree->current_handle;
692 unsigned long key = node->handle;
693 hash_table_insert(&tree->devman_devices, &key, &node->devman_link);
694
695 // add the node to the list of its parent's children
696 node->parent = parent;
697 if (NULL != parent) {
698 list_append(&node->sibling, &parent->children);
699 }
700 return true;
701}
702
703/**
704 * Find device node with a specified path in the device tree.
705 *
706 * @param path the path of the device node in the device tree.
707 * @param tree the device tree.
708 *
709 * @return the device node if it is present in the tree, NULL otherwise.
710 */
711node_t * find_dev_node_by_path(dev_tree_t *tree, char *path)
712{
713 fibril_rwlock_read_lock(&tree->rwlock);
714
715 node_t *dev = tree->root_node;
716 // relative path to the device from its parent (but with '/' at the beginning)
717 char *rel_path = path;
718 char *next_path_elem = NULL;
719 bool cont = '/' == rel_path[0];
720
721 while (cont && NULL != dev) {
722 next_path_elem = get_path_elem_end(rel_path + 1);
723 if ('/' == next_path_elem[0]) {
724 cont = true;
725 next_path_elem[0] = 0;
726 } else {
727 cont = false;
728 }
729
730 dev = find_node_child(dev, rel_path + 1);
731
732 if (cont) {
733 // restore the original path
734 next_path_elem[0] = '/';
735 }
736 rel_path = next_path_elem;
737 }
738
739 fibril_rwlock_read_unlock(&tree->rwlock);
740
741 return dev;
742}
743
744/**
745 * Find child device node with a specified name.
746 *
747 * Device tree rwlock should be held at least for reading.
748 *
749 * @param parent the parent device node.
750 * @param name the name of the child device node.
751 *
752 * @return the child device node.
753 */
754node_t *find_node_child(node_t *parent, const char *name)
755{
756 node_t *dev;
757 link_t *link;
758
759 link = parent->children.next;
760
761 while (link != &parent->children) {
762 dev = list_get_instance(link, node_t, sibling);
763
764 if (0 == str_cmp(name, dev->name)) {
765 return dev;
766 }
767
768 link = link->next;
769 }
770
771 return NULL;
772}
773
774/** Create unique device name within the class.
775 *
776 * @param cl the class.
777 * @param base_dev_name contains base name for the device
778 * if it was specified by the driver when it registered the device by the class;
779 * NULL if driver specified no base name.
780 * @return the unique name for the device within the class.
781 */
782char * create_dev_name_for_class(dev_class_t *cl, const char *base_dev_name)
783{
784 char *dev_name;
785 const char *base_name;
786 if (NULL != base_dev_name) {
787 base_name = base_dev_name;
788 } else {
789 base_name = cl->base_dev_name;
790 }
791
792 size_t idx = get_new_class_dev_idx(cl);
793 asprintf(&dev_name, "%s%d", base_name, idx);
794 return dev_name;
795}
796
797/** Add the device to the class.
798 *
799 * The device may be added to multiple classes and a class may contain multiple devices.
800 * The class and the device are associated with each other by the dev_class_info_t structure.
801 *
802 * @param dev the device.
803 * @param class the class.
804 * @param base_dev_name the base name of the device within the class if specified by the driver,
805 * NULL otherwise.
806 * @return dev_class_info_t structure which associates the device with the class.
807 */
808dev_class_info_t * add_device_to_class(node_t *dev, dev_class_t *cl, const char *base_dev_name)
809{
810 dev_class_info_t *info = create_dev_class_info();
811 info->dev_class = cl;
812 info->dev = dev;
813
814 // add the device to the class
815 fibril_mutex_lock(&cl->mutex);
816 list_append(&info->link, &cl->devices);
817 fibril_mutex_unlock(&cl->mutex);
818
819 // add the class to the device
820 list_append(&info->dev_classes, &dev->classes);
821
822 // create unique name for the device within the class
823 info->dev_name = create_dev_name_for_class(cl, base_dev_name);
824
825 return info;
826}
827
828/** @}
829 */
Note: See TracBrowser for help on using the repository browser.