smg.c revision 1.17 1 /* $NetBSD: smg.c,v 1.17 1999/08/27 17:49:41 ragge 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/time.h>
37 #include <sys/malloc.h>
38 #include <sys/conf.h>
39 #include <sys/kernel.h>
40
41 #include <dev/cons.h>
42
43 #include <dev/wscons/wsdisplayvar.h>
44 #include <dev/wscons/wsconsio.h>
45 #include <dev/wscons/wscons_callbacks.h>
46
47 #include <machine/vsbus.h>
48 #include <machine/sid.h>
49 #include <machine/cpu.h>
50 #include <machine/ka420.h>
51
52 #include "lkc.h"
53
54 #define SM_COLS 128 /* char width of screen */
55 #define SM_ROWS 57 /* rows of char on screen */
56 #define SM_CHEIGHT 15 /* lines a char consists of */
57 #define SM_NEXTROW (SM_COLS * SM_CHEIGHT)
58
59 static int smg_match __P((struct device *, struct cfdata *, void *));
60 static void smg_attach __P((struct device *, struct device *, void *));
61
62 struct smg_softc {
63 struct device ss_dev;
64 };
65
66 struct cfattach smg_ca = {
67 sizeof(struct smg_softc), smg_match, smg_attach,
68 };
69
70 static void smg_cursor __P((void *, int, int, int));
71 static int smg_mapchar __P((void *, int, unsigned int *));
72 static void smg_putchar __P((void *, int, int, u_int, long));
73 static void smg_copycols __P((void *, int, int, int,int));
74 static void smg_erasecols __P((void *, int, int, int, long));
75 static void smg_copyrows __P((void *, int, int, int));
76 static void smg_eraserows __P((void *, int, int, long));
77 static int smg_alloc_attr __P((void *, int, int, int, long *));
78
79 const struct wsdisplay_emulops smg_emulops = {
80 smg_cursor,
81 smg_mapchar,
82 smg_putchar,
83 smg_copycols,
84 smg_erasecols,
85 smg_copyrows,
86 smg_eraserows,
87 smg_alloc_attr
88 };
89
90 const struct wsscreen_descr smg_stdscreen = {
91 "128x57", SM_COLS, SM_ROWS,
92 &smg_emulops,
93 8, SM_CHEIGHT,
94 WSSCREEN_UNDERLINE|WSSCREEN_REVERSE,
95 };
96
97 const struct wsscreen_descr *_smg_scrlist[] = {
98 &smg_stdscreen,
99 };
100
101 const struct wsscreen_list smg_screenlist = {
102 sizeof(_smg_scrlist) / sizeof(struct wsscreen_descr *),
103 _smg_scrlist,
104 };
105
106 static caddr_t sm_addr;
107
108 extern char q_font[];
109 #define QCHAR(c) (c < 32 ? 32 : (c > 127 ? c - 66 : c - 32))
110 #define QFONT(c,line) q_font[QCHAR(c) * 15 + line]
111 #define SM_ADDR(row, col, line) \
112 sm_addr[col + (row * SM_CHEIGHT * SM_COLS) + line * SM_COLS]
113
114
115 static int smg_ioctl __P((void *, u_long, caddr_t, int, struct proc *));
116 static int smg_mmap __P((void *, off_t, int));
117 static int smg_alloc_screen __P((void *, const struct wsscreen_descr *,
118 void **, int *, int *, long *));
119 static void smg_free_screen __P((void *, void *));
120 static void smg_show_screen __P((void *, void *));
121 static void smg_crsr_blink __P((void *));
122
123 const struct wsdisplay_accessops smg_accessops = {
124 smg_ioctl,
125 smg_mmap,
126 smg_alloc_screen,
127 smg_free_screen,
128 smg_show_screen,
129 0 /* load_font */
130 };
131
132 struct smg_screen {
133 int ss_curx;
134 int ss_cury;
135 u_char ss_image[SM_ROWS][SM_COLS]; /* Image of current screen */
136 u_char ss_attr[SM_ROWS][SM_COLS]; /* Reversed etc... */
137 };
138
139 static struct smg_screen smg_conscreen;
140 static struct smg_screen *curscr;
141
142 int
143 smg_match(parent, match, aux)
144 struct device *parent;
145 struct cfdata *match;
146 void *aux;
147 {
148 struct vsbus_attach_args *va = aux;
149 volatile short *curcmd;
150 volatile short *cfgtst;
151 short tmp, tmp2;
152
153 if (vax_boardtype == VAX_BTYP_49)
154 return 0;
155
156 curcmd = (short *)va->va_addr;
157 cfgtst = (short *)vax_map_physmem(VS_CFGTST, 1);
158 /*
159 * Try to find the cursor chip by testing the flip-flop.
160 * If nonexistent, no glass tty.
161 */
162 curcmd[0] = 0x7fff;
163 DELAY(300000);
164 tmp = cfgtst[0];
165 curcmd[0] = 0x8000;
166 DELAY(300000);
167 tmp2 = cfgtst[0];
168 vax_unmap_physmem((vaddr_t)cfgtst, 1);
169
170 if (tmp2 != tmp)
171 return 20; /* Using periodic interrupt */
172 else
173 return 0;
174 }
175
176 void
177 smg_attach(parent, self, aux)
178 struct device *parent, *self;
179 void *aux;
180 {
181 struct wsemuldisplaydev_attach_args aa;
182
183 printf("\n");
184 sm_addr = (caddr_t)vax_map_physmem(SMADDR, (SMSIZE/VAX_NBPG));
185 if (sm_addr == 0) {
186 printf("%s: Couldn't alloc graphics memory.\n", self->dv_xname);
187 return;
188 }
189 curscr = &smg_conscreen;
190 aa.console = !(vax_confdata & 0x20);
191 aa.scrdata = &smg_screenlist;
192 aa.accessops = &smg_accessops;
193 timeout(smg_crsr_blink, 0, hz/2);
194
195 config_found(self, &aa, wsemuldisplaydevprint);
196 }
197
198 static u_char *cursor;
199 static int cur_on;
200
201 static void
202 smg_crsr_blink(arg)
203 void *arg;
204 {
205 if (cur_on)
206 *cursor ^= 255;
207 timeout(smg_crsr_blink, 0, hz/2);
208 }
209
210 void
211 smg_cursor(id, on, row, col)
212 void *id;
213 int on, row, col;
214 {
215 struct smg_screen *ss = id;
216
217 if (ss == curscr) {
218 SM_ADDR(ss->ss_cury, ss->ss_curx, 14) =
219 QFONT(ss->ss_image[ss->ss_cury][ss->ss_curx], 14);
220 cursor = &SM_ADDR(row, col, 14);
221 if ((cur_on = on))
222 *cursor ^= 255;
223 }
224 ss->ss_curx = col;
225 ss->ss_cury = row;
226 }
227
228 int
229 smg_mapchar(id, uni, index)
230 void *id;
231 int uni;
232 unsigned int *index;
233 {
234 if (uni < 256) {
235 *index = uni;
236 return (5);
237 }
238 *index = ' ';
239 return (0);
240 }
241
242 static void
243 smg_putchar(id, row, col, c, attr)
244 void *id;
245 int row, col;
246 u_int c;
247 long attr;
248 {
249 struct smg_screen *ss = id;
250 int i;
251
252 c &= 0xff;
253
254 ss->ss_image[row][col] = c;
255 ss->ss_attr[row][col] = attr;
256 if (ss != curscr)
257 return;
258 for (i = 0; i < 15; i++) {
259 unsigned char ch = QFONT(c, i);
260
261 SM_ADDR(row, col, i) = (attr & WSATTR_REVERSE ? ~ch : ch);
262
263 }
264 if (attr & WSATTR_UNDERLINE)
265 SM_ADDR(row, col, 14) ^= SM_ADDR(row, col, 14);
266 }
267
268 /*
269 * copies columns inside a row.
270 */
271 static void
272 smg_copycols(id, row, srccol, dstcol, ncols)
273 void *id;
274 int row, srccol, dstcol, ncols;
275 {
276 struct smg_screen *ss = id;
277 int i;
278
279 bcopy(&ss->ss_image[row][srccol], &ss->ss_image[row][dstcol], ncols);
280 bcopy(&ss->ss_attr[row][srccol], &ss->ss_attr[row][dstcol], ncols);
281 if (ss != curscr)
282 return;
283 for (i = 0; i < SM_CHEIGHT; i++)
284 bcopy(&SM_ADDR(row,srccol, i), &SM_ADDR(row, dstcol, i),ncols);
285 }
286
287 /*
288 * Erases a bunch of chars inside one row.
289 */
290 static void
291 smg_erasecols(id, row, startcol, ncols, fillattr)
292 void *id;
293 int row, startcol, ncols;
294 long fillattr;
295 {
296 struct smg_screen *ss = id;
297 int i;
298
299 bzero(&ss->ss_image[row][startcol], ncols);
300 bzero(&ss->ss_attr[row][startcol], ncols);
301 if (ss != curscr)
302 return;
303 for (i = 0; i < SM_CHEIGHT; i++)
304 bzero(&SM_ADDR(row, startcol, i), ncols);
305 }
306
307 static void
308 smg_copyrows(id, srcrow, dstrow, nrows)
309 void *id;
310 int srcrow, dstrow, nrows;
311 {
312 struct smg_screen *ss = id;
313 int frows;
314
315 bcopy(&ss->ss_image[srcrow][0], &ss->ss_image[dstrow][0],
316 nrows * SM_COLS);
317 bcopy(&ss->ss_attr[srcrow][0], &ss->ss_attr[dstrow][0],
318 nrows * SM_COLS);
319 if (ss != curscr)
320 return;
321 if (nrows > 25) {
322 frows = nrows >> 1;
323 if (srcrow > dstrow) {
324 bcopy(&sm_addr[(srcrow * SM_NEXTROW)],
325 &sm_addr[(dstrow * SM_NEXTROW)],
326 frows * SM_NEXTROW);
327 bcopy(&sm_addr[((srcrow + frows) * SM_NEXTROW)],
328 &sm_addr[((dstrow + frows) * SM_NEXTROW)],
329 (nrows - frows) * SM_NEXTROW);
330 } else {
331 bcopy(&sm_addr[((srcrow + frows) * SM_NEXTROW)],
332 &sm_addr[((dstrow + frows) * SM_NEXTROW)],
333 (nrows - frows) * SM_NEXTROW);
334 bcopy(&sm_addr[(srcrow * SM_NEXTROW)],
335 &sm_addr[(dstrow * SM_NEXTROW)],
336 frows * SM_NEXTROW);
337 }
338 } else
339 bcopy(&sm_addr[(srcrow * SM_NEXTROW)],
340 &sm_addr[(dstrow * SM_NEXTROW)], nrows * SM_NEXTROW);
341 }
342
343 static void
344 smg_eraserows(id, startrow, nrows, fillattr)
345 void *id;
346 int startrow, nrows;
347 long fillattr;
348 {
349 struct smg_screen *ss = id;
350 int frows;
351
352 bzero(&ss->ss_image[startrow][0], nrows * SM_COLS);
353 bzero(&ss->ss_attr[startrow][0], nrows * SM_COLS);
354 if (ss != curscr)
355 return;
356 if (nrows > 25) {
357 frows = nrows >> 1;
358 bzero(&sm_addr[(startrow * SM_NEXTROW)], frows * SM_NEXTROW);
359 bzero(&sm_addr[((startrow + frows) * SM_NEXTROW)],
360 (nrows - frows) * SM_NEXTROW);
361 } else
362 bzero(&sm_addr[(startrow * SM_NEXTROW)], nrows * SM_NEXTROW);
363 }
364
365 static int
366 smg_alloc_attr(id, fg, bg, flags, attrp)
367 void *id;
368 int fg, bg;
369 int flags;
370 long *attrp;
371 {
372 *attrp = flags;
373 return 0;
374 }
375
376 int
377 smg_ioctl(v, cmd, data, flag, p)
378 void *v;
379 u_long cmd;
380 caddr_t data;
381 int flag;
382 struct proc *p;
383 {
384 struct wsdisplay_fbinfo fb;
385
386 switch (cmd) {
387 case WSDISPLAYIO_GTYPE:
388 *(u_int *)data = WSDISPLAY_TYPE_PM_MONO;
389 break;
390
391 case WSDISPLAYIO_GINFO:
392 fb.height = 864;
393 fb.width = 1024;
394 return copyout(&fb, data, sizeof(struct wsdisplay_fbinfo));
395
396
397 default:
398 return -1;
399 }
400 return 0;
401 }
402
403 static int
404 smg_mmap(v, offset, prot)
405 void *v;
406 off_t offset;
407 int prot;
408 {
409 if (offset >= SMSIZE || offset < 0)
410 return -1;
411 return (SMADDR + offset) >> CLSHIFT;
412 }
413
414 int
415 smg_alloc_screen(v, type, cookiep, curxp, curyp, defattrp)
416 void *v;
417 const struct wsscreen_descr *type;
418 void **cookiep;
419 int *curxp, *curyp;
420 long *defattrp;
421 {
422 *cookiep = malloc(sizeof(struct smg_screen), M_DEVBUF, M_WAITOK);
423 bzero(*cookiep, sizeof(struct smg_screen));
424 *curxp = *curyp = *defattrp = 0;
425 return 0;
426 }
427
428 void
429 smg_free_screen(v, cookie)
430 void *v;
431 void *cookie;
432 {
433 }
434
435 void
436 smg_show_screen(v, cookie)
437 void *v;
438 void *cookie;
439 {
440 struct smg_screen *ss = cookie;
441 int row, col, line;
442
443 if (ss == curscr)
444 return;
445
446 for (row = 0; row < SM_ROWS; row++)
447 for (line = 0; line < SM_CHEIGHT; line++) {
448 for (col = 0; col < SM_COLS; col++) {
449 u_char s, c = ss->ss_image[row][col];
450
451 if (c < 32)
452 c = 32;
453 s = QFONT(c, line);
454 if (ss->ss_attr[row][col] & WSATTR_REVERSE)
455 s ^= 255;
456 SM_ADDR(row, col, line) = s;
457 }
458 if (ss->ss_attr[row][col] & WSATTR_UNDERLINE)
459 SM_ADDR(row, col, line) = 255;
460 }
461 cursor = &sm_addr[(ss->ss_cury * SM_CHEIGHT * SM_COLS) + ss->ss_curx +
462 ((SM_CHEIGHT - 1) * SM_COLS)];
463 curscr = ss;
464 }
465
466 cons_decl(smg);
467
468 #define WSCONSOLEMAJOR 68
469
470 void
471 smgcninit(cndev)
472 struct consdev *cndev;
473 {
474 extern void lkccninit __P((struct consdev *));
475 extern int lkccngetc __P((dev_t));
476 /* Clear screen */
477 memset(sm_addr, 0, 128*864);
478
479 curscr = &smg_conscreen;
480 wsdisplay_cnattach(&smg_stdscreen, &smg_conscreen, 0, 0, 0);
481 cn_tab->cn_dev = makedev(WSCONSOLEMAJOR, 0);
482 #if NLKC
483 lkccninit(cndev);
484 wsdisplay_set_cons_kbd(lkccngetc, nullcnpollc);
485 #endif
486 }
487
488 int smgprobe(void);
489 int
490 smgprobe()
491 {
492 switch (vax_boardtype) {
493 case VAX_BTYP_410:
494 case VAX_BTYP_420:
495 case VAX_BTYP_43:
496 if ((vax_confdata & KA420_CFG_L3CON) ||
497 (vax_confdata & KA420_CFG_MULTU))
498 break; /* doesn't use graphics console */
499 sm_addr = (caddr_t)vax_map_physmem(SMADDR, (SMSIZE/VAX_NBPG));
500 if (sm_addr == 0)
501 return 0;
502
503 return 1;
504
505 default:
506 break;
507 }
508 return 0;
509 }
510