filename | src/drivers/cd_osx.c |
changeset | 720:b5594d1ac80a |
prev | 709:18c39a8e504c |
next | 736:a02d1475ccfd |
author | nkeynes |
date | Sat Jul 05 11:57:36 2008 +0000 (14 years ago) |
permissions | -rw-r--r-- |
last change | Get OS X cdrom driver to the 'sort of working' stage. Hide most of the IOKit fun in a separate osx_iokit module. |
file | annotate | diff | log | raw |
1.1 --- a/src/drivers/cd_osx.c Wed Jun 25 10:40:45 2008 +00001.2 +++ b/src/drivers/cd_osx.c Sat Jul 05 11:57:36 2008 +00001.3 @@ -17,166 +17,86 @@1.4 */1.6 #include <IOKit/IOKitLib.h>1.7 +#include <IOKit/IOBSD.h>1.8 #include <IOKit/storage/IOStorageDeviceCharacteristics.h>1.9 -#include <IOKit/scsi-commands/SCSITaskLib.h>1.10 -#include <IOKit/scsi-commands/SCSICommandOperationCodes.h>1.11 +#include <IOKit/storage/IOCDMediaBSDClient.h>1.12 +#include <IOKit/storage/IOCDTypes.h>1.13 +#include <sys/param.h>1.14 +#include <errno.h>1.15 #include <stdio.h>1.16 +#include <string.h>1.17 +#include <paths.h>1.18 #include "gdrom/gddriver.h"1.19 +#include "gdrom/packet.h"1.20 +#include "drivers/osx_iokit.h"1.22 -static gboolean osx_image_is_valid( FILE *f );1.23 -static gdrom_disc_t osx_open_device( const gchar *filename, FILE *f );1.24 +#define MAXTOCENTRIES 600 /* This is a fairly generous overestimate really */1.25 +#define MAXTOCSIZE 4 + (MAXTOCENTRIES*11)1.26 +1.27 +static gboolean cdrom_osx_image_is_valid( FILE *f );1.28 +static gdrom_disc_t cdrom_osx_open_device( const gchar *filename, FILE *f );1.29 +static gdrom_error_t cdrom_osx_read_toc( gdrom_image_t disc );1.30 +static gdrom_error_t cdrom_osx_read_sector( gdrom_disc_t disc, uint32_t sector,1.31 + int mode, unsigned char *buf, uint32_t *length );1.33 struct gdrom_image_class cdrom_device_class = { "osx", NULL,1.34 - osx_image_is_valid, osx_open_device };1.35 + cdrom_osx_image_is_valid, cdrom_osx_open_device };1.37 -typedef struct osx_cdrom_disc {1.38 - struct gdrom_disc disc;1.39 -1.40 - io_object_t entry;1.41 - MMCDeviceInterface **mmc;1.42 - SCSITaskDeviceInterface **scsi;1.43 -} *osx_cdrom_disc_t;1.44 +#define OSX_DRIVE(disc) ( (osx_cdrom_drive_t)(((gdrom_image_t)disc)->private) )1.46 -/**1.47 - * CD-ROM drive visitor. Returns FALSE to continue iterating, TRUE if the desired CD-ROM1.48 - * has been found. In the latter case, the io_object is returned from find_cdrom_device1.49 - * (and not freed)1.50 - */1.51 -typedef gboolean (*find_cdrom_callback_t)( io_object_t object, char *vendor, char *product,1.52 - void *user_data );1.53 -1.54 -io_object_t find_cdrom_device( find_cdrom_callback_t callback, void *user_data )1.55 +static void cdrom_osx_destroy( gdrom_disc_t disc )1.56 {1.57 - mach_port_t master_port;1.58 - CFMutableDictionaryRef match;1.59 - io_iterator_t services;1.60 - io_object_t object;1.61 -1.62 - if( IOMasterPort( MACH_PORT_NULL, &master_port ) != KERN_SUCCESS ) {1.63 - return; // Failed to get the master port?1.64 - }1.65 -1.66 - match = IOServiceMatching("IODVDServices");1.67 - if( IOServiceGetMatchingServices(master_port, match, &services) != kIOReturnSuccess ) {1.68 - return;1.69 - }1.70 -1.71 - while( (object = IOIteratorNext(services)) != 0 ) {1.72 - CFMutableDictionaryRef props = 0;1.73 - if( IORegistryEntryCreateCFProperties(object, &props, kCFAllocatorDefault, kNilOptions) == KERN_SUCCESS ) {1.74 - CFDictionaryRef dict =1.75 - (CFDictionaryRef)CFDictionaryGetValue(props, CFSTR(kIOPropertyDeviceCharacteristicsKey));1.76 - if( dict ) {1.77 - /* The vendor name. */1.78 - char vendor[256] = "", product[256] = "";1.79 - CFTypeRef value = CFDictionaryGetValue(dict, CFSTR(kIOPropertyVendorNameKey));1.80 - if( value && CFGetTypeID(value) == CFStringGetTypeID() ) {1.81 - CFStringGetCString( (CFStringRef)value, vendor, sizeof(vendor),1.82 - kCFStringEncodingUTF8 );1.83 - }1.84 - value = CFDictionaryGetValue(dict, CFSTR(kIOPropertyProductNameKey));1.85 - if ( value && CFGetTypeID(value) == CFStringGetTypeID() ) {1.86 - CFStringGetCString( (CFStringRef)value, product, sizeof(product),1.87 - kCFStringEncodingUTF8 );1.88 - }1.89 - if( callback(object, vendor, product, user_data) ) {1.90 - CFRelease(props);1.91 - IOObjectRelease(services);1.92 - return object;1.93 - }1.94 - }1.95 - CFRelease(props);1.96 - }1.97 -1.98 - IOObjectRelease(object);1.99 - }1.100 - IOObjectRelease(services);1.101 + osx_cdrom_close_drive( OSX_DRIVE(disc) );1.102 + gdrom_image_destroy_no_close( disc );1.103 }1.105 -io_object_t get_cdrom_by_service_path( const gchar *path )1.106 +static void cdrom_osx_media_changed( osx_cdrom_drive_t drive, gboolean present,1.107 + void *user_data )1.108 {1.109 - mach_port_t master_port;1.110 - io_object_t result;1.111 -1.112 - if( IOMasterPort( MACH_PORT_NULL, &master_port ) != KERN_SUCCESS ) {1.113 - return MACH_PORT_NULL; // Failed to get the master port?1.114 + gdrom_image_t image = (gdrom_image_t)user_data;1.115 + if( present ) {1.116 + cdrom_osx_read_toc( image );1.117 + } else {1.118 + image->disc_type = IDE_DISC_NONE;1.119 + image->track_count = 0;1.120 }1.121 -1.122 - return IORegistryEntryFromPath( master_port, path );1.123 }1.125 -void cdrom_osx_destroy( gdrom_disc_t disc )1.126 +1.127 +static gdrom_disc_t cdrom_osx_new( const char *name, osx_cdrom_drive_t drive )1.128 {1.129 - osx_cdrom_disc_t cdrom = (osx_cdrom_disc_t)disc;1.130 + char tmp[strlen(name)+7];1.131 + sprintf( tmp, "dvd://%s", name );1.132 + gdrom_image_t image = (gdrom_image_t)gdrom_image_new(tmp, NULL);1.133 + image->private = drive;1.135 - if( cdrom->scsi != NULL ) {1.136 - (*cdrom->scsi)->Release(cdrom->scsi);1.137 - cdrom->scsi = NULL;1.138 - }1.139 - if( cdrom->mmc != NULL ) {1.140 - (*cdrom->mmc)->Release(cdrom->mmc);1.141 - cdrom->mmc = NULL;1.142 - }1.143 - if( cdrom->entry != MACH_PORT_NULL ) {1.144 - IOObjectRelease( cdrom->entry );1.145 - cdrom->entry = MACH_PORT_NULL;1.146 - }1.147 -1.148 - if( disc->name != NULL ) {1.149 - g_free( (gpointer)disc->name );1.150 - disc->name = NULL;1.151 - }1.152 - g_free(disc);1.153 + image->disc.read_sector = cdrom_osx_read_sector;1.154 + image->disc.close = cdrom_osx_destroy;1.155 + cdrom_osx_read_toc(image);1.156 + osx_cdrom_set_media_changed_callback( drive, cdrom_osx_media_changed, image );1.157 + return (gdrom_disc_t)image;1.158 }1.160 -gdrom_disc_t cdrom_osx_new( io_object_t obj )1.161 +gdrom_disc_t cdrom_open_device( const gchar *method, const gchar *path )1.162 {1.163 - osx_cdrom_disc_t cdrom = g_malloc0( sizeof(struct osx_cdrom_disc) );1.164 - gdrom_disc_t disc = &cdrom->disc;1.165 - IOCFPlugInInterface **pluginInterface = NULL;1.166 - HRESULT herr;1.167 - SInt32 score = 0;1.168 + gdrom_disc_t result = NULL;1.170 - cdrom->entry = obj;1.171 -1.172 - if( IOCreatePlugInInterfaceForService( obj, kIOMMCDeviceUserClientTypeID,1.173 - kIOCFPlugInInterfaceID, &pluginInterface, &score ) != KERN_SUCCESS ) {1.174 - ERROR( "Failed to create plugin interface" );1.175 - cdrom_osx_destroy(disc);1.176 + osx_cdrom_drive_t drive = osx_cdrom_open_drive(path);1.177 + if( drive == NULL ) {1.178 return NULL;1.179 + } else {1.180 + return cdrom_osx_new( path, drive );1.181 }1.182 -1.183 - herr = (*pluginInterface)->QueryInterface( pluginInterface,1.184 - CFUUIDGetUUIDBytes( kIOMMCDeviceInterfaceID ), (LPVOID *)&cdrom->mmc );1.185 - (*pluginInterface)->Release(pluginInterface);1.186 - pluginInterface = NULL;1.187 - if( herr != S_OK ) {1.188 - ERROR( "Failed to create MMC interface" );1.189 - cdrom_osx_destroy(disc);1.190 - return NULL;1.191 - }1.192 -1.193 - cdrom->scsi = (*cdrom->mmc)->GetSCSITaskDeviceInterface( cdrom->mmc );1.194 - if( cdrom->scsi == NULL ) {1.195 - ERROR( "Failed to create SCSI interface" );1.196 - cdrom_osx_destroy(disc);1.197 - return NULL;1.198 - }1.199 -1.200 - char name[sizeof(io_string_t) + 6] = "dvd://";1.201 - IORegistryEntryGetPath( cdrom->entry, kIOServicePlane, name+6 );1.202 - disc->name = g_strdup(name);1.203 -1.204 - disc->close = cdrom_osx_destroy;1.205 - return disc;1.206 }1.208 -gboolean cdrom_enum_callback( io_object_t object, char *vendor, char *product, void *ptr )1.209 +1.210 +1.211 +static gboolean cdrom_enum_callback( io_object_t object, char *vendor, char *product, char *iopath, void *ptr )1.212 {1.213 GList **list = (GList **)ptr;1.214 - char tmp1[sizeof(io_string_t) + 6] = "dvd://";1.215 + char tmp1[sizeof(io_string_t) + 6];1.216 char tmp2[512];1.217 - IORegistryEntryGetPath( object, kIOServicePlane, tmp1+6 );1.218 + snprintf( tmp1, sizeof(tmp1), "dvd://%s", iopath );1.219 snprintf( tmp2, sizeof(tmp2), "%s %s", vendor, product );1.220 *list = g_list_append( *list, gdrom_device_new( tmp1, tmp2 ) );1.221 return FALSE;1.222 @@ -185,34 +105,102 @@1.223 GList *cdrom_get_native_devices(void)1.224 {1.225 GList *list = NULL;1.226 - find_cdrom_device(cdrom_enum_callback, &list);1.227 + find_cdrom_drive(cdrom_enum_callback, &list);1.228 +1.229 + osx_register_iokit_notifications();1.230 return list;1.231 }1.233 -gdrom_disc_t cdrom_open_device( const gchar *method, const gchar *path )1.234 -{1.235 - io_object_t obj;1.236 - gdrom_disc_t result = NULL;1.237 -1.238 - if( strncasecmp( path, "IOService:", 10 ) == 0 ) {1.239 - obj = get_cdrom_by_service_path( path );1.240 - }1.241 -1.242 - if( obj == MACH_PORT_NULL ) {1.243 - return NULL;1.244 - } else {1.245 - return cdrom_osx_new( obj );1.246 - }1.247 -}1.250 -1.251 -static gboolean osx_image_is_valid( FILE *f )1.252 +static gboolean cdrom_osx_image_is_valid( FILE *f )1.253 {1.254 return FALSE;1.255 }1.257 -static gdrom_disc_t osx_open_device( const gchar *filename, FILE *f )1.258 +static gdrom_disc_t cdrom_osx_open_device( const gchar *filename, FILE *f )1.259 {1.260 return NULL;1.261 }1.262 +1.263 +static gdrom_error_t cdrom_osx_read_toc( gdrom_image_t image )1.264 +{1.265 + osx_cdrom_drive_t drive = OSX_DRIVE(image);1.266 +1.267 + int fh = osx_cdrom_get_media_handle(drive);1.268 + if( fh == -1 ) {1.269 + image->disc_type = IDE_DISC_NONE;1.270 + image->track_count = 0;1.271 + return -1;1.272 + } else {1.273 + unsigned char buf[MAXTOCSIZE];1.274 + dk_cd_read_toc_t readtoc;1.275 + memset( &readtoc, 0, sizeof(readtoc) );1.276 + readtoc.format = 2;1.277 + readtoc.formatAsTime = 0;1.278 + readtoc.address.session = 0;1.279 + readtoc.bufferLength = sizeof(buf);1.280 + readtoc.buffer = buf;1.281 +1.282 + if( ioctl(fh, DKIOCCDREADTOC, &readtoc ) == -1 ) {1.283 + ERROR( "Failed to read TOC: %s", strerror(errno) );1.284 + image->disc_type = IDE_DISC_NONE;1.285 + image->track_count = 0;1.286 + return -1;1.287 + } else {1.288 + mmc_parse_toc2( image, buf );1.289 + }1.290 + }1.291 + return 0;1.292 +}1.293 +1.294 +static gdrom_error_t cdrom_osx_read_sector( gdrom_disc_t disc, uint32_t sector,1.295 + int mode, unsigned char *buf, uint32_t *length )1.296 +{1.297 + osx_cdrom_drive_t drive = OSX_DRIVE(disc);1.298 + int fh = osx_cdrom_get_media_handle(drive);1.299 + if( fh == -1 ) {1.300 + return PKT_ERR_NODISC;1.301 + } else {1.302 + dk_cd_read_t readcd;1.303 +1.304 + memset( &readcd, 0, sizeof(readcd) );1.305 + // This is complicated by needing to know the exact read size. Gah.1.306 + if( READ_CD_RAW(mode) ) {1.307 + *length = 2352;1.308 + readcd.sectorArea = 0xF8;1.309 + } else {1.310 + // This is incomplete...1.311 + if( READ_CD_DATA(mode) ) {1.312 + readcd.sectorArea = kCDSectorAreaUser;1.313 + switch( READ_CD_MODE(mode) ) {1.314 + case READ_CD_MODE_CDDA:1.315 + *length = 2352;1.316 + break;1.317 + case READ_CD_MODE_1:1.318 + case READ_CD_MODE_2_FORM_1:1.319 + *length = 2048;1.320 + break;1.321 + case READ_CD_MODE_2:1.322 + *length = 2336;1.323 + break;1.324 + case READ_CD_MODE_2_FORM_2:1.325 + *length = 2324;1.326 + break;1.327 + }1.328 + }1.329 + }1.330 +1.331 + readcd.offset = *length * (sector - 150);1.332 + readcd.sectorType = READ_CD_MODE(mode)>>1;1.333 + readcd.bufferLength = *length;1.334 + readcd.buffer = buf;1.335 + if( ioctl( fh, DKIOCCDREAD, &readcd ) == -1 ) {1.336 + ERROR( "Failed to read CD: %s", strerror(errno) );1.337 + return -1;1.338 + } else {1.339 + return 0;1.340 + }1.341 + }1.342 +}1.343 +
.