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
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051 #include <linux/mutex.h>
0052 #include <linux/module.h>
0053 #include <linux/kernel.h>
0054 #include <linux/signal.h>
0055 #include <linux/fs.h>
0056 #include <linux/usb.h>
0057 #include <linux/tty.h>
0058 #include <linux/console.h>
0059 #include <linux/string.h>
0060 #include <linux/kd.h>
0061 #include <linux/init.h>
0062 #include <linux/vt_kern.h>
0063 #include <linux/selection.h>
0064 #include <linux/spinlock.h>
0065 #include <linux/kref.h>
0066 #include <linux/ioport.h>
0067 #include <linux/interrupt.h>
0068 #include <linux/vmalloc.h>
0069
0070 #include "sisusb.h"
0071 #include "sisusb_init.h"
0072
0073
0074 static struct sisusb_usb_data *mysisusbs[MAX_NR_CONSOLES];
0075
0076
0077 static const struct consw sisusb_con;
0078
0079 static inline void
0080 sisusbcon_memsetw(u16 *s, u16 c, unsigned int count)
0081 {
0082 memset16(s, c, count / 2);
0083 }
0084
0085 static inline void
0086 sisusb_initialize(struct sisusb_usb_data *sisusb)
0087 {
0088
0089 if (sisusb_setidxreg(sisusb, SISCR, 0x0c, 0x00))
0090 return;
0091 if (sisusb_setidxreg(sisusb, SISCR, 0x0d, 0x00))
0092 return;
0093 if (sisusb_setidxreg(sisusb, SISCR, 0x0e, 0x00))
0094 return;
0095 sisusb_setidxreg(sisusb, SISCR, 0x0f, 0x00);
0096 }
0097
0098 static inline void
0099 sisusbcon_set_start_address(struct sisusb_usb_data *sisusb, struct vc_data *c)
0100 {
0101 sisusb->cur_start_addr = (c->vc_visible_origin - sisusb->scrbuf) / 2;
0102
0103 sisusb_setidxreg(sisusb, SISCR, 0x0c, (sisusb->cur_start_addr >> 8));
0104 sisusb_setidxreg(sisusb, SISCR, 0x0d, (sisusb->cur_start_addr & 0xff));
0105 }
0106
0107 void
0108 sisusb_set_cursor(struct sisusb_usb_data *sisusb, unsigned int location)
0109 {
0110 if (sisusb->sisusb_cursor_loc == location)
0111 return;
0112
0113 sisusb->sisusb_cursor_loc = location;
0114
0115
0116
0117
0118
0119
0120 if ((location & 0x0007) == 0x0007) {
0121 sisusb->bad_cursor_pos = 1;
0122 location--;
0123 if (sisusb_setidxregandor(sisusb, SISCR, 0x0b, 0x1f, 0x20))
0124 return;
0125 } else if (sisusb->bad_cursor_pos) {
0126 if (sisusb_setidxregand(sisusb, SISCR, 0x0b, 0x1f))
0127 return;
0128 sisusb->bad_cursor_pos = 0;
0129 }
0130
0131 if (sisusb_setidxreg(sisusb, SISCR, 0x0e, (location >> 8)))
0132 return;
0133 sisusb_setidxreg(sisusb, SISCR, 0x0f, (location & 0xff));
0134 }
0135
0136 static inline struct sisusb_usb_data *
0137 sisusb_get_sisusb(unsigned short console)
0138 {
0139 return mysisusbs[console];
0140 }
0141
0142 static inline int
0143 sisusb_sisusb_valid(struct sisusb_usb_data *sisusb)
0144 {
0145 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev)
0146 return 0;
0147
0148 return 1;
0149 }
0150
0151 static struct sisusb_usb_data *
0152 sisusb_get_sisusb_lock_and_check(unsigned short console)
0153 {
0154 struct sisusb_usb_data *sisusb;
0155
0156
0157
0158
0159
0160
0161 if (in_atomic())
0162 return NULL;
0163
0164 sisusb = sisusb_get_sisusb(console);
0165 if (!sisusb)
0166 return NULL;
0167
0168 mutex_lock(&sisusb->lock);
0169
0170 if (!sisusb_sisusb_valid(sisusb) ||
0171 !sisusb->havethisconsole[console]) {
0172 mutex_unlock(&sisusb->lock);
0173 return NULL;
0174 }
0175
0176 return sisusb;
0177 }
0178
0179 static int
0180 sisusb_is_inactive(struct vc_data *c, struct sisusb_usb_data *sisusb)
0181 {
0182 if (sisusb->is_gfx ||
0183 sisusb->textmodedestroyed ||
0184 c->vc_mode != KD_TEXT)
0185 return 1;
0186
0187 return 0;
0188 }
0189
0190
0191 static const char *
0192 sisusbcon_startup(void)
0193 {
0194 return "SISUSBCON";
0195 }
0196
0197
0198 static void
0199 sisusbcon_init(struct vc_data *c, int init)
0200 {
0201 struct sisusb_usb_data *sisusb;
0202 int cols, rows;
0203
0204
0205
0206
0207
0208
0209
0210 sisusb = sisusb_get_sisusb(c->vc_num);
0211 if (!sisusb)
0212 return;
0213
0214 mutex_lock(&sisusb->lock);
0215
0216 if (!sisusb_sisusb_valid(sisusb)) {
0217 mutex_unlock(&sisusb->lock);
0218 return;
0219 }
0220
0221 c->vc_can_do_color = 1;
0222
0223 c->vc_complement_mask = 0x7700;
0224
0225 c->vc_hi_font_mask = sisusb->current_font_512 ? 0x0800 : 0;
0226
0227 sisusb->haveconsole = 1;
0228
0229 sisusb->havethisconsole[c->vc_num] = 1;
0230
0231
0232 c->vc_scan_lines = 400;
0233
0234 c->vc_font.height = sisusb->current_font_height;
0235
0236
0237 cols = 80;
0238 rows = c->vc_scan_lines / c->vc_font.height;
0239
0240
0241
0242
0243
0244
0245
0246
0247
0248
0249 kref_get(&sisusb->kref);
0250
0251 if (!*c->uni_pagedict_loc)
0252 con_set_default_unimap(c);
0253
0254 mutex_unlock(&sisusb->lock);
0255
0256 if (init) {
0257 c->vc_cols = cols;
0258 c->vc_rows = rows;
0259 } else
0260 vc_resize(c, cols, rows);
0261 }
0262
0263
0264 static void
0265 sisusbcon_deinit(struct vc_data *c)
0266 {
0267 struct sisusb_usb_data *sisusb;
0268 int i;
0269
0270
0271
0272
0273
0274 sisusb = sisusb_get_sisusb(c->vc_num);
0275 if (!sisusb)
0276 return;
0277
0278 mutex_lock(&sisusb->lock);
0279
0280
0281 mysisusbs[c->vc_num] = NULL;
0282
0283 sisusb->havethisconsole[c->vc_num] = 0;
0284
0285
0286 if (sisusb->font_backup) {
0287 for(i = 0; i < MAX_NR_CONSOLES; i++) {
0288 if (sisusb->havethisconsole[c->vc_num])
0289 break;
0290 }
0291 if (i == MAX_NR_CONSOLES) {
0292 vfree(sisusb->font_backup);
0293 sisusb->font_backup = NULL;
0294 }
0295 }
0296
0297 mutex_unlock(&sisusb->lock);
0298
0299
0300 kref_put(&sisusb->kref, sisusb_delete);
0301 }
0302
0303
0304 static u8
0305 sisusbcon_build_attr(struct vc_data *c, u8 color, enum vc_intensity intensity,
0306 bool blink, bool underline, bool reverse,
0307 bool unused)
0308 {
0309 u8 attr = color;
0310
0311 if (underline)
0312 attr = (attr & 0xf0) | c->vc_ulcolor;
0313 else if (intensity == VCI_HALF_BRIGHT)
0314 attr = (attr & 0xf0) | c->vc_halfcolor;
0315
0316 if (reverse)
0317 attr = ((attr) & 0x88) |
0318 ((((attr) >> 4) |
0319 ((attr) << 4)) & 0x77);
0320
0321 if (blink)
0322 attr ^= 0x80;
0323
0324 if (intensity == VCI_BOLD)
0325 attr ^= 0x08;
0326
0327 return attr;
0328 }
0329
0330
0331 static void
0332 sisusbcon_invert_region(struct vc_data *vc, u16 *p, int count)
0333 {
0334
0335
0336
0337
0338
0339
0340 while (count--) {
0341 u16 a = *p;
0342
0343 *p++ = ((a) & 0x88ff) |
0344 (((a) & 0x7000) >> 4) |
0345 (((a) & 0x0700) << 4);
0346 }
0347 }
0348
0349 static inline void *sisusb_vaddr(const struct sisusb_usb_data *sisusb,
0350 const struct vc_data *c, unsigned int x, unsigned int y)
0351 {
0352 return (u16 *)c->vc_origin + y * sisusb->sisusb_num_columns + x;
0353 }
0354
0355 static inline unsigned long sisusb_haddr(const struct sisusb_usb_data *sisusb,
0356 const struct vc_data *c, unsigned int x, unsigned int y)
0357 {
0358 unsigned long offset = c->vc_origin - sisusb->scrbuf;
0359
0360
0361 offset += 2 * (y * sisusb->sisusb_num_columns + x);
0362
0363 return sisusb->vrambase + offset;
0364 }
0365
0366
0367 static void
0368 sisusbcon_putc(struct vc_data *c, int ch, int y, int x)
0369 {
0370 struct sisusb_usb_data *sisusb;
0371
0372 sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
0373 if (!sisusb)
0374 return;
0375
0376
0377 if (sisusb_is_inactive(c, sisusb)) {
0378 mutex_unlock(&sisusb->lock);
0379 return;
0380 }
0381
0382 sisusb_copy_memory(sisusb, sisusb_vaddr(sisusb, c, x, y),
0383 sisusb_haddr(sisusb, c, x, y), 2);
0384
0385 mutex_unlock(&sisusb->lock);
0386 }
0387
0388
0389 static void
0390 sisusbcon_putcs(struct vc_data *c, const unsigned short *s,
0391 int count, int y, int x)
0392 {
0393 struct sisusb_usb_data *sisusb;
0394
0395 sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
0396 if (!sisusb)
0397 return;
0398
0399
0400
0401
0402
0403
0404
0405 memcpy(sisusb_vaddr(sisusb, c, x, y), s, count * 2);
0406
0407 if (sisusb_is_inactive(c, sisusb)) {
0408 mutex_unlock(&sisusb->lock);
0409 return;
0410 }
0411
0412 sisusb_copy_memory(sisusb, sisusb_vaddr(sisusb, c, x, y),
0413 sisusb_haddr(sisusb, c, x, y), count * 2);
0414
0415 mutex_unlock(&sisusb->lock);
0416 }
0417
0418
0419 static void
0420 sisusbcon_clear(struct vc_data *c, int y, int x, int height, int width)
0421 {
0422 struct sisusb_usb_data *sisusb;
0423 u16 eattr = c->vc_video_erase_char;
0424 int i, length, cols;
0425 u16 *dest;
0426
0427 if (width <= 0 || height <= 0)
0428 return;
0429
0430 sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
0431 if (!sisusb)
0432 return;
0433
0434
0435
0436
0437
0438
0439
0440 dest = sisusb_vaddr(sisusb, c, x, y);
0441
0442 cols = sisusb->sisusb_num_columns;
0443
0444 if (width > cols)
0445 width = cols;
0446
0447 if (x == 0 && width >= c->vc_cols) {
0448
0449 sisusbcon_memsetw(dest, eattr, height * cols * 2);
0450
0451 } else {
0452
0453 for (i = height; i > 0; i--, dest += cols)
0454 sisusbcon_memsetw(dest, eattr, width * 2);
0455
0456 }
0457
0458 if (sisusb_is_inactive(c, sisusb)) {
0459 mutex_unlock(&sisusb->lock);
0460 return;
0461 }
0462
0463 length = ((height * cols) - x - (cols - width - x)) * 2;
0464
0465
0466 sisusb_copy_memory(sisusb, sisusb_vaddr(sisusb, c, x, y),
0467 sisusb_haddr(sisusb, c, x, y), length);
0468
0469 mutex_unlock(&sisusb->lock);
0470 }
0471
0472
0473 static int
0474 sisusbcon_switch(struct vc_data *c)
0475 {
0476 struct sisusb_usb_data *sisusb;
0477 int length;
0478
0479
0480
0481
0482
0483
0484 sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
0485 if (!sisusb)
0486 return 0;
0487
0488
0489
0490
0491 if (sisusb_is_inactive(c, sisusb)) {
0492 mutex_unlock(&sisusb->lock);
0493 return 0;
0494 }
0495
0496
0497
0498
0499
0500 if (c->vc_origin == (unsigned long)c->vc_screenbuf) {
0501 mutex_unlock(&sisusb->lock);
0502 dev_dbg(&sisusb->sisusb_dev->dev, "ASSERT ORIGIN != SCREENBUF!\n");
0503 return 0;
0504 }
0505
0506
0507 length = min((int)c->vc_screenbuf_size,
0508 (int)(sisusb->scrbuf + sisusb->scrbuf_size - c->vc_origin));
0509
0510
0511 memcpy((u16 *)c->vc_origin, (u16 *)c->vc_screenbuf, length);
0512
0513 sisusb_copy_memory(sisusb, (u8 *)c->vc_origin,
0514 sisusb_haddr(sisusb, c, 0, 0), length);
0515
0516 mutex_unlock(&sisusb->lock);
0517
0518 return 0;
0519 }
0520
0521
0522 static void
0523 sisusbcon_save_screen(struct vc_data *c)
0524 {
0525 struct sisusb_usb_data *sisusb;
0526 int length;
0527
0528
0529
0530
0531
0532 sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
0533 if (!sisusb)
0534 return;
0535
0536
0537
0538 if (sisusb_is_inactive(c, sisusb)) {
0539 mutex_unlock(&sisusb->lock);
0540 return;
0541 }
0542
0543
0544 length = min((int)c->vc_screenbuf_size,
0545 (int)(sisusb->scrbuf + sisusb->scrbuf_size - c->vc_origin));
0546
0547
0548 memcpy((u16 *)c->vc_screenbuf, (u16 *)c->vc_origin, length);
0549
0550 mutex_unlock(&sisusb->lock);
0551 }
0552
0553
0554 static void
0555 sisusbcon_set_palette(struct vc_data *c, const unsigned char *table)
0556 {
0557 struct sisusb_usb_data *sisusb;
0558 int i, j;
0559
0560
0561
0562 if (!con_is_visible(c))
0563 return;
0564
0565 sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
0566 if (!sisusb)
0567 return;
0568
0569
0570
0571 if (sisusb_is_inactive(c, sisusb)) {
0572 mutex_unlock(&sisusb->lock);
0573 return;
0574 }
0575
0576 for (i = j = 0; i < 16; i++) {
0577 if (sisusb_setreg(sisusb, SISCOLIDX, table[i]))
0578 break;
0579 if (sisusb_setreg(sisusb, SISCOLDATA, c->vc_palette[j++] >> 2))
0580 break;
0581 if (sisusb_setreg(sisusb, SISCOLDATA, c->vc_palette[j++] >> 2))
0582 break;
0583 if (sisusb_setreg(sisusb, SISCOLDATA, c->vc_palette[j++] >> 2))
0584 break;
0585 }
0586
0587 mutex_unlock(&sisusb->lock);
0588 }
0589
0590
0591 static int
0592 sisusbcon_blank(struct vc_data *c, int blank, int mode_switch)
0593 {
0594 struct sisusb_usb_data *sisusb;
0595 u8 sr1, cr17, pmreg, cr63;
0596 int ret = 0;
0597
0598 sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
0599 if (!sisusb)
0600 return 0;
0601
0602
0603
0604 if (mode_switch)
0605 sisusb->is_gfx = blank ? 1 : 0;
0606
0607 if (sisusb_is_inactive(c, sisusb)) {
0608 mutex_unlock(&sisusb->lock);
0609 return 0;
0610 }
0611
0612 switch (blank) {
0613
0614 case 1:
0615 case -1:
0616 sisusbcon_memsetw((u16 *)c->vc_origin,
0617 c->vc_video_erase_char,
0618 c->vc_screenbuf_size);
0619 sisusb_copy_memory(sisusb, (u8 *)c->vc_origin,
0620 sisusb_haddr(sisusb, c, 0, 0),
0621 c->vc_screenbuf_size);
0622 sisusb->con_blanked = 1;
0623 ret = 1;
0624 break;
0625
0626 default:
0627 switch (blank) {
0628 case 0:
0629 sr1 = 0x00;
0630 cr17 = 0x80;
0631 pmreg = 0x00;
0632 cr63 = 0x00;
0633 ret = 1;
0634 sisusb->con_blanked = 0;
0635 break;
0636 case VESA_VSYNC_SUSPEND + 1:
0637 sr1 = 0x20;
0638 cr17 = 0x80;
0639 pmreg = 0x80;
0640 cr63 = 0x40;
0641 break;
0642 case VESA_HSYNC_SUSPEND + 1:
0643 sr1 = 0x20;
0644 cr17 = 0x80;
0645 pmreg = 0x40;
0646 cr63 = 0x40;
0647 break;
0648 case VESA_POWERDOWN + 1:
0649 sr1 = 0x20;
0650 cr17 = 0x00;
0651 pmreg = 0xc0;
0652 cr63 = 0x40;
0653 break;
0654 default:
0655 mutex_unlock(&sisusb->lock);
0656 return -EINVAL;
0657 }
0658
0659 sisusb_setidxregandor(sisusb, SISSR, 0x01, ~0x20, sr1);
0660 sisusb_setidxregandor(sisusb, SISCR, 0x17, 0x7f, cr17);
0661 sisusb_setidxregandor(sisusb, SISSR, 0x1f, 0x3f, pmreg);
0662 sisusb_setidxregandor(sisusb, SISCR, 0x63, 0xbf, cr63);
0663
0664 }
0665
0666 mutex_unlock(&sisusb->lock);
0667
0668 return ret;
0669 }
0670
0671
0672 static void
0673 sisusbcon_scrolldelta(struct vc_data *c, int lines)
0674 {
0675 struct sisusb_usb_data *sisusb;
0676
0677 sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
0678 if (!sisusb)
0679 return;
0680
0681
0682
0683 if (sisusb_is_inactive(c, sisusb)) {
0684 mutex_unlock(&sisusb->lock);
0685 return;
0686 }
0687
0688 vc_scrolldelta_helper(c, lines, sisusb->con_rolled_over,
0689 (void *)sisusb->scrbuf, sisusb->scrbuf_size);
0690
0691 sisusbcon_set_start_address(sisusb, c);
0692
0693 mutex_unlock(&sisusb->lock);
0694 }
0695
0696
0697 static void
0698 sisusbcon_cursor(struct vc_data *c, int mode)
0699 {
0700 struct sisusb_usb_data *sisusb;
0701 int from, to, baseline;
0702
0703 sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
0704 if (!sisusb)
0705 return;
0706
0707
0708
0709 if (sisusb_is_inactive(c, sisusb)) {
0710 mutex_unlock(&sisusb->lock);
0711 return;
0712 }
0713
0714 if (c->vc_origin != c->vc_visible_origin) {
0715 c->vc_visible_origin = c->vc_origin;
0716 sisusbcon_set_start_address(sisusb, c);
0717 }
0718
0719 if (mode == CM_ERASE) {
0720 sisusb_setidxregor(sisusb, SISCR, 0x0a, 0x20);
0721 sisusb->sisusb_cursor_size_to = -1;
0722 mutex_unlock(&sisusb->lock);
0723 return;
0724 }
0725
0726 sisusb_set_cursor(sisusb, (c->vc_pos - sisusb->scrbuf) / 2);
0727
0728 baseline = c->vc_font.height - (c->vc_font.height < 10 ? 1 : 2);
0729
0730 switch (CUR_SIZE(c->vc_cursor_type)) {
0731 case CUR_BLOCK: from = 1;
0732 to = c->vc_font.height;
0733 break;
0734 case CUR_TWO_THIRDS: from = c->vc_font.height / 3;
0735 to = baseline;
0736 break;
0737 case CUR_LOWER_HALF: from = c->vc_font.height / 2;
0738 to = baseline;
0739 break;
0740 case CUR_LOWER_THIRD: from = (c->vc_font.height * 2) / 3;
0741 to = baseline;
0742 break;
0743 case CUR_NONE: from = 31;
0744 to = 30;
0745 break;
0746 default:
0747 case CUR_UNDERLINE: from = baseline - 1;
0748 to = baseline;
0749 break;
0750 }
0751
0752 if (sisusb->sisusb_cursor_size_from != from ||
0753 sisusb->sisusb_cursor_size_to != to) {
0754
0755 sisusb_setidxreg(sisusb, SISCR, 0x0a, from);
0756 sisusb_setidxregandor(sisusb, SISCR, 0x0b, 0xe0, to);
0757
0758 sisusb->sisusb_cursor_size_from = from;
0759 sisusb->sisusb_cursor_size_to = to;
0760 }
0761
0762 mutex_unlock(&sisusb->lock);
0763 }
0764
0765 static bool
0766 sisusbcon_scroll_area(struct vc_data *c, struct sisusb_usb_data *sisusb,
0767 unsigned int t, unsigned int b, enum con_scroll dir,
0768 unsigned int lines)
0769 {
0770 int cols = sisusb->sisusb_num_columns;
0771 int length = ((b - t) * cols) * 2;
0772 u16 eattr = c->vc_video_erase_char;
0773
0774
0775
0776
0777
0778
0779
0780
0781
0782 switch (dir) {
0783
0784 case SM_UP:
0785 memmove(sisusb_vaddr(sisusb, c, 0, t),
0786 sisusb_vaddr(sisusb, c, 0, t + lines),
0787 (b - t - lines) * cols * 2);
0788 sisusbcon_memsetw(sisusb_vaddr(sisusb, c, 0, b - lines),
0789 eattr, lines * cols * 2);
0790 break;
0791
0792 case SM_DOWN:
0793 memmove(sisusb_vaddr(sisusb, c, 0, t + lines),
0794 sisusb_vaddr(sisusb, c, 0, t),
0795 (b - t - lines) * cols * 2);
0796 sisusbcon_memsetw(sisusb_vaddr(sisusb, c, 0, t), eattr,
0797 lines * cols * 2);
0798 break;
0799 }
0800
0801 sisusb_copy_memory(sisusb, sisusb_vaddr(sisusb, c, 0, t),
0802 sisusb_haddr(sisusb, c, 0, t), length);
0803
0804 mutex_unlock(&sisusb->lock);
0805
0806 return true;
0807 }
0808
0809
0810 static bool
0811 sisusbcon_scroll(struct vc_data *c, unsigned int t, unsigned int b,
0812 enum con_scroll dir, unsigned int lines)
0813 {
0814 struct sisusb_usb_data *sisusb;
0815 u16 eattr = c->vc_video_erase_char;
0816 int copyall = 0;
0817 unsigned long oldorigin;
0818 unsigned int delta = lines * c->vc_size_row;
0819
0820
0821
0822
0823
0824
0825
0826
0827 if (!lines)
0828 return true;
0829
0830 sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
0831 if (!sisusb)
0832 return false;
0833
0834
0835
0836 if (sisusb_is_inactive(c, sisusb)) {
0837 mutex_unlock(&sisusb->lock);
0838 return false;
0839 }
0840
0841
0842 if (t || b != c->vc_rows)
0843 return sisusbcon_scroll_area(c, sisusb, t, b, dir, lines);
0844
0845 if (c->vc_origin != c->vc_visible_origin) {
0846 c->vc_visible_origin = c->vc_origin;
0847 sisusbcon_set_start_address(sisusb, c);
0848 }
0849
0850
0851 if (lines > c->vc_rows)
0852 lines = c->vc_rows;
0853
0854 oldorigin = c->vc_origin;
0855
0856 switch (dir) {
0857
0858 case SM_UP:
0859
0860 if (c->vc_scr_end + delta >=
0861 sisusb->scrbuf + sisusb->scrbuf_size) {
0862 memcpy((u16 *)sisusb->scrbuf,
0863 (u16 *)(oldorigin + delta),
0864 c->vc_screenbuf_size - delta);
0865 c->vc_origin = sisusb->scrbuf;
0866 sisusb->con_rolled_over = oldorigin - sisusb->scrbuf;
0867 copyall = 1;
0868 } else
0869 c->vc_origin += delta;
0870
0871 sisusbcon_memsetw(
0872 (u16 *)(c->vc_origin + c->vc_screenbuf_size - delta),
0873 eattr, delta);
0874
0875 break;
0876
0877 case SM_DOWN:
0878
0879 if (oldorigin - delta < sisusb->scrbuf) {
0880 memmove((void *)sisusb->scrbuf + sisusb->scrbuf_size -
0881 c->vc_screenbuf_size + delta,
0882 (u16 *)oldorigin,
0883 c->vc_screenbuf_size - delta);
0884 c->vc_origin = sisusb->scrbuf +
0885 sisusb->scrbuf_size -
0886 c->vc_screenbuf_size;
0887 sisusb->con_rolled_over = 0;
0888 copyall = 1;
0889 } else
0890 c->vc_origin -= delta;
0891
0892 c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
0893
0894 scr_memsetw((u16 *)(c->vc_origin), eattr, delta);
0895
0896 break;
0897 }
0898
0899 if (copyall)
0900 sisusb_copy_memory(sisusb,
0901 (u8 *)c->vc_origin,
0902 sisusb_haddr(sisusb, c, 0, 0),
0903 c->vc_screenbuf_size);
0904 else if (dir == SM_UP)
0905 sisusb_copy_memory(sisusb,
0906 (u8 *)c->vc_origin + c->vc_screenbuf_size - delta,
0907 sisusb_haddr(sisusb, c, 0, 0) +
0908 c->vc_screenbuf_size - delta,
0909 delta);
0910 else
0911 sisusb_copy_memory(sisusb,
0912 (u8 *)c->vc_origin,
0913 sisusb_haddr(sisusb, c, 0, 0),
0914 delta);
0915
0916 c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
0917 c->vc_visible_origin = c->vc_origin;
0918
0919 sisusbcon_set_start_address(sisusb, c);
0920
0921 c->vc_pos = c->vc_pos - oldorigin + c->vc_origin;
0922
0923 mutex_unlock(&sisusb->lock);
0924
0925 return true;
0926 }
0927
0928
0929 static int
0930 sisusbcon_set_origin(struct vc_data *c)
0931 {
0932 struct sisusb_usb_data *sisusb;
0933
0934
0935
0936
0937
0938
0939 sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
0940 if (!sisusb)
0941 return 0;
0942
0943
0944
0945 if (sisusb_is_inactive(c, sisusb) || sisusb->con_blanked) {
0946 mutex_unlock(&sisusb->lock);
0947 return 0;
0948 }
0949
0950 c->vc_origin = c->vc_visible_origin = sisusb->scrbuf;
0951
0952 sisusbcon_set_start_address(sisusb, c);
0953
0954 sisusb->con_rolled_over = 0;
0955
0956 mutex_unlock(&sisusb->lock);
0957
0958 return true;
0959 }
0960
0961
0962 static int
0963 sisusbcon_resize(struct vc_data *c, unsigned int newcols, unsigned int newrows,
0964 unsigned int user)
0965 {
0966 struct sisusb_usb_data *sisusb;
0967 int fh;
0968
0969 sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
0970 if (!sisusb)
0971 return -ENODEV;
0972
0973 fh = sisusb->current_font_height;
0974
0975 mutex_unlock(&sisusb->lock);
0976
0977
0978
0979
0980
0981
0982
0983
0984 if (newcols != 80 || c->vc_scan_lines / fh != newrows)
0985 return -EINVAL;
0986
0987 return 0;
0988 }
0989
0990 int
0991 sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot,
0992 u8 *arg, int cmapsz, int ch512, int dorecalc,
0993 struct vc_data *c, int fh, int uplock)
0994 {
0995 int font_select = 0x00, i, err = 0;
0996 u32 offset = 0;
0997 u8 dummy;
0998
0999
1000
1001
1002
1003
1004
1005
1006
1007 if ((slot != 0 && slot != 2) || !fh) {
1008 if (uplock)
1009 mutex_unlock(&sisusb->lock);
1010 return -EINVAL;
1011 }
1012
1013 if (set)
1014 sisusb->font_slot = slot;
1015
1016
1017 if (slot == 0)
1018 ch512 = 0;
1019 else
1020 offset = 4 * cmapsz;
1021
1022 font_select = (slot == 0) ? 0x00 : (ch512 ? 0x0e : 0x0a);
1023
1024 err |= sisusb_setidxreg(sisusb, SISSR, 0x00, 0x01);
1025 err |= sisusb_setidxreg(sisusb, SISSR, 0x02, 0x04);
1026 err |= sisusb_setidxreg(sisusb, SISSR, 0x04, 0x07);
1027 err |= sisusb_setidxreg(sisusb, SISSR, 0x00, 0x03);
1028
1029 if (err)
1030 goto font_op_error;
1031
1032 err |= sisusb_setidxreg(sisusb, SISGR, 0x04, 0x03);
1033 err |= sisusb_setidxreg(sisusb, SISGR, 0x05, 0x00);
1034 err |= sisusb_setidxreg(sisusb, SISGR, 0x06, 0x00);
1035
1036 if (err)
1037 goto font_op_error;
1038
1039 if (arg) {
1040 if (set)
1041 for (i = 0; i < cmapsz; i++) {
1042 err |= sisusb_writeb(sisusb,
1043 sisusb->vrambase + offset + i,
1044 arg[i]);
1045 if (err)
1046 break;
1047 }
1048 else
1049 for (i = 0; i < cmapsz; i++) {
1050 err |= sisusb_readb(sisusb,
1051 sisusb->vrambase + offset + i,
1052 &arg[i]);
1053 if (err)
1054 break;
1055 }
1056
1057
1058
1059
1060
1061
1062 if (ch512) {
1063 if (set)
1064 for (i = 0; i < cmapsz; i++) {
1065 err |= sisusb_writeb(sisusb,
1066 sisusb->vrambase + offset +
1067 (2 * cmapsz) + i,
1068 arg[cmapsz + i]);
1069 if (err)
1070 break;
1071 }
1072 else
1073 for (i = 0; i < cmapsz; i++) {
1074 err |= sisusb_readb(sisusb,
1075 sisusb->vrambase + offset +
1076 (2 * cmapsz) + i,
1077 &arg[cmapsz + i]);
1078 if (err)
1079 break;
1080 }
1081 }
1082 }
1083
1084 if (err)
1085 goto font_op_error;
1086
1087 err |= sisusb_setidxreg(sisusb, SISSR, 0x00, 0x01);
1088 err |= sisusb_setidxreg(sisusb, SISSR, 0x02, 0x03);
1089 err |= sisusb_setidxreg(sisusb, SISSR, 0x04, 0x03);
1090 if (set)
1091 sisusb_setidxreg(sisusb, SISSR, 0x03, font_select);
1092 err |= sisusb_setidxreg(sisusb, SISSR, 0x00, 0x03);
1093
1094 if (err)
1095 goto font_op_error;
1096
1097 err |= sisusb_setidxreg(sisusb, SISGR, 0x04, 0x00);
1098 err |= sisusb_setidxreg(sisusb, SISGR, 0x05, 0x10);
1099 err |= sisusb_setidxreg(sisusb, SISGR, 0x06, 0x06);
1100
1101 if (err)
1102 goto font_op_error;
1103
1104 if ((set) && (ch512 != sisusb->current_font_512)) {
1105
1106
1107
1108
1109 for (i = 0; i < MAX_NR_CONSOLES; i++) {
1110 struct vc_data *d = vc_cons[i].d;
1111 if (d && d->vc_sw == &sisusb_con)
1112 d->vc_hi_font_mask = ch512 ? 0x0800 : 0;
1113 }
1114
1115 sisusb->current_font_512 = ch512;
1116
1117
1118
1119
1120 sisusb_getreg(sisusb, SISINPSTAT, &dummy);
1121 sisusb_setreg(sisusb, SISAR, 0x12);
1122 sisusb_setreg(sisusb, SISAR, ch512 ? 0x07 : 0x0f);
1123
1124 sisusb_getreg(sisusb, SISINPSTAT, &dummy);
1125 sisusb_setreg(sisusb, SISAR, 0x20);
1126 sisusb_getreg(sisusb, SISINPSTAT, &dummy);
1127 }
1128
1129 if (dorecalc) {
1130
1131
1132
1133
1134
1135 unsigned char ovr, vde, fsr;
1136 int rows = 0, maxscan = 0;
1137
1138 if (c) {
1139
1140
1141 rows = c->vc_scan_lines / fh;
1142
1143 maxscan = rows * fh - 1;
1144
1145
1146
1147
1148 sisusb_getidxreg(sisusb, SISCR, 0x07, &ovr);
1149 vde = maxscan & 0xff;
1150 ovr = (ovr & 0xbd) |
1151 ((maxscan & 0x100) >> 7) |
1152 ((maxscan & 0x200) >> 3);
1153 sisusb_setidxreg(sisusb, SISCR, 0x07, ovr);
1154 sisusb_setidxreg(sisusb, SISCR, 0x12, vde);
1155
1156 }
1157
1158 sisusb_getidxreg(sisusb, SISCR, 0x09, &fsr);
1159 fsr = (fsr & 0xe0) | (fh - 1);
1160 sisusb_setidxreg(sisusb, SISCR, 0x09, fsr);
1161 sisusb->current_font_height = fh;
1162
1163 sisusb->sisusb_cursor_size_from = -1;
1164 sisusb->sisusb_cursor_size_to = -1;
1165
1166 }
1167
1168 if (uplock)
1169 mutex_unlock(&sisusb->lock);
1170
1171 if (dorecalc && c) {
1172 int rows = c->vc_scan_lines / fh;
1173
1174
1175
1176 for (i = 0; i < MAX_NR_CONSOLES; i++) {
1177 struct vc_data *vc = vc_cons[i].d;
1178
1179 if (vc && vc->vc_sw == &sisusb_con) {
1180 if (con_is_visible(vc)) {
1181 vc->vc_sw->con_cursor(vc, CM_DRAW);
1182 }
1183 vc->vc_font.height = fh;
1184 vc_resize(vc, 0, rows);
1185 }
1186 }
1187 }
1188
1189 return 0;
1190
1191 font_op_error:
1192 if (uplock)
1193 mutex_unlock(&sisusb->lock);
1194
1195 return -EIO;
1196 }
1197
1198
1199 static int
1200 sisusbcon_font_set(struct vc_data *c, struct console_font *font,
1201 unsigned int flags)
1202 {
1203 struct sisusb_usb_data *sisusb;
1204 unsigned charcount = font->charcount;
1205
1206 if (font->width != 8 || (charcount != 256 && charcount != 512))
1207 return -EINVAL;
1208
1209 sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
1210 if (!sisusb)
1211 return -ENODEV;
1212
1213
1214
1215
1216
1217
1218
1219 if (sisusb->font_backup) {
1220 if (sisusb->font_backup_size < charcount) {
1221 vfree(sisusb->font_backup);
1222 sisusb->font_backup = NULL;
1223 }
1224 }
1225
1226 if (!sisusb->font_backup)
1227 sisusb->font_backup = vmalloc(array_size(charcount, 32));
1228
1229 if (sisusb->font_backup) {
1230 memcpy(sisusb->font_backup, font->data, array_size(charcount, 32));
1231 sisusb->font_backup_size = charcount;
1232 sisusb->font_backup_height = font->height;
1233 sisusb->font_backup_512 = (charcount == 512) ? 1 : 0;
1234 }
1235
1236
1237
1238 return sisusbcon_do_font_op(sisusb, 1, 2, font->data,
1239 8192, (charcount == 512),
1240 (!(flags & KD_FONT_FLAG_DONT_RECALC)) ? 1 : 0,
1241 c, font->height, 1);
1242 }
1243
1244
1245 static int
1246 sisusbcon_font_get(struct vc_data *c, struct console_font *font)
1247 {
1248 struct sisusb_usb_data *sisusb;
1249
1250 sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
1251 if (!sisusb)
1252 return -ENODEV;
1253
1254
1255
1256 font->width = 8;
1257 font->height = c->vc_font.height;
1258 font->charcount = 256;
1259
1260 if (!font->data) {
1261 mutex_unlock(&sisusb->lock);
1262 return 0;
1263 }
1264
1265 if (!sisusb->font_backup) {
1266 mutex_unlock(&sisusb->lock);
1267 return -ENODEV;
1268 }
1269
1270
1271 memcpy(font->data, sisusb->font_backup, 256 * 32);
1272
1273 mutex_unlock(&sisusb->lock);
1274
1275 return 0;
1276 }
1277
1278
1279
1280
1281
1282 static const struct consw sisusb_con = {
1283 .owner = THIS_MODULE,
1284 .con_startup = sisusbcon_startup,
1285 .con_init = sisusbcon_init,
1286 .con_deinit = sisusbcon_deinit,
1287 .con_clear = sisusbcon_clear,
1288 .con_putc = sisusbcon_putc,
1289 .con_putcs = sisusbcon_putcs,
1290 .con_cursor = sisusbcon_cursor,
1291 .con_scroll = sisusbcon_scroll,
1292 .con_switch = sisusbcon_switch,
1293 .con_blank = sisusbcon_blank,
1294 .con_font_set = sisusbcon_font_set,
1295 .con_font_get = sisusbcon_font_get,
1296 .con_set_palette = sisusbcon_set_palette,
1297 .con_scrolldelta = sisusbcon_scrolldelta,
1298 .con_build_attr = sisusbcon_build_attr,
1299 .con_invert_region = sisusbcon_invert_region,
1300 .con_set_origin = sisusbcon_set_origin,
1301 .con_save_screen = sisusbcon_save_screen,
1302 .con_resize = sisusbcon_resize,
1303 };
1304
1305
1306
1307 static const char *sisusbdummycon_startup(void)
1308 {
1309 return "SISUSBVGADUMMY";
1310 }
1311
1312 static void sisusbdummycon_init(struct vc_data *vc, int init)
1313 {
1314 vc->vc_can_do_color = 1;
1315 if (init) {
1316 vc->vc_cols = 80;
1317 vc->vc_rows = 25;
1318 } else
1319 vc_resize(vc, 80, 25);
1320 }
1321
1322 static void sisusbdummycon_deinit(struct vc_data *vc) { }
1323 static void sisusbdummycon_clear(struct vc_data *vc, int sy, int sx,
1324 int height, int width) { }
1325 static void sisusbdummycon_putc(struct vc_data *vc, int c, int ypos,
1326 int xpos) { }
1327 static void sisusbdummycon_putcs(struct vc_data *vc, const unsigned short *s,
1328 int count, int ypos, int xpos) { }
1329 static void sisusbdummycon_cursor(struct vc_data *vc, int mode) { }
1330
1331 static bool sisusbdummycon_scroll(struct vc_data *vc, unsigned int top,
1332 unsigned int bottom, enum con_scroll dir,
1333 unsigned int lines)
1334 {
1335 return false;
1336 }
1337
1338 static int sisusbdummycon_switch(struct vc_data *vc)
1339 {
1340 return 0;
1341 }
1342
1343 static int sisusbdummycon_blank(struct vc_data *vc, int blank, int mode_switch)
1344 {
1345 return 0;
1346 }
1347
1348 static const struct consw sisusb_dummy_con = {
1349 .owner = THIS_MODULE,
1350 .con_startup = sisusbdummycon_startup,
1351 .con_init = sisusbdummycon_init,
1352 .con_deinit = sisusbdummycon_deinit,
1353 .con_clear = sisusbdummycon_clear,
1354 .con_putc = sisusbdummycon_putc,
1355 .con_putcs = sisusbdummycon_putcs,
1356 .con_cursor = sisusbdummycon_cursor,
1357 .con_scroll = sisusbdummycon_scroll,
1358 .con_switch = sisusbdummycon_switch,
1359 .con_blank = sisusbdummycon_blank,
1360 };
1361
1362 int
1363 sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
1364 {
1365 int i, ret;
1366
1367 mutex_lock(&sisusb->lock);
1368
1369
1370 if (sisusb->haveconsole || !sisusb->SiS_Pr) {
1371 mutex_unlock(&sisusb->lock);
1372 return 1;
1373 }
1374
1375 sisusb->con_first = first;
1376 sisusb->con_last = last;
1377
1378 if (first > last ||
1379 first > MAX_NR_CONSOLES ||
1380 last > MAX_NR_CONSOLES) {
1381 mutex_unlock(&sisusb->lock);
1382 return 1;
1383 }
1384
1385
1386 if (!sisusb->gfxinit || first < 1 || last < 1) {
1387 mutex_unlock(&sisusb->lock);
1388 return 0;
1389 }
1390
1391 sisusb->sisusb_cursor_loc = -1;
1392 sisusb->sisusb_cursor_size_from = -1;
1393 sisusb->sisusb_cursor_size_to = -1;
1394
1395
1396 if (sisusb_reset_text_mode(sisusb, 1)) {
1397 mutex_unlock(&sisusb->lock);
1398 dev_err(&sisusb->sisusb_dev->dev, "Failed to set up text mode\n");
1399 return 1;
1400 }
1401
1402
1403 sisusb_initialize(sisusb);
1404
1405 for (i = first - 1; i <= last - 1; i++) {
1406
1407 mysisusbs[i] = sisusb;
1408 }
1409
1410
1411 sisusb->sisusb_num_columns = 80;
1412
1413
1414 sisusb->scrbuf_size = 32 * 1024;
1415
1416
1417 if (!(sisusb->scrbuf = (unsigned long)vmalloc(sisusb->scrbuf_size))) {
1418 mutex_unlock(&sisusb->lock);
1419 dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate screen buffer\n");
1420 return 1;
1421 }
1422
1423 mutex_unlock(&sisusb->lock);
1424
1425
1426 console_lock();
1427 ret = do_take_over_console(&sisusb_con, first - 1, last - 1, 0);
1428 console_unlock();
1429 if (!ret)
1430 sisusb->haveconsole = 1;
1431 else {
1432 for (i = first - 1; i <= last - 1; i++)
1433 mysisusbs[i] = NULL;
1434 }
1435
1436 return ret;
1437 }
1438
1439 void
1440 sisusb_console_exit(struct sisusb_usb_data *sisusb)
1441 {
1442 int i;
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470 if (sisusb->haveconsole) {
1471 for (i = 0; i < MAX_NR_CONSOLES; i++)
1472 if (sisusb->havethisconsole[i]) {
1473 console_lock();
1474 do_take_over_console(&sisusb_dummy_con, i, i, 0);
1475 console_unlock();
1476
1477
1478
1479 }
1480 sisusb->haveconsole = 0;
1481 }
1482
1483 vfree((void *)sisusb->scrbuf);
1484 sisusb->scrbuf = 0;
1485
1486 vfree(sisusb->font_backup);
1487 sisusb->font_backup = NULL;
1488 }
1489
1490 void __init sisusb_init_concode(void)
1491 {
1492 int i;
1493
1494 for (i = 0; i < MAX_NR_CONSOLES; i++)
1495 mysisusbs[i] = NULL;
1496 }