Project

General

Profile

Statistics
| Revision:

root / proj / src / uart.c @ 250

History | View | Annotate | Download (9.29 KB)

1
#include <lcom/lcf.h>
2

    
3
#include "uart.h"
4

    
5
#include "errors.h"
6

    
7
#define UART_BITRATE                            115200
8
#define UART_WAIT                               20 //microseconds
9

    
10
#define UART_RBR                                0
11
#define UART_THR                                0
12
#define UART_IER                                1
13
#define UART_IIR                                2
14
#define UART_FCR                                2
15
#define UART_LCR                                3
16
#define UART_MCR                                4
17
#define UART_LSR                                5
18
#define UART_MSR                                6
19
#define UART_SR                                 7
20

    
21
#define UART_DLL                                0
22
#define UART_DLM                                1
23

    
24
/// LCR
25
#define UART_BITS_PER_CHAR_POS                  0
26
#define UART_STOP_BITS_POS                      2
27
#define UART_PARITY_POS                         3
28
#define UART_BREAK_CONTROL_POS                  6
29
#define UART_DLAB_POS                           7
30

    
31
#define UART_BITS_PER_CHAR                      (BIT(0) | BIT(1))
32
#define UART_STOP_BITS                          (BIT(2))
33
#define UART_PARITY                             (BIT(3) | BIT(4) | BIT(5))
34
#define UART_BREAK_CONTROL                      (BIT(6))
35
#define UART_DLAB                               (BIT(7))
36

    
37
#define UART_GET_BITS_PER_CHAR(n)               (((n)&UART_BITS_PER_CHAR) + 5)
38
#define UART_GET_STOP_BITS(n)                   (((n)&UART_STOP_BITS)? 2 : 1)
39
#define UART_GET_PARITY(n)                      (((n)&UART_PARITY       )>>UART_PARITY_POS       )
40
#define UART_GET_BREAK_CONTROL(n)               (((n)&UART_BREAK_CONTROL)>>UART_BREAK_CONTROL_POS)
41
#define UART_GET_DLAB(n)                        (((n)&UART_DLAB         )>>UART_DLAB_POS         )
42
#define UART_GET_DIV_LATCH(m,l)                 ((m)<<8 | (l))
43
#define UART_GET_DLL(n)                         ((n)&0xFF)
44
#define UART_GET_DLM(n)                         (((n)>>8)&0xFF)
45

    
46
/// IER
47
#define UART_INT_EN_RECEIVED_DATA_POS           0
48
#define UART_INT_EN_TRANSMITTER_EMPTY_POS       1
49
#define UART_INT_EN_RECEIVER_LINE_STAT_POS      2
50
#define UART_INT_EN_MODEM_STAT_POS              3
51

    
52
#define UART_INT_EN_RECEIVED_DATA               (BIT(0))
53
#define UART_INT_EN_TRANSMITTER_EMPTY           (BIT(1))
54
#define UART_INT_EN_RECEIVER_LINE_STAT          (BIT(2))
55
#define UART_INT_EN_MODEM_STAT                  (BIT(3))
56

    
57
#define UART_INT_EN_GET_RECEIVED_DATA(n)        (((n)&UART_INT_EN_RECEIVED_DATA     )>>UART_INT_EN_RECEIVED_DATA_POS     )
58
#define UART_INT_EN_GET_TRANSMITTER_EMPTY(n)    (((n)&UART_INT_EN_TRANSMITTER_EMPTY )>>UART_INT_EN_TRANSMITTER_EMPTY_POS )
59
#define UART_INT_EN_GET_RECEIVER_LINE_STAT(n)   (((n)&UART_INT_EN_RECEIVER_LINE_STAT)>>UART_INT_EN_RECEIVER_LINE_STAT_POS)
60
#define UART_INT_EN_GET_MODEM_STAT(n)           (((n)&UART_INT_EN_MODEM_STAT        )>>UART_INT_EN_MODEM_STAT_POS        )
61

    
62
/// LSR
63
#define UART_RECEIVER_READY_POS                 0
64
#define UART_TRANSMITTER_EMPTY_POS              5
65

    
66
#define UART_RECEIVER_READY                     (BIT(0))
67
#define UART_TRANSMITTER_EMPTY                  (BIT(5))
68

    
69
#define UART_GET_RECEIVER_READY(n)              (((n)&UART_RECEIVER_READY           )>>UART_RECEIVER_READY_POS           )
70
#define UART_GET_TRANSMITTER_EMPTY(n)           (((n)&UART_TRANSMITTER_EMPTY        )>>UART_TRANSMITTER_EMPTY_POS        )
71

    
72
int uart_get_config(int base_addr, uart_config *config){
73
    int ret = SUCCESS;
74

    
75
    config->base_addr = base_addr;
76

    
77
    if((ret = util_sys_inb(base_addr+UART_LCR, &config->lcr))) return ret;
78

    
79
    if((ret = util_sys_inb(base_addr+UART_IER, &config->ier))) return ret;
80

    
81
    if((ret = uart_enable_divisor_latch (base_addr))) return ret;
82
    if((ret = util_sys_inb(base_addr+UART_DLL, &config->dll   ))) return ret;
83
    if((ret = util_sys_inb(base_addr+UART_DLM, &config->dlm   ))) return ret;
84
    if((ret = uart_disable_divisor_latch(base_addr))) return ret;
85

    
86
    uart_parse_config(config);
87
    return ret;
88
}
89
void uart_parse_config(uart_config *config){
90
    /// LCR
91
    config->bits_per_char          = UART_GET_BITS_PER_CHAR     (config->lcr);
92
    config->stop_bits              = UART_GET_STOP_BITS         (config->lcr);
93
    config->parity                 = UART_GET_PARITY            (config->lcr); if((config->parity & BIT(0)) == 0) config->parity = uart_parity_none;
94
    config->break_control          = UART_GET_BREAK_CONTROL     (config->lcr);
95
    config->dlab                   = UART_GET_DLAB              (config->lcr);
96
    /// IER
97
    config->received_data_int      = UART_INT_EN_GET_RECEIVED_DATA     (config->ier);
98
    config->transmitter_empty_int  = UART_INT_EN_GET_TRANSMITTER_EMPTY (config->ier);
99
    config->receiver_line_stat_int = UART_INT_EN_GET_RECEIVER_LINE_STAT(config->ier);
100
    config->modem_stat_int         = UART_INT_EN_GET_MODEM_STAT        (config->ier);
101
    /// DIV LATCH
102
    config->divisor_latch          = UART_GET_DIV_LATCH(config->dlm, config->dll);
103
}
104
void uart_print_config(uart_config config){
105

    
106
    printf("%s configuration:\n", (config.base_addr == COM1_ADDR ? "COM1" : "COM2"));
107
    printf("\tLCR = 0x%X: %d bits per char\t %d stop bits\t", config.lcr, config.bits_per_char, config.stop_bits);
108
    if((config.parity&BIT(0)) == 0) printf("NO parity\n");
109
    else switch(config.parity){
110
        case uart_parity_odd : printf("ODD parity\n"     ); break;
111
        case uart_parity_even: printf("EVEN parity\n"    ); break;
112
        case uart_parity_par1: printf("parity bit is 1\n"); break;
113
        case uart_parity_par0: printf("parity bit is 0\n"); break;
114
        default              : printf("invalid\n"        ); break;
115
    }
116
    printf("\tDLM = 0x%02X DLL=0x%02X: bitrate = %d bps\n", config.dlm, config.dll, UART_BITRATE/config.divisor_latch);
117
    printf("\tIER = 0x%02X: Rx interrupts: %s\tTx interrupts: %s\n", config.ier,
118
        (config.received_data_int     ? "ENABLED":"DISABLED"),
119
        (config.transmitter_empty_int ? "ENABLED":"DISABLED"));
120
}
121

    
122
int uart_enable_divisor_latch(int base_addr){
123
    int ret = SUCCESS;
124
    uint8_t conf; if((ret = util_sys_inb(base_addr+UART_LCR, &conf))) return ret;
125
    return uart_write_config(base_addr, conf | UART_DLAB);
126
}
127
int uart_disable_divisor_latch(int base_addr){
128
    int ret = SUCCESS;
129
    uint8_t conf; if((ret = util_sys_inb(base_addr+UART_LCR, &conf))) return ret;
130
    return uart_write_config(base_addr, conf & (~UART_DLAB));
131
}
132

    
133
int uart_write_config(int base_addr, uint8_t config){
134
    if(sys_outb(base_addr+UART_LCR, config)) return WRITE_ERROR;
135
    return SUCCESS;
136
}
137
int uart_set_bits_per_character(int base_addr, uint8_t bits_per_char){
138
    if(bits_per_char < 5 || bits_per_char > 8) return INVALID_ARG;
139
    int ret = SUCCESS;
140
    bits_per_char = (bits_per_char-5)&0x3;
141
    uint8_t conf; if((ret = util_sys_inb(base_addr+UART_LCR, &conf))) return ret;
142
    conf = (conf & (~UART_BITS_PER_CHAR)) | bits_per_char;
143
    return uart_write_config(base_addr, conf);
144
}
145
int uart_set_stop_bits(int base_addr, uint8_t stop){
146
    if(stop != 1 && stop != 2) return INVALID_ARG;
147
    int ret = SUCCESS;
148
    stop -= 1;
149
    stop = (stop&1)<<2;
150
    uint8_t conf; if((ret = util_sys_inb(base_addr+UART_LCR, &conf))) return ret;
151
    conf = (conf & (~UART_STOP_BITS)) | stop;
152
    return uart_write_config(base_addr, conf);
153
}
154
int uart_set_parity(int base_addr, uart_parity par){
155
    int ret = SUCCESS;
156
    uint8_t parity = par << 3;
157
    uint8_t conf; if((ret = util_sys_inb(base_addr+UART_LCR, &conf))) return ret;
158
    conf = (conf & (~UART_PARITY)) | parity;
159
    return uart_write_config(base_addr, conf);
160
}
161
int uart_set_bit_rate(int base_addr, float bit_rate){
162
    int ret = SUCCESS;
163
    uint16_t latch = UART_BITRATE/bit_rate;
164
    uint8_t dll = UART_GET_DLL(latch);
165
    uint8_t dlm = UART_GET_DLM(latch);
166
    if((ret = uart_enable_divisor_latch(base_addr))) return ret;
167
    if(sys_outb(base_addr+UART_DLL, dll)) return WRITE_ERROR;
168
    if(sys_outb(base_addr+UART_DLM, dlm)) return WRITE_ERROR;
169
    if((ret = uart_disable_divisor_latch(base_addr))) return ret;
170
    return SUCCESS;
171
}
172

    
173
/// PRIVATE
174
int uart_get_lsr(int base_addr, uint8_t *p){
175
    return util_sys_inb(base_addr+UART_LSR, p);
176
}
177
/**
178
 * @brief Get char from RBR.
179
 */
