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 1168:66e5113d4155
prev1109:700c5ab26a63
next1298:d0eb2307b847
author nkeynes
date Sat Jan 26 14:00:48 2013 +1000 (11 years ago)
permissions -rw-r--r--
last change Change glib includes to #include <glib.h> rather than the individual
headers, as recent glib versions are breaking on this
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@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
.