promcon.c 12 KB

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