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"
38 #include <sys/types.h>
40 #ifdef HAVE_SYS_IOCTL_H
41 #include <sys/ioctl.h>
46 #ifdef HAVE_SCSI_SCSI_IOCTL_H
47 # include <scsi/scsi_ioctl.h>
49 #ifdef HAVE_LINUX_MAJOR_H
50 # include <linux/major.h>
52 #ifdef HAVE_LINUX_HDREG_H
53 # include <linux/hdreg.h>
55 #ifdef HAVE_LINUX_PARAM_H
56 # include <linux/param.h>
58 #ifdef HAVE_LINUX_CDROM_H
59 # include <linux/cdrom.h>
61 #ifdef HAVE_LINUX_UCDROM_H
62 # include <linux/ucdrom.h>
64 #ifdef HAVE_SYS_CDIO_H
65 # include <sys/cdio.h>
67 #ifdef HAVE_SYS_SCSIIO_H
68 # include <sys/scsiio.h>
71 #define NONAMELESSUNION
72 #define NONAMELESSSTRUCT
84 #include "wine/debug.h"
86 /* Non-Linux systems do not have linux/cdrom.h and the like, and thus
87 lack the following constants. */
90 #define CD_SECS 60 /* seconds per minute */
93 #define CD_FRAMES 75 /* frames per second */
96 static const struct iocodexs
101 {IOCTL_CDROM_UNLOAD_DRIVER
, "IOCTL_CDROM_UNLOAD_DRIVER"},
102 {IOCTL_CDROM_READ_TOC
, "IOCTL_CDROM_READ_TOC"},
103 {IOCTL_CDROM_GET_CONTROL
, "IOCTL_CDROM_GET_CONTROL"},
104 {IOCTL_CDROM_PLAY_AUDIO_MSF
, "IOCTL_CDROM_PLAY_AUDIO_MSF"},
105 {IOCTL_CDROM_SEEK_AUDIO_MSF
, "IOCTL_CDROM_SEEK_AUDIO_MSF"},
106 {IOCTL_CDROM_STOP_AUDIO
, "IOCTL_CDROM_STOP_AUDIO"},
107 {IOCTL_CDROM_PAUSE_AUDIO
, "IOCTL_CDROM_PAUSE_AUDIO"},
108 {IOCTL_CDROM_RESUME_AUDIO
, "IOCTL_CDROM_RESUME_AUDIO"},
109 {IOCTL_CDROM_GET_VOLUME
, "IOCTL_CDROM_GET_VOLUME"},
110 {IOCTL_CDROM_SET_VOLUME
, "IOCTL_CDROM_SET_VOLUME"},
111 {IOCTL_CDROM_READ_Q_CHANNEL
, "IOCTL_CDROM_READ_Q_CHANNEL"},
112 {IOCTL_CDROM_GET_LAST_SESSION
, "IOCTL_CDROM_GET_LAST_SESSION"},
113 {IOCTL_CDROM_RAW_READ
, "IOCTL_CDROM_RAW_READ"},
114 {IOCTL_CDROM_DISK_TYPE
, "IOCTL_CDROM_DISK_TYPE"},
115 {IOCTL_CDROM_GET_DRIVE_GEOMETRY
, "IOCTL_CDROM_GET_DRIVE_GEOMETRY"},
116 {IOCTL_CDROM_CHECK_VERIFY
, "IOCTL_CDROM_CHECK_VERIFY"},
117 {IOCTL_CDROM_MEDIA_REMOVAL
, "IOCTL_CDROM_MEDIA_REMOVAL"},
118 {IOCTL_CDROM_EJECT_MEDIA
, "IOCTL_CDROM_EJECT_MEDIA"},
119 {IOCTL_CDROM_LOAD_MEDIA
, "IOCTL_CDROM_LOAD_MEDIA"},
120 {IOCTL_CDROM_RESERVE
, "IOCTL_CDROM_RESERVE"},
121 {IOCTL_CDROM_RELEASE
, "IOCTL_CDROM_RELEASE"},
122 {IOCTL_CDROM_FIND_NEW_DEVICES
, "IOCTL_CDROM_FIND_NEW_DEVICES"}
124 static const char *iocodex(DWORD code
)
127 static char buffer
[25];
128 for(i
=0; i
<sizeof(iocodextable
)/sizeof(struct iocodexs
); i
++)
129 if (code
==iocodextable
[i
].code
)
130 return iocodextable
[i
].codex
;
131 sprintf(buffer
, "IOCTL_CODE_%x", (int)code
);
135 WINE_DEFAULT_DEBUG_CHANNEL(cdrom
);
137 #define FRAME_OF_ADDR(a) (((int)(a)[1] * CD_SECS + (a)[2]) * CD_FRAMES + (a)[3])
138 #define FRAME_OF_MSF(a) (((int)(a).M * CD_SECS + (a).S) * CD_FRAMES + (a).F)
139 #define FRAME_OF_TOC(toc, idx) FRAME_OF_ADDR((toc).TrackData[idx - (toc).FirstTrack].Address)
140 #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;}
142 static NTSTATUS
CDROM_ReadTOC(int, CDROM_TOC
*);
143 static NTSTATUS
CDROM_GetStatusCode(int);
149 # define IDE6_MAJOR 88
152 # define IDE7_MAJOR 89
155 # ifdef CDROM_SEND_PACKET
156 /* structure for CDROM_PACKET_COMMAND ioctl */
157 /* not all Linux versions have all the fields, so we define the
158 * structure ourselves to make sure */
159 struct linux_cdrom_generic_command
161 unsigned char cmd
[CDROM_PACKET_SIZE
];
162 unsigned char *buffer
;
165 struct request_sense
*sense
;
166 unsigned char data_direction
;
171 # endif /* CDROM_SEND_PACKET */
175 /* FIXME: this is needed because we can't open simultaneously several times /dev/cdrom
176 * this should be removed when a proper device interface is implemented
178 * (WS) We need this to keep track of current position and to safely
179 * detect media changes. Besides this should provide a great speed up
185 char toc_good
; /* if false, will reread TOC from disk */
187 SUB_Q_CURRENT_POSITION CurrentPosition
;
189 static struct cdrom_cache cdrom_cache
[26];
191 /* Proposed media change function: not really needed at this time */
192 /* This is a 1 or 0 type of function */
194 static int CDROM_MediaChanged(int dev
)
198 struct cdrom_tochdr hdr
;
199 struct cdrom_tocentry entry
;
201 if (dev
< 0 || dev
>= 26)
203 if ( ioctl(cdrom_cache
[dev
].fd
, CDROMREADTOCHDR
, &hdr
) == -1 )
206 if ( memcmp(&hdr
, &cdrom_cache
[dev
].hdr
, sizeof(struct cdrom_tochdr
)) )
209 for (i
=hdr
.cdth_trk0
; i
<=hdr
.cdth_trk1
+1; i
++)
211 if (i
== hdr
.cdth_trk1
+ 1)
213 entry
.cdte_track
= CDROM_LEADOUT
;
215 entry
.cdte_track
= i
;
217 entry
.cdte_format
= CDROM_MSF
;
218 if ( ioctl(cdrom_cache
[dev
].fd
, CDROMREADTOCENTRY
, &entry
) == -1)
220 if ( memcmp(&entry
, cdrom_cache
[dev
].entry
+i
-hdr
.cdth_trk0
,
221 sizeof(struct cdrom_tocentry
)) )
228 /******************************************************************
229 * CDROM_SyncCache [internal]
231 * Read the TOC in and store it in the cdrom_cache structure.
232 * Further requests for the TOC will be copied from the cache
233 * unless certain events like disk ejection is detected, in which
234 * case the cache will be cleared, causing it to be resynced.
237 static int CDROM_SyncCache(int dev
)
241 struct cdrom_tochdr hdr
;
242 struct cdrom_tocentry entry
;
243 #elif defined(__FreeBSD__) || defined(__NetBSD__)
244 struct ioc_toc_header hdr
;
245 struct ioc_read_toc_entry entry
;
246 struct cd_toc_entry toc_buffer
;
248 CDROM_TOC
*toc
= &cdrom_cache
[dev
].toc
;
249 cdrom_cache
[dev
].toc_good
= 0;
253 io
= ioctl(cdrom_cache
[dev
].fd
, CDROMREADTOCHDR
, &hdr
);
256 WARN("(%d) -- Error occurred (%s)!\n", dev
, strerror(errno
));
260 TRACE("caching toc from=%d to=%d\n", toc
->FirstTrack
, toc
->LastTrack
);
262 toc
->FirstTrack
= hdr
.cdth_trk0
;
263 toc
->LastTrack
= hdr
.cdth_trk1
;
264 tsz
= sizeof(toc
->FirstTrack
) + sizeof(toc
->LastTrack
)
265 + sizeof(TRACK_DATA
) * (toc
->LastTrack
-toc
->FirstTrack
+2);
266 toc
->Length
[0] = tsz
>> 8;
267 toc
->Length
[1] = tsz
;
269 for (i
= toc
->FirstTrack
; i
<= toc
->LastTrack
+ 1; i
++)
271 if (i
== toc
->LastTrack
+ 1)
272 entry
.cdte_track
= CDROM_LEADOUT
;
274 entry
.cdte_track
= i
;
275 entry
.cdte_format
= CDROM_MSF
;
276 io
= ioctl(cdrom_cache
[dev
].fd
, CDROMREADTOCENTRY
, &entry
);
278 WARN("error read entry (%s)\n", strerror(errno
));
281 toc
->TrackData
[i
- toc
->FirstTrack
].Control
= entry
.cdte_ctrl
;
282 toc
->TrackData
[i
- toc
->FirstTrack
].Adr
= entry
.cdte_adr
;
283 /* marking last track with leadout value as index */
284 toc
->TrackData
[i
- toc
->FirstTrack
].TrackNumber
= entry
.cdte_track
;
285 toc
->TrackData
[i
- toc
->FirstTrack
].Address
[0] = 0;
286 toc
->TrackData
[i
- toc
->FirstTrack
].Address
[1] = entry
.cdte_addr
.msf
.minute
;
287 toc
->TrackData
[i
- toc
->FirstTrack
].Address
[2] = entry
.cdte_addr
.msf
.second
;
288 toc
->TrackData
[i
- toc
->FirstTrack
].Address
[3] = entry
.cdte_addr
.msf
.frame
;
290 cdrom_cache
[dev
].toc_good
= 1;
292 #elif defined(__FreeBSD__) || defined(__NetBSD__)
294 io
= ioctl(cdrom_cache
[dev
].fd
, CDIOREADTOCHEADER
, &hdr
);
297 WARN("(%d) -- Error occurred (%s)!\n", dev
, strerror(errno
));
300 toc
->FirstTrack
= hdr
.starting_track
;
301 toc
->LastTrack
= hdr
.ending_track
;
302 tsz
= sizeof(toc
->FirstTrack
) + sizeof(toc
->LastTrack
)
303 + sizeof(TRACK_DATA
) * (toc
->LastTrack
-toc
->FirstTrack
+2);
304 toc
->Length
[0] = tsz
>> 8;
305 toc
->Length
[1] = tsz
;
307 TRACE("caching toc from=%d to=%d\n", toc
->FirstTrack
, toc
->LastTrack
);
309 for (i
= toc
->FirstTrack
; i
<= toc
->LastTrack
+ 1; i
++)
311 if (i
== toc
->LastTrack
+ 1)
314 entry
.starting_track
= LEADOUT
;
316 entry
.starting_track
= i
;
318 memset((char *)&toc_buffer
, 0, sizeof(toc_buffer
));
319 entry
.address_format
= CD_MSF_FORMAT
;
320 entry
.data_len
= sizeof(toc_buffer
);
321 entry
.data
= &toc_buffer
;
322 io
= ioctl(cdrom_cache
[dev
].fd
, CDIOREADTOCENTRYS
, &entry
);
324 WARN("error read entry (%s)\n", strerror(errno
));
327 toc
->TrackData
[i
- toc
->FirstTrack
].Control
= toc_buffer
.control
;
328 toc
->TrackData
[i
- toc
->FirstTrack
].Adr
= toc_buffer
.addr_type
;
329 /* marking last track with leadout value as index */
330 toc
->TrackData
[i
- toc
->FirstTrack
].TrackNumber
= entry
.starting_track
;
331 toc
->TrackData
[i
- toc
->FirstTrack
].Address
[0] = 0;
332 toc
->TrackData
[i
- toc
->FirstTrack
].Address
[1] = toc_buffer
.addr
.msf
.minute
;
333 toc
->TrackData
[i
- toc
->FirstTrack
].Address
[2] = toc_buffer
.addr
.msf
.second
;
334 toc
->TrackData
[i
- toc
->FirstTrack
].Address
[3] = toc_buffer
.addr
.msf
.frame
;
336 cdrom_cache
[dev
].toc_good
= 1;
339 return STATUS_NOT_SUPPORTED
;
342 return CDROM_GetStatusCode(io
);
345 static void CDROM_ClearCacheEntry(int dev
)
347 cdrom_cache
[dev
].toc_good
= 0;
352 /******************************************************************
353 * CDROM_GetInterfaceInfo
355 * Determines the ide interface (the number after the ide), and the
356 * number of the device on that interface for ide cdroms (*port == 0).
357 * Determines the scsi information for scsi cdroms (*port >= 1).
358 * Returns false if the info cannot not be obtained.
360 * NOTE: this function is used in CDROM_InitRegistry and CDROM_GetAddress
362 static int CDROM_GetInterfaceInfo(int fd
, int* port
, int* iface
, int* device
,int* lun
)
367 if ( fstat(fd
, &st
) == -1 || ! S_ISBLK(st
.st_mode
)) {
368 FIXME("cdrom not a block device!!!\n");
375 switch (major(st
.st_rdev
)) {
376 case IDE0_MAJOR
: *iface
= 0; break;
377 case IDE1_MAJOR
: *iface
= 1; break;
378 case IDE2_MAJOR
: *iface
= 2; break;
379 case IDE3_MAJOR
: *iface
= 3; break;
380 case IDE4_MAJOR
: *iface
= 4; break;
381 case IDE5_MAJOR
: *iface
= 5; break;
382 case IDE6_MAJOR
: *iface
= 6; break;
383 case IDE7_MAJOR
: *iface
= 7; break;
384 default: *port
= 1; break;
388 *device
= (minor(st
.st_rdev
) >> 6);
391 #ifdef SCSI_IOCTL_GET_IDLUN
393 if (ioctl(fd
, SCSI_IOCTL_GET_IDLUN
, &idlun
) != -1)
395 *port
= ((idlun
[0] >> 24) & 0xff) + 1;
396 *iface
= (idlun
[0] >> 16) & 0xff;
397 *device
= idlun
[0] & 0xff;
398 *lun
= (idlun
[0] >> 8) & 0xff;
403 FIXME("CD-ROM device (%d, %d) not supported\n",
404 major(st
.st_rdev
), minor(st
.st_rdev
));
410 #elif defined(__NetBSD__)
412 struct scsi_addr addr
;
413 if (ioctl(fd
, SCIOCIDENTIFY
, &addr
) != -1) {
415 case TYPE_SCSI
: *port
= 1;
416 *iface
= addr
.addr
.scsi
.scbus
;
417 *device
= addr
.addr
.scsi
.target
;
418 *lun
= addr
.addr
.scsi
.lun
;
420 case TYPE_ATAPI
: *port
= 0;
421 *iface
= addr
.addr
.atapi
.atbus
;
422 *device
= addr
.addr
.atapi
.drive
;
430 #elif defined(__FreeBSD__)
431 FIXME("not implemented for BSD\n");
434 FIXME("not implemented for nonlinux\n");
440 /******************************************************************
443 * Initializes registry to contain scsi info about the cdrom in NT.
444 * All devices (even not real scsi ones) have this info in NT.
445 * TODO: for now it only works for non scsi devices
446 * NOTE: programs usually read these registry entries after sending the
447 * IOCTL_SCSI_GET_ADDRESS ioctl to the cdrom
449 void CDROM_InitRegistry(int fd
)
451 int portnum
, busid
, targetid
, lun
;
452 OBJECT_ATTRIBUTES attr
;
453 UNICODE_STRING nameW
;
465 attr
.Length
= sizeof(attr
);
466 attr
.RootDirectory
= 0;
467 attr
.ObjectName
= &nameW
;
469 attr
.SecurityDescriptor
= NULL
;
470 attr
.SecurityQualityOfService
= NULL
;
472 if ( ! CDROM_GetInterfaceInfo(fd
, &portnum
, &busid
, &targetid
, &lun
))
475 /* Ensure there is Scsi key */
476 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, "Machine\\HARDWARE\\DEVICEMAP\\Scsi" ) ||
477 NtCreateKey( &scsiKey
, KEY_ALL_ACCESS
, &attr
, 0,
478 NULL
, REG_OPTION_VOLATILE
, &disp
))
480 ERR("Cannot create DEVICEMAP\\Scsi registry key\n" );
483 RtlFreeUnicodeString( &nameW
);
485 snprintf(buffer
,sizeof(buffer
),"Scsi Port %d",portnum
);
486 attr
.RootDirectory
= scsiKey
;
487 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, buffer
) ||
488 NtCreateKey( &portKey
, KEY_ALL_ACCESS
, &attr
, 0,
489 NULL
, REG_OPTION_VOLATILE
, &disp
))
491 ERR("Cannot create DEVICEMAP\\Scsi Port registry key\n" );
494 RtlFreeUnicodeString( &nameW
);
496 RtlCreateUnicodeStringFromAsciiz( &nameW
, "Driver" );
498 RtlMultiByteToUnicodeN( dataW
, 50, &lenW
, data
, strlen(data
));
499 NtSetValueKey( portKey
, &nameW
, 0, REG_SZ
, (BYTE
*)dataW
, lenW
);
500 RtlFreeUnicodeString( &nameW
);
502 RtlCreateUnicodeStringFromAsciiz( &nameW
, "FirstBusTimeScanInMs" );
503 NtSetValueKey( portKey
,&nameW
, 0, REG_DWORD
, (BYTE
*)&value
, sizeof(DWORD
));
504 RtlFreeUnicodeString( &nameW
);
509 if (ioctl(fd
,HDIO_GET_DMA
, &dma
) != -1) {
511 TRACE("setting dma to %lx\n", value
);
515 RtlCreateUnicodeStringFromAsciiz( &nameW
, "DMAEnabled" );
516 NtSetValueKey( portKey
,&nameW
, 0, REG_DWORD
, (BYTE
*)&value
, sizeof(DWORD
));
517 RtlFreeUnicodeString( &nameW
);
519 snprintf(buffer
,40,"Scsi Bus %d", busid
);
520 attr
.RootDirectory
= portKey
;
521 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, buffer
) ||
522 NtCreateKey( &busKey
, KEY_ALL_ACCESS
, &attr
, 0,
523 NULL
, REG_OPTION_VOLATILE
, &disp
))
525 ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus registry key\n" );
528 RtlFreeUnicodeString( &nameW
);
530 attr
.RootDirectory
= busKey
;
531 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, "Initiator Id 255" ) ||
532 NtCreateKey( &targetKey
, KEY_ALL_ACCESS
, &attr
, 0,
533 NULL
, REG_OPTION_VOLATILE
, &disp
))
535 ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus\\Initiator Id 255 registry key\n" );
538 RtlFreeUnicodeString( &nameW
);
539 NtClose( targetKey
);
541 snprintf(buffer
,40,"Target Id %d", targetid
);
542 attr
.RootDirectory
= busKey
;
543 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, buffer
) ||
544 NtCreateKey( &targetKey
, KEY_ALL_ACCESS
, &attr
, 0,
545 NULL
, REG_OPTION_VOLATILE
, &disp
))
547 ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus 0\\Target Id registry key\n" );
550 RtlFreeUnicodeString( &nameW
);
552 RtlCreateUnicodeStringFromAsciiz( &nameW
, "Type" );
553 data
= "CdRomPeripheral";
554 RtlMultiByteToUnicodeN( dataW
, 50, &lenW
, data
, strlen(data
));
555 NtSetValueKey( targetKey
, &nameW
, 0, REG_SZ
, (BYTE
*)dataW
, lenW
);
556 RtlFreeUnicodeString( &nameW
);
557 /* FIXME - maybe read the real identifier?? */
558 RtlCreateUnicodeStringFromAsciiz( &nameW
, "Identifier" );
560 RtlMultiByteToUnicodeN( dataW
, 50, &lenW
, data
, strlen(data
));
561 NtSetValueKey( targetKey
, &nameW
, 0, REG_SZ
, (BYTE
*)dataW
, lenW
);
562 RtlFreeUnicodeString( &nameW
);
563 /* FIXME - we always use Cdrom0 - do not know about the nt behaviour */
564 RtlCreateUnicodeStringFromAsciiz( &nameW
, "DeviceName" );
566 RtlMultiByteToUnicodeN( dataW
, 50, &lenW
, data
, strlen(data
));
567 NtSetValueKey( targetKey
, &nameW
, 0, REG_SZ
, (BYTE
*)dataW
, lenW
);
568 RtlFreeUnicodeString( &nameW
);
570 NtClose( targetKey
);
577 /******************************************************************
581 static NTSTATUS
CDROM_Open(HANDLE hDevice
, DWORD clientID
, int* dev
)
583 *dev
= LOWORD(clientID
);
585 if (*dev
>= 26) return STATUS_NO_SUCH_DEVICE
;
587 if (!cdrom_cache
[*dev
].count
)
592 strcpy(root
, "A:\\");
594 if (GetDriveTypeA(root
) != DRIVE_CDROM
) return STATUS_NO_SUCH_DEVICE
;
595 if (!(device
= DRIVE_GetDevice(*dev
))) return STATUS_NO_SUCH_DEVICE
;
596 cdrom_cache
[*dev
].fd
= open(device
, O_RDONLY
|O_NONBLOCK
);
597 if (cdrom_cache
[*dev
].fd
== -1)
599 FIXME("Can't open configured CD-ROM drive at %s (device %s): %s\n",
600 root
, DRIVE_GetDevice(*dev
), strerror(errno
));
601 return STATUS_NO_SUCH_DEVICE
;
604 cdrom_cache
[*dev
].count
++;
605 TRACE("%d, %d, %d\n", *dev
, cdrom_cache
[*dev
].fd
, cdrom_cache
[*dev
].count
);
606 return STATUS_SUCCESS
;
609 /******************************************************************
614 static void CDROM_Close(DWORD clientID
)
616 int dev
= LOWORD(clientID
);
618 if (dev
>= 26 /*|| fd != cdrom_cache[dev].fd*/) FIXME("how come\n");
619 if (--cdrom_cache
[dev
].count
== 0)
621 close(cdrom_cache
[dev
].fd
);
622 cdrom_cache
[dev
].fd
= -1;
626 /******************************************************************
627 * CDROM_GetStatusCode
631 static NTSTATUS
CDROM_GetStatusCode(int io
)
633 if (io
== 0) return STATUS_SUCCESS
;
640 return STATUS_NO_MEDIA_IN_DEVICE
;
642 return STATUS_ACCESS_DENIED
;
644 return STATUS_INVALID_PARAMETER
;
645 /* case EBADF: Bad file descriptor */
647 return STATUS_NOT_SUPPORTED
;
649 FIXME("Unmapped error code %d: %s\n", errno
, strerror(errno
));
650 return STATUS_IO_DEVICE_ERROR
;
653 /******************************************************************
657 static NTSTATUS
CDROM_GetControl(int dev
, CDROM_AUDIO_CONTROL
* cac
)
659 cac
->LbaFormat
= 0; /* FIXME */
660 cac
->LogicalBlocksPerSecond
= 1; /* FIXME */
661 return STATUS_NOT_SUPPORTED
;
664 /******************************************************************
665 * CDROM_GetDeviceNumber
668 static NTSTATUS
CDROM_GetDeviceNumber(int dev
, STORAGE_DEVICE_NUMBER
* devnum
)
670 return STATUS_NOT_SUPPORTED
;
673 /******************************************************************
674 * CDROM_GetDriveGeometry
677 static NTSTATUS
CDROM_GetDriveGeometry(int dev
, DISK_GEOMETRY
* dg
)
683 if ((ret
= CDROM_ReadTOC(dev
, &toc
)) != 0) return ret
;
685 fsize
= FRAME_OF_TOC(toc
, toc
.LastTrack
+1)
686 - FRAME_OF_TOC(toc
, 1); /* Total size in frames */
688 dg
->Cylinders
.s
.LowPart
= fsize
/ (64 * 32);
689 dg
->Cylinders
.s
.HighPart
= 0;
690 dg
->MediaType
= RemovableMedia
;
691 dg
->TracksPerCylinder
= 64;
692 dg
->SectorsPerTrack
= 32;
693 dg
->BytesPerSector
= 2048;
697 /**************************************************************************
698 * CDROM_Reset [internal]
700 static NTSTATUS
CDROM_ResetAudio(int dev
)
703 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDROMRESET
));
704 #elif defined(__FreeBSD__) || defined(__NetBSD__)
705 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDIOCRESET
, NULL
));
707 return STATUS_NOT_SUPPORTED
;
711 /******************************************************************
716 static NTSTATUS
CDROM_SetTray(int dev
, BOOL doEject
)
719 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, doEject
? CDROMEJECT
: CDROMCLOSETRAY
));
720 #elif defined(__FreeBSD__) || defined(__NetBSD__)
721 return CDROM_GetStatusCode((ioctl(cdrom_cache
[dev
].fd
, CDIOCALLOW
, NULL
)) ||
722 (ioctl(cdrom_cache
[dev
].fd
, doEject
? CDIOCEJECT
: CDIOCCLOSE
, NULL
)) ||
723 (ioctl(cdrom_cache
[dev
].fd
, CDIOCPREVENT
, NULL
)));
725 return STATUS_NOT_SUPPORTED
;
729 /******************************************************************
730 * CDROM_ControlEjection
734 static NTSTATUS
CDROM_ControlEjection(int dev
, const PREVENT_MEDIA_REMOVAL
* rmv
)
737 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDROM_LOCKDOOR
, rmv
->PreventMediaRemoval
));
738 #elif defined(__FreeBSD__) || defined(__NetBSD__)
739 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, (rmv
->PreventMediaRemoval
) ? CDIOCPREVENT
: CDIOCALLOW
, NULL
));
741 return STATUS_NOT_SUPPORTED
;
745 /******************************************************************
750 static NTSTATUS
CDROM_ReadTOC(int dev
, CDROM_TOC
* toc
)
752 NTSTATUS ret
= STATUS_NOT_SUPPORTED
;
754 if (dev
< 0 || dev
>= 26)
755 return STATUS_INVALID_PARAMETER
;
756 if ( !cdrom_cache
[dev
].toc_good
) {
757 ret
= CDROM_SyncCache(dev
);
761 *toc
= cdrom_cache
[dev
].toc
;
762 return STATUS_SUCCESS
;
765 /******************************************************************
770 static NTSTATUS
CDROM_GetDiskData(int dev
, CDROM_DISK_DATA
* data
)
776 if ((ret
= CDROM_ReadTOC(dev
, &toc
)) != 0) return ret
;
778 for (i
= toc
.FirstTrack
; i
<= toc
.LastTrack
; i
++) {
779 if (toc
.TrackData
[i
-toc
.FirstTrack
].Control
& 0x04)
780 data
->DiskData
|= CDROM_DISK_DATA_TRACK
;
782 data
->DiskData
|= CDROM_DISK_AUDIO_TRACK
;
784 return STATUS_SUCCESS
;
787 /******************************************************************
792 static NTSTATUS
CDROM_ReadQChannel(int dev
, const CDROM_SUB_Q_DATA_FORMAT
* fmt
,
793 SUB_Q_CHANNEL_DATA
* data
)
795 NTSTATUS ret
= STATUS_NOT_SUPPORTED
;
798 SUB_Q_HEADER
* hdr
= (SUB_Q_HEADER
*)data
;
800 struct cdrom_subchnl sc
;
801 sc
.cdsc_format
= CDROM_MSF
;
803 io
= ioctl(cdrom_cache
[dev
].fd
, CDROMSUBCHNL
, &sc
);
806 TRACE("opened or no_media (%s)!\n", strerror(errno
));
807 hdr
->AudioStatus
= AUDIO_STATUS_NO_STATUS
;
808 CDROM_ClearCacheEntry(dev
);
812 hdr
->AudioStatus
= AUDIO_STATUS_NOT_SUPPORTED
;
814 switch (sc
.cdsc_audiostatus
) {
815 case CDROM_AUDIO_INVALID
:
816 CDROM_ClearCacheEntry(dev
);
817 hdr
->AudioStatus
= AUDIO_STATUS_NOT_SUPPORTED
;
819 case CDROM_AUDIO_NO_STATUS
:
820 CDROM_ClearCacheEntry(dev
);
821 hdr
->AudioStatus
= AUDIO_STATUS_NO_STATUS
;
823 case CDROM_AUDIO_PLAY
:
824 hdr
->AudioStatus
= AUDIO_STATUS_IN_PROGRESS
;
826 case CDROM_AUDIO_PAUSED
:
827 hdr
->AudioStatus
= AUDIO_STATUS_PAUSED
;
829 case CDROM_AUDIO_COMPLETED
:
830 hdr
->AudioStatus
= AUDIO_STATUS_PLAY_COMPLETE
;
832 case CDROM_AUDIO_ERROR
:
833 hdr
->AudioStatus
= AUDIO_STATUS_PLAY_ERROR
;
836 TRACE("status=%02X !\n", sc
.cdsc_audiostatus
);
841 case IOCTL_CDROM_CURRENT_POSITION
:
842 size
= sizeof(SUB_Q_CURRENT_POSITION
);
843 if (hdr
->AudioStatus
==AUDIO_STATUS_IN_PROGRESS
) {
844 data
->CurrentPosition
.FormatCode
= IOCTL_CDROM_CURRENT_POSITION
;
845 data
->CurrentPosition
.Control
= sc
.cdsc_ctrl
;
846 data
->CurrentPosition
.ADR
= sc
.cdsc_adr
;
847 data
->CurrentPosition
.TrackNumber
= sc
.cdsc_trk
;
848 data
->CurrentPosition
.IndexNumber
= sc
.cdsc_ind
;
850 data
->CurrentPosition
.AbsoluteAddress
[0] = 0;
851 data
->CurrentPosition
.AbsoluteAddress
[1] = sc
.cdsc_absaddr
.msf
.minute
;
852 data
->CurrentPosition
.AbsoluteAddress
[2] = sc
.cdsc_absaddr
.msf
.second
;
853 data
->CurrentPosition
.AbsoluteAddress
[3] = sc
.cdsc_absaddr
.msf
.frame
;
855 data
->CurrentPosition
.TrackRelativeAddress
[0] = 0;
856 data
->CurrentPosition
.TrackRelativeAddress
[1] = sc
.cdsc_reladdr
.msf
.minute
;
857 data
->CurrentPosition
.TrackRelativeAddress
[2] = sc
.cdsc_reladdr
.msf
.second
;
858 data
->CurrentPosition
.TrackRelativeAddress
[3] = sc
.cdsc_reladdr
.msf
.frame
;
860 cdrom_cache
[dev
].CurrentPosition
= data
->CurrentPosition
;
862 else /* not playing */
864 cdrom_cache
[dev
].CurrentPosition
.Header
= *hdr
; /* Preserve header info */
865 data
->CurrentPosition
= cdrom_cache
[dev
].CurrentPosition
;
868 case IOCTL_CDROM_MEDIA_CATALOG
:
869 size
= sizeof(SUB_Q_MEDIA_CATALOG_NUMBER
);
870 data
->MediaCatalog
.FormatCode
= IOCTL_CDROM_MEDIA_CATALOG
;
872 struct cdrom_mcn mcn
;
873 if ((io
= ioctl(cdrom_cache
[dev
].fd
, CDROM_GET_MCN
, &mcn
)) == -1) goto end
;
875 data
->MediaCatalog
.FormatCode
= IOCTL_CDROM_MEDIA_CATALOG
;
876 data
->MediaCatalog
.Mcval
= 0; /* FIXME */
877 memcpy(data
->MediaCatalog
.MediaCatalog
, mcn
.medium_catalog_number
, 14);
878 data
->MediaCatalog
.MediaCatalog
[14] = 0;
881 case IOCTL_CDROM_TRACK_ISRC
:
882 size
= sizeof(SUB_Q_CURRENT_POSITION
);
883 FIXME("TrackIsrc: NIY on linux\n");
884 data
->TrackIsrc
.FormatCode
= IOCTL_CDROM_TRACK_ISRC
;
885 data
->TrackIsrc
.Tcval
= 0;
891 ret
= CDROM_GetStatusCode(io
);
892 #elif defined(__FreeBSD__) || defined(__NetBSD__)
894 SUB_Q_HEADER
* hdr
= (SUB_Q_HEADER
*)data
;
896 struct ioc_read_subchannel read_sc
;
897 struct cd_sub_channel_info sc
;
899 read_sc
.address_format
= CD_MSF_FORMAT
;
901 read_sc
.data_len
= sizeof(sc
);
905 case IOCTL_CDROM_CURRENT_POSITION
:
906 read_sc
.data_format
= CD_CURRENT_POSITION
;
908 case IOCTL_CDROM_MEDIA_CATALOG
:
909 read_sc
.data_format
= CD_MEDIA_CATALOG
;
911 case IOCTL_CDROM_TRACK_ISRC
:
912 read_sc
.data_format
= CD_TRACK_INFO
;
913 sc
.what
.track_info
.track_number
= data
->TrackIsrc
.Track
;
916 io
= ioctl(cdrom_cache
[dev
].fd
, CDIOCREADSUBCHANNEL
, &read_sc
);
919 TRACE("opened or no_media (%s)!\n", strerror(errno
));
920 CDROM_ClearCacheEntry(dev
);
921 hdr
->AudioStatus
= AUDIO_STATUS_NO_STATUS
;
925 hdr
->AudioStatus
= AUDIO_STATUS_NOT_SUPPORTED
;
927 switch (sc
.header
.audio_status
) {
928 case CD_AS_AUDIO_INVALID
:
929 CDROM_ClearCacheEntry(dev
);
930 hdr
->AudioStatus
= AUDIO_STATUS_NOT_SUPPORTED
;
932 case CD_AS_NO_STATUS
:
933 CDROM_ClearCacheEntry(dev
);
934 hdr
->AudioStatus
= AUDIO_STATUS_NO_STATUS
;
936 case CD_AS_PLAY_IN_PROGRESS
:
937 hdr
->AudioStatus
= AUDIO_STATUS_IN_PROGRESS
;
939 case CD_AS_PLAY_PAUSED
:
940 hdr
->AudioStatus
= AUDIO_STATUS_PAUSED
;
942 case CD_AS_PLAY_COMPLETED
:
943 hdr
->AudioStatus
= AUDIO_STATUS_PLAY_COMPLETE
;
945 case CD_AS_PLAY_ERROR
:
946 hdr
->AudioStatus
= AUDIO_STATUS_PLAY_ERROR
;
949 TRACE("status=%02X !\n", sc
.header
.audio_status
);
953 case IOCTL_CDROM_CURRENT_POSITION
:
954 size
= sizeof(SUB_Q_CURRENT_POSITION
);
955 if (hdr
->AudioStatus
==AUDIO_STATUS_IN_PROGRESS
) {
956 data
->CurrentPosition
.FormatCode
= IOCTL_CDROM_CURRENT_POSITION
;
957 data
->CurrentPosition
.Control
= sc
.what
.position
.control
;
958 data
->CurrentPosition
.ADR
= sc
.what
.position
.addr_type
;
959 data
->CurrentPosition
.TrackNumber
= sc
.what
.position
.track_number
;
960 data
->CurrentPosition
.IndexNumber
= sc
.what
.position
.index_number
;
962 data
->CurrentPosition
.AbsoluteAddress
[0] = 0;
963 data
->CurrentPosition
.AbsoluteAddress
[1] = sc
.what
.position
.absaddr
.msf
.minute
;
964 data
->CurrentPosition
.AbsoluteAddress
[2] = sc
.what
.position
.absaddr
.msf
.second
;
965 data
->CurrentPosition
.AbsoluteAddress
[3] = sc
.what
.position
.absaddr
.msf
.frame
;
966 data
->CurrentPosition
.TrackRelativeAddress
[0] = 0;
967 data
->CurrentPosition
.TrackRelativeAddress
[1] = sc
.what
.position
.reladdr
.msf
.minute
;
968 data
->CurrentPosition
.TrackRelativeAddress
[2] = sc
.what
.position
.reladdr
.msf
.second
;
969 data
->CurrentPosition
.TrackRelativeAddress
[3] = sc
.what
.position
.reladdr
.msf
.frame
;
970 cdrom_cache
[dev
].CurrentPosition
= data
->CurrentPosition
;
972 else { /* not playing */
973 cdrom_cache
[dev
].CurrentPosition
.Header
= *hdr
; /* Preserve header info */
974 data
->CurrentPosition
= cdrom_cache
[dev
].CurrentPosition
;
977 case IOCTL_CDROM_MEDIA_CATALOG
:
978 size
= sizeof(SUB_Q_MEDIA_CATALOG_NUMBER
);
979 data
->MediaCatalog
.FormatCode
= IOCTL_CDROM_MEDIA_CATALOG
;
980 data
->MediaCatalog
.Mcval
= sc
.what
.media_catalog
.mc_valid
;
981 memcpy(data
->MediaCatalog
.MediaCatalog
, sc
.what
.media_catalog
.mc_number
, 15);
983 case IOCTL_CDROM_TRACK_ISRC
:
984 size
= sizeof(SUB_Q_CURRENT_POSITION
);
985 data
->TrackIsrc
.FormatCode
= IOCTL_CDROM_TRACK_ISRC
;
986 data
->TrackIsrc
.Tcval
= sc
.what
.track_info
.ti_valid
;
987 memcpy(data
->TrackIsrc
.TrackIsrc
, sc
.what
.track_info
.ti_number
, 15);
992 ret
= CDROM_GetStatusCode(io
);
997 /******************************************************************
1002 static NTSTATUS
CDROM_Verify(int dev
)
1004 /* quick implementation */
1005 CDROM_SUB_Q_DATA_FORMAT fmt
;
1006 SUB_Q_CHANNEL_DATA data
;
1008 fmt
.Format
= IOCTL_CDROM_CURRENT_POSITION
;
1009 return CDROM_ReadQChannel(dev
, &fmt
, &data
) ? 1 : 0;
1012 /******************************************************************
1013 * CDROM_PlayAudioMSF
1017 static NTSTATUS
CDROM_PlayAudioMSF(int dev
, const CDROM_PLAY_AUDIO_MSF
* audio_msf
)
1019 NTSTATUS ret
= STATUS_NOT_SUPPORTED
;
1021 struct cdrom_msf msf
;
1024 msf
.cdmsf_min0
= audio_msf
->StartingM
;
1025 msf
.cdmsf_sec0
= audio_msf
->StartingS
;
1026 msf
.cdmsf_frame0
= audio_msf
->StartingF
;
1027 msf
.cdmsf_min1
= audio_msf
->EndingM
;
1028 msf
.cdmsf_sec1
= audio_msf
->EndingS
;
1029 msf
.cdmsf_frame1
= audio_msf
->EndingF
;
1031 io
= ioctl(cdrom_cache
[dev
].fd
, CDROMSTART
);
1034 WARN("motor doesn't start !\n");
1037 io
= ioctl(cdrom_cache
[dev
].fd
, CDROMPLAYMSF
, &msf
);
1040 WARN("device doesn't play !\n");
1043 TRACE("msf = %d:%d:%d %d:%d:%d\n",
1044 msf
.cdmsf_min0
, msf
.cdmsf_sec0
, msf
.cdmsf_frame0
,
1045 msf
.cdmsf_min1
, msf
.cdmsf_sec1
, msf
.cdmsf_frame1
);
1047 ret
= CDROM_GetStatusCode(io
);
1048 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1049 struct ioc_play_msf msf
;
1052 msf
.start_m
= audio_msf
->StartingM
;
1053 msf
.start_s
= audio_msf
->StartingS
;
1054 msf
.start_f
= audio_msf
->StartingF
;
1055 msf
.end_m
= audio_msf
->EndingM
;
1056 msf
.end_s
= audio_msf
->EndingS
;
1057 msf
.end_f
= audio_msf
->EndingF
;
1059 io
= ioctl(cdrom_cache
[dev
].fd
, CDIOCSTART
, NULL
);
1062 WARN("motor doesn't start !\n");
1065 io
= ioctl(cdrom_cache
[dev
].fd
, CDIOCPLAYMSF
, &msf
);
1068 WARN("device doesn't play !\n");
1071 TRACE("msf = %d:%d:%d %d:%d:%d\n",
1072 msf
.start_m
, msf
.start_s
, msf
.start_f
,
1073 msf
.end_m
, msf
.end_s
, msf
.end_f
);
1075 ret
= CDROM_GetStatusCode(io
);
1080 /******************************************************************
1081 * CDROM_SeekAudioMSF
1085 static NTSTATUS
CDROM_SeekAudioMSF(int dev
, const CDROM_SEEK_AUDIO_MSF
* audio_msf
)
1089 SUB_Q_CURRENT_POSITION
*cp
;
1091 struct cdrom_msf0 msf
;
1092 struct cdrom_subchnl sc
;
1093 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1094 struct ioc_play_msf msf
;
1095 struct ioc_read_subchannel read_sc
;
1096 struct cd_sub_channel_info sc
;
1100 /* Use the information on the TOC to compute the new current
1101 * position, which is shadowed on the cache. [Portable]. */
1102 frame
= FRAME_OF_MSF(*audio_msf
);
1103 cp
= &cdrom_cache
[dev
].CurrentPosition
;
1104 if ((io
= CDROM_ReadTOC(dev
, &toc
)) != 0) return io
;
1106 for(i
=toc
.FirstTrack
;i
<=toc
.LastTrack
+1;i
++)
1107 if (FRAME_OF_TOC(toc
,i
)>frame
) break;
1108 if (i
<= toc
.FirstTrack
|| i
> toc
.LastTrack
+1)
1109 return STATUS_INVALID_PARAMETER
;
1111 cp
->FormatCode
= IOCTL_CDROM_CURRENT_POSITION
;
1112 cp
->Control
= toc
.TrackData
[i
-toc
.FirstTrack
].Control
;
1113 cp
->ADR
= toc
.TrackData
[i
-toc
.FirstTrack
].Adr
;
1114 cp
->TrackNumber
= toc
.TrackData
[i
-toc
.FirstTrack
].TrackNumber
;
1115 cp
->IndexNumber
= 0; /* FIXME: where do they keep these? */
1116 cp
->AbsoluteAddress
[0] = 0;
1117 cp
->AbsoluteAddress
[1] = toc
.TrackData
[i
-toc
.FirstTrack
].Address
[1];
1118 cp
->AbsoluteAddress
[2] = toc
.TrackData
[i
-toc
.FirstTrack
].Address
[2];
1119 cp
->AbsoluteAddress
[3] = toc
.TrackData
[i
-toc
.FirstTrack
].Address
[3];
1120 frame
-= FRAME_OF_TOC(toc
,i
);
1121 cp
->TrackRelativeAddress
[0] = 0;
1122 MSF_OF_FRAME(cp
->TrackRelativeAddress
[1], frame
);
1124 /* If playing, then issue a seek command, otherwise do nothing */
1126 sc
.cdsc_format
= CDROM_MSF
;
1128 io
= ioctl(cdrom_cache
[dev
].fd
, CDROMSUBCHNL
, &sc
);
1131 TRACE("opened or no_media (%s)!\n", strerror(errno
));
1132 CDROM_ClearCacheEntry(dev
);
1133 return CDROM_GetStatusCode(io
);
1135 if (sc
.cdsc_audiostatus
==CDROM_AUDIO_PLAY
)
1137 msf
.minute
= audio_msf
->M
;
1138 msf
.second
= audio_msf
->S
;
1139 msf
.frame
= audio_msf
->F
;
1140 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDROMSEEK
, &msf
));
1142 return STATUS_SUCCESS
;
1143 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1144 read_sc
.address_format
= CD_MSF_FORMAT
;
1146 read_sc
.data_len
= sizeof(sc
);
1148 read_sc
.data_format
= CD_CURRENT_POSITION
;
1150 io
= ioctl(cdrom_cache
[dev
].fd
, CDIOCREADSUBCHANNEL
, &read_sc
);
1153 TRACE("opened or no_media (%s)!\n", strerror(errno
));
1154 CDROM_ClearCacheEntry(dev
);
1155 return CDROM_GetStatusCode(io
);
1157 if (sc
.header
.audio_status
==CD_AS_PLAY_IN_PROGRESS
)
1160 msf
.start_m
= audio_msf
->M
;
1161 msf
.start_s
= audio_msf
->S
;
1162 msf
.start_f
= audio_msf
->F
;
1163 final_frame
= FRAME_OF_TOC(toc
,toc
.LastTrack
+1)-1;
1164 MSF_OF_FRAME(msf
.end_m
, final_frame
);
1166 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDIOCPLAYMSF
, &msf
));
1168 return STATUS_SUCCESS
;
1170 return STATUS_NOT_SUPPORTED
;
1174 /******************************************************************
1179 static NTSTATUS
CDROM_PauseAudio(int dev
)
1182 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDROMPAUSE
));
1183 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1184 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDIOCPAUSE
, NULL
));
1186 return STATUS_NOT_SUPPORTED
;
1190 /******************************************************************
1195 static NTSTATUS
CDROM_ResumeAudio(int dev
)
1198 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDROMRESUME
));
1199 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1200 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDIOCRESUME
, NULL
));
1202 return STATUS_NOT_SUPPORTED
;
1206 /******************************************************************
1211 static NTSTATUS
CDROM_StopAudio(int dev
)
1214 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDROMSTOP
));
1215 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1216 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDIOCSTOP
, NULL
));
1218 return STATUS_NOT_SUPPORTED
;
1222 /******************************************************************
1227 static NTSTATUS
CDROM_GetVolume(int dev
, VOLUME_CONTROL
* vc
)
1230 struct cdrom_volctrl volc
;
1233 io
= ioctl(cdrom_cache
[dev
].fd
, CDROMVOLREAD
, &volc
);
1236 vc
->PortVolume
[0] = volc
.channel0
;
1237 vc
->PortVolume
[1] = volc
.channel1
;
1238 vc
->PortVolume
[2] = volc
.channel2
;
1239 vc
->PortVolume
[3] = volc
.channel3
;
1241 return CDROM_GetStatusCode(io
);
1242 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1243 struct ioc_vol volc
;
1246 io
= ioctl(cdrom_cache
[dev
].fd
, CDIOCGETVOL
, &volc
);
1249 vc
->PortVolume
[0] = volc
.vol
[0];
1250 vc
->PortVolume
[1] = volc
.vol
[1];
1251 vc
->PortVolume
[2] = volc
.vol
[2];
1252 vc
->PortVolume
[3] = volc
.vol
[3];
1254 return CDROM_GetStatusCode(io
);
1256 return STATUS_NOT_SUPPORTED
;
1260 /******************************************************************
1265 static NTSTATUS
CDROM_SetVolume(int dev
, const VOLUME_CONTROL
* vc
)
1268 struct cdrom_volctrl volc
;
1270 volc
.channel0
= vc
->PortVolume
[0];
1271 volc
.channel1
= vc
->PortVolume
[1];
1272 volc
.channel2
= vc
->PortVolume
[2];
1273 volc
.channel3
= vc
->PortVolume
[3];
1275 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDROMVOLCTRL
, &volc
));
1276 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1277 struct ioc_vol volc
;
1279 volc
.vol
[0] = vc
->PortVolume
[0];
1280 volc
.vol
[1] = vc
->PortVolume
[1];
1281 volc
.vol
[2] = vc
->PortVolume
[2];
1282 volc
.vol
[3] = vc
->PortVolume
[3];
1284 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDIOCSETVOL
, &volc
));
1286 return STATUS_NOT_SUPPORTED
;
1290 /******************************************************************
1295 static NTSTATUS
CDROM_RawRead(int dev
, const RAW_READ_INFO
* raw
, void* buffer
, DWORD len
, DWORD
* sz
)
1297 int ret
= STATUS_NOT_SUPPORTED
;
1301 switch (raw
->TrackMode
)
1303 case YellowMode2
: sectSize
= 2336; break;
1304 case XAForm2
: sectSize
= 2328; break;
1305 case CDDA
: sectSize
= 2352; break;
1306 default: return STATUS_INVALID_PARAMETER
;
1308 if (len
< raw
->SectorCount
* sectSize
) return STATUS_BUFFER_TOO_SMALL
;
1309 /* strangely enough, it seems that sector offsets are always indicated with a size of 2048,
1310 * even if a larger size if read...
1314 struct cdrom_read cdr
;
1315 struct cdrom_read_audio cdra
;
1317 switch (raw
->TrackMode
)
1320 if (raw
->DiskOffset
.s
.HighPart
) FIXME("Unsupported value\n");
1321 cdr
.cdread_lba
= raw
->DiskOffset
.s
.LowPart
; /* FIXME ? */
1322 cdr
.cdread_bufaddr
= buffer
;
1323 cdr
.cdread_buflen
= raw
->SectorCount
* sectSize
;
1324 io
= ioctl(cdrom_cache
[dev
].fd
, CDROMREADMODE2
, &cdr
);
1327 FIXME("XAForm2: NIY\n");
1330 /* FIXME: the output doesn't seem 100% correct... in fact output is shifted
1331 * between by NT2K box and this... should check on the same drive...
1332 * otherwise, I fear a 2352/2368 mismatch somewhere in one of the drivers
1334 * Anyway, that's not critical at all. We're talking of 16/32 bytes, we're
1335 * talking of 0.2 ms of sound
1337 /* 2048 = 2 ** 11 */
1338 if (raw
->DiskOffset
.s
.HighPart
& ~2047) FIXME("Unsupported value\n");
1339 cdra
.addr
.lba
= ((raw
->DiskOffset
.s
.LowPart
>> 11) |
1340 (raw
->DiskOffset
.s
.HighPart
<< (32 - 11))) - 1;
1341 FIXME("reading at %u\n", cdra
.addr
.lba
);
1342 cdra
.addr_format
= CDROM_LBA
;
1343 cdra
.nframes
= raw
->SectorCount
;
1345 io
= ioctl(cdrom_cache
[dev
].fd
, CDROMREADAUDIO
, &cdra
);
1348 FIXME("NIY: %d\n", raw
->TrackMode
);
1352 #elif defined(__FreeBSD__)
1354 struct ioc_read_audio ira
;
1356 switch (raw
->TrackMode
)
1359 FIXME("YellowMode2: NIY\n");
1362 FIXME("XAForm2: NIY\n");
1365 /* 2048 = 2 ** 11 */
1366 if (raw
->DiskOffset
.s
.HighPart
& ~2047) FIXME("Unsupported value\n");
1367 ira
.address
.lba
= ((raw
->DiskOffset
.s
.LowPart
>> 11) |
1368 raw
->DiskOffset
.s
.HighPart
<< (32 - 11)) - 1;
1369 ira
.address_format
= CD_LBA_FORMAT
;
1370 ira
.nframes
= raw
->SectorCount
;
1371 ira
.buffer
= buffer
;
1372 io
= ioctl(cdrom_cache
[dev
].fd
, CDIOCREADAUDIO
, &ira
);
1376 #elif defined(__NetBSD__)
1378 switch (raw
->TrackMode
)
1381 FIXME("YellowMode2: NIY\n");
1384 FIXME("XAForm2: NIY\n");
1387 FIXME("CDDA: NIY\n");
1392 *sz
= sectSize
* raw
->SectorCount
;
1393 ret
= CDROM_GetStatusCode(io
);
1397 /******************************************************************
1398 * CDROM_ScsiPassThroughDirect
1402 static NTSTATUS
CDROM_ScsiPassThroughDirect(int dev
, PSCSI_PASS_THROUGH_DIRECT pPacket
)
1404 int ret
= STATUS_NOT_SUPPORTED
;
1405 #if defined(linux) && defined(CDROM_SEND_PACKET)
1406 struct linux_cdrom_generic_command cmd
;
1407 struct request_sense sense
;
1410 if (pPacket
->Length
< sizeof(SCSI_PASS_THROUGH_DIRECT
))
1411 return STATUS_BUFFER_TOO_SMALL
;
1413 if (pPacket
->CdbLength
> 12)
1414 return STATUS_INVALID_PARAMETER
;
1416 if (pPacket
->SenseInfoLength
> sizeof(sense
))
1417 return STATUS_INVALID_PARAMETER
;
1419 memset(&cmd
, 0, sizeof(cmd
));
1420 memset(&sense
, 0, sizeof(sense
));
1422 memcpy(&(cmd
.cmd
), &(pPacket
->Cdb
), pPacket
->CdbLength
);
1424 cmd
.buffer
= pPacket
->DataBuffer
;
1425 cmd
.buflen
= pPacket
->DataTransferLength
;
1428 cmd
.timeout
= pPacket
->TimeOutValue
*HZ
;
1430 switch (pPacket
->DataIn
)
1432 case SCSI_IOCTL_DATA_OUT
:
1433 cmd
.data_direction
= CGC_DATA_WRITE
;
1435 case SCSI_IOCTL_DATA_IN
:
1436 cmd
.data_direction
= CGC_DATA_READ
;
1438 case SCSI_IOCTL_DATA_UNSPECIFIED
:
1439 cmd
.data_direction
= CGC_DATA_NONE
;
1442 return STATUS_INVALID_PARAMETER
;
1445 io
= ioctl(cdrom_cache
[dev
].fd
, CDROM_SEND_PACKET
, &cmd
);
1447 if (pPacket
->SenseInfoLength
!= 0)
1449 memcpy((char*)pPacket
+ pPacket
->SenseInfoOffset
,
1450 &sense
, pPacket
->SenseInfoLength
);
1453 pPacket
->ScsiStatus
= cmd
.stat
;
1455 ret
= CDROM_GetStatusCode(io
);
1457 #elif defined(__NetBSD__)
1461 if (pPacket
->Length
< sizeof(SCSI_PASS_THROUGH_DIRECT
))
1462 return STATUS_BUFFER_TOO_SMALL
;
1464 if (pPacket
->CdbLength
> 12)
1465 return STATUS_INVALID_PARAMETER
;
1467 if (pPacket
->SenseInfoLength
> SENSEBUFLEN
)
1468 return STATUS_INVALID_PARAMETER
;
1470 memset(&cmd
, 0, sizeof(cmd
));
1471 memcpy(&(cmd
.cmd
), &(pPacket
->Cdb
), pPacket
->CdbLength
);
1473 cmd
.cmdlen
= pPacket
->CdbLength
;
1474 cmd
.databuf
= pPacket
->DataBuffer
;
1475 cmd
.datalen
= pPacket
->DataTransferLength
;
1476 cmd
.senselen
= pPacket
->SenseInfoLength
;
1477 cmd
.timeout
= pPacket
->TimeOutValue
*1000; /* in milliseconds */
1479 switch (pPacket
->DataIn
)
1481 case SCSI_IOCTL_DATA_OUT
:
1482 cmd
.flags
|= SCCMD_WRITE
;
1484 case SCSI_IOCTL_DATA_IN
:
1485 cmd
.flags
|= SCCMD_READ
;
1487 case SCSI_IOCTL_DATA_UNSPECIFIED
:
1491 return STATUS_INVALID_PARAMETER
;
1494 io
= ioctl(cdrom_cache
[dev
].fd
, SCIOCCOMMAND
, &cmd
);
1498 case SCCMD_OK
: break;
1499 case SCCMD_TIMEOUT
: return STATUS_TIMEOUT
;
1501 case SCCMD_BUSY
: return STATUS_DEVICE_BUSY
;
1503 case SCCMD_SENSE
: break;
1504 case SCCMD_UNKNOWN
: return STATUS_UNSUCCESSFUL
;
1508 if (pPacket
->SenseInfoLength
!= 0)
1510 memcpy((char*)pPacket
+ pPacket
->SenseInfoOffset
,
1511 cmd
.sense
, pPacket
->SenseInfoLength
);
1514 pPacket
->ScsiStatus
= cmd
.status
;
1516 ret
= CDROM_GetStatusCode(io
);
1521 /******************************************************************
1522 * CDROM_ScsiPassThrough
1526 static NTSTATUS
CDROM_ScsiPassThrough(int dev
, PSCSI_PASS_THROUGH pPacket
)
1528 int ret
= STATUS_NOT_SUPPORTED
;
1529 #if defined(linux) && defined(CDROM_SEND_PACKET)
1530 struct linux_cdrom_generic_command cmd
;
1531 struct request_sense sense
;
1534 if (pPacket
->Length
< sizeof(SCSI_PASS_THROUGH
))
1535 return STATUS_BUFFER_TOO_SMALL
;
1537 if (pPacket
->CdbLength
> 12)
1538 return STATUS_INVALID_PARAMETER
;
1540 if (pPacket
->SenseInfoLength
> sizeof(sense
))
1541 return STATUS_INVALID_PARAMETER
;
1543 memset(&cmd
, 0, sizeof(cmd
));
1544 memset(&sense
, 0, sizeof(sense
));
1546 memcpy(&(cmd
.cmd
), &(pPacket
->Cdb
), pPacket
->CdbLength
);
1548 if ( pPacket
->DataBufferOffset
> 0x1000 )
1550 cmd
.buffer
= (void*)pPacket
->DataBufferOffset
;
1554 cmd
.buffer
= (char*)pPacket
+ pPacket
->DataBufferOffset
;
1556 cmd
.buflen
= pPacket
->DataTransferLength
;
1559 cmd
.timeout
= pPacket
->TimeOutValue
*HZ
;
1561 switch (pPacket
->DataIn
)
1563 case SCSI_IOCTL_DATA_OUT
:
1564 cmd
.data_direction
= CGC_DATA_WRITE
;
1566 case SCSI_IOCTL_DATA_IN
:
1567 cmd
.data_direction
= CGC_DATA_READ
;
1569 case SCSI_IOCTL_DATA_UNSPECIFIED
:
1570 cmd
.data_direction
= CGC_DATA_NONE
;
1573 return STATUS_INVALID_PARAMETER
;
1576 io
= ioctl(cdrom_cache
[dev
].fd
, CDROM_SEND_PACKET
, &cmd
);
1578 if (pPacket
->SenseInfoLength
!= 0)
1580 memcpy((char*)pPacket
+ pPacket
->SenseInfoOffset
,
1581 &sense
, pPacket
->SenseInfoLength
);
1584 pPacket
->ScsiStatus
= cmd
.stat
;
1586 ret
= CDROM_GetStatusCode(io
);
1588 #elif defined(__NetBSD__)
1592 if (pPacket
->Length
< sizeof(SCSI_PASS_THROUGH
))
1593 return STATUS_BUFFER_TOO_SMALL
;
1595 if (pPacket
->CdbLength
> 12)
1596 return STATUS_INVALID_PARAMETER
;
1598 if (pPacket
->SenseInfoLength
> SENSEBUFLEN
)
1599 return STATUS_INVALID_PARAMETER
;
1601 memset(&cmd
, 0, sizeof(cmd
));
1602 memcpy(&(cmd
.cmd
), &(pPacket
->Cdb
), pPacket
->CdbLength
);
1604 if ( pPacket
->DataBufferOffset
> 0x1000 )
1606 cmd
.databuf
= (void*)pPacket
->DataBufferOffset
;
1610 cmd
.databuf
= (char*)pPacket
+ pPacket
->DataBufferOffset
;
1613 cmd
.cmdlen
= pPacket
->CdbLength
;
1614 cmd
.datalen
= pPacket
->DataTransferLength
;
1615 cmd
.senselen
= pPacket
->SenseInfoLength
;
1616 cmd
.timeout
= pPacket
->TimeOutValue
*1000; /* in milliseconds */
1618 switch (pPacket
->DataIn
)
1620 case SCSI_IOCTL_DATA_OUT
:
1621 cmd
.flags
|= SCCMD_WRITE
;
1623 case SCSI_IOCTL_DATA_IN
:
1624 cmd
.flags
|= SCCMD_READ
;
1626 case SCSI_IOCTL_DATA_UNSPECIFIED
:
1630 return STATUS_INVALID_PARAMETER
;
1633 io
= ioctl(cdrom_cache
[dev
].fd
, SCIOCCOMMAND
, &cmd
);
1637 case SCCMD_OK
: break;
1638 case SCCMD_TIMEOUT
: return STATUS_TIMEOUT
;
1640 case SCCMD_BUSY
: return STATUS_DEVICE_BUSY
;
1642 case SCCMD_SENSE
: break;
1643 case SCCMD_UNKNOWN
: return STATUS_UNSUCCESSFUL
;
1647 if (pPacket
->SenseInfoLength
!= 0)
1649 memcpy((char*)pPacket
+ pPacket
->SenseInfoOffset
,
1650 cmd
.sense
, pPacket
->SenseInfoLength
);
1653 pPacket
->ScsiStatus
= cmd
.status
;
1655 ret
= CDROM_GetStatusCode(io
);
1660 /******************************************************************
1665 static NTSTATUS
CDROM_ScsiGetCaps(int dev
, PIO_SCSI_CAPABILITIES caps
)
1667 NTSTATUS ret
= STATUS_NOT_IMPLEMENTED
;
1669 caps
->Length
= sizeof(*caps
);
1671 caps
->MaximumTransferLength
= SG_SCATTER_SZ
; /* FIXME */
1672 caps
->MaximumPhysicalPages
= SG_SCATTER_SZ
/ getpagesize();
1673 caps
->SupportedAsynchronousEvents
= TRUE
;
1674 caps
->AlignmentMask
= getpagesize();
1675 caps
->TaggedQueuing
= FALSE
; /* we could check that it works and answer TRUE */
1676 caps
->AdapterScansDown
= FALSE
; /* FIXME ? */
1677 caps
->AdapterUsesPio
= FALSE
; /* FIXME ? */
1678 ret
= STATUS_SUCCESS
;
1680 FIXME("Unimplemented\n");
1685 /******************************************************************
1688 * implements IOCTL_SCSI_GET_ADDRESS
1690 static NTSTATUS
CDROM_GetAddress(int dev
, SCSI_ADDRESS
* address
)
1692 int portnum
, busid
, targetid
, lun
;
1694 address
->Length
= sizeof(SCSI_ADDRESS
);
1695 if ( ! CDROM_GetInterfaceInfo(cdrom_cache
[dev
].fd
, &portnum
,
1696 &busid
, &targetid
, &lun
))
1697 return STATUS_NOT_SUPPORTED
;
1699 address
->PortNumber
= portnum
;
1700 address
->PathId
= busid
; /* bus number */
1701 address
->TargetId
= targetid
;
1703 return STATUS_SUCCESS
;
1706 /******************************************************************
1707 * CDROM_DeviceIoControl
1711 NTSTATUS
CDROM_DeviceIoControl(DWORD clientID
, HANDLE hDevice
,
1712 HANDLE hEvent
, PIO_APC_ROUTINE UserApcRoutine
,
1713 PVOID UserApcContext
,
1714 PIO_STATUS_BLOCK piosb
,
1715 ULONG dwIoControlCode
,
1716 LPVOID lpInBuffer
, DWORD nInBufferSize
,
1717 LPVOID lpOutBuffer
, DWORD nOutBufferSize
)
1720 NTSTATUS status
= STATUS_SUCCESS
;
1723 TRACE("%lx[%c] %s %lx %ld %lx %ld %p\n",
1724 (DWORD
)hDevice
, 'A' + LOWORD(clientID
), iocodex(dwIoControlCode
), (DWORD
)lpInBuffer
, nInBufferSize
,
1725 (DWORD
)lpOutBuffer
, nOutBufferSize
, piosb
);
1727 piosb
->Information
= 0;
1729 if ((status
= CDROM_Open(hDevice
, clientID
, &dev
))) goto error
;
1731 switch (dwIoControlCode
)
1733 case IOCTL_STORAGE_CHECK_VERIFY
:
1734 case IOCTL_CDROM_CHECK_VERIFY
:
1736 CDROM_ClearCacheEntry(dev
);
1737 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0 || lpOutBuffer
!= NULL
|| nOutBufferSize
!= 0)
1738 status
= STATUS_INVALID_PARAMETER
;
1739 else status
= CDROM_Verify(dev
);
1742 /* EPP case IOCTL_STORAGE_CHECK_VERIFY2: */
1744 /* EPP case IOCTL_STORAGE_FIND_NEW_DEVICES: */
1745 /* EPP case IOCTL_CDROM_FIND_NEW_DEVICES: */
1747 case IOCTL_STORAGE_LOAD_MEDIA
:
1748 case IOCTL_CDROM_LOAD_MEDIA
:
1750 CDROM_ClearCacheEntry(dev
);
1751 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0 || lpOutBuffer
!= NULL
|| nOutBufferSize
!= 0)
1752 status
= STATUS_INVALID_PARAMETER
;
1753 else status
= CDROM_SetTray(dev
, FALSE
);
1755 case IOCTL_STORAGE_EJECT_MEDIA
:
1757 CDROM_ClearCacheEntry(dev
);
1758 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0 || lpOutBuffer
!= NULL
|| nOutBufferSize
!= 0)
1759 status
= STATUS_INVALID_PARAMETER
;
1760 else status
= CDROM_SetTray(dev
, TRUE
);
1763 case IOCTL_CDROM_MEDIA_REMOVAL
:
1764 case IOCTL_DISK_MEDIA_REMOVAL
:
1765 case IOCTL_STORAGE_MEDIA_REMOVAL
:
1766 case IOCTL_STORAGE_EJECTION_CONTROL
:
1767 /* FIXME the last ioctl:s is not the same as the two others...
1768 * lockcount/owner should be handled */
1770 CDROM_ClearCacheEntry(dev
);
1771 if (lpOutBuffer
!= NULL
|| nOutBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
1772 else if (nInBufferSize
< sizeof(PREVENT_MEDIA_REMOVAL
)) status
= STATUS_BUFFER_TOO_SMALL
;
1773 else status
= CDROM_ControlEjection(dev
, (const PREVENT_MEDIA_REMOVAL
*)lpInBuffer
);
1776 /* EPP case IOCTL_STORAGE_GET_MEDIA_TYPES: */
1778 case IOCTL_STORAGE_GET_DEVICE_NUMBER
:
1779 sz
= sizeof(STORAGE_DEVICE_NUMBER
);
1780 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
1781 else if (nOutBufferSize
< sz
) status
= STATUS_BUFFER_TOO_SMALL
;
1782 else status
= CDROM_GetDeviceNumber(dev
, (STORAGE_DEVICE_NUMBER
*)lpOutBuffer
);
1785 case IOCTL_STORAGE_RESET_DEVICE
:
1787 CDROM_ClearCacheEntry(dev
);
1788 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0 || lpOutBuffer
!= NULL
|| nOutBufferSize
!= 0)
1789 status
= STATUS_INVALID_PARAMETER
;
1790 else status
= CDROM_ResetAudio(dev
);
1793 case IOCTL_CDROM_GET_CONTROL
:
1794 sz
= sizeof(CDROM_AUDIO_CONTROL
);
1795 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
1796 else if (nOutBufferSize
< sz
) status
= STATUS_BUFFER_TOO_SMALL
;
1797 else status
= CDROM_GetControl(dev
, (CDROM_AUDIO_CONTROL
*)lpOutBuffer
);
1800 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
:
1801 sz
= sizeof(DISK_GEOMETRY
);
1802 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
1803 else if (nOutBufferSize
< sz
) status
= STATUS_BUFFER_TOO_SMALL
;
1804 else status
= CDROM_GetDriveGeometry(dev
, (DISK_GEOMETRY
*)lpOutBuffer
);
1807 case IOCTL_CDROM_DISK_TYPE
:
1808 sz
= sizeof(CDROM_DISK_DATA
);
1809 /* CDROM_ClearCacheEntry(dev); */
1810 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
1811 else if (nOutBufferSize
< sz
) status
= STATUS_BUFFER_TOO_SMALL
;
1812 else status
= CDROM_GetDiskData(dev
, (CDROM_DISK_DATA
*)lpOutBuffer
);
1815 /* EPP case IOCTL_CDROM_GET_LAST_SESSION: */
1817 case IOCTL_CDROM_READ_Q_CHANNEL
:
1818 sz
= sizeof(SUB_Q_CHANNEL_DATA
);
1819 if (lpInBuffer
== NULL
|| nInBufferSize
< sizeof(CDROM_SUB_Q_DATA_FORMAT
))
1820 status
= STATUS_INVALID_PARAMETER
;
1821 else if (nOutBufferSize
< sz
) status
= STATUS_BUFFER_TOO_SMALL
;
1822 else status
= CDROM_ReadQChannel(dev
, (const CDROM_SUB_Q_DATA_FORMAT
*)lpInBuffer
,
1823 (SUB_Q_CHANNEL_DATA
*)lpOutBuffer
);
1826 case IOCTL_CDROM_READ_TOC
:
1827 sz
= sizeof(CDROM_TOC
);
1828 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
1829 else if (nOutBufferSize
< sz
) status
= STATUS_BUFFER_TOO_SMALL
;
1830 else status
= CDROM_ReadTOC(dev
, (CDROM_TOC
*)lpOutBuffer
);
1833 /* EPP case IOCTL_CDROM_READ_TOC_EX: */
1835 case IOCTL_CDROM_PAUSE_AUDIO
:
1837 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0 || lpOutBuffer
!= NULL
|| nOutBufferSize
!= 0)
1838 status
= STATUS_INVALID_PARAMETER
;
1839 else status
= CDROM_PauseAudio(dev
);
1841 case IOCTL_CDROM_PLAY_AUDIO_MSF
:
1843 if (lpOutBuffer
!= NULL
|| nOutBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
1844 else if (nInBufferSize
< sizeof(CDROM_PLAY_AUDIO_MSF
)) status
= STATUS_BUFFER_TOO_SMALL
;
1845 else status
= CDROM_PlayAudioMSF(dev
, (const CDROM_PLAY_AUDIO_MSF
*)lpInBuffer
);
1847 case IOCTL_CDROM_RESUME_AUDIO
:
1849 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0 || lpOutBuffer
!= NULL
|| nOutBufferSize
!= 0)
1850 status
= STATUS_INVALID_PARAMETER
;
1851 else status
= CDROM_ResumeAudio(dev
);
1853 case IOCTL_CDROM_SEEK_AUDIO_MSF
:
1855 if (lpOutBuffer
!= NULL
|| nOutBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
1856 else if (nInBufferSize
< sizeof(CDROM_SEEK_AUDIO_MSF
)) status
= STATUS_BUFFER_TOO_SMALL
;
1857 else status
= CDROM_SeekAudioMSF(dev
, (const CDROM_SEEK_AUDIO_MSF
*)lpInBuffer
);
1859 case IOCTL_CDROM_STOP_AUDIO
:
1861 CDROM_ClearCacheEntry(dev
); /* Maybe intention is to change media */
1862 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0 || lpOutBuffer
!= NULL
|| nOutBufferSize
!= 0)
1863 status
= STATUS_INVALID_PARAMETER
;
1864 else status
= CDROM_StopAudio(dev
);
1866 case IOCTL_CDROM_GET_VOLUME
:
1867 sz
= sizeof(VOLUME_CONTROL
);
1868 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
1869 else if (nOutBufferSize
< sz
) status
= STATUS_BUFFER_TOO_SMALL
;
1870 else status
= CDROM_GetVolume(dev
, (VOLUME_CONTROL
*)lpOutBuffer
);
1872 case IOCTL_CDROM_SET_VOLUME
:
1874 CDROM_ClearCacheEntry(dev
);
1875 if (lpInBuffer
== NULL
|| nInBufferSize
< sizeof(VOLUME_CONTROL
) || lpOutBuffer
!= NULL
)
1876 status
= STATUS_INVALID_PARAMETER
;
1877 else status
= CDROM_SetVolume(dev
, (const VOLUME_CONTROL
*)lpInBuffer
);
1879 case IOCTL_CDROM_RAW_READ
:
1881 if (nInBufferSize
< sizeof(RAW_READ_INFO
)) status
= STATUS_INVALID_PARAMETER
;
1882 else if (lpOutBuffer
== NULL
) status
= STATUS_BUFFER_TOO_SMALL
;
1883 else status
= CDROM_RawRead(dev
, (const RAW_READ_INFO
*)lpInBuffer
,
1884 lpOutBuffer
, nOutBufferSize
, &sz
);
1886 case IOCTL_SCSI_GET_ADDRESS
:
1887 sz
= sizeof(SCSI_ADDRESS
);
1888 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
1889 else if (nOutBufferSize
< sz
) status
= STATUS_BUFFER_TOO_SMALL
;
1890 else status
= CDROM_GetAddress(dev
, (SCSI_ADDRESS
*)lpOutBuffer
);
1892 case IOCTL_SCSI_PASS_THROUGH_DIRECT
:
1893 sz
= sizeof(SCSI_PASS_THROUGH_DIRECT
);
1894 if (lpOutBuffer
== NULL
) status
= STATUS_INVALID_PARAMETER
;
1895 else if (nOutBufferSize
< sizeof(SCSI_PASS_THROUGH_DIRECT
)) status
= STATUS_BUFFER_TOO_SMALL
;
1896 else status
= CDROM_ScsiPassThroughDirect(dev
, (PSCSI_PASS_THROUGH_DIRECT
)lpOutBuffer
);
1898 case IOCTL_SCSI_PASS_THROUGH
:
1899 sz
= sizeof(SCSI_PASS_THROUGH
);
1900 if (lpOutBuffer
== NULL
) status
= STATUS_INVALID_PARAMETER
;
1901 else if (nOutBufferSize
< sizeof(SCSI_PASS_THROUGH
)) status
= STATUS_BUFFER_TOO_SMALL
;
1902 else status
= CDROM_ScsiPassThrough(dev
, (PSCSI_PASS_THROUGH
)lpOutBuffer
);
1904 case IOCTL_SCSI_GET_CAPABILITIES
:
1905 sz
= sizeof(IO_SCSI_CAPABILITIES
);
1906 if (lpOutBuffer
== NULL
) status
= STATUS_INVALID_PARAMETER
;
1907 else if (nOutBufferSize
< sizeof(IO_SCSI_CAPABILITIES
)) status
= STATUS_BUFFER_TOO_SMALL
;
1908 else status
= CDROM_ScsiGetCaps(dev
, (PIO_SCSI_CAPABILITIES
)lpOutBuffer
);
1911 FIXME("Unsupported IOCTL %lx (type=%lx access=%lx func=%lx meth=%lx)\n",
1912 dwIoControlCode
, dwIoControlCode
>> 16, (dwIoControlCode
>> 14) & 3,
1913 (dwIoControlCode
>> 2) & 0xFFF, dwIoControlCode
& 3);
1915 status
= STATUS_INVALID_PARAMETER
;
1918 CDROM_Close(clientID
);
1920 piosb
->u
.Status
= status
;
1921 piosb
->Information
= sz
;
1922 if (hEvent
) NtSetEvent(hEvent
, NULL
);