1 /* $MirOS: src/sys/dev/isa/pcdisplay.c,v 1.3 2009/12/26 16:00:51 tg Exp $ */
2 /* $OpenBSD: pcdisplay.c,v 1.9 2006/11/29 19:08:22 miod Exp $ */
3 /* $NetBSD: pcdisplay.c,v 1.9.4.1 2000/06/30 16:27:48 simonb Exp $ */
4
5 /*
6 * Copyright (c) 1998
7 * Matthias Drochner. All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 */
30
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/kernel.h>
34 #include <sys/device.h>
35 #include <sys/malloc.h>
36 #include <machine/bus.h>
37
38 #include <dev/isa/isavar.h>
39 #include <dev/isa/isareg.h>
40
41 #include <dev/ic/mc6845reg.h>
42 #include <dev/ic/pcdisplayvar.h>
43 #include <dev/isa/pcdisplayvar.h>
44
45 #include <dev/ic/pcdisplay.h>
46
47 #include <dev/wscons/wsconsio.h>
48 #include <dev/wscons/wsdisplayvar.h>
49
50 struct pcdisplay_config {
51 struct pcdisplayscreen pcs;
52 struct pcdisplay_handle dc_ph;
53 int mono;
54 };
55
56 struct pcdisplay_softc {
57 struct device sc_dev;
58 struct pcdisplay_config *sc_dc;
59 int nscreens;
60 };
61
62 static int pcdisplayconsole, pcdisplay_console_attached;
63 static struct pcdisplay_config pcdisplay_console_dc;
64
65 int pcdisplay_match(struct device *, void *, void *);
66 void pcdisplay_attach(struct device *, struct device *, void *);
67
68 static int pcdisplay_is_console(bus_space_tag_t);
69 static int pcdisplay_probe_col(bus_space_tag_t, bus_space_tag_t);
70 static int pcdisplay_probe_mono(bus_space_tag_t, bus_space_tag_t);
71 static void pcdisplay_init(struct pcdisplay_config *,
72 bus_space_tag_t, bus_space_tag_t,
73 int);
74 static int pcdisplay_alloc_attr(void *, int, int, int, long *);
75 static void pcdisplay_unpack_attr(void *, long, int *, int *, int *);
76
77 struct cfattach pcdisplay_ca = {
78 sizeof(struct pcdisplay_softc), pcdisplay_match, pcdisplay_attach,
79 };
80
81 const struct wsdisplay_emulops pcdisplay_emulops = {
82 pcdisplay_cursor,
83 pcdisplay_mapchar,
84 pcdisplay_putchar,
85 pcdisplay_copycols,
86 pcdisplay_erasecols,
87 pcdisplay_copyrows,
88 pcdisplay_eraserows,
89 pcdisplay_alloc_attr,
90 pcdisplay_unpack_attr
91 };
92
93 const struct wsscreen_descr pcdisplay_scr = {
94 "80x25", 80, 25,
95 &pcdisplay_emulops,
96 0, 0, /* no font support */
97 #if 0
98 WSSCREEN_REVERSE /* that's minimal... */
99 #else
100 /* there is no fallback anyway, so support them all, most screens do */
101 WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE
102 #endif
103 };
104
105 const struct wsscreen_descr *_pcdisplay_scrlist[] = {
106 &pcdisplay_scr,
107 };
108
109 const struct wsscreen_list pcdisplay_screenlist = {
110 sizeof(_pcdisplay_scrlist) / sizeof(struct wsscreen_descr *),
111 _pcdisplay_scrlist
112 };
113
114 static int pcdisplay_ioctl(void *, u_long, caddr_t, int, struct proc *);
115 static paddr_t pcdisplay_mmap(void *, off_t, int);
116 static int pcdisplay_alloc_screen(void *, const struct wsscreen_descr *,
117 void **, int *, int *, long *);
118 static void pcdisplay_free_screen(void *, void *);
119 static int pcdisplay_show_screen(void *, void *, int,
120 void (*) (void *, int, int), void *);
121
122 const struct wsdisplay_accessops pcdisplay_accessops = {
123 pcdisplay_ioctl,
124 pcdisplay_mmap,
125 pcdisplay_alloc_screen,
126 pcdisplay_free_screen,
127 pcdisplay_show_screen,
128 0 /* load_font */
129 };
130
131 static int
pcdisplay_probe_col(iot,memt)132 pcdisplay_probe_col(iot, memt)
133 bus_space_tag_t iot, memt;
134 {
135 bus_space_handle_t memh, ioh_6845;
136 u_int16_t oldval, val;
137
138 if (bus_space_map(memt, 0xb8000, 0x8000, 0, &memh))
139 return (0);
140 oldval = bus_space_read_2(memt, memh, 0);
141 bus_space_write_2(memt, memh, 0, 0xa55a);
142 val = bus_space_read_2(memt, memh, 0);
143 bus_space_write_2(memt, memh, 0, oldval);
144 bus_space_unmap(memt, memh, 0x8000);
145 if (val != 0xa55a)
146 return (0);
147
148 if (bus_space_map(iot, 0x3d0, 0x10, 0, &ioh_6845))
149 return (0);
150 bus_space_unmap(iot, ioh_6845, 0x10);
151
152 return (1);
153 }
154
155 static int
pcdisplay_probe_mono(iot,memt)156 pcdisplay_probe_mono(iot, memt)
157 bus_space_tag_t iot, memt;
158 {
159 bus_space_handle_t memh, ioh_6845;
160 u_int16_t oldval, val;
161
162 if (bus_space_map(memt, 0xb0000, 0x8000, 0, &memh))
163 return (0);
164 oldval = bus_space_read_2(memt, memh, 0);
165 bus_space_write_2(memt, memh, 0, 0xa55a);
166 val = bus_space_read_2(memt, memh, 0);
167 bus_space_write_2(memt, memh, 0, oldval);
168 bus_space_unmap(memt, memh, 0x8000);
169 if (val != 0xa55a)
170 return (0);
171
172 if (bus_space_map(iot, 0x3b0, 0x10, 0, &ioh_6845))
173 return (0);
174 bus_space_unmap(iot, ioh_6845, 0x10);
175
176 return (1);
177 }
178
179 static void
pcdisplay_init(dc,iot,memt,mono)180 pcdisplay_init(dc, iot, memt, mono)
181 struct pcdisplay_config *dc;
182 bus_space_tag_t iot, memt;
183 int mono;
184 {
185 struct pcdisplay_handle *ph = &dc->dc_ph;
186 int cpos;
187
188 ph->ph_iot = iot;
189 ph->ph_memt = memt;
190 dc->mono = mono;
191
192 if (bus_space_map(memt, mono ? 0xb0000 : 0xb8000, 0x8000,
193 0, &ph->ph_memh))
194 panic("pcdisplay_init: cannot map memory");
195 if (bus_space_map(iot, mono ? 0x3b0 : 0x3d0, 0x10,
196 0, &ph->ph_ioh_6845))
197 panic("pcdisplay_init: cannot map io");
198
199 /*
200 * initialize the only screen
201 */
202 dc->pcs.hdl = ph;
203 dc->pcs.type = &pcdisplay_scr;
204 dc->pcs.active = 1;
205 dc->pcs.mem = NULL;
206
207 cpos = pcdisplay_6845_read(ph, cursorh) << 8;
208 cpos |= pcdisplay_6845_read(ph, cursorl);
209
210 /* make sure we have a valid cursor position */
211 if (cpos < 0 || cpos >= pcdisplay_scr.nrows * pcdisplay_scr.ncols)
212 cpos = 0;
213
214 dc->pcs.dispoffset = 0;
215 dc->pcs.visibleoffset = 0;
216
217 dc->pcs.vc_crow = cpos / pcdisplay_scr.ncols;
218 dc->pcs.vc_ccol = cpos % pcdisplay_scr.ncols;
219 pcdisplay_cursor_init(&dc->pcs, 1);
220 }
221
222 int
pcdisplay_match(parent,match,aux)223 pcdisplay_match(parent, match, aux)
224 struct device *parent;
225 void *match;
226 void *aux;
227 {
228 struct isa_attach_args *ia = aux;
229 int mono;
230
231 /* If values are hardwired to something that they can't be, punt. */
232 if ((ia->ia_iobase != IOBASEUNK &&
233 ia->ia_iobase != 0x3d0 &&
234 ia->ia_iobase != 0x3b0) ||
235 /* ia->ia_iosize != 0 || XXX isa.c */
236 (ia->ia_maddr != MADDRUNK &&
237 ia->ia_maddr != 0xb8000 &&
238 ia->ia_maddr != 0xb0000) ||
239 (ia->ia_msize != 0 && ia->ia_msize != 0x8000) ||
240 ia->ia_irq != IRQUNK || ia->ia_drq != DRQUNK)
241 return (0);
242
243 if (pcdisplay_is_console(ia->ia_iot))
244 mono = pcdisplay_console_dc.mono;
245 else if (ia->ia_iobase != 0x3b0 && ia->ia_maddr != 0xb0000 &&
246 pcdisplay_probe_col(ia->ia_iot, ia->ia_memt))
247 mono = 0;
248 else if (ia->ia_iobase != 0x3d0 && ia->ia_maddr != 0xb8000 &&
249 pcdisplay_probe_mono(ia->ia_iot, ia->ia_memt))
250 mono = 1;
251 else
252 return (0);
253
254 ia->ia_iobase = mono ? 0x3b0 : 0x3d0;
255 ia->ia_iosize = 0x10;
256 ia->ia_maddr = mono ? 0xb0000 : 0xb8000;
257 ia->ia_msize = 0x8000;
258 return (1);
259 }
260
261 void
pcdisplay_attach(parent,self,aux)262 pcdisplay_attach(parent, self, aux)
263 struct device *parent, *self;
264 void *aux;
265 {
266 struct isa_attach_args *ia = aux;
267 struct pcdisplay_softc *sc = (struct pcdisplay_softc *)self;
268 int console;
269 struct pcdisplay_config *dc;
270 struct wsemuldisplaydev_attach_args aa;
271
272 printf("\n");
273
274 console = pcdisplay_is_console(ia->ia_iot);
275
276 if (console) {
277 dc = &pcdisplay_console_dc;
278 sc->nscreens = 1;
279 pcdisplay_console_attached = 1;
280 } else {
281 dc = malloc(sizeof(struct pcdisplay_config),
282 M_DEVBUF, M_WAITOK);
283 if (ia->ia_iobase != 0x3b0 && ia->ia_maddr != 0xb0000 &&
284 pcdisplay_probe_col(ia->ia_iot, ia->ia_memt))
285 pcdisplay_init(dc, ia->ia_iot, ia->ia_memt, 0);
286 else if (ia->ia_iobase != 0x3d0 && ia->ia_maddr != 0xb8000 &&
287 pcdisplay_probe_mono(ia->ia_iot, ia->ia_memt))
288 pcdisplay_init(dc, ia->ia_iot, ia->ia_memt, 1);
289 else
290 panic("pcdisplay_attach: display disappeared");
291 }
292 sc->sc_dc = dc;
293
294 aa.console = console;
295 aa.scrdata = &pcdisplay_screenlist;
296 aa.accessops = &pcdisplay_accessops;
297 aa.accesscookie = sc;
298 aa.defaultscreens = 0;
299
300 config_found(self, &aa, wsemuldisplaydevprint);
301 }
302
303
304 int
pcdisplay_cnattach(iot,memt)305 pcdisplay_cnattach(iot, memt)
306 bus_space_tag_t iot, memt;
307 {
308 int mono;
309
310 if (pcdisplay_probe_col(iot, memt))
311 mono = 0;
312 else if (pcdisplay_probe_mono(iot, memt))
313 mono = 1;
314 else
315 return (ENXIO);
316
317 pcdisplay_init(&pcdisplay_console_dc, iot, memt, mono);
318
319 wsdisplay_cnattach(&pcdisplay_scr, &pcdisplay_console_dc,
320 pcdisplay_console_dc.pcs.vc_ccol,
321 pcdisplay_console_dc.pcs.vc_crow,
322 FG_LIGHTGREY | BG_BLACK);
323
324 pcdisplayconsole = 1;
325 return (0);
326 }
327
328 static int
pcdisplay_is_console(iot)329 pcdisplay_is_console(iot)
330 bus_space_tag_t iot;
331 {
332 if (pcdisplayconsole &&
333 !pcdisplay_console_attached &&
334 iot == pcdisplay_console_dc.dc_ph.ph_iot)
335 return (1);
336 return (0);
337 }
338
339 static int
pcdisplay_ioctl(v,cmd,data,flag,p)340 pcdisplay_ioctl(v, cmd, data, flag, p)
341 void *v;
342 u_long cmd;
343 caddr_t data;
344 int flag;
345 struct proc *p;
346 {
347 /*
348 * XXX "do something!"
349 */
350 return (-1);
351 }
352
353 static paddr_t
pcdisplay_mmap(v,offset,prot)354 pcdisplay_mmap(v, offset, prot)
355 void *v;
356 off_t offset;
357 int prot;
358 {
359 return (-1);
360 }
361
362 static int
pcdisplay_alloc_screen(v,type,cookiep,curxp,curyp,defattrp)363 pcdisplay_alloc_screen(v, type, cookiep, curxp, curyp, defattrp)
364 void *v;
365 const struct wsscreen_descr *type;
366 void **cookiep;
367 int *curxp, *curyp;
368 long *defattrp;
369 {
370 struct pcdisplay_softc *sc = v;
371
372 if (sc->nscreens > 0)
373 return (ENOMEM);
374
375 *cookiep = sc->sc_dc;
376 *curxp = 0;
377 *curyp = 0;
378 *defattrp = FG_LIGHTGREY | BG_BLACK;
379 sc->nscreens++;
380 return (0);
381 }
382
383 static void
pcdisplay_free_screen(v,cookie)384 pcdisplay_free_screen(v, cookie)
385 void *v;
386 void *cookie;
387 {
388 struct pcdisplay_softc *sc = v;
389
390 if (sc->sc_dc == &pcdisplay_console_dc)
391 panic("pcdisplay_free_screen: console");
392
393 sc->nscreens--;
394 }
395
396 static int
pcdisplay_show_screen(v,cookie,waitok,cb,cbarg)397 pcdisplay_show_screen(v, cookie, waitok, cb, cbarg)
398 void *v;
399 void *cookie;
400 int waitok;
401 void (*cb)(void *, int, int);
402 void *cbarg;
403 {
404 #ifdef DIAGNOSTIC
405 struct pcdisplay_softc *sc = v;
406
407 if (cookie != sc->sc_dc)
408 panic("pcdisplay_show_screen: bad screen");
409 #endif
410 return (0);
411 }
412
413 static int
pcdisplay_alloc_attr(id,fg,bg,flags,attrp)414 pcdisplay_alloc_attr(id, fg, bg, flags, attrp)
415 void *id;
416 int fg, bg;
417 int flags;
418 long *attrp;
419 {
420 if (flags & WSATTR_REVERSE)
421 *attrp = FG_BLACK | BG_LIGHTGREY;
422 else
423 *attrp = FG_LIGHTGREY | BG_BLACK;
424 return (0);
425 }
426
427 static void
pcdisplay_unpack_attr(id,attr,fg,bg,flags)428 pcdisplay_unpack_attr(id, attr, fg, bg, flags)
429 void *id;
430 long attr;
431 int *fg, *bg, *flags;
432 {
433 if (attr == (FG_BLACK | BG_LIGHTGREY)) {
434 *fg = WSCOL_BLACK;
435 *bg = WSCOL_WHITE;
436 if (flags != NULL)
437 *flags = WSATTR_REVERSE;
438 } else {
439 *fg = WSCOL_WHITE;
440 *bg = WSCOL_BLACK;
441 if (flags != NULL)
442 *flags = 0;
443 }
444 }
445
446 struct cfdriver pcdisplay_cd = {
447 NULL, "pcdisplay", DV_DULL
448 };
449