xboxfb.c revision 152219
11558Srgrimes/*- 21558Srgrimes * Copyright (c) 2005 Rink Springer 31558Srgrimes * All rights reserved. 41558Srgrimes * 51558Srgrimes * Redistribution and use in source and binary forms, with or without 61558Srgrimes * modification, are permitted provided that the following conditions 71558Srgrimes * are met: 81558Srgrimes * 1. Redistributions of source code must retain the above copyright 91558Srgrimes * notice, this list of conditions and the following disclaimer. 101558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111558Srgrimes * notice, this list of conditions and the following disclaimer in the 121558Srgrimes * documentation and/or other materials provided with the distribution. 131558Srgrimes * 3. The name of the author may not be used to endorse or promote products 141558Srgrimes * derived from this software without specific prior written permission 151558Srgrimes * 161558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 171558Srgrimes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 181558Srgrimes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 191558Srgrimes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 201558Srgrimes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 211558Srgrimes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 221558Srgrimes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 231558Srgrimes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 241558Srgrimes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 251558Srgrimes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 261558Srgrimes * 271558Srgrimes * $FreeBSD: head/sys/i386/xbox/xboxfb.c 152219 2005-11-09 03:55:40Z imp $ 281558Srgrimes */ 291558Srgrimes 30114589Sobrien/* 311558Srgrimes * This will handles video output using the XBOX' frame buffer. It assumes 3238036Scharnier * the graphics have been set up by Cromwell. This driver uses all video memory 331558Srgrimes * to avoid expensive memcpy()'s. 341558Srgrimes * 351558Srgrimes * It is usuable as console (to see the initial boot) as well as for interactive 361558Srgrimes * use. The latter is handeled using kbd_*() functionality. Keyboard hotplug is 371558Srgrimes * fully supported, the console will periodically rescan if no keyboard was 3841684Sbde * found. 39114589Sobrien * 4038036Scharnier */ 41114589Sobrien#include <sys/param.h> 42114589Sobrien#include <sys/systm.h> 431558Srgrimes#include <vm/vm_param.h> 441558Srgrimes#include <sys/kernel.h> 451558Srgrimes#include <sys/cons.h> 461558Srgrimes#include <sys/conf.h> 471558Srgrimes#include <sys/consio.h> 481558Srgrimes#include <sys/tty.h> 491558Srgrimes#include <sys/kbio.h> 5038036Scharnier#include <sys/fbio.h> 511558Srgrimes#include <dev/kbd/kbdreg.h> 52114763Sobrien#include <vm/vm.h> 531558Srgrimes#include <vm/pmap.h> 541558Srgrimes#include <machine/bus.h> 551558Srgrimes#include <machine/xbox.h> 561558Srgrimes#include <dev/fb/fbreg.h> 571558Srgrimes#include <dev/fb/gfb.h> 581558Srgrimes 591558Srgrimes#define SCREEN_WIDTH 640 601558Srgrimes#define SCREEN_HEIGHT 480 611558Srgrimes#define SCREEN_BPP 4 621558Srgrimes#define SCREEN_SIZE (SCREEN_WIDTH*SCREEN_HEIGHT*SCREEN_BPP) 631558Srgrimes 641558Srgrimes/* FONT_xxx declares the dimensions of the charachter structure, CHAR_xxx is how 651558Srgrimes * they appear on-screen. Having slightly more spacing improves readability. */ 661558Srgrimes#define FONT_HEIGHT 16 671558Srgrimes#define FONT_WIDTH 8 681558Srgrimes 691558Srgrimes#define CHAR_HEIGHT 16 701558Srgrimes#define CHAR_WIDTH 10 711558Srgrimes 721558Srgrimes#define RAM_SIZE (arch_i386_xbox_memsize * 1024 * 1024) 7332399Salex#define FB_SIZE (0x400000) 7432399Salex#define FB_START (0xf0000000 | (RAM_SIZE - FB_SIZE)) 7532399Salex#define FB_START_PTR (0xFD600800) 7632399Salex 7732399Salex/* colours */ 7832399Salex#define CONSOLE_COL 0xFF88FF88 /* greenish */ 7932399Salex#define NORM_COL 0xFFAAAAAA /* grayish */ 8032399Salex#define BLACK_COL 0x00000000 /* black */ 8132399Salex 8232399Salexstatic int xcon_x = 0; 8332399Salexstatic int xcon_y = 0; 8432399Salexstatic int xcon_yoffs = 0; 851558Srgrimes 861558Srgrimesextern struct gfb_font bold8x16; 871558Srgrimes 881558Srgrimesstatic char* xcon_map; 891558Srgrimesstatic int* xcon_memstartptr; 901558Srgrimes 9148078Srustatic struct tty* xboxfb_tp = NULL; 9279749Sddstatic struct keyboard* xbfb_kbd = NULL; 9379749Sddstatic int xbfb_keyboard = -1; 941558Srgrimesstatic d_open_t xboxfb_dev_open; 9592883Simpstatic d_close_t xboxfb_dev_close; 9692883Simpstatic int xboxfb_kbdevent(keyboard_t* thiskbd, int event, void* arg); 9792883Simp 9892883Simpstatic struct cdevsw xboxfb_cdevsw = { 9992883Simp .d_version = D_VERSION, 10092883Simp .d_open = xboxfb_dev_open, 10192883Simp .d_close = xboxfb_dev_close, 10292883Simp .d_name = "xboxfb", 10392883Simp .d_flags = D_TTY | D_NEEDGIANT, 1041558Srgrimes}; 105140796Sdelphij 106140796Sdelphijstatic void 1071558Srgrimesxcon_probe(struct consdev* cp) 108140796Sdelphij{ 1091558Srgrimes if (arch_i386_is_xbox) 11079749Sdd cp->cn_pri = CN_REMOTE; 1111558Srgrimes else 1121558Srgrimes cp->cn_pri = CN_DEAD; 1131558Srgrimes} 1141558Srgrimes 11526737Scharnierstatic int 11626737Scharnierxcon_getc(struct consdev* cp) 1171558Srgrimes{ 1181558Srgrimes return 0; 1191558Srgrimes} 12048078Sru 1211558Srgrimesstatic int 1221558Srgrimesxcon_checkc(struct consdev* cp) 1231558Srgrimes{ 1241558Srgrimes return 0; 1251558Srgrimes} 1261558Srgrimes 1271558Srgrimesstatic void 1281558Srgrimesxcon_real_putc(int basecol, int c) 1291558Srgrimes{ 1301558Srgrimes int i, j, ch = c, col; 1311558Srgrimes char mask; 1321558Srgrimes int* ptri = (int*)xcon_map; 1331558Srgrimes 13448078Sru /* special control chars */ 13548078Sru switch (ch) { 13648078Sru case '\r': /* carriage return */ 13741666Smsmith xcon_x = 0; 13841666Smsmith return; 13941666Smsmith case '\n': /* newline */ 1401558Srgrimes xcon_y += CHAR_HEIGHT; 1411558Srgrimes goto scroll; 1421558Srgrimes case 7: /* beep */ 1431558Srgrimes return; 1441558Srgrimes case 8: /* backspace */ 14548078Sru if (xcon_x > 0) { 1461558Srgrimes xcon_x -= CHAR_WIDTH; 1471558Srgrimes } else { 1481558Srgrimes if (xcon_y > CHAR_HEIGHT) { 1491558Srgrimes xcon_y -= CHAR_HEIGHT; 1501558Srgrimes xcon_x = (SCREEN_WIDTH - CHAR_WIDTH); 15148078Sru } 1521558Srgrimes } 15348078Sru return; 15448078Sru case 9: /* tab */ 15548062Sjkoshy xcon_real_putc (basecol, ' '); 15648078Sru while ((xcon_x % (8 * CHAR_WIDTH)) != 0) { 15748078Sru xcon_real_putc (basecol, ' '); 15848062Sjkoshy } 15948078Sru return; 16048078Sru } 16148078Sru ptri += (xcon_y * SCREEN_WIDTH) + xcon_x; 1621558Srgrimes 1631558Srgrimes /* we plot the font pixel-by-pixel. bit 7 is skipped as it renders the 1641558Srgrimes * console unreadable ... */ 1651558Srgrimes for (i = 0; i < FONT_HEIGHT; i++) { 1661558Srgrimes mask = 0x40; 1671558Srgrimes for (j = 0; j < FONT_WIDTH; j++) { 1681558Srgrimes col = (bold8x16.data[(ch * FONT_HEIGHT) + i] & mask) ? basecol : BLACK_COL; 1691558Srgrimes *ptri++ = col; 1701558Srgrimes mask >>= 1; 17141684Sbde } 1721558Srgrimes ptri += (SCREEN_WIDTH - FONT_WIDTH); 1731558Srgrimes } 1741558Srgrimes 1751558Srgrimes xcon_x += CHAR_WIDTH; 1761558Srgrimes if (xcon_x >= SCREEN_WIDTH) { 1771558Srgrimes xcon_x = 0; 1781558Srgrimes xcon_y += CHAR_HEIGHT; 1791558Srgrimes } 1801558Srgrimes 1811558Srgrimesscroll: 1821558Srgrimes if (((xcon_yoffs + CHAR_HEIGHT) * SCREEN_WIDTH * SCREEN_BPP) > (FB_SIZE - SCREEN_SIZE)) { 1831558Srgrimes /* we are about to run out of video memory, so move everything 1841558Srgrimes * back to the beginning of the video memory */ 1851558Srgrimes memcpy ((char*)xcon_map, 1861558Srgrimes (char*)(xcon_map + (xcon_yoffs * SCREEN_WIDTH * SCREEN_BPP)), 1871558Srgrimes SCREEN_SIZE); 1881558Srgrimes xcon_y -= xcon_yoffs; xcon_yoffs = 0; 1891558Srgrimes *xcon_memstartptr = FB_START; 1901558Srgrimes } 1911558Srgrimes 1921558Srgrimes /* we achieve much faster scrolling by just altering the video memory 1931558Srgrimes * address base. once all memory is used, we return to the beginning 1941558Srgrimes * again */ 1951558Srgrimes while ((xcon_y - xcon_yoffs) >= SCREEN_HEIGHT) { 1961558Srgrimes xcon_yoffs += CHAR_HEIGHT; 1971558Srgrimes memset ((char*)(xcon_map + (xcon_y * SCREEN_WIDTH * SCREEN_BPP)), 0, CHAR_HEIGHT * SCREEN_WIDTH * SCREEN_BPP); 1981558Srgrimes *xcon_memstartptr = FB_START + (xcon_yoffs * SCREEN_WIDTH * SCREEN_BPP); 1991558Srgrimes } 2001558Srgrimes} 2011558Srgrimes 2021558Srgrimesstatic void 2031558Srgrimesxcon_putc(struct consdev* cp, int c) 2041558Srgrimes{ 2051558Srgrimes xcon_real_putc (CONSOLE_COL, c); 2061558Srgrimes} 2071558Srgrimes 2081558Srgrimesstatic void 2091558Srgrimesxcon_init(struct consdev* cp) 21026737Scharnier{ 21126737Scharnier int i; 21226737Scharnier int* iptr; 21326737Scharnier 2141558Srgrimes /* Don't init the framebuffer on non-XBOX-es */ 21528613Sjoerg if (!arch_i386_is_xbox) 2161558Srgrimes return; 2171558Srgrimes 2181558Srgrimes /* 21938036Scharnier * We must make a mapping from video framebuffer memory to real. This is 2201558Srgrimes * very crude: we map the entire videomemory to PAGE_SIZE! Since our 2211558Srgrimes * kernel lives at it's relocated address range (0xc0xxxxxx), it won't 2221558Srgrimes * care. 2231558Srgrimes * 2241558Srgrimes * We use address PAGE_SIZE and up so we can still trap NULL pointers. 2251558Srgrimes * Once xboxfb_drvinit() is called, the mapping will be done via the OS 2261558Srgrimes * and stored in a more sensible location ... but since we're not fully 2271558Srgrimes * initialized, this is our only way to go :-( 2281558Srgrimes */ 2291558Srgrimes for (i = 0; i < (FB_SIZE / PAGE_SIZE); i++) { 2301558Srgrimes pmap_kenter (((i + 1) * PAGE_SIZE), FB_START + (i * PAGE_SIZE)); 2311558Srgrimes } 2321558Srgrimes pmap_kenter ((i + 1) * PAGE_SIZE, FB_START_PTR - FB_START_PTR % PAGE_SIZE); 2331558Srgrimes xcon_map = (char*)PAGE_SIZE; 2341558Srgrimes xcon_memstartptr = (int*)((i + 1) * PAGE_SIZE + FB_START_PTR % PAGE_SIZE); 2351558Srgrimes 2361558Srgrimes /* clear the screen */ 2371558Srgrimes iptr = (int*)xcon_map; 2381558Srgrimes for (i = 0; i < SCREEN_HEIGHT * SCREEN_WIDTH; i++) 23948004Sru *iptr++ = BLACK_COL; 2401558Srgrimes 2411558Srgrimes sprintf(cp->cn_name, "xboxfb"); 2421558Srgrimes cp->cn_tp = xboxfb_tp; 2431558Srgrimes} 2441558Srgrimes 24532399Salexstatic void 24679749Sddxboxfb_timer(void* arg) 2471558Srgrimes{ 2481558Srgrimes int i; 2491558Srgrimes 2501558Srgrimes if (xbfb_kbd != NULL) 2511558Srgrimes return; 2521558Srgrimes 2531558Srgrimes i = kbd_allocate ("*", 0, (void*)&xbfb_keyboard, xboxfb_kbdevent, NULL); 2541558Srgrimes if (i != -1) { 2551558Srgrimes /* allocation was successfull; xboxfb_kbdevent() is called to 2561558Srgrimes * feed the keystrokes to the tty driver */ 2571558Srgrimes xbfb_kbd = kbd_get_keyboard (i); 2581558Srgrimes xbfb_keyboard = i; 2591558Srgrimes return; 2601558Srgrimes } 2611558Srgrimes 2621558Srgrimes /* probe again in a few */ 2631558Srgrimes timeout (xboxfb_timer, NULL, hz / 10); 2641558Srgrimes} 2651558Srgrimes 26679749Sddstatic int 26732399Salexxboxfb_kbdevent(keyboard_t* thiskbd, int event, void* arg) 26832399Salex{ 26932399Salex int c; 27032399Salex 2711558Srgrimes if (event == KBDIO_UNLOADING) { 272140797Sdelphij /* keyboard was unplugged; clean up and enable probing */ 2731558Srgrimes xbfb_kbd = NULL; 2741558Srgrimes xbfb_keyboard = -1; 2751558Srgrimes kbd_release (thiskbd, (void*)&xbfb_keyboard); 2761558Srgrimes timeout (xboxfb_timer, NULL, hz / 10); 2771558Srgrimes return 0; 2781558Srgrimes } 2791558Srgrimes 2801558Srgrimes for (;;) { 2811558Srgrimes c = (kbdsw[xbfb_kbd->kb_index])->read_char (xbfb_kbd, 0); 2821558Srgrimes if (c == NOKEY) 2831558Srgrimes return 0; 28432399Salex 2851558Srgrimes /* only feed non-special keys to an open console */ 2861558Srgrimes if (c != ERRKEY) { 2871558Srgrimes if ((KEYFLAGS(c)) == 0x0) 2881558Srgrimes if (xboxfb_tp->t_state & TS_ISOPEN) 2891558Srgrimes ttyld_rint (xboxfb_tp, KEYCHAR(c)); 2901558Srgrimes } 2911558Srgrimes } 2921558Srgrimes 2931558Srgrimes return 0; 2941558Srgrimes} 2951558Srgrimes 2961558Srgrimesstatic void 2971558Srgrimesxboxfb_drvinit (void* unused) 2981558Srgrimes{ 2991558Srgrimes struct cdev* dev; 3001558Srgrimes int i; 3011558Srgrimes 3021558Srgrimes /* Don't init the framebuffer on non-XBOX-es */ 3031558Srgrimes if (!arch_i386_is_xbox) 3041558Srgrimes return; 3051558Srgrimes 3061558Srgrimes /* 3071558Srgrimes * When this function is called, the OS is capable of doing 3081558Srgrimes * device-memory mappings using pmap_mapdev(). Therefore, we ditch the 3091558Srgrimes * ugly PAGE_SIZE-based mapping and ask the OS to create a decent 31038036Scharnier * mapping for us. 3111558Srgrimes */ 3121558Srgrimes dev = make_dev (&xboxfb_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "%s", "xboxfb"); 3131558Srgrimes xcon_map = pmap_mapdev (FB_START, FB_SIZE); 3141558Srgrimes xcon_memstartptr = (int*)pmap_mapdev (FB_START_PTR, PAGE_SIZE); 3151558Srgrimes *xcon_memstartptr = FB_START; 3161558Srgrimes 3171558Srgrimes /* ditch all ugly previous mappings */ 3181558Srgrimes for (i = 0; i < (FB_SIZE / PAGE_SIZE); i++) { 3191558Srgrimes pmap_kremove (((i + 1) * PAGE_SIZE)); 3201558Srgrimes } 3211558Srgrimes pmap_kremove (PAGE_SIZE + FB_SIZE); 322140797Sdelphij 3231558Srgrimes /* probe for a keyboard */ 3241558Srgrimes xboxfb_timer (NULL); 3251558Srgrimes} 3261558Srgrimes 3271558Srgrimesstatic void 3281558Srgrimesxboxfb_tty_start(struct tty* tp) 3291558Srgrimes{ 33032399Salex struct clist* cl; 3311558Srgrimes int len, i; 3321558Srgrimes u_char buf[128]; 33341666Smsmith 33441666Smsmith if (tp->t_state & TS_BUSY) 3351558Srgrimes return; 3361558Srgrimes 3371558Srgrimes /* simply feed all outstanding tty data to real_putc() */ 3381558Srgrimes tp->t_state |= TS_BUSY; 3391558Srgrimes cl = &tp->t_outq; 3404844Sats len = q_to_b(cl, buf, 128); 3411558Srgrimes for (i = 0; i < len; i++) 3421558Srgrimes xcon_real_putc(NORM_COL, buf[i]); 3431558Srgrimes tp->t_state &= ~TS_BUSY; 3441558Srgrimes} 3451558Srgrimes 3461558Srgrimesstatic void 34741666Smsmithxboxfb_tty_stop(struct tty* tp, int flag) { 34841666Smsmith if (tp->t_state & TS_BUSY) 34948078Sru if ((tp->t_state & TS_TTSTOP) == 0) 3501558Srgrimes tp->t_state |= TS_FLUSH; 3511558Srgrimes} 3521558Srgrimes 35348078Srustatic int 35448078Sruxboxfb_tty_param(struct tty* tp, struct termios* t) 35548078Sru{ 35648078Sru return 0; 35748078Sru} 35848078Sru 35948078Srustatic int 36048078Sruxboxfb_dev_open(struct cdev* dev, int flag, int mode, struct thread* td) 36148078Sru{ 36248078Sru struct tty* tp; 36348078Sru 36448078Sru tp = xboxfb_tp = dev->si_tty = ttymalloc (xboxfb_tp); 36548078Sru 36648078Sru tp->t_oproc = xboxfb_tty_start; 36748078Sru tp->t_param = xboxfb_tty_param; 36848078Sru tp->t_stop = xboxfb_tty_stop; 36948078Sru tp->t_dev = dev; 37048078Sru 37148078Sru if ((tp->t_state & TS_ISOPEN) == 0) { 37248078Sru tp->t_state |= TS_CARR_ON; 37348078Sru ttychars(tp); 37448078Sru tp->t_iflag = TTYDEF_IFLAG; 37548078Sru tp->t_oflag = TTYDEF_OFLAG; 37648078Sru tp->t_cflag = TTYDEF_CFLAG | CLOCAL; 37748078Sru tp->t_lflag = TTYDEF_LFLAG; 37848078Sru tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 37948078Sru ttsetwater(tp); 38048078Sru } 3811558Srgrimes 3821558Srgrimes return ttyld_open (tp, dev); 3831558Srgrimes} 3841558Srgrimes 3851558Srgrimesstatic int 3861558Srgrimesxboxfb_dev_close(struct cdev* dev, int flag, int mode, struct thread* td) 3871558Srgrimes{ 3881558Srgrimes struct tty* tp; 389140797Sdelphij 3901558Srgrimes tp = xboxfb_tp; 39179749Sdd ttyld_close (tp, flag); 39279749Sdd tty_close(tp); 3931558Srgrimes return 0; 39432328Salex} 3951558Srgrimes 39648062SjkoshySYSINIT(xboxfbdev, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE, xboxfb_drvinit, NULL) 39748062Sjkoshy 3981558SrgrimesCONS_DRIVER(xcon, xcon_probe, xcon_init, NULL, xcon_getc, xcon_checkc, xcon_putc, NULL); 3991558Srgrimes