]> git.sesse.net Git - vlc/blob - extras/libdvdcss/ioctl.c
* QNX RTOS plug-in by Jon Lech Johansen.
[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.4 2001/07/19 11:50:50 massiot 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 SYS_BEOS
52 #   include <malloc.h>
53 #   include <scsi.h>
54 #endif
55
56 #include "config.h"
57 #include "common.h"
58
59 #ifdef SYS_DARWIN
60 #   include "DVDioctl/DVDioctl.h"
61 #endif
62
63 #include "ioctl.h"
64
65 /*****************************************************************************
66  * Local prototypes, BeOS specific
67  *****************************************************************************/
68 #if defined( SYS_BEOS )
69 static void BeInitRDC ( raw_device_command *, int );
70 #endif
71
72 /*****************************************************************************
73  * Local prototypes, win32 (aspi) specific
74  *****************************************************************************/
75 #if defined( WIN32 )
76 static void WinInitSSC ( struct SRB_ExecSCSICmd *, int );
77 static int  WinSendSSC ( int, struct SRB_ExecSCSICmd * );
78 #endif
79
80 /*****************************************************************************
81  * ioctl_ReadCopyright: check whether the disc is encrypted or not
82  *****************************************************************************/
83 int ioctl_ReadCopyright( int i_fd, int i_layer, int *pi_copyright )
84 {
85     int i_ret;
86
87 #if defined( DVD_STRUCT_IN_LINUX_CDROM_H )
88     dvd_struct dvd;
89
90     dvd.type = DVD_STRUCT_COPYRIGHT;
91     dvd.copyright.layer_num = i_layer;
92
93     i_ret = ioctl( i_fd, DVD_READ_STRUCT, &dvd );
94
95     *pi_copyright = dvd.copyright.cpst;
96
97 #elif defined( HAVE_BSD_DVD_STRUCT )
98     struct dvd_struct dvd;
99
100     dvd.format = DVD_STRUCT_COPYRIGHT;
101     dvd.layer_num = i_layer;
102
103     i_ret = ioctl( i_fd, DVDIOCREADSTRUCTURE, &dvd );
104
105     *pi_copyright = dvd.cpst;
106
107 #elif defined( SYS_BEOS )
108     INIT_RDC( GPCMD_READ_DVD_STRUCTURE, 8 );
109
110     rdc.command[ 6 ] = i_layer;
111     rdc.command[ 7 ] = DVD_STRUCT_COPYRIGHT;
112
113     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
114
115     *pi_copyright = p_buffer[ 4 ];
116
117 #elif defined( SYS_DARWIN )
118     _dvd_error( dvdcss, "DVD ioctls not fully functional yet, "
119                            "assuming disc is encrypted" );
120
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( DVD_STRUCT_IN_LINUX_CDROM_H )
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     _dvd_error( dvdcss, "DVD ioctls not fully functional yet, "
245                            "sending an empty key" );
246
247     i_ret = 0;
248
249     memset( p_key, 0x00, 2048 );
250
251 #elif defined( WIN32 )
252     if( WIN2K ) /* NT/Win2000/Whistler */
253     {
254         DWORD tmp;
255         u8 buffer[DVD_DISK_KEY_LENGTH];
256         PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
257
258         memset( &buffer, 0, sizeof( buffer ) );
259
260         key->KeyLength  = DVD_DISK_KEY_LENGTH;
261         key->SessionId  = *pi_agid;
262         key->KeyType    = DvdDiskKey;
263         key->KeyFlags   = 0;
264
265         i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key, 
266                 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
267
268         if( i_ret < 0 )
269         {   
270             return i_ret;
271         }
272
273         memcpy( p_key, key->KeyData, 2048 );
274     }
275     else
276     {
277         INIT_SSC( GPCMD_READ_DVD_STRUCTURE, 2048 + 4 );
278
279         ssc.CDBByte[ 7 ]  = DVD_STRUCT_DISCKEY;
280         ssc.CDBByte[ 10 ] = *pi_agid << 6;
281     
282         i_ret = WinSendSSC( i_fd, &ssc );
283
284         if( i_ret < 0 )
285         {
286             return i_ret;
287         }
288
289         memcpy( p_key, p_buffer + 4, 2048 );
290     }
291
292 #else
293     /* DVD ioctls unavailable - do as if the ioctl failed */
294     i_ret = -1;
295
296 #endif
297     return i_ret;
298 }
299
300 /*****************************************************************************
301  * ioctl_ReportAgid: get AGID from the drive
302  *****************************************************************************/
303 int ioctl_ReportAgid( int i_fd, int *pi_agid )
304 {
305     int i_ret;
306
307 #if defined( DVD_STRUCT_IN_LINUX_CDROM_H )
308     dvd_authinfo auth_info;
309
310     auth_info.type = DVD_LU_SEND_AGID;
311     auth_info.lsa.agid = *pi_agid;
312
313     i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
314
315     *pi_agid = auth_info.lsa.agid;
316
317 #elif defined( HAVE_BSD_DVD_STRUCT )
318     struct dvd_authinfo auth_info;
319
320     auth_info.format = DVD_REPORT_AGID;
321     auth_info.agid = *pi_agid;
322
323     i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
324
325     *pi_agid = auth_info.agid;
326
327 #elif defined( SYS_BEOS )
328     INIT_RDC( GPCMD_REPORT_KEY, 8 );
329
330     rdc.command[ 10 ] = DVD_REPORT_AGID | (*pi_agid << 6);
331
332     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
333
334     *pi_agid = p_buffer[ 7 ] >> 6;
335
336 #elif defined( SYS_DARWIN )
337     INIT_DVDIOCTL( 8 );
338
339     dvdioctl.i_keyformat = kCSSAGID;
340     dvdioctl.i_agid = *pi_agid;
341     dvdioctl.i_lba = 0;
342
343     i_ret = ioctl( i_fd, IODVD_REPORT_KEY, &dvdioctl );
344
345     *pi_agid = p_buffer[ 7 ] >> 6;
346
347 #elif defined( WIN32 )
348     if( WIN2K ) /* NT/Win2000/Whistler */
349     {
350         ULONG id;
351         DWORD tmp;
352
353         i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_START_SESSION, 
354                         &tmp, 4, &id, sizeof( id ), &tmp, NULL ) ? 0 : -1;
355
356         *pi_agid = id;
357     }
358     else
359     {
360         INIT_SSC( GPCMD_REPORT_KEY, 8 );
361
362         ssc.CDBByte[ 10 ] = DVD_REPORT_AGID | (*pi_agid << 6);
363
364         i_ret = WinSendSSC( i_fd, &ssc );
365
366         *pi_agid = p_buffer[ 7 ] >> 6;
367     }
368
369 #else
370     /* DVD ioctls unavailable - do as if the ioctl failed */
371     i_ret = -1;
372
373 #endif
374     return i_ret;
375 }
376
377 /*****************************************************************************
378  * ioctl_ReportChallenge: get challenge from the drive
379  *****************************************************************************/
380 int ioctl_ReportChallenge( int i_fd, int *pi_agid, u8 *p_challenge )
381 {
382     int i_ret;
383
384 #if defined( DVD_STRUCT_IN_LINUX_CDROM_H )
385     dvd_authinfo auth_info;
386
387     auth_info.type = DVD_LU_SEND_CHALLENGE;
388     auth_info.lsc.agid = *pi_agid;
389
390     i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
391
392     memcpy( p_challenge, auth_info.lsc.chal, sizeof(dvd_challenge) );
393
394 #elif defined( HAVE_BSD_DVD_STRUCT )
395     struct dvd_authinfo auth_info;
396
397     auth_info.format = DVD_REPORT_CHALLENGE;
398     auth_info.agid = *pi_agid;
399
400     i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
401
402     memcpy( p_challenge, auth_info.keychal, 10 );
403
404 #elif defined( SYS_BEOS )
405     INIT_RDC( GPCMD_REPORT_KEY, 16 );
406
407     rdc.command[ 10 ] = DVD_REPORT_CHALLENGE | (*pi_agid << 6);
408
409     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
410
411     memcpy( p_challenge, p_buffer + 4, 12 );
412
413 #elif defined( SYS_DARWIN )
414     INIT_DVDIOCTL( 16 );
415
416     dvdioctl.i_keyformat = kChallengeKey;
417     dvdioctl.i_agid = *pi_agid;
418     dvdioctl.i_lba = 0;
419
420     i_ret = ioctl( i_fd, IODVD_REPORT_KEY, &dvdioctl );
421
422     memcpy( p_challenge, p_buffer + 4, 12 );
423
424 #elif defined( WIN32 )
425     if( WIN2K ) /* NT/Win2000/Whistler */
426     {
427         DWORD tmp;
428         u8 buffer[DVD_CHALLENGE_KEY_LENGTH];
429         PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
430
431         memset( &buffer, 0, sizeof( buffer ) );
432
433         key->KeyLength  = DVD_CHALLENGE_KEY_LENGTH;
434         key->SessionId  = *pi_agid;
435         key->KeyType    = DvdChallengeKey;
436         key->KeyFlags   = 0;
437
438         i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key, 
439                 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
440
441         if( i_ret < 0 )
442         {
443             return i_ret;
444         }
445
446         memcpy( p_challenge, key->KeyData, 10 );
447     }
448     else
449     {
450         INIT_SSC( GPCMD_REPORT_KEY, 16 );
451
452         ssc.CDBByte[ 10 ] = DVD_REPORT_CHALLENGE | (*pi_agid << 6);
453
454         i_ret = WinSendSSC( i_fd, &ssc );
455
456         memcpy( p_challenge, p_buffer + 4, 12 );
457     }
458
459 #else
460     /* DVD ioctls unavailable - do as if the ioctl failed */
461     i_ret = -1;
462
463 #endif
464     return i_ret;
465 }
466
467 /*****************************************************************************
468  * ioctl_ReportASF: get ASF from the drive
469  *****************************************************************************/
470 int ioctl_ReportASF( int i_fd, int *pi_agid, int *pi_asf )
471 {
472     int i_ret;
473
474 #if defined( DVD_STRUCT_IN_LINUX_CDROM_H )
475     dvd_authinfo auth_info;
476
477     auth_info.type = DVD_LU_SEND_ASF;
478     auth_info.lsasf.agid = *pi_agid;
479     auth_info.lsasf.asf = *pi_asf;
480
481     i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
482
483     *pi_asf = auth_info.lsasf.asf;
484
485 #elif defined( HAVE_BSD_DVD_STRUCT )
486     struct dvd_authinfo auth_info;
487
488     auth_info.format = DVD_REPORT_ASF;
489     auth_info.agid = *pi_agid;
490     auth_info.asf = *pi_asf;
491
492     i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
493
494     *pi_asf = auth_info.asf;
495
496 #elif defined( SYS_BEOS )
497     INIT_RDC( GPCMD_REPORT_KEY, 8 );
498
499     rdc.command[ 10 ] = DVD_REPORT_ASF | (*pi_agid << 6);
500
501     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
502
503     *pi_asf = p_buffer[ 7 ] & 1;
504
505 #elif defined( SYS_DARWIN )
506     INIT_DVDIOCTL( 8 );
507
508     dvdioctl.i_keyformat = kASF;
509     dvdioctl.i_agid = *pi_agid;
510     dvdioctl.i_lba = 0;
511
512     i_ret = ioctl( i_fd, IODVD_REPORT_KEY, &dvdioctl );
513
514     *pi_asf = p_buffer[ 7 ] & 1;
515
516 #elif defined( WIN32 )
517     if( WIN2K ) /* NT/Win2000/Whistler */
518     {
519         DWORD tmp;
520         u8 buffer[DVD_ASF_LENGTH];
521         PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
522
523         memset( &buffer, 0, sizeof( buffer ) );
524
525         key->KeyLength  = DVD_ASF_LENGTH;
526         key->SessionId  = *pi_agid;
527         key->KeyType    = DvdAsf;
528         key->KeyFlags   = 0;
529
530         ((PDVD_ASF)key->KeyData)->SuccessFlag = *pi_asf;
531
532         i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key, 
533                 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
534
535         if( i_ret < 0 )
536         {
537             return i_ret;
538         }
539
540         *pi_asf = ((PDVD_ASF)key->KeyData)->SuccessFlag;
541     }
542     else
543     {
544         INIT_SSC( GPCMD_REPORT_KEY, 8 );
545
546         ssc.CDBByte[ 10 ] = DVD_REPORT_ASF | (*pi_agid << 6);
547
548         i_ret = WinSendSSC( i_fd, &ssc );
549
550         *pi_asf = p_buffer[ 7 ] & 1;
551     }
552
553 #else
554     /* DVD ioctls unavailable - do as if the ioctl failed */
555     i_ret = -1;
556
557 #endif
558     return i_ret;
559 }
560
561 /*****************************************************************************
562  * ioctl_ReportKey1: get the first key from the drive
563  *****************************************************************************/
564 int ioctl_ReportKey1( int i_fd, int *pi_agid, u8 *p_key )
565 {
566     int i_ret;
567
568 #if defined( DVD_STRUCT_IN_LINUX_CDROM_H )
569     dvd_authinfo auth_info;
570
571     auth_info.type = DVD_LU_SEND_KEY1;
572     auth_info.lsk.agid = *pi_agid;
573
574     i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
575
576     memcpy( p_key, auth_info.lsk.key, sizeof(dvd_key) );
577
578 #elif defined( HAVE_BSD_DVD_STRUCT )
579     struct dvd_authinfo auth_info;
580
581     auth_info.format = DVD_REPORT_KEY1;
582     auth_info.agid = *pi_agid;
583
584     i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
585
586     memcpy( p_key, auth_info.keychal, 8 );
587
588 #elif defined( SYS_BEOS )
589     INIT_RDC( GPCMD_REPORT_KEY, 12 );
590
591     rdc.command[ 10 ] = DVD_REPORT_KEY1 | (*pi_agid << 6);
592
593     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
594
595     memcpy( p_key, p_buffer + 4, 8 );
596
597 #elif defined( SYS_DARWIN )
598     INIT_DVDIOCTL( 12 );
599
600     dvdioctl.i_keyformat = kKey1;
601     dvdioctl.i_agid = *pi_agid;
602
603     i_ret = ioctl( i_fd, IODVD_SEND_KEY, &dvdioctl );
604
605     memcpy( p_key, p_buffer + 4, 8 );
606
607 #elif defined( WIN32 )
608     if( WIN2K ) /* NT/Win2000/Whistler */
609     {
610         DWORD tmp;
611         u8 buffer[DVD_BUS_KEY_LENGTH];
612         PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
613
614         memset( &buffer, 0, sizeof( buffer ) );
615
616         key->KeyLength  = DVD_BUS_KEY_LENGTH;
617         key->SessionId  = *pi_agid;
618         key->KeyType    = DvdBusKey1;
619         key->KeyFlags   = 0;
620
621         i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key, 
622                 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
623
624         memcpy( p_key, key->KeyData, 8 );
625     }
626     else
627     {
628         INIT_SSC( GPCMD_REPORT_KEY, 12 );
629
630         ssc.CDBByte[ 10 ] = DVD_REPORT_KEY1 | (*pi_agid << 6);
631
632         i_ret = WinSendSSC( i_fd, &ssc );
633
634         memcpy( p_key, p_buffer + 4, 8 );
635     }
636
637 #else
638     /* DVD ioctls unavailable - do as if the ioctl failed */
639     i_ret = -1;
640
641 #endif
642     return i_ret;
643 }
644
645 /*****************************************************************************
646  * ioctl_InvalidateAgid: invalidate the current AGID
647  *****************************************************************************/
648 int ioctl_InvalidateAgid( int i_fd, int *pi_agid )
649 {
650     int i_ret;
651
652 #if defined( DVD_STRUCT_IN_LINUX_CDROM_H )
653     dvd_authinfo auth_info;
654
655     auth_info.type = DVD_INVALIDATE_AGID;
656     auth_info.lsa.agid = *pi_agid;
657
658     i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
659
660     *pi_agid = auth_info.lsa.agid;
661
662 #elif defined( HAVE_BSD_DVD_STRUCT )
663     struct dvd_authinfo auth_info;
664
665     auth_info.format = DVD_INVALIDATE_AGID;
666     auth_info.agid = *pi_agid;
667
668     i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
669
670     *pi_agid = auth_info.agid;
671
672 #elif defined( SYS_BEOS )
673     INIT_RDC( GPCMD_REPORT_KEY, 0 );
674
675     rdc.command[ 10 ] = DVD_INVALIDATE_AGID | (*pi_agid << 6);
676
677     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
678
679 #elif defined( SYS_DARWIN )
680     INIT_DVDIOCTL( 0 );
681
682     dvdioctl.i_keyformat = kInvalidateAGID;
683     dvdioctl.i_agid = *pi_agid;
684
685     i_ret = ioctl( i_fd, IODVD_SEND_KEY, &dvdioctl );
686
687 #elif defined( WIN32 )
688     if( WIN2K ) /* NT/Win2000/Whistler */
689     {
690         DWORD tmp;
691
692         i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_END_SESSION, 
693                     pi_agid, sizeof( *pi_agid ), NULL, 0, &tmp, NULL ) ? 0 : -1;
694     }
695     else
696     {
697 #if defined( __MINGW32__ )
698         INIT_SSC( GPCMD_REPORT_KEY, 0 );
699 #else
700         INIT_SSC( GPCMD_REPORT_KEY, 1 );
701
702         ssc.SRB_BufLen    = 0;
703         ssc.CDBByte[ 8 ]  = 0;
704         ssc.CDBByte[ 9 ]  = 0;
705 #endif
706
707         ssc.CDBByte[ 10 ] = DVD_INVALIDATE_AGID | (*pi_agid << 6);
708
709         i_ret = WinSendSSC( i_fd, &ssc );
710     }
711
712 #else
713     /* DVD ioctls unavailable - do as if the ioctl failed */
714     i_ret = -1;
715
716 #endif
717     return i_ret;
718 }
719
720 /*****************************************************************************
721  * ioctl_SendChallenge: send challenge to the drive
722  *****************************************************************************/
723 int ioctl_SendChallenge( int i_fd, int *pi_agid, u8 *p_challenge )
724 {
725 #if defined( DVD_STRUCT_IN_LINUX_CDROM_H )
726     dvd_authinfo auth_info;
727
728     auth_info.type = DVD_HOST_SEND_CHALLENGE;
729     auth_info.hsc.agid = *pi_agid;
730
731     memcpy( auth_info.hsc.chal, p_challenge, sizeof(dvd_challenge) );
732
733     return ioctl( i_fd, DVD_AUTH, &auth_info );
734
735 #elif defined( HAVE_BSD_DVD_STRUCT )
736     struct dvd_authinfo auth_info;
737
738     auth_info.format = DVD_SEND_CHALLENGE;
739     auth_info.agid = *pi_agid;
740
741     memcpy( auth_info.keychal, p_challenge, 12 );
742
743     return ioctl( i_fd, DVDIOCSENDKEY, &auth_info );
744
745 #elif defined( SYS_BEOS )
746     INIT_RDC( GPCMD_SEND_KEY, 16 );
747
748     rdc.command[ 10 ] = DVD_SEND_CHALLENGE | (*pi_agid << 6);
749
750     p_buffer[ 1 ] = 0xe;
751     memcpy( p_buffer + 4, p_challenge, 12 );
752
753     return ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
754
755 #elif defined( SYS_DARWIN )
756     INIT_DVDIOCTL( 16 );
757
758     dvdioctl.i_keyformat = kChallengeKey;
759     dvdioctl.i_agid = *pi_agid;
760
761     p_buffer[ 1 ] = 0xe;
762     memcpy( p_buffer + 4, p_challenge, 12 );
763
764     return ioctl( i_fd, IODVD_SEND_KEY, &dvdioctl );
765
766 #elif defined( WIN32 )
767     if( WIN2K ) /* NT/Win2000/Whistler */
768     {
769         DWORD tmp;
770         u8 buffer[DVD_CHALLENGE_KEY_LENGTH];
771         PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
772
773         memset( &buffer, 0, sizeof( buffer ) );
774
775         key->KeyLength  = DVD_CHALLENGE_KEY_LENGTH;
776         key->SessionId  = *pi_agid;
777         key->KeyType    = DvdChallengeKey;
778         key->KeyFlags   = 0;
779
780         memcpy( key->KeyData, p_challenge, 10 );
781
782         return DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_SEND_KEY, key, 
783                 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
784     }
785     else
786     {
787         INIT_SSC( GPCMD_SEND_KEY, 16 );
788
789         ssc.CDBByte[ 10 ] = DVD_SEND_CHALLENGE | (*pi_agid << 6);
790
791         p_buffer[ 1 ] = 0xe;
792         memcpy( p_buffer + 4, p_challenge, 12 );
793
794         return WinSendSSC( i_fd, &ssc );
795     }
796
797 #else
798     /* DVD ioctls unavailable - do as if the ioctl failed */
799     return -1;
800
801 #endif
802 }
803
804 /*****************************************************************************
805  * ioctl_SendKey2: send the second key to the drive
806  *****************************************************************************/
807 int ioctl_SendKey2( int i_fd, int *pi_agid, u8 *p_key )
808 {
809 #if defined( DVD_STRUCT_IN_LINUX_CDROM_H )
810     dvd_authinfo auth_info;
811
812     auth_info.type = DVD_HOST_SEND_KEY2;
813     auth_info.hsk.agid = *pi_agid;
814
815     memcpy( auth_info.hsk.key, p_key, sizeof(dvd_key) );
816
817     return ioctl( i_fd, DVD_AUTH, &auth_info );
818
819 #elif defined( HAVE_BSD_DVD_STRUCT )
820     struct dvd_authinfo auth_info;
821
822     auth_info.format = DVD_SEND_KEY2;
823     auth_info.agid = *pi_agid;
824
825     memcpy( auth_info.keychal, p_key, 8 );
826
827     return ioctl( i_fd, DVDIOCSENDKEY, &auth_info );
828
829 #elif defined( SYS_BEOS )
830     INIT_RDC( GPCMD_SEND_KEY, 12 );
831
832     rdc.command[ 10 ] = DVD_SEND_KEY2 | (*pi_agid << 6);
833
834     p_buffer[ 1 ] = 0xa;
835     memcpy( p_buffer + 4, p_key, 8 );
836
837     return ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
838
839 #elif defined( WIN32 )
840     if( WIN2K ) /* NT/Win2000/Whistler */
841     {
842         DWORD tmp;
843         u8 buffer[DVD_BUS_KEY_LENGTH];
844         PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
845
846         memset( &buffer, 0, sizeof( buffer ) );
847
848         key->KeyLength  = DVD_BUS_KEY_LENGTH;
849         key->SessionId  = *pi_agid;
850         key->KeyType    = DvdBusKey2;
851         key->KeyFlags   = 0;
852
853         memcpy( key->KeyData, p_key, 8 );
854
855         return DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_SEND_KEY, key, 
856                 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
857     }
858     else
859     {
860         INIT_SSC( GPCMD_SEND_KEY, 12 );
861
862         ssc.CDBByte[ 10 ] = DVD_SEND_KEY2 | (*pi_agid << 6);
863
864         p_buffer[ 1 ] = 0xa;
865         memcpy( p_buffer + 4, p_key, 8 );
866
867         return WinSendSSC( i_fd, &ssc );
868     }
869
870 #elif defined( SYS_DARWIN )
871     INIT_DVDIOCTL( 12 );
872
873     dvdioctl.i_keyformat = kKey2;
874     dvdioctl.i_agid = *pi_agid;
875
876     p_buffer[ 1 ] = 0xa;
877     memcpy( p_buffer + 4, p_key, 8 );
878
879     return ioctl( i_fd, IODVD_SEND_KEY, &dvdioctl );
880
881 #else
882     /* DVD ioctls unavailable - do as if the ioctl failed */
883     return -1;
884
885 #endif
886 }
887
888 /* Local prototypes */
889
890 #if defined( SYS_BEOS )
891 /*****************************************************************************
892  * BeInitRDC: initialize a RDC structure for the BeOS kernel
893  *****************************************************************************
894  * This function initializes a BeOS raw device command structure for future
895  * use, either a read command or a write command.
896  *****************************************************************************/
897 static void BeInitRDC( raw_device_command *p_rdc, int i_type )
898 {
899     memset( p_rdc->data, 0, p_rdc->data_length );
900
901     switch( i_type )
902     {
903         case GPCMD_SEND_KEY:
904             /* leave the flags to 0 */
905             break;
906
907         case GPCMD_READ_DVD_STRUCTURE:
908         case GPCMD_REPORT_KEY:
909             p_rdc->flags = B_RAW_DEVICE_DATA_IN;
910             break;
911     }
912
913     p_rdc->command[ 0 ]      = i_type;
914
915     p_rdc->command[ 8 ]      = (p_rdc->data_length >> 8) & 0xff;
916     p_rdc->command[ 9 ]      =  p_rdc->data_length       & 0xff;
917     p_rdc->command_length    = 12;
918
919     p_rdc->sense_data        = NULL;
920     p_rdc->sense_data_length = 0;
921
922     p_rdc->timeout           = 1000000;
923 }
924 #endif
925
926 #if defined( WIN32 )
927 /*****************************************************************************
928  * WinInitSSC: initialize a ssc structure for the win32 aspi layer
929  *****************************************************************************
930  * This function initializes a ssc raw device command structure for future
931  * use, either a read command or a write command.
932  *****************************************************************************/
933 static void WinInitSSC( struct SRB_ExecSCSICmd *p_ssc, int i_type )
934 {
935     memset( p_ssc->SRB_BufPointer, 0, p_ssc->SRB_BufLen );
936
937     switch( i_type )
938     {
939         case GPCMD_SEND_KEY:
940             p_ssc->SRB_Flags = SRB_DIR_OUT;
941             break;
942
943         case GPCMD_READ_DVD_STRUCTURE:
944         case GPCMD_REPORT_KEY:
945             p_ssc->SRB_Flags = SRB_DIR_IN;
946             break;
947     }
948
949     p_ssc->SRB_Cmd      = SC_EXEC_SCSI_CMD;
950     p_ssc->SRB_Flags    |= SRB_EVENT_NOTIFY;
951
952     p_ssc->CDBByte[ 0 ] = i_type;
953
954     p_ssc->CDBByte[ 8 ] = (u8)(p_ssc->SRB_BufLen >> 8) & 0xff;
955     p_ssc->CDBByte[ 9 ] = (u8) p_ssc->SRB_BufLen       & 0xff;
956     p_ssc->SRB_CDBLen   = 12;
957
958     p_ssc->SRB_SenseLen = SENSE_LEN;
959 }
960
961 /*****************************************************************************
962  * WinSendSSC: send a ssc structure to the aspi layer
963  *****************************************************************************/
964 static int WinSendSSC( int i_fd, struct SRB_ExecSCSICmd *p_ssc )
965 {
966     HANDLE hEvent = NULL;
967     struct w32_aspidev *fd = (struct w32_aspidev *) i_fd;
968
969     hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
970     if( hEvent == NULL )
971     {
972         return -1;
973     }
974
975     p_ssc->SRB_PostProc  = hEvent;
976     p_ssc->SRB_HaId      = LOBYTE( fd->i_sid );
977     p_ssc->SRB_Target    = HIBYTE( fd->i_sid );
978
979     ResetEvent( hEvent );
980     if( fd->lpSendCommand( (void*) p_ssc ) == SS_PENDING )
981         WaitForSingleObject( hEvent, INFINITE );
982
983     CloseHandle( hEvent );
984
985     return p_ssc->SRB_Status == SS_COMP ? 0 : -1;
986 }
987 #endif