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

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