lunaws.c revision 1.35 1 /* $NetBSD: lunaws.c,v 1.35 2021/09/18 13:44:02 tsutsui Exp $ */
2
3 /*-
4 * Copyright (c) 2000 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Tohru Nishimura.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
33
34 __KERNEL_RCSID(0, "$NetBSD: lunaws.c,v 1.35 2021/09/18 13:44:02 tsutsui Exp $");
35
36 #include "opt_wsdisplay_compat.h"
37 #include "wsmouse.h"
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/conf.h>
42 #include <sys/device.h>
43
44 #include <dev/wscons/wsconsio.h>
45 #include <dev/wscons/wskbdvar.h>
46 #include <dev/wscons/wsksymdef.h>
47 #include <dev/wscons/wsksymvar.h>
48 #include <dev/wscons/wsmousevar.h>
49
50 #include <luna68k/dev/omkbdmap.h>
51 #include <luna68k/dev/sioreg.h>
52 #include <luna68k/dev/siovar.h>
53 #include <luna68k/dev/syscn.h>
54
55 #include "ioconf.h"
56
57 #define OMKBD_RXQ_LEN 64
58 #define OMKBD_RXQ_LEN_MASK (OMKBD_RXQ_LEN - 1)
59 #define OMKBD_NEXTRXQ(x) (((x) + 1) & OMKBD_RXQ_LEN_MASK)
60 #define OMKBD_TXQ_LEN 16
61 #define OMKBD_TXQ_LEN_MASK (OMKBD_TXQ_LEN - 1)
62 #define OMKBD_NEXTTXQ(x) (((x) + 1) & OMKBD_TXQ_LEN_MASK)
63
64 /* Keyboard commands */
65 /* 000XXXXXb : LED commands */
66 #define OMKBD_LED_ON_KANA 0x10 /* kana LED on */
67 #define OMKBD_LED_OFF_KANA 0x00 /* kana LED off */
68 #define OMKBD_LED_ON_CAPS 0x11 /* caps LED on */
69 #define OMKBD_LED_OFF_CAPS 0x01 /* caps LED off */
70 /* 010XXXXXb : buzzer commands */
71 #define OMKBD_BUZZER 0x40
72 #define OMKBD_BUZZER_PERIOD 0x18
73 #define OMKBD_BUZZER_40MS 0x00
74 #define OMKBD_BUZZER_150MS 0x08
75 #define OMKBD_BUZZER_400MS 0x10
76 #define OMKBD_BUZZER_700MS 0x18
77 #define OMKBD_BUZZER_PITCH 0x07
78 #define OMKBD_BUZZER_6000HZ 0x00
79 #define OMKBD_BUZZER_3000HZ 0x01
80 #define OMKBD_BUZZER_1500HZ 0x02
81 #define OMKBD_BUZZER_1000HZ 0x03
82 #define OMKBD_BUZZER_600HZ 0x04
83 #define OMKBD_BUZZER_300HZ 0x05
84 #define OMKBD_BUZZER_150HZ 0x06
85 #define OMKBD_BUZZER_100HZ 0x07
86 /* 011XXXXXb : mouse on command */
87 #define OMKBD_MOUSE_ON 0x60
88 /* 001XXXXXb : mouse off command */
89 #define OMKBD_MOUSE_OFF 0x20
90
91 #define OMKBD_BUZZER_DEFAULT \
92 (OMKBD_BUZZER | OMKBD_BUZZER_40MS | OMKBD_BUZZER_1500HZ)
93
94 static const uint8_t ch1_regs[6] = {
95 WR0_RSTINT, /* Reset E/S Interrupt */
96 WR1_RXALLS | WR1_TXENBL, /* Rx per char, Tx */
97 0, /* */
98 WR3_RX8BIT | WR3_RXENBL, /* Rx */
99 WR4_BAUD96 | WR4_STOP1 | WR4_NPARITY, /* Tx/Rx */
100 WR5_TX8BIT | WR5_TXENBL, /* Tx */
101 };
102
103 struct ws_softc {
104 device_t sc_dev;
105 struct sioreg *sc_ctl;
106 uint8_t sc_wr[6];
107 device_t sc_wskbddev;
108 uint8_t sc_rxq[OMKBD_RXQ_LEN];
109 u_int sc_rxqhead;
110 u_int sc_rxqtail;
111 uint8_t sc_txq[OMKBD_TXQ_LEN];
112 u_int sc_txqhead;
113 u_int sc_txqtail;
114 bool sc_tx_busy;
115 bool sc_tx_done;
116 int sc_leds;
117 #if NWSMOUSE > 0
118 device_t sc_wsmousedev;
119 int sc_msbuttons, sc_msdx, sc_msdy;
120 #endif
121 int sc_msreport;
122 void *sc_si;
123 int sc_rawkbd;
124 };
125
126 static void omkbd_input(struct ws_softc *, int);
127 static void omkbd_send(struct ws_softc *, uint8_t);
128 static void omkbd_decode(struct ws_softc *, int, u_int *, int *);
129
130 static int omkbd_enable(void *, int);
131 static void omkbd_set_leds(void *, int);
132 static int omkbd_ioctl(void *, u_long, void *, int, struct lwp *);
133
134 static void omkbd_complex_buzzer(struct ws_softc *, struct wskbd_bell_data *);
135 static uint8_t omkbd_get_buzcmd(struct ws_softc *, struct wskbd_bell_data *,
136 uint8_t);
137
138 static const struct wskbd_mapdata omkbd_keymapdata = {
139 .keydesc = omkbd_keydesctab,
140 .layout = KB_JP,
141 };
142 static const struct wskbd_accessops omkbd_accessops = {
143 .enable = omkbd_enable,
144 .set_leds = omkbd_set_leds,
145 .ioctl = omkbd_ioctl,
146 };
147
148 void ws_cnattach(void);
149 static void ws_cngetc(void *, u_int *, int *);
150 static void ws_cnpollc(void *, int);
151 static void ws_cnbell(void *, u_int, u_int, u_int);
152 static const struct wskbd_consops ws_consops = {
153 .getc = ws_cngetc,
154 .pollc = ws_cnpollc,
155 .bell = ws_cnbell,
156 };
157
158 #if NWSMOUSE > 0
159 static int omms_enable(void *);
160 static int omms_ioctl(void *, u_long, void *, int, struct lwp *);
161 static void omms_disable(void *);
162
163 static const struct wsmouse_accessops omms_accessops = {
164 omms_enable,
165 omms_ioctl,
166 omms_disable,
167 };
168 #endif
169
170 static void wsintr(void *);
171 static void wssoftintr(void *);
172
173 static int wsmatch(device_t, cfdata_t, void *);
174 static void wsattach(device_t, device_t, void *);
175
176 CFATTACH_DECL_NEW(ws, sizeof(struct ws_softc),
177 wsmatch, wsattach, NULL, NULL);
178
179 /* #define LUNAWS_DEBUG */
180
181 #ifdef LUNAWS_DEBUG
182 #define DEBUG_KBDTX 0x01
183 #define DEBUG_RXSOFT 0x02
184 #define DEBUG_BUZZER 0x04
185 uint32_t lunaws_debug = 0x00 /* | DEBUG_BUZZER | DEBUG_KBDTX | DEBUG_RXSOFT */;
186 #define DPRINTF(x, y) if (lunaws_debug & (x)) printf y
187 #else
188 #define DPRINTF(x, y) __nothing
189 #endif
190
191 static int
192 wsmatch(device_t parent, cfdata_t cf, void *aux)
193 {
194 struct sio_attach_args *args = aux;
195
196 if (args->channel != 1)
197 return 0;
198 return 1;
199 }
200
201 static void
202 wsattach(device_t parent, device_t self, void *aux)
203 {
204 struct ws_softc *sc = device_private(self);
205 struct sio_softc *siosc = device_private(parent);
206 struct sio_attach_args *args = aux;
207 int channel = args->channel;
208 struct wskbddev_attach_args a;
209
210 sc->sc_dev = self;
211 sc->sc_ctl = &siosc->sc_ctl[channel];
212 memcpy(sc->sc_wr, ch1_regs, sizeof(ch1_regs));
213 siosc->sc_intrhand[channel].ih_func = wsintr;
214 siosc->sc_intrhand[channel].ih_arg = sc;
215
216 setsioreg(sc->sc_ctl, WR0, sc->sc_wr[WR0]);
217 setsioreg(sc->sc_ctl, WR4, sc->sc_wr[WR4]);
218 setsioreg(sc->sc_ctl, WR3, sc->sc_wr[WR3]);
219 setsioreg(sc->sc_ctl, WR5, sc->sc_wr[WR5]);
220 setsioreg(sc->sc_ctl, WR0, sc->sc_wr[WR0]);
221
222 sc->sc_rxqhead = 0;
223 sc->sc_rxqtail = 0;
224 sc->sc_txqhead = 0;
225 sc->sc_txqtail = 0;
226 sc->sc_tx_busy = false;
227 sc->sc_tx_done = false;
228
229 sc->sc_si = softint_establish(SOFTINT_SERIAL, wssoftintr, sc);
230
231 /* enable interrupt */
232 setsioreg(sc->sc_ctl, WR1, sc->sc_wr[WR1]);
233
234 aprint_normal("\n");
235
236 /* keep mouse quiet */
237 omkbd_send(sc, OMKBD_MOUSE_OFF);
238
239 a.console = (args->hwflags == 1);
240 a.keymap = &omkbd_keymapdata;
241 a.accessops = &omkbd_accessops;
242 a.accesscookie = (void *)sc;
243 sc->sc_wskbddev = config_found(self, &a, wskbddevprint,
244 CFARGS(.iattr = "wskbddev"));
245
246 #if NWSMOUSE > 0
247 {
248 struct wsmousedev_attach_args b;
249 b.accessops = &omms_accessops;
250 b.accesscookie = (void *)sc;
251 sc->sc_wsmousedev = config_found(self, &b, wsmousedevprint,
252 CFARGS(.iattr = "wsmousedev"));
253 }
254 #endif
255 sc->sc_msreport = 0;
256 }
257
258 static void
259 wsintr(void *arg)
260 {
261 struct ws_softc *sc = arg;
262 struct sioreg *sio = sc->sc_ctl;
263 uint8_t code;
264 int rr;
265 bool handled = false;
266
267 rr = getsiocsr(sio);
268 if ((rr & RR_RXRDY) != 0) {
269 do {
270 code = sio->sio_data;
271 if (rr & (RR_FRAMING | RR_OVERRUN | RR_PARITY)) {
272 sio->sio_cmd = WR0_ERRRST;
273 continue;
274 }
275 sc->sc_rxq[sc->sc_rxqtail] = code;
276 sc->sc_rxqtail = OMKBD_NEXTRXQ(sc->sc_rxqtail);
277 } while (((rr = getsiocsr(sio)) & RR_RXRDY) != 0);
278 handled = true;
279 }
280 if ((rr & RR_TXRDY) != 0) {
281 sio->sio_cmd = WR0_RSTPEND;
282 if (sc->sc_tx_busy) {
283 sc->sc_tx_busy = false;
284 sc->sc_tx_done = true;
285 handled = true;
286 }
287 }
288 if (handled)
289 softint_schedule(sc->sc_si);
290 }
291
292 static void
293 wssoftintr(void *arg)
294 {
295 struct ws_softc *sc = arg;
296 uint8_t code;
297
298 /* handle pending keyboard commands */
299 if (sc->sc_tx_done) {
300 int s;
301
302 s = splserial();
303 sc->sc_tx_done = false;
304 DPRINTF(DEBUG_KBDTX, ("%s: tx complete\n", __func__));
305 if (sc->sc_txqhead != sc->sc_txqtail) {
306 struct sioreg *sio = sc->sc_ctl;
307
308 sc->sc_tx_busy = true;
309 sio->sio_data = sc->sc_txq[sc->sc_txqhead];
310 DPRINTF(DEBUG_KBDTX,
311 ("%s: sio_data <- txq[%2d] (%02x)\n", __func__,
312 sc->sc_txqhead, sc->sc_txq[sc->sc_txqhead]));
313
314 sc->sc_txqhead = OMKBD_NEXTTXQ(sc->sc_txqhead);
315 }
316 splx(s);
317 }
318
319 /* handle received keyboard and mouse data */
320 while (sc->sc_rxqhead != sc->sc_rxqtail) {
321 code = sc->sc_rxq[sc->sc_rxqhead];
322 DPRINTF(DEBUG_RXSOFT, ("%s: %02x <- rxq[%2d]\n", __func__,
323 code, sc->sc_rxqhead));
324 sc->sc_rxqhead = OMKBD_NEXTRXQ(sc->sc_rxqhead);
325 /*
326 * if (code >= 0x80 && code <= 0x87), i.e.
327 * if ((code & 0xf8) == 0x80), then
328 * it's the first byte of 3 byte long mouse report
329 * code[0] & 07 -> LMR button condition
330 * code[1], [2] -> x,y delta
331 * otherwise, key press or release event.
332 */
333 if (sc->sc_msreport == 1) {
334 #if NWSMOUSE > 0
335 sc->sc_msdx = (int8_t)code;
336 #endif
337 sc->sc_msreport = 2;
338 continue;
339 } else if (sc->sc_msreport == 2) {
340 #if NWSMOUSE > 0
341 sc->sc_msdy = (int8_t)code;
342 wsmouse_input(sc->sc_wsmousedev,
343 sc->sc_msbuttons, sc->sc_msdx, sc->sc_msdy, 0, 0,
344 WSMOUSE_INPUT_DELTA);
345 #endif
346 sc->sc_msreport = 0;
347 continue;
348 }
349 if ((code & 0xf8) == 0x80) {
350 #if NWSMOUSE > 0
351 /* buttons: Negative logic to positive */
352 code = ~code;
353 /* LMR->RML: wsevent counts 0 for leftmost */
354 sc->sc_msbuttons =
355 ((code & 1) << 2) | (code & 2) | ((code & 4) >> 2);
356 #endif
357 sc->sc_msreport = 1;
358 continue;
359 }
360 omkbd_input(sc, code);
361 }
362 }
363
364 static void
365 omkbd_send(struct ws_softc *sc, uint8_t txdata)
366 {
367 int s;
368
369 if (!sc->sc_tx_busy) {
370 struct sioreg *sio = sc->sc_ctl;
371
372 DPRINTF(DEBUG_KBDTX,
373 ("%s: sio_data <- %02x\n", __func__, txdata));
374 s = splserial();
375 sc->sc_tx_busy = true;
376 sio->sio_data = txdata;
377 splx(s);
378 } else {
379 s = splsoftserial();
380 sc->sc_txq[sc->sc_txqtail] = txdata;
381 DPRINTF(DEBUG_KBDTX,
382 ("%s: txq[%2d] <- %02x\n", __func__,
383 sc->sc_txqtail, sc->sc_txq[sc->sc_txqtail]));
384 sc->sc_txqtail = OMKBD_NEXTTXQ(sc->sc_txqtail);
385 splx(s);
386 softint_schedule(sc->sc_si);
387 }
388 }
389
390 static void
391 omkbd_input(struct ws_softc *sc, int data)
392 {
393 u_int type;
394 int key;
395
396 omkbd_decode(sc, data, &type, &key);
397
398 #ifdef WSDISPLAY_COMPAT_RAWKBD
399 if (sc->sc_rawkbd) {
400 uint8_t cbuf[2];
401 int c, j = 0;
402
403 c = omkbd_raw[key];
404 if (c != 0x00) {
405 /* fake extended scancode if necessary */
406 if (c & 0x80)
407 cbuf[j++] = 0xe0;
408 cbuf[j] = c & 0x7f;
409 if (type == WSCONS_EVENT_KEY_UP)
410 cbuf[j] |= 0x80;
411 j++;
412
413 wskbd_rawinput(sc->sc_wskbddev, cbuf, j);
414 }
415 } else
416 #endif
417 {
418 if (sc->sc_wskbddev != NULL)
419 wskbd_input(sc->sc_wskbddev, type, key);
420 }
421 }
422
423 static void
424 omkbd_decode(struct ws_softc *sc, int datain, u_int *type, int *dataout)
425 {
426
427 *type = (datain & 0x80) ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN;
428 *dataout = datain & 0x7f;
429 }
430
431 static void
432 omkbd_complex_buzzer(struct ws_softc *sc, struct wskbd_bell_data *wbd)
433 {
434 uint8_t buzcmd;
435
436 buzcmd = omkbd_get_buzcmd(sc, wbd, OMKBD_BUZZER_DEFAULT);
437 omkbd_send(sc, buzcmd);
438 }
439
440 static uint8_t
441 omkbd_get_buzcmd(struct ws_softc *sc, struct wskbd_bell_data *wbd,
442 uint8_t obuzcmd)
443 {
444 u_int pitch, period;
445 uint8_t buzcmd;
446
447 pitch = wbd->pitch;
448 period = wbd->period;
449 buzcmd = OMKBD_BUZZER;
450
451 if ((wbd->which & WSKBD_BELL_DOPERIOD) == 0)
452 buzcmd |= obuzcmd & OMKBD_BUZZER_PERIOD;
453 else if (period >= 700)
454 buzcmd |= OMKBD_BUZZER_700MS;
455 else if (period >= 400)
456 buzcmd |= OMKBD_BUZZER_400MS;
457 else if (period >= 150)
458 buzcmd |= OMKBD_BUZZER_150MS;
459 else
460 buzcmd |= OMKBD_BUZZER_40MS;
461
462 if ((wbd->which & WSKBD_BELL_DOPITCH) == 0)
463 buzcmd |= obuzcmd & OMKBD_BUZZER_PITCH;
464 else if (pitch >= 6000)
465 buzcmd |= OMKBD_BUZZER_6000HZ;
466 else if (pitch >= 3000)
467 buzcmd |= OMKBD_BUZZER_3000HZ;
468 else if (pitch >= 1500)
469 buzcmd |= OMKBD_BUZZER_1500HZ;
470 else if (pitch >= 1000)
471 buzcmd |= OMKBD_BUZZER_1000HZ;
472 else if (pitch >= 600)
473 buzcmd |= OMKBD_BUZZER_600HZ;
474 else if (pitch >= 300)
475 buzcmd |= OMKBD_BUZZER_300HZ;
476 else if (pitch >= 150)
477 buzcmd |= OMKBD_BUZZER_150HZ;
478 else
479 buzcmd |= OMKBD_BUZZER_100HZ;
480
481 /* no volume control for buzzer on the LUNA keyboards */
482
483 return buzcmd;
484 }
485
486 static void
487 ws_cngetc(void *cookie, u_int *type, int *data)
488 {
489 struct ws_softc *sc = cookie;
490 int code;
491
492 code = syscngetc((dev_t)1);
493 omkbd_decode(sc, code, type, data);
494 }
495
496 static void
497 ws_cnpollc(void *cookie, int on)
498 {
499 }
500
501 static void
502 ws_cnbell(void *cookie, u_int pitch, u_int period, u_int volume)
503 {
504 struct ws_softc *sc = cookie;
505 struct wskbd_bell_data wbd;
506 uint8_t buzcmd;
507
508 /*
509 * XXX cnbell(9) man page should describe each args..
510 * (it looks similar to the struct wskbd_bell_data)
511 * pitch: bell frequency in hertz
512 * period: bell period in ms
513 * volume: bell volume as a percentage (0-100) (as spkr(4))
514 */
515 wbd.which = WSKBD_BELL_DOALL;
516 wbd.period = period;
517 wbd.pitch = pitch;
518 wbd.volume = volume;
519 buzcmd = omkbd_get_buzcmd(sc, &wbd, OMKBD_BUZZER_DEFAULT);
520
521 syscnputc((dev_t)1, buzcmd);
522 }
523
524 /* EXPORT */ void
525 ws_cnattach(void)
526 {
527 static int voidfill;
528
529 /* XXX need CH.B initialization XXX */
530
531 wskbd_cnattach(&ws_consops, &voidfill, &omkbd_keymapdata);
532 }
533
534 static int
535 omkbd_enable(void *cookie, int on)
536 {
537
538 return 0;
539 }
540
541 static void
542 omkbd_set_leds(void *cookie, int leds)
543 {
544 struct ws_softc *sc = cookie;
545 uint8_t ledcmd;
546
547 sc->sc_leds = leds;
548 if ((leds & WSKBD_LED_CAPS) != 0) {
549 ledcmd = OMKBD_LED_ON_CAPS;
550 } else {
551 ledcmd = OMKBD_LED_OFF_CAPS;
552 }
553 omkbd_send(sc, ledcmd);
554
555 #if 0 /* no KANA lock support in wskbd */
556 if ((leds & WSKBD_LED_KANA) != 0) {
557 ledcmd = OMKBD_LED_ON_KANA;
558 } else
559 #endif
560 {
561 ledcmd = OMKBD_LED_OFF_KANA;
562 }
563 omkbd_send(sc, ledcmd);
564 }
565
566 static int
567 omkbd_ioctl(void *cookie, u_long cmd, void *data, int flag, struct lwp *l)
568 {
569 struct ws_softc *sc = cookie;
570 struct wskbd_bell_data *wbd;
571
572 switch (cmd) {
573 case WSKBDIO_GTYPE:
574 *(int *)data = WSKBD_TYPE_LUNA;
575 return 0;
576 case WSKBDIO_SETLEDS:
577 omkbd_set_leds(cookie, *(int *)data);
578 return 0;
579 case WSKBDIO_GETLEDS:
580 *(int *)data = sc->sc_leds;
581 return 0;
582
583 /*
584 * Note all WSKBDIO_*BELL ioctl(2)s except WSKBDIO_COMPLEXBELL
585 * are handled MI wskbd(4) layer.
586 * (wskbd_displayioctl() in src/sys/dev/wscons/wskbd.c)
587 */
588 case WSKBDIO_COMPLEXBELL:
589 wbd = data;
590 DPRINTF(DEBUG_BUZZER,
591 ("%s: WSKBDIO_COMPLEXBELL: pitch = %d, period = %d\n",
592 __func__, wbd->pitch, wbd->period));
593 omkbd_complex_buzzer(sc, wbd);
594 return 0;
595
596 #ifdef WSDISPLAY_COMPAT_RAWKBD
597 case WSKBDIO_SETMODE:
598 sc->sc_rawkbd = *(int *)data == WSKBD_RAW;
599 return 0;
600 case WSKBDIO_GETMODE:
601 *(int *)data = sc->sc_rawkbd;
602 return 0;
603 #endif
604 }
605 return EPASSTHROUGH;
606 }
607
608 #if NWSMOUSE > 0
609
610 static int
611 omms_enable(void *cookie)
612 {
613 struct ws_softc *sc = cookie;
614
615 /* enable 3 byte long mouse reporting */
616 omkbd_send(sc, OMKBD_MOUSE_ON);
617
618 return 0;
619 }
620
621 /*ARGUSED*/
622 static int
623 omms_ioctl(void *cookie, u_long cmd, void *data, int flag, struct lwp *l)
624 {
625
626 if (cmd == WSMOUSEIO_GTYPE) {
627 *(u_int *)data = 0x19991005; /* XXX */
628 return 0;
629 }
630 return EPASSTHROUGH;
631 }
632
633 static void
634 omms_disable(void *cookie)
635 {
636 struct ws_softc *sc = cookie;
637
638 omkbd_send(sc, OMKBD_MOUSE_OFF);
639 }
640 #endif
641