📄 vgacon_lcd.c
字号:
{ u16 i; lcd_num_columns = LCD_NUM_COLUMNS; lcd_num_lines = LCD_NUM_LINES; lcd_vram_base = (unsigned long)vram; lcd_vram_len = 0x2000; lcd_data_port = 0x378; lcd_status_port = lcd_data_port+1; lcd_control_port = lcd_data_port+2; lcd_type = TYPE_LCD; lcd_type_name = "generic Toshiba T6963C"; // initialize control port CEHI; // disable chip RDHI; // disable reading from LCD WRHI; // disable writing to LCD CDHI; // command/status mode DATAOUT; // make 8-bit parallel port an output port write_lcd_command_word(SET_GRAPHIC_HOME_ADDRESS,ATTRIB_BASE); write_lcd_command_word(SET_GRAPHIC_AREA,LCD_NUM_COLUMNS); write_lcd_command_word(SET_TEXT_HOME_ADDRESS,TEXT_BASE); write_lcd_command_word(SET_TEXT_AREA,LCD_NUM_COLUMNS); write_lcd_command(SET_MODE | ATTRIBUTE_MODE | EXTERNAL_CG); write_lcd_command_2_bytes(SET_OFFSET_REGISTER,CHARGEN_BASE>>11,0); write_lcd_command(SET_CURSOR_PATTERN | 7); // cursor is 8 lines high write_lcd_command_2_bytes(SET_CURSOR_POINTER,0,0); // load 6x8 font with VGA map write_lcd_command_word(SET_ADDRESS_POINTER,CHARGEN_BASE); for (i=0; i<FONTDATAMAX; ++i) { write_lcd_command_byte(DATA_WRITE_INC,fontdata_6x8[i]); } lcd_enable_text(); lcd_enable_graphic(); lcd_enable_cursor(); lcd_enable_blink(); lcd_clear_text_area(); printk("lcdcon: %s with %ldK of memory initialized (NO DETECTION IMPLEMENTED YET).\n", lcd_type_name, lcd_vram_len/1024); return "LCD-0";}static void lcdcon_init(struct vc_data *c, int init){ unsigned long p;#ifdef LCD_DEBUG printk(KERN_DEBUG "lcdcon: lcdcon_init %i\n",init);#endif c->vc_can_do_color = 0; c->vc_cols = lcd_num_columns; c->vc_rows = lcd_num_lines; c->vc_complement_mask = 0x0800; /* reverse video */ p = *c->vc_uni_pagedir_loc; if (c->vc_uni_pagedir_loc == &c->vc_uni_pagedir || !--c->vc_uni_pagedir_loc[1]) con_free_unimap(c->vc_num); c->vc_uni_pagedir_loc = lcdcon_uni_pagedir; lcdcon_uni_pagedir[1]++; if (!lcdcon_uni_pagedir[0] && p) con_set_default_unimap(c->vc_num);}static void lcd_set_mem_top(struct vc_data *c){ if (c->vc_visible_origin != lcd_vram_base) { printk("lcdcon: invalid lcd_set_mem_top"); }}static void lcdcon_deinit(struct vc_data *c){ /* When closing the last console, reset video origin */ if (!--lcdcon_uni_pagedir[1]) { c->vc_visible_origin = lcd_vram_base; lcd_set_mem_top(c); con_free_unimap(c->vc_num); } c->vc_uni_pagedir_loc = &c->vc_uni_pagedir; con_set_default_unimap(c->vc_num);#ifdef LCD_DEBUG printk(KERN_DEBUG "lcdcon: lcdcon_deinit\n");#endif}static inline u16 lcd_convert_attr(u16 ch){ /* only reverse, blinking and reverse+blinking supported */ /* underline simulated by reverse */ u16 attr=0;#ifdef LCD_DEBUG_X printk(KERN_DEBUG "lcdcon: lcdcon_convert_attr %i\n",ch);#endif if (ch & 0x8000) { // blink attr |= 0x0800; } if (ch & 0x1000) { // reverse attr |= 0x0500; } if (ch & 0x0800) { // underline, simulate by reverse attr |= 0x0500; } return (ch & 0x00ff) | attr;}static u8 lcdcon_build_attr(struct vc_data *c, u8 color, u8 intensity, u8 blink, u8 underline, u8 reverse){#ifdef LCD_DEBUG printk(KERN_DEBUG "lcdcon: lcdcon_build_attr " "%i,%i,%i,%i,%i\n",color,intensity,blink,underline,reverse);#endif return (intensity & 3) | ((underline & 1) << 2) | ((reverse & 1) << 3) | ((blink & 1) << 7);}static void lcdcon_invert_region(struct vc_data *c, u16 *p, int count){ /* u16 i; printk(KERN_DEBUG "lcdcon: unimplemented lcdcon_invert_region begin" "%p,%i\n",p,count); for (i=0; i<count; ++i) { printk(KERN_DEBUG "lcdcon: pos %i=%i\n",i,*(p+i)); } printk(KERN_DEBUG "lcdcon: lcdcon_invert_region end\n"); */}static void lcdcon_putc(struct vc_data *c, int ch, int y, int x){ u16 ch_converted; u16 position;#ifdef LCD_DEBUG printk(KERN_DEBUG "lcdcon: lcdcon_putc " "%i,%i,%i\n",ch,y,x);#endif position=POSITION(x,y); ch_converted=lcd_convert_attr(ch); // save character to memory buffer screen[position]=ch; // write character code to LCD write_lcd_command_word(SET_ADDRESS_POINTER,TEXT_BASE+position); write_lcd_command_byte(DATA_WRITE,ch_converted & 0x00ff); // write character attribute to LCD write_lcd_command_word(SET_ADDRESS_POINTER,ATTRIB_BASE+position); write_lcd_command_byte(DATA_WRITE,ch_converted>>8); lcd_enable_text(); lcd_enable_graphic();}static void lcdcon_putcs(struct vc_data *c, const unsigned short *s, int count, int y, int x){ u16 i; u16 position;#ifdef LCD_DEBUG printk(KERN_DEBUG "lcdcon: lcdcon_putcs begin " "%p,%i,%i,%i\n",s,count,y,x);#endif position=POSITION(x,y); // save characters to memory buffer for (i=0; i<count; ++i) {#ifdef LCD_DEBUG_X printk(KERN_DEBUG "lcdcon: lcdcon_putcs char " "%i\n",*(s+i));#endif screen[position+i]=*(s+i); } // write character codes to LCD write_lcd_command_word(SET_ADDRESS_POINTER,TEXT_BASE+position); for (i=0; i<count; ++i) { write_lcd_command_byte(DATA_WRITE_INC, lcd_convert_attr(screen[position+i]) & 0x00ff); } // write character attributes to LCD write_lcd_command_word(SET_ADDRESS_POINTER,ATTRIB_BASE+position); for (i=0; i<count; ++i) { write_lcd_command_byte(DATA_WRITE_INC, lcd_convert_attr(screen[position+i])>>8); }#ifdef LCD_DEBUG printk(KERN_DEBUG "lcdcon: lcdcon_putcs end\n");#endif lcd_enable_text(); lcd_enable_graphic();}static void lcdcon_clear(struct vc_data *c, int y, int x, int height, int width){ int xx,yy;#ifdef LCD_DEBUG printk(KERN_DEBUG "lcdcon: lcdcon_clear " "%i,%i,%i,%i\n",y,x,height,width);#endif if (width <= 0 || height <= 0) return; for (yy=0; yy<height; ++yy) { for (xx=0; xx<width; ++xx) { lcdcon_putc(c,c->vc_video_erase_char,y+yy,x+xx); } }} static void lcd_memset(u16 d, const unsigned short ch, u16 count){ u16 i; u16 ch_converted; ch_converted=lcd_convert_attr(ch); // memset to memory buffer for (i=0; i<count; ++i) { screen[d+i]=ch; } // memset to LCD text area write_lcd_command_word(SET_ADDRESS_POINTER,TEXT_BASE+d); for (i=0; i<count; ++i) { write_lcd_command_byte(DATA_WRITE_INC,ch_converted & 0x00ff); } // memset to LCD attribute area write_lcd_command_word(SET_ADDRESS_POINTER,ATTRIB_BASE+d); for (i=0; i<count; ++i) { write_lcd_command_byte(DATA_WRITE_INC,ch_converted>>8); }}static void lcd_memmove(u16 d, u16 s, u16 count){ u16 i; if (d<s) { // move memory buffer for (i=0; i<count; ++i) { screen[d+i]=screen[s+i]; } } else { // move memory buffer for (i=0; i<count; ++i) { screen[d+count-1-i]=screen[s+count-1-i]; } } // update LCD text area write_lcd_command_word(SET_ADDRESS_POINTER,TEXT_BASE+d); for (i=0; i<count; ++i) { write_lcd_command_byte(DATA_WRITE_INC, lcd_convert_attr(screen[d+i]) & 0x00ff); } // update LCD attribute area write_lcd_command_word(SET_ADDRESS_POINTER,ATTRIB_BASE+d); for (i=0; i<count; ++i) { write_lcd_command_byte(DATA_WRITE_INC, lcd_convert_attr(screen[d+i])>>8); }}static void lcdcon_bmove(struct vc_data *c, int sy, int sx, int dy, int dx, int height, int width){ u16 src, dest;#ifdef LCD_DEBUG printk("lcdcon: lcdcon_bmove " "%i,%i,%i,%i,%i,%i\n",sy,sx,dy,dx,height,width);#endif if (width <= 0 || height <= 0) return; if (sx==0 && dx==0 && width==lcd_num_columns) { lcd_memmove(POSITION(0,dy), POSITION(0,sy), height*width); } else if (dy < sy || (dy == sy && dx < sx)) { src = POSITION(sx, sy); dest = POSITION(dx, dy); for (; height > 0; height--) { lcd_memmove(dest, src, width); src += lcd_num_columns; dest += lcd_num_columns; } } else { src = POSITION(sx, sy+height-1); dest = POSITION(dx, dy+height-1); for (; height > 0; height--) { lcd_memmove(dest, src, width); src -= lcd_num_columns; dest -= lcd_num_columns; } } lcd_enable_text(); lcd_enable_graphic();}static int lcdcon_switch(struct vc_data *c){ return 1; /* redrawing needed */}static int lcdcon_set_palette(struct vc_data *c, unsigned char *table){ return -EINVAL;}static int lcdcon_blank(struct vc_data *c, int blank){ printk("lcdcon: unimplemented lcdcon_blank %i\n",blank); return 0;}static int lcdcon_font_op(struct vc_data *c, struct console_font_op *op){ return -ENOSYS;}static int lcdcon_scrolldelta(struct vc_data *c, int lines){#ifdef LCD_DEBUG printk(KERN_DEBUG "lcdcon: lcdcon_scrolldelta %i\n",lines);#endif return 0;}static void lcdcon_cursor(struct vc_data *c, int mode){#ifdef LCD_DEBUG printk(KERN_DEBUG "lcdcon: lcdcon_cursor %i\n",mode);#endif if (mode == CM_ERASE) { lcd_disable_cursor(); return; } write_lcd_command_2_bytes(SET_CURSOR_POINTER,c->vc_x,c->vc_y); switch (c->vc_cursor_type & 0x0f) { case CUR_LOWER_THIRD: lcd_set_cursor_size(0, 1); break; case CUR_LOWER_HALF: lcd_set_cursor_size(0, 3); break; case CUR_TWO_THIRDS: lcd_set_cursor_size(0, 5); break; case CUR_BLOCK: lcd_set_cursor_size(0, 7); break; case CUR_NONE: lcd_set_cursor_size(8, 7); break; default: lcd_set_cursor_size(0, 1); break; } lcd_enable_cursor(); lcd_enable_text(); lcd_enable_graphic();}static int lcdcon_scroll(struct vc_data *c, int t, int b, int dir, int lines){#ifdef LCD_DEBUG printk(KERN_DEBUG "lcdcon: lcdcon_scroll " "t=%i,b=%i,dir=%i,lines=%i\n",t,b,dir,lines);#endif if (!lines) return 0; if (lines>c->vc_rows) lines=c->vc_rows; switch (dir) { case SM_UP: lcd_memmove(POSITION(0,t),POSITION(0,t+lines), (b-t-lines)*lcd_num_columns); lcd_memset(POSITION(0,b-lines),c->vc_video_erase_char, lines*lcd_num_columns); break; case SM_DOWN: lcd_memmove(POSITION(0,t+lines),POSITION(0,t), (b-t-lines)*lcd_num_columns); lcd_memset(POSITION(0,t),c->vc_video_erase_char, lines*lcd_num_columns); break; } lcd_enable_text(); lcd_enable_graphic();#ifdef LCD_DEBUG printk(KERN_DEBUG "lcdcon: lcdcon_scroll more " "eattr=%i,lines=%i,lcd_num_columns=%i,c->vc_rows=%i\n", c->vc_video_erase_char,lines,lcd_num_columns,c->vc_rows);#endif return 0;}static int lcdcon_set_origin(struct vc_data *c){#ifdef LCD_DEBUG printk(KERN_DEBUG "lcdcon: lcdcon_set_origin\n");#endif c->vc_origin = c->vc_visible_origin = lcd_vram_base; lcd_set_mem_top(c); return 1;}static void lcdcon_save_screen(struct vc_data *c){ u16 i; static int lcd_bootup_console = 0;#ifdef LCD_DEBUG printk(KERN_DEBUG "lcdcon: lcdcon_set_origin\n");#endif if (!lcd_bootup_console) { /* This is a gross hack, but here is the only place we can * set bootup console parameters without messing up generic * console initialization routines. */ lcd_bootup_console = 1; c->vc_x = LCD_NUM_COLUMNS; c->vc_y = LCD_NUM_LINES; } for (i=0; i<c->vc_screenbuf_size/2; ++i) { *(c->vc_screenbuf+i)=screen[i]; }}/* * The console `switch' structure for the LCD based console */struct consw vga_con = { lcdcon_startup, /* con_startup */ lcdcon_init, /* con_init */ lcdcon_deinit, /* con_deinit */ lcdcon_clear, /* con_clear */ lcdcon_putc, /* con_putc */ lcdcon_putcs, /* con_putcs */ lcdcon_cursor, /* con_cursor */ lcdcon_scroll, /* con_scroll */ lcdcon_bmove, /* con_bmove */ lcdcon_switch, /* con_switch */ lcdcon_blank, /* con_blank */ lcdcon_font_op, /* con_font_op */ lcdcon_set_palette, /* con_set_palette */ lcdcon_scrolldelta, /* con_scrolldelta */ NULL, //lcdcon_set_origin, /* con_set_origin */ NULL, // lcdcon_save_screen, /* con_save_screen */ lcdcon_build_attr, /* con_build_attr */ NULL, // lcdcon_invert_region, /* con_invert_region */};#ifdef STANDALONEint main(void){ unsigned short buffer[80]; struct vc_data c; int i; ioperm(0x378,3,1); ioperm(0x80,1,1); c.vc_rows=16; c.vc_cols=40; c.vc_video_erase_char=32; lcdcon_startup(); lcdcon_init(&c,1); for (i=0; i<16; ++i) { buffer[0]=i/10+48; buffer[1]=i%10+48; lcdcon_putcs(&c,buffer,2,i,0); } lcdcon_scroll(&c,0,16,1,1); return 0;}#endif // def STANDALONE
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -