Search
lxdream.org :: lxdream/src/drivers/cd_osx.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/drivers/cd_osx.c
changeset 782:1af8b5ce627c
prev739:46fa527d9fef
next786:8f6ece92500e
author nkeynes
date Tue Jul 29 06:35:28 2008 +0000 (14 years ago)
permissions -rw-r--r--
last change Workaround OS X's inability to handle CD reads of unknown size (ie where the read
request failed to specify an expected sector type) - read raw sectors and parse it
out by hand.
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@709
    29
#include "gdrom/gddriver.h"
nkeynes@720
    30
#include "gdrom/packet.h"
nkeynes@720
    31
#include "drivers/osx_iokit.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@720
    37
static gdrom_disc_t cdrom_osx_open_device( const gchar *filename, FILE *f );
nkeynes@720
    38
static gdrom_error_t cdrom_osx_read_toc( gdrom_image_t disc );
nkeynes@720
    39
static gdrom_error_t cdrom_osx_read_sector( gdrom_disc_t disc, uint32_t sector,
nkeynes@736
    40
                                            int mode, unsigned char *buf, uint32_t *length );
nkeynes@709
    41
nkeynes@709
    42
struct gdrom_image_class cdrom_device_class = { "osx", NULL,
nkeynes@736
    43
        cdrom_osx_image_is_valid, cdrom_osx_open_device };
nkeynes@709
    44
nkeynes@720
    45
#define OSX_DRIVE(disc) ( (osx_cdrom_drive_t)(((gdrom_image_t)disc)->private) )
nkeynes@709
    46
nkeynes@720
    47
static void cdrom_osx_destroy( gdrom_disc_t disc )
nkeynes@709
    48
{
nkeynes@720
    49
    osx_cdrom_close_drive( OSX_DRIVE(disc) );
nkeynes@720
    50
    gdrom_image_destroy_no_close( disc );
nkeynes@709
    51
}
nkeynes@709
    52
nkeynes@720
    53
static void cdrom_osx_media_changed( osx_cdrom_drive_t drive, gboolean present,
nkeynes@720
    54
                                     void *user_data )
nkeynes@709
    55
{
nkeynes@720
    56
    gdrom_image_t image = (gdrom_image_t)user_data;
nkeynes@720
    57
    if( present ) {
nkeynes@720
    58
        cdrom_osx_read_toc( image );
nkeynes@720
    59
    } else {
nkeynes@720
    60
        image->disc_type = IDE_DISC_NONE;
nkeynes@720
    61
        image->track_count = 0;        
nkeynes@709
    62
    }
nkeynes@709
    63
}
nkeynes@709
    64
nkeynes@720
    65
nkeynes@720
    66
static gdrom_disc_t cdrom_osx_new( const char *name, osx_cdrom_drive_t drive )
nkeynes@709
    67
{
nkeynes@720
    68
    char tmp[strlen(name)+7];
nkeynes@720
    69
    sprintf( tmp, "dvd://%s", name );
nkeynes@720
    70
    gdrom_image_t image = (gdrom_image_t)gdrom_image_new(tmp, NULL);
nkeynes@720
    71
    image->private = drive;
nkeynes@736
    72
nkeynes@720
    73
    image->disc.read_sector = cdrom_osx_read_sector;
nkeynes@720
    74
    image->disc.close = cdrom_osx_destroy;
nkeynes@720
    75
    cdrom_osx_read_toc(image);
nkeynes@720
    76
    osx_cdrom_set_media_changed_callback( drive, cdrom_osx_media_changed, image );
nkeynes@720
    77
    return (gdrom_disc_t)image;
nkeynes@709
    78
}
nkeynes@709
    79
nkeynes@720
    80
gdrom_disc_t cdrom_open_device( const gchar *method, const gchar *path )
nkeynes@709
    81
{
nkeynes@720
    82
    gdrom_disc_t result = NULL;
nkeynes@736
    83
nkeynes@720
    84
    osx_cdrom_drive_t drive = osx_cdrom_open_drive(path);
nkeynes@720
    85
    if( drive == NULL ) {
nkeynes@709
    86
        return NULL;
nkeynes@720
    87
    } else {
nkeynes@720
    88
        return cdrom_osx_new( path, drive );
nkeynes@709
    89
    }
nkeynes@709
    90
}
nkeynes@709
    91
