00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include <stdio.h>
00030 #include <stdlib.h>
00031
00032 #include <vlc/vlc.h>
00033
00034 #ifdef HAVE_UNISTD_H
00035 # include <unistd.h>
00036 #endif
00037
00038 #include <fcntl.h>
00039 #include <sys/types.h>
00040 #include <sys/stat.h>
00041 #include <string.h>
00042 #include <errno.h>
00043
00044 #ifdef HAVE_SYS_IOCTL_H
00045 # include <sys/ioctl.h>
00046 #endif
00047
00048 #if defined( SYS_BSDI )
00049 # include <dvd.h>
00050 #elif defined ( SYS_DARWIN )
00051 # include <CoreFoundation/CFBase.h>
00052 # include <IOKit/IOKitLib.h>
00053 # include <IOKit/storage/IOCDTypes.h>
00054 # include <IOKit/storage/IOCDMedia.h>
00055 # include <IOKit/storage/IOCDMediaBSDClient.h>
00056 #elif defined( HAVE_SCSIREQ_IN_SYS_SCSIIO_H )
00057 # include <sys/inttypes.h>
00058 # include <sys/cdio.h>
00059 # include <sys/scsiio.h>
00060 #elif defined( HAVE_IOC_TOC_HEADER_IN_SYS_CDIO_H )
00061 # include <sys/cdio.h>
00062 # include <sys/cdrio.h>
00063 #elif defined( WIN32 )
00064 # include <windows.h>
00065 # include <winioctl.h>
00066 #else
00067 # include <linux/cdrom.h>
00068 #endif
00069
00070 #include "cdrom_internals.h"
00071 #include "cdrom.h"
00072
00073
00074
00075
00076 vcddev_t *ioctl_Open( vlc_object_t *p_this, const char *psz_dev )
00077 {
00078 int i_ret;
00079 int b_is_file;
00080 vcddev_t *p_vcddev;
00081 #ifndef WIN32
00082 struct stat fileinfo;
00083 #endif
00084
00085 if( !psz_dev ) return NULL;
00086
00087
00088
00089
00090 p_vcddev = (vcddev_t *)malloc( sizeof(vcddev_t) );
00091 if( p_vcddev == NULL )
00092 {
00093 msg_Err( p_this, "out of memory" );
00094 return NULL;
00095 }
00096 p_vcddev->i_vcdimage_handle = -1;
00097 p_vcddev->psz_dev = NULL;
00098 b_is_file = 1;
00099
00100
00101
00102
00103 #ifdef WIN32
00104 if( (strlen( psz_dev ) == 2 && psz_dev[1] == ':') )
00105 {
00106 b_is_file = 0;
00107 }
00108
00109 #else
00110 if( stat( psz_dev, &fileinfo ) < 0 )
00111 {
00112 free( p_vcddev );
00113 return NULL;
00114 }
00115
00116
00117 if( S_ISBLK( fileinfo.st_mode ) || S_ISCHR( fileinfo.st_mode ) )
00118 b_is_file = 0;
00119 #endif
00120
00121 if( b_is_file )
00122 {
00123 i_ret = OpenVCDImage( p_this, psz_dev, p_vcddev );
00124 }
00125 else
00126 {
00127
00128
00129
00130
00131 #ifdef WIN32
00132 i_ret = win32_vcd_open( p_this, psz_dev, p_vcddev );
00133 #else
00134 p_vcddev->i_device_handle = -1;
00135 p_vcddev->i_device_handle = open( psz_dev, O_RDONLY | O_NONBLOCK );
00136 i_ret = (p_vcddev->i_device_handle == -1) ? -1 : 0;
00137 #endif
00138 }
00139
00140 if( i_ret == 0 )
00141 {
00142 p_vcddev->psz_dev = (char *)strdup( psz_dev );
00143 }
00144 else
00145 {
00146 free( p_vcddev );
00147 p_vcddev = NULL;
00148 }
00149
00150 return p_vcddev;
00151 }
00152
00153
00154
00155
00156 void ioctl_Close( vlc_object_t * p_this, vcddev_t *p_vcddev )
00157 {
00158 if( p_vcddev->psz_dev ) free( p_vcddev->psz_dev );
00159
00160 if( p_vcddev->i_vcdimage_handle != -1 )
00161 {
00162
00163
00164
00165
00166 CloseVCDImage( p_this, p_vcddev );
00167 return;
00168 }
00169
00170
00171
00172
00173
00174 #ifdef WIN32
00175 if( p_vcddev->h_device_handle )
00176 CloseHandle( p_vcddev->h_device_handle );
00177 if( p_vcddev->hASPI )
00178 FreeLibrary( (HMODULE)p_vcddev->hASPI );
00179 #else
00180 if( p_vcddev->i_device_handle != -1 )
00181 close( p_vcddev->i_device_handle );
00182 #endif
00183 }
00184
00185
00186
00187
00188
00189
00190 int ioctl_GetTracksMap( vlc_object_t *p_this, const vcddev_t *p_vcddev,
00191 int **pp_sectors )
00192 {
00193 int i_tracks = 0;
00194
00195 if( p_vcddev->i_vcdimage_handle != -1 )
00196 {
00197
00198
00199
00200
00201 i_tracks = p_vcddev->i_tracks;
00202
00203 if( pp_sectors )
00204 {
00205 *pp_sectors = malloc( (i_tracks + 1) * sizeof(int) );
00206 if( *pp_sectors == NULL )
00207 {
00208 msg_Err( p_this, "out of memory" );
00209 return 0;
00210 }
00211 memcpy( *pp_sectors, p_vcddev->p_sectors,
00212 (i_tracks + 1) * sizeof(int) );
00213 }
00214
00215 return i_tracks;
00216 }
00217 else
00218 {
00219
00220
00221
00222
00223
00224 #if defined( SYS_DARWIN )
00225
00226 CDTOC *pTOC;
00227 int i_descriptors;
00228
00229 if( ( pTOC = darwin_getTOC( p_this, p_vcddev ) ) == NULL )
00230 {
00231 msg_Err( p_this, "failed to get the TOC" );
00232 return 0;
00233 }
00234
00235 i_descriptors = darwin_getNumberOfDescriptors( pTOC );
00236 i_tracks = darwin_getNumberOfTracks( pTOC, i_descriptors );
00237
00238 if( pp_sectors )
00239 {
00240 int i, i_leadout = -1;
00241 CDTOCDescriptor *pTrackDescriptors;
00242 u_char track;
00243
00244 *pp_sectors = malloc( (i_tracks + 1) * sizeof(int) );
00245 if( *pp_sectors == NULL )
00246 {
00247 msg_Err( p_this, "out of memory" );
00248 darwin_freeTOC( pTOC );
00249 return 0;
00250 }
00251
00252 pTrackDescriptors = pTOC->descriptors;
00253
00254 for( i_tracks = 0, i = 0; i <= i_descriptors; i++ )
00255 {
00256 track = pTrackDescriptors[i].point;
00257
00258 if( track == 0xA2 )
00259 i_leadout = i;
00260
00261 if( track > CD_MAX_TRACK_NO || track < CD_MIN_TRACK_NO )
00262 continue;
00263
00264 (*pp_sectors)[i_tracks++] =
00265 CDConvertMSFToLBA( pTrackDescriptors[i].p );
00266 }
00267
00268 if( i_leadout == -1 )
00269 {
00270 msg_Err( p_this, "leadout not found" );
00271 free( *pp_sectors );
00272 darwin_freeTOC( pTOC );
00273 return 0;
00274 }
00275
00276
00277 (*pp_sectors)[i_tracks] =
00278 CDConvertMSFToLBA( pTrackDescriptors[i_leadout].p );
00279 }
00280
00281 darwin_freeTOC( pTOC );
00282
00283 #elif defined( WIN32 )
00284 if( p_vcddev->hASPI )
00285 {
00286 HANDLE hEvent;
00287 struct SRB_ExecSCSICmd ssc;
00288 byte_t p_tocheader[ 4 ];
00289
00290
00291 hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
00292 if( hEvent == NULL )
00293 {
00294 return -1;
00295 }
00296
00297 memset( &ssc, 0, sizeof( ssc ) );
00298
00299 ssc.SRB_Cmd = SC_EXEC_SCSI_CMD;
00300 ssc.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY;
00301 ssc.SRB_HaId = LOBYTE( p_vcddev->i_sid );
00302 ssc.SRB_Target = HIBYTE( p_vcddev->i_sid );
00303 ssc.SRB_SenseLen = SENSE_LEN;
00304
00305 ssc.SRB_PostProc = (LPVOID) hEvent;
00306 ssc.SRB_CDBLen = 10;
00307
00308
00309 ssc.CDBByte[ 0 ] = READ_TOC;
00310
00311
00312 ssc.CDBByte[ 2 ] = READ_TOC_FORMAT_TOC;
00313
00314
00315 ssc.CDBByte[ 6 ] = 0;
00316
00317
00318 ssc.SRB_BufLen = sizeof( p_tocheader );
00319 ssc.SRB_BufPointer = p_tocheader;
00320 ssc.CDBByte[ 7 ] = ( ssc.SRB_BufLen >> 8 ) & 0xff;
00321 ssc.CDBByte[ 8 ] = ( ssc.SRB_BufLen ) & 0xff;
00322
00323
00324 ResetEvent( hEvent );
00325 p_vcddev->lpSendCommand( (void*) &ssc );
00326
00327
00328
00329 if( ssc.SRB_Status == SS_PENDING )
00330 WaitForSingleObject( hEvent, INFINITE );
00331
00332
00333 if( ssc.SRB_Status != SS_COMP )
00334 {
00335 CloseHandle( hEvent );
00336 return 0;
00337 }
00338
00339 i_tracks = p_tocheader[3] - p_tocheader[2] + 1;
00340
00341 if( pp_sectors )
00342 {
00343 int i, i_toclength;
00344 byte_t *p_fulltoc;
00345
00346 i_toclength = 4 + p_tocheader[0] +
00347 ((unsigned int)p_tocheader[1] << 8);
00348
00349 p_fulltoc = malloc( i_toclength );
00350 *pp_sectors = malloc( (i_tracks + 1) * sizeof(int) );
00351
00352 if( *pp_sectors == NULL || p_fulltoc == NULL )
00353 {
00354 if( *pp_sectors ) free( *pp_sectors );
00355 if( p_fulltoc ) free( p_fulltoc );
00356 msg_Err( p_this, "out of memory" );
00357 CloseHandle( hEvent );
00358 return 0;
00359 }
00360
00361
00362 ssc.SRB_BufLen = i_toclength;
00363 ssc.SRB_BufPointer = p_fulltoc;
00364 ssc.CDBByte[ 7 ] = ( ssc.SRB_BufLen >> 8 ) & 0xff;
00365 ssc.CDBByte[ 8 ] = ( ssc.SRB_BufLen ) & 0xff;
00366
00367
00368 ResetEvent( hEvent );
00369 p_vcddev->lpSendCommand( (void*) &ssc );
00370
00371
00372
00373 if( ssc.SRB_Status == SS_PENDING )
00374 WaitForSingleObject( hEvent, INFINITE );
00375
00376
00377 if( ssc.SRB_Status != SS_COMP )
00378 i_tracks = 0;
00379
00380 for( i = 0 ; i <= i_tracks ; i++ )
00381 {
00382 int i_index = 8 + 8 * i;
00383 (*pp_sectors)[ i ] = ((int)p_fulltoc[ i_index ] << 24) +
00384 ((int)p_fulltoc[ i_index+1 ] << 16) +
00385 ((int)p_fulltoc[ i_index+2 ] << 8) +
00386 (int)p_fulltoc[ i_index+3 ];
00387
00388 msg_Dbg( p_this, "p_sectors: %i, %i", i, (*pp_sectors)[i]);
00389 }
00390
00391 free( p_fulltoc );
00392 }
00393
00394 CloseHandle( hEvent );
00395
00396 }
00397 else
00398 {
00399 DWORD dwBytesReturned;
00400 CDROM_TOC cdrom_toc;
00401
00402 if( DeviceIoControl( p_vcddev->h_device_handle,
00403 IOCTL_CDROM_READ_TOC,
00404 NULL, 0, &cdrom_toc, sizeof(CDROM_TOC),
00405 &dwBytesReturned, NULL ) == 0 )
00406 {
00407 msg_Err( p_this, "could not read TOCHDR" );
00408 return 0;
00409 }
00410
00411 i_tracks = cdrom_toc.LastTrack - cdrom_toc.FirstTrack + 1;
00412
00413 if( pp_sectors )
00414 {
00415 int i;
00416
00417 *pp_sectors = malloc( (i_tracks + 1) * sizeof(int) );
00418 if( *pp_sectors == NULL )
00419 {
00420 msg_Err( p_this, "out of memory" );
00421 return 0;
00422 }
00423
00424 for( i = 0 ; i <= i_tracks ; i++ )
00425 {
00426 (*pp_sectors)[ i ] = MSF_TO_LBA2(
00427 cdrom_toc.TrackData[i].Address[1],
00428 cdrom_toc.TrackData[i].Address[2],
00429 cdrom_toc.TrackData[i].Address[3] );
00430 msg_Dbg( p_this, "p_sectors: %i, %i", i, (*pp_sectors)[i]);
00431 }
00432 }
00433 }
00434
00435 #elif defined( HAVE_IOC_TOC_HEADER_IN_SYS_CDIO_H ) \
00436 || defined( HAVE_SCSIREQ_IN_SYS_SCSIIO_H )
00437 struct ioc_toc_header tochdr;
00438 struct ioc_read_toc_entry toc_entries;
00439
00440 if( ioctl( p_vcddev->i_device_handle, CDIOREADTOCHEADER, &tochdr )
00441 == -1 )
00442 {
00443 msg_Err( p_this, "could not read TOCHDR" );
00444 return 0;
00445 }
00446
00447 i_tracks = tochdr.ending_track - tochdr.starting_track + 1;
00448
00449 if( pp_sectors )
00450 {
00451 int i;
00452
00453 *pp_sectors = malloc( (i_tracks + 1) * sizeof(int) );
00454 if( *pp_sectors == NULL )
00455 {
00456 msg_Err( p_this, "out of memory" );
00457 return NULL;
00458 }
00459
00460 toc_entries.address_format = CD_LBA_FORMAT;
00461 toc_entries.starting_track = 0;
00462 toc_entries.data_len = ( i_tracks + 1 ) *
00463 sizeof( struct cd_toc_entry );
00464 toc_entries.data = (struct cd_toc_entry *)
00465 malloc( toc_entries.data_len );
00466 if( toc_entries.data == NULL )
00467 {
00468 msg_Err( p_this, "out of memory" );
00469 free( *pp_sectors );
00470 return 0;
00471 }
00472
00473
00474 if( ioctl( p_vcddev->i_device_handle, CDIOREADTOCENTRYS,
00475 &toc_entries ) == -1 )
00476 {
00477 msg_Err( p_this, "could not read the TOC" );
00478 free( *pp_sectors );
00479 free( toc_entries.data );
00480 return 0;
00481 }
00482
00483
00484 for( i = 0 ; i <= i_tracks ; i++ )
00485 {
00486 #if defined( HAVE_SCSIREQ_IN_SYS_SCSIIO_H )
00487
00488 (*pp_sectors)[ i ] = toc_entries.data[i].addr.lba;
00489 #else
00490 (*pp_sectors)[ i ] = ntohl( toc_entries.data[i].addr.lba );
00491 #endif
00492 }
00493 }
00494 #else
00495 struct cdrom_tochdr tochdr;
00496 struct cdrom_tocentry tocent;
00497
00498
00499 if( ioctl( p_vcddev->i_device_handle, CDROMREADTOCHDR, &tochdr )
00500 == -1 )
00501 {
00502 msg_Err( p_this, "could not read TOCHDR" );
00503 return 0;
00504 }
00505
00506 i_tracks = tochdr.cdth_trk1 - tochdr.cdth_trk0 + 1;
00507
00508 if( pp_sectors )
00509 {
00510 int i;
00511
00512 *pp_sectors = malloc( (i_tracks + 1) * sizeof(int) );
00513 if( *pp_sectors == NULL )
00514 {
00515 msg_Err( p_this, "out of memory" );
00516 return 0;
00517 }
00518
00519
00520 for( i = 0 ; i <= i_tracks ; i++ )
00521 {
00522 tocent.cdte_format = CDROM_LBA;
00523 tocent.cdte_track =
00524 ( i == i_tracks ) ? CDROM_LEADOUT : tochdr.cdth_trk0 + i;
00525
00526 if( ioctl( p_vcddev->i_device_handle, CDROMREADTOCENTRY,
00527 &tocent ) == -1 )
00528 {
00529 msg_Err( p_this, "could not read TOCENTRY" );
00530 free( *pp_sectors );
00531 return 0;
00532 }
00533
00534 (*pp_sectors)[ i ] = tocent.cdte_addr.lba;
00535 }
00536 }
00537 #endif
00538
00539 return i_tracks;
00540 }
00541 }
00542
00543
00544
00545
00546 int ioctl_ReadSectors( vlc_object_t *p_this, const vcddev_t *p_vcddev,
00547 int i_sector, byte_t * p_buffer, int i_nb, int i_type )
00548 {
00549 byte_t *p_block;
00550 int i;
00551
00552 if( i_type == VCD_TYPE ) p_block = malloc( VCD_SECTOR_SIZE * i_nb );
00553 else p_block = p_buffer;
00554
00555 if( p_vcddev->i_vcdimage_handle != -1 )
00556 {
00557
00558
00559
00560 if( lseek( p_vcddev->i_vcdimage_handle, i_sector * VCD_SECTOR_SIZE,
00561 SEEK_SET ) == -1 )
00562 {
00563 msg_Err( p_this, "Could not lseek to sector %d", i_sector );
00564 if( i_type == VCD_TYPE ) free( p_block );
00565 return -1;
00566 }
00567
00568 if( read( p_vcddev->i_vcdimage_handle, p_block, VCD_SECTOR_SIZE * i_nb)
00569 == -1 )
00570 {
00571 msg_Err( p_this, "Could not read sector %d", i_sector );
00572 if( i_type == VCD_TYPE ) free( p_block );
00573 return -1;
00574 }
00575
00576 }
00577 else
00578 {
00579
00580
00581
00582
00583
00584 #if defined( SYS_DARWIN )
00585 dk_cd_read_t cd_read;
00586
00587 memset( &cd_read, 0, sizeof(cd_read) );
00588
00589 cd_read.offset = i_sector * VCD_SECTOR_SIZE;
00590 cd_read.sectorArea = kCDSectorAreaSync | kCDSectorAreaHeader |
00591 kCDSectorAreaSubHeader | kCDSectorAreaUser |
00592 kCDSectorAreaAuxiliary;
00593 cd_read.sectorType = kCDSectorTypeUnknown;
00594
00595 cd_read.buffer = p_block;
00596 cd_read.bufferLength = VCD_SECTOR_SIZE * i_nb;
00597
00598 if( ioctl( p_vcddev->i_device_handle, DKIOCCDREAD, &cd_read ) == -1 )
00599 {
00600 msg_Err( p_this, "could not read block %d", i_sector );
00601 if( i_type == VCD_TYPE ) free( p_block );
00602 return -1;
00603 }
00604
00605 #elif defined( WIN32 )
00606 if( p_vcddev->hASPI )
00607 {
00608 HANDLE hEvent;
00609 struct SRB_ExecSCSICmd ssc;
00610
00611
00612 hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
00613 if( hEvent == NULL )
00614 {
00615 if( i_type == VCD_TYPE ) free( p_block );
00616 return -1;
00617 }
00618
00619 memset( &ssc, 0, sizeof( ssc ) );
00620
00621 ssc.SRB_Cmd = SC_EXEC_SCSI_CMD;
00622 ssc.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY;
00623 ssc.SRB_HaId = LOBYTE( p_vcddev->i_sid );
00624 ssc.SRB_Target = HIBYTE( p_vcddev->i_sid );
00625 ssc.SRB_SenseLen = SENSE_LEN;
00626
00627 ssc.SRB_PostProc = (LPVOID) hEvent;
00628 ssc.SRB_CDBLen = 12;
00629
00630
00631 ssc.CDBByte[ 0 ] = READ_CD;
00632
00633
00634 ssc.CDBByte[ 1 ] = i_type == VCD_TYPE ? SECTOR_TYPE_MODE2_FORM2 :
00635 SECTOR_TYPE_CDDA;
00636
00637
00638 ssc.CDBByte[ 2 ] = ( i_sector >> 24 ) & 0xff;
00639 ssc.CDBByte[ 3 ] = ( i_sector >> 16 ) & 0xff;
00640 ssc.CDBByte[ 4 ] = ( i_sector >> 8 ) & 0xff;
00641 ssc.CDBByte[ 5 ] = ( i_sector ) & 0xff;
00642
00643
00644 ssc.CDBByte[ 6 ] = ( i_nb >> 16 ) & 0xff;
00645 ssc.CDBByte[ 7 ] = ( i_nb >> 8 ) & 0xff;
00646 ssc.CDBByte[ 8 ] = ( i_nb ) & 0xff;
00647
00648
00649 ssc.CDBByte[ 9 ] = i_type == VCD_TYPE ? READ_CD_RAW_MODE2 :
00650 READ_CD_USERDATA;
00651
00652
00653 ssc.SRB_BufPointer = p_block;
00654 ssc.SRB_BufLen = VCD_SECTOR_SIZE * i_nb;
00655
00656
00657 ResetEvent( hEvent );
00658 p_vcddev->lpSendCommand( (void*) &ssc );
00659
00660
00661
00662 if( ssc.SRB_Status == SS_PENDING )
00663 {
00664 WaitForSingleObject( hEvent, INFINITE );
00665 }
00666 CloseHandle( hEvent );
00667
00668
00669 if( ssc.SRB_Status != SS_COMP )
00670 {
00671 if( i_type == VCD_TYPE ) free( p_block );
00672 return -1;
00673 }
00674 }
00675 else
00676 {
00677 DWORD dwBytesReturned;
00678 RAW_READ_INFO cdrom_raw;
00679
00680
00681 cdrom_raw.DiskOffset.QuadPart = CD_SECTOR_SIZE * i_sector;
00682 cdrom_raw.SectorCount = i_nb;
00683 cdrom_raw.TrackMode = i_type == VCD_TYPE ? XAForm2 : CDDA;
00684
00685 if( DeviceIoControl( p_vcddev->h_device_handle,
00686 IOCTL_CDROM_RAW_READ, &cdrom_raw,
00687 sizeof(RAW_READ_INFO), p_block,
00688 VCD_SECTOR_SIZE * i_nb, &dwBytesReturned,
00689 NULL ) == 0 )
00690 {
00691 if( i_type == VCD_TYPE )
00692 {
00693
00694 cdrom_raw.TrackMode = YellowMode2;
00695 if( DeviceIoControl( p_vcddev->h_device_handle,
00696 IOCTL_CDROM_RAW_READ, &cdrom_raw,
00697 sizeof(RAW_READ_INFO), p_block,
00698 VCD_SECTOR_SIZE * i_nb, &dwBytesReturned,
00699 NULL ) == 0 )
00700 {
00701 free( p_block );
00702 return -1;
00703 }
00704 }
00705 else return -1;
00706 }
00707 }
00708
00709 #elif defined( HAVE_SCSIREQ_IN_SYS_SCSIIO_H )
00710 struct scsireq sc;
00711 int i_ret;
00712
00713 memset( &sc, 0, sizeof(sc) );
00714 sc.cmd[0] = 0xBE;
00715 sc.cmd[1] = i_type == VCD_TYPE ? SECTOR_TYPE_MODE2_FORM2:
00716 SECTOR_TYPE_CDDA;
00717 sc.cmd[2] = (i_sector >> 24) & 0xff;
00718 sc.cmd[3] = (i_sector >> 16) & 0xff;
00719 sc.cmd[4] = (i_sector >> 8) & 0xff;
00720 sc.cmd[5] = (i_sector >> 0) & 0xff;
00721 sc.cmd[6] = (i_nb >> 16) & 0xff;
00722 sc.cmd[7] = (i_nb >> 8) & 0xff;
00723 sc.cmd[8] = (i_nb ) & 0xff;
00724 sc.cmd[9] = i_type == VCD_TYPE ? READ_CD_RAW_MODE2 : READ_CD_USERDATA;
00725 sc.cmd[10] = 0;
00726 sc.cmdlen = 12;
00727 sc.databuf = (caddr_t)p_block;
00728 sc.datalen = VCD_SECTOR_SIZE * i_nb;
00729 sc.senselen = sizeof( sc.sense );
00730 sc.flags = SCCMD_READ;
00731 sc.timeout = 10000;
00732
00733 i_ret = ioctl( i_fd, SCIOCCOMMAND, &sc );
00734 if( i_ret == -1 )
00735 {
00736 msg_Err( p_this, "SCIOCCOMMAND failed" );
00737 if( i_type == VCD_TYPE ) free( p_block );
00738 return -1;
00739 }
00740 if( sc.retsts || sc.error )
00741 {
00742 msg_Err( p_this, "SCSI command failed: status %d error %d\n",
00743 sc.retsts, sc.error );
00744 if( i_type == VCD_TYPE ) free( p_block );
00745 return -1;
00746 }
00747
00748 #elif defined( HAVE_IOC_TOC_HEADER_IN_SYS_CDIO_H )
00749 int i_size = VCD_SECTOR_SIZE;
00750
00751 if( ioctl( p_vcddev->i_device_handle, CDRIOCSETBLOCKSIZE, &i_size )
00752 == -1 )
00753 {
00754 msg_Err( p_this, "Could not set block size" );
00755 if( i_type == VCD_TYPE ) free( p_block );
00756 return( -1 );
00757 }
00758
00759 if( lseek( p_vcddev->i_device_handle,
00760 i_sector * VCD_SECTOR_SIZE, SEEK_SET ) == -1 )
00761 {
00762 msg_Err( p_this, "Could not lseek to sector %d", i_sector );
00763 if( i_type == VCD_TYPE ) free( p_block );
00764 return( -1 );
00765 }
00766
00767 if( read( p_vcddev->i_device_handle,
00768 p_block, VCD_SECTOR_SIZE * i_nb ) == -1 )
00769 {
00770 msg_Err( p_this, "Could not read sector %d", i_sector );
00771 if( i_type == VCD_TYPE ) free( p_block );
00772 return( -1 );
00773 }
00774
00775 #else
00776 for( i = 0; i < i_nb; i++ )
00777 {
00778 int i_dummy = i_sector + i + 2 * CD_FRAMES;
00779
00780 #define p_msf ((struct cdrom_msf0 *)(p_block + i * VCD_SECTOR_SIZE))
00781 p_msf->minute = i_dummy / (CD_FRAMES * CD_SECS);
00782 p_msf->second = ( i_dummy % (CD_FRAMES * CD_SECS) ) / CD_FRAMES;
00783 p_msf->frame = ( i_dummy % (CD_FRAMES * CD_SECS) ) % CD_FRAMES;
00784 #undef p_msf
00785
00786 if( ioctl( p_vcddev->i_device_handle, CDROMREADRAW,
00787 p_block + i * VCD_SECTOR_SIZE ) == -1 )
00788 {
00789 msg_Err( p_this, "could not read block %i from disc",
00790 i_sector );
00791
00792 if( i == 0 )
00793 {
00794 if( i_type == VCD_TYPE ) free( p_block );
00795 return( -1 );
00796 }
00797 else break;
00798 }
00799 }
00800 #endif
00801 }
00802
00803
00804
00805 if( i_type == VCD_TYPE )
00806 {
00807 for( i = 0; i < i_nb; i++ )
00808 {
00809 memcpy( p_buffer + i * VCD_DATA_SIZE,
00810 p_block + i * VCD_SECTOR_SIZE + VCD_DATA_START,
00811 VCD_DATA_SIZE );
00812 }
00813 free( p_block );
00814 }
00815
00816 return( 0 );
00817 }
00818
00819
00820
00821
00822
00823
00824
00825
00826 static int OpenVCDImage( vlc_object_t * p_this, const char *psz_dev,
00827 vcddev_t *p_vcddev )
00828 {
00829 int i_ret = -1;
00830 char *p_pos;
00831 char *psz_vcdfile = NULL;
00832 char *psz_cuefile = NULL;
00833 FILE *cuefile;
00834 char line[1024];
00835
00836
00837 p_pos = strrchr( psz_dev, '.' );
00838 if( p_pos && !strcmp( p_pos, ".cue" ) )
00839 {
00840 psz_cuefile = strdup( psz_dev );
00841 }
00842 else
00843 {
00844
00845
00846 if( p_pos )
00847 {
00848 psz_cuefile = malloc( p_pos - psz_dev + 5 );
00849 strncpy( psz_cuefile, psz_dev, p_pos - psz_dev );
00850 strcpy( psz_cuefile + (p_pos - psz_dev), ".cue");
00851 }
00852 else
00853 {
00854 psz_cuefile = malloc( strlen(psz_dev) + 5 );
00855 sprintf( psz_cuefile, "%s.cue", psz_dev );
00856 }
00857 }
00858
00859
00860 msg_Dbg( p_this,"trying .cue file: %s", psz_cuefile );
00861 cuefile = fopen( psz_cuefile, "rt" );
00862 if( cuefile && fscanf( cuefile, "FILE %c", line ) &&
00863 fgets( line, 1024, cuefile ) )
00864 {
00865 p_pos = strchr( line, '"' );
00866 if( p_pos )
00867 {
00868 *p_pos = 0;
00869
00870
00871 if( *line != '/' && ((p_pos = strrchr( psz_cuefile, '/' ))
00872 || (p_pos = strrchr( psz_cuefile, '\\' ) )) )
00873 {
00874 psz_vcdfile = malloc( strlen(line) +
00875 (p_pos - psz_cuefile + 1) + 1 );
00876 strncpy( psz_vcdfile, psz_cuefile, (p_pos - psz_cuefile + 1) );
00877 strcpy( psz_vcdfile + (p_pos - psz_cuefile + 1), line );
00878 }
00879 else psz_vcdfile = strdup( line );
00880 }
00881 }
00882
00883 if( psz_vcdfile )
00884 {
00885 msg_Dbg( p_this,"using vcd image file: %s", psz_vcdfile );
00886 p_vcddev->i_vcdimage_handle = open( psz_vcdfile,
00887 O_RDONLY | O_NONBLOCK | O_BINARY );
00888 i_ret = (p_vcddev->i_vcdimage_handle == -1) ? -1 : 0;
00889 }
00890
00891
00892
00893 if( i_ret == 0 )
00894 {
00895 int p_sectors[100];
00896 int i_tracks = 0;
00897 int i_num;
00898 char psz_dummy[10];
00899
00900 while( fgets( line, 1024, cuefile ) )
00901 {
00902
00903 if( !sscanf( line, "%9s", psz_dummy ) ||
00904 strcmp(psz_dummy, "TRACK") )
00905 continue;
00906
00907
00908 while( fgets( line, 1024, cuefile ) )
00909 {
00910 int i_min, i_sec, i_frame;
00911
00912 if( (sscanf( line, "%9s %2u %2u:%2u:%2u", psz_dummy, &i_num,
00913 &i_min, &i_sec, &i_frame ) != 5) || (i_num != 1) )
00914 continue;
00915
00916 i_tracks++;
00917 p_sectors[i_tracks - 1] = MSF_TO_LBA(i_min, i_sec, i_frame);
00918 msg_Dbg( p_this, "vcd track %i begins at sector:%i",
00919 i_tracks - 1, p_sectors[i_tracks - 1] );
00920 break;
00921 }
00922 }
00923
00924
00925 p_sectors[i_tracks] = lseek(p_vcddev->i_vcdimage_handle, 0, SEEK_END)
00926 / VCD_SECTOR_SIZE;
00927 msg_Dbg( p_this, "vcd track %i, begins at sector:%i",
00928 i_tracks, p_sectors[i_tracks] );
00929 p_vcddev->i_tracks = i_tracks;
00930 p_vcddev->p_sectors = malloc( (i_tracks + 1) * sizeof(int) );
00931 memcpy( p_vcddev->p_sectors, p_sectors, (i_tracks + 1) * sizeof(int) );
00932
00933 }
00934
00935 if( cuefile ) fclose( cuefile );
00936 if( psz_cuefile ) free( psz_cuefile );
00937 if( psz_vcdfile ) free( psz_vcdfile );
00938
00939 return i_ret;
00940 }
00941
00942
00943
00944
00945 static void CloseVCDImage( vlc_object_t * p_this, vcddev_t *p_vcddev )
00946 {
00947 if( p_vcddev->i_vcdimage_handle != -1 )
00948 close( p_vcddev->i_vcdimage_handle );
00949 else
00950 return;
00951
00952 if( p_vcddev->p_sectors )
00953 free( p_vcddev->p_sectors );
00954 }
00955
00956 #if defined( SYS_DARWIN )
00957
00958
00959
00960 static CDTOC *darwin_getTOC( vlc_object_t * p_this, const vcddev_t *p_vcddev )
00961 {
00962 mach_port_t port;
00963 char *psz_devname;
00964 kern_return_t ret;
00965 CDTOC *pTOC = NULL;
00966 io_iterator_t iterator;
00967 io_registry_entry_t service;
00968 CFMutableDictionaryRef properties;
00969 CFDataRef data;
00970
00971
00972 if( ( psz_devname = strrchr( p_vcddev->psz_dev, '/') ) != NULL )
00973 ++psz_devname;
00974 else
00975 psz_devname = p_vcddev->psz_dev;
00976
00977
00978 if( *psz_devname == 'r' )
00979 ++psz_devname;
00980
00981
00982 if( ( ret = IOMasterPort( MACH_PORT_NULL, &port ) ) != KERN_SUCCESS )
00983 {
00984 msg_Err( p_this, "IOMasterPort: 0x%08x", ret );
00985 return( NULL );
00986 }
00987
00988
00989 if( ( ret = IOServiceGetMatchingServices(
00990 port, IOBSDNameMatching( port, 0, psz_devname ),
00991 &iterator ) ) != KERN_SUCCESS )
00992 {
00993 msg_Err( p_this, "IOServiceGetMatchingServices: 0x%08x", ret );
00994 return( NULL );
00995 }
00996
00997
00998 service = IOIteratorNext( iterator );
00999 IOObjectRelease( iterator );
01000
01001
01002 while( service && !IOObjectConformsTo( service, kIOCDMediaClass ) )
01003 {
01004 if( ( ret = IORegistryEntryGetParentIterator( service,
01005 kIOServicePlane, &iterator ) ) != KERN_SUCCESS )
01006 {
01007 msg_Err( p_this, "IORegistryEntryGetParentIterator: 0x%08x", ret );
01008 IOObjectRelease( service );
01009 return( NULL );
01010 }
01011
01012 IOObjectRelease( service );
01013 service = IOIteratorNext( iterator );
01014 IOObjectRelease( iterator );
01015 }
01016
01017 if( service == NULL )
01018 {
01019 msg_Err( p_this, "search for kIOCDMediaClass came up empty" );
01020 return( NULL );
01021 }
01022
01023
01024 if( ( ret = IORegistryEntryCreateCFProperties( service, &properties,
01025 kCFAllocatorDefault, kNilOptions ) ) != KERN_SUCCESS )
01026 {
01027 msg_Err( p_this, "IORegistryEntryCreateCFProperties: 0x%08x", ret );
01028 IOObjectRelease( service );
01029 return( NULL );
01030 }
01031
01032
01033 if( ( data = (CFDataRef) CFDictionaryGetValue( properties,
01034 CFSTR(kIOCDMediaTOCKey) ) ) != NULL )
01035 {
01036 CFRange range;
01037 CFIndex buf_len;
01038
01039 buf_len = CFDataGetLength( data ) + 1;
01040 range = CFRangeMake( 0, buf_len );
01041
01042 if( ( pTOC = (CDTOC *)malloc( buf_len ) ) != NULL )
01043 {
01044 CFDataGetBytes( data, range, (u_char *)pTOC );
01045 }
01046 }
01047 else
01048 {
01049 msg_Err( p_this, "CFDictionaryGetValue failed" );
01050 }
01051
01052 CFRelease( properties );
01053 IOObjectRelease( service );
01054
01055 return( pTOC );
01056 }
01057
01058
01059
01060
01061 static int darwin_getNumberOfDescriptors( CDTOC *pTOC )
01062 {
01063 int i_descriptors;
01064
01065
01066 i_descriptors = pTOC->length;
01067
01068
01069 i_descriptors -= ( sizeof(pTOC->sessionFirst) +
01070 sizeof(pTOC->sessionLast) );
01071
01072
01073 i_descriptors /= sizeof(CDTOCDescriptor);
01074
01075 return( i_descriptors );
01076 }
01077
01078
01079
01080
01081 static int darwin_getNumberOfTracks( CDTOC *pTOC, int i_descriptors )
01082 {
01083 u_char track;
01084 int i, i_tracks = 0;
01085 CDTOCDescriptor *pTrackDescriptors;
01086
01087 pTrackDescriptors = pTOC->descriptors;
01088
01089 for( i = i_descriptors; i >= 0; i-- )
01090 {
01091 track = pTrackDescriptors[i].point;
01092
01093 if( track > CD_MAX_TRACK_NO || track < CD_MIN_TRACK_NO )
01094 continue;
01095
01096 i_tracks++;
01097 }
01098
01099 return( i_tracks );
01100 }
01101 #endif
01102
01103 #if defined( WIN32 )
01104
01105
01106
01107
01108
01109 static int win32_vcd_open( vlc_object_t * p_this, const char *psz_dev,
01110 vcddev_t *p_vcddev )
01111 {
01112
01113 p_vcddev->h_device_handle = NULL;
01114 p_vcddev->i_sid = 0;
01115 p_vcddev->hASPI = 0;
01116 p_vcddev->lpSendCommand = 0;
01117
01118 if( WIN_NT )
01119 {
01120 char psz_win32_drive[7];
01121
01122 msg_Dbg( p_this, "using winNT/2K/XP ioctl layer" );
01123
01124 sprintf( psz_win32_drive, "\\\\.\\%c:", psz_dev[0] );
01125
01126 p_vcddev->h_device_handle = CreateFile( psz_win32_drive, GENERIC_READ,
01127 FILE_SHARE_READ | FILE_SHARE_WRITE,
01128 NULL, OPEN_EXISTING,
01129 FILE_FLAG_NO_BUFFERING |
01130 FILE_FLAG_RANDOM_ACCESS, NULL );
01131 return (p_vcddev->h_device_handle == NULL) ? -1 : 0;
01132 }
01133 else
01134 {
01135 HMODULE hASPI = NULL;
01136 long (*lpGetSupport)( void ) = NULL;
01137 long (*lpSendCommand)( void* ) = NULL;
01138 DWORD dwSupportInfo;
01139 int i, j, i_hostadapters;
01140 char c_drive = psz_dev[0];
01141
01142 hASPI = LoadLibrary( "wnaspi32.dll" );
01143 if( hASPI != NULL )
01144 {
01145 (FARPROC) lpGetSupport = GetProcAddress( hASPI,
01146 "GetASPI32SupportInfo" );
01147 (FARPROC) lpSendCommand = GetProcAddress( hASPI,
01148 "SendASPI32Command" );
01149 }
01150
01151 if( hASPI == NULL || lpGetSupport == NULL || lpSendCommand == NULL )
01152 {
01153 msg_Dbg( p_this,
01154 "unable to load aspi or get aspi function pointers" );
01155 if( hASPI ) FreeLibrary( hASPI );
01156 return -1;
01157 }
01158
01159
01160
01161 dwSupportInfo = lpGetSupport();
01162
01163 if( HIBYTE( LOWORD ( dwSupportInfo ) ) == SS_NO_ADAPTERS )
01164 {
01165 msg_Dbg( p_this, "no host adapters found (aspi)" );
01166 FreeLibrary( hASPI );
01167 return -1;
01168 }
01169
01170 if( HIBYTE( LOWORD ( dwSupportInfo ) ) != SS_COMP )
01171 {
01172 msg_Dbg( p_this, "unable to initalize aspi layer" );
01173 FreeLibrary( hASPI );
01174 return -1;
01175 }
01176
01177 i_hostadapters = LOBYTE( LOWORD( dwSupportInfo ) );
01178 if( i_hostadapters == 0 )
01179 {
01180 FreeLibrary( hASPI );
01181 return -1;
01182 }
01183
01184 c_drive = c_drive > 'Z' ? c_drive - 'a' : c_drive - 'A';
01185
01186 for( i = 0; i < i_hostadapters; i++ )
01187 {
01188 for( j = 0; j < 15; j++ )
01189 {
01190 struct SRB_GetDiskInfo srbDiskInfo;
01191
01192 srbDiskInfo.SRB_Cmd = SC_GET_DISK_INFO;
01193 srbDiskInfo.SRB_HaId = i;
01194 srbDiskInfo.SRB_Flags = 0;
01195 srbDiskInfo.SRB_Hdr_Rsvd = 0;
01196 srbDiskInfo.SRB_Target = j;
01197 srbDiskInfo.SRB_Lun = 0;
01198
01199 lpSendCommand( (void*) &srbDiskInfo );
01200
01201 if( (srbDiskInfo.SRB_Status == SS_COMP) &&
01202 (srbDiskInfo.SRB_Int13HDriveInfo == c_drive) )
01203 {
01204
01205 struct SRB_GDEVBlock srbGDEVBlock;
01206
01207 memset( &srbGDEVBlock, 0, sizeof(struct SRB_GDEVBlock) );
01208 srbGDEVBlock.SRB_Cmd = SC_GET_DEV_TYPE;
01209 srbGDEVBlock.SRB_HaId = i;
01210 srbGDEVBlock.SRB_Target = j;
01211
01212 lpSendCommand( (void*) &srbGDEVBlock );
01213
01214 if( ( srbGDEVBlock.SRB_Status == SS_COMP ) &&
01215 ( srbGDEVBlock.SRB_DeviceType == DTYPE_CDROM ) )
01216 {
01217 p_vcddev->i_sid = MAKEWORD( i, j );
01218 p_vcddev->hASPI = (long)hASPI;
01219 p_vcddev->lpSendCommand = lpSendCommand;
01220 msg_Dbg( p_this, "using aspi layer" );
01221
01222 return 0;
01223 }
01224 else
01225 {
01226 FreeLibrary( hASPI );
01227 msg_Dbg( p_this, "%c: is not a cdrom drive",
01228 psz_dev[0] );
01229 return -1;
01230 }
01231 }
01232 }
01233 }
01234
01235 FreeLibrary( hASPI );
01236 msg_Dbg( p_this, "unable to get haid and target (aspi)" );
01237
01238 }
01239
01240 return -1;
01241 }
01242
01243 #endif