]> git.saurik.com Git - apple/xnu.git/blob - iokit/Families/IOSCSIDVDDrive/IOSCSIDVDDrive.cpp
xnu-124.13.tar.gz
[apple/xnu.git] / iokit / Families / IOSCSIDVDDrive / IOSCSIDVDDrive.cpp
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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.
11 *
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
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 // =============================================================================
23 // Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
24 //
25 // IOSCSIDVDDrive.cpp
26 //
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>
35
36 #define super IOSCSICDDrive
37 OSDefineMetaClassAndStructors(IOSCSIDVDDrive,IOSCSICDDrive)
38
39 /*----------------*/
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;
70
71 void
72 IOSCSIDVDDrive::checkConfig(UInt8 *buf,UInt32 actual)
73 {
74 struct featureHdr {
75 UInt32 totalLen;
76 UInt8 reserved1[2];
77 UInt16 currentProfile;
78 };
79 struct featureDescriptor {
80 UInt16 featureCode;
81 UInt8 versionPC;
82 UInt8 additionalLength;
83 };
84
85 int len;
86 struct featureHdr *fh;
87 struct featureDescriptor *fdp;
88
89 fh = (struct featureHdr *)buf;
90 len = OSSwapBigToHostInt32(fh->totalLen);
91
92 fdp = (struct featureDescriptor *)(&buf[8]);
93
94 do {
95
96 switch (OSSwapBigToHostInt16(fdp->featureCode)) {
97
98 case kFeatureDVDRead :
99 _isDVDDrive = true;
100 break;
101 case kFeatureDVDCSS :
102 _canDoCSS = true;
103 break;
104 }
105 fdp = (struct featureDescriptor *)((char *)fdp +
106 sizeof(struct featureDescriptor) +
107 fdp->additionalLength);
108 } while ((UInt8 *)fdp < &buf[len]);
109 }
110
111 IOReturn
112 IOSCSIDVDDrive::determineMediaType(void)
113 {
114 struct featureHdr {
115 UInt32 totalLen;
116 UInt8 reserved1[2];
117 UInt16 currentProfile;
118 };
119 struct featureDescriptor {
120 UInt16 featureCode;
121 UInt8 versionPC;
122 UInt8 additionalLength;
123 };
124
125 int len;
126 struct featureHdr *fh;
127 struct featureDescriptor *fdp;
128 IOReturn result;
129 UInt32 configSize;
130 UInt8 configBuf[kMaxConfigLength];
131
132 /* Get the *current* configuration information, relating to the media. */
133
134 result = getConfiguration(configBuf,kMaxConfigLength,&configSize,true);
135 if (result != kIOReturnSuccess) {
136 IOLog("%s[IOSCSIDVDDrive]::determineMediaType; result = '%s'\n",
137 getName(),stringFromReturn(result));
138 return(result);
139 }
140
141 fh = (struct featureHdr *)configBuf;
142 len = OSSwapBigToHostInt32(fh->totalLen);
143
144 fdp = (struct featureDescriptor *)(&configBuf[8]);
145
146 _mediaType = kDVDMediaTypeUnknown; /* assume there is no media inserted */
147
148 do {
149
150 switch (OSSwapBigToHostInt16(fdp->featureCode)) {
151
152 case kFeatureCDRead :
153 _mediaType = kCDMediaTypeROM;
154 IOLog("%s[IOSCSIDVDDrive]::determineMediaType; media is %s.\n",getName(),"CD");
155 break;
156 case kFeatureDVDRead :
157 _mediaType = kDVDMediaTypeROM;
158 IOLog("%s[IOSCSIDVDDrive]::determineMediaType; media is %s.\n",getName(),"DVDROM");
159 break;
160 case kFeatureFormattable :
161 _mediaType = kDVDMediaTypeRAM;
162 IOLog("%s[IOSCSIDVDDrive]::determineMediaType; media is %s.\n",getName(),"DVDRam");
163 break;
164 case kFeatureRandomWrite :
165 _isWriteProtected = false;
166 IOLog("%s[IOSCSIDVDDrive]::determineMediaType; write-enabled.\n",getName());
167 break;
168 }
169 fdp = (struct featureDescriptor *)((char *)fdp +
170 sizeof(struct featureDescriptor) +
171 fdp->additionalLength);
172 } while ((UInt8 *)fdp < &configBuf[len]);
173
174 if (_mediaType == kDVDMediaTypeUnknown) {
175 IOLog("%s[IOSCSIDVDDrive]::determineMediaType; drive is empty.\n",getName());
176 }
177
178 return(kIOReturnSuccess);
179 }
180
181 bool
182 IOSCSIDVDDrive::deviceTypeMatches(UInt8 inqBuf[],UInt32 inqLen,SInt32 *score)
183 {
184 IOReturn result;
185 UInt8 type;
186
187 type = inqBuf[0] & 0x1f;
188
189 if (type == kIOSCSIDeviceTypeCDROM) {
190 // IOLog("%s[IOSCSIDVDDrive]::deviceTypeMatches; device type %d is CD/DVD\n",getName(),type);
191
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.
195 */
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);
200 if (_isDVDDrive) {
201 // IOLog("---isDVDDrive\n");
202 *score = 16; /* override any CD driver match */
203 return(true);
204 } else { /* not DVD */
205 return(false);
206 }
207 } else {
208 // IOLog("%s[IOSCSIDVDDrive]::deviceTypeMatches getConfig fail; returning false\n",getName());
209 return(false);
210 }
211 } else {
212 /**
213 IOLog("%s[IOSCSIDVDDrive]::deviceTypeMatches; device type %d not CD/DVD, returning FALSE\n",
214 getName(),type);
215 **/
216 return(false); /* we don't handle other devices */
217 }
218 }
219
220 IOReturn
221 IOSCSIDVDDrive::doAsyncReadWrite(IOMemoryDescriptor *buffer,
222 UInt32 block,UInt32 nblks,
223 IOStorageCompletion completion)
224 {
225 return(standardAsyncReadWrite(buffer,block,nblks,completion));
226 }
227
228 IOReturn
229 IOSCSIDVDDrive::doFormatMedia(UInt64 byteCapacity)
230 {
231 return(standardFormatMedia(byteCapacity));
232 }
233
234 UInt32
235 IOSCSIDVDDrive::doGetFormatCapacities(UInt64 *capacities,UInt32 capacitiesMaxCount) const
236 {
237 if (capacitiesMaxCount > 0) {
238 *capacities = (UInt64)((UInt64)2600 * (UInt64)1048576); /* DVD-RAM V1.0 is 2.6GB */
239 return(1);
240 } else {
241 return(0);
242 }
243 }
244
245 IOReturn
246 IOSCSIDVDDrive::doSynchronizeCache(void)
247 {
248 return(standardSynchronizeCache());
249 }
250
251 IOReturn
252 IOSCSIDVDDrive::doSyncReadWrite(IOMemoryDescriptor *buffer,UInt32 block,UInt32 nblks)
253 {
254 return(standardSyncReadWrite(buffer,block,nblks));
255 }
256
257 IOReturn
258 IOSCSIDVDDrive::getConfiguration(UInt8 *buffer,UInt32 length,UInt32 *actualLength,bool current)
259 {
260 struct context *cx;
261 struct IOGCCdb *c;
262 IOSCSICommand *req;
263 SCSICDBInfo scsiCDB;
264 SCSIResults scsiResults;
265 IOReturn result;
266
267 cx = allocateContext();
268 if (cx == NULL) {
269 return(kIOReturnNoMemory);
270 }
271
272 req = cx->scsireq;
273
274 bzero( &scsiCDB, sizeof(scsiCDB) );
275
276 bzero(buffer,length);
277
278 c = (struct IOGCCdb *)(scsiCDB.cdb);
279
280 c->opcode = kIOSCSICommandGetConfiguration;
281 c->lunRT = 0;
282 if (current) { /* only get current features */
283 c->lunRT |= 0x01;
284 }
285 c->startFeature_lo = 0;
286 c->startFeature_hi = 0;
287 c->len_hi = length >> 8;
288 c->len_lo = length & 0xff;
289 c->ctlbyte = 0;
290
291 scsiCDB.cdbLength = 10;
292 req->setCDB( &scsiCDB );
293
294 cx->memory = IOMemoryDescriptor::withAddress((void *)buffer,
295 length,
296 kIODirectionIn);
297 req->setPointers( cx->memory, length, false );
298 req->setPointers( cx->senseDataDesc, 255, false, true );
299 req->setTimeout( 5000 );
300
301 queueCommand(cx,kSync,getGetConfigurationPowerState());
302 result = simpleSynchIO(cx);
303
304 req->getResults(&scsiResults);
305 if (result == kIOReturnUnderrun) {
306 result = kIOReturnSuccess;
307 }
308 *actualLength = scsiResults.bytesTransferred;
309
310 deleteContext(cx);
311
312 return(result);
313 }
314
315 const char *
316 IOSCSIDVDDrive::getDeviceTypeName(void)
317 {
318 return(kIOBlockStorageDeviceTypeDVD);
319 }
320
321 UInt32
322 IOSCSIDVDDrive::getGetConfigurationPowerState(void)
323 {
324 return(kElectronicsOn);
325 }
326
327 UInt32
328 IOSCSIDVDDrive::getReportKeyPowerState(void)
329 {
330 return(kElectronicsOn);
331 }
332
333 UInt32
334 IOSCSIDVDDrive::getSendKeyPowerState(void)
335 {
336 return(kElectronicsOn);
337 }
338
339 UInt32
340 IOSCSIDVDDrive::getMediaType(void)
341 {
342 return(_mediaType);
343 }
344
345 bool
346 IOSCSIDVDDrive::init(OSDictionary * properties)
347 {
348 _isDVDDrive = false;
349 _canDoCSS = false;
350 _configSize = 0;
351 _mediaType = kDVDMediaTypeUnknown;
352 _isWriteProtected = true;
353
354 return(super::init(properties));
355 }
356
357 IOService *
358 IOSCSIDVDDrive::instantiateNub(void)
359 {
360 IOService *nub;
361
362 /* Instantiate a generic DVD nub so a generic driver can match above us. */
363
364 nub = new IOSCSIDVDDriveNub;
365 return(nub);
366 }
367
368 IOReturn
369 IOSCSIDVDDrive::reportKey(IOMemoryDescriptor *buffer,const DVDKeyClass keyClass,
370 const UInt32 lba,const UInt8 agid,const DVDKeyFormat keyFormat)
371 {
372 struct context *cx;
373 struct IORKCdb *c;
374 IOSCSICommand *req;
375 SCSICDBInfo scsiCDB;
376 IOReturn result;
377
378 cx = allocateContext();
379 if (cx == NULL) {
380 return(kIOReturnNoMemory);
381 }
382
383 req = cx->scsireq;
384
385 bzero( &scsiCDB, sizeof(scsiCDB) );
386
387 c = (struct IORKCdb *)(scsiCDB.cdb);
388
389 c->opcode = kIOSCSICommandReportKey;
390 if (keyFormat == kTitleKey) {
391 c->lba_0 = lba >> 24;
392 c->lba_1 = lba >> 16;
393 c->lba_2 = lba >> 8;
394 c->lba_3 = lba & 0xff;
395 }
396 c->keyClass = keyClass;
397 c->len_hi = buffer->getLength() >> 8;
398 c->len_lo = buffer->getLength() & 0xff;
399 c->agidKeyFormat = agid << 6 | keyFormat;
400 c->ctlbyte = 0;
401
402 scsiCDB.cdbLength = 10;
403 req->setCDB( &scsiCDB );
404
405 cx->memory = buffer;
406
407 req->setPointers( cx->memory, cx->memory->getLength(), false );
408 req->setPointers( cx->senseDataDesc, 255, false, true );
409 req->setTimeout( 5000 );
410
411 queueCommand(cx,kSync,getReportKeyPowerState());
412 result = simpleSynchIO(cx);
413
414 deleteContext(cx);
415
416 return(result);
417 }
418
419 IOReturn
420 IOSCSIDVDDrive::reportMediaState(bool *mediaPresent,bool *changed)
421 {
422 IOReturn result;
423
424 /* Let the superclass check for media in the standard way: */
425
426 result = super::reportMediaState(mediaPresent,changed);
427
428 if (result != kIOReturnSuccess) {
429 IOLog("%s[IOSCSIDVDDrive]:: reportMediaState; result = '%s' from super\n",
430 getName(),stringFromReturn(result));
431 return(result);
432 }
433
434 /* If we have newly-inserted media, determine its type: */
435
436 if (*mediaPresent && *changed) {
437 result = determineMediaType();
438 }
439
440 return(result);
441 }
442
443 IOReturn
444 IOSCSIDVDDrive::reportWriteProtection(bool *isWriteProtected)
445 {
446 *isWriteProtected = _isWriteProtected;
447 return(kIOReturnSuccess);
448 }
449
450 IOReturn
451 IOSCSIDVDDrive::sendKey(IOMemoryDescriptor *buffer,const DVDKeyClass keyClass,
452 const UInt8 agid,const DVDKeyFormat keyFormat)
453 {
454 struct context *cx;
455 struct IOSKCdb *c;
456 IOSCSICommand *req;
457 SCSICDBInfo scsiCDB;
458 IOReturn result;
459
460 cx = allocateContext();
461 if (cx == NULL) {
462 return(kIOReturnNoMemory);
463 }
464
465 req = cx->scsireq;
466
467 bzero( &scsiCDB, sizeof(scsiCDB) );
468
469 c = (struct IOSKCdb *)(scsiCDB.cdb);
470
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;
476 c->ctlbyte = 0;
477
478 scsiCDB.cdbLength = 10;
479 req->setCDB( &scsiCDB );
480
481 cx->memory = buffer;
482
483 req->setPointers( cx->memory, cx->memory->getLength(), false );
484 req->setPointers( cx->senseDataDesc, 255, false, true );
485 req->setTimeout( 5000 );
486
487 queueCommand(cx,kSync,getSendKeyPowerState());
488 result = simpleSynchIO(cx);
489
490 deleteContext(cx);
491
492 return(result);
493 }