nkeynes@720
    92
nkeynes@720
    93
nkeynes@720
    94
static gboolean cdrom_enum_callback( io_object_t object, char *vendor, char *product, char *iopath, void *ptr )
nkeynes@709
    95
{
nkeynes@709
    96
    GList **list = (GList **)ptr;
nkeynes@720
    97
    char tmp1[sizeof(io_string_t) + 6];
nkeynes@709
    98
    char tmp2[512];
nkeynes@720
    99
    snprintf( tmp1, sizeof(tmp1), "dvd://%s", iopath );
nkeynes@709
   100
    snprintf( tmp2, sizeof(tmp2), "%s %s", vendor, product );
nkeynes@709
   101
    *list = g_list_append( *list, gdrom_device_new( tmp1, tmp2 ) );
nkeynes@709
   102
    return FALSE;
nkeynes@709
   103
}
nkeynes@709
   104
nkeynes@709
   105
GList *cdrom_get_native_devices(void)
nkeynes@709
   106
{
nkeynes@709
   107
    GList *list = NULL;
nkeynes@720
   108
    find_cdrom_drive(cdrom_enum_callback, &list);
nkeynes@736
   109
nkeynes@720
   110
    osx_register_iokit_notifications();
nkeynes@709
   111
    return list;
nkeynes@709
   112
}
nkeynes@709
   113
nkeynes@709
   114
nkeynes@709
   115
nkeynes@720
   116
static gboolean cdrom_osx_image_is_valid( FILE *f )
nkeynes@709
   117
{
nkeynes@709
   118
    return FALSE;
nkeynes@709
   119
}
nkeynes@709
   120
nkeynes@720
   121
static gdrom_disc_t cdrom_osx_open_device( const gchar *filename, FILE *f )
nkeynes@709
   122
{
nkeynes@709
   123
    return NULL;
nkeynes@709
   124
}
nkeynes@720
   125
nkeynes@720
   126
static gdrom_error_t cdrom_osx_read_toc( gdrom_image_t image )
nkeynes@720
   127
{
nkeynes@720
   128
    osx_cdrom_drive_t drive = OSX_DRIVE(image);
nkeynes@736
   129
nkeynes@720
   130
    int fh = osx_cdrom_get_media_handle(drive);
nkeynes@720
   131
    if( fh == -1 ) {
nkeynes@720
   132
        image->disc_type = IDE_DISC_NONE;
nkeynes@720
   133
        image->track_count = 0;
nkeynes@720
   134
        return -1;
nkeynes@720
   135
    } else {
nkeynes@720
   136
        unsigned char buf[MAXTOCSIZE];
nkeynes@720
   137
        dk_cd_read_toc_t readtoc;
nkeynes@720
   138
        memset( &readtoc, 0, sizeof(readtoc) );
nkeynes@720
   139
        readtoc.format = 2;
nkeynes@720
   140
        readtoc.formatAsTime = 0;
nkeynes@720
   141
        readtoc.address.session = 0;
nkeynes@720
   142
        readtoc.bufferLength = sizeof(buf);
nkeynes@720
   143
        readtoc.buffer = buf;
nkeynes@736
   144
nkeynes@720
   145
        if( ioctl(fh, DKIOCCDREADTOC, &readtoc ) == -1 ) {
nkeynes@720
   146
            image->disc_type = IDE_DISC_NONE;
nkeynes@720
   147
            image->track_count = 0;
nkeynes@720
   148
            return -1;
nkeynes@720
   149
        } else {
nkeynes@720
   150
            mmc_parse_toc2( image, buf );
nkeynes@720
   151
        }
nkeynes@720
   152
    }
nkeynes@720
   153
    return 0;
nkeynes@720
   154
}
nkeynes@720
   155
nkeynes@782
   156
static gdrom_error_t cdrom_osx_read_sector( gdrom_disc_t disc, uint32_t lba,
nkeynes@736
   157
                                            int mode, unsigned char *buf, uint32_t *length ) 
