]> git.sesse.net Git - vlc/blobdiff - plugins/dvd/dvd_ioctl.c
* BeOS fixes. renamed iovec.h to input_iovec.h because of namespace issues.
[vlc] / plugins / dvd / dvd_ioctl.c
index 158b92ba9e1aa0c2c8a9cbbb7ef32a5f72913f0d..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.9 2001/04/11 04:31:59 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 <string.h>                                    /* memcpy(), memset() */
 #include <sys/types.h>
-#include <netinet/in.h>
 
-#ifdef HAVE_SYS_DVDIO_H
+#if defined( WIN32 )
+#   include <windows.h>
+#   include <winioctl.h>
+#else
+#   include <netinet/in.h>
 #   include <sys/ioctl.h>
+#endif
+
+#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
-#   include <sys/ioctl.h>
+#ifdef DVD_STRUCT_IN_LINUX_CDROM_H
 #   include <linux/cdrom.h>
 #endif
 #ifdef SYS_BEOS
-#   include <sys/ioctl.h>
 #   include <malloc.h>
 #   include <scsi.h>
 #endif
-#ifdef SYS_DARWIN1_3
-#   include <sys/ioctl.h>
-#endif
 
 #include "common.h"
 
 #include "dvd_ioctl.h"
 
 /*****************************************************************************
- * Local prototypes - BeOS specific
+ * Local prototypes, BeOS specific
  *****************************************************************************/
 #if defined( SYS_BEOS )
-static void BeInitRDC ( raw_device_command *, void *, int );
-#define INIT_RDC( TYPE, SIZE ) \
-    raw_device_command rdc; \
-    u8 p_buffer[ (SIZE) ]; \
-    BeInitRDC( &rdc, p_buffer, (SIZE), (TYPE) );
+static void BeInitRDC ( raw_device_command *, int );
 #endif
 
 /*****************************************************************************
@@ -77,7 +78,7 @@ int ioctl_ReadCopyright( int i_fd, int i_layer, int *pi_copyright )
 {
     int i_ret;
 
-#if defined( HAVE_SYS_DVDIO_H ) || defined( LINUX_DVD )
+#if defined( DVD_STRUCT_IN_LINUX_CDROM_H )
     dvd_struct dvd;
 
     dvd.type = DVD_STRUCT_COPYRIGHT;
@@ -87,6 +88,16 @@ int ioctl_ReadCopyright( int i_fd, int i_layer, int *pi_copyright )
 
     *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 )
     INIT_RDC( GPCMD_READ_DVD_STRUCTURE, 8 );
 
@@ -99,12 +110,55 @@ int ioctl_ReadCopyright( int i_fd, int i_layer, int *pi_copyright )
 
 #elif defined( SYS_DARWIN1_3 )
     intf_ErrMsg( "css error: DVD ioctls not fully functional yet" );
+    intf_ErrMsg( "css error: assuming disc is encrypted" );
 
-    intf_ErrMsg( "css error: assuming disc is unencrypted" );
-    *pi_copyright = 0;
+    *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;
@@ -120,12 +174,11 @@ int ioctl_ReadKey( int i_fd, int *pi_agid, u8 *p_key )
 {
     int i_ret;
 
-#if defined( HAVE_SYS_DVDIO_H ) || defined( LINUX_DVD )
+#if defined( DVD_STRUCT_IN_LINUX_CDROM_H )
     dvd_struct dvd;
 
     dvd.type = DVD_STRUCT_DISCKEY;
     dvd.disckey.agid = *pi_agid;
-
     memset( dvd.disckey.value, 0, 2048 );
 
     i_ret = ioctl( i_fd, DVD_READ_STRUCT, &dvd );
@@ -137,6 +190,22 @@ int ioctl_ReadKey( int i_fd, int *pi_agid, u8 *p_key )
 
     memcpy( p_key, dvd.disckey.value, 2048 );
 
+#elif defined( HAVE_BSD_DVD_STRUCT )
+    struct dvd_struct dvd;
+
+    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 )
+    {
+        return i_ret;
+    }
+
+    memcpy( p_key, dvd.data, 2048 );
+
 #elif defined( SYS_BEOS )
     INIT_RDC( GPCMD_READ_DVD_STRUCTURE, 2048 + 4 );
 
@@ -152,6 +221,43 @@ int ioctl_ReadKey( int i_fd, int *pi_agid, u8 *p_key )
 
     memcpy( p_key, p_buffer + 4, 2048 );
 
+#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;
+
+    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
+    {
+        i_ret = -1;
+    }
+
 #else
     /* DVD ioctls unavailable - do as if the ioctl failed */
     i_ret = -1;
