2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
22 // =============================================================================
23 // Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
27 #include <IOKit/IOLib.h>
28 #include <IOKit/IOReturn.h>
29 #include <IOKit/IOMemoryDescriptor.h>
30 #include <IOKit/scsi/IOSCSIDeviceInterface.h>
31 #include <IOKit/storage/scsi/IOSCSIDVDDrive.h>
32 #include <IOKit/storage/scsi/IOSCSIDVDDriveNub.h>
33 #include <IOKit/storage/IODVDTypes.h>
34 #include <libkern/OSByteOrder.h>
36 #define super IOSCSICDDrive
37 OSDefineMetaClassAndStructors(IOSCSIDVDDrive
,IOSCSICDDrive
)
40 const int kFeatureProfileList
= 0x0000;
41 const int kFeatureCore
= 0x0001;
42 const int kFeatureMorphing
= 0x0002;
43 const int kFeatureRemovableMedium
= 0x0003;
44 const int kFeatureRandomReadable
= 0x0010;
45 const int kFeatureMultiRead
= 0x001d;
46 const int kFeatureCDRead
= 0x001e;
47 const int kFeatureDVDRead
= 0x001f;
48 const int kFeatureRandomWrite
= 0x0020;
49 const int kFeatureIncrStreamWrite
= 0x0021;
50 const int kFeatureSectorErasable
= 0x0022;
51 const int kFeatureFormattable
= 0x0023;
52 const int kFeatureDefectManagement
= 0x0024;
53 const int kFeatureWriteOnce
= 0x0025;
54 const int kFeatureRestrictedOverwrite
= 0x0026;
55 const int kFeatureDVDRWRestrictedOverwrite
= 0x002c;
56 const int kFeatureCDTrackAtOnce
= 0x002d;
57 const int kFeatureCDMastering
= 0x002e;
58 const int kFeatureDVDR_RWWrite
= 0x002f;
59 const int kFeaturePowerManagement
= 0x0100;
60 const int kFeatureSMART
= 0x0101;
61 const int kFeatureEmbeddedChanger
= 0x0102;
62 const int kFeatureCDAudioAnalogPlay
= 0x0103;
63 const int kFeatureMicrocodeUpgrade
= 0x0104;
64 const int kFeatureTimeout
= 0x0105;
65 const int kFeatureDVDCSS
= 0x0106;
66 const int kFeatureRealTimeStreaming
= 0x0107;
67 const int kFeatureLUNSerialNumber
= 0x0108;
68 const int kFeatureDiskControlBlocks
= 0x010a;
69 const int kFeatureDVDCPRM
= 0x010b;
72 IOSCSIDVDDrive::checkConfig(UInt8
*buf
,UInt32 actual
)
77 UInt16 currentProfile
;
79 struct featureDescriptor
{
82 UInt8 additionalLength
;
86 struct featureHdr
*fh
;
87 struct featureDescriptor
*fdp
;
89 fh
= (struct featureHdr
*)buf
;
90 len
= OSSwapBigToHostInt32(fh
->totalLen
);
92 fdp
= (struct featureDescriptor
*)(&buf
[8]);
96 switch (OSSwapBigToHostInt16(fdp
->featureCode
)) {
98 case kFeatureDVDRead
:
101 case kFeatureDVDCSS
:
105 fdp
= (struct featureDescriptor
*)((char *)fdp
+
106 sizeof(struct featureDescriptor
) +
107 fdp
->additionalLength
);
108 } while ((UInt8
*)fdp
< &buf
[len
]);
112 IOSCSIDVDDrive::determineMediaType(void)
117 UInt16 currentProfile
;
119 struct featureDescriptor
{
122 UInt8 additionalLength
;
126 struct featureHdr
*fh
;
127 struct featureDescriptor
*fdp
;
130 UInt8 configBuf
[kMaxConfigLength
];
132 /* Get the *current* configuration information, relating to the media. */
134 result
= getConfiguration(configBuf
,kMaxConfigLength
,&configSize
,true);
135 if (result
!= kIOReturnSuccess
) {
136 IOLog("%s[IOSCSIDVDDrive]::determineMediaType; result = '%s'\n",
137 getName(),stringFromReturn(result
));
141 fh
= (struct featureHdr
*)configBuf
;
142 len
= OSSwapBigToHostInt32(fh
->totalLen
);
144 fdp
= (struct featureDescriptor
*)(&configBuf
[8]);
146 _mediaType
= kDVDMediaTypeUnknown
; /* assume there is no media inserted */
150 switch (OSSwapBigToHostInt16(fdp
->featureCode
)) {
152 case kFeatureCDRead
:
153 _mediaType
= kCDMediaTypeROM
;
154 IOLog("%s[IOSCSIDVDDrive]::determineMediaType; media is %s.\n",getName(),"CD");
156 case kFeatureDVDRead
:
157 _mediaType
= kDVDMediaTypeROM
;
158 IOLog("%s[IOSCSIDVDDrive]::determineMediaType; media is %s.\n",getName(),"DVDROM");
160 case kFeatureFormattable
:
161 _mediaType
= kDVDMediaTypeRAM
;
162 IOLog("%s[IOSCSIDVDDrive]::determineMediaType; media is %s.\n",getName(),"DVDRam");
164 case kFeatureRandomWrite
:
165 _isWriteProtected
= false;
166 IOLog("%s[IOSCSIDVDDrive]::determineMediaType; write-enabled.\n",getName());
169 fdp
= (struct featureDescriptor
*)((char *)fdp
+
170 sizeof(struct featureDescriptor
) +
171 fdp
->additionalLength
);
172 } while ((UInt8
*)fdp
< &configBuf
[len
]);
174 if (_mediaType
== kDVDMediaTypeUnknown
) {
175 IOLog("%s[IOSCSIDVDDrive]::determineMediaType; drive is empty.\n",getName());
178 return(kIOReturnSuccess
);
182 IOSCSIDVDDrive::deviceTypeMatches(UInt8 inqBuf
[],UInt32 inqLen
,SInt32
*score
)
187 type
= inqBuf
[0] & 0x1f;
189 if (type
== kIOSCSIDeviceTypeCDROM
) {
190 // IOLog("%s[IOSCSIDVDDrive]::deviceTypeMatches; device type %d is CD/DVD\n",getName(),type);
192 /* Try to get the device configuration. If we can, then it must be a DVD
193 * drive since it follows the MtFuji command set (so far). If we cannot
194 * get the configuration, then the device must be a plain CDROM drive.
196 result
= getConfiguration(_configBuf
,kMaxConfigLength
,&_configSize
,false);
197 if (result
== kIOReturnSuccess
) {
198 // IOLog("%s[IOSCSIDVDDrive]::deviceTypeMatches getConfig OK; returning true\n",getName());
199 checkConfig(_configBuf
,_configSize
);
201 // IOLog("---isDVDDrive\n");
202 *score
= 16; /* override any CD driver match */
204 } else { /* not DVD */
208 // IOLog("%s[IOSCSIDVDDrive]::deviceTypeMatches getConfig fail; returning false\n",getName());
213 IOLog("%s[IOSCSIDVDDrive]::deviceTypeMatches; device type %d not CD/DVD, returning FALSE\n",
216 return(false); /* we don't handle other devices */
221 IOSCSIDVDDrive::doAsyncReadWrite(IOMemoryDescriptor
*buffer
,
222 UInt32 block
,UInt32 nblks
,
223 IOStorageCompletion completion
)
225 return(standardAsyncReadWrite(buffer
,block
,nblks
,completion
));
229 IOSCSIDVDDrive::doFormatMedia(UInt64 byteCapacity
)
231 return(standardFormatMedia(byteCapacity
));
235 IOSCSIDVDDrive::doGetFormatCapacities(UInt64
*capacities
,UInt32 capacitiesMaxCount
) const
237 if (capacitiesMaxCount
> 0) {
238 *capacities
= (UInt64
)((UInt64
)2600 * (UInt64
)1048576); /* DVD-RAM V1.0 is 2.6GB */
246 IOSCSIDVDDrive::doSynchronizeCache(void)
248 return(standardSynchronizeCache());
252 IOSCSIDVDDrive::doSyncReadWrite(IOMemoryDescriptor
*buffer
,UInt32 block
,UInt32 nblks
)
254 return(standardSyncReadWrite(buffer
,block
,nblks
));
258 IOSCSIDVDDrive::getConfiguration(UInt8
*buffer
,UInt32 length
,UInt32
*actualLength
,bool current
)
264 SCSIResults scsiResults
;
267 cx
= allocateContext();
269 return(kIOReturnNoMemory
);
274 bzero( &scsiCDB
, sizeof(scsiCDB
) );
276 bzero(buffer
,length
);
278 c
= (struct IOGCCdb
*)(scsiCDB
.cdb
);
280 c
->opcode
= kIOSCSICommandGetConfiguration
;
282 if (current
) { /* only get current features */
285 c
->startFeature_lo
= 0;
286 c
->startFeature_hi
= 0;
287 c
->len_hi
= length
>> 8;
288 c
->len_lo
= length
& 0xff;
291 scsiCDB
.cdbLength
= 10;
292 req
->setCDB( &scsiCDB
);
294 cx
->memory
= IOMemoryDescriptor::withAddress((void *)buffer
,
297 req
->setPointers( cx
->memory
, length
, false );
298 req
->setPointers( cx
->senseDataDesc
, 255, false, true );
299 req
->setTimeout( 5000 );
301 queueCommand(cx
,kSync
,getGetConfigurationPowerState());
302 result
= simpleSynchIO(cx
);
304 req
->getResults(&scsiResults
);
305 if (result
== kIOReturnUnderrun
) {
306 result
= kIOReturnSuccess
;
308 *actualLength
= scsiResults
.bytesTransferred
;
316 IOSCSIDVDDrive::getDeviceTypeName(void)
318 return(kIOBlockStorageDeviceTypeDVD
);
322 IOSCSIDVDDrive::getGetConfigurationPowerState(void)
324 return(kElectronicsOn
);
328 IOSCSIDVDDrive::getReportKeyPowerState(void)
330 return(kElectronicsOn
);
334 IOSCSIDVDDrive::getSendKeyPowerState(void)
336 return(kElectronicsOn
);
340 IOSCSIDVDDrive::getMediaType(void)
346 IOSCSIDVDDrive::init(OSDictionary
* properties
)
351 _mediaType
= kDVDMediaTypeUnknown
;
352 _isWriteProtected
= true;
354 return(super::init(properties
));
358 IOSCSIDVDDrive::instantiateNub(void)
362 /* Instantiate a generic DVD nub so a generic driver can match above us. */
364 nub
= new IOSCSIDVDDriveNub
;
369 IOSCSIDVDDrive::reportKey(IOMemoryDescriptor
*buffer
,const DVDKeyClass keyClass
,
370 const UInt32 lba
,const UInt8 agid
,const DVDKeyFormat keyFormat
)
378 cx
= allocateContext();
380 return(kIOReturnNoMemory
);
385 bzero( &scsiCDB
, sizeof(scsiCDB
) );
387 c
= (struct IORKCdb
*)(scsiCDB
.cdb
);
389 c
->opcode
= kIOSCSICommandReportKey
;
390 if (keyFormat
== kTitleKey
) {
391 c
->lba_0
= lba
>> 24;
392 c
->lba_1
= lba
>> 16;
394 c
->lba_3
= lba
& 0xff;
396 c
->keyClass
= keyClass
;
397 c
->len_hi
= buffer
->getLength() >> 8;
398 c
->len_lo
= buffer
->getLength() & 0xff;
399 c
->agidKeyFormat
= agid
<< 6 | keyFormat
;
402 scsiCDB
.cdbLength
= 10;
403 req
->setCDB( &scsiCDB
);
407 req
->setPointers( cx
->memory
, cx
->memory
->getLength(), false );
408 req
->setPointers( cx
->senseDataDesc
, 255, false, true );
409 req
->setTimeout( 5000 );
411 queueCommand(cx
,kSync
,getReportKeyPowerState());
412 result
= simpleSynchIO(cx
);
420 IOSCSIDVDDrive::reportMediaState(bool *mediaPresent
,bool *changed
)
424 /* Let the superclass check for media in the standard way: */
426 result
= super::reportMediaState(mediaPresent
,changed
);
428 if (result
!= kIOReturnSuccess
) {
429 IOLog("%s[IOSCSIDVDDrive]:: reportMediaState; result = '%s' from super\n",
430 getName(),stringFromReturn(result
));
434 /* If we have newly-inserted media, determine its type: */
436 if (*mediaPresent
&& *changed
) {
437 result
= determineMediaType();
444 IOSCSIDVDDrive::reportWriteProtection(bool *isWriteProtected
)
446 *isWriteProtected
= _isWriteProtected
;
447 return(kIOReturnSuccess
);
451 IOSCSIDVDDrive::sendKey(IOMemoryDescriptor
*buffer
,const DVDKeyClass keyClass
,
452 const UInt8 agid
,const DVDKeyFormat keyFormat
)
460 cx
= allocateContext();
462 return(kIOReturnNoMemory
);
467 bzero( &scsiCDB
, sizeof(scsiCDB
) );
469 c
= (struct IOSKCdb
*)(scsiCDB
.cdb
);
471 c
->opcode
= kIOSCSICommandSendKey
;
472 c
->keyClass
= keyClass
;
473 c
->len_hi
= buffer
->getLength() >> 8;
474 c
->len_lo
= buffer
->getLength() & 0xff;
475 c
->agidKeyFormat
= agid
<< 6 | keyFormat
;
478 scsiCDB
.cdbLength
= 10;
479 req
->setCDB( &scsiCDB
);
483 req
->setPointers( cx
->memory
, cx
->memory
->getLength(), false );
484 req
->setPointers( cx
->senseDataDesc
, 255, false, true );
485 req
->setTimeout( 5000 );
487 queueCommand(cx
,kSync
,getSendKeyPowerState());
488 result
= simpleSynchIO(cx
);