#include "mystuff.h"
#include "ymsend.h"
#include "io.h"

enum {
  THR = 0,
  RBR = 0,
  DLL = 0,
  DLM = 1,
  IER = 1,
  IIR = 2,
  FCR = 2,
  LCR = 3,
  MCR = 4,
  LSR = 5,
  MSR = 6,
  SCR = 7,
};

int serial_init(struct serial_if *sif)
{
  uint16_t port = sif->port;
  uint8_t dll, dlm, lcr;

  /* Set 115200n81 */
  outb(0x83, port+LCR);
  outb(0x01, port+DLL);
  outb(0x00, port+DLM);
  (void)inb(port+IER);		/* Synchronize */
  dll = inb(port+DLL);
  dlm = inb(port+DLM);
  lcr = inb(port+LCR);
  outb(0x03, port+LCR);
  (void)inb(port+IER);		/* Synchronize */

  if (dll != 0x01 || dlm != 0x00 || lcr != 0x83)
    return -1;			/* This doesn't look like a serial port */

  /* Disable interrupts */
  outb(port+IER, 0);

  /* Enable 16550A FIFOs if available */
  outb(port+FCR, 0x01);		/* Enable FIFO */
  (void)inb(port+IER);		/* Synchronize */
  if (inb(port+IIR) < 0xc0)
    outb(port+FCR, 0x00);	/* Disable FIFOs if non-functional */
  (void)inb(port+IER);		/* Synchronize */

  return 0;
}

void serial_write(struct serial_if *sif, const void *data, size_t n)
{
  uint16_t port = sif->port;
  const char *p = data;
  uint8_t lsr;

  while (n--) {
    do {
      lsr = inb(port+LSR);
    } while (!(lsr & 0x20));

    outb(*p++, port+THR);
  }
}

void serial_read(struct serial_if *sif, void *data, size_t n)
{
  uint16_t port = sif->port;
  char *p = data;
  uint8_t lsr;

  while (n--) {
    do {
      lsr = inb(port+LSR);
    } while (!(lsr & 0x01));

    *p++ = inb(port+RBR);
  }
}
