1 /****************************************************************************
2 * cdrom_tools.c: cdrom tools
3 *****************************************************************************
4 * Copyright (C) 1998-2001 VideoLAN
5 * $Id: cdrom_tools.c,v 1.1 2002/02/20 05:50:00 jlj 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 *****************************************************************************/
31 #include <videolan/vlc.h>
38 #include <sys/types.h>
42 #include <sys/ioctl.h>
44 #if defined(HAVE_BSD_DVD_STRUCT) || \
45 defined(DVD_STRUCT_IN_BSDI_DVDIOCTL_DVD_H) || \
46 defined(DVD_STRUCT_IN_DVD_H)
48 #elif defined ( SYS_DARWIN )
49 # include <CoreFoundation/CFBase.h>
50 # include <IOKit/IOKitLib.h>
51 # include <IOKit/storage/IOCDTypes.h>
52 # include <IOKit/storage/IOCDMedia.h>
53 # include <IOKit/storage/IOCDMediaBSDClient.h>
55 # include <linux/cdrom.h>
58 #include "cdrom_tools.h"
60 /*****************************************************************************
62 *****************************************************************************/
63 #if defined( SYS_DARWIN )
64 CDTOC *getTOC( const char * );
65 #define freeTOC( p ) free( (void*)p )
66 int getNumberOfDescriptors( CDTOC * );
67 int getNumberOfTracks( CDTOC *, int );
68 #define CD_MIN_TRACK_NO 01
69 #define CD_MAX_TRACK_NO 99
72 /*****************************************************************************
73 * ioctl_ReadTocHeader: Read the TOC header and return the track number.
74 *****************************************************************************/
75 int ioctl_GetTrackCount( int i_fd, const char *psz_dev )
79 #if defined( SYS_DARWIN )
83 if( ( pTOC = getTOC( psz_dev ) ) == NULL )
85 intf_ErrMsg( "vcd error: failed to get the TOC" );
89 i_descriptors = getNumberOfDescriptors( pTOC );
90 i_count = getNumberOfTracks( pTOC, i_descriptors );
95 struct cdrom_tochdr tochdr;
97 /* First we read the TOC header */
98 if( ioctl( i_fd, CDROMREADTOCHDR, &tochdr ) == -1 )
100 intf_ErrMsg( "vcd error: could not read TOCHDR" );
104 i_count = tochdr.cdth_trk1 - tochdr.cdth_trk0 + 1;
110 /*****************************************************************************
111 * ioctl_GetSectors: Read the Table of Contents and fill p_vcd.
112 *****************************************************************************/
113 int * ioctl_GetSectors( int i_fd, const char *psz_dev )
116 int *p_sectors = NULL;
118 #if defined( SYS_DARWIN )
123 CDTOCDescriptor *pTrackDescriptors;
125 if( ( pTOC = getTOC( psz_dev ) ) == NULL )
127 intf_ErrMsg( "vcd error: failed to get the TOC" );
131 i_descriptors = getNumberOfDescriptors( pTOC );
132 i_tracks = getNumberOfTracks( pTOC, i_descriptors );
134 p_sectors = malloc( (i_tracks + 1) * sizeof(int) );
135 if( p_sectors == NULL )
137 intf_ErrMsg( "vcd error: could not allocate p_sectors" );
142 pTrackDescriptors = pTOC->descriptors;
144 for( i_tracks = 0, i = 0; i <= i_descriptors; i++ )
146 track = pTrackDescriptors[i].point;
151 if( track > CD_MAX_TRACK_NO || track < CD_MIN_TRACK_NO )
154 p_sectors[i_tracks++] =
155 CDConvertMSFToLBA( pTrackDescriptors[i].p );
158 if( i_leadout == -1 )
160 intf_ErrMsg( "vcd error: leadout not found" );
166 /* set leadout sector */
167 p_sectors[i_tracks] =
168 CDConvertMSFToLBA( pTrackDescriptors[i_leadout].p );
173 struct cdrom_tochdr tochdr;
174 struct cdrom_tocentry tocent;
176 /* First we read the TOC header */
177 if( ioctl( i_fd, CDROMREADTOCHDR, &tochdr ) == -1 )
179 intf_ErrMsg( "vcd error: could not read TOCHDR" );
183 i_tracks = tochdr.cdth_trk1 - tochdr.cdth_trk0 + 1;
185 p_sectors = malloc( (i_tracks + 1) * sizeof(int) );
186 if( p_sectors == NULL )
188 intf_ErrMsg( "vcd error: could not allocate p_sectors" );
192 /* Fill the p_sectors structure with the track/sector matches */
193 for( i = 0 ; i <= i_tracks ; i++ )
195 tocent.cdte_format = CDROM_LBA;
197 ( i == i_tracks ) ? CDROM_LEADOUT : tochdr.cdth_trk0 + i;
199 if( ioctl( i_fd, CDROMREADTOCENTRY, &tocent ) == -1 )
201 intf_ErrMsg( "vcd error: could not read TOCENTRY" );
206 p_sectors[ i ] = tocent.cdte_addr.lba;
213 /****************************************************************************
214 * ioctl_ReadSector: Read a sector (2324 bytes)
215 ****************************************************************************/
216 int ioctl_ReadSector( int i_fd, int i_sector, byte_t * p_buffer )
218 byte_t p_block[ VCD_SECTOR_SIZE ];
220 #if defined( SYS_DARWIN )
221 dk_cd_read_t cd_read;
223 memset( &cd_read, 0, sizeof(cd_read) );
225 cd_read.offset = i_sector * VCD_SECTOR_SIZE;
226 cd_read.sectorArea = kCDSectorAreaSync | kCDSectorAreaHeader |
227 kCDSectorAreaSubHeader | kCDSectorAreaUser |
228 kCDSectorAreaAuxiliary;
229 cd_read.sectorType = kCDSectorTypeUnknown;
231 cd_read.buffer = p_block;
232 cd_read.bufferLength = sizeof(p_block);
234 if( ioctl( i_fd, DKIOCCDREAD, &cd_read ) == -1 )
236 intf_ErrMsg( "vcd error: could not read block %d", i_sector );
241 int i_dummy = i_sector + 2 * CD_FRAMES;
243 #define p_msf ((struct cdrom_msf0 *)p_block)
244 p_msf->minute = i_dummy / (CD_FRAMES * CD_SECS);
245 p_msf->second = ( i_dummy % (CD_FRAMES * CD_SECS) ) / CD_FRAMES;
246 p_msf->frame = ( i_dummy % (CD_FRAMES * CD_SECS) ) % CD_FRAMES;
249 if( ioctl(i_fd, CDROMREADRAW, p_block) == -1 )
251 intf_ErrMsg( "vcd error: could not read block %i from disc",
257 /* We don't want to keep the header of the read sector */
258 FAST_MEMCPY( p_buffer, p_block + VCD_DATA_START, VCD_DATA_SIZE );
263 #if defined( SYS_DARWIN )
264 /****************************************************************************
265 * getTOC: get the TOC
266 ****************************************************************************/
267 CDTOC *getTOC( const char *psz_dev )
273 io_iterator_t iterator;
274 io_registry_entry_t service;
275 CFDictionaryRef properties;
278 if( psz_dev == NULL )
280 intf_ErrMsg( "vcd error: invalid device path" );
284 /* get the device name */
285 if( ( psz_devname = strrchr( psz_dev, '/') ) != NULL )
288 psz_devname = (char *)psz_dev;
290 /* unraw the device name */
291 if( *psz_devname == 'r' )
294 /* get port for IOKit communication */
295 if( ( ret = IOMasterPort( MACH_PORT_NULL, &port ) ) != KERN_SUCCESS )
297 intf_ErrMsg( "vcd error: IOMasterPort: 0x%08x", ret );
301 /* get service iterator for the device */
302 if( ( ret = IOServiceGetMatchingServices(
303 port, IOBSDNameMatching( port, 0, psz_devname ),
304 &iterator ) ) != KERN_SUCCESS )
306 intf_ErrMsg( "vcd error: IOServiceGetMatchingServices: 0x%08x", ret );
311 service = IOIteratorNext( iterator );
312 IOObjectRelease( iterator );
314 /* search for kIOCDMediaClass */
315 while( service && !IOObjectConformsTo( service, kIOCDMediaClass ) )
317 if( ( ret = IORegistryEntryGetParentIterator( service,
318 kIOServicePlane, &iterator ) ) != KERN_SUCCESS )
320 intf_ErrMsg( "vcd error: " \
321 "IORegistryEntryGetParentIterator: 0x%08x", ret );
322 IOObjectRelease( service );
326 IOObjectRelease( service );
327 service = IOIteratorNext( iterator );
328 IOObjectRelease( iterator );
331 if( service == NULL )
333 intf_ErrMsg( "vcd error: search for kIOCDMediaClass came up empty" );
337 /* create a CF dictionary containing the TOC */
338 if( ( ret = IORegistryEntryCreateCFProperties( service, &properties,
339 kCFAllocatorDefault, kNilOptions ) ) != KERN_SUCCESS )
341 intf_ErrMsg( "vcd error: " \
342 " IORegistryEntryCreateCFProperties: 0x%08x", ret );
343 IOObjectRelease( service );
347 /* get the TOC from the dictionary */
348 if( ( data = (CFDataRef) CFDictionaryGetValue( properties,
349 CFSTR(kIOCDMediaTOCKey) ) ) != NULL )
354 buf_len = CFDataGetLength( data ) + 1;
355 range = CFRangeMake( 0, buf_len );
357 if( ( pTOC = (CDTOC *)malloc( buf_len ) ) != NULL )
359 CFDataGetBytes( data, range, (u_char *)pTOC );
364 intf_ErrMsg( "vcd error: CFDictionaryGetValue failed" );
367 CFRelease( properties );
368 IOObjectRelease( service );
373 /****************************************************************************
374 * getNumberOfDescriptors: get number of descriptors in TOC
375 ****************************************************************************/
376 int getNumberOfDescriptors( CDTOC *pTOC )
381 i_descriptors = pTOC->length;
383 /* remove the first and last session */
384 i_descriptors -= ( sizeof(pTOC->sessionFirst) +
385 sizeof(pTOC->sessionLast) );
387 /* divide the length by the size of a single descriptor */
388 i_descriptors /= sizeof(CDTOCDescriptor);
390 return( i_descriptors );
393 /****************************************************************************
394 * getNumberOfTracks: get number of tracks in TOC
395 ****************************************************************************/
396 int getNumberOfTracks( CDTOC *pTOC, int i_descriptors )
400 CDTOCDescriptor *pTrackDescriptors;
402 pTrackDescriptors = pTOC->descriptors;
404 for( i = i_descriptors; i >= 0; i-- )
406 track = pTrackDescriptors[i].point;
408 if( track > CD_MAX_TRACK_NO || track < CD_MIN_TRACK_NO )