source: trunk/src/wnaspi32/winaspi32.cpp

Last change on this file was 8931, checked in by sandervl, 23 years ago

Fixes for cdrom drive/burner recognition

File size: 14.5 KB
Line 
1/* $Id: winaspi32.cpp,v 1.15 2002-07-28 15:38:09 sandervl Exp $ */
2/*
3 * WNASPI routines
4 *
5 * Copyright 1999 Markus Montkowski
6 * Copyright 2000 Przemyslaw Dobrowolski
7 * Copyright 2002 Sander van Leeuwen
8 *
9 * Partly based on WINE code (dlls\winaspi\winaspi32.c)
10 *
11 * Copyright 1997 Bruce Milner
12 * Copyright 1998 Andreas Mohr
13 *
14 * Project Odin Software License can be found in LICENSE.TXT
15 *
16 */
17#include <os2win.h>
18#include <stdlib.h>
19#include <string.h>
20#include <sys/types.h>
21#include <sys/stat.h>
22#include <errno.h>
23#include <fcntl.h>
24#include <memory.h>
25
26#include "aspi.h"
27#include "wnaspi32.h"
28#include "options.h"
29#include "debugtools.h"
30#include "cdio.h"
31
32#ifdef DEBUG
33#define DEBUG_BUFFER
34#endif
35
36
37#ifdef DEBUG
38//*****************************************************************************
39//*****************************************************************************
40static void ASPI_DebugPrintCmd(SRB_ExecSCSICmd *prb)
41{
42 BYTE cmd;
43 int i;
44 BYTE *cdb;
45
46 switch (prb->CDBByte[0]) {
47 case CMD_INQUIRY:
48 TRACE("{\n");
49 TRACE("\tEVPD: %d\n", prb->CDBByte[1] & 1);
50 TRACE("\tLUN: %d\n", (prb->CDBByte[1] & 0xc) >> 1);
51 TRACE("\tPAGE CODE: %d\n", prb->CDBByte[2]);
52 TRACE("\tALLOCATION LENGTH: %d\n", prb->CDBByte[4]);
53 TRACE("\tCONTROL: %d\n", prb->CDBByte[5]);
54 TRACE("}\n");
55 break;
56 case CMD_SCAN_SCAN:
57 TRACE("Transfer Length: %d\n", prb->CDBByte[4]);
58 break;
59 }
60
61 TRACE("Host Adapter: %d\n", prb->SRB_HaId);
62 TRACE("Flags: %d\n", prb->SRB_Flags);
63 if (TARGET_TO_HOST(prb)) {
64 TRACE("\tData transfer: Target to host. Length checked.\n");
65 }
66 else if (HOST_TO_TARGET(prb)) {
67 TRACE("\tData transfer: Host to target. Length checked.\n");
68 }
69 else if (NO_DATA_TRANSFERED(prb)) {
70 TRACE("\tData transfer: none\n");
71 }
72 else {
73 WARN("\tTransfer by scsi cmd. Length not checked.\n");
74 }
75
76 TRACE("\tResidual byte length reporting %s\n", prb->SRB_Flags & 0x4 ? "enabled" : "disabled");
77 TRACE("\tLinking %s\n", prb->SRB_Flags & 0x2 ? "enabled" : "disabled");
78 TRACE("\tPosting %s\n", prb->SRB_Flags & 0x1 ? "enabled" : "disabled");
79 TRACE("Target: %d\n", prb->SRB_Target);
80 TRACE("Lun: %d\n", prb->SRB_Lun);
81 TRACE("BufLen: %ld\n", prb->SRB_BufLen);
82 TRACE("SenseLen: %d\n", prb->SRB_SenseLen);
83 TRACE("BufPtr: %p\n", prb->SRB_BufPointer);
84 TRACE("CDB Length: %d\n", prb->SRB_CDBLen);
85 TRACE("POST Proc: %lx\n", (DWORD) prb->SRB_PostProc);
86 cdb = &prb->CDBByte[0];
87 cmd = prb->CDBByte[0];
88#ifdef DEBUG_BUFFER
89 dprintfNoEOL(("CDB buffer["));
90 for (i = 0; i < prb->SRB_CDBLen; i++) {
91 if (i != 0) dprintfNoEOL((",0x%02x", *cdb++));
92 else dprintfNoEOL(("0x%02x", *cdb++));
93 }
94 dprintfNoEOL(("]\n"));
95#endif
96}
97//*****************************************************************************
98//*****************************************************************************
99static void ASPI_PrintSenseArea(SRB_ExecSCSICmd *prb)
100{
101 int i;
102 BYTE *cdb;
103
104 cdb = &prb->CDBByte[0];
105 DPRINTF("SenseArea[");
106 for (i = 0; i < prb->SRB_SenseLen; i++) {
107 if (i) DPRINTF(",");
108 DPRINTF("%02x", *cdb++);
109 }
110 DPRINTF("]\n");
111}
112//*****************************************************************************
113//*****************************************************************************
114static void ASPI_DebugPrintResult(SRB_ExecSCSICmd *prb)
115{
116
117 switch (prb->CDBByte[0]) {
118 case CMD_INQUIRY:
119 TRACE("Vendor: '%s'\n", prb->SRB_BufPointer + INQUIRY_VENDOR);
120 break;
121 case CMD_TEST_UNIT_READY:
122 ASPI_PrintSenseArea(prb);
123 break;
124 }
125 dprintf(("Result code: %x", prb->SRB_Status));
126}
127#else
128#define ASPI_DebugPrintResult(a)
129#define ASPI_DebugPrintCmd(a)
130#endif
131
132//*****************************************************************************
133// Posting must be done in such a way that as soon as the SRB_Status is set
134// we don't touch the SRB anymore because it could possibly be freed
135// if the app is doing ASPI polling
136//*****************************************************************************
137static DWORD WNASPI32_DoPosting( SRB_ExecSCSICmd *lpPRB, DWORD status )
138{
139 void (* CDECL SRB_PostProc)(SRB_ExecSCSICmd *);
140 BYTE SRB_Flags = lpPRB->SRB_Flags;
141 if( status == SS_PENDING )
142 {
143 dprintf(("Tried posting SS_PENDING\n"));
144 return SS_PENDING;
145 }
146 *((DWORD *)&SRB_PostProc) = (DWORD)lpPRB->SRB_PostProc;
147
148 lpPRB->SRB_Status = status;
149 /* lpPRB is NOT safe, it could be freed in another thread */
150
151 if (SRB_PostProc)
152 {
153 if (SRB_Flags & 0x1)
154 {
155 dprintf(("Post Routine (%lx) called\n", (DWORD) SRB_PostProc));
156 /* Even though lpPRB could have been freed by
157 * the program.. that's unlikely if it planned
158 * to use it in the PostProc
159 */
160 (*SRB_PostProc)(lpPRB);
161 }
162 else if (SRB_Flags & SRB_EVENT_NOTIFY) {
163 dprintf(("Setting event %04x\n", (HANDLE)SRB_PostProc));
164 SetEvent((HANDLE)SRB_PostProc);
165 }
166 }
167 return lpPRB->SRB_Status;
168}
169//*****************************************************************************
170//*****************************************************************************
171static WORD ASPI_ExecScsiCmd(SRB_ExecSCSICmd *lpPRB)
172{
173 int status;
174 int error_code = 0;
175 LONG rc;
176 CDIO_CMD_BUFFER cdiocmd;
177
178 HCDIO hCDIO = OSLibCdIoGetDevice(lpPRB->SRB_HaId, lpPRB->SRB_Target, lpPRB->SRB_Lun);
179 if(hCDIO == -1) {
180 dprintf(("Failed: invalid device %d %d %d", lpPRB->SRB_HaId, lpPRB->SRB_Target, lpPRB->SRB_Lun));
181 ASPI_DebugPrintCmd(lpPRB);
182 return WNASPI32_DoPosting( lpPRB, SS_NO_DEVICE );
183 }
184
185 /* FIXME: hackmode */
186#define MAKE_TARGET_TO_HOST(lpPRB) \
187 if (!TARGET_TO_HOST(lpPRB)) { \
188 dprintf(("program was not sending target_to_host for cmd %x (flags=%x),correcting.\n",lpPRB->CDBByte[0],lpPRB->SRB_Flags)); \
189 lpPRB->SRB_Flags |= SRB_DIR_IN; \
190 }
191#define MAKE_HOST_TO_TARGET(lpPRB) \
192 if (!HOST_TO_TARGET(lpPRB)) { \
193 dprintf(("program was not sending host_to_target for cmd %x (flags=%x),correcting.\n",lpPRB->CDBByte[0],lpPRB->SRB_Flags)); \
194 lpPRB->SRB_Flags |= SRB_DIR_OUT; \
195 }
196 switch (lpPRB->CDBByte[0]) {
197 case 0x12: /* INQUIRY */
198 case 0x5a: /* MODE_SENSE_10 */
199 case 0xa4: /* REPORT_KEY (DVD) MMC-2 */
200 case 0xad: /* READ DVD STRUCTURE MMC-2 */
201 MAKE_TARGET_TO_HOST(lpPRB)
202 break;
203 case 0xa3: /* SEND KEY (DVD) MMC-2 */
204 MAKE_HOST_TO_TARGET(lpPRB)
205 break;
206 default:
207 if ((((lpPRB->SRB_Flags & 0x18) == 0x00) ||
208 ((lpPRB->SRB_Flags & 0x18) == 0x18)
209 ) && lpPRB->SRB_BufLen
210 ) {
211 dprintf(("command 0x%02x, no data transfer specified, but buflen is %ld!!!\n",lpPRB->CDBByte[0],lpPRB->SRB_BufLen));
212 }
213 break;
214 }
215
216 ASPI_DebugPrintCmd(lpPRB);
217
218 lpPRB->SRB_Status = SS_PENDING;
219
220 if (!lpPRB->SRB_CDBLen)
221 {
222 dprintf(("Failed: lpPRB->SRB_CDBLen = 0."));
223 return WNASPI32_DoPosting( lpPRB, SS_INVALID_SRB );
224 }
225
226 if(MAX_CDBLEN < lpPRB->SRB_CDBLen)
227 {
228 dprintf(("Failed: lpPRB->SRB_CDBLen > 64."));
229 return WNASPI32_DoPosting( lpPRB, SS_INVALID_SRB );
230 }
231
232 if(lpPRB->SRB_BufLen > 65536) // Check Max 64k!!
233 {
234 dprintf(("Failed: lpPRB->SRB_BufLen > 65536."));
235 return WNASPI32_DoPosting( lpPRB, SS_BUFFER_TO_BIG );
236 }
237
238 memset(&cdiocmd, 0, sizeof(cdiocmd));
239
240 if(lpPRB->SRB_Flags & SRB_DIR_IN) {
241 cdiocmd.flDirection |= CMDDIR_INPUT;
242 }
243 if(lpPRB->SRB_Flags & SRB_DIR_OUT) {
244 cdiocmd.flDirection |= CMDDIR_OUTPUT;
245 }
246
247 cdiocmd.cbCDB = lpPRB->SRB_CDBLen;
248 memcpy(cdiocmd.arCDB, lpPRB->CDBByte, lpPRB->SRB_CDBLen);
249
250#ifdef DEBUG_BUFFER
251 if(lpPRB->SRB_Flags & SRB_DIR_OUT) {
252 char *cdb = (char *)lpPRB->SRB_BufPointer;
253 dprintfNoEOL(("Write SRB buffer["));
254 for (int i = 0; i < lpPRB->SRB_BufLen; i++) {
255 if (i != 0) dprintfNoEOL((",0x%02x", *cdb++));
256 else dprintfNoEOL(("0x%02x", *cdb++));
257 }
258 dprintfNoEOL(("]\n"));
259 }
260#endif
261
262 lpPRB->SRB_HaStat = HASTAT_OK;
263 lpPRB->SRB_TargStat = HASTAT_OK;
264
265 if(OSLibCdIoSendCommand(hCDIO, &cdiocmd, lpPRB->SRB_BufPointer, lpPRB->SRB_BufLen) == FALSE) {
266 dprintf(("OSLibCdIoSendCommand failed!!"));
267 return WNASPI32_DoPosting( lpPRB, SS_ERR );
268 }
269
270 if(lpPRB->SRB_SenseLen) {
271 if(OSLibCdIoRequestSense(hCDIO, SENSE_BUFFER(lpPRB), lpPRB->SRB_SenseLen) == FALSE) {
272 dprintf(("OSLibCdIoRequestSense failed!!"));
273 return WNASPI32_DoPosting( lpPRB, SS_ERR );
274 }
275 }
276#ifdef DEBUG_BUFFER
277 if(lpPRB->SRB_Flags & SRB_DIR_IN) {
278 char *cdb = (char *)lpPRB->SRB_BufPointer;
279 dprintfNoEOL(("Write SRB buffer["));
280 for (int i = 0; i < lpPRB->SRB_BufLen; i++) {
281 if (i != 0) dprintfNoEOL((",0x%02x", *cdb++));
282 else dprintfNoEOL(("0x%02x", *cdb++));
283 }
284 dprintfNoEOL(("]\n"));
285 }
286#endif
287 ASPI_DebugPrintResult(lpPRB);
288 return WNASPI32_DoPosting( lpPRB, SS_COMP );
289}
290//*****************************************************************************
291// GetASPI32SupportInfo32 [WNASPI32.0]
292//
293// Checks if the ASPI subsystem is initialized correctly.
294//
295// RETURNS
296// HIWORD: 0.
297// HIBYTE of LOWORD: status (SS_COMP or SS_FAILED_INIT)
298// LOBYTE of LOWORD: # of host adapters.
299//*****************************************************************************
300DWORD CDECL GetASPI32SupportInfo()
301{
302 BYTE bNumDrv;
303 BYTE brc;
304
305 bNumDrv = 0;
306
307 // first thing we do is check whether we have a successful ASPI setup
308 if(fASPIAvailable == FALSE)
309 {
310 dprintf(("ASPI was not initialized successfully, return error"));
311 return (SS_FAILED_INIT << 8);
312 }
313
314 bNumDrv = OSLibCdIoGetNumDrives();
315 if (!bNumDrv)
316 return SS_NO_ADAPTERS << 8;
317
318 brc = SS_COMP;
319
320 //pretend there's only one controller
321 return ((brc << 8) | 1);
322}
323//*****************************************************************************
324// SendASPI32Command32 (WNASPI32.1)
325//*****************************************************************************
326DWORD CDECL SendASPI32Command(LPSRB lpSRB)
327{
328 DWORD dwRC;
329 ULONG ulParam, ulReturn;
330 BYTE bRC;
331 LONG rc;
332
333 // first thing we do is check whether we have a successful ASPI setup
334 if(fASPIAvailable == FALSE)
335 {
336 dprintf(("SendASPI32Command: ASPI was not initialized successfully, return error"));
337 return SS_NO_ASPI;
338 }
339
340 if(NULL==lpSRB)
341 return SS_INVALID_SRB; // Not sure what to return here but that is an error
342
343 dprintf(("SendASPI32Command %x %d", lpSRB, lpSRB->common.SRB_Cmd));
344
345 dwRC = SS_ERR;
346
347 switch (lpSRB->common.SRB_Cmd)
348 {
349 case SC_HA_INQUIRY:
350 lpSRB->inquiry.SRB_Status = SS_COMP; /* completed successfully */
351 lpSRB->inquiry.HA_Count = 1;
352 lpSRB->inquiry.HA_SCSI_ID = 7; /* not always ID 7 */
353 strcpy((char *)lpSRB->inquiry.HA_ManagerId, "ASPI for WIN32"); /* max 15 chars, don't change */
354 strcpy((char *)lpSRB->inquiry.HA_Identifier, "Odin host"); /* FIXME: return host adapter name */
355 memset(lpSRB->inquiry.HA_Unique, 0, 16); /* default HA_Unique content */
356 lpSRB->inquiry.HA_Unique[6] = 0x02; /* Maximum Transfer Length (128K, Byte> 4-7) */
357 lpSRB->inquiry.HA_Unique[3] = 0x08; /* Maximum number of SCSI targets */
358 dprintf(("ASPI: Partially implemented SC_HA_INQUIRY for adapter %d.\n", lpSRB->inquiry.SRB_HaId));
359
360 //OS/2 override
361 lpSRB->inquiry.HA_Unique[6] = 0x01; // transfer only 64KB
362 lpSRB->inquiry.HA_Unique[3] = 0x10; // 16 devices.
363
364 dwRC = SS_COMP;
365 break;
366
367 case SC_GET_DEV_TYPE:
368 {
369 dprintf(("SC_GET_DEV_TYPE %d %d %d", lpSRB->devtype.SRB_HaId, lpSRB->devtype.SRB_Target, lpSRB->devtype.SRB_Lun));
370
371 /* FIXME: We should return SS_NO_DEVICE if the device is not configured */
372 /* FIXME: We should return SS_INVALID_HA if HostAdapter!=0 */
373 SRB tmpsrb;
374 char inqbuf[200];
375 DWORD ret;
376
377 memset(&tmpsrb,0,sizeof(tmpsrb));
378
379 /* Copy header */
380 memcpy(&tmpsrb.common,&(lpSRB->common),sizeof(tmpsrb.common));
381
382 tmpsrb.cmd.SRB_Flags |= 8; /* target to host */
383 tmpsrb.cmd.SRB_Cmd = SC_EXEC_SCSI_CMD;
384 tmpsrb.cmd.SRB_Target = lpSRB->devtype.SRB_Target;
385 tmpsrb.cmd.SRB_Lun = lpSRB->devtype.SRB_Lun;
386 tmpsrb.cmd.SRB_BufLen = sizeof(inqbuf);
387 tmpsrb.cmd.SRB_BufPointer = (BYTE *)inqbuf;
388 tmpsrb.cmd.CDBByte[0] = 0x12; /* INQUIRY */
389 /* FIXME: handle lun */
390 tmpsrb.cmd.CDBByte[4] = sizeof(inqbuf);
391 tmpsrb.cmd.SRB_CDBLen = 6;
392
393 ret = ASPI_ExecScsiCmd(&tmpsrb.cmd);
394
395 lpSRB->devtype.SRB_Status = tmpsrb.cmd.SRB_Status;
396 lpSRB->devtype.SRB_DeviceType = inqbuf[0] & 0x1f;
397
398 TRACE("returning devicetype %d for target %d\n", inqbuf[0] & 0x1f, tmpsrb.cmd.SRB_Target);
399
400 if (ret!=SS_PENDING) /* Any error is passed down directly */
401 return ret;
402 /* FIXME: knows that the command is finished already, pass final Status */
403 return tmpsrb.cmd.SRB_Status;
404 }
405
406 case SC_EXEC_SCSI_CMD:
407 dwRC = ASPI_ExecScsiCmd(&lpSRB->cmd);
408 break;
409
410 case SC_ABORT_SRB:
411 dprintf(("SC_ABORT_SRB %d", lpSRB->abort.SRB_HaId));
412 dwRC = SS_INVALID_SRB; // We don't do async ASPI so no way to abort
413 break;
414
415 case SC_RESET_DEV:
416 {
417 HCDIO hCDIO = OSLibCdIoGetDevice(lpSRB->reset.SRB_HaId, lpSRB->reset.SRB_Target, lpSRB->reset.SRB_Lun);
418 if(hCDIO == -1) {
419 return SS_NO_DEVICE;
420 }
421 dprintf(("SC_RESET_DEV %d %d %d", lpSRB->reset.SRB_HaId, lpSRB->reset.SRB_Target, lpSRB->reset.SRB_Lun));
422 OSLibCdIoResetUnit(hCDIO);
423 dwRC = SS_COMP;
424 break;
425 }
426
427 case SC_GET_DISK_INFO:
428 /* here we have to find out the int13 / bios association.
429 * We just say we do not have any.
430 */
431 FIXME("SC_GET_DISK_INFO always return 'int13 unassociated disk'.\n");
432 lpSRB->diskinfo.SRB_DriveFlags = 0; /* disk is not int13 served */
433 return SS_COMP;
434
435 default:
436 dprintf(("Invalid command!"));
437 return SS_INVALID_SRB; // shoud be invalid command
438
439 } // end switch (lpSRB->common.SRB_Cmd)
440
441 dprintf(("SendASPI32Command %x %d done", lpSRB, lpSRB->common.SRB_Cmd));
442 return dwRC;
443}
444//*****************************************************************************
445// GetASPI32DLLVersion32 (WNASPI32.3)
446//*****************************************************************************
447DWORD CDECL GetASPI32DLLVersion()
448{
449 return (DWORD)1;
450}
451//*****************************************************************************
452//*****************************************************************************
453
454
Note: See TracBrowser for help on using the repository browser.