3 #include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
12 #include <isapnp/isapnp.h>
14 #include <hw/8254/8254.h> /* 8254 timer */
16 uint16_t isapnp_read_data = 0;
17 uint8_t isapnp_probe_next_csn = 0;
19 const unsigned char isa_pnp_init_keystring[32] = {
20 0x6A,0xB5,0xDA,0xED,0xF6,0xFB,0x7D,0xBE,
21 0xDF,0x6F,0x37,0x1B,0x0D,0x86,0xC3,0x61,
22 0xB0,0x58,0x2C,0x16,0x8B,0x45,0xA2,0xD1,
23 0xE8,0x74,0x3A,0x9D,0xCE,0xE7,0x73,0x39
26 const char *isapnp_config_block_str[3] = {
32 const char *isa_pnp_devd_pnp_0x00xx[] = { /* PNP00xx */
33 "AT interrupt controller", /* 00 */
34 "EISA interrupt controller", /* 01 */
35 "MCA interrupt controller", /* 02 */
37 "Cyrix SLiC MP interrupt controller" /* 04 */
40 const char *isa_pnp_devd_pnp_0x01xx[] = { /* PNP01xx */
42 "EISA Timer", /* 01 */
46 const char *isa_pnp_devd_pnp_0x02xx[] = { /* PNP02xx */
47 "AT DMA Controller", /* 00 */
48 "EISA DMA Controller", /* 01 */
49 "MCA DMA Controller" /* 02 */
52 const char *isa_pnp_devd_pnp_0x03xx[] = { /* PNP03xx */
53 "IBM PC/XT keyboard controller (83-key)", /* 00 */
54 "IBM PC/AT keyboard controller (86-key)", /* 01 */
55 "IBM PC/XT keyboard controller (84-key)", /* 02 */
56 "IBM Enhanced (101/102-key, PS/2 mouse support)", /* 03 */
57 "Olivetti Keyboard (83-key)", /* 04 */
58 "Olivetti Keyboard (102-key)", /* 05 */
59 "Olivetti Keyboard (86-key)", /* 06 */
60 "Microsoft Windows(R) Keyboard", /* 07 */
61 "General Input Device Emulation Interface (GIDEI) legacy", /* 08 */
62 "Olivetti Keyboard (A101/102 key)", /* 09 */
63 "AT&T 302 keyboard", /* 0A */
64 "Reserved by Microsoft", /* 0B */
69 NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, /* 10-17 */
70 NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, /* 18-1F */
71 "Japanese 106-key keyboard A01", /* 20 */
72 "Japanese 101-key keyboard", /* 21 */
73 "Japanese AX keyboard", /* 22 */
74 "Japanese 106-key keyboard 002/003", /* 23 */
75 "Japanese 106-key keyboard 001", /* 24 */
76 "Japanese Toshiba Desktop keyboard", /* 25 */
77 "Japanese Toshiba Laptop keyboard", /* 26 */
78 "Japanese Toshiba Notebook keyboard", /* 27 */
79 NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, /* 28-2F */
80 NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, /* 30-37 */
81 NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, /* 38-3F */
82 "Korean 84-key keyboard", /* 40 */
83 "Korean 86-key keyboard", /* 41 */
84 "Korean Enhanced keyboard", /* 42 */
85 "Korean Enhanced keyboard 101c", /* 43 */
86 "Korean Enhanced keyboard 103" /* 44 */
89 const char *isa_pnp_devd_pnp_0x04xx[] = { /* PNP04xx */
90 "Standard LPT printer port", /* 00 */
91 "ECP printer port" /* 01 */
94 const char *isa_pnp_devd_pnp_0x05xx[] = { /* PNP05xx */
95 "Standard PC COM port", /* 00 */
96 "16550A-compatible COM port", /* 01 */
97 "Multiport serial device", /* 02 */
111 "Generic IRDA-compatible", /* 10 */
112 "Generic IRDA-compatible" /* 11 */
115 const char *isa_pnp_devd_pnp_0x06xx[] = { /* PNP06xx */
116 "Generic ESDI/IDE/ATA controller", /* 00 */
117 "Plus Hardcard II", /* 01 */
118 "Plus Hardcard IIXL/EZ", /* 02 */
119 "Generic IDE, Microsoft Device Bay Specification"/* 03 */
122 const char *isa_pnp_devd_pnp_0x07xx[] = { /* PNP07xx */
123 "PC standard floppy disk controller", /* 00 */
124 "Standard floppy, Microsoft Device Bay Specification" /* 01 */
127 const char *isa_pnp_devd_pnp_0x09xx[] = { /* PNP09xx */
128 "VGA compatible", /* 00 */
129 "Video Seven VRAM/VRAM II/1024i", /* 01 */
130 "8514/A compatible", /* 02 */
131 "Trident VGA", /* 03 */
132 "Cirrus Logic Laptop VGA", /* 04 */
133 "Cirrus Logic VGA", /* 05 */
134 "Tseng ET4000", /* 06 */
135 "Western Digital VGA", /* 07 */
136 "Western Digital Laptop VGA", /* 08 */
137 "S3 911/924", /* 09 */
138 "ATI Ultra Pro/Plus Mach32", /* 0A */
139 "ATI Ultra Mach8", /* 0B */
140 "XGA compatible", /* 0C */
141 "ATI VGA wonder", /* 0D */
142 "Weitek P9000 graphics", /* 0E */
145 "Compaq QVision", /* 10 */
147 "Tseng W32/W32i/W32p", /* 12 */
148 "S3 801/928/964", /* 13 */
149 "Cirrus 5429/5434", /* 14 */
150 "Compaq advanced VGA", /* 15 */
151 "ATI Ultra Pro Turbo Mach64", /* 16 */
152 "Microsoft Reserved", /* 17 */
154 "Compaq QVision 2000", /* 19 */
155 "Tseng W128", /* 1A */
156 NULL,NULL,NULL,NULL,NULL, /* 1B-1F */
158 NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL, /* 20-27 */
159 NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL, /* 28-2F */
161 "Chips & Technologies SVGA", /* 30 */
162 "Chips & Technologies accelerator", /* 31 */
163 NULL,NULL, NULL,NULL,NULL,NULL, /* 32-37 */
164 NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL, /* 38-3F */
166 "NCR 77c22e SVGA", /* 40 */
167 "NCR 77c32blt" /* 41 */
170 const char *isa_pnp_devd_pnp_0x0Cxx[] = { /* PNP0Cxx */
171 "Plug & Play BIOS", /* 00 */
172 "System board", /* 01 */
173 "Motherboard resources", /* 02 */
174 "Plug & Play BIOS event interrupt", /* 03 */
175 "Math coprocessor", /* 04 */
177 "(early PnP #06)", /* 06 */
178 "(early PnP #07)", /* 07 */
179 "ACPI system board", /* 08 */
180 "ACPI embedded controller", /* 09 */
181 "ACPI control method battery", /* 0A */
183 "ACPI power button", /* 0C */
185 "ACPI sleep button", /* 0E */
186 "PCI interrupt link", /* 0F */
187 "ACPI system indicator", /* 10 */
188 "ACPI thermal zone", /* 11 */
189 "Device bay controller", /* 12 */
190 "Plug & Play BIOS (non-ACPI?)" /* 13 */
193 const char *isa_pnp_devd_pnp_0x0Axx[] = { /* PNP0Axx */
199 "Generic ACPI bus", /* 05 that's a bus? */
200 "Generic ACPI extended IO bus" /* 06 */
203 const char *isa_pnp_devd_pnp_0x0Exx[] = { /* PNP0Exx */
204 "Intel 82365-compatible PCMCIA controller", /* 00 */
205 "Cirrus Logic CL-PD6720 PCMCIA controller", /* 01 */
206 "VLSI VL82C146 PCMCIA controller", /* 02 */
207 "Intel 82365-compatible CardBus controller" /* 03 */
210 const char *isa_pnp_devd_pnp_0x0Fxx[] = { /* PNP0Fxx */
211 "Microsoft bus mouse", /* 00 */
212 "Microsoft serial", /* 01 */
213 "Microsoft InPort", /* 02 */
214 "Microsoft PS/2", /* 03 */
215 "Mouse systems", /* 04 */
216 "Mouse systems 3-button (COM2)", /* 05 */
217 "Genius mouse (COM1)", /* 06 */
218 "Genius mouse (COM2)", /* 07 */
219 "Logitech serial", /* 08 */
220 "Microsoft BallPoint serial", /* 09 */
221 "Microsoft plug & play", /* 0A */
222 "Microsoft plug & play BallPoint", /* 0B */
223 "Microsoft compatible serial", /* 0C */
224 "Microsoft compatible InPort compatible", /* 0D */
225 "Microsoft compatible PS/2", /* 0E */
226 "Microsoft compatible serial BallPoint compatible", /* 0F */
227 "Texas Instruments QuickPort", /* 10 */
228 "Microsoft compatible bus mouse", /* 11 */
229 "Logitech PS/2", /* 12 */
230 "PS/2 port for PS/2 mice", /* 13 */
231 "Microsoft kids mouse", /* 14 */
232 "Logitech bus mouse", /* 15 */
233 "Logitech swift device", /* 16 */
234 "Logitech compatible serial", /* 17 */
235 "Logitech compatible bus mouse", /* 18 */
236 "Logitech compatible PS/2", /* 19 */
237 "Logitech compatible swift", /* 1A */
238 "HP Omnibook mouse", /* 1B */
239 "Compaq LTE trackball PS/2", /* 1C */
240 "Compaq LTE trackball serial", /* 1D */
241 "Microsoft kids trackball", /* 1E */
245 const char *isapnp_fml32_miosize_str[4] = {
252 const char *isapnp_sdf_priority_strs[3] = {
258 const char *isapnp_dma_speed_str[4] = {
265 const char *isapnp_dma_xfer_preference_str[4] = {
272 const char *isapnp_tag_strs[] = {
273 /* small tags +0x00 */
276 "Logical device ID", /* 0x02 */
277 "Compatible device ID",
280 "Dependent function start", /* 0x06 */
281 "Dependent function end",
282 "I/O port", /* 0x08 */
288 "Vendor tag S-0xE", /* 0x0E */
290 /* large tags +0x10 */
293 "Identifier string (ANSI)", /* 0x12 */
294 "Identifier string (Unicode)",
295 "Vendor tag L-0x4", /* 0x14 */
296 "32-bit memory range",
297 "32-bit fixed memory range" /* 0x16 */
300 uint16_t isa_pnp_bios_offset = 0;
301 struct isa_pnp_bios_struct isa_pnp_info;
302 unsigned int (__cdecl far *isa_pnp_rm_call)() = NULL;
304 #if TARGET_MSDOS == 32
305 uint16_t isa_pnp_pm_code_seg = 0; /* code segment to call protected mode BIOS if */
306 uint16_t isa_pnp_pm_data_seg = 0; /* data segment to call protected mode BIOS if */
307 uint8_t isa_pnp_pm_use = 0; /* 1=call protected mode interface 0=call real mode interface */
308 uint8_t isa_pnp_pm_win95_mode = 0; /* 1=call protected mode interface with 32-bit stack (Windows 95 style) */
309 uint16_t isa_pnp_rm_call_area_code_sel = 0;
310 uint16_t isa_pnp_rm_call_area_sel = 0;
311 void* isa_pnp_rm_call_area = NULL;
314 int init_isa_pnp_bios() {
315 #if TARGET_MSDOS == 32
316 isa_pnp_rm_call_area_code_sel = 0;
317 isa_pnp_rm_call_area_sel = 0;
318 isa_pnp_pm_code_seg = 0;
319 isa_pnp_pm_data_seg = 0;
325 void free_isa_pnp_bios() {
326 #if TARGET_MSDOS == 32
327 if (isa_pnp_pm_code_seg != 0)
328 dpmi_free_descriptor(isa_pnp_pm_code_seg);
329 if (isa_pnp_pm_data_seg != 0)
330 dpmi_free_descriptor(isa_pnp_pm_data_seg);
331 if (isa_pnp_rm_call_area_code_sel != 0)
332 dpmi_free_descriptor(isa_pnp_rm_call_area_code_sel);
333 if (isa_pnp_rm_call_area_sel != 0)
334 dpmi_free_dos(isa_pnp_rm_call_area_sel);
335 isa_pnp_pm_code_seg = 0;
336 isa_pnp_pm_data_seg = 0;
337 isa_pnp_rm_call_area_sel = 0;
338 isa_pnp_rm_call_area_code_sel = 0;
339 isa_pnp_rm_call_area = NULL;
344 int find_isa_pnp_bios() {
345 #if TARGET_MSDOS == 32
346 uint8_t *scan = (uint8_t*)0xF0000;
348 uint8_t far *scan = (uint8_t far*)MK_FP(0xF000U,0x0000U);
350 unsigned int offset,i;
353 isa_pnp_bios_offset = (uint16_t)(~0U);
354 memset(&isa_pnp_info,0,sizeof(isa_pnp_info));
356 /* NTS: Stop at 0xFFE0 because 0xFFE0+0x21 >= end of 64K segment */
357 for (offset=0U;offset != 0xFFE0U;offset += 0x10U,scan += 0x10) {
358 if (scan[0] == '$' && scan[1] == 'P' && scan[2] == 'n' &&
359 scan[3] == 'P' && scan[4] >= 0x10 && scan[5] >= 0x21) {
361 for (i=0;i < scan[5];i++)
365 isa_pnp_bios_offset = (uint16_t)offset;
366 _fmemcpy(&isa_pnp_info,scan,sizeof(isa_pnp_info));
367 isa_pnp_rm_call = (void far*)MK_FP(isa_pnp_info.rm_ent_segment,
368 isa_pnp_info.rm_ent_offset);
370 #if TARGET_MSDOS == 32
371 isa_pnp_rm_call_area = dpmi_alloc_dos(ISA_PNP_RM_DOS_AREA_SIZE,&isa_pnp_rm_call_area_sel);
372 if (isa_pnp_rm_call_area == NULL) {
373 fprintf(stderr,"WARNING: Failed to allocate common area for DOS realmode calling\n");
377 /* allocate descriptors to make calling the BIOS from pm mode */
378 if ((isa_pnp_pm_code_seg = dpmi_alloc_descriptor()) != 0) {
379 if (!dpmi_set_segment_base(isa_pnp_pm_code_seg,isa_pnp_info.pm_ent_segment_base)) {
380 fprintf(stderr,"WARNING: Failed to set segment base\n"); goto fail; }
381 if (!dpmi_set_segment_limit(isa_pnp_pm_code_seg,0xFFFFUL)) {
382 fprintf(stderr,"WARNING: Failed to set segment limit\n"); goto fail; }
383 if (!dpmi_set_segment_access(isa_pnp_pm_code_seg,0x9A)) {
384 fprintf(stderr,"WARNING: Failed to set segment access rights\n"); goto fail; }
387 if ((isa_pnp_pm_data_seg = dpmi_alloc_descriptor()) != 0) {
388 if (!dpmi_set_segment_base(isa_pnp_pm_data_seg,isa_pnp_info.pm_ent_data_segment_base)) {
389 fprintf(stderr,"WARNING: Failed to set segment base\n"); goto fail; }
390 if (!dpmi_set_segment_limit(isa_pnp_pm_data_seg,0xFFFFUL)) {
391 fprintf(stderr,"WARNING: Failed to set segment limit\n"); goto fail; }
392 if (!dpmi_set_segment_access(isa_pnp_pm_data_seg,0x92)) {
393 fprintf(stderr,"WARNING: Failed to set segment access rights\n"); goto fail; }
396 /* allocate code selector for realmode area */
397 if ((isa_pnp_rm_call_area_code_sel = dpmi_alloc_descriptor()) != 0) {
398 if (!dpmi_set_segment_base(isa_pnp_rm_call_area_code_sel,(uint32_t)isa_pnp_rm_call_area)) {
399 fprintf(stderr,"WARNING: Failed to set segment base\n"); goto fail; }
400 if (!dpmi_set_segment_limit(isa_pnp_rm_call_area_code_sel,0xFFFFUL)) {
401 fprintf(stderr,"WARNING: Failed to set segment limit\n"); goto fail; }
402 if (!dpmi_set_segment_access(isa_pnp_rm_call_area_code_sel,0x9A)) {
403 fprintf(stderr,"WARNING: Failed to set segment access rights\n"); goto fail; }
410 #if TARGET_MSDOS == 32
411 fail: free_isa_pnp_bios();
421 #if TARGET_MSDOS == 32
423 static unsigned int isa_pnp_thunk_and_call() { /* private, don't export */
424 unsigned short sgm = isa_pnp_pm_use ? (unsigned short)isa_pnp_rm_call_area_sel : (unsigned short)((size_t)isa_pnp_rm_call_area >> 4);
425 if (isa_pnp_pm_use) {
426 unsigned char *callfunc = (unsigned char*)isa_pnp_rm_call_area + 0x8;
427 unsigned short ret_ax = ~0U,my_cs = 0;
434 /* 32-bit far pointer used in call below */
435 *((uint32_t*)(callfunc+0+0)) = 0x08+0x8;
436 *((uint32_t*)(callfunc+0+4)) = isa_pnp_rm_call_area_code_sel;
437 /* 386 assembly language: CALL <proc> */
438 *((uint8_t *)(callfunc+8+0)) = 0x9A;
439 *((uint16_t*)(callfunc+8+1)) = (uint16_t)isa_pnp_info.pm_ent_offset;
440 *((uint16_t*)(callfunc+8+3)) = (uint16_t)isa_pnp_pm_code_seg;
441 /* 386 assembly language: from 16-bit segment: [32-bit] call far <32-bit code segment:offset of label "asshole"> */
442 *((uint8_t *)(callfunc+8+5)) = 0x66;
443 *((uint8_t *)(callfunc+8+6)) = 0x67;
444 *((uint8_t *)(callfunc+8+7)) = 0xEA;
445 *((uint32_t*)(callfunc+8+8)) = 0;
446 *((uint32_t*)(callfunc+8+12)) = my_cs;
448 /* protected mode call */
449 if (isa_pnp_pm_win95_mode) {
450 /* Windows 95 mode: call just like below, but DON'T switch stacks (leave SS:ESP => 32-bit stack).
451 * This is what Windows 95 does and it's probably why the Bochs implementation of Plug & Play BIOS
452 * doesn't work, since everything in the PnP spec implies 16-bit FAR pointers */
458 ; These stupid acrobatics are necessary because Watcom has a hang-up
459 ; about inline assembly referring to stack variables and doesn't like
460 ; inline assembly referring to label addresses
461 call acrobat1 ; near call to put label address on stack
462 jmp asshole ; relative JMP address to the 'asshole' label below
463 acrobat1: pop eax ; retrieve the address of the 'acrobat1' label
464 add eax,dword ptr [eax+1] ; sum it against the relative 32-bit address portion of the JMP instruction (NTS: JMP = 0xEA <32-bit rel addr>)
466 mov dword ptr [esi+8+8],eax
473 mov esp,isa_pnp_rm_call_area
475 mov ax,isa_pnp_rm_call_area_sel
477 mov ax,isa_pnp_pm_data_seg
482 jmpf fword ptr fs:0x8
484 ; WARNING: do NOT remove these NOPs
500 ; restore stack (NTS: PnP BIOSes are supposed to restore ALL regs except AX)
520 ; These stupid acrobatics are necessary because Watcom has a hang-up
521 ; about inline assembly referring to stack variables and doesn't like
522 ; inline assembly referring to label addresses
523 call acrobat1 ; near call to put label address on stack
524 jmp asshole ; relative JMP address to the 'asshole' label below
525 acrobat1: pop eax ; retrieve the address of the 'acrobat1' label
526 add eax,dword ptr [eax+1] ; sum it against the relative 32-bit address portion of the JMP instruction (NTS: JMP = 0xEA <32-bit rel addr>)
528 mov dword ptr [esi+8+8],eax
536 mov ax,isa_pnp_rm_call_area_sel
538 mov ax,isa_pnp_pm_data_seg
543 jmpf fword ptr ss:0x8
545 ; WARNING: do NOT remove these NOPs
561 ; restore stack (NTS: PnP BIOSes are supposed to restore ALL regs except AX)
579 /* real-mode call via DPMI */
580 /* ..but wait---we might be running under DOS4/G which doesn't
581 provide the "real mode call" function! */
582 struct dpmi_realmode_call d={0};
583 unsigned int x = (unsigned int)(&d); /* NTS: Work around Watcom's "cannot take address of stack symbol" error */
584 d.cs = isa_pnp_info.rm_ent_segment;
585 d.ip = isa_pnp_info.rm_ent_offset;
586 d.ss = sgm; /* our real-mode segment is also the stack during the call */
589 if (dpmi_no_0301h < 0) probe_dpmi();
591 if (dpmi_no_0301h > 0) {
592 /* Fuck you DOS4/GW! */
593 dpmi_alternate_rm_call_stacko(&d);
602 mov eax,0x0301 ; DPMI call real-mode far routine
619 unsigned int isa_pnp_bios_number_of_sysdev_nodes(unsigned char far *a,unsigned int far *b) {
620 /* use the DOS segment we allocated as a "trampoline" for the 16-bit code to write the return values to */
623 * SEG:0x00F0 = stack for passing params */
624 unsigned int *rb_a = (unsigned int*)((unsigned char*)isa_pnp_rm_call_area);
625 unsigned int *rb_b = (unsigned int*)((unsigned char*)isa_pnp_rm_call_area + 4);
626 unsigned short *stk = (unsigned short*)((unsigned char*)isa_pnp_rm_call_area + 0x1F0);
627 unsigned short sgm = isa_pnp_pm_use ? (unsigned short)isa_pnp_rm_call_area_sel : (unsigned short)((size_t)isa_pnp_rm_call_area >> 4);
628 unsigned int ret_ax = ~0;
630 *rb_a = ~0UL; *rb_b = ~0UL;
632 /* build the stack */
633 stk[5] = isa_pnp_pm_use ? (unsigned short)isa_pnp_pm_data_seg : (unsigned short)isa_pnp_info.rm_ent_data_segment; /* BIOS data segment */
635 stk[3] = 4; /* offset of "b" (segment will be filled in separately) */
637 stk[1] = 0; /* offset of "a" (ditto) */
638 stk[0] = 0; /* function */
640 ret_ax = isa_pnp_thunk_and_call();
642 fprintf(stderr,"WARNING: Thunk and call failed\n");
645 *a = (unsigned char)(*rb_a);
653 unsigned int isa_pnp_bios_get_sysdev_node(unsigned char far *a,unsigned char far *b,unsigned int c) {
654 /* use the DOS segment we allocated as a "trampoline" for the 16-bit code to write the return values to */
655 /* SEG:0x0000 = a (node)
656 * SEG:0x00F0 = stack for passing params
657 * SEG:0x0100 = b (buffer for xfer)
658 * SEF:0x0FFF = end */
659 unsigned char *rb_a = (unsigned char*)((unsigned char*)isa_pnp_rm_call_area);
660 unsigned char *rb_b = (unsigned char*)((unsigned char*)isa_pnp_rm_call_area + 0x200);
661 unsigned short *stk = (unsigned short*)((unsigned char*)isa_pnp_rm_call_area + 0x1F0);
662 unsigned short sgm = isa_pnp_pm_use ? (unsigned short)isa_pnp_rm_call_area_sel : (unsigned short)((size_t)isa_pnp_rm_call_area >> 4);
663 unsigned int ret_ax = ~0;
666 rb_b[0] = rb_b[1] = 0;
668 stk[6] = isa_pnp_pm_use ? (unsigned short)isa_pnp_pm_data_seg : (unsigned short)isa_pnp_info.rm_ent_data_segment; /* BIOS data segment */
670 stk[4] = sgm; /* offset of "b" */
672 stk[2] = sgm; /* offset of "a" */
674 stk[0] = 1; /* function */
676 ret_ax = isa_pnp_thunk_and_call();
678 fprintf(stderr,"WARNING: Thunk and call failed\n");
681 unsigned int len = *((uint16_t*)rb_b); /* read back the size of the device node */
682 *a = (unsigned char)(*rb_a);
683 if ((0x100+len) > ISA_PNP_RM_DOS_AREA_SIZE) {
684 fprintf(stderr,"Whoahhhh..... the returned device struct is too large! len=%u\n",len);
688 if ((ret_ax&0xFF) == 0) _fmemcpy(b,rb_b,len);
696 unsigned int isa_pnp_bios_get_static_alloc_resinfo(unsigned char far *a) {
700 unsigned int isa_pnp_bios_get_pnp_isa_cfg(unsigned char far *a) {
701 /* use the DOS segment we allocated as a "trampoline" for the 16-bit code to write the return values to */
702 /* SEG:0x0000 = a (node)
703 * SEG:0x00F0 = stack for passing params
704 * SEG:0x0100 = b (buffer for xfer)
705 * SEF:0x0FFF = end */
706 unsigned char *rb_a = (unsigned char*)((unsigned char*)isa_pnp_rm_call_area + 0x200);
707 unsigned short *stk = (unsigned short*)((unsigned char*)isa_pnp_rm_call_area + 0x1F0);
708 unsigned short sgm = isa_pnp_pm_use ? (unsigned short)isa_pnp_rm_call_area_sel : (unsigned short)((size_t)isa_pnp_rm_call_area >> 4);
709 unsigned int ret_ax = ~0;
711 stk[3] = isa_pnp_pm_use ? (unsigned short)isa_pnp_pm_data_seg : (unsigned short)isa_pnp_info.rm_ent_data_segment; /* BIOS data segment */
712 stk[2] = sgm; /* offset of "a" */
714 stk[0] = 0x40; /* function */
716 ret_ax = isa_pnp_thunk_and_call();
718 fprintf(stderr,"WARNING: Thunk and call failed\n");
721 if ((ret_ax&0xFF) == 0) _fmemcpy(a,rb_a,sizeof(struct isapnp_pnp_isa_cfg));
728 /* UPDATE 2011/05/27: Holy shit, found an ancient Pentium Pro system who's BIOS implements the ESCD functions! */
729 unsigned int isa_pnp_bios_get_escd_info(unsigned int far *min_escd_write_size,unsigned int far *escd_size,unsigned long far *nv_storage_base) {
730 /* use the DOS segment we allocated as a "trampoline" for the 16-bit code to write the return values to */
731 /* SEG:0x0000 = a (node)
732 * SEG:0x00F0 = stack for passing params
733 * SEG:0x0100 = b (buffer for xfer)
734 * SEF:0x0FFF = end */
735 unsigned short *rb_a = (unsigned short*)((unsigned char*)isa_pnp_rm_call_area + 0x200);
736 unsigned short *rb_b = (unsigned short*)((unsigned char*)isa_pnp_rm_call_area + 0x204);
737 unsigned long *rb_c = (unsigned long*)((unsigned char*)isa_pnp_rm_call_area + 0x208);
738 unsigned short *stk = (unsigned short*)((unsigned char*)isa_pnp_rm_call_area + 0x1F0);
739 unsigned short sgm = isa_pnp_pm_use ? (unsigned short)isa_pnp_rm_call_area_sel : (unsigned short)((size_t)isa_pnp_rm_call_area >> 4);
740 unsigned int ret_ax = ~0;
746 stk[7] = isa_pnp_pm_use ? (unsigned short)isa_pnp_pm_data_seg : (unsigned short)isa_pnp_info.rm_ent_data_segment; /* BIOS data segment */
748 stk[6] = sgm; /* offset of "c" */
751 stk[4] = sgm; /* offset of "b" */
754 stk[2] = sgm; /* offset of "a" */
757 stk[0] = 0x41; /* function */
759 ret_ax = isa_pnp_thunk_and_call();
761 fprintf(stderr,"WARNING: Thunk and call failed\n");
764 if ((ret_ax&0xFF) == 0) {
765 *min_escd_write_size = *rb_a;
767 *nv_storage_base = *rb_c;
775 unsigned int isa_pnp_bios_send_message(unsigned int msg) {
776 /* use the DOS segment we allocated as a "trampoline" for the 16-bit code to write the return values to */
777 /* SEG:0x0000 = a (node)
778 * SEG:0x00F0 = stack for passing params
779 * SEG:0x0100 = b (buffer for xfer)
780 * SEF:0x0FFF = end */
781 unsigned short *stk = (unsigned short*)((unsigned char*)isa_pnp_rm_call_area + 0x1F0);
782 unsigned int ret_ax = ~0;
784 stk[2] = isa_pnp_pm_use ? (unsigned short)isa_pnp_pm_data_seg : (unsigned short)isa_pnp_info.rm_ent_data_segment; /* BIOS data segment */
787 stk[0] = 0x04; /* function */
789 ret_ax = isa_pnp_thunk_and_call();
791 fprintf(stderr,"WARNING: Thunk and call failed\n");
802 void isa_pnp_product_id_to_str(char *str,unsigned long id) {
803 sprintf(str,"%c%c%c%X%X%X%X",
804 (unsigned char)(0x40+((id>>2)&0x1F)),
805 (unsigned char)(0x40+((id&3)<<3)+((id>>13)&7)),
806 (unsigned char)(0x40+((id>>8)&0x1F)),
807 (unsigned char)((id>>20)&0xF),
808 (unsigned char)((id>>16)&0xF),
809 (unsigned char)((id>>28)&0xF),
810 (unsigned char)((id>>24)&0xF));
813 const char *isapnp_tag_str(uint8_t tag) { /* tag from struct isapnp_tag NOT the raw byte */
814 if (tag >= (sizeof(isapnp_tag_strs)/sizeof(isapnp_tag_strs[0])))
817 return isapnp_tag_strs[tag];
820 const char *isapnp_sdf_priority_str(uint8_t x) {
821 if (x >= 3) return NULL;
822 return isapnp_sdf_priority_strs[x];
825 int isapnp_read_tag(uint8_t far **pptr,uint8_t far *fence,struct isapnp_tag *tag) {
826 uint8_t far *ptr = *pptr;
833 if (c & 0x80) { /* large tag */
834 tag->tag = 0x10 + (c & 0x7F);
835 tag->len = *((uint16_t far*)(ptr));
842 else { /* small tag */
843 tag->tag = (c >> 3) & 0xF;
855 const char *isa_pnp_device_category(uint32_t productid) {
856 char tmp[8]; isa_pnp_product_id_to_str(tmp,productid);
857 if (!memcmp(tmp,"PNP",3)) {
859 case '0': switch(tmp[4]) {
860 case '0': return "System device, interrupt controller";
861 case '1': return "System device, timer";
862 case '2': return "System device, DMA controller";
863 case '3': return "System device, keyboard";
864 case '4': return "System device, parallel port";
865 case '5': return "System device, serial port";
866 case '6': return "System device, hard disk controller";
867 case '7': return "System device, floppy disk controller";
868 case '9': return "System device, display adapter";
869 case 'A': return "System device, peripheral bus";
870 case 'C': return "System device, motherboard device";
871 case 'E': return "System device, PCMCIA controller";
872 case 'F': return "System device, mouse";
873 default: return "System devices";
875 case '8': return "Network devices";
876 case 'A': return "SCSI & non-standard CD-ROM devices";
877 case 'B': return "Sound, video & multimedia";
878 case 'C': return "Modem devices";
885 void isa_pnp_device_description(char desc[255],uint32_t productid) {
886 char tmp[8]; isa_pnp_product_id_to_str(tmp,productid);
889 if (!memcmp(tmp,"PNP",3)) {
890 unsigned int hex = (unsigned int)strtol(tmp+3,0,16),hexm = 0;
891 const char *rets = NULL,**arr = NULL;
892 unsigned int ars = 0;
896 else if (hex == 0x0B00) {
897 rets = "Realtime clock";
899 else if (hex == 0x09FF) {
900 rets = "Plug & Play DDC monitor";
905 case a: ars = sizeof(isa_pnp_devd_pnp_##a##xx)/sizeof(isa_pnp_devd_pnp_##a##xx[0]); arr = isa_pnp_devd_pnp_##a##xx; hexm = 0xFF; break
906 PNP(0x00); /* PNP00xx */ PNP(0x01); /* PNP01xx */
907 PNP(0x02); /* PNP02xx */ PNP(0x03); /* PNP03xx */
908 PNP(0x04); /* PNP04xx */ PNP(0x05); /* PNP05xx */
909 PNP(0x06); /* PNP06xx */ PNP(0x07); /* PNP07xx */
910 PNP(0x09); /* PNP09xx */ PNP(0x0A); /* PNP0Axx */
911 PNP(0x0C); /* PNP0Cxx */ PNP(0x0E); /* PNP0Exx */
912 PNP(0x0F); /* PNP0Fxx */
917 if (rets == NULL && ars != (size_t)0 && arr != NULL && (hex&hexm) < ars)
918 rets = arr[hex&hexm];
925 const char *isa_pnp_device_type(const uint8_t far *b,const char **subtype,const char **inttype) {
926 const char *st = NULL;
927 const char *it = NULL;
928 const char *t = NULL;
931 case 1: t = "Mass Storage Device";
933 case 0: st = "SCSI controller"; break;
934 case 1: st = "IDE controller (Standard ATA compatible)";
936 case 0: it = "Generic IDE"; break;
939 case 2: st = "Floppy controller (Standard 765 compatible)";
941 case 0: it = "Generic floppy"; break;
944 case 3: st = "IPI controller";
946 case 0: it = "Generic"; break;
954 case 2: t = "Network Interface Controller";
956 case 0: st = "Ethernet controller";
958 case 0: it = "Generic"; break;
961 case 1: st = "Token ring controller";
963 case 0: it = "Generic"; break;
966 case 2: st = "FDDI controller";
968 case 0: it = "Generic"; break;
976 case 3: t = "Display Controller";
978 case 0: st = "VGA controller (Standard VGA compatible)";
980 case 0: it = "Generic VGA compatible"; break;
981 case 1: it = "VESA SVGA compatible"; break;
984 case 1: st = "XGA compatible controller";
986 case 0: it = "General XGA compatible"; break;
994 case 4: t = "Multimedia Controller";
996 case 0: st = "Video controller";
998 case 0: it = "General video"; break;
1001 case 1: st = "Audio controller";
1003 case 0: it = "General audio"; break;
1011 case 5: t = "Memory";
1015 case 0: it = "General RAM"; break;
1018 case 1: st = "Flash memory";
1020 case 0: it = "General flash memory"; break;
1028 case 6: t = "Bridge controller";
1030 case 0: st = "Host processor bridge";
1032 case 0: it = "General"; break;
1035 case 1: st = "ISA bridge";
1037 case 0: it = "General"; break;
1040 case 2: st = "EISA bridge";
1042 case 0: it = "General"; break;
1045 case 3: st = "MCA bridge";
1047 case 0: it = "General"; break;
1050 case 4: st = "PCI bridge";
1052 case 0: it = "General"; break;
1055 case 5: st = "PCMCIA bridge";
1057 case 0: it = "General"; break;
1065 case 7: t = "Communications device";
1067 case 0: st = "RS-232";
1069 case 0: it = "Generic"; break;
1070 case 1: it = "16450-compatible"; break;
1071 case 2: it = "16550-compatible"; break;
1074 case 1: st = "Parallel port (AT compatible)";
1076 case 0: it = "General"; break;
1077 case 1: it = "Model 30 bidirectional port"; break;
1078 case 2: it = "ECP 1.x port"; break;
1086 case 8: t = "System peripheral";
1088 case 0: st = "Programmable Interrupt Controller (8259 compatible)";
1090 case 0: it = "Generic"; break;
1091 case 1: it = "ISA"; break;
1092 case 2: it = "EISA"; break;
1095 case 1: st = "DMA controller (8237 compatible)";
1097 case 0: it = "General"; break;
1098 case 1: it = "ISA"; break;
1099 case 2: it = "EISA"; break;
1102 case 2: st = "System Timer (8254 compatible)";
1104 case 0: it = "General"; break;
1105 case 1: it = "ISA"; break;
1106 case 2: it = "EISA"; break;
1109 case 3: st = "Real-time clock";
1111 case 0: it = "Generic"; break;
1112 case 1: it = "ISA"; break;
1120 case 9: t = "Input device";
1122 case 0: st = "Keyboard controller";
1124 case 0: it = "N/A"; break;
1127 case 1: st = "Digitizer (pen)";
1129 case 0: it = "N/A"; break;
1132 case 2: st = "Mouse controller";
1134 case 0: it = "N/A"; break;
1142 case 10: t = "Docking station";
1144 case 0: st = "Generic";
1146 case 0: it = "N/A"; break;
1154 case 11: t = "CPU type";
1158 case 0: it = "N/A"; break;
1163 case 0: it = "N/A"; break;
1168 case 0: it = "N/A"; break;
1179 if (subtype != NULL)
1181 if (inttype != NULL)
1187 void isa_pnp_init_key() {
1191 isa_pnp_write_address(0);
1192 for (i=0;i < 32;i++)
1193 isa_pnp_write_address(isa_pnp_init_keystring[i]);
1195 /* software must delay 1ms prior to starting the first pair of isolation reads and must wait
1196 * 250us between each subsequent pair of isolation reads. this delay gives the ISA card time
1197 * to access information for possibly very slow storage devices */
1198 t8254_wait(t8254_us2ticks(1200));
1201 void isa_pnp_wake_csn(unsigned char id) {
1202 isa_pnp_write_address(3); /* Wake[CSN] */
1203 isa_pnp_write_data(id); /* isolation state */
1206 /* the caller is expected to specify which card by calling isa_pnp_wake_csn() */
1207 int isa_pnp_init_key_readback(unsigned char *data/*9 bytes*/) {
1208 unsigned char checksum = 0x6a;
1209 unsigned char b,c1,c2,bit;
1212 isa_pnp_write_address(1); /* serial isolation reg */
1213 for (i=0;i < 9;i++) {
1215 for (j=0;j < 8;j++) {
1216 c1 = isa_pnp_read_data();
1217 c2 = isa_pnp_read_data();
1218 if (c1 == 0x55 && c2 == 0xAA) {
1227 checksum = ((((checksum ^ (checksum >> 1)) & 1) ^ bit) << 7) | (checksum >> 1);
1229 t8254_wait(t8254_us2ticks(275));
1234 return (checksum == data[8]);
1237 void isa_pnp_set_read_data_port(uint16_t port) {
1238 isa_pnp_write_address(0x00); /* RD_DATA port */
1239 isa_pnp_write_data(port >> 2);
1242 unsigned char isa_pnp_read_config() {
1243 unsigned int patience = 20;
1244 unsigned char ret = 0xFF;
1247 isa_pnp_write_address(0x05);
1248 if (isa_pnp_read_data() & 1) {
1249 isa_pnp_write_address(0x04);
1250 ret = isa_pnp_read_data();
1254 if (--patience == 0) break;
1255 t8254_wait(t8254_us2ticks(100));
1261 uint8_t isa_pnp_read_data_register(uint8_t x) {
1262 isa_pnp_write_address(x);
1263 return isa_pnp_read_data();
1266 void isa_pnp_write_data_register(uint8_t x,uint8_t data) {
1267 isa_pnp_write_address(0x00);
1268 isa_pnp_write_address(x);
1269 isa_pnp_write_data(data);
1272 int isa_pnp_read_io_resource(unsigned int i) {
1275 if (i >= 8) return -1;
1276 ret = (uint16_t)isa_pnp_read_data_register(0x60 + (i*2)) << 8;
1277 ret |= (uint16_t)isa_pnp_read_data_register(0x60 + (i*2) + 1);
1281 void isa_pnp_write_io_resource(unsigned int i,uint16_t port) {
1283 isa_pnp_write_data_register(0x60 + (i*2),port >> 8);
1284 isa_pnp_write_data_register(0x60 + (i*2) + 1,port);
1285 t8254_wait(t8254_us2ticks(250));
1288 int isa_pnp_read_irq(unsigned int i) {
1291 if (i >= 2) return -1;
1292 c = isa_pnp_read_data_register(0x70 + (i*2));
1293 if (c == 0xFF) return -1;
1294 if ((c & 15) == 0) return -1; /* not assigned */
1298 void isa_pnp_write_irq(unsigned int i,int irq) {
1300 if (irq < 0) irq = 0;
1301 isa_pnp_write_data_register(0x70 + (i*2),irq);
1302 t8254_wait(t8254_us2ticks(250));
1305 void isa_pnp_write_irq_mode(unsigned int i,unsigned int im) {
1307 isa_pnp_write_data_register(0x70 + (i*2) + 1,im);
1308 t8254_wait(t8254_us2ticks(250));
1311 int isa_pnp_read_dma(unsigned int i) {
1314 if (i >= 2) return -1;
1315 c = isa_pnp_read_data_register(0x74 + i);
1316 if (c == 0xFF) return -1;
1317 if ((c & 7) == 4) return -1; /* not assigned */
1321 void isa_pnp_write_dma(unsigned int i,int dma) {
1323 if (dma < 0) dma = 4;
1324 isa_pnp_write_data_register(0x74 + i,dma);
1325 t8254_wait(t8254_us2ticks(250));