xref: /freebsd/sys/arm/broadcom/bcm2835/bcm2835_fb.c (revision 7cd2dcf07629713e5a3d60472cfe4701b705a167)
1 /*-
2  * Copyright (c) 2012 Oleksandr Tymoshenko <gonzo@freebsd.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  */
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/bio.h>
33 #include <sys/bus.h>
34 #include <sys/conf.h>
35 #include <sys/endian.h>
36 #include <sys/kernel.h>
37 #include <sys/kthread.h>
38 #include <sys/lock.h>
39 #include <sys/malloc.h>
40 #include <sys/module.h>
41 #include <sys/mutex.h>
42 #include <sys/queue.h>
43 #include <sys/resource.h>
44 #include <sys/rman.h>
45 #include <sys/time.h>
46 #include <sys/timetc.h>
47 #include <sys/fbio.h>
48 #include <sys/consio.h>
49 
50 #include <sys/kdb.h>
51 
52 #include <machine/bus.h>
53 #include <machine/cpu.h>
54 #include <machine/cpufunc.h>
55 #include <machine/resource.h>
56 #include <machine/frame.h>
57 #include <machine/intr.h>
58 
59 #include <dev/fdt/fdt_common.h>
60 #include <dev/ofw/ofw_bus.h>
61 #include <dev/ofw/ofw_bus_subr.h>
62 
63 #include <dev/fb/fbreg.h>
64 #include <dev/syscons/syscons.h>
65 
66 #include <arm/broadcom/bcm2835/bcm2835_mbox.h>
67 #include <arm/broadcom/bcm2835/bcm2835_vcbus.h>
68 
69 #define	BCMFB_FONT_HEIGHT	16
70 
71 #define FB_WIDTH		640
72 #define FB_HEIGHT		480
73 
74 struct bcm_fb_config {
75 	uint32_t	xres;
76 	uint32_t	yres;
77 	uint32_t	vxres;
78 	uint32_t	vyres;
79 	uint32_t	pitch;
80 	uint32_t	bpp;
81 	uint32_t	xoffset;
82 	uint32_t	yoffset;
83 	/* Filled by videocore */
84 	uint32_t	base;
85 	uint32_t	screen_size;
86 };
87 
88 struct bcmsc_softc {
89 	device_t		dev;
90 	struct cdev *		cdev;
91 	struct mtx		mtx;
92 	bus_dma_tag_t		dma_tag;
93 	bus_dmamap_t		dma_map;
94 	struct bcm_fb_config*	fb_config;
95 	bus_addr_t		fb_config_phys;
96 	struct intr_config_hook	init_hook;
97 
98 };
99 
100 struct video_adapter_softc {
101 	/* Videoadpater part */
102 	video_adapter_t	va;
103 	int		console;
104 
105 	intptr_t	fb_addr;
106 	unsigned int	fb_size;
107 
108 	unsigned int	height;
109 	unsigned int	width;
110 	unsigned int	stride;
111 
112 	unsigned int	xmargin;
113 	unsigned int	ymargin;
114 
115 	unsigned char	*font;
116 	int		initialized;
117 };
118 
119 static struct bcmsc_softc *bcmsc_softc;
120 static struct video_adapter_softc va_softc;
121 
122 #define	bcm_fb_lock(_sc)	mtx_lock(&(_sc)->mtx)
123 #define	bcm_fb_unlock(_sc)	mtx_unlock(&(_sc)->mtx)
124 #define	bcm_fb_lock_assert(sc)	mtx_assert(&(_sc)->mtx, MA_OWNED)
125 
126 static int bcm_fb_probe(device_t);
127 static int bcm_fb_attach(device_t);
128 static void bcm_fb_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err);
129 
130 static void
131 bcm_fb_init(void *arg)
132 {
133 	struct bcmsc_softc *sc = arg;
134 	struct video_adapter_softc *va_sc = &va_softc;
135 	int err;
136 	volatile struct bcm_fb_config*	fb_config = sc->fb_config;
137 
138 	/* TODO: replace it with FDT stuff */
139 	fb_config->xres = FB_WIDTH;
140 	fb_config->yres = FB_HEIGHT;
141 	fb_config->vxres = 0;
142 	fb_config->vyres = 0;
143 	fb_config->xoffset = 0;
144 	fb_config->yoffset = 0;
145 	fb_config->bpp = 24;
146 	fb_config->base = 0;
147 	fb_config->pitch = 0;
148 	fb_config->screen_size = 0;
149 
150 	bus_dmamap_sync(sc->dma_tag, sc->dma_map,
151 		BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
152 	bcm_mbox_write(BCM2835_MBOX_CHAN_FB, sc->fb_config_phys);
153 	bcm_mbox_read(BCM2835_MBOX_CHAN_FB, &err);
154 	bus_dmamap_sync(sc->dma_tag, sc->dma_map,
155 		BUS_DMASYNC_POSTREAD);
156 
157 	if (err == 0) {
158 		device_printf(sc->dev, "%dx%d(%dx%d@%d,%d) %dbpp\n",
159 			fb_config->xres, fb_config->yres,
160 			fb_config->vxres, fb_config->vyres,
161 			fb_config->xoffset, fb_config->yoffset,
162 			fb_config->bpp);
163 
164 
165 		device_printf(sc->dev, "pitch %d, base 0x%08x, screen_size %d\n",
166 			fb_config->pitch, fb_config->base,
167 			fb_config->screen_size);
168 
169 		if (fb_config->base) {
170 			va_sc->fb_addr = (intptr_t)pmap_mapdev(fb_config->base, fb_config->screen_size);
171 			va_sc->fb_size = fb_config->screen_size;
172 			va_sc->stride = fb_config->pitch;
173 		}
174 	}
175 	else
176 		device_printf(sc->dev, "Failed to set framebuffer info\n");
177 
178 	config_intrhook_disestablish(&sc->init_hook);
179 }
180 
181 static int
182 bcm_fb_probe(device_t dev)
183 {
184 	int error;
185 
186 	if (!ofw_bus_is_compatible(dev, "broadcom,bcm2835-fb"))
187 		return (ENXIO);
188 
189 	device_set_desc(dev, "BCM2835 framebuffer device");
190 
191 	error = sc_probe_unit(device_get_unit(dev),
192 	    device_get_flags(dev) | SC_AUTODETECT_KBD);
193 
194 	if (error != 0)
195 		return (error);
196 
197 	return (BUS_PROBE_DEFAULT);
198 }
199 
200 static int
201 bcm_fb_attach(device_t dev)
202 {
203 	struct bcmsc_softc *sc = device_get_softc(dev);
204 	int dma_size = sizeof(struct bcm_fb_config);
205 	int err;
206 
207 	if (bcmsc_softc)
208 		return (ENXIO);
209 
210 	bcmsc_softc = sc;
211 
212 	sc->dev = dev;
213 	mtx_init(&sc->mtx, "bcm2835fb", "fb", MTX_DEF);
214 
215 	err = bus_dma_tag_create(
216 	    bus_get_dma_tag(sc->dev),
217 	    PAGE_SIZE, 0,		/* alignment, boundary */
218 	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
219 	    BUS_SPACE_MAXADDR,		/* highaddr */
220 	    NULL, NULL,			/* filter, filterarg */
221 	    dma_size, 1,		/* maxsize, nsegments */
222 	    dma_size, 0,		/* maxsegsize, flags */
223 	    NULL, NULL,			/* lockfunc, lockarg */
224 	    &sc->dma_tag);
225 
226 	err = bus_dmamem_alloc(sc->dma_tag, (void **)&sc->fb_config,
227 	    0, &sc->dma_map);
228 	if (err) {
229 		device_printf(dev, "cannot allocate framebuffer\n");
230 		goto fail;
231 	}
232 
233 	err = bus_dmamap_load(sc->dma_tag, sc->dma_map, sc->fb_config,
234 	    dma_size, bcm_fb_dmamap_cb, &sc->fb_config_phys, BUS_DMA_NOWAIT);
235 
236 	if (err) {
237 		device_printf(dev, "cannot load DMA map\n");
238 		goto fail;
239 	}
240 
241 	err = (sc_attach_unit(device_get_unit(dev),
242 	    device_get_flags(dev) | SC_AUTODETECT_KBD));
243 
244 	if (err) {
245 		device_printf(dev, "failed to attach syscons\n");
246 		goto fail;
247 	}
248 
249 	/*
250 	 * We have to wait until interrupts are enabled.
251 	 * Mailbox relies on it to get data from VideoCore
252 	 */
253         sc->init_hook.ich_func = bcm_fb_init;
254         sc->init_hook.ich_arg = sc;
255 
256         if (config_intrhook_establish(&sc->init_hook) != 0) {
257 		device_printf(dev, "failed to establish intrhook\n");
258                 return (ENOMEM);
259 	}
260 
261 	return (0);
262 
263 fail:
264 	return (ENXIO);
265 }
266 
267 
268 static void
269 bcm_fb_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err)
270 {
271 	bus_addr_t *addr;
272 
273 	if (err)
274 		return;
275 
276 	addr = (bus_addr_t*)arg;
277 	*addr = PHYS_TO_VCBUS(segs[0].ds_addr);
278 }
279 
280 static device_method_t bcm_fb_methods[] = {
281 	/* Device interface */
282 	DEVMETHOD(device_probe,		bcm_fb_probe),
283 	DEVMETHOD(device_attach,	bcm_fb_attach),
284 
285 	{ 0, 0 }
286 };
287 
288 static devclass_t bcm_fb_devclass;
289 
290 static driver_t bcm_fb_driver = {
291 	"fb",
292 	bcm_fb_methods,
293 	sizeof(struct bcmsc_softc),
294 };
295 
296 DRIVER_MODULE(bcm2835fb, simplebus, bcm_fb_driver, bcm_fb_devclass, 0, 0);
297 
298 /*
299  * Video driver routines and glue.
300  */
301 static int			bcmfb_configure(int);
302 static vi_probe_t		bcmfb_probe;
303 static vi_init_t		bcmfb_init;
304 static vi_get_info_t		bcmfb_get_info;
305 static vi_query_mode_t		bcmfb_query_mode;
306 static vi_set_mode_t		bcmfb_set_mode;
307 static vi_save_font_t		bcmfb_save_font;
308 static vi_load_font_t		bcmfb_load_font;
309 static vi_show_font_t		bcmfb_show_font;
310 static vi_save_palette_t	bcmfb_save_palette;
311 static vi_load_palette_t	bcmfb_load_palette;
312 static vi_set_border_t		bcmfb_set_border;
313 static vi_save_state_t		bcmfb_save_state;
314 static vi_load_state_t		bcmfb_load_state;
315 static vi_set_win_org_t		bcmfb_set_win_org;
316 static vi_read_hw_cursor_t	bcmfb_read_hw_cursor;
317 static vi_set_hw_cursor_t	bcmfb_set_hw_cursor;
318 static vi_set_hw_cursor_shape_t	bcmfb_set_hw_cursor_shape;
319 static vi_blank_display_t	bcmfb_blank_display;
320 static vi_mmap_t		bcmfb_mmap;
321 static vi_ioctl_t		bcmfb_ioctl;
322 static vi_clear_t		bcmfb_clear;
323 static vi_fill_rect_t		bcmfb_fill_rect;
324 static vi_bitblt_t		bcmfb_bitblt;
325 static vi_diag_t		bcmfb_diag;
326 static vi_save_cursor_palette_t	bcmfb_save_cursor_palette;
327 static vi_load_cursor_palette_t	bcmfb_load_cursor_palette;
328 static vi_copy_t		bcmfb_copy;
329 static vi_putp_t		bcmfb_putp;
330 static vi_putc_t		bcmfb_putc;
331 static vi_puts_t		bcmfb_puts;
332 static vi_putm_t		bcmfb_putm;
333 
334 static video_switch_t bcmfbvidsw = {
335 	.probe			= bcmfb_probe,
336 	.init			= bcmfb_init,
337 	.get_info		= bcmfb_get_info,
338 	.query_mode		= bcmfb_query_mode,
339 	.set_mode		= bcmfb_set_mode,
340 	.save_font		= bcmfb_save_font,
341 	.load_font		= bcmfb_load_font,
342 	.show_font		= bcmfb_show_font,
343 	.save_palette		= bcmfb_save_palette,
344 	.load_palette		= bcmfb_load_palette,
345 	.set_border		= bcmfb_set_border,
346 	.save_state		= bcmfb_save_state,
347 	.load_state		= bcmfb_load_state,
348 	.set_win_org		= bcmfb_set_win_org,
349 	.read_hw_cursor		= bcmfb_read_hw_cursor,
350 	.set_hw_cursor		= bcmfb_set_hw_cursor,
351 	.set_hw_cursor_shape	= bcmfb_set_hw_cursor_shape,
352 	.blank_display		= bcmfb_blank_display,
353 	.mmap			= bcmfb_mmap,
354 	.ioctl			= bcmfb_ioctl,
355 	.clear			= bcmfb_clear,
356 	.fill_rect		= bcmfb_fill_rect,
357 	.bitblt			= bcmfb_bitblt,
358 	.diag			= bcmfb_diag,
359 	.save_cursor_palette	= bcmfb_save_cursor_palette,
360 	.load_cursor_palette	= bcmfb_load_cursor_palette,
361 	.copy			= bcmfb_copy,
362 	.putp			= bcmfb_putp,
363 	.putc			= bcmfb_putc,
364 	.puts			= bcmfb_puts,
365 	.putm			= bcmfb_putm,
366 };
367 
368 VIDEO_DRIVER(bcmfb, bcmfbvidsw, bcmfb_configure);
369 
370 extern sc_rndr_sw_t txtrndrsw;
371 RENDERER(bcmfb, 0, txtrndrsw, gfb_set);
372 RENDERER_MODULE(bcmfb, gfb_set);
373 
374 static uint16_t bcmfb_static_window[ROW*COL];
375 extern u_char dflt_font_16[];
376 
377 static int
378 bcmfb_configure(int flags)
379 {
380 	struct video_adapter_softc *sc;
381 
382 	sc = &va_softc;
383 
384 	if (sc->initialized)
385 		return 0;
386 
387 	sc->height = FB_HEIGHT;
388 	sc->width = FB_WIDTH;
389 
390 	bcmfb_init(0, &sc->va, 0);
391 
392 	sc->initialized = 1;
393 
394 	return (0);
395 }
396 
397 static int
398 bcmfb_probe(int unit, video_adapter_t **adp, void *arg, int flags)
399 {
400 
401 	return (0);
402 }
403 
404 static int
405 bcmfb_init(int unit, video_adapter_t *adp, int flags)
406 {
407 	struct video_adapter_softc *sc;
408 	video_info_t *vi;
409 
410 	sc = (struct video_adapter_softc *)adp;
411 	vi = &adp->va_info;
412 
413 	vid_init_struct(adp, "bcmfb", -1, unit);
414 
415 	sc->font = dflt_font_16;
416 	vi->vi_cheight = BCMFB_FONT_HEIGHT;
417 	vi->vi_cwidth = 8;
418 	vi->vi_width = sc->width/8;
419 	vi->vi_height = sc->height/vi->vi_cheight;
420 
421 	/*
422 	 * Clamp width/height to syscons maximums
423 	 */
424 	if (vi->vi_width > COL)
425 		vi->vi_width = COL;
426 	if (vi->vi_height > ROW)
427 		vi->vi_height = ROW;
428 
429 	sc->xmargin = (sc->width - (vi->vi_width * vi->vi_cwidth)) / 2;
430 	sc->ymargin = (sc->height - (vi->vi_height * vi->vi_cheight))/2;
431 
432 	adp->va_window = (vm_offset_t) bcmfb_static_window;
433 	adp->va_flags |= V_ADP_FONT /* | V_ADP_COLOR | V_ADP_MODECHANGE */;
434 
435 	vid_register(&sc->va);
436 
437 	return (0);
438 }
439 
440 static int
441 bcmfb_get_info(video_adapter_t *adp, int mode, video_info_t *info)
442 {
443 	bcopy(&adp->va_info, info, sizeof(*info));
444 	return (0);
445 }
446 
447 static int
448 bcmfb_query_mode(video_adapter_t *adp, video_info_t *info)
449 {
450 	return (0);
451 }
452 
453 static int
454 bcmfb_set_mode(video_adapter_t *adp, int mode)
455 {
456 	return (0);
457 }
458 
459 static int
460 bcmfb_save_font(video_adapter_t *adp, int page, int size, int width,
461     u_char *data, int c, int count)
462 {
463 	return (0);
464 }
465 
466 static int
467 bcmfb_load_font(video_adapter_t *adp, int page, int size, int width,
468     u_char *data, int c, int count)
469 {
470 	struct video_adapter_softc *sc = (struct video_adapter_softc *)adp;
471 
472 	sc->font = data;
473 
474 	return (0);
475 }
476 
477 static int
478 bcmfb_show_font(video_adapter_t *adp, int page)
479 {
480 	return (0);
481 }
482 
483 static int
484 bcmfb_save_palette(video_adapter_t *adp, u_char *palette)
485 {
486 	return (0);
487 }
488 
489 static int
490 bcmfb_load_palette(video_adapter_t *adp, u_char *palette)
491 {
492 	return (0);
493 }
494 
495 static int
496 bcmfb_set_border(video_adapter_t *adp, int border)
497 {
498 	return (bcmfb_blank_display(adp, border));
499 }
500 
501 static int
502 bcmfb_save_state(video_adapter_t *adp, void *p, size_t size)
503 {
504 	return (0);
505 }
506 
507 static int
508 bcmfb_load_state(video_adapter_t *adp, void *p)
509 {
510 	return (0);
511 }
512 
513 static int
514 bcmfb_set_win_org(video_adapter_t *adp, off_t offset)
515 {
516 	return (0);
517 }
518 
519 static int
520 bcmfb_read_hw_cursor(video_adapter_t *adp, int *col, int *row)
521 {
522 	*col = *row = 0;
523 
524 	return (0);
525 }
526 
527 static int
528 bcmfb_set_hw_cursor(video_adapter_t *adp, int col, int row)
529 {
530 	return (0);
531 }
532 
533 static int
534 bcmfb_set_hw_cursor_shape(video_adapter_t *adp, int base, int height,
535     int celsize, int blink)
536 {
537 	return (0);
538 }
539 
540 static int
541 bcmfb_blank_display(video_adapter_t *adp, int mode)
542 {
543 
544 	return (0);
545 }
546 
547 static int
548 bcmfb_mmap(video_adapter_t *adp, vm_ooffset_t offset, vm_paddr_t *paddr,
549     int prot, vm_memattr_t *memattr)
550 {
551 	struct video_adapter_softc *sc;
552 
553 	sc = (struct video_adapter_softc *)adp;
554 
555 	/*
556 	 * This might be a legacy VGA mem request: if so, just point it at the
557 	 * framebuffer, since it shouldn't be touched
558 	 */
559 	if (offset < sc->stride*sc->height) {
560 		*paddr = sc->fb_addr + offset;
561 		return (0);
562 	}
563 
564 	return (EINVAL);
565 }
566 
567 static int
568 bcmfb_ioctl(video_adapter_t *adp, u_long cmd, caddr_t data)
569 {
570 
571 	return (0);
572 }
573 
574 static int
575 bcmfb_clear(video_adapter_t *adp)
576 {
577 
578 	return (bcmfb_blank_display(adp, 0));
579 }
580 
581 static int
582 bcmfb_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy)
583 {
584 
585 	return (0);
586 }
587 
588 static int
589 bcmfb_bitblt(video_adapter_t *adp, ...)
590 {
591 
592 	return (0);
593 }
594 
595 static int
596 bcmfb_diag(video_adapter_t *adp, int level)
597 {
598 
599 	return (0);
600 }
601 
602 static int
603 bcmfb_save_cursor_palette(video_adapter_t *adp, u_char *palette)
604 {
605 
606 	return (0);
607 }
608 
609 static int
610 bcmfb_load_cursor_palette(video_adapter_t *adp, u_char *palette)
611 {
612 
613 	return (0);
614 }
615 
616 static int
617 bcmfb_copy(video_adapter_t *adp, vm_offset_t src, vm_offset_t dst, int n)
618 {
619 
620 	return (0);
621 }
622 
623 static int
624 bcmfb_putp(video_adapter_t *adp, vm_offset_t off, uint32_t p, uint32_t a,
625     int size, int bpp, int bit_ltor, int byte_ltor)
626 {
627 
628 	return (0);
629 }
630 
631 static int
632 bcmfb_putc(video_adapter_t *adp, vm_offset_t off, uint8_t c, uint8_t a)
633 {
634 	struct video_adapter_softc *sc;
635 	int row;
636 	int col;
637 	int i, j, k;
638 	uint8_t *addr;
639 	u_char *p;
640 	uint8_t fg, bg, color;
641 
642 	sc = (struct video_adapter_softc *)adp;
643 
644 	if (sc->fb_addr == 0)
645 		return (0);
646 
647 	row = (off / adp->va_info.vi_width) * adp->va_info.vi_cheight;
648 	col = (off % adp->va_info.vi_width) * adp->va_info.vi_cwidth;
649 	p = sc->font + c*BCMFB_FONT_HEIGHT;
650 	addr = (uint8_t *)sc->fb_addr
651 	    + (row + sc->ymargin)*(sc->stride)
652 	    + 3 * (col + sc->xmargin);
653 
654 	/*
655 	 * FIXME: hardcoded
656 	 */
657 	bg = 0x00;
658 	fg = 0x80;
659 
660 	for (i = 0; i < BCMFB_FONT_HEIGHT; i++) {
661 		for (j = 0, k = 7; j < 8; j++, k--) {
662 			if ((p[i] & (1 << k)) == 0)
663 				color = bg;
664 			else
665 				color = fg;
666 
667 			addr[3*j] = color;
668 			addr[3*j+1] = color;
669 			addr[3*j+2] = color;
670 		}
671 
672 		addr += (sc->stride);
673 	}
674 
675         return (0);
676 }
677 
678 static int
679 bcmfb_puts(video_adapter_t *adp, vm_offset_t off, u_int16_t *s, int len)
680 {
681 	int i;
682 
683 	for (i = 0; i < len; i++)
684 		bcmfb_putc(adp, off + i, s[i] & 0xff, (s[i] & 0xff00) >> 8);
685 
686 	return (0);
687 }
688 
689 static int
690 bcmfb_putm(video_adapter_t *adp, int x, int y, uint8_t *pixel_image,
691     uint32_t pixel_mask, int size, int width)
692 {
693 
694 	return (0);
695 }
696 
697 /*
698  * Define a stub keyboard driver in case one hasn't been
699  * compiled into the kernel
700  */
701 #include <sys/kbio.h>
702 #include <dev/kbd/kbdreg.h>
703 
704 static int dummy_kbd_configure(int flags);
705 
706 keyboard_switch_t bcmdummysw;
707 
708 static int
709 dummy_kbd_configure(int flags)
710 {
711 
712 	return (0);
713 }
714 KEYBOARD_DRIVER(bcmdummy, bcmdummysw, dummy_kbd_configure);
715