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 Debug("%i:%i:%i", BusID, dev, fcn);
\r
145 // Check if the device/function exists
\r
146 if(!PCI_EnumDevice(BusID, dev, fcn, &devInfo))
\r
150 tmpPtr = realloc(gPCI_Devices, (giPCI_DeviceCount+1)*sizeof(tPCIDevice));
\r
152 return MODULE_ERR_MALLOC;
\r
153 gPCI_Devices = tmpPtr;
\r
155 if(devInfo.oc == PCI_OC_PCIBRIDGE)
\r
158 Log_Log("PCI", "Bridge @ %i,%i:%i (0x%x:0x%x)",
\r
159 BusID, dev, fcn, devInfo.vendor, devInfo.device);
\r
161 //TODO: Handle PCI-PCI Bridges
\r
168 Log_Log("PCI", "Device %i,%i:%i %04x => 0x%04x:0x%04x",
\r
169 BusID, dev, fcn, devInfo.oc, devInfo.vendor, devInfo.device);
\r
173 devInfo.Node.Inode = giPCI_DeviceCount;
\r
174 memcpy(&gPCI_Devices[giPCI_DeviceCount], &devInfo, sizeof(tPCIDevice));
\r
175 giPCI_DeviceCount ++;
\r
177 // WTF is this for?
\r
178 // Maybe bit 23 must be set for the device to be valid?
\r
179 // - Actually, maybe 23 means that there are sub-functions
\r
181 if( !(devInfo.ConfigCache[3] & 0x800000) )
\r
187 return MODULE_ERR_OK;
\r
191 * \fn char *PCI_ReadDirRoot(tVFS_Node *Node, int Pos)
\r
192 * \brief Read from Root of PCI Driver
\r
194 char *PCI_ReadDirRoot(tVFS_Node *Node, int Pos)
\r
196 ENTER("pNode iPos", Node, Pos);
\r
197 if(Pos < 0 || Pos >= giPCI_DeviceCount) {
\r
202 LEAVE('s', gPCI_Devices[Pos].Name);
\r
203 return strdup( gPCI_Devices[Pos].Name );
\r
206 * \fn tVFS_Node *PCI_FindDirRoot(tVFS_Node *node, char *filename)
\r
208 tVFS_Node *PCI_FindDirRoot(tVFS_Node *node, char *filename)
\r
212 // Validate Filename (Pointer and length)
\r
213 if(!filename || strlen(filename) != 7)
\r
215 // Check for spacers
\r
216 if(filename[2] != '.' || filename[5] != ':')
\r
220 if(filename[0] < '0' || filename[0] > '9') return NULL;
\r
221 bus = (filename[0] - '0')*10;
\r
222 if(filename[1] < '0' || filename[1] > '9') return NULL;
\r
223 bus += filename[1] - '0';
\r
224 if(filename[3] < '0' || filename[3] > '9') return NULL;
\r
225 slot = (filename[3] - '0')*10;
\r
226 if(filename[4] < '0' || filename[4] > '9') return NULL;
\r
227 slot += filename[4] - '0';
\r
228 if(filename[6] < '0' || filename[6] > '9') return NULL;
\r
229 fcn = filename[6] - '0';
\r
232 for(i=0;i<giPCI_DeviceCount;i++)
\r
234 if(gPCI_Devices[i].bus != bus) continue;
\r
235 if(gPCI_Devices[i].slot != slot) continue;
\r
236 if(gPCI_Devices[i].fcn != fcn) continue;
\r
238 return &gPCI_Devices[i].Node;
\r
246 * \fn Uint64 PCI_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer)
\r
248 Uint64 PCI_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer)
\r
250 if( pos + length > 256 ) return 0;
\r
254 (char*)gPCI_Devices[node->Inode].ConfigCache + pos,
\r
260 // --- Kernel Code Interface ---
\r
262 \fn int PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn)
\r
263 \brief Counts the devices with the specified codes
\r
264 \param vendor Vendor ID
\r
265 \param device Device ID
\r
266 \param fcn Function ID
\r
268 int PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn)
\r
271 for(i=0;i<giPCI_DeviceCount;i++)
\r
273 if(gPCI_Devices[i].vendor != vendor) continue;
\r
274 if(gPCI_Devices[i].device != device) continue;
\r
275 if(gPCI_Devices[i].fcn != fcn) continue;
\r
282 \fn int PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, int idx)
\r
283 \brief Gets the ID of the specified PCI device
\r
284 \param vendor Vendor ID
\r
285 \param device Device ID
\r
286 \param fcn Function IDs
\r
287 \param idx Number of matching entry wanted
\r
289 int PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, int idx)
\r
292 for(i=0;i<giPCI_DeviceCount;i++)
\r
294 if(gPCI_Devices[i].vendor != vendor) continue;
\r
295 if(gPCI_Devices[i].device != device) continue;
\r
296 if(gPCI_Devices[i].fcn != fcn) continue;
\r
297 if(j == idx) return i;
\r
304 * \fn int PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int prev)
\r
305 * \brief Gets the ID of a device by it's class code
\r
306 * \param class Class Code
\r
307 * \param mask Mask for class comparison
\r
308 * \param prev ID of previous device (-1 for no previous)
\r
310 int PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int prev)
\r
313 // Check if prev is negative (meaning get first)
\r
314 if(prev < 0) i = 0;
\r
317 for( ; i < giPCI_DeviceCount; i++ )
\r
319 if((gPCI_Devices[i].oc & mask) == class)
\r
326 \fn Uint8 PCI_GetIRQ(int id)
\r
328 Uint8 PCI_GetIRQ(int id)
\r
330 if(id < 0 || id >= giPCI_DeviceCount)
\r
332 return gPCI_Devices[id].ConfigCache[15];
\r
333 //return PCI_CfgReadByte( gPCI_Devices[id].bus, gPCI_Devices[id].slot, gPCI_Devices[id].fcn, 0x3C);
\r
337 \fn Uint32 PCI_GetBAR0(int id)
\r
339 Uint32 PCI_GetBAR0(int id)
\r
341 if(id < 0 || id >= giPCI_DeviceCount)
\r
343 return gPCI_Devices[id].ConfigCache[4];
\r
347 \fn Uint32 PCI_GetBAR1(int id)
\r
349 Uint32 PCI_GetBAR1(int id)
\r
351 if(id < 0 || id >= giPCI_DeviceCount)
\r
353 return gPCI_Devices[id].ConfigCache[5];
\r
357 \fn Uint32 PCI_GetBAR2(int id)
\r
359 Uint32 PCI_GetBAR2(int id)
\r
361 if(id < 0 || id >= giPCI_DeviceCount)
\r
363 return gPCI_Devices[id].ConfigCache[6];
\r
367 \fn Uint32 PCI_GetBAR3(int id)
\r
369 Uint32 PCI_GetBAR3(int id)
\r
371 if(id < 0 || id >= giPCI_DeviceCount)
\r
373 return gPCI_Devices[id].ConfigCache[7];
\r
377 \fn Uint32 PCI_GetBAR4(int id)
\r
379 Uint32 PCI_GetBAR4(int id)
\r
381 if(id < 0 || id >= giPCI_DeviceCount)
\r
383 return gPCI_Devices[id].ConfigCache[8];
\r
387 \fn Uint32 PCI_GetBAR5(int id)
\r
389 Uint32 PCI_GetBAR5(int id)
\r
391 if(id < 0 || id >= giPCI_DeviceCount)
\r
393 return gPCI_Devices[id].ConfigCache[9];
\r
396 Uint16 PCI_AssignPort(int id, int bar, int count)
\r
403 //LogF("PCI_AssignPort: (id=%i,bar=%i,count=%i)\n", id, bar, count);
\r
405 if(id < 0 || id >= giPCI_DeviceCount) return 0;
\r
406 if(bar < 0 || bar > 5) return 0;
\r
408 dev = &gPCI_Devices[id];
\r
410 PCI_CfgWriteDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4, -1 );
\r
411 portVals = PCI_CfgReadDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4 );
\r
412 dev->ConfigCache[4+bar] = portVals;
\r
413 //LogF(" PCI_AssignPort: portVals = 0x%x\n", portVals);
\r
415 // Check for IO port
\r
416 if( !(portVals & 1) ) return 0;
\r
418 // Mask out final bit
\r
422 __asm__ __volatile__ ("bsf %%eax, %%ecx" : "=c" (gran) : "a" (portVals) );
\r
424 //LogF(" PCI_AssignPort: gran = 0x%x\n", gran);
\r
428 for( i = 0; i < 1<<16; i += gran )
\r
430 for( j = 0; j < count; j ++ )
\r
432 if( gaPCI_PortBitmap[ (i+j)>>5 ] & 1 << ((i+j)&0x1F) )
\r
443 for( j = 0; j < count; j ++ )
\r
445 if( gaPCI_PortBitmap[ (portVals+j)>>5 ] |= 1 << ((portVals+j)&0x1F) )
\r
448 PCI_CfgWriteDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4, portVals|1 );
\r
449 dev->ConfigCache[4+bar] = portVals|1;
\r
453 //LogF("PCI_AssignPort: RETURN 0x%x\n", portVals);
\r
458 * \fn int PCI_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, tPCIDevice *info)
\r
460 int PCI_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, tPCIDevice *info)
\r
466 vendor = PCI_CfgReadWord(bus, slot, fcn, 0x0|0);
\r
467 if(vendor == 0xFFFF) // Invalid Device
\r
473 info->vendor = vendor;
\r
474 info->device = PCI_CfgReadWord(bus, slot, fcn, 0x0|2);
\r
475 info->revision = PCI_CfgReadWord(bus, slot, fcn, 0x8|0);
\r
476 info->oc = PCI_CfgReadWord(bus, slot, fcn, 0x8|2);
\r
478 // Load Config Bytes
\r
479 addr = 0x80000000 | ((Uint)bus<<16) | ((Uint)slot<<11) | ((Uint)fcn<<8);
\r
480 for(i=0;i<256/4;i++)
\r
484 info->ConfigCache[i] = ind(0xCFC);
\r
487 info->ConfigCache[i] = PCI_CfgReadDWord(bus, slot, fcn, i*4);
\r
492 //Log("BAR0 0x%08x BAR1 0x%08x BAR2 0x%08x", info->ConfigCache[4], info->ConfigCache[5], info->ConfigCache[6]);
\r
493 //Log("BAR3 0x%08x BAR4 0x%08x BAR5 0x%08x", info->ConfigCache[7], info->ConfigCache[8], info->ConfigCache[9]);
\r
494 //Log("Class: 0x%04x", info->oc);
\r
498 info->Name[0] = '0' + bus/10;
\r
499 info->Name[1] = '0' + bus%10;
\r
500 info->Name[2] = '.';
\r
501 info->Name[3] = '0' + slot/10;
\r
502 info->Name[4] = '0' + slot%10;
\r
503 info->Name[5] = ':';
\r
504 info->Name[6] = '0' + fcn;
\r
505 info->Name[7] = '\0';
\r
508 memset( &info->Node, 0, sizeof(tVFS_Node) );
\r
509 info->Node.Size = 256;
\r
511 info->Node.NumACLs = 1;
\r
512 info->Node.ACLs = &gVFS_ACL_EveryoneRO;
\r
514 info->Node.Read = PCI_ReadDevice;
\r
519 Uint32 PCI_CfgReadDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset)
\r
524 bus &= 0xFF; // 8 Bits
\r
525 dev &= 0x1F; // 5 Bits
\r
526 func &= 0x7; // 3 Bits
\r
527 offset &= 0xFF; // 8 Bits
\r
529 address = 0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC);
\r
530 outd(0xCF8, address);
\r
533 //Debug("PCI(0x%x) = 0x%08x", address, data);
\r
536 void PCI_CfgWriteDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset, Uint32 data)
\r
540 bus &= 0xFF; // 8 Bits
\r
541 dev &= 0x1F; // 5 Bits
\r
542 func &= 0x7; // 3 Bits
\r
543 offset &= 0xFF; // 8 Bits
\r
545 address = 0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC);
\r
546 outd(0xCF8, address);
\r
549 Uint16 PCI_CfgReadWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset)
\r
551 Uint32 data = PCI_CfgReadDWord(bus, dev, func, offset);
\r
553 data >>= (offset&2)*8; // Allow Access to Upper Word
\r
555 return (Uint16)data;
\r
558 Uint8 PCI_CfgReadByte(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset)
\r
560 Uint32 data = PCI_CfgReadDWord(bus, dev, func, offset);
\r
562 data >>= (offset&3)*8; //Allow Access to Upper Word
\r
563 return (Uint8)data;
\r
569 EXPORT(PCI_CountDevices);
\r
570 EXPORT(PCI_GetDevice);
\r
571 EXPORT(PCI_GetDeviceByClass);
\r
572 EXPORT(PCI_AssignPort);
\r
573 EXPORT(PCI_GetIRQ);
\r