xref: /netbsd/sys/arch/luna68k/dev/lunaws.c (revision 806654ca)
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