pl050.c revision 256281
1/*
2 * Copyright (c) 2012 Oleksandr Tymoshenko <gonzo@freebsd.org>
3 * All rights reserved.
4 *
5 * Based on dev/usb/input/ukbd.c
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 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: stable/10/sys/arm/versatile/pl050.c 244197 2012-12-13 23:19:13Z gonzo $");
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/bus.h>
35#include <sys/kernel.h>
36#include <sys/module.h>
37#include <sys/malloc.h>
38#include <sys/rman.h>
39#include <sys/proc.h>
40#include <sys/sched.h>
41#include <sys/kdb.h>
42
43#include <machine/bus.h>
44#include <machine/cpu.h>
45#include <machine/frame.h>
46#include <machine/intr.h>
47
48#include <dev/fdt/fdt_common.h>
49#include <dev/ofw/openfirm.h>
50#include <dev/ofw/ofw_bus.h>
51#include <dev/ofw/ofw_bus_subr.h>
52
53#include <sys/ioccom.h>
54#include <sys/filio.h>
55#include <sys/tty.h>
56#include <sys/kbio.h>
57
58#include <dev/kbd/kbdreg.h>
59
60#include <machine/bus.h>
61#include <machine/fdt.h>
62
63#include <dev/kbd/kbdtables.h>
64
65#define	KMI_LOCK()	mtx_lock(&Giant)
66#define	KMI_UNLOCK()	mtx_unlock(&Giant)
67
68#ifdef	INVARIANTS
69/*
70 * Assert that the lock is held in all contexts
71 * where the code can be executed.
72 */
73#define	KMI_LOCK_ASSERT()	mtx_assert(&Giant, MA_OWNED)
74/*
75 * Assert that the lock is held in the contexts
76 * where it really has to be so.
77 */
78#define	KMI_CTX_LOCK_ASSERT()			 	\
79	do {						\
80		if (!kdb_active && panicstr == NULL)	\
81			mtx_assert(&Giant, MA_OWNED);	\
82	} while (0)
83#else
84#define KMI_LOCK_ASSERT()	(void)0
85#define KMI_CTX_LOCK_ASSERT()	(void)0
86#endif
87
88#define	KMICR		0x00
89#define		KMICR_TYPE_NONPS2	(1 << 5)
90#define		KMICR_RXINTREN		(1 << 4)
91#define		KMICR_TXINTREN		(1 << 3)
92#define		KMICR_EN		(1 << 2)
93#define		KMICR_FKMID		(1 << 1)
94#define		KMICR_FKMIC		(1 << 0)
95#define	KMISTAT		0x04
96#define		KMISTAT_TXEMPTY		(1 << 6)
97#define		KMISTAT_TXBUSY		(1 << 5)
98#define		KMISTAT_RXFULL		(1 << 4)
99#define		KMISTAT_RXBUSY		(1 << 3)
100#define		KMISTAT_RXPARITY	(1 << 2)
101#define		KMISTAT_KMIC		(1 << 1)
102#define		KMISTAT_KMID		(1 << 0)
103#define	KMIDATA		0x08
104#define	KMICLKDIV	0x0C
105#define	KMIIR		0x10
106#define		KMIIR_TXINTR		(1 << 1)
107#define		KMIIR_RXINTR		(1 << 0)
108
109#define	KMI_DRIVER_NAME          "kmi"
110#define	KMI_NFKEY        (sizeof(fkey_tab)/sizeof(fkey_tab[0]))	/* units */
111
112struct kmi_softc {
113	keyboard_t sc_kbd;
114	keymap_t sc_keymap;
115	accentmap_t sc_accmap;
116	fkeytab_t sc_fkeymap[KMI_NFKEY];
117
118	struct resource*	sc_mem_res;
119	struct resource*	sc_irq_res;
120	void*			sc_intr_hl;
121
122	int			sc_mode;		/* input mode (K_XLATE,K_RAW,K_CODE) */
123	int			sc_state;		/* shift/lock key state */
124	int			sc_accents;		/* accent key index (> 0) */
125	uint32_t		sc_flags;		/* flags */
126#define	KMI_FLAG_COMPOSE	0x00000001
127#define	KMI_FLAG_POLLING	0x00000002
128
129	struct			thread *sc_poll_thread;
130};
131
132/* Read/Write macros for Timer used as timecounter */
133#define pl050_kmi_read_4(sc, reg)		\
134	bus_read_4((sc)->sc_mem_res, (reg))
135
136#define pl050_kmi_write_4(sc, reg, val)	\
137	bus_write_4((sc)->sc_mem_res, (reg), (val))
138
139/* prototypes */
140static void	kmi_set_leds(struct kmi_softc *, uint8_t);
141static int	kmi_set_typematic(keyboard_t *, int);
142static uint32_t	kmi_read_char(keyboard_t *, int);
143static void	kmi_clear_state(keyboard_t *);
144static int	kmi_ioctl(keyboard_t *, u_long, caddr_t);
145static int	kmi_enable(keyboard_t *);
146static int	kmi_disable(keyboard_t *);
147
148/* early keyboard probe, not supported */
149static int
150kmi_configure(int flags)
151{
152	return (0);
153}
154
155/* detect a keyboard, not used */
156static int
157kmi_probe(int unit, void *arg, int flags)
158{
159	return (ENXIO);
160}
161
162/* reset and initialize the device, not used */
163static int
164kmi_init(int unit, keyboard_t **kbdp, void *arg, int flags)
165{
166	return (ENXIO);
167}
168
169/* test the interface to the device, not used */
170static int
171kmi_test_if(keyboard_t *kbd)
172{
173	return (0);
174}
175
176/* finish using this keyboard, not used */
177static int
178kmi_term(keyboard_t *kbd)
179{
180	return (ENXIO);
181}
182
183/* keyboard interrupt routine, not used */
184static int
185kmi_intr(keyboard_t *kbd, void *arg)
186{
187
188	return (0);
189}
190
191/* lock the access to the keyboard, not used */
192static int
193kmi_lock(keyboard_t *kbd, int lock)
194{
195	return (1);
196}
197
198/*
199 * Enable the access to the device; until this function is called,
200 * the client cannot read from the keyboard.
201 */
202static int
203kmi_enable(keyboard_t *kbd)
204{
205
206	KMI_LOCK();
207	KBD_ACTIVATE(kbd);
208	KMI_UNLOCK();
209
210	return (0);
211}
212
213/* disallow the access to the device */
214static int
215kmi_disable(keyboard_t *kbd)
216{
217
218	KMI_LOCK();
219	KBD_DEACTIVATE(kbd);
220	KMI_UNLOCK();
221
222	return (0);
223}
224
225/* check if data is waiting */
226static int
227kmi_check(keyboard_t *kbd)
228{
229	struct kmi_softc *sc = kbd->kb_data;
230	uint32_t reg;
231
232	KMI_CTX_LOCK_ASSERT();
233
234	if (!KBD_IS_ACTIVE(kbd))
235		return (0);
236
237	reg = pl050_kmi_read_4(sc, KMIIR);
238	return (reg & KMIIR_RXINTR);
239}
240
241/* check if char is waiting */
242static int
243kmi_check_char_locked(keyboard_t *kbd)
244{
245	KMI_CTX_LOCK_ASSERT();
246
247	if (!KBD_IS_ACTIVE(kbd))
248		return (0);
249
250	return (kmi_check(kbd));
251}
252
253static int
254kmi_check_char(keyboard_t *kbd)
255{
256	int result;
257
258	KMI_LOCK();
259	result = kmi_check_char_locked(kbd);
260	KMI_UNLOCK();
261
262	return (result);
263}
264
265/* read one byte from the keyboard if it's allowed */
266/* Currently unused. */
267static int
268kmi_read(keyboard_t *kbd, int wait)
269{
270	KMI_CTX_LOCK_ASSERT();
271
272	if (!KBD_IS_ACTIVE(kbd))
273		return (-1);
274
275	++(kbd->kb_count);
276	printf("Implement ME: %s\n", __func__);
277	return (0);
278}
279
280/* read char from the keyboard */
281static uint32_t
282kmi_read_char_locked(keyboard_t *kbd, int wait)
283{
284	struct kmi_softc *sc = kbd->kb_data;
285	uint32_t reg, data;
286
287	KMI_CTX_LOCK_ASSERT();
288
289	if (!KBD_IS_ACTIVE(kbd))
290		return (NOKEY);
291
292	reg = pl050_kmi_read_4(sc, KMIIR);
293	if (reg & KMIIR_RXINTR) {
294		data = pl050_kmi_read_4(sc, KMIDATA);
295		return (data);
296	}
297
298	++kbd->kb_count;
299	return (NOKEY);
300}
301
302/* Currently wait is always false. */
303static uint32_t
304kmi_read_char(keyboard_t *kbd, int wait)
305{
306	uint32_t keycode;
307
308	KMI_LOCK();
309	keycode = kmi_read_char_locked(kbd, wait);
310	KMI_UNLOCK();
311
312	return (keycode);
313}
314
315/* some useful control functions */
316static int
317kmi_ioctl_locked(keyboard_t *kbd, u_long cmd, caddr_t arg)
318{
319	struct kmi_softc *sc = kbd->kb_data;
320	int i;
321#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
322    defined(COMPAT_FREEBSD4) || defined(COMPAT_43)
323	int ival;
324
325#endif
326
327	KMI_LOCK_ASSERT();
328
329	switch (cmd) {
330	case KDGKBMODE:		/* get keyboard mode */
331		*(int *)arg = sc->sc_mode;
332		break;
333#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
334    defined(COMPAT_FREEBSD4) || defined(COMPAT_43)
335	case _IO('K', 7):
336		ival = IOCPARM_IVAL(arg);
337		arg = (caddr_t)&ival;
338		/* FALLTHROUGH */
339#endif
340	case KDSKBMODE:		/* set keyboard mode */
341		switch (*(int *)arg) {
342		case K_XLATE:
343			if (sc->sc_mode != K_XLATE) {
344				/* make lock key state and LED state match */
345				sc->sc_state &= ~LOCK_MASK;
346				sc->sc_state |= KBD_LED_VAL(kbd);
347			}
348			/* FALLTHROUGH */
349		case K_RAW:
350		case K_CODE:
351			if (sc->sc_mode != *(int *)arg) {
352				if ((sc->sc_flags & KMI_FLAG_POLLING) == 0)
353					kmi_clear_state(kbd);
354				sc->sc_mode = *(int *)arg;
355			}
356			break;
357		default:
358			return (EINVAL);
359		}
360		break;
361
362	case KDGETLED:			/* get keyboard LED */
363		*(int *)arg = KBD_LED_VAL(kbd);
364		break;
365#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
366    defined(COMPAT_FREEBSD4) || defined(COMPAT_43)
367	case _IO('K', 66):
368		ival = IOCPARM_IVAL(arg);
369		arg = (caddr_t)&ival;
370		/* FALLTHROUGH */
371#endif
372	case KDSETLED:			/* set keyboard LED */
373		/* NOTE: lock key state in "sc_state" won't be changed */
374		if (*(int *)arg & ~LOCK_MASK)
375			return (EINVAL);
376
377		i = *(int *)arg;
378
379		/* replace CAPS LED with ALTGR LED for ALTGR keyboards */
380		if (sc->sc_mode == K_XLATE &&
381		    kbd->kb_keymap->n_keys > ALTGR_OFFSET) {
382			if (i & ALKED)
383				i |= CLKED;
384			else
385				i &= ~CLKED;
386		}
387		if (KBD_HAS_DEVICE(kbd))
388			kmi_set_leds(sc, i);
389
390		KBD_LED_VAL(kbd) = *(int *)arg;
391		break;
392	case KDGKBSTATE:		/* get lock key state */
393		*(int *)arg = sc->sc_state & LOCK_MASK;
394		break;
395#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
396    defined(COMPAT_FREEBSD4) || defined(COMPAT_43)
397	case _IO('K', 20):
398		ival = IOCPARM_IVAL(arg);
399		arg = (caddr_t)&ival;
400		/* FALLTHROUGH */
401#endif
402	case KDSKBSTATE:		/* set lock key state */
403		if (*(int *)arg & ~LOCK_MASK) {
404			return (EINVAL);
405		}
406		sc->sc_state &= ~LOCK_MASK;
407		sc->sc_state |= *(int *)arg;
408
409		/* set LEDs and quit */
410		return (kmi_ioctl(kbd, KDSETLED, arg));
411
412	case KDSETREPEAT:		/* set keyboard repeat rate (new
413					 * interface) */
414		if (!KBD_HAS_DEVICE(kbd)) {
415			return (0);
416		}
417		if (((int *)arg)[1] < 0) {
418			return (EINVAL);
419		}
420		if (((int *)arg)[0] < 0) {
421			return (EINVAL);
422		}
423		if (((int *)arg)[0] < 200)	/* fastest possible value */
424			kbd->kb_delay1 = 200;
425		else
426			kbd->kb_delay1 = ((int *)arg)[0];
427		kbd->kb_delay2 = ((int *)arg)[1];
428		return (0);
429
430#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
431    defined(COMPAT_FREEBSD4) || defined(COMPAT_43)
432	case _IO('K', 67):
433		ival = IOCPARM_IVAL(arg);
434		arg = (caddr_t)&ival;
435		/* FALLTHROUGH */
436#endif
437	case KDSETRAD:			/* set keyboard repeat rate (old
438					 * interface) */
439		return (kmi_set_typematic(kbd, *(int *)arg));
440
441	case PIO_KEYMAP:		/* set keyboard translation table */
442	case OPIO_KEYMAP:		/* set keyboard translation table
443					 * (compat) */
444	case PIO_KEYMAPENT:		/* set keyboard translation table
445					 * entry */
446	case PIO_DEADKEYMAP:		/* set accent key translation table */
447		sc->sc_accents = 0;
448		/* FALLTHROUGH */
449	default:
450		return (genkbd_commonioctl(kbd, cmd, arg));
451	}
452
453	return (0);
454}
455
456static int
457kmi_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
458{
459	int result;
460
461	/*
462	 * XXX KDGKBSTATE, KDSKBSTATE and KDSETLED can be called from any
463	 * context where printf(9) can be called, which among other things
464	 * includes interrupt filters and threads with any kinds of locks
465	 * already held.  For this reason it would be dangerous to acquire
466	 * the Giant here unconditionally.  On the other hand we have to
467	 * have it to handle the ioctl.
468	 * So we make our best effort to auto-detect whether we can grab
469	 * the Giant or not.  Blame syscons(4) for this.
470	 */
471	switch (cmd) {
472	case KDGKBSTATE:
473	case KDSKBSTATE:
474	case KDSETLED:
475		if (!mtx_owned(&Giant) && !SCHEDULER_STOPPED())
476			return (EDEADLK);	/* best I could come up with */
477		/* FALLTHROUGH */
478	default:
479		KMI_LOCK();
480		result = kmi_ioctl_locked(kbd, cmd, arg);
481		KMI_UNLOCK();
482		return (result);
483	}
484}
485
486
487/* clear the internal state of the keyboard */
488static void
489kmi_clear_state(keyboard_t *kbd)
490{
491	struct kmi_softc *sc = kbd->kb_data;
492
493	KMI_CTX_LOCK_ASSERT();
494
495	sc->sc_flags &= ~(KMI_FLAG_COMPOSE | KMI_FLAG_POLLING);
496	sc->sc_state &= LOCK_MASK;	/* preserve locking key state */
497	sc->sc_accents = 0;
498}
499
500/* save the internal state, not used */
501static int
502kmi_get_state(keyboard_t *kbd, void *buf, size_t len)
503{
504	return (len == 0) ? 1 : -1;
505}
506
507/* set the internal state, not used */
508static int
509kmi_set_state(keyboard_t *kbd, void *buf, size_t len)
510{
511	return (EINVAL);
512}
513
514static int
515kmi_poll(keyboard_t *kbd, int on)
516{
517	struct kmi_softc *sc = kbd->kb_data;
518
519	KMI_LOCK();
520	if (on) {
521		sc->sc_flags |= KMI_FLAG_POLLING;
522		sc->sc_poll_thread = curthread;
523	} else {
524		sc->sc_flags &= ~KMI_FLAG_POLLING;
525	}
526	KMI_UNLOCK();
527
528	return (0);
529}
530
531/* local functions */
532
533static void
534kmi_set_leds(struct kmi_softc *sc, uint8_t leds)
535{
536
537	KMI_LOCK_ASSERT();
538
539	/* start transfer, if not already started */
540	printf("Implement me: %s\n", __func__);
541}
542
543static int
544kmi_set_typematic(keyboard_t *kbd, int code)
545{
546	static const int delays[] = {250, 500, 750, 1000};
547	static const int rates[] = {34, 38, 42, 46, 50, 55, 59, 63,
548		68, 76, 84, 92, 100, 110, 118, 126,
549		136, 152, 168, 184, 200, 220, 236, 252,
550	272, 304, 336, 368, 400, 440, 472, 504};
551
552	if (code & ~0x7f) {
553		return (EINVAL);
554	}
555	kbd->kb_delay1 = delays[(code >> 5) & 3];
556	kbd->kb_delay2 = rates[code & 0x1f];
557	return (0);
558}
559
560static keyboard_switch_t kmisw = {
561	.probe = &kmi_probe,
562	.init = &kmi_init,
563	.term = &kmi_term,
564	.intr = &kmi_intr,
565	.test_if = &kmi_test_if,
566	.enable = &kmi_enable,
567	.disable = &kmi_disable,
568	.read = &kmi_read,
569	.check = &kmi_check,
570	.read_char = &kmi_read_char,
571	.check_char = &kmi_check_char,
572	.ioctl = &kmi_ioctl,
573	.lock = &kmi_lock,
574	.clear_state = &kmi_clear_state,
575	.get_state = &kmi_get_state,
576	.set_state = &kmi_set_state,
577	.get_fkeystr = &genkbd_get_fkeystr,
578	.poll = &kmi_poll,
579	.diag = &genkbd_diag,
580};
581
582KEYBOARD_DRIVER(kmi, kmisw, kmi_configure);
583
584static void
585pl050_kmi_intr(void *arg)
586{
587	struct kmi_softc *sc = arg;
588	uint32_t c;
589
590	KMI_CTX_LOCK_ASSERT();
591
592	if ((sc->sc_flags & KMI_FLAG_POLLING) != 0)
593		return;
594
595	if (KBD_IS_ACTIVE(&sc->sc_kbd) &&
596	    KBD_IS_BUSY(&sc->sc_kbd)) {
597		/* let the callback function process the input */
598		(sc->sc_kbd.kb_callback.kc_func) (&sc->sc_kbd, KBDIO_KEYINPUT,
599		    sc->sc_kbd.kb_callback.kc_arg);
600	} else {
601		/* read and discard the input, no one is waiting for it */
602		do {
603			c = kmi_read_char_locked(&sc->sc_kbd, 0);
604		} while (c != NOKEY);
605	}
606
607}
608
609static int
610pl050_kmi_probe(device_t dev)
611{
612
613	if (ofw_bus_is_compatible(dev, "arm,pl050")) {
614		device_set_desc(dev, "PL050 Keyboard/Mouse Interface");
615		return (BUS_PROBE_DEFAULT);
616	}
617
618	return (ENXIO);
619}
620
621static int
622pl050_kmi_attach(device_t dev)
623{
624	struct kmi_softc *sc = device_get_softc(dev);
625	keyboard_t *kbd;
626	int rid;
627	int i;
628
629	kbd = &sc->sc_kbd;
630	rid = 0;
631
632	sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
633	if (sc->sc_mem_res == NULL) {
634		device_printf(dev, "could not allocate memory resource\n");
635		return (ENXIO);
636	}
637
638	/* Request the IRQ resources */
639	sc->sc_irq_res =  bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
640	if (sc->sc_irq_res == NULL) {
641		device_printf(dev, "Error: could not allocate irq resources\n");
642		return (ENXIO);
643	}
644
645	/* Setup and enable the timer */
646	if (bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_CLK,
647			NULL, pl050_kmi_intr, sc,
648			&sc->sc_intr_hl) != 0) {
649		bus_release_resource(dev, SYS_RES_IRQ, rid,
650			sc->sc_irq_res);
651		device_printf(dev, "Unable to setup the clock irq handler.\n");
652		return (ENXIO);
653	}
654
655	/* TODO: clock & divisor */
656
657	pl050_kmi_write_4(sc, KMICR, KMICR_EN | KMICR_RXINTREN);
658
659	kbd_init_struct(kbd, KMI_DRIVER_NAME, KB_OTHER,
660			device_get_unit(dev), 0, 0, 0);
661	kbd->kb_data = (void *)sc;
662
663	sc->sc_keymap = key_map;
664	sc->sc_accmap = accent_map;
665	for (i = 0; i < KMI_NFKEY; i++) {
666		sc->sc_fkeymap[i] = fkey_tab[i];
667	}
668
669	kbd_set_maps(kbd, &sc->sc_keymap, &sc->sc_accmap,
670	    sc->sc_fkeymap, KMI_NFKEY);
671
672	KBD_FOUND_DEVICE(kbd);
673	kmi_clear_state(kbd);
674	KBD_PROBE_DONE(kbd);
675
676	KBD_INIT_DONE(kbd);
677
678	if (kbd_register(kbd) < 0) {
679		goto detach;
680	}
681	KBD_CONFIG_DONE(kbd);
682
683#ifdef KBD_INSTALL_CDEV
684	if (kbd_attach(kbd)) {
685		goto detach;
686	}
687#endif
688
689	if (bootverbose) {
690		genkbd_diag(kbd, bootverbose);
691	}
692	return (0);
693
694detach:
695	return (ENXIO);
696
697}
698
699static device_method_t pl050_kmi_methods[] = {
700	DEVMETHOD(device_probe,		pl050_kmi_probe),
701	DEVMETHOD(device_attach,	pl050_kmi_attach),
702	{ 0, 0 }
703};
704
705static driver_t pl050_kmi_driver = {
706	"kmi",
707	pl050_kmi_methods,
708	sizeof(struct kmi_softc),
709};
710
711static devclass_t pl050_kmi_devclass;
712
713DRIVER_MODULE(pl050_kmi, simplebus, pl050_kmi_driver, pl050_kmi_devclass, 0, 0);
714