1/*
2 * Copyright (c) 1998-2012 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23#include <IOKit/IOBufferMemoryDescriptor.h>
24#include <IOKit/IOKitKeys.h>
25#include <IOKit/IOLib.h>
26#include <IOKit/storage/IOCDBlockStorageDriver.h>
27#include <IOKit/storage/IOCDMedia.h>
28#include <IOKit/storage/IOCDBlockStorageDevice.h>
29#include <libkern/OSByteOrder.h>
30
31#define	super	IOBlockStorageDriver
32OSDefineMetaClassAndStructors(IOCDBlockStorageDriver,IOBlockStorageDriver)
33
34#ifdef __LP64__
35#define original request
36#endif /* __LP64__ */
37
38IOCDBlockStorageDevice *
39IOCDBlockStorageDriver::getProvider() const
40{
41    return (IOCDBlockStorageDevice *) IOService::getProvider();
42}
43
44
45/* Accept a new piece of media, doing whatever's necessary to make it
46 * show up properly to the system. The arbitration lock is assumed to
47 * be held during the call.
48 */
49IOReturn
50IOCDBlockStorageDriver::acceptNewMedia(void)
51{
52    IOReturn result;
53    int i;
54    int nentries;
55    int nAudioTracks;
56
57    /* First, we cache information about the tracks on the disc: */
58
59    result = cacheTocInfo();
60    if (result != kIOReturnSuccess) {
61        assert(_toc == NULL);
62    }
63
64    /* Scan thru the track list, counting up the number of Data and Audio tracks. */
65
66    nAudioTracks = 0;
67
68    _minBlockNumberAudio = 0xFFFFFFFF;
69    _maxBlockNumberAudio = 0xFFFFFFFF;
70
71    if (_toc) {
72        nentries = CDTOCGetDescriptorCount(_toc);
73
74        for (i = 0; i < nentries; i++) {
75            UInt32 lba = CDConvertMSFToClippedLBA(_toc->descriptors[i].p);
76            /* tracks 1-99, not leadout or skip intervals */
77            if (_toc->descriptors[i].point <= 99 && _toc->descriptors[i].adr == 1) {
78                if ((_toc->descriptors[i].control & 0x04)) {
79                    /* it's a data track */
80                    _maxBlockNumberAudio = min(_maxBlockNumberAudio, lba ? (lba - 1) : 0);
81                } else {
82                    nAudioTracks++;
83                    _minBlockNumberAudio = min(_minBlockNumberAudio, lba);
84                }
85            /* leadout */
86            } else if (_toc->descriptors[i].point == 0xA2 && _toc->descriptors[i].adr == 1) {
87                _maxBlockNumber = max(_maxBlockNumber, lba ? (lba - 1) : 0);
88                _maxBlockNumberAudio = min(_maxBlockNumberAudio, lba ? (lba - 1) : 0);
89            }
90        }
91
92        if (_maxBlockNumberAudio < _minBlockNumberAudio) {
93            _maxBlockNumberAudio = 0xFFFFFFFF;
94
95            /* find first data track or leadout after the audio tracks */
96            for (i = 0; i < nentries; i++) {
97                UInt32 lba = CDConvertMSFToClippedLBA(_toc->descriptors[i].p);
98                /* tracks 1-99, not leadout or skip intervals */
99                if (_toc->descriptors[i].point <= 99 && _toc->descriptors[i].adr == 1) {
100                    if ((_toc->descriptors[i].control & 0x04)) {
101                        /* it's a data track */
102                        if (lba > _minBlockNumberAudio) {
103                            _maxBlockNumberAudio = min(_maxBlockNumberAudio, lba - 1);
104                        }
105                    }
106                /* leadout */
107                } else if (_toc->descriptors[i].point == 0xA2 && _toc->descriptors[i].adr == 1) {
108                    if (lba > _minBlockNumberAudio) {
109                        _maxBlockNumberAudio = min(_maxBlockNumberAudio, lba - 1);
110                    }
111                }
112            }
113        }
114    }
115
116    /* Obtain disc status: */
117
118    switch (getMediaType()) {
119        case kCDMediaTypeR:
120        case kCDMediaTypeRW: {
121            bool checkIsWritable = false;
122            CDDiscInfo discInfo;
123            CDTrackInfo trackInfo;
124
125            result = reportDiscInfo(&discInfo);
126            if (result != kIOReturnSuccess) {
127                break;
128            }
129
130            switch (discInfo.discStatus) {
131                case 0x01: /* is disc incomplete? */
132                    checkIsWritable = true;
133                    break;
134                case 0x02: /* is disc complete? */
135                    checkIsWritable = discInfo.erasable ? true : false;
136                    break;
137            }
138
139            /* Obtain track status: */
140
141            if (checkIsWritable) {
142                UInt16 trackLast = discInfo.lastTrackNumberInLastSessionLSB;
143
144                result = reportTrackInfo(trackLast,&trackInfo);
145                if (result != kIOReturnSuccess) {
146                    break;
147                }
148
149                if (discInfo.discStatus == 0x01) { /* is disc incomplete? */
150                    _maxBlockNumber = CDConvertMSFToClippedLBA(discInfo.lastPossibleStartTimeOfLeadOut);
151                }
152
153                if (trackInfo.packet) { /* is track incremental? */
154                    _writeProtected = false;
155                    break;
156                }
157
158                if (discInfo.discStatus == 0x01) { /* is disc incomplete? */
159                    if (trackInfo.blank) { /* is track invisible? */
160                        UInt16 trackFirst = discInfo.firstTrackNumberInLastSessionLSB;
161
162                        if (trackFirst < trackLast) {
163                            result = reportTrackInfo(trackLast - 1,&trackInfo);
164                            if (result != kIOReturnSuccess) {
165                                break;
166                            }
167
168                            if (trackInfo.packet) { /* is track incremental? */
169                                _writeProtected = false;
170                                break;
171                            }
172                        }
173                    }
174                }
175            }
176
177            break;
178        }
179    }
180
181    /* Instantiate a media object and attach it to ourselves. */
182
183    result = super::acceptNewMedia();
184    if (result != kIOReturnSuccess) {
185        return(result);			/* give up now */
186    }
187
188    return(result);
189}
190
191#ifndef __LP64__
192IOReturn
193IOCDBlockStorageDriver::audioPause(bool pause)
194{
195    return(getProvider()->audioPause(pause));
196}
197
198IOReturn
199IOCDBlockStorageDriver::audioPlay(CDMSF timeStart,CDMSF timeStop)
200{
201    return(getProvider()->audioPlay(timeStart,timeStop));
202}
203
204IOReturn
205IOCDBlockStorageDriver::audioScan(CDMSF timeStart,bool reverse)
206{
207    return(getProvider()->audioScan(timeStart,reverse));
208}
209
210IOReturn
211IOCDBlockStorageDriver::audioStop()
212{
213    return(getProvider()->audioStop());
214}
215#endif /* !__LP64__ */
216
217IOReturn
218IOCDBlockStorageDriver::cacheTocInfo(void)
219{
220    IOBufferMemoryDescriptor *buffer;
221    IOReturn result;
222    CDTOC *toc;
223    UInt16 tocSize;
224
225    assert(sizeof(CDTOC) == 4);		/* (compiler/platform check) */
226    assert(sizeof(CDTOCDescriptor) == 11);		/* (compiler/platform check) */
227
228    assert(_toc == NULL);
229
230    /* Read the TOC header: */
231
232    buffer = IOBufferMemoryDescriptor::withCapacity(sizeof(CDTOC),kIODirectionIn);
233    if (buffer == NULL) {
234        return(kIOReturnNoMemory);
235    }
236
237    result = getProvider()->readTOC(buffer);
238    if (result != kIOReturnSuccess) {
239        buffer->release();
240        return(result);
241    }
242
243    toc = (CDTOC *) buffer->getBytesNoCopy();
244    tocSize = OSSwapBigToHostInt16(toc->length) + sizeof(toc->length);
245
246    buffer->release();
247
248    /* Reject the TOC if its size is too small: */
249
250    if (tocSize <= sizeof(CDTOC)) {
251        return(kIOReturnNotFound);
252    }
253
254    /* Read the TOC in full: */
255
256    buffer = IOBufferMemoryDescriptor::withCapacity(tocSize,kIODirectionIn);
257    if (buffer == NULL) {
258        return(kIOReturnNoMemory);
259    }
260
261    result = getProvider()->readTOC(buffer);
262    if (result != kIOReturnSuccess) {
263        buffer->release();
264        return(result);
265    }
266
267    toc = (CDTOC *) IOMalloc(tocSize);
268    if (toc == NULL) {
269        buffer->release();
270        return(kIOReturnNoMemory);
271    }
272
273    if (buffer->readBytes(0,toc,tocSize) != tocSize) {
274        buffer->release();
275        IOFree(toc,tocSize);
276        return(kIOReturnNoMemory);
277    }
278
279    _toc = toc;
280    _tocSize = tocSize;
281
282    buffer->release();
283
284    return(result);
285}
286
287/* Decommission all nubs. The arbitration lock is assumed to
288 * be held during the call.
289 */
290IOReturn
291IOCDBlockStorageDriver::decommissionMedia(bool forcible)
292{
293    IOReturn result;
294
295    result = super::decommissionMedia(forcible);
296
297    if (result == kIOReturnSuccess) {
298        if (_toc) {
299            IOFree(_toc,_tocSize);
300            _toc = NULL;
301            _tocSize = 0;
302        }
303
304        _minBlockNumberAudio = 0;
305        _maxBlockNumberAudio = 0;
306    }
307
308    return(result);
309}
310
311/* We should check with other clients using the other nubs before we allow
312 * the client of the IOCDMedia to eject the media.
313 */
314IOReturn
315IOCDBlockStorageDriver::ejectMedia(void)
316{
317    /* For now, we don't check with the other clients. */
318
319    return(super::ejectMedia());
320}
321
322void
323IOCDBlockStorageDriver::executeRequest(UInt64 byteStart,
324                                       IOMemoryDescriptor *buffer,
325#ifdef __LP64__
326                                       IOStorageAttributes *attributes,
327                                       IOStorageCompletion *completion,
328#else /* !__LP64__ */
329                                       IOStorageCompletion completion,
330#endif /* !__LP64__ */
331                                       IOBlockStorageDriver::Context *context)
332{
333    UInt32 block;
334    UInt32 nblks;
335    IOReturn result;
336
337    if (!_mediaObject) {		/* no media? you lose */
338        complete(completion, kIOReturnNoMedia,0);
339        return;
340    }
341
342    /* We know that we are never called with a request too large,
343     * nor one that is misaligned with a block.
344     */
345    assert((byteStart           % context->block.size) == 0);
346    assert((buffer->getLength() % context->block.size) == 0);
347
348    block = byteStart           / context->block.size;
349    nblks = buffer->getLength() / context->block.size;
350
351/* Now the protocol-specific provider implements the actual
352     * start of the data transfer: */
353
354    if (context->block.type == kBlockTypeCD) {
355        /* Some drives have firmware that performs better at audio reads when
356         * the block type is specifically set to CDDA, rather than "unknown";
357         * this is a temporary measure until all clients cut over to the CDDA
358         * based APIs; this measure should not be depended upon in the future.
359         */
360        if (context->block.typeSub[1] == kCDSectorTypeUnknown &&
361            block                     >= _minBlockNumberAudio &&
362            block + nblks - 1         <= _maxBlockNumberAudio) {
363            context->block.typeSub[1] = kCDSectorTypeCDDA;
364
365            if (context->block.typeSub[0] & 0xF8) {
366                context->block.typeSub[0] &= ~(0xF8);
367                context->block.typeSub[0] |= kCDSectorAreaUser;
368            }
369        }
370
371        if (buffer->getDirection() == kIODirectionIn) {
372            result = getProvider()->doAsyncReadCD(buffer,block,nblks,
373                                   (CDSectorArea)context->block.typeSub[0],
374                                   (CDSectorType)context->block.typeSub[1],
375#ifdef __LP64__
376                                   completion ? *completion : (IOStorageCompletion) { 0 });
377#else /* !__LP64__ */
378                                   completion);
379#endif /* !__LP64__ */
380        } else {
381            complete(completion,kIOReturnUnsupported);
382            return;
383        }
384    } else {
385#ifdef __LP64__
386        result = getProvider()->doAsyncReadWrite(buffer,block,nblks,attributes,completion);
387#else /* !__LP64__ */
388        result = getProvider()->doAsyncReadWrite(buffer,block,nblks,&context->request.attributes,&completion);
389#endif /* !__LP64__ */
390    }
391
392    if (result != kIOReturnSuccess) {		/* it failed to start */
393        complete(completion,result);
394        return;
395    }
396}
397
398void
399IOCDBlockStorageDriver::free(void)
400{
401    if (_expansionData) {
402        IODelete(_expansionData, ExpansionData, 1);
403    }
404
405    super::free();
406}
407
408#ifndef __LP64__
409IOReturn
410IOCDBlockStorageDriver::getAudioStatus(CDAudioStatus *status)
411{
412    return(getProvider()->getAudioStatus(status));
413}
414
415IOReturn
416IOCDBlockStorageDriver::getAudioVolume(UInt8 *leftVolume,UInt8 *rightVolume)
417{
418    return(getProvider()->getAudioVolume(leftVolume,rightVolume));
419}
420#endif /* !__LP64__ */
421
422const char *
423IOCDBlockStorageDriver::getDeviceTypeName(void)
424{
425    return(kIOBlockStorageDeviceTypeCDROM);
426}
427
428UInt64
429IOCDBlockStorageDriver::getMediaBlockSize(CDSectorArea area,CDSectorType type)
430{
431    UInt64 blockSize = 0;
432
433    const SInt16 areaSize[kCDSectorTypeCount][8] =
434    {                  /* 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 */
435       /* Unknown    */ {   96,  294,   16,  280, 2048,    4,    8,   12 },
436       /* CDDA       */ {   96,  294,   16,    0, 2352,    0,    0,    0 },
437       /* Mode1      */ {   96,  294,   16,  288, 2048,    4,    0,   12 },
438       /* Mode2      */ {   96,  294,   16,    0, 2336,    4,    0,   12 },
439       /* Mode2Form1 */ {   96,  294,   16,  280, 2048,    4,    8,   12 },
440       /* Mode2Form2 */ {   96,  294,   16,    0, 2328,    4,    8,   12 },
441    };
442
443    if ( type >= kCDSectorTypeCount )  return 0;
444
445    for ( UInt32 index = 0; index < 8; index++ )
446    {
447        if ( ((area >> index) & 0x01) )
448        {
449            if ( areaSize[type][index] == -1 )  return 0;
450            blockSize += areaSize[type][index];
451        }
452    }
453
454    return blockSize;
455}
456
457UInt32
458IOCDBlockStorageDriver::getMediaType(void)
459{
460    return(_mediaType);
461}
462
463CDTOC *
464IOCDBlockStorageDriver::getTOC(void)
465{
466    return(_toc);
467}
468
469bool
470IOCDBlockStorageDriver::init(OSDictionary * properties)
471{
472    if (super::init(properties) == false) {
473        return false;
474    }
475
476    _expansionData = IONew(ExpansionData, 1);
477
478    if (_expansionData == NULL) {
479        return false;
480    }
481
482    _minBlockNumberAudio = 0;
483    _maxBlockNumberAudio = 0;
484#ifndef __LP64__
485    _maxReadByteTransfer = 196608;
486    _maxWriteByteTransfer = 196608;
487#endif /* !__LP64__ */
488    _toc = NULL;
489    _tocSize = 0;
490
491    return(true);
492}
493
494IOMedia *
495IOCDBlockStorageDriver::instantiateDesiredMediaObject(void)
496{
497    return(new IOCDMedia);
498}
499
500IOMedia *
501IOCDBlockStorageDriver::instantiateMediaObject(UInt64 base,UInt64 byteSize,
502                                        UInt32 blockSize,char *mediaName)
503{
504    IOMedia *media;
505
506    if (blockSize) {
507        byteSize /= blockSize;
508        byteSize *= kBlockSizeCD;
509        blockSize = kBlockSizeCD;
510    }
511
512    media = super::instantiateMediaObject(base,byteSize,blockSize,mediaName);
513
514    if (media) {
515        const char *description = NULL;
516        const char *picture = NULL;
517
518        switch (getMediaType()) {
519            case kCDMediaTypeROM:
520                description = kIOCDMediaTypeROM;
521                picture = "CD.icns";
522                break;
523            case kCDMediaTypeR:
524                description = kIOCDMediaTypeR;
525                picture = "CD-R.icns";
526                break;
527            case kCDMediaTypeRW:
528                description = kIOCDMediaTypeRW;
529                picture = "CD-RW.icns";
530                break;
531        }
532
533        if (description) {
534            media->setProperty(kIOCDMediaTypeKey, description);
535        }
536
537        if (picture) {
538            OSDictionary *dictionary = OSDictionary::withCapacity(2);
539            OSString *identifier = OSString::withCString("com.apple.iokit.IOCDStorageFamily");
540            OSString *resourceFile = OSString::withCString(picture);
541
542            if (dictionary && identifier && resourceFile) {
543                dictionary->setObject("CFBundleIdentifier", identifier);
544                dictionary->setObject("IOBundleResourceFile", resourceFile);
545            }
546
547            media->setProperty(kIOMediaIconKey, dictionary);
548
549            if (resourceFile) {
550                resourceFile->release();
551            }
552            if (identifier) {
553                identifier->release();
554            }
555            if (dictionary) {
556                dictionary->release();
557            }
558        }
559
560        if (_toc) {
561            media->setProperty(kIOCDMediaTOCKey,(void*)_toc,_tocSize);
562        }
563    }
564
565    return media;
566}
567
568void
569IOCDBlockStorageDriver::readCD(IOService *client,
570                               UInt64 byteStart,
571                               IOMemoryDescriptor *buffer,
572                               CDSectorArea sectorArea,
573                               CDSectorType sectorType,
574#ifdef __LP64__
575                               IOStorageAttributes *attributes,
576                               IOStorageCompletion *completion)
577#else /* !__LP64__ */
578                               IOStorageCompletion completion)
579#endif /* !__LP64__ */
580{
581    assert(buffer->getDirection() == kIODirectionIn);
582
583#ifdef __LP64__
584    prepareRequest(byteStart, buffer, sectorArea, sectorType, attributes, completion);
585#else /* !__LP64__ */
586    prepareRequest(byteStart, buffer, sectorArea, sectorType, completion);
587#endif /* !__LP64__ */
588}
589
590IOReturn
591IOCDBlockStorageDriver::reportDiscInfo(CDDiscInfo *discInfo)
592{
593    IOMemoryDescriptor *buffer;
594    IOReturn result;
595    UInt16 discInfoSize;
596
597    bzero(discInfo,sizeof(CDDiscInfo));
598
599    /* Read the Disc Information in full: */
600
601    buffer = IOMemoryDescriptor::withAddress(discInfo,sizeof(CDDiscInfo),kIODirectionIn);
602    if (buffer == NULL) {
603        return(kIOReturnNoMemory);
604    }
605
606    result = getProvider()->readDiscInfo(buffer,&discInfoSize);
607    if (result != kIOReturnSuccess) {
608        buffer->release();
609        return(result);
610    }
611
612    buffer->release();
613
614    /* Reject the Disc Information if its size is too small: */
615
616    if (discInfoSize < sizeof(CDDiscInfo)) {
617        return(kIOReturnNotFound);
618    }
619
620    discInfoSize = OSSwapBigToHostInt16(discInfo->dataLength) + sizeof(discInfo->dataLength);
621
622    if (discInfoSize < sizeof(CDDiscInfo)) {
623        return(kIOReturnNotFound);
624    }
625
626    return(result);
627}
628
629IOReturn
630IOCDBlockStorageDriver::reportTrackInfo(UInt16 track,CDTrackInfo *trackInfo)
631{
632    IOMemoryDescriptor *buffer;
633    IOReturn result;
634    UInt16 trackInfoSize;
635
636    bzero(trackInfo,sizeof(CDTrackInfo));
637
638    /* Read the Track Information in full: */
639
640    buffer = IOMemoryDescriptor::withAddress(trackInfo,sizeof(CDTrackInfo),kIODirectionIn);
641    if (buffer == NULL) {
642        return(kIOReturnNoMemory);
643    }
644
645    result = getProvider()->readTrackInfo(buffer,track,kCDTrackInfoAddressTypeTrackNumber,&trackInfoSize);
646    if (result != kIOReturnSuccess) {
647        buffer->release();
648        return(result);
649    }
650
651    buffer->release();
652
653    /* Reject the Track Information if its size is too small: */
654
655    if (trackInfoSize < offsetof(CDTrackInfo, lastRecordedAddress)) {
656        return(kIOReturnNotFound);
657    }
658
659    trackInfoSize = OSSwapBigToHostInt16(trackInfo->dataLength) + sizeof(trackInfo->dataLength);
660
661    if (trackInfoSize < offsetof(CDTrackInfo, lastRecordedAddress)) {
662        return(kIOReturnNotFound);
663    }
664
665    return(result);
666}
667
668void
669IOCDBlockStorageDriver::prepareRequest(UInt64 byteStart,
670                                       IOMemoryDescriptor *buffer,
671                                       CDSectorArea sectorArea,
672                                       CDSectorType sectorType,
673#ifdef __LP64__
674                                       IOStorageAttributes *attributes,
675                                       IOStorageCompletion *completion)
676#else /* !__LP64__ */
677                                       IOStorageCompletion completion)
678#endif /* !__LP64__ */
679{
680    IOStorageCompletion completionOut;
681    Context *           context;
682
683    // Determine whether an undefined sector area was specified.
684
685    if ((sectorArea & 0xFF) == 0x00 || (sectorArea & 0x05) == 0x05)
686    {
687        complete(completion, kIOReturnBadArgument);
688        return;
689    }
690
691    // Determine whether an undefined sector type was specified.
692
693    if (sectorType >= kCDSectorTypeCount)
694    {
695        complete(completion, kIOReturnBadArgument);
696        return;
697    }
698
699    // For a transfer that involves an unknown sector type, the sector area must
700    // not describe a vague sector size (and hence, a vague transfer size).  The
701    // SYNC, HEADER, SUBHEADER, USER and AUXILIARY sector areas differ in length
702    // from one sector type to the next.  All together, however, the same sector
703    // areas describe a consistent sector size from one sector type to the next,
704    // hence we permit either all the above sector areas to be specified at once
705    // or none to be specified at all.  The other sector areas are consistent in
706    // size from one sector type to the next, hence need not be considered here.
707
708    if (sectorType == kCDSectorTypeUnknown)
709    {
710        if ((sectorArea & 0xF8) != 0x00 && (sectorArea & 0xF8) != 0xF8)
711        {
712            complete(completion, kIOReturnBadArgument);
713            return;
714        }
715    }
716
717    // Allocate a context structure to hold some of our state.
718
719    context = allocateContext();
720
721    if (context == 0)
722    {
723        complete(completion, kIOReturnNoMemory);
724        return;
725    }
726
727    // Fill in the context structure with some of our state.
728
729    if ( ( sectorArea == kCDSectorAreaUser       )  &&
730         ( sectorType == kCDSectorTypeMode1      ||
731           sectorType == kCDSectorTypeMode2Form1 )  )
732    {
733        context->block.size       = getMediaBlockSize();
734        context->block.type       = kBlockTypeStandard;
735    }
736    else
737    {
738        context->block.size       = getMediaBlockSize(sectorArea, sectorType);
739        context->block.type       = kBlockTypeCD;
740        context->block.typeSub[0] = sectorArea;
741        context->block.typeSub[1] = sectorType;
742    }
743
744    context->original.byteStart  = byteStart;
745    context->original.buffer     = buffer;
746    context->original.buffer->retain();
747
748#ifdef __LP64__
749    if (attributes)  context->request.attributes = *attributes;
750    if (completion)  context->request.completion = *completion;
751#else /* !__LP64__ */
752    context->original.completion = completion;
753#endif /* !__LP64__ */
754
755    clock_get_uptime(&context->timeStart);
756
757    completionOut.target    = this;
758    completionOut.action    = prepareRequestCompletion;
759    completionOut.parameter = context;
760
761    // Deblock the transfer.
762
763#ifdef __LP64__
764    deblockRequest(byteStart, buffer, attributes, &completionOut, context);
765#else /* !__LP64__ */
766    deblockRequest(byteStart, buffer, completionOut, context);
767#endif /* !__LP64__ */
768}
769
770IOReturn
771IOCDBlockStorageDriver::readISRC(UInt8 track,CDISRC isrc)
772{
773    return(getProvider()->readISRC(track,isrc));
774}
775
776IOReturn
777IOCDBlockStorageDriver::readMCN(CDMCN mcn)
778{
779    return(getProvider()->readMCN(mcn));
780}
781
782IOReturn
783IOCDBlockStorageDriver::recordMediaParameters(void)
784{
785    IOReturn result;
786
787    result = super::recordMediaParameters();
788    if (result != kIOReturnSuccess) {
789        return(result);
790    }
791
792    _mediaType = getProvider()->getMediaType();
793
794    return(kIOReturnSuccess);
795}
796
797#ifndef __LP64__
798IOReturn
799IOCDBlockStorageDriver::setAudioVolume(UInt8 leftVolume,UInt8 rightVolume)
800{
801    return(getProvider()->setAudioVolume(leftVolume,rightVolume));
802}
803#endif /* !__LP64__ */
804
805IOReturn
806IOCDBlockStorageDriver::getSpeed(UInt16 * kilobytesPerSecond)
807{
808    return(getProvider()->getSpeed(kilobytesPerSecond));
809}
810
811IOReturn
812IOCDBlockStorageDriver::setSpeed(UInt16 kilobytesPerSecond)
813{
814    return(getProvider()->setSpeed(kilobytesPerSecond));
815}
816
817IOReturn
818IOCDBlockStorageDriver::readTOC(IOMemoryDescriptor *buffer,CDTOCFormat format,
819                                UInt8 formatAsTime,UInt8 trackOrSessionNumber,
820                                UInt16 *actualByteCount)
821{
822    return(getProvider()->readTOC(buffer,format,formatAsTime,trackOrSessionNumber,actualByteCount));
823}
824
825IOReturn
826IOCDBlockStorageDriver::readDiscInfo(IOMemoryDescriptor *buffer,
827                                     UInt16 *actualByteCount)
828{
829    return(getProvider()->readDiscInfo(buffer,actualByteCount));
830}
831
832IOReturn
833IOCDBlockStorageDriver::readTrackInfo(IOMemoryDescriptor *buffer,UInt32 address,
834                                      CDTrackInfoAddressType addressType,
835                                      UInt16 *actualByteCount)
836{
837    return(getProvider()->readTrackInfo(buffer,address,addressType,actualByteCount));
838}
839
840void
841IOCDBlockStorageDriver::writeCD(IOService *client,
842                                UInt64 byteStart,
843                                IOMemoryDescriptor *buffer,
844                                CDSectorArea sectorArea,
845                                CDSectorType sectorType,
846#ifdef __LP64__
847                                IOStorageAttributes *attributes,
848                                IOStorageCompletion *completion)
849#else /* !__LP64__ */
850                                IOStorageCompletion completion)
851#endif /* !__LP64__ */
852{
853    assert(buffer->getDirection() == kIODirectionOut);
854
855#ifdef __LP64__
856    prepareRequest(byteStart, buffer, sectorArea, sectorType, attributes, completion);
857#else /* !__LP64__ */
858    prepareRequest(byteStart, buffer, sectorArea, sectorType, completion);
859#endif /* !__LP64__ */
860}
861
862#ifdef __LP64__
863OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver,  0);
864OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver,  1);
865OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver,  2);
866OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver,  3);
867OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver,  4);
868OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver,  5);
869#else /* !__LP64__ */
870OSMetaClassDefineReservedUsed(IOCDBlockStorageDriver,  0);
871OSMetaClassDefineReservedUsed(IOCDBlockStorageDriver,  1);
872OSMetaClassDefineReservedUsed(IOCDBlockStorageDriver,  2);
873OSMetaClassDefineReservedUsed(IOCDBlockStorageDriver,  3);
874OSMetaClassDefineReservedUsed(IOCDBlockStorageDriver,  4);
875OSMetaClassDefineReservedUsed(IOCDBlockStorageDriver,  5);
876#endif /* !__LP64__ */
877OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver,  6);
878OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver,  7);
879OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver,  8);
880OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver,  9);
881OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver, 10);
882OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver, 11);
883OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver, 12);
884OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver, 13);
885OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver, 14);
886OSMetaClassDefineReservedUnused(IOCDBlockStorageDriver, 15);
887