xf86int10.c revision f7df2e56
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}
885