pl050.c revision 330897
1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2012 Oleksandr Tymoshenko <gonzo@freebsd.org>
5 * All rights reserved.
6 *
7 * Based on dev/usb/input/ukbd.c
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD: stable/11/sys/arm/versatile/pl050.c 330897 2018-03-14 03:19:51Z eadler $");
33
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/bus.h>
37#include <sys/kernel.h>
38#include <sys/module.h>
39#include <sys/malloc.h>
40#include <sys/rman.h>
41#include <sys/proc.h>
42#include <sys/sched.h>
43#include <sys/kdb.h>
44
45#include <machine/bus.h>
46#include <machine/cpu.h>
47#include <machine/intr.h>
48
49#include <dev/fdt/fdt_common.h>
50#include <dev/ofw/openfirm.h>
51#include <dev/ofw/ofw_bus.h>
52#include <dev/ofw/ofw_bus_subr.h>
53
54#include <sys/ioccom.h>
55#include <sys/filio.h>
56#include <sys/tty.h>
57#include <sys/kbio.h>
58
59#include <dev/kbd/kbdreg.h>
60
61#include <machine/bus.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_status_okay(dev))
614		return (ENXIO);
615
616	if (ofw_bus_is_compatible(dev, "arm,pl050")) {
617		device_set_desc(dev, "PL050 Keyboard/Mouse Interface");
618		return (BUS_PROBE_DEFAULT);
619	}
620
621	return (ENXIO);
622}
623
624static int
625pl050_kmi_attach(device_t dev)
626{
627	struct kmi_softc *sc = device_get_softc(dev);
628	keyboard_t *kbd;
629	int rid;
630	int i;
631
632	kbd = &sc->sc_kbd;
633	rid = 0;
634
635	sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
636	if (sc->sc_mem_res == NULL) {
637		device_printf(dev, "could not allocate memory resource\n");
638		return (ENXIO);
639	}
640
641	/* Request the IRQ resources */
642	sc->sc_irq_res =  bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
643	if (sc->sc_irq_res == NULL) {
644		device_printf(dev, "Error: could not allocate irq resources\n");
645		return (ENXIO);
646	}
647
648	/* Setup and enable the timer */
649	if (bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_CLK,
650			NULL, pl050_kmi_intr, sc,
651			&sc->sc_intr_hl) != 0) {
652		bus_release_resource(dev, SYS_RES_IRQ, rid,
653			sc->sc_irq_res);
654		device_printf(dev, "Unable to setup the clock irq handler.\n");
655		return (ENXIO);
656	}
657
658	/* TODO: clock & divisor */
659
660	pl050_kmi_write_4(sc, KMICR, KMICR_EN | KMICR_RXINTREN);
661
662	kbd_init_struct(kbd, KMI_DRIVER_NAME, KB_OTHER,
663			device_get_unit(dev), 0, 0, 0);
664	kbd->kb_data = (void *)sc;
665
666	sc->sc_keymap = key_map;
667	sc->sc_accmap = accent_map;
668	for (i = 0; i < KMI_NFKEY; i++) {
669		sc->sc_fkeymap[i] = fkey_tab[i];
670	}
671
672	kbd_set_maps(kbd, &sc->sc_keymap, &sc->sc_accmap,
673	    sc->sc_fkeymap, KMI_NFKEY);
674
675	KBD_FOUND_DEVICE(kbd);
676	kmi_clear_state(kbd);
677	KBD_PROBE_DONE(kbd);
678
679	KBD_INIT_DONE(kbd);
680
681	if (kbd_register(kbd) < 0) {
682		goto detach;
683	}
684	KBD_CONFIG_DONE(kbd);
685
686#ifdef KBD_INSTALL_CDEV
687	if (kbd_attach(kbd)) {
688		goto detach;
689	}
690#endif
691
692	if (bootverbose) {
693		genkbd_diag(kbd, bootverbose);
694	}
695	return (0);
696
697detach:
698	return (ENXIO);
699
700}
701
702static device_method_t pl050_kmi_methods[] = {
703	DEVMETHOD(device_probe,		pl050_kmi_probe),
704	DEVMETHOD(device_attach,	pl050_kmi_attach),
705	{ 0, 0 }
706};
707
708static driver_t pl050_kmi_driver = {
709	"kmi",
710	pl050_kmi_methods,
711	sizeof(struct kmi_softc),
712};
713
714static devclass_t pl050_kmi_devclass;
715
716DRIVER_MODULE(pl050_kmi, simplebus, pl050_kmi_driver, pl050_kmi_devclass, 0, 0);
717