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
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 * \brief Scan the PCI Bus for devices
\r
83 * \param Arguments Boot-time parameters
\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
102 // Scan Bus (Bus 0, Don't fill gPCI_Devices)
\r
103 i = PCI_ScanBus(0, 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 // Allocate device buffer
\r
112 tmpPtr = malloc(giPCI_DeviceCount * sizeof(tPCIDevice));
\r
113 if(tmpPtr == NULL) {
\r
114 Log_Warning("PCI", "Malloc ERROR");
\r
115 return MODULE_ERR_MALLOC;
\r
117 gPCI_Devices = tmpPtr;
\r
119 Log_Log("PCI", "%i devices, filling structure", giPCI_DeviceCount);
\r
122 giPCI_DeviceCount = 0;
\r
123 giPCI_BusCount = 0;
\r
124 memset(gaPCI_BusBitmap, 0, sizeof(gaPCI_BusBitmap));
\r
125 // Rescan, filling the PCI device array
\r
128 // Complete Driver Structure
\r
129 gPCI_DriverStruct.RootNode.Size = giPCI_DeviceCount;
\r
131 // And add to DevFS
\r
132 DevFS_AddDevice(&gPCI_DriverStruct);
\r
134 return MODULE_ERR_OK;
\r
138 * \brief Scans a specific PCI Bus
\r
139 * \param BusID PCI Bus ID to scan
\r
140 * \param bFill Fill the \a gPCI_Devices array?
\r
142 int PCI_ScanBus(int BusID, int bFill)
\r
145 tPCIDevice devInfo;
\r
147 if( gaPCI_BusBitmap[BusID/32] & (1 << (BusID%32)) )
\r
148 return MODULE_ERR_OK;
\r
150 gaPCI_BusBitmap[BusID/32] |= (1 << (BusID%32));
\r
152 for( dev = 0; dev < 32; dev++ ) // 32 Devices per bus
\r
154 for( fcn = 0; fcn < 8; fcn++ ) // Max 8 functions per device
\r
156 // Check if the device/function exists
\r
157 if(!PCI_EnumDevice(BusID, dev, fcn, &devInfo))
\r
160 if(devInfo.oc == PCI_OC_PCIBRIDGE)
\r
163 Log_Log("PCI", "Bridge @ %i,%i:%i (0x%x:0x%x)",
\r
164 BusID, dev, fcn, devInfo.vendor, devInfo.device);
\r
166 //TODO: Handle PCI-PCI Bridges
\r
167 //PCI_ScanBus(devInfo.???, bFill);
\r
173 Log_Log("PCI", "Device %i,%i:%i %04x => 0x%04x:0x%04x",
\r
174 BusID, dev, fcn, devInfo.oc, devInfo.vendor, devInfo.device);
\r
179 devInfo.Node.Inode = giPCI_DeviceCount;
\r
180 memcpy(&gPCI_Devices[giPCI_DeviceCount], &devInfo, sizeof(tPCIDevice));
\r
182 giPCI_DeviceCount ++;
\r
184 // WTF is this for?
\r
185 // Maybe bit 23 must be set for the device to be valid?
\r
186 // - Actually, maybe 23 means that there are sub-functions
\r
188 if( !(devInfo.ConfigCache[3] & 0x00800000) )
\r
194 return MODULE_ERR_OK;
\r
198 * \fn char *PCI_ReadDirRoot(tVFS_Node *Node, int Pos)
\r
199 * \brief Read from Root of PCI Driver
\r
201 char *PCI_ReadDirRoot(tVFS_Node *Node, int Pos)
\r
203 ENTER("pNode iPos", Node, Pos);
\r
204 if(Pos < 0 || Pos >= giPCI_DeviceCount) {
\r
209 LEAVE('s', gPCI_Devices[Pos].Name);
\r
210 return strdup( gPCI_Devices[Pos].Name );
\r
213 * \fn tVFS_Node *PCI_FindDirRoot(tVFS_Node *node, const char *filename)
\r
215 tVFS_Node *PCI_FindDirRoot(tVFS_Node *node, const char *filename)
\r
219 // Validate Filename (Pointer and length)
\r
220 if(!filename || strlen(filename) != 7)
\r
222 // Check for spacers
\r
223 if(filename[2] != '.' || filename[5] != ':')
\r
227 if(filename[0] < '0' || filename[0] > '9') return NULL;
\r
228 bus = (filename[0] - '0')*10;
\r
229 if(filename[1] < '0' || filename[1] > '9') return NULL;
\r
230 bus += filename[1] - '0';
\r
231 if(filename[3] < '0' || filename[3] > '9') return NULL;
\r
232 slot = (filename[3] - '0')*10;
\r
233 if(filename[4] < '0' || filename[4] > '9') return NULL;
\r
234 slot += filename[4] - '0';
\r
235 if(filename[6] < '0' || filename[6] > '9') return NULL;
\r
236 fcn = filename[6] - '0';
\r
239 for(i=0;i<giPCI_DeviceCount;i++)
\r
241 if(gPCI_Devices[i].bus != bus) continue;
\r
242 if(gPCI_Devices[i].slot != slot) continue;
\r
243 if(gPCI_Devices[i].fcn != fcn) continue;
\r
245 return &gPCI_Devices[i].Node;
\r
253 * \fn Uint64 PCI_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer)
\r
255 Uint64 PCI_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer)
\r
257 if( pos + length > 256 ) return 0;
\r
261 (char*)gPCI_Devices[node->Inode].ConfigCache + pos,
\r
267 // --- Kernel Code Interface ---
\r
269 \fn int PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn)
\r
270 \brief Counts the devices with the specified codes
\r
271 \param vendor Vendor ID
\r
272 \param device Device ID
\r
273 \param fcn Function ID
\r
275 int PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn)
\r
278 for(i=0;i<giPCI_DeviceCount;i++)
\r
280 if(gPCI_Devices[i].vendor != vendor) continue;
\r
281 if(gPCI_Devices[i].device != device) continue;
\r
282 if(gPCI_Devices[i].fcn != fcn) continue;
\r
289 \fn int PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, int idx)
\r
290 \brief Gets the ID of the specified PCI device
\r
291 \param vendor Vendor ID
\r
292 \param device Device ID
\r
293 \param fcn Function IDs
\r
294 \param idx Number of matching entry wanted
\r
296 int PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, int idx)
\r
299 for(i=0;i<giPCI_DeviceCount;i++)
\r
301 if(gPCI_Devices[i].vendor != vendor) continue;
\r
302 if(gPCI_Devices[i].device != device) continue;
\r
303 if(gPCI_Devices[i].fcn != fcn) continue;
\r
304 if(j == idx) return i;
\r
311 * \fn int PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int prev)
\r
312 * \brief Gets the ID of a device by it's class code
\r
313 * \param class Class Code
\r
314 * \param mask Mask for class comparison
\r
315 * \param prev ID of previous device (-1 for no previous)
\r
317 int PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int prev)
\r
320 // Check if prev is negative (meaning get first)
\r
321 if(prev < 0) i = 0;
\r
324 for( ; i < giPCI_DeviceCount; i++ )
\r
326 if((gPCI_Devices[i].oc & mask) == class)
\r
333 \fn Uint8 PCI_GetIRQ(int id)
\r
335 Uint8 PCI_GetIRQ(int id)
\r
337 if(id < 0 || id >= giPCI_DeviceCount)
\r
339 return gPCI_Devices[id].ConfigCache[15];
\r
340 //return PCI_CfgReadByte( gPCI_Devices[id].bus, gPCI_Devices[id].slot, gPCI_Devices[id].fcn, 0x3C);
\r
344 \fn Uint32 PCI_GetBAR0(int id)
\r
346 Uint32 PCI_GetBAR0(int id)
\r
348 if(id < 0 || id >= giPCI_DeviceCount)
\r
350 return gPCI_Devices[id].ConfigCache[4];
\r
354 \fn Uint32 PCI_GetBAR1(int id)
\r
356 Uint32 PCI_GetBAR1(int id)
\r
358 if(id < 0 || id >= giPCI_DeviceCount)
\r
360 return gPCI_Devices[id].ConfigCache[5];
\r
364 \fn Uint32 PCI_GetBAR2(int id)
\r
366 Uint32 PCI_GetBAR2(int id)
\r
368 if(id < 0 || id >= giPCI_DeviceCount)
\r
370 return gPCI_Devices[id].ConfigCache[6];
\r
374 \fn Uint32 PCI_GetBAR3(int id)
\r
376 Uint32 PCI_GetBAR3(int id)
\r
378 if(id < 0 || id >= giPCI_DeviceCount)
\r
380 return gPCI_Devices[id].ConfigCache[7];
\r
384 \fn Uint32 PCI_GetBAR4(int id)
\r
386 Uint32 PCI_GetBAR4(int id)
\r
388 if(id < 0 || id >= giPCI_DeviceCount)
\r
390 return gPCI_Devices[id].ConfigCache[8];
\r
394 \fn Uint32 PCI_GetBAR5(int id)
\r
396 Uint32 PCI_GetBAR5(int id)
\r
398 if(id < 0 || id >= giPCI_DeviceCount)
\r
400 return gPCI_Devices[id].ConfigCache[9];
\r
403 Uint16 PCI_AssignPort(int id, int bar, int count)
\r
410 //LogF("PCI_AssignPort: (id=%i,bar=%i,count=%i)\n", id, bar, count);
\r
412 if(id < 0 || id >= giPCI_DeviceCount) return 0;
\r
413 if(bar < 0 || bar > 5) return 0;
\r
415 dev = &gPCI_Devices[id];
\r
417 PCI_CfgWriteDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4, -1 );
\r
418 portVals = PCI_CfgReadDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4 );
\r
419 dev->ConfigCache[4+bar] = portVals;
\r
420 //LogF(" PCI_AssignPort: portVals = 0x%x\n", portVals);
\r
422 // Check for IO port
\r
423 if( !(portVals & 1) ) return 0;
\r
425 // Mask out final bit
\r
429 __asm__ __volatile__ ("bsf %%eax, %%ecx" : "=c" (gran) : "a" (portVals) );
\r
431 //LogF(" PCI_AssignPort: gran = 0x%x\n", gran);
\r
435 for( i = 0; i < 1<<16; i += gran )
\r
437 for( j = 0; j < count; j ++ )
\r
439 if( gaPCI_PortBitmap[ (i+j)>>5 ] & 1 << ((i+j)&0x1F) )
\r
450 for( j = 0; j < count; j ++ )
\r
452 if( gaPCI_PortBitmap[ (portVals+j)>>5 ] |= 1 << ((portVals+j)&0x1F) )
\r
455 PCI_CfgWriteDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4, portVals|1 );
\r
456 dev->ConfigCache[4+bar] = portVals|1;
\r
460 //LogF("PCI_AssignPort: RETURN 0x%x\n", portVals);
\r
465 * \fn int PCI_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, tPCIDevice *info)
\r
467 int PCI_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, tPCIDevice *info)
\r
472 vendor = PCI_CfgReadWord(bus, slot, fcn, 0x0|0);
\r
473 if(vendor == 0xFFFF) // Invalid Device
\r
479 info->vendor = vendor;
\r
480 info->device = PCI_CfgReadWord(bus, slot, fcn, 0x0|2);
\r
481 info->revision = PCI_CfgReadWord(bus, slot, fcn, 0x8|0);
\r
482 info->oc = PCI_CfgReadWord(bus, slot, fcn, 0x8|2);
\r
484 // Load Config Bytes
\r
485 for(i=0;i<256/4;i++)
\r
487 info->ConfigCache[i] = PCI_CfgReadDWord(bus, slot, fcn, i*4);
\r
491 //Log("BAR0 0x%08x BAR1 0x%08x BAR2 0x%08x", info->ConfigCache[4], info->ConfigCache[5], info->ConfigCache[6]);
\r
492 //Log("BAR3 0x%08x BAR4 0x%08x BAR5 0x%08x", info->ConfigCache[7], info->ConfigCache[8], info->ConfigCache[9]);
\r
493 //Log("Class: 0x%04x", info->oc);
\r
497 info->Name[0] = '0' + bus/10;
\r
498 info->Name[1] = '0' + bus%10;
\r
499 info->Name[2] = '.';
\r
500 info->Name[3] = '0' + slot/10;
\r
501 info->Name[4] = '0' + slot%10;
\r
502 info->Name[5] = ':';
\r
503 info->Name[6] = '0' + fcn;
\r
504 info->Name[7] = '\0';
\r
507 memset( &info->Node, 0, sizeof(tVFS_Node) );
\r
508 info->Node.Size = 256;
\r
510 info->Node.NumACLs = 1;
\r
511 info->Node.ACLs = &gVFS_ACL_EveryoneRO;
\r
513 info->Node.Read = PCI_ReadDevice;
\r
518 Uint32 PCI_CfgReadDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset)
\r
523 bus &= 0xFF; // 8 Bits
\r
524 dev &= 0x1F; // 5 Bits
\r
525 func &= 0x7; // 3 Bits
\r
526 offset &= 0xFF; // 8 Bits
\r
528 address = 0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC);
\r
529 outd(0xCF8, address);
\r
532 //Debug("PCI(0x%x) = 0x%08x", address, data);
\r
535 void PCI_CfgWriteDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset, Uint32 data)
\r
539 bus &= 0xFF; // 8 Bits
\r
540 dev &= 0x1F; // 5 Bits
\r
541 func &= 0x7; // 3 Bits
\r
542 offset &= 0xFF; // 8 Bits
\r
544 address = 0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC);
\r
545 outd(0xCF8, address);
\r
548 Uint16 PCI_CfgReadWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset)
\r
550 Uint32 data = PCI_CfgReadDWord(bus, dev, func, offset);
\r
552 data >>= (offset&2)*8; // Allow Access to Upper Word
\r
554 return (Uint16)data;
\r
557 Uint8 PCI_CfgReadByte(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset)
\r
559 Uint32 data = PCI_CfgReadDWord(bus, dev, func, offset);
\r
561 data >>= (offset&3)*8; //Allow Access to Upper Word
\r
562 return (Uint8)data;
\r
568 EXPORT(PCI_CountDevices);
\r
569 EXPORT(PCI_GetDevice);
\r
570 EXPORT(PCI_GetDeviceByClass);
\r
571 EXPORT(PCI_AssignPort);
\r
572 EXPORT(PCI_GetIRQ);
\r