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(&registry->reg_lock,
329     				    "dev_admin_registry_lock");
330     		registry->reg_first = NULL;
331     		registry->reg_last = &registry->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(&registry->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	= &reg_entry->admin_next;
392     
393     out:	DEV_ADMIN_REGISTRY_UNLOCK(&registry->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(&registry->reg_lock);
409     	scan = registry->reg_first;
410     
411     	while (scan) {
412     		if (strcmp(scan->admin_name,name) == 0) {
413     			DEV_ADMIN_REGISTRY_UNLOCK(&registry->reg_lock);
414     			return scan->admin_val;
415     		}
416     		scan = scan->admin_next;
417     	}
418     	DEV_ADMIN_REGISTRY_UNLOCK(&registry->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