/***************************************************************************** * dvd_ioctl.c: DVD ioctl replacement function ***************************************************************************** * Copyright (C) 1999-2001 VideoLAN * $Id: dvd_ioctl.c,v 1.5 2001/04/04 02:49:18 sam Exp $ * * Authors: Markus Kuespert * Samuel Hocevar * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. *****************************************************************************/ /***************************************************************************** * Preamble *****************************************************************************/ #include "defs.h" #include #include #ifdef HAVE_SYS_DVDIO_H # include # include #endif #ifdef LINUX_DVD # include # include #endif #ifdef SYS_BEOS # include # include # include #endif #ifdef SYS_DARWIN1_3 # include #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 - BeOS specific *****************************************************************************/ #if defined( SYS_BEOS ) static void BeInitRDC ( raw_device_command *, void *, int ); #endif /***************************************************************************** * ioctl_ReadCopyright: check whether the disc is encrypted or not *****************************************************************************/ int ioctl_ReadCopyright( int i_fd, int i_layer, int *pi_copyright ) { int i_ret; #if defined( HAVE_SYS_DVDIO_H ) || defined( LINUX_DVD ) 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( SYS_BEOS ) raw_device_command rdc; u8 p_buffer[ 8 ]; BeInitRDC( &rdc, p_buffer, 8 ); rdc.flags = B_RAW_DEVICE_DATA_IN; rdc.command[ 0 ] = GPCMD_READ_DVD_STRUCTURE; rdc.command[ 6 ] = i_layer; rdc.command[ 7 ] = DVD_STRUCT_COPYRIGHT; 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 unencrypted" ); *pi_copyright = 0; i_ret = 0; #else /* DVD ioctls unavailable - do as if the ioctl failed */ i_ret = -1; #endif return i_ret; } /***************************************************************************** * ioctl_ReadKey: get the disc key *****************************************************************************/ int ioctl_ReadKey( css_t *p_css, u8 *p_key ) { int i_ret; #if defined( HAVE_SYS_DVDIO_H ) || defined( LINUX_DVD ) dvd_struct dvd; dvd.type = DVD_STRUCT_DISCKEY; dvd.disckey.agid = p_css->i_agid; memset( dvd.disckey.value, 0, 2048 ); i_ret = ioctl( p_css->i_fd, DVD_READ_STRUCT, &dvd ); if( i_ret < 0 ) { return i_ret; } memcpy( p_key, dvd.disckey.value, 2048 ); #elif defined( SYS_BEOS ) raw_device_command rdc; u8 p_buffer[ 2048 + 4 ]; BeInitRDC( &rdc, p_buffer, 2048 + 4 ); rdc.flags = B_RAW_DEVICE_DATA_IN; rdc.command[ 0 ] = GPCMD_READ_DVD_STRUCTURE; rdc.command[ 7 ] = DVD_STRUCT_DISCKEY; rdc.command[ 10 ] = p_css->i_agid << 6; i_ret = ioctl( p_css->i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) ); if( i_ret < 0 ) { return i_ret; } memcpy( p_key, p_buffer + 4, 2048 ); #else /* DVD ioctls unavailable - do as if the ioctl failed */ i_ret = -1; #endif return i_ret; } /***************************************************************************** * ioctl_LUSendAgid: get AGID from the drive *****************************************************************************/ int ioctl_LUSendAgid( css_t *p_css ) { int i_ret; #if defined( HAVE_SYS_DVDIO_H ) || defined( LINUX_DVD ) dvd_authinfo auth_info; auth_info.type = DVD_LU_SEND_AGID; auth_info.lsa.agid = p_css->i_agid; i_ret = ioctl( p_css->i_fd, DVD_AUTH, &auth_info ); p_css->i_agid = auth_info.lsa.agid; #elif defined( SYS_BEOS ) raw_device_command rdc; u8 p_buffer[ 8 ]; BeInitRDC( &rdc, p_buffer, 8 ); rdc.flags = B_RAW_DEVICE_DATA_IN; rdc.command[ 0 ] = GPCMD_REPORT_KEY; rdc.command[ 10 ] = 0x00 | (p_css->i_agid << 6); i_ret = ioctl( p_css->i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) ); p_css->i_agid = p_buffer[ 7 ] >> 6; #else /* DVD ioctls unavailable - do as if the ioctl failed */ i_ret = -1; #endif return i_ret; } /***************************************************************************** * ioctl_LUSendChallenge: get challenge from the drive *****************************************************************************/ int ioctl_LUSendChallenge( css_t *p_css, u8 *p_challenge ) { int i_ret; #if defined( HAVE_SYS_DVDIO_H ) || defined( LINUX_DVD ) dvd_authinfo auth_info; auth_info.type = DVD_LU_SEND_CHALLENGE; i_ret = ioctl( p_css->i_fd, DVD_AUTH, &auth_info ); memcpy( p_challenge, auth_info.lsc.chal, sizeof(dvd_challenge) ); #elif defined( SYS_BEOS ) raw_device_command rdc; u8 p_buffer[ 16 ]; BeInitRDC( &rdc, p_buffer, 16 ); rdc.flags = B_RAW_DEVICE_DATA_IN; rdc.command[ 0 ] = GPCMD_REPORT_KEY; rdc.command[ 10 ] = 0x01 | (p_css->i_agid << 6); i_ret = ioctl( p_css->i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) ); memcpy( p_challenge, p_buffer + 4, 12 ); #else /* DVD ioctls unavailable - do as if the ioctl failed */ i_ret = -1; #endif return i_ret; } /***************************************************************************** * ioctl_LUSendASF: get ASF from the drive *****************************************************************************/ int ioctl_LUSendASF( css_t *p_css, int *pi_asf ) { int i_ret; #if defined( HAVE_SYS_DVDIO_H ) || defined( LINUX_DVD ) dvd_authinfo auth_info; auth_info.type = DVD_LU_SEND_ASF; auth_info.lsasf.agid = p_css->i_agid; auth_info.lsasf.asf = *pi_asf; i_ret = ioctl( p_css->i_fd, DVD_AUTH, &auth_info ); *pi_asf = auth_info.lsasf.asf; #elif defined( SYS_BEOS ) raw_device_command rdc; u8 p_buffer[ 8 ]; BeInitRDC( &rdc, p_buffer, 8 ); rdc.flags = B_RAW_DEVICE_DATA_IN; rdc.command[ 0 ] = GPCMD_REPORT_KEY; rdc.command[ 10 ] = 0x05 | (p_css->i_agid << 6); i_ret = ioctl( p_css->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 ]; data.p_buffer = p_buffer; data.i_lba = 0; data.i_agid = p_css->i_agid; data.i_keyclass = kCSS_CSS2_CPRM; data.i_keyformat = kASF; i_ret = ioctl( p_css->i_fd, IODVD_REPORT_KEY, &data ); *pi_asf = p_buffer[ 7 ] & 1; #else /* DVD ioctls unavailable - do as if the ioctl failed */ i_ret = -1; #endif return i_ret; } /***************************************************************************** * ioctl_LUSendKey1: get the first key from the drive *****************************************************************************/ int ioctl_LUSendKey1( css_t *p_css, u8 *p_key ) { int i_ret; #if defined( HAVE_SYS_DVDIO_H ) || defined( LINUX_DVD ) dvd_authinfo auth_info; auth_info.type = DVD_LU_SEND_KEY1; auth_info.lsk.agid = p_css->i_agid; i_ret = ioctl( p_css->i_fd, DVD_AUTH, &auth_info ); memcpy( p_key, auth_info.lsk.key, sizeof(dvd_key) ); #elif defined( SYS_BEOS ) raw_device_command rdc; u8 p_buffer[ 12 ]; BeInitRDC( &rdc, p_buffer, 12 ); rdc.flags = B_RAW_DEVICE_DATA_IN; rdc.command[ 0 ] = GPCMD_REPORT_KEY; rdc.command[ 10 ] = 0x02 | (p_css->i_agid << 6); i_ret = ioctl( p_css->i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) ); memcpy( p_key, p_buffer + 4, 8 ); #else /* DVD ioctls unavailable - do as if the ioctl failed */ i_ret = -1; #endif return i_ret; } /***************************************************************************** * ioctl_InvalidateAgid: invalidate the current AGID *****************************************************************************/ int ioctl_InvalidateAgid( css_t *p_css ) { int i_ret; #if defined( HAVE_SYS_DVDIO_H ) || defined( LINUX_DVD ) dvd_authinfo auth_info; auth_info.type = DVD_INVALIDATE_AGID; auth_info.lsa.agid = p_css->i_agid; i_ret = ioctl( p_css->i_fd, DVD_AUTH, &auth_info ); p_css->i_agid = auth_info.lsa.agid; #elif defined( SYS_BEOS ) raw_device_command rdc; u8 p_buffer[ 0 ]; BeInitRDC( &rdc, p_buffer, 0 ); rdc.flags = B_RAW_DEVICE_DATA_IN; rdc.command[ 0 ] = GPCMD_REPORT_KEY; rdc.command[ 10 ] = 0x3f | (p_css->i_agid << 6); i_ret = ioctl( p_css->i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) ); #else /* DVD ioctls unavailable - do as if the ioctl failed */ i_ret = -1; #endif return i_ret; } /***************************************************************************** * ioctl_HostSendChallenge: send challenge to the drive *****************************************************************************/ int ioctl_HostSendChallenge( css_t *p_css, u8 *p_challenge ) { #if defined( HAVE_SYS_DVDIO_H ) || defined( LINUX_DVD ) dvd_authinfo auth_info; auth_info.type = DVD_HOST_SEND_CHALLENGE; memcpy( auth_info.hsc.chal, p_challenge, sizeof(dvd_challenge) ); return ioctl( p_css->i_fd, DVD_AUTH, &auth_info ); #elif defined( SYS_BEOS ) raw_device_command rdc; u8 p_buffer[ 16 ]; BeInitRDC( &rdc, p_buffer, 16 ); rdc.command[ 0 ] = GPCMD_SEND_KEY; rdc.command[ 10 ] = 0x01 | (p_css->i_agid << 6); p_buffer[ 1 ] = 0xe; memcpy( p_buffer + 4, p_challenge, 12 ); return ioctl( p_css->i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) ); #else /* DVD ioctls unavailable - do as if the ioctl failed */ return -1; #endif } /***************************************************************************** * ioctl_HostSendKey2: send the second key to the drive *****************************************************************************/ int ioctl_HostSendKey2( css_t *p_css, u8 *p_key ) { #if defined( HAVE_SYS_DVDIO_H ) || defined( LINUX_DVD ) dvd_authinfo auth_info; auth_info.type = DVD_HOST_SEND_KEY2; auth_info.hsk.agid = p_css->i_agid; memcpy( auth_info.hsk.key, p_key, sizeof(dvd_key) ); return ioctl( p_css->i_fd, DVD_AUTH, &auth_info ); #elif defined( SYS_BEOS ) raw_device_command rdc; u8 p_buffer[ 12 ]; BeInitRDC( &rdc, p_buffer, 12 ); rdc.command[ 0 ] = GPCMD_REPORT_KEY; rdc.command[ 10 ] = 0x3 | (p_css->i_agid << 6); p_buffer[ 1 ] = 0xa; memcpy( p_buffer + 4, p_key, 8 ); return ioctl( p_css->i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) ); #else /* DVD ioctls unavailable - do as if the ioctl failed */ return -1; #endif } /* Local prototypes */ #if defined( SYS_BEOS ) /***************************************************************************** * 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 void BeInitRDC( raw_device_command *p_rdc, void *p_buffer, int i_len ) { memset( p_rdc, 0, sizeof( raw_device_command ) ); memset( p_buffer, 0, i_len ); p_rdc->command[ 8 ] = (i_len >> 8) & 0xff; p_rdc->command[ 9 ] = i_len & 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; p_rdc->timeout = 1000000; } #endif