~ubuntu-branches/ubuntu/edgy/libcdio/edgy-updates

« back to all changes in this revision

Viewing changes to lib/driver/MSWindows/win32_ioctl.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2005-11-15 16:53:23 UTC
  • mfrom: (3.1.1 etch)
  • Revision ID: james.westby@ubuntu.com-20051115165323-peroku75syl2j36u
Tags: 0.76-1ubuntu1
* Sync to new Debian version, manually apply Ubuntu patches:
  - debian/control: Remove dpkg-awk build dependency.
  - debian/rules: hardcode $LIBCDEV. This keeps the diff small (compared to
    the original patch of changing every ${libcdev} occurence).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    $Id: win32_ioctl.c,v 1.28 2005/06/11 18:59:47 rocky Exp $
 
3
 
 
4
    Copyright (C) 2004, 2005 Rocky Bernstein <rocky@panix.com>
 
5
 
 
6
    This program is free software; you can redistribute it and/or modify
 
7
    it under the terms of the GNU General Public License as published by
 
8
    the Free Software Foundation; either version 2 of the License, or
 
9
    (at your option) any later version.
 
10
 
 
11
    This program is distributed in the hope that it will be useful,
 
12
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
    GNU General Public License for more details.
 
15
 
 
16
    You should have received a copy of the GNU General Public License
 
17
    along with this program; if not, write to the Free Software
 
18
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
19
*/
 
20
 
 
21
/* This file contains Win32-specific code using the DeviceIoControl
 
22
   access method.
 
23
*/
 
24
 
 
25
#ifdef HAVE_CONFIG_H
 
26
# include "config.h"
 
27
#endif
 
28
 
 
29
static const char _rcsid[] = "$Id: win32_ioctl.c,v 1.28 2005/06/11 18:59:47 rocky Exp $";
 
30
 
 
31
#ifdef HAVE_WIN32_CDROM
 
32
 
 
33
#if defined (_XBOX)
 
34
#include "inttypes.h"
 
35
#include "NtScsi.h"
 
36
#include "undocumented.h"
 
37
#define FORMAT_ERROR(i_err, psz_msg) \
 
38
   psz_msg=(char *)LocalAlloc(LMEM_ZEROINIT, 255); \
 
39
   sprintf(psz_msg, "error file %s: line %d (%s) %d\n", 
 
40
           _FILE__, __LINE__, __PRETTY_FUNCTION__, i_err)
 
41
#else
 
42
#include <ddk/ntddcdrm.h>
 
43
#include <ddk/ntddscsi.h>
 
44
#include <ddk/scsi.h>
 
45
#define FORMAT_ERROR(i_err, psz_msg) \
 
46
   FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, \
 
47
                 NULL, i_err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), \
 
48
                 (LPSTR) psz_msg, 0, NULL)
 
49
#endif
 
50
 
 
51
#ifdef WIN32
 
52
#include <windows.h>
 
53
#endif
 
54
 
 
55
#include <stdio.h>
 
56
#include <stddef.h>  /* offsetof() macro */
 
57
#include <sys/stat.h>
 
58
#include <errno.h>
 
59
#include <sys/types.h>
 
60
 
 
61
#include <cdio/cdio.h>
 
62
#include <cdio/sector.h>
 
63
#include <cdio/util.h>
 
64
#include "cdio_assert.h"
 
65
#include <cdio/mmc.h>
 
66
#include "cdtext_private.h"
 
67
#include "cdio/logging.h"
 
68
 
 
69
typedef struct _TRACK_DATA_FULL {
 
70
    UCHAR SessionNumber;
 
71
    UCHAR Control : 4;
 
72
    UCHAR Adr : 4;
 
73
    UCHAR TNO;
 
74
    UCHAR POINT;  /* Tracknumber (of session?) or lead-out/in (0xA0, 0xA1, 0xA2)  */ 
 
75
    UCHAR Min;  /* Only valid if disctype is CDDA ? */
 
76
    UCHAR Sec;  /* Only valid if disctype is CDDA ? */
 
77
    UCHAR Frame;  /* Only valid if disctype is CDDA ? */
 
78
    UCHAR Zero;  /* Always zero */
 
79
    UCHAR PMIN;  /* start min, if POINT is a track; if lead-out/in 0xA0: First Track */
 
80
    UCHAR PSEC;
 
81
    UCHAR PFRAME;
 
82
} TRACK_DATA_FULL, *PTRACK_DATA_FULL;
 
83
 
 
84
typedef struct _CDROM_TOC_FULL {
 
85
    UCHAR Length[2];
 
86
    UCHAR FirstSession;
 
87
    UCHAR LastSession;
 
88
    TRACK_DATA_FULL TrackData[CDIO_CD_MAX_TRACKS+3];
 
89
} CDROM_TOC_FULL, *PCDROM_TOC_FULL;
 
90
 
 
91
typedef struct {
 
92
   SCSI_PASS_THROUGH Spt;
 
93
   ULONG Filler;
 
94
   UCHAR SenseBuf[32];
 
95
   UCHAR DataBuf[512];
 
96
} SCSI_PASS_THROUGH_WITH_BUFFERS;
 
97
 
 
98
#include "win32.h"
 
99
 
 
100
#define OP_TIMEOUT_MS 60 
 
101
 
 
102
/*!
 
103
  Pause playing CD through analog output
 
104
  
 
105
  @param p_cdio the CD object to be acted upon.
 
106
*/
 
107
driver_return_code_t
 
108
audio_pause_win32ioctl (void *p_user_data)
 
109
{
 
110
  const _img_private_t *p_env = p_user_data;
 
111
  DWORD dw_bytes_returned;
 
112
  
 
113
  bool b_success = 
 
114
    DeviceIoControl(p_env->h_device_handle, IOCTL_CDROM_PAUSE_AUDIO,
 
115
                    NULL, (DWORD) 0, NULL, 0, &dw_bytes_returned, NULL);
 
116
 
 
117
  if ( ! b_success ) {
 
118
    char *psz_msg = NULL;
 
119
    long int i_err = GetLastError();
 
120
    FORMAT_ERROR(i_err, psz_msg);
 
121
    if (psz_msg) 
 
122
      cdio_info("Error: %s", psz_msg);
 
123
    else 
 
124
      cdio_info("Error: %ld", i_err);
 
125
    LocalFree(psz_msg);
 
126
    return DRIVER_OP_ERROR;
 
127
  }
 
128
  return DRIVER_OP_SUCCESS;
 
129
}
 
