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 char *PCI_ReadDirRoot(tVFS_Node *node, int pos);
\r
38 tVFS_Node *PCI_FindDirRoot(tVFS_Node *node, char *filename);
\r
39 Uint64 PCI_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer);
\r
41 int PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn);
\r
42 int PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, int idx);
\r
43 int PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int prev);
\r
44 Uint8 PCI_GetIRQ(int id);
\r
45 Uint32 PCI_GetBAR0(int id);
\r
46 Uint32 PCI_GetBAR1(int id);
\r
47 Uint32 PCI_GetBAR3(int id);
\r
48 Uint32 PCI_GetBAR4(int id);
\r
49 Uint32 PCI_GetBAR5(int id);
\r
50 Uint16 PCI_AssignPort(int id, int bar, int count);
\r
52 int PCI_EnumDevice(Uint16 bus, Uint16 dev, Uint16 fcn, tPCIDevice *info);
\r
53 Uint32 PCI_CfgReadDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset);
\r
54 void PCI_CfgWriteDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset, Uint32 data);
\r
55 Uint16 PCI_CfgReadWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset);
\r
56 Uint8 PCI_CfgReadByte(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset);
\r
59 MODULE_DEFINE(0, 0x0100, PCI, PCI_Install, NULL, NULL);
\r
60 int giPCI_BusCount = 1;
\r
61 int giPCI_InodeHandle = -1;
\r
62 int giPCI_DeviceCount = 0;
\r
63 tPCIDevice *gPCI_Devices = NULL;
\r
64 tDevFS_Driver gPCI_DriverStruct = {
\r
67 .Flags = VFS_FFLAG_DIRECTORY,
\r
70 .ACLs = &gVFS_ACL_EveryoneRX,
\r
71 .ReadDir = PCI_ReadDirRoot,
\r
72 .FindDir = PCI_FindDirRoot
\r
75 Uint32 *gaPCI_PortBitmap = NULL;
\r
79 * \fn int PCI_Install()
\r
80 * \brief Scan the PCI Bus for devices
\r
82 int PCI_Install(char **Arguments)
\r
84 int bus, dev, fcn, i;
\r
87 void *tmpPtr = NULL;
\r
90 gaPCI_PortBitmap = malloc( 1 << 13 );
\r
91 if( !gaPCI_PortBitmap ) {
\r
92 Log_Error("PCI", "Unable to allocate %i bytes for bitmap", 1 << 13);
\r
93 return MODULE_ERR_MALLOC;
\r
95 memset( gaPCI_PortBitmap, 0, 1 << 13 );
\r
96 for( i = 0; i < MAX_RESERVED_PORT / 32; i ++ )
\r
97 gaPCI_PortBitmap[i] = -1;
\r
98 for( i = 0; i < MAX_RESERVED_PORT % 32; i ++ )
\r
99 gaPCI_PortBitmap[MAX_RESERVED_PORT / 32] = 1 << i;
\r
102 for( bus = 0; bus < giPCI_BusCount; bus++ )
\r
104 for( dev = 0; dev < 32; dev++ ) // 32 Devices per bus
\r
106 for( fcn = 0; fcn < 8; fcn++ ) // Max 8 functions per device
\r
108 // Check if the device/function exists
\r
109 if(!PCI_EnumDevice(bus, dev, fcn, &devInfo))
\r
112 if(giPCI_DeviceCount == space)
\r
114 space += SPACE_STEP;
\r
115 tmpPtr = realloc(gPCI_Devices, space*sizeof(tPCIDevice));
\r
117 return MODULE_ERR_MALLOC;
\r
118 gPCI_Devices = tmpPtr;
\r
120 if(devInfo.oc == PCI_OC_PCIBRIDGE)
\r
123 Log_Log("PCI", "Bridge @ %i,%i:%i (0x%x:0x%x)",
\r
124 bus, dev, fcn, devInfo.vendor, devInfo.device);
\r
131 Log_Log("PCI", "Device %i,%i:%i %04x => 0x%04x:0x%04x",
\r
132 bus, dev, fcn, devInfo.oc, devInfo.vendor, devInfo.device);
\r
136 devInfo.Node.Inode = giPCI_DeviceCount;
\r
137 memcpy(&gPCI_Devices[giPCI_DeviceCount], &devInfo, sizeof(tPCIDevice));
\r
138 giPCI_DeviceCount ++;
\r
140 // WTF is this for?
\r
141 // Maybe bit 23 must be set for the device to be valid?
\r
142 // - Actually, maybe 23 means that there are sub-functions
\r
144 if( !(devInfo.ConfigCache[3] & 0x800000) )
\r
151 if(giPCI_DeviceCount == 0) {
\r
152 Log_Notice("PCI", "No devices were found");
\r
153 return MODULE_ERR_NOTNEEDED;
\r
156 tmpPtr = realloc(gPCI_Devices, giPCI_DeviceCount*sizeof(tPCIDevice));
\r
158 return MODULE_ERR_MALLOC;
\r
159 gPCI_Devices = tmpPtr;
\r
161 // Complete Driver Structure
\r
162 gPCI_DriverStruct.RootNode.Size = giPCI_DeviceCount;
\r
164 // And add to DevFS
\r
165 DevFS_AddDevice(&gPCI_DriverStruct);
\r
167 return MODULE_ERR_OK;
\r
171 * \fn char *PCI_ReadDirRoot(tVFS_Node *Node, int Pos)
\r
172 * \brief Read from Root of PCI Driver
\r
174 char *PCI_ReadDirRoot(tVFS_Node *Node, int Pos)
\r
176 ENTER("pNode iPos", Node, Pos);
\r
177 if(Pos < 0 || Pos >= giPCI_DeviceCount) {
\r
182 LEAVE('s', gPCI_Devices[Pos].Name);
\r
183 return strdup( gPCI_Devices[Pos].Name );
\r
186 * \fn tVFS_Node *PCI_FindDirRoot(tVFS_Node *node, char *filename)
\r
188 tVFS_Node *PCI_FindDirRoot(tVFS_Node *node, char *filename)
\r
192 // Validate Filename (Pointer and length)
\r
193 if(!filename || strlen(filename) != 7)
\r
195 // Check for spacers
\r
196 if(filename[2] != '.' || filename[5] != ':')
\r
200 if(filename[0] < '0' || filename[0] > '9') return NULL;
\r
201 bus = (filename[0] - '0')*10;
\r
202 if(filename[1] < '0' || filename[1] > '9') return NULL;
\r
203 bus += filename[1] - '0';
\r
204 if(filename[3] < '0' || filename[3] > '9') return NULL;
\r
205 slot = (filename[3] - '0')*10;
\r
206 if(filename[4] < '0' || filename[4] > '9') return NULL;
\r
207 slot += filename[4] - '0';
\r
208 if(filename[6] < '0' || filename[6] > '9') return NULL;
\r
209 fcn = filename[6] - '0';
\r
212 for(i=0;i<giPCI_DeviceCount;i++)
\r
214 if(gPCI_Devices[i].bus != bus) continue;
\r
215 if(gPCI_Devices[i].slot != slot) continue;
\r
216 if(gPCI_Devices[i].fcn != fcn) continue;
\r
218 return &gPCI_Devices[i].Node;
\r
226 * \fn Uint64 PCI_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer)
\r
228 Uint64 PCI_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer)
\r
230 if( pos + length > 256 ) return 0;
\r
234 (char*)gPCI_Devices[node->Inode].ConfigCache + pos,
\r
240 // --- Kernel Code Interface ---
\r
242 \fn int PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn)
\r
243 \brief Counts the devices with the specified codes
\r
244 \param vendor Vendor ID
\r
245 \param device Device ID
\r
246 \param fcn Function ID
\r
248 int PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn)
\r
251 for(i=0;i<giPCI_DeviceCount;i++)
\r
253 if(gPCI_Devices[i].vendor != vendor) continue;
\r
254 if(gPCI_Devices[i].device != device) continue;
\r
255 if(gPCI_Devices[i].fcn != fcn) continue;
\r
262 \fn int PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, int idx)
\r
263 \brief Gets the ID of the specified PCI device
\r
264 \param vendor Vendor ID
\r
265 \param device Device ID
\r
266 \param fcn Function IDs
\r
267 \param idx Number of matching entry wanted
\r
269 int PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, int idx)
\r
272 for(i=0;i<giPCI_DeviceCount;i++)
\r
274 if(gPCI_Devices[i].vendor != vendor) continue;
\r
275 if(gPCI_Devices[i].device != device) continue;
\r
276 if(gPCI_Devices[i].fcn != fcn) continue;
\r
277 if(j == idx) return i;
\r
284 * \fn int PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int prev)
\r
285 * \brief Gets the ID of a device by it's class code
\r
286 * \param class Class Code
\r
287 * \param mask Mask for class comparison
\r
288 * \param prev ID of previous device (-1 for no previous)
\r
290 int PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int prev)
\r
293 // Check if prev is negative (meaning get first)
\r
294 if(prev < 0) i = 0;
\r
297 for( ; i < giPCI_DeviceCount; i++ )
\r
299 if((gPCI_Devices[i].oc & mask) == class)
\r
306 \fn Uint8 PCI_GetIRQ(int id)
\r
308 Uint8 PCI_GetIRQ(int id)
\r
310 if(id < 0 || id >= giPCI_DeviceCount)
\r
312 return gPCI_Devices[id].ConfigCache[15];
\r
313 //return PCI_CfgReadByte( gPCI_Devices[id].bus, gPCI_Devices[id].slot, gPCI_Devices[id].fcn, 0x3C);
\r
317 \fn Uint32 PCI_GetBAR0(int id)
\r
319 Uint32 PCI_GetBAR0(int id)
\r
321 if(id < 0 || id >= giPCI_DeviceCount)
\r
323 return gPCI_Devices[id].ConfigCache[4];
\r
327 \fn Uint32 PCI_GetBAR1(int id)
\r
329 Uint32 PCI_GetBAR1(int id)
\r
331 if(id < 0 || id >= giPCI_DeviceCount)
\r
333 return gPCI_Devices[id].ConfigCache[5];
\r
337 \fn Uint32 PCI_GetBAR2(int id)
\r
339 Uint32 PCI_GetBAR2(int id)
\r
341 if(id < 0 || id >= giPCI_DeviceCount)
\r
343 return gPCI_Devices[id].ConfigCache[6];
\r
347 \fn Uint32 PCI_GetBAR3(int id)
\r
349 Uint32 PCI_GetBAR3(int id)
\r
351 if(id < 0 || id >= giPCI_DeviceCount)
\r
353 return gPCI_Devices[id].ConfigCache[7];
\r
357 \fn Uint32 PCI_GetBAR4(int id)
\r
359 Uint32 PCI_GetBAR4(int id)
\r
361 if(id < 0 || id >= giPCI_DeviceCount)
\r
363 return gPCI_Devices[id].ConfigCache[8];
\r
367 \fn Uint32 PCI_GetBAR5(int id)
\r
369 Uint32 PCI_GetBAR5(int id)
\r
371 if(id < 0 || id >= giPCI_DeviceCount)
\r
373 return gPCI_Devices[id].ConfigCache[9];
\r
376 Uint16 PCI_AssignPort(int id, int bar, int count)
\r
383 //LogF("PCI_AssignPort: (id=%i,bar=%i,count=%i)\n", id, bar, count);
\r
385 if(id < 0 || id >= giPCI_DeviceCount) return 0;
\r
386 if(bar < 0 || bar > 5) return 0;
\r
388 dev = &gPCI_Devices[id];
\r
390 PCI_CfgWriteDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4, -1 );
\r
391 portVals = PCI_CfgReadDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4 );
\r
392 dev->ConfigCache[4+bar] = portVals;
\r
393 //LogF(" PCI_AssignPort: portVals = 0x%x\n", portVals);
\r
395 // Check for IO port
\r
396 if( !(portVals & 1) ) return 0;
\r
398 // Mask out final bit
\r
402 __asm__ __volatile__ ("bsf %%eax, %%ecx" : "=c" (gran) : "a" (portVals) );
\r
404 //LogF(" PCI_AssignPort: gran = 0x%x\n", gran);
\r
408 for( i = 0; i < 1<<16; i += gran )
\r
410 for( j = 0; j < count; j ++ )
\r
412 if( gaPCI_PortBitmap[ (i+j)>>5 ] & 1 << ((i+j)&0x1F) )
\r
423 for( j = 0; j < count; j ++ )
\r
425 if( gaPCI_PortBitmap[ (portVals+j)>>5 ] |= 1 << ((portVals+j)&0x1F) )
\r
428 PCI_CfgWriteDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4, portVals|1 );
\r
429 dev->ConfigCache[4+bar] = portVals|1;
\r
433 //LogF("PCI_AssignPort: RETURN 0x%x\n", portVals);
\r
438 * \fn int PCI_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, tPCIDevice *info)
\r
440 int PCI_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, tPCIDevice *info)
\r
446 vendor = PCI_CfgReadWord(bus, slot, fcn, 0x0|0);
\r
447 if(vendor == 0xFFFF) // Invalid Device
\r
453 info->vendor = vendor;
\r
454 info->device = PCI_CfgReadWord(bus, slot, fcn, 0x0|2);
\r
455 info->revision = PCI_CfgReadWord(bus, slot, fcn, 0x8|0);
\r
456 info->oc = PCI_CfgReadWord(bus, slot, fcn, 0x8|2);
\r
458 // Load Config Bytes
\r
459 addr = 0x80000000 | ((Uint)bus<<16) | ((Uint)slot<<11) | ((Uint)fcn<<8);
\r
460 for(i=0;i<256/4;i++)
\r
464 info->ConfigCache[i] = ind(0xCFC);
\r
467 info->ConfigCache[i] = PCI_CfgReadDWord(bus, slot, fcn, i*4);
\r
472 //Log("BAR0 0x%08x BAR1 0x%08x BAR2 0x%08x", info->ConfigCache[4], info->ConfigCache[5], info->ConfigCache[6]);
\r
473 //Log("BAR3 0x%08x BAR4 0x%08x BAR5 0x%08x", info->ConfigCache[7], info->ConfigCache[8], info->ConfigCache[9]);
\r
474 //Log("Class: 0x%04x", info->oc);
\r
478 info->Name[0] = '0' + bus/10;
\r
479 info->Name[1] = '0' + bus%10;
\r
480 info->Name[2] = '.';
\r
481 info->Name[3] = '0' + slot/10;
\r
482 info->Name[4] = '0' + slot%10;
\r
483 info->Name[5] = ':';
\r
484 info->Name[6] = '0' + fcn;
\r
485 info->Name[7] = '\0';
\r
488 memset( &info->Node, 0, sizeof(tVFS_Node) );
\r
489 info->Node.Size = 256;
\r
491 info->Node.NumACLs = 1;
\r
492 info->Node.ACLs = &gVFS_ACL_EveryoneRO;
\r
494 info->Node.Read = PCI_ReadDevice;
\r
499 Uint32 PCI_CfgReadDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset)
\r
504 bus &= 0xFF; // 8 Bits
\r
505 dev &= 0x1F; // 5 Bits
\r
506 func &= 0x7; // 3 Bits
\r
507 offset &= 0xFF; // 8 Bits
\r
509 address = 0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC);
\r
510 outd(0xCF8, address);
\r
513 return (Uint32)data;
\r
515 void PCI_CfgWriteDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset, Uint32 data)
\r
519 bus &= 0xFF; // 8 Bits
\r
520 dev &= 0x1F; // 5 Bits
\r
521 func &= 0x7; // 3 Bits
\r
522 offset &= 0xFF; // 8 Bits
\r
524 address = 0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC);
\r
525 outd(0xCF8, address);
\r
528 Uint16 PCI_CfgReadWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset)
\r
532 bus &= 0xFF; // 8 Bits
\r
533 dev &= 0x1F; // 5 Bits
\r
534 func &= 0x7; // 3 Bits
\r
535 offset &= 0xFF; // 8 Bits
\r
537 //LogF("PCI_CfgReadWord: (bus=0x%x,dev=0x%x,func=%x,offset=0x%x)\n", bus, dev, func, offset);
\r
540 0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC) );
\r
543 data >>= (offset&2)*8; //Allow Access to Upper Word
\r
544 //LogF("PCI_CfgReadWord: RETURN 0x%x\n", data&0xFFFF);
\r
545 return (Uint16)data;
\r
548 Uint8 PCI_CfgReadByte(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset)
\r
553 bus &= 0xFF; // 8 Bits
\r
554 dev &= 0x1F; // 4 Bits
\r
555 func &= 0x7; // 3 Bits
\r
556 offset &= 0xFF; // 8 Bits
\r
558 address = 0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC);
\r
559 outd(0xCF8, address);
\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