[BACK]Return to wbsio.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev / isa

Annotation of src/sys/dev/isa/wbsio.c, Revision 1.7

1.7     ! jakllsch    1: /*     $NetBSD: wbsio.c,v 1.6 2012/01/17 16:34:52 jakllsch Exp $       */
1.1       cnst        2: /*     $OpenBSD: wbsio.c,v 1.5 2009/03/29 21:53:52 sthen Exp $ */
                      3: /*
                      4:  * Copyright (c) 2008 Mark Kettenis <kettenis@openbsd.org>
                      5:  *
                      6:  * Permission to use, copy, modify, and distribute this software for any
                      7:  * purpose with or without fee is hereby granted, provided that the above
                      8:  * copyright notice and this permission notice appear in all copies.
                      9:  *
                     10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     14:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     15:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     16:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     17:  */
                     18:
                     19: /*
                     20:  * Winbond LPC Super I/O driver.
                     21:  */
                     22:
                     23: #include <sys/param.h>
                     24: #include <sys/device.h>
                     25: #include <sys/kernel.h>
1.6       jakllsch   26: #include <sys/module.h>
1.1       cnst       27: #include <sys/systm.h>
                     28:
1.3       dyoung     29: #include <sys/bus.h>
1.1       cnst       30:
                     31: #include <dev/isa/isareg.h>
                     32: #include <dev/isa/isavar.h>
                     33:
                     34: /* ISA bus registers */
                     35: #define WBSIO_INDEX            0x00    /* Configuration Index Register */
                     36: #define WBSIO_DATA             0x01    /* Configuration Data Register */
                     37:
                     38: #define WBSIO_IOSIZE           0x02    /* ISA I/O space size */
                     39:
                     40: #define WBSIO_CONF_EN_MAGIC    0x87    /* enable configuration mode */
                     41: #define WBSIO_CONF_DS_MAGIC    0xaa    /* disable configuration mode */
                     42:
                     43: /* Configuration Space Registers */
                     44: #define WBSIO_LDN              0x07    /* Logical Device Number */
                     45: #define WBSIO_ID               0x20    /* Device ID */
                     46: #define WBSIO_REV              0x21    /* Device Revision */
                     47:
                     48: #define WBSIO_ID_W83627HF      0x52
                     49: #define WBSIO_ID_W83627THF     0x82
                     50: #define WBSIO_ID_W83627EHF     0x88
                     51: #define WBSIO_ID_W83627DHG     0xa0
                     52: #define WBSIO_ID_W83627SF      0x59
                     53: #define WBSIO_ID_W83637HF      0x70
1.2       cnst       54: #define WBSIO_ID_W83667HG      0xa5
1.1       cnst       55: #define WBSIO_ID_W83697HF      0x60
                     56:
                     57: /* Logical Device Number (LDN) Assignments */
                     58: #define WBSIO_LDN_HM           0x0b
                     59:
                     60: /* Hardware Monitor Control Registers (LDN B) */
                     61: #define WBSIO_HM_ADDR_MSB      0x60    /* Address [15:8] */
                     62: #define WBSIO_HM_ADDR_LSB      0x61    /* Address [7:0] */
                     63:
                     64: struct wbsio_softc {
                     65:        struct device           sc_dev;
                     66:
                     67:        bus_space_tag_t         sc_iot;
                     68:        bus_space_handle_t      sc_ioh;
                     69: };
                     70:
                     71: int    wbsio_probe(device_t, cfdata_t, void *);
                     72: void   wbsio_attach(device_t, device_t, void *);
1.5       jakllsch   73: int    wbsio_detach(device_t, int);
                     74: void   wbsio_childdet(device_t, device_t);
1.1       cnst       75: int    wbsio_print(void *, const char *);
                     76:
1.5       jakllsch   77: CFATTACH_DECL2_NEW(wbsio, sizeof(struct wbsio_softc),
                     78:     wbsio_probe, wbsio_attach, wbsio_detach, NULL, NULL, wbsio_childdet);
