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

Last change on this file since 80 was 80, checked in by chris, 14 years ago

Version 1.06
============

  • Finally came across a BIOS which accesses the ICH7/8 controller via SATA registers (i.e. not AHCI mode). This required a few changes to the code at boot time because it turned out that COMRESETs are required whenever switching to/from AHCI mode to allow the AHCI or SATA controller to re-discover the attached devices:
  • 'init_reset' will now be forced on when finding a controller in non-AHCI mode at boot time.
  • A COMRESET is initiated for each implemented port after turning off AHCI mode when restoring the BIOS configuration; this is done only for Intel controllers at this point because they map the AHCI port SCR MMIO registers even when not in AHCI mode.
  • apm_suspend() has been adjusted to restore the BIOS configuration to prevent needless timeouts when the BIOS takes over during suspend or power-off operations.
  • Small changes to the functions which save/restore BIOS/port settings to avoid pitfalls; among others, the port save/restore code now also saves and restores the port's engine status.
  • Improvements to debug logging around port resets.
  • Moved code to clear pending interrupts from ahci_reset_port() to ahci_stop_port() because both need it and resetting a port involves stopping it, first.
  • NCQ mode has found to cause problems on a Dell D630. This may be related to the hard disk used for the test but since I've never seen more than one queued command regardless of the I/O load (even during simulaneous xcopy operations), NCQ mode is now off by default and needs to be turned on via the /N switch (i.e. the the /N switch now has a reversed meaning).
  • Removed the code which attempts to establish another MMIO base address in case the one assigned by the BIOS can't be reserved via resource manager; if there's a conflict, it's extremely unlikely we would ever be able to restore the BIOS MMIO address at boot time without the BIOS clashing with whatever conflicts with the MMIO address, thus there's no point trying to do any of this.
  • Implemented a reset context hook watchdog; in the early boot phase, some components apparently don't yield the CPU so the context hook will never execute without the watchdog. Now we'll give the context hook 10 seconds to execute, otherwise the watchdog will expire and we'll call the context hook directly from the corresponding timer callback.
