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