1 /* 2 * Copyright (c) 2005, 2006 Mark Kettenis 3 * Copyright (c) 2007 Constantine A. Murenin, Google Summer of Code 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 * 17 * $OpenBSD: lm78_isa.c,v 1.2 2007/07/01 21:48:57 cnst Exp $ 18 */ 19 20 #include <sys/param.h> 21 #include <sys/kernel.h> 22 #include <sys/bus.h> 23 #include <sys/module.h> 24 25 #include <sys/module.h> 26 #include <sys/bus.h> 27 #include <sys/rman.h> 28 29 #include <bus/isa/isavar.h> 30 31 #include <sys/systm.h> 32 33 #include <sys/sensors.h> 34 35 #include "lm78var.h" 36 37 /* ISA registers */ 38 #define LMC_ADDR 0x05 39 #define LMC_DATA 0x06 40 41 #if defined(LMDEBUG) 42 #define DPRINTF(x) do { kprintf x; } while (0) 43 #else 44 #define DPRINTF(x) 45 #endif 46 47 struct lm_isa_softc { 48 struct lm_softc sc_lmsc; 49 50 struct resource *sc_iores; 51 int sc_iorid; 52 bus_space_tag_t sc_iot; 53 bus_space_handle_t sc_ioh; 54 }; 55 56 static int lm_isa_probe(struct device *); 57 static int lm_isa_attach(struct device *); 58 static int lm_isa_detach(struct device *); 59 u_int8_t lm_isa_readreg(struct lm_softc *, int); 60 void lm_isa_writereg(struct lm_softc *, int, int); 61 62 static device_method_t lm_isa_methods[] = { 63 /* Methods from the device interface */ 64 DEVMETHOD(device_probe, lm_isa_probe), 65 DEVMETHOD(device_attach, lm_isa_attach), 66 DEVMETHOD(device_detach, lm_isa_detach), 67 68 /* Terminate method list */ 69 DEVMETHOD_END 70 }; 71 72 static driver_t lm_isa_driver = { 73 "lm", 74 lm_isa_methods, 75 sizeof (struct lm_isa_softc) 76 }; 77 78 static devclass_t lm_devclass; 79 80 DRIVER_MODULE(lm, isa, lm_isa_driver, lm_devclass, NULL, NULL); 81 82 int 83 lm_isa_probe(struct device *dev) 84 { 85 struct lm_isa_softc *sc = device_get_softc(dev); 86 struct resource *iores; 87 int iorid = 0; 88 bus_space_tag_t iot; 89 bus_space_handle_t ioh; 90 int banksel, vendid, chipid, addr; 91 92 iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &iorid, 93 0ul, ~0ul, 8, RF_ACTIVE); 94 if (iores == NULL) { 95 DPRINTF(("%s: can't map i/o space\n", __func__)); 96 return (1); 97 } 98 iot = rman_get_bustag(iores); 99 ioh = rman_get_bushandle(iores); 100 101 /* Probe for Winbond chips. */ 102 bus_space_write_1(iot, ioh, LMC_ADDR, WB_BANKSEL); 103 banksel = bus_space_read_1(iot, ioh, LMC_DATA); 104 bus_space_write_1(iot, ioh, LMC_ADDR, WB_VENDID); 105 vendid = bus_space_read_1(iot, ioh, LMC_DATA); 106 if (((banksel & 0x80) && vendid == (WB_VENDID_WINBOND >> 8)) || 107 (!(banksel & 0x80) && vendid == (WB_VENDID_WINBOND & 0xff))) 108 goto found; 109 110 /* Probe for ITE chips (and don't attach if we find one). */ 111 bus_space_write_1(iot, ioh, LMC_ADDR, 0x58 /*ITD_CHIPID*/); 112 vendid = bus_space_read_1(iot, ioh, LMC_DATA); 113 if (vendid == 0x90 /*IT_ID_IT87*/) 114 goto notfound; 115 116 /* 117 * Probe for National Semiconductor LM78/79/81. 118 * 119 * XXX This assumes the address has not been changed from the 120 * power up default. This is probably a reasonable 121 * assumption, and if it isn't true, we should be able to 122 * access the chip using the serial bus. 123 */ 124 bus_space_write_1(iot, ioh, LMC_ADDR, LM_SBUSADDR); 125 addr = bus_space_read_1(iot, ioh, LMC_DATA); 126 if ((addr & 0xfc) == 0x2c) { 127 bus_space_write_1(iot, ioh, LMC_ADDR, LM_CHIPID); 128 chipid = bus_space_read_1(iot, ioh, LMC_DATA); 129 130 switch (chipid & LM_CHIPID_MASK) { 131 case LM_CHIPID_LM78: 132 case LM_CHIPID_LM78J: 133 case LM_CHIPID_LM79: 134 case LM_CHIPID_LM81: 135 goto found; 136 } 137 } 138 139 notfound: 140 bus_release_resource(dev, SYS_RES_IOPORT, iorid, iores); 141 142 return (1); 143 144 found: 145 /* Bus-independent probe */ 146 sc->sc_lmsc.sc_dev = dev; 147 sc->sc_iot = iot; 148 sc->sc_ioh = ioh; 149 sc->sc_lmsc.lm_writereg = lm_isa_writereg; 150 sc->sc_lmsc.lm_readreg = lm_isa_readreg; 151 lm_probe(&sc->sc_lmsc); 152 153 bus_release_resource(dev, SYS_RES_IOPORT, iorid, iores); 154 sc->sc_iot = 0; 155 sc->sc_ioh = 0; 156 157 return (0); 158 } 159 160 int 161 lm_isa_attach(struct device *dev) 162 { 163 struct lm_isa_softc *sc = device_get_softc(dev); 164 #ifdef notyet 165 struct lm_softc *lmsc; 166 int i; 167 u_int8_t sbusaddr; 168 #endif 169 170 sc->sc_iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_iorid, 171 0ul, ~0ul, 8, RF_ACTIVE); 172 if (sc->sc_iores == NULL) { 173 device_printf(dev, "can't map i/o space\n"); 174 return (1); 175 } 176 sc->sc_iot = rman_get_bustag(sc->sc_iores); 177 sc->sc_ioh = rman_get_bushandle(sc->sc_iores); 178 179 /* Bus-independent attachment */ 180 lm_attach(&sc->sc_lmsc); 181 182 #ifdef notyet 183 /* 184 * Most devices supported by this driver can attach to iic(4) 185 * as well. However, we prefer to attach them to isa(4) since 186 * that causes less overhead and is more reliable. We look 187 * through all previously attached devices, and if we find an 188 * identical chip at the same serial bus address, we stop 189 * updating its sensors and mark them as invalid. 190 */ 191 192 sbusaddr = lm_isa_readreg(&sc->sc_lmsc, LM_SBUSADDR); 193 if (sbusaddr == 0) 194 return (0); 195 196 for (i = 0; i < lm_cd.cd_ndevs; i++) { 197 lmsc = lm_cd.cd_devs[i]; 198 if (lmsc == &sc->sc_lmsc) 199 continue; 200 if (lmsc && lmsc->sbusaddr == sbusaddr && 201 lmsc->chipid == sc->sc_lmsc.chipid) 202 config_detach(&lmsc->sc_dev, 0); 203 } 204 #endif 205 return (0); 206 } 207 208 int 209 lm_isa_detach(struct device *dev) 210 { 211 struct lm_isa_softc *sc = device_get_softc(dev); 212 int error; 213 214 /* Bus-independent detachment */ 215 error = lm_detach(&sc->sc_lmsc); 216 if (error) 217 return (error); 218 219 error = bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_iorid, 220 sc->sc_iores); 221 if (error) 222 return (error); 223 224 return (0); 225 } 226 227 u_int8_t 228 lm_isa_readreg(struct lm_softc *lmsc, int reg) 229 { 230 struct lm_isa_softc *sc = (struct lm_isa_softc *)lmsc; 231 232 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LMC_ADDR, reg); 233 return (bus_space_read_1(sc->sc_iot, sc->sc_ioh, LMC_DATA)); 234 } 235 236 void 237 lm_isa_writereg(struct lm_softc *lmsc, int reg, int val) 238 { 239 struct lm_isa_softc *sc = (struct lm_isa_softc *)lmsc; 240 241 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LMC_ADDR, reg); 242 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LMC_DATA, val); 243 } 244