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