📄 sisusb_con.c
字号:
if (sisusb_is_inactive(c, sisusb) || sisusb->con_blanked) { up(&sisusb->lock); return 0; } c->vc_origin = c->vc_visible_origin = sisusb->scrbuf; sisusbcon_set_start_address(sisusb, c); sisusb->con_rolled_over = 0; up(&sisusb->lock); return 1;}/* Interface routine */static intsisusbcon_resize(struct vc_data *c, unsigned int newcols, unsigned int newrows){ struct sisusb_usb_data *sisusb; int fh; if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num))) return -ENODEV; fh = sisusb->current_font_height; up(&sisusb->lock); /* We are quite unflexible as regards resizing. The vt code * handles sizes where the line length isn't equal the pitch * quite badly. As regards the rows, our panning tricks only * work well if the number of rows equals the visible number * of rows. */ if (newcols != 80 || c->vc_scan_lines / fh != newrows) return -EINVAL; return 0;}intsisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot, u8 *arg, int cmapsz, int ch512, int dorecalc, struct vc_data *c, int fh, int uplock){ int font_select = 0x00, i, err = 0; u32 offset = 0; u8 dummy; /* sisusb->lock is down */ /* * The default font is kept in slot 0. * A user font is loaded in slot 2 (256 ch) * or 2+3 (512 ch). */ if ((slot != 0 && slot != 2) || !fh) { if (uplock) up(&sisusb->lock); return -EINVAL; } if (set) sisusb->font_slot = slot; /* Default font is always 256 */ if (slot == 0) ch512 = 0; else offset = 4 * cmapsz; font_select = (slot == 0) ? 0x00 : (ch512 ? 0x0e : 0x0a); err |= sisusb_setidxreg(sisusb, SISSR, 0x00, 0x01); /* Reset */ err |= sisusb_setidxreg(sisusb, SISSR, 0x02, 0x04); /* Write to plane 2 */ err |= sisusb_setidxreg(sisusb, SISSR, 0x04, 0x07); /* Memory mode a0-bf */ err |= sisusb_setidxreg(sisusb, SISSR, 0x00, 0x03); /* Reset */ if (err) goto font_op_error; err |= sisusb_setidxreg(sisusb, SISGR, 0x04, 0x03); /* Select plane read 2 */ err |= sisusb_setidxreg(sisusb, SISGR, 0x05, 0x00); /* Disable odd/even */ err |= sisusb_setidxreg(sisusb, SISGR, 0x06, 0x00); /* Address range a0-bf */ if (err) goto font_op_error; if (arg) { if (set) for (i = 0; i < cmapsz; i++) { err |= sisusb_writeb(sisusb, sisusb->vrambase + offset + i, arg[i]); if (err) break; } else for (i = 0; i < cmapsz; i++) { err |= sisusb_readb(sisusb, sisusb->vrambase + offset + i, &arg[i]); if (err) break; } /* * In 512-character mode, the character map is not contiguous if * we want to remain EGA compatible -- which we do */ if (ch512) { if (set) for (i = 0; i < cmapsz; i++) { err |= sisusb_writeb(sisusb, sisusb->vrambase + offset + (2 * cmapsz) + i, arg[cmapsz + i]); if (err) break; } else for (i = 0; i < cmapsz; i++) { err |= sisusb_readb(sisusb, sisusb->vrambase + offset + (2 * cmapsz) + i, &arg[cmapsz + i]); if (err) break; } } } if (err) goto font_op_error; err |= sisusb_setidxreg(sisusb, SISSR, 0x00, 0x01); /* Reset */ err |= sisusb_setidxreg(sisusb, SISSR, 0x02, 0x03); /* Write to planes 0+1 */ err |= sisusb_setidxreg(sisusb, SISSR, 0x04, 0x03); /* Memory mode a0-bf */ if (set) sisusb_setidxreg(sisusb, SISSR, 0x03, font_select); err |= sisusb_setidxreg(sisusb, SISSR, 0x00, 0x03); /* Reset end */ if (err) goto font_op_error; err |= sisusb_setidxreg(sisusb, SISGR, 0x04, 0x00); /* Select plane read 0 */ err |= sisusb_setidxreg(sisusb, SISGR, 0x05, 0x10); /* Enable odd/even */ err |= sisusb_setidxreg(sisusb, SISGR, 0x06, 0x06); /* Address range b8-bf */ if (err) goto font_op_error; if ((set) && (ch512 != sisusb->current_font_512)) { /* Font is shared among all our consoles. * And so is the hi_font_mask. */ for (i = 0; i < MAX_NR_CONSOLES; i++) { struct vc_data *c = vc_cons[i].d; if (c && c->vc_sw == &sisusb_con) c->vc_hi_font_mask = ch512 ? 0x0800 : 0; } sisusb->current_font_512 = ch512; /* color plane enable register: 256-char: enable intensity bit 512-char: disable intensity bit */ sisusb_getreg(sisusb, SISINPSTAT, &dummy); sisusb_setreg(sisusb, SISAR, 0x12); sisusb_setreg(sisusb, SISAR, ch512 ? 0x07 : 0x0f); sisusb_getreg(sisusb, SISINPSTAT, &dummy); sisusb_setreg(sisusb, SISAR, 0x20); sisusb_getreg(sisusb, SISINPSTAT, &dummy); } if (dorecalc) { /* * Adjust the screen to fit a font of a certain height */ unsigned char ovr, vde, fsr; int rows = 0, maxscan = 0; if (c) { /* Number of video rows */ rows = c->vc_scan_lines / fh; /* Scan lines to actually display-1 */ maxscan = rows * fh - 1; /*printk(KERN_DEBUG "sisusb recalc rows %d maxscan %d fh %d sl %d\n", rows, maxscan, fh, c->vc_scan_lines);*/ sisusb_getidxreg(sisusb, SISCR, 0x07, &ovr); vde = maxscan & 0xff; ovr = (ovr & 0xbd) | ((maxscan & 0x100) >> 7) | ((maxscan & 0x200) >> 3); sisusb_setidxreg(sisusb, SISCR, 0x07, ovr); sisusb_setidxreg(sisusb, SISCR, 0x12, vde); } sisusb_getidxreg(sisusb, SISCR, 0x09, &fsr); fsr = (fsr & 0xe0) | (fh - 1); sisusb_setidxreg(sisusb, SISCR, 0x09, fsr); sisusb->current_font_height = fh; sisusb->sisusb_cursor_size_from = -1; sisusb->sisusb_cursor_size_to = -1; } if (uplock) up(&sisusb->lock); if (dorecalc && c) { int i, rows = c->vc_scan_lines / fh; /* Now adjust our consoles' size */ for (i = 0; i < MAX_NR_CONSOLES; i++) { struct vc_data *vc = vc_cons[i].d; if (vc && vc->vc_sw == &sisusb_con) { if (CON_IS_VISIBLE(vc)) { vc->vc_sw->con_cursor(vc, CM_DRAW); } vc->vc_font.height = fh; vc_resize(vc, 0, rows); } } } return 0;font_op_error: if (uplock) up(&sisusb->lock); return -EIO;}/* Interface routine */static intsisusbcon_font_set(struct vc_data *c, struct console_font *font, unsigned flags){ struct sisusb_usb_data *sisusb; unsigned charcount = font->charcount; if (font->width != 8 || (charcount != 256 && charcount != 512)) return -EINVAL; if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num))) return -ENODEV; /* sisusb->lock is down */ /* Save the user-provided font into a buffer. This * is used for restoring text mode after quitting * from X and for the con_getfont routine. */ if (sisusb->font_backup) { if (sisusb->font_backup_size < charcount) { vfree(sisusb->font_backup); sisusb->font_backup = NULL; } } if (!sisusb->font_backup) sisusb->font_backup = vmalloc(charcount * 32); if (sisusb->font_backup) { memcpy(sisusb->font_backup, font->data, charcount * 32); sisusb->font_backup_size = charcount; sisusb->font_backup_height = font->height; sisusb->font_backup_512 = (charcount == 512) ? 1 : 0; } /* do_font_op ups sisusb->lock */ return sisusbcon_do_font_op(sisusb, 1, 2, font->data, 8192, (charcount == 512), (!(flags & KD_FONT_FLAG_DONT_RECALC)) ? 1 : 0, c, font->height, 1);}/* Interface routine */static intsisusbcon_font_get(struct vc_data *c, struct console_font *font){ struct sisusb_usb_data *sisusb; if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num))) return -ENODEV; /* sisusb->lock is down */ font->width = 8; font->height = c->vc_font.height; font->charcount = 256; if (!font->data) { up(&sisusb->lock); return 0; } if (!sisusb->font_backup) { up(&sisusb->lock); return -ENODEV; } /* Copy 256 chars only, like vgacon */ memcpy(font->data, sisusb->font_backup, 256 * 32); up(&sisusb->lock); return 0;}/* * The console `switch' structure for the sisusb console */static const struct consw sisusb_con = { .owner = THIS_MODULE, .con_startup = sisusbcon_startup, .con_init = sisusbcon_init, .con_deinit = sisusbcon_deinit, .con_clear = sisusbcon_clear, .con_putc = sisusbcon_putc, .con_putcs = sisusbcon_putcs, .con_cursor = sisusbcon_cursor, .con_scroll = sisusbcon_scroll, .con_bmove = sisusbcon_bmove, .con_switch = sisusbcon_switch, .con_blank = sisusbcon_blank, .con_font_set = sisusbcon_font_set, .con_font_get = sisusbcon_font_get, .con_set_palette = sisusbcon_set_palette, .con_scrolldelta = sisusbcon_scrolldelta, .con_build_attr = sisusbcon_build_attr, .con_invert_region = sisusbcon_invert_region, .con_set_origin = sisusbcon_set_origin, .con_save_screen = sisusbcon_save_screen, .con_resize = sisusbcon_resize,};/* Our very own dummy console driver */static const char *sisusbdummycon_startup(void){ return "SISUSBVGADUMMY";}static void sisusbdummycon_init(struct vc_data *vc, int init){ vc->vc_can_do_color = 1; if (init) { vc->vc_cols = 80; vc->vc_rows = 25; } else vc_resize(vc, 80, 25);}static int sisusbdummycon_dummy(void){ return 0;}#define SISUSBCONDUMMY (void *)sisusbdummycon_dummyconst struct consw sisusb_dummy_con = { .owner = THIS_MODULE, .con_startup = sisusbdummycon_startup, .con_init = sisusbdummycon_init, .con_deinit = SISUSBCONDUMMY, .con_clear = SISUSBCONDUMMY, .con_putc = SISUSBCONDUMMY, .con_putcs = SISUSBCONDUMMY, .con_cursor = SISUSBCONDUMMY, .con_scroll = SISUSBCONDUMMY, .con_bmove = SISUSBCONDUMMY, .con_switch = SISUSBCONDUMMY, .con_blank = SISUSBCONDUMMY, .con_font_set = SISUSBCONDUMMY, .con_font_get = SISUSBCONDUMMY, .con_font_default = SISUSBCONDUMMY, .con_font_copy = SISUSBCONDUMMY, .con_set_palette = SISUSBCONDUMMY, .con_scrolldelta = SISUSBCONDUMMY,};intsisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last){ int i, ret, minor = sisusb->minor; down(&disconnect_sem); down(&sisusb->lock); /* Erm.. that should not happen */ if (sisusb->haveconsole || !sisusb->SiS_Pr) { up(&sisusb->lock); up(&disconnect_sem); return 1; } sisusb->con_first = first; sisusb->con_last = last; if (first > last || first > MAX_NR_CONSOLES || last > MAX_NR_CONSOLES) { up(&sisusb->lock); up(&disconnect_sem); return 1; } /* If gfxcore not initialized or no consoles given, quit graciously */ if (!sisusb->gfxinit || first < 1 || last < 1) { up(&sisusb->lock); up(&disconnect_sem); return 0; } sisusb->sisusb_cursor_loc = -1; sisusb->sisusb_cursor_size_from = -1; sisusb->sisusb_cursor_size_to = -1; /* Set up text mode (and upload default font) */ if (sisusb_reset_text_mode(sisusb, 1)) { up(&sisusb->lock); up(&disconnect_sem); printk(KERN_ERR "sisusbvga[%d]: Failed to set up text mode\n", minor); return 1; } /* Initialize some gfx registers */ sisusb_initialize(sisusb); for (i = first - 1; i <= last - 1; i++) { /* Save sisusb for our interface routines */ mysisusbs[i] = sisusb; } /* Initial console setup */ sisusb->sisusb_num_columns = 80; /* Use a 32K buffer (matches b8000-bffff area) */ sisusb->scrbuf_size = 32 * 1024; /* Allocate screen buffer */ if (!(sisusb->scrbuf = (unsigned long)vmalloc(sisusb->scrbuf_size))) { up(&sisusb->lock); up(&disconnect_sem); printk(KERN_ERR "sisusbvga[%d]: Failed to allocate screen buffer\n", minor); return 1; } up(&sisusb->lock); up(&disconnect_sem); /* Now grab the desired console(s) */ ret = take_over_console(&sisusb_con, first - 1, last - 1, 0); if (!ret) sisusb->haveconsole = 1; else { for (i = first - 1; i <= last - 1; i++) mysisusbs[i] = NULL; } return ret;}voidsisusb_console_exit(struct sisusb_usb_data *sisusb){ int i; /* This is called if the device is disconnected * and while disconnect and lock semaphores * are up. This should be save because we * can't lose our sisusb any other way but by * disconnection (and hence, the disconnect * sema is for protecting all other access * functions from disconnection, not the * other way round). */ /* Now what do we do in case of disconnection: * One alternative would be to simply call * give_up_console(). Nah, not a good idea. * give_up_console() is obviously buggy as it * only discards the consw pointer from the * driver_map, but doesn't adapt vc->vc_sw * of the affected consoles. Hence, the next * call to any of the console functions will * eventually take a trip to oops county. * Also, give_up_console for some reason * doesn't decrement our module refcount. * Instead, we switch our consoles to a private * dummy console. This, of course, keeps our * refcount up as well, but it works perfectly. */ if (sisusb->haveconsole) { for (i = 0; i < MAX_NR_CONSOLES; i++) if (sisusb->havethisconsole[i]) take_over_console(&sisusb_dummy_con, i, i, 0); /* At this point, con_deinit for all our * consoles is executed by take_over_console(). */ sisusb->haveconsole = 0; } vfree((void *)sisusb->scrbuf); sisusb->scrbuf = 0; vfree(sisusb->font_backup); sisusb->font_backup = NULL;}void __init sisusb_init_concode(void){ int i; for (i = 0; i < MAX_NR_CONSOLES; i++) mysisusbs[i] = NULL;}#endif /* INCL_CON */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -