smg.c revision 1.21 1 /* $NetBSD: smg.c,v 1.21 2000/03/23 06:46:44 thorpej Exp $ */
2 /*
3 * Copyright (c) 1998 Ludd, University of Lule}, Sweden.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed at Ludd, University of
17 * Lule}, Sweden and its contributors.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include <sys/param.h>
34 #include <sys/device.h>
35 #include <sys/systm.h>
36 #include <sys/callout.h>
37 #include <sys/time.h>
38 #include <sys/malloc.h>
39 #include <sys/conf.h>
40 #include <sys/kernel.h>
41
42 #include <dev/cons.h>
43
44 #include <dev/wscons/wsdisplayvar.h>
45 #include <dev/wscons/wsconsio.h>
46 #include <dev/wscons/wscons_callbacks.h>
47
48 #include <machine/vsbus.h>
49 #include <machine/sid.h>
50 #include <machine/cpu.h>
51 #include <machine/ka420.h>
52
53 #include "lkc.h"
54
55 #define SM_COLS 128 /* char width of screen */
56 #define SM_ROWS 57 /* rows of char on screen */
57 #define SM_CHEIGHT 15 /* lines a char consists of */
58 #define SM_NEXTROW (SM_COLS * SM_CHEIGHT)
59
60 static int smg_match __P((struct device *, struct cfdata *, void *));
61 static void smg_attach __P((struct device *, struct device *, void *));
62
63 struct smg_softc {
64 struct device ss_dev;
65 };
66
67 struct cfattach smg_ca = {
68 sizeof(struct smg_softc), smg_match, smg_attach,
69 };
70
71 static void smg_cursor __P((void *, int, int, int));
72 static int smg_mapchar __P((void *, int, unsigned int *));
73 static void smg_putchar __P((void *, int, int, u_int, long));
74 static void smg_copycols __P((void *, int, int, int,int));
75 static void smg_erasecols __P((void *, int, int, int, long));
76 static void smg_copyrows __P((void *, int, int, int));
77 static void smg_eraserows __P((void *, int, int, long));
78 static int smg_alloc_attr __P((void *, int, int, int, long *));
79
80 const struct wsdisplay_emulops smg_emulops = {
81 smg_cursor,
82 smg_mapchar,
83 smg_putchar,
84 smg_copycols,
85 smg_erasecols,
86 smg_copyrows,
87 smg_eraserows,
88 smg_alloc_attr
89 };
90
91 const struct wsscreen_descr smg_stdscreen = {
92 "128x57", SM_COLS, SM_ROWS,
93 &smg_emulops,
94 8, SM_CHEIGHT,
95 WSSCREEN_UNDERLINE|WSSCREEN_REVERSE,
96 };
97
98 const struct wsscreen_descr *_smg_scrlist[] = {
99 &smg_stdscreen,
100 };
101
102 const struct wsscreen_list smg_screenlist = {
103 sizeof(_smg_scrlist) / sizeof(struct wsscreen_descr *),
104 _smg_scrlist,
105 };
106
107 static caddr_t sm_addr;
108
109 extern char q_font[];
110 #define QCHAR(c) (c < 32 ? 32 : (c > 127 ? c - 66 : c - 32))
111 #define QFONT(c,line) q_font[QCHAR(c) * 15 + line]
112 #define SM_ADDR(row, col, line) \
113 sm_addr[col + (row * SM_CHEIGHT * SM_COLS) + line * SM_COLS]
114
115
116 static int smg_ioctl __P((void *, u_long, caddr_t, int, struct proc *));
117 static int smg_mmap __P((void *, off_t, int));
118 static int smg_alloc_screen __P((void *, const struct wsscreen_descr *,
119 void **, int *, int *, long *));
120 static void smg_free_screen __P((void *, void *));
121 static int smg_show_screen __P((void *, void *, int,
122 void (*) (void *, int, int), void *));
123 static void smg_crsr_blink __P((void *));
124
125 const struct wsdisplay_accessops smg_accessops = {
126 smg_ioctl,
127 smg_mmap,
128 smg_alloc_screen,
129 smg_free_screen,
130 smg_show_screen,
131 0 /* load_font */
132 };
133
134 struct smg_screen {
135 int ss_curx;
136 int ss_cury;
137 u_char ss_image[SM_ROWS][SM_COLS]; /* Image of current screen */
138 u_char ss_attr[SM_ROWS][SM_COLS]; /* Reversed etc... */
139 };
140
141 static struct smg_screen smg_conscreen;
142 static struct smg_screen *curscr;
143
144 static struct callout smg_cursor_ch = CALLOUT_INITIALIZER;
145
146 int
147 smg_match(parent, match, aux)
148 struct device *parent;
149 struct cfdata *match;
150 void *aux;
151 {
152 struct vsbus_attach_args *va = aux;
153 volatile short *curcmd;
154 volatile short *cfgtst;
155 short tmp, tmp2;
156
157 if (vax_boardtype == VAX_BTYP_49)
158 return 0;
159
160 curcmd = (short *)va->va_addr;
161 cfgtst = (short *)vax_map_physmem(VS_CFGTST, 1);
162 /*
163 * Try to find the cursor chip by testing the flip-flop.
164 * If nonexistent, no glass tty.
165 */
166 curcmd[0] = 0x7fff;
167 DELAY(300000);
168 tmp = cfgtst[0];
169 curcmd[0] = 0x8000;
170 DELAY(300000);
171 tmp2 = cfgtst[0];
172 vax_unmap_physmem((vaddr_t)cfgtst, 1);
173
174 if (tmp2 != tmp)
175 return 20; /* Using periodic interrupt */
176 else
177 return 0;
178 }
179
180 void
181 smg_attach(parent, self, aux)
182 struct device *parent, *self;
183 void *aux;
184 {
185 struct wsemuldisplaydev_attach_args aa;
186
187 printf("\n");
188 sm_addr = (caddr_t)vax_map_physmem(SMADDR, (SMSIZE/VAX_NBPG));
189 if (sm_addr == 0) {
190 printf("%s: Couldn't alloc graphics memory.\n", self->dv_xname);
191 return;
192 }
193 curscr = &smg_conscreen;
194 aa.console = !(vax_confdata & 0x20);
195 aa.scrdata = &smg_screenlist;
196 aa.accessops = &smg_accessops;
197 callout_reset(&smc_cursor_ch, hz / 2, smg_crsr_blink, NULL);
198
199 config_found(self, &aa, wsemuldisplaydevprint);
200 }
201
202 static u_char *cursor;
203 static int cur_on;
204
205 static void
206 smg_crsr_blink(arg)
207 void *arg;
208 {
209 if (cur_on)
210 *cursor ^= 255;
211 callout_reset(&smg_cursor_ch, hz / 2, smg_crsr_blink, NULL);
212 }
213
214 void
215 smg_cursor(id, on, row, col)
216 void *id;
217 int on, row, col;
218 {
219 struct smg_screen *ss = id;
220
221 if (ss == curscr) {
222 SM_ADDR(ss->ss_cury, ss->ss_curx, 14) =
223 QFONT(ss->ss_image[ss->ss_cury][ss->ss_curx], 14);
224 cursor = &SM_ADDR(row, col, 14);
225 if ((cur_on = on))
226 *cursor ^= 255;
227 }
228 ss->ss_curx = col;
229 ss->ss_cury = row;
230 }
231
232 int
233 smg_mapchar(id, uni, index)
234 void *id;
235 int uni;
236 unsigned int *index;
237 {
238 if (uni < 256) {
239 *index = uni;
240 return (5);
241 }
242 *index = ' ';
243 return (0);
244 }
245
246 static void
247 smg_putchar(id, row, col, c, attr)
248 void *id;
249 int row, col;
250 u_int c;
251 long attr;
252 {
253 struct smg_screen *ss = id;
254 int i;
255
256 c &= 0xff;
257
258 ss->ss_image[row][col] = c;
259 ss->ss_attr[row][col] = attr;
260 if (ss != curscr)
261 return;
262 for (i = 0; i < 15; i++) {
263 unsigned char ch = QFONT(c, i);
264
265 SM_ADDR(row, col, i) = (attr & WSATTR_REVERSE ? ~ch : ch);
266
267 }
268 if (attr & WSATTR_UNDERLINE)
269 SM_ADDR(row, col, 14) ^= SM_ADDR(row, col, 14);
270 }
271
272 /*
273 * copies columns inside a row.
274 */
275 static void
276 smg_copycols(id, row, srccol, dstcol, ncols)
277 void *id;
278 int row, srccol, dstcol, ncols;
279 {
280 struct smg_screen *ss = id;
281 int i;
282
283 bcopy(&ss->ss_image[row][srccol], &ss->ss_image[row][dstcol], ncols);
284 bcopy(&ss->ss_attr[row][srccol], &ss->ss_attr[row][dstcol], ncols);
285 if (ss != curscr)
286 return;
287 for (i = 0; i < SM_CHEIGHT; i++)
288 bcopy(&SM_ADDR(row,srccol, i), &SM_ADDR(row, dstcol, i),ncols);
289 }
290
291 /*
292 * Erases a bunch of chars inside one row.
293 */
294 static void
295 smg_erasecols(id, row, startcol, ncols, fillattr)
296 void *id;
297 int row, startcol, ncols;
298 long fillattr;
299 {
300 struct smg_screen *ss = id;
301 int i;
302
303 bzero(&ss->ss_image[row][startcol], ncols);
304 bzero(&ss->ss_attr[row][startcol], ncols);
305 if (ss != curscr)
306 return;
307 for (i = 0; i < SM_CHEIGHT; i++)
308 bzero(&SM_ADDR(row, startcol, i), ncols);
309 }
310
311 static void
312 smg_copyrows(id, srcrow, dstrow, nrows)
313 void *id;
314 int srcrow, dstrow, nrows;
315 {
316 struct smg_screen *ss = id;
317 int frows;
318
319 bcopy(&ss->ss_image[srcrow][0], &ss->ss_image[dstrow][0],
320 nrows * SM_COLS);
321 bcopy(&ss->ss_attr[srcrow][0], &ss->ss_attr[dstrow][0],
322 nrows * SM_COLS);
323 if (ss != curscr)
324 return;
325 if (nrows > 25) {
326 frows = nrows >> 1;
327 if (srcrow > dstrow) {
328 bcopy(&sm_addr[(srcrow * SM_NEXTROW)],
329 &sm_addr[(dstrow * SM_NEXTROW)],
330 frows * SM_NEXTROW);
331 bcopy(&sm_addr[((srcrow + frows) * SM_NEXTROW)],
332 &sm_addr[((dstrow + frows) * SM_NEXTROW)],
333 (nrows - frows) * SM_NEXTROW);
334 } else {
335 bcopy(&sm_addr[((srcrow + frows) * SM_NEXTROW)],
336 &sm_addr[((dstrow + frows) * SM_NEXTROW)],
337 (nrows - frows) * SM_NEXTROW);
338 bcopy(&sm_addr[(srcrow * SM_NEXTROW)],
339 &sm_addr[(dstrow * SM_NEXTROW)],
340 frows * SM_NEXTROW);
341 }
342 } else
343 bcopy(&sm_addr[(srcrow * SM_NEXTROW)],
344 &sm_addr[(dstrow * SM_NEXTROW)], nrows * SM_NEXTROW);
345 }
346
347 static void
348 smg_eraserows(id, startrow, nrows, fillattr)
349 void *id;
350 int startrow, nrows;
351 long fillattr;
352 {
353 struct smg_screen *ss = id;
354 int frows;
355
356 bzero(&ss->ss_image[startrow][0], nrows * SM_COLS);
357 bzero(&ss->ss_attr[startrow][0], nrows * SM_COLS);
358 if (ss != curscr)
359 return;
360 if (nrows > 25) {
361 frows = nrows >> 1;
362 bzero(&sm_addr[(startrow * SM_NEXTROW)], frows * SM_NEXTROW);
363 bzero(&sm_addr[((startrow + frows) * SM_NEXTROW)],
364 (nrows - frows) * SM_NEXTROW);
365 } else
366 bzero(&sm_addr[(startrow * SM_NEXTROW)], nrows * SM_NEXTROW);
367 }
368
369 static int
370 smg_alloc_attr(id, fg, bg, flags, attrp)
371 void *id;
372 int fg, bg;
373 int flags;
374 long *attrp;
375 {
376 *attrp = flags;
377 return 0;
378 }
379
380 int
381 smg_ioctl(v, cmd, data, flag, p)
382 void *v;
383 u_long cmd;
384 caddr_t data;
385 int flag;
386 struct proc *p;
387 {
388 struct wsdisplay_fbinfo fb;
389
390 switch (cmd) {
391 case WSDISPLAYIO_GTYPE:
392 *(u_int *)data = WSDISPLAY_TYPE_PM_MONO;
393 break;
394
395 case WSDISPLAYIO_GINFO:
396 fb.height = 864;
397 fb.width = 1024;
398 return copyout(&fb, data, sizeof(struct wsdisplay_fbinfo));
399
400
401 default:
402 return -1;
403 }
404 return 0;
405 }
406
407 static int
408 smg_mmap(v, offset, prot)
409 void *v;
410 off_t offset;
411 int prot;
412 {
413 if (offset >= SMSIZE || offset < 0)
414 return -1;
415 return (SMADDR + offset) >> PGSHIFT;
416 }
417
418 int
419 smg_alloc_screen(v, type, cookiep, curxp, curyp, defattrp)
420 void *v;
421 const struct wsscreen_descr *type;
422 void **cookiep;
423 int *curxp, *curyp;
424 long *defattrp;
425 {
426 *cookiep = malloc(sizeof(struct smg_screen), M_DEVBUF, M_WAITOK);
427 bzero(*cookiep, sizeof(struct smg_screen));
428 *curxp = *curyp = *defattrp = 0;
429 return 0;
430 }
431
432 void
433 smg_free_screen(v, cookie)
434 void *v;
435 void *cookie;
436 {
437 }
438
439 int
440 smg_show_screen(v, cookie, waitok, cb, cbarg)
441 void *v;
442 void *cookie;
443 int waitok;
444 void (*cb) __P((void *, int, int));
445 void *cbarg;
446 {
447 struct smg_screen *ss = cookie;
448 int row, col, line;
449
450 if (ss == curscr)
451 return (0);
452
453 for (row = 0; row < SM_ROWS; row++)
454 for (line = 0; line < SM_CHEIGHT; line++) {
455 for (col = 0; col < SM_COLS; col++) {
456 u_char s, c = ss->ss_image[row][col];
457
458 if (c < 32)
459 c = 32;
460 s = QFONT(c, line);
461 if (ss->ss_attr[row][col] & WSATTR_REVERSE)
462 s ^= 255;
463 SM_ADDR(row, col, line) = s;
464 }
465 if (ss->ss_attr[row][col] & WSATTR_UNDERLINE)
466 SM_ADDR(row, col, line) = 255;
467 }
468 cursor = &sm_addr[(ss->ss_cury * SM_CHEIGHT * SM_COLS) + ss->ss_curx +
469 ((SM_CHEIGHT - 1) * SM_COLS)];
470 curscr = ss;
471 return (0);
472 }
473
474 cons_decl(smg);
475
476 #define WSCONSOLEMAJOR 68
477
478 void
479 smgcninit(cndev)
480 struct consdev *cndev;
481 {
482 extern void lkccninit __P((struct consdev *));
483 extern int lkccngetc __P((dev_t));
484 /* Clear screen */
485 memset(sm_addr, 0, 128*864);
486
487 curscr = &smg_conscreen;
488 wsdisplay_cnattach(&smg_stdscreen, &smg_conscreen, 0, 0, 0);
489 cn_tab->cn_pri = CN_INTERNAL;
490 #if 0
491 lkccninit(cndev);
492 wsdisplay_set_cons_kbd(lkccngetc, nullcnpollc);
493 #endif
494 }
495
496 /*
497 * Called very early to setup the glass tty as console.
498 * Because it's called before the VM system is inited, virtual memory
499 * for the framebuffer can be stolen directly without disturbing anything.
500 */
501 void
502 smgcnprobe(cndev)
503 struct consdev *cndev;
504 {
505 extern vaddr_t virtual_avail;
506
507 switch (vax_boardtype) {
508 case VAX_BTYP_410:
509 case VAX_BTYP_420:
510 case VAX_BTYP_43:
511 if ((vax_confdata & KA420_CFG_L3CON) ||
512 (vax_confdata & KA420_CFG_MULTU))
513 break; /* doesn't use graphics console */
514 sm_addr = (caddr_t)virtual_avail;
515 virtual_avail += SMSIZE;
516 ioaccess((vaddr_t)sm_addr, SMADDR, (SMSIZE/VAX_NBPG));
517 cndev->cn_pri = CN_INTERNAL;
518 cndev->cn_dev = makedev(WSCONSOLEMAJOR, 0);
519 break;
520
521 default:
522 break;
523 }
524 }
525