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