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