eisaconf.c revision 13691
1/*
2 * EISA bus probe and attach routines
3 *
4 * Copyright (c) 1995, 1996 Justin T. Gibbs.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice immediately at the beginning of the file, without modification,
12 *    this list of conditions, and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. Absolutely no warranty of function or purpose is made by the author
17 *    Justin T. Gibbs.
18 * 4. Modifications may be freely made to this file if the above conditions
19 *    are met.
20 *
21 *	$Id: eisaconf.c,v 1.12 1996/01/03 06:28:01 gibbs Exp $
22 */
23#include <sys/param.h>
24#include <sys/systm.h>
25#include <sys/devconf.h>
26#include <sys/kernel.h>
27#include <sys/sysctl.h>
28#include <sys/conf.h>		/* For kdc_isa */
29#include <sys/malloc.h>
30
31#include <i386/eisa/eisaconf.h>
32
33#include <i386/isa/icu.h>	 /* Hmmm.  Interrupt stuff? */
34
35struct eisa_device_node{
36	struct	eisa_device dev;
37	struct	eisa_device_node *next;
38};
39
40extern struct kern_devconf kdc_cpu0;
41extern int bootverbose;
42
43struct kern_devconf kdc_eisa0 = {
44	0, 0, 0,                /* filled in by dev_attach */
45	"eisa", 0, { MDDT_BUS, 0 },
46	0, 0, 0, BUS_EXTERNALLEN,
47	&kdc_cpu0,              /* parent is the CPU */
48	0,                      /* no parentdata */
49	DC_BUSY,                /* busses are always busy */
50	NULL,
51	DC_CLS_BUS              /* class */
52};
53
54/*
55 * This should probably be a list of "struct device" once it exists.
56 * A struct device will incorperate ioconf and driver entry point data
57 * regardless of how its attached to the system (via unions) as well
58 * as more generic information that all device types should support (unit
59 * number, if its installed, etc).
60 */
61static struct eisa_device_node *eisa_dev_list;
62static struct eisa_device_node **eisa_dev_list_tail = &eisa_dev_list;
63static u_long eisa_unit;
64
65static struct eisa_driver mainboard_drv = {
66				     "eisa",
67				     NULL,
68				     NULL,
69				     NULL,
70				     &eisa_unit
71				   };
72
73/*
74 * Add the mainboard_drv to the eisa driver linkerset so that it is
75 * defined even if no EISA drivers are linked into the kernel.
76 */
77DATA_SET (eisadriver_set, mainboard_drv);
78
79/*
80 * Local function declarations and static variables
81 */
82void eisa_reg_print __P((struct eisa_device *e_dev, char *string,
83			 char *separator));
84static int eisa_add_resvaddr __P((struct resvlist *head, u_long	base,
85				  u_long size, int flags));
86static int eisa_reg_resvaddr __P((struct eisa_device *e_dev,
87				  struct resvlist *head, resvaddr_t *resvaddr,
88				  int *reg_count));
89
90/*
91 * Keep some state about what we've printed so far
92 * to make probe output pretty.
93 */
94static struct {
95	int	in_registration;/* reg_start has been called */
96	int	num_interrupts;
97	int	num_ioaddrs;
98	int	num_maddrs;
99	int	column;		/* How much we have output so far. */
100#define	MAX_COL 80
101} reg_state;
102
103/*
104** probe for EISA devices
105*/
106void
107eisa_configure()
108{
109	int i,slot;
110	char *id_string;
111	struct eisa_device_node *dev_node;
112	struct eisa_driver **e_drvp;
113	struct eisa_driver *e_drv;
114	struct eisa_device *e_dev;
115	int eisaBase = 0xc80;
116	eisa_id_t eisa_id;
117
118	e_drvp = (struct eisa_driver**)eisadriver_set.ls_items;
119
120	for (slot = 0; slot < EISA_SLOTS; eisaBase+=0x1000, slot++) {
121		int id_size = sizeof(eisa_id);
122		eisa_id = 0;
123    		for( i = 0; i < id_size; i++ ) {
124			outb(eisaBase,0x80 + i); /*Some cards require priming*/
125			eisa_id |= inb(eisaBase+i) << ((id_size-i-1)*CHAR_BIT);
126		}
127		if (eisa_id & 0x80000000)
128			continue;  /* no EISA card in slot */
129
130		/* Prepare an eisa_device_node for this slot */
131		dev_node = (struct eisa_device_node *)malloc(sizeof(*dev_node),
132							    M_DEVBUF, M_NOWAIT);
133		if (!dev_node) {
134			printf("eisa0: cannot malloc eisa_device_node");
135			break; /* Try to attach what we have already */
136		}
137		bzero(dev_node, sizeof(*dev_node));
138		e_dev = &(dev_node->dev);
139
140		e_dev->id = eisa_id;
141		/*
142		 * Add an EISA ID based descriptive name incase we don't
143		 * have a driver for it.  We do this now instead of after all
144		 * probes because in the future, the eisa module will only
145		 * be responsible for creating the list of devices in the system
146		 * for the configuration manager to use.
147		 */
148		e_dev->full_name = (char *)malloc(10*sizeof(char),
149						  M_DEVBUF, M_NOWAIT);
150		if (!e_dev->full_name) {
151			panic("Eisa probe unable to malloc");
152		}
153		sprintf(e_dev->full_name, "%c%c%c%x%x",
154			EISA_MFCTR_CHAR0(e_dev->id),
155			EISA_MFCTR_CHAR1(e_dev->id),
156			EISA_MFCTR_CHAR2(e_dev->id),
157			EISA_PRODUCT_ID(e_dev->id),
158			EISA_REVISION_ID(e_dev->id));
159
160		e_dev->ioconf.slot = slot;
161
162		/* Initialize our lists of reserved addresses */
163		LIST_INIT(&(e_dev->ioconf.ioaddrs));
164		LIST_INIT(&(e_dev->ioconf.maddrs));
165
166		*eisa_dev_list_tail = dev_node;
167		eisa_dev_list_tail = &dev_node->next;
168	}
169
170	dev_node = eisa_dev_list;
171
172	/*
173	 * "Attach" the system board
174	 */
175
176	/* The first will be the motherboard in a true EISA system */
177	if (dev_node && (dev_node->dev.ioconf.slot == 0)) {
178		e_dev = &dev_node->dev;
179		e_dev->driver = &mainboard_drv;
180		e_dev->unit = (*e_dev->driver->unit)++;
181		id_string = e_dev->full_name;
182		e_dev->full_name = (char *)malloc(strlen(e_dev->full_name)
183						  + sizeof(" (System Board)")
184						  + 1, M_DEVBUF, M_NOWAIT);
185		if (!e_dev->full_name) {
186			panic("Eisa probe unable to malloc");
187		}
188		sprintf(e_dev->full_name, "%s (System Board)", id_string);
189		free(id_string, M_DEVBUF);
190
191		printf("%s%ld: <%s>\n",
192		       e_dev->driver->name,
193		       e_dev->unit,
194		       e_dev->full_name);
195
196		/* Should set the iosize, but I don't have a spec handy */
197		kdc_eisa0.kdc_description =
198			(char *)malloc(strlen(e_dev->full_name)
199				       + sizeof("EISA bus <>")
200				       + 1, M_DEVBUF, M_NOWAIT);
201		if (!kdc_eisa0.kdc_description) {
202			panic("Eisa probe unable to malloc");
203		}
204		sprintf((char *)kdc_eisa0.kdc_description, "EISA bus <%s>",
205			e_dev->full_name);
206		dev_attach(&kdc_eisa0);
207		printf("Probing for devices on the EISA bus\n");
208		dev_node = dev_node->next;
209	}
210
211	if (!eisa_dev_list) {
212		/*
213		 * No devices.
214		 */
215		return;
216    	}
217	/*
218	 * See what devices we recognize.
219	 */
220	while((e_drv = *e_drvp++)) {
221		if (e_drv->probe)
222			(*e_drv->probe)();
223	}
224
225	/*
226	 * Attach the devices we found in slot order
227	 */
228	for (; dev_node; dev_node=dev_node->next) {
229		e_dev = &dev_node->dev;
230		e_drv = e_dev->driver;
231
232		if (e_drv) {
233			/*
234			 * Determine the proper unit number for this device.
235			 * Here we should look in the device table generated
236			 * by config to see if this type of device is enabled
237			 * either generically or for this particular address
238			 * as well as determine if a reserved unit number
239			 * should be used.  We should also ensure that the
240			 * "next availible unit number" skips over "wired" unit
241			 * numbers. This will be done after config is fixed or
242			 * some other configuration method is chosen.
243			 */
244			e_dev->unit = (*e_drv->unit)++;
245			if ((*e_drv->attach)(e_dev) < 0) {
246				/* Ensure registration has ended */
247				reg_state.in_registration = 0;
248				printf("\n%s0:%d <%s> attach failed\n",
249					mainboard_drv.name,
250					e_dev->ioconf.slot,
251					e_dev->full_name);
252				continue;
253			}
254			/* Ensure registration has ended */
255			reg_state.in_registration = 0;
256			e_dev->kdc->kdc_unit = e_dev->unit;
257		}
258		else {
259			/* Announce unattached device */
260			printf("%s0:%d <%s=0x%x> unknown device\n",
261				mainboard_drv.name,
262				e_dev->ioconf.slot,
263				e_dev->full_name,
264				e_dev->id);
265		}
266	}
267}
268
269struct eisa_device *
270eisa_match_dev(e_dev, match_func)
271	struct eisa_device *e_dev;
272	char* (*match_func)(eisa_id_t);
273{
274	struct eisa_device_node *e_node = eisa_dev_list;
275
276	if (e_dev) {
277		/* Start our search from the last successful match */
278		e_node = ((struct eisa_device_node *)e_dev)->next;
279	}
280
281	for(; e_node; e_node = e_node->next) {
282		char *result;
283		if (e_node->dev.driver) {
284			/* Already claimed */
285			continue;
286		}
287		result = (*match_func)(e_node->dev.id);
288		if (result) {
289			free(e_node->dev.full_name, M_DEVBUF);
290			e_node->dev.full_name = result;
291			return (&(e_node->dev));
292		}
293	}
294	return NULL;
295}
296
297/* Interrupt and I/O space registration facitlities */
298void
299eisa_reg_start(e_dev)
300	struct eisa_device *e_dev;
301{
302	/*
303	 * Announce the device.
304	 */
305	char *string;
306
307	reg_state.in_registration = 1;
308	reg_state.num_interrupts = 0;
309	reg_state.num_ioaddrs = 0;
310	reg_state.num_maddrs = 0;
311	reg_state.column = 0;
312
313	string = malloc(strlen(e_dev->full_name) + sizeof(" <>") + /*NULL*/1,
314			M_TEMP, M_NOWAIT);
315	if(!string) {
316		printf("eisa0: cannot malloc device description string\n");
317		return;
318	}
319	sprintf(string, " <%s>", e_dev->full_name);
320	eisa_reg_print(e_dev, string, /*separator=*/NULL);
321	free(string, M_TEMP);
322}
323
324/*
325 * Output registration information mindfull of screen wrap.
326 * Output an optional character separator before the string
327 * if the line does not wrap.
328 */
329void
330eisa_reg_print(e_dev, string, separator)
331	struct eisa_device *e_dev;
332	char *string;
333	char *separator;
334{
335	int len = strlen(string);
336
337	if( separator )
338		len++;
339
340	if(reg_state.column + len > MAX_COL) {
341		printf("\n");
342		reg_state.column = 0;
343	}
344	else if( separator ) {
345		printf("%c", *separator);
346		reg_state.column++;
347	}
348
349	if(reg_state.column == 0)
350		reg_state.column += printf("%s%ld:%s",
351					   e_dev->driver->name,
352					   e_dev->unit,
353					   string);
354	else
355		reg_state.column += printf("%s", string);
356}
357
358/* Interrupt and I/O space registration facitlities */
359void
360eisa_reg_end(e_dev)
361	struct eisa_device *e_dev;
362{
363	if( reg_state.in_registration )
364	{
365		/*
366		 * The device should have called eisa_registerdev()
367		 * during its probe.  So hopefully we can use the kdc
368		 * to weed out ISA/VL devices that use EISA id registers.
369		 */
370		char string[25];
371
372		if (e_dev->kdc && (e_dev->kdc->kdc_parent == &kdc_isa0)) {
373			sprintf(string, " on isa");
374		}
375		else {
376			sprintf(string, " on %s0 slot %d",
377				mainboard_drv.name,
378				e_dev->ioconf.slot);
379		}
380		eisa_reg_print(e_dev, string, NULL);
381		printf("\n");
382		reg_state.in_registration = 0;
383	}
384	else
385		printf("eisa_reg_end called outside of a "
386		       "registration session\n");
387}
388
389int
390eisa_add_intr(e_dev, irq)
391	struct eisa_device *e_dev;
392	int irq;
393{
394	e_dev->ioconf.irq |= 1ul << irq;
395	return 0;
396}
397
398int
399eisa_reg_intr(e_dev, irq, func, arg, maskptr, shared)
400	struct eisa_device *e_dev;
401	int   irq;
402	void  (*func)(void *);
403	void  *arg;
404	u_int *maskptr;
405	int   shared;
406{
407	int result;
408	int s;
409	char string[25];
410	char separator = ',';
411
412#if NOT_YET
413	/*
414	 * Punt on conflict detection for the moment.
415	 * I want to develop a generic routine to do
416	 * this for all device types.
417	 */
418	int checkthese = CC_IRQ;
419	if (haveseen_dev(dev, checkthese))
420        	return 1;
421#endif
422	if (reg_state.in_registration) {
423		s = splhigh();
424		/*
425		 * This should really go to a routine that can optionally
426		 * handle shared interrupts.
427		 */
428		result = register_intr(irq,		   /* isa irq	   */
429				       0,		   /* deviced??    */
430				       0,		   /* flags?       */
431				       (inthand2_t*) func, /* handler      */
432				       maskptr,		   /* mask pointer */
433				       (int)arg);	   /* handler arg  */
434
435		if (result) {
436			printf ("\neisa_reg_int: result=%d\n", result);
437			splx(s);
438			return (result);
439		};
440		update_intr_masks();
441		splx(s);
442	}
443	else
444		return EPERM;
445
446	e_dev->ioconf.irq |= 1ul << irq;
447	sprintf(string, " irq %d", irq);
448	eisa_reg_print(e_dev, string, reg_state.num_interrupts ?
449				      &separator : NULL);
450	reg_state.num_interrupts++;
451	return (0);
452}
453
454int
455eisa_release_intr(e_dev, irq, func)
456	struct eisa_device *e_dev;
457	int   irq;
458	void  (*func)(void *);
459{
460	int result;
461	int s;
462
463	if (!(e_dev->ioconf.irq & (1ul << irq))) {
464		printf("%s%ld: Attempted to release an interrupt (%d) "
465		       "it doesn't own\n", e_dev->driver->name,
466			e_dev->unit, irq);
467		return (-1);
468	}
469
470	s = splhigh();
471	INTRDIS ((1ul<<irq));
472
473	result = unregister_intr (irq, (inthand2_t*)func);
474
475	if (result)
476		printf ("eisa_release_intr: result=%d\n", result);
477
478	update_intr_masks();
479
480	splx(s);
481	return (result);
482}
483
484int
485eisa_enable_intr(e_dev, irq)
486	struct eisa_device *e_dev;
487	int irq;
488{
489	int s;
490
491	if (!(e_dev->ioconf.irq & (1ul << irq))) {
492		printf("%s%ld: Attempted to enable an interrupt (%d) "
493		       "it doesn't own\n", e_dev->driver->name,
494			e_dev->unit, irq);
495		return (-1);
496	}
497	s = splhigh();
498	INTREN((1ul << irq));
499	splx(s);
500	return 0;
501}
502
503static int
504eisa_add_resvaddr(head, base, size, flags)
505	struct resvlist *head;
506	u_long	base;
507	u_long	size;
508	int	flags;
509{
510	resvaddr_t *reservation;
511
512	reservation = (resvaddr_t *)malloc(sizeof(resvaddr_t),
513					   M_DEVBUF, M_NOWAIT);
514	if(!reservation)
515		return (ENOMEM);
516
517	reservation->addr = base;
518	reservation->size = size;
519	reservation->flags = flags;
520
521	if (!head->lh_first) {
522		LIST_INSERT_HEAD(head, reservation, links);
523	}
524	else {
525		resvaddr_t *node;
526		for(node = head->lh_first; node; node = node->links.le_next) {
527			if (node->addr > reservation->addr) {
528				/*
529				 * List is sorted in increasing
530				 * address order.
531				 */
532				LIST_INSERT_BEFORE(node, reservation, links);
533				break;
534			}
535
536			if (node->addr == reservation->addr) {
537				/*
538				 * If the entry we want to add
539				 * matches any already in here,
540				 * fail.
541				 */
542				free(reservation, M_DEVBUF);
543				return (EEXIST);
544			}
545
546			if (!node->links.le_next) {
547				LIST_INSERT_AFTER(node, reservation, links);
548				break;
549			}
550		}
551	}
552	return (0);
553}
554
555int
556eisa_add_mspace(e_dev, mbase, msize, flags)
557	struct eisa_device *e_dev;
558	u_long	mbase;
559	u_long	msize;
560	int	flags;
561{
562	return	eisa_add_resvaddr(&(e_dev->ioconf.maddrs), mbase, msize, flags);
563}
564
565int
566eisa_add_iospace(e_dev, iobase, iosize, flags)
567	struct eisa_device *e_dev;
568	u_long	iobase;
569	u_long	iosize;
570	int	flags;
571{
572	return	eisa_add_resvaddr(&(e_dev->ioconf.ioaddrs), iobase, iosize,
573				  flags);
574}
575
576static int
577eisa_reg_resvaddr(e_dev, head, resvaddr, reg_count)
578	struct eisa_device *e_dev;
579	struct resvlist *head;
580	resvaddr_t *resvaddr;
581	int *reg_count;
582{
583	if (reg_state.in_registration) {
584		resvaddr_t *node;
585		/*
586		 * Ensure that this resvaddr is actually in the devices'
587		 * reservation list.
588		 */
589		for(node = head->lh_first; node;
590		    node = node->links.le_next) {
591			if (node == resvaddr) {
592				char buf[35];
593				char separator = ',';
594				char *string = buf;
595
596				if (*reg_count == 0) {
597					/* First time */
598					string += sprintf(string, " at");
599				}
600
601				if (node->size == 1
602				  || (node->flags & RESVADDR_BITMASK))
603					sprintf(string, " 0x%lx", node->addr);
604				else
605					sprintf(string, " 0x%lx-0x%lx",
606						node->addr,
607						node->addr + node->size - 1);
608				eisa_reg_print(e_dev, buf,
609						*reg_count ? &separator : NULL);
610				(*reg_count)++;
611				return (0);
612			}
613		}
614		return (ENOENT);
615	}
616	return EPERM;
617}
618
619int
620eisa_reg_mspace(e_dev, resvaddr)
621	struct eisa_device *e_dev;
622	resvaddr_t *resvaddr;
623{
624#ifdef NOT_YET
625	/*
626	 * Punt on conflict detection for the moment.
627	 * I want to develop a generic routine to do
628	 * this for all device types.
629	 */
630	int checkthese = CC_MADDR;
631	if (haveseen_dev(dev, checkthese))
632		return -1;
633#endif
634	return (eisa_reg_resvaddr(e_dev, &(e_dev->ioconf.maddrs), resvaddr,
635				  &(reg_state.num_maddrs)));
636}
637
638int
639eisa_reg_iospace(e_dev, resvaddr)
640	struct eisa_device *e_dev;
641	resvaddr_t *resvaddr;
642{
643#ifdef NOT_YET
644	/*
645	 * Punt on conflict detection for the moment.
646	 * I want to develop a generic routine to do
647	 * this for all device types.
648	 */
649	int checkthese = CC_IOADDR;
650	if (haveseen_dev(dev, checkthese))
651		return -1;
652#endif
653	return (eisa_reg_resvaddr(e_dev, &(e_dev->ioconf.ioaddrs), resvaddr,
654				  &(reg_state.num_ioaddrs)));
655}
656
657int
658eisa_registerdev(e_dev, driver, kdc_template)
659	struct eisa_device *e_dev;
660	struct eisa_driver *driver;
661	struct kern_devconf *kdc_template;
662{
663	e_dev->driver = driver;	/* Driver now owns this device */
664	e_dev->kdc = (struct kern_devconf *)malloc(sizeof(struct kern_devconf),
665						   M_DEVBUF, M_NOWAIT);
666	if (!e_dev->kdc) {
667		printf("WARNING: eisa_registerdev unable to malloc! "
668		       "Device kdc will not be registerd\n");
669		return 1;
670	}
671	bcopy(kdc_template, e_dev->kdc, sizeof(*kdc_template));
672	e_dev->kdc->kdc_description = e_dev->full_name;
673	e_dev->kdc->kdc_parentdata = e_dev;
674	dev_attach(e_dev->kdc);
675	return (0);
676}
677
678int
679eisa_generic_externalize(struct kern_devconf *kdc, struct sysctl_req *req)
680{
681    return (SYSCTL_OUT(req, kdc->kdc_eisa, sizeof(struct eisa_device)));
682}
683