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 * from: pnp.c,v 1.11 1999/05/06 22:11:19 peter Exp 2750769Sdfr */ 2850769Sdfr 29116181Sobrien#include <sys/cdefs.h> 30116181Sobrien__FBSDID("$FreeBSD$"); 31116181Sobrien 3250769Sdfr#include <sys/param.h> 3350769Sdfr#include <sys/systm.h> 3450769Sdfr#include <sys/kernel.h> 3550769Sdfr#include <sys/module.h> 3650769Sdfr#include <sys/bus.h> 37150687Smarius#include <sys/endian.h> 3850769Sdfr#include <sys/malloc.h> 3950769Sdfr#include <isa/isavar.h> 4050769Sdfr#include <isa/pnpreg.h> 4150769Sdfr#include <isa/pnpvar.h> 4265176Sdfr#include <machine/bus.h> 4350769Sdfr 4450769Sdfrtypedef struct _pnp_id { 45139268Simp uint32_t vendor_id; 46139268Simp uint32_t serial; 4750769Sdfr u_char checksum; 4850769Sdfr} pnp_id; 4950769Sdfr 5050769Sdfrstruct pnp_set_config_arg { 5150769Sdfr int csn; /* Card number to configure */ 5250769Sdfr int ldn; /* Logical device on card */ 5350769Sdfr}; 5450769Sdfr 5550769Sdfrstruct pnp_quirk { 56139268Simp uint32_t vendor_id; /* Vendor of the card */ 57139268Simp uint32_t logical_id; /* ID of the device with quirk */ 5850769Sdfr int type; 5950769Sdfr#define PNP_QUIRK_WRITE_REG 1 /* Need to write a pnp register */ 6062947Stanimura#define PNP_QUIRK_EXTRA_IO 2 /* Has extra io ports */ 6150769Sdfr int arg1; 6250769Sdfr int arg2; 6350769Sdfr}; 6450769Sdfr 6550769Sdfrstruct pnp_quirk pnp_quirks[] = { 6650769Sdfr /* 6750769Sdfr * The Gravis UltraSound needs register 0xf2 to be set to 0xff 6850769Sdfr * to enable power. 6950769Sdfr * XXX need to know the logical device id. 7050769Sdfr */ 7150769Sdfr { 0x0100561e /* GRV0001 */, 0, 7250769Sdfr PNP_QUIRK_WRITE_REG, 0xf2, 0xff }, 7362947Stanimura /* 7462947Stanimura * An emu8000 does not give us other than the first 7562947Stanimura * port. 7662947Stanimura */ 7762947Stanimura { 0x26008c0e /* SB16 */, 0x21008c0e, 7862947Stanimura PNP_QUIRK_EXTRA_IO, 0x400, 0x800 }, 7962947Stanimura { 0x42008c0e /* SB32(CTL0042) */, 0x21008c0e, 8062947Stanimura PNP_QUIRK_EXTRA_IO, 0x400, 0x800 }, 8162947Stanimura { 0x44008c0e /* SB32(CTL0044) */, 0x21008c0e, 8262947Stanimura PNP_QUIRK_EXTRA_IO, 0x400, 0x800 }, 8362947Stanimura { 0x49008c0e /* SB32(CTL0049) */, 0x21008c0e, 8462947Stanimura PNP_QUIRK_EXTRA_IO, 0x400, 0x800 }, 8562947Stanimura { 0xf1008c0e /* SB32(CTL00f1) */, 0x21008c0e, 8662947Stanimura PNP_QUIRK_EXTRA_IO, 0x400, 0x800 }, 8762947Stanimura { 0xc1008c0e /* SB64(CTL00c1) */, 0x22008c0e, 8862947Stanimura PNP_QUIRK_EXTRA_IO, 0x400, 0x800 }, 8990234Stanimura { 0xc5008c0e /* SB64(CTL00c5) */, 0x22008c0e, 9090234Stanimura PNP_QUIRK_EXTRA_IO, 0x400, 0x800 }, 9162947Stanimura { 0xe4008c0e /* SB64(CTL00e4) */, 0x22008c0e, 9262947Stanimura PNP_QUIRK_EXTRA_IO, 0x400, 0x800 }, 9350769Sdfr 9450769Sdfr { 0 } 9550769Sdfr}; 9650769Sdfr 97104142Snyan#ifdef PC98 98104142Snyan/* Some NEC PnP cards have 9 bytes serial code. */ 99104142Snyanstatic pnp_id necids[] = { 100104142Snyan {0x4180a3b8, 0xffffffff, 0x00}, /* PC-9801CB-B04 (NEC8041) */ 101104142Snyan {0x5181a3b8, 0xffffffff, 0x46}, /* PC-9821CB2-B04(NEC8151) */ 102104142Snyan {0x5182a3b8, 0xffffffff, 0xb8}, /* PC-9801-XX (NEC8251) */ 103104142Snyan {0x9181a3b8, 0xffffffff, 0x00}, /* PC-9801-120 (NEC8191) */ 104104142Snyan {0, 0, 0} 105104142Snyan}; 106104142Snyan#endif 107104142Snyan 10850769Sdfr/* The READ_DATA port that we are using currently */ 10950769Sdfrstatic int pnp_rd_port; 11050769Sdfr 11150769Sdfrstatic void pnp_send_initiation_key(void); 11250769Sdfrstatic int pnp_get_serial(pnp_id *p); 11350769Sdfrstatic int pnp_isolation_protocol(device_t parent); 11450769Sdfr 11552241Sdfrchar * 116139268Simppnp_eisaformat(uint32_t id) 11752241Sdfr{ 118150687Smarius uint8_t *data; 11952241Sdfr static char idbuf[8]; 12052241Sdfr const char hextoascii[] = "0123456789abcdef"; 12152241Sdfr 122150687Smarius id = htole32(id); 123150687Smarius data = (uint8_t *)&id; 12452241Sdfr idbuf[0] = '@' + ((data[0] & 0x7c) >> 2); 12552241Sdfr idbuf[1] = '@' + (((data[0] & 0x3) << 3) + ((data[1] & 0xe0) >> 5)); 12652241Sdfr idbuf[2] = '@' + (data[1] & 0x1f); 12752241Sdfr idbuf[3] = hextoascii[(data[2] >> 4)]; 12852241Sdfr idbuf[4] = hextoascii[(data[2] & 0xf)]; 12952241Sdfr idbuf[5] = hextoascii[(data[3] >> 4)]; 13052241Sdfr idbuf[6] = hextoascii[(data[3] & 0xf)]; 13152241Sdfr idbuf[7] = 0; 13252241Sdfr return(idbuf); 13352241Sdfr} 13452241Sdfr 13550769Sdfrstatic void 13650769Sdfrpnp_write(int d, u_char r) 13750769Sdfr{ 13850769Sdfr outb (_PNP_ADDRESS, d); 13950769Sdfr outb (_PNP_WRITE_DATA, r); 14050769Sdfr} 14150769Sdfr 14250769Sdfr/* 14350769Sdfr * Send Initiation LFSR as described in "Plug and Play ISA Specification", 14450769Sdfr * Intel May 94. 14550769Sdfr */ 14650769Sdfrstatic void 14750769Sdfrpnp_send_initiation_key() 14850769Sdfr{ 14950769Sdfr int cur, i; 15050769Sdfr 15150769Sdfr /* Reset the LSFR */ 15250769Sdfr outb(_PNP_ADDRESS, 0); 15350769Sdfr outb(_PNP_ADDRESS, 0); /* yes, we do need it twice! */ 15450769Sdfr 15550769Sdfr cur = 0x6a; 15650769Sdfr outb(_PNP_ADDRESS, cur); 15750769Sdfr 15850769Sdfr for (i = 1; i < 32; i++) { 15950769Sdfr cur = (cur >> 1) | (((cur ^ (cur >> 1)) << 7) & 0xff); 16050769Sdfr outb(_PNP_ADDRESS, cur); 16150769Sdfr } 16250769Sdfr} 16350769Sdfr 16450769Sdfr 16550769Sdfr/* 16650769Sdfr * Get the device's serial number. Returns 1 if the serial is valid. 16750769Sdfr */ 16850769Sdfrstatic int 16950769Sdfrpnp_get_serial(pnp_id *p) 17050769Sdfr{ 17150769Sdfr int i, bit, valid = 0, sum = 0x6a; 17250769Sdfr u_char *data = (u_char *)p; 17350769Sdfr 17450769Sdfr bzero(data, sizeof(char) * 9); 17550769Sdfr outb(_PNP_ADDRESS, PNP_SERIAL_ISOLATION); 17650769Sdfr for (i = 0; i < 72; i++) { 17750769Sdfr bit = inb((pnp_rd_port << 2) | 0x3) == 0x55; 17850769Sdfr DELAY(250); /* Delay 250 usec */ 17950769Sdfr 18050769Sdfr /* Can't Short Circuit the next evaluation, so 'and' is last */ 18150769Sdfr bit = (inb((pnp_rd_port << 2) | 0x3) == 0xaa) && bit; 18250769Sdfr DELAY(250); /* Delay 250 usec */ 18350769Sdfr 18450769Sdfr valid = valid || bit; 18550769Sdfr if (i < 64) 18650769Sdfr sum = (sum >> 1) | 187139268Simp (((sum ^ (sum >> 1) ^ bit) << 7) & 0xff); 18850769Sdfr data[i / 8] = (data[i / 8] >> 1) | (bit ? 0x80 : 0); 18950769Sdfr } 19050769Sdfr 19150769Sdfr valid = valid && (data[8] == sum); 19250769Sdfr 193139268Simp return (valid); 19450769Sdfr} 19550769Sdfr 19650769Sdfr/* 19750769Sdfr * Fill's the buffer with resource info from the device. 19852059Sdfr * Returns the number of characters read. 19950769Sdfr */ 20050769Sdfrstatic int 20150769Sdfrpnp_get_resource_info(u_char *buffer, int len) 20250769Sdfr{ 20352059Sdfr int i, j, count; 20450769Sdfr u_char temp; 20550769Sdfr 20652059Sdfr count = 0; 20750769Sdfr for (i = 0; i < len; i++) { 20850769Sdfr outb(_PNP_ADDRESS, PNP_STATUS); 20950769Sdfr for (j = 0; j < 100; j++) { 21050769Sdfr if ((inb((pnp_rd_port << 2) | 0x3)) & 0x1) 21150769Sdfr break; 212220126Sjhb DELAY(10); 21350769Sdfr } 21450769Sdfr if (j == 100) { 21550769Sdfr printf("PnP device failed to report resource data\n"); 216139268Simp return (count); 21750769Sdfr } 21850769Sdfr outb(_PNP_ADDRESS, PNP_RESOURCE_DATA); 21950769Sdfr temp = inb((pnp_rd_port << 2) | 0x3); 22050769Sdfr if (buffer != NULL) 22150769Sdfr buffer[i] = temp; 22252059Sdfr count++; 22350769Sdfr } 224139268Simp return (count); 22550769Sdfr} 22650769Sdfr 22750769Sdfr/* 22850769Sdfr * This function is called after the bus has assigned resource 22950769Sdfr * locations for a logical device. 23050769Sdfr */ 23150769Sdfrstatic void 23250769Sdfrpnp_set_config(void *arg, struct isa_config *config, int enable) 23350769Sdfr{ 23450769Sdfr int csn = ((struct pnp_set_config_arg *) arg)->csn; 23550769Sdfr int ldn = ((struct pnp_set_config_arg *) arg)->ldn; 23650769Sdfr int i; 23750769Sdfr 23850769Sdfr /* 23950769Sdfr * First put all cards into Sleep state with the initiation 24050769Sdfr * key, then put our card into Config state. 24150769Sdfr */ 24250769Sdfr pnp_send_initiation_key(); 24350769Sdfr pnp_write(PNP_WAKE, csn); 24450769Sdfr 24550769Sdfr /* 24650769Sdfr * Select our logical device so that we can program it. 24750769Sdfr */ 24850769Sdfr pnp_write(PNP_SET_LDN, ldn); 24950769Sdfr 25050769Sdfr /* 25166840Smsmith * Constrain the number of resources we will try to program 25266840Smsmith */ 25366840Smsmith if (config->ic_nmem > ISA_PNP_NMEM) { 254139268Simp printf("too many ISA memory ranges (%d > %d)\n", 255139268Simp config->ic_nmem, ISA_PNP_NMEM); 256139268Simp config->ic_nmem = ISA_PNP_NMEM; 25766840Smsmith } 25866840Smsmith if (config->ic_nport > ISA_PNP_NPORT) { 259139268Simp printf("too many ISA I/O ranges (%d > %d)\n", config->ic_nport, 260139268Simp ISA_PNP_NPORT); 261139268Simp config->ic_nport = ISA_PNP_NPORT; 26266840Smsmith } 26366840Smsmith if (config->ic_nirq > ISA_PNP_NIRQ) { 264139268Simp printf("too many ISA IRQs (%d > %d)\n", config->ic_nirq, 265139268Simp ISA_PNP_NIRQ); 266139268Simp config->ic_nirq = ISA_PNP_NIRQ; 26766840Smsmith } 26866840Smsmith if (config->ic_ndrq > ISA_PNP_NDRQ) { 269139268Simp printf("too many ISA DRQs (%d > %d)\n", config->ic_ndrq, 270139268Simp ISA_PNP_NDRQ); 271139268Simp config->ic_ndrq = ISA_PNP_NDRQ; 27266840Smsmith } 27366840Smsmith 27466840Smsmith /* 27550769Sdfr * Now program the resources. 27650769Sdfr */ 27750769Sdfr for (i = 0; i < config->ic_nmem; i++) { 278139268Simp uint32_t start; 279139268Simp uint32_t size; 28083051Syokota 28183051Syokota /* XXX: should handle memory control register, 32 bit memory */ 28283051Syokota if (config->ic_mem[i].ir_size == 0) { 28383051Syokota pnp_write(PNP_MEM_BASE_HIGH(i), 0); 28483051Syokota pnp_write(PNP_MEM_BASE_LOW(i), 0); 28583051Syokota pnp_write(PNP_MEM_RANGE_HIGH(i), 0); 28683051Syokota pnp_write(PNP_MEM_RANGE_LOW(i), 0); 28783051Syokota } else { 28883051Syokota start = config->ic_mem[i].ir_start; 28983051Syokota size = config->ic_mem[i].ir_size; 29083051Syokota if (start & 0xff) 29183051Syokota panic("pnp_set_config: bogus memory assignment"); 29283051Syokota pnp_write(PNP_MEM_BASE_HIGH(i), (start >> 16) & 0xff); 29383051Syokota pnp_write(PNP_MEM_BASE_LOW(i), (start >> 8) & 0xff); 29483051Syokota pnp_write(PNP_MEM_RANGE_HIGH(i), (size >> 16) & 0xff); 29583051Syokota pnp_write(PNP_MEM_RANGE_LOW(i), (size >> 8) & 0xff); 29683051Syokota } 29750769Sdfr } 29866840Smsmith for (; i < ISA_PNP_NMEM; i++) { 29950769Sdfr pnp_write(PNP_MEM_BASE_HIGH(i), 0); 30050769Sdfr pnp_write(PNP_MEM_BASE_LOW(i), 0); 30150769Sdfr pnp_write(PNP_MEM_RANGE_HIGH(i), 0); 30250769Sdfr pnp_write(PNP_MEM_RANGE_LOW(i), 0); 30350769Sdfr } 30450769Sdfr 30550769Sdfr for (i = 0; i < config->ic_nport; i++) { 306139268Simp uint32_t start; 30783051Syokota 30883051Syokota if (config->ic_port[i].ir_size == 0) { 30983051Syokota pnp_write(PNP_IO_BASE_HIGH(i), 0); 31083051Syokota pnp_write(PNP_IO_BASE_LOW(i), 0); 31183051Syokota } else { 31283051Syokota start = config->ic_port[i].ir_start; 31383051Syokota pnp_write(PNP_IO_BASE_HIGH(i), (start >> 8) & 0xff); 31483051Syokota pnp_write(PNP_IO_BASE_LOW(i), (start >> 0) & 0xff); 31583051Syokota } 31650769Sdfr } 31766840Smsmith for (; i < ISA_PNP_NPORT; i++) { 31850769Sdfr pnp_write(PNP_IO_BASE_HIGH(i), 0); 31950769Sdfr pnp_write(PNP_IO_BASE_LOW(i), 0); 32050769Sdfr } 32150769Sdfr 32250769Sdfr for (i = 0; i < config->ic_nirq; i++) { 32383051Syokota int irq; 32483051Syokota 32583051Syokota /* XXX: interrupt type */ 32683051Syokota if (config->ic_irqmask[i] == 0) { 32783051Syokota pnp_write(PNP_IRQ_LEVEL(i), 0); 32883051Syokota pnp_write(PNP_IRQ_TYPE(i), 2); 32983051Syokota } else { 33083051Syokota irq = ffs(config->ic_irqmask[i]) - 1; 33183051Syokota pnp_write(PNP_IRQ_LEVEL(i), irq); 33283051Syokota pnp_write(PNP_IRQ_TYPE(i), 2); /* XXX */ 33383051Syokota } 33450769Sdfr } 33566840Smsmith for (; i < ISA_PNP_NIRQ; i++) { 33650769Sdfr /* 33750769Sdfr * IRQ 0 is not a valid interrupt selection and 33850769Sdfr * represents no interrupt selection. 33950769Sdfr */ 34050769Sdfr pnp_write(PNP_IRQ_LEVEL(i), 0); 34183051Syokota pnp_write(PNP_IRQ_TYPE(i), 2); 34250769Sdfr } 34350769Sdfr 34450769Sdfr for (i = 0; i < config->ic_ndrq; i++) { 34583051Syokota int drq; 34683051Syokota 34783051Syokota if (config->ic_drqmask[i] == 0) { 34883051Syokota pnp_write(PNP_DMA_CHANNEL(i), 4); 34983051Syokota } else { 35083051Syokota drq = ffs(config->ic_drqmask[i]) - 1; 35183051Syokota pnp_write(PNP_DMA_CHANNEL(i), drq); 35283051Syokota } 35350769Sdfr } 35466840Smsmith for (; i < ISA_PNP_NDRQ; i++) { 35550769Sdfr /* 35650769Sdfr * DMA channel 4, the cascade channel is used to 35750769Sdfr * indicate no DMA channel is active. 35850769Sdfr */ 35950769Sdfr pnp_write(PNP_DMA_CHANNEL(i), 4); 36050769Sdfr } 36150769Sdfr 36250769Sdfr pnp_write(PNP_ACTIVATE, enable ? 1 : 0); 36350769Sdfr 36450769Sdfr /* 36550769Sdfr * Wake everyone up again, we are finished. 36650769Sdfr */ 36750769Sdfr pnp_write(PNP_CONFIG_CONTROL, PNP_CONFIG_CONTROL_WAIT_FOR_KEY); 36850769Sdfr} 36950769Sdfr 37050769Sdfr/* 37150769Sdfr * Process quirks for a logical device.. The card must be in Config state. 37250769Sdfr */ 37362947Stanimuravoid 374139268Simppnp_check_quirks(uint32_t vendor_id, uint32_t logical_id, int ldn, 375139268Simp struct isa_config *config) 37650769Sdfr{ 37750769Sdfr struct pnp_quirk *qp; 37850769Sdfr 37950769Sdfr for (qp = &pnp_quirks[0]; qp->vendor_id; qp++) { 38050769Sdfr if (qp->vendor_id == vendor_id 381139268Simp && (qp->logical_id == 0 || qp->logical_id == logical_id)) { 38250769Sdfr switch (qp->type) { 38350769Sdfr case PNP_QUIRK_WRITE_REG: 38450769Sdfr pnp_write(PNP_SET_LDN, ldn); 38550769Sdfr pnp_write(qp->arg1, qp->arg2); 38650769Sdfr break; 38762947Stanimura case PNP_QUIRK_EXTRA_IO: 38862947Stanimura if (config == NULL) 38962947Stanimura break; 39062947Stanimura if (qp->arg1 != 0) { 39162947Stanimura config->ic_nport++; 39262947Stanimura config->ic_port[config->ic_nport - 1] = config->ic_port[0]; 39362947Stanimura config->ic_port[config->ic_nport - 1].ir_start += qp->arg1; 39462947Stanimura config->ic_port[config->ic_nport - 1].ir_end += qp->arg1; 39562947Stanimura } 39662947Stanimura if (qp->arg2 != 0) { 39762947Stanimura config->ic_nport++; 39862947Stanimura config->ic_port[config->ic_nport - 1] = config->ic_port[0]; 39962947Stanimura config->ic_port[config->ic_nport - 1].ir_start += qp->arg2; 40062947Stanimura config->ic_port[config->ic_nport - 1].ir_end += qp->arg2; 40162947Stanimura } 40262947Stanimura break; 40350769Sdfr } 40450769Sdfr } 40550769Sdfr } 40650769Sdfr} 40750769Sdfr 40850769Sdfr/* 40950769Sdfr * Scan Resource Data for Logical Devices. 41050769Sdfr * 41150769Sdfr * This function exits as soon as it gets an error reading *ANY* 41252059Sdfr * Resource Data or it reaches the end of Resource Data. In the first 41350769Sdfr * case the return value will be TRUE, FALSE otherwise. 41450769Sdfr */ 41550769Sdfrstatic int 41652059Sdfrpnp_create_devices(device_t parent, pnp_id *p, int csn, 417139268Simp u_char *resources, int len) 41850769Sdfr{ 41952059Sdfr u_char tag, *resp, *resinfo, *startres = 0; 42052059Sdfr int large_len, scanning = len, retval = FALSE; 421139268Simp uint32_t logical_id; 42250769Sdfr device_t dev = 0; 42350769Sdfr int ldn = 0; 42450769Sdfr struct pnp_set_config_arg *csnldn; 42552059Sdfr char buf[100]; 42650769Sdfr char *desc = 0; 42750769Sdfr 42852059Sdfr resp = resources; 42952059Sdfr while (scanning > 0) { 43052059Sdfr tag = *resp++; 43152059Sdfr scanning--; 43252059Sdfr if (PNP_RES_TYPE(tag) != 0) { 43352059Sdfr /* Large resource */ 43452059Sdfr if (scanning < 2) { 43550769Sdfr scanning = 0; 43650769Sdfr continue; 43750769Sdfr } 43852059Sdfr large_len = resp[0] + (resp[1] << 8); 43952059Sdfr resp += 2; 44050769Sdfr 44152059Sdfr if (scanning < large_len) { 44250769Sdfr scanning = 0; 44350769Sdfr continue; 44450769Sdfr } 44552059Sdfr resinfo = resp; 44652059Sdfr resp += large_len; 44752059Sdfr scanning -= large_len; 44850769Sdfr 44950769Sdfr if (PNP_LRES_NUM(tag) == PNP_TAG_ID_ANSI) { 45083504Syokota if (dev) { 45183504Syokota /* 45283504Syokota * This is an optional device 45383504Syokota * indentifier string. Skipt it 45483504Syokota * for now. 45583504Syokota */ 45683504Syokota continue; 45783504Syokota } 45883504Syokota /* else mandately card identifier string */ 45952059Sdfr if (large_len > sizeof(buf) - 1) 46052059Sdfr large_len = sizeof(buf) - 1; 46152059Sdfr bcopy(resinfo, buf, large_len); 46252059Sdfr 46350769Sdfr /* 46452059Sdfr * Trim trailing spaces. 46550769Sdfr */ 46652059Sdfr while (buf[large_len-1] == ' ') 46752059Sdfr large_len--; 46852059Sdfr buf[large_len] = '\0'; 46952059Sdfr desc = buf; 47050769Sdfr continue; 47150769Sdfr } 47250769Sdfr 47352059Sdfr continue; 47452059Sdfr } 47552059Sdfr 47652059Sdfr /* Small resource */ 47752059Sdfr if (scanning < PNP_SRES_LEN(tag)) { 47852059Sdfr scanning = 0; 47952059Sdfr continue; 48052059Sdfr } 48152059Sdfr resinfo = resp; 48252059Sdfr resp += PNP_SRES_LEN(tag); 483201758Smbr scanning -= PNP_SRES_LEN(tag); 48452059Sdfr 48552059Sdfr switch (PNP_SRES_NUM(tag)) { 48652059Sdfr case PNP_TAG_LOGICAL_DEVICE: 48752059Sdfr /* 48852059Sdfr * Parse the resources for the previous 48952059Sdfr * logical device (if any). 49052059Sdfr */ 49152059Sdfr if (startres) { 49252059Sdfr pnp_parse_resources(dev, startres, 493139268Simp resinfo - startres - 1, ldn); 49452059Sdfr dev = 0; 49552059Sdfr startres = 0; 49650769Sdfr } 49750769Sdfr 49852059Sdfr /* 49952059Sdfr * A new logical device. Scan for end of 50052059Sdfr * resources. 50152059Sdfr */ 50252059Sdfr bcopy(resinfo, &logical_id, 4); 50362947Stanimura pnp_check_quirks(p->vendor_id, logical_id, ldn, NULL); 50452059Sdfr dev = BUS_ADD_CHILD(parent, ISA_ORDER_PNP, NULL, -1); 50552059Sdfr if (desc) 50652059Sdfr device_set_desc_copy(dev, desc); 50783504Syokota else 50883504Syokota device_set_desc_copy(dev, 509139268Simp pnp_eisaformat(logical_id)); 51052059Sdfr isa_set_vendorid(dev, p->vendor_id); 51152059Sdfr isa_set_serial(dev, p->serial); 51252059Sdfr isa_set_logicalid(dev, logical_id); 51383051Syokota isa_set_configattr(dev, 514139268Simp ISACFGATTR_CANDISABLE | ISACFGATTR_DYNAMIC); 51552059Sdfr csnldn = malloc(sizeof *csnldn, M_DEVBUF, M_NOWAIT); 51652059Sdfr if (!csnldn) { 517139268Simp device_printf(parent, "out of memory\n"); 51850769Sdfr scanning = 0; 51952059Sdfr break; 52050769Sdfr } 52152059Sdfr csnldn->csn = csn; 52252059Sdfr csnldn->ldn = ldn; 523139268Simp ISA_SET_CONFIG_CALLBACK(parent, dev, pnp_set_config, 524139268Simp csnldn); 525184564Simp isa_set_pnp_csn(dev, csn); 526184564Simp isa_set_pnp_ldn(dev, ldn); 52752059Sdfr ldn++; 52852059Sdfr startres = resp; 52952059Sdfr break; 53052059Sdfr 53152059Sdfr case PNP_TAG_END: 53252059Sdfr if (!startres) { 533139268Simp device_printf(parent, "malformed resources\n"); 53450769Sdfr scanning = 0; 53550769Sdfr break; 53650769Sdfr } 53752059Sdfr pnp_parse_resources(dev, startres, 538139268Simp resinfo - startres - 1, ldn); 53952059Sdfr dev = 0; 54052059Sdfr startres = 0; 54152059Sdfr scanning = 0; 54252059Sdfr break; 54350769Sdfr 54452059Sdfr default: 54552059Sdfr /* Skip this resource */ 54652059Sdfr break; 54750769Sdfr } 54850769Sdfr } 54950769Sdfr 550139268Simp return (retval); 55150769Sdfr} 55250769Sdfr 55350769Sdfr/* 55452059Sdfr * Read 'amount' bytes of resources from the card, allocating memory 55552059Sdfr * as needed. If a buffer is already available, it should be passed in 55652059Sdfr * '*resourcesp' and its length in '*spacep'. The number of resource 55752059Sdfr * bytes already in the buffer should be passed in '*lenp'. The memory 55852059Sdfr * allocated will be returned in '*resourcesp' with its size and the 55952059Sdfr * number of bytes of resources in '*spacep' and '*lenp' respectively. 560105226Sphk * 561105226Sphk * XXX: Multiple problems here, we forget to free() stuff in one 562105226Sphk * XXX: error return, and in another case we free (*resourcesp) but 563105226Sphk * XXX: don't tell the caller. 56452059Sdfr */ 56552059Sdfrstatic int 56652059Sdfrpnp_read_bytes(int amount, u_char **resourcesp, int *spacep, int *lenp) 56752059Sdfr{ 56852059Sdfr u_char *resources = *resourcesp; 56952059Sdfr u_char *newres; 57052059Sdfr int space = *spacep; 57152059Sdfr int len = *lenp; 57252059Sdfr 57352059Sdfr if (space == 0) { 57452059Sdfr space = 1024; 57552059Sdfr resources = malloc(space, M_TEMP, M_NOWAIT); 57652059Sdfr if (!resources) 577139268Simp return (ENOMEM); 57852059Sdfr } 57952059Sdfr 58052059Sdfr if (len + amount > space) { 58152059Sdfr int extra = 1024; 58252059Sdfr while (len + amount > space + extra) 58352059Sdfr extra += 1024; 58452059Sdfr newres = malloc(space + extra, M_TEMP, M_NOWAIT); 585115543Sphk if (!newres) { 586115543Sphk /* XXX: free resources */ 587139268Simp return (ENOMEM); 588115543Sphk } 58952059Sdfr bcopy(resources, newres, len); 59052059Sdfr free(resources, M_TEMP); 59152059Sdfr resources = newres; 59252059Sdfr space += extra; 59352059Sdfr } 59452059Sdfr 59552059Sdfr if (pnp_get_resource_info(resources + len, amount) != amount) 596139268Simp return (EINVAL); 59752059Sdfr len += amount; 59852059Sdfr 59952059Sdfr *resourcesp = resources; 60052059Sdfr *spacep = space; 60152059Sdfr *lenp = len; 60252059Sdfr 603139268Simp return (0); 60452059Sdfr} 60552059Sdfr 60652059Sdfr/* 60752059Sdfr * Read all resources from the card, allocating memory as needed. If a 60852059Sdfr * buffer is already available, it should be passed in '*resourcesp' 60952059Sdfr * and its length in '*spacep'. The memory allocated will be returned 61052059Sdfr * in '*resourcesp' with its size and the number of bytes of resources 61152059Sdfr * in '*spacep' and '*lenp' respectively. 61252059Sdfr */ 61352059Sdfrstatic int 61452059Sdfrpnp_read_resources(u_char **resourcesp, int *spacep, int *lenp) 61552059Sdfr{ 61652059Sdfr u_char *resources = *resourcesp; 61752059Sdfr int space = *spacep; 61852059Sdfr int len = 0; 61952059Sdfr int error, done; 62052059Sdfr u_char tag; 62152059Sdfr 62252059Sdfr error = 0; 62352059Sdfr done = 0; 62452059Sdfr while (!done) { 62552059Sdfr error = pnp_read_bytes(1, &resources, &space, &len); 62652059Sdfr if (error) 62752059Sdfr goto out; 62852059Sdfr tag = resources[len-1]; 62952059Sdfr if (PNP_RES_TYPE(tag) == 0) { 63052059Sdfr /* 63152059Sdfr * Small resource, read contents. 63252059Sdfr */ 63352059Sdfr error = pnp_read_bytes(PNP_SRES_LEN(tag), 634139268Simp &resources, &space, &len); 63552059Sdfr if (error) 63652059Sdfr goto out; 63752059Sdfr if (PNP_SRES_NUM(tag) == PNP_TAG_END) 63852059Sdfr done = 1; 63952059Sdfr } else { 64052059Sdfr /* 64152059Sdfr * Large resource, read length and contents. 64252059Sdfr */ 64352059Sdfr error = pnp_read_bytes(2, &resources, &space, &len); 64452059Sdfr if (error) 64552059Sdfr goto out; 64652059Sdfr error = pnp_read_bytes(resources[len-2] 647139268Simp + (resources[len-1] << 8), &resources, &space, 648139268Simp &len); 64952059Sdfr if (error) 65052059Sdfr goto out; 65152059Sdfr } 65252059Sdfr } 65352059Sdfr 65452059Sdfr out: 65552059Sdfr *resourcesp = resources; 65652059Sdfr *spacep = space; 65752059Sdfr *lenp = len; 658139268Simp return (error); 65952059Sdfr} 66052059Sdfr 66152059Sdfr/* 66250769Sdfr * Run the isolation protocol. Use pnp_rd_port as the READ_DATA port 66350769Sdfr * value (caller should try multiple READ_DATA locations before giving 66450769Sdfr * up). Upon exiting, all cards are aware that they should use 66550769Sdfr * pnp_rd_port as the READ_DATA port. 66650769Sdfr * 66750769Sdfr * In the first pass, a csn is assigned to each board and pnp_id's 66850769Sdfr * are saved to an array, pnp_devices. In the second pass, each 66950769Sdfr * card is woken up and the device configuration is called. 67050769Sdfr */ 67150769Sdfrstatic int 67250769Sdfrpnp_isolation_protocol(device_t parent) 67350769Sdfr{ 67450769Sdfr int csn; 67550769Sdfr pnp_id id; 67652059Sdfr int found = 0, len; 67752059Sdfr u_char *resources = 0; 67852059Sdfr int space = 0; 67952059Sdfr int error; 680104142Snyan#ifdef PC98 681104142Snyan int n, necpnp; 682104142Snyan u_char buffer[10]; 683104142Snyan#endif 68450769Sdfr 68550769Sdfr /* 68650769Sdfr * Put all cards into the Sleep state so that we can clear 68750769Sdfr * their CSNs. 68850769Sdfr */ 68950769Sdfr pnp_send_initiation_key(); 69050769Sdfr 69150769Sdfr /* 69250769Sdfr * Clear the CSN for all cards. 69350769Sdfr */ 69450769Sdfr pnp_write(PNP_CONFIG_CONTROL, PNP_CONFIG_CONTROL_RESET_CSN); 69550769Sdfr 69650769Sdfr /* 69750769Sdfr * Move all cards to the Isolation state. 69850769Sdfr */ 69950769Sdfr pnp_write(PNP_WAKE, 0); 70050769Sdfr 70150769Sdfr /* 70250769Sdfr * Tell them where the read point is going to be this time. 70350769Sdfr */ 70450769Sdfr pnp_write(PNP_SET_RD_DATA, pnp_rd_port); 70550769Sdfr 70650769Sdfr for (csn = 1; csn < PNP_MAX_CARDS; csn++) { 70750769Sdfr /* 70850769Sdfr * Start the serial isolation protocol. 70950769Sdfr */ 71050769Sdfr outb(_PNP_ADDRESS, PNP_SERIAL_ISOLATION); 71150769Sdfr DELAY(1000); /* Delay 1 msec */ 71250769Sdfr 71350769Sdfr if (pnp_get_serial(&id)) { 71450769Sdfr /* 71550769Sdfr * We have read the id from a card 71650769Sdfr * successfully. The card which won the 71750769Sdfr * isolation protocol will be in Isolation 71852059Sdfr * mode and all others will be in Sleep. 71950769Sdfr * Program the CSN of the isolated card 72050769Sdfr * (taking it to Config state) and read its 72150769Sdfr * resources, creating devices as we find 72250769Sdfr * logical devices on the card. 72350769Sdfr */ 72450769Sdfr pnp_write(PNP_SET_CSN, csn); 725104142Snyan#ifdef PC98 726104142Snyan if (bootverbose) 727104142Snyan printf("PnP Vendor ID = %x\n", id.vendor_id); 728104142Snyan /* Check for NEC PnP (9 bytes serial). */ 729104142Snyan for (n = necpnp = 0; necids[n].vendor_id; n++) { 730104142Snyan if (id.vendor_id == necids[n].vendor_id) { 731104142Snyan necpnp = 1; 732104142Snyan break; 733104142Snyan } 734104142Snyan } 735104142Snyan if (necpnp) { 736104142Snyan if (bootverbose) 737139268Simp printf("An NEC-PnP card (%s).\n", 738139268Simp pnp_eisaformat(id.vendor_id)); 739104142Snyan /* Read dummy 9 bytes serial area. */ 740104142Snyan pnp_get_resource_info(buffer, 9); 741104142Snyan } else { 742104142Snyan if (bootverbose) 743139268Simp printf("A Normal-ISA-PnP card (%s).\n", 744139268Simp pnp_eisaformat(id.vendor_id)); 745104142Snyan } 746220126Sjhb#endif 747104142Snyan if (bootverbose) 748104142Snyan printf("Reading PnP configuration for %s.\n", 749139268Simp pnp_eisaformat(id.vendor_id)); 750139268Simp error = pnp_read_resources(&resources, &space, &len); 75152059Sdfr if (error) 75252059Sdfr break; 753139268Simp pnp_create_devices(parent, &id, csn, resources, len); 75450769Sdfr found++; 75550769Sdfr } else 75650769Sdfr break; 75750769Sdfr 75850769Sdfr /* 75950769Sdfr * Put this card back to the Sleep state and 76050769Sdfr * simultaneously move all cards which don't have a 76150769Sdfr * CSN yet to Isolation state. 76250769Sdfr */ 76350769Sdfr pnp_write(PNP_WAKE, 0); 76450769Sdfr } 76550769Sdfr 76650769Sdfr /* 76750769Sdfr * Unless we have chosen the wrong read port, all cards will 76850769Sdfr * be in Sleep state. Put them back into WaitForKey for 76950769Sdfr * now. Their resources will be programmed later. 77050769Sdfr */ 77150769Sdfr pnp_write(PNP_CONFIG_CONTROL, PNP_CONFIG_CONTROL_WAIT_FOR_KEY); 77250769Sdfr 77352059Sdfr /* 77452059Sdfr * Cleanup. 77552059Sdfr */ 77652059Sdfr if (resources) 77752059Sdfr free(resources, M_TEMP); 77852059Sdfr 779139268Simp return (found); 78050769Sdfr} 78150769Sdfr 78250769Sdfr 78350769Sdfr/* 78450769Sdfr * pnp_identify() 78550769Sdfr * 78650769Sdfr * autoconfiguration of pnp devices. This routine just runs the 78750769Sdfr * isolation protocol over several ports, until one is successful. 78850769Sdfr * 78950769Sdfr * may be called more than once ? 79050769Sdfr * 79150769Sdfr */ 79250769Sdfr 79350769Sdfrstatic void 79450769Sdfrpnp_identify(driver_t *driver, device_t parent) 79550769Sdfr{ 79650769Sdfr int num_pnp_devs; 79750769Sdfr 79850769Sdfr /* Try various READ_DATA ports from 0x203-0x3ff */ 79950769Sdfr for (pnp_rd_port = 0x80; (pnp_rd_port < 0xff); pnp_rd_port += 0x10) { 80050769Sdfr if (bootverbose) 801139271Simp printf("pnp_identify: Trying Read_Port at %x\n", 802139268Simp (pnp_rd_port << 2) | 0x3); 80350769Sdfr 80450769Sdfr num_pnp_devs = pnp_isolation_protocol(parent); 80550769Sdfr if (num_pnp_devs) 80650769Sdfr break; 80750769Sdfr } 808139269Simp if (bootverbose) 809139269Simp printf("PNP Identify complete\n"); 81050769Sdfr} 81150769Sdfr 81250769Sdfrstatic device_method_t pnp_methods[] = { 81350769Sdfr /* Device interface */ 81450769Sdfr DEVMETHOD(device_identify, pnp_identify), 81550769Sdfr 81650769Sdfr { 0, 0 } 81750769Sdfr}; 81850769Sdfr 81950769Sdfrstatic driver_t pnp_driver = { 82050769Sdfr "pnp", 82150769Sdfr pnp_methods, 82250769Sdfr 1, /* no softc */ 82350769Sdfr}; 82450769Sdfr 82550769Sdfrstatic devclass_t pnp_devclass; 82650769Sdfr 82750769SdfrDRIVER_MODULE(pnp, isa, pnp_driver, pnp_devclass, 0, 0); 828