1 /*****************************************************************************
2 * ioctl.c: DVD ioctl replacement function
3 *****************************************************************************
4 * Copyright (C) 1999-2001 VideoLAN
5 * $Id: ioctl.c,v 1.14 2001/10/18 23:13:46 ej Exp $
7 * Authors: Markus Kuespert <ltlBeBoy@beosmail.com>
8 * Samuel Hocevar <sam@zoy.org>
9 * Jon Lech Johansen <jon-vl@nanocrew.net>
10 * HÃ¥kan Hjort <d95hjort@dtek.chalmers.se>
11 * Eugenio Jarosiewicz <ej0@cise.ufl.edu>
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
26 *****************************************************************************/
28 /*****************************************************************************
30 *****************************************************************************/
35 #include <string.h> /* memcpy(), memset() */
36 #include <sys/types.h>
40 # include <winioctl.h>
42 # include <netinet/in.h>
43 # include <sys/ioctl.h>
46 #ifdef DVD_STRUCT_IN_SYS_CDIO_H
47 # include <sys/cdio.h>
49 #ifdef DVD_STRUCT_IN_SYS_DVDIO_H
50 # include <sys/dvdio.h>
52 #ifdef DVD_STRUCT_IN_LINUX_CDROM_H
53 # include <linux/cdrom.h>
55 #ifdef DVD_STRUCT_IN_DVD_H
58 #ifdef DVD_STRUCT_IN_BSDI_DVDIOCTL_DVD_H
59 # include <BSDI_dvdioctl/dvd.h>
68 # include <sys/scsi/scsi_types.h>
69 # include <sys/scsi/impl/uscsi.h>
76 # include <IOKit/storage/IODVDMediaBSDClient.h>
77 /* # include "DVDioctl/DVDioctl.h" */
83 /*****************************************************************************
84 * Local prototypes, BeOS specific
85 *****************************************************************************/
86 #if defined( SYS_BEOS )
87 static void BeInitRDC ( raw_device_command *, int );
90 /*****************************************************************************
91 * Local prototypes, Solaris specific
92 *****************************************************************************/
93 #if defined( SOLARIS_USCSI )
94 static void SolarisInitUSCSI( struct uscsi_cmd *p_sc, int i_type );
97 /*****************************************************************************
98 * Local prototypes, win32 (aspi) specific
99 *****************************************************************************/
101 static void WinInitSSC ( struct SRB_ExecSCSICmd *, int );
102 static int WinSendSSC ( int, struct SRB_ExecSCSICmd * );
105 /*****************************************************************************
106 * ioctl_ReadCopyright: check whether the disc is encrypted or not
107 *****************************************************************************/
108 int ioctl_ReadCopyright( int i_fd, int i_layer, int *pi_copyright )
112 #if defined( HAVE_LINUX_DVD_STRUCT )
115 dvd.type = DVD_STRUCT_COPYRIGHT;
116 dvd.copyright.layer_num = i_layer;
118 i_ret = ioctl( i_fd, DVD_READ_STRUCT, &dvd );
120 *pi_copyright = dvd.copyright.cpst;
122 #elif defined( HAVE_BSD_DVD_STRUCT )
123 struct dvd_struct dvd;
125 dvd.format = DVD_STRUCT_COPYRIGHT;
126 dvd.layer_num = i_layer;
128 i_ret = ioctl( i_fd, DVDIOCREADSTRUCTURE, &dvd );
130 *pi_copyright = dvd.cpst;
132 #elif defined( SYS_BEOS )
133 INIT_RDC( GPCMD_READ_DVD_STRUCTURE, 8 );
135 rdc.command[ 6 ] = i_layer;
136 rdc.command[ 7 ] = DVD_STRUCT_COPYRIGHT;
138 i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
140 *pi_copyright = p_buffer[ 4 ];
142 #elif defined( SOLARIS_USCSI )
143 INIT_USCSI( GPCMD_READ_DVD_STRUCTURE, 8 );
145 rs_cdb.cdb_opaque[ 6 ] = i_layer;
146 rs_cdb.cdb_opaque[ 7 ] = DVD_STRUCT_COPYRIGHT;
148 i_ret = ioctl(i_fd, USCSICMD, &sc);
150 if( i_ret < 0 || sc.uscsi_status ) {
154 *pi_copyright = p_buffer[ 4 ];
155 /* s->copyright.rmi = p_buffer[ 5 ]; */
157 #elif defined( SYS_DARWIN )
158 dk_dvd_read_structure_t dvd;
159 DVDCopyrightInfo dvdcpi;
161 memset(&dvd, 0, sizeof(dvd));
162 memset(&dvdcpi, 0, sizeof(dvdcpi));
164 dvd.buffer = &dvdcpi;
165 dvd.bufferLength = sizeof(dvdcpi);
166 dvd.format = kDVDStructureFormatCopyrightInfo;
169 /* dvdcpi.dataLength[0] = 0x00; */ /* dataLength[0] is already memset to 0 */
170 /* dvdcpi.dataLength[1] = 0x06; */
172 i_ret = ioctl( i_fd, DKIOCDVDREADSTRUCTURE, &dvd );
174 *pi_copyright = dvdcpi.copyrightProtectionSystemType;
176 #elif defined( WIN32 )
177 if( WIN2K ) /* NT/Win2000/Whistler */
181 SCSI_PASS_THROUGH_DIRECT sptd;
183 memset( &sptd, 0, sizeof( sptd ) );
184 memset( &p_buffer, 0, sizeof( p_buffer ) );
186 /* When using IOCTL_DVD_READ_STRUCTURE and
187 DVD_COPYRIGHT_DESCRIPTOR, CopyrightProtectionType
188 is always 6. So we send a raw scsi command instead. */
190 sptd.Length = sizeof( SCSI_PASS_THROUGH_DIRECT );
192 sptd.DataIn = SCSI_IOCTL_DATA_IN;
193 sptd.DataTransferLength = 8;
194 sptd.TimeOutValue = 2;
195 sptd.DataBuffer = p_buffer;
196 sptd.Cdb[ 0 ] = GPCMD_READ_DVD_STRUCTURE;
197 sptd.Cdb[ 6 ] = i_layer;
198 sptd.Cdb[ 7 ] = DVD_STRUCT_COPYRIGHT;
199 sptd.Cdb[ 8 ] = (8 >> 8) & 0xff;
200 sptd.Cdb[ 9 ] = 8 & 0xff;
202 i_ret = DeviceIoControl( (HANDLE) i_fd,
203 IOCTL_SCSI_PASS_THROUGH_DIRECT,
204 &sptd, sizeof( SCSI_PASS_THROUGH_DIRECT ),
205 &sptd, sizeof( SCSI_PASS_THROUGH_DIRECT ),
206 &tmp, NULL ) ? 0 : -1;
208 *pi_copyright = p_buffer[4];
212 INIT_SSC( GPCMD_READ_DVD_STRUCTURE, 8 );
214 ssc.CDBByte[ 6 ] = i_layer;
215 ssc.CDBByte[ 7 ] = DVD_STRUCT_COPYRIGHT;
217 i_ret = WinSendSSC( i_fd, &ssc );
219 *pi_copyright = p_buffer[ 4 ];
222 #elif defined( __QNXNTO__ )
224 QNX RTOS currently doesn't have a CAM
225 interface (they're working on it though).
226 Assume DVD is not encrypted.
233 /* DVD ioctls unavailable - do as if the ioctl failed */
240 /*****************************************************************************
241 * ioctl_ReadDiscKey: get the disc key
242 *****************************************************************************/
243 int ioctl_ReadDiscKey( int i_fd, int *pi_agid, u8 *p_key )
247 #if defined( HAVE_LINUX_DVD_STRUCT )
250 dvd.type = DVD_STRUCT_DISCKEY;
251 dvd.disckey.agid = *pi_agid;
252 memset( dvd.disckey.value, 0, 2048 );
254 i_ret = ioctl( i_fd, DVD_READ_STRUCT, &dvd );
261 memcpy( p_key, dvd.disckey.value, 2048 );
263 #elif defined( HAVE_BSD_DVD_STRUCT )
264 struct dvd_struct dvd;
266 dvd.format = DVD_STRUCT_DISCKEY;
268 memset( dvd.data, 0, 2048 );
270 i_ret = ioctl( i_fd, DVDIOCREADSTRUCTURE, &dvd );
277 memcpy( p_key, dvd.data, 2048 );
279 #elif defined( SYS_BEOS )
280 INIT_RDC( GPCMD_READ_DVD_STRUCTURE, 2048 + 4 );
282 rdc.command[ 7 ] = DVD_STRUCT_DISCKEY;
283 rdc.command[ 10 ] = *pi_agid << 6;
285 i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
292 memcpy( p_key, p_buffer + 4, 2048 );
294 #elif defined( SOLARIS_USCSI )
295 INIT_USCSI( GPCMD_READ_DVD_STRUCTURE, 2048 + 4 );
297 rs_cdb.cdb_opaque[ 7 ] = DVD_STRUCT_DISCKEY;
298 rs_cdb.cdb_opaque[ 10 ] = *pi_agid << 6;
300 i_ret = ioctl( i_fd, USCSICMD, &sc );
302 if( i_ret < 0 || sc.uscsi_status )
308 memcpy( p_key, p_buffer + 4, 2048 );
310 #elif defined( SYS_DARWIN )
311 dk_dvd_read_structure_t dvd;
312 DVDDiscKeyInfo dvddki;
314 memset(&dvd, 0, sizeof(dvd));
315 memset(&dvddki, 0, sizeof(dvddki));
317 dvd.buffer = &dvddki;
318 dvd.bufferLength = sizeof(dvddki);
319 dvd.format = kDVDStructureFormatDiscKeyInfo;
320 dvd.grantID = *pi_agid;
322 /* 2048+2 ; maybe we should do bit shifts to value of (sizeof(dvddki)-2) */
323 dvddki.dataLength[0] = 0x04;
324 dvddki.dataLength[1] = 0x02;
326 i_ret = ioctl( i_fd, DKIOCDVDREADSTRUCTURE, &dvd );
328 memcpy( p_key, dvddki.discKeyStructures, sizeof(dvddki.discKeyStructures) );
330 #elif defined( WIN32 )
331 if( WIN2K ) /* NT/Win2000/Whistler */
334 u8 buffer[DVD_DISK_KEY_LENGTH];
335 PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
337 memset( &buffer, 0, sizeof( buffer ) );
339 key->KeyLength = DVD_DISK_KEY_LENGTH;
340 key->SessionId = *pi_agid;
341 key->KeyType = DvdDiskKey;
344 i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key,
345 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
352 memcpy( p_key, key->KeyData, 2048 );
356 INIT_SSC( GPCMD_READ_DVD_STRUCTURE, 2048 + 4 );
358 ssc.CDBByte[ 7 ] = DVD_STRUCT_DISCKEY;
359 ssc.CDBByte[ 10 ] = *pi_agid << 6;
361 i_ret = WinSendSSC( i_fd, &ssc );
368 memcpy( p_key, p_buffer + 4, 2048 );
372 /* DVD ioctls unavailable - do as if the ioctl failed */
379 /*****************************************************************************
380 * ioctl_ReadTitleKey: get the title key
381 *****************************************************************************/
382 int ioctl_ReadTitleKey( int i_fd, int *pi_agid, int i_pos, u8 *p_key )
386 #if defined( HAVE_LINUX_DVD_STRUCT )
389 memset( &dvd_ai, 0, sizeof(dvd_ai) );
390 dvd_ai.type = DVD_LU_SEND_TITLE_KEY;
391 dvd_ai.lstk.agid = *pi_agid;
392 dvd_ai.lstk.lba = i_pos;
394 i_ret = ioctl( i_fd, DVD_AUTH, &dvd_ai );
401 memcpy( p_key, dvd_ai.lstk.title_key, 5 );
403 #elif defined( HAVE_BSD_DVD_STRUCT )
406 #elif defined( SYS_BEOS )
409 #elif defined( SOLARIS_USCSI )
412 #elif defined( SYS_DARWIN )
413 dk_dvd_report_key_t dvd;
414 DVDTitleKeyInfo dvdtki;
416 memset(&dvd, 0, sizeof(dvd));
417 memset(&dvdtki, 0, sizeof(dvdtki));
419 dvd.buffer = &dvdtki;
420 dvd.bufferLength = sizeof(dvdtki);
421 dvd.format = kDVDKeyFormatTitleKey;
422 dvd.grantID = *pi_agid;
423 dvd.keyClass = kDVDKeyClassCSS_CPPM_CPRM; /* or this - this is memset 0x00 anyways */
425 /* dvdtki.dataLength[0] = 0x00; */ /* dataLength[0] is already memset to 0 */
426 dvdtki.dataLength[1] = 0x0a;
428 /* What are DVDTitleKeyInfo.{CP_MOD,CGMS,CP_SEC,CPM} and do they need to be set? */
430 i_ret = ioctl( i_fd, DKIOCDVDREPORTKEY, &dvd );
432 memcpy( p_key, dvdtki.titleKeyValue, sizeof(dvdtki.titleKeyValue) );
434 #elif defined( WIN32 )
447 /*****************************************************************************
448 * ioctl_ReportAgid: get AGID from the drive
449 *****************************************************************************/
450 int ioctl_ReportAgid( int i_fd, int *pi_agid )
454 #if defined( HAVE_LINUX_DVD_STRUCT )
455 dvd_authinfo auth_info;
457 auth_info.type = DVD_LU_SEND_AGID;
458 auth_info.lsa.agid = *pi_agid;
460 i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
462 *pi_agid = auth_info.lsa.agid;
464 #elif defined( HAVE_BSD_DVD_STRUCT )
465 struct dvd_authinfo auth_info;
467 auth_info.format = DVD_REPORT_AGID;
468 auth_info.agid = *pi_agid;
470 i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
472 *pi_agid = auth_info.agid;
474 #elif defined( SYS_BEOS )
475 INIT_RDC( GPCMD_REPORT_KEY, 8 );
477 rdc.command[ 10 ] = DVD_REPORT_AGID | (*pi_agid << 6);
479 i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
481 *pi_agid = p_buffer[ 7 ] >> 6;
483 #elif defined( SOLARIS_USCSI )
484 INIT_USCSI( GPCMD_REPORT_KEY, 8 );
486 rs_cdb.cdb_opaque[ 10 ] = DVD_REPORT_AGID | (*pi_agid << 6);
488 i_ret = ioctl( i_fd, USCSICMD, &sc );
490 if( i_ret < 0 || sc.uscsi_status )
495 *pi_agid = p_buffer[ 7 ] >> 6;
497 #elif defined( SYS_DARWIN )
498 dk_dvd_report_key_t dvd;
499 DVDAuthenticationGrantIDInfo dvdagid;
501 memset(&dvd, 0, sizeof(dvd));
502 memset(&dvdagid, 0, sizeof(dvdagid));
504 dvd.buffer = &dvdagid;
505 dvd.bufferLength = sizeof(dvdagid);
506 dvd.format = kDVDKeyFormatAGID_CSS;
507 dvd.grantID = *pi_agid;
508 dvdagid.grantID = *pi_agid; /* do we need this? */
509 dvd.keyClass = kDVDKeyClassCSS_CPPM_CPRM; /* or this - this is memset 0x00 anyways */
511 /* dvdagid.dataLength[0] = 0x00; */ /* dataLength[0] is already memset to 0 */
512 /* dvdagid.dataLength[1] = 0x06; */
514 i_ret = ioctl( i_fd, DKIOCDVDREPORTKEY, &dvd );
516 *pi_agid = dvdagid.grantID;
518 #elif defined( WIN32 )
519 if( WIN2K ) /* NT/Win2000/Whistler */
524 i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_START_SESSION,
525 &tmp, 4, &id, sizeof( id ), &tmp, NULL ) ? 0 : -1;
531 INIT_SSC( GPCMD_REPORT_KEY, 8 );
533 ssc.CDBByte[ 10 ] = DVD_REPORT_AGID | (*pi_agid << 6);
535 i_ret = WinSendSSC( i_fd, &ssc );
537 *pi_agid = p_buffer[ 7 ] >> 6;
541 /* DVD ioctls unavailable - do as if the ioctl failed */
548 /*****************************************************************************
549 * ioctl_ReportChallenge: get challenge from the drive
550 *****************************************************************************/
551 int ioctl_ReportChallenge( int i_fd, int *pi_agid, u8 *p_challenge )
555 #if defined( HAVE_LINUX_DVD_STRUCT )
556 dvd_authinfo auth_info;
558 auth_info.type = DVD_LU_SEND_CHALLENGE;
559 auth_info.lsc.agid = *pi_agid;
561 i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
563 memcpy( p_challenge, auth_info.lsc.chal, sizeof(dvd_challenge) );
565 #elif defined( HAVE_BSD_DVD_STRUCT )
566 struct dvd_authinfo auth_info;
568 auth_info.format = DVD_REPORT_CHALLENGE;
569 auth_info.agid = *pi_agid;
571 i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
573 memcpy( p_challenge, auth_info.keychal, 10 );
575 #elif defined( SYS_BEOS )
576 INIT_RDC( GPCMD_REPORT_KEY, 16 );
578 rdc.command[ 10 ] = DVD_REPORT_CHALLENGE | (*pi_agid << 6);
580 i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
582 memcpy( p_challenge, p_buffer + 4, 12 );
584 #elif defined( SOLARIS_USCSI )
585 INIT_USCSI( GPCMD_REPORT_KEY, 16 );
587 rs_cdb.cdb_opaque[ 10 ] = DVD_REPORT_CHALLENGE | (*pi_agid << 6);
589 i_ret = ioctl( i_fd, USCSICMD, &sc );
591 if( i_ret < 0 || sc.uscsi_status )
596 memcpy( p_challenge, p_buffer + 4, 12 );
598 #elif defined( SYS_DARWIN )
599 dk_dvd_report_key_t dvd;
600 DVDChallengeKeyInfo dvdcki;
602 memset(&dvd, 0, sizeof(dvd));
603 memset(&dvdcki, 0, sizeof(dvdcki));
605 dvd.buffer = &dvdcki;
606 dvd.bufferLength = sizeof(dvdcki);
607 dvd.format = kDVDKeyFormatChallengeKey;
608 dvd.grantID = *pi_agid;
610 /* dvdcki.dataLength[0] = 0x00; */ /* dataLength[0] is already memset to 0 */
611 dvdcki.dataLength[1] = 0x0e;
613 i_ret = ioctl( i_fd, DKIOCDVDREPORTKEY, &dvd );
615 memcpy( p_challenge, dvdcki.challengeKeyValue, sizeof(dvdcki.challengeKeyValue) );
617 #elif defined( WIN32 )
618 if( WIN2K ) /* NT/Win2000/Whistler */
621 u8 buffer[DVD_CHALLENGE_KEY_LENGTH];
622 PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
624 memset( &buffer, 0, sizeof( buffer ) );
626 key->KeyLength = DVD_CHALLENGE_KEY_LENGTH;
627 key->SessionId = *pi_agid;
628 key->KeyType = DvdChallengeKey;
631 i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key,
632 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
639 memcpy( p_challenge, key->KeyData, 10 );
643 INIT_SSC( GPCMD_REPORT_KEY, 16 );
645 ssc.CDBByte[ 10 ] = DVD_REPORT_CHALLENGE | (*pi_agid << 6);
647 i_ret = WinSendSSC( i_fd, &ssc );
649 memcpy( p_challenge, p_buffer + 4, 12 );
653 /* DVD ioctls unavailable - do as if the ioctl failed */
660 /*****************************************************************************
661 * ioctl_ReportASF: get ASF from the drive
662 *****************************************************************************/
663 int ioctl_ReportASF( int i_fd, int *pi_agid, int *pi_asf )
667 #if defined( HAVE_LINUX_DVD_STRUCT )
668 dvd_authinfo auth_info;
670 auth_info.type = DVD_LU_SEND_ASF;
671 auth_info.lsasf.agid = *pi_agid;
672 auth_info.lsasf.asf = *pi_asf;
674 i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
676 *pi_asf = auth_info.lsasf.asf;
678 #elif defined( HAVE_BSD_DVD_STRUCT )
679 struct dvd_authinfo auth_info;
681 auth_info.format = DVD_REPORT_ASF;
682 auth_info.agid = *pi_agid;
683 auth_info.asf = *pi_asf;
685 i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
687 *pi_asf = auth_info.asf;
689 #elif defined( SYS_BEOS )
690 INIT_RDC( GPCMD_REPORT_KEY, 8 );
692 rdc.command[ 10 ] = DVD_REPORT_ASF | (*pi_agid << 6);
694 i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
696 *pi_asf = p_buffer[ 7 ] & 1;
698 #elif defined( SOLARIS_USCSI )
699 INIT_USCSI( GPCMD_REPORT_KEY, 8 );
701 rs_cdb.cdb_opaque[ 10 ] = DVD_REPORT_ASF | (*pi_agid << 6);
703 i_ret = ioctl( i_fd, USCSICMD, &sc );
705 if( i_ret < 0 || sc.uscsi_status )
710 *pi_asf = p_buffer[ 7 ] & 1;
712 #elif defined( SYS_DARWIN )
713 dk_dvd_report_key_t dvd;
714 DVDAuthenticationSuccessFlagInfo dvdasfi;
716 memset(&dvd, 0, sizeof(dvd));
717 memset(&dvdasfi, 0, sizeof(dvdasfi));
719 dvd.buffer = &dvdasfi;
720 dvd.bufferLength = sizeof(dvdasfi);
721 dvd.format = kDVDKeyFormatASF;
722 dvd.grantID = *pi_agid;
723 dvdasfi.successFlag = *pi_asf;
725 /* dvdasfi.dataLength[0] = 0x00; */ /* dataLength[0] is already memset to 0 */
726 dvdasfi.dataLength[1] = 0x06;
728 i_ret = ioctl( i_fd, DKIOCDVDREPORTKEY, &dvd );
730 *pi_asf = dvdasfi.successFlag;
732 #elif defined( WIN32 )
733 if( WIN2K ) /* NT/Win2000/Whistler */
736 u8 buffer[DVD_ASF_LENGTH];
737 PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
739 memset( &buffer, 0, sizeof( buffer ) );
741 key->KeyLength = DVD_ASF_LENGTH;
742 key->SessionId = *pi_agid;
743 key->KeyType = DvdAsf;
746 ((PDVD_ASF)key->KeyData)->SuccessFlag = *pi_asf;
748 i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key,
749 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
756 *pi_asf = ((PDVD_ASF)key->KeyData)->SuccessFlag;
760 INIT_SSC( GPCMD_REPORT_KEY, 8 );
762 ssc.CDBByte[ 10 ] = DVD_REPORT_ASF | (*pi_agid << 6);
764 i_ret = WinSendSSC( i_fd, &ssc );
766 *pi_asf = p_buffer[ 7 ] & 1;
770 /* DVD ioctls unavailable - do as if the ioctl failed */
777 /*****************************************************************************
778 * ioctl_ReportKey1: get the first key from the drive
779 *****************************************************************************/
780 int ioctl_ReportKey1( int i_fd, int *pi_agid, u8 *p_key )
784 #if defined( HAVE_LINUX_DVD_STRUCT )
785 dvd_authinfo auth_info;
787 auth_info.type = DVD_LU_SEND_KEY1;
788 auth_info.lsk.agid = *pi_agid;
790 i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
792 memcpy( p_key, auth_info.lsk.key, sizeof(dvd_key) );
794 #elif defined( HAVE_BSD_DVD_STRUCT )
795 struct dvd_authinfo auth_info;
797 auth_info.format = DVD_REPORT_KEY1;
798 auth_info.agid = *pi_agid;
800 i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
802 memcpy( p_key, auth_info.keychal, 8 );
804 #elif defined( SYS_BEOS )
805 INIT_RDC( GPCMD_REPORT_KEY, 12 );
807 rdc.command[ 10 ] = DVD_REPORT_KEY1 | (*pi_agid << 6);
809 i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
811 memcpy( p_key, p_buffer + 4, 8 );
813 #elif defined( SOLARIS_USCSI )
814 INIT_USCSI( GPCMD_REPORT_KEY, 12 );
816 rs_cdb.cdb_opaque[ 10 ] = DVD_REPORT_KEY1 | (*pi_agid << 6);
818 i_ret = ioctl( i_fd, USCSICMD, &sc );
820 if( i_ret < 0 || sc.uscsi_status )
825 memcpy( p_key, p_buffer + 4, 8 );;
827 #elif defined( SYS_DARWIN )
828 dk_dvd_report_key_t dvd;
831 memset(&dvd, 0, sizeof(dvd));
832 memset(&dvdk1i, 0, sizeof(dvdk1i));
834 dvd.buffer = &dvdk1i;
835 dvd.bufferLength = sizeof(dvdk1i);
836 dvd.format = kDVDKeyFormatKey1;
837 dvd.grantID = *pi_agid;
839 /* dvdk1i.dataLength[0] = 0x00; */ /* dataLength[0] is already memset to 0 */
840 dvdk1i.dataLength[1] = 0x0a;
842 i_ret = ioctl( i_fd, DKIOCDVDREPORTKEY, &dvd );
844 memcpy( p_key, dvdk1i.key1Value, sizeof(dvdk1i.key1Value) );
846 #elif defined( WIN32 )
847 if( WIN2K ) /* NT/Win2000/Whistler */
850 u8 buffer[DVD_BUS_KEY_LENGTH];
851 PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
853 memset( &buffer, 0, sizeof( buffer ) );
855 key->KeyLength = DVD_BUS_KEY_LENGTH;
856 key->SessionId = *pi_agid;
857 key->KeyType = DvdBusKey1;
860 i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key,
861 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
863 memcpy( p_key, key->KeyData, 8 );
867 INIT_SSC( GPCMD_REPORT_KEY, 12 );
869 ssc.CDBByte[ 10 ] = DVD_REPORT_KEY1 | (*pi_agid << 6);
871 i_ret = WinSendSSC( i_fd, &ssc );
873 memcpy( p_key, p_buffer + 4, 8 );
877 /* DVD ioctls unavailable - do as if the ioctl failed */
884 /*****************************************************************************
885 * ioctl_InvalidateAgid: invalidate the current AGID
886 *****************************************************************************/
887 int ioctl_InvalidateAgid( int i_fd, int *pi_agid )
891 #if defined( HAVE_LINUX_DVD_STRUCT )
892 dvd_authinfo auth_info;
894 auth_info.type = DVD_INVALIDATE_AGID;
895 auth_info.lsa.agid = *pi_agid;
897 i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
899 *pi_agid = auth_info.lsa.agid;
901 #elif defined( HAVE_BSD_DVD_STRUCT )
902 struct dvd_authinfo auth_info;
904 auth_info.format = DVD_INVALIDATE_AGID;
905 auth_info.agid = *pi_agid;
907 i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
909 *pi_agid = auth_info.agid;
911 #elif defined( SYS_BEOS )
912 INIT_RDC( GPCMD_REPORT_KEY, 0 );
914 rdc.command[ 10 ] = DVD_INVALIDATE_AGID | (*pi_agid << 6);
916 i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
918 #elif defined( SOLARIS_USCSI )
919 INIT_USCSI( GPCMD_REPORT_KEY, 0 );
921 rs_cdb.cdb_opaque[ 10 ] = DVD_INVALIDATE_AGID | (*pi_agid << 6);
923 i_ret = ioctl( i_fd, USCSICMD, &sc );
925 if( i_ret < 0 || sc.uscsi_status )
930 #elif defined( SYS_DARWIN )
931 dk_dvd_send_key_t dvd;
932 DVDAuthenticationGrantIDInfo dvdagid;
934 memset(&dvd, 0, sizeof(dvd));
935 memset(&dvdagid, 0, sizeof(dvdagid));
937 dvd.buffer = &dvdagid;
938 dvd.bufferLength = sizeof(dvdagid);
939 dvd.format = kDVDKeyFormatAGID_Invalidate;
940 dvd.grantID = *pi_agid;
941 dvdagid.grantID = *pi_agid; /* we need this? */
943 /* dvdagid.dataLength[0] = 0x00; */ /* dataLength[0] is already memset to 0 */
944 /* dvdagid.dataLength[1] = 0x06; */
946 i_ret = ioctl( i_fd, DKIOCDVDSENDKEY, &dvd );
948 *pi_agid = dvdagid.grantID;
950 #elif defined( WIN32 )
951 if( WIN2K ) /* NT/Win2000/Whistler */
955 i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_END_SESSION,
956 pi_agid, sizeof( *pi_agid ), NULL, 0, &tmp, NULL ) ? 0 : -1;
960 #if defined( __MINGW32__ )
961 INIT_SSC( GPCMD_REPORT_KEY, 0 );
963 INIT_SSC( GPCMD_REPORT_KEY, 1 );
966 ssc.CDBByte[ 8 ] = 0;
967 ssc.CDBByte[ 9 ] = 0;
970 ssc.CDBByte[ 10 ] = DVD_INVALIDATE_AGID | (*pi_agid << 6);
972 i_ret = WinSendSSC( i_fd, &ssc );
976 /* DVD ioctls unavailable - do as if the ioctl failed */
983 /*****************************************************************************
984 * ioctl_SendChallenge: send challenge to the drive
985 *****************************************************************************/
986 int ioctl_SendChallenge( int i_fd, int *pi_agid, u8 *p_challenge )
990 #if defined( HAVE_LINUX_DVD_STRUCT )
991 dvd_authinfo auth_info;
993 auth_info.type = DVD_HOST_SEND_CHALLENGE;
994 auth_info.hsc.agid = *pi_agid;
996 memcpy( auth_info.hsc.chal, p_challenge, sizeof(dvd_challenge) );
998 return ioctl( i_fd, DVD_AUTH, &auth_info );
1000 #elif defined( HAVE_BSD_DVD_STRUCT )
1001 struct dvd_authinfo auth_info;
1003 auth_info.format = DVD_SEND_CHALLENGE;
1004 auth_info.agid = *pi_agid;
1006 memcpy( auth_info.keychal, p_challenge, 12 );
1008 return ioctl( i_fd, DVDIOCSENDKEY, &auth_info );
1010 #elif defined( SYS_BEOS )
1011 INIT_RDC( GPCMD_SEND_KEY, 16 );
1013 rdc.command[ 10 ] = DVD_SEND_CHALLENGE | (*pi_agid << 6);
1015 p_buffer[ 1 ] = 0xe;
1016 memcpy( p_buffer + 4, p_challenge, 12 );
1018 return ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
1020 #elif defined( SOLARIS_USCSI )
1021 INIT_USCSI( GPCMD_SEND_KEY, 16 );
1023 rs_cdb.cdb_opaque[ 10 ] = DVD_SEND_CHALLENGE | (*pi_agid << 6);
1025 p_buffer[ 1 ] = 0xe;
1026 memcpy( p_buffer + 4, p_challenge, 12 );
1028 if( ioctl( i_fd, USCSICMD, &sc ) < 0 || sc.uscsi_status )
1035 #elif defined( SYS_DARWIN )
1036 dk_dvd_send_key_t dvd;
1037 DVDChallengeKeyInfo dvdcki;
1039 memset(&dvd, 0, sizeof(dvd));
1040 memset(&dvdcki, 0, sizeof(dvdcki));
1042 dvd.buffer = &dvdcki;
1043 dvd.bufferLength = sizeof(dvdcki);
1044 dvd.format = kDVDKeyFormatChallengeKey;
1045 dvd.grantID = *pi_agid;
1047 /* dvdcki.dataLength[0] = 0x00; */ /* dataLength[0] is already memset to 0 */
1048 dvdcki.dataLength[1] = 0x0e;
1050 memcpy( dvdcki.challengeKeyValue, p_challenge, sizeof(dvdcki.challengeKeyValue) );
1052 i_ret = ioctl( i_fd, DKIOCDVDSENDKEY, &dvd );
1054 #elif defined( WIN32 )
1055 if( WIN2K ) /* NT/Win2000/Whistler */
1058 u8 buffer[DVD_CHALLENGE_KEY_LENGTH];
1059 PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
1061 memset( &buffer, 0, sizeof( buffer ) );
1063 key->KeyLength = DVD_CHALLENGE_KEY_LENGTH;
1064 key->SessionId = *pi_agid;
1065 key->KeyType = DvdChallengeKey;
1068 memcpy( key->KeyData, p_challenge, 10 );
1070 return DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_SEND_KEY, key,
1071 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
1075 INIT_SSC( GPCMD_SEND_KEY, 16 );
1077 ssc.CDBByte[ 10 ] = DVD_SEND_CHALLENGE | (*pi_agid << 6);
1079 p_buffer[ 1 ] = 0xe;
1080 memcpy( p_buffer + 4, p_challenge, 12 );
1082 return WinSendSSC( i_fd, &ssc );
1086 /* DVD ioctls unavailable - do as if the ioctl failed */
1093 /*****************************************************************************
1094 * ioctl_SendKey2: send the second key to the drive
1095 *****************************************************************************/
1096 int ioctl_SendKey2( int i_fd, int *pi_agid, u8 *p_key )
1100 #if defined( HAVE_LINUX_DVD_STRUCT )
1101 dvd_authinfo auth_info;
1103 auth_info.type = DVD_HOST_SEND_KEY2;
1104 auth_info.hsk.agid = *pi_agid;
1106 memcpy( auth_info.hsk.key, p_key, sizeof(dvd_key) );
1108 return ioctl( i_fd, DVD_AUTH, &auth_info );
1110 #elif defined( HAVE_BSD_DVD_STRUCT )
1111 struct dvd_authinfo auth_info;
1113 auth_info.format = DVD_SEND_KEY2;
1114 auth_info.agid = *pi_agid;
1116 memcpy( auth_info.keychal, p_key, 8 );
1118 return ioctl( i_fd, DVDIOCSENDKEY, &auth_info );
1120 #elif defined( SYS_BEOS )
1121 INIT_RDC( GPCMD_SEND_KEY, 12 );
1123 rdc.command[ 10 ] = DVD_SEND_KEY2 | (*pi_agid << 6);
1125 p_buffer[ 1 ] = 0xa;
1126 memcpy( p_buffer + 4, p_key, 8 );
1128 return ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
1130 #elif defined( SOLARIS_USCSI )
1131 INIT_USCSI( GPCMD_SEND_KEY, 12 );
1133 rs_cdb.cdb_opaque[ 10 ] = DVD_SEND_KEY2 | (*pi_agid << 6);
1135 p_buffer[ 1 ] = 0xa;
1136 memcpy( p_buffer + 4, p_key, 8 );
1138 if( ioctl( i_fd, USCSICMD, &sc ) < 0 || sc.uscsi_status )
1145 #elif defined( SYS_DARWIN )
1146 dk_dvd_send_key_t dvd;
1149 memset(&dvd, 0, sizeof(dvd));
1150 memset(&dvdk2i, 0, sizeof(dvdk2i));
1152 dvd.buffer = &dvdk2i;
1153 dvd.bufferLength = sizeof(dvdk2i);
1154 dvd.format = kDVDKeyFormatKey2;
1155 dvd.grantID = *pi_agid;
1157 /* dvdk2i.dataLength[0] = 0x00; */ /*dataLength[0] is already memset to 0 */
1158 dvdk2i.dataLength[1] = 0x0a;
1160 memcpy( dvdk2i.key2Value, p_key, sizeof(dvdk2i.key2Value) );
1162 i_ret = ioctl( i_fd, DKIOCDVDSENDKEY, &dvd );
1164 #elif defined( WIN32 )
1165 if( WIN2K ) /* NT/Win2000/Whistler */
1168 u8 buffer[DVD_BUS_KEY_LENGTH];
1169 PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
1171 memset( &buffer, 0, sizeof( buffer ) );
1173 key->KeyLength = DVD_BUS_KEY_LENGTH;
1174 key->SessionId = *pi_agid;
1175 key->KeyType = DvdBusKey2;
1178 memcpy( key->KeyData, p_key, 8 );
1180 return DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_SEND_KEY, key,
1181 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
1185 INIT_SSC( GPCMD_SEND_KEY, 12 );
1187 ssc.CDBByte[ 10 ] = DVD_SEND_KEY2 | (*pi_agid << 6);
1189 p_buffer[ 1 ] = 0xa;
1190 memcpy( p_buffer + 4, p_key, 8 );
1192 return WinSendSSC( i_fd, &ssc );
1196 /* DVD ioctls unavailable - do as if the ioctl failed */
1203 /* Local prototypes */
1205 #if defined( SYS_BEOS )
1206 /*****************************************************************************
1207 * BeInitRDC: initialize a RDC structure for the BeOS kernel
1208 *****************************************************************************
1209 * This function initializes a BeOS raw device command structure for future
1210 * use, either a read command or a write command.
1211 *****************************************************************************/
1212 static void BeInitRDC( raw_device_command *p_rdc, int i_type )
1214 memset( p_rdc->data, 0, p_rdc->data_length );
1218 case GPCMD_SEND_KEY:
1219 /* leave the flags to 0 */
1222 case GPCMD_READ_DVD_STRUCTURE:
1223 case GPCMD_REPORT_KEY:
1224 p_rdc->flags = B_RAW_DEVICE_DATA_IN;
1228 p_rdc->command[ 0 ] = i_type;
1230 p_rdc->command[ 8 ] = (p_rdc->data_length >> 8) & 0xff;
1231 p_rdc->command[ 9 ] = p_rdc->data_length & 0xff;
1232 p_rdc->command_length = 12;
1234 p_rdc->sense_data = NULL;
1235 p_rdc->sense_data_length = 0;
1237 p_rdc->timeout = 1000000;
1241 #if defined( SOLARIS_USCSI )
1242 /*****************************************************************************
1243 * SolarisInitUSCSI: initialize a USCSICMD structure for the Solaris kernel
1244 *****************************************************************************
1245 * This function initializes a Solaris userspace scsi command structure for
1246 * future use, either a read command or a write command.
1247 *****************************************************************************/
1248 static void SolarisInitUSCSI( struct uscsi_cmd *p_sc, int i_type )
1250 union scsi_cdb *rs_cdb;
1251 memset( p_sc->uscsi_cdb, 0, sizeof( union scsi_cdb ) );
1252 memset( p_sc->uscsi_bufaddr, 0, p_sc->uscsi_buflen );
1256 case GPCMD_SEND_KEY:
1257 p_sc->uscsi_flags = USCSI_ISOLATE | USCSI_WRITE;
1260 case GPCMD_READ_DVD_STRUCTURE:
1261 case GPCMD_REPORT_KEY:
1262 p_sc->uscsi_flags = USCSI_ISOLATE | USCSI_READ;
1266 rs_cdb = (union scsi_cdb *)p_sc->uscsi_cdb;
1268 rs_cdb->scc_cmd = i_type;
1270 rs_cdb->cdb_opaque[ 8 ] = (p_sc->uscsi_buflen >> 8) & 0xff;
1271 rs_cdb->cdb_opaque[ 9 ] = p_sc->uscsi_buflen & 0xff;
1272 p_sc->uscsi_cdblen = 12;
1274 USCSI_TIMEOUT( p_sc, 15 );
1278 #if defined( WIN32 )
1279 /*****************************************************************************
1280 * WinInitSSC: initialize a ssc structure for the win32 aspi layer
1281 *****************************************************************************
1282 * This function initializes a ssc raw device command structure for future
1283 * use, either a read command or a write command.
1284 *****************************************************************************/
1285 static void WinInitSSC( struct SRB_ExecSCSICmd *p_ssc, int i_type )
1287 memset( p_ssc->SRB_BufPointer, 0, p_ssc->SRB_BufLen );
1291 case GPCMD_SEND_KEY:
1292 p_ssc->SRB_Flags = SRB_DIR_OUT;
1295 case GPCMD_READ_DVD_STRUCTURE:
1296 case GPCMD_REPORT_KEY:
1297 p_ssc->SRB_Flags = SRB_DIR_IN;
1301 p_ssc->SRB_Cmd = SC_EXEC_SCSI_CMD;
1302 p_ssc->SRB_Flags |= SRB_EVENT_NOTIFY;
1304 p_ssc->CDBByte[ 0 ] = i_type;
1306 p_ssc->CDBByte[ 8 ] = (u8)(p_ssc->SRB_BufLen >> 8) & 0xff;
1307 p_ssc->CDBByte[ 9 ] = (u8) p_ssc->SRB_BufLen & 0xff;
1308 p_ssc->SRB_CDBLen = 12;
1310 p_ssc->SRB_SenseLen = SENSE_LEN;
1313 /*****************************************************************************
1314 * WinSendSSC: send a ssc structure to the aspi layer
1315 *****************************************************************************/
1316 static int WinSendSSC( int i_fd, struct SRB_ExecSCSICmd *p_ssc )
1318 HANDLE hEvent = NULL;
1319 struct w32_aspidev *fd = (struct w32_aspidev *) i_fd;
1321 hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
1322 if( hEvent == NULL )
1327 p_ssc->SRB_PostProc = hEvent;
1328 p_ssc->SRB_HaId = LOBYTE( fd->i_sid );
1329 p_ssc->SRB_Target = HIBYTE( fd->i_sid );
1331 ResetEvent( hEvent );
1332 if( fd->lpSendCommand( (void*) p_ssc ) == SS_PENDING )
1333 WaitForSingleObject( hEvent, INFINITE );
1335 CloseHandle( hEvent );
1337 return p_ssc->SRB_Status == SS_COMP ? 0 : -1;