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