Added some very pedantic warning flags
[tpg/acess2.git] / Kernel / drv / pci.c
1 /*\r
2  * AcessOS/AcessBasic v0.1\r
3  * PCI Bus Driver\r
4  */\r
5 #define DEBUG   0\r
6 #include <acess.h>\r
7 #include <modules.h>\r
8 #include <vfs.h>\r
9 #include <fs_devfs.h>\r
10 #include <drv_pci.h>\r
11 \r
12 #define LIST_DEVICES    1\r
13 \r
14 // === STRUCTURES ===\r
15 typedef struct sPCIDevice\r
16 {\r
17         Uint16  bus, slot, fcn;\r
18         Uint16  vendor, device;\r
19         union {\r
20                 struct {\r
21                         Uint8 class, subclass;\r
22                 };\r
23                 Uint16  oc;\r
24         };\r
25         Uint16  revision;\r
26         Uint32  ConfigCache[256/4];\r
27         char    Name[8];\r
28         tVFS_Node       Node;\r
29 } tPCIDevice;\r
30 \r
31 // === CONSTANTS ===\r
32 #define SPACE_STEP      5\r
33 #define MAX_RESERVED_PORT       0xD00\r
34 \r
35 // === PROTOTYPES ===\r
36  int    PCI_Install(char **Arguments);\r
37  int    PCI_ScanBus(int ID, int bFill);\r
38  \r
39 char    *PCI_ReadDirRoot(tVFS_Node *node, int pos);\r
40 tVFS_Node       *PCI_FindDirRoot(tVFS_Node *node, const char *filename);\r
41 Uint64  PCI_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer);\r
42 \r
43 #if 0\r
44  int    PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn);\r
45  int    PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, int idx);\r
46  int    PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int prev);\r
47 Uint8   PCI_GetIRQ(int id);\r
48 Uint32  PCI_GetBAR0(int id);\r
49 Uint32  PCI_GetBAR1(int id);\r
50 Uint32  PCI_GetBAR2(int id);\r
51 Uint32  PCI_GetBAR3(int id);\r
52 Uint32  PCI_GetBAR4(int id);\r
53 Uint32  PCI_GetBAR5(int id);\r
54 Uint16  PCI_AssignPort(int id, int bar, int count);\r
55 #endif\r
56 \r
57  int    PCI_EnumDevice(Uint16 bus, Uint16 dev, Uint16 fcn, tPCIDevice *info);\r
58 Uint32  PCI_CfgReadDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset);\r
59 void    PCI_CfgWriteDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset, Uint32 data);\r
60 Uint16  PCI_CfgReadWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset);\r
61 Uint8   PCI_CfgReadByte(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset);\r
62 \r
63 // === GLOBALS ===\r
64 MODULE_DEFINE(0, 0x0100, PCI, PCI_Install, NULL, NULL);\r
65  int    giPCI_BusCount = 1;\r
66  int    giPCI_InodeHandle = -1;\r
67  int    giPCI_DeviceCount = 0;\r
68 tPCIDevice      *gPCI_Devices = NULL;\r
69 tDevFS_Driver   gPCI_DriverStruct = {\r
70         NULL, "pci",\r
71         {\r
72         .Flags = VFS_FFLAG_DIRECTORY,\r
73         .Size = -1,\r
74         .NumACLs = 1,\r
75         .ACLs = &gVFS_ACL_EveryoneRX,\r
76         .ReadDir = PCI_ReadDirRoot,\r
77         .FindDir = PCI_FindDirRoot\r
78         }\r
79 };\r
80 Uint32  *gaPCI_PortBitmap = NULL;\r
81 Uint32  gaPCI_BusBitmap[256/32];\r
82  \r
83 // === CODE ===\r
84 /**\r
85  * \brief Scan the PCI Bus for devices\r
86  * \param Arguments     Boot-time parameters\r
87  */\r
88 int PCI_Install(char **Arguments)\r
89 {\r
90          int    i;\r
91         void    *tmpPtr;\r
92         \r
93         // Build Portmap\r
94         gaPCI_PortBitmap = malloc( 1 << 13 );\r
95         if( !gaPCI_PortBitmap ) {\r
96                 Log_Error("PCI", "Unable to allocate %i bytes for bitmap", 1 << 13);\r
97                 return MODULE_ERR_MALLOC;\r
98         }\r
99         memset( gaPCI_PortBitmap, 0, 1 << 13 );\r
100         for( i = 0; i < MAX_RESERVED_PORT / 32; i ++ )\r
101                 gaPCI_PortBitmap[i] = -1;\r
102         for( i = 0; i < MAX_RESERVED_PORT % 32; i ++ )\r
103                 gaPCI_PortBitmap[MAX_RESERVED_PORT / 32] = 1 << i;\r
104         \r
105         // Scan Bus (Bus 0, Don't fill gPCI_Devices)\r
106         i = PCI_ScanBus(0, 0);\r
107         if(i != MODULE_ERR_OK)  return i;\r
108                 \r
109         if(giPCI_DeviceCount == 0) {\r
110                 Log_Notice("PCI", "No devices were found");\r
111                 return MODULE_ERR_NOTNEEDED;\r
112         }\r
113         \r
114         // Allocate device buffer\r
115         tmpPtr = malloc(giPCI_DeviceCount * sizeof(tPCIDevice));\r
116         if(tmpPtr == NULL) {\r
117                 Log_Warning("PCI", "Malloc ERROR");\r
118                 return MODULE_ERR_MALLOC;\r
119         }\r
120         gPCI_Devices = tmpPtr;\r
121         \r
122         Log_Log("PCI", "%i devices, filling structure", giPCI_DeviceCount);\r
123         \r
124         // Reset counts\r
125         giPCI_DeviceCount = 0;\r
126         giPCI_BusCount = 0;\r
127         memset(gaPCI_BusBitmap, 0, sizeof(gaPCI_BusBitmap));\r
128         // Rescan, filling the PCI device array\r
129         PCI_ScanBus(0, 1);\r
130         \r
131         // Complete Driver Structure\r
132         gPCI_DriverStruct.RootNode.Size = giPCI_DeviceCount;\r
133         \r
134         // And add to DevFS\r
135         DevFS_AddDevice(&gPCI_DriverStruct);\r
136         \r
137         return MODULE_ERR_OK;\r
138 }\r
139 \r
140 /**\r
141  * \brief Scans a specific PCI Bus\r
142  * \param BusID PCI Bus ID to scan\r
143  * \param bFill Fill the \a gPCI_Devices array?\r
144  */\r
145 int PCI_ScanBus(int BusID, int bFill)\r
146 {\r
147          int    dev, fcn;\r
148         tPCIDevice      devInfo;\r
149         \r
150         if( gaPCI_BusBitmap[BusID/32] & (1 << (BusID%32)) )\r
151                 return MODULE_ERR_OK;\r
152         \r
153         gaPCI_BusBitmap[BusID/32] |= (1 << (BusID%32));\r
154         \r
155         for( dev = 0; dev < 32; dev++ ) // 32 Devices per bus\r
156         {\r
157                 for( fcn = 0; fcn < 8; fcn++ )  // Max 8 functions per device\r
158                 {\r
159                         // Check if the device/function exists\r
160                         if(!PCI_EnumDevice(BusID, dev, fcn, &devInfo))\r
161                                 continue;\r
162                         \r
163                         if(devInfo.oc == PCI_OC_PCIBRIDGE)\r
164                         {\r
165                                 #if LIST_DEVICES\r
166                                 Log_Log("PCI", "Bridge @ %i,%i:%i (0x%x:0x%x)",\r
167                                         BusID, dev, fcn, devInfo.vendor, devInfo.device);\r
168                                 #endif\r
169                                 //TODO: Handle PCI-PCI Bridges\r
170                                 //PCI_ScanBus(devInfo.???, bFill);\r
171                                 giPCI_BusCount ++;\r
172                         }\r
173                         else\r
174                         {\r
175                                 #if LIST_DEVICES\r
176                                 Log_Log("PCI", "Device %i,%i:%i %04x => 0x%04x:0x%04x",\r
177                                         BusID, dev, fcn, devInfo.oc, devInfo.vendor, devInfo.device);\r
178                                 #endif\r
179                         }\r
180                         \r
181                         if( bFill ) {\r
182                                 devInfo.Node.Inode = giPCI_DeviceCount;\r
183                                 memcpy(&gPCI_Devices[giPCI_DeviceCount], &devInfo, sizeof(tPCIDevice));\r
184                         }\r
185                         giPCI_DeviceCount ++;\r
186                         \r
187                         // WTF is this for?\r
188                         // Maybe bit 23 must be set for the device to be valid?\r
189                         // - Actually, maybe 23 means that there are sub-functions\r
190                         if(fcn == 0) {\r
191                                 if( !(devInfo.ConfigCache[3] & 0x00800000) )\r
192                                         break;\r
193                         }\r
194                 }\r
195         }\r
196         \r
197         return MODULE_ERR_OK;\r
198 }\r
199 \r
200 /**\r
201  * \fn char *PCI_ReadDirRoot(tVFS_Node *Node, int Pos)\r
202  * \brief Read from Root of PCI Driver\r
203 */\r
204 char *PCI_ReadDirRoot(tVFS_Node *Node, int Pos)\r
205 {\r
206         ENTER("pNode iPos", Node, Pos);\r
207         if(Pos < 0 || Pos >= giPCI_DeviceCount) {\r
208                 LEAVE('n');\r
209                 return NULL;\r
210         }\r
211         \r
212         LEAVE('s', gPCI_Devices[Pos].Name);\r
213         return strdup( gPCI_Devices[Pos].Name );\r
214 }\r
215 /**\r
216  * \fn tVFS_Node *PCI_FindDirRoot(tVFS_Node *node, const char *filename)\r
217  */\r
218 tVFS_Node *PCI_FindDirRoot(tVFS_Node *node, const char *filename)\r
219 {\r
220          int    bus,slot,fcn;\r
221          int    i;\r
222         // Validate Filename (Pointer and length)\r
223         if(!filename || strlen(filename) != 7)\r
224                 return NULL;\r
225         // Check for spacers\r
226         if(filename[2] != '.' || filename[5] != ':')\r
227                 return NULL;\r
228         \r
229         // Get Information\r
230         if(filename[0] < '0' || filename[0] > '9')      return NULL;\r
231         bus = (filename[0] - '0')*10;\r
232         if(filename[1] < '0' || filename[1] > '9')      return NULL;\r
233         bus += filename[1] - '0';\r
234         if(filename[3] < '0' || filename[3] > '9')      return NULL;\r
235         slot = (filename[3] - '0')*10;\r
236         if(filename[4] < '0' || filename[4] > '9')      return NULL;\r
237         slot += filename[4] - '0';\r
238         if(filename[6] < '0' || filename[6] > '9')      return NULL;\r
239         fcn = filename[6] - '0';\r
240         \r
241         // Find Match\r
242         for(i=0;i<giPCI_DeviceCount;i++)\r
243         {\r
244                 if(gPCI_Devices[i].bus != bus)          continue;\r
245                 if(gPCI_Devices[i].slot != slot)        continue;\r
246                 if(gPCI_Devices[i].fcn != fcn)  continue;\r
247                 \r
248                 return &gPCI_Devices[i].Node;\r
249         }\r
250         \r
251         // Error Return\r
252         return NULL;\r
253 }\r
254 \r
255 /**\r
256  * \fn Uint64 PCI_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer)\r
257  */\r
258 Uint64 PCI_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer)\r
259 {       \r
260         if( pos + length > 256 )        return 0;\r
261         \r
262         memcpy(\r
263                 buffer,\r
264                 (char*)gPCI_Devices[node->Inode].ConfigCache + pos,\r
265                 length);\r
266         \r
267         return length;\r
268 }\r
269 \r
270 // --- Kernel Code Interface ---\r
271 /**\r
272  \fn int PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn)\r
273  \brief Counts the devices with the specified codes\r
274  \param vendor  Vendor ID\r
275  \param device  Device ID\r
276  \param fcn     Function ID\r
277 */\r
278 int PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn)\r
279 {\r
280         int i, ret=0;\r
281         for(i=0;i<giPCI_DeviceCount;i++)\r
282         {\r
283                 if(gPCI_Devices[i].vendor != vendor)    continue;\r
284                 if(gPCI_Devices[i].device != device)    continue;\r
285                 if(gPCI_Devices[i].fcn != fcn)  continue;\r
286                 ret ++;\r
287         }\r
288         return ret;\r
289 }\r
290 \r
291 /**\r
292  \fn int PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, int idx)\r
293  \brief Gets the ID of the specified PCI device\r
294  \param vendor  Vendor ID\r
295  \param device  Device ID\r
296  \param fcn     Function IDs\r
297  \param idx     Number of matching entry wanted\r
298 */\r
299 int PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, int idx)\r
300 {\r
301         int i, j=0;\r
302         for(i=0;i<giPCI_DeviceCount;i++)\r
303         {\r
304                 if(gPCI_Devices[i].vendor != vendor)    continue;\r
305                 if(gPCI_Devices[i].device != device)    continue;\r
306                 if(gPCI_Devices[i].fcn != fcn)  continue;\r
307                 if(j == idx)    return i;\r
308                 j ++;\r
309         }\r
310         return -1;\r
311 }\r
312 \r
313 /**\r
314  * \fn int PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int prev)\r
315  * \brief Gets the ID of a device by it's class code\r
316  * \param class Class Code\r
317  * \param mask  Mask for class comparison\r
318  * \param prev  ID of previous device (-1 for no previous)\r
319  */\r
320 int PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int prev)\r
321 {\r
322          int    i;\r
323         // Check if prev is negative (meaning get first)\r
324         if(prev < 0)    i = 0;\r
325         else    i = prev+1;\r
326         \r
327         for( ; i < giPCI_DeviceCount; i++ )\r
328         {\r
329                 if((gPCI_Devices[i].oc & mask) == class)\r
330                         return i;\r
331         }\r
332         return -1;\r
333 }\r
334 \r
335 /**\r
336  \fn Uint8 PCI_GetIRQ(int id)\r
337 */\r
338 Uint8 PCI_GetIRQ(int id)\r
339 {\r
340         if(id < 0 || id >= giPCI_DeviceCount)\r
341                 return 0;\r
342         return gPCI_Devices[id].ConfigCache[15];\r
343         //return PCI_CfgReadByte( gPCI_Devices[id].bus, gPCI_Devices[id].slot, gPCI_Devices[id].fcn, 0x3C);\r
344 }\r
345 \r
346 /**\r
347  \fn Uint32 PCI_GetBAR0(int id)\r
348 */\r
349 Uint32 PCI_GetBAR0(int id)\r
350 {\r
351         if(id < 0 || id >= giPCI_DeviceCount)\r
352                 return 0;\r
353         return gPCI_Devices[id].ConfigCache[4];\r
354 }\r
355 \r
356 /**\r
357  \fn Uint32 PCI_GetBAR1(int id)\r
358 */\r
359 Uint32 PCI_GetBAR1(int id)\r
360 {\r
361         if(id < 0 || id >= giPCI_DeviceCount)\r
362                 return 0;\r
363         return gPCI_Devices[id].ConfigCache[5];\r
364 }\r
365 \r
366 /**\r
367  \fn Uint32 PCI_GetBAR2(int id)\r
368 */\r
369 Uint32 PCI_GetBAR2(int id)\r
370 {\r
371         if(id < 0 || id >= giPCI_DeviceCount)\r
372                 return 0;\r
373         return gPCI_Devices[id].ConfigCache[6];\r
374 }\r
375 \r
376 /**\r
377  \fn Uint32 PCI_GetBAR3(int id)\r
378 */\r
379 Uint32 PCI_GetBAR3(int id)\r
380 {\r
381         if(id < 0 || id >= giPCI_DeviceCount)\r
382                 return 0;\r
383         return gPCI_Devices[id].ConfigCache[7];\r
384 }\r
385 \r
386 /**\r
387  \fn Uint32 PCI_GetBAR4(int id)\r
388 */\r
389 Uint32 PCI_GetBAR4(int id)\r
390 {\r
391         if(id < 0 || id >= giPCI_DeviceCount)\r
392                 return 0;\r
393         return gPCI_Devices[id].ConfigCache[8];\r
394 }\r
395 \r
396 /**\r
397  \fn Uint32 PCI_GetBAR5(int id)\r
398 */\r
399 Uint32 PCI_GetBAR5(int id)\r
400 {\r
401         if(id < 0 || id >= giPCI_DeviceCount)\r
402                 return 0;\r
403         return gPCI_Devices[id].ConfigCache[9];\r
404 }\r
405 \r
406 Uint16 PCI_AssignPort(int id, int bar, int count)\r
407 {\r
408         Uint16  portVals;\r
409          int    gran=0;\r
410          int    i, j;\r
411         tPCIDevice      *dev;\r
412         \r
413         //LogF("PCI_AssignPort: (id=%i,bar=%i,count=%i)\n", id, bar, count);\r
414         \r
415         if(id < 0 || id >= giPCI_DeviceCount)   return 0;\r
416         if(bar < 0 || bar > 5)  return 0;\r
417         \r
418         dev = &gPCI_Devices[id];\r
419         \r
420         PCI_CfgWriteDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4, -1 );\r
421         portVals = PCI_CfgReadDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4 );\r
422         dev->ConfigCache[4+bar] = portVals;\r
423         //LogF(" PCI_AssignPort: portVals = 0x%x\n", portVals);\r
424         \r
425         // Check for IO port\r
426         if( !(portVals & 1) )   return 0;\r
427         \r
428         // Mask out final bit\r
429         portVals &= ~1;\r
430         \r
431         // Get Granuality\r
432         __asm__ __volatile__ ("bsf %%eax, %%ecx" : "=c" (gran) : "a" (portVals) );\r
433         gran = 1 << gran;\r
434         //LogF(" PCI_AssignPort: gran = 0x%x\n", gran);\r
435         \r
436         // Find free space\r
437         portVals = 0;\r
438         for( i = 0; i < 1<<16; i += gran )\r
439         {\r
440                 for( j = 0; j < count; j ++ )\r
441                 {\r
442                         if( gaPCI_PortBitmap[ (i+j)>>5 ] & 1 << ((i+j)&0x1F) )\r
443                                 break;\r
444                 }\r
445                 if(j == count) {\r
446                         portVals = i;\r
447                         break;\r
448                 }\r
449         }\r
450         \r
451         if(portVals)\r
452         {\r
453                 for( j = 0; j < count; j ++ )\r
454                 {\r
455                         if( gaPCI_PortBitmap[ (portVals+j)>>5 ] |= 1 << ((portVals+j)&0x1F) )\r
456                                 break;\r
457                 }\r
458                 PCI_CfgWriteDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4, portVals|1 );\r
459                 dev->ConfigCache[4+bar] = portVals|1;\r
460         }\r
461         \r
462         // Return\r
463         //LogF("PCI_AssignPort: RETURN 0x%x\n", portVals);\r
464         return portVals;\r
465 }\r
466 \r
467 /**\r
468  * \fn int      PCI_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, tPCIDevice *info)\r
469  */\r
470 int     PCI_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, tPCIDevice *info)\r
471 {\r
472         Uint16  vendor;\r
473          int    i;\r
474         \r
475         vendor = PCI_CfgReadWord(bus, slot, fcn, 0x0|0);\r
476         if(vendor == 0xFFFF)    // Invalid Device\r
477                 return 0;\r
478                 \r
479         info->bus = bus;\r
480         info->slot = slot;\r
481         info->fcn = fcn;\r
482         info->vendor = vendor;\r
483         info->device = PCI_CfgReadWord(bus, slot, fcn, 0x0|2);\r
484         info->revision = PCI_CfgReadWord(bus, slot, fcn, 0x8|0);\r
485         info->oc = PCI_CfgReadWord(bus, slot, fcn, 0x8|2);\r
486         \r
487         // Load Config Bytes\r
488         for(i=0;i<256/4;i++)\r
489         {\r
490                 info->ConfigCache[i] = PCI_CfgReadDWord(bus, slot, fcn, i*4);\r
491         }\r
492         \r
493         //#if LIST_DEVICES\r
494         //Log("BAR0 0x%08x BAR1 0x%08x BAR2 0x%08x", info->ConfigCache[4], info->ConfigCache[5], info->ConfigCache[6]);\r
495         //Log("BAR3 0x%08x BAR4 0x%08x BAR5 0x%08x", info->ConfigCache[7], info->ConfigCache[8], info->ConfigCache[9]);\r
496         //Log("Class: 0x%04x", info->oc);\r
497         //#endif\r
498         \r
499         // Make node name\r
500         info->Name[0] = '0' + bus/10;\r
501         info->Name[1] = '0' + bus%10;\r
502         info->Name[2] = '.';\r
503         info->Name[3] = '0' + slot/10;\r
504         info->Name[4] = '0' + slot%10;\r
505         info->Name[5] = ':';\r
506         info->Name[6] = '0' + fcn;\r
507         info->Name[7] = '\0';\r
508         \r
509         // Create VFS Node\r
510         memset( &info->Node, 0, sizeof(tVFS_Node) );\r
511         info->Node.Size = 256;\r
512         \r
513         info->Node.NumACLs = 1;\r
514         info->Node.ACLs = &gVFS_ACL_EveryoneRO;\r
515         \r
516         info->Node.Read = PCI_ReadDevice;\r
517         \r
518         return 1;\r
519 }\r
520 \r
521 Uint32 PCI_CfgReadDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset)\r
522 {\r
523         Uint32  address;\r
524         Uint32  data;\r
525         \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
530         \r
531         address = 0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC);\r
532         outd(0xCF8, address);\r
533         \r
534         data = ind(0xCFC);\r
535         //Debug("PCI(0x%x) = 0x%08x", address, data);\r
536         return data;\r
537 }\r
538 void PCI_CfgWriteDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset, Uint32 data)\r
539 {\r
540         Uint32  address;\r
541         \r
542         bus &= 0xFF;    // 8 Bits\r
543         dev &= 0x1F;    // 5 Bits\r
544         func &= 0x7;    // 3 Bits\r
545         offset &= 0xFF; // 8 Bits\r
546         \r
547         address = 0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC);\r
548         outd(0xCF8, address);\r
549         outd(0xCFC, data);\r
550 }\r
551 Uint16 PCI_CfgReadWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset)\r
552 {\r
553         Uint32  data = PCI_CfgReadDWord(bus, dev, func, offset);\r
554         \r
555         data >>= (offset&2)*8;  // Allow Access to Upper Word\r
556         \r
557         return (Uint16)data;\r
558 }\r
559 \r
560 Uint8 PCI_CfgReadByte(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset)\r
561 {\r
562         Uint32  data = PCI_CfgReadDWord(bus, dev, func, offset);\r
563         \r
564         data >>= (offset&3)*8;  //Allow Access to Upper Word\r
565         return (Uint8)data;\r
566 }\r
567 \r
568 \r
569 // === EXPORTS ===\r
570 //*\r
571 EXPORT(PCI_CountDevices);\r
572 EXPORT(PCI_GetDevice);\r
573 EXPORT(PCI_GetDeviceByClass);\r
574 EXPORT(PCI_AssignPort);\r
575 EXPORT(PCI_GetIRQ);\r
576 //*/\r

UCC git Repository :: git.ucc.asn.au