]> git.sesse.net Git - vlc/blob - extras/MacOSX_dvdioctl/DVDioctl.cpp
* ./configure.in: fixed linking of the ipv4 plugin.
[vlc] / extras / MacOSX_dvdioctl / DVDioctl.cpp
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.7 2001/06/25 11:34:08 sam Exp $
7  *
8  * Authors: Samuel Hocevar <sam@zoy.org>
9  *          Eugenio Jarosiewicz <ej0@cise.ufl.edu>
10  *
11  * The contents of this file constitute Original Code as defined in and
12  * are subject to the Apple Public Source License Version 1.1 (the
13  * "License").  You may not use this file except in compliance with the
14  * License.  Please obtain a copy of the License at
15  * http://www.apple.com/publicsource and read it before using this file.
16  * 
17  * This Original Code and all software distributed under the License are
18  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
19  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
20  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
21  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
22  * License for the specific language governing rights and limitations
23  * under the License.
24  *****************************************************************************/
25
26 /*****************************************************************************
27  * TODO:
28  * - add a timeout to waitForService() so that we don't wait forever
29  * - find a way to prevent user from ejecting DVD using the GUI while
30  *   it is still in use
31  *****************************************************************************/
32
33 /*****************************************************************************
34  * Preamble
35  *****************************************************************************/
36 extern "C"
37 {
38 #include <sys/param.h>
39 #include <sys/conf.h>
40 #include <sys/syslog.h>
41 #include <sys/systm.h>
42 #include <sys/ioccom.h>
43 #include <sys/fcntl.h>
44 #include <sys/buf.h>
45 #include <sys/uio.h>
46 #include <miscfs/devfs/devfs.h>
47
48 #include <mach/mach_types.h>
49 }
50
51 #include <IOKit/IOLib.h>
52 #include <IOKit/IOService.h>
53 #include <IOKit/storage/IOMedia.h>
54 #include <IOKit/storage/IODVDMedia.h>
55 #include <IOKit/storage/IODVDBlockStorageDriver.h>
56
57 #undef CONTROL //some include above #defines this and breaks the next include...grr.
58 #include <IOKit/scsi-commands/IOSCSIMultimediaCommandsDevice.h>
59 #include <IOKit/scsi-commands/IODVDServices.h>
60
61 #include "DVDioctl.h"
62
63 /*****************************************************************************
64  * Driver class
65  *****************************************************************************/
66 class DVDioctl : public IOService
67 {
68     OSDeclareDefaultStructors( DVDioctl )
69
70 public:
71
72     virtual bool       init   ( OSDictionary *dictionary = 0 );
73     virtual IOService *probe  ( IOService *provider, SInt32 *score );
74     virtual bool       start  ( IOService *provider );
75     virtual void       stop   ( IOService *provider );
76     virtual void       free   ( void );
77 };
78
79 #define super IOService
80 OSDefineMetaClassAndStructors( DVDioctl, IOService )
81
82 /*****************************************************************************
83  * Variable typedefs
84  *****************************************************************************/
85 typedef enum       { DKRTYPE_BUF, DKRTYPE_DIO }      dkrtype_t;
86 typedef struct dio { dev_t dev; struct uio * uio; }  dio_t;
87 typedef struct buf                                   buf_t;
88 typedef void *                                       dkr_t;
89
90 /*****************************************************************************
91  * Local prototypes
92  *****************************************************************************/
93 static int  DVDClose        ( dev_t, int, int, struct proc * );
94 static int  DVDBlockIoctl   ( dev_t, u_long, caddr_t, int, struct proc * );
95 static int  DVDOpen         ( dev_t, int, int, struct proc * );
96 static int  DVDSize         ( dev_t );
97 static void DVDStrategy     ( buf_t * );
98 static int  DVDReadWrite    ( dkr_t, dkrtype_t );
99 static void DVDReadWriteCompletion( void *, void *, IOReturn, UInt64 );
100
101 static struct bdevsw device_functions =
102 {
103     DVDOpen, DVDClose, DVDStrategy, DVDBlockIoctl, eno_dump, DVDSize, D_DISK
104 };
105
106 /*****************************************************************************
107  * Local variables
108  *****************************************************************************/
109 static DVDioctl * p_this = NULL;
110
111 static bool b_inuse;
112 static int i_major;
113 static void *p_node;
114 static IODVDMedia *p_dvd;
115 static IODVDBlockStorageDriver *p_drive;
116 static IODVDServices *p_services;
117 static IOSCSIMultimediaCommandsDevice *p_scsi_mcd;
118
119 /*****************************************************************************
120  * DKR_GET_DEV: borrowed from IOMediaBSDClient.cpp
121  *****************************************************************************/
122 static inline dev_t DKR_GET_DEV(dkr_t dkr, dkrtype_t dkrtype)
123 {
124     return (dkrtype == DKRTYPE_BUF)
125            ? ((buf_t *)dkr)->b_dev : ((dio_t *)dkr)->dev;
126 }
127
128 /*****************************************************************************
129  * DKR_GET_BYTE_COUNT: borrowed from IOMediaBSDClient.cpp
130  *****************************************************************************/
131 static inline UInt64 DKR_GET_BYTE_COUNT(dkr_t dkr, dkrtype_t dkrtype)
132 {
133     return (dkrtype == DKRTYPE_BUF)
134            ? ((buf_t *)dkr)->b_bcount : ((dio_t *)dkr)->uio->uio_resid;
135 }
136
137 /*****************************************************************************
138  * DKR_GET_BYTE_START: borrowed from IOMediaBSDClient.cpp
139  *****************************************************************************/
140 static inline UInt64 DKR_GET_BYTE_START(dkr_t dkr, dkrtype_t dkrtype)
141 {
142     if (dkrtype == DKRTYPE_BUF)
143     {
144         buf_t * bp    = (buf_t *)dkr;
145         return bp->b_blkno * p_dvd->getPreferredBlockSize();
146     }
147     return ((dio_t *)dkr)->uio->uio_offset;
148 }
149
150 /*****************************************************************************
151  * DKR_IS_READ: borrowed from IOMediaBSDClient.cpp
152  *****************************************************************************/
153 static inline bool DKR_IS_READ(dkr_t dkr, dkrtype_t dkrtype)
154 {
155     return (dkrtype == DKRTYPE_BUF)
156            ? ((((buf_t *)dkr)->b_flags & B_READ) == B_READ)
157            : ((((dio_t *)dkr)->uio->uio_rw) == UIO_READ);
158 }
159
160 /*****************************************************************************
161  * DKR_IS_ASYNCHRONOUS: borrowed from IOMediaBSDClient.cpp
162  *****************************************************************************/
163 static inline bool DKR_IS_ASYNCHRONOUS(dkr_t dkr, dkrtype_t dkrtype)
164 {
165     return (dkrtype == DKRTYPE_BUF) ? true : false;
166 }
167
168 /*****************************************************************************
169  * DKR_IS_RAW: borrowed from IOMediaBSDClient.cpp
170  *****************************************************************************/
171 static inline bool DKR_IS_RAW(dkr_t dkr, dkrtype_t dkrtype)
172 {
173     return (dkrtype == DKRTYPE_BUF) ? false : true;
174 }
175
176 /*****************************************************************************
177  * DKR_SET_BYTE_COUNT: borrowed from IOMediaBSDClient.cpp
178  *****************************************************************************/
179 static inline void DKR_SET_BYTE_COUNT(dkr_t dkr, dkrtype_t dkrtype, UInt64 bcount)
180 {
181     if (dkrtype == DKRTYPE_BUF)
182     {
183         ((buf_t *)dkr)->b_resid = ((buf_t *)dkr)->b_bcount - bcount;
184     }
185     else
186     {
187         ((dio_t *)dkr)->uio->uio_resid -= bcount;
188     }
189 }
190
191 /*****************************************************************************
192  * DKR_RUN_COMPLETION: borrowed from IOMediaBSDClient.cpp
193  *****************************************************************************/
194 static inline void DKR_RUN_COMPLETION(dkr_t dkr, dkrtype_t dkrtype, IOReturn status)
195 {
196     if (dkrtype == DKRTYPE_BUF)
197     {
198         buf_t * bp = (buf_t *)dkr;
199
200         bp->b_error  = p_this->errnoFromReturn(status);
201         bp->b_flags |= (status != kIOReturnSuccess) ? B_ERROR : 0;
202         biodone(bp);
203     }
204 }
205
206 /*****************************************************************************
207  * DKR_GET_BUFFER: borrowed from IOMediaBSDClient.cpp
208  *****************************************************************************/
209 static inline IOMemoryDescriptor * DKR_GET_BUFFER(dkr_t dkr, dkrtype_t dkrtype)
210 {
211     if (dkrtype == DKRTYPE_BUF)
212     {
213         buf_t * bp = (buf_t *)dkr;
214
215         if ( (bp->b_flags & B_VECTORLIST) )
216         {
217             assert(sizeof(IOPhysicalRange         ) == sizeof(iovec          ));
218             assert(sizeof(IOPhysicalRange::address) == sizeof(iovec::iov_base));
219             assert(sizeof(IOPhysicalRange::length ) == sizeof(iovec::iov_len ));
220             return IOMemoryDescriptor::withPhysicalRanges(
221               (IOPhysicalRange *) bp->b_vectorlist,
222               (UInt32)            bp->b_vectorcount,
223               (bp->b_flags & B_READ) ? kIODirectionIn : kIODirectionOut,
224               true );
225         }
226
227         return IOMemoryDescriptor::withAddress(
228           (vm_address_t) bp->b_data,
229           (vm_size_t)    bp->b_bcount,
230           (bp->b_flags & B_READ) ? kIODirectionIn : kIODirectionOut,
231           (bp->b_flags & B_PHYS) ? current_task() : kernel_task );
232     }
233     else
234     {
235         struct uio * uio = ((dio_t *)dkr)->uio;
236
237         assert(sizeof(IOVirtualRange         ) == sizeof(iovec          ));
238         assert(sizeof(IOVirtualRange::address) == sizeof(iovec::iov_base));
239         assert(sizeof(IOVirtualRange::length ) == sizeof(iovec::iov_len ));
240
241         return IOMemoryDescriptor::withRanges(
242         (IOVirtualRange *) uio->uio_iov,
243         (UInt32)           uio->uio_iovcnt,
244         (uio->uio_rw     == UIO_READ    ) ? kIODirectionIn : kIODirectionOut,
245         (uio->uio_segflg != UIO_SYSSPACE) ? current_task() : kernel_task,
246         true );
247     }
248 }
249
250 /*****************************************************************************
251  * DVDioctl::init: initialize the driver structure
252  *****************************************************************************/
253 bool DVDioctl::init( OSDictionary *p_dict = 0 )
254 {
255     //IOLog( "DVD ioctl: initializing\n" );
256
257     p_this = this;
258
259     p_node  = NULL;
260     p_dvd   = NULL;
261     p_drive = NULL;
262     p_services = NULL;
263     p_scsi_mcd = NULL;
264     i_major = -1;
265     b_inuse = false;
266
267     bool res = super::init( p_dict );
268
269     return res;
270 }
271     
272 /*****************************************************************************
273  * DVDioctl::probe: check whether the driver can be safely activated
274  *****************************************************************************/
275 IOService * DVDioctl::probe( IOService *provider, SInt32 *score )
276 {
277     //IOLog( "DVD ioctl: probing\n" );
278     IOService * res = super::probe( provider, score );
279
280     return res;
281 }
282
283 /*****************************************************************************
284  * DVDioctl::start: start the driver
285  *****************************************************************************/
286 bool DVDioctl::start( IOService *provider )
287 {
288     //IOLog( "DVD ioctl: starting\n" );
289
290     if( !super::start( provider ) )
291     {
292         return false;
293     }
294
295     //IOLog( "DVD ioctl: creating device\n" );
296
297     i_major = bdevsw_add( -1, &device_functions );
298
299     if( i_major == -1 )
300     {
301         //log(LOG_INFO, "DVD ioctl: failed to allocate a major number\n");
302         return false;
303     }
304
305     p_node = devfs_make_node ( makedev( i_major, 0 ), DEVFS_BLOCK,
306                                UID_ROOT, GID_WHEEL, 0666, "dvd" );
307
308     if( p_node == NULL )
309     {
310         //log( LOG_INFO, "DVD ioctl: failed creating node\n" );
311
312         if( bdevsw_remove(i_major, &device_functions) == -1 )
313         {
314             //log( LOG_INFO, "DVD ioctl: bdevsw_remove failed\n" );
315         }
316
317         return false;
318     }
319
320     return true;
321 }
322
323 /*****************************************************************************
324  * DVDioctl::stop: stop the driver
325  *****************************************************************************/
326 void DVDioctl::stop( IOService *provider )
327 {
328     //IOLog( "DVD ioctl: removing device\n" );
329
330     if( p_node != NULL )
331     {
332         devfs_remove( p_node );
333     }
334
335     if( i_major != -1 )
336     {
337         if( bdevsw_remove(i_major, &device_functions) == -1 )
338         {
339             //log( LOG_INFO, "DVD ioctl: bdevsw_remove failed\n" );
340         }
341     }
342
343     //IOLog( "DVD ioctl: stopping\n" );
344     super::stop( provider );
345 }
346   
347 /*****************************************************************************
348  * DVDioctl::free: free all resources allocated by the driver
349  *****************************************************************************/
350 void DVDioctl::free( void )
351 {
352     //IOLog( "DVD ioctl: freeing\n" );
353     super::free( );
354 }
355
356 /* following functions are local */
357
358 /*****************************************************************************
359  * DVDOpen: look for an IODVDMedia object and open it
360  *****************************************************************************/
361 static int DVDOpen( dev_t dev, int flags, int devtype, struct proc * )
362 {
363     IOStorageAccess level;
364
365     /* Check that the device hasn't already been opened */
366     if( b_inuse )
367     {
368         //log( LOG_INFO, "DVD ioctl: already opened\n" );
369         return EBUSY;
370     }
371     else
372     {
373         b_inuse = true;
374     }
375
376     IOService * p_root = IOService::getServiceRoot();
377    
378     if( p_root == NULL )
379     {
380         //log( LOG_INFO, "DVD ioctl: couldn't find root\n" );
381         b_inuse = false;
382         return ENXIO;
383     }
384
385     OSDictionary * p_dict = p_root->serviceMatching( kIODVDMediaClass );
386
387     if( p_dict == NULL )
388     {
389         //log( LOG_INFO, "DVD ioctl: couldn't find dictionary\n" );
390         b_inuse = false;
391         return ENXIO;
392     }
393
394     p_dvd = OSDynamicCast( IODVDMedia, p_root->waitForService( p_dict ) );
395
396     if( p_dvd == NULL )
397     {
398         //log( LOG_INFO, "DVD ioctl: couldn't find service\n" );
399         b_inuse = false;
400         return ENXIO;
401     }
402
403     //log( LOG_INFO, "DVD ioctl: found DVD\n" );
404
405     level = (flags & FWRITE) ? kIOStorageAccessReaderWriter
406                              : kIOStorageAccessReader;
407
408     if( ! p_dvd->open( p_this, 0, level) )
409     {
410         log( LOG_INFO, "DVD ioctl: IODVDMedia object busy\n" );
411         b_inuse = false;
412         return EBUSY;
413     }
414
415     p_drive = p_dvd->getProvider();
416
417     p_services = OSDynamicCast( IODVDServices, p_drive->getProvider() );
418
419     p_scsi_mcd = OSDynamicCast( IOSCSIMultimediaCommandsDevice, p_services->getProvider() );
420
421     log( LOG_INFO, "DVD ioctl: IODVDMedia->open()\n" );
422
423     return 0;
424 }
425
426 /*****************************************************************************
427  * DVDClose: close the IODVDMedia object
428  *****************************************************************************/
429 static int DVDClose( dev_t dev, int flags, int devtype, struct proc * )
430 {
431     /* Release the device */
432     p_dvd->close( p_this );
433
434     p_dvd   = NULL;
435     p_drive = NULL;
436     p_services = NULL;
437     p_scsi_mcd = NULL;
438     b_inuse = false;
439
440     log( LOG_INFO, "DVD ioctl: IODVDMedia->close()\n" );
441
442     return 0;
443 }
444
445 /*****************************************************************************
446  * DVDSize: return the device size
447  *****************************************************************************/
448 static int DVDSize( dev_t dev )
449 {
450     return p_dvd->getPreferredBlockSize();
451 }
452
453 /*****************************************************************************
454  * DVDStrategy: perform read or write operations
455  *****************************************************************************/
456 static void DVDStrategy( buf_t * bp )
457 {
458     DVDReadWrite(bp, DKRTYPE_BUF);
459     return;
460 }
461
462 /*****************************************************************************
463  * DVDBlockIoctl: issue an ioctl on the block device
464  *****************************************************************************/
465 static int DVDBlockIoctl( dev_t dev, u_long cmd, caddr_t addr, int flags,
466                           struct proc *p )
467 {
468 #define p_data (((dvdioctl_data_t *)addr))
469     IOReturn            i_ret = EINVAL;
470
471     /* Only needed for IODVD_READ_STRUCTURE */
472     SCSITask           *p_request;
473     SCSIServiceResponse response;
474     
475     IOMemoryDescriptor *p_mem;
476
477     p_mem = IOMemoryDescriptor::withAddress( p_data->p_buffer,
478                                              p_data->i_size,
479                                              kIODirectionOutIn );
480
481     switch( cmd )
482     {
483         case IODVD_READ_STRUCTURE:
484
485             log( LOG_INFO, "DVD ioctl: IODVD_READ_STRUCTURE\n" );
486
487             i_ret = kIOReturnUnsupported;
488             response = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
489
490 /* 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. */
491             p_request = p_scsi_mcd->GetSCSITask( );
492
493             if ( p_scsi_mcd->READ_DVD_STRUCTURE ( p_request,
494                                                   p_mem,
495                                                   p_data->i_lba,
496                                                   0,//?LAYER_NUMBER
497                                                   p_data->i_keyformat,
498                                                   p_mem->getLength(),//p_data->i_size ?
499                                                   p_data->i_agid,
500                                                   0x00 //?CONTROL
501                                                    ) == true )
502                 {
503                     /* The command was successfully built, now send it */
504                     response = p_scsi_mcd->SendCommand( p_request );
505                 }
506                 else
507                 {
508 #if 0
509                     exit -1;
510                     PANIC_NOW(( "IOSCSIMultimediaCommandsDevice:: "
511                                 "readDVDstruct malformed command" ));
512 #endif
513                 }
514
515                 if( ( response == kSCSIServiceResponse_TASK_COMPLETE ) &&
516                     ( p_request->GetTaskStatus ( ) == kSCSITaskStatus_GOOD ) )
517                 {
518                     i_ret = kIOReturnSuccess;
519                 }
520                 else
521                 {
522                     i_ret = kIOReturnError;
523                 }
524
525                 p_scsi_mcd->ReleaseSCSITask( p_request );
526                         
527             }
528
529             break;
530
531         case IODVD_SEND_KEY:
532
533             log( LOG_INFO, "DVD ioctl: send key to `%s', "
534                  "buf %d, class %d, lba N/A, agid %d, format %d\n",
535                  p_drive->getDeviceTypeName(),
536                  (int)p_data->p_buffer, p_data->i_keyclass,
537                  p_data->i_agid, p_data->i_keyformat );
538
539             i_ret = p_drive->sendKey( p_mem, (DVDKeyClass)p_data->i_keyclass,
540                                       p_data->i_agid,
541                                       (DVDKeyFormat)p_data->i_keyformat );
542
543             break;
544
545         case IODVD_REPORT_KEY:
546
547             log( LOG_INFO, "DVD ioctl: report key from `%s', "
548                  "buf %d, class %d, lba %d, agid %d, format %d\n",
549                  p_drive->getDeviceTypeName(),
550                  (int)p_data->p_buffer, p_data->i_keyclass, p_data->i_lba,
551                  p_data->i_agid, p_data->i_keyformat );
552
553             i_ret = p_drive->reportKey( p_mem, (DVDKeyClass)p_data->i_keyclass,
554                                         p_data->i_lba, p_data->i_agid,
555                                         (DVDKeyFormat)p_data->i_keyformat );
556
557             break;
558
559         default:
560
561             log( LOG_INFO, "DVD ioctl: unknown ioctl\n" );
562
563             i_ret = EINVAL;
564
565             break;
566     }
567
568     return i_ret;
569 #undef p_data
570 }
571
572 /*****************************************************************************
573  * DVDReadWrite: borrowed from IOMediaBSDClient.cpp
574  *****************************************************************************/
575 static int DVDReadWrite(dkr_t dkr, dkrtype_t dkrtype)
576 {
577     IOMemoryDescriptor * buffer;
578     register UInt64      byteCount;
579     register UInt64      byteStart;
580     UInt64               mediaSize;
581     IOReturn             status;
582
583     byteCount = DKR_GET_BYTE_COUNT(dkr, dkrtype);
584     byteStart = DKR_GET_BYTE_START(dkr, dkrtype);
585     mediaSize = p_dvd->getSize();
586
587     if ( byteStart >= mediaSize )
588     {
589         status = DKR_IS_READ(dkr,dkrtype) ? kIOReturnSuccess : kIOReturnIOError;        goto dkreadwriteErr;
590     }
591
592     if ( DKR_IS_RAW(dkr, dkrtype) )
593     {
594         UInt64 mediaBlockSize = p_dvd->getPreferredBlockSize();
595
596         if ( (byteStart % mediaBlockSize) || (byteCount % mediaBlockSize) )
597         {
598             status = kIOReturnNotAligned;
599             goto dkreadwriteErr;
600         }
601     }
602
603     buffer = DKR_GET_BUFFER(dkr, dkrtype);
604
605     if ( buffer == 0 )
606     {
607         status = kIOReturnNoMemory;
608         goto dkreadwriteErr;
609     }
610
611     if ( byteCount > mediaSize - byteStart )
612     {
613         IOMemoryDescriptor * originalBuffer = buffer;
614
615         buffer = IOMemoryDescriptor::withSubRange( originalBuffer, 0,
616                      mediaSize - byteStart, originalBuffer->getDirection() );
617         originalBuffer->release();
618         if ( buffer == 0 )
619         {
620             status = kIOReturnNoMemory;
621             goto dkreadwriteErr;
622         }
623     }
624
625     if ( DKR_IS_ASYNCHRONOUS(dkr, dkrtype) )
626     {
627         IOStorageCompletion completion;
628
629         completion.target    = dkr;
630         completion.action    = DVDReadWriteCompletion;
631         completion.parameter = (void *) dkrtype;
632
633         if ( DKR_IS_READ(dkr, dkrtype) )
634         {
635             p_dvd->read(  p_this, byteStart, buffer, completion );
636         }
637         else
638         {
639             p_dvd->write( p_this, byteStart, buffer, completion );
640         }
641
642         status = kIOReturnSuccess;
643     }
644     else
645     {
646         if ( DKR_IS_READ(dkr, dkrtype) )
647         {
648             status = p_dvd->IOStorage::read( p_this, byteStart,
649                                              buffer, &byteCount );
650         }
651         else
652         {
653             status = p_dvd->IOStorage::write( p_this, byteStart,
654                                               buffer, &byteCount );
655         }
656
657         DVDReadWriteCompletion(dkr, (void *)dkrtype, status, byteCount);
658     }
659
660     buffer->release();
661     return p_this->errnoFromReturn(status);
662 dkreadwriteErr:
663
664     DVDReadWriteCompletion(dkr, (void *)dkrtype, status, 0);
665
666     return p_this->errnoFromReturn(status);
667 }
668
669 /*****************************************************************************
670  * DVDReadWriteCompletion: borrowed from IOMediaBSDClient.cpp
671  *****************************************************************************/
672 static void DVDReadWriteCompletion( void *   target,
673                                     void *   parameter,
674                                     IOReturn status,
675                                     UInt64   actualByteCount )
676 {
677     dkr_t     dkr      = (dkr_t) target;
678     dkrtype_t dkrtype  = (dkrtype_t) (int) parameter;
679     dev_t     dev      = DKR_GET_DEV(dkr, dkrtype);
680
681     if ( status != kIOReturnSuccess )
682     {
683         IOLog( "DVD ioctl: %s (is the disc authenticated ?)\n",
684                p_this->stringFromReturn(status) );
685     }
686
687     DKR_SET_BYTE_COUNT(dkr, dkrtype, actualByteCount);
688     DKR_RUN_COMPLETION(dkr, dkrtype, status);
689 }
690