1 /* $NetBSD: zs_ms.c,v 1.1 2004/07/08 22:30:53 sekiya Exp $ */ 2 3 /* 4 * Copyright (c) 2004 Steve Rumble 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 /* 31 * IP12/IP20 serial mouse driver attached to zs channel 1 at 4800bps. 32 * This layer feeds wsmouse. 33 * 34 * 5 byte packets: sync, x1, y1, x2, y2 35 * sync format: binary 10000LMR (left, middle, right) 0 is down 36 */ 37 38 #include <sys/cdefs.h> 39 __KERNEL_RCSID(0, "$NetBSD: zs_ms.c,v 1.1 2004/07/08 22:30:53 sekiya Exp $"); 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/conf.h> 44 #include <sys/device.h> 45 46 #include <dev/wscons/wsconsio.h> 47 #include <dev/wscons/wsmousevar.h> 48 49 #include <dev/ic/z8530reg.h> 50 #include <machine/machtype.h> 51 #include <machine/z8530var.h> 52 53 #define ZSMS_BAUD 4800 54 #define ZSMS_RXQ_LEN 64 /* power of 2 */ 55 56 /* protocol */ 57 #define ZSMS_SYNC 0x80 58 #define ZSMS_SYNC_MASK 0xf8 59 #define ZSMS_SYNC_BTN_R 0x01 60 #define ZSMS_SYNC_BTN_M 0x02 61 #define ZSMS_SYNC_BTN_L 0x04 62 #define ZSMS_SYNC_BTN_MASK 0x07 63 64 struct zsms_softc { 65 struct device sc_dev; 66 67 /* tail-chasing fifo */ 68 u_char rxq[ZSMS_RXQ_LEN]; 69 u_char rxq_head; 70 u_char rxq_tail; 71 72 /* 5-byte packet as described above */ 73 #define ZSMS_PACKET_SYNC 0 74 #define ZSMS_PACKET_X1 1 75 #define ZSMS_PACKET_Y1 2 76 #define ZSMS_PACKET_X2 3 77 #define ZSMS_PACKET_Y2 4 78 u_char packet[5]; 79 80 #define ZSMS_STATE_SYNC 0x01 81 #define ZSMS_STATE_X1 0x02 82 #define ZSMS_STATE_Y1 0x04 83 #define ZSMS_STATE_X2 0x08 84 #define ZSMS_STATE_Y2 0x10 85 u_char state; 86 87 /* wsmouse bits */ 88 int enabled; 89 struct device *wsmousedev; 90 }; 91 92 static int zsms_match(struct device *, struct cfdata *, void *); 93 static void zsms_attach(struct device *, struct device *, void *); 94 static void zsms_rxint(struct zs_chanstate *); 95 static void zsms_txint(struct zs_chanstate *); 96 static void zsms_stint(struct zs_chanstate *, int); 97 static void zsms_softint(struct zs_chanstate *); 98 99 static void zsms_wsmouse_input(struct zsms_softc *); 100 static int zsms_wsmouse_enable(void *); 101 static void zsms_wsmouse_disable(void *); 102 static int zsms_wsmouse_ioctl(void *, u_long, caddr_t, int, 103 struct proc *); 104 105 CFATTACH_DECL(zsms, sizeof(struct zsms_softc), 106 zsms_match, zsms_attach, NULL, NULL); 107 108 static struct zsops zsms_zsops = { 109 zsms_rxint, 110 zsms_stint, 111 zsms_txint, 112 zsms_softint 113 }; 114 115 static const struct wsmouse_accessops zsms_wsmouse_accessops = { 116 zsms_wsmouse_enable, 117 zsms_wsmouse_ioctl, 118 zsms_wsmouse_disable 119 }; 120 121 int 122 zsms_match(struct device *parent, struct cfdata *cf, void *aux) 123 { 124 if (mach_type == MACH_SGI_IP12 || mach_type == MACH_SGI_IP20) { 125 struct zsc_attach_args *args = aux; 126 127 if (args->channel == 1) 128 return (1); 129 } 130 131 return (0); 132 } 133 134 void 135 zsms_attach(struct device *parent, struct device *self, void *aux) 136 { 137 int s, channel; 138 struct zsc_softc *zsc = (struct zsc_softc *)parent; 139 struct zsms_softc *sc = (struct zsms_softc *)self; 140 struct zsc_attach_args *args = aux; 141 struct zs_chanstate *cs; 142 struct wsmousedev_attach_args wsmaa; 143 144 /* Establish ourself with the MD z8530 driver */ 145 channel = args->channel; 146 cs = zsc->zsc_cs[channel]; 147 cs->cs_ops = &zsms_zsops; 148 cs->cs_private = sc; 149 150 sc->enabled = 0; 151 sc->rxq_head = 0; 152 sc->rxq_tail = 0; 153 sc->state = ZSMS_STATE_SYNC; 154 155 printf(": baud rate %d\n", ZSMS_BAUD); 156 157 s = splzs(); 158 zs_write_reg(cs, 9, (channel == 0) ? ZSWR9_A_RESET : ZSWR9_B_RESET); 159 cs->cs_preg[1] = ZSWR1_RIE; 160 zs_set_speed(cs, ZSMS_BAUD); 161 zs_loadchannelregs(cs); 162 splx(s); 163 164 /* attach wsmouse */ 165 wsmaa.accessops = &zsms_wsmouse_accessops; 166 wsmaa.accesscookie = sc; 167 sc->wsmousedev = config_found(self, &wsmaa, wsmousedevprint); 168 } 169 170 void 171 zsms_rxint(struct zs_chanstate *cs) 172 { 173 u_char c, r; 174 struct zsms_softc *sc = (struct zsms_softc *)cs->cs_private; 175 176 /* clear errors */ 177 r = zs_read_reg(cs, 1); 178 if (r & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) 179 zs_write_csr(cs, ZSWR0_RESET_ERRORS); 180 181 /* read byte and append to our queue */ 182 c = zs_read_data(cs); 183 184 sc->rxq[sc->rxq_tail] = c; 185 sc->rxq_tail = (sc->rxq_tail + 1) & ~ZSMS_RXQ_LEN; 186 187 cs->cs_softreq = 1; 188 } 189 190 /* We should never get here. */ 191 void 192 zsms_txint(struct zs_chanstate *cs) 193 { 194 zs_write_reg(cs, 0, ZSWR0_RESET_TXINT); 195 196 /* seems like the in thing to do */ 197 cs->cs_softreq = 1; 198 } 199 200 void 201 zsms_stint(struct zs_chanstate *cs, int force) 202 { 203 zs_write_csr(cs, ZSWR0_RESET_STATUS); 204 cs->cs_softreq = 1; 205 } 206 207 void 208 zsms_softint(struct zs_chanstate *cs) 209 { 210 struct zsms_softc *sc = (struct zsms_softc *)cs->cs_private; 211 212 /* No need to keep score if nobody is listening */ 213 if (!sc->enabled) { 214 sc->rxq_head = sc->rxq_tail; 215 return; 216 } 217 218 /* 219 * Here's the real action. Read a full packet and 220 * then let wsmouse know what has happened. 221 */ 222 while (sc->rxq_head != sc->rxq_tail) { 223 u_char c = sc->rxq[sc->rxq_head]; 224 225 switch (sc->state) { 226 case ZSMS_STATE_SYNC: 227 if ((c & ZSMS_SYNC_MASK) == ZSMS_SYNC) { 228 sc->packet[ZSMS_PACKET_SYNC] = c; 229 sc->state = ZSMS_STATE_X1; 230 } 231 break; 232 233 case ZSMS_STATE_X1: 234 sc->packet[ZSMS_PACKET_X1] = c; 235 sc->state = ZSMS_STATE_Y1; 236 break; 237 238 case ZSMS_STATE_Y1: 239 sc->packet[ZSMS_PACKET_Y1] = c; 240 sc->state = ZSMS_STATE_X2; 241 break; 242 243 case ZSMS_STATE_X2: 244 sc->packet[ZSMS_PACKET_X2] = c; 245 sc->state = ZSMS_STATE_Y2; 246 break; 247 248 case ZSMS_STATE_Y2: 249 sc->packet[ZSMS_PACKET_Y2] = c; 250 251 /* tweak wsmouse */ 252 zsms_wsmouse_input(sc); 253 254 sc->state = ZSMS_STATE_SYNC; 255 } 256 257 sc->rxq_head = (sc->rxq_head + 1) & ~ZSMS_RXQ_LEN; 258 } 259 } 260 261 /****************************************************************************** 262 * wsmouse glue 263 ******************************************************************************/ 264 265 static void 266 zsms_wsmouse_input(struct zsms_softc *sc) 267 { 268 int x, y; 269 u_int btns; 270 271 btns = sc->packet[ZSMS_PACKET_SYNC] & ZSMS_SYNC_BTN_MASK; 272 x = sc->packet[ZSMS_PACKET_X1] + sc->packet[ZSMS_PACKET_X2]; 273 y = sc->packet[ZSMS_PACKET_Y1] + sc->packet[ZSMS_PACKET_Y2]; 274 275 /* 276 * XXX - how does wsmouse want the buttons represented??? 277 */ 278 279 wsmouse_input(sc->wsmousedev, btns, x, y, 0, WSMOUSE_INPUT_DELTA); 280 } 281 282 static int 283 zsms_wsmouse_enable(void *cookie) 284 { 285 struct zsms_softc *sc = (struct zsms_softc *)cookie; 286 287 if (sc->enabled) 288 return (EBUSY); 289 290 sc->state = ZSMS_STATE_SYNC; 291 sc->enabled = 1; 292 293 return (0); 294 } 295 296 void 297 zsms_wsmouse_disable(void *cookie) 298 { 299 struct zsms_softc *sc = (struct zsms_softc *)cookie; 300 301 sc->enabled = 0; 302 } 303 304 static int 305 zsms_wsmouse_ioctl(void *cookie, u_long cmd, 306 caddr_t data, int flag, struct proc *p) 307 { 308 switch (cmd) { 309 case WSMOUSEIO_GTYPE: 310 *(u_int *)data = WSMOUSE_TYPE_SGI; 311 break; 312 313 #ifdef notyet 314 case WSMOUSEIO_SRES: 315 case WSMOUSEIO_SSCALE: 316 case WSMOUSEIO_SRATE: 317 case WSMOUSEIO_SCALIBCOORDS: 318 case WSMOUSEIO_GCALIBCOORDS: 319 case WSMOUSEIO_GETID: 320 #endif 321 322 default: 323 return (EPASSTHROUGH); 324 } 325 326 return (0); 327 } 328