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 | } |