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
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "wine/port.h"
37 #include <sys/types.h>
39 #ifdef HAVE_SYS_IOCTL_H
40 #include <sys/ioctl.h>
45 #ifdef HAVE_LINUX_MAJOR_H
46 # include <linux/major.h>
48 #ifdef HAVE_LINUX_HDREG_H
49 # include <linux/hdreg.h>
51 #ifdef HAVE_LINUX_PARAM_H
52 # include <linux/param.h>
54 #ifdef HAVE_LINUX_CDROM_H
55 # include <linux/cdrom.h>
57 #ifdef HAVE_LINUX_UCDROM_H
58 # include <linux/ucdrom.h>
60 #ifdef HAVE_SYS_CDIO_H
61 # include <sys/cdio.h>
63 #ifdef HAVE_SYS_SCSIIO_H
64 # include <sys/scsiio.h>
67 #define NONAMELESSUNION
68 #define NONAMELESSSTRUCT
76 #include "wine/debug.h"
78 /* Non-Linux systems do not have linux/cdrom.h and the like, and thus
79 lack the following constants. */
82 #define CD_SECS 60 /* seconds per minute */
85 #define CD_FRAMES 75 /* frames per second */
88 static const struct iocodexs
93 {IOCTL_CDROM_UNLOAD_DRIVER, "IOCTL_CDROM_UNLOAD_DRIVER"},
94 {IOCTL_CDROM_READ_TOC, "IOCTL_CDROM_READ_TOC"},
95 {IOCTL_CDROM_GET_CONTROL, "IOCTL_CDROM_GET_CONTROL"},
96 {IOCTL_CDROM_PLAY_AUDIO_MSF, "IOCTL_CDROM_PLAY_AUDIO_MSF"},
97 {IOCTL_CDROM_SEEK_AUDIO_MSF, "IOCTL_CDROM_SEEK_AUDIO_MSF"},
98 {IOCTL_CDROM_STOP_AUDIO, "IOCTL_CDROM_STOP_AUDIO"},
99 {IOCTL_CDROM_PAUSE_AUDIO, "IOCTL_CDROM_PAUSE_AUDIO"},
100 {IOCTL_CDROM_RESUME_AUDIO, "IOCTL_CDROM_RESUME_AUDIO"},
101 {IOCTL_CDROM_GET_VOLUME, "IOCTL_CDROM_GET_VOLUME"},
102 {IOCTL_CDROM_SET_VOLUME, "IOCTL_CDROM_SET_VOLUME"},
103 {IOCTL_CDROM_READ_Q_CHANNEL, "IOCTL_CDROM_READ_Q_CHANNEL"},
104 {IOCTL_CDROM_GET_LAST_SESSION, "IOCTL_CDROM_GET_LAST_SESSION"},
105 {IOCTL_CDROM_RAW_READ, "IOCTL_CDROM_RAW_READ"},
106 {IOCTL_CDROM_DISK_TYPE, "IOCTL_CDROM_DISK_TYPE"},
107 {IOCTL_CDROM_GET_DRIVE_GEOMETRY, "IOCTL_CDROM_GET_DRIVE_GEOMETRY"},
108 {IOCTL_CDROM_CHECK_VERIFY, "IOCTL_CDROM_CHECK_VERIFY"},
109 {IOCTL_CDROM_MEDIA_REMOVAL, "IOCTL_CDROM_MEDIA_REMOVAL"},
110 {IOCTL_CDROM_EJECT_MEDIA, "IOCTL_CDROM_EJECT_MEDIA"},
111 {IOCTL_CDROM_LOAD_MEDIA, "IOCTL_CDROM_LOAD_MEDIA"},
112 {IOCTL_CDROM_RESERVE, "IOCTL_CDROM_RESERVE"},
113 {IOCTL_CDROM_RELEASE, "IOCTL_CDROM_RELEASE"},
114 {IOCTL_CDROM_FIND_NEW_DEVICES, "IOCTL_CDROM_FIND_NEW_DEVICES"}
116 static const char *iocodex(DWORD code)
119 static char buffer[25];
120 for(i=0; i<sizeof(iocodextable)/sizeof(struct iocodexs); i++)
121 if (code==iocodextable[i].code)
122 return iocodextable[i].codex;
123 sprintf(buffer, "IOCTL_CODE_%x", (int)code);
127 WINE_DEFAULT_DEBUG_CHANNEL(cdrom);
129 #define FRAME_OF_ADDR(a) (((int)(a)[1] * CD_SECS + (a)[2]) * CD_FRAMES + (a)[3])
130 #define FRAME_OF_MSF(a) (((int)(a).M * CD_SECS + (a).S) * CD_FRAMES + (a).F)
131 #define FRAME_OF_TOC(toc, idx) FRAME_OF_ADDR((toc).TrackData[idx - (toc).FirstTrack].Address)
132 #define MSF_OF_FRAME(m,fr) {int f=(fr); ((UCHAR *)&(m))[2]=f%CD_FRAMES;f/=CD_FRAMES;((UCHAR *)&(m))[1]=f%CD_SECS;((UCHAR *)&(m))[0]=f/CD_SECS;}
134 static NTSTATUS CDROM_ReadTOC(int, CDROM_TOC*);
135 static NTSTATUS CDROM_GetStatusCode(int);
141 # define IDE6_MAJOR 88
144 # define IDE7_MAJOR 89
147 # ifdef CDROM_SEND_PACKET
148 /* structure for CDROM_PACKET_COMMAND ioctl */
149 /* not all Linux versions have all the fields, so we define the
150 * structure ourselves to make sure */
151 struct linux_cdrom_generic_command
153 unsigned char cmd[CDROM_PACKET_SIZE];
154 unsigned char *buffer;
157 struct request_sense *sense;
158 unsigned char data_direction;
163 # endif /* CDROM_SEND_PACKET */
167 /* FIXME: this is needed because we can't open simultaneously several times /dev/cdrom
168 * this should be removed when a proper device interface is implemented
170 * (WS) We need this to keep track of current position and to safely
171 * detect media changes. Besides this should provide a great speed up
177 char toc_good; /* if false, will reread TOC from disk */
179 SUB_Q_CURRENT_POSITION CurrentPosition;
181 static struct cdrom_cache cdrom_cache[26];
183 /* Proposed media change function: not really needed at this time */
184 /* This is a 1 or 0 type of function */
186 static int CDROM_MediaChanged(int dev)
190 struct cdrom_tochdr hdr;
191 struct cdrom_tocentry entry;
193 if (dev < 0 || dev >= 26)
195 if ( ioctl(cdrom_cache[dev].fd, CDROMREADTOCHDR, &hdr) == -1 )
198 if ( memcmp(&hdr, &cdrom_cache[dev].hdr, sizeof(struct cdrom_tochdr)) )
201 for (i=hdr.cdth_trk0; i<=hdr.cdth_trk1+1; i++)
203 if (i == hdr.cdth_trk1 + 1)
205 entry.cdte_track = CDROM_LEADOUT;
207 entry.cdte_track = i;
209 entry.cdte_format = CDROM_MSF;
210 if ( ioctl(cdrom_cache[dev].fd, CDROMREADTOCENTRY, &entry) == -1)
212 if ( memcmp(&entry, cdrom_cache[dev].entry+i-hdr.cdth_trk0,
213 sizeof(struct cdrom_tocentry)) )
220 /******************************************************************
221 * CDROM_SyncCache [internal]
223 * Read the TOC in and store it in the cdrom_cache structure.
224 * Further requests for the TOC will be copied from the cache
225 * unless certain events like disk ejection is detected, in which
226 * case the cache will be cleared, causing it to be resynced.
229 static int CDROM_SyncCache(int dev)
233 struct cdrom_tochdr hdr;
234 struct cdrom_tocentry entry;
235 #elif defined(__FreeBSD__) || defined(__NetBSD__)
236 struct ioc_toc_header hdr;
237 struct ioc_read_toc_entry entry;
238 struct cd_toc_entry toc_buffer;
240 CDROM_TOC *toc = &cdrom_cache[dev].toc;
241 cdrom_cache[dev].toc_good = 0;
245 io = ioctl(cdrom_cache[dev].fd, CDROMREADTOCHDR, &hdr);
248 WARN("(%d) -- Error occurred (%s)!\n", dev, strerror(errno));
252 TRACE("caching toc from=%d to=%d\n", toc->FirstTrack, toc->LastTrack );
254 toc->FirstTrack = hdr.cdth_trk0;
255 toc->LastTrack = hdr.cdth_trk1;
256 tsz = sizeof(toc->FirstTrack) + sizeof(toc->LastTrack)
257 + sizeof(TRACK_DATA) * (toc->LastTrack-toc->FirstTrack+2);
258 toc->Length[0] = tsz >> 8;
259 toc->Length[1] = tsz;
261 for (i = toc->FirstTrack; i <= toc->LastTrack + 1; i++)
263 if (i == toc->LastTrack + 1)
264 entry.cdte_track = CDROM_LEADOUT;
266 entry.cdte_track = i;
267 entry.cdte_format = CDROM_MSF;
268 io = ioctl(cdrom_cache[dev].fd, CDROMREADTOCENTRY, &entry);
270 WARN("error read entry (%s)\n", strerror(errno));
273 toc->TrackData[i - toc->FirstTrack].Control = entry.cdte_ctrl;
274 toc->TrackData[i - toc->FirstTrack].Adr = entry.cdte_adr;
275 /* marking last track with leadout value as index */
276 toc->TrackData[i - toc->FirstTrack].TrackNumber = entry.cdte_track;
277 toc->TrackData[i - toc->FirstTrack].Address[0] = 0;
278 toc->TrackData[i - toc->FirstTrack].Address[1] = entry.cdte_addr.msf.minute;
279 toc->TrackData[i - toc->FirstTrack].Address[2] = entry.cdte_addr.msf.second;
280 toc->TrackData[i - toc->FirstTrack].Address[3] = entry.cdte_addr.msf.frame;
282 cdrom_cache[dev].toc_good = 1;
284 #elif defined(__FreeBSD__) || defined(__NetBSD__)
286 io = ioctl(cdrom_cache[dev].fd, CDIOREADTOCHEADER, &hdr);
289 WARN("(%d) -- Error occurred (%s)!\n", dev, strerror(errno));
292 toc->FirstTrack = hdr.starting_track;
293 toc->LastTrack = hdr.ending_track;
294 tsz = sizeof(toc->FirstTrack) + sizeof(toc->LastTrack)
295 + sizeof(TRACK_DATA) * (toc->LastTrack-toc->FirstTrack+2);
296 toc->Length[0] = tsz >> 8;
297 toc->Length[1] = tsz;
299 TRACE("caching toc from=%d to=%d\n", toc->FirstTrack, toc->LastTrack );
301 for (i = toc->FirstTrack; i <= toc->LastTrack + 1; i++)
303 if (i == toc->LastTrack + 1)
306 entry.starting_track = LEADOUT;
308 entry.starting_track = i;
310 memset((char *)&toc_buffer, 0, sizeof(toc_buffer));
311 entry.address_format = CD_MSF_FORMAT;
312 entry.data_len = sizeof(toc_buffer);
313 entry.data = &toc_buffer;
314 io = ioctl(cdrom_cache[dev].fd, CDIOREADTOCENTRYS, &entry);
316 WARN("error read entry (%s)\n", strerror(errno));
319 toc->TrackData[i - toc->FirstTrack].Control = toc_buffer.control;
320 toc->TrackData[i - toc->FirstTrack].Adr = toc_buffer.addr_type;
321 /* marking last track with leadout value as index */
322 toc->TrackData[i - toc->FirstTrack].TrackNumber = entry.starting_track;
323 toc->TrackData[i - toc->FirstTrack].Address[0] = 0;
324 toc->TrackData[i - toc->FirstTrack].Address[1] = toc_buffer.addr.msf.minute;
325 toc->TrackData[i - toc->FirstTrack].Address[2] = toc_buffer.addr.msf.second;
326 toc->TrackData[i - toc->FirstTrack].Address[3] = toc_buffer.addr.msf.frame;
328 cdrom_cache[dev].toc_good = 1;
331 return STATUS_NOT_SUPPORTED;
334 return CDROM_GetStatusCode(io);
337 static void CDROM_ClearCacheEntry(int dev)
339 cdrom_cache[dev].toc_good = 0;
344 /******************************************************************
345 * CDROM_GetInterfaceInfo
347 * Determines the ide interface (the number after the ide), and the
348 * number of the device on that interface for ide cdroms (*port == 0).
349 * Determines the scsi information for scsi cdroms (*port == 1).
350 * Returns false if the info could not be get
352 * NOTE: this function is used in CDROM_InitRegistry and CDROM_GetAddress
354 static int CDROM_GetInterfaceInfo(int fd, int* port, int* iface, int* device,int* lun)
359 #ifdef SG_EMULATED_HOST
360 if (ioctl(fd, SG_EMULATED_HOST) != -1) {
361 FIXME("not implemented for true scsi drives\n");
365 if ( fstat(fd, &st) == -1 || ! S_ISBLK(st.st_mode)) {
366 FIXME("cdrom not a block device!!!\n");
371 switch (major(st.st_rdev)) {
372 case IDE0_MAJOR: *iface = 0; break;
373 case IDE1_MAJOR: *iface = 1; break;
374 case IDE2_MAJOR: *iface = 2; break;
375 case IDE3_MAJOR: *iface = 3; break;
376 case IDE4_MAJOR: *iface = 4; break;
377 case IDE5_MAJOR: *iface = 5; break;
378 case IDE6_MAJOR: *iface = 6; break;
379 case IDE7_MAJOR: *iface = 7; break;
380 case SCSI_CDROM_MAJOR: *iface = 11; break;
382 FIXME("CD-ROM device with major ID %d not supported\n", major(st.st_rdev));
385 *device = (minor(st.st_rdev) == 63 ? 1 : 0);
388 #elif defined(__NetBSD__)
390 struct scsi_addr addr;
391 if (ioctl(fd, SCIOCIDENTIFY, &addr) != -1) {
393 case TYPE_SCSI: *port = 1;
394 *iface = addr.addr.scsi.scbus;
395 *device = addr.addr.scsi.target;
396 *lun = addr.addr.scsi.lun;
398 case TYPE_ATAPI: *port = 0;
399 *iface = addr.addr.atapi.atbus;
400 *device = addr.addr.atapi.drive;
408 #elif defined(__FreeBSD__)
409 FIXME("not implemented for BSD\n");
412 FIXME("not implemented for nonlinux\n");
418 /******************************************************************
421 * Initializes registry to contain scsi info about the cdrom in NT.
422 * All devices (even not real scsi ones) have this info in NT.
423 * TODO: for now it only works for non scsi devices
424 * NOTE: programs usually read these registry entries after sending the
425 * IOCTL_SCSI_GET_ADDRESS ioctl to the cdrom
427 void CDROM_InitRegistry(int fd)
429 int portnum, busid, targetid, lun;
430 OBJECT_ATTRIBUTES attr;
431 UNICODE_STRING nameW;
443 attr.Length = sizeof(attr);
444 attr.RootDirectory = 0;
445 attr.ObjectName = &nameW;
447 attr.SecurityDescriptor = NULL;
448 attr.SecurityQualityOfService = NULL;
450 if ( ! CDROM_GetInterfaceInfo(fd, &portnum, &busid, &targetid, &lun))
453 /* Ensure there is Scsi key */
454 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\HARDWARE\\DEVICEMAP\\Scsi" ) ||
455 NtCreateKey( &scsiKey, KEY_ALL_ACCESS, &attr, 0,
456 NULL, REG_OPTION_VOLATILE, &disp ))
458 ERR("Cannot create DEVICEMAP\\Scsi registry key\n" );
461 RtlFreeUnicodeString( &nameW );
463 snprintf(buffer,sizeof(buffer),"Scsi Port %d",portnum);
464 attr.RootDirectory = scsiKey;
465 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, buffer ) ||
466 NtCreateKey( &portKey, KEY_ALL_ACCESS, &attr, 0,
467 NULL, REG_OPTION_VOLATILE, &disp ))
469 ERR("Cannot create DEVICEMAP\\Scsi Port registry key\n" );
472 RtlFreeUnicodeString( &nameW );
474 RtlCreateUnicodeStringFromAsciiz( &nameW, "Driver" );
476 RtlMultiByteToUnicodeN( dataW, 50, &lenW, data, strlen(data));
477 NtSetValueKey( portKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW );
478 RtlFreeUnicodeString( &nameW );
480 RtlCreateUnicodeStringFromAsciiz( &nameW, "FirstBusTimeScanInMs" );
481 NtSetValueKey( portKey,&nameW, 0, REG_DWORD, (BYTE *)&value, sizeof(DWORD));
482 RtlFreeUnicodeString( &nameW );
487 if (ioctl(fd,HDIO_GET_DMA, &dma) != -1) {
489 TRACE("setting dma to %lx\n", value);
493 RtlCreateUnicodeStringFromAsciiz( &nameW, "DMAEnabled" );
494 NtSetValueKey( portKey,&nameW, 0, REG_DWORD, (BYTE *)&value, sizeof(DWORD));
495 RtlFreeUnicodeString( &nameW );
497 snprintf(buffer,40,"Scsi Bus %d", busid);
498 attr.RootDirectory = portKey;
499 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, buffer ) ||
500 NtCreateKey( &busKey, KEY_ALL_ACCESS, &attr, 0,
501 NULL, REG_OPTION_VOLATILE, &disp ))
503 ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus registry key\n" );
506 RtlFreeUnicodeString( &nameW );
508 attr.RootDirectory = busKey;
509 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Initiator Id 255" ) ||
510 NtCreateKey( &targetKey, KEY_ALL_ACCESS, &attr, 0,
511 NULL, REG_OPTION_VOLATILE, &disp ))
513 ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus\\Initiator Id 255 registry key\n" );
516 RtlFreeUnicodeString( &nameW );
517 NtClose( targetKey );
519 snprintf(buffer,40,"Target Id %d", targetid);
520 attr.RootDirectory = busKey;
521 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, buffer ) ||
522 NtCreateKey( &targetKey, KEY_ALL_ACCESS, &attr, 0,
523 NULL, REG_OPTION_VOLATILE, &disp ))
525 ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus 0\\Target Id registry key\n" );
528 RtlFreeUnicodeString( &nameW );
530 RtlCreateUnicodeStringFromAsciiz( &nameW, "Type" );
531 data = "CdRomPeripheral";
532 RtlMultiByteToUnicodeN( dataW, 50, &lenW, data, strlen(data));
533 NtSetValueKey( targetKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW );
534 RtlFreeUnicodeString( &nameW );
535 /* FIXME - maybe read the real identifier?? */
536 RtlCreateUnicodeStringFromAsciiz( &nameW, "Identifier" );
538 RtlMultiByteToUnicodeN( dataW, 50, &lenW, data, strlen(data));
539 NtSetValueKey( targetKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW );
540 RtlFreeUnicodeString( &nameW );
541 /* FIXME - we always use Cdrom0 - do not know about the nt behaviour */
542 RtlCreateUnicodeStringFromAsciiz( &nameW, "DeviceName" );
544 RtlMultiByteToUnicodeN( dataW, 50, &lenW, data, strlen(data));
545 NtSetValueKey( targetKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW );
546 RtlFreeUnicodeString( &nameW );
548 NtClose( targetKey );
555 /******************************************************************
559 static NTSTATUS CDROM_Open(HANDLE hDevice, DWORD clientID, int* dev)
561 *dev = LOWORD(clientID);
563 if (*dev >= 26) return STATUS_NO_SUCH_DEVICE;
565 if (!cdrom_cache[*dev].count)
570 strcpy(root, "A:\\");
572 if (GetDriveTypeA(root) != DRIVE_CDROM) return STATUS_NO_SUCH_DEVICE;
573 if (!(device = DRIVE_GetDevice(*dev))) return STATUS_NO_SUCH_DEVICE;
574 cdrom_cache[*dev].fd = open(device, O_RDONLY|O_NONBLOCK);
575 if (cdrom_cache[*dev].fd == -1)
577 FIXME("Can't open configured CD-ROM drive at %s (device %s): %s\n",
578 root, DRIVE_GetDevice(*dev), strerror(errno));
579 return STATUS_NO_SUCH_DEVICE;
582 cdrom_cache[*dev].count++;
583 TRACE("%d, %d, %d\n", *dev, cdrom_cache[*dev].fd, cdrom_cache[*dev].count);
584 return STATUS_SUCCESS;
587 /******************************************************************
592 static void CDROM_Close(DWORD clientID)
594 int dev = LOWORD(clientID);
596 if (dev >= 26 /*|| fd != cdrom_cache[dev].fd*/) FIXME("how come\n");
597 if (--cdrom_cache[dev].count == 0)
599 close(cdrom_cache[dev].fd);
600 cdrom_cache[dev].fd = -1;
604 /******************************************************************
605 * CDROM_GetStatusCode
609 static NTSTATUS CDROM_GetStatusCode(int io)
611 if (io == 0) return STATUS_SUCCESS;
618 return STATUS_NO_MEDIA_IN_DEVICE;
620 return STATUS_ACCESS_DENIED;
622 return STATUS_INVALID_PARAMETER;
623 /* case EBADF: Bad file descriptor */
625 FIXME("Unmapped error code %d: %s\n", errno, strerror(errno));
626 return STATUS_IO_DEVICE_ERROR;
629 /******************************************************************
633 static NTSTATUS CDROM_GetControl(int dev, CDROM_AUDIO_CONTROL* cac)
635 cac->LbaFormat = 0; /* FIXME */
636 cac->LogicalBlocksPerSecond = 1; /* FIXME */
637 return STATUS_NOT_SUPPORTED;
640 /******************************************************************
641 * CDROM_GetDeviceNumber
644 static NTSTATUS CDROM_GetDeviceNumber(int dev, STORAGE_DEVICE_NUMBER* devnum)
646 return STATUS_NOT_SUPPORTED;
649 /******************************************************************
650 * CDROM_GetDriveGeometry
653 static NTSTATUS CDROM_GetDriveGeometry(int dev, DISK_GEOMETRY* dg)
659 if ((ret = CDROM_ReadTOC(dev, &toc)) != 0) return ret;
661 fsize = FRAME_OF_TOC(toc, toc.LastTrack+1)
662 - FRAME_OF_TOC(toc, 1); /* Total size in frames */
664 dg->Cylinders.s.LowPart = fsize / (64 * 32);
665 dg->Cylinders.s.HighPart = 0;
666 dg->MediaType = RemovableMedia;
667 dg->TracksPerCylinder = 64;
668 dg->SectorsPerTrack = 32;
669 dg->BytesPerSector= 2048;
673 /**************************************************************************
674 * CDROM_Reset [internal]
676 static NTSTATUS CDROM_ResetAudio(int dev)
679 return CDROM_GetStatusCode(ioctl(cdrom_cache[dev].fd, CDROMRESET));
680 #elif defined(__FreeBSD__) || defined(__NetBSD__)
681 return CDROM_GetStatusCode(ioctl(cdrom_cache[dev].fd, CDIOCRESET, NULL));
683 return STATUS_NOT_SUPPORTED;
687 /******************************************************************
692 static NTSTATUS CDROM_SetTray(int dev, BOOL doEject)
695 return CDROM_GetStatusCode(ioctl(cdrom_cache[dev].fd, doEject ? CDROMEJECT : CDROMCLOSETRAY));
696 #elif defined(__FreeBSD__) || defined(__NetBSD__)
697 return CDROM_GetStatusCode((ioctl(cdrom_cache[dev].fd, CDIOCALLOW, NULL)) ||
698 (ioctl(cdrom_cache[dev].fd, doEject ? CDIOCEJECT : CDIOCCLOSE, NULL)) ||
699 (ioctl(cdrom_cache[dev].fd, CDIOCPREVENT, NULL)));
701 return STATUS_NOT_SUPPORTED;
705 /******************************************************************
706 * CDROM_ControlEjection
710 static NTSTATUS CDROM_ControlEjection(int dev, const PREVENT_MEDIA_REMOVAL* rmv)
713 return CDROM_GetStatusCode(ioctl(cdrom_cache[dev].fd, CDROM_LOCKDOOR, rmv->PreventMediaRemoval));
714 #elif defined(__FreeBSD__) || defined(__NetBSD__)
715 return CDROM_GetStatusCode(ioctl(cdrom_cache[dev].fd, (rmv->PreventMediaRemoval) ? CDIOCPREVENT : CDIOCALLOW, NULL));
717 return STATUS_NOT_SUPPORTED;
721 /******************************************************************
726 static NTSTATUS CDROM_ReadTOC(int dev, CDROM_TOC* toc)
728 NTSTATUS ret = STATUS_NOT_SUPPORTED;
730 if (dev < 0 || dev >= 26)
731 return STATUS_INVALID_PARAMETER;
732 if ( !cdrom_cache[dev].toc_good ) {
733 ret = CDROM_SyncCache(dev);
737 *toc = cdrom_cache[dev].toc;
738 return STATUS_SUCCESS;
741 /******************************************************************
746 static NTSTATUS CDROM_GetDiskData(int dev, CDROM_DISK_DATA* data)
752 if ((ret = CDROM_ReadTOC(dev, &toc)) != 0) return ret;
754 for (i = toc.FirstTrack; i <= toc.LastTrack; i++) {
755 if (toc.TrackData[i-toc.FirstTrack].Control & 0x04)
756 data->DiskData |= CDROM_DISK_DATA_TRACK;
758 data->DiskData |= CDROM_DISK_AUDIO_TRACK;
760 return STATUS_SUCCESS;
763 /******************************************************************
768 static NTSTATUS CDROM_ReadQChannel(int dev, const CDROM_SUB_Q_DATA_FORMAT* fmt,
769 SUB_Q_CHANNEL_DATA* data)
771 NTSTATUS ret = STATUS_NOT_SUPPORTED;
774 SUB_Q_HEADER* hdr = (SUB_Q_HEADER*)data;
776 struct cdrom_subchnl sc;
777 sc.cdsc_format = CDROM_MSF;
779 io = ioctl(cdrom_cache[dev].fd, CDROMSUBCHNL, &sc);
782 TRACE("opened or no_media (%s)!\n", strerror(errno));
783 hdr->AudioStatus = AUDIO_STATUS_NO_STATUS;
784 CDROM_ClearCacheEntry(dev);
788 hdr->AudioStatus = AUDIO_STATUS_NOT_SUPPORTED;
790 switch (sc.cdsc_audiostatus) {
791 case CDROM_AUDIO_INVALID:
792 CDROM_ClearCacheEntry(dev);
793 hdr->AudioStatus = AUDIO_STATUS_NOT_SUPPORTED;
795 case CDROM_AUDIO_NO_STATUS:
796 CDROM_ClearCacheEntry(dev);
797 hdr->AudioStatus = AUDIO_STATUS_NO_STATUS;
799 case CDROM_AUDIO_PLAY:
800 hdr->AudioStatus = AUDIO_STATUS_IN_PROGRESS;
802 case CDROM_AUDIO_PAUSED:
803 hdr->AudioStatus = AUDIO_STATUS_PAUSED;
805 case CDROM_AUDIO_COMPLETED:
806 hdr->AudioStatus = AUDIO_STATUS_PLAY_COMPLETE;
808 case CDROM_AUDIO_ERROR:
809 hdr->AudioStatus = AUDIO_STATUS_PLAY_ERROR;
812 TRACE("status=%02X !\n", sc.cdsc_audiostatus);
817 case IOCTL_CDROM_CURRENT_POSITION:
818 size = sizeof(SUB_Q_CURRENT_POSITION);
819 if (hdr->AudioStatus==AUDIO_STATUS_IN_PROGRESS) {
820 data->CurrentPosition.FormatCode = IOCTL_CDROM_CURRENT_POSITION;
821 data->CurrentPosition.Control = sc.cdsc_ctrl;
822 data->CurrentPosition.ADR = sc.cdsc_adr;
823 data->CurrentPosition.TrackNumber = sc.cdsc_trk;
824 data->CurrentPosition.IndexNumber = sc.cdsc_ind;
826 data->CurrentPosition.AbsoluteAddress[0] = 0;
827 data->CurrentPosition.AbsoluteAddress[1] = sc.cdsc_absaddr.msf.minute;
828 data->CurrentPosition.AbsoluteAddress[2] = sc.cdsc_absaddr.msf.second;
829 data->CurrentPosition.AbsoluteAddress[3] = sc.cdsc_absaddr.msf.frame;
831 data->CurrentPosition.TrackRelativeAddress[0] = 0;
832 data->CurrentPosition.TrackRelativeAddress[1] = sc.cdsc_reladdr.msf.minute;
833 data->CurrentPosition.TrackRelativeAddress[2] = sc.cdsc_reladdr.msf.second;
834 data->CurrentPosition.TrackRelativeAddress[3] = sc.cdsc_reladdr.msf.frame;
836 cdrom_cache[dev].CurrentPosition = data->CurrentPosition;
838 else /* not playing */
840 cdrom_cache[dev].CurrentPosition.Header = *hdr; /* Preserve header info */
841 data->CurrentPosition = cdrom_cache[dev].CurrentPosition;
844 case IOCTL_CDROM_MEDIA_CATALOG:
845 size = sizeof(SUB_Q_MEDIA_CATALOG_NUMBER);
846 data->MediaCatalog.FormatCode = IOCTL_CDROM_MEDIA_CATALOG;
848 struct cdrom_mcn mcn;
849 if ((io = ioctl(cdrom_cache[dev].fd, CDROM_GET_MCN, &mcn)) == -1) goto end;
851 data->MediaCatalog.FormatCode = IOCTL_CDROM_MEDIA_CATALOG;
852 data->MediaCatalog.Mcval = 0; /* FIXME */
853 memcpy(data->MediaCatalog.MediaCatalog, mcn.medium_catalog_number, 14);
854 data->MediaCatalog.MediaCatalog[14] = 0;
857 case IOCTL_CDROM_TRACK_ISRC:
858 size = sizeof(SUB_Q_CURRENT_POSITION);
859 FIXME("TrackIsrc: NIY on linux\n");
860 data->TrackIsrc.FormatCode = IOCTL_CDROM_TRACK_ISRC;
861 data->TrackIsrc.Tcval = 0;
867 ret = CDROM_GetStatusCode(io);
868 #elif defined(__FreeBSD__) || defined(__NetBSD__)
870 SUB_Q_HEADER* hdr = (SUB_Q_HEADER*)data;
872 struct ioc_read_subchannel read_sc;
873 struct cd_sub_channel_info sc;
875 read_sc.address_format = CD_MSF_FORMAT;
877 read_sc.data_len = sizeof(sc);
881 case IOCTL_CDROM_CURRENT_POSITION:
882 read_sc.data_format = CD_CURRENT_POSITION;
884 case IOCTL_CDROM_MEDIA_CATALOG:
885 read_sc.data_format = CD_MEDIA_CATALOG;
887 case IOCTL_CDROM_TRACK_ISRC:
888 read_sc.data_format = CD_TRACK_INFO;
889 sc.what.track_info.track_number = data->TrackIsrc.Track;
892 io = ioctl(cdrom_cache[dev].fd, CDIOCREADSUBCHANNEL, &read_sc);
895 TRACE("opened or no_media (%s)!\n", strerror(errno));
896 CDROM_ClearCacheEntry(dev);
897 hdr->AudioStatus = AUDIO_STATUS_NO_STATUS;
901 hdr->AudioStatus = AUDIO_STATUS_NOT_SUPPORTED;
903 switch (sc.header.audio_status) {
904 case CD_AS_AUDIO_INVALID:
905 CDROM_ClearCacheEntry(dev);
906 hdr->AudioStatus = AUDIO_STATUS_NOT_SUPPORTED;
908 case CD_AS_NO_STATUS:
909 CDROM_ClearCacheEntry(dev);
910 hdr->AudioStatus = AUDIO_STATUS_NO_STATUS;
912 case CD_AS_PLAY_IN_PROGRESS:
913 hdr->AudioStatus = AUDIO_STATUS_IN_PROGRESS;
915 case CD_AS_PLAY_PAUSED:
916 hdr->AudioStatus = AUDIO_STATUS_PAUSED;
918 case CD_AS_PLAY_COMPLETED:
919 hdr->AudioStatus = AUDIO_STATUS_PLAY_COMPLETE;
921 case CD_AS_PLAY_ERROR:
922 hdr->AudioStatus = AUDIO_STATUS_PLAY_ERROR;
925 TRACE("status=%02X !\n", sc.header.audio_status);
929 case IOCTL_CDROM_CURRENT_POSITION:
930 size = sizeof(SUB_Q_CURRENT_POSITION);
931 if (hdr->AudioStatus==AUDIO_STATUS_IN_PROGRESS) {
932 data->CurrentPosition.FormatCode = IOCTL_CDROM_CURRENT_POSITION;
933 data->CurrentPosition.Control = sc.what.position.control;
934 data->CurrentPosition.ADR = sc.what.position.addr_type;
935 data->CurrentPosition.TrackNumber = sc.what.position.track_number;
936 data->CurrentPosition.IndexNumber = sc.what.position.index_number;
938 data->CurrentPosition.AbsoluteAddress[0] = 0;
939 data->CurrentPosition.AbsoluteAddress[1] = sc.what.position.absaddr.msf.minute;
940 data->CurrentPosition.AbsoluteAddress[2] = sc.what.position.absaddr.msf.second;
941 data->CurrentPosition.AbsoluteAddress[3] = sc.what.position.absaddr.msf.frame;
942 data->CurrentPosition.TrackRelativeAddress[0] = 0;
943 data->CurrentPosition.TrackRelativeAddress[1] = sc.what.position.reladdr.msf.minute;
944 data->CurrentPosition.TrackRelativeAddress[2] = sc.what.position.reladdr.msf.second;
945 data->CurrentPosition.TrackRelativeAddress[3] = sc.what.position.reladdr.msf.frame;
946 cdrom_cache[dev].CurrentPosition = data->CurrentPosition;
948 else { /* not playing */
949 cdrom_cache[dev].CurrentPosition.Header = *hdr; /* Preserve header info */
950 data->CurrentPosition = cdrom_cache[dev].CurrentPosition;
953 case IOCTL_CDROM_MEDIA_CATALOG:
954 size = sizeof(SUB_Q_MEDIA_CATALOG_NUMBER);
955 data->MediaCatalog.FormatCode = IOCTL_CDROM_MEDIA_CATALOG;
956 data->MediaCatalog.Mcval = sc.what.media_catalog.mc_valid;
957 memcpy(data->MediaCatalog.MediaCatalog, sc.what.media_catalog.mc_number, 15);
959 case IOCTL_CDROM_TRACK_ISRC:
960 size = sizeof(SUB_Q_CURRENT_POSITION);
961 data->TrackIsrc.FormatCode = IOCTL_CDROM_TRACK_ISRC;
962 data->TrackIsrc.Tcval = sc.what.track_info.ti_valid;
963 memcpy(data->TrackIsrc.TrackIsrc, sc.what.track_info.ti_number, 15);
968 ret = CDROM_GetStatusCode(io);
973 /******************************************************************
978 static NTSTATUS CDROM_Verify(int dev)
980 /* quick implementation */
981 CDROM_SUB_Q_DATA_FORMAT fmt;
982 SUB_Q_CHANNEL_DATA data;
984 fmt.Format = IOCTL_CDROM_CURRENT_POSITION;
985 return CDROM_ReadQChannel(dev, &fmt, &data) ? 1 : 0;
988 /******************************************************************
993 static NTSTATUS CDROM_PlayAudioMSF(int dev, const CDROM_PLAY_AUDIO_MSF* audio_msf)
995 NTSTATUS ret = STATUS_NOT_SUPPORTED;
997 struct cdrom_msf msf;
1000 msf.cdmsf_min0 = audio_msf->StartingM;
1001 msf.cdmsf_sec0 = audio_msf->StartingS;
1002 msf.cdmsf_frame0 = audio_msf->StartingF;
1003 msf.cdmsf_min1 = audio_msf->EndingM;
1004 msf.cdmsf_sec1 = audio_msf->EndingS;
1005 msf.cdmsf_frame1 = audio_msf->EndingF;
1007 io = ioctl(cdrom_cache[dev].fd, CDROMSTART);
1010 WARN("motor doesn't start !\n");
1013 io = ioctl(cdrom_cache[dev].fd, CDROMPLAYMSF, &msf);
1016 WARN("device doesn't play !\n");
1019 TRACE("msf = %d:%d:%d %d:%d:%d\n",
1020 msf.cdmsf_min0, msf.cdmsf_sec0, msf.cdmsf_frame0,
1021 msf.cdmsf_min1, msf.cdmsf_sec1, msf.cdmsf_frame1);
1023 ret = CDROM_GetStatusCode(io);
1024 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1025 struct ioc_play_msf msf;
1028 msf.start_m = audio_msf->StartingM;
1029 msf.start_s = audio_msf->StartingS;
1030 msf.start_f = audio_msf->StartingF;
1031 msf.end_m = audio_msf->EndingM;
1032 msf.end_s = audio_msf->EndingS;
1033 msf.end_f = audio_msf->EndingF;
1035 io = ioctl(cdrom_cache[dev].fd, CDIOCSTART, NULL);
1038 WARN("motor doesn't start !\n");
1041 io = ioctl(cdrom_cache[dev].fd, CDIOCPLAYMSF, &msf);
1044 WARN("device doesn't play !\n");
1047 TRACE("msf = %d:%d:%d %d:%d:%d\n",
1048 msf.start_m, msf.start_s, msf.start_f,
1049 msf.end_m, msf.end_s, msf.end_f);
1051 ret = CDROM_GetStatusCode(io);
1056 /******************************************************************
1057 * CDROM_SeekAudioMSF
1061 static NTSTATUS CDROM_SeekAudioMSF(int dev, const CDROM_SEEK_AUDIO_MSF* audio_msf)
1065 SUB_Q_CURRENT_POSITION *cp;
1067 struct cdrom_msf0 msf;
1068 struct cdrom_subchnl sc;
1069 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1070 struct ioc_play_msf msf;
1071 struct ioc_read_subchannel read_sc;
1072 struct cd_sub_channel_info sc;
1076 /* Use the information on the TOC to compute the new current
1077 * position, which is shadowed on the cache. [Portable]. */
1078 frame = FRAME_OF_MSF(*audio_msf);
1079 cp = &cdrom_cache[dev].CurrentPosition;
1080 if ((io = CDROM_ReadTOC(dev, &toc)) != 0) return io;
1082 for(i=toc.FirstTrack;i<=toc.LastTrack+1;i++)
1083 if (FRAME_OF_TOC(toc,i)>frame) break;
1084 if (i <= toc.FirstTrack || i > toc.LastTrack+1)
1085 return STATUS_INVALID_PARAMETER;
1087 cp->FormatCode = IOCTL_CDROM_CURRENT_POSITION;
1088 cp->Control = toc.TrackData[i-toc.FirstTrack].Control;
1089 cp->ADR = toc.TrackData[i-toc.FirstTrack].Adr;
1090 cp->TrackNumber = toc.TrackData[i-toc.FirstTrack].TrackNumber;
1091 cp->IndexNumber = 0; /* FIXME: where do they keep these? */
1092 cp->AbsoluteAddress[0] = 0;
1093 cp->AbsoluteAddress[1] = toc.TrackData[i-toc.FirstTrack].Address[1];
1094 cp->AbsoluteAddress[2] = toc.TrackData[i-toc.FirstTrack].Address[2];
1095 cp->AbsoluteAddress[3] = toc.TrackData[i-toc.FirstTrack].Address[3];
1096 frame -= FRAME_OF_TOC(toc,i);
1097 cp->TrackRelativeAddress[0] = 0;
1098 MSF_OF_FRAME(cp->TrackRelativeAddress[1], frame);
1100 /* If playing, then issue a seek command, otherwise do nothing */
1102 sc.cdsc_format = CDROM_MSF;
1104 io = ioctl(cdrom_cache[dev].fd, CDROMSUBCHNL, &sc);
1107 TRACE("opened or no_media (%s)!\n", strerror(errno));
1108 CDROM_ClearCacheEntry(dev);
1109 return CDROM_GetStatusCode(io);
1111 if (sc.cdsc_audiostatus==CDROM_AUDIO_PLAY)
1113 msf.minute = audio_msf->M;
1114 msf.second = audio_msf->S;
1115 msf.frame = audio_msf->F;
1116 return CDROM_GetStatusCode(ioctl(cdrom_cache[dev].fd, CDROMSEEK, &msf));
1118 return STATUS_SUCCESS;
1119 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1120 read_sc.address_format = CD_MSF_FORMAT;
1122 read_sc.data_len = sizeof(sc);
1124 read_sc.data_format = CD_CURRENT_POSITION;
1126 io = ioctl(cdrom_cache[dev].fd, CDIOCREADSUBCHANNEL, &read_sc);
1129 TRACE("opened or no_media (%s)!\n", strerror(errno));
1130 CDROM_ClearCacheEntry(dev);
1131 return CDROM_GetStatusCode(io);
1133 if (sc.header.audio_status==CD_AS_PLAY_IN_PROGRESS)
1136 msf.start_m = audio_msf->M;
1137 msf.start_s = audio_msf->S;
1138 msf.start_f = audio_msf->F;
1139 final_frame = FRAME_OF_TOC(toc,toc.LastTrack+1)-1;
1140 MSF_OF_FRAME(msf.end_m, final_frame);
1142 return CDROM_GetStatusCode(ioctl(cdrom_cache[dev].fd, CDIOCPLAYMSF, &msf));
1144 return STATUS_SUCCESS;
1146 return STATUS_NOT_SUPPORTED;
1150 /******************************************************************
1155 static NTSTATUS CDROM_PauseAudio(int dev)
1158 return CDROM_GetStatusCode(ioctl(cdrom_cache[dev].fd, CDROMPAUSE));
1159 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1160 return CDROM_GetStatusCode(ioctl(cdrom_cache[dev].fd, CDIOCPAUSE, NULL));
1162 return STATUS_NOT_SUPPORTED;
1166 /******************************************************************
1171 static NTSTATUS CDROM_ResumeAudio(int dev)
1174 return CDROM_GetStatusCode(ioctl(cdrom_cache[dev].fd, CDROMRESUME));
1175 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1176 return CDROM_GetStatusCode(ioctl(cdrom_cache[dev].fd, CDIOCRESUME, NULL));
1178 return STATUS_NOT_SUPPORTED;
1182 /******************************************************************
1187 static NTSTATUS CDROM_StopAudio(int dev)
1190 return CDROM_GetStatusCode(ioctl(cdrom_cache[dev].fd, CDROMSTOP));
1191 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1192 return CDROM_GetStatusCode(ioctl(cdrom_cache[dev].fd, CDIOCSTOP, NULL));
1194 return STATUS_NOT_SUPPORTED;
1198 /******************************************************************
1203 static NTSTATUS CDROM_GetVolume(int dev, VOLUME_CONTROL* vc)
1206 struct cdrom_volctrl volc;
1209 io = ioctl(cdrom_cache[dev].fd, CDROMVOLREAD, &volc);
1212 vc->PortVolume[0] = volc.channel0;
1213 vc->PortVolume[1] = volc.channel1;
1214 vc->PortVolume[2] = volc.channel2;
1215 vc->PortVolume[3] = volc.channel3;
1217 return CDROM_GetStatusCode(io);
1218 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1219 struct ioc_vol volc;
1222 io = ioctl(cdrom_cache[dev].fd, CDIOCGETVOL, &volc);
1225 vc->PortVolume[0] = volc.vol[0];
1226 vc->PortVolume[1] = volc.vol[1];
1227 vc->PortVolume[2] = volc.vol[2];
1228 vc->PortVolume[3] = volc.vol[3];
1230 return CDROM_GetStatusCode(io);
1232 return STATUS_NOT_SUPPORTED;
1236 /******************************************************************
1241 static NTSTATUS CDROM_SetVolume(int dev, const VOLUME_CONTROL* vc)
1244 struct cdrom_volctrl volc;
1246 volc.channel0 = vc->PortVolume[0];
1247 volc.channel1 = vc->PortVolume[1];
1248 volc.channel2 = vc->PortVolume[2];
1249 volc.channel3 = vc->PortVolume[3];
1251 return CDROM_GetStatusCode(ioctl(cdrom_cache[dev].fd, CDROMVOLCTRL, &volc));
1252 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1253 struct ioc_vol volc;
1255 volc.vol[0] = vc->PortVolume[0];
1256 volc.vol[1] = vc->PortVolume[1];
1257 volc.vol[2] = vc->PortVolume[2];
1258 volc.vol[3] = vc->PortVolume[3];
1260 return CDROM_GetStatusCode(ioctl(cdrom_cache[dev].fd, CDIOCSETVOL, &volc));
1262 return STATUS_NOT_SUPPORTED;
1266 /******************************************************************
1271 static NTSTATUS CDROM_RawRead(int dev, const RAW_READ_INFO* raw, void* buffer, DWORD len, DWORD* sz)
1273 int ret = STATUS_NOT_SUPPORTED;
1277 switch (raw->TrackMode)
1279 case YellowMode2: sectSize = 2336; break;
1280 case XAForm2: sectSize = 2328; break;
1281 case CDDA: sectSize = 2352; break;
1282 default: return STATUS_INVALID_PARAMETER;
1284 if (len < raw->SectorCount * sectSize) return STATUS_BUFFER_TOO_SMALL;
1285 /* strangely enough, it seems that sector offsets are always indicated with a size of 2048,
1286 * even if a larger size if read...
1290 struct cdrom_read cdr;
1291 struct cdrom_read_audio cdra;
1293 switch (raw->TrackMode)
1296 if (raw->DiskOffset.s.HighPart) FIXME("Unsupported value\n");
1297 cdr.cdread_lba = raw->DiskOffset.s.LowPart; /* FIXME ? */
1298 cdr.cdread_bufaddr = buffer;
1299 cdr.cdread_buflen = raw->SectorCount * sectSize;
1300 io = ioctl(cdrom_cache[dev].fd, CDROMREADMODE2, &cdr);
1303 FIXME("XAForm2: NIY\n");
1306 /* FIXME: the output doesn't seem 100% correct... in fact output is shifted
1307 * between by NT2K box and this... should check on the same drive...
1308 * otherwise, I fear a 2352/2368 mismatch somewhere in one of the drivers
1310 * Anyway, that's not critical at all. We're talking of 16/32 bytes, we're
1311 * talking of 0.2 ms of sound
1313 /* 2048 = 2 ** 11 */
1314 if (raw->DiskOffset.s.HighPart & ~2047) FIXME("Unsupported value\n");
1315 cdra.addr.lba = ((raw->DiskOffset.s.LowPart >> 11) |
1316 (raw->DiskOffset.s.HighPart << (32 - 11))) - 1;
1317 FIXME("reading at %u\n", cdra.addr.lba);
1318 cdra.addr_format = CDROM_LBA;
1319 cdra.nframes = raw->SectorCount;
1321 io = ioctl(cdrom_cache[dev].fd, CDROMREADAUDIO, &cdra);
1324 FIXME("NIY: %d\n", raw->TrackMode);
1328 #elif defined(__FreeBSD__)
1330 struct ioc_read_audio ira;
1332 switch (raw->TrackMode)
1335 FIXME("YellowMode2: NIY\n");
1338 FIXME("XAForm2: NIY\n");
1341 /* 2048 = 2 ** 11 */
1342 if (raw->DiskOffset.s.HighPart & ~2047) FIXME("Unsupported value\n");
1343 ira.address.lba = ((raw->DiskOffset.s.LowPart >> 11) |
1344 raw->DiskOffset.s.HighPart << (32 - 11)) - 1;
1345 ira.address_format = CD_LBA_FORMAT;
1346 ira.nframes = raw->SectorCount;
1347 ira.buffer = buffer;
1348 io = ioctl(cdrom_cache[dev].fd, CDIOCREADAUDIO, &ira);
1352 #elif defined(__NetBSD__)
1354 switch (raw->TrackMode)
1357 FIXME("YellowMode2: NIY\n");
1360 FIXME("XAForm2: NIY\n");
1363 FIXME("CDDA: NIY\n");
1368 *sz = sectSize * raw->SectorCount;
1369 ret = CDROM_GetStatusCode(io);
1373 /******************************************************************
1374 * CDROM_ScsiPassThroughDirect
1378 static NTSTATUS CDROM_ScsiPassThroughDirect(int dev, PSCSI_PASS_THROUGH_DIRECT pPacket)
1380 int ret = STATUS_NOT_SUPPORTED;
1381 #if defined(linux) && defined(CDROM_SEND_PACKET)
1382 struct linux_cdrom_generic_command cmd;
1383 struct request_sense sense;
1386 if (pPacket->Length < sizeof(SCSI_PASS_THROUGH_DIRECT))
1387 return STATUS_BUFFER_TOO_SMALL;
1389 if (pPacket->CdbLength > 12)
1390 return STATUS_INVALID_PARAMETER;
1392 if (pPacket->SenseInfoLength > sizeof(sense))
1393 return STATUS_INVALID_PARAMETER;
1395 memset(&cmd, 0, sizeof(cmd));
1396 memset(&sense, 0, sizeof(sense));
1398 memcpy(&(cmd.cmd), &(pPacket->Cdb), pPacket->CdbLength);
1400 cmd.buffer = pPacket->DataBuffer;
1401 cmd.buflen = pPacket->DataTransferLength;
1404 cmd.timeout = pPacket->TimeOutValue*HZ;
1406 switch (pPacket->DataIn)
1408 case SCSI_IOCTL_DATA_OUT:
1409 cmd.data_direction = CGC_DATA_WRITE;
1411 case SCSI_IOCTL_DATA_IN:
1412 cmd.data_direction = CGC_DATA_READ;
1414 case SCSI_IOCTL_DATA_UNSPECIFIED:
1415 cmd.data_direction = CGC_DATA_NONE;
1418 return STATUS_INVALID_PARAMETER;
1421 io = ioctl(cdrom_cache[dev].fd, CDROM_SEND_PACKET, &cmd);
1423 if (pPacket->SenseInfoLength != 0)
1425 memcpy((char*)pPacket + pPacket->SenseInfoOffset,
1426 &sense, pPacket->SenseInfoLength);
1429 pPacket->ScsiStatus = cmd.stat;
1431 ret = CDROM_GetStatusCode(io);
1433 #elif defined(__NetBSD__)
1437 if (pPacket->Length < sizeof(SCSI_PASS_THROUGH_DIRECT))
1438 return STATUS_BUFFER_TOO_SMALL;
1440 if (pPacket->CdbLength > 12)
1441 return STATUS_INVALID_PARAMETER;
1443 if (pPacket->SenseInfoLength > SENSEBUFLEN)
1444 return STATUS_INVALID_PARAMETER;
1446 memset(&cmd, 0, sizeof(cmd));
1447 memcpy(&(cmd.cmd), &(pPacket->Cdb), pPacket->CdbLength);
1449 cmd.cmdlen = pPacket->CdbLength;
1450 cmd.databuf = pPacket->DataBuffer;
1451 cmd.datalen = pPacket->DataTransferLength;
1452 cmd.senselen = pPacket->SenseInfoLength;
1453 cmd.timeout = pPacket->TimeOutValue*1000; /* in milliseconds */
1455 switch (pPacket->DataIn)
1457 case SCSI_IOCTL_DATA_OUT:
1458 cmd.flags |= SCCMD_WRITE;
1460 case SCSI_IOCTL_DATA_IN:
1461 cmd.flags |= SCCMD_READ;
1463 case SCSI_IOCTL_DATA_UNSPECIFIED:
1467 return STATUS_INVALID_PARAMETER;
1470 io = ioctl(cdrom_cache[dev].fd, SCIOCCOMMAND, &cmd);
1474 case SCCMD_OK: break;
1475 case SCCMD_TIMEOUT: return STATUS_TIMEOUT;
1477 case SCCMD_BUSY: return STATUS_DEVICE_BUSY;
1479 case SCCMD_SENSE: break;
1480 case SCCMD_UNKNOWN: return STATUS_UNSUCCESSFUL;
1484 if (pPacket->SenseInfoLength != 0)
1486 memcpy((char*)pPacket + pPacket->SenseInfoOffset,
1487 cmd.sense, pPacket->SenseInfoLength);
1490 pPacket->ScsiStatus = cmd.status;
1492 ret = CDROM_GetStatusCode(io);
1497 /******************************************************************
1498 * CDROM_ScsiPassThrough
1502 static NTSTATUS CDROM_ScsiPassThrough(int dev, PSCSI_PASS_THROUGH pPacket)
1504 int ret = STATUS_NOT_SUPPORTED;
1505 #if defined(linux) && defined(CDROM_SEND_PACKET)
1506 struct linux_cdrom_generic_command cmd;
1507 struct request_sense sense;
1510 if (pPacket->Length < sizeof(SCSI_PASS_THROUGH))
1511 return STATUS_BUFFER_TOO_SMALL;
1513 if (pPacket->CdbLength > 12)
1514 return STATUS_INVALID_PARAMETER;
1516 if (pPacket->SenseInfoLength > sizeof(sense))
1517 return STATUS_INVALID_PARAMETER;
1519 memset(&cmd, 0, sizeof(cmd));
1520 memset(&sense, 0, sizeof(sense));
1522 memcpy(&(cmd.cmd), &(pPacket->Cdb), pPacket->CdbLength);
1524 if ( pPacket->DataBufferOffset > 0x1000 )
1526 cmd.buffer = (void*)pPacket->DataBufferOffset;
1530 cmd.buffer = (char*)pPacket + pPacket->DataBufferOffset;
1532 cmd.buflen = pPacket->DataTransferLength;
1535 cmd.timeout = pPacket->TimeOutValue*HZ;
1537 switch (pPacket->DataIn)
1539 case SCSI_IOCTL_DATA_OUT:
1540 cmd.data_direction = CGC_DATA_WRITE;
1542 case SCSI_IOCTL_DATA_IN:
1543 cmd.data_direction = CGC_DATA_READ;
1545 case SCSI_IOCTL_DATA_UNSPECIFIED:
1546 cmd.data_direction = CGC_DATA_NONE;
1549 return STATUS_INVALID_PARAMETER;
1552 io = ioctl(cdrom_cache[dev].fd, CDROM_SEND_PACKET, &cmd);
1554 if (pPacket->SenseInfoLength != 0)
1556 memcpy((char*)pPacket + pPacket->SenseInfoOffset,
1557 &sense, pPacket->SenseInfoLength);
1560 pPacket->ScsiStatus = cmd.stat;
1562 ret = CDROM_GetStatusCode(io);
1564 #elif defined(__NetBSD__)
1568 if (pPacket->Length < sizeof(SCSI_PASS_THROUGH))
1569 return STATUS_BUFFER_TOO_SMALL;
1571 if (pPacket->CdbLength > 12)
1572 return STATUS_INVALID_PARAMETER;
1574 if (pPacket->SenseInfoLength > SENSEBUFLEN)
1575 return STATUS_INVALID_PARAMETER;
1577 memset(&cmd, 0, sizeof(cmd));
1578 memcpy(&(cmd.cmd), &(pPacket->Cdb), pPacket->CdbLength);
1580 if ( pPacket->DataBufferOffset > 0x1000 )
1582 cmd.databuf = (void*)pPacket->DataBufferOffset;
1586 cmd.databuf = (char*)pPacket + pPacket->DataBufferOffset;
1589 cmd.cmdlen = pPacket->CdbLength;
1590 cmd.datalen = pPacket->DataTransferLength;
1591 cmd.senselen = pPacket->SenseInfoLength;
1592 cmd.timeout = pPacket->TimeOutValue*1000; /* in milliseconds */
1594 switch (pPacket->DataIn)
1596 case SCSI_IOCTL_DATA_OUT:
1597 cmd.flags |= SCCMD_WRITE;
1599 case SCSI_IOCTL_DATA_IN:
1600 cmd.flags |= SCCMD_READ;
1602 case SCSI_IOCTL_DATA_UNSPECIFIED:
1606 return STATUS_INVALID_PARAMETER;
1609 io = ioctl(cdrom_cache[dev].fd, SCIOCCOMMAND, &cmd);
1613 case SCCMD_OK: break;
1614 case SCCMD_TIMEOUT: return STATUS_TIMEOUT;
1616 case SCCMD_BUSY: return STATUS_DEVICE_BUSY;
1618 case SCCMD_SENSE: break;
1619 case SCCMD_UNKNOWN: return STATUS_UNSUCCESSFUL;
1623 if (pPacket->SenseInfoLength != 0)
1625 memcpy((char*)pPacket + pPacket->SenseInfoOffset,
1626 cmd.sense, pPacket->SenseInfoLength);
1629 pPacket->ScsiStatus = cmd.status;
1631 ret = CDROM_GetStatusCode(io);
1636 /******************************************************************
1641 static NTSTATUS CDROM_ScsiGetCaps(int dev, PIO_SCSI_CAPABILITIES caps)
1643 NTSTATUS ret = STATUS_NOT_IMPLEMENTED;
1645 caps->Length = sizeof(*caps);
1647 caps->MaximumTransferLength = SG_SCATTER_SZ; /* FIXME */
1648 caps->MaximumPhysicalPages = SG_SCATTER_SZ / getpagesize();
1649 caps->SupportedAsynchronousEvents = TRUE;
1650 caps->AlignmentMask = getpagesize();
1651 caps->TaggedQueuing = FALSE; /* we could check that it works and answer TRUE */
1652 caps->AdapterScansDown = FALSE; /* FIXME ? */
1653 caps->AdapterUsesPio = FALSE; /* FIXME ? */
1654 ret = STATUS_SUCCESS;
1656 FIXME("Unimplemented\n");
1661 /******************************************************************
1664 * implements IOCTL_SCSI_GET_ADDRESS
1666 static NTSTATUS CDROM_GetAddress(int dev, SCSI_ADDRESS* address)
1668 int portnum, busid, targetid, lun;
1670 address->Length = sizeof(SCSI_ADDRESS);
1671 if ( ! CDROM_GetInterfaceInfo(cdrom_cache[dev].fd, &portnum,
1672 &busid, &targetid, &lun))
1673 return STATUS_NOT_SUPPORTED;
1675 address->PortNumber = portnum;
1676 address->PathId = busid; /* bus number */
1677 address->TargetId = targetid;
1679 return STATUS_SUCCESS;
1682 /******************************************************************
1683 * CDROM_DeviceIoControl
1687 NTSTATUS CDROM_DeviceIoControl(DWORD clientID, HANDLE hDevice, DWORD dwIoControlCode,
1688 LPVOID lpInBuffer, DWORD nInBufferSize,
1689 LPVOID lpOutBuffer, DWORD nOutBufferSize,
1690 LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped)
1693 NTSTATUS status = STATUS_SUCCESS;
1696 TRACE("%lx[%c] %s %lx %ld %lx %ld %lx %lx\n",
1697 (DWORD)hDevice, 'A' + LOWORD(clientID), iocodex(dwIoControlCode), (DWORD)lpInBuffer, nInBufferSize,
1698 (DWORD)lpOutBuffer, nOutBufferSize, (DWORD)lpBytesReturned, (DWORD)lpOverlapped);
1700 if (lpBytesReturned) *lpBytesReturned = 0;
1702 if ((status = CDROM_Open(hDevice, clientID, &dev))) goto error;
1704 switch (dwIoControlCode)
1706 case IOCTL_STORAGE_CHECK_VERIFY:
1707 case IOCTL_CDROM_CHECK_VERIFY:
1709 CDROM_ClearCacheEntry(dev);
1710 if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
1711 status = STATUS_INVALID_PARAMETER;
1712 else status = CDROM_Verify(dev);
1715 /* EPP case IOCTL_STORAGE_CHECK_VERIFY2: */
1717 /* EPP case IOCTL_STORAGE_FIND_NEW_DEVICES: */
1718 /* EPP case IOCTL_CDROM_FIND_NEW_DEVICES: */
1720 case IOCTL_STORAGE_LOAD_MEDIA:
1721 case IOCTL_CDROM_LOAD_MEDIA:
1723 CDROM_ClearCacheEntry(dev);
1724 if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
1725 status = STATUS_INVALID_PARAMETER;
1726 else status = CDROM_SetTray(dev, FALSE);
1728 case IOCTL_STORAGE_EJECT_MEDIA:
1730 CDROM_ClearCacheEntry(dev);
1731 if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
1732 status = STATUS_INVALID_PARAMETER;
1733 else status = CDROM_SetTray(dev, TRUE);
1736 case IOCTL_CDROM_MEDIA_REMOVAL:
1737 case IOCTL_DISK_MEDIA_REMOVAL:
1738 case IOCTL_STORAGE_MEDIA_REMOVAL:
1739 case IOCTL_STORAGE_EJECTION_CONTROL:
1740 /* FIXME the last ioctl:s is not the same as the two others...
1741 * lockcount/owner should be handled */
1743 CDROM_ClearCacheEntry(dev);
1744 if (lpOutBuffer != NULL || nOutBufferSize != 0) status = STATUS_INVALID_PARAMETER;
1745 else if (nInBufferSize < sizeof(PREVENT_MEDIA_REMOVAL)) status = STATUS_BUFFER_TOO_SMALL;
1746 else status = CDROM_ControlEjection(dev, (const PREVENT_MEDIA_REMOVAL*)lpInBuffer);
1749 /* EPP case IOCTL_STORAGE_GET_MEDIA_TYPES: */
1751 case IOCTL_STORAGE_GET_DEVICE_NUMBER:
1752 sz = sizeof(STORAGE_DEVICE_NUMBER);
1753 if (lpInBuffer != NULL || nInBufferSize != 0) status = STATUS_INVALID_PARAMETER;
1754 else if (nOutBufferSize < sz) status = STATUS_BUFFER_TOO_SMALL;
1755 else status = CDROM_GetDeviceNumber(dev, (STORAGE_DEVICE_NUMBER*)lpOutBuffer);
1758 case IOCTL_STORAGE_RESET_DEVICE:
1760 CDROM_ClearCacheEntry(dev);
1761 if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
1762 status = STATUS_INVALID_PARAMETER;
1763 else status = CDROM_ResetAudio(dev);
1766 case IOCTL_CDROM_GET_CONTROL:
1767 sz = sizeof(CDROM_AUDIO_CONTROL);
1768 if (lpInBuffer != NULL || nInBufferSize != 0) status = STATUS_INVALID_PARAMETER;
1769 else if (nOutBufferSize < sz) status = STATUS_BUFFER_TOO_SMALL;
1770 else status = CDROM_GetControl(dev, (CDROM_AUDIO_CONTROL*)lpOutBuffer);
1773 case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
1774 sz = sizeof(DISK_GEOMETRY);
1775 if (lpInBuffer != NULL || nInBufferSize != 0) status = STATUS_INVALID_PARAMETER;
1776 else if (nOutBufferSize < sz) status = STATUS_BUFFER_TOO_SMALL;
1777 else status = CDROM_GetDriveGeometry(dev, (DISK_GEOMETRY*)lpOutBuffer);
1780 case IOCTL_CDROM_DISK_TYPE:
1781 sz = sizeof(CDROM_DISK_DATA);
1782 /* CDROM_ClearCacheEntry(dev); */
1783 if (lpInBuffer != NULL || nInBufferSize != 0) status = STATUS_INVALID_PARAMETER;
1784 else if (nOutBufferSize < sz) status = STATUS_BUFFER_TOO_SMALL;
1785 else status = CDROM_GetDiskData(dev, (CDROM_DISK_DATA*)lpOutBuffer);
1788 /* EPP case IOCTL_CDROM_GET_LAST_SESSION: */
1790 case IOCTL_CDROM_READ_Q_CHANNEL:
1791 sz = sizeof(SUB_Q_CHANNEL_DATA);
1792 if (lpInBuffer == NULL || nInBufferSize < sizeof(CDROM_SUB_Q_DATA_FORMAT))
1793 status = STATUS_INVALID_PARAMETER;
1794 else if (nOutBufferSize < sz) status = STATUS_BUFFER_TOO_SMALL;
1795 else status = CDROM_ReadQChannel(dev, (const CDROM_SUB_Q_DATA_FORMAT*)lpInBuffer,
1796 (SUB_Q_CHANNEL_DATA*)lpOutBuffer);
1799 case IOCTL_CDROM_READ_TOC:
1800 sz = sizeof(CDROM_TOC);
1801 if (lpInBuffer != NULL || nInBufferSize != 0) status = STATUS_INVALID_PARAMETER;
1802 else if (nOutBufferSize < sz) status = STATUS_BUFFER_TOO_SMALL;
1803 else status = CDROM_ReadTOC(dev, (CDROM_TOC*)lpOutBuffer);
1806 /* EPP case IOCTL_CDROM_READ_TOC_EX: */
1808 case IOCTL_CDROM_PAUSE_AUDIO:
1810 if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
1811 status = STATUS_INVALID_PARAMETER;
1812 else status = CDROM_PauseAudio(dev);
1814 case IOCTL_CDROM_PLAY_AUDIO_MSF:
1816 if (lpOutBuffer != NULL || nOutBufferSize != 0) status = STATUS_INVALID_PARAMETER;
1817 else if (nInBufferSize < sizeof(CDROM_PLAY_AUDIO_MSF)) status = STATUS_BUFFER_TOO_SMALL;
1818 else status = CDROM_PlayAudioMSF(dev, (const CDROM_PLAY_AUDIO_MSF*)lpInBuffer);
1820 case IOCTL_CDROM_RESUME_AUDIO:
1822 if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
1823 status = STATUS_INVALID_PARAMETER;
1824 else status = CDROM_ResumeAudio(dev);
1826 case IOCTL_CDROM_SEEK_AUDIO_MSF:
1828 if (lpOutBuffer != NULL || nOutBufferSize != 0) status = STATUS_INVALID_PARAMETER;
1829 else if (nInBufferSize < sizeof(CDROM_SEEK_AUDIO_MSF)) status = STATUS_BUFFER_TOO_SMALL;
1830 else status = CDROM_SeekAudioMSF(dev, (const CDROM_SEEK_AUDIO_MSF*)lpInBuffer);
1832 case IOCTL_CDROM_STOP_AUDIO:
1834 CDROM_ClearCacheEntry(dev); /* Maybe intention is to change media */
1835 if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
1836 status = STATUS_INVALID_PARAMETER;
1837 else status = CDROM_StopAudio(dev);
1839 case IOCTL_CDROM_GET_VOLUME:
1840 sz = sizeof(VOLUME_CONTROL);
1841 if (lpInBuffer != NULL || nInBufferSize != 0) status = STATUS_INVALID_PARAMETER;
1842 else if (nOutBufferSize < sz) status = STATUS_BUFFER_TOO_SMALL;
1843 else status = CDROM_GetVolume(dev, (VOLUME_CONTROL*)lpOutBuffer);
1845 case IOCTL_CDROM_SET_VOLUME:
1847 CDROM_ClearCacheEntry(dev);
1848 if (lpInBuffer == NULL || nInBufferSize < sizeof(VOLUME_CONTROL) || lpOutBuffer != NULL)
1849 status = STATUS_INVALID_PARAMETER;
1850 else status = CDROM_SetVolume(dev, (const VOLUME_CONTROL*)lpInBuffer);
1852 case IOCTL_CDROM_RAW_READ:
1854 if (nInBufferSize < sizeof(RAW_READ_INFO)) status = STATUS_INVALID_PARAMETER;
1855 else if (lpOutBuffer == NULL) status = STATUS_BUFFER_TOO_SMALL;
1856 else status = CDROM_RawRead(dev, (const RAW_READ_INFO*)lpInBuffer,
1857 lpOutBuffer, nOutBufferSize, &sz);
1859 case IOCTL_SCSI_GET_ADDRESS:
1860 sz = sizeof(SCSI_ADDRESS);
1861 if (lpInBuffer != NULL || nInBufferSize != 0) status = STATUS_INVALID_PARAMETER;
1862 else if (nOutBufferSize < sz) status = STATUS_BUFFER_TOO_SMALL;
1863 else status = CDROM_GetAddress(dev, (SCSI_ADDRESS*)lpOutBuffer);
1865 case IOCTL_SCSI_PASS_THROUGH_DIRECT:
1866 sz = sizeof(SCSI_PASS_THROUGH_DIRECT);
1867 if (lpOutBuffer == NULL) status = STATUS_INVALID_PARAMETER;
1868 else if (nOutBufferSize < sizeof(SCSI_PASS_THROUGH_DIRECT)) status = STATUS_BUFFER_TOO_SMALL;
1869 else status = CDROM_ScsiPassThroughDirect(dev, (PSCSI_PASS_THROUGH_DIRECT)lpOutBuffer);
1871 case IOCTL_SCSI_PASS_THROUGH:
1872 sz = sizeof(SCSI_PASS_THROUGH);
1873 if (lpOutBuffer == NULL) status = STATUS_INVALID_PARAMETER;
1874 else if (nOutBufferSize < sizeof(SCSI_PASS_THROUGH)) status = STATUS_BUFFER_TOO_SMALL;
1875 else status = CDROM_ScsiPassThrough(dev, (PSCSI_PASS_THROUGH)lpOutBuffer);
1877 case IOCTL_SCSI_GET_CAPABILITIES:
1878 sz = sizeof(IO_SCSI_CAPABILITIES);
1879 if (lpOutBuffer == NULL) status = STATUS_INVALID_PARAMETER;
1880 else if (nOutBufferSize < sizeof(IO_SCSI_CAPABILITIES)) status = STATUS_BUFFER_TOO_SMALL;
1881 else status = CDROM_ScsiGetCaps(dev, (PIO_SCSI_CAPABILITIES)lpOutBuffer);
1884 FIXME("Unsupported IOCTL %lx (type=%lx access=%lx func=%lx meth=%lx)\n",
1885 dwIoControlCode, dwIoControlCode >> 16, (dwIoControlCode >> 14) & 3,
1886 (dwIoControlCode >> 2) & 0xFFF, dwIoControlCode & 3);
1888 status = STATUS_INVALID_PARAMETER;
1894 lpOverlapped->Internal = status;
1895 lpOverlapped->InternalHigh = sz;
1896 NtSetEvent(lpOverlapped->hEvent, NULL);
1898 if (lpBytesReturned) *lpBytesReturned = sz;
1899 CDROM_Close(clientID);