nkeynes@720
   158
{
nkeynes@782
   159
    gdrom_image_t image = (gdrom_image_t)disc;
nkeynes@782
   160
    int real_lba = lba - 150;
nkeynes@782
   161
    int sector_size;
nkeynes@782
   162
    int direct_read = 1;
nkeynes@782
   163
    char data[MAX_SECTOR_SIZE];
nkeynes@720
   164
    osx_cdrom_drive_t drive = OSX_DRIVE(disc);
nkeynes@782
   165
    
nkeynes@720
   166
    int fh = osx_cdrom_get_media_handle(drive);
nkeynes@720
   167
    if( fh == -1 ) {
nkeynes@720
   168
        return PKT_ERR_NODISC;
nkeynes@720
   169
    } else {
nkeynes@720
   170
        dk_cd_read_t readcd;
nkeynes@782
   171
        memset( &readcd, 0, sizeof(readcd) );
nkeynes@782
   172
        readcd.buffer = buf;
nkeynes@720
   173
nkeynes@720
   174
        // This is complicated by needing to know the exact read size. Gah.
nkeynes@720
   175
        if( READ_CD_RAW(mode) ) {
nkeynes@782
   176
            sector_size = 2352;
nkeynes@720
   177
            readcd.sectorArea = 0xF8; 
nkeynes@782
   178
        } else if ( READ_CD_MODE(mode) == READ_CD_MODE_ANY ) {
nkeynes@782
   179
            /* Sector could be anything - need to do a raw read and then parse
nkeynes@782
   180
             * the requested data out ourselves
nkeynes@782
   181
             */
nkeynes@782
   182
            int track_no = gdrom_image_get_track_by_lba( image, lba );
nkeynes@782
   183
            struct gdrom_track *track = &image->track[track_no-1];
nkeynes@782
   184
nkeynes@782
   185
            sector_size = 2352;
nkeynes@782
   186
            if( track->mode == GDROM_CDDA ) {
nkeynes@782
   187
                readcd.sectorArea = kCDSectorAreaUser;
nkeynes@782
   188
            } else {
nkeynes@782
   189
                readcd.sectorArea = 0xF8;
nkeynes@782
   190
                readcd.buffer = data;
nkeynes@782
   191
                direct_read = 0;
nkeynes@782
   192
            }
nkeynes@720
   193
        } else {
nkeynes@720
   194
            // This is incomplete...
nkeynes@720
   195
            if( READ_CD_DATA(mode) ) {
nkeynes@720
   196
                readcd.sectorArea = kCDSectorAreaUser;
nkeynes@720
   197
                switch( READ_CD_MODE(mode) ) {
nkeynes@720
   198
                case READ_CD_MODE_CDDA:
nkeynes@782
   199
                    sector_size = 2352;
nkeynes@720
   200
                    break;
nkeynes@720
   201
                case READ_CD_MODE_1:
nkeynes@720
   202
                case READ_CD_MODE_2_FORM_1:
nkeynes@782
   203
                    sector_size = 2048;
nkeynes@720
   204
                    break;
nkeynes@720
   205
                case READ_CD_MODE_2:
nkeynes@782
   206
                    sector_size = 2336;
nkeynes@720
   207
                    break;
nkeynes@720
   208
                case READ_CD_MODE_2_FORM_2:
nkeynes@782
   209
                    sector_size = 2324;
nkeynes@720
   210
                    break;
nkeynes@720
   211
                }
nkeynes@720
   212
            }
nkeynes@720
   213
        }
nkeynes@736
   214
nkeynes@782
   215
        readcd.offset = sector_size * real_lba;
nkeynes@720
   216
        readcd.sectorType = READ_CD_MODE(mode)>>1;
nkeynes@782
   217
        readcd.bufferLength = sector_size;
nkeynes@720
   218
        if( ioctl( fh, DKIOCCDREAD, &readcd ) == -1 ) {
nkeynes@720
   219
            return -1;
nkeynes@782
   220
        }
nkeynes@782
   221
        
nkeynes@782
   222
        if( direct_read ) {
nkeynes@782
   223
            *length = sector_size;
nkeynes@720
   224
        } else {
nkeynes@782
   225
            gdrom_extract_raw_data_sector( data, mode, buf, length );
nkeynes@720
   226
        }
nkeynes@782
   227
        return 0;
nkeynes@720
   228
    }
nkeynes@720
   229
}
nkeynes@720
   230
.