1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2 /* Main file for CD-ROM support
4 * Copyright 1994 Martin Ayotte
5 * Copyright 1999, 2001 Eric Pouech
6 * Copyright 2000 Andreas Mohr
15 #include <sys/ioctl.h>
22 #include "debugtools.h"
24 #ifdef HAVE_LINUX_CDROM_H
25 # include <linux/cdrom.h>
27 #ifdef HAVE_LINUX_UCDROM_H
28 # include <linux/ucdrom.h>
30 #ifdef HAVE_SYS_CDIO_H
31 # include <sys/cdio.h>
34 DEFAULT_DEBUG_CHANNEL(cdrom);
36 /* FIXME: this is needed because we can't open simultaneously several times /dev/cdrom
37 * this should be removed when a proper device interface is implemented
43 static struct cdrom_cache cdrom_cache[26];
45 /******************************************************************
50 static int CDROM_Open(HANDLE hDevice, DWORD clientID)
52 int dev = LOWORD(clientID);
54 if (dev >= 26) return -1;
56 if (!cdrom_cache[dev].count)
62 if (GetDriveTypeA(root) != DRIVE_CDROM) return -1;
63 cdrom_cache[dev].fd = open(DRIVE_GetDevice(dev), O_RDONLY|O_NONBLOCK);
64 if (cdrom_cache[dev].fd == -1)
66 FIXME("Can't open %s: %s\n", root, strerror(errno));
70 cdrom_cache[dev].count++;
71 return cdrom_cache[dev].fd;
74 /******************************************************************
79 static void CDROM_Close(DWORD clientID, int fd)
81 int dev = LOWORD(clientID);
83 if (dev >= 26 || fd != cdrom_cache[dev].fd) FIXME("how come\n");
84 if (--cdrom_cache[dev].count == 0)
85 close(cdrom_cache[dev].fd);
88 /******************************************************************
93 static DWORD CDROM_GetStatusCode(int io)
95 if (io == 0) return 0;
98 case EIO: return STATUS_NO_MEDIA_IN_DEVICE;
100 FIXME("Unmapped error code %d: %s\n", errno, strerror(errno));
101 return STATUS_IO_DEVICE_ERROR;
104 static DWORD CDROM_GetControl(int dev, CDROM_AUDIO_CONTROL* cac)
106 cac->LbaFormat = 0; /* FIXME */
107 cac->LogicalBlocksPerSecond = 1; /* FIXME */
108 return STATUS_NOT_SUPPORTED;
111 static DWORD CDROM_GetDeviceNumber(int dev, STORAGE_DEVICE_NUMBER* devnum)
113 return STATUS_NOT_SUPPORTED;
116 static DWORD CDROM_GetDriveGeometry(int dev, DISK_GEOMETRY* dg)
119 dg->Cylinders.s.LowPart = 1; /* FIXME */
120 dg->Cylinders.s.HighPart = 0; /* FIXME */
121 dg->MediaType = 1; /* FIXME */
122 dg->TracksPerCylinder = 1; /* FIXME */
123 dg->SectorsPerTrack = 1; /* FIXME */
124 dg->BytesPerSector= 1; /* FIXME */
126 return STATUS_NOT_SUPPORTED;
129 /**************************************************************************
130 * CDROM_Reset [internal]
132 static DWORD CDROM_ResetAudio(int dev)
135 return CDROM_GetStatusCode(ioctl(dev, CDROMRESET));
136 #elif defined(__FreeBSD__) || defined(__NetBSD__)
137 return CDROM_GetStatusCode(ioctl(dev, CDIOCRESET, NULL));
139 return STATUS_NOT_SUPPORTED;
143 /******************************************************************
148 static DWORD CDROM_SetTray(int dev, BOOL doEject)
151 return CDROM_GetStatusCode(ioctl(dev, doEject ? CDROMEJECT : CDROMCLOSETRAY));
152 #elif defined(__FreeBSD__) || defined(__NetBSD__)
153 return CDROM_GetStatusCode((ioctl(dev, CDIOCALLOW, NULL)) ||
154 (ioctl(dev, doEject ? CDIOCEJECT : CDIOCCLOSE, NULL)) ||
155 (ioctl(dev, CDIOCPREVENT, NULL)));
157 return STATUS_NOT_SUPPORTED;
161 /******************************************************************
162 * CDROM_ControlEjection
166 static DWORD CDROM_ControlEjection(int dev, const PREVENT_MEDIA_REMOVAL* rmv)
168 int val = rmv->PreventMediaRemoval;
170 return CDROM_GetStatusCode(ioctl(dev, CDROM_LOCKDOOR, val));
171 #elif defined(__FreeBSD__) || defined(__NetBSD__)
172 return CDROM_GetStatusCode(ioctl(dev, (val) ? CDIOCPREVENT : CDIOCALLOW, NULL));
174 return STATUS_NOT_SUPPORTED;
178 /******************************************************************
183 static DWORD CDROM_ReadTOC(int dev, CDROM_TOC* toc)
185 DWORD ret = STATUS_NOT_SUPPORTED;
189 struct cdrom_tochdr hdr;
190 struct cdrom_tocentry entry;
192 io = ioctl(dev, CDROMREADTOCHDR, &hdr);
195 WARN("(%d) -- Error occurred (%s)!\n", dev, strerror(errno));
198 toc->FirstTrack = hdr.cdth_trk0;
199 toc->LastTrack = hdr.cdth_trk1;
201 TRACE("from=%d to=%d\n", toc->FirstTrack, toc->LastTrack);
203 for (i = toc->FirstTrack; i <= toc->LastTrack + 1; i++)
205 if (i == toc->LastTrack + 1)
207 entry.cdte_track = CDROM_LEADOUT;
209 entry.cdte_track = i;
211 entry.cdte_format = CDROM_MSF;
212 io = ioctl(dev, CDROMREADTOCENTRY, &entry);
214 WARN("error read entry (%s)\n", strerror(errno));
217 toc->TrackData[i - toc->FirstTrack].Control = entry.cdte_ctrl;
218 toc->TrackData[i - toc->FirstTrack].Adr = entry.cdte_adr;
219 /* marking last track with leadout value as index */
220 toc->TrackData[i - toc->FirstTrack].TrackNumber = entry.cdte_track;
221 toc->TrackData[i - toc->FirstTrack].Address[0] = 0;
222 toc->TrackData[i - toc->FirstTrack].Address[1] = entry.cdte_addr.msf.minute;
223 toc->TrackData[i - toc->FirstTrack].Address[2] = entry.cdte_addr.msf.second;
224 toc->TrackData[i - toc->FirstTrack].Address[3] = entry.cdte_addr.msf.frame;
227 ret = CDROM_GetStatusCode(io);
228 #elif defined(__FreeBSD__) || defined(__NetBSD__)
230 struct ioc_toc_header hdr;
231 struct ioc_read_toc_entry entry;
232 struct cd_toc_entry toc_buffer;
234 io = ioctl(dev, CDIOREADTOCHEADER, &hdr);
237 WARN("(%d) -- Error occurred (%s)!\n", dev, strerror(errno));
240 toc->FirstTrack = hdr.starting_track;
241 toc->LastTrack = hdr.ending_track;
243 TRACE("from=%d to=%d\n", toc->FirstTrack, toc->LastTrack);
245 for (i = toc->FirstTrack; i <= toc->LastTrack + 1; i++)
247 if (i == toc->LastTrack + 1)
250 entry.starting_track = LEADOUT;
252 entry.starting_track = i;
254 memset((char *)&toc_buffer, 0, sizeof(toc_buffer));
255 entry.address_format = CD_MSF_FORMAT;
256 entry.data_len = sizeof(toc_buffer);
257 entry.data = &toc_buffer;
258 io = ioctl(dev, CDIOREADTOCENTRYS, &entry);
260 WARN("error read entry (%s)\n", strerror(errno));
263 toc->TrackData[i - toc->FirstTrack].Control = toc_buffer.control;
264 toc->TrackData[i - toc->FirstTrack].Adr = toc_buffer.addr_type;
265 /* marking last track with leadout value as index */
266 toc->TrackData[i - toc->FirstTrack].TrackNumber = entry.starting_track;
267 toc->TrackData[i - toc->FirstTrack].Address[0] = 0;
268 toc->TrackData[i - toc->FirstTrack].Address[1] = toc_buffer.addr.msf.minute;
269 toc->TrackData[i - toc->FirstTrack].Address[2] = toc_buffer.addr.msf.second;
270 toc->TrackData[i - toc->FirstTrack].Address[3] = toc_buffer.addr.msf.frame;
273 ret = CDROM_GetStatusCode(io);
275 ret = STATUS_NOT_SUPPORTED;
280 /******************************************************************
285 static DWORD CDROM_GetDiskData(int dev, CDROM_DISK_DATA* data)
291 if ((ret = CDROM_ReadTOC(dev, &toc)) != 0) return ret;
293 for (i = toc.FirstTrack; i <= toc.LastTrack; i++) {
294 if (toc.TrackData[i].Control & 0x04)
295 data->DiskData |= CDROM_DISK_DATA_TRACK;
297 data->DiskData |= CDROM_DISK_AUDIO_TRACK;
302 /******************************************************************
307 static DWORD CDROM_ReadQChannel(int dev, const CDROM_SUB_Q_DATA_FORMAT* fmt,
308 SUB_Q_CHANNEL_DATA* data)
310 DWORD ret = STATUS_NOT_SUPPORTED;
312 SUB_Q_HEADER* hdr = (SUB_Q_HEADER*)data;
316 struct cdrom_subchnl sc;
317 sc.cdsc_format = CDROM_MSF;
319 io = ioctl(dev, CDROMSUBCHNL, &sc);
322 TRACE("opened or no_media (%s)!\n", strerror(errno));
323 hdr->AudioStatus = AUDIO_STATUS_NO_STATUS;
327 hdr->AudioStatus = AUDIO_STATUS_NOT_SUPPORTED;
329 switch (sc.cdsc_audiostatus) {
330 case CDROM_AUDIO_INVALID:
331 hdr->AudioStatus = AUDIO_STATUS_NOT_SUPPORTED;
333 case CDROM_AUDIO_NO_STATUS:
334 hdr->AudioStatus = AUDIO_STATUS_NO_STATUS;
336 case CDROM_AUDIO_PLAY:
337 hdr->AudioStatus = AUDIO_STATUS_IN_PROGRESS;
339 case CDROM_AUDIO_PAUSED:
340 hdr->AudioStatus = AUDIO_STATUS_PAUSED;
342 case CDROM_AUDIO_COMPLETED:
343 hdr->AudioStatus = AUDIO_STATUS_PLAY_COMPLETE;
345 case CDROM_AUDIO_ERROR:
346 hdr->AudioStatus = AUDIO_STATUS_PLAY_ERROR;
349 TRACE("status=%02X !\n", sc.cdsc_audiostatus);
354 case IOCTL_CDROM_CURRENT_POSITION:
355 size = sizeof(SUB_Q_CURRENT_POSITION);
356 data->CurrentPosition.FormatCode = sc.cdsc_format;
357 data->CurrentPosition.Control = sc.cdsc_ctrl;
358 data->CurrentPosition.ADR = sc.cdsc_adr;
359 data->CurrentPosition.TrackNumber = sc.cdsc_trk;
360 data->CurrentPosition.IndexNumber = sc.cdsc_ind;
362 data->CurrentPosition.AbsoluteAddress[0] = 0;
363 data->CurrentPosition.AbsoluteAddress[1] = sc.cdsc_absaddr.msf.minute;
364 data->CurrentPosition.AbsoluteAddress[2] = sc.cdsc_absaddr.msf.second;
365 data->CurrentPosition.AbsoluteAddress[3] = sc.cdsc_absaddr.msf.frame;
367 data->CurrentPosition.TrackRelativeAddress[0] = 0;
368 data->CurrentPosition.TrackRelativeAddress[1] = sc.cdsc_reladdr.msf.minute;
369 data->CurrentPosition.TrackRelativeAddress[2] = sc.cdsc_reladdr.msf.second;
370 data->CurrentPosition.TrackRelativeAddress[3] = sc.cdsc_reladdr.msf.frame;
372 case IOCTL_CDROM_MEDIA_CATALOG:
373 size = sizeof(SUB_Q_MEDIA_CATALOG_NUMBER);
374 data->MediaCatalog.FormatCode = IOCTL_CDROM_MEDIA_CATALOG;
376 struct cdrom_mcn mcn;
377 if ((io = ioctl(dev, CDROM_GET_MCN, &mcn)) == -1) goto end;
379 data->MediaCatalog.FormatCode = IOCTL_CDROM_MEDIA_CATALOG;
380 data->MediaCatalog.Mcval = 0; /* FIXME */
381 memcpy(data->MediaCatalog.MediaCatalog, mcn.medium_catalog_number, 14);
382 data->MediaCatalog.MediaCatalog[14] = 0;
385 case IOCTL_CDROM_TRACK_ISRC:
386 size = sizeof(SUB_Q_CURRENT_POSITION);
387 FIXME("TrackIsrc: NIY on linux");
388 data->TrackIsrc.FormatCode = IOCTL_CDROM_TRACK_ISRC;
389 data->TrackIsrc.Tcval = 0;
395 ret = CDROM_GetStatusCode(io);
396 #elif defined(__FreeBSD__) || defined(__NetBSD__)
397 struct ioc_read_subchannel read_sc;
398 struct cd_sub_channel_info sc;
400 read_sc.address_format = CD_MSF_FORMAT;
402 read_sc.data_len = sizeof(sc);
406 case IOCTL_CDROM_CURRENT_POSITION:
407 read_sc.data_format = CD_CURRENT_POSITION;
409 case IOCTL_CDROM_MEDIA_CATALOG:
410 read_sc.data_format = CD_MEDIA_CATALOG;
412 case IOCTL_CDROM_TRACK_ISRC:
413 read_sc.data_format = CD_TRACK_INFO;
414 sc.what.track_info.track_number = data->TrackIsrc.Track;
417 io = ioctl(dev, CDIOCREADSUBCHANNEL, &read_sc);
420 TRACE("opened or no_media (%s)!\n", strerror(errno));
421 hdr->AudioStatus = AUDIO_STATUS_NO_STATUS;
425 hdr->AudioStatus = AUDIO_STATUS_NOT_SUPPORTED;
427 switch (sc.header.audio_status) {
428 case CD_AS_AUDIO_INVALID:
429 hdr->AudioStatus = AUDIO_STATUS_NOT_SUPPORTED;
431 case CD_AS_NO_STATUS:
432 hdr->AudioStatus = AUDIO_STATUS_NO_STATUS;
434 case CD_AS_PLAY_IN_PROGRESS:
435 hdr->AudioStatus = AUDIO_STATUS_IN_PROGRESS;
437 case CD_AS_PLAY_PAUSED:
438 hdr->AudioStatus = AUDIO_STATUS_PAUSED;
440 case CD_AS_PLAY_COMPLETED:
441 hdr->AudioStatus = AUDIO_STATUS_PLAY_COMPLETE;
443 case CD_AS_PLAY_ERROR:
444 hdr->AudioStatus = AUDIO_STATUS_PLAY_ERROR;
447 TRACE("status=%02X !\n", sc.header.audio_status);
451 case IOCTL_CDROM_CURRENT_POSITION:
452 size = sizeof(SUB_Q_CURRENT_POSITION);
453 data->CurrentPosition.FormatCode = sc.what.position.data_format;
454 data->CurrentPosition.Control = sc.what.position.control;
455 data->CurrentPosition.ADR = sc.what.position.addr_type;
456 data->CurrentPosition.TrackNumber = sc.what.position.track_number;
457 data->CurrentPosition.IndexNumber = sc.what.position.index_number;
459 data->CurrentPosition.AbsoluteAddress[0] = 0;
460 data->CurrentPosition.AbsoluteAddress[1] = sc.what.position.absaddr.msf.minute;
461 data->CurrentPosition.AbsoluteAddress[2] = sc.what.position.absaddr.msf.second;
462 data->CurrentPosition.AbsoluteAddress[3] = sc.what.position.absaddr.msf.frame;
463 data->CurrentPosition.TrackRelativeAddress[0] = 0;
464 data->CurrentPosition.TrackRelativeAddress[1] = sc.what.position.reladdr.msf.minute;
465 data->CurrentPosition.TrackRelativeAddress[2] = sc.what.position.reladdr.msf.second;
466 data->CurrentPosition.TrackRelativeAddress[3] = sc.what.position.reladdr.msf.frame;
468 case IOCTL_CDROM_MEDIA_CATALOG:
469 size = sizeof(SUB_Q_MEDIA_CATALOG_NUMBER);
470 data->MediaCatalog.FormatCode = IOCTL_CDROM_MEDIA_CATALOG;
471 data->MediaCatalog.FormatCode = sc.what.media_catalog.data_format;
472 data->MediaCatalog.Mcval = sc.what.media_catalog.mc_valid;
473 memcpy(data->MediaCatalog.MediaCatalog, sc.what.media_catalog.mc_number, 15);
475 case IOCTL_CDROM_TRACK_ISRC:
476 size = sizeof(SUB_Q_CURRENT_POSITION);
477 data->TrackIsrc.Tcval = sc.what.track_info.ti_valid;
478 memcpy(data->TrackIsrc.TrackIsrc, sc.what.track_info.ti_number, 15);
483 ret = CDROM_GetStatusCode(io);
488 /******************************************************************
493 static DWORD CDROM_Verify(int dev)
495 /* quick implementation */
496 CDROM_SUB_Q_DATA_FORMAT fmt;
497 SUB_Q_CHANNEL_DATA data;
499 fmt.Format = IOCTL_CDROM_CURRENT_POSITION;
500 return CDROM_ReadQChannel(dev, &fmt, &data) ? 0 : 1;
503 /******************************************************************
508 static DWORD CDROM_PlayAudioMSF(int dev, const CDROM_PLAY_AUDIO_MSF* audio_msf)
510 DWORD ret = STATUS_NOT_SUPPORTED;
512 struct cdrom_msf msf;
515 msf.cdmsf_min0 = audio_msf->StartingM;
516 msf.cdmsf_sec0 = audio_msf->StartingS;
517 msf.cdmsf_frame0 = audio_msf->StartingF;
518 msf.cdmsf_min1 = audio_msf->EndingM;
519 msf.cdmsf_sec1 = audio_msf->EndingS;
520 msf.cdmsf_frame1 = audio_msf->EndingF;
522 io = ioctl(dev, CDROMSTART);
525 WARN("motor doesn't start !\n");
528 io = ioctl(dev, CDROMPLAYMSF, &msf);
531 WARN("device doesn't play !\n");
534 TRACE("msf = %d:%d:%d %d:%d:%d\n",
535 msf.cdmsf_min0, msf.cdmsf_sec0, msf.cdmsf_frame0,
536 msf.cdmsf_min1, msf.cdmsf_sec1, msf.cdmsf_frame1);
538 ret = CDROM_GetStatusCode(io);
539 #elif defined(__FreeBSD__) || defined(__NetBSD__)
540 struct ioc_play_msf msf;
543 msf.start_m = audio_msf->StartingM;
544 msf.start_s = audio_msf->StartingS;
545 msf.start_f = audio_msf->StartingF;
546 msf.end_m = audio_msf->EndingM;
547 msf.end_s = audio_msf->EndingS;
548 msf.end_f = audio_msf->EndingF;
550 io = ioctl(dev, CDIOCSTART, NULL);
553 WARN("motor doesn't start !\n");
556 io = ioctl(dev, CDIOCPLAYMSF, &msf);
559 WARN("device doesn't play !\n");
562 TRACE("msf = %d:%d:%d %d:%d:%d\n",
563 msf.start_m, msf.start_s, msf.start_f,
564 msf.end_m, msf.end_s, msf.end_f);
566 ret = CDROM_GetStatusCode(io);
571 /******************************************************************
576 static DWORD CDROM_SeekAudioMSF(int dev, const CDROM_SEEK_AUDIO_MSF* audio_msf)
579 struct cdrom_msf0 msf;
580 msf.minute = audio_msf->M;
581 msf.second = audio_msf->S;
582 msf.frame = audio_msf->F;
584 return CDROM_GetStatusCode(ioctl(dev, CDROMSEEK, &msf));
585 #elif defined(__FreeBSD__) || defined(__NetBSD__)
586 FIXME("Could a BSD expert implement the seek function ?\n");
587 return STATUS_NOT_SUPPORTED;
589 return STATUS_NOT_SUPPORTED;
593 /******************************************************************
598 static DWORD CDROM_PauseAudio(int dev)
601 return CDROM_GetStatusCode(ioctl(dev, CDROMPAUSE));
602 #elif defined(__FreeBSD__) || defined(__NetBSD__)
603 return CDROM_GetStatusCode(ioctl(dev, CDIOCPAUSE, NULL));
605 return STATUS_NOT_SUPPORTED;
609 /******************************************************************
614 static DWORD CDROM_ResumeAudio(int dev)
617 return CDROM_GetStatusCode(ioctl(dev, CDROMRESUME));
618 #elif defined(__FreeBSD__) || defined(__NetBSD__)
619 return CDROM_GetStatusCode(ioctl(dev, CDIOCRESUME, NULL));
621 return STATUS_NOT_SUPPORTED;
625 /******************************************************************
630 static DWORD CDROM_StopAudio(int dev)
633 return CDROM_GetStatusCode(ioctl(dev, CDROMSTOP));
634 #elif defined(__FreeBSD__) || defined(__NetBSD__)
635 return CDROM_GetStatusCode(ioctl(dev, CDIOCSTOP, NULL));
637 return STATUS_NOT_SUPPORTED;
641 /******************************************************************
646 static DWORD CDROM_GetVolume(int dev, VOLUME_CONTROL* vc)
649 struct cdrom_volctrl volc;
652 io = ioctl(dev, CDROMVOLREAD, &volc);
655 vc->PortVolume[0] = volc.channel0;
656 vc->PortVolume[1] = volc.channel1;
657 vc->PortVolume[2] = volc.channel2;
658 vc->PortVolume[3] = volc.channel3;
660 return CDROM_GetStatusCode(io);
661 #elif defined(__FreeBSD__) || defined(__NetBSD__)
665 io = ioctl(dev, CDIOCGETVOL, &volc);
668 vc->PortVolume[0] = volc.vol[0];
669 vc->PortVolume[1] = volc.vol[1];
670 vc->PortVolume[2] = volc.vol[2];
671 vc->PortVolume[3] = volc.vol[3];
673 return CDROM_GetStatusCode(io);
675 return STATUS_NOT_SUPPORTED;
679 /******************************************************************
684 static DWORD CDROM_SetVolume(int dev, const VOLUME_CONTROL* vc)
687 struct cdrom_volctrl volc;
689 volc.channel0 = vc->PortVolume[0];
690 volc.channel1 = vc->PortVolume[1];
691 volc.channel2 = vc->PortVolume[2];
692 volc.channel3 = vc->PortVolume[3];
694 return CDROM_GetStatusCode(ioctl(dev, CDROMVOLCTRL, &volc));
695 #elif defined(__FreeBSD__) || defined(__NetBSD__)
698 volc.vol[0] = vc->PortVolume[0];
699 volc.vol[1] = vc->PortVolume[1];
700 volc.vol[2] = vc->PortVolume[2];
701 volc.vol[3] = vc->PortVolume[3];
703 return CDROM_GetStatusCode(ioctl(dev, CDIOCSETVOL, &volc));
705 return STATUS_NOT_SUPPORTED;
709 /******************************************************************
714 static DWORD CDROM_RawRead(int dev, const RAW_READ_INFO* raw, void* buffer, DWORD len, DWORD* sz)
716 int ret = STATUS_NOT_SUPPORTED;
720 switch (raw->TrackMode)
722 case YellowMode2: sectSize = 2336; break;
723 case XAForm2: sectSize = 2328; break;
724 case CDDA: sectSize = 2352; break;
725 default: return STATUS_INVALID_PARAMETER;
727 if (len < raw->SectorCount * sectSize) return STATUS_BUFFER_TOO_SMALL;
728 /* strangely enough, it seems that sector offsets are always indicated with a size of 2048,
729 * even if a larger size if read...
733 struct cdrom_read cdr;
734 struct cdrom_read_audio cdra;
736 switch (raw->TrackMode)
739 if (raw->DiskOffset.s.HighPart) FIXME("Unsupported value\n");
740 cdr.cdread_lba = raw->DiskOffset.s.LowPart; /* FIXME ? */
741 cdr.cdread_bufaddr = buffer;
742 cdr.cdread_buflen = raw->SectorCount * sectSize;
743 io = ioctl(dev, CDROMREADMODE2, &cdr);
746 FIXME("XAForm2: NIY\n");
749 /* FIXME: the output doesn't seem 100% correct... in fact output is shifted
750 * between by NT2K box and this... should check on the same drive...
751 * otherwise, I fear a 2352/2368 mismatch somewhere in one of the drivers
753 * Anyway, that's not critical at all. We're talking of 16/32 bytes, we're
754 * talking of 0.2 ms of sound
757 if (raw->DiskOffset.s.HighPart & ~2047) FIXME("Unsupported value\n");
758 cdra.addr.lba = ((raw->DiskOffset.s.LowPart >> 11) |
759 (raw->DiskOffset.s.HighPart << (32 - 11))) - 1;
760 FIXME("reading at %u\n", cdra.addr.lba);
761 cdra.addr_format = CDROM_LBA;
762 cdra.nframes = raw->SectorCount;
764 io = ioctl(dev, CDROMREADAUDIO, &cdra);
768 #elif defined(__FreeBSD__)
770 struct ioc_read_audio ira;
772 switch (raw->TrackMode)
775 FIXME("YellowMode2: NIY\n");
778 FIXME("XAForm2: NIY\n");
782 if (raw->DiskOffset.s.HighPart & ~2047) FIXME("Unsupported value\n");
783 ira.address.lba = ((raw->DiskOffset.s.LowPart >> 11) |
784 raw->DiskOffset.s.HighPart << (32 - 11)) - 1;
785 ira.address_format = CD_LBA_FORMAT;
786 ira.nframes = raw->SectorCount;
788 io = ioctl(dev, CDIOCREADAUDIO, &ira);
792 #elif defined(__NetBSD__)
794 switch (raw->TrackMode)
797 FIXME("YellowMode2: NIY\n");
800 FIXME("XAForm2: NIY\n");
803 FIXME("CDDA: NIY\n");
808 *sz = sectSize * raw->SectorCount;
809 ret = CDROM_GetStatusCode(io);
813 /******************************************************************
814 * CDROM_DeviceIoControl
818 BOOL CDROM_DeviceIoControl(DWORD clientID, HANDLE hDevice, DWORD dwIoControlCode,
819 LPVOID lpInBuffer, DWORD nInBufferSize,
820 LPVOID lpOutBuffer, DWORD nOutBufferSize,
821 LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped)
827 TRACE("%lx[%c] %lx %lx %ld %lx %ld %lx %lx\n",
828 (DWORD)hDevice, 'A' + LOWORD(clientID), dwIoControlCode, (DWORD)lpInBuffer, nInBufferSize,
829 (DWORD)lpOutBuffer, nOutBufferSize, (DWORD)lpBytesReturned, (DWORD)lpOverlapped);
831 if (lpBytesReturned) *lpBytesReturned = 0;
834 FIXME("Overlapped isn't implemented yet\n");
835 SetLastError(STATUS_NOT_SUPPORTED);
840 dev = CDROM_Open(hDevice, clientID);
843 CDROM_GetStatusCode(-1);
847 switch (dwIoControlCode)
849 case IOCTL_STORAGE_CHECK_VERIFY:
850 case IOCTL_CDROM_CHECK_VERIFY:
852 if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
853 error = STATUS_INVALID_PARAMETER;
854 else error = CDROM_Verify(dev);
857 /* EPP case IOCTL_STORAGE_CHECK_VERIFY2: */
859 /* EPP case IOCTL_STORAGE_FIND_NEW_DEVICES: */
860 /* EPP case IOCTL_CDROM_FIND_NEW_DEVICES: */
862 case IOCTL_STORAGE_LOAD_MEDIA:
863 case IOCTL_CDROM_LOAD_MEDIA:
865 if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
866 error = STATUS_INVALID_PARAMETER;
867 else error = CDROM_SetTray(dev, FALSE);
869 case IOCTL_STORAGE_EJECT_MEDIA:
871 if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
872 error = STATUS_INVALID_PARAMETER;
873 else error = CDROM_SetTray(dev, TRUE);
876 case IOCTL_DISK_MEDIA_REMOVAL:
877 case IOCTL_STORAGE_MEDIA_REMOVAL:
878 case IOCTL_STORAGE_EJECTION_CONTROL:
879 /* FIXME the last ioctl:s is not the same as the two others...
880 * lockcount/owner should be handled */
882 if (lpOutBuffer != NULL || nOutBufferSize != 0) error = STATUS_INVALID_PARAMETER;
883 else if (nInBufferSize < sizeof(PREVENT_MEDIA_REMOVAL)) error = STATUS_BUFFER_TOO_SMALL;
884 else error = CDROM_ControlEjection(dev, (const PREVENT_MEDIA_REMOVAL*)lpInBuffer);
887 /* EPP case IOCTL_STORAGE_GET_MEDIA_TYPES: */
889 case IOCTL_STORAGE_GET_DEVICE_NUMBER:
890 sz = sizeof(STORAGE_DEVICE_NUMBER);
891 if (lpInBuffer != NULL || nInBufferSize != 0) error = STATUS_INVALID_PARAMETER;
892 else if (nOutBufferSize < sz) error = STATUS_BUFFER_TOO_SMALL;
893 else error = CDROM_GetDeviceNumber(dev, (STORAGE_DEVICE_NUMBER*)lpOutBuffer);
896 case IOCTL_STORAGE_RESET_DEVICE:
898 if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
899 error = STATUS_INVALID_PARAMETER;
900 else error = CDROM_ResetAudio(dev);
903 case IOCTL_CDROM_GET_CONTROL:
904 sz = sizeof(CDROM_AUDIO_CONTROL);
905 if (lpInBuffer != NULL || nInBufferSize != 0) error = STATUS_INVALID_PARAMETER;
906 else if (nOutBufferSize < sz) error = STATUS_BUFFER_TOO_SMALL;
907 else error = CDROM_GetControl(dev, (CDROM_AUDIO_CONTROL*)lpOutBuffer);
910 case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
911 sz = sizeof(DISK_GEOMETRY);
912 if (lpInBuffer != NULL || nInBufferSize != 0) error = STATUS_INVALID_PARAMETER;
913 else if (nOutBufferSize < sz) error = STATUS_BUFFER_TOO_SMALL;
914 else error = CDROM_GetDriveGeometry(dev, (DISK_GEOMETRY*)lpOutBuffer);
917 case IOCTL_CDROM_DISK_TYPE:
918 sz = sizeof(CDROM_DISK_DATA);
919 if (lpInBuffer != NULL || nInBufferSize != 0) error = STATUS_INVALID_PARAMETER;
920 else if (nOutBufferSize < sz) error = STATUS_BUFFER_TOO_SMALL;
921 else error = CDROM_GetDiskData(dev, (CDROM_DISK_DATA*)lpOutBuffer);
924 /* EPP case IOCTL_CDROM_GET_LAST_SESSION: */
926 case IOCTL_CDROM_READ_Q_CHANNEL:
927 sz = sizeof(SUB_Q_CHANNEL_DATA);
928 if (lpInBuffer == NULL || nInBufferSize < sizeof(CDROM_SUB_Q_DATA_FORMAT))
929 error = STATUS_INVALID_PARAMETER;
930 else if (nOutBufferSize < sz) error = STATUS_BUFFER_TOO_SMALL;
931 else error = CDROM_ReadQChannel(dev, (const CDROM_SUB_Q_DATA_FORMAT*)lpInBuffer,
932 (SUB_Q_CHANNEL_DATA*)lpOutBuffer);
935 case IOCTL_CDROM_READ_TOC:
936 sz = sizeof(CDROM_TOC);
937 if (lpInBuffer != NULL || nInBufferSize != 0) error = STATUS_INVALID_PARAMETER;
938 else if (nOutBufferSize < sz) error = STATUS_BUFFER_TOO_SMALL;
939 else error = CDROM_ReadTOC(dev, (CDROM_TOC*)lpOutBuffer);
942 /* EPP case IOCTL_CDROM_READ_TOC_EX: */
944 case IOCTL_CDROM_PAUSE_AUDIO:
946 if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
947 error = STATUS_INVALID_PARAMETER;
948 else error = CDROM_PauseAudio(dev);
950 case IOCTL_CDROM_PLAY_AUDIO_MSF:
952 if (lpOutBuffer != NULL || nOutBufferSize != 0) error = STATUS_INVALID_PARAMETER;
953 else if (nInBufferSize < sizeof(CDROM_PLAY_AUDIO_MSF)) error = STATUS_BUFFER_TOO_SMALL;
954 else error = CDROM_PlayAudioMSF(dev, (const CDROM_PLAY_AUDIO_MSF*)lpInBuffer);
956 case IOCTL_CDROM_RESUME_AUDIO:
958 if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
959 error = STATUS_INVALID_PARAMETER;
960 else error = CDROM_ResumeAudio(dev);
962 case IOCTL_CDROM_SEEK_AUDIO_MSF:
964 if (lpOutBuffer != NULL || nOutBufferSize != 0) error = STATUS_INVALID_PARAMETER;
965 else if (nInBufferSize < sizeof(CDROM_SEEK_AUDIO_MSF)) error = STATUS_BUFFER_TOO_SMALL;
966 else error = CDROM_SeekAudioMSF(dev, (const CDROM_SEEK_AUDIO_MSF*)lpInBuffer);
968 case IOCTL_CDROM_STOP_AUDIO:
970 if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
971 error = STATUS_INVALID_PARAMETER;
972 else error = CDROM_StopAudio(dev);
974 case IOCTL_CDROM_GET_VOLUME:
975 sz = sizeof(VOLUME_CONTROL);
976 if (lpInBuffer != NULL || nInBufferSize != 0) error = STATUS_INVALID_PARAMETER;
977 else if (nOutBufferSize < sz) error = STATUS_BUFFER_TOO_SMALL;
978 else error = CDROM_GetVolume(dev, (VOLUME_CONTROL*)lpOutBuffer);
980 case IOCTL_CDROM_SET_VOLUME:
982 if (lpInBuffer == NULL || nInBufferSize < sizeof(VOLUME_CONTROL) || lpOutBuffer != NULL)
983 error = STATUS_INVALID_PARAMETER;
984 else error = CDROM_SetVolume(dev, (const VOLUME_CONTROL*)lpInBuffer);
986 case IOCTL_CDROM_RAW_READ:
988 if (nInBufferSize < sizeof(RAW_READ_INFO)) error = STATUS_INVALID_PARAMETER;
989 else if (lpOutBuffer == NULL) error = STATUS_BUFFER_TOO_SMALL;
990 else error = CDROM_RawRead(dev, (const RAW_READ_INFO*)lpInBuffer,
991 lpOutBuffer, nOutBufferSize, &sz);
994 FIXME("Unsupported IOCTL %lx\n", dwIoControlCode);
996 error = STATUS_INVALID_PARAMETER;
1000 if (lpBytesReturned) *lpBytesReturned = sz;
1003 SetLastError(error);
1006 CDROM_Close(clientID, dev);