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 memset( gaPCI_PortBitmap, 0, 1 << 13 );
\r
92 for( i = 0; i < MAX_RESERVED_PORT / 32; i ++ )
\r
93 gaPCI_PortBitmap[i] = -1;
\r
94 for( i = 0; i < MAX_RESERVED_PORT % 32; i ++ )
\r
95 gaPCI_PortBitmap[MAX_RESERVED_PORT / 32] = 1 << i;
\r
98 for( bus = 0; bus < giPCI_BusCount; bus++ )
\r
100 for( dev = 0; dev < 32; dev++ ) // 32 Devices per bus
\r
102 for( fcn = 0; fcn < 8; fcn++ ) // Max 8 functions per device
\r
104 // Check if the device/function exists
\r
105 if(!PCI_EnumDevice(bus, dev, fcn, &devInfo))
\r
108 if(giPCI_DeviceCount == space)
\r
110 space += SPACE_STEP;
\r
111 tmpPtr = realloc(gPCI_Devices, space*sizeof(tPCIDevice));
\r
114 gPCI_Devices = tmpPtr;
\r
116 if(devInfo.oc == PCI_OC_PCIBRIDGE)
\r
119 Log_Log("PCI", "Bridge @ %i,%i:%i (0x%x:0x%x)",
\r
120 bus, dev, fcn, devInfo.vendor, devInfo.device);
\r
127 Log_Log("PCI", "Device %i,%i:%i %04x => 0x%04x:0x%04x",
\r
128 bus, dev, fcn, devInfo.oc, devInfo.vendor, devInfo.device);
\r
132 devInfo.Node.Inode = giPCI_DeviceCount;
\r
133 memcpy(&gPCI_Devices[giPCI_DeviceCount], &devInfo, sizeof(tPCIDevice));
\r
134 giPCI_DeviceCount ++;
\r
136 // WTF is this for?
\r
137 // Maybe bit 23 must be set for the device to be valid?
\r
138 // - Actually, maybe 23 means that there are sub-functions
\r
140 if( !(devInfo.ConfigCache[3] & 0x800000) )
\r
144 if(tmpPtr != gPCI_Devices)
\r
147 if(tmpPtr != gPCI_Devices)
\r
151 if(giPCI_DeviceCount == 0)
\r
152 return MODULE_ERR_NOTNEEDED;
\r
154 tmpPtr = realloc(gPCI_Devices, giPCI_DeviceCount*sizeof(tPCIDevice));
\r
156 return MODULE_ERR_MALLOC;
\r
157 gPCI_Devices = tmpPtr;
\r
159 // Complete Driver Structure
\r
160 gPCI_DriverStruct.RootNode.Size = giPCI_DeviceCount;
\r
162 // And add to DevFS
\r
163 DevFS_AddDevice(&gPCI_DriverStruct);
\r
165 return MODULE_ERR_OK;
\r
169 * \fn char *PCI_ReadDirRoot(tVFS_Node *Node, int Pos)
\r
170 * \brief Read from Root of PCI Driver
\r
172 char *PCI_ReadDirRoot(tVFS_Node *Node, int Pos)
\r
174 ENTER("pNode iPos", Node, Pos);
\r
175 if(Pos < 0 || Pos >= giPCI_DeviceCount) {
\r
180 LEAVE('s', gPCI_Devices[Pos].Name);
\r
181 return strdup( gPCI_Devices[Pos].Name );
\r
184 * \fn tVFS_Node *PCI_FindDirRoot(tVFS_Node *node, char *filename)
\r
186 tVFS_Node *PCI_FindDirRoot(tVFS_Node *node, char *filename)
\r
190 // Validate Filename (Pointer and length)
\r
191 if(!filename || strlen(filename) != 7)
\r
193 // Check for spacers
\r
194 if(filename[2] != '.' || filename[5] != ':')
\r
198 if(filename[0] < '0' || filename[0] > '9') return NULL;
\r
199 bus = (filename[0] - '0')*10;
\r
200 if(filename[1] < '0' || filename[1] > '9') return NULL;
\r
201 bus += filename[1] - '0';
\r
202 if(filename[3] < '0' || filename[3] > '9') return NULL;
\r
203 slot = (filename[3] - '0')*10;
\r
204 if(filename[4] < '0' || filename[4] > '9') return NULL;
\r
205 slot += filename[4] - '0';
\r
206 if(filename[6] < '0' || filename[6] > '9') return NULL;
\r
207 fcn = filename[6] - '0';
\r
210 for(i=0;i<giPCI_DeviceCount;i++)
\r
212 if(gPCI_Devices[i].bus != bus) continue;
\r
213 if(gPCI_Devices[i].slot != slot) continue;
\r
214 if(gPCI_Devices[i].fcn != fcn) continue;
\r
216 return &gPCI_Devices[i].Node;
\r
224 * \fn Uint64 PCI_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer)
\r
226 Uint64 PCI_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer)
\r
228 if( pos + length > 256 ) return 0;
\r
232 (char*)gPCI_Devices[node->Inode].ConfigCache + pos,
\r
238 // --- Kernel Code Interface ---
\r
240 \fn int PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn)
\r
241 \brief Counts the devices with the specified codes
\r
242 \param vendor Vendor ID
\r
243 \param device Device ID
\r
244 \param fcn Function ID
\r
246 int PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn)
\r
249 for(i=0;i<giPCI_DeviceCount;i++)
\r
251 if(gPCI_Devices[i].vendor != vendor) continue;
\r
252 if(gPCI_Devices[i].device != device) continue;
\r
253 if(gPCI_Devices[i].fcn != fcn) continue;
\r
260 \fn int PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, int idx)
\r
261 \brief Gets the ID of the specified PCI device
\r
262 \param vendor Vendor ID
\r
263 \param device Device ID
\r
264 \param fcn Function IDs
\r
265 \param idx Number of matching entry wanted
\r
267 int PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, int idx)
\r
270 for(i=0;i<giPCI_DeviceCount;i++)
\r
272 if(gPCI_Devices[i].vendor != vendor) continue;
\r
273 if(gPCI_Devices[i].device != device) continue;
\r
274 if(gPCI_Devices[i].fcn != fcn) continue;
\r
275 if(j == idx) return i;
\r
282 * \fn int PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int prev)
\r
283 * \brief Gets the ID of a device by it's class code
\r
284 * \param class Class Code
\r
285 * \param mask Mask for class comparison
\r
286 * \param prev ID of previous device (-1 for no previous)
\r
288 int PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int prev)
\r
291 // Check if prev is negative (meaning get first)
\r
292 if(prev < 0) i = 0;
\r
295 for( ; i < giPCI_DeviceCount; i++ )
\r
297 if((gPCI_Devices[i].oc & mask) == class)
\r
304 \fn Uint8 PCI_GetIRQ(int id)
\r
306 Uint8 PCI_GetIRQ(int id)
\r
308 if(id < 0 || id >= giPCI_DeviceCount)
\r
310 return gPCI_Devices[id].ConfigCache[15];
\r
311 //return PCI_CfgReadByte( gPCI_Devices[id].bus, gPCI_Devices[id].slot, gPCI_Devices[id].fcn, 0x3C);
\r
315 \fn Uint32 PCI_GetBAR0(int id)
\r
317 Uint32 PCI_GetBAR0(int id)
\r
319 if(id < 0 || id >= giPCI_DeviceCount)
\r
321 return gPCI_Devices[id].ConfigCache[4];
\r
325 \fn Uint32 PCI_GetBAR1(int id)
\r
327 Uint32 PCI_GetBAR1(int id)
\r
329 if(id < 0 || id >= giPCI_DeviceCount)
\r
331 return gPCI_Devices[id].ConfigCache[5];
\r
335 \fn Uint32 PCI_GetBAR2(int id)
\r
337 Uint32 PCI_GetBAR2(int id)
\r
339 if(id < 0 || id >= giPCI_DeviceCount)
\r
341 return gPCI_Devices[id].ConfigCache[6];
\r
345 \fn Uint32 PCI_GetBAR3(int id)
\r
347 Uint32 PCI_GetBAR3(int id)
\r
349 if(id < 0 || id >= giPCI_DeviceCount)
\r
351 return gPCI_Devices[id].ConfigCache[7];
\r
355 \fn Uint32 PCI_GetBAR4(int id)
\r
357 Uint32 PCI_GetBAR4(int id)
\r
359 if(id < 0 || id >= giPCI_DeviceCount)
\r
361 return gPCI_Devices[id].ConfigCache[8];
\r
365 \fn Uint32 PCI_GetBAR5(int id)
\r
367 Uint32 PCI_GetBAR5(int id)
\r
369 if(id < 0 || id >= giPCI_DeviceCount)
\r
371 return gPCI_Devices[id].ConfigCache[9];
\r
374 Uint16 PCI_AssignPort(int id, int bar, int count)
\r
381 //LogF("PCI_AssignPort: (id=%i,bar=%i,count=%i)\n", id, bar, count);
\r
383 if(id < 0 || id >= giPCI_DeviceCount) return 0;
\r
384 if(bar < 0 || bar > 5) return 0;
\r
386 dev = &gPCI_Devices[id];
\r
388 PCI_CfgWriteDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4, -1 );
\r
389 portVals = PCI_CfgReadDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4 );
\r
390 dev->ConfigCache[4+bar] = portVals;
\r
391 //LogF(" PCI_AssignPort: portVals = 0x%x\n", portVals);
\r
393 // Check for IO port
\r
394 if( !(portVals & 1) ) return 0;
\r
396 // Mask out final bit
\r
400 __asm__ __volatile__ ("bsf %%eax, %%ecx" : "=c" (gran) : "a" (portVals) );
\r
402 //LogF(" PCI_AssignPort: gran = 0x%x\n", gran);
\r
406 for( i = 0; i < 1<<16; i += gran )
\r
408 for( j = 0; j < count; j ++ )
\r
410 if( gaPCI_PortBitmap[ (i+j)>>5 ] & 1 << ((i+j)&0x1F) )
\r
421 for( j = 0; j < count; j ++ )
\r
423 if( gaPCI_PortBitmap[ (portVals+j)>>5 ] |= 1 << ((portVals+j)&0x1F) )
\r
426 PCI_CfgWriteDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4, portVals|1 );
\r
427 dev->ConfigCache[4+bar] = portVals|1;
\r
431 //LogF("PCI_AssignPort: RETURN 0x%x\n", portVals);
\r
436 * \fn int PCI_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, tPCIDevice *info)
\r
438 int PCI_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, tPCIDevice *info)
\r
444 vendor = PCI_CfgReadWord(bus, slot, fcn, 0x0|0);
\r
445 if(vendor == 0xFFFF) // Invalid Device
\r
451 info->vendor = vendor;
\r
452 info->device = PCI_CfgReadWord(bus, slot, fcn, 0x0|2);
\r
453 info->revision = PCI_CfgReadWord(bus, slot, fcn, 0x8|0);
\r
454 info->oc = PCI_CfgReadWord(bus, slot, fcn, 0x8|2);
\r
456 // Load Config Bytes
\r
457 addr = 0x80000000 | ((Uint)bus<<16) | ((Uint)slot<<11) | ((Uint)fcn<<8);
\r
458 for(i=0;i<256/4;i++)
\r
462 info->ConfigCache[i] = ind(0xCFC);
\r
465 info->ConfigCache[i] = PCI_CfgReadDWord(bus, slot, fcn, i*4);
\r
470 //Log("BAR0 0x%08x BAR1 0x%08x BAR2 0x%08x", info->ConfigCache[4], info->ConfigCache[5], info->ConfigCache[6]);
\r
471 //Log("BAR3 0x%08x BAR4 0x%08x BAR5 0x%08x", info->ConfigCache[7], info->ConfigCache[8], info->ConfigCache[9]);
\r
472 //Log("Class: 0x%04x", info->oc);
\r
476 info->Name[0] = '0' + bus/10;
\r
477 info->Name[1] = '0' + bus%10;
\r
478 info->Name[2] = '.';
\r
479 info->Name[3] = '0' + slot/10;
\r
480 info->Name[4] = '0' + slot%10;
\r
481 info->Name[5] = ':';
\r
482 info->Name[6] = '0' + fcn;
\r
483 info->Name[7] = '\0';
\r
486 memset( &info->Node, 0, sizeof(tVFS_Node) );
\r
487 info->Node.Size = 256;
\r
489 info->Node.NumACLs = 1;
\r
490 info->Node.ACLs = &gVFS_ACL_EveryoneRO;
\r
492 info->Node.Read = PCI_ReadDevice;
\r
497 Uint32 PCI_CfgReadDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset)
\r
502 bus &= 0xFF; // 8 Bits
\r
503 dev &= 0x1F; // 5 Bits
\r
504 func &= 0x7; // 3 Bits
\r
505 offset &= 0xFF; // 8 Bits
\r
507 address = 0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC);
\r
508 outd(0xCF8, address);
\r
511 return (Uint32)data;
\r
513 void PCI_CfgWriteDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset, Uint32 data)
\r
517 bus &= 0xFF; // 8 Bits
\r
518 dev &= 0x1F; // 5 Bits
\r
519 func &= 0x7; // 3 Bits
\r
520 offset &= 0xFF; // 8 Bits
\r
522 address = 0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC);
\r
523 outd(0xCF8, address);
\r
526 Uint16 PCI_CfgReadWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset)
\r
530 bus &= 0xFF; // 8 Bits
\r
531 dev &= 0x1F; // 5 Bits
\r
532 func &= 0x7; // 3 Bits
\r
533 offset &= 0xFF; // 8 Bits
\r
535 //LogF("PCI_CfgReadWord: (bus=0x%x,dev=0x%x,func=%x,offset=0x%x)\n", bus, dev, func, offset);
\r
538 0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC) );
\r
541 data >>= (offset&2)*8; //Allow Access to Upper Word
\r
542 //LogF("PCI_CfgReadWord: RETURN 0x%x\n", data&0xFFFF);
\r
543 return (Uint16)data;
\r
546 Uint8 PCI_CfgReadByte(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset)
\r
551 bus &= 0xFF; // 8 Bits
\r
552 dev &= 0x1F; // 4 Bits
\r
553 func &= 0x7; // 3 Bits
\r
554 offset &= 0xFF; // 8 Bits
\r
556 address = 0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC);
\r
557 outd(0xCF8, address);
\r
560 data >>= (offset&3)*8; //Allow Access to Upper Word
\r
561 return (Uint8)data;
\r
567 EXPORT(PCI_CountDevices);
\r
568 EXPORT(PCI_GetDevice);
\r
569 EXPORT(PCI_GetDeviceByClass);
\r
570 EXPORT(PCI_AssignPort);
\r
571 EXPORT(PCI_GetIRQ);
\r