Project

General

Profile

Statistics
| Revision:

root / proj / src / uart.c @ 242

History | View | Annotate | Download (7.19 KB)

1 235 up20180642
#include <lcom/lcf.h>
2
3
#include "uart.h"
4
5
#include "errors.h"
6
7 241 up20180642
#define UART_RBR            0
8
#define UART_THR            0
9
#define UART_IER            1
10
#define UART_IIR            2
11
#define UART_FCR            2
12
#define UART_LCR            3
13
#define UART_MCR            4
14
#define UART_LSR            5
15
#define UART_MSR            6
16
#define UART_SR             7
17
18
#define UART_DLL            0
19
#define UART_DLM            1
20
21
#define UART_BITS_PER_CHAR_POS 0
22
#define UART_STOP_BITS_POS     2
23
#define UART_PARITY_POS        3
24
#define UART_BREAK_CONTROL_POS 6
25
#define UART_DLAB_POS          7
26
27
#define UART_BITS_PER_CHAR  (BIT(0) | BIT(1))
28
#define UART_STOP_BITS      (BIT(2))
29
#define UART_PARITY         (BIT(3) | BIT(4) | BIT(5))
30
#define UART_BREAK_CONTROL  (BIT(6))
31
#define UART_DLAB           (BIT(7))
32
33
#define UART_GET_BITS_PER_CHAR(n) (((n)&UART_BITS_PER_CHAR) + 5)
34
#define UART_GET_STOP_BITS(n)     (((n)&UART_STOP_BITS)? 2 : 1)
35
#define UART_GET_PARITY(n)        (((n)&UART_PARITY       )>>UART_PARITY_POS       )
36
#define UART_GET_BREAK_CONTROL(n) (((n)&UART_BREAK_CONTROL)>>UART_BREAK_CONTROL_POS)
37
#define UART_GET_DLAB(n)          (((n)&UART_DLAB         )>>UART_DLAB_POS         )
38
#define UART_GET_DIV_LATCH(m,l)   ((m)<<8 | (l))
39
#define UART_GET_DLL(n)           ((n)&0xFF)
40
#define UART_GET_DLM(n)           (((n)>>8)&0xFF)
41
42 242 up20180642
#define UART_RECEIVED_DATA_POS      0
43
#define UART_TRANSMITTER_EMPTY_POS  1
44
#define UART_RECEIVER_LINE_STAT_POS 2
45
#define UART_MODEM_STAT_POS         3
46
47
#define UART_RECEIVED_DATA          (BIT(0))
48
#define UART_TRANSMITTER_EMPTY      (BIT(1))
49
#define UART_RECEIVER_LINE_STAT     (BIT(2))
50
#define UART_MODEM_STAT             (BIT(3))
51
52
#define UART_GET_RECEIVED_DATA(n)       (((n)&UART_RECEIVED_DATA     )>>UART_RECEIVED_DATA_POS     )
53
#define UART_GET_TRANSMITTER_EMPTY(n)   (((n)&UART_TRANSMITTER_EMPTY )>>UART_TRANSMITTER_EMPTY_POS )
54
#define UART_GET_RECEIVER_LINE_STAT(n)  (((n)&UART_RECEIVER_LINE_STAT)>>UART_RECEIVER_LINE_STAT_POS)
55
#define UART_GET_MODEM_STAT(n)          (((n)&UART_MODEM_STAT        )>>UART_MODEM_STAT_POS        )
56
57 235 up20180642
int uart_get_config(int base_addr, uart_config *config){
58
    int ret = SUCCESS;
59
60
    config->base_addr = base_addr;
61
62 242 up20180642
    if((ret = util_sys_inb(base_addr+UART_LCR, &config->lcr))) return ret;
63 235 up20180642
64 242 up20180642
    if((ret = util_sys_inb(base_addr+UART_IER, &config->ier))) return ret;
65
66
    if((ret = uart_enable_divisor_latch (base_addr))) return ret;
67 235 up20180642
    if((ret = util_sys_inb(base_addr+UART_DLL, &config->dll   ))) return ret;
68
    if((ret = util_sys_inb(base_addr+UART_DLM, &config->dlm   ))) return ret;
69 242 up20180642
    if((ret = uart_disable_divisor_latch(base_addr))) return ret;
70 235 up20180642
71
    uart_parse_config(config);
72
    return ret;
73
}
74
void uart_parse_config(uart_config *config){
75 242 up20180642
    /// LCR
76
    config->bits_per_char          = UART_GET_BITS_PER_CHAR     (config->lcr);
77
    config->stop_bits              = UART_GET_STOP_BITS         (config->lcr);
78
    config->parity                 = UART_GET_PARITY            (config->lcr);
79
    config->break_control          = UART_GET_BREAK_CONTROL     (config->lcr);
80
    config->dlab                   = UART_GET_DLAB              (config->lcr);
81
    /// IER
82
    config->received_data_int      = UART_GET_RECEIVED_DATA     (config->ier);
83
    config->transmitter_empty_int  = UART_GET_TRANSMITTER_EMPTY (config->ier);
84
    config->receiver_line_stat_int = UART_GET_RECEIVER_LINE_STAT(config->ier);
85
    config->modem_stat_int         = UART_GET_MODEM_STAT        (config->ier);
86
    /// DIV LATCH
87
    config->divisor_latch          = UART_GET_DIV_LATCH(config->dlm, config->dll);
88 235 up20180642
}
89
void uart_print_config(uart_config config){
90 242 up20180642
    printf("Base address                                   : 0x%X\n", config.base_addr);
91
    printf("    LCR configuration                          : 0x%02X\n", config.lcr);
92
    printf("        Number of bits per char                : %d\n", config.bits_per_char);
93
    printf("        Number of stop bits                    : %d\n", config.stop_bits);
94
    printf("        Parity                                 : ");
95 235 up20180642
    if((config.parity&1) == 0) printf("no parity\n");
96
    else switch(config.parity){
97
        case uart_parity_odd : printf("odd parity\n"     ); break;
98
        case uart_parity_even: printf("even parity\n"    ); break;
99
        case uart_parity_par1: printf("parity bit is 1\n"); break;
100
        case uart_parity_par0: printf("parity bit is 0\n"); break;
101
        default              : printf("invalid\n"        ); break;
102
    }
103 242 up20180642
    printf("    Break control                              : %d\n", config.break_control);
104
    printf("    DLAB                                       : %d\n", config.dlab);
105
106
    printf("    IER configuration                          : 0x%02X\n", config.ier);
107
    printf("        Received data interrupts enabled       : %d\n", config.received_data_int);
108
    printf("        Transmitter empty interrupts enabled   : %d\n", config.transmitter_empty_int);
109
    printf("        Receiver line status interrupts enabled: %d\n", config.receiver_line_stat_int);
110
    printf("        Modem status interrupts enabled        : %d\n", config.modem_stat_int);
111
112
    printf("    Divisor latch (DLM & DLL)                  : %d\n", config.divisor_latch);
113
    printf("        Bit rate                               : %d\n", UART_BITRATE/config.divisor_latch);
114 235 up20180642
}
115
116
int uart_enable_divisor_latch(int base_addr){
117
    int ret = SUCCESS;
118
    uint8_t conf; if((ret = util_sys_inb(base_addr+UART_LCR, &conf))) return ret;
119
    return uart_write_config(base_addr, conf | UART_DLAB);
120
}
121
int uart_disable_divisor_latch(int base_addr){
122
    int ret = SUCCESS;
123
    uint8_t conf; if((ret = util_sys_inb(base_addr+UART_LCR, &conf))) return ret;
124
    return uart_write_config(base_addr, conf & (~UART_DLAB));
125
}
126
127
int uart_write_config(int base_addr, uint8_t config){
128
    if(sys_outb(base_addr+UART_LCR, config)) return WRITE_ERROR;
129
    return SUCCESS;
130
}
131
int uart_set_bits_per_character(int base_addr, uint8_t bits_per_char){
132
    if(bits_per_char < 5 || bits_per_char > 8) return INVALID_ARG;
133
    int ret = SUCCESS;
134
    bits_per_char = (bits_per_char-5)&0x3;
135
    uint8_t conf; if((ret = util_sys_inb(base_addr+UART_LCR, &conf))) return ret;
136
    conf = (conf & (~UART_BITS_PER_CHAR)) | bits_per_char;
137
    return uart_write_config(base_addr, conf);
138
}
139
int uart_set_stop_bits(int base_addr, uint8_t stop){
140
    if(stop != 1 && stop != 2) return INVALID_ARG;
141
    int ret = SUCCESS;
142
    stop -= 1;
143
    stop = (stop&1)<<2;
144
    uint8_t conf; if((ret = util_sys_inb(base_addr+UART_LCR, &conf))) return ret;
145
    conf = (conf & (~UART_STOP_BITS)) | stop;
146
    return uart_write_config(base_addr, conf);
147
}
148
int uart_set_parity(int base_addr, uart_parity par){
149
    int ret = SUCCESS;
150
    uint8_t parity = par << 3;
151
    uint8_t conf; if((ret = util_sys_inb(base_addr+UART_LCR, &conf))) return ret;
152
    conf = (conf & (~UART_PARITY)) | parity;
153
    return uart_write_config(base_addr, conf);
154
}
155 241 up20180642
int uart_set_bit_rate(int base_addr, float bit_rate){
156 235 up20180642
    int ret = SUCCESS;
157
    uint16_t latch = UART_BITRATE/bit_rate;
158 241 up20180642
    uint8_t dll = UART_GET_DLL(latch);
159
    uint8_t dlm = UART_GET_DLM(latch);
160 235 up20180642
    if((ret = uart_enable_divisor_latch(base_addr))) return ret;
161
    if(sys_outb(base_addr+UART_DLL, dll)) return WRITE_ERROR;
162
    if(sys_outb(base_addr+UART_DLM, dlm)) return WRITE_ERROR;
163
    if((ret = util_sys_inb(base_addr+UART_DLM, &dlm))) return ret;
164
    return SUCCESS;
165
}