Go to most recent revision | Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 4667 | trochtova | 1 | #include <unistd.h> |
| 2 | #include <ddi.h> |
||
| 3 | #include <libarch/ddi.h> |
||
| 4 | #include <stdio.h> |
||
| 5 | |||
| 6 | #include "isa.h" |
||
| 7 | #include "serial.h" |
||
| 8 | |||
| 9 | #define NAME "serial" |
||
| 10 | |||
| 11 | #define REG_COUNT 7 |
||
| 12 | #define COM1 0x3F8 |
||
| 13 | #define COM2 0x2F8 |
||
| 14 | |||
| 15 | static ioport8_t *com1 = 0, *com2 = 0; |
||
| 16 | |||
| 17 | static void serial_init_port(ioport8_t *port); |
||
| 18 | static void serial_write_8(ioport8_t *port, uint8_t c); |
||
| 19 | static bool is_transmit_empty(ioport8_t *port); |
||
| 20 | static uint8_t serial_read_8(ioport8_t *port); |
||
| 21 | static bool serial_received(ioport8_t *port); |
||
| 22 | static void serial_probe(bridge_to_isa_t *parent); |
||
| 23 | static void * serial_probe_port(void *phys_addr); |
||
| 24 | |||
| 25 | static isa_drv_ops_t serial_isa_ops = { |
||
| 26 | .probe = serial_probe |
||
| 27 | }; |
||
| 28 | |||
| 29 | static isa_drv_t serial_isa_drv = { |
||
| 30 | .name = NAME, |
||
| 31 | .ops = &serial_isa_ops |
||
| 32 | }; |
||
| 33 | |||
| 34 | int serial_init() |
||
| 35 | { |
||
| 36 | // TODO: register this driver by generic isa bus driver |
||
| 37 | |||
| 38 | isa_register_driver(&serial_isa_drv); |
||
| 39 | return 1; |
||
| 40 | } |
||
| 41 | |||
| 42 | static bool serial_received(ioport8_t *port) |
||
| 43 | { |
||
| 44 | return (pio_read_8(port + 5) & 1) != 0; |
||
| 45 | } |
||
| 46 | |||
| 47 | static uint8_t serial_read_8(ioport8_t *port) |
||
| 48 | { |
||
| 49 | while (!serial_received(port)) |
||
| 50 | ; |
||
| 51 | |||
| 52 | uint8_t c = pio_read_8(port); |
||
| 53 | return c; |
||
| 54 | } |
||
| 55 | |||
| 56 | static bool is_transmit_empty(ioport8_t *port) |
||
| 57 | { |
||
| 58 | return (pio_read_8(port + 5) & 0x20) != 0; |
||
| 59 | } |
||
| 60 | |||
| 61 | static void serial_write_8(ioport8_t *port, uint8_t c) |
||
| 62 | { |
||
| 63 | while (!is_transmit_empty(port)) |
||
| 64 | ; |
||
| 65 | |||
| 66 | pio_write_8(port, c); |
||
| 67 | } |
||
| 68 | |||
| 69 | static void serial_init_port(ioport8_t *port) |
||
| 70 | { |
||
| 71 | pio_write_8(port + 1, 0x00); // Disable all interrupts |
||
| 72 | pio_write_8(port + 3, 0x80); // Enable DLAB (set baud rate divisor) |
||
| 73 | pio_write_8(port + 0, 0x60); // Set divisor to 96 (lo byte) 1200 baud |
||
| 74 | pio_write_8(port + 1, 0x00); // (hi byte) |
||
| 75 | pio_write_8(port + 3, 0x07); // 8 bits, no parity, two stop bits |
||
| 76 | pio_write_8(port + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold |
||
| 77 | pio_write_8(port + 4, 0x0B); // IRQs enabled, RTS/DSR set |
||
| 78 | } |
||
| 79 | |||
| 80 | static void serial_probe(bridge_to_isa_t *parent) |
||
| 81 | { |
||
| 82 | printf(NAME " driver: probe()\n"); |
||
| 83 | |||
| 84 | printf(NAME " driver: probing com1 \n"); |
||
| 85 | if (com1 = (ioport8_t *)serial_probe_port(parent->ops->absolutize(COM1))) { |
||
| 86 | printf(NAME " driver: initializing com1 \n"); |
||
| 87 | serial_init_port(com1); |
||
| 88 | } else { |
||
| 89 | printf(NAME " driver: com1 is not present \n"); |
||
| 90 | } |
||
| 91 | |||
| 92 | printf(NAME " driver: probing com2 \n"); |
||
| 93 | if (com2 = (ioport8_t *)serial_probe_port(parent->ops->absolutize(COM2))) { |
||
| 94 | printf(NAME " driver: initializing com2 \n"); |
||
| 95 | serial_init_port(com2); |
||
| 96 | } |
||
| 97 | else { |
||
| 98 | printf(NAME " driver: com2 is not present \n"); |
||
| 99 | } |
||
| 100 | } |
||
| 101 | |||
| 102 | // returns virtual address of the serial port, if the serial port is present at this physical address, NULL otherwise |
||
| 103 | static void * serial_probe_port(void *phys_addr) |
||
| 104 | { |
||
| 105 | ioport8_t *port_addr = NULL; |
||
| 106 | |||
| 107 | if (pio_enable(phys_addr, REG_COUNT, (void **)(&port_addr))) { // Gain control over port's registers. |
||
| 108 | printf(NAME ": Error - cannot gain the port %lx.\n", phys_addr); |
||
| 109 | return NULL; |
||
| 110 | } |
||
| 111 | |||
| 112 | uint8_t olddata; |
||
| 113 | |||
| 114 | olddata = pio_read_8(port_addr + 4); |
||
| 115 | pio_write_8(port_addr + 4, 0x10); |
||
| 116 | if ((pio_read_8(port_addr + 6) & 0xf0)) { |
||
| 117 | return NULL; |
||
| 118 | } |
||
| 119 | |||
| 120 | pio_write_8(port_addr + 4, 0x1f); |
||
| 121 | if ((pio_read_8(port_addr + 6) & 0xf0) != 0xf0) { |
||
| 122 | return 0; |
||
| 123 | } |
||
| 124 | pio_write_8(port_addr + 4, olddata); |
||
| 125 | |||
| 126 | return port_addr; |
||
| 127 | } |