130
 
 
131
/*!
 
132
  Playing starting at given MSF through analog output
 
133
  
 
134
  @param p_cdio the CD object to be acted upon.
 
135
*/
 
136
driver_return_code_t
 
137
audio_play_msf_win32ioctl (void *p_user_data, msf_t *p_start_msf, 
 
138
                           msf_t *p_end_msf)
 
139
{
 
140
  const _img_private_t *p_env = p_user_data;
 
141
  CDROM_PLAY_AUDIO_MSF play;
 
142
  DWORD dw_bytes_returned;
 
143
 
 
144
  play.StartingM = cdio_from_bcd8(p_start_msf->m);
 
145
  play.StartingS = cdio_from_bcd8(p_start_msf->s);
 
146
  play.StartingF = cdio_from_bcd8(p_start_msf->f);
 
147
 
 
148
  play.EndingM   = cdio_from_bcd8(p_end_msf->m);
 
149
  play.EndingS   = cdio_from_bcd8(p_end_msf->s);
 
150
  play.EndingF   = cdio_from_bcd8(p_end_msf->f);
 
151
 
 
152
  bool b_success = 
 
153
    DeviceIoControl(p_env->h_device_handle, IOCTL_CDROM_PLAY_AUDIO_MSF,
 
154
                    &play, sizeof(play), NULL, 0, &dw_bytes_returned, NULL);
 
155
  
 
156
  if ( ! b_success ) {
 
157
    char *psz_msg = NULL;
 
158
    long int i_err = GetLastError();
 
159
    FORMAT_ERROR(i_err, psz_msg);
 
160
    if (psz_msg) 
 
161
      cdio_info("Error: %s", psz_msg);
 
162
    else 
 
163
      cdio_info("Error: %ld", i_err);
 
164
    LocalFree(psz_msg);
 
165
    return DRIVER_OP_ERROR;
 
166
  }
 
167
  return DRIVER_OP_SUCCESS;
 
168
  
 
169
}
 
170
 
 
171
/*!
 
172
  Read Audio Subchannel information
 
173
  
 
174
  @param p_cdio the CD object to be acted upon.
 
175
  
 
176
*/
 
177
driver_return_code_t
 
178
audio_read_subchannel_win32ioctl (void *p_user_data, 
 
179
                                  cdio_subchannel_t *p_subchannel)
 
180
{
 
181
  const _img_private_t *p_env = p_user_data;
 
182
  DWORD dw_bytes_returned;
 
183
  CDROM_SUB_Q_DATA_FORMAT q_data_format;
 
184
  SUB_Q_CHANNEL_DATA q_subchannel_data;
 
185
  
 
186
  q_data_format.Format = CDIO_SUBCHANNEL_CURRENT_POSITION;
 
187
  q_data_format.Track=0; /* Not sure if this has to be set or if so what
 
188
                            it should be. */
 
189
  
 
190
  if( ! DeviceIoControl( p_env->h_device_handle,
 
191
                       IOCTL_CDROM_READ_Q_CHANNEL,
 
192
                       &q_data_format, sizeof(q_data_format), 
 
193
                       &q_subchannel_data, sizeof(q_subchannel_data),
 
194
                       &dw_bytes_returned, NULL ) ) {
 
195
    char *psz_msg = NULL;
 
196
    long int i_err = GetLastError();
 
197
    FORMAT_ERROR(i_err, psz_msg);
 
198
    if (psz_msg) 
 
199
      cdio_info("Error: %s", psz_msg);
 
200
    else 
 
201
      cdio_info("Error: %ld", i_err);
 
202
    LocalFree(psz_msg);
 
203
    return DRIVER_OP_ERROR;
 
204
  }
 
205
  p_subchannel->audio_status = 
 
206
    q_subchannel_data.CurrentPosition.Header.AudioStatus;
 
207
  p_subchannel->track = 
 
208
    q_subchannel_data.CurrentPosition.TrackNumber;
 
209
  p_subchannel->index = 
 
210
    q_subchannel_data.CurrentPosition.IndexNumber;
 
211
  p_subchannel->index = 
 
212
    q_subchannel_data.CurrentPosition.IndexNumber;
 
213
  p_subchannel->address = q_subchannel_data.CurrentPosition.ADR;
 
214
  p_subchannel->control = q_subchannel_data.CurrentPosition.Control;
 
215
 
 
216
  { 
 
217
    const UCHAR *abs_addr = 
 
218
      q_subchannel_data.CurrentPosition.AbsoluteAddress;
 
219
    const UCHAR *rel_addr = 
 
220
      q_subchannel_data.CurrentPosition.TrackRelativeAddress;
 
221
 
 
222
    p_subchannel->abs_addr.m = cdio_to_bcd8(abs_addr[1]);
 
223
    p_subchannel->abs_addr.s = cdio_to_bcd8(abs_addr[2]);
 
224
    p_subchannel->abs_addr.f = cdio_to_bcd8(abs_addr[3]);
 
225
    p_subchannel->rel_addr.m = cdio_to_bcd8(rel_addr[1]);
 
226
    p_subchannel->rel_addr.s = cdio_to_bcd8(rel_addr[2]);
 
227
    p_subchannel->rel_addr.f = cdio_to_bcd8(rel_addr[3]);
 
228
  }
 
229
 
 
230
  return DRIVER_OP_SUCCESS;
 
231
}
 
232
 
 
233
 
 
234
/*!
 
235
  Resume playing an audio CD.
 
236
  
 
237
  @param p_user_data the CD object to be acted upon.
 
238
  
 
239
*/
 
240
driver_return_code_t
 
241
audio_resume_win32ioctl (void *p_user_data)
 
242
{
 
243
  const _img_private_t *p_env = p_user_data;
 
244
  DWORD dw_bytes_returned;
 
245
  
 
246
  bool b_success = 
 
247
    DeviceIoControl(p_env->h_device_handle, IOCTL_CDROM_RESUME_AUDIO,
 
248
                    NULL, (DWORD) 0, NULL, 0, &dw_bytes_returned, NULL);
 
249
 
 
250
  if ( ! b_success ) {
 
251
    char *psz_msg = NULL;
 
252
    long int i_err = GetLastError();
 
253
    FORMAT_ERROR(i_err, psz_msg);
 
254
    if (psz_msg) 
 
255
      cdio_info("Error: %s", psz_msg);
 
256
    else 
 
257
      cdio_info("Error: %ld", i_err);
 
258
    LocalFree(psz_msg);
 
259
    return DRIVER_OP_ERROR;
 
260
  }
 
261
  return DRIVER_OP_SUCCESS;
 
262
}
 
