2 * AcessOS/AcessBasic v0.1
\r
9 #include <fs_devfs.h>
\r
10 #include <drv_pci.h>
\r
12 #define LIST_DEVICES 1
\r
15 extern Uint32 PCI_CfgReadDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset);
\r
16 extern void PCI_CfgWriteDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset, Uint32 data);
\r
17 extern Uint16 PCI_CfgReadWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset);
\r
18 extern Uint8 PCI_CfgReadByte(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset);
\r
20 // === STRUCTURES ===
\r
21 typedef struct sPCIDevice
\r
23 Uint16 bus, slot, fcn;
\r
24 Uint16 vendor, device;
\r
27 Uint8 class, subclass;
\r
32 Uint32 ConfigCache[256/4];
\r
37 // === CONSTANTS ===
\r
38 #define SPACE_STEP 5
\r
39 #define MAX_RESERVED_PORT 0xD00
\r
41 // === PROTOTYPES ===
\r
42 int PCI_Install(char **Arguments);
\r
43 int PCI_ScanBus(int ID, int bFill);
\r
45 char *PCI_ReadDirRoot(tVFS_Node *node, int pos);
\r
46 tVFS_Node *PCI_FindDirRoot(tVFS_Node *node, const char *filename);
\r
47 Uint64 PCI_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer);
\r
50 int PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn);
\r
51 int PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, int idx);
\r
52 int PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int prev);
\r
53 Uint8 PCI_GetIRQ(int id);
\r
54 Uint32 PCI_GetBAR0(int id);
\r
55 Uint32 PCI_GetBAR1(int id);
\r
56 Uint32 PCI_GetBAR2(int id);
\r
57 Uint32 PCI_GetBAR3(int id);
\r
58 Uint32 PCI_GetBAR4(int id);
\r
59 Uint32 PCI_GetBAR5(int id);
\r
60 Uint16 PCI_AssignPort(int id, int bar, int count);
\r
63 int PCI_EnumDevice(Uint16 bus, Uint16 dev, Uint16 fcn, tPCIDevice *info);
\r
66 MODULE_DEFINE(0, 0x0100, PCI, PCI_Install, NULL, NULL);
\r
67 int giPCI_BusCount = 1;
\r
68 int giPCI_InodeHandle = -1;
\r
69 int giPCI_DeviceCount = 0;
\r
70 tPCIDevice *gPCI_Devices = NULL;
\r
71 tDevFS_Driver gPCI_DriverStruct = {
\r
74 .Flags = VFS_FFLAG_DIRECTORY,
\r
77 .ACLs = &gVFS_ACL_EveryoneRX,
\r
78 .ReadDir = PCI_ReadDirRoot,
\r
79 .FindDir = PCI_FindDirRoot
\r
82 Uint32 *gaPCI_PortBitmap = NULL;
\r
83 Uint32 gaPCI_BusBitmap[256/32];
\r
87 * \brief Scan the PCI Bus for devices
\r
88 * \param Arguments Boot-time parameters
\r
90 int PCI_Install(char **Arguments)
\r
96 gaPCI_PortBitmap = malloc( 1 << 13 );
\r
97 if( !gaPCI_PortBitmap ) {
\r
98 Log_Error("PCI", "Unable to allocate %i bytes for bitmap", 1 << 13);
\r
99 return MODULE_ERR_MALLOC;
\r
101 memset( gaPCI_PortBitmap, 0, 1 << 13 );
\r
102 for( i = 0; i < MAX_RESERVED_PORT / 32; i ++ )
\r
103 gaPCI_PortBitmap[i] = -1;
\r
104 for( i = 0; i < MAX_RESERVED_PORT % 32; i ++ )
\r
105 gaPCI_PortBitmap[MAX_RESERVED_PORT / 32] = 1 << i;
\r
107 // Scan Bus (Bus 0, Don't fill gPCI_Devices)
\r
108 i = PCI_ScanBus(0, 0);
\r
109 if(i != MODULE_ERR_OK) return i;
\r
111 if(giPCI_DeviceCount == 0) {
\r
112 Log_Notice("PCI", "No devices were found");
\r
113 return MODULE_ERR_NOTNEEDED;
\r
116 // Allocate device buffer
\r
117 tmpPtr = malloc(giPCI_DeviceCount * sizeof(tPCIDevice));
\r
118 if(tmpPtr == NULL) {
\r
119 Log_Warning("PCI", "Malloc ERROR");
\r
120 return MODULE_ERR_MALLOC;
\r
122 gPCI_Devices = tmpPtr;
\r
124 Log_Log("PCI", "%i devices, filling structure", giPCI_DeviceCount);
\r
127 giPCI_DeviceCount = 0;
\r
128 giPCI_BusCount = 0;
\r
129 memset(gaPCI_BusBitmap, 0, sizeof(gaPCI_BusBitmap));
\r
130 // Rescan, filling the PCI device array
\r
133 // Complete Driver Structure
\r
134 gPCI_DriverStruct.RootNode.Size = giPCI_DeviceCount;
\r
136 // And add to DevFS
\r
137 DevFS_AddDevice(&gPCI_DriverStruct);
\r
139 return MODULE_ERR_OK;
\r
143 * \brief Scans a specific PCI Bus
\r
144 * \param BusID PCI Bus ID to scan
\r
145 * \param bFill Fill the \a gPCI_Devices array?
\r
147 int PCI_ScanBus(int BusID, int bFill)
\r
150 tPCIDevice devInfo;
\r
152 if( gaPCI_BusBitmap[BusID/32] & (1 << (BusID%32)) )
\r
153 return MODULE_ERR_OK;
\r
155 gaPCI_BusBitmap[BusID/32] |= (1 << (BusID%32));
\r
157 for( dev = 0; dev < 32; dev++ ) // 32 Devices per bus
\r
159 for( fcn = 0; fcn < 8; fcn++ ) // Max 8 functions per device
\r
161 // Check if the device/function exists
\r
162 if(!PCI_EnumDevice(BusID, dev, fcn, &devInfo))
\r
165 if(devInfo.oc == PCI_OC_PCIBRIDGE)
\r
168 Log_Log("PCI", "Bridge @ %i,%i:%i (0x%x:0x%x)",
\r
169 BusID, dev, fcn, devInfo.vendor, devInfo.device);
\r
171 //TODO: Handle PCI-PCI Bridges
\r
172 //PCI_ScanBus(devInfo.???, bFill);
\r
178 Log_Log("PCI", "Device %i,%i:%i %04x => 0x%04x:0x%04x",
\r
179 BusID, dev, fcn, devInfo.oc, devInfo.vendor, devInfo.device);
\r
184 devInfo.Node.Inode = giPCI_DeviceCount;
\r
185 memcpy(&gPCI_Devices[giPCI_DeviceCount], &devInfo, sizeof(tPCIDevice));
\r
187 giPCI_DeviceCount ++;
\r
189 // If bit 23 of (soemthing) is set, there are sub-functions
\r
190 if(fcn == 0 && !(devInfo.ConfigCache[3] & 0x00800000) )
\r
195 return MODULE_ERR_OK;
\r
199 * \fn char *PCI_ReadDirRoot(tVFS_Node *Node, int Pos)
\r
200 * \brief Read from Root of PCI Driver
\r
202 char *PCI_ReadDirRoot(tVFS_Node *Node, int Pos)
\r
204 ENTER("pNode iPos", Node, Pos);
\r
205 if(Pos < 0 || Pos >= giPCI_DeviceCount) {
\r
210 LEAVE('s', gPCI_Devices[Pos].Name);
\r
211 return strdup( gPCI_Devices[Pos].Name );
\r
214 * \fn tVFS_Node *PCI_FindDirRoot(tVFS_Node *node, const char *filename)
\r
216 tVFS_Node *PCI_FindDirRoot(tVFS_Node *node, const char *filename)
\r
220 // Validate Filename (Pointer and length)
\r
221 if(!filename || strlen(filename) != 7)
\r
223 // Check for spacers
\r
224 if(filename[2] != '.' || filename[5] != ':')
\r
228 if(filename[0] < '0' || filename[0] > '9') return NULL;
\r
229 bus = (filename[0] - '0')*10;
\r
230 if(filename[1] < '0' || filename[1] > '9') return NULL;
\r
231 bus += filename[1] - '0';
\r
232 if(filename[3] < '0' || filename[3] > '9') return NULL;
\r
233 slot = (filename[3] - '0')*10;
\r
234 if(filename[4] < '0' || filename[4] > '9') return NULL;
\r
235 slot += filename[4] - '0';
\r
236 if(filename[6] < '0' || filename[6] > '9') return NULL;
\r
237 fcn = filename[6] - '0';
\r
240 for(i=0;i<giPCI_DeviceCount;i++)
\r
242 if(gPCI_Devices[i].bus != bus) continue;
\r
243 if(gPCI_Devices[i].slot != slot) continue;
\r
244 if(gPCI_Devices[i].fcn != fcn) continue;
\r
246 return &gPCI_Devices[i].Node;
\r
254 * \fn Uint64 PCI_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer)
\r
256 Uint64 PCI_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer)
\r
258 if( pos + length > 256 ) return 0;
\r
262 (char*)gPCI_Devices[node->Inode].ConfigCache + pos,
\r
268 // --- Kernel Code Interface ---
\r
270 \fn int PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn)
\r
271 \brief Counts the devices with the specified codes
\r
272 \param vendor Vendor ID
\r
273 \param device Device ID
\r
274 \param fcn Function ID
\r
276 int PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn)
\r
279 for(i=0;i<giPCI_DeviceCount;i++)
\r
281 if(gPCI_Devices[i].vendor != vendor) continue;
\r
282 if(gPCI_Devices[i].device != device) continue;
\r
283 if(gPCI_Devices[i].fcn != fcn) continue;
\r
290 \fn int PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, int idx)
\r
291 \brief Gets the ID of the specified PCI device
\r
292 \param vendor Vendor ID
\r
293 \param device Device ID
\r
294 \param fcn Function IDs
\r
295 \param idx Number of matching entry wanted
\r
297 int PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, int idx)
\r
300 for(i=0;i<giPCI_DeviceCount;i++)
\r
302 if(gPCI_Devices[i].vendor != vendor) continue;
\r
303 if(gPCI_Devices[i].device != device) continue;
\r
304 if(gPCI_Devices[i].fcn != fcn) continue;
\r
305 if(j == idx) return i;
\r
312 * \fn int PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int prev)
\r
313 * \brief Gets the ID of a device by it's class code
\r
314 * \param class Class Code
\r
315 * \param mask Mask for class comparison
\r
316 * \param prev ID of previous device (-1 for no previous)
\r
318 int PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int prev)
\r
321 // Check if prev is negative (meaning get first)
\r
322 if(prev < 0) i = 0;
\r
325 for( ; i < giPCI_DeviceCount; i++ )
\r
327 if((gPCI_Devices[i].oc & mask) == class)
\r
334 \fn Uint8 PCI_GetIRQ(int id)
\r
336 Uint8 PCI_GetIRQ(int id)
\r
338 if(id < 0 || id >= giPCI_DeviceCount)
\r
340 return gPCI_Devices[id].ConfigCache[15];
\r
341 //return PCI_CfgReadByte( gPCI_Devices[id].bus, gPCI_Devices[id].slot, gPCI_Devices[id].fcn, 0x3C);
\r
345 \fn Uint32 PCI_GetBAR0(int id)
\r
347 Uint32 PCI_GetBAR0(int id)
\r
349 if(id < 0 || id >= giPCI_DeviceCount)
\r
351 return gPCI_Devices[id].ConfigCache[4];
\r
355 \fn Uint32 PCI_GetBAR1(int id)
\r
357 Uint32 PCI_GetBAR1(int id)
\r
359 if(id < 0 || id >= giPCI_DeviceCount)
\r
361 return gPCI_Devices[id].ConfigCache[5];
\r
365 \fn Uint32 PCI_GetBAR2(int id)
\r
367 Uint32 PCI_GetBAR2(int id)
\r
369 if(id < 0 || id >= giPCI_DeviceCount)
\r
371 return gPCI_Devices[id].ConfigCache[6];
\r
375 \fn Uint32 PCI_GetBAR3(int id)
\r
377 Uint32 PCI_GetBAR3(int id)
\r
379 if(id < 0 || id >= giPCI_DeviceCount)
\r
381 return gPCI_Devices[id].ConfigCache[7];
\r
385 \fn Uint32 PCI_GetBAR4(int id)
\r
387 Uint32 PCI_GetBAR4(int id)
\r
389 if(id < 0 || id >= giPCI_DeviceCount)
\r
391 return gPCI_Devices[id].ConfigCache[8];
\r
395 \fn Uint32 PCI_GetBAR5(int id)
\r
397 Uint32 PCI_GetBAR5(int id)
\r
399 if(id < 0 || id >= giPCI_DeviceCount)
\r
401 return gPCI_Devices[id].ConfigCache[9];
\r
404 Uint16 PCI_AssignPort(int id, int bar, int count)
\r
410 if(id < 0 || id >= giPCI_DeviceCount) return 0;
\r
411 if(bar < 0 || bar > 5) return 0;
\r
412 dev = &gPCI_Devices[id];
\r
414 rv = PCI_CfgReadDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4 );
\r
415 if(rv & 1) return rv & ~1;
\r
423 //LogF("PCI_AssignPort: (id=%i,bar=%i,count=%i)\n", id, bar, count);
\r
425 if(id < 0 || id >= giPCI_DeviceCount) return 0;
\r
426 if(bar < 0 || bar > 5) return 0;
\r
428 dev = &gPCI_Devices[id];
\r
430 PCI_CfgWriteDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4, -1 );
\r
431 portVals = PCI_CfgReadDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4 );
\r
432 dev->ConfigCache[4+bar] = portVals;
\r
433 //LogF(" PCI_AssignPort: portVals = 0x%x\n", portVals);
\r
435 // Check for IO port
\r
436 if( !(portVals & 1) ) return 0;
\r
438 // Mask out final bit
\r
442 #if ARCHDIR_IS_x86 || ARCHDIR_IS_x86_64
\r
443 __asm__ __volatile__ ("bsf %%eax, %%ecx" : "=c" (gran) : "a" (portVals) );
\r
447 for(gran = 1; gran && !(portVals & gran); gran <<= 1);
\r
450 //LogF(" PCI_AssignPort: gran = 0x%x\n", gran);
\r
454 for( i = 0; i < 1<<16; i += gran )
\r
456 for( j = 0; j < count; j ++ )
\r
458 if( gaPCI_PortBitmap[ (i+j)>>5 ] & 1 << ((i+j)&0x1F) )
\r
469 for( j = 0; j < count; j ++ )
\r
471 if( gaPCI_PortBitmap[ (portVals+j)>>5 ] |= 1 << ((portVals+j)&0x1F) )
\r
474 PCI_CfgWriteDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4, portVals|1 );
\r
475 dev->ConfigCache[4+bar] = portVals|1;
\r
479 //LogF("PCI_AssignPort: RETURN 0x%x\n", portVals);
\r
485 * \fn int PCI_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, tPCIDevice *info)
\r
486 * \brief Get device information for a slot/function
\r
488 int PCI_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, tPCIDevice *info)
\r
493 vendor = PCI_CfgReadWord(bus, slot, fcn, 0x0|0);
\r
494 if(vendor == 0xFFFF) // Invalid Device
\r
500 info->vendor = vendor;
\r
501 info->device = PCI_CfgReadWord(bus, slot, fcn, 0x0|2);
\r
502 info->revision = PCI_CfgReadWord(bus, slot, fcn, 0x8|0);
\r
503 info->oc = PCI_CfgReadWord(bus, slot, fcn, 0x8|2);
\r
505 // Load Config Bytes
\r
506 for(i=0;i<256/4;i++)
\r
508 info->ConfigCache[i] = PCI_CfgReadDWord(bus, slot, fcn, i*4);
\r
512 //Log("BAR0 0x%08x BAR1 0x%08x BAR2 0x%08x", info->ConfigCache[4], info->ConfigCache[5], info->ConfigCache[6]);
\r
513 //Log("BAR3 0x%08x BAR4 0x%08x BAR5 0x%08x", info->ConfigCache[7], info->ConfigCache[8], info->ConfigCache[9]);
\r
514 //Log("Class: 0x%04x", info->oc);
\r
518 info->Name[0] = '0' + bus/10;
\r
519 info->Name[1] = '0' + bus%10;
\r
520 info->Name[2] = '.';
\r
521 info->Name[3] = '0' + slot/10;
\r
522 info->Name[4] = '0' + slot%10;
\r
523 info->Name[5] = ':';
\r
524 info->Name[6] = '0' + fcn;
\r
525 info->Name[7] = '\0';
\r
528 memset( &info->Node, 0, sizeof(tVFS_Node) );
\r
529 info->Node.Size = 256;
\r
531 info->Node.NumACLs = 1;
\r
532 info->Node.ACLs = &gVFS_ACL_EveryoneRO;
\r
534 info->Node.Read = PCI_ReadDevice;
\r
541 EXPORT(PCI_CountDevices);
\r
542 EXPORT(PCI_GetDevice);
\r
543 EXPORT(PCI_GetDeviceByClass);
\r
544 EXPORT(PCI_AssignPort);
\r
545 EXPORT(PCI_GetIRQ);
\r