Release 1.1.37.
[wine/gsoc-2012-control.git] / dlls / ntdll / cdrom.c
blob069ac015b923b7587a59ce3b510d149fa7105dcd
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
7 * Copyright 2005 Ivan Leo Puoti
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
25 #include "wine/port.h"
27 #include <errno.h>
28 #include <string.h>
29 #include <stdarg.h>
30 #include <stdio.h>
31 #ifdef HAVE_IO_H
32 # include <io.h>
33 #endif
34 #ifdef HAVE_UNISTD_H
35 # include <unistd.h>
36 #endif
37 #include <fcntl.h>
38 #ifdef HAVE_SYS_STAT_H
39 # include <sys/stat.h>
40 #endif
41 #include <sys/types.h>
43 #ifdef HAVE_SYS_IOCTL_H
44 #include <sys/ioctl.h>
45 #endif
46 #ifdef HAVE_SCSI_SG_H
47 # include <scsi/sg.h>
48 #endif
49 #ifdef HAVE_SCSI_SCSI_H
50 # include <scsi/scsi.h>
51 # undef REASSIGN_BLOCKS /* avoid conflict with winioctl.h */
52 # undef FAILED /* avoid conflict with winerror.h */
53 #endif
54 #ifdef HAVE_SCSI_SCSI_IOCTL_H
55 # include <scsi/scsi_ioctl.h>
56 #endif
57 #ifdef HAVE_LINUX_MAJOR_H
58 # include <linux/major.h>
59 #endif
60 #ifdef HAVE_LINUX_HDREG_H
61 # include <linux/hdreg.h>
62 #endif
63 #ifdef HAVE_LINUX_PARAM_H
64 # include <linux/param.h>
65 #endif
66 #ifdef HAVE_LINUX_CDROM_H
67 # include <linux/cdrom.h>
68 #endif
69 #ifdef HAVE_LINUX_UCDROM_H
70 # include <linux/ucdrom.h>
71 #endif
72 #ifdef HAVE_SYS_CDIO_H
73 # include <sys/cdio.h>
74 #endif
75 #ifdef HAVE_SYS_SCSIIO_H
76 # include <sys/scsiio.h>
77 #endif
79 #ifdef HAVE_IOKIT_IOKITLIB_H
80 # include <libkern/OSByteOrder.h>
81 # include <sys/disk.h>
82 # include <IOKit/IOKitLib.h>
83 # include <IOKit/storage/IOMedia.h>
84 # include <IOKit/storage/IOCDMediaBSDClient.h>
85 # include <IOKit/storage/IODVDMediaBSDClient.h>
86 # include <IOKit/scsi/SCSICmds_REQUEST_SENSE_Defs.h>
87 # define SENSEBUFLEN kSenseDefaultSize
88 #endif
90 #define NONAMELESSUNION
91 #define NONAMELESSSTRUCT
92 #include "ntstatus.h"
93 #define WIN32_NO_STATUS
94 #include "windef.h"
95 #include "winternl.h"
96 #include "winioctl.h"
97 #include "ntddstor.h"
98 #include "ntddcdrm.h"
99 #include "ddk/ntddcdvd.h"
100 #include "ntddscsi.h"
101 #include "ntdll_misc.h"
102 #include "wine/server.h"
103 #include "wine/library.h"
104 #include "wine/debug.h"
106 WINE_DEFAULT_DEBUG_CHANNEL(cdrom);
108 /* Non-Linux systems do not have linux/cdrom.h and the like, and thus
109 lack the following constants. */
111 #ifndef CD_SECS
112 # define CD_SECS 60 /* seconds per minute */
113 #endif
114 #ifndef CD_FRAMES
115 # define CD_FRAMES 75 /* frames per second */
116 #endif
118 static const struct iocodexs
120 DWORD code;
121 const char *codex;
122 } iocodextable[] = {
123 #define X(x) { x, #x },
124 X(IOCTL_CDROM_CHECK_VERIFY)
125 X(IOCTL_CDROM_CURRENT_POSITION)
126 X(IOCTL_CDROM_DISK_TYPE)
127 X(IOCTL_CDROM_GET_CONTROL)
128 X(IOCTL_CDROM_GET_DRIVE_GEOMETRY)
129 X(IOCTL_CDROM_GET_VOLUME)
130 X(IOCTL_CDROM_LOAD_MEDIA)
131 X(IOCTL_CDROM_MEDIA_CATALOG)
132 X(IOCTL_CDROM_MEDIA_REMOVAL)
133 X(IOCTL_CDROM_PAUSE_AUDIO)
134 X(IOCTL_CDROM_PLAY_AUDIO_MSF)
135 X(IOCTL_CDROM_RAW_READ)
136 X(IOCTL_CDROM_READ_Q_CHANNEL)
137 X(IOCTL_CDROM_READ_TOC)
138 X(IOCTL_CDROM_RESUME_AUDIO)
139 X(IOCTL_CDROM_SEEK_AUDIO_MSF)
140 X(IOCTL_CDROM_SET_VOLUME)
141 X(IOCTL_CDROM_STOP_AUDIO)
142 X(IOCTL_CDROM_TRACK_ISRC)
143 X(IOCTL_DISK_MEDIA_REMOVAL)
144 X(IOCTL_DVD_END_SESSION)
145 X(IOCTL_DVD_GET_REGION)
146 X(IOCTL_DVD_READ_KEY)
147 X(IOCTL_DVD_READ_STRUCTURE)
148 X(IOCTL_DVD_SEND_KEY)
149 X(IOCTL_DVD_START_SESSION)
150 X(IOCTL_SCSI_GET_ADDRESS)
151 X(IOCTL_SCSI_GET_CAPABILITIES)
152 X(IOCTL_SCSI_GET_INQUIRY_DATA)
153 X(IOCTL_SCSI_PASS_THROUGH)
154 X(IOCTL_SCSI_PASS_THROUGH_DIRECT)
155 X(IOCTL_STORAGE_CHECK_VERIFY)
156 X(IOCTL_STORAGE_EJECTION_CONTROL)
157 X(IOCTL_STORAGE_EJECT_MEDIA)
158 X(IOCTL_STORAGE_GET_DEVICE_NUMBER)
159 X(IOCTL_STORAGE_LOAD_MEDIA)
160 X(IOCTL_STORAGE_MEDIA_REMOVAL)
161 X(IOCTL_STORAGE_RESET_DEVICE)
162 #undef X
164 static const char *iocodex(DWORD code)
166 unsigned int i;
167 static char buffer[25];
168 for(i=0; i<sizeof(iocodextable)/sizeof(struct iocodexs); i++)
169 if (code==iocodextable[i].code)
170 return iocodextable[i].codex;
171 sprintf(buffer, "IOCTL_CODE_%x", (int)code);
172 return buffer;
175 #define INQ_REPLY_LEN 36
176 #define INQ_CMD_LEN 6
178 #define FRAME_OF_ADDR(a) (((int)(a)[1] * CD_SECS + (a)[2]) * CD_FRAMES + (a)[3])
179 #define FRAME_OF_MSF(a) (((int)(a).M * CD_SECS + (a).S) * CD_FRAMES + (a).F)
180 #define FRAME_OF_TOC(toc, idx) FRAME_OF_ADDR((toc).TrackData[idx - (toc).FirstTrack].Address)
181 #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;}
183 /* The documented format of DVD_LAYER_DESCRIPTOR is wrong. Even the format in the
184 * DDK's header is wrong. There are four bytes at the start defined by
185 * MMC-5. The first two are the size of the structure in big-endian order as
186 * defined by MMC-5. The other two are reserved.
188 typedef struct
190 UCHAR DataLength[2];
191 UCHAR Reserved0[2];
192 UCHAR BookVersion : 4;
193 UCHAR BookType : 4;
194 UCHAR MinimumRate : 4;
195 UCHAR DiskSize : 4;
196 UCHAR LayerType : 4;
197 UCHAR TrackPath : 1;
198 UCHAR NumberOfLayers : 2;
199 UCHAR Reserved1 : 1;
200 UCHAR TrackDensity : 4;
201 UCHAR LinearDensity : 4;
202 ULONG StartingDataSector;
203 ULONG EndDataSector;
204 ULONG EndLayerZeroSector;
205 UCHAR Reserved5 : 7;
206 UCHAR BCAFlag : 1;
207 UCHAR Reserved6;
208 } internal_dvd_layer_descriptor;
211 static NTSTATUS CDROM_ReadTOC(int, int, CDROM_TOC*);
212 static NTSTATUS CDROM_GetStatusCode(int);
215 #ifdef linux
217 # ifndef IDE6_MAJOR
218 # define IDE6_MAJOR 88
219 # endif
220 # ifndef IDE7_MAJOR
221 # define IDE7_MAJOR 89
222 # endif
224 # ifdef CDROM_SEND_PACKET
225 /* structure for CDROM_PACKET_COMMAND ioctl */
226 /* not all Linux versions have all the fields, so we define the
227 * structure ourselves to make sure */
228 struct linux_cdrom_generic_command
230 unsigned char cmd[CDROM_PACKET_SIZE];
231 unsigned char *buffer;
232 unsigned int buflen;
233 int stat;
234 struct request_sense *sense;
235 unsigned char data_direction;
236 int quiet;
237 int timeout;
238 void *reserved[1];
240 # endif /* CDROM_SEND_PACKET */
242 #endif /* linux */
244 /* FIXME: this is needed because we can't open simultaneously several times /dev/cdrom
245 * this should be removed when a proper device interface is implemented
247 * (WS) We need this to keep track of current position and to safely
248 * detect media changes. Besides this should provide a great speed up
249 * for toc inquiries.
251 struct cdrom_cache {
252 dev_t device;
253 ino_t inode;
254 char toc_good; /* if false, will reread TOC from disk */
255 CDROM_TOC toc;
256 SUB_Q_CURRENT_POSITION CurrentPosition;
258 /* who has more than 5 cdroms on his/her machine ?? */
259 /* FIXME: this should grow depending on the number of cdroms we install/configure
260 * at startup
262 #define MAX_CACHE_ENTRIES 5
263 static struct cdrom_cache cdrom_cache[MAX_CACHE_ENTRIES];
265 static RTL_CRITICAL_SECTION cache_section;
266 static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
268 0, 0, &cache_section,
269 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
270 0, 0, { (DWORD_PTR)(__FILE__ ": cache_section") }
272 static RTL_CRITICAL_SECTION cache_section = { &critsect_debug, -1, 0, 0, 0, 0 };
274 /* Proposed media change function: not really needed at this time */
275 /* This is a 1 or 0 type of function */
276 #if 0
277 static int CDROM_MediaChanged(int dev)
279 int i;
281 struct cdrom_tochdr hdr;
282 struct cdrom_tocentry entry;
284 if (dev < 0 || dev >= MAX_CACHE_ENTRIES)
285 return 0;
286 if ( ioctl(cdrom_cache[dev].fd, CDROMREADTOCHDR, &hdr) == -1 )
287 return 0;
289 if ( memcmp(&hdr, &cdrom_cache[dev].hdr, sizeof(struct cdrom_tochdr)) )
290 return 1;
292 for (i=hdr.cdth_trk0; i<=hdr.cdth_trk1+1; i++)
294 if (i == hdr.cdth_trk1 + 1)
296 entry.cdte_track = CDROM_LEADOUT;
297 } else {
298 entry.cdte_track = i;
300 entry.cdte_format = CDROM_MSF;
301 if ( ioctl(cdrom_cache[dev].fd, CDROMREADTOCENTRY, &entry) == -1)
302 return 0;
303 if ( memcmp(&entry, cdrom_cache[dev].entry+i-hdr.cdth_trk0,
304 sizeof(struct cdrom_tocentry)) )
305 return 1;
307 return 0;
309 #endif
312 /******************************************************************
313 * get_parent_device
315 * On Mac OS, get the device for the whole disk from a fd that points to a partition.
316 * This is ugly and inefficient, but we have no choice since the partition fd doesn't
317 * support the eject ioctl.
319 #ifdef __APPLE__
320 static NTSTATUS get_parent_device( int fd, char *name, size_t len )
322 NTSTATUS status = STATUS_NO_SUCH_FILE;
323 struct stat st;
324 int i;
325 io_service_t service;
326 CFMutableDictionaryRef dict;
327 CFTypeRef val;
329 if (fstat( fd, &st ) == -1) return FILE_GetNtStatus();
330 if (!S_ISCHR( st.st_mode )) return STATUS_OBJECT_TYPE_MISMATCH;
332 /* create a dictionary with the right major/minor numbers */
334 if (!(dict = IOServiceMatching( kIOMediaClass ))) return STATUS_NO_MEMORY;
336 i = major( st.st_rdev );
337 val = CFNumberCreate( NULL, kCFNumberIntType, &i );
338 CFDictionaryAddValue( dict, CFSTR( "BSD Major" ), val );
339 CFRelease( val );
341 i = minor( st.st_rdev );
342 val = CFNumberCreate( NULL, kCFNumberIntType, &i );
343 CFDictionaryAddValue( dict, CFSTR( "BSD Minor" ), val );
344 CFRelease( val );
346 CFDictionaryAddValue( dict, CFSTR("Removable"), kCFBooleanTrue );
348 service = IOServiceGetMatchingService( kIOMasterPortDefault, dict );
350 /* now look for the parent that has the "Whole" attribute set to TRUE */
352 while (service)
354 io_service_t parent = 0;
355 CFBooleanRef whole;
356 CFStringRef str;
357 int ok;
359 if (!IOObjectConformsTo( service, kIOMediaClass ))
360 goto next;
361 if (!(whole = IORegistryEntryCreateCFProperty( service, CFSTR("Whole"), NULL, 0 )))
362 goto next;
363 ok = (whole == kCFBooleanTrue);
364 CFRelease( whole );
365 if (!ok) goto next;
367 if ((str = IORegistryEntryCreateCFProperty( service, CFSTR("BSD Name"), NULL, 0 )))
369 strcpy( name, "/dev/r" );
370 CFStringGetCString( str, name + 6, len - 6, kCFStringEncodingUTF8 );
371 CFRelease( str );
372 status = STATUS_SUCCESS;
374 IOObjectRelease( service );
375 break;
377 next:
378 IORegistryEntryGetParentEntry( service, kIOServicePlane, &parent );
379 IOObjectRelease( service );
380 service = parent;
382 return status;
384 #endif
387 /******************************************************************
388 * CDROM_SyncCache [internal]
390 * Read the TOC in and store it in the cdrom_cache structure.
391 * Further requests for the TOC will be copied from the cache
392 * unless certain events like disk ejection is detected, in which
393 * case the cache will be cleared, causing it to be resynced.
394 * The cache section must be held by caller.
396 static NTSTATUS CDROM_SyncCache(int dev, int fd)
398 #ifdef linux
399 int i, tsz;
400 struct cdrom_tochdr hdr;
401 struct cdrom_tocentry entry;
403 CDROM_TOC *toc = &cdrom_cache[dev].toc;
404 cdrom_cache[dev].toc_good = 0;
406 if (ioctl(fd, CDROMREADTOCHDR, &hdr) == -1)
408 WARN("(%d) -- Error occurred (%s)!\n", dev, strerror(errno));
409 return FILE_GetNtStatus();
412 toc->FirstTrack = hdr.cdth_trk0;
413 toc->LastTrack = hdr.cdth_trk1;
414 tsz = sizeof(toc->FirstTrack) + sizeof(toc->LastTrack)
415 + sizeof(TRACK_DATA) * (toc->LastTrack-toc->FirstTrack+2);
416 toc->Length[0] = tsz >> 8;
417 toc->Length[1] = tsz;
419 TRACE("caching toc from=%d to=%d\n", toc->FirstTrack, toc->LastTrack );
421 for (i = toc->FirstTrack; i <= toc->LastTrack + 1; i++)
423 if (i == toc->LastTrack + 1)
424 entry.cdte_track = CDROM_LEADOUT;
425 else
426 entry.cdte_track = i;
427 entry.cdte_format = CDROM_MSF;
428 if (ioctl(fd, CDROMREADTOCENTRY, &entry) == -1)
430 WARN("error read entry (%s)\n", strerror(errno));
431 return FILE_GetNtStatus();
433 toc->TrackData[i - toc->FirstTrack].Control = entry.cdte_ctrl;
434 toc->TrackData[i - toc->FirstTrack].Adr = entry.cdte_adr;
435 /* marking last track with leadout value as index */
436 toc->TrackData[i - toc->FirstTrack].TrackNumber = entry.cdte_track;
437 toc->TrackData[i - toc->FirstTrack].Address[0] = 0;
438 toc->TrackData[i - toc->FirstTrack].Address[1] = entry.cdte_addr.msf.minute;
439 toc->TrackData[i - toc->FirstTrack].Address[2] = entry.cdte_addr.msf.second;
440 toc->TrackData[i - toc->FirstTrack].Address[3] = entry.cdte_addr.msf.frame;
442 cdrom_cache[dev].toc_good = 1;
443 return STATUS_SUCCESS;
445 #elif defined(__FreeBSD__) || defined(__NetBSD__)
447 int i, tsz;
448 struct ioc_toc_header hdr;
449 struct ioc_read_toc_entry entry;
450 struct cd_toc_entry toc_buffer;
452 CDROM_TOC *toc = &cdrom_cache[dev].toc;
453 cdrom_cache[dev].toc_good = 0;
455 if (ioctl(fd, CDIOREADTOCHEADER, &hdr) == -1)
457 WARN("(%d) -- Error occurred (%s)!\n", dev, strerror(errno));
458 return FILE_GetNtStatus();
460 toc->FirstTrack = hdr.starting_track;
461 toc->LastTrack = hdr.ending_track;
462 tsz = sizeof(toc->FirstTrack) + sizeof(toc->LastTrack)
463 + sizeof(TRACK_DATA) * (toc->LastTrack-toc->FirstTrack+2);
464 toc->Length[0] = tsz >> 8;
465 toc->Length[1] = tsz;
467 TRACE("caching toc from=%d to=%d\n", toc->FirstTrack, toc->LastTrack );
469 for (i = toc->FirstTrack; i <= toc->LastTrack + 1; i++)
471 if (i == toc->LastTrack + 1)
473 #define LEADOUT 0xaa
474 entry.starting_track = LEADOUT;
475 } else {
476 entry.starting_track = i;
478 memset(&toc_buffer, 0, sizeof(toc_buffer));
479 entry.address_format = CD_MSF_FORMAT;
480 entry.data_len = sizeof(toc_buffer);
481 entry.data = &toc_buffer;
482 if (ioctl(fd, CDIOREADTOCENTRYS, &entry) == -1)
484 WARN("error read entry (%s)\n", strerror(errno));
485 return FILE_GetNtStatus();
487 toc->TrackData[i - toc->FirstTrack].Control = toc_buffer.control;
488 toc->TrackData[i - toc->FirstTrack].Adr = toc_buffer.addr_type;
489 /* marking last track with leadout value as index */
490 toc->TrackData[i - toc->FirstTrack].TrackNumber = entry.starting_track;
491 toc->TrackData[i - toc->FirstTrack].Address[0] = 0;
492 toc->TrackData[i - toc->FirstTrack].Address[1] = toc_buffer.addr.msf.minute;
493 toc->TrackData[i - toc->FirstTrack].Address[2] = toc_buffer.addr.msf.second;
494 toc->TrackData[i - toc->FirstTrack].Address[3] = toc_buffer.addr.msf.frame;
496 cdrom_cache[dev].toc_good = 1;
497 return STATUS_SUCCESS;
499 #elif defined(__APPLE__)
500 int i;
501 dk_cd_read_toc_t hdr;
502 CDROM_TOC *toc = &cdrom_cache[dev].toc;
503 cdrom_cache[dev].toc_good = 0;
505 memset( &hdr, 0, sizeof(hdr) );
506 hdr.buffer = toc;
507 hdr.bufferLength = sizeof(*toc);
508 if (ioctl(fd, DKIOCCDREADTOC, &hdr) == -1)
510 WARN("(%d) -- Error occurred (%s)!\n", dev, strerror(errno));
511 return FILE_GetNtStatus();
513 for (i = toc->FirstTrack; i <= toc->LastTrack + 1; i++)
515 /* convert address format */
516 TRACK_DATA *data = &toc->TrackData[i - toc->FirstTrack];
517 DWORD frame = (((DWORD)data->Address[0] << 24) | ((DWORD)data->Address[1] << 16) |
518 ((DWORD)data->Address[2] << 8) | data->Address[3]);
519 MSF_OF_FRAME( data->Address[1], frame );
520 data->Address[0] = 0;
523 cdrom_cache[dev].toc_good = 1;
524 return STATUS_SUCCESS;
525 #else
526 return STATUS_NOT_SUPPORTED;
527 #endif
530 static void CDROM_ClearCacheEntry(int dev)
532 RtlEnterCriticalSection( &cache_section );
533 cdrom_cache[dev].toc_good = 0;
534 RtlLeaveCriticalSection( &cache_section );
539 /******************************************************************
540 * CDROM_GetInterfaceInfo
542 * Determines the ide interface (the number after the ide), and the
543 * number of the device on that interface for ide cdroms (*iface <= 1).
544 * Determines the scsi information for scsi cdroms (*iface >= 2).
545 * Returns false if the info cannot not be obtained.
547 static int CDROM_GetInterfaceInfo(int fd, UCHAR* iface, UCHAR* port, UCHAR* device, UCHAR* lun)
549 #if defined(linux)
550 struct stat st;
551 if ( fstat(fd, &st) == -1 || ! S_ISBLK(st.st_mode)) return 0;
552 *port = 0;
553 *iface = 0;
554 *device = 0;
555 *lun = 0;
556 switch (major(st.st_rdev)) {
557 case IDE0_MAJOR: *iface = 0; break;
558 case IDE1_MAJOR: *iface = 1; break;
559 case IDE2_MAJOR: *iface = 2; break;
560 case IDE3_MAJOR: *iface = 3; break;
561 case IDE4_MAJOR: *iface = 4; break;
562 case IDE5_MAJOR: *iface = 5; break;
563 case IDE6_MAJOR: *iface = 6; break;
564 case IDE7_MAJOR: *iface = 7; break;
565 default: *port = 1; break;
568 if (*port == 0)
569 *device = (minor(st.st_rdev) >> 6);
570 else
572 #ifdef SCSI_IOCTL_GET_IDLUN
573 UINT32 idlun[2];
574 if (ioctl(fd, SCSI_IOCTL_GET_IDLUN, idlun) != -1)
576 *port = (idlun[0] >> 24) & 0xff;
577 *iface = ((idlun[0] >> 16) & 0xff) + 2;
578 *device = idlun[0] & 0xff;
579 *lun = (idlun[0] >> 8) & 0xff;
581 else
582 #endif
584 WARN("CD-ROM device (%d, %d) not supported\n", major(st.st_rdev), minor(st.st_rdev));
585 return 0;
588 return 1;
589 #elif defined(__NetBSD__)
590 struct scsi_addr addr;
591 if (ioctl(fd, SCIOCIDENTIFY, &addr) != -1)
593 switch (addr.type)
595 case TYPE_SCSI: *port = 1;
596 *iface = addr.addr.scsi.scbus;
597 *device = addr.addr.scsi.target;
598 *lun = addr.addr.scsi.lun;
599 break;
600 case TYPE_ATAPI: *port = 0;
601 *iface = addr.addr.atapi.atbus;
602 *device = addr.addr.atapi.drive;
603 *lun = 0;
604 break;
606 return 1;
608 return 0;
609 #elif defined(__FreeBSD__)
610 FIXME("not implemented for BSD\n");
611 return 0;
612 #else
613 FIXME("not implemented for nonlinux\n");
614 return 0;
615 #endif
619 /******************************************************************
620 * CDROM_Open
623 static NTSTATUS CDROM_Open(int fd, int* dev)
625 struct stat st;
626 NTSTATUS ret = STATUS_SUCCESS;
627 int empty = -1;
629 fstat(fd, &st);
631 RtlEnterCriticalSection( &cache_section );
632 for (*dev = 0; *dev < MAX_CACHE_ENTRIES; (*dev)++)
634 if (empty == -1 &&
635 cdrom_cache[*dev].device == 0 &&
636 cdrom_cache[*dev].inode == 0)
637 empty = *dev;
638 else if (cdrom_cache[*dev].device == st.st_dev &&
639 cdrom_cache[*dev].inode == st.st_ino)
640 break;
642 if (*dev == MAX_CACHE_ENTRIES)
644 if (empty == -1) ret = STATUS_NOT_IMPLEMENTED;
645 else
647 *dev = empty;
648 cdrom_cache[*dev].device = st.st_dev;
649 cdrom_cache[*dev].inode = st.st_ino;
652 RtlLeaveCriticalSection( &cache_section );
654 TRACE("%d, %d\n", *dev, fd);
655 return ret;
658 /******************************************************************
659 * CDROM_GetStatusCode
663 static NTSTATUS CDROM_GetStatusCode(int io)
665 if (io == 0) return STATUS_SUCCESS;
666 return FILE_GetNtStatus();
669 /******************************************************************
670 * CDROM_GetControl
673 static NTSTATUS CDROM_GetControl(int dev, int fd, CDROM_AUDIO_CONTROL* cac)
675 #ifdef __APPLE__
676 uint16_t speed;
677 int io = ioctl( fd, DKIOCCDGETSPEED, &speed );
678 if (io != 0) return CDROM_GetStatusCode( io );
679 /* DKIOCCDGETSPEED returns the speed in kilobytes per second,
680 * so convert to logical blocks (assumed to be ~2 KB).
682 cac->LogicalBlocksPerSecond = speed/2;
683 #else
684 cac->LogicalBlocksPerSecond = 1; /* FIXME */
685 #endif
686 cac->LbaFormat = 0; /* FIXME */
687 return STATUS_NOT_SUPPORTED;
690 /******************************************************************
691 * CDROM_GetDeviceNumber
694 static NTSTATUS CDROM_GetDeviceNumber(int dev, STORAGE_DEVICE_NUMBER* devnum)
696 FIXME( "stub\n" );
697 devnum->DeviceType = FILE_DEVICE_DISK;
698 devnum->DeviceNumber = 1;
699 devnum->PartitionNumber = 1;
700 return STATUS_SUCCESS;
703 /******************************************************************
704 * CDROM_GetDriveGeometry
707 static NTSTATUS CDROM_GetDriveGeometry(int dev, int fd, DISK_GEOMETRY* dg)
709 CDROM_TOC toc;
710 NTSTATUS ret = 0;
711 int fsize = 0;
713 if ((ret = CDROM_ReadTOC(dev, fd, &toc)) != 0) return ret;
715 fsize = FRAME_OF_TOC(toc, toc.LastTrack+1)
716 - FRAME_OF_TOC(toc, 1); /* Total size in frames */
718 dg->Cylinders.u.LowPart = fsize / (64 * 32);
719 dg->Cylinders.u.HighPart = 0;
720 dg->MediaType = RemovableMedia;
721 dg->TracksPerCylinder = 64;
722 dg->SectorsPerTrack = 32;
723 dg->BytesPerSector= 2048;
724 return ret;
727 /**************************************************************************
728 * CDROM_Reset [internal]
730 static NTSTATUS CDROM_ResetAudio(int fd)
732 #if defined(linux)
733 return CDROM_GetStatusCode(ioctl(fd, CDROMRESET));
734 #elif defined(__FreeBSD__) || defined(__NetBSD__)
735 return CDROM_GetStatusCode(ioctl(fd, CDIOCRESET, NULL));
736 #else
737 return STATUS_NOT_SUPPORTED;
738 #endif
741 /******************************************************************
742 * CDROM_SetTray
746 static NTSTATUS CDROM_SetTray(int fd, BOOL doEject)
748 #if defined(linux)
749 return CDROM_GetStatusCode(ioctl(fd, doEject ? CDROMEJECT : CDROMCLOSETRAY));
750 #elif defined(__FreeBSD__) || defined(__NetBSD__)
751 return CDROM_GetStatusCode((ioctl(fd, CDIOCALLOW, NULL)) ||
752 (ioctl(fd, doEject ? CDIOCEJECT : CDIOCCLOSE, NULL)) ||
753 (ioctl(fd, CDIOCPREVENT, NULL)));
754 #elif defined(__APPLE__)
755 if (doEject) return CDROM_GetStatusCode( ioctl( fd, DKIOCEJECT, NULL ) );
756 else return STATUS_NOT_SUPPORTED;
757 #else
758 return STATUS_NOT_SUPPORTED;
759 #endif
762 /******************************************************************
763 * CDROM_ControlEjection
767 static NTSTATUS CDROM_ControlEjection(int fd, const PREVENT_MEDIA_REMOVAL* rmv)
769 #if defined(linux)
770 return CDROM_GetStatusCode(ioctl(fd, CDROM_LOCKDOOR, rmv->PreventMediaRemoval));
771 #elif defined(__FreeBSD__) || defined(__NetBSD__)
772 return CDROM_GetStatusCode(ioctl(fd, (rmv->PreventMediaRemoval) ? CDIOCPREVENT : CDIOCALLOW, NULL));
773 #else
774 return STATUS_NOT_SUPPORTED;
775 #endif
778 /******************************************************************
779 * CDROM_ReadTOC
783 static NTSTATUS CDROM_ReadTOC(int dev, int fd, CDROM_TOC* toc)
785 NTSTATUS ret = STATUS_NOT_SUPPORTED;
787 if (dev < 0 || dev >= MAX_CACHE_ENTRIES)
788 return STATUS_INVALID_PARAMETER;
790 RtlEnterCriticalSection( &cache_section );
791 if (cdrom_cache[dev].toc_good || !(ret = CDROM_SyncCache(dev, fd)))
793 *toc = cdrom_cache[dev].toc;
794 ret = STATUS_SUCCESS;
796 RtlLeaveCriticalSection( &cache_section );
797 return ret;
800 /******************************************************************
801 * CDROM_GetDiskData
805 static NTSTATUS CDROM_GetDiskData(int dev, int fd, CDROM_DISK_DATA* data)
807 CDROM_TOC toc;
808 NTSTATUS ret;
809 int i;
811 if ((ret = CDROM_ReadTOC(dev, fd, &toc)) != 0) return ret;
812 data->DiskData = 0;
813 for (i = toc.FirstTrack; i <= toc.LastTrack; i++) {
814 if (toc.TrackData[i-toc.FirstTrack].Control & 0x04)
815 data->DiskData |= CDROM_DISK_DATA_TRACK;
816 else
817 data->DiskData |= CDROM_DISK_AUDIO_TRACK;
819 return STATUS_SUCCESS;
822 /******************************************************************
823 * CDROM_ReadQChannel
827 static NTSTATUS CDROM_ReadQChannel(int dev, int fd, const CDROM_SUB_Q_DATA_FORMAT* fmt,
828 SUB_Q_CHANNEL_DATA* data)
830 NTSTATUS ret = STATUS_NOT_SUPPORTED;
831 #ifdef linux
832 SUB_Q_HEADER* hdr = (SUB_Q_HEADER*)data;
833 int io;
834 struct cdrom_subchnl sc;
835 sc.cdsc_format = CDROM_MSF;
837 io = ioctl(fd, CDROMSUBCHNL, &sc);
838 if (io == -1)
840 TRACE("opened or no_media (%s)!\n", strerror(errno));
841 hdr->AudioStatus = AUDIO_STATUS_NO_STATUS;
842 CDROM_ClearCacheEntry(dev);
843 goto end;
846 hdr->AudioStatus = AUDIO_STATUS_NOT_SUPPORTED;
848 switch (sc.cdsc_audiostatus) {
849 case CDROM_AUDIO_INVALID:
850 CDROM_ClearCacheEntry(dev);
851 hdr->AudioStatus = AUDIO_STATUS_NOT_SUPPORTED;
852 break;
853 case CDROM_AUDIO_NO_STATUS:
854 CDROM_ClearCacheEntry(dev);
855 hdr->AudioStatus = AUDIO_STATUS_NO_STATUS;
856 break;
857 case CDROM_AUDIO_PLAY:
858 hdr->AudioStatus = AUDIO_STATUS_IN_PROGRESS;
859 break;
860 case CDROM_AUDIO_PAUSED:
861 hdr->AudioStatus = AUDIO_STATUS_PAUSED;
862 break;
863 case CDROM_AUDIO_COMPLETED:
864 hdr->AudioStatus = AUDIO_STATUS_PLAY_COMPLETE;
865 break;
866 case CDROM_AUDIO_ERROR:
867 hdr->AudioStatus = AUDIO_STATUS_PLAY_ERROR;
868 break;
869 default:
870 TRACE("status=%02X !\n", sc.cdsc_audiostatus);
871 break;
873 switch (fmt->Format)
875 case IOCTL_CDROM_CURRENT_POSITION:
876 RtlEnterCriticalSection( &cache_section );
877 if (hdr->AudioStatus==AUDIO_STATUS_IN_PROGRESS) {
878 data->CurrentPosition.FormatCode = IOCTL_CDROM_CURRENT_POSITION;
879 data->CurrentPosition.Control = sc.cdsc_ctrl;
880 data->CurrentPosition.ADR = sc.cdsc_adr;
881 data->CurrentPosition.TrackNumber = sc.cdsc_trk;
882 data->CurrentPosition.IndexNumber = sc.cdsc_ind;
884 data->CurrentPosition.AbsoluteAddress[0] = 0;
885 data->CurrentPosition.AbsoluteAddress[1] = sc.cdsc_absaddr.msf.minute;
886 data->CurrentPosition.AbsoluteAddress[2] = sc.cdsc_absaddr.msf.second;
887 data->CurrentPosition.AbsoluteAddress[3] = sc.cdsc_absaddr.msf.frame;
889 data->CurrentPosition.TrackRelativeAddress[0] = 0;
890 data->CurrentPosition.TrackRelativeAddress[1] = sc.cdsc_reladdr.msf.minute;
891 data->CurrentPosition.TrackRelativeAddress[2] = sc.cdsc_reladdr.msf.second;
892 data->CurrentPosition.TrackRelativeAddress[3] = sc.cdsc_reladdr.msf.frame;
894 cdrom_cache[dev].CurrentPosition = data->CurrentPosition;
896 else /* not playing */
898 cdrom_cache[dev].CurrentPosition.Header = *hdr; /* Preserve header info */
899 data->CurrentPosition = cdrom_cache[dev].CurrentPosition;
901 RtlLeaveCriticalSection( &cache_section );
902 break;
903 case IOCTL_CDROM_MEDIA_CATALOG:
904 data->MediaCatalog.FormatCode = IOCTL_CDROM_MEDIA_CATALOG;
906 struct cdrom_mcn mcn;
907 if ((io = ioctl(fd, CDROM_GET_MCN, &mcn)) == -1) goto end;
909 data->MediaCatalog.FormatCode = IOCTL_CDROM_MEDIA_CATALOG;
910 data->MediaCatalog.Mcval = 0; /* FIXME */
911 memcpy(data->MediaCatalog.MediaCatalog, mcn.medium_catalog_number, 14);
912 data->MediaCatalog.MediaCatalog[14] = 0;
914 break;
915 case IOCTL_CDROM_TRACK_ISRC:
916 FIXME("TrackIsrc: NIY on linux\n");
917 data->TrackIsrc.FormatCode = IOCTL_CDROM_TRACK_ISRC;
918 data->TrackIsrc.Tcval = 0;
919 io = 0;
920 break;
923 end:
924 ret = CDROM_GetStatusCode(io);
925 #elif defined(__FreeBSD__) || defined(__NetBSD__)
926 SUB_Q_HEADER* hdr = (SUB_Q_HEADER*)data;
927 int io;
928 struct ioc_read_subchannel read_sc;
929 struct cd_sub_channel_info sc;
931 read_sc.address_format = CD_MSF_FORMAT;
932 read_sc.track = 0;
933 read_sc.data_len = sizeof(sc);
934 read_sc.data = &sc;
935 switch (fmt->Format)
937 case IOCTL_CDROM_CURRENT_POSITION:
938 read_sc.data_format = CD_CURRENT_POSITION;
939 break;
940 case IOCTL_CDROM_MEDIA_CATALOG:
941 read_sc.data_format = CD_MEDIA_CATALOG;
942 break;
943 case IOCTL_CDROM_TRACK_ISRC:
944 read_sc.data_format = CD_TRACK_INFO;
945 sc.what.track_info.track_number = data->TrackIsrc.Track;
946 break;
948 io = ioctl(fd, CDIOCREADSUBCHANNEL, &read_sc);
949 if (io == -1)
951 TRACE("opened or no_media (%s)!\n", strerror(errno));
952 CDROM_ClearCacheEntry(dev);
953 hdr->AudioStatus = AUDIO_STATUS_NO_STATUS;
954 goto end;
957 hdr->AudioStatus = AUDIO_STATUS_NOT_SUPPORTED;
959 switch (sc.header.audio_status) {
960 case CD_AS_AUDIO_INVALID:
961 CDROM_ClearCacheEntry(dev);
962 hdr->AudioStatus = AUDIO_STATUS_NOT_SUPPORTED;
963 break;
964 case CD_AS_NO_STATUS:
965 CDROM_ClearCacheEntry(dev);
966 hdr->AudioStatus = AUDIO_STATUS_NO_STATUS;
967 break;
968 case CD_AS_PLAY_IN_PROGRESS:
969 hdr->AudioStatus = AUDIO_STATUS_IN_PROGRESS;
970 break;
971 case CD_AS_PLAY_PAUSED:
972 hdr->AudioStatus = AUDIO_STATUS_PAUSED;
973 break;
974 case CD_AS_PLAY_COMPLETED:
975 hdr->AudioStatus = AUDIO_STATUS_PLAY_COMPLETE;
976 break;
977 case CD_AS_PLAY_ERROR:
978 hdr->AudioStatus = AUDIO_STATUS_PLAY_ERROR;
979 break;
980 default:
981 TRACE("status=%02X !\n", sc.header.audio_status);
983 switch (fmt->Format)
985 case IOCTL_CDROM_CURRENT_POSITION:
986 RtlEnterCriticalSection( &cache_section );
987 if (hdr->AudioStatus==AUDIO_STATUS_IN_PROGRESS) {
988 data->CurrentPosition.FormatCode = IOCTL_CDROM_CURRENT_POSITION;
989 data->CurrentPosition.Control = sc.what.position.control;
990 data->CurrentPosition.ADR = sc.what.position.addr_type;
991 data->CurrentPosition.TrackNumber = sc.what.position.track_number;
992 data->CurrentPosition.IndexNumber = sc.what.position.index_number;
994 data->CurrentPosition.AbsoluteAddress[0] = 0;
995 data->CurrentPosition.AbsoluteAddress[1] = sc.what.position.absaddr.msf.minute;
996 data->CurrentPosition.AbsoluteAddress[2] = sc.what.position.absaddr.msf.second;
997 data->CurrentPosition.AbsoluteAddress[3] = sc.what.position.absaddr.msf.frame;
998 data->CurrentPosition.TrackRelativeAddress[0] = 0;
999 data->CurrentPosition.TrackRelativeAddress[1] = sc.what.position.reladdr.msf.minute;
1000 data->CurrentPosition.TrackRelativeAddress[2] = sc.what.position.reladdr.msf.second;
1001 data->CurrentPosition.TrackRelativeAddress[3] = sc.what.position.reladdr.msf.frame;
1002 cdrom_cache[dev].CurrentPosition = data->CurrentPosition;
1004 else { /* not playing */
1005 cdrom_cache[dev].CurrentPosition.Header = *hdr; /* Preserve header info */
1006 data->CurrentPosition = cdrom_cache[dev].CurrentPosition;
1008 RtlLeaveCriticalSection( &cache_section );
1009 break;
1010 case IOCTL_CDROM_MEDIA_CATALOG:
1011 data->MediaCatalog.FormatCode = IOCTL_CDROM_MEDIA_CATALOG;
1012 data->MediaCatalog.Mcval = sc.what.media_catalog.mc_valid;
1013 memcpy(data->MediaCatalog.MediaCatalog, sc.what.media_catalog.mc_number, 15);
1014 break;
1015 case IOCTL_CDROM_TRACK_ISRC:
1016 data->TrackIsrc.FormatCode = IOCTL_CDROM_TRACK_ISRC;
1017 data->TrackIsrc.Tcval = sc.what.track_info.ti_valid;
1018 memcpy(data->TrackIsrc.TrackIsrc, sc.what.track_info.ti_number, 15);
1019 break;
1022 end:
1023 ret = CDROM_GetStatusCode(io);
1024 #elif defined(__APPLE__)
1025 SUB_Q_HEADER* hdr = (SUB_Q_HEADER*)data;
1026 int io = 0;
1027 union
1029 dk_cd_read_mcn_t mcn;
1030 dk_cd_read_isrc_t isrc;
1031 } ioc;
1032 /* We need IOCDAudioControl for IOCTL_CDROM_CURRENT_POSITION */
1033 if (fmt->Format == IOCTL_CDROM_CURRENT_POSITION)
1035 FIXME("NIY\n");
1036 return STATUS_NOT_SUPPORTED;
1038 /* No IOCDAudioControl support; just set the audio status to none */
1039 hdr->AudioStatus = AUDIO_STATUS_NO_STATUS;
1040 switch(fmt->Format)
1042 case IOCTL_CDROM_MEDIA_CATALOG:
1043 if ((io = ioctl(fd, DKIOCCDREADMCN, &ioc.mcn)) == -1) break;
1044 memcpy(data->MediaCatalog.MediaCatalog, ioc.mcn.mcn, kCDMCNMaxLength);
1045 data->MediaCatalog.Mcval = 1;
1046 break;
1047 case IOCTL_CDROM_TRACK_ISRC:
1048 ioc.isrc.track = fmt->Track;
1049 if ((io = ioctl(fd, DKIOCCDREADISRC, &ioc.isrc)) == -1) break;
1050 memcpy(data->TrackIsrc.TrackIsrc, ioc.isrc.isrc, kCDISRCMaxLength);
1051 data->TrackIsrc.Tcval = 1;
1052 data->TrackIsrc.Track = ioc.isrc.track;
1054 ret = CDROM_GetStatusCode(io);
1055 #endif
1056 return ret;
1059 /******************************************************************
1060 * CDROM_Verify
1061 * Implements: IOCTL_STORAGE_CHECK_VERIFY
1062 * IOCTL_CDROM_CHECK_VERIFY
1063 * IOCTL_DISK_CHECK_VERIFY
1066 static NTSTATUS CDROM_Verify(int dev, int fd)
1068 #if defined(linux)
1069 int ret;
1071 ret = ioctl(fd, CDROM_DRIVE_STATUS, NULL);
1072 if(ret == -1) {
1073 TRACE("ioctl CDROM_DRIVE_STATUS failed(%s)!\n", strerror(errno));
1074 return CDROM_GetStatusCode(ret);
1077 if(ret == CDS_DISC_OK)
1078 return STATUS_SUCCESS;
1079 else
1080 return STATUS_NO_MEDIA_IN_DEVICE;
1081 #elif defined(__FreeBSD__)
1082 int ret;
1083 ret = ioctl(fd, CDIOCSTART, NULL);
1084 if(ret == 0)
1085 return STATUS_SUCCESS;
1086 else
1087 return STATUS_NO_MEDIA_IN_DEVICE;
1088 #else
1089 FIXME("not implemented for non-linux\n");
1090 return STATUS_NOT_SUPPORTED;
1091 #endif
1094 /******************************************************************
1095 * CDROM_PlayAudioMSF
1099 static NTSTATUS CDROM_PlayAudioMSF(int fd, const CDROM_PLAY_AUDIO_MSF* audio_msf)
1101 NTSTATUS ret = STATUS_NOT_SUPPORTED;
1102 #ifdef linux
1103 struct cdrom_msf msf;
1104 int io;
1106 msf.cdmsf_min0 = audio_msf->StartingM;
1107 msf.cdmsf_sec0 = audio_msf->StartingS;
1108 msf.cdmsf_frame0 = audio_msf->StartingF;
1109 msf.cdmsf_min1 = audio_msf->EndingM;
1110 msf.cdmsf_sec1 = audio_msf->EndingS;
1111 msf.cdmsf_frame1 = audio_msf->EndingF;
1113 io = ioctl(fd, CDROMSTART);
1114 if (io == -1)
1116 WARN("motor doesn't start !\n");
1117 goto end;
1119 io = ioctl(fd, CDROMPLAYMSF, &msf);
1120 if (io == -1)
1122 WARN("device doesn't play !\n");
1123 goto end;
1125 TRACE("msf = %d:%d:%d %d:%d:%d\n",
1126 msf.cdmsf_min0, msf.cdmsf_sec0, msf.cdmsf_frame0,
1127 msf.cdmsf_min1, msf.cdmsf_sec1, msf.cdmsf_frame1);
1128 end:
1129 ret = CDROM_GetStatusCode(io);
1130 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1131 struct ioc_play_msf msf;
1132 int io;
1134 msf.start_m = audio_msf->StartingM;
1135 msf.start_s = audio_msf->StartingS;
1136 msf.start_f = audio_msf->StartingF;
1137 msf.end_m = audio_msf->EndingM;
1138 msf.end_s = audio_msf->EndingS;
1139 msf.end_f = audio_msf->EndingF;
1141 io = ioctl(fd, CDIOCSTART, NULL);
1142 if (io == -1)
1144 WARN("motor doesn't start !\n");
1145 goto end;
1147 io = ioctl(fd, CDIOCPLAYMSF, &msf);
1148 if (io == -1)
1150 WARN("device doesn't play !\n");
1151 goto end;
1153 TRACE("msf = %d:%d:%d %d:%d:%d\n",
1154 msf.start_m, msf.start_s, msf.start_f,
1155 msf.end_m, msf.end_s, msf.end_f);
1156 end:
1157 ret = CDROM_GetStatusCode(io);
1158 #endif
1159 return ret;
1162 /******************************************************************
1163 * CDROM_SeekAudioMSF
1167 static NTSTATUS CDROM_SeekAudioMSF(int dev, int fd, const CDROM_SEEK_AUDIO_MSF* audio_msf)
1169 CDROM_TOC toc;
1170 int i, io, frame;
1171 SUB_Q_CURRENT_POSITION *cp;
1172 #if defined(linux)
1173 struct cdrom_msf0 msf;
1174 struct cdrom_subchnl sc;
1175 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1176 struct ioc_play_msf msf;
1177 struct ioc_read_subchannel read_sc;
1178 struct cd_sub_channel_info sc;
1179 int final_frame;
1180 #endif
1182 /* Use the information on the TOC to compute the new current
1183 * position, which is shadowed on the cache. [Portable]. */
1184 frame = FRAME_OF_MSF(*audio_msf);
1186 if ((io = CDROM_ReadTOC(dev, fd, &toc)) != 0) return io;
1188 for(i=toc.FirstTrack;i<=toc.LastTrack+1;i++)
1189 if (FRAME_OF_TOC(toc,i)>frame) break;
1190 if (i <= toc.FirstTrack || i > toc.LastTrack+1)
1191 return STATUS_INVALID_PARAMETER;
1192 i--;
1193 RtlEnterCriticalSection( &cache_section );
1194 cp = &cdrom_cache[dev].CurrentPosition;
1195 cp->FormatCode = IOCTL_CDROM_CURRENT_POSITION;
1196 cp->Control = toc.TrackData[i-toc.FirstTrack].Control;
1197 cp->ADR = toc.TrackData[i-toc.FirstTrack].Adr;
1198 cp->TrackNumber = toc.TrackData[i-toc.FirstTrack].TrackNumber;
1199 cp->IndexNumber = 0; /* FIXME: where do they keep these? */
1200 cp->AbsoluteAddress[0] = 0;
1201 cp->AbsoluteAddress[1] = toc.TrackData[i-toc.FirstTrack].Address[1];
1202 cp->AbsoluteAddress[2] = toc.TrackData[i-toc.FirstTrack].Address[2];
1203 cp->AbsoluteAddress[3] = toc.TrackData[i-toc.FirstTrack].Address[3];
1204 frame -= FRAME_OF_TOC(toc,i);
1205 cp->TrackRelativeAddress[0] = 0;
1206 MSF_OF_FRAME(cp->TrackRelativeAddress[1], frame);
1207 RtlLeaveCriticalSection( &cache_section );
1209 /* If playing, then issue a seek command, otherwise do nothing */
1210 #ifdef linux
1211 sc.cdsc_format = CDROM_MSF;
1213 io = ioctl(fd, CDROMSUBCHNL, &sc);
1214 if (io == -1)
1216 TRACE("opened or no_media (%s)!\n", strerror(errno));
1217 CDROM_ClearCacheEntry(dev);
1218 return CDROM_GetStatusCode(io);
1220 if (sc.cdsc_audiostatus==CDROM_AUDIO_PLAY)
1222 msf.minute = audio_msf->M;
1223 msf.second = audio_msf->S;
1224 msf.frame = audio_msf->F;
1225 return CDROM_GetStatusCode(ioctl(fd, CDROMSEEK, &msf));
1227 return STATUS_SUCCESS;
1228 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1229 read_sc.address_format = CD_MSF_FORMAT;
1230 read_sc.track = 0;
1231 read_sc.data_len = sizeof(sc);
1232 read_sc.data = &sc;
1233 read_sc.data_format = CD_CURRENT_POSITION;
1235 io = ioctl(fd, CDIOCREADSUBCHANNEL, &read_sc);
1236 if (io == -1)
1238 TRACE("opened or no_media (%s)!\n", strerror(errno));
1239 CDROM_ClearCacheEntry(dev);
1240 return CDROM_GetStatusCode(io);
1242 if (sc.header.audio_status==CD_AS_PLAY_IN_PROGRESS)
1245 msf.start_m = audio_msf->M;
1246 msf.start_s = audio_msf->S;
1247 msf.start_f = audio_msf->F;
1248 final_frame = FRAME_OF_TOC(toc,toc.LastTrack+1)-1;
1249 MSF_OF_FRAME(msf.end_m, final_frame);
1251 return CDROM_GetStatusCode(ioctl(fd, CDIOCPLAYMSF, &msf));
1253 return STATUS_SUCCESS;
1254 #else
1255 return STATUS_NOT_SUPPORTED;
1256 #endif
1259 /******************************************************************
1260 * CDROM_PauseAudio
1264 static NTSTATUS CDROM_PauseAudio(int fd)
1266 #if defined(linux)
1267 return CDROM_GetStatusCode(ioctl(fd, CDROMPAUSE));
1268 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1269 return CDROM_GetStatusCode(ioctl(fd, CDIOCPAUSE, NULL));
1270 #else
1271 return STATUS_NOT_SUPPORTED;
1272 #endif
1275 /******************************************************************
1276 * CDROM_ResumeAudio
1280 static NTSTATUS CDROM_ResumeAudio(int fd)
1282 #if defined(linux)
1283 return CDROM_GetStatusCode(ioctl(fd, CDROMRESUME));
1284 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1285 return CDROM_GetStatusCode(ioctl(fd, CDIOCRESUME, NULL));
1286 #else
1287 return STATUS_NOT_SUPPORTED;
1288 #endif
1291 /******************************************************************
1292 * CDROM_StopAudio
1296 static NTSTATUS CDROM_StopAudio(int fd)
1298 #if defined(linux)
1299 return CDROM_GetStatusCode(ioctl(fd, CDROMSTOP));
1300 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1301 return CDROM_GetStatusCode(ioctl(fd, CDIOCSTOP, NULL));
1302 #else
1303 return STATUS_NOT_SUPPORTED;
1304 #endif
1307 /******************************************************************
1308 * CDROM_GetVolume
1312 static NTSTATUS CDROM_GetVolume(int fd, VOLUME_CONTROL* vc)
1314 #if defined(linux)
1315 struct cdrom_volctrl volc;
1316 int io;
1318 io = ioctl(fd, CDROMVOLREAD, &volc);
1319 if (io != -1)
1321 vc->PortVolume[0] = volc.channel0;
1322 vc->PortVolume[1] = volc.channel1;
1323 vc->PortVolume[2] = volc.channel2;
1324 vc->PortVolume[3] = volc.channel3;
1326 return CDROM_GetStatusCode(io);
1327 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1328 struct ioc_vol volc;
1329 int io;
1331 io = ioctl(fd, CDIOCGETVOL, &volc);
1332 if (io != -1)
1334 vc->PortVolume[0] = volc.vol[0];
1335 vc->PortVolume[1] = volc.vol[1];
1336 vc->PortVolume[2] = volc.vol[2];
1337 vc->PortVolume[3] = volc.vol[3];
1339 return CDROM_GetStatusCode(io);
1340 #else
1341 return STATUS_NOT_SUPPORTED;
1342 #endif
1345 /******************************************************************
1346 * CDROM_SetVolume
1350 static NTSTATUS CDROM_SetVolume(int fd, const VOLUME_CONTROL* vc)
1352 #if defined(linux)
1353 struct cdrom_volctrl volc;
1355 volc.channel0 = vc->PortVolume[0];
1356 volc.channel1 = vc->PortVolume[1];
1357 volc.channel2 = vc->PortVolume[2];
1358 volc.channel3 = vc->PortVolume[3];
1360 return CDROM_GetStatusCode(ioctl(fd, CDROMVOLCTRL, &volc));
1361 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1362 struct ioc_vol volc;
1364 volc.vol[0] = vc->PortVolume[0];
1365 volc.vol[1] = vc->PortVolume[1];
1366 volc.vol[2] = vc->PortVolume[2];
1367 volc.vol[3] = vc->PortVolume[3];
1369 return CDROM_GetStatusCode(ioctl(fd, CDIOCSETVOL, &volc));
1370 #else
1371 return STATUS_NOT_SUPPORTED;
1372 #endif
1375 /******************************************************************
1376 * CDROM_RawRead
1378 * Some features of this IOCTL are rather poorly documented and
1379 * not really intuitive either:
1381 * 1. Although the DiskOffset parameter is meant to be a
1382 * byte offset into the disk, it is in fact the sector
1383 * number multiplied by 2048 regardless of the actual
1384 * sector size.
1386 * 2. The least significant 11 bits of DiskOffset are ignored.
1388 * 3. The TrackMode parameter has no effect on the sector
1389 * size. The entire raw sector (i.e. 2352 bytes of data)
1390 * is always returned. IMO the TrackMode is only used
1391 * to check the correct sector type.
1394 static NTSTATUS CDROM_RawRead(int fd, const RAW_READ_INFO* raw, void* buffer, DWORD len, DWORD* sz)
1396 int ret = STATUS_NOT_SUPPORTED;
1397 int io = -1;
1399 TRACE("RAW_READ_INFO: DiskOffset=%i,%i SectorCount=%i TrackMode=%i\n buffer=%p len=%i sz=%p\n",
1400 raw->DiskOffset.u.HighPart, raw->DiskOffset.u.LowPart, raw->SectorCount, raw->TrackMode, buffer, len, sz);
1402 if (len < raw->SectorCount * 2352) return STATUS_BUFFER_TOO_SMALL;
1404 #if defined(linux)
1405 if (raw->DiskOffset.u.HighPart & ~2047) {
1406 WARN("DiskOffset points to a sector >= 2**32\n");
1407 return ret;
1410 switch (raw->TrackMode)
1412 case YellowMode2:
1413 case XAForm2:
1415 DWORD lba = raw->DiskOffset.QuadPart >> 11;
1416 struct cdrom_msf* msf;
1417 PBYTE *bp; /* current buffer pointer */
1418 DWORD i;
1420 if ((lba + raw->SectorCount) >
1421 ((1 << 8*sizeof(msf->cdmsf_min0)) * CD_SECS * CD_FRAMES
1422 - CD_MSF_OFFSET)) {
1423 WARN("DiskOffset not accessible with MSF\n");
1424 return ret;
1427 /* Linux reads only one sector at a time.
1428 * ioctl CDROMREADRAW takes struct cdrom_msf as an argument
1429 * on the contrary to what header comments state.
1431 lba += CD_MSF_OFFSET;
1432 for (i = 0, bp = buffer; i < raw->SectorCount;
1433 i++, lba++, bp += 2352)
1435 msf = (struct cdrom_msf*)bp;
1436 msf->cdmsf_min0 = lba / CD_FRAMES / CD_SECS;
1437 msf->cdmsf_sec0 = lba / CD_FRAMES % CD_SECS;
1438 msf->cdmsf_frame0 = lba % CD_FRAMES;
1439 io = ioctl(fd, CDROMREADRAW, msf);
1440 if (io != 0)
1442 *sz = 2352 * i;
1443 return CDROM_GetStatusCode(io);
1446 break;
1449 case CDDA:
1451 struct cdrom_read_audio cdra;
1453 cdra.addr.lba = raw->DiskOffset.QuadPart >> 11;
1454 TRACE("reading at %u\n", cdra.addr.lba);
1455 cdra.addr_format = CDROM_LBA;
1456 cdra.nframes = raw->SectorCount;
1457 cdra.buf = buffer;
1458 io = ioctl(fd, CDROMREADAUDIO, &cdra);
1459 break;
1462 default:
1463 FIXME("NIY: %d\n", raw->TrackMode);
1464 return STATUS_INVALID_PARAMETER;
1466 #elif defined(__APPLE__)
1467 switch (raw->TrackMode)
1469 case YellowMode2:
1471 /* Mac OS, on the other hand, DOES read only one part of the sector
1472 * at a time. Therefore, we have to read each part of the sector, in
1473 * order, to get the whole raw sector in.
1474 * This means that we have to read each sector one at a time, as on
1475 * Linux.
1477 dk_cd_read_t cdrd;
1478 UInt64 lba = raw->DiskOffset.QuadPart >> 11;
1479 PBYTE bp;
1480 int i;
1482 for (i = 0, bp = buffer; i < raw->SectorCount;
1483 i++, lba++, bp += kCDSectorSizeWhole)
1485 cdrd.offset = lba * kCDSectorSizeWhole;
1486 cdrd.sectorType = kCDSectorTypeMode2;
1488 /* First, the sync area */
1489 cdrd.sectorArea = kCDSectorAreaSync;
1490 cdrd.buffer = bp;
1491 cdrd.bufferLength = 12;
1492 io = ioctl(fd, DKIOCCDREAD, &cdrd);
1493 if (io != 0)
1495 *sz = kCDSectorSizeWhole * i;
1496 return CDROM_GetStatusCode(io);
1499 /* Then the header */
1500 cdrd.offset += 12;
1501 cdrd.sectorArea = kCDSectorAreaHeader;
1502 cdrd.buffer = (PBYTE)cdrd.buffer + 12;
1503 cdrd.bufferLength = 4;
1504 io = ioctl(fd, DKIOCCDREAD, &cdrd);
1505 if (io != 0)
1507 *sz = kCDSectorSizeWhole * i + 12;
1508 return CDROM_GetStatusCode(io);
1511 /* And finally the sector proper */
1512 cdrd.offset += 4;
1513 cdrd.sectorArea = kCDSectorAreaUser;
1514 cdrd.buffer = (PBYTE)cdrd.buffer + 4;
1515 cdrd.bufferLength = kCDSectorSizeMode2;
1516 io = ioctl(fd, DKIOCCDREAD, &cdrd);
1517 if (io != 0)
1519 *sz = kCDSectorSizeWhole * i + 16;
1520 return CDROM_GetStatusCode(io);
1524 break;
1527 case XAForm2:
1529 /* Same here */
1530 dk_cd_read_t cdrd;
1531 UInt64 lba = raw->DiskOffset.QuadPart >> 11;
1532 PBYTE bp;
1533 int i;
1535 for (i = 0, bp = buffer; i < raw->SectorCount;
1536 i++, lba++, bp += kCDSectorSizeWhole)
1538 cdrd.offset = lba * kCDSectorSizeWhole;
1539 cdrd.sectorType = kCDSectorTypeMode2Form2;
1541 /* First, the sync area */
1542 cdrd.sectorArea = kCDSectorAreaSync;
1543 cdrd.buffer = bp;
1544 cdrd.bufferLength = 12;
1545 io = ioctl(fd, DKIOCCDREAD, &cdrd);
1546 if (io != 0)
1548 *sz = kCDSectorSizeWhole * i;
1549 return CDROM_GetStatusCode(io);
1552 /* Then the header */
1553 cdrd.offset += 12;
1554 cdrd.sectorArea = kCDSectorAreaHeader;
1555 cdrd.buffer = (PBYTE)cdrd.buffer + 12;
1556 cdrd.bufferLength = 4;
1557 io = ioctl(fd, DKIOCCDREAD, &cdrd);
1558 if (io != 0)
1560 *sz = kCDSectorSizeWhole * i + 12;
1561 return CDROM_GetStatusCode(io);
1564 /* And the sub-header */
1565 cdrd.offset += 4;
1566 cdrd.sectorArea = kCDSectorAreaSubHeader;
1567 cdrd.buffer = (PBYTE)cdrd.buffer + 4;
1568 cdrd.bufferLength = 8;
1569 io = ioctl(fd, DKIOCCDREAD, &cdrd);
1570 if (io != 0)
1572 *sz = kCDSectorSizeWhole * i + 16;
1573 return CDROM_GetStatusCode(io);
1576 /* And finally the sector proper */
1577 cdrd.offset += 8;
1578 cdrd.sectorArea = kCDSectorAreaUser;
1579 cdrd.buffer = (PBYTE)cdrd.buffer + 8;
1580 cdrd.bufferLength = kCDSectorSizeMode2;
1581 io = ioctl(fd, DKIOCCDREAD, &cdrd);
1582 if (io != 0)
1584 *sz = kCDSectorSizeWhole * i + 24;
1585 return CDROM_GetStatusCode(io);
1589 break;
1592 case CDDA:
1594 /* With CDDA, the whole raw sector is considered user data, so there's
1595 * no need to read one at a time.
1597 dk_cd_read_t cdrd;
1599 cdrd.offset = (raw->DiskOffset.QuadPart >> 11) * kCDSectorSizeCDDA;
1600 cdrd.sectorArea = kCDSectorAreaUser;
1601 cdrd.sectorType = kCDSectorTypeCDDA;
1602 cdrd.buffer = buffer;
1603 cdrd.bufferLength = len < raw->SectorCount*kCDSectorSizeCDDA ? len :
1604 raw->SectorCount*kCDSectorSizeCDDA;
1606 io = ioctl(fd, DKIOCCDREAD, &cdrd);
1607 if (io != 0) return CDROM_GetStatusCode(io);
1608 break;
1611 default:
1612 FIXME("NIY: %d\n", raw->TrackMode);
1613 return STATUS_INVALID_PARAMETER;
1615 #else
1616 switch (raw->TrackMode)
1618 case YellowMode2:
1619 FIXME("YellowMode2: NIY\n");
1620 return ret;
1621 case XAForm2:
1622 FIXME("XAForm2: NIY\n");
1623 return ret;
1624 case CDDA:
1625 FIXME("CDDA: NIY\n");
1626 return ret;
1627 default:
1628 FIXME("NIY: %d\n", raw->TrackMode);
1629 return STATUS_INVALID_PARAMETER;
1631 #endif
1633 *sz = 2352 * raw->SectorCount;
1634 ret = CDROM_GetStatusCode(io);
1635 return ret;
1638 /******************************************************************
1639 * CDROM_ScsiPassThroughDirect
1640 * Implements IOCTL_SCSI_PASS_THROUGH_DIRECT
1643 static NTSTATUS CDROM_ScsiPassThroughDirect(int fd, PSCSI_PASS_THROUGH_DIRECT pPacket)
1645 int ret = STATUS_NOT_SUPPORTED;
1646 #ifdef HAVE_SG_IO_HDR_T_INTERFACE_ID
1647 sg_io_hdr_t cmd;
1648 int io;
1649 #elif defined HAVE_SCSIREQ_T_CMD
1650 scsireq_t cmd;
1651 int io;
1652 #endif
1654 if (pPacket->Length < sizeof(SCSI_PASS_THROUGH_DIRECT))
1655 return STATUS_BUFFER_TOO_SMALL;
1657 if (pPacket->CdbLength > 16)
1658 return STATUS_INVALID_PARAMETER;
1660 #ifdef SENSEBUFLEN
1661 if (pPacket->SenseInfoLength > SENSEBUFLEN)
1662 return STATUS_INVALID_PARAMETER;
1663 #elif defined HAVE_REQUEST_SENSE
1664 if (pPacket->SenseInfoLength > sizeof(struct request_sense))
1665 return STATUS_INVALID_PARAMETER;
1666 #endif
1668 if (pPacket->DataTransferLength > 0 && !pPacket->DataBuffer)
1669 return STATUS_INVALID_PARAMETER;
1671 #ifdef HAVE_SG_IO_HDR_T_INTERFACE_ID
1672 RtlZeroMemory(&cmd, sizeof(cmd));
1674 cmd.interface_id = 'S';
1675 cmd.cmd_len = pPacket->CdbLength;
1676 cmd.mx_sb_len = pPacket->SenseInfoLength;
1677 cmd.dxfer_len = pPacket->DataTransferLength;
1678 cmd.dxferp = pPacket->DataBuffer;
1679 cmd.cmdp = pPacket->Cdb;
1680 cmd.sbp = (unsigned char*)pPacket + pPacket->SenseInfoOffset;
1681 cmd.timeout = pPacket->TimeOutValue*1000;
1683 switch (pPacket->DataIn)
1685 case SCSI_IOCTL_DATA_IN:
1686 cmd.dxfer_direction = SG_DXFER_FROM_DEV;
1687 break;
1688 case SCSI_IOCTL_DATA_OUT:
1689 cmd.dxfer_direction = SG_DXFER_TO_DEV;
1690 break;
1691 case SCSI_IOCTL_DATA_UNSPECIFIED:
1692 cmd.dxfer_direction = SG_DXFER_NONE;
1693 break;
1694 default:
1695 return STATUS_INVALID_PARAMETER;
1698 io = ioctl(fd, SG_IO, &cmd);
1700 pPacket->ScsiStatus = cmd.status;
1701 pPacket->DataTransferLength = cmd.resid;
1702 pPacket->SenseInfoLength = cmd.sb_len_wr;
1704 ret = CDROM_GetStatusCode(io);
1706 #elif defined HAVE_SCSIREQ_T_CMD
1708 memset(&cmd, 0, sizeof(cmd));
1709 memcpy(&(cmd.cmd), &(pPacket->Cdb), pPacket->CdbLength);
1711 cmd.cmdlen = pPacket->CdbLength;
1712 cmd.databuf = pPacket->DataBuffer;
1713 cmd.datalen = pPacket->DataTransferLength;
1714 cmd.senselen = pPacket->SenseInfoLength;
1715 cmd.timeout = pPacket->TimeOutValue*1000; /* in milliseconds */
1717 switch (pPacket->DataIn)
1719 case SCSI_IOCTL_DATA_OUT:
1720 cmd.flags |= SCCMD_WRITE;
1721 break;
1722 case SCSI_IOCTL_DATA_IN:
1723 cmd.flags |= SCCMD_READ;
1724 break;
1725 case SCSI_IOCTL_DATA_UNSPECIFIED:
1726 cmd.flags = 0;
1727 break;
1728 default:
1729 return STATUS_INVALID_PARAMETER;
1732 io = ioctl(fd, SCIOCCOMMAND, &cmd);
1734 switch (cmd.retsts)
1736 case SCCMD_OK: break;
1737 case SCCMD_TIMEOUT: return STATUS_TIMEOUT;
1738 break;
1739 case SCCMD_BUSY: return STATUS_DEVICE_BUSY;
1740 break;
1741 case SCCMD_SENSE: break;
1742 case SCCMD_UNKNOWN: return STATUS_UNSUCCESSFUL;
1743 break;
1746 if (pPacket->SenseInfoLength != 0)
1748 memcpy((char*)pPacket + pPacket->SenseInfoOffset,
1749 cmd.sense, pPacket->SenseInfoLength);
1752 pPacket->ScsiStatus = cmd.status;
1754 ret = CDROM_GetStatusCode(io);
1755 #endif
1756 return ret;
1759 /******************************************************************
1760 * CDROM_ScsiPassThrough
1761 * Implements IOCTL_SCSI_PASS_THROUGH
1764 static NTSTATUS CDROM_ScsiPassThrough(int fd, PSCSI_PASS_THROUGH pPacket)
1766 int ret = STATUS_NOT_SUPPORTED;
1767 #ifdef HAVE_SG_IO_HDR_T_INTERFACE_ID
1768 sg_io_hdr_t cmd;
1769 int io;
1770 #elif defined HAVE_SCSIREQ_T_CMD
1771 scsireq_t cmd;
1772 int io;
1773 #endif
1775 if (pPacket->Length < sizeof(SCSI_PASS_THROUGH))
1776 return STATUS_BUFFER_TOO_SMALL;
1778 if (pPacket->CdbLength > 16)
1779 return STATUS_INVALID_PARAMETER;
1781 #ifdef SENSEBUFLEN
1782 if (pPacket->SenseInfoLength > SENSEBUFLEN)
1783 return STATUS_INVALID_PARAMETER;
1784 #elif defined HAVE_REQUEST_SENSE
1785 if (pPacket->SenseInfoLength > sizeof(struct request_sense))
1786 return STATUS_INVALID_PARAMETER;
1787 #endif
1789 if (pPacket->DataTransferLength > 0 && pPacket->DataBufferOffset < sizeof(SCSI_PASS_THROUGH))
1790 return STATUS_INVALID_PARAMETER;
1792 #ifdef HAVE_SG_IO_HDR_T_INTERFACE_ID
1793 RtlZeroMemory(&cmd, sizeof(cmd));
1795 cmd.interface_id = 'S';
1796 cmd.dxfer_len = pPacket->DataTransferLength;
1797 cmd.dxferp = (char*)pPacket + pPacket->DataBufferOffset;
1798 cmd.cmd_len = pPacket->CdbLength;
1799 cmd.cmdp = pPacket->Cdb;
1800 cmd.mx_sb_len = pPacket->SenseInfoLength;
1801 cmd.timeout = pPacket->TimeOutValue*1000;
1803 if(cmd.mx_sb_len > 0)
1804 cmd.sbp = (unsigned char*)pPacket + pPacket->SenseInfoOffset;
1806 switch (pPacket->DataIn)
1808 case SCSI_IOCTL_DATA_IN:
1809 cmd.dxfer_direction = SG_DXFER_FROM_DEV;
1810 break;
1811 case SCSI_IOCTL_DATA_OUT:
1812 cmd.dxfer_direction = SG_DXFER_TO_DEV;
1813 break;
1814 case SCSI_IOCTL_DATA_UNSPECIFIED:
1815 cmd.dxfer_direction = SG_DXFER_NONE;
1816 break;
1817 default:
1818 return STATUS_INVALID_PARAMETER;
1821 io = ioctl(fd, SG_IO, &cmd);
1823 pPacket->ScsiStatus = cmd.status;
1824 pPacket->DataTransferLength = cmd.resid;
1825 pPacket->SenseInfoLength = cmd.sb_len_wr;
1827 ret = CDROM_GetStatusCode(io);
1829 #elif defined HAVE_SCSIREQ_T_CMD
1831 memset(&cmd, 0, sizeof(cmd));
1832 memcpy(&(cmd.cmd), &(pPacket->Cdb), pPacket->CdbLength);
1834 if ( pPacket->DataBufferOffset > 0x1000 )
1836 cmd.databuf = (void*)pPacket->DataBufferOffset;
1838 else
1840 cmd.databuf = (char*)pPacket + pPacket->DataBufferOffset;
1843 cmd.cmdlen = pPacket->CdbLength;
1844 cmd.datalen = pPacket->DataTransferLength;
1845 cmd.senselen = pPacket->SenseInfoLength;
1846 cmd.timeout = pPacket->TimeOutValue*1000; /* in milliseconds */
1848 switch (pPacket->DataIn)
1850 case SCSI_IOCTL_DATA_OUT:
1851 cmd.flags |= SCCMD_WRITE;
1852 break;
1853 case SCSI_IOCTL_DATA_IN:
1854 cmd.flags |= SCCMD_READ;
1855 break;
1856 case SCSI_IOCTL_DATA_UNSPECIFIED:
1857 cmd.flags = 0;
1858 break;
1859 default:
1860 return STATUS_INVALID_PARAMETER;
1863 io = ioctl(fd, SCIOCCOMMAND, &cmd);
1865 switch (cmd.retsts)
1867 case SCCMD_OK: break;
1868 case SCCMD_TIMEOUT: return STATUS_TIMEOUT;
1869 break;
1870 case SCCMD_BUSY: return STATUS_DEVICE_BUSY;
1871 break;
1872 case SCCMD_SENSE: break;
1873 case SCCMD_UNKNOWN: return STATUS_UNSUCCESSFUL;
1874 break;
1877 if (pPacket->SenseInfoLength != 0)
1879 memcpy((char*)pPacket + pPacket->SenseInfoOffset,
1880 cmd.sense, pPacket->SenseInfoLength);
1883 pPacket->ScsiStatus = cmd.status;
1885 ret = CDROM_GetStatusCode(io);
1886 #endif
1887 return ret;
1890 /******************************************************************
1891 * CDROM_ScsiGetCaps
1895 static NTSTATUS CDROM_ScsiGetCaps(int fd, PIO_SCSI_CAPABILITIES caps)
1897 NTSTATUS ret = STATUS_NOT_IMPLEMENTED;
1899 #ifdef SG_SCATTER_SZ
1900 caps->Length = sizeof(*caps);
1901 caps->MaximumTransferLength = SG_SCATTER_SZ; /* FIXME */
1902 caps->MaximumPhysicalPages = SG_SCATTER_SZ / getpagesize();
1903 caps->SupportedAsynchronousEvents = TRUE;
1904 caps->AlignmentMask = getpagesize();
1905 caps->TaggedQueuing = FALSE; /* we could check that it works and answer TRUE */
1906 caps->AdapterScansDown = FALSE; /* FIXME ? */
1907 caps->AdapterUsesPio = FALSE; /* FIXME ? */
1908 ret = STATUS_SUCCESS;
1909 #elif defined __APPLE__
1910 uint64_t bytesr, bytesw, align;
1911 int io = ioctl(fd, DKIOCGETMAXBYTECOUNTREAD, &bytesr);
1912 if (io != 0) return CDROM_GetStatusCode(io);
1913 io = ioctl(fd, DKIOCGETMAXBYTECOUNTWRITE, &bytesw);
1914 if (io != 0) return CDROM_GetStatusCode(io);
1915 io = ioctl(fd, DKIOCGETMINSEGMENTALIGNMENTBYTECOUNT, &align);
1916 if (io != 0) return CDROM_GetStatusCode(io);
1917 caps->Length = sizeof(*caps);
1918 caps->MaximumTransferLength = bytesr < bytesw ? bytesr : bytesw;
1919 caps->MaximumPhysicalPages = caps->MaximumTransferLength / getpagesize();
1920 caps->SupportedAsynchronousEvents = TRUE;
1921 caps->AlignmentMask = align-1;
1922 caps->TaggedQueuing = FALSE; /* we could check that it works and answer TRUE */
1923 caps->AdapterScansDown = FALSE; /* FIXME ? */
1924 caps->AdapterUsesPio = FALSE; /* FIXME ? */
1925 ret = STATUS_SUCCESS;
1926 #else
1927 FIXME("Unimplemented\n");
1928 #endif
1929 return ret;
1932 /******************************************************************
1933 * CDROM_GetAddress
1935 * implements IOCTL_SCSI_GET_ADDRESS
1937 static NTSTATUS CDROM_GetAddress(int fd, SCSI_ADDRESS* address)
1939 UCHAR portnum, busid, targetid, lun;
1941 address->Length = sizeof(SCSI_ADDRESS);
1942 if ( ! CDROM_GetInterfaceInfo(fd, &portnum, &busid, &targetid, &lun))
1943 return STATUS_NOT_SUPPORTED;
1945 address->PortNumber = portnum; /* primary=0 secondary=1 for ide */
1946 address->PathId = busid; /* always 0 for ide */
1947 address->TargetId = targetid; /* master=0 slave=1 for ide */
1948 address->Lun = lun;
1949 return STATUS_SUCCESS;
1952 /******************************************************************
1953 * DVD_StartSession
1957 static NTSTATUS DVD_StartSession(int fd, const DVD_SESSION_ID *sid_in, PDVD_SESSION_ID sid_out)
1959 #if defined(linux)
1960 NTSTATUS ret = STATUS_NOT_SUPPORTED;
1961 dvd_authinfo auth_info;
1963 memset( &auth_info, 0, sizeof( auth_info ) );
1964 auth_info.type = DVD_LU_SEND_AGID;
1965 if (sid_in) auth_info.lsa.agid = *(const int*)sid_in; /* ?*/
1967 TRACE("fd 0x%08x\n",fd);
1968 ret =CDROM_GetStatusCode(ioctl(fd, DVD_AUTH, &auth_info));
1969 *sid_out = auth_info.lsa.agid;
1970 return ret;
1971 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1972 return STATUS_NOT_SUPPORTED;
1973 #elif defined(__APPLE__)
1974 NTSTATUS ret = STATUS_NOT_SUPPORTED;
1975 dk_dvd_report_key_t dvdrk;
1976 DVDAuthenticationGrantIDInfo agid_info;
1978 dvdrk.format = kDVDKeyFormatAGID_CSS;
1979 dvdrk.keyClass = kDVDKeyClassCSS_CPPM_CPRM;
1980 if(sid_in) dvdrk.grantID = *(uint8_t*)sid_in; /* ? */
1981 dvdrk.bufferLength = sizeof(DVDAuthenticationGrantIDInfo);
1982 dvdrk.buffer = &agid_info;
1984 ret = CDROM_GetStatusCode(ioctl(fd, DKIOCDVDREPORTKEY, &dvdrk));
1985 *sid_out = agid_info.grantID;
1986 return ret;
1987 #else
1988 return STATUS_NOT_SUPPORTED;
1989 #endif
1992 /******************************************************************
1993 * DVD_EndSession
1997 static NTSTATUS DVD_EndSession(int fd, const DVD_SESSION_ID *sid)
1999 #if defined(linux)
2000 dvd_authinfo auth_info;
2002 memset( &auth_info, 0, sizeof( auth_info ) );
2003 auth_info.type = DVD_INVALIDATE_AGID;
2004 auth_info.lsa.agid = *(const int*)sid;
2006 TRACE("\n");
2007 return CDROM_GetStatusCode(ioctl(fd, DVD_AUTH, &auth_info));
2008 #elif defined(__FreeBSD__) || defined(__NetBSD__)
2009 return STATUS_NOT_SUPPORTED;
2010 #elif defined(__APPLE__)
2011 dk_dvd_send_key_t dvdsk;
2013 dvdsk.format = kDVDKeyFormatAGID_Invalidate;
2014 dvdsk.keyClass = kDVDKeyClassCSS_CPPM_CPRM;
2015 dvdsk.grantID = (uint8_t)*sid;
2017 return CDROM_GetStatusCode(ioctl(fd, DKIOCDVDSENDKEY, &dvdsk));
2018 #else
2019 return STATUS_NOT_SUPPORTED;
2020 #endif
2023 /******************************************************************
2024 * DVD_SendKey
2028 static NTSTATUS DVD_SendKey(int fd, const DVD_COPY_PROTECT_KEY *key)
2030 #if defined(linux)
2031 NTSTATUS ret = STATUS_NOT_SUPPORTED;
2032 dvd_authinfo auth_info;
2034 memset( &auth_info, 0, sizeof( auth_info ) );
2035 switch (key->KeyType)
2037 case DvdChallengeKey:
2038 auth_info.type = DVD_HOST_SEND_CHALLENGE;
2039 auth_info.hsc.agid = (int)key->SessionId;
2040 TRACE("DvdChallengeKey ioc 0x%x\n", DVD_AUTH );
2041 memcpy( auth_info.hsc.chal, key->KeyData, DVD_CHALLENGE_SIZE );
2042 ret = CDROM_GetStatusCode(ioctl( fd, DVD_AUTH, &auth_info ));
2043 break;
2044 case DvdBusKey2:
2045 auth_info.type = DVD_HOST_SEND_KEY2;
2046 auth_info.hsk.agid = (int)key->SessionId;
2048 memcpy( auth_info.hsk.key, key->KeyData, DVD_KEY_SIZE );
2050 TRACE("DvdBusKey2\n");
2051 ret = CDROM_GetStatusCode(ioctl( fd, DVD_AUTH, &auth_info ));
2052 break;
2054 default:
2055 FIXME("Unknown Keytype 0x%x\n",key->KeyType);
2057 return ret;
2058 #elif defined(__APPLE__)
2059 dk_dvd_send_key_t dvdsk;
2060 union
2062 DVDChallengeKeyInfo chal;
2063 DVDKey2Info key2;
2064 } key_desc;
2066 switch(key->KeyType)
2068 case DvdChallengeKey:
2069 dvdsk.format = kDVDKeyFormatChallengeKey;
2070 dvdsk.bufferLength = sizeof(key_desc.chal);
2071 dvdsk.buffer = &key_desc.chal;
2072 OSWriteBigInt16(key_desc.chal.dataLength, 0, key->KeyLength);
2073 memcpy(key_desc.chal.challengeKeyValue, key->KeyData, key->KeyLength);
2074 break;
2075 case DvdBusKey2:
2076 dvdsk.format = kDVDKeyFormatKey2;
2077 dvdsk.bufferLength = sizeof(key_desc.key2);
2078 dvdsk.buffer = &key_desc.key2;
2079 OSWriteBigInt16(key_desc.key2.dataLength, 0, key->KeyLength);
2080 memcpy(key_desc.key2.key2Value, key->KeyData, key->KeyLength);
2081 break;
2082 case DvdInvalidateAGID:
2083 dvdsk.format = kDVDKeyFormatAGID_Invalidate;
2084 break;
2085 case DvdBusKey1:
2086 case DvdTitleKey:
2087 case DvdAsf:
2088 case DvdGetRpcKey:
2089 case DvdDiskKey:
2090 ERR("attempted to write read-only key type 0x%x\n", key->KeyType);
2091 return STATUS_NOT_SUPPORTED;
2092 case DvdSetRpcKey:
2093 FIXME("DvdSetRpcKey NIY\n");
2094 return STATUS_NOT_SUPPORTED;
2095 default:
2096 FIXME("got unknown key type 0x%x\n", key->KeyType);
2097 return STATUS_NOT_SUPPORTED;
2099 dvdsk.keyClass = kDVDKeyClassCSS_CPPM_CPRM;
2100 dvdsk.grantID = (uint8_t)key->SessionId;
2102 return CDROM_GetStatusCode(ioctl(fd, DKIOCDVDSENDKEY, &dvdsk));
2103 #else
2104 FIXME("unsupported on this platform\n");
2105 return STATUS_NOT_SUPPORTED;
2106 #endif
2109 /******************************************************************
2110 * DVD_ReadKey
2114 static NTSTATUS DVD_ReadKey(int fd, PDVD_COPY_PROTECT_KEY key)
2116 #if defined(linux)
2117 NTSTATUS ret = STATUS_NOT_SUPPORTED;
2118 dvd_struct dvd;
2119 dvd_authinfo auth_info;
2121 memset( &dvd, 0, sizeof( dvd_struct ) );
2122 memset( &auth_info, 0, sizeof( auth_info ) );
2123 switch (key->KeyType)
2125 case DvdDiskKey:
2127 dvd.type = DVD_STRUCT_DISCKEY;
2128 dvd.disckey.agid = (int)key->SessionId;
2129 memset( dvd.disckey.value, 0, DVD_DISCKEY_SIZE );
2131 TRACE("DvdDiskKey\n");
2132 ret = CDROM_GetStatusCode(ioctl( fd, DVD_READ_STRUCT, &dvd ));
2133 if (ret == STATUS_SUCCESS)
2134 memcpy(key->KeyData,dvd.disckey.value,DVD_DISCKEY_SIZE);
2135 break;
2136 case DvdTitleKey:
2137 auth_info.type = DVD_LU_SEND_TITLE_KEY;
2138 auth_info.lstk.agid = (int)key->SessionId;
2139 auth_info.lstk.lba = (int)(key->Parameters.TitleOffset.QuadPart>>11);
2140 TRACE("DvdTitleKey session %d Quadpart 0x%08lx offset 0x%08x\n",
2141 (int)key->SessionId, (long)key->Parameters.TitleOffset.QuadPart,
2142 auth_info.lstk.lba);
2143 ret = CDROM_GetStatusCode(ioctl( fd, DVD_AUTH, &auth_info ));
2144 if (ret == STATUS_SUCCESS)
2145 memcpy(key->KeyData, auth_info.lstk.title_key, DVD_KEY_SIZE );
2146 break;
2147 case DvdChallengeKey:
2149 auth_info.type = DVD_LU_SEND_CHALLENGE;
2150 auth_info.lsc.agid = (int)key->SessionId;
2152 TRACE("DvdChallengeKey\n");
2153 ret = CDROM_GetStatusCode(ioctl( fd, DVD_AUTH, &auth_info ));
2154 if (ret == STATUS_SUCCESS)
2155 memcpy( key->KeyData, auth_info.lsc.chal, DVD_CHALLENGE_SIZE );
2156 break;
2157 case DvdAsf:
2158 auth_info.type = DVD_LU_SEND_ASF;
2159 TRACE("DvdAsf\n");
2160 auth_info.lsasf.asf=((PDVD_ASF)key->KeyData)->SuccessFlag;
2161 ret = CDROM_GetStatusCode(ioctl( fd, DVD_AUTH, &auth_info ));
2162 ((PDVD_ASF)key->KeyData)->SuccessFlag = auth_info.lsasf.asf;
2163 break;
2164 case DvdBusKey1:
2165 auth_info.type = DVD_LU_SEND_KEY1;
2166 auth_info.lsk.agid = (int)key->SessionId;
2168 TRACE("DvdBusKey1\n");
2169 ret = CDROM_GetStatusCode(ioctl( fd, DVD_AUTH, &auth_info ));
2171 if (ret == STATUS_SUCCESS)
2172 memcpy( key->KeyData, auth_info.lsk.key, DVD_KEY_SIZE );
2173 break;
2174 case DvdGetRpcKey:
2175 auth_info.type = DVD_LU_SEND_RPC_STATE;
2177 TRACE("DvdGetRpcKey\n");
2178 ret = CDROM_GetStatusCode(ioctl( fd, DVD_AUTH, &auth_info ));
2180 if (ret == STATUS_SUCCESS)
2182 ((PDVD_RPC_KEY)key->KeyData)->TypeCode = auth_info.lrpcs.type;
2183 ((PDVD_RPC_KEY)key->KeyData)->RegionMask = auth_info.lrpcs.region_mask;
2184 ((PDVD_RPC_KEY)key->KeyData)->RpcScheme = auth_info.lrpcs.rpc_scheme;
2185 ((PDVD_RPC_KEY)key->KeyData)->UserResetsAvailable = auth_info.lrpcs.ucca;
2186 ((PDVD_RPC_KEY)key->KeyData)->ManufacturerResetsAvailable = auth_info.lrpcs.vra;
2188 break;
2189 default:
2190 FIXME("Unknown keytype 0x%x\n",key->KeyType);
2192 return ret;
2193 #elif defined(__FreeBSD__) || defined(__NetBSD__)
2194 TRACE("bsd\n");
2195 return STATUS_NOT_SUPPORTED;
2196 #elif defined(__APPLE__)
2197 union
2199 dk_dvd_report_key_t key;
2200 dk_dvd_read_structure_t disk_key;
2201 } ioc;
2202 union
2204 DVDDiscKeyInfo disk_key;
2205 DVDChallengeKeyInfo chal;
2206 DVDKey1Info key1;
2207 DVDTitleKeyInfo title;
2208 DVDAuthenticationSuccessFlagInfo asf;
2209 DVDRegionPlaybackControlInfo rpc;
2210 } desc;
2211 NTSTATUS ret = STATUS_NOT_SUPPORTED;
2213 switch(key->KeyType)
2215 case DvdChallengeKey:
2216 ioc.key.format = kDVDKeyFormatChallengeKey;
2217 ioc.key.grantID = (uint8_t)key->SessionId;
2218 ioc.key.keyClass = kDVDKeyClassCSS_CPPM_CPRM;
2219 ioc.key.bufferLength = sizeof(desc.chal);
2220 ioc.key.buffer = &desc.chal;
2221 OSWriteBigInt16(desc.chal.dataLength, 0, key->KeyLength);
2222 break;
2223 case DvdBusKey1:
2224 ioc.key.format = kDVDKeyFormatKey1;
2225 ioc.key.grantID = (uint8_t)key->SessionId;
2226 ioc.key.keyClass = kDVDKeyClassCSS_CPPM_CPRM;
2227 ioc.key.bufferLength = sizeof(desc.key1);
2228 ioc.key.buffer = &desc.key1;
2229 OSWriteBigInt16(desc.key1.dataLength, 0, key->KeyLength);
2230 break;
2231 case DvdTitleKey:
2232 ioc.key.format = kDVDKeyFormatTitleKey;
2233 ioc.key.grantID = (uint8_t)key->SessionId;
2234 ioc.key.keyClass = kDVDKeyClassCSS_CPPM_CPRM;
2235 ioc.key.bufferLength = sizeof(desc.title);
2236 ioc.key.buffer = &desc.title;
2237 ioc.key.address = (uint32_t)(key->Parameters.TitleOffset.QuadPart>>11);
2238 OSWriteBigInt16(desc.title.dataLength, 0, key->KeyLength);
2239 break;
2240 case DvdAsf:
2241 ioc.key.format = kDVDKeyFormatASF;
2242 ioc.key.grantID = (uint8_t)key->SessionId;
2243 ioc.key.keyClass = kDVDKeyClassCSS_CPPM_CPRM;
2244 ioc.key.bufferLength = sizeof(desc.asf);
2245 ioc.key.buffer = &desc.asf;
2246 OSWriteBigInt16(desc.asf.dataLength, 0, key->KeyLength);
2247 break;
2248 case DvdGetRpcKey:
2249 ioc.key.format = kDVDKeyFormatRegionState;
2250 ioc.key.grantID = (uint8_t)key->SessionId;
2251 ioc.key.keyClass = kDVDKeyClassCSS_CPPM_CPRM;
2252 ioc.key.bufferLength = sizeof(desc.rpc);
2253 ioc.key.buffer = &desc.rpc;
2254 OSWriteBigInt16(desc.rpc.dataLength, 0, key->KeyLength);
2255 break;
2256 case DvdDiskKey:
2257 ioc.disk_key.format = kDVDStructureFormatDiscKeyInfo;
2258 ioc.disk_key.grantID = (uint8_t)key->SessionId;
2259 ioc.disk_key.bufferLength = sizeof(desc.disk_key);
2260 ioc.disk_key.buffer = &desc.disk_key;
2261 break;
2262 case DvdInvalidateAGID:
2263 ioc.key.format = kDVDKeyFormatAGID_Invalidate;
2264 ioc.key.grantID = (uint8_t)key->SessionId;
2265 ioc.key.keyClass = kDVDKeyClassCSS_CPPM_CPRM;
2266 break;
2267 case DvdBusKey2:
2268 case DvdSetRpcKey:
2269 ERR("attempted to read write-only key type 0x%x\n", key->KeyType);
2270 return STATUS_NOT_SUPPORTED;
2271 default:
2272 FIXME("got unknown key type 0x%x\n", key->KeyType);
2273 return STATUS_NOT_SUPPORTED;
2276 ret = CDROM_GetStatusCode(ioctl(fd, (key->KeyType == DvdDiskKey ? DKIOCDVDREADSTRUCTURE : DKIOCDVDREPORTKEY), &ioc));
2278 if (ret == STATUS_SUCCESS)
2280 switch(key->KeyType)
2282 case DvdChallengeKey:
2283 key->KeyLength = OSReadBigInt16(desc.chal.dataLength, 0);
2284 memcpy(key->KeyData, desc.chal.challengeKeyValue, key->KeyLength);
2285 break;
2286 case DvdBusKey1:
2287 key->KeyLength = OSReadBigInt16(desc.key1.dataLength, 0);
2288 memcpy(key->KeyData, desc.key1.key1Value, key->KeyLength);
2289 break;
2290 case DvdTitleKey:
2291 key->KeyLength = OSReadBigInt16(desc.title.dataLength, 0);
2292 memcpy(key->KeyData, desc.title.titleKeyValue, key->KeyLength);
2293 key->KeyFlags = 0;
2294 if (desc.title.CPM)
2296 /*key->KeyFlags |= DVD_COPYRIGHTED;*/
2297 if (desc.title.CP_SEC) key->KeyFlags |= DVD_SECTOR_PROTECTED;
2298 /*else key->KeyFlags |= DVD_SECTOR_NOT_PROTECTED;*/
2299 #if 0
2300 switch (desc.title.CGMS)
2302 case 0:
2303 key->KeyFlags |= DVD_CGMS_COPY_PERMITTED;
2304 break;
2305 case 2:
2306 key->KeyFlags |= DVD_CGMS_COPY_ONCE;
2307 break;
2308 case 3:
2309 key->KeyFlags |= DVD_CGMS_NO_COPY;
2310 break;
2312 #endif
2313 } /*else key->KeyFlags |= DVD_NOT_COPYRIGHTED;*/
2314 break;
2315 case DvdAsf:
2316 key->KeyLength = OSReadBigInt16(desc.title.dataLength, 0);
2317 ((PDVD_ASF)key->KeyData)->SuccessFlag = desc.asf.successFlag;
2318 break;
2319 case DvdGetRpcKey:
2320 key->KeyLength = OSReadBigInt16(desc.rpc.dataLength, 0);
2321 ((PDVD_RPC_KEY)key->KeyData)->UserResetsAvailable =
2322 desc.rpc.numberUserResets;
2323 ((PDVD_RPC_KEY)key->KeyData)->ManufacturerResetsAvailable =
2324 desc.rpc.numberVendorResets;
2325 ((PDVD_RPC_KEY)key->KeyData)->TypeCode =
2326 desc.rpc.typeCode;
2327 ((PDVD_RPC_KEY)key->KeyData)->RegionMask =
2328 desc.rpc.driveRegion;
2329 ((PDVD_RPC_KEY)key->KeyData)->RpcScheme =
2330 desc.rpc.rpcScheme;
2331 case DvdDiskKey:
2332 key->KeyLength = OSReadBigInt16(desc.disk_key.dataLength, 0);
2333 memcpy(key->KeyData, desc.disk_key.discKeyStructures, key->KeyLength);
2334 break;
2335 case DvdBusKey2:
2336 case DvdSetRpcKey:
2337 case DvdInvalidateAGID:
2338 default:
2339 /* Silence warning */
2343 return ret;
2344 #else
2345 TRACE("outside\n");
2346 return STATUS_NOT_SUPPORTED;
2347 #endif
2350 /******************************************************************
2351 * DVD_GetRegion
2353 * This IOCTL combines information from both IOCTL_DVD_READ_KEY
2354 * with key type DvdGetRpcKey and IOCTL_DVD_READ_STRUCTURE with
2355 * structure type DvdCopyrightInformation into one structure.
2357 static NTSTATUS DVD_GetRegion(int fd, PDVD_REGION region)
2359 #if defined(linux)
2360 NTSTATUS ret = STATUS_NOT_SUPPORTED;
2361 dvd_struct dvd;
2362 dvd_authinfo auth_info;
2364 dvd.type = DVD_STRUCT_COPYRIGHT;
2365 dvd.copyright.layer_num = 0;
2366 auth_info.type = DVD_LU_SEND_RPC_STATE;
2368 ret = CDROM_GetStatusCode(ioctl( fd, DVD_AUTH, &auth_info ));
2370 if (ret == STATUS_SUCCESS)
2372 ret = CDROM_GetStatusCode(ioctl( fd, DVD_READ_STRUCT, &dvd ));
2374 if (ret == STATUS_SUCCESS)
2376 region->CopySystem = dvd.copyright.cpst;
2377 region->RegionData = dvd.copyright.rmi;
2378 region->SystemRegion = auth_info.lrpcs.region_mask;
2379 region->ResetCount = auth_info.lrpcs.ucca;
2382 return ret;
2383 #elif defined(__FreeBSD__) || defined(__NetBSD__)
2384 TRACE("bsd\n");
2385 return STATUS_NOT_SUPPORTED;
2386 #elif defined(__APPLE__)
2387 dk_dvd_report_key_t key;
2388 dk_dvd_read_structure_t dvd;
2389 DVDRegionPlaybackControlInfo rpc;
2390 DVDCopyrightInfo copy;
2391 NTSTATUS ret = STATUS_NOT_SUPPORTED;
2393 key.format = kDVDKeyFormatRegionState;
2394 key.keyClass = kDVDKeyClassCSS_CPPM_CPRM;
2395 key.bufferLength = sizeof(rpc);
2396 key.buffer = &rpc;
2397 dvd.format = kDVDStructureFormatCopyrightInfo;
2398 dvd.bufferLength = sizeof(copy);
2399 dvd.buffer = &copy;
2401 ret = CDROM_GetStatusCode(ioctl( fd, DKIOCDVDREPORTKEY, &key ));
2403 if (ret == STATUS_SUCCESS)
2405 ret = CDROM_GetStatusCode(ioctl( fd, DKIOCDVDREADSTRUCTURE, &dvd ));
2407 if (ret == STATUS_SUCCESS)
2409 region->CopySystem = copy.copyrightProtectionSystemType;
2410 region->RegionData = copy.regionMask;
2411 region->SystemRegion = rpc.driveRegion;
2412 region->ResetCount = rpc.numberUserResets;
2415 return ret;
2416 #else
2417 FIXME("\n");
2418 return STATUS_NOT_SUPPORTED;
2419 #endif
2422 /******************************************************************
2423 * DVD_ReadStructure
2427 static NTSTATUS DVD_ReadStructure(int dev, const DVD_READ_STRUCTURE *structure, PDVD_LAYER_DESCRIPTOR layer)
2429 #ifdef DVD_READ_STRUCT
2430 /* dvd_struct is not defined consistently across platforms */
2431 union
2433 struct dvd_physical physical;
2434 struct dvd_copyright copyright;
2435 struct dvd_disckey disckey;
2436 struct dvd_bca bca;
2437 struct dvd_manufact manufact;
2438 } s;
2440 if (structure->BlockByteOffset.u.HighPart || structure->BlockByteOffset.u.LowPart)
2441 FIXME(": BlockByteOffset is not handled\n");
2443 switch (structure->Format)
2445 case DvdPhysicalDescriptor:
2446 s.physical.type = DVD_STRUCT_PHYSICAL;
2447 s.physical.layer_num = structure->LayerNumber;
2448 break;
2450 case DvdCopyrightDescriptor:
2451 s.copyright.type = DVD_STRUCT_COPYRIGHT;
2452 s.copyright.layer_num = structure->LayerNumber;
2453 break;
2455 case DvdDiskKeyDescriptor:
2456 s.disckey.type = DVD_STRUCT_DISCKEY;
2457 s.disckey.agid = structure->SessionId;
2458 break;
2460 case DvdBCADescriptor:
2461 s.bca.type = DVD_STRUCT_BCA;
2462 break;
2464 case DvdManufacturerDescriptor:
2465 s.manufact.type = DVD_STRUCT_MANUFACT;
2466 s.manufact.layer_num = structure->LayerNumber;
2467 break;
2469 case DvdMaxDescriptor: /* This is not a real request, no matter what MSDN says! */
2470 default:
2471 return STATUS_INVALID_PARAMETER;
2474 if (ioctl(dev, DVD_READ_STRUCT, &s) < 0)
2475 return STATUS_INVALID_PARAMETER;
2477 switch (structure->Format)
2479 case DvdPhysicalDescriptor:
2481 internal_dvd_layer_descriptor *p = (internal_dvd_layer_descriptor *) layer;
2482 struct dvd_layer *l = &s.physical.layer[s.physical.layer_num];
2484 p->DataLength[0] = 2;
2485 p->DataLength[1] = 8;
2486 p->Reserved0[0] = 0;
2487 p->Reserved0[1] = 0;
2488 p->BookVersion = l->book_version;
2489 p->BookType = l->book_type;
2490 p->MinimumRate = l->min_rate;
2491 p->DiskSize = l->disc_size;
2492 p->LayerType = l->layer_type;
2493 p->TrackPath = l->track_path;
2494 p->NumberOfLayers = l->nlayers;
2495 p->Reserved1 = 0;
2496 p->TrackDensity = l->track_density;
2497 p->LinearDensity = l->linear_density;
2498 p->StartingDataSector = l->start_sector;
2499 p->EndDataSector = l->end_sector;
2500 p->EndLayerZeroSector = l->end_sector_l0;
2501 p->Reserved5 = 0;
2502 p->BCAFlag = l->bca;
2503 p->Reserved6 = 0;
2505 break;
2507 case DvdCopyrightDescriptor:
2509 PDVD_COPYRIGHT_DESCRIPTOR p = (PDVD_COPYRIGHT_DESCRIPTOR) layer;
2511 p->CopyrightProtectionType = s.copyright.cpst;
2512 p->RegionManagementInformation = s.copyright.rmi;
2513 p->Reserved = 0;
2515 break;
2517 case DvdDiskKeyDescriptor:
2519 PDVD_DISK_KEY_DESCRIPTOR p = (PDVD_DISK_KEY_DESCRIPTOR) layer;
2521 memcpy(p->DiskKeyData, s.disckey.value, 2048);
2523 break;
2525 case DvdBCADescriptor:
2527 PDVD_BCA_DESCRIPTOR p = (PDVD_BCA_DESCRIPTOR) layer;
2529 memcpy(p->BCAInformation, s.bca.value, s.bca.len);
2531 break;
2533 case DvdManufacturerDescriptor:
2535 PDVD_MANUFACTURER_DESCRIPTOR p = (PDVD_MANUFACTURER_DESCRIPTOR) layer;
2537 memcpy(p->ManufacturingInformation, s.manufact.value, 2048);
2539 break;
2541 case DvdMaxDescriptor: /* Suppress warning */
2542 break;
2544 #elif defined(__APPLE__)
2545 NTSTATUS ret = STATUS_NOT_SUPPORTED;
2546 dk_dvd_read_structure_t dvdrs;
2547 union
2549 DVDPhysicalFormatInfo phys;
2550 DVDCopyrightInfo copy;
2551 DVDDiscKeyInfo disk_key;
2552 DVDManufacturingInfo manf;
2553 } desc;
2554 union
2556 PDVD_LAYER_DESCRIPTOR layer;
2557 internal_dvd_layer_descriptor *xlayer;
2558 PDVD_COPYRIGHT_DESCRIPTOR copy;
2559 PDVD_DISK_KEY_DESCRIPTOR disk_key;
2560 PDVD_MANUFACTURER_DESCRIPTOR manf;
2561 } nt_desc;
2563 nt_desc.layer = layer;
2564 dvdrs.address = (uint32_t)(structure->BlockByteOffset.QuadPart>>11);
2565 dvdrs.grantID = (uint8_t)structure->SessionId;
2566 dvdrs.layer = structure->LayerNumber;
2567 switch(structure->Format)
2569 case DvdPhysicalDescriptor:
2570 dvdrs.format = kDVDStructureFormatPhysicalFormatInfo;
2571 dvdrs.bufferLength = sizeof(desc.phys);
2572 dvdrs.buffer = &desc.phys;
2573 break;
2575 case DvdCopyrightDescriptor:
2576 dvdrs.format = kDVDStructureFormatCopyrightInfo;
2577 dvdrs.bufferLength = sizeof(desc.copy);
2578 dvdrs.buffer = &desc.copy;
2579 break;
2581 case DvdDiskKeyDescriptor:
2582 dvdrs.format = kDVDStructureFormatDiscKeyInfo;
2583 dvdrs.bufferLength = sizeof(desc.disk_key);
2584 dvdrs.buffer = &desc.disk_key;
2585 break;
2587 case DvdBCADescriptor:
2588 FIXME("DvdBCADescriptor NIY\n");
2589 return STATUS_NOT_SUPPORTED;
2591 case DvdManufacturerDescriptor:
2592 dvdrs.format = kDVDStructureFormatManufacturingInfo;
2593 dvdrs.bufferLength = sizeof(desc.manf);
2594 dvdrs.buffer = &desc.manf;
2595 break;
2597 case DvdMaxDescriptor:
2598 default:
2599 FIXME("got unknown structure type 0x%x\n", structure->Format);
2600 return STATUS_NOT_SUPPORTED;
2602 ret = CDROM_GetStatusCode(ioctl(dev, DKIOCDVDREADSTRUCTURE, &dvdrs));
2603 if(ret == STATUS_SUCCESS)
2605 switch(structure->Format)
2607 case DvdPhysicalDescriptor:
2608 nt_desc.xlayer->DataLength[0] = 2;
2609 nt_desc.xlayer->DataLength[1] = 8;
2610 nt_desc.xlayer->Reserved0[0] = 0;
2611 nt_desc.xlayer->Reserved0[1] = 0;
2612 nt_desc.xlayer->BookVersion = desc.phys.partVersion;
2613 nt_desc.xlayer->BookType = desc.phys.bookType;
2614 nt_desc.xlayer->MinimumRate = desc.phys.minimumRate;
2615 nt_desc.xlayer->DiskSize = desc.phys.discSize;
2616 nt_desc.xlayer->LayerType = desc.phys.layerType;
2617 nt_desc.xlayer->TrackPath = desc.phys.trackPath;
2618 nt_desc.xlayer->NumberOfLayers = desc.phys.numberOfLayers;
2619 nt_desc.xlayer->Reserved1 = 0;
2620 nt_desc.xlayer->TrackDensity = desc.phys.trackDensity;
2621 nt_desc.xlayer->LinearDensity = desc.phys.linearDensity;
2622 nt_desc.xlayer->BCAFlag = desc.phys.bcaFlag;
2623 nt_desc.xlayer->StartingDataSector = OSReadBigInt32(&desc.phys.zero1, 0);
2624 nt_desc.xlayer->EndDataSector = OSReadBigInt32(&desc.phys.zero2, 0);
2625 nt_desc.xlayer->EndLayerZeroSector = OSReadBigInt32(&desc.phys.zero3, 0);
2626 nt_desc.xlayer->Reserved5 = 0;
2627 nt_desc.xlayer->Reserved6 = 0;
2628 break;
2630 case DvdCopyrightDescriptor:
2631 nt_desc.copy->CopyrightProtectionType =
2632 desc.copy.copyrightProtectionSystemType;
2633 nt_desc.copy->RegionManagementInformation =
2634 desc.copy.regionMask;
2635 nt_desc.copy->Reserved = 0;
2636 break;
2638 case DvdDiskKeyDescriptor:
2639 memcpy(
2640 nt_desc.disk_key->DiskKeyData,
2641 desc.disk_key.discKeyStructures,
2642 2048);
2643 break;
2645 case DvdManufacturerDescriptor:
2646 memcpy(
2647 nt_desc.manf->ManufacturingInformation,
2648 desc.manf.discManufacturingInfo,
2649 2048);
2650 break;
2652 case DvdBCADescriptor:
2653 case DvdMaxDescriptor:
2654 default:
2655 /* Silence warning */
2656 break;
2659 return ret;
2660 #else
2661 FIXME("\n");
2662 #endif
2663 return STATUS_SUCCESS;
2667 /******************************************************************
2668 * GetInquiryData
2669 * Implements the IOCTL_GET_INQUIRY_DATA ioctl.
2670 * Returns Inquiry data for all devices on the specified scsi bus
2671 * Returns STATUS_BUFFER_TOO_SMALL if the output buffer is too small,
2672 * STATUS_INVALID_DEVICE_REQUEST if the given handle isn't to a SCSI device,
2673 * or STATUS_NOT_SUPPORTED if the OS driver is too old
2675 static NTSTATUS GetInquiryData(int fd, PSCSI_ADAPTER_BUS_INFO BufferOut, DWORD OutBufferSize)
2677 #ifdef HAVE_SG_IO_HDR_T_INTERFACE_ID
2678 PSCSI_INQUIRY_DATA pInquiryData = NULL;
2679 UCHAR sense_buffer[32];
2680 int iochk, version;
2681 sg_io_hdr_t iocmd;
2682 UCHAR inquiry[INQ_CMD_LEN] = {INQUIRY, 0, 0, 0, INQ_REPLY_LEN, 0};
2684 /* Check we have a SCSI device and a supported driver */
2685 if(ioctl(fd, SG_GET_VERSION_NUM, &version) != 0)
2687 WARN("IOCTL_SCSI_GET_INQUIRY_DATA sg driver is not loaded\n");
2688 return STATUS_INVALID_DEVICE_REQUEST;
2690 if(version < 30000 )
2691 return STATUS_NOT_SUPPORTED;
2693 /* FIXME: Enumerate devices on the bus */
2694 BufferOut->NumberOfBuses = 1;
2695 BufferOut->BusData[0].NumberOfLogicalUnits = 1;
2696 BufferOut->BusData[0].InquiryDataOffset = sizeof(SCSI_ADAPTER_BUS_INFO);
2698 pInquiryData = (PSCSI_INQUIRY_DATA)(BufferOut + 1);
2700 RtlZeroMemory(&iocmd, sizeof(iocmd));
2701 iocmd.interface_id = 'S';
2702 iocmd.cmd_len = sizeof(inquiry);
2703 iocmd.mx_sb_len = sizeof(sense_buffer);
2704 iocmd.dxfer_direction = SG_DXFER_FROM_DEV;
2705 iocmd.dxfer_len = INQ_REPLY_LEN;
2706 iocmd.dxferp = pInquiryData->InquiryData;
2707 iocmd.cmdp = inquiry;
2708 iocmd.sbp = sense_buffer;
2709 iocmd.timeout = 1000;
2711 iochk = ioctl(fd, SG_IO, &iocmd);
2712 if(iochk != 0)
2713 WARN("ioctl SG_IO returned %d, error (%s)\n", iochk, strerror(errno));
2715 CDROM_GetInterfaceInfo(fd, &BufferOut->BusData[0].InitiatorBusId, &pInquiryData->PathId, &pInquiryData->TargetId, &pInquiryData->Lun);
2716 pInquiryData->DeviceClaimed = TRUE;
2717 pInquiryData->InquiryDataLength = INQ_REPLY_LEN;
2718 pInquiryData->NextInquiryDataOffset = 0;
2719 return STATUS_SUCCESS;
2720 #else
2721 FIXME("not implemented for nonlinux\n");
2722 return STATUS_NOT_SUPPORTED;
2723 #endif
2726 /******************************************************************
2727 * CDROM_DeviceIoControl
2731 NTSTATUS CDROM_DeviceIoControl(HANDLE hDevice,
2732 HANDLE hEvent, PIO_APC_ROUTINE UserApcRoutine,
2733 PVOID UserApcContext,
2734 PIO_STATUS_BLOCK piosb,
2735 ULONG dwIoControlCode,
2736 LPVOID lpInBuffer, DWORD nInBufferSize,
2737 LPVOID lpOutBuffer, DWORD nOutBufferSize)
2739 DWORD sz = 0;
2740 NTSTATUS status = STATUS_SUCCESS;
2741 int fd, needs_close, dev;
2743 TRACE("%p %s %p %d %p %d %p\n",
2744 hDevice, iocodex(dwIoControlCode), lpInBuffer, nInBufferSize,
2745 lpOutBuffer, nOutBufferSize, piosb);
2747 piosb->Information = 0;
2749 if ((status = server_get_unix_fd( hDevice, 0, &fd, &needs_close, NULL, NULL )))
2751 if (status == STATUS_BAD_DEVICE_TYPE) return status; /* no associated fd */
2752 goto error;
2755 if ((status = CDROM_Open(fd, &dev)))
2757 if (needs_close) close( fd );
2758 goto error;
2761 #ifdef __APPLE__
2763 char name[100];
2765 /* This is ugly as hell, but Mac OS is unable to do anything from the
2766 * partition fd, it wants an fd for the whole device, and it sometimes
2767 * also requires the device fd to be closed first, so we have to close
2768 * the handle that the caller gave us.
2769 * Also for some reason it wants the fd to be closed before we even
2770 * open the parent if we're trying to eject the disk.
2772 if ((status = get_parent_device( fd, name, sizeof(name) ))) goto error;
2773 if (dwIoControlCode == IOCTL_STORAGE_EJECT_MEDIA)
2774 NtClose( hDevice );
2775 if (needs_close) close( fd );
2776 TRACE("opening parent %s\n", name );
2777 if ((fd = open( name, O_RDONLY )) == -1)
2779 status = FILE_GetNtStatus();
2780 goto error;
2782 needs_close = 1;
2784 #endif
2786 switch (dwIoControlCode)
2788 case IOCTL_STORAGE_CHECK_VERIFY:
2789 case IOCTL_CDROM_CHECK_VERIFY:
2790 case IOCTL_DISK_CHECK_VERIFY:
2791 sz = 0;
2792 CDROM_ClearCacheEntry(dev);
2793 if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
2794 status = STATUS_INVALID_PARAMETER;
2795 else status = CDROM_Verify(dev, fd);
2796 break;
2798 /* EPP case IOCTL_STORAGE_CHECK_VERIFY2: */
2800 /* EPP case IOCTL_STORAGE_FIND_NEW_DEVICES: */
2801 /* EPP case IOCTL_CDROM_FIND_NEW_DEVICES: */
2803 case IOCTL_STORAGE_LOAD_MEDIA:
2804 case IOCTL_CDROM_LOAD_MEDIA:
2805 sz = 0;
2806 CDROM_ClearCacheEntry(dev);
2807 if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
2808 status = STATUS_INVALID_PARAMETER;
2809 else status = CDROM_SetTray(fd, FALSE);
2810 break;
2811 case IOCTL_STORAGE_EJECT_MEDIA:
2812 sz = 0;
2813 CDROM_ClearCacheEntry(dev);
2814 if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
2815 status = STATUS_INVALID_PARAMETER;
2816 else
2817 status = CDROM_SetTray(fd, TRUE);
2818 break;
2820 case IOCTL_CDROM_MEDIA_REMOVAL:
2821 case IOCTL_DISK_MEDIA_REMOVAL:
2822 case IOCTL_STORAGE_MEDIA_REMOVAL:
2823 case IOCTL_STORAGE_EJECTION_CONTROL:
2824 /* FIXME the last ioctl:s is not the same as the two others...
2825 * lockcount/owner should be handled */
2826 sz = 0;
2827 CDROM_ClearCacheEntry(dev);
2828 if (lpOutBuffer != NULL || nOutBufferSize != 0) status = STATUS_INVALID_PARAMETER;
2829 else if (nInBufferSize < sizeof(PREVENT_MEDIA_REMOVAL)) status = STATUS_BUFFER_TOO_SMALL;
2830 else status = CDROM_ControlEjection(fd, lpInBuffer);
2831 break;
2833 /* EPP case IOCTL_STORAGE_GET_MEDIA_TYPES: */
2835 case IOCTL_STORAGE_GET_DEVICE_NUMBER:
2836 sz = sizeof(STORAGE_DEVICE_NUMBER);
2837 if (lpInBuffer != NULL || nInBufferSize != 0) status = STATUS_INVALID_PARAMETER;
2838 else if (nOutBufferSize < sz) status = STATUS_BUFFER_TOO_SMALL;
2839 else status = CDROM_GetDeviceNumber(dev, lpOutBuffer);
2840 break;
2842 case IOCTL_STORAGE_RESET_DEVICE:
2843 sz = 0;
2844 CDROM_ClearCacheEntry(dev);
2845 if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
2846 status = STATUS_INVALID_PARAMETER;
2847 else status = CDROM_ResetAudio(fd);
2848 break;
2850 case IOCTL_CDROM_GET_CONTROL:
2851 sz = sizeof(CDROM_AUDIO_CONTROL);
2852 if (lpInBuffer != NULL || nInBufferSize != 0) status = STATUS_INVALID_PARAMETER;
2853 else if (nOutBufferSize < sz) status = STATUS_BUFFER_TOO_SMALL;
2854 else status = CDROM_GetControl(dev, fd, lpOutBuffer);
2855 break;
2857 case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
2858 sz = sizeof(DISK_GEOMETRY);
2859 if (lpInBuffer != NULL || nInBufferSize != 0) status = STATUS_INVALID_PARAMETER;
2860 else if (nOutBufferSize < sz) status = STATUS_BUFFER_TOO_SMALL;
2861 else status = CDROM_GetDriveGeometry(dev, fd, lpOutBuffer);
2862 break;
2864 case IOCTL_CDROM_DISK_TYPE:
2865 sz = sizeof(CDROM_DISK_DATA);
2866 /* CDROM_ClearCacheEntry(dev); */
2867 if (lpInBuffer != NULL || nInBufferSize != 0) status = STATUS_INVALID_PARAMETER;
2868 else if (nOutBufferSize < sz) status = STATUS_BUFFER_TOO_SMALL;
2869 else status = CDROM_GetDiskData(dev, fd, lpOutBuffer);
2870 break;
2872 /* EPP case IOCTL_CDROM_GET_LAST_SESSION: */
2874 case IOCTL_CDROM_READ_Q_CHANNEL:
2875 sz = sizeof(SUB_Q_CHANNEL_DATA);
2876 if (lpInBuffer == NULL || nInBufferSize < sizeof(CDROM_SUB_Q_DATA_FORMAT))
2877 status = STATUS_INVALID_PARAMETER;
2878 else if (nOutBufferSize < sz) status = STATUS_BUFFER_TOO_SMALL;
2879 else status = CDROM_ReadQChannel(dev, fd, lpInBuffer, lpOutBuffer);
2880 break;
2882 case IOCTL_CDROM_READ_TOC:
2883 sz = sizeof(CDROM_TOC);
2884 if (lpInBuffer != NULL || nInBufferSize != 0) status = STATUS_INVALID_PARAMETER;
2885 else if (nOutBufferSize < sz) status = STATUS_BUFFER_TOO_SMALL;
2886 else status = CDROM_ReadTOC(dev, fd, lpOutBuffer);
2887 break;
2889 /* EPP case IOCTL_CDROM_READ_TOC_EX: */
2891 case IOCTL_CDROM_PAUSE_AUDIO:
2892 sz = 0;
2893 if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
2894 status = STATUS_INVALID_PARAMETER;
2895 else status = CDROM_PauseAudio(fd);
2896 break;
2897 case IOCTL_CDROM_PLAY_AUDIO_MSF:
2898 sz = 0;
2899 if (lpOutBuffer != NULL || nOutBufferSize != 0) status = STATUS_INVALID_PARAMETER;
2900 else if (nInBufferSize < sizeof(CDROM_PLAY_AUDIO_MSF)) status = STATUS_BUFFER_TOO_SMALL;
2901 else status = CDROM_PlayAudioMSF(fd, lpInBuffer);
2902 break;
2903 case IOCTL_CDROM_RESUME_AUDIO:
2904 sz = 0;
2905 if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
2906 status = STATUS_INVALID_PARAMETER;
2907 else status = CDROM_ResumeAudio(fd);
2908 break;
2909 case IOCTL_CDROM_SEEK_AUDIO_MSF:
2910 sz = 0;
2911 if (lpOutBuffer != NULL || nOutBufferSize != 0) status = STATUS_INVALID_PARAMETER;
2912 else if (nInBufferSize < sizeof(CDROM_SEEK_AUDIO_MSF)) status = STATUS_BUFFER_TOO_SMALL;
2913 else status = CDROM_SeekAudioMSF(dev, fd, lpInBuffer);
2914 break;
2915 case IOCTL_CDROM_STOP_AUDIO:
2916 sz = 0;
2917 CDROM_ClearCacheEntry(dev); /* Maybe intention is to change media */
2918 if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
2919 status = STATUS_INVALID_PARAMETER;
2920 else status = CDROM_StopAudio(fd);
2921 break;
2922 case IOCTL_CDROM_GET_VOLUME:
2923 sz = sizeof(VOLUME_CONTROL);
2924 if (lpInBuffer != NULL || nInBufferSize != 0) status = STATUS_INVALID_PARAMETER;
2925 else if (nOutBufferSize < sz) status = STATUS_BUFFER_TOO_SMALL;
2926 else status = CDROM_GetVolume(fd, lpOutBuffer);
2927 break;
2928 case IOCTL_CDROM_SET_VOLUME:
2929 sz = 0;
2930 CDROM_ClearCacheEntry(dev);
2931 if (lpInBuffer == NULL || nInBufferSize < sizeof(VOLUME_CONTROL) || lpOutBuffer != NULL)
2932 status = STATUS_INVALID_PARAMETER;
2933 else status = CDROM_SetVolume(fd, lpInBuffer);
2934 break;
2935 case IOCTL_CDROM_RAW_READ:
2936 sz = 0;
2937 if (nInBufferSize < sizeof(RAW_READ_INFO)) status = STATUS_INVALID_PARAMETER;
2938 else if (lpOutBuffer == NULL) status = STATUS_BUFFER_TOO_SMALL;
2939 else status = CDROM_RawRead(fd, lpInBuffer, lpOutBuffer,
2940 nOutBufferSize, &sz);
2941 break;
2942 case IOCTL_SCSI_GET_ADDRESS:
2943 sz = sizeof(SCSI_ADDRESS);
2944 if (lpInBuffer != NULL || nInBufferSize != 0) status = STATUS_INVALID_PARAMETER;
2945 else if (nOutBufferSize < sz) status = STATUS_BUFFER_TOO_SMALL;
2946 else status = CDROM_GetAddress(fd, lpOutBuffer);
2947 break;
2948 case IOCTL_SCSI_PASS_THROUGH_DIRECT:
2949 sz = sizeof(SCSI_PASS_THROUGH_DIRECT);
2950 if (lpOutBuffer == NULL) status = STATUS_INVALID_PARAMETER;
2951 else if (nOutBufferSize < sizeof(SCSI_PASS_THROUGH_DIRECT)) status = STATUS_BUFFER_TOO_SMALL;
2952 else status = CDROM_ScsiPassThroughDirect(fd, lpOutBuffer);
2953 break;
2954 case IOCTL_SCSI_PASS_THROUGH:
2955 sz = sizeof(SCSI_PASS_THROUGH);
2956 if (lpOutBuffer == NULL) status = STATUS_INVALID_PARAMETER;
2957 else if (nOutBufferSize < sizeof(SCSI_PASS_THROUGH)) status = STATUS_BUFFER_TOO_SMALL;
2958 else status = CDROM_ScsiPassThrough(fd, lpOutBuffer);
2959 break;
2960 case IOCTL_SCSI_GET_CAPABILITIES:
2961 sz = sizeof(IO_SCSI_CAPABILITIES);
2962 if (lpOutBuffer == NULL) status = STATUS_INVALID_PARAMETER;
2963 else if (nOutBufferSize < sizeof(IO_SCSI_CAPABILITIES)) status = STATUS_BUFFER_TOO_SMALL;
2964 else status = CDROM_ScsiGetCaps(fd, lpOutBuffer);
2965 break;
2966 case IOCTL_DVD_START_SESSION:
2967 sz = sizeof(DVD_SESSION_ID);
2968 if (lpOutBuffer == NULL) status = STATUS_INVALID_PARAMETER;
2969 else if (nOutBufferSize < sz) status = STATUS_BUFFER_TOO_SMALL;
2970 else
2972 TRACE("before in 0x%08x out 0x%08x\n",(lpInBuffer)?*(PDVD_SESSION_ID)lpInBuffer:0,
2973 *(PDVD_SESSION_ID)lpOutBuffer);
2974 status = DVD_StartSession(fd, lpInBuffer, lpOutBuffer);
2975 TRACE("before in 0x%08x out 0x%08x\n",(lpInBuffer)?*(PDVD_SESSION_ID)lpInBuffer:0,
2976 *(PDVD_SESSION_ID)lpOutBuffer);
2978 break;
2979 case IOCTL_DVD_END_SESSION:
2980 sz = sizeof(DVD_SESSION_ID);
2981 if ((lpInBuffer == NULL) || (nInBufferSize < sz))status = STATUS_INVALID_PARAMETER;
2982 else status = DVD_EndSession(fd, lpInBuffer);
2983 break;
2984 case IOCTL_DVD_SEND_KEY:
2985 sz = 0;
2986 if (!lpInBuffer ||
2987 (((PDVD_COPY_PROTECT_KEY)lpInBuffer)->KeyLength != nInBufferSize))
2988 status = STATUS_INVALID_PARAMETER;
2989 else
2991 TRACE("doing DVD_SendKey\n");
2992 status = DVD_SendKey(fd, lpInBuffer);
2994 break;
2995 case IOCTL_DVD_READ_KEY:
2996 if (!lpInBuffer ||
2997 (((PDVD_COPY_PROTECT_KEY)lpInBuffer)->KeyLength != nInBufferSize))
2998 status = STATUS_INVALID_PARAMETER;
2999 else if (lpInBuffer !=lpOutBuffer) status = STATUS_BUFFER_TOO_SMALL;
3000 else
3002 TRACE("doing DVD_READ_KEY\n");
3003 sz = ((PDVD_COPY_PROTECT_KEY)lpInBuffer)->KeyLength;
3004 status = DVD_ReadKey(fd, lpInBuffer);
3006 break;
3007 case IOCTL_DVD_GET_REGION:
3008 sz = sizeof(DVD_REGION);
3009 if (lpInBuffer != NULL || nInBufferSize != 0) status = STATUS_INVALID_PARAMETER;
3010 else if (nOutBufferSize < sz) status = STATUS_BUFFER_TOO_SMALL;
3011 TRACE("doing DVD_Get_REGION\n");
3012 status = DVD_GetRegion(fd, lpOutBuffer);
3013 break;
3014 case IOCTL_DVD_READ_STRUCTURE:
3015 sz = sizeof(DVD_LAYER_DESCRIPTOR);
3016 if (lpInBuffer == NULL || nInBufferSize != sizeof(DVD_READ_STRUCTURE)) status = STATUS_INVALID_PARAMETER;
3017 else if (nOutBufferSize < sz) status = STATUS_BUFFER_TOO_SMALL;
3018 else
3020 TRACE("doing DVD_READ_STRUCTURE\n");
3021 status = DVD_ReadStructure(fd, lpInBuffer, lpOutBuffer);
3023 break;
3025 case IOCTL_SCSI_GET_INQUIRY_DATA:
3026 sz = INQ_REPLY_LEN;
3027 status = GetInquiryData(fd, lpOutBuffer, nOutBufferSize);
3028 break;
3030 default:
3031 if (needs_close) close( fd );
3032 return STATUS_NOT_SUPPORTED;
3034 if (needs_close) close( fd );
3035 error:
3036 piosb->u.Status = status;
3037 piosb->Information = sz;
3038 if (hEvent) NtSetEvent(hEvent, NULL);
3039 return status;