@@ -161,13 +267,13 @@ int ioctl_ReadKey( int i_fd, int *pi_agid, u8 *p_key )
 }
 
 /*****************************************************************************
- * ioctl_LUSendAgid: get AGID from the drive
+ * ioctl_ReportAgid: get AGID from the drive
  *****************************************************************************/
-int ioctl_LUSendAgid( int i_fd, int *pi_agid )
+int ioctl_ReportAgid( int i_fd, int *pi_agid )
 {
     int i_ret;
 
-#if defined( HAVE_SYS_DVDIO_H ) || defined( LINUX_DVD )
+#if defined( DVD_STRUCT_IN_LINUX_CDROM_H )
     dvd_authinfo auth_info;
 
     auth_info.type = DVD_LU_SEND_AGID;
@@ -177,15 +283,52 @@ int ioctl_LUSendAgid( int i_fd, int *pi_agid )
 
     *pi_agid = auth_info.lsa.agid;
 
+#elif defined( HAVE_BSD_DVD_STRUCT )
+    struct dvd_authinfo auth_info;
+
+    auth_info.format = DVD_REPORT_AGID;
+    auth_info.agid = *pi_agid;
+
+    i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
+
+    *pi_agid = auth_info.agid;
+
 #elif defined( SYS_BEOS )
     INIT_RDC( GPCMD_REPORT_KEY, 8 );
 
-    rdc.command[ 10 ] = 0x00 | (*pi_agid << 6);
+    rdc.command[ 10 ] = DVD_REPORT_AGID | (*pi_agid << 6);
 
     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
 
     *pi_agid = p_buffer[ 7 ] >> 6;
 
+#elif defined( SYS_DARWIN1_3 )
+    INIT_DVDIOCTL( 8 );
+
+    dvdioctl.i_keyformat = kCSSAGID;
+    dvdioctl.i_agid = *pi_agid;
+    dvdioctl.i_lba = 0;
+
+    i_ret = ioctl( i_fd, IODVD_REPORT_KEY, &dvdioctl );
+
+    *pi_agid = p_buffer[ 7 ] >> 6;
+
+#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;
+
+        *pi_agid = id;
+    }
+    else
+    {
+        i_ret = -1;
+    }
+
 #else
     /* DVD ioctls unavailable - do as if the ioctl failed */
     i_ret = -1;
@@ -195,13 +338,13 @@ int ioctl_LUSendAgid( int i_fd, int *pi_agid )
 }
 
 /*****************************************************************************
- * ioctl_LUSendChallenge: get challenge from the drive
+ * ioctl_ReportChallenge: get challenge from the drive
  *****************************************************************************/
