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