xref: /OK3568_Linux_fs/external/xserver/hw/xfree86/int10/xf86int10.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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 
20 xf86Int10InfoPtr Int10Current = NULL;
21 
22 static int int1A_handler(xf86Int10InfoPtr pInt);
23 
24 #ifndef _PC
25 static int int42_handler(xf86Int10InfoPtr pInt);
26 #endif
27 static int intE6_handler(xf86Int10InfoPtr pInt);
28 static struct pci_device *findPci(xf86Int10InfoPtr pInt, unsigned short bx);
29 static CARD32 pciSlotBX(const struct pci_device *pvp);
30 
31 int
int_handler(xf86Int10InfoPtr pInt)32 int_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  */
77 static int
int42_handler(xf86Int10InfoPtr pInt)78 int42_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  */
604 static struct pci_device *
do_find(const struct pci_id_match * m,char n,const struct pci_device * exclude)605 do_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 
624 static struct pci_device *
find_pci_device_vendor(CARD16 vendorID,CARD16 deviceID,char n,const struct pci_device * exclude)625 find_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 
640 static struct pci_device *
find_pci_class(CARD8 intf,CARD8 subClass,CARD16 _class,char n,const struct pci_device * exclude)641 find_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  */
662 static int
int1A_last_bus_number(struct pci_device * dev)663 int1A_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 
686 static int
int1A_handler(xf86Int10InfoPtr pInt)687 int1A_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 
852 static struct pci_device *
findPci(xf86Int10InfoPtr pInt,unsigned short bx)853 findPci(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 
862 static CARD32
pciSlotBX(const struct pci_device * pvp)863 pciSlotBX(const struct pci_device *pvp)
864 {
865     return ((pvp->bus << 8) & 0x00FF00) | (pvp->dev << 3) | (pvp->func);
866 }
867 
868 /*
869  * handle initialization
870  */
871 static int
intE6_handler(xf86Int10InfoPtr pInt)872 intE6_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 }
885