263
 
 
264
/*!
 
265
  Set the volume of an audio CD.
 
266
  
 
267
  @param p_user_data pointer to the CD object to be acted upon.
 
268
  @param p_volume pointer to the volume levels
 
269
  
 
270
*/
 
271
driver_return_code_t
 
272
audio_set_volume_win32ioctl (void *p_user_data, 
 
273
                             /*in*/ cdio_audio_volume_t *p_volume)
 
274
{
 
275
  const _img_private_t *p_env = p_user_data;
 
276
  DWORD dw_bytes_returned;
 
277
  
 
278
  bool b_success = 
 
279
    DeviceIoControl(p_env->h_device_handle, IOCTL_CDROM_SET_VOLUME,
 
280
                    p_volume, (DWORD) sizeof(cdio_audio_volume_t), 
 
281
                    NULL, 0, &dw_bytes_returned, NULL);
 
282
 
 
283
  if ( ! b_success ) {
 
284
    char *psz_msg = NULL;
 
285
    long int i_err = GetLastError();
 
286
    FORMAT_ERROR(i_err, psz_msg);
 
287
    if (psz_msg) 
 
288
      cdio_info("Error: %s", psz_msg);
 
289
    else 
 
290
      cdio_info("Error: %ld", i_err);
 
291
    LocalFree(psz_msg);
 
292
    return DRIVER_OP_ERROR;
 
293
  }
 
294
  return DRIVER_OP_SUCCESS;
 
295
}
 
296
 
 
297
driver_return_code_t
 
298
audio_get_volume_win32ioctl (void *p_user_data, 
 
299
                             /*out*/ cdio_audio_volume_t *p_volume)
 
300
{
 
301
  const _img_private_t *p_env = p_user_data;
 
302
  DWORD dw_bytes_returned;
 
303
 
 
304
  bool b_success = 
 
305
    DeviceIoControl(p_env->h_device_handle, IOCTL_CDROM_GET_VOLUME,
 
306
                    NULL, 0, 
 
307
                    p_volume, (DWORD) sizeof(cdio_audio_volume_t), 
 
308
                    &dw_bytes_returned, NULL);
 
309
 
 
310
  if ( ! b_success ) {
 
311
    char *psz_msg = NULL;
 
312
    long int i_err = GetLastError();
 
313
    FORMAT_ERROR(i_err, psz_msg);
 
314
    if (psz_msg) 
 
315
      cdio_info("Error: %s", psz_msg);
 
316
    else 
 
317
      cdio_info("Error: %ld", i_err);
 
318
    LocalFree(psz_msg);
 
319
    return DRIVER_OP_ERROR;
 
320
  }
 
321
  return DRIVER_OP_SUCCESS;
 
322
}
 
323
 
 
324
/*!
 
325
  Stop playing an audio CD.
 
326
  
 
327
  @param p_user_data the CD object to be acted upon.
 
328
  
 
329
*/
 
330
driver_return_code_t 
 
331
audio_stop_win32ioctl (void *p_user_data)
 
332
{
 
333
  const _img_private_t *p_env = p_user_data;
 
334
  DWORD dw_bytes_returned;
 
335
  
 
336
  bool b_success = 
 
337
    DeviceIoControl(p_env->h_device_handle, IOCTL_CDROM_STOP_AUDIO,
 
338
                    NULL, (DWORD) 0, NULL, 0, &dw_bytes_returned, NULL);
 
339
 
 
340
  if ( ! b_success ) {
 
341
    char *psz_msg = NULL;
 
342
    long int i_err = GetLastError();
 
343
    FORMAT_ERROR(i_err, psz_msg);
 
344
    if (psz_msg) 
 
345
      cdio_info("Error: %s", psz_msg);
 
346
    else 
 
347
      cdio_info("Error: %ld", i_err);
 
348
    LocalFree(psz_msg);
 
349
    return DRIVER_OP_ERROR;
 
350
  }
 
351
  return DRIVER_OP_SUCCESS;
 
352
}
 
353
 
 
354
/*!
 
355
  Close the tray of a CD-ROM
 
356
  
 
357
  @param p_user_data the CD object to be acted upon.
 
358
  
 
359
*/
 
360
driver_return_code_t 
 
361
close_tray_win32ioctl (const char *psz_win32_drive)
 
362
{
 
363
#ifdef WIN32
 
364
  DWORD dw_bytes_returned;
 
365
  DWORD dw_access_flags;
 
366
  
 
367
  OSVERSIONINFO ov;
 
368
  HANDLE h_device_handle;
 
369
  bool b_success;
 
370
  
 
371
  memset(&ov,0,sizeof(OSVERSIONINFO));
 
372
  ov.dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
 
373
  GetVersionEx(&ov);
 
374
  
 
375
  if((ov.dwPlatformId==VER_PLATFORM_WIN32_NT) &&        
 
376
     (ov.dwMajorVersion>4))
 
377
    dw_access_flags = GENERIC_READ|GENERIC_WRITE;  /* add gen write on W2k/XP */
 
378
  else dw_access_flags = GENERIC_READ;
 
379
 
 
380
  h_device_handle = CreateFile( psz_win32_drive, 
 
381
                                dw_access_flags,
 
382
                                FILE_SHARE_READ | FILE_SHARE_WRITE, 
 
383
                                NULL, 
 
384
                                OPEN_EXISTING,
 
385
                                FILE_ATTRIBUTE_NORMAL, 
 
386
                                NULL );
 
387
 
 
388
  if( h_device_handle == INVALID_HANDLE_VALUE ) {
 
389
    return DRIVER_OP_ERROR;
 
390
  }
 
391
 
 
392
  b_success = 
 
393
    DeviceIoControl(h_device_handle, IOCTL_STORAGE_LOAD_MEDIA2,
 
394
                    NULL, (DWORD) 0, NULL, 0, &dw_bytes_returned, NULL);
 
395
  
 
396
 
 
397
  CloseHandle(h_device_handle);
 
398
  
 
399
  if ( ! b_success ) {
 
400
    char *psz_msg = NULL;
 
401
    long int i_err = GetLastError();
 
402
    FORMAT_ERROR(i_err, psz_msg);
 
403
    if (psz_msg) 
 
404
      cdio_info("Error: %s", psz_msg);
 
405
    else 
 
406
      cdio_info("Error: %ld", i_err);
 
407
    LocalFree(psz_msg);
 
408
    return DRIVER_OP_ERROR;
 
409
  }
 
410
  return DRIVER_OP_SUCCESS;
 
411
#else 
 
412
  return DRIVER_OP_UNSUPPORTED;
 
413
#endif
 
414
}
 
