Search
lxdream.org :: lxdream/src/drivers/cdrom/cd_osx.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/drivers/cdrom/cd_osx.c
changeset 1298:d0eb2307b847
prev1168:66e5113d4155
author nkeynes
date Fri May 29 18:47:05 2015 +1000 (8 years ago)
permissions -rw-r--r--
last change Fix test case
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@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
.