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