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@720 | 29 | #include "drivers/osx_iokit.h"
|
nkeynes@1097 | 30 | #include "drivers/cdrom/cdimpl.h"
|
nkeynes@1097 | 31 | #include "drivers/cdrom/drive.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@1097 | 37 | static cdrom_disc_t cdrom_osx_open_file( FILE *f, const gchar *filename, ERROR *err );
|
nkeynes@1097 | 38 | static gboolean cdrom_osx_read_toc( cdrom_disc_t disc, ERROR *err );
|
nkeynes@1097 | 39 | static cdrom_error_t cdrom_osx_read_sectors( sector_source_t disc, cdrom_lba_t sector, cdrom_count_t count,
|
nkeynes@1097 | 40 | cdrom_read_mode_t mode, unsigned char *buf, size_t *length );
|
nkeynes@709 | 41 |
|
nkeynes@1097 | 42 | /* Note: We don't support opening OS X devices by filename, so no disc factory */
|
nkeynes@709 | 43 |
|
nkeynes@1097 | 44 | #define OSX_DRIVE(disc) ( (osx_cdrom_drive_t)(((cdrom_disc_t)disc)->impl_data) )
|
nkeynes@709 | 45 |
|
nkeynes@1097 | 46 | static void cdrom_osx_destroy( sector_source_t disc )
|
nkeynes@709 | 47 | {
|
nkeynes@1097 | 48 | osx_cdrom_close_drive( OSX_DRIVE(disc) );
|
nkeynes@1097 | 49 | default_cdrom_disc_destroy( disc );
|
nkeynes@709 | 50 | }
|
nkeynes@709 | 51 |
|
nkeynes@720 | 52 | static void cdrom_osx_media_changed( osx_cdrom_drive_t drive, gboolean present,
|
nkeynes@720 | 53 | void *user_data )
|
nkeynes@709 | 54 | {
|
nkeynes@1097 | 55 | cdrom_disc_t disc = (cdrom_disc_t)user_data;
|
nkeynes@720 | 56 | if( present ) {
|
nkeynes@1097 | 57 | cdrom_osx_read_toc( disc, NULL );
|
nkeynes@720 | 58 | } else {
|
nkeynes@1097 | 59 | disc->disc_type = CDROM_DISC_NONE;
|
nkeynes@1023 | 60 | disc->track_count = 0;
|
nkeynes@709 | 61 | }
|
nkeynes@709 | 62 | }
|
nkeynes@709 | 63 |
|
nkeynes@720 | 64 |
|
nkeynes@1097 | 65 | static cdrom_disc_t cdrom_osx_new( const char *name, osx_cdrom_drive_t drive, ERROR *err )
|
nkeynes@709 | 66 | {
|
nkeynes@1097 | 67 | cdrom_disc_t disc = cdrom_disc_new(name, err);
|
nkeynes@1023 | 68 | disc->impl_data = drive;
|
nkeynes@736 | 69 |
|
nkeynes@1097 | 70 | disc->source.read_sectors = cdrom_osx_read_sectors;
|
nkeynes@1097 | 71 | disc->source.destroy = cdrom_osx_destroy;
|
nkeynes@1097 | 72 | disc->read_toc = cdrom_osx_read_toc;
|
nkeynes@1097 | 73 | cdrom_disc_read_toc(disc, err);
|
nkeynes@1023 | 74 | osx_cdrom_set_media_changed_callback( drive, cdrom_osx_media_changed, disc );
|
nkeynes@1097 | 75 | return (cdrom_disc_t)disc;
|
nkeynes@709 | 76 | }
|
nkeynes@709 | 77 |
|
nkeynes@1097 | 78 | static cdrom_disc_t cdrom_osx_open( cdrom_drive_t drive, ERROR *err )
|
nkeynes@709 | 79 | {
|
nkeynes@1097 | 80 | cdrom_disc_t result = NULL;
|
nkeynes@736 | 81 |
|
nkeynes@1097 | 82 | osx_cdrom_drive_t osx_drive = osx_cdrom_open_drive(drive->name);
|
nkeynes@1097 | 83 | if( osx_drive == NULL ) {
|
nkeynes@1109 | 84 | SET_ERROR( err, LX_ERR_FILE_NOOPEN, "Unable to open CDROM drive" );
|
nkeynes@709 | 85 | return NULL;
|
nkeynes@720 | 86 | } else {
|
nkeynes@1097 | 87 | return cdrom_osx_new( drive->name, osx_drive, err );
|
nkeynes@709 | 88 | }
|
nkeynes@709 | 89 | }
|
nkeynes@709 | 90 |
|
nkeynes@720 | 91 |
|
nkeynes@720 | 92 |
|
nkeynes@720 | 93 | static gboolean cdrom_enum_callback( io_object_t object, char *vendor, char *product, char *iopath, void *ptr )
|
nkeynes@709 | 94 | {
|
nkeynes@720 | 95 | char tmp1[sizeof(io_string_t) + 6];
|
nkeynes@709 | 96 | char tmp2[512];
|
nkeynes@720 | 97 | snprintf( tmp1, sizeof(tmp1), "dvd://%s", iopath );
|
nkeynes@709 | 98 | snprintf( tmp2, sizeof(tmp2), "%s %s", vendor, product );
|
nkeynes@1097 | 99 | cdrom_drive_add( iopath, tmp2, cdrom_osx_open );
|
nkeynes@709 | 100 | return FALSE;
|
nkeynes@709 | 101 | }
|
nkeynes@709 | 102 |
|
nkeynes@1097 | 103 | void cdrom_drive_scan(void)
|
nkeynes@709 | 104 | {
|
nkeynes@1097 | 105 | find_cdrom_drive(cdrom_enum_callback, NULL);
|
nkeynes@720 | 106 | osx_register_iokit_notifications();
|
nkeynes@709 | 107 | }
|
nkeynes@709 | 108 |
|
nkeynes@720 | 109 | static gboolean cdrom_osx_image_is_valid( FILE *f )
|
nkeynes@709 | 110 | {
|
nkeynes@709 | 111 | return FALSE;
|
nkeynes@709 | 112 | }
|
nkeynes@709 | 113 |
|
nkeynes@1097 | 114 | static cdrom_disc_t cdrom_osx_open_file( FILE *f, const gchar *filename, ERROR *err )
|
nkeynes@709 | 115 | {
|
nkeynes@1097 | 116 | return NULL; /* Not supported */
|
nkeynes@709 | 117 | }
|
nkeynes@720 | 118 |
|
nkeynes@1097 | 119 | static gboolean cdrom_osx_read_toc( cdrom_disc_t disc, ERROR *err )
|
nkeynes@720 | 120 | {
|
nkeynes@1023 | 121 | osx_cdrom_drive_t drive = OSX_DRIVE(disc);
|
nkeynes@736 | 122 |
|
nkeynes@720 | 123 | int fh = osx_cdrom_get_media_handle(drive);
|
nkeynes@720 | 124 | if( fh == -1 ) {
|
nkeynes@1097 | 125 | disc->disc_type = CDROM_DISC_NONE;
|
nkeynes@1023 | 126 | disc->track_count = 0;
|
nkeynes@1097 | 127 | return FALSE;
|
nkeynes@720 | 128 | } else {
|
nkeynes@720 | 129 | unsigned char buf[MAXTOCSIZE];
|
nkeynes@720 | 130 | dk_cd_read_toc_t readtoc;
|
nkeynes@720 | 131 | memset( &readtoc, 0, sizeof(readtoc) );
|
nkeynes@720 | 132 | readtoc.format = 2;
|
nkeynes@720 | 133 | readtoc.formatAsTime = 0;
|
nkeynes@720 | 134 | readtoc.address.session = 0;
|
nkeynes@720 | 135 | readtoc.bufferLength = sizeof(buf);
|
nkeynes@720 | 136 | readtoc.buffer = buf;
|
nkeynes@736 | 137 |
|
nkeynes@720 | 138 | if( ioctl(fh, DKIOCCDREADTOC, &readtoc ) == -1 ) {
|
nkeynes@1023 | 139 | WARN( "Failed to read TOC (%s)", strerror(errno) );
|
nkeynes@1097 | 140 | disc->disc_type = CDROM_DISC_NONE;
|
nkeynes@1023 | 141 | disc->track_count = 0;
|
nkeynes@1097 | 142 | return FALSE;
|
nkeynes@720 | 143 | } else {
|
nkeynes@1023 | 144 | mmc_parse_toc2( disc, buf );
|
nkeynes@720 | 145 | }
|
nkeynes@720 | 146 | }
|
nkeynes@1097 | 147 | return TRUE;
|
nkeynes@720 | 148 | }
|
nkeynes@720 | 149 |
|
nkeynes@1097 | 150 | static cdrom_error_t cdrom_osx_read_sectors( sector_source_t source, cdrom_lba_t lba, cdrom_count_t count,
|
nkeynes@1097 | 151 | cdrom_read_mode_t mode, unsigned char *buf, size_t *length )
|
nkeynes@720 | 152 | {
|
nkeynes@1097 | 153 | cdrom_disc_t disc = (cdrom_disc_t)source;
|
nkeynes@786 | 154 | int sector_size = 2352;
|
nkeynes@1097 | 155 | char data[CDROM_MAX_SECTOR_SIZE];
|
nkeynes@720 | 156 | osx_cdrom_drive_t drive = OSX_DRIVE(disc);
|
nkeynes@782 | 157 |
|
nkeynes@720 | 158 | int fh = osx_cdrom_get_media_handle(drive);
|
nkeynes@720 | 159 | if( fh == -1 ) {
|
nkeynes@1097 | 160 | return CDROM_ERROR_NODISC;
|
nkeynes@720 | 161 | } else {
|
nkeynes@720 | 162 | dk_cd_read_t readcd;
|
nkeynes@782 | 163 | memset( &readcd, 0, sizeof(readcd) );
|
nkeynes@782 | 164 | readcd.buffer = buf;
|
nkeynes@1168 | 165 | readcd.sectorType = CDROM_READ_TYPE(mode) >> 2;
|
nkeynes@720 | 166 |
|
nkeynes@1097 | 167 | cdrom_track_t track = cdrom_disc_get_track_by_lba(disc,lba);
|
nkeynes@1097 | 168 | if( track == NULL ) {
|
nkeynes@1097 | 169 | return CDROM_ERROR_BADREAD;
|
nkeynes@1097 | 170 | }
|
nkeynes@1097 | 171 |
|
nkeynes@1097 | 172 | /* This is complicated by needing to know the exact read size. Gah.
|
nkeynes@1097 | 173 | * For now, anything other than a data-only read of known size is
|
nkeynes@1097 | 174 | * executed by a raw read + extraction.
|
nkeynes@1097 | 175 | */
|
nkeynes@1097 | 176 | if( (CDROM_READ_FIELDS(mode) == CDROM_READ_DATA && CDROM_READ_TYPE(mode) != CDROM_READ_ANY) ||
|
nkeynes@1097 | 177 | ((track->flags & TRACK_FLAG_DATA) == 0 && CDROM_READ_FIELDS(mode) != CDROM_READ_NONE) ) {
|
nkeynes@1097 | 178 | switch( CDROM_READ_TYPE(mode) ) {
|
nkeynes@1097 | 179 | case CDROM_READ_ANY:
|
nkeynes@1097 | 180 | case CDROM_READ_CDDA:
|
nkeynes@1097 | 181 | sector_size = 2352;
|
nkeynes@1097 | 182 | break;
|
nkeynes@1097 | 183 | case CDROM_READ_MODE1:
|
nkeynes@1097 | 184 | case CDROM_READ_MODE2_FORM1:
|
nkeynes@1097 | 185 | sector_size = 2048;
|
nkeynes@1097 | 186 | break;
|
nkeynes@1097 | 187 | case CDROM_READ_MODE2:
|
nkeynes@1097 | 188 | sector_size = 2336;
|
nkeynes@1097 | 189 | break;
|
nkeynes@1097 | 190 | case CDROM_READ_MODE2_FORM2:
|
nkeynes@1097 | 191 | sector_size = 2324;
|
nkeynes@1097 | 192 | break;
|
nkeynes@1097 | 193 | }
|
nkeynes@1097 | 194 | readcd.sectorArea = kCDSectorAreaUser;
|
nkeynes@1097 | 195 | readcd.offset = sector_size * lba;
|
nkeynes@1097 | 196 | readcd.bufferLength = sector_size * count;
|
nkeynes@1097 | 197 | if( ioctl( fh, DKIOCCDREAD, &readcd ) == -1 ) {
|
nkeynes@1097 | 198 | return CDROM_ERROR_BADREAD;
|
nkeynes@1097 | 199 | }
|
nkeynes@1097 | 200 | *length = sector_size * count;
|
nkeynes@1097 | 201 | } else {
|
nkeynes@782 | 202 | /* Sector could be anything - need to do a raw read and then parse
|
nkeynes@782 | 203 | * the requested data out ourselves
|
nkeynes@782 | 204 | */
|
nkeynes@1097 | 205 | sector_size = 2352;
|
nkeynes@1097 | 206 | size_t tmplen, len = 0;
|
nkeynes@782 | 207 |
|
nkeynes@1097 | 208 | readcd.offset = sector_size * lba;
|
nkeynes@1097 | 209 | readcd.sectorArea = 0xf8;
|
nkeynes@1097 | 210 | readcd.buffer = data;
|
nkeynes@1097 | 211 | readcd.bufferLength = sector_size;
|
nkeynes@1097 | 212 | while( count > 0 ) {
|
nkeynes@1097 | 213 | if( ioctl( fh, DKIOCCDREAD, &readcd ) == -1 ) {
|
nkeynes@1097 | 214 | return CDROM_ERROR_BADREAD;
|
nkeynes@1097 | 215 | }
|
nkeynes@1097 | 216 | cdrom_error_t err = sector_extract_from_raw( data, mode, &buf[len], &tmplen );
|
nkeynes@1097 | 217 | if( err != CDROM_ERROR_OK )
|
nkeynes@1097 | 218 | return err;
|
nkeynes@1097 | 219 | len += tmplen;
|
nkeynes@1097 | 220 | readcd.offset += sector_size;
|
nkeynes@782 | 221 | }
|
nkeynes@1097 | 222 | *length = len;
|
nkeynes@720 | 223 | }
|
nkeynes@736 | 224 |
|
nkeynes@1097 | 225 | return CDROM_ERROR_OK;
|
nkeynes@720 | 226 | }
|
nkeynes@720 | 227 | }
|
nkeynes@720 | 228 |
|