1 /* $NetBSD: smg.c,v 1.52 2009/03/19 22:52:16 he Exp $ */
3 * Copyright (c) 1998 Ludd, University of Lule}, Sweden.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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
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.
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: smg.c,v 1.52 2009/03/19 22:52:16 he Exp $");
36 #include <sys/param.h>
37 #include <sys/device.h>
38 #include <sys/systm.h>
39 #include <sys/callout.h>
41 #include <sys/malloc.h>
43 #include <sys/kernel.h>
45 #include <machine/vsbus.h>
46 #include <machine/sid.h>
47 #include <machine/cpu.h>
48 #include <machine/ka420.h>
52 #include <dev/dec/dzreg.h>
53 #include <dev/dec/dzvar.h>
54 #include <dev/dec/dzkbdvar.h>
56 #include <dev/wscons/wsdisplayvar.h>
57 #include <dev/wscons/wsconsio.h>
58 #include <dev/wscons/wscons_callbacks.h>
59 #include <dev/wsfont/wsfont.h>
62 #include "opt_wsfont.h"
64 /* Screen hardware defs */
65 #define SM_COLS 128 /* char width of screen */
66 #define SM_ROWS 57 /* rows of char on screen */
67 #define SM_CHEIGHT 15 /* lines a char consists of */
68 #define SM_NEXTROW (SM_COLS * SM_CHEIGHT)
70 #define SM_XWIDTH 1024
72 /* Cursor register definitions */
86 #define CUR_CMD_TEST 0x8000
87 #define CUR_CMD_HSHI 0x4000
88 #define CUR_CMD_VBHI 0x2000
89 #define CUR_CMD_LODSA 0x1000
90 #define CUR_CMD_FORG2 0x0800
91 #define CUR_CMD_ENRG2 0x0400
92 #define CUR_CMD_FORG1 0x0200
93 #define CUR_CMD_ENRG1 0x0100
94 #define CUR_CMD_XHWID 0x0080
95 #define CUR_CMD_XHCL1 0x0040
96 #define CUR_CMD_XHCLP 0x0020
97 #define CUR_CMD_XHAIR 0x0010
98 #define CUR_CMD_FOPB 0x0008
99 #define CUR_CMD_ENPB 0x0004
100 #define CUR_CMD_FOPA 0x0002
101 #define CUR_CMD_ENPA 0x0001
103 #define CUR_XBIAS 216 /* Add to cursor position */
106 #define WRITECUR(addr, val) *(volatile uint16_t *)(curaddr + (addr)) = (val)
107 static char *curaddr
;
108 static uint16_t curcmd
, curx
, cury
, hotX
, hotY
;
109 static int bgmask
, fgmask
;
111 static int smg_match(device_t
, cfdata_t
, void *);
112 static void smg_attach(device_t
, device_t
, void *);
114 CFATTACH_DECL_NEW(smg
, 0,
115 smg_match
, smg_attach
, NULL
, NULL
);
117 static void smg_cursor(void *, int, int, int);
118 static int smg_mapchar(void *, int, unsigned int *);
119 static void smg_putchar(void *, int, int, u_int
, long);
120 static void smg_copycols(void *, int, int, int,int);
121 static void smg_erasecols(void *, int, int, int, long);
122 static void smg_copyrows(void *, int, int, int);
123 static void smg_eraserows(void *, int, int, long);
124 static int smg_allocattr(void *, int, int, int, long *);
126 const struct wsdisplay_emulops smg_emulops
= {
127 .cursor
= smg_cursor
,
128 .mapchar
= smg_mapchar
,
129 .putchar
= smg_putchar
,
130 .copycols
= smg_copycols
,
131 .erasecols
= smg_erasecols
,
132 .copyrows
= smg_copyrows
,
133 .eraserows
= smg_eraserows
,
134 .allocattr
= smg_allocattr
137 const struct wsscreen_descr smg_stdscreen
= {
141 .textops
= &smg_emulops
,
143 .fontheight
= SM_CHEIGHT
,
144 .capabilities
= WSSCREEN_UNDERLINE
|WSSCREEN_REVERSE
,
147 const struct wsscreen_descr
*_smg_scrlist
[] = {
151 const struct wsscreen_list smg_screenlist
= {
152 .nscreens
= __arraycount(_smg_scrlist
),
153 .screens
= _smg_scrlist
,
156 static char *sm_addr
;
160 #define QCHAR(c) (c < 32 ? 32 : (c > 127 ? c - 66 : c - 32))
161 #define QFONT(c,line) qf[QCHAR(c) * 15 + line]
162 #define SM_ADDR(row, col, line) \
163 sm_addr[col + (row * SM_CHEIGHT * SM_COLS) + line * SM_COLS]
166 static int smg_ioctl(void *, void *, u_long
, void *, int, struct lwp
*);
167 static paddr_t
smg_mmap(void *, void *, off_t
, int);
168 static int smg_alloc_screen(void *, const struct wsscreen_descr
*,
169 void **, int *, int *, long *);
170 static void smg_free_screen(void *, void *);
171 static int smg_show_screen(void *, void *, int,
172 void (*) (void *, int, int), void *);
173 static void smg_crsr_blink(void *);
175 const struct wsdisplay_accessops smg_accessops
= {
178 .alloc_screen
= smg_alloc_screen
,
179 .free_screen
= smg_free_screen
,
180 .show_screen
= smg_show_screen
,
186 u_char ss_image
[SM_ROWS
][SM_COLS
]; /* Image of current screen */
187 u_char ss_attr
[SM_ROWS
][SM_COLS
]; /* Reversed etc... */
190 static struct smg_screen smg_conscreen
;
191 static struct smg_screen
*curscr
;
193 static callout_t smg_cursor_ch
;
196 smg_match(device_t parent
, cfdata_t match
, void *aux
)
198 struct vsbus_attach_args
* const va
= aux
;
199 volatile uint16_t *ccmd
;
200 volatile uint16_t *cfgtst
;
203 if (vax_boardtype
== VAX_BTYP_49
|| vax_boardtype
== VAX_BTYP_53
)
206 ccmd
= (uint16_t *)va
->va_addr
;
207 cfgtst
= (uint16_t *)vax_map_physmem(VS_CFGTST
, 1);
209 * Try to find the cursor chip by testing the flip-flop.
210 * If nonexistent, no glass tty.
212 ccmd
[0] = CUR_CMD_HSHI
|CUR_CMD_FOPB
;
215 ccmd
[0] = CUR_CMD_TEST
|CUR_CMD_HSHI
;
218 vax_unmap_physmem((vaddr_t
)cfgtst
, 1);
221 return 20; /* Using periodic interrupt */
227 smg_attach(device_t parent
, device_t self
, void *aux
)
229 struct wsemuldisplaydev_attach_args aa
;
230 struct wsdisplay_font
*console_font
;
234 sm_addr
= (void *)vax_map_physmem(SMADDR
, (SMSIZE
/VAX_NBPG
));
235 curaddr
= (void *)vax_map_physmem(KA420_CUR_BASE
, 1);
237 aprint_error_dev(self
, "Couldn't alloc graphics memory.\n");
241 callout_init(&smg_cursor_ch
, 0);
242 curscr
= &smg_conscreen
;
243 aa
.console
= (vax_confdata
& (KA420_CFG_L3CON
|KA420_CFG_MULTU
)) == 0;
245 aa
.scrdata
= &smg_screenlist
;
246 aa
.accessops
= &smg_accessops
;
247 callout_reset(&smg_cursor_ch
, hz
/ 2, smg_crsr_blink
, NULL
);
248 curcmd
= CUR_CMD_HSHI
;
249 WRITECUR(CUR_CMD
, curcmd
);
250 if ((fcookie
= wsfont_find(NULL
, 8, 15, 0,
251 WSDISPLAY_FONTORDER_R2L
, WSDISPLAY_FONTORDER_L2R
)) < 0) {
252 aprint_error_dev(self
, "could not find 8x15 font\n");
255 if (wsfont_lock(fcookie
, &console_font
) != 0) {
256 aprint_error_dev(self
, "could not lock 8x15 font\n");
259 qf
= console_font
->data
;
261 config_found(self
, &aa
, wsemuldisplaydevprint
);
264 static u_char
*cursor
;
268 smg_crsr_blink(void *arg
)
272 callout_reset(&smg_cursor_ch
, hz
/ 2, smg_crsr_blink
, NULL
);
276 smg_cursor(void *id
, int on
, int row
, int col
)
278 struct smg_screen
* const ss
= id
;
281 SM_ADDR(ss
->ss_cury
, ss
->ss_curx
, 14) =
282 QFONT(ss
->ss_image
[ss
->ss_cury
][ss
->ss_curx
], 14);
283 cursor
= &SM_ADDR(row
, col
, 14);
292 smg_mapchar(void *id
, int uni
, unsigned int *index
)
303 smg_putchar(void *id
, int row
, int col
, u_int c
, long attr
)
305 struct smg_screen
* const ss
= id
;
310 ss
->ss_image
[row
][col
] = c
;
311 ss
->ss_attr
[row
][col
] = attr
;
314 for (i
= 0; i
< 15; i
++) {
315 unsigned char ch
= QFONT(c
, i
);
317 SM_ADDR(row
, col
, i
) = (attr
& WSATTR_REVERSE
? ~ch
: ch
);
320 if (attr
& WSATTR_UNDERLINE
)
321 SM_ADDR(row
, col
, 14) ^= SM_ADDR(row
, col
, 14);
325 * copies columns inside a row.
328 smg_copycols(void *id
, int row
, int srccol
, int dstcol
, int ncols
)
330 struct smg_screen
* const ss
= id
;
333 memcpy(&ss
->ss_image
[row
][dstcol
], &ss
->ss_image
[row
][srccol
], ncols
);
334 memcpy(&ss
->ss_attr
[row
][dstcol
], &ss
->ss_attr
[row
][srccol
], ncols
);
337 for (i
= 0; i
< SM_CHEIGHT
; i
++)
338 memcpy(&SM_ADDR(row
, dstcol
, i
), &SM_ADDR(row
, srccol
, i
), ncols
);
342 * Erases a bunch of chars inside one row.
345 smg_erasecols(void *id
, int row
, int startcol
, int ncols
, long fillattr
)
347 struct smg_screen
* const ss
= id
;
350 memset(&ss
->ss_image
[row
][startcol
], 0, ncols
);
351 memset(&ss
->ss_attr
[row
][startcol
], 0, ncols
);
354 for (i
= 0; i
< SM_CHEIGHT
; i
++)
355 memset(&SM_ADDR(row
, startcol
, i
), 0, ncols
);
359 smg_copyrows(void *id
, int srcrow
, int dstrow
, int nrows
)
361 struct smg_screen
* const ss
= id
;
364 memcpy(&ss
->ss_image
[dstrow
][0], &ss
->ss_image
[srcrow
][0],
366 memcpy(&ss
->ss_attr
[dstrow
][0], &ss
->ss_attr
[srcrow
][0],
372 if (srcrow
> dstrow
) {
373 bcopy(&sm_addr
[(srcrow
* SM_NEXTROW
)],
374 &sm_addr
[(dstrow
* SM_NEXTROW
)],
376 bcopy(&sm_addr
[((srcrow
+ frows
) * SM_NEXTROW
)],
377 &sm_addr
[((dstrow
+ frows
) * SM_NEXTROW
)],
378 (nrows
- frows
) * SM_NEXTROW
);
380 bcopy(&sm_addr
[((srcrow
+ frows
) * SM_NEXTROW
)],
381 &sm_addr
[((dstrow
+ frows
) * SM_NEXTROW
)],
382 (nrows
- frows
) * SM_NEXTROW
);
383 bcopy(&sm_addr
[(srcrow
* SM_NEXTROW
)],
384 &sm_addr
[(dstrow
* SM_NEXTROW
)],
388 bcopy(&sm_addr
[(srcrow
* SM_NEXTROW
)],
389 &sm_addr
[(dstrow
* SM_NEXTROW
)], nrows
* SM_NEXTROW
);
393 smg_eraserows(void *id
, int startrow
, int nrows
, long fillattr
)
395 struct smg_screen
* const ss
= id
;
398 memset(&ss
->ss_image
[startrow
][0], 0, nrows
* SM_COLS
);
399 memset(&ss
->ss_attr
[startrow
][0], 0, nrows
* SM_COLS
);
404 memset(&sm_addr
[(startrow
* SM_NEXTROW
)], 0, frows
* SM_NEXTROW
);
405 memset(&sm_addr
[((startrow
+ frows
) * SM_NEXTROW
)], 0,
406 (nrows
- frows
) * SM_NEXTROW
);
408 memset(&sm_addr
[(startrow
* SM_NEXTROW
)], 0, nrows
* SM_NEXTROW
);
412 smg_allocattr(void *id
, int fg
, int bg
, int flags
, long *attrp
)
419 setcursor(struct wsdisplay_cursor
*v
)
421 uint16_t red
, green
, blue
;
422 uint32_t curfg
[16], curmask
[16];
426 if (v
->which
& WSDISPLAY_CURSOR_DOCUR
) {
428 curcmd
|= CUR_CMD_ENPB
|CUR_CMD_ENPA
;
430 curcmd
&= ~(CUR_CMD_ENPB
|CUR_CMD_ENPA
);
431 WRITECUR(CUR_CMD
, curcmd
);
433 if (v
->which
& WSDISPLAY_CURSOR_DOHOT
) {
437 if (v
->which
& WSDISPLAY_CURSOR_DOCMAP
) {
438 /* First background */
439 red
= fusword(v
->cmap
.red
);
440 green
= fusword(v
->cmap
.green
);
441 blue
= fusword(v
->cmap
.blue
);
442 bgmask
= (((30L * red
+ 59L * green
+ 11L * blue
) >> 8) >=
443 (((1<<8)-1)*50)) ? ~0 : 0;
444 red
= fusword(v
->cmap
.red
+2);
445 green
= fusword(v
->cmap
.green
+2);
446 blue
= fusword(v
->cmap
.blue
+2);
447 fgmask
= (((30L * red
+ 59L * green
+ 11L * blue
) >> 8) >=
448 (((1<<8)-1)*50)) ? ~0 : 0;
450 if (v
->which
& WSDISPLAY_CURSOR_DOSHAPE
) {
451 WRITECUR(CUR_CMD
, curcmd
| CUR_CMD_LODSA
);
452 copyin(v
->image
, curfg
, sizeof(curfg
));
453 copyin(v
->mask
, curmask
, sizeof(curmask
));
454 for (i
= 0; i
< sizeof(curfg
)/sizeof(curfg
[0]); i
++) {
455 WRITECUR(CUR_LOAD
, ((uint16_t)curfg
[i
] & fgmask
) |
456 (((uint16_t)curmask
[i
] & (uint16_t)~curfg
[i
])
459 for (i
= 0; i
< sizeof(curmask
)/sizeof(curmask
[0]); i
++) {
460 WRITECUR(CUR_LOAD
, (uint16_t)curmask
[i
]);
462 WRITECUR(CUR_CMD
, curcmd
);
467 smg_ioctl(void *v
, void *vs
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
469 struct wsdisplay_fbinfo
*fb
= (void *)data
;
470 static uint16_t curc
;
473 case WSDISPLAYIO_GTYPE
:
474 *(u_int
*)data
= WSDISPLAY_TYPE_VAX_MONO
;
477 case WSDISPLAYIO_GINFO
:
478 fb
->height
= SM_YWIDTH
;
479 fb
->width
= SM_XWIDTH
;
484 case WSDISPLAYIO_SVIDEO
:
485 if (*(u_int
*)data
== WSDISPLAYIO_VIDEO_ON
) {
489 curcmd
&= ~(CUR_CMD_FOPA
|CUR_CMD_ENPA
);
490 curcmd
|= CUR_CMD_FOPB
;
492 WRITECUR(CUR_CMD
, curcmd
);
495 case WSDISPLAYIO_GVIDEO
:
496 *(u_int
*)data
= (curcmd
& CUR_CMD_FOPB
?
497 WSDISPLAYIO_VIDEO_OFF
: WSDISPLAYIO_VIDEO_ON
);
500 case WSDISPLAYIO_SCURSOR
:
501 setcursor((struct wsdisplay_cursor
*)data
);
504 case WSDISPLAYIO_SCURPOS
:
505 curx
= ((struct wsdisplay_curpos
*)data
)->x
;
506 cury
= ((struct wsdisplay_curpos
*)data
)->y
;
507 WRITECUR(CUR_XPOS
, curx
+ CUR_XBIAS
);
508 WRITECUR(CUR_YPOS
, cury
+ CUR_YBIAS
);
511 case WSDISPLAYIO_GCURPOS
:
512 ((struct wsdisplay_curpos
*)data
)->x
= curx
;
513 ((struct wsdisplay_curpos
*)data
)->y
= cury
;
516 case WSDISPLAYIO_GCURMAX
:
517 ((struct wsdisplay_curpos
*)data
)->x
= 16;
518 ((struct wsdisplay_curpos
*)data
)->y
= 16;
528 smg_mmap(void *v
, void *vs
, off_t offset
, int prot
)
530 if (offset
>= SMSIZE
|| offset
< 0)
532 return (SMADDR
+ offset
) >> PGSHIFT
;
536 smg_alloc_screen(void *v
, const struct wsscreen_descr
*type
, void **cookiep
,
537 int *curxp
, int *curyp
, long *defattrp
)
539 *cookiep
= malloc(sizeof(struct smg_screen
), M_DEVBUF
, M_WAITOK
|M_ZERO
);
540 *curxp
= *curyp
= *defattrp
= 0;
545 smg_free_screen(void *v
, void *cookie
)
550 smg_show_screen(void *v
, void *cookie
, int waitok
,
551 void (*cb
)(void *, int, int), void *cbarg
)
553 struct smg_screen
*ss
= cookie
;
559 for (row
= 0; row
< SM_ROWS
; row
++)
560 for (line
= 0; line
< SM_CHEIGHT
; line
++) {
561 for (col
= 0; col
< SM_COLS
; col
++) {
562 u_char s
, c
= ss
->ss_image
[row
][col
];
567 if (ss
->ss_attr
[row
][col
] & WSATTR_REVERSE
)
569 SM_ADDR(row
, col
, line
) = s
;
570 if (ss
->ss_attr
[row
][col
] & WSATTR_UNDERLINE
)
571 SM_ADDR(row
, col
, line
) = 255;
574 cursor
= &sm_addr
[(ss
->ss_cury
* SM_CHEIGHT
* SM_COLS
) + ss
->ss_curx
+
575 ((SM_CHEIGHT
- 1) * SM_COLS
)];
583 smgcninit(struct consdev
*cndev
)
586 struct wsdisplay_font
*console_font
;
587 extern void lkccninit(struct consdev
*);
588 extern int lkccngetc(dev_t
);
589 extern int dz_vsbus_lk201_cnattach(int);
591 memset(sm_addr
, 0, 128*864);
593 callout_init(&smg_cursor_ch
, 0);
595 curscr
= &smg_conscreen
;
596 wsdisplay_cnattach(&smg_stdscreen
, &smg_conscreen
, 0, 0, 0);
597 cn_tab
->cn_pri
= CN_INTERNAL
;
598 if ((fcookie
= wsfont_find(NULL
, 8, 15, 0,
599 WSDISPLAY_FONTORDER_R2L
, WSDISPLAY_FONTORDER_L2R
)) < 0)
601 printf("smg: could not find 8x15 font\n");
604 if (wsfont_lock(fcookie
, &console_font
) != 0) {
605 printf("smg: could not lock 8x15 font\n");
608 qf
= console_font
->data
;
611 dzkbd_cnattach(0); /* Connect keyboard and screen together */
616 * Called very early to setup the glass tty as console.
617 * Because it's called before the VM system is inited, virtual memory
618 * for the framebuffer can be stolen directly without disturbing anything.
621 smgcnprobe(struct consdev
*cndev
)
623 extern vaddr_t virtual_avail
;
624 extern const struct cdevsw wsdisplay_cdevsw
;
626 switch (vax_boardtype
) {
630 if ((vax_confdata
& KA420_CFG_L3CON
) ||
631 (vax_confdata
& KA420_CFG_MULTU
))
632 break; /* doesn't use graphics console */
633 sm_addr
= (void *)virtual_avail
;
634 virtual_avail
+= SMSIZE
;
635 ioaccess((vaddr_t
)sm_addr
, SMADDR
, (SMSIZE
/VAX_NBPG
));
636 cndev
->cn_pri
= CN_INTERNAL
;
637 cndev
->cn_dev
= makedev(cdevsw_lookup_major(&wsdisplay_cdevsw
),