X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=plugins%2Fdvd%2Fdvd_ioctl.c;h=d0a480f5258df24e346d8f877ea5295428e24596;hb=0c128d47071e1e107cd25820ae0c664ab5ca5b70;hp=1723a2fab387e911e69bdf259a8bfdf1b00bf2f4;hpb=583c6553f6761421260d86bbc21b5b3169c04319;p=vlc diff --git a/plugins/dvd/dvd_ioctl.c b/plugins/dvd/dvd_ioctl.c index 1723a2fab3..d0a480f525 100644 --- a/plugins/dvd/dvd_ioctl.c +++ b/plugins/dvd/dvd_ioctl.c @@ -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 * Samuel Hocevar + * Jon Lech Johansen * * 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 @@ -27,14 +28,24 @@ *****************************************************************************/ #include "defs.h" -#include -#ifdef HAVE_SYS_IOCTL_H +#include /* memcpy(), memset() */ +#include + +#if defined( WIN32 ) +# include +# include +#else +# include # include #endif -#ifdef HAVE_SYS_DVDIO_H + +#ifdef DVD_STRUCT_IN_SYS_CDIO_H +# include +#endif +#ifdef DVD_STRUCT_IN_SYS_DVDIO_H # include #endif -#ifdef LINUX_DVD +#ifdef DVD_STRUCT_IN_LINUX_CDROM_H # include #endif #ifdef SYS_BEOS @@ -43,633 +54,791 @@ #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