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