]> git.sesse.net Git - vlc/blob - extras/libdvdcss/ioctl.c
* Solaris DVD decryption support by H}kan Hjort <d95hjort@dtek.chalmers.se>.
[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.8 2001/08/08 02:48:44 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 DVD_STRUCT_IN_DVD_H
52 #   include <dvd.h>
53 #endif
54 #ifdef SYS_BEOS
55 #   include <malloc.h>
56 #   include <scsi.h>
57 #endif
58 #ifdef SOLARIS_USCSI
59 #   include <unistd.h>
60 #   include <stropts.h>
61 #   include </usr/include/sys/scsi/scsi_types.h>
62 #   include <sys/scsi/impl/uscsi.h>
63 #endif
64
65 #include "config.h"
66 #include "common.h"
67
68 #ifdef SYS_DARWIN
69 #   include "DVDioctl/DVDioctl.h"
70 #endif
71
72 #include "ioctl.h"
73
74 /*****************************************************************************
75  * Local prototypes, BeOS specific
76  *****************************************************************************/
77 #if defined( SYS_BEOS )
78 static void BeInitRDC ( raw_device_command *, int );
79 #endif
80
81 /*****************************************************************************
82  * Local prototypes, Solaris specific
83  *****************************************************************************/
84 #if defined( SOLARIS_USCSI )
85 static void SolarisInitUSCSI( struct uscsi_cmd *p_sc, int i_type );
86 #endif
87
88 /*****************************************************************************
89  * Local prototypes, win32 (aspi) specific
90  *****************************************************************************/
91 #if defined( WIN32 )
92 static void WinInitSSC ( struct SRB_ExecSCSICmd *, int );
93 static int  WinSendSSC ( int, struct SRB_ExecSCSICmd * );
94 #endif
95
96 /*****************************************************************************
97  * ioctl_ReadCopyright: check whether the disc is encrypted or not
98  *****************************************************************************/
99 int ioctl_ReadCopyright( int i_fd, int i_layer, int *pi_copyright )
100 {
101     int i_ret;
102
103 #if defined( HAVE_LINUX_DVD_STRUCT )
104     dvd_struct dvd;
105
106     dvd.type = DVD_STRUCT_COPYRIGHT;
107     dvd.copyright.layer_num = i_layer;
108
109     i_ret = ioctl( i_fd, DVD_READ_STRUCT, &dvd );
110
111     *pi_copyright = dvd.copyright.cpst;
112
113 #elif defined( HAVE_BSD_DVD_STRUCT )
114     struct dvd_struct dvd;
115
116     dvd.format = DVD_STRUCT_COPYRIGHT;
117     dvd.layer_num = i_layer;
118
119     i_ret = ioctl( i_fd, DVDIOCREADSTRUCTURE, &dvd );
120
121     *pi_copyright = dvd.cpst;
122
123 #elif defined( SYS_BEOS )
124     INIT_RDC( GPCMD_READ_DVD_STRUCTURE, 8 );
125
126     rdc.command[ 6 ] = i_layer;
127     rdc.command[ 7 ] = DVD_STRUCT_COPYRIGHT;
128
129     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
130
131     *pi_copyright = p_buffer[ 4 ];
132
133 #elif defined( SOLARIS_USCSI )
134     INIT_USCSI( GPCMD_READ_DVD_STRUCTURE, 8 );
135     
136     rs_cdb.cdb_opaque[ 6 ] = i_layer;
137     rs_cdb.cdb_opaque[ 7 ] = DVD_STRUCT_COPYRIGHT;
138
139     i_ret = ioctl(i_fd, USCSICMD, &sc);
140
141     if( i_ret < 0 || sc.uscsi_status ) {
142         i_ret = -1;
143     }
144     
145     *pi_copyright = p_buffer[ 4 ];
146     // s->copyright.rmi = p_buffer[ 5 ];
147
148 #elif defined( SYS_DARWIN )
149     *pi_copyright = 1;
150
151     i_ret = 0;
152
153 #elif defined( WIN32 )
154     if( WIN2K ) /* NT/Win2000/Whistler */
155     {
156         DWORD tmp;
157         u8 p_buffer[ 8 ];
158         SCSI_PASS_THROUGH_DIRECT sptd;
159
160         memset( &sptd, 0, sizeof( sptd ) );
161         memset( &p_buffer, 0, sizeof( p_buffer ) );
162    
163         /*  When using IOCTL_DVD_READ_STRUCTURE and 
164             DVD_COPYRIGHT_DESCRIPTOR, CopyrightProtectionType
165             is always 6. So we send a raw scsi command instead. */
166
167         sptd.Length             = sizeof( SCSI_PASS_THROUGH_DIRECT );
168         sptd.CdbLength          = 12;
169         sptd.DataIn             = SCSI_IOCTL_DATA_IN;
170         sptd.DataTransferLength = 8;
171         sptd.TimeOutValue       = 2;
172         sptd.DataBuffer         = p_buffer;
173         sptd.Cdb[ 0 ]           = GPCMD_READ_DVD_STRUCTURE;
174         sptd.Cdb[ 6 ]           = i_layer;
175         sptd.Cdb[ 7 ]           = DVD_STRUCT_COPYRIGHT;
176         sptd.Cdb[ 8 ]           = (8 >> 8) & 0xff;
177         sptd.Cdb[ 9 ]           =  8       & 0xff;
178
179         i_ret = DeviceIoControl( (HANDLE) i_fd,
180                              IOCTL_SCSI_PASS_THROUGH_DIRECT,
181                              &sptd, sizeof( SCSI_PASS_THROUGH_DIRECT ),
182                              &sptd, sizeof( SCSI_PASS_THROUGH_DIRECT ),
183                              &tmp, NULL ) ? 0 : -1;
184
185         *pi_copyright = p_buffer[4];
186     }
187     else
188     {
189         INIT_SSC( GPCMD_READ_DVD_STRUCTURE, 8 );
190
191         ssc.CDBByte[ 6 ] = i_layer;
192         ssc.CDBByte[ 7 ] = DVD_STRUCT_COPYRIGHT;
193
194         i_ret = WinSendSSC( i_fd, &ssc );
195
196         *pi_copyright = p_buffer[ 4 ];
197     }
198
199 #elif defined( __QNXNTO__ )
200     /*
201         QNX RTOS currently doesn't have a CAM
202         interface (they're working on it though).
203         Assume DVD is not encrypted.
204     */
205
206     *pi_copyright = 0;
207     i_ret = 0;
208
209 #else
210     /* DVD ioctls unavailable - do as if the ioctl failed */
211     i_ret = -1;
212
213 #endif
214     return i_ret;
215 }
216
217 /*****************************************************************************
218  * ioctl_ReadKey: get the disc key
219  *****************************************************************************/
220 int ioctl_ReadKey( int i_fd, int *pi_agid, u8 *p_key )
221 {
222     int i_ret;
223
224 #if defined( HAVE_LINUX_DVD_STRUCT )
225     dvd_struct dvd;
226
227     dvd.type = DVD_STRUCT_DISCKEY;
228     dvd.disckey.agid = *pi_agid;
229     memset( dvd.disckey.value, 0, 2048 );
230
231     i_ret = ioctl( i_fd, DVD_READ_STRUCT, &dvd );
232
233     if( i_ret < 0 )
234     {
235         return i_ret;
236     }
237
238     memcpy( p_key, dvd.disckey.value, 2048 );
239
240 #elif defined( HAVE_BSD_DVD_STRUCT )
241     struct dvd_struct dvd;
242
243     dvd.format = DVD_STRUCT_DISCKEY;
244     dvd.agid = *pi_agid;
245     memset( dvd.data, 0, 2048 );
246
247     i_ret = ioctl( i_fd, DVDIOCREADSTRUCTURE, &dvd );
248
249     if( i_ret < 0 )
250     {
251         return i_ret;
252     }
253
254     memcpy( p_key, dvd.data, 2048 );
255
256 #elif defined( SYS_BEOS )
257     INIT_RDC( GPCMD_READ_DVD_STRUCTURE, 2048 + 4 );
258
259     rdc.command[ 7 ]  = DVD_STRUCT_DISCKEY;
260     rdc.command[ 10 ] = *pi_agid << 6;
261     
262     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
263
264     if( i_ret < 0 )
265     {
266         return i_ret;
267     }
268
269     memcpy( p_key, p_buffer + 4, 2048 );
270
271 #elif defined( SOLARIS_USCSI )
272     INIT_USCSI( GPCMD_READ_DVD_STRUCTURE, 2048 + 4 );
273     
274     rs_cdb.cdb_opaque[ 7 ] = DVD_STRUCT_DISCKEY;
275     rs_cdb.cdb_opaque[ 10 ] = *pi_agid << 6;
276     
277     i_ret = ioctl( i_fd, USCSICMD, &sc );
278     
279     if( i_ret < 0 || sc.uscsi_status )
280     {
281         i_ret = -1;
282         return i_ret;
283     }
284
285     memcpy( p_key, p_buffer + 4, 2048 );
286
287 #elif defined( SYS_DARWIN )
288     i_ret = 0;
289
290     memset( p_key, 0x00, 2048 );
291
292 #elif defined( WIN32 )
293     if( WIN2K ) /* NT/Win2000/Whistler */
294     {
295         DWORD tmp;
296         u8 buffer[DVD_DISK_KEY_LENGTH];
297         PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
298
299         memset( &buffer, 0, sizeof( buffer ) );
300
301         key->KeyLength  = DVD_DISK_KEY_LENGTH;
302         key->SessionId  = *pi_agid;
303         key->KeyType    = DvdDiskKey;
304         key->KeyFlags   = 0;
305
306         i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key, 
307                 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
308
309         if( i_ret < 0 )
310         {   
311             return i_ret;
312         }
313
314         memcpy( p_key, key->KeyData, 2048 );
315     }
316     else
317     {
318         INIT_SSC( GPCMD_READ_DVD_STRUCTURE, 2048 + 4 );
319
320         ssc.CDBByte[ 7 ]  = DVD_STRUCT_DISCKEY;
321         ssc.CDBByte[ 10 ] = *pi_agid << 6;
322     
323         i_ret = WinSendSSC( i_fd, &ssc );
324
325         if( i_ret < 0 )
326         {
327             return i_ret;
328         }
329
330         memcpy( p_key, p_buffer + 4, 2048 );
331     }
332
333 #else
334     /* DVD ioctls unavailable - do as if the ioctl failed */
335     i_ret = -1;
336
337 #endif
338     return i_ret;
339 }
340
341 /*****************************************************************************
342  * ioctl_ReportAgid: get AGID from the drive
343  *****************************************************************************/
344 int ioctl_ReportAgid( int i_fd, int *pi_agid )
345 {
346     int i_ret;
347
348 #if defined( HAVE_LINUX_DVD_STRUCT )
349     dvd_authinfo auth_info;
350
351     auth_info.type = DVD_LU_SEND_AGID;
352     auth_info.lsa.agid = *pi_agid;
353
354     i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
355
356     *pi_agid = auth_info.lsa.agid;
357
358 #elif defined( HAVE_BSD_DVD_STRUCT )
359     struct dvd_authinfo auth_info;
360
361     auth_info.format = DVD_REPORT_AGID;
362     auth_info.agid = *pi_agid;
363
364     i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
365
366     *pi_agid = auth_info.agid;
367
368 #elif defined( SYS_BEOS )
369     INIT_RDC( GPCMD_REPORT_KEY, 8 );
370
371     rdc.command[ 10 ] = DVD_REPORT_AGID | (*pi_agid << 6);
372
373     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
374
375     *pi_agid = p_buffer[ 7 ] >> 6;
376
377 #elif defined( SOLARIS_USCSI )
378     INIT_USCSI( GPCMD_REPORT_KEY, 8 );
379     
380     rs_cdb.cdb_opaque[ 10 ] = DVD_REPORT_AGID | (*pi_agid << 6);
381     
382     i_ret = ioctl( i_fd, USCSICMD, &sc );
383     
384     if( i_ret < 0 || sc.uscsi_status )
385     {
386         i_ret = -1;
387     }
388
389     *pi_agid = p_buffer[ 7 ] >> 6;
390     
391 #elif defined( SYS_DARWIN )
392     INIT_DVDIOCTL( 8 );
393
394     dvdioctl.i_keyformat = kCSSAGID;
395     dvdioctl.i_agid = *pi_agid;
396     dvdioctl.i_lba = 0;
397
398     i_ret = ioctl( i_fd, IODVD_REPORT_KEY, &dvdioctl );
399
400     *pi_agid = p_buffer[ 7 ] >> 6;
401
402 #elif defined( WIN32 )
403     if( WIN2K ) /* NT/Win2000/Whistler */
404     {
405         ULONG id;
406         DWORD tmp;
407
408         i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_START_SESSION, 
409                         &tmp, 4, &id, sizeof( id ), &tmp, NULL ) ? 0 : -1;
410
411         *pi_agid = id;
412     }
413     else
414     {
415         INIT_SSC( GPCMD_REPORT_KEY, 8 );
416
417         ssc.CDBByte[ 10 ] = DVD_REPORT_AGID | (*pi_agid << 6);
418
419         i_ret = WinSendSSC( i_fd, &ssc );
420
421         *pi_agid = p_buffer[ 7 ] >> 6;
422     }
423
424 #else
425     /* DVD ioctls unavailable - do as if the ioctl failed */
426     i_ret = -1;
427
428 #endif
429     return i_ret;
430 }
431
432 /*****************************************************************************
433  * ioctl_ReportChallenge: get challenge from the drive
434  *****************************************************************************/
435 int ioctl_ReportChallenge( int i_fd, int *pi_agid, u8 *p_challenge )
436 {
437     int i_ret;
438
439 #if defined( HAVE_LINUX_DVD_STRUCT )
440     dvd_authinfo auth_info;
441
442     auth_info.type = DVD_LU_SEND_CHALLENGE;
443     auth_info.lsc.agid = *pi_agid;
444
445     i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
446
447     memcpy( p_challenge, auth_info.lsc.chal, sizeof(dvd_challenge) );
448
449 #elif defined( HAVE_BSD_DVD_STRUCT )
450     struct dvd_authinfo auth_info;
451
452     auth_info.format = DVD_REPORT_CHALLENGE;
453     auth_info.agid = *pi_agid;
454
455     i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
456
457     memcpy( p_challenge, auth_info.keychal, 10 );
458
459 #elif defined( SYS_BEOS )
460     INIT_RDC( GPCMD_REPORT_KEY, 16 );
461
462     rdc.command[ 10 ] = DVD_REPORT_CHALLENGE | (*pi_agid << 6);
463
464     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
465
466     memcpy( p_challenge, p_buffer + 4, 12 );
467
468 #elif defined( SOLARIS_USCSI )
469     INIT_USCSI( GPCMD_REPORT_KEY, 16 );
470     
471     rs_cdb.cdb_opaque[ 10 ] = DVD_REPORT_CHALLENGE | (*pi_agid << 6);
472     
473     i_ret = ioctl( i_fd, USCSICMD, &sc );
474     
475     if( i_ret < 0 || sc.uscsi_status )
476     {
477         i_ret = -1;
478     }
479
480     memcpy( p_challenge, p_buffer + 4, 12 );
481     
482 #elif defined( SYS_DARWIN )
483     INIT_DVDIOCTL( 16 );
484
485     dvdioctl.i_keyformat = kChallengeKey;
486     dvdioctl.i_agid = *pi_agid;
487     dvdioctl.i_lba = 0;
488
489     i_ret = ioctl( i_fd, IODVD_REPORT_KEY, &dvdioctl );
490
491     memcpy( p_challenge, p_buffer + 4, 12 );
492
493 #elif defined( WIN32 )
494     if( WIN2K ) /* NT/Win2000/Whistler */
495     {
496         DWORD tmp;
497         u8 buffer[DVD_CHALLENGE_KEY_LENGTH];
498         PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
499
500         memset( &buffer, 0, sizeof( buffer ) );
501
502         key->KeyLength  = DVD_CHALLENGE_KEY_LENGTH;
503         key->SessionId  = *pi_agid;
504         key->KeyType    = DvdChallengeKey;
505         key->KeyFlags   = 0;
506
507         i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key, 
508                 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
509
510         if( i_ret < 0 )
511         {
512             return i_ret;
513         }
514
515         memcpy( p_challenge, key->KeyData, 10 );
516     }
517     else
518     {
519         INIT_SSC( GPCMD_REPORT_KEY, 16 );
520
521         ssc.CDBByte[ 10 ] = DVD_REPORT_CHALLENGE | (*pi_agid << 6);
522
523         i_ret = WinSendSSC( i_fd, &ssc );
524
525         memcpy( p_challenge, p_buffer + 4, 12 );
526     }
527
528 #else
529     /* DVD ioctls unavailable - do as if the ioctl failed */
530     i_ret = -1;
531
532 #endif
533     return i_ret;
534 }
535
536 /*****************************************************************************
537  * ioctl_ReportASF: get ASF from the drive
538  *****************************************************************************/
539 int ioctl_ReportASF( int i_fd, int *pi_agid, int *pi_asf )
540 {
541     int i_ret;
542
543 #if defined( HAVE_LINUX_DVD_STRUCT )
544     dvd_authinfo auth_info;
545
546     auth_info.type = DVD_LU_SEND_ASF;
547     auth_info.lsasf.agid = *pi_agid;
548     auth_info.lsasf.asf = *pi_asf;
549
550     i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
551
552     *pi_asf = auth_info.lsasf.asf;
553
554 #elif defined( HAVE_BSD_DVD_STRUCT )
555     struct dvd_authinfo auth_info;
556
557     auth_info.format = DVD_REPORT_ASF;
558     auth_info.agid = *pi_agid;
559     auth_info.asf = *pi_asf;
560
561     i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
562
563     *pi_asf = auth_info.asf;
564
565 #elif defined( SYS_BEOS )
566     INIT_RDC( GPCMD_REPORT_KEY, 8 );
567
568     rdc.command[ 10 ] = DVD_REPORT_ASF | (*pi_agid << 6);
569
570     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
571
572     *pi_asf = p_buffer[ 7 ] & 1;
573
574 #elif defined( SOLARIS_USCSI )
575     INIT_USCSI( GPCMD_REPORT_KEY, 8 );
576     
577     rs_cdb.cdb_opaque[ 10 ] = DVD_REPORT_ASF | (*pi_agid << 6);
578     
579     i_ret = ioctl( i_fd, USCSICMD, &sc );
580     
581     if( i_ret < 0 || sc.uscsi_status )
582     {
583         i_ret = -1;
584     }
585
586     *pi_asf = p_buffer[ 7 ] & 1;
587     
588 #elif defined( SYS_DARWIN )
589     INIT_DVDIOCTL( 8 );
590
591     dvdioctl.i_keyformat = kASF;
592     dvdioctl.i_agid = *pi_agid;
593     dvdioctl.i_lba = 0;
594
595     i_ret = ioctl( i_fd, IODVD_REPORT_KEY, &dvdioctl );
596
597     *pi_asf = p_buffer[ 7 ] & 1;
598
599 #elif defined( WIN32 )
600     if( WIN2K ) /* NT/Win2000/Whistler */
601     {
602         DWORD tmp;
603         u8 buffer[DVD_ASF_LENGTH];
604         PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
605
606         memset( &buffer, 0, sizeof( buffer ) );
607
608         key->KeyLength  = DVD_ASF_LENGTH;
609         key->SessionId  = *pi_agid;
610         key->KeyType    = DvdAsf;
611         key->KeyFlags   = 0;
612
613         ((PDVD_ASF)key->KeyData)->SuccessFlag = *pi_asf;
614
615         i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key, 
616                 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
617
618         if( i_ret < 0 )
619         {
620             return i_ret;
621         }
622
623         *pi_asf = ((PDVD_ASF)key->KeyData)->SuccessFlag;
624     }
625     else
626     {
627         INIT_SSC( GPCMD_REPORT_KEY, 8 );
628
629         ssc.CDBByte[ 10 ] = DVD_REPORT_ASF | (*pi_agid << 6);
630
631         i_ret = WinSendSSC( i_fd, &ssc );
632
633         *pi_asf = p_buffer[ 7 ] & 1;
634     }
635
636 #else
637     /* DVD ioctls unavailable - do as if the ioctl failed */
638     i_ret = -1;
639
640 #endif
641     return i_ret;
642 }
643
644 /*****************************************************************************
645  * ioctl_ReportKey1: get the first key from the drive
646  *****************************************************************************/
647 int ioctl_ReportKey1( int i_fd, int *pi_agid, u8 *p_key )
648 {
649     int i_ret;
650
651 #if defined( HAVE_LINUX_DVD_STRUCT )
652     dvd_authinfo auth_info;
653
654     auth_info.type = DVD_LU_SEND_KEY1;
655     auth_info.lsk.agid = *pi_agid;
656
657     i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
658
659     memcpy( p_key, auth_info.lsk.key, sizeof(dvd_key) );
660
661 #elif defined( HAVE_BSD_DVD_STRUCT )
662     struct dvd_authinfo auth_info;
663
664     auth_info.format = DVD_REPORT_KEY1;
665     auth_info.agid = *pi_agid;
666
667     i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
668
669     memcpy( p_key, auth_info.keychal, 8 );
670
671 #elif defined( SYS_BEOS )
672     INIT_RDC( GPCMD_REPORT_KEY, 12 );
673
674     rdc.command[ 10 ] = DVD_REPORT_KEY1 | (*pi_agid << 6);
675
676     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
677
678     memcpy( p_key, p_buffer + 4, 8 );
679
680 #elif defined( SOLARIS_USCSI )
681     INIT_USCSI( GPCMD_REPORT_KEY, 12 );
682     
683     rs_cdb.cdb_opaque[ 10 ] = DVD_REPORT_KEY1 | (*pi_agid << 6);
684     
685     i_ret = ioctl( i_fd, USCSICMD, &sc );
686     
687     if( i_ret < 0 || sc.uscsi_status )
688     {
689         i_ret = -1;
690     }
691
692     memcpy( p_key, p_buffer + 4, 8 );;
693     
694 #elif defined( SYS_DARWIN )
695     INIT_DVDIOCTL( 12 );
696
697     dvdioctl.i_keyformat = kKey1;
698     dvdioctl.i_agid = *pi_agid;
699
700     i_ret = ioctl( i_fd, IODVD_SEND_KEY, &dvdioctl );
701
702     memcpy( p_key, p_buffer + 4, 8 );
703
704 #elif defined( WIN32 )
705     if( WIN2K ) /* NT/Win2000/Whistler */
706     {
707         DWORD tmp;
708         u8 buffer[DVD_BUS_KEY_LENGTH];
709         PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
710
711         memset( &buffer, 0, sizeof( buffer ) );
712
713         key->KeyLength  = DVD_BUS_KEY_LENGTH;
714         key->SessionId  = *pi_agid;
715         key->KeyType    = DvdBusKey1;
716         key->KeyFlags   = 0;
717
718         i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key, 
719                 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
720
721         memcpy( p_key, key->KeyData, 8 );
722     }
723     else
724     {
725         INIT_SSC( GPCMD_REPORT_KEY, 12 );
726
727         ssc.CDBByte[ 10 ] = DVD_REPORT_KEY1 | (*pi_agid << 6);
728
729         i_ret = WinSendSSC( i_fd, &ssc );
730
731         memcpy( p_key, p_buffer + 4, 8 );
732     }
733
734 #else
735     /* DVD ioctls unavailable - do as if the ioctl failed */
736     i_ret = -1;
737
738 #endif
739     return i_ret;
740 }
741
742 /*****************************************************************************
743  * ioctl_InvalidateAgid: invalidate the current AGID
744  *****************************************************************************/
745 int ioctl_InvalidateAgid( int i_fd, int *pi_agid )
746 {
747     int i_ret;
748
749 #if defined( HAVE_LINUX_DVD_STRUCT )
750     dvd_authinfo auth_info;
751
752     auth_info.type = DVD_INVALIDATE_AGID;
753     auth_info.lsa.agid = *pi_agid;
754
755     i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
756
757     *pi_agid = auth_info.lsa.agid;
758
759 #elif defined( HAVE_BSD_DVD_STRUCT )
760     struct dvd_authinfo auth_info;
761
762     auth_info.format = DVD_INVALIDATE_AGID;
763     auth_info.agid = *pi_agid;
764
765     i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
766
767     *pi_agid = auth_info.agid;
768
769 #elif defined( SYS_BEOS )
770     INIT_RDC( GPCMD_REPORT_KEY, 0 );
771
772     rdc.command[ 10 ] = DVD_INVALIDATE_AGID | (*pi_agid << 6);
773
774     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
775
776 #elif defined( SOLARIS_USCSI )
777     INIT_USCSI( GPCMD_REPORT_KEY, 0 );
778     
779     rs_cdb.cdb_opaque[ 10 ] = DVD_INVALIDATE_AGID | (*pi_agid << 6);
780     
781     i_ret = ioctl( i_fd, USCSICMD, &sc );
782     
783     if( i_ret < 0 || sc.uscsi_status )
784     {
785         i_ret = -1;
786     }
787
788 #elif defined( SYS_DARWIN )
789     INIT_DVDIOCTL( 0 );
790
791     dvdioctl.i_keyformat = kInvalidateAGID;
792     dvdioctl.i_agid = *pi_agid;
793
794     i_ret = ioctl( i_fd, IODVD_SEND_KEY, &dvdioctl );
795
796 #elif defined( WIN32 )
797     if( WIN2K ) /* NT/Win2000/Whistler */
798     {
799         DWORD tmp;
800
801         i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_END_SESSION, 
802                     pi_agid, sizeof( *pi_agid ), NULL, 0, &tmp, NULL ) ? 0 : -1;
803     }
804     else
805     {
806 #if defined( __MINGW32__ )
807         INIT_SSC( GPCMD_REPORT_KEY, 0 );
808 #else
809         INIT_SSC( GPCMD_REPORT_KEY, 1 );
810
811         ssc.SRB_BufLen    = 0;
812         ssc.CDBByte[ 8 ]  = 0;
813         ssc.CDBByte[ 9 ]  = 0;
814 #endif
815
816         ssc.CDBByte[ 10 ] = DVD_INVALIDATE_AGID | (*pi_agid << 6);
817
818         i_ret = WinSendSSC( i_fd, &ssc );
819     }
820
821 #else
822     /* DVD ioctls unavailable - do as if the ioctl failed */
823     i_ret = -1;
824
825 #endif
826     return i_ret;
827 }
828
829 /*****************************************************************************
830  * ioctl_SendChallenge: send challenge to the drive
831  *****************************************************************************/
832 int ioctl_SendChallenge( int i_fd, int *pi_agid, u8 *p_challenge )
833 {
834 #if defined( HAVE_LINUX_DVD_STRUCT )
835     dvd_authinfo auth_info;
836
837     auth_info.type = DVD_HOST_SEND_CHALLENGE;
838     auth_info.hsc.agid = *pi_agid;
839
840     memcpy( auth_info.hsc.chal, p_challenge, sizeof(dvd_challenge) );
841
842     return ioctl( i_fd, DVD_AUTH, &auth_info );
843
844 #elif defined( HAVE_BSD_DVD_STRUCT )
845     struct dvd_authinfo auth_info;
846
847     auth_info.format = DVD_SEND_CHALLENGE;
848     auth_info.agid = *pi_agid;
849
850     memcpy( auth_info.keychal, p_challenge, 12 );
851
852     return ioctl( i_fd, DVDIOCSENDKEY, &auth_info );
853
854 #elif defined( SYS_BEOS )
855     INIT_RDC( GPCMD_SEND_KEY, 16 );
856
857     rdc.command[ 10 ] = DVD_SEND_CHALLENGE | (*pi_agid << 6);
858
859     p_buffer[ 1 ] = 0xe;
860     memcpy( p_buffer + 4, p_challenge, 12 );
861
862     return ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
863
864 #elif defined( SOLARIS_USCSI )
865     INIT_USCSI( GPCMD_SEND_KEY, 16 );
866     
867     rs_cdb.cdb_opaque[ 10 ] = DVD_SEND_CHALLENGE | (*pi_agid << 6);
868     
869     p_buffer[ 1 ] = 0xe;
870     memcpy( p_buffer + 4, p_challenge, 12 );
871     
872     if( ioctl( i_fd, USCSICMD, &sc ) < 0 || sc.uscsi_status )
873     {
874         return -1;
875     }
876
877     return 0;
878     
879 #elif defined( SYS_DARWIN )
880     INIT_DVDIOCTL( 16 );
881
882     dvdioctl.i_keyformat = kChallengeKey;
883     dvdioctl.i_agid = *pi_agid;
884
885     p_buffer[ 1 ] = 0xe;
886     memcpy( p_buffer + 4, p_challenge, 12 );
887
888     return ioctl( i_fd, IODVD_SEND_KEY, &dvdioctl );
889
890 #elif defined( WIN32 )
891     if( WIN2K ) /* NT/Win2000/Whistler */
892     {
893         DWORD tmp;
894         u8 buffer[DVD_CHALLENGE_KEY_LENGTH];
895         PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
896
897         memset( &buffer, 0, sizeof( buffer ) );
898
899         key->KeyLength  = DVD_CHALLENGE_KEY_LENGTH;
900         key->SessionId  = *pi_agid;
901         key->KeyType    = DvdChallengeKey;
902         key->KeyFlags   = 0;
903
904         memcpy( key->KeyData, p_challenge, 10 );
905
906         return DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_SEND_KEY, key, 
907                 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
908     }
909     else
910     {
911         INIT_SSC( GPCMD_SEND_KEY, 16 );
912
913         ssc.CDBByte[ 10 ] = DVD_SEND_CHALLENGE | (*pi_agid << 6);
914
915         p_buffer[ 1 ] = 0xe;
916         memcpy( p_buffer + 4, p_challenge, 12 );
917
918         return WinSendSSC( i_fd, &ssc );
919     }
920
921 #else
922     /* DVD ioctls unavailable - do as if the ioctl failed */
923     return -1;
924
925 #endif
926 }
927
928 /*****************************************************************************
929  * ioctl_SendKey2: send the second key to the drive
930  *****************************************************************************/
931 int ioctl_SendKey2( int i_fd, int *pi_agid, u8 *p_key )
932 {
933 #if defined( HAVE_LINUX_DVD_STRUCT )
934     dvd_authinfo auth_info;
935
936     auth_info.type = DVD_HOST_SEND_KEY2;
937     auth_info.hsk.agid = *pi_agid;
938
939     memcpy( auth_info.hsk.key, p_key, sizeof(dvd_key) );
940
941     return ioctl( i_fd, DVD_AUTH, &auth_info );
942
943 #elif defined( HAVE_BSD_DVD_STRUCT )
944     struct dvd_authinfo auth_info;
945
946     auth_info.format = DVD_SEND_KEY2;
947     auth_info.agid = *pi_agid;
948
949     memcpy( auth_info.keychal, p_key, 8 );
950
951     return ioctl( i_fd, DVDIOCSENDKEY, &auth_info );
952
953 #elif defined( SYS_BEOS )
954     INIT_RDC( GPCMD_SEND_KEY, 12 );
955
956     rdc.command[ 10 ] = DVD_SEND_KEY2 | (*pi_agid << 6);
957
958     p_buffer[ 1 ] = 0xa;
959     memcpy( p_buffer + 4, p_key, 8 );
960
961     return ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
962
963 #elif defined( SOLARIS_USCSI )
964     INIT_USCSI( GPCMD_SEND_KEY, 12 );
965     
966     rs_cdb.cdb_opaque[ 10 ] = DVD_SEND_KEY2 | (*pi_agid << 6);
967     
968     p_buffer[ 1 ] = 0xa;
969     memcpy( p_buffer + 4, p_key, 8 );
970     
971     if( ioctl( i_fd, USCSICMD, &sc ) < 0 || sc.uscsi_status )
972     {
973         return -1;
974     }
975
976     return 0;
977     
978 #elif defined( WIN32 )
979     if( WIN2K ) /* NT/Win2000/Whistler */
980     {
981         DWORD tmp;
982         u8 buffer[DVD_BUS_KEY_LENGTH];
983         PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
984
985         memset( &buffer, 0, sizeof( buffer ) );
986
987         key->KeyLength  = DVD_BUS_KEY_LENGTH;
988         key->SessionId  = *pi_agid;
989         key->KeyType    = DvdBusKey2;
990         key->KeyFlags   = 0;
991
992         memcpy( key->KeyData, p_key, 8 );
993
994         return DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_SEND_KEY, key, 
995                 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
996     }
997     else
998     {
999         INIT_SSC( GPCMD_SEND_KEY, 12 );
1000
1001         ssc.CDBByte[ 10 ] = DVD_SEND_KEY2 | (*pi_agid << 6);
1002
1003         p_buffer[ 1 ] = 0xa;
1004         memcpy( p_buffer + 4, p_key, 8 );
1005
1006         return WinSendSSC( i_fd, &ssc );
1007     }
1008
1009 #elif defined( SYS_DARWIN )
1010     INIT_DVDIOCTL( 12 );
1011
1012     dvdioctl.i_keyformat = kKey2;
1013     dvdioctl.i_agid = *pi_agid;
1014
1015     p_buffer[ 1 ] = 0xa;
1016     memcpy( p_buffer + 4, p_key, 8 );
1017
1018     return ioctl( i_fd, IODVD_SEND_KEY, &dvdioctl );
1019
1020 #else
1021     /* DVD ioctls unavailable - do as if the ioctl failed */
1022     return -1;
1023
1024 #endif
1025 }
1026
1027 /* Local prototypes */
1028
1029 #if defined( SYS_BEOS )
1030 /*****************************************************************************
1031  * BeInitRDC: initialize a RDC structure for the BeOS kernel
1032  *****************************************************************************
1033  * This function initializes a BeOS raw device command structure for future
1034  * use, either a read command or a write command.
1035  *****************************************************************************/
1036 static void BeInitRDC( raw_device_command *p_rdc, int i_type )
1037 {
1038     memset( p_rdc->data, 0, p_rdc->data_length );
1039
1040     switch( i_type )
1041     {
1042         case GPCMD_SEND_KEY:
1043             /* leave the flags to 0 */
1044             break;
1045
1046         case GPCMD_READ_DVD_STRUCTURE:
1047         case GPCMD_REPORT_KEY:
1048             p_rdc->flags = B_RAW_DEVICE_DATA_IN;
1049             break;
1050     }
1051
1052     p_rdc->command[ 0 ]      = i_type;
1053
1054     p_rdc->command[ 8 ]      = (p_rdc->data_length >> 8) & 0xff;
1055     p_rdc->command[ 9 ]      =  p_rdc->data_length       & 0xff;
1056     p_rdc->command_length    = 12;
1057
1058     p_rdc->sense_data        = NULL;
1059     p_rdc->sense_data_length = 0;
1060
1061     p_rdc->timeout           = 1000000;
1062 }
1063 #endif
1064
1065 #if defined( SOLARIS_USCSI )
1066 /*****************************************************************************
1067  * SolarisInitUSCSI: initialize a USCSICMD structure for the Solaris kernel
1068  *****************************************************************************
1069  * This function initializes a Solaris userspace scsi command structure for 
1070  * future use, either a read command or a write command.
1071  *****************************************************************************/
1072 static void SolarisInitUSCSI( struct uscsi_cmd *p_sc, int i_type )
1073 {   
1074     union scsi_cdb *rs_cdb;
1075     memset( p_sc->uscsi_cdb, 0, sizeof( union scsi_cdb ) );
1076     memset( p_sc->uscsi_bufaddr, 0, p_sc->uscsi_buflen );
1077     
1078     switch( i_type )
1079     {
1080         case GPCMD_SEND_KEY:
1081             p_sc->uscsi_flags = USCSI_ISOLATE | USCSI_WRITE;
1082             break;
1083
1084         case GPCMD_READ_DVD_STRUCTURE:
1085         case GPCMD_REPORT_KEY:
1086             p_sc->uscsi_flags = USCSI_ISOLATE | USCSI_READ;
1087             break;
1088     }
1089     
1090     rs_cdb = (union scsi_cdb *)p_sc->uscsi_cdb;
1091     
1092     rs_cdb->scc_cmd = i_type;
1093
1094     rs_cdb->cdb_opaque[ 8 ] = (p_sc->uscsi_buflen >> 8) & 0xff;
1095     rs_cdb->cdb_opaque[ 9 ] =  p_sc->uscsi_buflen       & 0xff;
1096     p_sc->uscsi_cdblen = 12;
1097
1098     USCSI_TIMEOUT( p_sc, 15 );
1099 }
1100 #endif
1101
1102 #if defined( WIN32 )
1103 /*****************************************************************************
1104  * WinInitSSC: initialize a ssc structure for the win32 aspi layer
1105  *****************************************************************************
1106  * This function initializes a ssc raw device command structure for future
1107  * use, either a read command or a write command.
1108  *****************************************************************************/
1109 static void WinInitSSC( struct SRB_ExecSCSICmd *p_ssc, int i_type )
1110 {
1111     memset( p_ssc->SRB_BufPointer, 0, p_ssc->SRB_BufLen );
1112
1113     switch( i_type )
1114     {
1115         case GPCMD_SEND_KEY:
1116             p_ssc->SRB_Flags = SRB_DIR_OUT;
1117             break;
1118
1119         case GPCMD_READ_DVD_STRUCTURE:
1120         case GPCMD_REPORT_KEY:
1121             p_ssc->SRB_Flags = SRB_DIR_IN;
1122             break;
1123     }
1124
1125     p_ssc->SRB_Cmd      = SC_EXEC_SCSI_CMD;
1126     p_ssc->SRB_Flags    |= SRB_EVENT_NOTIFY;
1127
1128     p_ssc->CDBByte[ 0 ] = i_type;
1129
1130     p_ssc->CDBByte[ 8 ] = (u8)(p_ssc->SRB_BufLen >> 8) & 0xff;
1131     p_ssc->CDBByte[ 9 ] = (u8) p_ssc->SRB_BufLen       & 0xff;
1132     p_ssc->SRB_CDBLen   = 12;
1133
1134     p_ssc->SRB_SenseLen = SENSE_LEN;
1135 }
1136
1137 /*****************************************************************************
1138  * WinSendSSC: send a ssc structure to the aspi layer
1139  *****************************************************************************/
1140 static int WinSendSSC( int i_fd, struct SRB_ExecSCSICmd *p_ssc )
1141 {
1142     HANDLE hEvent = NULL;
1143     struct w32_aspidev *fd = (struct w32_aspidev *) i_fd;
1144
1145     hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
1146     if( hEvent == NULL )
1147     {
1148         return -1;
1149     }
1150
1151     p_ssc->SRB_PostProc  = hEvent;
1152     p_ssc->SRB_HaId      = LOBYTE( fd->i_sid );
1153     p_ssc->SRB_Target    = HIBYTE( fd->i_sid );
1154
1155     ResetEvent( hEvent );
1156     if( fd->lpSendCommand( (void*) p_ssc ) == SS_PENDING )
1157         WaitForSingleObject( hEvent, INFINITE );
1158
1159     CloseHandle( hEvent );
1160
1161     return p_ssc->SRB_Status == SS_COMP ? 0 : -1;
1162 }
1163 #endif
1164