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#ifndef _PC
24static int int42_handler(xf86Int10InfoPtr pInt);
25#endif
26static int intE6_handler(xf86Int10InfoPtr pInt);
27static struct pci_device *findPci(xf86Int10InfoPtr pInt, unsigned short bx);
28static CARD32 pciSlotBX( const struct pci_device * pvp );
29
30int
31int_handler(xf86Int10InfoPtr pInt)
32{
33    int num = pInt->num;
34    int ret = 0;
35
36    switch (num) {
37#ifndef _PC
38    case 0x10:
39    case 0x42:
40    case 0x6D:
41	if (getIntVect(pInt, num) == I_S_DEFAULT_INT_VECT)
42	    ret = int42_handler(pInt);
43	break;
44#endif
45    case 0x1A:
46	ret = int1A_handler(pInt);
47	break;
48    case 0xe6:
49	ret = intE6_handler(pInt);
50	break;
51    default:
52	break;
53    }
54
55    if (!ret)
56	ret = run_bios_int(num, pInt);
57
58    if (!ret) {
59	xf86DrvMsg(pInt->scrnIndex, X_ERROR,
60	    "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	    IOADDRESS 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	    /* Remap I/O port number into its domain */
176	    ioport += pInt->ioBase;
177
178	    /* Programme the mode */
179	    outb(ioport + 4, cgamode & 0x37);   /* Turn off screen */
180	    for (i = 0; i < 0x10; i++) {
181		tmp = MEM_RB(pInt, regvals + i);
182		outb(ioport, i);
183		outb(ioport + 1, tmp);
184	    }
185	    outb(ioport + 5, cgacolour);        /* Select colour mode */
186	    outb(ioport + 4, cgamode);          /* Turn on screen */
187	}
188	break;
189
190    case 0x01:
191	/* Set Cursor Type                                    */
192	/* Enter:  CH = starting line for cursor              */
193	/*         CL = ending line for cursor                */
194	/* Leave:  Nothing                                    */
195	/* Implemented                                        */
196	{                                         /* Localise */
197	    IOADDRESS ioport = MEM_RW(pInt, 0x0463) + pInt->ioBase;
198
199	    MEM_WB(pInt, 0x0460, X86_CL);
200	    MEM_WB(pInt, 0x0461, X86_CH);
201
202	    outb(ioport, 0x0A);
203	    outb(ioport + 1, X86_CH);
204	    outb(ioport, 0x0B);
205	    outb(ioport + 1, X86_CL);
206	}
207	break;
208
209    case 0x02:
210	/* Set Cursor Position                                */
211	/* Enter:  BH = display page number                   */
212	/*         DH = row                                   */
213	/*         DL = column                                */
214	/* Leave:  Nothing                                    */
215	/* Implemented                                        */
216	{                                         /* Localise */
217	    IOADDRESS ioport;
218	    CARD16 offset;
219
220	    MEM_WB(pInt, (X86_BH << 1) + 0x0450, X86_DL);
221	    MEM_WB(pInt, (X86_BH << 1) + 0x0451, X86_DH);
222
223	    if (X86_BH != MEM_RB(pInt, 0x0462))
224		break;
225
226	    offset = (X86_DH * MEM_RW(pInt, 0x044A)) + X86_DL;
227	    offset += MEM_RW(pInt, 0x044E) << 1;
228
229	    ioport = MEM_RW(pInt, 0x0463) + pInt->ioBase;
230	    outb(ioport, 0x0E);
231	    outb(ioport + 1, offset >> 8);
232	    outb(ioport, 0x0F);
233	    outb(ioport + 1, offset & 0xFF);
234	}
235	break;
236
237    case 0x03:
238	/* Get Cursor Position                                */
239	/* Enter:  BH = display page number                   */
240	/* Leave:  CH = starting line for cursor              */
241	/*         CL = ending line for cursor                */
242	/*         DH = row                                   */
243	/*         DL = column                                */
244	/* Implemented                                        */
245	{                                         /* Localise */
246	    X86_CL = MEM_RB(pInt, 0x0460);
247	    X86_CH = MEM_RB(pInt, 0x0461);
248	    X86_DL = MEM_RB(pInt, (X86_BH << 1) + 0x0450);
249	    X86_DH = MEM_RB(pInt, (X86_BH << 1) + 0x0451);
250	}
251	break;
252
253    case 0x04:
254	/* Get Light Pen Position                             */
255	/* Enter:  Nothing                                    */
256	/* Leave:  AH = 0x01 (down/triggered) or 0x00 (not)   */
257	/*         BX = pixel column                          */
258	/*         CX = pixel row                             */
259	/*         DH = character row                         */
260	/*         DL = character column                      */
261	/* Not Implemented                                    */
262	{                                         /* Localise */
263	    xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 2,
264		"int 0x%2.2x(AH=0x04) -- Get Light Pen Position\n", pInt->num);
265	    if (xf86GetVerbosity() > 3) {
266		dump_registers(pInt);
267		stack_trace(pInt);
268	    }
269	    X86_AH = X86_BX = X86_CX = X86_DX = 0;
270	}
271	break;
272
273    case 0x05:
274	/* Set Display Page                                   */
275	/* Enter:  AL = display page number                   */
276	/* Leave:  Nothing                                    */
277	/* Implemented                                        */
278	{                                         /* Localise */
279	    IOADDRESS ioport = MEM_RW(pInt, 0x0463) + pInt->ioBase;
280	    CARD16 start;
281	    CARD8 x, y;
282
283	    /* Calculate new start address */
284	    MEM_WB(pInt, 0x0462, X86_AL);
285	    start = X86_AL * MEM_RW(pInt, 0x044C);
286	    MEM_WW(pInt, 0x044E, start);
287	    start <<= 1;
288
289	    /* Update start address */
290	    outb(ioport, 0x0C);
291	    outb(ioport + 1, start >> 8);
292	    outb(ioport, 0x0D);
293	    outb(ioport + 1, start & 0xFF);
294
295	    /* Switch cursor position */
296	    y = MEM_RB(pInt, (X86_AL << 1) + 0x0450);
297	    x = MEM_RB(pInt, (X86_AL << 1) + 0x0451);
298	    start += (y * MEM_RW(pInt, 0x044A)) + x;
299
300	    /* Update cursor position */
301	    outb(ioport, 0x0E);
302	    outb(ioport + 1, start >> 8);
303	    outb(ioport, 0x0F);
304	    outb(ioport + 1, start & 0xFF);
305	}
306	break;
307
308    case 0x06:
309	/* Initialise or Scroll Window Up                     */
310	/* Enter:  AL = lines to scroll up                    */
311	/*         BH = attribute for blank                   */
312	/*         CH = upper y of window                     */
313	/*         CL = left x of window                      */
314	/*         DH = lower y of window                     */
315	/*         DL = right x of window                     */
316	/* Leave:  Nothing                                    */
317	/* Not Implemented                                    */
318	{                                         /* Localise */
319	    xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 2,
320		"int 0x%2.2x(AH=0x06) -- Initialise or Scroll Window Up\n",
321		pInt->num);
322	    xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 3,
323		" AL=0x%2.2x, BH=0x%2.2x,"
324		" CH=0x%2.2x, CL=0x%2.2x, DH=0x%2.2x, DL=0x%2.2x\n",
325		X86_AL, X86_BH, X86_CH, X86_CL, X86_DH, X86_DL);
326	    if (xf86GetVerbosity() > 3) {
327		dump_registers(pInt);
328		stack_trace(pInt);
329	    }
330	}
331	break;
332
333    case 0x07:
334	/* Initialise or Scroll Window Down                   */
335	/* Enter:  AL = lines to scroll down                  */
336	/*         BH = attribute for blank                   */
337	/*         CH = upper y of window                     */
338	/*         CL = left x of window                      */
339	/*         DH = lower y of window                     */
340	/*         DL = right x of window                     */
341	/* Leave:  Nothing                                    */
342	/* Not Implemented                                    */
343	{                                         /* Localise */
344	    xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 2,
345		"int 0x%2.2x(AH=0x07) -- Initialise or Scroll Window Down\n",
346		pInt->num);
347	    xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 3,
348		" AL=0x%2.2x, BH=0x%2.2x,"
349		" CH=0x%2.2x, CL=0x%2.2x, DH=0x%2.2x, DL=0x%2.2x\n",
350		X86_AL, X86_BH, X86_CH, X86_CL, X86_DH, X86_DL);
351	    if (xf86GetVerbosity() > 3) {
352		dump_registers(pInt);
353		stack_trace(pInt);
354	    }
355	}
356	break;
357
358    case 0x08:
359	/* Read Character and Attribute at Cursor             */
360	/* Enter:  BH = display page number                   */
361	/* Leave:  AH = attribute                             */
362	/*         AL = character                             */
363	/* Not Implemented                                    */
364	{                                         /* Localise */
365	    xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 2,
366		"int 0x%2.2x(AH=0x08) -- Read Character and Attribute at"
367		" Cursor\n", pInt->num);
368	    xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 3,
369		"BH=0x%2.2x\n", X86_BH);
370	    if (xf86GetVerbosity() > 3) {
371		dump_registers(pInt);
372		stack_trace(pInt);
373	    }
374	    X86_AX = 0;
375	}
376	break;
377
378    case 0x09:
379	/* Write Character and Attribute at Cursor            */
380	/* Enter:  AL = character                             */
381	/*         BH = display page number                   */
382	/*         BL = attribute (text) or colour (graphics) */
383	/*         CX = replication count                     */
384	/* Leave:  Nothing                                    */
385	/* Not Implemented                                    */
386	{                                         /* Localise */
387	    xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 2,
388		"int 0x%2.2x(AH=0x09) -- Write Character and Attribute at"
389		" Cursor\n", pInt->num);
390	    xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 3,
391		"AL=0x%2.2x, BH=0x%2.2x, BL=0x%2.2x, CX=0x%4.4x\n",
392		X86_AL, X86_BH, X86_BL, X86_CX);
393	    if (xf86GetVerbosity() > 3) {
394		dump_registers(pInt);
395		stack_trace(pInt);
396	    }
397	}
398	break;
399
400    case 0x0a:
401	/* Write Character at Cursor                          */
402	/* Enter:  AL = character                             */
403	/*         BH = display page number                   */
404	/*         BL = colour                                */
405	/*         CX = replication count                     */
406	/* Leave:  Nothing                                    */
407	/* Not Implemented                                    */
408	{                                         /* Localise */
409	    xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 2,
410		"int 0x%2.2x(AH=0x0A) -- Write Character at Cursor\n",
411		pInt->num);
412	    xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 3,
413		"AL=0x%2.2x, BH=0x%2.2x, BL=0x%2.2x, CX=0x%4.4x\n",
414		X86_AL, X86_BH, X86_BL, X86_CX);
415	    if (xf86GetVerbosity() > 3) {
416		dump_registers(pInt);
417		stack_trace(pInt);
418	    }
419	}
420	break;
421
422    case 0x0b:
423	/* Set Palette, Background or Border                  */
424	/* Enter:  BH = 0x00 or 0x01                          */
425	/*         BL = colour or palette (respectively)      */
426	/* Leave:  Nothing                                    */
427	/* Implemented                                        */
428	{                                         /* Localise */
429	    IOADDRESS ioport = MEM_RW(pInt, 0x0463) + 5 + pInt->ioBase;
430	    CARD8 cgacolour = MEM_RB(pInt, 0x0466);
431
432	    if (X86_BH) {
433		cgacolour &= 0xDF;
434		cgacolour |= (X86_BL & 0x01) << 5;
435	    } else {
436		cgacolour &= 0xE0;
437		cgacolour |= X86_BL & 0x1F;
438	    }
439
440	    MEM_WB(pInt, 0x0466, cgacolour);
441	    outb(ioport, cgacolour);
442	}
443	break;
444
445    case 0x0c:
446	/* Write Graphics Pixel                               */
447	/* Enter:  AL = pixel value                           */
448	/*         BH = display page number                   */
449	/*         CX = column                                */
450	/*         DX = row                                   */
451	/* Leave:  Nothing                                    */
452	/* Not Implemented                                    */
453	{                                         /* Localise */
454	    xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 2,
455		"int 0x%2.2x(AH=0x0C) -- Write Graphics Pixel\n", pInt->num);
456	    xf86DrvMsgVerb(pInt->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->scrnIndex, X_NOT_IMPLEMENTED, 2,
475		"int 0x%2.2x(AH=0x0D) -- Read Graphics Pixel\n", pInt->num);
476	    xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 3,
477		"BH=0x%2.2x, CX=0x%4.4x, DX=0x%4.4x\n",
478		X86_BH, X86_CX, X86_DX);
479	    if (xf86GetVerbosity() > 3) {
480		dump_registers(pInt);
481		stack_trace(pInt);
482	    }
483	    X86_AL = 0;
484	}
485	break;
486
487    case 0x0e:
488	/* Write Character in Teletype Mode                   */
489	/* Enter:  AL = character                             */
490	/*         BH = display page number                   */
491	/*         BL = foreground colour                     */
492	/* Leave:  Nothing                                    */
493	/* Not Implemented                                    */
494	/* WARNING:  Emulation of BEL characters will require */
495	/*           emulation of RTC and PC speaker I/O.     */
496	/*           Also, this recurses through int 0x10     */
497	/*           which might or might not have been       */
498	/*           installed yet.                           */
499	{                                         /* Localise */
500	    xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 2,
501		"int 0x%2.2x(AH=0x0E) -- Write Character in Teletype Mode\n",
502		pInt->num);
503	    xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 3,
504		"AL=0x%2.2x, BH=0x%2.2x, BL=0x%2.2x\n",
505		X86_AL, X86_BH, X86_BL);
506	    if (xf86GetVerbosity() > 3) {
507		dump_registers(pInt);
508		stack_trace(pInt);
509	    }
510	}
511	break;
512
513    case 0x0f:
514	/* Get Video Mode                                     */
515	/* Enter:  Nothing                                    */
516	/* Leave:  AH = number of columns                     */
517	/*         AL = video mode number                     */
518	/*         BH = display page number                   */
519	/* Implemented                                        */
520	{                                         /* Localise */
521	    X86_AH = MEM_RW(pInt, 0x044A);
522	    X86_AL = MEM_RB(pInt, 0x0449);
523	    X86_BH = MEM_RB(pInt, 0x0462);
524	}
525	break;
526
527    case 0x10:
528	/* Colour Control (subfunction in AL)                 */
529	/* Enter:  Various                                    */
530	/* Leave:  Various                                    */
531	/* Ignored                                            */
532	break;
533
534    case 0x11:
535	/* Font Control (subfunction in AL)                   */
536	/* Enter:  Various                                    */
537	/* Leave:  Various                                    */
538	/* Ignored                                            */
539	break;
540
541    case 0x12:
542	/* Miscellaneous (subfunction in BL)                  */
543	/* Enter:  Various                                    */
544	/* Leave:  Various                                    */
545	/* Ignored.  Previous code here optionally allowed    */
546	/* the enabling and disabling of VGA, but no system   */
547	/* BIOS I've come across actually implements it.      */
548	break;
549
550    case 0x13:
551	/* Write String in Teletype Mode                      */
552	/* Enter:  AL = write mode                            */
553	/*         BL = attribute (if (AL & 0x02) == 0)       */
554	/*         CX = string length                         */
555	/*         DH = row                                   */
556	/*         DL = column                                */
557	/*         ES:BP = string segment:offset              */
558	/* Leave:  Nothing                                    */
559	/* Not Implemented                                    */
560	/* WARNING:  Emulation of BEL characters will require */
561	/*           emulation of RTC and PC speaker I/O.     */
562	/*           Also, this recurses through int 0x10     */
563	/*           which might or might not have been       */
564	/*           installed yet.                           */
565	{                                         /* Localise */
566	    xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 2,
567		"int 0x%2.2x(AH=0x13) -- Write String in Teletype Mode\n",
568		pInt->num);
569	    xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 3,
570		"AL=0x%2.2x, BL=0x%2.2x, CX=0x%4.4x,"
571		" DH=0x%2.2x, DL=0x%2.2x, ES:BP=0x%4.4x:0x%4.4x\n",
572		X86_AL, X86_BL, X86_CX, X86_DH, X86_DL, X86_ES, X86_BP);
573	    if (xf86GetVerbosity() > 3) {
574		dump_registers(pInt);
575		stack_trace(pInt);
576	    }
577	}
578	break;
579
580    default:
581	/* Various extensions                                 */
582	/* Enter:  Various                                    */
583	/* Leave:  Various                                    */
584	/* Ignored                                            */
585	break;
586    }
587
588    return 1;
589}
590#endif
591
592#define SUCCESSFUL              0x00
593#define DEVICE_NOT_FOUND        0x86
594#define BAD_REGISTER_NUMBER     0x87
595
596#ifdef SHOW_ALL_DEVICES
597/**
598 * These functions are meant to be used by the PCI BIOS emulation. Some
599 * BIOSes need to see if there are \b other chips of the same type around so
600 * by setting \c exclude one PCI device can be explicitely excluded, if
601 * required.
602 */
603static struct pci_device *
604do_find(const struct pci_id_match *m, char n, const struct pci_device * exclude)
605{
606    struct pci_device *dev;
607    struct pci_device_iterator *iter;
608
609    n++;
610
611    iter = pci_id_match_iterator_create(m);
612    while ((dev = pci_device_next(iter)) != NULL) {
613	if ((dev != exclude) && !(--n)) {
614	    break;
615	}
616    }
617
618    pci_iterator_destroy(iter);
619
620    return dev;
621}
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    struct pci_slot_match m = { dev->domain,
667				PCI_MATCH_ANY,
668				PCI_MATCH_ANY,
669				PCI_MATCH_ANY };
670    struct pci_device_iterator *iter;
671    int i = 0;
672
673    iter = pci_slot_match_iterator_create(&m);
674
675    while ((d = pci_device_next(iter)))
676	if (d->bus > i)
677	    i = d->bus;
678
679    pci_iterator_destroy(iter);
680
681    return i;
682}
683
684static int
685int1A_handler(xf86Int10InfoPtr pInt)
686{
687    struct pci_device * const pvp = xf86GetPciInfoForEntity(pInt->entityIndex);
688    struct pci_device * dev;
689
690    if (pvp == NULL)
691	return 0; /* oops */
692
693#ifdef PRINT_INT
694    ErrorF("int 0x1a: ax=0x%x bx=0x%x cx=0x%x dx=0x%x di=0x%x es=0x%x\n",
695	    X86_EAX, X86_EBX, X86_ECX, X86_EDX, X86_EDI, X86_ESI);
696#endif
697    switch (X86_AX) {
698    case 0xb101:
699	X86_EAX &= 0xFF00;   /* no config space/special cycle support */
700	X86_EDX = 0x20494350; /* " ICP" */
701	X86_EBX = 0x0210;    /* Version 2.10 */
702	X86_ECX &= 0xFF00;
703	X86_ECX |= int1A_last_bus_number(pvp);
704	X86_EFLAGS &= ~((unsigned long)0x01); /* clear carry flag */
705#ifdef PRINT_INT
706	ErrorF("ax=0x%x dx=0x%x bx=0x%x cx=0x%x flags=0x%x\n",
707		 X86_EAX, X86_EDX, X86_EBX, X86_ECX, X86_EFLAGS);
708#endif
709	return 1;
710    case 0xb102:
711	if ( (X86_DX == pvp->vendor_id)
712	     && (X86_CX == pvp->device_id)
713	     && (X86_ESI == 0) ) {
714	    X86_EAX = X86_AL | (SUCCESSFUL << 8);
715	    X86_EFLAGS &= ~((unsigned long)0x01); /* clear carry flag */
716	    X86_EBX = pciSlotBX(pvp);
717	}
718#ifdef SHOW_ALL_DEVICES
719	else
720	if ((dev = find_pci_device_vendor(X86_EDX, X86_ECX, X86_ESI, pvp))) {
721	    X86_EAX = X86_AL | (SUCCESSFUL << 8);
722	    X86_EFLAGS &= ~((unsigned long)0x01); /* clear carry flag */
723	    X86_EBX = pciSlotBX(dev);
724	}
725#endif
726	else {
727	    X86_EAX = X86_AL | (DEVICE_NOT_FOUND << 8);
728	    X86_EFLAGS |= ((unsigned long)0x01); /* set carry flag */
729	}
730#ifdef PRINT_INT
731	ErrorF("ax=0x%x bx=0x%x flags=0x%x\n", X86_EAX, X86_EBX, X86_EFLAGS);
732#endif
733	return 1;
734    case 0xb103:
735	if ( (X86_ECX & 0x00FFFFFF) == pvp->device_class ) {
736	    X86_EAX = X86_AL | (SUCCESSFUL << 8);
737	    X86_EBX = pciSlotBX(pvp);
738	    X86_EFLAGS &= ~((unsigned long)0x01); /* clear carry flag */
739	}
740#ifdef SHOW_ALL_DEVICES
741	else if ((dev = find_pci_class(X86_CL, X86_CH,
742				       (X86_ECX & 0xffff0000) >> 16,
743				       X86_ESI, pvp))) {
744	    X86_EAX = X86_AL | (SUCCESSFUL << 8);
745	    X86_EFLAGS &= ~((unsigned long)0x01); /* clear carry flag */
746	    X86_EBX = pciSlotBX(dev);
747	}
748#endif
749	else {
750	    X86_EAX = X86_AL | (DEVICE_NOT_FOUND << 8);
751	    X86_EFLAGS |= ((unsigned long)0x01); /* set carry flag */
752	}
753#ifdef PRINT_INT
754	ErrorF("ax=0x%x flags=0x%x\n", X86_EAX, X86_EFLAGS);
755#endif
756	return 1;
757    case 0xb108:
758	if ((dev = findPci(pInt, X86_EBX)) != NULL) {
759	    pci_device_cfg_read_u8(dev, & X86_CL, X86_DI);
760	    X86_EAX = X86_AL | (SUCCESSFUL << 8);
761	    X86_EFLAGS &= ~((unsigned long)0x01); /* clear carry flag */
762	} else {
763	    X86_EAX = X86_AL | (BAD_REGISTER_NUMBER << 8);
764	    X86_EFLAGS |= ((unsigned long)0x01); /* set carry flag */
765	}
766#ifdef PRINT_INT
767	ErrorF("ax=0x%x cx=0x%x flags=0x%x\n", X86_EAX, X86_ECX, X86_EFLAGS);
768#endif
769	return 1;
770    case 0xb109:
771	if ((dev = findPci(pInt, X86_EBX)) != NULL) {
772	    pci_device_cfg_read_u16(dev, & X86_CX, X86_DI);
773	    X86_EAX = X86_AL | (SUCCESSFUL << 8);
774	    X86_EFLAGS &= ~((unsigned long)0x01); /* clear carry flag */
775	} else {
776	    X86_EAX = X86_AL | (BAD_REGISTER_NUMBER << 8);
777	    X86_EFLAGS |= ((unsigned long)0x01); /* set carry flag */
778	}
779#ifdef PRINT_INT
780	ErrorF("ax=0x%x cx=0x%x flags=0x%x\n", X86_EAX, X86_ECX, X86_EFLAGS);
781#endif
782	return 1;
783    case 0xb10a:
784	if ((dev = findPci(pInt, X86_EBX)) != NULL) {
785	    uint32_t ecx;
786	    pci_device_cfg_read_u32(dev, & ecx, X86_DI);
787	    X86_ECX = ecx;
788	    X86_EAX = X86_AL | (SUCCESSFUL << 8);
789	    X86_EFLAGS &= ~((unsigned long)0x01); /* clear carry flag */
790	} else {
791	    X86_EAX = X86_AL | (BAD_REGISTER_NUMBER << 8);
792	    X86_EFLAGS |= ((unsigned long)0x01); /* set carry flag */
793	}
794#ifdef PRINT_INT
795	ErrorF("ax=0x%x cx=0x%x flags=0x%x\n", X86_EAX, X86_ECX, X86_EFLAGS);
796#endif
797	return 1;
798    case 0xb10b:
799	if ((dev = findPci(pInt, X86_EBX)) != NULL) {
800	    pci_device_cfg_write_u8(dev, X86_CL, X86_DI);
801	    X86_EAX = X86_AL | (SUCCESSFUL << 8);
802	    X86_EFLAGS &= ~((unsigned long)0x01); /* clear carry flag */
803	} else {
804	    X86_EAX = X86_AL | (BAD_REGISTER_NUMBER << 8);
805	    X86_EFLAGS |= ((unsigned long)0x01); /* set carry flag */
806	}
807#ifdef PRINT_INT
808	ErrorF("ax=0x%x flags=0x%x\n", X86_EAX, X86_EFLAGS);
809#endif
810	return 1;
811    case 0xb10c:
812	if ((dev = findPci(pInt, X86_EBX)) != NULL) {
813	    pci_device_cfg_write_u16(dev, X86_CX, X86_DI);
814	    X86_EAX = X86_AL | (SUCCESSFUL << 8);
815	    X86_EFLAGS &= ~((unsigned long)0x01); /* clear carry flag */
816	} else {
817	    X86_EAX = X86_AL | (BAD_REGISTER_NUMBER << 8);
818	    X86_EFLAGS |= ((unsigned long)0x01); /* set carry flag */
819	}
820#ifdef PRINT_INT
821	ErrorF("ax=0x%x flags=0x%x\n", X86_EAX, X86_EFLAGS);
822#endif
823	return 1;
824    case 0xb10d:
825	if ((dev = findPci(pInt, X86_EBX)) != NULL) {
826	    pci_device_cfg_write_u32(dev, X86_ECX, X86_DI);
827	    X86_EAX = X86_AL | (SUCCESSFUL << 8);
828	    X86_EFLAGS &= ~((unsigned long)0x01); /* clear carry flag */
829	} else {
830	    X86_EAX = X86_AL | (BAD_REGISTER_NUMBER << 8);
831	    X86_EFLAGS |= ((unsigned long)0x01); /* set carry flag */
832	}
833#ifdef PRINT_INT
834	ErrorF("ax=0x%x flags=0x%x\n", X86_EAX, X86_EFLAGS);
835#endif
836	return 1;
837    default:
838	xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 2,
839	    "int 0x1a subfunction\n");
840	dump_registers(pInt);
841	if (xf86GetVerbosity() > 3)
842	    stack_trace(pInt);
843	return 0;
844    }
845}
846
847static struct pci_device *
848findPci(xf86Int10InfoPtr pInt, unsigned short bx)
849{
850    const unsigned bus =  (bx >> 8) & 0x00FF;
851    const unsigned dev =  (bx >> 3) & 0x001F;
852    const unsigned func = (bx     ) & 0x0007;
853
854    return pci_device_find_by_slot(pInt->dev->domain, bus, dev, func);
855}
856
857static CARD32
858pciSlotBX(const struct pci_device * pvp)
859{
860    return ((pvp->bus << 8) & 0x00FF00) | (pvp->dev << 3) | (pvp->func);
861}
862
863/*
864 * handle initialization
865 */
866static int
867intE6_handler(xf86Int10InfoPtr pInt)
868{
869    struct pci_device * pvp;
870
871    if ((pvp = xf86GetPciInfoForEntity(pInt->entityIndex)))
872	X86_AX = (pvp->bus << 8) | (pvp->dev << 3) | (pvp->func & 0x7);
873    pushw(pInt, X86_CS);
874    pushw(pInt, X86_IP);
875    X86_CS = pInt->BIOSseg;
876    X86_EIP = 0x0003;
877    X86_ES = 0;                  /* standard pc es */
878    return 1;
879}
880