#include <sys/types.h>
#include <machine/biosvar.h>
#include <machine/pio.h>
#include <dev/isa/isareg.h>
#include <dev/ic/mc146818reg.h>
#include <dev/ic/comreg.h>
#include <dev/ic/ns16450reg.h>
#include <dev/cons.h>
#include <lib/libsa/stand.h>
#include "debug.h"
#include "biosdev.h"
#if 0
#define PRESENT_MASK (NVRAM_EQUIPMENT_KBD|NVRAM_EQUIPMENT_DISPLAY)
#else
#define PRESENT_MASK 0
#endif
void
pc_probe(struct consdev *cn)
{
cn->cn_pri = CN_MIDPRI;
cn->cn_dev = makedev(12, 0);
printf(" pc%d", minor(cn->cn_dev));
#if 0
outb(IO_RTC, NVRAM_EQUIPMENT);
if ((inb(IO_RTC+1) & PRESENT_MASK) == PRESENT_MASK) {
cn->cn_pri = CN_MIDPRI;
cn->cn_dev = makedev(12, 0);
printf(" pc%d", minor(cn->cn_dev));
}
#endif
}
void
pc_init(struct consdev *cn)
{
}
int
pc_getc(dev_t dev)
{
register int rv;
if (dev & 0x80) {
__asm volatile(DOINT(0x16) "; setnz %b0" : "=a" (rv) :
"0" (0x100) : "%ecx", "%edx", "cc" );
return (rv & 0xff);
}
do {
__asm volatile(DOINT(0x16) "; setnz %b0" : "=a" (rv) :
"0" (0x100) : "%ecx", "%edx", "cc" );
} while ((rv & 0xff) == 0);
__asm volatile(DOINT(0x16) : "=a" (rv) : "0" (0x000) :
"%ecx", "%edx", "cc" );
return (rv & 0xff);
}
int
pc_getshifts(dev_t dev)
{
register int rv;
__asm volatile(DOINT(0x16) : "=a" (rv) : "0" (0x200) :
"%ecx", "%edx", "cc" );
return (rv & 0xff);
}
void
pc_putc(dev_t dev, int c)
{
__asm volatile(DOINT(0x10) : : "a" (c | 0xe00), "b" (1) :
"%ecx", "%edx", "cc" );
}
const int comports[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
void
com_probe(struct consdev *cn)
{
register int i, n;
__asm volatile(DOINT(0x11) : "=a" (n) : : "%ecx", "%edx", "cc");
n >>= 9;
n &= 7;
for (i = 0; i < n; i++)
printf(" com%d", i);
cn->cn_pri = CN_LOWPRI;
cn->cn_dev = makedev(8, 0);
}
int com_speed = -1;
int com_addr = -1;
void
com_init(struct consdev *cn)
{
int port = (com_addr == -1) ? comports[minor(cn->cn_dev)] : com_addr;
time_t tt = getsecs() + 1;
u_long i = 1;
outb(port + com_ier, 0);
if (com_speed == -1)
comspeed(cn->cn_dev, 9600);
outb(port + com_mcr, MCR_DTR | MCR_RTS);
outb(port + com_fifo, FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST |
FIFO_TRIGGER_1);
(void) inb(port + com_iir);
while (!(i++ % 1000) && getsecs() < tt)
;
while (inb(port + com_lsr) & LSR_RXRDY)
(void)inb(port + com_data);
}
int
com_getc(dev_t dev)
{
int port = (com_addr == -1) ? comports[minor(dev & 0x7f)] : com_addr;
if (dev & 0x80)
return (inb(port + com_lsr) & LSR_RXRDY);
while ((inb(port + com_lsr) & LSR_RXRDY) == 0)
;
return (inb(port + com_data) & 0xff);
}
int
comspeed(dev_t dev, int sp)
{
int port = (com_addr == -1) ? comports[minor(dev)] : com_addr;
int i, newsp;
int err;
if (sp <= 0)
return com_speed;
if (115200 < sp || sp < 75)
return -1;
for (i = sp; i != 75 && i != 14400; i >>= 1)
if (i & 1)
return -1;
#define divrnd(n, q) (((n)*2/(q)+1)/2)
newsp = divrnd((COM_FREQ / 16), sp);
if (newsp <= 0)
return -1;
err = divrnd((COM_FREQ / 16) * 1000, sp * newsp) - 1000;
if (err < 0)
err = -err;
if (err > COM_TOLERANCE)
return -1;
#undef divrnd
if (com_speed != -1 && cn_tab && cn_tab->cn_dev == dev &&
com_speed != sp) {
printf("com%d: changing speed to %d baud in 5 seconds, "
"change your terminal to match!\n\a",
minor(dev), sp);
sleep(5);
}
outb(port + com_cfcr, LCR_DLAB);
outb(port + com_dlbl, newsp);
outb(port + com_dlbh, newsp>>8);
outb(port + com_cfcr, LCR_8BITS);
if (com_speed != -1)
printf("\ncom%d: %d baud\n", minor(dev), sp);
newsp = com_speed;
com_speed = sp;
return newsp;
}
void
com_putc(dev_t dev, int c)
{
int port = (com_addr == -1) ? comports[minor(dev)] : com_addr;
while ((inb(port + com_lsr) & LSR_TXRDY) == 0)
;
outb(port + com_data, c);
}