Coding style cleanup
[platform/kernel/u-boot.git] / board / MAI / bios_emulator / scitech / src / pm / common / pcilib.c
1 /****************************************************************************
2 *
3 *                   SciTech OS Portability Manager Library
4 *
5 *  ========================================================================
6 *
7 *    The contents of this file are subject to the SciTech MGL Public
8 *    License Version 1.0 (the "License"); you may not use this file
9 *    except in compliance with the License. You may obtain a copy of
10 *    the License at http://www.scitechsoft.com/mgl-license.txt
11 *
12 *    Software distributed under the License is distributed on an
13 *    "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14 *    implied. See the License for the specific language governing
15 *    rights and limitations under the License.
16 *
17 *    The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
18 *
19 *    The Initial Developer of the Original Code is SciTech Software, Inc.
20 *    All Rights Reserved.
21 *
22 *  ========================================================================
23 *
24 * Language:     ANSI C
25 * Environment:  Any
26 *
27 * Description:  Module for interfacing to the PCI bus and configuration
28 *               space registers.
29 *
30 ****************************************************************************/
31
32 #include "pmapi.h"
33 #include "pcilib.h"
34 #if !defined(__WIN32_VXD__) && !defined(__NT_DRIVER__)
35 #include <string.h>
36 #endif
37
38 /*---------------------- Macros and type definitions ----------------------*/
39
40 #pragma pack(1)
41
42 /* Length of the memory mapping for the PCI BIOS */
43
44 #define BIOS_LIMIT          (128 * 1024L - 1)
45
46 /* Macros for accessing the PCI BIOS functions from 32-bit protected mode */
47
48 #define BIOS32_SIGNATURE    (((ulong)'_' << 0) + ((ulong)'3' << 8) + ((ulong)'2' << 16) + ((ulong)'_' << 24))
49 #define PCI_SIGNATURE       (((ulong)'P' << 0) + ((ulong)'C' << 8) + ((ulong)'I' << 16) + ((ulong)' ' << 24))
50 #define PCI_SERVICE         (((ulong)'$' << 0) + ((ulong)'P' << 8) + ((ulong)'C' << 16) + ((ulong)'I' << 24))
51 #define PCI_BIOS_PRESENT    0xB101
52 #define FIND_PCI_DEVICE     0xB102
53 #define FIND_PCI_CLASS      0xB103
54 #define GENERATE_SPECIAL    0xB106
55 #define READ_CONFIG_BYTE    0xB108
56 #define READ_CONFIG_WORD    0xB109
57 #define READ_CONFIG_DWORD   0xB10A
58 #define WRITE_CONFIG_BYTE   0xB10B
59 #define WRITE_CONFIG_WORD   0xB10C
60 #define WRITE_CONFIG_DWORD  0xB10D
61 #define GET_IRQ_ROUTING_OPT 0xB10E
62 #define SET_PCI_IRQ         0xB10F
63
64 /* This is the standard structure used to identify the entry point to the
65  * BIOS32 Service Directory, as documented in PCI 2.1 BIOS Specicition.
66  */
67
68 typedef union {
69     struct {
70         ulong signature;        /* _32_                                 */
71         ulong entry;            /* 32 bit physical address              */
72         uchar revision;         /* Revision level, 0                    */
73         uchar length;           /* Length in paragraphs should be 01    */
74         uchar checksum;         /* All bytes must add up to zero        */
75         uchar reserved[5];      /* Must be zero                         */
76         } fields;
77     char chars[16];
78     } PCI_bios32;
79
80 /* Structure for a far pointer to call the PCI BIOS services with */
81
82 typedef struct {
83     ulong   address;
84     ushort  segment;
85     } PCIBIOS_entry;
86
87 /* Macros to copy a structure that includes dwSize members */
88
89 #define COPY_STRUCTURE(d,s) memcpy(d,s,MIN((s)->dwSize,(d)->dwSize))
90
91 #pragma pack()
92
93 /*--------------------------- Global variables ----------------------------*/
94
95 static uchar            *BIOSImage = NULL;  /* BIOS image mapping       */
96 static int              PCIBIOSVersion = -1;/* PCI BIOS version         */
97 static PCIBIOS_entry    PCIEntry;           /* PCI services entry point */
98 static ulong            PCIPhysEntry = 0;   /* Physical address         */
99
100 /*----------------------------- Implementation ----------------------------*/
101
102 /* External assembler helper functions */
103
104 uchar   _ASMAPI _BIOS32_service(ulong service,ulong function,ulong *physBase,ulong *length,ulong *serviceOffset,PCIBIOS_entry entry);
105 ushort  _ASMAPI _PCIBIOS_isPresent(ulong i_eax,ulong *o_edx,ushort *o_ax,uchar *o_cl,PCIBIOS_entry entry);
106 ulong   _ASMAPI _PCIBIOS_service(ulong r_eax,ulong r_ebx,ulong r_edi,ulong r_ecx,PCIBIOS_entry entry);
107 int     _ASMAPI _PCIBIOS_getRouting(PCIRoutingOptionsBuffer *buf,PCIBIOS_entry entry);
108 ibool   _ASMAPI _PCIBIOS_setIRQ(int busDev,int intPin,int IRQ,PCIBIOS_entry entry);
109 ulong   _ASMAPI _PCIBIOS_specialCycle(int bus,ulong data,PCIBIOS_entry entry);
110 ushort  _ASMAPI _PCI_getCS(void);
111
112 /****************************************************************************
113 REMARKS:
114 This functions returns the physical address of the PCI BIOS entry point.
115 ****************************************************************************/
116 ulong _ASMAPI PCIBIOS_getEntry(void)
117 { return PCIPhysEntry; }
118
119 /****************************************************************************
120 PARAMETERS:
121 hwType  - Place to store the PCI hardware access mechanism flags
122 lastBus - Place to store the index of the last PCI bus in the system
123
124 RETURNS:
125 Version number of the PCI BIOS found.
126
127 REMARKS:
128 This function determines if the PCI BIOS is present in the system, and if
129 so returns the information returned by the PCI BIOS detect function.
130 ****************************************************************************/
131 static int PCIBIOS_detect(
132     uchar *hwType,
133     uchar *lastBus)
134 {
135     ulong   signature;
136     ushort  stat,version;
137
138 #ifndef __16BIT__
139     PCIBIOS_entry   BIOSEntry = {0};
140     uchar           *BIOSEnd;
141     PCI_bios32      *BIOSDir;
142     ulong           physBase,length,offset;
143
144     /* Bail if we have already detected no BIOS is present */
145     if (PCIBIOSVersion == 0)
146         return 0;
147
148     /* First scan the memory from 0xE0000 to 0xFFFFF looking for the
149      * BIOS32 service directory, so we can determine if we can call it
150      * from 32-bit protected mode.
151      */
152     if (PCIBIOSVersion == -1) {
153         PCIBIOSVersion = 0;
154         BIOSImage = PM_mapPhysicalAddr(0xE0000,BIOS_LIMIT,false);
155         if (!BIOSImage)
156             return 0;
157         BIOSEnd = BIOSImage + 0x20000;
158         for (BIOSDir = (PCI_bios32*)BIOSImage; BIOSDir < (PCI_bios32*)BIOSEnd; BIOSDir++) {
159             uchar   sum;
160             int     i,length;
161
162             if (BIOSDir->fields.signature != BIOS32_SIGNATURE)
163                 continue;
164             length = BIOSDir->fields.length * 16;
165             if (!length)
166                 continue;
167             for (sum = i = 0; i < length ; i++)
168                 sum += BIOSDir->chars[i];
169             if (sum != 0)
170                 continue;
171             BIOSEntry.address = (ulong)BIOSImage + (BIOSDir->fields.entry - 0xE0000);
172             BIOSEntry.segment = _PCI_getCS();
173             break;
174             }
175
176         /* If we found the BIOS32 directory, call it to get the address of the
177          * PCI services.
178          */
179         if (BIOSEntry.address == 0)
180             return 0;
181         if (_BIOS32_service(PCI_SERVICE,0,&physBase,&length,&offset,BIOSEntry) != 0)
182             return 0;
183         PCIPhysEntry = physBase + offset;
184         PCIEntry.address = (ulong)BIOSImage + (PCIPhysEntry - 0xE0000);
185         PCIEntry.segment = _PCI_getCS();
186         }
187 #endif
188     /* We found the BIOS entry, so now do the version check */
189     version = _PCIBIOS_isPresent(PCI_BIOS_PRESENT,&signature,&stat,lastBus,PCIEntry);
190     if (version > 0 && ((stat >> 8) == 0) && signature == PCI_SIGNATURE) {
191         *hwType = stat & 0xFF;
192         return PCIBIOSVersion = version;
193         }
194     return 0;
195 }
196
197 /****************************************************************************
198 PARAMETERS:
199 info    - Array of PCIDeviceInfo structures to check against
200 index   - Index of the current device to check
201
202 RETURNS:
203 True if the device is a duplicate, false if not.
204
205 REMARKS:
206 This function goes through the list of all devices preceeding the newly
207 found device in the info structure, and checks that the device is not a
208 duplicate of a previous device. Some devices incorrectly enumerate
209 themselves at different function addresses so we check here to exclude
210 those cases.
211 ****************************************************************************/
212 static ibool CheckDuplicate(
213     PCIDeviceInfo *info,
214     PCIDeviceInfo *prev)
215 {
216     /* Ignore devices with a vendor ID of 0 */
217     if (info->VendorID == 0)
218         return true;
219
220     /* NOTE: We only check against the current device on
221      *       the bus to ensure that we do not exclude
222      *       multiple controllers of the same device ID.
223      */
224     if (info->slot.p.Bus == prev->slot.p.Bus &&
225         info->slot.p.Device == prev->slot.p.Device &&
226         info->DeviceID == prev->DeviceID)
227         return true;
228     return false;
229 }
230
231 /****************************************************************************
232 PARAMETERS:
233 info        - Array of PCIDeviceInfo structures to fill in
234 maxDevices  - Maximum number of of devices to enumerate into array
235
236 RETURNS:
237 Number of PCI devices found and enumerated on the PCI bus, 0 if not PCI.
238
239 REMARKS:
240 Function to enumerate all available devices on the PCI bus into an array
241 of configuration information blocks.
242 ****************************************************************************/
243 static int PCI_enumerateMech1(
244     PCIDeviceInfo info[])
245 {
246     int             bus,device,function,i,numFound = 0;
247     ulong           *lp,tmp;
248     PCIslot         slot = {{0,0,0,0,0,0,1}};
249     PCIDeviceInfo   pci,prev = {0};
250
251     /* Try PCI access mechanism 1 */
252     PM_outpb(0xCFB,0x01);
253     tmp = PM_inpd(0xCF8);
254     PM_outpd(0xCF8,slot.i);
255     if ((PM_inpd(0xCF8) == slot.i) && (PM_inpd(0xCFC) != 0xFFFFFFFFUL)) {
256         /* PCI access mechanism 1 - the preferred mechanism */
257         for (bus = 0; bus < 8; bus++) {
258             slot.p.Bus = bus;
259             for (device = 0; device < 32; device++) {
260                 slot.p.Device = device;
261                 for (function = 0; function < 8; function++) {
262                     slot.p.Function = function;
263                     slot.p.Register = 0;
264                     PM_outpd(0xCF8,slot.i);
265                     if (PM_inpd(0xCFC) != 0xFFFFFFFFUL) {
266                         memset(&pci,0,sizeof(pci));
267                         pci.dwSize = sizeof(pci);
268                         pci.mech1 = 1;
269                         pci.slot = slot;
270                         lp = (ulong*)&(pci.VendorID);
271                         for (i = 0; i < NUM_PCI_REG; i++, lp++) {
272                             slot.p.Register = i;
273                             PM_outpd(0xCF8,slot.i);
274                             *lp = PM_inpd(0xCFC);
275                             }
276                         if (!CheckDuplicate(&pci,&prev)) {
277                             if (info)
278                                 COPY_STRUCTURE(&info[numFound],&pci);
279                             ++numFound;
280                             }
281                         prev = pci;
282                         }
283                     }
284                 }
285             }
286
287         /* Disable PCI config cycle on exit */
288         PM_outpd(0xCF8,0);
289         return numFound;
290         }
291     PM_outpd(0xCF8,tmp);
292
293     /* No hardware access mechanism 1 found */
294     return 0;
295 }
296
297 /****************************************************************************
298 PARAMETERS:
299 info        - Array of PCIDeviceInfo structures to fill in
300 maxDevices  - Maximum number of of devices to enumerate into array
301
302 RETURNS:
303 Number of PCI devices found and enumerated on the PCI bus, 0 if not PCI.
304
305 REMARKS:
306 Function to enumerate all available devices on the PCI bus into an array
307 of configuration information blocks.
308 ****************************************************************************/
309 static int PCI_enumerateMech2(
310     PCIDeviceInfo info[])
311 {
312     int             bus,device,function,i,numFound = 0;
313     ushort          deviceIO;
314     ulong           *lp;
315     PCIslot         slot = {{0,0,0,0,0,0,1}};
316     PCIDeviceInfo   pci,prev = {0};
317
318     /* Try PCI access mechanism 2 */
319     PM_outpb(0xCFB,0x00);
320     PM_outpb(0xCF8,0x00);
321     PM_outpb(0xCFA,0x00);
322     if (PM_inpb(0xCF8) == 0x00 && PM_inpb(0xCFB) == 0x00) {
323         /* PCI access mechanism 2 - the older mechanism for legacy busses */
324         for (bus = 0; bus < 2; bus++) {
325             slot.p.Bus = bus;
326             PM_outpb(0xCFA,(uchar)bus);
327             for (device = 0; device < 16; device++) {
328                 slot.p.Device = device;
329                 deviceIO = 0xC000 + (device << 8);
330                 for (function = 0; function < 8; function++) {
331                     slot.p.Function = function;
332                     slot.p.Register = 0;
333                     PM_outpb(0xCF8,(uchar)((function << 1) | 0x10));
334                     if (PM_inpd(deviceIO) != 0xFFFFFFFFUL) {
335                         memset(&pci,0,sizeof(pci));
336                         pci.dwSize = sizeof(pci);
337                         pci.mech1 = 0;
338                         pci.slot = slot;
339                         lp = (ulong*)&(pci.VendorID);
340                         for (i = 0; i < NUM_PCI_REG; i++, lp++) {
341                             slot.p.Register = i;
342                             *lp = PM_inpd(deviceIO + (i << 2));
343                             }
344                         if (!CheckDuplicate(&pci,&prev)) {
345                             if (info)
346                                 COPY_STRUCTURE(&info[numFound],&pci);
347                             ++numFound;
348                             }
349                         prev = pci;
350                         }
351                     }
352                 }
353             }
354
355         /* Disable PCI config cycle on exit */
356         PM_outpb(0xCF8,0);
357         return numFound;
358         }
359
360     /* No hardware access mechanism 2 found */
361     return 0;
362 }
363
364 /****************************************************************************
365 REMARKS:
366 This functions reads a configuration dword via the PCI BIOS.
367 ****************************************************************************/
368 static ulong PCIBIOS_readDWORD(
369     int index,
370     ulong slot)
371 {
372     return (ulong)_PCIBIOS_service(READ_CONFIG_DWORD,slot >> 8,index,0,PCIEntry);
373 }
374
375 /****************************************************************************
376 PARAMETERS:
377 info        - Array of PCIDeviceInfo structures to fill in
378 maxDevices  - Maximum number of of devices to enumerate into array
379
380 RETURNS:
381 Number of PCI devices found and enumerated on the PCI bus, 0 if not PCI.
382
383 REMARKS:
384 Function to enumerate all available devices on the PCI bus into an array
385 of configuration information blocks.
386 ****************************************************************************/
387 static int PCI_enumerateBIOS(
388     PCIDeviceInfo info[])
389 {
390     uchar           hwType,lastBus;
391     int             bus,device,function,i,numFound = 0;
392     ulong           *lp;
393     PCIslot         slot = {{0,0,0,0,0,0,1}};
394     PCIDeviceInfo   pci,prev = {0};
395
396     if (PCIBIOS_detect(&hwType,&lastBus)) {
397         /* PCI BIOS access - the ultimate fallback */
398         for (bus = 0; bus <= lastBus; bus++) {
399             slot.p.Bus = bus;
400             for (device = 0; device < 32; device++) {
401                 slot.p.Device = device;
402                 for (function = 0; function < 8; function++) {
403                     slot.p.Function = function;
404                     if (PCIBIOS_readDWORD(0,slot.i) != 0xFFFFFFFFUL) {
405                         memset(&pci,0,sizeof(pci));
406                         pci.dwSize = sizeof(pci);
407                         pci.mech1 = 2;
408                         pci.slot = slot;
409                         lp = (ulong*)&(pci.VendorID);
410                         for (i = 0; i < NUM_PCI_REG; i++, lp++)
411                             *lp = PCIBIOS_readDWORD(i << 2,slot.i);
412                         if (!CheckDuplicate(&pci,&prev)) {
413                             if (info)
414                                 COPY_STRUCTURE(&info[numFound],&pci);
415                             ++numFound;
416                             }
417                         prev = pci;
418                         }
419                     }
420                 }
421             }
422         }
423
424     /* Return number of devices found */
425     return numFound;
426 }
427
428 /****************************************************************************
429 PARAMETERS:
430 info        - Array of PCIDeviceInfo structures to fill in
431 maxDevices  - Maximum number of of devices to enumerate into array
432
433 RETURNS:
434 Number of PCI devices found and enumerated on the PCI bus, 0 if not PCI.
435
436 REMARKS:
437 Function to enumerate all available devices on the PCI bus into an array
438 of configuration information blocks.
439 ****************************************************************************/
440 int _ASMAPI PCI_enumerate(
441     PCIDeviceInfo info[])
442 {
443     int numFound;
444
445     /* First try via the direct access mechanisms which are faster if we
446      * have them (nearly always). The BIOS is used as a fallback, and for
447      * stuff we can't do directly.
448      */
449     if ((numFound = PCI_enumerateMech1(info)) == 0) {
450         if ((numFound = PCI_enumerateMech2(info)) == 0) {
451             if ((numFound = PCI_enumerateBIOS(info)) == 0)
452                 return 0;
453             }
454         }
455     return numFound;
456 }
457
458 /****************************************************************************
459 PARAMETERS:
460 info        - Array of PCIDeviceInfo structures to fill in
461 maxDevices  - Maximum number of of devices to enumerate into array
462
463 RETURNS:
464 Number of PCI devices found and enumerated on the PCI bus, 0 if not PCI.
465
466 REMARKS:
467 Function to enumerate all available devices on the PCI bus into an array
468 of configuration information blocks.
469 ****************************************************************************/
470 int _ASMAPI PCI_getNumDevices(void)
471 {
472     return PCI_enumerate(NULL);
473 }
474
475 /****************************************************************************
476 PARAMETERS:
477 bar - Base address to measure
478 pci - PCI device to access
479
480 RETURNS:
481 Size of the PCI base address in bytes
482
483 REMARKS:
484 This function measures the size of the PCI base address register in bytes,
485 by writing all F's to the register, and reading the value back. The size
486 of the base address is determines by the bits that are hardwired to zero's.
487 ****************************************************************************/
488 ulong _ASMAPI PCI_findBARSize(
489     int bar,
490     PCIDeviceInfo *pci)
491 {
492     ulong   base,size = 0;
493
494     base = PCI_accessReg(bar,0,PCI_READ_DWORD,pci);
495     if (base && !(base & 0x1)) {
496         /* For some strange reason some devices don't properly decode
497          * their base address registers (Intel PCI/PCI bridges!), and
498          * we read completely bogus values. We check for that here
499          * and clear out those BAR's.
500          *
501          * We check for that here because at least the low 12 bits
502          * of the address range must be zeros, since the page size
503          * on IA32 processors is always 4Kb.
504          */
505         if ((base & 0xFFF) == 0) {
506             PCI_accessReg(bar,0xFFFFFFFF,PCI_WRITE_DWORD,pci);
507             size = PCI_accessReg(bar,0,PCI_READ_DWORD,pci) & ~0xFF;
508             size = ~size+1;
509             PCI_accessReg(bar,base,PCI_WRITE_DWORD,pci);
510             }
511         }
512     pci->slot.p.Register = 0;
513     return size;
514 }
515
516 /****************************************************************************
517 PARAMETERS:
518 index   - DWORD index of the register to access
519 value   - Value to write to the register for write access
520 func    - Function to implement
521
522 RETURNS:
523 The value read from the register for read operations
524
525 REMARKS:
526 The function code are defined as follows
527
528 code    - function
529 0       - Read BYTE
530 1       - Read WORD
531 2       - Read DWORD
532 3       - Write BYTE
533 4       - Write WORD
534 5       - Write DWORD
535 ****************************************************************************/
536 ulong _ASMAPI PCI_accessReg(
537     int index,
538     ulong value,
539     int func,
540     PCIDeviceInfo *info)
541 {
542     int iobase;
543
544     if (info->mech1 == 2) {
545         /* Use PCI BIOS access since we dont have direct hardware access */
546         switch (func) {
547             case PCI_READ_BYTE:
548                 return (uchar)_PCIBIOS_service(READ_CONFIG_BYTE,info->slot.i >> 8,index,0,PCIEntry);
549             case PCI_READ_WORD:
550                 return (ushort)_PCIBIOS_service(READ_CONFIG_WORD,info->slot.i >> 8,index,0,PCIEntry);
551             case PCI_READ_DWORD:
552                 return (ulong)_PCIBIOS_service(READ_CONFIG_DWORD,info->slot.i >> 8,index,0,PCIEntry);
553             case PCI_WRITE_BYTE:
554                 _PCIBIOS_service(WRITE_CONFIG_BYTE,info->slot.i >> 8,index,value,PCIEntry);
555                 break;
556             case PCI_WRITE_WORD:
557                 _PCIBIOS_service(WRITE_CONFIG_WORD,info->slot.i >> 8,index,value,PCIEntry);
558                 break;
559             case PCI_WRITE_DWORD:
560                 _PCIBIOS_service(WRITE_CONFIG_DWORD,info->slot.i >> 8,index,value,PCIEntry);
561                 break;
562             }
563         }
564     else {
565         /* Use direct hardware access mechanisms */
566         if (info->mech1) {
567             /* PCI access mechanism 1 */
568             iobase = 0xCFC + (index & 3);
569             info->slot.p.Register = index >> 2;
570             PM_outpd(0xCF8,info->slot.i);
571             }
572         else {
573             /* PCI access mechanism 2 */
574             PM_outpb(0xCF8,(uchar)((info->slot.p.Function << 1) | 0x10));
575             PM_outpb(0xCFA,(uchar)info->slot.p.Bus);
576             iobase = 0xC000 + (info->slot.p.Device << 8) + index;
577             }
578         switch (func) {
579             case PCI_READ_BYTE:
580             case PCI_READ_WORD:
581             case PCI_READ_DWORD:    value = PM_inpd(iobase);        break;
582             case PCI_WRITE_BYTE:    PM_outpb(iobase,(uchar)value);  break;
583             case PCI_WRITE_WORD:    PM_outpw(iobase,(ushort)value); break;
584             case PCI_WRITE_DWORD:   PM_outpd(iobase,(ulong)value);  break;
585             }
586         PM_outpd(0xCF8,0);
587         }
588     return value;
589 }
590
591 /****************************************************************************
592 PARAMETERS:
593 numDevices  - Number of devices to query info for
594
595 RETURNS:
596 0 on success, -1 on error, number of devices to enumerate if numDevices = 0
597
598 REMARKS:
599 This function reads the PCI routing information. If you pass a value of
600 0 for numDevices, this function will return with the number of devices
601 needed in the routing buffer that will be filled in by the BIOS.
602 ****************************************************************************/
603 ibool _ASMAPI PCI_getIRQRoutingOptions(
604     int numDevices,
605     PCIRouteInfo *buffer)
606 {
607     PCIRoutingOptionsBuffer buf;
608     int                     ret;
609
610     if (PCIPhysEntry) {
611         buf.BufferSize = numDevices * sizeof(PCIRouteInfo);
612         buf.DataBuffer = buffer;
613         if ((ret = _PCIBIOS_getRouting(&buf,PCIEntry)) == 0x89)
614             return buf.BufferSize / sizeof(PCIRouteInfo);
615         if (ret != 0)
616             return -1;
617         return 0;
618         }
619
620     /* We currently only support this via the PCI BIOS functions */
621     return -1;
622 }
623
624 /****************************************************************************
625 PARAMETERS:
626 info    - PCI device information for the specified device
627 intPin  - Value to store in the PCI InterruptPin register
628 IRQ     - New ISA IRQ to map the PCI interrupt to (0-15)
629
630 RETURNS:
631 True on success, or false if this function failed.
632
633 REMARKS:
634 This function changes the PCI IRQ routing for the specified device to the
635 desired PCI interrupt and the desired ISA bus compatible IRQ. This function
636 may not be supported by the PCI BIOS, in which case this function will
637 fail.
638 ****************************************************************************/
639 ibool _ASMAPI PCI_setHardwareIRQ(
640     PCIDeviceInfo *info,
641     uint intPin,
642     uint IRQ)
643 {
644     if (PCIPhysEntry) {
645         if (_PCIBIOS_setIRQ(info->slot.i >> 8,intPin,IRQ,PCIEntry)) {
646             info->u.type0.InterruptPin = intPin;
647             info->u.type0.InterruptLine = IRQ;
648             return true;
649             }
650         return false;
651         }
652
653     /* We currently only support this via the PCI BIOS functions */
654     return false;
655 }
656
657 /****************************************************************************
658 PARAMETERS:
659 bus                 - Bus number to generate the special cycle for
660 specialCycleData    - Data to send for the special cyle
661
662 REMARKS:
663 This function generates a special cycle on the specified bus using with
664 the specified data.
665 ****************************************************************************/
666 void _ASMAPI PCI_generateSpecialCyle(
667     uint bus,
668     ulong specialCycleData)
669 {
670     if (PCIPhysEntry)
671         _PCIBIOS_specialCycle(bus,specialCycleData,PCIEntry);
672     /* We currently only support this via the PCI BIOS functions */
673 }
674
675 /****************************************************************************
676 PARAMETERS:
677 info    - PCI device information block for device to access
678 index   - Index of register to start reading from
679 dst     - Place to store the values read from configuration space
680 count   - Count of bytes to read from configuration space
681
682 REMARKS:
683 This function is used to read a block of PCI configuration space registers
684 from the configuration space into the passed in data block. This function
685 will properly handle reading non-DWORD aligned data from the configuration
686 space correctly.
687 ****************************************************************************/
688 void _ASMAPI PCI_readRegBlock(
689     PCIDeviceInfo *info,
690     int index,
691     void *dst,
692     int count)
693 {
694     uchar   *pb;
695     ulong   *pd;
696     int     i;
697     int     startCount = (index & 3);
698     int     middleCount = (count - startCount) >> 2;
699     int     endCount = count - middleCount * 4 - startCount;
700
701     for (i = 0,pb = dst; i < startCount; i++, index++) {
702         *pb++ = (uchar)PCI_accessReg(index,0,PCI_READ_BYTE,info);
703         }
704     for (i = 0,pd = (ulong*)pb; i < middleCount; i++, index += 4) {
705         *pd++ = (ulong)PCI_accessReg(index,0,PCI_READ_DWORD,info);
706         }
707     for (i = 0,pb = (uchar*)pd; i < endCount; i++, index++) {
708         *pb++ = (uchar)PCI_accessReg(index,0,PCI_READ_BYTE,info);
709         }
710 }
711
712 /****************************************************************************
713 PARAMETERS:
714 info    - PCI device information block for device to access
715 index   - Index of register to start reading from
716 dst     - Place to store the values read from configuration space
717 count   - Count of bytes to read from configuration space
718
719 REMARKS:
720 This function is used to write a block of PCI configuration space registers
721 to the configuration space from the passed in data block. This function
722 will properly handle writing non-DWORD aligned data to the configuration
723 space correctly.
724 ****************************************************************************/
725 void _ASMAPI PCI_writeRegBlock(
726     PCIDeviceInfo *info,
727     int index,
728     void *src,
729     int count)
730 {
731     uchar   *pb;
732     ulong   *pd;
733     int     i;
734     int     startCount = (index & 3);
735     int     middleCount = (count - startCount) >> 2;
736     int     endCount = count - middleCount * 4 - startCount;
737
738     for (i = 0,pb = src; i < startCount; i++, index++) {
739         PCI_accessReg(index,*pb++,PCI_WRITE_BYTE,info);
740         }
741     for (i = 0,pd = (ulong*)pb; i < middleCount; i++, index += 4) {
742         PCI_accessReg(index,*pd++,PCI_WRITE_DWORD,info);
743         }
744     for (i = 0,pb = (uchar*)pd; i < endCount; i++, index++) {
745         PCI_accessReg(index,*pb++,PCI_WRITE_BYTE,info);
746         }
747 }