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