180
int uart_get_char(int base_addr, uint8_t *p){
181
    int ret;
182
    if((ret = uart_disable_divisor_latch(base_addr))) return ret;
183
    return util_sys_inb(base_addr+UART_RBR, p);
184
}
185
int uart_send_char(int base_addr, uint8_t c){
186
    int ret;
187
    if((ret = uart_disable_divisor_latch(base_addr))) return ret;
188
    if(sys_outb(base_addr, c)) return WRITE_ERROR;
189
    return SUCCESS;
190
}
191
int uart_receiver_ready(int base_addr){
192
    uint8_t lsr;
193
    if(uart_get_lsr(base_addr, &lsr)) return false;
194
    return UART_GET_RECEIVER_READY(lsr);
195
}
196
int uart_transmitter_empty(int base_addr){
197
    uint8_t lsr;
198
    if(uart_get_lsr(base_addr, &lsr)) return false;
199
    return UART_GET_TRANSMITTER_EMPTY(lsr);
200
}
201
///PUBLIC
202
int uart_get_char_poll(int base_addr, uint8_t *p){
203
    int ret;
204
    while(!uart_receiver_ready(base_addr)){}
205
    if((ret = uart_get_char(base_addr, p))) return ret;
206
    return SUCCESS;
207
}
208
int uart_send_char_poll(int base_addr, uint8_t  c){
209
    int ret;
210
    while(!uart_transmitter_empty(base_addr)){}
211
    if((ret = uart_send_char(base_addr, c))) return ret;
212
    return SUCCESS;
213
}
214
int uart_send_memory_poll(int base_addr, void *str, size_t n){
215
    int ret;
216
    uint8_t *p = str;
217
    for(size_t i = 0; i < n; ++i, ++p){
218
        if((ret = uart_send_char_poll(base_addr, *p))) return ret;
219
    }
220
    return SUCCESS;
221
}