typedef  unsigned char        u8_t;
typedef  unsigned short int   u16_t;
typedef  unsigned int         u32_t;
typedef  unsigned long long   u64_t;

static inline u8_t inb(u16_t port)
{
  u8_t val;
  if(port < 0x100)
    asm volatile ("in %b0, %w1 \n" : "=a" (val) : "dN" (port) );
  else
    asm volatile ("in %b0, %w1 \n" : "=a" (val) : "d" (port) );
	return val;
}

static inline outb(u16_t port, u8_t val)
{
  if (port < 0x100) /* GCC can optimize this if constant */
    asm volatile ("out %w0, %b1" : :"dN"(port), "a"(val));
  else
    asm volatile ("out %w0, %b1" : :"d"(port), "a"(val));
}


/* Convert the integer D to a string and save the string in BUF. If
   BASE is equal to 'd', interpret that D is decimal, and if BASE is
   equal to 'x', interpret that D is hexadecimal.  */
static void itoa (char *buf, int base, int d)
{
  char *p = buf;
  char *p1, *p2;
  unsigned long ud = d;
  int divisor = 10;

  /* If %d is specified and D is minus, put `-' in the head.  */
  if (base == 'd' && d < 0)
    {
      *p++ = '-';
      buf++;
      ud = -d;
    }
  else if (base == 'x')
    divisor = 16;

  /* Divide UD by DIVISOR until UD == 0.  */
  do
    {
      int remainder = ud % divisor;

      *p++ = (remainder < 10) ? remainder + '0' : remainder + 'a' - 10;
    }
  while (ud /= divisor);

  /* Terminate BUF.  */
  *p = 0;

  /* Reverse BUF.  */
  p1 = buf;
  p2 = p - 1;
  while (p1 < p2)
    {
      char tmp = *p1;
      *p1 = *p2;
      *p2 = tmp;
      p1++;
      p2--;
    }
}

void putc(int c)
{
    while (!(inb(0x3f8+5) & 0x60));
    outb(0x3f8,c);
    if (c == '\n')
      putc('\r');
}

void _printf (const char *format, ...)
{
  char **arg = (char **) &format;
  int c;
  char buf[20];

  arg++;

  while ((c = *format++) != 0)
  {
    if (c != '%')
      putc(c);
    else
    {
      char *p;

      c = *format++;
      switch (c)
      {
        case 'd':
        case 'u':
        case 'x':
          itoa (buf, c, *((int *) arg++));
          p = buf;
          goto string;
          break;

        case 's':
          p = *arg++;
          if (! p)
            p = "(null)";

  string:
          while (*p)
          putc(*p++);
          break;

        default:
          putc(*((int *) arg++));
          break;
	    }
    }
  }
}