Imported Upstream version 1.15.1
[deb_xorg-server.git] / hw / xfree86 / int10 / xf86int10.c
CommitLineData
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
7#ifdef HAVE_XORG_CONFIG_H
8#include <xorg-config.h>
9#endif
10
11#include "xf86.h"
12#include "compiler.h"
13#define _INT10_PRIVATE
14#include "xf86int10.h"
15#include "int10Defines.h"
16#include "Pci.h"
17
18#define REG pInt
19
20xf86Int10InfoPtr Int10Current = NULL;
21
22static int int1A_handler(xf86Int10InfoPtr pInt);
23
24#ifndef _PC
25static int int42_handler(xf86Int10InfoPtr pInt);
26#endif
27static int intE6_handler(xf86Int10InfoPtr pInt);
28static struct pci_device *findPci(xf86Int10InfoPtr pInt, unsigned short bx);
29static CARD32 pciSlotBX(const struct pci_device *pvp);
30
31int
32int_handler(xf86Int10InfoPtr pInt)
33{
34 int num = pInt->num;
35 int ret = 0;
36
37 switch (num) {
38#ifndef _PC
39 case 0x10:
40 case 0x42:
41 case 0x6D:
42 if (getIntVect(pInt, num) == I_S_DEFAULT_INT_VECT)
43 ret = int42_handler(pInt);
44 break;
45#endif
46 case 0x1A:
47 ret = int1A_handler(pInt);
48 break;
49 case 0xe6:
50 ret = intE6_handler(pInt);
51 break;
52 default:
53 break;
54 }
55
56 if (!ret)
57 ret = run_bios_int(num, pInt);
58
59 if (!ret) {
60 xf86DrvMsg(pInt->pScrn->scrnIndex, X_ERROR, "Halting on int 0x%2.2x!\n", num);
61 dump_registers(pInt);
62 stack_trace(pInt);
63 }
64
65 return ret;
66}
67
68#ifndef _PC
69/*
70 * This is derived from a number of PC system BIOS'es. The intent here is to
71 * provide very primitive video support, before an EGA/VGA BIOS installs its
72 * own interrupt vector. Here, "Ignored" calls should remain so. "Not
73 * Implemented" denotes functionality that can be implemented should the need
74 * arise. What are "Not Implemented" throughout are video memory accesses.
75 * Also, very little input validity checking is done here.
76 */
77static int
78int42_handler(xf86Int10InfoPtr pInt)
79{
80 switch (X86_AH) {
81 case 0x00:
82 /* Set Video Mode */
83 /* Enter: AL = video mode number */
84 /* Leave: Nothing */
85 /* Implemented (except for clearing the screen) */
86 { /* Localise */
87 unsigned int ioport;
88 int i;
89 CARD16 int1d, regvals, tmp;
90 CARD8 mode, cgamode, cgacolour;
91
92 /*
93 * Ignore all mode numbers but 0x00-0x13. Some systems also ignore
94 * 0x0B and 0x0C, but don't do that here.
95 */
96 if (X86_AL > 0x13)
97 break;
98
99 /*
100 * You didn't think that was really the mode set, did you? There
101 * are only so many slots in the video parameter table...
102 */
103 mode = X86_AL;
104 ioport = 0x03D4;
105 switch (MEM_RB(pInt, 0x0410) & 0x30) {
106 case 0x30: /* MDA */
107 mode = 0x07; /* Force mode to 0x07 */
108 ioport = 0x03B4;
109 break;
110 case 0x10: /* CGA 40x25 */
111 if (mode >= 0x07)
112 mode = 0x01;
113 break;
114 case 0x20: /* CGA 80x25 (MCGA?) */
115 if (mode >= 0x07)
116 mode = 0x03;
117 break;
118 case 0x00: /* EGA/VGA */
119 if (mode >= 0x07) /* Don't try MDA timings */
120 mode = 0x01; /* !?!?! */
121 break;
122 }
123
124 /* Locate data in video parameter table */
125 int1d = MEM_RW(pInt, 0x1d << 2);
126 regvals = ((mode >> 1) << 4) + int1d;
127 cgacolour = 0x30;
128 if (mode == 0x06) {
129 regvals -= 0x10;
130 cgacolour = 0x3F;
131 }
132
133 /** Update BIOS Data Area **/
134
135 /* Video mode */
136 MEM_WB(pInt, 0x0449, mode);
137
138 /* Columns */
139 tmp = MEM_RB(pInt, mode + int1d + 0x48);
140 MEM_WW(pInt, 0x044A, tmp);
141
142 /* Page length */
143 tmp = MEM_RW(pInt, (mode & 0x06) + int1d + 0x40);
144 MEM_WW(pInt, 0x044C, tmp);
145
146 /* Start Address */
147 MEM_WW(pInt, 0x044E, 0);
148
149 /* Cursor positions, one for each display page */
150 for (i = 0x0450; i < 0x0460; i += 2)
151 MEM_WW(pInt, i, 0);
152
153 /* Cursor start & end scanlines */
154 tmp = MEM_RB(pInt, regvals + 0x0B);
155 MEM_WB(pInt, 0x0460, tmp);
156 tmp = MEM_RB(pInt, regvals + 0x0A);
157 MEM_WB(pInt, 0x0461, tmp);
158
159 /* Current display page number */
160 MEM_WB(pInt, 0x0462, 0);
161
162 /* CRTC I/O address */
163 MEM_WW(pInt, 0x0463, ioport);
164
165 /* CGA Mode register value */
166 cgamode = MEM_RB(pInt, mode + int1d + 0x50);
167 MEM_WB(pInt, 0x0465, cgamode);
168
169 /* CGA Colour register value */
170 MEM_WB(pInt, 0x0466, cgacolour);
171
172 /* Rows */
173 MEM_WB(pInt, 0x0484, (25 - 1));
174
175 /* Program the mode */
176 pci_io_write8(pInt->io, ioport + 4, cgamode & 0x37); /* Turn off screen */
177 for (i = 0; i < 0x10; i++) {
178 tmp = MEM_RB(pInt, regvals + i);
179 pci_io_write8(pInt->io, ioport, i);
180 pci_io_write8(pInt->io, ioport + 1, tmp);
181 }
182 pci_io_write8(pInt->io, ioport + 5, cgacolour); /* Select colour mode */
183 pci_io_write8(pInt->io, ioport + 4, cgamode); /* Turn on screen */
184 }
185 break;
186
187 case 0x01:
188 /* Set Cursor Type */
189 /* Enter: CH = starting line for cursor */
190 /* CL = ending line for cursor */
191 /* Leave: Nothing */
192 /* Implemented */
193 { /* Localise */
194 unsigned int ioport = MEM_RW(pInt, 0x0463);
195
196 MEM_WB(pInt, 0x0460, X86_CL);
197 MEM_WB(pInt, 0x0461, X86_CH);
198
199 pci_io_write8(pInt->io, ioport, 0x0A);
200 pci_io_write8(pInt->io, ioport + 1, X86_CH);
201 pci_io_write8(pInt->io, ioport, 0x0B);
202 pci_io_write8(pInt->io, ioport + 1, X86_CL);
203 }
204 break;
205
206 case 0x02:
207 /* Set Cursor Position */
208 /* Enter: BH = display page number */
209 /* DH = row */
210 /* DL = column */
211 /* Leave: Nothing */
212 /* Implemented */
213 { /* Localise */
214 unsigned int ioport;
215 CARD16 offset;
216
217 MEM_WB(pInt, (X86_BH << 1) + 0x0450, X86_DL);
218 MEM_WB(pInt, (X86_BH << 1) + 0x0451, X86_DH);
219
220 if (X86_BH != MEM_RB(pInt, 0x0462))
221 break;
222
223 offset = (X86_DH * MEM_RW(pInt, 0x044A)) + X86_DL;
224 offset += MEM_RW(pInt, 0x044E) << 1;
225
226 ioport = MEM_RW(pInt, 0x0463);
227 pci_io_write8(pInt->io, ioport, 0x0E);
228 pci_io_write8(pInt->io, ioport + 1, offset >> 8);
229 pci_io_write8(pInt->io, ioport, 0x0F);
230 pci_io_write8(pInt->io, ioport + 1, offset & 0xFF);
231 }
232 break;
233
234 case 0x03:
235 /* Get Cursor Position */
236 /* Enter: BH = display page number */
237 /* Leave: CH = starting line for cursor */
238 /* CL = ending line for cursor */
239 /* DH = row */
240 /* DL = column */
241 /* Implemented */
242 { /* Localise */
243 X86_CL = MEM_RB(pInt, 0x0460);
244 X86_CH = MEM_RB(pInt, 0x0461);
245 X86_DL = MEM_RB(pInt, (X86_BH << 1) + 0x0450);
246 X86_DH = MEM_RB(pInt, (X86_BH << 1) + 0x0451);
247 }
248 break;
249
250 case 0x04:
251 /* Get Light Pen Position */
252 /* Enter: Nothing */
253 /* Leave: AH = 0x01 (down/triggered) or 0x00 (not) */
254 /* BX = pixel column */
255 /* CX = pixel row */
256 /* DH = character row */
257 /* DL = character column */
258 /* Not Implemented */
259 { /* Localise */
260 xf86DrvMsgVerb(pInt->pScrn->scrnIndex, X_NOT_IMPLEMENTED, 2,
261 "int 0x%2.2x(AH=0x04) -- Get Light Pen Position\n",
262 pInt->num);
263 if (xf86GetVerbosity() > 3) {
264 dump_registers(pInt);
265 stack_trace(pInt);
266 }
267 X86_AH = X86_BX = X86_CX = X86_DX = 0;
268 }
269 break;
270
271 case 0x05:
272 /* Set Display Page */
273 /* Enter: AL = display page number */
274 /* Leave: Nothing */
275 /* Implemented */
276 { /* Localise */
277 unsigned int ioport = MEM_RW(pInt, 0x0463);
278 CARD16 start;
279 CARD8 x, y;
280
281 /* Calculate new start address */
282 MEM_WB(pInt, 0x0462, X86_AL);
283 start = X86_AL * MEM_RW(pInt, 0x044C);
284 MEM_WW(pInt, 0x044E, start);
285 start <<= 1;
286
287 /* Update start address */
288 pci_io_write8(pInt->io, ioport, 0x0C);
289 pci_io_write8(pInt->io, ioport + 1, start >> 8);
290 pci_io_write8(pInt->io, ioport, 0x0D);
291 pci_io_write8(pInt->io, ioport + 1, start & 0xFF);
292
293 /* Switch cursor position */
294 y = MEM_RB(pInt, (X86_AL << 1) + 0x0450);
295 x = MEM_RB(pInt, (X86_AL << 1) + 0x0451);
296 start += (y * MEM_RW(pInt, 0x044A)) + x;
297
298 /* Update cursor position */
299 pci_io_write8(pInt->io, ioport, 0x0E);
300 pci_io_write8(pInt->io, ioport + 1, start >> 8);
301 pci_io_write8(pInt->io, ioport, 0x0F);
302 pci_io_write8(pInt->io, ioport + 1, start & 0xFF);
303 }
304 break;
305
306 case 0x06:
307 /* Initialise or Scroll Window Up */
308 /* Enter: AL = lines to scroll up */
309 /* BH = attribute for blank */
310 /* CH = upper y of window */
311 /* CL = left x of window */
312 /* DH = lower y of window */
313 /* DL = right x of window */
314 /* Leave: Nothing */
315 /* Not Implemented */
316 { /* Localise */
317 xf86DrvMsgVerb(pInt->pScrn->scrnIndex, X_NOT_IMPLEMENTED, 2,
318 "int 0x%2.2x(AH=0x06) -- Initialise or Scroll Window Up\n",
319 pInt->num);
320 xf86DrvMsgVerb(pInt->pScrn->scrnIndex, X_NOT_IMPLEMENTED, 3,
321 " AL=0x%2.2x, BH=0x%2.2x,"
322 " CH=0x%2.2x, CL=0x%2.2x, DH=0x%2.2x, DL=0x%2.2x\n",
323 X86_AL, X86_BH, X86_CH, X86_CL, X86_DH, X86_DL);
324 if (xf86GetVerbosity() > 3) {
325 dump_registers(pInt);
326 stack_trace(pInt);
327 }
328 }
329 break;
330
331 case 0x07:
332 /* Initialise or Scroll Window Down */
333 /* Enter: AL = lines to scroll down */
334 /* BH = attribute for blank */
335 /* CH = upper y of window */
336 /* CL = left x of window */
337 /* DH = lower y of window */
338 /* DL = right x of window */
339 /* Leave: Nothing */
340 /* Not Implemented */
341 { /* Localise */
342 xf86DrvMsgVerb(pInt->pScrn->scrnIndex, X_NOT_IMPLEMENTED, 2,
343 "int 0x%2.2x(AH=0x07) -- Initialise or Scroll Window Down\n",
344 pInt->num);
345 xf86DrvMsgVerb(pInt->pScrn->scrnIndex, X_NOT_IMPLEMENTED, 3,
346 " AL=0x%2.2x, BH=0x%2.2x,"
347 " CH=0x%2.2x, CL=0x%2.2x, DH=0x%2.2x, DL=0x%2.2x\n",
348 X86_AL, X86_BH, X86_CH, X86_CL, X86_DH, X86_DL);
349 if (xf86GetVerbosity() > 3) {
350 dump_registers(pInt);
351 stack_trace(pInt);
352 }
353 }
354 break;
355
356 case 0x08:
357 /* Read Character and Attribute at Cursor */
358 /* Enter: BH = display page number */
359 /* Leave: AH = attribute */
360 /* AL = character */
361 /* Not Implemented */
362 { /* Localise */
363 xf86DrvMsgVerb(pInt->pScrn->scrnIndex, X_NOT_IMPLEMENTED, 2,
364 "int 0x%2.2x(AH=0x08) -- Read Character and Attribute at"
365 " Cursor\n", pInt->num);
366 xf86DrvMsgVerb(pInt->pScrn->scrnIndex, X_NOT_IMPLEMENTED, 3,
367 "BH=0x%2.2x\n", X86_BH);
368 if (xf86GetVerbosity() > 3) {
369 dump_registers(pInt);
370 stack_trace(pInt);
371 }
372 X86_AX = 0;
373 }
374 break;
375
376 case 0x09:
377 /* Write Character and Attribute at Cursor */
378 /* Enter: AL = character */
379 /* BH = display page number */
380 /* BL = attribute (text) or colour (graphics) */
381 /* CX = replication count */
382 /* Leave: Nothing */
383 /* Not Implemented */
384 { /* Localise */
385 xf86DrvMsgVerb(pInt->pScrn->scrnIndex, X_NOT_IMPLEMENTED, 2,
386 "int 0x%2.2x(AH=0x09) -- Write Character and Attribute at"
387 " Cursor\n", pInt->num);
388 xf86DrvMsgVerb(pInt->pScrn->scrnIndex, X_NOT_IMPLEMENTED, 3,
389 "AL=0x%2.2x, BH=0x%2.2x, BL=0x%2.2x, CX=0x%4.4x\n",
390 X86_AL, X86_BH, X86_BL, X86_CX);
391 if (xf86GetVerbosity() > 3) {
392 dump_registers(pInt);
393 stack_trace(pInt);
394 }
395 }
396 break;
397
398 case 0x0a:
399 /* Write Character at Cursor */
400 /* Enter: AL = character */
401 /* BH = display page number */
402 /* BL = colour */
403 /* CX = replication count */
404 /* Leave: Nothing */
405 /* Not Implemented */
406 { /* Localise */
407 xf86DrvMsgVerb(pInt->pScrn->scrnIndex, X_NOT_IMPLEMENTED, 2,
408 "int 0x%2.2x(AH=0x0A) -- Write Character at Cursor\n",
409 pInt->num);
410 xf86DrvMsgVerb(pInt->pScrn->scrnIndex, X_NOT_IMPLEMENTED, 3,
411 "AL=0x%2.2x, BH=0x%2.2x, BL=0x%2.2x, CX=0x%4.4x\n",
412 X86_AL, X86_BH, X86_BL, X86_CX);
413 if (xf86GetVerbosity() > 3) {
414 dump_registers(pInt);
415 stack_trace(pInt);
416 }
417 }
418 break;
419
420 case 0x0b:
421 /* Set Palette, Background or Border */
422 /* Enter: BH = 0x00 or 0x01 */
423 /* BL = colour or palette (respectively) */
424 /* Leave: Nothing */
425 /* Implemented */
426 { /* Localise */
427 unsigned int ioport = MEM_RW(pInt, 0x0463) + 5;
428 CARD8 cgacolour = MEM_RB(pInt, 0x0466);
429
430 if (X86_BH) {
431 cgacolour &= 0xDF;
432 cgacolour |= (X86_BL & 0x01) << 5;
433 }
434 else {
435 cgacolour &= 0xE0;
436 cgacolour |= X86_BL & 0x1F;
437 }
438
439 MEM_WB(pInt, 0x0466, cgacolour);
440 pci_io_write8(pInt->io, ioport, cgacolour);
441 }
442 break;
443
444 case 0x0c:
445 /* Write Graphics Pixel */
446 /* Enter: AL = pixel value */
447 /* BH = display page number */
448 /* CX = column */
449 /* DX = row */
450 /* Leave: Nothing */
451 /* Not Implemented */
452 { /* Localise */
453 xf86DrvMsgVerb(pInt->pScrn->scrnIndex, X_NOT_IMPLEMENTED, 2,
454 "int 0x%2.2x(AH=0x0C) -- Write Graphics Pixel\n",
455 pInt->num);
456 xf86DrvMsgVerb(pInt->pScrn->scrnIndex, X_NOT_IMPLEMENTED, 3,
457 "AL=0x%2.2x, BH=0x%2.2x, CX=0x%4.4x, DX=0x%4.4x\n",
458 X86_AL, X86_BH, X86_CX, X86_DX);
459 if (xf86GetVerbosity() > 3) {
460 dump_registers(pInt);
461 stack_trace(pInt);
462 }
463 }
464 break;
465
466 case 0x0d:
467 /* Read Graphics Pixel */
468 /* Enter: BH = display page number */
469 /* CX = column */
470 /* DX = row */
471 /* Leave: AL = pixel value */
472 /* Not Implemented */
473 { /* Localise */
474 xf86DrvMsgVerb(pInt->pScrn->scrnIndex, X_NOT_IMPLEMENTED, 2,
475 "int 0x%2.2x(AH=0x0D) -- Read Graphics Pixel\n",
476 pInt->num);
477 xf86DrvMsgVerb(pInt->pScrn->scrnIndex, X_NOT_IMPLEMENTED, 3,
478 "BH=0x%2.2x, CX=0x%4.4x, DX=0x%4.4x\n", X86_BH, X86_CX,
479 X86_DX);
480 if (xf86GetVerbosity() > 3) {
481 dump_registers(pInt);
482 stack_trace(pInt);
483 }
484 X86_AL = 0;
485 }
486 break;
487
488 case 0x0e:
489 /* Write Character in Teletype Mode */
490 /* Enter: AL = character */
491 /* BH = display page number */
492 /* BL = foreground colour */
493 /* Leave: Nothing */
494 /* Not Implemented */
495 /* WARNING: Emulation of BEL characters will require */
496 /* emulation of RTC and PC speaker I/O. */
497 /* Also, this recurses through int 0x10 */
498 /* which might or might not have been */
499 /* installed yet. */
500 { /* Localise */
501 xf86DrvMsgVerb(pInt->pScrn->scrnIndex, X_NOT_IMPLEMENTED, 2,
502 "int 0x%2.2x(AH=0x0E) -- Write Character in Teletype Mode\n",
503 pInt->num);
504 xf86DrvMsgVerb(pInt->pScrn->scrnIndex, X_NOT_IMPLEMENTED, 3,
505 "AL=0x%2.2x, BH=0x%2.2x, BL=0x%2.2x\n",
506 X86_AL, X86_BH, X86_BL);
507 if (xf86GetVerbosity() > 3) {
508 dump_registers(pInt);
509 stack_trace(pInt);
510 }
511 }
512 break;
513
514 case 0x0f:
515 /* Get Video Mode */
516 /* Enter: Nothing */
517 /* Leave: AH = number of columns */
518 /* AL = video mode number */
519 /* BH = display page number */
520 /* Implemented */
521 { /* Localise */
522 X86_AH = MEM_RW(pInt, 0x044A);
523 X86_AL = MEM_RB(pInt, 0x0449);
524 X86_BH = MEM_RB(pInt, 0x0462);
525 }
526 break;
527
528 case 0x10:
529 /* Colour Control (subfunction in AL) */
530 /* Enter: Various */
531 /* Leave: Various */
532 /* Ignored */
533 break;
534
535 case 0x11:
536 /* Font Control (subfunction in AL) */
537 /* Enter: Various */
538 /* Leave: Various */
539 /* Ignored */
540 break;
541
542 case 0x12:
543 /* Miscellaneous (subfunction in BL) */
544 /* Enter: Various */
545 /* Leave: Various */
546 /* Ignored. Previous code here optionally allowed */
547 /* the enabling and disabling of VGA, but no system */
548 /* BIOS I've come across actually implements it. */
549 break;
550
551 case 0x13:
552 /* Write String in Teletype Mode */
553 /* Enter: AL = write mode */
554 /* BL = attribute (if (AL & 0x02) == 0) */
555 /* CX = string length */
556 /* DH = row */
557 /* DL = column */
558 /* ES:BP = string segment:offset */
559 /* Leave: Nothing */
560 /* Not Implemented */
561 /* WARNING: Emulation of BEL characters will require */
562 /* emulation of RTC and PC speaker I/O. */
563 /* Also, this recurses through int 0x10 */
564 /* which might or might not have been */
565 /* installed yet. */
566 { /* Localise */
567 xf86DrvMsgVerb(pInt->pScrn->scrnIndex, X_NOT_IMPLEMENTED, 2,
568 "int 0x%2.2x(AH=0x13) -- Write String in Teletype Mode\n",
569 pInt->num);
570 xf86DrvMsgVerb(pInt->pScrn->scrnIndex, X_NOT_IMPLEMENTED, 3,
571 "AL=0x%2.2x, BL=0x%2.2x, CX=0x%4.4x,"
572 " DH=0x%2.2x, DL=0x%2.2x, ES:BP=0x%4.4x:0x%4.4x\n",
573 X86_AL, X86_BL, X86_CX, X86_DH, X86_DL, X86_ES, X86_BP);
574 if (xf86GetVerbosity() > 3) {
575 dump_registers(pInt);
576 stack_trace(pInt);
577 }
578 }
579 break;
580
581 default:
582 /* Various extensions */
583 /* Enter: Various */
584 /* Leave: Various */
585 /* Ignored */
586 break;
587 }
588
589 return 1;
590}
591#endif
592
593#define SUCCESSFUL 0x00
594#define DEVICE_NOT_FOUND 0x86
595#define BAD_REGISTER_NUMBER 0x87
596
597#ifdef SHOW_ALL_DEVICES
598/**
599 * These functions are meant to be used by the PCI BIOS emulation. Some
600 * BIOSes need to see if there are \b other chips of the same type around so
601 * by setting \c exclude one PCI device can be explicitely excluded, if
602 * required.
603 */
604static struct pci_device *
605do_find(const struct pci_id_match *m, char n, const struct pci_device *exclude)
606{
607 struct pci_device *dev;
608 struct pci_device_iterator *iter;
609
610 n++;
611
612 iter = pci_id_match_iterator_create(m);
613 while ((dev = pci_device_next(iter)) != NULL) {
614 if ((dev != exclude) && !(--n)) {
615 break;
616 }
617 }
618
619 pci_iterator_destroy(iter);
620
621 return dev;
622}
623
624static struct pci_device *
625find_pci_device_vendor(CARD16 vendorID, CARD16 deviceID,
626 char n, const struct pci_device *exclude)
627{
628 struct pci_id_match m;
629
630 m.vendor_id = vendorID;
631 m.device_id = deviceID;
632 m.subvendor_id = PCI_MATCH_ANY;
633 m.subdevice_id = PCI_MATCH_ANY;
634 m.device_class = 0;
635 m.device_class_mask = 0;
636
637 return do_find(&m, n, exclude);
638}
639
640static struct pci_device *
641find_pci_class(CARD8 intf, CARD8 subClass, CARD16 _class,
642 char n, const struct pci_device *exclude)
643{
644 struct pci_id_match m;
645
646 m.vendor_id = PCI_MATCH_ANY;
647 m.device_id = PCI_MATCH_ANY;
648 m.subvendor_id = PCI_MATCH_ANY;
649 m.subdevice_id = PCI_MATCH_ANY;
650 m.device_class = (((uint32_t) _class) << 16)
651 | (((uint32_t) subClass) << 8) | intf;
652 m.device_class_mask = 0x00ffffff;
653
654 return do_find(&m, n, exclude);
655}
656#endif
657
658/*
659 * Return the last bus number in the same domain as dev. Only look at the
660 * one domain since this is going into %cl, and VGA I/O is per-domain anyway.
661 */
662static int
663int1A_last_bus_number(struct pci_device *dev)
664{
665 struct pci_device *d;
666
667 struct pci_slot_match m = { dev->domain,
668 PCI_MATCH_ANY,
669 PCI_MATCH_ANY,
670 PCI_MATCH_ANY
671 };
672 struct pci_device_iterator *iter;
673 int i = 0;
674
675 iter = pci_slot_match_iterator_create(&m);
676
677 while ((d = pci_device_next(iter)))
678 if (d->bus > i)
679 i = d->bus;
680
681 pci_iterator_destroy(iter);
682
683 return i;
684}
685
686static int
687int1A_handler(xf86Int10InfoPtr pInt)
688{
689 struct pci_device *const pvp = xf86GetPciInfoForEntity(pInt->entityIndex);
690 struct pci_device *dev;
691
692 if (pvp == NULL)
693 return 0; /* oops */
694
695#ifdef PRINT_INT
696 ErrorF("int 0x1a: ax=0x%x bx=0x%x cx=0x%x dx=0x%x di=0x%x es=0x%x\n",
697 X86_EAX, X86_EBX, X86_ECX, X86_EDX, X86_EDI, X86_ESI);
698#endif
699 switch (X86_AX) {
700 case 0xb101:
701 X86_EAX &= 0xFF00; /* no config space/special cycle support */
702 X86_EDX = 0x20494350; /* " ICP" */
703 X86_EBX = 0x0210; /* Version 2.10 */
704 X86_ECX &= 0xFF00;
705 X86_ECX |= int1A_last_bus_number(pvp);
706 X86_EFLAGS &= ~((unsigned long) 0x01); /* clear carry flag */
707#ifdef PRINT_INT
708 ErrorF("ax=0x%x dx=0x%x bx=0x%x cx=0x%x flags=0x%x\n",
709 X86_EAX, X86_EDX, X86_EBX, X86_ECX, X86_EFLAGS);
710#endif
711 return 1;
712 case 0xb102:
713 if ((X86_DX == pvp->vendor_id)
714 && (X86_CX == pvp->device_id)
715 && (X86_ESI == 0)) {
716 X86_EAX = X86_AL | (SUCCESSFUL << 8);
717 X86_EFLAGS &= ~((unsigned long) 0x01); /* clear carry flag */
718 X86_EBX = pciSlotBX(pvp);
719 }
720#ifdef SHOW_ALL_DEVICES
721 else if ((dev = find_pci_device_vendor(X86_EDX, X86_ECX, X86_ESI, pvp))) {
722 X86_EAX = X86_AL | (SUCCESSFUL << 8);
723 X86_EFLAGS &= ~((unsigned long) 0x01); /* clear carry flag */
724 X86_EBX = pciSlotBX(dev);
725 }
726#endif
727 else {
728 X86_EAX = X86_AL | (DEVICE_NOT_FOUND << 8);
729 X86_EFLAGS |= ((unsigned long) 0x01); /* set carry flag */
730 }
731#ifdef PRINT_INT
732 ErrorF("ax=0x%x bx=0x%x flags=0x%x\n", X86_EAX, X86_EBX, X86_EFLAGS);
733#endif
734 return 1;
735 case 0xb103:
736 if ((X86_ECX & 0x00FFFFFF) == pvp->device_class) {
737 X86_EAX = X86_AL | (SUCCESSFUL << 8);
738 X86_EBX = pciSlotBX(pvp);
739 X86_EFLAGS &= ~((unsigned long) 0x01); /* clear carry flag */
740 }
741#ifdef SHOW_ALL_DEVICES
742 else if ((dev = find_pci_class(X86_CL, X86_CH,
743 (X86_ECX & 0xffff0000) >> 16,
744 X86_ESI, pvp))) {
745 X86_EAX = X86_AL | (SUCCESSFUL << 8);
746 X86_EFLAGS &= ~((unsigned long) 0x01); /* clear carry flag */
747 X86_EBX = pciSlotBX(dev);
748 }
749#endif
750 else {
751 X86_EAX = X86_AL | (DEVICE_NOT_FOUND << 8);
752 X86_EFLAGS |= ((unsigned long) 0x01); /* set carry flag */
753 }
754#ifdef PRINT_INT
755 ErrorF("ax=0x%x flags=0x%x\n", X86_EAX, X86_EFLAGS);
756#endif
757 return 1;
758 case 0xb108:
759 if ((dev = findPci(pInt, X86_EBX)) != NULL) {
760 pci_device_cfg_read_u8(dev, &X86_CL, X86_DI);
761 X86_EAX = X86_AL | (SUCCESSFUL << 8);
762 X86_EFLAGS &= ~((unsigned long) 0x01); /* clear carry flag */
763 }
764 else {
765 X86_EAX = X86_AL | (BAD_REGISTER_NUMBER << 8);
766 X86_EFLAGS |= ((unsigned long) 0x01); /* set carry flag */
767 }
768#ifdef PRINT_INT
769 ErrorF("ax=0x%x cx=0x%x flags=0x%x\n", X86_EAX, X86_ECX, X86_EFLAGS);
770#endif
771 return 1;
772 case 0xb109:
773 if ((dev = findPci(pInt, X86_EBX)) != NULL) {
774 pci_device_cfg_read_u16(dev, &X86_CX, X86_DI);
775 X86_EAX = X86_AL | (SUCCESSFUL << 8);
776 X86_EFLAGS &= ~((unsigned long) 0x01); /* clear carry flag */
777 }
778 else {
779 X86_EAX = X86_AL | (BAD_REGISTER_NUMBER << 8);
780 X86_EFLAGS |= ((unsigned long) 0x01); /* set carry flag */
781 }
782#ifdef PRINT_INT
783 ErrorF("ax=0x%x cx=0x%x flags=0x%x\n", X86_EAX, X86_ECX, X86_EFLAGS);
784#endif
785 return 1;
786 case 0xb10a:
787 if ((dev = findPci(pInt, X86_EBX)) != NULL) {
788 pci_device_cfg_read_u32(dev, &X86_ECX, X86_DI);
789 X86_EAX = X86_AL | (SUCCESSFUL << 8);
790 X86_EFLAGS &= ~((unsigned long) 0x01); /* clear carry flag */
791 }
792 else {
793 X86_EAX = X86_AL | (BAD_REGISTER_NUMBER << 8);
794 X86_EFLAGS |= ((unsigned long) 0x01); /* set carry flag */
795 }
796#ifdef PRINT_INT
797 ErrorF("ax=0x%x cx=0x%x flags=0x%x\n", X86_EAX, X86_ECX, X86_EFLAGS);
798#endif
799 return 1;
800 case 0xb10b:
801 if ((dev = findPci(pInt, X86_EBX)) != NULL) {
802 pci_device_cfg_write_u8(dev, X86_CL, X86_DI);
803 X86_EAX = X86_AL | (SUCCESSFUL << 8);
804 X86_EFLAGS &= ~((unsigned long) 0x01); /* clear carry flag */
805 }
806 else {
807 X86_EAX = X86_AL | (BAD_REGISTER_NUMBER << 8);
808 X86_EFLAGS |= ((unsigned long) 0x01); /* set carry flag */
809 }
810#ifdef PRINT_INT
811 ErrorF("ax=0x%x flags=0x%x\n", X86_EAX, X86_EFLAGS);
812#endif
813 return 1;
814 case 0xb10c:
815 if ((dev = findPci(pInt, X86_EBX)) != NULL) {
816 pci_device_cfg_write_u16(dev, X86_CX, X86_DI);
817 X86_EAX = X86_AL | (SUCCESSFUL << 8);
818 X86_EFLAGS &= ~((unsigned long) 0x01); /* clear carry flag */
819 }
820 else {
821 X86_EAX = X86_AL | (BAD_REGISTER_NUMBER << 8);
822 X86_EFLAGS |= ((unsigned long) 0x01); /* set carry flag */
823 }
824#ifdef PRINT_INT
825 ErrorF("ax=0x%x flags=0x%x\n", X86_EAX, X86_EFLAGS);
826#endif
827 return 1;
828 case 0xb10d:
829 if ((dev = findPci(pInt, X86_EBX)) != NULL) {
830 pci_device_cfg_write_u32(dev, X86_ECX, X86_DI);
831 X86_EAX = X86_AL | (SUCCESSFUL << 8);
832 X86_EFLAGS &= ~((unsigned long) 0x01); /* clear carry flag */
833 }
834 else {
835 X86_EAX = X86_AL | (BAD_REGISTER_NUMBER << 8);
836 X86_EFLAGS |= ((unsigned long) 0x01); /* set carry flag */
837 }
838#ifdef PRINT_INT
839 ErrorF("ax=0x%x flags=0x%x\n", X86_EAX, X86_EFLAGS);
840#endif
841 return 1;
842 default:
843 xf86DrvMsgVerb(pInt->pScrn->scrnIndex, X_NOT_IMPLEMENTED, 2,
844 "int 0x1a subfunction\n");
845 dump_registers(pInt);
846 if (xf86GetVerbosity() > 3)
847 stack_trace(pInt);
848 return 0;
849 }
850}
851
852static struct pci_device *
853findPci(xf86Int10InfoPtr pInt, unsigned short bx)
854{
855 const unsigned bus = (bx >> 8) & 0x00FF;
856 const unsigned dev = (bx >> 3) & 0x001F;
857 const unsigned func = (bx) & 0x0007;
858
859 return pci_device_find_by_slot(pInt->dev->domain, bus, dev, func);
860}
861
862static CARD32
863pciSlotBX(const struct pci_device *pvp)
864{
865 return ((pvp->bus << 8) & 0x00FF00) | (pvp->dev << 3) | (pvp->func);
866}
867
868/*
869 * handle initialization
870 */
871static int
872intE6_handler(xf86Int10InfoPtr pInt)
873{
874 struct pci_device *pvp;
875
876 if ((pvp = xf86GetPciInfoForEntity(pInt->entityIndex)))
877 X86_AX = (pvp->bus << 8) | (pvp->dev << 3) | (pvp->func & 0x7);
878 pushw(pInt, X86_CS);
879 pushw(pInt, X86_IP);
880 X86_CS = pInt->BIOSseg;
881 X86_EIP = 0x0003;
882 X86_ES = 0; /* standard pc es */
883 return 1;
884}