-int ioctl_LUSendChallenge( int i_fd, int *pi_agid, u8 *p_challenge )
+int ioctl_ReportChallenge( int i_fd, int *pi_agid, u8 *p_challenge )
 {
     int i_ret;
 
-#if defined( HAVE_SYS_DVDIO_H ) || defined( LINUX_DVD )
+#if defined( DVD_STRUCT_IN_LINUX_CDROM_H )
     dvd_authinfo auth_info;
 
     auth_info.type = DVD_LU_SEND_CHALLENGE;
@@ -211,15 +354,65 @@ int ioctl_LUSendChallenge( int i_fd, int *pi_agid, u8 *p_challenge )
 
     memcpy( p_challenge, auth_info.lsc.chal, sizeof(dvd_challenge) );
 
+#elif defined( HAVE_BSD_DVD_STRUCT )
+    struct dvd_authinfo auth_info;
+
+    auth_info.format = DVD_REPORT_CHALLENGE;
+    auth_info.agid = *pi_agid;
+
+    i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
+
+    memcpy( p_challenge, auth_info.keychal, 10 );
+
 #elif defined( SYS_BEOS )
     INIT_RDC( GPCMD_REPORT_KEY, 16 );
 
-    rdc.command[ 10 ] = 0x01 | (*pi_agid << 6);
+    rdc.command[ 10 ] = DVD_REPORT_CHALLENGE | (*pi_agid << 6);
 
     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
 
     memcpy( p_challenge, p_buffer + 4, 12 );
 
+#elif defined( SYS_DARWIN1_3 )
+    INIT_DVDIOCTL( 16 );
+
+    dvdioctl.i_keyformat = kChallengeKey;
+    dvdioctl.i_agid = *pi_agid;
+    dvdioctl.i_lba = 0;
+
+    i_ret = ioctl( i_fd, IODVD_REPORT_KEY, &dvdioctl );
+
+    memcpy( p_challenge, p_buffer + 4, 12 );
+
+#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;
+
+        memset( &buffer, 0, sizeof( buffer ) );
+
+        key->KeyLength  = DVD_CHALLENGE_KEY_LENGTH;
+        key->SessionId  = *pi_agid;
+        key->KeyType    = DvdChallengeKey;
+        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_challenge, key->KeyData, 10 );
+    }
+    else
+    {
+        i_ret = -1;
+    }
+
 #else
     /* DVD ioctls unavailable - do as if the ioctl failed */
     i_ret = -1;
@@ -229,13 +422,13 @@ int ioctl_LUSendChallenge( int i_fd, int *pi_agid, u8 *p_challenge )
 }
 
 /*****************************************************************************
- * ioctl_LUSendASF: get ASF from the drive
+ * ioctl_ReportASF: get ASF from the drive
  *****************************************************************************/
-int ioctl_LUSendASF( int i_fd, int *pi_agid, int *pi_asf )
+int ioctl_ReportASF( int i_fd, int *pi_agid, int *pi_asf )
 {
     int i_ret;
 
-#if defined( HAVE_SYS_DVDIO_H ) || defined( LINUX_DVD )
+#if defined( DVD_STRUCT_IN_LINUX_CDROM_H )
     dvd_authinfo auth_info;
 
     auth_info.type = DVD_LU_SEND_ASF;
@@ -246,29 +439,68 @@ int ioctl_LUSendASF( int i_fd, int *pi_agid, int *pi_asf )
 
     *pi_asf = auth_info.lsasf.asf;
 
+#elif defined( HAVE_BSD_DVD_STRUCT )
+    struct dvd_authinfo auth_info;
+
+    auth_info.format = DVD_REPORT_ASF;
+    auth_info.agid = *pi_agid;
+    auth_info.asf = *pi_asf;
+
+    i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
+
+    *pi_asf = auth_info.asf;
+
 #elif defined( SYS_BEOS )
     INIT_RDC( GPCMD_REPORT_KEY, 8 );
 
-    rdc.command[ 10 ] = 0x05 | (*pi_agid << 6);
+    rdc.command[ 10 ] = DVD_REPORT_ASF | (*pi_agid << 6);
 
     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
 
     *pi_asf = p_buffer[ 7 ] & 1;
 
 #elif defined( SYS_DARWIN1_3 )
-    dvdioctl_data_t data;
-    u8 p_buffer[ 8 ];
+    INIT_DVDIOCTL( 8 );
 
-    data.p_buffer = p_buffer;
-    data.i_lba = 0;
-    data.i_agid = *pi_agid;
-    data.i_keyclass = kCSS_CSS2_CPRM;
-    data.i_keyformat = kASF;
+    dvdioctl.i_keyformat = kASF;
+    dvdioctl.i_agid = *pi_agid;
+    dvdioctl.i_lba = 0;
 
-    i_ret = ioctl( i_fd, IODVD_REPORT_KEY, &data );
+    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;
+
+        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;
+    }
+
 #else
     /* DVD ioctls unavailable - do as if the ioctl failed */
     i_ret = -1;
