]> git.sesse.net Git - vlc/blob - extras/libdvdcss/ioctl.c
* Added vlc-arts to the debian package generation.
[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.16 2001/12/11 14:43:38 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  *          Håkan Hjort <d95hjort@dtek.chalmers.se>
11  *          Eugenio Jarosiewicz <ej0@cise.ufl.edu>
12  *          David Siebörger <drs-videolan@rucus.ru.ac.za>
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
27  *****************************************************************************/
28
29 /*****************************************************************************
30  * Preamble
31  *****************************************************************************/
32 #include "defs.h"
33
34 #include <stdio.h>
35
36 #include <string.h>                                    /* memcpy(), memset() */
37 #include <sys/types.h>
38
39 #if defined( WIN32 )
40 #   include <windows.h>
41 #   include <winioctl.h>
42 #else
43 #   include <netinet/in.h>
44 #   include <sys/ioctl.h>
45 #endif
46
47 #ifdef DVD_STRUCT_IN_SYS_CDIO_H
48 #   include <sys/cdio.h>
49 #endif
50 #ifdef DVD_STRUCT_IN_SYS_DVDIO_H
51 #   include <sys/dvdio.h>
52 #endif
53 #ifdef DVD_STRUCT_IN_LINUX_CDROM_H
54 #   include <linux/cdrom.h>
55 #endif
56 #ifdef DVD_STRUCT_IN_DVD_H
57 #   include <dvd.h>
58 #endif
59 #ifdef DVD_STRUCT_IN_BSDI_DVDIOCTL_DVD_H
60 #   include <BSDI_dvdioctl/dvd.h>
61 #endif
62 #ifdef SYS_BEOS
63 #   include <malloc.h>
64 #   include <scsi.h>
65 #endif
66 #ifdef HPUX_SCTL_IO
67 #   include <sys/scsi.h>
68 #endif
69 #ifdef SOLARIS_USCSI
70 #   include <unistd.h>
71 #   include <stropts.h>
72 #   include <sys/scsi/scsi_types.h>
73 #   include <sys/scsi/impl/uscsi.h>
74 #endif
75
76 #include "common.h"
77
78 #ifdef SYS_DARWIN
79 #   include <IOKit/storage/IODVDMediaBSDClient.h>
80 /* #   include "DVDioctl/DVDioctl.h" */
81 #endif
82
83 #include "ioctl.h"
84
85
86 /*****************************************************************************
87  * Local prototypes, BeOS specific
88  *****************************************************************************/
89 #if defined( SYS_BEOS )
90 static void BeInitRDC ( raw_device_command *, int );
91 #endif
92
93 /*****************************************************************************
94  * Local prototypes, HP-UX specific
95  *****************************************************************************/
96 #if defined( HPUX_SCTL_IO )
97 static void HPUXInitSCTL ( struct sctl_io *sctl_io, int i_type );
98 #endif
99
100 /*****************************************************************************
101  * Local prototypes, Solaris specific
102  *****************************************************************************/
103 #if defined( SOLARIS_USCSI )
104 static void SolarisInitUSCSI( struct uscsi_cmd *p_sc, int i_type );
105 #endif
106
107 /*****************************************************************************
108  * Local prototypes, win32 (aspi) specific
109  *****************************************************************************/
110 #if defined( WIN32 )
111 static void WinInitSSC ( struct SRB_ExecSCSICmd *, int );
112 static int  WinSendSSC ( int, struct SRB_ExecSCSICmd * );
113 #endif
114
115 /*****************************************************************************
116  * ioctl_ReadCopyright: check whether the disc is encrypted or not
117  *****************************************************************************/
118 int ioctl_ReadCopyright( int i_fd, int i_layer, int *pi_copyright )
119 {
120     int i_ret;
121
122 #if defined( HAVE_LINUX_DVD_STRUCT )
123     dvd_struct dvd;
124
125     dvd.type = DVD_STRUCT_COPYRIGHT;
126     dvd.copyright.layer_num = i_layer;
127
128     i_ret = ioctl( i_fd, DVD_READ_STRUCT, &dvd );
129
130     *pi_copyright = dvd.copyright.cpst;
131
132 #elif defined( HAVE_BSD_DVD_STRUCT )
133     struct dvd_struct dvd;
134
135     dvd.format = DVD_STRUCT_COPYRIGHT;
136     dvd.layer_num = i_layer;
137
138     i_ret = ioctl( i_fd, DVDIOCREADSTRUCTURE, &dvd );
139
140     *pi_copyright = dvd.cpst;
141
142 #elif defined( SYS_BEOS )
143     INIT_RDC( GPCMD_READ_DVD_STRUCTURE, 8 );
144
145     rdc.command[ 6 ] = i_layer;
146     rdc.command[ 7 ] = DVD_STRUCT_COPYRIGHT;
147
148     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
149
150     *pi_copyright = p_buffer[ 4 ];
151
152 #elif defined( HPUX_SCTL_IO )
153     INIT_SCTL_IO( GPCMD_READ_DVD_STRUCTURE, 8 );
154
155     sctl_io.cdb[ 6 ] = i_layer;
156     sctl_io.cdb[ 7 ] = DVD_STRUCT_COPYRIGHT;
157
158     i_ret = ioctl( i_fd, SIOC_IO, &sctl_io );
159
160     *pi_copyright = p_buffer[ 4 ];
161
162 #elif defined( SOLARIS_USCSI )
163     INIT_USCSI( GPCMD_READ_DVD_STRUCTURE, 8 );
164     
165     rs_cdb.cdb_opaque[ 6 ] = i_layer;
166     rs_cdb.cdb_opaque[ 7 ] = DVD_STRUCT_COPYRIGHT;
167
168     i_ret = ioctl(i_fd, USCSICMD, &sc);
169
170     if( i_ret < 0 || sc.uscsi_status ) {
171         i_ret = -1;
172     }
173     
174     *pi_copyright = p_buffer[ 4 ];
175     /* s->copyright.rmi = p_buffer[ 5 ]; */
176
177 #elif defined( SYS_DARWIN )
178     dk_dvd_read_structure_t dvd;
179     DVDCopyrightInfo dvdcpi;
180     
181     memset(&dvd, 0, sizeof(dvd));
182     memset(&dvdcpi, 0, sizeof(dvdcpi));
183
184     dvd.buffer = &dvdcpi;
185     dvd.bufferLength = sizeof(dvdcpi);
186     dvd.format = kDVDStructureFormatCopyrightInfo;
187     dvd.layer = i_layer;
188
189     /* dvdcpi.dataLength[0] = 0x00; */ /* dataLength[0] is already memset to 0 */
190     /* dvdcpi.dataLength[1] = 0x06; */
191     
192     i_ret = ioctl( i_fd, DKIOCDVDREADSTRUCTURE, &dvd );
193
194     *pi_copyright = dvdcpi.copyrightProtectionSystemType;
195
196 #elif defined( WIN32 )
197     if( WIN2K ) /* NT/Win2000/Whistler */
198     {
199         DWORD tmp;
200         u8 p_buffer[ 8 ];
201         SCSI_PASS_THROUGH_DIRECT sptd;
202
203         memset( &sptd, 0, sizeof( sptd ) );
204         memset( &p_buffer, 0, sizeof( p_buffer ) );
205    
206         /*  When using IOCTL_DVD_READ_STRUCTURE and 
207             DVD_COPYRIGHT_DESCRIPTOR, CopyrightProtectionType
208             is always 6. So we send a raw scsi command instead. */
209
210         sptd.Length             = sizeof( SCSI_PASS_THROUGH_DIRECT );
211         sptd.CdbLength          = 12;
212         sptd.DataIn             = SCSI_IOCTL_DATA_IN;
213         sptd.DataTransferLength = 8;
214         sptd.TimeOutValue       = 2;
215         sptd.DataBuffer         = p_buffer;
216         sptd.Cdb[ 0 ]           = GPCMD_READ_DVD_STRUCTURE;
217         sptd.Cdb[ 6 ]           = i_layer;
218         sptd.Cdb[ 7 ]           = DVD_STRUCT_COPYRIGHT;
219         sptd.Cdb[ 8 ]           = (8 >> 8) & 0xff;
220         sptd.Cdb[ 9 ]           =  8       & 0xff;
221
222         i_ret = DeviceIoControl( (HANDLE) i_fd,
223                              IOCTL_SCSI_PASS_THROUGH_DIRECT,
224                              &sptd, sizeof( SCSI_PASS_THROUGH_DIRECT ),
225                              &sptd, sizeof( SCSI_PASS_THROUGH_DIRECT ),
226                              &tmp, NULL ) ? 0 : -1;
227
228         *pi_copyright = p_buffer[4];
229     }
230     else
231     {
232         INIT_SSC( GPCMD_READ_DVD_STRUCTURE, 8 );
233
234         ssc.CDBByte[ 6 ] = i_layer;
235         ssc.CDBByte[ 7 ] = DVD_STRUCT_COPYRIGHT;
236
237         i_ret = WinSendSSC( i_fd, &ssc );
238
239         *pi_copyright = p_buffer[ 4 ];
240     }
241
242 #elif defined( __QNXNTO__ )
243     /*
244         QNX RTOS currently doesn't have a CAM
245         interface (they're working on it though).
246         Assume DVD is not encrypted.
247     */
248
249     *pi_copyright = 0;
250     i_ret = 0;
251
252 #else
253     /* DVD ioctls unavailable - do as if the ioctl failed */
254     i_ret = -1;
255
256 #endif
257     return i_ret;
258 }
259
260 /*****************************************************************************
261  * ioctl_ReadDiscKey: get the disc key
262  *****************************************************************************/
263 int ioctl_ReadDiscKey( int i_fd, int *pi_agid, u8 *p_key )
264 {
265     int i_ret;
266
267 #if defined( HAVE_LINUX_DVD_STRUCT )
268     dvd_struct dvd;
269
270     dvd.type = DVD_STRUCT_DISCKEY;
271     dvd.disckey.agid = *pi_agid;
272     memset( dvd.disckey.value, 0, 2048 );
273
274     i_ret = ioctl( i_fd, DVD_READ_STRUCT, &dvd );
275
276     if( i_ret < 0 )
277     {
278         return i_ret;
279     }
280
281     memcpy( p_key, dvd.disckey.value, 2048 );
282
283 #elif defined( HAVE_BSD_DVD_STRUCT )
284     struct dvd_struct dvd;
285
286     dvd.format = DVD_STRUCT_DISCKEY;
287     dvd.agid = *pi_agid;
288     memset( dvd.data, 0, 2048 );
289
290     i_ret = ioctl( i_fd, DVDIOCREADSTRUCTURE, &dvd );
291
292     if( i_ret < 0 )
293     {
294         return i_ret;
295     }
296
297     memcpy( p_key, dvd.data, 2048 );
298
299 #elif defined( SYS_BEOS )
300     INIT_RDC( GPCMD_READ_DVD_STRUCTURE, 2048 + 4 );
301
302     rdc.command[ 7 ]  = DVD_STRUCT_DISCKEY;
303     rdc.command[ 10 ] = *pi_agid << 6;
304     
305     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
306
307     if( i_ret < 0 )
308     {
309         return i_ret;
310     }
311
312     memcpy( p_key, p_buffer + 4, 2048 );
313
314 #elif defined( HPUX_SCTL_IO )
315     INIT_SCTL_IO( GPCMD_READ_DVD_STRUCTURE, 2048 + 4 );
316
317     sctl_io.cdb[ 7 ]  = DVD_STRUCT_DISCKEY;
318     sctl_io.cdb[ 10 ] = *pi_agid << 6;
319     
320     i_ret = ioctl( i_fd, SIOC_IO, &sctl_io );
321
322     if( i_ret < 0 )
323     {
324         return i_ret;
325     }
326
327     memcpy( p_key, p_buffer + 4, 2048 );
328
329 #elif defined( SOLARIS_USCSI )
330     INIT_USCSI( GPCMD_READ_DVD_STRUCTURE, 2048 + 4 );
331     
332     rs_cdb.cdb_opaque[ 7 ] = DVD_STRUCT_DISCKEY;
333     rs_cdb.cdb_opaque[ 10 ] = *pi_agid << 6;
334     
335     i_ret = ioctl( i_fd, USCSICMD, &sc );
336     
337     if( i_ret < 0 || sc.uscsi_status )
338     {
339         i_ret = -1;
340         return i_ret;
341     }
342
343     memcpy( p_key, p_buffer + 4, 2048 );
344
345 #elif defined( SYS_DARWIN )
346     dk_dvd_read_structure_t dvd;
347     DVDDiscKeyInfo dvddki;
348     
349     memset(&dvd, 0, sizeof(dvd));
350     memset(&dvddki, 0, sizeof(dvddki));
351
352     dvd.buffer = &dvddki;
353     dvd.bufferLength = sizeof(dvddki);
354     dvd.format = kDVDStructureFormatDiscKeyInfo;
355     dvd.grantID = *pi_agid;
356
357     /* 2048+2 ; maybe we should do bit shifts to value of (sizeof(dvddki)-2) */
358     dvddki.dataLength[0] = 0x04;
359     dvddki.dataLength[1] = 0x02;
360
361     i_ret = ioctl( i_fd, DKIOCDVDREADSTRUCTURE, &dvd );
362
363     memcpy( p_key, dvddki.discKeyStructures, sizeof(dvddki.discKeyStructures) );
364
365 #elif defined( WIN32 )
366     if( WIN2K ) /* NT/Win2000/Whistler */
367     {
368         DWORD tmp;
369         u8 buffer[DVD_DISK_KEY_LENGTH];
370         PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
371
372         memset( &buffer, 0, sizeof( buffer ) );
373
374         key->KeyLength  = DVD_DISK_KEY_LENGTH;
375         key->SessionId  = *pi_agid;
376         key->KeyType    = DvdDiskKey;
377         key->KeyFlags   = 0;
378
379         i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key, 
380                 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
381
382         if( i_ret < 0 )
383         {   
384             return i_ret;
385         }
386
387         memcpy( p_key, key->KeyData, 2048 );
388     }
389     else
390     {
391         INIT_SSC( GPCMD_READ_DVD_STRUCTURE, 2048 + 4 );
392
393         ssc.CDBByte[ 7 ]  = DVD_STRUCT_DISCKEY;
394         ssc.CDBByte[ 10 ] = *pi_agid << 6;
395     
396         i_ret = WinSendSSC( i_fd, &ssc );
397
398         if( i_ret < 0 )
399         {
400             return i_ret;
401         }
402
403         memcpy( p_key, p_buffer + 4, 2048 );
404     }
405
406 #else
407     /* DVD ioctls unavailable - do as if the ioctl failed */
408     i_ret = -1;
409
410 #endif
411     return i_ret;
412 }
413
414 /*****************************************************************************
415  * ioctl_ReadTitleKey: get the title key
416  *****************************************************************************/
417 int ioctl_ReadTitleKey( int i_fd, int *pi_agid, int i_pos, u8 *p_key )
418 {
419     int i_ret;
420
421 #if defined( HAVE_LINUX_DVD_STRUCT )
422     dvd_authinfo dvd_ai;
423
424     memset( &dvd_ai, 0, sizeof(dvd_ai) );
425     dvd_ai.type = DVD_LU_SEND_TITLE_KEY;
426     dvd_ai.lstk.agid = *pi_agid;
427     dvd_ai.lstk.lba = i_pos;
428
429     i_ret = ioctl( i_fd, DVD_AUTH, &dvd_ai );
430
431     if( i_ret < 0 )
432     {
433         return i_ret;
434     }
435
436     memcpy( p_key, dvd_ai.lstk.title_key, 5 );
437
438 #elif defined( HAVE_BSD_DVD_STRUCT )
439     i_ret = -1;
440
441 #elif defined( SYS_BEOS )
442     i_ret = -1;
443
444 #elif defined( HPUX_SCTL_IO )
445     i_ret = -1;
446
447 #elif defined( SOLARIS_USCSI )
448     i_ret = -1;
449
450 #elif defined( SYS_DARWIN )
451     dk_dvd_report_key_t dvd;
452     DVDTitleKeyInfo dvdtki;
453     
454     memset(&dvd, 0, sizeof(dvd));
455     memset(&dvdtki, 0, sizeof(dvdtki));
456
457     dvd.buffer = &dvdtki;
458     dvd.bufferLength = sizeof(dvdtki);
459     dvd.format = kDVDKeyFormatTitleKey;
460     dvd.grantID = *pi_agid;
461     dvd.keyClass = kDVDKeyClassCSS_CPPM_CPRM; /* or this - this is memset 0x00 anyways */
462
463     /* dvdtki.dataLength[0] = 0x00; */ /* dataLength[0] is already memset to 0 */
464     dvdtki.dataLength[1] = 0x0a;
465     
466     /* What are DVDTitleKeyInfo.{CP_MOD,CGMS,CP_SEC,CPM} and do they need to be set? */
467
468     i_ret = ioctl( i_fd, DKIOCDVDREPORTKEY, &dvd );
469
470     memcpy( p_key, dvdtki.titleKeyValue, sizeof(dvdtki.titleKeyValue) );
471
472 #elif defined( WIN32 )
473     i_ret = -1;
474
475 #else
476
477     i_ret = -1;
478
479 #endif
480
481     return i_ret;
482 }
483
484
485 /*****************************************************************************
486  * ioctl_ReportAgid: get AGID from the drive
487  *****************************************************************************/
488 int ioctl_ReportAgid( int i_fd, int *pi_agid )
489 {
490     int i_ret;
491
492 #if defined( HAVE_LINUX_DVD_STRUCT )
493     dvd_authinfo auth_info;
494
495     auth_info.type = DVD_LU_SEND_AGID;
496     auth_info.lsa.agid = *pi_agid;
497
498     i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
499
500     *pi_agid = auth_info.lsa.agid;
501
502 #elif defined( HAVE_BSD_DVD_STRUCT )
503     struct dvd_authinfo auth_info;
504
505     auth_info.format = DVD_REPORT_AGID;
506     auth_info.agid = *pi_agid;
507
508     i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
509
510     *pi_agid = auth_info.agid;
511
512 #elif defined( SYS_BEOS )
513     INIT_RDC( GPCMD_REPORT_KEY, 8 );
514
515     rdc.command[ 10 ] = DVD_REPORT_AGID | (*pi_agid << 6);
516
517     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
518
519     *pi_agid = p_buffer[ 7 ] >> 6;
520
521 #elif defined( HPUX_SCTL_IO )
522     INIT_SCTL_IO( GPCMD_REPORT_KEY, 8 );
523
524     sctl_io.cdb[ 10 ] = DVD_REPORT_AGID | (*pi_agid << 6);
525
526     i_ret = ioctl( i_fd, SIOC_IO, &sctl_io );
527
528     *pi_agid = p_buffer[ 7 ] >> 6;
529
530 #elif defined( SOLARIS_USCSI )
531     INIT_USCSI( GPCMD_REPORT_KEY, 8 );
532     
533     rs_cdb.cdb_opaque[ 10 ] = DVD_REPORT_AGID | (*pi_agid << 6);
534     
535     i_ret = ioctl( i_fd, USCSICMD, &sc );
536     
537     if( i_ret < 0 || sc.uscsi_status )
538     {
539         i_ret = -1;
540     }
541
542     *pi_agid = p_buffer[ 7 ] >> 6;
543     
544 #elif defined( SYS_DARWIN )
545     dk_dvd_report_key_t dvd;
546     DVDAuthenticationGrantIDInfo dvdagid;
547     
548     memset(&dvd, 0, sizeof(dvd));
549     memset(&dvdagid, 0, sizeof(dvdagid));
550
551     dvd.buffer = &dvdagid;
552     dvd.bufferLength = sizeof(dvdagid);
553     dvd.format = kDVDKeyFormatAGID_CSS;
554     dvd.grantID = *pi_agid;
555     dvdagid.grantID = *pi_agid; /* do we need this? */
556     dvd.keyClass = kDVDKeyClassCSS_CPPM_CPRM; /* or this - this is memset 0x00 anyways */
557
558     /* dvdagid.dataLength[0] = 0x00; */ /* dataLength[0] is already memset to 0 */
559     /* dvdagid.dataLength[1] = 0x06; */
560
561     i_ret = ioctl( i_fd, DKIOCDVDREPORTKEY, &dvd );
562
563     *pi_agid = dvdagid.grantID;
564
565 #elif defined( WIN32 )
566     if( WIN2K ) /* NT/Win2000/Whistler */
567     {
568         ULONG id;
569         DWORD tmp;
570
571         i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_START_SESSION, 
572                         &tmp, 4, &id, sizeof( id ), &tmp, NULL ) ? 0 : -1;
573
574         *pi_agid = id;
575     }
576     else
577     {
578         INIT_SSC( GPCMD_REPORT_KEY, 8 );
579
580         ssc.CDBByte[ 10 ] = DVD_REPORT_AGID | (*pi_agid << 6);
581
582         i_ret = WinSendSSC( i_fd, &ssc );
583
584         *pi_agid = p_buffer[ 7 ] >> 6;
585     }
586
587 #else
588     /* DVD ioctls unavailable - do as if the ioctl failed */
589     i_ret = -1;
590
591 #endif
592     return i_ret;
593 }
594
595 /*****************************************************************************
596  * ioctl_ReportChallenge: get challenge from the drive
597  *****************************************************************************/
598 int ioctl_ReportChallenge( int i_fd, int *pi_agid, u8 *p_challenge )
599 {
600     int i_ret;
601
602 #if defined( HAVE_LINUX_DVD_STRUCT )
603     dvd_authinfo auth_info;
604
605     auth_info.type = DVD_LU_SEND_CHALLENGE;
606     auth_info.lsc.agid = *pi_agid;
607
608     i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
609
610     memcpy( p_challenge, auth_info.lsc.chal, sizeof(dvd_challenge) );
611
612 #elif defined( HAVE_BSD_DVD_STRUCT )
613     struct dvd_authinfo auth_info;
614
615     auth_info.format = DVD_REPORT_CHALLENGE;
616     auth_info.agid = *pi_agid;
617
618     i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
619
620     memcpy( p_challenge, auth_info.keychal, 10 );
621
622 #elif defined( SYS_BEOS )
623     INIT_RDC( GPCMD_REPORT_KEY, 16 );
624
625     rdc.command[ 10 ] = DVD_REPORT_CHALLENGE | (*pi_agid << 6);
626
627     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
628
629     memcpy( p_challenge, p_buffer + 4, 12 );
630
631 #elif defined( HPUX_SCTL_IO )
632     INIT_SCTL_IO( GPCMD_REPORT_KEY, 16 );
633
634     sctl_io.cdb[ 10 ] = DVD_REPORT_CHALLENGE | (*pi_agid << 6);
635
636     i_ret = ioctl( i_fd, SIOC_IO, &sctl_io );
637
638     memcpy( p_challenge, p_buffer + 4, 12 );
639
640 #elif defined( SOLARIS_USCSI )
641     INIT_USCSI( GPCMD_REPORT_KEY, 16 );
642     
643     rs_cdb.cdb_opaque[ 10 ] = DVD_REPORT_CHALLENGE | (*pi_agid << 6);
644     
645     i_ret = ioctl( i_fd, USCSICMD, &sc );
646     
647     if( i_ret < 0 || sc.uscsi_status )
648     {
649         i_ret = -1;
650     }
651
652     memcpy( p_challenge, p_buffer + 4, 12 );
653     
654 #elif defined( SYS_DARWIN )
655     dk_dvd_report_key_t dvd;
656     DVDChallengeKeyInfo dvdcki;
657     
658     memset(&dvd, 0, sizeof(dvd));
659     memset(&dvdcki, 0, sizeof(dvdcki));
660
661     dvd.buffer = &dvdcki;
662     dvd.bufferLength = sizeof(dvdcki);
663     dvd.format = kDVDKeyFormatChallengeKey;
664     dvd.grantID = *pi_agid;
665
666     /* dvdcki.dataLength[0] = 0x00; */ /* dataLength[0] is already memset to 0 */
667     dvdcki.dataLength[1] = 0x0e;
668
669     i_ret = ioctl( i_fd, DKIOCDVDREPORTKEY, &dvd );
670
671     memcpy( p_challenge, dvdcki.challengeKeyValue, sizeof(dvdcki.challengeKeyValue) );
672
673 #elif defined( WIN32 )
674     if( WIN2K ) /* NT/Win2000/Whistler */
675     {
676         DWORD tmp;
677         u8 buffer[DVD_CHALLENGE_KEY_LENGTH];
678         PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
679
680         memset( &buffer, 0, sizeof( buffer ) );
681
682         key->KeyLength  = DVD_CHALLENGE_KEY_LENGTH;
683         key->SessionId  = *pi_agid;
684         key->KeyType    = DvdChallengeKey;
685         key->KeyFlags   = 0;
686
687         i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key, 
688                 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
689
690         if( i_ret < 0 )
691         {
692             return i_ret;
693         }
694
695         memcpy( p_challenge, key->KeyData, 10 );
696     }
697     else
698     {
699         INIT_SSC( GPCMD_REPORT_KEY, 16 );
700
701         ssc.CDBByte[ 10 ] = DVD_REPORT_CHALLENGE | (*pi_agid << 6);
702
703         i_ret = WinSendSSC( i_fd, &ssc );
704
705         memcpy( p_challenge, p_buffer + 4, 12 );
706     }
707
708 #else
709     /* DVD ioctls unavailable - do as if the ioctl failed */
710     i_ret = -1;
711
712 #endif
713     return i_ret;
714 }
715
716 /*****************************************************************************
717  * ioctl_ReportASF: get ASF from the drive
718  *****************************************************************************/
719 int ioctl_ReportASF( int i_fd, int *pi_agid, int *pi_asf )
720 {
721     int i_ret;
722
723 #if defined( HAVE_LINUX_DVD_STRUCT )
724     dvd_authinfo auth_info;
725
726     auth_info.type = DVD_LU_SEND_ASF;
727     auth_info.lsasf.agid = *pi_agid;
728     auth_info.lsasf.asf = *pi_asf;
729
730     i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
731
732     *pi_asf = auth_info.lsasf.asf;
733
734 #elif defined( HAVE_BSD_DVD_STRUCT )
735     struct dvd_authinfo auth_info;
736
737     auth_info.format = DVD_REPORT_ASF;
738     auth_info.agid = *pi_agid;
739     auth_info.asf = *pi_asf;
740
741     i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
742
743     *pi_asf = auth_info.asf;
744
745 #elif defined( SYS_BEOS )
746     INIT_RDC( GPCMD_REPORT_KEY, 8 );
747
748     rdc.command[ 10 ] = DVD_REPORT_ASF | (*pi_agid << 6);
749
750     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
751
752     *pi_asf = p_buffer[ 7 ] & 1;
753
754 #elif defined( HPUX_SCTL_IO )
755     INIT_SCTL_IO( GPCMD_REPORT_KEY, 8 );
756
757     sctl_io.cdb[ 10 ] = DVD_REPORT_ASF | (*pi_agid << 6);
758
759     i_ret = ioctl( i_fd, SIOC_IO, &sctl_io );
760
761     *pi_asf = p_buffer[ 7 ] & 1;
762
763 #elif defined( SOLARIS_USCSI )
764     INIT_USCSI( GPCMD_REPORT_KEY, 8 );
765     
766     rs_cdb.cdb_opaque[ 10 ] = DVD_REPORT_ASF | (*pi_agid << 6);
767     
768     i_ret = ioctl( i_fd, USCSICMD, &sc );
769     
770     if( i_ret < 0 || sc.uscsi_status )
771     {
772         i_ret = -1;
773     }
774
775     *pi_asf = p_buffer[ 7 ] & 1;
776     
777 #elif defined( SYS_DARWIN )
778     dk_dvd_report_key_t dvd;
779     DVDAuthenticationSuccessFlagInfo dvdasfi;
780     
781     memset(&dvd, 0, sizeof(dvd));
782     memset(&dvdasfi, 0, sizeof(dvdasfi));
783
784     dvd.buffer = &dvdasfi;
785     dvd.bufferLength = sizeof(dvdasfi);
786     dvd.format = kDVDKeyFormatASF;
787     dvd.grantID = *pi_agid;
788     dvdasfi.successFlag = *pi_asf;
789
790     /* dvdasfi.dataLength[0] = 0x00; */ /* dataLength[0] is already memset to 0 */
791     dvdasfi.dataLength[1] = 0x06;
792     
793     i_ret = ioctl( i_fd, DKIOCDVDREPORTKEY, &dvd );
794
795     *pi_asf = dvdasfi.successFlag;
796
797 #elif defined( WIN32 )
798     if( WIN2K ) /* NT/Win2000/Whistler */
799     {
800         DWORD tmp;
801         u8 buffer[DVD_ASF_LENGTH];
802         PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
803
804         memset( &buffer, 0, sizeof( buffer ) );
805
806         key->KeyLength  = DVD_ASF_LENGTH;
807         key->SessionId  = *pi_agid;
808         key->KeyType    = DvdAsf;
809         key->KeyFlags   = 0;
810
811         ((PDVD_ASF)key->KeyData)->SuccessFlag = *pi_asf;
812
813         i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key, 
814                 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
815
816         if( i_ret < 0 )
817         {
818             return i_ret;
819         }
820
821         *pi_asf = ((PDVD_ASF)key->KeyData)->SuccessFlag;
822     }
823     else
824     {
825         INIT_SSC( GPCMD_REPORT_KEY, 8 );
826
827         ssc.CDBByte[ 10 ] = DVD_REPORT_ASF | (*pi_agid << 6);
828
829         i_ret = WinSendSSC( i_fd, &ssc );
830
831         *pi_asf = p_buffer[ 7 ] & 1;
832     }
833
834 #else
835     /* DVD ioctls unavailable - do as if the ioctl failed */
836     i_ret = -1;
837
838 #endif
839     return i_ret;
840 }
841
842 /*****************************************************************************
843  * ioctl_ReportKey1: get the first key from the drive
844  *****************************************************************************/
845 int ioctl_ReportKey1( int i_fd, int *pi_agid, u8 *p_key )
846 {
847     int i_ret;
848
849 #if defined( HAVE_LINUX_DVD_STRUCT )
850     dvd_authinfo auth_info;
851
852     auth_info.type = DVD_LU_SEND_KEY1;
853     auth_info.lsk.agid = *pi_agid;
854
855     i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
856
857     memcpy( p_key, auth_info.lsk.key, sizeof(dvd_key) );
858
859 #elif defined( HAVE_BSD_DVD_STRUCT )
860     struct dvd_authinfo auth_info;
861
862     auth_info.format = DVD_REPORT_KEY1;
863     auth_info.agid = *pi_agid;
864
865     i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
866
867     memcpy( p_key, auth_info.keychal, 8 );
868
869 #elif defined( SYS_BEOS )
870     INIT_RDC( GPCMD_REPORT_KEY, 12 );
871
872     rdc.command[ 10 ] = DVD_REPORT_KEY1 | (*pi_agid << 6);
873
874     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
875
876     memcpy( p_key, p_buffer + 4, 8 );
877
878 #elif defined( HPUX_SCTL_IO )
879     INIT_SCTL_IO( GPCMD_REPORT_KEY, 12 );
880
881     sctl_io.cdb[ 10 ] = DVD_REPORT_KEY1 | (*pi_agid << 6);
882
883     i_ret = ioctl( i_fd, SIOC_IO, &sctl_io );
884
885     memcpy( p_key, p_buffer + 4, 8 );
886
887 #elif defined( SOLARIS_USCSI )
888     INIT_USCSI( GPCMD_REPORT_KEY, 12 );
889     
890     rs_cdb.cdb_opaque[ 10 ] = DVD_REPORT_KEY1 | (*pi_agid << 6);
891     
892     i_ret = ioctl( i_fd, USCSICMD, &sc );
893     
894     if( i_ret < 0 || sc.uscsi_status )
895     {
896         i_ret = -1;
897     }
898
899     memcpy( p_key, p_buffer + 4, 8 );;
900     
901 #elif defined( SYS_DARWIN )
902     dk_dvd_report_key_t dvd;
903     DVDKey1Info dvdk1i;
904     
905     memset(&dvd, 0, sizeof(dvd));
906     memset(&dvdk1i, 0, sizeof(dvdk1i));
907
908     dvd.buffer = &dvdk1i;
909     dvd.bufferLength = sizeof(dvdk1i);
910     dvd.format = kDVDKeyFormatKey1;
911     dvd.grantID = *pi_agid;
912     
913     /* dvdk1i.dataLength[0] = 0x00; */ /* dataLength[0] is already memset to 0 */
914     dvdk1i.dataLength[1] = 0x0a;
915
916     i_ret = ioctl( i_fd, DKIOCDVDREPORTKEY, &dvd );
917
918     memcpy( p_key, dvdk1i.key1Value, sizeof(dvdk1i.key1Value) );
919
920 #elif defined( WIN32 )
921     if( WIN2K ) /* NT/Win2000/Whistler */
922     {
923         DWORD tmp;
924         u8 buffer[DVD_BUS_KEY_LENGTH];
925         PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
926
927         memset( &buffer, 0, sizeof( buffer ) );
928
929         key->KeyLength  = DVD_BUS_KEY_LENGTH;
930         key->SessionId  = *pi_agid;
931         key->KeyType    = DvdBusKey1;
932         key->KeyFlags   = 0;
933
934         i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key, 
935                 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
936
937         memcpy( p_key, key->KeyData, 8 );
938     }
939     else
940     {
941         INIT_SSC( GPCMD_REPORT_KEY, 12 );
942
943         ssc.CDBByte[ 10 ] = DVD_REPORT_KEY1 | (*pi_agid << 6);
944
945         i_ret = WinSendSSC( i_fd, &ssc );
946
947         memcpy( p_key, p_buffer + 4, 8 );
948     }
949
950 #else
951     /* DVD ioctls unavailable - do as if the ioctl failed */
952     i_ret = -1;
953
954 #endif
955     return i_ret;
956 }
957
958 /*****************************************************************************
959  * ioctl_InvalidateAgid: invalidate the current AGID
960  *****************************************************************************/
961 int ioctl_InvalidateAgid( int i_fd, int *pi_agid )
962 {
963     int i_ret;
964
965 #if defined( HAVE_LINUX_DVD_STRUCT )
966     dvd_authinfo auth_info;
967
968     auth_info.type = DVD_INVALIDATE_AGID;
969     auth_info.lsa.agid = *pi_agid;
970
971     i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
972
973     *pi_agid = auth_info.lsa.agid;
974
975 #elif defined( HAVE_BSD_DVD_STRUCT )
976     struct dvd_authinfo auth_info;
977
978     auth_info.format = DVD_INVALIDATE_AGID;
979     auth_info.agid = *pi_agid;
980
981     i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
982
983     *pi_agid = auth_info.agid;
984
985 #elif defined( SYS_BEOS )
986     INIT_RDC( GPCMD_REPORT_KEY, 0 );
987
988     rdc.command[ 10 ] = DVD_INVALIDATE_AGID | (*pi_agid << 6);
989
990     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
991
992 #elif defined( HPUX_SCTL_IO )
993     INIT_SCTL_IO( GPCMD_REPORT_KEY, 0 );
994
995     sctl_io.cdb[ 10 ] = DVD_INVALIDATE_AGID | (*pi_agid << 6);
996
997     i_ret = ioctl( i_fd, SIOC_IO, &sctl_io );
998
999 #elif defined( SOLARIS_USCSI )
1000     INIT_USCSI( GPCMD_REPORT_KEY, 0 );
1001     
1002     rs_cdb.cdb_opaque[ 10 ] = DVD_INVALIDATE_AGID | (*pi_agid << 6);
1003     
1004     i_ret = ioctl( i_fd, USCSICMD, &sc );
1005     
1006     if( i_ret < 0 || sc.uscsi_status )
1007     {
1008         i_ret = -1;
1009     }
1010
1011 #elif defined( SYS_DARWIN )
1012     dk_dvd_send_key_t dvd;
1013     DVDAuthenticationGrantIDInfo dvdagid;
1014     
1015     memset(&dvd, 0, sizeof(dvd));
1016     memset(&dvdagid, 0, sizeof(dvdagid));
1017
1018     dvd.buffer = &dvdagid;
1019     dvd.bufferLength = sizeof(dvdagid);
1020     dvd.format = kDVDKeyFormatAGID_Invalidate;
1021     dvd.grantID = *pi_agid;
1022     dvdagid.grantID = *pi_agid; /* we need this? */
1023     
1024     /* dvdagid.dataLength[0] = 0x00; */ /* dataLength[0] is already memset to 0 */
1025     /* dvdagid.dataLength[1] = 0x06; */
1026
1027     i_ret = ioctl( i_fd, DKIOCDVDSENDKEY, &dvd );
1028
1029     *pi_agid = dvdagid.grantID;
1030
1031 #elif defined( WIN32 )
1032     if( WIN2K ) /* NT/Win2000/Whistler */
1033     {
1034         DWORD tmp;
1035
1036         i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_END_SESSION, 
1037                     pi_agid, sizeof( *pi_agid ), NULL, 0, &tmp, NULL ) ? 0 : -1;
1038     }
1039     else
1040     {
1041 #if defined( __MINGW32__ )
1042         INIT_SSC( GPCMD_REPORT_KEY, 0 );
1043 #else
1044         INIT_SSC( GPCMD_REPORT_KEY, 1 );
1045
1046         ssc.SRB_BufLen    = 0;
1047         ssc.CDBByte[ 8 ]  = 0;
1048         ssc.CDBByte[ 9 ]  = 0;
1049 #endif
1050
1051         ssc.CDBByte[ 10 ] = DVD_INVALIDATE_AGID | (*pi_agid << 6);
1052
1053         i_ret = WinSendSSC( i_fd, &ssc );
1054     }
1055
1056 #else
1057     /* DVD ioctls unavailable - do as if the ioctl failed */
1058     i_ret = -1;
1059
1060 #endif
1061     return i_ret;
1062 }
1063
1064 /*****************************************************************************
1065  * ioctl_SendChallenge: send challenge to the drive
1066  *****************************************************************************/
1067 int ioctl_SendChallenge( int i_fd, int *pi_agid, u8 *p_challenge )
1068 {
1069     int i_ret;
1070
1071 #if defined( HAVE_LINUX_DVD_STRUCT )
1072     dvd_authinfo auth_info;
1073
1074     auth_info.type = DVD_HOST_SEND_CHALLENGE;
1075     auth_info.hsc.agid = *pi_agid;
1076
1077     memcpy( auth_info.hsc.chal, p_challenge, sizeof(dvd_challenge) );
1078
1079     return ioctl( i_fd, DVD_AUTH, &auth_info );
1080
1081 #elif defined( HAVE_BSD_DVD_STRUCT )
1082     struct dvd_authinfo auth_info;
1083
1084     auth_info.format = DVD_SEND_CHALLENGE;
1085     auth_info.agid = *pi_agid;
1086
1087     memcpy( auth_info.keychal, p_challenge, 12 );
1088
1089     return ioctl( i_fd, DVDIOCSENDKEY, &auth_info );
1090
1091 #elif defined( SYS_BEOS )
1092     INIT_RDC( GPCMD_SEND_KEY, 16 );
1093
1094     rdc.command[ 10 ] = DVD_SEND_CHALLENGE | (*pi_agid << 6);
1095
1096     p_buffer[ 1 ] = 0xe;
1097     memcpy( p_buffer + 4, p_challenge, 12 );
1098
1099     return ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
1100
1101 #elif defined( HPUX_SCTL_IO )
1102     INIT_SCTL_IO( GPCMD_SEND_KEY, 16 );
1103
1104     sctl_io.cdb[ 10 ] = DVD_SEND_CHALLENGE | (*pi_agid << 6);
1105
1106     p_buffer[ 1 ] = 0xe;
1107     memcpy( p_buffer + 4, p_challenge, 12 );
1108
1109     return ioctl( i_fd, SIOC_IO, &sctl_io );
1110
1111 #elif defined( SOLARIS_USCSI )
1112     INIT_USCSI( GPCMD_SEND_KEY, 16 );
1113     
1114     rs_cdb.cdb_opaque[ 10 ] = DVD_SEND_CHALLENGE | (*pi_agid << 6);
1115     
1116     p_buffer[ 1 ] = 0xe;
1117     memcpy( p_buffer + 4, p_challenge, 12 );
1118     
1119     if( ioctl( i_fd, USCSICMD, &sc ) < 0 || sc.uscsi_status )
1120     {
1121         return -1;
1122     }
1123
1124     return 0;
1125     
1126 #elif defined( SYS_DARWIN )
1127     dk_dvd_send_key_t dvd;
1128     DVDChallengeKeyInfo dvdcki;
1129     
1130     memset(&dvd, 0, sizeof(dvd));
1131     memset(&dvdcki, 0, sizeof(dvdcki));
1132
1133     dvd.buffer = &dvdcki;
1134     dvd.bufferLength = sizeof(dvdcki);
1135     dvd.format = kDVDKeyFormatChallengeKey;
1136     dvd.grantID = *pi_agid;
1137
1138     /* dvdcki.dataLength[0] = 0x00; */ /* dataLength[0] is already memset to 0 */
1139     dvdcki.dataLength[1] = 0x0e;
1140
1141     memcpy( dvdcki.challengeKeyValue, p_challenge,  sizeof(dvdcki.challengeKeyValue) );
1142
1143     i_ret = ioctl( i_fd, DKIOCDVDSENDKEY, &dvd );
1144
1145 #elif defined( WIN32 )
1146     if( WIN2K ) /* NT/Win2000/Whistler */
1147     {
1148         DWORD tmp;
1149         u8 buffer[DVD_CHALLENGE_KEY_LENGTH];
1150         PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
1151
1152         memset( &buffer, 0, sizeof( buffer ) );
1153
1154         key->KeyLength  = DVD_CHALLENGE_KEY_LENGTH;
1155         key->SessionId  = *pi_agid;
1156         key->KeyType    = DvdChallengeKey;
1157         key->KeyFlags   = 0;
1158
1159         memcpy( key->KeyData, p_challenge, 10 );
1160
1161         return DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_SEND_KEY, key, 
1162                 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
1163     }
1164     else
1165     {
1166         INIT_SSC( GPCMD_SEND_KEY, 16 );
1167
1168         ssc.CDBByte[ 10 ] = DVD_SEND_CHALLENGE | (*pi_agid << 6);
1169
1170         p_buffer[ 1 ] = 0xe;
1171         memcpy( p_buffer + 4, p_challenge, 12 );
1172
1173         return WinSendSSC( i_fd, &ssc );
1174     }
1175
1176 #else
1177     /* DVD ioctls unavailable - do as if the ioctl failed */
1178     return -1;
1179
1180 #endif
1181     return i_ret;
1182 }
1183
1184 /*****************************************************************************
1185  * ioctl_SendKey2: send the second key to the drive
1186  *****************************************************************************/
1187 int ioctl_SendKey2( int i_fd, int *pi_agid, u8 *p_key )
1188 {
1189     int i_ret;
1190
1191 #if defined( HAVE_LINUX_DVD_STRUCT )
1192     dvd_authinfo auth_info;
1193
1194     auth_info.type = DVD_HOST_SEND_KEY2;
1195     auth_info.hsk.agid = *pi_agid;
1196
1197     memcpy( auth_info.hsk.key, p_key, sizeof(dvd_key) );
1198
1199     return ioctl( i_fd, DVD_AUTH, &auth_info );
1200
1201 #elif defined( HAVE_BSD_DVD_STRUCT )
1202     struct dvd_authinfo auth_info;
1203
1204     auth_info.format = DVD_SEND_KEY2;
1205     auth_info.agid = *pi_agid;
1206
1207     memcpy( auth_info.keychal, p_key, 8 );
1208
1209     return ioctl( i_fd, DVDIOCSENDKEY, &auth_info );
1210
1211 #elif defined( SYS_BEOS )
1212     INIT_RDC( GPCMD_SEND_KEY, 12 );
1213
1214     rdc.command[ 10 ] = DVD_SEND_KEY2 | (*pi_agid << 6);
1215
1216     p_buffer[ 1 ] = 0xa;
1217     memcpy( p_buffer + 4, p_key, 8 );
1218
1219     return ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
1220
1221 #elif defined( HPUX_SCTL_IO )
1222     INIT_SCTL_IO( GPCMD_SEND_KEY, 12 );
1223
1224     sctl_io.cdb[ 10 ] = DVD_SEND_KEY2 | (*pi_agid << 6);
1225
1226     p_buffer[ 1 ] = 0xa;
1227     memcpy( p_buffer + 4, p_key, 8 );
1228
1229     return ioctl( i_fd, SIOC_IO, &sctl_io );
1230
1231 #elif defined( SOLARIS_USCSI )
1232     INIT_USCSI( GPCMD_SEND_KEY, 12 );
1233     
1234     rs_cdb.cdb_opaque[ 10 ] = DVD_SEND_KEY2 | (*pi_agid << 6);
1235     
1236     p_buffer[ 1 ] = 0xa;
1237     memcpy( p_buffer + 4, p_key, 8 );
1238     
1239     if( ioctl( i_fd, USCSICMD, &sc ) < 0 || sc.uscsi_status )
1240     {
1241         return -1;
1242     }
1243
1244     return 0;
1245     
1246 #elif defined( SYS_DARWIN )
1247     dk_dvd_send_key_t dvd;
1248     DVDKey2Info dvdk2i;
1249     
1250     memset(&dvd, 0, sizeof(dvd));
1251     memset(&dvdk2i, 0, sizeof(dvdk2i));
1252
1253     dvd.buffer = &dvdk2i;
1254     dvd.bufferLength = sizeof(dvdk2i);
1255     dvd.format = kDVDKeyFormatKey2;
1256     dvd.grantID = *pi_agid;
1257
1258     /* dvdk2i.dataLength[0] = 0x00; */ /*dataLength[0] is already memset to 0 */
1259     dvdk2i.dataLength[1] = 0x0a;
1260     
1261     memcpy( dvdk2i.key2Value, p_key, sizeof(dvdk2i.key2Value) );
1262
1263     i_ret = ioctl( i_fd, DKIOCDVDSENDKEY, &dvd );
1264
1265 #elif defined( WIN32 )
1266     if( WIN2K ) /* NT/Win2000/Whistler */
1267     {
1268         DWORD tmp;
1269         u8 buffer[DVD_BUS_KEY_LENGTH];
1270         PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
1271
1272         memset( &buffer, 0, sizeof( buffer ) );
1273
1274         key->KeyLength  = DVD_BUS_KEY_LENGTH;
1275         key->SessionId  = *pi_agid;
1276         key->KeyType    = DvdBusKey2;
1277         key->KeyFlags   = 0;
1278
1279         memcpy( key->KeyData, p_key, 8 );
1280
1281         return DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_SEND_KEY, key, 
1282                 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
1283     }
1284     else
1285     {
1286         INIT_SSC( GPCMD_SEND_KEY, 12 );
1287
1288         ssc.CDBByte[ 10 ] = DVD_SEND_KEY2 | (*pi_agid << 6);
1289
1290         p_buffer[ 1 ] = 0xa;
1291         memcpy( p_buffer + 4, p_key, 8 );
1292
1293         return WinSendSSC( i_fd, &ssc );
1294     }
1295
1296 #else
1297     /* DVD ioctls unavailable - do as if the ioctl failed */
1298     return -1;
1299
1300 #endif
1301     return i_ret;
1302 }
1303
1304 /* Local prototypes */
1305
1306 #if defined( SYS_BEOS )
1307 /*****************************************************************************
1308  * BeInitRDC: initialize a RDC structure for the BeOS kernel
1309  *****************************************************************************
1310  * This function initializes a BeOS raw device command structure for future
1311  * use, either a read command or a write command.
1312  *****************************************************************************/
1313 static void BeInitRDC( raw_device_command *p_rdc, int i_type )
1314 {
1315     memset( p_rdc->data, 0, p_rdc->data_length );
1316
1317     switch( i_type )
1318     {
1319         case GPCMD_SEND_KEY:
1320             /* leave the flags to 0 */
1321             break;
1322
1323         case GPCMD_READ_DVD_STRUCTURE:
1324         case GPCMD_REPORT_KEY:
1325             p_rdc->flags = B_RAW_DEVICE_DATA_IN;
1326             break;
1327     }
1328
1329     p_rdc->command[ 0 ]      = i_type;
1330
1331     p_rdc->command[ 8 ]      = (p_rdc->data_length >> 8) & 0xff;
1332     p_rdc->command[ 9 ]      =  p_rdc->data_length       & 0xff;
1333     p_rdc->command_length    = 12;
1334
1335     p_rdc->sense_data        = NULL;
1336     p_rdc->sense_data_length = 0;
1337
1338     p_rdc->timeout           = 1000000;
1339 }
1340 #endif
1341
1342 #if defined( HPUX_SCTL_IO )
1343 /*****************************************************************************
1344  * HPUXInitSCTL: initialize a sctl_io structure for the HP-UX kernel
1345  *****************************************************************************
1346  * This function initializes a HP-UX command structure for future
1347  * use, either a read command or a write command.
1348  *****************************************************************************/
1349 static void HPUXInitSCTL( struct sctl_io *sctl_io, int i_type )
1350 {
1351     memset( sctl_io->data, 0, sctl_io->data_length );
1352
1353     switch( i_type )
1354     {
1355         case GPCMD_SEND_KEY:
1356             /* leave the flags to 0 */
1357             break;
1358
1359         case GPCMD_READ_DVD_STRUCTURE:
1360         case GPCMD_REPORT_KEY:
1361             sctl_io->flags = SCTL_READ;
1362             break;
1363     }
1364
1365     sctl_io->cdb[ 0 ]        = i_type;
1366
1367     sctl_io->cdb[ 8 ]        = (sctl_io->data_length >> 8) & 0xff;
1368     sctl_io->cdb[ 9 ]        =  sctl_io->data_length       & 0xff;
1369     sctl_io->cdb_length      = 12;
1370
1371     sctl_io->max_msecs       = 1000000;
1372 }
1373 #endif
1374
1375 #if defined( SOLARIS_USCSI )
1376 /*****************************************************************************
1377  * SolarisInitUSCSI: initialize a USCSICMD structure for the Solaris kernel
1378  *****************************************************************************
1379  * This function initializes a Solaris userspace scsi command structure for 
1380  * future use, either a read command or a write command.
1381  *****************************************************************************/
1382 static void SolarisInitUSCSI( struct uscsi_cmd *p_sc, int i_type )
1383 {   
1384     union scsi_cdb *rs_cdb;
1385     memset( p_sc->uscsi_cdb, 0, sizeof( union scsi_cdb ) );
1386     memset( p_sc->uscsi_bufaddr, 0, p_sc->uscsi_buflen );
1387     
1388     switch( i_type )
1389     {
1390         case GPCMD_SEND_KEY:
1391             p_sc->uscsi_flags = USCSI_ISOLATE | USCSI_WRITE;
1392             break;
1393
1394         case GPCMD_READ_DVD_STRUCTURE:
1395         case GPCMD_REPORT_KEY:
1396             p_sc->uscsi_flags = USCSI_ISOLATE | USCSI_READ;
1397             break;
1398     }
1399     
1400     rs_cdb = (union scsi_cdb *)p_sc->uscsi_cdb;
1401     
1402     rs_cdb->scc_cmd = i_type;
1403
1404     rs_cdb->cdb_opaque[ 8 ] = (p_sc->uscsi_buflen >> 8) & 0xff;
1405     rs_cdb->cdb_opaque[ 9 ] =  p_sc->uscsi_buflen       & 0xff;
1406     p_sc->uscsi_cdblen = 12;
1407
1408     USCSI_TIMEOUT( p_sc, 15 );
1409 }
1410 #endif
1411
1412 #if defined( WIN32 )
1413 /*****************************************************************************
1414  * WinInitSSC: initialize a ssc structure for the win32 aspi layer
1415  *****************************************************************************
1416  * This function initializes a ssc raw device command structure for future
1417  * use, either a read command or a write command.
1418  *****************************************************************************/
1419 static void WinInitSSC( struct SRB_ExecSCSICmd *p_ssc, int i_type )
1420 {
1421     memset( p_ssc->SRB_BufPointer, 0, p_ssc->SRB_BufLen );
1422
1423     switch( i_type )
1424     {
1425         case GPCMD_SEND_KEY:
1426             p_ssc->SRB_Flags = SRB_DIR_OUT;
1427             break;
1428
1429         case GPCMD_READ_DVD_STRUCTURE:
1430         case GPCMD_REPORT_KEY:
1431             p_ssc->SRB_Flags = SRB_DIR_IN;
1432             break;
1433     }
1434
1435     p_ssc->SRB_Cmd      = SC_EXEC_SCSI_CMD;
1436     p_ssc->SRB_Flags    |= SRB_EVENT_NOTIFY;
1437
1438     p_ssc->CDBByte[ 0 ] = i_type;
1439
1440     p_ssc->CDBByte[ 8 ] = (u8)(p_ssc->SRB_BufLen >> 8) & 0xff;
1441     p_ssc->CDBByte[ 9 ] = (u8) p_ssc->SRB_BufLen       & 0xff;
1442     p_ssc->SRB_CDBLen   = 12;
1443
1444     p_ssc->SRB_SenseLen = SENSE_LEN;
1445 }
1446
1447 /*****************************************************************************
1448  * WinSendSSC: send a ssc structure to the aspi layer
1449  *****************************************************************************/
1450 static int WinSendSSC( int i_fd, struct SRB_ExecSCSICmd *p_ssc )
1451 {
1452     HANDLE hEvent = NULL;
1453     struct w32_aspidev *fd = (struct w32_aspidev *) i_fd;
1454
1455     hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
1456     if( hEvent == NULL )
1457     {
1458         return -1;
1459     }
1460
1461     p_ssc->SRB_PostProc  = hEvent;
1462     p_ssc->SRB_HaId      = LOBYTE( fd->i_sid );
1463     p_ssc->SRB_Target    = HIBYTE( fd->i_sid );
1464
1465     ResetEvent( hEvent );
1466     if( fd->lpSendCommand( (void*) p_ssc ) == SS_PENDING )
1467         WaitForSingleObject( hEvent, INFINITE );
1468
1469     CloseHandle( hEvent );
1470
1471     return p_ssc->SRB_Status == SS_COMP ? 0 : -1;
1472 }
1473 #endif
1474