diff options
Diffstat (limited to 'test/dvd_region.c')
-rw-r--r-- | test/dvd_region.c | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/test/dvd_region.c b/test/dvd_region.c new file mode 100644 index 0000000..40b15c8 --- /dev/null +++ b/test/dvd_region.c @@ -0,0 +1,297 @@ +/* + * Set / inspect region settings on a DVD drive. This is most interesting + * on a RPC Phase-2 drive, of course. + * + * Usage: dvd_region [ -d device ] [ [ -s ] [ -r region ] ] + * + * Based on code from Jens Axboe <axboe@suse.de>. + * + * FIXME: This code does _not_ work yet. + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <fcntl.h> +#include <getopt.h> + +#include <dvdcss/dvdcss.h> + +#include "config.h" +#include "common.h" +#include "ioctl.h" +#include "libdvdcss.h" + +/* On non-Linux platforms static functions from ioctl.c are used. */ +#include "ioctl.c" + +#define DEFAULT_DEVICE "/dev/dvd" + +/***************************************************************************** + * ioctl_SendRPC: set RPC status for the drive + *****************************************************************************/ +static int ioctl_SendRPC( int i_fd, int i_pdrc ) +{ + int i_ret; + + /* Shut up warnings about unused parameters. */ + (void)i_fd; + (void)i_pdrc; + +#if defined( HAVE_LINUX_DVD_STRUCT ) && defined( DVD_HOST_SEND_RPC_STATE ) + dvd_authinfo auth_info = { 0 }; + + auth_info.type = DVD_HOST_SEND_RPC_STATE; + auth_info.hrpcs.pdrc = i_pdrc; + + i_ret = ioctl( i_fd, DVD_AUTH, &auth_info ); + +#elif defined( HAVE_LINUX_DVD_STRUCT ) + /* FIXME: OpenBSD doesn't know this */ + i_ret = -1; + +#elif defined( HAVE_BSD_DVD_STRUCT ) + struct dvd_authinfo auth_info = { 0 }; + + auth_info.format = DVD_SEND_RPC; + auth_info.region = i_pdrc; + + i_ret = ioctl( i_fd, DVDIOCSENDKEY, &auth_info ); + +#elif defined( __HAIKU__ ) + INIT_RDC( GPCMD_SEND_KEY, 8 ); + + rdc.command[ 10 ] = DVD_SEND_RPC; + + p_buffer[ 1 ] = 6; + p_buffer[ 4 ] = i_pdrc; + + i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) ); + +#elif defined( SOLARIS_USCSI ) + INIT_USCSI( GPCMD_SEND_KEY, 8 ); + + rs_cdb.cdb_opaque[ 10 ] = DVD_SEND_RPC; + + p_buffer[ 1 ] = 6; + p_buffer[ 4 ] = i_pdrc; + + i_ret = SolarisSendUSCSI( i_fd, &sc ); + + if( i_ret < 0 || sc.uscsi_status ) + { + i_ret = -1; + } + +#elif defined( DARWIN_DVD_IOCTL ) + INIT_DVDIOCTL( dk_dvd_send_key_t, DVDRegionPlaybackControlInfo, + kDVDKeyFormatSetRegion ); + + dvd.keyClass = kDVDKeyClassCSS_CPPM_CPRM; + dvdbs.driveRegion = i_pdrc; + + i_ret = ioctl( i_fd, DKIOCDVDSENDKEY, &dvd ); + +#elif defined( _WIN32 ) + DWORD tmp; + SCSI_PASS_THROUGH_DIRECT sptd = { 0 }; + uint8_t p_buffer[8]; + sptd.Length = sizeof( SCSI_PASS_THROUGH_DIRECT ); + sptd.DataBuffer = p_buffer; + sptd.DataTransferLength = sizeof( p_buffer ); + WinInitSPTD( &sptd, GPCMD_SEND_KEY ); + + sptd.Cdb[ 10 ] = DVD_SEND_RPC; + + p_buffer[ 1 ] = 6; + p_buffer[ 4 ] = i_pdrc; + + 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; + +#elif defined( __QNXNTO__ ) + + INIT_CPT( GPCMD_SEND_KEY, 8 ); + + p_cpt->cam_cdb[ 10 ] = DVD_SEND_RPC; + + p_buffer[ 1 ] = 6; + p_buffer[ 4 ] = i_pdrc; + + i_ret = devctl(i_fd, DCMD_CAM_PASS_THRU, p_cpt, structSize, NULL); + +#elif defined( __OS2__ ) + INIT_SSC( GPCMD_SEND_KEY, 8 ); + + sdc.command[ 10 ] = DVD_SEND_RPC; + + p_buffer[ 1 ] = 6; + p_buffer[ 4 ] = i_pdrc; + + i_ret = DosDevIOCtl( i_fd, IOCTL_CDROMDISK, CDROMDISK_EXECMD, + &sdc, sizeof(sdc), &ulParamLen, + p_buffer, sizeof(p_buffer), &ulDataLen ); + +#else +# error "DVD ioctls are unavailable on this system" + +#endif + return i_ret; +} + +static int set_region(int fd, int region) +{ + int ret, region_mask; + + if(region > 8 || region <= 0) { + printf("Invalid region( %d)\n", region); + return 1; + } + printf("Setting drive region can only be done a finite " + "number of times, press Ctrl-C now to cancel!\n"); + /* Discard returned character, just wait for any key as confirmation. */ + (void) getchar(); + + region_mask = 0xff & ~(1 << (region - 1)); + printf("Setting region to %d( %x)\n", region, region_mask); + if( (ret = ioctl_SendRPC(fd, region_mask)) < 0) { + perror("dvd_region"); + return ret; + } + + return 0; +} + +static int print_region(int fd) +{ + int type, region_mask, rpc_scheme; + int region = 1; + int ret; + + printf("Drive region info:\n"); + + if( (ret = ioctl_ReportRPC(fd, &type, ®ion_mask, &rpc_scheme)) < 0) { + perror("dvd_region"); + return ret; + } + + printf("Type: "); + switch( type ) { + case 0: + printf("No drive region setting\n"); + break; + case 1: + printf("Drive region is set\n"); + break; + case 2: + printf("Drive region is set, with additional " + "restrictions required to make a change\n"); + break; + case 3: + printf("Drive region has been set permanently, but " + "may be reset by the vendor if necessary\n"); + break; + default: + printf("Invalid( %x)\n", type); + break; + } + + printf("Region: "); + if( region_mask) + while(region_mask) { + if( !(region_mask & 1) ) + printf("%d playable\n", region); + region++; + region_mask >>= 1; + } + else + printf("non-RPC( all)\n"); + + printf("RPC Scheme: "); + switch( rpc_scheme ) { + case 0: + printf("The Logical Unit does not enforce Regional " + "Playback Control (RPC).\n"); + break; + case 1: + printf("The Logical Unit _shall_ adhere to the " + "specification and all requirements of the " + "Content Scrambling System (CSS) license " + "agreement concerning RPC.\n"); + break; + default: + printf("Reserved( %x)\n", rpc_scheme); + } + + return 0; +} + +static void usage(void) +{ + fprintf( stderr, + "Usage: dvd_region [ -d device ] [ [ -s ] [ -r region ] ]\n" ); +} + +int main(int argc, char *argv[]) +{ + char device_name[FILENAME_MAX], c, set, region = 0; + int ret; + dvdcss_t dvdcss; + + strcpy(device_name, DEFAULT_DEVICE); + set = 0; + while( (c = getopt(argc, argv, "d:sr:h?")) != EOF ) { + switch( c ) { + case 'd': + strncpy(device_name, optarg, FILENAME_MAX - 1); + break; + case 's': + set = 1; + break; + case 'r': + region = strtoul(optarg, NULL, 10); + printf("region %d\n", region); + break; + case 'h': + case '?': + default: + usage(); + return -1; + break; + } + } + + if( optind != argc ) { + fprintf(stderr, "Unknown argument\n"); + usage(); + return -1; + } + + if( !(dvdcss = dvdcss_open(device_name)) ) { + usage(); + return 1; + } + + { + int copyright; + ret = ioctl_ReadCopyright( dvdcss->i_fd, 0, ©right ); + printf( "ret %d, copyright %d\n", ret, copyright ); + } + + if( (ret = print_region(dvdcss->i_fd)) < 0 ) + return ret; + + if( set ) { + if( !region ) { + fprintf( stderr, "you must specify the region!\n" ); + exit(0); + } + + if( (ret = set_region(dvdcss->i_fd, region)) < 0 ) + return ret; + } + + exit( 0 ); +} |