@@ -278,13 +510,13 @@ int ioctl_LUSendASF( int i_fd, int *pi_agid, int *pi_asf )
 }
 
 /*****************************************************************************
- * ioctl_LUSendKey1: get the first key from the drive
+ * ioctl_ReportKey1: get the first key from the drive
  *****************************************************************************/
-int ioctl_LUSendKey1( int i_fd, int *pi_agid, u8 *p_key )
+int ioctl_ReportKey1( int i_fd, int *pi_agid, u8 *p_key )
 {
     int i_ret;
 
-#if defined( HAVE_SYS_DVDIO_H ) || defined( LINUX_DVD )
+#if defined( DVD_STRUCT_IN_LINUX_CDROM_H )
     dvd_authinfo auth_info;
 
     auth_info.type = DVD_LU_SEND_KEY1;
@@ -294,15 +526,59 @@ int ioctl_LUSendKey1( int i_fd, int *pi_agid, u8 *p_key )
 
     memcpy( p_key, auth_info.lsk.key, sizeof(dvd_key) );
 
+#elif defined( HAVE_BSD_DVD_STRUCT )
+    struct dvd_authinfo auth_info;
+
+    auth_info.format = DVD_REPORT_KEY1;
+    auth_info.agid = *pi_agid;
+
+    i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
+
+    memcpy( p_key, auth_info.keychal, 8 );
+
 #elif defined( SYS_BEOS )
     INIT_RDC( GPCMD_REPORT_KEY, 12 );
 
-    rdc.command[ 10 ] = 0x02 | (*pi_agid << 6);
+    rdc.command[ 10 ] = DVD_REPORT_KEY1 | (*pi_agid << 6);
 
     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
 
     memcpy( p_key, p_buffer + 4, 8 );
 
+#elif defined( SYS_DARWIN1_3 )
+    INIT_DVDIOCTL( 12 );
+
+    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 */
+    {
+        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    = DvdBusKey1;
+        key->KeyFlags   = 0;
+
+        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
+    {
+        i_ret = -1;
+    }
+
 #else
     /* DVD ioctls unavailable - do as if the ioctl failed */
     i_ret = -1;
@@ -318,7 +594,7 @@ int ioctl_InvalidateAgid( int i_fd, int *pi_agid )
 {
     int i_ret;
 
-#if defined( HAVE_SYS_DVDIO_H ) || defined( LINUX_DVD )
+#if defined( DVD_STRUCT_IN_LINUX_CDROM_H )
     dvd_authinfo auth_info;
 
     auth_info.type = DVD_INVALIDATE_AGID;
@@ -328,13 +604,44 @@ int ioctl_InvalidateAgid( int i_fd, int *pi_agid )
 
     *pi_agid = auth_info.lsa.agid;
 
+#elif defined( HAVE_BSD_DVD_STRUCT )
+    struct dvd_authinfo auth_info;
+
+    auth_info.format = DVD_INVALIDATE_AGID;
+    auth_info.agid = *pi_agid;
+
+    i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
+
+    *pi_agid = auth_info.agid;
+
 #elif defined( SYS_BEOS )
     INIT_RDC( GPCMD_REPORT_KEY, 0 );
 
-    rdc.command[ 10 ] = 0x3f | (*pi_agid << 6);
+    rdc.command[ 10 ] = DVD_INVALIDATE_AGID | (*pi_agid << 6);
 
     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
 
+#elif defined( SYS_DARWIN1_3 )
+    INIT_DVDIOCTL( 0 );
+
+    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
+    {
+        i_ret = -1;
+    }
+
 #else
     /* DVD ioctls unavailable - do as if the ioctl failed */
     i_ret = -1;
@@ -344,11 +651,11 @@ int ioctl_InvalidateAgid( int i_fd, int *pi_agid )
 }
 
 /*****************************************************************************
- * ioctl_HostSendChallenge: send challenge to the drive
+ * ioctl_SendChallenge: send challenge to the drive
  *****************************************************************************/
-int ioctl_HostSendChallenge( int i_fd, int *pi_agid, u8 *p_challenge )
+int ioctl_SendChallenge( int i_fd, int *pi_agid, u8 *p_challenge )
 {
-#if defined( HAVE_SYS_DVDIO_H ) || defined( LINUX_DVD )
+#if defined( DVD_STRUCT_IN_LINUX_CDROM_H )
     dvd_authinfo auth_info;
 
     auth_info.type = DVD_HOST_SEND_CHALLENGE;
@@ -358,16 +665,61 @@ int ioctl_HostSendChallenge( int i_fd, int *pi_agid, u8 *p_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;
+
+    memcpy( auth_info.keychal, p_challenge, 12 );
+
+    return ioctl( i_fd, DVDIOCSENDKEY, &auth_info );
+
 #elif defined( SYS_BEOS )
     INIT_RDC( GPCMD_SEND_KEY, 16 );
 
-    rdc.command[ 10 ] = 0x01 | (*pi_agid << 6);
+    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 */
+    {
+        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 );
+
+        return DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_SEND_KEY, key, 
+                key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
+    }
+    else
+    {
+        return -1;
+    }
+
 #else
     /* DVD ioctls unavailable - do as if the ioctl failed */
     return -1;
@@ -376,11 +728,11 @@ int ioctl_HostSendChallenge( int i_fd, int *pi_agid, u8 *p_challenge )
 }
 
 /*****************************************************************************
- * ioctl_HostSendKey2: send the second key to the drive
+ * ioctl_SendKey2: send the second key to the drive
  *****************************************************************************/
-int ioctl_HostSendKey2( int i_fd, int *pi_agid, u8 *p_key )
+int ioctl_SendKey2( int i_fd, int *pi_agid, u8 *p_key )
 {
-#if defined( HAVE_SYS_DVDIO_H ) || defined( LINUX_DVD )
+#if defined( DVD_STRUCT_IN_LINUX_CDROM_H )
     dvd_authinfo auth_info;
 
     auth_info.type = DVD_HOST_SEND_KEY2;
@@ -390,16 +742,61 @@ int ioctl_HostSendKey2( int i_fd, int *pi_agid, u8 *p_key )
 
     return ioctl( i_fd, DVD_AUTH, &auth_info );
 
+#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 );
 
-    rdc.command[ 10 ] = 0x3 | (*pi_agid << 6);
+    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 */
+    {
+        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
+    {
+        return -1;
+    }
+
+#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;
@@ -416,11 +813,9 @@ int ioctl_HostSendKey2( int i_fd, int *pi_agid, u8 *p_key )
  * This function initializes a BeOS raw device command structure for future
  * use, either a read command or a write command.
  *****************************************************************************/
-static void BeInitRDC( raw_device_command *p_rdc,
-                       void *p_buffer, int i_len, int i_type )
+static void BeInitRDC( raw_device_command *p_rdc, int i_type )
 {
-    memset( p_rdc, 0, sizeof( raw_device_command ) );
-    memset( p_buffer, 0, i_len );
+    memset( p_rdc->data, 0, p_rdc->data_length );
 
     switch( i_type )
     {
@@ -430,19 +825,16 @@ static void BeInitRDC( raw_device_command *p_rdc,
 
         case GPCMD_READ_DVD_STRUCTURE:
         case GPCMD_REPORT_KEY:
-            p_rdc.flags         = B_RAW_DEVICE_DATA_IN;
+            p_rdc->flags = B_RAW_DEVICE_DATA_IN;
             break;
     }
 
     p_rdc->command[ 0 ]      = i_type;
 
-    p_rdc->command[ 8 ]      = (i_len >> 8) & 0xff;
-    p_rdc->command[ 9 ]      =  i_len       & 0xff;
+    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->data              = (char *)p_buffer;
-    p_rdc->data_length       = i_len;
-
     p_rdc->sense_data        = NULL;
     p_rdc->sense_data_length = 0;