You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
690 lines
23 KiB
690 lines
23 KiB
/*****************************************************************************
|
|
* DVDioctl.cpp: Linux-like DVD driver for Darwin and MacOS X
|
|
*****************************************************************************
|
|
* Copyright (C) 1998-2000 Apple Computer, Inc. All rights reserved.
|
|
* Copyright (C) 2001 VideoLAN
|
|
* $Id: DVDioctl.cpp,v 1.7 2001/06/25 11:34:08 sam Exp $
|
|
*
|
|
* Authors: Samuel Hocevar <sam@zoy.org>
|
|
* Eugenio Jarosiewicz <ej0@cise.ufl.edu>
|
|
*
|
|
* The contents of this file constitute Original Code as defined in and
|
|
* are subject to the Apple Public Source License Version 1.1 (the
|
|
* "License"). You may not use this file except in compliance with the
|
|
* License. Please obtain a copy of the License at
|
|
* http://www.apple.com/publicsource and read it before using this file.
|
|
*
|
|
* This Original Code and all software distributed under the License are
|
|
* distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
|
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
|
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
|
|
* License for the specific language governing rights and limitations
|
|
* under the License.
|
|
*****************************************************************************/
|
|
|
|
/*****************************************************************************
|
|
* TODO:
|
|
* - add a timeout to waitForService() so that we don't wait forever
|
|
* - find a way to prevent user from ejecting DVD using the GUI while
|
|
* it is still in use
|
|
*****************************************************************************/
|
|
|
|
/*****************************************************************************
|
|
* Preamble
|
|
*****************************************************************************/
|
|
extern "C"
|
|
{
|
|
#include <sys/param.h>
|
|
#include <sys/conf.h>
|
|
#include <sys/syslog.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/ioccom.h>
|
|
#include <sys/fcntl.h>
|
|
#include <sys/buf.h>
|
|
#include <sys/uio.h>
|
|
#include <miscfs/devfs/devfs.h>
|
|
|
|
#include <mach/mach_types.h>
|
|
}
|
|
|
|
#include <IOKit/IOLib.h>
|
|
#include <IOKit/IOService.h>
|
|
#include <IOKit/storage/IOMedia.h>
|
|
#include <IOKit/storage/IODVDMedia.h>
|
|
#include <IOKit/storage/IODVDBlockStorageDriver.h>
|
|
|
|
#undef CONTROL //some include above #defines this and breaks the next include...grr.
|
|
#include <IOKit/scsi-commands/IOSCSIMultimediaCommandsDevice.h>
|
|
#include <IOKit/scsi-commands/IODVDServices.h>
|
|
|
|
#include "DVDioctl.h"
|
|
|
|
/*****************************************************************************
|
|
* Driver class
|
|
*****************************************************************************/
|
|
class DVDioctl : public IOService
|
|
{
|
|
OSDeclareDefaultStructors( DVDioctl )
|
|
|
|
public:
|
|
|
|
virtual bool init ( OSDictionary *dictionary = 0 );
|
|
virtual IOService *probe ( IOService *provider, SInt32 *score );
|
|
virtual bool start ( IOService *provider );
|
|
virtual void stop ( IOService *provider );
|
|
virtual void free ( void );
|
|
};
|
|
|
|
#define super IOService
|
|
OSDefineMetaClassAndStructors( DVDioctl, IOService )
|
|
|
|
/*****************************************************************************
|
|
* Variable typedefs
|
|
*****************************************************************************/
|
|
typedef enum { DKRTYPE_BUF, DKRTYPE_DIO } dkrtype_t;
|
|
typedef struct dio { dev_t dev; struct uio * uio; } dio_t;
|
|
typedef struct buf buf_t;
|
|
typedef void * dkr_t;
|
|
|
|
/*****************************************************************************
|
|
* Local prototypes
|
|
*****************************************************************************/
|
|
static int DVDClose ( dev_t, int, int, struct proc * );
|
|
static int DVDBlockIoctl ( dev_t, u_long, caddr_t, int, struct proc * );
|
|
static int DVDOpen ( dev_t, int, int, struct proc * );
|
|
static int DVDSize ( dev_t );
|
|
static void DVDStrategy ( buf_t * );
|
|
static int DVDReadWrite ( dkr_t, dkrtype_t );
|
|
static void DVDReadWriteCompletion( void *, void *, IOReturn, UInt64 );
|
|
|
|
static struct bdevsw device_functions =
|
|
{
|
|
DVDOpen, DVDClose, DVDStrategy, DVDBlockIoctl, eno_dump, DVDSize, D_DISK
|
|
};
|
|
|
|
/*****************************************************************************
|
|
* Local variables
|
|
*****************************************************************************/
|
|
static DVDioctl * p_this = NULL;
|
|
|
|
static bool b_inuse;
|
|
static int i_major;
|
|
static void *p_node;
|
|
static IODVDMedia *p_dvd;
|
|
static IODVDBlockStorageDriver *p_drive;
|
|
static IODVDServices *p_services;
|
|
static IOSCSIMultimediaCommandsDevice *p_scsi_mcd;
|
|
|
|
/*****************************************************************************
|
|
* DKR_GET_DEV: borrowed from IOMediaBSDClient.cpp
|
|
*****************************************************************************/
|
|
static inline dev_t DKR_GET_DEV(dkr_t dkr, dkrtype_t dkrtype)
|
|
{
|
|
return (dkrtype == DKRTYPE_BUF)
|
|
? ((buf_t *)dkr)->b_dev : ((dio_t *)dkr)->dev;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* DKR_GET_BYTE_COUNT: borrowed from IOMediaBSDClient.cpp
|
|
*****************************************************************************/
|
|
static inline UInt64 DKR_GET_BYTE_COUNT(dkr_t dkr, dkrtype_t dkrtype)
|
|
{
|
|
return (dkrtype == DKRTYPE_BUF)
|
|
? ((buf_t *)dkr)->b_bcount : ((dio_t *)dkr)->uio->uio_resid;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* DKR_GET_BYTE_START: borrowed from IOMediaBSDClient.cpp
|
|
*****************************************************************************/
|
|
static inline UInt64 DKR_GET_BYTE_START(dkr_t dkr, dkrtype_t dkrtype)
|
|
{
|
|
if (dkrtype == DKRTYPE_BUF)
|
|
{
|
|
buf_t * bp = (buf_t *)dkr;
|
|
return bp->b_blkno * p_dvd->getPreferredBlockSize();
|
|
}
|
|
return ((dio_t *)dkr)->uio->uio_offset;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* DKR_IS_READ: borrowed from IOMediaBSDClient.cpp
|
|
*****************************************************************************/
|
|
static inline bool DKR_IS_READ(dkr_t dkr, dkrtype_t dkrtype)
|
|
{
|
|
return (dkrtype == DKRTYPE_BUF)
|
|
? ((((buf_t *)dkr)->b_flags & B_READ) == B_READ)
|
|
: ((((dio_t *)dkr)->uio->uio_rw) == UIO_READ);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* DKR_IS_ASYNCHRONOUS: borrowed from IOMediaBSDClient.cpp
|
|
*****************************************************************************/
|
|
static inline bool DKR_IS_ASYNCHRONOUS(dkr_t dkr, dkrtype_t dkrtype)
|
|
{
|
|
return (dkrtype == DKRTYPE_BUF) ? true : false;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* DKR_IS_RAW: borrowed from IOMediaBSDClient.cpp
|
|
*****************************************************************************/
|
|
static inline bool DKR_IS_RAW(dkr_t dkr, dkrtype_t dkrtype)
|
|
{
|
|
return (dkrtype == DKRTYPE_BUF) ? false : true;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* DKR_SET_BYTE_COUNT: borrowed from IOMediaBSDClient.cpp
|
|
*****************************************************************************/
|
|
static inline void DKR_SET_BYTE_COUNT(dkr_t dkr, dkrtype_t dkrtype, UInt64 bcount)
|
|
{
|
|
if (dkrtype == DKRTYPE_BUF)
|
|
{
|
|
((buf_t *)dkr)->b_resid = ((buf_t *)dkr)->b_bcount - bcount;
|
|
}
|
|
else
|
|
{
|
|
((dio_t *)dkr)->uio->uio_resid -= bcount;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* DKR_RUN_COMPLETION: borrowed from IOMediaBSDClient.cpp
|
|
*****************************************************************************/
|
|
static inline void DKR_RUN_COMPLETION(dkr_t dkr, dkrtype_t dkrtype, IOReturn status)
|
|
{
|
|
if (dkrtype == DKRTYPE_BUF)
|
|
{
|
|
buf_t * bp = (buf_t *)dkr;
|
|
|
|
bp->b_error = p_this->errnoFromReturn(status);
|
|
bp->b_flags |= (status != kIOReturnSuccess) ? B_ERROR : 0;
|
|
biodone(bp);
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* DKR_GET_BUFFER: borrowed from IOMediaBSDClient.cpp
|
|
*****************************************************************************/
|
|
static inline IOMemoryDescriptor * DKR_GET_BUFFER(dkr_t dkr, dkrtype_t dkrtype)
|
|
{
|
|
if (dkrtype == DKRTYPE_BUF)
|
|
{
|
|
buf_t * bp = (buf_t *)dkr;
|
|
|
|
if ( (bp->b_flags & B_VECTORLIST) )
|
|
{
|
|
assert(sizeof(IOPhysicalRange ) == sizeof(iovec ));
|
|
assert(sizeof(IOPhysicalRange::address) == sizeof(iovec::iov_base));
|
|
assert(sizeof(IOPhysicalRange::length ) == sizeof(iovec::iov_len ));
|
|
return IOMemoryDescriptor::withPhysicalRanges(
|
|
(IOPhysicalRange *) bp->b_vectorlist,
|
|
(UInt32) bp->b_vectorcount,
|
|
(bp->b_flags & B_READ) ? kIODirectionIn : kIODirectionOut,
|
|
true );
|
|
}
|
|
|
|
return IOMemoryDescriptor::withAddress(
|
|
(vm_address_t) bp->b_data,
|
|
(vm_size_t) bp->b_bcount,
|
|
(bp->b_flags & B_READ) ? kIODirectionIn : kIODirectionOut,
|
|
(bp->b_flags & B_PHYS) ? current_task() : kernel_task );
|
|
}
|
|
else
|
|
{
|
|
struct uio * uio = ((dio_t *)dkr)->uio;
|
|
|
|
assert(sizeof(IOVirtualRange ) == sizeof(iovec ));
|
|
assert(sizeof(IOVirtualRange::address) == sizeof(iovec::iov_base));
|
|
assert(sizeof(IOVirtualRange::length ) == sizeof(iovec::iov_len ));
|
|
|
|
return IOMemoryDescriptor::withRanges(
|
|
(IOVirtualRange *) uio->uio_iov,
|
|
(UInt32) uio->uio_iovcnt,
|
|
(uio->uio_rw == UIO_READ ) ? kIODirectionIn : kIODirectionOut,
|
|
(uio->uio_segflg != UIO_SYSSPACE) ? current_task() : kernel_task,
|
|
true );
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* DVDioctl::init: initialize the driver structure
|
|
*****************************************************************************/
|
|
bool DVDioctl::init( OSDictionary *p_dict = 0 )
|
|
{
|
|
//IOLog( "DVD ioctl: initializing\n" );
|
|
|
|
p_this = this;
|
|
|
|
p_node = NULL;
|
|
p_dvd = NULL;
|
|
p_drive = NULL;
|
|
p_services = NULL;
|
|
p_scsi_mcd = NULL;
|
|
i_major = -1;
|
|
b_inuse = false;
|
|
|
|
bool res = super::init( p_dict );
|
|
|
|
return res;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* DVDioctl::probe: check whether the driver can be safely activated
|
|
*****************************************************************************/
|
|
IOService * DVDioctl::probe( IOService *provider, SInt32 *score )
|
|
{
|
|
//IOLog( "DVD ioctl: probing\n" );
|
|
IOService * res = super::probe( provider, score );
|
|
|
|
return res;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* DVDioctl::start: start the driver
|
|
*****************************************************************************/
|
|
bool DVDioctl::start( IOService *provider )
|
|
{
|
|
//IOLog( "DVD ioctl: starting\n" );
|
|
|
|
if( !super::start( provider ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//IOLog( "DVD ioctl: creating device\n" );
|
|
|
|
i_major = bdevsw_add( -1, &device_functions );
|
|
|
|
if( i_major == -1 )
|
|
{
|
|
//log(LOG_INFO, "DVD ioctl: failed to allocate a major number\n");
|
|
return false;
|
|
}
|
|
|
|
p_node = devfs_make_node ( makedev( i_major, 0 ), DEVFS_BLOCK,
|
|
UID_ROOT, GID_WHEEL, 0666, "dvd" );
|
|
|
|
if( p_node == NULL )
|
|
{
|
|
//log( LOG_INFO, "DVD ioctl: failed creating node\n" );
|
|
|
|
if( bdevsw_remove(i_major, &device_functions) == -1 )
|
|
{
|
|
//log( LOG_INFO, "DVD ioctl: bdevsw_remove failed\n" );
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* DVDioctl::stop: stop the driver
|
|
*****************************************************************************/
|
|
void DVDioctl::stop( IOService *provider )
|
|
{
|
|
//IOLog( "DVD ioctl: removing device\n" );
|
|
|
|
if( p_node != NULL )
|
|
{
|
|
devfs_remove( p_node );
|
|
}
|
|
|
|
if( i_major != -1 )
|
|
{
|
|
if( bdevsw_remove(i_major, &device_functions) == -1 )
|
|
{
|
|
//log( LOG_INFO, "DVD ioctl: bdevsw_remove failed\n" );
|
|
}
|
|
}
|
|
|
|
//IOLog( "DVD ioctl: stopping\n" );
|
|
super::stop( provider );
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* DVDioctl::free: free all resources allocated by the driver
|
|
*****************************************************************************/
|
|
void DVDioctl::free( void )
|
|
{
|
|
//IOLog( "DVD ioctl: freeing\n" );
|
|
super::free( );
|
|
}
|
|
|
|
/* following functions are local */
|
|
|
|
/*****************************************************************************
|
|
* DVDOpen: look for an IODVDMedia object and open it
|
|
*****************************************************************************/
|
|
static int DVDOpen( dev_t dev, int flags, int devtype, struct proc * )
|
|
{
|
|
IOStorageAccess level;
|
|
|
|
/* Check that the device hasn't already been opened */
|
|
if( b_inuse )
|
|
{
|
|
//log( LOG_INFO, "DVD ioctl: already opened\n" );
|
|
return EBUSY;
|
|
}
|
|
else
|
|
{
|
|
b_inuse = true;
|
|
}
|
|
|
|
IOService * p_root = IOService::getServiceRoot();
|
|
|
|
if( p_root == NULL )
|
|
{
|
|
//log( LOG_INFO, "DVD ioctl: couldn't find root\n" );
|
|
b_inuse = false;
|
|
return ENXIO;
|
|
}
|
|
|
|
OSDictionary * p_dict = p_root->serviceMatching( kIODVDMediaClass );
|
|
|
|
if( p_dict == NULL )
|
|
{
|
|
//log( LOG_INFO, "DVD ioctl: couldn't find dictionary\n" );
|
|
b_inuse = false;
|
|
return ENXIO;
|
|
}
|
|
|
|
p_dvd = OSDynamicCast( IODVDMedia, p_root->waitForService( p_dict ) );
|
|
|
|
if( p_dvd == NULL )
|
|
{
|
|
//log( LOG_INFO, "DVD ioctl: couldn't find service\n" );
|
|
b_inuse = false;
|
|
return ENXIO;
|
|
}
|
|
|
|
//log( LOG_INFO, "DVD ioctl: found DVD\n" );
|
|
|
|
level = (flags & FWRITE) ? kIOStorageAccessReaderWriter
|
|
: kIOStorageAccessReader;
|
|
|
|
if( ! p_dvd->open( p_this, 0, level) )
|
|
{
|
|
log( LOG_INFO, "DVD ioctl: IODVDMedia object busy\n" );
|
|
b_inuse = false;
|
|
return EBUSY;
|
|
}
|
|
|
|
p_drive = p_dvd->getProvider();
|
|
|
|
p_services = OSDynamicCast( IODVDServices, p_drive->getProvider() );
|
|
|
|
p_scsi_mcd = OSDynamicCast( IOSCSIMultimediaCommandsDevice, p_services->getProvider() );
|
|
|
|
log( LOG_INFO, "DVD ioctl: IODVDMedia->open()\n" );
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* DVDClose: close the IODVDMedia object
|
|
*****************************************************************************/
|
|
static int DVDClose( dev_t dev, int flags, int devtype, struct proc * )
|
|
{
|
|
/* Release the device */
|
|
p_dvd->close( p_this );
|
|
|
|
p_dvd = NULL;
|
|
p_drive = NULL;
|
|
p_services = NULL;
|
|
p_scsi_mcd = NULL;
|
|
b_inuse = false;
|
|
|
|
log( LOG_INFO, "DVD ioctl: IODVDMedia->close()\n" );
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* DVDSize: return the device size
|
|
*****************************************************************************/
|
|
static int DVDSize( dev_t dev )
|
|
{
|
|
return p_dvd->getPreferredBlockSize();
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* DVDStrategy: perform read or write operations
|
|
*****************************************************************************/
|
|
static void DVDStrategy( buf_t * bp )
|
|
{
|
|
DVDReadWrite(bp, DKRTYPE_BUF);
|
|
return;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* DVDBlockIoctl: issue an ioctl on the block device
|
|
*****************************************************************************/
|
|
static int DVDBlockIoctl( dev_t dev, u_long cmd, caddr_t addr, int flags,
|
|
struct proc *p )
|
|
{
|
|
#define p_data (((dvdioctl_data_t *)addr))
|
|
IOReturn i_ret = EINVAL;
|
|
|
|
/* Only needed for IODVD_READ_STRUCTURE */
|
|
SCSITask *p_request;
|
|
SCSIServiceResponse response;
|
|
|
|
IOMemoryDescriptor *p_mem;
|
|
|
|
p_mem = IOMemoryDescriptor::withAddress( p_data->p_buffer,
|
|
p_data->i_size,
|
|
kIODirectionOutIn );
|
|
|
|
switch( cmd )
|
|
{
|
|
case IODVD_READ_STRUCTURE:
|
|
|
|
log( LOG_INFO, "DVD ioctl: IODVD_READ_STRUCTURE\n" );
|
|
|
|
i_ret = kIOReturnUnsupported;
|
|
response = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
|
|
|
|
/* HACK! - Make GetSCSITask and friends in /System/Library/Frameworks/Kernel.framework/Versions/A/Headers/IOKit/scsi-commands/IOSCSIPrimaryCommandsDevice.h public by moving public: from line 96 to line 79 (as root). It's only a compile time check - not a link time thing, so it should be ok. */
|
|
p_request = p_scsi_mcd->GetSCSITask( );
|
|
|
|
if ( p_scsi_mcd->READ_DVD_STRUCTURE ( p_request,
|
|
p_mem,
|
|
p_data->i_lba,
|
|
0,//?LAYER_NUMBER
|
|
p_data->i_keyformat,
|
|
p_mem->getLength(),//p_data->i_size ?
|
|
p_data->i_agid,
|
|
0x00 //?CONTROL
|
|
) == true )
|
|
{
|
|
/* The command was successfully built, now send it */
|
|
response = p_scsi_mcd->SendCommand( p_request );
|
|
}
|
|
else
|
|
{
|
|
#if 0
|
|
exit -1;
|
|
PANIC_NOW(( "IOSCSIMultimediaCommandsDevice:: "
|
|
"readDVDstruct malformed command" ));
|
|
#endif
|
|
}
|
|
|
|
if( ( response == kSCSIServiceResponse_TASK_COMPLETE ) &&
|
|
( p_request->GetTaskStatus ( ) == kSCSITaskStatus_GOOD ) )
|
|
{
|
|
i_ret = kIOReturnSuccess;
|
|
}
|
|
else
|
|
{
|
|
i_ret = kIOReturnError;
|
|
}
|
|
|
|
p_scsi_mcd->ReleaseSCSITask( p_request );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case IODVD_SEND_KEY:
|
|
|
|
log( LOG_INFO, "DVD ioctl: send key to `%s', "
|
|
"buf %d, class %d, lba N/A, agid %d, format %d\n",
|
|
p_drive->getDeviceTypeName(),
|
|
(int)p_data->p_buffer, p_data->i_keyclass,
|
|
p_data->i_agid, p_data->i_keyformat );
|
|
|
|
i_ret = p_drive->sendKey( p_mem, (DVDKeyClass)p_data->i_keyclass,
|
|
p_data->i_agid,
|
|
(DVDKeyFormat)p_data->i_keyformat );
|
|
|
|
break;
|
|
|
|
case IODVD_REPORT_KEY:
|
|
|
|
log( LOG_INFO, "DVD ioctl: report key from `%s', "
|
|
"buf %d, class %d, lba %d, agid %d, format %d\n",
|
|
p_drive->getDeviceTypeName(),
|
|
(int)p_data->p_buffer, p_data->i_keyclass, p_data->i_lba,
|
|
p_data->i_agid, p_data->i_keyformat );
|
|
|
|
i_ret = p_drive->reportKey( p_mem, (DVDKeyClass)p_data->i_keyclass,
|
|
p_data->i_lba, p_data->i_agid,
|
|
(DVDKeyFormat)p_data->i_keyformat );
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
log( LOG_INFO, "DVD ioctl: unknown ioctl\n" );
|
|
|
|
i_ret = EINVAL;
|
|
|
|
break;
|
|
}
|
|
|
|
return i_ret;
|
|
#undef p_data
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* DVDReadWrite: borrowed from IOMediaBSDClient.cpp
|
|
*****************************************************************************/
|
|
static int DVDReadWrite(dkr_t dkr, dkrtype_t dkrtype)
|
|
{
|
|
IOMemoryDescriptor * buffer;
|
|
register UInt64 byteCount;
|
|
register UInt64 byteStart;
|
|
UInt64 mediaSize;
|
|
IOReturn status;
|
|
|
|
byteCount = DKR_GET_BYTE_COUNT(dkr, dkrtype);
|
|
byteStart = DKR_GET_BYTE_START(dkr, dkrtype);
|
|
mediaSize = p_dvd->getSize();
|
|
|
|
if ( byteStart >= mediaSize )
|
|
{
|
|
status = DKR_IS_READ(dkr,dkrtype) ? kIOReturnSuccess : kIOReturnIOError; goto dkreadwriteErr;
|
|
}
|
|
|
|
if ( DKR_IS_RAW(dkr, dkrtype) )
|
|
{
|
|
UInt64 mediaBlockSize = p_dvd->getPreferredBlockSize();
|
|
|
|
if ( (byteStart % mediaBlockSize) || (byteCount % mediaBlockSize) )
|
|
{
|
|
status = kIOReturnNotAligned;
|
|
goto dkreadwriteErr;
|
|
}
|
|
}
|
|
|
|
buffer = DKR_GET_BUFFER(dkr, dkrtype);
|
|
|
|
if ( buffer == 0 )
|
|
{
|
|
status = kIOReturnNoMemory;
|
|
goto dkreadwriteErr;
|
|
}
|
|
|
|
if ( byteCount > mediaSize - byteStart )
|
|
{
|
|
IOMemoryDescriptor * originalBuffer = buffer;
|
|
|
|
buffer = IOMemoryDescriptor::withSubRange( originalBuffer, 0,
|
|
mediaSize - byteStart, originalBuffer->getDirection() );
|
|
originalBuffer->release();
|
|
if ( buffer == 0 )
|
|
{
|
|
status = kIOReturnNoMemory;
|
|
goto dkreadwriteErr;
|
|
}
|
|
}
|
|
|
|
if ( DKR_IS_ASYNCHRONOUS(dkr, dkrtype) )
|
|
{
|
|
IOStorageCompletion completion;
|
|
|
|
completion.target = dkr;
|
|
completion.action = DVDReadWriteCompletion;
|
|
completion.parameter = (void *) dkrtype;
|
|
|
|
if ( DKR_IS_READ(dkr, dkrtype) )
|
|
{
|
|
p_dvd->read( p_this, byteStart, buffer, completion );
|
|
}
|
|
else
|
|
{
|
|
p_dvd->write( p_this, byteStart, buffer, completion );
|
|
}
|
|
|
|
status = kIOReturnSuccess;
|
|
}
|
|
else
|
|
{
|
|
if ( DKR_IS_READ(dkr, dkrtype) )
|
|
{
|
|
status = p_dvd->IOStorage::read( p_this, byteStart,
|
|
buffer, &byteCount );
|
|
}
|
|
else
|
|
{
|
|
status = p_dvd->IOStorage::write( p_this, byteStart,
|
|
buffer, &byteCount );
|
|
}
|
|
|
|
DVDReadWriteCompletion(dkr, (void *)dkrtype, status, byteCount);
|
|
}
|
|
|
|
buffer->release();
|
|
return p_this->errnoFromReturn(status);
|
|
dkreadwriteErr:
|
|
|
|
DVDReadWriteCompletion(dkr, (void *)dkrtype, status, 0);
|
|
|
|
return p_this->errnoFromReturn(status);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* DVDReadWriteCompletion: borrowed from IOMediaBSDClient.cpp
|
|
*****************************************************************************/
|
|
static void DVDReadWriteCompletion( void * target,
|
|
void * parameter,
|
|
IOReturn status,
|
|
UInt64 actualByteCount )
|
|
{
|
|
dkr_t dkr = (dkr_t) target;
|
|
dkrtype_t dkrtype = (dkrtype_t) (int) parameter;
|
|
dev_t dev = DKR_GET_DEV(dkr, dkrtype);
|
|
|
|
if ( status != kIOReturnSuccess )
|
|
{
|
|
IOLog( "DVD ioctl: %s (is the disc authenticated ?)\n",
|
|
p_this->stringFromReturn(status) );
|
|
}
|
|
|
|
DKR_SET_BYTE_COUNT(dkr, dkrtype, actualByteCount);
|
|
DKR_RUN_COMPLETION(dkr, dkrtype, status);
|
|
}
|
|
|
|
|