2 * AcessOS/AcessBasic v0.1
\r
8 #include <fs_devfs.h>
\r
11 #define LIST_DEVICES 1
\r
13 // === STRUCTURES ===
\r
14 typedef struct s_pciDevice {
\r
15 Uint16 bus, slot, fcn;
\r
16 Uint16 vendor, device;
\r
18 struct {Uint8 class, subclass;};
\r
22 Uint32 ConfigCache[256/4];
\r
27 // === CONSTANTS ===
\r
28 #define SPACE_STEP 5
\r
29 #define MAX_RESERVED_PORT 0xD00
\r
31 // === PROTOTYPES ===
\r
32 int PCI_Install(char **Arguments);
\r
33 char *PCI_ReadDirRoot(tVFS_Node *node, int pos);
\r
34 tVFS_Node *PCI_FindDirRoot(tVFS_Node *node, char *filename);
\r
35 Uint64 PCI_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer);
\r
37 int PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn);
\r
38 int PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, int idx);
\r
39 int PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int prev);
\r
40 Uint8 PCI_GetIRQ(int id);
\r
41 Uint32 PCI_GetBAR0(int id);
\r
42 Uint32 PCI_GetBAR1(int id);
\r
43 Uint32 PCI_GetBAR3(int id);
\r
44 Uint32 PCI_GetBAR4(int id);
\r
45 Uint32 PCI_GetBAR5(int id);
\r
46 Uint16 PCI_AssignPort(int id, int bar, int count);
\r
48 int PCI_EnumDevice(Uint16 bus, Uint16 dev, Uint16 fcn, t_pciDevice *info);
\r
49 Uint32 PCI_CfgReadDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset);
\r
50 void PCI_CfgWriteDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset, Uint32 data);
\r
51 Uint16 PCI_CfgReadWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset);
\r
52 Uint8 PCI_CfgReadByte(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset);
\r
55 //MODULE_DEFINE(0, 0x0100, PCI, PCI_Install, NULL);
\r
56 int giPCI_BusCount = 1;
\r
57 int giPCI_InodeHandle = -1;
\r
58 int giPCI_DeviceCount = 0;
\r
59 t_pciDevice *gPCI_Devices = NULL;
\r
60 tDevFS_Driver gPCI_DriverStruct = {
\r
63 .Flags = VFS_FFLAG_DIRECTORY,
\r
66 .ACLs = &gVFS_ACL_EveryoneRX,
\r
67 .ReadDir = PCI_ReadDirRoot,
\r
68 .FindDir = PCI_FindDirRoot
\r
71 Uint32 *gaPCI_PortBitmap = NULL;
\r
75 * \fn int PCI_Install()
\r
76 * \brief Scan the PCI Bus for devices
\r
78 int PCI_Install(char **Arguments)
\r
80 int bus, dev, fcn, i;
\r
82 t_pciDevice devInfo;
\r
83 void *tmpPtr = NULL;
\r
86 gaPCI_PortBitmap = malloc( 1 << 13 );
\r
87 memset( gaPCI_PortBitmap, 0, 1 << 13 );
\r
88 for( i = 0; i < MAX_RESERVED_PORT / 32; i ++ )
\r
89 gaPCI_PortBitmap[i] = -1;
\r
90 for( i = 0; i < MAX_RESERVED_PORT % 32; i ++ )
\r
91 gaPCI_PortBitmap[MAX_RESERVED_PORT / 32] = 1 << i;
\r
95 for( bus = 0; bus < giPCI_BusCount; bus++ )
\r
97 for( dev = 0; dev < 10; dev++ ) // 10 Devices per bus
\r
99 for( fcn = 0; fcn < 8; fcn++ ) // 8 functions per device
\r
101 // Check if the device/function exists
\r
102 if(!PCI_EnumDevice(bus, dev, fcn, &devInfo))
\r
107 if(giPCI_DeviceCount == space)
\r
109 space += SPACE_STEP;
\r
110 tmpPtr = realloc(gPCI_Devices, space*sizeof(t_pciDevice));
\r
113 gPCI_Devices = tmpPtr;
\r
115 if(devInfo.oc == PCI_OC_PCIBRIDGE)
\r
118 Log("[PCI ] Bridge @ %i,%i:%i (0x%x:0x%x)",
\r
119 bus, dev, fcn, devInfo.vendor, devInfo.device);
\r
123 devInfo.Node.Inode = giPCI_DeviceCount;
\r
124 memcpy(&gPCI_Devices[giPCI_DeviceCount], &devInfo, sizeof(t_pciDevice));
\r
125 giPCI_DeviceCount ++;
\r
127 Log("[PCI ] Device %i,%i:%i => 0x%x:0x%x",
\r
128 bus, dev, fcn, devInfo.vendor, devInfo.device);
\r
131 // WTF is this for?
\r
133 if( !(devInfo.ConfigCache[3] & 0x800000) )
\r
137 if(tmpPtr != gPCI_Devices)
\r
140 if(tmpPtr != gPCI_Devices)
\r
143 tmpPtr = realloc(gPCI_Devices, giPCI_DeviceCount*sizeof(t_pciDevice));
\r
146 gPCI_Devices = tmpPtr;
\r
149 // Complete Driver Structure
\r
150 gPCI_DriverStruct.RootNode.Size = giPCI_DeviceCount;
\r
152 // And add to DevFS
\r
153 DevFS_AddDevice(&gPCI_DriverStruct);
\r
159 * \fn char *PCI_ReadDirRoot(tVFS_Node *Node, int Pos)
\r
160 * \brief Read from Root of PCI Driver
\r
162 char *PCI_ReadDirRoot(tVFS_Node *Node, int Pos)
\r
164 ENTER("pNode iPos", Node, Pos);
\r
165 if(Pos < 0 || Pos >= giPCI_DeviceCount) {
\r
170 LEAVE('s', gPCI_Devices[Pos].Name);
\r
171 return strdup( gPCI_Devices[Pos].Name );
\r
174 * \fn tVFS_Node *PCI_FindDirRoot(tVFS_Node *node, char *filename)
\r
176 tVFS_Node *PCI_FindDirRoot(tVFS_Node *node, char *filename)
\r
180 // Validate Filename (Pointer and length)
\r
181 if(!filename || strlen(filename) != 7)
\r
183 // Check for spacers
\r
184 if(filename[2] != '.' || filename[5] != ':')
\r
188 if(filename[0] < '0' || filename[0] > '9') return NULL;
\r
189 bus = (filename[0] - '0')*10;
\r
190 if(filename[1] < '0' || filename[1] > '9') return NULL;
\r
191 bus += filename[1] - '0';
\r
192 if(filename[3] < '0' || filename[3] > '9') return NULL;
\r
193 slot = (filename[3] - '0')*10;
\r
194 if(filename[4] < '0' || filename[4] > '9') return NULL;
\r
195 slot += filename[4] - '0';
\r
196 if(filename[6] < '0' || filename[6] > '9') return NULL;
\r
197 fcn = filename[6] - '0';
\r
200 for(i=0;i<giPCI_DeviceCount;i++)
\r
202 if(gPCI_Devices[i].bus != bus) continue;
\r
203 if(gPCI_Devices[i].slot != slot) continue;
\r
204 if(gPCI_Devices[i].fcn != fcn) continue;
\r
206 return &gPCI_Devices[i].Node;
\r
214 * \fn Uint64 PCI_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer)
\r
216 Uint64 PCI_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer)
\r
218 if( pos + length > 256 ) return 0;
\r
222 (char*)gPCI_Devices[node->Inode].ConfigCache + pos,
\r
228 // --- Kernel Code Interface ---
\r
230 \fn int PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn)
\r
231 \brief Counts the devices with the specified codes
\r
232 \param vendor Vendor ID
\r
233 \param device Device ID
\r
234 \param fcn Function ID
\r
236 int PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn)
\r
239 for(i=0;i<giPCI_DeviceCount;i++)
\r
241 if(gPCI_Devices[i].vendor != vendor) continue;
\r
242 if(gPCI_Devices[i].device != device) continue;
\r
243 if(gPCI_Devices[i].fcn != fcn) continue;
\r
250 \fn int PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, int idx)
\r
251 \brief Gets the ID of the specified PCI device
\r
252 \param vendor Vendor ID
\r
253 \param device Device ID
\r
254 \param fcn Function IDs
\r
255 \param idx Number of matching entry wanted
\r
257 int PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, int idx)
\r
260 for(i=0;i<giPCI_DeviceCount;i++)
\r
262 if(gPCI_Devices[i].vendor != vendor) continue;
\r
263 if(gPCI_Devices[i].device != device) continue;
\r
264 if(gPCI_Devices[i].fcn != fcn) continue;
\r
265 if(j == idx) return i;
\r
272 * \fn int PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int prev)
\r
273 * \brief Gets the ID of a device by it's class code
\r
274 * \param class Class Code
\r
275 * \param mask Mask for class comparison
\r
276 * \param prev ID of previous device (-1 for no previous)
\r
278 int PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int prev)
\r
281 // Check if prev is negative (meaning get first)
\r
282 if(prev < 0) i = 0;
\r
285 for( ; i < giPCI_DeviceCount; i++ )
\r
287 if((gPCI_Devices[i].oc & mask) != class) continue;
\r
294 \fn Uint8 PCI_GetIRQ(int id)
\r
296 Uint8 PCI_GetIRQ(int id)
\r
298 if(id < 0 || id >= giPCI_DeviceCount)
\r
300 return gPCI_Devices[id].ConfigCache[15];
\r
301 //return PCI_CfgReadByte( gPCI_Devices[id].bus, gPCI_Devices[id].slot, gPCI_Devices[id].fcn, 0x3C);
\r
305 \fn Uint32 PCI_GetBAR0(int id)
\r
307 Uint32 PCI_GetBAR0(int id)
\r
309 if(id < 0 || id >= giPCI_DeviceCount)
\r
311 return gPCI_Devices[id].ConfigCache[4];
\r
315 \fn Uint32 PCI_GetBAR1(int id)
\r
317 Uint32 PCI_GetBAR1(int id)
\r
319 if(id < 0 || id >= giPCI_DeviceCount)
\r
321 return gPCI_Devices[id].ConfigCache[5];
\r
325 \fn Uint32 PCI_GetBAR2(int id)
\r
327 Uint32 PCI_GetBAR2(int id)
\r
329 if(id < 0 || id >= giPCI_DeviceCount)
\r
331 return gPCI_Devices[id].ConfigCache[6];
\r
335 \fn Uint32 PCI_GetBAR3(int id)
\r
337 Uint32 PCI_GetBAR3(int id)
\r
339 if(id < 0 || id >= giPCI_DeviceCount)
\r
341 return gPCI_Devices[id].ConfigCache[7];
\r
345 \fn Uint32 PCI_GetBAR4(int id)
\r
347 Uint32 PCI_GetBAR4(int id)
\r
349 if(id < 0 || id >= giPCI_DeviceCount)
\r
351 return gPCI_Devices[id].ConfigCache[8];
\r
355 \fn Uint32 PCI_GetBAR5(int id)
\r
357 Uint32 PCI_GetBAR5(int id)
\r
359 if(id < 0 || id >= giPCI_DeviceCount)
\r
361 return gPCI_Devices[id].ConfigCache[9];
\r
364 Uint16 PCI_AssignPort(int id, int bar, int count)
\r
371 //LogF("PCI_AssignPort: (id=%i,bar=%i,count=%i)\n", id, bar, count);
\r
373 if(id < 0 || id >= giPCI_DeviceCount) return 0;
\r
374 if(bar < 0 || bar > 5) return 0;
\r
376 dev = &gPCI_Devices[id];
\r
378 PCI_CfgWriteDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4, -1 );
\r
379 portVals = PCI_CfgReadDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4 );
\r
380 dev->ConfigCache[4+bar] = portVals;
\r
381 //LogF(" PCI_AssignPort: portVals = 0x%x\n", portVals);
\r
383 // Check for IO port
\r
384 if( !(portVals & 1) ) return 0;
\r
386 // Mask out final bit
\r
390 __asm__ __volatile__ ("bsf %%eax, %%ecx" : "=c" (gran) : "a" (portVals) );
\r
392 //LogF(" PCI_AssignPort: gran = 0x%x\n", gran);
\r
396 for( i = 0; i < 1<<16; i += gran )
\r
398 for( j = 0; j < count; j ++ )
\r
400 if( gaPCI_PortBitmap[ (i+j)>>5 ] & 1 << ((i+j)&0x1F) )
\r
411 for( j = 0; j < count; j ++ )
\r
413 if( gaPCI_PortBitmap[ (portVals+j)>>5 ] |= 1 << ((portVals+j)&0x1F) )
\r
416 PCI_CfgWriteDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4, portVals|1 );
\r
417 dev->ConfigCache[4+bar] = portVals|1;
\r
421 //LogF("PCI_AssignPort: RETURN 0x%x\n", portVals);
\r
426 * \fn int PCI_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, t_pciDevice *info)
\r
428 int PCI_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, t_pciDevice *info)
\r
434 vendor = PCI_CfgReadWord(bus, slot, fcn, 0x0|0);
\r
435 if(vendor == 0xFFFF) // Invalid Device
\r
441 info->vendor = vendor;
\r
442 info->device = PCI_CfgReadWord(bus, slot, fcn, 0x0|2);
\r
443 info->revision = PCI_CfgReadWord(bus, slot, fcn, 0x8|0);
\r
444 info->oc = PCI_CfgReadWord(bus, slot, fcn, 0x8|2);
\r
446 // Load Config Bytes
\r
447 addr = 0x80000000 | ((Uint)bus<<16) | ((Uint)slot<<11) | ((Uint)fcn<<8);
\r
448 for(i=0;i<256/4;i++)
\r
452 info->ConfigCache[i] = ind(0xCFC);
\r
455 info->ConfigCache[i] = PCI_CfgReadDWord(bus, slot, fcn, i*4);
\r
460 //Log("BAR0 0x%08x BAR1 0x%08x BAR2 0x%08x", info->ConfigCache[4], info->ConfigCache[5], info->ConfigCache[6]);
\r
461 //Log("BAR3 0x%08x BAR4 0x%08x BAR5 0x%08x", info->ConfigCache[7], info->ConfigCache[8], info->ConfigCache[9]);
\r
462 //Log("Class: 0x%04x", info->oc);
\r
466 info->Name[0] = '0' + bus/10;
\r
467 info->Name[1] = '0' + bus%10;
\r
468 info->Name[2] = '.';
\r
469 info->Name[3] = '0' + slot/10;
\r
470 info->Name[4] = '0' + slot%10;
\r
471 info->Name[5] = ':';
\r
472 info->Name[6] = '0' + fcn;
\r
473 info->Name[7] = '\0';
\r
476 memset( &info->Node, 0, sizeof(tVFS_Node) );
\r
477 info->Node.Size = 256;
\r
479 info->Node.NumACLs = 1;
\r
480 info->Node.ACLs = &gVFS_ACL_EveryoneRO;
\r
482 info->Node.Read = PCI_ReadDevice;
\r
487 Uint32 PCI_CfgReadDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset)
\r
492 bus &= 0xFF; // 8 Bits
\r
493 dev &= 0x1F; // 5 Bits
\r
494 func &= 0x7; // 3 Bits
\r
495 offset &= 0xFF; // 8 Bits
\r
497 address = 0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC);
\r
498 outd(0xCF8, address);
\r
501 return (Uint32)data;
\r
503 void PCI_CfgWriteDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset, Uint32 data)
\r
507 bus &= 0xFF; // 8 Bits
\r
508 dev &= 0x1F; // 5 Bits
\r
509 func &= 0x7; // 3 Bits
\r
510 offset &= 0xFF; // 8 Bits
\r
512 address = 0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC);
\r
513 outd(0xCF8, address);
\r
516 Uint16 PCI_CfgReadWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset)
\r
520 bus &= 0xFF; // 8 Bits
\r
521 dev &= 0x1F; // 5 Bits
\r
522 func &= 0x7; // 3 Bits
\r
523 offset &= 0xFF; // 8 Bits
\r
525 //LogF("PCI_CfgReadWord: (bus=0x%x,dev=0x%x,func=%x,offset=0x%x)\n", bus, dev, func, offset);
\r
528 0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC) );
\r
531 data >>= (offset&2)*8; //Allow Access to Upper Word
\r
532 //LogF("PCI_CfgReadWord: RETURN 0x%x\n", data&0xFFFF);
\r
533 return (Uint16)data;
\r
536 Uint8 PCI_CfgReadByte(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset)
\r
541 bus &= 0xFF; // 8 Bits
\r
542 dev &= 0x1F; // 4 Bits
\r
543 func &= 0x7; // 3 Bits
\r
544 offset &= 0xFF; // 8 Bits
\r
546 address = 0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC);
\r
547 outd(0xCF8, address);
\r
550 data >>= (offset&3)*8; //Allow Access to Upper Word
\r
551 return (Uint8)data;
\r
557 EXPORT(PCI_CountDevices);
\r
558 EXPORT(PCI_GetDevice);
\r
559 EXPORT(PCI_GetDeviceByClass);
\r
560 EXPORT(PCI_AssignPort);
\r
561 EXPORT(PCI_GetIRQ);
\r