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

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