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, int bFill);
\r
39 char *PCI_ReadDirRoot(tVFS_Node *node, int pos);
\r
40 tVFS_Node *PCI_FindDirRoot(tVFS_Node *node, const char *filename);
\r
41 Uint64 PCI_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer);
\r
44 int PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn);
\r
45 int PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, int idx);
\r
46 int PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int prev);
\r
47 Uint8 PCI_GetIRQ(int id);
\r
48 Uint32 PCI_GetBAR0(int id);
\r
49 Uint32 PCI_GetBAR1(int id);
\r
50 Uint32 PCI_GetBAR2(int id);
\r
51 Uint32 PCI_GetBAR3(int id);
\r
52 Uint32 PCI_GetBAR4(int id);
\r
53 Uint32 PCI_GetBAR5(int id);
\r
54 Uint16 PCI_AssignPort(int id, int bar, int count);
\r
57 int PCI_EnumDevice(Uint16 bus, Uint16 dev, Uint16 fcn, tPCIDevice *info);
\r
58 Uint32 PCI_CfgReadDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset);
\r
59 void PCI_CfgWriteDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset, Uint32 data);
\r
60 Uint16 PCI_CfgReadWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset);
\r
61 Uint8 PCI_CfgReadByte(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset);
\r
64 MODULE_DEFINE(0, 0x0100, PCI, PCI_Install, NULL, NULL);
\r
65 int giPCI_BusCount = 1;
\r
66 int giPCI_InodeHandle = -1;
\r
67 int giPCI_DeviceCount = 0;
\r
68 tPCIDevice *gPCI_Devices = NULL;
\r
69 tDevFS_Driver gPCI_DriverStruct = {
\r
72 .Flags = VFS_FFLAG_DIRECTORY,
\r
75 .ACLs = &gVFS_ACL_EveryoneRX,
\r
76 .ReadDir = PCI_ReadDirRoot,
\r
77 .FindDir = PCI_FindDirRoot
\r
80 Uint32 *gaPCI_PortBitmap = NULL;
\r
81 Uint32 gaPCI_BusBitmap[256/32];
\r
85 * \brief Scan the PCI Bus for devices
\r
86 * \param Arguments Boot-time parameters
\r
88 int PCI_Install(char **Arguments)
\r
94 gaPCI_PortBitmap = malloc( 1 << 13 );
\r
95 if( !gaPCI_PortBitmap ) {
\r
96 Log_Error("PCI", "Unable to allocate %i bytes for bitmap", 1 << 13);
\r
97 return MODULE_ERR_MALLOC;
\r
99 memset( gaPCI_PortBitmap, 0, 1 << 13 );
\r
100 for( i = 0; i < MAX_RESERVED_PORT / 32; i ++ )
\r
101 gaPCI_PortBitmap[i] = -1;
\r
102 for( i = 0; i < MAX_RESERVED_PORT % 32; i ++ )
\r
103 gaPCI_PortBitmap[MAX_RESERVED_PORT / 32] = 1 << i;
\r
105 // Scan Bus (Bus 0, Don't fill gPCI_Devices)
\r
106 i = PCI_ScanBus(0, 0);
\r
107 if(i != MODULE_ERR_OK) return i;
\r
109 if(giPCI_DeviceCount == 0) {
\r
110 Log_Notice("PCI", "No devices were found");
\r
111 return MODULE_ERR_NOTNEEDED;
\r
114 // Allocate device buffer
\r
115 tmpPtr = malloc(giPCI_DeviceCount * sizeof(tPCIDevice));
\r
116 if(tmpPtr == NULL) {
\r
117 Log_Warning("PCI", "Malloc ERROR");
\r
118 return MODULE_ERR_MALLOC;
\r
120 gPCI_Devices = tmpPtr;
\r
122 Log_Log("PCI", "%i devices, filling structure", giPCI_DeviceCount);
\r
125 giPCI_DeviceCount = 0;
\r
126 giPCI_BusCount = 0;
\r
127 memset(gaPCI_BusBitmap, 0, sizeof(gaPCI_BusBitmap));
\r
128 // Rescan, filling the PCI device array
\r
131 // Complete Driver Structure
\r
132 gPCI_DriverStruct.RootNode.Size = giPCI_DeviceCount;
\r
134 // And add to DevFS
\r
135 DevFS_AddDevice(&gPCI_DriverStruct);
\r
137 return MODULE_ERR_OK;
\r
141 * \brief Scans a specific PCI Bus
\r
142 * \param BusID PCI Bus ID to scan
\r
143 * \param bFill Fill the \a gPCI_Devices array?
\r
145 int PCI_ScanBus(int BusID, int bFill)
\r
148 tPCIDevice devInfo;
\r
150 if( gaPCI_BusBitmap[BusID/32] & (1 << (BusID%32)) )
\r
151 return MODULE_ERR_OK;
\r
153 gaPCI_BusBitmap[BusID/32] |= (1 << (BusID%32));
\r
155 for( dev = 0; dev < 32; dev++ ) // 32 Devices per bus
\r
157 for( fcn = 0; fcn < 8; fcn++ ) // Max 8 functions per device
\r
159 // Check if the device/function exists
\r
160 if(!PCI_EnumDevice(BusID, dev, fcn, &devInfo))
\r
163 if(devInfo.oc == PCI_OC_PCIBRIDGE)
\r
166 Log_Log("PCI", "Bridge @ %i,%i:%i (0x%x:0x%x)",
\r
167 BusID, dev, fcn, devInfo.vendor, devInfo.device);
\r
169 //TODO: Handle PCI-PCI Bridges
\r
170 //PCI_ScanBus(devInfo.???, bFill);
\r
176 Log_Log("PCI", "Device %i,%i:%i %04x => 0x%04x:0x%04x",
\r
177 BusID, dev, fcn, devInfo.oc, devInfo.vendor, devInfo.device);
\r
182 devInfo.Node.Inode = giPCI_DeviceCount;
\r
183 memcpy(&gPCI_Devices[giPCI_DeviceCount], &devInfo, sizeof(tPCIDevice));
\r
185 giPCI_DeviceCount ++;
\r
187 // WTF is this for?
\r
188 // Maybe bit 23 must be set for the device to be valid?
\r
189 // - Actually, maybe 23 means that there are sub-functions
\r
191 if( !(devInfo.ConfigCache[3] & 0x00800000) )
\r
197 return MODULE_ERR_OK;
\r
201 * \fn char *PCI_ReadDirRoot(tVFS_Node *Node, int Pos)
\r
202 * \brief Read from Root of PCI Driver
\r
204 char *PCI_ReadDirRoot(tVFS_Node *Node, int Pos)
\r
206 ENTER("pNode iPos", Node, Pos);
\r
207 if(Pos < 0 || Pos >= giPCI_DeviceCount) {
\r
212 LEAVE('s', gPCI_Devices[Pos].Name);
\r
213 return strdup( gPCI_Devices[Pos].Name );
\r
216 * \fn tVFS_Node *PCI_FindDirRoot(tVFS_Node *node, const char *filename)
\r
218 tVFS_Node *PCI_FindDirRoot(tVFS_Node *node, const char *filename)
\r
222 // Validate Filename (Pointer and length)
\r
223 if(!filename || strlen(filename) != 7)
\r
225 // Check for spacers
\r
226 if(filename[2] != '.' || filename[5] != ':')
\r
230 if(filename[0] < '0' || filename[0] > '9') return NULL;
\r
231 bus = (filename[0] - '0')*10;
\r
232 if(filename[1] < '0' || filename[1] > '9') return NULL;
\r
233 bus += filename[1] - '0';
\r
234 if(filename[3] < '0' || filename[3] > '9') return NULL;
\r
235 slot = (filename[3] - '0')*10;
\r
236 if(filename[4] < '0' || filename[4] > '9') return NULL;
\r
237 slot += filename[4] - '0';
\r
238 if(filename[6] < '0' || filename[6] > '9') return NULL;
\r
239 fcn = filename[6] - '0';
\r
242 for(i=0;i<giPCI_DeviceCount;i++)
\r
244 if(gPCI_Devices[i].bus != bus) continue;
\r
245 if(gPCI_Devices[i].slot != slot) continue;
\r
246 if(gPCI_Devices[i].fcn != fcn) continue;
\r
248 return &gPCI_Devices[i].Node;
\r
256 * \fn Uint64 PCI_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer)
\r
258 Uint64 PCI_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer)
\r
260 if( pos + length > 256 ) return 0;
\r
264 (char*)gPCI_Devices[node->Inode].ConfigCache + pos,
\r
270 // --- Kernel Code Interface ---
\r
272 \fn int PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn)
\r
273 \brief Counts the devices with the specified codes
\r
274 \param vendor Vendor ID
\r
275 \param device Device ID
\r
276 \param fcn Function ID
\r
278 int PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn)
\r
281 for(i=0;i<giPCI_DeviceCount;i++)
\r
283 if(gPCI_Devices[i].vendor != vendor) continue;
\r
284 if(gPCI_Devices[i].device != device) continue;
\r
285 if(gPCI_Devices[i].fcn != fcn) continue;
\r
292 \fn int PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, int idx)
\r
293 \brief Gets the ID of the specified PCI device
\r
294 \param vendor Vendor ID
\r
295 \param device Device ID
\r
296 \param fcn Function IDs
\r
297 \param idx Number of matching entry wanted
\r
299 int PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, int idx)
\r
302 for(i=0;i<giPCI_DeviceCount;i++)
\r
304 if(gPCI_Devices[i].vendor != vendor) continue;
\r
305 if(gPCI_Devices[i].device != device) continue;
\r
306 if(gPCI_Devices[i].fcn != fcn) continue;
\r
307 if(j == idx) return i;
\r
314 * \fn int PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int prev)
\r
315 * \brief Gets the ID of a device by it's class code
\r
316 * \param class Class Code
\r
317 * \param mask Mask for class comparison
\r
318 * \param prev ID of previous device (-1 for no previous)
\r
320 int PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int prev)
\r
323 // Check if prev is negative (meaning get first)
\r
324 if(prev < 0) i = 0;
\r
327 for( ; i < giPCI_DeviceCount; i++ )
\r
329 if((gPCI_Devices[i].oc & mask) == class)
\r
336 \fn Uint8 PCI_GetIRQ(int id)
\r
338 Uint8 PCI_GetIRQ(int id)
\r
340 if(id < 0 || id >= giPCI_DeviceCount)
\r
342 return gPCI_Devices[id].ConfigCache[15];
\r
343 //return PCI_CfgReadByte( gPCI_Devices[id].bus, gPCI_Devices[id].slot, gPCI_Devices[id].fcn, 0x3C);
\r
347 \fn Uint32 PCI_GetBAR0(int id)
\r
349 Uint32 PCI_GetBAR0(int id)
\r
351 if(id < 0 || id >= giPCI_DeviceCount)
\r
353 return gPCI_Devices[id].ConfigCache[4];
\r
357 \fn Uint32 PCI_GetBAR1(int id)
\r
359 Uint32 PCI_GetBAR1(int id)
\r
361 if(id < 0 || id >= giPCI_DeviceCount)
\r
363 return gPCI_Devices[id].ConfigCache[5];
\r
367 \fn Uint32 PCI_GetBAR2(int id)
\r
369 Uint32 PCI_GetBAR2(int id)
\r
371 if(id < 0 || id >= giPCI_DeviceCount)
\r
373 return gPCI_Devices[id].ConfigCache[6];
\r
377 \fn Uint32 PCI_GetBAR3(int id)
\r
379 Uint32 PCI_GetBAR3(int id)
\r
381 if(id < 0 || id >= giPCI_DeviceCount)
\r
383 return gPCI_Devices[id].ConfigCache[7];
\r
387 \fn Uint32 PCI_GetBAR4(int id)
\r
389 Uint32 PCI_GetBAR4(int id)
\r
391 if(id < 0 || id >= giPCI_DeviceCount)
\r
393 return gPCI_Devices[id].ConfigCache[8];
\r
397 \fn Uint32 PCI_GetBAR5(int id)
\r
399 Uint32 PCI_GetBAR5(int id)
\r
401 if(id < 0 || id >= giPCI_DeviceCount)
\r
403 return gPCI_Devices[id].ConfigCache[9];
\r
406 Uint16 PCI_AssignPort(int id, int bar, int count)
\r
413 //LogF("PCI_AssignPort: (id=%i,bar=%i,count=%i)\n", id, bar, count);
\r
415 if(id < 0 || id >= giPCI_DeviceCount) return 0;
\r
416 if(bar < 0 || bar > 5) return 0;
\r
418 dev = &gPCI_Devices[id];
\r
420 PCI_CfgWriteDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4, -1 );
\r
421 portVals = PCI_CfgReadDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4 );
\r
422 dev->ConfigCache[4+bar] = portVals;
\r
423 //LogF(" PCI_AssignPort: portVals = 0x%x\n", portVals);
\r
425 // Check for IO port
\r
426 if( !(portVals & 1) ) return 0;
\r
428 // Mask out final bit
\r
432 __asm__ __volatile__ ("bsf %%eax, %%ecx" : "=c" (gran) : "a" (portVals) );
\r
434 //LogF(" PCI_AssignPort: gran = 0x%x\n", gran);
\r
438 for( i = 0; i < 1<<16; i += gran )
\r
440 for( j = 0; j < count; j ++ )
\r
442 if( gaPCI_PortBitmap[ (i+j)>>5 ] & 1 << ((i+j)&0x1F) )
\r
453 for( j = 0; j < count; j ++ )
\r
455 if( gaPCI_PortBitmap[ (portVals+j)>>5 ] |= 1 << ((portVals+j)&0x1F) )
\r
458 PCI_CfgWriteDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4, portVals|1 );
\r
459 dev->ConfigCache[4+bar] = portVals|1;
\r
463 //LogF("PCI_AssignPort: RETURN 0x%x\n", portVals);
\r
468 * \fn int PCI_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, tPCIDevice *info)
\r
470 int PCI_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, tPCIDevice *info)
\r
475 vendor = PCI_CfgReadWord(bus, slot, fcn, 0x0|0);
\r
476 if(vendor == 0xFFFF) // Invalid Device
\r
482 info->vendor = vendor;
\r
483 info->device = PCI_CfgReadWord(bus, slot, fcn, 0x0|2);
\r
484 info->revision = PCI_CfgReadWord(bus, slot, fcn, 0x8|0);
\r
485 info->oc = PCI_CfgReadWord(bus, slot, fcn, 0x8|2);
\r
487 // Load Config Bytes
\r
488 for(i=0;i<256/4;i++)
\r
490 info->ConfigCache[i] = PCI_CfgReadDWord(bus, slot, fcn, i*4);
\r
494 //Log("BAR0 0x%08x BAR1 0x%08x BAR2 0x%08x", info->ConfigCache[4], info->ConfigCache[5], info->ConfigCache[6]);
\r
495 //Log("BAR3 0x%08x BAR4 0x%08x BAR5 0x%08x", info->ConfigCache[7], info->ConfigCache[8], info->ConfigCache[9]);
\r
496 //Log("Class: 0x%04x", info->oc);
\r
500 info->Name[0] = '0' + bus/10;
\r
501 info->Name[1] = '0' + bus%10;
\r
502 info->Name[2] = '.';
\r
503 info->Name[3] = '0' + slot/10;
\r
504 info->Name[4] = '0' + slot%10;
\r
505 info->Name[5] = ':';
\r
506 info->Name[6] = '0' + fcn;
\r
507 info->Name[7] = '\0';
\r
510 memset( &info->Node, 0, sizeof(tVFS_Node) );
\r
511 info->Node.Size = 256;
\r
513 info->Node.NumACLs = 1;
\r
514 info->Node.ACLs = &gVFS_ACL_EveryoneRO;
\r
516 info->Node.Read = PCI_ReadDevice;
\r
521 Uint32 PCI_CfgReadDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset)
\r
526 bus &= 0xFF; // 8 Bits
\r
527 dev &= 0x1F; // 5 Bits
\r
528 func &= 0x7; // 3 Bits
\r
529 offset &= 0xFF; // 8 Bits
\r
531 address = 0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC);
\r
532 outd(0xCF8, address);
\r
535 //Debug("PCI(0x%x) = 0x%08x", address, data);
\r
538 void PCI_CfgWriteDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset, Uint32 data)
\r
542 bus &= 0xFF; // 8 Bits
\r
543 dev &= 0x1F; // 5 Bits
\r
544 func &= 0x7; // 3 Bits
\r
545 offset &= 0xFF; // 8 Bits
\r
547 address = 0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC);
\r
548 outd(0xCF8, address);
\r
551 Uint16 PCI_CfgReadWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset)
\r
553 Uint32 data = PCI_CfgReadDWord(bus, dev, func, offset);
\r
555 data >>= (offset&2)*8; // Allow Access to Upper Word
\r
557 return (Uint16)data;
\r
560 Uint8 PCI_CfgReadByte(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset)
\r
562 Uint32 data = PCI_CfgReadDWord(bus, dev, func, offset);
\r
564 data >>= (offset&3)*8; //Allow Access to Upper Word
\r
565 return (Uint8)data;
\r
571 EXPORT(PCI_CountDevices);
\r
572 EXPORT(PCI_GetDevice);
\r
573 EXPORT(PCI_GetDeviceByClass);
\r
574 EXPORT(PCI_AssignPort);
\r
575 EXPORT(PCI_GetIRQ);
\r