]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/vt/hw/fb/vt_fb.c
vm_ooffset_t is now unsigned
[FreeBSD/FreeBSD.git] / sys / dev / vt / hw / fb / vt_fb.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2013 The FreeBSD Foundation
5  * All rights reserved.
6  *
7  * This software was developed by Aleksandr Rybalko under sponsorship from the
8  * FreeBSD Foundation.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/malloc.h>
38 #include <sys/queue.h>
39 #include <sys/fbio.h>
40 #include <sys/kernel.h>
41 #include <dev/vt/vt.h>
42 #include <dev/vt/hw/fb/vt_fb.h>
43 #include <dev/vt/colors/vt_termcolors.h>
44
45 #include <vm/vm.h>
46 #include <vm/pmap.h>
47
48 static struct vt_driver vt_fb_driver = {
49         .vd_name = "fb",
50         .vd_init = vt_fb_init,
51         .vd_fini = vt_fb_fini,
52         .vd_blank = vt_fb_blank,
53         .vd_bitblt_text = vt_fb_bitblt_text,
54         .vd_invalidate_text = vt_fb_invalidate_text,
55         .vd_bitblt_bmp = vt_fb_bitblt_bitmap,
56         .vd_drawrect = vt_fb_drawrect,
57         .vd_setpixel = vt_fb_setpixel,
58         .vd_postswitch = vt_fb_postswitch,
59         .vd_priority = VD_PRIORITY_GENERIC+10,
60         .vd_fb_ioctl = vt_fb_ioctl,
61         .vd_fb_mmap = vt_fb_mmap,
62         .vd_suspend = vt_fb_suspend,
63         .vd_resume = vt_fb_resume,
64 };
65
66 VT_DRIVER_DECLARE(vt_fb, vt_fb_driver);
67
68 static void
69 vt_fb_mem_wr1(struct fb_info *sc, uint32_t o, uint8_t v)
70 {
71
72         KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o));
73         *(uint8_t *)(sc->fb_vbase + o) = v;
74 }
75
76 static void
77 vt_fb_mem_wr2(struct fb_info *sc, uint32_t o, uint16_t v)
78 {
79
80         KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o));
81         *(uint16_t *)(sc->fb_vbase + o) = v;
82 }
83
84 static void
85 vt_fb_mem_wr4(struct fb_info *sc, uint32_t o, uint32_t v)
86 {
87
88         KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o));
89         *(uint32_t *)(sc->fb_vbase + o) = v;
90 }
91
92 int
93 vt_fb_ioctl(struct vt_device *vd, u_long cmd, caddr_t data, struct thread *td)
94 {
95         struct fb_info *info;
96         int error = 0;
97
98         info = vd->vd_softc;
99
100         switch (cmd) {
101         case FBIOGTYPE:
102                 bcopy(info, (struct fbtype *)data, sizeof(struct fbtype));
103                 break;
104
105         case FBIO_GETWINORG:    /* get frame buffer window origin */
106                 *(u_int *)data = 0;
107                 break;
108
109         case FBIO_GETDISPSTART: /* get display start address */
110                 ((video_display_start_t *)data)->x = 0;
111                 ((video_display_start_t *)data)->y = 0;
112                 break;
113
114         case FBIO_GETLINEWIDTH: /* get scan line width in bytes */
115                 *(u_int *)data = info->fb_stride;
116                 break;
117
118         case FBIO_BLANK:        /* blank display */
119                 if (vd->vd_driver->vd_blank == NULL)
120                         return (ENODEV);
121                 vd->vd_driver->vd_blank(vd, TC_BLACK);
122                 break;
123
124         default:
125                 error = ENOIOCTL;
126                 break;
127         }
128
129         return (error);
130 }
131
132 int
133 vt_fb_mmap(struct vt_device *vd, vm_ooffset_t offset, vm_paddr_t *paddr,
134     int prot, vm_memattr_t *memattr)
135 {
136         struct fb_info *info;
137
138         info = vd->vd_softc;
139
140         if (info->fb_flags & FB_FLAG_NOMMAP)
141                 return (ENODEV);
142
143         if (offset < info->fb_size) {
144                 if (info->fb_pbase == 0) {
145                         *paddr = vtophys((uint8_t *)info->fb_vbase + offset);
146                 } else {
147                         *paddr = info->fb_pbase + offset;
148                         if (info->fb_flags & FB_FLAG_MEMATTR)
149                                 *memattr = info->fb_memattr;
150 #ifdef VM_MEMATTR_WRITE_COMBINING
151                         else
152                                 *memattr = VM_MEMATTR_WRITE_COMBINING;
153 #endif
154                 }
155                 return (0);
156         }
157
158         return (EINVAL);
159 }
160
161 void
162 vt_fb_setpixel(struct vt_device *vd, int x, int y, term_color_t color)
163 {
164         struct fb_info *info;
165         uint32_t c;
166         u_int o;
167
168         info = vd->vd_softc;
169         c = info->fb_cmap[color];
170         o = info->fb_stride * y + x * FBTYPE_GET_BYTESPP(info);
171
172         if (info->fb_flags & FB_FLAG_NOWRITE)
173                 return;
174
175         KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer"));
176
177         switch (FBTYPE_GET_BYTESPP(info)) {
178         case 1:
179                 vt_fb_mem_wr1(info, o, c);
180                 break;
181         case 2:
182                 vt_fb_mem_wr2(info, o, c);
183                 break;
184         case 3:
185                 vt_fb_mem_wr1(info, o, (c >> 16) & 0xff);
186                 vt_fb_mem_wr1(info, o + 1, (c >> 8) & 0xff);
187                 vt_fb_mem_wr1(info, o + 2, c & 0xff);
188                 break;
189         case 4:
190                 vt_fb_mem_wr4(info, o, c);
191                 break;
192         default:
193                 /* panic? */
194                 return;
195         }
196 }
197
198 void
199 vt_fb_drawrect(struct vt_device *vd, int x1, int y1, int x2, int y2, int fill,
200     term_color_t color)
201 {
202         int x, y;
203
204         for (y = y1; y <= y2; y++) {
205                 if (fill || (y == y1) || (y == y2)) {
206                         for (x = x1; x <= x2; x++)
207                                 vt_fb_setpixel(vd, x, y, color);
208                 } else {
209                         vt_fb_setpixel(vd, x1, y, color);
210                         vt_fb_setpixel(vd, x2, y, color);
211                 }
212         }
213 }
214
215 void
216 vt_fb_blank(struct vt_device *vd, term_color_t color)
217 {
218         struct fb_info *info;
219         uint32_t c;
220         u_int o, h;
221
222         info = vd->vd_softc;
223         c = info->fb_cmap[color];
224
225         if (info->fb_flags & FB_FLAG_NOWRITE)
226                 return;
227
228         KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer"));
229
230         switch (FBTYPE_GET_BYTESPP(info)) {
231         case 1:
232                 for (h = 0; h < info->fb_height; h++)
233                         for (o = 0; o < info->fb_stride; o++)
234                                 vt_fb_mem_wr1(info, h*info->fb_stride + o, c);
235                 break;
236         case 2:
237                 for (h = 0; h < info->fb_height; h++)
238                         for (o = 0; o < info->fb_stride - 1; o += 2)
239                                 vt_fb_mem_wr2(info, h*info->fb_stride + o, c);
240                 break;
241         case 3:
242                 for (h = 0; h < info->fb_height; h++)
243                         for (o = 0; o < info->fb_stride - 2; o += 3) {
244                                 vt_fb_mem_wr1(info, h*info->fb_stride + o,
245                                     (c >> 16) & 0xff);
246                                 vt_fb_mem_wr1(info, h*info->fb_stride + o + 1,
247                                     (c >> 8) & 0xff);
248                                 vt_fb_mem_wr1(info, h*info->fb_stride + o + 2,
249                                     c & 0xff);
250                         }
251                 break;
252         case 4:
253                 for (h = 0; h < info->fb_height; h++)
254                         for (o = 0; o < info->fb_stride - 3; o += 4)
255                                 vt_fb_mem_wr4(info, h*info->fb_stride + o, c);
256                 break;
257         default:
258                 /* panic? */
259                 return;
260         }
261 }
262
263 void
264 vt_fb_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw,
265     const uint8_t *pattern, const uint8_t *mask,
266     unsigned int width, unsigned int height,
267     unsigned int x, unsigned int y, term_color_t fg, term_color_t bg)
268 {
269         struct fb_info *info;
270         uint32_t fgc, bgc, cc, o;
271         int bpp, bpl, xi, yi;
272         int bit, byte;
273
274         info = vd->vd_softc;
275         bpp = FBTYPE_GET_BYTESPP(info);
276         fgc = info->fb_cmap[fg];
277         bgc = info->fb_cmap[bg];
278         bpl = (width + 7) / 8; /* Bytes per source line. */
279
280         if (info->fb_flags & FB_FLAG_NOWRITE)
281                 return;
282
283         KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer"));
284
285         /* Bound by right and bottom edges. */
286         if (y + height > vw->vw_draw_area.tr_end.tp_row) {
287                 if (y >= vw->vw_draw_area.tr_end.tp_row)
288                         return;
289                 height = vw->vw_draw_area.tr_end.tp_row - y;
290         }
291         if (x + width > vw->vw_draw_area.tr_end.tp_col) {
292                 if (x >= vw->vw_draw_area.tr_end.tp_col)
293                         return;
294                 width = vw->vw_draw_area.tr_end.tp_col - x;
295         }
296         for (yi = 0; yi < height; yi++) {
297                 for (xi = 0; xi < width; xi++) {
298                         byte = yi * bpl + xi / 8;
299                         bit = 0x80 >> (xi % 8);
300                         /* Skip pixel write, if mask bit not set. */
301                         if (mask != NULL && (mask[byte] & bit) == 0)
302                                 continue;
303                         o = (y + yi) * info->fb_stride + (x + xi) * bpp;
304                         o += vd->vd_transpose;
305                         cc = pattern[byte] & bit ? fgc : bgc;
306
307                         switch(bpp) {
308                         case 1:
309                                 vt_fb_mem_wr1(info, o, cc);
310                                 break;
311                         case 2:
312                                 vt_fb_mem_wr2(info, o, cc);
313                                 break;
314                         case 3:
315                                 /* Packed mode, so unaligned. Byte access. */
316                                 vt_fb_mem_wr1(info, o, (cc >> 16) & 0xff);
317                                 vt_fb_mem_wr1(info, o + 1, (cc >> 8) & 0xff);
318                                 vt_fb_mem_wr1(info, o + 2, cc & 0xff);
319                                 break;
320                         case 4:
321                                 vt_fb_mem_wr4(info, o, cc);
322                                 break;
323                         default:
324                                 /* panic? */
325                                 break;
326                         }
327                 }
328         }
329 }
330
331 void
332 vt_fb_bitblt_text(struct vt_device *vd, const struct vt_window *vw,
333     const term_rect_t *area)
334 {
335         unsigned int col, row, x, y;
336         struct vt_font *vf;
337         term_char_t c;
338         term_color_t fg, bg;
339         const uint8_t *pattern;
340         size_t z;
341
342         vf = vw->vw_font;
343
344         for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) {
345                 for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col;
346                     ++col) {
347                         x = col * vf->vf_width +
348                             vw->vw_draw_area.tr_begin.tp_col;
349                         y = row * vf->vf_height +
350                             vw->vw_draw_area.tr_begin.tp_row;
351
352                         c = VTBUF_GET_FIELD(&vw->vw_buf, row, col);
353                         pattern = vtfont_lookup(vf, c);
354                         vt_determine_colors(c,
355                             VTBUF_ISCURSOR(&vw->vw_buf, row, col), &fg, &bg);
356
357                         z = row * PIXEL_WIDTH(VT_FB_MAX_WIDTH) + col;
358                         if (vd->vd_drawn && (vd->vd_drawn[z] == c) &&
359                             vd->vd_drawnfg && (vd->vd_drawnfg[z] == fg) &&
360                             vd->vd_drawnbg && (vd->vd_drawnbg[z] == bg))
361                                 continue;
362
363                         vt_fb_bitblt_bitmap(vd, vw,
364                             pattern, NULL, vf->vf_width, vf->vf_height,
365                             x, y, fg, bg);
366
367                         if (vd->vd_drawn)
368                                 vd->vd_drawn[z] = c;
369                         if (vd->vd_drawnfg)
370                                 vd->vd_drawnfg[z] = fg;
371                         if (vd->vd_drawnbg)
372                                 vd->vd_drawnbg[z] = bg;
373                 }
374         }
375
376 #ifndef SC_NO_CUTPASTE
377         if (!vd->vd_mshown)
378                 return;
379
380         term_rect_t drawn_area;
381
382         drawn_area.tr_begin.tp_col = area->tr_begin.tp_col * vf->vf_width;
383         drawn_area.tr_begin.tp_row = area->tr_begin.tp_row * vf->vf_height;
384         drawn_area.tr_end.tp_col = area->tr_end.tp_col * vf->vf_width;
385         drawn_area.tr_end.tp_row = area->tr_end.tp_row * vf->vf_height;
386
387         if (vt_is_cursor_in_area(vd, &drawn_area)) {
388                 vt_fb_bitblt_bitmap(vd, vw,
389                     vd->vd_mcursor->map, vd->vd_mcursor->mask,
390                     vd->vd_mcursor->width, vd->vd_mcursor->height,
391                     vd->vd_mx_drawn + vw->vw_draw_area.tr_begin.tp_col,
392                     vd->vd_my_drawn + vw->vw_draw_area.tr_begin.tp_row,
393                     vd->vd_mcursor_fg, vd->vd_mcursor_bg);
394         }
395 #endif
396 }
397
398 void
399 vt_fb_invalidate_text(struct vt_device *vd, const term_rect_t *area)
400 {
401         unsigned int col, row;
402         size_t z;
403
404         for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) {
405                 for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col;
406                     ++col) {
407                         z = row * PIXEL_WIDTH(VT_FB_MAX_WIDTH) + col;
408                         if (vd->vd_drawn)
409                                 vd->vd_drawn[z] = 0;
410                         if (vd->vd_drawnfg)
411                                 vd->vd_drawnfg[z] = 0;
412                         if (vd->vd_drawnbg)
413                                 vd->vd_drawnbg[z] = 0;
414                 }
415         }
416 }
417
418 void
419 vt_fb_postswitch(struct vt_device *vd)
420 {
421         struct fb_info *info;
422
423         info = vd->vd_softc;
424
425         if (info->enter != NULL)
426                 info->enter(info->fb_priv);
427 }
428
429 static int
430 vt_fb_init_cmap(uint32_t *cmap, int depth)
431 {
432
433         switch (depth) {
434         case 8:
435                 return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB,
436                     0x7, 5, 0x7, 2, 0x3, 0));
437         case 15:
438                 return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB,
439                     0x1f, 10, 0x1f, 5, 0x1f, 0));
440         case 16:
441                 return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB,
442                     0x1f, 11, 0x3f, 5, 0x1f, 0));
443         case 24:
444         case 32: /* Ignore alpha. */
445                 return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB,
446                     0xff, 16, 0xff, 8, 0xff, 0));
447         default:
448                 return (1);
449         }
450 }
451
452 int
453 vt_fb_init(struct vt_device *vd)
454 {
455         struct fb_info *info;
456         u_int margin;
457         int bg, err;
458         term_color_t c;
459
460         info = vd->vd_softc;
461         vd->vd_height = MIN(VT_FB_MAX_HEIGHT, info->fb_height);
462         margin = (info->fb_height - vd->vd_height) >> 1;
463         vd->vd_transpose = margin * info->fb_stride;
464         vd->vd_width = MIN(VT_FB_MAX_WIDTH, info->fb_width);
465         margin = (info->fb_width - vd->vd_width) >> 1;
466         vd->vd_transpose += margin * (info->fb_bpp / NBBY);
467         vd->vd_video_dev = info->fb_video_dev;
468
469         if (info->fb_size == 0)
470                 return (CN_DEAD);
471
472         if (info->fb_pbase == 0 && info->fb_vbase == 0)
473                 info->fb_flags |= FB_FLAG_NOMMAP;
474
475         if (info->fb_cmsize <= 0) {
476                 err = vt_fb_init_cmap(info->fb_cmap, FBTYPE_GET_BPP(info));
477                 if (err)
478                         return (CN_DEAD);
479                 info->fb_cmsize = 16;
480         }
481
482         c = TC_BLACK;
483         if (TUNABLE_INT_FETCH("teken.bg_color", &bg) != 0) {
484                 if (bg == TC_WHITE)
485                         bg |= TC_LIGHT;
486                 c = bg;
487         }
488         /* Clear the screen. */
489         vd->vd_driver->vd_blank(vd, c);
490
491         /* Wakeup screen. KMS need this. */
492         vt_fb_postswitch(vd);
493
494         return (CN_INTERNAL);
495 }
496
497 void
498 vt_fb_fini(struct vt_device *vd, void *softc)
499 {
500
501         vd->vd_video_dev = NULL;
502 }
503
504 int
505 vt_fb_attach(struct fb_info *info)
506 {
507
508         vt_allocate(&vt_fb_driver, info);
509
510         return (0);
511 }
512
513 int
514 vt_fb_detach(struct fb_info *info)
515 {
516
517         vt_deallocate(&vt_fb_driver, info);
518
519         return (0);
520 }
521
522 void
523 vt_fb_suspend(struct vt_device *vd)
524 {
525
526         vt_suspend(vd);
527 }
528
529 void
530 vt_fb_resume(struct vt_device *vd)
531 {
532
533         vt_resume(vd);
534 }