0,0 → 1,127 |
#include <unistd.h> |
#include <ddi.h> |
#include <libarch/ddi.h> |
#include <stdio.h> |
|
#include "isa.h" |
#include "serial.h" |
|
#define NAME "serial" |
|
#define REG_COUNT 7 |
#define COM1 0x3F8 |
#define COM2 0x2F8 |
|
static ioport8_t *com1 = 0, *com2 = 0; |
|
static void serial_init_port(ioport8_t *port); |
static void serial_write_8(ioport8_t *port, uint8_t c); |
static bool is_transmit_empty(ioport8_t *port); |
static uint8_t serial_read_8(ioport8_t *port); |
static bool serial_received(ioport8_t *port); |
static void serial_probe(bridge_to_isa_t *parent); |
static void * serial_probe_port(void *phys_addr); |
|
static isa_drv_ops_t serial_isa_ops = { |
.probe = serial_probe |
}; |
|
static isa_drv_t serial_isa_drv = { |
.name = NAME, |
.ops = &serial_isa_ops |
}; |
|
int serial_init() |
{ |
// TODO: register this driver by generic isa bus driver |
|
isa_register_driver(&serial_isa_drv); |
return 1; |
} |
|
static bool serial_received(ioport8_t *port) |
{ |
return (pio_read_8(port + 5) & 1) != 0; |
} |
|
static uint8_t serial_read_8(ioport8_t *port) |
{ |
while (!serial_received(port)) |
; |
|
uint8_t c = pio_read_8(port); |
return c; |
} |
|
static bool is_transmit_empty(ioport8_t *port) |
{ |
return (pio_read_8(port + 5) & 0x20) != 0; |
} |
|
static void serial_write_8(ioport8_t *port, uint8_t c) |
{ |
while (!is_transmit_empty(port)) |
; |
|
pio_write_8(port, c); |
} |
|
static void serial_init_port(ioport8_t *port) |
{ |
pio_write_8(port + 1, 0x00); // Disable all interrupts |
pio_write_8(port + 3, 0x80); // Enable DLAB (set baud rate divisor) |
pio_write_8(port + 0, 0x60); // Set divisor to 96 (lo byte) 1200 baud |
pio_write_8(port + 1, 0x00); // (hi byte) |
pio_write_8(port + 3, 0x07); // 8 bits, no parity, two stop bits |
pio_write_8(port + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold |
pio_write_8(port + 4, 0x0B); // IRQs enabled, RTS/DSR set |
} |
|
static void serial_probe(bridge_to_isa_t *parent) |
{ |
printf(NAME " driver: probe()\n"); |
|
printf(NAME " driver: probing com1 \n"); |
if (com1 = (ioport8_t *)serial_probe_port(parent->ops->absolutize(COM1))) { |
printf(NAME " driver: initializing com1 \n"); |
serial_init_port(com1); |
} else { |
printf(NAME " driver: com1 is not present \n"); |
} |
|
printf(NAME " driver: probing com2 \n"); |
if (com2 = (ioport8_t *)serial_probe_port(parent->ops->absolutize(COM2))) { |
printf(NAME " driver: initializing com2 \n"); |
serial_init_port(com2); |
} |
else { |
printf(NAME " driver: com2 is not present \n"); |
} |
} |
|
// returns virtual address of the serial port, if the serial port is present at this physical address, NULL otherwise |
static void * serial_probe_port(void *phys_addr) |
{ |
ioport8_t *port_addr = NULL; |
|
if (pio_enable(phys_addr, REG_COUNT, (void **)(&port_addr))) { // Gain control over port's registers. |
printf(NAME ": Error - cannot gain the port %lx.\n", phys_addr); |
return NULL; |
} |
|
uint8_t olddata; |
|
olddata = pio_read_8(port_addr + 4); |
pio_write_8(port_addr + 4, 0x10); |
if ((pio_read_8(port_addr + 6) & 0xf0)) { |
return NULL; |
} |
|
pio_write_8(port_addr + 4, 0x1f); |
if ((pio_read_8(port_addr + 6) & 0xf0) != 0xf0) { |
return 0; |
} |
pio_write_8(port_addr + 4, olddata); |
|
return port_addr; |
} |