1 /* $NetBSD: pcdisplay.c,v 1.37 2009/05/12 08:44:19 cegger Exp $ */
5 * Matthias Drochner. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: pcdisplay.c,v 1.37 2009/05/12 08:44:19 cegger Exp $");
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/device.h>
36 #include <sys/malloc.h>
39 #include <dev/isa/isavar.h>
41 #include <dev/ic/mc6845reg.h>
42 #include <dev/ic/pcdisplayvar.h>
43 #include <dev/isa/pcdisplayvar.h>
45 #include <dev/ic/pcdisplay.h>
47 #include <dev/wscons/wsconsio.h>
48 #include <dev/wscons/wsdisplayvar.h>
52 #include <dev/isa/weaselreg.h>
53 #include <dev/isa/weaselvar.h>
56 struct pcdisplay_config
{
57 struct pcdisplayscreen pcs
;
58 struct pcdisplay_handle dc_ph
;
62 struct pcdisplay_softc
{
64 struct pcdisplay_config
*sc_dc
;
67 struct weasel_handle sc_weasel
;
71 static int pcdisplayconsole
, pcdisplay_console_attached
;
72 static struct pcdisplay_config pcdisplay_console_dc
;
74 int pcdisplay_match(device_t
, cfdata_t
, void *);
75 void pcdisplay_attach(device_t
, device_t
, void *);
77 static int pcdisplay_is_console(bus_space_tag_t
);
78 static int pcdisplay_probe_col(bus_space_tag_t
, bus_space_tag_t
);
79 static int pcdisplay_probe_mono(bus_space_tag_t
, bus_space_tag_t
);
80 static void pcdisplay_init(struct pcdisplay_config
*,
81 bus_space_tag_t
, bus_space_tag_t
,
83 static int pcdisplay_allocattr(void *, int, int, int, long *);
85 CFATTACH_DECL(pcdisplay
, sizeof(struct pcdisplay_softc
),
86 pcdisplay_match
, pcdisplay_attach
, NULL
, NULL
);
88 const struct wsdisplay_emulops pcdisplay_emulops
= {
97 NULL
, /* replaceattr */
100 const struct wsscreen_descr pcdisplay_scr
= {
103 0, 0, /* no font support */
104 WSSCREEN_REVERSE
, /* that's minimal... */
105 NULL
, /* modecookie */
108 const struct wsscreen_descr
*_pcdisplay_scrlist
[] = {
112 const struct wsscreen_list pcdisplay_screenlist
= {
113 sizeof(_pcdisplay_scrlist
) / sizeof(struct wsscreen_descr
*),
117 static int pcdisplay_ioctl(void *, void *, u_long
, void *, int, struct lwp
*);
118 static paddr_t
pcdisplay_mmap(void *, void *, off_t
, int);
119 static int pcdisplay_alloc_screen(void *, const struct wsscreen_descr
*,
120 void **, int *, int *, long *);
121 static void pcdisplay_free_screen(void *, void *);
122 static int pcdisplay_show_screen(void *, void *, int,
123 void (*) (void *, int, int), void *);
125 const struct wsdisplay_accessops pcdisplay_accessops
= {
128 pcdisplay_alloc_screen
,
129 pcdisplay_free_screen
,
130 pcdisplay_show_screen
,
131 NULL
, /* load_font */
137 pcdisplay_probe_col(bus_space_tag_t iot
, bus_space_tag_t memt
)
139 bus_space_handle_t memh
, ioh_6845
;
140 u_int16_t oldval
, val
;
142 if (bus_space_map(memt
, 0xb8000, 0x8000, 0, &memh
))
144 oldval
= bus_space_read_2(memt
, memh
, 0);
145 bus_space_write_2(memt
, memh
, 0, 0xa55a);
146 val
= bus_space_read_2(memt
, memh
, 0);
147 bus_space_write_2(memt
, memh
, 0, oldval
);
148 bus_space_unmap(memt
, memh
, 0x8000);
152 if (bus_space_map(iot
, 0x3d0, 0x10, 0, &ioh_6845
))
154 bus_space_unmap(iot
, ioh_6845
, 0x10);
160 pcdisplay_probe_mono(bus_space_tag_t iot
, bus_space_tag_t memt
)
162 bus_space_handle_t memh
, ioh_6845
;
163 u_int16_t oldval
, val
;
165 if (bus_space_map(memt
, 0xb0000, 0x8000, 0, &memh
))
167 oldval
= bus_space_read_2(memt
, memh
, 0);
168 bus_space_write_2(memt
, memh
, 0, 0xa55a);
169 val
= bus_space_read_2(memt
, memh
, 0);
170 bus_space_write_2(memt
, memh
, 0, oldval
);
171 bus_space_unmap(memt
, memh
, 0x8000);
175 if (bus_space_map(iot
, 0x3b0, 0x10, 0, &ioh_6845
))
177 bus_space_unmap(iot
, ioh_6845
, 0x10);
183 pcdisplay_init(struct pcdisplay_config
*dc
, bus_space_tag_t iot
, bus_space_tag_t memt
, int mono
)
185 struct pcdisplay_handle
*ph
= &dc
->dc_ph
;
192 if (bus_space_map(memt
, mono
? 0xb0000 : 0xb8000, 0x8000,
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");
200 * initialize the only screen
203 dc
->pcs
.type
= &pcdisplay_scr
;
207 cpos
= pcdisplay_6845_read(ph
, cursorh
) << 8;
208 cpos
|= pcdisplay_6845_read(ph
, cursorl
);
210 /* make sure we have a valid cursor position */
211 if (cpos
< 0 || cpos
>= pcdisplay_scr
.nrows
* pcdisplay_scr
.ncols
)
214 dc
->pcs
.dispoffset
= 0;
216 dc
->pcs
.cursorrow
= cpos
/ pcdisplay_scr
.ncols
;
217 dc
->pcs
.cursorcol
= cpos
% pcdisplay_scr
.ncols
;
218 pcdisplay_cursor_init(&dc
->pcs
, 1);
222 pcdisplay_match(device_t parent
, cfdata_t match
, void *aux
)
224 struct isa_attach_args
*ia
= aux
;
227 if (ISA_DIRECT_CONFIG(ia
))
230 /* If values are hardwired to something that they can't be, punt. */
231 if (ia
->ia_nio
< 1 ||
232 (ia
->ia_io
[0].ir_addr
!= ISA_UNKNOWN_PORT
&&
233 ia
->ia_io
[0].ir_addr
!= 0x3d0 &&
234 ia
->ia_io
[0].ir_addr
!= 0x3b0))
237 if (ia
->ia_niomem
< 1 ||
238 (ia
->ia_iomem
[0].ir_addr
!= ISA_UNKNOWN_IOMEM
&&
239 ia
->ia_iomem
[0].ir_addr
!= 0xb8000 &&
240 ia
->ia_iomem
[0].ir_addr
!= 0xb0000))
242 if (ia
->ia_iomem
[0].ir_size
!= 0 &&
243 ia
->ia_iomem
[0].ir_size
!= 0x8000)
246 if (ia
->ia_nirq
> 0 &&
247 ia
->ia_irq
[0].ir_irq
!= ISA_UNKNOWN_IRQ
)
250 if (ia
->ia_ndrq
> 0 &&
251 ia
->ia_drq
[0].ir_drq
!= ISA_UNKNOWN_DRQ
)
254 if (pcdisplay_is_console(ia
->ia_iot
))
255 mono
= pcdisplay_console_dc
.mono
;
256 else if (ia
->ia_io
[0].ir_addr
!= 0x3b0 &&
257 ia
->ia_iomem
[0].ir_addr
!= 0xb0000 &&
258 pcdisplay_probe_col(ia
->ia_iot
, ia
->ia_memt
))
260 else if (ia
->ia_io
[0].ir_addr
!= 0x3d0 &&
261 ia
->ia_iomem
[0].ir_addr
!= 0xb8000 &&
262 pcdisplay_probe_mono(ia
->ia_iot
, ia
->ia_memt
))
268 ia
->ia_io
[0].ir_addr
= mono
? 0x3b0 : 0x3d0;
269 ia
->ia_io
[0].ir_size
= 0x10;
272 ia
->ia_iomem
[0].ir_size
= mono
? 0xb0000 : 0xb8000;
273 ia
->ia_iomem
[0].ir_size
= 0x8000;
282 pcdisplay_attach(device_t parent
, device_t self
, void *aux
)
284 struct isa_attach_args
*ia
= aux
;
285 struct pcdisplay_softc
*sc
= (struct pcdisplay_softc
*)self
;
287 struct pcdisplay_config
*dc
;
288 struct wsemuldisplaydev_attach_args aa
;
292 console
= pcdisplay_is_console(ia
->ia_iot
);
295 dc
= &pcdisplay_console_dc
;
297 pcdisplay_console_attached
= 1;
299 dc
= malloc(sizeof(struct pcdisplay_config
),
301 if (ia
->ia_io
[0].ir_addr
!= 0x3b0 &&
302 ia
->ia_iomem
[0].ir_addr
!= 0xb0000 &&
303 pcdisplay_probe_col(ia
->ia_iot
, ia
->ia_memt
))
304 pcdisplay_init(dc
, ia
->ia_iot
, ia
->ia_memt
, 0);
305 else if (ia
->ia_io
[0].ir_addr
!= 0x3d0 &&
306 ia
->ia_iomem
[0].ir_addr
!= 0xb8000 &&
307 pcdisplay_probe_mono(ia
->ia_iot
, ia
->ia_memt
))
308 pcdisplay_init(dc
, ia
->ia_iot
, ia
->ia_memt
, 1);
310 panic("pcdisplay_attach: display disappeared");
316 * If the display is monochrome, check to see if we have
317 * a PC-Weasel, and initialize its special features.
320 sc
->sc_weasel
.wh_st
= dc
->dc_ph
.ph_memt
;
321 sc
->sc_weasel
.wh_sh
= dc
->dc_ph
.ph_memh
;
322 sc
->sc_weasel
.wh_parent
= &sc
->sc_dev
;
323 weasel_isa_init(&sc
->sc_weasel
);
325 #endif /* NPCWEASEL > 0 */
327 aa
.console
= console
;
328 aa
.scrdata
= &pcdisplay_screenlist
;
329 aa
.accessops
= &pcdisplay_accessops
;
330 aa
.accesscookie
= sc
;
332 config_found(self
, &aa
, wsemuldisplaydevprint
);
337 pcdisplay_cnattach(bus_space_tag_t iot
, bus_space_tag_t memt
)
341 if (pcdisplay_probe_col(iot
, memt
))
343 else if (pcdisplay_probe_mono(iot
, memt
))
348 pcdisplay_init(&pcdisplay_console_dc
, iot
, memt
, mono
);
350 wsdisplay_cnattach(&pcdisplay_scr
, &pcdisplay_console_dc
,
351 pcdisplay_console_dc
.pcs
.cursorcol
,
352 pcdisplay_console_dc
.pcs
.cursorrow
,
353 FG_LIGHTGREY
| BG_BLACK
);
355 pcdisplayconsole
= 1;
360 pcdisplay_is_console(bus_space_tag_t iot
)
362 if (pcdisplayconsole
&&
363 !pcdisplay_console_attached
&&
364 iot
== pcdisplay_console_dc
.dc_ph
.ph_iot
)
370 pcdisplay_ioctl(void *v
, void *vs
, u_long cmd
,
371 void *data
, int flag
, struct lwp
*l
)
374 * XXX "do something!"
376 return (EPASSTHROUGH
);
380 pcdisplay_mmap(void *v
, void *vs
, off_t offset
,
387 pcdisplay_alloc_screen(void *v
, const struct wsscreen_descr
*type
,
388 void **cookiep
, int *curxp
, int *curyp
, long *defattrp
)
390 struct pcdisplay_softc
*sc
= v
;
392 if (sc
->nscreens
> 0)
395 *cookiep
= sc
->sc_dc
;
398 *defattrp
= FG_LIGHTGREY
| BG_BLACK
;
404 pcdisplay_free_screen(void *v
, void *cookie
)
406 struct pcdisplay_softc
*sc
= v
;
408 if (sc
->sc_dc
== &pcdisplay_console_dc
)
409 panic("pcdisplay_free_screen: console");
415 pcdisplay_show_screen(void *v
, void *cookie
,
416 int waitok
, void (*cb
)(void *, int, int),
420 struct pcdisplay_softc
*sc
= v
;
422 if (cookie
!= sc
->sc_dc
)
423 panic("pcdisplay_show_screen: bad screen");
429 pcdisplay_allocattr(void *id
, int fg
, int bg
,
430 int flags
, long *attrp
)
432 if (flags
& WSATTR_REVERSE
)
433 *attrp
= FG_BLACK
| BG_LIGHTGREY
;
435 *attrp
= FG_LIGHTGREY
| BG_BLACK
;