Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


imported SEABIOS source tree
[palacios.git] / bios / seabios / src / serial.c
1 // 16bit code to handle serial and printer services.
2 //
3 // Copyright (C) 2008,2009  Kevin O'Connor <kevin@koconnor.net>
4 // Copyright (C) 2002  MandrakeSoft S.A.
5 //
6 // This file may be distributed under the terms of the GNU LGPLv3 license.
7
8 #include "biosvar.h" // SET_BDA
9 #include "util.h" // debug_enter
10 #include "bregs.h" // struct bregs
11
12
13 /****************************************************************
14  * COM ports
15  ****************************************************************/
16
17 static u16
18 detect_serial(u16 port, u8 timeout, u8 count)
19 {
20     outb(0x02, port+SEROFF_IER);
21     u8 ier = inb(port+SEROFF_IER);
22     if (ier != 0x02)
23         return 0;
24     u8 iir = inb(port+SEROFF_IIR);
25     if ((iir & 0x3f) != 0x02)
26         return 0;
27
28     outb(0x00, port+SEROFF_IER);
29     SET_BDA(port_com[count], port);
30     SET_BDA(com_timeout[count], timeout);
31     return 1;
32 }
33
34 void
35 serial_setup(void)
36 {
37     if (! CONFIG_SERIAL)
38         return;
39     dprintf(3, "init serial\n");
40
41     u16 count = 0;
42     count += detect_serial(PORT_SERIAL1, 0x0a, count);
43     count += detect_serial(PORT_SERIAL2, 0x0a, count);
44     count += detect_serial(PORT_SERIAL3, 0x0a, count);
45     count += detect_serial(PORT_SERIAL4, 0x0a, count);
46     dprintf(1, "Found %d serial ports\n", count);
47
48     // Equipment word bits 9..11 determing # serial ports
49     u16 eqb = GET_BDA(equipment_list_flags);
50     SET_BDA(equipment_list_flags, (eqb & 0xf1ff) | (count << 9));
51 }
52
53 static u16
54 getComAddr(struct bregs *regs)
55 {
56     if (regs->dx >= 4) {
57         set_invalid(regs);
58         return 0;
59     }
60     u16 addr = GET_BDA(port_com[regs->dx]);
61     if (! addr)
62         set_invalid(regs);
63     return addr;
64 }
65
66 // SERIAL - INITIALIZE PORT
67 static void
68 handle_1400(struct bregs *regs)
69 {
70     u16 addr = getComAddr(regs);
71     if (!addr)
72         return;
73     outb(inb(addr+SEROFF_LCR) | 0x80, addr+SEROFF_LCR);
74     if ((regs->al & 0xE0) == 0) {
75         outb(0x17, addr+SEROFF_DLL);
76         outb(0x04, addr+SEROFF_DLH);
77     } else {
78         u16 val16 = 0x600 >> ((regs->al & 0xE0) >> 5);
79         outb(val16 & 0xFF, addr+SEROFF_DLL);
80         outb(val16 >> 8, addr+SEROFF_DLH);
81     }
82     outb(regs->al & 0x1F, addr+SEROFF_LCR);
83     regs->ah = inb(addr+SEROFF_LSR);
84     regs->al = inb(addr+SEROFF_MSR);
85     set_success(regs);
86 }
87
88 // SERIAL - WRITE CHARACTER TO PORT
89 static void
90 handle_1401(struct bregs *regs)
91 {
92     u16 addr = getComAddr(regs);
93     if (!addr)
94         return;
95     u32 end = calc_future_timer_ticks(GET_BDA(com_timeout[regs->dx]));
96     for (;;) {
97         u8 lsr = inb(addr+SEROFF_LSR);
98         if ((lsr & 0x60) == 0x60) {
99             // Success - can write data
100             outb(regs->al, addr+SEROFF_DATA);
101             // XXX - reread lsr?
102             regs->ah = lsr;
103             break;
104         }
105         if (check_timer(end)) {
106             // Timed out - can't write data.
107             regs->ah = lsr | 0x80;
108             break;
109         }
110         yield();
111     }
112     set_success(regs);
113 }
114
115 // SERIAL - READ CHARACTER FROM PORT
116 static void
117 handle_1402(struct bregs *regs)
118 {
119     u16 addr = getComAddr(regs);
120     if (!addr)
121         return;
122     u32 end = calc_future_timer_ticks(GET_BDA(com_timeout[regs->dx]));
123     for (;;) {
124         u8 lsr = inb(addr+SEROFF_LSR);
125         if (lsr & 0x01) {
126             // Success - can read data
127             regs->al = inb(addr+SEROFF_DATA);
128             regs->ah = lsr;
129             break;
130         }
131         if (check_timer(end)) {
132             // Timed out - can't read data.
133             regs->ah = lsr | 0x80;
134             break;
135         }
136         yield();
137     }
138     set_success(regs);
139 }
140
141 // SERIAL - GET PORT STATUS
142 static void
143 handle_1403(struct bregs *regs)
144 {
145     u16 addr = getComAddr(regs);
146     if (!addr)
147         return;
148     regs->ah = inb(addr+SEROFF_LSR);
149     regs->al = inb(addr+SEROFF_MSR);
150     set_success(regs);
151 }
152
153 static void
154 handle_14XX(struct bregs *regs)
155 {
156     set_unimplemented(regs);
157 }
158
159 // INT 14h Serial Communications Service Entry Point
160 void VISIBLE16
161 handle_14(struct bregs *regs)
162 {
163     debug_enter(regs, DEBUG_HDL_14);
164     if (! CONFIG_SERIAL) {
165         handle_14XX(regs);
166         return;
167     }
168
169     switch (regs->ah) {
170     case 0x00: handle_1400(regs); break;
171     case 0x01: handle_1401(regs); break;
172     case 0x02: handle_1402(regs); break;
173     case 0x03: handle_1403(regs); break;
174     default:   handle_14XX(regs); break;
175     }
176 }
177
178 // XXX - Baud Rate Generator Table
179 u8 BaudTable[16] VAR16FIXED(0xe729);
180
181
182 /****************************************************************
183  * LPT ports
184  ****************************************************************/
185
186 static u16
187 detect_parport(u16 port, u8 timeout, u8 count)
188 {
189     // clear input mode
190     outb(inb(port+2) & 0xdf, port+2);
191
192     outb(0xaa, port);
193     if (inb(port) != 0xaa)
194         // Not present
195         return 0;
196     SET_BDA(port_lpt[count], port);
197     SET_BDA(lpt_timeout[count], timeout);
198     return 1;
199 }
200
201 void
202 lpt_setup(void)
203 {
204     if (! CONFIG_LPT)
205         return;
206     dprintf(3, "init lpt\n");
207
208     u16 count = 0;
209     count += detect_parport(PORT_LPT1, 0x14, count);
210     count += detect_parport(PORT_LPT2, 0x14, count);
211     dprintf(1, "Found %d lpt ports\n", count);
212
213     // Equipment word bits 14..15 determing # parallel ports
214     u16 eqb = GET_BDA(equipment_list_flags);
215     SET_BDA(equipment_list_flags, (eqb & 0x3fff) | (count << 14));
216 }
217
218 static u16
219 getLptAddr(struct bregs *regs)
220 {
221     if (regs->dx >= 3) {
222         set_invalid(regs);
223         return 0;
224     }
225     u16 addr = GET_BDA(port_lpt[regs->dx]);
226     if (! addr)
227         set_invalid(regs);
228     return addr;
229 }
230
231 // INT 17 - PRINTER - WRITE CHARACTER
232 static void
233 handle_1700(struct bregs *regs)
234 {
235     u16 addr = getLptAddr(regs);
236     if (!addr)
237         return;
238
239     u32 end = calc_future_timer_ticks(GET_BDA(lpt_timeout[regs->dx]));
240
241     outb(regs->al, addr);
242     u8 val8 = inb(addr+2);
243     outb(val8 | 0x01, addr+2); // send strobe
244     udelay(5);
245     outb(val8 & ~0x01, addr+2);
246
247     for (;;) {
248         u8 v = inb(addr+1);
249         if (!(v & 0x40)) {
250             // Success
251             regs->ah = v ^ 0x48;
252             break;
253         }
254         if (check_timer(end)) {
255             // Timeout
256             regs->ah = (v ^ 0x48) | 0x01;
257             break;
258         }
259         yield();
260     }
261
262     set_success(regs);
263 }
264
265 // INT 17 - PRINTER - INITIALIZE PORT
266 static void
267 handle_1701(struct bregs *regs)
268 {
269     u16 addr = getLptAddr(regs);
270     if (!addr)
271         return;
272
273     u8 val8 = inb(addr+2);
274     outb(val8 & ~0x04, addr+2); // send init
275     udelay(5);
276     outb(val8 | 0x04, addr+2);
277
278     regs->ah = inb(addr+1) ^ 0x48;
279     set_success(regs);
280 }
281
282 // INT 17 - PRINTER - GET STATUS
283 static void
284 handle_1702(struct bregs *regs)
285 {
286     u16 addr = getLptAddr(regs);
287     if (!addr)
288         return;
289     regs->ah = inb(addr+1) ^ 0x48;
290     set_success(regs);
291 }
292
293 static void
294 handle_17XX(struct bregs *regs)
295 {
296     set_unimplemented(regs);
297 }
298
299 // INT17h : Printer Service Entry Point
300 void VISIBLE16
301 handle_17(struct bregs *regs)
302 {
303     debug_enter(regs, DEBUG_HDL_17);
304     if (! CONFIG_LPT) {
305         handle_17XX(regs);
306         return;
307     }
308
309     switch (regs->ah) {
310     case 0x00: handle_1700(regs); break;
311     case 0x01: handle_1701(regs); break;
312     case 0x02: handle_1702(regs); break;
313     default:   handle_17XX(regs); break;
314     }
315 }