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
31 Uint8 revision, progif;
\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_int_ReadDirRoot(tVFS_Node *node, int pos);
\r
46 tVFS_Node *PCI_int_FindDirRoot(tVFS_Node *node, const char *filename);
\r
47 Uint64 PCI_int_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer);
\r
48 int PCI_int_EnumDevice(Uint16 bus, Uint16 dev, Uint16 fcn, tPCIDevice *info);
\r
51 MODULE_DEFINE(0, 0x0100, PCI, PCI_Install, NULL, NULL);
\r
52 int giPCI_BusCount = 1;
\r
53 int giPCI_InodeHandle = -1;
\r
54 int giPCI_DeviceCount = 0;
\r
55 tPCIDevice *gPCI_Devices = NULL;
\r
56 tDevFS_Driver gPCI_DriverStruct = {
\r
59 .Flags = VFS_FFLAG_DIRECTORY,
\r
62 .ACLs = &gVFS_ACL_EveryoneRX,
\r
63 .ReadDir = PCI_int_ReadDirRoot,
\r
64 .FindDir = PCI_int_FindDirRoot
\r
67 Uint32 *gaPCI_PortBitmap = NULL;
\r
68 Uint32 gaPCI_BusBitmap[256/32];
\r
72 * \brief Scan the PCI Bus for devices
\r
73 * \param Arguments Boot-time parameters
\r
75 int PCI_Install(char **Arguments)
\r
81 gaPCI_PortBitmap = malloc( 1 << 13 );
\r
82 if( !gaPCI_PortBitmap ) {
\r
83 Log_Error("PCI", "Unable to allocate %i bytes for bitmap", 1 << 13);
\r
84 return MODULE_ERR_MALLOC;
\r
86 memset( gaPCI_PortBitmap, 0, 1 << 13 );
\r
87 for( i = 0; i < MAX_RESERVED_PORT / 32; i ++ )
\r
88 gaPCI_PortBitmap[i] = -1;
\r
89 for( i = 0; i < MAX_RESERVED_PORT % 32; i ++ )
\r
90 gaPCI_PortBitmap[MAX_RESERVED_PORT / 32] = 1 << i;
\r
92 // Scan Bus (Bus 0, Don't fill gPCI_Devices)
\r
93 i = PCI_ScanBus(0, 0);
\r
94 if(i != MODULE_ERR_OK) return i;
\r
96 if(giPCI_DeviceCount == 0) {
\r
97 Log_Notice("PCI", "No devices were found");
\r
98 return MODULE_ERR_NOTNEEDED;
\r
101 // Allocate device buffer
\r
102 tmpPtr = malloc(giPCI_DeviceCount * sizeof(tPCIDevice));
\r
103 if(tmpPtr == NULL) {
\r
104 Log_Warning("PCI", "Malloc ERROR");
\r
105 return MODULE_ERR_MALLOC;
\r
107 gPCI_Devices = tmpPtr;
\r
109 Log_Log("PCI", "%i devices, filling structure", giPCI_DeviceCount);
\r
112 giPCI_DeviceCount = 0;
\r
113 giPCI_BusCount = 0;
\r
114 memset(gaPCI_BusBitmap, 0, sizeof(gaPCI_BusBitmap));
\r
115 // Rescan, filling the PCI device array
\r
118 // Complete Driver Structure
\r
119 gPCI_DriverStruct.RootNode.Size = giPCI_DeviceCount;
\r
121 // And add to DevFS
\r
122 DevFS_AddDevice(&gPCI_DriverStruct);
\r
124 return MODULE_ERR_OK;
\r
128 * \brief Scans a specific PCI Bus
\r
129 * \param BusID PCI Bus ID to scan
\r
130 * \param bFill Fill the \a gPCI_Devices array?
\r
132 int PCI_ScanBus(int BusID, int bFill)
\r
135 tPCIDevice devInfo;
\r
137 if( gaPCI_BusBitmap[BusID/32] & (1 << (BusID%32)) )
\r
138 return MODULE_ERR_OK;
\r
140 gaPCI_BusBitmap[BusID/32] |= (1 << (BusID%32));
\r
142 for( dev = 0; dev < 32; dev++ ) // 32 Devices per bus
\r
144 for( fcn = 0; fcn < 8; fcn++ ) // Max 8 functions per device
\r
146 // Check if the device/function exists
\r
147 if(!PCI_int_EnumDevice(BusID, dev, fcn, &devInfo))
\r
150 if(devInfo.oc == PCI_OC_PCIBRIDGE)
\r
154 Log_Log("PCI", "Bridge @ %i,%i:%i (0x%x:0x%x)",
\r
155 BusID, dev, fcn, devInfo.vendor, devInfo.device);
\r
157 //TODO: Handle PCI-PCI Bridges
\r
158 //PCI_ScanBus(devInfo.???, bFill);
\r
165 Log_Log("PCI", "Device %i,%i:%i %04x => 0x%04x:0x%04x",
\r
166 BusID, dev, fcn, devInfo.oc, devInfo.vendor, devInfo.device);
\r
171 devInfo.Node.Inode = giPCI_DeviceCount;
\r
172 memcpy(&gPCI_Devices[giPCI_DeviceCount], &devInfo, sizeof(tPCIDevice));
\r
174 giPCI_DeviceCount ++;
\r
176 // If bit 23 of (soemthing) is set, there are sub-functions
\r
177 if(fcn == 0 && !(devInfo.ConfigCache[3] & 0x00800000) )
\r
182 return MODULE_ERR_OK;
\r
186 * \brief Read from Root of PCI Driver
\r
188 char *PCI_int_ReadDirRoot(tVFS_Node *Node, int Pos)
\r
190 ENTER("pNode iPos", Node, Pos);
\r
191 if(Pos < 0 || Pos >= giPCI_DeviceCount) {
\r
196 LEAVE('s', gPCI_Devices[Pos].Name);
\r
197 return strdup( gPCI_Devices[Pos].Name );
\r
201 tVFS_Node *PCI_int_FindDirRoot(tVFS_Node *node, const char *filename)
\r
205 // Validate Filename (Pointer and length)
\r
206 if(!filename || strlen(filename) != 7)
\r
208 // Check for spacers
\r
209 if(filename[2] != '.' || filename[5] != ':')
\r
213 if(filename[0] < '0' || filename[0] > '9') return NULL;
\r
214 bus = (filename[0] - '0')*10;
\r
215 if(filename[1] < '0' || filename[1] > '9') return NULL;
\r
216 bus += filename[1] - '0';
\r
217 if(filename[3] < '0' || filename[3] > '9') return NULL;
\r
218 slot = (filename[3] - '0')*10;
\r
219 if(filename[4] < '0' || filename[4] > '9') return NULL;
\r
220 slot += filename[4] - '0';
\r
221 if(filename[6] < '0' || filename[6] > '9') return NULL;
\r
222 fcn = filename[6] - '0';
\r
225 for(i=0;i<giPCI_DeviceCount;i++)
\r
227 if(gPCI_Devices[i].bus != bus) continue;
\r
228 if(gPCI_Devices[i].slot != slot) continue;
\r
229 if(gPCI_Devices[i].fcn != fcn) continue;
\r
231 return &gPCI_Devices[i].Node;
\r
240 Uint64 PCI_int_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer)
\r
242 if( pos + length > 256 ) return 0;
\r
246 (char*)gPCI_Devices[node->Inode].ConfigCache + pos,
\r
252 // --- Kernel Code Interface ---
\r
254 * \brief Counts the devices with the specified codes
\r
255 * \param vendor Vendor ID
\r
256 * \param device Device ID
\r
258 int PCI_CountDevices(Uint16 vendor, Uint16 device)
\r
261 for(i=0;i<giPCI_DeviceCount;i++)
\r
263 if(gPCI_Devices[i].vendor != vendor) continue;
\r
264 if(gPCI_Devices[i].device != device) continue;
\r
271 * \brief Gets the ID of the specified PCI device
\r
272 * \param vendor Vendor ID
\r
273 * \param device Device ID
\r
274 * \param idx Number of matching entry wanted
\r
276 tPCIDev PCI_GetDevice(Uint16 vendor, Uint16 device, int idx)
\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(j == idx) return i;
\r
290 * \brief Gets the ID of a device by it's class code
\r
291 * \param class Class Code
\r
292 * \param mask Mask for class comparison
\r
293 * \param prev ID of previous device (-1 for no previous)
\r
295 tPCIDev PCI_GetDeviceByClass(Uint16 class, Uint16 mask, tPCIDev prev)
\r
298 // Check if prev is negative (meaning get first)
\r
299 if(prev < 0) i = 0;
\r
302 for( ; i < giPCI_DeviceCount; i++ )
\r
304 if((gPCI_Devices[i].oc & mask) == class)
\r
310 int PCI_GetDeviceInfo(tPCIDev ID, Uint16 *Vendor, Uint16 *Device, Uint16 *Class)
\r
312 tPCIDevice *dev = &gPCI_Devices[ID];
\r
313 if(ID < 0 || ID >= giPCI_DeviceCount) return 1;
\r
315 if(Vendor) *Vendor = dev->vendor;
\r
316 if(Device) *Device = dev->device;
\r
317 if(Class) *Class = dev->oc;
\r
321 int PCI_GetDeviceVersion(tPCIDev ID, Uint8 *Revision, Uint8 *ProgIF)
\r
323 tPCIDevice *dev = &gPCI_Devices[ID];
\r
324 if(ID < 0 || ID >= giPCI_DeviceCount) return 1;
\r
326 if(Revision) *Revision = dev->revision;
\r
327 if(ProgIF) *ProgIF = dev->progif;
\r
331 int PCI_GetDeviceSubsys(tPCIDev ID, Uint16 *SubsystemVendor, Uint16 *SubsystemID)
\r
333 tPCIDevice *dev = &gPCI_Devices[ID];
\r
334 if(ID < 0 || ID >= giPCI_DeviceCount) return 1;
\r
336 if(SubsystemVendor) *SubsystemVendor = dev->ConfigCache[0x2c/4] & 0xFFFF;
\r
337 if(SubsystemID) *SubsystemID = dev->ConfigCache[0x2c/4] >> 16;
\r
342 Uint32 PCI_ConfigRead(tPCIDev ID, int Offset, int Size)
\r
346 if( ID < 0 || ID >= giPCI_DeviceCount ) return 0;
\r
347 if( Offset < 0 || Offset > 256 ) return 0;
\r
349 // TODO: Should I support non-aligned reads?
\r
350 if( Offset & (Size - 1) ) return 0;
\r
352 dev = &gPCI_Devices[ID];
\r
354 dword = PCI_CfgReadDWord(dev->bus, dev->slot, dev->fcn, Offset / 4);
\r
355 gPCI_Devices[ID].ConfigCache[Offset/4] = dword;
\r
358 case 1: return (dword >> (8 * (Offset&3))) & 0xFF;
\r
359 case 2: return (dword >> (8 * (Offset&2))) & 0xFFFF;
\r
360 case 4: return dword;
\r
366 void PCI_ConfigWrite(tPCIDev ID, int Offset, int Size, Uint32 Value)
\r
371 if( ID < 0 || ID >= giPCI_DeviceCount ) return ;
\r
372 if( Offset < 0 || Offset > 256 ) return ;
\r
374 dev = &gPCI_Devices[ID];
\r
376 dword = PCI_CfgReadDWord(dev->bus, dev->slot, dev->fcn, Offset/4);
\r
380 shift = (Offset&3)*8;
\r
381 dword &= ~(0xFF << shift);
\r
382 dword |= Value << shift;
\r
385 shift = (Offset&2)*8;
\r
386 dword &= ~(0xFFFF << shift);
\r
387 dword |= Value << shift;
\r
395 PCI_CfgWriteDWord(dev->bus, dev->slot, dev->fcn, Offset/4, dword);
\r
399 * \brief Get the IRQ assigned to a device
\r
401 Uint8 PCI_GetIRQ(tPCIDev id)
\r
403 if(id < 0 || id >= giPCI_DeviceCount)
\r
405 return gPCI_Devices[id].ConfigCache[15] & 0xFF;
\r
406 //return PCI_CfgReadByte( gPCI_Devices[id].bus, gPCI_Devices[id].slot, gPCI_Devices[id].fcn, 0x3C);
\r
410 * \brief Read the a BAR (base address register) from the PCI config space
\r
412 Uint32 PCI_GetBAR(tPCIDev id, int BARNum)
\r
414 if(id < 0 || id >= giPCI_DeviceCount)
\r
416 if(BARNum < 0 || BARNum >= 6)
\r
418 return gPCI_Devices[id].ConfigCache[4+BARNum];
\r
423 * \brief Assign a port to a BAR
\r
425 Uint16 PCI_AssignPort(tPCIDev ID, int bar, int Count)
\r
431 if(id < 0 || id >= giPCI_DeviceCount) return 0;
\r
432 if(bar < 0 || bar >= 6) return 0;
\r
433 dev = &gPCI_Devices[id];
\r
435 rv = PCI_CfgReadDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4 );
\r
436 if(rv & 1) return rv & ~1;
\r
444 //LogF("PCI_AssignPort: (id=%i,bar=%i,count=%i)\n", id, bar, count);
\r
446 if(id < 0 || id >= giPCI_DeviceCount) return 0;
\r
447 if(bar < 0 || bar > 5) return 0;
\r
449 dev = &gPCI_Devices[id];
\r
451 PCI_CfgWriteDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4, -1 );
\r
452 portVals = PCI_CfgReadDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4 );
\r
453 dev->ConfigCache[4+bar] = portVals;
\r
454 //LogF(" PCI_AssignPort: portVals = 0x%x\n", portVals);
\r
456 // Check for IO port
\r
457 if( !(portVals & 1) ) return 0;
\r
459 // Mask out final bit
\r
463 #if ARCHDIR_IS_x86 || ARCHDIR_IS_x86_64
\r
464 __asm__ __volatile__ ("bsf %%eax, %%ecx" : "=c" (gran) : "a" (portVals) );
\r
468 for(gran = 1; gran && !(portVals & gran); gran <<= 1);
\r
471 //LogF(" PCI_AssignPort: gran = 0x%x\n", gran);
\r
475 for( i = 0; i < 1<<16; i += gran )
\r
477 for( j = 0; j < count; j ++ )
\r
479 if( gaPCI_PortBitmap[ (i+j)>>5 ] & 1 << ((i+j)&0x1F) )
\r
490 for( j = 0; j < count; j ++ )
\r
492 if( gaPCI_PortBitmap[ (portVals+j)>>5 ] |= 1 << ((portVals+j)&0x1F) )
\r
495 PCI_CfgWriteDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4, portVals|1 );
\r
496 dev->ConfigCache[4+bar] = portVals|1;
\r
500 //LogF("PCI_AssignPort: RETURN 0x%x\n", portVals);
\r
507 * \brief Get device information for a slot/function
\r
509 int PCI_int_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, tPCIDevice *info)
\r
514 vendor = PCI_CfgReadWord(bus, slot, fcn, 0x0|0);
\r
515 if(vendor == 0xFFFF) // Invalid Device
\r
521 info->vendor = vendor;
\r
522 info->device = PCI_CfgReadWord(bus, slot, fcn, 0x0|2);
\r
523 info->revision = PCI_CfgReadWord(bus, slot, fcn, 0x8|0);
\r
524 info->oc = PCI_CfgReadWord(bus, slot, fcn, 0x8|2);
\r
526 // Load Config Bytes
\r
527 for(i=0;i<256/4;i++)
\r
529 info->ConfigCache[i] = PCI_CfgReadDWord(bus, slot, fcn, i*4);
\r
533 //Log("BAR0 0x%08x BAR1 0x%08x BAR2 0x%08x", info->ConfigCache[4], info->ConfigCache[5], info->ConfigCache[6]);
\r
534 //Log("BAR3 0x%08x BAR4 0x%08x BAR5 0x%08x", info->ConfigCache[7], info->ConfigCache[8], info->ConfigCache[9]);
\r
535 //Log("Class: 0x%04x", info->oc);
\r
539 info->Name[0] = '0' + bus/10;
\r
540 info->Name[1] = '0' + bus%10;
\r
541 info->Name[2] = '.';
\r
542 info->Name[3] = '0' + slot/10;
\r
543 info->Name[4] = '0' + slot%10;
\r
544 info->Name[5] = ':';
\r
545 info->Name[6] = '0' + fcn;
\r
546 info->Name[7] = '\0';
\r
549 memset( &info->Node, 0, sizeof(tVFS_Node) );
\r
550 info->Node.Size = 256;
\r
552 info->Node.NumACLs = 1;
\r
553 info->Node.ACLs = &gVFS_ACL_EveryoneRO;
\r
555 info->Node.Read = PCI_int_ReadDevice;
\r
562 EXPORT(PCI_CountDevices);
\r
563 EXPORT(PCI_GetDevice);
\r
564 EXPORT(PCI_GetDeviceByClass);
\r
565 EXPORT(PCI_GetDeviceInfo);
\r
566 EXPORT(PCI_GetDeviceVersion);
\r
567 EXPORT(PCI_GetDeviceSubsys);
\r
568 //EXPORT(PCI_AssignPort);
\r
569 EXPORT(PCI_GetBAR);
\r
570 EXPORT(PCI_GetIRQ);
\r