1 /* $NetBSD: spic.c,v 1.1 2002/04/22 12:42:11 augustss Exp $ */ 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> 59 __KERNEL_RCSID(0, "$NetBSD: spic.c,v 1.1 2002/04/22 12:42:11 augustss Exp $"); 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 68 #include <machine/bus.h> 69 70 #include <dev/ic/spicvar.h> 71 72 #include <dev/wscons/wsconsio.h> 73 #include <dev/wscons/wsmousevar.h> 74 75 #define POLLRATE (hz/30) 76 77 /* Some hardware constants */ 78 #define SPIC_PORT1 0 79 #define SPIC_PORT2 4 80 81 #ifdef SPIC_DEBUG 82 int spicdebug = 0; 83 #endif 84 85 static int spic_enable(void *); 86 static void spic_disable(void *); 87 static int spic_ioctl(void *, u_long, caddr_t, int, struct proc *); 88 89 static const struct wsmouse_accessops spic_accessops = { 90 spic_enable, 91 spic_ioctl, 92 spic_disable, 93 }; 94 95 #define SPIC_COMMAND(quiet, command) do { \ 96 unsigned int n = 10000; \ 97 while (--n && (command)) \ 98 delay(1); \ 99 if (n == 0 && !(quiet)) \ 100 printf("spic: command failed at line %d\n", __LINE__); \ 101 } while (0) 102 103 #if 0 104 #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))) 105 #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) 106 #else 107 #define INB(sc, p) (delay(100), bus_space_read_1(sc->sc_iot, sc->sc_ioh, (p))) 108 #define OUTB(sc, v, p) do { delay(100); bus_space_write_1(sc->sc_iot, sc->sc_ioh, (p), (v)); } while(0) 109 #endif 110 111 static u_int8_t 112 spic_call1(struct spic_softc *sc, u_int8_t dev) 113 { 114 u_int8_t v1, v2; 115 116 SPIC_COMMAND(0, INB(sc, SPIC_PORT2) & 2); 117 OUTB(sc, dev, SPIC_PORT2); 118 v1 = INB(sc, SPIC_PORT2); 119 v2 = INB(sc, SPIC_PORT1); 120 return v2; 121 } 122 123 static u_int8_t 124 spic_call2(struct spic_softc *sc, u_int8_t dev, u_int8_t fn) 125 { 126 u_int8_t v1; 127 128 SPIC_COMMAND(0, INB(sc, SPIC_PORT2) & 2); 129 OUTB(sc, dev, SPIC_PORT2); 130 SPIC_COMMAND(0, INB(sc, SPIC_PORT2) & 2); 131 OUTB(sc, fn, SPIC_PORT1); 132 v1 = INB(sc, SPIC_PORT1); 133 return v1; 134 } 135 136 /* Interrupt handler: some event is available */ 137 int 138 spic_intr(void *v) { 139 struct spic_softc *sc = v; 140 u_int8_t v1, v2; 141 int dz, buttons; 142 143 v1 = INB(sc, SPIC_PORT1); 144 v2 = INB(sc, SPIC_PORT2); 145 146 buttons = 0; 147 if (v1 & 0x40) 148 buttons |= 1 << 1; 149 if (v1 & 0x20) 150 buttons |= 1 << 5; 151 dz = v1 & 0x1f; 152 switch (dz) { 153 case 0: 154 case 1: 155 case 2: 156 case 3: 157 break; 158 case 0x1f: 159 case 0x1e: 160 case 0x1d: 161 dz -= 0x20; 162 break; 163 default: 164 printf("spic: v1=0x%02x v2=0x%02x\n", v1, v2); 165 goto skip; 166 } 167 168 if (!sc->sc_enabled) { 169 /*printf("spic: not enabled\n");*/ 170 goto skip; 171 } 172 173 if (dz != 0 || buttons != sc->sc_buttons) { 174 #ifdef SPIC_DEBUG 175 if (spicdebug) 176 printf("spic: but=0x%x dz=%d v1=0x%02x v2=0x%02x\n", 177 buttons, dz, v1, v2); 178 #endif 179 sc->sc_buttons = buttons; 180 if (sc->sc_wsmousedev != NULL) { 181 wsmouse_input(sc->sc_wsmousedev, buttons, 0, 0, dz, 182 WSMOUSE_INPUT_DELTA); 183 } 184 } 185 186 skip: 187 spic_call2(sc, 0x81, 0xff); /* Clear event */ 188 return (1); 189 } 190 191 static void 192 spictimeout(void *v) 193 { 194 struct spic_softc *sc = v; 195 int s = spltty(); 196 spic_intr(v); 197 splx(s); 198 callout_reset(&sc->sc_poll, POLLRATE, spictimeout, sc); 199 } 200 201 void 202 spic_attach(struct spic_softc *sc) 203 { 204 struct wsmousedev_attach_args a; 205 206 #ifdef SPIC_DEBUG 207 if (spicdebug) 208 printf("spic_attach %x %x\n", sc->sc_iot, (uint)sc->sc_ioh); 209 #endif 210 211 callout_init(&sc->sc_poll); 212 213 spic_call1(sc, 0x82); 214 spic_call2(sc, 0x81, 0xff); 215 spic_call1(sc, 0x92); /* or 0x82 */ 216 217 a.accessops = &spic_accessops; 218 a.accesscookie = sc; 219 sc->sc_wsmousedev = config_found(&sc->sc_dev, &a, wsmousedevprint); 220 } 221 222 223 static int 224 spic_enable(void *v) 225 { 226 struct spic_softc *sc = v; 227 228 if (sc->sc_enabled) 229 return (EBUSY); 230 231 sc->sc_enabled = 1; 232 sc->sc_buttons = 0; 233 234 #ifdef SPIC_DEBUG 235 if (spicdebug) 236 printf("spic_enable\n"); 237 #endif 238 239 callout_reset(&sc->sc_poll, POLLRATE, spictimeout, sc); 240 241 return (0); 242 } 243 244 static void 245 spic_disable(void *v) 246 { 247 struct spic_softc *sc = v; 248 249 #ifdef DIAGNOSTIC 250 if (!sc->sc_enabled) { 251 printf("spic_disable: not enabled\n"); 252 return; 253 } 254 #endif 255 256 callout_stop(&sc->sc_poll); 257 258 sc->sc_enabled = 0; 259 260 #ifdef SPIC_DEBUG 261 if (spicdebug) 262 printf("spic_disable\n"); 263 #endif 264 } 265 266 static int 267 spic_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 268 { 269 switch (cmd) { 270 case WSMOUSEIO_GTYPE: 271 /* XXX this is not really correct */ 272 *(u_int *)data = WSMOUSE_TYPE_PS2; 273 return (0); 274 } 275 276 return (-1); 277 } 278