1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2 /* Main file for CD-ROM support
4 * Copyright 1994 Martin Ayotte
5 * Copyright 1999, 2001, 2003 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 "ntdll_misc.h"
87 #include "wine/server.h"
88 #include "wine/library.h"
89 #include "wine/debug.h"
91 /* Non-Linux systems do not have linux/cdrom.h and the like, and thus
92 lack the following constants. */
95 # define CD_SECS 60 /* seconds per minute */
98 # define CD_FRAMES 75 /* frames per second */
101 /* definitions taken from libdvdcss */
103 #define IOCTL_DVD_BASE FILE_DEVICE_DVD
105 #define IOCTL_DVD_START_SESSION CTL_CODE(IOCTL_DVD_BASE, 0x0400, METHOD_BUFFERED, FILE_READ_ACCESS)
106 #define IOCTL_DVD_READ_KEY CTL_CODE(IOCTL_DVD_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS)
107 #define IOCTL_DVD_SEND_KEY CTL_CODE(IOCTL_DVD_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS)
108 #define IOCTL_DVD_END_SESSION CTL_CODE(IOCTL_DVD_BASE, 0x0403, METHOD_BUFFERED, FILE_READ_ACCESS)
109 #define IOCTL_DVD_SET_READ_AHEAD CTL_CODE(IOCTL_DVD_BASE, 0x0404, METHOD_BUFFERED, FILE_READ_ACCESS)
110 #define IOCTL_DVD_GET_REGION CTL_CODE(IOCTL_DVD_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS)
111 #define IOCTL_DVD_SEND_KEY2 CTL_CODE(IOCTL_DVD_BASE, 0x0406, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
113 #define IOCTL_DVD_READ_STRUCTURE CTL_CODE(IOCTL_DVD_BASE, 0x0450, METHOD_BUFFERED, FILE_READ_ACCESS)
116 DvdChallengeKey = 0x01,
124 DvdInvalidateAGID = 0x3f
127 typedef ULONG DVD_SESSION_ID, *PDVD_SESSION_ID;
129 typedef struct _DVD_COPY_PROTECT_KEY {
131 DVD_SESSION_ID SessionId;
132 DVD_KEY_TYPE KeyType;
137 ULONG Reserved; /* used for NT alignment */
139 LARGE_INTEGER TitleOffset;
142 } DVD_COPY_PROTECT_KEY, *PDVD_COPY_PROTECT_KEY;
144 typedef struct _DVD_RPC_KEY {
145 UCHAR UserResetsAvailable:3;
146 UCHAR ManufacturerResetsAvailable:3;
151 } DVD_RPC_KEY, * PDVD_RPC_KEY;
153 typedef struct _DVD_ASF {
157 } DVD_ASF, * PDVD_ASF;
159 typedef struct _DVD_REGION
161 unsigned char copy_system;
162 unsigned char region_data; /* current media region (not playable when set) */
163 unsigned char system_region; /* current drive region (playable when set) */
164 unsigned char reset_count; /* number of resets available */
165 } DVD_REGION, * PDVD_REGION;
167 typedef struct _DVD_READ_STRUCTURE {
168 /* Contains an offset to the logical block address of the descriptor to be retrieved. */
169 LARGE_INTEGER block_byte_offset;
171 /* 0:Physical descriptor, 1:Copyright descriptor, 2:Disk key descriptor
172 3:BCA descriptor, 4:Manufacturer descriptor, 5:Max descriptor
176 /* Session ID, that is obtained by IOCTL_DVD_START_SESSION */
180 unsigned char layer_no;
181 }DVD_READ_STRUCTURE, * PDVD_READ_STRUCTURE;
183 typedef struct _DVD_LAYER_DESCRIPTOR
185 unsigned short length;
187 unsigned char book_version : 4;
189 /* 0:DVD-ROM, 1:DVD-RAM, 2:DVD-R, 3:DVD-RW, 9:DVD-RW */
190 unsigned char book_type : 4;
192 unsigned char minimum_rate : 4;
194 /* The physical size of the media. 0:120 mm, 1:80 mm. */
195 unsigned char disk_size : 4;
197 /* 1:Read-only layer, 2:Recordable layer, 4:Rewritable layer */
198 unsigned char layer_type : 4;
200 /* 0:parallel track path, 1:opposite track path */
201 unsigned char track_path : 1;
203 /* 0:one layers, 1:two layers, and so on */
204 unsigned char num_of_layers : 2;
206 unsigned char reserved1 : 1;
208 /* 0:0.74 µm/track, 1:0.80 µm/track, 2:0.615 µm/track */
209 unsigned char track_density : 4;
211 /* 0:0.267 µm/bit, 1:0.293 µm/bit, 2:0.409 to 0.435 µm/bit, 4:0.280 to 0.291 µm/bit, 8:0.353 µm/bit */
212 unsigned char linear_density : 4;
214 /* Must be either 0x30000:DVD-ROM or DVD-R/-RW or 0x31000:DVD-RAM or DVD+RW */
215 unsigned long starting_data_sector;
217 unsigned long end_data_sector;
218 unsigned long end_layer_zero_sector;
219 unsigned char reserved5 : 7;
221 /* 0 indicates no BCA data */
222 unsigned char BCA_flag : 1;
224 unsigned char reserved6;
225 }DVD_LAYER_DESCRIPTOR, * PDVD_LAYER_DESCRIPTOR;
227 typedef struct _DVD_COPYRIGHT_DESCRIPTOR
229 unsigned char protection;
230 unsigned char region;
231 unsigned short reserved;
232 }DVD_COPYRIGHT_DESCRIPTOR, * PDVD_COPYRIGHT_DESCRIPTOR;
234 typedef struct _DVD_MANUFACTURER_DESCRIPTOR
236 unsigned char manufacturing[2048];
237 }DVD_MANUFACTURER_DESCRIPTOR, * PDVD_MANUFACTURER_DESCRIPTOR;
239 #define DVD_CHALLENGE_KEY_LENGTH (12 + sizeof(DVD_COPY_PROTECT_KEY) - sizeof(UCHAR))
241 #define DVD_DISK_KEY_LENGTH (2048 + sizeof(DVD_COPY_PROTECT_KEY) - sizeof(UCHAR))
243 #define DVD_KEY_SIZE 5
244 #define DVD_CHALLENGE_SIZE 10
245 #define DVD_DISCKEY_SIZE 2048
246 #define DVD_SECTOR_PROTECTED 0x00000020
248 static const struct iocodexs
253 #define X(x) { x, #x },
254 X(IOCTL_CDROM_CHECK_VERIFY)
255 X(IOCTL_CDROM_CURRENT_POSITION)
256 X(IOCTL_CDROM_DISK_TYPE)
257 X(IOCTL_CDROM_GET_CONTROL)
258 X(IOCTL_CDROM_GET_DRIVE_GEOMETRY)
259 X(IOCTL_CDROM_GET_VOLUME)
260 X(IOCTL_CDROM_LOAD_MEDIA)
261 X(IOCTL_CDROM_MEDIA_CATALOG)
262 X(IOCTL_CDROM_MEDIA_REMOVAL)
263 X(IOCTL_CDROM_PAUSE_AUDIO)
264 X(IOCTL_CDROM_PLAY_AUDIO_MSF)
265 X(IOCTL_CDROM_RAW_READ)
266 X(IOCTL_CDROM_READ_Q_CHANNEL)
267 X(IOCTL_CDROM_READ_TOC)
268 X(IOCTL_CDROM_RESUME_AUDIO)
269 X(IOCTL_CDROM_SEEK_AUDIO_MSF)
270 X(IOCTL_CDROM_SET_VOLUME)
271 X(IOCTL_CDROM_STOP_AUDIO)
272 X(IOCTL_CDROM_TRACK_ISRC)
273 X(IOCTL_DISK_MEDIA_REMOVAL)
274 X(IOCTL_DVD_END_SESSION)
275 X(IOCTL_DVD_GET_REGION)
276 X(IOCTL_DVD_READ_KEY)
277 X(IOCTL_DVD_READ_STRUCTURE)
278 X(IOCTL_DVD_SEND_KEY)
279 X(IOCTL_DVD_START_SESSION)
280 X(IOCTL_SCSI_GET_ADDRESS)
281 X(IOCTL_SCSI_GET_CAPABILITIES)
282 X(IOCTL_SCSI_PASS_THROUGH)
283 X(IOCTL_SCSI_PASS_THROUGH_DIRECT)
284 X(IOCTL_STORAGE_CHECK_VERIFY)
285 X(IOCTL_STORAGE_EJECTION_CONTROL)
286 X(IOCTL_STORAGE_EJECT_MEDIA)
287 X(IOCTL_STORAGE_GET_DEVICE_NUMBER)
288 X(IOCTL_STORAGE_LOAD_MEDIA)
289 X(IOCTL_STORAGE_MEDIA_REMOVAL)
290 X(IOCTL_STORAGE_RESET_DEVICE)
293 static const char *iocodex(DWORD code)
296 static char buffer[25];
297 for(i=0; i<sizeof(iocodextable)/sizeof(struct iocodexs); i++)
298 if (code==iocodextable[i].code)
299 return iocodextable[i].codex;
300 sprintf(buffer, "IOCTL_CODE_%x", (int)code);
304 WINE_DEFAULT_DEBUG_CHANNEL(cdrom);
306 #define FRAME_OF_ADDR(a) (((int)(a)[1] * CD_SECS + (a)[2]) * CD_FRAMES + (a)[3])
307 #define FRAME_OF_MSF(a) (((int)(a).M * CD_SECS + (a).S) * CD_FRAMES + (a).F)
308 #define FRAME_OF_TOC(toc, idx) FRAME_OF_ADDR((toc).TrackData[idx - (toc).FirstTrack].Address)
309 #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;}
311 static NTSTATUS CDROM_ReadTOC(int, int, CDROM_TOC*);
312 static NTSTATUS CDROM_GetStatusCode(int);
318 # define IDE6_MAJOR 88
321 # define IDE7_MAJOR 89
324 # ifdef CDROM_SEND_PACKET
325 /* structure for CDROM_PACKET_COMMAND ioctl */
326 /* not all Linux versions have all the fields, so we define the
327 * structure ourselves to make sure */
328 struct linux_cdrom_generic_command
330 unsigned char cmd[CDROM_PACKET_SIZE];
331 unsigned char *buffer;
334 struct request_sense *sense;
335 unsigned char data_direction;
340 # endif /* CDROM_SEND_PACKET */
344 /* FIXME: this is needed because we can't open simultaneously several times /dev/cdrom
345 * this should be removed when a proper device interface is implemented
347 * (WS) We need this to keep track of current position and to safely
348 * detect media changes. Besides this should provide a great speed up
354 char toc_good; /* if false, will reread TOC from disk */
356 SUB_Q_CURRENT_POSITION CurrentPosition;
358 /* who has more than 5 cdroms on his/her machine ?? */
359 /* FIXME: this should grow depending on the number of cdroms we install/configure
362 #define MAX_CACHE_ENTRIES 5
363 static struct cdrom_cache cdrom_cache[MAX_CACHE_ENTRIES];
365 static CRITICAL_SECTION cache_section;
366 static CRITICAL_SECTION_DEBUG critsect_debug =
368 0, 0, &cache_section,
369 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
370 0, 0, { 0, (DWORD)(__FILE__ ": cache_section") }
372 static CRITICAL_SECTION cache_section = { &critsect_debug, -1, 0, 0, 0, 0 };
374 /* Proposed media change function: not really needed at this time */
375 /* This is a 1 or 0 type of function */
377 static int CDROM_MediaChanged(int dev)
381 struct cdrom_tochdr hdr;
382 struct cdrom_tocentry entry;
384 if (dev < 0 || dev >= MAX_CACHE_ENTRIES)
386 if ( ioctl(cdrom_cache[dev].fd, CDROMREADTOCHDR, &hdr) == -1 )
389 if ( memcmp(&hdr, &cdrom_cache[dev].hdr, sizeof(struct cdrom_tochdr)) )
392 for (i=hdr.cdth_trk0; i<=hdr.cdth_trk1+1; i++)
394 if (i == hdr.cdth_trk1 + 1)
396 entry.cdte_track = CDROM_LEADOUT;
398 entry.cdte_track = i;
400 entry.cdte_format = CDROM_MSF;
401 if ( ioctl(cdrom_cache[dev].fd, CDROMREADTOCENTRY, &entry) == -1)
403 if ( memcmp(&entry, cdrom_cache[dev].entry+i-hdr.cdth_trk0,
404 sizeof(struct cdrom_tocentry)) )
411 /******************************************************************
412 * CDROM_SyncCache [internal]
414 * Read the TOC in and store it in the cdrom_cache structure.
415 * Further requests for the TOC will be copied from the cache
416 * unless certain events like disk ejection is detected, in which
417 * case the cache will be cleared, causing it to be resynced.
418 * The cache section must be held by caller.
420 static int CDROM_SyncCache(int dev, int fd)
424 struct cdrom_tochdr hdr;
425 struct cdrom_tocentry entry;
426 #elif defined(__FreeBSD__) || defined(__NetBSD__)
427 struct ioc_toc_header hdr;
428 struct ioc_read_toc_entry entry;
429 struct cd_toc_entry toc_buffer;
431 CDROM_TOC *toc = &cdrom_cache[dev].toc;
432 cdrom_cache[dev].toc_good = 0;
436 io = ioctl(fd, CDROMREADTOCHDR, &hdr);
439 WARN("(%d) -- Error occurred (%s)!\n", dev, strerror(errno));
443 toc->FirstTrack = hdr.cdth_trk0;
444 toc->LastTrack = hdr.cdth_trk1;
445 tsz = sizeof(toc->FirstTrack) + sizeof(toc->LastTrack)
446 + sizeof(TRACK_DATA) * (toc->LastTrack-toc->FirstTrack+2);
447 toc->Length[0] = tsz >> 8;
448 toc->Length[1] = tsz;
450 TRACE("caching toc from=%d to=%d\n", toc->FirstTrack, toc->LastTrack );
452 for (i = toc->FirstTrack; i <= toc->LastTrack + 1; i++)
454 if (i == toc->LastTrack + 1)
455 entry.cdte_track = CDROM_LEADOUT;
457 entry.cdte_track = i;
458 entry.cdte_format = CDROM_MSF;
459 io = ioctl(fd, CDROMREADTOCENTRY, &entry);
461 WARN("error read entry (%s)\n", strerror(errno));
464 toc->TrackData[i - toc->FirstTrack].Control = entry.cdte_ctrl;
465 toc->TrackData[i - toc->FirstTrack].Adr = entry.cdte_adr;
466 /* marking last track with leadout value as index */
467 toc->TrackData[i - toc->FirstTrack].TrackNumber = entry.cdte_track;
468 toc->TrackData[i - toc->FirstTrack].Address[0] = 0;
469 toc->TrackData[i - toc->FirstTrack].Address[1] = entry.cdte_addr.msf.minute;
470 toc->TrackData[i - toc->FirstTrack].Address[2] = entry.cdte_addr.msf.second;
471 toc->TrackData[i - toc->FirstTrack].Address[3] = entry.cdte_addr.msf.frame;
473 cdrom_cache[dev].toc_good = 1;
475 #elif defined(__FreeBSD__) || defined(__NetBSD__)
477 io = ioctl(fd, CDIOREADTOCHEADER, &hdr);
480 WARN("(%d) -- Error occurred (%s)!\n", dev, strerror(errno));
483 toc->FirstTrack = hdr.starting_track;
484 toc->LastTrack = hdr.ending_track;
485 tsz = sizeof(toc->FirstTrack) + sizeof(toc->LastTrack)
486 + sizeof(TRACK_DATA) * (toc->LastTrack-toc->FirstTrack+2);
487 toc->Length[0] = tsz >> 8;
488 toc->Length[1] = tsz;
490 TRACE("caching toc from=%d to=%d\n", toc->FirstTrack, toc->LastTrack );
492 for (i = toc->FirstTrack; i <= toc->LastTrack + 1; i++)
494 if (i == toc->LastTrack + 1)
497 entry.starting_track = LEADOUT;
499 entry.starting_track = i;
501 memset((char *)&toc_buffer, 0, sizeof(toc_buffer));
502 entry.address_format = CD_MSF_FORMAT;
503 entry.data_len = sizeof(toc_buffer);
504 entry.data = &toc_buffer;
505 io = ioctl(fd, CDIOREADTOCENTRYS, &entry);
507 WARN("error read entry (%s)\n", strerror(errno));
510 toc->TrackData[i - toc->FirstTrack].Control = toc_buffer.control;
511 toc->TrackData[i - toc->FirstTrack].Adr = toc_buffer.addr_type;
512 /* marking last track with leadout value as index */
513 toc->TrackData[i - toc->FirstTrack].TrackNumber = entry.starting_track;
514 toc->TrackData[i - toc->FirstTrack].Address[0] = 0;
515 toc->TrackData[i - toc->FirstTrack].Address[1] = toc_buffer.addr.msf.minute;
516 toc->TrackData[i - toc->FirstTrack].Address[2] = toc_buffer.addr.msf.second;
517 toc->TrackData[i - toc->FirstTrack].Address[3] = toc_buffer.addr.msf.frame;
519 cdrom_cache[dev].toc_good = 1;
522 return STATUS_NOT_SUPPORTED;
525 return CDROM_GetStatusCode(io);
528 static void CDROM_ClearCacheEntry(int dev)
530 RtlEnterCriticalSection( &cache_section );
531 cdrom_cache[dev].toc_good = 0;
532 RtlLeaveCriticalSection( &cache_section );
537 /******************************************************************
538 * CDROM_GetInterfaceInfo
540 * Determines the ide interface (the number after the ide), and the
541 * number of the device on that interface for ide cdroms (*port == 0).
542 * Determines the scsi information for scsi cdroms (*port >= 1).
543 * Returns false if the info cannot not be obtained.
545 static int CDROM_GetInterfaceInfo(int fd, int* port, int* iface, int* device,int* lun)
549 if ( fstat(fd, &st) == -1 || ! S_ISBLK(st.st_mode)) return 0;
554 switch (major(st.st_rdev)) {
555 case IDE0_MAJOR: *iface = 0; break;
556 case IDE1_MAJOR: *iface = 1; break;
557 case IDE2_MAJOR: *iface = 2; break;
558 case IDE3_MAJOR: *iface = 3; break;
559 case IDE4_MAJOR: *iface = 4; break;
560 case IDE5_MAJOR: *iface = 5; break;
561 case IDE6_MAJOR: *iface = 6; break;
562 case IDE7_MAJOR: *iface = 7; break;
563 default: *port = 1; break;
567 *device = (minor(st.st_rdev) >> 6);
570 #ifdef SCSI_IOCTL_GET_IDLUN
572 if (ioctl(fd, SCSI_IOCTL_GET_IDLUN, &idlun) != -1)
574 *port = ((idlun[0] >> 24) & 0xff) + 1;
575 *iface = (idlun[0] >> 16) & 0xff;
576 *device = idlun[0] & 0xff;
577 *lun = (idlun[0] >> 8) & 0xff;
582 WARN("CD-ROM device (%d, %d) not supported\n", major(st.st_rdev), minor(st.st_rdev));
587 #elif defined(__NetBSD__)
588 struct scsi_addr addr;
589 if (ioctl(fd, SCIOCIDENTIFY, &addr) != -1)
593 case TYPE_SCSI: *port = 1;
594 *iface = addr.addr.scsi.scbus;
595 *device = addr.addr.scsi.target;
596 *lun = addr.addr.scsi.lun;
598 case TYPE_ATAPI: *port = 0;
599 *iface = addr.addr.atapi.atbus;
600 *device = addr.addr.atapi.drive;
607 #elif defined(__FreeBSD__)
608 FIXME("not implemented for BSD\n");
611 FIXME("not implemented for nonlinux\n");
617 /******************************************************************
621 static NTSTATUS CDROM_Open(int fd, int* dev)
624 NTSTATUS ret = STATUS_SUCCESS;
629 RtlEnterCriticalSection( &cache_section );
630 for (*dev = 0; *dev < MAX_CACHE_ENTRIES; (*dev)++)
633 cdrom_cache[*dev].device == 0 &&
634 cdrom_cache[*dev].inode == 0)
636 else if (cdrom_cache[*dev].device == st.st_dev &&
637 cdrom_cache[*dev].inode == st.st_ino)
640 if (*dev == MAX_CACHE_ENTRIES)
642 if (empty == -1) ret = STATUS_NOT_IMPLEMENTED;
646 cdrom_cache[*dev].device = st.st_dev;
647 cdrom_cache[*dev].inode = st.st_ino;
650 RtlLeaveCriticalSection( &cache_section );
652 TRACE("%d, %d\n", *dev, fd);
656 /******************************************************************
657 * CDROM_GetStatusCode
661 static NTSTATUS CDROM_GetStatusCode(int io)
663 if (io == 0) return STATUS_SUCCESS;
664 return FILE_GetNtStatus();
667 /******************************************************************
671 static NTSTATUS CDROM_GetControl(int dev, CDROM_AUDIO_CONTROL* cac)
673 cac->LbaFormat = 0; /* FIXME */
674 cac->LogicalBlocksPerSecond = 1; /* FIXME */
675 return STATUS_NOT_SUPPORTED;
678 /******************************************************************
679 * CDROM_GetDeviceNumber
682 static NTSTATUS CDROM_GetDeviceNumber(int dev, STORAGE_DEVICE_NUMBER* devnum)
684 return STATUS_NOT_SUPPORTED;
687 /******************************************************************
688 * CDROM_GetDriveGeometry
691 static NTSTATUS CDROM_GetDriveGeometry(int dev, int fd, DISK_GEOMETRY* dg)
697 if ((ret = CDROM_ReadTOC(dev, fd, &toc)) != 0) return ret;
699 fsize = FRAME_OF_TOC(toc, toc.LastTrack+1)
700 - FRAME_OF_TOC(toc, 1); /* Total size in frames */
702 dg->Cylinders.u.LowPart = fsize / (64 * 32);
703 dg->Cylinders.u.HighPart = 0;
704 dg->MediaType = RemovableMedia;
705 dg->TracksPerCylinder = 64;
706 dg->SectorsPerTrack = 32;
707 dg->BytesPerSector= 2048;
711 /**************************************************************************
712 * CDROM_Reset [internal]
714 static NTSTATUS CDROM_ResetAudio(int fd)
717 return CDROM_GetStatusCode(ioctl(fd, CDROMRESET));
718 #elif defined(__FreeBSD__) || defined(__NetBSD__)
719 return CDROM_GetStatusCode(ioctl(fd, CDIOCRESET, NULL));
721 return STATUS_NOT_SUPPORTED;
725 /******************************************************************
730 static NTSTATUS CDROM_SetTray(int fd, BOOL doEject)
733 return CDROM_GetStatusCode(ioctl(fd, doEject ? CDROMEJECT : CDROMCLOSETRAY));
734 #elif defined(__FreeBSD__) || defined(__NetBSD__)
735 return CDROM_GetStatusCode((ioctl(fd, CDIOCALLOW, NULL)) ||
736 (ioctl(fd, doEject ? CDIOCEJECT : CDIOCCLOSE, NULL)) ||
737 (ioctl(fd, CDIOCPREVENT, NULL)));
739 return STATUS_NOT_SUPPORTED;
743 /******************************************************************
744 * CDROM_ControlEjection
748 static NTSTATUS CDROM_ControlEjection(int fd, const PREVENT_MEDIA_REMOVAL* rmv)
751 return CDROM_GetStatusCode(ioctl(fd, CDROM_LOCKDOOR, rmv->PreventMediaRemoval));
752 #elif defined(__FreeBSD__) || defined(__NetBSD__)
753 return CDROM_GetStatusCode(ioctl(fd, (rmv->PreventMediaRemoval) ? CDIOCPREVENT : CDIOCALLOW, NULL));
755 return STATUS_NOT_SUPPORTED;
759 /******************************************************************
764 static NTSTATUS CDROM_ReadTOC(int dev, int fd, CDROM_TOC* toc)
766 NTSTATUS ret = STATUS_NOT_SUPPORTED;
768 if (dev < 0 || dev >= MAX_CACHE_ENTRIES)
769 return STATUS_INVALID_PARAMETER;
771 RtlEnterCriticalSection( &cache_section );
772 if (cdrom_cache[dev].toc_good || !(ret = CDROM_SyncCache(dev, fd)))
774 *toc = cdrom_cache[dev].toc;
775 ret = STATUS_SUCCESS;
777 RtlLeaveCriticalSection( &cache_section );
781 /******************************************************************
786 static NTSTATUS CDROM_GetDiskData(int dev, int fd, CDROM_DISK_DATA* data)
792 if ((ret = CDROM_ReadTOC(dev, fd, &toc)) != 0) return ret;
794 for (i = toc.FirstTrack; i <= toc.LastTrack; i++) {
795 if (toc.TrackData[i-toc.FirstTrack].Control & 0x04)
796 data->DiskData |= CDROM_DISK_DATA_TRACK;
798 data->DiskData |= CDROM_DISK_AUDIO_TRACK;
800 return STATUS_SUCCESS;
803 /******************************************************************
808 static NTSTATUS CDROM_ReadQChannel(int dev, int fd, const CDROM_SUB_Q_DATA_FORMAT* fmt,
809 SUB_Q_CHANNEL_DATA* data)
811 NTSTATUS ret = STATUS_NOT_SUPPORTED;
814 SUB_Q_HEADER* hdr = (SUB_Q_HEADER*)data;
816 struct cdrom_subchnl sc;
817 sc.cdsc_format = CDROM_MSF;
819 io = ioctl(fd, CDROMSUBCHNL, &sc);
822 TRACE("opened or no_media (%s)!\n", strerror(errno));
823 hdr->AudioStatus = AUDIO_STATUS_NO_STATUS;
824 CDROM_ClearCacheEntry(dev);
828 hdr->AudioStatus = AUDIO_STATUS_NOT_SUPPORTED;
830 switch (sc.cdsc_audiostatus) {
831 case CDROM_AUDIO_INVALID:
832 CDROM_ClearCacheEntry(dev);
833 hdr->AudioStatus = AUDIO_STATUS_NOT_SUPPORTED;
835 case CDROM_AUDIO_NO_STATUS:
836 CDROM_ClearCacheEntry(dev);
837 hdr->AudioStatus = AUDIO_STATUS_NO_STATUS;
839 case CDROM_AUDIO_PLAY:
840 hdr->AudioStatus = AUDIO_STATUS_IN_PROGRESS;
842 case CDROM_AUDIO_PAUSED:
843 hdr->AudioStatus = AUDIO_STATUS_PAUSED;
845 case CDROM_AUDIO_COMPLETED:
846 hdr->AudioStatus = AUDIO_STATUS_PLAY_COMPLETE;
848 case CDROM_AUDIO_ERROR:
849 hdr->AudioStatus = AUDIO_STATUS_PLAY_ERROR;
852 TRACE("status=%02X !\n", sc.cdsc_audiostatus);
857 case IOCTL_CDROM_CURRENT_POSITION:
858 size = sizeof(SUB_Q_CURRENT_POSITION);
859 RtlEnterCriticalSection( &cache_section );
860 if (hdr->AudioStatus==AUDIO_STATUS_IN_PROGRESS) {
861 data->CurrentPosition.FormatCode = IOCTL_CDROM_CURRENT_POSITION;
862 data->CurrentPosition.Control = sc.cdsc_ctrl;
863 data->CurrentPosition.ADR = sc.cdsc_adr;
864 data->CurrentPosition.TrackNumber = sc.cdsc_trk;
865 data->CurrentPosition.IndexNumber = sc.cdsc_ind;
867 data->CurrentPosition.AbsoluteAddress[0] = 0;
868 data->CurrentPosition.AbsoluteAddress[1] = sc.cdsc_absaddr.msf.minute;
869 data->CurrentPosition.AbsoluteAddress[2] = sc.cdsc_absaddr.msf.second;
870 data->CurrentPosition.AbsoluteAddress[3] = sc.cdsc_absaddr.msf.frame;
872 data->CurrentPosition.TrackRelativeAddress[0] = 0;
873 data->CurrentPosition.TrackRelativeAddress[1] = sc.cdsc_reladdr.msf.minute;
874 data->CurrentPosition.TrackRelativeAddress[2] = sc.cdsc_reladdr.msf.second;
875 data->CurrentPosition.TrackRelativeAddress[3] = sc.cdsc_reladdr.msf.frame;
877 cdrom_cache[dev].CurrentPosition = data->CurrentPosition;
879 else /* not playing */
881 cdrom_cache[dev].CurrentPosition.Header = *hdr; /* Preserve header info */
882 data->CurrentPosition = cdrom_cache[dev].CurrentPosition;
884 RtlLeaveCriticalSection( &cache_section );
886 case IOCTL_CDROM_MEDIA_CATALOG:
887 size = sizeof(SUB_Q_MEDIA_CATALOG_NUMBER);
888 data->MediaCatalog.FormatCode = IOCTL_CDROM_MEDIA_CATALOG;
890 struct cdrom_mcn mcn;
891 if ((io = ioctl(fd, CDROM_GET_MCN, &mcn)) == -1) goto end;
893 data->MediaCatalog.FormatCode = IOCTL_CDROM_MEDIA_CATALOG;
894 data->MediaCatalog.Mcval = 0; /* FIXME */
895 memcpy(data->MediaCatalog.MediaCatalog, mcn.medium_catalog_number, 14);
896 data->MediaCatalog.MediaCatalog[14] = 0;
899 case IOCTL_CDROM_TRACK_ISRC:
900 size = sizeof(SUB_Q_CURRENT_POSITION);
901 FIXME("TrackIsrc: NIY on linux\n");
902 data->TrackIsrc.FormatCode = IOCTL_CDROM_TRACK_ISRC;
903 data->TrackIsrc.Tcval = 0;
909 ret = CDROM_GetStatusCode(io);
910 #elif defined(__FreeBSD__) || defined(__NetBSD__)
912 SUB_Q_HEADER* hdr = (SUB_Q_HEADER*)data;
914 struct ioc_read_subchannel read_sc;
915 struct cd_sub_channel_info sc;
917 read_sc.address_format = CD_MSF_FORMAT;
919 read_sc.data_len = sizeof(sc);
923 case IOCTL_CDROM_CURRENT_POSITION:
924 read_sc.data_format = CD_CURRENT_POSITION;
926 case IOCTL_CDROM_MEDIA_CATALOG:
927 read_sc.data_format = CD_MEDIA_CATALOG;
929 case IOCTL_CDROM_TRACK_ISRC:
930 read_sc.data_format = CD_TRACK_INFO;
931 sc.what.track_info.track_number = data->TrackIsrc.Track;
934 io = ioctl(fd, CDIOCREADSUBCHANNEL, &read_sc);
937 TRACE("opened or no_media (%s)!\n", strerror(errno));
938 CDROM_ClearCacheEntry(dev);
939 hdr->AudioStatus = AUDIO_STATUS_NO_STATUS;
943 hdr->AudioStatus = AUDIO_STATUS_NOT_SUPPORTED;
945 switch (sc.header.audio_status) {
946 case CD_AS_AUDIO_INVALID:
947 CDROM_ClearCacheEntry(dev);
948 hdr->AudioStatus = AUDIO_STATUS_NOT_SUPPORTED;
950 case CD_AS_NO_STATUS:
951 CDROM_ClearCacheEntry(dev);
952 hdr->AudioStatus = AUDIO_STATUS_NO_STATUS;
954 case CD_AS_PLAY_IN_PROGRESS:
955 hdr->AudioStatus = AUDIO_STATUS_IN_PROGRESS;
957 case CD_AS_PLAY_PAUSED:
958 hdr->AudioStatus = AUDIO_STATUS_PAUSED;
960 case CD_AS_PLAY_COMPLETED:
961 hdr->AudioStatus = AUDIO_STATUS_PLAY_COMPLETE;
963 case CD_AS_PLAY_ERROR:
964 hdr->AudioStatus = AUDIO_STATUS_PLAY_ERROR;
967 TRACE("status=%02X !\n", sc.header.audio_status);
971 case IOCTL_CDROM_CURRENT_POSITION:
972 size = sizeof(SUB_Q_CURRENT_POSITION);
973 RtlEnterCriticalSection( &cache_section );
974 if (hdr->AudioStatus==AUDIO_STATUS_IN_PROGRESS) {
975 data->CurrentPosition.FormatCode = IOCTL_CDROM_CURRENT_POSITION;
976 data->CurrentPosition.Control = sc.what.position.control;
977 data->CurrentPosition.ADR = sc.what.position.addr_type;
978 data->CurrentPosition.TrackNumber = sc.what.position.track_number;
979 data->CurrentPosition.IndexNumber = sc.what.position.index_number;
981 data->CurrentPosition.AbsoluteAddress[0] = 0;
982 data->CurrentPosition.AbsoluteAddress[1] = sc.what.position.absaddr.msf.minute;
983 data->CurrentPosition.AbsoluteAddress[2] = sc.what.position.absaddr.msf.second;
984 data->CurrentPosition.AbsoluteAddress[3] = sc.what.position.absaddr.msf.frame;
985 data->CurrentPosition.TrackRelativeAddress[0] = 0;
986 data->CurrentPosition.TrackRelativeAddress[1] = sc.what.position.reladdr.msf.minute;
987 data->CurrentPosition.TrackRelativeAddress[2] = sc.what.position.reladdr.msf.second;
988 data->CurrentPosition.TrackRelativeAddress[3] = sc.what.position.reladdr.msf.frame;
989 cdrom_cache[dev].CurrentPosition = data->CurrentPosition;
991 else { /* not playing */
992 cdrom_cache[dev].CurrentPosition.Header = *hdr; /* Preserve header info */
993 data->CurrentPosition = cdrom_cache[dev].CurrentPosition;
995 RtlLeaveCriticalSection( &cache_section );
997 case IOCTL_CDROM_MEDIA_CATALOG:
998 size = sizeof(SUB_Q_MEDIA_CATALOG_NUMBER);
999 data->MediaCatalog.FormatCode = IOCTL_CDROM_MEDIA_CATALOG;
1000 data->MediaCatalog.Mcval = sc.what.media_catalog.mc_valid;
1001 memcpy(data->MediaCatalog.MediaCatalog, sc.what.media_catalog.mc_number, 15);
1003 case IOCTL_CDROM_TRACK_ISRC:
1004 size = sizeof(SUB_Q_CURRENT_POSITION);
1005 data->TrackIsrc.FormatCode = IOCTL_CDROM_TRACK_ISRC;
1006 data->TrackIsrc.Tcval = sc.what.track_info.ti_valid;
1007 memcpy(data->TrackIsrc.TrackIsrc, sc.what.track_info.ti_number, 15);
1012 ret = CDROM_GetStatusCode(io);
1017 /******************************************************************
1022 static NTSTATUS CDROM_Verify(int dev, int fd)
1024 /* quick implementation */
1025 CDROM_SUB_Q_DATA_FORMAT fmt;
1026 SUB_Q_CHANNEL_DATA data;
1028 fmt.Format = IOCTL_CDROM_CURRENT_POSITION;
1029 return CDROM_ReadQChannel(dev, fd, &fmt, &data) ? 1 : 0;
1032 /******************************************************************
1033 * CDROM_PlayAudioMSF
1037 static NTSTATUS CDROM_PlayAudioMSF(int fd, const CDROM_PLAY_AUDIO_MSF* audio_msf)
1039 NTSTATUS ret = STATUS_NOT_SUPPORTED;
1041 struct cdrom_msf msf;
1044 msf.cdmsf_min0 = audio_msf->StartingM;
1045 msf.cdmsf_sec0 = audio_msf->StartingS;
1046 msf.cdmsf_frame0 = audio_msf->StartingF;
1047 msf.cdmsf_min1 = audio_msf->EndingM;
1048 msf.cdmsf_sec1 = audio_msf->EndingS;
1049 msf.cdmsf_frame1 = audio_msf->EndingF;
1051 io = ioctl(fd, CDROMSTART);
1054 WARN("motor doesn't start !\n");
1057 io = ioctl(fd, CDROMPLAYMSF, &msf);
1060 WARN("device doesn't play !\n");
1063 TRACE("msf = %d:%d:%d %d:%d:%d\n",
1064 msf.cdmsf_min0, msf.cdmsf_sec0, msf.cdmsf_frame0,
1065 msf.cdmsf_min1, msf.cdmsf_sec1, msf.cdmsf_frame1);
1067 ret = CDROM_GetStatusCode(io);
1068 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1069 struct ioc_play_msf msf;
1072 msf.start_m = audio_msf->StartingM;
1073 msf.start_s = audio_msf->StartingS;
1074 msf.start_f = audio_msf->StartingF;
1075 msf.end_m = audio_msf->EndingM;
1076 msf.end_s = audio_msf->EndingS;
1077 msf.end_f = audio_msf->EndingF;
1079 io = ioctl(fd, CDIOCSTART, NULL);
1082 WARN("motor doesn't start !\n");
1085 io = ioctl(fd, CDIOCPLAYMSF, &msf);
1088 WARN("device doesn't play !\n");
1091 TRACE("msf = %d:%d:%d %d:%d:%d\n",
1092 msf.start_m, msf.start_s, msf.start_f,
1093 msf.end_m, msf.end_s, msf.end_f);
1095 ret = CDROM_GetStatusCode(io);
1100 /******************************************************************
1101 * CDROM_SeekAudioMSF
1105 static NTSTATUS CDROM_SeekAudioMSF(int dev, int fd, const CDROM_SEEK_AUDIO_MSF* audio_msf)
1109 SUB_Q_CURRENT_POSITION *cp;
1111 struct cdrom_msf0 msf;
1112 struct cdrom_subchnl sc;
1113 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1114 struct ioc_play_msf msf;
1115 struct ioc_read_subchannel read_sc;
1116 struct cd_sub_channel_info sc;
1120 /* Use the information on the TOC to compute the new current
1121 * position, which is shadowed on the cache. [Portable]. */
1122 frame = FRAME_OF_MSF(*audio_msf);
1124 if ((io = CDROM_ReadTOC(dev, fd, &toc)) != 0) return io;
1126 for(i=toc.FirstTrack;i<=toc.LastTrack+1;i++)
1127 if (FRAME_OF_TOC(toc,i)>frame) break;
1128 if (i <= toc.FirstTrack || i > toc.LastTrack+1)
1129 return STATUS_INVALID_PARAMETER;
1131 RtlEnterCriticalSection( &cache_section );
1132 cp = &cdrom_cache[dev].CurrentPosition;
1133 cp->FormatCode = IOCTL_CDROM_CURRENT_POSITION;
1134 cp->Control = toc.TrackData[i-toc.FirstTrack].Control;
1135 cp->ADR = toc.TrackData[i-toc.FirstTrack].Adr;
1136 cp->TrackNumber = toc.TrackData[i-toc.FirstTrack].TrackNumber;
1137 cp->IndexNumber = 0; /* FIXME: where do they keep these? */
1138 cp->AbsoluteAddress[0] = 0;
1139 cp->AbsoluteAddress[1] = toc.TrackData[i-toc.FirstTrack].Address[1];
1140 cp->AbsoluteAddress[2] = toc.TrackData[i-toc.FirstTrack].Address[2];
1141 cp->AbsoluteAddress[3] = toc.TrackData[i-toc.FirstTrack].Address[3];
1142 frame -= FRAME_OF_TOC(toc,i);
1143 cp->TrackRelativeAddress[0] = 0;
1144 MSF_OF_FRAME(cp->TrackRelativeAddress[1], frame);
1145 RtlLeaveCriticalSection( &cache_section );
1147 /* If playing, then issue a seek command, otherwise do nothing */
1149 sc.cdsc_format = CDROM_MSF;
1151 io = ioctl(fd, CDROMSUBCHNL, &sc);
1154 TRACE("opened or no_media (%s)!\n", strerror(errno));
1155 CDROM_ClearCacheEntry(dev);
1156 return CDROM_GetStatusCode(io);
1158 if (sc.cdsc_audiostatus==CDROM_AUDIO_PLAY)
1160 msf.minute = audio_msf->M;
1161 msf.second = audio_msf->S;
1162 msf.frame = audio_msf->F;
1163 return CDROM_GetStatusCode(ioctl(fd, CDROMSEEK, &msf));
1165 return STATUS_SUCCESS;
1166 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1167 read_sc.address_format = CD_MSF_FORMAT;
1169 read_sc.data_len = sizeof(sc);
1171 read_sc.data_format = CD_CURRENT_POSITION;
1173 io = ioctl(fd, CDIOCREADSUBCHANNEL, &read_sc);
1176 TRACE("opened or no_media (%s)!\n", strerror(errno));
1177 CDROM_ClearCacheEntry(dev);
1178 return CDROM_GetStatusCode(io);
1180 if (sc.header.audio_status==CD_AS_PLAY_IN_PROGRESS)
1183 msf.start_m = audio_msf->M;
1184 msf.start_s = audio_msf->S;
1185 msf.start_f = audio_msf->F;
1186 final_frame = FRAME_OF_TOC(toc,toc.LastTrack+1)-1;
1187 MSF_OF_FRAME(msf.end_m, final_frame);
1189 return CDROM_GetStatusCode(ioctl(fd, CDIOCPLAYMSF, &msf));
1191 return STATUS_SUCCESS;
1193 return STATUS_NOT_SUPPORTED;
1197 /******************************************************************
1202 static NTSTATUS CDROM_PauseAudio(int fd)
1205 return CDROM_GetStatusCode(ioctl(fd, CDROMPAUSE));
1206 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1207 return CDROM_GetStatusCode(ioctl(fd, CDIOCPAUSE, NULL));
1209 return STATUS_NOT_SUPPORTED;
1213 /******************************************************************
1218 static NTSTATUS CDROM_ResumeAudio(int fd)
1221 return CDROM_GetStatusCode(ioctl(fd, CDROMRESUME));
1222 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1223 return CDROM_GetStatusCode(ioctl(fd, CDIOCRESUME, NULL));
1225 return STATUS_NOT_SUPPORTED;
1229 /******************************************************************
1234 static NTSTATUS CDROM_StopAudio(int fd)
1237 return CDROM_GetStatusCode(ioctl(fd, CDROMSTOP));
1238 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1239 return CDROM_GetStatusCode(ioctl(fd, CDIOCSTOP, NULL));
1241 return STATUS_NOT_SUPPORTED;
1245 /******************************************************************
1250 static NTSTATUS CDROM_GetVolume(int fd, VOLUME_CONTROL* vc)
1253 struct cdrom_volctrl volc;
1256 io = ioctl(fd, CDROMVOLREAD, &volc);
1259 vc->PortVolume[0] = volc.channel0;
1260 vc->PortVolume[1] = volc.channel1;
1261 vc->PortVolume[2] = volc.channel2;
1262 vc->PortVolume[3] = volc.channel3;
1264 return CDROM_GetStatusCode(io);
1265 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1266 struct ioc_vol volc;
1269 io = ioctl(fd, CDIOCGETVOL, &volc);
1272 vc->PortVolume[0] = volc.vol[0];
1273 vc->PortVolume[1] = volc.vol[1];
1274 vc->PortVolume[2] = volc.vol[2];
1275 vc->PortVolume[3] = volc.vol[3];
1277 return CDROM_GetStatusCode(io);
1279 return STATUS_NOT_SUPPORTED;
1283 /******************************************************************
1288 static NTSTATUS CDROM_SetVolume(int fd, const VOLUME_CONTROL* vc)
1291 struct cdrom_volctrl volc;
1293 volc.channel0 = vc->PortVolume[0];
1294 volc.channel1 = vc->PortVolume[1];
1295 volc.channel2 = vc->PortVolume[2];
1296 volc.channel3 = vc->PortVolume[3];
1298 return CDROM_GetStatusCode(ioctl(fd, CDROMVOLCTRL, &volc));
1299 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1300 struct ioc_vol volc;
1302 volc.vol[0] = vc->PortVolume[0];
1303 volc.vol[1] = vc->PortVolume[1];
1304 volc.vol[2] = vc->PortVolume[2];
1305 volc.vol[3] = vc->PortVolume[3];
1307 return CDROM_GetStatusCode(ioctl(fd, CDIOCSETVOL, &volc));
1309 return STATUS_NOT_SUPPORTED;
1313 /******************************************************************
1318 static NTSTATUS CDROM_RawRead(int fd, const RAW_READ_INFO* raw, void* buffer, DWORD len, DWORD* sz)
1320 int ret = STATUS_NOT_SUPPORTED;
1324 switch (raw->TrackMode)
1326 case YellowMode2: sectSize = 2336; break;
1327 case XAForm2: sectSize = 2328; break;
1328 case CDDA: sectSize = 2352; break;
1329 default: return STATUS_INVALID_PARAMETER;
1331 if (len < raw->SectorCount * sectSize) return STATUS_BUFFER_TOO_SMALL;
1332 /* strangely enough, it seems that sector offsets are always indicated with a size of 2048,
1333 * even if a larger size if read...
1337 struct cdrom_read cdr;
1338 struct cdrom_read_audio cdra;
1340 switch (raw->TrackMode)
1343 if (raw->DiskOffset.u.HighPart) FIXME("Unsupported value\n");
1344 cdr.cdread_lba = raw->DiskOffset.u.LowPart; /* FIXME ? */
1345 cdr.cdread_bufaddr = buffer;
1346 cdr.cdread_buflen = raw->SectorCount * sectSize;
1347 io = ioctl(fd, CDROMREADMODE2, &cdr);
1350 FIXME("XAForm2: NIY\n");
1353 /* FIXME: the output doesn't seem 100% correct... in fact output is shifted
1354 * between by NT2K box and this... should check on the same drive...
1355 * otherwise, I fear a 2352/2368 mismatch somewhere in one of the drivers
1357 * Anyway, that's not critical at all. We're talking of 16/32 bytes, we're
1358 * talking of 0.2 ms of sound
1360 /* 2048 = 2 ** 11 */
1361 if (raw->DiskOffset.u.HighPart & ~2047) FIXME("Unsupported value\n");
1362 cdra.addr.lba = ((raw->DiskOffset.u.LowPart >> 11) |
1363 (raw->DiskOffset.u.HighPart << (32 - 11))) - 1;
1364 FIXME("reading at %u\n", cdra.addr.lba);
1365 cdra.addr_format = CDROM_LBA;
1366 cdra.nframes = raw->SectorCount;
1368 io = ioctl(fd, CDROMREADAUDIO, &cdra);
1371 FIXME("NIY: %d\n", raw->TrackMode);
1377 switch (raw->TrackMode)
1380 FIXME("YellowMode2: NIY\n");
1383 FIXME("XAForm2: NIY\n");
1386 FIXME("CDDA: NIY\n");
1392 *sz = sectSize * raw->SectorCount;
1393 ret = CDROM_GetStatusCode(io);
1397 /******************************************************************
1398 * CDROM_ScsiPassThroughDirect
1402 static NTSTATUS CDROM_ScsiPassThroughDirect(int fd, PSCSI_PASS_THROUGH_DIRECT pPacket)
1404 int ret = STATUS_NOT_SUPPORTED;
1405 #if defined(linux) && defined(CDROM_SEND_PACKET)
1406 struct linux_cdrom_generic_command cmd;
1407 struct request_sense sense;
1410 if (pPacket->Length < sizeof(SCSI_PASS_THROUGH_DIRECT))
1411 return STATUS_BUFFER_TOO_SMALL;
1413 if (pPacket->CdbLength > 12)
1414 return STATUS_INVALID_PARAMETER;
1416 if (pPacket->SenseInfoLength > sizeof(sense))
1417 return STATUS_INVALID_PARAMETER;
1419 memset(&cmd, 0, sizeof(cmd));
1420 memset(&sense, 0, sizeof(sense));
1422 memcpy(&(cmd.cmd), &(pPacket->Cdb), pPacket->CdbLength);
1424 cmd.buffer = pPacket->DataBuffer;
1425 cmd.buflen = pPacket->DataTransferLength;
1428 cmd.timeout = pPacket->TimeOutValue*HZ;
1430 switch (pPacket->DataIn)
1432 case SCSI_IOCTL_DATA_OUT:
1433 cmd.data_direction = CGC_DATA_WRITE;
1435 case SCSI_IOCTL_DATA_IN:
1436 cmd.data_direction = CGC_DATA_READ;
1438 case SCSI_IOCTL_DATA_UNSPECIFIED:
1439 cmd.data_direction = CGC_DATA_NONE;
1442 return STATUS_INVALID_PARAMETER;
1445 io = ioctl(fd, CDROM_SEND_PACKET, &cmd);
1447 if (pPacket->SenseInfoLength != 0)
1449 memcpy((char*)pPacket + pPacket->SenseInfoOffset,
1450 &sense, pPacket->SenseInfoLength);
1453 pPacket->ScsiStatus = cmd.stat;
1455 ret = CDROM_GetStatusCode(io);
1457 #elif defined(__NetBSD__)
1461 if (pPacket->Length < sizeof(SCSI_PASS_THROUGH_DIRECT))
1462 return STATUS_BUFFER_TOO_SMALL;
1464 if (pPacket->CdbLength > 12)
1465 return STATUS_INVALID_PARAMETER;
1467 if (pPacket->SenseInfoLength > SENSEBUFLEN)
1468 return STATUS_INVALID_PARAMETER;
1470 memset(&cmd, 0, sizeof(cmd));
1471 memcpy(&(cmd.cmd), &(pPacket->Cdb), pPacket->CdbLength);
1473 cmd.cmdlen = pPacket->CdbLength;
1474 cmd.databuf = pPacket->DataBuffer;
1475 cmd.datalen = pPacket->DataTransferLength;
1476 cmd.senselen = pPacket->SenseInfoLength;
1477 cmd.timeout = pPacket->TimeOutValue*1000; /* in milliseconds */
1479 switch (pPacket->DataIn)
1481 case SCSI_IOCTL_DATA_OUT:
1482 cmd.flags |= SCCMD_WRITE;
1484 case SCSI_IOCTL_DATA_IN:
1485 cmd.flags |= SCCMD_READ;
1487 case SCSI_IOCTL_DATA_UNSPECIFIED:
1491 return STATUS_INVALID_PARAMETER;
1494 io = ioctl(fd, SCIOCCOMMAND, &cmd);
1498 case SCCMD_OK: break;
1499 case SCCMD_TIMEOUT: return STATUS_TIMEOUT;
1501 case SCCMD_BUSY: return STATUS_DEVICE_BUSY;
1503 case SCCMD_SENSE: break;
1504 case SCCMD_UNKNOWN: return STATUS_UNSUCCESSFUL;
1508 if (pPacket->SenseInfoLength != 0)
1510 memcpy((char*)pPacket + pPacket->SenseInfoOffset,
1511 cmd.sense, pPacket->SenseInfoLength);
1514 pPacket->ScsiStatus = cmd.status;
1516 ret = CDROM_GetStatusCode(io);
1521 /******************************************************************
1522 * CDROM_ScsiPassThrough
1526 static NTSTATUS CDROM_ScsiPassThrough(int fd, PSCSI_PASS_THROUGH pPacket)
1528 int ret = STATUS_NOT_SUPPORTED;
1529 #if defined(linux) && defined(CDROM_SEND_PACKET)
1530 struct linux_cdrom_generic_command cmd;
1531 struct request_sense sense;
1534 if (pPacket->Length < sizeof(SCSI_PASS_THROUGH))
1535 return STATUS_BUFFER_TOO_SMALL;
1537 if (pPacket->CdbLength > 12)
1538 return STATUS_INVALID_PARAMETER;
1540 if (pPacket->SenseInfoLength > sizeof(sense))
1541 return STATUS_INVALID_PARAMETER;
1543 memset(&cmd, 0, sizeof(cmd));
1544 memset(&sense, 0, sizeof(sense));
1546 memcpy(&(cmd.cmd), &(pPacket->Cdb), pPacket->CdbLength);
1548 if ( pPacket->DataBufferOffset > 0x1000 )
1550 cmd.buffer = (void*)pPacket->DataBufferOffset;
1554 cmd.buffer = (char*)pPacket + pPacket->DataBufferOffset;
1556 cmd.buflen = pPacket->DataTransferLength;
1559 cmd.timeout = pPacket->TimeOutValue*HZ;
1561 switch (pPacket->DataIn)
1563 case SCSI_IOCTL_DATA_OUT:
1564 cmd.data_direction = CGC_DATA_WRITE;
1566 case SCSI_IOCTL_DATA_IN:
1567 cmd.data_direction = CGC_DATA_READ;
1569 case SCSI_IOCTL_DATA_UNSPECIFIED:
1570 cmd.data_direction = CGC_DATA_NONE;
1573 return STATUS_INVALID_PARAMETER;
1576 io = ioctl(fd, CDROM_SEND_PACKET, &cmd);
1578 if (pPacket->SenseInfoLength != 0)
1580 memcpy((char*)pPacket + pPacket->SenseInfoOffset,
1581 &sense, pPacket->SenseInfoLength);
1584 pPacket->ScsiStatus = cmd.stat;
1586 ret = CDROM_GetStatusCode(io);
1588 #elif defined(__NetBSD__)
1592 if (pPacket->Length < sizeof(SCSI_PASS_THROUGH))
1593 return STATUS_BUFFER_TOO_SMALL;
1595 if (pPacket->CdbLength > 12)
1596 return STATUS_INVALID_PARAMETER;
1598 if (pPacket->SenseInfoLength > SENSEBUFLEN)
1599 return STATUS_INVALID_PARAMETER;
1601 memset(&cmd, 0, sizeof(cmd));
1602 memcpy(&(cmd.cmd), &(pPacket->Cdb), pPacket->CdbLength);
1604 if ( pPacket->DataBufferOffset > 0x1000 )
1606 cmd.databuf = (void*)pPacket->DataBufferOffset;
1610 cmd.databuf = (char*)pPacket + pPacket->DataBufferOffset;
1613 cmd.cmdlen = pPacket->CdbLength;
1614 cmd.datalen = pPacket->DataTransferLength;
1615 cmd.senselen = pPacket->SenseInfoLength;
1616 cmd.timeout = pPacket->TimeOutValue*1000; /* in milliseconds */
1618 switch (pPacket->DataIn)
1620 case SCSI_IOCTL_DATA_OUT:
1621 cmd.flags |= SCCMD_WRITE;
1623 case SCSI_IOCTL_DATA_IN:
1624 cmd.flags |= SCCMD_READ;
1626 case SCSI_IOCTL_DATA_UNSPECIFIED:
1630 return STATUS_INVALID_PARAMETER;
1633 io = ioctl(fd, SCIOCCOMMAND, &cmd);
1637 case SCCMD_OK: break;
1638 case SCCMD_TIMEOUT: return STATUS_TIMEOUT;
1640 case SCCMD_BUSY: return STATUS_DEVICE_BUSY;
1642 case SCCMD_SENSE: break;
1643 case SCCMD_UNKNOWN: return STATUS_UNSUCCESSFUL;
1647 if (pPacket->SenseInfoLength != 0)
1649 memcpy((char*)pPacket + pPacket->SenseInfoOffset,
1650 cmd.sense, pPacket->SenseInfoLength);
1653 pPacket->ScsiStatus = cmd.status;
1655 ret = CDROM_GetStatusCode(io);
1660 /******************************************************************
1665 static NTSTATUS CDROM_ScsiGetCaps(PIO_SCSI_CAPABILITIES caps)
1667 NTSTATUS ret = STATUS_NOT_IMPLEMENTED;
1669 caps->Length = sizeof(*caps);
1671 caps->MaximumTransferLength = SG_SCATTER_SZ; /* FIXME */
1672 caps->MaximumPhysicalPages = SG_SCATTER_SZ / getpagesize();
1673 caps->SupportedAsynchronousEvents = TRUE;
1674 caps->AlignmentMask = getpagesize();
1675 caps->TaggedQueuing = FALSE; /* we could check that it works and answer TRUE */
1676 caps->AdapterScansDown = FALSE; /* FIXME ? */
1677 caps->AdapterUsesPio = FALSE; /* FIXME ? */
1678 ret = STATUS_SUCCESS;
1680 FIXME("Unimplemented\n");
1685 /******************************************************************
1688 * implements IOCTL_SCSI_GET_ADDRESS
1690 static NTSTATUS CDROM_GetAddress(int fd, SCSI_ADDRESS* address)
1692 int portnum, busid, targetid, lun;
1694 address->Length = sizeof(SCSI_ADDRESS);
1695 if ( ! CDROM_GetInterfaceInfo(fd, &portnum, &busid, &targetid, &lun))
1696 return STATUS_NOT_SUPPORTED;
1698 address->PortNumber = portnum;
1699 address->PathId = busid; /* bus number */
1700 address->TargetId = targetid;
1702 return STATUS_SUCCESS;
1705 /******************************************************************
1710 static NTSTATUS DVD_StartSession(int fd, PDVD_SESSION_ID sid_in, PDVD_SESSION_ID sid_out)
1713 NTSTATUS ret = STATUS_NOT_SUPPORTED;
1714 dvd_authinfo auth_info;
1716 memset( &auth_info, 0, sizeof( auth_info ) );
1717 auth_info.type = DVD_LU_SEND_AGID;
1718 if (sid_in) auth_info.lsa.agid = *(int*)sid_in; /* ?*/
1720 TRACE("fd 0x%08x\n",fd);
1721 ret =CDROM_GetStatusCode(ioctl(fd, DVD_AUTH, &auth_info));
1722 *sid_out = auth_info.lsa.agid;
1724 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1725 return STATUS_NOT_SUPPORTED;
1727 return STATUS_NOT_SUPPORTED;
1731 /******************************************************************
1736 static NTSTATUS DVD_EndSession(int fd, PDVD_SESSION_ID sid)
1739 dvd_authinfo auth_info;
1741 memset( &auth_info, 0, sizeof( auth_info ) );
1742 auth_info.type = DVD_INVALIDATE_AGID;
1743 auth_info.lsa.agid = *(int*)sid;
1746 return CDROM_GetStatusCode(ioctl(fd, DVD_AUTH, &auth_info));
1747 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1748 return STATUS_NOT_SUPPORTED;
1750 return STATUS_NOT_SUPPORTED;
1754 /******************************************************************
1759 static NTSTATUS DVD_SendKey(int fd, PDVD_COPY_PROTECT_KEY key)
1762 NTSTATUS ret = STATUS_NOT_SUPPORTED;
1763 dvd_authinfo auth_info;
1765 memset( &auth_info, 0, sizeof( auth_info ) );
1766 switch (key->KeyType)
1768 case DvdChallengeKey:
1769 auth_info.type = DVD_HOST_SEND_CHALLENGE;
1770 auth_info.hsc.agid = (int)key->SessionId;
1771 TRACE("DvdChallengeKey ioc 0x%x\n", DVD_AUTH );
1772 memcpy( auth_info.hsc.chal, key->KeyData, DVD_CHALLENGE_SIZE );
1773 ret = CDROM_GetStatusCode(ioctl( fd, DVD_AUTH, &auth_info ));
1776 auth_info.type = DVD_HOST_SEND_KEY2;
1777 auth_info.hsk.agid = (int)key->SessionId;
1779 memcpy( auth_info.hsk.key, key->KeyData, DVD_KEY_SIZE );
1781 TRACE("DvdBusKey2\n");
1782 ret = CDROM_GetStatusCode(ioctl( fd, DVD_AUTH, &auth_info ));
1786 FIXME("Unknown Keytype 0x%x\n",key->KeyType);
1789 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1791 return STATUS_NOT_SUPPORTED;
1794 return STATUS_NOT_SUPPORTED;
1796 TRACE("not reached\n");
1799 /******************************************************************
1804 static NTSTATUS DVD_ReadKey(int fd, PDVD_COPY_PROTECT_KEY key)
1807 NTSTATUS ret = STATUS_NOT_SUPPORTED;
1809 dvd_authinfo auth_info;
1811 memset( &dvd, 0, sizeof( dvd_struct ) );
1812 memset( &auth_info, 0, sizeof( auth_info ) );
1813 switch (key->KeyType)
1817 dvd.type = DVD_STRUCT_DISCKEY;
1818 dvd.disckey.agid = (int)key->SessionId;
1819 memset( dvd.disckey.value, 0, DVD_DISCKEY_SIZE );
1821 TRACE("DvdDiskKey\n");
1822 ret = CDROM_GetStatusCode(ioctl( fd, DVD_READ_STRUCT, &dvd ));
1823 if (ret == STATUS_SUCCESS)
1824 memcpy(key->KeyData,dvd.disckey.value,DVD_DISCKEY_SIZE);
1827 auth_info.type = DVD_LU_SEND_TITLE_KEY;
1828 auth_info.lstk.agid = (int)key->SessionId;
1829 auth_info.lstk.lba = (int)(key->Parameters.TitleOffset.QuadPart>>11);
1830 TRACE("DvdTitleKey session %d Quadpart 0x%08lx offset 0x%08x\n",
1831 (int)key->SessionId, (long)key->Parameters.TitleOffset.QuadPart,
1832 auth_info.lstk.lba);
1833 ret = CDROM_GetStatusCode(ioctl( fd, DVD_AUTH, &auth_info ));
1834 if (ret == STATUS_SUCCESS)
1835 memcpy(key->KeyData, auth_info.lstk.title_key, DVD_KEY_SIZE );
1837 case DvdChallengeKey:
1839 auth_info.type = DVD_LU_SEND_CHALLENGE;
1840 auth_info.lsc.agid = (int)key->SessionId;
1842 TRACE("DvdChallengeKey\n");
1843 ret = CDROM_GetStatusCode(ioctl( fd, DVD_AUTH, &auth_info ));
1844 if (ret == STATUS_SUCCESS)
1845 memcpy( key->KeyData, auth_info.lsc.chal, DVD_CHALLENGE_SIZE );
1848 auth_info.type = DVD_LU_SEND_ASF;
1850 auth_info.lsasf.asf=((PDVD_ASF)key->KeyData)->SuccessFlag;
1851 ret = CDROM_GetStatusCode(ioctl( fd, DVD_AUTH, &auth_info ));
1852 ((PDVD_ASF)key->KeyData)->SuccessFlag = auth_info.lsasf.asf;
1855 auth_info.type = DVD_LU_SEND_KEY1;
1856 auth_info.lsk.agid = (int)key->SessionId;
1858 TRACE("DvdBusKey1\n");
1859 ret = CDROM_GetStatusCode(ioctl( fd, DVD_AUTH, &auth_info ));
1861 if (ret == STATUS_SUCCESS)
1862 memcpy( key->KeyData, auth_info.lsk.key, DVD_KEY_SIZE );
1865 auth_info.type = DVD_LU_SEND_RPC_STATE;
1867 TRACE("DvdGetRpcKey\n");
1868 ret = CDROM_GetStatusCode(ioctl( fd, DVD_AUTH, &auth_info ));
1870 if (ret == STATUS_SUCCESS)
1872 ((PDVD_RPC_KEY)key->KeyData)->TypeCode = auth_info.lrpcs.type;
1873 ((PDVD_RPC_KEY)key->KeyData)->RegionMask = auth_info.lrpcs.region_mask;
1874 ((PDVD_RPC_KEY)key->KeyData)->RpcScheme = auth_info.lrpcs.rpc_scheme;
1878 FIXME("Unknown keytype 0x%x\n",key->KeyType);
1881 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1883 return STATUS_NOT_SUPPORTED;
1886 return STATUS_NOT_SUPPORTED;
1888 TRACE("not reached\n");
1891 /******************************************************************
1896 static NTSTATUS DVD_GetRegion(int dev, PDVD_REGION region)
1899 return STATUS_SUCCESS;
1903 /******************************************************************
1908 static NTSTATUS DVD_ReadStructure(int dev, PDVD_READ_STRUCTURE structure, PDVD_LAYER_DESCRIPTOR layer)
1911 return STATUS_SUCCESS;
1914 /******************************************************************
1915 * CDROM_DeviceIoControl
1919 NTSTATUS CDROM_DeviceIoControl(HANDLE hDevice,
1920 HANDLE hEvent, PIO_APC_ROUTINE UserApcRoutine,
1921 PVOID UserApcContext,
1922 PIO_STATUS_BLOCK piosb,
1923 ULONG dwIoControlCode,
1924 LPVOID lpInBuffer, DWORD nInBufferSize,
1925 LPVOID lpOutBuffer, DWORD nOutBufferSize)
1928 NTSTATUS status = STATUS_SUCCESS;
1931 TRACE("%lx %s %lx %ld %lx %ld %p\n",
1932 (DWORD)hDevice, iocodex(dwIoControlCode), (DWORD)lpInBuffer, nInBufferSize,
1933 (DWORD)lpOutBuffer, nOutBufferSize, piosb);
1935 piosb->Information = 0;
1937 if ((status = wine_server_handle_to_fd( hDevice, 0, &fd, NULL ))) goto error;
1938 if ((status = CDROM_Open(fd, &dev)))
1940 wine_server_release_fd( hDevice, fd );
1944 switch (dwIoControlCode)
1946 case IOCTL_STORAGE_CHECK_VERIFY:
1947 case IOCTL_CDROM_CHECK_VERIFY:
1949 CDROM_ClearCacheEntry(dev);
1950 if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
1951 status = STATUS_INVALID_PARAMETER;
1952 else status = CDROM_Verify(dev, fd);
1955 /* EPP case IOCTL_STORAGE_CHECK_VERIFY2: */
1957 /* EPP case IOCTL_STORAGE_FIND_NEW_DEVICES: */
1958 /* EPP case IOCTL_CDROM_FIND_NEW_DEVICES: */
1960 case IOCTL_STORAGE_LOAD_MEDIA:
1961 case IOCTL_CDROM_LOAD_MEDIA:
1963 CDROM_ClearCacheEntry(dev);
1964 if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
1965 status = STATUS_INVALID_PARAMETER;
1966 else status = CDROM_SetTray(fd, FALSE);
1968 case IOCTL_STORAGE_EJECT_MEDIA:
1970 CDROM_ClearCacheEntry(dev);
1971 if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
1972 status = STATUS_INVALID_PARAMETER;
1973 else status = CDROM_SetTray(fd, TRUE);
1976 case IOCTL_CDROM_MEDIA_REMOVAL:
1977 case IOCTL_DISK_MEDIA_REMOVAL:
1978 case IOCTL_STORAGE_MEDIA_REMOVAL:
1979 case IOCTL_STORAGE_EJECTION_CONTROL:
1980 /* FIXME the last ioctl:s is not the same as the two others...
1981 * lockcount/owner should be handled */
1983 CDROM_ClearCacheEntry(dev);
1984 if (lpOutBuffer != NULL || nOutBufferSize != 0) status = STATUS_INVALID_PARAMETER;
1985 else if (nInBufferSize < sizeof(PREVENT_MEDIA_REMOVAL)) status = STATUS_BUFFER_TOO_SMALL;
1986 else status = CDROM_ControlEjection(fd, (const PREVENT_MEDIA_REMOVAL*)lpInBuffer);
1989 /* EPP case IOCTL_STORAGE_GET_MEDIA_TYPES: */
1991 case IOCTL_STORAGE_GET_DEVICE_NUMBER:
1992 sz = sizeof(STORAGE_DEVICE_NUMBER);
1993 if (lpInBuffer != NULL || nInBufferSize != 0) status = STATUS_INVALID_PARAMETER;
1994 else if (nOutBufferSize < sz) status = STATUS_BUFFER_TOO_SMALL;
1995 else status = CDROM_GetDeviceNumber(dev, (STORAGE_DEVICE_NUMBER*)lpOutBuffer);
1998 case IOCTL_STORAGE_RESET_DEVICE:
2000 CDROM_ClearCacheEntry(dev);
2001 if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
2002 status = STATUS_INVALID_PARAMETER;
2003 else status = CDROM_ResetAudio(fd);
2006 case IOCTL_CDROM_GET_CONTROL:
2007 sz = sizeof(CDROM_AUDIO_CONTROL);
2008 if (lpInBuffer != NULL || nInBufferSize != 0) status = STATUS_INVALID_PARAMETER;
2009 else if (nOutBufferSize < sz) status = STATUS_BUFFER_TOO_SMALL;
2010 else status = CDROM_GetControl(dev, (CDROM_AUDIO_CONTROL*)lpOutBuffer);
2013 case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
2014 sz = sizeof(DISK_GEOMETRY);
2015 if (lpInBuffer != NULL || nInBufferSize != 0) status = STATUS_INVALID_PARAMETER;
2016 else if (nOutBufferSize < sz) status = STATUS_BUFFER_TOO_SMALL;
2017 else status = CDROM_GetDriveGeometry(dev, fd, (DISK_GEOMETRY*)lpOutBuffer);
2020 case IOCTL_CDROM_DISK_TYPE:
2021 sz = sizeof(CDROM_DISK_DATA);
2022 /* CDROM_ClearCacheEntry(dev); */
2023 if (lpInBuffer != NULL || nInBufferSize != 0) status = STATUS_INVALID_PARAMETER;
2024 else if (nOutBufferSize < sz) status = STATUS_BUFFER_TOO_SMALL;
2025 else status = CDROM_GetDiskData(dev, fd, (CDROM_DISK_DATA*)lpOutBuffer);
2028 /* EPP case IOCTL_CDROM_GET_LAST_SESSION: */
2030 case IOCTL_CDROM_READ_Q_CHANNEL:
2031 sz = sizeof(SUB_Q_CHANNEL_DATA);
2032 if (lpInBuffer == NULL || nInBufferSize < sizeof(CDROM_SUB_Q_DATA_FORMAT))
2033 status = STATUS_INVALID_PARAMETER;
2034 else if (nOutBufferSize < sz) status = STATUS_BUFFER_TOO_SMALL;
2035 else status = CDROM_ReadQChannel(dev, fd, (const CDROM_SUB_Q_DATA_FORMAT*)lpInBuffer,
2036 (SUB_Q_CHANNEL_DATA*)lpOutBuffer);
2039 case IOCTL_CDROM_READ_TOC:
2040 sz = sizeof(CDROM_TOC);
2041 if (lpInBuffer != NULL || nInBufferSize != 0) status = STATUS_INVALID_PARAMETER;
2042 else if (nOutBufferSize < sz) status = STATUS_BUFFER_TOO_SMALL;
2043 else status = CDROM_ReadTOC(dev, fd, (CDROM_TOC*)lpOutBuffer);
2046 /* EPP case IOCTL_CDROM_READ_TOC_EX: */
2048 case IOCTL_CDROM_PAUSE_AUDIO:
2050 if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
2051 status = STATUS_INVALID_PARAMETER;
2052 else status = CDROM_PauseAudio(fd);
2054 case IOCTL_CDROM_PLAY_AUDIO_MSF:
2056 if (lpOutBuffer != NULL || nOutBufferSize != 0) status = STATUS_INVALID_PARAMETER;
2057 else if (nInBufferSize < sizeof(CDROM_PLAY_AUDIO_MSF)) status = STATUS_BUFFER_TOO_SMALL;
2058 else status = CDROM_PlayAudioMSF(fd, (const CDROM_PLAY_AUDIO_MSF*)lpInBuffer);
2060 case IOCTL_CDROM_RESUME_AUDIO:
2062 if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
2063 status = STATUS_INVALID_PARAMETER;
2064 else status = CDROM_ResumeAudio(fd);
2066 case IOCTL_CDROM_SEEK_AUDIO_MSF:
2068 if (lpOutBuffer != NULL || nOutBufferSize != 0) status = STATUS_INVALID_PARAMETER;
2069 else if (nInBufferSize < sizeof(CDROM_SEEK_AUDIO_MSF)) status = STATUS_BUFFER_TOO_SMALL;
2070 else status = CDROM_SeekAudioMSF(dev, fd, (const CDROM_SEEK_AUDIO_MSF*)lpInBuffer);
2072 case IOCTL_CDROM_STOP_AUDIO:
2074 CDROM_ClearCacheEntry(dev); /* Maybe intention is to change media */
2075 if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
2076 status = STATUS_INVALID_PARAMETER;
2077 else status = CDROM_StopAudio(fd);
2079 case IOCTL_CDROM_GET_VOLUME:
2080 sz = sizeof(VOLUME_CONTROL);
2081 if (lpInBuffer != NULL || nInBufferSize != 0) status = STATUS_INVALID_PARAMETER;
2082 else if (nOutBufferSize < sz) status = STATUS_BUFFER_TOO_SMALL;
2083 else status = CDROM_GetVolume(fd, (VOLUME_CONTROL*)lpOutBuffer);
2085 case IOCTL_CDROM_SET_VOLUME:
2087 CDROM_ClearCacheEntry(dev);
2088 if (lpInBuffer == NULL || nInBufferSize < sizeof(VOLUME_CONTROL) || lpOutBuffer != NULL)
2089 status = STATUS_INVALID_PARAMETER;
2090 else status = CDROM_SetVolume(fd, (const VOLUME_CONTROL*)lpInBuffer);
2092 case IOCTL_CDROM_RAW_READ:
2094 if (nInBufferSize < sizeof(RAW_READ_INFO)) status = STATUS_INVALID_PARAMETER;
2095 else if (lpOutBuffer == NULL) status = STATUS_BUFFER_TOO_SMALL;
2096 else status = CDROM_RawRead(fd, (const RAW_READ_INFO*)lpInBuffer,
2097 lpOutBuffer, nOutBufferSize, &sz);
2099 case IOCTL_SCSI_GET_ADDRESS:
2100 sz = sizeof(SCSI_ADDRESS);
2101 if (lpInBuffer != NULL || nInBufferSize != 0) status = STATUS_INVALID_PARAMETER;
2102 else if (nOutBufferSize < sz) status = STATUS_BUFFER_TOO_SMALL;
2103 else status = CDROM_GetAddress(fd, (SCSI_ADDRESS*)lpOutBuffer);
2105 case IOCTL_SCSI_PASS_THROUGH_DIRECT:
2106 sz = sizeof(SCSI_PASS_THROUGH_DIRECT);
2107 if (lpOutBuffer == NULL) status = STATUS_INVALID_PARAMETER;
2108 else if (nOutBufferSize < sizeof(SCSI_PASS_THROUGH_DIRECT)) status = STATUS_BUFFER_TOO_SMALL;
2109 else status = CDROM_ScsiPassThroughDirect(fd, (PSCSI_PASS_THROUGH_DIRECT)lpOutBuffer);
2111 case IOCTL_SCSI_PASS_THROUGH:
2112 sz = sizeof(SCSI_PASS_THROUGH);
2113 if (lpOutBuffer == NULL) status = STATUS_INVALID_PARAMETER;
2114 else if (nOutBufferSize < sizeof(SCSI_PASS_THROUGH)) status = STATUS_BUFFER_TOO_SMALL;
2115 else status = CDROM_ScsiPassThrough(fd, (PSCSI_PASS_THROUGH)lpOutBuffer);
2117 case IOCTL_SCSI_GET_CAPABILITIES:
2118 sz = sizeof(IO_SCSI_CAPABILITIES);
2119 if (lpOutBuffer == NULL) status = STATUS_INVALID_PARAMETER;
2120 else if (nOutBufferSize < sizeof(IO_SCSI_CAPABILITIES)) status = STATUS_BUFFER_TOO_SMALL;
2121 else status = CDROM_ScsiGetCaps((PIO_SCSI_CAPABILITIES)lpOutBuffer);
2123 case IOCTL_DVD_START_SESSION:
2124 sz = sizeof(DVD_SESSION_ID);
2125 if (lpOutBuffer == NULL) status = STATUS_INVALID_PARAMETER;
2126 else if (nOutBufferSize < sz) status = STATUS_BUFFER_TOO_SMALL;
2129 TRACE("before in 0x%08lx out 0x%08lx\n",(lpInBuffer)?*(PDVD_SESSION_ID)lpInBuffer:0,
2130 *(PDVD_SESSION_ID)lpOutBuffer);
2131 status = DVD_StartSession(fd, (PDVD_SESSION_ID)lpInBuffer, (PDVD_SESSION_ID)lpOutBuffer);
2132 TRACE("before in 0x%08lx out 0x%08lx\n",(lpInBuffer)?*(PDVD_SESSION_ID)lpInBuffer:0,
2133 *(PDVD_SESSION_ID)lpOutBuffer);
2136 case IOCTL_DVD_END_SESSION:
2137 sz = sizeof(DVD_SESSION_ID);
2138 if ((lpInBuffer == NULL) || (nInBufferSize < sz))status = STATUS_INVALID_PARAMETER;
2139 else status = DVD_EndSession(fd, (PDVD_SESSION_ID)lpInBuffer);
2141 case IOCTL_DVD_SEND_KEY:
2144 (((PDVD_COPY_PROTECT_KEY)lpInBuffer)->KeyLength != nInBufferSize))
2145 status = STATUS_INVALID_PARAMETER;
2148 TRACE("doing DVD_SendKey\n");
2149 status = DVD_SendKey(fd, (PDVD_COPY_PROTECT_KEY)lpInBuffer);
2152 case IOCTL_DVD_READ_KEY:
2154 (((PDVD_COPY_PROTECT_KEY)lpInBuffer)->KeyLength != nInBufferSize))
2155 status = STATUS_INVALID_PARAMETER;
2156 else if (lpInBuffer !=lpOutBuffer) status = STATUS_BUFFER_TOO_SMALL;
2159 TRACE("doing DVD_READ_KEY\n");
2160 sz = ((PDVD_COPY_PROTECT_KEY)lpInBuffer)->KeyLength;
2161 status = DVD_ReadKey(fd, (PDVD_COPY_PROTECT_KEY)lpInBuffer);
2164 case IOCTL_DVD_GET_REGION:
2165 sz = sizeof(DVD_REGION);
2166 if (lpInBuffer != NULL || nInBufferSize != 0) status = STATUS_INVALID_PARAMETER;
2167 else if (nOutBufferSize < sz) status = STATUS_BUFFER_TOO_SMALL;
2168 TRACE("doing DVD_Get_REGION\n");
2169 status = DVD_GetRegion(fd, (PDVD_REGION)lpOutBuffer);
2171 case IOCTL_DVD_READ_STRUCTURE:
2172 sz = sizeof(DVD_LAYER_DESCRIPTOR);
2173 if (lpInBuffer == NULL || nInBufferSize != sizeof(DVD_READ_STRUCTURE)) status = STATUS_INVALID_PARAMETER;
2174 else if (nOutBufferSize < sz) status = STATUS_BUFFER_TOO_SMALL;
2175 TRACE("doing DVD_READ_STRUCTURE\n");
2176 status = DVD_ReadStructure(fd, (PDVD_READ_STRUCTURE)lpInBuffer, (PDVD_LAYER_DESCRIPTOR)lpOutBuffer);
2180 FIXME("Unsupported IOCTL %lx (type=%lx access=%lx func=%lx meth=%lx)\n",
2181 dwIoControlCode, dwIoControlCode >> 16, (dwIoControlCode >> 14) & 3,
2182 (dwIoControlCode >> 2) & 0xFFF, dwIoControlCode & 3);
2184 status = STATUS_INVALID_PARAMETER;
2187 wine_server_release_fd( hDevice, fd );
2189 piosb->u.Status = status;
2190 piosb->Information = sz;
2191 if (hEvent) NtSetEvent(hEvent, NULL);