|
|
1.1 root 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: #include <IOKit/IOLib.h>
23: #include <IOKit/storage/IOCDDrive.h>
24: #include <IOKit/storage/IOCDMedia.h>
25: #include "IOCDAudioNub.h"
26: #include <IOKit/storage/IOCDDriveNub.h>
27:
28: #define super IOHDDrive
29: OSDefineMetaClassAndStructors(IOCDDrive,IOHDDrive)
30:
31: /* Accept a new piece of media, doing whatever's necessary to make it
32: * show up properly to the system.
33: */
34: IOReturn
35: IOCDDrive::acceptNewMedia(void)
36: {
37: IOReturn result;
38: bool ok;
39: int i;
40: UInt32 nblocks;
41: UInt64 nbytes;
42: int nDataTracks;
43: int nAudioTracks;
44: char name[128];
45: bool nameSep;
46:
47: // IOLog("%s[IOCDDrive]::acceptNewMedia\n",getName());
48:
49: /* First, we cache information about the tracks on the disc: */
50:
51: result = cacheTocInfo();
52: if (result != kIOReturnSuccess) {
53: IOLog("%s[IOCDDrive]::acceptNewMedia; err '%s' from cacheTocInfo\n",
54: getName(),stringFromReturn(result));
55: return(result);
56: }
57:
58: /* Scan thru the track list, counting up the number of Data and Audio tracks.
59: * We also total up the number of blocks (bytes) for all data tracks.
60: */
61:
62: nDataTracks = 0;
63: nAudioTracks = 0;
64: nblocks = 0;
65:
66: for (i = 1; i <= 99; i++) { /* only tracks 1-99, not leadout or points */
67: if (trackExists(i)) {
68: if (trackIsData(i)) {
69: nDataTracks++;
70: nblocks += getTrackBlocks(i);
71: } else {
72: nAudioTracks++;
73: }
74: }
75: }
76:
77: nbytes = nblocks * 2048;
78:
79: /* Instantiate a CD Media nub above ourselves. */
80:
81: name[0] = 0;
82: nameSep = false;
83: if (_provider->getVendorString()) {
84: strcat(name, _provider->getVendorString());
85: nameSep = true;
86: }
87: if (_provider->getProductString()) {
88: if (nameSep == true) strcat(name, " ");
89: strcat(name, _provider->getProductString());
90: nameSep = true;
91: }
92: if (nameSep == true) strcat(name, " ");
93: strcat(name, "Media");
94:
95: result = instantiateMediaObject((IOMedia **)&_mediaNub,0,nbytes,2048,true,name);
96:
97: if (_mediaNub) {
98: ok = _mediaNub->attach(this);
99: } else {
100: IOLog("%s[IOCDDrive]::acceptNewMedia; can't instantiate CD media nub.\n",getName());
101: return(result); /* give up now */
102: }
103: if (!ok) {
104: IOLog("%s[IOCDDrive]::acceptNewMedia; can't attach CD media nub.\n",getName());
105: _mediaNub->release();
106: _mediaNub = NULL;
107: return(kIOReturnNoMemory); /* give up now */
108: }
109:
110: /* Instantiate an audio control nub for the audio portion of the media. */
111:
112: _acNub = new IOCDAudioNub;
113: if (_acNub) {
114: _acNub->init();
115: ok = _acNub->attach(this);
116: if (!ok) {
117: IOLog("%s[IOCDDrive]::acceptNewMedia; can't attach audio control nub.\n",getName());
118: _acNub->release();
119: _acNub = NULL;
120: }
121: } else {
122: IOLog("%s[IOCDDrive]::acceptNewMedia; can't instantiate audio control nub.\n",
123: getName());
124: }
125:
126: IOLog("%s media: %ld blocks, %ld bytes each, %d data tracks, %d audio tracks.\n",
127: getName(),nblocks,2048L,nDataTracks,nAudioTracks);
128:
129: /* Now that the nubs are attached, register them. */
130:
131: _mediaNub->setProperty("audio tracks",nAudioTracks,32);
132: _mediaNub->setProperty("data tracks",nDataTracks,32);
133: _mediaNub->registerService();
134:
135: if (_acNub) {
136: _acNub->registerService();
137: }
138:
139: _mediaPresent = true;
140:
141: return(result);
142: }
143:
144: IOReturn
145: IOCDDrive::audioPlay(positioningType addressType,cdAddress address,audioPlayMode mode)
146: {
147: return(_CDprovider->audioPlay(addressType,address,mode));
148: }
149:
150: IOReturn
151: IOCDDrive::audioPause(bool pause)
152: {
153: return(_CDprovider->audioPause(pause));
154: }
155:
156: IOReturn
157: IOCDDrive::audioScan(positioningType addressType,cdAddress address,bool reverse)
158: {
159: return(_CDprovider->audioScan(addressType,address,reverse));
160: }
161:
162: IOReturn
163: IOCDDrive::audioTrackSearch(positioningType addressType,cdAddress address,
164: bool startPlay,audioPlayMode mode)
165: {
166: return(_CDprovider->audioTrackSearch(addressType,address,startPlay,mode));
167: }
168:
169: IOReturn
170: IOCDDrive::cacheTocInfo(void)
171: {
172: IOReturn result;
173: struct rawToc *toc;
174: struct tocTrackDescriptor *d;
175: struct tocTrackDescriptor *end;
176: int length;
177: struct trackInfo *t;
178: struct trackInfo *priorTrack = 0; /* =0 avoids "uninitialized" warning */
179: int i;
180:
181: for (i = 0; i < kTrackEntries; i++) { /* max 99 tracks plus leadout */
182: bzero((void *)&_trackInfo[i],sizeof(struct trackInfo));
183: }
184:
185: toc = IONew(struct rawToc,1);
186: if (toc == NULL) {
187: return(kIOReturnNoMemory);
188: }
189:
190: /* Read the TOC in Lba format to get most of the info we need: */
191:
192: result = _CDprovider->readTOC(toc,sizeof(struct rawToc),ktocSCSI2LBA);
193:
194: // IOLog("raw toc in LBA format:\n");
195: // dump((char *)toc,sizeof(struct rawToc));
196:
197: if (result != kIOReturnSuccess) {
198: IODelete(toc,struct rawToc,1);
199: return(result);
200: }
201:
202: /* Scan all the tracks in the TOC, setting up our track info.*/
203:
204: d = &toc->descriptors[0];
205: length = toc->header.len_hi << 8 | toc->header.len_lo - 2; /* bytes used for descriptors */
206: end = &toc->descriptors[length / sizeof(struct tocTrackDescriptor)];
207:
208: while (d < end) {
209: t = &_trackInfo[d->track];
210: setTrackInfoEntry(d,t);
211: t->lba = d->lba_3 << 24 | d->lba_2 << 16 | d->lba_1 << 8 | d->lba_0;
212:
213: /* Compute the number of blocks in the prior track, now that we
214: * know the starting LBA of this track.
215: */
216: if (d->track > 1) {
217: priorTrack->nblocks = t->lba - priorTrack->lba;
218: }
219: priorTrack = t;
220: d++;
221: }
222:
223: /* Read the TOC again, this time in MSF format, and grab the MSF info. */
224:
225: result = _CDprovider->readTOC(toc,sizeof(struct rawToc),ktocSCSI2MSF);
226: if (result != kIOReturnSuccess) {
227: IODelete(toc,struct rawToc,1);
228: return(result);
229: }
230:
231: d = &toc->descriptors[0];
232: length = toc->header.len_hi << 8 | toc->header.len_lo - 2; /* bytes used for descriptors */
233: end = &toc->descriptors[length / sizeof(struct tocTrackDescriptor)];
234:
235: while (d < end) {
236: t = &_trackInfo[d->track];
237: // setTrackInfoEntry(d,t);
238: t->msf = d->lba_3 << 24 | d->lba_2 << 16 | d->lba_1 << 8 | d->lba_0;
239: d++;
240: }
241:
242: IODelete(toc,struct rawToc,1);
243:
244: _tocInfoCached = true;
245:
246: IOLog("-CD track ctl isdata lba10 lba16 M:S:F nblks10 nblks16\n");
247:
248: #define SHOWTOC
249: #ifdef SHOWTOC
250: for (i = 1; i < kTrackEntries; i++) {
251: if (_trackInfo[i].track != 0) {
252: IOLog(" %02x %02x %s %8d %08x %02d:%02d:%02d %8d %08x\n",
253: _trackInfo[i].track,
254: _trackInfo[i].control,
255: _trackInfo[i].isData ? "Y" : "N",
256: (int)_trackInfo[i].lba,
257: (int)_trackInfo[i].lba,
258: (int)_trackInfo[i].msf >> 16 & 0xff,
259: (int)_trackInfo[i].msf >> 8 & 0xff,
260: (int)_trackInfo[i].msf & 0xff,
261: (int)_trackInfo[i].nblocks,
262: (int)_trackInfo[i].nblocks);
263: }
264: }
265: #endif
266:
267: return(result);
268: }
269:
270: /* Decommission all nubs. */
271: IOReturn
272: IOCDDrive::decommissionMedia(bool forcible)
273: {
274: IOReturn result;
275:
276: result = kIOReturnSuccess;
277:
278: lockForArbitration();
279:
280: if (_mediaNub) {
281: result = tearDown(_mediaNub);
282: if (forcible || (result == kIOReturnSuccess)) {
283: _mediaNub = 0;
284: }
285: }
286:
287: /* If it's not a forcible teardown, we only attempt to decommission the
288: * audio portion of the CD if all the data tracks decommissioned successfully.
289: */
290:
291: if (forcible || (result == kIOReturnSuccess)) {
292: if (_acNub) {
293: result = tearDown(_acNub);
294: if (forcible || (result == kIOReturnSuccess)) {
295: _acNub = 0;
296: }
297: }
298: }
299:
300: if (forcible || (result == kIOReturnSuccess)) {
301: initMediaStates(); /* deny existence of any media */
302: _tocInfoCached = false;
303: }
304:
305: unlockForArbitration();
306:
307: return(result);
308: }
309:
310: /* We should check with other clients using the other nubs before we allow
311: * the client of the IOCDMediaNub to eject the media.
312: */
313: IOReturn
314: IOCDDrive::ejectMedia(void)
315: {
316: /* For now, we don't check with the other clients. */
317:
318: return(super::ejectMedia());
319: }
320:
321: IOReturn
322: IOCDDrive::getAudioStatus(struct audioStatus *status)
323: {
324: return(_CDprovider->getAudioStatus(status));
325: }
326:
327: const char *
328: IOCDDrive::getDeviceTypeName(void)
329: {
330: return(kDeviceTypeCDROM);
331: }
332:
333: UInt32
334: IOCDDrive::getTrackBlocks(UInt32 track)
335: {
336: if (trackExists(track)) {
337: return(_trackInfo[track].nblocks);
338: } else {
339: return(0);
340: }
341: }
342:
343: UInt32
344: IOCDDrive::getTrackStartBlock(UInt32 track)
345: {
346: if (trackExists(track)) {
347: return(_trackInfo[track].lba);
348: } else {
349: return(0);
350: }
351: }
352:
353: bool
354: IOCDDrive::init(OSDictionary * properties)
355: {
356: int i;
357:
358: for (i = 0; i < kTrackEntries; i++) {
359: bzero((void *)&_trackInfo[i],sizeof(struct trackInfo));
360: }
361:
362: _acNub = NULL;
363: _mediaNub = NULL;
364:
365: _tocInfoCached = false;
366:
367: return(super::init(properties));
368: }
369:
370: IOMedia *
371: IOCDDrive::instantiateDesiredMediaObject(void)
372: {
373: return(new IOCDMedia);
374: }
375:
376: IOReturn
377: IOCDDrive::readAudioData(positioningType addressType,cdAddress address,
378: UInt8 blockCount,UInt8 *buffer)
379: {
380: return(_CDprovider->readAudioData(addressType,address,blockCount,buffer));
381: }
382:
383: IOReturn
384: IOCDDrive::readAudioSubcodes(positioningType addressType,cdAddress address,
385: UInt8 blockCount,UInt8 *buffer)
386: {
387: return(_CDprovider->readAudioSubcodes(addressType,address,blockCount,buffer));
388: }
389:
390: IOReturn
391: IOCDDrive::readAudioVolume(UInt8 *leftVolume,UInt8 *rightVolume)
392: {
393: return(_CDprovider->readAudioVolume(leftVolume,rightVolume));
394: }
395:
396: IOReturn
397: IOCDDrive::readAudioWithQSubcode(positioningType addressType,cdAddress address,
398: UInt8 blockCount,UInt8 *buffer)
399: {
400: return(_CDprovider->readAudioWithQSubcode(addressType,address,blockCount,buffer));
401: }
402:
403: IOReturn
404: IOCDDrive::readAudioWithAllSubcodes(positioningType addressType,cdAddress address,
405: UInt8 blockCount,UInt8 *buffer)
406: {
407: return(_CDprovider->readAudioWithAllSubcodes(addressType,address,blockCount,buffer));
408: }
409:
410: IOReturn
411: IOCDDrive::readEntireTOC(struct macEntireToc *buffer)
412: {
413: /* Return our cached TOC info. */
414:
415: int i;
416: int out;
417:
418: bzero(buffer,sizeof(struct macEntireToc));
419:
420: out = 0;
421:
422: /* Copy A0, A1, A2: */
423:
424: for (i = 0xa0; i <= 0xa2; i++) {
425: if (_trackInfo[i].track != 0) { /* then the track exists */
426: buffer->entries[out].trackPoint = _trackInfo[i].track;
427: buffer->entries[out].type = (trackType)_trackInfo[i].control;
428: buffer->entries[out].pMin = _trackInfo[i].msf >> 16;
429: buffer->entries[out].pSec = _trackInfo[i].msf >> 8;
430: buffer->entries[out].pFrame = _trackInfo[i].msf & 0xff;
431:
432: out++;
433: }
434: }
435:
436: /* Copy tracks: */
437:
438: for (i = 1; i <= 99; i++) {
439: if (_trackInfo[i].track != 0) { /* then the track exists */
440: buffer->entries[out].trackPoint = _trackInfo[i].track;
441: buffer->entries[out].type = (trackType)_trackInfo[i].control;
442: buffer->entries[out].pMin = _trackInfo[i].msf >> 16;
443: buffer->entries[out].pSec = _trackInfo[i].msf >> 8;
444: buffer->entries[out].pFrame = _trackInfo[i].msf & 0xff;
445:
446: out++;
447: }
448: }
449: return(kIOReturnSuccess);
450: }
451:
452: IOReturn
453: IOCDDrive::readHeader(UInt32 blockAddress,struct headerInfo *buffer)
454: {
455: return(_CDprovider->readHeader(blockAddress,buffer));
456: }
457:
458: IOReturn
459: IOCDDrive::readISRC(UInt32 track,UInt8 *buffer,bool *found)
460: {
461: return(_CDprovider->readISRC(track,buffer,found));
462: }
463:
464: IOReturn
465: IOCDDrive::readLeadOutAddress(cdAddress *buffer)
466: {
467: if (!_tocInfoCached) {
468: return(kIOReturnNotReady);
469: }
470:
471: *buffer = (cdAddress)_trackInfo[0xaa].msf;
472: return(kIOReturnSuccess);
473: }
474:
475: IOReturn
476: IOCDDrive::readMCN(UInt8 *buffer,bool *found)
477: {
478: return(_CDprovider->readMCN(buffer,found));
479: }
480:
481: IOReturn
482: IOCDDrive::readQSubcodes(struct qSubcodeTocInfo *buffer,UInt32 bufSize)
483: {
484: return(_CDprovider->readQSubcodes(buffer,bufSize));
485: }
486:
487: IOReturn
488: IOCDDrive::readSessionInfo(struct sessionInfo *info)
489: {
490: IOReturn result;
491: struct rawToc *toc;
492: struct tocTrackDescriptor *d;
493:
494: toc = IONew(struct rawToc,1);
495: if (toc == NULL) {
496: return(kIOReturnNoMemory);
497: }
498:
499: result = _CDprovider->readTOC(toc,sizeof(struct rawToc),ktocSessionInfo);
500:
501: if (result == kIOReturnSuccess) {
502: info->firstSessionNumber = toc->header.firstTrack;
503: info->lastSessionNumber = toc->header.lastTrack;
504: d = &toc->descriptors[0];
505: info->trackNumber = d->track;
506: info->info.type = (trackType)(d->adrControl);
507: info->info.address = (cdAddress)( d->lba_3 << 24 |
508: d->lba_2 << 16 |
509: d->lba_1 << 8 |
510: d->lba_0);
511: }
512:
513: IODelete(toc,struct rawToc,1);
514:
515: return(result);
516: }
517:
518: IOReturn
519: IOCDDrive::readSubcodeBuffer(UInt8 *buffer,bool purge,UInt32 entryCount)
520: {
521: return(_CDprovider->readSubcodeBuffer(buffer,purge,entryCount));
522: }
523:
524: IOReturn
525: IOCDDrive::readTheQSubcode(struct qSubcode *buffer)
526: {
527: return(_CDprovider->readTheQSubcode(buffer));
528: }
529:
530: IOReturn
531: IOCDDrive::readTrackInfo(UInt32 startingTrack,struct trackTypeInfo *buf,UInt32 bufSize)
532: {
533: struct trackTypeInfo *end;
534:
535: if (!_tocInfoCached) {
536: return(kIOReturnNotReady);
537: }
538:
539: end = &buf[bufSize / sizeof(struct trackTypeInfo)];
540:
541: /* Copy till we run past track 99 or the buffer runs out. */
542:
543: while (startingTrack <= 99) {
544: if (buf >= end) {
545: return(kIOReturnSuccess);
546: }
547: if (_trackInfo[startingTrack].track != 0) { /* then the track exists */
548: buf->type = (trackType)_trackInfo[startingTrack].control;
549: buf->address = _trackInfo[startingTrack].msf;
550:
551: buf++;
552: }
553:
554: startingTrack++;
555: }
556:
557: return(kIOReturnSuccess);
558: }
559:
560: IOReturn
561: IOCDDrive::readTrackLimits(UInt32 *first,UInt32 *last)
562: {
563: int i;
564: bool gotFirst;
565:
566: if (!_tocInfoCached) {
567: return(kIOReturnNotReady);
568: }
569:
570: gotFirst = false;
571:
572: for (i = 1; i < 99; i++) {
573: if (_trackInfo[i].track == 0) { /* track doesn't exist; skip it */
574: continue;
575: }
576:
577: if (!gotFirst) {
578: *first = _trackInfo[i].track;
579: gotFirst = true;
580: }
581:
582: /* Last will keep changing till we end the loop and will end up right. */
583:
584: *last = _trackInfo[i].track;
585: }
586:
587: return(kIOReturnSuccess);
588: }
589:
590: IOReturn
591: IOCDDrive::setAudioStopAddress(positioningType addressType,cdAddress address)
592: {
593: return(_CDprovider->setAudioStopAddress(addressType,address));
594: }
595:
596: bool
597: IOCDDrive::setProvider(IOService * provider)
598: {
599: _CDprovider = OSDynamicCast(IOCDDriveNub,provider);
600:
601: if (_CDprovider == NULL) {
602: return(false);
603: } else {
604: super::setProvider(provider);
605: return(true);
606: }
607: }
608:
609: void
610: IOCDDrive::setTrackInfoEntry(struct tocTrackDescriptor *d,struct trackInfo *t)
611: {
612: t->track = d->track;
613: t->control = d->adrControl & 0xff;
614: if ((d->adrControl & 0xf0) == 0x10) { /* then Qsub info is present */
615: t->control = d->adrControl & 0xff;
616: if (d->adrControl & tt_data) { /* it's a data track */
617: t->isData = true;
618: } else {
619: t->isData = false;
620: }
621: }
622: }
623:
624: IOReturn
625: IOCDDrive::setVolume(UInt8 leftVolume,UInt8 rightVolume)
626: {
627: return(_CDprovider->setVolume(leftVolume,rightVolume));
628: }
629:
630: bool
631: IOCDDrive::showStats(void)
632: {
633: return(false);
634: }
635:
636: bool
637: IOCDDrive::trackExists(UInt32 track)
638: {
639: if (_trackInfo[track].track != 0) {
640: return(true);
641: } else {
642: return(false);
643: }
644: }
645:
646: bool
647: IOCDDrive::trackIsAudio(UInt32 track)
648: {
649: if (trackExists(track)) {
650: return(!_trackInfo[track].isData);
651: } else {
652: return(false);
653: }
654: }
655:
656: bool
657: IOCDDrive::trackIsData(UInt32 track)
658: {
659: if (trackExists(track)) {
660: return(_trackInfo[track].isData);
661: } else {
662: return(false);
663: }
664: }
665:
666: void
667: IOCDDrive::dump(char *buf,int count)
668: {
669: static char string[17] = "xxxxxxxxxxxxxxxx";
670:
671: short i;
672: char c;
673: char *cp;
674:
675: if (!count) return;
676:
677: i = 0;
678: cp = buf;
679: do {
680: c = *cp;
681: IOLog("%02x ",(c & 0xff));
682: c &= 0x7f;
683: string[i % 16] = /* (isprint(c) || (c == ' ')) ? c : */ '.';
684: if ((i % 16)==15)
685: IOLog("%s\n",string);
686: cp++; i++;
687: } while (--count);
688:
689: /* pad out for last line */
690: if (i % 16) { /* then a shortie left */
691: string[i % 16] = '\0';
692: while (i % 16) {
693: IOLog(" ");
694: i++;
695: }
696: IOLog("%s\n",string);
697: }
698: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.