]> mj.ucw.cz Git - pciutils.git/blob - lib/generic.c
ee95f260694467d9245d7a2db3268a845b541172
[pciutils.git] / lib / generic.c
1 /*
2  *      $Id: generic.c,v 1.8 2002/12/27 19:01:51 mj Exp $
3  *
4  *      The PCI Library -- Generic Direct Access Functions
5  *
6  *      Copyright (c) 1997--2000 Martin Mares <mj@ucw.cz>
7  *
8  *      Can be freely distributed and used under the terms of the GNU GPL.
9  */
10
11 #include <string.h>
12
13 #include "internal.h"
14
15 void
16 pci_generic_scan_bus(struct pci_access *a, byte *busmap, int bus)
17 {
18   int dev, multi, ht;
19   struct pci_dev *t = pci_alloc_dev(a);
20
21   a->debug("Scanning bus %02x for devices...\n", bus);
22   if (busmap[bus])
23     {
24       a->warning("Bus %02x seen twice (firmware bug). Ignored.", bus);
25       return;
26     }
27   busmap[bus] = 1;
28   t->bus = bus;
29   for(dev=0; dev<32; dev++)
30     {
31       t->dev = dev;
32       multi = 0;
33       for(t->func=0; !t->func || multi && t->func<8; t->func++)
34         {
35           u32 vd = pci_read_long(t, PCI_VENDOR_ID);
36           struct pci_dev *d;
37
38           if (!vd || vd == 0xffffffff)
39             continue;
40           ht = pci_read_byte(t, PCI_HEADER_TYPE);
41           if (!t->func)
42             multi = ht & 0x80;
43           ht &= 0x7f;
44           d = pci_alloc_dev(a);
45           d->bus = t->bus;
46           d->dev = t->dev;
47           d->func = t->func;
48           d->vendor_id = vd & 0xffff;
49           d->device_id = vd >> 16U;
50           d->known_fields = PCI_FILL_IDENT;
51           d->hdrtype = ht;
52           pci_link_dev(a, d);
53           switch (ht)
54             {
55             case PCI_HEADER_TYPE_NORMAL:
56               break;
57             case PCI_HEADER_TYPE_BRIDGE:
58             case PCI_HEADER_TYPE_CARDBUS:
59               pci_generic_scan_bus(a, busmap, pci_read_byte(t, PCI_SECONDARY_BUS));
60               break;
61             default:
62               a->debug("Device %02x:%02x.%d has unknown header type %02x.\n", d->bus, d->dev, d->func, ht);
63             }
64         }
65     }
66 }
67
68 void
69 pci_generic_scan(struct pci_access *a)
70 {
71   byte busmap[256];
72
73   bzero(busmap, sizeof(busmap));
74   pci_generic_scan_bus(a, busmap, 0);
75 }
76
77 int
78 pci_generic_fill_info(struct pci_dev *d, int flags)
79 {
80   struct pci_access *a = d->access;
81
82   if (flags & PCI_FILL_IDENT)
83     {
84       d->vendor_id = pci_read_word(d, PCI_VENDOR_ID);
85       d->device_id = pci_read_word(d, PCI_DEVICE_ID);
86     }
87   if (flags & PCI_FILL_IRQ)
88     d->irq = pci_read_byte(d, PCI_INTERRUPT_LINE);
89   if (flags & PCI_FILL_BASES)
90     {
91       int cnt = 0, i;
92       bzero(d->base_addr, sizeof(d->base_addr));
93       switch (d->hdrtype)
94         {
95         case PCI_HEADER_TYPE_NORMAL:
96           cnt = 6;
97           break;
98         case PCI_HEADER_TYPE_BRIDGE:
99           cnt = 2;
100           break;
101         case PCI_HEADER_TYPE_CARDBUS:
102           cnt = 1;
103           break;
104         }
105       if (cnt)
106         {
107           u16 cmd = pci_read_word(d, PCI_COMMAND);
108           for(i=0; i<cnt; i++)
109             {
110               u32 x = pci_read_long(d, PCI_BASE_ADDRESS_0 + i*4);
111               if (!x || x == (u32) ~0)
112                 continue;
113               d->base_addr[i] = x;
114               if (x & PCI_BASE_ADDRESS_SPACE_IO)
115                 {
116                   if (!a->buscentric && !(cmd & PCI_COMMAND_IO))
117                     d->base_addr[i] = 0;
118                 }
119               else if (a->buscentric || (cmd & PCI_COMMAND_MEMORY))
120                 {
121                   if ((x & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64)
122                     {
123                       if (i >= cnt-1)
124                         a->warning("%02x:%02x.%d: Invalid 64-bit address seen.", d->bus, d->dev, d->func);
125                       else
126                         {
127                           u32 y = pci_read_long(d, PCI_BASE_ADDRESS_0 + (++i)*4);
128 #ifdef HAVE_64BIT_ADDRESS
129                           d->base_addr[i-1] |= ((pciaddr_t) y) << 32;
130 #else
131                           if (y)
132                             {
133                               a->warning("%02x:%02x.%d 64-bit device address ignored.", d->bus, d->dev, d->func);
134                               d->base_addr[i-1] = 0;
135                             }
136 #endif
137                         }
138                     }
139                 }
140               else
141                 d->base_addr[i] = 0;
142             }
143         }
144     }
145   if (flags & PCI_FILL_ROM_BASE)
146     {
147       int reg = 0;
148       d->rom_base_addr = 0;
149       switch (d->hdrtype)
150         {
151         case PCI_HEADER_TYPE_NORMAL:
152           reg = PCI_ROM_ADDRESS;
153           break;
154         case PCI_HEADER_TYPE_BRIDGE:
155           reg = PCI_ROM_ADDRESS1;
156           break;
157         }
158       if (reg)
159         {
160           u32 a = pci_read_long(d, reg);
161           if (a & PCI_ROM_ADDRESS_ENABLE)
162             d->rom_base_addr = a;
163         }
164     }
165   return flags & ~PCI_FILL_SIZES;
166 }
167
168 static int
169 pci_generic_block_op(struct pci_dev *d, int pos, byte *buf, int len,
170                  int (*r)(struct pci_dev *d, int pos, byte *buf, int len))
171 {
172   if ((pos & 1) && len >= 1)
173     {
174       if (!r(d, pos, buf, 1))
175         return 0;
176       pos++; buf++; len--;
177     }
178   if ((pos & 3) && len >= 2)
179     {
180       if (!r(d, pos, buf, 2))
181         return 0;
182       pos += 2; buf += 2; len -= 2;
183     }
184   while (len >= 4)
185     {
186       if (!r(d, pos, buf, 4))
187         return 0;
188       pos += 4; buf += 4; len -= 4;
189     }
190   if (len >= 2)
191     {
192       if (!r(d, pos, buf, 2))
193         return 0;
194       pos += 2; buf += 2; len -= 2;
195     }
196   if (len && !r(d, pos, buf, 1))
197     return 0;
198   return 1;
199 }
200
201 int
202 pci_generic_block_read(struct pci_dev *d, int pos, byte *buf, int len)
203 {
204   return pci_generic_block_op(d, pos, buf, len, d->access->methods->read);
205 }
206
207 int
208 pci_generic_block_write(struct pci_dev *d, int pos, byte *buf, int len)
209 {
210   return pci_generic_block_op(d, pos, buf, len, d->access->methods->write);
211 }