415
 
 
416
/*!
 
417
  Run a SCSI MMC command. 
 
418
 
 
419
  env           private CD structure 
 
420
  i_timeout     time in milliseconds we will wait for the command
 
421
                to complete. If this value is -1, use the default 
 
422
                time-out value.
 
423
  p_buf         Buffer for data, both sending and receiving
 
424
  i_buf         Size of buffer
 
425
  e_direction   direction the transfer is to go.
 
426
  cdb           CDB bytes. All values that are needed should be set on 
 
427
                input. We'll figure out what the right CDB length should be.
 
428
 
 
429
  Return 0 if command completed successfully.
 
430
 */
 
431
int
 
432
run_mmc_cmd_win32ioctl( void *p_user_data, 
 
433
                        unsigned int i_timeout_ms,
 
434
                        unsigned int i_cdb, const mmc_cdb_t * p_cdb,
 
435
                        mmc_direction_t e_direction, 
 
436
                        unsigned int i_buf, /*in/out*/ void *p_buf )
 
437
{
 
438
  const _img_private_t *p_env = p_user_data;
 
439
  SCSI_PASS_THROUGH_DIRECT sptd;
 
440
  bool b_success;
 
441
  DWORD dw_bytes_returned;
 
442
  
 
443
  sptd.Length  = sizeof(sptd);
 
444
  sptd.PathId  = 0;      /* SCSI card ID will be filled in automatically */
 
445
  sptd.TargetId= 0;      /* SCSI target ID will also be filled in */
 
446
  sptd.Lun=0;            /* SCSI lun ID will also be filled in */
 
447
  sptd.CdbLength         = i_cdb;
 
448
  sptd.SenseInfoLength   = 0; /* Don't return any sense data */
 
449
  sptd.DataIn            = SCSI_MMC_DATA_READ == e_direction ? 
 
450
    SCSI_IOCTL_DATA_IN : SCSI_IOCTL_DATA_OUT; 
 
451
  sptd.DataTransferLength= i_buf; 
 
452
  sptd.TimeOutValue      = msecs2secs(i_timeout_ms);
 
453
  sptd.DataBuffer        = (void *) p_buf;
 
454
  sptd.SenseInfoOffset   = 0;
 
455
 
 
456
  memcpy(sptd.Cdb, p_cdb, i_cdb);
 
457
 
 
458
  /* Send the command to drive */
 
459
  b_success = DeviceIoControl(p_env->h_device_handle,
 
460
                              IOCTL_SCSI_PASS_THROUGH_DIRECT,               
 
461
                              (void *)&sptd, 
 
462
                              (DWORD)sizeof(SCSI_PASS_THROUGH_DIRECT),
 
463
                              NULL, 0,                        
 
464
                              &dw_bytes_returned,
 
465
                              NULL);
 
466
 
 
467
  if ( !b_success ) {
 
468
    char *psz_msg = NULL;
 
469
    long int i_err = GetLastError();
 
470
    FORMAT_ERROR(i_err, psz_msg);
 
471
    if (psz_msg) 
 
472
      cdio_info("Error: %s", psz_msg);
 
473
    else 
 
474
      cdio_info("Error: %ld", i_err);
 
475
    LocalFree(psz_msg);
 
476
    return DRIVER_OP_ERROR;
 
477
  }
 
478
  return DRIVER_OP_SUCCESS;
 
479
}
 
480
 
 
481
/*! 
 
482
  Get disc type associated with cd object.
 
483
*/
 
484
static discmode_t
 
485
dvd_discmode_win32ioctl (_img_private_t *p_env)
 
486
{
 
487
  discmode_t discmode=CDIO_DISC_MODE_NO_INFO;
 
488
  driver_return_code_t rc;
 
489
 
 
490
  /* See if this is a DVD. */
 
491
  cdio_dvd_struct_t dvd;  /* DVD READ STRUCT for layer 0. */
 
492
 
 
493
  dvd.physical.type = CDIO_DVD_STRUCT_PHYSICAL;
 
494
  dvd.physical.layer_num = 0;
 
495
 
 
496
  rc = mmc_get_dvd_struct_physical_private (p_env, &run_mmc_cmd_win32ioctl,
 
497
                                            &dvd);
 
498
 
 
499
  if (DRIVER_OP_SUCCESS == rc) {
 
500
    switch(dvd.physical.layer[0].book_type) {
 
501
    case CDIO_DVD_BOOK_DVD_ROM:  return CDIO_DISC_MODE_DVD_ROM;
 
502
    case CDIO_DVD_BOOK_DVD_RAM:  return CDIO_DISC_MODE_DVD_RAM;
 
503
    case CDIO_DVD_BOOK_DVD_R:    return CDIO_DISC_MODE_DVD_R;
 
504
    case CDIO_DVD_BOOK_DVD_RW:   return CDIO_DISC_MODE_DVD_RW;
 
505
    case CDIO_DVD_BOOK_DVD_PR:   return CDIO_DISC_MODE_DVD_PR;
 
506
    case CDIO_DVD_BOOK_DVD_PRW:  return CDIO_DISC_MODE_DVD_PRW;
 
507
    default: return CDIO_DISC_MODE_DVD_OTHER;
 
508
    }
 
509
  }
 
510
  return discmode;
 
511
}
 
512
 
 
513
 
 
514
/*! 
 
515
  Get disc type associated with cd object.
 
516
*/
 
517
discmode_t
 
518
get_discmode_win32ioctl (_img_private_t *p_env)
 
