scvidctl.c revision 204281
153642Sguido/*- 2255332Scy * Copyright (c) 1998 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp> 353642Sguido * All rights reserved. 480482Sdarrenr * 553642Sguido * This code is derived from software contributed to The DragonFly Project 653642Sguido * by Sascha Wildner <saw@online.de> 757126Sguido * 8172776Sdarrenr * Redistribution and use in source and binary forms, with or without 953642Sguido * modification, are permitted provided that the following conditions 1053642Sguido * are met: 1153642Sguido * 1. Redistributions of source code must retain the above copyright 1253642Sguido * notice, this list of conditions and the following disclaimer as 1353642Sguido * the first lines of this file unmodified. 14145562Sdarrenr * 2. Redistributions in binary form must reproduce the above copyright 15255332Scy * notice, this list of conditions and the following disclaimer in the 16255332Scy * documentation and/or other materials provided with the distribution. 17255332Scy * 18255332Scy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19255332Scy * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20255332Scy * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21255332Scy * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22255332Scy * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23255332Scy * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24255332Scy * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25255332Scy * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26145562Sdarrenr * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27255332Scy * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28255332Scy */ 29255332Scy 30255332Scy#include <sys/cdefs.h> 3153642Sguido__FBSDID("$FreeBSD: head/sys/dev/syscons/scvidctl.c 204281 2010-02-24 20:13:34Z jkim $"); 3253642Sguido 3353642Sguido#include "opt_compat.h" 3453642Sguido#include "opt_syscons.h" 3553642Sguido 3653642Sguido#include <sys/param.h> 3753642Sguido#include <sys/systm.h> 3853642Sguido#include <sys/conf.h> 3953642Sguido#include <sys/signalvar.h> 4053642Sguido#include <sys/tty.h> 4153642Sguido#include <sys/kernel.h> 4253642Sguido#include <sys/fbio.h> 43153876Sguido#include <sys/consio.h> 44145522Sdarrenr#include <sys/filedesc.h> 45145522Sdarrenr#include <sys/lock.h> 4653642Sguido#include <sys/sx.h> 4753642Sguido#include <sys/mutex.h> 48145522Sdarrenr#include <sys/proc.h> 4953642Sguido 5053642Sguido#include <dev/fb/fbreg.h> 51145522Sdarrenr#include <dev/syscons/syscons.h> 52145522Sdarrenr 5353642SguidoSET_DECLARE(scrndr_set, const sc_renderer_t); 54145522Sdarrenr 55145522Sdarrenr/* for compatibility with previous versions */ 5653642Sguido/* 3.0-RELEASE used the following structure */ 5753642Sguidotypedef struct old_video_adapter { 58145522Sdarrenr int va_index; 59145522Sdarrenr int va_type; 60145522Sdarrenr int va_flags; 61145522Sdarrenr/* flag bits are the same as the -CURRENT 62170268Sdarrenr#define V_ADP_COLOR (1<<0) 6360851Sdarrenr#define V_ADP_MODECHANGE (1<<1) 64145522Sdarrenr#define V_ADP_STATESAVE (1<<2) 65145522Sdarrenr#define V_ADP_STATELOAD (1<<3) 66145522Sdarrenr#define V_ADP_FONT (1<<4) 67170268Sdarrenr#define V_ADP_PALETTE (1<<5) 68145522Sdarrenr#define V_ADP_BORDER (1<<6) 69145522Sdarrenr#define V_ADP_VESA (1<<7) 70145522Sdarrenr*/ 71145522Sdarrenr int va_crtc_addr; 72145522Sdarrenr u_int va_window; /* virtual address */ 73145522Sdarrenr size_t va_window_size; 74145522Sdarrenr size_t va_window_gran; 75170268Sdarrenr u_int va_buffer; /* virtual address */ 76170268Sdarrenr size_t va_buffer_size; 77170268Sdarrenr int va_initial_mode; 78170268Sdarrenr int va_initial_bios_mode; 79170268Sdarrenr int va_mode; 80170268Sdarrenr} old_video_adapter_t; 81255332Scy 82255332Scy#define OLD_CONS_ADPINFO _IOWR('c', 101, old_video_adapter_t) 8353642Sguido 84145522Sdarrenr/* 3.1-RELEASE used the following structure */ 85145522Sdarrenrtypedef struct old_video_adapter_info { 8653642Sguido int va_index; 8753642Sguido int va_type; 88145522Sdarrenr char va_name[16]; 8953642Sguido int va_unit; 9053642Sguido int va_flags; 91145522Sdarrenr int va_io_base; 92145522Sdarrenr int va_io_size; 9353642Sguido int va_crtc_addr; 94145522Sdarrenr int va_mem_base; 95145522Sdarrenr int va_mem_size; 9653642Sguido u_int va_window; /* virtual address */ 9753642Sguido size_t va_window_size; 98145522Sdarrenr size_t va_window_gran; 99145522Sdarrenr u_int va_buffer; 100145522Sdarrenr size_t va_buffer_size; 101145522Sdarrenr int va_initial_mode; 102170268Sdarrenr int va_initial_bios_mode; 10360851Sdarrenr int va_mode; 104145522Sdarrenr int va_line_width; 105145522Sdarrenr} old_video_adapter_info_t; 106145522Sdarrenr 107170268Sdarrenr#define OLD_CONS_ADPINFO2 _IOWR('c', 101, old_video_adapter_info_t) 108145522Sdarrenr 109145522Sdarrenr/* 3.0-RELEASE and 3.1-RELEASE used the following structure */ 110145522Sdarrenrtypedef struct old_video_info { 111145522Sdarrenr int vi_mode; 112145522Sdarrenr int vi_flags; 113145522Sdarrenr/* flag bits are the same as the -CURRENT 114145522Sdarrenr#define V_INFO_COLOR (1<<0) 115170268Sdarrenr#define V_INFO_GRAPHICS (1<<1) 116170268Sdarrenr#define V_INFO_LINEAR (1<<2) 117170268Sdarrenr#define V_INFO_VESA (1<<3) 118170268Sdarrenr*/ 119170268Sdarrenr int vi_width; 120170268Sdarrenr int vi_height; 121255332Scy int vi_cwidth; 122255332Scy int vi_cheight; 12353642Sguido int vi_depth; 12453642Sguido int vi_planes; 12553642Sguido u_int vi_window; /* physical address */ 12653642Sguido size_t vi_window_size; 127170268Sdarrenr size_t vi_window_gran; 128170268Sdarrenr u_int vi_buffer; /* physical address */ 12953642Sguido size_t vi_buffer_size; 13060851Sdarrenr} old_video_info_t; 131145522Sdarrenr 132145522Sdarrenr#define OLD_CONS_MODEINFO _IOWR('c', 102, old_video_info_t) 133255332Scy#define OLD_CONS_FINDMODE _IOWR('c', 103, old_video_info_t) 134145522Sdarrenr 135255332Scyint 136255332Scysc_set_text_mode(scr_stat *scp, struct tty *tp, int mode, int xsize, int ysize, 137145522Sdarrenr int fontsize, int fontwidth) 138145522Sdarrenr{ 139145522Sdarrenr video_info_t info; 140145522Sdarrenr u_char *font; 141145522Sdarrenr int prev_ysize; 142145522Sdarrenr int error; 143145522Sdarrenr int s; 144145522Sdarrenr 145145522Sdarrenr if (vidd_get_info(scp->sc->adp, mode, &info)) 146145522Sdarrenr return ENODEV; 147145522Sdarrenr 148145522Sdarrenr /* adjust argument values */ 149170268Sdarrenr if (fontwidth <= 0) 150170268Sdarrenr fontwidth = info.vi_cwidth; 151170268Sdarrenr if (fontsize <= 0) 152255332Scy fontsize = info.vi_cheight; 153170268Sdarrenr if (fontsize < 14) { 154145522Sdarrenr fontsize = 8; 155145522Sdarrenr#ifndef SC_NO_FONT_LOADING 156145522Sdarrenr if (!(scp->sc->fonts_loaded & FONT_8)) 157145522Sdarrenr return EINVAL; 158145522Sdarrenr font = scp->sc->font_8; 159145522Sdarrenr#else 160145522Sdarrenr font = NULL; 161170268Sdarrenr#endif 162170268Sdarrenr } else if (fontsize >= 16) { 163170268Sdarrenr fontsize = 16; 164255332Scy#ifndef SC_NO_FONT_LOADING 165170268Sdarrenr if (!(scp->sc->fonts_loaded & FONT_16)) 166145522Sdarrenr return EINVAL; 167145522Sdarrenr font = scp->sc->font_16; 168145522Sdarrenr#else 169145522Sdarrenr font = NULL; 170170268Sdarrenr#endif 171255332Scy } else { 172170268Sdarrenr fontsize = 14; 173170268Sdarrenr#ifndef SC_NO_FONT_LOADING 174145522Sdarrenr if (!(scp->sc->fonts_loaded & FONT_14)) 175145522Sdarrenr return EINVAL; 176145522Sdarrenr font = scp->sc->font_14; 177145522Sdarrenr#else 178145522Sdarrenr font = NULL; 179145522Sdarrenr#endif 180172776Sdarrenr } 181172776Sdarrenr if ((xsize <= 0) || (xsize > info.vi_width)) 182172776Sdarrenr xsize = info.vi_width; 183172776Sdarrenr if ((ysize <= 0) || (ysize > info.vi_height)) 184172776Sdarrenr ysize = info.vi_height; 185172776Sdarrenr 186172776Sdarrenr /* stop screen saver, etc */ 187172776Sdarrenr s = spltty(); 188145522Sdarrenr if ((error = sc_clean_up(scp))) { 189145522Sdarrenr splx(s); 190145522Sdarrenr return error; 191145522Sdarrenr } 192145522Sdarrenr 193145522Sdarrenr if (sc_render_match(scp, scp->sc->adp->va_name, 0) == NULL) { 194145522Sdarrenr splx(s); 195255332Scy return ENODEV; 196255332Scy } 197255332Scy 198255332Scy /* set up scp */ 199255332Scy#ifndef SC_NO_HISTORY 200255332Scy if (scp->history != NULL) 201255332Scy sc_hist_save(scp); 202255332Scy#endif 203255332Scy prev_ysize = scp->ysize; 204255332Scy /* 205255332Scy * This is a kludge to fend off scrn_update() while we 206255332Scy * muck around with scp. XXX 207255332Scy */ 208255332Scy scp->status |= UNKNOWN_MODE | MOUSE_HIDDEN; 209255332Scy scp->status &= ~(GRAPHICS_MODE | PIXEL_MODE | MOUSE_VISIBLE); 210255332Scy scp->mode = mode; 211145522Sdarrenr scp->xsize = xsize; 212145522Sdarrenr scp->ysize = ysize; 213255332Scy scp->xoff = 0; 214172776Sdarrenr scp->yoff = 0; 215172776Sdarrenr scp->xpixel = scp->xsize*8; 216172776Sdarrenr scp->ypixel = scp->ysize*fontsize; 217172776Sdarrenr scp->font = font; 218172776Sdarrenr scp->font_size = fontsize; 219172776Sdarrenr scp->font_width = fontwidth; 220172776Sdarrenr 221145522Sdarrenr /* allocate buffers */ 222145522Sdarrenr sc_alloc_scr_buffer(scp, TRUE, TRUE); 223145522Sdarrenr sc_init_emulator(scp, NULL); 224255332Scy#ifndef SC_NO_CUTPASTE 225145522Sdarrenr sc_alloc_cut_buffer(scp, FALSE); 226255332Scy#endif 227145522Sdarrenr#ifndef SC_NO_HISTORY 228145522Sdarrenr sc_alloc_history_buffer(scp, 0, prev_ysize, FALSE); 229145522Sdarrenr#endif 230145522Sdarrenr splx(s); 231145522Sdarrenr 232145522Sdarrenr if (scp == scp->sc->cur_scp) 233145522Sdarrenr set_mode(scp); 234145522Sdarrenr scp->status &= ~UNKNOWN_MODE; 235145522Sdarrenr 236145522Sdarrenr if (tp == NULL) 237145522Sdarrenr return 0; 238255332Scy DPRINTF(5, ("ws_*size (%d,%d), size (%d,%d)\n", 239255332Scy tp->t_winsize.ws_col, tp->t_winsize.ws_row, scp->xsize, scp->ysize)); 240255332Scy if (tp->t_winsize.ws_col != scp->xsize 241145522Sdarrenr || tp->t_winsize.ws_row != scp->ysize) { 242145522Sdarrenr tp->t_winsize.ws_col = scp->xsize; 243145522Sdarrenr tp->t_winsize.ws_row = scp->ysize; 244145522Sdarrenr 245145522Sdarrenr tty_signal_pgrp(tp, SIGWINCH); 246255332Scy } 247255332Scy 248255332Scy return 0; 249255332Scy} 250255332Scy 251255332Scyint 252255332Scysc_set_graphics_mode(scr_stat *scp, struct tty *tp, int mode) 253255332Scy{ 254255332Scy#ifdef SC_NO_MODE_CHANGE 255255332Scy return ENODEV; 256255332Scy#else 257255332Scy video_info_t info; 258255332Scy int error; 259255332Scy int s; 260255332Scy 261255332Scy if (vidd_get_info(scp->sc->adp, mode, &info)) 262255332Scy return ENODEV; 263255332Scy 264255332Scy /* stop screen saver, etc */ 265145522Sdarrenr s = spltty(); 266255332Scy if ((error = sc_clean_up(scp))) { 267145522Sdarrenr splx(s); 268145522Sdarrenr return error; 269145522Sdarrenr } 270145522Sdarrenr 271145522Sdarrenr if (sc_render_match(scp, scp->sc->adp->va_name, GRAPHICS_MODE) == NULL) { 272145522Sdarrenr splx(s); 273255332Scy return ENODEV; 274255332Scy } 275255332Scy 276255332Scy /* set up scp */ 277255332Scy scp->status |= (UNKNOWN_MODE | GRAPHICS_MODE | MOUSE_HIDDEN); 278255332Scy scp->status &= ~(PIXEL_MODE | MOUSE_VISIBLE); 279255332Scy scp->mode = mode; 280255332Scy /* 281255332Scy * Don't change xsize and ysize; preserve the previous vty 282255332Scy * and history buffers. 283255332Scy */ 284255332Scy scp->xoff = 0; 285255332Scy scp->yoff = 0; 286255332Scy scp->xpixel = info.vi_width; 287255332Scy scp->ypixel = info.vi_height; 288255332Scy scp->font = NULL; 289255332Scy scp->font_size = 0; 290255332Scy#ifndef SC_NO_SYSMOUSE 291255332Scy /* move the mouse cursor at the center of the screen */ 292145522Sdarrenr sc_mouse_move(scp, scp->xpixel / 2, scp->ypixel / 2); 293255332Scy#endif 294255332Scy sc_init_emulator(scp, NULL); 295255332Scy splx(s); 296255332Scy 297145522Sdarrenr if (scp == scp->sc->cur_scp) 29853642Sguido set_mode(scp); 29960851Sdarrenr /* clear_graphics();*/ 300145522Sdarrenr scp->status &= ~UNKNOWN_MODE; 30160851Sdarrenr 30260851Sdarrenr if (tp == NULL) 30360851Sdarrenr return 0; 30453642Sguido if (tp->t_winsize.ws_xpixel != scp->xpixel 305145522Sdarrenr || tp->t_winsize.ws_ypixel != scp->ypixel) { 306145522Sdarrenr tp->t_winsize.ws_xpixel = scp->xpixel; 307255332Scy tp->t_winsize.ws_ypixel = scp->ypixel; 308145522Sdarrenr 309145522Sdarrenr tty_signal_pgrp(tp, SIGWINCH); 310255332Scy } 311255332Scy 312255332Scy return 0; 313255332Scy#endif /* SC_NO_MODE_CHANGE */ 31453642Sguido} 31553642Sguido 316145522Sdarrenrint 317145522Sdarrenrsc_set_pixel_mode(scr_stat *scp, struct tty *tp, int xsize, int ysize, 318145522Sdarrenr int fontsize, int fontwidth) 319145522Sdarrenr{ 320145522Sdarrenr#ifndef SC_PIXEL_MODE 321145522Sdarrenr return ENODEV; 322145522Sdarrenr#else 323145522Sdarrenr video_info_t info; 324145522Sdarrenr ksiginfo_t ksi; 325145522Sdarrenr u_char *font; 326145522Sdarrenr int prev_ysize; 327145522Sdarrenr int error; 328145522Sdarrenr int s; 329145522Sdarrenr 330145522Sdarrenr if (vidd_get_info(scp->sc->adp, scp->mode, &info)) 331145522Sdarrenr return ENODEV; /* this shouldn't happen */ 332145522Sdarrenr 333145522Sdarrenr /* adjust argument values */ 334145522Sdarrenr if (fontsize <= 0) 335255332Scy fontsize = info.vi_cheight; 336145522Sdarrenr if (fontsize < 14) { 337255332Scy fontsize = 8; 338145522Sdarrenr#ifndef SC_NO_FONT_LOADING 339145522Sdarrenr if (!(scp->sc->fonts_loaded & FONT_8)) 340172776Sdarrenr return EINVAL; 341255332Scy font = scp->sc->font_8; 342255332Scy#else 343255332Scy font = NULL; 344255332Scy#endif 345145522Sdarrenr } else if (fontsize >= 16) { 346255332Scy fontsize = 16; 347145522Sdarrenr#ifndef SC_NO_FONT_LOADING 34853642Sguido if (!(scp->sc->fonts_loaded & FONT_16)) 349255332Scy return EINVAL; 350255332Scy font = scp->sc->font_16; 351255332Scy#else 35260851Sdarrenr font = NULL; 35360851Sdarrenr#endif 354145522Sdarrenr } else { 355145522Sdarrenr fontsize = 14; 356170268Sdarrenr#ifndef SC_NO_FONT_LOADING 357170268Sdarrenr if (!(scp->sc->fonts_loaded & FONT_14)) 358145522Sdarrenr return EINVAL; 359145522Sdarrenr font = scp->sc->font_14; 360170268Sdarrenr#else 361170268Sdarrenr font = NULL; 362145522Sdarrenr#endif 363145522Sdarrenr } 364145522Sdarrenr if (xsize <= 0) 365145522Sdarrenr xsize = info.vi_width/8; 36660851Sdarrenr if (ysize <= 0) 36760851Sdarrenr ysize = info.vi_height/fontsize; 36853642Sguido 36953642Sguido if ((info.vi_width < xsize*8) || (info.vi_height < ysize*fontsize)) 37053642Sguido return EINVAL; 371145522Sdarrenr 37253642Sguido if (!sc_support_pixel_mode(&info)) 373145522Sdarrenr return ENODEV; 374145522Sdarrenr 375145522Sdarrenr /* stop screen saver, etc */ 376145522Sdarrenr s = spltty(); 377145522Sdarrenr if ((error = sc_clean_up(scp))) { 378145522Sdarrenr splx(s); 379145522Sdarrenr return error; 380145522Sdarrenr } 381145522Sdarrenr 382255332Scy if (sc_render_match(scp, scp->sc->adp->va_name, PIXEL_MODE) == NULL) { 38353642Sguido splx(s); 384255332Scy return ENODEV; 385255332Scy } 386255332Scy 387255332Scy#if 0 388145522Sdarrenr if (scp->tsw) 389255332Scy (*scp->tsw->te_term)(scp, scp->ts); 390255332Scy scp->tsw = NULL; 391255332Scy scp->ts = NULL; 392255332Scy#endif 393255332Scy 394255332Scy /* set up scp */ 395255332Scy#ifndef SC_NO_HISTORY 396255332Scy if (scp->history != NULL) 397255332Scy sc_hist_save(scp); 398255332Scy#endif 399255332Scy prev_ysize = scp->ysize; 400255332Scy scp->status |= (UNKNOWN_MODE | PIXEL_MODE | MOUSE_HIDDEN); 401255332Scy scp->status &= ~(GRAPHICS_MODE | MOUSE_VISIBLE); 402255332Scy scp->xsize = xsize; 403255332Scy scp->ysize = ysize; 404255332Scy scp->xoff = (scp->xpixel/8 - xsize)/2; 405255332Scy scp->yoff = (scp->ypixel/fontsize - ysize)/2; 406255332Scy scp->font = font; 407255332Scy scp->font_size = fontsize; 408255332Scy scp->font_width = fontwidth; 409255332Scy 410255332Scy /* allocate buffers */ 411255332Scy sc_alloc_scr_buffer(scp, TRUE, TRUE); 412255332Scy sc_init_emulator(scp, NULL); 413255332Scy#ifndef SC_NO_CUTPASTE 414255332Scy sc_alloc_cut_buffer(scp, FALSE); 415255332Scy#endif 416255332Scy#ifndef SC_NO_HISTORY 417255332Scy sc_alloc_history_buffer(scp, 0, prev_ysize, FALSE); 418255332Scy#endif 41953642Sguido splx(s); 420255332Scy 42153642Sguido if (scp == scp->sc->cur_scp) { 422255332Scy sc_set_border(scp, scp->border); 423145522Sdarrenr sc_set_cursor_image(scp); 424255332Scy } 425255332Scy 426255332Scy scp->status &= ~UNKNOWN_MODE; 427255332Scy 428255332Scy if (tp == NULL) 42995418Sdarrenr return 0; 430145522Sdarrenr if (tp->t_winsize.ws_col != scp->xsize 431145522Sdarrenr || tp->t_winsize.ws_row != scp->ysize) { 432255332Scy tp->t_winsize.ws_col = scp->xsize; 433255332Scy tp->t_winsize.ws_row = scp->ysize; 434255332Scy if (tp->t_pgrp != NULL) { 435255332Scy ksiginfo_init(&ksi); 436255332Scy ksi.ksi_signo = SIGWINCH; 437255332Scy ksi.ksi_code = SI_KERNEL; 438255332Scy PGRP_LOCK(tp->t_pgrp); 439255332Scy pgsignal(tp->t_pgrp, SIGWINCH, 1, &ksi); 440255332Scy PGRP_UNLOCK(tp->t_pgrp); 441255332Scy } 442255332Scy } 443255332Scy 444255332Scy return 0; 445145522Sdarrenr#endif /* SC_PIXEL_MODE */ 446255332Scy} 447255332Scy 44892685Sdarrenrint 449145522Sdarrenrsc_support_pixel_mode(void *arg) 450145522Sdarrenr{ 451255332Scy#ifdef SC_PIXEL_MODE 452255332Scy video_info_t *info = arg; 453255332Scy 454145522Sdarrenr if ((info->vi_flags & V_INFO_GRAPHICS) == 0) 455255332Scy return (0); 456255332Scy 457255332Scy /* 458255332Scy * We currently support the following graphic modes: 459255332Scy * 460255332Scy * - 4 bpp planar modes whose memory size does not exceed 64K 461255332Scy * - 15, 16, 24 and 32 bpp linear modes 462255332Scy */ 463130886Sdarrenr switch (info->vi_mem_model) { 464145522Sdarrenr case V_INFO_MM_PLANAR: 465145522Sdarrenr if (info->vi_planes != 4) 466145522Sdarrenr break; 467145522Sdarrenr /* 468161356Sguido * A memory size >64K requires bank switching to access 46953642Sguido * the entire screen. XXX 470145522Sdarrenr */ 471145522Sdarrenr if (info->vi_width * info->vi_height / 8 > info->vi_window_size) 472145522Sdarrenr break; 473255332Scy return (1); 47453642Sguido case V_INFO_MM_DIRECT: 47553642Sguido if ((info->vi_flags & V_INFO_LINEAR) == 0 && 476255332Scy info->vi_depth != 15 && info->vi_depth != 16 && 477255332Scy info->vi_depth != 24 && info->vi_depth != 32) 47880482Sdarrenr break; 47992685Sdarrenr return (1); 480145522Sdarrenr case V_INFO_MM_PACKED: 481145522Sdarrenr if ((info->vi_flags & V_INFO_LINEAR) == 0 && 482145522Sdarrenr info->vi_depth != 8) 483255332Scy break; 484145522Sdarrenr return (1); 485145522Sdarrenr } 48680482Sdarrenr#endif 487145522Sdarrenr return (0); 48880482Sdarrenr} 489255332Scy 490255332Scy#define fb_ioctl(a, c, d) \ 491255332Scy (((a) == NULL) ? ENODEV : \ 492255332Scy vidd_ioctl((a), (c), (caddr_t)(d))) 493255332Scy 494255332Scyint 495255332Scysc_vid_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td) 496255332Scy{ 49760851Sdarrenr scr_stat *scp; 498170268Sdarrenr video_adapter_t *adp; 499170268Sdarrenr video_info_t info; 500145522Sdarrenr video_adapter_info_t adp_info; 501145522Sdarrenr int error; 502255332Scy int s; 503145522Sdarrenr#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 504145522Sdarrenr defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 505145522Sdarrenr int ival; 506145522Sdarrenr#endif 507145522Sdarrenr 508255332Scy scp = SC_STAT(tp); 509145522Sdarrenr if (scp == NULL) /* tp == SC_MOUSE */ 510145522Sdarrenr return ENOIOCTL; 51153642Sguido adp = scp->sc->adp; 51253642Sguido if (adp == NULL) /* shouldn't happen??? */ 51353642Sguido return ENODEV; 51453642Sguido 51592685Sdarrenr switch (cmd) { 51653642Sguido 51753642Sguido case CONS_CURRENTADP: /* get current adapter index */ 518145522Sdarrenr case FBIO_ADAPTER: 51995418Sdarrenr return fb_ioctl(adp, FBIO_ADAPTER, data); 520145522Sdarrenr 52195418Sdarrenr case CONS_CURRENT: /* get current adapter type */ 52295418Sdarrenr case FBIO_ADPTYPE: 523145522Sdarrenr return fb_ioctl(adp, FBIO_ADPTYPE, data); 52453642Sguido 525145522Sdarrenr case OLD_CONS_ADPINFO: /* adapter information (old interface) */ 526145522Sdarrenr if (((old_video_adapter_t *)data)->va_index >= 0) { 527145522Sdarrenr adp = vid_get_adapter(((old_video_adapter_t *)data)->va_index); 528145522Sdarrenr if (adp == NULL) 529145522Sdarrenr return ENODEV; 530145522Sdarrenr } 531145522Sdarrenr ((old_video_adapter_t *)data)->va_index = adp->va_index; 532145522Sdarrenr ((old_video_adapter_t *)data)->va_type = adp->va_type; 53353642Sguido ((old_video_adapter_t *)data)->va_flags = adp->va_flags; 534145522Sdarrenr ((old_video_adapter_t *)data)->va_crtc_addr = adp->va_crtc_addr; 535145522Sdarrenr ((old_video_adapter_t *)data)->va_window = adp->va_window; 536145522Sdarrenr ((old_video_adapter_t *)data)->va_window_size = adp->va_window_size; 537255332Scy ((old_video_adapter_t *)data)->va_window_gran = adp->va_window_gran; 538255332Scy ((old_video_adapter_t *)data)->va_buffer = adp->va_buffer; 539255332Scy ((old_video_adapter_t *)data)->va_buffer_size = adp->va_buffer_size; 540255332Scy ((old_video_adapter_t *)data)->va_mode = adp->va_mode; 541255332Scy ((old_video_adapter_t *)data)->va_initial_mode = adp->va_initial_mode; 542255332Scy ((old_video_adapter_t *)data)->va_initial_bios_mode 543255332Scy = adp->va_initial_bios_mode; 544255332Scy return 0; 545255332Scy 546145522Sdarrenr case OLD_CONS_ADPINFO2: /* adapter information (yet another old I/F) */ 547255332Scy adp_info.va_index = ((old_video_adapter_info_t *)data)->va_index; 548255332Scy if (adp_info.va_index >= 0) { 549255332Scy adp = vid_get_adapter(adp_info.va_index); 550255332Scy if (adp == NULL) 551255332Scy return ENODEV; 552255332Scy } 553255332Scy error = fb_ioctl(adp, FBIO_ADPINFO, &adp_info); 554255332Scy if (error == 0) 555255332Scy bcopy(&adp_info, data, sizeof(old_video_adapter_info_t)); 556255332Scy return error; 557255332Scy 558255332Scy case CONS_ADPINFO: /* adapter information */ 559255332Scy case FBIO_ADPINFO: 560255332Scy if (((video_adapter_info_t *)data)->va_index >= 0) { 561255332Scy adp = vid_get_adapter(((video_adapter_info_t *)data)->va_index); 562255332Scy if (adp == NULL) 563255332Scy return ENODEV; 564255332Scy } 565255332Scy return fb_ioctl(adp, FBIO_ADPINFO, data); 566255332Scy 567255332Scy case CONS_GET: /* get current video mode */ 568255332Scy case FBIO_GETMODE: 569255332Scy *(int *)data = scp->mode; 570255332Scy return 0; 571145522Sdarrenr 572145522Sdarrenr#ifndef SC_NO_MODE_CHANGE 573145522Sdarrenr case FBIO_SETMODE: /* set video mode */ 574145522Sdarrenr if (!(adp->va_flags & V_ADP_MODECHANGE)) 57553642Sguido return ENODEV; 576255332Scy info.vi_mode = *(int *)data; 577255332Scy error = fb_ioctl(adp, FBIO_MODEINFO, &info); 578255332Scy if (error) 579255332Scy return error; 580255332Scy if (info.vi_flags & V_INFO_GRAPHICS) 58153642Sguido return sc_set_graphics_mode(scp, tp, *(int *)data); 58253642Sguido else 583255332Scy return sc_set_text_mode(scp, tp, *(int *)data, 0, 0, 0, 0); 58492685Sdarrenr#endif /* SC_NO_MODE_CHANGE */ 58592685Sdarrenr 58692685Sdarrenr case OLD_CONS_MODEINFO: /* get mode information (old infterface) */ 587255332Scy info.vi_mode = ((old_video_info_t *)data)->vi_mode; 588255332Scy error = fb_ioctl(adp, FBIO_MODEINFO, &info); 589255332Scy if (error == 0) 590255332Scy bcopy(&info, (old_video_info_t *)data, sizeof(old_video_info_t)); 591255332Scy return error; 592255332Scy 593255332Scy case CONS_MODEINFO: /* get mode information */ 594255332Scy case FBIO_MODEINFO: 595255332Scy return fb_ioctl(adp, FBIO_MODEINFO, data); 596255332Scy 597255332Scy case OLD_CONS_FINDMODE: /* find a matching video mode (old interface) */ 598255332Scy bzero(&info, sizeof(info)); 599255332Scy bcopy((old_video_info_t *)data, &info, sizeof(old_video_info_t)); 600145522Sdarrenr error = fb_ioctl(adp, FBIO_FINDMODE, &info); 601145522Sdarrenr if (error == 0) 602145522Sdarrenr bcopy(&info, (old_video_info_t *)data, sizeof(old_video_info_t)); 60360851Sdarrenr return error; 604255332Scy 605255332Scy case CONS_FINDMODE: /* find a matching video mode */ 606255332Scy case FBIO_FINDMODE: 60760851Sdarrenr return fb_ioctl(adp, FBIO_FINDMODE, data); 60860851Sdarrenr 609145522Sdarrenr#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 610145522Sdarrenr defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 611145522Sdarrenr case _IO('c', 104): 612145522Sdarrenr ival = IOCPARM_IVAL(data); 613145522Sdarrenr data = (caddr_t)&ival; 61460851Sdarrenr /* FALLTHROUGH */ 615145522Sdarrenr#endif 616145522Sdarrenr case CONS_SETWINORG: /* set frame buffer window origin */ 61760851Sdarrenr case FBIO_SETWINORG: 61860851Sdarrenr if (scp != scp->sc->cur_scp) 61960851Sdarrenr return ENODEV; /* XXX */ 62060851Sdarrenr return fb_ioctl(adp, FBIO_SETWINORG, data); 62160851Sdarrenr 62260851Sdarrenr case FBIO_GETWINORG: /* get frame buffer window origin */ 62360851Sdarrenr if (scp != scp->sc->cur_scp) 62460851Sdarrenr return ENODEV; /* XXX */ 62560851Sdarrenr return fb_ioctl(adp, FBIO_GETWINORG, data); 62660851Sdarrenr 62760851Sdarrenr case FBIO_GETDISPSTART: 628145522Sdarrenr case FBIO_SETDISPSTART: 629145522Sdarrenr case FBIO_GETLINEWIDTH: 630255332Scy case FBIO_SETLINEWIDTH: 631255332Scy if (scp != scp->sc->cur_scp) 632255332Scy return ENODEV; /* XXX */ 633255332Scy return fb_ioctl(adp, cmd, data); 634255332Scy 635255332Scy case FBIO_GETPALETTE: 636255332Scy case FBIO_SETPALETTE: 637255332Scy case FBIOPUTCMAP: 638255332Scy case FBIOGETCMAP: 639255332Scy case FBIOGTYPE: 640255332Scy case FBIOGATTR: 641255332Scy case FBIOSVIDEO: 642255332Scy case FBIOGVIDEO: 643255332Scy case FBIOSCURSOR: 644145522Sdarrenr case FBIOGCURSOR: 645145522Sdarrenr case FBIOSCURPOS: 646145522Sdarrenr case FBIOGCURPOS: 647145522Sdarrenr case FBIOGCURMAX: 648145522Sdarrenr if (scp != scp->sc->cur_scp) 649145522Sdarrenr return ENODEV; /* XXX */ 650255332Scy return fb_ioctl(adp, cmd, data); 651255332Scy 652145522Sdarrenr case FBIO_BLANK: 653255332Scy if (scp != scp->sc->cur_scp) 654255332Scy return ENODEV; /* XXX */ 655145522Sdarrenr return fb_ioctl(adp, cmd, data); 656255332Scy 657255332Scy#ifndef SC_NO_MODE_CHANGE 658255332Scy /* generic text modes */ 659255332Scy case SW_TEXT_80x25: case SW_TEXT_80x30: 660255332Scy case SW_TEXT_80x43: case SW_TEXT_80x50: 661145522Sdarrenr case SW_TEXT_80x60: 662145522Sdarrenr /* FALLTHROUGH */ 663170268Sdarrenr 664170268Sdarrenr /* VGA TEXT MODES */ 665170268Sdarrenr case SW_VGA_C40x25: 666145522Sdarrenr case SW_VGA_C80x25: case SW_VGA_M80x25: 667170268Sdarrenr case SW_VGA_C80x30: case SW_VGA_M80x30: 668170268Sdarrenr case SW_VGA_C80x50: case SW_VGA_M80x50: 669170268Sdarrenr case SW_VGA_C80x60: case SW_VGA_M80x60: 670145522Sdarrenr case SW_VGA_C90x25: case SW_VGA_M90x25: 671145522Sdarrenr case SW_VGA_C90x30: case SW_VGA_M90x30: 672145522Sdarrenr case SW_VGA_C90x43: case SW_VGA_M90x43: 673255332Scy case SW_VGA_C90x50: case SW_VGA_M90x50: 674255332Scy case SW_VGA_C90x60: case SW_VGA_M90x60: 675255332Scy case SW_B40x25: case SW_C40x25: 676255332Scy case SW_B80x25: case SW_C80x25: 677255332Scy case SW_ENH_B40x25: case SW_ENH_C40x25: 678255332Scy case SW_ENH_B80x25: case SW_ENH_C80x25: 679255332Scy case SW_ENH_B80x43: case SW_ENH_C80x43: 680255332Scy case SW_EGAMONO80x25: 681255332Scy 682255332Scy#ifdef PC98 683255332Scy /* PC98 TEXT MODES */ 684255332Scy case SW_PC98_80x25: 685255332Scy case SW_PC98_80x30: 686255332Scy#endif 687145522Sdarrenr if (!(adp->va_flags & V_ADP_MODECHANGE)) 688145522Sdarrenr return ENODEV; 689145522Sdarrenr return sc_set_text_mode(scp, tp, cmd & 0xff, 0, 0, 0, 0); 69053642Sguido 691145522Sdarrenr /* GRAPHICS MODES */ 69253642Sguido case SW_BG320: case SW_BG640: 693255332Scy case SW_CG320: case SW_CG320_D: case SW_CG640_E: 694255332Scy case SW_CG640x350: case SW_ENH_CG640: 695255332Scy case SW_BG640x480: case SW_CG640x480: case SW_VGA_CG320: 696255332Scy case SW_VGA_MODEX: 697145522Sdarrenr#ifdef PC98 698255332Scy /* PC98 GRAPHICS MODES */ 699255332Scy case SW_PC98_EGC640x400: case SW_PC98_PEGC640x400: 700145522Sdarrenr case SW_PC98_PEGC640x480: 701145522Sdarrenr#endif 702255332Scy if (!(adp->va_flags & V_ADP_MODECHANGE)) 703255332Scy return ENODEV; 704255332Scy return sc_set_graphics_mode(scp, tp, cmd & 0xff); 705145522Sdarrenr#endif /* SC_NO_MODE_CHANGE */ 706255332Scy 707255332Scy#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 70853642Sguido defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 709170268Sdarrenr case _IO('K', 10): 710170268Sdarrenr ival = IOCPARM_IVAL(data); 711170268Sdarrenr data = (caddr_t)&ival; 712170268Sdarrenr /* FALLTHROUGH */ 713170268Sdarrenr#endif 714170268Sdarrenr case KDSETMODE: /* set current mode of this (virtual) console */ 715170268Sdarrenr switch (*(int *)data) { 71653642Sguido case KD_TEXT: /* switch to TEXT (known) mode */ 71753642Sguido /* 71853642Sguido * If scp->mode is of graphics modes, we don't know which 71953642Sguido * text mode to switch back to... 72053642Sguido */ 721145522Sdarrenr if (scp->status & GRAPHICS_MODE) 72253642Sguido return EINVAL; 723145522Sdarrenr /* restore fonts & palette ! */ 724255332Scy#if 0 725255332Scy#ifndef SC_NO_FONT_LOADING 72653642Sguido if (ISFONTAVAIL(adp->va_flags) 727255332Scy && !(scp->status & (GRAPHICS_MODE | PIXEL_MODE))) 728255332Scy /* 729255332Scy * FONT KLUDGE 730255332Scy * Don't load fonts for now... XXX 731145522Sdarrenr */ 73253642Sguido if (scp->sc->fonts_loaded & FONT_8) 733145522Sdarrenr sc_load_font(scp, 0, 8, 8, scp->sc->font_8, 0, 256); 734145522Sdarrenr if (scp->sc->fonts_loaded & FONT_14) 735255332Scy sc_load_font(scp, 0, 14, 8, scp->sc->font_14, 0, 256); 736145522Sdarrenr if (scp->sc->fonts_loaded & FONT_16) 737145522Sdarrenr sc_load_font(scp, 0, 16, 8, scp->sc->font_16, 0, 256); 738145522Sdarrenr } 73953642Sguido#endif /* SC_NO_FONT_LOADING */ 740145522Sdarrenr#endif 741145522Sdarrenr 742145522Sdarrenr#ifndef SC_NO_PALETTE_LOADING 743145522Sdarrenr#ifdef SC_PIXEL_MODE 744145522Sdarrenr if ((adp->va_flags & V_ADP_DAC8) != 0) 745145522Sdarrenr vidd_load_palette(adp, scp->sc->palette2); 746255332Scy else 74753642Sguido#endif 748145522Sdarrenr vidd_load_palette(adp, scp->sc->palette); 749145522Sdarrenr#endif 750255332Scy 75160851Sdarrenr#ifndef PC98 752255332Scy /* move hardware cursor out of the way */ 75360851Sdarrenr vidd_set_hw_cursor(adp, -1, -1); 754255332Scy#endif 755255332Scy 756255332Scy /* FALLTHROUGH */ 757255332Scy 758255332Scy case KD_TEXT1: /* switch to TEXT (known) mode */ 759145522Sdarrenr /* 760145522Sdarrenr * If scp->mode is of graphics modes, we don't know which 761145522Sdarrenr * text/pixel mode to switch back to... 762145522Sdarrenr */ 763255332Scy if (scp->status & GRAPHICS_MODE) 764145522Sdarrenr return EINVAL; 765255332Scy s = spltty(); 766255332Scy if ((error = sc_clean_up(scp))) { 767255332Scy splx(s); 768255332Scy return error; 769255332Scy } 770255332Scy#ifndef PC98 771255332Scy scp->status |= UNKNOWN_MODE | MOUSE_HIDDEN; 772255332Scy splx(s); 773255332Scy /* no restore fonts & palette */ 774255332Scy if (scp == scp->sc->cur_scp) 77553642Sguido set_mode(scp); 77653642Sguido sc_clear_screen(scp); 777255332Scy scp->status &= ~UNKNOWN_MODE; 778145522Sdarrenr#else /* PC98 */ 779145522Sdarrenr scp->status &= ~UNKNOWN_MODE; 780145522Sdarrenr /* no restore fonts & palette */ 781145522Sdarrenr if (scp == scp->sc->cur_scp) 782145522Sdarrenr set_mode(scp); 783145522Sdarrenr sc_clear_screen(scp); 784145522Sdarrenr splx(s); 785145522Sdarrenr#endif /* PC98 */ 786145522Sdarrenr return 0; 787145522Sdarrenr 788145522Sdarrenr#ifdef SC_PIXEL_MODE 789145522Sdarrenr case KD_PIXEL: /* pixel (raster) display */ 790145522Sdarrenr if (!(scp->status & (GRAPHICS_MODE | PIXEL_MODE))) 79153642Sguido return EINVAL; 792145522Sdarrenr if (scp->status & GRAPHICS_MODE) 79353642Sguido return sc_set_pixel_mode(scp, tp, scp->xsize, scp->ysize, 794145522Sdarrenr scp->font_size, scp->font_width); 79553642Sguido s = spltty(); 796145522Sdarrenr if ((error = sc_clean_up(scp))) { 79760851Sdarrenr splx(s); 79860851Sdarrenr return error; 79960851Sdarrenr } 80060851Sdarrenr scp->status |= (UNKNOWN_MODE | PIXEL_MODE | MOUSE_HIDDEN); 80160851Sdarrenr splx(s); 80260851Sdarrenr if (scp == scp->sc->cur_scp) { 80360851Sdarrenr set_mode(scp); 80460851Sdarrenr#ifndef SC_NO_PALETTE_LOADING 80560851Sdarrenr if ((adp->va_flags & V_ADP_DAC8) != 0) 806255332Scy vidd_load_palette(adp, scp->sc->palette2); 807145522Sdarrenr else 80860851Sdarrenr vidd_load_palette(adp, scp->sc->palette); 809255332Scy#endif 810145522Sdarrenr } 81160851Sdarrenr sc_clear_screen(scp); 812255332Scy scp->status &= ~UNKNOWN_MODE; 813145522Sdarrenr return 0; 81460851Sdarrenr#endif /* SC_PIXEL_MODE */ 815255332Scy 816145522Sdarrenr case KD_GRAPHICS: /* switch to GRAPHICS (unknown) mode */ 817145522Sdarrenr s = spltty(); 818145522Sdarrenr if ((error = sc_clean_up(scp))) { 819170268Sdarrenr splx(s); 820170268Sdarrenr return error; 821170268Sdarrenr } 822170268Sdarrenr scp->status |= UNKNOWN_MODE | MOUSE_HIDDEN; 823145522Sdarrenr splx(s); 824145522Sdarrenr#ifdef PC98 825170268Sdarrenr if (scp == scp->sc->cur_scp) 826170268Sdarrenr set_mode(scp); 827145522Sdarrenr#endif 828145522Sdarrenr return 0; 829145522Sdarrenr 830145522Sdarrenr default: 831145522Sdarrenr return EINVAL; 832145522Sdarrenr } 833145522Sdarrenr /* NOT REACHED */ 834145522Sdarrenr 835145522Sdarrenr#ifdef SC_PIXEL_MODE 836145522Sdarrenr case KDRASTER: /* set pixel (raster) display mode */ 837255332Scy if (ISUNKNOWNSC(scp) || ISTEXTSC(scp)) 838255332Scy return ENODEV; 839145522Sdarrenr return sc_set_pixel_mode(scp, tp, ((int *)data)[0], ((int *)data)[1], 840145522Sdarrenr ((int *)data)[2], 8); 84192685Sdarrenr#endif /* SC_PIXEL_MODE */ 84292685Sdarrenr 843145522Sdarrenr case KDGETMODE: /* get current mode of this (virtual) console */ 844145522Sdarrenr /* 84553642Sguido * From the user program's point of view, KD_PIXEL is the same 846145522Sdarrenr * as KD_TEXT... 84753642Sguido */ 848145522Sdarrenr *data = ISGRAPHSC(scp) ? KD_GRAPHICS : KD_TEXT; 849145522Sdarrenr return 0; 850255332Scy 851145522Sdarrenr#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 852145522Sdarrenr defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 853145522Sdarrenr case _IO('K', 13): 85453642Sguido ival = IOCPARM_IVAL(data); 85553642Sguido data = (caddr_t)&ival; 85653642Sguido /* FALLTHROUGH */ 85753642Sguido#endif 858145522Sdarrenr case KDSBORDER: /* set border color of this (virtual) console */ 859145522Sdarrenr scp->border = *(int *)data; 860145522Sdarrenr if (scp == scp->sc->cur_scp) 861145522Sdarrenr sc_set_border(scp, scp->border); 862255332Scy return 0; 863255332Scy } 864145522Sdarrenr 86553642Sguido return ENOIOCTL; 86653642Sguido} 86753642Sguido 868145522Sdarrenrstatic LIST_HEAD(, sc_renderer) sc_rndr_list = 869145522Sdarrenr LIST_HEAD_INITIALIZER(sc_rndr_list); 870145522Sdarrenr 871145522Sdarrenrint 872145522Sdarrenrsc_render_add(sc_renderer_t *rndr) 873145522Sdarrenr{ 874145522Sdarrenr LIST_INSERT_HEAD(&sc_rndr_list, rndr, link); 875145522Sdarrenr return 0; 876145522Sdarrenr} 877145522Sdarrenr 878145522Sdarrenrint 879145522Sdarrenrsc_render_remove(sc_renderer_t *rndr) 880145522Sdarrenr{ 881145522Sdarrenr /* 882145522Sdarrenr LIST_REMOVE(rndr, link); 88353642Sguido */ 884255332Scy return EBUSY; /* XXX */ 885145522Sdarrenr} 886145522Sdarrenr 887145522Sdarrenrsc_rndr_sw_t 888145522Sdarrenr*sc_render_match(scr_stat *scp, char *name, int mode) 889145522Sdarrenr{ 890255332Scy const sc_renderer_t **list; 891255332Scy const sc_renderer_t *p; 892145522Sdarrenr 893145522Sdarrenr if (!LIST_EMPTY(&sc_rndr_list)) { 894145522Sdarrenr LIST_FOREACH(p, &sc_rndr_list, link) { 895145522Sdarrenr if ((strcmp(p->name, name) == 0) 896145522Sdarrenr && (mode == p->mode)) { 89753642Sguido scp->status &= 89853642Sguido ~(VR_CURSOR_ON | VR_CURSOR_BLINK); 899145522Sdarrenr return p->rndrsw; 900145522Sdarrenr } 901145522Sdarrenr } 902145522Sdarrenr } else { 903145522Sdarrenr SET_FOREACH(list, scrndr_set) { 904145522Sdarrenr p = *list; 905255332Scy if ((strcmp(p->name, name) == 0) 906145522Sdarrenr && (mode == p->mode)) { 907145522Sdarrenr scp->status &= 90853642Sguido ~(VR_CURSOR_ON | VR_CURSOR_BLINK); 90953642Sguido return p->rndrsw; 91053642Sguido } 91153642Sguido } 91253642Sguido } 91353642Sguido 91453642Sguido return NULL; 91553642Sguido} 91653642Sguido