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