]> git.sesse.net Git - vlc/blob - plugins/dvd/dvd_ioctl.c
* Win2000 DVD input by Jon Lech Johansen <jon-vl@nanocrew.net>.
[vlc] / plugins / dvd / dvd_ioctl.c
1 /*****************************************************************************
2  * dvd_ioctl.c: DVD ioctl replacement function
3  *****************************************************************************
4  * Copyright (C) 1999-2001 VideoLAN
5  * $Id: dvd_ioctl.c,v 1.16 2001/05/31 03:12:49 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 "common.h"
57
58 #include "intf_msg.h"
59
60 #ifdef SYS_DARWIN1_3
61 #   include "DVDioctl/DVDioctl.h"
62 #endif
63
64 #include "dvd_css.h"
65 #include "dvd_ioctl.h"
66
67 /*****************************************************************************
68  * Local prototypes, BeOS specific
69  *****************************************************************************/
70 #if defined( SYS_BEOS )
71 static void BeInitRDC ( raw_device_command *, int );
72 #endif
73
74 /*****************************************************************************
75  * ioctl_ReadCopyright: check whether the disc is encrypted or not
76  *****************************************************************************/
77 int ioctl_ReadCopyright( int i_fd, int i_layer, int *pi_copyright )
78 {
79     int i_ret;
80
81 #if defined( DVD_STRUCT_IN_LINUX_CDROM_H )
82     dvd_struct dvd;
83
84     dvd.type = DVD_STRUCT_COPYRIGHT;
85     dvd.copyright.layer_num = i_layer;
86
87     i_ret = ioctl( i_fd, DVD_READ_STRUCT, &dvd );
88
89     *pi_copyright = dvd.copyright.cpst;
90
91 #elif defined( HAVE_BSD_DVD_STRUCT )
92     struct dvd_struct dvd;
93
94     dvd.format = DVD_STRUCT_COPYRIGHT;
95     dvd.layer_num = i_layer;
96
97     i_ret = ioctl( i_fd, DVDIOCREADSTRUCTURE, &dvd );
98
99     *pi_copyright = dvd.cpst;
100
101 #elif defined( SYS_BEOS )
102     INIT_RDC( GPCMD_READ_DVD_STRUCTURE, 8 );
103
104     rdc.command[ 6 ] = i_layer;
105     rdc.command[ 7 ] = DVD_STRUCT_COPYRIGHT;
106
107     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
108
109     *pi_copyright = p_buffer[ 4 ];
110
111 #elif defined( SYS_DARWIN1_3 )
112     intf_ErrMsg( "css error: DVD ioctls not fully functional yet" );
113     intf_ErrMsg( "css error: assuming disc is encrypted" );
114
115     *pi_copyright = 1;
116
117     i_ret = 0;
118
119 #elif defined( WIN32 )
120     if( GetVersion() < 0x80000000 ) /* NT/Win2000/Whistler */
121     {
122         DWORD tmp;
123         u8 p_buffer[ 8 ];
124         SCSI_PASS_THROUGH_DIRECT sptd;
125
126         memset( &sptd, 0, sizeof( sptd ) );
127         memset( &p_buffer, 0, sizeof( p_buffer ) );
128    
129         /*  When using IOCTL_DVD_READ_STRUCTURE and 
130             DVD_COPYRIGHT_DESCRIPTOR, CopyrightProtectionType
131             is always 6. So we send a raw scsi command instead. */
132
133         sptd.Length             = sizeof( SCSI_PASS_THROUGH_DIRECT );
134         sptd.CdbLength          = 12;
135         sptd.DataIn             = SCSI_IOCTL_DATA_IN;
136         sptd.DataTransferLength = 8;
137         sptd.TimeOutValue       = 2;
138         sptd.DataBuffer         = p_buffer;
139         sptd.Cdb[ 0 ]           = GPCMD_READ_DVD_STRUCTURE;
140         sptd.Cdb[ 6 ]           = i_layer;
141         sptd.Cdb[ 7 ]           = DVD_STRUCT_COPYRIGHT;
142         sptd.Cdb[ 8 ]           = (8 >> 8) & 0xff;
143         sptd.Cdb[ 9 ]           =  8       & 0xff;
144
145         i_ret = DeviceIoControl( (HANDLE) i_fd,
146                              IOCTL_SCSI_PASS_THROUGH_DIRECT,
147                              &sptd, sizeof( SCSI_PASS_THROUGH_DIRECT ),
148                              &sptd, sizeof( SCSI_PASS_THROUGH_DIRECT ),
149                              &tmp, NULL ) ? 0 : -1;
150
151         *pi_copyright = p_buffer[4];
152     }
153     else
154     {
155         /* TODO: add WNASPI support for Win9x */
156         intf_ErrMsg( "css error: DVD ioctls not functional yet" );
157         intf_ErrMsg( "css error: assuming disc is unencrypted" );
158         *pi_copyright = 0;
159         i_ret = 0;
160     }
161
162 #else
163     /* DVD ioctls unavailable - do as if the ioctl failed */
164     i_ret = -1;
165
166 #endif
167     return i_ret;
168 }
169
170 /*****************************************************************************
171  * ioctl_ReadKey: get the disc key
172  *****************************************************************************/
173 int ioctl_ReadKey( int i_fd, int *pi_agid, u8 *p_key )
174 {
175     int i_ret;
176
177 #if defined( DVD_STRUCT_IN_LINUX_CDROM_H )
178     dvd_struct dvd;
179
180     dvd.type = DVD_STRUCT_DISCKEY;
181     dvd.disckey.agid = *pi_agid;
182     memset( dvd.disckey.value, 0, 2048 );
183
184     i_ret = ioctl( i_fd, DVD_READ_STRUCT, &dvd );
185
186     if( i_ret < 0 )
187     {
188         return i_ret;
189     }
190
191     memcpy( p_key, dvd.disckey.value, 2048 );
192
193 #elif defined( HAVE_BSD_DVD_STRUCT )
194     struct dvd_struct dvd;
195
196     dvd.format = DVD_STRUCT_DISCKEY;
197     dvd.agid = *pi_agid;
198     memset( dvd.data, 0, 2048 );
199
200     i_ret = ioctl( i_fd, DVDIOCREADSTRUCTURE, &dvd );
201
202     if( i_ret < 0 )
203     {
204         return i_ret;
205     }
206
207     memcpy( p_key, dvd.data, 2048 );
208
209 #elif defined( SYS_BEOS )
210     INIT_RDC( GPCMD_READ_DVD_STRUCTURE, 2048 + 4 );
211
212     rdc.command[ 7 ]  = DVD_STRUCT_DISCKEY;
213     rdc.command[ 10 ] = *pi_agid << 6;
214     
215     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
216
217     if( i_ret < 0 )
218     {
219         return i_ret;
220     }
221
222     memcpy( p_key, p_buffer + 4, 2048 );
223
224 #elif defined( SYS_DARWIN1_3 )
225     intf_ErrMsg( "css error: DVD ioctls not fully functional yet" );
226     intf_ErrMsg( "css error: sending an empty key" );
227
228     i_ret = 0;
229
230     memset( p_key, 0x00, 2048 );
231
232 #elif defined( WIN32 )
233     if( GetVersion() < 0x80000000 ) /* NT/Win2000/Whistler */
234     {
235         DWORD tmp;
236         u8 buffer[DVD_DISK_KEY_LENGTH];
237         PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
238
239         memset( &buffer, 0, sizeof( buffer ) );
240
241         key->KeyLength  = DVD_DISK_KEY_LENGTH;
242         key->SessionId  = *pi_agid;
243         key->KeyType    = DvdDiskKey;
244         key->KeyFlags   = 0;
245
246         i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key, 
247                 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
248
249         if( i_ret < 0 )
250         {   
251             return i_ret;
252         }
253
254         memcpy( p_key, key->KeyData, 2048 );
255     }
256     else
257     {
258         i_ret = -1;
259     }
260
261 #else
262     /* DVD ioctls unavailable - do as if the ioctl failed */
263     i_ret = -1;
264
265 #endif
266     return i_ret;
267 }
268
269 /*****************************************************************************
270  * ioctl_ReportAgid: get AGID from the drive
271  *****************************************************************************/
272 int ioctl_ReportAgid( int i_fd, int *pi_agid )
273 {
274     int i_ret;
275
276 #if defined( DVD_STRUCT_IN_LINUX_CDROM_H )
277     dvd_authinfo auth_info;
278
279     auth_info.type = DVD_LU_SEND_AGID;
280     auth_info.lsa.agid = *pi_agid;
281
282     i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
283
284     *pi_agid = auth_info.lsa.agid;
285
286 #elif defined( HAVE_BSD_DVD_STRUCT )
287     struct dvd_authinfo auth_info;
288
289     auth_info.format = DVD_REPORT_AGID;
290     auth_info.agid = *pi_agid;
291
292     i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
293
294     *pi_agid = auth_info.agid;
295
296 #elif defined( SYS_BEOS )
297     INIT_RDC( GPCMD_REPORT_KEY, 8 );
298
299     rdc.command[ 10 ] = DVD_REPORT_AGID | (*pi_agid << 6);
300
301     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
302
303     *pi_agid = p_buffer[ 7 ] >> 6;
304
305 #elif defined( SYS_DARWIN1_3 )
306     INIT_DVDIOCTL( 8 );
307
308     dvdioctl.i_keyformat = kCSSAGID;
309     dvdioctl.i_agid = *pi_agid;
310     dvdioctl.i_lba = 0;
311
312     i_ret = ioctl( i_fd, IODVD_REPORT_KEY, &dvdioctl );
313
314     *pi_agid = p_buffer[ 7 ] >> 6;
315
316 #elif defined( WIN32 )
317     if( GetVersion() < 0x80000000 ) /* NT/Win2000/Whistler */
318     {
319         ULONG id;
320         DWORD tmp;
321
322         i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_START_SESSION, 
323                         &tmp, 4, &id, sizeof( id ), &tmp, NULL ) ? 0 : -1;
324
325         *pi_agid = id;
326     }
327     else
328     {
329         i_ret = -1;
330     }
331
332 #else
333     /* DVD ioctls unavailable - do as if the ioctl failed */
334     i_ret = -1;
335
336 #endif
337     return i_ret;
338 }
339
340 /*****************************************************************************
341  * ioctl_ReportChallenge: get challenge from the drive
342  *****************************************************************************/
343 int ioctl_ReportChallenge( int i_fd, int *pi_agid, u8 *p_challenge )
344 {
345     int i_ret;
346
347 #if defined( DVD_STRUCT_IN_LINUX_CDROM_H )
348     dvd_authinfo auth_info;
349
350     auth_info.type = DVD_LU_SEND_CHALLENGE;
351     auth_info.lsc.agid = *pi_agid;
352
353     i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
354
355     memcpy( p_challenge, auth_info.lsc.chal, sizeof(dvd_challenge) );
356
357 #elif defined( HAVE_BSD_DVD_STRUCT )
358     struct dvd_authinfo auth_info;
359
360     auth_info.format = DVD_REPORT_CHALLENGE;
361     auth_info.agid = *pi_agid;
362
363     i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
364
365     memcpy( p_challenge, auth_info.keychal, 10 );
366
367 #elif defined( SYS_BEOS )
368     INIT_RDC( GPCMD_REPORT_KEY, 16 );
369
370     rdc.command[ 10 ] = DVD_REPORT_CHALLENGE | (*pi_agid << 6);
371
372     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
373
374     memcpy( p_challenge, p_buffer + 4, 12 );
375
376 #elif defined( SYS_DARWIN1_3 )
377     INIT_DVDIOCTL( 16 );
378
379     dvdioctl.i_keyformat = kChallengeKey;
380     dvdioctl.i_agid = *pi_agid;
381     dvdioctl.i_lba = 0;
382
383     i_ret = ioctl( i_fd, IODVD_REPORT_KEY, &dvdioctl );
384
385     memcpy( p_challenge, p_buffer + 4, 12 );
386
387 #elif defined( WIN32 )
388     if( GetVersion() < 0x80000000 ) /* NT/Win2000/Whistler */
389     {
390         DWORD tmp;
391         u8 buffer[DVD_CHALLENGE_KEY_LENGTH];
392         PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
393
394         memset( &buffer, 0, sizeof( buffer ) );
395
396         key->KeyLength  = DVD_CHALLENGE_KEY_LENGTH;
397         key->SessionId  = *pi_agid;
398         key->KeyType    = DvdChallengeKey;
399         key->KeyFlags   = 0;
400
401         i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key, 
402                 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
403
404         if( i_ret < 0 )
405         {
406             return i_ret;
407         }
408
409         memcpy( p_challenge, key->KeyData, 10 );
410     }
411     else
412     {
413         i_ret = -1;
414     }
415
416 #else
417     /* DVD ioctls unavailable - do as if the ioctl failed */
418     i_ret = -1;
419
420 #endif
421     return i_ret;
422 }
423
424 /*****************************************************************************
425  * ioctl_ReportASF: get ASF from the drive
426  *****************************************************************************/
427 int ioctl_ReportASF( int i_fd, int *pi_agid, int *pi_asf )
428 {
429     int i_ret;
430
431 #if defined( DVD_STRUCT_IN_LINUX_CDROM_H )
432     dvd_authinfo auth_info;
433
434     auth_info.type = DVD_LU_SEND_ASF;
435     auth_info.lsasf.agid = *pi_agid;
436     auth_info.lsasf.asf = *pi_asf;
437
438     i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
439
440     *pi_asf = auth_info.lsasf.asf;
441
442 #elif defined( HAVE_BSD_DVD_STRUCT )
443     struct dvd_authinfo auth_info;
444
445     auth_info.format = DVD_REPORT_ASF;
446     auth_info.agid = *pi_agid;
447     auth_info.asf = *pi_asf;
448
449     i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
450
451     *pi_asf = auth_info.asf;
452
453 #elif defined( SYS_BEOS )
454     INIT_RDC( GPCMD_REPORT_KEY, 8 );
455
456     rdc.command[ 10 ] = DVD_REPORT_ASF | (*pi_agid << 6);
457
458     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
459
460     *pi_asf = p_buffer[ 7 ] & 1;
461
462 #elif defined( SYS_DARWIN1_3 )
463     INIT_DVDIOCTL( 8 );
464
465     dvdioctl.i_keyformat = kASF;
466     dvdioctl.i_agid = *pi_agid;
467     dvdioctl.i_lba = 0;
468
469     i_ret = ioctl( i_fd, IODVD_REPORT_KEY, &dvdioctl );
470
471     *pi_asf = p_buffer[ 7 ] & 1;
472
473 #elif defined( WIN32 )
474     if( GetVersion() < 0x80000000 ) /* NT/Win2000/Whistler */
475     {
476         DWORD tmp;
477         u8 buffer[DVD_ASF_LENGTH];
478         PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
479
480         memset( &buffer, 0, sizeof( buffer ) );
481
482         key->KeyLength  = DVD_ASF_LENGTH;
483         key->SessionId  = *pi_agid;
484         key->KeyType    = DvdAsf;
485         key->KeyFlags   = 0;
486
487         ((PDVD_ASF)key->KeyData)->SuccessFlag = *pi_asf;
488
489         i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key, 
490                 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
491
492         if( i_ret < 0 )
493         {
494             return i_ret;
495         }
496
497         *pi_asf = ((PDVD_ASF)key->KeyData)->SuccessFlag;
498     }
499     else
500     {
501         i_ret = -1;
502     }
503
504 #else
505     /* DVD ioctls unavailable - do as if the ioctl failed */
506     i_ret = -1;
507
508 #endif
509     return i_ret;
510 }
511
512 /*****************************************************************************
513  * ioctl_ReportKey1: get the first key from the drive
514  *****************************************************************************/
515 int ioctl_ReportKey1( int i_fd, int *pi_agid, u8 *p_key )
516 {
517     int i_ret;
518
519 #if defined( DVD_STRUCT_IN_LINUX_CDROM_H )
520     dvd_authinfo auth_info;
521
522     auth_info.type = DVD_LU_SEND_KEY1;
523     auth_info.lsk.agid = *pi_agid;
524
525     i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
526
527     memcpy( p_key, auth_info.lsk.key, sizeof(dvd_key) );
528
529 #elif defined( HAVE_BSD_DVD_STRUCT )
530     struct dvd_authinfo auth_info;
531
532     auth_info.format = DVD_REPORT_KEY1;
533     auth_info.agid = *pi_agid;
534
535     i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
536
537     memcpy( p_key, auth_info.keychal, 8 );
538
539 #elif defined( SYS_BEOS )
540     INIT_RDC( GPCMD_REPORT_KEY, 12 );
541
542     rdc.command[ 10 ] = DVD_REPORT_KEY1 | (*pi_agid << 6);
543
544     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
545
546     memcpy( p_key, p_buffer + 4, 8 );
547
548 #elif defined( SYS_DARWIN1_3 )
549     INIT_DVDIOCTL( 12 );
550
551     dvdioctl.i_keyformat = kKey1;
552     dvdioctl.i_agid = *pi_agid;
553
554     i_ret = ioctl( i_fd, IODVD_SEND_KEY, &dvdioctl );
555
556     memcpy( p_key, p_buffer + 4, 8 );
557
558 #elif defined( WIN32 )
559     if( GetVersion() < 0x80000000 ) /* NT/Win2000/Whistler */
560     {
561         DWORD tmp;
562         u8 buffer[DVD_BUS_KEY_LENGTH];
563         PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
564
565         memset( &buffer, 0, sizeof( buffer ) );
566
567         key->KeyLength  = DVD_BUS_KEY_LENGTH;
568         key->SessionId  = *pi_agid;
569         key->KeyType    = DvdBusKey1;
570         key->KeyFlags   = 0;
571
572         i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key, 
573                 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
574
575         memcpy( p_key, key->KeyData, 8 );
576     }
577     else
578     {
579         i_ret = -1;
580     }
581
582 #else
583     /* DVD ioctls unavailable - do as if the ioctl failed */
584     i_ret = -1;
585
586 #endif
587     return i_ret;
588 }
589
590 /*****************************************************************************
591  * ioctl_InvalidateAgid: invalidate the current AGID
592  *****************************************************************************/
593 int ioctl_InvalidateAgid( int i_fd, int *pi_agid )
594 {
595     int i_ret;
596
597 #if defined( DVD_STRUCT_IN_LINUX_CDROM_H )
598     dvd_authinfo auth_info;
599
600     auth_info.type = DVD_INVALIDATE_AGID;
601     auth_info.lsa.agid = *pi_agid;
602
603     i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
604
605     *pi_agid = auth_info.lsa.agid;
606
607 #elif defined( HAVE_BSD_DVD_STRUCT )
608     struct dvd_authinfo auth_info;
609
610     auth_info.format = DVD_INVALIDATE_AGID;
611     auth_info.agid = *pi_agid;
612
613     i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
614
615     *pi_agid = auth_info.agid;
616
617 #elif defined( SYS_BEOS )
618     INIT_RDC( GPCMD_REPORT_KEY, 0 );
619
620     rdc.command[ 10 ] = DVD_INVALIDATE_AGID | (*pi_agid << 6);
621
622     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
623
624 #elif defined( SYS_DARWIN1_3 )
625     INIT_DVDIOCTL( 0 );
626
627     dvdioctl.i_keyformat = kInvalidateAGID;
628     dvdioctl.i_agid = *pi_agid;
629
630     i_ret = ioctl( i_fd, IODVD_SEND_KEY, &dvdioctl );
631
632 #elif defined( WIN32 )
633     if( GetVersion() < 0x80000000 ) /* NT/Win2000/Whistler */
634     {
635         DWORD tmp;
636
637         i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_END_SESSION, 
638                     pi_agid, sizeof( *pi_agid ), NULL, 0, &tmp, NULL ) ? 0 : -1;
639     }
640     else
641     {
642         i_ret = -1;
643     }
644
645 #else
646     /* DVD ioctls unavailable - do as if the ioctl failed */
647     i_ret = -1;
648
649 #endif
650     return i_ret;
651 }
652
653 /*****************************************************************************
654  * ioctl_SendChallenge: send challenge to the drive
655  *****************************************************************************/
656 int ioctl_SendChallenge( int i_fd, int *pi_agid, u8 *p_challenge )
657 {
658 #if defined( DVD_STRUCT_IN_LINUX_CDROM_H )
659     dvd_authinfo auth_info;
660
661     auth_info.type = DVD_HOST_SEND_CHALLENGE;
662     auth_info.hsc.agid = *pi_agid;
663
664     memcpy( auth_info.hsc.chal, p_challenge, sizeof(dvd_challenge) );
665
666     return ioctl( i_fd, DVD_AUTH, &auth_info );
667
668 #elif defined( HAVE_BSD_DVD_STRUCT )
669     struct dvd_authinfo auth_info;
670
671     auth_info.format = DVD_SEND_CHALLENGE;
672     auth_info.agid = *pi_agid;
673
674     memcpy( auth_info.keychal, p_challenge, 12 );
675
676     return ioctl( i_fd, DVDIOCSENDKEY, &auth_info );
677
678 #elif defined( SYS_BEOS )
679     INIT_RDC( GPCMD_SEND_KEY, 16 );
680
681     rdc.command[ 10 ] = DVD_SEND_CHALLENGE | (*pi_agid << 6);
682
683     p_buffer[ 1 ] = 0xe;
684     memcpy( p_buffer + 4, p_challenge, 12 );
685
686     return ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
687
688 #elif defined( SYS_DARWIN1_3 )
689     INIT_DVDIOCTL( 16 );
690
691     dvdioctl.i_keyformat = kChallengeKey;
692     dvdioctl.i_agid = *pi_agid;
693
694     p_buffer[ 1 ] = 0xe;
695     memcpy( p_buffer + 4, p_challenge, 12 );
696
697     return ioctl( i_fd, IODVD_SEND_KEY, &dvdioctl );
698
699 #elif defined( WIN32 )
700     if( GetVersion() < 0x80000000 ) /* NT/Win2000/Whistler */
701     {
702         DWORD tmp;
703         u8 buffer[DVD_CHALLENGE_KEY_LENGTH];
704         PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
705
706         memset( &buffer, 0, sizeof( buffer ) );
707
708         key->KeyLength  = DVD_CHALLENGE_KEY_LENGTH;
709         key->SessionId  = *pi_agid;
710         key->KeyType    = DvdChallengeKey;
711         key->KeyFlags   = 0;
712
713         memcpy( key->KeyData, p_challenge, 10 );
714
715         return DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_SEND_KEY, key, 
716                 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
717     }
718     else
719     {
720         return -1;
721     }
722
723 #else
724     /* DVD ioctls unavailable - do as if the ioctl failed */
725     return -1;
726
727 #endif
728 }
729
730 /*****************************************************************************
731  * ioctl_SendKey2: send the second key to the drive
732  *****************************************************************************/
733 int ioctl_SendKey2( int i_fd, int *pi_agid, u8 *p_key )
734 {
735 #if defined( DVD_STRUCT_IN_LINUX_CDROM_H )
736     dvd_authinfo auth_info;
737
738     auth_info.type = DVD_HOST_SEND_KEY2;
739     auth_info.hsk.agid = *pi_agid;
740
741     memcpy( auth_info.hsk.key, p_key, sizeof(dvd_key) );
742
743     return ioctl( i_fd, DVD_AUTH, &auth_info );
744
745 #elif defined( HAVE_BSD_DVD_STRUCT )
746     struct dvd_authinfo auth_info;
747
748     auth_info.format = DVD_SEND_KEY2;
749     auth_info.agid = *pi_agid;
750
751     memcpy( auth_info.keychal, p_key, 8 );
752
753     return ioctl( i_fd, DVDIOCSENDKEY, &auth_info );
754
755 #elif defined( SYS_BEOS )
756     INIT_RDC( GPCMD_SEND_KEY, 12 );
757
758     rdc.command[ 10 ] = DVD_SEND_KEY2 | (*pi_agid << 6);
759
760     p_buffer[ 1 ] = 0xa;
761     memcpy( p_buffer + 4, p_key, 8 );
762
763     return ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
764
765 #elif defined( WIN32 )
766     if( GetVersion() < 0x80000000 ) /* NT/Win2000/Whistler */
767     {
768         DWORD tmp;
769         u8 buffer[DVD_BUS_KEY_LENGTH];
770         PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
771
772         memset( &buffer, 0, sizeof( buffer ) );
773
774         key->KeyLength  = DVD_BUS_KEY_LENGTH;
775         key->SessionId  = *pi_agid;
776         key->KeyType    = DvdBusKey2;
777         key->KeyFlags   = 0;
778
779         memcpy( key->KeyData, p_key, 8 );
780
781         return DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_SEND_KEY, key, 
782                 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
783     }
784     else
785     {
786         return -1;
787     }
788
789 #elif defined( SYS_DARWIN1_3 )
790     INIT_DVDIOCTL( 12 );
791
792     dvdioctl.i_keyformat = kKey2;
793     dvdioctl.i_agid = *pi_agid;
794
795     p_buffer[ 1 ] = 0xa;
796     memcpy( p_buffer + 4, p_key, 8 );
797
798     return ioctl( i_fd, IODVD_SEND_KEY, &dvdioctl );
799
800 #else
801     /* DVD ioctls unavailable - do as if the ioctl failed */
802     return -1;
803
804 #endif
805 }
806
807 /* Local prototypes */
808
809 #if defined( SYS_BEOS )
810 /*****************************************************************************
811  * BeInitRDC: initialize a RDC structure for the BeOS kernel
812  *****************************************************************************
813  * This function initializes a BeOS raw device command structure for future
814  * use, either a read command or a write command.
815  *****************************************************************************/
816 static void BeInitRDC( raw_device_command *p_rdc, int i_type )
817 {
818     memset( p_rdc->data, 0, p_rdc->data_length );
819
820     switch( i_type )
821     {
822         case GPCMD_SEND_KEY:
823             /* leave the flags to 0 */
824             break;
825
826         case GPCMD_READ_DVD_STRUCTURE:
827         case GPCMD_REPORT_KEY:
828             p_rdc->flags = B_RAW_DEVICE_DATA_IN;
829             break;
830     }
831
832     p_rdc->command[ 0 ]      = i_type;
833
834     p_rdc->command[ 8 ]      = (p_rdc->data_length >> 8) & 0xff;
835     p_rdc->command[ 9 ]      =  p_rdc->data_length       & 0xff;
836     p_rdc->command_length    = 12;
837
838     p_rdc->sense_data        = NULL;
839     p_rdc->sense_data_length = 0;
840
841     p_rdc->timeout           = 1000000;
842 }
843 #endif
844