promcon.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  1. /* $Id: promcon.c,v 1.17 2000/07/26 23:02:52 davem Exp $
  2. * Console driver utilizing PROM sun terminal emulation
  3. *
  4. * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
  5. * Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz)
  6. */
  7. #include <linux/config.h>
  8. #include <linux/module.h>
  9. #include <linux/kernel.h>
  10. #include <linux/errno.h>
  11. #include <linux/string.h>
  12. #include <linux/mm.h>
  13. #include <linux/tty.h>
  14. #include <linux/slab.h>
  15. #include <linux/delay.h>
  16. #include <linux/console.h>
  17. #include <linux/vt_kern.h>
  18. #include <linux/selection.h>
  19. #include <linux/fb.h>
  20. #include <linux/init.h>
  21. #include <linux/kd.h>
  22. #include <asm/oplib.h>
  23. #include <asm/uaccess.h>
  24. static short pw = 80 - 1, ph = 34 - 1;
  25. static short px, py;
  26. static unsigned long promcon_uni_pagedir[2];
  27. extern u8 promfont_unicount[];
  28. extern u16 promfont_unitable[];
  29. #define PROMCON_COLOR 0
  30. #if PROMCON_COLOR
  31. #define inverted(s) ((((s) & 0x7700) == 0x0700) ? 0 : 1)
  32. #else
  33. #define inverted(s) (((s) & 0x0800) ? 1 : 0)
  34. #endif
  35. static __inline__ void
  36. promcon_puts(char *buf, int cnt)
  37. {
  38. prom_printf("%*.*s", cnt, cnt, buf);
  39. }
  40. static int
  41. promcon_start(struct vc_data *conp, char *b)
  42. {
  43. unsigned short *s = (unsigned short *)
  44. (conp->vc_origin + py * conp->vc_size_row + (px << 1));
  45. u16 cs;
  46. cs = scr_readw(s);
  47. if (px == pw) {
  48. unsigned short *t = s - 1;
  49. u16 ct = scr_readw(t);
  50. if (inverted(cs) && inverted(ct))
  51. return sprintf(b, "\b\033[7m%c\b\033[@%c\033[m", cs,
  52. ct);
  53. else if (inverted(cs))
  54. return sprintf(b, "\b\033[7m%c\033[m\b\033[@%c", cs,
  55. ct);
  56. else if (inverted(ct))
  57. return sprintf(b, "\b%c\b\033[@\033[7m%c\033[m", cs,
  58. ct);
  59. else
  60. return sprintf(b, "\b%c\b\033[@%c", cs, ct);
  61. }
  62. if (inverted(cs))
  63. return sprintf(b, "\033[7m%c\033[m\b", cs);
  64. else
  65. return sprintf(b, "%c\b", cs);
  66. }
  67. static int
  68. promcon_end(struct vc_data *conp, char *b)
  69. {
  70. unsigned short *s = (unsigned short *)
  71. (conp->vc_origin + py * conp->vc_size_row + (px << 1));
  72. char *p = b;
  73. u16 cs;
  74. b += sprintf(b, "\033[%d;%dH", py + 1, px + 1);
  75. cs = scr_readw(s);
  76. if (px == pw) {
  77. unsigned short *t = s - 1;
  78. u16 ct = scr_readw(t);
  79. if (inverted(cs) && inverted(ct))
  80. b += sprintf(b, "\b%c\b\033[@\033[7m%c\033[m", cs, ct);
  81. else if (inverted(cs))
  82. b += sprintf(b, "\b%c\b\033[@%c", cs, ct);
  83. else if (inverted(ct))
  84. b += sprintf(b, "\b\033[7m%c\b\033[@%c\033[m", cs, ct);
  85. else
  86. b += sprintf(b, "\b\033[7m%c\033[m\b\033[@%c", cs, ct);
  87. return b - p;
  88. }
  89. if (inverted(cs))
  90. b += sprintf(b, "%c\b", cs);
  91. else
  92. b += sprintf(b, "\033[7m%c\033[m\b", cs);
  93. return b - p;
  94. }
  95. const char __init *promcon_startup(void)
  96. {
  97. const char *display_desc = "PROM";
  98. int node;
  99. char buf[40];
  100. node = prom_getchild(prom_root_node);
  101. node = prom_searchsiblings(node, "options");
  102. if (prom_getproperty(node, "screen-#columns", buf, 40) != -1) {
  103. pw = simple_strtoul(buf, NULL, 0);
  104. if (pw < 10 || pw > 256)
  105. pw = 80;
  106. pw--;
  107. }
  108. if (prom_getproperty(node, "screen-#rows", buf, 40) != -1) {
  109. ph = simple_strtoul(buf, NULL, 0);
  110. if (ph < 10 || ph > 256)
  111. ph = 34;
  112. ph--;
  113. }
  114. promcon_puts("\033[H\033[J", 6);
  115. return display_desc;
  116. }
  117. static void __init
  118. promcon_init_unimap(struct vc_data *conp)
  119. {
  120. mm_segment_t old_fs = get_fs();
  121. struct unipair *p, *p1;
  122. u16 *q;
  123. int i, j, k;
  124. p = kmalloc(256*sizeof(struct unipair), GFP_KERNEL);
  125. if (!p) return;
  126. q = promfont_unitable;
  127. p1 = p;
  128. k = 0;
  129. for (i = 0; i < 256; i++)
  130. for (j = promfont_unicount[i]; j; j--) {
  131. p1->unicode = *q++;
  132. p1->fontpos = i;
  133. p1++;
  134. k++;
  135. }
  136. set_fs(KERNEL_DS);
  137. con_clear_unimap(conp, NULL);
  138. con_set_unimap(conp, k, p);
  139. con_protect_unimap(conp, 1);
  140. set_fs(old_fs);
  141. kfree(p);
  142. }
  143. static void
  144. promcon_init(struct vc_data *conp, int init)
  145. {
  146. unsigned long p;
  147. conp->vc_can_do_color = PROMCON_COLOR;
  148. if (init) {
  149. conp->vc_cols = pw + 1;
  150. conp->vc_rows = ph + 1;
  151. }
  152. p = *conp->vc_uni_pagedir_loc;
  153. if (conp->vc_uni_pagedir_loc == &conp->vc_uni_pagedir ||
  154. !--conp->vc_uni_pagedir_loc[1])
  155. con_free_unimap(conp);
  156. conp->vc_uni_pagedir_loc = promcon_uni_pagedir;
  157. promcon_uni_pagedir[1]++;
  158. if (!promcon_uni_pagedir[0] && p) {
  159. promcon_init_unimap(conp);
  160. }
  161. if (!init) {
  162. if (conp->vc_cols != pw + 1 || conp->vc_rows != ph + 1)
  163. vc_resize(conp, pw + 1, ph + 1);
  164. }
  165. }
  166. static void
  167. promcon_deinit(struct vc_data *conp)
  168. {
  169. /* When closing the last console, reset video origin */
  170. if (!--promcon_uni_pagedir[1])
  171. con_free_unimap(conp);
  172. conp->vc_uni_pagedir_loc = &conp->vc_uni_pagedir;
  173. con_set_default_unimap(conp);
  174. }
  175. static int
  176. promcon_switch(struct vc_data *conp)
  177. {
  178. return 1;
  179. }
  180. static unsigned short *
  181. promcon_repaint_line(unsigned short *s, unsigned char *buf, unsigned char **bp)
  182. {
  183. int cnt = pw + 1;
  184. int attr = -1;
  185. unsigned char *b = *bp;
  186. while (cnt--) {
  187. u16 c = scr_readw(s);
  188. if (attr != inverted(c)) {
  189. attr = inverted(c);
  190. if (attr) {
  191. strcpy (b, "\033[7m");
  192. b += 4;
  193. } else {
  194. strcpy (b, "\033[m");
  195. b += 3;
  196. }
  197. }
  198. *b++ = c;
  199. s++;
  200. if (b - buf >= 224) {
  201. promcon_puts(buf, b - buf);
  202. b = buf;
  203. }
  204. }
  205. *bp = b;
  206. return s;
  207. }
  208. static void
  209. promcon_putcs(struct vc_data *conp, const unsigned short *s,
  210. int count, int y, int x)
  211. {
  212. unsigned char buf[256], *b = buf;
  213. unsigned short attr = scr_readw(s);
  214. unsigned char save;
  215. int i, last = 0;
  216. if (console_blanked)
  217. return;
  218. if (count <= 0)
  219. return;
  220. b += promcon_start(conp, b);
  221. if (x + count >= pw + 1) {
  222. if (count == 1) {
  223. x -= 1;
  224. save = scr_readw((unsigned short *)(conp->vc_origin
  225. + y * conp->vc_size_row
  226. + (x << 1)));
  227. if (px != x || py != y) {
  228. b += sprintf(b, "\033[%d;%dH", y + 1, x + 1);
  229. px = x;
  230. py = y;
  231. }
  232. if (inverted(attr))
  233. b += sprintf(b, "\033[7m%c\033[m", scr_readw(s++));
  234. else
  235. b += sprintf(b, "%c", scr_readw(s++));
  236. strcpy(b, "\b\033[@");
  237. b += 4;
  238. if (inverted(save))
  239. b += sprintf(b, "\033[7m%c\033[m", save);
  240. else
  241. b += sprintf(b, "%c", save);
  242. px++;
  243. b += promcon_end(conp, b);
  244. promcon_puts(buf, b - buf);
  245. return;
  246. } else {
  247. last = 1;
  248. count = pw - x - 1;
  249. }
  250. }
  251. if (inverted(attr)) {
  252. strcpy(b, "\033[7m");
  253. b += 4;
  254. }
  255. if (px != x || py != y) {
  256. b += sprintf(b, "\033[%d;%dH", y + 1, x + 1);
  257. px = x;
  258. py = y;
  259. }
  260. for (i = 0; i < count; i++) {
  261. if (b - buf >= 224) {
  262. promcon_puts(buf, b - buf);
  263. b = buf;
  264. }
  265. *b++ = scr_readw(s++);
  266. }
  267. px += count;
  268. if (last) {
  269. save = scr_readw(s++);
  270. b += sprintf(b, "%c\b\033[@%c", scr_readw(s++), save);
  271. px++;
  272. }
  273. if (inverted(attr)) {
  274. strcpy(b, "\033[m");
  275. b += 3;
  276. }
  277. b += promcon_end(conp, b);
  278. promcon_puts(buf, b - buf);
  279. }
  280. static void
  281. promcon_putc(struct vc_data *conp, int c, int y, int x)
  282. {
  283. unsigned short s;
  284. if (console_blanked)
  285. return;
  286. scr_writew(c, &s);
  287. promcon_putcs(conp, &s, 1, y, x);
  288. }
  289. static void
  290. promcon_clear(struct vc_data *conp, int sy, int sx, int height, int width)
  291. {
  292. unsigned char buf[256], *b = buf;
  293. int i, j;
  294. if (console_blanked)
  295. return;
  296. b += promcon_start(conp, b);
  297. if (!sx && width == pw + 1) {
  298. if (!sy && height == ph + 1) {
  299. strcpy(b, "\033[H\033[J");
  300. b += 6;
  301. b += promcon_end(conp, b);
  302. promcon_puts(buf, b - buf);
  303. return;
  304. } else if (sy + height == ph + 1) {
  305. b += sprintf(b, "\033[%dH\033[J", sy + 1);
  306. b += promcon_end(conp, b);
  307. promcon_puts(buf, b - buf);
  308. return;
  309. }
  310. b += sprintf(b, "\033[%dH", sy + 1);
  311. for (i = 1; i < height; i++) {
  312. strcpy(b, "\033[K\n");
  313. b += 4;
  314. }
  315. strcpy(b, "\033[K");
  316. b += 3;
  317. b += promcon_end(conp, b);
  318. promcon_puts(buf, b - buf);
  319. return;
  320. } else if (sx + width == pw + 1) {
  321. b += sprintf(b, "\033[%d;%dH", sy + 1, sx + 1);
  322. for (i = 1; i < height; i++) {
  323. strcpy(b, "\033[K\n");
  324. b += 4;
  325. }
  326. strcpy(b, "\033[K");
  327. b += 3;
  328. b += promcon_end(conp, b);
  329. promcon_puts(buf, b - buf);
  330. return;
  331. }
  332. for (i = sy + 1; i <= sy + height; i++) {
  333. b += sprintf(b, "\033[%d;%dH", i, sx + 1);
  334. for (j = 0; j < width; j++)
  335. *b++ = ' ';
  336. if (b - buf + width >= 224) {
  337. promcon_puts(buf, b - buf);
  338. b = buf;
  339. }
  340. }
  341. b += promcon_end(conp, b);
  342. promcon_puts(buf, b - buf);
  343. }
  344. static void
  345. promcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
  346. int height, int width)
  347. {
  348. char buf[256], *b = buf;
  349. if (console_blanked)
  350. return;
  351. b += promcon_start(conp, b);
  352. if (sy == dy && height == 1) {
  353. if (dx > sx && dx + width == conp->vc_cols)
  354. b += sprintf(b, "\033[%d;%dH\033[%d@\033[%d;%dH",
  355. sy + 1, sx + 1, dx - sx, py + 1, px + 1);
  356. else if (dx < sx && sx + width == conp->vc_cols)
  357. b += sprintf(b, "\033[%d;%dH\033[%dP\033[%d;%dH",
  358. dy + 1, dx + 1, sx - dx, py + 1, px + 1);
  359. b += promcon_end(conp, b);
  360. promcon_puts(buf, b - buf);
  361. return;
  362. }
  363. /*
  364. * FIXME: What to do here???
  365. * Current console.c should not call it like that ever.
  366. */
  367. prom_printf("\033[7mFIXME: bmove not handled\033[m\n");
  368. }
  369. static void
  370. promcon_cursor(struct vc_data *conp, int mode)
  371. {
  372. char buf[32], *b = buf;
  373. switch (mode) {
  374. case CM_ERASE:
  375. break;
  376. case CM_MOVE:
  377. case CM_DRAW:
  378. b += promcon_start(conp, b);
  379. if (px != conp->vc_x || py != conp->vc_y) {
  380. px = conp->vc_x;
  381. py = conp->vc_y;
  382. b += sprintf(b, "\033[%d;%dH", py + 1, px + 1);
  383. }
  384. promcon_puts(buf, b - buf);
  385. break;
  386. }
  387. }
  388. static int
  389. promcon_blank(struct vc_data *conp, int blank, int mode_switch)
  390. {
  391. if (blank) {
  392. promcon_puts("\033[H\033[J\033[7m \033[m\b", 15);
  393. return 0;
  394. } else {
  395. /* Let console.c redraw */
  396. return 1;
  397. }
  398. }
  399. static int
  400. promcon_scroll(struct vc_data *conp, int t, int b, int dir, int count)
  401. {
  402. unsigned char buf[256], *p = buf;
  403. unsigned short *s;
  404. int i;
  405. if (console_blanked)
  406. return 0;
  407. p += promcon_start(conp, p);
  408. switch (dir) {
  409. case SM_UP:
  410. if (b == ph + 1) {
  411. p += sprintf(p, "\033[%dH\033[%dM", t + 1, count);
  412. px = 0;
  413. py = t;
  414. p += promcon_end(conp, p);
  415. promcon_puts(buf, p - buf);
  416. break;
  417. }
  418. s = (unsigned short *)(conp->vc_origin
  419. + (t + count) * conp->vc_size_row);
  420. p += sprintf(p, "\033[%dH", t + 1);
  421. for (i = t; i < b - count; i++)
  422. s = promcon_repaint_line(s, buf, &p);
  423. for (; i < b - 1; i++) {
  424. strcpy(p, "\033[K\n");
  425. p += 4;
  426. if (p - buf >= 224) {
  427. promcon_puts(buf, p - buf);
  428. p = buf;
  429. }
  430. }
  431. strcpy(p, "\033[K");
  432. p += 3;
  433. p += promcon_end(conp, p);
  434. promcon_puts(buf, p - buf);
  435. break;
  436. case SM_DOWN:
  437. if (b == ph + 1) {
  438. p += sprintf(p, "\033[%dH\033[%dL", t + 1, count);
  439. px = 0;
  440. py = t;
  441. p += promcon_end(conp, p);
  442. promcon_puts(buf, p - buf);
  443. break;
  444. }
  445. s = (unsigned short *)(conp->vc_origin + t * conp->vc_size_row);
  446. p += sprintf(p, "\033[%dH", t + 1);
  447. for (i = t; i < t + count; i++) {
  448. strcpy(p, "\033[K\n");
  449. p += 4;
  450. if (p - buf >= 224) {
  451. promcon_puts(buf, p - buf);
  452. p = buf;
  453. }
  454. }
  455. for (; i < b; i++)
  456. s = promcon_repaint_line(s, buf, &p);
  457. p += promcon_end(conp, p);
  458. promcon_puts(buf, p - buf);
  459. break;
  460. }
  461. return 0;
  462. }
  463. #if !(PROMCON_COLOR)
  464. static u8 promcon_build_attr(struct vc_data *conp, u8 _color, u8 _intensity, u8 _blink, u8 _underline, u8 _reverse)
  465. {
  466. return (_reverse) ? 0xf : 0x7;
  467. }
  468. #endif
  469. /*
  470. * The console 'switch' structure for the VGA based console
  471. */
  472. static int promcon_dummy(void)
  473. {
  474. return 0;
  475. }
  476. #define DUMMY (void *) promcon_dummy
  477. const struct consw prom_con = {
  478. .owner = THIS_MODULE,
  479. .con_startup = promcon_startup,
  480. .con_init = promcon_init,
  481. .con_deinit = promcon_deinit,
  482. .con_clear = promcon_clear,
  483. .con_putc = promcon_putc,
  484. .con_putcs = promcon_putcs,
  485. .con_cursor = promcon_cursor,
  486. .con_scroll = promcon_scroll,
  487. .con_bmove = promcon_bmove,
  488. .con_switch = promcon_switch,
  489. .con_blank = promcon_blank,
  490. .con_set_palette = DUMMY,
  491. .con_scrolldelta = DUMMY,
  492. #if !(PROMCON_COLOR)
  493. .con_build_attr = promcon_build_attr,
  494. #endif
  495. };
  496. void __init prom_con_init(void)
  497. {
  498. #ifdef CONFIG_DUMMY_CONSOLE
  499. if (conswitchp == &dummy_con)
  500. take_over_console(&prom_con, 0, MAX_NR_CONSOLES-1, 1);
  501. else
  502. #endif
  503. if (conswitchp == &prom_con)
  504. promcon_init_unimap(vc_cons[fg_console].d);
  505. }