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);
\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 < 10; dev++ ) // 10 Devices per bus
\r
102 for( fcn = 0; fcn < 8; fcn++ ) // 8 functions per device
\r
104 // Check if the device/function exists
\r
105 if(!PCI_EnumDevice(bus, dev, fcn, &devInfo))
\r
110 if(giPCI_DeviceCount == space)
\r
112 space += SPACE_STEP;
\r
113 tmpPtr = realloc(gPCI_Devices, space*sizeof(tPCIDevice));
\r
116 gPCI_Devices = tmpPtr;
\r
118 if(devInfo.oc == PCI_OC_PCIBRIDGE)
\r
121 Log("[PCI ] Bridge @ %i,%i:%i (0x%x:0x%x)",
\r
122 bus, dev, fcn, devInfo.vendor, devInfo.device);
\r
126 devInfo.Node.Inode = giPCI_DeviceCount;
\r
127 memcpy(&gPCI_Devices[giPCI_DeviceCount], &devInfo, sizeof(tPCIDevice));
\r
128 giPCI_DeviceCount ++;
\r
130 Log("[PCI ] Device %i,%i:%i => 0x%x:0x%x",
\r
131 bus, dev, fcn, devInfo.vendor, devInfo.device);
\r
134 // WTF is this for?
\r
136 if( !(devInfo.ConfigCache[3] & 0x800000) )
\r
140 if(tmpPtr != gPCI_Devices)
\r
143 if(tmpPtr != gPCI_Devices)
\r
147 if(giPCI_DeviceCount == 0)
\r
148 return MODULE_ERR_NOTNEEDED;
\r
150 tmpPtr = realloc(gPCI_Devices, giPCI_DeviceCount*sizeof(tPCIDevice));
\r
152 return MODULE_ERR_MALLOC;
\r
153 gPCI_Devices = tmpPtr;
\r
155 // Complete Driver Structure
\r
156 gPCI_DriverStruct.RootNode.Size = giPCI_DeviceCount;
\r
158 // And add to DevFS
\r
159 DevFS_AddDevice(&gPCI_DriverStruct);
\r
161 return MODULE_ERR_OK;
\r
165 * \fn char *PCI_ReadDirRoot(tVFS_Node *Node, int Pos)
\r
166 * \brief Read from Root of PCI Driver
\r
168 char *PCI_ReadDirRoot(tVFS_Node *Node, int Pos)
\r
170 ENTER("pNode iPos", Node, Pos);
\r
171 if(Pos < 0 || Pos >= giPCI_DeviceCount) {
\r
176 LEAVE('s', gPCI_Devices[Pos].Name);
\r
177 return strdup( gPCI_Devices[Pos].Name );
\r
180 * \fn tVFS_Node *PCI_FindDirRoot(tVFS_Node *node, char *filename)
\r
182 tVFS_Node *PCI_FindDirRoot(tVFS_Node *node, char *filename)
\r
186 // Validate Filename (Pointer and length)
\r
187 if(!filename || strlen(filename) != 7)
\r
189 // Check for spacers
\r
190 if(filename[2] != '.' || filename[5] != ':')
\r
194 if(filename[0] < '0' || filename[0] > '9') return NULL;
\r
195 bus = (filename[0] - '0')*10;
\r
196 if(filename[1] < '0' || filename[1] > '9') return NULL;
\r
197 bus += filename[1] - '0';
\r
198 if(filename[3] < '0' || filename[3] > '9') return NULL;
\r
199 slot = (filename[3] - '0')*10;
\r
200 if(filename[4] < '0' || filename[4] > '9') return NULL;
\r
201 slot += filename[4] - '0';
\r
202 if(filename[6] < '0' || filename[6] > '9') return NULL;
\r
203 fcn = filename[6] - '0';
\r
206 for(i=0;i<giPCI_DeviceCount;i++)
\r
208 if(gPCI_Devices[i].bus != bus) continue;
\r
209 if(gPCI_Devices[i].slot != slot) continue;
\r
210 if(gPCI_Devices[i].fcn != fcn) continue;
\r
212 return &gPCI_Devices[i].Node;
\r
220 * \fn Uint64 PCI_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer)
\r
222 Uint64 PCI_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer)
\r
224 if( pos + length > 256 ) return 0;
\r
228 (char*)gPCI_Devices[node->Inode].ConfigCache + pos,
\r
234 // --- Kernel Code Interface ---
\r
236 \fn int PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn)
\r
237 \brief Counts the devices with the specified codes
\r
238 \param vendor Vendor ID
\r
239 \param device Device ID
\r
240 \param fcn Function ID
\r
242 int PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn)
\r
245 for(i=0;i<giPCI_DeviceCount;i++)
\r
247 if(gPCI_Devices[i].vendor != vendor) continue;
\r
248 if(gPCI_Devices[i].device != device) continue;
\r
249 if(gPCI_Devices[i].fcn != fcn) continue;
\r
256 \fn int PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, int idx)
\r
257 \brief Gets the ID of the specified PCI device
\r
258 \param vendor Vendor ID
\r
259 \param device Device ID
\r
260 \param fcn Function IDs
\r
261 \param idx Number of matching entry wanted
\r
263 int PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, int idx)
\r
266 for(i=0;i<giPCI_DeviceCount;i++)
\r
268 if(gPCI_Devices[i].vendor != vendor) continue;
\r
269 if(gPCI_Devices[i].device != device) continue;
\r
270 if(gPCI_Devices[i].fcn != fcn) continue;
\r
271 if(j == idx) return i;
\r
278 * \fn int PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int prev)
\r
279 * \brief Gets the ID of a device by it's class code
\r
280 * \param class Class Code
\r
281 * \param mask Mask for class comparison
\r
282 * \param prev ID of previous device (-1 for no previous)
\r
284 int PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int prev)
\r
287 // Check if prev is negative (meaning get first)
\r
288 if(prev < 0) i = 0;
\r
291 for( ; i < giPCI_DeviceCount; i++ )
\r
293 if((gPCI_Devices[i].oc & mask) != class) continue;
\r
300 \fn Uint8 PCI_GetIRQ(int id)
\r
302 Uint8 PCI_GetIRQ(int id)
\r
304 if(id < 0 || id >= giPCI_DeviceCount)
\r
306 return gPCI_Devices[id].ConfigCache[15];
\r
307 //return PCI_CfgReadByte( gPCI_Devices[id].bus, gPCI_Devices[id].slot, gPCI_Devices[id].fcn, 0x3C);
\r
311 \fn Uint32 PCI_GetBAR0(int id)
\r
313 Uint32 PCI_GetBAR0(int id)
\r
315 if(id < 0 || id >= giPCI_DeviceCount)
\r
317 return gPCI_Devices[id].ConfigCache[4];
\r
321 \fn Uint32 PCI_GetBAR1(int id)
\r
323 Uint32 PCI_GetBAR1(int id)
\r
325 if(id < 0 || id >= giPCI_DeviceCount)
\r
327 return gPCI_Devices[id].ConfigCache[5];
\r
331 \fn Uint32 PCI_GetBAR2(int id)
\r
333 Uint32 PCI_GetBAR2(int id)
\r
335 if(id < 0 || id >= giPCI_DeviceCount)
\r
337 return gPCI_Devices[id].ConfigCache[6];
\r
341 \fn Uint32 PCI_GetBAR3(int id)
\r
343 Uint32 PCI_GetBAR3(int id)
\r
345 if(id < 0 || id >= giPCI_DeviceCount)
\r
347 return gPCI_Devices[id].ConfigCache[7];
\r
351 \fn Uint32 PCI_GetBAR4(int id)
\r
353 Uint32 PCI_GetBAR4(int id)
\r
355 if(id < 0 || id >= giPCI_DeviceCount)
\r
357 return gPCI_Devices[id].ConfigCache[8];
\r
361 \fn Uint32 PCI_GetBAR5(int id)
\r
363 Uint32 PCI_GetBAR5(int id)
\r
365 if(id < 0 || id >= giPCI_DeviceCount)
\r
367 return gPCI_Devices[id].ConfigCache[9];
\r
370 Uint16 PCI_AssignPort(int id, int bar, int count)
\r
377 //LogF("PCI_AssignPort: (id=%i,bar=%i,count=%i)\n", id, bar, count);
\r
379 if(id < 0 || id >= giPCI_DeviceCount) return 0;
\r
380 if(bar < 0 || bar > 5) return 0;
\r
382 dev = &gPCI_Devices[id];
\r
384 PCI_CfgWriteDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4, -1 );
\r
385 portVals = PCI_CfgReadDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4 );
\r
386 dev->ConfigCache[4+bar] = portVals;
\r
387 //LogF(" PCI_AssignPort: portVals = 0x%x\n", portVals);
\r
389 // Check for IO port
\r
390 if( !(portVals & 1) ) return 0;
\r
392 // Mask out final bit
\r
396 __asm__ __volatile__ ("bsf %%eax, %%ecx" : "=c" (gran) : "a" (portVals) );
\r
398 //LogF(" PCI_AssignPort: gran = 0x%x\n", gran);
\r
402 for( i = 0; i < 1<<16; i += gran )
\r
404 for( j = 0; j < count; j ++ )
\r
406 if( gaPCI_PortBitmap[ (i+j)>>5 ] & 1 << ((i+j)&0x1F) )
\r
417 for( j = 0; j < count; j ++ )
\r
419 if( gaPCI_PortBitmap[ (portVals+j)>>5 ] |= 1 << ((portVals+j)&0x1F) )
\r
422 PCI_CfgWriteDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4, portVals|1 );
\r
423 dev->ConfigCache[4+bar] = portVals|1;
\r
427 //LogF("PCI_AssignPort: RETURN 0x%x\n", portVals);
\r
432 * \fn int PCI_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, tPCIDevice *info)
\r
434 int PCI_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, tPCIDevice *info)
\r
440 vendor = PCI_CfgReadWord(bus, slot, fcn, 0x0|0);
\r
441 if(vendor == 0xFFFF) // Invalid Device
\r
447 info->vendor = vendor;
\r
448 info->device = PCI_CfgReadWord(bus, slot, fcn, 0x0|2);
\r
449 info->revision = PCI_CfgReadWord(bus, slot, fcn, 0x8|0);
\r
450 info->oc = PCI_CfgReadWord(bus, slot, fcn, 0x8|2);
\r
452 // Load Config Bytes
\r
453 addr = 0x80000000 | ((Uint)bus<<16) | ((Uint)slot<<11) | ((Uint)fcn<<8);
\r
454 for(i=0;i<256/4;i++)
\r
458 info->ConfigCache[i] = ind(0xCFC);
\r
461 info->ConfigCache[i] = PCI_CfgReadDWord(bus, slot, fcn, i*4);
\r
466 //Log("BAR0 0x%08x BAR1 0x%08x BAR2 0x%08x", info->ConfigCache[4], info->ConfigCache[5], info->ConfigCache[6]);
\r
467 //Log("BAR3 0x%08x BAR4 0x%08x BAR5 0x%08x", info->ConfigCache[7], info->ConfigCache[8], info->ConfigCache[9]);
\r
468 //Log("Class: 0x%04x", info->oc);
\r
472 info->Name[0] = '0' + bus/10;
\r
473 info->Name[1] = '0' + bus%10;
\r
474 info->Name[2] = '.';
\r
475 info->Name[3] = '0' + slot/10;
\r
476 info->Name[4] = '0' + slot%10;
\r
477 info->Name[5] = ':';
\r
478 info->Name[6] = '0' + fcn;
\r
479 info->Name[7] = '\0';
\r
482 memset( &info->Node, 0, sizeof(tVFS_Node) );
\r
483 info->Node.Size = 256;
\r
485 info->Node.NumACLs = 1;
\r
486 info->Node.ACLs = &gVFS_ACL_EveryoneRO;
\r
488 info->Node.Read = PCI_ReadDevice;
\r
493 Uint32 PCI_CfgReadDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset)
\r
498 bus &= 0xFF; // 8 Bits
\r
499 dev &= 0x1F; // 5 Bits
\r
500 func &= 0x7; // 3 Bits
\r
501 offset &= 0xFF; // 8 Bits
\r
503 address = 0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC);
\r
504 outd(0xCF8, address);
\r
507 return (Uint32)data;
\r
509 void PCI_CfgWriteDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset, Uint32 data)
\r
513 bus &= 0xFF; // 8 Bits
\r
514 dev &= 0x1F; // 5 Bits
\r
515 func &= 0x7; // 3 Bits
\r
516 offset &= 0xFF; // 8 Bits
\r
518 address = 0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC);
\r
519 outd(0xCF8, address);
\r
522 Uint16 PCI_CfgReadWord(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 //LogF("PCI_CfgReadWord: (bus=0x%x,dev=0x%x,func=%x,offset=0x%x)\n", bus, dev, func, offset);
\r
534 0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC) );
\r
537 data >>= (offset&2)*8; //Allow Access to Upper Word
\r
538 //LogF("PCI_CfgReadWord: RETURN 0x%x\n", data&0xFFFF);
\r
539 return (Uint16)data;
\r
542 Uint8 PCI_CfgReadByte(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset)
\r
547 bus &= 0xFF; // 8 Bits
\r
548 dev &= 0x1F; // 4 Bits
\r
549 func &= 0x7; // 3 Bits
\r
550 offset &= 0xFF; // 8 Bits
\r
552 address = 0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC);
\r
553 outd(0xCF8, address);
\r
556 data >>= (offset&3)*8; //Allow Access to Upper Word
\r
557 return (Uint8)data;
\r
563 EXPORT(PCI_CountDevices);
\r
564 EXPORT(PCI_GetDevice);
\r
565 EXPORT(PCI_GetDeviceByClass);
\r
566 EXPORT(PCI_AssignPort);
\r
567 EXPORT(PCI_GetIRQ);
\r