Search
lxdream.org :: lxdream/src/drivers/cd_osx.c :: diff
lxdream 0.9.1
released Jun 29
Download Now
filename src/drivers/cd_osx.c
changeset 720:b5594d1ac80a
prev709:18c39a8e504c
next736: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 +0000
1.2 +++ b/src/drivers/cd_osx.c Sat Jul 05 11:57:36 2008 +0000
1.3 @@ -17,166 +17,86 @@
1.4 */
1.5
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.21
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.32
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.36
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.45
1.46 -/**
1.47 - * CD-ROM drive visitor. Returns FALSE to continue iterating, TRUE if the desired CD-ROM
1.48 - * has been found. In the latter case, the io_object is returned from find_cdrom_device
1.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.104
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.124
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.134
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.159
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.169
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.207
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.232
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.248
1.249
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.256
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 +
.