Extract 'struct bregs' out of biosvar.h; clean up header includes.
[seabios.git] / src / serial.c
1 // 16bit code to handle serial and printer services.
2 //
3 // Copyright (C) 2008  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 GPLv3 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+1);
21     if (inb(port+1) != 0x02)
22         return 0;
23     if (inb(port+2) != 0x02)
24         return 0;
25     outb(0x00, port+1);
26     SET_BDA(port_com[count], port);
27     SET_BDA(com_timeout[count], timeout);
28     return 1;
29 }
30
31 void
32 serial_setup()
33 {
34     dprintf(3, "init serial\n");
35     u16 count = 0;
36     count += detect_serial(0x3f8, 0x0a, count);
37     count += detect_serial(0x2f8, 0x0a, count);
38     count += detect_serial(0x3e8, 0x0a, count);
39     count += detect_serial(0x2e8, 0x0a, count);
40
41     // Equipment word bits 9..11 determing # serial ports
42     u16 eqb = GET_BDA(equipment_list_flags);
43     SET_BDA(equipment_list_flags, (eqb & 0xf1ff) | (count << 9));
44 }
45
46 static u16
47 getComAddr(struct bregs *regs)
48 {
49     if (regs->dx >= 4) {
50         set_fail(regs);
51         return 0;
52     }
53     u16 addr = GET_BDA(port_com[regs->dx]);
54     if (! addr)
55         set_fail(regs);
56     return addr;
57 }
58
59 // SERIAL - INITIALIZE PORT
60 static void
61 handle_1400(struct bregs *regs)
62 {
63     u16 addr = getComAddr(regs);
64     if (!addr)
65         return;
66     outb(inb(addr+3) | 0x80, addr+3);
67     if ((regs->al & 0xE0) == 0) {
68         outb(0x17, addr);
69         outb(0x04, addr+1);
70     } else {
71         u16 val16 = 0x600 >> ((regs->al & 0xE0) >> 5);
72         outb(val16 & 0xFF, addr);
73         outb(val16 >> 8, addr+1);
74     }
75     outb(regs->al & 0x1F, addr+3);
76     regs->ah = inb(addr+5);
77     regs->al = inb(addr+6);
78     set_success(regs);
79 }
80
81 // SERIAL - WRITE CHARACTER TO PORT
82 static void
83 handle_1401(struct bregs *regs)
84 {
85     u16 addr = getComAddr(regs);
86     if (!addr)
87         return;
88     u16 timer = GET_BDA(timer_counter);
89     u16 timeout = GET_BDA(com_timeout[regs->dx]);
90     while (((inb(addr+5) & 0x60) != 0x60) && (timeout)) {
91         u16 val16 = GET_BDA(timer_counter);
92         if (val16 != timer) {
93             timer = val16;
94             timeout--;
95         }
96     }
97     if (timeout)
98         outb(regs->al, addr);
99     regs->ah = inb(addr+5);
100     if (!timeout)
101         regs->ah |= 0x80;
102     set_success(regs);
103 }
104
105 // SERIAL - READ CHARACTER FROM PORT
106 static void
107 handle_1402(struct bregs *regs)
108 {
109     u16 addr = getComAddr(regs);
110     if (!addr)
111         return;
112     u16 timer = GET_BDA(timer_counter);
113     u16 timeout = GET_BDA(com_timeout[regs->dx]);
114     while (((inb(addr+5) & 0x01) == 0) && (timeout)) {
115         u16 val16 = GET_BDA(timer_counter);
116         if (val16 != timer) {
117             timer = val16;
118             timeout--;
119         }
120     }
121     if (timeout) {
122         regs->ah = 0;
123         regs->al = inb(addr);
124     } else {
125         regs->ah = inb(addr+5);
126     }
127     set_success(regs);
128 }
129
130 // SERIAL - GET PORT STATUS
131 static void
132 handle_1403(struct bregs *regs)
133 {
134     u16 addr = getComAddr(regs);
135     if (!addr)
136         return;
137     regs->ah = inb(addr+5);
138     regs->al = inb(addr+6);
139     set_success(regs);
140 }
141
142 static void
143 handle_14XX(struct bregs *regs)
144 {
145     // Unsupported
146     set_fail(regs);
147 }
148
149 // INT 14h Serial Communications Service Entry Point
150 void VISIBLE16
151 handle_14(struct bregs *regs)
152 {
153     debug_enter(regs, DEBUG_HDL_14);
154
155     irq_enable();
156
157     switch (regs->ah) {
158     case 0x00: handle_1400(regs); break;
159     case 0x01: handle_1401(regs); break;
160     case 0x02: handle_1402(regs); break;
161     case 0x03: handle_1403(regs); break;
162     default:   handle_14XX(regs); break;
163     }
164 }
165
166
167 /****************************************************************
168  * LPT ports
169  ****************************************************************/
170
171 static u16
172 detect_parport(u16 port, u8 timeout, u8 count)
173 {
174     // clear input mode
175     outb(inb(port+2) & 0xdf, port+2);
176
177     outb(0xaa, port);
178     if (inb(port) != 0xaa)
179         // Not present
180         return 0;
181     SET_BDA(port_lpt[count], port);
182     SET_BDA(lpt_timeout[count], timeout);
183     return 1;
184 }
185
186 void
187 lpt_setup()
188 {
189     dprintf(3, "init lpt\n");
190     u16 count = 0;
191     count += detect_parport(0x378, 0x14, count);
192     count += detect_parport(0x278, 0x14, count);
193
194     // Equipment word bits 14..15 determing # parallel ports
195     u16 eqb = GET_BDA(equipment_list_flags);
196     SET_BDA(equipment_list_flags, (eqb & 0x3fff) | (count << 14));
197 }
198
199 static u16
200 getLptAddr(struct bregs *regs)
201 {
202     if (regs->dx >= 3) {
203         set_fail(regs);
204         return 0;
205     }
206     u16 addr = GET_BDA(port_lpt[regs->dx]);
207     if (! addr)
208         set_fail(regs);
209     return addr;
210 }
211
212 static void
213 lpt_ret(struct bregs *regs, u16 addr, u16 timeout)
214 {
215     u8 val8 = inb(addr+1);
216     regs->ah = (val8 ^ 0x48);
217     if (!timeout)
218         regs->ah |= 0x01;
219     set_success(regs);
220 }
221
222 // INT 17 - PRINTER - WRITE CHARACTER
223 static void
224 handle_1700(struct bregs *regs)
225 {
226     u16 addr = getLptAddr(regs);
227     if (!addr)
228         return;
229     u16 timeout = GET_BDA(lpt_timeout[regs->dx]) << 8;
230
231     outb(regs->al, addr);
232     u8 val8 = inb(addr+2);
233     outb(val8 | 0x01, addr+2); // send strobe
234     nop();
235     outb(val8 & ~0x01, addr+2);
236     while (((inb(addr+1) & 0x40) == 0x40) && (timeout))
237         timeout--;
238
239     lpt_ret(regs, addr, timeout);
240 }
241
242 // INT 17 - PRINTER - INITIALIZE PORT
243 static void
244 handle_1701(struct bregs *regs)
245 {
246     u16 addr = getLptAddr(regs);
247     if (!addr)
248         return;
249     u16 timeout = GET_BDA(lpt_timeout[regs->dx]) << 8;
250
251     u8 val8 = inb(addr+2);
252     outb(val8 & ~0x04, addr+2); // send init
253     nop();
254     outb(val8 | 0x04, addr+2);
255
256     lpt_ret(regs, addr, timeout);
257 }
258
259 // INT 17 - PRINTER - GET STATUS
260 static void
261 handle_1702(struct bregs *regs)
262 {
263     u16 addr = getLptAddr(regs);
264     if (!addr)
265         return;
266     u16 timeout = GET_BDA(lpt_timeout[regs->dx]) << 8;
267
268     lpt_ret(regs, addr, timeout);
269 }
270
271 static void
272 handle_17XX(struct bregs *regs)
273 {
274     // Unsupported
275     set_fail(regs);
276 }
277
278 // INT17h : Printer Service Entry Point
279 void VISIBLE16
280 handle_17(struct bregs *regs)
281 {
282     debug_enter(regs, DEBUG_HDL_17);
283
284     irq_enable();
285
286     switch (regs->ah) {
287     case 0x00: handle_1700(regs); break;
288     case 0x01: handle_1701(regs); break;
289     case 0x02: handle_1702(regs); break;
290     default:   handle_17XX(regs); break;
291     }
292 }