xref: /openbsd-src/sys/dev/sun/sunkbd.c (revision f0cdf84b2ddcee98f5a05c229aef4efc8fb72fd6)
1*f0cdf84bScheloha /*	$OpenBSD: sunkbd.c,v 1.28 2020/04/06 19:03:09 cheloha Exp $	*/
2add80fdfSjason 
3add80fdfSjason /*
4add80fdfSjason  * Copyright (c) 2002 Jason L. Wright (jason@thought.net)
5add80fdfSjason  * All rights reserved.
6add80fdfSjason  *
7add80fdfSjason  * Redistribution and use in source and binary forms, with or without
8add80fdfSjason  * modification, are permitted provided that the following conditions
9add80fdfSjason  * are met:
10add80fdfSjason  * 1. Redistributions of source code must retain the above copyright
11add80fdfSjason  *    notice, this list of conditions and the following disclaimer.
12add80fdfSjason  * 2. Redistributions in binary form must reproduce the above copyright
13add80fdfSjason  *    notice, this list of conditions and the following disclaimer in the
14add80fdfSjason  *    documentation and/or other materials provided with the distribution.
15add80fdfSjason  *
16add80fdfSjason  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17add80fdfSjason  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18add80fdfSjason  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19add80fdfSjason  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20add80fdfSjason  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21add80fdfSjason  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22add80fdfSjason  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23add80fdfSjason  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24add80fdfSjason  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25add80fdfSjason  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26add80fdfSjason  * POSSIBILITY OF SUCH DAMAGE.
275248d82bSjason  *
285248d82bSjason  * Effort sponsored in part by the Defense Advanced Research Projects
295248d82bSjason  * Agency (DARPA) and Air Force Research Laboratory, Air Force
305248d82bSjason  * Materiel Command, USAF, under agreement number F30602-01-2-0537.
315248d82bSjason  *
32add80fdfSjason  */
335248d82bSjason 
34add80fdfSjason #include <sys/param.h>
35add80fdfSjason #include <sys/systm.h>
36add80fdfSjason #include <sys/device.h>
37add80fdfSjason #include <sys/kernel.h>
38e45e36eeSmiod #include <sys/timeout.h>
39add80fdfSjason 
40add80fdfSjason #include <dev/wscons/wsconsio.h>
41add80fdfSjason #include <dev/wscons/wskbdvar.h>
428ff6df28Smiod #ifdef WSDISPLAY_COMPAT_RAWKBD
438ff6df28Smiod #include <dev/wscons/wskbdraw.h>
448ff6df28Smiod #endif
45add80fdfSjason 
46add80fdfSjason #include <dev/sun/sunkbdreg.h>
47add80fdfSjason #include <dev/sun/sunkbdvar.h>
48add80fdfSjason 
49e45e36eeSmiod #ifdef __sparc64__
50e45e36eeSmiod #define	NTCTRL 0
5117cae25cSmaja #else
52e45e36eeSmiod #include "tctrl.h"
5317cae25cSmaja #endif
54e45e36eeSmiod 
55e45e36eeSmiod #if NTCTRL > 0
56e45e36eeSmiod #include <sparc/dev/tctrlvar.h>		/* XXX for tadpole_bell() */
57e45e36eeSmiod #endif
58e45e36eeSmiod 
59e45e36eeSmiod void	sunkbd_bell(struct sunkbd_softc *, u_int, u_int, u_int);
60a4e5462dSmiod void	sunkbd_decode5(u_int8_t, u_int *, int *);
61e45e36eeSmiod int	sunkbd_enable(void *, int);
62e45e36eeSmiod int	sunkbd_getleds(struct sunkbd_softc *);
63e45e36eeSmiod int	sunkbd_ioctl(void *, u_long, caddr_t, int, struct proc *);
64e45e36eeSmiod void	sunkbd_setleds(void *, int);
65e45e36eeSmiod 
66e45e36eeSmiod struct wskbd_accessops sunkbd_accessops = {
67e45e36eeSmiod 	sunkbd_enable,
68e45e36eeSmiod 	sunkbd_setleds,
69e45e36eeSmiod 	sunkbd_ioctl
70add80fdfSjason };
71a6f10be2Smaja 
72e45e36eeSmiod void
sunkbd_attach(struct sunkbd_softc * sc,struct wskbddev_attach_args * waa)73e75d5666Smiod sunkbd_attach(struct sunkbd_softc *sc, struct wskbddev_attach_args *waa)
74e75d5666Smiod {
75a4e5462dSmiod 	if (ISTYPE5(sc->sc_layout))
76a4e5462dSmiod 		sc->sc_decode = sunkbd_decode5;
77a4e5462dSmiod 	else
78a4e5462dSmiod 		sc->sc_decode = sunkbd_decode;
79a4e5462dSmiod 
80e75d5666Smiod 	sc->sc_wskbddev = config_found((struct device *)sc, waa,
81e75d5666Smiod 	    wskbddevprint);
82e75d5666Smiod }
83e75d5666Smiod 
84e75d5666Smiod void
sunkbd_bell(struct sunkbd_softc * sc,u_int period,u_int pitch,u_int volume)85e45e36eeSmiod sunkbd_bell(struct sunkbd_softc *sc, u_int period, u_int pitch, u_int volume)
86e45e36eeSmiod {
87*f0cdf84bScheloha 	int s;
88e45e36eeSmiod 	u_int8_t c = SKBD_CMD_BELLON;
89e45e36eeSmiod 
90e45e36eeSmiod #if NTCTRL > 0
91e45e36eeSmiod 	if (tadpole_bell(period / 10, pitch, volume) != 0)
92e45e36eeSmiod 		return;
93a6f10be2Smaja #endif
94e45e36eeSmiod 
95e45e36eeSmiod 	s = spltty();
96e45e36eeSmiod 	if (sc->sc_bellactive) {
97e45e36eeSmiod 		if (sc->sc_belltimeout == 0)
98e45e36eeSmiod 			timeout_del(&sc->sc_bellto);
99e45e36eeSmiod 	}
100e45e36eeSmiod 	if (pitch == 0 || period == 0) {
101e45e36eeSmiod 		sunkbd_bellstop(sc);
102e45e36eeSmiod 		splx(s);
103e45e36eeSmiod 		return;
104e45e36eeSmiod 	}
105e45e36eeSmiod 	if (sc->sc_bellactive == 0) {
106e45e36eeSmiod 		sc->sc_bellactive = 1;
107e45e36eeSmiod 		sc->sc_belltimeout = 1;
108e45e36eeSmiod 		(*sc->sc_sendcmd)(sc, &c, 1);
109*f0cdf84bScheloha 		timeout_add_msec(&sc->sc_bellto, period);
110e45e36eeSmiod 	}
111e45e36eeSmiod 	splx(s);
112e45e36eeSmiod }
113e45e36eeSmiod 
114e45e36eeSmiod void
sunkbd_bellstop(void * v)115e45e36eeSmiod sunkbd_bellstop(void *v)
116e45e36eeSmiod {
117e45e36eeSmiod 	struct sunkbd_softc *sc = v;
118e45e36eeSmiod 	int s;
119e45e36eeSmiod 	u_int8_t c;
120e45e36eeSmiod 
121e45e36eeSmiod 	s = spltty();
122e45e36eeSmiod 	sc->sc_belltimeout = 0;
123e45e36eeSmiod 	c = SKBD_CMD_BELLOFF;
124e45e36eeSmiod 	(*sc->sc_sendcmd)(v, &c, 1);
125e45e36eeSmiod 	sc->sc_bellactive = 0;
126e45e36eeSmiod 	splx(s);
127e45e36eeSmiod }
128e45e36eeSmiod 
129e45e36eeSmiod void
sunkbd_decode(u_int8_t c,u_int * type,int * value)130e45e36eeSmiod sunkbd_decode(u_int8_t c, u_int *type, int *value)
131e45e36eeSmiod {
132e45e36eeSmiod 	switch (c) {
133e45e36eeSmiod 	case SKBD_RSP_IDLE:
134e45e36eeSmiod 		*type = WSCONS_EVENT_ALL_KEYS_UP;
135e45e36eeSmiod 		*value = 0;
136e45e36eeSmiod 		break;
137e45e36eeSmiod 	default:
138e45e36eeSmiod 		*type = (c & 0x80) ?
139e45e36eeSmiod 		    WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN;
140e45e36eeSmiod 		*value = c & 0x7f;
141e45e36eeSmiod 		break;
142e45e36eeSmiod 	}
143e45e36eeSmiod }
144e45e36eeSmiod 
145a4e5462dSmiod void
sunkbd_decode5(u_int8_t c,u_int * type,int * value)146a4e5462dSmiod sunkbd_decode5(u_int8_t c, u_int *type, int *value)
147a4e5462dSmiod {
148a4e5462dSmiod 	sunkbd_decode(c, type, value);
149a4e5462dSmiod 	/*
150a4e5462dSmiod 	 * Scancode 0x2d is KS_KP_Equal on type 4, and KS_AudioMute on
151a4e5462dSmiod 	 * type 5. Rather than provide two distinct maps, we remap the
152a4e5462dSmiod 	 * scancode here.
153a4e5462dSmiod 	 */
154a4e5462dSmiod 	if (*value == 0x2d)
155a4e5462dSmiod 		*value = 0x7f;
156a4e5462dSmiod }
157a4e5462dSmiod 
158e45e36eeSmiod int
sunkbd_enable(void * v,int on)159e45e36eeSmiod sunkbd_enable(void *v, int on)
160e45e36eeSmiod {
161e45e36eeSmiod 	return (0);
162e45e36eeSmiod }
163e45e36eeSmiod 
164e45e36eeSmiod int
sunkbd_getleds(struct sunkbd_softc * sc)165e45e36eeSmiod sunkbd_getleds(struct sunkbd_softc *sc)
166e45e36eeSmiod {
167e45e36eeSmiod 	return (sc->sc_leds);
168e45e36eeSmiod }
169e45e36eeSmiod 
170e75d5666Smiod void
sunkbd_input(struct sunkbd_softc * sc,u_int8_t * buf,u_int buflen)171e75d5666Smiod sunkbd_input(struct sunkbd_softc *sc, u_int8_t *buf, u_int buflen)
172e75d5666Smiod {
173e75d5666Smiod 	u_int type;
174e75d5666Smiod 	int value;
1758ff6df28Smiod 	int s;
176e75d5666Smiod 
1778ff6df28Smiod 	if (sc->sc_wskbddev == NULL)
1788ff6df28Smiod 		return;	/* why bother */
1798ff6df28Smiod 
1808ff6df28Smiod #ifdef WSDISPLAY_COMPAT_RAWKBD
1818ff6df28Smiod 	if (sc->sc_rawkbd) {
1828ff6df28Smiod 		u_char rbuf[SUNKBD_MAX_INPUT_SIZE * 2];
1837ce15ad7Sshadchin 		int c, rlen = 0;
1848ff6df28Smiod 
1858ff6df28Smiod 		while (buflen-- != 0) {
186a4e5462dSmiod 			(*sc->sc_decode)(*buf++, &type, &value);
1878ff6df28Smiod 			c = sunkbd_rawmap[value];
1888ff6df28Smiod 			if (c == RAWKEY_Null)
1898ff6df28Smiod 				continue;
1908ff6df28Smiod 			/* fake extended scancode if necessary */
1918ff6df28Smiod 			if (c & 0x80)
1928ff6df28Smiod 				rbuf[rlen++] = 0xe0;
1938ff6df28Smiod 			rbuf[rlen] = c & 0x7f;
1948ff6df28Smiod 			if (type == WSCONS_EVENT_KEY_UP)
1958ff6df28Smiod 				rbuf[rlen] |= 0x80;
1968ff6df28Smiod 			rlen++;
1978ff6df28Smiod 		}
1988ff6df28Smiod 
1998ff6df28Smiod 		s = spltty();
2008ff6df28Smiod 		wskbd_rawinput(sc->sc_wskbddev, rbuf, rlen);
2018ff6df28Smiod 		splx(s);
2028ff6df28Smiod 	} else
2038ff6df28Smiod #endif
2048ff6df28Smiod 	{
2058ff6df28Smiod 		s = spltty();
206e75d5666Smiod 		while (buflen-- != 0) {
207a4e5462dSmiod 			(*sc->sc_decode)(*buf++, &type, &value);
208e75d5666Smiod 			wskbd_input(sc->sc_wskbddev, type, value);
209e75d5666Smiod 		}
2108ff6df28Smiod 		splx(s);
2118ff6df28Smiod 	}
212e75d5666Smiod }
213e75d5666Smiod 
214e45e36eeSmiod int
sunkbd_ioctl(void * v,u_long cmd,caddr_t data,int flag,struct proc * p)215e45e36eeSmiod sunkbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
216e45e36eeSmiod {
217e45e36eeSmiod 	struct sunkbd_softc *sc = v;
218e45e36eeSmiod 	int *d_int = (int *)data;
219e45e36eeSmiod 	struct wskbd_bell_data *d_bell = (struct wskbd_bell_data *)data;
220e45e36eeSmiod 
221e45e36eeSmiod 	switch (cmd) {
222e45e36eeSmiod 	case WSKBDIO_GTYPE:
223e45e36eeSmiod 		if (ISTYPE5(sc->sc_layout)) {
224e45e36eeSmiod 			*d_int = WSKBD_TYPE_SUN5;
225e45e36eeSmiod 		} else {
226e45e36eeSmiod 			*d_int = WSKBD_TYPE_SUN;
227e45e36eeSmiod 		}
228e45e36eeSmiod 		return (0);
229e45e36eeSmiod 	case WSKBDIO_SETLEDS:
230e45e36eeSmiod 		sunkbd_setleds(sc, *d_int);
231e45e36eeSmiod 		return (0);
232e45e36eeSmiod 	case WSKBDIO_GETLEDS:
233e45e36eeSmiod 		*d_int = sunkbd_getleds(sc);
234e45e36eeSmiod 		return (0);
235e45e36eeSmiod 	case WSKBDIO_COMPLEXBELL:
236e45e36eeSmiod 		sunkbd_bell(sc, d_bell->period, d_bell->pitch, d_bell->volume);
237e45e36eeSmiod 		return (0);
2388ff6df28Smiod #ifdef WSDISPLAY_COMPAT_RAWKBD
2398ff6df28Smiod 	case WSKBDIO_SETMODE:
2408ff6df28Smiod 		sc->sc_rawkbd = *(int *)data == WSKBD_RAW;
2418ff6df28Smiod 		return (0);
2428ff6df28Smiod #endif
243e45e36eeSmiod 	}
244e45e36eeSmiod 
245e45e36eeSmiod 	return (-1);
246e45e36eeSmiod }
247e45e36eeSmiod 
248e45e36eeSmiod void
sunkbd_raw(struct sunkbd_softc * sc,u_int8_t c)249e45e36eeSmiod sunkbd_raw(struct sunkbd_softc *sc, u_int8_t c)
250e45e36eeSmiod {
251e45e36eeSmiod 	int claimed = 0;
252e45e36eeSmiod 
253e45e36eeSmiod 	if (sc->sc_kbdstate == SKBD_STATE_LAYOUT) {
254e45e36eeSmiod 		sc->sc_kbdstate = SKBD_STATE_GETKEY;
255e45e36eeSmiod 		sc->sc_layout = c;
256e45e36eeSmiod 		return;
257e45e36eeSmiod 	}
258e45e36eeSmiod 
259e45e36eeSmiod 	switch (c) {
260e45e36eeSmiod 	case SKBD_RSP_RESET:
261e45e36eeSmiod 		sc->sc_kbdstate = SKBD_STATE_RESET;
262e45e36eeSmiod 		claimed = 1;
263e45e36eeSmiod 		break;
264e45e36eeSmiod 	case SKBD_RSP_LAYOUT:
265e45e36eeSmiod 		sc->sc_kbdstate = SKBD_STATE_LAYOUT;
266e45e36eeSmiod 		claimed = 1;
267e45e36eeSmiod 		break;
268e45e36eeSmiod 	case SKBD_RSP_IDLE:
269e45e36eeSmiod 		sc->sc_kbdstate = SKBD_STATE_GETKEY;
270e45e36eeSmiod 		claimed = 1;
271e45e36eeSmiod 	}
272e45e36eeSmiod 
273e45e36eeSmiod 	if (claimed)
274e45e36eeSmiod 		return;
275e45e36eeSmiod 
276e45e36eeSmiod 	switch (sc->sc_kbdstate) {
277e45e36eeSmiod 	case SKBD_STATE_RESET:
278e45e36eeSmiod 		sc->sc_kbdstate = SKBD_STATE_GETKEY;
279e45e36eeSmiod 		if (c < KB_SUN2 || c > KB_SUN4)
280e45e36eeSmiod 			printf("%s: reset: invalid keyboard type 0x%02x\n",
281e45e36eeSmiod 			    sc->sc_dev.dv_xname, c);
282e45e36eeSmiod 		else
283e45e36eeSmiod 			sc->sc_id = c;
284e45e36eeSmiod 		break;
285e45e36eeSmiod 	case SKBD_STATE_GETKEY:
286e45e36eeSmiod 		break;
287e45e36eeSmiod 	}
288e45e36eeSmiod }
289e45e36eeSmiod 
29020b3d8f3Smiod int
sunkbd_setclick(struct sunkbd_softc * sc,int click)29120b3d8f3Smiod sunkbd_setclick(struct sunkbd_softc *sc, int click)
29220b3d8f3Smiod {
29320b3d8f3Smiod 	u_int8_t c;
29420b3d8f3Smiod 
29520b3d8f3Smiod 	/* Type 2 keyboards do not support keyclick */
29620b3d8f3Smiod 	if (sc->sc_id == KB_SUN2)
29720b3d8f3Smiod 		return (ENXIO);
29820b3d8f3Smiod 
29920b3d8f3Smiod 	c = click ? SKBD_CMD_CLICKON : SKBD_CMD_CLICKOFF;
30020b3d8f3Smiod 	(*sc->sc_sendcmd)(sc, &c, 1);
30120b3d8f3Smiod 	return (0);
30220b3d8f3Smiod }
30320b3d8f3Smiod 
304e45e36eeSmiod void
sunkbd_setleds(void * v,int wled)305e45e36eeSmiod sunkbd_setleds(void *v, int wled)
306e45e36eeSmiod {
307e45e36eeSmiod 	struct sunkbd_softc *sc = v;
308e45e36eeSmiod 	u_int8_t sled = 0;
309e45e36eeSmiod 	u_int8_t cmd[2];
310e45e36eeSmiod 
311e45e36eeSmiod 	sc->sc_leds = wled;
312e45e36eeSmiod 
313e45e36eeSmiod 	if (wled & WSKBD_LED_CAPS)
314e45e36eeSmiod 		sled |= SKBD_LED_CAPSLOCK;
315e45e36eeSmiod 	if (wled & WSKBD_LED_NUM)
316e45e36eeSmiod 		sled |= SKBD_LED_NUMLOCK;
317e45e36eeSmiod 	if (wled & WSKBD_LED_SCROLL)
318e45e36eeSmiod 		sled |= SKBD_LED_SCROLLLOCK;
319e45e36eeSmiod 	if (wled & WSKBD_LED_COMPOSE)
320e45e36eeSmiod 		sled |= SKBD_LED_COMPOSE;
321e45e36eeSmiod 
322e45e36eeSmiod 	cmd[0] = SKBD_CMD_SETLED;
323e45e36eeSmiod 	cmd[1] = sled;
324e45e36eeSmiod 	(*sc->sc_sendcmd)(sc, cmd, sizeof(cmd));
325e45e36eeSmiod }
326