bcm2835_fbd.c revision 245071
1239922Sgonzo/*- 2239922Sgonzo * Copyright (c) 2012 Oleksandr Tymoshenko <gonzo@freebsd.org> 3239922Sgonzo * All rights reserved. 4239922Sgonzo * 5239922Sgonzo * Redistribution and use in source and binary forms, with or without 6239922Sgonzo * modification, are permitted provided that the following conditions 7239922Sgonzo * are met: 8239922Sgonzo * 1. Redistributions of source code must retain the above copyright 9239922Sgonzo * notice, this list of conditions and the following disclaimer. 10239922Sgonzo * 2. Redistributions in binary form must reproduce the above copyright 11239922Sgonzo * notice, this list of conditions and the following disclaimer in the 12239922Sgonzo * documentation and/or other materials provided with the distribution. 13239922Sgonzo * 14239922Sgonzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15239922Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16239922Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17239922Sgonzo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18239922Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19239922Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20239922Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21239922Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22239922Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23239922Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24239922Sgonzo * SUCH DAMAGE. 25239922Sgonzo * 26239922Sgonzo */ 27239922Sgonzo#include <sys/cdefs.h> 28239922Sgonzo__FBSDID("$FreeBSD: head/sys/arm/broadcom/bcm2835/bcm2835_fb.c 245071 2013-01-05 21:05:16Z gonzo $"); 29239922Sgonzo 30239922Sgonzo#include <sys/param.h> 31239922Sgonzo#include <sys/systm.h> 32239922Sgonzo#include <sys/bio.h> 33239922Sgonzo#include <sys/bus.h> 34239922Sgonzo#include <sys/conf.h> 35239922Sgonzo#include <sys/endian.h> 36239922Sgonzo#include <sys/kernel.h> 37239922Sgonzo#include <sys/kthread.h> 38239922Sgonzo#include <sys/lock.h> 39239922Sgonzo#include <sys/malloc.h> 40239922Sgonzo#include <sys/module.h> 41239922Sgonzo#include <sys/mutex.h> 42239922Sgonzo#include <sys/queue.h> 43239922Sgonzo#include <sys/resource.h> 44239922Sgonzo#include <sys/rman.h> 45239922Sgonzo#include <sys/time.h> 46239922Sgonzo#include <sys/timetc.h> 47239922Sgonzo#include <sys/fbio.h> 48239922Sgonzo#include <sys/consio.h> 49239922Sgonzo 50239922Sgonzo#include <sys/kdb.h> 51239922Sgonzo 52239922Sgonzo#include <machine/bus.h> 53239922Sgonzo#include <machine/cpu.h> 54239922Sgonzo#include <machine/cpufunc.h> 55239922Sgonzo#include <machine/resource.h> 56239922Sgonzo#include <machine/frame.h> 57239922Sgonzo#include <machine/intr.h> 58239922Sgonzo 59239922Sgonzo#include <dev/fdt/fdt_common.h> 60239922Sgonzo#include <dev/ofw/ofw_bus.h> 61239922Sgonzo#include <dev/ofw/ofw_bus_subr.h> 62239922Sgonzo 63239922Sgonzo#include <dev/fb/fbreg.h> 64239922Sgonzo#include <dev/syscons/syscons.h> 65239922Sgonzo 66239922Sgonzo#include <arm/broadcom/bcm2835/bcm2835_mbox.h> 67239922Sgonzo#include <arm/broadcom/bcm2835/bcm2835_vcbus.h> 68239922Sgonzo 69239922Sgonzo#define BCMFB_FONT_HEIGHT 16 70239922Sgonzo 71243423Sgonzostruct argb { 72243423Sgonzo uint8_t a; 73243423Sgonzo uint8_t r; 74243423Sgonzo uint8_t g; 75243423Sgonzo uint8_t b; 76243423Sgonzo}; 77243423Sgonzo 78243423Sgonzostatic struct argb bcmfb_palette[16] = { 79243423Sgonzo {0x00, 0x00, 0x00, 0x00}, 80243423Sgonzo {0x00, 0x00, 0x00, 0xaa}, 81243423Sgonzo {0x00, 0x00, 0xaa, 0x00}, 82243423Sgonzo {0x00, 0x00, 0xaa, 0xaa}, 83243423Sgonzo {0x00, 0xaa, 0x00, 0x00}, 84243423Sgonzo {0x00, 0xaa, 0x00, 0xaa}, 85243423Sgonzo {0x00, 0xaa, 0x55, 0x00}, 86243423Sgonzo {0x00, 0xaa, 0xaa, 0xaa}, 87243423Sgonzo {0x00, 0x55, 0x55, 0x55}, 88243423Sgonzo {0x00, 0x55, 0x55, 0xff}, 89243423Sgonzo {0x00, 0x55, 0xff, 0x55}, 90243423Sgonzo {0x00, 0x55, 0xff, 0xff}, 91243423Sgonzo {0x00, 0xff, 0x55, 0x55}, 92243423Sgonzo {0x00, 0xff, 0x55, 0xff}, 93243423Sgonzo {0x00, 0xff, 0xff, 0x55}, 94243423Sgonzo {0x00, 0xff, 0xff, 0xff} 95243423Sgonzo}; 96243423Sgonzo 97244762Sgonzo/* mouse pointer from dev/syscons/scgfbrndr.c */ 98244762Sgonzostatic u_char mouse_pointer[16] = { 99244762Sgonzo 0x00, 0x40, 0x60, 0x70, 0x78, 0x7c, 0x7e, 0x68, 100244762Sgonzo 0x0c, 0x0c, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00 101244762Sgonzo}; 102244762Sgonzo 103239922Sgonzo#define FB_WIDTH 640 104239922Sgonzo#define FB_HEIGHT 480 105243423Sgonzo#define FB_DEPTH 24 106239922Sgonzo 107239922Sgonzostruct bcm_fb_config { 108239922Sgonzo uint32_t xres; 109239922Sgonzo uint32_t yres; 110239922Sgonzo uint32_t vxres; 111239922Sgonzo uint32_t vyres; 112239922Sgonzo uint32_t pitch; 113239922Sgonzo uint32_t bpp; 114239922Sgonzo uint32_t xoffset; 115239922Sgonzo uint32_t yoffset; 116239922Sgonzo /* Filled by videocore */ 117239922Sgonzo uint32_t base; 118239922Sgonzo uint32_t screen_size; 119239922Sgonzo}; 120239922Sgonzo 121239922Sgonzostruct bcmsc_softc { 122239922Sgonzo device_t dev; 123239922Sgonzo struct cdev * cdev; 124239922Sgonzo struct mtx mtx; 125239922Sgonzo bus_dma_tag_t dma_tag; 126239922Sgonzo bus_dmamap_t dma_map; 127239922Sgonzo struct bcm_fb_config* fb_config; 128239922Sgonzo bus_addr_t fb_config_phys; 129239922Sgonzo struct intr_config_hook init_hook; 130239922Sgonzo 131239922Sgonzo}; 132239922Sgonzo 133239922Sgonzostruct video_adapter_softc { 134239922Sgonzo /* Videoadpater part */ 135239922Sgonzo video_adapter_t va; 136239922Sgonzo int console; 137239922Sgonzo 138239922Sgonzo intptr_t fb_addr; 139239922Sgonzo unsigned int fb_size; 140239922Sgonzo 141239922Sgonzo unsigned int height; 142239922Sgonzo unsigned int width; 143243423Sgonzo unsigned int depth; 144239922Sgonzo unsigned int stride; 145239922Sgonzo 146239922Sgonzo unsigned int xmargin; 147239922Sgonzo unsigned int ymargin; 148239922Sgonzo 149239922Sgonzo unsigned char *font; 150239922Sgonzo int initialized; 151239922Sgonzo}; 152239922Sgonzo 153239922Sgonzostatic struct bcmsc_softc *bcmsc_softc; 154239922Sgonzostatic struct video_adapter_softc va_softc; 155239922Sgonzo 156239922Sgonzo#define bcm_fb_lock(_sc) mtx_lock(&(_sc)->mtx) 157239922Sgonzo#define bcm_fb_unlock(_sc) mtx_unlock(&(_sc)->mtx) 158239922Sgonzo#define bcm_fb_lock_assert(sc) mtx_assert(&(_sc)->mtx, MA_OWNED) 159239922Sgonzo 160239922Sgonzostatic int bcm_fb_probe(device_t); 161239922Sgonzostatic int bcm_fb_attach(device_t); 162239922Sgonzostatic void bcm_fb_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err); 163243423Sgonzostatic void bcmfb_update_margins(video_adapter_t *adp); 164243423Sgonzostatic int bcmfb_configure(int); 165239922Sgonzo 166239922Sgonzostatic void 167239922Sgonzobcm_fb_init(void *arg) 168239922Sgonzo{ 169239922Sgonzo struct bcmsc_softc *sc = arg; 170239922Sgonzo struct video_adapter_softc *va_sc = &va_softc; 171239922Sgonzo int err; 172239922Sgonzo volatile struct bcm_fb_config* fb_config = sc->fb_config; 173243423Sgonzo phandle_t node; 174243423Sgonzo pcell_t cell; 175239922Sgonzo 176243423Sgonzo node = ofw_bus_get_node(sc->dev); 177243423Sgonzo 178243423Sgonzo fb_config->xres = 0; 179243423Sgonzo fb_config->yres = 0; 180243423Sgonzo fb_config->bpp = 0; 181243423Sgonzo 182243423Sgonzo if ((OF_getprop(node, "broadcom,width", &cell, sizeof(cell))) > 0) 183243423Sgonzo fb_config->xres = (int)fdt32_to_cpu(cell); 184243423Sgonzo if (fb_config->xres == 0) 185243423Sgonzo fb_config->xres = FB_WIDTH; 186243423Sgonzo 187243423Sgonzo if ((OF_getprop(node, "broadcom,height", &cell, sizeof(cell))) > 0) 188243423Sgonzo fb_config->yres = (uint32_t)fdt32_to_cpu(cell); 189243423Sgonzo if (fb_config->yres == 0) 190243423Sgonzo fb_config->yres = FB_HEIGHT; 191243423Sgonzo 192243423Sgonzo if ((OF_getprop(node, "broadcom,depth", &cell, sizeof(cell))) > 0) 193243423Sgonzo fb_config->bpp = (uint32_t)fdt32_to_cpu(cell); 194243423Sgonzo if (fb_config->bpp == 0) 195243423Sgonzo fb_config->bpp = FB_DEPTH; 196243423Sgonzo 197239922Sgonzo fb_config->vxres = 0; 198239922Sgonzo fb_config->vyres = 0; 199239922Sgonzo fb_config->xoffset = 0; 200239922Sgonzo fb_config->yoffset = 0; 201239922Sgonzo fb_config->base = 0; 202239922Sgonzo fb_config->pitch = 0; 203239922Sgonzo fb_config->screen_size = 0; 204239922Sgonzo 205239922Sgonzo bus_dmamap_sync(sc->dma_tag, sc->dma_map, 206239922Sgonzo BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); 207239922Sgonzo bcm_mbox_write(BCM2835_MBOX_CHAN_FB, sc->fb_config_phys); 208239922Sgonzo bcm_mbox_read(BCM2835_MBOX_CHAN_FB, &err); 209239922Sgonzo bus_dmamap_sync(sc->dma_tag, sc->dma_map, 210239922Sgonzo BUS_DMASYNC_POSTREAD); 211239922Sgonzo 212243423Sgonzo if (fb_config->base != 0) { 213239922Sgonzo device_printf(sc->dev, "%dx%d(%dx%d@%d,%d) %dbpp\n", 214239922Sgonzo fb_config->xres, fb_config->yres, 215239922Sgonzo fb_config->vxres, fb_config->vyres, 216239922Sgonzo fb_config->xoffset, fb_config->yoffset, 217239922Sgonzo fb_config->bpp); 218239922Sgonzo 219239922Sgonzo 220239922Sgonzo device_printf(sc->dev, "pitch %d, base 0x%08x, screen_size %d\n", 221239922Sgonzo fb_config->pitch, fb_config->base, 222239922Sgonzo fb_config->screen_size); 223239922Sgonzo 224243423Sgonzo va_sc->fb_addr = (intptr_t)pmap_mapdev(fb_config->base, fb_config->screen_size); 225243423Sgonzo va_sc->fb_size = fb_config->screen_size; 226243423Sgonzo va_sc->depth = fb_config->bpp; 227243423Sgonzo va_sc->stride = fb_config->pitch; 228243423Sgonzo 229243423Sgonzo va_sc->width = fb_config->xres; 230243423Sgonzo va_sc->height = fb_config->yres; 231243423Sgonzo bcmfb_update_margins(&va_sc->va); 232239922Sgonzo } 233243423Sgonzo else { 234239922Sgonzo device_printf(sc->dev, "Failed to set framebuffer info\n"); 235243423Sgonzo return; 236243423Sgonzo } 237239922Sgonzo 238239922Sgonzo config_intrhook_disestablish(&sc->init_hook); 239239922Sgonzo} 240239922Sgonzo 241239922Sgonzostatic int 242239922Sgonzobcm_fb_probe(device_t dev) 243239922Sgonzo{ 244243423Sgonzo int error = 0; 245239922Sgonzo 246239922Sgonzo if (!ofw_bus_is_compatible(dev, "broadcom,bcm2835-fb")) 247239922Sgonzo return (ENXIO); 248239922Sgonzo 249239922Sgonzo device_set_desc(dev, "BCM2835 framebuffer device"); 250239922Sgonzo 251239922Sgonzo error = sc_probe_unit(device_get_unit(dev), 252239922Sgonzo device_get_flags(dev) | SC_AUTODETECT_KBD); 253239922Sgonzo if (error != 0) 254239922Sgonzo return (error); 255239922Sgonzo 256243423Sgonzo 257239922Sgonzo return (BUS_PROBE_DEFAULT); 258239922Sgonzo} 259239922Sgonzo 260239922Sgonzostatic int 261239922Sgonzobcm_fb_attach(device_t dev) 262239922Sgonzo{ 263239922Sgonzo struct bcmsc_softc *sc = device_get_softc(dev); 264239922Sgonzo int dma_size = sizeof(struct bcm_fb_config); 265239922Sgonzo int err; 266239922Sgonzo 267239922Sgonzo if (bcmsc_softc) 268239922Sgonzo return (ENXIO); 269239922Sgonzo 270239922Sgonzo bcmsc_softc = sc; 271239922Sgonzo 272239922Sgonzo sc->dev = dev; 273239922Sgonzo mtx_init(&sc->mtx, "bcm2835fb", "fb", MTX_DEF); 274239922Sgonzo 275239922Sgonzo err = bus_dma_tag_create( 276239922Sgonzo bus_get_dma_tag(sc->dev), 277239922Sgonzo PAGE_SIZE, 0, /* alignment, boundary */ 278239922Sgonzo BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 279239922Sgonzo BUS_SPACE_MAXADDR, /* highaddr */ 280239922Sgonzo NULL, NULL, /* filter, filterarg */ 281239922Sgonzo dma_size, 1, /* maxsize, nsegments */ 282239922Sgonzo dma_size, 0, /* maxsegsize, flags */ 283239922Sgonzo NULL, NULL, /* lockfunc, lockarg */ 284239922Sgonzo &sc->dma_tag); 285239922Sgonzo 286239922Sgonzo err = bus_dmamem_alloc(sc->dma_tag, (void **)&sc->fb_config, 287239922Sgonzo 0, &sc->dma_map); 288239922Sgonzo if (err) { 289239922Sgonzo device_printf(dev, "cannot allocate framebuffer\n"); 290239922Sgonzo goto fail; 291239922Sgonzo } 292239922Sgonzo 293239922Sgonzo err = bus_dmamap_load(sc->dma_tag, sc->dma_map, sc->fb_config, 294239922Sgonzo dma_size, bcm_fb_dmamap_cb, &sc->fb_config_phys, BUS_DMA_NOWAIT); 295239922Sgonzo 296239922Sgonzo if (err) { 297239922Sgonzo device_printf(dev, "cannot load DMA map\n"); 298239922Sgonzo goto fail; 299239922Sgonzo } 300239922Sgonzo 301239922Sgonzo err = (sc_attach_unit(device_get_unit(dev), 302239922Sgonzo device_get_flags(dev) | SC_AUTODETECT_KBD)); 303239922Sgonzo 304239922Sgonzo if (err) { 305239922Sgonzo device_printf(dev, "failed to attach syscons\n"); 306239922Sgonzo goto fail; 307239922Sgonzo } 308239922Sgonzo 309239922Sgonzo /* 310239922Sgonzo * We have to wait until interrupts are enabled. 311239922Sgonzo * Mailbox relies on it to get data from VideoCore 312239922Sgonzo */ 313239922Sgonzo sc->init_hook.ich_func = bcm_fb_init; 314239922Sgonzo sc->init_hook.ich_arg = sc; 315239922Sgonzo 316239922Sgonzo if (config_intrhook_establish(&sc->init_hook) != 0) { 317239922Sgonzo device_printf(dev, "failed to establish intrhook\n"); 318239922Sgonzo return (ENOMEM); 319239922Sgonzo } 320239922Sgonzo 321239922Sgonzo return (0); 322239922Sgonzo 323239922Sgonzofail: 324239922Sgonzo return (ENXIO); 325239922Sgonzo} 326239922Sgonzo 327239922Sgonzo 328239922Sgonzostatic void 329239922Sgonzobcm_fb_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err) 330239922Sgonzo{ 331239922Sgonzo bus_addr_t *addr; 332239922Sgonzo 333239922Sgonzo if (err) 334239922Sgonzo return; 335239922Sgonzo 336239922Sgonzo addr = (bus_addr_t*)arg; 337239922Sgonzo *addr = PHYS_TO_VCBUS(segs[0].ds_addr); 338239922Sgonzo} 339239922Sgonzo 340239922Sgonzostatic device_method_t bcm_fb_methods[] = { 341239922Sgonzo /* Device interface */ 342239922Sgonzo DEVMETHOD(device_probe, bcm_fb_probe), 343239922Sgonzo DEVMETHOD(device_attach, bcm_fb_attach), 344239922Sgonzo 345239922Sgonzo { 0, 0 } 346239922Sgonzo}; 347239922Sgonzo 348239922Sgonzostatic devclass_t bcm_fb_devclass; 349239922Sgonzo 350239922Sgonzostatic driver_t bcm_fb_driver = { 351239922Sgonzo "fb", 352239922Sgonzo bcm_fb_methods, 353239922Sgonzo sizeof(struct bcmsc_softc), 354239922Sgonzo}; 355239922Sgonzo 356243423SgonzoDRIVER_MODULE(bcm2835fb, fdtbus, bcm_fb_driver, bcm_fb_devclass, 0, 0); 357239922Sgonzo 358239922Sgonzo/* 359239922Sgonzo * Video driver routines and glue. 360239922Sgonzo */ 361239922Sgonzostatic vi_probe_t bcmfb_probe; 362239922Sgonzostatic vi_init_t bcmfb_init; 363239922Sgonzostatic vi_get_info_t bcmfb_get_info; 364239922Sgonzostatic vi_query_mode_t bcmfb_query_mode; 365239922Sgonzostatic vi_set_mode_t bcmfb_set_mode; 366239922Sgonzostatic vi_save_font_t bcmfb_save_font; 367239922Sgonzostatic vi_load_font_t bcmfb_load_font; 368239922Sgonzostatic vi_show_font_t bcmfb_show_font; 369239922Sgonzostatic vi_save_palette_t bcmfb_save_palette; 370239922Sgonzostatic vi_load_palette_t bcmfb_load_palette; 371239922Sgonzostatic vi_set_border_t bcmfb_set_border; 372239922Sgonzostatic vi_save_state_t bcmfb_save_state; 373239922Sgonzostatic vi_load_state_t bcmfb_load_state; 374239922Sgonzostatic vi_set_win_org_t bcmfb_set_win_org; 375239922Sgonzostatic vi_read_hw_cursor_t bcmfb_read_hw_cursor; 376239922Sgonzostatic vi_set_hw_cursor_t bcmfb_set_hw_cursor; 377239922Sgonzostatic vi_set_hw_cursor_shape_t bcmfb_set_hw_cursor_shape; 378239922Sgonzostatic vi_blank_display_t bcmfb_blank_display; 379239922Sgonzostatic vi_mmap_t bcmfb_mmap; 380239922Sgonzostatic vi_ioctl_t bcmfb_ioctl; 381239922Sgonzostatic vi_clear_t bcmfb_clear; 382239922Sgonzostatic vi_fill_rect_t bcmfb_fill_rect; 383239922Sgonzostatic vi_bitblt_t bcmfb_bitblt; 384239922Sgonzostatic vi_diag_t bcmfb_diag; 385239922Sgonzostatic vi_save_cursor_palette_t bcmfb_save_cursor_palette; 386239922Sgonzostatic vi_load_cursor_palette_t bcmfb_load_cursor_palette; 387239922Sgonzostatic vi_copy_t bcmfb_copy; 388239922Sgonzostatic vi_putp_t bcmfb_putp; 389239922Sgonzostatic vi_putc_t bcmfb_putc; 390239922Sgonzostatic vi_puts_t bcmfb_puts; 391239922Sgonzostatic vi_putm_t bcmfb_putm; 392239922Sgonzo 393239922Sgonzostatic video_switch_t bcmfbvidsw = { 394239922Sgonzo .probe = bcmfb_probe, 395239922Sgonzo .init = bcmfb_init, 396239922Sgonzo .get_info = bcmfb_get_info, 397239922Sgonzo .query_mode = bcmfb_query_mode, 398239922Sgonzo .set_mode = bcmfb_set_mode, 399239922Sgonzo .save_font = bcmfb_save_font, 400239922Sgonzo .load_font = bcmfb_load_font, 401239922Sgonzo .show_font = bcmfb_show_font, 402239922Sgonzo .save_palette = bcmfb_save_palette, 403239922Sgonzo .load_palette = bcmfb_load_palette, 404239922Sgonzo .set_border = bcmfb_set_border, 405239922Sgonzo .save_state = bcmfb_save_state, 406239922Sgonzo .load_state = bcmfb_load_state, 407239922Sgonzo .set_win_org = bcmfb_set_win_org, 408239922Sgonzo .read_hw_cursor = bcmfb_read_hw_cursor, 409239922Sgonzo .set_hw_cursor = bcmfb_set_hw_cursor, 410239922Sgonzo .set_hw_cursor_shape = bcmfb_set_hw_cursor_shape, 411239922Sgonzo .blank_display = bcmfb_blank_display, 412239922Sgonzo .mmap = bcmfb_mmap, 413239922Sgonzo .ioctl = bcmfb_ioctl, 414239922Sgonzo .clear = bcmfb_clear, 415239922Sgonzo .fill_rect = bcmfb_fill_rect, 416239922Sgonzo .bitblt = bcmfb_bitblt, 417239922Sgonzo .diag = bcmfb_diag, 418239922Sgonzo .save_cursor_palette = bcmfb_save_cursor_palette, 419239922Sgonzo .load_cursor_palette = bcmfb_load_cursor_palette, 420239922Sgonzo .copy = bcmfb_copy, 421239922Sgonzo .putp = bcmfb_putp, 422239922Sgonzo .putc = bcmfb_putc, 423239922Sgonzo .puts = bcmfb_puts, 424239922Sgonzo .putm = bcmfb_putm, 425239922Sgonzo}; 426239922Sgonzo 427239922SgonzoVIDEO_DRIVER(bcmfb, bcmfbvidsw, bcmfb_configure); 428239922Sgonzo 429244762Sgonzostatic vr_init_t bcmrend_init; 430244762Sgonzostatic vr_clear_t bcmrend_clear; 431244762Sgonzostatic vr_draw_border_t bcmrend_draw_border; 432244762Sgonzostatic vr_draw_t bcmrend_draw; 433244762Sgonzostatic vr_set_cursor_t bcmrend_set_cursor; 434244762Sgonzostatic vr_draw_cursor_t bcmrend_draw_cursor; 435244762Sgonzostatic vr_blink_cursor_t bcmrend_blink_cursor; 436244762Sgonzostatic vr_set_mouse_t bcmrend_set_mouse; 437244762Sgonzostatic vr_draw_mouse_t bcmrend_draw_mouse; 438244762Sgonzo 439244762Sgonzo/* 440244762Sgonzo * We use our own renderer; this is because we must emulate a hardware 441244762Sgonzo * cursor. 442244762Sgonzo */ 443244762Sgonzostatic sc_rndr_sw_t bcmrend = { 444244762Sgonzo bcmrend_init, 445244762Sgonzo bcmrend_clear, 446244762Sgonzo bcmrend_draw_border, 447244762Sgonzo bcmrend_draw, 448244762Sgonzo bcmrend_set_cursor, 449244762Sgonzo bcmrend_draw_cursor, 450244762Sgonzo bcmrend_blink_cursor, 451244762Sgonzo bcmrend_set_mouse, 452244762Sgonzo bcmrend_draw_mouse 453244762Sgonzo}; 454244762Sgonzo 455244762SgonzoRENDERER(bcmfb, 0, bcmrend, gfb_set); 456239922SgonzoRENDERER_MODULE(bcmfb, gfb_set); 457239922Sgonzo 458244762Sgonzostatic void 459244762Sgonzobcmrend_init(scr_stat* scp) 460244762Sgonzo{ 461244762Sgonzo} 462244762Sgonzo 463244762Sgonzostatic void 464244762Sgonzobcmrend_clear(scr_stat* scp, int c, int attr) 465244762Sgonzo{ 466244762Sgonzo} 467244762Sgonzo 468244762Sgonzostatic void 469244762Sgonzobcmrend_draw_border(scr_stat* scp, int color) 470244762Sgonzo{ 471244762Sgonzo} 472244762Sgonzo 473244762Sgonzostatic void 474244762Sgonzobcmrend_draw(scr_stat* scp, int from, int count, int flip) 475244762Sgonzo{ 476244762Sgonzo video_adapter_t* adp = scp->sc->adp; 477244762Sgonzo int i, c, a; 478244762Sgonzo 479244762Sgonzo if (!flip) { 480244762Sgonzo /* Normal printing */ 481244762Sgonzo vidd_puts(adp, from, (uint16_t*)sc_vtb_pointer(&scp->vtb, from), count); 482244762Sgonzo } else { 483244762Sgonzo /* This is for selections and such: invert the color attribute */ 484244762Sgonzo for (i = count; i-- > 0; ++from) { 485244762Sgonzo c = sc_vtb_getc(&scp->vtb, from); 486244762Sgonzo a = sc_vtb_geta(&scp->vtb, from) >> 8; 487244762Sgonzo vidd_putc(adp, from, c, (a >> 4) | ((a & 0xf) << 4)); 488244762Sgonzo } 489244762Sgonzo } 490244762Sgonzo} 491244762Sgonzo 492244762Sgonzostatic void 493244762Sgonzobcmrend_set_cursor(scr_stat* scp, int base, int height, int blink) 494244762Sgonzo{ 495244762Sgonzo} 496244762Sgonzo 497244762Sgonzostatic void 498244762Sgonzobcmrend_draw_cursor(scr_stat* scp, int off, int blink, int on, int flip) 499244762Sgonzo{ 500244762Sgonzo video_adapter_t* adp = scp->sc->adp; 501244762Sgonzo struct video_adapter_softc *sc; 502244762Sgonzo int row, col; 503244762Sgonzo uint8_t *addr; 504244762Sgonzo int i, j, bytes; 505244762Sgonzo 506244762Sgonzo sc = (struct video_adapter_softc *)adp; 507244762Sgonzo 508244762Sgonzo if (scp->curs_attr.height <= 0) 509244762Sgonzo return; 510244762Sgonzo 511244762Sgonzo if (sc->fb_addr == 0) 512244762Sgonzo return; 513244762Sgonzo 514244762Sgonzo if (off >= adp->va_info.vi_width * adp->va_info.vi_height) 515244762Sgonzo return; 516244762Sgonzo 517244762Sgonzo /* calculate the coordinates in the video buffer */ 518244762Sgonzo row = (off / adp->va_info.vi_width) * adp->va_info.vi_cheight; 519244762Sgonzo col = (off % adp->va_info.vi_width) * adp->va_info.vi_cwidth; 520244762Sgonzo 521244762Sgonzo addr = (uint8_t *)sc->fb_addr 522244762Sgonzo + (row + sc->ymargin)*(sc->stride) 523244762Sgonzo + (sc->depth/8) * (col + sc->xmargin); 524244762Sgonzo 525244762Sgonzo bytes = sc->depth/8; 526244762Sgonzo 527244762Sgonzo /* our cursor consists of simply inverting the char under it */ 528244762Sgonzo for (i = 0; i < adp->va_info.vi_cheight; i++) { 529244762Sgonzo for (j = 0; j < adp->va_info.vi_cwidth; j++) { 530244762Sgonzo switch (sc->depth) { 531244762Sgonzo case 32: 532244762Sgonzo case 24: 533244762Sgonzo addr[bytes*j + 2] ^= 0xff; 534244762Sgonzo /* FALLTHROUGH */ 535244762Sgonzo case 16: 536244762Sgonzo addr[bytes*j + 1] ^= 0xff; 537244762Sgonzo addr[bytes*j] ^= 0xff; 538244762Sgonzo break; 539244762Sgonzo default: 540244762Sgonzo break; 541244762Sgonzo } 542244762Sgonzo } 543244762Sgonzo 544244762Sgonzo addr += sc->stride; 545244762Sgonzo } 546244762Sgonzo} 547244762Sgonzo 548244762Sgonzostatic void 549244762Sgonzobcmrend_blink_cursor(scr_stat* scp, int at, int flip) 550244762Sgonzo{ 551244762Sgonzo} 552244762Sgonzo 553244762Sgonzostatic void 554244762Sgonzobcmrend_set_mouse(scr_stat* scp) 555244762Sgonzo{ 556244762Sgonzo} 557244762Sgonzo 558244762Sgonzostatic void 559244762Sgonzobcmrend_draw_mouse(scr_stat* scp, int x, int y, int on) 560244762Sgonzo{ 561244762Sgonzo vidd_putm(scp->sc->adp, x, y, mouse_pointer, 0xffffffff, 16, 8); 562244762Sgonzo} 563244762Sgonzo 564239922Sgonzostatic uint16_t bcmfb_static_window[ROW*COL]; 565239922Sgonzoextern u_char dflt_font_16[]; 566239922Sgonzo 567243423Sgonzo/* 568243423Sgonzo * Update videoadapter settings after changing resolution 569243423Sgonzo */ 570243423Sgonzostatic void 571243423Sgonzobcmfb_update_margins(video_adapter_t *adp) 572243423Sgonzo{ 573243423Sgonzo struct video_adapter_softc *sc; 574243423Sgonzo video_info_t *vi; 575243423Sgonzo 576243423Sgonzo sc = (struct video_adapter_softc *)adp; 577243423Sgonzo vi = &adp->va_info; 578243423Sgonzo 579243423Sgonzo sc->xmargin = (sc->width - (vi->vi_width * vi->vi_cwidth)) / 2; 580243423Sgonzo sc->ymargin = (sc->height - (vi->vi_height * vi->vi_cheight))/2; 581243423Sgonzo} 582243423Sgonzo 583239922Sgonzostatic int 584239922Sgonzobcmfb_configure(int flags) 585239922Sgonzo{ 586243423Sgonzo struct video_adapter_softc *va_sc; 587239922Sgonzo 588243423Sgonzo va_sc = &va_softc; 589243423Sgonzo phandle_t display, root; 590243423Sgonzo pcell_t cell; 591239922Sgonzo 592243423Sgonzo if (va_sc->initialized) 593243423Sgonzo return (0); 594239922Sgonzo 595243423Sgonzo va_sc->width = 0; 596243423Sgonzo va_sc->height = 0; 597239922Sgonzo 598243423Sgonzo /* 599243423Sgonzo * It seems there is no way to let syscons framework know 600243423Sgonzo * that framebuffer resolution has changed. So just try 601243423Sgonzo * to fetch data from FDT and go with defaults if failed 602243423Sgonzo */ 603243423Sgonzo root = OF_finddevice("/"); 604243423Sgonzo if ((root != 0) && 605243423Sgonzo (display = fdt_find_compatible(root, "broadcom,bcm2835-fb", 1))) { 606243423Sgonzo if ((OF_getprop(display, "broadcom,width", 607243423Sgonzo &cell, sizeof(cell))) > 0) 608243423Sgonzo va_sc->width = (int)fdt32_to_cpu(cell); 609239922Sgonzo 610243423Sgonzo if ((OF_getprop(display, "broadcom,height", 611243423Sgonzo &cell, sizeof(cell))) > 0) 612243423Sgonzo va_sc->height = (int)fdt32_to_cpu(cell); 613243423Sgonzo } 614239922Sgonzo 615243423Sgonzo if (va_sc->width == 0) 616243423Sgonzo va_sc->width = FB_WIDTH; 617243423Sgonzo if (va_sc->height == 0) 618243423Sgonzo va_sc->height = FB_HEIGHT; 619243423Sgonzo 620243423Sgonzo bcmfb_init(0, &va_sc->va, 0); 621243423Sgonzo 622243423Sgonzo va_sc->initialized = 1; 623243423Sgonzo 624239922Sgonzo return (0); 625239922Sgonzo} 626239922Sgonzo 627239922Sgonzostatic int 628239922Sgonzobcmfb_probe(int unit, video_adapter_t **adp, void *arg, int flags) 629239922Sgonzo{ 630239922Sgonzo 631239922Sgonzo return (0); 632239922Sgonzo} 633239922Sgonzo 634239922Sgonzostatic int 635239922Sgonzobcmfb_init(int unit, video_adapter_t *adp, int flags) 636239922Sgonzo{ 637239922Sgonzo struct video_adapter_softc *sc; 638239922Sgonzo video_info_t *vi; 639239922Sgonzo 640239922Sgonzo sc = (struct video_adapter_softc *)adp; 641239922Sgonzo vi = &adp->va_info; 642239922Sgonzo 643239922Sgonzo vid_init_struct(adp, "bcmfb", -1, unit); 644239922Sgonzo 645239922Sgonzo sc->font = dflt_font_16; 646239922Sgonzo vi->vi_cheight = BCMFB_FONT_HEIGHT; 647239922Sgonzo vi->vi_cwidth = 8; 648243423Sgonzo 649239922Sgonzo vi->vi_width = sc->width/8; 650239922Sgonzo vi->vi_height = sc->height/vi->vi_cheight; 651239922Sgonzo 652239922Sgonzo /* 653239922Sgonzo * Clamp width/height to syscons maximums 654239922Sgonzo */ 655239922Sgonzo if (vi->vi_width > COL) 656239922Sgonzo vi->vi_width = COL; 657239922Sgonzo if (vi->vi_height > ROW) 658239922Sgonzo vi->vi_height = ROW; 659239922Sgonzo 660239922Sgonzo sc->xmargin = (sc->width - (vi->vi_width * vi->vi_cwidth)) / 2; 661239922Sgonzo sc->ymargin = (sc->height - (vi->vi_height * vi->vi_cheight))/2; 662239922Sgonzo 663243423Sgonzo 664239922Sgonzo adp->va_window = (vm_offset_t) bcmfb_static_window; 665239922Sgonzo adp->va_flags |= V_ADP_FONT /* | V_ADP_COLOR | V_ADP_MODECHANGE */; 666239922Sgonzo 667239922Sgonzo vid_register(&sc->va); 668239922Sgonzo 669239922Sgonzo return (0); 670239922Sgonzo} 671239922Sgonzo 672239922Sgonzostatic int 673239922Sgonzobcmfb_get_info(video_adapter_t *adp, int mode, video_info_t *info) 674239922Sgonzo{ 675239922Sgonzo bcopy(&adp->va_info, info, sizeof(*info)); 676239922Sgonzo return (0); 677239922Sgonzo} 678239922Sgonzo 679239922Sgonzostatic int 680239922Sgonzobcmfb_query_mode(video_adapter_t *adp, video_info_t *info) 681239922Sgonzo{ 682239922Sgonzo return (0); 683239922Sgonzo} 684239922Sgonzo 685239922Sgonzostatic int 686239922Sgonzobcmfb_set_mode(video_adapter_t *adp, int mode) 687239922Sgonzo{ 688239922Sgonzo return (0); 689239922Sgonzo} 690239922Sgonzo 691239922Sgonzostatic int 692239922Sgonzobcmfb_save_font(video_adapter_t *adp, int page, int size, int width, 693239922Sgonzo u_char *data, int c, int count) 694239922Sgonzo{ 695239922Sgonzo return (0); 696239922Sgonzo} 697239922Sgonzo 698239922Sgonzostatic int 699239922Sgonzobcmfb_load_font(video_adapter_t *adp, int page, int size, int width, 700239922Sgonzo u_char *data, int c, int count) 701239922Sgonzo{ 702239922Sgonzo struct video_adapter_softc *sc = (struct video_adapter_softc *)adp; 703239922Sgonzo 704239922Sgonzo sc->font = data; 705239922Sgonzo 706239922Sgonzo return (0); 707239922Sgonzo} 708239922Sgonzo 709239922Sgonzostatic int 710239922Sgonzobcmfb_show_font(video_adapter_t *adp, int page) 711239922Sgonzo{ 712239922Sgonzo return (0); 713239922Sgonzo} 714239922Sgonzo 715239922Sgonzostatic int 716239922Sgonzobcmfb_save_palette(video_adapter_t *adp, u_char *palette) 717239922Sgonzo{ 718239922Sgonzo return (0); 719239922Sgonzo} 720239922Sgonzo 721239922Sgonzostatic int 722239922Sgonzobcmfb_load_palette(video_adapter_t *adp, u_char *palette) 723239922Sgonzo{ 724239922Sgonzo return (0); 725239922Sgonzo} 726239922Sgonzo 727239922Sgonzostatic int 728239922Sgonzobcmfb_set_border(video_adapter_t *adp, int border) 729239922Sgonzo{ 730239922Sgonzo return (bcmfb_blank_display(adp, border)); 731239922Sgonzo} 732239922Sgonzo 733239922Sgonzostatic int 734239922Sgonzobcmfb_save_state(video_adapter_t *adp, void *p, size_t size) 735239922Sgonzo{ 736239922Sgonzo return (0); 737239922Sgonzo} 738239922Sgonzo 739239922Sgonzostatic int 740239922Sgonzobcmfb_load_state(video_adapter_t *adp, void *p) 741239922Sgonzo{ 742239922Sgonzo return (0); 743239922Sgonzo} 744239922Sgonzo 745239922Sgonzostatic int 746239922Sgonzobcmfb_set_win_org(video_adapter_t *adp, off_t offset) 747239922Sgonzo{ 748239922Sgonzo return (0); 749239922Sgonzo} 750239922Sgonzo 751239922Sgonzostatic int 752239922Sgonzobcmfb_read_hw_cursor(video_adapter_t *adp, int *col, int *row) 753239922Sgonzo{ 754239922Sgonzo *col = *row = 0; 755239922Sgonzo 756239922Sgonzo return (0); 757239922Sgonzo} 758239922Sgonzo 759239922Sgonzostatic int 760239922Sgonzobcmfb_set_hw_cursor(video_adapter_t *adp, int col, int row) 761239922Sgonzo{ 762239922Sgonzo return (0); 763239922Sgonzo} 764239922Sgonzo 765239922Sgonzostatic int 766239922Sgonzobcmfb_set_hw_cursor_shape(video_adapter_t *adp, int base, int height, 767239922Sgonzo int celsize, int blink) 768239922Sgonzo{ 769239922Sgonzo return (0); 770239922Sgonzo} 771239922Sgonzo 772239922Sgonzostatic int 773239922Sgonzobcmfb_blank_display(video_adapter_t *adp, int mode) 774239922Sgonzo{ 775239922Sgonzo 776243423Sgonzo struct video_adapter_softc *sc; 777243423Sgonzo 778243423Sgonzo sc = (struct video_adapter_softc *)adp; 779243423Sgonzo if (sc && sc->fb_addr) 780243423Sgonzo memset((void*)sc->fb_addr, 0, sc->fb_size); 781243423Sgonzo 782239922Sgonzo return (0); 783239922Sgonzo} 784239922Sgonzo 785239922Sgonzostatic int 786239922Sgonzobcmfb_mmap(video_adapter_t *adp, vm_ooffset_t offset, vm_paddr_t *paddr, 787239922Sgonzo int prot, vm_memattr_t *memattr) 788239922Sgonzo{ 789239922Sgonzo struct video_adapter_softc *sc; 790239922Sgonzo 791239922Sgonzo sc = (struct video_adapter_softc *)adp; 792239922Sgonzo 793239922Sgonzo /* 794239922Sgonzo * This might be a legacy VGA mem request: if so, just point it at the 795239922Sgonzo * framebuffer, since it shouldn't be touched 796239922Sgonzo */ 797239922Sgonzo if (offset < sc->stride*sc->height) { 798239922Sgonzo *paddr = sc->fb_addr + offset; 799239922Sgonzo return (0); 800239922Sgonzo } 801239922Sgonzo 802239922Sgonzo return (EINVAL); 803239922Sgonzo} 804239922Sgonzo 805239922Sgonzostatic int 806239922Sgonzobcmfb_ioctl(video_adapter_t *adp, u_long cmd, caddr_t data) 807239922Sgonzo{ 808239922Sgonzo 809239922Sgonzo return (0); 810239922Sgonzo} 811239922Sgonzo 812239922Sgonzostatic int 813239922Sgonzobcmfb_clear(video_adapter_t *adp) 814239922Sgonzo{ 815239922Sgonzo 816239922Sgonzo return (bcmfb_blank_display(adp, 0)); 817239922Sgonzo} 818239922Sgonzo 819239922Sgonzostatic int 820239922Sgonzobcmfb_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy) 821239922Sgonzo{ 822239922Sgonzo 823239922Sgonzo return (0); 824239922Sgonzo} 825239922Sgonzo 826239922Sgonzostatic int 827239922Sgonzobcmfb_bitblt(video_adapter_t *adp, ...) 828239922Sgonzo{ 829239922Sgonzo 830239922Sgonzo return (0); 831239922Sgonzo} 832239922Sgonzo 833239922Sgonzostatic int 834239922Sgonzobcmfb_diag(video_adapter_t *adp, int level) 835239922Sgonzo{ 836239922Sgonzo 837239922Sgonzo return (0); 838239922Sgonzo} 839239922Sgonzo 840239922Sgonzostatic int 841239922Sgonzobcmfb_save_cursor_palette(video_adapter_t *adp, u_char *palette) 842239922Sgonzo{ 843239922Sgonzo 844239922Sgonzo return (0); 845239922Sgonzo} 846239922Sgonzo 847239922Sgonzostatic int 848239922Sgonzobcmfb_load_cursor_palette(video_adapter_t *adp, u_char *palette) 849239922Sgonzo{ 850239922Sgonzo 851239922Sgonzo return (0); 852239922Sgonzo} 853239922Sgonzo 854239922Sgonzostatic int 855239922Sgonzobcmfb_copy(video_adapter_t *adp, vm_offset_t src, vm_offset_t dst, int n) 856239922Sgonzo{ 857239922Sgonzo 858239922Sgonzo return (0); 859239922Sgonzo} 860239922Sgonzo 861239922Sgonzostatic int 862239922Sgonzobcmfb_putp(video_adapter_t *adp, vm_offset_t off, uint32_t p, uint32_t a, 863239922Sgonzo int size, int bpp, int bit_ltor, int byte_ltor) 864239922Sgonzo{ 865239922Sgonzo 866239922Sgonzo return (0); 867239922Sgonzo} 868239922Sgonzo 869239922Sgonzostatic int 870239922Sgonzobcmfb_putc(video_adapter_t *adp, vm_offset_t off, uint8_t c, uint8_t a) 871239922Sgonzo{ 872239922Sgonzo struct video_adapter_softc *sc; 873239922Sgonzo int row; 874239922Sgonzo int col; 875239922Sgonzo int i, j, k; 876239922Sgonzo uint8_t *addr; 877239922Sgonzo u_char *p; 878239922Sgonzo uint8_t fg, bg, color; 879243423Sgonzo uint16_t rgb; 880239922Sgonzo 881239922Sgonzo sc = (struct video_adapter_softc *)adp; 882239922Sgonzo 883239922Sgonzo if (sc->fb_addr == 0) 884239922Sgonzo return (0); 885239922Sgonzo 886239922Sgonzo row = (off / adp->va_info.vi_width) * adp->va_info.vi_cheight; 887239922Sgonzo col = (off % adp->va_info.vi_width) * adp->va_info.vi_cwidth; 888239922Sgonzo p = sc->font + c*BCMFB_FONT_HEIGHT; 889239922Sgonzo addr = (uint8_t *)sc->fb_addr 890239922Sgonzo + (row + sc->ymargin)*(sc->stride) 891243666Sgonzo + (sc->depth/8) * (col + sc->xmargin); 892239922Sgonzo 893243423Sgonzo fg = a & 0xf ; 894245071Sgonzo bg = (a >> 4) & 0xf; 895239922Sgonzo 896239922Sgonzo for (i = 0; i < BCMFB_FONT_HEIGHT; i++) { 897239922Sgonzo for (j = 0, k = 7; j < 8; j++, k--) { 898239922Sgonzo if ((p[i] & (1 << k)) == 0) 899239922Sgonzo color = bg; 900239922Sgonzo else 901239922Sgonzo color = fg; 902239922Sgonzo 903243423Sgonzo switch (sc->depth) { 904243423Sgonzo case 32: 905243423Sgonzo addr[4*j+0] = bcmfb_palette[color].r; 906243423Sgonzo addr[4*j+1] = bcmfb_palette[color].g; 907243423Sgonzo addr[4*j+2] = bcmfb_palette[color].b; 908243423Sgonzo addr[4*j+3] = bcmfb_palette[color].a; 909243423Sgonzo break; 910243423Sgonzo case 24: 911243423Sgonzo addr[3*j] = bcmfb_palette[color].r; 912243423Sgonzo addr[3*j+1] = bcmfb_palette[color].g; 913243423Sgonzo addr[3*j+2] = bcmfb_palette[color].b; 914243423Sgonzo break; 915243423Sgonzo case 16: 916243687Sgonzo rgb = (bcmfb_palette[color].r >> 3) << 11; 917243687Sgonzo rgb |= (bcmfb_palette[color].g >> 2) << 5; 918243423Sgonzo rgb |= (bcmfb_palette[color].b >> 3); 919243687Sgonzo addr[2*j] = rgb & 0xff; 920243687Sgonzo addr[2*j + 1] = (rgb >> 8) & 0xff; 921243423Sgonzo default: 922243423Sgonzo /* Not supported yet */ 923243423Sgonzo break; 924243423Sgonzo } 925239922Sgonzo } 926239922Sgonzo 927239922Sgonzo addr += (sc->stride); 928239922Sgonzo } 929239922Sgonzo 930239922Sgonzo return (0); 931239922Sgonzo} 932239922Sgonzo 933239922Sgonzostatic int 934239922Sgonzobcmfb_puts(video_adapter_t *adp, vm_offset_t off, u_int16_t *s, int len) 935239922Sgonzo{ 936239922Sgonzo int i; 937239922Sgonzo 938239922Sgonzo for (i = 0; i < len; i++) 939239922Sgonzo bcmfb_putc(adp, off + i, s[i] & 0xff, (s[i] & 0xff00) >> 8); 940239922Sgonzo 941239922Sgonzo return (0); 942239922Sgonzo} 943239922Sgonzo 944239922Sgonzostatic int 945239922Sgonzobcmfb_putm(video_adapter_t *adp, int x, int y, uint8_t *pixel_image, 946239922Sgonzo uint32_t pixel_mask, int size, int width) 947239922Sgonzo{ 948239922Sgonzo 949239922Sgonzo return (0); 950239922Sgonzo} 951239922Sgonzo 952239922Sgonzo/* 953239922Sgonzo * Define a stub keyboard driver in case one hasn't been 954239922Sgonzo * compiled into the kernel 955239922Sgonzo */ 956239922Sgonzo#include <sys/kbio.h> 957239922Sgonzo#include <dev/kbd/kbdreg.h> 958239922Sgonzo 959239922Sgonzostatic int dummy_kbd_configure(int flags); 960239922Sgonzo 961239922Sgonzokeyboard_switch_t bcmdummysw; 962239922Sgonzo 963239922Sgonzostatic int 964239922Sgonzodummy_kbd_configure(int flags) 965239922Sgonzo{ 966239922Sgonzo 967239922Sgonzo return (0); 968239922Sgonzo} 969239922SgonzoKEYBOARD_DRIVER(bcmdummy, bcmdummysw, dummy_kbd_configure); 970