bcm2835_fb.c revision 253006
1203288Srnoland/*- 2203288Srnoland * Copyright (c) 2012 Oleksandr Tymoshenko <gonzo@freebsd.org> 3203288Srnoland * All rights reserved. 4203288Srnoland * 5203288Srnoland * Redistribution and use in source and binary forms, with or without 6203288Srnoland * modification, are permitted provided that the following conditions 7203288Srnoland * are met: 8203288Srnoland * 1. Redistributions of source code must retain the above copyright 9203288Srnoland * notice, this list of conditions and the following disclaimer. 10203288Srnoland * 2. Redistributions in binary form must reproduce the above copyright 11203288Srnoland * notice, this list of conditions and the following disclaimer in the 12203288Srnoland * documentation and/or other materials provided with the distribution. 13203288Srnoland * 14203288Srnoland * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15203288Srnoland * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16203288Srnoland * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17203288Srnoland * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18203288Srnoland * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19203288Srnoland * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20203288Srnoland * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21203288Srnoland * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22203288Srnoland * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23203288Srnoland * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24203288Srnoland * SUCH DAMAGE. 25203288Srnoland * 26203288Srnoland */ 27203288Srnoland#include <sys/cdefs.h> 28203288Srnoland__FBSDID("$FreeBSD: head/sys/arm/broadcom/bcm2835/bcm2835_fb.c 253006 2013-07-07 21:23:58Z rpaulo $"); 29203288Srnoland 30203288Srnoland#include <sys/param.h> 31203288Srnoland#include <sys/systm.h> 32203288Srnoland#include <sys/bio.h> 33203288Srnoland#include <sys/bus.h> 34203288Srnoland#include <sys/conf.h> 35203288Srnoland#include <sys/endian.h> 36203288Srnoland#include <sys/kernel.h> 37203288Srnoland#include <sys/kthread.h> 38203288Srnoland#include <sys/lock.h> 39203288Srnoland#include <sys/malloc.h> 40203288Srnoland#include <sys/module.h> 41203288Srnoland#include <sys/mutex.h> 42203288Srnoland#include <sys/queue.h> 43203288Srnoland#include <sys/resource.h> 44203288Srnoland#include <sys/rman.h> 45203288Srnoland#include <sys/time.h> 46203288Srnoland#include <sys/timetc.h> 47203288Srnoland#include <sys/fbio.h> 48203288Srnoland#include <sys/consio.h> 49203288Srnoland 50203288Srnoland#include <sys/kdb.h> 51203288Srnoland 52203288Srnoland#include <machine/bus.h> 53203288Srnoland#include <machine/cpu.h> 54203288Srnoland#include <machine/cpufunc.h> 55203288Srnoland#include <machine/resource.h> 56203288Srnoland#include <machine/frame.h> 57203288Srnoland#include <machine/intr.h> 58203288Srnoland 59203288Srnoland#include <dev/fdt/fdt_common.h> 60203288Srnoland#include <dev/ofw/ofw_bus.h> 61203288Srnoland#include <dev/ofw/ofw_bus_subr.h> 62203288Srnoland 63203288Srnoland#include <dev/fb/fbreg.h> 64203288Srnoland#include <dev/syscons/syscons.h> 65203288Srnoland 66203288Srnoland#include <arm/broadcom/bcm2835/bcm2835_mbox.h> 67203288Srnoland#include <arm/broadcom/bcm2835/bcm2835_vcbus.h> 68203288Srnoland 69203288Srnoland#include "mbox_if.h" 70203288Srnoland 71203288Srnoland#define BCMFB_FONT_HEIGHT 16 72203288Srnoland 73203288Srnolandstruct argb { 74203288Srnoland uint8_t a; 75203288Srnoland uint8_t r; 76203288Srnoland uint8_t g; 77203288Srnoland uint8_t b; 78203288Srnoland}; 79203288Srnoland 80203288Srnolandstatic struct argb bcmfb_palette[16] = { 81203288Srnoland {0x00, 0x00, 0x00, 0x00}, 82203288Srnoland {0x00, 0x00, 0x00, 0xaa}, 83203288Srnoland {0x00, 0x00, 0xaa, 0x00}, 84203288Srnoland {0x00, 0x00, 0xaa, 0xaa}, 85203288Srnoland {0x00, 0xaa, 0x00, 0x00}, 86203288Srnoland {0x00, 0xaa, 0x00, 0xaa}, 87203288Srnoland {0x00, 0xaa, 0x55, 0x00}, 88203288Srnoland {0x00, 0xaa, 0xaa, 0xaa}, 89203288Srnoland {0x00, 0x55, 0x55, 0x55}, 90203288Srnoland {0x00, 0x55, 0x55, 0xff}, 91203288Srnoland {0x00, 0x55, 0xff, 0x55}, 92203288Srnoland {0x00, 0x55, 0xff, 0xff}, 93203288Srnoland {0x00, 0xff, 0x55, 0x55}, 94203288Srnoland {0x00, 0xff, 0x55, 0xff}, 95203288Srnoland {0x00, 0xff, 0xff, 0x55}, 96203288Srnoland {0x00, 0xff, 0xff, 0xff} 97203288Srnoland}; 98203288Srnoland 99203288Srnoland/* mouse pointer from dev/syscons/scgfbrndr.c */ 100203288Srnolandstatic u_char mouse_pointer[16] = { 101203288Srnoland 0x00, 0x40, 0x60, 0x70, 0x78, 0x7c, 0x7e, 0x68, 102203288Srnoland 0x0c, 0x0c, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00 103203288Srnoland}; 104203288Srnoland 105203288Srnoland#define FB_WIDTH 640 106203288Srnoland#define FB_HEIGHT 480 107203288Srnoland#define FB_DEPTH 24 108203288Srnoland 109203288Srnolandstruct bcm_fb_config { 110203288Srnoland uint32_t xres; 111203288Srnoland uint32_t yres; 112203288Srnoland uint32_t vxres; 113203288Srnoland uint32_t vyres; 114203288Srnoland uint32_t pitch; 115203288Srnoland uint32_t bpp; 116203288Srnoland uint32_t xoffset; 117203288Srnoland uint32_t yoffset; 118203288Srnoland /* Filled by videocore */ 119203288Srnoland uint32_t base; 120203288Srnoland uint32_t screen_size; 121203288Srnoland}; 122203288Srnoland 123203288Srnolandstruct bcmsc_softc { 124203288Srnoland device_t dev; 125203288Srnoland struct cdev * cdev; 126203288Srnoland struct mtx mtx; 127203288Srnoland bus_dma_tag_t dma_tag; 128203288Srnoland bus_dmamap_t dma_map; 129203288Srnoland struct bcm_fb_config* fb_config; 130203288Srnoland bus_addr_t fb_config_phys; 131203288Srnoland struct intr_config_hook init_hook; 132203288Srnoland 133203288Srnoland}; 134203288Srnoland 135203288Srnolandstruct video_adapter_softc { 136203288Srnoland /* Videoadpater part */ 137203288Srnoland video_adapter_t va; 138203288Srnoland int console; 139203288Srnoland 140203288Srnoland intptr_t fb_addr; 141203288Srnoland intptr_t fb_paddr; 142203288Srnoland unsigned int fb_size; 143203288Srnoland 144203288Srnoland unsigned int height; 145203288Srnoland unsigned int width; 146203288Srnoland unsigned int depth; 147203288Srnoland unsigned int stride; 148203288Srnoland 149203288Srnoland unsigned int xmargin; 150203288Srnoland unsigned int ymargin; 151203288Srnoland 152203288Srnoland unsigned char *font; 153203288Srnoland int initialized; 154203288Srnoland}; 155203288Srnoland 156203288Srnolandstatic struct bcmsc_softc *bcmsc_softc; 157203288Srnolandstatic struct video_adapter_softc va_softc; 158203288Srnoland 159203288Srnoland#define bcm_fb_lock(_sc) mtx_lock(&(_sc)->mtx) 160203288Srnoland#define bcm_fb_unlock(_sc) mtx_unlock(&(_sc)->mtx) 161203288Srnoland#define bcm_fb_lock_assert(sc) mtx_assert(&(_sc)->mtx, MA_OWNED) 162203288Srnoland 163203288Srnolandstatic int bcm_fb_probe(device_t); 164203288Srnolandstatic int bcm_fb_attach(device_t); 165203288Srnolandstatic void bcm_fb_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err); 166203288Srnolandstatic void bcmfb_update_margins(video_adapter_t *adp); 167203288Srnolandstatic int bcmfb_configure(int); 168203288Srnoland 169203288Srnolandstatic void 170203288Srnolandbcm_fb_init(void *arg) 171203288Srnoland{ 172203288Srnoland struct bcmsc_softc *sc = arg; 173203288Srnoland struct video_adapter_softc *va_sc = &va_softc; 174203288Srnoland int err; 175203288Srnoland volatile struct bcm_fb_config* fb_config = sc->fb_config; 176203288Srnoland phandle_t node; 177203288Srnoland pcell_t cell; 178203288Srnoland device_t mbox; 179203288Srnoland 180203288Srnoland node = ofw_bus_get_node(sc->dev); 181203288Srnoland 182203288Srnoland fb_config->xres = 0; 183203288Srnoland fb_config->yres = 0; 184203288Srnoland fb_config->bpp = 0; 185203288Srnoland 186203288Srnoland if ((OF_getprop(node, "broadcom,width", &cell, sizeof(cell))) > 0) 187203288Srnoland fb_config->xres = (int)fdt32_to_cpu(cell); 188203288Srnoland if (fb_config->xres == 0) 189203288Srnoland fb_config->xres = FB_WIDTH; 190203288Srnoland 191203288Srnoland if ((OF_getprop(node, "broadcom,height", &cell, sizeof(cell))) > 0) 192203288Srnoland fb_config->yres = (uint32_t)fdt32_to_cpu(cell); 193203288Srnoland if (fb_config->yres == 0) 194203288Srnoland fb_config->yres = FB_HEIGHT; 195203288Srnoland 196203288Srnoland if ((OF_getprop(node, "broadcom,depth", &cell, sizeof(cell))) > 0) 197203288Srnoland fb_config->bpp = (uint32_t)fdt32_to_cpu(cell); 198203288Srnoland if (fb_config->bpp == 0) 199203288Srnoland fb_config->bpp = FB_DEPTH; 200203288Srnoland 201203288Srnoland fb_config->vxres = 0; 202203288Srnoland fb_config->vyres = 0; 203203288Srnoland fb_config->xoffset = 0; 204203288Srnoland fb_config->yoffset = 0; 205203288Srnoland fb_config->base = 0; 206203288Srnoland fb_config->pitch = 0; 207203288Srnoland fb_config->screen_size = 0; 208203288Srnoland 209203288Srnoland bus_dmamap_sync(sc->dma_tag, sc->dma_map, 210203288Srnoland BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); 211203288Srnoland 212203288Srnoland mbox = devclass_get_device(devclass_find("mbox"), 0); 213203288Srnoland if (mbox) { 214203288Srnoland MBOX_WRITE(mbox, BCM2835_MBOX_CHAN_FB, sc->fb_config_phys); 215203288Srnoland MBOX_READ(mbox, BCM2835_MBOX_CHAN_FB, &err); 216203288Srnoland } 217203288Srnoland bus_dmamap_sync(sc->dma_tag, sc->dma_map, 218203288Srnoland BUS_DMASYNC_POSTREAD); 219203288Srnoland 220203288Srnoland if (fb_config->base != 0) { 221203288Srnoland device_printf(sc->dev, "%dx%d(%dx%d@%d,%d) %dbpp\n", 222203288Srnoland fb_config->xres, fb_config->yres, 223203288Srnoland fb_config->vxres, fb_config->vyres, 224203288Srnoland fb_config->xoffset, fb_config->yoffset, 225203288Srnoland fb_config->bpp); 226203288Srnoland 227203288Srnoland 228203288Srnoland device_printf(sc->dev, "pitch %d, base 0x%08x, screen_size %d\n", 229203288Srnoland fb_config->pitch, fb_config->base, 230203288Srnoland fb_config->screen_size); 231203288Srnoland 232203288Srnoland va_sc->fb_addr = (intptr_t)pmap_mapdev(fb_config->base, fb_config->screen_size); 233203288Srnoland va_sc->fb_paddr = fb_config->base; 234203288Srnoland va_sc->fb_size = fb_config->screen_size; 235203288Srnoland va_sc->depth = fb_config->bpp; 236203288Srnoland va_sc->stride = fb_config->pitch; 237203288Srnoland 238203288Srnoland va_sc->width = fb_config->xres; 239203288Srnoland va_sc->height = fb_config->yres; 240203288Srnoland bcmfb_update_margins(&va_sc->va); 241203288Srnoland } 242203288Srnoland else { 243203288Srnoland device_printf(sc->dev, "Failed to set framebuffer info\n"); 244203288Srnoland return; 245203288Srnoland } 246203288Srnoland 247203288Srnoland config_intrhook_disestablish(&sc->init_hook); 248203288Srnoland} 249203288Srnoland 250203288Srnolandstatic int 251203288Srnolandbcm_fb_probe(device_t dev) 252203288Srnoland{ 253203288Srnoland int error = 0; 254203288Srnoland 255203288Srnoland if (!ofw_bus_is_compatible(dev, "broadcom,bcm2835-fb")) 256203288Srnoland return (ENXIO); 257203288Srnoland 258203288Srnoland device_set_desc(dev, "BCM2835 framebuffer device"); 259203288Srnoland 260203288Srnoland error = sc_probe_unit(device_get_unit(dev), 261203288Srnoland device_get_flags(dev) | SC_AUTODETECT_KBD); 262203288Srnoland if (error != 0) 263203288Srnoland return (error); 264203288Srnoland 265203288Srnoland 266203288Srnoland return (BUS_PROBE_DEFAULT); 267203288Srnoland} 268203288Srnoland 269203288Srnolandstatic int 270203288Srnolandbcm_fb_attach(device_t dev) 271203288Srnoland{ 272203288Srnoland struct bcmsc_softc *sc = device_get_softc(dev); 273203288Srnoland int dma_size = sizeof(struct bcm_fb_config); 274203288Srnoland int err; 275203288Srnoland 276203288Srnoland if (bcmsc_softc) 277203288Srnoland return (ENXIO); 278203288Srnoland 279203288Srnoland bcmsc_softc = sc; 280203288Srnoland 281203288Srnoland sc->dev = dev; 282203288Srnoland mtx_init(&sc->mtx, "bcm2835fb", "fb", MTX_DEF); 283203288Srnoland 284203288Srnoland err = bus_dma_tag_create( 285203288Srnoland bus_get_dma_tag(sc->dev), 286203288Srnoland PAGE_SIZE, 0, /* alignment, boundary */ 287203288Srnoland BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 288203288Srnoland BUS_SPACE_MAXADDR, /* highaddr */ 289203288Srnoland NULL, NULL, /* filter, filterarg */ 290203288Srnoland dma_size, 1, /* maxsize, nsegments */ 291203288Srnoland dma_size, 0, /* maxsegsize, flags */ 292203288Srnoland NULL, NULL, /* lockfunc, lockarg */ 293203288Srnoland &sc->dma_tag); 294203288Srnoland 295203288Srnoland err = bus_dmamem_alloc(sc->dma_tag, (void **)&sc->fb_config, 296203288Srnoland 0, &sc->dma_map); 297203288Srnoland if (err) { 298203288Srnoland device_printf(dev, "cannot allocate framebuffer\n"); 299203288Srnoland goto fail; 300203288Srnoland } 301203288Srnoland 302203288Srnoland err = bus_dmamap_load(sc->dma_tag, sc->dma_map, sc->fb_config, 303203288Srnoland dma_size, bcm_fb_dmamap_cb, &sc->fb_config_phys, BUS_DMA_NOWAIT); 304203288Srnoland 305203288Srnoland if (err) { 306203288Srnoland device_printf(dev, "cannot load DMA map\n"); 307203288Srnoland goto fail; 308203288Srnoland } 309203288Srnoland 310203288Srnoland err = (sc_attach_unit(device_get_unit(dev), 311203288Srnoland device_get_flags(dev) | SC_AUTODETECT_KBD)); 312203288Srnoland 313203288Srnoland if (err) { 314203288Srnoland device_printf(dev, "failed to attach syscons\n"); 315203288Srnoland goto fail; 316203288Srnoland } 317203288Srnoland 318203288Srnoland /* 319203288Srnoland * We have to wait until interrupts are enabled. 320203288Srnoland * Mailbox relies on it to get data from VideoCore 321203288Srnoland */ 322203288Srnoland sc->init_hook.ich_func = bcm_fb_init; 323203288Srnoland sc->init_hook.ich_arg = sc; 324203288Srnoland 325203288Srnoland if (config_intrhook_establish(&sc->init_hook) != 0) { 326203288Srnoland device_printf(dev, "failed to establish intrhook\n"); 327203288Srnoland return (ENOMEM); 328203288Srnoland } 329203288Srnoland 330203288Srnoland return (0); 331203288Srnoland 332203288Srnolandfail: 333203288Srnoland return (ENXIO); 334203288Srnoland} 335203288Srnoland 336203288Srnoland 337203288Srnolandstatic void 338203288Srnolandbcm_fb_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err) 339203288Srnoland{ 340203288Srnoland bus_addr_t *addr; 341203288Srnoland 342203288Srnoland if (err) 343203288Srnoland return; 344203288Srnoland 345203288Srnoland addr = (bus_addr_t*)arg; 346203288Srnoland *addr = PHYS_TO_VCBUS(segs[0].ds_addr); 347203288Srnoland} 348203288Srnoland 349203288Srnolandstatic device_method_t bcm_fb_methods[] = { 350203288Srnoland /* Device interface */ 351203288Srnoland DEVMETHOD(device_probe, bcm_fb_probe), 352203288Srnoland DEVMETHOD(device_attach, bcm_fb_attach), 353203288Srnoland 354203288Srnoland { 0, 0 } 355203288Srnoland}; 356203288Srnoland 357203288Srnolandstatic devclass_t bcm_fb_devclass; 358203288Srnoland 359203288Srnolandstatic driver_t bcm_fb_driver = { 360203288Srnoland "fb", 361203288Srnoland bcm_fb_methods, 362203288Srnoland sizeof(struct bcmsc_softc), 363203288Srnoland}; 364203288Srnoland 365203288SrnolandDRIVER_MODULE(bcm2835fb, fdtbus, bcm_fb_driver, bcm_fb_devclass, 0, 0); 366203288Srnoland 367203288Srnoland/* 368203288Srnoland * Video driver routines and glue. 369203288Srnoland */ 370203288Srnolandstatic vi_probe_t bcmfb_probe; 371203288Srnolandstatic vi_init_t bcmfb_init; 372203288Srnolandstatic vi_get_info_t bcmfb_get_info; 373203288Srnolandstatic vi_query_mode_t bcmfb_query_mode; 374203288Srnolandstatic vi_set_mode_t bcmfb_set_mode; 375203288Srnolandstatic vi_save_font_t bcmfb_save_font; 376203288Srnolandstatic vi_load_font_t bcmfb_load_font; 377203288Srnolandstatic vi_show_font_t bcmfb_show_font; 378203288Srnolandstatic vi_save_palette_t bcmfb_save_palette; 379203288Srnolandstatic vi_load_palette_t bcmfb_load_palette; 380203288Srnolandstatic vi_set_border_t bcmfb_set_border; 381203288Srnolandstatic vi_save_state_t bcmfb_save_state; 382203288Srnolandstatic vi_load_state_t bcmfb_load_state; 383203288Srnolandstatic vi_set_win_org_t bcmfb_set_win_org; 384203288Srnolandstatic vi_read_hw_cursor_t bcmfb_read_hw_cursor; 385203288Srnolandstatic vi_set_hw_cursor_t bcmfb_set_hw_cursor; 386203288Srnolandstatic vi_set_hw_cursor_shape_t bcmfb_set_hw_cursor_shape; 387203288Srnolandstatic vi_blank_display_t bcmfb_blank_display; 388203288Srnolandstatic vi_mmap_t bcmfb_mmap; 389203288Srnolandstatic vi_ioctl_t bcmfb_ioctl; 390203288Srnolandstatic vi_clear_t bcmfb_clear; 391203288Srnolandstatic vi_fill_rect_t bcmfb_fill_rect; 392203288Srnolandstatic vi_bitblt_t bcmfb_bitblt; 393203288Srnolandstatic vi_diag_t bcmfb_diag; 394203288Srnolandstatic vi_save_cursor_palette_t bcmfb_save_cursor_palette; 395203288Srnolandstatic vi_load_cursor_palette_t bcmfb_load_cursor_palette; 396203288Srnolandstatic vi_copy_t bcmfb_copy; 397203288Srnolandstatic vi_putp_t bcmfb_putp; 398203288Srnolandstatic vi_putc_t bcmfb_putc; 399203288Srnolandstatic vi_puts_t bcmfb_puts; 400203288Srnolandstatic vi_putm_t bcmfb_putm; 401203288Srnoland 402203288Srnolandstatic video_switch_t bcmfbvidsw = { 403203288Srnoland .probe = bcmfb_probe, 404203288Srnoland .init = bcmfb_init, 405203288Srnoland .get_info = bcmfb_get_info, 406203288Srnoland .query_mode = bcmfb_query_mode, 407203288Srnoland .set_mode = bcmfb_set_mode, 408203288Srnoland .save_font = bcmfb_save_font, 409203288Srnoland .load_font = bcmfb_load_font, 410203288Srnoland .show_font = bcmfb_show_font, 411203288Srnoland .save_palette = bcmfb_save_palette, 412203288Srnoland .load_palette = bcmfb_load_palette, 413203288Srnoland .set_border = bcmfb_set_border, 414203288Srnoland .save_state = bcmfb_save_state, 415203288Srnoland .load_state = bcmfb_load_state, 416203288Srnoland .set_win_org = bcmfb_set_win_org, 417203288Srnoland .read_hw_cursor = bcmfb_read_hw_cursor, 418203288Srnoland .set_hw_cursor = bcmfb_set_hw_cursor, 419203288Srnoland .set_hw_cursor_shape = bcmfb_set_hw_cursor_shape, 420203288Srnoland .blank_display = bcmfb_blank_display, 421203288Srnoland .mmap = bcmfb_mmap, 422203288Srnoland .ioctl = bcmfb_ioctl, 423203288Srnoland .clear = bcmfb_clear, 424203288Srnoland .fill_rect = bcmfb_fill_rect, 425203288Srnoland .bitblt = bcmfb_bitblt, 426203288Srnoland .diag = bcmfb_diag, 427203288Srnoland .save_cursor_palette = bcmfb_save_cursor_palette, 428203288Srnoland .load_cursor_palette = bcmfb_load_cursor_palette, 429203288Srnoland .copy = bcmfb_copy, 430203288Srnoland .putp = bcmfb_putp, 431203288Srnoland .putc = bcmfb_putc, 432203288Srnoland .puts = bcmfb_puts, 433203288Srnoland .putm = bcmfb_putm, 434203288Srnoland}; 435203288Srnoland 436203288SrnolandVIDEO_DRIVER(bcmfb, bcmfbvidsw, bcmfb_configure); 437203288Srnoland 438203288Srnolandstatic vr_init_t bcmrend_init; 439203288Srnolandstatic vr_clear_t bcmrend_clear; 440203288Srnolandstatic vr_draw_border_t bcmrend_draw_border; 441203288Srnolandstatic vr_draw_t bcmrend_draw; 442203288Srnolandstatic vr_set_cursor_t bcmrend_set_cursor; 443203288Srnolandstatic vr_draw_cursor_t bcmrend_draw_cursor; 444203288Srnolandstatic vr_blink_cursor_t bcmrend_blink_cursor; 445203288Srnolandstatic vr_set_mouse_t bcmrend_set_mouse; 446203288Srnolandstatic vr_draw_mouse_t bcmrend_draw_mouse; 447203288Srnoland 448203288Srnoland/* 449203288Srnoland * We use our own renderer; this is because we must emulate a hardware 450203288Srnoland * cursor. 451203288Srnoland */ 452203288Srnolandstatic sc_rndr_sw_t bcmrend = { 453203288Srnoland bcmrend_init, 454203288Srnoland bcmrend_clear, 455203288Srnoland bcmrend_draw_border, 456203288Srnoland bcmrend_draw, 457203288Srnoland bcmrend_set_cursor, 458203288Srnoland bcmrend_draw_cursor, 459203288Srnoland bcmrend_blink_cursor, 460203288Srnoland bcmrend_set_mouse, 461203288Srnoland bcmrend_draw_mouse 462203288Srnoland}; 463203288Srnoland 464203288SrnolandRENDERER(bcmfb, 0, bcmrend, gfb_set); 465203288SrnolandRENDERER_MODULE(bcmfb, gfb_set); 466203288Srnoland 467203288Srnolandstatic void 468203288Srnolandbcmrend_init(scr_stat* scp) 469203288Srnoland{ 470203288Srnoland} 471203288Srnoland 472203288Srnolandstatic void 473203288Srnolandbcmrend_clear(scr_stat* scp, int c, int attr) 474203288Srnoland{ 475203288Srnoland} 476203288Srnoland 477203288Srnolandstatic void 478203288Srnolandbcmrend_draw_border(scr_stat* scp, int color) 479203288Srnoland{ 480203288Srnoland} 481203288Srnoland 482203288Srnolandstatic void 483203288Srnolandbcmrend_draw(scr_stat* scp, int from, int count, int flip) 484203288Srnoland{ 485203288Srnoland video_adapter_t* adp = scp->sc->adp; 486203288Srnoland int i, c, a; 487203288Srnoland 488203288Srnoland if (!flip) { 489203288Srnoland /* Normal printing */ 490203288Srnoland vidd_puts(adp, from, (uint16_t*)sc_vtb_pointer(&scp->vtb, from), count); 491203288Srnoland } else { 492203288Srnoland /* This is for selections and such: invert the color attribute */ 493203288Srnoland for (i = count; i-- > 0; ++from) { 494203288Srnoland c = sc_vtb_getc(&scp->vtb, from); 495203288Srnoland a = sc_vtb_geta(&scp->vtb, from) >> 8; 496203288Srnoland vidd_putc(adp, from, c, (a >> 4) | ((a & 0xf) << 4)); 497203288Srnoland } 498203288Srnoland } 499203288Srnoland} 500203288Srnoland 501203288Srnolandstatic void 502203288Srnolandbcmrend_set_cursor(scr_stat* scp, int base, int height, int blink) 503203288Srnoland{ 504203288Srnoland} 505203288Srnoland 506203288Srnolandstatic void 507203288Srnolandbcmrend_draw_cursor(scr_stat* scp, int off, int blink, int on, int flip) 508203288Srnoland{ 509203288Srnoland video_adapter_t* adp = scp->sc->adp; 510203288Srnoland struct video_adapter_softc *sc; 511203288Srnoland int row, col; 512203288Srnoland uint8_t *addr; 513203288Srnoland int i, j, bytes; 514203288Srnoland 515203288Srnoland sc = (struct video_adapter_softc *)adp; 516203288Srnoland 517203288Srnoland if (scp->curs_attr.height <= 0) 518203288Srnoland return; 519203288Srnoland 520203288Srnoland if (sc->fb_addr == 0) 521203288Srnoland return; 522203288Srnoland 523203288Srnoland if (off >= adp->va_info.vi_width * adp->va_info.vi_height) 524203288Srnoland return; 525203288Srnoland 526203288Srnoland /* calculate the coordinates in the video buffer */ 527203288Srnoland row = (off / adp->va_info.vi_width) * adp->va_info.vi_cheight; 528203288Srnoland col = (off % adp->va_info.vi_width) * adp->va_info.vi_cwidth; 529203288Srnoland 530203288Srnoland addr = (uint8_t *)sc->fb_addr 531203288Srnoland + (row + sc->ymargin)*(sc->stride) 532203288Srnoland + (sc->depth/8) * (col + sc->xmargin); 533203288Srnoland 534203288Srnoland bytes = sc->depth/8; 535203288Srnoland 536203288Srnoland /* our cursor consists of simply inverting the char under it */ 537203288Srnoland for (i = 0; i < adp->va_info.vi_cheight; i++) { 538203288Srnoland for (j = 0; j < adp->va_info.vi_cwidth; j++) { 539203288Srnoland switch (sc->depth) { 540203288Srnoland case 32: 541203288Srnoland case 24: 542203288Srnoland addr[bytes*j + 2] ^= 0xff; 543203288Srnoland /* FALLTHROUGH */ 544203288Srnoland case 16: 545203288Srnoland addr[bytes*j + 1] ^= 0xff; 546203288Srnoland addr[bytes*j] ^= 0xff; 547203288Srnoland break; 548203288Srnoland default: 549203288Srnoland break; 550203288Srnoland } 551203288Srnoland } 552203288Srnoland 553203288Srnoland addr += sc->stride; 554203288Srnoland } 555203288Srnoland} 556203288Srnoland 557203288Srnolandstatic void 558203288Srnolandbcmrend_blink_cursor(scr_stat* scp, int at, int flip) 559203288Srnoland{ 560203288Srnoland} 561203288Srnoland 562203288Srnolandstatic void 563203288Srnolandbcmrend_set_mouse(scr_stat* scp) 564203288Srnoland{ 565203288Srnoland} 566203288Srnoland 567203288Srnolandstatic void 568203288Srnolandbcmrend_draw_mouse(scr_stat* scp, int x, int y, int on) 569203288Srnoland{ 570203288Srnoland vidd_putm(scp->sc->adp, x, y, mouse_pointer, 0xffffffff, 16, 8); 571203288Srnoland} 572203288Srnoland 573203288Srnolandstatic uint16_t bcmfb_static_window[ROW*COL]; 574203288Srnolandextern u_char dflt_font_16[]; 575203288Srnoland 576203288Srnoland/* 577203288Srnoland * Update videoadapter settings after changing resolution 578203288Srnoland */ 579203288Srnolandstatic void 580203288Srnolandbcmfb_update_margins(video_adapter_t *adp) 581203288Srnoland{ 582203288Srnoland struct video_adapter_softc *sc; 583203288Srnoland video_info_t *vi; 584203288Srnoland 585203288Srnoland sc = (struct video_adapter_softc *)adp; 586203288Srnoland vi = &adp->va_info; 587203288Srnoland 588203288Srnoland sc->xmargin = (sc->width - (vi->vi_width * vi->vi_cwidth)) / 2; 589203288Srnoland sc->ymargin = (sc->height - (vi->vi_height * vi->vi_cheight))/2; 590203288Srnoland} 591203288Srnoland 592203288Srnolandstatic int 593203288Srnolandbcmfb_configure(int flags) 594203288Srnoland{ 595203288Srnoland struct video_adapter_softc *va_sc; 596203288Srnoland 597203288Srnoland va_sc = &va_softc; 598203288Srnoland phandle_t display, root; 599203288Srnoland pcell_t cell; 600203288Srnoland 601203288Srnoland if (va_sc->initialized) 602203288Srnoland return (0); 603203288Srnoland 604203288Srnoland va_sc->width = 0; 605203288Srnoland va_sc->height = 0; 606203288Srnoland 607203288Srnoland /* 608203288Srnoland * It seems there is no way to let syscons framework know 609203288Srnoland * that framebuffer resolution has changed. So just try 610203288Srnoland * to fetch data from FDT and go with defaults if failed 611203288Srnoland */ 612203288Srnoland root = OF_finddevice("/"); 613203288Srnoland if ((root != 0) && 614203288Srnoland (display = fdt_find_compatible(root, "broadcom,bcm2835-fb", 1))) { 615203288Srnoland if ((OF_getprop(display, "broadcom,width", 616203288Srnoland &cell, sizeof(cell))) > 0) 617203288Srnoland va_sc->width = (int)fdt32_to_cpu(cell); 618203288Srnoland 619203288Srnoland if ((OF_getprop(display, "broadcom,height", 620203288Srnoland &cell, sizeof(cell))) > 0) 621203288Srnoland va_sc->height = (int)fdt32_to_cpu(cell); 622203288Srnoland } 623203288Srnoland 624203288Srnoland if (va_sc->width == 0) 625203288Srnoland va_sc->width = FB_WIDTH; 626203288Srnoland if (va_sc->height == 0) 627203288Srnoland va_sc->height = FB_HEIGHT; 628203288Srnoland 629203288Srnoland bcmfb_init(0, &va_sc->va, 0); 630203288Srnoland 631203288Srnoland va_sc->initialized = 1; 632203288Srnoland 633203288Srnoland return (0); 634203288Srnoland} 635203288Srnoland 636203288Srnolandstatic int 637203288Srnolandbcmfb_probe(int unit, video_adapter_t **adp, void *arg, int flags) 638203288Srnoland{ 639203288Srnoland 640203288Srnoland return (0); 641203288Srnoland} 642203288Srnoland 643203288Srnolandstatic int 644203288Srnolandbcmfb_init(int unit, video_adapter_t *adp, int flags) 645203288Srnoland{ 646203288Srnoland struct video_adapter_softc *sc; 647203288Srnoland video_info_t *vi; 648203288Srnoland 649203288Srnoland sc = (struct video_adapter_softc *)adp; 650203288Srnoland vi = &adp->va_info; 651203288Srnoland 652203288Srnoland vid_init_struct(adp, "bcmfb", -1, unit); 653203288Srnoland 654203288Srnoland sc->font = dflt_font_16; 655203288Srnoland vi->vi_cheight = BCMFB_FONT_HEIGHT; 656203288Srnoland vi->vi_cwidth = 8; 657203288Srnoland 658203288Srnoland vi->vi_width = sc->width/8; 659203288Srnoland vi->vi_height = sc->height/vi->vi_cheight; 660203288Srnoland 661203288Srnoland /* 662203288Srnoland * Clamp width/height to syscons maximums 663203288Srnoland */ 664203288Srnoland if (vi->vi_width > COL) 665203288Srnoland vi->vi_width = COL; 666203288Srnoland if (vi->vi_height > ROW) 667203288Srnoland vi->vi_height = ROW; 668203288Srnoland 669203288Srnoland sc->xmargin = (sc->width - (vi->vi_width * vi->vi_cwidth)) / 2; 670203288Srnoland sc->ymargin = (sc->height - (vi->vi_height * vi->vi_cheight))/2; 671203288Srnoland 672203288Srnoland 673203288Srnoland adp->va_window = (vm_offset_t) bcmfb_static_window; 674203288Srnoland adp->va_flags |= V_ADP_FONT /* | V_ADP_COLOR | V_ADP_MODECHANGE */; 675203288Srnoland 676203288Srnoland vid_register(&sc->va); 677203288Srnoland 678203288Srnoland return (0); 679203288Srnoland} 680203288Srnoland 681203288Srnolandstatic int 682203288Srnolandbcmfb_get_info(video_adapter_t *adp, int mode, video_info_t *info) 683203288Srnoland{ 684203288Srnoland bcopy(&adp->va_info, info, sizeof(*info)); 685203288Srnoland return (0); 686203288Srnoland} 687203288Srnoland 688203288Srnolandstatic int 689203288Srnolandbcmfb_query_mode(video_adapter_t *adp, video_info_t *info) 690203288Srnoland{ 691203288Srnoland return (0); 692203288Srnoland} 693203288Srnoland 694203288Srnolandstatic int 695203288Srnolandbcmfb_set_mode(video_adapter_t *adp, int mode) 696203288Srnoland{ 697203288Srnoland return (0); 698203288Srnoland} 699203288Srnoland 700203288Srnolandstatic int 701203288Srnolandbcmfb_save_font(video_adapter_t *adp, int page, int size, int width, 702203288Srnoland u_char *data, int c, int count) 703203288Srnoland{ 704203288Srnoland return (0); 705203288Srnoland} 706203288Srnoland 707203288Srnolandstatic int 708203288Srnolandbcmfb_load_font(video_adapter_t *adp, int page, int size, int width, 709203288Srnoland u_char *data, int c, int count) 710203288Srnoland{ 711203288Srnoland struct video_adapter_softc *sc = (struct video_adapter_softc *)adp; 712203288Srnoland 713203288Srnoland sc->font = data; 714203288Srnoland 715203288Srnoland return (0); 716203288Srnoland} 717203288Srnoland 718203288Srnolandstatic int 719203288Srnolandbcmfb_show_font(video_adapter_t *adp, int page) 720203288Srnoland{ 721203288Srnoland return (0); 722203288Srnoland} 723203288Srnoland 724203288Srnolandstatic int 725203288Srnolandbcmfb_save_palette(video_adapter_t *adp, u_char *palette) 726203288Srnoland{ 727203288Srnoland return (0); 728203288Srnoland} 729203288Srnoland 730203288Srnolandstatic int 731203288Srnolandbcmfb_load_palette(video_adapter_t *adp, u_char *palette) 732203288Srnoland{ 733203288Srnoland return (0); 734203288Srnoland} 735203288Srnoland 736203288Srnolandstatic int 737203288Srnolandbcmfb_set_border(video_adapter_t *adp, int border) 738203288Srnoland{ 739203288Srnoland return (bcmfb_blank_display(adp, border)); 740203288Srnoland} 741203288Srnoland 742203288Srnolandstatic int 743203288Srnolandbcmfb_save_state(video_adapter_t *adp, void *p, size_t size) 744203288Srnoland{ 745203288Srnoland return (0); 746203288Srnoland} 747203288Srnoland 748203288Srnolandstatic int 749203288Srnolandbcmfb_load_state(video_adapter_t *adp, void *p) 750203288Srnoland{ 751203288Srnoland return (0); 752203288Srnoland} 753203288Srnoland 754203288Srnolandstatic int 755203288Srnolandbcmfb_set_win_org(video_adapter_t *adp, off_t offset) 756203288Srnoland{ 757203288Srnoland return (0); 758203288Srnoland} 759203288Srnoland 760203288Srnolandstatic int 761203288Srnolandbcmfb_read_hw_cursor(video_adapter_t *adp, int *col, int *row) 762203288Srnoland{ 763203288Srnoland *col = *row = 0; 764203288Srnoland 765203288Srnoland return (0); 766203288Srnoland} 767203288Srnoland 768203288Srnolandstatic int 769203288Srnolandbcmfb_set_hw_cursor(video_adapter_t *adp, int col, int row) 770203288Srnoland{ 771203288Srnoland return (0); 772203288Srnoland} 773203288Srnoland 774203288Srnolandstatic int 775203288Srnolandbcmfb_set_hw_cursor_shape(video_adapter_t *adp, int base, int height, 776203288Srnoland int celsize, int blink) 777203288Srnoland{ 778203288Srnoland return (0); 779203288Srnoland} 780203288Srnoland 781203288Srnolandstatic int 782203288Srnolandbcmfb_blank_display(video_adapter_t *adp, int mode) 783203288Srnoland{ 784203288Srnoland 785203288Srnoland struct video_adapter_softc *sc; 786203288Srnoland 787203288Srnoland sc = (struct video_adapter_softc *)adp; 788203288Srnoland if (sc && sc->fb_addr) 789203288Srnoland memset((void*)sc->fb_addr, 0, sc->fb_size); 790203288Srnoland 791203288Srnoland return (0); 792203288Srnoland} 793203288Srnoland 794203288Srnolandstatic int 795203288Srnolandbcmfb_mmap(video_adapter_t *adp, vm_ooffset_t offset, vm_paddr_t *paddr, 796203288Srnoland int prot, vm_memattr_t *memattr) 797203288Srnoland{ 798203288Srnoland struct video_adapter_softc *sc; 799203288Srnoland 800203288Srnoland sc = (struct video_adapter_softc *)adp; 801203288Srnoland 802203288Srnoland /* 803203288Srnoland * This might be a legacy VGA mem request: if so, just point it at the 804203288Srnoland * framebuffer, since it shouldn't be touched 805203288Srnoland */ 806203288Srnoland if (offset < sc->stride*sc->height) { 807203288Srnoland *paddr = sc->fb_paddr + offset; 808203288Srnoland return (0); 809203288Srnoland } 810203288Srnoland 811203288Srnoland return (EINVAL); 812203288Srnoland} 813203288Srnoland 814203288Srnolandstatic int 815203288Srnolandbcmfb_ioctl(video_adapter_t *adp, u_long cmd, caddr_t data) 816203288Srnoland{ 817203288Srnoland struct video_adapter_softc *sc; 818203288Srnoland struct fbtype *fb; 819203288Srnoland 820203288Srnoland sc = (struct video_adapter_softc *)adp; 821203288Srnoland 822203288Srnoland switch (cmd) { 823203288Srnoland case FBIOGTYPE: 824203288Srnoland fb = (struct fbtype *)data; 825203288Srnoland fb->fb_type = FBTYPE_PCIMISC; 826203288Srnoland fb->fb_height = sc->height; 827203288Srnoland fb->fb_width = sc->width; 828203288Srnoland fb->fb_depth = sc->depth; 829203288Srnoland if (sc->depth <= 1 || sc->depth > 8) 830203288Srnoland fb->fb_cmsize = 0; 831203288Srnoland else 832203288Srnoland fb->fb_cmsize = 1 << sc->depth; 833203288Srnoland fb->fb_size = sc->fb_size; 834203288Srnoland break; 835203288Srnoland default: 836203288Srnoland return (fb_commonioctl(adp, cmd, data)); 837203288Srnoland } 838203288Srnoland 839203288Srnoland return (0); 840203288Srnoland} 841203288Srnoland 842203288Srnolandstatic int 843203288Srnolandbcmfb_clear(video_adapter_t *adp) 844203288Srnoland{ 845203288Srnoland 846203288Srnoland return (bcmfb_blank_display(adp, 0)); 847203288Srnoland} 848203288Srnoland 849203288Srnolandstatic int 850203288Srnolandbcmfb_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy) 851203288Srnoland{ 852203288Srnoland 853203288Srnoland return (0); 854203288Srnoland} 855203288Srnoland 856203288Srnolandstatic int 857203288Srnolandbcmfb_bitblt(video_adapter_t *adp, ...) 858203288Srnoland{ 859203288Srnoland 860203288Srnoland return (0); 861203288Srnoland} 862203288Srnoland 863203288Srnolandstatic int 864203288Srnolandbcmfb_diag(video_adapter_t *adp, int level) 865203288Srnoland{ 866203288Srnoland 867203288Srnoland return (0); 868203288Srnoland} 869203288Srnoland 870203288Srnolandstatic int 871203288Srnolandbcmfb_save_cursor_palette(video_adapter_t *adp, u_char *palette) 872203288Srnoland{ 873203288Srnoland 874203288Srnoland return (0); 875203288Srnoland} 876203288Srnoland 877203288Srnolandstatic int 878203288Srnolandbcmfb_load_cursor_palette(video_adapter_t *adp, u_char *palette) 879203288Srnoland{ 880203288Srnoland 881203288Srnoland return (0); 882203288Srnoland} 883203288Srnoland 884203288Srnolandstatic int 885203288Srnolandbcmfb_copy(video_adapter_t *adp, vm_offset_t src, vm_offset_t dst, int n) 886203288Srnoland{ 887203288Srnoland 888203288Srnoland return (0); 889203288Srnoland} 890203288Srnoland 891203288Srnolandstatic int 892203288Srnolandbcmfb_putp(video_adapter_t *adp, vm_offset_t off, uint32_t p, uint32_t a, 893203288Srnoland int size, int bpp, int bit_ltor, int byte_ltor) 894203288Srnoland{ 895203288Srnoland 896203288Srnoland return (0); 897203288Srnoland} 898203288Srnoland 899203288Srnolandstatic int 900203288Srnolandbcmfb_putc(video_adapter_t *adp, vm_offset_t off, uint8_t c, uint8_t a) 901203288Srnoland{ 902203288Srnoland struct video_adapter_softc *sc; 903203288Srnoland int row; 904203288Srnoland int col; 905203288Srnoland int i, j, k; 906203288Srnoland uint8_t *addr; 907203288Srnoland u_char *p; 908203288Srnoland uint8_t fg, bg, color; 909203288Srnoland uint16_t rgb; 910203288Srnoland 911203288Srnoland sc = (struct video_adapter_softc *)adp; 912203288Srnoland 913203288Srnoland if (sc->fb_addr == 0) 914203288Srnoland return (0); 915203288Srnoland 916203288Srnoland row = (off / adp->va_info.vi_width) * adp->va_info.vi_cheight; 917203288Srnoland col = (off % adp->va_info.vi_width) * adp->va_info.vi_cwidth; 918203288Srnoland p = sc->font + c*BCMFB_FONT_HEIGHT; 919203288Srnoland addr = (uint8_t *)sc->fb_addr 920203288Srnoland + (row + sc->ymargin)*(sc->stride) 921203288Srnoland + (sc->depth/8) * (col + sc->xmargin); 922203288Srnoland 923203288Srnoland fg = a & 0xf ; 924203288Srnoland bg = (a >> 4) & 0xf; 925203288Srnoland 926203288Srnoland for (i = 0; i < BCMFB_FONT_HEIGHT; i++) { 927203288Srnoland for (j = 0, k = 7; j < 8; j++, k--) { 928203288Srnoland if ((p[i] & (1 << k)) == 0) 929203288Srnoland color = bg; 930203288Srnoland else 931203288Srnoland color = fg; 932203288Srnoland 933203288Srnoland switch (sc->depth) { 934203288Srnoland case 32: 935203288Srnoland addr[4*j+0] = bcmfb_palette[color].r; 936203288Srnoland addr[4*j+1] = bcmfb_palette[color].g; 937203288Srnoland addr[4*j+2] = bcmfb_palette[color].b; 938203288Srnoland addr[4*j+3] = bcmfb_palette[color].a; 939203288Srnoland break; 940203288Srnoland case 24: 941203288Srnoland addr[3*j] = bcmfb_palette[color].r; 942203288Srnoland addr[3*j+1] = bcmfb_palette[color].g; 943203288Srnoland addr[3*j+2] = bcmfb_palette[color].b; 944203288Srnoland break; 945203288Srnoland case 16: 946203288Srnoland rgb = (bcmfb_palette[color].r >> 3) << 11; 947203288Srnoland rgb |= (bcmfb_palette[color].g >> 2) << 5; 948203288Srnoland rgb |= (bcmfb_palette[color].b >> 3); 949203288Srnoland addr[2*j] = rgb & 0xff; 950203288Srnoland addr[2*j + 1] = (rgb >> 8) & 0xff; 951203288Srnoland default: 952203288Srnoland /* Not supported yet */ 953203288Srnoland break; 954203288Srnoland } 955203288Srnoland } 956203288Srnoland 957203288Srnoland addr += (sc->stride); 958203288Srnoland } 959203288Srnoland 960203288Srnoland return (0); 961203288Srnoland} 962203288Srnoland 963203288Srnolandstatic int 964203288Srnolandbcmfb_puts(video_adapter_t *adp, vm_offset_t off, u_int16_t *s, int len) 965203288Srnoland{ 966203288Srnoland int i; 967203288Srnoland 968203288Srnoland for (i = 0; i < len; i++) 969203288Srnoland bcmfb_putc(adp, off + i, s[i] & 0xff, (s[i] & 0xff00) >> 8); 970203288Srnoland 971203288Srnoland return (0); 972203288Srnoland} 973203288Srnoland 974203288Srnolandstatic int 975203288Srnolandbcmfb_putm(video_adapter_t *adp, int x, int y, uint8_t *pixel_image, 976203288Srnoland uint32_t pixel_mask, int size, int width) 977203288Srnoland{ 978203288Srnoland 979203288Srnoland return (0); 980203288Srnoland} 981203288Srnoland 982203288Srnoland/* 983203288Srnoland * Define a stub keyboard driver in case one hasn't been 984203288Srnoland * compiled into the kernel 985203288Srnoland */ 986203288Srnoland#include <sys/kbio.h> 987203288Srnoland#include <dev/kbd/kbdreg.h> 988203288Srnoland 989203288Srnolandstatic int dummy_kbd_configure(int flags); 990203288Srnoland 991203288Srnolandkeyboard_switch_t bcmdummysw; 992203288Srnoland 993203288Srnolandstatic int 994203288Srnolanddummy_kbd_configure(int flags) 995203288Srnoland{ 996203288Srnoland 997203288Srnoland return (0); 998203288Srnoland} 999203288SrnolandKEYBOARD_DRIVER(bcmdummy, bcmdummysw, dummy_kbd_configure); 1000203288Srnoland