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_LINUX_MAJOR_H
47 # include <linux/major.h>
49 #ifdef HAVE_LINUX_HDREG_H
50 # include <linux/hdreg.h>
52 #ifdef HAVE_LINUX_PARAM_H
53 # include <linux/param.h>
55 #ifdef HAVE_LINUX_CDROM_H
56 # include <linux/cdrom.h>
58 #ifdef HAVE_LINUX_UCDROM_H
59 # include <linux/ucdrom.h>
61 #ifdef HAVE_SYS_CDIO_H
62 # include <sys/cdio.h>
64 #ifdef HAVE_SYS_SCSIIO_H
65 # include <sys/scsiio.h>
68 #define NONAMELESSUNION
69 #define NONAMELESSSTRUCT
81 #include "wine/debug.h"
83 /* Non-Linux systems do not have linux/cdrom.h and the like, and thus
84 lack the following constants. */
87 #define CD_SECS 60 /* seconds per minute */
90 #define CD_FRAMES 75 /* frames per second */
93 static const struct iocodexs
98 {IOCTL_CDROM_UNLOAD_DRIVER
, "IOCTL_CDROM_UNLOAD_DRIVER"},
99 {IOCTL_CDROM_READ_TOC
, "IOCTL_CDROM_READ_TOC"},
100 {IOCTL_CDROM_GET_CONTROL
, "IOCTL_CDROM_GET_CONTROL"},
101 {IOCTL_CDROM_PLAY_AUDIO_MSF
, "IOCTL_CDROM_PLAY_AUDIO_MSF"},
102 {IOCTL_CDROM_SEEK_AUDIO_MSF
, "IOCTL_CDROM_SEEK_AUDIO_MSF"},
103 {IOCTL_CDROM_STOP_AUDIO
, "IOCTL_CDROM_STOP_AUDIO"},
104 {IOCTL_CDROM_PAUSE_AUDIO
, "IOCTL_CDROM_PAUSE_AUDIO"},
105 {IOCTL_CDROM_RESUME_AUDIO
, "IOCTL_CDROM_RESUME_AUDIO"},
106 {IOCTL_CDROM_GET_VOLUME
, "IOCTL_CDROM_GET_VOLUME"},
107 {IOCTL_CDROM_SET_VOLUME
, "IOCTL_CDROM_SET_VOLUME"},
108 {IOCTL_CDROM_READ_Q_CHANNEL
, "IOCTL_CDROM_READ_Q_CHANNEL"},
109 {IOCTL_CDROM_GET_LAST_SESSION
, "IOCTL_CDROM_GET_LAST_SESSION"},
110 {IOCTL_CDROM_RAW_READ
, "IOCTL_CDROM_RAW_READ"},
111 {IOCTL_CDROM_DISK_TYPE
, "IOCTL_CDROM_DISK_TYPE"},
112 {IOCTL_CDROM_GET_DRIVE_GEOMETRY
, "IOCTL_CDROM_GET_DRIVE_GEOMETRY"},
113 {IOCTL_CDROM_CHECK_VERIFY
, "IOCTL_CDROM_CHECK_VERIFY"},
114 {IOCTL_CDROM_MEDIA_REMOVAL
, "IOCTL_CDROM_MEDIA_REMOVAL"},
115 {IOCTL_CDROM_EJECT_MEDIA
, "IOCTL_CDROM_EJECT_MEDIA"},
116 {IOCTL_CDROM_LOAD_MEDIA
, "IOCTL_CDROM_LOAD_MEDIA"},
117 {IOCTL_CDROM_RESERVE
, "IOCTL_CDROM_RESERVE"},
118 {IOCTL_CDROM_RELEASE
, "IOCTL_CDROM_RELEASE"},
119 {IOCTL_CDROM_FIND_NEW_DEVICES
, "IOCTL_CDROM_FIND_NEW_DEVICES"}
121 static const char *iocodex(DWORD code
)
124 static char buffer
[25];
125 for(i
=0; i
<sizeof(iocodextable
)/sizeof(struct iocodexs
); i
++)
126 if (code
==iocodextable
[i
].code
)
127 return iocodextable
[i
].codex
;
128 sprintf(buffer
, "IOCTL_CODE_%x", (int)code
);
132 WINE_DEFAULT_DEBUG_CHANNEL(cdrom
);
134 #define FRAME_OF_ADDR(a) (((int)(a)[1] * CD_SECS + (a)[2]) * CD_FRAMES + (a)[3])
135 #define FRAME_OF_MSF(a) (((int)(a).M * CD_SECS + (a).S) * CD_FRAMES + (a).F)
136 #define FRAME_OF_TOC(toc, idx) FRAME_OF_ADDR((toc).TrackData[idx - (toc).FirstTrack].Address)
137 #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;}
139 static NTSTATUS
CDROM_ReadTOC(int, CDROM_TOC
*);
140 static NTSTATUS
CDROM_GetStatusCode(int);
146 # define IDE6_MAJOR 88
149 # define IDE7_MAJOR 89
152 # ifdef CDROM_SEND_PACKET
153 /* structure for CDROM_PACKET_COMMAND ioctl */
154 /* not all Linux versions have all the fields, so we define the
155 * structure ourselves to make sure */
156 struct linux_cdrom_generic_command
158 unsigned char cmd
[CDROM_PACKET_SIZE
];
159 unsigned char *buffer
;
162 struct request_sense
*sense
;
163 unsigned char data_direction
;
168 # endif /* CDROM_SEND_PACKET */
172 /* FIXME: this is needed because we can't open simultaneously several times /dev/cdrom
173 * this should be removed when a proper device interface is implemented
175 * (WS) We need this to keep track of current position and to safely
176 * detect media changes. Besides this should provide a great speed up
182 char toc_good
; /* if false, will reread TOC from disk */
184 SUB_Q_CURRENT_POSITION CurrentPosition
;
186 static struct cdrom_cache cdrom_cache
[26];
188 /* Proposed media change function: not really needed at this time */
189 /* This is a 1 or 0 type of function */
191 static int CDROM_MediaChanged(int dev
)
195 struct cdrom_tochdr hdr
;
196 struct cdrom_tocentry entry
;
198 if (dev
< 0 || dev
>= 26)
200 if ( ioctl(cdrom_cache
[dev
].fd
, CDROMREADTOCHDR
, &hdr
) == -1 )
203 if ( memcmp(&hdr
, &cdrom_cache
[dev
].hdr
, sizeof(struct cdrom_tochdr
)) )
206 for (i
=hdr
.cdth_trk0
; i
<=hdr
.cdth_trk1
+1; i
++)
208 if (i
== hdr
.cdth_trk1
+ 1)
210 entry
.cdte_track
= CDROM_LEADOUT
;
212 entry
.cdte_track
= i
;
214 entry
.cdte_format
= CDROM_MSF
;
215 if ( ioctl(cdrom_cache
[dev
].fd
, CDROMREADTOCENTRY
, &entry
) == -1)
217 if ( memcmp(&entry
, cdrom_cache
[dev
].entry
+i
-hdr
.cdth_trk0
,
218 sizeof(struct cdrom_tocentry
)) )
225 /******************************************************************
226 * CDROM_SyncCache [internal]
228 * Read the TOC in and store it in the cdrom_cache structure.
229 * Further requests for the TOC will be copied from the cache
230 * unless certain events like disk ejection is detected, in which
231 * case the cache will be cleared, causing it to be resynced.
234 static int CDROM_SyncCache(int dev
)
238 struct cdrom_tochdr hdr
;
239 struct cdrom_tocentry entry
;
240 #elif defined(__FreeBSD__) || defined(__NetBSD__)
241 struct ioc_toc_header hdr
;
242 struct ioc_read_toc_entry entry
;
243 struct cd_toc_entry toc_buffer
;
245 CDROM_TOC
*toc
= &cdrom_cache
[dev
].toc
;
246 cdrom_cache
[dev
].toc_good
= 0;
250 io
= ioctl(cdrom_cache
[dev
].fd
, CDROMREADTOCHDR
, &hdr
);
253 WARN("(%d) -- Error occurred (%s)!\n", dev
, strerror(errno
));
257 TRACE("caching toc from=%d to=%d\n", toc
->FirstTrack
, toc
->LastTrack
);
259 toc
->FirstTrack
= hdr
.cdth_trk0
;
260 toc
->LastTrack
= hdr
.cdth_trk1
;
261 tsz
= sizeof(toc
->FirstTrack
) + sizeof(toc
->LastTrack
)
262 + sizeof(TRACK_DATA
) * (toc
->LastTrack
-toc
->FirstTrack
+2);
263 toc
->Length
[0] = tsz
>> 8;
264 toc
->Length
[1] = tsz
;
266 for (i
= toc
->FirstTrack
; i
<= toc
->LastTrack
+ 1; i
++)
268 if (i
== toc
->LastTrack
+ 1)
269 entry
.cdte_track
= CDROM_LEADOUT
;
271 entry
.cdte_track
= i
;
272 entry
.cdte_format
= CDROM_MSF
;
273 io
= ioctl(cdrom_cache
[dev
].fd
, CDROMREADTOCENTRY
, &entry
);
275 WARN("error read entry (%s)\n", strerror(errno
));
278 toc
->TrackData
[i
- toc
->FirstTrack
].Control
= entry
.cdte_ctrl
;
279 toc
->TrackData
[i
- toc
->FirstTrack
].Adr
= entry
.cdte_adr
;
280 /* marking last track with leadout value as index */
281 toc
->TrackData
[i
- toc
->FirstTrack
].TrackNumber
= entry
.cdte_track
;
282 toc
->TrackData
[i
- toc
->FirstTrack
].Address
[0] = 0;
283 toc
->TrackData
[i
- toc
->FirstTrack
].Address
[1] = entry
.cdte_addr
.msf
.minute
;
284 toc
->TrackData
[i
- toc
->FirstTrack
].Address
[2] = entry
.cdte_addr
.msf
.second
;
285 toc
->TrackData
[i
- toc
->FirstTrack
].Address
[3] = entry
.cdte_addr
.msf
.frame
;
287 cdrom_cache
[dev
].toc_good
= 1;
289 #elif defined(__FreeBSD__) || defined(__NetBSD__)
291 io
= ioctl(cdrom_cache
[dev
].fd
, CDIOREADTOCHEADER
, &hdr
);
294 WARN("(%d) -- Error occurred (%s)!\n", dev
, strerror(errno
));
297 toc
->FirstTrack
= hdr
.starting_track
;
298 toc
->LastTrack
= hdr
.ending_track
;
299 tsz
= sizeof(toc
->FirstTrack
) + sizeof(toc
->LastTrack
)
300 + sizeof(TRACK_DATA
) * (toc
->LastTrack
-toc
->FirstTrack
+2);
301 toc
->Length
[0] = tsz
>> 8;
302 toc
->Length
[1] = tsz
;
304 TRACE("caching toc from=%d to=%d\n", toc
->FirstTrack
, toc
->LastTrack
);
306 for (i
= toc
->FirstTrack
; i
<= toc
->LastTrack
+ 1; i
++)
308 if (i
== toc
->LastTrack
+ 1)
311 entry
.starting_track
= LEADOUT
;
313 entry
.starting_track
= i
;
315 memset((char *)&toc_buffer
, 0, sizeof(toc_buffer
));
316 entry
.address_format
= CD_MSF_FORMAT
;
317 entry
.data_len
= sizeof(toc_buffer
);
318 entry
.data
= &toc_buffer
;
319 io
= ioctl(cdrom_cache
[dev
].fd
, CDIOREADTOCENTRYS
, &entry
);
321 WARN("error read entry (%s)\n", strerror(errno
));
324 toc
->TrackData
[i
- toc
->FirstTrack
].Control
= toc_buffer
.control
;
325 toc
->TrackData
[i
- toc
->FirstTrack
].Adr
= toc_buffer
.addr_type
;
326 /* marking last track with leadout value as index */
327 toc
->TrackData
[i
- toc
->FirstTrack
].TrackNumber
= entry
.starting_track
;
328 toc
->TrackData
[i
- toc
->FirstTrack
].Address
[0] = 0;
329 toc
->TrackData
[i
- toc
->FirstTrack
].Address
[1] = toc_buffer
.addr
.msf
.minute
;
330 toc
->TrackData
[i
- toc
->FirstTrack
].Address
[2] = toc_buffer
.addr
.msf
.second
;
331 toc
->TrackData
[i
- toc
->FirstTrack
].Address
[3] = toc_buffer
.addr
.msf
.frame
;
333 cdrom_cache
[dev
].toc_good
= 1;
336 return STATUS_NOT_SUPPORTED
;
339 return CDROM_GetStatusCode(io
);
342 static void CDROM_ClearCacheEntry(int dev
)
344 cdrom_cache
[dev
].toc_good
= 0;
349 /******************************************************************
350 * CDROM_GetInterfaceInfo
352 * Determines the ide interface (the number after the ide), and the
353 * number of the device on that interface for ide cdroms (*port == 0).
354 * Determines the scsi information for scsi cdroms (*port == 1).
355 * Returns false if the info could not be get
357 * NOTE: this function is used in CDROM_InitRegistry and CDROM_GetAddress
359 static int CDROM_GetInterfaceInfo(int fd
, int* port
, int* iface
, int* device
,int* lun
)
364 #ifdef SG_EMULATED_HOST
365 if (ioctl(fd
, SG_EMULATED_HOST
) != -1) {
366 FIXME("not implemented for true scsi drives\n");
370 if ( fstat(fd
, &st
) == -1 || ! S_ISBLK(st
.st_mode
)) {
371 FIXME("cdrom not a block device!!!\n");
376 switch (major(st
.st_rdev
)) {
377 case IDE0_MAJOR
: *iface
= 0; break;
378 case IDE1_MAJOR
: *iface
= 1; break;
379 case IDE2_MAJOR
: *iface
= 2; break;
380 case IDE3_MAJOR
: *iface
= 3; break;
381 case IDE4_MAJOR
: *iface
= 4; break;
382 case IDE5_MAJOR
: *iface
= 5; break;
383 case IDE6_MAJOR
: *iface
= 6; break;
384 case IDE7_MAJOR
: *iface
= 7; break;
385 case SCSI_CDROM_MAJOR
: *iface
= 11; break;
387 FIXME("CD-ROM device with major ID %d not supported\n", major(st
.st_rdev
));
390 *device
= (minor(st
.st_rdev
) == 63 ? 1 : 0);
393 #elif defined(__NetBSD__)
395 struct scsi_addr addr
;
396 if (ioctl(fd
, SCIOCIDENTIFY
, &addr
) != -1) {
398 case TYPE_SCSI
: *port
= 1;
399 *iface
= addr
.addr
.scsi
.scbus
;
400 *device
= addr
.addr
.scsi
.target
;
401 *lun
= addr
.addr
.scsi
.lun
;
403 case TYPE_ATAPI
: *port
= 0;
404 *iface
= addr
.addr
.atapi
.atbus
;
405 *device
= addr
.addr
.atapi
.drive
;
413 #elif defined(__FreeBSD__)
414 FIXME("not implemented for BSD\n");
417 FIXME("not implemented for nonlinux\n");
423 /******************************************************************
426 * Initializes registry to contain scsi info about the cdrom in NT.
427 * All devices (even not real scsi ones) have this info in NT.
428 * TODO: for now it only works for non scsi devices
429 * NOTE: programs usually read these registry entries after sending the
430 * IOCTL_SCSI_GET_ADDRESS ioctl to the cdrom
432 void CDROM_InitRegistry(int fd
)
434 int portnum
, busid
, targetid
, lun
;
435 OBJECT_ATTRIBUTES attr
;
436 UNICODE_STRING nameW
;
448 attr
.Length
= sizeof(attr
);
449 attr
.RootDirectory
= 0;
450 attr
.ObjectName
= &nameW
;
452 attr
.SecurityDescriptor
= NULL
;
453 attr
.SecurityQualityOfService
= NULL
;
455 if ( ! CDROM_GetInterfaceInfo(fd
, &portnum
, &busid
, &targetid
, &lun
))
458 /* Ensure there is Scsi key */
459 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, "Machine\\HARDWARE\\DEVICEMAP\\Scsi" ) ||
460 NtCreateKey( &scsiKey
, KEY_ALL_ACCESS
, &attr
, 0,
461 NULL
, REG_OPTION_VOLATILE
, &disp
))
463 ERR("Cannot create DEVICEMAP\\Scsi registry key\n" );
466 RtlFreeUnicodeString( &nameW
);
468 snprintf(buffer
,sizeof(buffer
),"Scsi Port %d",portnum
);
469 attr
.RootDirectory
= scsiKey
;
470 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, buffer
) ||
471 NtCreateKey( &portKey
, KEY_ALL_ACCESS
, &attr
, 0,
472 NULL
, REG_OPTION_VOLATILE
, &disp
))
474 ERR("Cannot create DEVICEMAP\\Scsi Port registry key\n" );
477 RtlFreeUnicodeString( &nameW
);
479 RtlCreateUnicodeStringFromAsciiz( &nameW
, "Driver" );
481 RtlMultiByteToUnicodeN( dataW
, 50, &lenW
, data
, strlen(data
));
482 NtSetValueKey( portKey
, &nameW
, 0, REG_SZ
, (BYTE
*)dataW
, lenW
);
483 RtlFreeUnicodeString( &nameW
);
485 RtlCreateUnicodeStringFromAsciiz( &nameW
, "FirstBusTimeScanInMs" );
486 NtSetValueKey( portKey
,&nameW
, 0, REG_DWORD
, (BYTE
*)&value
, sizeof(DWORD
));
487 RtlFreeUnicodeString( &nameW
);
492 if (ioctl(fd
,HDIO_GET_DMA
, &dma
) != -1) {
494 TRACE("setting dma to %lx\n", value
);
498 RtlCreateUnicodeStringFromAsciiz( &nameW
, "DMAEnabled" );
499 NtSetValueKey( portKey
,&nameW
, 0, REG_DWORD
, (BYTE
*)&value
, sizeof(DWORD
));
500 RtlFreeUnicodeString( &nameW
);
502 snprintf(buffer
,40,"Scsi Bus %d", busid
);
503 attr
.RootDirectory
= portKey
;
504 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, buffer
) ||
505 NtCreateKey( &busKey
, KEY_ALL_ACCESS
, &attr
, 0,
506 NULL
, REG_OPTION_VOLATILE
, &disp
))
508 ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus registry key\n" );
511 RtlFreeUnicodeString( &nameW
);
513 attr
.RootDirectory
= busKey
;
514 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, "Initiator Id 255" ) ||
515 NtCreateKey( &targetKey
, KEY_ALL_ACCESS
, &attr
, 0,
516 NULL
, REG_OPTION_VOLATILE
, &disp
))
518 ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus\\Initiator Id 255 registry key\n" );
521 RtlFreeUnicodeString( &nameW
);
522 NtClose( targetKey
);
524 snprintf(buffer
,40,"Target Id %d", targetid
);
525 attr
.RootDirectory
= busKey
;
526 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, buffer
) ||
527 NtCreateKey( &targetKey
, KEY_ALL_ACCESS
, &attr
, 0,
528 NULL
, REG_OPTION_VOLATILE
, &disp
))
530 ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus 0\\Target Id registry key\n" );
533 RtlFreeUnicodeString( &nameW
);
535 RtlCreateUnicodeStringFromAsciiz( &nameW
, "Type" );
536 data
= "CdRomPeripheral";
537 RtlMultiByteToUnicodeN( dataW
, 50, &lenW
, data
, strlen(data
));
538 NtSetValueKey( targetKey
, &nameW
, 0, REG_SZ
, (BYTE
*)dataW
, lenW
);
539 RtlFreeUnicodeString( &nameW
);
540 /* FIXME - maybe read the real identifier?? */
541 RtlCreateUnicodeStringFromAsciiz( &nameW
, "Identifier" );
543 RtlMultiByteToUnicodeN( dataW
, 50, &lenW
, data
, strlen(data
));
544 NtSetValueKey( targetKey
, &nameW
, 0, REG_SZ
, (BYTE
*)dataW
, lenW
);
545 RtlFreeUnicodeString( &nameW
);
546 /* FIXME - we always use Cdrom0 - do not know about the nt behaviour */
547 RtlCreateUnicodeStringFromAsciiz( &nameW
, "DeviceName" );
549 RtlMultiByteToUnicodeN( dataW
, 50, &lenW
, data
, strlen(data
));
550 NtSetValueKey( targetKey
, &nameW
, 0, REG_SZ
, (BYTE
*)dataW
, lenW
);
551 RtlFreeUnicodeString( &nameW
);
553 NtClose( targetKey
);
560 /******************************************************************
564 static NTSTATUS
CDROM_Open(HANDLE hDevice
, DWORD clientID
, int* dev
)
566 *dev
= LOWORD(clientID
);
568 if (*dev
>= 26) return STATUS_NO_SUCH_DEVICE
;
570 if (!cdrom_cache
[*dev
].count
)
575 strcpy(root
, "A:\\");
577 if (GetDriveTypeA(root
) != DRIVE_CDROM
) return STATUS_NO_SUCH_DEVICE
;
578 if (!(device
= DRIVE_GetDevice(*dev
))) return STATUS_NO_SUCH_DEVICE
;
579 cdrom_cache
[*dev
].fd
= open(device
, O_RDONLY
|O_NONBLOCK
);
580 if (cdrom_cache
[*dev
].fd
== -1)
582 FIXME("Can't open configured CD-ROM drive at %s (device %s): %s\n",
583 root
, DRIVE_GetDevice(*dev
), strerror(errno
));
584 return STATUS_NO_SUCH_DEVICE
;
587 cdrom_cache
[*dev
].count
++;
588 TRACE("%d, %d, %d\n", *dev
, cdrom_cache
[*dev
].fd
, cdrom_cache
[*dev
].count
);
589 return STATUS_SUCCESS
;
592 /******************************************************************
597 static void CDROM_Close(DWORD clientID
)
599 int dev
= LOWORD(clientID
);
601 if (dev
>= 26 /*|| fd != cdrom_cache[dev].fd*/) FIXME("how come\n");
602 if (--cdrom_cache
[dev
].count
== 0)
604 close(cdrom_cache
[dev
].fd
);
605 cdrom_cache
[dev
].fd
= -1;
609 /******************************************************************
610 * CDROM_GetStatusCode
614 static NTSTATUS
CDROM_GetStatusCode(int io
)
616 if (io
== 0) return STATUS_SUCCESS
;
623 return STATUS_NO_MEDIA_IN_DEVICE
;
625 return STATUS_ACCESS_DENIED
;
627 return STATUS_INVALID_PARAMETER
;
628 /* case EBADF: Bad file descriptor */
630 return STATUS_NOT_SUPPORTED
;
632 FIXME("Unmapped error code %d: %s\n", errno
, strerror(errno
));
633 return STATUS_IO_DEVICE_ERROR
;
636 /******************************************************************
640 static NTSTATUS
CDROM_GetControl(int dev
, CDROM_AUDIO_CONTROL
* cac
)
642 cac
->LbaFormat
= 0; /* FIXME */
643 cac
->LogicalBlocksPerSecond
= 1; /* FIXME */
644 return STATUS_NOT_SUPPORTED
;
647 /******************************************************************
648 * CDROM_GetDeviceNumber
651 static NTSTATUS
CDROM_GetDeviceNumber(int dev
, STORAGE_DEVICE_NUMBER
* devnum
)
653 return STATUS_NOT_SUPPORTED
;
656 /******************************************************************
657 * CDROM_GetDriveGeometry
660 static NTSTATUS
CDROM_GetDriveGeometry(int dev
, DISK_GEOMETRY
* dg
)
666 if ((ret
= CDROM_ReadTOC(dev
, &toc
)) != 0) return ret
;
668 fsize
= FRAME_OF_TOC(toc
, toc
.LastTrack
+1)
669 - FRAME_OF_TOC(toc
, 1); /* Total size in frames */
671 dg
->Cylinders
.s
.LowPart
= fsize
/ (64 * 32);
672 dg
->Cylinders
.s
.HighPart
= 0;
673 dg
->MediaType
= RemovableMedia
;
674 dg
->TracksPerCylinder
= 64;
675 dg
->SectorsPerTrack
= 32;
676 dg
->BytesPerSector
= 2048;
680 /**************************************************************************
681 * CDROM_Reset [internal]
683 static NTSTATUS
CDROM_ResetAudio(int dev
)
686 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDROMRESET
));
687 #elif defined(__FreeBSD__) || defined(__NetBSD__)
688 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDIOCRESET
, NULL
));
690 return STATUS_NOT_SUPPORTED
;
694 /******************************************************************
699 static NTSTATUS
CDROM_SetTray(int dev
, BOOL doEject
)
702 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, doEject
? CDROMEJECT
: CDROMCLOSETRAY
));
703 #elif defined(__FreeBSD__) || defined(__NetBSD__)
704 return CDROM_GetStatusCode((ioctl(cdrom_cache
[dev
].fd
, CDIOCALLOW
, NULL
)) ||
705 (ioctl(cdrom_cache
[dev
].fd
, doEject
? CDIOCEJECT
: CDIOCCLOSE
, NULL
)) ||
706 (ioctl(cdrom_cache
[dev
].fd
, CDIOCPREVENT
, NULL
)));
708 return STATUS_NOT_SUPPORTED
;
712 /******************************************************************
713 * CDROM_ControlEjection
717 static NTSTATUS
CDROM_ControlEjection(int dev
, const PREVENT_MEDIA_REMOVAL
* rmv
)
720 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDROM_LOCKDOOR
, rmv
->PreventMediaRemoval
));
721 #elif defined(__FreeBSD__) || defined(__NetBSD__)
722 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, (rmv
->PreventMediaRemoval
) ? CDIOCPREVENT
: CDIOCALLOW
, NULL
));
724 return STATUS_NOT_SUPPORTED
;
728 /******************************************************************
733 static NTSTATUS
CDROM_ReadTOC(int dev
, CDROM_TOC
* toc
)
735 NTSTATUS ret
= STATUS_NOT_SUPPORTED
;
737 if (dev
< 0 || dev
>= 26)
738 return STATUS_INVALID_PARAMETER
;
739 if ( !cdrom_cache
[dev
].toc_good
) {
740 ret
= CDROM_SyncCache(dev
);
744 *toc
= cdrom_cache
[dev
].toc
;
745 return STATUS_SUCCESS
;
748 /******************************************************************
753 static NTSTATUS
CDROM_GetDiskData(int dev
, CDROM_DISK_DATA
* data
)
759 if ((ret
= CDROM_ReadTOC(dev
, &toc
)) != 0) return ret
;
761 for (i
= toc
.FirstTrack
; i
<= toc
.LastTrack
; i
++) {
762 if (toc
.TrackData
[i
-toc
.FirstTrack
].Control
& 0x04)
763 data
->DiskData
|= CDROM_DISK_DATA_TRACK
;
765 data
->DiskData
|= CDROM_DISK_AUDIO_TRACK
;
767 return STATUS_SUCCESS
;
770 /******************************************************************
775 static NTSTATUS
CDROM_ReadQChannel(int dev
, const CDROM_SUB_Q_DATA_FORMAT
* fmt
,
776 SUB_Q_CHANNEL_DATA
* data
)
778 NTSTATUS ret
= STATUS_NOT_SUPPORTED
;
781 SUB_Q_HEADER
* hdr
= (SUB_Q_HEADER
*)data
;
783 struct cdrom_subchnl sc
;
784 sc
.cdsc_format
= CDROM_MSF
;
786 io
= ioctl(cdrom_cache
[dev
].fd
, CDROMSUBCHNL
, &sc
);
789 TRACE("opened or no_media (%s)!\n", strerror(errno
));
790 hdr
->AudioStatus
= AUDIO_STATUS_NO_STATUS
;
791 CDROM_ClearCacheEntry(dev
);
795 hdr
->AudioStatus
= AUDIO_STATUS_NOT_SUPPORTED
;
797 switch (sc
.cdsc_audiostatus
) {
798 case CDROM_AUDIO_INVALID
:
799 CDROM_ClearCacheEntry(dev
);
800 hdr
->AudioStatus
= AUDIO_STATUS_NOT_SUPPORTED
;
802 case CDROM_AUDIO_NO_STATUS
:
803 CDROM_ClearCacheEntry(dev
);
804 hdr
->AudioStatus
= AUDIO_STATUS_NO_STATUS
;
806 case CDROM_AUDIO_PLAY
:
807 hdr
->AudioStatus
= AUDIO_STATUS_IN_PROGRESS
;
809 case CDROM_AUDIO_PAUSED
:
810 hdr
->AudioStatus
= AUDIO_STATUS_PAUSED
;
812 case CDROM_AUDIO_COMPLETED
:
813 hdr
->AudioStatus
= AUDIO_STATUS_PLAY_COMPLETE
;
815 case CDROM_AUDIO_ERROR
:
816 hdr
->AudioStatus
= AUDIO_STATUS_PLAY_ERROR
;
819 TRACE("status=%02X !\n", sc
.cdsc_audiostatus
);
824 case IOCTL_CDROM_CURRENT_POSITION
:
825 size
= sizeof(SUB_Q_CURRENT_POSITION
);
826 if (hdr
->AudioStatus
==AUDIO_STATUS_IN_PROGRESS
) {
827 data
->CurrentPosition
.FormatCode
= IOCTL_CDROM_CURRENT_POSITION
;
828 data
->CurrentPosition
.Control
= sc
.cdsc_ctrl
;
829 data
->CurrentPosition
.ADR
= sc
.cdsc_adr
;
830 data
->CurrentPosition
.TrackNumber
= sc
.cdsc_trk
;
831 data
->CurrentPosition
.IndexNumber
= sc
.cdsc_ind
;
833 data
->CurrentPosition
.AbsoluteAddress
[0] = 0;
834 data
->CurrentPosition
.AbsoluteAddress
[1] = sc
.cdsc_absaddr
.msf
.minute
;
835 data
->CurrentPosition
.AbsoluteAddress
[2] = sc
.cdsc_absaddr
.msf
.second
;
836 data
->CurrentPosition
.AbsoluteAddress
[3] = sc
.cdsc_absaddr
.msf
.frame
;
838 data
->CurrentPosition
.TrackRelativeAddress
[0] = 0;
839 data
->CurrentPosition
.TrackRelativeAddress
[1] = sc
.cdsc_reladdr
.msf
.minute
;
840 data
->CurrentPosition
.TrackRelativeAddress
[2] = sc
.cdsc_reladdr
.msf
.second
;
841 data
->CurrentPosition
.TrackRelativeAddress
[3] = sc
.cdsc_reladdr
.msf
.frame
;
843 cdrom_cache
[dev
].CurrentPosition
= data
->CurrentPosition
;
845 else /* not playing */
847 cdrom_cache
[dev
].CurrentPosition
.Header
= *hdr
; /* Preserve header info */
848 data
->CurrentPosition
= cdrom_cache
[dev
].CurrentPosition
;
851 case IOCTL_CDROM_MEDIA_CATALOG
:
852 size
= sizeof(SUB_Q_MEDIA_CATALOG_NUMBER
);
853 data
->MediaCatalog
.FormatCode
= IOCTL_CDROM_MEDIA_CATALOG
;
855 struct cdrom_mcn mcn
;
856 if ((io
= ioctl(cdrom_cache
[dev
].fd
, CDROM_GET_MCN
, &mcn
)) == -1) goto end
;
858 data
->MediaCatalog
.FormatCode
= IOCTL_CDROM_MEDIA_CATALOG
;
859 data
->MediaCatalog
.Mcval
= 0; /* FIXME */
860 memcpy(data
->MediaCatalog
.MediaCatalog
, mcn
.medium_catalog_number
, 14);
861 data
->MediaCatalog
.MediaCatalog
[14] = 0;
864 case IOCTL_CDROM_TRACK_ISRC
:
865 size
= sizeof(SUB_Q_CURRENT_POSITION
);
866 FIXME("TrackIsrc: NIY on linux\n");
867 data
->TrackIsrc
.FormatCode
= IOCTL_CDROM_TRACK_ISRC
;
868 data
->TrackIsrc
.Tcval
= 0;
874 ret
= CDROM_GetStatusCode(io
);
875 #elif defined(__FreeBSD__) || defined(__NetBSD__)
877 SUB_Q_HEADER
* hdr
= (SUB_Q_HEADER
*)data
;
879 struct ioc_read_subchannel read_sc
;
880 struct cd_sub_channel_info sc
;
882 read_sc
.address_format
= CD_MSF_FORMAT
;
884 read_sc
.data_len
= sizeof(sc
);
888 case IOCTL_CDROM_CURRENT_POSITION
:
889 read_sc
.data_format
= CD_CURRENT_POSITION
;
891 case IOCTL_CDROM_MEDIA_CATALOG
:
892 read_sc
.data_format
= CD_MEDIA_CATALOG
;
894 case IOCTL_CDROM_TRACK_ISRC
:
895 read_sc
.data_format
= CD_TRACK_INFO
;
896 sc
.what
.track_info
.track_number
= data
->TrackIsrc
.Track
;
899 io
= ioctl(cdrom_cache
[dev
].fd
, CDIOCREADSUBCHANNEL
, &read_sc
);
902 TRACE("opened or no_media (%s)!\n", strerror(errno
));
903 CDROM_ClearCacheEntry(dev
);
904 hdr
->AudioStatus
= AUDIO_STATUS_NO_STATUS
;
908 hdr
->AudioStatus
= AUDIO_STATUS_NOT_SUPPORTED
;
910 switch (sc
.header
.audio_status
) {
911 case CD_AS_AUDIO_INVALID
:
912 CDROM_ClearCacheEntry(dev
);
913 hdr
->AudioStatus
= AUDIO_STATUS_NOT_SUPPORTED
;
915 case CD_AS_NO_STATUS
:
916 CDROM_ClearCacheEntry(dev
);
917 hdr
->AudioStatus
= AUDIO_STATUS_NO_STATUS
;
919 case CD_AS_PLAY_IN_PROGRESS
:
920 hdr
->AudioStatus
= AUDIO_STATUS_IN_PROGRESS
;
922 case CD_AS_PLAY_PAUSED
:
923 hdr
->AudioStatus
= AUDIO_STATUS_PAUSED
;
925 case CD_AS_PLAY_COMPLETED
:
926 hdr
->AudioStatus
= AUDIO_STATUS_PLAY_COMPLETE
;
928 case CD_AS_PLAY_ERROR
:
929 hdr
->AudioStatus
= AUDIO_STATUS_PLAY_ERROR
;
932 TRACE("status=%02X !\n", sc
.header
.audio_status
);
936 case IOCTL_CDROM_CURRENT_POSITION
:
937 size
= sizeof(SUB_Q_CURRENT_POSITION
);
938 if (hdr
->AudioStatus
==AUDIO_STATUS_IN_PROGRESS
) {
939 data
->CurrentPosition
.FormatCode
= IOCTL_CDROM_CURRENT_POSITION
;
940 data
->CurrentPosition
.Control
= sc
.what
.position
.control
;
941 data
->CurrentPosition
.ADR
= sc
.what
.position
.addr_type
;
942 data
->CurrentPosition
.TrackNumber
= sc
.what
.position
.track_number
;
943 data
->CurrentPosition
.IndexNumber
= sc
.what
.position
.index_number
;
945 data
->CurrentPosition
.AbsoluteAddress
[0] = 0;
946 data
->CurrentPosition
.AbsoluteAddress
[1] = sc
.what
.position
.absaddr
.msf
.minute
;
947 data
->CurrentPosition
.AbsoluteAddress
[2] = sc
.what
.position
.absaddr
.msf
.second
;
948 data
->CurrentPosition
.AbsoluteAddress
[3] = sc
.what
.position
.absaddr
.msf
.frame
;
949 data
->CurrentPosition
.TrackRelativeAddress
[0] = 0;
950 data
->CurrentPosition
.TrackRelativeAddress
[1] = sc
.what
.position
.reladdr
.msf
.minute
;
951 data
->CurrentPosition
.TrackRelativeAddress
[2] = sc
.what
.position
.reladdr
.msf
.second
;
952 data
->CurrentPosition
.TrackRelativeAddress
[3] = sc
.what
.position
.reladdr
.msf
.frame
;
953 cdrom_cache
[dev
].CurrentPosition
= data
->CurrentPosition
;
955 else { /* not playing */
956 cdrom_cache
[dev
].CurrentPosition
.Header
= *hdr
; /* Preserve header info */
957 data
->CurrentPosition
= cdrom_cache
[dev
].CurrentPosition
;
960 case IOCTL_CDROM_MEDIA_CATALOG
:
961 size
= sizeof(SUB_Q_MEDIA_CATALOG_NUMBER
);
962 data
->MediaCatalog
.FormatCode
= IOCTL_CDROM_MEDIA_CATALOG
;
963 data
->MediaCatalog
.Mcval
= sc
.what
.media_catalog
.mc_valid
;
964 memcpy(data
->MediaCatalog
.MediaCatalog
, sc
.what
.media_catalog
.mc_number
, 15);
966 case IOCTL_CDROM_TRACK_ISRC
:
967 size
= sizeof(SUB_Q_CURRENT_POSITION
);
968 data
->TrackIsrc
.FormatCode
= IOCTL_CDROM_TRACK_ISRC
;
969 data
->TrackIsrc
.Tcval
= sc
.what
.track_info
.ti_valid
;
970 memcpy(data
->TrackIsrc
.TrackIsrc
, sc
.what
.track_info
.ti_number
, 15);
975 ret
= CDROM_GetStatusCode(io
);
980 /******************************************************************
985 static NTSTATUS
CDROM_Verify(int dev
)
987 /* quick implementation */
988 CDROM_SUB_Q_DATA_FORMAT fmt
;
989 SUB_Q_CHANNEL_DATA data
;
991 fmt
.Format
= IOCTL_CDROM_CURRENT_POSITION
;
992 return CDROM_ReadQChannel(dev
, &fmt
, &data
) ? 1 : 0;
995 /******************************************************************
1000 static NTSTATUS
CDROM_PlayAudioMSF(int dev
, const CDROM_PLAY_AUDIO_MSF
* audio_msf
)
1002 NTSTATUS ret
= STATUS_NOT_SUPPORTED
;
1004 struct cdrom_msf msf
;
1007 msf
.cdmsf_min0
= audio_msf
->StartingM
;
1008 msf
.cdmsf_sec0
= audio_msf
->StartingS
;
1009 msf
.cdmsf_frame0
= audio_msf
->StartingF
;
1010 msf
.cdmsf_min1
= audio_msf
->EndingM
;
1011 msf
.cdmsf_sec1
= audio_msf
->EndingS
;
1012 msf
.cdmsf_frame1
= audio_msf
->EndingF
;
1014 io
= ioctl(cdrom_cache
[dev
].fd
, CDROMSTART
);
1017 WARN("motor doesn't start !\n");
1020 io
= ioctl(cdrom_cache
[dev
].fd
, CDROMPLAYMSF
, &msf
);
1023 WARN("device doesn't play !\n");
1026 TRACE("msf = %d:%d:%d %d:%d:%d\n",
1027 msf
.cdmsf_min0
, msf
.cdmsf_sec0
, msf
.cdmsf_frame0
,
1028 msf
.cdmsf_min1
, msf
.cdmsf_sec1
, msf
.cdmsf_frame1
);
1030 ret
= CDROM_GetStatusCode(io
);
1031 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1032 struct ioc_play_msf msf
;
1035 msf
.start_m
= audio_msf
->StartingM
;
1036 msf
.start_s
= audio_msf
->StartingS
;
1037 msf
.start_f
= audio_msf
->StartingF
;
1038 msf
.end_m
= audio_msf
->EndingM
;
1039 msf
.end_s
= audio_msf
->EndingS
;
1040 msf
.end_f
= audio_msf
->EndingF
;
1042 io
= ioctl(cdrom_cache
[dev
].fd
, CDIOCSTART
, NULL
);
1045 WARN("motor doesn't start !\n");
1048 io
= ioctl(cdrom_cache
[dev
].fd
, CDIOCPLAYMSF
, &msf
);
1051 WARN("device doesn't play !\n");
1054 TRACE("msf = %d:%d:%d %d:%d:%d\n",
1055 msf
.start_m
, msf
.start_s
, msf
.start_f
,
1056 msf
.end_m
, msf
.end_s
, msf
.end_f
);
1058 ret
= CDROM_GetStatusCode(io
);
1063 /******************************************************************
1064 * CDROM_SeekAudioMSF
1068 static NTSTATUS
CDROM_SeekAudioMSF(int dev
, const CDROM_SEEK_AUDIO_MSF
* audio_msf
)
1072 SUB_Q_CURRENT_POSITION
*cp
;
1074 struct cdrom_msf0 msf
;
1075 struct cdrom_subchnl sc
;
1076 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1077 struct ioc_play_msf msf
;
1078 struct ioc_read_subchannel read_sc
;
1079 struct cd_sub_channel_info sc
;
1083 /* Use the information on the TOC to compute the new current
1084 * position, which is shadowed on the cache. [Portable]. */
1085 frame
= FRAME_OF_MSF(*audio_msf
);
1086 cp
= &cdrom_cache
[dev
].CurrentPosition
;
1087 if ((io
= CDROM_ReadTOC(dev
, &toc
)) != 0) return io
;
1089 for(i
=toc
.FirstTrack
;i
<=toc
.LastTrack
+1;i
++)
1090 if (FRAME_OF_TOC(toc
,i
)>frame
) break;
1091 if (i
<= toc
.FirstTrack
|| i
> toc
.LastTrack
+1)
1092 return STATUS_INVALID_PARAMETER
;
1094 cp
->FormatCode
= IOCTL_CDROM_CURRENT_POSITION
;
1095 cp
->Control
= toc
.TrackData
[i
-toc
.FirstTrack
].Control
;
1096 cp
->ADR
= toc
.TrackData
[i
-toc
.FirstTrack
].Adr
;
1097 cp
->TrackNumber
= toc
.TrackData
[i
-toc
.FirstTrack
].TrackNumber
;
1098 cp
->IndexNumber
= 0; /* FIXME: where do they keep these? */
1099 cp
->AbsoluteAddress
[0] = 0;
1100 cp
->AbsoluteAddress
[1] = toc
.TrackData
[i
-toc
.FirstTrack
].Address
[1];
1101 cp
->AbsoluteAddress
[2] = toc
.TrackData
[i
-toc
.FirstTrack
].Address
[2];
1102 cp
->AbsoluteAddress
[3] = toc
.TrackData
[i
-toc
.FirstTrack
].Address
[3];
1103 frame
-= FRAME_OF_TOC(toc
,i
);
1104 cp
->TrackRelativeAddress
[0] = 0;
1105 MSF_OF_FRAME(cp
->TrackRelativeAddress
[1], frame
);
1107 /* If playing, then issue a seek command, otherwise do nothing */
1109 sc
.cdsc_format
= CDROM_MSF
;
1111 io
= ioctl(cdrom_cache
[dev
].fd
, CDROMSUBCHNL
, &sc
);
1114 TRACE("opened or no_media (%s)!\n", strerror(errno
));
1115 CDROM_ClearCacheEntry(dev
);
1116 return CDROM_GetStatusCode(io
);
1118 if (sc
.cdsc_audiostatus
==CDROM_AUDIO_PLAY
)
1120 msf
.minute
= audio_msf
->M
;
1121 msf
.second
= audio_msf
->S
;
1122 msf
.frame
= audio_msf
->F
;
1123 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDROMSEEK
, &msf
));
1125 return STATUS_SUCCESS
;
1126 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1127 read_sc
.address_format
= CD_MSF_FORMAT
;
1129 read_sc
.data_len
= sizeof(sc
);
1131 read_sc
.data_format
= CD_CURRENT_POSITION
;
1133 io
= ioctl(cdrom_cache
[dev
].fd
, CDIOCREADSUBCHANNEL
, &read_sc
);
1136 TRACE("opened or no_media (%s)!\n", strerror(errno
));
1137 CDROM_ClearCacheEntry(dev
);
1138 return CDROM_GetStatusCode(io
);
1140 if (sc
.header
.audio_status
==CD_AS_PLAY_IN_PROGRESS
)
1143 msf
.start_m
= audio_msf
->M
;
1144 msf
.start_s
= audio_msf
->S
;
1145 msf
.start_f
= audio_msf
->F
;
1146 final_frame
= FRAME_OF_TOC(toc
,toc
.LastTrack
+1)-1;
1147 MSF_OF_FRAME(msf
.end_m
, final_frame
);
1149 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDIOCPLAYMSF
, &msf
));
1151 return STATUS_SUCCESS
;
1153 return STATUS_NOT_SUPPORTED
;
1157 /******************************************************************
1162 static NTSTATUS
CDROM_PauseAudio(int dev
)
1165 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDROMPAUSE
));
1166 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1167 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDIOCPAUSE
, NULL
));
1169 return STATUS_NOT_SUPPORTED
;
1173 /******************************************************************
1178 static NTSTATUS
CDROM_ResumeAudio(int dev
)
1181 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDROMRESUME
));
1182 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1183 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDIOCRESUME
, NULL
));
1185 return STATUS_NOT_SUPPORTED
;
1189 /******************************************************************
1194 static NTSTATUS
CDROM_StopAudio(int dev
)
1197 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDROMSTOP
));
1198 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1199 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDIOCSTOP
, NULL
));
1201 return STATUS_NOT_SUPPORTED
;
1205 /******************************************************************
1210 static NTSTATUS
CDROM_GetVolume(int dev
, VOLUME_CONTROL
* vc
)
1213 struct cdrom_volctrl volc
;
1216 io
= ioctl(cdrom_cache
[dev
].fd
, CDROMVOLREAD
, &volc
);
1219 vc
->PortVolume
[0] = volc
.channel0
;
1220 vc
->PortVolume
[1] = volc
.channel1
;
1221 vc
->PortVolume
[2] = volc
.channel2
;
1222 vc
->PortVolume
[3] = volc
.channel3
;
1224 return CDROM_GetStatusCode(io
);
1225 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1226 struct ioc_vol volc
;
1229 io
= ioctl(cdrom_cache
[dev
].fd
, CDIOCGETVOL
, &volc
);
1232 vc
->PortVolume
[0] = volc
.vol
[0];
1233 vc
->PortVolume
[1] = volc
.vol
[1];
1234 vc
->PortVolume
[2] = volc
.vol
[2];
1235 vc
->PortVolume
[3] = volc
.vol
[3];
1237 return CDROM_GetStatusCode(io
);
1239 return STATUS_NOT_SUPPORTED
;
1243 /******************************************************************
1248 static NTSTATUS
CDROM_SetVolume(int dev
, const VOLUME_CONTROL
* vc
)
1251 struct cdrom_volctrl volc
;
1253 volc
.channel0
= vc
->PortVolume
[0];
1254 volc
.channel1
= vc
->PortVolume
[1];
1255 volc
.channel2
= vc
->PortVolume
[2];
1256 volc
.channel3
= vc
->PortVolume
[3];
1258 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDROMVOLCTRL
, &volc
));
1259 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1260 struct ioc_vol volc
;
1262 volc
.vol
[0] = vc
->PortVolume
[0];
1263 volc
.vol
[1] = vc
->PortVolume
[1];
1264 volc
.vol
[2] = vc
->PortVolume
[2];
1265 volc
.vol
[3] = vc
->PortVolume
[3];
1267 return CDROM_GetStatusCode(ioctl(cdrom_cache
[dev
].fd
, CDIOCSETVOL
, &volc
));
1269 return STATUS_NOT_SUPPORTED
;
1273 /******************************************************************
1278 static NTSTATUS
CDROM_RawRead(int dev
, const RAW_READ_INFO
* raw
, void* buffer
, DWORD len
, DWORD
* sz
)
1280 int ret
= STATUS_NOT_SUPPORTED
;
1284 switch (raw
->TrackMode
)
1286 case YellowMode2
: sectSize
= 2336; break;
1287 case XAForm2
: sectSize
= 2328; break;
1288 case CDDA
: sectSize
= 2352; break;
1289 default: return STATUS_INVALID_PARAMETER
;
1291 if (len
< raw
->SectorCount
* sectSize
) return STATUS_BUFFER_TOO_SMALL
;
1292 /* strangely enough, it seems that sector offsets are always indicated with a size of 2048,
1293 * even if a larger size if read...
1297 struct cdrom_read cdr
;
1298 struct cdrom_read_audio cdra
;
1300 switch (raw
->TrackMode
)
1303 if (raw
->DiskOffset
.s
.HighPart
) FIXME("Unsupported value\n");
1304 cdr
.cdread_lba
= raw
->DiskOffset
.s
.LowPart
; /* FIXME ? */
1305 cdr
.cdread_bufaddr
= buffer
;
1306 cdr
.cdread_buflen
= raw
->SectorCount
* sectSize
;
1307 io
= ioctl(cdrom_cache
[dev
].fd
, CDROMREADMODE2
, &cdr
);
1310 FIXME("XAForm2: NIY\n");
1313 /* FIXME: the output doesn't seem 100% correct... in fact output is shifted
1314 * between by NT2K box and this... should check on the same drive...
1315 * otherwise, I fear a 2352/2368 mismatch somewhere in one of the drivers
1317 * Anyway, that's not critical at all. We're talking of 16/32 bytes, we're
1318 * talking of 0.2 ms of sound
1320 /* 2048 = 2 ** 11 */
1321 if (raw
->DiskOffset
.s
.HighPart
& ~2047) FIXME("Unsupported value\n");
1322 cdra
.addr
.lba
= ((raw
->DiskOffset
.s
.LowPart
>> 11) |
1323 (raw
->DiskOffset
.s
.HighPart
<< (32 - 11))) - 1;
1324 FIXME("reading at %u\n", cdra
.addr
.lba
);
1325 cdra
.addr_format
= CDROM_LBA
;
1326 cdra
.nframes
= raw
->SectorCount
;
1328 io
= ioctl(cdrom_cache
[dev
].fd
, CDROMREADAUDIO
, &cdra
);
1331 FIXME("NIY: %d\n", raw
->TrackMode
);
1335 #elif defined(__FreeBSD__)
1337 struct ioc_read_audio ira
;
1339 switch (raw
->TrackMode
)
1342 FIXME("YellowMode2: NIY\n");
1345 FIXME("XAForm2: NIY\n");
1348 /* 2048 = 2 ** 11 */
1349 if (raw
->DiskOffset
.s
.HighPart
& ~2047) FIXME("Unsupported value\n");
1350 ira
.address
.lba
= ((raw
->DiskOffset
.s
.LowPart
>> 11) |
1351 raw
->DiskOffset
.s
.HighPart
<< (32 - 11)) - 1;
1352 ira
.address_format
= CD_LBA_FORMAT
;
1353 ira
.nframes
= raw
->SectorCount
;
1354 ira
.buffer
= buffer
;
1355 io
= ioctl(cdrom_cache
[dev
].fd
, CDIOCREADAUDIO
, &ira
);
1359 #elif defined(__NetBSD__)
1361 switch (raw
->TrackMode
)
1364 FIXME("YellowMode2: NIY\n");
1367 FIXME("XAForm2: NIY\n");
1370 FIXME("CDDA: NIY\n");
1375 *sz
= sectSize
* raw
->SectorCount
;
1376 ret
= CDROM_GetStatusCode(io
);
1380 /******************************************************************
1381 * CDROM_ScsiPassThroughDirect
1385 static NTSTATUS
CDROM_ScsiPassThroughDirect(int dev
, PSCSI_PASS_THROUGH_DIRECT pPacket
)
1387 int ret
= STATUS_NOT_SUPPORTED
;
1388 #if defined(linux) && defined(CDROM_SEND_PACKET)
1389 struct linux_cdrom_generic_command cmd
;
1390 struct request_sense sense
;
1393 if (pPacket
->Length
< sizeof(SCSI_PASS_THROUGH_DIRECT
))
1394 return STATUS_BUFFER_TOO_SMALL
;
1396 if (pPacket
->CdbLength
> 12)
1397 return STATUS_INVALID_PARAMETER
;
1399 if (pPacket
->SenseInfoLength
> sizeof(sense
))
1400 return STATUS_INVALID_PARAMETER
;
1402 memset(&cmd
, 0, sizeof(cmd
));
1403 memset(&sense
, 0, sizeof(sense
));
1405 memcpy(&(cmd
.cmd
), &(pPacket
->Cdb
), pPacket
->CdbLength
);
1407 cmd
.buffer
= pPacket
->DataBuffer
;
1408 cmd
.buflen
= pPacket
->DataTransferLength
;
1411 cmd
.timeout
= pPacket
->TimeOutValue
*HZ
;
1413 switch (pPacket
->DataIn
)
1415 case SCSI_IOCTL_DATA_OUT
:
1416 cmd
.data_direction
= CGC_DATA_WRITE
;
1418 case SCSI_IOCTL_DATA_IN
:
1419 cmd
.data_direction
= CGC_DATA_READ
;
1421 case SCSI_IOCTL_DATA_UNSPECIFIED
:
1422 cmd
.data_direction
= CGC_DATA_NONE
;
1425 return STATUS_INVALID_PARAMETER
;
1428 io
= ioctl(cdrom_cache
[dev
].fd
, CDROM_SEND_PACKET
, &cmd
);
1430 if (pPacket
->SenseInfoLength
!= 0)
1432 memcpy((char*)pPacket
+ pPacket
->SenseInfoOffset
,
1433 &sense
, pPacket
->SenseInfoLength
);
1436 pPacket
->ScsiStatus
= cmd
.stat
;
1438 ret
= CDROM_GetStatusCode(io
);
1440 #elif defined(__NetBSD__)
1444 if (pPacket
->Length
< sizeof(SCSI_PASS_THROUGH_DIRECT
))
1445 return STATUS_BUFFER_TOO_SMALL
;
1447 if (pPacket
->CdbLength
> 12)
1448 return STATUS_INVALID_PARAMETER
;
1450 if (pPacket
->SenseInfoLength
> SENSEBUFLEN
)
1451 return STATUS_INVALID_PARAMETER
;
1453 memset(&cmd
, 0, sizeof(cmd
));
1454 memcpy(&(cmd
.cmd
), &(pPacket
->Cdb
), pPacket
->CdbLength
);
1456 cmd
.cmdlen
= pPacket
->CdbLength
;
1457 cmd
.databuf
= pPacket
->DataBuffer
;
1458 cmd
.datalen
= pPacket
->DataTransferLength
;
1459 cmd
.senselen
= pPacket
->SenseInfoLength
;
1460 cmd
.timeout
= pPacket
->TimeOutValue
*1000; /* in milliseconds */
1462 switch (pPacket
->DataIn
)
1464 case SCSI_IOCTL_DATA_OUT
:
1465 cmd
.flags
|= SCCMD_WRITE
;
1467 case SCSI_IOCTL_DATA_IN
:
1468 cmd
.flags
|= SCCMD_READ
;
1470 case SCSI_IOCTL_DATA_UNSPECIFIED
:
1474 return STATUS_INVALID_PARAMETER
;
1477 io
= ioctl(cdrom_cache
[dev
].fd
, SCIOCCOMMAND
, &cmd
);
1481 case SCCMD_OK
: break;
1482 case SCCMD_TIMEOUT
: return STATUS_TIMEOUT
;
1484 case SCCMD_BUSY
: return STATUS_DEVICE_BUSY
;
1486 case SCCMD_SENSE
: break;
1487 case SCCMD_UNKNOWN
: return STATUS_UNSUCCESSFUL
;
1491 if (pPacket
->SenseInfoLength
!= 0)
1493 memcpy((char*)pPacket
+ pPacket
->SenseInfoOffset
,
1494 cmd
.sense
, pPacket
->SenseInfoLength
);
1497 pPacket
->ScsiStatus
= cmd
.status
;
1499 ret
= CDROM_GetStatusCode(io
);
1504 /******************************************************************
1505 * CDROM_ScsiPassThrough
1509 static NTSTATUS
CDROM_ScsiPassThrough(int dev
, PSCSI_PASS_THROUGH pPacket
)
1511 int ret
= STATUS_NOT_SUPPORTED
;
1512 #if defined(linux) && defined(CDROM_SEND_PACKET)
1513 struct linux_cdrom_generic_command cmd
;
1514 struct request_sense sense
;
1517 if (pPacket
->Length
< sizeof(SCSI_PASS_THROUGH
))
1518 return STATUS_BUFFER_TOO_SMALL
;
1520 if (pPacket
->CdbLength
> 12)
1521 return STATUS_INVALID_PARAMETER
;
1523 if (pPacket
->SenseInfoLength
> sizeof(sense
))
1524 return STATUS_INVALID_PARAMETER
;
1526 memset(&cmd
, 0, sizeof(cmd
));
1527 memset(&sense
, 0, sizeof(sense
));
1529 memcpy(&(cmd
.cmd
), &(pPacket
->Cdb
), pPacket
->CdbLength
);
1531 if ( pPacket
->DataBufferOffset
> 0x1000 )
1533 cmd
.buffer
= (void*)pPacket
->DataBufferOffset
;
1537 cmd
.buffer
= (char*)pPacket
+ pPacket
->DataBufferOffset
;
1539 cmd
.buflen
= pPacket
->DataTransferLength
;
1542 cmd
.timeout
= pPacket
->TimeOutValue
*HZ
;
1544 switch (pPacket
->DataIn
)
1546 case SCSI_IOCTL_DATA_OUT
:
1547 cmd
.data_direction
= CGC_DATA_WRITE
;
1549 case SCSI_IOCTL_DATA_IN
:
1550 cmd
.data_direction
= CGC_DATA_READ
;
1552 case SCSI_IOCTL_DATA_UNSPECIFIED
:
1553 cmd
.data_direction
= CGC_DATA_NONE
;
1556 return STATUS_INVALID_PARAMETER
;
1559 io
= ioctl(cdrom_cache
[dev
].fd
, CDROM_SEND_PACKET
, &cmd
);
1561 if (pPacket
->SenseInfoLength
!= 0)
1563 memcpy((char*)pPacket
+ pPacket
->SenseInfoOffset
,
1564 &sense
, pPacket
->SenseInfoLength
);
1567 pPacket
->ScsiStatus
= cmd
.stat
;
1569 ret
= CDROM_GetStatusCode(io
);
1571 #elif defined(__NetBSD__)
1575 if (pPacket
->Length
< sizeof(SCSI_PASS_THROUGH
))
1576 return STATUS_BUFFER_TOO_SMALL
;
1578 if (pPacket
->CdbLength
> 12)
1579 return STATUS_INVALID_PARAMETER
;
1581 if (pPacket
->SenseInfoLength
> SENSEBUFLEN
)
1582 return STATUS_INVALID_PARAMETER
;
1584 memset(&cmd
, 0, sizeof(cmd
));
1585 memcpy(&(cmd
.cmd
), &(pPacket
->Cdb
), pPacket
->CdbLength
);
1587 if ( pPacket
->DataBufferOffset
> 0x1000 )
1589 cmd
.databuf
= (void*)pPacket
->DataBufferOffset
;
1593 cmd
.databuf
= (char*)pPacket
+ pPacket
->DataBufferOffset
;
1596 cmd
.cmdlen
= pPacket
->CdbLength
;
1597 cmd
.datalen
= pPacket
->DataTransferLength
;
1598 cmd
.senselen
= pPacket
->SenseInfoLength
;
1599 cmd
.timeout
= pPacket
->TimeOutValue
*1000; /* in milliseconds */
1601 switch (pPacket
->DataIn
)
1603 case SCSI_IOCTL_DATA_OUT
:
1604 cmd
.flags
|= SCCMD_WRITE
;
1606 case SCSI_IOCTL_DATA_IN
:
1607 cmd
.flags
|= SCCMD_READ
;
1609 case SCSI_IOCTL_DATA_UNSPECIFIED
:
1613 return STATUS_INVALID_PARAMETER
;
1616 io
= ioctl(cdrom_cache
[dev
].fd
, SCIOCCOMMAND
, &cmd
);
1620 case SCCMD_OK
: break;
1621 case SCCMD_TIMEOUT
: return STATUS_TIMEOUT
;
1623 case SCCMD_BUSY
: return STATUS_DEVICE_BUSY
;
1625 case SCCMD_SENSE
: break;
1626 case SCCMD_UNKNOWN
: return STATUS_UNSUCCESSFUL
;
1630 if (pPacket
->SenseInfoLength
!= 0)
1632 memcpy((char*)pPacket
+ pPacket
->SenseInfoOffset
,
1633 cmd
.sense
, pPacket
->SenseInfoLength
);
1636 pPacket
->ScsiStatus
= cmd
.status
;
1638 ret
= CDROM_GetStatusCode(io
);
1643 /******************************************************************
1648 static NTSTATUS
CDROM_ScsiGetCaps(int dev
, PIO_SCSI_CAPABILITIES caps
)
1650 NTSTATUS ret
= STATUS_NOT_IMPLEMENTED
;
1652 caps
->Length
= sizeof(*caps
);
1654 caps
->MaximumTransferLength
= SG_SCATTER_SZ
; /* FIXME */
1655 caps
->MaximumPhysicalPages
= SG_SCATTER_SZ
/ getpagesize();
1656 caps
->SupportedAsynchronousEvents
= TRUE
;
1657 caps
->AlignmentMask
= getpagesize();
1658 caps
->TaggedQueuing
= FALSE
; /* we could check that it works and answer TRUE */
1659 caps
->AdapterScansDown
= FALSE
; /* FIXME ? */
1660 caps
->AdapterUsesPio
= FALSE
; /* FIXME ? */
1661 ret
= STATUS_SUCCESS
;
1663 FIXME("Unimplemented\n");
1668 /******************************************************************
1671 * implements IOCTL_SCSI_GET_ADDRESS
1673 static NTSTATUS
CDROM_GetAddress(int dev
, SCSI_ADDRESS
* address
)
1675 int portnum
, busid
, targetid
, lun
;
1677 address
->Length
= sizeof(SCSI_ADDRESS
);
1678 if ( ! CDROM_GetInterfaceInfo(cdrom_cache
[dev
].fd
, &portnum
,
1679 &busid
, &targetid
, &lun
))
1680 return STATUS_NOT_SUPPORTED
;
1682 address
->PortNumber
= portnum
;
1683 address
->PathId
= busid
; /* bus number */
1684 address
->TargetId
= targetid
;
1686 return STATUS_SUCCESS
;
1689 /******************************************************************
1690 * CDROM_DeviceIoControl
1694 NTSTATUS
CDROM_DeviceIoControl(DWORD clientID
, HANDLE hDevice
,
1695 HANDLE hEvent
, PIO_APC_ROUTINE UserApcRoutine
,
1696 PVOID UserApcContext
,
1697 PIO_STATUS_BLOCK piosb
,
1698 ULONG dwIoControlCode
,
1699 LPVOID lpInBuffer
, DWORD nInBufferSize
,
1700 LPVOID lpOutBuffer
, DWORD nOutBufferSize
)
1703 NTSTATUS status
= STATUS_SUCCESS
;
1706 TRACE("%lx[%c] %s %lx %ld %lx %ld %p\n",
1707 (DWORD
)hDevice
, 'A' + LOWORD(clientID
), iocodex(dwIoControlCode
), (DWORD
)lpInBuffer
, nInBufferSize
,
1708 (DWORD
)lpOutBuffer
, nOutBufferSize
, piosb
);
1710 piosb
->Information
= 0;
1712 if ((status
= CDROM_Open(hDevice
, clientID
, &dev
))) goto error
;
1714 switch (dwIoControlCode
)
1716 case IOCTL_STORAGE_CHECK_VERIFY
:
1717 case IOCTL_CDROM_CHECK_VERIFY
:
1719 CDROM_ClearCacheEntry(dev
);
1720 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0 || lpOutBuffer
!= NULL
|| nOutBufferSize
!= 0)
1721 status
= STATUS_INVALID_PARAMETER
;
1722 else status
= CDROM_Verify(dev
);
1725 /* EPP case IOCTL_STORAGE_CHECK_VERIFY2: */
1727 /* EPP case IOCTL_STORAGE_FIND_NEW_DEVICES: */
1728 /* EPP case IOCTL_CDROM_FIND_NEW_DEVICES: */
1730 case IOCTL_STORAGE_LOAD_MEDIA
:
1731 case IOCTL_CDROM_LOAD_MEDIA
:
1733 CDROM_ClearCacheEntry(dev
);
1734 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0 || lpOutBuffer
!= NULL
|| nOutBufferSize
!= 0)
1735 status
= STATUS_INVALID_PARAMETER
;
1736 else status
= CDROM_SetTray(dev
, FALSE
);
1738 case IOCTL_STORAGE_EJECT_MEDIA
:
1740 CDROM_ClearCacheEntry(dev
);
1741 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0 || lpOutBuffer
!= NULL
|| nOutBufferSize
!= 0)
1742 status
= STATUS_INVALID_PARAMETER
;
1743 else status
= CDROM_SetTray(dev
, TRUE
);
1746 case IOCTL_CDROM_MEDIA_REMOVAL
:
1747 case IOCTL_DISK_MEDIA_REMOVAL
:
1748 case IOCTL_STORAGE_MEDIA_REMOVAL
:
1749 case IOCTL_STORAGE_EJECTION_CONTROL
:
1750 /* FIXME the last ioctl:s is not the same as the two others...
1751 * lockcount/owner should be handled */
1753 CDROM_ClearCacheEntry(dev
);
1754 if (lpOutBuffer
!= NULL
|| nOutBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
1755 else if (nInBufferSize
< sizeof(PREVENT_MEDIA_REMOVAL
)) status
= STATUS_BUFFER_TOO_SMALL
;
1756 else status
= CDROM_ControlEjection(dev
, (const PREVENT_MEDIA_REMOVAL
*)lpInBuffer
);
1759 /* EPP case IOCTL_STORAGE_GET_MEDIA_TYPES: */
1761 case IOCTL_STORAGE_GET_DEVICE_NUMBER
:
1762 sz
= sizeof(STORAGE_DEVICE_NUMBER
);
1763 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
1764 else if (nOutBufferSize
< sz
) status
= STATUS_BUFFER_TOO_SMALL
;
1765 else status
= CDROM_GetDeviceNumber(dev
, (STORAGE_DEVICE_NUMBER
*)lpOutBuffer
);
1768 case IOCTL_STORAGE_RESET_DEVICE
:
1770 CDROM_ClearCacheEntry(dev
);
1771 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0 || lpOutBuffer
!= NULL
|| nOutBufferSize
!= 0)
1772 status
= STATUS_INVALID_PARAMETER
;
1773 else status
= CDROM_ResetAudio(dev
);
1776 case IOCTL_CDROM_GET_CONTROL
:
1777 sz
= sizeof(CDROM_AUDIO_CONTROL
);
1778 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
1779 else if (nOutBufferSize
< sz
) status
= STATUS_BUFFER_TOO_SMALL
;
1780 else status
= CDROM_GetControl(dev
, (CDROM_AUDIO_CONTROL
*)lpOutBuffer
);
1783 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
:
1784 sz
= sizeof(DISK_GEOMETRY
);
1785 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
1786 else if (nOutBufferSize
< sz
) status
= STATUS_BUFFER_TOO_SMALL
;
1787 else status
= CDROM_GetDriveGeometry(dev
, (DISK_GEOMETRY
*)lpOutBuffer
);
1790 case IOCTL_CDROM_DISK_TYPE
:
1791 sz
= sizeof(CDROM_DISK_DATA
);
1792 /* CDROM_ClearCacheEntry(dev); */
1793 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
1794 else if (nOutBufferSize
< sz
) status
= STATUS_BUFFER_TOO_SMALL
;
1795 else status
= CDROM_GetDiskData(dev
, (CDROM_DISK_DATA
*)lpOutBuffer
);
1798 /* EPP case IOCTL_CDROM_GET_LAST_SESSION: */
1800 case IOCTL_CDROM_READ_Q_CHANNEL
:
1801 sz
= sizeof(SUB_Q_CHANNEL_DATA
);
1802 if (lpInBuffer
== NULL
|| nInBufferSize
< sizeof(CDROM_SUB_Q_DATA_FORMAT
))
1803 status
= STATUS_INVALID_PARAMETER
;
1804 else if (nOutBufferSize
< sz
) status
= STATUS_BUFFER_TOO_SMALL
;
1805 else status
= CDROM_ReadQChannel(dev
, (const CDROM_SUB_Q_DATA_FORMAT
*)lpInBuffer
,
1806 (SUB_Q_CHANNEL_DATA
*)lpOutBuffer
);
1809 case IOCTL_CDROM_READ_TOC
:
1810 sz
= sizeof(CDROM_TOC
);
1811 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
1812 else if (nOutBufferSize
< sz
) status
= STATUS_BUFFER_TOO_SMALL
;
1813 else status
= CDROM_ReadTOC(dev
, (CDROM_TOC
*)lpOutBuffer
);
1816 /* EPP case IOCTL_CDROM_READ_TOC_EX: */
1818 case IOCTL_CDROM_PAUSE_AUDIO
:
1820 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0 || lpOutBuffer
!= NULL
|| nOutBufferSize
!= 0)
1821 status
= STATUS_INVALID_PARAMETER
;
1822 else status
= CDROM_PauseAudio(dev
);
1824 case IOCTL_CDROM_PLAY_AUDIO_MSF
:
1826 if (lpOutBuffer
!= NULL
|| nOutBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
1827 else if (nInBufferSize
< sizeof(CDROM_PLAY_AUDIO_MSF
)) status
= STATUS_BUFFER_TOO_SMALL
;
1828 else status
= CDROM_PlayAudioMSF(dev
, (const CDROM_PLAY_AUDIO_MSF
*)lpInBuffer
);
1830 case IOCTL_CDROM_RESUME_AUDIO
:
1832 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0 || lpOutBuffer
!= NULL
|| nOutBufferSize
!= 0)
1833 status
= STATUS_INVALID_PARAMETER
;
1834 else status
= CDROM_ResumeAudio(dev
);
1836 case IOCTL_CDROM_SEEK_AUDIO_MSF
:
1838 if (lpOutBuffer
!= NULL
|| nOutBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
1839 else if (nInBufferSize
< sizeof(CDROM_SEEK_AUDIO_MSF
)) status
= STATUS_BUFFER_TOO_SMALL
;
1840 else status
= CDROM_SeekAudioMSF(dev
, (const CDROM_SEEK_AUDIO_MSF
*)lpInBuffer
);
1842 case IOCTL_CDROM_STOP_AUDIO
:
1844 CDROM_ClearCacheEntry(dev
); /* Maybe intention is to change media */
1845 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0 || lpOutBuffer
!= NULL
|| nOutBufferSize
!= 0)
1846 status
= STATUS_INVALID_PARAMETER
;
1847 else status
= CDROM_StopAudio(dev
);
1849 case IOCTL_CDROM_GET_VOLUME
:
1850 sz
= sizeof(VOLUME_CONTROL
);
1851 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
1852 else if (nOutBufferSize
< sz
) status
= STATUS_BUFFER_TOO_SMALL
;
1853 else status
= CDROM_GetVolume(dev
, (VOLUME_CONTROL
*)lpOutBuffer
);
1855 case IOCTL_CDROM_SET_VOLUME
:
1857 CDROM_ClearCacheEntry(dev
);
1858 if (lpInBuffer
== NULL
|| nInBufferSize
< sizeof(VOLUME_CONTROL
) || lpOutBuffer
!= NULL
)
1859 status
= STATUS_INVALID_PARAMETER
;
1860 else status
= CDROM_SetVolume(dev
, (const VOLUME_CONTROL
*)lpInBuffer
);
1862 case IOCTL_CDROM_RAW_READ
:
1864 if (nInBufferSize
< sizeof(RAW_READ_INFO
)) status
= STATUS_INVALID_PARAMETER
;
1865 else if (lpOutBuffer
== NULL
) status
= STATUS_BUFFER_TOO_SMALL
;
1866 else status
= CDROM_RawRead(dev
, (const RAW_READ_INFO
*)lpInBuffer
,
1867 lpOutBuffer
, nOutBufferSize
, &sz
);
1869 case IOCTL_SCSI_GET_ADDRESS
:
1870 sz
= sizeof(SCSI_ADDRESS
);
1871 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
1872 else if (nOutBufferSize
< sz
) status
= STATUS_BUFFER_TOO_SMALL
;
1873 else status
= CDROM_GetAddress(dev
, (SCSI_ADDRESS
*)lpOutBuffer
);
1875 case IOCTL_SCSI_PASS_THROUGH_DIRECT
:
1876 sz
= sizeof(SCSI_PASS_THROUGH_DIRECT
);
1877 if (lpOutBuffer
== NULL
) status
= STATUS_INVALID_PARAMETER
;
1878 else if (nOutBufferSize
< sizeof(SCSI_PASS_THROUGH_DIRECT
)) status
= STATUS_BUFFER_TOO_SMALL
;
1879 else status
= CDROM_ScsiPassThroughDirect(dev
, (PSCSI_PASS_THROUGH_DIRECT
)lpOutBuffer
);
1881 case IOCTL_SCSI_PASS_THROUGH
:
1882 sz
= sizeof(SCSI_PASS_THROUGH
);
1883 if (lpOutBuffer
== NULL
) status
= STATUS_INVALID_PARAMETER
;
1884 else if (nOutBufferSize
< sizeof(SCSI_PASS_THROUGH
)) status
= STATUS_BUFFER_TOO_SMALL
;
1885 else status
= CDROM_ScsiPassThrough(dev
, (PSCSI_PASS_THROUGH
)lpOutBuffer
);
1887 case IOCTL_SCSI_GET_CAPABILITIES
:
1888 sz
= sizeof(IO_SCSI_CAPABILITIES
);
1889 if (lpOutBuffer
== NULL
) status
= STATUS_INVALID_PARAMETER
;
1890 else if (nOutBufferSize
< sizeof(IO_SCSI_CAPABILITIES
)) status
= STATUS_BUFFER_TOO_SMALL
;
1891 else status
= CDROM_ScsiGetCaps(dev
, (PIO_SCSI_CAPABILITIES
)lpOutBuffer
);
1894 FIXME("Unsupported IOCTL %lx (type=%lx access=%lx func=%lx meth=%lx)\n",
1895 dwIoControlCode
, dwIoControlCode
>> 16, (dwIoControlCode
>> 14) & 3,
1896 (dwIoControlCode
>> 2) & 0xFFF, dwIoControlCode
& 3);
1898 status
= STATUS_INVALID_PARAMETER
;
1902 piosb
->u
.Status
= status
;
1903 piosb
->Information
= sz
;
1904 if (hEvent
) NtSetEvent(hEvent
, NULL
);
1906 CDROM_Close(clientID
);