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