Commit | Line | Data |
---|---|---|
a09e091a JB |
1 | /* |
2 | * XFree86 int10 module | |
3 | * execute BIOS int 10h calls in x86 real mode environment | |
4 | * Copyright 1999 Egbert Eich | |
5 | * | |
6 | * Part of this code was inspired by the VBIOS POSTing code in DOSEMU | |
7 | * developed by the "DOSEMU-Development-Team" | |
8 | */ | |
9 | ||
10 | /* | |
11 | * To debug port accesses define PRINT_PORT to 1. | |
12 | * Note! You also have to comment out ioperm() | |
13 | * in xf86EnableIO(). Otherwise we won't trap | |
14 | * on PIO. | |
15 | */ | |
16 | ||
17 | #ifdef HAVE_XORG_CONFIG_H | |
18 | #include <xorg-config.h> | |
19 | #endif | |
20 | ||
21 | #define PRINT_PORT 0 | |
22 | ||
23 | #include <unistd.h> | |
24 | ||
25 | #include <X11/Xos.h> | |
26 | #include "xf86.h" | |
27 | #include "xf86_OSproc.h" | |
28 | #include "compiler.h" | |
29 | #define _INT10_PRIVATE | |
30 | #include "int10Defines.h" | |
31 | #include "xf86int10.h" | |
32 | #include "Pci.h" | |
33 | #ifdef _X86EMU | |
34 | #include "x86emu/x86emui.h" | |
35 | #else | |
36 | #define DEBUG_IO_TRACE() 0 | |
37 | #endif | |
38 | #include <pciaccess.h> | |
39 | ||
40 | static int pciCfg1in(CARD16 addr, CARD32 *val); | |
41 | static int pciCfg1out(CARD16 addr, CARD32 val); | |
42 | static int pciCfg1inw(CARD16 addr, CARD16 *val); | |
43 | static int pciCfg1outw(CARD16 addr, CARD16 val); | |
44 | static int pciCfg1inb(CARD16 addr, CARD8 *val); | |
45 | static int pciCfg1outb(CARD16 addr, CARD8 val); | |
46 | ||
47 | #if defined (_PC) | |
48 | static void SetResetBIOSVars(xf86Int10InfoPtr pInt, Bool set); | |
49 | #endif | |
50 | ||
51 | #define REG pInt | |
52 | ||
53 | int | |
54 | setup_int(xf86Int10InfoPtr pInt) | |
55 | { | |
56 | if (pInt != Int10Current) { | |
57 | if (!MapCurrentInt10(pInt)) | |
58 | return -1; | |
59 | Int10Current = pInt; | |
60 | } | |
61 | X86_EAX = (CARD32) pInt->ax; | |
62 | X86_EBX = (CARD32) pInt->bx; | |
63 | X86_ECX = (CARD32) pInt->cx; | |
64 | X86_EDX = (CARD32) pInt->dx; | |
65 | X86_ESI = (CARD32) pInt->si; | |
66 | X86_EDI = (CARD32) pInt->di; | |
67 | X86_EBP = (CARD32) pInt->bp; | |
68 | X86_ESP = 0x1000; | |
69 | X86_SS = pInt->stackseg >> 4; | |
70 | X86_EIP = 0x0600; | |
71 | X86_CS = 0x0; /* address of 'hlt' */ | |
72 | X86_DS = 0x40; /* standard pc ds */ | |
73 | X86_ES = pInt->es; | |
74 | X86_FS = 0; | |
75 | X86_GS = 0; | |
76 | X86_EFLAGS = X86_IF_MASK | X86_IOPL_MASK; | |
77 | #if defined (_PC) | |
78 | if (pInt->Flags & SET_BIOS_SCRATCH) | |
79 | SetResetBIOSVars(pInt, TRUE); | |
80 | #endif | |
81 | OsBlockSignals(); | |
82 | return 0; | |
83 | } | |
84 | ||
85 | void | |
86 | finish_int(xf86Int10InfoPtr pInt, int sig) | |
87 | { | |
88 | OsReleaseSignals(); | |
89 | pInt->ax = (CARD32) X86_EAX; | |
90 | pInt->bx = (CARD32) X86_EBX; | |
91 | pInt->cx = (CARD32) X86_ECX; | |
92 | pInt->dx = (CARD32) X86_EDX; | |
93 | pInt->si = (CARD32) X86_ESI; | |
94 | pInt->di = (CARD32) X86_EDI; | |
95 | pInt->es = (CARD16) X86_ES; | |
96 | pInt->bp = (CARD32) X86_EBP; | |
97 | pInt->flags = (CARD32) X86_FLAGS; | |
98 | #if defined (_PC) | |
99 | if (pInt->Flags & RESTORE_BIOS_SCRATCH) | |
100 | SetResetBIOSVars(pInt, FALSE); | |
101 | #endif | |
102 | } | |
103 | ||
104 | /* general software interrupt handler */ | |
105 | CARD32 | |
106 | getIntVect(xf86Int10InfoPtr pInt, int num) | |
107 | { | |
108 | return MEM_RW(pInt, num << 2) + (MEM_RW(pInt, (num << 2) + 2) << 4); | |
109 | } | |
110 | ||
111 | void | |
112 | pushw(xf86Int10InfoPtr pInt, CARD16 val) | |
113 | { | |
114 | X86_ESP -= 2; | |
115 | MEM_WW(pInt, ((CARD32) X86_SS << 4) + X86_SP, val); | |
116 | } | |
117 | ||
118 | int | |
119 | run_bios_int(int num, xf86Int10InfoPtr pInt) | |
120 | { | |
121 | CARD32 eflags; | |
122 | ||
123 | #ifndef _PC | |
124 | /* check if bios vector is initialized */ | |
125 | if (MEM_RW(pInt, (num << 2) + 2) == (SYS_BIOS >> 4)) { /* SYS_BIOS_SEG ? */ | |
126 | ||
127 | if (num == 21 && X86_AH == 0x4e) { | |
128 | xf86DrvMsg(pInt->pScrn->scrnIndex, X_NOTICE, | |
129 | "Failing Find-Matching-File on non-PC" | |
130 | " (int 21, func 4e)\n"); | |
131 | X86_AX = 2; | |
132 | SET_FLAG(F_CF); | |
133 | return 1; | |
134 | } | |
135 | else { | |
136 | xf86DrvMsgVerb(pInt->pScrn->scrnIndex, X_NOT_IMPLEMENTED, 2, | |
137 | "Ignoring int 0x%02x call\n", num); | |
138 | if (xf86GetVerbosity() > 3) { | |
139 | dump_registers(pInt); | |
140 | stack_trace(pInt); | |
141 | } | |
142 | return 1; | |
143 | } | |
144 | } | |
145 | #endif | |
146 | #ifdef PRINT_INT | |
147 | ErrorF("calling card BIOS at: "); | |
148 | #endif | |
149 | eflags = X86_EFLAGS; | |
150 | #if 0 | |
151 | eflags = eflags | IF_MASK; | |
152 | X86_EFLAGS = X86_EFLAGS & ~(VIF_MASK | TF_MASK | IF_MASK | NT_MASK); | |
153 | #endif | |
154 | pushw(pInt, eflags); | |
155 | pushw(pInt, X86_CS); | |
156 | pushw(pInt, X86_IP); | |
157 | X86_CS = MEM_RW(pInt, (num << 2) + 2); | |
158 | X86_IP = MEM_RW(pInt, num << 2); | |
159 | #ifdef PRINT_INT | |
160 | ErrorF("0x%x:%lx\n", X86_CS, X86_EIP); | |
161 | #endif | |
162 | return 1; | |
163 | } | |
164 | ||
165 | /* Debugging stuff */ | |
166 | void | |
167 | dump_code(xf86Int10InfoPtr pInt) | |
168 | { | |
169 | int i; | |
170 | CARD32 lina = SEG_ADR((CARD32), X86_CS, IP); | |
171 | ||
172 | xf86DrvMsgVerb(pInt->pScrn->scrnIndex, X_INFO, 3, "code at 0x%8.8" PRIx32 ":\n", | |
173 | lina); | |
174 | for (i = 0; i < 0x10; i++) | |
175 | xf86ErrorFVerb(3, " %2.2x", MEM_RB(pInt, lina + i)); | |
176 | xf86ErrorFVerb(3, "\n"); | |
177 | for (; i < 0x20; i++) | |
178 | xf86ErrorFVerb(3, " %2.2x", MEM_RB(pInt, lina + i)); | |
179 | xf86ErrorFVerb(3, "\n"); | |
180 | } | |
181 | ||
182 | void | |
183 | dump_registers(xf86Int10InfoPtr pInt) | |
184 | { | |
185 | xf86DrvMsgVerb(pInt->pScrn->scrnIndex, X_INFO, 3, | |
186 | "EAX=0x%8.8lx, EBX=0x%8.8lx, ECX=0x%8.8lx, EDX=0x%8.8lx\n", | |
187 | (unsigned long) X86_EAX, (unsigned long) X86_EBX, | |
188 | (unsigned long) X86_ECX, (unsigned long) X86_EDX); | |
189 | xf86DrvMsgVerb(pInt->pScrn->scrnIndex, X_INFO, 3, | |
190 | "ESP=0x%8.8lx, EBP=0x%8.8lx, ESI=0x%8.8lx, EDI=0x%8.8lx\n", | |
191 | (unsigned long) X86_ESP, (unsigned long) X86_EBP, | |
192 | (unsigned long) X86_ESI, (unsigned long) X86_EDI); | |
193 | xf86DrvMsgVerb(pInt->pScrn->scrnIndex, X_INFO, 3, | |
194 | "CS=0x%4.4x, SS=0x%4.4x," | |
195 | " DS=0x%4.4x, ES=0x%4.4x, FS=0x%4.4x, GS=0x%4.4x\n", | |
196 | X86_CS, X86_SS, X86_DS, X86_ES, X86_FS, X86_GS); | |
197 | xf86DrvMsgVerb(pInt->pScrn->scrnIndex, X_INFO, 3, | |
198 | "EIP=0x%8.8lx, EFLAGS=0x%8.8lx\n", | |
199 | (unsigned long) X86_EIP, (unsigned long) X86_EFLAGS); | |
200 | } | |
201 | ||
202 | void | |
203 | stack_trace(xf86Int10InfoPtr pInt) | |
204 | { | |
205 | int i = 0; | |
206 | unsigned long stack = SEG_ADR((CARD32), X86_SS, SP); | |
207 | unsigned long tail = (CARD32) ((X86_SS << 4) + 0x1000); | |
208 | ||
209 | if (stack >= tail) | |
210 | return; | |
211 | ||
212 | xf86MsgVerb(X_INFO, 3, "stack at 0x%8.8lx:\n", stack); | |
213 | for (; stack < tail; stack++) { | |
214 | xf86ErrorFVerb(3, " %2.2x", MEM_RB(pInt, stack)); | |
215 | i = (i + 1) % 0x10; | |
216 | if (!i) | |
217 | xf86ErrorFVerb(3, "\n"); | |
218 | } | |
219 | if (i) | |
220 | xf86ErrorFVerb(3, "\n"); | |
221 | } | |
222 | ||
223 | int | |
224 | port_rep_inb(xf86Int10InfoPtr pInt, | |
225 | CARD16 port, CARD32 base, int d_f, CARD32 count) | |
226 | { | |
227 | register int inc = d_f ? -1 : 1; | |
228 | CARD32 dst = base; | |
229 | ||
230 | if (PRINT_PORT && DEBUG_IO_TRACE()) | |
231 | ErrorF(" rep_insb(%#x) %" PRIu32 " bytes at %8.8" PRIx32 " %s\n", | |
232 | port, count, base, d_f ? "up" : "down"); | |
233 | while (count--) { | |
234 | MEM_WB(pInt, dst, x_inb(port)); | |
235 | dst += inc; | |
236 | } | |
237 | return dst - base; | |
238 | } | |
239 | ||
240 | int | |
241 | port_rep_inw(xf86Int10InfoPtr pInt, | |
242 | CARD16 port, CARD32 base, int d_f, CARD32 count) | |
243 | { | |
244 | register int inc = d_f ? -2 : 2; | |
245 | CARD32 dst = base; | |
246 | ||
247 | if (PRINT_PORT && DEBUG_IO_TRACE()) | |
248 | ErrorF(" rep_insw(%#x) %" PRIu32 " bytes at %8.8" PRIx32 " %s\n", | |
249 | port, count, base, d_f ? "up" : "down"); | |
250 | while (count--) { | |
251 | MEM_WW(pInt, dst, x_inw(port)); | |
252 | dst += inc; | |
253 | } | |
254 | return dst - base; | |
255 | } | |
256 | ||
257 | int | |
258 | port_rep_inl(xf86Int10InfoPtr pInt, | |
259 | CARD16 port, CARD32 base, int d_f, CARD32 count) | |
260 | { | |
261 | register int inc = d_f ? -4 : 4; | |
262 | CARD32 dst = base; | |
263 | ||
264 | if (PRINT_PORT && DEBUG_IO_TRACE()) | |
265 | ErrorF(" rep_insl(%#x) %" PRIu32 " bytes at %8.8" PRIx32 " %s\n", | |
266 | port, count, base, d_f ? "up" : "down"); | |
267 | while (count--) { | |
268 | MEM_WL(pInt, dst, x_inl(port)); | |
269 | dst += inc; | |
270 | } | |
271 | return dst - base; | |
272 | } | |
273 | ||
274 | int | |
275 | port_rep_outb(xf86Int10InfoPtr pInt, | |
276 | CARD16 port, CARD32 base, int d_f, CARD32 count) | |
277 | { | |
278 | register int inc = d_f ? -1 : 1; | |
279 | CARD32 dst = base; | |
280 | ||
281 | if (PRINT_PORT && DEBUG_IO_TRACE()) | |
282 | ErrorF(" rep_outb(%#x) %" PRIu32 " bytes at %8.8" PRIx32 " %s\n", | |
283 | port, count, base, d_f ? "up" : "down"); | |
284 | while (count--) { | |
285 | x_outb(port, MEM_RB(pInt, dst)); | |
286 | dst += inc; | |
287 | } | |
288 | return dst - base; | |
289 | } | |
290 | ||
291 | int | |
292 | port_rep_outw(xf86Int10InfoPtr pInt, | |
293 | CARD16 port, CARD32 base, int d_f, CARD32 count) | |
294 | { | |
295 | register int inc = d_f ? -2 : 2; | |
296 | CARD32 dst = base; | |
297 | ||
298 | if (PRINT_PORT && DEBUG_IO_TRACE()) | |
299 | ErrorF(" rep_outw(%#x) %" PRIu32 " bytes at %8.8" PRIx32 " %s\n", | |
300 | port, count, base, d_f ? "up" : "down"); | |
301 | while (count--) { | |
302 | x_outw(port, MEM_RW(pInt, dst)); | |
303 | dst += inc; | |
304 | } | |
305 | return dst - base; | |
306 | } | |
307 | ||
308 | int | |
309 | port_rep_outl(xf86Int10InfoPtr pInt, | |
310 | CARD16 port, CARD32 base, int d_f, CARD32 count) | |
311 | { | |
312 | register int inc = d_f ? -4 : 4; | |
313 | CARD32 dst = base; | |
314 | ||
315 | if (PRINT_PORT && DEBUG_IO_TRACE()) | |
316 | ErrorF(" rep_outl(%#x) %" PRIu32 " bytes at %8.8" PRIx32 " %s\n", | |
317 | port, count, base, d_f ? "up" : "down"); | |
318 | while (count--) { | |
319 | x_outl(port, MEM_RL(pInt, dst)); | |
320 | dst += inc; | |
321 | } | |
322 | return dst - base; | |
323 | } | |
324 | ||
325 | CARD8 | |
326 | x_inb(CARD16 port) | |
327 | { | |
328 | CARD8 val; | |
329 | ||
330 | if (port == 0x40) { | |
331 | Int10Current->inb40time++; | |
332 | val = (CARD8) (Int10Current->inb40time >> | |
333 | ((Int10Current->inb40time & 1) << 3)); | |
334 | if (PRINT_PORT && DEBUG_IO_TRACE()) | |
335 | ErrorF(" inb(%#x) = %2.2x\n", port, val); | |
336 | #ifdef __NOT_YET__ | |
337 | } | |
338 | else if (port < 0x0100) { /* Don't interfere with mainboard */ | |
339 | val = 0; | |
340 | xf86DrvMsgVerb(Int10Current->pScrn->scrnIndex, X_NOT_IMPLEMENTED, 2, | |
341 | "inb 0x%4.4x\n", port); | |
342 | if (xf86GetVerbosity() > 3) { | |
343 | dump_registers(Int10Current); | |
344 | stack_trace(Int10Current); | |
345 | } | |
346 | #endif /* __NOT_YET__ */ | |
347 | } | |
348 | else if (!pciCfg1inb(port, &val)) { | |
349 | val = pci_io_read8(Int10Current->io, port); | |
350 | if (PRINT_PORT && DEBUG_IO_TRACE()) | |
351 | ErrorF(" inb(%#x) = %2.2x\n", port, val); | |
352 | } | |
353 | return val; | |
354 | } | |
355 | ||
356 | CARD16 | |
357 | x_inw(CARD16 port) | |
358 | { | |
359 | CARD16 val; | |
360 | ||
361 | if (port == 0x5c) { | |
362 | struct timeval tv; | |
363 | ||
364 | /* | |
365 | * Emulate a PC's timer. Typical resolution is 3.26 usec. | |
366 | * Approximate this by dividing by 3. | |
367 | */ | |
368 | X_GETTIMEOFDAY(&tv); | |
369 | val = (CARD16) (tv.tv_usec / 3); | |
370 | } | |
371 | else if (!pciCfg1inw(port, &val)) { | |
372 | val = pci_io_read16(Int10Current->io, port); | |
373 | if (PRINT_PORT && DEBUG_IO_TRACE()) | |
374 | ErrorF(" inw(%#x) = %4.4x\n", port, val); | |
375 | } | |
376 | return val; | |
377 | } | |
378 | ||
379 | void | |
380 | x_outb(CARD16 port, CARD8 val) | |
381 | { | |
382 | if ((port == 0x43) && (val == 0)) { | |
383 | struct timeval tv; | |
384 | ||
385 | /* | |
386 | * Emulate a PC's timer 0. Such timers typically have a resolution of | |
387 | * some .838 usec per tick, but this can only provide 1 usec per tick. | |
388 | * (Not that this matters much, given inherent emulation delays.) Use | |
389 | * the bottom bit as a byte select. See inb(0x40) above. | |
390 | */ | |
391 | X_GETTIMEOFDAY(&tv); | |
392 | Int10Current->inb40time = (CARD16) (tv.tv_usec | 1); | |
393 | if (PRINT_PORT && DEBUG_IO_TRACE()) | |
394 | ErrorF(" outb(%#x, %2.2x)\n", port, val); | |
395 | #ifdef __NOT_YET__ | |
396 | } | |
397 | else if (port < 0x0100) { /* Don't interfere with mainboard */ | |
398 | xf86DrvMsgVerb(Int10Current->pScrn->scrnIndex, X_NOT_IMPLEMENTED, 2, | |
399 | "outb 0x%4.4x,0x%2.2x\n", port, val); | |
400 | if (xf86GetVerbosity() > 3) { | |
401 | dump_registers(Int10Current); | |
402 | stack_trace(Int10Current); | |
403 | } | |
404 | #endif /* __NOT_YET__ */ | |
405 | } | |
406 | else if (!pciCfg1outb(port, val)) { | |
407 | if (PRINT_PORT && DEBUG_IO_TRACE()) | |
408 | ErrorF(" outb(%#x, %2.2x)\n", port, val); | |
409 | pci_io_write8(Int10Current->io, port, val); | |
410 | } | |
411 | } | |
412 | ||
413 | void | |
414 | x_outw(CARD16 port, CARD16 val) | |
415 | { | |
416 | ||
417 | if (!pciCfg1outw(port, val)) { | |
418 | if (PRINT_PORT && DEBUG_IO_TRACE()) | |
419 | ErrorF(" outw(%#x, %4.4x)\n", port, val); | |
420 | pci_io_write16(Int10Current->io, port, val); | |
421 | } | |
422 | } | |
423 | ||
424 | CARD32 | |
425 | x_inl(CARD16 port) | |
426 | { | |
427 | CARD32 val; | |
428 | ||
429 | if (!pciCfg1in(port, &val)) { | |
430 | val = pci_io_read32(Int10Current->io, port); | |
431 | if (PRINT_PORT && DEBUG_IO_TRACE()) | |
432 | ErrorF(" inl(%#x) = %8.8" PRIx32 "\n", port, val); | |
433 | } | |
434 | return val; | |
435 | } | |
436 | ||
437 | void | |
438 | x_outl(CARD16 port, CARD32 val) | |
439 | { | |
440 | if (!pciCfg1out(port, val)) { | |
441 | if (PRINT_PORT && DEBUG_IO_TRACE()) | |
442 | ErrorF(" outl(%#x, %8.8" PRIx32 ")\n", port, val); | |
443 | pci_io_write32(Int10Current->io, port, val); | |
444 | } | |
445 | } | |
446 | ||
447 | CARD8 | |
448 | Mem_rb(CARD32 addr) | |
449 | { | |
450 | return (*Int10Current->mem->rb) (Int10Current, addr); | |
451 | } | |
452 | ||
453 | CARD16 | |
454 | Mem_rw(CARD32 addr) | |
455 | { | |
456 | return (*Int10Current->mem->rw) (Int10Current, addr); | |
457 | } | |
458 | ||
459 | CARD32 | |
460 | Mem_rl(CARD32 addr) | |
461 | { | |
462 | return (*Int10Current->mem->rl) (Int10Current, addr); | |
463 | } | |
464 | ||
465 | void | |
466 | Mem_wb(CARD32 addr, CARD8 val) | |
467 | { | |
468 | (*Int10Current->mem->wb) (Int10Current, addr, val); | |
469 | } | |
470 | ||
471 | void | |
472 | Mem_ww(CARD32 addr, CARD16 val) | |
473 | { | |
474 | (*Int10Current->mem->ww) (Int10Current, addr, val); | |
475 | } | |
476 | ||
477 | void | |
478 | Mem_wl(CARD32 addr, CARD32 val) | |
479 | { | |
480 | (*Int10Current->mem->wl) (Int10Current, addr, val); | |
481 | } | |
482 | ||
483 | static CARD32 PciCfg1Addr = 0; | |
484 | ||
485 | #define PCI_DOM_FROM_TAG(tag) (((tag) >> 24) & (PCI_DOM_MASK)) | |
486 | #define PCI_BUS_FROM_TAG(tag) (((tag) >> 16) & (PCI_DOMBUS_MASK)) | |
487 | #define PCI_DEV_FROM_TAG(tag) (((tag) & 0x0000f800u) >> 11) | |
488 | #define PCI_FUNC_FROM_TAG(tag) (((tag) & 0x00000700u) >> 8) | |
489 | ||
490 | #define PCI_OFFSET(x) ((x) & 0x000000ff) | |
491 | #define PCI_TAG(x) ((x) & 0x7fffff00) | |
492 | ||
493 | static struct pci_device * | |
494 | pci_device_for_cfg_address(CARD32 addr) | |
495 | { | |
496 | struct pci_device *dev = NULL; | |
497 | CARD32 tag = PCI_TAG(addr); | |
498 | ||
499 | struct pci_slot_match slot_match = { | |
500 | .domain = PCI_DOM_FROM_TAG(tag), | |
501 | .bus = PCI_BUS_NO_DOMAIN(PCI_BUS_FROM_TAG(tag)), | |
502 | .dev = PCI_DEV_FROM_TAG(tag), | |
503 | .func = PCI_FUNC_FROM_TAG(tag), | |
504 | .match_data = 0 | |
505 | }; | |
506 | ||
507 | struct pci_device_iterator *iter = | |
508 | pci_slot_match_iterator_create(&slot_match); | |
509 | ||
510 | if (iter) | |
511 | dev = pci_device_next(iter); | |
512 | ||
513 | pci_iterator_destroy(iter); | |
514 | ||
515 | return dev; | |
516 | } | |
517 | ||
518 | static int | |
519 | pciCfg1in(CARD16 addr, CARD32 *val) | |
520 | { | |
521 | if (addr == 0xCF8) { | |
522 | *val = PciCfg1Addr; | |
523 | return 1; | |
524 | } | |
525 | if (addr == 0xCFC) { | |
526 | pci_device_cfg_read_u32(pci_device_for_cfg_address(PciCfg1Addr), | |
527 | (uint32_t *) val, PCI_OFFSET(PciCfg1Addr)); | |
528 | if (PRINT_PORT && DEBUG_IO_TRACE()) | |
529 | ErrorF(" cfg_inl(%#" PRIx32 ") = %8.8" PRIx32 "\n", PciCfg1Addr, | |
530 | *val); | |
531 | return 1; | |
532 | } | |
533 | return 0; | |
534 | } | |
535 | ||
536 | static int | |
537 | pciCfg1out(CARD16 addr, CARD32 val) | |
538 | { | |
539 | if (addr == 0xCF8) { | |
540 | PciCfg1Addr = val; | |
541 | return 1; | |
542 | } | |
543 | if (addr == 0xCFC) { | |
544 | if (PRINT_PORT && DEBUG_IO_TRACE()) | |
545 | ErrorF(" cfg_outl(%#" PRIx32 ", %8.8" PRIx32 ")\n", PciCfg1Addr, | |
546 | val); | |
547 | pci_device_cfg_write_u32(pci_device_for_cfg_address(PciCfg1Addr), val, | |
548 | PCI_OFFSET(PciCfg1Addr)); | |
549 | return 1; | |
550 | } | |
551 | return 0; | |
552 | } | |
553 | ||
554 | static int | |
555 | pciCfg1inw(CARD16 addr, CARD16 *val) | |
556 | { | |
557 | int shift; | |
558 | ||
559 | if ((addr >= 0xCF8) && (addr <= 0xCFB)) { | |
560 | shift = (addr - 0xCF8) * 8; | |
561 | *val = (PciCfg1Addr >> shift) & 0xffff; | |
562 | return 1; | |
563 | } | |
564 | if ((addr >= 0xCFC) && (addr <= 0xCFF)) { | |
565 | const unsigned offset = addr - 0xCFC; | |
566 | ||
567 | pci_device_cfg_read_u16(pci_device_for_cfg_address(PciCfg1Addr), | |
568 | val, PCI_OFFSET(PciCfg1Addr) + offset); | |
569 | if (PRINT_PORT && DEBUG_IO_TRACE()) | |
570 | ErrorF(" cfg_inw(%#" PRIx32 ") = %4.4x\n", PciCfg1Addr + offset, | |
571 | *val); | |
572 | return 1; | |
573 | } | |
574 | return 0; | |
575 | } | |
576 | ||
577 | static int | |
578 | pciCfg1outw(CARD16 addr, CARD16 val) | |
579 | { | |
580 | int shift; | |
581 | ||
582 | if ((addr >= 0xCF8) && (addr <= 0xCFB)) { | |
583 | shift = (addr - 0xCF8) * 8; | |
584 | PciCfg1Addr &= ~(0xffff << shift); | |
585 | PciCfg1Addr |= ((CARD32) val) << shift; | |
586 | return 1; | |
587 | } | |
588 | if ((addr >= 0xCFC) && (addr <= 0xCFF)) { | |
589 | const unsigned offset = addr - 0xCFC; | |
590 | ||
591 | if (PRINT_PORT && DEBUG_IO_TRACE()) | |
592 | ErrorF(" cfg_outw(%#" PRIx32 ", %4.4x)\n", PciCfg1Addr + offset, | |
593 | val); | |
594 | pci_device_cfg_write_u16(pci_device_for_cfg_address(PciCfg1Addr), val, | |
595 | PCI_OFFSET(PciCfg1Addr) + offset); | |
596 | return 1; | |
597 | } | |
598 | return 0; | |
599 | } | |
600 | ||
601 | static int | |
602 | pciCfg1inb(CARD16 addr, CARD8 *val) | |
603 | { | |
604 | int shift; | |
605 | ||
606 | if ((addr >= 0xCF8) && (addr <= 0xCFB)) { | |
607 | shift = (addr - 0xCF8) * 8; | |
608 | *val = (PciCfg1Addr >> shift) & 0xff; | |
609 | return 1; | |
610 | } | |
611 | if ((addr >= 0xCFC) && (addr <= 0xCFF)) { | |
612 | const unsigned offset = addr - 0xCFC; | |
613 | ||
614 | pci_device_cfg_read_u8(pci_device_for_cfg_address(PciCfg1Addr), | |
615 | val, PCI_OFFSET(PciCfg1Addr) + offset); | |
616 | if (PRINT_PORT && DEBUG_IO_TRACE()) | |
617 | ErrorF(" cfg_inb(%#" PRIx32 ") = %2.2x\n", PciCfg1Addr + offset, | |
618 | *val); | |
619 | return 1; | |
620 | } | |
621 | return 0; | |
622 | } | |
623 | ||
624 | static int | |
625 | pciCfg1outb(CARD16 addr, CARD8 val) | |
626 | { | |
627 | int shift; | |
628 | ||
629 | if ((addr >= 0xCF8) && (addr <= 0xCFB)) { | |
630 | shift = (addr - 0xCF8) * 8; | |
631 | PciCfg1Addr &= ~(0xff << shift); | |
632 | PciCfg1Addr |= ((CARD32) val) << shift; | |
633 | return 1; | |
634 | } | |
635 | if ((addr >= 0xCFC) && (addr <= 0xCFF)) { | |
636 | const unsigned offset = addr - 0xCFC; | |
637 | ||
638 | if (PRINT_PORT && DEBUG_IO_TRACE()) | |
639 | ErrorF(" cfg_outb(%#" PRIx32 ", %2.2x)\n", PciCfg1Addr + offset, | |
640 | val); | |
641 | pci_device_cfg_write_u8(pci_device_for_cfg_address(PciCfg1Addr), val, | |
642 | PCI_OFFSET(PciCfg1Addr) + offset); | |
643 | return 1; | |
644 | } | |
645 | return 0; | |
646 | } | |
647 | ||
648 | CARD8 | |
649 | bios_checksum(const CARD8 *start, int size) | |
650 | { | |
651 | CARD8 sum = 0; | |
652 | ||
653 | while (size-- > 0) | |
654 | sum += *start++; | |
655 | return sum; | |
656 | } | |
657 | ||
658 | /* | |
659 | * Lock/Unlock legacy VGA. Some Bioses try to be very clever and make | |
660 | * an attempt to detect a legacy ISA card. If they find one they might | |
661 | * act very strange: for example they might configure the card as a | |
662 | * monochrome card. This might cause some drivers to choke. | |
663 | * To avoid this we attempt legacy VGA by writing to all know VGA | |
664 | * disable registers before we call the BIOS initialization and | |
665 | * restore the original values afterwards. In beween we hold our | |
666 | * breath. To get to a (possibly exising) ISA card need to disable | |
667 | * our current PCI card. | |
668 | */ | |
669 | /* | |
670 | * This is just for booting: we just want to catch pure | |
671 | * legacy vga therefore we don't worry about mmio etc. | |
672 | * This stuff should really go into vgaHW.c. However then | |
673 | * the driver would have to load the vga-module prior to | |
674 | * doing int10. | |
675 | */ | |
676 | void | |
677 | LockLegacyVGA(xf86Int10InfoPtr pInt, legacyVGAPtr vga) | |
678 | { | |
679 | vga->save_msr = pci_io_read8(pInt->io, 0x03CC); | |
680 | vga->save_vse = pci_io_read8(pInt->io, 0x03C3); | |
681 | #ifndef __ia64__ | |
682 | vga->save_46e8 = pci_io_read8(pInt->io, 0x46E8); | |
683 | #endif | |
684 | vga->save_pos102 = pci_io_read8(pInt->io, 0x0102); | |
685 | pci_io_write8(pInt->io, 0x03C2, ~(CARD8) 0x03 & vga->save_msr); | |
686 | pci_io_write8(pInt->io, 0x03C3, ~(CARD8) 0x01 & vga->save_vse); | |
687 | #ifndef __ia64__ | |
688 | pci_io_write8(pInt->io, 0x46E8, ~(CARD8) 0x08 & vga->save_46e8); | |
689 | #endif | |
690 | pci_io_write8(pInt->io, 0x0102, ~(CARD8) 0x01 & vga->save_pos102); | |
691 | } | |
692 | ||
693 | void | |
694 | UnlockLegacyVGA(xf86Int10InfoPtr pInt, legacyVGAPtr vga) | |
695 | { | |
696 | pci_io_write8(pInt->io, 0x0102, vga->save_pos102); | |
697 | #ifndef __ia64__ | |
698 | pci_io_write8(pInt->io, 0x46E8, vga->save_46e8); | |
699 | #endif | |
700 | pci_io_write8(pInt->io, 0x03C3, vga->save_vse); | |
701 | pci_io_write8(pInt->io, 0x03C2, vga->save_msr); | |
702 | } | |
703 | ||
704 | #if defined (_PC) | |
705 | static void | |
706 | SetResetBIOSVars(xf86Int10InfoPtr pInt, Bool set) | |
707 | { | |
708 | int pagesize = getpagesize(); | |
709 | unsigned char *base; | |
710 | int i; | |
711 | ||
712 | if (pci_device_map_legacy | |
713 | (pInt->dev, 0, pagesize, PCI_DEV_MAP_FLAG_WRITABLE, (void **) &base)) | |
714 | return; /* eek */ | |
715 | ||
716 | if (set) { | |
717 | for (i = BIOS_SCRATCH_OFF; i < BIOS_SCRATCH_END; i++) | |
718 | MEM_WW(pInt, i, *(base + i)); | |
719 | } | |
720 | else { | |
721 | for (i = BIOS_SCRATCH_OFF; i < BIOS_SCRATCH_END; i++) | |
722 | *(base + i) = MEM_RW(pInt, i); | |
723 | } | |
724 | ||
725 | pci_device_unmap_legacy(pInt->dev, base, pagesize); | |
726 | } | |
727 | ||
728 | void | |
729 | xf86Int10SaveRestoreBIOSVars(xf86Int10InfoPtr pInt, Bool save) | |
730 | { | |
731 | int pagesize = getpagesize(); | |
732 | unsigned char *base; | |
733 | int i; | |
734 | ||
735 | if (!xf86IsEntityPrimary(pInt->entityIndex) | |
736 | || (!save && !pInt->BIOSScratch)) | |
737 | return; | |
738 | ||
739 | if (pci_device_map_legacy | |
740 | (pInt->dev, 0, pagesize, PCI_DEV_MAP_FLAG_WRITABLE, (void **) &base)) | |
741 | return; /* eek */ | |
742 | ||
743 | base += BIOS_SCRATCH_OFF; | |
744 | if (save) { | |
745 | if ((pInt->BIOSScratch = xnfalloc(BIOS_SCRATCH_LEN))) | |
746 | for (i = 0; i < BIOS_SCRATCH_LEN; i++) | |
747 | *(((char *) pInt->BIOSScratch + i)) = *(base + i); | |
748 | } | |
749 | else { | |
750 | if (pInt->BIOSScratch) { | |
751 | for (i = 0; i < BIOS_SCRATCH_LEN; i++) | |
752 | *(base + i) = *(pInt->BIOSScratch + i); | |
753 | free(pInt->BIOSScratch); | |
754 | pInt->BIOSScratch = NULL; | |
755 | } | |
756 | } | |
757 | ||
758 | pci_device_unmap_legacy(pInt->dev, base - BIOS_SCRATCH_OFF, pagesize); | |
759 | } | |
760 | #endif | |
761 | ||
762 | xf86Int10InfoPtr | |
763 | xf86InitInt10(int entityIndex) | |
764 | { | |
765 | return xf86ExtendedInitInt10(entityIndex, 0); | |
766 | } |