2 * AcessOS/AcessBasic v0.1
\r
9 #include <fs_devfs.h>
\r
10 #include <drv_pci.h>
\r
12 #define LIST_DEVICES 1
\r
14 // === STRUCTURES ===
\r
15 typedef struct sPCIDevice
\r
17 Uint16 bus, slot, fcn;
\r
18 Uint16 vendor, device;
\r
21 Uint8 class, subclass;
\r
26 Uint32 ConfigCache[256/4];
\r
31 // === CONSTANTS ===
\r
32 #define SPACE_STEP 5
\r
33 #define MAX_RESERVED_PORT 0xD00
\r
35 // === PROTOTYPES ===
\r
36 int PCI_Install(char **Arguments);
\r
37 int PCI_ScanBus(int ID);
\r
39 char *PCI_ReadDirRoot(tVFS_Node *node, int pos);
\r
40 tVFS_Node *PCI_FindDirRoot(tVFS_Node *node, char *filename);
\r
41 Uint64 PCI_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer);
\r
43 int PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn);
\r
44 int PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, int idx);
\r
45 int PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int prev);
\r
46 Uint8 PCI_GetIRQ(int id);
\r
47 Uint32 PCI_GetBAR0(int id);
\r
48 Uint32 PCI_GetBAR1(int id);
\r
49 Uint32 PCI_GetBAR3(int id);
\r
50 Uint32 PCI_GetBAR4(int id);
\r
51 Uint32 PCI_GetBAR5(int id);
\r
52 Uint16 PCI_AssignPort(int id, int bar, int count);
\r
54 int PCI_EnumDevice(Uint16 bus, Uint16 dev, Uint16 fcn, tPCIDevice *info);
\r
55 Uint32 PCI_CfgReadDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset);
\r
56 void PCI_CfgWriteDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset, Uint32 data);
\r
57 Uint16 PCI_CfgReadWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset);
\r
58 Uint8 PCI_CfgReadByte(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset);
\r
61 MODULE_DEFINE(0, 0x0100, PCI, PCI_Install, NULL, NULL);
\r
62 int giPCI_BusCount = 1;
\r
63 int giPCI_InodeHandle = -1;
\r
64 int giPCI_DeviceCount = 0;
\r
65 tPCIDevice *gPCI_Devices = NULL;
\r
66 tDevFS_Driver gPCI_DriverStruct = {
\r
69 .Flags = VFS_FFLAG_DIRECTORY,
\r
72 .ACLs = &gVFS_ACL_EveryoneRX,
\r
73 .ReadDir = PCI_ReadDirRoot,
\r
74 .FindDir = PCI_FindDirRoot
\r
77 Uint32 *gaPCI_PortBitmap = NULL;
\r
78 Uint32 gaPCI_BusBitmap[256/32];
\r
82 * \fn int PCI_Install()
\r
83 * \brief Scan the PCI Bus for devices
\r
85 int PCI_Install(char **Arguments)
\r
91 gaPCI_PortBitmap = malloc( 1 << 13 );
\r
92 if( !gaPCI_PortBitmap ) {
\r
93 Log_Error("PCI", "Unable to allocate %i bytes for bitmap", 1 << 13);
\r
94 return MODULE_ERR_MALLOC;
\r
96 memset( gaPCI_PortBitmap, 0, 1 << 13 );
\r
97 for( i = 0; i < MAX_RESERVED_PORT / 32; i ++ )
\r
98 gaPCI_PortBitmap[i] = -1;
\r
99 for( i = 0; i < MAX_RESERVED_PORT % 32; i ++ )
\r
100 gaPCI_PortBitmap[MAX_RESERVED_PORT / 32] = 1 << i;
\r
103 i = PCI_ScanBus(0);
\r
104 if(i != MODULE_ERR_OK) return i;
\r
106 if(giPCI_DeviceCount == 0) {
\r
107 Log_Notice("PCI", "No devices were found");
\r
108 return MODULE_ERR_NOTNEEDED;
\r
111 // Ensure the buffer is nice and tight
\r
112 tmpPtr = realloc(gPCI_Devices, giPCI_DeviceCount*sizeof(tPCIDevice));
\r
114 return MODULE_ERR_MALLOC;
\r
115 gPCI_Devices = tmpPtr;
\r
117 // Complete Driver Structure
\r
118 gPCI_DriverStruct.RootNode.Size = giPCI_DeviceCount;
\r
120 // And add to DevFS
\r
121 DevFS_AddDevice(&gPCI_DriverStruct);
\r
123 return MODULE_ERR_OK;
\r
127 * \brief Scans a specific PCI Bus
\r
129 int PCI_ScanBus(int BusID)
\r
132 tPCIDevice devInfo;
\r
133 void *tmpPtr = NULL;
\r
135 if( gaPCI_BusBitmap[BusID/32] & (1 << (BusID%32)) )
\r
136 return MODULE_ERR_OK;
\r
138 gaPCI_BusBitmap[BusID/32] |= (1 << (BusID%32));
\r
140 for( dev = 0; dev < 32; dev++ ) // 32 Devices per bus
\r
142 for( fcn = 0; fcn < 8; fcn++ ) // Max 8 functions per device
\r
144 // Check if the device/function exists
\r
145 if(!PCI_EnumDevice(BusID, dev, fcn, &devInfo))
\r
149 tmpPtr = realloc(gPCI_Devices, (giPCI_DeviceCount+1)*sizeof(tPCIDevice));
\r
151 return MODULE_ERR_MALLOC;
\r
152 gPCI_Devices = tmpPtr;
\r
154 if(devInfo.oc == PCI_OC_PCIBRIDGE)
\r
157 Log_Log("PCI", "Bridge @ %i,%i:%i (0x%x:0x%x)",
\r
158 BusID, dev, fcn, devInfo.vendor, devInfo.device);
\r
160 //TODO: Handle PCI-PCI Bridges
\r
167 Log_Log("PCI", "Device %i,%i:%i %04x => 0x%04x:0x%04x",
\r
168 BusID, dev, fcn, devInfo.oc, devInfo.vendor, devInfo.device);
\r
172 devInfo.Node.Inode = giPCI_DeviceCount;
\r
173 memcpy(&gPCI_Devices[giPCI_DeviceCount], &devInfo, sizeof(tPCIDevice));
\r
174 giPCI_DeviceCount ++;
\r
176 // WTF is this for?
\r
177 // Maybe bit 23 must be set for the device to be valid?
\r
178 // - Actually, maybe 23 means that there are sub-functions
\r
180 if( !(devInfo.ConfigCache[3] & 0x00800000) )
\r
186 return MODULE_ERR_OK;
\r
190 * \fn char *PCI_ReadDirRoot(tVFS_Node *Node, int Pos)
\r
191 * \brief Read from Root of PCI Driver
\r
193 char *PCI_ReadDirRoot(tVFS_Node *Node, int Pos)
\r
195 ENTER("pNode iPos", Node, Pos);
\r
196 if(Pos < 0 || Pos >= giPCI_DeviceCount) {
\r
201 LEAVE('s', gPCI_Devices[Pos].Name);
\r
202 return strdup( gPCI_Devices[Pos].Name );
\r
205 * \fn tVFS_Node *PCI_FindDirRoot(tVFS_Node *node, char *filename)
\r
207 tVFS_Node *PCI_FindDirRoot(tVFS_Node *node, char *filename)
\r
211 // Validate Filename (Pointer and length)
\r
212 if(!filename || strlen(filename) != 7)
\r
214 // Check for spacers
\r
215 if(filename[2] != '.' || filename[5] != ':')
\r
219 if(filename[0] < '0' || filename[0] > '9') return NULL;
\r
220 bus = (filename[0] - '0')*10;
\r
221 if(filename[1] < '0' || filename[1] > '9') return NULL;
\r
222 bus += filename[1] - '0';
\r
223 if(filename[3] < '0' || filename[3] > '9') return NULL;
\r
224 slot = (filename[3] - '0')*10;
\r
225 if(filename[4] < '0' || filename[4] > '9') return NULL;
\r
226 slot += filename[4] - '0';
\r
227 if(filename[6] < '0' || filename[6] > '9') return NULL;
\r
228 fcn = filename[6] - '0';
\r
231 for(i=0;i<giPCI_DeviceCount;i++)
\r
233 if(gPCI_Devices[i].bus != bus) continue;
\r
234 if(gPCI_Devices[i].slot != slot) continue;
\r
235 if(gPCI_Devices[i].fcn != fcn) continue;
\r
237 return &gPCI_Devices[i].Node;
\r
245 * \fn Uint64 PCI_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer)
\r
247 Uint64 PCI_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer)
\r
249 if( pos + length > 256 ) return 0;
\r
253 (char*)gPCI_Devices[node->Inode].ConfigCache + pos,
\r
259 // --- Kernel Code Interface ---
\r
261 \fn int PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn)
\r
262 \brief Counts the devices with the specified codes
\r
263 \param vendor Vendor ID
\r
264 \param device Device ID
\r
265 \param fcn Function ID
\r
267 int PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn)
\r
270 for(i=0;i<giPCI_DeviceCount;i++)
\r
272 if(gPCI_Devices[i].vendor != vendor) continue;
\r
273 if(gPCI_Devices[i].device != device) continue;
\r
274 if(gPCI_Devices[i].fcn != fcn) continue;
\r
281 \fn int PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, int idx)
\r
282 \brief Gets the ID of the specified PCI device
\r
283 \param vendor Vendor ID
\r
284 \param device Device ID
\r
285 \param fcn Function IDs
\r
286 \param idx Number of matching entry wanted
\r
288 int PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, int idx)
\r
291 for(i=0;i<giPCI_DeviceCount;i++)
\r
293 if(gPCI_Devices[i].vendor != vendor) continue;
\r
294 if(gPCI_Devices[i].device != device) continue;
\r
295 if(gPCI_Devices[i].fcn != fcn) continue;
\r
296 if(j == idx) return i;
\r
303 * \fn int PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int prev)
\r
304 * \brief Gets the ID of a device by it's class code
\r
305 * \param class Class Code
\r
306 * \param mask Mask for class comparison
\r
307 * \param prev ID of previous device (-1 for no previous)
\r
309 int PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int prev)
\r
312 // Check if prev is negative (meaning get first)
\r
313 if(prev < 0) i = 0;
\r
316 for( ; i < giPCI_DeviceCount; i++ )
\r
318 if((gPCI_Devices[i].oc & mask) == class)
\r
325 \fn Uint8 PCI_GetIRQ(int id)
\r
327 Uint8 PCI_GetIRQ(int id)
\r
329 if(id < 0 || id >= giPCI_DeviceCount)
\r
331 return gPCI_Devices[id].ConfigCache[15];
\r
332 //return PCI_CfgReadByte( gPCI_Devices[id].bus, gPCI_Devices[id].slot, gPCI_Devices[id].fcn, 0x3C);
\r
336 \fn Uint32 PCI_GetBAR0(int id)
\r
338 Uint32 PCI_GetBAR0(int id)
\r
340 if(id < 0 || id >= giPCI_DeviceCount)
\r
342 return gPCI_Devices[id].ConfigCache[4];
\r
346 \fn Uint32 PCI_GetBAR1(int id)
\r
348 Uint32 PCI_GetBAR1(int id)
\r
350 if(id < 0 || id >= giPCI_DeviceCount)
\r
352 return gPCI_Devices[id].ConfigCache[5];
\r
356 \fn Uint32 PCI_GetBAR2(int id)
\r
358 Uint32 PCI_GetBAR2(int id)
\r
360 if(id < 0 || id >= giPCI_DeviceCount)
\r
362 return gPCI_Devices[id].ConfigCache[6];
\r
366 \fn Uint32 PCI_GetBAR3(int id)
\r
368 Uint32 PCI_GetBAR3(int id)
\r
370 if(id < 0 || id >= giPCI_DeviceCount)
\r
372 return gPCI_Devices[id].ConfigCache[7];
\r
376 \fn Uint32 PCI_GetBAR4(int id)
\r
378 Uint32 PCI_GetBAR4(int id)
\r
380 if(id < 0 || id >= giPCI_DeviceCount)
\r
382 return gPCI_Devices[id].ConfigCache[8];
\r
386 \fn Uint32 PCI_GetBAR5(int id)
\r
388 Uint32 PCI_GetBAR5(int id)
\r
390 if(id < 0 || id >= giPCI_DeviceCount)
\r
392 return gPCI_Devices[id].ConfigCache[9];
\r
395 Uint16 PCI_AssignPort(int id, int bar, int count)
\r
402 //LogF("PCI_AssignPort: (id=%i,bar=%i,count=%i)\n", id, bar, count);
\r
404 if(id < 0 || id >= giPCI_DeviceCount) return 0;
\r
405 if(bar < 0 || bar > 5) return 0;
\r
407 dev = &gPCI_Devices[id];
\r
409 PCI_CfgWriteDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4, -1 );
\r
410 portVals = PCI_CfgReadDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4 );
\r
411 dev->ConfigCache[4+bar] = portVals;
\r
412 //LogF(" PCI_AssignPort: portVals = 0x%x\n", portVals);
\r
414 // Check for IO port
\r
415 if( !(portVals & 1) ) return 0;
\r
417 // Mask out final bit
\r
421 __asm__ __volatile__ ("bsf %%eax, %%ecx" : "=c" (gran) : "a" (portVals) );
\r
423 //LogF(" PCI_AssignPort: gran = 0x%x\n", gran);
\r
427 for( i = 0; i < 1<<16; i += gran )
\r
429 for( j = 0; j < count; j ++ )
\r
431 if( gaPCI_PortBitmap[ (i+j)>>5 ] & 1 << ((i+j)&0x1F) )
\r
442 for( j = 0; j < count; j ++ )
\r
444 if( gaPCI_PortBitmap[ (portVals+j)>>5 ] |= 1 << ((portVals+j)&0x1F) )
\r
447 PCI_CfgWriteDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4, portVals|1 );
\r
448 dev->ConfigCache[4+bar] = portVals|1;
\r
452 //LogF("PCI_AssignPort: RETURN 0x%x\n", portVals);
\r
457 * \fn int PCI_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, tPCIDevice *info)
\r
459 int PCI_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, tPCIDevice *info)
\r
464 vendor = PCI_CfgReadWord(bus, slot, fcn, 0x0|0);
\r
465 if(vendor == 0xFFFF) // Invalid Device
\r
471 info->vendor = vendor;
\r
472 info->device = PCI_CfgReadWord(bus, slot, fcn, 0x0|2);
\r
473 info->revision = PCI_CfgReadWord(bus, slot, fcn, 0x8|0);
\r
474 info->oc = PCI_CfgReadWord(bus, slot, fcn, 0x8|2);
\r
476 // Load Config Bytes
\r
477 for(i=0;i<256/4;i++)
\r
479 info->ConfigCache[i] = PCI_CfgReadDWord(bus, slot, fcn, i*4);
\r
483 //Log("BAR0 0x%08x BAR1 0x%08x BAR2 0x%08x", info->ConfigCache[4], info->ConfigCache[5], info->ConfigCache[6]);
\r
484 //Log("BAR3 0x%08x BAR4 0x%08x BAR5 0x%08x", info->ConfigCache[7], info->ConfigCache[8], info->ConfigCache[9]);
\r
485 //Log("Class: 0x%04x", info->oc);
\r
489 info->Name[0] = '0' + bus/10;
\r
490 info->Name[1] = '0' + bus%10;
\r
491 info->Name[2] = '.';
\r
492 info->Name[3] = '0' + slot/10;
\r
493 info->Name[4] = '0' + slot%10;
\r
494 info->Name[5] = ':';
\r
495 info->Name[6] = '0' + fcn;
\r
496 info->Name[7] = '\0';
\r
499 memset( &info->Node, 0, sizeof(tVFS_Node) );
\r
500 info->Node.Size = 256;
\r
502 info->Node.NumACLs = 1;
\r
503 info->Node.ACLs = &gVFS_ACL_EveryoneRO;
\r
505 info->Node.Read = PCI_ReadDevice;
\r
510 Uint32 PCI_CfgReadDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset)
\r
515 bus &= 0xFF; // 8 Bits
\r
516 dev &= 0x1F; // 5 Bits
\r
517 func &= 0x7; // 3 Bits
\r
518 offset &= 0xFF; // 8 Bits
\r
520 address = 0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC);
\r
521 outd(0xCF8, address);
\r
524 //Debug("PCI(0x%x) = 0x%08x", address, data);
\r
527 void PCI_CfgWriteDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset, Uint32 data)
\r
531 bus &= 0xFF; // 8 Bits
\r
532 dev &= 0x1F; // 5 Bits
\r
533 func &= 0x7; // 3 Bits
\r
534 offset &= 0xFF; // 8 Bits
\r
536 address = 0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC);
\r
537 outd(0xCF8, address);
\r
540 Uint16 PCI_CfgReadWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset)
\r
542 Uint32 data = PCI_CfgReadDWord(bus, dev, func, offset);
\r
544 data >>= (offset&2)*8; // Allow Access to Upper Word
\r
546 return (Uint16)data;
\r
549 Uint8 PCI_CfgReadByte(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset)
\r
551 Uint32 data = PCI_CfgReadDWord(bus, dev, func, offset);
\r
553 data >>= (offset&3)*8; //Allow Access to Upper Word
\r
554 return (Uint8)data;
\r
560 EXPORT(PCI_CountDevices);
\r
561 EXPORT(PCI_GetDevice);
\r
562 EXPORT(PCI_GetDeviceByClass);
\r
563 EXPORT(PCI_AssignPort);
\r
564 EXPORT(PCI_GetIRQ);
\r