diff --git a/lib/MSWindows/aspi32.c b/lib/MSWindows/aspi32.c index 21d0ccbe..340df9ca 100644 --- a/lib/MSWindows/aspi32.c +++ b/lib/MSWindows/aspi32.c @@ -1,5 +1,5 @@ /* - $Id: aspi32.c,v 1.6 2004/05/16 13:33:28 rocky Exp $ + $Id: aspi32.c,v 1.7 2004/06/20 15:06:42 rocky Exp $ Copyright (C) 2004 Rocky Bernstein @@ -27,7 +27,7 @@ # include "config.h" #endif -static const char _rcsid[] = "$Id: aspi32.c,v 1.6 2004/05/16 13:33:28 rocky Exp $"; +static const char _rcsid[] = "$Id: aspi32.c,v 1.7 2004/06/20 15:06:42 rocky Exp $"; #include #include @@ -55,7 +55,7 @@ static const char _rcsid[] = "$Id: aspi32.c,v 1.6 2004/05/16 13:33:28 rocky Exp /* General ioctl() CD-ROM command function */ static bool -wnaspi32_mciSendCommand(int id, UINT msg, DWORD flags, void *arg) +mciSendCommand_aspi(int id, UINT msg, DWORD flags, void *arg) { MCIERROR mci_error; @@ -70,14 +70,14 @@ wnaspi32_mciSendCommand(int id, UINT msg, DWORD flags, void *arg) } const char * -wnaspi32_is_cdrom(const char drive_letter) +is_cdrom_aspi(const char drive_letter) { static char psz_win32_drive[7]; HMODULE hASPI = NULL; long (*lpGetSupport)( void ) = NULL; long (*lpSendCommand)( void* ) = NULL; DWORD dwSupportInfo; - int i_adapter, i_num_adapters; + int i_adapter, i_hostadapters; char c_drive; hASPI = LoadLibrary( "wnaspi32.dll" ); @@ -94,7 +94,7 @@ wnaspi32_is_cdrom(const char drive_letter) return NULL; } - /* ASPI support seems to be there */ + /* ASPI support seems to be there. */ dwSupportInfo = lpGetSupport(); @@ -110,15 +110,15 @@ wnaspi32_is_cdrom(const char drive_letter) return NULL; } - i_num_adapters = LOBYTE( LOWORD( dwSupportInfo ) ); - if( i_num_adapters == 0 ) { + i_hostadapters = LOBYTE( LOWORD( dwSupportInfo ) ); + if( i_hostadapters == 0 ) { FreeLibrary( hASPI ); return NULL; } c_drive = toupper(drive_letter) - 'A'; - for( i_adapter = 0; i_adapter < i_num_adapters; i_adapter++ ) { + for( i_adapter = 0; i_adapter < i_hostadapters; i_adapter++ ) { struct SRB_GetDiskInfo srbDiskInfo; int i_target; SRB_HAInquiry srbInquiry; @@ -147,7 +147,7 @@ wnaspi32_is_cdrom(const char drive_letter) if( (srbDiskInfo.SRB_Status == SS_COMP) && (srbDiskInfo.SRB_Int13HDriveInfo == c_drive) ) { - /* Make sure this is a cdrom device */ + /* Make sure this is a CD-ROM device. */ struct SRB_GDEVBlock srbGDEVBlock; memset( &srbGDEVBlock, 0, sizeof(struct SRB_GDEVBlock) ); @@ -175,13 +175,13 @@ wnaspi32_is_cdrom(const char drive_letter) Initialize CD device. */ bool -wnaspi32_init_win32 (_img_private_t *env) +init_aspi (_img_private_t *env) { HMODULE hASPI = NULL; long (*lpGetSupport)( void ) = NULL; long (*lpSendCommand)( void* ) = NULL; DWORD dwSupportInfo; - int i, j, i_num_adapters; + int i_adapter, i_hostadapters; char c_drive; if (2 == strlen(env->gen.source_name) && isalpha(env->gen.source_name[0]) ) @@ -206,7 +206,7 @@ wnaspi32_init_win32 (_img_private_t *env) return false; } - /* ASPI support seems to be there */ + /* ASPI support seems to be there. */ dwSupportInfo = lpGetSupport(); @@ -222,62 +222,73 @@ wnaspi32_init_win32 (_img_private_t *env) return false; } - i_num_adapters = LOBYTE( LOWORD( dwSupportInfo ) ); - if( i_num_adapters == 0 ) { + i_hostadapters = LOBYTE( LOWORD( dwSupportInfo ) ); + if( i_hostadapters == 0 ) { FreeLibrary( hASPI ); return false; } c_drive = toupper(c_drive) - 'A'; - for( i = 0; i < i_num_adapters; i++ ) { - for( j = 0; j < 15; j++ ) { - struct SRB_GetDiskInfo srbDiskInfo; - int lun; - - for (lun = 0; lun < 8; lun++ ) { - srbDiskInfo.SRB_Cmd = SC_GET_DISK_INFO; - srbDiskInfo.SRB_HaId = i; - srbDiskInfo.SRB_Flags = 0; - srbDiskInfo.SRB_Hdr_Rsvd = 0; - srbDiskInfo.SRB_Target = j; - srbDiskInfo.SRB_Lun = lun; - - lpSendCommand( (void*) &srbDiskInfo ); - - if( (srbDiskInfo.SRB_Status == SS_COMP) ) { + for( i_adapter = 0; i_adapter < i_hostadapters; i_adapter++ ) { + struct SRB_GetDiskInfo srbDiskInfo; + int i_target; + SRB_HAInquiry srbInquiry; + + srbInquiry.SRB_Cmd = SC_HA_INQUIRY; + srbInquiry.SRB_HaId = i_adapter; + + lpSendCommand( (void*) &srbInquiry ); + + if( srbInquiry.SRB_Status != SS_COMP ) continue; + if( !srbInquiry.HA_Unique[3]) srbInquiry.HA_Unique[3]=8; + + for(i_target=0; i_target < srbInquiry.HA_Unique[3]; i_target++) + { + int i_lun; + for (i_lun = 0; i_lun < 8; i_lun++ ) { + srbDiskInfo.SRB_Cmd = SC_GET_DISK_INFO; + srbDiskInfo.SRB_Flags = 0; + srbDiskInfo.SRB_Hdr_Rsvd = 0; + srbDiskInfo.SRB_HaId = i_adapter; + srbDiskInfo.SRB_Target = i_target; + srbDiskInfo.SRB_Lun = i_lun; - if (srbDiskInfo.SRB_Int13HDriveInfo != c_drive) - { - continue; - } else { - /* Make sure this is a cdrom device */ - struct SRB_GDEVBlock srbGDEVBlock; - - memset( &srbGDEVBlock, 0, sizeof(struct SRB_GDEVBlock) ); - srbGDEVBlock.SRB_Cmd = SC_GET_DEV_TYPE; - srbGDEVBlock.SRB_HaId = i; - srbGDEVBlock.SRB_Target = j; - - lpSendCommand( (void*) &srbGDEVBlock ); - - if( ( srbGDEVBlock.SRB_Status == SS_COMP ) && - ( srbGDEVBlock.SRB_DeviceType == DTYPE_CDROM ) ) { - env->i_sid = MAKEWORD( i, j ); - env->hASPI = (long)hASPI; - env->lpSendCommand = lpSendCommand; - env->b_aspi_init = true; - cdio_debug("Using ASPI layer"); - - return true; + lpSendCommand( (void*) &srbDiskInfo ); + + if( (srbDiskInfo.SRB_Status == SS_COMP) ) { + + if (srbDiskInfo.SRB_Int13HDriveInfo != c_drive) + { + continue; } else { - FreeLibrary( hASPI ); - cdio_debug( "%c: is not a CD-ROM drive", - env->gen.source_name[0] ); - return false; + /* Make sure this is a CD-ROM device. */ + struct SRB_GDEVBlock srbGDEVBlock; + + memset( &srbGDEVBlock, 0, sizeof(struct SRB_GDEVBlock) ); + srbGDEVBlock.SRB_Cmd = SC_GET_DEV_TYPE; + srbGDEVBlock.SRB_HaId = i_adapter; + srbGDEVBlock.SRB_Target = i_target; + + lpSendCommand( (void*) &srbGDEVBlock ); + + if( ( srbGDEVBlock.SRB_Status == SS_COMP ) && + ( srbGDEVBlock.SRB_DeviceType == DTYPE_CDROM ) ) { + env->i_sid = MAKEWORD( i_adapter, i_target ); + env->hASPI = (long)hASPI; + env->lpSendCommand = lpSendCommand; + env->b_aspi_init = true; + cdio_debug("Using ASPI layer"); + + return true; + } else { + FreeLibrary( hASPI ); + cdio_debug( "%c: is not a CD-ROM drive", + env->gen.source_name[0] ); + return false; + } } - } - } + } } } } @@ -292,21 +303,26 @@ wnaspi32_init_win32 (_img_private_t *env) Returns 0 if no error. */ static int -wnaspi32_mmc_read_sectors (_img_private_t *env, void *data, lsn_t lsn, - int sector_type, unsigned int nblocks) +mmc_read_sectors_aspi (const _img_private_t *env, void *data, lsn_t lsn, + int sector_type, unsigned int nblocks) { unsigned char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, }; HANDLE hEvent; struct SRB_ExecSCSICmd ssc; - -#if 1 + +#if 0 sector_type = 0; /*all types */ + /*sector_type = 1;*/ /* CD-DA */ + /*sector_type = 2;*/ /* mode1 */ + /*sector_type = 3;*/ /* mode2 */ + /*sector_type = 4;*/ /* mode2/form1 */ + /*sector_type = 5;*/ /* mode2/form2 */ +#endif int sync = 0; int header_code = 2; int i_user_data = 1; int edc_ecc = 0; int error_field = 0; -#endif /* Create the transfer completion event */ @@ -376,11 +392,13 @@ wnaspi32_mmc_read_sectors (_img_private_t *env, void *data, lsn_t lsn, Returns 0 if no error. */ int -wnaspi32_read_audio_sectors (_img_private_t *env, void *data, lsn_t lsn, +read_audio_sectors_aspi (_img_private_t *env, void *data, lsn_t lsn, unsigned int nblocks) { - return wnaspi32_mmc_read_sectors( env, data, lsn, CDIO_MMC_READ_TYPE_CDDA, - nblocks ); + if (mmc_read_sectors_aspi(env, data, lsn, CDIO_MMC_READ_TYPE_CDDA, 1)) { + return mmc_read_sectors_aspi(env, data, lsn, CDIO_MMC_READ_TYPE_ANY, 1); + } + return 0; } /*! @@ -388,10 +406,31 @@ wnaspi32_read_audio_sectors (_img_private_t *env, void *data, lsn_t lsn, from lsn. Returns 0 if no error. */ int -wnaspi32_read_mode2_sector (_img_private_t *env, void *data, lsn_t lsn) +read_mode2_sector_aspi (const _img_private_t *env, void *data, lsn_t lsn, + bool b_form2) { - return wnaspi32_mmc_read_sectors(env, data, lsn, CDIO_MMC_READ_TYPE_ANY, - 1); + + if (mmc_read_sectors_aspi(env, data, lsn, b_form2 + ? CDIO_MMC_READ_TYPE_M2F2 + : CDIO_MMC_READ_TYPE_M2F1, + 1)) { + return mmc_read_sectors_aspi(env, data, lsn, CDIO_MMC_READ_TYPE_ANY, 1); + } + return 0; +} + +/*! + Reads a single mode2 sector from cd device into data starting + from lsn. Returns 0 if no error. + */ +int +read_mode1_sector_aspi (const _img_private_t *env, void *data, lsn_t lsn, + bool b_form2) +{ + if (mmc_read_sectors_aspi(env, data, lsn, CDIO_MMC_READ_TYPE_MODE1, 1)) { + return mmc_read_sectors_aspi(env, data, lsn, CDIO_MMC_READ_TYPE_ANY, 1); + } + return 0; } /*! @@ -399,7 +438,7 @@ wnaspi32_read_mode2_sector (_img_private_t *env, void *data, lsn_t lsn) Return true if successful or false if an error. */ bool -wnaspi32_read_toc (_img_private_t *env) +read_toc_aspi (_img_private_t *env) { HANDLE hEvent; struct SRB_ExecSCSICmd ssc; @@ -434,8 +473,8 @@ wnaspi32_read_toc (_img_private_t *env) /* Allocation length and buffer */ ssc.SRB_BufLen = sizeof( p_tocheader ); ssc.SRB_BufPointer = p_tocheader; - ssc.CDBByte[ 7 ] = ( ssc.SRB_BufLen >> 8 ) & 0xff; - ssc.CDBByte[ 8 ] = ( ssc.SRB_BufLen ) & 0xff; + ssc.CDBByte[ 7 ] = (unsigned char) ( ssc.SRB_BufLen >> 8 ) & 0xff; + ssc.CDBByte[ 8 ] = (unsigned char) ( ssc.SRB_BufLen ) & 0xff; /* Initiate transfer */ ResetEvent( hEvent ); @@ -452,8 +491,8 @@ wnaspi32_read_toc (_img_private_t *env) return false; } - env->first_track_num = p_tocheader[2]; - env->total_tracks = p_tocheader[3] - p_tocheader[2] + 1; + env->i_first_track = p_tocheader[2]; + env->total_tracks = p_tocheader[3] - p_tocheader[2] + 1; { int i, i_toclength; @@ -473,8 +512,8 @@ wnaspi32_read_toc (_img_private_t *env) /* Allocation length and buffer */ ssc.SRB_BufLen = i_toclength; ssc.SRB_BufPointer = p_fulltoc; - ssc.CDBByte[ 7 ] = ( ssc.SRB_BufLen >> 8 ) & 0xff; - ssc.CDBByte[ 8 ] = ( ssc.SRB_BufLen ) & 0xff; + ssc.CDBByte[ 7 ] = (unsigned char) ( ssc.SRB_BufLen >> 8 ) & 0xff; + ssc.CDBByte[ 8 ] = (unsigned char) ( ssc.SRB_BufLen ) & 0xff; /* Initiate transfer */ ResetEvent( hEvent ); @@ -486,8 +525,10 @@ wnaspi32_read_toc (_img_private_t *env) WaitForSingleObject( hEvent, INFINITE ); /* check that the transfer went as planned */ +#if 0 if( ssc.SRB_Status != SS_COMP ) env->total_tracks = 0; +#endif for( i = 0 ; i <= env->total_tracks ; i++ ) { int i_index = 8 + 8 * i; @@ -536,13 +577,13 @@ wnaspi32_eject_media (void *user_data) { i_flags = MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID | MCI_OPEN_ELEMENT | MCI_OPEN_SHAREABLE; - if( wnaspi32_mciSendCommand( 0, MCI_OPEN, i_flags, &op ) ) { + if( mciSendCommand_aspi( 0, MCI_OPEN, i_flags, &op ) ) { st.dwItem = MCI_STATUS_READY; /* Eject disc */ - ret = wnaspi32_mciSendCommand( op.wDeviceID, MCI_SET, + ret = mciSendCommand_aspi( op.wDeviceID, MCI_SET, MCI_SET_DOOR_OPEN, 0 ) != 0; /* Release access to the device */ - wnaspi32_mciSendCommand( op.wDeviceID, MCI_CLOSE, MCI_WAIT, 0 ); + mciSendCommand_aspi( op.wDeviceID, MCI_CLOSE, MCI_WAIT, 0 ); } else ret = 0; @@ -550,11 +591,95 @@ wnaspi32_eject_media (void *user_data) { } #endif +/*! + Return the the kind of drive capabilities of device. + + Note: string is malloc'd so caller should free() then returned + string when done with it. + + */ +cdio_drive_cap_t +get_drive_cap_aspi (const _img_private_t *env) +{ + int32_t i_drivetype = CDIO_DRIVE_CAP_CD_AUDIO | CDIO_DRIVE_CAP_UNKNOWN; + unsigned char buf[192] = { 0, }; + + HANDLE hEvent; + struct SRB_ExecSCSICmd ssc; + + /* Create the transfer completion event */ + hEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); + if( hEvent == NULL ) { + return CDIO_DRIVE_CAP_ERROR; + } + + memset( &ssc, 0, sizeof( ssc ) ); + + /* If device supports SCSI-3, then we can get the CD drive + capabilities, i.e. ability to read/write to CD-ROM/R/RW + or/and read/write to DVD-ROM/R/RW. */ + + ssc.SRB_Cmd = SC_EXEC_SCSI_CMD; + ssc.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + ssc.SRB_HaId = LOBYTE( env->i_sid ); + ssc.SRB_Target = HIBYTE( env->i_sid ); + ssc.SRB_SenseLen = SENSE_LEN; + + ssc.SRB_PostProc = (LPVOID) hEvent; + ssc.SRB_CDBLen = 6; + + /* Operation code */ + CDIO_MMC_SET_COMMAND(ssc.CDBByte, CDIO_MMC_MODE_SENSE); + + /*ssc.CDBByte[1] = 0x08; /+ doesn't return block descriptors */ + ssc.CDBByte[1] = 0x0; + ssc.CDBByte[2] = 0x2a; /*MODE_PAGE_CAPABILITIES*/; + ssc.CDBByte[3] = 0; /* Not used */ + ssc.CDBByte[4] = 128; + ssc.CDBByte[5] = 0; /* Not used */ + + /* Allocation length and buffer */ + ssc.SRB_BufPointer = buf; + ssc.SRB_BufLen = sizeof( buf ); + + /* Initiate transfer */ + ResetEvent( hEvent ); + env->lpSendCommand( (void*) &ssc ); + + /* If the command has still not been processed, wait until it's + * finished */ + if( ssc.SRB_Status == SS_PENDING ) + WaitForSingleObject( hEvent, INFINITE ); + + /* check that the transfer went as planned */ + if( ssc.SRB_Status != SS_COMP ) { + CloseHandle( hEvent ); + return i_drivetype; + } + { + unsigned int n=buf[3]+4; + /* Reader? */ + if (buf[n+5] & 0x01) i_drivetype |= CDIO_DRIVE_CAP_CD_AUDIO; + if (buf[n+2] & 0x02) i_drivetype |= CDIO_DRIVE_CAP_CD_RW; + if (buf[n+2] & 0x08) i_drivetype |= CDIO_DRIVE_CAP_DVD; + + /* Writer? */ + if (buf[n+3] & 0x01) i_drivetype |= CDIO_DRIVE_CAP_CD_R; + if (buf[n+3] & 0x10) i_drivetype |= CDIO_DRIVE_CAP_DVD_R; + if (buf[n+3] & 0x20) i_drivetype |= CDIO_DRIVE_CAP_DVD_RAM; + + if (buf[n+6] & 0x08) i_drivetype |= CDIO_DRIVE_CAP_OPEN_TRAY; + if (buf[n+6] >> 5 != 0) + i_drivetype |= CDIO_DRIVE_CAP_CLOSE_TRAY; + } + return i_drivetype; +} + /*! Get format of track. */ track_format_t -wnaspi32_get_track_format(_img_private_t *env, track_t track_num) +get_track_format_aspi(const _img_private_t *env, track_t track_num) { MCI_OPEN_PARMS op; MCI_STATUS_PARMS st; @@ -569,14 +694,14 @@ wnaspi32_get_track_format(_img_private_t *env, track_t track_num) i_flags = MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID | MCI_OPEN_ELEMENT | MCI_OPEN_SHAREABLE; - if( wnaspi32_mciSendCommand( 0, MCI_OPEN, i_flags, &op ) ) { + if( mciSendCommand_aspi( 0, MCI_OPEN, i_flags, &op ) ) { st.dwItem = MCI_CDA_STATUS_TYPE_TRACK; st.dwTrack = track_num; i_flags = MCI_TRACK | MCI_STATUS_ITEM ; - ret = wnaspi32_mciSendCommand( op.wDeviceID, MCI_STATUS, i_flags, &st ); + ret = mciSendCommand_aspi( op.wDeviceID, MCI_STATUS, i_flags, &st ); /* Release access to the device */ - wnaspi32_mciSendCommand( op.wDeviceID, MCI_CLOSE, MCI_WAIT, 0 ); + mciSendCommand_aspi( op.wDeviceID, MCI_CLOSE, MCI_WAIT, 0 ); switch(st.dwReturn) { case MCI_CDA_TRACK_AUDIO: diff --git a/lib/MSWindows/win32.c b/lib/MSWindows/win32.c index 77296f7c..e9f5885c 100644 --- a/lib/MSWindows/win32.c +++ b/lib/MSWindows/win32.c @@ -1,5 +1,5 @@ /* - $Id: win32.c,v 1.16 2004/05/16 13:33:28 rocky Exp $ + $Id: win32.c,v 1.17 2004/06/20 15:06:42 rocky Exp $ Copyright (C) 2003, 2004 Rocky Bernstein @@ -26,7 +26,7 @@ # include "config.h" #endif -static const char _rcsid[] = "$Id: win32.c,v 1.16 2004/05/16 13:33:28 rocky Exp $"; +static const char _rcsid[] = "$Id: win32.c,v 1.17 2004/06/20 15:06:42 rocky Exp $"; #include #include @@ -94,9 +94,9 @@ str_to_access_mode_win32(const char *psz_access_mode) static const char * cdio_is_cdrom(const char drive_letter) { if ( WIN_NT ) { - return win32ioctl_is_cdrom(drive_letter); + return is_cdrom_win32ioctl (drive_letter); } else { - return wnaspi32_is_cdrom(drive_letter); + return is_cdrom_aspi(drive_letter); } } @@ -113,10 +113,10 @@ _cdio_get_drive_cap (const void *env) { if (_obj->hASPI) { /* A safe guess */ - return CDIO_DRIVE_CAP_UNKNOWN | CDIO_DRIVE_CAP_CD_AUDIO - | CDIO_DRIVE_CAP_CD_R ; + + return get_drive_cap_aspi (env); } else { - return win32ioctl_get_drive_cap (env); + return get_drive_cap_win32ioctl (env); } } @@ -145,9 +145,9 @@ _cdio_init_win32 (void *user_data) env->b_ioctl_init = false; if ( _AM_IOCTL == env->access_mode ) { - return win32ioctl_init_win32(env); + return init_win32ioctl(env); } else { - return wnaspi32_init_win32(env); + return init_aspi(env); } } @@ -180,9 +180,9 @@ _cdio_read_audio_sectors (void *user_data, void *data, lsn_t lsn, { _img_private_t *env = user_data; if ( env->hASPI ) { - return wnaspi32_read_audio_sectors( env, data, lsn, nblocks ); + return read_audio_sectors_aspi( env, data, lsn, nblocks ); } else { - return win32ioctl_read_audio_sectors( env, data, lsn, nblocks ); + return read_audio_sectors_win32ioctl( env, data, lsn, nblocks ); } } @@ -211,9 +211,9 @@ _cdio_read_mode1_sector (void *user_data, void *data, lsn_t lsn, env->gen.ioctls_debugged++; if ( env->hASPI ) { - return 1; + return read_mode1_sector_aspi( env, data, lsn, b_form2 ); } else { - return win32ioctl_read_mode1_sector( env, data, lsn, b_form2 ); + return read_mode1_sector_win32ioctl( env, data, lsn, b_form2 ); } } @@ -275,7 +275,7 @@ _cdio_read_mode2_sector (void *user_data, void *data, lsn_t lsn, if ( env->hASPI ) { int ret; - ret = wnaspi32_read_mode2_sector(user_data, buf, lsn); + ret = read_mode2_sector_aspi(user_data, buf, lsn, 1); if( ret != 0 ) return ret; if (b_form2) memcpy (data, buf, M2RAW_SECTOR_SIZE); @@ -283,7 +283,7 @@ _cdio_read_mode2_sector (void *user_data, void *data, lsn_t lsn, memcpy (((char *)data), buf + CDIO_CD_SUBHEADER_SIZE, CDIO_CD_FRAMESIZE); return 0; } else { - return win32ioctl_read_mode2_sector( env, data, lsn, b_form2 ); + return read_mode2_sector_win32ioctl( env, data, lsn, b_form2 ); } } @@ -341,9 +341,9 @@ _set_arg_win32 (void *user_data, const char key[], const char value[]) { env->access_mode = str_to_access_mode_win32(value); if (env->access_mode == _AM_ASPI && !env->b_aspi_init) - return wnaspi32_init_win32(env) ? 1 : -3; + return init_aspi(env) ? 1 : -3; else if (env->access_mode == _AM_IOCTL && !env->b_ioctl_init) - return win32ioctl_init_win32(env) ? 1 : -3; + return init_win32ioctl(env) ? 1 : -3; else return -4; return 0; @@ -363,9 +363,9 @@ _cdio_read_toc (_img_private_t *env) { bool ret; if( env->hASPI ) { - ret = wnaspi32_read_toc( env ); + ret = read_toc_aspi( env ); } else { - ret =win32ioctl_read_toc(env); + ret = read_toc_win32ioctl( env ); } if (ret) env->gen.toc_init = true ; return true; @@ -438,7 +438,7 @@ _cdio_get_first_track_num(void *user_data) if (!env->toc_init) _cdio_read_toc (env) ; - return env->first_track_num; + return env->i_first_track; } /*! @@ -454,7 +454,7 @@ _cdio_get_mcn (const void *env) { const _img_private_t *_env = env; if( ! _env->hASPI ) { - return win32ioctl_get_mcn(_env); + return get_mcn_win32ioctl(_env); } return NULL; } @@ -487,9 +487,9 @@ _cdio_get_track_format(void *obj, track_t track_num) return TRACK_FORMAT_ERROR; if( env->hASPI ) { - return wnaspi32_get_track_format(env, track_num); + return get_track_format_aspi(env, track_num); } else { - return win32ioctl_get_track_format(env, track_num); + return get_track_format_win32ioctl(env, track_num); } } @@ -502,22 +502,27 @@ _cdio_get_track_format(void *obj, track_t track_num) FIXME: there's gotta be a better design for this and get_track_format? */ static bool -_cdio_get_track_green(void *obj, track_t track_num) +_cdio_get_track_green(void *obj, track_t i_track) { _img_private_t *env = obj; if (!env->toc_init) _cdio_read_toc (env) ; - if (track_num == CDIO_CDROM_LEADOUT_TRACK) track_num = env->total_tracks+1; + if (i_track == CDIO_CDROM_LEADOUT_TRACK) i_track = env->total_tracks+1; - if (track_num > env->total_tracks+1 || track_num == 0) + if (i_track > env->total_tracks+1 || i_track == 0) return false; - switch (_cdio_get_track_format(env, track_num)) { + switch (_cdio_get_track_format(env, i_track)) { + case TRACK_FORMAT_XA: + return true; case TRACK_FORMAT_ERROR: case TRACK_FORMAT_CDI: case TRACK_FORMAT_AUDIO: return false; + case TRACK_FORMAT_DATA: + if (_AM_ASPI == env->access_mode ) + return false; default: break; } @@ -525,7 +530,7 @@ _cdio_get_track_green(void *obj, track_t track_num) /* FIXME: Dunno if this is the right way, but it's what I was using in cd-info for a while. */ - return ((env->tocent[track_num-1].Control & 2) != 0); + return ((env->tocent[i_track-1].Control & 2) != 0); } /*! diff --git a/lib/MSWindows/win32.h b/lib/MSWindows/win32.h index 18cd0d07..b6637cea 100644 --- a/lib/MSWindows/win32.h +++ b/lib/MSWindows/win32.h @@ -1,110 +1,133 @@ -/* - $Id: win32.h,v 1.4 2004/04/30 07:33:51 rocky Exp $ - - Copyright (C) 2004 Rocky Bernstein - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include "cdio_private.h" - -#pragma pack() - -typedef struct { - lsn_t start_lsn; - UCHAR Control : 4; - UCHAR Format; -} track_info_t; - -typedef enum { - _AM_NONE, - _AM_IOCTL, - _AM_ASPI, -} access_mode_t; - -typedef struct { - /* Things common to all drivers like this. - This must be first. */ - generic_img_private_t gen; - - access_mode_t access_mode; - - bool b_ioctl_init; - bool b_aspi_init; - - HANDLE h_device_handle; /* device descriptor */ - long hASPI; - short i_sid; - long (*lpSendCommand)( void* ); - - /* Track information */ - bool toc_init; /* if true, info below is valid. */ - track_info_t tocent[100]; /* entry info for each track */ - track_t total_tracks; /* number of tracks in image */ - track_t first_track_num; /* track number of first track */ - -} _img_private_t; - -/*! - Reads an audio device using the DeviceIoControl method into data - starting from lsn. Returns 0 if no error. - */ -int win32ioctl_read_audio_sectors (_img_private_t *obj, void *data, lsn_t lsn, - unsigned int nblocks); -/*! - Reads a single mode2 sector using the DeviceIoControl method into - data starting from lsn. Returns 0 if no error. - */ -int -win32ioctl_read_mode2_sector (_img_private_t *env, void *data, lsn_t lsn, - bool mode2_form2); - -/*! - Reads a single mode1 sector using the DeviceIoControl method into - data starting from lsn. Returns 0 if no error. - */ -int -win32ioctl_read_mode1_sector (_img_private_t *env, void *data, lsn_t lsn, - bool mode2_form2); - -const char *win32ioctl_is_cdrom(const char drive_letter); - -/*! - Initialize internal structures for CD device. - */ -bool win32ioctl_init_win32 (_img_private_t *env); - -/*! - Read and cache the CD's Track Table of Contents and track info. - Return true if successful or false if an error. -*/ -bool win32ioctl_read_toc (_img_private_t *env); - -char *win32ioctl_get_mcn (const _img_private_t *env); - -/*! - Return the the kind of drive capabilities of device. - - Note: string is malloc'd so caller should free() then returned - string when done with it. - - */ -cdio_drive_cap_t win32ioctl_get_drive_cap (const void *env); - -/*! - Get the format (XA, DATA, AUDIO) of a track. -*/ -track_format_t win32ioctl_get_track_format(_img_private_t *env, - track_t track_num); +/* + $Id: win32.h,v 1.5 2004/06/20 15:06:42 rocky Exp $ + + Copyright (C) 2004 Rocky Bernstein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "cdio_private.h" + +#pragma pack() + +typedef struct { + lsn_t start_lsn; + UCHAR Control : 4; + UCHAR Format; +} track_info_t; + +typedef enum { + _AM_NONE, + _AM_IOCTL, + _AM_ASPI, +} access_mode_t; + +typedef struct { + /* Things common to all drivers like this. + This must be first. */ + generic_img_private_t gen; + + access_mode_t access_mode; + + bool b_ioctl_init; + bool b_aspi_init; + + HANDLE h_device_handle; /* device descriptor */ + long hASPI; + short i_sid; + long (*lpSendCommand)( void* ); + + /* Track information */ + bool toc_init; /* if true, info below is valid. */ + track_info_t tocent[100]; /* entry info for each track */ + track_t total_tracks; /* number of tracks in image */ + track_t i_first_track; /* track number of first track */ + +} _img_private_t; + +/*! + Reads an audio device using the DeviceIoControl method into data + starting from lsn. Returns 0 if no error. + */ +int read_audio_sectors_aspi (_img_private_t *obj, void *data, lsn_t lsn, + unsigned int nblocks); +/*! + Reads an audio device using the DeviceIoControl method into data + starting from lsn. Returns 0 if no error. + */ +int read_audio_sectors_win32ioctl (_img_private_t *obj, void *data, lsn_t lsn, + unsigned int nblocks); +/*! + Reads a single mode2 sector using the DeviceIoControl method into + data starting from lsn. Returns 0 if no error. + */ +int read_mode2_sector_aspi (const _img_private_t *env, void *data, lsn_t lsn, + bool b_form2); +int read_mode2_sector_win32ioctl (const _img_private_t *env, void *data, + lsn_t lsn, bool b_form2); + +/*! + Reads a single mode1 sector using the DeviceIoControl method into + data starting from lsn. Returns 0 if no error. + */ +int read_mode1_sector_aspi (const _img_private_t *env, void *data, + lsn_t lsn, bool b_form2); +int read_mode1_sector_win32ioctl (const _img_private_t *env, void *data, + lsn_t lsn, bool b_form2); + +const char *is_cdrom_aspi(const char drive_letter); +const char *is_cdrom_win32ioctl (const char drive_letter); + +/*! + Initialize internal structures for CD device. + */ +bool init_aspi (_img_private_t *env); +bool init_win32ioctl (_img_private_t *env); + +/*! + Read and cache the CD's Track Table of Contents and track info. + Return true if successful or false if an error. +*/ +bool read_toc_win32ioctl (_img_private_t *env); +bool read_toc_aspi (_img_private_t *env); + +char *get_mcn_win32ioctl (const _img_private_t *env); + +/*! + Return the the kind of drive capabilities of device. + + Note: string is malloc'd so caller should free() then returned + string when done with it. + + */ +cdio_drive_cap_t get_drive_cap_aspi (const _img_private_t *env); + +/*! + Return the the kind of drive capabilities of device. + + Note: string is malloc'd so caller should free() then returned + string when done with it. + + */ +cdio_drive_cap_t get_drive_cap_win32ioctl (const _img_private_t *env); + +/*! + Get the format (XA, DATA, AUDIO) of a track. +*/ +track_format_t get_track_format_win32ioctl(const _img_private_t *env, + track_t i_track); + +track_format_t get_track_format_aspi(const _img_private_t *env, + track_t i_track); diff --git a/lib/MSWindows/win32_ioctl.c b/lib/MSWindows/win32_ioctl.c index 1eea0015..80e383df 100644 --- a/lib/MSWindows/win32_ioctl.c +++ b/lib/MSWindows/win32_ioctl.c @@ -1,511 +1,510 @@ -/* - $Id: win32_ioctl.c,v 1.3 2004/05/10 03:28:57 rocky Exp $ - - Copyright (C) 2004 Rocky Bernstein - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* This file contains Win32-specific code using the DeviceIoControl - access method. -*/ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -static const char _rcsid[] = "$Id: win32_ioctl.c,v 1.3 2004/05/10 03:28:57 rocky Exp $"; - -#include -#include -#include "cdio_assert.h" - -#ifdef HAVE_WIN32_CDROM - -#include -#include -#include -#include - -#include -#include /* offsetof() macro */ -#include -#include -#include - -/* Win32 DeviceIoControl specifics */ -/***** FIXME: #include ntddcdrm.h from Wine, but probably need to - modify it a little. -*/ - -#ifndef IOCTL_CDROM_BASE -# define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM -#endif -#ifndef IOCTL_CDROM_READ_TOC -#define IOCTL_CDROM_READ_TOC \ - CTL_CODE(IOCTL_CDROM_BASE, 0x0000, METHOD_BUFFERED, FILE_READ_ACCESS) -#endif -#ifndef IOCTL_CDROM_RAW_READ -#define IOCTL_CDROM_RAW_READ CTL_CODE(IOCTL_CDROM_BASE, 0x000F, \ - METHOD_OUT_DIRECT, FILE_READ_ACCESS) -#endif - -#ifndef IOCTL_CDROM_READ_Q_CHANNEL -#define IOCTL_CDROM_READ_Q_CHANNEL \ - CTL_CODE(IOCTL_CDROM_BASE, 0x000B, METHOD_BUFFERED, FILE_READ_ACCESS) -#endif - -typedef struct { - SCSI_PASS_THROUGH Spt; - ULONG Filler; - UCHAR SenseBuf[32]; - UCHAR DataBuf[512]; -} SCSI_PASS_THROUGH_WITH_BUFFERS; - -typedef struct _TRACK_DATA { - UCHAR Format; - UCHAR Control : 4; - UCHAR Adr : 4; - UCHAR TrackNumber; - UCHAR Reserved1; - UCHAR Address[4]; -} TRACK_DATA, *PTRACK_DATA; - -typedef struct _CDROM_TOC { - UCHAR Length[2]; - UCHAR FirstTrack; - UCHAR LastTrack; - TRACK_DATA TrackData[CDIO_CD_MAX_TRACKS+1]; -} CDROM_TOC, *PCDROM_TOC; - -#define IOCTL_CDROM_SUB_Q_CHANNEL 0x00 -#define IOCTL_CDROM_CURRENT_POSITION 0x01 -#define IOCTL_CDROM_MEDIA_CATALOG 0x02 -#define IOCTL_CDROM_TRACK_ISRC 0x03 - -typedef enum _TRACK_MODE_TYPE { - YellowMode2, - XAForm2, - CDDA -} TRACK_MODE_TYPE, *PTRACK_MODE_TYPE; - -typedef struct __RAW_READ_INFO { - LARGE_INTEGER DiskOffset; - ULONG SectorCount; - TRACK_MODE_TYPE TrackMode; -} RAW_READ_INFO, *PRAW_READ_INFO; - -typedef struct _CDROM_SUB_Q_DATA_FORMAT { - UCHAR Format; - UCHAR Track; -} CDROM_SUB_Q_DATA_FORMAT, *PCDROM_SUB_Q_DATA_FORMAT; - -typedef struct _SUB_Q_HEADER { - UCHAR Reserved; - UCHAR AudioStatus; - UCHAR DataLength[2]; -} SUB_Q_HEADER, *PSUB_Q_HEADER; - -typedef struct _SUB_Q_MEDIA_CATALOG_NUMBER { - SUB_Q_HEADER Header; - UCHAR FormatCode; - UCHAR Reserved[3]; - UCHAR Reserved1 : 7; - UCHAR Mcval :1; - UCHAR MediaCatalog[15]; -} SUB_Q_MEDIA_CATALOG_NUMBER, *PSUB_Q_MEDIA_CATALOG_NUMBER; - -#include "win32.h" - -/* - Returns a string that can be used in a CreateFile call if - c_drive letter is a character. If not NULL is returned. - */ - -const char * -win32ioctl_is_cdrom(const char c_drive_letter) -{ - - UINT uDriveType; - char sz_win32_drive[4]; - - sz_win32_drive[0]= c_drive_letter; - sz_win32_drive[1]=':'; - sz_win32_drive[2]='\\'; - sz_win32_drive[3]='\0'; - - uDriveType = GetDriveType(sz_win32_drive); - - switch(uDriveType) { - case DRIVE_CDROM: { - char sz_win32_drive_full[] = "\\\\.\\X:"; - sz_win32_drive_full[4] = c_drive_letter; - return strdup(sz_win32_drive_full); - } - default: - cdio_debug("Drive %c is not a CD-ROM", c_drive_letter); - return NULL; - } -} - -/*! - Reads an audio device using the DeviceIoControl method into data - starting from lsn. Returns 0 if no error. - */ -int -win32ioctl_read_audio_sectors (_img_private_t *env, void *data, lsn_t lsn, - unsigned int nblocks) -{ - DWORD dwBytesReturned; - RAW_READ_INFO cdrom_raw; - - /* Initialize CDROM_RAW_READ structure */ - cdrom_raw.DiskOffset.QuadPart = CDIO_CD_FRAMESIZE_RAW * lsn; - cdrom_raw.SectorCount = nblocks; - cdrom_raw.TrackMode = CDDA; - - if( DeviceIoControl( env->h_device_handle, - IOCTL_CDROM_RAW_READ, &cdrom_raw, - sizeof(RAW_READ_INFO), data, - CDIO_CD_FRAMESIZE_RAW * nblocks, - &dwBytesReturned, NULL ) == 0 ) { - cdio_info("Error reading audio-mode %lu (%ld)\n", - (long unsigned int) lsn, GetLastError()); - return 1; - } - return 0; -} - -/*! - Reads a single raw sector using the DeviceIoControl method into - data starting from lsn. Returns 0 if no error. - */ -static int -win32ioctl_read_raw_sector (_img_private_t *env, void *buf, lsn_t lsn) -{ - SCSI_PASS_THROUGH_DIRECT sptd; - BOOL success; - DWORD dwBytesReturned; - - sptd.Length=sizeof(sptd); - sptd.PathId=0; /* SCSI card ID will be filled in automatically */ - sptd.TargetId=0; /* SCSI target ID will also be filled in */ - sptd.Lun=0; /* SCSI lun ID will also be filled in */ - sptd.CdbLength=12; /* CDB size is 12 for ReadCD MMC1 command */ - sptd.SenseInfoLength=0; /* Don't return any sense data */ - sptd.DataIn = SCSI_IOCTL_DATA_IN; - sptd.DataTransferLength= CDIO_CD_FRAMESIZE_RAW; - sptd.TimeOutValue=60; /*SCSI timeout value (60 seconds - - maybe it should be longer) */ - sptd.DataBuffer= (PVOID) buf; - sptd.SenseInfoOffset=0; - - /* ReadCD CDB12 command. The values were taken from MMC1 draft paper. */ - CDIO_MMC_SET_COMMAND(sptd.Cdb, CDIO_MMC_GPCMD_READ_CD); - - CDIO_MMC_SET_READ_LBA(sptd.Cdb, lsn); - CDIO_MMC_SET_READ_LENGTH(sptd.Cdb, 1); - - sptd.Cdb[9]=0xF8; /* Raw read, 2352 bytes per sector */ - sptd.Cdb[10]=0; - sptd.Cdb[11]=0; - sptd.Cdb[12]=0; - sptd.Cdb[13]=0; - sptd.Cdb[14]=0; - sptd.Cdb[15]=0; - - /* Send the command to drive */ - success=DeviceIoControl(env->h_device_handle, - IOCTL_SCSI_PASS_THROUGH_DIRECT, - (PVOID)&sptd, - (DWORD)sizeof(SCSI_PASS_THROUGH_DIRECT), - NULL, 0, - &dwBytesReturned, - NULL); - - if(! success) { - cdio_info("Error reading %lu (%ld)\n", (long unsigned) lsn, - GetLastError()); - return 1; - } - - return 0; -} - -/*! - Reads a single mode2 sector using the DeviceIoControl method into - data starting from lsn. Returns 0 if no error. - */ -int -win32ioctl_read_mode2_sector (_img_private_t *env, void *data, lsn_t lsn, - bool mode2_form2) -{ - char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, }; - int ret = win32ioctl_read_raw_sector (env, buf, lsn); - - if ( 0 != ret) return ret; - - memcpy (data, - buf + CDIO_CD_SYNC_SIZE + CDIO_CD_XA_HEADER, - mode2_form2 ? M2RAW_SECTOR_SIZE: CDIO_CD_FRAMESIZE); - - return 0; - -} - -/*! - Reads a single mode2 sector using the DeviceIoControl method into - data starting from lsn. Returns 0 if no error. - */ -int -win32ioctl_read_mode1_sector (_img_private_t *env, void *data, lsn_t lsn, - bool mode2_form2) -{ - char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, }; - int ret = win32ioctl_read_raw_sector (env, buf, lsn); - - if ( 0 != ret) return ret; - - memcpy (data, - buf + CDIO_CD_SYNC_SIZE+CDIO_CD_HEADER_SIZE, - mode2_form2 ? M2RAW_SECTOR_SIZE: CDIO_CD_FRAMESIZE); - - return 0; - -} - -/*! - Initialize internal structures for CD device. - */ -bool -win32ioctl_init_win32 (_img_private_t *env) -{ - char psz_win32_drive[7]; - unsigned int len=strlen(env->gen.source_name); - OSVERSIONINFO ov; - DWORD dw_access_flags; - - cdio_debug("using winNT/2K/XP ioctl layer"); - - memset(&ov,0,sizeof(OSVERSIONINFO)); - ov.dwOSVersionInfoSize=sizeof(OSVERSIONINFO); - GetVersionEx(&ov); - - if((ov.dwPlatformId==VER_PLATFORM_WIN32_NT) && - (ov.dwMajorVersion>4)) - dw_access_flags = GENERIC_READ|GENERIC_WRITE; /* add gen write on W2k/XP */ - else dw_access_flags = GENERIC_READ; - - if (cdio_is_device_win32(env->gen.source_name)) { - sprintf( psz_win32_drive, "\\\\.\\%c:", env->gen.source_name[len-2] ); - - env->h_device_handle = CreateFile( psz_win32_drive, - dw_access_flags, - FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - NULL ); - if( env->h_device_handle == INVALID_HANDLE_VALUE ) - { - /* No good. try toggle write. */ - dw_access_flags ^= GENERIC_WRITE; - env->h_device_handle = CreateFile( psz_win32_drive, - dw_access_flags, - FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - NULL ); - return (env->h_device_handle == NULL) ? false : true; - } - env->b_ioctl_init = true; - return true; - } - return false; -} - -#define MSF_TO_LBA2(min, sec, frame) \ - ((int) frame + CDIO_CD_FRAMES_PER_SEC * (CDIO_CD_SECS_PER_MIN*min + sec) \ - - CDIO_PREGAP_SECTORS ) - -/*! - Read and cache the CD's Track Table of Contents and track info. - Return true if successful or false if an error. -*/ -bool -win32ioctl_read_toc (_img_private_t *env) -{ - - DWORD dwBytesReturned; - CDROM_TOC cdrom_toc; - int i; - - if( DeviceIoControl( env->h_device_handle, - IOCTL_CDROM_READ_TOC, - NULL, 0, &cdrom_toc, sizeof(CDROM_TOC), - &dwBytesReturned, NULL ) == 0 ) { - cdio_warn( "could not read TOCHDR: %ld" , (long int) GetLastError()); - return false; - } - - env->first_track_num = cdrom_toc.FirstTrack; - env->total_tracks = cdrom_toc.LastTrack - cdrom_toc.FirstTrack + 1; - - - for( i = 0 ; i <= env->total_tracks ; i++ ) { - env->tocent[ i ].start_lsn = MSF_TO_LBA2( - cdrom_toc.TrackData[i].Address[1], - cdrom_toc.TrackData[i].Address[2], - cdrom_toc.TrackData[i].Address[3] ); - env->tocent[ i ].Control = cdrom_toc.TrackData[i].Control; - env->tocent[ i ].Format = cdrom_toc.TrackData[i].Format; - cdio_debug("p_sectors: %i, %lu", i, - (unsigned long int) (env->tocent[i].start_lsn)); - } - env->gen.toc_init = true; - return true; -} - -/*! - Return the media catalog number MCN. - - Note: string is malloc'd so caller should free() then returned - string when done with it. - - */ -char * -win32ioctl_get_mcn (const _img_private_t *env) { - - DWORD dwBytesReturned; - SUB_Q_MEDIA_CATALOG_NUMBER mcn; - CDROM_SUB_Q_DATA_FORMAT q_data_format; - - memset( &mcn, 0, sizeof(mcn) ); - - q_data_format.Format = IOCTL_CDROM_MEDIA_CATALOG; - - q_data_format.Track=1; - - if( DeviceIoControl( env->h_device_handle, - IOCTL_CDROM_READ_Q_CHANNEL, - &q_data_format, sizeof(q_data_format), - &mcn, sizeof(mcn), - &dwBytesReturned, NULL ) == 0 ) { - cdio_warn( "could not read Q Channel at track %d", 1); - } else if (mcn.Mcval) - return strdup(mcn.MediaCatalog); - return NULL; -} - -/*! - Get the format (XA, DATA, AUDIO) of a track. -*/ -track_format_t -win32ioctl_get_track_format(_img_private_t *env, track_t track_num) -{ - /* This is pretty much copied from the "badly broken" cdrom_count_tracks - in linux/cdrom.c. - */ - if (env->tocent[track_num-1].Control & 0x04) { - if (env->tocent[track_num-1].Format == 0x10) - return TRACK_FORMAT_CDI; - else if (env->tocent[track_num-1].Format == 0x20) - return TRACK_FORMAT_XA; - else - return TRACK_FORMAT_DATA; - } else - return TRACK_FORMAT_AUDIO; -} - - -/*! - Return the the kind of drive capabilities of device. - - Note: string is malloc'd so caller should free() then returned - string when done with it. - - */ -cdio_drive_cap_t -win32ioctl_get_drive_cap (const void *env) -{ - const _img_private_t *_obj = env; - int32_t i_drivetype = 0; - SCSI_PASS_THROUGH_WITH_BUFFERS sptwb; - ULONG returned = 0; - ULONG length; - - /* If device supports SCSI-3, then we can get the CD drive - capabilities, i.e. ability to read/write to CD-ROM/R/RW - or/and read/write to DVD-ROM/R/RW. */ - - memset(&sptwb,0, sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS)); - - sptwb.Spt.Length = sizeof(SCSI_PASS_THROUGH); - sptwb.Spt.PathId = 0; - sptwb.Spt.TargetId = 1; - sptwb.Spt.Lun = 0; - sptwb.Spt.CdbLength = 6; /* CDB6GENERIC_LENGTH; */ - sptwb.Spt.SenseInfoLength = 24; - sptwb.Spt.DataIn = SCSI_IOCTL_DATA_IN; - sptwb.Spt.DataTransferLength = 192; - sptwb.Spt.TimeOutValue = 2; - sptwb.Spt.DataBufferOffset = - offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,DataBuf); - sptwb.Spt.SenseInfoOffset = - offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,SenseBuf); - - CDIO_MMC_SET_COMMAND(sptwb.Spt.Cdb, CDIO_MMC_MODE_SENSE); - /*sptwb.Spt.Cdb[1] = 0x08; /+ doesn't return block descriptors */ - sptwb.Spt.Cdb[1] = 0x0; - sptwb.Spt.Cdb[2] = 0x2a; /*MODE_PAGE_CAPABILITIES*/; - sptwb.Spt.Cdb[3] = 0; /* Not used */ - sptwb.Spt.Cdb[4] = 128; - sptwb.Spt.Cdb[5] = 0; /* Not used */ - length = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,DataBuf) + - sptwb.Spt.DataTransferLength; - - if ( DeviceIoControl(_obj->h_device_handle, - IOCTL_SCSI_PASS_THROUGH, - &sptwb, - sizeof(SCSI_PASS_THROUGH), - &sptwb, - length, - &returned, - FALSE) ) - { - unsigned int n=sptwb.DataBuf[3]+4; - /* Reader? */ - if (sptwb.DataBuf[n+5] & 0x01) i_drivetype |= CDIO_DRIVE_CAP_CD_AUDIO; - if (sptwb.DataBuf[n+2] & 0x02) i_drivetype |= CDIO_DRIVE_CAP_CD_RW; - if (sptwb.DataBuf[n+2] & 0x08) i_drivetype |= CDIO_DRIVE_CAP_DVD; - - /* Writer? */ - if (sptwb.DataBuf[n+3] & 0x01) i_drivetype |= CDIO_DRIVE_CAP_CD_R; - if (sptwb.DataBuf[n+3] & 0x10) i_drivetype |= CDIO_DRIVE_CAP_DVD_R; - if (sptwb.DataBuf[n+3] & 0x20) i_drivetype |= CDIO_DRIVE_CAP_DVD_RAM; - - if (sptwb.DataBuf[n+6] & 0x08) i_drivetype |= CDIO_DRIVE_CAP_OPEN_TRAY; - if (sptwb.DataBuf[n+6] >> 5 != 0) - i_drivetype |= CDIO_DRIVE_CAP_CLOSE_TRAY; - - return i_drivetype; - } else { - i_drivetype = CDIO_DRIVE_CAP_CD_AUDIO | CDIO_DRIVE_CAP_UNKNOWN; - } - return CDIO_DRIVE_CAP_ERROR; -} - -#endif /*HAVE_WIN32_CDROM*/ +/* + $Id: win32_ioctl.c,v 1.4 2004/06/20 15:06:42 rocky Exp $ + + Copyright (C) 2004 Rocky Bernstein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* This file contains Win32-specific code using the DeviceIoControl + access method. +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +static const char _rcsid[] = "$Id: win32_ioctl.c,v 1.4 2004/06/20 15:06:42 rocky Exp $"; + +#include +#include +#include "cdio_assert.h" + +#ifdef HAVE_WIN32_CDROM + +#include +#include +#include +#include + +#include +#include /* offsetof() macro */ +#include +#include +#include + +/* Win32 DeviceIoControl specifics */ +/***** FIXME: #include ntddcdrm.h from Wine, but probably need to + modify it a little. +*/ + +#ifndef IOCTL_CDROM_BASE +# define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM +#endif +#ifndef IOCTL_CDROM_READ_TOC +#define IOCTL_CDROM_READ_TOC \ + CTL_CODE(IOCTL_CDROM_BASE, 0x0000, METHOD_BUFFERED, FILE_READ_ACCESS) +#endif +#ifndef IOCTL_CDROM_RAW_READ +#define IOCTL_CDROM_RAW_READ CTL_CODE(IOCTL_CDROM_BASE, 0x000F, \ + METHOD_OUT_DIRECT, FILE_READ_ACCESS) +#endif + +#ifndef IOCTL_CDROM_READ_Q_CHANNEL +#define IOCTL_CDROM_READ_Q_CHANNEL \ + CTL_CODE(IOCTL_CDROM_BASE, 0x000B, METHOD_BUFFERED, FILE_READ_ACCESS) +#endif + +typedef struct { + SCSI_PASS_THROUGH Spt; + ULONG Filler; + UCHAR SenseBuf[32]; + UCHAR DataBuf[512]; +} SCSI_PASS_THROUGH_WITH_BUFFERS; + +typedef struct _TRACK_DATA { + UCHAR Format; + UCHAR Control : 4; + UCHAR Adr : 4; + UCHAR TrackNumber; + UCHAR Reserved1; + UCHAR Address[4]; +} TRACK_DATA, *PTRACK_DATA; + +typedef struct _CDROM_TOC { + UCHAR Length[2]; + UCHAR FirstTrack; + UCHAR LastTrack; + TRACK_DATA TrackData[CDIO_CD_MAX_TRACKS+1]; +} CDROM_TOC, *PCDROM_TOC; + +#define IOCTL_CDROM_SUB_Q_CHANNEL 0x00 +#define IOCTL_CDROM_CURRENT_POSITION 0x01 +#define IOCTL_CDROM_MEDIA_CATALOG 0x02 +#define IOCTL_CDROM_TRACK_ISRC 0x03 + +typedef enum _TRACK_MODE_TYPE { + YellowMode2, + XAForm2, + CDDA +} TRACK_MODE_TYPE, *PTRACK_MODE_TYPE; + +typedef struct __RAW_READ_INFO { + LARGE_INTEGER DiskOffset; + ULONG SectorCount; + TRACK_MODE_TYPE TrackMode; +} RAW_READ_INFO, *PRAW_READ_INFO; + +typedef struct _CDROM_SUB_Q_DATA_FORMAT { + UCHAR Format; + UCHAR Track; +} CDROM_SUB_Q_DATA_FORMAT, *PCDROM_SUB_Q_DATA_FORMAT; + +typedef struct _SUB_Q_HEADER { + UCHAR Reserved; + UCHAR AudioStatus; + UCHAR DataLength[2]; +} SUB_Q_HEADER, *PSUB_Q_HEADER; + +typedef struct _SUB_Q_MEDIA_CATALOG_NUMBER { + SUB_Q_HEADER Header; + UCHAR FormatCode; + UCHAR Reserved[3]; + UCHAR Reserved1 : 7; + UCHAR Mcval :1; + UCHAR MediaCatalog[15]; +} SUB_Q_MEDIA_CATALOG_NUMBER, *PSUB_Q_MEDIA_CATALOG_NUMBER; + +#include "win32.h" + +/* + Returns a string that can be used in a CreateFile call if + c_drive letter is a character. If not NULL is returned. + */ + +const char * +is_cdrom_win32ioctl(const char c_drive_letter) +{ + + UINT uDriveType; + char sz_win32_drive[4]; + + sz_win32_drive[0]= c_drive_letter; + sz_win32_drive[1]=':'; + sz_win32_drive[2]='\\'; + sz_win32_drive[3]='\0'; + + uDriveType = GetDriveType(sz_win32_drive); + + switch(uDriveType) { + case DRIVE_CDROM: { + char sz_win32_drive_full[] = "\\\\.\\X:"; + sz_win32_drive_full[4] = c_drive_letter; + return strdup(sz_win32_drive_full); + } + default: + cdio_debug("Drive %c is not a CD-ROM", c_drive_letter); + return NULL; + } +} + +/*! + Reads an audio device using the DeviceIoControl method into data + starting from lsn. Returns 0 if no error. + */ +int +read_audio_sectors_win32ioctl (_img_private_t *env, void *data, lsn_t lsn, + unsigned int nblocks) +{ + DWORD dwBytesReturned; + RAW_READ_INFO cdrom_raw; + + /* Initialize CDROM_RAW_READ structure */ + cdrom_raw.DiskOffset.QuadPart = CDIO_CD_FRAMESIZE_RAW * lsn; + cdrom_raw.SectorCount = nblocks; + cdrom_raw.TrackMode = CDDA; + + if( DeviceIoControl( env->h_device_handle, + IOCTL_CDROM_RAW_READ, &cdrom_raw, + sizeof(RAW_READ_INFO), data, + CDIO_CD_FRAMESIZE_RAW * nblocks, + &dwBytesReturned, NULL ) == 0 ) { + cdio_info("Error reading audio-mode %lu (%ld)\n", + (long unsigned int) lsn, GetLastError()); + return 1; + } + return 0; +} + +/*! + Reads a single raw sector using the DeviceIoControl method into + data starting from lsn. Returns 0 if no error. + */ +static int +read_raw_sector (const _img_private_t *env, void *buf, lsn_t lsn) +{ + SCSI_PASS_THROUGH_DIRECT sptd; + BOOL success; + DWORD dwBytesReturned; + + sptd.Length=sizeof(sptd); + sptd.PathId=0; /* SCSI card ID will be filled in automatically */ + sptd.TargetId=0; /* SCSI target ID will also be filled in */ + sptd.Lun=0; /* SCSI lun ID will also be filled in */ + sptd.CdbLength=12; /* CDB size is 12 for ReadCD MMC1 command */ + sptd.SenseInfoLength=0; /* Don't return any sense data */ + sptd.DataIn = SCSI_IOCTL_DATA_IN; + sptd.DataTransferLength= CDIO_CD_FRAMESIZE_RAW; + sptd.TimeOutValue=60; /*SCSI timeout value (60 seconds - + maybe it should be longer) */ + sptd.DataBuffer= (PVOID) buf; + sptd.SenseInfoOffset=0; + + /* ReadCD CDB12 command. The values were taken from MMC1 draft paper. */ + CDIO_MMC_SET_COMMAND(sptd.Cdb, CDIO_MMC_GPCMD_READ_CD); + + CDIO_MMC_SET_READ_LBA(sptd.Cdb, lsn); + CDIO_MMC_SET_READ_LENGTH(sptd.Cdb, 1); + + sptd.Cdb[9]=0xF8; /* Raw read, 2352 bytes per sector */ + sptd.Cdb[10]=0; + sptd.Cdb[11]=0; + sptd.Cdb[12]=0; + sptd.Cdb[13]=0; + sptd.Cdb[14]=0; + sptd.Cdb[15]=0; + + /* Send the command to drive */ + success=DeviceIoControl(env->h_device_handle, + IOCTL_SCSI_PASS_THROUGH_DIRECT, + (PVOID)&sptd, + (DWORD)sizeof(SCSI_PASS_THROUGH_DIRECT), + NULL, 0, + &dwBytesReturned, + NULL); + + if(! success) { + cdio_info("Error reading %lu (%ld)\n", (long unsigned) lsn, + GetLastError()); + return 1; + } + + return 0; +} + +/*! + Reads a single mode2 sector using the DeviceIoControl method into + data starting from lsn. Returns 0 if no error. + */ +int +read_mode2_sector_win32ioctl (const _img_private_t *env, void *data, + lsn_t lsn, bool b_form2) +{ + char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, }; + int ret = read_raw_sector (env, buf, lsn); + + if ( 0 != ret) return ret; + + memcpy (data, + buf + CDIO_CD_SYNC_SIZE + CDIO_CD_XA_HEADER, + b_form2 ? M2RAW_SECTOR_SIZE: CDIO_CD_FRAMESIZE); + + return 0; + +} + +/*! + Reads a single mode2 sector using the DeviceIoControl method into + data starting from lsn. Returns 0 if no error. + */ +int +read_mode1_sector_win32ioctl (const _img_private_t *env, void *data, + lsn_t lsn, bool b_form2) +{ + char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, }; + int ret = read_raw_sector (env, buf, lsn); + + if ( 0 != ret) return ret; + + memcpy (data, + buf + CDIO_CD_SYNC_SIZE+CDIO_CD_HEADER_SIZE, + b_form2 ? M2RAW_SECTOR_SIZE: CDIO_CD_FRAMESIZE); + + return 0; + +} + +/*! + Initialize internal structures for CD device. + */ +bool +init_win32ioctl (_img_private_t *env) +{ + char psz_win32_drive[7]; + unsigned int len=strlen(env->gen.source_name); + OSVERSIONINFO ov; + DWORD dw_access_flags; + + cdio_debug("using winNT/2K/XP ioctl layer"); + + memset(&ov,0,sizeof(OSVERSIONINFO)); + ov.dwOSVersionInfoSize=sizeof(OSVERSIONINFO); + GetVersionEx(&ov); + + if((ov.dwPlatformId==VER_PLATFORM_WIN32_NT) && + (ov.dwMajorVersion>4)) + dw_access_flags = GENERIC_READ|GENERIC_WRITE; /* add gen write on W2k/XP */ + else dw_access_flags = GENERIC_READ; + + if (cdio_is_device_win32(env->gen.source_name)) { + sprintf( psz_win32_drive, "\\\\.\\%c:", env->gen.source_name[len-2] ); + + env->h_device_handle = CreateFile( psz_win32_drive, + dw_access_flags, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL ); + if( env->h_device_handle == INVALID_HANDLE_VALUE ) + { + /* No good. try toggle write. */ + dw_access_flags ^= GENERIC_WRITE; + env->h_device_handle = CreateFile( psz_win32_drive, + dw_access_flags, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL ); + return (env->h_device_handle == NULL) ? false : true; + } + env->b_ioctl_init = true; + return true; + } + return false; +} + +#define MSF_TO_LBA2(min, sec, frame) \ + ((int) frame + CDIO_CD_FRAMES_PER_SEC * (CDIO_CD_SECS_PER_MIN*min + sec) \ + - CDIO_PREGAP_SECTORS ) + +/*! + Read and cache the CD's Track Table of Contents and track info. + Return true if successful or false if an error. +*/ +bool +read_toc_win32ioctl (_img_private_t *env) +{ + + DWORD dwBytesReturned; + CDROM_TOC cdrom_toc; + int i; + + if( DeviceIoControl( env->h_device_handle, + IOCTL_CDROM_READ_TOC, + NULL, 0, &cdrom_toc, sizeof(CDROM_TOC), + &dwBytesReturned, NULL ) == 0 ) { + cdio_warn( "could not read TOCHDR: %ld" , (long int) GetLastError()); + return false; + } + + env->i_first_track = cdrom_toc.FirstTrack; + env->total_tracks = cdrom_toc.LastTrack - cdrom_toc.FirstTrack + 1; + + + for( i = 0 ; i <= env->total_tracks ; i++ ) { + env->tocent[ i ].start_lsn = MSF_TO_LBA2( + cdrom_toc.TrackData[i].Address[1], + cdrom_toc.TrackData[i].Address[2], + cdrom_toc.TrackData[i].Address[3] ); + env->tocent[ i ].Control = cdrom_toc.TrackData[i].Control; + env->tocent[ i ].Format = cdrom_toc.TrackData[i].Format; + cdio_debug("p_sectors: %i, %lu", i, + (unsigned long int) (env->tocent[i].start_lsn)); + } + env->gen.toc_init = true; + return true; +} + +/*! + Return the media catalog number MCN. + + Note: string is malloc'd so caller should free() then returned + string when done with it. + + */ +char * +get_mcn_win32ioctl (const _img_private_t *env) { + + DWORD dwBytesReturned; + SUB_Q_MEDIA_CATALOG_NUMBER mcn; + CDROM_SUB_Q_DATA_FORMAT q_data_format; + + memset( &mcn, 0, sizeof(mcn) ); + + q_data_format.Format = IOCTL_CDROM_MEDIA_CATALOG; + + q_data_format.Track=1; + + if( DeviceIoControl( env->h_device_handle, + IOCTL_CDROM_READ_Q_CHANNEL, + &q_data_format, sizeof(q_data_format), + &mcn, sizeof(mcn), + &dwBytesReturned, NULL ) == 0 ) { + cdio_warn( "could not read Q Channel at track %d", 1); + } else if (mcn.Mcval) + return strdup(mcn.MediaCatalog); + return NULL; +} + +/*! + Get the format (XA, DATA, AUDIO) of a track. +*/ +track_format_t +get_track_format_win32ioctl(const _img_private_t *env, track_t i_track) +{ + /* This is pretty much copied from the "badly broken" cdrom_count_tracks + in linux/cdrom.c. + */ + if (env->tocent[i_track - env->i_first_track].Control & 0x04) { + if (env->tocent[i_track - env->i_first_track].Format == 0x10) + return TRACK_FORMAT_CDI; + else if (env->tocent[i_track - env->i_first_track].Format == 0x20) + return TRACK_FORMAT_XA; + else + return TRACK_FORMAT_DATA; + } else + return TRACK_FORMAT_AUDIO; +} + + +/*! + Return the the kind of drive capabilities of device. + + Note: string is malloc'd so caller should free() then returned + string when done with it. + + */ +cdio_drive_cap_t +get_drive_cap_win32ioctl (const _img_private_t *env) +{ + int32_t i_drivetype = 0; + SCSI_PASS_THROUGH_WITH_BUFFERS sptwb; + ULONG returned = 0; + ULONG length; + + /* If device supports SCSI-3, then we can get the CD drive + capabilities, i.e. ability to read/write to CD-ROM/R/RW + or/and read/write to DVD-ROM/R/RW. */ + + memset(&sptwb,0, sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS)); + + sptwb.Spt.Length = sizeof(SCSI_PASS_THROUGH); + sptwb.Spt.PathId = 0; + sptwb.Spt.TargetId = 1; + sptwb.Spt.Lun = 0; + sptwb.Spt.CdbLength = 6; /* CDB6GENERIC_LENGTH; */ + sptwb.Spt.SenseInfoLength = 24; + sptwb.Spt.DataIn = SCSI_IOCTL_DATA_IN; + sptwb.Spt.DataTransferLength = 192; + sptwb.Spt.TimeOutValue = 2; + sptwb.Spt.DataBufferOffset = + offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,DataBuf); + sptwb.Spt.SenseInfoOffset = + offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,SenseBuf); + + CDIO_MMC_SET_COMMAND(sptwb.Spt.Cdb, CDIO_MMC_MODE_SENSE); + /*sptwb.Spt.Cdb[1] = 0x08; /+ doesn't return block descriptors */ + sptwb.Spt.Cdb[1] = 0x0; + sptwb.Spt.Cdb[2] = 0x2a; /*MODE_PAGE_CAPABILITIES*/; + sptwb.Spt.Cdb[3] = 0; /* Not used */ + sptwb.Spt.Cdb[4] = 128; + sptwb.Spt.Cdb[5] = 0; /* Not used */ + length = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,DataBuf) + + sptwb.Spt.DataTransferLength; + + if ( DeviceIoControl(env->h_device_handle, + IOCTL_SCSI_PASS_THROUGH, + &sptwb, + sizeof(SCSI_PASS_THROUGH), + &sptwb, + length, + &returned, + FALSE) ) + { + unsigned int n=sptwb.DataBuf[3]+4; + /* Reader? */ + if (sptwb.DataBuf[n+5] & 0x01) i_drivetype |= CDIO_DRIVE_CAP_CD_AUDIO; + if (sptwb.DataBuf[n+2] & 0x02) i_drivetype |= CDIO_DRIVE_CAP_CD_RW; + if (sptwb.DataBuf[n+2] & 0x08) i_drivetype |= CDIO_DRIVE_CAP_DVD; + + /* Writer? */ + if (sptwb.DataBuf[n+3] & 0x01) i_drivetype |= CDIO_DRIVE_CAP_CD_R; + if (sptwb.DataBuf[n+3] & 0x10) i_drivetype |= CDIO_DRIVE_CAP_DVD_R; + if (sptwb.DataBuf[n+3] & 0x20) i_drivetype |= CDIO_DRIVE_CAP_DVD_RAM; + + if (sptwb.DataBuf[n+6] & 0x08) i_drivetype |= CDIO_DRIVE_CAP_OPEN_TRAY; + if (sptwb.DataBuf[n+6] >> 5 != 0) + i_drivetype |= CDIO_DRIVE_CAP_CLOSE_TRAY; + + return i_drivetype; + } else { + i_drivetype = CDIO_DRIVE_CAP_CD_AUDIO | CDIO_DRIVE_CAP_UNKNOWN; + } + return CDIO_DRIVE_CAP_ERROR; +} + +#endif /*HAVE_WIN32_CDROM*/