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
25 #include "wine/port.h"
38 #ifdef HAVE_SYS_STAT_H
39 # include <sys/stat.h>
41 #include <sys/types.h>
43 #ifdef HAVE_SYS_IOCTL_H
44 #include <sys/ioctl.h>
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 */
54 #ifdef HAVE_SCSI_SCSI_IOCTL_H
55 # include <scsi/scsi_ioctl.h>
57 #ifdef HAVE_LINUX_MAJOR_H
58 # include <linux/major.h>
60 #ifdef HAVE_LINUX_HDREG_H
61 # include <linux/hdreg.h>
63 #ifdef HAVE_LINUX_PARAM_H
64 # include <linux/param.h>
66 #ifdef HAVE_LINUX_CDROM_H
67 # include <linux/cdrom.h>
69 #ifdef HAVE_LINUX_UCDROM_H
70 # include <linux/ucdrom.h>
72 #ifdef HAVE_SYS_CDIO_H
73 # include <sys/cdio.h>
75 #ifdef HAVE_SYS_SCSIIO_H
76 # include <sys/scsiio.h>
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/SCSITask.h>
87 # include <IOKit/scsi/SCSICmds_REQUEST_SENSE_Defs.h>
88 # define SENSEBUFLEN kSenseDefaultSize
98 uint8_t reserved0144
[2];
112 } dk_scsi_identify_t
;
114 #define DKIOCSCSICOMMAND _IOWR('d', 253, dk_scsi_command_t)
115 #define DKIOCSCSIIDENTIFY _IOR('d', 254, dk_scsi_identify_t)
119 #define NONAMELESSUNION
120 #define NONAMELESSSTRUCT
121 #include "ntstatus.h"
122 #define WIN32_NO_STATUS
124 #include "winternl.h"
125 #include "winioctl.h"
126 #include "ntddstor.h"
127 #include "ntddcdrm.h"
128 #include "ddk/ntddcdvd.h"
129 #include "ntddscsi.h"
130 #include "ntdll_misc.h"
131 #include "wine/server.h"
132 #include "wine/library.h"
133 #include "wine/debug.h"
135 WINE_DEFAULT_DEBUG_CHANNEL(cdrom
);
137 /* Non-Linux systems do not have linux/cdrom.h and the like, and thus
138 lack the following constants. */
141 # define CD_SECS 60 /* seconds per minute */
144 # define CD_FRAMES 75 /* frames per second */
147 #ifdef WORDS_BIGENDIAN
148 #define GET_BE_DWORD(x) (x)
150 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
153 static const struct iocodexs
158 #define X(x) { x, #x },
159 X(IOCTL_CDROM_CHECK_VERIFY
)
160 X(IOCTL_CDROM_CURRENT_POSITION
)
161 X(IOCTL_CDROM_DISK_TYPE
)
162 X(IOCTL_CDROM_GET_CONTROL
)
163 X(IOCTL_CDROM_GET_DRIVE_GEOMETRY
)
164 X(IOCTL_CDROM_GET_VOLUME
)
165 X(IOCTL_CDROM_LOAD_MEDIA
)
166 X(IOCTL_CDROM_MEDIA_CATALOG
)
167 X(IOCTL_CDROM_MEDIA_REMOVAL
)
168 X(IOCTL_CDROM_PAUSE_AUDIO
)
169 X(IOCTL_CDROM_PLAY_AUDIO_MSF
)
170 X(IOCTL_CDROM_RAW_READ
)
171 X(IOCTL_CDROM_READ_Q_CHANNEL
)
172 X(IOCTL_CDROM_READ_TOC
)
173 X(IOCTL_CDROM_RESUME_AUDIO
)
174 X(IOCTL_CDROM_SEEK_AUDIO_MSF
)
175 X(IOCTL_CDROM_SET_VOLUME
)
176 X(IOCTL_CDROM_STOP_AUDIO
)
177 X(IOCTL_CDROM_TRACK_ISRC
)
178 X(IOCTL_DISK_MEDIA_REMOVAL
)
179 X(IOCTL_DVD_END_SESSION
)
180 X(IOCTL_DVD_GET_REGION
)
181 X(IOCTL_DVD_READ_KEY
)
182 X(IOCTL_DVD_READ_STRUCTURE
)
183 X(IOCTL_DVD_SEND_KEY
)
184 X(IOCTL_DVD_START_SESSION
)
185 X(IOCTL_SCSI_GET_ADDRESS
)
186 X(IOCTL_SCSI_GET_CAPABILITIES
)
187 X(IOCTL_SCSI_GET_INQUIRY_DATA
)
188 X(IOCTL_SCSI_PASS_THROUGH
)
189 X(IOCTL_SCSI_PASS_THROUGH_DIRECT
)
190 X(IOCTL_STORAGE_CHECK_VERIFY
)
191 X(IOCTL_STORAGE_CHECK_VERIFY2
)
192 X(IOCTL_STORAGE_EJECTION_CONTROL
)
193 X(IOCTL_STORAGE_EJECT_MEDIA
)
194 X(IOCTL_STORAGE_GET_DEVICE_NUMBER
)
195 X(IOCTL_STORAGE_GET_MEDIA_TYPES
)
196 X(IOCTL_STORAGE_GET_MEDIA_TYPES_EX
)
197 X(IOCTL_STORAGE_LOAD_MEDIA
)
198 X(IOCTL_STORAGE_MEDIA_REMOVAL
)
199 X(IOCTL_STORAGE_RESET_DEVICE
)
202 static const char *iocodex(DWORD code
)
205 static char buffer
[25];
206 for(i
=0; i
<sizeof(iocodextable
)/sizeof(struct iocodexs
); i
++)
207 if (code
==iocodextable
[i
].code
)
208 return iocodextable
[i
].codex
;
209 sprintf(buffer
, "IOCTL_CODE_%x", (int)code
);
213 #define INQ_REPLY_LEN 36
214 #define INQ_CMD_LEN 6
216 #define FRAME_OF_ADDR(a) (((int)(a)[1] * CD_SECS + (a)[2]) * CD_FRAMES + (a)[3])
217 #define FRAME_OF_MSF(a) (((int)(a).M * CD_SECS + (a).S) * CD_FRAMES + (a).F)
218 #define FRAME_OF_TOC(toc, idx) FRAME_OF_ADDR((toc).TrackData[idx - (toc).FirstTrack].Address)
219 #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;}
221 /* The documented format of DVD_LAYER_DESCRIPTOR is wrong. Even the format in the
222 * DDK's header is wrong. There are four bytes at the start defined by
223 * MMC-5. The first two are the size of the structure in big-endian order as
224 * defined by MMC-5. The other two are reserved.
230 UCHAR BookVersion
: 4;
232 UCHAR MinimumRate
: 4;
236 UCHAR NumberOfLayers
: 2;
238 UCHAR TrackDensity
: 4;
239 UCHAR LinearDensity
: 4;
240 ULONG StartingDataSector
;
242 ULONG EndLayerZeroSector
;
246 } internal_dvd_layer_descriptor
;
249 static NTSTATUS
CDROM_ReadTOC(int, int, CDROM_TOC
*);
250 static NTSTATUS
CDROM_GetStatusCode(int);
256 # define IDE6_MAJOR 88
259 # define IDE7_MAJOR 89
262 # ifdef CDROM_SEND_PACKET
263 /* structure for CDROM_PACKET_COMMAND ioctl */
264 /* not all Linux versions have all the fields, so we define the
265 * structure ourselves to make sure */
266 struct linux_cdrom_generic_command
268 unsigned char cmd
[CDROM_PACKET_SIZE
];
269 unsigned char *buffer
;
272 struct request_sense
*sense
;
273 unsigned char data_direction
;
278 # endif /* CDROM_SEND_PACKET */
282 /* FIXME: this is needed because we can't open simultaneously several times /dev/cdrom
283 * this should be removed when a proper device interface is implemented
285 * (WS) We need this to keep track of current position and to safely
286 * detect media changes. Besides this should provide a great speed up
292 char toc_good
; /* if false, will reread TOC from disk */
294 SUB_Q_CURRENT_POSITION CurrentPosition
;
296 /* who has more than 5 cdroms on his/her machine ?? */
297 /* FIXME: this should grow depending on the number of cdroms we install/configure
300 #define MAX_CACHE_ENTRIES 5
301 static struct cdrom_cache cdrom_cache
[MAX_CACHE_ENTRIES
];
303 static RTL_CRITICAL_SECTION cache_section
;
304 static RTL_CRITICAL_SECTION_DEBUG critsect_debug
=
306 0, 0, &cache_section
,
307 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
308 0, 0, { (DWORD_PTR
)(__FILE__
": cache_section") }
310 static RTL_CRITICAL_SECTION cache_section
= { &critsect_debug
, -1, 0, 0, 0, 0 };
312 /* Proposed media change function: not really needed at this time */
313 /* This is a 1 or 0 type of function */
315 static int CDROM_MediaChanged(int dev
)
319 struct cdrom_tochdr hdr
;
320 struct cdrom_tocentry entry
;
322 if (dev
< 0 || dev
>= MAX_CACHE_ENTRIES
)
324 if ( ioctl(cdrom_cache
[dev
].fd
, CDROMREADTOCHDR
, &hdr
) == -1 )
327 if ( memcmp(&hdr
, &cdrom_cache
[dev
].hdr
, sizeof(struct cdrom_tochdr
)) )
330 for (i
=hdr
.cdth_trk0
; i
<=hdr
.cdth_trk1
+1; i
++)
332 if (i
== hdr
.cdth_trk1
+ 1)
334 entry
.cdte_track
= CDROM_LEADOUT
;
336 entry
.cdte_track
= i
;
338 entry
.cdte_format
= CDROM_MSF
;
339 if ( ioctl(cdrom_cache
[dev
].fd
, CDROMREADTOCENTRY
, &entry
) == -1)
341 if ( memcmp(&entry
, cdrom_cache
[dev
].entry
+i
-hdr
.cdth_trk0
,
342 sizeof(struct cdrom_tocentry
)) )
350 /******************************************************************
353 * On Mac OS, get the device for the whole disk from a fd that points to a partition.
354 * This is ugly and inefficient, but we have no choice since the partition fd doesn't
355 * support the eject ioctl.
358 static NTSTATUS
get_parent_device( int fd
, char *name
, size_t len
)
360 NTSTATUS status
= STATUS_NO_SUCH_FILE
;
363 io_service_t service
;
364 CFMutableDictionaryRef dict
;
367 if (fstat( fd
, &st
) == -1) return FILE_GetNtStatus();
368 if (!S_ISCHR( st
.st_mode
)) return STATUS_OBJECT_TYPE_MISMATCH
;
370 /* create a dictionary with the right major/minor numbers */
372 if (!(dict
= IOServiceMatching( kIOMediaClass
))) return STATUS_NO_MEMORY
;
374 i
= major( st
.st_rdev
);
375 val
= CFNumberCreate( NULL
, kCFNumberIntType
, &i
);
376 CFDictionaryAddValue( dict
, CFSTR( "BSD Major" ), val
);
379 i
= minor( st
.st_rdev
);
380 val
= CFNumberCreate( NULL
, kCFNumberIntType
, &i
);
381 CFDictionaryAddValue( dict
, CFSTR( "BSD Minor" ), val
);
384 CFDictionaryAddValue( dict
, CFSTR("Removable"), kCFBooleanTrue
);
386 service
= IOServiceGetMatchingService( kIOMasterPortDefault
, dict
);
388 /* now look for the parent that has the "Whole" attribute set to TRUE */
392 io_service_t parent
= 0;
397 if (!IOObjectConformsTo( service
, kIOMediaClass
))
399 if (!(whole
= IORegistryEntryCreateCFProperty( service
, CFSTR("Whole"), NULL
, 0 )))
401 ok
= (whole
== kCFBooleanTrue
);
405 if ((str
= IORegistryEntryCreateCFProperty( service
, CFSTR("BSD Name"), NULL
, 0 )))
407 strcpy( name
, "/dev/r" );
408 CFStringGetCString( str
, name
+ 6, len
- 6, kCFStringEncodingUTF8
);
410 status
= STATUS_SUCCESS
;
412 IOObjectRelease( service
);
416 IORegistryEntryGetParentEntry( service
, kIOServicePlane
, &parent
);
417 IOObjectRelease( service
);
425 /******************************************************************
426 * CDROM_SyncCache [internal]
428 * Read the TOC in and store it in the cdrom_cache structure.
429 * Further requests for the TOC will be copied from the cache
430 * unless certain events like disk ejection is detected, in which
431 * case the cache will be cleared, causing it to be resynced.
432 * The cache section must be held by caller.
434 static NTSTATUS
CDROM_SyncCache(int dev
, int fd
)
438 struct cdrom_tochdr hdr
;
439 struct cdrom_tocentry entry
;
441 CDROM_TOC
*toc
= &cdrom_cache
[dev
].toc
;
442 cdrom_cache
[dev
].toc_good
= 0;
444 if (ioctl(fd
, CDROMREADTOCHDR
, &hdr
) == -1)
446 WARN("(%d) -- Error occurred (%s)!\n", dev
, strerror(errno
));
447 return FILE_GetNtStatus();
450 toc
->FirstTrack
= hdr
.cdth_trk0
;
451 toc
->LastTrack
= hdr
.cdth_trk1
;
452 tsz
= sizeof(toc
->FirstTrack
) + sizeof(toc
->LastTrack
)
453 + sizeof(TRACK_DATA
) * (toc
->LastTrack
-toc
->FirstTrack
+2);
454 toc
->Length
[0] = tsz
>> 8;
455 toc
->Length
[1] = tsz
;
457 TRACE("caching toc from=%d to=%d\n", toc
->FirstTrack
, toc
->LastTrack
);
459 for (i
= toc
->FirstTrack
; i
<= toc
->LastTrack
+ 1; i
++)
461 if (i
== toc
->LastTrack
+ 1)
462 entry
.cdte_track
= CDROM_LEADOUT
;
464 entry
.cdte_track
= i
;
465 entry
.cdte_format
= CDROM_MSF
;
466 if (ioctl(fd
, CDROMREADTOCENTRY
, &entry
) == -1)
468 WARN("error read entry (%s)\n", strerror(errno
));
469 return FILE_GetNtStatus();
471 toc
->TrackData
[i
- toc
->FirstTrack
].Control
= entry
.cdte_ctrl
;
472 toc
->TrackData
[i
- toc
->FirstTrack
].Adr
= entry
.cdte_adr
;
473 /* marking last track with leadout value as index */
474 toc
->TrackData
[i
- toc
->FirstTrack
].TrackNumber
= entry
.cdte_track
;
475 toc
->TrackData
[i
- toc
->FirstTrack
].Address
[0] = 0;
476 toc
->TrackData
[i
- toc
->FirstTrack
].Address
[1] = entry
.cdte_addr
.msf
.minute
;
477 toc
->TrackData
[i
- toc
->FirstTrack
].Address
[2] = entry
.cdte_addr
.msf
.second
;
478 toc
->TrackData
[i
- toc
->FirstTrack
].Address
[3] = entry
.cdte_addr
.msf
.frame
;
480 cdrom_cache
[dev
].toc_good
= 1;
481 return STATUS_SUCCESS
;
483 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__DragonFly__)
486 struct ioc_toc_header hdr
;
487 struct ioc_read_toc_entry entry
;
488 struct cd_toc_entry toc_buffer
;
490 CDROM_TOC
*toc
= &cdrom_cache
[dev
].toc
;
491 cdrom_cache
[dev
].toc_good
= 0;
493 if (ioctl(fd
, CDIOREADTOCHEADER
, &hdr
) == -1)
495 WARN("(%d) -- Error occurred (%s)!\n", dev
, strerror(errno
));
496 return FILE_GetNtStatus();
498 toc
->FirstTrack
= hdr
.starting_track
;
499 toc
->LastTrack
= hdr
.ending_track
;
500 tsz
= sizeof(toc
->FirstTrack
) + sizeof(toc
->LastTrack
)
501 + sizeof(TRACK_DATA
) * (toc
->LastTrack
-toc
->FirstTrack
+2);
502 toc
->Length
[0] = tsz
>> 8;
503 toc
->Length
[1] = tsz
;
505 TRACE("caching toc from=%d to=%d\n", toc
->FirstTrack
, toc
->LastTrack
);
507 for (i
= toc
->FirstTrack
; i
<= toc
->LastTrack
+ 1; i
++)
509 if (i
== toc
->LastTrack
+ 1)
512 entry
.starting_track
= LEADOUT
;
514 entry
.starting_track
= i
;
516 memset(&toc_buffer
, 0, sizeof(toc_buffer
));
517 entry
.address_format
= CD_MSF_FORMAT
;
518 entry
.data_len
= sizeof(toc_buffer
);
519 entry
.data
= &toc_buffer
;
520 if (ioctl(fd
, CDIOREADTOCENTRYS
, &entry
) == -1)
522 WARN("error read entry (%s)\n", strerror(errno
));
523 return FILE_GetNtStatus();
525 toc
->TrackData
[i
- toc
->FirstTrack
].Control
= toc_buffer
.control
;
526 toc
->TrackData
[i
- toc
->FirstTrack
].Adr
= toc_buffer
.addr_type
;
527 /* marking last track with leadout value as index */
528 toc
->TrackData
[i
- toc
->FirstTrack
].TrackNumber
= entry
.starting_track
;
529 toc
->TrackData
[i
- toc
->FirstTrack
].Address
[0] = 0;
530 toc
->TrackData
[i
- toc
->FirstTrack
].Address
[1] = toc_buffer
.addr
.msf
.minute
;
531 toc
->TrackData
[i
- toc
->FirstTrack
].Address
[2] = toc_buffer
.addr
.msf
.second
;
532 toc
->TrackData
[i
- toc
->FirstTrack
].Address
[3] = toc_buffer
.addr
.msf
.frame
;
534 cdrom_cache
[dev
].toc_good
= 1;
535 return STATUS_SUCCESS
;
537 #elif defined(__APPLE__)
539 dk_cd_read_toc_t hdr
;
540 CDROM_TOC
*toc
= &cdrom_cache
[dev
].toc
;
541 cdrom_cache
[dev
].toc_good
= 0;
543 memset( &hdr
, 0, sizeof(hdr
) );
545 hdr
.bufferLength
= sizeof(*toc
);
546 if (ioctl(fd
, DKIOCCDREADTOC
, &hdr
) == -1)
548 WARN("(%d) -- Error occurred (%s)!\n", dev
, strerror(errno
));
549 return FILE_GetNtStatus();
551 for (i
= toc
->FirstTrack
; i
<= toc
->LastTrack
+ 1; i
++)
553 /* convert address format */
554 TRACK_DATA
*data
= &toc
->TrackData
[i
- toc
->FirstTrack
];
555 DWORD frame
= (((DWORD
)data
->Address
[0] << 24) | ((DWORD
)data
->Address
[1] << 16) |
556 ((DWORD
)data
->Address
[2] << 8) | data
->Address
[3]);
557 MSF_OF_FRAME( data
->Address
[1], frame
);
558 data
->Address
[0] = 0;
561 cdrom_cache
[dev
].toc_good
= 1;
562 return STATUS_SUCCESS
;
564 FIXME("not supported on this O/S\n");
565 return STATUS_NOT_SUPPORTED
;
569 static void CDROM_ClearCacheEntry(int dev
)
571 RtlEnterCriticalSection( &cache_section
);
572 cdrom_cache
[dev
].toc_good
= 0;
573 RtlLeaveCriticalSection( &cache_section
);
578 /******************************************************************
579 * CDROM_GetInterfaceInfo
581 * Determines the ide interface (the number after the ide), and the
582 * number of the device on that interface for ide cdroms (*iface <= 1).
583 * Determines the scsi information for scsi cdroms (*iface >= 2).
584 * Returns false if the info cannot not be obtained.
586 static int CDROM_GetInterfaceInfo(int fd
, UCHAR
* iface
, UCHAR
* port
, UCHAR
* device
, UCHAR
* lun
)
590 if ( fstat(fd
, &st
) == -1 || ! S_ISBLK(st
.st_mode
)) return 0;
595 switch (major(st
.st_rdev
)) {
596 case IDE0_MAJOR
: *iface
= 0; break;
597 case IDE1_MAJOR
: *iface
= 1; break;
598 case IDE2_MAJOR
: *iface
= 2; break;
599 case IDE3_MAJOR
: *iface
= 3; break;
600 case IDE4_MAJOR
: *iface
= 4; break;
601 case IDE5_MAJOR
: *iface
= 5; break;
602 case IDE6_MAJOR
: *iface
= 6; break;
603 case IDE7_MAJOR
: *iface
= 7; break;
604 default: *port
= 1; break;
608 *device
= (minor(st
.st_rdev
) >> 6);
611 #ifdef SCSI_IOCTL_GET_IDLUN
613 if (ioctl(fd
, SCSI_IOCTL_GET_IDLUN
, idlun
) != -1)
615 *port
= (idlun
[0] >> 24) & 0xff;
616 *iface
= ((idlun
[0] >> 16) & 0xff) + 2;
617 *device
= idlun
[0] & 0xff;
618 *lun
= (idlun
[0] >> 8) & 0xff;
623 WARN("CD-ROM device (%d, %d) not supported\n", major(st
.st_rdev
), minor(st
.st_rdev
));
628 #elif defined(__NetBSD__)
629 struct scsi_addr addr
;
630 if (ioctl(fd
, SCIOCIDENTIFY
, &addr
) != -1)
636 *iface
= addr
.addr
.scsi
.scbus
;
637 *device
= addr
.addr
.scsi
.target
;
638 *lun
= addr
.addr
.scsi
.lun
;
642 *iface
= addr
.addr
.atapi
.atbus
;
643 *device
= addr
.addr
.atapi
.drive
;
649 #elif defined(__APPLE__)
650 dk_scsi_identify_t addr
;
651 if (ioctl(fd
, DKIOCSCSIIDENTIFY
, &addr
) != -1)
655 *device
= addr
.target
;
661 FIXME("not implemented on this O/S\n");
667 /******************************************************************
671 static NTSTATUS
CDROM_Open(int fd
, int* dev
)
674 NTSTATUS ret
= STATUS_SUCCESS
;
679 RtlEnterCriticalSection( &cache_section
);
680 for (*dev
= 0; *dev
< MAX_CACHE_ENTRIES
; (*dev
)++)
683 cdrom_cache
[*dev
].device
== 0 &&
684 cdrom_cache
[*dev
].inode
== 0)
686 else if (cdrom_cache
[*dev
].device
== st
.st_dev
&&
687 cdrom_cache
[*dev
].inode
== st
.st_ino
)
690 if (*dev
== MAX_CACHE_ENTRIES
)
692 if (empty
== -1) ret
= STATUS_NOT_IMPLEMENTED
;
696 cdrom_cache
[*dev
].device
= st
.st_dev
;
697 cdrom_cache
[*dev
].inode
= st
.st_ino
;
700 RtlLeaveCriticalSection( &cache_section
);
702 TRACE("%d, %d\n", *dev
, fd
);
706 /******************************************************************
707 * CDROM_GetStatusCode
711 static NTSTATUS
CDROM_GetStatusCode(int io
)
713 if (io
== 0) return STATUS_SUCCESS
;
714 return FILE_GetNtStatus();
717 /******************************************************************
721 static NTSTATUS
CDROM_GetControl(int dev
, int fd
, CDROM_AUDIO_CONTROL
* cac
)
725 int io
= ioctl( fd
, DKIOCCDGETSPEED
, &speed
);
726 if (io
!= 0) return CDROM_GetStatusCode( io
);
727 /* DKIOCCDGETSPEED returns the speed in kilobytes per second,
728 * so convert to logical blocks (assumed to be ~2 KB).
730 cac
->LogicalBlocksPerSecond
= speed
/2;
732 cac
->LogicalBlocksPerSecond
= 1; /* FIXME */
734 cac
->LbaFormat
= 0; /* FIXME */
735 return STATUS_NOT_SUPPORTED
;
738 /******************************************************************
739 * CDROM_GetDeviceNumber
742 static NTSTATUS
CDROM_GetDeviceNumber(int dev
, STORAGE_DEVICE_NUMBER
* devnum
)
745 devnum
->DeviceType
= FILE_DEVICE_DISK
;
746 devnum
->DeviceNumber
= 1;
747 devnum
->PartitionNumber
= 1;
748 return STATUS_SUCCESS
;
751 /******************************************************************
752 * CDROM_GetDriveGeometry
755 static NTSTATUS
CDROM_GetDriveGeometry(int dev
, int fd
, DISK_GEOMETRY
* dg
)
761 if ((ret
= CDROM_ReadTOC(dev
, fd
, &toc
)) != 0) return ret
;
763 fsize
= FRAME_OF_TOC(toc
, toc
.LastTrack
+1)
764 - FRAME_OF_TOC(toc
, 1); /* Total size in frames */
766 dg
->Cylinders
.u
.LowPart
= fsize
/ (64 * 32);
767 dg
->Cylinders
.u
.HighPart
= 0;
768 dg
->MediaType
= RemovableMedia
;
769 dg
->TracksPerCylinder
= 64;
770 dg
->SectorsPerTrack
= 32;
771 dg
->BytesPerSector
= 2048;
775 /******************************************************************
779 static NTSTATUS
CDROM_GetMediaType(int dev
, GET_MEDIA_TYPES
* medtype
)
781 FIXME(": faking success\n");
782 medtype
->DeviceType
= FILE_DEVICE_CD_ROM
;
783 medtype
->MediaInfoCount
= 0;
784 return STATUS_SUCCESS
;
787 /**************************************************************************
788 * CDROM_Reset [internal]
790 static NTSTATUS
CDROM_ResetAudio(int fd
)
793 return CDROM_GetStatusCode(ioctl(fd
, CDROMRESET
));
794 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__DragonFly__)
795 return CDROM_GetStatusCode(ioctl(fd
, CDIOCRESET
, NULL
));
797 FIXME("not supported on this O/S\n");
798 return STATUS_NOT_SUPPORTED
;
802 /******************************************************************
807 static NTSTATUS
CDROM_SetTray(int fd
, BOOL doEject
)
810 return CDROM_GetStatusCode(ioctl(fd
, doEject
? CDROMEJECT
: CDROMCLOSETRAY
));
811 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__DragonFly__)
812 return CDROM_GetStatusCode((ioctl(fd
, CDIOCALLOW
, NULL
)) ||
813 (ioctl(fd
, doEject
? CDIOCEJECT
: CDIOCCLOSE
, NULL
)) ||
814 (ioctl(fd
, CDIOCPREVENT
, NULL
)));
815 #elif defined(__APPLE__)
816 if (doEject
) return CDROM_GetStatusCode( ioctl( fd
, DKIOCEJECT
, NULL
) );
817 else return STATUS_NOT_SUPPORTED
;
819 FIXME("not supported on this O/S\n");
820 return STATUS_NOT_SUPPORTED
;
824 /******************************************************************
825 * CDROM_ControlEjection
829 static NTSTATUS
CDROM_ControlEjection(int fd
, const PREVENT_MEDIA_REMOVAL
* rmv
)
832 return CDROM_GetStatusCode(ioctl(fd
, CDROM_LOCKDOOR
, rmv
->PreventMediaRemoval
));
833 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__DragonFly__)
834 return CDROM_GetStatusCode(ioctl(fd
, (rmv
->PreventMediaRemoval
) ? CDIOCPREVENT
: CDIOCALLOW
, NULL
));
836 FIXME("not supported on this O/S\n");
837 return STATUS_NOT_SUPPORTED
;
841 /******************************************************************
846 static NTSTATUS
CDROM_ReadTOC(int dev
, int fd
, CDROM_TOC
* toc
)
848 NTSTATUS ret
= STATUS_NOT_SUPPORTED
;
850 if (dev
< 0 || dev
>= MAX_CACHE_ENTRIES
)
851 return STATUS_INVALID_PARAMETER
;
853 RtlEnterCriticalSection( &cache_section
);
854 if (cdrom_cache
[dev
].toc_good
|| !(ret
= CDROM_SyncCache(dev
, fd
)))
856 *toc
= cdrom_cache
[dev
].toc
;
857 ret
= STATUS_SUCCESS
;
859 RtlLeaveCriticalSection( &cache_section
);
863 /******************************************************************
868 static NTSTATUS
CDROM_GetDiskData(int dev
, int fd
, CDROM_DISK_DATA
* data
)
874 if ((ret
= CDROM_ReadTOC(dev
, fd
, &toc
)) != 0) return ret
;
876 for (i
= toc
.FirstTrack
; i
<= toc
.LastTrack
; i
++) {
877 if (toc
.TrackData
[i
-toc
.FirstTrack
].Control
& 0x04)
878 data
->DiskData
|= CDROM_DISK_DATA_TRACK
;
880 data
->DiskData
|= CDROM_DISK_AUDIO_TRACK
;
882 return STATUS_SUCCESS
;
885 /******************************************************************
890 static NTSTATUS
CDROM_ReadQChannel(int dev
, int fd
, const CDROM_SUB_Q_DATA_FORMAT
* fmt
,
891 SUB_Q_CHANNEL_DATA
* data
)
893 NTSTATUS ret
= STATUS_NOT_SUPPORTED
;
895 SUB_Q_HEADER
* hdr
= (SUB_Q_HEADER
*)data
;
897 struct cdrom_subchnl sc
;
898 sc
.cdsc_format
= CDROM_MSF
;
900 io
= ioctl(fd
, CDROMSUBCHNL
, &sc
);
903 TRACE("opened or no_media (%s)!\n", strerror(errno
));
904 hdr
->AudioStatus
= AUDIO_STATUS_NO_STATUS
;
905 CDROM_ClearCacheEntry(dev
);
909 hdr
->AudioStatus
= AUDIO_STATUS_NOT_SUPPORTED
;
911 switch (sc
.cdsc_audiostatus
) {
912 case CDROM_AUDIO_INVALID
:
913 CDROM_ClearCacheEntry(dev
);
914 hdr
->AudioStatus
= AUDIO_STATUS_NOT_SUPPORTED
;
916 case CDROM_AUDIO_NO_STATUS
:
917 CDROM_ClearCacheEntry(dev
);
918 hdr
->AudioStatus
= AUDIO_STATUS_NO_STATUS
;
920 case CDROM_AUDIO_PLAY
:
921 hdr
->AudioStatus
= AUDIO_STATUS_IN_PROGRESS
;
923 case CDROM_AUDIO_PAUSED
:
924 hdr
->AudioStatus
= AUDIO_STATUS_PAUSED
;
926 case CDROM_AUDIO_COMPLETED
:
927 hdr
->AudioStatus
= AUDIO_STATUS_PLAY_COMPLETE
;
929 case CDROM_AUDIO_ERROR
:
930 hdr
->AudioStatus
= AUDIO_STATUS_PLAY_ERROR
;
933 TRACE("status=%02X !\n", sc
.cdsc_audiostatus
);
938 case IOCTL_CDROM_CURRENT_POSITION
:
939 RtlEnterCriticalSection( &cache_section
);
940 if (hdr
->AudioStatus
==AUDIO_STATUS_IN_PROGRESS
) {
941 data
->CurrentPosition
.FormatCode
= IOCTL_CDROM_CURRENT_POSITION
;
942 data
->CurrentPosition
.Control
= sc
.cdsc_ctrl
;
943 data
->CurrentPosition
.ADR
= sc
.cdsc_adr
;
944 data
->CurrentPosition
.TrackNumber
= sc
.cdsc_trk
;
945 data
->CurrentPosition
.IndexNumber
= sc
.cdsc_ind
;
947 data
->CurrentPosition
.AbsoluteAddress
[0] = 0;
948 data
->CurrentPosition
.AbsoluteAddress
[1] = sc
.cdsc_absaddr
.msf
.minute
;
949 data
->CurrentPosition
.AbsoluteAddress
[2] = sc
.cdsc_absaddr
.msf
.second
;
950 data
->CurrentPosition
.AbsoluteAddress
[3] = sc
.cdsc_absaddr
.msf
.frame
;
952 data
->CurrentPosition
.TrackRelativeAddress
[0] = 0;
953 data
->CurrentPosition
.TrackRelativeAddress
[1] = sc
.cdsc_reladdr
.msf
.minute
;
954 data
->CurrentPosition
.TrackRelativeAddress
[2] = sc
.cdsc_reladdr
.msf
.second
;
955 data
->CurrentPosition
.TrackRelativeAddress
[3] = sc
.cdsc_reladdr
.msf
.frame
;
957 cdrom_cache
[dev
].CurrentPosition
= data
->CurrentPosition
;
959 else /* not playing */
961 cdrom_cache
[dev
].CurrentPosition
.Header
= *hdr
; /* Preserve header info */
962 data
->CurrentPosition
= cdrom_cache
[dev
].CurrentPosition
;
964 RtlLeaveCriticalSection( &cache_section
);
966 case IOCTL_CDROM_MEDIA_CATALOG
:
967 data
->MediaCatalog
.FormatCode
= IOCTL_CDROM_MEDIA_CATALOG
;
969 struct cdrom_mcn mcn
;
970 if ((io
= ioctl(fd
, CDROM_GET_MCN
, &mcn
)) == -1) goto end
;
972 data
->MediaCatalog
.FormatCode
= IOCTL_CDROM_MEDIA_CATALOG
;
973 data
->MediaCatalog
.Mcval
= 0; /* FIXME */
974 memcpy(data
->MediaCatalog
.MediaCatalog
, mcn
.medium_catalog_number
, 14);
975 data
->MediaCatalog
.MediaCatalog
[14] = 0;
978 case IOCTL_CDROM_TRACK_ISRC
:
979 FIXME("TrackIsrc: NIY on linux\n");
980 data
->TrackIsrc
.FormatCode
= IOCTL_CDROM_TRACK_ISRC
;
981 data
->TrackIsrc
.Tcval
= 0;
987 ret
= CDROM_GetStatusCode(io
);
988 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__DragonFly__)
989 SUB_Q_HEADER
* hdr
= (SUB_Q_HEADER
*)data
;
991 struct ioc_read_subchannel read_sc
;
992 struct cd_sub_channel_info sc
;
994 read_sc
.address_format
= CD_MSF_FORMAT
;
996 read_sc
.data_len
= sizeof(sc
);
1000 case IOCTL_CDROM_CURRENT_POSITION
:
1001 read_sc
.data_format
= CD_CURRENT_POSITION
;
1003 case IOCTL_CDROM_MEDIA_CATALOG
:
1004 read_sc
.data_format
= CD_MEDIA_CATALOG
;
1006 case IOCTL_CDROM_TRACK_ISRC
:
1007 read_sc
.data_format
= CD_TRACK_INFO
;
1008 sc
.what
.track_info
.track_number
= data
->TrackIsrc
.Track
;
1011 io
= ioctl(fd
, CDIOCREADSUBCHANNEL
, &read_sc
);
1014 TRACE("opened or no_media (%s)!\n", strerror(errno
));
1015 CDROM_ClearCacheEntry(dev
);
1016 hdr
->AudioStatus
= AUDIO_STATUS_NO_STATUS
;
1020 hdr
->AudioStatus
= AUDIO_STATUS_NOT_SUPPORTED
;
1022 switch (sc
.header
.audio_status
) {
1023 case CD_AS_AUDIO_INVALID
:
1024 CDROM_ClearCacheEntry(dev
);
1025 hdr
->AudioStatus
= AUDIO_STATUS_NOT_SUPPORTED
;
1027 case CD_AS_NO_STATUS
:
1028 CDROM_ClearCacheEntry(dev
);
1029 hdr
->AudioStatus
= AUDIO_STATUS_NO_STATUS
;
1031 case CD_AS_PLAY_IN_PROGRESS
:
1032 hdr
->AudioStatus
= AUDIO_STATUS_IN_PROGRESS
;
1034 case CD_AS_PLAY_PAUSED
:
1035 hdr
->AudioStatus
= AUDIO_STATUS_PAUSED
;
1037 case CD_AS_PLAY_COMPLETED
:
1038 hdr
->AudioStatus
= AUDIO_STATUS_PLAY_COMPLETE
;
1040 case CD_AS_PLAY_ERROR
:
1041 hdr
->AudioStatus
= AUDIO_STATUS_PLAY_ERROR
;
1044 TRACE("status=%02X !\n", sc
.header
.audio_status
);
1046 switch (fmt
->Format
)
1048 case IOCTL_CDROM_CURRENT_POSITION
:
1049 RtlEnterCriticalSection( &cache_section
);
1050 if (hdr
->AudioStatus
==AUDIO_STATUS_IN_PROGRESS
) {
1051 data
->CurrentPosition
.FormatCode
= IOCTL_CDROM_CURRENT_POSITION
;
1052 data
->CurrentPosition
.Control
= sc
.what
.position
.control
;
1053 data
->CurrentPosition
.ADR
= sc
.what
.position
.addr_type
;
1054 data
->CurrentPosition
.TrackNumber
= sc
.what
.position
.track_number
;
1055 data
->CurrentPosition
.IndexNumber
= sc
.what
.position
.index_number
;
1057 data
->CurrentPosition
.AbsoluteAddress
[0] = 0;
1058 data
->CurrentPosition
.AbsoluteAddress
[1] = sc
.what
.position
.absaddr
.msf
.minute
;
1059 data
->CurrentPosition
.AbsoluteAddress
[2] = sc
.what
.position
.absaddr
.msf
.second
;
1060 data
->CurrentPosition
.AbsoluteAddress
[3] = sc
.what
.position
.absaddr
.msf
.frame
;
1061 data
->CurrentPosition
.TrackRelativeAddress
[0] = 0;
1062 data
->CurrentPosition
.TrackRelativeAddress
[1] = sc
.what
.position
.reladdr
.msf
.minute
;
1063 data
->CurrentPosition
.TrackRelativeAddress
[2] = sc
.what
.position
.reladdr
.msf
.second
;
1064 data
->CurrentPosition
.TrackRelativeAddress
[3] = sc
.what
.position
.reladdr
.msf
.frame
;
1065 cdrom_cache
[dev
].CurrentPosition
= data
->CurrentPosition
;
1067 else { /* not playing */
1068 cdrom_cache
[dev
].CurrentPosition
.Header
= *hdr
; /* Preserve header info */
1069 data
->CurrentPosition
= cdrom_cache
[dev
].CurrentPosition
;
1071 RtlLeaveCriticalSection( &cache_section
);
1073 case IOCTL_CDROM_MEDIA_CATALOG
:
1074 data
->MediaCatalog
.FormatCode
= IOCTL_CDROM_MEDIA_CATALOG
;
1075 data
->MediaCatalog
.Mcval
= sc
.what
.media_catalog
.mc_valid
;
1076 memcpy(data
->MediaCatalog
.MediaCatalog
, sc
.what
.media_catalog
.mc_number
, 15);
1078 case IOCTL_CDROM_TRACK_ISRC
:
1079 data
->TrackIsrc
.FormatCode
= IOCTL_CDROM_TRACK_ISRC
;
1080 data
->TrackIsrc
.Tcval
= sc
.what
.track_info
.ti_valid
;
1081 memcpy(data
->TrackIsrc
.TrackIsrc
, sc
.what
.track_info
.ti_number
, 15);
1086 ret
= CDROM_GetStatusCode(io
);
1087 #elif defined(__APPLE__)
1088 SUB_Q_HEADER
* hdr
= (SUB_Q_HEADER
*)data
;
1092 dk_cd_read_mcn_t mcn
;
1093 dk_cd_read_isrc_t isrc
;
1095 /* We need IOCDAudioControl for IOCTL_CDROM_CURRENT_POSITION */
1096 if (fmt
->Format
== IOCTL_CDROM_CURRENT_POSITION
)
1099 return STATUS_NOT_SUPPORTED
;
1101 /* No IOCDAudioControl support; just set the audio status to none */
1102 hdr
->AudioStatus
= AUDIO_STATUS_NO_STATUS
;
1105 case IOCTL_CDROM_MEDIA_CATALOG
:
1106 if ((io
= ioctl(fd
, DKIOCCDREADMCN
, &ioc
.mcn
)) == -1) break;
1107 memcpy(data
->MediaCatalog
.MediaCatalog
, ioc
.mcn
.mcn
, kCDMCNMaxLength
);
1108 data
->MediaCatalog
.Mcval
= 1;
1110 case IOCTL_CDROM_TRACK_ISRC
:
1111 ioc
.isrc
.track
= fmt
->Track
;
1112 if ((io
= ioctl(fd
, DKIOCCDREADISRC
, &ioc
.isrc
)) == -1) break;
1113 memcpy(data
->TrackIsrc
.TrackIsrc
, ioc
.isrc
.isrc
, kCDISRCMaxLength
);
1114 data
->TrackIsrc
.Tcval
= 1;
1115 data
->TrackIsrc
.Track
= ioc
.isrc
.track
;
1117 ret
= CDROM_GetStatusCode(io
);
1122 /******************************************************************
1124 * Implements: IOCTL_STORAGE_CHECK_VERIFY
1125 * IOCTL_CDROM_CHECK_VERIFY
1126 * IOCTL_DISK_CHECK_VERIFY
1129 static NTSTATUS
CDROM_Verify(int dev
, int fd
)
1134 ret
= ioctl(fd
, CDROM_DRIVE_STATUS
, NULL
);
1136 TRACE("ioctl CDROM_DRIVE_STATUS failed(%s)!\n", strerror(errno
));
1137 return CDROM_GetStatusCode(ret
);
1140 if(ret
== CDS_DISC_OK
)
1141 return STATUS_SUCCESS
;
1143 return STATUS_NO_MEDIA_IN_DEVICE
;
1144 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__DragonFly__)
1146 ret
= ioctl(fd
, CDIOCSTART
, NULL
);
1148 return STATUS_SUCCESS
;
1150 return STATUS_NO_MEDIA_IN_DEVICE
;
1151 #elif defined(__APPLE__)
1152 /* At this point, we know that we have media, because in Mac OS X, the
1153 * device file is only created when media is present. */
1154 return STATUS_SUCCESS
;
1156 FIXME("not supported on this O/S\n");
1157 return STATUS_NOT_SUPPORTED
;
1161 /******************************************************************
1162 * CDROM_PlayAudioMSF
1166 static NTSTATUS
CDROM_PlayAudioMSF(int fd
, const CDROM_PLAY_AUDIO_MSF
* audio_msf
)
1168 NTSTATUS ret
= STATUS_NOT_SUPPORTED
;
1170 struct cdrom_msf msf
;
1173 msf
.cdmsf_min0
= audio_msf
->StartingM
;
1174 msf
.cdmsf_sec0
= audio_msf
->StartingS
;
1175 msf
.cdmsf_frame0
= audio_msf
->StartingF
;
1176 msf
.cdmsf_min1
= audio_msf
->EndingM
;
1177 msf
.cdmsf_sec1
= audio_msf
->EndingS
;
1178 msf
.cdmsf_frame1
= audio_msf
->EndingF
;
1180 io
= ioctl(fd
, CDROMSTART
);
1183 WARN("motor doesn't start !\n");
1186 io
= ioctl(fd
, CDROMPLAYMSF
, &msf
);
1189 WARN("device doesn't play !\n");
1192 TRACE("msf = %d:%d:%d %d:%d:%d\n",
1193 msf
.cdmsf_min0
, msf
.cdmsf_sec0
, msf
.cdmsf_frame0
,
1194 msf
.cdmsf_min1
, msf
.cdmsf_sec1
, msf
.cdmsf_frame1
);
1196 ret
= CDROM_GetStatusCode(io
);
1197 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__DragonFly__)
1198 struct ioc_play_msf msf
;
1201 msf
.start_m
= audio_msf
->StartingM
;
1202 msf
.start_s
= audio_msf
->StartingS
;
1203 msf
.start_f
= audio_msf
->StartingF
;
1204 msf
.end_m
= audio_msf
->EndingM
;
1205 msf
.end_s
= audio_msf
->EndingS
;
1206 msf
.end_f
= audio_msf
->EndingF
;
1208 io
= ioctl(fd
, CDIOCSTART
, NULL
);
1211 WARN("motor doesn't start !\n");
1214 io
= ioctl(fd
, CDIOCPLAYMSF
, &msf
);
1217 WARN("device doesn't play !\n");
1220 TRACE("msf = %d:%d:%d %d:%d:%d\n",
1221 msf
.start_m
, msf
.start_s
, msf
.start_f
,
1222 msf
.end_m
, msf
.end_s
, msf
.end_f
);
1224 ret
= CDROM_GetStatusCode(io
);
1229 /******************************************************************
1230 * CDROM_SeekAudioMSF
1234 static NTSTATUS
CDROM_SeekAudioMSF(int dev
, int fd
, const CDROM_SEEK_AUDIO_MSF
* audio_msf
)
1238 SUB_Q_CURRENT_POSITION
*cp
;
1240 struct cdrom_msf0 msf
;
1241 struct cdrom_subchnl sc
;
1242 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__DragonFly__)
1243 struct ioc_play_msf msf
;
1244 struct ioc_read_subchannel read_sc
;
1245 struct cd_sub_channel_info sc
;
1249 /* Use the information on the TOC to compute the new current
1250 * position, which is shadowed on the cache. [Portable]. */
1251 frame
= FRAME_OF_MSF(*audio_msf
);
1253 if ((io
= CDROM_ReadTOC(dev
, fd
, &toc
)) != 0) return io
;
1255 for(i
=toc
.FirstTrack
;i
<=toc
.LastTrack
+1;i
++)
1256 if (FRAME_OF_TOC(toc
,i
)>frame
) break;
1257 if (i
<= toc
.FirstTrack
|| i
> toc
.LastTrack
+1)
1258 return STATUS_INVALID_PARAMETER
;
1260 RtlEnterCriticalSection( &cache_section
);
1261 cp
= &cdrom_cache
[dev
].CurrentPosition
;
1262 cp
->FormatCode
= IOCTL_CDROM_CURRENT_POSITION
;
1263 cp
->Control
= toc
.TrackData
[i
-toc
.FirstTrack
].Control
;
1264 cp
->ADR
= toc
.TrackData
[i
-toc
.FirstTrack
].Adr
;
1265 cp
->TrackNumber
= toc
.TrackData
[i
-toc
.FirstTrack
].TrackNumber
;
1266 cp
->IndexNumber
= 0; /* FIXME: where do they keep these? */
1267 cp
->AbsoluteAddress
[0] = 0;
1268 cp
->AbsoluteAddress
[1] = toc
.TrackData
[i
-toc
.FirstTrack
].Address
[1];
1269 cp
->AbsoluteAddress
[2] = toc
.TrackData
[i
-toc
.FirstTrack
].Address
[2];
1270 cp
->AbsoluteAddress
[3] = toc
.TrackData
[i
-toc
.FirstTrack
].Address
[3];
1271 frame
-= FRAME_OF_TOC(toc
,i
);
1272 cp
->TrackRelativeAddress
[0] = 0;
1273 MSF_OF_FRAME(cp
->TrackRelativeAddress
[1], frame
);
1274 RtlLeaveCriticalSection( &cache_section
);
1276 /* If playing, then issue a seek command, otherwise do nothing */
1278 sc
.cdsc_format
= CDROM_MSF
;
1280 io
= ioctl(fd
, CDROMSUBCHNL
, &sc
);
1283 TRACE("opened or no_media (%s)!\n", strerror(errno
));
1284 CDROM_ClearCacheEntry(dev
);
1285 return CDROM_GetStatusCode(io
);
1287 if (sc
.cdsc_audiostatus
==CDROM_AUDIO_PLAY
)
1289 msf
.minute
= audio_msf
->M
;
1290 msf
.second
= audio_msf
->S
;
1291 msf
.frame
= audio_msf
->F
;
1292 return CDROM_GetStatusCode(ioctl(fd
, CDROMSEEK
, &msf
));
1294 return STATUS_SUCCESS
;
1295 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__DragonFly__)
1296 read_sc
.address_format
= CD_MSF_FORMAT
;
1298 read_sc
.data_len
= sizeof(sc
);
1300 read_sc
.data_format
= CD_CURRENT_POSITION
;
1302 io
= ioctl(fd
, CDIOCREADSUBCHANNEL
, &read_sc
);
1305 TRACE("opened or no_media (%s)!\n", strerror(errno
));
1306 CDROM_ClearCacheEntry(dev
);
1307 return CDROM_GetStatusCode(io
);
1309 if (sc
.header
.audio_status
==CD_AS_PLAY_IN_PROGRESS
)
1312 msf
.start_m
= audio_msf
->M
;
1313 msf
.start_s
= audio_msf
->S
;
1314 msf
.start_f
= audio_msf
->F
;
1315 final_frame
= FRAME_OF_TOC(toc
,toc
.LastTrack
+1)-1;
1316 MSF_OF_FRAME(msf
.end_m
, final_frame
);
1318 return CDROM_GetStatusCode(ioctl(fd
, CDIOCPLAYMSF
, &msf
));
1320 return STATUS_SUCCESS
;
1322 FIXME("not supported on this O/S\n");
1323 return STATUS_NOT_SUPPORTED
;
1327 /******************************************************************
1332 static NTSTATUS
CDROM_PauseAudio(int fd
)
1335 return CDROM_GetStatusCode(ioctl(fd
, CDROMPAUSE
));
1336 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__DragonFly__)
1337 return CDROM_GetStatusCode(ioctl(fd
, CDIOCPAUSE
, NULL
));
1339 FIXME(": not supported on this O/S\n");
1340 return STATUS_NOT_SUPPORTED
;
1344 /******************************************************************
1349 static NTSTATUS
CDROM_ResumeAudio(int fd
)
1352 return CDROM_GetStatusCode(ioctl(fd
, CDROMRESUME
));
1353 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__DragonFly__)
1354 return CDROM_GetStatusCode(ioctl(fd
, CDIOCRESUME
, NULL
));
1356 FIXME("not supported on this O/S\n");
1357 return STATUS_NOT_SUPPORTED
;
1361 /******************************************************************
1366 static NTSTATUS
CDROM_StopAudio(int fd
)
1369 return CDROM_GetStatusCode(ioctl(fd
, CDROMSTOP
));
1370 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__DragonFly__)
1371 return CDROM_GetStatusCode(ioctl(fd
, CDIOCSTOP
, NULL
));
1373 FIXME("not supported on this O/S\n");
1374 return STATUS_NOT_SUPPORTED
;
1378 /******************************************************************
1383 static NTSTATUS
CDROM_GetVolume(int fd
, VOLUME_CONTROL
* vc
)
1386 struct cdrom_volctrl volc
;
1389 io
= ioctl(fd
, CDROMVOLREAD
, &volc
);
1392 vc
->PortVolume
[0] = volc
.channel0
;
1393 vc
->PortVolume
[1] = volc
.channel1
;
1394 vc
->PortVolume
[2] = volc
.channel2
;
1395 vc
->PortVolume
[3] = volc
.channel3
;
1397 return CDROM_GetStatusCode(io
);
1398 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__DragonFly__)
1399 struct ioc_vol volc
;
1402 io
= ioctl(fd
, CDIOCGETVOL
, &volc
);
1405 vc
->PortVolume
[0] = volc
.vol
[0];
1406 vc
->PortVolume
[1] = volc
.vol
[1];
1407 vc
->PortVolume
[2] = volc
.vol
[2];
1408 vc
->PortVolume
[3] = volc
.vol
[3];
1410 return CDROM_GetStatusCode(io
);
1412 FIXME("not supported on this O/S\n");
1413 return STATUS_NOT_SUPPORTED
;
1417 /******************************************************************
1422 static NTSTATUS
CDROM_SetVolume(int fd
, const VOLUME_CONTROL
* vc
)
1425 struct cdrom_volctrl volc
;
1427 volc
.channel0
= vc
->PortVolume
[0];
1428 volc
.channel1
= vc
->PortVolume
[1];
1429 volc
.channel2
= vc
->PortVolume
[2];
1430 volc
.channel3
= vc
->PortVolume
[3];
1432 return CDROM_GetStatusCode(ioctl(fd
, CDROMVOLCTRL
, &volc
));
1433 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__DragonFly__)
1434 struct ioc_vol volc
;
1436 volc
.vol
[0] = vc
->PortVolume
[0];
1437 volc
.vol
[1] = vc
->PortVolume
[1];
1438 volc
.vol
[2] = vc
->PortVolume
[2];
1439 volc
.vol
[3] = vc
->PortVolume
[3];
1441 return CDROM_GetStatusCode(ioctl(fd
, CDIOCSETVOL
, &volc
));
1443 FIXME(": not supported on this O/S\n");
1444 return STATUS_NOT_SUPPORTED
;
1448 /******************************************************************
1451 * Some features of this IOCTL are rather poorly documented and
1452 * not really intuitive either:
1454 * 1. Although the DiskOffset parameter is meant to be a
1455 * byte offset into the disk, it is in fact the sector
1456 * number multiplied by 2048 regardless of the actual
1459 * 2. The least significant 11 bits of DiskOffset are ignored.
1461 * 3. The TrackMode parameter has no effect on the sector
1462 * size. The entire raw sector (i.e. 2352 bytes of data)
1463 * is always returned. IMO the TrackMode is only used
1464 * to check the correct sector type.
1467 static NTSTATUS
CDROM_RawRead(int fd
, const RAW_READ_INFO
* raw
, void* buffer
, DWORD len
, DWORD
* sz
)
1469 int ret
= STATUS_NOT_SUPPORTED
;
1475 TRACE("RAW_READ_INFO: DiskOffset=%i,%i SectorCount=%i TrackMode=%i\n buffer=%p len=%i sz=%p\n",
1476 raw
->DiskOffset
.u
.HighPart
, raw
->DiskOffset
.u
.LowPart
, raw
->SectorCount
, raw
->TrackMode
, buffer
, len
, sz
);
1478 if (len
< raw
->SectorCount
* 2352) return STATUS_BUFFER_TOO_SMALL
;
1481 if (raw
->DiskOffset
.u
.HighPart
& ~2047) {
1482 WARN("DiskOffset points to a sector >= 2**32\n");
1486 switch (raw
->TrackMode
)
1491 DWORD lba
= raw
->DiskOffset
.QuadPart
>> 11;
1492 struct cdrom_msf
* msf
;
1493 PBYTE
*bp
; /* current buffer pointer */
1496 if ((lba
+ raw
->SectorCount
) >
1497 ((1 << 8*sizeof(msf
->cdmsf_min0
)) * CD_SECS
* CD_FRAMES
1499 WARN("DiskOffset not accessible with MSF\n");
1503 /* Linux reads only one sector at a time.
1504 * ioctl CDROMREADRAW takes struct cdrom_msf as an argument
1505 * on the contrary to what header comments state.
1507 lba
+= CD_MSF_OFFSET
;
1508 for (i
= 0, bp
= buffer
; i
< raw
->SectorCount
;
1509 i
++, lba
++, bp
+= 2352)
1511 msf
= (struct cdrom_msf
*)bp
;
1512 msf
->cdmsf_min0
= lba
/ CD_FRAMES
/ CD_SECS
;
1513 msf
->cdmsf_sec0
= lba
/ CD_FRAMES
% CD_SECS
;
1514 msf
->cdmsf_frame0
= lba
% CD_FRAMES
;
1515 io
= ioctl(fd
, CDROMREADRAW
, msf
);
1519 return CDROM_GetStatusCode(io
);
1527 struct cdrom_read_audio cdra
;
1529 cdra
.addr
.lba
= raw
->DiskOffset
.QuadPart
>> 11;
1530 TRACE("reading at %u\n", cdra
.addr
.lba
);
1531 cdra
.addr_format
= CDROM_LBA
;
1532 cdra
.nframes
= raw
->SectorCount
;
1534 io
= ioctl(fd
, CDROMREADAUDIO
, &cdra
);
1539 FIXME("NIY: %d\n", raw
->TrackMode
);
1540 return STATUS_INVALID_PARAMETER
;
1542 #elif defined(__APPLE__)
1543 /* Mac OS lets us read multiple parts of the sector at a time.
1544 * We can read all the sectors in at once, unlike Linux.
1546 memset(&cdrd
, 0, sizeof(cdrd
));
1547 cdrd
.offset
= (raw
->DiskOffset
.QuadPart
>> 11) * kCDSectorSizeWhole
;
1548 cdrd
.buffer
= buffer
;
1549 cdrd
.bufferLength
= raw
->SectorCount
* kCDSectorSizeWhole
;
1550 switch (raw
->TrackMode
)
1553 cdrd
.sectorType
= kCDSectorTypeMode2
;
1554 cdrd
.sectorArea
= kCDSectorAreaSync
| kCDSectorAreaHeader
| kCDSectorAreaUser
;
1558 cdrd
.sectorType
= kCDSectorTypeMode2Form2
;
1559 cdrd
.sectorArea
= kCDSectorAreaSync
| kCDSectorAreaHeader
| kCDSectorAreaSubHeader
| kCDSectorAreaUser
;
1563 cdrd
.sectorType
= kCDSectorTypeCDDA
;
1564 cdrd
.sectorArea
= kCDSectorAreaUser
;
1568 FIXME("NIY: %d\n", raw
->TrackMode
);
1569 return STATUS_INVALID_PARAMETER
;
1571 io
= ioctl(fd
, DKIOCCDREAD
, &cdrd
);
1574 *sz
= cdrd
.bufferLength
;
1575 return CDROM_GetStatusCode(io
);
1578 switch (raw
->TrackMode
)
1581 FIXME("YellowMode2: NIY\n");
1584 FIXME("XAForm2: NIY\n");
1587 FIXME("CDDA: NIY\n");
1590 FIXME("NIY: %d\n", raw
->TrackMode
);
1591 return STATUS_INVALID_PARAMETER
;
1595 *sz
= 2352 * raw
->SectorCount
;
1596 ret
= CDROM_GetStatusCode(io
);
1600 /******************************************************************
1601 * CDROM_ScsiPassThroughDirect
1602 * Implements IOCTL_SCSI_PASS_THROUGH_DIRECT
1605 static NTSTATUS
CDROM_ScsiPassThroughDirect(int fd
, PSCSI_PASS_THROUGH_DIRECT pPacket
)
1607 int ret
= STATUS_NOT_SUPPORTED
;
1608 #ifdef HAVE_SG_IO_HDR_T_INTERFACE_ID
1611 #elif defined HAVE_SCSIREQ_T_CMD
1614 #elif defined __APPLE__
1615 dk_scsi_command_t cmd
;
1619 if (pPacket
->Length
< sizeof(SCSI_PASS_THROUGH_DIRECT
))
1620 return STATUS_BUFFER_TOO_SMALL
;
1622 if (pPacket
->CdbLength
> 16)
1623 return STATUS_INVALID_PARAMETER
;
1626 if (pPacket
->SenseInfoLength
> SENSEBUFLEN
)
1627 return STATUS_INVALID_PARAMETER
;
1628 #elif defined HAVE_REQUEST_SENSE
1629 if (pPacket
->SenseInfoLength
> sizeof(struct request_sense
))
1630 return STATUS_INVALID_PARAMETER
;
1633 if (pPacket
->DataTransferLength
> 0 && !pPacket
->DataBuffer
)
1634 return STATUS_INVALID_PARAMETER
;
1636 #ifdef HAVE_SG_IO_HDR_T_INTERFACE_ID
1637 RtlZeroMemory(&cmd
, sizeof(cmd
));
1639 cmd
.interface_id
= 'S';
1640 cmd
.cmd_len
= pPacket
->CdbLength
;
1641 cmd
.mx_sb_len
= pPacket
->SenseInfoLength
;
1642 cmd
.dxfer_len
= pPacket
->DataTransferLength
;
1643 cmd
.dxferp
= pPacket
->DataBuffer
;
1644 cmd
.cmdp
= pPacket
->Cdb
;
1645 cmd
.sbp
= (unsigned char*)pPacket
+ pPacket
->SenseInfoOffset
;
1646 cmd
.timeout
= pPacket
->TimeOutValue
*1000;
1648 switch (pPacket
->DataIn
)
1650 case SCSI_IOCTL_DATA_IN
:
1651 cmd
.dxfer_direction
= SG_DXFER_FROM_DEV
;
1653 case SCSI_IOCTL_DATA_OUT
:
1654 cmd
.dxfer_direction
= SG_DXFER_TO_DEV
;
1656 case SCSI_IOCTL_DATA_UNSPECIFIED
:
1657 cmd
.dxfer_direction
= SG_DXFER_NONE
;
1660 return STATUS_INVALID_PARAMETER
;
1663 io
= ioctl(fd
, SG_IO
, &cmd
);
1665 pPacket
->ScsiStatus
= cmd
.status
;
1666 pPacket
->DataTransferLength
= cmd
.resid
;
1667 pPacket
->SenseInfoLength
= cmd
.sb_len_wr
;
1669 ret
= CDROM_GetStatusCode(io
);
1671 #elif defined HAVE_SCSIREQ_T_CMD
1673 memset(&cmd
, 0, sizeof(cmd
));
1674 memcpy(&(cmd
.cmd
), &(pPacket
->Cdb
), pPacket
->CdbLength
);
1676 cmd
.cmdlen
= pPacket
->CdbLength
;
1677 cmd
.databuf
= pPacket
->DataBuffer
;
1678 cmd
.datalen
= pPacket
->DataTransferLength
;
1679 cmd
.senselen
= pPacket
->SenseInfoLength
;
1680 cmd
.timeout
= pPacket
->TimeOutValue
*1000; /* in milliseconds */
1682 switch (pPacket
->DataIn
)
1684 case SCSI_IOCTL_DATA_OUT
:
1685 cmd
.flags
|= SCCMD_WRITE
;
1687 case SCSI_IOCTL_DATA_IN
:
1688 cmd
.flags
|= SCCMD_READ
;
1690 case SCSI_IOCTL_DATA_UNSPECIFIED
:
1694 return STATUS_INVALID_PARAMETER
;
1697 io
= ioctl(fd
, SCIOCCOMMAND
, &cmd
);
1701 case SCCMD_OK
: break;
1702 case SCCMD_TIMEOUT
: return STATUS_TIMEOUT
;
1704 case SCCMD_BUSY
: return STATUS_DEVICE_BUSY
;
1706 case SCCMD_SENSE
: break;
1707 case SCCMD_UNKNOWN
: return STATUS_UNSUCCESSFUL
;
1711 if (pPacket
->SenseInfoLength
!= 0)
1713 memcpy((char*)pPacket
+ pPacket
->SenseInfoOffset
,
1714 cmd
.sense
, pPacket
->SenseInfoLength
);
1717 pPacket
->ScsiStatus
= cmd
.status
;
1719 ret
= CDROM_GetStatusCode(io
);
1721 #elif defined(__APPLE__)
1723 memset(&cmd
, 0, sizeof(cmd
));
1724 memcpy(cmd
.cdb
, pPacket
->Cdb
, pPacket
->CdbLength
);
1726 cmd
.cdbSize
= pPacket
->CdbLength
;
1727 cmd
.buffer
= pPacket
->DataBuffer
;
1728 cmd
.bufferSize
= pPacket
->DataTransferLength
;
1729 cmd
.sense
= (char*)pPacket
+ pPacket
->SenseInfoOffset
;
1730 cmd
.senseLen
= pPacket
->SenseInfoLength
;
1731 cmd
.timeout
= pPacket
->TimeOutValue
*1000; /* in milliseconds */
1733 switch (pPacket
->DataIn
)
1735 case SCSI_IOCTL_DATA_OUT
:
1736 cmd
.direction
= kSCSIDataTransfer_FromInitiatorToTarget
;
1738 case SCSI_IOCTL_DATA_IN
:
1739 cmd
.direction
= kSCSIDataTransfer_FromTargetToInitiator
;
1741 case SCSI_IOCTL_DATA_UNSPECIFIED
:
1742 cmd
.direction
= kSCSIDataTransfer_NoDataTransfer
;
1745 return STATUS_INVALID_PARAMETER
;
1748 io
= ioctl(fd
, DKIOCSCSICOMMAND
, &cmd
);
1750 if (cmd
.response
== kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE
)
1752 /* Command failed */
1755 case kSCSITaskStatus_TaskTimeoutOccurred
: return STATUS_TIMEOUT
;
1757 case kSCSITaskStatus_ProtocolTimeoutOccurred
: return STATUS_IO_TIMEOUT
;
1759 case kSCSITaskStatus_DeviceNotResponding
: return STATUS_DEVICE_BUSY
;
1761 case kSCSITaskStatus_DeviceNotPresent
:
1762 return STATUS_NO_SUCH_DEVICE
;
1764 case kSCSITaskStatus_DeliveryFailure
:
1765 return STATUS_DEVICE_PROTOCOL_ERROR
;
1767 case kSCSITaskStatus_No_Status
:
1769 return STATUS_UNSUCCESSFUL
;
1774 if (cmd
.status
!= kSCSITaskStatus_No_Status
)
1775 pPacket
->ScsiStatus
= cmd
.status
;
1777 ret
= CDROM_GetStatusCode(io
);
1782 /******************************************************************
1783 * CDROM_ScsiPassThrough
1784 * Implements IOCTL_SCSI_PASS_THROUGH
1787 static NTSTATUS
CDROM_ScsiPassThrough(int fd
, PSCSI_PASS_THROUGH pPacket
)
1789 int ret
= STATUS_NOT_SUPPORTED
;
1790 #ifdef HAVE_SG_IO_HDR_T_INTERFACE_ID
1793 #elif defined HAVE_SCSIREQ_T_CMD
1796 #elif defined __APPLE__
1797 dk_scsi_command_t cmd
;
1801 if (pPacket
->Length
< sizeof(SCSI_PASS_THROUGH
))
1802 return STATUS_BUFFER_TOO_SMALL
;
1804 if (pPacket
->CdbLength
> 16)
1805 return STATUS_INVALID_PARAMETER
;
1808 if (pPacket
->SenseInfoLength
> SENSEBUFLEN
)
1809 return STATUS_INVALID_PARAMETER
;
1810 #elif defined HAVE_REQUEST_SENSE
1811 if (pPacket
->SenseInfoLength
> sizeof(struct request_sense
))
1812 return STATUS_INVALID_PARAMETER
;
1815 if (pPacket
->DataTransferLength
> 0 && pPacket
->DataBufferOffset
< sizeof(SCSI_PASS_THROUGH
))
1816 return STATUS_INVALID_PARAMETER
;
1818 #ifdef HAVE_SG_IO_HDR_T_INTERFACE_ID
1819 RtlZeroMemory(&cmd
, sizeof(cmd
));
1821 cmd
.interface_id
= 'S';
1822 cmd
.dxfer_len
= pPacket
->DataTransferLength
;
1823 cmd
.dxferp
= (char*)pPacket
+ pPacket
->DataBufferOffset
;
1824 cmd
.cmd_len
= pPacket
->CdbLength
;
1825 cmd
.cmdp
= pPacket
->Cdb
;
1826 cmd
.mx_sb_len
= pPacket
->SenseInfoLength
;
1827 cmd
.timeout
= pPacket
->TimeOutValue
*1000;
1829 if(cmd
.mx_sb_len
> 0)
1830 cmd
.sbp
= (unsigned char*)pPacket
+ pPacket
->SenseInfoOffset
;
1832 switch (pPacket
->DataIn
)
1834 case SCSI_IOCTL_DATA_IN
:
1835 cmd
.dxfer_direction
= SG_DXFER_FROM_DEV
;
1837 case SCSI_IOCTL_DATA_OUT
:
1838 cmd
.dxfer_direction
= SG_DXFER_TO_DEV
;
1840 case SCSI_IOCTL_DATA_UNSPECIFIED
:
1841 cmd
.dxfer_direction
= SG_DXFER_NONE
;
1844 return STATUS_INVALID_PARAMETER
;
1847 io
= ioctl(fd
, SG_IO
, &cmd
);
1849 pPacket
->ScsiStatus
= cmd
.status
;
1850 pPacket
->DataTransferLength
= cmd
.resid
;
1851 pPacket
->SenseInfoLength
= cmd
.sb_len_wr
;
1853 ret
= CDROM_GetStatusCode(io
);
1855 #elif defined HAVE_SCSIREQ_T_CMD
1857 memset(&cmd
, 0, sizeof(cmd
));
1858 memcpy(&(cmd
.cmd
), &(pPacket
->Cdb
), pPacket
->CdbLength
);
1860 if ( pPacket
->DataBufferOffset
> 0x1000 )
1862 cmd
.databuf
= (void*)pPacket
->DataBufferOffset
;
1866 cmd
.databuf
= (char*)pPacket
+ pPacket
->DataBufferOffset
;
1869 cmd
.cmdlen
= pPacket
->CdbLength
;
1870 cmd
.datalen
= pPacket
->DataTransferLength
;
1871 cmd
.senselen
= pPacket
->SenseInfoLength
;
1872 cmd
.timeout
= pPacket
->TimeOutValue
*1000; /* in milliseconds */
1874 switch (pPacket
->DataIn
)
1876 case SCSI_IOCTL_DATA_OUT
:
1877 cmd
.flags
|= SCCMD_WRITE
;
1879 case SCSI_IOCTL_DATA_IN
:
1880 cmd
.flags
|= SCCMD_READ
;
1882 case SCSI_IOCTL_DATA_UNSPECIFIED
:
1886 return STATUS_INVALID_PARAMETER
;
1889 io
= ioctl(fd
, SCIOCCOMMAND
, &cmd
);
1893 case SCCMD_OK
: break;
1894 case SCCMD_TIMEOUT
: return STATUS_TIMEOUT
;
1896 case SCCMD_BUSY
: return STATUS_DEVICE_BUSY
;
1898 case SCCMD_SENSE
: break;
1899 case SCCMD_UNKNOWN
: return STATUS_UNSUCCESSFUL
;
1903 if (pPacket
->SenseInfoLength
!= 0)
1905 memcpy((char*)pPacket
+ pPacket
->SenseInfoOffset
,
1906 cmd
.sense
, pPacket
->SenseInfoLength
);
1909 pPacket
->ScsiStatus
= cmd
.status
;
1911 ret
= CDROM_GetStatusCode(io
);
1913 #elif defined(__APPLE__)
1915 memset(&cmd
, 0, sizeof(cmd
));
1916 memcpy(cmd
.cdb
, pPacket
->Cdb
, pPacket
->CdbLength
);
1918 cmd
.cdbSize
= pPacket
->CdbLength
;
1919 cmd
.buffer
= (char*)pPacket
+ pPacket
->DataBufferOffset
;
1920 cmd
.bufferSize
= pPacket
->DataTransferLength
;
1921 cmd
.sense
= (char*)pPacket
+ pPacket
->SenseInfoOffset
;
1922 cmd
.senseLen
= pPacket
->SenseInfoLength
;
1923 cmd
.timeout
= pPacket
->TimeOutValue
*1000; /* in milliseconds */
1925 switch (pPacket
->DataIn
)
1927 case SCSI_IOCTL_DATA_OUT
:
1928 cmd
.direction
= kSCSIDataTransfer_FromInitiatorToTarget
;
1930 case SCSI_IOCTL_DATA_IN
:
1931 cmd
.direction
= kSCSIDataTransfer_FromTargetToInitiator
;
1933 case SCSI_IOCTL_DATA_UNSPECIFIED
:
1934 cmd
.direction
= kSCSIDataTransfer_NoDataTransfer
;
1937 return STATUS_INVALID_PARAMETER
;
1940 io
= ioctl(fd
, DKIOCSCSICOMMAND
, &cmd
);
1942 if (cmd
.response
== kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE
)
1944 /* Command failed */
1947 case kSCSITaskStatus_TaskTimeoutOccurred
:
1948 return STATUS_TIMEOUT
;
1950 case kSCSITaskStatus_ProtocolTimeoutOccurred
:
1951 return STATUS_IO_TIMEOUT
;
1953 case kSCSITaskStatus_DeviceNotResponding
:
1954 return STATUS_DEVICE_BUSY
;
1956 case kSCSITaskStatus_DeviceNotPresent
:
1957 return STATUS_NO_SUCH_DEVICE
;
1959 case kSCSITaskStatus_DeliveryFailure
:
1960 return STATUS_DEVICE_PROTOCOL_ERROR
;
1962 case kSCSITaskStatus_No_Status
:
1964 return STATUS_UNSUCCESSFUL
;
1969 if (cmd
.status
!= kSCSITaskStatus_No_Status
)
1970 pPacket
->ScsiStatus
= cmd
.status
;
1972 ret
= CDROM_GetStatusCode(io
);
1977 /******************************************************************
1982 static NTSTATUS
CDROM_ScsiGetCaps(int fd
, PIO_SCSI_CAPABILITIES caps
)
1984 NTSTATUS ret
= STATUS_NOT_IMPLEMENTED
;
1986 #ifdef SG_SCATTER_SZ
1987 caps
->Length
= sizeof(*caps
);
1988 caps
->MaximumTransferLength
= SG_SCATTER_SZ
; /* FIXME */
1989 caps
->MaximumPhysicalPages
= SG_SCATTER_SZ
/ getpagesize();
1990 caps
->SupportedAsynchronousEvents
= TRUE
;
1991 caps
->AlignmentMask
= getpagesize();
1992 caps
->TaggedQueuing
= FALSE
; /* we could check that it works and answer TRUE */
1993 caps
->AdapterScansDown
= FALSE
; /* FIXME ? */
1994 caps
->AdapterUsesPio
= FALSE
; /* FIXME ? */
1995 ret
= STATUS_SUCCESS
;
1996 #elif defined __APPLE__
1997 uint64_t bytesr
, bytesw
, align
;
1998 int io
= ioctl(fd
, DKIOCGETMAXBYTECOUNTREAD
, &bytesr
);
1999 if (io
!= 0) return CDROM_GetStatusCode(io
);
2000 io
= ioctl(fd
, DKIOCGETMAXBYTECOUNTWRITE
, &bytesw
);
2001 if (io
!= 0) return CDROM_GetStatusCode(io
);
2002 io
= ioctl(fd
, DKIOCGETMINSEGMENTALIGNMENTBYTECOUNT
, &align
);
2003 if (io
!= 0) return CDROM_GetStatusCode(io
);
2004 caps
->Length
= sizeof(*caps
);
2005 caps
->MaximumTransferLength
= bytesr
< bytesw
? bytesr
: bytesw
;
2006 caps
->MaximumPhysicalPages
= caps
->MaximumTransferLength
/ getpagesize();
2007 caps
->SupportedAsynchronousEvents
= TRUE
;
2008 caps
->AlignmentMask
= align
-1;
2009 caps
->TaggedQueuing
= FALSE
; /* we could check that it works and answer TRUE */
2010 caps
->AdapterScansDown
= FALSE
; /* FIXME ? */
2011 caps
->AdapterUsesPio
= FALSE
; /* FIXME ? */
2012 ret
= STATUS_SUCCESS
;
2014 FIXME("Unimplemented\n");
2019 /******************************************************************
2022 * implements IOCTL_SCSI_GET_ADDRESS
2024 static NTSTATUS
CDROM_GetAddress(int fd
, SCSI_ADDRESS
* address
)
2026 UCHAR portnum
, busid
, targetid
, lun
;
2028 address
->Length
= sizeof(SCSI_ADDRESS
);
2029 if ( ! CDROM_GetInterfaceInfo(fd
, &portnum
, &busid
, &targetid
, &lun
))
2030 return STATUS_NOT_SUPPORTED
;
2032 address
->PortNumber
= portnum
; /* primary=0 secondary=1 for ide */
2033 address
->PathId
= busid
; /* always 0 for ide */
2034 address
->TargetId
= targetid
; /* master=0 slave=1 for ide */
2036 return STATUS_SUCCESS
;
2039 /******************************************************************
2044 static NTSTATUS
DVD_StartSession(int fd
, const DVD_SESSION_ID
*sid_in
, PDVD_SESSION_ID sid_out
)
2047 NTSTATUS ret
= STATUS_NOT_SUPPORTED
;
2048 dvd_authinfo auth_info
;
2050 memset( &auth_info
, 0, sizeof( auth_info
) );
2051 auth_info
.type
= DVD_LU_SEND_AGID
;
2052 if (sid_in
) auth_info
.lsa
.agid
= *(const int*)sid_in
; /* ?*/
2054 TRACE("fd 0x%08x\n",fd
);
2055 ret
=CDROM_GetStatusCode(ioctl(fd
, DVD_AUTH
, &auth_info
));
2056 *sid_out
= auth_info
.lsa
.agid
;
2058 #elif defined(__APPLE__)
2059 NTSTATUS ret
= STATUS_NOT_SUPPORTED
;
2060 dk_dvd_report_key_t dvdrk
;
2061 DVDAuthenticationGrantIDInfo agid_info
;
2063 dvdrk
.format
= kDVDKeyFormatAGID_CSS
;
2064 dvdrk
.keyClass
= kDVDKeyClassCSS_CPPM_CPRM
;
2065 if(sid_in
) dvdrk
.grantID
= *(uint8_t*)sid_in
; /* ? */
2066 dvdrk
.bufferLength
= sizeof(DVDAuthenticationGrantIDInfo
);
2067 dvdrk
.buffer
= &agid_info
;
2069 ret
= CDROM_GetStatusCode(ioctl(fd
, DKIOCDVDREPORTKEY
, &dvdrk
));
2070 *sid_out
= agid_info
.grantID
;
2073 FIXME("not supported on this O/S\n");
2074 return STATUS_NOT_SUPPORTED
;
2078 /******************************************************************
2083 static NTSTATUS
DVD_EndSession(int fd
, const DVD_SESSION_ID
*sid
)
2086 dvd_authinfo auth_info
;
2088 memset( &auth_info
, 0, sizeof( auth_info
) );
2089 auth_info
.type
= DVD_INVALIDATE_AGID
;
2090 auth_info
.lsa
.agid
= *(const int*)sid
;
2093 return CDROM_GetStatusCode(ioctl(fd
, DVD_AUTH
, &auth_info
));
2094 #elif defined(__APPLE__)
2095 dk_dvd_send_key_t dvdsk
;
2097 dvdsk
.format
= kDVDKeyFormatAGID_Invalidate
;
2098 dvdsk
.keyClass
= kDVDKeyClassCSS_CPPM_CPRM
;
2099 dvdsk
.grantID
= (uint8_t)*sid
;
2101 return CDROM_GetStatusCode(ioctl(fd
, DKIOCDVDSENDKEY
, &dvdsk
));
2103 FIXME("not supported on this O/S\n");
2104 return STATUS_NOT_SUPPORTED
;
2108 /******************************************************************
2113 static NTSTATUS
DVD_SendKey(int fd
, const DVD_COPY_PROTECT_KEY
*key
)
2116 NTSTATUS ret
= STATUS_NOT_SUPPORTED
;
2117 dvd_authinfo auth_info
;
2119 memset( &auth_info
, 0, sizeof( auth_info
) );
2120 switch (key
->KeyType
)
2122 case DvdChallengeKey
:
2123 auth_info
.type
= DVD_HOST_SEND_CHALLENGE
;
2124 auth_info
.hsc
.agid
= (int)key
->SessionId
;
2125 TRACE("DvdChallengeKey ioc 0x%x\n", DVD_AUTH
);
2126 memcpy( auth_info
.hsc
.chal
, key
->KeyData
, DVD_CHALLENGE_SIZE
);
2127 ret
= CDROM_GetStatusCode(ioctl( fd
, DVD_AUTH
, &auth_info
));
2130 auth_info
.type
= DVD_HOST_SEND_KEY2
;
2131 auth_info
.hsk
.agid
= (int)key
->SessionId
;
2133 memcpy( auth_info
.hsk
.key
, key
->KeyData
, DVD_KEY_SIZE
);
2135 TRACE("DvdBusKey2\n");
2136 ret
= CDROM_GetStatusCode(ioctl( fd
, DVD_AUTH
, &auth_info
));
2140 FIXME("Unknown Keytype 0x%x\n",key
->KeyType
);
2143 #elif defined(__APPLE__)
2144 dk_dvd_send_key_t dvdsk
;
2147 DVDChallengeKeyInfo chal
;
2151 switch(key
->KeyType
)
2153 case DvdChallengeKey
:
2154 dvdsk
.format
= kDVDKeyFormatChallengeKey
;
2155 dvdsk
.bufferLength
= sizeof(key_desc
.chal
);
2156 dvdsk
.buffer
= &key_desc
.chal
;
2157 OSWriteBigInt16(key_desc
.chal
.dataLength
, 0, key
->KeyLength
);
2158 memcpy(key_desc
.chal
.challengeKeyValue
, key
->KeyData
, key
->KeyLength
);
2161 dvdsk
.format
= kDVDKeyFormatKey2
;
2162 dvdsk
.bufferLength
= sizeof(key_desc
.key2
);
2163 dvdsk
.buffer
= &key_desc
.key2
;
2164 OSWriteBigInt16(key_desc
.key2
.dataLength
, 0, key
->KeyLength
);
2165 memcpy(key_desc
.key2
.key2Value
, key
->KeyData
, key
->KeyLength
);
2167 case DvdInvalidateAGID
:
2168 dvdsk
.format
= kDVDKeyFormatAGID_Invalidate
;
2175 ERR("attempted to write read-only key type 0x%x\n", key
->KeyType
);
2176 return STATUS_NOT_SUPPORTED
;
2178 FIXME("DvdSetRpcKey NIY\n");
2179 return STATUS_NOT_SUPPORTED
;
2181 FIXME("got unknown key type 0x%x\n", key
->KeyType
);
2182 return STATUS_NOT_SUPPORTED
;
2184 dvdsk
.keyClass
= kDVDKeyClassCSS_CPPM_CPRM
;
2185 dvdsk
.grantID
= (uint8_t)key
->SessionId
;
2187 return CDROM_GetStatusCode(ioctl(fd
, DKIOCDVDSENDKEY
, &dvdsk
));
2189 FIXME("not supported on this O/S\n");
2190 return STATUS_NOT_SUPPORTED
;
2194 /******************************************************************
2199 static NTSTATUS
DVD_ReadKey(int fd
, PDVD_COPY_PROTECT_KEY key
)
2202 NTSTATUS ret
= STATUS_NOT_SUPPORTED
;
2204 dvd_authinfo auth_info
;
2206 memset( &dvd
, 0, sizeof( dvd_struct
) );
2207 memset( &auth_info
, 0, sizeof( auth_info
) );
2208 switch (key
->KeyType
)
2212 dvd
.type
= DVD_STRUCT_DISCKEY
;
2213 dvd
.disckey
.agid
= (int)key
->SessionId
;
2214 memset( dvd
.disckey
.value
, 0, DVD_DISCKEY_SIZE
);
2216 TRACE("DvdDiskKey\n");
2217 ret
= CDROM_GetStatusCode(ioctl( fd
, DVD_READ_STRUCT
, &dvd
));
2218 if (ret
== STATUS_SUCCESS
)
2219 memcpy(key
->KeyData
,dvd
.disckey
.value
,DVD_DISCKEY_SIZE
);
2222 auth_info
.type
= DVD_LU_SEND_TITLE_KEY
;
2223 auth_info
.lstk
.agid
= (int)key
->SessionId
;
2224 auth_info
.lstk
.lba
= (int)(key
->Parameters
.TitleOffset
.QuadPart
>>11);
2225 TRACE("DvdTitleKey session %d Quadpart 0x%08lx offset 0x%08x\n",
2226 (int)key
->SessionId
, (long)key
->Parameters
.TitleOffset
.QuadPart
,
2227 auth_info
.lstk
.lba
);
2228 ret
= CDROM_GetStatusCode(ioctl( fd
, DVD_AUTH
, &auth_info
));
2229 if (ret
== STATUS_SUCCESS
)
2230 memcpy(key
->KeyData
, auth_info
.lstk
.title_key
, DVD_KEY_SIZE
);
2232 case DvdChallengeKey
:
2234 auth_info
.type
= DVD_LU_SEND_CHALLENGE
;
2235 auth_info
.lsc
.agid
= (int)key
->SessionId
;
2237 TRACE("DvdChallengeKey\n");
2238 ret
= CDROM_GetStatusCode(ioctl( fd
, DVD_AUTH
, &auth_info
));
2239 if (ret
== STATUS_SUCCESS
)
2240 memcpy( key
->KeyData
, auth_info
.lsc
.chal
, DVD_CHALLENGE_SIZE
);
2243 auth_info
.type
= DVD_LU_SEND_ASF
;
2245 auth_info
.lsasf
.asf
=((PDVD_ASF
)key
->KeyData
)->SuccessFlag
;
2246 ret
= CDROM_GetStatusCode(ioctl( fd
, DVD_AUTH
, &auth_info
));
2247 ((PDVD_ASF
)key
->KeyData
)->SuccessFlag
= auth_info
.lsasf
.asf
;
2250 auth_info
.type
= DVD_LU_SEND_KEY1
;
2251 auth_info
.lsk
.agid
= (int)key
->SessionId
;
2253 TRACE("DvdBusKey1\n");
2254 ret
= CDROM_GetStatusCode(ioctl( fd
, DVD_AUTH
, &auth_info
));
2256 if (ret
== STATUS_SUCCESS
)
2257 memcpy( key
->KeyData
, auth_info
.lsk
.key
, DVD_KEY_SIZE
);
2260 auth_info
.type
= DVD_LU_SEND_RPC_STATE
;
2262 TRACE("DvdGetRpcKey\n");
2263 ret
= CDROM_GetStatusCode(ioctl( fd
, DVD_AUTH
, &auth_info
));
2265 if (ret
== STATUS_SUCCESS
)
2267 ((PDVD_RPC_KEY
)key
->KeyData
)->TypeCode
= auth_info
.lrpcs
.type
;
2268 ((PDVD_RPC_KEY
)key
->KeyData
)->RegionMask
= auth_info
.lrpcs
.region_mask
;
2269 ((PDVD_RPC_KEY
)key
->KeyData
)->RpcScheme
= auth_info
.lrpcs
.rpc_scheme
;
2270 ((PDVD_RPC_KEY
)key
->KeyData
)->UserResetsAvailable
= auth_info
.lrpcs
.ucca
;
2271 ((PDVD_RPC_KEY
)key
->KeyData
)->ManufacturerResetsAvailable
= auth_info
.lrpcs
.vra
;
2275 FIXME("Unknown keytype 0x%x\n",key
->KeyType
);
2278 #elif defined(__APPLE__)
2281 dk_dvd_report_key_t key
;
2282 dk_dvd_read_structure_t disk_key
;
2286 DVDDiscKeyInfo disk_key
;
2287 DVDChallengeKeyInfo chal
;
2289 DVDTitleKeyInfo title
;
2290 DVDAuthenticationSuccessFlagInfo asf
;
2291 DVDRegionPlaybackControlInfo rpc
;
2293 NTSTATUS ret
= STATUS_NOT_SUPPORTED
;
2295 switch(key
->KeyType
)
2297 case DvdChallengeKey
:
2298 ioc
.key
.format
= kDVDKeyFormatChallengeKey
;
2299 ioc
.key
.grantID
= (uint8_t)key
->SessionId
;
2300 ioc
.key
.keyClass
= kDVDKeyClassCSS_CPPM_CPRM
;
2301 ioc
.key
.bufferLength
= sizeof(desc
.chal
);
2302 ioc
.key
.buffer
= &desc
.chal
;
2303 OSWriteBigInt16(desc
.chal
.dataLength
, 0, key
->KeyLength
);
2306 ioc
.key
.format
= kDVDKeyFormatKey1
;
2307 ioc
.key
.grantID
= (uint8_t)key
->SessionId
;
2308 ioc
.key
.keyClass
= kDVDKeyClassCSS_CPPM_CPRM
;
2309 ioc
.key
.bufferLength
= sizeof(desc
.key1
);
2310 ioc
.key
.buffer
= &desc
.key1
;
2311 OSWriteBigInt16(desc
.key1
.dataLength
, 0, key
->KeyLength
);
2314 ioc
.key
.format
= kDVDKeyFormatTitleKey
;
2315 ioc
.key
.grantID
= (uint8_t)key
->SessionId
;
2316 ioc
.key
.keyClass
= kDVDKeyClassCSS_CPPM_CPRM
;
2317 ioc
.key
.bufferLength
= sizeof(desc
.title
);
2318 ioc
.key
.buffer
= &desc
.title
;
2319 ioc
.key
.address
= (uint32_t)(key
->Parameters
.TitleOffset
.QuadPart
>>11);
2320 OSWriteBigInt16(desc
.title
.dataLength
, 0, key
->KeyLength
);
2323 ioc
.key
.format
= kDVDKeyFormatASF
;
2324 ioc
.key
.grantID
= (uint8_t)key
->SessionId
;
2325 ioc
.key
.keyClass
= kDVDKeyClassCSS_CPPM_CPRM
;
2326 ioc
.key
.bufferLength
= sizeof(desc
.asf
);
2327 ioc
.key
.buffer
= &desc
.asf
;
2328 OSWriteBigInt16(desc
.asf
.dataLength
, 0, key
->KeyLength
);
2331 ioc
.key
.format
= kDVDKeyFormatRegionState
;
2332 ioc
.key
.grantID
= (uint8_t)key
->SessionId
;
2333 ioc
.key
.keyClass
= kDVDKeyClassCSS_CPPM_CPRM
;
2334 ioc
.key
.bufferLength
= sizeof(desc
.rpc
);
2335 ioc
.key
.buffer
= &desc
.rpc
;
2336 OSWriteBigInt16(desc
.rpc
.dataLength
, 0, key
->KeyLength
);
2339 ioc
.disk_key
.format
= kDVDStructureFormatDiscKeyInfo
;
2340 ioc
.disk_key
.grantID
= (uint8_t)key
->SessionId
;
2341 ioc
.disk_key
.bufferLength
= sizeof(desc
.disk_key
);
2342 ioc
.disk_key
.buffer
= &desc
.disk_key
;
2344 case DvdInvalidateAGID
:
2345 ioc
.key
.format
= kDVDKeyFormatAGID_Invalidate
;
2346 ioc
.key
.grantID
= (uint8_t)key
->SessionId
;
2347 ioc
.key
.keyClass
= kDVDKeyClassCSS_CPPM_CPRM
;
2351 ERR("attempted to read write-only key type 0x%x\n", key
->KeyType
);
2352 return STATUS_NOT_SUPPORTED
;
2354 FIXME("got unknown key type 0x%x\n", key
->KeyType
);
2355 return STATUS_NOT_SUPPORTED
;
2358 ret
= CDROM_GetStatusCode(ioctl(fd
, (key
->KeyType
== DvdDiskKey
? DKIOCDVDREADSTRUCTURE
: DKIOCDVDREPORTKEY
), &ioc
));
2360 if (ret
== STATUS_SUCCESS
)
2362 switch(key
->KeyType
)
2364 case DvdChallengeKey
:
2365 key
->KeyLength
= OSReadBigInt16(desc
.chal
.dataLength
, 0);
2366 memcpy(key
->KeyData
, desc
.chal
.challengeKeyValue
, key
->KeyLength
);
2369 key
->KeyLength
= OSReadBigInt16(desc
.key1
.dataLength
, 0);
2370 memcpy(key
->KeyData
, desc
.key1
.key1Value
, key
->KeyLength
);
2373 key
->KeyLength
= OSReadBigInt16(desc
.title
.dataLength
, 0);
2374 memcpy(key
->KeyData
, desc
.title
.titleKeyValue
, key
->KeyLength
);
2378 /*key->KeyFlags |= DVD_COPYRIGHTED;*/
2379 if (desc
.title
.CP_SEC
) key
->KeyFlags
|= DVD_SECTOR_PROTECTED
;
2380 /*else key->KeyFlags |= DVD_SECTOR_NOT_PROTECTED;*/
2382 switch (desc
.title
.CGMS
)
2385 key
->KeyFlags
|= DVD_CGMS_COPY_PERMITTED
;
2388 key
->KeyFlags
|= DVD_CGMS_COPY_ONCE
;
2391 key
->KeyFlags
|= DVD_CGMS_NO_COPY
;
2395 } /*else key->KeyFlags |= DVD_NOT_COPYRIGHTED;*/
2398 key
->KeyLength
= OSReadBigInt16(desc
.title
.dataLength
, 0);
2399 ((PDVD_ASF
)key
->KeyData
)->SuccessFlag
= desc
.asf
.successFlag
;
2402 key
->KeyLength
= OSReadBigInt16(desc
.rpc
.dataLength
, 0);
2403 ((PDVD_RPC_KEY
)key
->KeyData
)->UserResetsAvailable
=
2404 desc
.rpc
.numberUserResets
;
2405 ((PDVD_RPC_KEY
)key
->KeyData
)->ManufacturerResetsAvailable
=
2406 desc
.rpc
.numberVendorResets
;
2407 ((PDVD_RPC_KEY
)key
->KeyData
)->TypeCode
=
2409 ((PDVD_RPC_KEY
)key
->KeyData
)->RegionMask
=
2410 desc
.rpc
.driveRegion
;
2411 ((PDVD_RPC_KEY
)key
->KeyData
)->RpcScheme
=
2414 key
->KeyLength
= OSReadBigInt16(desc
.disk_key
.dataLength
, 0);
2415 memcpy(key
->KeyData
, desc
.disk_key
.discKeyStructures
, key
->KeyLength
);
2419 case DvdInvalidateAGID
:
2421 /* Silence warning */
2427 FIXME("not supported on this O/S\n");
2428 return STATUS_NOT_SUPPORTED
;
2432 /******************************************************************
2435 * This IOCTL combines information from both IOCTL_DVD_READ_KEY
2436 * with key type DvdGetRpcKey and IOCTL_DVD_READ_STRUCTURE with
2437 * structure type DvdCopyrightInformation into one structure.
2439 static NTSTATUS
DVD_GetRegion(int fd
, PDVD_REGION region
)
2442 NTSTATUS ret
= STATUS_NOT_SUPPORTED
;
2444 dvd_authinfo auth_info
;
2446 dvd
.type
= DVD_STRUCT_COPYRIGHT
;
2447 dvd
.copyright
.layer_num
= 0;
2448 auth_info
.type
= DVD_LU_SEND_RPC_STATE
;
2450 ret
= CDROM_GetStatusCode(ioctl( fd
, DVD_AUTH
, &auth_info
));
2452 if (ret
== STATUS_SUCCESS
)
2454 ret
= CDROM_GetStatusCode(ioctl( fd
, DVD_READ_STRUCT
, &dvd
));
2456 if (ret
== STATUS_SUCCESS
)
2458 region
->CopySystem
= dvd
.copyright
.cpst
;
2459 region
->RegionData
= dvd
.copyright
.rmi
;
2460 region
->SystemRegion
= auth_info
.lrpcs
.region_mask
;
2461 region
->ResetCount
= auth_info
.lrpcs
.ucca
;
2465 #elif defined(__APPLE__)
2466 dk_dvd_report_key_t key
;
2467 dk_dvd_read_structure_t dvd
;
2468 DVDRegionPlaybackControlInfo rpc
;
2469 DVDCopyrightInfo copy
;
2470 NTSTATUS ret
= STATUS_NOT_SUPPORTED
;
2472 key
.format
= kDVDKeyFormatRegionState
;
2473 key
.keyClass
= kDVDKeyClassCSS_CPPM_CPRM
;
2474 key
.bufferLength
= sizeof(rpc
);
2476 dvd
.format
= kDVDStructureFormatCopyrightInfo
;
2477 dvd
.bufferLength
= sizeof(copy
);
2480 ret
= CDROM_GetStatusCode(ioctl( fd
, DKIOCDVDREPORTKEY
, &key
));
2482 if (ret
== STATUS_SUCCESS
)
2484 ret
= CDROM_GetStatusCode(ioctl( fd
, DKIOCDVDREADSTRUCTURE
, &dvd
));
2486 if (ret
== STATUS_SUCCESS
)
2488 region
->CopySystem
= copy
.copyrightProtectionSystemType
;
2489 region
->RegionData
= copy
.regionMask
;
2490 region
->SystemRegion
= rpc
.driveRegion
;
2491 region
->ResetCount
= rpc
.numberUserResets
;
2496 FIXME("not supported on this O/S\n");
2497 return STATUS_NOT_SUPPORTED
;
2501 /******************************************************************
2506 static NTSTATUS
DVD_ReadStructure(int dev
, const DVD_READ_STRUCTURE
*structure
, PDVD_LAYER_DESCRIPTOR layer
)
2508 #ifdef DVD_READ_STRUCT
2509 /* dvd_struct is not defined consistently across platforms */
2512 struct dvd_physical physical
;
2513 struct dvd_copyright copyright
;
2514 struct dvd_disckey disckey
;
2516 struct dvd_manufact manufact
;
2519 if (structure
->BlockByteOffset
.u
.HighPart
|| structure
->BlockByteOffset
.u
.LowPart
)
2520 FIXME(": BlockByteOffset is not handled\n");
2522 switch (structure
->Format
)
2524 case DvdPhysicalDescriptor
:
2525 s
.physical
.type
= DVD_STRUCT_PHYSICAL
;
2526 s
.physical
.layer_num
= structure
->LayerNumber
;
2529 case DvdCopyrightDescriptor
:
2530 s
.copyright
.type
= DVD_STRUCT_COPYRIGHT
;
2531 s
.copyright
.layer_num
= structure
->LayerNumber
;
2534 case DvdDiskKeyDescriptor
:
2535 s
.disckey
.type
= DVD_STRUCT_DISCKEY
;
2536 s
.disckey
.agid
= structure
->SessionId
;
2539 case DvdBCADescriptor
:
2540 s
.bca
.type
= DVD_STRUCT_BCA
;
2543 case DvdManufacturerDescriptor
:
2544 s
.manufact
.type
= DVD_STRUCT_MANUFACT
;
2545 s
.manufact
.layer_num
= structure
->LayerNumber
;
2548 case DvdMaxDescriptor
: /* This is not a real request, no matter what MSDN says! */
2550 return STATUS_INVALID_PARAMETER
;
2553 if (ioctl(dev
, DVD_READ_STRUCT
, &s
) < 0)
2554 return STATUS_INVALID_PARAMETER
;
2556 switch (structure
->Format
)
2558 case DvdPhysicalDescriptor
:
2560 internal_dvd_layer_descriptor
*p
= (internal_dvd_layer_descriptor
*) layer
;
2561 struct dvd_layer
*l
= &s
.physical
.layer
[s
.physical
.layer_num
];
2563 p
->DataLength
[0] = 2;
2564 p
->DataLength
[1] = 8;
2565 p
->Reserved0
[0] = 0;
2566 p
->Reserved0
[1] = 0;
2567 p
->BookVersion
= l
->book_version
;
2568 p
->BookType
= l
->book_type
;
2569 p
->MinimumRate
= l
->min_rate
;
2570 p
->DiskSize
= l
->disc_size
;
2571 p
->LayerType
= l
->layer_type
;
2572 p
->TrackPath
= l
->track_path
;
2573 p
->NumberOfLayers
= l
->nlayers
;
2575 p
->TrackDensity
= l
->track_density
;
2576 p
->LinearDensity
= l
->linear_density
;
2577 p
->StartingDataSector
= GET_BE_DWORD(l
->start_sector
);
2578 p
->EndDataSector
= GET_BE_DWORD(l
->end_sector
);
2579 p
->EndLayerZeroSector
= GET_BE_DWORD(l
->end_sector_l0
);
2581 p
->BCAFlag
= l
->bca
;
2586 case DvdCopyrightDescriptor
:
2588 PDVD_COPYRIGHT_DESCRIPTOR p
= (PDVD_COPYRIGHT_DESCRIPTOR
) layer
;
2590 p
->CopyrightProtectionType
= s
.copyright
.cpst
;
2591 p
->RegionManagementInformation
= s
.copyright
.rmi
;
2596 case DvdDiskKeyDescriptor
:
2598 PDVD_DISK_KEY_DESCRIPTOR p
= (PDVD_DISK_KEY_DESCRIPTOR
) layer
;
2600 memcpy(p
->DiskKeyData
, s
.disckey
.value
, 2048);
2604 case DvdBCADescriptor
:
2606 PDVD_BCA_DESCRIPTOR p
= (PDVD_BCA_DESCRIPTOR
) layer
;
2608 memcpy(p
->BCAInformation
, s
.bca
.value
, s
.bca
.len
);
2612 case DvdManufacturerDescriptor
:
2614 PDVD_MANUFACTURER_DESCRIPTOR p
= (PDVD_MANUFACTURER_DESCRIPTOR
) layer
;
2616 memcpy(p
->ManufacturingInformation
, s
.manufact
.value
, 2048);
2620 case DvdMaxDescriptor
: /* Suppress warning */
2623 #elif defined(__APPLE__)
2624 NTSTATUS ret
= STATUS_NOT_SUPPORTED
;
2625 dk_dvd_read_structure_t dvdrs
;
2628 DVDPhysicalFormatInfo phys
;
2629 DVDCopyrightInfo copy
;
2630 DVDDiscKeyInfo disk_key
;
2631 DVDManufacturingInfo manf
;
2635 PDVD_LAYER_DESCRIPTOR layer
;
2636 internal_dvd_layer_descriptor
*xlayer
;
2637 PDVD_COPYRIGHT_DESCRIPTOR copy
;
2638 PDVD_DISK_KEY_DESCRIPTOR disk_key
;
2639 PDVD_MANUFACTURER_DESCRIPTOR manf
;
2642 nt_desc
.layer
= layer
;
2643 RtlZeroMemory(&dvdrs
, sizeof(dvdrs
));
2644 dvdrs
.address
= (uint32_t)(structure
->BlockByteOffset
.QuadPart
>>11);
2645 dvdrs
.grantID
= (uint8_t)structure
->SessionId
;
2646 dvdrs
.layer
= structure
->LayerNumber
;
2647 switch(structure
->Format
)
2649 case DvdPhysicalDescriptor
:
2650 dvdrs
.format
= kDVDStructureFormatPhysicalFormatInfo
;
2651 dvdrs
.bufferLength
= sizeof(desc
.phys
);
2652 dvdrs
.buffer
= &desc
.phys
;
2655 case DvdCopyrightDescriptor
:
2656 dvdrs
.format
= kDVDStructureFormatCopyrightInfo
;
2657 dvdrs
.bufferLength
= sizeof(desc
.copy
);
2658 dvdrs
.buffer
= &desc
.copy
;
2661 case DvdDiskKeyDescriptor
:
2662 dvdrs
.format
= kDVDStructureFormatDiscKeyInfo
;
2663 dvdrs
.bufferLength
= sizeof(desc
.disk_key
);
2664 dvdrs
.buffer
= &desc
.disk_key
;
2667 case DvdBCADescriptor
:
2668 FIXME("DvdBCADescriptor NIY\n");
2669 return STATUS_NOT_SUPPORTED
;
2671 case DvdManufacturerDescriptor
:
2672 dvdrs
.format
= kDVDStructureFormatManufacturingInfo
;
2673 dvdrs
.bufferLength
= sizeof(desc
.manf
);
2674 dvdrs
.buffer
= &desc
.manf
;
2677 case DvdMaxDescriptor
:
2679 FIXME("got unknown structure type 0x%x\n", structure
->Format
);
2680 return STATUS_NOT_SUPPORTED
;
2682 ret
= CDROM_GetStatusCode(ioctl(dev
, DKIOCDVDREADSTRUCTURE
, &dvdrs
));
2683 if(ret
== STATUS_SUCCESS
)
2685 switch(structure
->Format
)
2687 case DvdPhysicalDescriptor
:
2688 nt_desc
.xlayer
->DataLength
[0] = 2;
2689 nt_desc
.xlayer
->DataLength
[1] = 8;
2690 nt_desc
.xlayer
->Reserved0
[0] = 0;
2691 nt_desc
.xlayer
->Reserved0
[1] = 0;
2692 nt_desc
.xlayer
->BookVersion
= desc
.phys
.partVersion
;
2693 nt_desc
.xlayer
->BookType
= desc
.phys
.bookType
;
2694 nt_desc
.xlayer
->MinimumRate
= desc
.phys
.minimumRate
;
2695 nt_desc
.xlayer
->DiskSize
= desc
.phys
.discSize
;
2696 nt_desc
.xlayer
->LayerType
= desc
.phys
.layerType
;
2697 nt_desc
.xlayer
->TrackPath
= desc
.phys
.trackPath
;
2698 nt_desc
.xlayer
->NumberOfLayers
= desc
.phys
.numberOfLayers
;
2699 nt_desc
.xlayer
->Reserved1
= 0;
2700 nt_desc
.xlayer
->TrackDensity
= desc
.phys
.trackDensity
;
2701 nt_desc
.xlayer
->LinearDensity
= desc
.phys
.linearDensity
;
2702 nt_desc
.xlayer
->BCAFlag
= desc
.phys
.bcaFlag
;
2703 nt_desc
.xlayer
->StartingDataSector
= *(DWORD
*)&desc
.phys
.zero1
;
2704 nt_desc
.xlayer
->EndDataSector
= *(DWORD
*)&desc
.phys
.zero2
;
2705 nt_desc
.xlayer
->EndLayerZeroSector
= *(DWORD
*)&desc
.phys
.zero3
;
2706 nt_desc
.xlayer
->Reserved5
= 0;
2707 nt_desc
.xlayer
->Reserved6
= 0;
2710 case DvdCopyrightDescriptor
:
2711 nt_desc
.copy
->CopyrightProtectionType
=
2712 desc
.copy
.copyrightProtectionSystemType
;
2713 nt_desc
.copy
->RegionManagementInformation
=
2714 desc
.copy
.regionMask
;
2715 nt_desc
.copy
->Reserved
= 0;
2718 case DvdDiskKeyDescriptor
:
2720 nt_desc
.disk_key
->DiskKeyData
,
2721 desc
.disk_key
.discKeyStructures
,
2725 case DvdManufacturerDescriptor
:
2727 nt_desc
.manf
->ManufacturingInformation
,
2728 desc
.manf
.discManufacturingInfo
,
2732 case DvdBCADescriptor
:
2733 case DvdMaxDescriptor
:
2735 /* Silence warning */
2743 return STATUS_SUCCESS
;
2747 /******************************************************************
2749 * Implements the IOCTL_GET_INQUIRY_DATA ioctl.
2750 * Returns Inquiry data for all devices on the specified scsi bus
2751 * Returns STATUS_BUFFER_TOO_SMALL if the output buffer is too small,
2752 * STATUS_INVALID_DEVICE_REQUEST if the given handle isn't to a SCSI device,
2753 * or STATUS_NOT_SUPPORTED if the OS driver is too old
2755 static NTSTATUS
GetInquiryData(int fd
, PSCSI_ADAPTER_BUS_INFO BufferOut
, DWORD OutBufferSize
)
2757 #ifdef HAVE_SG_IO_HDR_T_INTERFACE_ID
2758 PSCSI_INQUIRY_DATA pInquiryData
= NULL
;
2759 UCHAR sense_buffer
[32];
2762 UCHAR inquiry
[INQ_CMD_LEN
] = {INQUIRY
, 0, 0, 0, INQ_REPLY_LEN
, 0};
2764 /* Check we have a SCSI device and a supported driver */
2765 if(ioctl(fd
, SG_GET_VERSION_NUM
, &version
) != 0)
2767 WARN("IOCTL_SCSI_GET_INQUIRY_DATA sg driver is not loaded\n");
2768 return STATUS_INVALID_DEVICE_REQUEST
;
2770 if(version
< 30000 )
2771 return STATUS_NOT_SUPPORTED
;
2773 /* FIXME: Enumerate devices on the bus */
2774 BufferOut
->NumberOfBuses
= 1;
2775 BufferOut
->BusData
[0].NumberOfLogicalUnits
= 1;
2776 BufferOut
->BusData
[0].InquiryDataOffset
= sizeof(SCSI_ADAPTER_BUS_INFO
);
2778 pInquiryData
= (PSCSI_INQUIRY_DATA
)(BufferOut
+ 1);
2780 RtlZeroMemory(&iocmd
, sizeof(iocmd
));
2781 iocmd
.interface_id
= 'S';
2782 iocmd
.cmd_len
= sizeof(inquiry
);
2783 iocmd
.mx_sb_len
= sizeof(sense_buffer
);
2784 iocmd
.dxfer_direction
= SG_DXFER_FROM_DEV
;
2785 iocmd
.dxfer_len
= INQ_REPLY_LEN
;
2786 iocmd
.dxferp
= pInquiryData
->InquiryData
;
2787 iocmd
.cmdp
= inquiry
;
2788 iocmd
.sbp
= sense_buffer
;
2789 iocmd
.timeout
= 1000;
2791 iochk
= ioctl(fd
, SG_IO
, &iocmd
);
2793 WARN("ioctl SG_IO returned %d, error (%s)\n", iochk
, strerror(errno
));
2795 CDROM_GetInterfaceInfo(fd
, &BufferOut
->BusData
[0].InitiatorBusId
, &pInquiryData
->PathId
, &pInquiryData
->TargetId
, &pInquiryData
->Lun
);
2796 pInquiryData
->DeviceClaimed
= TRUE
;
2797 pInquiryData
->InquiryDataLength
= INQ_REPLY_LEN
;
2798 pInquiryData
->NextInquiryDataOffset
= 0;
2799 return STATUS_SUCCESS
;
2801 FIXME("not supported on this O/S\n");
2802 return STATUS_NOT_SUPPORTED
;
2806 /******************************************************************
2807 * CDROM_DeviceIoControl
2811 NTSTATUS
CDROM_DeviceIoControl(HANDLE hDevice
,
2812 HANDLE hEvent
, PIO_APC_ROUTINE UserApcRoutine
,
2813 PVOID UserApcContext
,
2814 PIO_STATUS_BLOCK piosb
,
2815 ULONG dwIoControlCode
,
2816 LPVOID lpInBuffer
, DWORD nInBufferSize
,
2817 LPVOID lpOutBuffer
, DWORD nOutBufferSize
)
2820 NTSTATUS status
= STATUS_SUCCESS
;
2821 int fd
, needs_close
, dev
;
2823 TRACE("%p %s %p %d %p %d %p\n",
2824 hDevice
, iocodex(dwIoControlCode
), lpInBuffer
, nInBufferSize
,
2825 lpOutBuffer
, nOutBufferSize
, piosb
);
2827 piosb
->Information
= 0;
2829 if ((status
= server_get_unix_fd( hDevice
, 0, &fd
, &needs_close
, NULL
, NULL
)))
2831 if (status
== STATUS_BAD_DEVICE_TYPE
) return status
; /* no associated fd */
2835 if ((status
= CDROM_Open(fd
, &dev
)))
2837 if (needs_close
) close( fd
);
2845 /* This is ugly as hell, but Mac OS is unable to do anything from the
2846 * partition fd, it wants an fd for the whole device, and it sometimes
2847 * also requires the device fd to be closed first, so we have to close
2848 * the handle that the caller gave us.
2849 * Also for some reason it wants the fd to be closed before we even
2850 * open the parent if we're trying to eject the disk.
2852 if ((status
= get_parent_device( fd
, name
, sizeof(name
) ))) goto error
;
2853 if (dwIoControlCode
== IOCTL_STORAGE_EJECT_MEDIA
)
2855 if (needs_close
) close( fd
);
2856 TRACE("opening parent %s\n", name
);
2857 if ((fd
= open( name
, O_RDONLY
)) == -1)
2859 status
= FILE_GetNtStatus();
2866 switch (dwIoControlCode
)
2868 case IOCTL_CDROM_CHECK_VERIFY
:
2869 case IOCTL_DISK_CHECK_VERIFY
:
2870 case IOCTL_STORAGE_CHECK_VERIFY
:
2871 case IOCTL_STORAGE_CHECK_VERIFY2
:
2873 CDROM_ClearCacheEntry(dev
);
2874 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0 || lpOutBuffer
!= NULL
|| nOutBufferSize
!= 0)
2875 status
= STATUS_INVALID_PARAMETER
;
2876 else status
= CDROM_Verify(dev
, fd
);
2879 /* EPP case IOCTL_STORAGE_CHECK_VERIFY2: */
2881 /* EPP case IOCTL_STORAGE_FIND_NEW_DEVICES: */
2882 /* EPP case IOCTL_CDROM_FIND_NEW_DEVICES: */
2884 case IOCTL_STORAGE_LOAD_MEDIA
:
2885 case IOCTL_CDROM_LOAD_MEDIA
:
2887 CDROM_ClearCacheEntry(dev
);
2888 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0 || lpOutBuffer
!= NULL
|| nOutBufferSize
!= 0)
2889 status
= STATUS_INVALID_PARAMETER
;
2890 else status
= CDROM_SetTray(fd
, FALSE
);
2892 case IOCTL_STORAGE_EJECT_MEDIA
:
2894 CDROM_ClearCacheEntry(dev
);
2895 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0 || lpOutBuffer
!= NULL
|| nOutBufferSize
!= 0)
2896 status
= STATUS_INVALID_PARAMETER
;
2898 status
= CDROM_SetTray(fd
, TRUE
);
2901 case IOCTL_CDROM_MEDIA_REMOVAL
:
2902 case IOCTL_DISK_MEDIA_REMOVAL
:
2903 case IOCTL_STORAGE_MEDIA_REMOVAL
:
2904 case IOCTL_STORAGE_EJECTION_CONTROL
:
2905 /* FIXME the last ioctl:s is not the same as the two others...
2906 * lockcount/owner should be handled */
2908 CDROM_ClearCacheEntry(dev
);
2909 if (lpOutBuffer
!= NULL
|| nOutBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
2910 else if (nInBufferSize
< sizeof(PREVENT_MEDIA_REMOVAL
)) status
= STATUS_BUFFER_TOO_SMALL
;
2911 else status
= CDROM_ControlEjection(fd
, lpInBuffer
);
2914 case IOCTL_STORAGE_GET_MEDIA_TYPES
:
2915 case IOCTL_STORAGE_GET_MEDIA_TYPES_EX
:
2916 sz
= sizeof(GET_MEDIA_TYPES
);
2917 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
2918 else if (nOutBufferSize
< sz
) status
= STATUS_BUFFER_TOO_SMALL
;
2919 else status
= CDROM_GetMediaType(dev
, lpOutBuffer
);
2922 case IOCTL_STORAGE_GET_DEVICE_NUMBER
:
2923 sz
= sizeof(STORAGE_DEVICE_NUMBER
);
2924 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
2925 else if (nOutBufferSize
< sz
) status
= STATUS_BUFFER_TOO_SMALL
;
2926 else status
= CDROM_GetDeviceNumber(dev
, lpOutBuffer
);
2929 case IOCTL_STORAGE_RESET_DEVICE
:
2931 CDROM_ClearCacheEntry(dev
);
2932 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0 || lpOutBuffer
!= NULL
|| nOutBufferSize
!= 0)
2933 status
= STATUS_INVALID_PARAMETER
;
2934 else status
= CDROM_ResetAudio(fd
);
2937 case IOCTL_CDROM_GET_CONTROL
:
2938 sz
= sizeof(CDROM_AUDIO_CONTROL
);
2939 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
2940 else if (nOutBufferSize
< sz
) status
= STATUS_BUFFER_TOO_SMALL
;
2941 else status
= CDROM_GetControl(dev
, fd
, lpOutBuffer
);
2944 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
:
2945 sz
= sizeof(DISK_GEOMETRY
);
2946 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
2947 else if (nOutBufferSize
< sz
) status
= STATUS_BUFFER_TOO_SMALL
;
2948 else status
= CDROM_GetDriveGeometry(dev
, fd
, lpOutBuffer
);
2951 case IOCTL_CDROM_DISK_TYPE
:
2952 sz
= sizeof(CDROM_DISK_DATA
);
2953 /* CDROM_ClearCacheEntry(dev); */
2954 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
2955 else if (nOutBufferSize
< sz
) status
= STATUS_BUFFER_TOO_SMALL
;
2956 else status
= CDROM_GetDiskData(dev
, fd
, lpOutBuffer
);
2959 /* EPP case IOCTL_CDROM_GET_LAST_SESSION: */
2961 case IOCTL_CDROM_READ_Q_CHANNEL
:
2962 sz
= sizeof(SUB_Q_CHANNEL_DATA
);
2963 if (lpInBuffer
== NULL
|| nInBufferSize
< sizeof(CDROM_SUB_Q_DATA_FORMAT
))
2964 status
= STATUS_INVALID_PARAMETER
;
2965 else if (nOutBufferSize
< sz
) status
= STATUS_BUFFER_TOO_SMALL
;
2966 else status
= CDROM_ReadQChannel(dev
, fd
, lpInBuffer
, lpOutBuffer
);
2969 case IOCTL_CDROM_READ_TOC
:
2970 sz
= sizeof(CDROM_TOC
);
2971 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
2972 else if (nOutBufferSize
< sz
) status
= STATUS_BUFFER_TOO_SMALL
;
2973 else status
= CDROM_ReadTOC(dev
, fd
, lpOutBuffer
);
2976 /* EPP case IOCTL_CDROM_READ_TOC_EX: */
2978 case IOCTL_CDROM_PAUSE_AUDIO
:
2980 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0 || lpOutBuffer
!= NULL
|| nOutBufferSize
!= 0)
2981 status
= STATUS_INVALID_PARAMETER
;
2982 else status
= CDROM_PauseAudio(fd
);
2984 case IOCTL_CDROM_PLAY_AUDIO_MSF
:
2986 if (lpOutBuffer
!= NULL
|| nOutBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
2987 else if (nInBufferSize
< sizeof(CDROM_PLAY_AUDIO_MSF
)) status
= STATUS_BUFFER_TOO_SMALL
;
2988 else status
= CDROM_PlayAudioMSF(fd
, lpInBuffer
);
2990 case IOCTL_CDROM_RESUME_AUDIO
:
2992 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0 || lpOutBuffer
!= NULL
|| nOutBufferSize
!= 0)
2993 status
= STATUS_INVALID_PARAMETER
;
2994 else status
= CDROM_ResumeAudio(fd
);
2996 case IOCTL_CDROM_SEEK_AUDIO_MSF
:
2998 if (lpOutBuffer
!= NULL
|| nOutBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
2999 else if (nInBufferSize
< sizeof(CDROM_SEEK_AUDIO_MSF
)) status
= STATUS_BUFFER_TOO_SMALL
;
3000 else status
= CDROM_SeekAudioMSF(dev
, fd
, lpInBuffer
);
3002 case IOCTL_CDROM_STOP_AUDIO
:
3004 CDROM_ClearCacheEntry(dev
); /* Maybe intention is to change media */
3005 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0 || lpOutBuffer
!= NULL
|| nOutBufferSize
!= 0)
3006 status
= STATUS_INVALID_PARAMETER
;
3007 else status
= CDROM_StopAudio(fd
);
3009 case IOCTL_CDROM_GET_VOLUME
:
3010 sz
= sizeof(VOLUME_CONTROL
);
3011 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
3012 else if (nOutBufferSize
< sz
) status
= STATUS_BUFFER_TOO_SMALL
;
3013 else status
= CDROM_GetVolume(fd
, lpOutBuffer
);
3015 case IOCTL_CDROM_SET_VOLUME
:
3017 CDROM_ClearCacheEntry(dev
);
3018 if (lpInBuffer
== NULL
|| nInBufferSize
< sizeof(VOLUME_CONTROL
) || lpOutBuffer
!= NULL
)
3019 status
= STATUS_INVALID_PARAMETER
;
3020 else status
= CDROM_SetVolume(fd
, lpInBuffer
);
3022 case IOCTL_CDROM_RAW_READ
:
3024 if (nInBufferSize
< sizeof(RAW_READ_INFO
)) status
= STATUS_INVALID_PARAMETER
;
3025 else if (lpOutBuffer
== NULL
) status
= STATUS_BUFFER_TOO_SMALL
;
3026 else status
= CDROM_RawRead(fd
, lpInBuffer
, lpOutBuffer
,
3027 nOutBufferSize
, &sz
);
3029 case IOCTL_SCSI_GET_ADDRESS
:
3030 sz
= sizeof(SCSI_ADDRESS
);
3031 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
3032 else if (nOutBufferSize
< sz
) status
= STATUS_BUFFER_TOO_SMALL
;
3033 else status
= CDROM_GetAddress(fd
, lpOutBuffer
);
3035 case IOCTL_SCSI_PASS_THROUGH_DIRECT
:
3036 sz
= sizeof(SCSI_PASS_THROUGH_DIRECT
);
3037 if (lpOutBuffer
== NULL
) status
= STATUS_INVALID_PARAMETER
;
3038 else if (nOutBufferSize
< sizeof(SCSI_PASS_THROUGH_DIRECT
)) status
= STATUS_BUFFER_TOO_SMALL
;
3039 else status
= CDROM_ScsiPassThroughDirect(fd
, lpOutBuffer
);
3041 case IOCTL_SCSI_PASS_THROUGH
:
3042 sz
= sizeof(SCSI_PASS_THROUGH
);
3043 if (lpOutBuffer
== NULL
) status
= STATUS_INVALID_PARAMETER
;
3044 else if (nOutBufferSize
< sizeof(SCSI_PASS_THROUGH
)) status
= STATUS_BUFFER_TOO_SMALL
;
3045 else status
= CDROM_ScsiPassThrough(fd
, lpOutBuffer
);
3047 case IOCTL_SCSI_GET_CAPABILITIES
:
3048 sz
= sizeof(IO_SCSI_CAPABILITIES
);
3049 if (lpOutBuffer
== NULL
) status
= STATUS_INVALID_PARAMETER
;
3050 else if (nOutBufferSize
< sizeof(IO_SCSI_CAPABILITIES
)) status
= STATUS_BUFFER_TOO_SMALL
;
3051 else status
= CDROM_ScsiGetCaps(fd
, lpOutBuffer
);
3053 case IOCTL_DVD_START_SESSION
:
3054 sz
= sizeof(DVD_SESSION_ID
);
3055 if (lpOutBuffer
== NULL
) status
= STATUS_INVALID_PARAMETER
;
3056 else if (nOutBufferSize
< sz
) status
= STATUS_BUFFER_TOO_SMALL
;
3059 TRACE("before in 0x%08x out 0x%08x\n",(lpInBuffer
)?*(PDVD_SESSION_ID
)lpInBuffer
:0,
3060 *(PDVD_SESSION_ID
)lpOutBuffer
);
3061 status
= DVD_StartSession(fd
, lpInBuffer
, lpOutBuffer
);
3062 TRACE("before in 0x%08x out 0x%08x\n",(lpInBuffer
)?*(PDVD_SESSION_ID
)lpInBuffer
:0,
3063 *(PDVD_SESSION_ID
)lpOutBuffer
);
3066 case IOCTL_DVD_END_SESSION
:
3067 sz
= sizeof(DVD_SESSION_ID
);
3068 if ((lpInBuffer
== NULL
) || (nInBufferSize
< sz
))status
= STATUS_INVALID_PARAMETER
;
3069 else status
= DVD_EndSession(fd
, lpInBuffer
);
3071 case IOCTL_DVD_SEND_KEY
:
3074 (((PDVD_COPY_PROTECT_KEY
)lpInBuffer
)->KeyLength
!= nInBufferSize
))
3075 status
= STATUS_INVALID_PARAMETER
;
3078 TRACE("doing DVD_SendKey\n");
3079 status
= DVD_SendKey(fd
, lpInBuffer
);
3082 case IOCTL_DVD_READ_KEY
:
3084 (((PDVD_COPY_PROTECT_KEY
)lpInBuffer
)->KeyLength
!= nInBufferSize
))
3085 status
= STATUS_INVALID_PARAMETER
;
3086 else if (lpInBuffer
!=lpOutBuffer
) status
= STATUS_BUFFER_TOO_SMALL
;
3089 TRACE("doing DVD_READ_KEY\n");
3090 sz
= ((PDVD_COPY_PROTECT_KEY
)lpInBuffer
)->KeyLength
;
3091 status
= DVD_ReadKey(fd
, lpInBuffer
);
3094 case IOCTL_DVD_GET_REGION
:
3095 sz
= sizeof(DVD_REGION
);
3096 if (lpInBuffer
!= NULL
|| nInBufferSize
!= 0) status
= STATUS_INVALID_PARAMETER
;
3097 else if (nOutBufferSize
< sz
) status
= STATUS_BUFFER_TOO_SMALL
;
3098 TRACE("doing DVD_Get_REGION\n");
3099 status
= DVD_GetRegion(fd
, lpOutBuffer
);
3101 case IOCTL_DVD_READ_STRUCTURE
:
3102 sz
= sizeof(DVD_LAYER_DESCRIPTOR
);
3103 if (lpInBuffer
== NULL
|| nInBufferSize
!= sizeof(DVD_READ_STRUCTURE
)) status
= STATUS_INVALID_PARAMETER
;
3104 else if (nOutBufferSize
< sz
) status
= STATUS_BUFFER_TOO_SMALL
;
3107 TRACE("doing DVD_READ_STRUCTURE\n");
3108 status
= DVD_ReadStructure(fd
, lpInBuffer
, lpOutBuffer
);
3112 case IOCTL_SCSI_GET_INQUIRY_DATA
:
3114 status
= GetInquiryData(fd
, lpOutBuffer
, nOutBufferSize
);
3118 if (needs_close
) close( fd
);
3119 return STATUS_NOT_SUPPORTED
;
3121 if (needs_close
) close( fd
);
3123 piosb
->u
.Status
= status
;
3124 piosb
->Information
= sz
;
3125 if (hEvent
) NtSetEvent(hEvent
, NULL
);