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