~ubuntu-branches/ubuntu/utopic/cdrdao/utopic

« back to all changes in this revision

Viewing changes to dao/ScsiIf-nt.cc

  • Committer: Bazaar Package Importer
  • Author(s): Andrew Suffield
  • Date: 2004-06-24 22:33:16 UTC
  • Revision ID: james.westby@ubuntu.com-20040624223316-534onzugaeeyq61j
Tags: upstream-1.1.9
ImportĀ upstreamĀ versionĀ 1.1.9

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*  cdrdao - write audio CD-Rs in disc-at-once mode
 
2
 *
 
3
 *  Copyright (C) 1998-2001  Andreas Mueller <andreas@daneb.de>
 
4
 *
 
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.
 
9
 *
 
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.
 
14
 *
 
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.
 
18
 */
 
19
 
 
20
#include "config.h"
 
21
 
 
22
#include <windows.h>
 
23
#include <winioctl.h>
 
24
#include <stdio.h>
 
25
#include <fcntl.h>
 
26
#include <errno.h>
 
27
#include <stddef.h>
 
28
#include <string.h>
 
29
#include <assert.h>
 
30
 
 
31
#include "ScsiIf.h"
 
32
#include "util.h"
 
33
 
 
34
#include "ntddcdrm.h"
 
35
 
 
36
#include "decodeSense.cc"
 
37
 
 
38
//
 
39
// SCSI Definitionen.
 
40
//
 
41
 
 
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)
 
46
 
 
47
 
 
48
#define SCSI_IOCTL_DATA_OUT          0
 
49
#define SCSI_IOCTL_DATA_IN           1
 
50
#define SCSI_IOCTL_DATA_UNSPECIFIED  2
 
51
 
 
52
#pragma pack(4)
 
53
 
 
54
typedef struct _IO_SCSI_CAPABILITIES 
 
55
{
 
56
    ULONG Length;
 
57
    ULONG MaximumTransferLength;
 
58
    ULONG MaximumPhysicalPages;
 
59
    ULONG SupportedAsynchronousEvents;
 
60
    ULONG AlignmentMask;
 
61
    BOOLEAN TaggedQueuing;
 
62
    BOOLEAN AdapterScansDown;
 
63
    BOOLEAN AdapterUsesPio;
 
64
} IO_SCSI_CAPABILITIES, *PIO_SCSI_CAPABILITIES;
 
65
 
 
66
typedef struct _SCSI_PASS_THROUGH_DIRECT 
 
67
{
 
68
    USHORT Length;
 
69
    UCHAR ScsiStatus;
 
70
    UCHAR PathId;
 
71
    UCHAR TargetId;
 
72
    UCHAR Lun;
 
73
    UCHAR CdbLength;
 
74
    UCHAR SenseInfoLength;
 
75
    UCHAR DataIn;
 
76
    ULONG DataTransferLength;
 
77
    ULONG TimeOutValue;
 
78
    PVOID DataBuffer;
 
79
    ULONG SenseInfoOffset;
 
80
    UCHAR Cdb[16];
 
81
} SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT;
 
82
 
 
83
 
 
84
typedef struct _SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER 
 
85
{
 
86
  SCSI_PASS_THROUGH_DIRECT sptd;
 
87
  ULONG Filler;      // realign buffer to double word boundary
 
88
  UCHAR ucSenseBuf[32];
 
89
} SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, *PSCSI_PASS_THROUGH_DIRECT_WITH_BUFFER;
 
90
 
 
91
typedef struct _SCSI_INQUIRY_DEVICE 
 
92
{
 
93
  UCHAR Type;
 
94
  UCHAR TypeModifier;
 
95
  UCHAR Version;
 
96
  UCHAR Format;
 
97
  UCHAR AddLength; // n-4
 
98
  UCHAR Reserved[2];
 
99
  UCHAR Flags;
 
100
  char  VendorId[8];
 
101
  char  ProductId[16];
 
102
  char  ProductRevLevel[4];
 
103
  char  ProductRevDate[8];
 
104
} SCSI_INQUIRY_DEVICE, *PSCSI_INQUIRY_DEVICE;
 
