1
/* cdrdao - write audio CD-Rs in disc-at-once mode
3
* Copyright (C) 1998-2001 Andreas Mueller <andreas@daneb.de>
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
36
#include "decodeSense.cc"
42
#define IOCTL_SCSI_BASE FILE_DEVICE_CONTROLLER
43
#define IOCTL_SCSI_GET_CAPABILITIES CTL_CODE(IOCTL_SCSI_BASE, 0x0404, METHOD_BUFFERED, FILE_ANY_ACCESS)
44
#define IOCTL_SCSI_PASS_THROUGH_DIRECT CTL_CODE(IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
45
#define IOCTL_SCSI_GET_ADDRESS CTL_CODE(IOCTL_SCSI_BASE, 0x0406, METHOD_BUFFERED, FILE_ANY_ACCESS)
48
#define SCSI_IOCTL_DATA_OUT 0
49
#define SCSI_IOCTL_DATA_IN 1
50
#define SCSI_IOCTL_DATA_UNSPECIFIED 2
54
typedef struct _IO_SCSI_CAPABILITIES
57
ULONG MaximumTransferLength;
58
ULONG MaximumPhysicalPages;
59
ULONG SupportedAsynchronousEvents;
61
BOOLEAN TaggedQueuing;
62
BOOLEAN AdapterScansDown;
63
BOOLEAN AdapterUsesPio;
64
} IO_SCSI_CAPABILITIES, *PIO_SCSI_CAPABILITIES;
66
typedef struct _SCSI_PASS_THROUGH_DIRECT
74
UCHAR SenseInfoLength;
76
ULONG DataTransferLength;
79
ULONG SenseInfoOffset;
81
} SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT;
84
typedef struct _SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER
86
SCSI_PASS_THROUGH_DIRECT sptd;
87
ULONG Filler; // realign buffer to double word boundary
89
} SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, *PSCSI_PASS_THROUGH_DIRECT_WITH_BUFFER;
91
typedef struct _SCSI_INQUIRY_DEVICE
97
UCHAR AddLength; // n-4
102
char ProductRevLevel[4];
103
char ProductRevDate[8];
104
} SCSI_INQUIRY_DEVICE, *PSCSI_INQUIRY_DEVICE;
107
typedef struct _SCSI_ADDRESS {
113
}SCSI_ADDRESS, *PSCSI_ADDRESS;
119
// SCSI CDB operation codes
122
#define SCSIOP_INQUIRY 0x12
123
#define SCSIOP_MODE_SELECT 0x15
124
#define SCSIOP_MODE_SENSE 0x1A
126
#define AUDIO_BLOCK_LEN 2352
127
#define BUF_SIZE (63*1024)
135
SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sb;
137
unsigned char senseBuffer_[32];
144
ScsiIf::ScsiIf(const char *dev)
146
impl_ = new ScsiIfImpl;
148
impl_->dev_ = strdup3CC("\\\\.\\", dev, NULL);
150
impl_->hCD = INVALID_HANDLE_VALUE;
159
if (impl_->hCD != INVALID_HANDLE_VALUE)
160
CloseHandle (impl_->hCD);
167
// 1: device could not be opened
176
IO_SCSI_CAPABILITIES ca;
178
while (i++ < 3 && (impl_->hCD == INVALID_HANDLE_VALUE))
180
impl_->hCD = CreateFile (impl_->dev_, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
183
if (impl_->hCD == INVALID_HANDLE_VALUE) {
187
if (DeviceIoControl (impl_->hCD, IOCTL_SCSI_GET_ADDRESS, NULL, 0, &sa, sizeof(SCSI_ADDRESS), &ol, NULL))
189
impl_->haid_ = sa.PortNumber;
190
impl_->lun_ = sa.Lun;
191
impl_->scsi_id_ = sa.TargetId;
195
CloseHandle (impl_->hCD);
196
impl_->hCD = INVALID_HANDLE_VALUE;
200
if (DeviceIoControl (impl_->hCD, IOCTL_SCSI_GET_CAPABILITIES, NULL, 0, &ca, sizeof(IO_SCSI_CAPABILITIES), &ol, NULL))
202
maxDataLen_ = ca.MaximumTransferLength;
206
CloseHandle (impl_->hCD);
207
impl_->hCD = INVALID_HANDLE_VALUE;
217
// Sets given timeout value in seconds and returns old timeout.
218
// return: old timeout
220
int ScsiIf::timeout (int t)
225
// sends a scsi command and receives data
227
// 1: scsi command failed (os level, no sense data available)
228
// 2: scsi command failed (sense data available)
230
int ScsiIf::sendCmd (unsigned char *cmd, int cmdLen,
231
unsigned char *dataOut, int dataOutLen,
232
unsigned char *dataIn, int dataInLen,
239
ZeroMemory (&impl_->sb, sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER));
241
impl_->sb.sptd.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
242
impl_->sb.sptd.PathId = 0;
243
impl_->sb.sptd.TargetId = impl_->scsi_id_;
244
impl_->sb.sptd.Lun = impl_->lun_;
245
impl_->sb.sptd.CdbLength = cmdLen;
246
impl_->sb.sptd.SenseInfoLength = 32;
247
impl_->sb.sptd.TimeOutValue = 4;
248
impl_->sb.sptd.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf);
249
memcpy (impl_->sb.sptd.Cdb, cmd, cmdLen);
251
if (dataOut && dataOutLen)
253
impl_->sb.sptd.DataIn = SCSI_IOCTL_DATA_OUT;
254
impl_->sb.sptd.DataBuffer = dataOut;
255
impl_->sb.sptd.DataTransferLength = dataOutLen;
259
impl_->sb.sptd.DataIn = SCSI_IOCTL_DATA_IN;
260
impl_->sb.sptd.DataBuffer = dataIn;
261
impl_->sb.sptd.DataTransferLength = dataInLen;
264
il = sizeof (SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER);
266
// AM: what about sense data?
267
if (DeviceIoControl (impl_->hCD, IOCTL_SCSI_PASS_THROUGH_DIRECT, &impl_->sb, il, &impl_->sb, il, &ol, NULL))
269
er = impl_->sb.sptd.ScsiStatus ? impl_->sb.sptd.ScsiStatus | 0x20000000 : 0;
280
const unsigned char *ScsiIf::getSense(int &len) const
283
return impl_->sb.ucSenseBuf;
286
void ScsiIf::printError()
288
decodeSense(impl_->sb.ucSenseBuf, 32);
291
int ScsiIf::inquiry()
293
unsigned char cmd[6];
296
SCSI_INQUIRY_DEVICE NTinqbuf;
298
ZeroMemory (&NTinqbuf, sizeof(SCSI_INQUIRY_DEVICE));
300
cmd[0] = 0x12; // INQUIRY
301
cmd[1] = cmd[2] = cmd[3] = 0;
302
cmd[4] = sizeof (NTinqbuf);
305
if (sendCmd (cmd, 6, NULL, 0,
306
(unsigned char *) &NTinqbuf, sizeof (NTinqbuf), 1) != 0) {
307
message (-2, "Inquiry command failed on '%s': ", impl_->dev_);
311
strncpy(vendor_, (char *)(NTinqbuf.VendorId), 8);
314
strncpy(product_, (char *)(NTinqbuf.ProductId), 16);
317
strncpy(revision_, (char *)(NTinqbuf.ProductRevLevel), 4);
320
for (i = 7; i >= 0 && vendor_[i] == ' '; i--)
325
for (i = 15; i >= 0 && product_[i] == ' '; i--)
330
for (i = 3; i >= 0 && revision_[i] == ' '; i--)