18a997770SDoug Rabson /*- 28a997770SDoug Rabson * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp> 38a997770SDoug Rabson * All rights reserved. 48a997770SDoug Rabson * 58a997770SDoug Rabson * Redistribution and use in source and binary forms, with or without 68a997770SDoug Rabson * modification, are permitted provided that the following conditions 78a997770SDoug Rabson * are met: 88a997770SDoug Rabson * 1. Redistributions of source code must retain the above copyright 98a997770SDoug Rabson * notice, this list of conditions and the following disclaimer as 108a997770SDoug Rabson * the first lines of this file unmodified. 118a997770SDoug Rabson * 2. Redistributions in binary form must reproduce the above copyright 128a997770SDoug Rabson * notice, this list of conditions and the following disclaimer in the 138a997770SDoug Rabson * documentation and/or other materials provided with the distribution. 148a997770SDoug Rabson * 158a997770SDoug Rabson * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 168a997770SDoug Rabson * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 178a997770SDoug Rabson * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 188a997770SDoug Rabson * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 198a997770SDoug Rabson * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 208a997770SDoug Rabson * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 218a997770SDoug Rabson * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 228a997770SDoug Rabson * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 238a997770SDoug Rabson * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 248a997770SDoug Rabson * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 258a997770SDoug Rabson * 26c3aac50fSPeter Wemm * $FreeBSD$ 278a997770SDoug Rabson */ 288a997770SDoug Rabson 298a997770SDoug Rabson #include "opt_syscons.h" 308a997770SDoug Rabson 318a997770SDoug Rabson #include <sys/param.h> 328a997770SDoug Rabson #include <sys/systm.h> 338a997770SDoug Rabson #include <sys/kernel.h> 348a997770SDoug Rabson #include <sys/module.h> 358a997770SDoug Rabson #include <sys/bus.h> 36ce9edcf5SPoul-Henning Kamp #include <sys/cons.h> 3700d25f51SPoul-Henning Kamp #include <sys/kbio.h> 3800d25f51SPoul-Henning Kamp #include <sys/consio.h> 398a997770SDoug Rabson 406e8394b8SKazutaka YOKOTA 416182fdbdSPeter Wemm #ifdef __i386__ 426e8394b8SKazutaka YOKOTA 436e8394b8SKazutaka YOKOTA #include <machine/clock.h> 446e8394b8SKazutaka YOKOTA #include <machine/md_var.h> 456e8394b8SKazutaka YOKOTA #include <machine/pc/bios.h> 466e8394b8SKazutaka YOKOTA 476e8394b8SKazutaka YOKOTA #include <vm/vm.h> 486e8394b8SKazutaka YOKOTA #include <vm/pmap.h> 496e8394b8SKazutaka YOKOTA 506e8394b8SKazutaka YOKOTA #include <i386/isa/timerreg.h> 516e8394b8SKazutaka YOKOTA 526e8394b8SKazutaka YOKOTA #define BIOS_CLKED (1 << 6) 536e8394b8SKazutaka YOKOTA #define BIOS_NLKED (1 << 5) 546e8394b8SKazutaka YOKOTA #define BIOS_SLKED (1 << 4) 556e8394b8SKazutaka YOKOTA #define BIOS_ALKED 0 566e8394b8SKazutaka YOKOTA 576e8394b8SKazutaka YOKOTA #endif /* __i386__ */ 588a997770SDoug Rabson 598a997770SDoug Rabson #include <dev/syscons/syscons.h> 608a997770SDoug Rabson 618a997770SDoug Rabson #include <isa/isareg.h> 628a997770SDoug Rabson #include <isa/isavar.h> 638a997770SDoug Rabson 646e8394b8SKazutaka YOKOTA static devclass_t sc_devclass; 658a997770SDoug Rabson 66e2f29c6eSKazutaka YOKOTA static sc_softc_t main_softc; 676e8394b8SKazutaka YOKOTA 68c20ac811SPeter Wemm static void 69c20ac811SPeter Wemm scidentify (driver_t *driver, device_t parent) 70c20ac811SPeter Wemm { 71c20ac811SPeter Wemm BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "sc", 0); 72c20ac811SPeter Wemm } 73c20ac811SPeter Wemm 748a997770SDoug Rabson static int 758a997770SDoug Rabson scprobe(device_t dev) 768a997770SDoug Rabson { 77f7f2df54SDoug Rabson /* No pnp support */ 78f7f2df54SDoug Rabson if (isa_get_vendorid(dev)) 79f7f2df54SDoug Rabson return (ENXIO); 80f7f2df54SDoug Rabson 818a997770SDoug Rabson device_set_desc(dev, "System console"); 82062acdb7SDoug Rabson return sc_probe_unit(device_get_unit(dev), device_get_flags(dev)); 838a997770SDoug Rabson } 848a997770SDoug Rabson 858a997770SDoug Rabson static int 868a997770SDoug Rabson scattach(device_t dev) 878a997770SDoug Rabson { 88062acdb7SDoug Rabson return sc_attach_unit(device_get_unit(dev), device_get_flags(dev)); 898a997770SDoug Rabson } 908a997770SDoug Rabson 916e8394b8SKazutaka YOKOTA static int 926e8394b8SKazutaka YOKOTA scresume(device_t dev) 936e8394b8SKazutaka YOKOTA { 946e8394b8SKazutaka YOKOTA return sc_resume_unit(device_get_unit(dev)); 956e8394b8SKazutaka YOKOTA } 966e8394b8SKazutaka YOKOTA 976e8394b8SKazutaka YOKOTA int 986e8394b8SKazutaka YOKOTA sc_max_unit(void) 996e8394b8SKazutaka YOKOTA { 1006e8394b8SKazutaka YOKOTA return devclass_get_maxunit(sc_devclass); 1016e8394b8SKazutaka YOKOTA } 1026e8394b8SKazutaka YOKOTA 1036e8394b8SKazutaka YOKOTA sc_softc_t 1046e8394b8SKazutaka YOKOTA *sc_get_softc(int unit, int flags) 1056e8394b8SKazutaka YOKOTA { 1066e8394b8SKazutaka YOKOTA sc_softc_t *sc; 1076e8394b8SKazutaka YOKOTA 1088f8e5879SPeter Wemm if (unit < 0) 1096e8394b8SKazutaka YOKOTA return NULL; 1106e8394b8SKazutaka YOKOTA if (flags & SC_KERNEL_CONSOLE) { 1116e8394b8SKazutaka YOKOTA /* FIXME: clear if it is wired to another unit! */ 112e2f29c6eSKazutaka YOKOTA sc = &main_softc; 1136e8394b8SKazutaka YOKOTA } else { 114ffc1d9bdSKazutaka YOKOTA sc = (sc_softc_t *)device_get_softc(devclass_get_device(sc_devclass, unit)); 1158f8e5879SPeter Wemm if (sc == NULL) 1168f8e5879SPeter Wemm return NULL; 117e2f29c6eSKazutaka YOKOTA } 1186e8394b8SKazutaka YOKOTA sc->unit = unit; 119e2f29c6eSKazutaka YOKOTA if (!(sc->flags & SC_INIT_DONE)) { 1206e8394b8SKazutaka YOKOTA sc->keyboard = -1; 1216e8394b8SKazutaka YOKOTA sc->adapter = -1; 12209132359SKazutaka YOKOTA sc->cursor_char = SC_CURSOR_CHAR; 123e2f29c6eSKazutaka YOKOTA sc->mouse_char = SC_MOUSE_CHAR; 1246e8394b8SKazutaka YOKOTA } 1256e8394b8SKazutaka YOKOTA return sc; 1266e8394b8SKazutaka YOKOTA } 1276e8394b8SKazutaka YOKOTA 1286e8394b8SKazutaka YOKOTA sc_softc_t 1296e8394b8SKazutaka YOKOTA *sc_find_softc(struct video_adapter *adp, struct keyboard *kbd) 1306e8394b8SKazutaka YOKOTA { 1316e8394b8SKazutaka YOKOTA sc_softc_t *sc; 1326e8394b8SKazutaka YOKOTA int units; 1336e8394b8SKazutaka YOKOTA int i; 1346e8394b8SKazutaka YOKOTA 1356e8394b8SKazutaka YOKOTA sc = &main_softc; 1366e8394b8SKazutaka YOKOTA if (((adp == NULL) || (adp == sc->adp)) 1376e8394b8SKazutaka YOKOTA && ((kbd == NULL) || (kbd == sc->kbd))) 1386e8394b8SKazutaka YOKOTA return sc; 1396e8394b8SKazutaka YOKOTA units = devclass_get_maxunit(sc_devclass); 1406e8394b8SKazutaka YOKOTA for (i = 0; i < units; ++i) { 141ffc1d9bdSKazutaka YOKOTA sc = (sc_softc_t *)device_get_softc(devclass_get_device(sc_devclass, i)); 1426e8394b8SKazutaka YOKOTA if (sc == NULL) 1436e8394b8SKazutaka YOKOTA continue; 1446e8394b8SKazutaka YOKOTA if (((adp == NULL) || (adp == sc->adp)) 1456e8394b8SKazutaka YOKOTA && ((kbd == NULL) || (kbd == sc->kbd))) 1466e8394b8SKazutaka YOKOTA return sc; 1476e8394b8SKazutaka YOKOTA } 1486e8394b8SKazutaka YOKOTA return NULL; 1496e8394b8SKazutaka YOKOTA } 1506e8394b8SKazutaka YOKOTA 1516e8394b8SKazutaka YOKOTA int 1526e8394b8SKazutaka YOKOTA sc_get_cons_priority(int *unit, int *flags) 1536e8394b8SKazutaka YOKOTA { 1546e8394b8SKazutaka YOKOTA int disabled; 155c864c67bSPeter Wemm const char *at; 1566e8394b8SKazutaka YOKOTA int u, f; 1576e8394b8SKazutaka YOKOTA 1586e8394b8SKazutaka YOKOTA *unit = -1; 15981e3fd99SPeter Wemm for (u = 0; u < 16; u++) { 1606e8394b8SKazutaka YOKOTA if ((resource_int_value(SC_DRIVER_NAME, u, "disabled", 1616e8394b8SKazutaka YOKOTA &disabled) == 0) && disabled) 1626e8394b8SKazutaka YOKOTA continue; 16381e3fd99SPeter Wemm if (resource_string_value(SC_DRIVER_NAME, u, "at", &at) != 0) 16481e3fd99SPeter Wemm continue; 1656e8394b8SKazutaka YOKOTA if (resource_int_value(SC_DRIVER_NAME, u, "flags", &f) != 0) 1666e8394b8SKazutaka YOKOTA f = 0; 1676e8394b8SKazutaka YOKOTA if (f & SC_KERNEL_CONSOLE) { 1686e8394b8SKazutaka YOKOTA /* the user designates this unit to be the console */ 1696e8394b8SKazutaka YOKOTA *unit = u; 1706e8394b8SKazutaka YOKOTA *flags = f; 1716e8394b8SKazutaka YOKOTA break; 1726e8394b8SKazutaka YOKOTA } 1736e8394b8SKazutaka YOKOTA if (*unit < 0) { 1746e8394b8SKazutaka YOKOTA /* ...otherwise remember the first found unit */ 1756e8394b8SKazutaka YOKOTA *unit = u; 1766e8394b8SKazutaka YOKOTA *flags = f; 1776e8394b8SKazutaka YOKOTA } 1786e8394b8SKazutaka YOKOTA } 17981e3fd99SPeter Wemm if (*unit < 0) 1806e8394b8SKazutaka YOKOTA return CN_DEAD; 1816e8394b8SKazutaka YOKOTA #if 0 1826e8394b8SKazutaka YOKOTA return ((*flags & SC_KERNEL_CONSOLE) ? CN_INTERNAL : CN_NORMAL); 1836e8394b8SKazutaka YOKOTA #endif 1846e8394b8SKazutaka YOKOTA return CN_INTERNAL; 1856e8394b8SKazutaka YOKOTA } 1866e8394b8SKazutaka YOKOTA 1876e8394b8SKazutaka YOKOTA void 1886e8394b8SKazutaka YOKOTA sc_get_bios_values(bios_values_t *values) 1896e8394b8SKazutaka YOKOTA { 1906e8394b8SKazutaka YOKOTA #ifdef __i386__ 1916e8394b8SKazutaka YOKOTA u_int8_t shift; 1926e8394b8SKazutaka YOKOTA 1936e8394b8SKazutaka YOKOTA values->cursor_start = *(u_int8_t *)BIOS_PADDRTOVADDR(0x461); 1946e8394b8SKazutaka YOKOTA values->cursor_end = *(u_int8_t *)BIOS_PADDRTOVADDR(0x460); 1956e8394b8SKazutaka YOKOTA shift = *(u_int8_t *)BIOS_PADDRTOVADDR(0x417); 1966e8394b8SKazutaka YOKOTA values->shift_state = ((shift & BIOS_CLKED) ? CLKED : 0) 1976e8394b8SKazutaka YOKOTA | ((shift & BIOS_NLKED) ? NLKED : 0) 1986e8394b8SKazutaka YOKOTA | ((shift & BIOS_SLKED) ? SLKED : 0) 1996e8394b8SKazutaka YOKOTA | ((shift & BIOS_ALKED) ? ALKED : 0); 2006e8394b8SKazutaka YOKOTA values->bell_pitch = BELL_PITCH; 2016e8394b8SKazutaka YOKOTA #else /* !__i386__ */ 2026e8394b8SKazutaka YOKOTA values->cursor_start = 0; 2036e8394b8SKazutaka YOKOTA values->cursor_end = 32; 2046e8394b8SKazutaka YOKOTA values->shift_state = 0; 2056e8394b8SKazutaka YOKOTA values->bell_pitch = BELL_PITCH; 2066e8394b8SKazutaka YOKOTA #endif /* __i386__ */ 2076e8394b8SKazutaka YOKOTA } 2086e8394b8SKazutaka YOKOTA 2096e8394b8SKazutaka YOKOTA int 2106e8394b8SKazutaka YOKOTA sc_tone(int herz) 2116e8394b8SKazutaka YOKOTA { 2126e8394b8SKazutaka YOKOTA #ifdef __i386__ 2136e8394b8SKazutaka YOKOTA int pitch; 2146e8394b8SKazutaka YOKOTA 2156e8394b8SKazutaka YOKOTA if (herz) { 2166e8394b8SKazutaka YOKOTA /* set command for counter 2, 2 byte write */ 2176e8394b8SKazutaka YOKOTA if (acquire_timer2(TIMER_16BIT | TIMER_SQWAVE)) 2186e8394b8SKazutaka YOKOTA return EBUSY; 2196e8394b8SKazutaka YOKOTA /* set pitch */ 2206e8394b8SKazutaka YOKOTA pitch = timer_freq/herz; 2216e8394b8SKazutaka YOKOTA outb(TIMER_CNTR2, pitch); 2226e8394b8SKazutaka YOKOTA outb(TIMER_CNTR2, pitch >> 8); 2236e8394b8SKazutaka YOKOTA /* enable counter 2 output to speaker */ 2246e8394b8SKazutaka YOKOTA outb(IO_PPI, inb(IO_PPI) | 3); 2256e8394b8SKazutaka YOKOTA } else { 2266e8394b8SKazutaka YOKOTA /* disable counter 2 output to speaker */ 2276e8394b8SKazutaka YOKOTA outb(IO_PPI, inb(IO_PPI) & 0xFC); 2286e8394b8SKazutaka YOKOTA release_timer2(); 2296e8394b8SKazutaka YOKOTA } 2306e8394b8SKazutaka YOKOTA #endif /* __i386__ */ 2316e8394b8SKazutaka YOKOTA 2326e8394b8SKazutaka YOKOTA return 0; 2336e8394b8SKazutaka YOKOTA } 2346e8394b8SKazutaka YOKOTA 235c20ac811SPeter Wemm static device_method_t sc_methods[] = { 236c20ac811SPeter Wemm DEVMETHOD(device_identify, scidentify), 237c20ac811SPeter Wemm DEVMETHOD(device_probe, scprobe), 238c20ac811SPeter Wemm DEVMETHOD(device_attach, scattach), 239c20ac811SPeter Wemm DEVMETHOD(device_resume, scresume), 240c20ac811SPeter Wemm { 0, 0 } 241c20ac811SPeter Wemm }; 242c20ac811SPeter Wemm 243c20ac811SPeter Wemm static driver_t sc_driver = { 244c20ac811SPeter Wemm SC_DRIVER_NAME, 245c20ac811SPeter Wemm sc_methods, 246c20ac811SPeter Wemm sizeof(sc_softc_t), 247c20ac811SPeter Wemm }; 248c20ac811SPeter Wemm 2498a997770SDoug Rabson DRIVER_MODULE(sc, isa, sc_driver, sc_devclass, 0, 0); 250