1 /* $NetBSD: pcdisplay_subr.c,v 1.36 2022/03/25 12:24:44 uwe Exp $ */
2 
3 /*
4  * Copyright (c) 1995, 1996 Carnegie-Mellon University.
5  * All rights reserved.
6  *
7  * Author: Chris G. Demetriou
8  *
9  * Permission to use, copy, modify and distribute this software and
10  * its documentation is hereby granted, provided that both the copyright
11  * notice and this permission notice appear in all copies of the
12  * software, derivative works or modified versions, and any portions
13  * thereof, and that both notices appear in supporting documentation.
14  *
15  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
16  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
17  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
18  *
19  * Carnegie Mellon requests users of this software to return to
20  *
21  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
22  *  School of Computer Science
23  *  Carnegie Mellon University
24  *  Pittsburgh PA 15213-3890
25  *
26  * any improvements or extensions that they make and grant Carnegie the
27  * rights to redistribute these changes.
28  */
29 
30 #include <sys/cdefs.h>
31 __KERNEL_RCSID(0, "$NetBSD: pcdisplay_subr.c,v 1.36 2022/03/25 12:24:44 uwe Exp $");
32 
33 #include "opt_wsmsgattrs.h" /* for WSDISPLAY_CUSTOM_OUTPUT */
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/device.h>
38 #include <sys/bus.h>
39 
40 #include <dev/ic/mc6845reg.h>
41 #include <dev/ic/pcdisplayvar.h>
42 #include <dev/wscons/wsconsio.h>
43 
44 #include <dev/wscons/wsdisplayvar.h>
45 
46 void
pcdisplay_cursor_init(struct pcdisplayscreen * scr,int existing)47 pcdisplay_cursor_init(struct pcdisplayscreen *scr, int existing)
48 {
49 #ifdef PCDISPLAY_SOFTCURSOR
50           bus_space_tag_t memt;
51           bus_space_handle_t memh;
52           int off;
53 
54           /* Disable the hardware cursor */
55           pcdisplay_6845_write(scr->hdl, curstart, 0x20);
56           pcdisplay_6845_write(scr->hdl, curend, 0x00);
57 
58           if (existing) {
59                     /*
60                      * This is the first screen. At this point, scr->mem is NULL
61                      * (no backing store), so we can't use pcdisplay_cursor() to
62                      * do this.
63                      */
64                     memt = scr->hdl->ph_memt;
65                     memh = scr->hdl->ph_memh;
66                     off = (scr->cursorrow * scr->type->ncols + scr->cursorcol) * 2
67                         + scr->dispoffset;
68 
69                     scr->cursortmp = bus_space_read_2(memt, memh, off);
70                     bus_space_write_2(memt, memh, off, scr->cursortmp ^ 0x7700);
71           } else
72                     scr->cursortmp = 0;
73 #else
74           /*
75            * Firmware might not have initialized the cursor shape.  Make
76            * sure there's something we can see.
77            * Don't touch the hardware if this is not the first screen.
78            */
79           if (existing) {
80                     pcdisplay_6845_write(scr->hdl, curstart,
81                                              scr->type->fontheight - 2);
82                     pcdisplay_6845_write(scr->hdl, curend,
83                                              scr->type->fontheight - 1);
84           }
85 #endif
86           scr->cursoron = 1;
87 }
88 
89 void
pcdisplay_cursor(void * id,int on,int row,int col)90 pcdisplay_cursor(void *id, int on, int row, int col)
91 {
92 #ifdef PCDISPLAY_SOFTCURSOR
93           struct pcdisplayscreen *scr = id;
94           bus_space_tag_t memt = scr->hdl->ph_memt;
95           bus_space_handle_t memh = scr->hdl->ph_memh;
96           int off;
97 
98           /* Remove old cursor image */
99           if (scr->cursoron) {
100                     off = scr->cursorrow * scr->type->ncols + scr->cursorcol;
101                     if (scr->active)
102                               bus_space_write_2(memt, memh, scr->dispoffset + off * 2,
103                                   scr->cursortmp);
104                     else
105                               scr->mem[off] = scr->cursortmp;
106           }
107 
108           scr->cursorrow = row;
109           scr->cursorcol = col;
110 
111           if ((scr->cursoron = on) == 0)
112                     return;
113 
114           off = (scr->cursorrow * scr->type->ncols + scr->cursorcol);
115           if (scr->active) {
116                     off = off * 2 + scr->dispoffset;
117                     scr->cursortmp = bus_space_read_2(memt, memh, off);
118                     bus_space_write_2(memt, memh, off, scr->cursortmp ^ 0x7700);
119           } else {
120                     scr->cursortmp = scr->mem[off];
121                     scr->mem[off] = scr->cursortmp ^ 0x7700;
122           }
123 #else     /* PCDISPLAY_SOFTCURSOR */
124           struct pcdisplayscreen *scr = id;
125           int pos;
126 
127           scr->cursorrow = row;
128           scr->cursorcol = col;
129           scr->cursoron = on;
130 
131           if (scr->active) {
132                     if (!on)
133                               pos = 0x3fff;
134                     else
135                               pos = scr->dispoffset / 2
136                                         + row * scr->type->ncols + col;
137 
138                     pcdisplay_6845_write(scr->hdl, cursorh, pos >> 8);
139                     pcdisplay_6845_write(scr->hdl, cursorl, pos);
140           }
141 #endif    /* PCDISPLAY_SOFTCURSOR */
142 }
143 
144 #if 0
145 unsigned int
146 pcdisplay_mapchar_simple(void *id, int uni)
147 {
148           if (uni < 128)
149                     return (uni);
150 
151           return (1); /* XXX ??? smiley */
152 }
153 #endif
154 
155 void
pcdisplay_putchar(void * id,int row,int col,unsigned int c,long attr)156 pcdisplay_putchar(void *id, int row, int col, unsigned int c, long attr)
157 {
158           struct pcdisplayscreen *scr = id;
159           bus_space_tag_t memt = scr->hdl->ph_memt;
160           bus_space_handle_t memh = scr->hdl->ph_memh;
161           size_t off;
162 
163           off = row * scr->type->ncols + col;
164 
165           /* check for bogus row and column sizes */
166           if (__predict_false(off >= (scr->type->ncols * scr->type->nrows)))
167                     return;
168 
169           if (scr->active)
170                     bus_space_write_2(memt, memh, scr->dispoffset + off * 2,
171                                           c | (attr << 8));
172           else
173                     scr->mem[off] = c | (attr << 8);
174 
175           scr->visibleoffset = scr->dispoffset;
176 }
177 
178 void
pcdisplay_copycols(void * id,int row,int srccol,int dstcol,int ncols)179 pcdisplay_copycols(void *id, int row, int srccol, int dstcol, int ncols)
180 {
181           struct pcdisplayscreen *scr = id;
182           bus_space_tag_t memt = scr->hdl->ph_memt;
183           bus_space_handle_t memh = scr->hdl->ph_memh;
184           bus_size_t srcoff, dstoff;
185 
186           srcoff = dstoff = row * scr->type->ncols;
187           srcoff += srccol;
188           dstoff += dstcol;
189 
190           if (scr->active)
191                     bus_space_copy_region_2(memt, memh,
192                                                   scr->dispoffset + srcoff * 2,
193                                                   memh, scr->dispoffset + dstoff * 2,
194                                                   ncols);
195           else
196                     memcpy(&scr->mem[dstoff], &scr->mem[srcoff], ncols * 2);
197 }
198 
199 void
pcdisplay_erasecols(void * id,int row,int startcol,int ncols,long fillattr)200 pcdisplay_erasecols(void *id, int row, int startcol, int ncols, long fillattr)
201 {
202           struct pcdisplayscreen *scr = id;
203           bus_space_tag_t memt = scr->hdl->ph_memt;
204           bus_space_handle_t memh = scr->hdl->ph_memh;
205           bus_size_t off;
206           u_int16_t val;
207           int i;
208 
209           off = row * scr->type->ncols + startcol;
210 
211           val = (fillattr << 8) | ' ';
212 
213           if (scr->active)
214                     bus_space_set_region_2(memt, memh, scr->dispoffset + off * 2,
215                                                val, ncols);
216           else
217                     for (i = 0; i < ncols; i++)
218                               scr->mem[off + i] = val;
219 }
220 
221 void
pcdisplay_copyrows(void * id,int srcrow,int dstrow,int nrows)222 pcdisplay_copyrows(void *id, int srcrow, int dstrow, int nrows)
223 {
224           struct pcdisplayscreen *scr = id;
225           bus_space_tag_t memt = scr->hdl->ph_memt;
226           bus_space_handle_t memh = scr->hdl->ph_memh;
227           int ncols = scr->type->ncols;
228           bus_size_t srcoff, dstoff;
229 
230           srcoff = srcrow * ncols + 0;
231           dstoff = dstrow * ncols + 0;
232 
233           if (scr->active)
234                     bus_space_copy_region_2(memt, memh,
235                                                   scr->dispoffset + srcoff * 2,
236                                                   memh, scr->dispoffset + dstoff * 2,
237                                                   nrows * ncols);
238           else
239                     memcpy(&scr->mem[dstoff], &scr->mem[srcoff],
240                           nrows * ncols * 2);
241 }
242 
243 void
pcdisplay_eraserows(void * id,int startrow,int nrows,long fillattr)244 pcdisplay_eraserows(void *id, int startrow, int nrows, long fillattr)
245 {
246           struct pcdisplayscreen *scr = id;
247           bus_space_tag_t memt = scr->hdl->ph_memt;
248           bus_space_handle_t memh = scr->hdl->ph_memh;
249           bus_size_t off, count;
250           u_int16_t val;
251           u_int i;
252 
253           off = startrow * scr->type->ncols;
254           count = nrows * scr->type->ncols;
255 
256           val = (fillattr << 8) | ' ';
257 
258           if (scr->active)
259                     bus_space_set_region_2(memt, memh, scr->dispoffset + off * 2,
260                                                val, count);
261           else
262                     for (i = 0; i < count; i++)
263                               scr->mem[off + i] = val;
264 }
265 
266 #ifdef WSDISPLAY_CUSTOM_OUTPUT
267 void
pcdisplay_replaceattr(void * id,long oldattr,long newattr)268 pcdisplay_replaceattr(void *id, long oldattr, long newattr)
269 {
270           struct pcdisplayscreen *scr = id;
271           bus_space_tag_t memt = scr->hdl->ph_memt;
272           bus_space_handle_t memh = scr->hdl->ph_memh;
273           int off;
274           uint16_t chardata;
275 
276           if (scr->active)
277                     for (off = 0; off < scr->type->nrows * scr->type->ncols;
278                          off++) {
279                               chardata = bus_space_read_2(memt, memh,
280                                                                 scr->dispoffset + off * 2);
281                               if ((long)(chardata >> 8) == oldattr)
282                                         bus_space_write_2(memt, memh,
283                                                           scr->dispoffset + off * 2,
284                                                               ((u_int16_t)(newattr << 8)) |
285                                                           (chardata & 0x00FF));
286                     }
287           else
288                     for (off = 0; off < scr->type->nrows * scr->type->ncols;
289                          off++) {
290                               chardata = scr->mem[off];
291                               if ((long)(chardata >> 8) == oldattr)
292                                         scr->mem[off] = ((u_int16_t)(newattr << 8)) |
293                                                         (chardata & 0x00FF);
294                     }
295 }
296 #endif /* WSDISPLAY_CUSTOM_OUTPUT */
297 
298 int
pcdisplay_getwschar(struct pcdisplayscreen * scr,struct wsdisplay_char * wschar)299 pcdisplay_getwschar(struct pcdisplayscreen *scr, struct wsdisplay_char *wschar)
300 {
301           size_t off;
302           uint16_t chardata;
303           uint8_t attrbyte;
304 
305           KASSERT(scr != NULL && wschar != NULL);
306 
307           off = wschar->row * scr->type->ncols + wschar->col;
308           if (off >= scr->type->ncols * scr->type->nrows)
309                     return EINVAL;
310 
311           if (scr->active)
312                     chardata = bus_space_read_2(scr->hdl->ph_memt,
313                         scr->hdl->ph_memh, scr->dispoffset + off * 2);
314           else
315                     chardata = scr->mem[off];
316 
317           wschar->letter = (chardata & 0x00FF);
318           wschar->flags = 0;
319           attrbyte = (chardata & 0xFF00) >> 8;
320           if ((attrbyte & 0x08)) wschar->flags |= WSDISPLAY_CHAR_BRIGHT;
321           if ((attrbyte & 0x80)) wschar->flags |= WSDISPLAY_CHAR_BLINK;
322           wschar->foreground = attrbyte & 0x07;
323           wschar->background = (attrbyte >> 4) & 0x07;
324 
325           return 0;
326 }
327 
328 int
pcdisplay_putwschar(struct pcdisplayscreen * scr,struct wsdisplay_char * wschar)329 pcdisplay_putwschar(struct pcdisplayscreen *scr, struct wsdisplay_char *wschar)
330 {
331           size_t off;
332           uint16_t chardata;
333           uint8_t attrbyte;
334 
335           KASSERT(scr != NULL && wschar != NULL);
336 
337           off = wschar->row * scr->type->ncols + wschar->col;
338           if (off >= (scr->type->ncols * scr->type->nrows))
339                     return EINVAL;
340 
341           attrbyte = wschar->background & 0x07;
342           if (wschar->flags & WSDISPLAY_CHAR_BLINK) attrbyte |= 0x08;
343           attrbyte <<= 4;
344           attrbyte |= wschar->foreground & 0x07;
345           if (wschar->flags & WSDISPLAY_CHAR_BRIGHT) attrbyte |= 0x08;
346           chardata = (attrbyte << 8) | wschar->letter;
347 
348           if (scr->active)
349                     bus_space_write_2(scr->hdl->ph_memt, scr->hdl->ph_memh,
350                         scr->dispoffset + off * 2, chardata);
351           else
352                     scr->mem[off] = chardata;
353 
354           return 0;
355 }
356