]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/broadcom/bcm2835/bcm2835_fb.c
Merge compiler-rt trunk r338150, and resolve conflicts.
[FreeBSD/FreeBSD.git] / sys / arm / broadcom / bcm2835 / bcm2835_fb.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2012 Oleksandr Tymoshenko <gonzo@freebsd.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  */
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/bus.h>
35 #include <sys/consio.h>
36 #include <sys/fbio.h>
37 #include <sys/kdb.h>
38 #include <sys/kernel.h>
39 #include <sys/malloc.h>
40 #include <sys/module.h>
41
42 #include <vm/vm.h>
43 #include <vm/pmap.h>
44
45 #include <dev/fb/fbreg.h>
46 #include <dev/ofw/ofw_bus.h>
47 #include <dev/ofw/ofw_bus_subr.h>
48 #include <dev/syscons/syscons.h>
49
50 #include <arm/broadcom/bcm2835/bcm2835_mbox_prop.h>
51
52 #include "mbox_if.h"
53
54 struct argb {
55         uint8_t         a;
56         uint8_t         r;
57         uint8_t         g;
58         uint8_t         b;
59 };
60
61 static struct argb bcmfb_palette[16] = {
62         {0x00, 0x00, 0x00, 0x00},
63         {0x00, 0x00, 0x00, 0xaa},
64         {0x00, 0x00, 0xaa, 0x00},
65         {0x00, 0x00, 0xaa, 0xaa},
66         {0x00, 0xaa, 0x00, 0x00},
67         {0x00, 0xaa, 0x00, 0xaa},
68         {0x00, 0xaa, 0x55, 0x00},
69         {0x00, 0xaa, 0xaa, 0xaa},
70         {0x00, 0x55, 0x55, 0x55},
71         {0x00, 0x55, 0x55, 0xff},
72         {0x00, 0x55, 0xff, 0x55},
73         {0x00, 0x55, 0xff, 0xff},
74         {0x00, 0xff, 0x55, 0x55},
75         {0x00, 0xff, 0x55, 0xff},
76         {0x00, 0xff, 0xff, 0x55},
77         {0x00, 0xff, 0xff, 0xff}
78 };
79
80 /* mouse pointer from dev/syscons/scgfbrndr.c */
81 static u_char mouse_pointer[16] = {
82         0x00, 0x40, 0x60, 0x70, 0x78, 0x7c, 0x7e, 0x68,
83         0x0c, 0x0c, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00
84 };
85
86 #define BCMFB_FONT_HEIGHT       16
87 #define BCMFB_FONT_WIDTH        8
88 #define FB_WIDTH                640
89 #define FB_HEIGHT               480
90 #define FB_DEPTH                24
91
92 struct bcmsc_softc {
93         /* Videoadpater part */
94         video_adapter_t va;
95
96         intptr_t        fb_addr;
97         intptr_t        fb_paddr;
98         unsigned int    fb_size;
99
100         unsigned int    height;
101         unsigned int    width;
102         unsigned int    depth;
103         unsigned int    stride;
104
105         unsigned int    xmargin;
106         unsigned int    ymargin;
107
108         unsigned char   *font;
109         int             fbswap;
110         int             initialized;
111 };
112
113 static struct bcmsc_softc bcmsc;
114
115 static struct ofw_compat_data compat_data[] = {
116         {"broadcom,bcm2835-fb",         1},
117         {"brcm,bcm2708-fb",             1},
118         {NULL,                          0}
119 };
120
121 static int bcm_fb_probe(device_t);
122 static int bcm_fb_attach(device_t);
123 static void bcmfb_update_margins(video_adapter_t *adp);
124 static int bcmfb_configure(int);
125
126 static int
127 bcm_fb_probe(device_t dev)
128 {
129         int error;
130
131         if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
132                 return (ENXIO);
133
134         device_set_desc(dev, "BCM2835 framebuffer device");
135         error = sc_probe_unit(device_get_unit(dev), 
136             device_get_flags(dev) | SC_AUTODETECT_KBD);
137         if (error != 0)
138                 return (error);
139
140         return (BUS_PROBE_DEFAULT);
141 }
142
143 static int
144 bcm_fb_attach(device_t dev)
145 {
146         struct bcm2835_fb_config fb;
147         struct bcmsc_softc *sc;
148
149         sc = (struct bcmsc_softc *)vid_get_adapter(vid_find_adapter(
150             "bcmfb", 0));
151         if (sc != NULL)
152                 device_set_softc(dev, sc);
153         else
154                 sc = device_get_softc(dev);
155
156         memset(&fb, 0, sizeof(fb));
157         if (bcm2835_mbox_fb_get_w_h(&fb) != 0)
158                 return (ENXIO);
159         fb.bpp = FB_DEPTH;
160         fb.vxres = fb.xres;
161         fb.vyres = fb.yres;
162         fb.xoffset = fb.yoffset = 0;
163         if (bcm2835_mbox_fb_init(&fb) != 0)
164                 return (ENXIO);
165
166         sc->fb_addr = (intptr_t)pmap_mapdev(fb.base, fb.size);
167         sc->fb_paddr = fb.base;
168         sc->fb_size = fb.size;
169         sc->depth = fb.bpp;
170         sc->stride = fb.pitch;
171         sc->width = fb.xres;
172         sc->height = fb.yres;
173         bcmfb_update_margins(&sc->va);
174
175         if (sc_attach_unit(device_get_unit(dev),
176             device_get_flags(dev) | SC_AUTODETECT_KBD) != 0) {
177                 device_printf(dev, "failed to attach syscons\n");
178                 return (ENXIO);
179         }
180
181         device_printf(dev, "%dx%d(%dx%d@%d,%d) %dbpp\n", fb.xres, fb.yres,
182             fb.vxres, fb.vyres, fb.xoffset, fb.yoffset, fb.bpp);
183         device_printf(dev,
184             "fbswap: %d, pitch %d, base 0x%08x, screen_size %d\n",
185             sc->fbswap, fb.pitch, fb.base, fb.size);
186
187         return (0);
188 }
189
190 static device_method_t bcm_fb_methods[] = {
191         /* Device interface */
192         DEVMETHOD(device_probe,         bcm_fb_probe),
193         DEVMETHOD(device_attach,        bcm_fb_attach),
194
195         { 0, 0 }
196 };
197
198 static devclass_t bcm_fb_devclass;
199
200 static driver_t bcm_fb_driver = {
201         "fb",
202         bcm_fb_methods,
203         sizeof(struct bcmsc_softc),
204 };
205
206 DRIVER_MODULE(bcm2835fb, ofwbus, bcm_fb_driver, bcm_fb_devclass, 0, 0);
207 DRIVER_MODULE(bcm2835fb, simplebus, bcm_fb_driver, bcm_fb_devclass, 0, 0);
208
209 /*
210  * Video driver routines and glue.
211  */
212 static vi_probe_t               bcmfb_probe;
213 static vi_init_t                bcmfb_init;
214 static vi_get_info_t            bcmfb_get_info;
215 static vi_query_mode_t          bcmfb_query_mode;
216 static vi_set_mode_t            bcmfb_set_mode;
217 static vi_save_font_t           bcmfb_save_font;
218 static vi_load_font_t           bcmfb_load_font;
219 static vi_show_font_t           bcmfb_show_font;
220 static vi_save_palette_t        bcmfb_save_palette;
221 static vi_load_palette_t        bcmfb_load_palette;
222 static vi_set_border_t          bcmfb_set_border;
223 static vi_save_state_t          bcmfb_save_state;
224 static vi_load_state_t          bcmfb_load_state;
225 static vi_set_win_org_t         bcmfb_set_win_org;
226 static vi_read_hw_cursor_t      bcmfb_read_hw_cursor;
227 static vi_set_hw_cursor_t       bcmfb_set_hw_cursor;
228 static vi_set_hw_cursor_shape_t bcmfb_set_hw_cursor_shape;
229 static vi_blank_display_t       bcmfb_blank_display;
230 static vi_mmap_t                bcmfb_mmap;
231 static vi_ioctl_t               bcmfb_ioctl;
232 static vi_clear_t               bcmfb_clear;
233 static vi_fill_rect_t           bcmfb_fill_rect;
234 static vi_bitblt_t              bcmfb_bitblt;
235 static vi_diag_t                bcmfb_diag;
236 static vi_save_cursor_palette_t bcmfb_save_cursor_palette;
237 static vi_load_cursor_palette_t bcmfb_load_cursor_palette;
238 static vi_copy_t                bcmfb_copy;
239 static vi_putp_t                bcmfb_putp;
240 static vi_putc_t                bcmfb_putc;
241 static vi_puts_t                bcmfb_puts;
242 static vi_putm_t                bcmfb_putm;
243
244 static video_switch_t bcmfbvidsw = {
245         .probe                  = bcmfb_probe,
246         .init                   = bcmfb_init,
247         .get_info               = bcmfb_get_info,
248         .query_mode             = bcmfb_query_mode,
249         .set_mode               = bcmfb_set_mode,
250         .save_font              = bcmfb_save_font,
251         .load_font              = bcmfb_load_font,
252         .show_font              = bcmfb_show_font,
253         .save_palette           = bcmfb_save_palette,
254         .load_palette           = bcmfb_load_palette,
255         .set_border             = bcmfb_set_border,
256         .save_state             = bcmfb_save_state,
257         .load_state             = bcmfb_load_state,
258         .set_win_org            = bcmfb_set_win_org,
259         .read_hw_cursor         = bcmfb_read_hw_cursor,
260         .set_hw_cursor          = bcmfb_set_hw_cursor,
261         .set_hw_cursor_shape    = bcmfb_set_hw_cursor_shape,
262         .blank_display          = bcmfb_blank_display,
263         .mmap                   = bcmfb_mmap,
264         .ioctl                  = bcmfb_ioctl,
265         .clear                  = bcmfb_clear,
266         .fill_rect              = bcmfb_fill_rect,
267         .bitblt                 = bcmfb_bitblt,
268         .diag                   = bcmfb_diag,
269         .save_cursor_palette    = bcmfb_save_cursor_palette,
270         .load_cursor_palette    = bcmfb_load_cursor_palette,
271         .copy                   = bcmfb_copy,
272         .putp                   = bcmfb_putp,
273         .putc                   = bcmfb_putc,
274         .puts                   = bcmfb_puts,
275         .putm                   = bcmfb_putm,
276 };
277
278 VIDEO_DRIVER(bcmfb, bcmfbvidsw, bcmfb_configure);
279
280 static vr_init_t bcmrend_init;
281 static vr_clear_t bcmrend_clear;
282 static vr_draw_border_t bcmrend_draw_border;
283 static vr_draw_t bcmrend_draw;
284 static vr_set_cursor_t bcmrend_set_cursor;
285 static vr_draw_cursor_t bcmrend_draw_cursor;
286 static vr_blink_cursor_t bcmrend_blink_cursor;
287 static vr_set_mouse_t bcmrend_set_mouse;
288 static vr_draw_mouse_t bcmrend_draw_mouse;
289
290 /*
291  * We use our own renderer; this is because we must emulate a hardware
292  * cursor.
293  */
294 static sc_rndr_sw_t bcmrend = {
295         bcmrend_init,
296         bcmrend_clear,
297         bcmrend_draw_border,
298         bcmrend_draw,
299         bcmrend_set_cursor,
300         bcmrend_draw_cursor,
301         bcmrend_blink_cursor,
302         bcmrend_set_mouse,
303         bcmrend_draw_mouse
304 };
305
306 RENDERER(bcmfb, 0, bcmrend, gfb_set);
307 RENDERER_MODULE(bcmfb, gfb_set);
308
309 static void
310 bcmrend_init(scr_stat* scp)
311 {
312 }
313
314 static void
315 bcmrend_clear(scr_stat* scp, int c, int attr)
316 {
317 }
318
319 static void
320 bcmrend_draw_border(scr_stat* scp, int color)
321 {
322 }
323
324 static void
325 bcmrend_draw(scr_stat* scp, int from, int count, int flip)
326 {
327         video_adapter_t* adp = scp->sc->adp;
328         int i, c, a;
329
330         if (!flip) {
331                 /* Normal printing */
332                 vidd_puts(adp, from, (uint16_t*)sc_vtb_pointer(&scp->vtb, from), count);
333         } else {        
334                 /* This is for selections and such: invert the color attribute */
335                 for (i = count; i-- > 0; ++from) {
336                         c = sc_vtb_getc(&scp->vtb, from);
337                         a = sc_vtb_geta(&scp->vtb, from) >> 8;
338                         vidd_putc(adp, from, c, (a >> 4) | ((a & 0xf) << 4));
339                 }
340         }
341 }
342
343 static void
344 bcmrend_set_cursor(scr_stat* scp, int base, int height, int blink)
345 {
346 }
347
348 static void
349 bcmrend_draw_cursor(scr_stat* scp, int off, int blink, int on, int flip)
350 {
351         int bytes, col, i, j, row;
352         struct bcmsc_softc *sc;
353         uint8_t *addr;
354         video_adapter_t *adp;
355
356         adp = scp->sc->adp;
357         sc = (struct bcmsc_softc *)adp;
358
359         if (scp->curs_attr.height <= 0)
360                 return;
361
362         if (sc->fb_addr == 0)
363                 return;
364
365         if (off >= adp->va_info.vi_width * adp->va_info.vi_height)
366                 return;
367
368         /* calculate the coordinates in the video buffer */
369         row = (off / adp->va_info.vi_width) * adp->va_info.vi_cheight;
370         col = (off % adp->va_info.vi_width) * adp->va_info.vi_cwidth;
371
372         addr = (uint8_t *)sc->fb_addr
373             + (row + sc->ymargin)*(sc->stride)
374             + (sc->depth/8) * (col + sc->xmargin);
375
376         bytes = sc->depth / 8;
377         /* our cursor consists of simply inverting the char under it */
378         for (i = 0; i < adp->va_info.vi_cheight; i++) {
379                 for (j = 0; j < adp->va_info.vi_cwidth; j++) {
380                         switch (sc->depth) {
381                         case 32:
382                         case 24:
383                                 addr[bytes*j + 2] ^= 0xff;
384                                 /* FALLTHROUGH */
385                         case 16:
386                                 addr[bytes*j + 1] ^= 0xff;
387                                 addr[bytes*j] ^= 0xff;
388                                 break;
389                         default:
390                                 break;
391                         }
392                 }
393
394                 addr += sc->stride;
395         }
396 }
397
398 static void
399 bcmrend_blink_cursor(scr_stat* scp, int at, int flip)
400 {
401 }
402
403 static void
404 bcmrend_set_mouse(scr_stat* scp)
405 {
406 }
407
408 static void
409 bcmrend_draw_mouse(scr_stat* scp, int x, int y, int on)
410 {
411         vidd_putm(scp->sc->adp, x, y, mouse_pointer, 0xffffffff, 16, 8);
412 }
413
414 static uint16_t bcmfb_static_window[ROW*COL];
415 extern u_char dflt_font_16[];
416
417 /*
418  * Update videoadapter settings after changing resolution
419  */
420 static void
421 bcmfb_update_margins(video_adapter_t *adp)
422 {
423         struct bcmsc_softc *sc;
424         video_info_t *vi;
425
426         sc = (struct bcmsc_softc *)adp;
427         vi = &adp->va_info;
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
433 static int
434 bcmfb_configure(int flags)
435 {
436         char bootargs[2048], *n, *p, *v;
437         pcell_t cell;
438         phandle_t chosen, display, root;
439         struct bcmsc_softc *sc;
440
441         sc = &bcmsc;
442         if (sc->initialized)
443                 return (0);
444
445         sc->width = 0;
446         sc->height = 0;
447
448         /*
449          * It seems there is no way to let syscons framework know
450          * that framebuffer resolution has changed. So just try
451          * to fetch data from FDT bootargs, FDT display data and
452          * finally go with defaults if everything else has failed.
453          */
454         chosen = OF_finddevice("/chosen");
455         if (chosen != -1 &&
456             OF_getprop(chosen, "bootargs", &bootargs, sizeof(bootargs)) > 0) {
457                 p = bootargs;
458                 while ((v = strsep(&p, " ")) != NULL) {
459                         if (*v == '\0')
460                                 continue;
461                         n = strsep(&v, "=");
462                         if (strcmp(n, "bcm2708_fb.fbwidth") == 0 && v != NULL)
463                                 sc->width = (unsigned int)strtol(v, NULL, 0);
464                         else if (strcmp(n, "bcm2708_fb.fbheight") == 0 &&
465                             v != NULL)
466                                 sc->height = (unsigned int)strtol(v, NULL, 0);
467                         else if (strcmp(n, "bcm2708_fb.fbswap") == 0 &&
468                             v != NULL)
469                                 if (*v == '1')
470                                         sc->fbswap = 1;
471                 }
472         }
473
474         root = OF_finddevice("/");
475         if ((root != -1) && 
476             (display = fdt_find_compatible(root, "broadcom,bcm2835-fb", 1))) {
477                 if (sc->width == 0) {
478                         if ((OF_getencprop(display, "broadcom,width",
479                             &cell, sizeof(cell))) > 0)
480                                 sc->width = cell;
481                 }
482
483                 if (sc->height == 0) {
484                         if ((OF_getencprop(display, "broadcom,height", 
485                             &cell, sizeof(cell))) > 0)
486                                 sc->height = cell;
487                 }
488         }
489
490         if (sc->width == 0)
491                 sc->width = FB_WIDTH;
492         if (sc->height == 0)
493                 sc->height = FB_HEIGHT;
494
495         bcmfb_init(0, &sc->va, 0);
496         sc->initialized = 1;
497
498         return (0);
499 }
500
501 static int
502 bcmfb_probe(int unit, video_adapter_t **adp, void *arg, int flags)
503 {
504
505         return (0);
506 }
507
508 static int
509 bcmfb_init(int unit, video_adapter_t *adp, int flags)
510 {
511         struct bcmsc_softc *sc;
512         video_info_t *vi;
513
514         sc = (struct bcmsc_softc *)adp;
515         vi = &adp->va_info;
516
517         vid_init_struct(adp, "bcmfb", -1, unit);
518
519         sc->font = dflt_font_16;
520         vi->vi_cheight = BCMFB_FONT_HEIGHT;
521         vi->vi_cwidth = BCMFB_FONT_WIDTH;
522         vi->vi_width = sc->width / vi->vi_cwidth;
523         vi->vi_height = sc->height / vi->vi_cheight;
524
525         /*
526          * Clamp width/height to syscons maximums
527          */
528         if (vi->vi_width > COL)
529                 vi->vi_width = COL;
530         if (vi->vi_height > ROW)
531                 vi->vi_height = ROW;
532
533         sc->xmargin = (sc->width - (vi->vi_width * vi->vi_cwidth)) / 2;
534         sc->ymargin = (sc->height - (vi->vi_height * vi->vi_cheight)) / 2;
535
536         adp->va_window = (vm_offset_t) bcmfb_static_window;
537         adp->va_flags |= V_ADP_FONT /* | V_ADP_COLOR | V_ADP_MODECHANGE */;
538
539         vid_register(&sc->va);
540
541         return (0);
542 }
543
544 static int
545 bcmfb_get_info(video_adapter_t *adp, int mode, video_info_t *info)
546 {
547         bcopy(&adp->va_info, info, sizeof(*info));
548         return (0);
549 }
550
551 static int
552 bcmfb_query_mode(video_adapter_t *adp, video_info_t *info)
553 {
554         return (0);
555 }
556
557 static int
558 bcmfb_set_mode(video_adapter_t *adp, int mode)
559 {
560         return (0);
561 }
562
563 static int
564 bcmfb_save_font(video_adapter_t *adp, int page, int size, int width,
565     u_char *data, int c, int count)
566 {
567         return (0);
568 }
569
570 static int
571 bcmfb_load_font(video_adapter_t *adp, int page, int size, int width,
572     u_char *data, int c, int count)
573 {
574         struct bcmsc_softc *sc;
575
576         sc = (struct bcmsc_softc *)adp;
577         sc->font = data;
578
579         return (0);
580 }
581
582 static int
583 bcmfb_show_font(video_adapter_t *adp, int page)
584 {
585         return (0);
586 }
587
588 static int
589 bcmfb_save_palette(video_adapter_t *adp, u_char *palette)
590 {
591         return (0);
592 }
593
594 static int
595 bcmfb_load_palette(video_adapter_t *adp, u_char *palette)
596 {
597         return (0);
598 }
599
600 static int
601 bcmfb_set_border(video_adapter_t *adp, int border)
602 {
603         return (bcmfb_blank_display(adp, border));
604 }
605
606 static int
607 bcmfb_save_state(video_adapter_t *adp, void *p, size_t size)
608 {
609         return (0);
610 }
611
612 static int
613 bcmfb_load_state(video_adapter_t *adp, void *p)
614 {
615         return (0);
616 }
617
618 static int
619 bcmfb_set_win_org(video_adapter_t *adp, off_t offset)
620 {
621         return (0);
622 }
623
624 static int
625 bcmfb_read_hw_cursor(video_adapter_t *adp, int *col, int *row)
626 {
627         *col = *row = 0;
628
629         return (0);
630 }
631
632 static int
633 bcmfb_set_hw_cursor(video_adapter_t *adp, int col, int row)
634 {
635         return (0);
636 }
637
638 static int
639 bcmfb_set_hw_cursor_shape(video_adapter_t *adp, int base, int height,
640     int celsize, int blink)
641 {
642         return (0);
643 }
644
645 static int
646 bcmfb_blank_display(video_adapter_t *adp, int mode)
647 {
648
649         struct bcmsc_softc *sc;
650
651         sc = (struct bcmsc_softc *)adp;
652         if (sc && sc->fb_addr)
653                 memset((void*)sc->fb_addr, 0, sc->fb_size);
654
655         return (0);
656 }
657
658 static int
659 bcmfb_mmap(video_adapter_t *adp, vm_ooffset_t offset, vm_paddr_t *paddr,
660     int prot, vm_memattr_t *memattr)
661 {
662         struct bcmsc_softc *sc;
663
664         sc = (struct bcmsc_softc *)adp;
665
666         /*
667          * This might be a legacy VGA mem request: if so, just point it at the
668          * framebuffer, since it shouldn't be touched
669          */
670         if (offset < sc->stride*sc->height) {
671                 *paddr = sc->fb_paddr + offset;
672                 return (0);
673         }
674
675         return (EINVAL);
676 }
677
678 static int
679 bcmfb_ioctl(video_adapter_t *adp, u_long cmd, caddr_t data)
680 {
681         struct bcmsc_softc *sc;
682         struct fbtype *fb;
683
684         sc = (struct bcmsc_softc *)adp;
685
686         switch (cmd) {
687         case FBIOGTYPE:
688                 fb = (struct fbtype *)data;
689                 fb->fb_type = FBTYPE_PCIMISC;
690                 fb->fb_height = sc->height;
691                 fb->fb_width = sc->width;
692                 fb->fb_depth = sc->depth;
693                 if (sc->depth <= 1 || sc->depth > 8)
694                         fb->fb_cmsize = 0;
695                 else
696                         fb->fb_cmsize = 1 << sc->depth;
697                 fb->fb_size = sc->fb_size;
698                 break;
699         default:
700                 return (fb_commonioctl(adp, cmd, data));
701         }
702
703         return (0);
704 }
705
706 static int
707 bcmfb_clear(video_adapter_t *adp)
708 {
709
710         return (bcmfb_blank_display(adp, 0));
711 }
712
713 static int
714 bcmfb_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy)
715 {
716
717         return (0);
718 }
719
720 static int
721 bcmfb_bitblt(video_adapter_t *adp, ...)
722 {
723
724         return (0);
725 }
726
727 static int
728 bcmfb_diag(video_adapter_t *adp, int level)
729 {
730
731         return (0);
732 }
733
734 static int
735 bcmfb_save_cursor_palette(video_adapter_t *adp, u_char *palette)
736 {
737
738         return (0);
739 }
740
741 static int
742 bcmfb_load_cursor_palette(video_adapter_t *adp, u_char *palette)
743 {
744
745         return (0);
746 }
747
748 static int
749 bcmfb_copy(video_adapter_t *adp, vm_offset_t src, vm_offset_t dst, int n)
750 {
751
752         return (0);
753 }
754
755 static int
756 bcmfb_putp(video_adapter_t *adp, vm_offset_t off, uint32_t p, uint32_t a,
757     int size, int bpp, int bit_ltor, int byte_ltor)
758 {
759
760         return (0);
761 }
762
763 static int
764 bcmfb_putc(video_adapter_t *adp, vm_offset_t off, uint8_t c, uint8_t a)
765 {
766         int bytes, col, i, j, k, row;
767         struct bcmsc_softc *sc;
768         u_char *p;
769         uint8_t *addr, fg, bg, color;
770         uint16_t rgb;
771
772         sc = (struct bcmsc_softc *)adp;
773
774         if (sc->fb_addr == 0)
775                 return (0);
776
777         row = (off / adp->va_info.vi_width) * adp->va_info.vi_cheight;
778         col = (off % adp->va_info.vi_width) * adp->va_info.vi_cwidth;
779         p = sc->font + c*BCMFB_FONT_HEIGHT;
780         addr = (uint8_t *)sc->fb_addr
781             + (row + sc->ymargin)*(sc->stride)
782             + (sc->depth/8) * (col + sc->xmargin);
783
784         fg = a & 0xf ;
785         bg = (a >> 4) & 0xf;
786
787         bytes = sc->depth / 8;
788         for (i = 0; i < BCMFB_FONT_HEIGHT; i++) {
789                 for (j = 0, k = 7; j < 8; j++, k--) {
790                         if ((p[i] & (1 << k)) == 0)
791                                 color = bg;
792                         else
793                                 color = fg;
794
795                         switch (sc->depth) {
796                         case 32:
797                         case 24:
798                                 if (sc->fbswap) {
799                                         addr[bytes * j + 0] =
800                                             bcmfb_palette[color].b;
801                                         addr[bytes * j + 1] =
802                                             bcmfb_palette[color].g;
803                                         addr[bytes * j + 2] =
804                                             bcmfb_palette[color].r;
805                                 } else {
806                                         addr[bytes * j + 0] =
807                                             bcmfb_palette[color].r;
808                                         addr[bytes * j + 1] =
809                                             bcmfb_palette[color].g;
810                                         addr[bytes * j + 2] =
811                                             bcmfb_palette[color].b;
812                                 }
813                                 if (sc->depth == 32)
814                                         addr[bytes * j + 3] =
815                                             bcmfb_palette[color].a;
816                                 break;
817                         case 16:
818                                 rgb = (bcmfb_palette[color].r >> 3) << 11;
819                                 rgb |= (bcmfb_palette[color].g >> 2) << 5;
820                                 rgb |= (bcmfb_palette[color].b >> 3);
821                                 addr[bytes * j] = rgb & 0xff;
822                                 addr[bytes * j + 1] = (rgb >> 8) & 0xff;
823                         default:
824                                 /* Not supported yet */
825                                 break;
826                         }
827                 }
828
829                 addr += (sc->stride);
830         }
831
832         return (0);
833 }
834
835 static int
836 bcmfb_puts(video_adapter_t *adp, vm_offset_t off, u_int16_t *s, int len)
837 {
838         int i;
839
840         for (i = 0; i < len; i++) 
841                 bcmfb_putc(adp, off + i, s[i] & 0xff, (s[i] & 0xff00) >> 8);
842
843         return (0);
844 }
845
846 static int
847 bcmfb_putm(video_adapter_t *adp, int x, int y, uint8_t *pixel_image,
848     uint32_t pixel_mask, int size, int width)
849 {
850
851         return (0);
852 }
853
854 /*
855  * Define a stub keyboard driver in case one hasn't been
856  * compiled into the kernel
857  */
858 #include <sys/kbio.h>
859 #include <dev/kbd/kbdreg.h>
860
861 static int dummy_kbd_configure(int flags);
862
863 keyboard_switch_t bcmdummysw;
864
865 static int
866 dummy_kbd_configure(int flags)
867 {
868
869         return (0);
870 }
871 KEYBOARD_DRIVER(bcmdummy, bcmdummysw, dummy_kbd_configure);