519
{
 
520
  track_t i_track;
 
521
  discmode_t discmode;
 
522
 
 
523
  if (!p_env) return CDIO_DISC_MODE_ERROR;
 
524
  
 
525
  discmode = dvd_discmode_win32ioctl(p_env);
 
526
 
 
527
  if (CDIO_DISC_MODE_NO_INFO != discmode) return discmode;
 
528
  
 
529
  if (!p_env->gen.toc_init) read_toc_win32ioctl (p_env);
 
530
 
 
531
  if (!p_env->gen.toc_init) return CDIO_DISC_MODE_ERROR;
 
532
 
 
533
  for (i_track = p_env->gen.i_first_track; 
 
534
       i_track < p_env->gen.i_first_track + p_env->gen.i_tracks ; 
 
535
       i_track ++) {
 
536
    track_format_t track_fmt=get_track_format_win32ioctl(p_env, i_track);
 
537
 
 
538
    switch(track_fmt) {
 
539
    case TRACK_FORMAT_AUDIO:
 
540
      switch(discmode) {
 
541
        case CDIO_DISC_MODE_NO_INFO:
 
542
          discmode = CDIO_DISC_MODE_CD_DA;
 
543
          break;
 
544
        case CDIO_DISC_MODE_CD_DA:
 
545
        case CDIO_DISC_MODE_CD_MIXED: 
 
546
        case CDIO_DISC_MODE_ERROR: 
 
547
          /* No change*/
 
548
          break;
 
549
      default:
 
550
          discmode = CDIO_DISC_MODE_CD_MIXED;
 
551
      }
 
552
      break;
 
553
    case TRACK_FORMAT_XA:
 
554
      switch(discmode) {
 
555
        case CDIO_DISC_MODE_NO_INFO:
 
556
          discmode = CDIO_DISC_MODE_CD_XA;
 
557
          break;
 
558
        case CDIO_DISC_MODE_CD_XA:
 
559
        case CDIO_DISC_MODE_CD_MIXED: 
 
560
        case CDIO_DISC_MODE_ERROR: 
 
561
          /* No change*/
 
562
          break;
 
563
      default:
 
564
        discmode = CDIO_DISC_MODE_CD_MIXED;
 
565
      }
 
566
      break;
 
567
    case TRACK_FORMAT_DATA:
 
568
      switch(discmode) {
 
569
        case CDIO_DISC_MODE_NO_INFO:
 
570
          discmode = CDIO_DISC_MODE_CD_DATA;
 
571
          break;
 
572
        case CDIO_DISC_MODE_CD_DATA:
 
573
        case CDIO_DISC_MODE_CD_MIXED: 
 
574
        case CDIO_DISC_MODE_ERROR: 
 
575
          /* No change*/
 
576
          break;
 
577
      default:
 
578
        discmode = CDIO_DISC_MODE_CD_MIXED;
 
579
      }
 
580
      break;
 
581
    case TRACK_FORMAT_ERROR:
 
582
    default:
 
583
      discmode = CDIO_DISC_MODE_ERROR;
 
584
    }
 
585
  }
 
586
  return discmode;
 
587
}
 
588
 
 
589
/*
 
590
  Returns a string that can be used in a CreateFile call if 
 
591
  c_drive letter is a character. If not NULL is returned.
 
592
 */
 
593
 
 
594
const char *
 
595
is_cdrom_win32ioctl(const char c_drive_letter) 
 
596
{
 
597
#ifdef _XBOX
 
598
  char sz_win32_drive_full[] = "\\\\.\\X:";
 
599
  sz_win32_drive_full[4] = c_drive_letter;
 
600
  return strdup(sz_win32_drive_full);
 
601
#else
 
602
  UINT uDriveType;
 
603
  char sz_win32_drive[4];
 
604
  
 
605
  sz_win32_drive[0]= c_drive_letter;
 
606
  sz_win32_drive[1]=':';
 
607
  sz_win32_drive[2]='\\';
 
608
  sz_win32_drive[3]='\0';
 
609
  
 
610
  uDriveType = GetDriveType(sz_win32_drive);
 
611
  
 
612
  switch(uDriveType) {
 
613
  case DRIVE_CDROM: {
 
614
    char sz_win32_drive_full[] = "\\\\.\\X:";
 
615
    sz_win32_drive_full[4] = c_drive_letter;
 
616
    return strdup(sz_win32_drive_full);
 
617
  }
 
618
  default:
 
619
    cdio_debug("Drive %c is not a CD-ROM", c_drive_letter);
 
620
    return NULL;
 
621
  }
 
622
#endif
 
623
}
 
624
  
 
625
/*!
 
626
   Reads an audio device using the DeviceIoControl method into data
 
627
   starting from lsn.  Returns 0 if no error.
 
628
 */
 
629
driver_return_code_t
 
630
read_audio_sectors_win32ioctl (_img_private_t *p_env, void *data, lsn_t lsn, 
 
631
                               unsigned int nblocks) 
 
632
{
 
633
  DWORD dw_bytes_returned;
 
634
  RAW_READ_INFO cdrom_raw;
 
635
  
 
636
  /* Initialize CDROM_RAW_READ structure */
 
637
  cdrom_raw.DiskOffset.QuadPart = (long long) CDIO_CD_FRAMESIZE_RAW * lsn;
 
638
  cdrom_raw.SectorCount = nblocks;
 
639
  cdrom_raw.TrackMode = CDDA;
 
640
  
 
641
  if( DeviceIoControl( p_env->h_device_handle,
 
642
                       IOCTL_CDROM_RAW_READ, &cdrom_raw,
 
643
                       sizeof(RAW_READ_INFO), data,
 
644
                       CDIO_CD_FRAMESIZE_RAW * nblocks,
 
645
                       &dw_bytes_returned, NULL ) == 0 ) {
 
646
    char *psz_msg = NULL;
 
647
    long int i_err = GetLastError();
 
648
    FORMAT_ERROR(i_err, psz_msg);
 
649
    if (psz_msg) {
 
650
      cdio_info("Error reading audio-mode lsn %lu\n%s (%ld))", 
 
651
                (long unsigned int) lsn, psz_msg, i_err);
 
652
    } else {
 
653
      cdio_info("Error reading audio-mode lsn %lu\n (%ld))",
 
654
                (long unsigned int) lsn, i_err);
 
655
    }
 
656
    LocalFree(psz_msg);
 
657
    return DRIVER_OP_ERROR;
 
658
  }
 
659
  return DRIVER_OP_SUCCESS;
 
660
}
 
661
 
 
662
/*!
 
663
   Reads a single raw sector using the DeviceIoControl method into
 
664
   data starting from lsn. Returns 0 if no error.
 
665
 */
 
666
static int
 
667
read_raw_sector (_img_private_t *p_env, void *p_buf, lsn_t lsn) 
 
