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

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