105
 
 
106
 
 
107
typedef struct _SCSI_ADDRESS {
 
108
    ULONG Length;
 
109
    UCHAR PortNumber;
 
110
    UCHAR PathId;
 
111
    UCHAR TargetId;
 
112
    UCHAR Lun;
 
113
}SCSI_ADDRESS, *PSCSI_ADDRESS;
 
114
 
 
115
 
 
116
#pragma pack(1)
 
117
 
 
118
//
 
119
// SCSI CDB operation codes
 
120
//
 
121
 
 
122
#define SCSIOP_INQUIRY             0x12
 
123
#define SCSIOP_MODE_SELECT         0x15
 
124
#define SCSIOP_MODE_SENSE          0x1A
 
125
 
 
126
#define AUDIO_BLOCK_LEN 2352
 
127
#define BUF_SIZE  (63*1024)
 
128
 
 
129
class ScsiIfImpl 
 
130
{
 
131
public:
 
132
  char *dev_;
 
133
 
 
134
  HANDLE hCD;
 
135
  SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sb;
 
136
  
 
137
  unsigned char senseBuffer_[32];
 
138
 
 
139
  char haid_;
 
140
  char lun_;
 
141
  char scsi_id_;
 
142
};
 
143
 
 
144
ScsiIf::ScsiIf(const char *dev)
 
145
{
 
146
  impl_ = new ScsiIfImpl;
 
147
 
 
148
  impl_->dev_ = strdup3CC("\\\\.\\", dev, NULL);
 
149
 
 
150
  impl_->hCD = INVALID_HANDLE_VALUE;
 
151
 
 
152
  vendor_[0] = 0;
 
153
  product_[0] = 0;
 
154
  revision_[0] = 0;
 
155
}
 
156
 
 
157
ScsiIf::~ScsiIf()
 
158
{
 
159
  if (impl_->hCD != INVALID_HANDLE_VALUE)
 
160
     CloseHandle (impl_->hCD);
 
161
 
 
162
  delete impl_;
 
163
}
 
164
 
 
165
// opens scsi device
 
166
// return: 0: OK
 
167
//         1: device could not be opened
 
168
//         2: inquiry failed
 
169
 
 
170
int ScsiIf::init()
 
171
{
 
172
  int i = 0;
 
173
  DWORD ol;
 
174
 
 
175
  SCSI_ADDRESS sa;
 
176
  IO_SCSI_CAPABILITIES ca;
 
177
 
 
178
  while (i++ < 3 && (impl_->hCD == INVALID_HANDLE_VALUE))
 
179
  {
 
180
    impl_->hCD = CreateFile (impl_->dev_, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
 
181
  }
 
182
 
 
183
  if (impl_->hCD == INVALID_HANDLE_VALUE) {
 
184
    return 1;
 
185
  }
 
186
 
 
187
  if (DeviceIoControl (impl_->hCD, IOCTL_SCSI_GET_ADDRESS, NULL, 0, &sa, sizeof(SCSI_ADDRESS), &ol, NULL)) 
 
188
  { 
 
189
    impl_->haid_    = sa.PortNumber;
 
190
    impl_->lun_     = sa.Lun;
 
191
    impl_->scsi_id_ = sa.TargetId;
 
192
  }
 
193
  else
 
194
  {
 
195
    CloseHandle (impl_->hCD);
 
196
    impl_->hCD = INVALID_HANDLE_VALUE;
 
197
    return 1;
 
198
  }
 
199
 
 
200
  if (DeviceIoControl (impl_->hCD, IOCTL_SCSI_GET_CAPABILITIES, NULL, 0, &ca, sizeof(IO_SCSI_CAPABILITIES), &ol, NULL)) 
 
201
  {
 
202
    maxDataLen_ = ca.MaximumTransferLength;
 
203
  }
 
204
  else
 
205
  {
 
206
    CloseHandle (impl_->hCD);
 
207
    impl_->hCD = INVALID_HANDLE_VALUE;
 
208
    return 1;
 
209
  }
 
210
 
 
211
  if (inquiry() != 0) 
 
212
    return 2;
 
213
 
 
214
  return 0;
 
215
}
 
216
 
 
217
// Sets given timeout value in seconds and returns old timeout.
 
218
// return: old timeout
 
219
 
 
220
int ScsiIf::timeout (int t)
 
221
{
 
222
  return 0;
 
223
}
 
224
 
 
225
// sends a scsi command and receives data
 
226
// return 0: OK
 
227
//        1: scsi command failed (os level, no sense data available)
 
228
//        2: scsi command failed (sense data available)
 
229
 
 
230
int ScsiIf::sendCmd (unsigned char *cmd,     int cmdLen, 
 
231
                     unsigned char *dataOut, int dataOutLen,
 
232
                     unsigned char *dataIn,  int dataInLen,
 
233
                     int showMessage)
 
234
{
 
235
  int i = 10;
 
236
 
 
237
  DWORD er, il, ol;
 
238
 
 
239
  ZeroMemory (&impl_->sb, sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER));
 
240
 
 
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);
 
