/* * Mach Operating System * Copyright (c) 1991,1990,1989 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie Mellon * the rights to redistribute these changes. */ /* * File: pm_misc.c * Author: Alessandro Forin, Carnegie Mellon University * Date: 9/90 * * Driver for the VFB01/02 Mono/Color framebuffer (pmax) * Hardware-independent operations, mostly shared with * the CFB driver (see each individual function header), * and possibly others. */ #include #include #if defined(DECSTATION) || defined(FLAMINGO) #include #include #include #include #define NPM (NFB+NCFB+NMFB+NXCFB+NSFB) #endif /*DECSTATION*/ #ifdef VAXSTATION #define NPM (NFB) #endif /*VAXSTATION*/ #if (NPM > 0) #include /* PAGE_SIZE */ #include #include /* kernel_pmap */ #include #include #ifdef DECSTATION #define machine_btop mips_btop #define MONO_BM (256*1024) #endif /*DECSTATION*/ #ifdef VAXSTATION #define machine_btop vax_btop /* For now we use the last page of the frame for the user_info structure. */ #define MONO_BM (256*1024-PAGE_SIZE) #endif /*VAXSTATION*/ #ifdef FLAMINGO #define machine_btop alpha_btop #define MONO_BM (256*1024) #define LOG2_SIZEOF_LONG 3 /* 64bit archies */ #endif /* FLAMINGO */ #ifndef LOG2_SIZEOF_LONG #define LOG2_SIZEOF_LONG 2 /* 32bit archies */ #endif /* Hardware state */ pm_softc_t pm_softc_data[NPM]; pm_softc_t* pm_alloc( int unit, char *cur, unsigned char *fb, unsigned char *pl) { pm_softc_t *pm = &pm_softc_data[unit]; pm->cursor_registers = cur; pm->framebuffer = fb; pm->plane_mask = pl; pm->vdac_registers = 0; /* later, if ever */ screen_attach(unit, (char *) pm); return pm; } /* * Routine to paint a char on a simple framebuffer. * This is common to the pm, fb and cfb drivers. */ pm_char_paint( screen_softc_t sc, int c, int row, int col) { register int incr; int line_size; register unsigned char *font, *bmap; pm_softc_t *pm = (pm_softc_t*)sc->hw_state; /* * Here are the magic numbers that drive the loops below: * incr bytes between scanlines of the glyph * line_size bytes in a row, using the system font * * This code has been optimized to avoid multiplications, * and is therefore much less obvious than it could be. */ if (sc->flags & MONO_SCREEN) { /* * B&W screen: 1 bit/pixel * incr --> 1 * BytesPerLine, with possible stride */ incr = sc->frame_scanline_width >> 3; } else { /* * Color screen: 8 bits/pixel * incr --> 8 * BytesPerLine, with possible stride */ incr = sc->frame_scanline_width; col <<= 3; } /* not all compilers are smart about multiply by 15 */ #if (KfontHeight==15) # define TIMES_KfontHeight(w) (((w)<<4)-(w)) #else # define TIMES_KfontHeight(w) ((w)*KfontHeight) #endif line_size = TIMES_KfontHeight(incr); bmap = pm->framebuffer + col + (row * line_size); font = &kfont_7x14[ (int)(c - ' ') * 15]; if (sc->flags & MONO_SCREEN) { /* * Unroll simple loops, take note of common cases */ if (sc->standout) { # define mv() *bmap = ~*font++; bmap += incr; mv();mv();mv();mv();mv();mv();mv();mv(); mv();mv();mv();mv();mv();mv();mv(); # undef mv } else if (c == ' ') { # define mv() *bmap = 0; bmap += incr; mv();mv();mv();mv();mv();mv();mv();mv(); mv();mv();mv();mv();mv();mv();mv(); # undef mv } else { # define mv() *bmap = *font++; bmap += incr; mv();mv();mv();mv();mv();mv();mv();mv(); mv();mv();mv();mv();mv();mv();mv(); # undef mv } } else { /* * 8 bits per pixel --> paint one byte per each font bit. * In order to spread out the 8 bits of a glyph line over * the 64 bits per scanline use a simple vector multiply, * taking 4 bits at a time to get the two resulting words */ static unsigned int spread[16] = { 0x00000000, 0x00000001, 0x00000100, 0x00000101, 0x00010000, 0x00010001, 0x00010100, 0x00010101, 0x01000000, 0x01000001, 0x01000100, 0x01000101, 0x01010000, 0x01010001, 0x01010100, 0x01010101, }; register int rev_video = sc->standout; register int j; for (j = 0; j < KfontHeight; j++) { register unsigned char c = *font++; if (rev_video) c = ~c; #if (LOG2_SIZEOF_LONG==3) *((long*)bmap) = (long)spread[ c & 0xf ] | ((long)(spread[ (c>>4) & 0xf ]) << 32); #else ((int*)bmap)[0] = spread[ c & 0xf ]; ((int*)bmap)[1] = spread[ (c>>4) & 0xf ]; #endif bmap += incr; } } } /* * Delete the line at the given row. * This is common to the pm, fb and cfb drivers. */ pm_remove_line( screen_softc_t sc, short row) { register long *dest, *src; register long *end; register long temp0,temp1,temp2,temp3; register long i, scaninc, blockcnt; long line_size, incr; unsigned char *framebuffer; pm_softc_t *pm = (pm_softc_t*)sc->hw_state; long CharRows, CharCols; CharRows = sc->up->max_row; CharCols = sc->up->max_col; framebuffer = pm->framebuffer; /* Inner loop works 4 long words at a time (writebuffer deep) */ # define BlockSizeShift (2+LOG2_SIZEOF_LONG) /* To copy one (MONO) line, we need to iterate this many times */ # define Blocks (CharCols>>BlockSizeShift) /* Skip this many bytes to get to the next line */ # define Slop(w) ((w) - (blockcnt<flags & MONO_SCREEN) { blockcnt = Blocks; /* See comments in pm_char_paint() */ incr = sc->frame_scanline_width >> 3; } else { blockcnt = Blocks << 3; /* See comments in pm_char_paint() */ incr = sc->frame_scanline_width; } line_size = TIMES_KfontHeight(incr); scaninc = (Slop(incr)) >> LOG2_SIZEOF_LONG; /* pointers are long* */ dest = (long *)(framebuffer + row * line_size); src = (long *)((char*)dest + line_size); end = (long *)(framebuffer + CharRows * line_size); while (src < end) { i = 0; do { temp0 = src[0]; temp1 = src[1]; temp2 = src[2]; temp3 = src[3]; dest[0] = temp0; dest[1] = temp1; dest[2] = temp2; dest[3] = temp3; dest += 4; src += 4; i++; } while (i < blockcnt); src += scaninc; dest += scaninc; } /* Now zero out the last line */ bzero(framebuffer + (CharRows - 1) * line_size, line_size); ascii_screen_rem_update(sc, row); } /* * Open a new blank line at the given row. * This is common to the pm, fb and cfb drivers. */ pm_insert_line( screen_softc_t sc, short row) { register long *dest, *src; register long *end; register long temp0,temp1,temp2,temp3; register long i, scaninc, blockcnt; long line_size, incr; unsigned char *framebuffer; pm_softc_t *pm = (pm_softc_t*)sc->hw_state; long CharRows, CharCols; CharRows = sc->up->max_row; CharCols = sc->up->max_col; framebuffer = pm->framebuffer; /* See above for comments */ if (sc->flags & MONO_SCREEN) { blockcnt = Blocks; /* See comments in pm_char_paint() */ incr = sc->frame_scanline_width >> 3; } else { blockcnt = Blocks << 3; /* See comments in pm_char_paint() */ incr = sc->frame_scanline_width; } line_size = TIMES_KfontHeight(incr); scaninc = Slop(incr) + ((2 * blockcnt) << BlockSizeShift); scaninc >>= LOG2_SIZEOF_LONG; /* pointers are long* */ dest = (long *)(framebuffer + (CharRows - 1) * line_size); src = (long *)((char*)dest - line_size); end = (long *)(framebuffer + row * line_size); while (src >= end) { i = 0; do { temp0 = src[0]; temp1 = src[1]; temp2 = src[2]; temp3 = src[3]; dest[0] = temp0; dest[1] = temp1; dest[2] = temp2; dest[3] = temp3; dest += 4; src += 4; i++; } while (i < blockcnt); src -= scaninc; dest -= scaninc; } /* Now zero out the line being opened */ bzero(framebuffer + row * line_size, line_size); ascii_screen_ins_update(sc, row); } #undef Slop /* * Initialize screen parameters in the * user-mapped descriptor. * This is common to various drivers. */ pm_init_screen_params( screen_softc_t sc, user_info_t *up) { register int vis_x, vis_y; up->frame_scanline_width = sc->frame_scanline_width; up->frame_height = sc->frame_height; vis_x = sc->frame_visible_width; vis_y = sc->frame_visible_height; up->max_x = vis_x; up->max_y = vis_y; up->max_cur_x = vis_x - 1; up->max_cur_y = vis_y - 1; up->min_cur_x = -15; up->min_cur_y = -15; up->max_row = vis_y / KfontHeight; up->max_col = vis_x / KfontWidth; up->version = 11; up->mouse_threshold = 4; up->mouse_scale = 2; up->dev_dep_2.pm.tablet_scale_x = ((vis_x - 1) * 1000) / 2200; up->dev_dep_2.pm.tablet_scale_y = ((vis_y - 1) * 1000) / 2200; } /* * Clear the screen * Used by pm, fb and cfb */ pm_clear_bitmap( screen_softc_t sc) { pm_softc_t *pm = (pm_softc_t *) sc->hw_state; unsigned int screen_size; /* Do not touch the non visible part */ screen_size = sc->frame_scanline_width * sc->frame_visible_height; blkclr((char *)pm->framebuffer, (sc->flags & MONO_SCREEN) ? (screen_size>>3) : screen_size); /* clear ascii screenmap */ ascii_screen_fill(sc, ' '); } /* * Size of the user-mapped structure * Used by both pm and cfb */ pm_mem_need() { return USER_INFO_SIZE; } /* * Device-specific get status. * Used by fb and cfb also. */ pm_get_status( screen_softc_t sc, dev_flavor_t flavor, dev_status_t status, natural_t *status_count) { if (flavor == SCREEN_GET_OFFSETS) { unsigned *offs = (unsigned *) status; offs[0] = PM_SIZE(sc); /* virtual size */ offs[1] = 0; /* offset of user_info_t */ *status_count = 2; return D_SUCCESS; } else return D_INVALID_OPERATION; } /* * Driver-specific set status * Only partially used by fb and cfb. */ pm_set_status( screen_softc_t sc, dev_flavor_t flavor, dev_status_t status, natural_t status_count) { switch (flavor) { case SCREEN_ADJ_MAPPED_INFO: { unsigned user_addr = *(unsigned *) status; user_info_t *up = sc->up; /* Make it point to the event_queue, in user virtual */ up->evque.events = (screen_event_t *)(user_addr + ((char*)up->event_queue - (char*)up)); /* Make it point to the point_track, in user virtual */ up->evque.track = (screen_timed_point_t *)(user_addr + ((char*)up->point_track - (char*)up)); up->dev_dep_1.pm.planemask = (unsigned char *)(user_addr + USER_INFO_SIZE); up->dev_dep_1.pm.bitmap = up->dev_dep_1.pm.planemask + PMASK_SIZE; break; } case SCREEN_LOAD_CURSOR: { sc->flags |= SCREEN_BEING_UPDATED; dc503_load_cursor(sc->hw_state, (unsigned short*)status); sc->flags &= ~SCREEN_BEING_UPDATED; break; } #ifdef DECSTATION case SCREEN_SET_CURSOR_COLOR: { pm_softc_t *pm = (pm_softc_t*) sc->hw_state; sc->flags |= SCREEN_BEING_UPDATED; bt478_cursor_color (pm->vdac_registers, (cursor_color_t*) status); sc->flags &= ~SCREEN_BEING_UPDATED; break; } case SCREEN_SET_CMAP_ENTRY: { pm_softc_t *pm = (pm_softc_t*) sc->hw_state; color_map_entry_t *e = (color_map_entry_t*) status; if (e->index < 256) { sc->flags |= SCREEN_BEING_UPDATED; bt478_load_colormap_entry( pm->vdac_registers, e->index, &e->value); sc->flags &= ~SCREEN_BEING_UPDATED; } break; } #endif /*DECSTATION*/ default: return D_INVALID_OPERATION; } return D_SUCCESS; } /* * Map pages to user space */ vm_offset_t pm_map_page_empty = (vm_offset_t) 0; integer_t pm_map_page( screen_softc_t sc, vm_offset_t off, int prot) { int bitmapsize; integer_t addr; pm_softc_t *pm = (pm_softc_t *)sc->hw_state; extern vm_offset_t pmap_extract( pmap_t map, vm_offset_t addr); bitmapsize = BITMAP_SIZE(sc); #define OFF0 USER_INFO_SIZE /* user mapped info */ #define OFF1 OFF0+PMASK_SIZE /* plane mask register */ #define OFF2 OFF1+bitmapsize /* frame buffer mem */ if (off < OFF0) #ifdef DECSTATION addr = kvtophys(sc->up); #else addr = (integer_t) pmap_extract(kernel_pmap, (vm_offset_t)sc->up); #endif else if (off < OFF1) { #ifdef VAXSTATION if (pm_map_page_empty == 0) { pm_map_page_empty = vm_page_grab_phys_addr(); } addr = (integer_t)pmap_extract(kernel_pmap, pm_map_page_empty); #else addr = (integer_t) pm->plane_mask; #endif off -= OFF0; } else if (off < OFF2) { #ifdef DECSTATION addr = (integer_t)pm->framebuffer; #else addr = (integer_t)pmap_extract(kernel_pmap, (vm_offset_t)pm->framebuffer); #endif off -= OFF1; } else return D_INVALID_SIZE; /* ??? */ addr = machine_btop(addr + off); return (addr); } /* *----------------------------------------------------------- * The rest of this file is stricly pmax/pvax-specific *----------------------------------------------------------- */ #if (NFB > 0) /* * Do what's needed when the X server exits */ pm_soft_reset( screen_softc_t sc) { pm_softc_t *pm = (pm_softc_t*) sc->hw_state; user_info_t *up = sc->up; /* * Restore params in mapped structure */ pm_init_screen_params(sc, up); up->row = up->max_row - 2; dc503_init(pm); #ifdef DECSTATION if (sc->flags & MONO_SCREEN) bt478_init_bw_map(pm->vdac_registers, pm->plane_mask); else bt478_init_color_map(pm->vdac_registers, pm->plane_mask); #endif /*DECSTATION*/ } #endif /* NFB > 0 */ #endif /* NPM > 0 */