1 /* $NetBSD: lunaws.c,v 1.42 2023/01/15 05:08:33 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.42 2023/01/15 05:08:33 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 #include <sys/rndsource.h>
44
45 #include <dev/wscons/wsconsio.h>
46 #include <dev/wscons/wskbdvar.h>
47 #include <dev/wscons/wsksymdef.h>
48 #include <dev/wscons/wsksymvar.h>
49 #include <dev/wscons/wsmousevar.h>
50
51 #include <luna68k/dev/omkbdmap.h>
52 #include <luna68k/dev/sioreg.h>
53 #include <luna68k/dev/siovar.h>
54
55 #include <machine/board.h>
56
57 #include "ioconf.h"
58
59 #define OMKBD_RXQ_LEN 64
60 #define OMKBD_RXQ_LEN_MASK (OMKBD_RXQ_LEN - 1)
61 #define OMKBD_NEXTRXQ(x) (((x) + 1) & OMKBD_RXQ_LEN_MASK)
62 #define OMKBD_TXQ_LEN 16
63 #define OMKBD_TXQ_LEN_MASK (OMKBD_TXQ_LEN - 1)
64 #define OMKBD_NEXTTXQ(x) (((x) + 1) & OMKBD_TXQ_LEN_MASK)
65
66 /* Keyboard commands */
67 /* 000XXXXXb : LED commands */
68 #define OMKBD_LED_ON_KANA 0x10 /* kana LED on */
69 #define OMKBD_LED_OFF_KANA 0x00 /* kana LED off */
70 #define OMKBD_LED_ON_CAPS 0x11 /* caps LED on */
71 #define OMKBD_LED_OFF_CAPS 0x01 /* caps LED off */
72 /* 010XXXXXb : buzzer commands */
73 #define OMKBD_BUZZER 0x40
74 #define OMKBD_BUZZER_PERIOD 0x18
75 #define OMKBD_BUZZER_40MS 0x00
76 #define OMKBD_BUZZER_150MS 0x08
77 #define OMKBD_BUZZER_400MS 0x10
78 #define OMKBD_BUZZER_700MS 0x18
79 #define OMKBD_BUZZER_PITCH 0x07
80 #define OMKBD_BUZZER_6000HZ 0x00
81 #define OMKBD_BUZZER_3000HZ 0x01
82 #define OMKBD_BUZZER_1500HZ 0x02
83 #define OMKBD_BUZZER_1000HZ 0x03
84 #define OMKBD_BUZZER_600HZ 0x04
85 #define OMKBD_BUZZER_300HZ 0x05
86 #define OMKBD_BUZZER_150HZ 0x06
87 #define OMKBD_BUZZER_100HZ 0x07
88 /* 011XXXXXb : mouse on command */
89 #define OMKBD_MOUSE_ON 0x60
90 /* 001XXXXXb : mouse off command */
91 #define OMKBD_MOUSE_OFF 0x20
92
93 #define OMKBD_BUZZER_DEFAULT \
94 (OMKBD_BUZZER | OMKBD_BUZZER_40MS | OMKBD_BUZZER_1500HZ)
95
96 static const uint8_t ch1_regs[6] = {
97 WR0_RSTINT, /* Reset E/S Interrupt */
98 WR1_RXALLS | WR1_TXENBL, /* Rx per char, Tx */
99 0, /* */
100 WR3_RX8BIT | WR3_RXENBL, /* Rx */
101 WR4_BAUD96 | WR4_STOP1 | WR4_NPARITY, /* Tx/Rx */
102 WR5_TX8BIT | WR5_TXENBL, /* Tx */
103 };
104
105 struct ws_conscookie {
106 struct sioreg *cc_sio;
107 int cc_polling;
108 struct ws_softc *cc_sc;
109 };
110
111 struct ws_softc {
112 device_t sc_dev;
113 struct sioreg *sc_ctl;
114 uint8_t sc_wr[6];
115 device_t sc_wskbddev;
116 uint8_t sc_rxq[OMKBD_RXQ_LEN];
117 u_int sc_rxqhead;
118 u_int sc_rxqtail;
119 uint8_t sc_txq[OMKBD_TXQ_LEN];
120 u_int sc_txqhead;
121 u_int sc_txqtail;
122 bool sc_tx_busy;
123 bool sc_tx_done;
124 int sc_leds;
125 #if NWSMOUSE > 0
126 device_t sc_wsmousedev;
127 int sc_msbuttons, sc_msdx, sc_msdy;
128 #endif
129 int sc_msreport;
130 void *sc_si;
131 int sc_rawkbd;
132
133 struct ws_conscookie *sc_conscookie;
134 krndsource_t sc_rndsource;
135 };
136
137 static void omkbd_input(struct ws_softc *, int);
138 static void omkbd_send(struct ws_softc *, uint8_t);
139 static void omkbd_decode(struct ws_softc *, int, u_int *, int *);
140
141 static int omkbd_enable(void *, int);
142 static void omkbd_set_leds(void *, int);
143 static int omkbd_ioctl(void *, u_long, void *, int, struct lwp *);
144
145 static void omkbd_complex_buzzer(struct ws_softc *, struct wskbd_bell_data *);
146 static uint8_t omkbd_get_buzcmd(struct ws_softc *, struct wskbd_bell_data *,
147 uint8_t);
148
149 static const struct wskbd_mapdata omkbd_keymapdata = {
150 .keydesc = omkbd_keydesctab,
151 .layout = KB_JP,
152 };
153 static const struct wskbd_accessops omkbd_accessops = {
154 .enable = omkbd_enable,
155 .set_leds = omkbd_set_leds,
156 .ioctl = omkbd_ioctl,
157 };
158
159 void ws_cnattach(void);
160 static void ws_cngetc(void *, u_int *, int *);
161 static void ws_cnpollc(void *, int);
162 static void ws_cnbell(void *, u_int, u_int, u_int);
163 static const struct wskbd_consops ws_consops = {
164 .getc = ws_cngetc,
165 .pollc = ws_cnpollc,
166 .bell = ws_cnbell,
167 };
168 static struct ws_conscookie ws_conscookie;
169
170 #if NWSMOUSE > 0
171 static int omms_enable(void *);
172 static int omms_ioctl(void *, u_long, void *, int, struct lwp *);
173 static void omms_disable(void *);
174
175 static const struct wsmouse_accessops omms_accessops = {
176 .enable = omms_enable,
177 .ioctl = omms_ioctl,
178 .disable = omms_disable,
179 };
180 #endif
181
182 static void wsintr(void *);
183 static void wssoftintr(void *);
184
185 static int wsmatch(device_t, cfdata_t, void *);
186 static void wsattach(device_t, device_t, void *);
187
188 CFATTACH_DECL_NEW(ws, sizeof(struct ws_softc),
189 wsmatch, wsattach, NULL, NULL);
190
191 /* #define LUNAWS_DEBUG */
192
193 #ifdef LUNAWS_DEBUG
194 #define DEBUG_KBDTX 0x01
195 #define DEBUG_RXSOFT 0x02
196 #define DEBUG_BUZZER 0x04
197 uint32_t lunaws_debug = 0x00 /* | DEBUG_BUZZER | DEBUG_KBDTX | DEBUG_RXSOFT */;
198 #define DPRINTF(x, y) if (lunaws_debug & (x)) printf y
199 #else
200 #define DPRINTF(x, y) __nothing
201 #endif
202
203 static int
wsmatch(device_t parent,cfdata_t cf,void * aux)204 wsmatch(device_t parent, cfdata_t cf, void *aux)
205 {
206 struct sio_attach_args *args = aux;
207
208 if (args->channel != 1)
209 return 0;
210 return 1;
211 }
212
213 static void
wsattach(device_t parent,device_t self,void * aux)214 wsattach(device_t parent, device_t self, void *aux)
215 {
216 struct ws_softc *sc = device_private(self);
217 struct sio_softc *siosc = device_private(parent);
218 struct sio_attach_args *args = aux;
219 int channel = args->channel;
220 struct wskbddev_attach_args a;
221
222 sc->sc_dev = self;
223 sc->sc_ctl = &siosc->sc_ctl[channel];
224 memcpy(sc->sc_wr, ch1_regs, sizeof(ch1_regs));
225 siosc->sc_intrhand[channel].ih_func = wsintr;
226 siosc->sc_intrhand[channel].ih_arg = sc;
227
228 sc->sc_conscookie = &ws_conscookie;
229 sc->sc_conscookie->cc_sc = sc;
230 sc->sc_conscookie->cc_polling = 0;
231
232 setsioreg(sc->sc_ctl, WR0, sc->sc_wr[WR0]);
233 setsioreg(sc->sc_ctl, WR4, sc->sc_wr[WR4]);
234 setsioreg(sc->sc_ctl, WR3, sc->sc_wr[WR3]);
235 setsioreg(sc->sc_ctl, WR5, sc->sc_wr[WR5]);
236 setsioreg(sc->sc_ctl, WR0, sc->sc_wr[WR0]);
237
238 sc->sc_rxqhead = 0;
239 sc->sc_rxqtail = 0;
240 sc->sc_txqhead = 0;
241 sc->sc_txqtail = 0;
242 sc->sc_tx_busy = false;
243 sc->sc_tx_done = false;
244
245 sc->sc_si = softint_establish(SOFTINT_SERIAL, wssoftintr, sc);
246 rnd_attach_source(&sc->sc_rndsource, device_xname(self),
247 RND_TYPE_TTY, RND_FLAG_DEFAULT);
248
249 /* enable interrupt */
250 setsioreg(sc->sc_ctl, WR1, sc->sc_wr[WR1]);
251
252 aprint_normal("\n");
253
254 /* keep mouse quiet */
255 omkbd_send(sc, OMKBD_MOUSE_OFF);
256
257 a.console = (args->hwflags == 1);
258 a.keymap = &omkbd_keymapdata;
259 a.accessops = &omkbd_accessops;
260 a.accesscookie = (void *)sc;
261 sc->sc_wskbddev = config_found(self, &a, wskbddevprint,
262 CFARGS(.iattr = "wskbddev"));
263
264 #if NWSMOUSE > 0
265 {
266 struct wsmousedev_attach_args b;
267 b.accessops = &omms_accessops;
268 b.accesscookie = (void *)sc;
269 sc->sc_wsmousedev = config_found(self, &b, wsmousedevprint,
270 CFARGS(.iattr = "wsmousedev"));
271 }
272 #endif
273 sc->sc_msreport = 0;
274 }
275
276 static void
wsintr(void * arg)277 wsintr(void *arg)
278 {
279 struct ws_softc *sc = arg;
280 struct sioreg *sio = sc->sc_ctl;
281 uint8_t code = 0;
282 uint16_t rr, rndcsr = 0;
283 bool handled = false;
284
285 rr = getsiocsr(sio);
286 rndcsr = rr;
287 if ((rr & RR_RXRDY) != 0) {
288 do {
289 code = sio->sio_data;
290 if (rr & (RR_FRAMING | RR_OVERRUN | RR_PARITY)) {
291 sio->sio_cmd = WR0_ERRRST;
292 continue;
293 }
294 sc->sc_rxq[sc->sc_rxqtail] = code;
295 sc->sc_rxqtail = OMKBD_NEXTRXQ(sc->sc_rxqtail);
296 } while (((rr = getsiocsr(sio)) & RR_RXRDY) != 0);
297 handled = true;
298 }
299 if ((rr & RR_TXRDY) != 0) {
300 sio->sio_cmd = WR0_RSTPEND;
301 if (sc->sc_tx_busy) {
302 sc->sc_tx_busy = false;
303 sc->sc_tx_done = true;
304 handled = true;
305 }
306 }
307 if (handled) {
308 softint_schedule(sc->sc_si);
309 rnd_add_uint32(&sc->sc_rndsource, (rndcsr << 8) | code);
310 }
311 }
312
313 static void
wssoftintr(void * arg)314 wssoftintr(void *arg)
315 {
316 struct ws_softc *sc = arg;
317 uint8_t code;
318
319 /* handle pending keyboard commands */
320 if (sc->sc_tx_done) {
321 int s;
322
323 s = splserial();
324 sc->sc_tx_done = false;
325 DPRINTF(DEBUG_KBDTX, ("%s: tx complete\n", __func__));
326 if (sc->sc_txqhead != sc->sc_txqtail) {
327 struct sioreg *sio = sc->sc_ctl;
328
329 sc->sc_tx_busy = true;
330 sio->sio_data = sc->sc_txq[sc->sc_txqhead];
331 DPRINTF(DEBUG_KBDTX,
332 ("%s: sio_data <- txq[%2d] (%02x)\n", __func__,
333 sc->sc_txqhead, sc->sc_txq[sc->sc_txqhead]));
334
335 sc->sc_txqhead = OMKBD_NEXTTXQ(sc->sc_txqhead);
336 }
337 splx(s);
338 }
339
340 /* handle received keyboard and mouse data */
341 while (sc->sc_rxqhead != sc->sc_rxqtail) {
342 code = sc->sc_rxq[sc->sc_rxqhead];
343 DPRINTF(DEBUG_RXSOFT, ("%s: %02x <- rxq[%2d]\n", __func__,
344 code, sc->sc_rxqhead));
345 sc->sc_rxqhead = OMKBD_NEXTRXQ(sc->sc_rxqhead);
346 /*
347 * if (code >= 0x80 && code <= 0x87), i.e.
348 * if ((code & 0xf8) == 0x80), then
349 * it's the first byte of 3 byte long mouse report
350 * code[0] & 07 -> LMR button condition
351 * code[1], [2] -> x,y delta
352 * otherwise, key press or release event.
353 */
354 if (sc->sc_msreport == 1) {
355 #if NWSMOUSE > 0
356 sc->sc_msdx = (int8_t)code;
357 #endif
358 sc->sc_msreport = 2;
359 continue;
360 } else if (sc->sc_msreport == 2) {
361 #if NWSMOUSE > 0
362 sc->sc_msdy = (int8_t)code;
363 wsmouse_input(sc->sc_wsmousedev,
364 sc->sc_msbuttons, sc->sc_msdx, sc->sc_msdy, 0, 0,
365 WSMOUSE_INPUT_DELTA);
366 #endif
367 sc->sc_msreport = 0;
368 continue;
369 }
370 if ((code & 0xf8) == 0x80) {
371 #if NWSMOUSE > 0
372 /* buttons: Negative logic to positive */
373 code = ~code;
374 /* LMR->RML: wsevent counts 0 for leftmost */
375 sc->sc_msbuttons =
376 ((code & 1) << 2) | (code & 2) | ((code & 4) >> 2);
377 #endif
378 sc->sc_msreport = 1;
379 continue;
380 }
381 omkbd_input(sc, code);
382 }
383 }
384
385 static void
omkbd_send(struct ws_softc * sc,uint8_t txdata)386 omkbd_send(struct ws_softc *sc, uint8_t txdata)
387 {
388 int s;
389
390 if (!sc->sc_tx_busy) {
391 struct sioreg *sio = sc->sc_ctl;
392
393 DPRINTF(DEBUG_KBDTX,
394 ("%s: sio_data <- %02x\n", __func__, txdata));
395 s = splserial();
396 sc->sc_tx_busy = true;
397 sio->sio_data = txdata;
398 splx(s);
399 } else {
400 s = splsoftserial();
401 sc->sc_txq[sc->sc_txqtail] = txdata;
402 DPRINTF(DEBUG_KBDTX,
403 ("%s: txq[%2d] <- %02x\n", __func__,
404 sc->sc_txqtail, sc->sc_txq[sc->sc_txqtail]));
405 sc->sc_txqtail = OMKBD_NEXTTXQ(sc->sc_txqtail);
406 splx(s);
407 softint_schedule(sc->sc_si);
408 }
409 }
410
411 static void
omkbd_input(struct ws_softc * sc,int data)412 omkbd_input(struct ws_softc *sc, int data)
413 {
414 u_int type;
415 int key;
416
417 omkbd_decode(sc, data, &type, &key);
418
419 #ifdef WSDISPLAY_COMPAT_RAWKBD
420 if (sc->sc_rawkbd) {
421 uint8_t cbuf[2];
422 int c, j = 0;
423
424 c = omkbd_raw[key];
425 if (c == 0x70 /* Kana */ ||
426 c == 0x3a /* CAP */) {
427 /* See comment in !sc->sc_rawkbd case */
428 cbuf[0] = c;
429 wskbd_rawinput(sc->sc_wskbddev, cbuf, 1);
430 cbuf[0] = c | 0x80;
431 wskbd_rawinput(sc->sc_wskbddev, cbuf, 1);
432 } else
433 if (c != 0x00) {
434 /* fake extended scancode if necessary */
435 if (c & 0x80)
436 cbuf[j++] = 0xe0;
437 cbuf[j] = c & 0x7f;
438 if (type == WSCONS_EVENT_KEY_UP)
439 cbuf[j] |= 0x80;
440 j++;
441
442 wskbd_rawinput(sc->sc_wskbddev, cbuf, j);
443 }
444 } else
445 #endif
446 {
447 if (sc->sc_wskbddev != NULL) {
448 if (key == 0x0b /* Kana */ ||
449 key == 0x0e /* CAP */) {
450 /*
451 * LUNA's keyboard doesn't send any keycode
452 * when these modifier keys are released.
453 * Instead, it sends a pressed or released code
454 * per how each modifier LED status will be
455 * changed when the modifier keys are pressed.
456 * To handle this quirk in MI wskbd(4) layer,
457 * we have to send a faked
458 * "pressed and released" sequence here.
459 */
460 wskbd_input(sc->sc_wskbddev,
461 WSCONS_EVENT_KEY_DOWN, key);
462 wskbd_input(sc->sc_wskbddev,
463 WSCONS_EVENT_KEY_UP, key);
464 } else {
465 wskbd_input(sc->sc_wskbddev, type, key);
466 }
467 }
468 }
469 }
470
471 static void
omkbd_decode(struct ws_softc * sc,int datain,u_int * type,int * dataout)472 omkbd_decode(struct ws_softc *sc, int datain, u_int *type, int *dataout)
473 {
474
475 *type = (datain & 0x80) ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN;
476 *dataout = datain & 0x7f;
477 }
478
479 static void
omkbd_complex_buzzer(struct ws_softc * sc,struct wskbd_bell_data * wbd)480 omkbd_complex_buzzer(struct ws_softc *sc, struct wskbd_bell_data *wbd)
481 {
482 uint8_t buzcmd;
483
484 buzcmd = omkbd_get_buzcmd(sc, wbd, OMKBD_BUZZER_DEFAULT);
485 omkbd_send(sc, buzcmd);
486 }
487
488 static uint8_t
omkbd_get_buzcmd(struct ws_softc * sc,struct wskbd_bell_data * wbd,uint8_t obuzcmd)489 omkbd_get_buzcmd(struct ws_softc *sc, struct wskbd_bell_data *wbd,
490 uint8_t obuzcmd)
491 {
492 u_int pitch, period;
493 uint8_t buzcmd;
494
495 pitch = wbd->pitch;
496 period = wbd->period;
497 buzcmd = OMKBD_BUZZER;
498
499 if ((wbd->which & WSKBD_BELL_DOPERIOD) == 0)
500 buzcmd |= obuzcmd & OMKBD_BUZZER_PERIOD;
501 else if (period >= 700)
502 buzcmd |= OMKBD_BUZZER_700MS;
503 else if (period >= 400)
504 buzcmd |= OMKBD_BUZZER_400MS;
505 else if (period >= 150)
506 buzcmd |= OMKBD_BUZZER_150MS;
507 else
508 buzcmd |= OMKBD_BUZZER_40MS;
509
510 if ((wbd->which & WSKBD_BELL_DOPITCH) == 0)
511 buzcmd |= obuzcmd & OMKBD_BUZZER_PITCH;
512 else if (pitch >= 6000)
513 buzcmd |= OMKBD_BUZZER_6000HZ;
514 else if (pitch >= 3000)
515 buzcmd |= OMKBD_BUZZER_3000HZ;
516 else if (pitch >= 1500)
517 buzcmd |= OMKBD_BUZZER_1500HZ;
518 else if (pitch >= 1000)
519 buzcmd |= OMKBD_BUZZER_1000HZ;
520 else if (pitch >= 600)
521 buzcmd |= OMKBD_BUZZER_600HZ;
522 else if (pitch >= 300)
523 buzcmd |= OMKBD_BUZZER_300HZ;
524 else if (pitch >= 150)
525 buzcmd |= OMKBD_BUZZER_150HZ;
526 else
527 buzcmd |= OMKBD_BUZZER_100HZ;
528
529 /* no volume control for buzzer on the LUNA keyboards */
530
531 return buzcmd;
532 }
533
534 static void
ws_cngetc(void * cookie,u_int * type,int * data)535 ws_cngetc(void *cookie, u_int *type, int *data)
536 {
537 struct ws_conscookie *conscookie = cookie;
538 struct sioreg *sio = conscookie->cc_sio;
539 struct ws_softc *sc = conscookie->cc_sc; /* currently unused */
540 int code;
541
542 code = siogetc(sio);
543 omkbd_decode(sc, code, type, data);
544 }
545
546 static void
ws_cnpollc(void * cookie,int on)547 ws_cnpollc(void *cookie, int on)
548 {
549 struct ws_conscookie *conscookie = cookie;
550
551 conscookie->cc_polling = on;
552 }
553
554 static void
ws_cnbell(void * cookie,u_int pitch,u_int period,u_int volume)555 ws_cnbell(void *cookie, u_int pitch, u_int period, u_int volume)
556 {
557 struct ws_conscookie *conscookie = cookie;
558 struct sioreg *sio = conscookie->cc_sio;
559 struct ws_softc *sc = conscookie->cc_sc; /* currently unused */
560 struct wskbd_bell_data wbd;
561 uint8_t buzcmd;
562
563 /*
564 * XXX cnbell(9) man page should describe each args..
565 * (it looks similar to the struct wskbd_bell_data)
566 * pitch: bell frequency in hertz
567 * period: bell period in ms
568 * volume: bell volume as a percentage (0-100) (as spkr(4))
569 */
570 wbd.which = WSKBD_BELL_DOALL;
571 wbd.period = period;
572 wbd.pitch = pitch;
573 wbd.volume = volume;
574 buzcmd = omkbd_get_buzcmd(sc, &wbd, OMKBD_BUZZER_DEFAULT);
575
576 sioputc(sio, buzcmd);
577 }
578
579 /* EXPORT */ void
ws_cnattach(void)580 ws_cnattach(void)
581 {
582 struct sioreg *sio_base;
583
584 sio_base = (struct sioreg *)OBIO_SIO;
585 ws_conscookie.cc_sio = &sio_base[1]; /* channel B */
586
587 /* XXX need CH.B initialization XXX */
588
589 wskbd_cnattach(&ws_consops, &ws_conscookie, &omkbd_keymapdata);
590 }
591
592 static int
omkbd_enable(void * cookie,int on)593 omkbd_enable(void *cookie, int on)
594 {
595
596 return 0;
597 }
598
599 static void
omkbd_set_leds(void * cookie,int leds)600 omkbd_set_leds(void *cookie, int leds)
601 {
602 struct ws_softc *sc = cookie;
603 uint8_t capsledcmd, kanaledcmd;
604
605 if (sc == NULL) {
606 /*
607 * This has been checked by the caller in wskbd(9) layer
608 * for the early console, but just for sanity.
609 */
610 return;
611 }
612
613 sc->sc_leds = leds;
614 if ((leds & WSKBD_LED_CAPS) != 0) {
615 capsledcmd = OMKBD_LED_ON_CAPS;
616 } else {
617 capsledcmd = OMKBD_LED_OFF_CAPS;
618 }
619
620 #if 0 /* no KANA lock support in wskbd */
621 if ((leds & WSKBD_LED_KANA) != 0) {
622 kanaledcmd = OMKBD_LED_ON_KANA;
623 } else
624 #endif
625 {
626 kanaledcmd = OMKBD_LED_OFF_KANA;
627 }
628
629 if (sc->sc_conscookie->cc_polling != 0) {
630 struct sioreg *sio = sc->sc_ctl;
631
632 sioputc(sio, capsledcmd);
633 sioputc(sio, kanaledcmd);
634 } else {
635 omkbd_send(sc, capsledcmd);
636 omkbd_send(sc, kanaledcmd);
637 }
638 }
639
640 static int
omkbd_ioctl(void * cookie,u_long cmd,void * data,int flag,struct lwp * l)641 omkbd_ioctl(void *cookie, u_long cmd, void *data, int flag, struct lwp *l)
642 {
643 struct ws_softc *sc = cookie;
644 struct wskbd_bell_data *wbd;
645
646 switch (cmd) {
647 case WSKBDIO_GTYPE:
648 *(int *)data = WSKBD_TYPE_LUNA;
649 return 0;
650 case WSKBDIO_SETLEDS:
651 omkbd_set_leds(cookie, *(int *)data);
652 return 0;
653 case WSKBDIO_GETLEDS:
654 *(int *)data = sc->sc_leds;
655 return 0;
656
657 /*
658 * Note all WSKBDIO_*BELL ioctl(2)s except WSKBDIO_COMPLEXBELL
659 * are handled MI wskbd(4) layer.
660 * (wskbd_displayioctl() in src/sys/dev/wscons/wskbd.c)
661 */
662 case WSKBDIO_COMPLEXBELL:
663 wbd = data;
664 DPRINTF(DEBUG_BUZZER,
665 ("%s: WSKBDIO_COMPLEXBELL: pitch = %d, period = %d\n",
666 __func__, wbd->pitch, wbd->period));
667 omkbd_complex_buzzer(sc, wbd);
668 return 0;
669
670 #ifdef WSDISPLAY_COMPAT_RAWKBD
671 case WSKBDIO_SETMODE:
672 sc->sc_rawkbd = *(int *)data == WSKBD_RAW;
673 return 0;
674 case WSKBDIO_GETMODE:
675 *(int *)data = sc->sc_rawkbd;
676 return 0;
677 #endif
678 }
679 return EPASSTHROUGH;
680 }
681
682 #if NWSMOUSE > 0
683
684 static int
omms_enable(void * cookie)685 omms_enable(void *cookie)
686 {
687 struct ws_softc *sc = cookie;
688
689 /* enable 3 byte long mouse reporting */
690 omkbd_send(sc, OMKBD_MOUSE_ON);
691
692 return 0;
693 }
694
695 /*ARGUSED*/
696 static int
omms_ioctl(void * cookie,u_long cmd,void * data,int flag,struct lwp * l)697 omms_ioctl(void *cookie, u_long cmd, void *data, int flag, struct lwp *l)
698 {
699
700 if (cmd == WSMOUSEIO_GTYPE) {
701 *(u_int *)data = 0x19991005; /* XXX */
702 return 0;
703 }
704 return EPASSTHROUGH;
705 }
706
707 static void
omms_disable(void * cookie)708 omms_disable(void *cookie)
709 {
710 struct ws_softc *sc = cookie;
711
712 omkbd_send(sc, OMKBD_MOUSE_OFF);
713 }
714 #endif
715