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