668
{
 
669
  mmc_cdb_t cdb = {{0, }};
 
670
 
 
671
  /* ReadCD CDB12 command.  The values were taken from MMC1 draft paper. */
 
672
  CDIO_MMC_SET_COMMAND      (cdb.field, CDIO_MMC_GPCMD_READ_CD);
 
673
  CDIO_MMC_SET_READ_LBA     (cdb.field, lsn);
 
674
  CDIO_MMC_SET_READ_LENGTH24(cdb.field, 1);
 
675
 
 
676
  cdb.field[9]=0xF8;  /* Raw read, 2352 bytes per sector */
 
677
  
 
678
  return run_mmc_cmd_win32ioctl(p_env, OP_TIMEOUT_MS,
 
679
                                mmc_get_cmd_len(cdb.field[0]), 
 
680
                                &cdb, SCSI_MMC_DATA_READ, 
 
681
                                CDIO_CD_FRAMESIZE_RAW, p_buf);
 
682
}
 
683
 
 
684
/*!
 
685
   Reads a single mode2 sector using the DeviceIoControl method into
 
686
   data starting from lsn. Returns 0 if no error.
 
687
 */
 
688
int
 
689
read_mode2_sector_win32ioctl (_img_private_t *p_env, void *p_data, 
 
690
                              lsn_t lsn, bool b_form2)
 
691
{
 
692
  char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, };
 
693
  int ret = read_raw_sector (p_env, buf, lsn);
 
694
 
 
695
  if ( 0 != ret) return ret;
 
696
 
 
697
  memcpy (p_data,
 
698
          buf + CDIO_CD_SYNC_SIZE + CDIO_CD_XA_HEADER,
 
699
          b_form2 ? M2RAW_SECTOR_SIZE: CDIO_CD_FRAMESIZE);
 
700
  
 
701
  return 0;
 
702
 
 
703
}
 
704
 
 
705
/*!
 
706
   Reads a single mode2 sector using the DeviceIoControl method into
 
707
   data starting from lsn. Returns 0 if no error.
 
708
 */
 
709
int
 
710
read_mode1_sector_win32ioctl (_img_private_t *env, void *data, 
 
711
                              lsn_t lsn, bool b_form2)
 
712
{
 
713
  char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, };
 
714
  int ret = read_raw_sector (env, buf, lsn);
 
715
 
 
716
  if ( 0 != ret) return ret;
 
717
 
 
718
  memcpy (data, 
 
719
          buf + CDIO_CD_SYNC_SIZE+CDIO_CD_HEADER_SIZE,
 
720
          b_form2 ? M2RAW_SECTOR_SIZE: CDIO_CD_FRAMESIZE);  
 
721
 
 
722
  return 0;
 
723
 
 
724
}
 
725
 
 
726
/*!
 
727
  Initialize internal structures for CD device.
 
728
 */
 
729
bool
 
730
init_win32ioctl (_img_private_t *env)
 
731
{
 
732
#ifdef WIN32
 
733
  OSVERSIONINFO ov;
 
734
#endif
 
735
 
 
736
#ifdef _XBOX
 
737
  ANSI_STRING filename;
 
738
  OBJECT_ATTRIBUTES attributes;
 
739
  IO_STATUS_BLOCK status;
 
740
  HANDLE hDevice;
 
741
  NTSTATUS error;
 
742
#else
 
743
  unsigned int len=strlen(env->gen.source_name);
 
744
  char psz_win32_drive[7];
 
745
  DWORD dw_access_flags;
 
746
#endif
 
747
  
 
748
  cdio_debug("using winNT/2K/XP ioctl layer");
 
749
 
 
750
#ifdef WIN32
 
751
  memset(&ov,0,sizeof(OSVERSIONINFO));
 
752
  ov.dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
 
753
  GetVersionEx(&ov);
 
754
  
 
755
  if((ov.dwPlatformId==VER_PLATFORM_WIN32_NT) &&        
 
756
     (ov.dwMajorVersion>4))
 
757
    dw_access_flags = GENERIC_READ|GENERIC_WRITE;  /* add gen write on W2k/XP */
 
758
  else dw_access_flags = GENERIC_READ;
 
759
#endif
 
760
 
 
761
  if (cdio_is_device_win32(env->gen.source_name)) 
 
762
  {
 
763
#ifdef _XBOX
 
764
    //  Use XBOX cdrom, no matter what drive letter is given.
 
765
    RtlInitAnsiString(&filename,"\\Device\\Cdrom0");
 
766
    InitializeObjectAttributes(&attributes, &filename, OBJ_CASE_INSENSITIVE,
 
767
                               NULL);
 
768
    error = NtCreateFile( &hDevice, 
 
769
                          GENERIC_READ |SYNCHRONIZE | FILE_READ_ATTRIBUTES, 
 
770
                          &attributes, 
 
771
                          &status, 
 
772
                          NULL, 
 
773
                          0,
 
774
                          FILE_SHARE_READ,
 
775
                          FILE_OPEN,    
 
776
                          FILE_NON_DIRECTORY_FILE 
 
777
                          | FILE_SYNCHRONOUS_IO_NONALERT );
 
778
    
 
779
    if (!NT_SUCCESS(error))
 
780
    {
 
781
          return false;
 
782
    }
 
783
        env->h_device_handle = hDevice;
 
784
#else
 
785
    sprintf( psz_win32_drive, "\\\\.\\%c:", env->gen.source_name[len-2] );
 
786
 
 
787
    env->h_device_handle = CreateFile( psz_win32_drive, 
 
788
                                       dw_access_flags,
 
789
                                       FILE_SHARE_READ | FILE_SHARE_WRITE, 
 
790
                                       NULL, 
 
791
                                       OPEN_EXISTING,
 
792
                                       FILE_ATTRIBUTE_NORMAL, 
 
793
                                       NULL );
 
794
 
 
795
    if( env->h_device_handle == INVALID_HANDLE_VALUE )
 
796
    {
 
797
          /* No good. try toggle write. */
 
798
          dw_access_flags ^= GENERIC_WRITE;  
 
799
          env->h_device_handle = CreateFile( psz_win32_drive, 
 
800
                                             dw_access_flags, 
 
801
                                             FILE_SHARE_READ,  
 
802
                                             NULL, 
 
803
                                             OPEN_EXISTING, 
 
804
                                             FILE_ATTRIBUTE_NORMAL, 
 
805
                                             NULL );
 
806
          if (env->h_device_handle == NULL)
 
807
                return false;
 
808
    }
 
809
#endif
 
810
    env->b_ioctl_init = true;
 
811
    return true;
 
812
  }
 
813
  return false;
 
814
}
 
