Where can I find programming info :: PCI |
The official PCI web site is located at www.pcisig.com
This PCI Special Interest Group site contains a little information on PCI as Microsoft Word 6 document files which are the official specifications, it also contains a few test/diagnostic programs in C for working with PCI that you can download and also they keep a list of Vendor ID numbers but not product ID numbers. Alternatively, two good sites that seem to be the mainstay for collecting a database on Equipment vendor ID's and Product ID's are; Craig "Merlin" Hart's PCI page http://members.hyperlink.net.au/~chart/pci.htm |
I heard you can do PCI BIOS calls in pmode? |
True! You can call the PCI bios functions from pmode and its quite easy to do, and it does not require any mode switching back into real-mode to do it.
First thing is, you have to locate the BIOS32 service directory entry point. This is done by scanning for the 4 bytes of "magic" that is "_32_" (0x5F32335F). The BIOS32 SD can lie in memory from 0xE0000 to 0x100000 and it always lies on a paragraph alignment. CALL xxxxh:xxxxh - BIOS32 Service Directory InstallCheck: scan paragraph boundaries E000h to FFFFh for signature string "_32_", followed by a valid header structure (see #F0021) Notes: a 32-bit-code alternate PCI BIOS entry point may be found (if supported) by requesting the entry point for the API with identifier "$PCI". an alternate entry point for INT 1A/AH=B4h may be found (if supported) by requesting the entry point for the API with identifier "$ACF" other known identifiers are "$WDS" and "MPTN" SeeAlso: INT 1A/AX=B100h Format of BIOS32 Service Directory header structure: Offset Size Description (Table F0021) 00h 4 BYTEs signature "_32_" 04h DWORD physical address of BSD entry point (see #F0022) 08h BYTE header structure version number (currently 00h) 09h BYTE header structure length in paragraphs (currently 01h) 0Ah BYTE checksum (8-bit sum of all bytes in structure, including this one, should equal zero) 0Bh 5 BYTEs reserved (0) (Table F0022) Call BIOS32 Service Directory entry point with: EBX = function 00000000h get service entry point EAX = service identifier 46434124h ("FCA$") Plug-and-Play Auto-Configuration 49435024h ("ICP$") PCI BIOS 4E54504Dh ("NTPM") ??? MPTN [PhoenixBIOS4 Rev. 6.0] 54435724h ("SDW$") ??? WDS$ [PhoenixBIOS4 Rev. 6.0] Return: AL = status 00h successful EBX = base address of handler's code seg ECX = size of code segment EDX = offset of handler in code seg 80h unknown service identifier else Return: AL = 81h invalid function Notes: the BSD handler assumes that it is running in a 32-bit code segment the returned entry points for PCI BIOS and Auto-Config must be called with the same registers as the real-mode INT 1Ah interface, including the value B1h or B4h in AH (AMI BIOS v1.00.05.AX1 returns the same entry point for both interfaces and uses AH to distinguish which API is desired) some references indicate that only BL is used for the function number, though at least one implementation actually checks the entire EBX register; for maximum compatibility, the upper 24 bits of EBX should be cleared when calling the entry pointHere is an example of detecting the BIOS32 service directory. typedef struct BIOS32 { ULONG magic __attribute__ ((packed)); ULONG phys_bsd_entry __attribute__ ((packed)); UCHAR vers __attribute__ ((packed)); UCHAR prg_lens __attribute__ ((packed)); UCHAR crc __attribute__ ((packed)); } BIOS32; BIOS32 *master_bios32; ULONG bios32_call; UCHAR search_pci_bios(void) { UCHAR *p=(UCHAR*)0xE0000; BIOS32 *x; UCHAR flag=0; UCHAR crc; int i; master_bios32=NULL; bios32_call=0; while(flag==0 && (ULONG)p<0X100000) { X=(BIOS32*)P; IF(X->magic==0x5F32335F) /* _32_ */ { for(i=0, crc=0; i<(X->prg_lens*16); i++) crc+=*(p+i); if(crc==0) { flag=1; master_bios32=x; bios32_call=master_bios32->phys_bsd_entry; } } else p+=0x10; } }Once you have located the service directory you can do a far call to its physical entry point and ask it if PCI bios32 calls exist. (PCI v2.0c+) void bios32_scan_pci_entry(void) { ULONG cseg_size, offset, base_addr; /* call the BIOS32 BSD for the PCI address BSD calls terminate in RETF not RET */ /* eax is loaded with "$PCI" magic */ asm("movl $0x49435024, %%eax\n" "xorl %%ebx, %%ebx\n" "movl _bios32_call, %%ebp\n" "pushl %%cs\n" "call %%ebp\n" : "=c" (cseg_size), "=d" (offset), "=b" (base_addr) : : "eax", "ebx", "ecx", "edx", "ebp", "memory" ); /* setup two new selectors of pci_code32, pci_data32, etc. */ }Once you have determined that PCI v2.0c+ BIOS calls exist for pmode applications, you can call the PCI v2.0c+ calls (see INT 0x1A, function 0xB101 down to 0xB18F in Ralf Brown's INT List). |