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