1 /*****************************************************************************
2 * DVDioctl.cpp: Linux-like DVD driver for Darwin and MacOS X
3 *****************************************************************************
4 * Copyright (C) 1998-2000 Apple Computer, Inc. All rights reserved.
5 * Copyright (C) 2001 VideoLAN
6 * $Id: DVDioctl.cpp,v 1.1 2001/04/02 23:30:41 sam Exp $
8 * Authors: Samuel Hocevar <sam@zoy.org>
10 * The contents of this file constitute Original Code as defined in and
11 * are subject to the Apple Public Source License Version 1.1 (the
12 * "License"). You may not use this file except in compliance with the
13 * License. Please obtain a copy of the License at
14 * http://www.apple.com/publicsource and read it before using this file.
16 * This Original Code and all software distributed under the License are
17 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
18 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
19 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
21 * License for the specific language governing rights and limitations
23 *****************************************************************************/
25 /*****************************************************************************
27 * - add a timeout to waitForService() so that we don't wait forever
28 * - find a way to prevent user from ejecting DVD using the GUI while
30 *****************************************************************************/
32 /*****************************************************************************
34 *****************************************************************************/
37 #include <sys/param.h>
39 #include <sys/syslog.h>
40 #include <sys/systm.h>
41 #include <sys/ioccom.h>
42 #include <sys/fcntl.h>
45 #include <miscfs/devfs/devfs.h>
47 #include <mach/mach_types.h>
50 #include <IOKit/IOLib.h>
51 #include <IOKit/IOService.h>
52 #include <IOKit/storage/IODVDMedia.h>
53 #include <IOKit/storage/IOMedia.h>
57 /*****************************************************************************
59 *****************************************************************************/
60 class DVDioctl : public IOService
62 OSDeclareDefaultStructors( DVDioctl )
66 virtual bool init ( OSDictionary *dictionary = 0 );
67 virtual IOService *probe ( IOService *provider, SInt32 *score );
68 virtual bool start ( IOService *provider );
69 virtual void stop ( IOService *provider );
70 virtual void free ( void );
73 #define super IOService
74 OSDefineMetaClassAndStructors( DVDioctl, IOService )
76 /*****************************************************************************
78 *****************************************************************************/
80 typedef enum { DKRTYPE_BUF, DKRTYPE_DIO } dkrtype_t;
81 typedef struct dio { dev_t dev; struct uio * uio; } dio_t;
82 typedef struct buf buf_t;
84 /*****************************************************************************
86 *****************************************************************************/
87 static int DVDClose ( dev_t, int, int, struct proc * );
88 static int DVDIoctl ( dev_t, u_long, caddr_t, int, struct proc * );
89 static int DVDOpen ( dev_t, int, int, struct proc * );
90 static int DVDSize ( dev_t );
91 static void DVDStrategy ( buf_t * );
92 static int DVDReadWrite( dkr_t, dkrtype_t );
93 static void DVDReadWriteCompletion( void *, void *, IOReturn, UInt64 );
95 static struct bdevsw device_functions =
97 DVDOpen, DVDClose, DVDStrategy, DVDIoctl, eno_dump, DVDSize, D_DISK
100 /*****************************************************************************
102 *****************************************************************************/
103 static DVDioctl * p_this = NULL;
108 static IODVDMedia *p_dvd;
110 /*****************************************************************************
111 * DKR_GET_DEV: borrowed from IOMediaBSDClient.cpp
112 *****************************************************************************/
113 static inline dev_t DKR_GET_DEV(dkr_t dkr, dkrtype_t dkrtype)
115 return (dkrtype == DKRTYPE_BUF)
116 ? ((buf_t *)dkr)->b_dev : ((dio_t *)dkr)->dev;
119 /*****************************************************************************
120 * DKR_GET_BYTE_COUNT: borrowed from IOMediaBSDClient.cpp
121 *****************************************************************************/
122 static inline UInt64 DKR_GET_BYTE_COUNT(dkr_t dkr, dkrtype_t dkrtype)
124 return (dkrtype == DKRTYPE_BUF)
125 ? ((buf_t *)dkr)->b_bcount : ((dio_t *)dkr)->uio->uio_resid;
128 /*****************************************************************************
129 * DKR_GET_BYTE_START: borrowed from IOMediaBSDClient.cpp
130 *****************************************************************************/
131 static inline UInt64 DKR_GET_BYTE_START(dkr_t dkr, dkrtype_t dkrtype)
133 if (dkrtype == DKRTYPE_BUF)
135 buf_t * bp = (buf_t *)dkr;
136 return bp->b_blkno * p_dvd->getPreferredBlockSize();
138 return ((dio_t *)dkr)->uio->uio_offset;
141 /*****************************************************************************
142 * DKR_IS_READ: borrowed from IOMediaBSDClient.cpp
143 *****************************************************************************/
144 static inline bool DKR_IS_READ(dkr_t dkr, dkrtype_t dkrtype)
146 return (dkrtype == DKRTYPE_BUF)
147 ? ((((buf_t *)dkr)->b_flags & B_READ) == B_READ)
148 : ((((dio_t *)dkr)->uio->uio_rw) == UIO_READ);
151 /*****************************************************************************
152 * DKR_IS_ASYNCHRONOUS: borrowed from IOMediaBSDClient.cpp
153 *****************************************************************************/
154 static inline bool DKR_IS_ASYNCHRONOUS(dkr_t dkr, dkrtype_t dkrtype)
156 return (dkrtype == DKRTYPE_BUF) ? true : false;
159 /*****************************************************************************
160 * DKR_IS_RAW: borrowed from IOMediaBSDClient.cpp
161 *****************************************************************************/
162 static inline bool DKR_IS_RAW(dkr_t dkr, dkrtype_t dkrtype)
164 return (dkrtype == DKRTYPE_BUF) ? false : true;
167 /*****************************************************************************
168 * DKR_SET_BYTE_COUNT: borrowed from IOMediaBSDClient.cpp
169 *****************************************************************************/
170 static inline void DKR_SET_BYTE_COUNT(dkr_t dkr, dkrtype_t dkrtype, UInt64 bcount)
172 if (dkrtype == DKRTYPE_BUF)
174 ((buf_t *)dkr)->b_resid = ((buf_t *)dkr)->b_bcount - bcount;
178 ((dio_t *)dkr)->uio->uio_resid -= bcount;
182 /*****************************************************************************
183 * DKR_RUN_COMPLETION: borrowed from IOMediaBSDClient.cpp
184 *****************************************************************************/
185 static inline void DKR_RUN_COMPLETION(dkr_t dkr, dkrtype_t dkrtype, IOReturn status)
187 if (dkrtype == DKRTYPE_BUF)
189 buf_t * bp = (buf_t *)dkr;
191 bp->b_error = p_this->errnoFromReturn(status);
192 bp->b_flags |= (status != kIOReturnSuccess) ? B_ERROR : 0;
197 /*****************************************************************************
198 * DKR_GET_BUFFER: borrowed from IOMediaBSDClient.cpp
199 *****************************************************************************/
200 static inline IOMemoryDescriptor * DKR_GET_BUFFER(dkr_t dkr, dkrtype_t dkrtype)
202 if (dkrtype == DKRTYPE_BUF)
204 buf_t * bp = (buf_t *)dkr;
206 if ( (bp->b_flags & B_VECTORLIST) )
208 assert(sizeof(IOPhysicalRange ) == sizeof(iovec ));
209 assert(sizeof(IOPhysicalRange::address) == sizeof(iovec::iov_base));
210 assert(sizeof(IOPhysicalRange::length ) == sizeof(iovec::iov_len ));
211 return IOMemoryDescriptor::withPhysicalRanges(
212 (IOPhysicalRange *) bp->b_vectorlist,
213 (UInt32) bp->b_vectorcount,
214 (bp->b_flags & B_READ) ? kIODirectionIn : kIODirectionOut,
218 return IOMemoryDescriptor::withAddress(
219 (vm_address_t) bp->b_data,
220 (vm_size_t) bp->b_bcount,
221 (bp->b_flags & B_READ) ? kIODirectionIn : kIODirectionOut,
222 (bp->b_flags & B_PHYS) ? current_task() : kernel_task );
226 struct uio * uio = ((dio_t *)dkr)->uio;
228 assert(sizeof(IOVirtualRange ) == sizeof(iovec ));
229 assert(sizeof(IOVirtualRange::address) == sizeof(iovec::iov_base));
230 assert(sizeof(IOVirtualRange::length ) == sizeof(iovec::iov_len ));
232 return IOMemoryDescriptor::withRanges(
233 (IOVirtualRange *) uio->uio_iov,
234 (UInt32) uio->uio_iovcnt,
235 (uio->uio_rw == UIO_READ ) ? kIODirectionIn : kIODirectionOut,
236 (uio->uio_segflg != UIO_SYSSPACE) ? current_task() : kernel_task,
241 /*****************************************************************************
242 * DVDioctl::init: initialize the driver structure
243 *****************************************************************************/
244 bool DVDioctl::init( OSDictionary *p_dict = 0 )
246 //IOLog( "DVD ioctl: initializing\n" );
255 bool res = super::init( p_dict );
260 /*****************************************************************************
261 * DVDioctl::probe: check whether the driver can be safely activated
262 *****************************************************************************/
263 IOService * DVDioctl::probe( IOService *provider, SInt32 *score )
265 //IOLog( "DVD ioctl: probing\n" );
266 IOService * res = super::probe( provider, score );
271 /*****************************************************************************
272 * DVDioctl::start: start the driver
273 *****************************************************************************/
274 bool DVDioctl::start( IOService *provider )
276 //IOLog( "DVD ioctl: starting\n" );
278 if( !super::start( provider ) )
283 //IOLog( "DVD ioctl: creating device\n" );
285 i_major = bdevsw_add( -1, &device_functions );
289 //log(LOG_INFO, "DVD ioctl: failed to allocate a major number\n");
293 p_node = devfs_make_node ( makedev( i_major, 0 ), DEVFS_BLOCK,
294 UID_ROOT, GID_WHEEL, 0666, "dvd" );
298 //log( LOG_INFO, "DVD ioctl: failed creating node\n" );
300 if( bdevsw_remove(i_major, &device_functions) == -1 )
302 //log( LOG_INFO, "DVD ioctl: bdevsw_remove failed\n" );
311 /*****************************************************************************
312 * DVDioctl::stop: stop the driver
313 *****************************************************************************/
314 void DVDioctl::stop( IOService *provider )
316 //IOLog( "DVD ioctl: removing device\n" );
320 devfs_remove( p_node );
325 if( bdevsw_remove(i_major, &device_functions) == -1 )
327 //log( LOG_INFO, "DVD ioctl: bdevsw_remove failed\n" );
331 //IOLog( "DVD ioctl: stopping\n" );
332 super::stop( provider );
335 /*****************************************************************************
336 * DVDioctl::free: free all resources allocated by the driver
337 *****************************************************************************/
338 void DVDioctl::free( void )
340 //IOLog( "DVD ioctl: freeing\n" );
345 IOReturn DVDioctl::report( IODVDMedia *DVD, IOMemoryDescriptor *buffer, const DVDKeyClass keyClass, const UInt32 lba, const UInt8 agid, const DVDKeyFormat keyFormat )
347 IOLog( "DVD ioctl: reportkey\n" );
348 return DVD->getProvider()->reportKey( buffer, keyClass, lba, agid, keyFormat );
351 IOReturn DVDioctl::send( IODVDMedia *DVD, IOMemoryDescriptor *buffer, const DVDKeyClass keyClass, const UInt32 lba, const DVDKeyFormat keyFormat )
353 IOLog( "DVD ioctl: sendkey\n" );
354 return DVD->getProvider()->sendKey( buffer, keyClass, lba, keyFormat );
358 /* following functions are local */
360 /*****************************************************************************
361 * DVDOpen: look for an IODVDMedia object and open it
362 *****************************************************************************/
363 static int DVDOpen( dev_t dev, int flags, int devtype, struct proc * )
365 IOStorageAccess level;
368 /* Check that the device hasn't already been opened */
371 //log( LOG_INFO, "DVD ioctl: already opened\n" );
379 IOService * p_root = IOService::getServiceRoot();
383 //log( LOG_INFO, "DVD ioctl: couldn't find root\n" );
388 OSDictionary * p_dict = p_root->serviceMatching( kIODVDMediaClass );
392 //log( LOG_INFO, "DVD ioctl: couldn't find dictionary\n" );
397 p_dvd = OSDynamicCast( IODVDMedia, p_root->waitForService( p_dict ) );
401 //log( LOG_INFO, "DVD ioctl: couldn't find service\n" );
406 //log( LOG_INFO, "DVD ioctl: found DVD\n" );
408 level = (flags & FWRITE) ? kIOStorageAccessReaderWriter
409 : kIOStorageAccessReader;
411 if( p_dvd->open( p_this, 0, level) )
413 log( LOG_INFO, "DVD ioctl: IODVDMedia->open()\n" );
418 log( LOG_INFO, "DVD ioctl: IODVDMedia object busy\n" );
426 /*****************************************************************************
427 * DVDClose: close the IODVDMedia object
428 *****************************************************************************/
429 static int DVDClose( dev_t dev, int flags, int devtype, struct proc * )
431 /* Release the device */
432 p_dvd->close( p_this );
435 log( LOG_INFO, "DVD ioctl: IODVDMedia->close()\n" );
440 /*****************************************************************************
441 * DVDSize: return the device size
442 *****************************************************************************/
443 static int DVDSize( dev_t dev )
445 return p_dvd->getPreferredBlockSize();
448 /*****************************************************************************
449 * DVDStrategy: perform read or write operations
450 *****************************************************************************/
451 static void DVDStrategy( buf_t * bp )
453 DVDReadWrite(bp, DKRTYPE_BUF);
457 /*****************************************************************************
458 * DVDIoctl: issue an ioctl on the device
459 *****************************************************************************/
460 static int DVDIoctl( dev_t dev, u_long cmd, caddr_t addr, int flags,
465 case IODVD_READ_STRUCTURE:
466 //log( LOG_INFO, "DVD ioctl: IODVD_READ_STRUCTURE\n" );
470 //log( LOG_INFO, "DVD ioctl: IODVD_SEND_KEY\n" );
473 case IODVD_REPORT_KEY:
474 //log( LOG_INFO, "DVD ioctl: IODVD_REPORT_KEY\n" );
478 //log( LOG_INFO, "DVD ioctl: unknown ioctl\n" );
483 /*****************************************************************************
484 * DVDReadWrite: borrowed from IOMediaBSDClient.cpp
485 *****************************************************************************/
486 static int DVDReadWrite(dkr_t dkr, dkrtype_t dkrtype)
488 IOMemoryDescriptor * buffer;
489 register UInt64 byteCount;
490 register UInt64 byteStart;
494 byteCount = DKR_GET_BYTE_COUNT(dkr, dkrtype);
495 byteStart = DKR_GET_BYTE_START(dkr, dkrtype);
496 mediaSize = p_dvd->getSize();
498 if ( byteStart >= mediaSize )
500 status = DKR_IS_READ(dkr,dkrtype) ? kIOReturnSuccess : kIOReturnIOError; goto dkreadwriteErr;
503 if ( DKR_IS_RAW(dkr, dkrtype) )
505 UInt64 mediaBlockSize = p_dvd->getPreferredBlockSize();
507 if ( (byteStart % mediaBlockSize) || (byteCount % mediaBlockSize) )
509 status = kIOReturnNotAligned;
514 buffer = DKR_GET_BUFFER(dkr, dkrtype);
518 status = kIOReturnNoMemory;
522 if ( byteCount > mediaSize - byteStart )
524 IOMemoryDescriptor * originalBuffer = buffer;
526 buffer = IOMemoryDescriptor::withSubRange( originalBuffer, 0,
527 mediaSize - byteStart, originalBuffer->getDirection() );
528 originalBuffer->release();
531 status = kIOReturnNoMemory;
536 if ( DKR_IS_ASYNCHRONOUS(dkr, dkrtype) )
538 IOStorageCompletion completion;
540 completion.target = dkr;
541 completion.action = DVDReadWriteCompletion;
542 completion.parameter = (void *) dkrtype;
544 if ( DKR_IS_READ(dkr, dkrtype) )
546 p_dvd->read( p_this, byteStart, buffer, completion );
550 p_dvd->write( p_this, byteStart, buffer, completion );
553 status = kIOReturnSuccess;
557 if ( DKR_IS_READ(dkr, dkrtype) )
559 status = p_dvd->IOStorage::read( p_this, byteStart,
560 buffer, &byteCount );
564 status = p_dvd->IOStorage::write( p_this, byteStart,
565 buffer, &byteCount );
568 DVDReadWriteCompletion(dkr, (void *)dkrtype, status, byteCount);
572 return p_this->errnoFromReturn(status);
575 DVDReadWriteCompletion(dkr, (void *)dkrtype, status, 0);
577 return p_this->errnoFromReturn(status);
580 /*****************************************************************************
581 * DVDReadWriteCompletion: borrowed from IOMediaBSDClient.cpp
582 *****************************************************************************/
583 static void DVDReadWriteCompletion( void * target,
586 UInt64 actualByteCount )
588 dkr_t dkr = (dkr_t) target;
589 dkrtype_t dkrtype = (dkrtype_t) (int) parameter;
590 dev_t dev = DKR_GET_DEV(dkr, dkrtype);
592 if ( status != kIOReturnSuccess )
594 IOLog( "%s: %s.\n", /*p_this->name*/ "DVD ioctl",
595 p_this->stringFromReturn(status) );
598 DKR_SET_BYTE_COUNT(dkr, dkrtype, actualByteCount);
599 DKR_RUN_COMPLETION(dkr, dkrtype, status);