* Fixed a bug in the gtk interface which caused vlc to go amok after
[vlc.git] / extras / libdvdcss / ioctl.c
blobdede5fcf07995adc392cf4174d7a305c7dd6d0c7
1 /*****************************************************************************
2 * ioctl.c: DVD ioctl replacement function
3 *****************************************************************************
4 * Copyright (C) 1999-2001 VideoLAN
5 * $Id: ioctl.c,v 1.9 2001/08/09 08:20:26 sam 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>
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
25 *****************************************************************************/
27 /*****************************************************************************
28 * Preamble
29 *****************************************************************************/
30 #include "defs.h"
32 #include <string.h> /* memcpy(), memset() */
33 #include <sys/types.h>
35 #if defined( WIN32 )
36 # include <windows.h>
37 # include <winioctl.h>
38 #else
39 # include <netinet/in.h>
40 # include <sys/ioctl.h>
41 #endif
43 #ifdef DVD_STRUCT_IN_SYS_CDIO_H
44 # include <sys/cdio.h>
45 #endif
46 #ifdef DVD_STRUCT_IN_SYS_DVDIO_H
47 # include <sys/dvdio.h>
48 #endif
49 #ifdef DVD_STRUCT_IN_LINUX_CDROM_H
50 # include <linux/cdrom.h>
51 #endif
52 #ifdef DVD_STRUCT_IN_DVD_H
53 # include <dvd.h>
54 #endif
55 #ifdef SYS_BEOS
56 # include <malloc.h>
57 # include <scsi.h>
58 #endif
59 #ifdef SOLARIS_USCSI
60 # include <unistd.h>
61 # include <stropts.h>
62 # include </usr/include/sys/scsi/scsi_types.h>
63 # include <sys/scsi/impl/uscsi.h>
64 #endif
66 #include "config.h"
67 #include "common.h"
69 #ifdef SYS_DARWIN
70 # include "DVDioctl/DVDioctl.h"
71 #endif
73 #include "ioctl.h"
75 /*****************************************************************************
76 * Local prototypes, BeOS specific
77 *****************************************************************************/
78 #if defined( SYS_BEOS )
79 static void BeInitRDC ( raw_device_command *, int );
80 #endif
82 /*****************************************************************************
83 * Local prototypes, Solaris specific
84 *****************************************************************************/
85 #if defined( SOLARIS_USCSI )
86 static void SolarisInitUSCSI( struct uscsi_cmd *p_sc, int i_type );
87 #endif
89 /*****************************************************************************
90 * Local prototypes, win32 (aspi) specific
91 *****************************************************************************/
92 #if defined( WIN32 )
93 static void WinInitSSC ( struct SRB_ExecSCSICmd *, int );
94 static int WinSendSSC ( int, struct SRB_ExecSCSICmd * );
95 #endif
97 /*****************************************************************************
98 * ioctl_ReadCopyright: check whether the disc is encrypted or not
99 *****************************************************************************/
100 int ioctl_ReadCopyright( int i_fd, int i_layer, int *pi_copyright )
102 int i_ret;
104 #if defined( HAVE_LINUX_DVD_STRUCT )
105 dvd_struct dvd;
107 dvd.type = DVD_STRUCT_COPYRIGHT;
108 dvd.copyright.layer_num = i_layer;
110 i_ret = ioctl( i_fd, DVD_READ_STRUCT, &dvd );
112 *pi_copyright = dvd.copyright.cpst;
114 #elif defined( HAVE_BSD_DVD_STRUCT )
115 struct dvd_struct dvd;
117 dvd.format = DVD_STRUCT_COPYRIGHT;
118 dvd.layer_num = i_layer;
120 i_ret = ioctl( i_fd, DVDIOCREADSTRUCTURE, &dvd );
122 *pi_copyright = dvd.cpst;
124 #elif defined( SYS_BEOS )
125 INIT_RDC( GPCMD_READ_DVD_STRUCTURE, 8 );
127 rdc.command[ 6 ] = i_layer;
128 rdc.command[ 7 ] = DVD_STRUCT_COPYRIGHT;
130 i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
132 *pi_copyright = p_buffer[ 4 ];
134 #elif defined( SOLARIS_USCSI )
135 INIT_USCSI( GPCMD_READ_DVD_STRUCTURE, 8 );
137 rs_cdb.cdb_opaque[ 6 ] = i_layer;
138 rs_cdb.cdb_opaque[ 7 ] = DVD_STRUCT_COPYRIGHT;
140 i_ret = ioctl(i_fd, USCSICMD, &sc);
142 if( i_ret < 0 || sc.uscsi_status ) {
143 i_ret = -1;
146 *pi_copyright = p_buffer[ 4 ];
147 // s->copyright.rmi = p_buffer[ 5 ];
149 #elif defined( SYS_DARWIN )
150 *pi_copyright = 1;
152 i_ret = 0;
154 #elif defined( WIN32 )
155 if( WIN2K ) /* NT/Win2000/Whistler */
157 DWORD tmp;
158 u8 p_buffer[ 8 ];
159 SCSI_PASS_THROUGH_DIRECT sptd;
161 memset( &sptd, 0, sizeof( sptd ) );
162 memset( &p_buffer, 0, sizeof( p_buffer ) );
164 /* When using IOCTL_DVD_READ_STRUCTURE and
165 DVD_COPYRIGHT_DESCRIPTOR, CopyrightProtectionType
166 is always 6. So we send a raw scsi command instead. */
168 sptd.Length = sizeof( SCSI_PASS_THROUGH_DIRECT );
169 sptd.CdbLength = 12;
170 sptd.DataIn = SCSI_IOCTL_DATA_IN;
171 sptd.DataTransferLength = 8;
172 sptd.TimeOutValue = 2;
173 sptd.DataBuffer = p_buffer;
174 sptd.Cdb[ 0 ] = GPCMD_READ_DVD_STRUCTURE;
175 sptd.Cdb[ 6 ] = i_layer;
176 sptd.Cdb[ 7 ] = DVD_STRUCT_COPYRIGHT;
177 sptd.Cdb[ 8 ] = (8 >> 8) & 0xff;
178 sptd.Cdb[ 9 ] = 8 & 0xff;
180 i_ret = DeviceIoControl( (HANDLE) i_fd,
181 IOCTL_SCSI_PASS_THROUGH_DIRECT,
182 &sptd, sizeof( SCSI_PASS_THROUGH_DIRECT ),
183 &sptd, sizeof( SCSI_PASS_THROUGH_DIRECT ),
184 &tmp, NULL ) ? 0 : -1;
186 *pi_copyright = p_buffer[4];
188 else
190 INIT_SSC( GPCMD_READ_DVD_STRUCTURE, 8 );
192 ssc.CDBByte[ 6 ] = i_layer;
193 ssc.CDBByte[ 7 ] = DVD_STRUCT_COPYRIGHT;
195 i_ret = WinSendSSC( i_fd, &ssc );
197 *pi_copyright = p_buffer[ 4 ];
200 #elif defined( __QNXNTO__ )
202 QNX RTOS currently doesn't have a CAM
203 interface (they're working on it though).
204 Assume DVD is not encrypted.
207 *pi_copyright = 0;
208 i_ret = 0;
210 #else
211 /* DVD ioctls unavailable - do as if the ioctl failed */
212 i_ret = -1;
214 #endif
215 return i_ret;
218 /*****************************************************************************
219 * ioctl_ReadKey: get the disc key
220 *****************************************************************************/
221 int ioctl_ReadKey( int i_fd, int *pi_agid, u8 *p_key )
223 int i_ret;
225 #if defined( HAVE_LINUX_DVD_STRUCT )
226 dvd_struct dvd;
228 dvd.type = DVD_STRUCT_DISCKEY;
229 dvd.disckey.agid = *pi_agid;
230 memset( dvd.disckey.value, 0, 2048 );
232 i_ret = ioctl( i_fd, DVD_READ_STRUCT, &dvd );
234 if( i_ret < 0 )
236 return i_ret;
239 memcpy( p_key, dvd.disckey.value, 2048 );
241 #elif defined( HAVE_BSD_DVD_STRUCT )
242 struct dvd_struct dvd;
244 dvd.format = DVD_STRUCT_DISCKEY;
245 dvd.agid = *pi_agid;
246 memset( dvd.data, 0, 2048 );
248 i_ret = ioctl( i_fd, DVDIOCREADSTRUCTURE, &dvd );
250 if( i_ret < 0 )
252 return i_ret;
255 memcpy( p_key, dvd.data, 2048 );
257 #elif defined( SYS_BEOS )
258 INIT_RDC( GPCMD_READ_DVD_STRUCTURE, 2048 + 4 );
260 rdc.command[ 7 ] = DVD_STRUCT_DISCKEY;
261 rdc.command[ 10 ] = *pi_agid << 6;
263 i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
265 if( i_ret < 0 )
267 return i_ret;
270 memcpy( p_key, p_buffer + 4, 2048 );
272 #elif defined( SOLARIS_USCSI )
273 INIT_USCSI( GPCMD_READ_DVD_STRUCTURE, 2048 + 4 );
275 rs_cdb.cdb_opaque[ 7 ] = DVD_STRUCT_DISCKEY;
276 rs_cdb.cdb_opaque[ 10 ] = *pi_agid << 6;
278 i_ret = ioctl( i_fd, USCSICMD, &sc );
280 if( i_ret < 0 || sc.uscsi_status )
282 i_ret = -1;
283 return i_ret;
286 memcpy( p_key, p_buffer + 4, 2048 );
288 #elif defined( SYS_DARWIN )
289 i_ret = 0;
291 memset( p_key, 0x00, 2048 );
293 #elif defined( WIN32 )
294 if( WIN2K ) /* NT/Win2000/Whistler */
296 DWORD tmp;
297 u8 buffer[DVD_DISK_KEY_LENGTH];
298 PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
300 memset( &buffer, 0, sizeof( buffer ) );
302 key->KeyLength = DVD_DISK_KEY_LENGTH;
303 key->SessionId = *pi_agid;
304 key->KeyType = DvdDiskKey;
305 key->KeyFlags = 0;
307 i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key,
308 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
310 if( i_ret < 0 )
312 return i_ret;
315 memcpy( p_key, key->KeyData, 2048 );
317 else
319 INIT_SSC( GPCMD_READ_DVD_STRUCTURE, 2048 + 4 );
321 ssc.CDBByte[ 7 ] = DVD_STRUCT_DISCKEY;
322 ssc.CDBByte[ 10 ] = *pi_agid << 6;
324 i_ret = WinSendSSC( i_fd, &ssc );
326 if( i_ret < 0 )
328 return i_ret;
331 memcpy( p_key, p_buffer + 4, 2048 );
334 #else
335 /* DVD ioctls unavailable - do as if the ioctl failed */
336 i_ret = -1;
338 #endif
339 return i_ret;
342 /*****************************************************************************
343 * ioctl_ReportAgid: get AGID from the drive
344 *****************************************************************************/
345 int ioctl_ReportAgid( int i_fd, int *pi_agid )
347 int i_ret;
349 #if defined( HAVE_LINUX_DVD_STRUCT )
350 dvd_authinfo auth_info;
352 auth_info.type = DVD_LU_SEND_AGID;
353 auth_info.lsa.agid = *pi_agid;
355 i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
357 *pi_agid = auth_info.lsa.agid;
359 #elif defined( HAVE_BSD_DVD_STRUCT )
360 struct dvd_authinfo auth_info;
362 auth_info.format = DVD_REPORT_AGID;
363 auth_info.agid = *pi_agid;
365 i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
367 *pi_agid = auth_info.agid;
369 #elif defined( SYS_BEOS )
370 INIT_RDC( GPCMD_REPORT_KEY, 8 );
372 rdc.command[ 10 ] = DVD_REPORT_AGID | (*pi_agid << 6);
374 i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
376 *pi_agid = p_buffer[ 7 ] >> 6;
378 #elif defined( SOLARIS_USCSI )
379 INIT_USCSI( GPCMD_REPORT_KEY, 8 );
381 rs_cdb.cdb_opaque[ 10 ] = DVD_REPORT_AGID | (*pi_agid << 6);
383 i_ret = ioctl( i_fd, USCSICMD, &sc );
385 if( i_ret < 0 || sc.uscsi_status )
387 i_ret = -1;
390 *pi_agid = p_buffer[ 7 ] >> 6;
392 #elif defined( SYS_DARWIN )
393 INIT_DVDIOCTL( 8 );
395 dvdioctl.i_keyformat = kCSSAGID;
396 dvdioctl.i_agid = *pi_agid;
397 dvdioctl.i_lba = 0;
399 i_ret = ioctl( i_fd, IODVD_REPORT_KEY, &dvdioctl );
401 *pi_agid = p_buffer[ 7 ] >> 6;
403 #elif defined( WIN32 )
404 if( WIN2K ) /* NT/Win2000/Whistler */
406 ULONG id;
407 DWORD tmp;
409 i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_START_SESSION,
410 &tmp, 4, &id, sizeof( id ), &tmp, NULL ) ? 0 : -1;
412 *pi_agid = id;
414 else
416 INIT_SSC( GPCMD_REPORT_KEY, 8 );
418 ssc.CDBByte[ 10 ] = DVD_REPORT_AGID | (*pi_agid << 6);
420 i_ret = WinSendSSC( i_fd, &ssc );
422 *pi_agid = p_buffer[ 7 ] >> 6;
425 #else
426 /* DVD ioctls unavailable - do as if the ioctl failed */
427 i_ret = -1;
429 #endif
430 return i_ret;
433 /*****************************************************************************
434 * ioctl_ReportChallenge: get challenge from the drive
435 *****************************************************************************/
436 int ioctl_ReportChallenge( int i_fd, int *pi_agid, u8 *p_challenge )
438 int i_ret;
440 #if defined( HAVE_LINUX_DVD_STRUCT )
441 dvd_authinfo auth_info;
443 auth_info.type = DVD_LU_SEND_CHALLENGE;
444 auth_info.lsc.agid = *pi_agid;
446 i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
448 memcpy( p_challenge, auth_info.lsc.chal, sizeof(dvd_challenge) );
450 #elif defined( HAVE_BSD_DVD_STRUCT )
451 struct dvd_authinfo auth_info;
453 auth_info.format = DVD_REPORT_CHALLENGE;
454 auth_info.agid = *pi_agid;
456 i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
458 memcpy( p_challenge, auth_info.keychal, 10 );
460 #elif defined( SYS_BEOS )
461 INIT_RDC( GPCMD_REPORT_KEY, 16 );
463 rdc.command[ 10 ] = DVD_REPORT_CHALLENGE | (*pi_agid << 6);
465 i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
467 memcpy( p_challenge, p_buffer + 4, 12 );
469 #elif defined( SOLARIS_USCSI )
470 INIT_USCSI( GPCMD_REPORT_KEY, 16 );
472 rs_cdb.cdb_opaque[ 10 ] = DVD_REPORT_CHALLENGE | (*pi_agid << 6);
474 i_ret = ioctl( i_fd, USCSICMD, &sc );
476 if( i_ret < 0 || sc.uscsi_status )
478 i_ret = -1;
481 memcpy( p_challenge, p_buffer + 4, 12 );
483 #elif defined( SYS_DARWIN )
484 INIT_DVDIOCTL( 16 );
486 dvdioctl.i_keyformat = kChallengeKey;
487 dvdioctl.i_agid = *pi_agid;
488 dvdioctl.i_lba = 0;
490 i_ret = ioctl( i_fd, IODVD_REPORT_KEY, &dvdioctl );
492 memcpy( p_challenge, p_buffer + 4, 12 );
494 #elif defined( WIN32 )
495 if( WIN2K ) /* NT/Win2000/Whistler */
497 DWORD tmp;
498 u8 buffer[DVD_CHALLENGE_KEY_LENGTH];
499 PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
501 memset( &buffer, 0, sizeof( buffer ) );
503 key->KeyLength = DVD_CHALLENGE_KEY_LENGTH;
504 key->SessionId = *pi_agid;
505 key->KeyType = DvdChallengeKey;
506 key->KeyFlags = 0;
508 i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key,
509 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
511 if( i_ret < 0 )
513 return i_ret;
516 memcpy( p_challenge, key->KeyData, 10 );
518 else
520 INIT_SSC( GPCMD_REPORT_KEY, 16 );
522 ssc.CDBByte[ 10 ] = DVD_REPORT_CHALLENGE | (*pi_agid << 6);
524 i_ret = WinSendSSC( i_fd, &ssc );
526 memcpy( p_challenge, p_buffer + 4, 12 );
529 #else
530 /* DVD ioctls unavailable - do as if the ioctl failed */
531 i_ret = -1;
533 #endif
534 return i_ret;
537 /*****************************************************************************
538 * ioctl_ReportASF: get ASF from the drive
539 *****************************************************************************/
540 int ioctl_ReportASF( int i_fd, int *pi_agid, int *pi_asf )
542 int i_ret;
544 #if defined( HAVE_LINUX_DVD_STRUCT )
545 dvd_authinfo auth_info;
547 auth_info.type = DVD_LU_SEND_ASF;
548 auth_info.lsasf.agid = *pi_agid;
549 auth_info.lsasf.asf = *pi_asf;
551 i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
553 *pi_asf = auth_info.lsasf.asf;
555 #elif defined( HAVE_BSD_DVD_STRUCT )
556 struct dvd_authinfo auth_info;
558 auth_info.format = DVD_REPORT_ASF;
559 auth_info.agid = *pi_agid;
560 auth_info.asf = *pi_asf;
562 i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
564 *pi_asf = auth_info.asf;
566 #elif defined( SYS_BEOS )
567 INIT_RDC( GPCMD_REPORT_KEY, 8 );
569 rdc.command[ 10 ] = DVD_REPORT_ASF | (*pi_agid << 6);
571 i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
573 *pi_asf = p_buffer[ 7 ] & 1;
575 #elif defined( SOLARIS_USCSI )
576 INIT_USCSI( GPCMD_REPORT_KEY, 8 );
578 rs_cdb.cdb_opaque[ 10 ] = DVD_REPORT_ASF | (*pi_agid << 6);
580 i_ret = ioctl( i_fd, USCSICMD, &sc );
582 if( i_ret < 0 || sc.uscsi_status )
584 i_ret = -1;
587 *pi_asf = p_buffer[ 7 ] & 1;
589 #elif defined( SYS_DARWIN )
590 INIT_DVDIOCTL( 8 );
592 dvdioctl.i_keyformat = kASF;
593 dvdioctl.i_agid = *pi_agid;
594 dvdioctl.i_lba = 0;
596 i_ret = ioctl( i_fd, IODVD_REPORT_KEY, &dvdioctl );
598 *pi_asf = p_buffer[ 7 ] & 1;
600 #elif defined( WIN32 )
601 if( WIN2K ) /* NT/Win2000/Whistler */
603 DWORD tmp;
604 u8 buffer[DVD_ASF_LENGTH];
605 PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
607 memset( &buffer, 0, sizeof( buffer ) );
609 key->KeyLength = DVD_ASF_LENGTH;
610 key->SessionId = *pi_agid;
611 key->KeyType = DvdAsf;
612 key->KeyFlags = 0;
614 ((PDVD_ASF)key->KeyData)->SuccessFlag = *pi_asf;
616 i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key,
617 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
619 if( i_ret < 0 )
621 return i_ret;
624 *pi_asf = ((PDVD_ASF)key->KeyData)->SuccessFlag;
626 else
628 INIT_SSC( GPCMD_REPORT_KEY, 8 );
630 ssc.CDBByte[ 10 ] = DVD_REPORT_ASF | (*pi_agid << 6);
632 i_ret = WinSendSSC( i_fd, &ssc );
634 *pi_asf = p_buffer[ 7 ] & 1;
637 #else
638 /* DVD ioctls unavailable - do as if the ioctl failed */
639 i_ret = -1;
641 #endif
642 return i_ret;
645 /*****************************************************************************
646 * ioctl_ReportKey1: get the first key from the drive
647 *****************************************************************************/
648 int ioctl_ReportKey1( int i_fd, int *pi_agid, u8 *p_key )
650 int i_ret;
652 #if defined( HAVE_LINUX_DVD_STRUCT )
653 dvd_authinfo auth_info;
655 auth_info.type = DVD_LU_SEND_KEY1;
656 auth_info.lsk.agid = *pi_agid;
658 i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
660 memcpy( p_key, auth_info.lsk.key, sizeof(dvd_key) );
662 #elif defined( HAVE_BSD_DVD_STRUCT )
663 struct dvd_authinfo auth_info;
665 auth_info.format = DVD_REPORT_KEY1;
666 auth_info.agid = *pi_agid;
668 i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
670 memcpy( p_key, auth_info.keychal, 8 );
672 #elif defined( SYS_BEOS )
673 INIT_RDC( GPCMD_REPORT_KEY, 12 );
675 rdc.command[ 10 ] = DVD_REPORT_KEY1 | (*pi_agid << 6);
677 i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
679 memcpy( p_key, p_buffer + 4, 8 );
681 #elif defined( SOLARIS_USCSI )
682 INIT_USCSI( GPCMD_REPORT_KEY, 12 );
684 rs_cdb.cdb_opaque[ 10 ] = DVD_REPORT_KEY1 | (*pi_agid << 6);
686 i_ret = ioctl( i_fd, USCSICMD, &sc );
688 if( i_ret < 0 || sc.uscsi_status )
690 i_ret = -1;
693 memcpy( p_key, p_buffer + 4, 8 );;
695 #elif defined( SYS_DARWIN )
696 INIT_DVDIOCTL( 12 );
698 dvdioctl.i_keyformat = kKey1;
699 dvdioctl.i_agid = *pi_agid;
701 i_ret = ioctl( i_fd, IODVD_SEND_KEY, &dvdioctl );
703 memcpy( p_key, p_buffer + 4, 8 );
705 #elif defined( WIN32 )
706 if( WIN2K ) /* NT/Win2000/Whistler */
708 DWORD tmp;
709 u8 buffer[DVD_BUS_KEY_LENGTH];
710 PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
712 memset( &buffer, 0, sizeof( buffer ) );
714 key->KeyLength = DVD_BUS_KEY_LENGTH;
715 key->SessionId = *pi_agid;
716 key->KeyType = DvdBusKey1;
717 key->KeyFlags = 0;
719 i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key,
720 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
722 memcpy( p_key, key->KeyData, 8 );
724 else
726 INIT_SSC( GPCMD_REPORT_KEY, 12 );
728 ssc.CDBByte[ 10 ] = DVD_REPORT_KEY1 | (*pi_agid << 6);
730 i_ret = WinSendSSC( i_fd, &ssc );
732 memcpy( p_key, p_buffer + 4, 8 );
735 #else
736 /* DVD ioctls unavailable - do as if the ioctl failed */
737 i_ret = -1;
739 #endif
740 return i_ret;
743 /*****************************************************************************
744 * ioctl_InvalidateAgid: invalidate the current AGID
745 *****************************************************************************/
746 int ioctl_InvalidateAgid( int i_fd, int *pi_agid )
748 int i_ret;
750 #if defined( HAVE_LINUX_DVD_STRUCT )
751 dvd_authinfo auth_info;
753 auth_info.type = DVD_INVALIDATE_AGID;
754 auth_info.lsa.agid = *pi_agid;
756 i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
758 *pi_agid = auth_info.lsa.agid;
760 #elif defined( HAVE_BSD_DVD_STRUCT )
761 struct dvd_authinfo auth_info;
763 auth_info.format = DVD_INVALIDATE_AGID;
764 auth_info.agid = *pi_agid;
766 i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
768 *pi_agid = auth_info.agid;
770 #elif defined( SYS_BEOS )
771 INIT_RDC( GPCMD_REPORT_KEY, 0 );
773 rdc.command[ 10 ] = DVD_INVALIDATE_AGID | (*pi_agid << 6);
775 i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
777 #elif defined( SOLARIS_USCSI )
778 INIT_USCSI( GPCMD_REPORT_KEY, 0 );
780 rs_cdb.cdb_opaque[ 10 ] = DVD_INVALIDATE_AGID | (*pi_agid << 6);
782 i_ret = ioctl( i_fd, USCSICMD, &sc );
784 if( i_ret < 0 || sc.uscsi_status )
786 i_ret = -1;
789 #elif defined( SYS_DARWIN )
790 INIT_DVDIOCTL( 0 );
792 dvdioctl.i_keyformat = kInvalidateAGID;
793 dvdioctl.i_agid = *pi_agid;
795 i_ret = ioctl( i_fd, IODVD_SEND_KEY, &dvdioctl );
797 #elif defined( WIN32 )
798 if( WIN2K ) /* NT/Win2000/Whistler */
800 DWORD tmp;
802 i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_END_SESSION,
803 pi_agid, sizeof( *pi_agid ), NULL, 0, &tmp, NULL ) ? 0 : -1;
805 else
807 #if defined( __MINGW32__ )
808 INIT_SSC( GPCMD_REPORT_KEY, 0 );
809 #else
810 INIT_SSC( GPCMD_REPORT_KEY, 1 );
812 ssc.SRB_BufLen = 0;
813 ssc.CDBByte[ 8 ] = 0;
814 ssc.CDBByte[ 9 ] = 0;
815 #endif
817 ssc.CDBByte[ 10 ] = DVD_INVALIDATE_AGID | (*pi_agid << 6);
819 i_ret = WinSendSSC( i_fd, &ssc );
822 #else
823 /* DVD ioctls unavailable - do as if the ioctl failed */
824 i_ret = -1;
826 #endif
827 return i_ret;
830 /*****************************************************************************
831 * ioctl_SendChallenge: send challenge to the drive
832 *****************************************************************************/
833 int ioctl_SendChallenge( int i_fd, int *pi_agid, u8 *p_challenge )
835 #if defined( HAVE_LINUX_DVD_STRUCT )
836 dvd_authinfo auth_info;
838 auth_info.type = DVD_HOST_SEND_CHALLENGE;
839 auth_info.hsc.agid = *pi_agid;
841 memcpy( auth_info.hsc.chal, p_challenge, sizeof(dvd_challenge) );
843 return ioctl( i_fd, DVD_AUTH, &auth_info );
845 #elif defined( HAVE_BSD_DVD_STRUCT )
846 struct dvd_authinfo auth_info;
848 auth_info.format = DVD_SEND_CHALLENGE;
849 auth_info.agid = *pi_agid;
851 memcpy( auth_info.keychal, p_challenge, 12 );
853 return ioctl( i_fd, DVDIOCSENDKEY, &auth_info );
855 #elif defined( SYS_BEOS )
856 INIT_RDC( GPCMD_SEND_KEY, 16 );
858 rdc.command[ 10 ] = DVD_SEND_CHALLENGE | (*pi_agid << 6);
860 p_buffer[ 1 ] = 0xe;
861 memcpy( p_buffer + 4, p_challenge, 12 );
863 return ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
865 #elif defined( SOLARIS_USCSI )
866 INIT_USCSI( GPCMD_SEND_KEY, 16 );
868 rs_cdb.cdb_opaque[ 10 ] = DVD_SEND_CHALLENGE | (*pi_agid << 6);
870 p_buffer[ 1 ] = 0xe;
871 memcpy( p_buffer + 4, p_challenge, 12 );
873 if( ioctl( i_fd, USCSICMD, &sc ) < 0 || sc.uscsi_status )
875 return -1;
878 return 0;
880 #elif defined( SYS_DARWIN )
881 INIT_DVDIOCTL( 16 );
883 dvdioctl.i_keyformat = kChallengeKey;
884 dvdioctl.i_agid = *pi_agid;
886 p_buffer[ 1 ] = 0xe;
887 memcpy( p_buffer + 4, p_challenge, 12 );
889 return ioctl( i_fd, IODVD_SEND_KEY, &dvdioctl );
891 #elif defined( WIN32 )
892 if( WIN2K ) /* NT/Win2000/Whistler */
894 DWORD tmp;
895 u8 buffer[DVD_CHALLENGE_KEY_LENGTH];
896 PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
898 memset( &buffer, 0, sizeof( buffer ) );
900 key->KeyLength = DVD_CHALLENGE_KEY_LENGTH;
901 key->SessionId = *pi_agid;
902 key->KeyType = DvdChallengeKey;
903 key->KeyFlags = 0;
905 memcpy( key->KeyData, p_challenge, 10 );
907 return DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_SEND_KEY, key,
908 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
910 else
912 INIT_SSC( GPCMD_SEND_KEY, 16 );
914 ssc.CDBByte[ 10 ] = DVD_SEND_CHALLENGE | (*pi_agid << 6);
916 p_buffer[ 1 ] = 0xe;
917 memcpy( p_buffer + 4, p_challenge, 12 );
919 return WinSendSSC( i_fd, &ssc );
922 #else
923 /* DVD ioctls unavailable - do as if the ioctl failed */
924 return -1;
926 #endif
929 /*****************************************************************************
930 * ioctl_SendKey2: send the second key to the drive
931 *****************************************************************************/
932 int ioctl_SendKey2( int i_fd, int *pi_agid, u8 *p_key )
934 #if defined( HAVE_LINUX_DVD_STRUCT )
935 dvd_authinfo auth_info;
937 auth_info.type = DVD_HOST_SEND_KEY2;
938 auth_info.hsk.agid = *pi_agid;
940 memcpy( auth_info.hsk.key, p_key, sizeof(dvd_key) );
942 return ioctl( i_fd, DVD_AUTH, &auth_info );
944 #elif defined( HAVE_BSD_DVD_STRUCT )
945 struct dvd_authinfo auth_info;
947 auth_info.format = DVD_SEND_KEY2;
948 auth_info.agid = *pi_agid;
950 memcpy( auth_info.keychal, p_key, 8 );
952 return ioctl( i_fd, DVDIOCSENDKEY, &auth_info );
954 #elif defined( SYS_BEOS )
955 INIT_RDC( GPCMD_SEND_KEY, 12 );
957 rdc.command[ 10 ] = DVD_SEND_KEY2 | (*pi_agid << 6);
959 p_buffer[ 1 ] = 0xa;
960 memcpy( p_buffer + 4, p_key, 8 );
962 return ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
964 #elif defined( SOLARIS_USCSI )
965 INIT_USCSI( GPCMD_SEND_KEY, 12 );
967 rs_cdb.cdb_opaque[ 10 ] = DVD_SEND_KEY2 | (*pi_agid << 6);
969 p_buffer[ 1 ] = 0xa;
970 memcpy( p_buffer + 4, p_key, 8 );
972 if( ioctl( i_fd, USCSICMD, &sc ) < 0 || sc.uscsi_status )
974 return -1;
977 return 0;
979 #elif defined( WIN32 )
980 if( WIN2K ) /* NT/Win2000/Whistler */
982 DWORD tmp;
983 u8 buffer[DVD_BUS_KEY_LENGTH];
984 PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
986 memset( &buffer, 0, sizeof( buffer ) );
988 key->KeyLength = DVD_BUS_KEY_LENGTH;
989 key->SessionId = *pi_agid;
990 key->KeyType = DvdBusKey2;
991 key->KeyFlags = 0;
993 memcpy( key->KeyData, p_key, 8 );
995 return DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_SEND_KEY, key,
996 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
998 else
1000 INIT_SSC( GPCMD_SEND_KEY, 12 );
1002 ssc.CDBByte[ 10 ] = DVD_SEND_KEY2 | (*pi_agid << 6);
1004 p_buffer[ 1 ] = 0xa;
1005 memcpy( p_buffer + 4, p_key, 8 );
1007 return WinSendSSC( i_fd, &ssc );
1010 #elif defined( SYS_DARWIN )
1011 INIT_DVDIOCTL( 12 );
1013 dvdioctl.i_keyformat = kKey2;
1014 dvdioctl.i_agid = *pi_agid;
1016 p_buffer[ 1 ] = 0xa;
1017 memcpy( p_buffer + 4, p_key, 8 );
1019 return ioctl( i_fd, IODVD_SEND_KEY, &dvdioctl );
1021 #else
1022 /* DVD ioctls unavailable - do as if the ioctl failed */
1023 return -1;
1025 #endif
1028 /* Local prototypes */
1030 #if defined( SYS_BEOS )
1031 /*****************************************************************************
1032 * BeInitRDC: initialize a RDC structure for the BeOS kernel
1033 *****************************************************************************
1034 * This function initializes a BeOS raw device command structure for future
1035 * use, either a read command or a write command.
1036 *****************************************************************************/
1037 static void BeInitRDC( raw_device_command *p_rdc, int i_type )
1039 memset( p_rdc->data, 0, p_rdc->data_length );
1041 switch( i_type )
1043 case GPCMD_SEND_KEY:
1044 /* leave the flags to 0 */
1045 break;
1047 case GPCMD_READ_DVD_STRUCTURE:
1048 case GPCMD_REPORT_KEY:
1049 p_rdc->flags = B_RAW_DEVICE_DATA_IN;
1050 break;
1053 p_rdc->command[ 0 ] = i_type;
1055 p_rdc->command[ 8 ] = (p_rdc->data_length >> 8) & 0xff;
1056 p_rdc->command[ 9 ] = p_rdc->data_length & 0xff;
1057 p_rdc->command_length = 12;
1059 p_rdc->sense_data = NULL;
1060 p_rdc->sense_data_length = 0;
1062 p_rdc->timeout = 1000000;
1064 #endif
1066 #if defined( SOLARIS_USCSI )
1067 /*****************************************************************************
1068 * SolarisInitUSCSI: initialize a USCSICMD structure for the Solaris kernel
1069 *****************************************************************************
1070 * This function initializes a Solaris userspace scsi command structure for
1071 * future use, either a read command or a write command.
1072 *****************************************************************************/
1073 static void SolarisInitUSCSI( struct uscsi_cmd *p_sc, int i_type )
1075 union scsi_cdb *rs_cdb;
1076 memset( p_sc->uscsi_cdb, 0, sizeof( union scsi_cdb ) );
1077 memset( p_sc->uscsi_bufaddr, 0, p_sc->uscsi_buflen );
1079 switch( i_type )
1081 case GPCMD_SEND_KEY:
1082 p_sc->uscsi_flags = USCSI_ISOLATE | USCSI_WRITE;
1083 break;
1085 case GPCMD_READ_DVD_STRUCTURE:
1086 case GPCMD_REPORT_KEY:
1087 p_sc->uscsi_flags = USCSI_ISOLATE | USCSI_READ;
1088 break;
1091 rs_cdb = (union scsi_cdb *)p_sc->uscsi_cdb;
1093 rs_cdb->scc_cmd = i_type;
1095 rs_cdb->cdb_opaque[ 8 ] = (p_sc->uscsi_buflen >> 8) & 0xff;
1096 rs_cdb->cdb_opaque[ 9 ] = p_sc->uscsi_buflen & 0xff;
1097 p_sc->uscsi_cdblen = 12;
1099 USCSI_TIMEOUT( p_sc, 15 );
1101 #endif
1103 #if defined( WIN32 )
1104 /*****************************************************************************
1105 * WinInitSSC: initialize a ssc structure for the win32 aspi layer
1106 *****************************************************************************
1107 * This function initializes a ssc raw device command structure for future
1108 * use, either a read command or a write command.
1109 *****************************************************************************/
1110 static void WinInitSSC( struct SRB_ExecSCSICmd *p_ssc, int i_type )
1112 memset( p_ssc->SRB_BufPointer, 0, p_ssc->SRB_BufLen );
1114 switch( i_type )
1116 case GPCMD_SEND_KEY:
1117 p_ssc->SRB_Flags = SRB_DIR_OUT;
1118 break;
1120 case GPCMD_READ_DVD_STRUCTURE:
1121 case GPCMD_REPORT_KEY:
1122 p_ssc->SRB_Flags = SRB_DIR_IN;
1123 break;
1126 p_ssc->SRB_Cmd = SC_EXEC_SCSI_CMD;
1127 p_ssc->SRB_Flags |= SRB_EVENT_NOTIFY;
1129 p_ssc->CDBByte[ 0 ] = i_type;
1131 p_ssc->CDBByte[ 8 ] = (u8)(p_ssc->SRB_BufLen >> 8) & 0xff;
1132 p_ssc->CDBByte[ 9 ] = (u8) p_ssc->SRB_BufLen & 0xff;
1133 p_ssc->SRB_CDBLen = 12;
1135 p_ssc->SRB_SenseLen = SENSE_LEN;
1138 /*****************************************************************************
1139 * WinSendSSC: send a ssc structure to the aspi layer
1140 *****************************************************************************/
1141 static int WinSendSSC( int i_fd, struct SRB_ExecSCSICmd *p_ssc )
1143 HANDLE hEvent = NULL;
1144 struct w32_aspidev *fd = (struct w32_aspidev *) i_fd;
1146 hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
1147 if( hEvent == NULL )
1149 return -1;
1152 p_ssc->SRB_PostProc = hEvent;
1153 p_ssc->SRB_HaId = LOBYTE( fd->i_sid );
1154 p_ssc->SRB_Target = HIBYTE( fd->i_sid );
1156 ResetEvent( hEvent );
1157 if( fd->lpSendCommand( (void*) p_ssc ) == SS_PENDING )
1158 WaitForSingleObject( hEvent, INFINITE );
1160 CloseHandle( hEvent );
1162 return p_ssc->SRB_Status == SS_COMP ? 0 : -1;
1164 #endif