1226031Sstas/*- 2226031Sstas * Device driver for Specialix range (SI/XIO) of serial line multiplexors. 3226031Sstas * 4226031Sstas * Copyright (C) 2000, Peter Wemm <peter@netplex.com.au> 5226031Sstas * 6226031Sstas * Redistribution and use in source and binary forms, with or without 7226031Sstas * modification, are permitted provided that the following conditions 8226031Sstas * are met: 9226031Sstas * 1. Redistributions of source code must retain the above copyright 10226031Sstas * notices, this list of conditions and the following disclaimer. 11226031Sstas * 2. Redistributions in binary form must reproduce the above copyright 12226031Sstas * notices, this list of conditions and the following disclaimer in the 13226031Sstas * documentation and/or other materials provided with the distribution. 14226031Sstas * 15226031Sstas * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED 16226031Sstas * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 17226031Sstas * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 18226031Sstas * NO EVENT SHALL THE AUTHORS BE LIABLE. 19226031Sstas * 20226031Sstas */ 21226031Sstas 22226031Sstas#include <sys/cdefs.h> 23226031Sstas__FBSDID("$FreeBSD$"); 24226031Sstas 25226031Sstas#include "opt_debug_si.h" 26226031Sstas 27226031Sstas#include <sys/param.h> 28226031Sstas#include <sys/systm.h> 29226031Sstas#include <sys/kernel.h> 30226031Sstas#include <sys/module.h> 31226031Sstas#include <sys/bus.h> 32226031Sstas#include <machine/bus.h> 33226031Sstas#include <sys/rman.h> 34226031Sstas#include <machine/resource.h> 35226031Sstas 36226031Sstas#include <dev/si/sireg.h> 37226031Sstas#include <dev/si/sivar.h> 38226031Sstas 39226031Sstas#include <isa/isavar.h> 40226031Sstas 41226031Sstas/* Look for a valid board at the given mem addr */ 42226031Sstasstatic int 43226031Sstassi_isa_probe(device_t dev) 44226031Sstas{ 45226031Sstas struct si_softc *sc; 46226031Sstas int type; 47226031Sstas u_int i, ramsize; 48226031Sstas volatile unsigned char was, *ux; 49226031Sstas volatile unsigned char *maddr; 50226031Sstas unsigned char *paddr; 51226031Sstas int unit; 52226031Sstas 53226031Sstas /* No pnp support */ 54226031Sstas if (isa_get_vendorid(dev)) 55226031Sstas return (ENXIO); 56226031Sstas 57226031Sstas sc = device_get_softc(dev); 58226031Sstas unit = device_get_unit(dev); 59226031Sstas 60226031Sstas sc->sc_mem_rid = 0; 61226031Sstas sc->sc_mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, 62226031Sstas &sc->sc_mem_rid, 63226031Sstas 0, ~0, SIPROBEALLOC, RF_ACTIVE); 64226031Sstas if (!sc->sc_mem_res) { 65226031Sstas device_printf(dev, "cannot allocate memory resource\n"); 66226031Sstas return ENXIO; 67226031Sstas } 68226031Sstas paddr = (caddr_t)rman_get_start(sc->sc_mem_res);/* physical */ 69226031Sstas maddr = rman_get_virtual(sc->sc_mem_res); /* in kvm */ 70226031Sstas 71226031Sstas DPRINT((0, DBG_AUTOBOOT, "si%d: probe at virtual=0x%x physical=0x%x\n", 72226031Sstas unit, maddr, paddr)); 73226031Sstas 74226031Sstas /* 75226031Sstas * this is a lie, but it's easier than trying to handle caching 76226031Sstas * and ram conflicts in the >1M and <16M region. 77226031Sstas */ 78226031Sstas if ((caddr_t)paddr < (caddr_t)0xA0000 || 79226031Sstas (caddr_t)paddr >= (caddr_t)0x100000) { 80226031Sstas device_printf(dev, "maddr (%p) out of range\n", paddr); 81226031Sstas goto fail; 82226031Sstas } 83226031Sstas 84226031Sstas if (((uintptr_t)paddr & 0x7fff) != 0) { 85226031Sstas device_printf(dev, "maddr (%p) not on 32k boundary\n", paddr); 86226031Sstas goto fail; 87226031Sstas } 88226031Sstas 89226031Sstas /* Is there anything out there? (0x17 is just an arbitrary number) */ 90226031Sstas *maddr = 0x17; 91226031Sstas if (*maddr != 0x17) { 92226031Sstas device_printf(dev, "0x17 check fail at phys %p\n", paddr); 93226031Sstas goto fail; 94226031Sstas } 95226031Sstas /* 96226031Sstas * Let's look first for a JET ISA card, since that's pretty easy 97226031Sstas * 98226031Sstas * All jet hosts are supposed to have this string in the IDROM, 99226031Sstas * but it's not worth checking on self-IDing busses like PCI. 100226031Sstas */ 101226031Sstas { 102226031Sstas unsigned char *jet_chk_str = "JET HOST BY KEV#"; 103226031Sstas 104226031Sstas for (i = 0; i < strlen(jet_chk_str); i++) 105226031Sstas if (jet_chk_str[i] != *(maddr + SIJETIDSTR + 2 * i)) 106226031Sstas goto try_mk2; 107226031Sstas } 108226031Sstas DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, "si%d: JET first check - 0x%x\n", 109226031Sstas unit, (*(maddr+SIJETIDBASE)))); 110226031Sstas if (*(maddr+SIJETIDBASE) != (SISPLXID&0xff)) 111226031Sstas goto try_mk2; 112226031Sstas DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, "si%d: JET second check - 0x%x\n", 113226031Sstas unit, (*(maddr+SIJETIDBASE+2)))); 114226031Sstas if (*(maddr+SIJETIDBASE+2) != ((SISPLXID&0xff00)>>8)) 115226031Sstas goto try_mk2; 116226031Sstas /* It must be a Jet ISA or RIO card */ 117226031Sstas DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, "si%d: JET id check - 0x%x\n", 118226031Sstas unit, (*(maddr+SIUNIQID)))); 119226031Sstas if ((*(maddr+SIUNIQID) & 0xf0) != 0x20) 120226031Sstas goto try_mk2; 121226031Sstas /* It must be a Jet ISA SI/XIO card */ 122226031Sstas *(maddr + SIJETCONFIG) = 0; 123226031Sstas type = SIJETISA; 124226031Sstas ramsize = SIJET_RAMSIZE; 125226031Sstas goto got_card; 126226031Sstas 127226031Sstastry_mk2: 128226031Sstas /* 129226031Sstas * OK, now to see if whatever responded is really an SI card. 130226031Sstas * Try for a MK II next (SIHOST2) 131226031Sstas */ 132226031Sstas for (i = SIPLSIG; i < SIPLSIG + 8; i++) 133226031Sstas if ((*(maddr+i) & 7) != (~(unsigned char)i & 7)) 134226031Sstas goto try_mk1; 135226031Sstas 136226031Sstas /* It must be an SIHOST2 */ 137226031Sstas *(maddr + SIPLRESET) = 0; 138226031Sstas *(maddr + SIPLIRQCLR) = 0; 139226031Sstas *(maddr + SIPLIRQSET) = 0x10; 140226031Sstas type = SIHOST2; 141226031Sstas ramsize = SIHOST2_RAMSIZE; 142226031Sstas goto got_card; 143226031Sstas 144226031Sstastry_mk1: 145226031Sstas /* 146226031Sstas * Its not a MK II, so try for a MK I (SIHOST) 147226031Sstas */ 148226031Sstas *(maddr+SIRESET) = 0x0; /* reset the card */ 149226031Sstas *(maddr+SIINTCL) = 0x0; /* clear int */ 150226031Sstas *(maddr+SIRAM) = 0x17; 151226031Sstas if (*(maddr+SIRAM) != (unsigned char)0x17) 152226031Sstas goto fail; 153226031Sstas *(maddr+0x7ff8) = 0x17; 154226031Sstas if (*(maddr+0x7ff8) != (unsigned char)0x17) { 155226031Sstas device_printf(dev, "0x17 check fail at phys %p = 0x%x\n", 156226031Sstas paddr+0x77f8, *(maddr+0x77f8)); 157226031Sstas goto fail; 158226031Sstas } 159226031Sstas 160226031Sstas /* It must be an SIHOST (maybe?) - there must be a better way XXX */ 161226031Sstas type = SIHOST; 162226031Sstas ramsize = SIHOST_RAMSIZE; 163226031Sstas 164226031Sstasgot_card: 165226031Sstas DPRINT((0, DBG_AUTOBOOT, "si%d: found type %d card, try memory test\n", 166226031Sstas unit, type)); 167226031Sstas /* Try the acid test */ 168226031Sstas ux = maddr + SIRAM; 169226031Sstas for (i = 0; i < ramsize; i++, ux++) 170226031Sstas *ux = (unsigned char)(i&0xff); 171226031Sstas ux = maddr + SIRAM; 172226031Sstas for (i = 0; i < ramsize; i++, ux++) { 173226031Sstas if ((was = *ux) != (unsigned char)(i&0xff)) { 174226031Sstas device_printf(dev, 175226031Sstas "memtest fail at phys %p, was %x should be %x\n", 176226031Sstas paddr + i, was, i & 0xff); 177226031Sstas goto fail; 178226031Sstas } 179226031Sstas } 180226031Sstas 181226031Sstas /* clear out the RAM */ 182226031Sstas ux = maddr + SIRAM; 183226031Sstas for (i = 0; i < ramsize; i++) 184226031Sstas *ux++ = 0; 185226031Sstas ux = maddr + SIRAM; 186226031Sstas for (i = 0; i < ramsize; i++) { 187226031Sstas if ((was = *ux++) != 0) { 188226031Sstas device_printf(dev, "clear fail at phys %p, was %x\n", 189226031Sstas paddr + i, was); 190226031Sstas goto fail; 191226031Sstas } 192226031Sstas } 193226031Sstas 194226031Sstas /* 195226031Sstas * Success, we've found a valid board, now fill in 196226031Sstas * the adapter structure. 197226031Sstas */ 198226031Sstas switch (type) { 199226031Sstas case SIHOST2: 200226031Sstas switch (isa_get_irq(dev)) { 201226031Sstas case 11: 202226031Sstas case 12: 203226031Sstas case 15: 204226031Sstas break; 205226031Sstas default: 206226031Sstas device_printf(dev, 207226031Sstas "bad IRQ value - %d (11, 12, 15 allowed)\n", 208226031Sstas isa_get_irq(dev)); 209226031Sstas goto fail; 210226031Sstas } 211226031Sstas sc->sc_memsize = SIHOST2_MEMSIZE; 212226031Sstas break; 213226031Sstas case SIHOST: 214226031Sstas switch (isa_get_irq(dev)) { 215226031Sstas case 11: 216226031Sstas case 12: 217226031Sstas case 15: 218226031Sstas break; 219226031Sstas default: 220226031Sstas device_printf(dev, 221226031Sstas "bad IRQ value - %d (11, 12, 15 allowed)\n", 222226031Sstas isa_get_irq(dev)); 223226031Sstas goto fail; 224226031Sstas } 225226031Sstas sc->sc_memsize = SIHOST_MEMSIZE; 226226031Sstas break; 227226031Sstas case SIJETISA: 228226031Sstas switch (isa_get_irq(dev)) { 229226031Sstas case 9: 230226031Sstas case 10: 231226031Sstas case 11: 232226031Sstas case 12: 233226031Sstas case 15: 234226031Sstas break; 235226031Sstas default: 236226031Sstas device_printf(dev, 237226031Sstas "bad IRQ value - %d (9, 10, 11, 12, 15 allowed)\n", 238226031Sstas isa_get_irq(dev)); 239226031Sstas goto fail; 240226031Sstas } 241226031Sstas sc->sc_memsize = SIJETISA_MEMSIZE; 242226031Sstas break; 243226031Sstas case SIMCA: /* MCA */ 244226031Sstas default: 245226031Sstas device_printf(dev, "card type %d not supported\n", type); 246226031Sstas goto fail; 247226031Sstas } 248226031Sstas sc->sc_type = type; 249226031Sstas bus_release_resource(dev, SYS_RES_MEMORY, 250226031Sstas sc->sc_mem_rid, sc->sc_mem_res); 251226031Sstas sc->sc_mem_res = 0; 252226031Sstas return (0); /* success! */ 253226031Sstas 254226031Sstasfail: 255226031Sstas if (sc->sc_mem_res) { 256226031Sstas bus_release_resource(dev, SYS_RES_MEMORY, 257226031Sstas sc->sc_mem_rid, sc->sc_mem_res); 258226031Sstas sc->sc_mem_res = 0; 259226031Sstas } 260226031Sstas return(EINVAL); 261226031Sstas} 262226031Sstas 263226031Sstasstatic int 264226031Sstassi_isa_attach(device_t dev) 265226031Sstas{ 266226031Sstas int error; 267226031Sstas void *ih; 268226031Sstas struct si_softc *sc; 269226031Sstas 270226031Sstas error = 0; 271226031Sstas ih = NULL; 272226031Sstas sc = device_get_softc(dev); 273226031Sstas 274226031Sstas sc->sc_mem_rid = 0; 275226031Sstas sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 276226031Sstas &sc->sc_mem_rid, 277226031Sstas RF_ACTIVE); 278226031Sstas if (!sc->sc_mem_res) { 279226031Sstas device_printf(dev, "couldn't map memory\n"); 280226031Sstas goto fail; 281226031Sstas } 282226031Sstas sc->sc_paddr = (caddr_t)rman_get_start(sc->sc_mem_res); 283226031Sstas sc->sc_maddr = rman_get_virtual(sc->sc_mem_res); 284226031Sstas 285226031Sstas sc->sc_irq_rid = 0; 286226031Sstas sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 287226031Sstas &sc->sc_irq_rid, 288226031Sstas RF_ACTIVE | RF_SHAREABLE); 289226031Sstas if (!sc->sc_irq_res) { 290226031Sstas device_printf(dev, "couldn't allocate interrupt\n"); 291226031Sstas goto fail; 292226031Sstas } 293226031Sstas sc->sc_irq = rman_get_start(sc->sc_irq_res); 294226031Sstas error = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_TTY, 295226031Sstas NULL, si_intr, sc, &ih); 296226031Sstas if (error) { 297226031Sstas device_printf(dev, "couldn't activate interrupt\n"); 298226031Sstas goto fail; 299226031Sstas } 300226031Sstas 301226031Sstas error = siattach(dev); 302226031Sstas if (error) 303226031Sstas goto fail; 304226031Sstas return (0); /* success */ 305226031Sstas 306226031Sstasfail: 307226031Sstas if (error == 0) 308226031Sstas error = ENXIO; 309226031Sstas if (sc->sc_irq_res) { 310226031Sstas if (ih) 311226031Sstas bus_teardown_intr(dev, sc->sc_irq_res, ih); 312226031Sstas bus_release_resource(dev, SYS_RES_IRQ, 313226031Sstas sc->sc_irq_rid, sc->sc_irq_res); 314226031Sstas sc->sc_irq_res = 0; 315226031Sstas } 316226031Sstas if (sc->sc_mem_res) { 317226031Sstas bus_release_resource(dev, SYS_RES_MEMORY, 318226031Sstas sc->sc_mem_rid, sc->sc_mem_res); 319226031Sstas sc->sc_mem_res = 0; 320226031Sstas } 321226031Sstas return (error); 322226031Sstas} 323226031Sstas 324226031Sstasstatic device_method_t si_isa_methods[] = { 325226031Sstas /* Device interface */ 326226031Sstas DEVMETHOD(device_probe, si_isa_probe), 327226031Sstas DEVMETHOD(device_attach, si_isa_attach), 328226031Sstas 329226031Sstas { 0, 0 } 330226031Sstas}; 331226031Sstas 332226031Sstasstatic driver_t si_isa_driver = { 333226031Sstas "si", 334226031Sstas si_isa_methods, 335226031Sstas sizeof(struct si_softc), 336226031Sstas}; 337226031Sstas 338226031SstasDRIVER_MODULE(si, isa, si_isa_driver, si_devclass, 0, 0); 339226031Sstas