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