1256904Sray/*- 2256904Sray * Copyright (c) 2013 The FreeBSD Foundation 3256904Sray * All rights reserved. 4256904Sray * 5256904Sray * This software was developed by Aleksandr Rybalko under sponsorship from the 6256904Sray * FreeBSD Foundation. 7256904Sray * 8256904Sray * Redistribution and use in source and binary forms, with or without 9256904Sray * modification, are permitted provided that the following conditions 10256904Sray * are met: 11256904Sray * 1. Redistributions of source code must retain the above copyright 12256904Sray * notice, this list of conditions and the following disclaimer. 13256904Sray * 2. Redistributions in binary form must reproduce the above copyright 14256904Sray * notice, this list of conditions and the following disclaimer in the 15256904Sray * documentation and/or other materials provided with the distribution. 16256904Sray * 17256904Sray * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18256904Sray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19256904Sray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20256904Sray * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21256904Sray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22256904Sray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23256904Sray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24256904Sray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25256904Sray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26256904Sray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27256904Sray * SUCH DAMAGE. 28256904Sray */ 29256904Sray 30256904Sray#include <sys/cdefs.h> 31256904Sray__FBSDID("$FreeBSD: stable/11/sys/dev/vt/hw/fb/vt_fb.c 360309 2020-04-25 15:27:45Z emaste $"); 32256904Sray 33256904Sray#include <sys/param.h> 34256904Sray#include <sys/systm.h> 35256904Sray#include <sys/malloc.h> 36256904Sray#include <sys/queue.h> 37256904Sray#include <sys/fbio.h> 38256904Sray#include <dev/vt/vt.h> 39256904Sray#include <dev/vt/hw/fb/vt_fb.h> 40256904Sray#include <dev/vt/colors/vt_termcolors.h> 41256904Sray 42279752Shselasky#include <vm/vm.h> 43279752Shselasky#include <vm/pmap.h> 44279752Shselasky 45256904Sraystatic struct vt_driver vt_fb_driver = { 46265397Sray .vd_name = "fb", 47256904Sray .vd_init = vt_fb_init, 48279488Sdumbbell .vd_fini = vt_fb_fini, 49256904Sray .vd_blank = vt_fb_blank, 50270411Sdumbbell .vd_bitblt_text = vt_fb_bitblt_text, 51270431Sdumbbell .vd_bitblt_bmp = vt_fb_bitblt_bitmap, 52261552Sray .vd_drawrect = vt_fb_drawrect, 53261552Sray .vd_setpixel = vt_fb_setpixel, 54256904Sray .vd_postswitch = vt_fb_postswitch, 55256904Sray .vd_priority = VD_PRIORITY_GENERIC+10, 56259777Sray .vd_fb_ioctl = vt_fb_ioctl, 57259777Sray .vd_fb_mmap = vt_fb_mmap, 58277795Savg .vd_suspend = vt_fb_suspend, 59277795Savg .vd_resume = vt_fb_resume, 60256904Sray}; 61256904Sray 62265397SrayVT_DRIVER_DECLARE(vt_fb, vt_fb_driver); 63265397Sray 64269620Snwhitehornstatic void 65269620Snwhitehornvt_fb_mem_wr1(struct fb_info *sc, uint32_t o, uint8_t v) 66269620Snwhitehorn{ 67269620Snwhitehorn 68269620Snwhitehorn KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 69269620Snwhitehorn *(uint8_t *)(sc->fb_vbase + o) = v; 70269620Snwhitehorn} 71269620Snwhitehorn 72269620Snwhitehornstatic void 73269620Snwhitehornvt_fb_mem_wr2(struct fb_info *sc, uint32_t o, uint16_t v) 74269620Snwhitehorn{ 75269620Snwhitehorn 76269620Snwhitehorn KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 77269620Snwhitehorn *(uint16_t *)(sc->fb_vbase + o) = v; 78269620Snwhitehorn} 79269620Snwhitehorn 80269620Snwhitehornstatic void 81269620Snwhitehornvt_fb_mem_wr4(struct fb_info *sc, uint32_t o, uint32_t v) 82269620Snwhitehorn{ 83269620Snwhitehorn 84269620Snwhitehorn KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 85269620Snwhitehorn *(uint32_t *)(sc->fb_vbase + o) = v; 86269620Snwhitehorn} 87269620Snwhitehorn 88268771Snwhitehornint 89259777Srayvt_fb_ioctl(struct vt_device *vd, u_long cmd, caddr_t data, struct thread *td) 90259777Sray{ 91259777Sray struct fb_info *info; 92268771Snwhitehorn int error = 0; 93259777Sray 94259777Sray info = vd->vd_softc; 95259777Sray 96268771Snwhitehorn switch (cmd) { 97268771Snwhitehorn case FBIOGTYPE: 98268771Snwhitehorn bcopy(info, (struct fbtype *)data, sizeof(struct fbtype)); 99268771Snwhitehorn break; 100259777Sray 101268771Snwhitehorn case FBIO_GETWINORG: /* get frame buffer window origin */ 102268771Snwhitehorn *(u_int *)data = 0; 103268771Snwhitehorn break; 104268771Snwhitehorn 105268771Snwhitehorn case FBIO_GETDISPSTART: /* get display start address */ 106268771Snwhitehorn ((video_display_start_t *)data)->x = 0; 107268771Snwhitehorn ((video_display_start_t *)data)->y = 0; 108268771Snwhitehorn break; 109268771Snwhitehorn 110268771Snwhitehorn case FBIO_GETLINEWIDTH: /* get scan line width in bytes */ 111268771Snwhitehorn *(u_int *)data = info->fb_stride; 112268771Snwhitehorn break; 113268771Snwhitehorn 114268771Snwhitehorn case FBIO_BLANK: /* blank display */ 115268771Snwhitehorn if (vd->vd_driver->vd_blank == NULL) 116268771Snwhitehorn return (ENODEV); 117268771Snwhitehorn vd->vd_driver->vd_blank(vd, TC_BLACK); 118268771Snwhitehorn break; 119268771Snwhitehorn 120268771Snwhitehorn default: 121268771Snwhitehorn error = ENOIOCTL; 122268771Snwhitehorn break; 123268771Snwhitehorn } 124268771Snwhitehorn 125268771Snwhitehorn return (error); 126259777Sray} 127259777Sray 128268771Snwhitehornint 129260953Srayvt_fb_mmap(struct vt_device *vd, vm_ooffset_t offset, vm_paddr_t *paddr, 130260953Sray int prot, vm_memattr_t *memattr) 131259777Sray{ 132259777Sray struct fb_info *info; 133259777Sray 134259777Sray info = vd->vd_softc; 135259777Sray 136268771Snwhitehorn if (info->fb_flags & FB_FLAG_NOMMAP) 137268771Snwhitehorn return (ENODEV); 138259777Sray 139268771Snwhitehorn if (offset >= 0 && offset < info->fb_size) { 140279752Shselasky if (info->fb_pbase == 0) { 141279752Shselasky *paddr = vtophys((uint8_t *)info->fb_vbase + offset); 142279752Shselasky } else { 143279752Shselasky *paddr = info->fb_pbase + offset; 144279752Shselasky#ifdef VM_MEMATTR_WRITE_COMBINING 145279752Shselasky *memattr = VM_MEMATTR_WRITE_COMBINING; 146279752Shselasky#endif 147279752Shselasky } 148268771Snwhitehorn return (0); 149268771Snwhitehorn } 150268771Snwhitehorn 151268771Snwhitehorn return (EINVAL); 152259777Sray} 153259777Sray 154271684Sdumbbellvoid 155261552Srayvt_fb_setpixel(struct vt_device *vd, int x, int y, term_color_t color) 156261552Sray{ 157261552Sray struct fb_info *info; 158261552Sray uint32_t c; 159261552Sray u_int o; 160261552Sray 161261552Sray info = vd->vd_softc; 162261552Sray c = info->fb_cmap[color]; 163261552Sray o = info->fb_stride * y + x * FBTYPE_GET_BYTESPP(info); 164261552Sray 165276679Snwhitehorn if (info->fb_flags & FB_FLAG_NOWRITE) 166276679Snwhitehorn return; 167276679Snwhitehorn 168269620Snwhitehorn KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer")); 169269620Snwhitehorn 170261552Sray switch (FBTYPE_GET_BYTESPP(info)) { 171261552Sray case 1: 172269620Snwhitehorn vt_fb_mem_wr1(info, o, c); 173261552Sray break; 174261552Sray case 2: 175269620Snwhitehorn vt_fb_mem_wr2(info, o, c); 176261552Sray break; 177261552Sray case 3: 178269620Snwhitehorn vt_fb_mem_wr1(info, o, (c >> 16) & 0xff); 179269620Snwhitehorn vt_fb_mem_wr1(info, o + 1, (c >> 8) & 0xff); 180269620Snwhitehorn vt_fb_mem_wr1(info, o + 2, c & 0xff); 181261552Sray break; 182261552Sray case 4: 183269620Snwhitehorn vt_fb_mem_wr4(info, o, c); 184261552Sray break; 185261552Sray default: 186261552Sray /* panic? */ 187261552Sray return; 188261552Sray } 189261552Sray} 190261552Sray 191271684Sdumbbellvoid 192261552Srayvt_fb_drawrect(struct vt_device *vd, int x1, int y1, int x2, int y2, int fill, 193261552Sray term_color_t color) 194261552Sray{ 195261552Sray int x, y; 196261552Sray 197261552Sray for (y = y1; y <= y2; y++) { 198261552Sray if (fill || (y == y1) || (y == y2)) { 199261552Sray for (x = x1; x <= x2; x++) 200261552Sray vt_fb_setpixel(vd, x, y, color); 201261552Sray } else { 202261552Sray vt_fb_setpixel(vd, x1, y, color); 203261552Sray vt_fb_setpixel(vd, x2, y, color); 204261552Sray } 205261552Sray } 206261552Sray} 207261552Sray 208261552Srayvoid 209256904Srayvt_fb_blank(struct vt_device *vd, term_color_t color) 210256904Sray{ 211256904Sray struct fb_info *info; 212256904Sray uint32_t c; 213268771Snwhitehorn u_int o, h; 214256904Sray 215256904Sray info = vd->vd_softc; 216256904Sray c = info->fb_cmap[color]; 217257725Sray 218276679Snwhitehorn if (info->fb_flags & FB_FLAG_NOWRITE) 219276679Snwhitehorn return; 220276679Snwhitehorn 221269620Snwhitehorn KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer")); 222269620Snwhitehorn 223256904Sray switch (FBTYPE_GET_BYTESPP(info)) { 224256904Sray case 1: 225268796Snwhitehorn for (h = 0; h < info->fb_height; h++) 226268771Snwhitehorn for (o = 0; o < info->fb_stride; o++) 227269620Snwhitehorn vt_fb_mem_wr1(info, h*info->fb_stride + o, c); 228256904Sray break; 229256904Sray case 2: 230268796Snwhitehorn for (h = 0; h < info->fb_height; h++) 231360309Semaste for (o = 0; o < info->fb_stride - 1; o += 2) 232269620Snwhitehorn vt_fb_mem_wr2(info, h*info->fb_stride + o, c); 233256904Sray break; 234256904Sray case 3: 235268796Snwhitehorn for (h = 0; h < info->fb_height; h++) 236360309Semaste for (o = 0; o < info->fb_stride - 2; o += 3) { 237269620Snwhitehorn vt_fb_mem_wr1(info, h*info->fb_stride + o, 238268771Snwhitehorn (c >> 16) & 0xff); 239269620Snwhitehorn vt_fb_mem_wr1(info, h*info->fb_stride + o + 1, 240268771Snwhitehorn (c >> 8) & 0xff); 241269620Snwhitehorn vt_fb_mem_wr1(info, h*info->fb_stride + o + 2, 242268771Snwhitehorn c & 0xff); 243268771Snwhitehorn } 244256904Sray break; 245256904Sray case 4: 246268796Snwhitehorn for (h = 0; h < info->fb_height; h++) 247360309Semaste for (o = 0; o < info->fb_stride - 3; o += 4) 248269620Snwhitehorn vt_fb_mem_wr4(info, h*info->fb_stride + o, c); 249256904Sray break; 250256904Sray default: 251256904Sray /* panic? */ 252256904Sray return; 253256904Sray } 254256904Sray} 255256904Sray 256270431Sdumbbellvoid 257270411Sdumbbellvt_fb_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw, 258270411Sdumbbell const uint8_t *pattern, const uint8_t *mask, 259270411Sdumbbell unsigned int width, unsigned int height, 260270411Sdumbbell unsigned int x, unsigned int y, term_color_t fg, term_color_t bg) 261256904Sray{ 262256904Sray struct fb_info *info; 263256904Sray uint32_t fgc, bgc, cc, o; 264282247Semaste int bpp, bpl, xi, yi; 265282247Semaste int bit, byte; 266256904Sray 267256904Sray info = vd->vd_softc; 268256904Sray bpp = FBTYPE_GET_BYTESPP(info); 269256904Sray fgc = info->fb_cmap[fg]; 270256904Sray bgc = info->fb_cmap[bg]; 271282247Semaste bpl = (width + 7) / 8; /* Bytes per source line. */ 272256904Sray 273276679Snwhitehorn if (info->fb_flags & FB_FLAG_NOWRITE) 274276679Snwhitehorn return; 275276679Snwhitehorn 276269620Snwhitehorn KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer")); 277269620Snwhitehorn 278282247Semaste /* Bound by right and bottom edges. */ 279282247Semaste if (y + height > vw->vw_draw_area.tr_end.tp_row) { 280282247Semaste if (y >= vw->vw_draw_area.tr_end.tp_row) 281282247Semaste return; 282282247Semaste height = vw->vw_draw_area.tr_end.tp_row - y; 283282247Semaste } 284282247Semaste if (x + width > vw->vw_draw_area.tr_end.tp_col) { 285282247Semaste if (x >= vw->vw_draw_area.tr_end.tp_col) 286282247Semaste return; 287282247Semaste width = vw->vw_draw_area.tr_end.tp_col - x; 288282247Semaste } 289282247Semaste for (yi = 0; yi < height; yi++) { 290282247Semaste for (xi = 0; xi < width; xi++) { 291282247Semaste byte = yi * bpl + xi / 8; 292282247Semaste bit = 0x80 >> (xi % 8); 293282247Semaste /* Skip pixel write, if mask bit not set. */ 294282247Semaste if (mask != NULL && (mask[byte] & bit) == 0) 295282247Semaste continue; 296282247Semaste o = (y + yi) * info->fb_stride + (x + xi) * bpp; 297286867Smarcel o += vd->vd_transpose; 298282247Semaste cc = pattern[byte] & bit ? fgc : bgc; 299256904Sray 300256904Sray switch(bpp) { 301256904Sray case 1: 302269620Snwhitehorn vt_fb_mem_wr1(info, o, cc); 303256904Sray break; 304256904Sray case 2: 305269620Snwhitehorn vt_fb_mem_wr2(info, o, cc); 306256904Sray break; 307256904Sray case 3: 308256904Sray /* Packed mode, so unaligned. Byte access. */ 309269620Snwhitehorn vt_fb_mem_wr1(info, o, (cc >> 16) & 0xff); 310269620Snwhitehorn vt_fb_mem_wr1(info, o + 1, (cc >> 8) & 0xff); 311269620Snwhitehorn vt_fb_mem_wr1(info, o + 2, cc & 0xff); 312256904Sray break; 313256904Sray case 4: 314269620Snwhitehorn vt_fb_mem_wr4(info, o, cc); 315256904Sray break; 316256904Sray default: 317256904Sray /* panic? */ 318256904Sray break; 319256904Sray } 320256904Sray } 321256904Sray } 322256904Sray} 323256904Sray 324257725Srayvoid 325270411Sdumbbellvt_fb_bitblt_text(struct vt_device *vd, const struct vt_window *vw, 326270411Sdumbbell const term_rect_t *area) 327270411Sdumbbell{ 328270411Sdumbbell unsigned int col, row, x, y; 329270411Sdumbbell struct vt_font *vf; 330270411Sdumbbell term_char_t c; 331270411Sdumbbell term_color_t fg, bg; 332270411Sdumbbell const uint8_t *pattern; 333270411Sdumbbell 334270411Sdumbbell vf = vw->vw_font; 335270411Sdumbbell 336270411Sdumbbell for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) { 337270411Sdumbbell for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col; 338270411Sdumbbell ++col) { 339270613Sdumbbell x = col * vf->vf_width + 340270613Sdumbbell vw->vw_draw_area.tr_begin.tp_col; 341270613Sdumbbell y = row * vf->vf_height + 342270613Sdumbbell vw->vw_draw_area.tr_begin.tp_row; 343270411Sdumbbell 344270411Sdumbbell c = VTBUF_GET_FIELD(&vw->vw_buf, row, col); 345270411Sdumbbell pattern = vtfont_lookup(vf, c); 346270411Sdumbbell vt_determine_colors(c, 347270411Sdumbbell VTBUF_ISCURSOR(&vw->vw_buf, row, col), &fg, &bg); 348270411Sdumbbell 349270411Sdumbbell vt_fb_bitblt_bitmap(vd, vw, 350270411Sdumbbell pattern, NULL, vf->vf_width, vf->vf_height, 351270411Sdumbbell x, y, fg, bg); 352270411Sdumbbell } 353270411Sdumbbell } 354270411Sdumbbell 355270411Sdumbbell#ifndef SC_NO_CUTPASTE 356270411Sdumbbell if (!vd->vd_mshown) 357270411Sdumbbell return; 358270411Sdumbbell 359270411Sdumbbell term_rect_t drawn_area; 360270411Sdumbbell 361270720Sdumbbell drawn_area.tr_begin.tp_col = area->tr_begin.tp_col * vf->vf_width; 362270720Sdumbbell drawn_area.tr_begin.tp_row = area->tr_begin.tp_row * vf->vf_height; 363270720Sdumbbell drawn_area.tr_end.tp_col = area->tr_end.tp_col * vf->vf_width; 364270720Sdumbbell drawn_area.tr_end.tp_row = area->tr_end.tp_row * vf->vf_height; 365270411Sdumbbell 366270411Sdumbbell if (vt_is_cursor_in_area(vd, &drawn_area)) { 367270411Sdumbbell vt_fb_bitblt_bitmap(vd, vw, 368270411Sdumbbell vd->vd_mcursor->map, vd->vd_mcursor->mask, 369270411Sdumbbell vd->vd_mcursor->width, vd->vd_mcursor->height, 370270720Sdumbbell vd->vd_mx_drawn + vw->vw_draw_area.tr_begin.tp_col, 371270720Sdumbbell vd->vd_my_drawn + vw->vw_draw_area.tr_begin.tp_row, 372270411Sdumbbell vd->vd_mcursor_fg, vd->vd_mcursor_bg); 373270411Sdumbbell } 374270411Sdumbbell#endif 375270411Sdumbbell} 376270411Sdumbbell 377270411Sdumbbellvoid 378256904Srayvt_fb_postswitch(struct vt_device *vd) 379256904Sray{ 380256904Sray struct fb_info *info; 381256904Sray 382256904Sray info = vd->vd_softc; 383256904Sray 384256904Sray if (info->enter != NULL) 385256904Sray info->enter(info->fb_priv); 386256904Sray} 387256904Sray 388256904Sraystatic int 389256904Srayvt_fb_init_cmap(uint32_t *cmap, int depth) 390256904Sray{ 391256904Sray 392256904Sray switch (depth) { 393256904Sray case 8: 394269783Sdumbbell return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB, 395256904Sray 0x7, 5, 0x7, 2, 0x3, 0)); 396256904Sray case 15: 397269783Sdumbbell return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB, 398256904Sray 0x1f, 10, 0x1f, 5, 0x1f, 0)); 399256904Sray case 16: 400269783Sdumbbell return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB, 401256904Sray 0x1f, 11, 0x3f, 5, 0x1f, 0)); 402256904Sray case 24: 403256904Sray case 32: /* Ignore alpha. */ 404269783Sdumbbell return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB, 405269783Sdumbbell 0xff, 16, 0xff, 8, 0xff, 0)); 406256904Sray default: 407256904Sray return (1); 408256904Sray } 409256904Sray} 410256904Sray 411257725Srayint 412256904Srayvt_fb_init(struct vt_device *vd) 413256904Sray{ 414256904Sray struct fb_info *info; 415286867Smarcel u_int margin; 416256904Sray int err; 417256904Sray 418256904Sray info = vd->vd_softc; 419303312Sbdrewery vd->vd_height = MIN(VT_FB_MAX_HEIGHT, info->fb_height); 420286867Smarcel margin = (info->fb_height - vd->vd_height) >> 1; 421286867Smarcel vd->vd_transpose = margin * info->fb_stride; 422303312Sbdrewery vd->vd_width = MIN(VT_FB_MAX_WIDTH, info->fb_width); 423286867Smarcel margin = (info->fb_width - vd->vd_width) >> 1; 424286867Smarcel vd->vd_transpose += margin * (info->fb_bpp / NBBY); 425279488Sdumbbell vd->vd_video_dev = info->fb_video_dev; 426256904Sray 427269620Snwhitehorn if (info->fb_size == 0) 428269620Snwhitehorn return (CN_DEAD); 429269620Snwhitehorn 430279752Shselasky if (info->fb_pbase == 0 && info->fb_vbase == 0) 431269620Snwhitehorn info->fb_flags |= FB_FLAG_NOMMAP; 432269620Snwhitehorn 433256904Sray if (info->fb_cmsize <= 0) { 434256904Sray err = vt_fb_init_cmap(info->fb_cmap, FBTYPE_GET_BPP(info)); 435256904Sray if (err) 436256904Sray return (CN_DEAD); 437256904Sray info->fb_cmsize = 16; 438256904Sray } 439256904Sray 440256904Sray /* Clear the screen. */ 441269437Snwhitehorn vd->vd_driver->vd_blank(vd, TC_BLACK); 442256904Sray 443256904Sray /* Wakeup screen. KMS need this. */ 444256904Sray vt_fb_postswitch(vd); 445256904Sray 446256904Sray return (CN_INTERNAL); 447256904Sray} 448256904Sray 449279488Sdumbbellvoid 450279488Sdumbbellvt_fb_fini(struct vt_device *vd, void *softc) 451279488Sdumbbell{ 452279488Sdumbbell 453279488Sdumbbell vd->vd_video_dev = NULL; 454279488Sdumbbell} 455279488Sdumbbell 456256904Srayint 457256904Srayvt_fb_attach(struct fb_info *info) 458256904Sray{ 459256904Sray 460256904Sray vt_allocate(&vt_fb_driver, info); 461257725Sray 462256904Sray return (0); 463256904Sray} 464257815Sray 465279488Sdumbbellint 466279488Sdumbbellvt_fb_detach(struct fb_info *info) 467279488Sdumbbell{ 468279488Sdumbbell 469279488Sdumbbell vt_deallocate(&vt_fb_driver, info); 470279488Sdumbbell 471279488Sdumbbell return (0); 472279488Sdumbbell} 473279488Sdumbbell 474257815Srayvoid 475277795Savgvt_fb_suspend(struct vt_device *vd) 476257815Sray{ 477257815Sray 478277795Savg vt_suspend(vd); 479257815Sray} 480257815Sray 481257815Srayvoid 482277795Savgvt_fb_resume(struct vt_device *vd) 483257815Sray{ 484257815Sray 485277795Savg vt_resume(vd); 486257815Sray} 487