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 s_pciDevice {
\r
16 Uint16 bus, slot, fcn;
\r
17 Uint16 vendor, device;
\r
19 struct {Uint8 class, subclass;};
\r
23 Uint32 ConfigCache[256/4];
\r
28 // === CONSTANTS ===
\r
29 #define SPACE_STEP 5
\r
30 #define MAX_RESERVED_PORT 0xD00
\r
32 // === PROTOTYPES ===
\r
33 int PCI_Install(char **Arguments);
\r
34 char *PCI_ReadDirRoot(tVFS_Node *node, int pos);
\r
35 tVFS_Node *PCI_FindDirRoot(tVFS_Node *node, char *filename);
\r
36 Uint64 PCI_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer);
\r
38 int PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn);
\r
39 int PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, int idx);
\r
40 int PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int prev);
\r
41 Uint8 PCI_GetIRQ(int id);
\r
42 Uint32 PCI_GetBAR0(int id);
\r
43 Uint32 PCI_GetBAR1(int id);
\r
44 Uint32 PCI_GetBAR3(int id);
\r
45 Uint32 PCI_GetBAR4(int id);
\r
46 Uint32 PCI_GetBAR5(int id);
\r
47 Uint16 PCI_AssignPort(int id, int bar, int count);
\r
49 int PCI_EnumDevice(Uint16 bus, Uint16 dev, Uint16 fcn, t_pciDevice *info);
\r
50 Uint32 PCI_CfgReadDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset);
\r
51 void PCI_CfgWriteDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset, Uint32 data);
\r
52 Uint16 PCI_CfgReadWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset);
\r
53 Uint8 PCI_CfgReadByte(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset);
\r
56 //MODULE_DEFINE(0, 0x0100, PCI, PCI_Install, NULL);
\r
57 int giPCI_BusCount = 1;
\r
58 int giPCI_InodeHandle = -1;
\r
59 int giPCI_DeviceCount = 0;
\r
60 t_pciDevice *gPCI_Devices = NULL;
\r
61 tDevFS_Driver gPCI_DriverStruct = {
\r
64 .Flags = VFS_FFLAG_DIRECTORY,
\r
67 .ACLs = &gVFS_ACL_EveryoneRX,
\r
68 .ReadDir = PCI_ReadDirRoot,
\r
69 .FindDir = PCI_FindDirRoot
\r
72 Uint32 *gaPCI_PortBitmap = NULL;
\r
76 * \fn int PCI_Install()
\r
77 * \brief Scan the PCI Bus for devices
\r
79 int PCI_Install(char **Arguments)
\r
81 int bus, dev, fcn, i;
\r
83 t_pciDevice devInfo;
\r
84 void *tmpPtr = NULL;
\r
87 gaPCI_PortBitmap = malloc( 1 << 13 );
\r
88 memset( gaPCI_PortBitmap, 0, 1 << 13 );
\r
89 for( i = 0; i < MAX_RESERVED_PORT / 32; i ++ )
\r
90 gaPCI_PortBitmap[i] = -1;
\r
91 for( i = 0; i < MAX_RESERVED_PORT % 32; i ++ )
\r
92 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
144 if(giPCI_DeviceCount == 0)
\r
145 return MODULE_ERR_NOTNEEDED;
\r
147 tmpPtr = realloc(gPCI_Devices, giPCI_DeviceCount*sizeof(t_pciDevice));
\r
149 return MODULE_ERR_MALLOC;
\r
150 gPCI_Devices = tmpPtr;
\r
152 // Complete Driver Structure
\r
153 gPCI_DriverStruct.RootNode.Size = giPCI_DeviceCount;
\r
155 // And add to DevFS
\r
156 DevFS_AddDevice(&gPCI_DriverStruct);
\r
158 return MODULE_ERR_OK;
\r
162 * \fn char *PCI_ReadDirRoot(tVFS_Node *Node, int Pos)
\r
163 * \brief Read from Root of PCI Driver
\r
165 char *PCI_ReadDirRoot(tVFS_Node *Node, int Pos)
\r
167 ENTER("pNode iPos", Node, Pos);
\r
168 if(Pos < 0 || Pos >= giPCI_DeviceCount) {
\r
173 LEAVE('s', gPCI_Devices[Pos].Name);
\r
174 return strdup( gPCI_Devices[Pos].Name );
\r
177 * \fn tVFS_Node *PCI_FindDirRoot(tVFS_Node *node, char *filename)
\r
179 tVFS_Node *PCI_FindDirRoot(tVFS_Node *node, char *filename)
\r
183 // Validate Filename (Pointer and length)
\r
184 if(!filename || strlen(filename) != 7)
\r
186 // Check for spacers
\r
187 if(filename[2] != '.' || filename[5] != ':')
\r
191 if(filename[0] < '0' || filename[0] > '9') return NULL;
\r
192 bus = (filename[0] - '0')*10;
\r
193 if(filename[1] < '0' || filename[1] > '9') return NULL;
\r
194 bus += filename[1] - '0';
\r
195 if(filename[3] < '0' || filename[3] > '9') return NULL;
\r
196 slot = (filename[3] - '0')*10;
\r
197 if(filename[4] < '0' || filename[4] > '9') return NULL;
\r
198 slot += filename[4] - '0';
\r
199 if(filename[6] < '0' || filename[6] > '9') return NULL;
\r
200 fcn = filename[6] - '0';
\r
203 for(i=0;i<giPCI_DeviceCount;i++)
\r
205 if(gPCI_Devices[i].bus != bus) continue;
\r
206 if(gPCI_Devices[i].slot != slot) continue;
\r
207 if(gPCI_Devices[i].fcn != fcn) continue;
\r
209 return &gPCI_Devices[i].Node;
\r
217 * \fn Uint64 PCI_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer)
\r
219 Uint64 PCI_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer)
\r
221 if( pos + length > 256 ) return 0;
\r
225 (char*)gPCI_Devices[node->Inode].ConfigCache + pos,
\r
231 // --- Kernel Code Interface ---
\r
233 \fn int PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn)
\r
234 \brief Counts the devices with the specified codes
\r
235 \param vendor Vendor ID
\r
236 \param device Device ID
\r
237 \param fcn Function ID
\r
239 int PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn)
\r
242 for(i=0;i<giPCI_DeviceCount;i++)
\r
244 if(gPCI_Devices[i].vendor != vendor) continue;
\r
245 if(gPCI_Devices[i].device != device) continue;
\r
246 if(gPCI_Devices[i].fcn != fcn) continue;
\r
253 \fn int PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, int idx)
\r
254 \brief Gets the ID of the specified PCI device
\r
255 \param vendor Vendor ID
\r
256 \param device Device ID
\r
257 \param fcn Function IDs
\r
258 \param idx Number of matching entry wanted
\r
260 int PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, int idx)
\r
263 for(i=0;i<giPCI_DeviceCount;i++)
\r
265 if(gPCI_Devices[i].vendor != vendor) continue;
\r
266 if(gPCI_Devices[i].device != device) continue;
\r
267 if(gPCI_Devices[i].fcn != fcn) continue;
\r
268 if(j == idx) return i;
\r
275 * \fn int PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int prev)
\r
276 * \brief Gets the ID of a device by it's class code
\r
277 * \param class Class Code
\r
278 * \param mask Mask for class comparison
\r
279 * \param prev ID of previous device (-1 for no previous)
\r
281 int PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int prev)
\r
284 // Check if prev is negative (meaning get first)
\r
285 if(prev < 0) i = 0;
\r
288 for( ; i < giPCI_DeviceCount; i++ )
\r
290 if((gPCI_Devices[i].oc & mask) != class) continue;
\r
297 \fn Uint8 PCI_GetIRQ(int id)
\r
299 Uint8 PCI_GetIRQ(int id)
\r
301 if(id < 0 || id >= giPCI_DeviceCount)
\r
303 return gPCI_Devices[id].ConfigCache[15];
\r
304 //return PCI_CfgReadByte( gPCI_Devices[id].bus, gPCI_Devices[id].slot, gPCI_Devices[id].fcn, 0x3C);
\r
308 \fn Uint32 PCI_GetBAR0(int id)
\r
310 Uint32 PCI_GetBAR0(int id)
\r
312 if(id < 0 || id >= giPCI_DeviceCount)
\r
314 return gPCI_Devices[id].ConfigCache[4];
\r
318 \fn Uint32 PCI_GetBAR1(int id)
\r
320 Uint32 PCI_GetBAR1(int id)
\r
322 if(id < 0 || id >= giPCI_DeviceCount)
\r
324 return gPCI_Devices[id].ConfigCache[5];
\r
328 \fn Uint32 PCI_GetBAR2(int id)
\r
330 Uint32 PCI_GetBAR2(int id)
\r
332 if(id < 0 || id >= giPCI_DeviceCount)
\r
334 return gPCI_Devices[id].ConfigCache[6];
\r
338 \fn Uint32 PCI_GetBAR3(int id)
\r
340 Uint32 PCI_GetBAR3(int id)
\r
342 if(id < 0 || id >= giPCI_DeviceCount)
\r
344 return gPCI_Devices[id].ConfigCache[7];
\r
348 \fn Uint32 PCI_GetBAR4(int id)
\r
350 Uint32 PCI_GetBAR4(int id)
\r
352 if(id < 0 || id >= giPCI_DeviceCount)
\r
354 return gPCI_Devices[id].ConfigCache[8];
\r
358 \fn Uint32 PCI_GetBAR5(int id)
\r
360 Uint32 PCI_GetBAR5(int id)
\r
362 if(id < 0 || id >= giPCI_DeviceCount)
\r
364 return gPCI_Devices[id].ConfigCache[9];
\r
367 Uint16 PCI_AssignPort(int id, int bar, int count)
\r
374 //LogF("PCI_AssignPort: (id=%i,bar=%i,count=%i)\n", id, bar, count);
\r
376 if(id < 0 || id >= giPCI_DeviceCount) return 0;
\r
377 if(bar < 0 || bar > 5) return 0;
\r
379 dev = &gPCI_Devices[id];
\r
381 PCI_CfgWriteDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4, -1 );
\r
382 portVals = PCI_CfgReadDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4 );
\r
383 dev->ConfigCache[4+bar] = portVals;
\r
384 //LogF(" PCI_AssignPort: portVals = 0x%x\n", portVals);
\r
386 // Check for IO port
\r
387 if( !(portVals & 1) ) return 0;
\r
389 // Mask out final bit
\r
393 __asm__ __volatile__ ("bsf %%eax, %%ecx" : "=c" (gran) : "a" (portVals) );
\r
395 //LogF(" PCI_AssignPort: gran = 0x%x\n", gran);
\r
399 for( i = 0; i < 1<<16; i += gran )
\r
401 for( j = 0; j < count; j ++ )
\r
403 if( gaPCI_PortBitmap[ (i+j)>>5 ] & 1 << ((i+j)&0x1F) )
\r
414 for( j = 0; j < count; j ++ )
\r
416 if( gaPCI_PortBitmap[ (portVals+j)>>5 ] |= 1 << ((portVals+j)&0x1F) )
\r
419 PCI_CfgWriteDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4, portVals|1 );
\r
420 dev->ConfigCache[4+bar] = portVals|1;
\r
424 //LogF("PCI_AssignPort: RETURN 0x%x\n", portVals);
\r
429 * \fn int PCI_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, t_pciDevice *info)
\r
431 int PCI_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, t_pciDevice *info)
\r
437 vendor = PCI_CfgReadWord(bus, slot, fcn, 0x0|0);
\r
438 if(vendor == 0xFFFF) // Invalid Device
\r
444 info->vendor = vendor;
\r
445 info->device = PCI_CfgReadWord(bus, slot, fcn, 0x0|2);
\r
446 info->revision = PCI_CfgReadWord(bus, slot, fcn, 0x8|0);
\r
447 info->oc = PCI_CfgReadWord(bus, slot, fcn, 0x8|2);
\r
449 // Load Config Bytes
\r
450 addr = 0x80000000 | ((Uint)bus<<16) | ((Uint)slot<<11) | ((Uint)fcn<<8);
\r
451 for(i=0;i<256/4;i++)
\r
455 info->ConfigCache[i] = ind(0xCFC);
\r
458 info->ConfigCache[i] = PCI_CfgReadDWord(bus, slot, fcn, i*4);
\r
463 //Log("BAR0 0x%08x BAR1 0x%08x BAR2 0x%08x", info->ConfigCache[4], info->ConfigCache[5], info->ConfigCache[6]);
\r
464 //Log("BAR3 0x%08x BAR4 0x%08x BAR5 0x%08x", info->ConfigCache[7], info->ConfigCache[8], info->ConfigCache[9]);
\r
465 //Log("Class: 0x%04x", info->oc);
\r
469 info->Name[0] = '0' + bus/10;
\r
470 info->Name[1] = '0' + bus%10;
\r
471 info->Name[2] = '.';
\r
472 info->Name[3] = '0' + slot/10;
\r
473 info->Name[4] = '0' + slot%10;
\r
474 info->Name[5] = ':';
\r
475 info->Name[6] = '0' + fcn;
\r
476 info->Name[7] = '\0';
\r
479 memset( &info->Node, 0, sizeof(tVFS_Node) );
\r
480 info->Node.Size = 256;
\r
482 info->Node.NumACLs = 1;
\r
483 info->Node.ACLs = &gVFS_ACL_EveryoneRO;
\r
485 info->Node.Read = PCI_ReadDevice;
\r
490 Uint32 PCI_CfgReadDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset)
\r
495 bus &= 0xFF; // 8 Bits
\r
496 dev &= 0x1F; // 5 Bits
\r
497 func &= 0x7; // 3 Bits
\r
498 offset &= 0xFF; // 8 Bits
\r
500 address = 0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC);
\r
501 outd(0xCF8, address);
\r
504 return (Uint32)data;
\r
506 void PCI_CfgWriteDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset, Uint32 data)
\r
510 bus &= 0xFF; // 8 Bits
\r
511 dev &= 0x1F; // 5 Bits
\r
512 func &= 0x7; // 3 Bits
\r
513 offset &= 0xFF; // 8 Bits
\r
515 address = 0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC);
\r
516 outd(0xCF8, address);
\r
519 Uint16 PCI_CfgReadWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset)
\r
523 bus &= 0xFF; // 8 Bits
\r
524 dev &= 0x1F; // 5 Bits
\r
525 func &= 0x7; // 3 Bits
\r
526 offset &= 0xFF; // 8 Bits
\r
528 //LogF("PCI_CfgReadWord: (bus=0x%x,dev=0x%x,func=%x,offset=0x%x)\n", bus, dev, func, offset);
\r
531 0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC) );
\r
534 data >>= (offset&2)*8; //Allow Access to Upper Word
\r
535 //LogF("PCI_CfgReadWord: RETURN 0x%x\n", data&0xFFFF);
\r
536 return (Uint16)data;
\r
539 Uint8 PCI_CfgReadByte(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset)
\r
544 bus &= 0xFF; // 8 Bits
\r
545 dev &= 0x1F; // 4 Bits
\r
546 func &= 0x7; // 3 Bits
\r
547 offset &= 0xFF; // 8 Bits
\r
549 address = 0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC);
\r
550 outd(0xCF8, address);
\r
553 data >>= (offset&3)*8; //Allow Access to Upper Word
\r
554 return (Uint8)data;
\r
560 EXPORT(PCI_CountDevices);
\r
561 EXPORT(PCI_GetDevice);
\r
562 EXPORT(PCI_GetDeviceByClass);
\r
563 EXPORT(PCI_AssignPort);
\r
564 EXPORT(PCI_GetIRQ);
\r