]> git.saurik.com Git - apple/xnu.git/blob - iokit/Families/IOATAPICDDrive/IOATAPICDDrive.cpp
xnu-124.13.tar.gz
[apple/xnu.git] / iokit / Families / IOATAPICDDrive / IOATAPICDDrive.cpp
1 /*
2 * Copyright (c) 1998-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) 1999 Apple Computer, Inc. All rights reserved.
24 *
25 * IOATAPICDDrive.h - Generic ATAPI CD-ROM driver.
26 *
27 * HISTORY
28 * Sep 2, 1999 jliu - Ported from AppleATAPIDrive.
29 */
30
31 #include <IOKit/assert.h>
32 #include <IOKit/IOBufferMemoryDescriptor.h>
33 #include <IOKit/storage/ata/IOATAPICDDrive.h>
34 #include <IOKit/storage/ata/IOATAPICDDriveNub.h>
35
36 #define super IOATAPIHDDrive
37 OSDefineMetaClassAndStructors( IOATAPICDDrive, IOATAPIHDDrive )
38
39 //---------------------------------------------------------------------------
40 // Looks for an ATAPI device which is a CD-ROM device.
41
42 bool
43 IOATAPICDDrive::matchATAPIDeviceType(UInt8 type, SInt32 * score)
44 {
45 if (type == kIOATAPIDeviceTypeCDROM)
46 return true;
47
48 return false;
49 }
50
51 //---------------------------------------------------------------------------
52 // Instantiate an ATAPI specific subclass of IOCDBlockStorageDevice.
53
54 IOService *
55 IOATAPICDDrive::instantiateNub()
56 {
57 IOService * nub = new IOATAPICDDriveNub;
58 return nub;
59 }
60
61 //---------------------------------------------------------------------------
62 // Report whether media is write-protected.
63
64 IOReturn
65 IOATAPICDDrive::reportWriteProtection(bool * isWriteProtected)
66 {
67 *isWriteProtected = true;
68 return kIOReturnSuccess;
69 }
70
71 //---------------------------------------------------------------------------
72 // Returns the device type.
73
74 const char *
75 IOATAPICDDrive::getDeviceTypeName()
76 {
77 return kIOBlockStorageDeviceTypeCDROM;
78 }
79
80 //---------------------------------------------------------------------------
81 // Read the Table of Contents.
82 //
83 // The LG DVD-ROM DRN8080B LAB8 drive returns a TOC Data Length field which
84 // describes the number of bytes *returned* in the transfer, not the number
85 // bytes available to be transferred like it should. There is a workaround
86 // that addresses this problem here, however the workaround should be moved
87 // into a separate drive-specific subclass in the future.
88
89 #define LG_DVD_ROM_DRN8080B_SUPPORT
90
91 IOReturn
92 IOATAPICDDrive::readTOC(IOMemoryDescriptor * buffer)
93 {
94 IOReturn ret;
95 IOATACommand * cmd;
96
97 assert(buffer);
98
99 #ifdef LG_DVD_ROM_DRN8080B_SUPPORT
100 IOMemoryDescriptor * bufferOrig = buffer;
101 bool isLG_DVD_ROM_DRN8080B =
102 ( getVendorString() &&
103 getProductString() &&
104 !strcmp(getVendorString(), "LG") &&
105 !strcmp(getProductString(), "DVD-ROM DRN8080B") );
106
107 if (isLG_DVD_ROM_DRN8080B) {
108 buffer = IOBufferMemoryDescriptor::withCapacity(
109 max(4096, (bufferOrig->getLength()+1) & (~1)),
110 kIODirectionIn);
111 if (!buffer)
112 return kIOReturnNoMemory;
113 }
114 #endif LG_DVD_ROM_DRN8080B_SUPPORT
115
116 cmd = atapiCommandReadTOC(buffer, true, 2, 0);
117 if (!cmd)
118 return kIOReturnNoMemory;
119
120 // Execute the Read TOC command.
121 //
122 ret = syncExecute(cmd);
123
124 #ifdef LG_DVD_ROM_DRN8080B_SUPPORT
125 if (isLG_DVD_ROM_DRN8080B) {
126 void * toc;
127 UInt16 tocSize;
128 ATAResults results;
129
130 cmd->getResults(&results);
131 toc = ((IOBufferMemoryDescriptor *)buffer)->getBytesNoCopy();
132 tocSize = min(results.bytesTransferred, bufferOrig->getLength());
133
134 if (bufferOrig->writeBytes(0, toc, tocSize) < bufferOrig->getLength())
135 ret = (ret == kIOReturnSuccess) ? kIOReturnUnderrun : ret;
136 else
137 ret = (ret == kIOReturnUnderrun) ? kIOReturnSuccess : ret;
138
139 buffer->release();
140 }
141 #endif LG_DVD_ROM_DRN8080B_SUPPORT
142
143 cmd->release();
144
145 return ret;
146 }
147
148 //---------------------------------------------------------------------------
149 // Start analog audio play
150
151 IOReturn
152 IOATAPICDDrive::audioPlay(CDMSF timeStart,CDMSF timeStop)
153 {
154 IOATACommand * cmd;
155 IOReturn ret;
156
157 // IOLog("IOATAPICDDrive::audioPlay %x %x\n",timeStart,timeStop);
158 cmd = atapiCommandPlayAudioMSF(timeStart, timeStop);
159 if (!cmd)
160 return kIOReturnNoMemory;
161
162 // Execute the audio play command.
163 //
164 ret = syncExecute(cmd);
165
166 cmd->release();
167
168 return ret;
169 }
170
171 IOReturn
172 IOATAPICDDrive::audioPause(bool pause)
173 {
174 IOATACommand * cmd;
175 IOReturn ret;
176
177 // IOLog("IOATAPICDDrive::audioPause\n");
178 cmd = atapiCommandPauseResume(!pause);
179 if (!cmd)
180 return kIOReturnNoMemory;
181
182 // Execute the audio pause/resume command.
183 //
184 ret = syncExecute(cmd);
185
186 cmd->release();
187
188 return ret;
189 }
190
191 IOReturn
192 IOATAPICDDrive::audioScan(CDMSF timeStart, bool reverse)
193 {
194 IOATACommand * cmd;
195 IOReturn ret;
196
197 cmd = atapiCommandScan(timeStart, reverse);
198 if (!cmd)
199 return kIOReturnNoMemory;
200
201 // Execute the audio scan command.
202 //
203 ret = syncExecute(cmd);
204
205 cmd->release();
206
207 return ret;
208 }
209
210 IOReturn
211 IOATAPICDDrive::audioStop()
212 {
213 IOATACommand * cmd;
214 IOReturn ret;
215
216 cmd = atapiCommandStopPlay();
217 if (!cmd)
218 return kIOReturnNoMemory;
219
220 // Execute the audio stop play command.
221 //
222 ret = syncExecute(cmd);
223
224 cmd->release();
225
226 return ret;
227 }
228
229 IOReturn
230 IOATAPICDDrive::getAudioVolume(UInt8 * leftVolume, UInt8 * rightVolume)
231 {
232 UInt8 audio_control[24];
233 IOReturn status;
234
235 status = readModeSense(audio_control,sizeof(audio_control),(UInt32)0xe);
236
237 if (status == kIOReturnSuccess) {
238 assert((audio_control[0] ) == 0x00);
239 assert((audio_control[1] ) == sizeof(audio_control) - 2);
240 assert((audio_control[8] & 0x3f) == 0x0e);
241 assert((audio_control[9] ) == 0x0e);
242
243 *leftVolume = audio_control[17];
244 *rightVolume = audio_control[19];
245 }
246
247 return status;
248 }
249
250 IOReturn
251 IOATAPICDDrive::setAudioVolume(UInt8 leftVolume, UInt8 rightVolume)
252 {
253 UInt8 audio_control[24];
254 IOReturn status;
255
256 // get current values
257 status = readModeSense(audio_control,sizeof(audio_control),(UInt32)0xe);
258
259 if (status == kIOReturnSuccess) {
260 assert((audio_control[0] ) == 0x00);
261 assert((audio_control[1] ) == sizeof(audio_control) - 2);
262 assert((audio_control[8] & 0x3f) == 0x0e);
263 assert((audio_control[9] ) == 0x0e);
264
265 // set new values
266 audio_control[17] = audio_control[21] = leftVolume;
267 audio_control[19] = audio_control[23] = rightVolume;
268
269 status = writeModeSelect(audio_control,sizeof(audio_control));
270 }
271
272 return status;
273 }
274
275 IOReturn
276 IOATAPICDDrive::readModeSense(UInt8 * buffer,
277 UInt32 length,
278 UInt8 pageCode,
279 UInt8 pageControl = 0)
280 {
281 IOReturn ret;
282 IOATACommand * cmd;
283 IOMemoryDescriptor * senseDesc;
284
285 assert(buffer);
286
287 // IOLog("IOATAPICDDrive::readModeSense len=%d page=%d\n",length,pageCode);
288
289 senseDesc = IOMemoryDescriptor::withAddress(buffer,
290 length,
291 kIODirectionIn);
292 if (!senseDesc)
293 return kIOReturnNoMemory;
294
295 cmd = atapiCommandModeSense(senseDesc, pageCode, pageControl);
296 if (!cmd)
297 return kIOReturnNoMemory;
298
299 // Execute the Mode Sense command.
300 //
301 ret = syncExecute(cmd);
302
303 // Release the memory descriptor.
304 //
305 senseDesc->release();
306
307 cmd->release();
308
309 return ret;
310 }
311
312 IOReturn
313 IOATAPICDDrive::writeModeSelect(UInt8 * buffer, UInt32 length)
314 {
315 IOReturn ret;
316 IOATACommand * cmd;
317 IOMemoryDescriptor * selectDesc;
318
319 // IOLog("IOATAPICDDrive::writeModeSelect %d %d\n",length);
320 assert(buffer);
321
322 selectDesc = IOMemoryDescriptor::withAddress(buffer,
323 length,
324 kIODirectionOut);
325 if (!selectDesc)
326 return kIOReturnNoMemory;
327
328 cmd = atapiCommandModeSelect(selectDesc);
329 if (!cmd)
330 return kIOReturnNoMemory;
331
332 // Execute the Mode Select command.
333 //
334 ret = syncExecute(cmd);
335
336 // Release the memory descriptor.
337 //
338 selectDesc->release();
339
340 cmd->release();
341
342 return ret;
343 }
344
345 IOReturn
346 IOATAPICDDrive::getAudioStatus(CDAudioStatus * status)
347 {
348 UInt8 * channel_data;
349 IOReturn ret;
350
351 // init
352 channel_data = (UInt8 *)IOMalloc(16);
353 if (!channel_data) return kIOReturnNoMemory;
354
355 // get audio status
356 ret = readSubChannel(channel_data,16,0x01,0x00);
357
358 if (ret == kIOReturnSuccess) {
359 // state our assumptions
360 assert(channel_data[2] == 0);
361 assert(channel_data[3] == 12);
362 assert(channel_data[4] == 1);
363
364 // get current status
365 status->status = channel_data[ 1];
366
367 // get current track and track index
368 status->position.track.number = channel_data[ 6];
369 status->position.track.index = channel_data[ 7];
370
371 // get current absolute address
372 status->position.time.minute = channel_data[ 9];
373 status->position.time.second = channel_data[10];
374 status->position.time.frame = channel_data[11];
375
376 // get current relative address
377 status->position.track.time.minute = channel_data[13];
378 status->position.track.time.second = channel_data[14];
379 status->position.track.time.frame = channel_data[15];
380 }
381
382 // cleanup
383 IOFree(channel_data,16);
384 return ret;
385 }
386
387 IOReturn
388 IOATAPICDDrive::readMCN(CDMCN mcn)
389 {
390 UInt8 * channel_data;
391 IOReturn ret;
392
393 // init
394 channel_data = (UInt8 *)IOMalloc(24);
395 if (!channel_data) return kIOReturnNoMemory;
396
397 // get audio status
398 ret = readSubChannel(channel_data,24,0x02,0x00);
399
400 if (ret == kIOReturnSuccess) {
401 // state our assumptions
402 assert(channel_data[2] == 0);
403 assert(channel_data[3] == 20);
404 assert(channel_data[4] == 2);
405
406 // check if found
407 if ((channel_data[8] & 0x80)) {
408 // copy the data
409 bcopy(&channel_data[9],mcn,kCDMCNMaxLength);
410 mcn[kCDMCNMaxLength] = '\0';
411 } else {
412 ret = kIOReturnNotFound;
413 }
414 }
415
416 // cleanup
417 IOFree(channel_data,24);
418 return ret;
419 }
420
421 IOReturn
422 IOATAPICDDrive::readISRC(UInt8 track, CDISRC isrc)
423 {
424 UInt8 * channel_data;
425 IOReturn ret;
426
427 // init
428 channel_data = (UInt8 *)IOMalloc(24);
429 if (!channel_data) return kIOReturnNoMemory;
430
431 // get audio status
432 ret = readSubChannel(channel_data,24,0x03,track);
433
434 if (ret == kIOReturnSuccess) {
435 // state our assumptions
436 assert(channel_data[2] == 0);
437 assert(channel_data[3] == 20);
438 assert(channel_data[4] == 3);
439
440 // check if found
441 if ((channel_data[8] & 0x80)) {
442 // copy the data
443 bcopy(&channel_data[9],isrc,kCDISRCMaxLength);
444 isrc[kCDISRCMaxLength] = '\0';
445 } else {
446 ret = kIOReturnNotFound;
447 }
448 }
449
450 // cleanup
451 IOFree(channel_data,24);
452 return ret;
453 }
454
455 IOReturn
456 IOATAPICDDrive::readSubChannel(UInt8 * buffer,
457 UInt32 length,
458 UInt8 dataFormat,
459 UInt8 trackNumber)
460 {
461 IOReturn ret;
462 IOATACommand * cmd;
463 IOMemoryDescriptor * readDesc;
464
465 assert(buffer);
466
467 // IOLog("IOATAPICDDrive::readSubChannel len=%d\n",length);
468
469 readDesc = IOMemoryDescriptor::withAddress(buffer,
470 length,
471 kIODirectionIn);
472 if (!readDesc)
473 return kIOReturnNoMemory;
474
475 cmd = atapiCommandReadSubChannel(readDesc, dataFormat, trackNumber);
476 if (!cmd)
477 return kIOReturnNoMemory;
478
479 // Execute the Mode Sense command.
480 //
481 ret = syncExecute(cmd);
482
483 // Release the memory descriptor.
484 //
485 readDesc->release();
486
487 cmd->release();
488
489 return ret;
490 }
491
492 IOReturn
493 IOATAPICDDrive::doAsyncReadCD(IOMemoryDescriptor * buffer,
494 UInt32 block,
495 UInt32 nblks,
496 CDSectorArea sectorArea,
497 CDSectorType sectorType,
498 IOStorageCompletion completion)
499 {
500 IOReturn ret;
501 IOATACommand * cmd;
502
503 cmd = atapiCommandReadCD(buffer,block,nblks,sectorArea,sectorType);
504
505 if (!cmd)
506 return kIOReturnNoMemory;
507
508 ret = asyncExecute(cmd, completion);
509
510 cmd->release();
511
512 return ret;
513 }