pnp.c revision 115543
150769Sdfr/* 250769Sdfr * Copyright (c) 1996, Sujal M. Patel 350769Sdfr * All rights reserved. 450769Sdfr * 550769Sdfr * Redistribution and use in source and binary forms, with or without 650769Sdfr * modification, are permitted provided that the following conditions 750769Sdfr * are met: 850769Sdfr * 1. Redistributions of source code must retain the above copyright 950769Sdfr * notice, this list of conditions and the following disclaimer. 1050769Sdfr * 2. Redistributions in binary form must reproduce the above copyright 1150769Sdfr * notice, this list of conditions and the following disclaimer in the 1250769Sdfr * documentation and/or other materials provided with the distribution. 1350769Sdfr * 1450769Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1550769Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1650769Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1750769Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1850769Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1950769Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2050769Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2150769Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2250769Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2350769Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2450769Sdfr * SUCH DAMAGE. 2550769Sdfr * 2650769Sdfr * $FreeBSD: head/sys/isa/pnp.c 115543 2003-05-31 20:21:53Z phk $ 2750769Sdfr * from: pnp.c,v 1.11 1999/05/06 22:11:19 peter Exp 2850769Sdfr */ 2950769Sdfr 3050769Sdfr#include <sys/param.h> 3150769Sdfr#include <sys/systm.h> 3250769Sdfr#include <sys/kernel.h> 3350769Sdfr#include <sys/module.h> 3450769Sdfr#include <sys/bus.h> 3550769Sdfr#include <sys/malloc.h> 3650769Sdfr#include <isa/isavar.h> 3750769Sdfr#include <isa/pnpreg.h> 3850769Sdfr#include <isa/pnpvar.h> 3965176Sdfr#include <machine/bus.h> 4050769Sdfr 4150769Sdfrtypedef struct _pnp_id { 4250769Sdfr u_int32_t vendor_id; 4350769Sdfr u_int32_t serial; 4450769Sdfr u_char checksum; 4550769Sdfr} pnp_id; 4650769Sdfr 4750769Sdfrstruct pnp_set_config_arg { 4850769Sdfr int csn; /* Card number to configure */ 4950769Sdfr int ldn; /* Logical device on card */ 5050769Sdfr}; 5150769Sdfr 5250769Sdfrstruct pnp_quirk { 5350769Sdfr u_int32_t vendor_id; /* Vendor of the card */ 5450769Sdfr u_int32_t logical_id; /* ID of the device with quirk */ 5550769Sdfr int type; 5650769Sdfr#define PNP_QUIRK_WRITE_REG 1 /* Need to write a pnp register */ 5762947Stanimura#define PNP_QUIRK_EXTRA_IO 2 /* Has extra io ports */ 5850769Sdfr int arg1; 5950769Sdfr int arg2; 6050769Sdfr}; 6150769Sdfr 6250769Sdfrstruct pnp_quirk pnp_quirks[] = { 6350769Sdfr /* 6450769Sdfr * The Gravis UltraSound needs register 0xf2 to be set to 0xff 6550769Sdfr * to enable power. 6650769Sdfr * XXX need to know the logical device id. 6750769Sdfr */ 6850769Sdfr { 0x0100561e /* GRV0001 */, 0, 6950769Sdfr PNP_QUIRK_WRITE_REG, 0xf2, 0xff }, 7062947Stanimura /* 7162947Stanimura * An emu8000 does not give us other than the first 7262947Stanimura * port. 7362947Stanimura */ 7462947Stanimura { 0x26008c0e /* SB16 */, 0x21008c0e, 7562947Stanimura PNP_QUIRK_EXTRA_IO, 0x400, 0x800 }, 7662947Stanimura { 0x42008c0e /* SB32(CTL0042) */, 0x21008c0e, 7762947Stanimura PNP_QUIRK_EXTRA_IO, 0x400, 0x800 }, 7862947Stanimura { 0x44008c0e /* SB32(CTL0044) */, 0x21008c0e, 7962947Stanimura PNP_QUIRK_EXTRA_IO, 0x400, 0x800 }, 8062947Stanimura { 0x49008c0e /* SB32(CTL0049) */, 0x21008c0e, 8162947Stanimura PNP_QUIRK_EXTRA_IO, 0x400, 0x800 }, 8262947Stanimura { 0xf1008c0e /* SB32(CTL00f1) */, 0x21008c0e, 8362947Stanimura PNP_QUIRK_EXTRA_IO, 0x400, 0x800 }, 8462947Stanimura { 0xc1008c0e /* SB64(CTL00c1) */, 0x22008c0e, 8562947Stanimura PNP_QUIRK_EXTRA_IO, 0x400, 0x800 }, 8690234Stanimura { 0xc5008c0e /* SB64(CTL00c5) */, 0x22008c0e, 8790234Stanimura PNP_QUIRK_EXTRA_IO, 0x400, 0x800 }, 8862947Stanimura { 0xe4008c0e /* SB64(CTL00e4) */, 0x22008c0e, 8962947Stanimura PNP_QUIRK_EXTRA_IO, 0x400, 0x800 }, 9050769Sdfr 9150769Sdfr { 0 } 9250769Sdfr}; 9350769Sdfr 94104142Snyan#ifdef PC98 95104142Snyan/* Some NEC PnP cards have 9 bytes serial code. */ 96104142Snyanstatic pnp_id necids[] = { 97104142Snyan {0x4180a3b8, 0xffffffff, 0x00}, /* PC-9801CB-B04 (NEC8041) */ 98104142Snyan {0x5181a3b8, 0xffffffff, 0x46}, /* PC-9821CB2-B04(NEC8151) */ 99104142Snyan {0x5182a3b8, 0xffffffff, 0xb8}, /* PC-9801-XX (NEC8251) */ 100104142Snyan {0x9181a3b8, 0xffffffff, 0x00}, /* PC-9801-120 (NEC8191) */ 101104142Snyan {0, 0, 0} 102104142Snyan}; 103104142Snyan#endif 104104142Snyan 10550769Sdfr#if 0 10650769Sdfr/* 10750769Sdfr * these entries are initialized using the autoconfig menu 10850769Sdfr * The struct is invalid (and must be initialized) if the first 10950769Sdfr * CSN is zero. The init code fills invalid entries with CSN 255 11050769Sdfr * which is not a supported value. 11150769Sdfr */ 11250769Sdfr 11350769Sdfrstruct pnp_cinfo pnp_ldn_overrides[MAX_PNP_LDN] = { 11450769Sdfr { 0 } 11550769Sdfr}; 11650769Sdfr#endif 11750769Sdfr 11850769Sdfr/* The READ_DATA port that we are using currently */ 11950769Sdfrstatic int pnp_rd_port; 12050769Sdfr 12150769Sdfrstatic void pnp_send_initiation_key(void); 12250769Sdfrstatic int pnp_get_serial(pnp_id *p); 12350769Sdfrstatic int pnp_isolation_protocol(device_t parent); 12450769Sdfr 12552241Sdfrchar * 12652241Sdfrpnp_eisaformat(u_int32_t id) 12752241Sdfr{ 12852241Sdfr u_int8_t *data = (u_int8_t *) &id; 12952241Sdfr static char idbuf[8]; 13052241Sdfr const char hextoascii[] = "0123456789abcdef"; 13152241Sdfr 13252241Sdfr idbuf[0] = '@' + ((data[0] & 0x7c) >> 2); 13352241Sdfr idbuf[1] = '@' + (((data[0] & 0x3) << 3) + ((data[1] & 0xe0) >> 5)); 13452241Sdfr idbuf[2] = '@' + (data[1] & 0x1f); 13552241Sdfr idbuf[3] = hextoascii[(data[2] >> 4)]; 13652241Sdfr idbuf[4] = hextoascii[(data[2] & 0xf)]; 13752241Sdfr idbuf[5] = hextoascii[(data[3] >> 4)]; 13852241Sdfr idbuf[6] = hextoascii[(data[3] & 0xf)]; 13952241Sdfr idbuf[7] = 0; 14052241Sdfr return(idbuf); 14152241Sdfr} 14252241Sdfr 14350769Sdfrstatic void 14450769Sdfrpnp_write(int d, u_char r) 14550769Sdfr{ 14650769Sdfr outb (_PNP_ADDRESS, d); 14750769Sdfr outb (_PNP_WRITE_DATA, r); 14850769Sdfr} 14950769Sdfr 15050769Sdfr#if 0 15150769Sdfr 15250769Sdfrstatic u_char 15350769Sdfrpnp_read(int d) 15450769Sdfr{ 15550769Sdfr outb (_PNP_ADDRESS, d); 15650769Sdfr return (inb(3 | (pnp_rd_port <<2))); 15750769Sdfr} 15850769Sdfr 15950769Sdfr#endif 16050769Sdfr 16150769Sdfr/* 16250769Sdfr * Send Initiation LFSR as described in "Plug and Play ISA Specification", 16350769Sdfr * Intel May 94. 16450769Sdfr */ 16550769Sdfrstatic void 16650769Sdfrpnp_send_initiation_key() 16750769Sdfr{ 16850769Sdfr int cur, i; 16950769Sdfr 17050769Sdfr /* Reset the LSFR */ 17150769Sdfr outb(_PNP_ADDRESS, 0); 17250769Sdfr outb(_PNP_ADDRESS, 0); /* yes, we do need it twice! */ 17350769Sdfr 17450769Sdfr cur = 0x6a; 17550769Sdfr outb(_PNP_ADDRESS, cur); 17650769Sdfr 17750769Sdfr for (i = 1; i < 32; i++) { 17850769Sdfr cur = (cur >> 1) | (((cur ^ (cur >> 1)) << 7) & 0xff); 17950769Sdfr outb(_PNP_ADDRESS, cur); 18050769Sdfr } 18150769Sdfr} 18250769Sdfr 18350769Sdfr 18450769Sdfr/* 18550769Sdfr * Get the device's serial number. Returns 1 if the serial is valid. 18650769Sdfr */ 18750769Sdfrstatic int 18850769Sdfrpnp_get_serial(pnp_id *p) 18950769Sdfr{ 19050769Sdfr int i, bit, valid = 0, sum = 0x6a; 19150769Sdfr u_char *data = (u_char *)p; 19250769Sdfr 19350769Sdfr bzero(data, sizeof(char) * 9); 19450769Sdfr outb(_PNP_ADDRESS, PNP_SERIAL_ISOLATION); 19550769Sdfr for (i = 0; i < 72; i++) { 19650769Sdfr bit = inb((pnp_rd_port << 2) | 0x3) == 0x55; 19750769Sdfr DELAY(250); /* Delay 250 usec */ 19850769Sdfr 19950769Sdfr /* Can't Short Circuit the next evaluation, so 'and' is last */ 20050769Sdfr bit = (inb((pnp_rd_port << 2) | 0x3) == 0xaa) && bit; 20150769Sdfr DELAY(250); /* Delay 250 usec */ 20250769Sdfr 20350769Sdfr valid = valid || bit; 20450769Sdfr 20550769Sdfr if (i < 64) 20650769Sdfr sum = (sum >> 1) | 20750769Sdfr (((sum ^ (sum >> 1) ^ bit) << 7) & 0xff); 20850769Sdfr 20950769Sdfr data[i / 8] = (data[i / 8] >> 1) | (bit ? 0x80 : 0); 21050769Sdfr } 21150769Sdfr 21250769Sdfr valid = valid && (data[8] == sum); 21350769Sdfr 21450769Sdfr return valid; 21550769Sdfr} 21650769Sdfr 21750769Sdfr/* 21850769Sdfr * Fill's the buffer with resource info from the device. 21952059Sdfr * Returns the number of characters read. 22050769Sdfr */ 22150769Sdfrstatic int 22250769Sdfrpnp_get_resource_info(u_char *buffer, int len) 22350769Sdfr{ 22452059Sdfr int i, j, count; 22550769Sdfr u_char temp; 22650769Sdfr 22752059Sdfr count = 0; 22850769Sdfr for (i = 0; i < len; i++) { 22950769Sdfr outb(_PNP_ADDRESS, PNP_STATUS); 23050769Sdfr for (j = 0; j < 100; j++) { 23150769Sdfr if ((inb((pnp_rd_port << 2) | 0x3)) & 0x1) 23250769Sdfr break; 23350769Sdfr DELAY(1); 23450769Sdfr } 23550769Sdfr if (j == 100) { 23650769Sdfr printf("PnP device failed to report resource data\n"); 23752059Sdfr return count; 23850769Sdfr } 23950769Sdfr outb(_PNP_ADDRESS, PNP_RESOURCE_DATA); 24050769Sdfr temp = inb((pnp_rd_port << 2) | 0x3); 24150769Sdfr if (buffer != NULL) 24250769Sdfr buffer[i] = temp; 24352059Sdfr count++; 24450769Sdfr } 24552059Sdfr return count; 24650769Sdfr} 24750769Sdfr 24850769Sdfr#if 0 24950769Sdfr/* 25050769Sdfr * write_pnp_parms initializes a logical device with the parms 25150769Sdfr * in d, and then activates the board if the last parameter is 1. 25250769Sdfr */ 25350769Sdfr 25450769Sdfrstatic int 25550769Sdfrwrite_pnp_parms(struct pnp_cinfo *d, pnp_id *p, int ldn) 25650769Sdfr{ 25750769Sdfr int i, empty = -1 ; 25850769Sdfr 25950769Sdfr pnp_write (SET_LDN, ldn ); 26050769Sdfr i = pnp_read(SET_LDN) ; 26150769Sdfr if (i != ldn) { 26250769Sdfr printf("Warning: LDN %d does not exist\n", ldn); 26350769Sdfr } 26450769Sdfr for (i = 0; i < 8; i++) { 26550769Sdfr pnp_write(IO_CONFIG_BASE + i * 2, d->ic_port[i] >> 8 ); 26650769Sdfr pnp_write(IO_CONFIG_BASE + i * 2 + 1, d->ic_port[i] & 0xff ); 26750769Sdfr } 26850769Sdfr for (i = 0; i < 4; i++) { 26950769Sdfr pnp_write(MEM_CONFIG + i*8, (d->ic_mem[i].base >> 16) & 0xff ); 27050769Sdfr pnp_write(MEM_CONFIG + i*8+1, (d->ic_mem[i].base >> 8) & 0xff ); 27150769Sdfr pnp_write(MEM_CONFIG + i*8+2, d->ic_mem[i].control & 0xff ); 27250769Sdfr pnp_write(MEM_CONFIG + i*8+3, (d->ic_mem[i].range >> 16) & 0xff ); 27350769Sdfr pnp_write(MEM_CONFIG + i*8+4, (d->ic_mem[i].range >> 8) & 0xff ); 27450769Sdfr } 27550769Sdfr for (i = 0; i < 2; i++) { 27650769Sdfr pnp_write(IRQ_CONFIG + i*2 , d->irq[i] ); 27750769Sdfr pnp_write(IRQ_CONFIG + i*2 + 1, d->irq_type[i] ); 27850769Sdfr pnp_write(DRQ_CONFIG + i, d->drq[i] ); 27950769Sdfr } 28050769Sdfr /* 28150769Sdfr * store parameters read into the current kernel 28250769Sdfr * so manual editing next time is easier 28350769Sdfr */ 28450769Sdfr for (i = 0 ; i < MAX_PNP_LDN; i++) { 28550769Sdfr if (pnp_ldn_overrides[i].csn == d->csn && 28650769Sdfr pnp_ldn_overrides[i].ldn == ldn) { 28750769Sdfr d->flags = pnp_ldn_overrides[i].flags ; 28850769Sdfr pnp_ldn_overrides[i] = *d ; 28950769Sdfr break ; 29050769Sdfr } else if (pnp_ldn_overrides[i].csn < 1 || 29150769Sdfr pnp_ldn_overrides[i].csn == 255) 29250769Sdfr empty = i ; 29350769Sdfr } 29450769Sdfr if (i== MAX_PNP_LDN && empty != -1) 29550769Sdfr pnp_ldn_overrides[empty] = *d; 29650769Sdfr 29750769Sdfr /* 29850769Sdfr * Here should really perform the range check, and 29950769Sdfr * return a failure if not successful. 30050769Sdfr */ 30150769Sdfr pnp_write (IO_RANGE_CHECK, 0); 30250769Sdfr DELAY(1000); /* XXX is it really necessary ? */ 30350769Sdfr pnp_write (ACTIVATE, d->enable ? 1 : 0); 30450769Sdfr DELAY(1000); /* XXX is it really necessary ? */ 30550769Sdfr return 1 ; 30650769Sdfr} 30750769Sdfr#endif 30850769Sdfr 30950769Sdfr/* 31050769Sdfr * This function is called after the bus has assigned resource 31150769Sdfr * locations for a logical device. 31250769Sdfr */ 31350769Sdfrstatic void 31450769Sdfrpnp_set_config(void *arg, struct isa_config *config, int enable) 31550769Sdfr{ 31650769Sdfr int csn = ((struct pnp_set_config_arg *) arg)->csn; 31750769Sdfr int ldn = ((struct pnp_set_config_arg *) arg)->ldn; 31850769Sdfr int i; 31950769Sdfr 32050769Sdfr /* 32150769Sdfr * First put all cards into Sleep state with the initiation 32250769Sdfr * key, then put our card into Config state. 32350769Sdfr */ 32450769Sdfr pnp_send_initiation_key(); 32550769Sdfr pnp_write(PNP_WAKE, csn); 32650769Sdfr 32750769Sdfr /* 32850769Sdfr * Select our logical device so that we can program it. 32950769Sdfr */ 33050769Sdfr pnp_write(PNP_SET_LDN, ldn); 33150769Sdfr 33250769Sdfr /* 33366840Smsmith * Constrain the number of resources we will try to program 33466840Smsmith */ 33566840Smsmith if (config->ic_nmem > ISA_PNP_NMEM) { 33666840Smsmith printf("too many ISA memory ranges (%d > %d)\n", config->ic_nmem, ISA_PNP_NMEM); 33766840Smsmith config->ic_nmem = ISA_PNP_NMEM; 33866840Smsmith } 33966840Smsmith if (config->ic_nport > ISA_PNP_NPORT) { 34066840Smsmith printf("too many ISA I/O ranges (%d > %d)\n", config->ic_nport, ISA_PNP_NPORT); 34166840Smsmith config->ic_nport = ISA_PNP_NPORT; 34266840Smsmith } 34366840Smsmith if (config->ic_nirq > ISA_PNP_NIRQ) { 34466840Smsmith printf("too many ISA IRQs (%d > %d)\n", config->ic_nirq, ISA_PNP_NIRQ); 34566840Smsmith config->ic_nirq = ISA_PNP_NIRQ; 34666840Smsmith } 34766840Smsmith if (config->ic_ndrq > ISA_PNP_NDRQ) { 34866840Smsmith printf("too many ISA DRQs (%d > %d)\n", config->ic_ndrq, ISA_PNP_NDRQ); 34966840Smsmith config->ic_ndrq = ISA_PNP_NDRQ; 35066840Smsmith } 35166840Smsmith 35266840Smsmith /* 35350769Sdfr * Now program the resources. 35450769Sdfr */ 35550769Sdfr for (i = 0; i < config->ic_nmem; i++) { 35683051Syokota u_int32_t start; 35783051Syokota u_int32_t size; 35883051Syokota 35983051Syokota /* XXX: should handle memory control register, 32 bit memory */ 36083051Syokota if (config->ic_mem[i].ir_size == 0) { 36183051Syokota pnp_write(PNP_MEM_BASE_HIGH(i), 0); 36283051Syokota pnp_write(PNP_MEM_BASE_LOW(i), 0); 36383051Syokota pnp_write(PNP_MEM_RANGE_HIGH(i), 0); 36483051Syokota pnp_write(PNP_MEM_RANGE_LOW(i), 0); 36583051Syokota } else { 36683051Syokota start = config->ic_mem[i].ir_start; 36783051Syokota size = config->ic_mem[i].ir_size; 36883051Syokota if (start & 0xff) 36983051Syokota panic("pnp_set_config: bogus memory assignment"); 37083051Syokota pnp_write(PNP_MEM_BASE_HIGH(i), (start >> 16) & 0xff); 37183051Syokota pnp_write(PNP_MEM_BASE_LOW(i), (start >> 8) & 0xff); 37283051Syokota pnp_write(PNP_MEM_RANGE_HIGH(i), (size >> 16) & 0xff); 37383051Syokota pnp_write(PNP_MEM_RANGE_LOW(i), (size >> 8) & 0xff); 37483051Syokota } 37550769Sdfr } 37666840Smsmith for (; i < ISA_PNP_NMEM; i++) { 37750769Sdfr pnp_write(PNP_MEM_BASE_HIGH(i), 0); 37850769Sdfr pnp_write(PNP_MEM_BASE_LOW(i), 0); 37950769Sdfr pnp_write(PNP_MEM_RANGE_HIGH(i), 0); 38050769Sdfr pnp_write(PNP_MEM_RANGE_LOW(i), 0); 38150769Sdfr } 38250769Sdfr 38350769Sdfr for (i = 0; i < config->ic_nport; i++) { 38483051Syokota u_int32_t start; 38583051Syokota 38683051Syokota if (config->ic_port[i].ir_size == 0) { 38783051Syokota pnp_write(PNP_IO_BASE_HIGH(i), 0); 38883051Syokota pnp_write(PNP_IO_BASE_LOW(i), 0); 38983051Syokota } else { 39083051Syokota start = config->ic_port[i].ir_start; 39183051Syokota pnp_write(PNP_IO_BASE_HIGH(i), (start >> 8) & 0xff); 39283051Syokota pnp_write(PNP_IO_BASE_LOW(i), (start >> 0) & 0xff); 39383051Syokota } 39450769Sdfr } 39566840Smsmith for (; i < ISA_PNP_NPORT; i++) { 39650769Sdfr pnp_write(PNP_IO_BASE_HIGH(i), 0); 39750769Sdfr pnp_write(PNP_IO_BASE_LOW(i), 0); 39850769Sdfr } 39950769Sdfr 40050769Sdfr for (i = 0; i < config->ic_nirq; i++) { 40183051Syokota int irq; 40283051Syokota 40383051Syokota /* XXX: interrupt type */ 40483051Syokota if (config->ic_irqmask[i] == 0) { 40583051Syokota pnp_write(PNP_IRQ_LEVEL(i), 0); 40683051Syokota pnp_write(PNP_IRQ_TYPE(i), 2); 40783051Syokota } else { 40883051Syokota irq = ffs(config->ic_irqmask[i]) - 1; 40983051Syokota pnp_write(PNP_IRQ_LEVEL(i), irq); 41083051Syokota pnp_write(PNP_IRQ_TYPE(i), 2); /* XXX */ 41183051Syokota } 41250769Sdfr } 41366840Smsmith for (; i < ISA_PNP_NIRQ; i++) { 41450769Sdfr /* 41550769Sdfr * IRQ 0 is not a valid interrupt selection and 41650769Sdfr * represents no interrupt selection. 41750769Sdfr */ 41850769Sdfr pnp_write(PNP_IRQ_LEVEL(i), 0); 41983051Syokota pnp_write(PNP_IRQ_TYPE(i), 2); 42050769Sdfr } 42150769Sdfr 42250769Sdfr for (i = 0; i < config->ic_ndrq; i++) { 42383051Syokota int drq; 42483051Syokota 42583051Syokota if (config->ic_drqmask[i] == 0) { 42683051Syokota pnp_write(PNP_DMA_CHANNEL(i), 4); 42783051Syokota } else { 42883051Syokota drq = ffs(config->ic_drqmask[i]) - 1; 42983051Syokota pnp_write(PNP_DMA_CHANNEL(i), drq); 43083051Syokota } 43150769Sdfr } 43266840Smsmith for (; i < ISA_PNP_NDRQ; i++) { 43350769Sdfr /* 43450769Sdfr * DMA channel 4, the cascade channel is used to 43550769Sdfr * indicate no DMA channel is active. 43650769Sdfr */ 43750769Sdfr pnp_write(PNP_DMA_CHANNEL(i), 4); 43850769Sdfr } 43950769Sdfr 44050769Sdfr pnp_write(PNP_ACTIVATE, enable ? 1 : 0); 44150769Sdfr 44250769Sdfr /* 44350769Sdfr * Wake everyone up again, we are finished. 44450769Sdfr */ 44550769Sdfr pnp_write(PNP_CONFIG_CONTROL, PNP_CONFIG_CONTROL_WAIT_FOR_KEY); 44650769Sdfr} 44750769Sdfr 44850769Sdfr/* 44950769Sdfr * Process quirks for a logical device.. The card must be in Config state. 45050769Sdfr */ 45162947Stanimuravoid 45262947Stanimurapnp_check_quirks(u_int32_t vendor_id, u_int32_t logical_id, int ldn, struct isa_config *config) 45350769Sdfr{ 45450769Sdfr struct pnp_quirk *qp; 45550769Sdfr 45650769Sdfr for (qp = &pnp_quirks[0]; qp->vendor_id; qp++) { 45750769Sdfr if (qp->vendor_id == vendor_id 45850769Sdfr && (qp->logical_id == 0 45950769Sdfr || qp->logical_id == logical_id)) { 46050769Sdfr switch (qp->type) { 46150769Sdfr case PNP_QUIRK_WRITE_REG: 46250769Sdfr pnp_write(PNP_SET_LDN, ldn); 46350769Sdfr pnp_write(qp->arg1, qp->arg2); 46450769Sdfr break; 46562947Stanimura case PNP_QUIRK_EXTRA_IO: 46662947Stanimura if (config == NULL) 46762947Stanimura break; 46862947Stanimura if (qp->arg1 != 0) { 46962947Stanimura config->ic_nport++; 47062947Stanimura config->ic_port[config->ic_nport - 1] = config->ic_port[0]; 47162947Stanimura config->ic_port[config->ic_nport - 1].ir_start += qp->arg1; 47262947Stanimura config->ic_port[config->ic_nport - 1].ir_end += qp->arg1; 47362947Stanimura } 47462947Stanimura if (qp->arg2 != 0) { 47562947Stanimura config->ic_nport++; 47662947Stanimura config->ic_port[config->ic_nport - 1] = config->ic_port[0]; 47762947Stanimura config->ic_port[config->ic_nport - 1].ir_start += qp->arg2; 47862947Stanimura config->ic_port[config->ic_nport - 1].ir_end += qp->arg2; 47962947Stanimura } 48062947Stanimura break; 48150769Sdfr } 48250769Sdfr } 48350769Sdfr } 48450769Sdfr} 48550769Sdfr 48650769Sdfr/* 48750769Sdfr * Scan Resource Data for Logical Devices. 48850769Sdfr * 48950769Sdfr * This function exits as soon as it gets an error reading *ANY* 49052059Sdfr * Resource Data or it reaches the end of Resource Data. In the first 49150769Sdfr * case the return value will be TRUE, FALSE otherwise. 49250769Sdfr */ 49350769Sdfrstatic int 49452059Sdfrpnp_create_devices(device_t parent, pnp_id *p, int csn, 49552059Sdfr u_char *resources, int len) 49650769Sdfr{ 49752059Sdfr u_char tag, *resp, *resinfo, *startres = 0; 49852059Sdfr int large_len, scanning = len, retval = FALSE; 49950769Sdfr u_int32_t logical_id; 50050769Sdfr device_t dev = 0; 50150769Sdfr int ldn = 0; 50250769Sdfr struct pnp_set_config_arg *csnldn; 50352059Sdfr char buf[100]; 50450769Sdfr char *desc = 0; 50550769Sdfr 50652059Sdfr resp = resources; 50752059Sdfr while (scanning > 0) { 50852059Sdfr tag = *resp++; 50952059Sdfr scanning--; 51052059Sdfr if (PNP_RES_TYPE(tag) != 0) { 51152059Sdfr /* Large resource */ 51252059Sdfr if (scanning < 2) { 51350769Sdfr scanning = 0; 51450769Sdfr continue; 51550769Sdfr } 51652059Sdfr large_len = resp[0] + (resp[1] << 8); 51752059Sdfr resp += 2; 51850769Sdfr 51952059Sdfr if (scanning < large_len) { 52050769Sdfr scanning = 0; 52150769Sdfr continue; 52250769Sdfr } 52352059Sdfr resinfo = resp; 52452059Sdfr resp += large_len; 52552059Sdfr scanning -= large_len; 52650769Sdfr 52750769Sdfr if (PNP_LRES_NUM(tag) == PNP_TAG_ID_ANSI) { 52883504Syokota if (dev) { 52983504Syokota /* 53083504Syokota * This is an optional device 53183504Syokota * indentifier string. Skipt it 53283504Syokota * for now. 53383504Syokota */ 53483504Syokota continue; 53583504Syokota } 53683504Syokota /* else mandately card identifier string */ 53752059Sdfr if (large_len > sizeof(buf) - 1) 53852059Sdfr large_len = sizeof(buf) - 1; 53952059Sdfr bcopy(resinfo, buf, large_len); 54052059Sdfr 54150769Sdfr /* 54252059Sdfr * Trim trailing spaces. 54350769Sdfr */ 54452059Sdfr while (buf[large_len-1] == ' ') 54552059Sdfr large_len--; 54652059Sdfr buf[large_len] = '\0'; 54752059Sdfr desc = buf; 54850769Sdfr continue; 54950769Sdfr } 55050769Sdfr 55152059Sdfr continue; 55252059Sdfr } 55352059Sdfr 55452059Sdfr /* Small resource */ 55552059Sdfr if (scanning < PNP_SRES_LEN(tag)) { 55652059Sdfr scanning = 0; 55752059Sdfr continue; 55852059Sdfr } 55952059Sdfr resinfo = resp; 56052059Sdfr resp += PNP_SRES_LEN(tag); 56152059Sdfr scanning -= PNP_SRES_LEN(tag);; 56252059Sdfr 56352059Sdfr switch (PNP_SRES_NUM(tag)) { 56452059Sdfr case PNP_TAG_LOGICAL_DEVICE: 56552059Sdfr /* 56652059Sdfr * Parse the resources for the previous 56752059Sdfr * logical device (if any). 56852059Sdfr */ 56952059Sdfr if (startres) { 57052059Sdfr pnp_parse_resources(dev, startres, 57162947Stanimura resinfo - startres - 1, 57283051Syokota ldn); 57352059Sdfr dev = 0; 57452059Sdfr startres = 0; 57550769Sdfr } 57650769Sdfr 57752059Sdfr /* 57852059Sdfr * A new logical device. Scan for end of 57952059Sdfr * resources. 58052059Sdfr */ 58152059Sdfr bcopy(resinfo, &logical_id, 4); 58262947Stanimura pnp_check_quirks(p->vendor_id, logical_id, ldn, NULL); 58352059Sdfr dev = BUS_ADD_CHILD(parent, ISA_ORDER_PNP, NULL, -1); 58452059Sdfr if (desc) 58552059Sdfr device_set_desc_copy(dev, desc); 58683504Syokota else 58783504Syokota device_set_desc_copy(dev, 58883504Syokota pnp_eisaformat(logical_id)); 58952059Sdfr isa_set_vendorid(dev, p->vendor_id); 59052059Sdfr isa_set_serial(dev, p->serial); 59152059Sdfr isa_set_logicalid(dev, logical_id); 59283051Syokota isa_set_configattr(dev, 59383051Syokota ISACFGATTR_CANDISABLE | 59483051Syokota ISACFGATTR_DYNAMIC); 59552059Sdfr csnldn = malloc(sizeof *csnldn, M_DEVBUF, M_NOWAIT); 59652059Sdfr if (!csnldn) { 59752059Sdfr device_printf(parent, 59852059Sdfr "out of memory\n"); 59950769Sdfr scanning = 0; 60052059Sdfr break; 60150769Sdfr } 60252059Sdfr csnldn->csn = csn; 60352059Sdfr csnldn->ldn = ldn; 60452059Sdfr ISA_SET_CONFIG_CALLBACK(parent, dev, 60552059Sdfr pnp_set_config, csnldn); 60652059Sdfr ldn++; 60752059Sdfr startres = resp; 60852059Sdfr break; 60952059Sdfr 61052059Sdfr case PNP_TAG_END: 61152059Sdfr if (!startres) { 61250769Sdfr device_printf(parent, 61352059Sdfr "malformed resources\n"); 61450769Sdfr scanning = 0; 61550769Sdfr break; 61650769Sdfr } 61752059Sdfr pnp_parse_resources(dev, startres, 61883051Syokota resinfo - startres - 1, ldn); 61952059Sdfr dev = 0; 62052059Sdfr startres = 0; 62152059Sdfr scanning = 0; 62252059Sdfr break; 62350769Sdfr 62452059Sdfr default: 62552059Sdfr /* Skip this resource */ 62652059Sdfr break; 62750769Sdfr } 62850769Sdfr } 62950769Sdfr 63050769Sdfr return retval; 63150769Sdfr} 63250769Sdfr 63350769Sdfr/* 63452059Sdfr * Read 'amount' bytes of resources from the card, allocating memory 63552059Sdfr * as needed. If a buffer is already available, it should be passed in 63652059Sdfr * '*resourcesp' and its length in '*spacep'. The number of resource 63752059Sdfr * bytes already in the buffer should be passed in '*lenp'. The memory 63852059Sdfr * allocated will be returned in '*resourcesp' with its size and the 63952059Sdfr * number of bytes of resources in '*spacep' and '*lenp' respectively. 640105226Sphk * 641105226Sphk * XXX: Multiple problems here, we forget to free() stuff in one 642105226Sphk * XXX: error return, and in another case we free (*resourcesp) but 643105226Sphk * XXX: don't tell the caller. 64452059Sdfr */ 64552059Sdfrstatic int 64652059Sdfrpnp_read_bytes(int amount, u_char **resourcesp, int *spacep, int *lenp) 64752059Sdfr{ 64852059Sdfr u_char *resources = *resourcesp; 64952059Sdfr u_char *newres; 65052059Sdfr int space = *spacep; 65152059Sdfr int len = *lenp; 65252059Sdfr 65352059Sdfr if (space == 0) { 65452059Sdfr space = 1024; 65552059Sdfr resources = malloc(space, M_TEMP, M_NOWAIT); 65652059Sdfr if (!resources) 65752059Sdfr return ENOMEM; 65852059Sdfr } 65952059Sdfr 66052059Sdfr if (len + amount > space) { 66152059Sdfr int extra = 1024; 66252059Sdfr while (len + amount > space + extra) 66352059Sdfr extra += 1024; 66452059Sdfr newres = malloc(space + extra, M_TEMP, M_NOWAIT); 665115543Sphk if (!newres) { 666115543Sphk /* XXX: free resources */ 66752059Sdfr return ENOMEM; 668115543Sphk } 66952059Sdfr bcopy(resources, newres, len); 67052059Sdfr free(resources, M_TEMP); 67152059Sdfr resources = newres; 67252059Sdfr space += extra; 67352059Sdfr } 67452059Sdfr 67552059Sdfr if (pnp_get_resource_info(resources + len, amount) != amount) 67652059Sdfr return EINVAL; 67752059Sdfr len += amount; 67852059Sdfr 67952059Sdfr *resourcesp = resources; 68052059Sdfr *spacep = space; 68152059Sdfr *lenp = len; 68252059Sdfr 68352059Sdfr return 0; 68452059Sdfr} 68552059Sdfr 68652059Sdfr/* 68752059Sdfr * Read all resources from the card, allocating memory as needed. If a 68852059Sdfr * buffer is already available, it should be passed in '*resourcesp' 68952059Sdfr * and its length in '*spacep'. The memory allocated will be returned 69052059Sdfr * in '*resourcesp' with its size and the number of bytes of resources 69152059Sdfr * in '*spacep' and '*lenp' respectively. 69252059Sdfr */ 69352059Sdfrstatic int 69452059Sdfrpnp_read_resources(u_char **resourcesp, int *spacep, int *lenp) 69552059Sdfr{ 69652059Sdfr u_char *resources = *resourcesp; 69752059Sdfr int space = *spacep; 69852059Sdfr int len = 0; 69952059Sdfr int error, done; 70052059Sdfr u_char tag; 70152059Sdfr 70252059Sdfr error = 0; 70352059Sdfr done = 0; 70452059Sdfr while (!done) { 70552059Sdfr error = pnp_read_bytes(1, &resources, &space, &len); 70652059Sdfr if (error) 70752059Sdfr goto out; 70852059Sdfr tag = resources[len-1]; 70952059Sdfr if (PNP_RES_TYPE(tag) == 0) { 71052059Sdfr /* 71152059Sdfr * Small resource, read contents. 71252059Sdfr */ 71352059Sdfr error = pnp_read_bytes(PNP_SRES_LEN(tag), 71452059Sdfr &resources, &space, &len); 71552059Sdfr if (error) 71652059Sdfr goto out; 71752059Sdfr if (PNP_SRES_NUM(tag) == PNP_TAG_END) 71852059Sdfr done = 1; 71952059Sdfr } else { 72052059Sdfr /* 72152059Sdfr * Large resource, read length and contents. 72252059Sdfr */ 72352059Sdfr error = pnp_read_bytes(2, &resources, &space, &len); 72452059Sdfr if (error) 72552059Sdfr goto out; 72652059Sdfr error = pnp_read_bytes(resources[len-2] 72752059Sdfr + (resources[len-1] << 8), 72852059Sdfr &resources, &space, &len); 72952059Sdfr if (error) 73052059Sdfr goto out; 73152059Sdfr } 73252059Sdfr } 73352059Sdfr 73452059Sdfr out: 73552059Sdfr *resourcesp = resources; 73652059Sdfr *spacep = space; 73752059Sdfr *lenp = len; 73852059Sdfr return error; 73952059Sdfr} 74052059Sdfr 74152059Sdfr/* 74250769Sdfr * Run the isolation protocol. Use pnp_rd_port as the READ_DATA port 74350769Sdfr * value (caller should try multiple READ_DATA locations before giving 74450769Sdfr * up). Upon exiting, all cards are aware that they should use 74550769Sdfr * pnp_rd_port as the READ_DATA port. 74650769Sdfr * 74750769Sdfr * In the first pass, a csn is assigned to each board and pnp_id's 74850769Sdfr * are saved to an array, pnp_devices. In the second pass, each 74950769Sdfr * card is woken up and the device configuration is called. 75050769Sdfr */ 75150769Sdfrstatic int 75250769Sdfrpnp_isolation_protocol(device_t parent) 75350769Sdfr{ 75450769Sdfr int csn; 75550769Sdfr pnp_id id; 75652059Sdfr int found = 0, len; 75752059Sdfr u_char *resources = 0; 75852059Sdfr int space = 0; 75952059Sdfr int error; 760104142Snyan#ifdef PC98 761104142Snyan int n, necpnp; 762104142Snyan u_char buffer[10]; 763104142Snyan#endif 76450769Sdfr 76550769Sdfr /* 76650769Sdfr * Put all cards into the Sleep state so that we can clear 76750769Sdfr * their CSNs. 76850769Sdfr */ 76950769Sdfr pnp_send_initiation_key(); 77050769Sdfr 77150769Sdfr /* 77250769Sdfr * Clear the CSN for all cards. 77350769Sdfr */ 77450769Sdfr pnp_write(PNP_CONFIG_CONTROL, PNP_CONFIG_CONTROL_RESET_CSN); 77550769Sdfr 77650769Sdfr /* 77750769Sdfr * Move all cards to the Isolation state. 77850769Sdfr */ 77950769Sdfr pnp_write(PNP_WAKE, 0); 78050769Sdfr 78150769Sdfr /* 78250769Sdfr * Tell them where the read point is going to be this time. 78350769Sdfr */ 78450769Sdfr pnp_write(PNP_SET_RD_DATA, pnp_rd_port); 78550769Sdfr 78650769Sdfr for (csn = 1; csn < PNP_MAX_CARDS; csn++) { 78750769Sdfr /* 78850769Sdfr * Start the serial isolation protocol. 78950769Sdfr */ 79050769Sdfr outb(_PNP_ADDRESS, PNP_SERIAL_ISOLATION); 79150769Sdfr DELAY(1000); /* Delay 1 msec */ 79250769Sdfr 79350769Sdfr if (pnp_get_serial(&id)) { 79450769Sdfr /* 79550769Sdfr * We have read the id from a card 79650769Sdfr * successfully. The card which won the 79750769Sdfr * isolation protocol will be in Isolation 79852059Sdfr * mode and all others will be in Sleep. 79950769Sdfr * Program the CSN of the isolated card 80050769Sdfr * (taking it to Config state) and read its 80150769Sdfr * resources, creating devices as we find 80250769Sdfr * logical devices on the card. 80350769Sdfr */ 80450769Sdfr pnp_write(PNP_SET_CSN, csn); 805104142Snyan#ifdef PC98 806104142Snyan if (bootverbose) 807104142Snyan printf("PnP Vendor ID = %x\n", id.vendor_id); 808104142Snyan /* Check for NEC PnP (9 bytes serial). */ 809104142Snyan for (n = necpnp = 0; necids[n].vendor_id; n++) { 810104142Snyan if (id.vendor_id == necids[n].vendor_id) { 811104142Snyan necpnp = 1; 812104142Snyan break; 813104142Snyan } 814104142Snyan } 815104142Snyan if (necpnp) { 816104142Snyan if (bootverbose) 817104142Snyan printf("It seems to NEC-PnP card (%s).\n", 818104142Snyan pnp_eisaformat(id.vendor_id)); 819104142Snyan /* Read dummy 9 bytes serial area. */ 820104142Snyan pnp_get_resource_info(buffer, 9); 821104142Snyan } else { 822104142Snyan if (bootverbose) 823104142Snyan printf("It seems to Normal-ISA-PnP card (%s).\n", 824104142Snyan pnp_eisaformat(id.vendor_id)); 825104142Snyan } 826104142Snyan if (bootverbose) 827104142Snyan printf("Reading PnP configuration for %s.\n", 828104142Snyan pnp_eisaformat(id.vendor_id)); 829104142Snyan#endif 83052059Sdfr error = pnp_read_resources(&resources, 83152059Sdfr &space, 83252059Sdfr &len); 83352059Sdfr if (error) 83452059Sdfr break; 83552059Sdfr pnp_create_devices(parent, &id, csn, 83652059Sdfr resources, len); 83750769Sdfr found++; 83850769Sdfr } else 83950769Sdfr break; 84050769Sdfr 84150769Sdfr /* 84250769Sdfr * Put this card back to the Sleep state and 84350769Sdfr * simultaneously move all cards which don't have a 84450769Sdfr * CSN yet to Isolation state. 84550769Sdfr */ 84650769Sdfr pnp_write(PNP_WAKE, 0); 84750769Sdfr } 84850769Sdfr 84950769Sdfr /* 85050769Sdfr * Unless we have chosen the wrong read port, all cards will 85150769Sdfr * be in Sleep state. Put them back into WaitForKey for 85250769Sdfr * now. Their resources will be programmed later. 85350769Sdfr */ 85450769Sdfr pnp_write(PNP_CONFIG_CONTROL, PNP_CONFIG_CONTROL_WAIT_FOR_KEY); 85550769Sdfr 85652059Sdfr /* 85752059Sdfr * Cleanup. 85852059Sdfr */ 85952059Sdfr if (resources) 86052059Sdfr free(resources, M_TEMP); 86152059Sdfr 86250769Sdfr return found; 86350769Sdfr} 86450769Sdfr 86550769Sdfr 86650769Sdfr/* 86750769Sdfr * pnp_identify() 86850769Sdfr * 86950769Sdfr * autoconfiguration of pnp devices. This routine just runs the 87050769Sdfr * isolation protocol over several ports, until one is successful. 87150769Sdfr * 87250769Sdfr * may be called more than once ? 87350769Sdfr * 87450769Sdfr */ 87550769Sdfr 87650769Sdfrstatic void 87750769Sdfrpnp_identify(driver_t *driver, device_t parent) 87850769Sdfr{ 87950769Sdfr int num_pnp_devs; 88050769Sdfr 88150769Sdfr#if 0 88250769Sdfr if (pnp_ldn_overrides[0].csn == 0) { 88350769Sdfr if (bootverbose) 88450769Sdfr printf("Initializing PnP override table\n"); 88550769Sdfr bzero (pnp_ldn_overrides, sizeof(pnp_ldn_overrides)); 88650769Sdfr pnp_ldn_overrides[0].csn = 255 ; 88750769Sdfr } 88850769Sdfr#endif 88950769Sdfr 89050769Sdfr /* Try various READ_DATA ports from 0x203-0x3ff */ 89150769Sdfr for (pnp_rd_port = 0x80; (pnp_rd_port < 0xff); pnp_rd_port += 0x10) { 89250769Sdfr if (bootverbose) 89350769Sdfr printf("Trying Read_Port at %x\n", (pnp_rd_port << 2) | 0x3); 89450769Sdfr 89550769Sdfr num_pnp_devs = pnp_isolation_protocol(parent); 89650769Sdfr if (num_pnp_devs) 89750769Sdfr break; 89850769Sdfr } 89950769Sdfr} 90050769Sdfr 90150769Sdfrstatic device_method_t pnp_methods[] = { 90250769Sdfr /* Device interface */ 90350769Sdfr DEVMETHOD(device_identify, pnp_identify), 90450769Sdfr 90550769Sdfr { 0, 0 } 90650769Sdfr}; 90750769Sdfr 90850769Sdfrstatic driver_t pnp_driver = { 90950769Sdfr "pnp", 91050769Sdfr pnp_methods, 91150769Sdfr 1, /* no softc */ 91250769Sdfr}; 91350769Sdfr 91450769Sdfrstatic devclass_t pnp_devclass; 91550769Sdfr 91650769SdfrDRIVER_MODULE(pnp, isa, pnp_driver, pnp_devclass, 0, 0); 917