815
 
 
816
/*!  
 
817
  Read and cache the CD's Track Table of Contents and track info.
 
818
  via a SCSI MMC READ_TOC (FULTOC).  Return true if successful or
 
819
  false if an error.
 
820
*/
 
821
static bool
 
822
read_fulltoc_win32mmc (_img_private_t *p_env) 
 
823
{
 
824
  mmc_cdb_t  cdb = {{0, }};
 
825
  CDROM_TOC_FULL  cdrom_toc_full;
 
826
  int             i_status, i, j;
 
827
  int             i_track_format = 0;
 
828
  int             i_seen_flag;
 
829
 
 
830
  /* Operation code */
 
831
  CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_READ_TOC);
 
832
 
 
833
  cdb.field[1] = 0x00;
 
834
 
 
835
  /* Format */
 
836
  cdb.field[2] = CDIO_MMC_READTOC_FMT_FULTOC;
 
837
 
 
838
  memset(&cdrom_toc_full, 0, sizeof(cdrom_toc_full));
 
839
 
 
840
  /* Setup to read header, to get length of data */
 
841
  CDIO_MMC_SET_READ_LENGTH16(cdb.field, sizeof(cdrom_toc_full));
 
842
 
 
843
  i_status = run_mmc_cmd_win32ioctl (p_env, 1000*60*3,
 
844
                                     mmc_get_cmd_len(cdb.field[0]), 
 
845
                                     &cdb, SCSI_MMC_DATA_READ, 
 
846
                                     sizeof(cdrom_toc_full), &cdrom_toc_full);
 
847
 
 
848
  if ( 0 != i_status ) {
 
849
    cdio_debug ("SCSI MMC READ_TOC failed\n");  
 
850
    return false;
 
851
  } 
 
852
    
 
853
  i_seen_flag=0;
 
854
  for( i = 0 ; i <= CDIO_CD_MAX_TRACKS+3; i++ ) {
 
855
    
 
856
    if ( 0xA0 == cdrom_toc_full.TrackData[i].POINT ) { 
 
857
      /* First track number */
 
858
      p_env->gen.i_first_track = cdrom_toc_full.TrackData[i].PMIN;
 
859
      i_track_format = cdrom_toc_full.TrackData[i].PSEC;
 
860
      i_seen_flag|=0x01;
 
861
    }
 
862
    
 
863
    if ( 0xA1 == cdrom_toc_full.TrackData[i].POINT ) { 
 
864
      /* Last track number */
 
865
      p_env->gen.i_tracks = 
 
866
        cdrom_toc_full.TrackData[i].PMIN - p_env->gen.i_first_track + 1;
 
867
      i_seen_flag|=0x02;
 
868
    }
 
869
 
 
870
    j = cdrom_toc_full.TrackData[i].POINT;
 
871
    if ( 0xA2 ==  j ) { 
 
872
      /* Start position of the lead out */
 
873
      p_env->tocent[ p_env->gen.i_tracks ].start_lsn = 
 
874
        cdio_lba_to_lsn(
 
875
                        cdio_msf3_to_lba(
 
876
                                         cdrom_toc_full.TrackData[i].PMIN,
 
877
                                         cdrom_toc_full.TrackData[i].PSEC,
 
878
                                         cdrom_toc_full.TrackData[i].PFRAME 
 
879
                                         )
 
880
                        );
 
881
      p_env->tocent[ p_env->gen.i_tracks ].Control 
 
882
        = cdrom_toc_full.TrackData[i].Control;
 
883
      p_env->tocent[ p_env->gen.i_tracks ].Format  = i_track_format;
 
884
      i_seen_flag|=0x04;
 
885
    }
 
886
    
 
887
    if (cdrom_toc_full.TrackData[i].POINT > 0 
 
888
        && cdrom_toc_full.TrackData[i].POINT <= p_env->gen.i_tracks) {
 
889
      p_env->tocent[j-1].start_lsn = 
 
890
        cdio_lba_to_lsn(
 
891
                        cdio_msf3_to_lba(
 
892
                                         cdrom_toc_full.TrackData[i].PMIN,
 
893
                                         cdrom_toc_full.TrackData[i].PSEC,
 
894
                                         cdrom_toc_full.TrackData[i].PFRAME 
 
895
                                         )
 
896
                        );
 
897
      p_env->tocent[j-1].Control = 
 
898
        cdrom_toc_full.TrackData[i].Control;
 
899
      p_env->tocent[j-1].Format  = i_track_format;
 
900
      
 
901
      set_track_flags(&(p_env->gen.track_flags[j]), 
 
902
                      p_env->tocent[j-1].Control);
 
903
    
 
904
      cdio_debug("p_sectors: %i, %lu", i, 
 
905
                 (unsigned long int) (p_env->tocent[i].start_lsn));
 
906
      
 
907
      if (cdrom_toc_full.TrackData[i].POINT == p_env->gen.i_tracks)
 
908
        i_seen_flag|=0x08;
 
909
    }
 
910
    
 
911
    if ( 0x0F == i_seen_flag ) break;
 
912
  }
 
913
  if ( 0x0F == i_seen_flag ) {
 
914
    p_env->gen.toc_init = true; 
 
915
    return true;
 
916
  }
 
917
  return false;
 
918
}
 
919
 
 
920
/*! 
 
921
  Read and cache the CD's Track Table of Contents and track info.
 
922
  Return true if successful or false if an error.
 
923
*/
 
924
bool
 
925
read_toc_win32ioctl (_img_private_t *p_env) 
 