1.1       cnst       79:
                     80: static __inline void
                     81: wbsio_conf_enable(bus_space_tag_t iot, bus_space_handle_t ioh)
                     82: {
                     83:        bus_space_write_1(iot, ioh, WBSIO_INDEX, WBSIO_CONF_EN_MAGIC);
                     84:        bus_space_write_1(iot, ioh, WBSIO_INDEX, WBSIO_CONF_EN_MAGIC);
                     85: }
                     86:
                     87: static __inline void
                     88: wbsio_conf_disable(bus_space_tag_t iot, bus_space_handle_t ioh)
                     89: {
                     90:        bus_space_write_1(iot, ioh, WBSIO_INDEX, WBSIO_CONF_DS_MAGIC);
                     91: }
                     92:
                     93: static __inline u_int8_t
                     94: wbsio_conf_read(bus_space_tag_t iot, bus_space_handle_t ioh, u_int8_t index)
                     95: {
                     96:        bus_space_write_1(iot, ioh, WBSIO_INDEX, index);
                     97:        return (bus_space_read_1(iot, ioh, WBSIO_DATA));
                     98: }
                     99:
                    100: static __inline void
                    101: wbsio_conf_write(bus_space_tag_t iot, bus_space_handle_t ioh, u_int8_t index,
                    102:     u_int8_t data)
                    103: {
                    104:        bus_space_write_1(iot, ioh, WBSIO_INDEX, index);
                    105:        bus_space_write_1(iot, ioh, WBSIO_DATA, data);
                    106: }
                    107:
                    108: int
                    109: wbsio_probe(device_t parent, cfdata_t match, void *aux)
                    110: {
                    111:        struct isa_attach_args *ia = aux;
                    112:        bus_space_tag_t iot;
                    113:        bus_space_handle_t ioh;
                    114:        u_int8_t reg;
                    115:
                    116:        /* Must supply an address */
                    117:        if (ia->ia_nio < 1)
                    118:                return 0;
                    119:
                    120:        if (ISA_DIRECT_CONFIG(ia))
                    121:                return 0;
                    122:
                    123:        if (ia->ia_io[0].ir_addr == ISA_UNKNOWN_PORT)
                    124:                return 0;
                    125:
                    126:        /* Match by device ID */
                    127:        iot = ia->ia_iot;
                    128:        if (bus_space_map(iot, ia->ia_io[0].ir_addr, WBSIO_IOSIZE, 0, &ioh))
                    129:                return 0;
                    130:        wbsio_conf_enable(iot, ioh);
                    131:        reg = wbsio_conf_read(iot, ioh, WBSIO_ID);
                    132:        aprint_debug("wbsio_probe: id 0x%02x\n", reg);
                    133:        wbsio_conf_disable(iot, ioh);
                    134:        bus_space_unmap(iot, ioh, WBSIO_IOSIZE);
                    135:        switch (reg) {
                    136:        case WBSIO_ID_W83627HF:
                    137:        case WBSIO_ID_W83627THF:
                    138:        case WBSIO_ID_W83627EHF:
                    139:        case WBSIO_ID_W83627DHG:
                    140:        case WBSIO_ID_W83637HF:
                    141:        case WBSIO_ID_W83697HF:
                    142:                ia->ia_nio = 1;
                    143:                ia->ia_io[0].ir_size = WBSIO_IOSIZE;
                    144:                ia->ia_niomem = 0;
                    145:                ia->ia_nirq = 0;
                    146:                ia->ia_ndrq = 0;
                    147:                return 1;
                    148:        }
                    149:
                    150:        return 0;
                    151: }
                    152:
                    153: void
                    154: wbsio_attach(device_t parent, device_t self, void *aux)
                    155: {
                    156:        struct wbsio_softc *sc = (void *)self;
                    157:        struct isa_attach_args *ia = aux;
                    158:        struct isa_attach_args nia;
                    159:        const char *desc = NULL;
                    160:        u_int8_t reg, reg0, reg1;
                    161:        u_int16_t iobase;
                    162:
                    163:        /* Map ISA I/O space */
                    164:        sc->sc_iot = ia->ia_iot;
                    165:        if (bus_space_map(sc->sc_iot, ia->ia_io[0].ir_addr,
                    166:            WBSIO_IOSIZE, 0, &sc->sc_ioh)) {
                    167:                aprint_error(": can't map i/o space\n");
                    168:                return;
                    169:        }
                    170:
                    171:        /* Enter configuration mode */
                    172:        wbsio_conf_enable(sc->sc_iot, sc->sc_ioh);
                    173:
                    174:        /* Read device ID */
                    175:        reg = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_ID);
                    176:        switch (reg) {
                    177:        case WBSIO_ID_W83627HF:
                    178:                desc = "W83627HF";
                    179:                break;
                    180:        case WBSIO_ID_W83627THF:
                    181:                desc = "W83627THF";
                    182:                break;
                    183:        case WBSIO_ID_W83627EHF:
                    184:                desc = "W83627EHF";
                    185:                break;
                    186:        case WBSIO_ID_W83627DHG:
                    187:                desc = "W83627DHG";
                    188:                break;
                    189:        case WBSIO_ID_W83637HF:
                    190:                desc = "W83637HF";
                    191:                break;
1.2       cnst      192:        case WBSIO_ID_W83667HG:
                    193:                desc = "W83667HG";
                    194:                break;
1.1       cnst      195:        case WBSIO_ID_W83697HF:
                    196:                desc = "W83697HF";
                    197:                break;
                    198:        }
                    199:
                    200:        /* Read device revision */
                    201:        reg = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_REV);
                    202:
                    203:        aprint_naive("\n");
                    204:        aprint_normal(": Winbond LPC Super I/O %s rev 0x%02x\n", desc, reg);
                    205:
                    206:        /* Select HM logical device */
                    207:        wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_HM);
                    208:
                    209:        /*
                    210:         * The address should be 8-byte aligned, but it seems some
                    211:         * BIOSes ignore this.  They get away with it, because
                    212:         * Apparently the hardware simply ignores the lower three
                    213:         * bits.  We do the same here.
                    214:         */
                    215:        reg0 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_HM_ADDR_LSB);
                    216:        reg1 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_HM_ADDR_MSB);
                    217:        iobase = (reg1 << 8) | (reg0 & ~0x7);
                    218:
                    219:        /* Escape from configuration mode */
                    220:        wbsio_conf_disable(sc->sc_iot, sc->sc_ioh);
                    221:
1.4       jakllsch  222:        if (!pmf_device_register(self, NULL, NULL))
                    223:                aprint_error_dev(self, "couldn't establish power handler\n");
                    224:
1.1       cnst      225:        if (iobase == 0)
                    226:                return;
                    227:
                    228:        nia = *ia;
                    229:        nia.ia_io[0].ir_addr = iobase;
                    230:        config_found(self, &nia, wbsio_print);
                    231: }
                    232:
                    233: int
1.5       jakllsch  234: wbsio_detach(device_t self, int flags)
                    235: {
                    236:        int rc;
                    237:
                    238:        if ((rc = config_detach_children(self, flags)) != 0)
                    239:                return rc;
                    240:        bus_space_unmap(sc->sc_iot, sc->sc_ioh, WBSIO_IOSIZE);
                    241:        pmf_device_deregister(self);
                    242:        return 0;
                    243: }
                    244:
                    245: void
                    246: wbsio_childdet(device_t self, device_t child)
                    247: {
                    248:        return;
                    249: }
                    250:
                    251: int
1.1       cnst      252: wbsio_print(void *aux, const char *pnp)
                    253: {
                    254:        struct isa_attach_args *ia = aux;
                    255:
                    256:        if (pnp)
                    257:                aprint_normal("%s", pnp);
                    258:        if (ia->ia_io[0].ir_size)
                    259:                aprint_normal(" port 0x%x", ia->ia_io[0].ir_addr);
                    260:        if (ia->ia_io[0].ir_size > 1)
                    261:                aprint_normal("-0x%x", ia->ia_io[0].ir_addr +
                    262:                    ia->ia_io[0].ir_size - 1);
                    263:        return (UNCONF);
                    264: }
1.6       jakllsch  265:
1.7     ! jakllsch  266: MODULE(MODULE_CLASS_DRIVER, wbsio, NULL);
1.6       jakllsch  267:
                    268: #ifdef _MODULE
                    269: #include "ioconf.c"
                    270: #endif
                    271:
                    272: static int
                    273: wbsio_modcmd(modcmd_t cmd, void *opaque)
                    274: {
                    275:        switch (cmd) {
                    276:        case MODULE_CMD_INIT:
                    277: #ifdef _MODULE
                    278:                return config_init_component(cfdriver_ioconf_wbsio,
                    279:                    cfattach_ioconf_wbsio, cfdata_ioconf_wbsio);
                    280: #else
                    281:                return 0;
                    282: #endif
                    283:        case MODULE_CMD_FINI:
                    284: #ifdef _MODULE
                    285:                return config_fini_component(cfdriver_ioconf_wbsio,
                    286:                    cfattach_ioconf_wbsio, cfdata_ioconf_wbsio);
                    287: #else
                    288:                return 0;
                    289: #endif
                    290:        default:
                    291:                return ENOTTY;
                    292:        }
                    293: }

CVSweb <webmaster@jp.NetBSD.org>