2
$Id: win32_ioctl.c,v 1.28 2005/06/11 18:59:47 rocky Exp $
4
Copyright (C) 2004, 2005 Rocky Bernstein <rocky@panix.com>
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.
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.
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
21
/* This file contains Win32-specific code using the DeviceIoControl
29
static const char _rcsid[] = "$Id: win32_ioctl.c,v 1.28 2005/06/11 18:59:47 rocky Exp $";
31
#ifdef HAVE_WIN32_CDROM
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)
42
#include <ddk/ntddcdrm.h>
43
#include <ddk/ntddscsi.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)
56
#include <stddef.h> /* offsetof() macro */
59
#include <sys/types.h>
61
#include <cdio/cdio.h>
62
#include <cdio/sector.h>
63
#include <cdio/util.h>
64
#include "cdio_assert.h"
66
#include "cdtext_private.h"
67
#include "cdio/logging.h"
69
typedef struct _TRACK_DATA_FULL {
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 */
82
} TRACK_DATA_FULL, *PTRACK_DATA_FULL;
84
typedef struct _CDROM_TOC_FULL {
88
TRACK_DATA_FULL TrackData[CDIO_CD_MAX_TRACKS+3];
89
} CDROM_TOC_FULL, *PCDROM_TOC_FULL;
92
SCSI_PASS_THROUGH Spt;
96
} SCSI_PASS_THROUGH_WITH_BUFFERS;
100
#define OP_TIMEOUT_MS 60
103
Pause playing CD through analog output
105
@param p_cdio the CD object to be acted upon.
108
audio_pause_win32ioctl (void *p_user_data)
110
const _img_private_t *p_env = p_user_data;
111
DWORD dw_bytes_returned;
114
DeviceIoControl(p_env->h_device_handle, IOCTL_CDROM_PAUSE_AUDIO,
115
NULL, (DWORD) 0, NULL, 0, &dw_bytes_returned, NULL);
118
char *psz_msg = NULL;
119
long int i_err = GetLastError();
120
FORMAT_ERROR(i_err, psz_msg);
122
cdio_info("Error: %s", psz_msg);
124
cdio_info("Error: %ld", i_err);
126
return DRIVER_OP_ERROR;
128
return DRIVER_OP_SUCCESS;
132
Playing starting at given MSF through analog output
134
@param p_cdio the CD object to be acted upon.
137
audio_play_msf_win32ioctl (void *p_user_data, msf_t *p_start_msf,
140
const _img_private_t *p_env = p_user_data;
141
CDROM_PLAY_AUDIO_MSF play;
142
DWORD dw_bytes_returned;
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);
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);
153
DeviceIoControl(p_env->h_device_handle, IOCTL_CDROM_PLAY_AUDIO_MSF,
154
&play, sizeof(play), NULL, 0, &dw_bytes_returned, NULL);
157
char *psz_msg = NULL;
158
long int i_err = GetLastError();
159
FORMAT_ERROR(i_err, psz_msg);
161
cdio_info("Error: %s", psz_msg);
163
cdio_info("Error: %ld", i_err);
165
return DRIVER_OP_ERROR;
167
return DRIVER_OP_SUCCESS;
172
Read Audio Subchannel information
174
@param p_cdio the CD object to be acted upon.
178
audio_read_subchannel_win32ioctl (void *p_user_data,
179
cdio_subchannel_t *p_subchannel)
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;
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
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);
199
cdio_info("Error: %s", psz_msg);
201
cdio_info("Error: %ld", i_err);
203
return DRIVER_OP_ERROR;
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;
217
const UCHAR *abs_addr =
218
q_subchannel_data.CurrentPosition.AbsoluteAddress;
219
const UCHAR *rel_addr =
220
q_subchannel_data.CurrentPosition.TrackRelativeAddress;
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]);
230
return DRIVER_OP_SUCCESS;
235
Resume playing an audio CD.
237
@param p_user_data the CD object to be acted upon.
241
audio_resume_win32ioctl (void *p_user_data)
243
const _img_private_t *p_env = p_user_data;
244
DWORD dw_bytes_returned;
247
DeviceIoControl(p_env->h_device_handle, IOCTL_CDROM_RESUME_AUDIO,
248
NULL, (DWORD) 0, NULL, 0, &dw_bytes_returned, NULL);
251
char *psz_msg = NULL;
252
long int i_err = GetLastError();
253
FORMAT_ERROR(i_err, psz_msg);
255
cdio_info("Error: %s", psz_msg);
257
cdio_info("Error: %ld", i_err);
259
return DRIVER_OP_ERROR;
261
return DRIVER_OP_SUCCESS;
265
Set the volume of an audio CD.
267
@param p_user_data pointer to the CD object to be acted upon.
268
@param p_volume pointer to the volume levels
272
audio_set_volume_win32ioctl (void *p_user_data,
273
/*in*/ cdio_audio_volume_t *p_volume)
275
const _img_private_t *p_env = p_user_data;
276
DWORD dw_bytes_returned;
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);
284
char *psz_msg = NULL;
285
long int i_err = GetLastError();
286
FORMAT_ERROR(i_err, psz_msg);
288
cdio_info("Error: %s", psz_msg);
290
cdio_info("Error: %ld", i_err);
292
return DRIVER_OP_ERROR;
294
return DRIVER_OP_SUCCESS;
298
audio_get_volume_win32ioctl (void *p_user_data,
299
/*out*/ cdio_audio_volume_t *p_volume)
301
const _img_private_t *p_env = p_user_data;
302
DWORD dw_bytes_returned;
305
DeviceIoControl(p_env->h_device_handle, IOCTL_CDROM_GET_VOLUME,
307
p_volume, (DWORD) sizeof(cdio_audio_volume_t),
308
&dw_bytes_returned, NULL);
311
char *psz_msg = NULL;
312
long int i_err = GetLastError();
313
FORMAT_ERROR(i_err, psz_msg);
315
cdio_info("Error: %s", psz_msg);
317
cdio_info("Error: %ld", i_err);
319
return DRIVER_OP_ERROR;
321
return DRIVER_OP_SUCCESS;
325
Stop playing an audio CD.
327
@param p_user_data the CD object to be acted upon.
331
audio_stop_win32ioctl (void *p_user_data)
333
const _img_private_t *p_env = p_user_data;
334
DWORD dw_bytes_returned;
337
DeviceIoControl(p_env->h_device_handle, IOCTL_CDROM_STOP_AUDIO,
338
NULL, (DWORD) 0, NULL, 0, &dw_bytes_returned, NULL);
341
char *psz_msg = NULL;
342
long int i_err = GetLastError();
343
FORMAT_ERROR(i_err, psz_msg);
345
cdio_info("Error: %s", psz_msg);
347
cdio_info("Error: %ld", i_err);
349
return DRIVER_OP_ERROR;
351
return DRIVER_OP_SUCCESS;
355
Close the tray of a CD-ROM
357
@param p_user_data the CD object to be acted upon.
361
close_tray_win32ioctl (const char *psz_win32_drive)
364
DWORD dw_bytes_returned;
365
DWORD dw_access_flags;
368
HANDLE h_device_handle;
371
memset(&ov,0,sizeof(OSVERSIONINFO));
372
ov.dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
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;
380
h_device_handle = CreateFile( psz_win32_drive,
382
FILE_SHARE_READ | FILE_SHARE_WRITE,
385
FILE_ATTRIBUTE_NORMAL,
388
if( h_device_handle == INVALID_HANDLE_VALUE ) {
389
return DRIVER_OP_ERROR;
393
DeviceIoControl(h_device_handle, IOCTL_STORAGE_LOAD_MEDIA2,
394
NULL, (DWORD) 0, NULL, 0, &dw_bytes_returned, NULL);
397
CloseHandle(h_device_handle);
400
char *psz_msg = NULL;
401
long int i_err = GetLastError();
402
FORMAT_ERROR(i_err, psz_msg);
404
cdio_info("Error: %s", psz_msg);
406
cdio_info("Error: %ld", i_err);
408
return DRIVER_OP_ERROR;
410
return DRIVER_OP_SUCCESS;
412
return DRIVER_OP_UNSUPPORTED;
417
Run a SCSI MMC command.
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
423
p_buf Buffer for data, both sending and receiving
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.
429
Return 0 if command completed successfully.
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 )
438
const _img_private_t *p_env = p_user_data;
439
SCSI_PASS_THROUGH_DIRECT sptd;
441
DWORD dw_bytes_returned;
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;
456
memcpy(sptd.Cdb, p_cdb, i_cdb);
458
/* Send the command to drive */
459
b_success = DeviceIoControl(p_env->h_device_handle,
460
IOCTL_SCSI_PASS_THROUGH_DIRECT,
462
(DWORD)sizeof(SCSI_PASS_THROUGH_DIRECT),
468
char *psz_msg = NULL;
469
long int i_err = GetLastError();
470
FORMAT_ERROR(i_err, psz_msg);
472
cdio_info("Error: %s", psz_msg);
474
cdio_info("Error: %ld", i_err);
476
return DRIVER_OP_ERROR;
478
return DRIVER_OP_SUCCESS;
482
Get disc type associated with cd object.
485
dvd_discmode_win32ioctl (_img_private_t *p_env)
487
discmode_t discmode=CDIO_DISC_MODE_NO_INFO;
488
driver_return_code_t rc;
490
/* See if this is a DVD. */
491
cdio_dvd_struct_t dvd; /* DVD READ STRUCT for layer 0. */
493
dvd.physical.type = CDIO_DVD_STRUCT_PHYSICAL;
494
dvd.physical.layer_num = 0;
496
rc = mmc_get_dvd_struct_physical_private (p_env, &run_mmc_cmd_win32ioctl,
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;
515
Get disc type associated with cd object.
518
get_discmode_win32ioctl (_img_private_t *p_env)
523
if (!p_env) return CDIO_DISC_MODE_ERROR;
525
discmode = dvd_discmode_win32ioctl(p_env);
527
if (CDIO_DISC_MODE_NO_INFO != discmode) return discmode;
529
if (!p_env->gen.toc_init) read_toc_win32ioctl (p_env);
531
if (!p_env->gen.toc_init) return CDIO_DISC_MODE_ERROR;
533
for (i_track = p_env->gen.i_first_track;
534
i_track < p_env->gen.i_first_track + p_env->gen.i_tracks ;
536
track_format_t track_fmt=get_track_format_win32ioctl(p_env, i_track);
539
case TRACK_FORMAT_AUDIO:
541
case CDIO_DISC_MODE_NO_INFO:
542
discmode = CDIO_DISC_MODE_CD_DA;
544
case CDIO_DISC_MODE_CD_DA:
545
case CDIO_DISC_MODE_CD_MIXED:
546
case CDIO_DISC_MODE_ERROR:
550
discmode = CDIO_DISC_MODE_CD_MIXED;
553
case TRACK_FORMAT_XA:
555
case CDIO_DISC_MODE_NO_INFO:
556
discmode = CDIO_DISC_MODE_CD_XA;
558
case CDIO_DISC_MODE_CD_XA:
559
case CDIO_DISC_MODE_CD_MIXED:
560
case CDIO_DISC_MODE_ERROR:
564
discmode = CDIO_DISC_MODE_CD_MIXED;
567
case TRACK_FORMAT_DATA:
569
case CDIO_DISC_MODE_NO_INFO:
570
discmode = CDIO_DISC_MODE_CD_DATA;
572
case CDIO_DISC_MODE_CD_DATA:
573
case CDIO_DISC_MODE_CD_MIXED:
574
case CDIO_DISC_MODE_ERROR:
578
discmode = CDIO_DISC_MODE_CD_MIXED;
581
case TRACK_FORMAT_ERROR:
583
discmode = CDIO_DISC_MODE_ERROR;
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.
595
is_cdrom_win32ioctl(const char c_drive_letter)
598
char sz_win32_drive_full[] = "\\\\.\\X:";
599
sz_win32_drive_full[4] = c_drive_letter;
600
return strdup(sz_win32_drive_full);
603
char sz_win32_drive[4];
605
sz_win32_drive[0]= c_drive_letter;
606
sz_win32_drive[1]=':';
607
sz_win32_drive[2]='\\';
608
sz_win32_drive[3]='\0';
610
uDriveType = GetDriveType(sz_win32_drive);
614
char sz_win32_drive_full[] = "\\\\.\\X:";
615
sz_win32_drive_full[4] = c_drive_letter;
616
return strdup(sz_win32_drive_full);
619
cdio_debug("Drive %c is not a CD-ROM", c_drive_letter);
626
Reads an audio device using the DeviceIoControl method into data
627
starting from lsn. Returns 0 if no error.
630
read_audio_sectors_win32ioctl (_img_private_t *p_env, void *data, lsn_t lsn,
631
unsigned int nblocks)
633
DWORD dw_bytes_returned;
634
RAW_READ_INFO cdrom_raw;
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;
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);
650
cdio_info("Error reading audio-mode lsn %lu\n%s (%ld))",
651
(long unsigned int) lsn, psz_msg, i_err);
653
cdio_info("Error reading audio-mode lsn %lu\n (%ld))",
654
(long unsigned int) lsn, i_err);
657
return DRIVER_OP_ERROR;
659
return DRIVER_OP_SUCCESS;
663
Reads a single raw sector using the DeviceIoControl method into
664
data starting from lsn. Returns 0 if no error.
667
read_raw_sector (_img_private_t *p_env, void *p_buf, lsn_t lsn)
669
mmc_cdb_t cdb = {{0, }};
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);
676
cdb.field[9]=0xF8; /* Raw read, 2352 bytes per sector */
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);
685
Reads a single mode2 sector using the DeviceIoControl method into
686
data starting from lsn. Returns 0 if no error.
689
read_mode2_sector_win32ioctl (_img_private_t *p_env, void *p_data,
690
lsn_t lsn, bool b_form2)
692
char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, };
693
int ret = read_raw_sector (p_env, buf, lsn);
695
if ( 0 != ret) return ret;
698
buf + CDIO_CD_SYNC_SIZE + CDIO_CD_XA_HEADER,
699
b_form2 ? M2RAW_SECTOR_SIZE: CDIO_CD_FRAMESIZE);
706
Reads a single mode2 sector using the DeviceIoControl method into
707
data starting from lsn. Returns 0 if no error.
710
read_mode1_sector_win32ioctl (_img_private_t *env, void *data,
711
lsn_t lsn, bool b_form2)
713
char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, };
714
int ret = read_raw_sector (env, buf, lsn);
716
if ( 0 != ret) return ret;
719
buf + CDIO_CD_SYNC_SIZE+CDIO_CD_HEADER_SIZE,
720
b_form2 ? M2RAW_SECTOR_SIZE: CDIO_CD_FRAMESIZE);
727
Initialize internal structures for CD device.
730
init_win32ioctl (_img_private_t *env)
737
ANSI_STRING filename;
738
OBJECT_ATTRIBUTES attributes;
739
IO_STATUS_BLOCK status;
743
unsigned int len=strlen(env->gen.source_name);
744
char psz_win32_drive[7];
745
DWORD dw_access_flags;
748
cdio_debug("using winNT/2K/XP ioctl layer");
751
memset(&ov,0,sizeof(OSVERSIONINFO));
752
ov.dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
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;
761
if (cdio_is_device_win32(env->gen.source_name))
764
// Use XBOX cdrom, no matter what drive letter is given.
765
RtlInitAnsiString(&filename,"\\Device\\Cdrom0");
766
InitializeObjectAttributes(&attributes, &filename, OBJ_CASE_INSENSITIVE,
768
error = NtCreateFile( &hDevice,
769
GENERIC_READ |SYNCHRONIZE | FILE_READ_ATTRIBUTES,
776
FILE_NON_DIRECTORY_FILE
777
| FILE_SYNCHRONOUS_IO_NONALERT );
779
if (!NT_SUCCESS(error))
783
env->h_device_handle = hDevice;
785
sprintf( psz_win32_drive, "\\\\.\\%c:", env->gen.source_name[len-2] );
787
env->h_device_handle = CreateFile( psz_win32_drive,
789
FILE_SHARE_READ | FILE_SHARE_WRITE,
792
FILE_ATTRIBUTE_NORMAL,
795
if( env->h_device_handle == INVALID_HANDLE_VALUE )
797
/* No good. try toggle write. */
798
dw_access_flags ^= GENERIC_WRITE;
799
env->h_device_handle = CreateFile( psz_win32_drive,
804
FILE_ATTRIBUTE_NORMAL,
806
if (env->h_device_handle == NULL)
810
env->b_ioctl_init = true;
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
822
read_fulltoc_win32mmc (_img_private_t *p_env)
824
mmc_cdb_t cdb = {{0, }};
825
CDROM_TOC_FULL cdrom_toc_full;
827
int i_track_format = 0;
831
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_READ_TOC);
836
cdb.field[2] = CDIO_MMC_READTOC_FMT_FULTOC;
838
memset(&cdrom_toc_full, 0, sizeof(cdrom_toc_full));
840
/* Setup to read header, to get length of data */
841
CDIO_MMC_SET_READ_LENGTH16(cdb.field, sizeof(cdrom_toc_full));
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);
848
if ( 0 != i_status ) {
849
cdio_debug ("SCSI MMC READ_TOC failed\n");
854
for( i = 0 ; i <= CDIO_CD_MAX_TRACKS+3; i++ ) {
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;
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;
870
j = cdrom_toc_full.TrackData[i].POINT;
872
/* Start position of the lead out */
873
p_env->tocent[ p_env->gen.i_tracks ].start_lsn =
876
cdrom_toc_full.TrackData[i].PMIN,
877
cdrom_toc_full.TrackData[i].PSEC,
878
cdrom_toc_full.TrackData[i].PFRAME
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;
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 =
892
cdrom_toc_full.TrackData[i].PMIN,
893
cdrom_toc_full.TrackData[i].PSEC,
894
cdrom_toc_full.TrackData[i].PFRAME
897
p_env->tocent[j-1].Control =
898
cdrom_toc_full.TrackData[i].Control;
899
p_env->tocent[j-1].Format = i_track_format;
901
set_track_flags(&(p_env->gen.track_flags[j]),
902
p_env->tocent[j-1].Control);
904
cdio_debug("p_sectors: %i, %lu", i,
905
(unsigned long int) (p_env->tocent[i].start_lsn));
907
if (cdrom_toc_full.TrackData[i].POINT == p_env->gen.i_tracks)
911
if ( 0x0F == i_seen_flag ) break;
913
if ( 0x0F == i_seen_flag ) {
914
p_env->gen.toc_init = true;
921
Read and cache the CD's Track Table of Contents and track info.
922
Return true if successful or false if an error.
925
read_toc_win32ioctl (_img_private_t *p_env)
928
DWORD dw_bytes_returned;
930
bool b_fulltoc_first; /* Do we do fulltoc or DeviceIoControl
932
if ( ! p_env ) return false;
936
For media other than CD, information may be fabricated in order
938
to emulate a CD structure for the specific media.
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.
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
950
Is this complicated enough? I could be wrong...
953
b_fulltoc_first = (CDIO_DISC_MODE_NO_INFO == dvd_discmode_win32ioctl(p_env));
955
if ( b_fulltoc_first && read_fulltoc_win32mmc(p_env) ) return true;
957
/* SCSI-MMC READ_TOC (FULTOC) read failed or we don't want to try it
958
initiaily. Try reading TOC via DeviceIoControl... */
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;
969
FORMAT_ERROR(i_err, psz_msg);
971
cdio_log(loglevel, "could not read TOC (%ld): %s", i_err, psz_msg);
974
cdio_log(loglevel, "could not read TOC (%ld)", i_err);
976
if ( !b_fulltoc_first && read_fulltoc_win32mmc(p_env) ) return true;
980
p_env->gen.i_first_track = cdrom_toc.FirstTrack;
981
p_env->gen.i_tracks = cdrom_toc.LastTrack - cdrom_toc.FirstTrack + 1;
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 =
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] )
991
p_env->tocent[i].Control = cdrom_toc.TrackData[i].Control;
992
p_env->tocent[i].Format = cdrom_toc.TrackData[i].Adr;
994
p_env->gen.track_flags[j].preemphasis =
995
p_env->tocent[i].Control & 0x1
996
? CDIO_TRACK_FLAG_TRUE : CDIO_TRACK_FLAG_FALSE;
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;
1002
p_env->gen.track_flags[j].channels =
1003
p_env->tocent[i].Control & 0x8 ? 4 : 2;
1006
cdio_debug("p_sectors: %i, %lu", i,
1007
(unsigned long int) (p_env->tocent[i].start_lsn));
1009
p_env->gen.toc_init = true;
1014
Return the media catalog number MCN.
1016
Note: string is malloc'd so caller should free() then returned
1017
string when done with it.
1021
get_mcn_win32ioctl (const _img_private_t *p_env) {
1023
DWORD dw_bytes_returned;
1024
SUB_Q_MEDIA_CATALOG_NUMBER mcn;
1025
CDROM_SUB_Q_DATA_FORMAT q_data_format;
1027
memset( &mcn, 0, sizeof(mcn) );
1029
q_data_format.Format = CDIO_SUBCHANNEL_MEDIA_CATALOG;
1031
/* MSDN info on CDROM_SUB_Q_DATA_FORMAT says if Format is set to
1032
get MCN, track must be set 0.
1034
q_data_format.Track=0;
1036
if( ! DeviceIoControl( p_env->h_device_handle,
1037
IOCTL_CDROM_READ_Q_CHANNEL,
1038
&q_data_format, sizeof(q_data_format),
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);
1048
Get the format (XA, DATA, AUDIO) of a track.
1051
get_track_format_win32ioctl(const _img_private_t *env, track_t i_track)
1053
/* This is pretty much copied from the "badly broken" cdrom_count_tracks
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;
1063
return TRACK_FORMAT_DATA;
1065
return TRACK_FORMAT_AUDIO;
1068
#endif /*HAVE_WIN32_CDROM*/