1 /****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 1998-2001 VideoLAN
5 * $Id: cdrom.c,v 1.2 2002/08/08 22:28:22 sam Exp $
7 * Author: Johan Bilien <jobi@via.ecp.fr>
8 * Jon Lech Johansen <jon-vl@nanocrew.net>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
38 #include <sys/types.h>
42 #include <sys/ioctl.h>
44 #if defined( SYS_BSDI )
46 #elif defined ( SYS_DARWIN )
47 # include <CoreFoundation/CFBase.h>
48 # include <IOKit/IOKitLib.h>
49 # include <IOKit/storage/IOCDTypes.h>
50 # include <IOKit/storage/IOCDMedia.h>
51 # include <IOKit/storage/IOCDMediaBSDClient.h>
52 #elif defined( HAVE_IOC_TOC_HEADER_IN_SYS_CDIO_H )
53 # include <sys/cdio.h>
54 # include <sys/cdrio.h>
56 # include <linux/cdrom.h>
61 /*****************************************************************************
63 *****************************************************************************/
64 #if defined( SYS_DARWIN )
65 CDTOC *getTOC( const char * );
66 #define freeTOC( p ) free( (void*)p )
67 int getNumberOfDescriptors( CDTOC * );
68 int getNumberOfTracks( CDTOC *, int );
69 #define CD_MIN_TRACK_NO 01
70 #define CD_MAX_TRACK_NO 99
73 /*****************************************************************************
74 * ioctl_ReadTocHeader: Read the TOC header and return the track number.
75 *****************************************************************************/
76 int ioctl_GetTrackCount( vlc_object_t * p_this, int i_fd, const char *psz_dev )
80 #if defined( SYS_DARWIN )
84 if( ( pTOC = getTOC( psz_dev ) ) == NULL )
86 msg_Err( p_this, "failed to get the TOC" );
90 i_descriptors = getNumberOfDescriptors( pTOC );
91 i_count = getNumberOfTracks( pTOC, i_descriptors );
95 #elif defined( HAVE_IOC_TOC_HEADER_IN_SYS_CDIO_H )
96 struct ioc_toc_header tochdr;
98 if( ioctl( i_fd, CDIOREADTOCHEADER, &tochdr ) == -1 )
100 msg_Err( p_this, "could not read TOCHDR" );
104 i_count = tochdr.ending_track - tochdr.starting_track + 1;
107 struct cdrom_tochdr tochdr;
109 /* First we read the TOC header */
110 if( ioctl( i_fd, CDROMREADTOCHDR, &tochdr ) == -1 )
112 msg_Err( p_this, "could not read TOCHDR" );
116 i_count = tochdr.cdth_trk1 - tochdr.cdth_trk0 + 1;
122 /*****************************************************************************
123 * ioctl_GetSectors: Read the Table of Contents and fill p_vcd.
124 *****************************************************************************/
125 int * ioctl_GetSectors( vlc_object_t *p_this, int i_fd, const char *psz_dev )
128 int *p_sectors = NULL;
130 #if defined( SYS_DARWIN )
135 CDTOCDescriptor *pTrackDescriptors;
137 if( ( pTOC = getTOC( psz_dev ) ) == NULL )
139 msg_Err( p_this, "failed to get the TOC" );
143 i_descriptors = getNumberOfDescriptors( pTOC );
144 i_tracks = getNumberOfTracks( pTOC, i_descriptors );
146 p_sectors = malloc( (i_tracks + 1) * sizeof(int) );
147 if( p_sectors == NULL )
149 msg_Err( p_this, "out of memory" );
154 pTrackDescriptors = pTOC->descriptors;
156 for( i_tracks = 0, i = 0; i <= i_descriptors; i++ )
158 track = pTrackDescriptors[i].point;
163 if( track > CD_MAX_TRACK_NO || track < CD_MIN_TRACK_NO )
166 p_sectors[i_tracks++] =
167 CDConvertMSFToLBA( pTrackDescriptors[i].p );
170 if( i_leadout == -1 )
172 msg_Err( p_this, "leadout not found" );
178 /* set leadout sector */
179 p_sectors[i_tracks] =
180 CDConvertMSFToLBA( pTrackDescriptors[i_leadout].p );
184 #elif defined( HAVE_IOC_TOC_HEADER_IN_SYS_CDIO_H )
185 struct ioc_read_toc_entry toc_entries;
187 i_tracks = ioctl_GetTrackCount( p_this, i_fd, psz_dev );
188 p_sectors = malloc( (i_tracks + 1) * sizeof(int) );
189 if( p_sectors == NULL )
191 msg_Err( p_this, "out of memory" );
195 toc_entries.address_format = CD_LBA_FORMAT;
196 toc_entries.starting_track = 0;
197 toc_entries.data_len = ( i_tracks + 1 ) * sizeof( struct cd_toc_entry );
198 toc_entries.data = (struct cd_toc_entry *) malloc( toc_entries.data_len );
199 if( toc_entries.data == NULL )
201 msg_Err( p_this, "out of memory" );
207 if( ioctl( i_fd, CDIOREADTOCENTRYS, &toc_entries ) == -1 )
209 msg_Err( p_this, "could not read the TOC" );
211 free( toc_entries.data );
215 /* Fill the p_sectors structure with the track/sector matches */
216 for( i = 0 ; i <= i_tracks ; i++ )
218 p_sectors[ i ] = ntohl( toc_entries.data[i].addr.lba );
221 struct cdrom_tochdr tochdr;
222 struct cdrom_tocentry tocent;
224 /* First we read the TOC header */
225 if( ioctl( i_fd, CDROMREADTOCHDR, &tochdr ) == -1 )
227 msg_Err( p_this, "could not read TOCHDR" );
231 i_tracks = tochdr.cdth_trk1 - tochdr.cdth_trk0 + 1;
233 p_sectors = malloc( (i_tracks + 1) * sizeof(int) );
234 if( p_sectors == NULL )
236 msg_Err( p_this, "out of memory" );
240 /* Fill the p_sectors structure with the track/sector matches */
241 for( i = 0 ; i <= i_tracks ; i++ )
243 tocent.cdte_format = CDROM_LBA;
245 ( i == i_tracks ) ? CDROM_LEADOUT : tochdr.cdth_trk0 + i;
247 if( ioctl( i_fd, CDROMREADTOCENTRY, &tocent ) == -1 )
249 msg_Err( p_this, "could not read TOCENTRY" );
254 p_sectors[ i ] = tocent.cdte_addr.lba;
261 /****************************************************************************
262 * ioctl_ReadSector: Read a sector (2324 bytes)
263 ****************************************************************************/
264 int ioctl_ReadSector( vlc_object_t *p_this,
265 int i_fd, int i_sector, byte_t * p_buffer )
267 byte_t p_block[ VCD_SECTOR_SIZE ];
269 #if defined( SYS_DARWIN )
270 dk_cd_read_t cd_read;
272 memset( &cd_read, 0, sizeof(cd_read) );
274 cd_read.offset = i_sector * VCD_SECTOR_SIZE;
275 cd_read.sectorArea = kCDSectorAreaSync | kCDSectorAreaHeader |
276 kCDSectorAreaSubHeader | kCDSectorAreaUser |
277 kCDSectorAreaAuxiliary;
278 cd_read.sectorType = kCDSectorTypeUnknown;
280 cd_read.buffer = p_block;
281 cd_read.bufferLength = sizeof(p_block);
283 if( ioctl( i_fd, DKIOCCDREAD, &cd_read ) == -1 )
285 msg_Err( p_this, "could not read block %d", i_sector );
289 #elif defined( HAVE_IOC_TOC_HEADER_IN_SYS_CDIO_H )
291 int i_size = VCD_SECTOR_SIZE;
293 if( ioctl( i_fd, CDRIOCSETBLOCKSIZE, &i_size ) == -1 )
295 msg_Err( p_this, "Could not set block size" );
299 if( lseek( i_fd, i_sector * VCD_SECTOR_SIZE, SEEK_SET ) == -1 )
301 msg_Err( p_this, "Could not lseek to sector %d", i_sector );
305 if( read( i_fd, p_block, VCD_SECTOR_SIZE ) == -1 )
307 msg_Err( p_this, "Could not read sector %d", i_sector );
312 int i_dummy = i_sector + 2 * CD_FRAMES;
314 #define p_msf ((struct cdrom_msf0 *)p_block)
315 p_msf->minute = i_dummy / (CD_FRAMES * CD_SECS);
316 p_msf->second = ( i_dummy % (CD_FRAMES * CD_SECS) ) / CD_FRAMES;
317 p_msf->frame = ( i_dummy % (CD_FRAMES * CD_SECS) ) % CD_FRAMES;
320 if( ioctl(i_fd, CDROMREADRAW, p_block) == -1 )
322 msg_Err( p_this, "could not read block %i from disc", i_sector );
327 /* We don't want to keep the header of the read sector */
328 memcpy( p_buffer, p_block + VCD_DATA_START, VCD_DATA_SIZE );
333 #if defined( SYS_DARWIN )
334 /****************************************************************************
335 * getTOC: get the TOC
336 ****************************************************************************/
337 CDTOC *getTOC( const char *psz_dev )
343 io_iterator_t iterator;
344 io_registry_entry_t service;
345 CFDictionaryRef properties;
348 if( psz_dev == NULL )
350 msg_Err( p_this, "invalid device path" );
354 /* get the device name */
355 if( ( psz_devname = strrchr( psz_dev, '/') ) != NULL )
358 psz_devname = (char *)psz_dev;
360 /* unraw the device name */
361 if( *psz_devname == 'r' )
364 /* get port for IOKit communication */
365 if( ( ret = IOMasterPort( MACH_PORT_NULL, &port ) ) != KERN_SUCCESS )
367 msg_Err( p_this, "IOMasterPort: 0x%08x", ret );
371 /* get service iterator for the device */
372 if( ( ret = IOServiceGetMatchingServices(
373 port, IOBSDNameMatching( port, 0, psz_devname ),
374 &iterator ) ) != KERN_SUCCESS )
376 msg_Err( p_this, "IOServiceGetMatchingServices: 0x%08x", ret );
381 service = IOIteratorNext( iterator );
382 IOObjectRelease( iterator );
384 /* search for kIOCDMediaClass */
385 while( service && !IOObjectConformsTo( service, kIOCDMediaClass ) )
387 if( ( ret = IORegistryEntryGetParentIterator( service,
388 kIOServicePlane, &iterator ) ) != KERN_SUCCESS )
390 msg_Err( p_this, "IORegistryEntryGetParentIterator: 0x%08x", ret );
391 IOObjectRelease( service );
395 IOObjectRelease( service );
396 service = IOIteratorNext( iterator );
397 IOObjectRelease( iterator );
400 if( service == NULL )
402 msg_Err( p_this, "search for kIOCDMediaClass came up empty" );
406 /* create a CF dictionary containing the TOC */
407 if( ( ret = IORegistryEntryCreateCFProperties( service, &properties,
408 kCFAllocatorDefault, kNilOptions ) ) != KERN_SUCCESS )
410 msg_Err( p_this, "IORegistryEntryCreateCFProperties: 0x%08x", ret );
411 IOObjectRelease( service );
415 /* get the TOC from the dictionary */
416 if( ( data = (CFDataRef) CFDictionaryGetValue( properties,
417 CFSTR(kIOCDMediaTOCKey) ) ) != NULL )
422 buf_len = CFDataGetLength( data ) + 1;
423 range = CFRangeMake( 0, buf_len );
425 if( ( pTOC = (CDTOC *)malloc( buf_len ) ) != NULL )
427 CFDataGetBytes( data, range, (u_char *)pTOC );
432 msg_Err( p_this, "CFDictionaryGetValue failed" );
435 CFRelease( properties );
436 IOObjectRelease( service );
441 /****************************************************************************
442 * getNumberOfDescriptors: get number of descriptors in TOC
443 ****************************************************************************/
444 int getNumberOfDescriptors( CDTOC *pTOC )
449 i_descriptors = pTOC->length;
451 /* remove the first and last session */
452 i_descriptors -= ( sizeof(pTOC->sessionFirst) +
453 sizeof(pTOC->sessionLast) );
455 /* divide the length by the size of a single descriptor */
456 i_descriptors /= sizeof(CDTOCDescriptor);
458 return( i_descriptors );
461 /****************************************************************************
462 * getNumberOfTracks: get number of tracks in TOC
463 ****************************************************************************/
464 int getNumberOfTracks( CDTOC *pTOC, int i_descriptors )
468 CDTOCDescriptor *pTrackDescriptors;
470 pTrackDescriptors = pTOC->descriptors;
472 for( i = i_descriptors; i >= 0; i-- )
474 track = pTrackDescriptors[i].point;
476 if( track > CD_MAX_TRACK_NO || track < CD_MIN_TRACK_NO )