Subversion Repositories HelenOS

Rev

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
}