source: trunk/src/os2ahci/pci.c@ 36

Last change on this file since 36 was 36, checked in by markus, 15 years ago

Heureka! Fixed problems on real hardware (AHCI enabled bit must be set explicitly for each command...)

File size: 39.8 KB
Line 
1/******************************************************************************
2 * PCI.c - PCI constants and detection code for os2ahci driver
3 *
4 * Copyright (c) 2010 Christian Mueller. Parts copied from/inspired by the
5 * LINUX ahci driver; those parts are (c) Linux AHCI/ATA maintainers
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22#include "os2ahci.h"
23
24/* -------------------------- macros and constants ------------------------- */
25
26/* offset of PCI base address register (BAR) in the PCI config space */
27#define PCI_BAR(reg) (0x10 + (reg) * sizeof(u32))
28
29/* offset of MMIO base address register (BAR) for AHCI adapters */
30#define AHCI_MMIO PCI_BAR(AHCI_PCI_BAR)
31
32/******************************************************************************
33 * OEMHLP constants for PCI access
34 */
35#define GENERIC_IOCTL 0x10
36#define OH_CATEGORY 0x00
37#define OH_FUNC_PCI 0x0b
38
39/* subfunctions */
40#define OH_BIOS_INFO 0x00
41#define OH_FIND_DEVICE 0x01
42#define OH_FIND_CLASS 0x02
43#define OH_READ_CONFIG 0x03
44#define OH_WRITE_CONFIG 0x04
45
46/* return codes */
47#define OH_SUCCESS 0x00
48#define OH_NOT_SUPPORTED 0x81
49#define OH_BAD_VENDOR 0x83
50#define OH_NOT_FOUND 0x86
51#define OH_BAD_REGISTER 0x87
52
53/* ------------------------ typedefs and structures ------------------------ */
54
55/******************************************************************************
56 * OEMHLP IOCtl parameter union. The parameter area is generally used as input
57 * to the OEMHLP IOCtl calls.
58 */
59typedef union {
60
61 /* query PCI BIOS information" */
62 struct {
63 UCHAR subfunction;
64 } bios_info;
65
66 /* find PCI device */
67 struct {
68 UCHAR subfunction;
69 USHORT device;
70 USHORT vendor;
71 UCHAR index;
72 } find_device;
73
74 /* find PCI class code */
75 struct {
76 UCHAR subfunction;
77 ULONG class;
78 UCHAR index;
79 } find_class;
80
81 /* read PCI configuration space */
82 struct {
83 UCHAR subfunction;
84 UCHAR bus;
85 UCHAR dev_func;
86 UCHAR reg;
87 UCHAR size;
88 } read_config;
89
90 /* write PCI configuration space */
91 struct {
92 UCHAR subfunction;
93 UCHAR bus;
94 UCHAR dev_func;
95 UCHAR reg;
96 UCHAR size;
97 ULONG data;
98 } write_config;
99
100} OH_PARM;
101
102/******************************************************************************
103 * OEMHLP IOCtl data union. The data area is generally used as output from the
104 * OEMHLP IOCtl calls.
105 */
106typedef union {
107
108 /* query PCI BIOS information" */
109 struct {
110 UCHAR rc;
111 UCHAR hw_mech;
112 UCHAR major_version;
113 UCHAR minor_version;
114 UCHAR last_bus;
115 } bios_info;
116
117 /* find PCI device */
118 struct {
119 UCHAR rc;
120 UCHAR bus;
121 UCHAR dev_func;
122 } find_device;
123
124 /* find PCI class code */
125 struct {
126 UCHAR rc;
127 UCHAR bus;
128 UCHAR dev_func;
129 } find_class;
130
131 /* read PCI confguration space */
132 struct {
133 UCHAR rc;
134 ULONG data;
135 } read_config;
136
137 /* write PCI confguration space */
138 struct {
139 UCHAR rc;
140 } write_config;
141
142} OH_DATA;
143
144/* -------------------------- function prototypes -------------------------- */
145
146static void add_pci_device (PCI_ID *pci_id, OH_DATA _far *data);
147static UCHAR pci_read_conf (UCHAR bus, UCHAR dev_func, UCHAR indx,
148 UCHAR size, ULONG _far *val);
149static UCHAR pci_write_conf (UCHAR bus, UCHAR dev_func, UCHAR indx, UCHAR size,
150 ULONG val);
151static int oemhlp_call (UCHAR subfunction, OH_PARM _far *parm,
152 OH_DATA _far *data);
153
154/* ------------------------ global/static variables ------------------------ */
155
156/******************************************************************************
157 * chipset/controller name strings
158 */
159static char chip_esb2[] = "ESB2";
160static char chip_ich8[] = "ICH8";
161static char chip_ich8m[] = "ICH8M";
162static char chip_ich9[] = "ICH9";
163static char chip_ich9m[] = "ICH9M";
164static char chip_ich10[] = "ICH10";
165static char chip_pchahci[] = "PCH AHCI";
166static char chip_pchraid[] = "PCH RAID";
167static char chip_tolapai[] = "Tolapai";
168static char chip_sb600[] = "SB600";
169static char chip_sb700[] = "SB700/800";
170static char chip_vt8251[] = "VT8251";
171static char chip_mcp65[] = "MCP65";
172static char chip_mcp67[] = "MCP67";
173static char chip_mcp73[] = "MCP73";
174static char chip_mcp77[] = "MCP77";
175static char chip_mcp79[] = "MCP79";
176static char chip_mcp89[] = "MCP689";
177static char chip_sis968[] = "968";
178
179static char s_generic[] = "Generic";
180
181
182
183/******************************************************************************
184 * PCI vendor and device IDs for known AHCI adapters. Copied from the Linux
185 * AHCI driver.
186 */
187
188PCI_ID pci_ids[] = {
189
190 /* Intel
191 * NOTE: ICH5 controller does NOT support AHCI, so we do
192 * not add it here! */
193 { PCI_VDEVICE(INTEL, 0x2652), board_ahci, "ICH6" }, /* ICH6 */
194 { PCI_VDEVICE(INTEL, 0x2653), board_ahci, "ICH6M" }, /* ICH6M */
195 { PCI_VDEVICE(INTEL, 0x27c1), board_ahci, "ICH7" }, /* ICH7 */
196 { PCI_VDEVICE(INTEL, 0x27c5), board_ahci, "ICH7M" }, /* ICH7M */
197 { PCI_VDEVICE(INTEL, 0x27c3), board_ahci, "ICH7R" }, /* ICH7R */
198 { PCI_VDEVICE(AL, 0x5288), board_ahci_ign_iferr, "ULiM5288" }, /* ULi M5288 */
199 { PCI_VDEVICE(INTEL, 0x2681), board_ahci, chip_esb2 }, /* ESB2 */
200 { PCI_VDEVICE(INTEL, 0x2682), board_ahci, chip_esb2 }, /* ESB2 */
201 { PCI_VDEVICE(INTEL, 0x2683), board_ahci, chip_esb2 }, /* ESB2 */
202 { PCI_VDEVICE(INTEL, 0x27c6), board_ahci, "ICH7MDH" }, /* ICH7-M DH */
203 { PCI_VDEVICE(INTEL, 0x2821), board_ahci, chip_ich8 }, /* ICH8 */
204 { PCI_VDEVICE(INTEL, 0x2822), board_ahci_nosntf, chip_ich8 }, /* ICH8 */
205 { PCI_VDEVICE(INTEL, 0x2824), board_ahci, chip_ich8 }, /* ICH8 */
206 { PCI_VDEVICE(INTEL, 0x2829), board_ahci, chip_ich8m }, /* ICH8M */
207 { PCI_VDEVICE(INTEL, 0x282a), board_ahci, chip_ich8m }, /* ICH8M */
208 { PCI_VDEVICE(INTEL, 0x2922), board_ahci, chip_ich9 }, /* ICH9 */
209 { PCI_VDEVICE(INTEL, 0x2923), board_ahci, chip_ich9 }, /* ICH9 */
210 { PCI_VDEVICE(INTEL, 0x2924), board_ahci, chip_ich9 }, /* ICH9 */
211 { PCI_VDEVICE(INTEL, 0x2925), board_ahci, chip_ich9 }, /* ICH9 */
212 { PCI_VDEVICE(INTEL, 0x2927), board_ahci, chip_ich9 }, /* ICH9 */
213 { PCI_VDEVICE(INTEL, 0x2929), board_ahci, chip_ich9m }, /* ICH9M */
214 { PCI_VDEVICE(INTEL, 0x292a), board_ahci, chip_ich9m }, /* ICH9M */
215 { PCI_VDEVICE(INTEL, 0x292b), board_ahci, chip_ich9m }, /* ICH9M */
216 { PCI_VDEVICE(INTEL, 0x292c), board_ahci, chip_ich9m }, /* ICH9M */
217 { PCI_VDEVICE(INTEL, 0x292f), board_ahci, chip_ich9m }, /* ICH9M */
218 { PCI_VDEVICE(INTEL, 0x294d), board_ahci, chip_ich9 }, /* ICH9 */
219 { PCI_VDEVICE(INTEL, 0x294e), board_ahci, chip_ich9m }, /* ICH9M */
220 { PCI_VDEVICE(INTEL, 0x502a), board_ahci, chip_tolapai }, /* Tolapai */
221 { PCI_VDEVICE(INTEL, 0x502b), board_ahci, chip_tolapai }, /* Tolapai */
222 { PCI_VDEVICE(INTEL, 0x3a05), board_ahci, chip_ich10 }, /* ICH10 */
223 { PCI_VDEVICE(INTEL, 0x3a22), board_ahci, chip_ich10 }, /* ICH10 */
224 { PCI_VDEVICE(INTEL, 0x3a25), board_ahci, chip_ich10 }, /* ICH10 */
225 { PCI_VDEVICE(INTEL, 0x3b22), board_ahci, chip_pchahci }, /* PCH AHCI */
226 { PCI_VDEVICE(INTEL, 0x3b23), board_ahci, chip_pchahci }, /* PCH AHCI */
227 { PCI_VDEVICE(INTEL, 0x3b24), board_ahci, chip_pchraid }, /* PCH RAID */
228 { PCI_VDEVICE(INTEL, 0x3b25), board_ahci, chip_pchraid }, /* PCH RAID */
229 { PCI_VDEVICE(INTEL, 0x3b29), board_ahci, chip_pchahci }, /* PCH AHCI */
230 { PCI_VDEVICE(INTEL, 0x3b2b), board_ahci, chip_pchraid }, /* PCH RAID */
231 { PCI_VDEVICE(INTEL, 0x3b2c), board_ahci, chip_pchraid }, /* PCH RAID */
232 { PCI_VDEVICE(INTEL, 0x3b2f), board_ahci, chip_pchahci }, /* PCH AHCI */
233
234 /* JMicron 360/1/3/5/6, match class to avoid IDE function */
235 { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
236 PCI_CLASS_STORAGE_SATA_AHCI, 0xffffffL, board_ahci_ign_iferr, "360" },
237
238 /* ATI */
239 { PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600, "SB600" }, /* ATI SB600 */
240 { PCI_VDEVICE(ATI, 0x4390), board_ahci_sb700, chip_sb700 }, /* ATI SB700/800 */
241 { PCI_VDEVICE(ATI, 0x4391), board_ahci_sb700, chip_sb700 }, /* ATI SB700/800 */
242 { PCI_VDEVICE(ATI, 0x4392), board_ahci_sb700, chip_sb700 }, /* ATI SB700/800 */
243 { PCI_VDEVICE(ATI, 0x4393), board_ahci_sb700, chip_sb700 }, /* ATI SB700/800 */
244 { PCI_VDEVICE(ATI, 0x4394), board_ahci_sb700, chip_sb700 }, /* ATI SB700/800 */
245 { PCI_VDEVICE(ATI, 0x4395), board_ahci_sb700, chip_sb700 }, /* ATI SB700/800 */
246
247 /* AMD */
248 { PCI_VDEVICE(AMD, 0x7800), board_ahci }, /* AMD Hudson-2 */
249 /* AMD is using RAID class only for ahci controllers */
250 { PCI_VENDOR_ID_AMD, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
251 PCI_CLASS_STORAGE_RAID << 8, 0xffffffL, board_ahci, "Hudson2" },
252
253 /* VIA */
254 { PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251, chip_vt8251 }, /* VIA VT8251 */
255 { PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251, chip_vt8251 }, /* VIA VT8251 */
256
257 /* NVIDIA */
258 { PCI_VDEVICE(NVIDIA, 0x044c), board_ahci_mcp65, chip_mcp65 }, /* MCP65 */
259 { PCI_VDEVICE(NVIDIA, 0x044d), board_ahci_mcp65, chip_mcp65 }, /* MCP65 */
260 { PCI_VDEVICE(NVIDIA, 0x044e), board_ahci_mcp65, chip_mcp65 }, /* MCP65 */
261 { PCI_VDEVICE(NVIDIA, 0x044f), board_ahci_mcp65, chip_mcp65 }, /* MCP65 */
262 { PCI_VDEVICE(NVIDIA, 0x045c), board_ahci_mcp65, chip_mcp65 }, /* MCP65 */
263 { PCI_VDEVICE(NVIDIA, 0x045d), board_ahci_mcp65, chip_mcp65 }, /* MCP65 */
264 { PCI_VDEVICE(NVIDIA, 0x045e), board_ahci_mcp65, chip_mcp65 }, /* MCP65 */
265 { PCI_VDEVICE(NVIDIA, 0x045f), board_ahci_mcp65, chip_mcp65 }, /* MCP65 */
266 { PCI_VDEVICE(NVIDIA, 0x0550), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
267 { PCI_VDEVICE(NVIDIA, 0x0551), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
268 { PCI_VDEVICE(NVIDIA, 0x0552), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
269 { PCI_VDEVICE(NVIDIA, 0x0553), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
270 { PCI_VDEVICE(NVIDIA, 0x0554), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
271 { PCI_VDEVICE(NVIDIA, 0x0555), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
272 { PCI_VDEVICE(NVIDIA, 0x0556), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
273 { PCI_VDEVICE(NVIDIA, 0x0557), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
274 { PCI_VDEVICE(NVIDIA, 0x0558), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
275 { PCI_VDEVICE(NVIDIA, 0x0559), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
276 { PCI_VDEVICE(NVIDIA, 0x055a), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
277 { PCI_VDEVICE(NVIDIA, 0x055b), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
278 { PCI_VDEVICE(NVIDIA, 0x0580), board_ahci_yesncq, chip_mcp67 }, /* Linux ID */
279 { PCI_VDEVICE(NVIDIA, 0x07f0), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
280 { PCI_VDEVICE(NVIDIA, 0x07f1), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
281 { PCI_VDEVICE(NVIDIA, 0x07f2), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
282 { PCI_VDEVICE(NVIDIA, 0x07f3), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
283 { PCI_VDEVICE(NVIDIA, 0x07f4), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
284 { PCI_VDEVICE(NVIDIA, 0x07f5), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
285 { PCI_VDEVICE(NVIDIA, 0x07f6), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
286 { PCI_VDEVICE(NVIDIA, 0x07f7), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
287 { PCI_VDEVICE(NVIDIA, 0x07f8), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
288 { PCI_VDEVICE(NVIDIA, 0x07f9), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
289 { PCI_VDEVICE(NVIDIA, 0x07fa), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
290 { PCI_VDEVICE(NVIDIA, 0x07fb), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
291 { PCI_VDEVICE(NVIDIA, 0x0ad0), board_ahci, chip_mcp77 }, /* MCP77 */
292 { PCI_VDEVICE(NVIDIA, 0x0ad1), board_ahci, chip_mcp77 }, /* MCP77 */
293 { PCI_VDEVICE(NVIDIA, 0x0ad2), board_ahci, chip_mcp77 }, /* MCP77 */
294 { PCI_VDEVICE(NVIDIA, 0x0ad3), board_ahci, chip_mcp77 }, /* MCP77 */
295 { PCI_VDEVICE(NVIDIA, 0x0ad4), board_ahci, chip_mcp77 }, /* MCP77 */
296 { PCI_VDEVICE(NVIDIA, 0x0ad5), board_ahci, chip_mcp77 }, /* MCP77 */
297 { PCI_VDEVICE(NVIDIA, 0x0ad6), board_ahci, chip_mcp77 }, /* MCP77 */
298 { PCI_VDEVICE(NVIDIA, 0x0ad7), board_ahci, chip_mcp77 }, /* MCP77 */
299 { PCI_VDEVICE(NVIDIA, 0x0ad8), board_ahci, chip_mcp77 }, /* MCP77 */
300 { PCI_VDEVICE(NVIDIA, 0x0ad9), board_ahci, chip_mcp77 }, /* MCP77 */
301 { PCI_VDEVICE(NVIDIA, 0x0ada), board_ahci, chip_mcp77 }, /* MCP77 */
302 { PCI_VDEVICE(NVIDIA, 0x0adb), board_ahci, chip_mcp77 }, /* MCP77 */
303 { PCI_VDEVICE(NVIDIA, 0x0ab4), board_ahci, chip_mcp79 }, /* MCP79 */
304 { PCI_VDEVICE(NVIDIA, 0x0ab5), board_ahci, chip_mcp79 }, /* MCP79 */
305 { PCI_VDEVICE(NVIDIA, 0x0ab6), board_ahci, chip_mcp79 }, /* MCP79 */
306 { PCI_VDEVICE(NVIDIA, 0x0ab7), board_ahci, chip_mcp79 }, /* MCP79 */
307 { PCI_VDEVICE(NVIDIA, 0x0ab8), board_ahci, chip_mcp79 }, /* MCP79 */
308 { PCI_VDEVICE(NVIDIA, 0x0ab9), board_ahci, chip_mcp79 }, /* MCP79 */
309 { PCI_VDEVICE(NVIDIA, 0x0aba), board_ahci, chip_mcp79 }, /* MCP79 */
310 { PCI_VDEVICE(NVIDIA, 0x0abb), board_ahci, chip_mcp79 }, /* MCP79 */
311 { PCI_VDEVICE(NVIDIA, 0x0abc), board_ahci, chip_mcp79 }, /* MCP79 */
312 { PCI_VDEVICE(NVIDIA, 0x0abd), board_ahci, chip_mcp79 }, /* MCP79 */
313 { PCI_VDEVICE(NVIDIA, 0x0abe), board_ahci, chip_mcp79 }, /* MCP79 */
314 { PCI_VDEVICE(NVIDIA, 0x0abf), board_ahci, chip_mcp79 }, /* MCP79 */
315 { PCI_VDEVICE(NVIDIA, 0x0d84), board_ahci, chip_mcp89 }, /* MCP89 */
316 { PCI_VDEVICE(NVIDIA, 0x0d85), board_ahci, chip_mcp89 }, /* MCP89 */
317 { PCI_VDEVICE(NVIDIA, 0x0d86), board_ahci, chip_mcp89 }, /* MCP89 */
318 { PCI_VDEVICE(NVIDIA, 0x0d87), board_ahci, chip_mcp89 }, /* MCP89 */
319 { PCI_VDEVICE(NVIDIA, 0x0d88), board_ahci, chip_mcp89 }, /* MCP89 */
320 { PCI_VDEVICE(NVIDIA, 0x0d89), board_ahci, chip_mcp89 }, /* MCP89 */
321 { PCI_VDEVICE(NVIDIA, 0x0d8a), board_ahci, chip_mcp89 }, /* MCP89 */
322 { PCI_VDEVICE(NVIDIA, 0x0d8b), board_ahci, chip_mcp89 }, /* MCP89 */
323 { PCI_VDEVICE(NVIDIA, 0x0d8c), board_ahci, chip_mcp89 }, /* MCP89 */
324 { PCI_VDEVICE(NVIDIA, 0x0d8d), board_ahci, chip_mcp89 }, /* MCP89 */
325 { PCI_VDEVICE(NVIDIA, 0x0d8e), board_ahci, chip_mcp89 }, /* MCP89 */
326 { PCI_VDEVICE(NVIDIA, 0x0d8f), board_ahci, chip_mcp89 }, /* MCP89 */
327
328 /* SiS */
329 { PCI_VDEVICE(SI, 0x1184), board_ahci, "966" }, /* SiS 966 */
330 { PCI_VDEVICE(SI, 0x1185), board_ahci, chip_sis968 }, /* SiS 968 */
331 { PCI_VDEVICE(SI, 0x0186), board_ahci, chip_sis968 }, /* SiS 968 */
332
333 /* Marvell */
334 { PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv, "6145" }, /* 6145 */
335 { PCI_VDEVICE(MARVELL, 0x6121), board_ahci_mv, "6121" }, /* 6121 */
336
337 /* Promise */
338 { PCI_VDEVICE(PROMISE, 0x3f20), board_ahci, "PDC42819" }, /* PDC42819 */
339
340 /* Generic, PCI class code for AHCI */
341 { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
342 PCI_CLASS_STORAGE_SATA_AHCI, 0xffffffL, board_ahci, s_generic },
343
344 /* end of list, including a few slots to define custom adapters (10) */
345 { 0, 0, 0, 0, 0, 0, 0, NULL },
346 { 0, 0, 0, 0, 0, 0, 0, NULL },
347 { 0, 0, 0, 0, 0, 0, 0, NULL },
348 { 0, 0, 0, 0, 0, 0, 0, NULL },
349 { 0, 0, 0, 0, 0, 0, 0, NULL },
350 { 0, 0, 0, 0, 0, 0, 0, NULL },
351 { 0, 0, 0, 0, 0, 0, 0, NULL },
352 { 0, 0, 0, 0, 0, 0, 0, NULL },
353 { 0, 0, 0, 0, 0, 0, 0, NULL },
354 { 0, 0, 0, 0, 0, 0, 0, NULL },
355
356 { 0, 0, 0, 0, 0, 0, 0, NULL }
357};
358
359/******************************************************************************
360 * OEMHLP$ is used by OS/2 to provide access to OEM-specific machine resources
361 * like PCI BIOS access. We're using this to enumerate the PCI bus. Due to
362 * BIOS bugs, it may be necessary to use I/O operations for this purpose but
363 * so far I think this is only relevant for rather old PCs and SATA is not
364 * expected to be a priority on those machines.
365 */
366static IDCTABLE oemhlp; /* OEMHLP$ IDC entry point */
367
368/* ----------------------------- start of code ----------------------------- */
369
370/******************************************************************************
371 * Add specified PCI vendor and device ID to the list of supported AHCI
372 * controllers. Please note that the last slot in pci_ids needs to remain
373 * empty because it's used as end marker.
374 */
375int add_pci_id(u16 vendor, u16 device)
376{
377 int max_slot = sizeof(pci_ids) / sizeof(*pci_ids) - 2;
378 int i;
379
380 /* search for last used slot in 'pci_ids' */
381 for (i = max_slot; i >= 0 && pci_ids[i].vendor == 0; i--);
382 if (i >= max_slot) {
383 /* all slots in use */
384 return(-1);
385 }
386
387 /* use slot after the last used slot */
388 i++;
389 pci_ids[i].vendor = vendor;
390 pci_ids[i].device = device;
391 pci_ids[i].board = board_ahci;
392 pci_ids[i].chipname = s_generic;
393 return(0);
394}
395
396/******************************************************************************
397 * Scan PCI bus using OEMHLP$ IOCTLs and build adapter list.
398 */
399void scan_pci_bus(void)
400{
401 OH_PARM parm;
402 OH_DATA data;
403 UCHAR index;
404 UCHAR rc;
405 int i;
406
407 ddprintf("scanning PCI bus...\n");
408
409 /* verify that we have a PCI system */
410 memset(&parm, 0x00, sizeof(parm));
411 if (oemhlp_call(OH_BIOS_INFO, &parm, &data) != OH_SUCCESS) {
412 cprintf("couldn't get PCI BIOS information\n");
413 return;
414 }
415
416 /* Go through the list of PCI IDs and search for each device
417 *
418 * NOTES:
419 *
420 * - When searching via class code, the OEMHLP$ interface doesn't allow
421 * setting a bitmask to look for individual portions of class code,
422 * subclass code and programming interface. However, all bitmasks in the
423 * PCI list currently use 0xffffff, thus this should not be a problem at
424 * this point in time.
425 *
426 * - Scanning via OEMHLP$ seems rather slow, at least in the virtual
427 * machine I'm currenly using to test this driver. Thus, class code
428 * scans are preferred unless the option "-t" (thorough_scan) has been
429 * specified. The assumption is that most, if not all, modern AHCI
430 * adapters have the correct class code (PCI_CLASS_STORAGE_SATA_AHCI).
431 */
432 for (i = 0; pci_ids[i].vendor != 0; i++) {
433 index = 0;
434 do {
435 if (pci_ids[i].device == PCI_ANY_ID || pci_ids[i].vendor == PCI_ANY_ID) {
436 /* look for class code */
437 memset(&parm, 0x00, sizeof(parm));
438 parm.find_class.class = pci_ids[i].class;
439 parm.find_class.index = index;
440 rc = oemhlp_call(OH_FIND_CLASS, &parm, &data);
441
442 } else if (thorough_scan) {
443 /* look for this specific vendor and device ID */
444 memset(&parm, 0x00, sizeof(parm));
445 parm.find_device.device = pci_ids[i].device;
446 parm.find_device.vendor = pci_ids[i].vendor;
447 parm.find_device.index = index;
448 rc = oemhlp_call(OH_FIND_DEVICE, &parm, &data);
449
450 } else {
451 rc = OH_NOT_FOUND;
452 }
453
454 if (rc == OH_SUCCESS) {
455 /* found a device */
456 add_pci_device(pci_ids + i, &data);
457 if (++index > 180) {
458 /* something's wrong here... */
459 return;
460 }
461 }
462
463 } while (rc == OH_SUCCESS);
464 }
465}
466
467/******************************************************************************
468 * Enable interrupt generation. PCI 2.3 added a bit which allows disabling
469 * interrupt generation for a device. This function clears the corresponding
470 * bit in the configuration space command register.
471 */
472int pci_enable_int(UCHAR bus, UCHAR dev_func)
473{
474 ULONG tmp;
475
476 if (pci_read_conf (bus, dev_func, 4, sizeof(u32), &tmp) != OH_SUCCESS ||
477 pci_write_conf(bus, dev_func, 4, sizeof(u32), tmp & ~(1UL << 10)) != OH_SUCCESS) {
478 return(-1);
479 }
480 return(0);
481}
482
483/******************************************************************************
484 * Hack to set up proper IRQ mappings in the emulated PIIX3 ISA bridge in
485 * VirtualBox (for some reason, the first mapped IRQ is 0x80 without this
486 * hack).
487 */
488void pci_hack_virtualbox(void)
489{
490 ULONG irq = 0;
491
492 if (pci_read_conf(0, 0x08, 0x60, 1, &irq) == OH_SUCCESS && irq == 0x80) {
493 /* set IRQ for first device/func to 11 */
494 dprintf("hacking virtualbox PIIX3 PCI to ISA bridge IRQ mapping\n");
495 irq = ad_infos[0].irq;
496 pci_write_conf(0, 0x08, 0x60, 1, irq);
497 }
498}
499
500/******************************************************************************
501 * Add a single PCI device to the list of adapters.
502 */
503static void add_pci_device(PCI_ID *pci_id, OH_DATA _far *data)
504{
505 char rc_list_buf[sizeof(AHRESOURCE) + sizeof(HRESOURCE) * 4];
506 AHRESOURCE _far *rc_list = (AHRESOURCE _far *) rc_list_buf;
507 RESOURCESTRUCT resource;
508 ADAPTERSTRUCT adapter;
509 ADJUNCT adj;
510 AD_INFO *ad_info;
511 APIRET ret;
512 UCHAR bus = data->find_class.bus;
513 UCHAR dev_func = data->find_class.dev_func;
514 ULONG val;
515 SEL gdt[PORT_DMA_BUF_SEGS + 1];
516 char tmp[40];
517 u16 device;
518 u16 vendor;
519 u32 class;
520 u32 mmio_bios = 0;
521 u32 mmio_size;
522 u32 mmio_rqd;
523 int irq;
524 int pin;
525 int i;
526
527 /*****************************************************************************
528 * Part 1: Get further information about the device to be added; PCI ID...
529 */
530 if (pci_read_conf(bus, dev_func, 0x00, sizeof(ULONG), &val) != OH_SUCCESS) {
531 return;
532 }
533 device = (u16) (val >> 16);
534 vendor = (u16) (val & 0xffff);
535
536 /* ... and class code */
537 if (pci_read_conf(bus, dev_func, 0x08, sizeof(ULONG), &val) != OH_SUCCESS) {
538 return;
539 }
540 class = (u32) (val >> 8);
541
542 if (pci_id->device == PCI_ANY_ID) {
543 /* We found this device in a wildcard search. There are two possible
544 * reasons which require a different handling:
545 *
546 * 1) This device uses a non-standard PCI class and has been identified
547 * with the corresponding class in pci_ids[] (e.g. the entry
548 * PCI_VENDOR_ID_JMICRON), but there is a vendor ID in pci_ids[]. In
549 * this case, we need to verify that the vendor is correct (see
550 * comments regarding OEMHLP limitations in 'scan_pci_bus()')
551 *
552 * 2) This device was identified using a generic PCI class for AHCI
553 * adapters such as PCI_CLASS_STORAGE_SATA_AHCI and we need to map
554 * the device and vendor ID to the corresponding index in pci_ids[]
555 * if there is such an entry; the index passed to this function will
556 * be the generic class-based index which is fine as long as there's
557 * not special treatment required as indicated by the board_*
558 * constants in pci_ids[]...
559 *
560 * The main reason for this kludge is that it seems as if OEMHLP$
561 * is rather slow searching for PCI devices, adding around 30s
562 * to the boot time when scanning for individual AHCI PCI IDs. Thus,
563 * the OS2AHCI driver avoids this kind of scan in favor of a class-
564 * based scan (unless overridden with the "/T" option).
565 */
566 if (pci_id->vendor != PCI_ANY_ID) {
567 /* case 1: the vendor is known but we found the PCI device using a class
568 * search; verify vendor matches the one in pci_ids[]
569 */
570 if (pci_id->vendor != vendor) {
571 /* vendor doesn't match */
572 return;
573 }
574
575 } else {
576 /* case 2: we found this device using a generic class search; if the
577 * device/vendor is listed in pci_ids[], use this entry in favor of the
578 * one passed in 'pci_id'
579 */
580 for (i = 0; pci_ids[i].vendor != 0; i++) {
581 if (pci_ids[i].device == device && pci_ids[i].vendor == vendor) {
582 pci_id = pci_ids + i;
583 break;
584 }
585 }
586 }
587 }
588
589 /* found a supported AHCI device */
590 cprintf("found AHCI device: %s %s (%04x:%04x)\n"
591 " class:0x%06lx bus:%d devfunc:0x%02x\n",
592 vendor_from_id(vendor), device_from_id(device),
593 vendor, device,
594 class, bus, dev_func);
595
596 /* make sure we got room in the adapter information array */
597 if (ad_info_cnt >= MAX_AD - 1) {
598 cprintf("error: too many AHCI devices\n");
599 return;
600 }
601
602 /****************************************************************************
603 * Part 2: Determine resource requirements and allocate resources with the
604 * OS/2 resource manager. While doing so, some of the entries of the
605 * corresponding slot in the AD_INFO array, namely resource manager
606 * handles, are initialized so we need prepare the slot.
607 *
608 * NOTE: While registering resources with the resource manager, each new
609 * resource is added to the corresponding rc_list.hResource[] slot.
610 * rc_list is used further down to associate resources to adapters
611 * whe the adapter itself is registered with the OS/2 resource manager.
612 */
613 ad_info = ad_infos + ad_info_cnt;
614 memset(ad_info, 0x00, sizeof(*ad_info));
615 rc_list->NumResource = 0;
616
617 /* Register IRQ with resource manager
618 *
619 * NOTE: We rely on the IRQ number saved in the PCI config space by the PCI
620 * BIOS. There's no reliable way to find out the IRQ number in any
621 * other way unless we start using message-driven interrupts (which
622 * is out of scope for the time being).
623 */
624 if (pci_read_conf(bus, dev_func, 0x3c, sizeof(u32), &val) != OH_SUCCESS) {
625 return;
626 }
627 irq = (int) (val & 0xff);
628 pin = (int) ((val >> 8) & 0xff);
629
630 memset(&resource, 0x00, sizeof(resource));
631 resource.ResourceType = RS_TYPE_IRQ;
632 resource.IRQResource.IRQLevel = irq;
633 resource.IRQResource.PCIIrqPin = pin;
634 resource.IRQResource.IRQFlags = RS_IRQ_SHARED;
635
636 ret = RMAllocResource(rm_drvh, &ad_info->rm_irq, &resource);
637 switch (ret) {
638 case RMRC_SUCCESS:
639 break;
640 case RMRC_DEV_ALREADY_CLAIMED:
641 case RMRC_RES_ALREADY_CLAIMED:
642 cprintf("warning: device already claimed by other driver\n");
643 return;
644 default:
645 cprintf("error: couldn't register IRQ %d (rc = %d)\n", irq, ret);
646 return;
647 }
648 rc_list->hResource[rc_list->NumResource++] = ad_info->rm_irq;
649
650 /* Determine MMIO size for this device
651 *
652 * NOTE: In order to do this, we need to temporarily write 0xffffffff to
653 * the MMIO base address register (BAR), read back the resulting value
654 * and check the 0 bits from the right end. After doing this, we must
655 * restore the original value set up by the BIOS because we're not yet
656 * ready to take over.
657 *
658 * The least significant 4 bits are not relevant for the MMIO address, thus
659 * we'll start at 0x10:
660 *
661 * 31 4 3 2 1 0
662 * -------------------------------------------------------------------
663 * base address P T T I
664 * P = prefetchable
665 * T = type
666 * I = I/O (1) or memory (0)
667 */
668 if (pci_read_conf (bus, dev_func, AHCI_MMIO, sizeof(u32), &mmio_bios) != OH_SUCCESS ||
669 pci_write_conf(bus, dev_func, AHCI_MMIO, sizeof(u32), ~(0UL)) != OH_SUCCESS ||
670 pci_read_conf (bus, dev_func, AHCI_MMIO, sizeof(u32), &mmio_rqd) != OH_SUCCESS ||
671 pci_write_conf(bus, dev_func, AHCI_MMIO, sizeof(u32), mmio_bios) != OH_SUCCESS) {
672
673 cprintf("error: couldn't determine MMIO size\n");
674 if (mmio_bios != 0) {
675 cprintf("restoring BIOS MMIO address\n");
676 pci_write_conf(bus, dev_func, AHCI_MMIO, sizeof(u32), mmio_bios);
677 }
678 goto add_pci_fail;
679 }
680 for (mmio_size = 0x00000010UL;
681 mmio_size < 0x10000000UL && (mmio_rqd & mmio_size) == 0;
682 mmio_size <<= 1);
683
684 ddprintf("MMIO size = %ld\n", mmio_size);
685 ddprintf("MMIO address (BIOS) = 0x%08lx\n", mmio_bios & 0xfffffff0UL);
686
687 /* register BIOS MMIO address space with resource manager */
688 memset(&resource, 0x00, sizeof(resource));
689 resource.ResourceType = RS_TYPE_MEM;
690 resource.MEMResource.MemBase = mmio_bios & 0xfffffff0UL;
691 resource.MEMResource.MemSize = mmio_size;
692 resource.MEMResource.MemFlags = RS_MEM_EXCLUSIVE;
693
694 ret = RMAllocResource(rm_drvh, &ad_info->rm_mmio, &resource);
695
696 if (ret != RMRC_SUCCESS) {
697 /* didn't work; try to find another MMIO region */
698 cprintf("warning: BIOS MMIO address not accepted by resource manager\n");
699 memset(&resource, 0x00, sizeof(resource));
700 resource.ResourceType = RS_TYPE_MEM;
701 resource.MEMResource.MemSize = mmio_size;
702 resource.MEMResource.MemFlags = RS_MEM_EXCLUSIVE | RS_SEARCH;
703
704 ret = RMAllocResource(rm_drvh, &ad_info->rm_mmio, &resource);
705
706 if (ret == RMRC_SUCCESS) {
707 /* MT: got a new address from Resource Manager; now we
708 * need to tell PCI about the new address.
709 * Leave the last 4 bits of the original MMIO value alone.
710 */
711 mmio_bios = (mmio_bios & 0x0000000fUL) |
712 (resource.MEMResource.MemBase & 0xfffffff0UL);
713 ddprintf("address we got from RM: 0x%08lx\n",
714 resource.MEMResource.MemBase);
715 ddprintf("setting new MMIO addr to 0x%08lx\n", mmio_bios);
716
717 if (pci_write_conf(bus, dev_func, AHCI_MMIO,
718 sizeof(u32), mmio_bios) != OH_SUCCESS) {
719 /* failed to update MMIO address - bail out */
720 cprintf("error: couldn't update MMIO address\n");
721 ret = ~RMRC_SUCCESS;
722 goto add_pci_fail;
723 }
724
725 }
726 }
727
728 if (ret != RMRC_SUCCESS) {
729 cprintf("error: couldn't register MMIO region (rc = %d)\n", ret);
730 goto add_pci_fail;
731 }
732 rc_list->hResource[rc_list->NumResource++] = ad_info->rm_mmio;
733 ddprintf("MMIO address (final) = 0x%08lx\n", resource.MEMResource.MemBase);
734
735 /****************************************************************************
736 * Part 3: Fill in the remaining fields in the AD_INFO slot and allocate
737 * memory and GDT selectors for the adapter. Finally, register the adapter
738 * itself with the OS/2 resource manager
739 */
740 ad_info->pci = pci_ids + i;
741 ad_info->bus = bus;
742 ad_info->dev_func = dev_func;
743 ad_info->irq = irq;
744 ad_info->mmio_phys = resource.MEMResource.MemBase;
745
746 /* allocate memory for port-specific DMA scratch buffers */
747 if (DevHelp_AllocPhys((long) AHCI_PORT_PRIV_DMA_SZ * AHCI_MAX_PORTS,
748 MEMTYPE_ABOVE_1M, &ad_info->dma_buf_phys) != 0) {
749 cprintf("error: couldn't allocate DMA scratch buffers for AHCI ports\n");
750 ad_info->dma_buf_phys = 0;
751 goto add_pci_fail;
752 }
753
754 /* allocate GDT selectors for memory-mapped I/O and DMA scratch buffers */
755 if (DevHelp_AllocGDTSelector(gdt, PORT_DMA_BUF_SEGS + 1) != 0) {
756 cprintf("error: couldn't allocate GDT selectors\n");
757 memset(gdt, 0x00, sizeof(gdt));
758 goto add_pci_fail;
759 }
760
761 /* map MMIO address to first GDT selector */
762 if (DevHelp_PhysToGDTSelector(ad_info->mmio_phys, (USHORT) mmio_size,
763 gdt[0]) != 0) {
764 cprintf("error: couldn't map MMIO address to GDT selector\n");
765 goto add_pci_fail;
766 }
767
768 /* map DMA scratch buffers to remaining GDT selectors */
769 for (i = 0; i < PORT_DMA_BUF_SEGS; i++) {
770 ULONG addr = ad_info->dma_buf_phys + i * PORT_DMA_SEG_SIZE;
771 USHORT len = AHCI_PORT_PRIV_DMA_SZ * PORT_DMA_BUFS_PER_SEG;
772
773 if (DevHelp_PhysToGDTSelector(addr, len, gdt[i+1]) != 0) {
774 cprintf("error: couldn't map DMA scratch buffer to GDT selector\n");
775 goto add_pci_fail;
776 }
777 }
778
779 /* fill in MMIO and DMA scratch buffer addresses in adapter info */
780 ad_info->mmio = (u8 _far *) ((u32) gdt[0] << 16);
781 for (i = 0; i < PORT_DMA_BUF_SEGS; i++) {
782 ad_info->dma_buf[i] = (u8 _far *) ((u32) gdt[i+1] << 16);
783 }
784
785 /* register adapter with resource manager */
786 memset(&adj, 0x00, sizeof(adj));
787 adj.pNextAdj = NULL;
788 adj.AdjLength = sizeof(adj);
789 adj.AdjType = ADJ_ADAPTER_NUMBER;
790 adj.Adapter_Number = ad_info_cnt;
791
792 memset(&adapter, 0x00, sizeof(adapter));
793 sprintf(tmp, "AHCI_%d Controller", ad_info_cnt);
794 adapter.AdaptDescriptName = tmp;
795 adapter.AdaptFlags = 0;
796 adapter.BaseType = AS_BASE_MSD;
797 adapter.SubType = AS_SUB_IDE;
798 adapter.InterfaceType = AS_INTF_GENERIC;
799 adapter.HostBusType = AS_HOSTBUS_PCI;
800 adapter.HostBusWidth = AS_BUSWIDTH_32BIT;
801 adapter.pAdjunctList = &adj;
802
803 ret = RMCreateAdapter(rm_drvh, &ad_info->rm_adh, &adapter, NULL, rc_list);
804 if (ret != RMRC_SUCCESS) {
805 cprintf("error: couldn't register adapter (rc = %d)\n", ret);
806 goto add_pci_fail;
807 }
808
809 /* Successfully added the adapter and reserved its resources; the adapter
810 * is still under BIOS control so we're not going to do anything else at
811 * this point.
812 */
813 ad_info_cnt++;
814 return;
815
816add_pci_fail:
817 /* something went wrong; try to clean up as far as possible */
818 if (ad_info->rm_mmio != 0) {
819 RMDeallocResource(rm_drvh, ad_info->rm_mmio);
820 }
821 if (ad_info->rm_irq != 0) {
822 RMDeallocResource(rm_drvh, ad_info->rm_irq);
823 }
824 if (&ad_info->dma_buf_phys != 0) {
825 DevHelp_FreePhys(ad_info->dma_buf_phys);
826 }
827 for (i = 0; i < sizeof(gdt) / sizeof(*gdt); i++) {
828 if (gdt[i] != 0) {
829 DevHelp_FreeGDTSelector(gdt[i]);
830 }
831 }
832}
833
834/******************************************************************************
835 * Read PCI configuration space register
836 */
837static UCHAR pci_read_conf(UCHAR bus, UCHAR dev_func, UCHAR indx, UCHAR size,
838 ULONG _far *val)
839{
840 OH_PARM parm;
841 OH_DATA data;
842 UCHAR rc;
843
844 memset(&parm, 0x00, sizeof(parm));
845 parm.read_config.bus = bus;
846 parm.read_config.dev_func = dev_func;
847 parm.read_config.reg = indx;
848 parm.read_config.size = size;
849 if ((rc = oemhlp_call(OH_READ_CONFIG, &parm, &data) != OH_SUCCESS)) {
850 cprintf("error: couldn't read config space (bus = %d, dev_func = 0x%02x, indx = 0x%02x, rc = %d)\n",
851 bus, dev_func, indx, rc);
852 return(rc);
853 }
854
855 *val = data.read_config.data;
856 return(OH_SUCCESS);
857}
858
859/******************************************************************************
860 * Write PCI configuration space register
861 */
862static UCHAR pci_write_conf(UCHAR bus, UCHAR dev_func, UCHAR indx, UCHAR size,
863 ULONG val)
864{
865 OH_PARM parm;
866 OH_DATA data;
867 UCHAR rc;
868
869 memset(&parm, 0x00, sizeof(parm));
870 parm.write_config.bus = bus;
871 parm.write_config.dev_func = dev_func;
872 parm.write_config.reg = indx;
873 parm.write_config.size = size;
874 parm.write_config.data = val;
875
876 if ((rc = oemhlp_call(OH_WRITE_CONFIG, &parm, &data) != OH_SUCCESS)) {
877 cprintf("error: couldn't write config space (bus = %d, dev_func = 0x%02x, indx = 0x%02x, rc = %d)\n",
878 bus, dev_func, indx, rc);
879 return(rc);
880 }
881
882 return(OH_SUCCESS);
883}
884/******************************************************************************
885 * Call OEMHLP$ IDC entry point with the specified IOCtl parameter and data
886 * packets.
887 */
888static int oemhlp_call(UCHAR subfunction, OH_PARM _far *parm,
889 OH_DATA _far *data)
890{
891 void (_far *func)(void);
892 RP_GENIOCTL ioctl;
893 unsigned short prot_idc_ds;
894
895 if (oemhlp.ProtIDCEntry == NULL || oemhlp.ProtIDC_DS == 0) {
896 /* attach to OEMHLP$ device driver */
897 if (DevHelp_AttachDD("OEMHLP$ ", (NPBYTE) &oemhlp) ||
898 oemhlp.ProtIDCEntry == NULL ||
899 oemhlp.ProtIDC_DS == 0) {
900 cprintf("couldn't attach to OEMHLP$\n");
901 return(OH_NOT_SUPPORTED);
902 }
903 }
904
905 /* store subfuntion in first byte of pararameter packet */
906 parm->bios_info.subfunction = subfunction;
907 memset(data, 0x00, sizeof(*data));
908
909 /* assemble IOCtl request */
910 memset(&ioctl, 0x00, sizeof(ioctl));
911 ioctl.rph.Len = sizeof(ioctl);
912 ioctl.rph.Unit = 0;
913 ioctl.rph.Cmd = GENERIC_IOCTL;
914 ioctl.rph.Status = 0;
915
916 ioctl.Category = OH_CATEGORY;
917 ioctl.Function = OH_FUNC_PCI;
918 ioctl.ParmPacket = (PUCHAR) parm;
919 ioctl.DataPacket = (PUCHAR) data;
920 ioctl.ParmLen = sizeof(*parm);
921 ioctl.DataLen = sizeof(*data);
922
923 /* Call OEMHLP's IDC routine. Before doing so, we need to assign the address
924 * to be called to a stack variable because the inter-device driver calling
925 * convention forces us to set DS to the device driver's data segment and ES
926 * to the segment of the request packet.
927 */
928 func = oemhlp.ProtIDCEntry;
929
930 /* The WATCOM compiler does not support struct references in inline
931 * assembler code, so we pass it in a stack variable
932 */
933 prot_idc_ds = oemhlp.ProtIDC_DS;
934
935 _asm {
936 push ds;
937 push es;
938 push bx;
939 push si;
940 push di;
941
942 push ss
943 pop es
944 lea bx, ioctl;
945 mov ds, prot_idc_ds;
946 call dword ptr [func];
947
948 pop di;
949 pop si;
950 pop bx;
951 pop es;
952 pop ds;
953 }
954
955 dddphex(parm, sizeof(*parm), "oemhlp_parm: ");
956 dddphex(data, sizeof(*data), "oemhlp_data: ");
957
958 if (ioctl.rph.Status & STERR) {
959 return(OH_NOT_SUPPORTED);
960 }
961 return(data->bios_info.rc);
962}
963
964/******************************************************************************
965 * return vendor name for PCI vendor ID
966 */
967char *vendor_from_id(u16 id)
968{
969
970 switch(id) {
971
972 case PCI_VENDOR_ID_AL:
973 return "Ali";
974 case PCI_VENDOR_ID_AMD:
975 case PCI_VENDOR_ID_ATI:
976 return "AMD";
977 case PCI_VENDOR_ID_AT:
978 return "Allied Telesyn";
979 case PCI_VENDOR_ID_ATT:
980 return "ATT";
981 case PCI_VENDOR_ID_CMD:
982 return "CMD";
983 case PCI_VENDOR_ID_CT:
984 return "CT";
985 case PCI_VENDOR_ID_INTEL:
986 return "Intel";
987 case PCI_VENDOR_ID_INITIO:
988 return "Initio";
989 case PCI_VENDOR_ID_JMICRON:
990 return "JMicron";
991 case PCI_VENDOR_ID_MARVELL:
992 return "Marvell";
993 case PCI_VENDOR_ID_NVIDIA:
994 return "NVIDIA";
995 case PCI_VENDOR_ID_PROMISE:
996 return "PROMISE";
997 case PCI_VENDOR_ID_SI:
998 return "SiS";
999 case PCI_VENDOR_ID_VIA:
1000 return "VIA";
1001 default:
1002 break;
1003 }
1004
1005 return "Generic";
1006
1007}
1008
1009/******************************************************************************
1010 * return a device name for a PCI device id
1011 * NOTE: this is as simple as can be, so don't call it twice in one statement.
1012 */
1013char *device_from_id(u16 device)
1014{
1015 int i;
1016
1017 for (i = 0; pci_ids[i].vendor != 0; i++) {
1018
1019 if (pci_ids[i].device == device) {
1020 return pci_ids[i].chipname;
1021 }
1022
1023 }
1024
1025 return s_generic;
1026}
Note: See TracBrowser for help on using the repository browser.