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 return STATUS_NOT_SUPPORTED
;
627 FIXME("Unmapped error code %d: %s\n", errno
, strerror(errno
));
628 return STATUS_IO_DEVICE_ERROR
;
631 /******************************************************************
635 static NTSTATUS
CDROM_GetControl(int dev
, CDROM_AUDIO_CONTROL
* cac
)
637 cac
->LbaFormat
= 0; /* FIXME */
638 cac
->LogicalBlocksPerSecond
= 1; /* FIXME */
639 return STATUS_NOT_SUPPORTED
;
642 /******************************************************************
643 * CDROM_GetDeviceNumber
646 static NTSTATUS
CDROM_GetDeviceNumber(int dev
, STORAGE_DEVICE_NUMBER
* devnum
)
648 return STATUS_NOT_SUPPORTED
;
651 /******************************************************************
652 * CDROM_GetDriveGeometry
655 static NTSTATUS
CDROM_GetDriveGeometry(int dev
, DISK_GEOMETRY
* dg
)
661 if ((ret
= CDROM_ReadTOC(dev
, &toc
)) != 0) return ret
;
663 fsize
= FRAME_OF_TOC(toc
, toc
.LastTrack
+1)
664 - FRAME_OF_TOC(toc
, 1); /* Total size in frames */
666 dg
->Cylinders
.s
.LowPart
= fsize
/ (64 * 32);
667 dg
->Cylinders
.s
.HighPart
= 0;
668 dg
->MediaType
= RemovableMedia
;
669 dg
->TracksPerCylinder
= 64;
670 dg
->SectorsPerTrack
= 32;
671 dg
->BytesPerSector
= 2048;
675 /**************************************************************************
676 * CDROM_Reset [internal]
678 static NTSTATUS
CDROM_ResetAudio(int dev
)
681 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDROMRESET
));
682 #elif defined(__FreeBSD__) || defined(__NetBSD__)
683 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDIOCRESET
, NULL
));
685 return STATUS_NOT_SUPPORTED
;
689 /******************************************************************
694 static NTSTATUS
CDROM_SetTray(int dev
, BOOL doEject
)
697 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, doEject
? CDROMEJECT
: CDROMCLOSETRAY
));
698 #elif defined(__FreeBSD__) || defined(__NetBSD__)
699 return CDROM_GetStatusCode((ioctl(cdrom_cache
[dev
].fd
, CDIOCALLOW
, NULL
)) ||
700 (ioctl(cdrom_cache
[dev
].fd
, doEject
? CDIOCEJECT
: CDIOCCLOSE
, NULL
)) ||
701 (ioctl(cdrom_cache
[dev
].fd
, CDIOCPREVENT
, NULL
)));
703 return STATUS_NOT_SUPPORTED
;
707 /******************************************************************
708 * CDROM_ControlEjection
712 static NTSTATUS
CDROM_ControlEjection(int dev
, const PREVENT_MEDIA_REMOVAL
* rmv
)
715 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDROM_LOCKDOOR
, rmv
->PreventMediaRemoval
));
716 #elif defined(__FreeBSD__) || defined(__NetBSD__)
717 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, (rmv
->PreventMediaRemoval
) ? CDIOCPREVENT
: CDIOCALLOW
, NULL
));
719 return STATUS_NOT_SUPPORTED
;
723 /******************************************************************
728 static NTSTATUS
CDROM_ReadTOC(int dev
, CDROM_TOC
* toc
)
730 NTSTATUS ret
= STATUS_NOT_SUPPORTED
;
732 if (dev
< 0 || dev
>= 26)
733 return STATUS_INVALID_PARAMETER
;
734 if ( !cdrom_cache
[dev
].toc_good
) {
735 ret
= CDROM_SyncCache(dev
);
739 *toc
= cdrom_cache
[dev
].toc
;
740 return STATUS_SUCCESS
;
743 /******************************************************************
748 static NTSTATUS
CDROM_GetDiskData(int dev
, CDROM_DISK_DATA
* data
)
754 if ((ret
= CDROM_ReadTOC(dev
, &toc
)) != 0) return ret
;
756 for (i
= toc
.FirstTrack
; i
<= toc
.LastTrack
; i
++) {
757 if (toc
.TrackData
[i
-toc
.FirstTrack
].Control
& 0x04)
758 data
->DiskData
|= CDROM_DISK_DATA_TRACK
;
760 data
->DiskData
|= CDROM_DISK_AUDIO_TRACK
;
762 return STATUS_SUCCESS
;
765 /******************************************************************
770 static NTSTATUS
CDROM_ReadQChannel(int dev
, const CDROM_SUB_Q_DATA_FORMAT
* fmt
,
771 SUB_Q_CHANNEL_DATA
* data
)
773 NTSTATUS ret
= STATUS_NOT_SUPPORTED
;
776 SUB_Q_HEADER
* hdr
= (SUB_Q_HEADER
*)data
;
778 struct cdrom_subchnl sc
;
779 sc
.cdsc_format
= CDROM_MSF
;
781 io
= ioctl(cdrom_cache
[dev
].fd
, CDROMSUBCHNL
, &sc
);
784 TRACE("opened or no_media (%s)!\n", strerror(errno
));
785 hdr
->AudioStatus
= AUDIO_STATUS_NO_STATUS
;
786 CDROM_ClearCacheEntry(dev
);
790 hdr
->AudioStatus
= AUDIO_STATUS_NOT_SUPPORTED
;
792 switch (sc
.cdsc_audiostatus
) {
793 case CDROM_AUDIO_INVALID
:
794 CDROM_ClearCacheEntry(dev
);
795 hdr
->AudioStatus
= AUDIO_STATUS_NOT_SUPPORTED
;
797 case CDROM_AUDIO_NO_STATUS
:
798 CDROM_ClearCacheEntry(dev
);
799 hdr
->AudioStatus
= AUDIO_STATUS_NO_STATUS
;
801 case CDROM_AUDIO_PLAY
:
802 hdr
->AudioStatus
= AUDIO_STATUS_IN_PROGRESS
;
804 case CDROM_AUDIO_PAUSED
:
805 hdr
->AudioStatus
= AUDIO_STATUS_PAUSED
;
807 case CDROM_AUDIO_COMPLETED
:
808 hdr
->AudioStatus
= AUDIO_STATUS_PLAY_COMPLETE
;
810 case CDROM_AUDIO_ERROR
:
811 hdr
->AudioStatus
= AUDIO_STATUS_PLAY_ERROR
;
814 TRACE("status=%02X !\n", sc
.cdsc_audiostatus
);
819 case IOCTL_CDROM_CURRENT_POSITION
:
820 size
= sizeof(SUB_Q_CURRENT_POSITION
);
821 if (hdr
->AudioStatus
==AUDIO_STATUS_IN_PROGRESS
) {
822 data
->CurrentPosition
.FormatCode
= IOCTL_CDROM_CURRENT_POSITION
;
823 data
->CurrentPosition
.Control
= sc
.cdsc_ctrl
;
824 data
->CurrentPosition
.ADR
= sc
.cdsc_adr
;
825 data
->CurrentPosition
.TrackNumber
= sc
.cdsc_trk
;
826 data
->CurrentPosition
.IndexNumber
= sc
.cdsc_ind
;
828 data
->CurrentPosition
.AbsoluteAddress
[0] = 0;
829 data
->CurrentPosition
.AbsoluteAddress
[1] = sc
.cdsc_absaddr
.msf
.minute
;
830 data
->CurrentPosition
.AbsoluteAddress
[2] = sc
.cdsc_absaddr
.msf
.second
;
831 data
->CurrentPosition
.AbsoluteAddress
[3] = sc
.cdsc_absaddr
.msf
.frame
;
833 data
->CurrentPosition
.TrackRelativeAddress
[0] = 0;
834 data
->CurrentPosition
.TrackRelativeAddress
[1] = sc
.cdsc_reladdr
.msf
.minute
;
835 data
->CurrentPosition
.TrackRelativeAddress
[2] = sc
.cdsc_reladdr
.msf
.second
;
836 data
->CurrentPosition
.TrackRelativeAddress
[3] = sc
.cdsc_reladdr
.msf
.frame
;
838 cdrom_cache
[dev
].CurrentPosition
= data
->CurrentPosition
;
840 else /* not playing */
842 cdrom_cache
[dev
].CurrentPosition
.Header
= *hdr
; /* Preserve header info */
843 data
->CurrentPosition
= cdrom_cache
[dev
].CurrentPosition
;
846 case IOCTL_CDROM_MEDIA_CATALOG
:
847 size
= sizeof(SUB_Q_MEDIA_CATALOG_NUMBER
);
848 data
->MediaCatalog
.FormatCode
= IOCTL_CDROM_MEDIA_CATALOG
;
850 struct cdrom_mcn mcn
;
851 if ((io
= ioctl(cdrom_cache
[dev
].fd
, CDROM_GET_MCN
, &mcn
)) == -1) goto end
;
853 data
->MediaCatalog
.FormatCode
= IOCTL_CDROM_MEDIA_CATALOG
;
854 data
->MediaCatalog
.Mcval
= 0; /* FIXME */
855 memcpy(data
->MediaCatalog
.MediaCatalog
, mcn
.medium_catalog_number
, 14);
856 data
->MediaCatalog
.MediaCatalog
[14] = 0;
859 case IOCTL_CDROM_TRACK_ISRC
:
860 size
= sizeof(SUB_Q_CURRENT_POSITION
);
861 FIXME("TrackIsrc: NIY on linux\n");
862 data
->TrackIsrc
.FormatCode
= IOCTL_CDROM_TRACK_ISRC
;
863 data
->TrackIsrc
.Tcval
= 0;
869 ret
= CDROM_GetStatusCode(io
);
870 #elif defined(__FreeBSD__) || defined(__NetBSD__)
872 SUB_Q_HEADER
* hdr
= (SUB_Q_HEADER
*)data
;
874 struct ioc_read_subchannel read_sc
;
875 struct cd_sub_channel_info sc
;
877 read_sc
.address_format
= CD_MSF_FORMAT
;
879 read_sc
.data_len
= sizeof(sc
);
883 case IOCTL_CDROM_CURRENT_POSITION
:
884 read_sc
.data_format
= CD_CURRENT_POSITION
;
886 case IOCTL_CDROM_MEDIA_CATALOG
:
887 read_sc
.data_format
= CD_MEDIA_CATALOG
;
889 case IOCTL_CDROM_TRACK_ISRC
:
890 read_sc
.data_format
= CD_TRACK_INFO
;
891 sc
.what
.track_info
.track_number
= data
->TrackIsrc
.Track
;
894 io
= ioctl(cdrom_cache
[dev
].fd
, CDIOCREADSUBCHANNEL
, &read_sc
);
897 TRACE("opened or no_media (%s)!\n", strerror(errno
));
898 CDROM_ClearCacheEntry(dev
);
899 hdr
->AudioStatus
= AUDIO_STATUS_NO_STATUS
;
903 hdr
->AudioStatus
= AUDIO_STATUS_NOT_SUPPORTED
;
905 switch (sc
.header
.audio_status
) {
906 case CD_AS_AUDIO_INVALID
:
907 CDROM_ClearCacheEntry(dev
);
908 hdr
->AudioStatus
= AUDIO_STATUS_NOT_SUPPORTED
;
910 case CD_AS_NO_STATUS
:
911 CDROM_ClearCacheEntry(dev
);
912 hdr
->AudioStatus
= AUDIO_STATUS_NO_STATUS
;
914 case CD_AS_PLAY_IN_PROGRESS
:
915 hdr
->AudioStatus
= AUDIO_STATUS_IN_PROGRESS
;
917 case CD_AS_PLAY_PAUSED
:
918 hdr
->AudioStatus
= AUDIO_STATUS_PAUSED
;
920 case CD_AS_PLAY_COMPLETED
:
921 hdr
->AudioStatus
= AUDIO_STATUS_PLAY_COMPLETE
;
923 case CD_AS_PLAY_ERROR
:
924 hdr
->AudioStatus
= AUDIO_STATUS_PLAY_ERROR
;
927 TRACE("status=%02X !\n", sc
.header
.audio_status
);
931 case IOCTL_CDROM_CURRENT_POSITION
:
932 size
= sizeof(SUB_Q_CURRENT_POSITION
);
933 if (hdr
->AudioStatus
==AUDIO_STATUS_IN_PROGRESS
) {
934 data
->CurrentPosition
.FormatCode
= IOCTL_CDROM_CURRENT_POSITION
;
935 data
->CurrentPosition
.Control
= sc
.what
.position
.control
;
936 data
->CurrentPosition
.ADR
= sc
.what
.position
.addr_type
;
937 data
->CurrentPosition
.TrackNumber
= sc
.what
.position
.track_number
;
938 data
->CurrentPosition
.IndexNumber
= sc
.what
.position
.index_number
;
940 data
->CurrentPosition
.AbsoluteAddress
[0] = 0;
941 data
->CurrentPosition
.AbsoluteAddress
[1] = sc
.what
.position
.absaddr
.msf
.minute
;
942 data
->CurrentPosition
.AbsoluteAddress
[2] = sc
.what
.position
.absaddr
.msf
.second
;
943 data
->CurrentPosition
.AbsoluteAddress
[3] = sc
.what
.position
.absaddr
.msf
.frame
;
944 data
->CurrentPosition
.TrackRelativeAddress
[0] = 0;
945 data
->CurrentPosition
.TrackRelativeAddress
[1] = sc
.what
.position
.reladdr
.msf
.minute
;
946 data
->CurrentPosition
.TrackRelativeAddress
[2] = sc
.what
.position
.reladdr
.msf
.second
;
947 data
->CurrentPosition
.TrackRelativeAddress
[3] = sc
.what
.position
.reladdr
.msf
.frame
;
948 cdrom_cache
[dev
].CurrentPosition
= data
->CurrentPosition
;
950 else { /* not playing */
951 cdrom_cache
[dev
].CurrentPosition
.Header
= *hdr
; /* Preserve header info */
952 data
->CurrentPosition
= cdrom_cache
[dev
].CurrentPosition
;
955 case IOCTL_CDROM_MEDIA_CATALOG
:
956 size
= sizeof(SUB_Q_MEDIA_CATALOG_NUMBER
);
957 data
->MediaCatalog
.FormatCode
= IOCTL_CDROM_MEDIA_CATALOG
;
958 data
->MediaCatalog
.Mcval
= sc
.what
.media_catalog
.mc_valid
;
959 memcpy(data
->MediaCatalog
.MediaCatalog
, sc
.what
.media_catalog
.mc_number
, 15);
961 case IOCTL_CDROM_TRACK_ISRC
:
962 size
= sizeof(SUB_Q_CURRENT_POSITION
);
963 data
->TrackIsrc
.FormatCode
= IOCTL_CDROM_TRACK_ISRC
;
964 data
->TrackIsrc
.Tcval
= sc
.what
.track_info
.ti_valid
;
965 memcpy(data
->TrackIsrc
.TrackIsrc
, sc
.what
.track_info
.ti_number
, 15);
970 ret
= CDROM_GetStatusCode(io
);
975 /******************************************************************
980 static NTSTATUS
CDROM_Verify(int dev
)
982 /* quick implementation */
983 CDROM_SUB_Q_DATA_FORMAT fmt
;
984 SUB_Q_CHANNEL_DATA data
;
986 fmt
.Format
= IOCTL_CDROM_CURRENT_POSITION
;
987 return CDROM_ReadQChannel(dev
, &fmt
, &data
) ? 1 : 0;
990 /******************************************************************
995 static NTSTATUS
CDROM_PlayAudioMSF(int dev
, const CDROM_PLAY_AUDIO_MSF
* audio_msf
)
997 NTSTATUS ret
= STATUS_NOT_SUPPORTED
;
999 struct cdrom_msf msf
;
1002 msf
.cdmsf_min0
= audio_msf
->StartingM
;
1003 msf
.cdmsf_sec0
= audio_msf
->StartingS
;
1004 msf
.cdmsf_frame0
= audio_msf
->StartingF
;
1005 msf
.cdmsf_min1
= audio_msf
->EndingM
;
1006 msf
.cdmsf_sec1
= audio_msf
->EndingS
;
1007 msf
.cdmsf_frame1
= audio_msf
->EndingF
;
1009 io
= ioctl(cdrom_cache
[dev
].fd
, CDROMSTART
);
1012 WARN("motor doesn't start !\n");
1015 io
= ioctl(cdrom_cache
[dev
].fd
, CDROMPLAYMSF
, &msf
);
1018 WARN("device doesn't play !\n");
1021 TRACE("msf = %d:%d:%d %d:%d:%d\n",
1022 msf
.cdmsf_min0
, msf
.cdmsf_sec0
, msf
.cdmsf_frame0
,
1023 msf
.cdmsf_min1
, msf
.cdmsf_sec1
, msf
.cdmsf_frame1
);
1025 ret
= CDROM_GetStatusCode(io
);
1026 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1027 struct ioc_play_msf msf
;
1030 msf
.start_m
= audio_msf
->StartingM
;
1031 msf
.start_s
= audio_msf
->StartingS
;
1032 msf
.start_f
= audio_msf
->StartingF
;
1033 msf
.end_m
= audio_msf
->EndingM
;
1034 msf
.end_s
= audio_msf
->EndingS
;
1035 msf
.end_f
= audio_msf
->EndingF
;
1037 io
= ioctl(cdrom_cache
[dev
].fd
, CDIOCSTART
, NULL
);
1040 WARN("motor doesn't start !\n");
1043 io
= ioctl(cdrom_cache
[dev
].fd
, CDIOCPLAYMSF
, &msf
);
1046 WARN("device doesn't play !\n");
1049 TRACE("msf = %d:%d:%d %d:%d:%d\n",
1050 msf
.start_m
, msf
.start_s
, msf
.start_f
,
1051 msf
.end_m
, msf
.end_s
, msf
.end_f
);
1053 ret
= CDROM_GetStatusCode(io
);
1058 /******************************************************************
1059 * CDROM_SeekAudioMSF
1063 static NTSTATUS
CDROM_SeekAudioMSF(int dev
, const CDROM_SEEK_AUDIO_MSF
* audio_msf
)
1067 SUB_Q_CURRENT_POSITION
*cp
;
1069 struct cdrom_msf0 msf
;
1070 struct cdrom_subchnl sc
;
1071 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1072 struct ioc_play_msf msf
;
1073 struct ioc_read_subchannel read_sc
;
1074 struct cd_sub_channel_info sc
;
1078 /* Use the information on the TOC to compute the new current
1079 * position, which is shadowed on the cache. [Portable]. */
1080 frame
= FRAME_OF_MSF(*audio_msf
);
1081 cp
= &cdrom_cache
[dev
].CurrentPosition
;
1082 if ((io
= CDROM_ReadTOC(dev
, &toc
)) != 0) return io
;
1084 for(i
=toc
.FirstTrack
;i
<=toc
.LastTrack
+1;i
++)
1085 if (FRAME_OF_TOC(toc
,i
)>frame
) break;
1086 if (i
<= toc
.FirstTrack
|| i
> toc
.LastTrack
+1)
1087 return STATUS_INVALID_PARAMETER
;
1089 cp
->FormatCode
= IOCTL_CDROM_CURRENT_POSITION
;
1090 cp
->Control
= toc
.TrackData
[i
-toc
.FirstTrack
].Control
;
1091 cp
->ADR
= toc
.TrackData
[i
-toc
.FirstTrack
].Adr
;
1092 cp
->TrackNumber
= toc
.TrackData
[i
-toc
.FirstTrack
].TrackNumber
;
1093 cp
->IndexNumber
= 0; /* FIXME: where do they keep these? */
1094 cp
->AbsoluteAddress
[0] = 0;
1095 cp
->AbsoluteAddress
[1] = toc
.TrackData
[i
-toc
.FirstTrack
].Address
[1];
1096 cp
->AbsoluteAddress
[2] = toc
.TrackData
[i
-toc
.FirstTrack
].Address
[2];
1097 cp
->AbsoluteAddress
[3] = toc
.TrackData
[i
-toc
.FirstTrack
].Address
[3];
1098 frame
-= FRAME_OF_TOC(toc
,i
);
1099 cp
->TrackRelativeAddress
[0] = 0;
1100 MSF_OF_FRAME(cp
->TrackRelativeAddress
[1], frame
);
1102 /* If playing, then issue a seek command, otherwise do nothing */
1104 sc
.cdsc_format
= CDROM_MSF
;
1106 io
= ioctl(cdrom_cache
[dev
].fd
, CDROMSUBCHNL
, &sc
);
1109 TRACE("opened or no_media (%s)!\n", strerror(errno
));
1110 CDROM_ClearCacheEntry(dev
);
1111 return CDROM_GetStatusCode(io
);
1113 if (sc
.cdsc_audiostatus
==CDROM_AUDIO_PLAY
)
1115 msf
.minute
= audio_msf
->M
;
1116 msf
.second
= audio_msf
->S
;
1117 msf
.frame
= audio_msf
->F
;
1118 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDROMSEEK
, &msf
));
1120 return STATUS_SUCCESS
;
1121 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1122 read_sc
.address_format
= CD_MSF_FORMAT
;
1124 read_sc
.data_len
= sizeof(sc
);
1126 read_sc
.data_format
= CD_CURRENT_POSITION
;
1128 io
= ioctl(cdrom_cache
[dev
].fd
, CDIOCREADSUBCHANNEL
, &read_sc
);
1131 TRACE("opened or no_media (%s)!\n", strerror(errno
));
1132 CDROM_ClearCacheEntry(dev
);
1133 return CDROM_GetStatusCode(io
);
1135 if (sc
.header
.audio_status
==CD_AS_PLAY_IN_PROGRESS
)
1138 msf
.start_m
= audio_msf
->M
;
1139 msf
.start_s
= audio_msf
->S
;
1140 msf
.start_f
= audio_msf
->F
;
1141 final_frame
= FRAME_OF_TOC(toc
,toc
.LastTrack
+1)-1;
1142 MSF_OF_FRAME(msf
.end_m
, final_frame
);
1144 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDIOCPLAYMSF
, &msf
));
1146 return STATUS_SUCCESS
;
1148 return STATUS_NOT_SUPPORTED
;
1152 /******************************************************************
1157 static NTSTATUS
CDROM_PauseAudio(int dev
)
1160 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDROMPAUSE
));
1161 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1162 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDIOCPAUSE
, NULL
));
1164 return STATUS_NOT_SUPPORTED
;
1168 /******************************************************************
1173 static NTSTATUS
CDROM_ResumeAudio(int dev
)
1176 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDROMRESUME
));
1177 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1178 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDIOCRESUME
, NULL
));
1180 return STATUS_NOT_SUPPORTED
;
1184 /******************************************************************
1189 static NTSTATUS
CDROM_StopAudio(int dev
)
1192 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDROMSTOP
));
1193 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1194 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDIOCSTOP
, NULL
));
1196 return STATUS_NOT_SUPPORTED
;
1200 /******************************************************************
1205 static NTSTATUS
CDROM_GetVolume(int dev
, VOLUME_CONTROL
* vc
)
1208 struct cdrom_volctrl volc
;
1211 io
= ioctl(cdrom_cache
[dev
].fd
, CDROMVOLREAD
, &volc
);
1214 vc
->PortVolume
[0] = volc
.channel0
;
1215 vc
->PortVolume
[1] = volc
.channel1
;
1216 vc
->PortVolume
[2] = volc
.channel2
;
1217 vc
->PortVolume
[3] = volc
.channel3
;
1219 return CDROM_GetStatusCode(io
);
1220 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1221 struct ioc_vol volc
;
1224 io
= ioctl(cdrom_cache
[dev
].fd
, CDIOCGETVOL
, &volc
);
1227 vc
->PortVolume
[0] = volc
.vol
[0];
1228 vc
->PortVolume
[1] = volc
.vol
[1];
1229 vc
->PortVolume
[2] = volc
.vol
[2];
1230 vc
->PortVolume
[3] = volc
.vol
[3];
1232 return CDROM_GetStatusCode(io
);
1234 return STATUS_NOT_SUPPORTED
;
1238 /******************************************************************
1243 static NTSTATUS
CDROM_SetVolume(int dev
, const VOLUME_CONTROL
* vc
)
1246 struct cdrom_volctrl volc
;
1248 volc
.channel0
= vc
->PortVolume
[0];
1249 volc
.channel1
= vc
->PortVolume
[1];
1250 volc
.channel2
= vc
->PortVolume
[2];
1251 volc
.channel3
= vc
->PortVolume
[3];
1253 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDROMVOLCTRL
, &volc
));
1254 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1255 struct ioc_vol volc
;
1257 volc
.vol
[0] = vc
->PortVolume
[0];
1258 volc
.vol
[1] = vc
->PortVolume
[1];
1259 volc
.vol
[2] = vc
->PortVolume
[2];
1260 volc
.vol
[3] = vc
->PortVolume
[3];
1262 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDIOCSETVOL
, &volc
));
1264 return STATUS_NOT_SUPPORTED
;
1268 /******************************************************************
1273 static NTSTATUS
CDROM_RawRead(int dev
, const RAW_READ_INFO
* raw
, void* buffer
, DWORD len
, DWORD
* sz
)
1275 int ret
= STATUS_NOT_SUPPORTED
;
1279 switch (raw
->TrackMode
)
1281 case YellowMode2
: sectSize
= 2336; break;
1282 case XAForm2
: sectSize
= 2328; break;
1283 case CDDA
: sectSize
= 2352; break;
1284 default: return STATUS_INVALID_PARAMETER
;
1286 if (len
< raw
->SectorCount
* sectSize
) return STATUS_BUFFER_TOO_SMALL
;
1287 /* strangely enough, it seems that sector offsets are always indicated with a size of 2048,
1288 * even if a larger size if read...
1292 struct cdrom_read cdr
;
1293 struct cdrom_read_audio cdra
;
1295 switch (raw
->TrackMode
)
1298 if (raw
->DiskOffset
.s
.HighPart
) FIXME("Unsupported value\n");
1299 cdr
.cdread_lba
= raw
->DiskOffset
.s
.LowPart
; /* FIXME ? */
1300 cdr
.cdread_bufaddr
= buffer
;
1301 cdr
.cdread_buflen
= raw
->SectorCount
* sectSize
;
1302 io
= ioctl(cdrom_cache
[dev
].fd
, CDROMREADMODE2
, &cdr
);
1305 FIXME("XAForm2: NIY\n");
1308 /* FIXME: the output doesn't seem 100% correct... in fact output is shifted
1309 * between by NT2K box and this... should check on the same drive...
1310 * otherwise, I fear a 2352/2368 mismatch somewhere in one of the drivers
1312 * Anyway, that's not critical at all. We're talking of 16/32 bytes, we're
1313 * talking of 0.2 ms of sound
1315 /* 2048 = 2 ** 11 */
1316 if (raw
->DiskOffset
.s
.HighPart
& ~2047) FIXME("Unsupported value\n");
1317 cdra
.addr
.lba
= ((raw
->DiskOffset
.s
.LowPart
>> 11) |
1318 (raw
->DiskOffset
.s
.HighPart
<< (32 - 11))) - 1;
1319 FIXME("reading at %u\n", cdra
.addr
.lba
);
1320 cdra
.addr_format
= CDROM_LBA
;
1321 cdra
.nframes
= raw
->SectorCount
;
1323 io
= ioctl(cdrom_cache
[dev
].fd
, CDROMREADAUDIO
, &cdra
);
1326 FIXME("NIY: %d\n", raw
->TrackMode
);
1330 #elif defined(__FreeBSD__)
1332 struct ioc_read_audio ira
;
1334 switch (raw
->TrackMode
)
1337 FIXME("YellowMode2: NIY\n");
1340 FIXME("XAForm2: NIY\n");
1343 /* 2048 = 2 ** 11 */
1344 if (raw
->DiskOffset
.s
.HighPart
& ~2047) FIXME("Unsupported value\n");
1345 ira
.address
.lba
= ((raw
->DiskOffset
.s
.LowPart
>> 11) |
1346 raw
->DiskOffset
.s
.HighPart
<< (32 - 11)) - 1;
1347 ira
.address_format
= CD_LBA_FORMAT
;
1348 ira
.nframes
= raw
->SectorCount
;
1349 ira
.buffer
= buffer
;
1350 io
= ioctl(cdrom_cache
[dev
].fd
, CDIOCREADAUDIO
, &ira
);
1354 #elif defined(__NetBSD__)
1356 switch (raw
->TrackMode
)
1359 FIXME("YellowMode2: NIY\n");
1362 FIXME("XAForm2: NIY\n");
1365 FIXME("CDDA: NIY\n");
1370 *sz
= sectSize
* raw
->SectorCount
;
1371 ret
= CDROM_GetStatusCode(io
);
1375 /******************************************************************
1376 * CDROM_ScsiPassThroughDirect
1380 static NTSTATUS
CDROM_ScsiPassThroughDirect(int dev
, PSCSI_PASS_THROUGH_DIRECT pPacket
)
1382 int ret
= STATUS_NOT_SUPPORTED
;
1383 #if defined(linux) && defined(CDROM_SEND_PACKET)
1384 struct linux_cdrom_generic_command cmd
;
1385 struct request_sense sense
;
1388 if (pPacket
->Length
< sizeof(SCSI_PASS_THROUGH_DIRECT
))
1389 return STATUS_BUFFER_TOO_SMALL
;
1391 if (pPacket
->CdbLength
> 12)
1392 return STATUS_INVALID_PARAMETER
;
1394 if (pPacket
->SenseInfoLength
> sizeof(sense
))
1395 return STATUS_INVALID_PARAMETER
;
1397 memset(&cmd
, 0, sizeof(cmd
));
1398 memset(&sense
, 0, sizeof(sense
));
1400 memcpy(&(cmd
.cmd
), &(pPacket
->Cdb
), pPacket
->CdbLength
);
1402 cmd
.buffer
= pPacket
->DataBuffer
;
1403 cmd
.buflen
= pPacket
->DataTransferLength
;
1406 cmd
.timeout
= pPacket
->TimeOutValue
*HZ
;
1408 switch (pPacket
->DataIn
)
1410 case SCSI_IOCTL_DATA_OUT
:
1411 cmd
.data_direction
= CGC_DATA_WRITE
;
1413 case SCSI_IOCTL_DATA_IN
:
1414 cmd
.data_direction
= CGC_DATA_READ
;
1416 case SCSI_IOCTL_DATA_UNSPECIFIED
:
1417 cmd
.data_direction
= CGC_DATA_NONE
;
1420 return STATUS_INVALID_PARAMETER
;
1423 io
= ioctl(cdrom_cache
[dev
].fd
, CDROM_SEND_PACKET
, &cmd
);
1425 if (pPacket
->SenseInfoLength
!= 0)
1427 memcpy((char*)pPacket
+ pPacket
->SenseInfoOffset
,
1428 &sense
, pPacket
->SenseInfoLength
);
1431 pPacket
->ScsiStatus
= cmd
.stat
;
1433 ret
= CDROM_GetStatusCode(io
);
1435 #elif defined(__NetBSD__)
1439 if (pPacket
->Length
< sizeof(SCSI_PASS_THROUGH_DIRECT
))
1440 return STATUS_BUFFER_TOO_SMALL
;
1442 if (pPacket
->CdbLength
> 12)
1443 return STATUS_INVALID_PARAMETER
;
1445 if (pPacket
->SenseInfoLength
> SENSEBUFLEN
)
1446 return STATUS_INVALID_PARAMETER
;
1448 memset(&cmd
, 0, sizeof(cmd
));
1449 memcpy(&(cmd
.cmd
), &(pPacket
->Cdb
), pPacket
->CdbLength
);
1451 cmd
.cmdlen
= pPacket
->CdbLength
;
1452 cmd
.databuf
= pPacket
->DataBuffer
;
1453 cmd
.datalen
= pPacket
->DataTransferLength
;
1454 cmd
.senselen
= pPacket
->SenseInfoLength
;
1455 cmd
.timeout
= pPacket
->TimeOutValue
*1000; /* in milliseconds */
1457 switch (pPacket
->DataIn
)
1459 case SCSI_IOCTL_DATA_OUT
:
1460 cmd
.flags
|= SCCMD_WRITE
;
1462 case SCSI_IOCTL_DATA_IN
:
1463 cmd
.flags
|= SCCMD_READ
;
1465 case SCSI_IOCTL_DATA_UNSPECIFIED
:
1469 return STATUS_INVALID_PARAMETER
;
1472 io
= ioctl(cdrom_cache
[dev
].fd
, SCIOCCOMMAND
, &cmd
);
1476 case SCCMD_OK
: break;
1477 case SCCMD_TIMEOUT
: return STATUS_TIMEOUT
;
1479 case SCCMD_BUSY
: return STATUS_DEVICE_BUSY
;
1481 case SCCMD_SENSE
: break;
1482 case SCCMD_UNKNOWN
: return STATUS_UNSUCCESSFUL
;
1486 if (pPacket
->SenseInfoLength
!= 0)
1488 memcpy((char*)pPacket
+ pPacket
->SenseInfoOffset
,
1489 cmd
.sense
, pPacket
->SenseInfoLength
);
1492 pPacket
->ScsiStatus
= cmd
.status
;
1494 ret
= CDROM_GetStatusCode(io
);
1499 /******************************************************************
1500 * CDROM_ScsiPassThrough
1504 static NTSTATUS
CDROM_ScsiPassThrough(int dev
, PSCSI_PASS_THROUGH pPacket
)
1506 int ret
= STATUS_NOT_SUPPORTED
;
1507 #if defined(linux) && defined(CDROM_SEND_PACKET)
1508 struct linux_cdrom_generic_command cmd
;
1509 struct request_sense sense
;
1512 if (pPacket
->Length
< sizeof(SCSI_PASS_THROUGH
))
1513 return STATUS_BUFFER_TOO_SMALL
;
1515 if (pPacket
->CdbLength
> 12)
1516 return STATUS_INVALID_PARAMETER
;
1518 if (pPacket
->SenseInfoLength
> sizeof(sense
))
1519 return STATUS_INVALID_PARAMETER
;
1521 memset(&cmd
, 0, sizeof(cmd
));
1522 memset(&sense
, 0, sizeof(sense
));
1524 memcpy(&(cmd
.cmd
), &(pPacket
->Cdb
), pPacket
->CdbLength
);
1526 if ( pPacket
->DataBufferOffset
> 0x1000 )
1528 cmd
.buffer
= (void*)pPacket
->DataBufferOffset
;
1532 cmd
.buffer
= (char*)pPacket
+ pPacket
->DataBufferOffset
;
1534 cmd
.buflen
= pPacket
->DataTransferLength
;
1537 cmd
.timeout
= pPacket
->TimeOutValue
*HZ
;
1539 switch (pPacket
->DataIn
)
1541 case SCSI_IOCTL_DATA_OUT
:
1542 cmd
.data_direction
= CGC_DATA_WRITE
;
1544 case SCSI_IOCTL_DATA_IN
:
1545 cmd
.data_direction
= CGC_DATA_READ
;
1547 case SCSI_IOCTL_DATA_UNSPECIFIED
:
1548 cmd
.data_direction
= CGC_DATA_NONE
;
1551 return STATUS_INVALID_PARAMETER
;
1554 io
= ioctl(cdrom_cache
[dev
].fd
, CDROM_SEND_PACKET
, &cmd
);
1556 if (pPacket
->SenseInfoLength
!= 0)
1558 memcpy((char*)pPacket
+ pPacket
->SenseInfoOffset
,
1559 &sense
, pPacket
->SenseInfoLength
);
1562 pPacket
->ScsiStatus
= cmd
.stat
;
1564 ret
= CDROM_GetStatusCode(io
);
1566 #elif defined(__NetBSD__)
1570 if (pPacket
->Length
< sizeof(SCSI_PASS_THROUGH
))
1571 return STATUS_BUFFER_TOO_SMALL
;
1573 if (pPacket
->CdbLength
> 12)
1574 return STATUS_INVALID_PARAMETER
;
1576 if (pPacket
->SenseInfoLength
> SENSEBUFLEN
)
1577 return STATUS_INVALID_PARAMETER
;
1579 memset(&cmd
, 0, sizeof(cmd
));
1580 memcpy(&(cmd
.cmd
), &(pPacket
->Cdb
), pPacket
->CdbLength
);
1582 if ( pPacket
->DataBufferOffset
> 0x1000 )
1584 cmd
.databuf
= (void*)pPacket
->DataBufferOffset
;
1588 cmd
.databuf
= (char*)pPacket
+ pPacket
->DataBufferOffset
;
1591 cmd
.cmdlen
= pPacket
->CdbLength
;
1592 cmd
.datalen
= pPacket
->DataTransferLength
;
1593 cmd
.senselen
= pPacket
->SenseInfoLength
;
1594 cmd
.timeout
= pPacket
->TimeOutValue
*1000; /* in milliseconds */
1596 switch (pPacket
->DataIn
)
1598 case SCSI_IOCTL_DATA_OUT
:
1599 cmd
.flags
|= SCCMD_WRITE
;
1601 case SCSI_IOCTL_DATA_IN
:
1602 cmd
.flags
|= SCCMD_READ
;
1604 case SCSI_IOCTL_DATA_UNSPECIFIED
:
1608 return STATUS_INVALID_PARAMETER
;
1611 io
= ioctl(cdrom_cache
[dev
].fd
, SCIOCCOMMAND
, &cmd
);
1615 case SCCMD_OK
: break;
1616 case SCCMD_TIMEOUT
: return STATUS_TIMEOUT
;
1618 case SCCMD_BUSY
: return STATUS_DEVICE_BUSY
;
1620 case SCCMD_SENSE
: break;
1621 case SCCMD_UNKNOWN
: return STATUS_UNSUCCESSFUL
;
1625 if (pPacket
->SenseInfoLength
!= 0)
1627 memcpy((char*)pPacket
+ pPacket
->SenseInfoOffset
,
1628 cmd
.sense
, pPacket
->SenseInfoLength
);
1631 pPacket
->ScsiStatus
= cmd
.status
;
1633 ret
= CDROM_GetStatusCode(io
);
1638 /******************************************************************
1643 static NTSTATUS
CDROM_ScsiGetCaps(int dev
, PIO_SCSI_CAPABILITIES caps
)
1645 NTSTATUS ret
= STATUS_NOT_IMPLEMENTED
;
1647 caps
->Length
= sizeof(*caps
);
1649 caps
->MaximumTransferLength
= SG_SCATTER_SZ
; /* FIXME */
1650 caps
->MaximumPhysicalPages
= SG_SCATTER_SZ
/ getpagesize();
1651 caps
->SupportedAsynchronousEvents
= TRUE
;
1652 caps
->AlignmentMask
= getpagesize();
1653 caps
->TaggedQueuing
= FALSE
; /* we could check that it works and answer TRUE */
1654 caps
->AdapterScansDown
= FALSE
; /* FIXME ? */
1655 caps
->AdapterUsesPio
= FALSE
; /* FIXME ? */
1656 ret
= STATUS_SUCCESS
;
1658 FIXME("Unimplemented\n");
1663 /******************************************************************
1666 * implements IOCTL_SCSI_GET_ADDRESS
1668 static NTSTATUS
CDROM_GetAddress(int dev
, SCSI_ADDRESS
* address
)
1670 int portnum
, busid
, targetid
, lun
;
1672 address
->Length
= sizeof(SCSI_ADDRESS
);
1673 if ( ! CDROM_GetInterfaceInfo(cdrom_cache
[dev
].fd
, &portnum
,
1674 &busid
, &targetid
, &lun
))
1675 return STATUS_NOT_SUPPORTED
;
1677 address
->PortNumber
= portnum
;
1678 address
->PathId
= busid
; /* bus number */
1679 address
->TargetId
= targetid
;
1681 return STATUS_SUCCESS
;
1684 /******************************************************************
1685 * CDROM_DeviceIoControl
1689 NTSTATUS
CDROM_DeviceIoControl(DWORD clientID
, HANDLE hDevice
,
1690 HANDLE hEvent
, PIO_APC_ROUTINE UserApcRoutine
,
1691 PVOID UserApcContext
,
1692 PIO_STATUS_BLOCK piosb
,
1693 ULONG dwIoControlCode
,
1694 LPVOID lpInBuffer
, DWORD nInBufferSize
,
1695 LPVOID lpOutBuffer
, DWORD nOutBufferSize
)
1698 NTSTATUS status
= STATUS_SUCCESS
;
1701 TRACE("%lx[%c] %s %lx %ld %lx %ld %p\n",
1702 (DWORD
)hDevice
, 'A' + LOWORD(clientID
), iocodex(dwIoControlCode
), (DWORD
)lpInBuffer
, nInBufferSize
,
1703 (DWORD
)lpOutBuffer
, nOutBufferSize
, piosb
);
1705 piosb
->Information
= 0;
1707 if ((status
= CDROM_Open(hDevice
, clientID
, &dev
))) goto error
;
1709 switch (dwIoControlCode
)
1711 case IOCTL_STORAGE_CHECK_VERIFY
:
1712 case IOCTL_CDROM_CHECK_VERIFY
:
1714 CDROM_ClearCacheEntry(dev
);
1715 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0 || lpOutBuffer
!= NULL
|| nOutBufferSize
!= 0)
1716 status
= STATUS_INVALID_PARAMETER
;
1717 else status
= CDROM_Verify(dev
);
1720 /* EPP case IOCTL_STORAGE_CHECK_VERIFY2: */
1722 /* EPP case IOCTL_STORAGE_FIND_NEW_DEVICES: */
1723 /* EPP case IOCTL_CDROM_FIND_NEW_DEVICES: */
1725 case IOCTL_STORAGE_LOAD_MEDIA
:
1726 case IOCTL_CDROM_LOAD_MEDIA
:
1728 CDROM_ClearCacheEntry(dev
);
1729 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0 || lpOutBuffer
!= NULL
|| nOutBufferSize
!= 0)
1730 status
= STATUS_INVALID_PARAMETER
;
1731 else status
= CDROM_SetTray(dev
, FALSE
);
1733 case IOCTL_STORAGE_EJECT_MEDIA
:
1735 CDROM_ClearCacheEntry(dev
);
1736 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0 || lpOutBuffer
!= NULL
|| nOutBufferSize
!= 0)
1737 status
= STATUS_INVALID_PARAMETER
;
1738 else status
= CDROM_SetTray(dev
, TRUE
);
1741 case IOCTL_CDROM_MEDIA_REMOVAL
:
1742 case IOCTL_DISK_MEDIA_REMOVAL
:
1743 case IOCTL_STORAGE_MEDIA_REMOVAL
:
1744 case IOCTL_STORAGE_EJECTION_CONTROL
:
1745 /* FIXME the last ioctl:s is not the same as the two others...
1746 * lockcount/owner should be handled */
1748 CDROM_ClearCacheEntry(dev
);
1749 if (lpOutBuffer
!= NULL
|| nOutBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
1750 else if (nInBufferSize
< sizeof(PREVENT_MEDIA_REMOVAL
)) status
= STATUS_BUFFER_TOO_SMALL
;
1751 else status
= CDROM_ControlEjection(dev
, (const PREVENT_MEDIA_REMOVAL
*)lpInBuffer
);
1754 /* EPP case IOCTL_STORAGE_GET_MEDIA_TYPES: */
1756 case IOCTL_STORAGE_GET_DEVICE_NUMBER
:
1757 sz
= sizeof(STORAGE_DEVICE_NUMBER
);
1758 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
1759 else if (nOutBufferSize
< sz
) status
= STATUS_BUFFER_TOO_SMALL
;
1760 else status
= CDROM_GetDeviceNumber(dev
, (STORAGE_DEVICE_NUMBER
*)lpOutBuffer
);
1763 case IOCTL_STORAGE_RESET_DEVICE
:
1765 CDROM_ClearCacheEntry(dev
);
1766 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0 || lpOutBuffer
!= NULL
|| nOutBufferSize
!= 0)
1767 status
= STATUS_INVALID_PARAMETER
;
1768 else status
= CDROM_ResetAudio(dev
);
1771 case IOCTL_CDROM_GET_CONTROL
:
1772 sz
= sizeof(CDROM_AUDIO_CONTROL
);
1773 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
1774 else if (nOutBufferSize
< sz
) status
= STATUS_BUFFER_TOO_SMALL
;
1775 else status
= CDROM_GetControl(dev
, (CDROM_AUDIO_CONTROL
*)lpOutBuffer
);
1778 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
:
1779 sz
= sizeof(DISK_GEOMETRY
);
1780 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
1781 else if (nOutBufferSize
< sz
) status
= STATUS_BUFFER_TOO_SMALL
;
1782 else status
= CDROM_GetDriveGeometry(dev
, (DISK_GEOMETRY
*)lpOutBuffer
);
1785 case IOCTL_CDROM_DISK_TYPE
:
1786 sz
= sizeof(CDROM_DISK_DATA
);
1787 /* CDROM_ClearCacheEntry(dev); */
1788 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
1789 else if (nOutBufferSize
< sz
) status
= STATUS_BUFFER_TOO_SMALL
;
1790 else status
= CDROM_GetDiskData(dev
, (CDROM_DISK_DATA
*)lpOutBuffer
);
1793 /* EPP case IOCTL_CDROM_GET_LAST_SESSION: */
1795 case IOCTL_CDROM_READ_Q_CHANNEL
:
1796 sz
= sizeof(SUB_Q_CHANNEL_DATA
);
1797 if (lpInBuffer
== NULL
|| nInBufferSize
< sizeof(CDROM_SUB_Q_DATA_FORMAT
))
1798 status
= STATUS_INVALID_PARAMETER
;
1799 else if (nOutBufferSize
< sz
) status
= STATUS_BUFFER_TOO_SMALL
;
1800 else status
= CDROM_ReadQChannel(dev
, (const CDROM_SUB_Q_DATA_FORMAT
*)lpInBuffer
,
1801 (SUB_Q_CHANNEL_DATA
*)lpOutBuffer
);
1804 case IOCTL_CDROM_READ_TOC
:
1805 sz
= sizeof(CDROM_TOC
);
1806 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
1807 else if (nOutBufferSize
< sz
) status
= STATUS_BUFFER_TOO_SMALL
;
1808 else status
= CDROM_ReadTOC(dev
, (CDROM_TOC
*)lpOutBuffer
);
1811 /* EPP case IOCTL_CDROM_READ_TOC_EX: */
1813 case IOCTL_CDROM_PAUSE_AUDIO
:
1815 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0 || lpOutBuffer
!= NULL
|| nOutBufferSize
!= 0)
1816 status
= STATUS_INVALID_PARAMETER
;
1817 else status
= CDROM_PauseAudio(dev
);
1819 case IOCTL_CDROM_PLAY_AUDIO_MSF
:
1821 if (lpOutBuffer
!= NULL
|| nOutBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
1822 else if (nInBufferSize
< sizeof(CDROM_PLAY_AUDIO_MSF
)) status
= STATUS_BUFFER_TOO_SMALL
;
1823 else status
= CDROM_PlayAudioMSF(dev
, (const CDROM_PLAY_AUDIO_MSF
*)lpInBuffer
);
1825 case IOCTL_CDROM_RESUME_AUDIO
:
1827 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0 || lpOutBuffer
!= NULL
|| nOutBufferSize
!= 0)
1828 status
= STATUS_INVALID_PARAMETER
;
1829 else status
= CDROM_ResumeAudio(dev
);
1831 case IOCTL_CDROM_SEEK_AUDIO_MSF
:
1833 if (lpOutBuffer
!= NULL
|| nOutBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
1834 else if (nInBufferSize
< sizeof(CDROM_SEEK_AUDIO_MSF
)) status
= STATUS_BUFFER_TOO_SMALL
;
1835 else status
= CDROM_SeekAudioMSF(dev
, (const CDROM_SEEK_AUDIO_MSF
*)lpInBuffer
);
1837 case IOCTL_CDROM_STOP_AUDIO
:
1839 CDROM_ClearCacheEntry(dev
); /* Maybe intention is to change media */
1840 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0 || lpOutBuffer
!= NULL
|| nOutBufferSize
!= 0)
1841 status
= STATUS_INVALID_PARAMETER
;
1842 else status
= CDROM_StopAudio(dev
);
1844 case IOCTL_CDROM_GET_VOLUME
:
1845 sz
= sizeof(VOLUME_CONTROL
);
1846 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
1847 else if (nOutBufferSize
< sz
) status
= STATUS_BUFFER_TOO_SMALL
;
1848 else status
= CDROM_GetVolume(dev
, (VOLUME_CONTROL
*)lpOutBuffer
);
1850 case IOCTL_CDROM_SET_VOLUME
:
1852 CDROM_ClearCacheEntry(dev
);
1853 if (lpInBuffer
== NULL
|| nInBufferSize
< sizeof(VOLUME_CONTROL
) || lpOutBuffer
!= NULL
)
1854 status
= STATUS_INVALID_PARAMETER
;
1855 else status
= CDROM_SetVolume(dev
, (const VOLUME_CONTROL
*)lpInBuffer
);
1857 case IOCTL_CDROM_RAW_READ
:
1859 if (nInBufferSize
< sizeof(RAW_READ_INFO
)) status
= STATUS_INVALID_PARAMETER
;
1860 else if (lpOutBuffer
== NULL
) status
= STATUS_BUFFER_TOO_SMALL
;
1861 else status
= CDROM_RawRead(dev
, (const RAW_READ_INFO
*)lpInBuffer
,
1862 lpOutBuffer
, nOutBufferSize
, &sz
);
1864 case IOCTL_SCSI_GET_ADDRESS
:
1865 sz
= sizeof(SCSI_ADDRESS
);
1866 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
1867 else if (nOutBufferSize
< sz
) status
= STATUS_BUFFER_TOO_SMALL
;
1868 else status
= CDROM_GetAddress(dev
, (SCSI_ADDRESS
*)lpOutBuffer
);
1870 case IOCTL_SCSI_PASS_THROUGH_DIRECT
:
1871 sz
= sizeof(SCSI_PASS_THROUGH_DIRECT
);
1872 if (lpOutBuffer
== NULL
) status
= STATUS_INVALID_PARAMETER
;
1873 else if (nOutBufferSize
< sizeof(SCSI_PASS_THROUGH_DIRECT
)) status
= STATUS_BUFFER_TOO_SMALL
;
1874 else status
= CDROM_ScsiPassThroughDirect(dev
, (PSCSI_PASS_THROUGH_DIRECT
)lpOutBuffer
);
1876 case IOCTL_SCSI_PASS_THROUGH
:
1877 sz
= sizeof(SCSI_PASS_THROUGH
);
1878 if (lpOutBuffer
== NULL
) status
= STATUS_INVALID_PARAMETER
;
1879 else if (nOutBufferSize
< sizeof(SCSI_PASS_THROUGH
)) status
= STATUS_BUFFER_TOO_SMALL
;
1880 else status
= CDROM_ScsiPassThrough(dev
, (PSCSI_PASS_THROUGH
)lpOutBuffer
);
1882 case IOCTL_SCSI_GET_CAPABILITIES
:
1883 sz
= sizeof(IO_SCSI_CAPABILITIES
);
1884 if (lpOutBuffer
== NULL
) status
= STATUS_INVALID_PARAMETER
;
1885 else if (nOutBufferSize
< sizeof(IO_SCSI_CAPABILITIES
)) status
= STATUS_BUFFER_TOO_SMALL
;
1886 else status
= CDROM_ScsiGetCaps(dev
, (PIO_SCSI_CAPABILITIES
)lpOutBuffer
);
1889 FIXME("Unsupported IOCTL %lx (type=%lx access=%lx func=%lx meth=%lx)\n",
1890 dwIoControlCode
, dwIoControlCode
>> 16, (dwIoControlCode
>> 14) & 3,
1891 (dwIoControlCode
>> 2) & 0xFFF, dwIoControlCode
& 3);
1893 status
= STATUS_INVALID_PARAMETER
;
1897 piosb
->u
.Status
= status
;
1898 piosb
->Information
= sz
;
1899 if (hEvent
) NtSetEvent(hEvent
, NULL
);
1901 CDROM_Close(clientID
);