* dvd_ioctl.c: DVD ioctl replacement function
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
- * $Id: dvd_ioctl.c,v 1.1 2001/02/20 07:49:12 sam Exp $
+ * $Id: dvd_ioctl.c,v 1.16 2001/05/31 03:12:49 sam Exp $
*
* Authors: Markus Kuespert <ltlBeBoy@beosmail.com>
* Samuel Hocevar <sam@zoy.org>
+ * Jon Lech Johansen <jon-vl@nanocrew.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
*****************************************************************************/
#include "defs.h"
-#include <netinet/in.h>
-#ifdef HAVE_SYS_IOCTL_H
+#include <string.h> /* memcpy(), memset() */
+#include <sys/types.h>
+
+#if defined( WIN32 )
+# include <windows.h>
+# include <winioctl.h>
+#else
+# include <netinet/in.h>
# include <sys/ioctl.h>
#endif
-#ifdef HAVE_SYS_DVDIO_H
+
+#ifdef DVD_STRUCT_IN_SYS_CDIO_H
+# include <sys/cdio.h>
+#endif
+#ifdef DVD_STRUCT_IN_SYS_DVDIO_H
# include <sys/dvdio.h>
#endif
-#ifdef LINUX_DVD
+#ifdef DVD_STRUCT_IN_LINUX_CDROM_H
# include <linux/cdrom.h>
#endif
#ifdef SYS_BEOS
#endif
#include "common.h"
+
#include "intf_msg.h"
+#ifdef SYS_DARWIN1_3
+# include "DVDioctl/DVDioctl.h"
+#endif
+
+#include "dvd_css.h"
#include "dvd_ioctl.h"
/*****************************************************************************
- * Local prototypes
+ * Local prototypes, BeOS specific
*****************************************************************************/
#if defined( SYS_BEOS )
-static int dvd_do_auth ( int i_fd, dvd_authinfo *p_authinfo );
-static int dvd_read_struct ( int i_fd, dvd_struct *p_dvd );
-static int dvd_read_physical ( int i_fd, dvd_struct *p_dvd );
-static int dvd_read_copyright ( int i_fd, dvd_struct *p_dvd );
-static int dvd_read_disckey ( int i_fd, dvd_struct *p_dvd );
-static int dvd_read_bca ( int i_fd, dvd_struct *p_dvd );
-static int dvd_read_manufact ( int i_fd, dvd_struct *p_dvd );
-static int communicate_with_dvd ( int i_fd,
- struct cdrom_generic_command *p_cgc );
-static void init_cdrom_command ( struct cdrom_generic_command *p_cgc,
- void *buf, int i_len, int i_type );
-static void setup_report_key ( struct cdrom_generic_command *p_cgc,
- unsigned i_agid, unsigned i_type );
-static void setup_send_key ( struct cdrom_generic_command *p_cgc,
- unsigned i_agid, unsigned i_type );
+static void BeInitRDC ( raw_device_command *, int );
#endif
/*****************************************************************************
- * dvd_ioctl: DVD ioctl() wrapper
- *****************************************************************************
- * Since the DVD ioctls do not exist on every machine, we provide this wrapper
- * so that it becomes easier to port them to any architecture.
+ * ioctl_ReadCopyright: check whether the disc is encrypted or not
*****************************************************************************/
-int dvd_ioctl( int i_fd, unsigned long i_op, void *p_arg )
+int ioctl_ReadCopyright( int i_fd, int i_layer, int *pi_copyright )
{
-#if defined( HAVE_SYS_DVDIO_H ) || defined( LINUX_DVD )
- return( ioctl( i_fd, i_op, p_arg ) );
+ int i_ret;
+
+#if defined( DVD_STRUCT_IN_LINUX_CDROM_H )
+ dvd_struct dvd;
+
+ dvd.type = DVD_STRUCT_COPYRIGHT;
+ dvd.copyright.layer_num = i_layer;
+
+ i_ret = ioctl( i_fd, DVD_READ_STRUCT, &dvd );
+
+ *pi_copyright = dvd.copyright.cpst;
+
+#elif defined( HAVE_BSD_DVD_STRUCT )
+ struct dvd_struct dvd;
+
+ dvd.format = DVD_STRUCT_COPYRIGHT;
+ dvd.layer_num = i_layer;
+
+ i_ret = ioctl( i_fd, DVDIOCREADSTRUCTURE, &dvd );
+
+ *pi_copyright = dvd.cpst;
#elif defined( SYS_BEOS )
- switch ( i_op )
- {
- case DVD_AUTH:
- return dvd_do_auth( i_fd, (dvd_authinfo *)p_arg );
+ INIT_RDC( GPCMD_READ_DVD_STRUCTURE, 8 );
- case DVD_READ_STRUCT:
- return dvd_read_struct( i_fd, (dvd_struct *)p_arg );
+ rdc.command[ 6 ] = i_layer;
+ rdc.command[ 7 ] = DVD_STRUCT_COPYRIGHT;
- default:
- intf_ErrMsg( "css error: unknown command 0x%x", i_op );
- return -1;
+ i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
+
+ *pi_copyright = p_buffer[ 4 ];
+
+#elif defined( SYS_DARWIN1_3 )
+ intf_ErrMsg( "css error: DVD ioctls not fully functional yet" );
+ intf_ErrMsg( "css error: assuming disc is encrypted" );
+
+ *pi_copyright = 1;
+
+ i_ret = 0;
+
+#elif defined( WIN32 )
+ if( GetVersion() < 0x80000000 ) /* NT/Win2000/Whistler */
+ {
+ DWORD tmp;
+ u8 p_buffer[ 8 ];
+ SCSI_PASS_THROUGH_DIRECT sptd;
+
+ memset( &sptd, 0, sizeof( sptd ) );
+ memset( &p_buffer, 0, sizeof( p_buffer ) );
+
+ /* When using IOCTL_DVD_READ_STRUCTURE and
+ DVD_COPYRIGHT_DESCRIPTOR, CopyrightProtectionType
+ is always 6. So we send a raw scsi command instead. */
+
+ sptd.Length = sizeof( SCSI_PASS_THROUGH_DIRECT );
+ sptd.CdbLength = 12;
+ sptd.DataIn = SCSI_IOCTL_DATA_IN;
+ sptd.DataTransferLength = 8;
+ sptd.TimeOutValue = 2;
+ sptd.DataBuffer = p_buffer;
+ sptd.Cdb[ 0 ] = GPCMD_READ_DVD_STRUCTURE;
+ sptd.Cdb[ 6 ] = i_layer;
+ sptd.Cdb[ 7 ] = DVD_STRUCT_COPYRIGHT;
+ sptd.Cdb[ 8 ] = (8 >> 8) & 0xff;
+ sptd.Cdb[ 9 ] = 8 & 0xff;
+
+ i_ret = DeviceIoControl( (HANDLE) i_fd,
+ IOCTL_SCSI_PASS_THROUGH_DIRECT,
+ &sptd, sizeof( SCSI_PASS_THROUGH_DIRECT ),
+ &sptd, sizeof( SCSI_PASS_THROUGH_DIRECT ),
+ &tmp, NULL ) ? 0 : -1;
+
+ *pi_copyright = p_buffer[4];
+ }
+ else
+ {
+ /* TODO: add WNASPI support for Win9x */
+ intf_ErrMsg( "css error: DVD ioctls not functional yet" );
+ intf_ErrMsg( "css error: assuming disc is unencrypted" );
+ *pi_copyright = 0;
+ i_ret = 0;
}
+
#else
+ /* DVD ioctls unavailable - do as if the ioctl failed */
+ i_ret = -1;
- return -1;
#endif
+ return i_ret;
}
-#if defined( SYS_BEOS )
-
/*****************************************************************************
- * setup_report_key
+ * ioctl_ReadKey: get the disc key
*****************************************************************************/
-static void setup_report_key( struct cdrom_generic_command *p_cgc,
- unsigned i_agid, unsigned i_type )
+int ioctl_ReadKey( int i_fd, int *pi_agid, u8 *p_key )
{
- p_cgc->cmd[0] = GPCMD_REPORT_KEY;
- p_cgc->cmd[10] = i_type | (i_agid << 6);
+ int i_ret;
- switch( i_type )
- {
- case 0:
- case 8:
- case 5:
- p_cgc->buflen = 8;
- break;
+#if defined( DVD_STRUCT_IN_LINUX_CDROM_H )
+ dvd_struct dvd;
- case 1:
- p_cgc->buflen = 16;
- break;
+ dvd.type = DVD_STRUCT_DISCKEY;
+ dvd.disckey.agid = *pi_agid;
+ memset( dvd.disckey.value, 0, 2048 );
- case 2:
- case 4:
- p_cgc->buflen = 12;
- break;
+ i_ret = ioctl( i_fd, DVD_READ_STRUCT, &dvd );
+
+ if( i_ret < 0 )
+ {
+ return i_ret;
}
- p_cgc->cmd[9] = p_cgc->buflen;
- p_cgc->data_direction = CGC_DATA_READ;
-}
+ memcpy( p_key, dvd.disckey.value, 2048 );
-/*****************************************************************************
- * setup_send_key
- *****************************************************************************/
-static void setup_send_key( struct cdrom_generic_command *p_cgc,
- unsigned i_agid, unsigned i_type )
-{
- p_cgc->cmd[0] = GPCMD_SEND_KEY;
- p_cgc->cmd[10] = i_type | (i_agid << 6);
+#elif defined( HAVE_BSD_DVD_STRUCT )
+ struct dvd_struct dvd;
- switch( i_type )
+ dvd.format = DVD_STRUCT_DISCKEY;
+ dvd.agid = *pi_agid;
+ memset( dvd.data, 0, 2048 );
+
+ i_ret = ioctl( i_fd, DVDIOCREADSTRUCTURE, &dvd );
+
+ if( i_ret < 0 )
{
- case 1:
- p_cgc->buflen = 16;
- break;
+ return i_ret;
+ }
- case 3:
- p_cgc->buflen = 12;
- break;
+ memcpy( p_key, dvd.data, 2048 );
- case 6:
- p_cgc->buflen = 8;
- break;
+#elif defined( SYS_BEOS )
+ INIT_RDC( GPCMD_READ_DVD_STRUCTURE, 2048 + 4 );
+
+ rdc.command[ 7 ] = DVD_STRUCT_DISCKEY;
+ rdc.command[ 10 ] = *pi_agid << 6;
+
+ i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
+
+ if( i_ret < 0 )
+ {
+ return i_ret;
}
- p_cgc->cmd[9] = p_cgc->buflen;
- p_cgc->data_direction = CGC_DATA_WRITE;
-}
+ memcpy( p_key, p_buffer + 4, 2048 );
-/*****************************************************************************
- * init_cdrom_command
- *****************************************************************************/
-static void init_cdrom_command( struct cdrom_generic_command *p_cgc,
- void *buf, int i_len, int i_type )
-{
- memset( p_cgc, 0, sizeof(struct cdrom_generic_command) );
+#elif defined( SYS_DARWIN1_3 )
+ intf_ErrMsg( "css error: DVD ioctls not fully functional yet" );
+ intf_ErrMsg( "css error: sending an empty key" );
+
+ i_ret = 0;
- if (buf)
+ memset( p_key, 0x00, 2048 );
+
+#elif defined( WIN32 )
+ if( GetVersion() < 0x80000000 ) /* NT/Win2000/Whistler */
+ {
+ DWORD tmp;
+ u8 buffer[DVD_DISK_KEY_LENGTH];
+ PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
+
+ memset( &buffer, 0, sizeof( buffer ) );
+
+ key->KeyLength = DVD_DISK_KEY_LENGTH;
+ key->SessionId = *pi_agid;
+ key->KeyType = DvdDiskKey;
+ key->KeyFlags = 0;
+
+ i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key,
+ key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
+
+ if( i_ret < 0 )
+ {
+ return i_ret;
+ }
+
+ memcpy( p_key, key->KeyData, 2048 );
+ }
+ else
{
- memset( buf, 0, i_len );
+ i_ret = -1;
}
- p_cgc->buffer = (char *) buf;
- p_cgc->buflen = i_len;
- p_cgc->data_direction = i_type;
- p_cgc->timeout = 255;
-}
+#else
+ /* DVD ioctls unavailable - do as if the ioctl failed */
+ i_ret = -1;
-/* DVD handling */
+#endif
+ return i_ret;
+}
/*****************************************************************************
- * dvd_do_auth
+ * ioctl_ReportAgid: get AGID from the drive
*****************************************************************************/
-static int dvd_do_auth( int i_fd, dvd_authinfo *p_authinfo )
+int ioctl_ReportAgid( int i_fd, int *pi_agid )
{
int i_ret;
- unsigned char buf[20];
- struct cdrom_generic_command p_cgc;
-#define copy_key(dest,src) memcpy((dest), (src), sizeof(dvd_key))
-#define copy_chal(dest,src) memcpy((dest), (src), sizeof(dvd_challenge))
+#if defined( DVD_STRUCT_IN_LINUX_CDROM_H )
+ dvd_authinfo auth_info;
-#if 0
- struct rpc_state_t rpc_state;
-#endif
+ auth_info.type = DVD_LU_SEND_AGID;
+ auth_info.lsa.agid = *pi_agid;
- memset( buf, 0, sizeof(buf) );
- init_cdrom_command( &p_cgc, buf, 0, CGC_DATA_READ );
+ i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
- switch (p_authinfo->type)
- {
- /* LU data send */
- case DVD_LU_SEND_AGID:
+ *pi_agid = auth_info.lsa.agid;
- intf_WarnMsg( 2, "css dvd_do_auth: DVD_LU_SEND_AGID" );
+#elif defined( HAVE_BSD_DVD_STRUCT )
+ struct dvd_authinfo auth_info;
- setup_report_key(&p_cgc, p_authinfo->lsa.agid, 0);
+ auth_info.format = DVD_REPORT_AGID;
+ auth_info.agid = *pi_agid;
- /* handle uniform packets for scsi type devices (scsi,atapi) */
- if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
- {
- return i_ret;
- }
+ i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
- p_authinfo->lsa.agid = buf[7] >> 6;
- /* Returning data, let host change state */
+ *pi_agid = auth_info.agid;
- break;
+#elif defined( SYS_BEOS )
+ INIT_RDC( GPCMD_REPORT_KEY, 8 );
- case DVD_LU_SEND_KEY1:
+ rdc.command[ 10 ] = DVD_REPORT_AGID | (*pi_agid << 6);
- intf_WarnMsg( 2, "css dvd_do_auth: DVD_LU_SEND_KEY1" );
+ i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
- setup_report_key(&p_cgc, p_authinfo->lsk.agid, 2);
+ *pi_agid = p_buffer[ 7 ] >> 6;
- /* handle uniform packets for scsi type devices (scsi,atapi) */
- if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
- {
- return i_ret;
- }
+#elif defined( SYS_DARWIN1_3 )
+ INIT_DVDIOCTL( 8 );
- copy_key(p_authinfo->lsk.key, &buf[4]);
- /* Returning data, let host change state */
+ dvdioctl.i_keyformat = kCSSAGID;
+ dvdioctl.i_agid = *pi_agid;
+ dvdioctl.i_lba = 0;
- break;
+ i_ret = ioctl( i_fd, IODVD_REPORT_KEY, &dvdioctl );
- case DVD_LU_SEND_CHALLENGE:
+ *pi_agid = p_buffer[ 7 ] >> 6;
- intf_WarnMsg( 2, "css dvd_do_auth: DVD_LU_SEND_CHALLENGE" );
+#elif defined( WIN32 )
+ if( GetVersion() < 0x80000000 ) /* NT/Win2000/Whistler */
+ {
+ ULONG id;
+ DWORD tmp;
+
+ i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_START_SESSION,
+ &tmp, 4, &id, sizeof( id ), &tmp, NULL ) ? 0 : -1;
- setup_report_key(&p_cgc, p_authinfo->lsc.agid, 1);
+ *pi_agid = id;
+ }
+ else
+ {
+ i_ret = -1;
+ }
- /* handle uniform packets for scsi type devices (scsi,atapi) */
- if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
- {
- return i_ret;
- }
+#else
+ /* DVD ioctls unavailable - do as if the ioctl failed */
+ i_ret = -1;
- copy_chal(p_authinfo->lsc.chal, &buf[4]);
- /* Returning data, let host change state */
+#endif
+ return i_ret;
+}
- break;
+/*****************************************************************************
+ * ioctl_ReportChallenge: get challenge from the drive
+ *****************************************************************************/
+int ioctl_ReportChallenge( int i_fd, int *pi_agid, u8 *p_challenge )
+{
+ int i_ret;
- /* Post-auth key */
- case DVD_LU_SEND_TITLE_KEY:
+#if defined( DVD_STRUCT_IN_LINUX_CDROM_H )
+ dvd_authinfo auth_info;
- intf_WarnMsg( 2, "css dvd_do_auth: DVD_LU_SEND_TITLE_KEY" );
+ auth_info.type = DVD_LU_SEND_CHALLENGE;
+ auth_info.lsc.agid = *pi_agid;
- setup_report_key(&p_cgc, p_authinfo->lstk.agid, 4);
- p_cgc.cmd[5] = p_authinfo->lstk.lba;
- p_cgc.cmd[4] = p_authinfo->lstk.lba >> 8;
- p_cgc.cmd[3] = p_authinfo->lstk.lba >> 16;
- p_cgc.cmd[2] = p_authinfo->lstk.lba >> 24;
+ i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
- /* handle uniform packets for scsi type devices (scsi,atapi) */
- if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
- {
- return i_ret;
- }
+ memcpy( p_challenge, auth_info.lsc.chal, sizeof(dvd_challenge) );
- p_authinfo->lstk.cpm = (buf[4] >> 7) & 1;
- p_authinfo->lstk.cp_sec = (buf[4] >> 6) & 1;
- p_authinfo->lstk.cgms = (buf[4] >> 4) & 3;
- copy_key(p_authinfo->lstk.title_key, &buf[5]);
- /* Returning data, let host change state */
+#elif defined( HAVE_BSD_DVD_STRUCT )
+ struct dvd_authinfo auth_info;
- break;
+ auth_info.format = DVD_REPORT_CHALLENGE;
+ auth_info.agid = *pi_agid;
- case DVD_LU_SEND_ASF:
+ i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
- intf_WarnMsg( 2, "css dvd_do_auth: DVD_LU_SEND_ASF" );
+ memcpy( p_challenge, auth_info.keychal, 10 );
- setup_report_key(&p_cgc, p_authinfo->lsasf.agid, 5);
+#elif defined( SYS_BEOS )
+ INIT_RDC( GPCMD_REPORT_KEY, 16 );
- /* handle uniform packets for scsi type devices (scsi,atapi) */
- if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
- {
- return i_ret;
- }
+ rdc.command[ 10 ] = DVD_REPORT_CHALLENGE | (*pi_agid << 6);
- p_authinfo->lsasf.asf = buf[7] & 1;
+ i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
- break;
+ memcpy( p_challenge, p_buffer + 4, 12 );
- /* LU data receive (LU changes state) */
- case DVD_HOST_SEND_CHALLENGE:
+#elif defined( SYS_DARWIN1_3 )
+ INIT_DVDIOCTL( 16 );
- intf_WarnMsg( 2, "css dvd_do_auth: DVD_LU_SEND_CHALLENGE" );
+ dvdioctl.i_keyformat = kChallengeKey;
+ dvdioctl.i_agid = *pi_agid;
+ dvdioctl.i_lba = 0;
- setup_send_key(&p_cgc, p_authinfo->hsc.agid, 1);
- buf[1] = 0xe;
- copy_chal(&buf[4], p_authinfo->hsc.chal);
+ i_ret = ioctl( i_fd, IODVD_REPORT_KEY, &dvdioctl );
- /* handle uniform packets for scsi type devices (scsi,atapi) */
- if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
- {
- return i_ret;
- }
+ memcpy( p_challenge, p_buffer + 4, 12 );
- p_authinfo->type = DVD_LU_SEND_KEY1;
+#elif defined( WIN32 )
+ if( GetVersion() < 0x80000000 ) /* NT/Win2000/Whistler */
+ {
+ DWORD tmp;
+ u8 buffer[DVD_CHALLENGE_KEY_LENGTH];
+ PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
- break;
+ memset( &buffer, 0, sizeof( buffer ) );
- case DVD_HOST_SEND_KEY2:
+ key->KeyLength = DVD_CHALLENGE_KEY_LENGTH;
+ key->SessionId = *pi_agid;
+ key->KeyType = DvdChallengeKey;
+ key->KeyFlags = 0;
- intf_WarnMsg( 2, "css dvd_do_auth: DVD_LU_SEND_KEY2" );
+ i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key,
+ key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
- setup_send_key(&p_cgc, p_authinfo->hsk.agid, 3);
- buf[1] = 0xa;
- copy_key(&buf[4], p_authinfo->hsk.key);
+ if( i_ret < 0 )
+ {
+ return i_ret;
+ }
- /* handle uniform packets for scsi type devices (scsi,atapi) */
- if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
- {
- p_authinfo->type = DVD_AUTH_FAILURE;
- return i_ret;
- }
- p_authinfo->type = DVD_AUTH_ESTABLISHED;
+ memcpy( p_challenge, key->KeyData, 10 );
+ }
+ else
+ {
+ i_ret = -1;
+ }
- break;
+#else
+ /* DVD ioctls unavailable - do as if the ioctl failed */
+ i_ret = -1;
- /* Misc */
- case DVD_INVALIDATE_AGID:
+#endif
+ return i_ret;
+}
- intf_WarnMsg( 2, "css dvd_do_auth: DVD_INVALIDATE_AGID" );
+/*****************************************************************************
+ * ioctl_ReportASF: get ASF from the drive
+ *****************************************************************************/
+int ioctl_ReportASF( int i_fd, int *pi_agid, int *pi_asf )
+{
+ int i_ret;
- setup_report_key(&p_cgc, p_authinfo->lsa.agid, 0x3f);
+#if defined( DVD_STRUCT_IN_LINUX_CDROM_H )
+ dvd_authinfo auth_info;
- /* handle uniform packets for scsi type devices (scsi,atapi) */
- if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
- {
- return i_ret;
- }
+ auth_info.type = DVD_LU_SEND_ASF;
+ auth_info.lsasf.agid = *pi_agid;
+ auth_info.lsasf.asf = *pi_asf;
- break;
+ i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
- /* Get region settings */
- case DVD_LU_SEND_RPC_STATE:
+ *pi_asf = auth_info.lsasf.asf;
- intf_WarnMsg( 2, "css dvd_do_auth: DVD_LU_SEND_RPC_STATE "
- "(unimplemented)" );
+#elif defined( HAVE_BSD_DVD_STRUCT )
+ struct dvd_authinfo auth_info;
-#if 0
- p_dvdetup_report_key(&p_cgc, 0, 8);
- memset(&rpc_state, 0, sizeof(rpc_state_t));
- p_cgc.buffer = (char *) &rpc_state;
+ auth_info.format = DVD_REPORT_ASF;
+ auth_info.agid = *pi_agid;
+ auth_info.asf = *pi_asf;
- /* handle uniform packets for scsi type devices (scsi,atapi) */
- if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
- {
- return i_ret;
- }
+ i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
- p_authinfo->lrpcs.type = rpc_state.type_code;
- p_authinfo->lrpcs.vra = rpc_state.vra;
- p_authinfo->lrpcs.ucca = rpc_state.ucca;
- p_authinfo->lrpcs.region_mask = rpc_state.region_mask;
- p_authinfo->lrpcs.rpc_scheme = rpc_state.rpc_scheme;
-#endif
+ *pi_asf = auth_info.asf;
- break;
+#elif defined( SYS_BEOS )
+ INIT_RDC( GPCMD_REPORT_KEY, 8 );
- /* Set region settings */
- case DVD_HOST_SEND_RPC_STATE:
+ rdc.command[ 10 ] = DVD_REPORT_ASF | (*pi_agid << 6);
- intf_WarnMsg( 2, "css dvd_do_auth: DVD_HOST_SEND_RPC_STATE" );
+ i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
- setup_send_key(&p_cgc, 0, 6);
- buf[1] = 6;
- buf[4] = p_authinfo->hrpcs.pdrc;
+ *pi_asf = p_buffer[ 7 ] & 1;
- /* handle uniform packets for scsi type devices (scsi,atapi) */
- if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
- {
- return i_ret;
- }
+#elif defined( SYS_DARWIN1_3 )
+ INIT_DVDIOCTL( 8 );
- break;
+ dvdioctl.i_keyformat = kASF;
+ dvdioctl.i_agid = *pi_agid;
+ dvdioctl.i_lba = 0;
+
+ i_ret = ioctl( i_fd, IODVD_REPORT_KEY, &dvdioctl );
+
+ *pi_asf = p_buffer[ 7 ] & 1;
+
+#elif defined( WIN32 )
+ if( GetVersion() < 0x80000000 ) /* NT/Win2000/Whistler */
+ {
+ DWORD tmp;
+ u8 buffer[DVD_ASF_LENGTH];
+ PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
- default:
- intf_ErrMsg( "css dvd_do_auth: invalid DVD key ioctl" );
- return -1;
+ memset( &buffer, 0, sizeof( buffer ) );
+ key->KeyLength = DVD_ASF_LENGTH;
+ key->SessionId = *pi_agid;
+ key->KeyType = DvdAsf;
+ key->KeyFlags = 0;
+
+ ((PDVD_ASF)key->KeyData)->SuccessFlag = *pi_asf;
+
+ i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key,
+ key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
+
+ if( i_ret < 0 )
+ {
+ return i_ret;
+ }
+
+ *pi_asf = ((PDVD_ASF)key->KeyData)->SuccessFlag;
+ }
+ else
+ {
+ i_ret = -1;
}
- return 0;
+#else
+ /* DVD ioctls unavailable - do as if the ioctl failed */
+ i_ret = -1;
+
+#endif
+ return i_ret;
}
/*****************************************************************************
- * dvd_read_struct
+ * ioctl_ReportKey1: get the first key from the drive
*****************************************************************************/
-static int dvd_read_struct( int i_fd, dvd_struct *p_dvd )
+int ioctl_ReportKey1( int i_fd, int *pi_agid, u8 *p_key )
{
- switch (p_dvd->type)
- {
- case DVD_STRUCT_PHYSICAL:
+ int i_ret;
- intf_WarnMsg( 2, "css dvd_read_struct: DVD_STRUCT_PHYSICAL" );
- return dvd_read_physical(i_fd, p_dvd);
+#if defined( DVD_STRUCT_IN_LINUX_CDROM_H )
+ dvd_authinfo auth_info;
- case DVD_STRUCT_COPYRIGHT:
+ auth_info.type = DVD_LU_SEND_KEY1;
+ auth_info.lsk.agid = *pi_agid;
- intf_WarnMsg( 2, "css dvd_read_struct: DVD_STRUCT_COPYRIGHT" );
- return dvd_read_copyright(i_fd, p_dvd);
+ i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
- case DVD_STRUCT_DISCKEY:
+ memcpy( p_key, auth_info.lsk.key, sizeof(dvd_key) );
- intf_WarnMsg( 2, "css dvd_read_struct: DVD_STRUCT_DISCKEY" );
- return dvd_read_disckey(i_fd, p_dvd);
+#elif defined( HAVE_BSD_DVD_STRUCT )
+ struct dvd_authinfo auth_info;
- case DVD_STRUCT_BCA:
+ auth_info.format = DVD_REPORT_KEY1;
+ auth_info.agid = *pi_agid;
- intf_WarnMsg( 2, "css dvd_read_struct: DVD_STRUCT_BCA" );
- return dvd_read_bca(i_fd, p_dvd);
+ i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
- case DVD_STRUCT_MANUFACT:
+ memcpy( p_key, auth_info.keychal, 8 );
- intf_WarnMsg( 2, "css dvd_read_struct: DVD_STRUCT_MANUFACT" );
- return dvd_read_manufact(i_fd, p_dvd);
+#elif defined( SYS_BEOS )
+ INIT_RDC( GPCMD_REPORT_KEY, 12 );
- default:
- intf_WarnMsg( 2, "css dvd_read_struct: invalid request (%d)",
- p_dvd->type );
- return -1;
- }
-}
+ rdc.command[ 10 ] = DVD_REPORT_KEY1 | (*pi_agid << 6);
-/*****************************************************************************
- * dvd_read_physical
- *****************************************************************************/
-static int dvd_read_physical( int i_fd, dvd_struct *p_dvd )
-{
- int i_ret, i;
- u_char buf[4 + 4 * 20], *base;
- struct dvd_layer *layer;
- struct cdrom_generic_command cgc;
+ i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
- init_cdrom_command( &cgc, buf, sizeof(buf), CGC_DATA_READ );
+ memcpy( p_key, p_buffer + 4, 8 );
- cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
- cgc.cmd[6] = p_dvd->physical.layer_num;
- cgc.cmd[7] = p_dvd->type;
- cgc.cmd[9] = cgc.buflen & 0xff;
+#elif defined( SYS_DARWIN1_3 )
+ INIT_DVDIOCTL( 12 );
- /* handle uniform packets for scsi type devices (scsi,atapi) */
- if ((i_ret = communicate_with_dvd(i_fd, &cgc)))
+ dvdioctl.i_keyformat = kKey1;
+ dvdioctl.i_agid = *pi_agid;
+
+ i_ret = ioctl( i_fd, IODVD_SEND_KEY, &dvdioctl );
+
+ memcpy( p_key, p_buffer + 4, 8 );
+
+#elif defined( WIN32 )
+ if( GetVersion() < 0x80000000 ) /* NT/Win2000/Whistler */
{
- return i_ret;
- }
+ DWORD tmp;
+ u8 buffer[DVD_BUS_KEY_LENGTH];
+ PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
+
+ memset( &buffer, 0, sizeof( buffer ) );
- base = &buf[4];
- layer = &p_dvd->physical.layer[0];
+ key->KeyLength = DVD_BUS_KEY_LENGTH;
+ key->SessionId = *pi_agid;
+ key->KeyType = DvdBusKey1;
+ key->KeyFlags = 0;
- /* place the data... really ugly, but at least we won't have to
- * worry about endianess in userspace or here. */
- for( i = 0; i < 4; ++i, base += 20, ++layer )
+ i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key,
+ key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
+
+ memcpy( p_key, key->KeyData, 8 );
+ }
+ else
{
- memset( layer, 0, sizeof(*layer) );
-
- layer->book_version = base[0] & 0xf;
- layer->book_type = base[0] >> 4;
- layer->min_rate = base[1] & 0xf;
- layer->disc_size = base[1] >> 4;
- layer->layer_type = base[2] & 0xf;
- layer->track_path = (base[2] >> 4) & 1;
- layer->nlayers = (base[2] >> 5) & 3;
- layer->track_density = base[3] & 0xf;
- layer->linear_density = base[3] >> 4;
- layer->start_sector = base[5] << 16 | base[6] << 8 | base[7];
- layer->end_sector = base[9] << 16 | base[10] << 8 | base[11];
- layer->end_sector_l0 = base[13] << 16 | base[14] << 8 | base[15];
- layer->bca = base[16] >> 7;
+ i_ret = -1;
}
- return 0;
+#else
+ /* DVD ioctls unavailable - do as if the ioctl failed */
+ i_ret = -1;
+
+#endif
+ return i_ret;
}
/*****************************************************************************
- * dvd_read_copyright
+ * ioctl_InvalidateAgid: invalidate the current AGID
*****************************************************************************/
-static int dvd_read_copyright( int i_fd, dvd_struct *p_dvd )
+int ioctl_InvalidateAgid( int i_fd, int *pi_agid )
{
int i_ret;
- u_char buf[8];
- struct cdrom_generic_command cgc;
- init_cdrom_command( &cgc, buf, sizeof(buf), CGC_DATA_READ );
+#if defined( DVD_STRUCT_IN_LINUX_CDROM_H )
+ dvd_authinfo auth_info;
- cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
- cgc.cmd[6] = p_dvd->copyright.layer_num;
- cgc.cmd[7] = p_dvd->type;
- cgc.cmd[8] = cgc.buflen >> 8;
- cgc.cmd[9] = cgc.buflen & 0xff;
+ auth_info.type = DVD_INVALIDATE_AGID;
+ auth_info.lsa.agid = *pi_agid;
- /* handle uniform packets for scsi type devices (scsi,atapi) */
- if( (i_ret = communicate_with_dvd(i_fd, &cgc)) )
- {
- return i_ret;
- }
+ i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
- p_dvd->copyright.cpst = buf[4];
- p_dvd->copyright.rmi = buf[5];
+ *pi_agid = auth_info.lsa.agid;
- return 0;
-}
+#elif defined( HAVE_BSD_DVD_STRUCT )
+ struct dvd_authinfo auth_info;
-/*****************************************************************************
- * dvd_read_disckey
- *****************************************************************************/
-static int dvd_read_disckey( int i_fd, dvd_struct *p_dvd )
-{
- int i_ret, size;
- u_char *buf;
- struct cdrom_generic_command cgc;
+ auth_info.format = DVD_INVALIDATE_AGID;
+ auth_info.agid = *pi_agid;
- size = sizeof( p_dvd->disckey.value ) + 4;
+ i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
-#if 0
- if ((buf = (u_char *) kmalloc(size, GFP_KERNEL)) == NULL)
- {
- return -ENOMEM;
- }
-#endif
- buf = (u_char *) malloc(size);
+ *pi_agid = auth_info.agid;
+
+#elif defined( SYS_BEOS )
+ INIT_RDC( GPCMD_REPORT_KEY, 0 );
+
+ rdc.command[ 10 ] = DVD_INVALIDATE_AGID | (*pi_agid << 6);
+
+ i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
- init_cdrom_command(&cgc, buf, size, CGC_DATA_READ);
- cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
- cgc.cmd[7] = p_dvd->type;
- cgc.cmd[8] = size >> 8;
- cgc.cmd[9] = size & 0xff;
- cgc.cmd[10] = p_dvd->disckey.agid << 6;
+#elif defined( SYS_DARWIN1_3 )
+ INIT_DVDIOCTL( 0 );
- /* handle uniform packets for scsi type devices (scsi,atapi) */
- if( !(i_ret = communicate_with_dvd(i_fd, &cgc)) )
+ dvdioctl.i_keyformat = kInvalidateAGID;
+ dvdioctl.i_agid = *pi_agid;
+
+ i_ret = ioctl( i_fd, IODVD_SEND_KEY, &dvdioctl );
+
+#elif defined( WIN32 )
+ if( GetVersion() < 0x80000000 ) /* NT/Win2000/Whistler */
+ {
+ DWORD tmp;
+
+ i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_END_SESSION,
+ pi_agid, sizeof( *pi_agid ), NULL, 0, &tmp, NULL ) ? 0 : -1;
+ }
+ else
{
- memcpy( p_dvd->disckey.value, &buf[4], sizeof(p_dvd->disckey.value) );
+ i_ret = -1;
}
- free( buf );
+#else
+ /* DVD ioctls unavailable - do as if the ioctl failed */
+ i_ret = -1;
+
+#endif
return i_ret;
}
/*****************************************************************************
- * dvd_read_bca
+ * ioctl_SendChallenge: send challenge to the drive
*****************************************************************************/
-static int dvd_read_bca( int i_fd, dvd_struct *p_dvd )
+int ioctl_SendChallenge( int i_fd, int *pi_agid, u8 *p_challenge )
{
- int i_ret;
- u_char buf[4 + 188];
- struct cdrom_generic_command cgc;
+#if defined( DVD_STRUCT_IN_LINUX_CDROM_H )
+ dvd_authinfo auth_info;
+
+ auth_info.type = DVD_HOST_SEND_CHALLENGE;
+ auth_info.hsc.agid = *pi_agid;
+
+ memcpy( auth_info.hsc.chal, p_challenge, sizeof(dvd_challenge) );
+
+ return ioctl( i_fd, DVD_AUTH, &auth_info );
+
+#elif defined( HAVE_BSD_DVD_STRUCT )
+ struct dvd_authinfo auth_info;
+
+ auth_info.format = DVD_SEND_CHALLENGE;
+ auth_info.agid = *pi_agid;
- init_cdrom_command( &cgc, buf, sizeof(buf), CGC_DATA_READ );
- cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
- cgc.cmd[7] = p_dvd->type;
- cgc.cmd[9] = cgc.buflen = 0xff;
+ memcpy( auth_info.keychal, p_challenge, 12 );
- /* handle uniform packets for scsi type devices (scsi,atapi) */
- if( (i_ret = communicate_with_dvd(i_fd, &cgc)) )
+ return ioctl( i_fd, DVDIOCSENDKEY, &auth_info );
+
+#elif defined( SYS_BEOS )
+ INIT_RDC( GPCMD_SEND_KEY, 16 );
+
+ rdc.command[ 10 ] = DVD_SEND_CHALLENGE | (*pi_agid << 6);
+
+ p_buffer[ 1 ] = 0xe;
+ memcpy( p_buffer + 4, p_challenge, 12 );
+
+ return ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
+
+#elif defined( SYS_DARWIN1_3 )
+ INIT_DVDIOCTL( 16 );
+
+ dvdioctl.i_keyformat = kChallengeKey;
+ dvdioctl.i_agid = *pi_agid;
+
+ p_buffer[ 1 ] = 0xe;
+ memcpy( p_buffer + 4, p_challenge, 12 );
+
+ return ioctl( i_fd, IODVD_SEND_KEY, &dvdioctl );
+
+#elif defined( WIN32 )
+ if( GetVersion() < 0x80000000 ) /* NT/Win2000/Whistler */
{
- return i_ret;
- }
+ DWORD tmp;
+ u8 buffer[DVD_CHALLENGE_KEY_LENGTH];
+ PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
+
+ memset( &buffer, 0, sizeof( buffer ) );
+
+ key->KeyLength = DVD_CHALLENGE_KEY_LENGTH;
+ key->SessionId = *pi_agid;
+ key->KeyType = DvdChallengeKey;
+ key->KeyFlags = 0;
+
+ memcpy( key->KeyData, p_challenge, 10 );
- p_dvd->bca.len = buf[0] << 8 | buf[1];
- if( p_dvd->bca.len < 12 || p_dvd->bca.len > 188 )
+ return DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_SEND_KEY, key,
+ key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
+ }
+ else
{
- intf_ErrMsg("css error: invalid BCA length (%d)", p_dvd->bca.len );
return -1;
}
- memcpy( p_dvd->bca.value, &buf[4], p_dvd->bca.len );
+#else
+ /* DVD ioctls unavailable - do as if the ioctl failed */
+ return -1;
- return 0;
+#endif
}
/*****************************************************************************
- * dvd_read_manufact
+ * ioctl_SendKey2: send the second key to the drive
*****************************************************************************/
-static int dvd_read_manufact( int i_fd, dvd_struct *p_dvd )
+int ioctl_SendKey2( int i_fd, int *pi_agid, u8 *p_key )
{
- int i_ret = 0, size;
- u_char *buf;
- struct cdrom_generic_command cgc;
+#if defined( DVD_STRUCT_IN_LINUX_CDROM_H )
+ dvd_authinfo auth_info;
- size = sizeof(p_dvd->manufact.value) + 4;
+ auth_info.type = DVD_HOST_SEND_KEY2;
+ auth_info.hsk.agid = *pi_agid;
-#if 0
- if( (buf = (u_char *) kmalloc(size, GFP_KERNEL)) == NULL )
- {
- return -ENOMEM;
- }
-#endif
- buf = (u_char *) malloc(size);
+ memcpy( auth_info.hsk.key, p_key, sizeof(dvd_key) );
- init_cdrom_command( &cgc, buf, size, CGC_DATA_READ );
- cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
- cgc.cmd[7] = p_dvd->type;
- cgc.cmd[8] = size >> 8;
- cgc.cmd[9] = size & 0xff;
+ return ioctl( i_fd, DVD_AUTH, &auth_info );
- /* handle uniform packets for scsi type devices (scsi,atapi) */
- if ((i_ret = communicate_with_dvd(i_fd, &cgc)))
- {
- return i_ret;
- }
+#elif defined( HAVE_BSD_DVD_STRUCT )
+ struct dvd_authinfo auth_info;
+
+ auth_info.format = DVD_SEND_KEY2;
+ auth_info.agid = *pi_agid;
+
+ memcpy( auth_info.keychal, p_key, 8 );
+
+ return ioctl( i_fd, DVDIOCSENDKEY, &auth_info );
+
+#elif defined( SYS_BEOS )
+ INIT_RDC( GPCMD_SEND_KEY, 12 );
- p_dvd->manufact.len = buf[0] << 8 | buf[1];
- if( p_dvd->manufact.len < 0 || p_dvd->manufact.len > 2048 )
+ rdc.command[ 10 ] = DVD_SEND_KEY2 | (*pi_agid << 6);
+
+ p_buffer[ 1 ] = 0xa;
+ memcpy( p_buffer + 4, p_key, 8 );
+
+ return ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
+
+#elif defined( WIN32 )
+ if( GetVersion() < 0x80000000 ) /* NT/Win2000/Whistler */
{
- intf_ErrMsg( "css error: invalid manufacturer info length "
- "(%d)\n", p_dvd->bca.len );
- i_ret = -1;
+ DWORD tmp;
+ u8 buffer[DVD_BUS_KEY_LENGTH];
+ PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
+
+ memset( &buffer, 0, sizeof( buffer ) );
+
+ key->KeyLength = DVD_BUS_KEY_LENGTH;
+ key->SessionId = *pi_agid;
+ key->KeyType = DvdBusKey2;
+ key->KeyFlags = 0;
+
+ memcpy( key->KeyData, p_key, 8 );
+
+ return DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_SEND_KEY, key,
+ key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
}
else
{
- memcpy( p_dvd->manufact.value, &buf[4], p_dvd->manufact.len );
+ return -1;
}
- free( buf );
- return i_ret;
+#elif defined( SYS_DARWIN1_3 )
+ INIT_DVDIOCTL( 12 );
+
+ dvdioctl.i_keyformat = kKey2;
+ dvdioctl.i_agid = *pi_agid;
+
+ p_buffer[ 1 ] = 0xa;
+ memcpy( p_buffer + 4, p_key, 8 );
+
+ return ioctl( i_fd, IODVD_SEND_KEY, &dvdioctl );
+
+#else
+ /* DVD ioctls unavailable - do as if the ioctl failed */
+ return -1;
+
+#endif
}
+/* Local prototypes */
+
+#if defined( SYS_BEOS )
/*****************************************************************************
- * communicate_with_dvd
+ * BeInitRDC: initialize a RDC structure for the BeOS kernel
+ *****************************************************************************
+ * This function initializes a BeOS raw device command structure for future
+ * use, either a read command or a write command.
*****************************************************************************/
-static int communicate_with_dvd( int i_fd,
- struct cdrom_generic_command *p_cgc )
+static void BeInitRDC( raw_device_command *p_rdc, int i_type )
{
- raw_device_command rdc;
- memset( &rdc, 0, sizeof( rdc ) );
+ memset( p_rdc->data, 0, p_rdc->data_length );
- /* fill out our raw device command data */
- rdc.data = p_cgc->buffer;
- rdc.data_length = p_cgc->buflen;
- rdc.sense_data = p_cgc->sense;
- rdc.sense_data_length = 0;
- rdc.timeout = 1000000;
-
- if( p_cgc->data_direction == CGC_DATA_READ )
+ switch( i_type )
{
- intf_WarnMsg( 2, "css: data_direction == CGC_DATA_READ" );
- rdc.flags = B_RAW_DEVICE_DATA_IN;
+ case GPCMD_SEND_KEY:
+ /* leave the flags to 0 */
+ break;
+
+ case GPCMD_READ_DVD_STRUCTURE:
+ case GPCMD_REPORT_KEY:
+ p_rdc->flags = B_RAW_DEVICE_DATA_IN;
+ break;
}
- rdc.command_length = 12;
- rdc.command[0] = p_cgc->cmd[0];
- rdc.command[1] = p_cgc->cmd[1];
- rdc.command[2] = p_cgc->cmd[2];
- rdc.command[3] = p_cgc->cmd[3];
- rdc.command[4] = p_cgc->cmd[4];
- rdc.command[5] = p_cgc->cmd[5];
- rdc.command[6] = p_cgc->cmd[6];
- rdc.command[7] = p_cgc->cmd[7];
- rdc.command[8] = p_cgc->cmd[8];
- rdc.command[9] = p_cgc->cmd[9];
- rdc.command[10] = p_cgc->cmd[10];
- rdc.command[11] = p_cgc->cmd[11];
- rdc.command[12] = p_cgc->cmd[12];
+ p_rdc->command[ 0 ] = i_type;
- return ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
-}
+ p_rdc->command[ 8 ] = (p_rdc->data_length >> 8) & 0xff;
+ p_rdc->command[ 9 ] = p_rdc->data_length & 0xff;
+ p_rdc->command_length = 12;
+
+ p_rdc->sense_data = NULL;
+ p_rdc->sense_data_length = 0;
+ p_rdc->timeout = 1000000;
+}
#endif