File: /usr/src/linux/arch/ia64/sn/io/devsupport.c
1 /* $Id$
2 *
3 * This file is subject to the terms and conditions of the GNU General Public
4 * License. See the file "COPYING" in the main directory of this archive
5 * for more details.
6 *
7 * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc.
8 * Copyright (C) 2000 by Colin Ngam
9 */
10
11 #include <linux/types.h>
12 #include <linux/mm.h>
13 #include <linux/slab.h>
14 #include <asm/sn/sgi.h>
15 #include <asm/sn/invent.h>
16 #include <asm/sn/hcl.h>
17 #include <asm/sn/iobus.h>
18 #include <asm/sn/iograph.h>
19
20 /*
21 * Interfaces in this file are all platform-independent AND IObus-independent.
22 * Be aware that there may be macro equivalents to each of these hiding in
23 * header files which supercede these functions.
24 */
25
26 /* =====Generic iobus support===== */
27
28 /* String table to hold names of interrupts. */
29 #ifdef LATER
30 static struct string_table device_desc_string_table;
31 #endif
32
33 /* One time initialization for device descriptor support. */
34 static void
35 device_desc_init(void)
36 {
37 #ifdef LATER
38 string_table_init(&device_desc_string_table);
39 #endif
40 FIXME("device_desc_init");
41 }
42
43
44 /* Drivers use these interfaces to manage device descriptors */
45 static device_desc_t
46 device_desc_alloc(void)
47 {
48 #ifdef LATER
49 device_desc_t device_desc;
50
51 device_desc = (device_desc_t)kmem_zalloc(sizeof(struct device_desc_s), 0);
52 device_desc->intr_target = GRAPH_VERTEX_NONE;
53
54 ASSERT(device_desc->intr_policy == 0);
55 device_desc->intr_swlevel = -1;
56 ASSERT(device_desc->intr_name == NULL);
57 ASSERT(device_desc->flags == 0);
58
59 ASSERT(!(device_desc->flags & D_IS_ASSOC));
60 return(device_desc);
61 #else
62 FIXME("device_desc_alloc");
63 return((device_desc_t)0);
64 #endif
65 }
66
67 void
68 device_desc_free(device_desc_t device_desc)
69 {
70 #ifdef LATER
71 if (!(device_desc->flags & D_IS_ASSOC)) /* sanity */
72 kfree(device_desc);
73 #endif
74 FIXME("device_desc_free");
75 }
76
77 device_desc_t
78 device_desc_dup(devfs_handle_t dev)
79 {
80 #ifdef LATER
81 device_desc_t orig_device_desc, new_device_desc;
82
83
84 new_device_desc = device_desc_alloc();
85 orig_device_desc = device_desc_default_get(dev);
86 if (orig_device_desc)
87 *new_device_desc = *orig_device_desc;/* small structure copy */
88 else {
89 device_driver_t driver;
90 ilvl_t pri;
91 /*
92 * Use the driver's thread priority in
93 * case the device thread priority has not
94 * been given.
95 */
96 if (driver = device_driver_getbydev(dev)) {
97 pri = device_driver_thread_pri_get(driver);
98 device_desc_intr_swlevel_set(new_device_desc,pri);
99 }
100 }
101 new_device_desc->flags &= ~D_IS_ASSOC;
102 return(new_device_desc);
103 #else
104 FIXME("device_desc_dup");
105 return((device_desc_t)0);
106 #endif
107 }
108
109 device_desc_t
110 device_desc_default_get(devfs_handle_t dev)
111 {
112 #ifdef LATER
113 graph_error_t rc;
114 device_desc_t device_desc;
115
116 rc = hwgraph_info_get_LBL(dev, INFO_LBL_DEVICE_DESC, (arbitrary_info_t *)&device_desc);
117
118 if (rc == GRAPH_SUCCESS)
119 return(device_desc);
120 else
121 return(NULL);
122 #else
123 FIXME("device_desc_default_get");
124 return((device_desc_t)0);
125 #endif
126 }
127
128 void
129 device_desc_default_set(devfs_handle_t dev, device_desc_t new_device_desc)
130 {
131 #ifdef LATER
132 graph_error_t rc;
133 device_desc_t old_device_desc = NULL;
134
135 if (new_device_desc) {
136 new_device_desc->flags |= D_IS_ASSOC;
137 rc = hwgraph_info_add_LBL(dev, INFO_LBL_DEVICE_DESC,
138 (arbitrary_info_t)new_device_desc);
139 if (rc == GRAPH_DUP) {
140 rc = hwgraph_info_replace_LBL(dev, INFO_LBL_DEVICE_DESC,
141 (arbitrary_info_t)new_device_desc,
142 (arbitrary_info_t *)&old_device_desc);
143
144 ASSERT(rc == GRAPH_SUCCESS);
145 }
146 hwgraph_info_export_LBL(dev, INFO_LBL_DEVICE_DESC,
147 sizeof(struct device_desc_s));
148 } else {
149 rc = hwgraph_info_remove_LBL(dev, INFO_LBL_DEVICE_DESC,
150 (arbitrary_info_t *)&old_device_desc);
151 }
152
153 if (old_device_desc) {
154 ASSERT(old_device_desc->flags & D_IS_ASSOC);
155 old_device_desc->flags &= ~D_IS_ASSOC;
156 device_desc_free(old_device_desc);
157 }
158 #endif
159 FIXME("device_desc_default_set");
160 }
161
162 devfs_handle_t
163 device_desc_intr_target_get(device_desc_t device_desc)
164 {
165 #ifdef LATER
166 return(device_desc->intr_target);
167 #else
168 FIXME("device_desc_intr_target_get");
169 return((devfs_handle_t)0);
170 #endif
171 }
172
173 int
174 device_desc_intr_policy_get(device_desc_t device_desc)
175 {
176 #ifdef LATER
177 return(device_desc->intr_policy);
178 #else
179 FIXME("device_desc_intr_policy_get");
180 return(0);
181 #endif
182 }
183
184 ilvl_t
185 device_desc_intr_swlevel_get(device_desc_t device_desc)
186 {
187 #ifdef LATER
188 return(device_desc->intr_swlevel);
189 #else
190 FIXME("device_desc_intr_swlevel_get");
191 return((ilvl_t)0);
192 #endif
193 }
194
195 char *
196 device_desc_intr_name_get(device_desc_t device_desc)
197 {
198 #ifdef LATER
199 return(device_desc->intr_name);
200 #else
201 FIXME("device_desc_intr_name_get");
202 return(NULL);
203 #endif
204 }
205
206 int
207 device_desc_flags_get(device_desc_t device_desc)
208 {
209 #ifdef LATER
210 return(device_desc->flags);
211 #else
212 FIXME("device_desc_flags_get");
213 return(0);
214 #endif
215 }
216
217 void
218 device_desc_intr_target_set(device_desc_t device_desc, devfs_handle_t target)
219 {
220 if ( device_desc != (device_desc_t)0 )
221 device_desc->intr_target = target;
222 }
223
224 void
225 device_desc_intr_policy_set(device_desc_t device_desc, int policy)
226 {
227 if ( device_desc != (device_desc_t)0 )
228 device_desc->intr_policy = policy;
229 }
230
231 void
232 device_desc_intr_swlevel_set(device_desc_t device_desc, ilvl_t swlevel)
233 {
234 if ( device_desc != (device_desc_t)0 )
235 device_desc->intr_swlevel = swlevel;
236 }
237
238 void
239 device_desc_intr_name_set(device_desc_t device_desc, char *name)
240 {
241 #ifdef LATER
242 if ( device_desc != (device_desc_t)0 )
243 device_desc->intr_name = string_table_insert(&device_desc_string_table, name);
244 #else
245 FIXME("device_desc_intr_name_set");
246 #endif
247 }
248
249 void
250 device_desc_flags_set(device_desc_t device_desc, int flags)
251 {
252 if ( device_desc != (device_desc_t)0 )
253 device_desc->flags = flags;
254 }
255
256
257
258 /*============= device admin registry routines ===================== */
259
260 /* Linked list of <admin-name,admin-val> pairs */
261 typedef struct dev_admin_list_s {
262 struct dev_admin_list_s *admin_next; /* next entry in the
263 * list
264 */
265 char *admin_name; /* info label */
266 char *admin_val; /* actual info */
267 } dev_admin_list_t;
268
269 /* Device/Driver administration registry */
270 typedef struct dev_admin_registry_s {
271 mrlock_t reg_lock; /* To allow
272 * exclusive
273 * access
274 */
275 dev_admin_list_t *reg_first; /* first entry in
276 * the list
277 */
278 dev_admin_list_t **reg_last; /* pointer to the
279 * next to last entry
280 * in the last which
281 * is also the place
282 * where the new
283 * entry gets
284 * inserted
285 */
286 } dev_admin_registry_t;
287
288 /*
289 ** device_driver_s associates a device driver prefix with device switch entries.
290 */
291 struct device_driver_s {
292 struct device_driver_s *dd_next; /* next element on hash chain */
293 struct device_driver_s *dd_prev; /* previous element on hash chain */
294 char *dd_prefix; /* driver prefix string */
295 struct bdevsw *dd_bdevsw; /* driver's bdevsw */
296 struct cdevsw *dd_cdevsw; /* driver's cdevsw */
297
298 /* driver administration specific data structures need to
299 * maintain the list of <driver-paramater,value> pairs
300 */
301 dev_admin_registry_t dd_dev_admin_registry;
302 ilvl_t dd_thread_pri; /* default thread priority for
303 * all this driver's
304 * threads.
305 */
306
307 };
308
309 #define NEW(_p) (_p = kmalloc(sizeof(*_p), GFP_KERNEL))
310 #define FREE(_p) (kmem_free(_p))
311
312 /*
313 * helpful lock macros
314 */
315
316 #define DEV_ADMIN_REGISTRY_INITLOCK(lockp,name) mrinit(lockp,name)
317 #define DEV_ADMIN_REGISTRY_RDLOCK(lockp) mraccess(lockp)
318 #define DEV_ADMIN_REGISTRY_WRLOCK(lockp) mrupdate(lockp)
319 #define DEV_ADMIN_REGISTRY_UNLOCK(lockp) mrunlock(lockp)
320
321 /* Initialize the registry
322 */
323 static void
324 dev_admin_registry_init(dev_admin_registry_t *registry)
325 {
326 #ifdef LATER
327 if ( registry != (dev_admin_registry_t *)0 )
328 DEV_ADMIN_REGISTRY_INITLOCK(®istry->reg_lock,
329 "dev_admin_registry_lock");
330 registry->reg_first = NULL;
331 registry->reg_last = ®istry->reg_first;
332 }
333 #else
334 FIXME("dev_admin_registry_init");
335 #endif
336 }
337
338 /*
339 * add an <name , value > entry to the dev admin registry.
340 * if the name already exists in the registry then change the
341 * value iff the new value differs from the old value.
342 * if the name doesn't exist a new list entry is created and put
343 * at the end.
344 */
345 static void
346 dev_admin_registry_add(dev_admin_registry_t *registry,
347 char *name,
348 char *val)
349 {
350 #ifdef LATER
351 dev_admin_list_t *reg_entry;
352 dev_admin_list_t *scan = 0;
353
354 DEV_ADMIN_REGISTRY_WRLOCK(®istry->reg_lock);
355
356 /* check if the name already exists in the registry */
357 scan = registry->reg_first;
358
359 while (scan) {
360 if (strcmp(scan->admin_name,name) == 0) {
361 /* name is there in the registry */
362 if (strcmp(scan->admin_val,val)) {
363 /* old value != new value
364 * reallocate memory and copy the new value
365 */
366 FREE(scan->admin_val);
367 scan->admin_val =
368 (char *)kern_calloc(1,strlen(val)+1);
369 strcpy(scan->admin_val,val);
370 goto out;
371 }
372 goto out; /* old value == new value */
373 }
374 scan = scan->admin_next;
375 }
376
377 /* name is not there in the registry.
378 * allocate memory for the new registry entry
379 */
380 NEW(reg_entry);
381
382 reg_entry->admin_next = 0;
383 reg_entry->admin_name = (char *)kern_calloc(1,strlen(name)+1);
384 strcpy(reg_entry->admin_name,name);
385 reg_entry->admin_val = (char *)kern_calloc(1,strlen(val)+1);
386 strcpy(reg_entry->admin_val,val);
387
388 /* add the entry at the end of the registry */
389
390 *(registry->reg_last) = reg_entry;
391 registry->reg_last = ®_entry->admin_next;
392
393 out: DEV_ADMIN_REGISTRY_UNLOCK(®istry->reg_lock);
394 #endif
395 FIXME("dev_admin_registry_add");
396 }
397 /*
398 * check if there is an info corr. to a particular
399 * name starting from the cursor position in the
400 * registry
401 */
402 static char *
403 dev_admin_registry_find(dev_admin_registry_t *registry,char *name)
404 {
405 #ifdef LATER
406 dev_admin_list_t *scan = 0;
407
408 DEV_ADMIN_REGISTRY_RDLOCK(®istry->reg_lock);
409 scan = registry->reg_first;
410
411 while (scan) {
412 if (strcmp(scan->admin_name,name) == 0) {
413 DEV_ADMIN_REGISTRY_UNLOCK(®istry->reg_lock);
414 return scan->admin_val;
415 }
416 scan = scan->admin_next;
417 }
418 DEV_ADMIN_REGISTRY_UNLOCK(®istry->reg_lock);
419 return 0;
420 #else
421 FIXME("dev_admin_registry_find");
422 return(NULL);
423 #endif
424 }
425 /*============= MAIN DEVICE/ DRIVER ADMINISTRATION INTERFACE================ */
426 /*
427 * return any labelled info associated with a device.
428 * called by any kernel code including device drivers.
429 */
430 char *
431 device_admin_info_get(devfs_handle_t dev_vhdl,
432 char *info_lbl)
433 {
434 #ifdef LATER
435 char *info = 0;
436
437 /* return value need not be GRAPH_SUCCESS as the labelled
438 * info may not be present
439 */
440 (void)hwgraph_info_get_LBL(dev_vhdl,info_lbl,
441 (arbitrary_info_t *)&info);
442
443
444 return info;
445 #else
446 FIXME("device_admin_info_get");
447 return(NULL);
448 #endif
449 }
450
451 /*
452 * set labelled info associated with a device.
453 * called by hwgraph infrastructure . may also be called
454 * by device drivers etc.
455 */
456 int
457 device_admin_info_set(devfs_handle_t dev_vhdl,
458 char *dev_info_lbl,
459 char *dev_info_val)
460 {
461 #ifdef LATER
462 graph_error_t rv;
463 arbitrary_info_t old_info;
464
465 /* Handle the labelled info
466 * intr_target
467 * sw_level
468 * in a special way. These are part of device_desc_t
469 * Right now this is the only case where we have
470 * a set of related device_admin attributes which
471 * are grouped together.
472 * In case there is a need for another set we need to
473 * take a more generic approach to solving this.
474 * Basically a registry should be implemented. This
475 * registry is initialized with the callbacks for the
476 * attributes which need to handled in a special way
477 * For example:
478 * Consider
479 * device_desc
480 * intr_target
481 * intr_swlevel
482 * register "do_intr_target" for intr_target
483 * register "do_intr_swlevel" for intr_swlevel.
484 * When the device_admin interface layer gets an <attr,val> pair
485 * it looks in the registry to see if there is a function registered to
486 * handle "attr. If not follow the default path of setting the <attr,val>
487 * as labelled information hanging off the vertex.
488 * In the above example:
489 * "do_intr_target" does what is being done below for the ADMIN_LBL_INTR_TARGET
490 * case
491 */
492 if (!strcmp(dev_info_lbl,ADMIN_LBL_INTR_TARGET) ||
493 !strcmp(dev_info_lbl,ADMIN_LBL_INTR_SWLEVEL)) {
494
495 device_desc_t device_desc;
496
497 /* Check if there is a default device descriptor
498 * information for this vertex. If not dup one .
499 */
500 if (!(device_desc = device_desc_default_get(dev_vhdl))) {
501 device_desc = device_desc_dup(dev_vhdl);
502 device_desc_default_set(dev_vhdl,device_desc);
503
504 }
505 if (!strcmp(dev_info_lbl,ADMIN_LBL_INTR_TARGET)) {
506 /* Check if a target cpu has been specified
507 * for this device by a device administration
508 * directive
509 */
510 #ifdef DEBUG
511 printf(ADMIN_LBL_INTR_TARGET
512 " dev = 0x%x "
513 "dev_admin_info = %s"
514 " target = 0x%x\n",
515 dev_vhdl,
516 dev_info_lbl,
517 hwgraph_path_to_vertex(dev_info_val));
518 #endif
519
520 device_desc->intr_target =
521 hwgraph_path_to_vertex(dev_info_val);
522 } else if (!strcmp(dev_info_lbl,ADMIN_LBL_INTR_SWLEVEL)) {
523 /* Check if the ithread priority level has been
524 * specified for this device by a device administration
525 * directive
526 */
527 #ifdef DEBUG
528 printf(ADMIN_LBL_INTR_SWLEVEL
529 " dev = 0x%x "
530 "dev_admin_info = %s"
531 " sw level = 0x%x\n",
532 dev_vhdl,
533 dev_info_lbl,
534 atoi(dev_info_val));
535 #endif
536 device_desc->intr_swlevel = atoi(dev_info_val);
537 }
538
539 }
540 if (!dev_info_val)
541 rv = hwgraph_info_remove_LBL(dev_vhdl,
542 dev_info_lbl,
543 &old_info);
544 else {
545
546 rv = hwgraph_info_add_LBL(dev_vhdl,
547 dev_info_lbl,
548 (arbitrary_info_t)dev_info_val);
549
550 if (rv == GRAPH_DUP) {
551 rv = hwgraph_info_replace_LBL(dev_vhdl,
552 dev_info_lbl,
553 (arbitrary_info_t)dev_info_val,
554 &old_info);
555 }
556 }
557 ASSERT(rv == GRAPH_SUCCESS);
558 #endif
559 FIXME("device_admin_info_set");
560 return 0;
561 }
562
563 /*
564 * return labelled info associated with a device driver
565 * called by kernel code including device drivers
566 */
567 char *
568 device_driver_admin_info_get(char *driver_prefix,
569 char *driver_info_lbl)
570 {
571 #ifdef LATER
572 device_driver_t driver;
573
574 driver = device_driver_get(driver_prefix);
575 return (dev_admin_registry_find(&driver->dd_dev_admin_registry,
576 driver_info_lbl));
577 #else
578 FIXME("device_driver_admin_info_get");
579 return(NULL);
580 #endif
581 }
582
583 /*
584 * set labelled info associated with a device driver.
585 * called by hwgraph infrastructure . may also be called
586 * from drivers etc.
587 */
588 int
589 device_driver_admin_info_set(char *driver_prefix,
590 char *driver_info_lbl,
591 char *driver_info_val)
592 {
593 #ifdef LATER
594 device_driver_t driver;
595
596 driver = device_driver_get(driver_prefix);
597 dev_admin_registry_add(&driver->dd_dev_admin_registry,
598 driver_info_lbl,
599 driver_info_val);
600 #endif
601 FIXME("device_driver_admin_info_set");
602 return 0;
603 }
604 /*================== device / driver admin support routines================*/
605
606 /* static tables created by lboot */
607 extern dev_admin_info_t dev_admin_table[];
608 extern dev_admin_info_t drv_admin_table[];
609 extern int dev_admin_table_size;
610 extern int drv_admin_table_size;
611
612 /* Extend the device admin table to allow the kernel startup code to
613 * provide some device specific administrative hints
614 */
615 #define ADMIN_TABLE_CHUNK 100
616 static dev_admin_info_t extended_dev_admin_table[ADMIN_TABLE_CHUNK];
617 static int extended_dev_admin_table_size = 0;
618 static mrlock_t extended_dev_admin_table_lock;
619
620 /* Initialize the extended device admin table */
621 void
622 device_admin_table_init(void)
623 {
624 #ifdef LATER
625 extended_dev_admin_table_size = 0;
626 mrinit(&extended_dev_admin_table_lock,
627 "extended_dev_admin_table_lock");
628 #endif
629 FIXME("device_admin_table_init");
630 }
631 /* Add <device-name , parameter-name , parameter-value> triple to
632 * the extended device administration info table. This is helpful
633 * for kernel startup code to put some hints before the hwgraph
634 * is setup
635 */
636 void
637 device_admin_table_update(char *name,char *label,char *value)
638 {
639 #ifdef LATER
640 dev_admin_info_t *p;
641
642 mrupdate(&extended_dev_admin_table_lock);
643
644 /* Safety check that we haven't exceeded array limits */
645 ASSERT(extended_dev_admin_table_size < ADMIN_TABLE_CHUNK);
646
647 if (extended_dev_admin_table_size == ADMIN_TABLE_CHUNK)
648 goto out;
649
650 /* Get the pointer to the entry in the table where we are
651 * going to put the new information
652 */
653 p = &extended_dev_admin_table[extended_dev_admin_table_size++];
654
655 /* Allocate memory for the strings and copy them in */
656 p->dai_name = (char *)kern_calloc(1,strlen(name)+1);
657 strcpy(p->dai_name,name);
658 p->dai_param_name = (char *)kern_calloc(1,strlen(label)+1);
659 strcpy(p->dai_param_name,label);
660 p->dai_param_val = (char *)kern_calloc(1,strlen(value)+1);
661 strcpy(p->dai_param_val,value);
662
663 out: mrunlock(&extended_dev_admin_table_lock);
664 #endif
665 FIXME("device_admin_table_update");
666 }
667 /* Extend the device driver admin table to allow the kernel startup code to
668 * provide some device driver specific administrative hints
669 */
670
671 static dev_admin_info_t extended_drv_admin_table[ADMIN_TABLE_CHUNK];
672 static int extended_drv_admin_table_size = 0;
673 mrlock_t extended_drv_admin_table_lock;
674
675 /* Initialize the extended device driver admin table */
676 void
677 device_driver_admin_table_init(void)
678 {
679 #ifdef LATER
680 extended_drv_admin_table_size = 0;
681 mrinit(&extended_drv_admin_table_lock,
682 "extended_drv_admin_table_lock");
683 #endif
684 FIXME("device_driver_admin_table_init");
685 }
686 /* Add <device-driver prefix , parameter-name , parameter-value> triple to
687 * the extended device administration info table. This is helpful
688 * for kernel startup code to put some hints before the hwgraph
689 * is setup
690 */
691 void
692 device_driver_admin_table_update(char *name,char *label,char *value)
693 {
694 #ifdef LATER
695 dev_admin_info_t *p;
696
697 mrupdate(&extended_dev_admin_table_lock);
698
699 /* Safety check that we haven't exceeded array limits */
700 ASSERT(extended_drv_admin_table_size < ADMIN_TABLE_CHUNK);
701
702 if (extended_drv_admin_table_size == ADMIN_TABLE_CHUNK)
703 goto out;
704
705 /* Get the pointer to the entry in the table where we are
706 * going to put the new information
707 */
708 p = &extended_drv_admin_table[extended_drv_admin_table_size++];
709
710 /* Allocate memory for the strings and copy them in */
711 p->dai_name = (char *)kern_calloc(1,strlen(name)+1);
712 strcpy(p->dai_name,name);
713 p->dai_param_name = (char *)kern_calloc(1,strlen(label)+1);
714 strcpy(p->dai_param_name,label);
715 p->dai_param_val = (char *)kern_calloc(1,strlen(value)+1);
716 strcpy(p->dai_param_val,value);
717
718 out: mrunlock(&extended_drv_admin_table_lock);
719 #endif
720 FIXME("device_driver_admin_table_update");
721 }
722 /*
723 * keeps on adding the labelled info for each new (lbl,value) pair
724 * that it finds in the static dev admin table ( created by lboot)
725 * and the extended dev admin table ( created if at all by the kernel startup
726 * code) corresponding to a device in the hardware graph.
727 */
728 void
729 device_admin_info_update(devfs_handle_t dev_vhdl)
730 {
731 #ifdef LATER
732 int i = 0;
733 dev_admin_info_t *scan;
734 devfs_handle_t scan_vhdl;
735
736 /* Check the static device administration info table */
737 scan = dev_admin_table;
738 while (i < dev_admin_table_size) {
739
740 scan_vhdl = hwgraph_path_to_dev(scan->dai_name);
741 if (scan_vhdl == dev_vhdl) {
742 device_admin_info_set(dev_vhdl,
743 scan->dai_param_name,
744 scan->dai_param_val);
745 }
746 if (scan_vhdl != NODEV)
747 hwgraph_vertex_unref(scan_vhdl);
748 scan++;i++;
749
750 }
751 i = 0;
752 /* Check the extended device administration info table */
753 scan = extended_dev_admin_table;
754 while (i < extended_dev_admin_table_size) {
755 scan_vhdl = hwgraph_path_to_dev(scan->dai_name);
756 if (scan_vhdl == dev_vhdl) {
757 device_admin_info_set(dev_vhdl,
758 scan->dai_param_name,
759 scan->dai_param_val);
760 }
761 if (scan_vhdl != NODEV)
762 hwgraph_vertex_unref(scan_vhdl);
763 scan++;i++;
764
765 }
766
767
768 #endif
769 FIXME("device_admin_info_update");
770 }
771
772 /* looks up the static drv admin table ( created by the lboot) and the extended
773 * drv admin table (created if at all by the kernel startup code)
774 * for this driver specific administration info and adds it to the admin info
775 * associated with this device driver's object
776 */
777 void
778 device_driver_admin_info_update(device_driver_t driver)
779 {
780 #ifdef LATER
781 int i = 0;
782 dev_admin_info_t *scan;
783
784 /* Check the static device driver administration info table */
785 scan = drv_admin_table;
786 while (i < drv_admin_table_size) {
787
788 if (strcmp(scan->dai_name,driver->dd_prefix) == 0) {
789 dev_admin_registry_add(&driver->dd_dev_admin_registry,
790 scan->dai_param_name,
791 scan->dai_param_val);
792 }
793 scan++;i++;
794 }
795 i = 0;
796 /* Check the extended device driver administration info table */
797 scan = extended_drv_admin_table;
798 while (i < extended_drv_admin_table_size) {
799
800 if (strcmp(scan->dai_name,driver->dd_prefix) == 0) {
801 dev_admin_registry_add(&driver->dd_dev_admin_registry,
802 scan->dai_param_name,
803 scan->dai_param_val);
804 }
805 scan++;i++;
806 }
807 #endif
808 FIXME("device_driver_admin_info_update");
809 }
810
811 /* =====Device Driver Support===== */
812
813
814
815 /*
816 ** Generic device driver support routines for use by kernel modules that
817 ** deal with device drivers (but NOT for use by the drivers themselves).
818 ** EVERY registered driver currently in the system -- static or loadable --
819 ** has an entry in the device_driver_hash table. A pointer to such an entry
820 ** serves as a generic device driver handle.
821 */
822
823 #define DEVICE_DRIVER_HASH_SIZE 32
824 #ifdef LATER
825 lock_t device_driver_lock[DEVICE_DRIVER_HASH_SIZE];
826 device_driver_t device_driver_hash[DEVICE_DRIVER_HASH_SIZE];
827 static struct string_table driver_prefix_string_table;
828 #endif
829
830 /*
831 ** Initialize device driver infrastructure.
832 */
833 void
834 device_driver_init(void)
835 {
836 #ifdef LATER
837 int i;
838 extern void alenlist_init(void);
839 extern void hwgraph_init(void);
840 extern void device_desc_init(void);
841
842 ASSERT(DEVICE_DRIVER_NONE == NULL);
843 alenlist_init();
844 hwgraph_init();
845 device_desc_init();
846
847 string_table_init(&driver_prefix_string_table);
848
849 for (i=0; i<DEVICE_DRIVER_HASH_SIZE; i++) {
850 spin_lock_init(&device_driver_lock[i]);
851 device_driver_hash[i] = NULL;
852 }
853
854 /* Initialize static drivers from master.c table */
855 for (i=0; i<static_devsw_count; i++) {
856 device_driver_t driver;
857 static_device_driver_desc_t desc;
858 int pri;
859
860 desc = &static_device_driver_table[i];
861 driver = device_driver_get(desc->sdd_prefix);
862 if (!driver)
863 driver = device_driver_alloc(desc->sdd_prefix);
864 pri = device_driver_sysgen_thread_pri_get(desc->sdd_prefix);
865 device_driver_thread_pri_set(driver, pri);
866 device_driver_devsw_put(driver, desc->sdd_bdevsw, desc->sdd_cdevsw);
867 }
868 #endif
869 FIXME("device_driver_init");
870 }
871
872 /*
873 ** Hash a prefix string into a hash table chain.
874 */
875 static int
876 driver_prefix_hash(char *prefix)
877 {
878 #ifdef LATER
879 int accum = 0;
880 char nextchar;
881
882 while (nextchar = *prefix++)
883 accum = accum ^ nextchar;
884
885 return(accum % DEVICE_DRIVER_HASH_SIZE);
886 #else
887 FIXME("driver_prefix_hash");
888 return(0);
889 #endif
890 }
891
892
893 /*
894 ** Allocate a driver handle.
895 ** Returns the driver handle, or NULL if the driver prefix
896 ** already has a handle.
897 **
898 ** Upper layers prevent races among device_driver_alloc,
899 ** device_driver_free, and device_driver_get*.
900 */
901 device_driver_t
902 device_driver_alloc(char *prefix)
903 {
904 #ifdef LATER
905 int which_hash;
906 device_driver_t new_driver;
907 unsigned long s;
908
909 which_hash = driver_prefix_hash(prefix);
910
911 new_driver = kern_calloc(1, sizeof(*new_driver));
912 ASSERT(new_driver != NULL);
913 new_driver->dd_prev = NULL;
914 new_driver->dd_prefix = string_table_insert(&driver_prefix_string_table, prefix);
915 new_driver->dd_bdevsw = NULL;
916 new_driver->dd_cdevsw = NULL;
917
918 dev_admin_registry_init(&new_driver->dd_dev_admin_registry);
919 device_driver_admin_info_update(new_driver);
920
921 s = mutex_spinlock(&device_driver_lock[which_hash]);
922
923 #if DEBUG
924 {
925 device_driver_t drvscan;
926
927 /* Make sure we haven't already added a driver with this prefix */
928 drvscan = device_driver_hash[which_hash];
929 while (drvscan &&
930 strcmp(drvscan->dd_prefix, prefix)) {
931 drvscan = drvscan->dd_next;
932 }
933
934 ASSERT(!drvscan);
935 }
936 #endif /* DEBUG */
937
938
939 /* Add new_driver to front of hash chain. */
940 new_driver->dd_next = device_driver_hash[which_hash];
941 if (new_driver->dd_next)
942 new_driver->dd_next->dd_prev = new_driver;
943 device_driver_hash[which_hash] = new_driver;
944
945 mutex_spinunlock(&device_driver_lock[which_hash], s);
946
947 return(new_driver);
948 #else
949 FIXME("device_driver_alloc");
950 return((device_driver_t)0);
951 #endif
952 }
953
954 /*
955 ** Free a driver handle.
956 **
957 ** Statically loaded drivers should never device_driver_free.
958 ** Dynamically loaded drivers device_driver_free when either an
959 ** unloaded driver is unregistered, or when an unregistered driver
960 ** is unloaded.
961 */
962 void
963 device_driver_free(device_driver_t driver)
964 {
965 #ifdef LATER
966 int which_hash;
967 unsigned long s;
968
969 if (!driver)
970 return;
971
972 which_hash = driver_prefix_hash(driver->dd_prefix);
973
974 s = mutex_spinlock(&device_driver_lock[which_hash]);
975
976 #if DEBUG
977 {
978 device_driver_t drvscan;
979
980 /* Make sure we're dealing with the right list */
981 drvscan = device_driver_hash[which_hash];
982 while (drvscan && (drvscan != driver))
983 drvscan = drvscan->dd_next;
984
985 ASSERT(drvscan);
986 }
987 #endif /* DEBUG */
988
989 if (driver->dd_next)
990 driver->dd_next->dd_prev = driver->dd_prev;
991
992 if (driver->dd_prev)
993 driver->dd_prev->dd_next = driver->dd_next;
994 else
995 device_driver_hash[which_hash] = driver->dd_next;
996
997 mutex_spinunlock(&device_driver_lock[which_hash], s);
998
999 driver->dd_next = NULL; /* sanity */
1000 driver->dd_prev = NULL; /* sanity */
1001 driver->dd_prefix = NULL; /* sanity */
1002
1003 if (driver->dd_bdevsw) {
1004 driver->dd_bdevsw->d_driver = NULL;
1005 driver->dd_bdevsw = NULL;
1006 }
1007
1008 if (driver->dd_cdevsw) {
1009 if (driver->dd_cdevsw->d_str) {
1010 str_free_mux_node(driver);
1011 }
1012 driver->dd_cdevsw->d_driver = NULL;
1013 driver->dd_cdevsw = NULL;
1014 }
1015
1016 kern_free(driver);
1017 #endif
1018 FIXME("device_driver_free");
1019 }
1020
1021
1022 /*
1023 ** Given a device driver prefix, return a handle to the caller.
1024 */
1025 device_driver_t
1026 device_driver_get(char *prefix)
1027 {
1028 #ifdef LATER
1029 int which_hash;
1030 device_driver_t drvscan;
1031 unsigned long s;
1032
1033 if (prefix == NULL)
1034 return(NULL);
1035
1036 which_hash = driver_prefix_hash(prefix);
1037
1038 s = mutex_spinlock(&device_driver_lock[which_hash]);
1039
1040 drvscan = device_driver_hash[which_hash];
1041 while (drvscan && strcmp(drvscan->dd_prefix, prefix))
1042 drvscan = drvscan->dd_next;
1043
1044 mutex_spinunlock(&device_driver_lock[which_hash], s);
1045
1046 return(drvscan);
1047 #else
1048 FIXME("device_driver_get");
1049 return((device_driver_t)0);
1050 #endif
1051 }
1052
1053
1054 /*
1055 ** Given a block or char special file devfs_handle_t, find the
1056 ** device driver that controls it.
1057 */
1058 device_driver_t
1059 device_driver_getbydev(devfs_handle_t device)
1060 {
1061 #ifdef LATER
1062 struct bdevsw *my_bdevsw;
1063 struct cdevsw *my_cdevsw;
1064
1065 my_cdevsw = get_cdevsw(device);
1066 if (my_cdevsw != NULL)
1067 return(my_cdevsw->d_driver);
1068
1069 my_bdevsw = get_bdevsw(device);
1070 if (my_bdevsw != NULL)
1071 return(my_bdevsw->d_driver);
1072
1073 #endif
1074 FIXME("device_driver_getbydev");
1075 return((device_driver_t)0);
1076 }
1077
1078
1079 /*
1080 ** Associate a driver with bdevsw/cdevsw pointers.
1081 **
1082 ** Statically loaded drivers are permanently and automatically associated
1083 ** with the proper bdevsw/cdevsw. Dynamically loaded drivers associate
1084 ** themselves when the driver is registered, and disassociate when the
1085 ** driver unregisters.
1086 **
1087 ** Returns 0 on success, -1 on failure (devsw already associated with driver)
1088 */
1089 int
1090 device_driver_devsw_put(device_driver_t driver,
1091 struct bdevsw *my_bdevsw,
1092 struct cdevsw *my_cdevsw)
1093 {
1094 #ifdef LATER
1095 int i;
1096
1097 if (!driver)
1098 return(-1);
1099
1100 /* Trying to re-register data? */
1101 if (((my_bdevsw != NULL) && (driver->dd_bdevsw != NULL)) ||
1102 ((my_cdevsw != NULL) && (driver->dd_cdevsw != NULL)))
1103 return(-1);
1104
1105 if (my_bdevsw != NULL) {
1106 driver->dd_bdevsw = my_bdevsw;
1107 my_bdevsw->d_driver = driver;
1108 for (i = 0; i < bdevmax; i++) {
1109 if (driver->dd_bdevsw->d_flags == bdevsw[i].d_flags) {
1110 bdevsw[i].d_driver = driver;
1111 break;
1112 }
1113 }
1114 }
1115
1116 if (my_cdevsw != NULL) {
1117 driver->dd_cdevsw = my_cdevsw;
1118 my_cdevsw->d_driver = driver;
1119 for (i = 0; i < cdevmax; i++) {
1120 if (driver->dd_cdevsw->d_flags == cdevsw[i].d_flags) {
1121 cdevsw[i].d_driver = driver;
1122 break;
1123 }
1124 }
1125 }
1126 #endif
1127 FIXME("device_driver_devsw_put");
1128 return(0);
1129 }
1130
1131
1132 /*
1133 ** Given a driver, return the corresponding bdevsw and cdevsw pointers.
1134 */
1135 void
1136 device_driver_devsw_get( device_driver_t driver,
1137 struct bdevsw **bdevswp,
1138 struct cdevsw **cdevswp)
1139 {
1140 if (!driver) {
1141 *bdevswp = NULL;
1142 *cdevswp = NULL;
1143 } else {
1144 *bdevswp = driver->dd_bdevsw;
1145 *cdevswp = driver->dd_cdevsw;
1146 }
1147 }
1148
1149 /*
1150 * device_driver_thread_pri_set
1151 * Given a driver try to set its thread priority.
1152 * Returns 0 on success , -1 on failure.
1153 */
1154 int
1155 device_driver_thread_pri_set(device_driver_t driver,ilvl_t pri)
1156 {
1157 if (!driver)
1158 return(-1);
1159 driver->dd_thread_pri = pri;
1160 return(0);
1161 }
1162 /*
1163 * device_driver_thread_pri_get
1164 * Given a driver return the driver thread priority.
1165 * If the driver is NULL return invalid driver thread
1166 * priority.
1167 */
1168 ilvl_t
1169 device_driver_thread_pri_get(device_driver_t driver)
1170 {
1171 if (driver)
1172 return(driver->dd_thread_pri);
1173 else
1174 return(DRIVER_THREAD_PRI_INVALID);
1175 }
1176 /*
1177 ** Given a device driver, return it's handle (prefix).
1178 */
1179 void
1180 device_driver_name_get(device_driver_t driver, char *buffer, int length)
1181 {
1182 if (driver == NULL)
1183 return;
1184
1185 strncpy(buffer, driver->dd_prefix, length);
1186 }
1187
1188
1189 /*
1190 ** Associate a pointer-sized piece of information with a device.
1191 */
1192 void
1193 device_info_set(devfs_handle_t device, void *info)
1194 {
1195 #ifdef LATER
1196 hwgraph_fastinfo_set(device, (arbitrary_info_t)info);
1197 #endif
1198 FIXME("device_info_set");
1199 }
1200
1201
1202 /*
1203 ** Retrieve a pointer-sized piece of information associated with a device.
1204 */
1205 void *
1206 device_info_get(devfs_handle_t device)
1207 {
1208 #ifdef LATER
1209 return((void *)hwgraph_fastinfo_get(device));
1210 #else
1211 FIXME("device_info_get");
1212 return(NULL);
1213 #endif
1214 }
1215
1216 /*
1217 * Find the thread priority for a device, from the various
1218 * sysgen files.
1219 */
1220 int
1221 device_driver_sysgen_thread_pri_get(char *dev_prefix)
1222 {
1223 #ifdef LATER
1224 int pri;
1225 char *pri_s;
1226 char *class;
1227
1228 extern default_intr_pri;
1229 extern disk_intr_pri;
1230 extern serial_intr_pri;
1231 extern parallel_intr_pri;
1232 extern tape_intr_pri;
1233 extern graphics_intr_pri;
1234 extern network_intr_pri;
1235 extern scsi_intr_pri;
1236 extern audio_intr_pri;
1237 extern video_intr_pri;
1238 extern external_intr_pri;
1239 extern tserialio_intr_pri;
1240
1241 /* Check if there is a thread priority specified for
1242 * this driver's thread thru admin hints. If so
1243 * use that value. Otherwise set it to its default
1244 * class value, otherwise set it to the default
1245 * value.
1246 */
1247
1248 if (pri_s = device_driver_admin_info_get(dev_prefix,
1249 ADMIN_LBL_THREAD_PRI)) {
1250 pri = atoi(pri_s);
1251 } else if (class = device_driver_admin_info_get(dev_prefix,
1252 ADMIN_LBL_THREAD_CLASS)) {
1253 if (strcmp(class, "disk") == 0)
1254 pri = disk_intr_pri;
1255 else if (strcmp(class, "serial") == 0)
1256 pri = serial_intr_pri;
1257 else if (strcmp(class, "parallel") == 0)
1258 pri = parallel_intr_pri;
1259 else if (strcmp(class, "tape") == 0)
1260 pri = tape_intr_pri;
1261 else if (strcmp(class, "graphics") == 0)
1262 pri = graphics_intr_pri;
1263 else if (strcmp(class, "network") == 0)
1264 pri = network_intr_pri;
1265 else if (strcmp(class, "scsi") == 0)
1266 pri = scsi_intr_pri;
1267 else if (strcmp(class, "audio") == 0)
1268 pri = audio_intr_pri;
1269 else if (strcmp(class, "video") == 0)
1270 pri = video_intr_pri;
1271 else if (strcmp(class, "external") == 0)
1272 pri = external_intr_pri;
1273 else if (strcmp(class, "tserialio") == 0)
1274 pri = tserialio_intr_pri;
1275 else
1276 pri = default_intr_pri;
1277 } else
1278 pri = default_intr_pri;
1279
1280 if (pri > 255)
1281 pri = 255;
1282 else if (pri < 0)
1283 pri = 0;
1284 return pri;
1285 #else
1286 FIXME("device_driver_sysgen_thread_pri_get");
1287 return(-1);
1288 #endif
1289 }
1290