]> git.sesse.net Git - vlc/blobdiff - plugins/dvd/dvd_ioctl.c
* Win2000 DVD input by Jon Lech Johansen <jon-vl@nanocrew.net>.
[vlc] / plugins / dvd / dvd_ioctl.c
index 1723a2fab387e911e69bdf259a8bfdf1b00bf2f4..d0a480f5258df24e346d8f877ea5295428e24596 100644 (file)
@@ -2,10 +2,11 @@
  * 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