0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038 #include <linux/init.h>
0039 #include <linux/kernel.h>
0040 #include <linux/console.h>
0041 #include <linux/errno.h>
0042 #include <linux/vt_kern.h>
0043 #include <linux/kd.h>
0044 #include <linux/selection.h>
0045 #include <linux/module.h>
0046 #include <linux/slab.h>
0047 #include <linux/font.h>
0048 #include <linux/crc32.h>
0049 #include <linux/fb.h>
0050
0051 #include <asm/io.h>
0052
0053 #include "../fbdev/sticore.h"
0054
0055
0056 #define BLANK 0
0057 static int vga_is_gfx;
0058
0059 #define STI_DEF_FONT sticon_sti->font
0060
0061
0062 #define FNTREFCOUNT(fd) (fd->refcount)
0063 #define FNTCRC(fd) (fd->crc)
0064 static struct sti_cooked_font *font_data[MAX_NR_CONSOLES];
0065
0066
0067 static struct sti_struct *sticon_sti;
0068
0069 static const char *sticon_startup(void)
0070 {
0071 return "STI console";
0072 }
0073
0074 static void sticon_putc(struct vc_data *conp, int c, int ypos, int xpos)
0075 {
0076 if (vga_is_gfx || console_blanked)
0077 return;
0078
0079 if (conp->vc_mode != KD_TEXT)
0080 return;
0081
0082 sti_putc(sticon_sti, c, ypos, xpos, font_data[conp->vc_num]);
0083 }
0084
0085 static void sticon_putcs(struct vc_data *conp, const unsigned short *s,
0086 int count, int ypos, int xpos)
0087 {
0088 if (vga_is_gfx || console_blanked)
0089 return;
0090
0091 if (conp->vc_mode != KD_TEXT)
0092 return;
0093
0094 while (count--) {
0095 sti_putc(sticon_sti, scr_readw(s++), ypos, xpos++,
0096 font_data[conp->vc_num]);
0097 }
0098 }
0099
0100 static void sticon_cursor(struct vc_data *conp, int mode)
0101 {
0102 unsigned short car1;
0103
0104
0105 if (vga_is_gfx || console_blanked)
0106 return;
0107
0108 car1 = conp->vc_screenbuf[conp->state.x + conp->state.y * conp->vc_cols];
0109 switch (mode) {
0110 case CM_ERASE:
0111 sti_putc(sticon_sti, car1, conp->state.y, conp->state.x,
0112 font_data[conp->vc_num]);
0113 break;
0114 case CM_MOVE:
0115 case CM_DRAW:
0116 switch (CUR_SIZE(conp->vc_cursor_type)) {
0117 case CUR_UNDERLINE:
0118 case CUR_LOWER_THIRD:
0119 case CUR_LOWER_HALF:
0120 case CUR_TWO_THIRDS:
0121 case CUR_BLOCK:
0122 sti_putc(sticon_sti, (car1 & 255) + (0 << 8) + (7 << 11),
0123 conp->state.y, conp->state.x, font_data[conp->vc_num]);
0124 break;
0125 }
0126 break;
0127 }
0128 }
0129
0130 static bool sticon_scroll(struct vc_data *conp, unsigned int t,
0131 unsigned int b, enum con_scroll dir, unsigned int count)
0132 {
0133 struct sti_struct *sti = sticon_sti;
0134
0135 if (vga_is_gfx)
0136 return false;
0137
0138 sticon_cursor(conp, CM_ERASE);
0139
0140 switch (dir) {
0141 case SM_UP:
0142 sti_bmove(sti, t + count, 0, t, 0, b - t - count, conp->vc_cols,
0143 font_data[conp->vc_num]);
0144 sti_clear(sti, b - count, 0, count, conp->vc_cols,
0145 conp->vc_video_erase_char, font_data[conp->vc_num]);
0146 break;
0147
0148 case SM_DOWN:
0149 sti_bmove(sti, t, 0, t + count, 0, b - t - count, conp->vc_cols,
0150 font_data[conp->vc_num]);
0151 sti_clear(sti, t, 0, count, conp->vc_cols,
0152 conp->vc_video_erase_char, font_data[conp->vc_num]);
0153 break;
0154 }
0155
0156 return false;
0157 }
0158
0159 static int sticon_set_def_font(int unit, struct console_font *op)
0160 {
0161 if (font_data[unit] != STI_DEF_FONT) {
0162 if (--FNTREFCOUNT(font_data[unit]) == 0) {
0163 kfree(font_data[unit]->raw_ptr);
0164 kfree(font_data[unit]);
0165 }
0166 font_data[unit] = STI_DEF_FONT;
0167 }
0168
0169 return 0;
0170 }
0171
0172 static int sticon_set_font(struct vc_data *vc, struct console_font *op)
0173 {
0174 struct sti_struct *sti = sticon_sti;
0175 int vc_cols, vc_rows, vc_old_cols, vc_old_rows;
0176 int unit = vc->vc_num;
0177 int w = op->width;
0178 int h = op->height;
0179 int size, i, bpc, pitch;
0180 struct sti_rom_font *new_font;
0181 struct sti_cooked_font *cooked_font;
0182 unsigned char *data = op->data, *p;
0183
0184 if ((w < 6) || (h < 6) || (w > 32) || (h > 32)
0185 || (op->charcount != 256 && op->charcount != 512))
0186 return -EINVAL;
0187 pitch = ALIGN(w, 8) / 8;
0188 bpc = pitch * h;
0189 size = bpc * op->charcount;
0190
0191 new_font = kmalloc(sizeof(*new_font) + size, STI_LOWMEM);
0192 if (!new_font)
0193 return -ENOMEM;
0194
0195 new_font->first_char = 0;
0196 new_font->last_char = op->charcount - 1;
0197 new_font->width = w;
0198 new_font->height = h;
0199 new_font->font_type = STI_FONT_HPROMAN8;
0200 new_font->bytes_per_char = bpc;
0201 new_font->underline_height = 0;
0202 new_font->underline_pos = 0;
0203
0204 cooked_font = kzalloc(sizeof(*cooked_font), GFP_KERNEL);
0205 if (!cooked_font) {
0206 kfree(new_font);
0207 return -ENOMEM;
0208 }
0209 cooked_font->raw = new_font;
0210 cooked_font->raw_ptr = new_font;
0211 cooked_font->width = w;
0212 cooked_font->height = h;
0213 FNTREFCOUNT(cooked_font) = 0;
0214
0215 p = (unsigned char *) new_font;
0216 p += sizeof(*new_font);
0217 for (i = 0; i < op->charcount; i++) {
0218 memcpy(p, data, bpc);
0219 data += pitch*32;
0220 p += bpc;
0221 }
0222 FNTCRC(cooked_font) = crc32(0, new_font, size + sizeof(*new_font));
0223 sti_font_convert_bytemode(sti, cooked_font);
0224 new_font = cooked_font->raw_ptr;
0225
0226
0227 for (i = 0; i < MAX_NR_CONSOLES; i++) {
0228 if (font_data[i] != STI_DEF_FONT
0229 && (FNTCRC(font_data[i]) == FNTCRC(cooked_font))) {
0230 kfree(new_font);
0231 kfree(cooked_font);
0232
0233 if (i == unit)
0234 return 0;
0235 cooked_font = font_data[i];
0236 new_font = cooked_font->raw_ptr;
0237 break;
0238 }
0239 }
0240
0241
0242 vc_old_rows = vc->vc_rows;
0243 vc_old_cols = vc->vc_cols;
0244 sti_clear(sticon_sti, 0, 0, vc_old_rows, vc_old_cols,
0245 vc->vc_video_erase_char, font_data[vc->vc_num]);
0246
0247
0248 sticon_set_def_font(unit, NULL);
0249
0250 FNTREFCOUNT(cooked_font)++;
0251 font_data[unit] = cooked_font;
0252
0253 vc_cols = sti_onscreen_x(sti) / cooked_font->width;
0254 vc_rows = sti_onscreen_y(sti) / cooked_font->height;
0255 vc_resize(vc, vc_cols, vc_rows);
0256
0257
0258 if (vc_cols == vc_old_cols && vc_rows == vc_old_rows)
0259 update_screen(vc);
0260
0261 return 0;
0262 }
0263
0264 static int sticon_font_default(struct vc_data *vc, struct console_font *op, char *name)
0265 {
0266 return sticon_set_def_font(vc->vc_num, op);
0267 }
0268
0269 static int sticon_font_set(struct vc_data *vc, struct console_font *font,
0270 unsigned int flags)
0271 {
0272 return sticon_set_font(vc, font);
0273 }
0274
0275 static void sticon_init(struct vc_data *c, int init)
0276 {
0277 struct sti_struct *sti = sticon_sti;
0278 int vc_cols, vc_rows;
0279
0280 sti_set(sti, 0, 0, sti_onscreen_y(sti), sti_onscreen_x(sti), 0);
0281 vc_cols = sti_onscreen_x(sti) / sti->font->width;
0282 vc_rows = sti_onscreen_y(sti) / sti->font->height;
0283 c->vc_can_do_color = 1;
0284
0285 if (init) {
0286 c->vc_cols = vc_cols;
0287 c->vc_rows = vc_rows;
0288 } else {
0289 vc_resize(c, vc_cols, vc_rows);
0290 }
0291 }
0292
0293 static void sticon_deinit(struct vc_data *c)
0294 {
0295 int i;
0296
0297
0298 for (i = 0; i < MAX_NR_CONSOLES; i++)
0299 sticon_set_def_font(i, NULL);
0300 }
0301
0302 static void sticon_clear(struct vc_data *conp, int sy, int sx, int height,
0303 int width)
0304 {
0305 if (!height || !width)
0306 return;
0307
0308 sti_clear(sticon_sti, sy, sx, height, width,
0309 conp->vc_video_erase_char, font_data[conp->vc_num]);
0310 }
0311
0312 static int sticon_switch(struct vc_data *conp)
0313 {
0314 return 1;
0315 }
0316
0317 static int sticon_blank(struct vc_data *c, int blank, int mode_switch)
0318 {
0319 if (blank == 0) {
0320 if (mode_switch)
0321 vga_is_gfx = 0;
0322 return 1;
0323 }
0324 sti_clear(sticon_sti, 0, 0, c->vc_rows, c->vc_cols, BLANK,
0325 font_data[c->vc_num]);
0326 if (mode_switch)
0327 vga_is_gfx = 1;
0328 return 1;
0329 }
0330
0331 static u8 sticon_build_attr(struct vc_data *conp, u8 color,
0332 enum vc_intensity intens,
0333 bool blink, bool underline, bool reverse,
0334 bool italic)
0335 {
0336 u8 fg = color & 7;
0337 u8 bg = (color & 0x70) >> 4;
0338
0339 if (reverse)
0340 return (fg << 3) | bg;
0341 else
0342 return (bg << 3) | fg;
0343 }
0344
0345 static void sticon_invert_region(struct vc_data *conp, u16 *p, int count)
0346 {
0347 int col = 1;
0348
0349 while (count--) {
0350 u16 a = scr_readw(p);
0351
0352 if (col)
0353 a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);
0354 else
0355 a = ((a & 0x0700) == 0x0100) ? 0x7000 : 0x7700;
0356
0357 scr_writew(a, p++);
0358 }
0359 }
0360
0361 static const struct consw sti_con = {
0362 .owner = THIS_MODULE,
0363 .con_startup = sticon_startup,
0364 .con_init = sticon_init,
0365 .con_deinit = sticon_deinit,
0366 .con_clear = sticon_clear,
0367 .con_putc = sticon_putc,
0368 .con_putcs = sticon_putcs,
0369 .con_cursor = sticon_cursor,
0370 .con_scroll = sticon_scroll,
0371 .con_switch = sticon_switch,
0372 .con_blank = sticon_blank,
0373 .con_font_set = sticon_font_set,
0374 .con_font_default = sticon_font_default,
0375 .con_build_attr = sticon_build_attr,
0376 .con_invert_region = sticon_invert_region,
0377 };
0378
0379
0380
0381 static int __init sticonsole_init(void)
0382 {
0383 int err, i;
0384
0385
0386 if (sticon_sti)
0387 return 0;
0388
0389 sticon_sti = sti_get_rom(0);
0390 if (!sticon_sti)
0391 return -ENODEV;
0392
0393 for (i = 0; i < MAX_NR_CONSOLES; i++)
0394 font_data[i] = STI_DEF_FONT;
0395
0396 pr_info("sticon: Initializing STI text console on %s at [%s]\n",
0397 sticon_sti->sti_data->inq_outptr.dev_name,
0398 sticon_sti->pa_path);
0399 console_lock();
0400 err = do_take_over_console(&sti_con, 0, MAX_NR_CONSOLES - 1,
0401 PAGE0->mem_cons.cl_class != CL_DUPLEX);
0402 console_unlock();
0403
0404 return err;
0405 }
0406
0407 module_init(sticonsole_init);
0408 MODULE_LICENSE("GPL");