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

Annotation of src/sys/dev/ic/spic.c, Revision 1.9

1.9     ! ad          1: /*     $NetBSD: spic.c,v 1.8 2007/07/09 21:00:39 ad Exp $      */
1.1       augustss    2:
                      3: /*
                      4:  * Copyright (c) 2002 The NetBSD Foundation, Inc.
                      5:  * All rights reserved.
                      6:  *
                      7:  * This code is derived from software contributed to The NetBSD Foundation
                      8:  * by Lennart Augustsson (lennart@augustsson.net) at
                      9:  * Carlstedt Research & Technology.
                     10:  *
                     11:  * Redistribution and use in source and binary forms, with or without
                     12:  * modification, are permitted provided that the following conditions
                     13:  * are met:
                     14:  * 1. Redistributions of source code must retain the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer.
                     16:  * 2. Redistributions in binary form must reproduce the above copyright
                     17:  *    notice, this list of conditions and the following disclaimer in the
                     18:  *    documentation and/or other materials provided with the distribution.
                     19:  * 3. All advertising materials mentioning features or use of this software
                     20:  *    must display the following acknowledgement:
                     21:  *        This product includes software developed by the NetBSD
                     22:  *        Foundation, Inc. and its contributors.
                     23:  * 4. Neither the name of The NetBSD Foundation nor the names of its
                     24:  *    contributors may be used to endorse or promote products derived
                     25:  *    from this software without specific prior written permission.
                     26:  *
                     27:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     28:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     29:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     30:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     31:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     32:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     33:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     34:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     35:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     36:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     37:  * POSSIBILITY OF SUCH DAMAGE.
                     38:  */
                     39:
                     40: /*
                     41:  * The SPIC is used on some Sony Vaios to handle the jog dial and other
                     42:  * peripherals.
                     43:  * The protocol used by the SPIC seems to vary wildly among the different
                     44:  * models, and I've found no documentation.
                     45:  * This file handles the jog dial on the SRX77 model, and perhaps nothing
                     46:  * else.
                     47:  *
                     48:  * The general way of talking to the SPIC was gleaned from the Linux and
                     49:  * FreeBSD drivers.  The hex numbers were taken from these drivers (they
                     50:  * come from reverese engineering.)
                     51:  *
                     52:  * TODO:
                     53:  *   Make it handle more models.
                     54:  *   Figure out why the interrupt mode doesn't work.
                     55:  */
                     56:
                     57:
                     58: #include <sys/cdefs.h>
1.9     ! ad         59: __KERNEL_RCSID(0, "$NetBSD: spic.c,v 1.8 2007/07/09 21:00:39 ad Exp $");
1.1       augustss   60:
                     61: #include <sys/param.h>
                     62: #include <sys/systm.h>
                     63: #include <sys/device.h>
                     64: #include <sys/proc.h>
                     65: #include <sys/kernel.h>
                     66: #include <sys/callout.h>
                     67:
1.9     ! ad         68: #include <sys/bus.h>
1.1       augustss   69:
1.3       jmcneill   70: #include <dev/sysmon/sysmonvar.h>
                     71:
1.1       augustss   72: #include <dev/ic/spicvar.h>
                     73:
                     74: #include <dev/wscons/wsconsio.h>
                     75: #include <dev/wscons/wsmousevar.h>
                     76:
                     77: #define POLLRATE (hz/30)
                     78:
                     79: /* Some hardware constants */
                     80: #define SPIC_PORT1 0
                     81: #define SPIC_PORT2 4
                     82:
                     83: #ifdef SPIC_DEBUG
                     84: int spicdebug = 0;
                     85: #endif
                     86:
1.3       jmcneill   87: static int spicerror = 0;
                     88:
1.1       augustss   89: static int     spic_enable(void *);
                     90: static void    spic_disable(void *);
1.7       christos   91: static int     spic_ioctl(void *, u_long, void *, int, struct lwp *);
1.1       augustss   92:
                     93: static const struct wsmouse_accessops spic_accessops = {
                     94:        spic_enable,
                     95:        spic_ioctl,
                     96:        spic_disable,
                     97: };
                     98:
                     99: #define SPIC_COMMAND(quiet, command) do { \
                    100:        unsigned int n = 10000; \
                    101:        while (--n && (command)) \
                    102:                delay(1); \
1.3       jmcneill  103:        if (n == 0 && !(quiet)) { \
                    104:                printf("spic0: command failed at line %d\n", __LINE__); \
                    105:                spicerror++; \
                    106:        } \
1.1       augustss  107: } while (0)
                    108:
                    109: #if 0
                    110: #define INB(sc, p) (delay(100), printf("inb(%x)=%x\n", (uint)sc->sc_ioh+p, bus_space_read_1(sc->sc_iot, sc->sc_ioh, p)), delay(100), bus_space_read_1(sc->sc_iot, sc->sc_ioh, (p)))
                    111: #define OUTB(sc, v, p) do { delay(100); bus_space_write_1(sc->sc_iot, sc->sc_ioh, (p), (v)); printf("outb(%x, %x)\n", (uint)sc->sc_ioh+p, v); } while(0)
                    112: #else
                    113: #define INB(sc, p) (delay(100), bus_space_read_1(sc->sc_iot, sc->sc_ioh, (p)))
                    114: #define OUTB(sc, v, p) do { delay(100); bus_space_write_1(sc->sc_iot, sc->sc_ioh, (p), (v)); } while(0)
                    115: #endif
                    116:
                    117: static u_int8_t
                    118: spic_call1(struct spic_softc *sc, u_int8_t dev)
                    119: {
                    120:        u_int8_t v1, v2;
                    121:
                    122:        SPIC_COMMAND(0, INB(sc, SPIC_PORT2) & 2);
                    123:        OUTB(sc, dev, SPIC_PORT2);
                    124:        v1 = INB(sc, SPIC_PORT2);
                    125:        v2 = INB(sc, SPIC_PORT1);
                    126:        return v2;
                    127: }
                    128:
                    129: static u_int8_t
                    130: spic_call2(struct spic_softc *sc, u_int8_t dev, u_int8_t fn)
                    131: {
                    132:        u_int8_t v1;
                    133:
                    134:        SPIC_COMMAND(0, INB(sc, SPIC_PORT2) & 2);
                    135:        OUTB(sc, dev, SPIC_PORT2);
                    136:        SPIC_COMMAND(0, INB(sc, SPIC_PORT2) & 2);
                    137:        OUTB(sc, fn, SPIC_PORT1);
                    138:        v1 = INB(sc, SPIC_PORT1);
                    139:        return v1;
                    140: }
                    141:
                    142: /* Interrupt handler: some event is available */
                    143: int
                    144: spic_intr(void *v) {
                    145:        struct spic_softc *sc = v;
                    146:        u_int8_t v1, v2;
                    147:        int dz, buttons;
                    148:
                    149:        v1 = INB(sc, SPIC_PORT1);
                    150:        v2 = INB(sc, SPIC_PORT2);
                    151:
1.3       jmcneill  152:        /* Handle lid switch */
                    153:        if (v2 == 0x30) {
                    154:                switch (v1) {
                    155:                case 0x50:      /* opened */
                    156:                        sysmon_pswitch_event(&sc->sc_smpsw[SPIC_PSWITCH_LID],
                    157:                            PSWITCH_EVENT_RELEASED);
                    158:                        goto skip;
                    159:                        break;
                    160:                case 0x51:      /* closed */
                    161:                        sysmon_pswitch_event(&sc->sc_smpsw[SPIC_PSWITCH_LID],
                    162:                            PSWITCH_EVENT_PRESSED);
                    163:                        goto skip;
                    164:                        break;
                    165:                default:
                    166:                        aprint_debug("%s: unknown lid event 0x%02x\n",
                    167:                            sc->sc_dev.dv_xname, v1);
                    168:                        goto skip;
                    169:                        break;
                    170:                }
                    171:        }
                    172:
                    173:        /* Handle suspend/hibernate buttons */
                    174:        if (v2 == 0x20) {
                    175:                switch (v1) {
                    176:                case 0x10:      /* suspend */
                    177:                        sysmon_pswitch_event(
                    178:                            &sc->sc_smpsw[SPIC_PSWITCH_SUSPEND],
                    179:                            PSWITCH_EVENT_PRESSED);
                    180:                        goto skip;
                    181:                        break;
                    182:                case 0x1c:      /* hibernate */
                    183:                        sysmon_pswitch_event(
                    184:                            &sc->sc_smpsw[SPIC_PSWITCH_HIBERNATE],
                    185:                            PSWITCH_EVENT_PRESSED);
                    186:                        goto skip;
                    187:                        break;
                    188:                }
                    189:        }
                    190:
1.1       augustss  191:        buttons = 0;
                    192:        if (v1 & 0x40)
                    193:                buttons |= 1 << 1;
                    194:        if (v1 & 0x20)
                    195:                buttons |= 1 << 5;
                    196:        dz = v1 & 0x1f;
                    197:        switch (dz) {
                    198:        case 0:
                    199:        case 1:
                    200:        case 2:
                    201:        case 3:
                    202:                break;
                    203:        case 0x1f:
                    204:        case 0x1e:
                    205:        case 0x1d:
                    206:                dz -= 0x20;
                    207:                break;
                    208:        default:
1.3       jmcneill  209:                printf("spic0: v1=0x%02x v2=0x%02x\n", v1, v2);
1.1       augustss  210:                goto skip;
                    211:        }
                    212:
                    213:        if (!sc->sc_enabled) {
                    214:                /*printf("spic: not enabled\n");*/
                    215:                goto skip;
                    216:        }
                    217:
                    218:        if (dz != 0 || buttons != sc->sc_buttons) {
                    219: #ifdef SPIC_DEBUG
                    220:                if (spicdebug)
                    221:                        printf("spic: but=0x%x dz=%d v1=0x%02x v2=0x%02x\n",
                    222:                               buttons, dz, v1, v2);
                    223: #endif
                    224:                sc->sc_buttons = buttons;
                    225:                if (sc->sc_wsmousedev != NULL) {
1.5       plunky    226:                        wsmouse_input(sc->sc_wsmousedev, buttons, 0, 0, dz, 0,
1.1       augustss  227:                                      WSMOUSE_INPUT_DELTA);
                    228:                }
                    229:        }
                    230:
                    231: skip:
                    232:        spic_call2(sc, 0x81, 0xff); /* Clear event */
                    233:        return (1);
                    234: }
                    235:
                    236: static void
                    237: spictimeout(void *v)
                    238: {
                    239:        struct spic_softc *sc = v;
1.3       jmcneill  240:        int s;
                    241:
                    242:        if (spicerror >= 3)
                    243:                return;
                    244:
                    245:        s = spltty();
1.1       augustss  246:        spic_intr(v);
                    247:        splx(s);
                    248:        callout_reset(&sc->sc_poll, POLLRATE, spictimeout, sc);
                    249: }
                    250:
                    251: void
                    252: spic_attach(struct spic_softc *sc)
                    253: {
                    254:        struct wsmousedev_attach_args a;
1.3       jmcneill  255:        int i, rv;
1.1       augustss  256:
                    257: #ifdef SPIC_DEBUG
                    258:        if (spicdebug)
                    259:                printf("spic_attach %x %x\n", sc->sc_iot, (uint)sc->sc_ioh);
                    260: #endif
                    261:
1.8       ad        262:        callout_init(&sc->sc_poll, 0);
1.1       augustss  263:
                    264:        spic_call1(sc, 0x82);
                    265:        spic_call2(sc, 0x81, 0xff);
                    266:        spic_call1(sc, 0x92);   /* or 0x82 */
                    267:
                    268:        a.accessops = &spic_accessops;
                    269:        a.accesscookie = sc;
                    270:        sc->sc_wsmousedev = config_found(&sc->sc_dev, &a, wsmousedevprint);
1.3       jmcneill  271:
                    272:        sc->sc_smpsw[SPIC_PSWITCH_LID].smpsw_name = "spiclid0";
                    273:        sc->sc_smpsw[SPIC_PSWITCH_LID].smpsw_type = PSWITCH_TYPE_LID;
                    274:        sc->sc_smpsw[SPIC_PSWITCH_SUSPEND].smpsw_name = "spicsuspend0";
                    275:        sc->sc_smpsw[SPIC_PSWITCH_SUSPEND].smpsw_type = PSWITCH_TYPE_SLEEP;
                    276:        sc->sc_smpsw[SPIC_PSWITCH_HIBERNATE].smpsw_name = "spichibernate0";
                    277:        sc->sc_smpsw[SPIC_PSWITCH_HIBERNATE].smpsw_type = PSWITCH_TYPE_SLEEP;
                    278:
                    279:        for (i = 0; i < SPIC_NPSWITCH; i++) {
                    280:                rv = sysmon_pswitch_register(&sc->sc_smpsw[i]);
                    281:                if (rv != 0)
                    282:                        aprint_error("%s: unable to register %s with sysmon\n",
                    283:                            sc->sc_dev.dv_xname,
                    284:                            sc->sc_smpsw[i].smpsw_name);
                    285:        }
                    286:
                    287:        callout_reset(&sc->sc_poll, POLLRATE, spictimeout, sc);
                    288:
                    289:        return;
1.1       augustss  290: }
                    291:
                    292:
                    293: static int
                    294: spic_enable(void *v)
                    295: {
                    296:        struct spic_softc *sc = v;
                    297:
                    298:        if (sc->sc_enabled)
                    299:                return (EBUSY);
                    300:
                    301:        sc->sc_enabled = 1;
                    302:        sc->sc_buttons = 0;
                    303:
                    304: #ifdef SPIC_DEBUG
                    305:        if (spicdebug)
                    306:                printf("spic_enable\n");
                    307: #endif
                    308:
                    309:        return (0);
                    310: }
                    311:
                    312: static void
                    313: spic_disable(void *v)
                    314: {
                    315:        struct spic_softc *sc = v;
                    316:
                    317: #ifdef DIAGNOSTIC
                    318:        if (!sc->sc_enabled) {
                    319:                printf("spic_disable: not enabled\n");
                    320:                return;
                    321:        }
                    322: #endif
                    323:
                    324:        sc->sc_enabled = 0;
                    325:
                    326: #ifdef SPIC_DEBUG
                    327:        if (spicdebug)
                    328:                printf("spic_disable\n");
                    329: #endif
                    330: }
                    331:
                    332: static int
1.7       christos  333: spic_ioctl(void *v, u_long cmd, void *data,
1.6       christos  334:     int flag, struct lwp *l)
1.1       augustss  335: {
                    336:        switch (cmd) {
                    337:        case WSMOUSEIO_GTYPE:
                    338:                /* XXX this is not really correct */
                    339:                *(u_int *)data = WSMOUSE_TYPE_PS2;
                    340:                return (0);
                    341:        }
                    342:
                    343:        return (-1);
                    344: }

CVSweb <webmaster@jp.NetBSD.org>