Project

General

Profile

Statistics
| Revision:

root / proj / src / uart.c @ 258

History | View | Annotate | Download (10.2 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_RX_POS                      0
48
#define UART_INT_EN_TX_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_RX                          (BIT(0))
53
#define UART_INT_EN_TX                          (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_GET_INT_EN_RX(n)                   (((n)&UART_INT_EN_RX                )>>UART_INT_EN_RX_POS                )
58
#define UART_GET_INT_EN_TX(n)                   (((n)&UART_INT_EN_TX                )>>UART_INT_EN_TX_POS                )
59
#define UART_GET_INT_EN_RECEIVER_LINE_STAT(n)   (((n)&UART_INT_EN_RECEIVER_LINE_STAT)>>UART_INT_EN_RECEIVER_LINE_STAT_POS)
60
#define UART_GET_INT_EN_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
static void uart_parse_config(uart_config *config){
73
    /// LCR
74
    config->bits_per_char          = UART_GET_BITS_PER_CHAR     (config->lcr);
75
    config->stop_bits              = UART_GET_STOP_BITS         (config->lcr);
76
    config->parity                 = UART_GET_PARITY            (config->lcr); if((config->parity & BIT(0)) == 0) config->parity = uart_parity_none;
77
    config->break_control          = UART_GET_BREAK_CONTROL     (config->lcr);
78
    config->dlab                   = UART_GET_DLAB              (config->lcr);
79
    /// IER
80
    config->received_data_int      = UART_GET_INT_EN_RX                (config->ier);
81
    config->transmitter_empty_int  = UART_GET_INT_EN_TX                (config->ier);
82
    config->receiver_line_stat_int = UART_GET_INT_EN_RECEIVER_LINE_STAT(config->ier);
83
    config->modem_stat_int         = UART_GET_INT_EN_MODEM_STAT        (config->ier);
84
    /// DIV LATCH
85
    config->divisor_latch          = UART_GET_DIV_LATCH(config->dlm, config->dll);
86
}
87

    
88
static int uart_get_lcr(int base_addr, uint8_t *p){
89
    return util_sys_inb(base_addr+UART_LCR, p);
90
}
91
static int uart_set_lcr(int base_addr, uint8_t config){
92
    if(sys_outb(base_addr+UART_LCR, config)) return WRITE_ERROR;
93
    return SUCCESS;
94
}
95
static int uart_get_lsr(int base_addr, uint8_t *p){
96
    return util_sys_inb(base_addr+UART_LSR, p);
97
}
98

    
99
static int uart_enable_divisor_latch(int base_addr){
100
    int ret = SUCCESS;
101
    uint8_t conf; if((ret = uart_get_lcr(base_addr, &conf))) return ret;
102
    return uart_set_lcr(base_addr, conf | UART_DLAB);
103
}
104
static int uart_disable_divisor_latch(int base_addr){
105
    int ret = SUCCESS;
106
    uint8_t conf; if((ret = uart_get_lcr(base_addr, &conf))) return ret;
107
    return uart_set_lcr(base_addr, conf & (~UART_DLAB));
108
}
109

    
110
static int uart_get_ier(int base_addr, uint8_t *p){
111
    int ret;
112
    if((ret = uart_disable_divisor_latch(base_addr))) return ret;
113
    return util_sys_inb(base_addr+UART_IER, p);
114
}
115
static int uart_set_ier(int base_addr, uint8_t n){
116
    int ret;
117
    if((ret = uart_disable_divisor_latch(base_addr))) return ret;
118
    if(sys_outb(base_addr+UART_IER, n)) return WRITE_ERROR;
119
    return SUCCESS;
120
}
121

    
122
int uart_get_config(int base_addr, uart_config *config){
123
    int ret = SUCCESS;
124

    
125
    config->base_addr = base_addr;
126

    
127
    if((ret = uart_get_lcr(base_addr, &config->lcr))) return ret;
128

    
129
    if((ret = uart_get_ier(base_addr, &config->ier))) return ret;
130

    
131
    if((ret = uart_enable_divisor_latch (base_addr))) return ret;
132
    if((ret = util_sys_inb(base_addr+UART_DLL, &config->dll   ))) return ret;
133
    if((ret = util_sys_inb(base_addr+UART_DLM, &config->dlm   ))) return ret;
134
    if((ret = uart_disable_divisor_latch(base_addr))) return ret;
135

    
136
    uart_parse_config(config);
137
    return ret;
138
}
139
void uart_print_config(uart_config config){
140

    
141
    printf("%s configuration:\n", (config.base_addr == COM1_ADDR ? "COM1" : "COM2"));
142
    printf("\tLCR = 0x%X: %d bits per char\t %d stop bits\t", config.lcr, config.bits_per_char, config.stop_bits);
143
    if((config.parity&BIT(0)) == 0) printf("NO parity\n");
144
    else switch(config.parity){
145
        case uart_parity_odd : printf("ODD parity\n"     ); break;
146
        case uart_parity_even: printf("EVEN parity\n"    ); break;
147
        case uart_parity_par1: printf("parity bit is 1\n"); break;
148
        case uart_parity_par0: printf("parity bit is 0\n"); break;
149
        default              : printf("invalid\n"        ); break;
150
    }
151
    printf("\tDLM = 0x%02X DLL=0x%02X: bitrate = %d bps\n", config.dlm, config.dll, UART_BITRATE/config.divisor_latch);
152
    printf("\tIER = 0x%02X: Rx interrupts: %s\tTx interrupts: %s\n", config.ier,
153
        (config.received_data_int     ? "ENABLED":"DISABLED"),
154
        (config.transmitter_empty_int ? "ENABLED":"DISABLED"));
155
}
156

    
157
int uart_set_bits_per_character(int base_addr, uint8_t bits_per_char){
158
    if(bits_per_char < 5 || bits_per_char > 8) return INVALID_ARG;
159
    int ret = SUCCESS;
160
    bits_per_char = (bits_per_char-5)&0x3;
161
    uint8_t conf; if((ret = uart_get_lcr(base_addr, &conf))) return ret;
162
    conf = (conf & (~UART_BITS_PER_CHAR)) | bits_per_char;
163
    return uart_set_lcr(base_addr, conf);
164
}
165
int uart_set_stop_bits(int base_addr, uint8_t stop){
166
    if(stop != 1 && stop != 2) return INVALID_ARG;
167
    int ret = SUCCESS;
168
    stop -= 1;
169
    stop = (stop&1)<<2;
170
    uint8_t conf; if((ret = uart_get_lcr(base_addr, &conf))) return ret;
171
    conf = (conf & (~UART_STOP_BITS)) | stop;
172
    return uart_set_lcr(base_addr, conf);
173
}
174
int uart_set_parity(int base_addr, uart_parity par){
175
    int ret = SUCCESS;
176
    uint8_t parity = par << 3;
177
    uint8_t conf; if((ret = uart_get_lcr(base_addr, &conf))) return ret;
178
    conf = (conf & (~UART_PARITY)) | parity;
179
    return uart_set_lcr(base_addr, conf);
180
}
181
int uart_set_bit_rate(int base_addr, float bit_rate){
182
    int ret = SUCCESS;
183
    uint16_t latch = UART_BITRATE/bit_rate;
184
    uint8_t dll = UART_GET_DLL(latch);
185
    uint8_t dlm = UART_GET_DLM(latch);
186
    if((ret = uart_enable_divisor_latch(base_addr))) return ret;
187
    if(sys_outb(base_addr+UART_DLL, dll)) return WRITE_ERROR;
188
    if(sys_outb(base_addr+UART_DLM, dlm)) return WRITE_ERROR;
189
    if((ret = uart_disable_divisor_latch(base_addr))) return ret;
190
    return SUCCESS;
191
}
192

    
193
static int uart_get_char(int base_addr, uint8_t *p){
194
    int ret;
195
    if((ret = uart_disable_divisor_latch(base_addr))) return ret;
196
    return util_sys_inb(base_addr+UART_RBR, p);
197
}
198
static int uart_send_char(int base_addr, uint8_t c){
199
    int ret;
200
    if((ret = uart_disable_divisor_latch(base_addr))) return ret;
201
    if(sys_outb(base_addr+UART_THR, c)) return WRITE_ERROR;
202
    return SUCCESS;
203
}
204
static int uart_receiver_ready(int base_addr){
205
    uint8_t lsr;
206
    if(uart_get_lsr(base_addr, &lsr)) return false;
207
    return UART_GET_RECEIVER_READY(lsr);
208
}
209
static int uart_transmitter_empty(int base_addr){
210
    uint8_t lsr;
211
    if(uart_get_lsr(base_addr, &lsr)) return false;
212
    return UART_GET_TRANSMITTER_EMPTY(lsr);
213
}
214

    
215
int uart_enable_int_rx(int base_addr){
216
    int ret;
217
    uint8_t ier;
218
    if((ret = uart_get_ier(base_addr, &ier))) return ret;
219
    ier |= UART_INT_EN_RX;
220
    return uart_set_ier(base_addr, ier);
221
}
222
int uart_disable_int_rx(int base_addr){
223
    int ret;
224
    uint8_t ier;
225
    if((ret = uart_get_ier(base_addr, &ier))) return ret;
226
    ier &= ~UART_INT_EN_RX;
227
    return uart_set_ier(base_addr, ier);
228
}
229
int uart_enable_int_tx(int base_addr){
230
    int ret;
231
    uint8_t ier;
232
    if((ret = uart_get_ier(base_addr, &ier))) return ret;
233
    ier |= UART_INT_EN_TX;
234
    return uart_set_ier(base_addr, ier);
235
}
236
int uart_disable_int_tx(int base_addr){
237
    int ret;
238
    uint8_t ier;
239
    if((ret = uart_get_ier(base_addr, &ier))) return ret;
240
    ier &= ~UART_INT_EN_TX;
241
    return uart_set_ier(base_addr, ier);
242
}
243

    
244
int uart_get_char_poll(int base_addr, uint8_t *p){
245
    int ret;
246
    while(!uart_receiver_ready(base_addr)){}
247
    if((ret = uart_get_char(base_addr, p))) return ret;
248
    return SUCCESS;
249
}
250
int uart_send_char_poll(int base_addr, uint8_t  c){
251
    int ret;
252
    while(!uart_transmitter_empty(base_addr)){}
253
    if((ret = uart_send_char(base_addr, c))) return ret;
254
    return SUCCESS;
255
}