File size: 39.5 KB
Line 
1/******************************************************************************
2 * PCI.c - PCI constants and detection code for os2ahci driver
3 *
4 * Copyright (c) 2010 Christian Mueller, Markus Thielen.
5 * Parts copied from/inspired by the LINUX ahci driver;
6 * those parts are (c) Linux AHCI/ATA maintainers
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#include "os2ahci.h"
24
25/* -------------------------- macros and constants ------------------------- */
26
27/* offset of PCI base address register (BAR) in the PCI config space */
28#define PCI_BAR(reg) (0x10 + (reg) * sizeof(u32))
29
30/* offset of MMIO base address register (BAR) for AHCI adapters */
31#define AHCI_MMIO PCI_BAR(AHCI_PCI_BAR)
32
33/******************************************************************************
34 * OEMHLP constants for PCI access
35 */
36#define GENERIC_IOCTL 0x10
37#define OH_CATEGORY 0x00
38#define OH_FUNC_PCI 0x0b
39
40/* subfunctions */
41#define OH_BIOS_INFO 0x00
42#define OH_FIND_DEVICE 0x01
43#define OH_FIND_CLASS 0x02
44#define OH_READ_CONFIG 0x03
45#define OH_WRITE_CONFIG 0x04
46
47/* return codes */
48#define OH_SUCCESS 0x00
49#define OH_NOT_SUPPORTED 0x81
50#define OH_BAD_VENDOR 0x83
51#define OH_NOT_FOUND 0x86
52#define OH_BAD_REGISTER 0x87
53
54/* ------------------------ typedefs and structures ------------------------ */
55
56/******************************************************************************
57 * OEMHLP IOCtl parameter union. The parameter area is generally used as input
58 * to the OEMHLP IOCtl calls.
59 */
60typedef union {
61
62 /* query PCI BIOS information" */
63 struct {
64 UCHAR subfunction;
65 } bios_info;
66
67 /* find PCI device */
68 struct {
69 UCHAR subfunction;
70 USHORT device;
71 USHORT vendor;
72 UCHAR index;
73 } find_device;
74
75 /* find PCI class code */
76 struct {
77 UCHAR subfunction;
78 ULONG class;
79 UCHAR index;
80 } find_class;
81
82 /* read PCI configuration space */
83 struct {
84 UCHAR subfunction;
85 UCHAR bus;
86 UCHAR dev_func;
87 UCHAR reg;
88 UCHAR size;
89 } read_config;
90
91 /* write PCI configuration space */
92 struct {
93 UCHAR subfunction;
94 UCHAR bus;
95 UCHAR dev_func;
96 UCHAR reg;
97 UCHAR size;
98 ULONG data;
99 } write_config;
100
101} OH_PARM;
102
103/******************************************************************************
104 * OEMHLP IOCtl data union. The data area is generally used as output from the
105 * OEMHLP IOCtl calls.
106 */
107typedef union {
108
109 /* query PCI BIOS information" */
110 struct {
111 UCHAR rc;
112 UCHAR hw_mech;
113 UCHAR major_version;
114 UCHAR minor_version;
115 UCHAR last_bus;
116 } bios_info;
117
118 /* find PCI device */
119 struct {
120 UCHAR rc;
121 UCHAR bus;
122 UCHAR dev_func;
123 } find_device;
124
125 /* find PCI class code */
126 struct {
127 UCHAR rc;
128 UCHAR bus;
129 UCHAR dev_func;
130 } find_class;
131
132 /* read PCI confguration space */
133 struct {
134 UCHAR rc;
135 ULONG data;
136 } read_config;
137
138 /* write PCI confguration space */
139 struct {
140 UCHAR rc;
141 } write_config;
142
143} OH_DATA;
144
145/* -------------------------- function prototypes -------------------------- */
146
147static void add_pci_device (PCI_ID *pci_id, OH_DATA _far *data);
148static UCHAR pci_read_conf (UCHAR bus, UCHAR dev_func, UCHAR indx,
149 UCHAR size, ULONG _far *val);
150static UCHAR pci_write_conf (UCHAR bus, UCHAR dev_func, UCHAR indx, UCHAR size,
151 ULONG val);
152static int oemhlp_call (UCHAR subfunction, OH_PARM _far *parm,
153 OH_DATA _far *data);
154
155/* ------------------------ global/static variables ------------------------ */
156
157/******************************************************************************
158 * chipset/controller name strings
159 */
160static char chip_esb2[] = "ESB2";
161static char chip_ich8[] = "ICH8";
162static char chip_ich8m[] = "ICH8M";
163static char chip_ich9[] = "ICH9";
164static char chip_ich9m[] = "ICH9M";
165static char chip_ich10[] = "ICH10";
166static char chip_pchahci[] = "PCH AHCI";
167static char chip_pchraid[] = "PCH RAID";
168static char chip_tolapai[] = "Tolapai";
169static char chip_sb600[] = "SB600";
170static char chip_sb700[] = "SB700/800";
171static char chip_vt8251[] = "VT8251";
172static char chip_mcp65[] = "MCP65";
173static char chip_mcp67[] = "MCP67";
174static char chip_mcp73[] = "MCP73";
175static char chip_mcp77[] = "MCP77";
176static char chip_mcp79[] = "MCP79";
177static char chip_mcp89[] = "MCP689";
178static char chip_sis968[] = "968";
179
180static char s_generic[] = "Generic";
181
182/******************************************************************************
183 * other strings
184 */
185static char s_already_claimed[] = "Warning: device already claimed by another driver.\n";
186
187
188
189/******************************************************************************
190 * PCI vendor and device IDs for known AHCI adapters. Copied from the Linux
191 * AHCI driver.
192 */
193
194PCI_ID pci_ids[] = {
195
196 /* Intel
197 * NOTE: ICH5 controller does NOT support AHCI, so we do
198 * not add it here! */
199 { PCI_VDEVICE(INTEL, 0x2652), board_ahci, "ICH6" }, /* ICH6 */
200 { PCI_VDEVICE(INTEL, 0x2653), board_ahci, "ICH6M" }, /* ICH6M */
201 { PCI_VDEVICE(INTEL, 0x27c1), board_ahci, "ICH7" }, /* ICH7 */
202 { PCI_VDEVICE(INTEL, 0x27c5), board_ahci, "ICH7M" }, /* ICH7M */
203 { PCI_VDEVICE(INTEL, 0x27c3), board_ahci, "ICH7R" }, /* ICH7R */
204 { PCI_VDEVICE(AL, 0x5288), board_ahci_ign_iferr, "ULiM5288" }, /* ULi M5288 */
205 { PCI_VDEVICE(INTEL, 0x2681), board_ahci, chip_esb2 }, /* ESB2 */
206 { PCI_VDEVICE(INTEL, 0x2682), board_ahci, chip_esb2 }, /* ESB2 */
207 { PCI_VDEVICE(INTEL, 0x2683), board_ahci, chip_esb2 }, /* ESB2 */
208 { PCI_VDEVICE(INTEL, 0x27c6), board_ahci, "ICH7MDH" }, /* ICH7-M DH */
209 { PCI_VDEVICE(INTEL, 0x2821), board_ahci, chip_ich8 }, /* ICH8 */
210 { PCI_VDEVICE(INTEL, 0x2822), board_ahci_nosntf, chip_ich8 }, /* ICH8 */
211 { PCI_VDEVICE(INTEL, 0x2824), board_ahci, chip_ich8 }, /* ICH8 */
212 { PCI_VDEVICE(INTEL, 0x2829), board_ahci, chip_ich8m }, /* ICH8M */
213 { PCI_VDEVICE(INTEL, 0x282a), board_ahci, chip_ich8m }, /* ICH8M */
214 { PCI_VDEVICE(INTEL, 0x2922), board_ahci, chip_ich9 }, /* ICH9 */
215 { PCI_VDEVICE(INTEL, 0x2923), board_ahci, chip_ich9 }, /* ICH9 */
216 { PCI_VDEVICE(INTEL, 0x2924), board_ahci, chip_ich9 }, /* ICH9 */
217 { PCI_VDEVICE(INTEL, 0x2925), board_ahci, chip_ich9 }, /* ICH9 */
218 { PCI_VDEVICE(INTEL, 0x2927), board_ahci, chip_ich9 }, /* ICH9 */
219 { PCI_VDEVICE(INTEL, 0x2929), board_ahci, chip_ich9m }, /* ICH9M */
220 { PCI_VDEVICE(INTEL, 0x292a), board_ahci, chip_ich9m }, /* ICH9M */
221 { PCI_VDEVICE(INTEL, 0x292b), board_ahci, chip_ich9m }, /* ICH9M */
222 { PCI_VDEVICE(INTEL, 0x292c), board_ahci, chip_ich9m }, /* ICH9M */
223 { PCI_VDEVICE(INTEL, 0x292f), board_ahci, chip_ich9m }, /* ICH9M */
224 { PCI_VDEVICE(INTEL, 0x294d), board_ahci, chip_ich9 }, /* ICH9 */
225 { PCI_VDEVICE(INTEL, 0x294e), board_ahci, chip_ich9m }, /* ICH9M */
226 { PCI_VDEVICE(INTEL, 0x502a), board_ahci, chip_tolapai }, /* Tolapai */
227 { PCI_VDEVICE(INTEL, 0x502b), board_ahci, chip_tolapai }, /* Tolapai */
228 { PCI_VDEVICE(INTEL, 0x3a05), board_ahci, chip_ich10 }, /* ICH10 */
229 { PCI_VDEVICE(INTEL, 0x3a22), board_ahci, chip_ich10 }, /* ICH10 */
230 { PCI_VDEVICE(INTEL, 0x3a25), board_ahci, chip_ich10 }, /* ICH10 */
231 { PCI_VDEVICE(INTEL, 0x3b22), board_ahci, chip_pchahci }, /* PCH AHCI */
232 { PCI_VDEVICE(INTEL, 0x3b23), board_ahci, chip_pchahci }, /* PCH AHCI */
233 { PCI_VDEVICE(INTEL, 0x3b24), board_ahci, chip_pchraid }, /* PCH RAID */
234 { PCI_VDEVICE(INTEL, 0x3b25), board_ahci, chip_pchraid }, /* PCH RAID */
235 { PCI_VDEVICE(INTEL, 0x3b29), board_ahci, chip_pchahci }, /* PCH AHCI */
236 { PCI_VDEVICE(INTEL, 0x3b2b), board_ahci, chip_pchraid }, /* PCH RAID */
237 { PCI_VDEVICE(INTEL, 0x3b2c), board_ahci, chip_pchraid }, /* PCH RAID */
238 { PCI_VDEVICE(INTEL, 0x3b2f), board_ahci, chip_pchahci }, /* PCH AHCI */
239
240 /* JMicron 360/1/3/5/6, match class to avoid IDE function */
241 { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
242 PCI_CLASS_STORAGE_SATA_AHCI, 0xffffffL, board_ahci_ign_iferr, "360" },
243
244 /* ATI */
245 { PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600, chip_sb600 }, /* ATI SB600 */
246 { PCI_VDEVICE(ATI, 0x4390), board_ahci_sb700, chip_sb700 }, /* ATI SB700/800 */
247 { PCI_VDEVICE(ATI, 0x4391), board_ahci_sb700, chip_sb700 }, /* ATI SB700/800 */
248 { PCI_VDEVICE(ATI, 0x4392), board_ahci_sb700, chip_sb700 }, /* ATI SB700/800 */
249 { PCI_VDEVICE(ATI, 0x4393), board_ahci_sb700, chip_sb700 }, /* ATI SB700/800 */
250 { PCI_VDEVICE(ATI, 0x4394), board_ahci_sb700, chip_sb700 }, /* ATI SB700/800 */
251 { PCI_VDEVICE(ATI, 0x4395), board_ahci_sb700, chip_sb700 }, /* ATI SB700/800 */
252
253 /* AMD */
254 { PCI_VDEVICE(AMD, 0x7800), board_ahci }, /* AMD Hudson-2 */
255 /* AMD is using RAID class only for ahci controllers */
256 { PCI_VENDOR_ID_AMD, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
257 PCI_CLASS_STORAGE_RAID << 8, 0xffffffL, board_ahci, "Hudson2" },
258
259 /* VIA */
260 { PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251, chip_vt8251 }, /* VIA VT8251 */
261 { PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251, chip_vt8251 }, /* VIA VT8251 */
262
263 /* NVIDIA */
264 { PCI_VDEVICE(NVIDIA, 0x044c), board_ahci_mcp65, chip_mcp65 }, /* MCP65 */
265 { PCI_VDEVICE(NVIDIA, 0x044d), board_ahci_mcp65, chip_mcp65 }, /* MCP65 */
266 { PCI_VDEVICE(NVIDIA, 0x044e), board_ahci_mcp65, chip_mcp65 }, /* MCP65 */
267 { PCI_VDEVICE(NVIDIA, 0x044f), board_ahci_mcp65, chip_mcp65 }, /* MCP65 */
268 { PCI_VDEVICE(NVIDIA, 0x045c), board_ahci_mcp65, chip_mcp65 }, /* MCP65 */
269 { PCI_VDEVICE(NVIDIA, 0x045d), board_ahci_mcp65, chip_mcp65 }, /* MCP65 */
270 { PCI_VDEVICE(NVIDIA, 0x045e), board_ahci_mcp65, chip_mcp65 }, /* MCP65 */
271 { PCI_VDEVICE(NVIDIA, 0x045f), board_ahci_mcp65, chip_mcp65 }, /* MCP65 */
272 { PCI_VDEVICE(NVIDIA, 0x0550), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
273 { PCI_VDEVICE(NVIDIA, 0x0551), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
274 { PCI_VDEVICE(NVIDIA, 0x0552), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
275 { PCI_VDEVICE(NVIDIA, 0x0553), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
276 { PCI_VDEVICE(NVIDIA, 0x0554), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
277 { PCI_VDEVICE(NVIDIA, 0x0555), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
278 { PCI_VDEVICE(NVIDIA, 0x0556), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
279 { PCI_VDEVICE(NVIDIA, 0x0557), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
280 { PCI_VDEVICE(NVIDIA, 0x0558), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
281 { PCI_VDEVICE(NVIDIA, 0x0559), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
282 { PCI_VDEVICE(NVIDIA, 0x055a), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
283 { PCI_VDEVICE(NVIDIA, 0x055b), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
284 { PCI_VDEVICE(NVIDIA, 0x0580), board_ahci_yesncq, chip_mcp67 }, /* Linux ID */
285 { PCI_VDEVICE(NVIDIA, 0x07f0), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
286 { PCI_VDEVICE(NVIDIA, 0x07f1), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
287 { PCI_VDEVICE(NVIDIA, 0x07f2), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
288 { PCI_VDEVICE(NVIDIA, 0x07f3), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
289 { PCI_VDEVICE(NVIDIA, 0x07f4), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
290 { PCI_VDEVICE(NVIDIA, 0x07f5), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
291 { PCI_VDEVICE(NVIDIA, 0x07f6), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
292 { PCI_VDEVICE(NVIDIA, 0x07f7), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
293 { PCI_VDEVICE(NVIDIA, 0x07f8), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
294 { PCI_VDEVICE(NVIDIA, 0x07f9), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
295 { PCI_VDEVICE(NVIDIA, 0x07fa), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
296 { PCI_VDEVICE(NVIDIA, 0x07fb), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
297 { PCI_VDEVICE(NVIDIA, 0x0ad0), board_ahci, chip_mcp77 }, /* MCP77 */
298 { PCI_VDEVICE(NVIDIA, 0x0ad1), board_ahci, chip_mcp77 }, /* MCP77 */
299 { PCI_VDEVICE(NVIDIA, 0x0ad2), board_ahci, chip_mcp77 }, /* MCP77 */
300 { PCI_VDEVICE(NVIDIA, 0x0ad3), board_ahci, chip_mcp77 }, /* MCP77 */
301 { PCI_VDEVICE(NVIDIA, 0x0ad4), board_ahci, chip_mcp77 }, /* MCP77 */
302 { PCI_VDEVICE(NVIDIA, 0x0ad5), board_ahci, chip_mcp77 }, /* MCP77 */
303 { PCI_VDEVICE(NVIDIA, 0x0ad6), board_ahci, chip_mcp77 }, /* MCP77 */
304 { PCI_VDEVICE(NVIDIA, 0x0ad7), board_ahci, chip_mcp77 }, /* MCP77 */
305 { PCI_VDEVICE(NVIDIA, 0x0ad8), board_ahci, chip_mcp77 }, /* MCP77 */
306 { PCI_VDEVICE(NVIDIA, 0x0ad9), board_ahci, chip_mcp77 }, /* MCP77 */
307 { PCI_VDEVICE(NVIDIA, 0x0ada), board_ahci, chip_mcp77 }, /* MCP77 */
308 { PCI_VDEVICE(NVIDIA, 0x0adb), board_ahci, chip_mcp77 }, /* MCP77 */
309 { PCI_VDEVICE(NVIDIA, 0x0ab4), board_ahci, chip_mcp79 }, /* MCP79 */
310 { PCI_VDEVICE(NVIDIA, 0x0ab5), board_ahci, chip_mcp79 }, /* MCP79 */
311 { PCI_VDEVICE(NVIDIA, 0x0ab6), board_ahci, chip_mcp79 }, /* MCP79 */
312 { PCI_VDEVICE(NVIDIA, 0x0ab7), board_ahci, chip_mcp79 }, /* MCP79 */
313 { PCI_VDEVICE(NVIDIA, 0x0ab8), board_ahci, chip_mcp79 }, /* MCP79 */
314 { PCI_VDEVICE(NVIDIA, 0x0ab9), board_ahci, chip_mcp79 }, /* MCP79 */
315 { PCI_VDEVICE(NVIDIA, 0x0aba), board_ahci, chip_mcp79 }, /* MCP79 */
316 { PCI_VDEVICE(NVIDIA, 0x0abb), board_ahci, chip_mcp79 }, /* MCP79 */
317 { PCI_VDEVICE(NVIDIA, 0x0abc), board_ahci, chip_mcp79 }, /* MCP79 */
318 { PCI_VDEVICE(NVIDIA, 0x0abd), board_ahci, chip_mcp79 }, /* MCP79 */
319 { PCI_VDEVICE(NVIDIA, 0x0abe), board_ahci, chip_mcp79 }, /* MCP79 */
320 { PCI_VDEVICE(NVIDIA, 0x0abf), board_ahci, chip_mcp79 }, /* MCP79 */
321 { PCI_VDEVICE(NVIDIA, 0x0d84), board_ahci, chip_mcp89 }, /* MCP89 */
322 { PCI_VDEVICE(NVIDIA, 0x0d85), board_ahci, chip_mcp89 }, /* MCP89 */
323 { PCI_VDEVICE(NVIDIA, 0x0d86), board_ahci, chip_mcp89 }, /* MCP89 */
324 { PCI_VDEVICE(NVIDIA, 0x0d87), board_ahci, chip_mcp89 }, /* MCP89 */
325 { PCI_VDEVICE(NVIDIA, 0x0d88), board_ahci, chip_mcp89 }, /* MCP89 */
326 { PCI_VDEVICE(NVIDIA, 0x0d89), board_ahci, chip_mcp89 }, /* MCP89 */
327 { PCI_VDEVICE(NVIDIA, 0x0d8a), board_ahci, chip_mcp89 }, /* MCP89 */
328 { PCI_VDEVICE(NVIDIA, 0x0d8b), board_ahci, chip_mcp89 }, /* MCP89 */
329 { PCI_VDEVICE(NVIDIA, 0x0d8c), board_ahci, chip_mcp89 }, /* MCP89 */
330 { PCI_VDEVICE(NVIDIA, 0x0d8d), board_ahci, chip_mcp89 }, /* MCP89 */
331 { PCI_VDEVICE(NVIDIA, 0x0d8e), board_ahci, chip_mcp89 }, /* MCP89 */
332 { PCI_VDEVICE(NVIDIA, 0x0d8f), board_ahci, chip_mcp89 }, /* MCP89 */
333
334 /* SiS */
335 { PCI_VDEVICE(SI, 0x1184), board_ahci, "966" }, /* SiS 966 */
336 { PCI_VDEVICE(SI, 0x1185), board_ahci, chip_sis968 }, /* SiS 968 */
337 { PCI_VDEVICE(SI, 0x0186), board_ahci, chip_sis968 }, /* SiS 968 */
338
339 /* Marvell */
340 { PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv, "6145" }, /* 6145 */
341 { PCI_VDEVICE(MARVELL, 0x6121), board_ahci_mv, "6121" }, /* 6121 */
342
343 /* Promise */
344 { PCI_VDEVICE(PROMISE, 0x3f20), board_ahci, "PDC42819" }, /* PDC42819 */
345
346 /* Generic, PCI class code for AHCI */
347 { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
348 PCI_CLASS_STORAGE_SATA_AHCI, 0xffffffL, board_ahci, s_generic },
349
350 /* end of list, including a few slots to define custom adapters (10) */
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 { 0, 0, 0, 0, 0, 0, 0, NULL },
356 { 0, 0, 0, 0, 0, 0, 0, NULL },
357 { 0, 0, 0, 0, 0, 0, 0, NULL },
358 { 0, 0, 0, 0, 0, 0, 0, NULL },
359 { 0, 0, 0, 0, 0, 0, 0, NULL },
360 { 0, 0, 0, 0, 0, 0, 0, NULL },
361
362 { 0, 0, 0, 0, 0, 0, 0, NULL }
363};
364
365/******************************************************************************
366 * OEMHLP$ is used by OS/2 to provide access to OEM-specific machine resources
367 * like PCI BIOS access. We're using this to enumerate the PCI bus. Due to
368 * BIOS bugs, it may be necessary to use I/O operations for this purpose but
369 * so far I think this is only relevant for rather old PCs and SATA is not
370 * expected to be a priority on those machines.
371 */
372static IDCTABLE oemhlp; /* OEMHLP$ IDC entry point */
373
374/* ----------------------------- start of code ----------------------------- */
375
376/******************************************************************************
377 * Add specified PCI vendor and device ID to the list of supported AHCI
378 * controllers. Please note that the last slot in pci_ids needs to remain
379 * empty because it's used as end marker.
380 */
381int add_pci_id(u16 vendor, u16 device)
382{
383 int max_slot = sizeof(pci_ids) / sizeof(*pci_ids) - 2;
384 int i;
385
386 /* search for last used slot in 'pci_ids' */
387 for (i = max_slot; i >= 0 && pci_ids[i].vendor == 0; i--);
388 if (i >= max_slot) {
389 /* all slots in use */
390 return(-1);
391 }
392
393 /* use slot after the last used slot */
394 i++;
395 pci_ids[i].vendor = vendor;
396 pci_ids[i].device = device;
397 pci_ids[i].board = board_ahci;
398 pci_ids[i].chipname = s_generic;
399 return(0);
400}
401
402/******************************************************************************
403 * Scan PCI bus using OEMHLP$ IOCTLs and build adapter list.
404 */
405void scan_pci_bus(void)
406{
407 OH_PARM parm;
408 OH_DATA data;
409 UCHAR index;
410 UCHAR rc;
411 int ad_indx = 0;
412 int i;
413 int n;
414
415 ddprintf("scanning PCI bus...\n");
416
417 /* verify that we have a PCI system */
418 memset(&parm, 0x00, sizeof(parm));
419 if (oemhlp_call(OH_BIOS_INFO, &parm, &data) != OH_SUCCESS) {
420 cprintf("couldn't get PCI BIOS information\n");
421 return;
422 }
423
424 /* Go through the list of PCI IDs and search for each device
425 *
426 * NOTES:
427 *
428 * - When searching via class code, the OEMHLP$ interface doesn't allow
429 * setting a bitmask to look for individual portions of class code,
430 * subclass code and programming interface. However, all bitmasks in the
431 * PCI list currently use 0xffffff, thus this should not be a problem at
432 * this point in time.
433 *
434 * - Scanning via OEMHLP$ seems rather slow, at least in the virtual
435 * machine I'm currenly using to test this driver. Thus, class code
436 * scans are preferred unless the option "-t" (thorough_scan) has been
437 * specified. The assumption is that most, if not all, modern AHCI
438 * adapters have the correct class code (PCI_CLASS_STORAGE_SATA_AHCI).
439 */
440 for (i = 0; pci_ids[i].vendor != 0; i++) {
441 index = 0;
442 do {
443 if (pci_ids[i].device == PCI_ANY_ID || pci_ids[i].vendor == PCI_ANY_ID) {
444 /* look for class code */
445 memset(&parm, 0x00, sizeof(parm));
446 parm.find_class.class = pci_ids[i].class;
447 parm.find_class.index = index;
448 rc = oemhlp_call(OH_FIND_CLASS, &parm, &data);
449
450 } else if (thorough_scan) {
451 /* look for this specific vendor and device ID */
452 memset(&parm, 0x00, sizeof(parm));
453 parm.find_device.device = pci_ids[i].device;
454 parm.find_device.vendor = pci_ids[i].vendor;
455 parm.find_device.index = index;
456 rc = oemhlp_call(OH_FIND_DEVICE, &parm, &data);
457
458 } else {
459 rc = OH_NOT_FOUND;
460 }
461
462 if (rc == OH_SUCCESS) {
463 /* found a device */
464 int already_found = 0;
465
466 /* increment index for next loop */
467 if (++index > 180) {
468 /* something's wrong here... */
469 return;
470 }
471
472 /* check whether we already found this device */
473 for (n = 0; n < ad_info_cnt; n++) {
474 if (ad_infos[n].bus == data.find_device.bus &&
475 ad_infos[n].dev_func == data.find_device.dev_func) {
476 /* this device has already been found (e.g. via thorough scan) */
477 already_found = 1;
478 break;
479 }
480 }
481
482 if (already_found || (ad_ignore & (1U << ad_indx++))) {
483 /* ignore this device; it has either already been found via a
484 * thorough scan or has been specified to be ignored via command
485 * line option */
486 continue;
487 }
488
489 /* add this PCI device to ad_infos[] */
490 add_pci_device(pci_ids + i, &data);
491 }
492
493 } while (rc == OH_SUCCESS);
494 }
495}
496
497/******************************************************************************
498 * Enable interrupt generation. PCI 2.3 added a bit which allows disabling
499 * interrupt generation for a device. This function clears the corresponding
500 * bit in the configuration space command register.
501 */
502int pci_enable_int(UCHAR bus, UCHAR dev_func)
503{
504 ULONG tmp;
505
506 if (pci_read_conf (bus, dev_func, 4, sizeof(u32), &tmp) != OH_SUCCESS ||
507 pci_write_conf(bus, dev_func, 4, sizeof(u32), tmp & ~(1UL << 10)) != OH_SUCCESS) {
508 return(-1);
509 }
510 return(0);
511}
512
513/******************************************************************************
514 * Hack to set up proper IRQ mappings in the emulated PIIX3 ISA bridge in
515 * VirtualBox (for some reason, the first mapped IRQ is 0x80 without this
516 * hack).
517 */
518void pci_hack_virtualbox(void)
519{
520 ULONG irq = 0;
521
522 if (pci_read_conf(0, 0x08, 0x60, 1, &irq) == OH_SUCCESS && irq == 0x80) {
523 /* set IRQ for first device/func to 11 */
524 dprintf("hacking virtualbox PIIX3 PCI to ISA bridge IRQ mapping\n");
525 irq = ad_infos[0].irq;
526 pci_write_conf(0, 0x08, 0x60, 1, irq);
527 }
528}
529
530/******************************************************************************
531 * Add a single PCI device to the list of adapters.
532 */
533static void add_pci_device(PCI_ID *pci_id, OH_DATA _far *data)
534{
535 char rc_list_buf[sizeof(AHRESOURCE) + sizeof(HRESOURCE) * 4];
536 AHRESOURCE _far *rc_list = (AHRESOURCE _far *) rc_list_buf;
537 RESOURCESTRUCT resource;
538 ADAPTERSTRUCT adapter;
539 ADJUNCT adj;
540 AD_INFO *ad_info;
541 APIRET ret;
542 UCHAR bus = data->find_class.bus;
543 UCHAR dev_func = data->find_class.dev_func;
544 ULONG val;
545 SEL gdt[PORT_DMA_BUF_SEGS + 1];
546 char tmp[40];
547 u16 device;
548 u16 vendor;
549 u32 class;
550 u32 mmio_bios = 0;
551 u32 mmio_size;
552 u32 mmio_rqd;
553 int irq;
554 int pin;
555 int i;
556
557 /*****************************************************************************
558 * Part 1: Get further information about the device to be added; PCI ID...
559 */
560 if (pci_read_conf(bus, dev_func, 0x00, sizeof(ULONG), &val) != OH_SUCCESS) {
561 return;
562 }
563 device = (u16) (val >> 16);
564 vendor = (u16) (val & 0xffff);
565
566 /* ... and class code */
567 if (pci_read_conf(bus, dev_func, 0x08, sizeof(ULONG), &val) != OH_SUCCESS) {
568 return;
569 }
570 class = (u32) (val >> 8);
571
572 if (pci_id->device == PCI_ANY_ID) {
573 /* We found this device in a wildcard search. There are two possible
574 * reasons which require a different handling:
575 *
576 * 1) This device uses a non-standard PCI class and has been identified
577 * with the corresponding class in pci_ids[] (e.g. the entry
578 * PCI_VENDOR_ID_JMICRON), but there is a vendor ID in pci_ids[]. In
579 * this case, we need to verify that the vendor is correct (see
580 * comments regarding OEMHLP limitations in 'scan_pci_bus()')
581 *
582 * 2) This device was identified using a generic PCI class for AHCI
583 * adapters such as PCI_CLASS_STORAGE_SATA_AHCI and we need to map
584 * the device and vendor ID to the corresponding index in pci_ids[]
585 * if there is such an entry; the index passed to this function will
586 * be the generic class-based index which is fine as long as there's
587 * not special treatment required as indicated by the board_*
588 * constants in pci_ids[]...
589 *
590 * The main reason for this kludge is that it seems as if OEMHLP$
591 * is rather slow searching for PCI devices, adding around 30s
592 * to the boot time when scanning for individual AHCI PCI IDs. Thus,
593 * the OS2AHCI driver avoids this kind of scan in favor of a class-
594 * based scan (unless overridden with the "/T" option).
595 */
596 if (pci_id->vendor != PCI_ANY_ID) {
597 /* case 1: the vendor is known but we found the PCI device using a class
598 * search; verify vendor matches the one in pci_ids[]
599 */
600 if (pci_id->vendor != vendor) {
601 /* vendor doesn't match */
602 return;
603 }
604
605 } else {
606 /* case 2: we found this device using a generic class search; if the
607 * device/vendor is listed in pci_ids[], use this entry in favor of the
608 * one passed in 'pci_id'
609 */
610 for (i = 0; pci_ids[i].vendor != 0; i++) {
611 if (pci_ids[i].device == device && pci_ids[i].vendor == vendor) {
612 pci_id = pci_ids + i;
613 break;
614 }
615 }
616 }
617 }
618
619 /* found a supported AHCI device */
620 cprintf("found AHCI device: %s %s (%04x:%04x)\n"
621 " class:0x%06lx bus:%d devfunc:0x%02x\n",
622 vendor_from_id(vendor), device_from_id(device),
623 vendor, device,
624 class, bus, dev_func);
625
626 /* make sure we got room in the adapter information array */
627 if (ad_info_cnt >= MAX_AD - 1) {
628 cprintf("error: too many AHCI devices\n");
629 return;
630 }
631
632 /****************************************************************************
633 * Part 2: Determine resource requirements and allocate resources with the
634 * OS/2 resource manager. While doing so, some of the entries of the
635 * corresponding slot in the AD_INFO array, namely resource manager
636 * handles, are initialized so we need prepare the slot.
637 *
638 * NOTE: While registering resources with the resource manager, each new
639 * resource is added to the corresponding rc_list.hResource[] slot.
640 * rc_list is used further down to associate resources to adapters
641 * when the adapter itself is registered with the OS/2 resource
642 * manager.
643 */
644 ad_info = ad_infos + ad_info_cnt;
645 memset(ad_info, 0x00, sizeof(*ad_info));
646 rc_list->NumResource = 0;
647
648 /* Register IRQ with resource manager
649 *
650 * NOTE: We rely on the IRQ number saved in the PCI config space by the PCI
651 * BIOS. There's no reliable way to find out the IRQ number in any
652 * other way unless we start using message-driven interrupts (which
653 * is out of scope for the time being).
654 */
655 if (pci_read_conf(bus, dev_func, 0x3c, sizeof(u32), &val) != OH_SUCCESS) {
656 return;
657 }
658 irq = (int) (val & 0xff);
659 pin = (int) ((val >> 8) & 0xff);
660
661 memset(&resource, 0x00, sizeof(resource));
662 resource.ResourceType = RS_TYPE_IRQ;
663 resource.IRQResource.IRQLevel = irq;
664 resource.IRQResource.PCIIrqPin = pin;
665 resource.IRQResource.IRQFlags = RS_IRQ_SHARED;
666
667 ret = RMAllocResource(rm_drvh, &ad_info->rm_irq, &resource);
668 switch (ret) {
669 case RMRC_SUCCESS:
670 break;
671 case RMRC_DEV_ALREADY_CLAIMED:
672 case RMRC_RES_ALREADY_CLAIMED:
673 cprintf(s_already_claimed);
674 return;
675 default:
676 cprintf("error: couldn't register IRQ %d (rc = %d)\n", irq, ret);
677 return;
678 }
679 rc_list->hResource[rc_list->NumResource++] = ad_info->rm_irq;
680
681 /* Determine MMIO size for this device
682 *
683 * NOTE: In order to do this, we need to temporarily write 0xffffffff to
684 * the MMIO base address register (BAR), read back the resulting value
685 * and check the 0 bits from the right end. After doing this, we must
686 * restore the original value set up by the BIOS.
687 *
688 * The least significant 4 bits are not relevant for the MMIO address, thus
689 * we'll start at 0x10:
690 *
691 * 31 4 3 2 1 0
692 * -------------------------------------------------------------------
693 * base address P T T I
694 * P = prefetchable
695 * T = type
696 * I = I/O (1) or memory (0)
697 */
698 if (pci_read_conf (bus, dev_func, AHCI_MMIO, sizeof(u32), &mmio_bios) != OH_SUCCESS ||
699 pci_write_conf(bus, dev_func, AHCI_MMIO, sizeof(u32), ~(0UL)) != OH_SUCCESS ||
700 pci_read_conf (bus, dev_func, AHCI_MMIO, sizeof(u32), &mmio_rqd) != OH_SUCCESS ||
701 pci_write_conf(bus, dev_func, AHCI_MMIO, sizeof(u32), mmio_bios) != OH_SUCCESS) {
702
703 cprintf("error: couldn't determine MMIO size\n");
704 if (mmio_bios != 0) {
705 cprintf("restoring BIOS MMIO address\n");
706 pci_write_conf(bus, dev_func, AHCI_MMIO, sizeof(u32), mmio_bios);
707 }
708 return;
709 }
710 for (mmio_size = 0x00000010UL;
711 mmio_size < 0x10000000UL && (mmio_rqd & mmio_size) == 0;
712 mmio_size <<= 1);
713
714 ddprintf("MMIO size = %ld\n", mmio_size);
715 ddprintf("MMIO address = 0x%08lx\n", mmio_bios & 0xfffffff0UL);
716
717 /* register BIOS MMIO address space with resource manager */
718 memset(&resource, 0x00, sizeof(resource));
719 resource.ResourceType = RS_TYPE_MEM;
720 resource.MEMResource.MemBase = mmio_bios & 0xfffffff0UL;
721 resource.MEMResource.MemSize = mmio_size;
722 resource.MEMResource.MemFlags = RS_MEM_EXCLUSIVE;
723
724 ret = RMAllocResource(rm_drvh, &ad_info->rm_mmio, &resource);
725 if (ret != RMRC_SUCCESS) {
726 if (ret == RMRC_RES_ALREADY_CLAIMED) {
727 cprintf(s_already_claimed);
728 } else {
729 cprintf("error: couldn't register MMIO region (rc = %d)\n", ret);
730 }
731 return;
732 }
733 rc_list->hResource[rc_list->NumResource++] = ad_info->rm_mmio;
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.