xref: /netbsd-src/sys/dev/hpc/hpf1275a_tty.c (revision 23c8222edbfb0f0932d88a8351d3a0cf817dfb9e)
1 /*	$NetBSD: hpf1275a_tty.c,v 1.2 2004/10/15 04:38:37 thorpej 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.2 2004/10/15 04:38:37 thorpej Exp $");
32 
33 #include <sys/param.h>
34 #include <sys/kernel.h>
35 #include <sys/conf.h>
36 #include <sys/device.h>
37 #include <sys/tty.h>
38 #include <sys/fcntl.h>
39 #include <sys/proc.h>		/* XXX: for curproc */
40 #include <sys/systm.h>
41 #ifdef GPROF
42 #include <sys/gmon.h>
43 #endif
44 
45 #include <dev/pckbport/wskbdmap_mfii.h>
46 #ifdef WSDISPLAY_COMPAT_RAWKBD
47 #include <dev/hpc/pckbd_encode.h>
48 #endif
49 
50 #include <dev/wscons/wsconsio.h>
51 #include <dev/wscons/wskbdvar.h>
52 #include <dev/wscons/wsksymdef.h>
53 #include <dev/wscons/wsksymvar.h>
54 
55 
56 extern struct cfdriver hpf1275a_cd;
57 
58 struct hpf1275a_softc {
59 	struct device sc_dev;
60 
61 	struct tty *sc_tp;		/* back reference to the tty */
62 	struct device *sc_wskbd;	/* wskbd child */
63 	int sc_enabled;
64 
65 };
66 
67 
68 /* pseudo-device initialization */
69 extern void	hpf1275aattach(int);
70 
71 /* line discipline methods */
72 static int	hpf1275a_open(dev_t, struct tty *);
73 static int	hpf1275a_close(struct tty *, int);
74 static int	hpf1275a_input(int, struct tty *);
75 
76 /* autoconf(9) methods */
77 static int	hpf1275a_match(struct device *, struct cfdata *, void *);
78 static void	hpf1275a_attach(struct device *, struct device *, void *);
79 static int	hpf1275a_detach(struct device *, int);
80 
81 /* wskbd(4) accessops */
82 static int	hpf1275a_wskbd_enable(void *, int);
83 static void	hpf1275a_wskbd_set_leds(void *, int);
84 static int	hpf1275a_wskbd_ioctl(void *, u_long, caddr_t, int,
85 				     struct proc *);
86 
87 
88 CFATTACH_DECL(hpf1275a, sizeof(struct hpf1275a_softc),
89     hpf1275a_match, hpf1275a_attach, hpf1275a_detach, NULL);
90 
91 
92 static struct linesw hpf1275a_disc = {
93 	"hpf1275a", -1, hpf1275a_open, hpf1275a_close,
94 	ttyerrio, ttyerrio, ttynullioctl,
95 	hpf1275a_input, ttstart, nullmodem, ttpoll,
96 };
97 
98 
99 static const struct wskbd_accessops hpf1275a_wskbd_accessops = {
100 	hpf1275a_wskbd_enable,
101 	hpf1275a_wskbd_set_leds,
102 	hpf1275a_wskbd_ioctl
103 };
104 
105 
106 static struct wskbd_mapdata hpf1275a_wskbd_keymapdata = {
107 	pckbd_keydesctab, KB_US
108 };
109 
110 
111 /* F1275A scancodes -> XT scancodes so that we can use pckbd_keydesctab. */
112 static uint8_t hpf1275a_to_xtscan[128] = {
113 	[0x04] = 30,		/* a */
114 	[0x05] = 48,		/* b */
115 	[0x06] = 46,		/* c */
116 	[0x07] = 32,		/* d */
117 	[0x08] = 18,		/* e */
118 	[0x09] = 33,		/* f */
119 	[0x0a] = 34,		/* g */
120 	[0x0b] = 35,		/* h */
121 	[0x0c] = 23,		/* i */
122 	[0x0d] = 36,		/* j */
123 	[0x0e] = 37,		/* k */
124 	[0x0f] = 38,		/* l */
125 	[0x10] = 50,		/* m */
126 	[0x11] = 49,		/* n */
127 	[0x12] = 24,		/* o */
128 	[0x13] = 25,		/* p */
129 	[0x14] = 16,		/* q */
130 	[0x15] = 19,		/* r */
131 	[0x16] = 31,		/* s */
132 	[0x17] = 20,		/* t */
133 	[0x18] = 22,		/* u */
134 	[0x19] = 47,		/* v */
135 	[0x1a] = 17,		/* w */
136 	[0x1b] = 45,		/* x */
137 	[0x1c] = 21,		/* y */
138 	[0x1d] = 44,		/* z */
139 
140 	[0x1e] = 2,		/* 1 */
141 	[0x1f] = 3,		/* 2 */
142 	[0x20] = 4,		/* 3 */
143 	[0x21] = 5,		/* 4 */
144 	[0x22] = 6,		/* 5 */
145 	[0x23] = 7,		/* 6 */
146 	[0x24] = 8,		/* 7 */
147 	[0x25] = 9,		/* 8 */
148 	[0x26] = 10,		/* 9 */
149 	[0x27] = 11,		/* 0 */
150 
151 	[0x28] = 28,		/* Enter */
152 
153 	[0x29] = 1,		/* ESC */
154 	[0x2a] = 14,		/* Backspace */
155 	[0x2b] = 15,		/* Tab */
156 	[0x2c] = 57,		/* Space */
157 
158 	[0x2d] = 12,		/* - */
159 	[0x2e] = 13,		/* = */
160 	[0x2f] = 26,		/* [ */
161 	[0x30] = 27,		/* ] */
162 	[0x31] = 43,		/* \ */
163 
164 	[0x33] = 39,		/* ; */
165 	[0x34] = 40,		/* ' */
166 	[0x35] = 41,		/* ` */
167 	[0x36] = 51,		/* , */
168 	[0x37] = 52,		/* . */
169 	[0x38] = 53,		/* / */
170 
171 	[0x3a] = 59,		/* F1 */
172 	[0x3b] = 60,		/* F2 */
173 	[0x3c] = 61,		/* F3 */
174 	[0x3d] = 62,		/* F4 */
175 	[0x3e] = 63,		/* F5 */
176 	[0x3f] = 64,		/* F6 */
177 	[0x40] = 65,		/* F7 */
178 	[0x41] = 66,		/* F8 */
179 
180 	[0x42] = 68,		/* "OK" -> F10 */
181 	[0x43] = 87,		/* "Cancel" -> F11 */
182 
183 	[0x4c] = 211,		/* Del */
184 
185 	[0x4f] = 205,		/* Right */
186 	[0x50] = 203,		/* Left  */
187 	[0x51] = 208,		/* Down  */
188 	[0x52] = 200,		/* Up    */
189 
190 	[0x53] = 67,		/* "task switch" -> F9 */
191 
192 	[0x65] = 221,		/* windows */
193 	[0x66] = 88,		/* "keyboard" -> F12 */
194 
195 	[0x74] = 42,		/* Shift (left) */
196 	[0x75] = 54,		/* Shift (right) */
197 	[0x76] = 56,		/* Alt (left) */
198 	[0x77] = 184,		/* Fn -> AltGr == Mode Switch */
199 	[0x78] = 29,		/* Control (left) */
200 };
201 
202 
203 /*
204  * Pseudo-device initialization routine called from main().
205  */
206 void
207 hpf1275aattach(int n)
208 {
209 	int discno;
210 	int error;
211 
212 	discno = ttyldisc_add(&hpf1275a_disc, -1);
213 	if (discno < 0) {
214 		printf("%s: unable to register line discipline\n",
215 		       hpf1275a_cd.cd_name);
216 		return;
217 	}
218 
219 	error = config_cfattach_attach(hpf1275a_cd.cd_name, &hpf1275a_ca);
220 	if (error) {
221 		printf("%s: unable to register cfattach, error = %d\n",
222 		       hpf1275a_cd.cd_name, error);
223 		config_cfdriver_detach(&hpf1275a_cd);
224 		ttyldisc_remove(hpf1275a_disc.l_name);
225 	}
226 }
227 
228 
229 /*
230  * Autoconf match routine.
231  *
232  * XXX: unused: config_attach_pseudo(9) does not call ca_match.
233  */
234 static int
235 hpf1275a_match(struct device *self, struct cfdata *cfdata, void *arg)
236 {
237 
238 	/* pseudo-device; always present */
239 	return (1);
240 }
241 
242 
243 /*
244  * Autoconf attach routine.  Called by config_attach_pseudo(9) when we
245  * open the line discipline.
246  */
247 static void
248 hpf1275a_attach(struct device *parent, struct device *self, void *aux)
249 {
250 	struct hpf1275a_softc *sc = (struct hpf1275a_softc *)self;
251 	struct wskbddev_attach_args wska;
252 
253 	wska.console = 0;
254 	wska.keymap = &hpf1275a_wskbd_keymapdata;
255 	wska.accessops = &hpf1275a_wskbd_accessops;
256 	wska.accesscookie = sc;
257 
258 	sc->sc_enabled = 0;
259 	sc->sc_wskbd = config_found(self, &wska, wskbddevprint);
260 }
261 
262 
263 /*
264  * Autoconf detach routine.  Called when we close the line discipline.
265  */
266 static int
267 hpf1275a_detach(struct device *self, int flags)
268 {
269 	struct hpf1275a_softc *sc = (struct hpf1275a_softc *)self;
270 	int error;
271 
272 	if (sc->sc_wskbd == NULL)
273 		return (0);
274 
275 	error = config_detach(sc->sc_wskbd, 0);
276 
277 	return (error);
278 }
279 
280 
281 /*
282  * Line discipline open routine.
283  */
284 int
285 hpf1275a_open(dev_t dev, struct tty *tp)
286 {
287 	static struct cfdata hpf1275a_cfdata = {
288 		.cf_name = "hpf1275a",
289 		.cf_atname = "hpf1275a",
290 		.cf_unit = DVUNIT_ANY,
291 		.cf_fstate = FSTATE_STAR,
292 	};
293 	struct proc *p = curproc;		/* XXX */
294 	struct hpf1275a_softc *sc;
295 	int error, s;
296 
297 	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
298 		return (error);
299 
300 	s = spltty();
301 
302 	sc = (struct hpf1275a_softc *) config_attach_pseudo(&hpf1275a_cfdata);
303 	if (sc == NULL) {
304 		splx(s);
305 		return (EIO);
306 	}
307 
308 	tp->t_sc = sc;
309 	sc->sc_tp = tp;
310 
311 	splx(s);
312 	return (0);
313 }
314 
315 
316 /*
317  * Line discipline close routine.
318  */
319 int
320 hpf1275a_close(struct tty *tp, int flag)
321 {
322 	struct hpf1275a_softc *sc = (struct hpf1275a_softc *)tp->t_sc;
323 	int s;
324 
325 	s = spltty();
326 	ttyflush(tp, FREAD | FWRITE);
327 	tp->t_linesw = linesw[0]; /* default line discipline */
328 	if (sc != NULL) {
329 		tp->t_sc = NULL;
330 		if (sc->sc_tp == tp)
331 			config_detach(&sc->sc_dev, 0);
332 	}
333 	splx(s);
334 	return (0);
335 }
336 
337 
338 /*
339  * Feed input from the keyboard to wskbd(4).
340  */
341 int
342 hpf1275a_input(int c, struct tty *tp)
343 {
344 	struct hpf1275a_softc *sc = (struct hpf1275a_softc *)tp->t_sc;
345 	int code;
346 	u_int type;
347 	int xtscan;
348 
349 	if (!sc->sc_enabled)
350 		return (0);
351 
352 	if (c & TTY_ERRORMASK)
353 		return (0);	/* TODO? */
354 
355 	code = c & TTY_CHARMASK;
356 	if (code & 0x80) {
357 		type = WSCONS_EVENT_KEY_UP;
358 		code &= ~0x80;
359 	} else
360 		type = WSCONS_EVENT_KEY_DOWN;
361 
362 	xtscan = hpf1275a_to_xtscan[code];
363 	if (xtscan == 0) {
364 		printf("hpf1275a: unknown code 0x%x\n", code);
365 		return (0);
366 	}
367 
368 	KASSERT(sc->sc_wskbd != NULL);
369 	wskbd_input(sc->sc_wskbd, type, xtscan);
370 
371 	return (0);
372 }
373 
374 
375 static int
376 hpf1275a_wskbd_enable(void *self, int on)
377 {
378 	struct hpf1275a_softc *sc = (struct hpf1275a_softc *)self;
379 
380 	sc->sc_enabled = on;
381 	return (0);
382 }
383 
384 
385 /* ARGSUSED */
386 static void
387 hpf1275a_wskbd_set_leds(void *self, int leds)
388 {
389 
390 	/* this keyboard has no leds; nothing to do */
391 	return;
392 }
393 
394 
395 static int
396 hpf1275a_wskbd_ioctl(void *self, u_long cmd, caddr_t data, int flag,
397 		     struct proc *p)
398 {
399 	/* struct hpf1275a_softc *sc = (struct hpf1275a_softc *)self; */
400 
401 	switch (cmd) {
402 	case WSKBDIO_GTYPE:
403 		*(int *)data = WSKBD_TYPE_HPC_KBD; /* may be use new type? */
404 		return (0);
405 
406 	case WSKBDIO_GETLEDS:
407 		*(int *)data = 0; /* this keyboard has no leds */
408 		return (0);
409 
410 	default:
411 		return (EPASSTHROUGH);
412 	}
413 }
414