Index: linux-2.6.25.20-source/drivers/video/console/cocon.c =================================================================== --- /dev/null +++ linux-2.6.25.20-source/drivers/video/console/cocon.c @@ -0,0 +1,488 @@ +/* + * linux/drivers/video/cocon.c -- Cooperative Linux console VGA driver + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + * + * Based on code copied from vgacon.c. + * + * Dan Aloni , 2003-2004 (c) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * Interface used by the world + */ + +static int cocon_cols = 80; +static int cocon_rows = 25; +static int cocon_attr = 0x07; /* fg=white, bg=black */ + +static const char __init *cocon_startup(void) +{ + unsigned long flags; + co_console_message_t *message; + co_message_t *co_message; + + co_message = co_send_message_save(&flags); + if (co_message) { + message = (co_console_message_t *)co_message->data; + co_message->from = CO_MODULE_LINUX; + co_message->to = CO_MODULE_CONSOLE; + co_message->priority = CO_PRIORITY_DISCARDABLE; + co_message->type = CO_MESSAGE_TYPE_STRING; + co_message->size = ((char *)(&message->type + 1)) - ((char *)message); + message->type = CO_OPERATION_CONSOLE_STARTUP; + co_switch_wrapper(); + if (message->type == CO_OPERATION_CONSOLE_CONFIG) { + cocon_cols = message->config.cols; + cocon_rows = message->config.rows; + cocon_attr = message->config.attr; + } + co_passage_page_release(flags); + } + + return "CoCON"; +} + +static void cocon_init(struct vc_data *c, int init) +{ + unsigned long flags; + co_console_message_t *message; + co_message_t *co_message; + + /* We cannot be loaded as a module, therefore init is always 1 */ + c->vc_can_do_color = 1; + c->vc_cols = cocon_cols; + c->vc_rows = cocon_rows; + + /* drivers/char/vt.c: Must hack vc_init() for vc_def_color */ + c->vc_def_color = cocon_attr; + + c->vc_complement_mask = 0x7700; + c->vc_visible_origin = 0; + c->vc_origin = 0; + + co_message = co_send_message_save(&flags); + if (!co_message) + return; + + message = (co_console_message_t *)co_message->data; + co_message->from = CO_MODULE_LINUX; + co_message->to = CO_MODULE_CONSOLE; + co_message->priority = CO_PRIORITY_DISCARDABLE; + co_message->type = CO_MESSAGE_TYPE_STRING; + co_message->size = ((char *)(&message->type + 1)) - ((char *)message); + message->type = CO_OPERATION_CONSOLE_INIT; + co_send_message_restore(flags); +} + +static void cocon_deinit(struct vc_data *c) +{ + unsigned long flags; + co_console_message_t *message; + co_message_t *co_message; + + co_message = co_send_message_save(&flags); + if (!co_message) + return; + + message = (co_console_message_t *)co_message->data; + co_message->from = CO_MODULE_LINUX; + co_message->to = CO_MODULE_CONSOLE; + co_message->priority = CO_PRIORITY_DISCARDABLE; + co_message->type = CO_MESSAGE_TYPE_STRING; + co_message->size = ((char *)(&message->type + 1)) - ((char *)message); + message->type = CO_OPERATION_CONSOLE_DEINIT; + co_send_message_restore(flags); + +} + +static void cocon_clear(struct vc_data *c, int top, int left, int rows, int cols) +{ + unsigned long flags; + co_console_message_t *message; + co_message_t *co_message; + + co_message = co_send_message_save(&flags); + if (!co_message) + return; + + message = (co_console_message_t *)co_message->data; + co_message->from = CO_MODULE_LINUX; + co_message->to = CO_MODULE_CONSOLE; + co_message->priority = CO_PRIORITY_DISCARDABLE; + co_message->type = CO_MESSAGE_TYPE_STRING; + co_message->size = ((char *)(&message->clear + 1)) - ((char *)message); + message->type = CO_OPERATION_CONSOLE_CLEAR; + message->clear.top = top; + message->clear.left = left; + message->clear.bottom = top + rows - 1; + message->clear.right = left + cols - 1; + message->clear.charattr = c->vc_video_erase_char; + co_send_message_restore(flags); +} + +static void cocon_putc(struct vc_data *c, int charattr, int y, int x) +{ + unsigned long flags; + co_message_t *co_message; + co_console_message_t *message; + + co_message = co_send_message_save(&flags); + if (!co_message) + return; + + message = (co_console_message_t *)co_message->data; + co_message->from = CO_MODULE_LINUX; + co_message->to = CO_MODULE_CONSOLE; + co_message->priority = CO_PRIORITY_DISCARDABLE; + co_message->type = CO_MESSAGE_TYPE_STRING; + co_message->size = ((char *)(&message->putc + 1)) - ((char *)message); + message->type = CO_OPERATION_CONSOLE_PUTC; + message->putc.x = x; + message->putc.y = y; + message->putc.charattr = charattr; + co_send_message_restore(flags); +} + + +static void cocon_putcs(struct vc_data *conp, + const unsigned short *s, int count, int yy, int xx) +{ + unsigned long flags; + co_console_message_t *message; + co_message_t *co_message; + + if (count > CO_MAX_PARAM_SIZE/2 - 16) + return; + + co_message = co_send_message_save(&flags); + if (!co_message) + return; + + message = (co_console_message_t *)co_message->data; + co_message->from = CO_MODULE_LINUX; + co_message->to = CO_MODULE_CONSOLE; + co_message->priority = CO_PRIORITY_DISCARDABLE; + co_message->type = CO_MESSAGE_TYPE_STRING; + co_message->size = ((char *)(&message->putcs + 1)) - ((char *)message) + + count * sizeof(unsigned short); + message->type = CO_OPERATION_CONSOLE_PUTCS; + message->putcs.x = xx; + message->putcs.y = yy; + message->putcs.count = count; + memcpy(&message->putcs.data, s, count * sizeof(unsigned short)); + co_send_message_restore(flags); +} + +static u8 cocon_build_attr(struct vc_data *c, u8 color, u8 intensity, u8 blink, u8 underline, u8 reverse, u8 italic) +{ + u8 attr = color; + + if (underline) + attr = (attr & 0xf0) | c->vc_ulcolor; + else if (intensity == 0) + attr = (attr & 0xf0) | c->vc_halfcolor; + if (reverse) + attr = ((attr) & 0x88) | ((((attr) >> 4) | ((attr) << 4)) & 0x77); + if (blink) + attr ^= 0x80; + if (intensity == 2) + attr ^= 0x08; + + return attr; +} + +static void cocon_invert_region(struct vc_data *c, u16 *p, int count) +{ + unsigned long flags; + co_message_t *co_message; + co_console_message_t *message; + unsigned long x = (unsigned long)(p - c->vc_origin); // UPDATE: vc_origin = 0; but not yet + + co_message = co_send_message_save(&flags); + if (co_message) { + message = (co_console_message_t *)co_message->data; + co_message->from = CO_MODULE_LINUX; + co_message->to = CO_MODULE_CONSOLE; + co_message->priority = CO_PRIORITY_DISCARDABLE; + co_message->type = CO_MESSAGE_TYPE_STRING; + co_message->size = ((char *)(&message->invert + 1)) - ((char *)message); + message->type = CO_OPERATION_CONSOLE_INVERT_REGION; + message->invert.y = ((unsigned)x)/c->vc_cols; + message->invert.x = ((unsigned)x)-(message->invert.y); + message->invert.count = count; + co_send_message_restore(flags); + } + + while (count--) { + u16 a = scr_readw(p); + a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4); + scr_writew(a, p++); + } + +} + +static void cocon_cursor(struct vc_data *c, int mode) +{ + unsigned long flags; + co_console_message_t *message; + co_message_t *co_message; + + co_message = co_send_message_save(&flags); + if (!co_message) + return; + + message = (co_console_message_t *)co_message->data; + co_message->from = CO_MODULE_LINUX; + co_message->to = CO_MODULE_CONSOLE; + co_message->priority = CO_PRIORITY_DISCARDABLE; + co_message->type = CO_MESSAGE_TYPE_STRING; + co_message->size = ((char *)(&message->cursor + 1)) - ((char *)message);; + if (mode==CM_ERASE) { + message->type = CO_OPERATION_CONSOLE_CURSOR_ERASE; + message->cursor.height = CUR_NONE; + co_send_message_restore(flags); + return; + } + + if(mode==CM_MOVE) { + message->type = CO_OPERATION_CONSOLE_CURSOR_MOVE; + } else /*(mode==CM_DRAW)*/ { + message->type = CO_OPERATION_CONSOLE_CURSOR_DRAW; + } + message->cursor.x = c->vc_x; + message->cursor.y = c->vc_y; + message->cursor.height = c->vc_cursor_type & CUR_HWMASK; + + co_send_message_restore(flags); +} + +static int cocon_switch(struct vc_data *c) +{ + unsigned long flags; + co_console_message_t *message; + co_message_t *co_message; + + co_message = co_send_message_save(&flags); + if (co_message) { + message = (co_console_message_t *)co_message->data; + co_message->from = CO_MODULE_LINUX; + co_message->to = CO_MODULE_CONSOLE; + co_message->priority = CO_PRIORITY_DISCARDABLE; + co_message->type = CO_MESSAGE_TYPE_STRING; + co_message->size = ((char *)(&message->type + 1)) - ((char *)message); + message->type = CO_OPERATION_CONSOLE_SWITCH; + co_send_message_restore(flags); + } + + return 1; /* Redrawing not needed */ +} + +static int cocon_set_palette(struct vc_data *c, unsigned char *table) +{ + unsigned long flags; + co_console_message_t *message; + co_message_t *co_message; + + co_message = co_send_message_save(&flags); + if (co_message) { + message = (co_console_message_t *)co_message->data; + co_message->from = CO_MODULE_LINUX; + co_message->to = CO_MODULE_CONSOLE; + co_message->priority = CO_PRIORITY_DISCARDABLE; + co_message->type = CO_MESSAGE_TYPE_STRING; + co_message->size = ((char *)(&message->type + 1)) - ((char *)message); + message->type = CO_OPERATION_CONSOLE_SET_PALETTE; + co_send_message_restore(flags); + } + + return 1; +} + +static int cocon_blank(struct vc_data *c, int blank, int mode_switchg) +{ + unsigned long flags; + co_console_message_t *message; + co_message_t *co_message; + + co_message = co_send_message_save(&flags); + if (co_message) { + message = (co_console_message_t *)co_message->data; + co_message->from = CO_MODULE_LINUX; + co_message->to = CO_MODULE_CONSOLE; + co_message->priority = CO_PRIORITY_DISCARDABLE; + co_message->type = CO_MESSAGE_TYPE_STRING; + co_message->size = ((char *)(&message->type + 1)) - ((char *)message); + message->type = CO_OPERATION_CONSOLE_BLANK; + co_send_message_restore(flags); + } + + return 1; +} + + +static int cocon_scrolldelta(struct vc_data *c, int lines) +{ + unsigned long flags; + co_console_message_t *message; + co_message_t *co_message; + + co_message = co_send_message_save(&flags); + if (co_message) { + message = (co_console_message_t *)co_message->data; + co_message->from = CO_MODULE_LINUX; + co_message->to = CO_MODULE_CONSOLE; + co_message->priority = CO_PRIORITY_DISCARDABLE; + co_message->type = CO_MESSAGE_TYPE_STRING; + co_message->size = ((char *)(&message->type + 1)) - ((char *)message); + message->type = CO_OPERATION_CONSOLE_SCROLLDELTA; + co_send_message_restore(flags); + } + + return 1; +} + +static int cocon_set_origin(struct vc_data *c) +{ + unsigned long flags; + co_console_message_t *message; + co_message_t *co_message; + + co_message = co_send_message_save(&flags); + if (co_message) { + message = (co_console_message_t *)co_message->data; + co_message->from = CO_MODULE_LINUX; + co_message->to = CO_MODULE_CONSOLE; + co_message->priority = CO_PRIORITY_DISCARDABLE; + co_message->type = CO_MESSAGE_TYPE_STRING; + co_message->size = ((char *)(&message->type + 1)) - ((char *)message); + message->type = CO_OPERATION_CONSOLE_SET_ORIGIN; + co_send_message_restore(flags); + } + + return 1; +} + +static void cocon_save_screen(struct vc_data *c) +{ + unsigned long flags; + co_console_message_t *message; + co_message_t *co_message; + + co_message = co_send_message_save(&flags); + if (co_message) { + message = (co_console_message_t *)co_message->data; + co_message->from = CO_MODULE_LINUX; + co_message->to = CO_MODULE_CONSOLE; + co_message->priority = CO_PRIORITY_DISCARDABLE; + co_message->type = CO_MESSAGE_TYPE_STRING; + co_message->size = ((char *)(&message->type + 1)) - ((char *)message); + message->type = CO_OPERATION_CONSOLE_SAVE_SCREEN; + co_send_message_restore(flags); + } +} + +static int cocon_scroll(struct vc_data *c, int t, int b, int dir, int lines) +{ + unsigned long flags; + co_console_message_t *message; + co_message_t *co_message; + + co_message = co_send_message_save(&flags); + if (co_message) { + message = (co_console_message_t *)co_message->data; + co_message->from = CO_MODULE_LINUX; + co_message->to = CO_MODULE_CONSOLE; + co_message->priority = CO_PRIORITY_DISCARDABLE; + co_message->type = CO_MESSAGE_TYPE_STRING; + co_message->size = ((char *)(&message->scroll + 1)) - ((char *)message); + if (dir == SM_UP) + message->type = CO_OPERATION_CONSOLE_SCROLL_UP; + else + message->type = CO_OPERATION_CONSOLE_SCROLL_DOWN; + message->scroll.top = t; + message->scroll.bottom = b-1; + message->scroll.lines = lines; + message->scroll.charattr = c->vc_video_erase_char; + co_send_message_restore(flags); + } + + return 0; +} + +static void cocon_bmove(struct vc_data *c, int sy, int sx, int dy, int dx, int h, int w) +{ + unsigned long flags; + co_console_message_t *message; + co_message_t *co_message; + + co_message = co_send_message_save(&flags); + if (!co_message) + return; + + message = (co_console_message_t *)co_message->data; + co_message->from = CO_MODULE_LINUX; + co_message->to = CO_MODULE_CONSOLE; + co_message->priority = CO_PRIORITY_DISCARDABLE; + co_message->type = CO_MESSAGE_TYPE_STRING; + co_message->size = ((char *)(&message->bmove + 1)) - ((char *)message); + message->type = CO_OPERATION_CONSOLE_BMOVE; + message->bmove.row = dy; + message->bmove.column = dx; + message->bmove.top = sy; + message->bmove.left = sx; + message->bmove.bottom = sy + h - 1; + message->bmove.right = sx + w - 1; + co_send_message_restore(flags); +} + +static int cocon_resize(struct vc_data *c, unsigned int width, + unsigned int height) +{ + return -EINVAL; +} + +/* + * The console `switch' structure for the VGA based console + */ + +const struct consw colinux_con = { + con_startup: cocon_startup, + con_init: cocon_init, + con_deinit: cocon_deinit, + con_clear: cocon_clear, + con_putc: cocon_putc, + con_putcs: cocon_putcs, + con_cursor: cocon_cursor, + con_scroll: cocon_scroll, + con_bmove: cocon_bmove, + con_switch: cocon_switch, + con_blank: cocon_blank, + con_resize: cocon_resize, + con_set_palette: cocon_set_palette, + con_scrolldelta: cocon_scrolldelta, + con_set_origin: cocon_set_origin, + con_save_screen: cocon_save_screen, + con_build_attr: cocon_build_attr, + con_invert_region: cocon_invert_region, +}; + +MODULE_LICENSE("GPL");