xref: /netbsd-src/sys/dev/hpc/hpf1275a_tty.c (revision 7330f729ccf0bd976a06f95fad452fe774fc7fd1)
1 /*	$NetBSD: hpf1275a_tty.c,v 1.29 2017/10/28 04:53:56 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.29 2017/10/28 04:53:56 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
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
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
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);
275 }
276 
277 
278 /*
279  * Autoconf detach routine.  Called when we close the line discipline.
280  */
281 static int
282 hpf1275a_detach(device_t self, int flags)
283 {
284 	struct hpf1275a_softc *sc = device_private(self);
285 	int error;
286 
287 	if (sc->sc_wskbd == NULL)
288 		return (0);
289 
290 	error = config_detach(sc->sc_wskbd, 0);
291 
292 	return (error);
293 }
294 
295 
296 /*
297  * Line discipline open routine.
298  */
299 static int
300 hpf1275a_open(dev_t dev, struct tty *tp)
301 {
302 	static struct cfdata hpf1275a_cfdata = {
303 		.cf_name = "hpf1275a",
304 		.cf_atname = "hpf1275a",
305 		.cf_unit = 0,
306 		.cf_fstate = FSTATE_STAR,
307 	};
308 	struct lwp *l = curlwp;		/* XXX */
309 	struct hpf1275a_softc *sc;
310 	device_t self;
311 	int error, s;
312 
313 	if ((error = kauth_authorize_device_tty(l->l_cred,
314 			KAUTH_DEVICE_TTY_OPEN, tp)))
315 		return (error);
316 
317 	s = spltty();
318 
319 	if (tp->t_linesw == &hpf1275a_disc) {
320 		splx(s);
321 		return 0;
322 	}
323 
324 	self = config_attach_pseudo(&hpf1275a_cfdata);
325 	if (self == NULL) {
326 		splx(s);
327 		return (EIO);
328 	}
329 
330 	sc = device_private(self);
331 	tp->t_sc = sc;
332 	sc->sc_tp = tp;
333 
334 	splx(s);
335 	return (0);
336 }
337 
338 
339 /*
340  * Line discipline close routine.
341  */
342 static int
343 hpf1275a_close(struct tty *tp, int flag)
344 {
345 	struct hpf1275a_softc *sc = tp->t_sc;
346 	int s;
347 
348 	s = spltty();
349 	mutex_spin_enter(&tty_lock);
350 	ttyflush(tp, FREAD | FWRITE);
351 	mutex_spin_exit(&tty_lock);	 /* XXX */
352 	ttyldisc_release(tp->t_linesw);
353 	tp->t_linesw = ttyldisc_default();
354 	if (sc != NULL) {
355 		tp->t_sc = NULL;
356 		if (sc->sc_tp == tp)
357 			config_detach(sc->sc_dev, 0);
358 	}
359 	splx(s);
360 	return (0);
361 }
362 
363 
364 /*
365  * Feed input from the keyboard to wskbd(4).
366  */
367 static int
368 hpf1275a_input(int c, struct tty *tp)
369 {
370 	struct hpf1275a_softc *sc = tp->t_sc;
371 	int code;
372 	u_int type;
373 	int xtscan;
374 
375 	if (!sc->sc_enabled)
376 		return (0);
377 
378 	if (c & TTY_ERRORMASK)
379 		return (0);	/* TODO? */
380 
381 	code = c & TTY_CHARMASK;
382 	if (code & 0x80) {
383 		type = WSCONS_EVENT_KEY_UP;
384 		code &= ~0x80;
385 	} else
386 		type = WSCONS_EVENT_KEY_DOWN;
387 
388 	xtscan = hpf1275a_to_xtscan[code];
389 	if (xtscan == 0) {
390 		aprint_error_dev(sc->sc_dev, "unknown code 0x%x\n", code);
391 		return (0);
392 	}
393 
394 	KASSERT(sc->sc_wskbd != NULL);
395 
396 #ifdef WSDISPLAY_COMPAT_RAWKBD
397 	if (sc->sc_rawkbd) {
398 		u_char data[16];
399 		int n;
400 
401 		n = pckbd_encode(type, xtscan, data);
402 		wskbd_rawinput(sc->sc_wskbd, data, n);
403 	} else
404 #endif
405 		wskbd_input(sc->sc_wskbd, type, xtscan);
406 
407 	return (0);
408 }
409 
410 
411 static int
412 hpf1275a_wskbd_enable(void *self, int on)
413 {
414 	struct hpf1275a_softc *sc = self;
415 
416 	sc->sc_enabled = on;
417 	return (0);
418 }
419 
420 
421 /* ARGSUSED */
422 static void
423 hpf1275a_wskbd_set_leds(void *self, int leds)
424 {
425 
426 	/* this keyboard has no leds; nothing to do */
427 	return;
428 }
429 
430 
431 static int
432 hpf1275a_wskbd_ioctl(void *self, u_long cmd, void *data, int flag,
433 		     struct lwp *l)
434 {
435 #ifdef WSDISPLAY_COMPAT_RAWKBD
436 	struct hpf1275a_softc *sc = self;
437 #endif
438 
439 	switch (cmd) {
440 	case WSKBDIO_GTYPE:
441 		*(int *)data = WSKBD_TYPE_HPC_KBD; /* may be use new type? */
442 		return (0);
443 
444 	case WSKBDIO_GETLEDS:
445 		*(int *)data = 0; /* this keyboard has no leds */
446 		return (0);
447 
448 #ifdef WSDISPLAY_COMPAT_RAWKBD
449 	case WSKBDIO_SETMODE:
450 		sc->sc_rawkbd = (*(int *)data == WSKBD_RAW);
451 		return (0);
452 #endif
453 
454 	default:
455 		return (EPASSTHROUGH);
456 	}
457 }
458