250
 
 
251
  if (dataOut && dataOutLen)
 
252
  {
 
253
     impl_->sb.sptd.DataIn              = SCSI_IOCTL_DATA_OUT;
 
254
     impl_->sb.sptd.DataBuffer          = dataOut;
 
255
     impl_->sb.sptd.DataTransferLength  = dataOutLen;
 
256
  }
 
257
  else
 
258
  {
 
259
     impl_->sb.sptd.DataIn              = SCSI_IOCTL_DATA_IN;
 
260
     impl_->sb.sptd.DataBuffer          = dataIn;
 
261
     impl_->sb.sptd.DataTransferLength  = dataInLen;
 
262
  }
 
263
 
 
264
  il = sizeof (SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER);
 
265
 
 
266
  // AM: what about sense data?
 
267
  if (DeviceIoControl (impl_->hCD, IOCTL_SCSI_PASS_THROUGH_DIRECT, &impl_->sb, il, &impl_->sb, il, &ol, NULL)) 
 
268
  {
 
269
      er = impl_->sb.sptd.ScsiStatus ? impl_->sb.sptd.ScsiStatus | 0x20000000 : 0;
 
270
 
 
271
      if (!er)
 
272
         return (0); 
 
273
  }
 
274
  else 
 
275
     return (1);
 
276
  
 
277
  return 0;
 
278
}
 
279
 
 
280
const unsigned char *ScsiIf::getSense(int &len) const
 
281
{
 
282
  len = 32;
 
283
  return impl_->sb.ucSenseBuf;
 
284
}
 
285
 
 
286
void ScsiIf::printError()
 
287
{
 
288
  decodeSense(impl_->sb.ucSenseBuf, 32);
 
289
}
 
290
 
 
291
int ScsiIf::inquiry()
 
292
{
 
293
  unsigned char cmd[6];
 
294
  int i;
 
295
 
 
296
  SCSI_INQUIRY_DEVICE NTinqbuf;
 
297
 
 
298
  ZeroMemory (&NTinqbuf, sizeof(SCSI_INQUIRY_DEVICE));
 
299
 
 
300
  cmd[0] = 0x12; // INQUIRY
 
301
  cmd[1] = cmd[2] = cmd[3] = 0;
 
302
  cmd[4] = sizeof (NTinqbuf);
 
303
  cmd[5] = 0;
 
304
 
 
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_);
 
308
    return 1;
 
309
  }
 
310
 
 
311
  strncpy(vendor_, (char *)(NTinqbuf.VendorId), 8);
 
312
  vendor_[8] = 0;
 
313
 
 
314
  strncpy(product_, (char *)(NTinqbuf.ProductId), 16);
 
315
  product_[16] = 0;
 
316
 
 
317
  strncpy(revision_, (char *)(NTinqbuf.ProductRevLevel), 4);
 
318
  revision_[4] = 0;
 
319
 
 
320
  for (i = 7; i >= 0 && vendor_[i] == ' '; i--) 
 
321
  {
 
322
     vendor_[i] = 0;
 
323
  }
 
324
 
 
325
  for (i = 15; i >= 0 && product_[i] == ' '; i--) 
 
326
  {
 
327
     product_[i] = 0;
 
328
  }
 
329
 
 
330
  for (i = 3; i >= 0 && revision_[i] == ' '; i--) 
 
331
  {
 
332
     revision_[i] = 0;
 
333
  }
 
334
 
 
335
  return 0;
 
336
}
 
337
 
 
338