926
{
 
927
  CDROM_TOC    cdrom_toc;
 
928
  DWORD        dw_bytes_returned;
 
929
  unsigned int i, j;
 
930
  bool         b_fulltoc_first;  /* Do we do fulltoc or DeviceIoControl 
 
931
                                    first? */
 
932
  if ( ! p_env ) return false;
 
933
 
 
934
  /* 
 
935
     The MMC5 spec says:
 
936
       For media other than CD, information may be fabricated in order
 
937
                                            ^^^ ^^
 
938
       to emulate a CD structure for the specific media.
 
939
 
 
940
     There is no requirement though that it *has* to and some DVD
 
941
     drives like one by Thompson for XBOX don't support a
 
942
     IOCTL_CDROM_READ_TOC for DVD's. So if we have a DVD we should not
 
943
     prefer getting the TOC via MMC.
 
944
 
 
945
     But on the other hand in GNU/Linux it is reported that using the
 
946
     TOC via MMC gives better information such as for CD DATA Form 2 (used
 
947
     in SVCDs). So if we *don't* have a DVD I think we want to try MMC
 
948
     first. 
 
949
 
 
950
     Is this complicated enough? I could be wrong...
 
951
 
 
952
   */
 
953
  b_fulltoc_first = (CDIO_DISC_MODE_NO_INFO == dvd_discmode_win32ioctl(p_env));
 
954
 
 
955
  if ( b_fulltoc_first && read_fulltoc_win32mmc(p_env) ) return true;
 
956
 
 
957
  /* SCSI-MMC READ_TOC (FULTOC) read failed or we don't want to try it
 
958
     initiaily.  Try reading TOC via DeviceIoControl... */
 
959
 
 
960
  if( DeviceIoControl( p_env->h_device_handle,
 
961
                       IOCTL_CDROM_READ_TOC,
 
962
                       NULL, 0, &cdrom_toc, sizeof(CDROM_TOC),
 
963
                       &dw_bytes_returned, NULL ) == 0 ) {
 
964
    char *psz_msg = NULL;
 
965
    long int i_err = GetLastError();
 
966
    cdio_log_level_t loglevel = b_fulltoc_first 
 
967
      ? CDIO_LOG_WARN : CDIO_LOG_DEBUG;
 
968
 
 
969
    FORMAT_ERROR(i_err, psz_msg);
 
970
    if (psz_msg) {
 
971
      cdio_log(loglevel, "could not read TOC (%ld): %s", i_err, psz_msg);
 
972
      LocalFree(psz_msg);
 
973
    } else 
 
974
      cdio_log(loglevel, "could not read TOC (%ld)", i_err);
 
975
 
 
976
    if ( !b_fulltoc_first && read_fulltoc_win32mmc(p_env) ) return true;
 
977
    return false;
 
978
  }
 
979
  
 
980
  p_env->gen.i_first_track = cdrom_toc.FirstTrack;
 
981
  p_env->gen.i_tracks  = cdrom_toc.LastTrack - cdrom_toc.FirstTrack + 1;
 
982
 
 
983
  j = p_env->gen.i_first_track;
 
984
  for( i = 0 ; i <= p_env->gen.i_tracks ; i++, j++ ) {
 
985
    p_env->tocent[ i ].start_lsn = 
 
986
      cdio_lba_to_lsn(
 
987
                      cdio_msf3_to_lba( cdrom_toc.TrackData[i].Address[1],
 
988
                                        cdrom_toc.TrackData[i].Address[2],
 
989
                                        cdrom_toc.TrackData[i].Address[3] )
 
990
                      );
 
991
    p_env->tocent[i].Control   = cdrom_toc.TrackData[i].Control;
 
992
    p_env->tocent[i].Format    = cdrom_toc.TrackData[i].Adr;
 
993
 
 
994
    p_env->gen.track_flags[j].preemphasis = 
 
995
      p_env->tocent[i].Control & 0x1 
 
996
      ? CDIO_TRACK_FLAG_TRUE : CDIO_TRACK_FLAG_FALSE;
 
997
 
 
998
    p_env->gen.track_flags[j].copy_permit = 
 
999
      p_env->tocent[i].Control & 0x2 
 
1000
      ? CDIO_TRACK_FLAG_TRUE : CDIO_TRACK_FLAG_FALSE;
 
1001
    
 
1002
    p_env->gen.track_flags[j].channels = 
 
1003
      p_env->tocent[i].Control & 0x8 ? 4 : 2;
 
1004
    
 
1005
 
 
1006
    cdio_debug("p_sectors: %i, %lu", i, 
 
1007
               (unsigned long int) (p_env->tocent[i].start_lsn));
 
1008
  }
 
1009
  p_env->gen.toc_init = true;
 
1010
  return true;
 
1011
}
 
1012
 
 
1013
/*!
 
1014
  Return the media catalog number MCN.
 
1015
 
 
1016
  Note: string is malloc'd so caller should free() then returned
 
1017
  string when done with it.
 
1018
 
 
1019
 */
 
1020
char *
 
1021
get_mcn_win32ioctl (const _img_private_t *p_env) {
 
1022
 
 
1023
  DWORD dw_bytes_returned;
 
1024
  SUB_Q_MEDIA_CATALOG_NUMBER mcn;
 
1025
  CDROM_SUB_Q_DATA_FORMAT q_data_format;
 
1026
  
 
1027
  memset( &mcn, 0, sizeof(mcn) );
 
1028
  
 
1029
  q_data_format.Format = CDIO_SUBCHANNEL_MEDIA_CATALOG;
 
1030
 
 
1031
  /* MSDN info on CDROM_SUB_Q_DATA_FORMAT says if Format is set to 
 
1032
     get MCN, track must be set 0.
 
1033
   */
 
1034
  q_data_format.Track=0; 
 
1035
  
 
1036
  if( ! DeviceIoControl( p_env->h_device_handle,
 
1037
                       IOCTL_CDROM_READ_Q_CHANNEL,
 
1038
                       &q_data_format, sizeof(q_data_format), 
 
1039
                       &mcn, sizeof(mcn),
 
1040
                       &dw_bytes_returned, NULL ) ) {
 
1041
    cdio_warn( "could not read Q Channel at track %d", 1);
 
1042
  } else if (mcn.Mcval) 
 
1043
    return strdup(mcn.MediaCatalog);
 
1044
  return NULL;
 
1045
}
 
1046
 
 
1047
/*!  
 
1048
  Get the format (XA, DATA, AUDIO) of a track. 
 
1049
*/
 
1050
track_format_t
 
1051
get_track_format_win32ioctl(const _img_private_t *env, track_t i_track) 
 
1052
{
 
1053
  /* This is pretty much copied from the "badly broken" cdrom_count_tracks
 
1054
     in linux/cdrom.c.
 
1055
  */
 
1056
 
 
1057
  if (env->tocent[i_track - env->gen.i_first_track].Control & 0x04) {
 
1058
    if (env->tocent[i_track - env->gen.i_first_track].Format == 0x10)
 
1059
      return TRACK_FORMAT_CDI;
 
1060
    else if (env->tocent[i_track - env->gen.i_first_track].Format == 0x20) 
 
1061
      return TRACK_FORMAT_XA;
 
1062
    else
 
1063
      return TRACK_FORMAT_DATA;
 
1064
  } else
 
1065
    return TRACK_FORMAT_AUDIO;
 
1066
}
 
1067
 
 
1068
#endif /*HAVE_WIN32_CDROM*/