]> git.sesse.net Git - vlc/blob - extras/libdvdcss/ioctl.c
a81d69430a14846c962495580071dddfd52e5587
[vlc] / extras / libdvdcss / ioctl.c
1 /*****************************************************************************
2  * ioctl.c: DVD ioctl replacement function
3  *****************************************************************************
4  * Copyright (C) 1999-2001 VideoLAN
5  * $Id: ioctl.c,v 1.7 2001/08/07 02:48:24 sam Exp $
6  *
7  * Authors: Markus Kuespert <ltlBeBoy@beosmail.com>
8  *          Samuel Hocevar <sam@zoy.org>
9  *          Jon Lech Johansen <jon-vl@nanocrew.net>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
24  *****************************************************************************/
25
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29 #include "defs.h"
30
31 #include <string.h>                                    /* memcpy(), memset() */
32 #include <sys/types.h>
33
34 #if defined( WIN32 )
35 #   include <windows.h>
36 #   include <winioctl.h>
37 #else
38 #   include <netinet/in.h>
39 #   include <sys/ioctl.h>
40 #endif
41
42 #ifdef DVD_STRUCT_IN_SYS_CDIO_H
43 #   include <sys/cdio.h>
44 #endif
45 #ifdef DVD_STRUCT_IN_SYS_DVDIO_H
46 #   include <sys/dvdio.h>
47 #endif
48 #ifdef DVD_STRUCT_IN_LINUX_CDROM_H
49 #   include <linux/cdrom.h>
50 #endif
51 #ifdef DVD_STRUCT_IN_DVD_H
52 #   include <dvd.h>
53 #endif
54 #ifdef SYS_BEOS
55 #   include <malloc.h>
56 #   include <scsi.h>
57 #endif
58
59 #include "config.h"
60 #include "common.h"
61
62 #ifdef SYS_DARWIN
63 #   include "DVDioctl/DVDioctl.h"
64 #endif
65
66 #include "ioctl.h"
67
68 /*****************************************************************************
69  * Local prototypes, BeOS specific
70  *****************************************************************************/
71 #if defined( SYS_BEOS )
72 static void BeInitRDC ( raw_device_command *, int );
73 #endif
74
75 /*****************************************************************************
76  * Local prototypes, win32 (aspi) specific
77  *****************************************************************************/
78 #if defined( WIN32 )
79 static void WinInitSSC ( struct SRB_ExecSCSICmd *, int );
80 static int  WinSendSSC ( int, struct SRB_ExecSCSICmd * );
81 #endif
82
83 /*****************************************************************************
84  * ioctl_ReadCopyright: check whether the disc is encrypted or not
85  *****************************************************************************/
86 int ioctl_ReadCopyright( int i_fd, int i_layer, int *pi_copyright )
87 {
88     int i_ret;
89
90 #if defined( HAVE_LINUX_DVD_STRUCT )
91     dvd_struct dvd;
92
93     dvd.type = DVD_STRUCT_COPYRIGHT;
94     dvd.copyright.layer_num = i_layer;
95
96     i_ret = ioctl( i_fd, DVD_READ_STRUCT, &dvd );
97
98     *pi_copyright = dvd.copyright.cpst;
99
100 #elif defined( HAVE_BSD_DVD_STRUCT )
101     struct dvd_struct dvd;
102
103     dvd.format = DVD_STRUCT_COPYRIGHT;
104     dvd.layer_num = i_layer;
105
106     i_ret = ioctl( i_fd, DVDIOCREADSTRUCTURE, &dvd );
107
108     *pi_copyright = dvd.cpst;
109
110 #elif defined( SYS_BEOS )
111     INIT_RDC( GPCMD_READ_DVD_STRUCTURE, 8 );
112
113     rdc.command[ 6 ] = i_layer;
114     rdc.command[ 7 ] = DVD_STRUCT_COPYRIGHT;
115
116     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
117
118     *pi_copyright = p_buffer[ 4 ];
119
120 #elif defined( SYS_DARWIN )
121     *pi_copyright = 1;
122
123     i_ret = 0;
124
125 #elif defined( WIN32 )
126     if( WIN2K ) /* NT/Win2000/Whistler */
127     {
128         DWORD tmp;
129         u8 p_buffer[ 8 ];
130         SCSI_PASS_THROUGH_DIRECT sptd;
131
132         memset( &sptd, 0, sizeof( sptd ) );
133         memset( &p_buffer, 0, sizeof( p_buffer ) );
134    
135         /*  When using IOCTL_DVD_READ_STRUCTURE and 
136             DVD_COPYRIGHT_DESCRIPTOR, CopyrightProtectionType
137             is always 6. So we send a raw scsi command instead. */
138
139         sptd.Length             = sizeof( SCSI_PASS_THROUGH_DIRECT );
140         sptd.CdbLength          = 12;
141         sptd.DataIn             = SCSI_IOCTL_DATA_IN;
142         sptd.DataTransferLength = 8;
143         sptd.TimeOutValue       = 2;
144         sptd.DataBuffer         = p_buffer;
145         sptd.Cdb[ 0 ]           = GPCMD_READ_DVD_STRUCTURE;
146         sptd.Cdb[ 6 ]           = i_layer;
147         sptd.Cdb[ 7 ]           = DVD_STRUCT_COPYRIGHT;
148         sptd.Cdb[ 8 ]           = (8 >> 8) & 0xff;
149         sptd.Cdb[ 9 ]           =  8       & 0xff;
150
151         i_ret = DeviceIoControl( (HANDLE) i_fd,
152                              IOCTL_SCSI_PASS_THROUGH_DIRECT,
153                              &sptd, sizeof( SCSI_PASS_THROUGH_DIRECT ),
154                              &sptd, sizeof( SCSI_PASS_THROUGH_DIRECT ),
155                              &tmp, NULL ) ? 0 : -1;
156
157         *pi_copyright = p_buffer[4];
158     }
159     else
160     {
161         INIT_SSC( GPCMD_READ_DVD_STRUCTURE, 8 );
162
163         ssc.CDBByte[ 6 ] = i_layer;
164         ssc.CDBByte[ 7 ] = DVD_STRUCT_COPYRIGHT;
165
166         i_ret = WinSendSSC( i_fd, &ssc );
167
168         *pi_copyright = p_buffer[ 4 ];
169     }
170
171 #elif defined( __QNXNTO__ )
172     /*
173         QNX RTOS currently doesn't have a CAM
174         interface (they're working on it though).
175         Assume DVD is not encrypted.
176     */
177
178     *pi_copyright = 0;
179     i_ret = 0;
180
181 #else
182     /* DVD ioctls unavailable - do as if the ioctl failed */
183     i_ret = -1;
184
185 #endif
186     return i_ret;
187 }
188
189 /*****************************************************************************
190  * ioctl_ReadKey: get the disc key
191  *****************************************************************************/
192 int ioctl_ReadKey( int i_fd, int *pi_agid, u8 *p_key )
193 {
194     int i_ret;
195
196 #if defined( HAVE_LINUX_DVD_STRUCT )
197     dvd_struct dvd;
198
199     dvd.type = DVD_STRUCT_DISCKEY;
200     dvd.disckey.agid = *pi_agid;
201     memset( dvd.disckey.value, 0, 2048 );
202
203     i_ret = ioctl( i_fd, DVD_READ_STRUCT, &dvd );
204
205     if( i_ret < 0 )
206     {
207         return i_ret;
208     }
209
210     memcpy( p_key, dvd.disckey.value, 2048 );
211
212 #elif defined( HAVE_BSD_DVD_STRUCT )
213     struct dvd_struct dvd;
214
215     dvd.format = DVD_STRUCT_DISCKEY;
216     dvd.agid = *pi_agid;
217     memset( dvd.data, 0, 2048 );
218
219     i_ret = ioctl( i_fd, DVDIOCREADSTRUCTURE, &dvd );
220
221     if( i_ret < 0 )
222     {
223         return i_ret;
224     }
225
226     memcpy( p_key, dvd.data, 2048 );
227
228 #elif defined( SYS_BEOS )
229     INIT_RDC( GPCMD_READ_DVD_STRUCTURE, 2048 + 4 );
230
231     rdc.command[ 7 ]  = DVD_STRUCT_DISCKEY;
232     rdc.command[ 10 ] = *pi_agid << 6;
233     
234     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
235
236     if( i_ret < 0 )
237     {
238         return i_ret;
239     }
240
241     memcpy( p_key, p_buffer + 4, 2048 );
242
243 #elif defined( SYS_DARWIN )
244     i_ret = 0;
245
246     memset( p_key, 0x00, 2048 );
247
248 #elif defined( WIN32 )
249     if( WIN2K ) /* NT/Win2000/Whistler */
250     {
251         DWORD tmp;
252         u8 buffer[DVD_DISK_KEY_LENGTH];
253         PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
254
255         memset( &buffer, 0, sizeof( buffer ) );
256
257         key->KeyLength  = DVD_DISK_KEY_LENGTH;
258         key->SessionId  = *pi_agid;
259         key->KeyType    = DvdDiskKey;
260         key->KeyFlags   = 0;
261
262         i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key, 
263                 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
264
265         if( i_ret < 0 )
266         {   
267             return i_ret;
268         }
269
270         memcpy( p_key, key->KeyData, 2048 );
271     }
272     else
273     {
274         INIT_SSC( GPCMD_READ_DVD_STRUCTURE, 2048 + 4 );
275
276         ssc.CDBByte[ 7 ]  = DVD_STRUCT_DISCKEY;
277         ssc.CDBByte[ 10 ] = *pi_agid << 6;
278     
279         i_ret = WinSendSSC( i_fd, &ssc );
280
281         if( i_ret < 0 )
282         {
283             return i_ret;
284         }
285
286         memcpy( p_key, p_buffer + 4, 2048 );
287     }
288
289 #else
290     /* DVD ioctls unavailable - do as if the ioctl failed */
291     i_ret = -1;
292
293 #endif
294     return i_ret;
295 }
296
297 /*****************************************************************************
298  * ioctl_ReportAgid: get AGID from the drive
299  *****************************************************************************/
300 int ioctl_ReportAgid( int i_fd, int *pi_agid )
301 {
302     int i_ret;
303
304 #if defined( HAVE_LINUX_DVD_STRUCT )
305     dvd_authinfo auth_info;
306
307     auth_info.type = DVD_LU_SEND_AGID;
308     auth_info.lsa.agid = *pi_agid;
309
310     i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
311
312     *pi_agid = auth_info.lsa.agid;
313
314 #elif defined( HAVE_BSD_DVD_STRUCT )
315     struct dvd_authinfo auth_info;
316
317     auth_info.format = DVD_REPORT_AGID;
318     auth_info.agid = *pi_agid;
319
320     i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
321
322     *pi_agid = auth_info.agid;
323
324 #elif defined( SYS_BEOS )
325     INIT_RDC( GPCMD_REPORT_KEY, 8 );
326
327     rdc.command[ 10 ] = DVD_REPORT_AGID | (*pi_agid << 6);
328
329     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
330
331     *pi_agid = p_buffer[ 7 ] >> 6;
332
333 #elif defined( SYS_DARWIN )
334     INIT_DVDIOCTL( 8 );
335
336     dvdioctl.i_keyformat = kCSSAGID;
337     dvdioctl.i_agid = *pi_agid;
338     dvdioctl.i_lba = 0;
339
340     i_ret = ioctl( i_fd, IODVD_REPORT_KEY, &dvdioctl );
341
342     *pi_agid = p_buffer[ 7 ] >> 6;
343
344 #elif defined( WIN32 )
345     if( WIN2K ) /* NT/Win2000/Whistler */
346     {
347         ULONG id;
348         DWORD tmp;
349
350         i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_START_SESSION, 
351                         &tmp, 4, &id, sizeof( id ), &tmp, NULL ) ? 0 : -1;
352
353         *pi_agid = id;
354     }
355     else
356     {
357         INIT_SSC( GPCMD_REPORT_KEY, 8 );
358
359         ssc.CDBByte[ 10 ] = DVD_REPORT_AGID | (*pi_agid << 6);
360
361         i_ret = WinSendSSC( i_fd, &ssc );
362
363         *pi_agid = p_buffer[ 7 ] >> 6;
364     }
365
366 #else
367     /* DVD ioctls unavailable - do as if the ioctl failed */
368     i_ret = -1;
369
370 #endif
371     return i_ret;
372 }
373
374 /*****************************************************************************
375  * ioctl_ReportChallenge: get challenge from the drive
376  *****************************************************************************/
377 int ioctl_ReportChallenge( int i_fd, int *pi_agid, u8 *p_challenge )
378 {
379     int i_ret;
380
381 #if defined( HAVE_LINUX_DVD_STRUCT )
382     dvd_authinfo auth_info;
383
384     auth_info.type = DVD_LU_SEND_CHALLENGE;
385     auth_info.lsc.agid = *pi_agid;
386
387     i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
388
389     memcpy( p_challenge, auth_info.lsc.chal, sizeof(dvd_challenge) );
390
391 #elif defined( HAVE_BSD_DVD_STRUCT )
392     struct dvd_authinfo auth_info;
393
394     auth_info.format = DVD_REPORT_CHALLENGE;
395     auth_info.agid = *pi_agid;
396
397     i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
398
399     memcpy( p_challenge, auth_info.keychal, 10 );
400
401 #elif defined( SYS_BEOS )
402     INIT_RDC( GPCMD_REPORT_KEY, 16 );
403
404     rdc.command[ 10 ] = DVD_REPORT_CHALLENGE | (*pi_agid << 6);
405
406     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
407
408     memcpy( p_challenge, p_buffer + 4, 12 );
409
410 #elif defined( SYS_DARWIN )
411     INIT_DVDIOCTL( 16 );
412
413     dvdioctl.i_keyformat = kChallengeKey;
414     dvdioctl.i_agid = *pi_agid;
415     dvdioctl.i_lba = 0;
416
417     i_ret = ioctl( i_fd, IODVD_REPORT_KEY, &dvdioctl );
418
419     memcpy( p_challenge, p_buffer + 4, 12 );
420
421 #elif defined( WIN32 )
422     if( WIN2K ) /* NT/Win2000/Whistler */
423     {
424         DWORD tmp;
425         u8 buffer[DVD_CHALLENGE_KEY_LENGTH];
426         PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
427
428         memset( &buffer, 0, sizeof( buffer ) );
429
430         key->KeyLength  = DVD_CHALLENGE_KEY_LENGTH;
431         key->SessionId  = *pi_agid;
432         key->KeyType    = DvdChallengeKey;
433         key->KeyFlags   = 0;
434
435         i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key, 
436                 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
437
438         if( i_ret < 0 )
439         {
440             return i_ret;
441         }
442
443         memcpy( p_challenge, key->KeyData, 10 );
444     }
445     else
446     {
447         INIT_SSC( GPCMD_REPORT_KEY, 16 );
448
449         ssc.CDBByte[ 10 ] = DVD_REPORT_CHALLENGE | (*pi_agid << 6);
450
451         i_ret = WinSendSSC( i_fd, &ssc );
452
453         memcpy( p_challenge, p_buffer + 4, 12 );
454     }
455
456 #else
457     /* DVD ioctls unavailable - do as if the ioctl failed */
458     i_ret = -1;
459
460 #endif
461     return i_ret;
462 }
463
464 /*****************************************************************************
465  * ioctl_ReportASF: get ASF from the drive
466  *****************************************************************************/
467 int ioctl_ReportASF( int i_fd, int *pi_agid, int *pi_asf )
468 {
469     int i_ret;
470
471 #if defined( HAVE_LINUX_DVD_STRUCT )
472     dvd_authinfo auth_info;
473
474     auth_info.type = DVD_LU_SEND_ASF;
475     auth_info.lsasf.agid = *pi_agid;
476     auth_info.lsasf.asf = *pi_asf;
477
478     i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
479
480     *pi_asf = auth_info.lsasf.asf;
481
482 #elif defined( HAVE_BSD_DVD_STRUCT )
483     struct dvd_authinfo auth_info;
484
485     auth_info.format = DVD_REPORT_ASF;
486     auth_info.agid = *pi_agid;
487     auth_info.asf = *pi_asf;
488
489     i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
490
491     *pi_asf = auth_info.asf;
492
493 #elif defined( SYS_BEOS )
494     INIT_RDC( GPCMD_REPORT_KEY, 8 );
495
496     rdc.command[ 10 ] = DVD_REPORT_ASF | (*pi_agid << 6);
497
498     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
499
500     *pi_asf = p_buffer[ 7 ] & 1;
501
502 #elif defined( SYS_DARWIN )
503     INIT_DVDIOCTL( 8 );
504
505     dvdioctl.i_keyformat = kASF;
506     dvdioctl.i_agid = *pi_agid;
507     dvdioctl.i_lba = 0;
508
509     i_ret = ioctl( i_fd, IODVD_REPORT_KEY, &dvdioctl );
510
511     *pi_asf = p_buffer[ 7 ] & 1;
512
513 #elif defined( WIN32 )
514     if( WIN2K ) /* NT/Win2000/Whistler */
515     {
516         DWORD tmp;
517         u8 buffer[DVD_ASF_LENGTH];
518         PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
519
520         memset( &buffer, 0, sizeof( buffer ) );
521
522         key->KeyLength  = DVD_ASF_LENGTH;
523         key->SessionId  = *pi_agid;
524         key->KeyType    = DvdAsf;
525         key->KeyFlags   = 0;
526
527         ((PDVD_ASF)key->KeyData)->SuccessFlag = *pi_asf;
528
529         i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key, 
530                 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
531
532         if( i_ret < 0 )
533         {
534             return i_ret;
535         }
536
537         *pi_asf = ((PDVD_ASF)key->KeyData)->SuccessFlag;
538     }
539     else
540     {
541         INIT_SSC( GPCMD_REPORT_KEY, 8 );
542
543         ssc.CDBByte[ 10 ] = DVD_REPORT_ASF | (*pi_agid << 6);
544
545         i_ret = WinSendSSC( i_fd, &ssc );
546
547         *pi_asf = p_buffer[ 7 ] & 1;
548     }
549
550 #else
551     /* DVD ioctls unavailable - do as if the ioctl failed */
552     i_ret = -1;
553
554 #endif
555     return i_ret;
556 }
557
558 /*****************************************************************************
559  * ioctl_ReportKey1: get the first key from the drive
560  *****************************************************************************/
561 int ioctl_ReportKey1( int i_fd, int *pi_agid, u8 *p_key )
562 {
563     int i_ret;
564
565 #if defined( HAVE_LINUX_DVD_STRUCT )
566     dvd_authinfo auth_info;
567
568     auth_info.type = DVD_LU_SEND_KEY1;
569     auth_info.lsk.agid = *pi_agid;
570
571     i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
572
573     memcpy( p_key, auth_info.lsk.key, sizeof(dvd_key) );
574
575 #elif defined( HAVE_BSD_DVD_STRUCT )
576     struct dvd_authinfo auth_info;
577
578     auth_info.format = DVD_REPORT_KEY1;
579     auth_info.agid = *pi_agid;
580
581     i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
582
583     memcpy( p_key, auth_info.keychal, 8 );
584
585 #elif defined( SYS_BEOS )
586     INIT_RDC( GPCMD_REPORT_KEY, 12 );
587
588     rdc.command[ 10 ] = DVD_REPORT_KEY1 | (*pi_agid << 6);
589
590     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
591
592     memcpy( p_key, p_buffer + 4, 8 );
593
594 #elif defined( SYS_DARWIN )
595     INIT_DVDIOCTL( 12 );
596
597     dvdioctl.i_keyformat = kKey1;
598     dvdioctl.i_agid = *pi_agid;
599
600     i_ret = ioctl( i_fd, IODVD_SEND_KEY, &dvdioctl );
601
602     memcpy( p_key, p_buffer + 4, 8 );
603
604 #elif defined( WIN32 )
605     if( WIN2K ) /* NT/Win2000/Whistler */
606     {
607         DWORD tmp;
608         u8 buffer[DVD_BUS_KEY_LENGTH];
609         PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
610
611         memset( &buffer, 0, sizeof( buffer ) );
612
613         key->KeyLength  = DVD_BUS_KEY_LENGTH;
614         key->SessionId  = *pi_agid;
615         key->KeyType    = DvdBusKey1;
616         key->KeyFlags   = 0;
617
618         i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key, 
619                 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
620
621         memcpy( p_key, key->KeyData, 8 );
622     }
623     else
624     {
625         INIT_SSC( GPCMD_REPORT_KEY, 12 );
626
627         ssc.CDBByte[ 10 ] = DVD_REPORT_KEY1 | (*pi_agid << 6);
628
629         i_ret = WinSendSSC( i_fd, &ssc );
630
631         memcpy( p_key, p_buffer + 4, 8 );
632     }
633
634 #else
635     /* DVD ioctls unavailable - do as if the ioctl failed */
636     i_ret = -1;
637
638 #endif
639     return i_ret;
640 }
641
642 /*****************************************************************************
643  * ioctl_InvalidateAgid: invalidate the current AGID
644  *****************************************************************************/
645 int ioctl_InvalidateAgid( int i_fd, int *pi_agid )
646 {
647     int i_ret;
648
649 #if defined( HAVE_LINUX_DVD_STRUCT )
650     dvd_authinfo auth_info;
651
652     auth_info.type = DVD_INVALIDATE_AGID;
653     auth_info.lsa.agid = *pi_agid;
654
655     i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
656
657     *pi_agid = auth_info.lsa.agid;
658
659 #elif defined( HAVE_BSD_DVD_STRUCT )
660     struct dvd_authinfo auth_info;
661
662     auth_info.format = DVD_INVALIDATE_AGID;
663     auth_info.agid = *pi_agid;
664
665     i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
666
667     *pi_agid = auth_info.agid;
668
669 #elif defined( SYS_BEOS )
670     INIT_RDC( GPCMD_REPORT_KEY, 0 );
671
672     rdc.command[ 10 ] = DVD_INVALIDATE_AGID | (*pi_agid << 6);
673
674     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
675
676 #elif defined( SYS_DARWIN )
677     INIT_DVDIOCTL( 0 );
678
679     dvdioctl.i_keyformat = kInvalidateAGID;
680     dvdioctl.i_agid = *pi_agid;
681
682     i_ret = ioctl( i_fd, IODVD_SEND_KEY, &dvdioctl );
683
684 #elif defined( WIN32 )
685     if( WIN2K ) /* NT/Win2000/Whistler */
686     {
687         DWORD tmp;
688
689         i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_END_SESSION, 
690                     pi_agid, sizeof( *pi_agid ), NULL, 0, &tmp, NULL ) ? 0 : -1;
691     }
692     else
693     {
694 #if defined( __MINGW32__ )
695         INIT_SSC( GPCMD_REPORT_KEY, 0 );
696 #else
697         INIT_SSC( GPCMD_REPORT_KEY, 1 );
698
699         ssc.SRB_BufLen    = 0;
700         ssc.CDBByte[ 8 ]  = 0;
701         ssc.CDBByte[ 9 ]  = 0;
702 #endif
703
704         ssc.CDBByte[ 10 ] = DVD_INVALIDATE_AGID | (*pi_agid << 6);
705
706         i_ret = WinSendSSC( i_fd, &ssc );
707     }
708
709 #else
710     /* DVD ioctls unavailable - do as if the ioctl failed */
711     i_ret = -1;
712
713 #endif
714     return i_ret;
715 }
716
717 /*****************************************************************************
718  * ioctl_SendChallenge: send challenge to the drive
719  *****************************************************************************/
720 int ioctl_SendChallenge( int i_fd, int *pi_agid, u8 *p_challenge )
721 {
722 #if defined( HAVE_LINUX_DVD_STRUCT )
723     dvd_authinfo auth_info;
724
725     auth_info.type = DVD_HOST_SEND_CHALLENGE;
726     auth_info.hsc.agid = *pi_agid;
727
728     memcpy( auth_info.hsc.chal, p_challenge, sizeof(dvd_challenge) );
729
730     return ioctl( i_fd, DVD_AUTH, &auth_info );
731
732 #elif defined( HAVE_BSD_DVD_STRUCT )
733     struct dvd_authinfo auth_info;
734
735     auth_info.format = DVD_SEND_CHALLENGE;
736     auth_info.agid = *pi_agid;
737
738     memcpy( auth_info.keychal, p_challenge, 12 );
739
740     return ioctl( i_fd, DVDIOCSENDKEY, &auth_info );
741
742 #elif defined( SYS_BEOS )
743     INIT_RDC( GPCMD_SEND_KEY, 16 );
744
745     rdc.command[ 10 ] = DVD_SEND_CHALLENGE | (*pi_agid << 6);
746
747     p_buffer[ 1 ] = 0xe;
748     memcpy( p_buffer + 4, p_challenge, 12 );
749
750     return ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
751
752 #elif defined( SYS_DARWIN )
753     INIT_DVDIOCTL( 16 );
754
755     dvdioctl.i_keyformat = kChallengeKey;
756     dvdioctl.i_agid = *pi_agid;
757
758     p_buffer[ 1 ] = 0xe;
759     memcpy( p_buffer + 4, p_challenge, 12 );
760
761     return ioctl( i_fd, IODVD_SEND_KEY, &dvdioctl );
762
763 #elif defined( WIN32 )
764     if( WIN2K ) /* NT/Win2000/Whistler */
765     {
766         DWORD tmp;
767         u8 buffer[DVD_CHALLENGE_KEY_LENGTH];
768         PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
769
770         memset( &buffer, 0, sizeof( buffer ) );
771
772         key->KeyLength  = DVD_CHALLENGE_KEY_LENGTH;
773         key->SessionId  = *pi_agid;
774         key->KeyType    = DvdChallengeKey;
775         key->KeyFlags   = 0;
776
777         memcpy( key->KeyData, p_challenge, 10 );
778
779         return DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_SEND_KEY, key, 
780                 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
781     }
782     else
783     {
784         INIT_SSC( GPCMD_SEND_KEY, 16 );
785
786         ssc.CDBByte[ 10 ] = DVD_SEND_CHALLENGE | (*pi_agid << 6);
787
788         p_buffer[ 1 ] = 0xe;
789         memcpy( p_buffer + 4, p_challenge, 12 );
790
791         return WinSendSSC( i_fd, &ssc );
792     }
793
794 #else
795     /* DVD ioctls unavailable - do as if the ioctl failed */
796     return -1;
797
798 #endif
799 }
800
801 /*****************************************************************************
802  * ioctl_SendKey2: send the second key to the drive
803  *****************************************************************************/
804 int ioctl_SendKey2( int i_fd, int *pi_agid, u8 *p_key )
805 {
806 #if defined( HAVE_LINUX_DVD_STRUCT )
807     dvd_authinfo auth_info;
808
809     auth_info.type = DVD_HOST_SEND_KEY2;
810     auth_info.hsk.agid = *pi_agid;
811
812     memcpy( auth_info.hsk.key, p_key, sizeof(dvd_key) );
813
814     return ioctl( i_fd, DVD_AUTH, &auth_info );
815
816 #elif defined( HAVE_BSD_DVD_STRUCT )
817     struct dvd_authinfo auth_info;
818
819     auth_info.format = DVD_SEND_KEY2;
820     auth_info.agid = *pi_agid;
821
822     memcpy( auth_info.keychal, p_key, 8 );
823
824     return ioctl( i_fd, DVDIOCSENDKEY, &auth_info );
825
826 #elif defined( SYS_BEOS )
827     INIT_RDC( GPCMD_SEND_KEY, 12 );
828
829     rdc.command[ 10 ] = DVD_SEND_KEY2 | (*pi_agid << 6);
830
831     p_buffer[ 1 ] = 0xa;
832     memcpy( p_buffer + 4, p_key, 8 );
833
834     return ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
835
836 #elif defined( WIN32 )
837     if( WIN2K ) /* NT/Win2000/Whistler */
838     {
839         DWORD tmp;
840         u8 buffer[DVD_BUS_KEY_LENGTH];
841         PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
842
843         memset( &buffer, 0, sizeof( buffer ) );
844
845         key->KeyLength  = DVD_BUS_KEY_LENGTH;
846         key->SessionId  = *pi_agid;
847         key->KeyType    = DvdBusKey2;
848         key->KeyFlags   = 0;
849
850         memcpy( key->KeyData, p_key, 8 );
851
852         return DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_SEND_KEY, key, 
853                 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
854     }
855     else
856     {
857         INIT_SSC( GPCMD_SEND_KEY, 12 );
858
859         ssc.CDBByte[ 10 ] = DVD_SEND_KEY2 | (*pi_agid << 6);
860
861         p_buffer[ 1 ] = 0xa;
862         memcpy( p_buffer + 4, p_key, 8 );
863
864         return WinSendSSC( i_fd, &ssc );
865     }
866
867 #elif defined( SYS_DARWIN )
868     INIT_DVDIOCTL( 12 );
869
870     dvdioctl.i_keyformat = kKey2;
871     dvdioctl.i_agid = *pi_agid;
872
873     p_buffer[ 1 ] = 0xa;
874     memcpy( p_buffer + 4, p_key, 8 );
875
876     return ioctl( i_fd, IODVD_SEND_KEY, &dvdioctl );
877
878 #else
879     /* DVD ioctls unavailable - do as if the ioctl failed */
880     return -1;
881
882 #endif
883 }
884
885 /* Local prototypes */
886
887 #if defined( SYS_BEOS )
888 /*****************************************************************************
889  * BeInitRDC: initialize a RDC structure for the BeOS kernel
890  *****************************************************************************
891  * This function initializes a BeOS raw device command structure for future
892  * use, either a read command or a write command.
893  *****************************************************************************/
894 static void BeInitRDC( raw_device_command *p_rdc, int i_type )
895 {
896     memset( p_rdc->data, 0, p_rdc->data_length );
897
898     switch( i_type )
899     {
900         case GPCMD_SEND_KEY:
901             /* leave the flags to 0 */
902             break;
903
904         case GPCMD_READ_DVD_STRUCTURE:
905         case GPCMD_REPORT_KEY:
906             p_rdc->flags = B_RAW_DEVICE_DATA_IN;
907             break;
908     }
909
910     p_rdc->command[ 0 ]      = i_type;
911
912     p_rdc->command[ 8 ]      = (p_rdc->data_length >> 8) & 0xff;
913     p_rdc->command[ 9 ]      =  p_rdc->data_length       & 0xff;
914     p_rdc->command_length    = 12;
915
916     p_rdc->sense_data        = NULL;
917     p_rdc->sense_data_length = 0;
918
919     p_rdc->timeout           = 1000000;
920 }
921 #endif
922
923 #if defined( WIN32 )
924 /*****************************************************************************
925  * WinInitSSC: initialize a ssc structure for the win32 aspi layer
926  *****************************************************************************
927  * This function initializes a ssc raw device command structure for future
928  * use, either a read command or a write command.
929  *****************************************************************************/
930 static void WinInitSSC( struct SRB_ExecSCSICmd *p_ssc, int i_type )
931 {
932     memset( p_ssc->SRB_BufPointer, 0, p_ssc->SRB_BufLen );
933
934     switch( i_type )
935     {
936         case GPCMD_SEND_KEY:
937             p_ssc->SRB_Flags = SRB_DIR_OUT;
938             break;
939
940         case GPCMD_READ_DVD_STRUCTURE:
941         case GPCMD_REPORT_KEY:
942             p_ssc->SRB_Flags = SRB_DIR_IN;
943             break;
944     }
945
946     p_ssc->SRB_Cmd      = SC_EXEC_SCSI_CMD;
947     p_ssc->SRB_Flags    |= SRB_EVENT_NOTIFY;
948
949     p_ssc->CDBByte[ 0 ] = i_type;
950
951     p_ssc->CDBByte[ 8 ] = (u8)(p_ssc->SRB_BufLen >> 8) & 0xff;
952     p_ssc->CDBByte[ 9 ] = (u8) p_ssc->SRB_BufLen       & 0xff;
953     p_ssc->SRB_CDBLen   = 12;
954
955     p_ssc->SRB_SenseLen = SENSE_LEN;
956 }
957
958 /*****************************************************************************
959  * WinSendSSC: send a ssc structure to the aspi layer
960  *****************************************************************************/
961 static int WinSendSSC( int i_fd, struct SRB_ExecSCSICmd *p_ssc )
962 {
963     HANDLE hEvent = NULL;
964     struct w32_aspidev *fd = (struct w32_aspidev *) i_fd;
965
966     hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
967     if( hEvent == NULL )
968     {
969         return -1;
970     }
971
972     p_ssc->SRB_PostProc  = hEvent;
973     p_ssc->SRB_HaId      = LOBYTE( fd->i_sid );
974     p_ssc->SRB_Target    = HIBYTE( fd->i_sid );
975
976     ResetEvent( hEvent );
977     if( fd->lpSendCommand( (void*) p_ssc ) == SS_PENDING )
978         WaitForSingleObject( hEvent, INFINITE );
979
980     CloseHandle( hEvent );
981
982     return p_ssc->SRB_Status == SS_COMP ? 0 : -1;
983 }
984 #endif
985