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
65 .ACLs = &gVFS_ACL_EveryoneRX,
\r
66 .ReadDir = PCI_ReadDirRoot,
\r
67 .FindDir = PCI_FindDirRoot
\r
70 Uint32 *gaPCI_PortBitmap = NULL;
\r
74 * \fn int PCI_Install()
\r
75 * \brief Scan the PCI Bus for devices
\r
77 int PCI_Install(char **Arguments)
\r
79 int bus, dev, fcn, i;
\r
81 t_pciDevice devInfo;
\r
82 void *tmpPtr = NULL;
\r
85 gaPCI_PortBitmap = malloc( 1 << 13 );
\r
86 memset( gaPCI_PortBitmap, 0, 1 << 13 );
\r
87 for( i = 0; i < MAX_RESERVED_PORT / 32; i ++ )
\r
88 gaPCI_PortBitmap[i] = -1;
\r
89 for( i = 0; i < MAX_RESERVED_PORT % 32; i ++ )
\r
90 gaPCI_PortBitmap[MAX_RESERVED_PORT / 32] = 1 << i;
\r
94 for( bus = 0; bus < giPCI_BusCount; bus++ )
\r
96 for( dev = 0; dev < 10; dev++ ) // 10 Devices per bus
\r
98 for( fcn = 0; fcn < 8; fcn++ ) // 8 functions per device
\r
100 // Check if the device/function exists
\r
101 if(!PCI_EnumDevice(bus, dev, fcn, &devInfo))
\r
106 if(giPCI_DeviceCount == space)
\r
108 space += SPACE_STEP;
\r
109 tmpPtr = realloc(gPCI_Devices, space*sizeof(t_pciDevice));
\r
112 gPCI_Devices = tmpPtr;
\r
114 if(devInfo.oc == PCI_OC_PCIBRIDGE)
\r
117 Log("[PCI ] Bridge @ %i,%i:%i (0x%x:0x%x)",
\r
118 bus, dev, fcn, devInfo.vendor, devInfo.device);
\r
122 devInfo.Node.Inode = giPCI_DeviceCount;
\r
123 memcpy(&gPCI_Devices[giPCI_DeviceCount], &devInfo, sizeof(t_pciDevice));
\r
124 giPCI_DeviceCount ++;
\r
126 Log("[PCI ] Device %i,%i:%i => 0x%x:0x%x",
\r
127 bus, dev, fcn, devInfo.vendor, devInfo.device);
\r
130 // WTF is this for?
\r
132 if( !(devInfo.ConfigCache[3] & 0x800000) )
\r
136 if(tmpPtr != gPCI_Devices)
\r
139 if(tmpPtr != gPCI_Devices)
\r
142 tmpPtr = realloc(gPCI_Devices, giPCI_DeviceCount*sizeof(t_pciDevice));
\r
145 gPCI_Devices = tmpPtr;
\r
148 // Complete Driver Structure
\r
149 gPCI_DriverStruct.RootNode.Size = giPCI_DeviceCount;
\r
151 // And add to DevFS
\r
152 DevFS_AddDevice(&gPCI_DriverStruct);
\r
158 * \fn char *PCI_ReadDirRoot(tVFS_Node *node, int pos)
\r
159 * \brief Read from Root of PCI Driver
\r
161 char *PCI_ReadDirRoot(tVFS_Node *node, int pos)
\r
163 if(pos < 0 || pos >= giPCI_DeviceCount)
\r
166 return gPCI_Devices[pos].Name;
\r
169 * \fn tVFS_Node *PCI_FindDirRoot(tVFS_Node *node, char *filename)
\r
171 tVFS_Node *PCI_FindDirRoot(tVFS_Node *node, char *filename)
\r
175 // Validate Filename (Pointer and length)
\r
176 if(!filename || strlen(filename) != 7)
\r
178 // Check for spacers
\r
179 if(filename[2] != '.' || filename[5] != ':')
\r
183 if(filename[0] < '0' || filename[0] > '9') return NULL;
\r
184 bus = (filename[0] - '0')*10;
\r
185 if(filename[1] < '0' || filename[1] > '9') return NULL;
\r
186 bus += filename[1] - '0';
\r
187 if(filename[3] < '0' || filename[3] > '9') return NULL;
\r
188 slot = (filename[3] - '0')*10;
\r
189 if(filename[4] < '0' || filename[4] > '9') return NULL;
\r
190 slot += filename[4] - '0';
\r
191 if(filename[6] < '0' || filename[6] > '9') return NULL;
\r
192 fcn = filename[6] - '0';
\r
195 for(i=0;i<giPCI_DeviceCount;i++)
\r
197 if(gPCI_Devices[i].bus != bus) continue;
\r
198 if(gPCI_Devices[i].slot != slot) continue;
\r
199 if(gPCI_Devices[i].fcn != fcn) continue;
\r
201 return &gPCI_Devices[i].Node;
\r
209 * \fn Uint64 PCI_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer)
\r
211 Uint64 PCI_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer)
\r
213 if( pos + length > 256 ) return 0;
\r
217 (char*)gPCI_Devices[node->Inode].ConfigCache + pos,
\r
223 // --- Kernel Code Interface ---
\r
225 \fn int PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn)
\r
226 \brief Counts the devices with the specified codes
\r
227 \param vendor Vendor ID
\r
228 \param device Device ID
\r
229 \param fcn Function ID
\r
231 int PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn)
\r
234 for(i=0;i<giPCI_DeviceCount;i++)
\r
236 if(gPCI_Devices[i].vendor != vendor) continue;
\r
237 if(gPCI_Devices[i].device != device) continue;
\r
238 if(gPCI_Devices[i].fcn != fcn) continue;
\r
245 \fn int PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, int idx)
\r
246 \brief Gets the ID of the specified PCI device
\r
247 \param vendor Vendor ID
\r
248 \param device Device ID
\r
249 \param fcn Function IDs
\r
250 \param idx Number of matching entry wanted
\r
252 int PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, int idx)
\r
255 for(i=0;i<giPCI_DeviceCount;i++)
\r
257 if(gPCI_Devices[i].vendor != vendor) continue;
\r
258 if(gPCI_Devices[i].device != device) continue;
\r
259 if(gPCI_Devices[i].fcn != fcn) continue;
\r
260 if(j == idx) return i;
\r
267 * \fn int PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int prev)
\r
268 * \brief Gets the ID of a device by it's class code
\r
269 * \param class Class Code
\r
270 * \param mask Mask for class comparison
\r
271 * \param prev ID of previous device (-1 for no previous)
\r
273 int PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int prev)
\r
276 // Check if prev is negative (meaning get first)
\r
277 if(prev < 0) i = 0;
\r
280 for( ; i < giPCI_DeviceCount; i++ )
\r
282 if((gPCI_Devices[i].oc & mask) != class) continue;
\r
289 \fn Uint8 PCI_GetIRQ(int id)
\r
291 Uint8 PCI_GetIRQ(int id)
\r
293 if(id < 0 || id >= giPCI_DeviceCount)
\r
295 return gPCI_Devices[id].ConfigCache[15];
\r
296 //return PCI_CfgReadByte( gPCI_Devices[id].bus, gPCI_Devices[id].slot, gPCI_Devices[id].fcn, 0x3C);
\r
300 \fn Uint32 PCI_GetBAR0(int id)
\r
302 Uint32 PCI_GetBAR0(int id)
\r
304 if(id < 0 || id >= giPCI_DeviceCount)
\r
306 return gPCI_Devices[id].ConfigCache[4];
\r
310 \fn Uint32 PCI_GetBAR1(int id)
\r
312 Uint32 PCI_GetBAR1(int id)
\r
314 if(id < 0 || id >= giPCI_DeviceCount)
\r
316 return gPCI_Devices[id].ConfigCache[5];
\r
320 \fn Uint32 PCI_GetBAR2(int id)
\r
322 Uint32 PCI_GetBAR2(int id)
\r
324 if(id < 0 || id >= giPCI_DeviceCount)
\r
326 return gPCI_Devices[id].ConfigCache[6];
\r
330 \fn Uint32 PCI_GetBAR3(int id)
\r
332 Uint32 PCI_GetBAR3(int id)
\r
334 if(id < 0 || id >= giPCI_DeviceCount)
\r
336 return gPCI_Devices[id].ConfigCache[7];
\r
340 \fn Uint32 PCI_GetBAR4(int id)
\r
342 Uint32 PCI_GetBAR4(int id)
\r
344 if(id < 0 || id >= giPCI_DeviceCount)
\r
346 return gPCI_Devices[id].ConfigCache[8];
\r
350 \fn Uint32 PCI_GetBAR5(int id)
\r
352 Uint32 PCI_GetBAR5(int id)
\r
354 if(id < 0 || id >= giPCI_DeviceCount)
\r
356 return gPCI_Devices[id].ConfigCache[9];
\r
359 Uint16 PCI_AssignPort(int id, int bar, int count)
\r
366 //LogF("PCI_AssignPort: (id=%i,bar=%i,count=%i)\n", id, bar, count);
\r
368 if(id < 0 || id >= giPCI_DeviceCount) return 0;
\r
369 if(bar < 0 || bar > 5) return 0;
\r
371 dev = &gPCI_Devices[id];
\r
373 PCI_CfgWriteDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4, -1 );
\r
374 portVals = PCI_CfgReadDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4 );
\r
375 dev->ConfigCache[4+bar] = portVals;
\r
376 //LogF(" PCI_AssignPort: portVals = 0x%x\n", portVals);
\r
378 // Check for IO port
\r
379 if( !(portVals & 1) ) return 0;
\r
381 // Mask out final bit
\r
385 __asm__ __volatile__ ("bsf %%eax, %%ecx" : "=c" (gran) : "a" (portVals) );
\r
387 //LogF(" PCI_AssignPort: gran = 0x%x\n", gran);
\r
391 for( i = 0; i < 1<<16; i += gran )
\r
393 for( j = 0; j < count; j ++ )
\r
395 if( gaPCI_PortBitmap[ (i+j)>>5 ] & 1 << ((i+j)&0x1F) )
\r
406 for( j = 0; j < count; j ++ )
\r
408 if( gaPCI_PortBitmap[ (portVals+j)>>5 ] |= 1 << ((portVals+j)&0x1F) )
\r
411 PCI_CfgWriteDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4, portVals|1 );
\r
412 dev->ConfigCache[4+bar] = portVals|1;
\r
416 //LogF("PCI_AssignPort: RETURN 0x%x\n", portVals);
\r
421 * \fn int PCI_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, t_pciDevice *info)
\r
423 int PCI_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, t_pciDevice *info)
\r
429 vendor = PCI_CfgReadWord(bus, slot, fcn, 0x0|0);
\r
430 if(vendor == 0xFFFF) // Invalid Device
\r
436 info->vendor = vendor;
\r
437 info->device = PCI_CfgReadWord(bus, slot, fcn, 0x0|2);
\r
438 info->revision = PCI_CfgReadWord(bus, slot, fcn, 0x8|0);
\r
439 info->oc = PCI_CfgReadWord(bus, slot, fcn, 0x8|2);
\r
441 // Load Config Bytes
\r
442 addr = 0x80000000 | ((Uint)bus<<16) | ((Uint)slot<<11) | ((Uint)fcn<<8);
\r
443 for(i=0;i<256/4;i++)
\r
447 info->ConfigCache[i] = ind(0xCFC);
\r
450 info->ConfigCache[i] = PCI_CfgReadDWord(bus, slot, fcn, i*4);
\r
455 //Log("BAR0 0x%08x BAR1 0x%08x BAR2 0x%08x", info->ConfigCache[4], info->ConfigCache[5], info->ConfigCache[6]);
\r
456 //Log("BAR3 0x%08x BAR4 0x%08x BAR5 0x%08x", info->ConfigCache[7], info->ConfigCache[8], info->ConfigCache[9]);
\r
457 //Log("Class: 0x%04x", info->oc);
\r
461 info->Name[0] = '0' + bus/10;
\r
462 info->Name[1] = '0' + bus%10;
\r
463 info->Name[2] = '.';
\r
464 info->Name[3] = '0' + slot/10;
\r
465 info->Name[4] = '0' + slot%10;
\r
466 info->Name[5] = '.';
\r
467 info->Name[6] = '0' + fcn;
\r
468 info->Name[7] = '\0';
\r
471 memset( &info->Node, 0, sizeof(tVFS_Node) );
\r
472 info->Node.Size = 256;
\r
474 info->Node.NumACLs = 1;
\r
475 info->Node.ACLs = &gVFS_ACL_EveryoneRO;
\r
477 info->Node.Read = PCI_ReadDevice;
\r
482 Uint32 PCI_CfgReadDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset)
\r
487 bus &= 0xFF; // 8 Bits
\r
488 dev &= 0x1F; // 5 Bits
\r
489 func &= 0x7; // 3 Bits
\r
490 offset &= 0xFF; // 8 Bits
\r
492 address = 0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC);
\r
493 outd(0xCF8, address);
\r
496 return (Uint32)data;
\r
498 void PCI_CfgWriteDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset, Uint32 data)
\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 Uint16 PCI_CfgReadWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset)
\r
515 bus &= 0xFF; // 8 Bits
\r
516 dev &= 0x1F; // 5 Bits
\r
517 func &= 0x7; // 3 Bits
\r
518 offset &= 0xFF; // 8 Bits
\r
520 //LogF("PCI_CfgReadWord: (bus=0x%x,dev=0x%x,func=%x,offset=0x%x)\n", bus, dev, func, offset);
\r
523 0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC) );
\r
526 data >>= (offset&2)*8; //Allow Access to Upper Word
\r
527 //LogF("PCI_CfgReadWord: RETURN 0x%x\n", data&0xFFFF);
\r
528 return (Uint16)data;
\r
531 Uint8 PCI_CfgReadByte(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset)
\r
536 bus &= 0xFF; // 8 Bits
\r
537 dev &= 0x1F; // 4 Bits
\r
538 func &= 0x7; // 3 Bits
\r
539 offset &= 0xFF; // 8 Bits
\r
541 address = 0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC);
\r
542 outd(0xCF8, address);
\r
545 data >>= (offset&3)*8; //Allow Access to Upper Word
\r
546 return (Uint8)data;
\r
552 EXPORT(PCI_CountDevices);
\r
553 EXPORT(PCI_GetDevice);
\r
554 EXPORT(PCI_AssignPort);
\r
555 EXPORT(PCI_GetIRQ);
\r