1 /* $NetBSD: hpf1275a_tty.c,v 1.33 2023/05/10 00:09:54 riastradh Exp $ */
2
3 /*
4 * Copyright (c) 2004 Valeriy E. Ushakov
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include <sys/cdefs.h>
31 __KERNEL_RCSID(0, "$NetBSD: hpf1275a_tty.c,v 1.33 2023/05/10 00:09:54 riastradh Exp $");
32
33 #include "opt_wsdisplay_compat.h"
34
35 #include <sys/param.h>
36 #include <sys/kernel.h>
37 #include <sys/conf.h>
38 #include <sys/device.h>
39 #include <sys/tty.h>
40 #include <sys/fcntl.h>
41 #include <sys/proc.h>
42 #include <sys/systm.h>
43 #include <sys/kauth.h>
44
45 #include <dev/wscons/wsconsio.h>
46 #include <dev/wscons/wskbdvar.h>
47 #include <dev/wscons/wsksymdef.h>
48 #include <dev/wscons/wsksymvar.h>
49
50 #include <dev/pckbport/wskbdmap_mfii.h>
51 #ifdef WSDISPLAY_COMPAT_RAWKBD
52 #include <dev/hpc/pckbd_encode.h>
53 #endif
54
55 #include "ioconf.h"
56
57 struct hpf1275a_softc {
58 device_t sc_dev;
59
60 struct tty *sc_tp; /* back reference to the tty */
61 device_t sc_wskbd; /* wskbd child */
62 int sc_enabled;
63 #ifdef WSDISPLAY_COMPAT_RAWKBD
64 int sc_rawkbd;
65 #endif
66 };
67
68
69 /* pseudo-device initialization */
70 extern void hpf1275aattach(int);
71
72 /* line discipline methods */
73 static int hpf1275a_open(dev_t, struct tty *);
74 static int hpf1275a_close(struct tty *, int);
75 static int hpf1275a_input(int, struct tty *);
76
77 /* autoconf(9) methods */
78 static int hpf1275a_match(device_t, cfdata_t, void *);
79 static void hpf1275a_attach(device_t, device_t, void *);
80 static int hpf1275a_detach(device_t, int);
81
82 /* wskbd(4) accessops */
83 static int hpf1275a_wskbd_enable(void *, int);
84 static void hpf1275a_wskbd_set_leds(void *, int);
85 static int hpf1275a_wskbd_ioctl(void *, u_long, void *, int,
86 struct lwp *);
87
88
89 /*
90 * It doesn't need to be exported, as only hpf1275aattach() uses it,
91 * but there's no "official" way to make it static.
92 */
93 CFATTACH_DECL_NEW(hpf1275a, sizeof(struct hpf1275a_softc),
94 hpf1275a_match, hpf1275a_attach, hpf1275a_detach, NULL);
95
96
97 static struct linesw hpf1275a_disc = {
98 .l_name = "hpf1275a",
99 .l_open = hpf1275a_open,
100 .l_close = hpf1275a_close,
101 .l_read = ttyerrio,
102 .l_write = ttyerrio,
103 .l_ioctl = ttynullioctl,
104 .l_rint = hpf1275a_input,
105 .l_start = ttstart,
106 .l_modem = nullmodem,
107 .l_poll = ttpoll
108 };
109
110
111 static const struct wskbd_accessops hpf1275a_wskbd_accessops = {
112 hpf1275a_wskbd_enable,
113 hpf1275a_wskbd_set_leds,
114 hpf1275a_wskbd_ioctl
115 };
116
117
118 static const struct wskbd_mapdata hpf1275a_wskbd_keymapdata = {
119 pckbd_keydesctab, KB_US
120 };
121
122
123 /* F1275A scancodes -> XT scancodes so that we can use pckbd_keydesctab. */
124 static const uint8_t hpf1275a_to_xtscan[128] = {
125 [0x04] = 30, /* a */
126 [0x05] = 48, /* b */
127 [0x06] = 46, /* c */
128 [0x07] = 32, /* d */
129 [0x08] = 18, /* e */
130 [0x09] = 33, /* f */
131 [0x0a] = 34, /* g */
132 [0x0b] = 35, /* h */
133 [0x0c] = 23, /* i */
134 [0x0d] = 36, /* j */
135 [0x0e] = 37, /* k */
136 [0x0f] = 38, /* l */
137 [0x10] = 50, /* m */
138 [0x11] = 49, /* n */
139 [0x12] = 24, /* o */
140 [0x13] = 25, /* p */
141 [0x14] = 16, /* q */
142 [0x15] = 19, /* r */
143 [0x16] = 31, /* s */
144 [0x17] = 20, /* t */
145 [0x18] = 22, /* u */
146 [0x19] = 47, /* v */
147 [0x1a] = 17, /* w */
148 [0x1b] = 45, /* x */
149 [0x1c] = 21, /* y */
150 [0x1d] = 44, /* z */
151
152 [0x1e] = 2, /* 1 */
153 [0x1f] = 3, /* 2 */
154 [0x20] = 4, /* 3 */
155 [0x21] = 5, /* 4 */
156 [0x22] = 6, /* 5 */
157 [0x23] = 7, /* 6 */
158 [0x24] = 8, /* 7 */
159 [0x25] = 9, /* 8 */
160 [0x26] = 10, /* 9 */
161 [0x27] = 11, /* 0 */
162
163 [0x28] = 28, /* Enter */
164
165 [0x29] = 1, /* ESC */
166 [0x2a] = 14, /* Backspace */
167 [0x2b] = 15, /* Tab */
168 [0x2c] = 57, /* Space */
169
170 [0x2d] = 12, /* - */
171 [0x2e] = 13, /* = */
172 [0x2f] = 26, /* [ */
173 [0x30] = 27, /* ] */
174 [0x31] = 43, /* \ */
175
176 [0x33] = 39, /* ; */
177 [0x34] = 40, /* ' */
178 [0x35] = 41, /* ` */
179 [0x36] = 51, /* , */
180 [0x37] = 52, /* . */
181 [0x38] = 53, /* / */
182
183 [0x3a] = 59, /* F1 */
184 [0x3b] = 60, /* F2 */
185 [0x3c] = 61, /* F3 */
186 [0x3d] = 62, /* F4 */
187 [0x3e] = 63, /* F5 */
188 [0x3f] = 64, /* F6 */
189 [0x40] = 65, /* F7 */
190 [0x41] = 66, /* F8 */
191
192 [0x42] = 68, /* "OK" -> F10 */
193 [0x43] = 87, /* "Cancel" -> F11 */
194
195 [0x4c] = 211, /* Del */
196
197 [0x4f] = 205, /* Right */
198 [0x50] = 203, /* Left */
199 [0x51] = 208, /* Down */
200 [0x52] = 200, /* Up */
201
202 [0x53] = 67, /* "task switch" -> F9 */
203
204 [0x65] = 221, /* windows */
205 [0x66] = 88, /* "keyboard" -> F12 */
206
207 [0x74] = 42, /* Shift (left) */
208 [0x75] = 54, /* Shift (right) */
209 [0x76] = 56, /* Alt (left) */
210 [0x77] = 184, /* Fn -> AltGr == Mode Switch */
211 [0x78] = 29, /* Control (left) */
212 };
213
214
215 /*
216 * Pseudo-device initialization routine called from main().
217 */
218 void
hpf1275aattach(int n)219 hpf1275aattach(int n)
220 {
221 int error;
222
223 error = ttyldisc_attach(&hpf1275a_disc);
224 if (error) {
225 printf("%s: unable to register line discipline, error = %d\n",
226 hpf1275a_cd.cd_name, error);
227 return;
228 }
229
230 error = config_cfattach_attach(hpf1275a_cd.cd_name, &hpf1275a_ca);
231 if (error) {
232 printf("%s: unable to register cfattach, error = %d\n",
233 hpf1275a_cd.cd_name, error);
234 config_cfdriver_detach(&hpf1275a_cd);
235 (void) ttyldisc_detach(&hpf1275a_disc);
236 }
237 }
238
239
240 /*
241 * Autoconf match routine.
242 *
243 * XXX: unused: config_attach_pseudo(9) does not call ca_match.
244 */
245 static int
hpf1275a_match(device_t self,cfdata_t cfdata,void * arg)246 hpf1275a_match(device_t self, cfdata_t cfdata, void *arg)
247 {
248
249 /* pseudo-device; always present */
250 return (1);
251 }
252
253
254 /*
255 * Autoconf attach routine. Called by config_attach_pseudo(9) when we
256 * open the line discipline.
257 */
258 static void
hpf1275a_attach(device_t parent,device_t self,void * aux)259 hpf1275a_attach(device_t parent, device_t self, void *aux)
260 {
261 struct hpf1275a_softc *sc = device_private(self);
262 struct wskbddev_attach_args wska;
263
264 wska.console = 0;
265 wska.keymap = &hpf1275a_wskbd_keymapdata;
266 wska.accessops = &hpf1275a_wskbd_accessops;
267 wska.accesscookie = sc;
268
269 sc->sc_dev = self;
270 sc->sc_enabled = 0;
271 #ifdef WSDISPLAY_COMPAT_RAWKBD
272 sc->sc_rawkbd = 0;
273 #endif
274 sc->sc_wskbd = config_found(self, &wska, wskbddevprint, CFARGS_NONE);
275 }
276
277
278 /*
279 * Autoconf detach routine. Called when we close the line discipline.
280 */
281 static int
hpf1275a_detach(device_t self,int flags)282 hpf1275a_detach(device_t self, int flags)
283 {
284 struct hpf1275a_softc *sc = device_private(self);
285 int error;
286
287 error = config_detach_children(self, flags);
288 if (error)
289 return error;
290
291 return 0;
292 }
293
294
295 /*
296 * Line discipline open routine.
297 */
298 static int
hpf1275a_open(dev_t dev,struct tty * tp)299 hpf1275a_open(dev_t dev, struct tty *tp)
300 {
301 static struct cfdata hpf1275a_cfdata = {
302 .cf_name = "hpf1275a",
303 .cf_atname = "hpf1275a",
304 .cf_unit = 0,
305 .cf_fstate = FSTATE_STAR,
306 };
307 struct lwp *l = curlwp; /* XXX */
308 struct hpf1275a_softc *sc;
309 device_t self;
310 int error, s;
311
312 if ((error = kauth_authorize_device_tty(l->l_cred,
313 KAUTH_DEVICE_TTY_OPEN, tp)))
314 return (error);
315
316 s = spltty();
317
318 if (tp->t_linesw == &hpf1275a_disc) {
319 splx(s);
320 return 0;
321 }
322
323 self = config_attach_pseudo(&hpf1275a_cfdata);
324 if (self == NULL) {
325 splx(s);
326 return (EIO);
327 }
328
329 sc = device_private(self);
330 tp->t_sc = sc;
331 sc->sc_tp = tp;
332
333 splx(s);
334 return (0);
335 }
336
337
338 /*
339 * Line discipline close routine.
340 */
341 static int
hpf1275a_close(struct tty * tp,int flag)342 hpf1275a_close(struct tty *tp, int flag)
343 {
344 struct hpf1275a_softc *sc = tp->t_sc;
345 int s;
346
347 s = spltty();
348 ttylock(tp);
349 ttyflush(tp, FREAD | FWRITE);
350 ttyunlock(tp); /* XXX */
351 ttyldisc_release(tp->t_linesw);
352 tp->t_linesw = ttyldisc_default();
353 if (sc != NULL) {
354 tp->t_sc = NULL;
355 if (sc->sc_tp == tp)
356 config_detach(sc->sc_dev, 0);
357 }
358 splx(s);
359 return (0);
360 }
361
362
363 /*
364 * Feed input from the keyboard to wskbd(4).
365 */
366 static int
hpf1275a_input(int c,struct tty * tp)367 hpf1275a_input(int c, struct tty *tp)
368 {
369 struct hpf1275a_softc *sc = tp->t_sc;
370 int code;
371 u_int type;
372 int xtscan;
373
374 if (!sc->sc_enabled)
375 return (0);
376
377 if (c & TTY_ERRORMASK)
378 return (0); /* TODO? */
379
380 code = c & TTY_CHARMASK;
381 if (code & 0x80) {
382 type = WSCONS_EVENT_KEY_UP;
383 code &= ~0x80;
384 } else
385 type = WSCONS_EVENT_KEY_DOWN;
386
387 xtscan = hpf1275a_to_xtscan[code];
388 if (xtscan == 0) {
389 aprint_error_dev(sc->sc_dev, "unknown code 0x%x\n", code);
390 return (0);
391 }
392
393 KASSERT(sc->sc_wskbd != NULL);
394
395 #ifdef WSDISPLAY_COMPAT_RAWKBD
396 if (sc->sc_rawkbd) {
397 u_char data[16];
398 int n;
399
400 n = pckbd_encode(type, xtscan, data);
401 wskbd_rawinput(sc->sc_wskbd, data, n);
402 } else
403 #endif
404 wskbd_input(sc->sc_wskbd, type, xtscan);
405
406 return (0);
407 }
408
409
410 static int
hpf1275a_wskbd_enable(void * self,int on)411 hpf1275a_wskbd_enable(void *self, int on)
412 {
413 struct hpf1275a_softc *sc = self;
414
415 sc->sc_enabled = on;
416 return (0);
417 }
418
419
420 /* ARGSUSED */
421 static void
hpf1275a_wskbd_set_leds(void * self,int leds)422 hpf1275a_wskbd_set_leds(void *self, int leds)
423 {
424
425 /* this keyboard has no leds; nothing to do */
426 return;
427 }
428
429
430 static int
hpf1275a_wskbd_ioctl(void * self,u_long cmd,void * data,int flag,struct lwp * l)431 hpf1275a_wskbd_ioctl(void *self, u_long cmd, void *data, int flag,
432 struct lwp *l)
433 {
434 #ifdef WSDISPLAY_COMPAT_RAWKBD
435 struct hpf1275a_softc *sc = self;
436 #endif
437
438 switch (cmd) {
439 case WSKBDIO_GTYPE:
440 *(int *)data = WSKBD_TYPE_HPC_KBD; /* may be use new type? */
441 return (0);
442
443 case WSKBDIO_GETLEDS:
444 *(int *)data = 0; /* this keyboard has no leds */
445 return (0);
446
447 #ifdef WSDISPLAY_COMPAT_RAWKBD
448 case WSKBDIO_SETMODE:
449 sc->sc_rawkbd = (*(int *)data == WSKBD_RAW);
450 return (0);
451 #endif
452
453 default:
454 return (EPASSTHROUGH);
455 }
456 }
457