2 * Copyright (c) 1998-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@
23 #include <IOKit/assert.h>
24 #include <IOKit/IOBufferMemoryDescriptor.h>
25 #include <IOKit/storage/ata/IOATAPIDVDDrive.h>
26 #include <IOKit/storage/ata/IOATAPIDVDDriveNub.h>
27 #include <IOKit/storage/IODVDTypes.h>
28 #include <libkern/OSByteOrder.h>
30 // Define this to log debug messages.
32 // #define LOG_DVD_MESSAGES 1
34 #ifdef LOG_DVD_MESSAGES
35 #define DEBUG_LOG(fmt, args...) IOLog(fmt, ## args)
37 #define DEBUG_LOG(fmt, args...)
40 #define super IOATAPICDDrive
41 OSDefineMetaClassAndStructors( IOATAPIDVDDrive
, IOATAPICDDrive
)
43 //---------------------------------------------------------------------------
44 // Feature header and descriptor definition.
49 UInt16 currentProfile
;
52 struct featureDescriptor
{
55 UInt8 additionalLength
;
58 #define kConfigBufferSize 2048
59 #define kConfigFeatureHeaderBytes sizeof(struct featureHdr)
60 #define kConfigDataLengthBytes sizeof(UInt32)
61 #define kConfigMinDataLength (sizeof(struct featureHdr) - \
62 kConfigDataLengthBytes + \
63 sizeof(struct featureDescriptor))
65 //---------------------------------------------------------------------------
66 // Classify an ATAPI CD-ROM drive as a CD or a DVD drive.
68 IOReturn
IOATAPIDVDDrive::classifyDrive(bool * isDVDDrive
)
70 IOATACommand
* cmd
= 0;
71 IOBufferMemoryDescriptor
* copyrightDesc
;
72 IOBufferMemoryDescriptor
* senseDesc
;
73 IOReturn ret
= kIOReturnSuccess
;
76 // Buffer descriptor to hold Copyright Information.
78 copyrightDesc
= IOBufferMemoryDescriptor::withCapacity(8,
81 // Buffer descriptor to hold sense data.
83 senseDesc
= IOBufferMemoryDescriptor::withCapacity(
87 if ( (copyrightDesc
== 0) || (senseDesc
== 0) )
89 ret
= kIOReturnNoMemory
;
93 bzero(senseDesc
->getBytesNoCopy(), senseDesc
->getCapacity());
95 // READ DVD STRUCTURE command - DVD Copyright Information
97 cmd
= atapiCommandReadDVDStructure(copyrightDesc
,
98 kIODVDReadStructureCopyright
);
101 ret
= kIOReturnNoMemory
;
105 // Execute the command, and get sense data.
107 ret
= syncExecute(cmd
,
112 // By default, consider it a DVD drive, unless the drive
113 // returns an error, and the sense data contains,
121 if (ret
!= kIOReturnSuccess
)
123 ATASenseData
* senseData
;
125 senseData
= (ATASenseData
*) senseDesc
->getBytesNoCopy();
127 if ((senseData
->errorCode
== kATAPISenseCurrentErr
) ||
128 (senseData
->errorCode
== kATAPISenseDeferredErr
))
130 if ((senseData
->senseKey
== kATAPISenseIllegalReq
) &&
131 (senseData
->additionalSenseCode
== 0x20) &&
132 (senseData
->additionalSenseQualifier
== 0x0))
138 ret
= kIOReturnSuccess
;
143 if (senseDesc
) senseDesc
->release();
144 if (copyrightDesc
) copyrightDesc
->release();
145 if (cmd
) cmd
->release();
150 //---------------------------------------------------------------------------
151 // Determine the media type (book type) in the DVD drive.
154 IOATAPIDVDDrive::determineMediaType(UInt32
* mediaType
)
156 IOATACommand
* cmd
= 0;
157 IOBufferMemoryDescriptor
* dataDesc
;
158 IODVDStructurePhysical
* data
;
159 IOReturn ret
= kIOReturnSuccess
;
161 *mediaType
= kDVDMediaTypeUnknown
;
164 // Buffer descriptor to hold Physical Format Information.
166 dataDesc
= IOBufferMemoryDescriptor::withCapacity(sizeof(*data
),
171 ret
= kIOReturnNoMemory
;
175 data
= (IODVDStructurePhysical
*) dataDesc
->getBytesNoCopy();
176 bzero(data
, sizeof(data
->length
));
178 // READ DVD STRUCTURE command - Physical Format Information
180 cmd
= atapiCommandReadDVDStructure(dataDesc
,
181 kIODVDReadStructurePhysical
);
184 ret
= kIOReturnNoMemory
;
188 // Execute the command.
190 if ( syncExecute(cmd
) != kIOReturnSuccess
)
192 *mediaType
= kCDMediaTypeROM
; // Assume its a CD.
194 else if ( IODVDGetDataLength16(data
->length
) <
195 (sizeof(*data
) - sizeof(data
->length
)) )
197 ret
= kIOReturnUnderrun
;
201 DEBUG_LOG("%s: DVD Book Type: %x Part Version: %x\n",
202 getName(), data
->bookType
, data
->partVersion
);
204 switch (data
->bookType
)
207 case kIODVDBookTypeDVDROM
:
208 case kIODVDBookTypeDVDR
:
209 case kIODVDBookTypeDVDRW
:
210 case kIODVDBookTypeDVDPlusRW
:
211 *mediaType
= kDVDMediaTypeROM
;
214 case kIODVDBookTypeDVDRAM
:
215 *mediaType
= kDVDMediaTypeRAM
;
222 if (dataDesc
) dataDesc
->release();
223 if (cmd
) cmd
->release();
228 //---------------------------------------------------------------------------
229 // Perform active matching with an ATAPI device nub published by the
230 // ATA controller driver.
233 IOATAPIDVDDrive::matchATAPIDeviceType(UInt8 type
, SInt32
* score
)
239 // If the device type reported by INQUIRY data is not a CD-ROM type,
240 // then give up immediately.
242 if ( type
!= kIOATAPIDeviceTypeCDROM
)
245 // Select timing protocol before performing I/O.
247 if ( selectTimingProtocol() == false )
250 // Is this unit a DVD drive?
252 if ( classifyDrive(&isDVDDrive
) != kIOReturnSuccess
)
257 // Indicate a strong affinity for the DVD drive by setting
258 // a higher probe score when a DVD drive is detected.
260 DEBUG_LOG("%s::%s DVD drive detected\n", getName(), __FUNCTION__
);
267 DEBUG_LOG("%s::%s Not a DVD drive\n", getName(), __FUNCTION__
);
275 //---------------------------------------------------------------------------
276 // GET CONFIGURATION command.
279 IOATAPIDVDDrive::getConfiguration(UInt8
* buf
,
281 UInt32
* actualLength
,
284 IOMemoryDescriptor
* bufDesc
= 0;
285 IOATACommand
* cmd
= 0;
286 IOReturn ret
= kIOReturnNoMemory
;
290 bufDesc
= IOMemoryDescriptor::withAddress(buf
, length
, kIODirectionIn
);
294 cmd
= atapiCommandGetConfiguration(bufDesc
, 0x01);
298 ret
= syncExecute(cmd
);
300 cmd
->getResults(&results
);
301 *actualLength
= results
.bytesTransferred
;
305 if (cmd
) cmd
->release();
306 if (bufDesc
) bufDesc
->release();
311 //---------------------------------------------------------------------------
315 IOATAPIDVDDrive::getDeviceTypeName()
317 return kIOBlockStorageDeviceTypeDVD
;
320 //---------------------------------------------------------------------------
321 // Report the type of media in the DVD drive.
324 IOATAPIDVDDrive::getMediaType()
328 determineMediaType(&mediaType
);
333 //---------------------------------------------------------------------------
334 // Initialize the IOATAPIDVDDrive object.
337 IOATAPIDVDDrive::init(OSDictionary
* properties
)
339 return super::init(properties
);
342 //---------------------------------------------------------------------------
343 // Instantiate an IOATAPIDVDDriveNub nub.
346 IOATAPIDVDDrive::instantiateNub(void)
348 IOService
* nub
= new IOATAPIDVDDriveNub
;
350 /* Instantiate a generic DVD nub so a generic driver can match above us. */
355 //---------------------------------------------------------------------------
356 // Report the media state.
359 IOATAPIDVDDrive::reportMediaState(bool * mediaPresent
, bool * changed
)
363 // Let superclass check for media in a generic fashion.
365 result
= super::reportMediaState(mediaPresent
, changed
);
367 #if 0 // For testing only
369 if (result
!= kIOReturnSuccess
)
374 // For a new media, determine its type.
376 if (*mediaPresent
&& *changed
)
385 //---------------------------------------------------------------------------
386 // Report random write support.
389 IOATAPIDVDDrive::reportWriteProtection(bool * isWriteProtected
)
392 struct featureHdr
* fh
;
393 struct featureDescriptor
* fdp
;
396 UInt32 configBufSize
; /* not used */
398 *isWriteProtected
= true;
400 /* Allocate memory for the configuration data.
401 Theoretically, this can be up to 65534 bytes. */
403 configBuf
= (UInt8
*) IOMalloc(kConfigBufferSize
);
404 if ( configBuf
== 0 )
405 return kIOReturnNoMemory
;
407 bzero((void *) configBuf
, kConfigBufferSize
);
409 /* Get the *current* configuration information, relating to the media. */
412 result
= getConfiguration(configBuf
,
415 true); /* Get current (active) features */
417 if (result
== kIOReturnUnderrun
)
419 // getConfiguration() will report an underrun.
420 result
= kIOReturnSuccess
;
423 if (result
!= kIOReturnSuccess
)
425 DEBUG_LOG("%s::%s getConfiguration() error = %s\n",
426 getName(), __FUNCTION__
, stringFromReturn(result
));
427 result
= kIOReturnSuccess
;
431 fh
= (struct featureHdr
*) configBuf
;
432 len
= OSSwapBigToHostInt32(fh
->totalLen
);
434 if (len
< kConfigMinDataLength
)
436 result
= kIOReturnUnderrun
;
440 // total length, including the Data Length field.
442 len
+= kConfigDataLengthBytes
;
443 len
= min(len
, kConfigBufferSize
);
444 DEBUG_LOG("%s::%s config length = %ld\n", getName(), __FUNCTION__
, len
);
446 // Points to the first Feature Descriptor after the Feature Header.
448 fdp
= (struct featureDescriptor
*)
449 &configBuf
[kConfigFeatureHeaderBytes
];
452 if (OSSwapBigToHostInt16(fdp
->featureCode
) ==
453 kIOATAPIFeatureRandomWrite
)
455 *isWriteProtected
= false;
459 fdp
= (struct featureDescriptor
*)((char *)fdp
+
460 sizeof(struct featureDescriptor
) +
461 fdp
->additionalLength
);
463 while ( ((UInt8
*)fdp
+ sizeof(*fdp
)) <= &configBuf
[len
] );
467 IOFree((void *) configBuf
, kConfigBufferSize
);
472 //---------------------------------------------------------------------------
476 IOATAPIDVDDrive::sendKey(IOMemoryDescriptor
* buffer
,
477 const DVDKeyClass keyClass
,
479 const DVDKeyFormat keyFormat
)
481 IOATACommand
* cmd
= 0;
482 IOReturn ret
= kIOReturnNoMemory
;
487 cmd
= atapiCommandSendKey(buffer
, keyClass
, agid
, keyFormat
);
491 ret
= syncExecute(cmd
);
501 //---------------------------------------------------------------------------
502 // REPORT KEY command.
505 IOATAPIDVDDrive::reportKey(IOMemoryDescriptor
* buffer
,
506 const DVDKeyClass keyClass
,
509 const DVDKeyFormat keyFormat
)
511 IOATACommand
* cmd
= 0;
512 IOReturn ret
= kIOReturnNoMemory
;
517 cmd
= atapiCommandReportKey(buffer
, keyClass
, lba
, agid
, keyFormat
);
521 ret
= syncExecute(cmd
);