pcdisplay.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. /* $OpenBSD: pcdisplay.c,v 1.12 2013/10/20 20:07:29 miod Exp $ */
  2. /* $NetBSD: pcdisplay.c,v 1.9.4.1 2000/06/30 16:27:48 simonb Exp $ */
  3. /*
  4. * Copyright (c) 1998
  5. * Matthias Drochner. All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  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.
  15. *
  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.
  26. *
  27. */
  28. #include <sys/param.h>
  29. #include <sys/systm.h>
  30. #include <sys/kernel.h>
  31. #include <sys/device.h>
  32. #include <sys/malloc.h>
  33. #include <machine/bus.h>
  34. #include <dev/isa/isavar.h>
  35. #include <dev/isa/isareg.h>
  36. #include <dev/ic/mc6845reg.h>
  37. #include <dev/ic/pcdisplayvar.h>
  38. #include <dev/isa/pcdisplayvar.h>
  39. #include <dev/ic/pcdisplay.h>
  40. #include <dev/wscons/wsconsio.h>
  41. #include <dev/wscons/wsdisplayvar.h>
  42. struct pcdisplay_config {
  43. struct pcdisplayscreen pcs;
  44. struct pcdisplay_handle dc_ph;
  45. int mono;
  46. };
  47. struct pcdisplay_softc {
  48. struct device sc_dev;
  49. struct pcdisplay_config *sc_dc;
  50. int nscreens;
  51. };
  52. static int pcdisplayconsole, pcdisplay_console_attached;
  53. static struct pcdisplay_config pcdisplay_console_dc;
  54. int pcdisplay_match(struct device *, void *, void *);
  55. void pcdisplay_attach(struct device *, struct device *, void *);
  56. static int pcdisplay_is_console(bus_space_tag_t);
  57. static int pcdisplay_probe_col(bus_space_tag_t, bus_space_tag_t);
  58. static int pcdisplay_probe_mono(bus_space_tag_t, bus_space_tag_t);
  59. static void pcdisplay_init(struct pcdisplay_config *,
  60. bus_space_tag_t, bus_space_tag_t,
  61. int);
  62. static int pcdisplay_alloc_attr(void *, int, int, int, long *);
  63. static void pcdisplay_unpack_attr(void *, long, int *, int *, int *);
  64. struct cfattach pcdisplay_ca = {
  65. sizeof(struct pcdisplay_softc), pcdisplay_match, pcdisplay_attach,
  66. };
  67. const struct wsdisplay_emulops pcdisplay_emulops = {
  68. pcdisplay_cursor,
  69. pcdisplay_mapchar,
  70. pcdisplay_putchar,
  71. pcdisplay_copycols,
  72. pcdisplay_erasecols,
  73. pcdisplay_copyrows,
  74. pcdisplay_eraserows,
  75. pcdisplay_alloc_attr,
  76. pcdisplay_unpack_attr
  77. };
  78. const struct wsscreen_descr pcdisplay_scr = {
  79. "80x25", 80, 25,
  80. &pcdisplay_emulops,
  81. 0, 0, /* no font support */
  82. WSSCREEN_REVERSE /* that's minimal... */
  83. };
  84. const struct wsscreen_descr *_pcdisplay_scrlist[] = {
  85. &pcdisplay_scr,
  86. };
  87. const struct wsscreen_list pcdisplay_screenlist = {
  88. sizeof(_pcdisplay_scrlist) / sizeof(struct wsscreen_descr *),
  89. _pcdisplay_scrlist
  90. };
  91. static int pcdisplay_ioctl(void *, u_long, caddr_t, int, struct proc *);
  92. static paddr_t pcdisplay_mmap(void *, off_t, int);
  93. static int pcdisplay_alloc_screen(void *, const struct wsscreen_descr *,
  94. void **, int *, int *, long *);
  95. static void pcdisplay_free_screen(void *, void *);
  96. static int pcdisplay_show_screen(void *, void *, int,
  97. void (*) (void *, int, int), void *);
  98. const struct wsdisplay_accessops pcdisplay_accessops = {
  99. .ioctl = pcdisplay_ioctl,
  100. .mmap = pcdisplay_mmap,
  101. .alloc_screen = pcdisplay_alloc_screen,
  102. .free_screen = pcdisplay_free_screen,
  103. .show_screen = pcdisplay_show_screen
  104. };
  105. static int
  106. pcdisplay_probe_col(bus_space_tag_t iot, bus_space_tag_t memt)
  107. {
  108. bus_space_handle_t memh, ioh_6845;
  109. u_int16_t oldval, val;
  110. if (bus_space_map(memt, 0xb8000, 0x8000, 0, &memh))
  111. return (0);
  112. oldval = bus_space_read_2(memt, memh, 0);
  113. bus_space_write_2(memt, memh, 0, 0xa55a);
  114. val = bus_space_read_2(memt, memh, 0);
  115. bus_space_write_2(memt, memh, 0, oldval);
  116. bus_space_unmap(memt, memh, 0x8000);
  117. if (val != 0xa55a)
  118. return (0);
  119. if (bus_space_map(iot, 0x3d0, 0x10, 0, &ioh_6845))
  120. return (0);
  121. bus_space_unmap(iot, ioh_6845, 0x10);
  122. return (1);
  123. }
  124. static int
  125. pcdisplay_probe_mono(bus_space_tag_t iot, bus_space_tag_t memt)
  126. {
  127. bus_space_handle_t memh, ioh_6845;
  128. u_int16_t oldval, val;
  129. if (bus_space_map(memt, 0xb0000, 0x8000, 0, &memh))
  130. return (0);
  131. oldval = bus_space_read_2(memt, memh, 0);
  132. bus_space_write_2(memt, memh, 0, 0xa55a);
  133. val = bus_space_read_2(memt, memh, 0);
  134. bus_space_write_2(memt, memh, 0, oldval);
  135. bus_space_unmap(memt, memh, 0x8000);
  136. if (val != 0xa55a)
  137. return (0);
  138. if (bus_space_map(iot, 0x3b0, 0x10, 0, &ioh_6845))
  139. return (0);
  140. bus_space_unmap(iot, ioh_6845, 0x10);
  141. return (1);
  142. }
  143. static void
  144. pcdisplay_init(struct pcdisplay_config *dc, bus_space_tag_t iot,
  145. bus_space_tag_t memt, int mono)
  146. {
  147. struct pcdisplay_handle *ph = &dc->dc_ph;
  148. int cpos;
  149. ph->ph_iot = iot;
  150. ph->ph_memt = memt;
  151. dc->mono = mono;
  152. if (bus_space_map(memt, mono ? 0xb0000 : 0xb8000, 0x8000,
  153. 0, &ph->ph_memh))
  154. panic("pcdisplay_init: can't map mem space");
  155. if (bus_space_map(iot, mono ? 0x3b0 : 0x3d0, 0x10,
  156. 0, &ph->ph_ioh_6845))
  157. panic("pcdisplay_init: can't map i/o space");
  158. /*
  159. * initialize the only screen
  160. */
  161. dc->pcs.hdl = ph;
  162. dc->pcs.type = &pcdisplay_scr;
  163. dc->pcs.active = 1;
  164. dc->pcs.mem = NULL;
  165. cpos = pcdisplay_6845_read(ph, cursorh) << 8;
  166. cpos |= pcdisplay_6845_read(ph, cursorl);
  167. /* make sure we have a valid cursor position */
  168. if (cpos < 0 || cpos >= pcdisplay_scr.nrows * pcdisplay_scr.ncols)
  169. cpos = 0;
  170. dc->pcs.dispoffset = 0;
  171. dc->pcs.visibleoffset = 0;
  172. dc->pcs.vc_crow = cpos / pcdisplay_scr.ncols;
  173. dc->pcs.vc_ccol = cpos % pcdisplay_scr.ncols;
  174. pcdisplay_cursor_init(&dc->pcs, 1);
  175. }
  176. int
  177. pcdisplay_match(struct device *parent, void *match, void *aux)
  178. {
  179. struct isa_attach_args *ia = aux;
  180. int mono;
  181. /* If values are hardwired to something that they can't be, punt. */
  182. if ((ia->ia_iobase != IOBASEUNK &&
  183. ia->ia_iobase != 0x3d0 &&
  184. ia->ia_iobase != 0x3b0) ||
  185. /* ia->ia_iosize != 0 || XXX isa.c */
  186. (ia->ia_maddr != MADDRUNK &&
  187. ia->ia_maddr != 0xb8000 &&
  188. ia->ia_maddr != 0xb0000) ||
  189. (ia->ia_msize != 0 && ia->ia_msize != 0x8000) ||
  190. ia->ia_irq != IRQUNK || ia->ia_drq != DRQUNK)
  191. return (0);
  192. if (pcdisplay_is_console(ia->ia_iot))
  193. mono = pcdisplay_console_dc.mono;
  194. else if (ia->ia_iobase != 0x3b0 && ia->ia_maddr != 0xb0000 &&
  195. pcdisplay_probe_col(ia->ia_iot, ia->ia_memt))
  196. mono = 0;
  197. else if (ia->ia_iobase != 0x3d0 && ia->ia_maddr != 0xb8000 &&
  198. pcdisplay_probe_mono(ia->ia_iot, ia->ia_memt))
  199. mono = 1;
  200. else
  201. return (0);
  202. ia->ia_iobase = mono ? 0x3b0 : 0x3d0;
  203. ia->ia_iosize = 0x10;
  204. ia->ia_maddr = mono ? 0xb0000 : 0xb8000;
  205. ia->ia_msize = 0x8000;
  206. return (1);
  207. }
  208. void
  209. pcdisplay_attach(struct device *parent, struct device *self, void *aux)
  210. {
  211. struct isa_attach_args *ia = aux;
  212. struct pcdisplay_softc *sc = (struct pcdisplay_softc *)self;
  213. int console;
  214. struct pcdisplay_config *dc;
  215. struct wsemuldisplaydev_attach_args aa;
  216. printf("\n");
  217. console = pcdisplay_is_console(ia->ia_iot);
  218. if (console) {
  219. dc = &pcdisplay_console_dc;
  220. sc->nscreens = 1;
  221. pcdisplay_console_attached = 1;
  222. } else {
  223. dc = malloc(sizeof(struct pcdisplay_config),
  224. M_DEVBUF, M_WAITOK);
  225. if (ia->ia_iobase != 0x3b0 && ia->ia_maddr != 0xb0000 &&
  226. pcdisplay_probe_col(ia->ia_iot, ia->ia_memt))
  227. pcdisplay_init(dc, ia->ia_iot, ia->ia_memt, 0);
  228. else if (ia->ia_iobase != 0x3d0 && ia->ia_maddr != 0xb8000 &&
  229. pcdisplay_probe_mono(ia->ia_iot, ia->ia_memt))
  230. pcdisplay_init(dc, ia->ia_iot, ia->ia_memt, 1);
  231. else
  232. panic("pcdisplay_attach: display disappeared");
  233. }
  234. sc->sc_dc = dc;
  235. aa.console = console;
  236. aa.scrdata = &pcdisplay_screenlist;
  237. aa.accessops = &pcdisplay_accessops;
  238. aa.accesscookie = sc;
  239. aa.defaultscreens = 0;
  240. config_found(self, &aa, wsemuldisplaydevprint);
  241. }
  242. int
  243. pcdisplay_cnattach(bus_space_tag_t iot, bus_space_tag_t memt)
  244. {
  245. int mono;
  246. if (pcdisplay_probe_col(iot, memt))
  247. mono = 0;
  248. else if (pcdisplay_probe_mono(iot, memt))
  249. mono = 1;
  250. else
  251. return (ENXIO);
  252. pcdisplay_init(&pcdisplay_console_dc, iot, memt, mono);
  253. wsdisplay_cnattach(&pcdisplay_scr, &pcdisplay_console_dc,
  254. pcdisplay_console_dc.pcs.vc_ccol,
  255. pcdisplay_console_dc.pcs.vc_crow,
  256. FG_LIGHTGREY | BG_BLACK);
  257. pcdisplayconsole = 1;
  258. return (0);
  259. }
  260. static int
  261. pcdisplay_is_console(bus_space_tag_t iot)
  262. {
  263. if (pcdisplayconsole &&
  264. !pcdisplay_console_attached &&
  265. iot == pcdisplay_console_dc.dc_ph.ph_iot)
  266. return (1);
  267. return (0);
  268. }
  269. static int
  270. pcdisplay_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
  271. {
  272. /*
  273. * XXX "do something!"
  274. */
  275. return (-1);
  276. }
  277. static paddr_t
  278. pcdisplay_mmap(void *v, off_t offset, int prot)
  279. {
  280. return (-1);
  281. }
  282. static int
  283. pcdisplay_alloc_screen(void *v, const struct wsscreen_descr *type,
  284. void **cookiep, int *curxp, int *curyp, long *defattrp)
  285. {
  286. struct pcdisplay_softc *sc = v;
  287. if (sc->nscreens > 0)
  288. return (ENOMEM);
  289. *cookiep = sc->sc_dc;
  290. *curxp = 0;
  291. *curyp = 0;
  292. *defattrp = FG_LIGHTGREY | BG_BLACK;
  293. sc->nscreens++;
  294. return (0);
  295. }
  296. static void
  297. pcdisplay_free_screen(void *v, void *cookie)
  298. {
  299. struct pcdisplay_softc *sc = v;
  300. if (sc->sc_dc == &pcdisplay_console_dc)
  301. panic("pcdisplay_free_screen: console");
  302. sc->nscreens--;
  303. }
  304. static int
  305. pcdisplay_show_screen(void *v, void *cookie, int waitok,
  306. void (*cb)(void *, int, int), void *cbarg)
  307. {
  308. #ifdef DIAGNOSTIC
  309. struct pcdisplay_softc *sc = v;
  310. if (cookie != sc->sc_dc)
  311. panic("pcdisplay_show_screen: bad screen");
  312. #endif
  313. return (0);
  314. }
  315. static int
  316. pcdisplay_alloc_attr(void *id, int fg, int bg, int flags, long *attrp)
  317. {
  318. if (flags & WSATTR_REVERSE)
  319. *attrp = FG_BLACK | BG_LIGHTGREY;
  320. else
  321. *attrp = FG_LIGHTGREY | BG_BLACK;
  322. return (0);
  323. }
  324. static void
  325. pcdisplay_unpack_attr(void *id, long attr, int *fg, int *bg, int *ul)
  326. {
  327. if (attr == (FG_BLACK | BG_LIGHTGREY)) {
  328. *fg = WSCOL_BLACK;
  329. *bg = WSCOL_WHITE;
  330. } else {
  331. *fg = WSCOL_WHITE;
  332. *bg = WSCOL_BLACK;
  333. }
  334. if (ul != NULL)
  335. *ul = 0;
  336. }
  337. struct cfdriver pcdisplay_cd = {
  338. NULL, "pcdisplay", DV_DULL
  339. };