2 AcessOS/AcessBasic v0.1
\r
7 #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 if(pos < 0 || pos >= giPCI_DeviceCount)
\r
167 return strdup( gPCI_Devices[pos].Name );
\r
170 * \fn tVFS_Node *PCI_FindDirRoot(tVFS_Node *node, char *filename)
\r
172 tVFS_Node *PCI_FindDirRoot(tVFS_Node *node, char *filename)
\r
176 // Validate Filename (Pointer and length)
\r
177 if(!filename || strlen(filename) != 7)
\r
179 // Check for spacers
\r
180 if(filename[2] != '.' || filename[5] != ':')
\r
184 if(filename[0] < '0' || filename[0] > '9') return NULL;
\r
185 bus = (filename[0] - '0')*10;
\r
186 if(filename[1] < '0' || filename[1] > '9') return NULL;
\r
187 bus += filename[1] - '0';
\r
188 if(filename[3] < '0' || filename[3] > '9') return NULL;
\r
189 slot = (filename[3] - '0')*10;
\r
190 if(filename[4] < '0' || filename[4] > '9') return NULL;
\r
191 slot += filename[4] - '0';
\r
192 if(filename[6] < '0' || filename[6] > '9') return NULL;
\r
193 fcn = filename[6] - '0';
\r
196 for(i=0;i<giPCI_DeviceCount;i++)
\r
198 if(gPCI_Devices[i].bus != bus) continue;
\r
199 if(gPCI_Devices[i].slot != slot) continue;
\r
200 if(gPCI_Devices[i].fcn != fcn) continue;
\r
202 return &gPCI_Devices[i].Node;
\r
210 * \fn Uint64 PCI_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer)
\r
212 Uint64 PCI_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer)
\r
214 if( pos + length > 256 ) return 0;
\r
218 (char*)gPCI_Devices[node->Inode].ConfigCache + pos,
\r
224 // --- Kernel Code Interface ---
\r
226 \fn int PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn)
\r
227 \brief Counts the devices with the specified codes
\r
228 \param vendor Vendor ID
\r
229 \param device Device ID
\r
230 \param fcn Function ID
\r
232 int PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn)
\r
235 for(i=0;i<giPCI_DeviceCount;i++)
\r
237 if(gPCI_Devices[i].vendor != vendor) continue;
\r
238 if(gPCI_Devices[i].device != device) continue;
\r
239 if(gPCI_Devices[i].fcn != fcn) continue;
\r
246 \fn int PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, int idx)
\r
247 \brief Gets the ID of the specified PCI device
\r
248 \param vendor Vendor ID
\r
249 \param device Device ID
\r
250 \param fcn Function IDs
\r
251 \param idx Number of matching entry wanted
\r
253 int PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, int idx)
\r
256 for(i=0;i<giPCI_DeviceCount;i++)
\r
258 if(gPCI_Devices[i].vendor != vendor) continue;
\r
259 if(gPCI_Devices[i].device != device) continue;
\r
260 if(gPCI_Devices[i].fcn != fcn) continue;
\r
261 if(j == idx) return i;
\r
268 * \fn int PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int prev)
\r
269 * \brief Gets the ID of a device by it's class code
\r
270 * \param class Class Code
\r
271 * \param mask Mask for class comparison
\r
272 * \param prev ID of previous device (-1 for no previous)
\r
274 int PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int prev)
\r
277 // Check if prev is negative (meaning get first)
\r
278 if(prev < 0) i = 0;
\r
281 for( ; i < giPCI_DeviceCount; i++ )
\r
283 if((gPCI_Devices[i].oc & mask) != class) continue;
\r
290 \fn Uint8 PCI_GetIRQ(int id)
\r
292 Uint8 PCI_GetIRQ(int id)
\r
294 if(id < 0 || id >= giPCI_DeviceCount)
\r
296 return gPCI_Devices[id].ConfigCache[15];
\r
297 //return PCI_CfgReadByte( gPCI_Devices[id].bus, gPCI_Devices[id].slot, gPCI_Devices[id].fcn, 0x3C);
\r
301 \fn Uint32 PCI_GetBAR0(int id)
\r
303 Uint32 PCI_GetBAR0(int id)
\r
305 if(id < 0 || id >= giPCI_DeviceCount)
\r
307 return gPCI_Devices[id].ConfigCache[4];
\r
311 \fn Uint32 PCI_GetBAR1(int id)
\r
313 Uint32 PCI_GetBAR1(int id)
\r
315 if(id < 0 || id >= giPCI_DeviceCount)
\r
317 return gPCI_Devices[id].ConfigCache[5];
\r
321 \fn Uint32 PCI_GetBAR2(int id)
\r
323 Uint32 PCI_GetBAR2(int id)
\r
325 if(id < 0 || id >= giPCI_DeviceCount)
\r
327 return gPCI_Devices[id].ConfigCache[6];
\r
331 \fn Uint32 PCI_GetBAR3(int id)
\r
333 Uint32 PCI_GetBAR3(int id)
\r
335 if(id < 0 || id >= giPCI_DeviceCount)
\r
337 return gPCI_Devices[id].ConfigCache[7];
\r
341 \fn Uint32 PCI_GetBAR4(int id)
\r
343 Uint32 PCI_GetBAR4(int id)
\r
345 if(id < 0 || id >= giPCI_DeviceCount)
\r
347 return gPCI_Devices[id].ConfigCache[8];
\r
351 \fn Uint32 PCI_GetBAR5(int id)
\r
353 Uint32 PCI_GetBAR5(int id)
\r
355 if(id < 0 || id >= giPCI_DeviceCount)
\r
357 return gPCI_Devices[id].ConfigCache[9];
\r
360 Uint16 PCI_AssignPort(int id, int bar, int count)
\r
367 //LogF("PCI_AssignPort: (id=%i,bar=%i,count=%i)\n", id, bar, count);
\r
369 if(id < 0 || id >= giPCI_DeviceCount) return 0;
\r
370 if(bar < 0 || bar > 5) return 0;
\r
372 dev = &gPCI_Devices[id];
\r
374 PCI_CfgWriteDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4, -1 );
\r
375 portVals = PCI_CfgReadDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4 );
\r
376 dev->ConfigCache[4+bar] = portVals;
\r
377 //LogF(" PCI_AssignPort: portVals = 0x%x\n", portVals);
\r
379 // Check for IO port
\r
380 if( !(portVals & 1) ) return 0;
\r
382 // Mask out final bit
\r
386 __asm__ __volatile__ ("bsf %%eax, %%ecx" : "=c" (gran) : "a" (portVals) );
\r
388 //LogF(" PCI_AssignPort: gran = 0x%x\n", gran);
\r
392 for( i = 0; i < 1<<16; i += gran )
\r
394 for( j = 0; j < count; j ++ )
\r
396 if( gaPCI_PortBitmap[ (i+j)>>5 ] & 1 << ((i+j)&0x1F) )
\r
407 for( j = 0; j < count; j ++ )
\r
409 if( gaPCI_PortBitmap[ (portVals+j)>>5 ] |= 1 << ((portVals+j)&0x1F) )
\r
412 PCI_CfgWriteDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4, portVals|1 );
\r
413 dev->ConfigCache[4+bar] = portVals|1;
\r
417 //LogF("PCI_AssignPort: RETURN 0x%x\n", portVals);
\r
422 * \fn int PCI_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, t_pciDevice *info)
\r
424 int PCI_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, t_pciDevice *info)
\r
430 vendor = PCI_CfgReadWord(bus, slot, fcn, 0x0|0);
\r
431 if(vendor == 0xFFFF) // Invalid Device
\r
437 info->vendor = vendor;
\r
438 info->device = PCI_CfgReadWord(bus, slot, fcn, 0x0|2);
\r
439 info->revision = PCI_CfgReadWord(bus, slot, fcn, 0x8|0);
\r
440 info->oc = PCI_CfgReadWord(bus, slot, fcn, 0x8|2);
\r
442 // Load Config Bytes
\r
443 addr = 0x80000000 | ((Uint)bus<<16) | ((Uint)slot<<11) | ((Uint)fcn<<8);
\r
444 for(i=0;i<256/4;i++)
\r
448 info->ConfigCache[i] = ind(0xCFC);
\r
451 info->ConfigCache[i] = PCI_CfgReadDWord(bus, slot, fcn, i*4);
\r
456 //Log("BAR0 0x%08x BAR1 0x%08x BAR2 0x%08x", info->ConfigCache[4], info->ConfigCache[5], info->ConfigCache[6]);
\r
457 //Log("BAR3 0x%08x BAR4 0x%08x BAR5 0x%08x", info->ConfigCache[7], info->ConfigCache[8], info->ConfigCache[9]);
\r
458 //Log("Class: 0x%04x", info->oc);
\r
462 info->Name[0] = '0' + bus/10;
\r
463 info->Name[1] = '0' + bus%10;
\r
464 info->Name[2] = '.';
\r
465 info->Name[3] = '0' + slot/10;
\r
466 info->Name[4] = '0' + slot%10;
\r
467 info->Name[5] = '.';
\r
468 info->Name[6] = '0' + fcn;
\r
469 info->Name[7] = '\0';
\r
472 memset( &info->Node, 0, sizeof(tVFS_Node) );
\r
473 info->Node.Size = 256;
\r
475 info->Node.NumACLs = 1;
\r
476 info->Node.ACLs = &gVFS_ACL_EveryoneRO;
\r
478 info->Node.Read = PCI_ReadDevice;
\r
483 Uint32 PCI_CfgReadDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset)
\r
488 bus &= 0xFF; // 8 Bits
\r
489 dev &= 0x1F; // 5 Bits
\r
490 func &= 0x7; // 3 Bits
\r
491 offset &= 0xFF; // 8 Bits
\r
493 address = 0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC);
\r
494 outd(0xCF8, address);
\r
497 return (Uint32)data;
\r
499 void PCI_CfgWriteDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset, Uint32 data)
\r
503 bus &= 0xFF; // 8 Bits
\r
504 dev &= 0x1F; // 5 Bits
\r
505 func &= 0x7; // 3 Bits
\r
506 offset &= 0xFF; // 8 Bits
\r
508 address = 0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC);
\r
509 outd(0xCF8, address);
\r
512 Uint16 PCI_CfgReadWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset)
\r
516 bus &= 0xFF; // 8 Bits
\r
517 dev &= 0x1F; // 5 Bits
\r
518 func &= 0x7; // 3 Bits
\r
519 offset &= 0xFF; // 8 Bits
\r
521 //LogF("PCI_CfgReadWord: (bus=0x%x,dev=0x%x,func=%x,offset=0x%x)\n", bus, dev, func, offset);
\r
524 0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC) );
\r
527 data >>= (offset&2)*8; //Allow Access to Upper Word
\r
528 //LogF("PCI_CfgReadWord: RETURN 0x%x\n", data&0xFFFF);
\r
529 return (Uint16)data;
\r
532 Uint8 PCI_CfgReadByte(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset)
\r
537 bus &= 0xFF; // 8 Bits
\r
538 dev &= 0x1F; // 4 Bits
\r
539 func &= 0x7; // 3 Bits
\r
540 offset &= 0xFF; // 8 Bits
\r
542 address = 0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC);
\r
543 outd(0xCF8, address);
\r
546 data >>= (offset&3)*8; //Allow Access to Upper Word
\r
547 return (Uint8)data;
\r
553 EXPORT(PCI_CountDevices);
\r
554 EXPORT(PCI_GetDevice);
\r
555 EXPORT(PCI_AssignPort);
\r
556 EXPORT(PCI_GetIRQ);
\r