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