eisaconf.c revision 12122
190075Sobrien/*
2132718Skan * EISA bus probe and attach routines
390075Sobrien *
451885Sobrien * Copyright (c) 1995 Justin T. Gibbs.
518334Speter * All rights reserved.
690075Sobrien *
718334Speter * Redistribution and use in source and binary forms, with or without
890075Sobrien * modification, are permitted provided that the following conditions
990075Sobrien * are met:
1090075Sobrien * 1. Redistributions of source code must retain the above copyright
1190075Sobrien *    notice immediately at the beginning of the file, without modification,
1218334Speter *    this list of conditions, and the following disclaimer.
1390075Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1490075Sobrien *    notice, this list of conditions and the following disclaimer in the
1590075Sobrien *    documentation and/or other materials provided with the distribution.
1690075Sobrien * 3. Absolutely no warranty of function or purpose is made by the author
1718334Speter *    Justin T. Gibbs.
1818334Speter * 4. Modifications may be freely made to this file if the above conditions
1990075Sobrien *    are met.
2090075Sobrien *
2190075Sobrien *	$Id: eisaconf.c,v 1.3 1995/11/05 04:42:49 gibbs Exp $
2218334Speter */
2390075Sobrien#include <sys/param.h>
2490075Sobrien#include <sys/systm.h>
2590075Sobrien#include <sys/kernel.h>
26117395Skan#include <sys/conf.h>
27117395Skan#include <sys/malloc.h>
28117395Skan
29117395Skan#include "sys/types.h"
30132718Skan#include "i386/isa/icu.h"	 /* Hmmm.  Interrupt stuff? */
31132718Skan#include <sys/devconf.h>
32132718Skan#include "eisaconf.h"
33132718Skan
34132718Skanstruct eisa_device_node{
35132718Skan	struct eisa_device	 dev;
36132718Skan	struct eisa_device_node	*next;
37117395Skan};
3890075Sobrien
3990075Sobrienextern struct kern_devconf kdc_cpu0;
4090075Sobrienextern int bootverbose;
4190075Sobrien
4290075Sobrienstruct kern_devconf kdc_eisa0 = {
4390075Sobrien	0, 0, 0,                /* filled in by dev_attach */
4490075Sobrien	"eisa", 0, { MDDT_BUS, 0 },
4590075Sobrien	0, 0, 0, BUS_EXTERNALLEN,
4690075Sobrien	&kdc_cpu0,              /* parent is the CPU */
4790075Sobrien	0,                      /* no parentdata */
4890075Sobrien	DC_BUSY,                /* busses are always busy */
4990075Sobrien	"EISA bus",
50132718Skan	DC_CLS_BUS              /* class */
51132718Skan};
5218334Speter
5318334Speter/*
54132718Skan * This should probably be a list of "struct device" once it exists.
55132718Skan * A struct device will incorperate ioconf and driver entry point data
56132718Skan * regardless of how its attached to the system (via unions) as well
57132718Skan * as more generic information that all device types should support (unit
58132718Skan * number, if its installed, etc).
59132718Skan */
60132718Skanstatic struct eisa_device_node *eisa_dev_list;
61132718Skanstatic struct eisa_device_node **eisa_dev_list_tail = &eisa_dev_list;
62132718Skanstatic u_long eisa_unit;
63132718Skan
64132718Skanstatic struct eisa_driver mainboard_drv = {
65132718Skan				     "eisa",
6618334Speter				     NULL,
67132718Skan				     NULL,
68132718Skan				     NULL,
69132718Skan				     &eisa_unit
70132718Skan				   };
7118334Speter/*
7218334Speter** probe for EISA devices
7318334Speter*/
7418334Spetervoid
7590075Sobrieneisa_configure()
7618334Speter{
7718334Speter    int i,slot;
7818334Speter    char *id_string;
7918334Speter    struct eisa_device_node *dev_node;
8018334Speter    struct eisa_driver **e_drvp = (struct eisa_driver**)eisadriver_set.ls_items;
8118334Speter    struct eisa_driver *e_drv;
8218334Speter    struct eisa_device *e_dev;
8390075Sobrien    int eisaBase = 0xC80;
84132718Skan    int first_slot = 0;
8518334Speter    eisa_id_t eisa_id;
8618334Speter
8718334Speter    outb(eisaBase,0xFF);
8818334Speter    eisa_id = inb(eisaBase);
89132718Skan    if (eisa_id & 0x80) {
9018334Speter	/*
9118334Speter	 * Not an EISA machine.  We still want to find boards like the
9218334Speter	 * Adaptec 284x that respond to EISA probes, so we "fake" the
9318334Speter	 * system board entry which the rest of the code uses as the
9418334Speter	 * sentinal node in the eisa_dev_list.
9590075Sobrien	 */
9618334Speter	first_slot = 1;		/* Start at slot 1 just to be safe */
9718334Speter	eisaBase+=0x1000;
9818334Speter	dev_node = (struct eisa_device_node *)malloc(sizeof(*dev_node),
9990075Sobrien						     M_DEVBUF, M_NOWAIT);
10018334Speter	if (!dev_node) {
10118334Speter		printf("eisa0: cannot malloc eisa_device_node");
10218334Speter		return;
10318334Speter	}
10418334Speter	bzero(dev_node, sizeof(*dev_node));
10518334Speter	e_dev = &(dev_node->dev);
10690075Sobrien	e_dev->ioconf.slot = 0;
10718334Speter	*eisa_dev_list_tail = dev_node;
10818334Speter	eisa_dev_list_tail = &dev_node->next;
10990075Sobrien    }
11018334Speter
11118334Speter    for (slot = first_slot; slot < EISA_SLOTS; eisaBase+=0x1000, slot++) {
11218334Speter	int id_size = sizeof(eisa_id);
11318334Speter	eisa_id = 0;
11418334Speter    	for( i = 0; i < id_size; i++ ) {
11518334Speter		outb(eisaBase,0xc80 + i); /* Some cards require priming */
11690075Sobrien		eisa_id |= inb(eisaBase + i) << ((id_size - i - 1) * CHAR_BIT);
11718334Speter	}
11818334Speter	if (eisa_id & 0x80000000)
11990075Sobrien	    continue;  /* no EISA card in slot */
12018334Speter
12118334Speter	/* Prepare an eisa_device_node for this slot */
12218334Speter	dev_node = (struct eisa_device_node *)malloc(sizeof(*dev_node),
12318334Speter						     M_DEVBUF, M_NOWAIT);
12418334Speter	if (!dev_node) {
12518334Speter		printf("eisa0: cannot malloc eisa_device_node");
12618334Speter		break; /* Try to attach what we have already */
12718334Speter	}
12818334Speter	bzero(dev_node, sizeof(*dev_node));
12918334Speter	e_dev = &(dev_node->dev);
13018334Speter	e_dev->id = eisa_id;
13118334Speter	/*
13218334Speter	 * Add an EISA ID based descriptive name incase we don't
13390075Sobrien	 * have a driver for it.  We do this now instead of after all
13418334Speter	 * probes because in the future, the eisa module will only
13518334Speter	 * be responsible for creating the list of devices in the system
13618334Speter	 * for the configuration manager to use.
13718334Speter	 */
13818334Speter	e_dev->full_name = (char *)malloc(14*sizeof(char), M_DEVBUF, M_NOWAIT);
13918334Speter	if (!e_dev->full_name) {
14018334Speter	    panic("Eisa probe unable to malloc");
14118334Speter	}
142146895Skan	sprintf(e_dev->full_name, "%c%c%c%x rev %x",
143146895Skan		EISA_MFCTR_CHAR0(e_dev->id),
144146895Skan		EISA_MFCTR_CHAR1(e_dev->id),
145146895Skan		EISA_MFCTR_CHAR2(e_dev->id),
146146895Skan		EISA_PRODUCT_ID(e_dev->id),
147146895Skan		EISA_REVISION_ID(e_dev->id));
148117395Skan	e_dev->ioconf.slot = slot;
149117395Skan	/* Is iobase defined in any EISA specs? */
150117395Skan	e_dev->ioconf.iobase = eisaBase & 0xff00;
151117395Skan	*eisa_dev_list_tail = dev_node;
152117395Skan	eisa_dev_list_tail = &dev_node->next;
153117395Skan    }
154117395Skan
155117395Skan    dev_node = eisa_dev_list;
15651885Sobrien
15751885Sobrien    /*
15851885Sobrien     * "Attach" the system board
15956173Sobrien     */
16051885Sobrien
16151885Sobrien    /* The first entry had better be the motherboard */
16290075Sobrien    if (!dev_node || (dev_node->dev.ioconf.slot != 0))
16390075Sobrien	panic("EISA system board not in eisa_dev_list");
16490075Sobrien
16590075Sobrien    e_dev = &dev_node->dev;
16690075Sobrien    e_dev->driver = &mainboard_drv;
16790075Sobrien    e_dev->unit = (*e_dev->driver->unit)++;
168132718Skan
16990075Sobrien    if (e_dev->full_name) { /* This is a real EISA system */
17090075Sobrien	id_string = e_dev->full_name;
17190075Sobrien	e_dev->full_name = (char *)malloc(strlen(e_dev->full_name)
17290075Sobrien					  + sizeof(" (System Board)")
17390075Sobrien					  + 1, M_DEVBUF, M_NOWAIT);
17490075Sobrien	if (!e_dev->full_name) {
17590075Sobrien	    panic("Eisa probe unable to malloc");
17690075Sobrien	}
17790075Sobrien	sprintf(e_dev->full_name, "%s (System Board)", id_string);
17890075Sobrien	free(id_string, M_DEVBUF);
17990075Sobrien
18090075Sobrien	printf("%s%ld: <%s>\n",
18190075Sobrien	       e_dev->driver->name,
18290075Sobrien	       e_dev->unit,
18390075Sobrien	       e_dev->full_name);
18490075Sobrien
185117395Skan	/* Should set the iosize, but I don't have a spec handy */
186117395Skan
187117395Skan	dev_attach(&kdc_eisa0); /*
188117395Skan				 * Hmm. Do I need to do this attach always
189117395Skan				 * in case I attach a 284x in an otherwise
190117395Skan				 * non-EISA machine?
191117395Skan				 */
192117395Skan	printf("Probing for devices on the EISA bus\n");
193117395Skan    }
194117395Skan
195117395Skan    if (!eisa_dev_list->next) {
196117395Skan	/*
197117395Skan	 * No devices.
198117395Skan	 * We may be able to remove the sentinal node in the non-EISA
199117395Skan	 * system case here depending on whether we had to do the
200117395Skan	 * dev_attach(&kdc_eisa0) up above.
201117395Skan	 */
202117395Skan	return;
203117395Skan    }
204117395Skan    /*
205117395Skan     * See what devices we recognize.
206117395Skan     */
207117395Skan    while((e_drv = *e_drvp++)) {
208117395Skan	(*e_drv->probe)();
209117395Skan    }
210132718Skan
211117395Skan    /*
212117395Skan     * Attach the devices we found in slot order
213117395Skan     */
214117395Skan    for (dev_node = eisa_dev_list->next; dev_node; dev_node = dev_node->next) {
215117395Skan	e_dev = &dev_node->dev;
216117395Skan	e_drv = e_dev->driver;
217117395Skan	if (e_drv) {
218117395Skan	    /*
219117395Skan	     * Determine the proper unit number for this device.
220117395Skan	     * Here we should look in the device table generated
221117395Skan	     * by config to see if this type of device is enabled
222117395Skan	     * either generically or for this particular address
223117395Skan	     * as well as determine if a reserved unit number should
224117395Skan	     * be used.  We should also ensure that the "next availible
225117395Skan	     * unit number" skips over "wired" unit numbers. This will
226117395Skan	     * be done after config is fixed or some other configuration
227117395Skan	     * method is chosen.
22818334Speter	     */
22918334Speter	    e_dev->unit = (*e_drv->unit)++;
23096263Sobrien	    if ((*e_drv->attach)(e_dev) < 0) {
23118334Speter		/* Clean up after the device?? */
23218334Speter	    }
23318334Speter	    e_dev->kdc->kdc_unit = e_dev->unit;
23418334Speter	}
23518334Speter	else {
23651885Sobrien	    /* Announce unattached device */
23790075Sobrien	    printf("%s%ld:%d <%s> unknown device\n",
23890075Sobrien		   eisa_dev_list->dev.driver->name, /* Mainboard */
23990075Sobrien		   eisa_dev_list->dev.unit,
24090075Sobrien		   e_dev->ioconf.slot,
24190075Sobrien		   e_dev->full_name);
24290075Sobrien	}
24390075Sobrien    }
24490075Sobrien}
24590075Sobrien
246117395Skanstruct eisa_device *
247117395Skaneisa_match_dev(e_dev, match_func)
248117395Skan	struct eisa_device *e_dev;
249117395Skan	char* (*match_func)(eisa_id_t);
250117395Skan{
25156173Sobrien    struct eisa_device_node *e_node = eisa_dev_list;
25256173Sobrien
25356173Sobrien    if(e_dev) {
25490075Sobrien	/* Start our search from the last successful match */
25556173Sobrien	 e_node = (struct eisa_device_node *)e_dev;
25656173Sobrien    }
25756173Sobrien
25856173Sobrien    /*
25956173Sobrien     * The first node in the list is the motherboard, so don't bother
26056173Sobrien     * to look at it.
26156173Sobrien     */
26256173Sobrien    while (e_node->next != NULL) {
26356173Sobrien	char *result;
26456173Sobrien	e_node = e_node->next;
26556173Sobrien	if (e_node->dev.driver) {
26656173Sobrien	     /* Already claimed */
26790075Sobrien	    continue;
26890075Sobrien	}
26990075Sobrien	result = (*match_func)(e_node->dev.id);
27090075Sobrien	if (result) {
27190075Sobrien	    free(e_node->dev.full_name, M_DEVBUF);
27290075Sobrien	    e_node->dev.full_name = result;
27390075Sobrien	    return (&(e_node->dev));
27490075Sobrien	}
27590075Sobrien    }
27690075Sobrien    return NULL;
27790075Sobrien}
27890075Sobrien
27990075Sobrien/* Interrupt and I/O space registration facitlities */
28051885Sobrienvoid
28151885Sobrieneisa_reg_start(e_dev)
28251885Sobrien	struct eisa_device *e_dev;
28351885Sobrien{
28451885Sobrien    /*
28590075Sobrien     * Announce the device.
28690075Sobrien     */
28790075Sobrien    printf("%s%ld: <%s>",
288117395Skan	   e_dev->driver->name,
289117395Skan	   e_dev->unit,
29090075Sobrien	   e_dev->full_name);
29190075Sobrien}
29290075Sobrien
29390075Sobrien/* Interrupt and I/O space registration facitlities */
29490075Sobrienvoid
29590075Sobrieneisa_reg_end(e_dev)
29690075Sobrien	struct eisa_device *e_dev;
29790075Sobrien{
29890075Sobrien    printf(" on %s%ld slot %d\n",
29990075Sobrien	   eisa_dev_list->dev.driver->name, /* Mainboard */
30090075Sobrien	   eisa_dev_list->dev.unit,
30190075Sobrien	   e_dev->ioconf.slot);
30290075Sobrien}
30390075Sobrien
30490075Sobrienint
30590075Sobrieneisa_add_intr(e_dev, irq)
30690075Sobrien	struct eisa_device *e_dev;
30790075Sobrien	int irq;
30890075Sobrien{
30990075Sobrien    e_dev->ioconf.irq |= 1ul << irq;
31090075Sobrien    return 0;
31190075Sobrien}
31290075Sobrien
31390075Sobrienint
31490075Sobrieneisa_reg_intr(e_dev, irq, func, arg, maskptr, shared)
31590075Sobrien	struct eisa_device *e_dev;
31690075Sobrien	int   irq;
31790075Sobrien	void  (*func)(void *);
31890075Sobrien	void  *arg;
31990075Sobrien	u_int *maskptr;
32090075Sobrien	int   shared;
32190075Sobrien{
32290075Sobrien    int result;
32390075Sobrien    int s;
32490075Sobrien
32590075Sobrien#if NOT_YET
32690075Sobrien    /*
32790075Sobrien     * Punt on conflict detection for the moment.
32890075Sobrien     * I want to develop a generic routine to do
32990075Sobrien     * this for all device types.
33090075Sobrien     */
33190075Sobrien    int checkthese = CC_IRQ;
33290075Sobrien    if(haveseen_dev(dev, checkthese))
33390075Sobrien        return 1;
33490075Sobrien#endif
33590075Sobrien    s = splhigh();
33690075Sobrien    /*
337117395Skan     * This should really go to a routine that can optionally
338117395Skan     * handle shared interrupts.
339117395Skan     */
340117395Skan    result = register_intr(irq,                /* isa irq      */
341117395Skan			   0,                  /* deviced??    */
342117395Skan			   0,                  /* flags?       */
343117395Skan			   (inthand2_t*) func, /* handler      */
344117395Skan			   maskptr,            /* mask pointer */
34590075Sobrien			   (int)arg);          /* handler arg  */
34690075Sobrien
34790075Sobrien    if (result) {
34890075Sobrien        printf ("eisa_reg_int: result=%d\n", result);
34996263Sobrien	splx(s);
35096263Sobrien        return (result);
35196263Sobrien    };
35296263Sobrien    update_intr_masks();
35396263Sobrien    splx(s);
35490075Sobrien
35590075Sobrien    e_dev->ioconf.irq |= 1ul << irq;
35690075Sobrien    printf(" irq %d", irq);
35790075Sobrien    return (0);
35890075Sobrien}
35990075Sobrien
36090075Sobrienint
36190075Sobrieneisa_release_intr(e_dev, irq, func)
36290075Sobrien	struct eisa_device *e_dev;
36390075Sobrien	int   irq;
36490075Sobrien	void  (*func)(void *);
36590075Sobrien{
36690075Sobrien    int result;
36790075Sobrien    int s;
36890075Sobrien
36990075Sobrien    if (!(e_dev->ioconf.irq & (1ul << irq))) {
37090075Sobrien	printf("%s%ld: Attempted to release an interrupt (%d) it doesn't own\n",
37190075Sobrien		e_dev->driver->name, e_dev->unit, irq);
37290075Sobrien	return (-1);
37390075Sobrien    }
37490075Sobrien
37590075Sobrien    s = splhigh();
37690075Sobrien    INTRDIS ((1ul<<irq));
37790075Sobrien
37890075Sobrien    result = unregister_intr (irq, (inthand2_t*)func);
37990075Sobrien
38090075Sobrien    if (result)
38190075Sobrien	printf ("eisa_release_intr: result=%d\n", result);
38290075Sobrien
38390075Sobrien    update_intr_masks();
38490075Sobrien
38590075Sobrien    splx(s);
386117395Skan    return (result);
387117395Skan}
388117395Skan
389117395Skanint
390117395Skaneisa_enable_intr(e_dev, irq)
39190075Sobrien	struct eisa_device *e_dev;
39290075Sobrien	int irq;
39390075Sobrien{
39490075Sobrien    int s;
39590075Sobrien
39690075Sobrien    if (!(e_dev->ioconf.irq & (1ul << irq))) {
39790075Sobrien	printf("%s%ld: Attempted to enable an interrupt (%d) it doesn't own\n",
39890075Sobrien		e_dev->driver->name, e_dev->unit, irq);
39990075Sobrien	return (-1);
40090075Sobrien    }
40190075Sobrien    s = splhigh();
40290075Sobrien    INTREN((1ul << irq));
40390075Sobrien    splx(s);
40490075Sobrien    return 0;
40590075Sobrien}
40690075Sobrien
40790075Sobrienint
40890075Sobrieneisa_add_iospace(e_dev, iobase, iosize)
40990075Sobrien	struct eisa_device *e_dev;
41090075Sobrien	u_long	iobase;
41190075Sobrien	int	iosize;
41290075Sobrien{
41390075Sobrien    /*
41490075Sobrien     * We should develop a scheme for storing the results of
41590075Sobrien     * multiple calls to this function.
416132718Skan     */
417132718Skan    e_dev->ioconf.iobase = iobase;
418132718Skan    e_dev->ioconf.iosize = iosize;
419132718Skan    return 0;
420132718Skan}
421132718Skan
422132718Skanint
423132718Skaneisa_reg_iospace(e_dev, iobase, iosize)
424132718Skan	struct eisa_device *e_dev;
425132718Skan	u_long	iobase;
426132718Skan	int	iosize;
427132718Skan{
428132718Skan    /*
429132718Skan     * We should develop a scheme for storing the results of
430132718Skan     * multiple calls to this function.
431132718Skan     */
432132718Skan#ifdef NOT_YET
433132718Skan    /*
434132718Skan     * Punt on conflict detection for the moment.
435132718Skan     * I want to develop a generic routine to do
43690075Sobrien     * this for all device types.
43790075Sobrien     */
43890075Sobrien    int checkthese = CC_IOADDR;
43990075Sobrien    if(haveseen_dev(dev, checkthese))
44090075Sobrien        return -1;
44190075Sobrien#endif
44290075Sobrien    e_dev->ioconf.iobase = iobase;
443117395Skan    e_dev->ioconf.iosize = iosize;
44490075Sobrien
44590075Sobrien    printf(" at 0x%lx-0x%lx", iobase, iobase + iosize - 1);
44690075Sobrien    return (0);
44790075Sobrien}
44890075Sobrien
44990075Sobrienint
45090075Sobrieneisa_registerdev(e_dev, driver, kdc_template)
45190075Sobrien	struct eisa_device *e_dev;
452117395Skan	struct eisa_driver *driver;
453117395Skan	struct kern_devconf *kdc_template;
454117395Skan{
455117395Skan    e_dev->driver = driver;	/* Driver now owns this device */
456117395Skan    e_dev->kdc = (struct kern_devconf *)malloc(sizeof(struct kern_devconf),
457117395Skan						   M_DEVBUF, M_NOWAIT);
458117395Skan    if (!e_dev->kdc) {
459117395Skan	printf("WARNING: eisa_registerdev unable to malloc! "
460117395Skan	       "Device kdc will not be registerd\n");
461117395Skan	return 1;
462117395Skan    }
463117395Skan    bcopy(kdc_template, e_dev->kdc, sizeof(*kdc_template));
464117395Skan    e_dev->kdc->kdc_description = e_dev->full_name;
465117395Skan    dev_attach(e_dev->kdc);
466117395Skan    return (0);
467117395Skan}
46890075Sobrien
46990075Sobrien/*
47090075Sobrien * Provide EISA-specific device information to user programs using the
47190075Sobrien * hw.devconf interface.
47290075Sobrien */
47390075Sobrienint
47490075Sobrieneisa_externalize(struct eisa_device *id, void *userp, size_t *maxlen)
47590075Sobrien{
47690075Sobrien    if(*maxlen < (sizeof *id)) {
47790075Sobrien	return ENOMEM;
47890075Sobrien    }
47990075Sobrien    *maxlen -= (sizeof *id);
48090075Sobrien    return (copyout(id, userp, sizeof *id));
48190075Sobrien}
48290075Sobrien
48390075Sobrien
48490075Sobrienint
48590075Sobrieneisa_generic_externalize(struct proc *p, struct kern_devconf *kdc,
48690075Sobrien			 void *userp, size_t l)
48790075Sobrien{
48890075Sobrien    return eisa_externalize(kdc->kdc_eisa, userp, &l);
48990075Sobrien}
49090075Sobrien