linker.ld: use all .data* and .bss* sections
[marionette.git] / kernel / serial.c
blob1e65c5a53189995aa1dfd52ea8302467e6a629b8
1 /*
2 * Copyright (c) 2008 Joshua Phillips. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
15 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
16 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
19 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
23 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
25 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include "serial.h"
29 #include "portio.h"
31 struct serial com1, com2, com3, com4;
33 #define com1Irq 4
34 #define com2Irq 3
35 #define com1Base 0x3F8
36 #define com2Base 0x2F8
37 #define com3Base 0x3E8
38 #define com4Base 0x2E8
40 static int detect_uart(struct serial *self);
41 static char sanitise_output(struct serial *self, char ch);
42 static void send_char(struct serial *self, char ch);
44 // Probe to see if the device is there
45 // 0 - no UART
46 // 1 - 8250
47 // 2 - 16450 or 8250 with scratch reg
48 // 3 - 16550
49 // 4 - 16550A
50 static int detect_uart(struct serial *self)
52 unsigned int x, tmp;
54 // Check if UART is present
55 tmp = inb(self->port + 4);
56 outb(self->port + 4, 0x10);
57 if ((inb(self->port + 6) & 0xF0))
58 return 0;
59 outb(self->port + 4, 0x1F);
60 if ((inb(self->port + 6) & 0xF0) != 0xF0)
61 return 0;
62 outb(self->port + 4, tmp);
64 // Look for scratch register
65 tmp = inb(self->port + 7);
66 outb(self->port + 7, 0x55);
67 if (inb(self->port + 7) != 0x55)
68 return 1;
69 outb(self->port + 7, 0xAA);
70 if (inb(self->port + 7) != 0xAA)
71 return 1;
72 outb(self->port + 7, tmp);
74 // Look for a FIFO
75 outb(self->port + 2, 1);
76 x = inb(self->port + 2);
77 outb(self->port + 2, 0x00);
78 if ((x & 0x80) == 0)
79 return 2;
80 if ((x & 0x40) == 0)
81 return 3;
82 return 4;
85 static char sanitise_output(struct serial *self, char ch)
87 if (ch == '\n'){
88 // We have to send the age-old CRLF combo
89 // for a newline
90 send_char(self, '\r');
91 return '\n';
92 } else if (ch == '\b'){
93 return 0;
94 } else {
95 return ch;
99 // send a single character
100 static void send_char(struct serial *self, char ch)
102 // remove characters we don't want (control characters, etc.)
103 if (!(ch = sanitise_output(self, ch)))
104 return;
105 // wait for UART to be ready
106 while (!(inb(self->port + 5) & 0x20)){
107 // do nothing
109 // send!
110 outb(self->port, ch);
113 bool serial_init(struct serial *self, int com_number, unsigned long baud)
115 unsigned int divisor;
117 switch (com_number){
118 case 1:
119 self->port = com1Base;
120 self->irq = com1Irq;
121 break;
122 case 2:
123 self->port = com2Base;
124 self->irq = com2Irq;
125 break;
126 case 3:
127 self->port = com3Base;
128 self->irq = com1Irq;
129 break;
130 case 4:
131 self->port = com4Base;
132 self->irq = com2Irq;
133 break;
134 default:
135 return false;
138 if (detect_uart(self) == 0){
139 // couldn't actually find the device
140 return false;
143 divisor = 115200 / baud;
144 outb(self->port + 1, 0x00); // disable all interrupts
145 outb(self->port + 3, 0x80); // enable 'DLAB' - baud rate divisor
146 outb(self->port + 0, divisor); // divisor (lower)
147 outb(self->port + 1, divisor >> 8); // divisor (upper)
148 outb(self->port + 3, 0x03); // 8-bits, no parity, one stop bit
149 outb(self->port + 2, 0xC7); // enable FIFO, clear them, with 14-byte threshold
150 outb(self->port + 4, 0x0B); // enable (something)
151 outb(self->port + 4, inb(self->port + 4) | 8); // set OUT2 bit to enable interrupts
152 outb(self->port + 1, 0x01); // enable ERBFI (receiver buffer full) interrupt
154 self->initialized = true;
155 return true;
158 bool serial_is_initialized(struct serial *self)
160 return self->initialized;
163 void serial_send(struct serial *self, const char *str)
165 while (*str){
166 send_char(self, *str);
167 str++;