filename | src/drivers/cd_osx.c |
changeset | 782:1af8b5ce627c |
prev | 739:46fa527d9fef |
next | 786:8f6ece92500e |
author | nkeynes |
date | Tue Jul 29 06:35:28 2008 +0000 (15 years ago) |
permissions | -rw-r--r-- |
last change | Workaround OS X's inability to handle CD reads of unknown size (ie where the read request failed to specify an expected sector type) - read raw sectors and parse it out by hand. |
file | annotate | diff | log | raw |
nkeynes@709 | 1 | /** |
nkeynes@709 | 2 | * $Id$ |
nkeynes@709 | 3 | * |
nkeynes@709 | 4 | * OSX native cd-rom driver. |
nkeynes@709 | 5 | * |
nkeynes@709 | 6 | * Copyright (c) 2005 Nathan Keynes. |
nkeynes@709 | 7 | * |
nkeynes@709 | 8 | * This program is free software; you can redistribute it and/or modify |
nkeynes@709 | 9 | * it under the terms of the GNU General Public License as published by |
nkeynes@709 | 10 | * the Free Software Foundation; either version 2 of the License, or |
nkeynes@709 | 11 | * (at your option) any later version. |
nkeynes@709 | 12 | * |
nkeynes@709 | 13 | * This program is distributed in the hope that it will be useful, |
nkeynes@709 | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
nkeynes@709 | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
nkeynes@709 | 16 | * GNU General Public License for more details. |
nkeynes@709 | 17 | */ |
nkeynes@709 | 18 | |
nkeynes@709 | 19 | #include <IOKit/IOKitLib.h> |
nkeynes@720 | 20 | #include <IOKit/IOBSD.h> |
nkeynes@709 | 21 | #include <IOKit/storage/IOStorageDeviceCharacteristics.h> |
nkeynes@720 | 22 | #include <IOKit/storage/IOCDMediaBSDClient.h> |
nkeynes@720 | 23 | #include <IOKit/storage/IOCDTypes.h> |
nkeynes@720 | 24 | #include <sys/param.h> |
nkeynes@720 | 25 | #include <errno.h> |
nkeynes@709 | 26 | #include <stdio.h> |
nkeynes@720 | 27 | #include <string.h> |
nkeynes@720 | 28 | #include <paths.h> |
nkeynes@709 | 29 | #include "gdrom/gddriver.h" |
nkeynes@720 | 30 | #include "gdrom/packet.h" |
nkeynes@720 | 31 | #include "drivers/osx_iokit.h" |
nkeynes@709 | 32 | |
nkeynes@720 | 33 | #define MAXTOCENTRIES 600 /* This is a fairly generous overestimate really */ |
nkeynes@720 | 34 | #define MAXTOCSIZE 4 + (MAXTOCENTRIES*11) |
nkeynes@720 | 35 | |
nkeynes@720 | 36 | static gboolean cdrom_osx_image_is_valid( FILE *f ); |
nkeynes@720 | 37 | static gdrom_disc_t cdrom_osx_open_device( const gchar *filename, FILE *f ); |
nkeynes@720 | 38 | static gdrom_error_t cdrom_osx_read_toc( gdrom_image_t disc ); |
nkeynes@720 | 39 | static gdrom_error_t cdrom_osx_read_sector( gdrom_disc_t disc, uint32_t sector, |
nkeynes@736 | 40 | int mode, unsigned char *buf, uint32_t *length ); |
nkeynes@709 | 41 | |
nkeynes@709 | 42 | struct gdrom_image_class cdrom_device_class = { "osx", NULL, |
nkeynes@736 | 43 | cdrom_osx_image_is_valid, cdrom_osx_open_device }; |
nkeynes@709 | 44 | |
nkeynes@720 | 45 | #define OSX_DRIVE(disc) ( (osx_cdrom_drive_t)(((gdrom_image_t)disc)->private) ) |
nkeynes@709 | 46 | |
nkeynes@720 | 47 | static void cdrom_osx_destroy( gdrom_disc_t disc ) |
nkeynes@709 | 48 | { |
nkeynes@720 | 49 | osx_cdrom_close_drive( OSX_DRIVE(disc) ); |
nkeynes@720 | 50 | gdrom_image_destroy_no_close( disc ); |
nkeynes@709 | 51 | } |
nkeynes@709 | 52 | |
nkeynes@720 | 53 | static void cdrom_osx_media_changed( osx_cdrom_drive_t drive, gboolean present, |
nkeynes@720 | 54 | void *user_data ) |
nkeynes@709 | 55 | { |
nkeynes@720 | 56 | gdrom_image_t image = (gdrom_image_t)user_data; |
nkeynes@720 | 57 | if( present ) { |
nkeynes@720 | 58 | cdrom_osx_read_toc( image ); |
nkeynes@720 | 59 | } else { |
nkeynes@720 | 60 | image->disc_type = IDE_DISC_NONE; |
nkeynes@720 | 61 | image->track_count = 0; |
nkeynes@709 | 62 | } |
nkeynes@709 | 63 | } |
nkeynes@709 | 64 | |
nkeynes@720 | 65 | |
nkeynes@720 | 66 | static gdrom_disc_t cdrom_osx_new( const char *name, osx_cdrom_drive_t drive ) |
nkeynes@709 | 67 | { |
nkeynes@720 | 68 | char tmp[strlen(name)+7]; |
nkeynes@720 | 69 | sprintf( tmp, "dvd://%s", name ); |
nkeynes@720 | 70 | gdrom_image_t image = (gdrom_image_t)gdrom_image_new(tmp, NULL); |
nkeynes@720 | 71 | image->private = drive; |
nkeynes@736 | 72 | |
nkeynes@720 | 73 | image->disc.read_sector = cdrom_osx_read_sector; |
nkeynes@720 | 74 | image->disc.close = cdrom_osx_destroy; |
nkeynes@720 | 75 | cdrom_osx_read_toc(image); |
nkeynes@720 | 76 | osx_cdrom_set_media_changed_callback( drive, cdrom_osx_media_changed, image ); |
nkeynes@720 | 77 | return (gdrom_disc_t)image; |
nkeynes@709 | 78 | } |
nkeynes@709 | 79 | |
nkeynes@720 | 80 | gdrom_disc_t cdrom_open_device( const gchar *method, const gchar *path ) |
nkeynes@709 | 81 | { |
nkeynes@720 | 82 | gdrom_disc_t result = NULL; |
nkeynes@736 | 83 | |
nkeynes@720 | 84 | osx_cdrom_drive_t drive = osx_cdrom_open_drive(path); |
nkeynes@720 | 85 | if( drive == NULL ) { |
nkeynes@709 | 86 | return NULL; |
nkeynes@720 | 87 | } else { |
nkeynes@720 | 88 | return cdrom_osx_new( path, drive ); |
nkeynes@709 | 89 | } |
nkeynes@709 | 90 | } |
nkeynes@709 | 91 | |
nkeynes@720 | 92 | |
nkeynes@720 | 93 | |
nkeynes@720 | 94 | static gboolean cdrom_enum_callback( io_object_t object, char *vendor, char *product, char *iopath, void *ptr ) |
nkeynes@709 | 95 | { |
nkeynes@709 | 96 | GList **list = (GList **)ptr; |
nkeynes@720 | 97 | char tmp1[sizeof(io_string_t) + 6]; |
nkeynes@709 | 98 | char tmp2[512]; |
nkeynes@720 | 99 | snprintf( tmp1, sizeof(tmp1), "dvd://%s", iopath ); |
nkeynes@709 | 100 | snprintf( tmp2, sizeof(tmp2), "%s %s", vendor, product ); |
nkeynes@709 | 101 | *list = g_list_append( *list, gdrom_device_new( tmp1, tmp2 ) ); |
nkeynes@709 | 102 | return FALSE; |
nkeynes@709 | 103 | } |
nkeynes@709 | 104 | |
nkeynes@709 | 105 | GList *cdrom_get_native_devices(void) |
nkeynes@709 | 106 | { |
nkeynes@709 | 107 | GList *list = NULL; |
nkeynes@720 | 108 | find_cdrom_drive(cdrom_enum_callback, &list); |
nkeynes@736 | 109 | |
nkeynes@720 | 110 | osx_register_iokit_notifications(); |
nkeynes@709 | 111 | return list; |
nkeynes@709 | 112 | } |
nkeynes@709 | 113 | |
nkeynes@709 | 114 | |
nkeynes@709 | 115 | |
nkeynes@720 | 116 | static gboolean cdrom_osx_image_is_valid( FILE *f ) |
nkeynes@709 | 117 | { |
nkeynes@709 | 118 | return FALSE; |
nkeynes@709 | 119 | } |
nkeynes@709 | 120 | |
nkeynes@720 | 121 | static gdrom_disc_t cdrom_osx_open_device( const gchar *filename, FILE *f ) |
nkeynes@709 | 122 | { |
nkeynes@709 | 123 | return NULL; |
nkeynes@709 | 124 | } |
nkeynes@720 | 125 | |
nkeynes@720 | 126 | static gdrom_error_t cdrom_osx_read_toc( gdrom_image_t image ) |
nkeynes@720 | 127 | { |
nkeynes@720 | 128 | osx_cdrom_drive_t drive = OSX_DRIVE(image); |
nkeynes@736 | 129 | |
nkeynes@720 | 130 | int fh = osx_cdrom_get_media_handle(drive); |
nkeynes@720 | 131 | if( fh == -1 ) { |
nkeynes@720 | 132 | image->disc_type = IDE_DISC_NONE; |
nkeynes@720 | 133 | image->track_count = 0; |
nkeynes@720 | 134 | return -1; |
nkeynes@720 | 135 | } else { |
nkeynes@720 | 136 | unsigned char buf[MAXTOCSIZE]; |
nkeynes@720 | 137 | dk_cd_read_toc_t readtoc; |
nkeynes@720 | 138 | memset( &readtoc, 0, sizeof(readtoc) ); |
nkeynes@720 | 139 | readtoc.format = 2; |
nkeynes@720 | 140 | readtoc.formatAsTime = 0; |
nkeynes@720 | 141 | readtoc.address.session = 0; |
nkeynes@720 | 142 | readtoc.bufferLength = sizeof(buf); |
nkeynes@720 | 143 | readtoc.buffer = buf; |
nkeynes@736 | 144 | |
nkeynes@720 | 145 | if( ioctl(fh, DKIOCCDREADTOC, &readtoc ) == -1 ) { |
nkeynes@720 | 146 | image->disc_type = IDE_DISC_NONE; |
nkeynes@720 | 147 | image->track_count = 0; |
nkeynes@720 | 148 | return -1; |
nkeynes@720 | 149 | } else { |
nkeynes@720 | 150 | mmc_parse_toc2( image, buf ); |
nkeynes@720 | 151 | } |
nkeynes@720 | 152 | } |
nkeynes@720 | 153 | return 0; |
nkeynes@720 | 154 | } |
nkeynes@720 | 155 | |
nkeynes@782 | 156 | static gdrom_error_t cdrom_osx_read_sector( gdrom_disc_t disc, uint32_t lba, |
nkeynes@736 | 157 | int mode, unsigned char *buf, uint32_t *length ) |
nkeynes@720 | 158 | { |
nkeynes@782 | 159 | gdrom_image_t image = (gdrom_image_t)disc; |
nkeynes@782 | 160 | int real_lba = lba - 150; |
nkeynes@782 | 161 | int sector_size; |
nkeynes@782 | 162 | int direct_read = 1; |
nkeynes@782 | 163 | char data[MAX_SECTOR_SIZE]; |
nkeynes@720 | 164 | osx_cdrom_drive_t drive = OSX_DRIVE(disc); |
nkeynes@782 | 165 | |
nkeynes@720 | 166 | int fh = osx_cdrom_get_media_handle(drive); |
nkeynes@720 | 167 | if( fh == -1 ) { |
nkeynes@720 | 168 | return PKT_ERR_NODISC; |
nkeynes@720 | 169 | } else { |
nkeynes@720 | 170 | dk_cd_read_t readcd; |
nkeynes@782 | 171 | memset( &readcd, 0, sizeof(readcd) ); |
nkeynes@782 | 172 | readcd.buffer = buf; |
nkeynes@720 | 173 | |
nkeynes@720 | 174 | // This is complicated by needing to know the exact read size. Gah. |
nkeynes@720 | 175 | if( READ_CD_RAW(mode) ) { |
nkeynes@782 | 176 | sector_size = 2352; |
nkeynes@720 | 177 | readcd.sectorArea = 0xF8; |
nkeynes@782 | 178 | } else if ( READ_CD_MODE(mode) == READ_CD_MODE_ANY ) { |
nkeynes@782 | 179 | /* Sector could be anything - need to do a raw read and then parse |
nkeynes@782 | 180 | * the requested data out ourselves |
nkeynes@782 | 181 | */ |
nkeynes@782 | 182 | int track_no = gdrom_image_get_track_by_lba( image, lba ); |
nkeynes@782 | 183 | struct gdrom_track *track = &image->track[track_no-1]; |
nkeynes@782 | 184 | |
nkeynes@782 | 185 | sector_size = 2352; |
nkeynes@782 | 186 | if( track->mode == GDROM_CDDA ) { |
nkeynes@782 | 187 | readcd.sectorArea = kCDSectorAreaUser; |
nkeynes@782 | 188 | } else { |
nkeynes@782 | 189 | readcd.sectorArea = 0xF8; |
nkeynes@782 | 190 | readcd.buffer = data; |
nkeynes@782 | 191 | direct_read = 0; |
nkeynes@782 | 192 | } |
nkeynes@720 | 193 | } else { |
nkeynes@720 | 194 | // This is incomplete... |
nkeynes@720 | 195 | if( READ_CD_DATA(mode) ) { |
nkeynes@720 | 196 | readcd.sectorArea = kCDSectorAreaUser; |
nkeynes@720 | 197 | switch( READ_CD_MODE(mode) ) { |
nkeynes@720 | 198 | case READ_CD_MODE_CDDA: |
nkeynes@782 | 199 | sector_size = 2352; |
nkeynes@720 | 200 | break; |
nkeynes@720 | 201 | case READ_CD_MODE_1: |
nkeynes@720 | 202 | case READ_CD_MODE_2_FORM_1: |
nkeynes@782 | 203 | sector_size = 2048; |
nkeynes@720 | 204 | break; |
nkeynes@720 | 205 | case READ_CD_MODE_2: |
nkeynes@782 | 206 | sector_size = 2336; |
nkeynes@720 | 207 | break; |
nkeynes@720 | 208 | case READ_CD_MODE_2_FORM_2: |
nkeynes@782 | 209 | sector_size = 2324; |
nkeynes@720 | 210 | break; |
nkeynes@720 | 211 | } |
nkeynes@720 | 212 | } |
nkeynes@720 | 213 | } |
nkeynes@736 | 214 | |
nkeynes@782 | 215 | readcd.offset = sector_size * real_lba; |
nkeynes@720 | 216 | readcd.sectorType = READ_CD_MODE(mode)>>1; |
nkeynes@782 | 217 | readcd.bufferLength = sector_size; |
nkeynes@720 | 218 | if( ioctl( fh, DKIOCCDREAD, &readcd ) == -1 ) { |
nkeynes@720 | 219 | return -1; |
nkeynes@782 | 220 | } |
nkeynes@782 | 221 | |
nkeynes@782 | 222 | if( direct_read ) { |
nkeynes@782 | 223 | *length = sector_size; |
nkeynes@720 | 224 | } else { |
nkeynes@782 | 225 | gdrom_extract_raw_data_sector( data, mode, buf, length ); |
nkeynes@720 | 226 | } |
nkeynes@782 | 227 | return 0; |
nkeynes@720 | 228 | } |
nkeynes@720 | 229 | } |
nkeynes@720 | 230 |
.