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