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_H
47 # include <scsi/scsi.h>
48 # undef REASSIGN_BLOCKS /* avoid conflict with winioctl.h */
50 #ifdef HAVE_SCSI_SCSI_IOCTL_H
51 # include <scsi/scsi_ioctl.h>
53 #ifdef HAVE_LINUX_MAJOR_H
54 # include <linux/major.h>
56 #ifdef HAVE_LINUX_HDREG_H
57 # include <linux/hdreg.h>
59 #ifdef HAVE_LINUX_PARAM_H
60 # include <linux/param.h>
62 #ifdef HAVE_LINUX_CDROM_H
63 # include <linux/cdrom.h>
65 #ifdef HAVE_LINUX_UCDROM_H
66 # include <linux/ucdrom.h>
68 #ifdef HAVE_SYS_CDIO_H
69 # include <sys/cdio.h>
71 #ifdef HAVE_SYS_SCSIIO_H
72 # include <sys/scsiio.h>
75 #define NONAMELESSUNION
76 #define NONAMELESSSTRUCT
86 #include "wine/debug.h"
88 /* Non-Linux systems do not have linux/cdrom.h and the like, and thus
89 lack the following constants. */
92 #define CD_SECS 60 /* seconds per minute */
95 #define CD_FRAMES 75 /* frames per second */
98 static const struct iocodexs
103 {IOCTL_CDROM_UNLOAD_DRIVER
, "IOCTL_CDROM_UNLOAD_DRIVER"},
104 {IOCTL_CDROM_READ_TOC
, "IOCTL_CDROM_READ_TOC"},
105 {IOCTL_CDROM_GET_CONTROL
, "IOCTL_CDROM_GET_CONTROL"},
106 {IOCTL_CDROM_PLAY_AUDIO_MSF
, "IOCTL_CDROM_PLAY_AUDIO_MSF"},
107 {IOCTL_CDROM_SEEK_AUDIO_MSF
, "IOCTL_CDROM_SEEK_AUDIO_MSF"},
108 {IOCTL_CDROM_STOP_AUDIO
, "IOCTL_CDROM_STOP_AUDIO"},
109 {IOCTL_CDROM_PAUSE_AUDIO
, "IOCTL_CDROM_PAUSE_AUDIO"},
110 {IOCTL_CDROM_RESUME_AUDIO
, "IOCTL_CDROM_RESUME_AUDIO"},
111 {IOCTL_CDROM_GET_VOLUME
, "IOCTL_CDROM_GET_VOLUME"},
112 {IOCTL_CDROM_SET_VOLUME
, "IOCTL_CDROM_SET_VOLUME"},
113 {IOCTL_CDROM_READ_Q_CHANNEL
, "IOCTL_CDROM_READ_Q_CHANNEL"},
114 {IOCTL_CDROM_GET_LAST_SESSION
, "IOCTL_CDROM_GET_LAST_SESSION"},
115 {IOCTL_CDROM_RAW_READ
, "IOCTL_CDROM_RAW_READ"},
116 {IOCTL_CDROM_DISK_TYPE
, "IOCTL_CDROM_DISK_TYPE"},
117 {IOCTL_CDROM_GET_DRIVE_GEOMETRY
, "IOCTL_CDROM_GET_DRIVE_GEOMETRY"},
118 {IOCTL_CDROM_CHECK_VERIFY
, "IOCTL_CDROM_CHECK_VERIFY"},
119 {IOCTL_CDROM_MEDIA_REMOVAL
, "IOCTL_CDROM_MEDIA_REMOVAL"},
120 {IOCTL_CDROM_EJECT_MEDIA
, "IOCTL_CDROM_EJECT_MEDIA"},
121 {IOCTL_CDROM_LOAD_MEDIA
, "IOCTL_CDROM_LOAD_MEDIA"},
122 {IOCTL_CDROM_RESERVE
, "IOCTL_CDROM_RESERVE"},
123 {IOCTL_CDROM_RELEASE
, "IOCTL_CDROM_RELEASE"},
124 {IOCTL_CDROM_FIND_NEW_DEVICES
, "IOCTL_CDROM_FIND_NEW_DEVICES"}
126 static const char *iocodex(DWORD code
)
129 static char buffer
[25];
130 for(i
=0; i
<sizeof(iocodextable
)/sizeof(struct iocodexs
); i
++)
131 if (code
==iocodextable
[i
].code
)
132 return iocodextable
[i
].codex
;
133 sprintf(buffer
, "IOCTL_CODE_%x", (int)code
);
137 WINE_DEFAULT_DEBUG_CHANNEL(cdrom
);
139 #define FRAME_OF_ADDR(a) (((int)(a)[1] * CD_SECS + (a)[2]) * CD_FRAMES + (a)[3])
140 #define FRAME_OF_MSF(a) (((int)(a).M * CD_SECS + (a).S) * CD_FRAMES + (a).F)
141 #define FRAME_OF_TOC(toc, idx) FRAME_OF_ADDR((toc).TrackData[idx - (toc).FirstTrack].Address)
142 #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;}
144 static NTSTATUS
CDROM_ReadTOC(int, CDROM_TOC
*);
145 static NTSTATUS
CDROM_GetStatusCode(int);
151 # define IDE6_MAJOR 88
154 # define IDE7_MAJOR 89
157 # ifdef CDROM_SEND_PACKET
158 /* structure for CDROM_PACKET_COMMAND ioctl */
159 /* not all Linux versions have all the fields, so we define the
160 * structure ourselves to make sure */
161 struct linux_cdrom_generic_command
163 unsigned char cmd
[CDROM_PACKET_SIZE
];
164 unsigned char *buffer
;
167 struct request_sense
*sense
;
168 unsigned char data_direction
;
173 # endif /* CDROM_SEND_PACKET */
177 /* FIXME: this is needed because we can't open simultaneously several times /dev/cdrom
178 * this should be removed when a proper device interface is implemented
180 * (WS) We need this to keep track of current position and to safely
181 * detect media changes. Besides this should provide a great speed up
187 char toc_good
; /* if false, will reread TOC from disk */
189 SUB_Q_CURRENT_POSITION CurrentPosition
;
192 static struct cdrom_cache cdrom_cache
[26];
194 /* Proposed media change function: not really needed at this time */
195 /* This is a 1 or 0 type of function */
197 static int CDROM_MediaChanged(int dev
)
201 struct cdrom_tochdr hdr
;
202 struct cdrom_tocentry entry
;
204 if (dev
< 0 || dev
>= 26)
206 if ( ioctl(cdrom_cache
[dev
].fd
, CDROMREADTOCHDR
, &hdr
) == -1 )
209 if ( memcmp(&hdr
, &cdrom_cache
[dev
].hdr
, sizeof(struct cdrom_tochdr
)) )
212 for (i
=hdr
.cdth_trk0
; i
<=hdr
.cdth_trk1
+1; i
++)
214 if (i
== hdr
.cdth_trk1
+ 1)
216 entry
.cdte_track
= CDROM_LEADOUT
;
218 entry
.cdte_track
= i
;
220 entry
.cdte_format
= CDROM_MSF
;
221 if ( ioctl(cdrom_cache
[dev
].fd
, CDROMREADTOCENTRY
, &entry
) == -1)
223 if ( memcmp(&entry
, cdrom_cache
[dev
].entry
+i
-hdr
.cdth_trk0
,
224 sizeof(struct cdrom_tocentry
)) )
231 /******************************************************************
232 * CDROM_SyncCache [internal]
234 * Read the TOC in and store it in the cdrom_cache structure.
235 * Further requests for the TOC will be copied from the cache
236 * unless certain events like disk ejection is detected, in which
237 * case the cache will be cleared, causing it to be resynced.
240 static int CDROM_SyncCache(int dev
)
244 struct cdrom_tochdr hdr
;
245 struct cdrom_tocentry entry
;
246 #elif defined(__FreeBSD__) || defined(__NetBSD__)
247 struct ioc_toc_header hdr
;
248 struct ioc_read_toc_entry entry
;
249 struct cd_toc_entry toc_buffer
;
251 CDROM_TOC
*toc
= &cdrom_cache
[dev
].toc
;
252 cdrom_cache
[dev
].toc_good
= 0;
256 io
= ioctl(cdrom_cache
[dev
].fd
, CDROMREADTOCHDR
, &hdr
);
259 WARN("(%d) -- Error occurred (%s)!\n", dev
, strerror(errno
));
263 TRACE("caching toc from=%d to=%d\n", toc
->FirstTrack
, toc
->LastTrack
);
265 toc
->FirstTrack
= hdr
.cdth_trk0
;
266 toc
->LastTrack
= hdr
.cdth_trk1
;
267 tsz
= sizeof(toc
->FirstTrack
) + sizeof(toc
->LastTrack
)
268 + sizeof(TRACK_DATA
) * (toc
->LastTrack
-toc
->FirstTrack
+2);
269 toc
->Length
[0] = tsz
>> 8;
270 toc
->Length
[1] = tsz
;
272 for (i
= toc
->FirstTrack
; i
<= toc
->LastTrack
+ 1; i
++)
274 if (i
== toc
->LastTrack
+ 1)
275 entry
.cdte_track
= CDROM_LEADOUT
;
277 entry
.cdte_track
= i
;
278 entry
.cdte_format
= CDROM_MSF
;
279 io
= ioctl(cdrom_cache
[dev
].fd
, CDROMREADTOCENTRY
, &entry
);
281 WARN("error read entry (%s)\n", strerror(errno
));
284 toc
->TrackData
[i
- toc
->FirstTrack
].Control
= entry
.cdte_ctrl
;
285 toc
->TrackData
[i
- toc
->FirstTrack
].Adr
= entry
.cdte_adr
;
286 /* marking last track with leadout value as index */
287 toc
->TrackData
[i
- toc
->FirstTrack
].TrackNumber
= entry
.cdte_track
;
288 toc
->TrackData
[i
- toc
->FirstTrack
].Address
[0] = 0;
289 toc
->TrackData
[i
- toc
->FirstTrack
].Address
[1] = entry
.cdte_addr
.msf
.minute
;
290 toc
->TrackData
[i
- toc
->FirstTrack
].Address
[2] = entry
.cdte_addr
.msf
.second
;
291 toc
->TrackData
[i
- toc
->FirstTrack
].Address
[3] = entry
.cdte_addr
.msf
.frame
;
293 cdrom_cache
[dev
].toc_good
= 1;
295 #elif defined(__FreeBSD__) || defined(__NetBSD__)
297 io
= ioctl(cdrom_cache
[dev
].fd
, CDIOREADTOCHEADER
, &hdr
);
300 WARN("(%d) -- Error occurred (%s)!\n", dev
, strerror(errno
));
303 toc
->FirstTrack
= hdr
.starting_track
;
304 toc
->LastTrack
= hdr
.ending_track
;
305 tsz
= sizeof(toc
->FirstTrack
) + sizeof(toc
->LastTrack
)
306 + sizeof(TRACK_DATA
) * (toc
->LastTrack
-toc
->FirstTrack
+2);
307 toc
->Length
[0] = tsz
>> 8;
308 toc
->Length
[1] = tsz
;
310 TRACE("caching toc from=%d to=%d\n", toc
->FirstTrack
, toc
->LastTrack
);
312 for (i
= toc
->FirstTrack
; i
<= toc
->LastTrack
+ 1; i
++)
314 if (i
== toc
->LastTrack
+ 1)
317 entry
.starting_track
= LEADOUT
;
319 entry
.starting_track
= i
;
321 memset((char *)&toc_buffer
, 0, sizeof(toc_buffer
));
322 entry
.address_format
= CD_MSF_FORMAT
;
323 entry
.data_len
= sizeof(toc_buffer
);
324 entry
.data
= &toc_buffer
;
325 io
= ioctl(cdrom_cache
[dev
].fd
, CDIOREADTOCENTRYS
, &entry
);
327 WARN("error read entry (%s)\n", strerror(errno
));
330 toc
->TrackData
[i
- toc
->FirstTrack
].Control
= toc_buffer
.control
;
331 toc
->TrackData
[i
- toc
->FirstTrack
].Adr
= toc_buffer
.addr_type
;
332 /* marking last track with leadout value as index */
333 toc
->TrackData
[i
- toc
->FirstTrack
].TrackNumber
= entry
.starting_track
;
334 toc
->TrackData
[i
- toc
->FirstTrack
].Address
[0] = 0;
335 toc
->TrackData
[i
- toc
->FirstTrack
].Address
[1] = toc_buffer
.addr
.msf
.minute
;
336 toc
->TrackData
[i
- toc
->FirstTrack
].Address
[2] = toc_buffer
.addr
.msf
.second
;
337 toc
->TrackData
[i
- toc
->FirstTrack
].Address
[3] = toc_buffer
.addr
.msf
.frame
;
339 cdrom_cache
[dev
].toc_good
= 1;
342 return STATUS_NOT_SUPPORTED
;
345 return CDROM_GetStatusCode(io
);
348 static void CDROM_ClearCacheEntry(int dev
)
350 cdrom_cache
[dev
].toc_good
= 0;
355 /******************************************************************
356 * CDROM_GetInterfaceInfo
358 * Determines the ide interface (the number after the ide), and the
359 * number of the device on that interface for ide cdroms (*port == 0).
360 * Determines the scsi information for scsi cdroms (*port >= 1).
361 * Returns false if the info cannot not be obtained.
363 * NOTE: this function is used in CDROM_InitRegistry and CDROM_GetAddress
365 static int CDROM_GetInterfaceInfo(int fd
, int* port
, int* iface
, int* device
,int* lun
)
370 if ( fstat(fd
, &st
) == -1 || ! S_ISBLK(st
.st_mode
)) {
371 FIXME("cdrom not a block device!!!\n");
378 switch (major(st
.st_rdev
)) {
379 case IDE0_MAJOR
: *iface
= 0; break;
380 case IDE1_MAJOR
: *iface
= 1; break;
381 case IDE2_MAJOR
: *iface
= 2; break;
382 case IDE3_MAJOR
: *iface
= 3; break;
383 case IDE4_MAJOR
: *iface
= 4; break;
384 case IDE5_MAJOR
: *iface
= 5; break;
385 case IDE6_MAJOR
: *iface
= 6; break;
386 case IDE7_MAJOR
: *iface
= 7; break;
387 default: *port
= 1; break;
391 *device
= (minor(st
.st_rdev
) >> 6);
394 #ifdef SCSI_IOCTL_GET_IDLUN
396 if (ioctl(fd
, SCSI_IOCTL_GET_IDLUN
, &idlun
) != -1)
398 *port
= ((idlun
[0] >> 24) & 0xff) + 1;
399 *iface
= (idlun
[0] >> 16) & 0xff;
400 *device
= idlun
[0] & 0xff;
401 *lun
= (idlun
[0] >> 8) & 0xff;
406 FIXME("CD-ROM device (%d, %d) not supported\n",
407 major(st
.st_rdev
), minor(st
.st_rdev
));
413 #elif defined(__NetBSD__)
415 struct scsi_addr addr
;
416 if (ioctl(fd
, SCIOCIDENTIFY
, &addr
) != -1) {
418 case TYPE_SCSI
: *port
= 1;
419 *iface
= addr
.addr
.scsi
.scbus
;
420 *device
= addr
.addr
.scsi
.target
;
421 *lun
= addr
.addr
.scsi
.lun
;
423 case TYPE_ATAPI
: *port
= 0;
424 *iface
= addr
.addr
.atapi
.atbus
;
425 *device
= addr
.addr
.atapi
.drive
;
433 #elif defined(__FreeBSD__)
434 FIXME("not implemented for BSD\n");
437 FIXME("not implemented for nonlinux\n");
443 /******************************************************************
446 * Initializes registry to contain scsi info about the cdrom in NT.
447 * All devices (even not real scsi ones) have this info in NT.
448 * TODO: for now it only works for non scsi devices
449 * NOTE: programs usually read these registry entries after sending the
450 * IOCTL_SCSI_GET_ADDRESS ioctl to the cdrom
452 void CDROM_InitRegistry(int fd
, int device_id
, const char *device
)
454 int portnum
, busid
, targetid
, lun
;
455 OBJECT_ATTRIBUTES attr
;
456 UNICODE_STRING nameW
;
468 cdrom_cache
[device_id
].device
= device
;
470 attr
.Length
= sizeof(attr
);
471 attr
.RootDirectory
= 0;
472 attr
.ObjectName
= &nameW
;
474 attr
.SecurityDescriptor
= NULL
;
475 attr
.SecurityQualityOfService
= NULL
;
477 if ( ! CDROM_GetInterfaceInfo(fd
, &portnum
, &busid
, &targetid
, &lun
))
480 /* Ensure there is Scsi key */
481 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, "Machine\\HARDWARE\\DEVICEMAP\\Scsi" ) ||
482 NtCreateKey( &scsiKey
, KEY_ALL_ACCESS
, &attr
, 0,
483 NULL
, REG_OPTION_VOLATILE
, &disp
))
485 ERR("Cannot create DEVICEMAP\\Scsi registry key\n" );
488 RtlFreeUnicodeString( &nameW
);
490 snprintf(buffer
,sizeof(buffer
),"Scsi Port %d",portnum
);
491 attr
.RootDirectory
= scsiKey
;
492 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, buffer
) ||
493 NtCreateKey( &portKey
, KEY_ALL_ACCESS
, &attr
, 0,
494 NULL
, REG_OPTION_VOLATILE
, &disp
))
496 ERR("Cannot create DEVICEMAP\\Scsi Port registry key\n" );
499 RtlFreeUnicodeString( &nameW
);
501 RtlCreateUnicodeStringFromAsciiz( &nameW
, "Driver" );
503 RtlMultiByteToUnicodeN( dataW
, 50, &lenW
, data
, strlen(data
));
504 NtSetValueKey( portKey
, &nameW
, 0, REG_SZ
, (BYTE
*)dataW
, lenW
);
505 RtlFreeUnicodeString( &nameW
);
507 RtlCreateUnicodeStringFromAsciiz( &nameW
, "FirstBusTimeScanInMs" );
508 NtSetValueKey( portKey
,&nameW
, 0, REG_DWORD
, (BYTE
*)&value
, sizeof(DWORD
));
509 RtlFreeUnicodeString( &nameW
);
514 if (ioctl(fd
,HDIO_GET_DMA
, &dma
) != -1) {
516 TRACE("setting dma to %lx\n", value
);
520 RtlCreateUnicodeStringFromAsciiz( &nameW
, "DMAEnabled" );
521 NtSetValueKey( portKey
,&nameW
, 0, REG_DWORD
, (BYTE
*)&value
, sizeof(DWORD
));
522 RtlFreeUnicodeString( &nameW
);
524 snprintf(buffer
,40,"Scsi Bus %d", busid
);
525 attr
.RootDirectory
= portKey
;
526 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, buffer
) ||
527 NtCreateKey( &busKey
, KEY_ALL_ACCESS
, &attr
, 0,
528 NULL
, REG_OPTION_VOLATILE
, &disp
))
530 ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus registry key\n" );
533 RtlFreeUnicodeString( &nameW
);
535 attr
.RootDirectory
= busKey
;
536 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, "Initiator Id 255" ) ||
537 NtCreateKey( &targetKey
, KEY_ALL_ACCESS
, &attr
, 0,
538 NULL
, REG_OPTION_VOLATILE
, &disp
))
540 ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus\\Initiator Id 255 registry key\n" );
543 RtlFreeUnicodeString( &nameW
);
544 NtClose( targetKey
);
546 snprintf(buffer
,40,"Target Id %d", targetid
);
547 attr
.RootDirectory
= busKey
;
548 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, buffer
) ||
549 NtCreateKey( &targetKey
, KEY_ALL_ACCESS
, &attr
, 0,
550 NULL
, REG_OPTION_VOLATILE
, &disp
))
552 ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus 0\\Target Id registry key\n" );
555 RtlFreeUnicodeString( &nameW
);
557 RtlCreateUnicodeStringFromAsciiz( &nameW
, "Type" );
558 data
= "CdRomPeripheral";
559 RtlMultiByteToUnicodeN( dataW
, 50, &lenW
, data
, strlen(data
));
560 NtSetValueKey( targetKey
, &nameW
, 0, REG_SZ
, (BYTE
*)dataW
, lenW
);
561 RtlFreeUnicodeString( &nameW
);
562 /* FIXME - maybe read the real identifier?? */
563 RtlCreateUnicodeStringFromAsciiz( &nameW
, "Identifier" );
565 RtlMultiByteToUnicodeN( dataW
, 50, &lenW
, data
, strlen(data
));
566 NtSetValueKey( targetKey
, &nameW
, 0, REG_SZ
, (BYTE
*)dataW
, lenW
);
567 RtlFreeUnicodeString( &nameW
);
568 /* FIXME - we always use Cdrom0 - do not know about the nt behaviour */
569 RtlCreateUnicodeStringFromAsciiz( &nameW
, "DeviceName" );
571 RtlMultiByteToUnicodeN( dataW
, 50, &lenW
, data
, strlen(data
));
572 NtSetValueKey( targetKey
, &nameW
, 0, REG_SZ
, (BYTE
*)dataW
, lenW
);
573 RtlFreeUnicodeString( &nameW
);
575 NtClose( targetKey
);
582 /******************************************************************
586 static NTSTATUS
CDROM_Open(HANDLE hDevice
, DWORD clientID
, int* dev
)
588 *dev
= LOWORD(clientID
);
590 if (*dev
>= 26) return STATUS_NO_SUCH_DEVICE
;
592 if (!cdrom_cache
[*dev
].count
)
596 if (!(device
= cdrom_cache
[*dev
].device
)) return STATUS_NO_SUCH_DEVICE
;
597 cdrom_cache
[*dev
].fd
= open(device
, O_RDONLY
|O_NONBLOCK
);
598 if (cdrom_cache
[*dev
].fd
== -1)
600 FIXME("Can't open configured CD-ROM drive %c: (device %s): %s\n",
601 'A' + *dev
, device
, strerror(errno
));
602 return STATUS_NO_SUCH_DEVICE
;
605 cdrom_cache
[*dev
].count
++;
606 TRACE("%d, %d, %d\n", *dev
, cdrom_cache
[*dev
].fd
, cdrom_cache
[*dev
].count
);
607 return STATUS_SUCCESS
;
610 /******************************************************************
615 static void CDROM_Close(DWORD clientID
)
617 int dev
= LOWORD(clientID
);
619 if (dev
>= 26 /*|| fd != cdrom_cache[dev].fd*/) FIXME("how come\n");
620 if (--cdrom_cache
[dev
].count
== 0)
622 close(cdrom_cache
[dev
].fd
);
623 cdrom_cache
[dev
].fd
= -1;
627 /******************************************************************
628 * CDROM_GetStatusCode
632 static NTSTATUS
CDROM_GetStatusCode(int io
)
634 if (io
== 0) return STATUS_SUCCESS
;
641 return STATUS_NO_MEDIA_IN_DEVICE
;
643 return STATUS_ACCESS_DENIED
;
645 return STATUS_INVALID_PARAMETER
;
646 /* case EBADF: Bad file descriptor */
648 return STATUS_NOT_SUPPORTED
;
650 FIXME("Unmapped error code %d: %s\n", errno
, strerror(errno
));
651 return STATUS_IO_DEVICE_ERROR
;
654 /******************************************************************
658 static NTSTATUS
CDROM_GetControl(int dev
, CDROM_AUDIO_CONTROL
* cac
)
660 cac
->LbaFormat
= 0; /* FIXME */
661 cac
->LogicalBlocksPerSecond
= 1; /* FIXME */
662 return STATUS_NOT_SUPPORTED
;
665 /******************************************************************
666 * CDROM_GetDeviceNumber
669 static NTSTATUS
CDROM_GetDeviceNumber(int dev
, STORAGE_DEVICE_NUMBER
* devnum
)
671 return STATUS_NOT_SUPPORTED
;
674 /******************************************************************
675 * CDROM_GetDriveGeometry
678 static NTSTATUS
CDROM_GetDriveGeometry(int dev
, DISK_GEOMETRY
* dg
)
684 if ((ret
= CDROM_ReadTOC(dev
, &toc
)) != 0) return ret
;
686 fsize
= FRAME_OF_TOC(toc
, toc
.LastTrack
+1)
687 - FRAME_OF_TOC(toc
, 1); /* Total size in frames */
689 dg
->Cylinders
.u
.LowPart
= fsize
/ (64 * 32);
690 dg
->Cylinders
.u
.HighPart
= 0;
691 dg
->MediaType
= RemovableMedia
;
692 dg
->TracksPerCylinder
= 64;
693 dg
->SectorsPerTrack
= 32;
694 dg
->BytesPerSector
= 2048;
698 /**************************************************************************
699 * CDROM_Reset [internal]
701 static NTSTATUS
CDROM_ResetAudio(int dev
)
704 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDROMRESET
));
705 #elif defined(__FreeBSD__) || defined(__NetBSD__)
706 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDIOCRESET
, NULL
));
708 return STATUS_NOT_SUPPORTED
;
712 /******************************************************************
717 static NTSTATUS
CDROM_SetTray(int dev
, BOOL doEject
)
720 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, doEject
? CDROMEJECT
: CDROMCLOSETRAY
));
721 #elif defined(__FreeBSD__) || defined(__NetBSD__)
722 return CDROM_GetStatusCode((ioctl(cdrom_cache
[dev
].fd
, CDIOCALLOW
, NULL
)) ||
723 (ioctl(cdrom_cache
[dev
].fd
, doEject
? CDIOCEJECT
: CDIOCCLOSE
, NULL
)) ||
724 (ioctl(cdrom_cache
[dev
].fd
, CDIOCPREVENT
, NULL
)));
726 return STATUS_NOT_SUPPORTED
;
730 /******************************************************************
731 * CDROM_ControlEjection
735 static NTSTATUS
CDROM_ControlEjection(int dev
, const PREVENT_MEDIA_REMOVAL
* rmv
)
738 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDROM_LOCKDOOR
, rmv
->PreventMediaRemoval
));
739 #elif defined(__FreeBSD__) || defined(__NetBSD__)
740 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, (rmv
->PreventMediaRemoval
) ? CDIOCPREVENT
: CDIOCALLOW
, NULL
));
742 return STATUS_NOT_SUPPORTED
;
746 /******************************************************************
751 static NTSTATUS
CDROM_ReadTOC(int dev
, CDROM_TOC
* toc
)
753 NTSTATUS ret
= STATUS_NOT_SUPPORTED
;
755 if (dev
< 0 || dev
>= 26)
756 return STATUS_INVALID_PARAMETER
;
757 if ( !cdrom_cache
[dev
].toc_good
) {
758 ret
= CDROM_SyncCache(dev
);
762 *toc
= cdrom_cache
[dev
].toc
;
763 return STATUS_SUCCESS
;
766 /******************************************************************
771 static NTSTATUS
CDROM_GetDiskData(int dev
, CDROM_DISK_DATA
* data
)
777 if ((ret
= CDROM_ReadTOC(dev
, &toc
)) != 0) return ret
;
779 for (i
= toc
.FirstTrack
; i
<= toc
.LastTrack
; i
++) {
780 if (toc
.TrackData
[i
-toc
.FirstTrack
].Control
& 0x04)
781 data
->DiskData
|= CDROM_DISK_DATA_TRACK
;
783 data
->DiskData
|= CDROM_DISK_AUDIO_TRACK
;
785 return STATUS_SUCCESS
;
788 /******************************************************************
793 static NTSTATUS
CDROM_ReadQChannel(int dev
, const CDROM_SUB_Q_DATA_FORMAT
* fmt
,
794 SUB_Q_CHANNEL_DATA
* data
)
796 NTSTATUS ret
= STATUS_NOT_SUPPORTED
;
799 SUB_Q_HEADER
* hdr
= (SUB_Q_HEADER
*)data
;
801 struct cdrom_subchnl sc
;
802 sc
.cdsc_format
= CDROM_MSF
;
804 io
= ioctl(cdrom_cache
[dev
].fd
, CDROMSUBCHNL
, &sc
);
807 TRACE("opened or no_media (%s)!\n", strerror(errno
));
808 hdr
->AudioStatus
= AUDIO_STATUS_NO_STATUS
;
809 CDROM_ClearCacheEntry(dev
);
813 hdr
->AudioStatus
= AUDIO_STATUS_NOT_SUPPORTED
;
815 switch (sc
.cdsc_audiostatus
) {
816 case CDROM_AUDIO_INVALID
:
817 CDROM_ClearCacheEntry(dev
);
818 hdr
->AudioStatus
= AUDIO_STATUS_NOT_SUPPORTED
;
820 case CDROM_AUDIO_NO_STATUS
:
821 CDROM_ClearCacheEntry(dev
);
822 hdr
->AudioStatus
= AUDIO_STATUS_NO_STATUS
;
824 case CDROM_AUDIO_PLAY
:
825 hdr
->AudioStatus
= AUDIO_STATUS_IN_PROGRESS
;
827 case CDROM_AUDIO_PAUSED
:
828 hdr
->AudioStatus
= AUDIO_STATUS_PAUSED
;
830 case CDROM_AUDIO_COMPLETED
:
831 hdr
->AudioStatus
= AUDIO_STATUS_PLAY_COMPLETE
;
833 case CDROM_AUDIO_ERROR
:
834 hdr
->AudioStatus
= AUDIO_STATUS_PLAY_ERROR
;
837 TRACE("status=%02X !\n", sc
.cdsc_audiostatus
);
842 case IOCTL_CDROM_CURRENT_POSITION
:
843 size
= sizeof(SUB_Q_CURRENT_POSITION
);
844 if (hdr
->AudioStatus
==AUDIO_STATUS_IN_PROGRESS
) {
845 data
->CurrentPosition
.FormatCode
= IOCTL_CDROM_CURRENT_POSITION
;
846 data
->CurrentPosition
.Control
= sc
.cdsc_ctrl
;
847 data
->CurrentPosition
.ADR
= sc
.cdsc_adr
;
848 data
->CurrentPosition
.TrackNumber
= sc
.cdsc_trk
;
849 data
->CurrentPosition
.IndexNumber
= sc
.cdsc_ind
;
851 data
->CurrentPosition
.AbsoluteAddress
[0] = 0;
852 data
->CurrentPosition
.AbsoluteAddress
[1] = sc
.cdsc_absaddr
.msf
.minute
;
853 data
->CurrentPosition
.AbsoluteAddress
[2] = sc
.cdsc_absaddr
.msf
.second
;
854 data
->CurrentPosition
.AbsoluteAddress
[3] = sc
.cdsc_absaddr
.msf
.frame
;
856 data
->CurrentPosition
.TrackRelativeAddress
[0] = 0;
857 data
->CurrentPosition
.TrackRelativeAddress
[1] = sc
.cdsc_reladdr
.msf
.minute
;
858 data
->CurrentPosition
.TrackRelativeAddress
[2] = sc
.cdsc_reladdr
.msf
.second
;
859 data
->CurrentPosition
.TrackRelativeAddress
[3] = sc
.cdsc_reladdr
.msf
.frame
;
861 cdrom_cache
[dev
].CurrentPosition
= data
->CurrentPosition
;
863 else /* not playing */
865 cdrom_cache
[dev
].CurrentPosition
.Header
= *hdr
; /* Preserve header info */
866 data
->CurrentPosition
= cdrom_cache
[dev
].CurrentPosition
;
869 case IOCTL_CDROM_MEDIA_CATALOG
:
870 size
= sizeof(SUB_Q_MEDIA_CATALOG_NUMBER
);
871 data
->MediaCatalog
.FormatCode
= IOCTL_CDROM_MEDIA_CATALOG
;
873 struct cdrom_mcn mcn
;
874 if ((io
= ioctl(cdrom_cache
[dev
].fd
, CDROM_GET_MCN
, &mcn
)) == -1) goto end
;
876 data
->MediaCatalog
.FormatCode
= IOCTL_CDROM_MEDIA_CATALOG
;
877 data
->MediaCatalog
.Mcval
= 0; /* FIXME */
878 memcpy(data
->MediaCatalog
.MediaCatalog
, mcn
.medium_catalog_number
, 14);
879 data
->MediaCatalog
.MediaCatalog
[14] = 0;
882 case IOCTL_CDROM_TRACK_ISRC
:
883 size
= sizeof(SUB_Q_CURRENT_POSITION
);
884 FIXME("TrackIsrc: NIY on linux\n");
885 data
->TrackIsrc
.FormatCode
= IOCTL_CDROM_TRACK_ISRC
;
886 data
->TrackIsrc
.Tcval
= 0;
892 ret
= CDROM_GetStatusCode(io
);
893 #elif defined(__FreeBSD__) || defined(__NetBSD__)
895 SUB_Q_HEADER
* hdr
= (SUB_Q_HEADER
*)data
;
897 struct ioc_read_subchannel read_sc
;
898 struct cd_sub_channel_info sc
;
900 read_sc
.address_format
= CD_MSF_FORMAT
;
902 read_sc
.data_len
= sizeof(sc
);
906 case IOCTL_CDROM_CURRENT_POSITION
:
907 read_sc
.data_format
= CD_CURRENT_POSITION
;
909 case IOCTL_CDROM_MEDIA_CATALOG
:
910 read_sc
.data_format
= CD_MEDIA_CATALOG
;
912 case IOCTL_CDROM_TRACK_ISRC
:
913 read_sc
.data_format
= CD_TRACK_INFO
;
914 sc
.what
.track_info
.track_number
= data
->TrackIsrc
.Track
;
917 io
= ioctl(cdrom_cache
[dev
].fd
, CDIOCREADSUBCHANNEL
, &read_sc
);
920 TRACE("opened or no_media (%s)!\n", strerror(errno
));
921 CDROM_ClearCacheEntry(dev
);
922 hdr
->AudioStatus
= AUDIO_STATUS_NO_STATUS
;
926 hdr
->AudioStatus
= AUDIO_STATUS_NOT_SUPPORTED
;
928 switch (sc
.header
.audio_status
) {
929 case CD_AS_AUDIO_INVALID
:
930 CDROM_ClearCacheEntry(dev
);
931 hdr
->AudioStatus
= AUDIO_STATUS_NOT_SUPPORTED
;
933 case CD_AS_NO_STATUS
:
934 CDROM_ClearCacheEntry(dev
);
935 hdr
->AudioStatus
= AUDIO_STATUS_NO_STATUS
;
937 case CD_AS_PLAY_IN_PROGRESS
:
938 hdr
->AudioStatus
= AUDIO_STATUS_IN_PROGRESS
;
940 case CD_AS_PLAY_PAUSED
:
941 hdr
->AudioStatus
= AUDIO_STATUS_PAUSED
;
943 case CD_AS_PLAY_COMPLETED
:
944 hdr
->AudioStatus
= AUDIO_STATUS_PLAY_COMPLETE
;
946 case CD_AS_PLAY_ERROR
:
947 hdr
->AudioStatus
= AUDIO_STATUS_PLAY_ERROR
;
950 TRACE("status=%02X !\n", sc
.header
.audio_status
);
954 case IOCTL_CDROM_CURRENT_POSITION
:
955 size
= sizeof(SUB_Q_CURRENT_POSITION
);
956 if (hdr
->AudioStatus
==AUDIO_STATUS_IN_PROGRESS
) {
957 data
->CurrentPosition
.FormatCode
= IOCTL_CDROM_CURRENT_POSITION
;
958 data
->CurrentPosition
.Control
= sc
.what
.position
.control
;
959 data
->CurrentPosition
.ADR
= sc
.what
.position
.addr_type
;
960 data
->CurrentPosition
.TrackNumber
= sc
.what
.position
.track_number
;
961 data
->CurrentPosition
.IndexNumber
= sc
.what
.position
.index_number
;
963 data
->CurrentPosition
.AbsoluteAddress
[0] = 0;
964 data
->CurrentPosition
.AbsoluteAddress
[1] = sc
.what
.position
.absaddr
.msf
.minute
;
965 data
->CurrentPosition
.AbsoluteAddress
[2] = sc
.what
.position
.absaddr
.msf
.second
;
966 data
->CurrentPosition
.AbsoluteAddress
[3] = sc
.what
.position
.absaddr
.msf
.frame
;
967 data
->CurrentPosition
.TrackRelativeAddress
[0] = 0;
968 data
->CurrentPosition
.TrackRelativeAddress
[1] = sc
.what
.position
.reladdr
.msf
.minute
;
969 data
->CurrentPosition
.TrackRelativeAddress
[2] = sc
.what
.position
.reladdr
.msf
.second
;
970 data
->CurrentPosition
.TrackRelativeAddress
[3] = sc
.what
.position
.reladdr
.msf
.frame
;
971 cdrom_cache
[dev
].CurrentPosition
= data
->CurrentPosition
;
973 else { /* not playing */
974 cdrom_cache
[dev
].CurrentPosition
.Header
= *hdr
; /* Preserve header info */
975 data
->CurrentPosition
= cdrom_cache
[dev
].CurrentPosition
;
978 case IOCTL_CDROM_MEDIA_CATALOG
:
979 size
= sizeof(SUB_Q_MEDIA_CATALOG_NUMBER
);
980 data
->MediaCatalog
.FormatCode
= IOCTL_CDROM_MEDIA_CATALOG
;
981 data
->MediaCatalog
.Mcval
= sc
.what
.media_catalog
.mc_valid
;
982 memcpy(data
->MediaCatalog
.MediaCatalog
, sc
.what
.media_catalog
.mc_number
, 15);
984 case IOCTL_CDROM_TRACK_ISRC
:
985 size
= sizeof(SUB_Q_CURRENT_POSITION
);
986 data
->TrackIsrc
.FormatCode
= IOCTL_CDROM_TRACK_ISRC
;
987 data
->TrackIsrc
.Tcval
= sc
.what
.track_info
.ti_valid
;
988 memcpy(data
->TrackIsrc
.TrackIsrc
, sc
.what
.track_info
.ti_number
, 15);
993 ret
= CDROM_GetStatusCode(io
);
998 /******************************************************************
1003 static NTSTATUS
CDROM_Verify(int dev
)
1005 /* quick implementation */
1006 CDROM_SUB_Q_DATA_FORMAT fmt
;
1007 SUB_Q_CHANNEL_DATA data
;
1009 fmt
.Format
= IOCTL_CDROM_CURRENT_POSITION
;
1010 return CDROM_ReadQChannel(dev
, &fmt
, &data
) ? 1 : 0;
1013 /******************************************************************
1014 * CDROM_PlayAudioMSF
1018 static NTSTATUS
CDROM_PlayAudioMSF(int dev
, const CDROM_PLAY_AUDIO_MSF
* audio_msf
)
1020 NTSTATUS ret
= STATUS_NOT_SUPPORTED
;
1022 struct cdrom_msf msf
;
1025 msf
.cdmsf_min0
= audio_msf
->StartingM
;
1026 msf
.cdmsf_sec0
= audio_msf
->StartingS
;
1027 msf
.cdmsf_frame0
= audio_msf
->StartingF
;
1028 msf
.cdmsf_min1
= audio_msf
->EndingM
;
1029 msf
.cdmsf_sec1
= audio_msf
->EndingS
;
1030 msf
.cdmsf_frame1
= audio_msf
->EndingF
;
1032 io
= ioctl(cdrom_cache
[dev
].fd
, CDROMSTART
);
1035 WARN("motor doesn't start !\n");
1038 io
= ioctl(cdrom_cache
[dev
].fd
, CDROMPLAYMSF
, &msf
);
1041 WARN("device doesn't play !\n");
1044 TRACE("msf = %d:%d:%d %d:%d:%d\n",
1045 msf
.cdmsf_min0
, msf
.cdmsf_sec0
, msf
.cdmsf_frame0
,
1046 msf
.cdmsf_min1
, msf
.cdmsf_sec1
, msf
.cdmsf_frame1
);
1048 ret
= CDROM_GetStatusCode(io
);
1049 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1050 struct ioc_play_msf msf
;
1053 msf
.start_m
= audio_msf
->StartingM
;
1054 msf
.start_s
= audio_msf
->StartingS
;
1055 msf
.start_f
= audio_msf
->StartingF
;
1056 msf
.end_m
= audio_msf
->EndingM
;
1057 msf
.end_s
= audio_msf
->EndingS
;
1058 msf
.end_f
= audio_msf
->EndingF
;
1060 io
= ioctl(cdrom_cache
[dev
].fd
, CDIOCSTART
, NULL
);
1063 WARN("motor doesn't start !\n");
1066 io
= ioctl(cdrom_cache
[dev
].fd
, CDIOCPLAYMSF
, &msf
);
1069 WARN("device doesn't play !\n");
1072 TRACE("msf = %d:%d:%d %d:%d:%d\n",
1073 msf
.start_m
, msf
.start_s
, msf
.start_f
,
1074 msf
.end_m
, msf
.end_s
, msf
.end_f
);
1076 ret
= CDROM_GetStatusCode(io
);
1081 /******************************************************************
1082 * CDROM_SeekAudioMSF
1086 static NTSTATUS
CDROM_SeekAudioMSF(int dev
, const CDROM_SEEK_AUDIO_MSF
* audio_msf
)
1090 SUB_Q_CURRENT_POSITION
*cp
;
1092 struct cdrom_msf0 msf
;
1093 struct cdrom_subchnl sc
;
1094 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1095 struct ioc_play_msf msf
;
1096 struct ioc_read_subchannel read_sc
;
1097 struct cd_sub_channel_info sc
;
1101 /* Use the information on the TOC to compute the new current
1102 * position, which is shadowed on the cache. [Portable]. */
1103 frame
= FRAME_OF_MSF(*audio_msf
);
1104 cp
= &cdrom_cache
[dev
].CurrentPosition
;
1105 if ((io
= CDROM_ReadTOC(dev
, &toc
)) != 0) return io
;
1107 for(i
=toc
.FirstTrack
;i
<=toc
.LastTrack
+1;i
++)
1108 if (FRAME_OF_TOC(toc
,i
)>frame
) break;
1109 if (i
<= toc
.FirstTrack
|| i
> toc
.LastTrack
+1)
1110 return STATUS_INVALID_PARAMETER
;
1112 cp
->FormatCode
= IOCTL_CDROM_CURRENT_POSITION
;
1113 cp
->Control
= toc
.TrackData
[i
-toc
.FirstTrack
].Control
;
1114 cp
->ADR
= toc
.TrackData
[i
-toc
.FirstTrack
].Adr
;
1115 cp
->TrackNumber
= toc
.TrackData
[i
-toc
.FirstTrack
].TrackNumber
;
1116 cp
->IndexNumber
= 0; /* FIXME: where do they keep these? */
1117 cp
->AbsoluteAddress
[0] = 0;
1118 cp
->AbsoluteAddress
[1] = toc
.TrackData
[i
-toc
.FirstTrack
].Address
[1];
1119 cp
->AbsoluteAddress
[2] = toc
.TrackData
[i
-toc
.FirstTrack
].Address
[2];
1120 cp
->AbsoluteAddress
[3] = toc
.TrackData
[i
-toc
.FirstTrack
].Address
[3];
1121 frame
-= FRAME_OF_TOC(toc
,i
);
1122 cp
->TrackRelativeAddress
[0] = 0;
1123 MSF_OF_FRAME(cp
->TrackRelativeAddress
[1], frame
);
1125 /* If playing, then issue a seek command, otherwise do nothing */
1127 sc
.cdsc_format
= CDROM_MSF
;
1129 io
= ioctl(cdrom_cache
[dev
].fd
, CDROMSUBCHNL
, &sc
);
1132 TRACE("opened or no_media (%s)!\n", strerror(errno
));
1133 CDROM_ClearCacheEntry(dev
);
1134 return CDROM_GetStatusCode(io
);
1136 if (sc
.cdsc_audiostatus
==CDROM_AUDIO_PLAY
)
1138 msf
.minute
= audio_msf
->M
;
1139 msf
.second
= audio_msf
->S
;
1140 msf
.frame
= audio_msf
->F
;
1141 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDROMSEEK
, &msf
));
1143 return STATUS_SUCCESS
;
1144 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1145 read_sc
.address_format
= CD_MSF_FORMAT
;
1147 read_sc
.data_len
= sizeof(sc
);
1149 read_sc
.data_format
= CD_CURRENT_POSITION
;
1151 io
= ioctl(cdrom_cache
[dev
].fd
, CDIOCREADSUBCHANNEL
, &read_sc
);
1154 TRACE("opened or no_media (%s)!\n", strerror(errno
));
1155 CDROM_ClearCacheEntry(dev
);
1156 return CDROM_GetStatusCode(io
);
1158 if (sc
.header
.audio_status
==CD_AS_PLAY_IN_PROGRESS
)
1161 msf
.start_m
= audio_msf
->M
;
1162 msf
.start_s
= audio_msf
->S
;
1163 msf
.start_f
= audio_msf
->F
;
1164 final_frame
= FRAME_OF_TOC(toc
,toc
.LastTrack
+1)-1;
1165 MSF_OF_FRAME(msf
.end_m
, final_frame
);
1167 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDIOCPLAYMSF
, &msf
));
1169 return STATUS_SUCCESS
;
1171 return STATUS_NOT_SUPPORTED
;
1175 /******************************************************************
1180 static NTSTATUS
CDROM_PauseAudio(int dev
)
1183 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDROMPAUSE
));
1184 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1185 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDIOCPAUSE
, NULL
));
1187 return STATUS_NOT_SUPPORTED
;
1191 /******************************************************************
1196 static NTSTATUS
CDROM_ResumeAudio(int dev
)
1199 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDROMRESUME
));
1200 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1201 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDIOCRESUME
, NULL
));
1203 return STATUS_NOT_SUPPORTED
;
1207 /******************************************************************
1212 static NTSTATUS
CDROM_StopAudio(int dev
)
1215 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDROMSTOP
));
1216 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1217 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDIOCSTOP
, NULL
));
1219 return STATUS_NOT_SUPPORTED
;
1223 /******************************************************************
1228 static NTSTATUS
CDROM_GetVolume(int dev
, VOLUME_CONTROL
* vc
)
1231 struct cdrom_volctrl volc
;
1234 io
= ioctl(cdrom_cache
[dev
].fd
, CDROMVOLREAD
, &volc
);
1237 vc
->PortVolume
[0] = volc
.channel0
;
1238 vc
->PortVolume
[1] = volc
.channel1
;
1239 vc
->PortVolume
[2] = volc
.channel2
;
1240 vc
->PortVolume
[3] = volc
.channel3
;
1242 return CDROM_GetStatusCode(io
);
1243 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1244 struct ioc_vol volc
;
1247 io
= ioctl(cdrom_cache
[dev
].fd
, CDIOCGETVOL
, &volc
);
1250 vc
->PortVolume
[0] = volc
.vol
[0];
1251 vc
->PortVolume
[1] = volc
.vol
[1];
1252 vc
->PortVolume
[2] = volc
.vol
[2];
1253 vc
->PortVolume
[3] = volc
.vol
[3];
1255 return CDROM_GetStatusCode(io
);
1257 return STATUS_NOT_SUPPORTED
;
1261 /******************************************************************
1266 static NTSTATUS
CDROM_SetVolume(int dev
, const VOLUME_CONTROL
* vc
)
1269 struct cdrom_volctrl volc
;
1271 volc
.channel0
= vc
->PortVolume
[0];
1272 volc
.channel1
= vc
->PortVolume
[1];
1273 volc
.channel2
= vc
->PortVolume
[2];
1274 volc
.channel3
= vc
->PortVolume
[3];
1276 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDROMVOLCTRL
, &volc
));
1277 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1278 struct ioc_vol volc
;
1280 volc
.vol
[0] = vc
->PortVolume
[0];
1281 volc
.vol
[1] = vc
->PortVolume
[1];
1282 volc
.vol
[2] = vc
->PortVolume
[2];
1283 volc
.vol
[3] = vc
->PortVolume
[3];
1285 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDIOCSETVOL
, &volc
));
1287 return STATUS_NOT_SUPPORTED
;
1291 /******************************************************************
1296 static NTSTATUS
CDROM_RawRead(int dev
, const RAW_READ_INFO
* raw
, void* buffer
, DWORD len
, DWORD
* sz
)
1298 int ret
= STATUS_NOT_SUPPORTED
;
1302 switch (raw
->TrackMode
)
1304 case YellowMode2
: sectSize
= 2336; break;
1305 case XAForm2
: sectSize
= 2328; break;
1306 case CDDA
: sectSize
= 2352; break;
1307 default: return STATUS_INVALID_PARAMETER
;
1309 if (len
< raw
->SectorCount
* sectSize
) return STATUS_BUFFER_TOO_SMALL
;
1310 /* strangely enough, it seems that sector offsets are always indicated with a size of 2048,
1311 * even if a larger size if read...
1315 struct cdrom_read cdr
;
1316 struct cdrom_read_audio cdra
;
1318 switch (raw
->TrackMode
)
1321 if (raw
->DiskOffset
.u
.HighPart
) FIXME("Unsupported value\n");
1322 cdr
.cdread_lba
= raw
->DiskOffset
.u
.LowPart
; /* FIXME ? */
1323 cdr
.cdread_bufaddr
= buffer
;
1324 cdr
.cdread_buflen
= raw
->SectorCount
* sectSize
;
1325 io
= ioctl(cdrom_cache
[dev
].fd
, CDROMREADMODE2
, &cdr
);
1328 FIXME("XAForm2: NIY\n");
1331 /* FIXME: the output doesn't seem 100% correct... in fact output is shifted
1332 * between by NT2K box and this... should check on the same drive...
1333 * otherwise, I fear a 2352/2368 mismatch somewhere in one of the drivers
1335 * Anyway, that's not critical at all. We're talking of 16/32 bytes, we're
1336 * talking of 0.2 ms of sound
1338 /* 2048 = 2 ** 11 */
1339 if (raw
->DiskOffset
.u
.HighPart
& ~2047) FIXME("Unsupported value\n");
1340 cdra
.addr
.lba
= ((raw
->DiskOffset
.u
.LowPart
>> 11) |
1341 (raw
->DiskOffset
.u
.HighPart
<< (32 - 11))) - 1;
1342 FIXME("reading at %u\n", cdra
.addr
.lba
);
1343 cdra
.addr_format
= CDROM_LBA
;
1344 cdra
.nframes
= raw
->SectorCount
;
1346 io
= ioctl(cdrom_cache
[dev
].fd
, CDROMREADAUDIO
, &cdra
);
1349 FIXME("NIY: %d\n", raw
->TrackMode
);
1355 switch (raw
->TrackMode
)
1358 FIXME("YellowMode2: NIY\n");
1361 FIXME("XAForm2: NIY\n");
1364 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
;
1896 CDROM_Close(clientID
);
1898 piosb
->u
.Status
= status
;
1899 piosb
->Information
= sz
;
1900 if (hEvent
) NtSetEvent(hEvent
, NULL
);