Commit 7325feef authored by Diego Biurrun's avatar Diego Biurrun
Browse files

Drop support for ASPI disc access (and thus Windows 9x).

The ASPI access method is only relevant on Windows 9x versions where no
alternative exists. However, These Windows versions are obsolete since a
long time and have no more real world usage. Also, the ASPI code is ugly
and a maintenance burden.
parent 3d52f9e2
......@@ -5,10 +5,9 @@ Changes between 1.2.13 and 1.3.0:
- the function dvdcss_title()
- the type dvdcss_handle
- the variable dvdcss_interface_2
* Drop support for Windows 98 and Windows NT 4.0.
Windows 98 SE with IE 5.0 and Windows NT 4.0 SP4 with IE 5.0 are required.
* Support for Android
* Drop support for HP-UX.
* Drop support for HP-UX, Windows 9x, and Windows NT 4.0.
Windows NT 4.0 SP4 with IE 5.0 is now required.
Changes between 1.2.12 and 1.2.13:
......
......@@ -32,8 +32,8 @@ Conflicts: libdvdcss0.0.1, libdvdcss0.0.2
libdvdcss is a simple library designed for accessing DVDs like a block device
without having to bother about the decryption. The important features are:
* Portability: Currently supported platforms are GNU/Linux, FreeBSD, NetBSD,
OpenBSD, BeOS, Mac OS X, Solaris, OS/2, Windows 98 SE (with IE 5.0) or
later, and Windows NT 4.0 (with IE 5.0) or later.
OpenBSD, BeOS, Mac OS X, Solaris, OS/2, and Windows NT 4.0 SP4 (with IE 5.0)
or later.
* Adaptability: Unlike most similar projects, libdvdcss does not require the
region of your drive to be set and will try its best to read from the disc
even in the case of a region mismatch.
......@@ -49,8 +49,8 @@ Provides: %name = %version-%release
libdvdcss is a simple library designed for accessing DVDs like a block device
without having to bother about the decryption. The important features are:
* Portability: Currently supported platforms are GNU/Linux, FreeBSD, NetBSD,
OpenBSD, BeOS, Mac OS X, Solaris, OS/2, Windows 98 SE (with IE 5.0) or
later, and Windows NT 4.0 (with IE 5.0) or later.
OpenBSD, BeOS, Mac OS X, Solaris, OS/2, and Windows NT 4.0 SP4 (with IE 5.0)
or later.
* Adaptability: Unlike most similar projects, libdvdcss does not require the
region of your drive to be set and will try its best to read from the disc
even in the case of a region mismatch.
......
......@@ -84,14 +84,10 @@ static int libc_readv ( dvdcss_t, struct iovec *, int );
#ifdef WIN32
static int win2k_open ( dvdcss_t, const char * );
static int aspi_open ( dvdcss_t, const char * );
static int win2k_seek ( dvdcss_t, int );
static int aspi_seek ( dvdcss_t, int );
static int win2k_read ( dvdcss_t, void *, int );
static int aspi_read ( dvdcss_t, void *, int );
static int win_readv ( dvdcss_t, struct iovec *, int );
static int aspi_read_internal ( int, void *, int );
#elif defined( __OS2__ )
static int os2_open ( dvdcss_t, const char * );
/* just use macros for libc */
......@@ -362,7 +358,7 @@ int dvdcss_open_device ( dvdcss_t dvdcss )
dvdcss->p_readv_buffer = NULL;
dvdcss->i_readv_buf_size = 0;
if( !dvdcss->b_file && WIN2K )
if( !dvdcss->b_file )
{
print_debug( dvdcss, "using Win2K API for access" );
dvdcss->pf_seek = win2k_seek;
......@@ -370,14 +366,6 @@ int dvdcss_open_device ( dvdcss_t dvdcss )
dvdcss->pf_readv = win_readv;
return win2k_open( dvdcss, psz_device );
}
else if( !dvdcss->b_file )
{
print_debug( dvdcss, "using ASPI for access" );
dvdcss->pf_seek = aspi_seek;
dvdcss->pf_read = aspi_read;
dvdcss->pf_readv = win_readv;
return aspi_open( dvdcss, psz_device );
}
else
#elif defined( __OS2__ )
/* If device is "X:" or "X:\", we are not actually opening a file. */
......@@ -429,18 +417,10 @@ int dvdcss_close_device ( dvdcss_t dvdcss )
{
close( dvdcss->i_fd );
}
else if( WIN2K )
else
{
CloseHandle( (HANDLE) dvdcss->i_fd );
}
else /* ASPI */
{
struct w32_aspidev *fd = (struct w32_aspidev *) dvdcss->i_fd;
/* Unload ASPI and free w32_aspidev structure */
FreeLibrary( (HMODULE) fd->hASPI );
free( (void*) dvdcss->i_fd );
}
/* Free readv temporary buffer */
free( dvdcss->p_readv_buffer );
......@@ -527,124 +507,6 @@ error:
print_error( dvdcss, "failed opening device" );
return -1;
}
static int aspi_open( dvdcss_t dvdcss, const char *psz_device )
{
HMODULE hASPI;
DWORD dwSupportInfo;
struct w32_aspidev *fd;
int i, j, i_hostadapters;
GETASPI32SUPPORTINFO lpGetSupport;
SENDASPI32COMMAND lpSendCommand;
char c_drive = psz_device[0];
/* load ASPI and init w32_aspidev structure */
hASPI = LoadLibrary( "wnaspi32.dll" );
if( hASPI == NULL )
{
print_error( dvdcss, "unable to load wnaspi32.dll" );
return -1;
}
lpGetSupport = (GETASPI32SUPPORTINFO) GetProcAddress( hASPI, "GetASPI32SupportInfo" );
lpSendCommand = (SENDASPI32COMMAND) GetProcAddress( hASPI, "SendASPI32Command" );
if(lpGetSupport == NULL || lpSendCommand == NULL )
{
print_error( dvdcss, "unable to get ASPI function pointers" );
FreeLibrary( hASPI );
return -1;
}
dwSupportInfo = lpGetSupport();
if( HIBYTE( LOWORD ( dwSupportInfo ) ) == SS_NO_ADAPTERS )
{
print_error( dvdcss, "no ASPI adapters found" );
FreeLibrary( hASPI );
return -1;
}
if( HIBYTE( LOWORD ( dwSupportInfo ) ) != SS_COMP )
{
print_error( dvdcss, "unable to initialize ASPI layer" );
FreeLibrary( hASPI );
return -1;
}
i_hostadapters = LOBYTE( LOWORD( dwSupportInfo ) );
if( i_hostadapters == 0 )
{
print_error( dvdcss, "no ASPI adapters ready" );
FreeLibrary( hASPI );
return -1;
}
fd = malloc( sizeof( struct w32_aspidev ) );
if( fd == NULL )
{
print_error( dvdcss, "not enough memory" );
FreeLibrary( hASPI );
return -1;
}
fd->i_blocks = 0;
fd->hASPI = (long) hASPI;
fd->lpSendCommand = lpSendCommand;
c_drive = c_drive > 'Z' ? c_drive - 'a' : c_drive - 'A';
for( i = 0; i < i_hostadapters; i++ )
{
for( j = 0; j < 15; j++ )
{
struct SRB_GetDiskInfo srbDiskInfo;
srbDiskInfo.SRB_Cmd = SC_GET_DISK_INFO;
srbDiskInfo.SRB_HaId = i;
srbDiskInfo.SRB_Flags = 0;
srbDiskInfo.SRB_Hdr_Rsvd = 0;
srbDiskInfo.SRB_Target = j;
srbDiskInfo.SRB_Lun = 0;
lpSendCommand( (void*) &srbDiskInfo );
if( (srbDiskInfo.SRB_Status == SS_COMP) &&
(srbDiskInfo.SRB_Int13HDriveInfo == c_drive) )
{
/* Make sure this is a CD-ROM device */
struct SRB_GDEVBlock srbGDEVBlock = { 0 };
srbGDEVBlock.SRB_Cmd = SC_GET_DEV_TYPE;
srbGDEVBlock.SRB_HaId = i;
srbGDEVBlock.SRB_Target = j;
lpSendCommand( (void*) &srbGDEVBlock );
if( ( srbGDEVBlock.SRB_Status == SS_COMP ) &&
( srbGDEVBlock.SRB_DeviceType == DTYPE_CDROM ) )
{
fd->i_sid = MAKEWORD( i, j );
dvdcss->i_fd = (int) fd;
dvdcss->i_pos = 0;
return 0;
}
else
{
free( fd );
FreeLibrary( hASPI );
print_error( dvdcss,"this is not a CD-ROM drive" );
return -1;
}
}
}
}
free( (void*) fd );
FreeLibrary( hASPI );
print_error( dvdcss, "unable to get haid and target (ASPI)" );
return -1;
}
#endif
#ifdef __OS2__
......@@ -733,35 +595,6 @@ static int win2k_seek( dvdcss_t dvdcss, int i_blocks )
return dvdcss->i_pos;
}
static int aspi_seek( dvdcss_t dvdcss, int i_blocks )
{
int i_old_blocks;
char sz_buf[ DVDCSS_BLOCK_SIZE ];
struct w32_aspidev *fd = (struct w32_aspidev *) dvdcss->i_fd;
if( dvdcss->i_pos == i_blocks )
{
/* We are already in position */
return i_blocks;
}
i_old_blocks = fd->i_blocks;
fd->i_blocks = i_blocks;
if( aspi_read_internal( dvdcss->i_fd, sz_buf, 1 ) == -1 )
{
fd->i_blocks = i_old_blocks;
dvdcss->i_pos = -1;
return -1;
}
(fd->i_blocks)--;
dvdcss->i_pos = fd->i_blocks;
return dvdcss->i_pos;
}
#endif
/*****************************************************************************
......@@ -817,20 +650,6 @@ static int win2k_read ( dvdcss_t dvdcss, void *p_buffer, int i_blocks )
dvdcss->i_pos += i_bytes / DVDCSS_BLOCK_SIZE;
return i_bytes / DVDCSS_BLOCK_SIZE;
}
static int aspi_read ( dvdcss_t dvdcss, void *p_buffer, int i_blocks )
{
int i_read = aspi_read_internal( dvdcss->i_fd, p_buffer, i_blocks );
if( i_read < 0 )
{
dvdcss->i_pos = -1;
return i_read;
}
dvdcss->i_pos += i_read;
return i_read;
}
#endif
/*****************************************************************************
......@@ -905,7 +724,7 @@ static int libc_readv ( dvdcss_t dvdcss, struct iovec *p_iovec, int i_blocks )
#if defined( WIN32 )
/*****************************************************************************
* win_readv: vectored read using ReadFile for Win2K and ASPI for win9x
* win_readv: vectored read using ReadFile for Win2K
*****************************************************************************/
static int win_readv ( dvdcss_t dvdcss, struct iovec *p_iovec, int i_blocks )
{
......@@ -941,31 +760,16 @@ static int win_readv ( dvdcss_t dvdcss, struct iovec *p_iovec, int i_blocks )
i_blocks_total /= DVDCSS_BLOCK_SIZE;
if( WIN2K )
if( !ReadFile( (HANDLE)dvdcss->i_fd, dvdcss->p_readv_buffer,
i_blocks_total * DVDCSS_BLOCK_SIZE, &i_bytes, NULL ) )
{
if( !ReadFile( (HANDLE)dvdcss->i_fd, dvdcss->p_readv_buffer,
i_blocks_total * DVDCSS_BLOCK_SIZE, &i_bytes, NULL ) )
{
/* The read failed... too bad.
* As in the POSIX spec the file position is left
* unspecified after a failure */
dvdcss->i_pos = -1;
return -1;
}
i_blocks_read = i_bytes / DVDCSS_BLOCK_SIZE;
}
else /* Win9x */
{
i_blocks_read = aspi_read_internal( dvdcss->i_fd,
dvdcss->p_readv_buffer,
i_blocks_total );
if( i_blocks_read < 0 )
{
/* See above */
dvdcss->i_pos = -1;
return -1;
}
/* The read failed... too bad.
* As in the POSIX spec the file position is left
* unspecified after a failure */
dvdcss->i_pos = -1;
return -1;
}
i_blocks_read = i_bytes / DVDCSS_BLOCK_SIZE;
/* We just have to copy the content of the temp buffer into the iovecs */
for( i_index = 0, i_blocks_total = i_blocks_read;
......@@ -985,82 +789,4 @@ static int win_readv ( dvdcss_t dvdcss, struct iovec *p_iovec, int i_blocks )
dvdcss->i_pos += i_blocks_read;
return i_blocks_read;
}
static int aspi_read_internal( int i_fd, void *p_data, int i_blocks )
{
HANDLE hEvent;
struct SRB_ExecSCSICmd ssc = { 0 };
struct w32_aspidev *fd = (struct w32_aspidev *) i_fd;
/* Create the transfer completion event */
hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
if( hEvent == NULL )
{
return -1;
}
ssc.SRB_Cmd = SC_EXEC_SCSI_CMD;
ssc.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY;
ssc.SRB_HaId = LOBYTE( fd->i_sid );
ssc.SRB_Target = HIBYTE( fd->i_sid );
ssc.SRB_SenseLen = SENSE_LEN;
ssc.SRB_PostProc = (LPVOID) hEvent;
ssc.SRB_BufPointer = p_data;
ssc.SRB_CDBLen = 12;
ssc.CDBByte[0] = 0xA8; /* RAW */
ssc.CDBByte[2] = (UCHAR) (fd->i_blocks >> 24);
ssc.CDBByte[3] = (UCHAR) (fd->i_blocks >> 16) & 0xff;
ssc.CDBByte[4] = (UCHAR) (fd->i_blocks >> 8) & 0xff;
ssc.CDBByte[5] = (UCHAR) (fd->i_blocks) & 0xff;
/* We have to break down the reads into 64KB pieces (ASPI restriction) */
if( i_blocks > 32 )
{
ssc.SRB_BufLen = 32 * DVDCSS_BLOCK_SIZE;
ssc.CDBByte[9] = 32;
fd->i_blocks += 32;
/* Initiate transfer */
ResetEvent( hEvent );
fd->lpSendCommand( (void*) &ssc );
/* transfer the next 64KB (aspi_read_internal is called recursively)
* We need to check the status of the read on return */
if( aspi_read_internal( i_fd,
(uint8_t*) p_data + 32 * DVDCSS_BLOCK_SIZE,
i_blocks - 32) < 0 )
{
return -1;
}
}
else
{
/* This is the last transfer */
ssc.SRB_BufLen = i_blocks * DVDCSS_BLOCK_SIZE;
ssc.CDBByte[9] = (UCHAR) i_blocks;
fd->i_blocks += i_blocks;
/* Initiate transfer */
ResetEvent( hEvent );
fd->lpSendCommand( (void*) &ssc );
}
/* If the command has still not been processed, wait until it's finished */
if( ssc.SRB_Status == SS_PENDING )
{
WaitForSingleObject( hEvent, INFINITE );
}
CloseHandle( hEvent );
/* check that the transfer went as planned */
if( ssc.SRB_Status != SS_COMP )
{
return -1;
}
return i_blocks;
}
#endif
......@@ -103,12 +103,10 @@ static int SolarisSendUSCSI( int fd, struct uscsi_cmd *p_sc );
#endif
/*****************************************************************************
* Local prototypes, win32 (aspi) specific
* Local prototypes, Win32 specific
*****************************************************************************/
#if defined( WIN32 )
static void WinInitSPTD ( SCSI_PASS_THROUGH_DIRECT *, int );
static void WinInitSSC ( struct SRB_ExecSCSICmd *, int );
static int WinSendSSC ( int, struct SRB_ExecSCSICmd * );
#endif
/*****************************************************************************
......@@ -188,35 +186,21 @@ int ioctl_ReadCopyright( int i_fd, int i_layer, int *pi_copyright )
*pi_copyright = dvdbs.copyrightProtectionSystemType;
#elif defined( WIN32 )
if( WIN2K ) /* NT/2k/XP */
{
INIT_SPTD( GPCMD_READ_DVD_STRUCTURE, 8 );
INIT_SPTD( GPCMD_READ_DVD_STRUCTURE, 8 );
/* When using IOCTL_DVD_READ_STRUCTURE and
DVD_COPYRIGHT_DESCRIPTOR, CopyrightProtectionType
seems to be always 6 ???
To work around this MS bug we try to send a raw SCSI command
instead (if we've got enough privileges to do so). */
/* When using IOCTL_DVD_READ_STRUCTURE and
DVD_COPYRIGHT_DESCRIPTOR, CopyrightProtectionType
seems to be always 6 ???
To work around this MS bug we try to send a raw SCSI command
instead (if we've got enough privileges to do so). */
sptd.Cdb[ 6 ] = i_layer;
sptd.Cdb[ 7 ] = DVD_STRUCT_COPYRIGHT;
sptd.Cdb[ 6 ] = i_layer;
sptd.Cdb[ 7 ] = DVD_STRUCT_COPYRIGHT;
i_ret = SEND_SPTD( i_fd, &sptd, &tmp );
i_ret = SEND_SPTD( i_fd, &sptd, &tmp );
if( i_ret == 0 )
{
*pi_copyright = p_buffer[ 4 ];
}
}
else
if( i_ret == 0 )
{
INIT_SSC( GPCMD_READ_DVD_STRUCTURE, 8 );
ssc.CDBByte[ 6 ] = i_layer;
ssc.CDBByte[ 7 ] = DVD_STRUCT_COPYRIGHT;
i_ret = WinSendSSC( i_fd, &ssc );
*pi_copyright = p_buffer[ 4 ];
}
......@@ -329,44 +313,25 @@ int ioctl_ReadDiscKey( int i_fd, int *pi_agid, uint8_t *p_key )
memcpy( p_key, dvdbs.discKeyStructures, DVD_DISCKEY_SIZE );
#elif defined( WIN32 )
if( WIN2K ) /* NT/2k/XP */
{
DWORD tmp;
uint8_t buffer[DVD_DISK_KEY_LENGTH] = { 0 };
PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
DWORD tmp;
uint8_t buffer[DVD_DISK_KEY_LENGTH] = { 0 };
PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
key->KeyLength = DVD_DISK_KEY_LENGTH;
key->SessionId = *pi_agid;
key->KeyType = DvdDiskKey;
key->KeyFlags = 0;
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;
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, DVD_DISCKEY_SIZE );
}
else
if( i_ret < 0 )
{
INIT_SSC( GPCMD_READ_DVD_STRUCTURE, DVD_DISCKEY_SIZE + 4 );
ssc.CDBByte[ 7 ] = DVD_STRUCT_DISCKEY;
ssc.CDBByte[ 10 ] = *pi_agid << 6;
i_ret = WinSendSSC( i_fd, &ssc );
if( i_ret < 0 )
{
return i_ret;
}
memcpy( p_key, p_buffer + 4, DVD_DISCKEY_SIZE );
return i_ret;
}
memcpy( p_key, key->KeyData, DVD_DISCKEY_SIZE );
#elif defined( __QNXNTO__ )
INIT_CPT( GPCMD_READ_DVD_STRUCTURE, DVD_DISCKEY_SIZE + 4 );
......@@ -480,38 +445,21 @@ int ioctl_ReadTitleKey( int i_fd, int *pi_agid, int i_pos, uint8_t *p_key )
memcpy( p_key, dvdbs.titleKeyValue, DVD_KEY_SIZE );
#elif defined( WIN32 )
if( WIN2K ) /* NT/2k/XP */
{
DWORD tmp;
uint8_t buffer[DVD_TITLE_KEY_LENGTH] = { 0 };
PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
key->KeyLength = DVD_TITLE_KEY_LENGTH;
key->SessionId = *pi_agid;
key->KeyType = DvdTitleKey;
key->KeyFlags = 0;
key->Parameters.TitleOffset.QuadPart = (LONGLONG) i_pos *
DVDCSS_BLOCK_SIZE;
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, DVD_KEY_SIZE );
}
else
{
INIT_SSC( GPCMD_REPORT_KEY, 12 );
DWORD tmp;
uint8_t buffer[DVD_TITLE_KEY_LENGTH] = { 0 };
PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
ssc.CDBByte[ 2 ] = ( i_pos >> 24 ) & 0xff;
ssc.CDBByte[ 3 ] = ( i_pos >> 16 ) & 0xff;
ssc.CDBByte[ 4 ] = ( i_pos >> 8 ) & 0xff;
ssc.CDBByte[ 5 ] = ( i_pos ) & 0xff;
ssc.CDBByte[ 10 ] = DVD_REPORT_TITLE_KEY | (*pi_agid << 6);
key->KeyLength = DVD_TITLE_KEY_LENGTH;
key->SessionId = *pi_agid;
key->KeyType = DvdTitleKey;
key->KeyFlags = 0;
key->Parameters.TitleOffset.QuadPart = (LONGLONG) i_pos *
DVDCSS_BLOCK_SIZE;
i_ret = WinSendSSC( i_fd, &ssc );
i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key,
key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
memcpy( p_key, p_buffer + 5, DVD_KEY_SIZE );
}
memcpy( p_key, key->KeyData, DVD_KEY_SIZE );
#elif defined( __QNXNTO__ )
......@@ -613,26 +561,13 @@ int ioctl_ReportAgid( int i_fd, int *pi_agid )
*pi_agid = dvdbs.grantID;
#elif defined( WIN32 )
if( WIN2K ) /* NT/2k/XP */
{
ULONG id;
DWORD tmp = 0;
i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_START_SESSION,
&tmp, 4, &id, sizeof( id ), &tmp, NULL ) ? 0 : -1;
*pi_agid = id;
}
else
{
INIT_SSC( GPCMD_REPORT_KEY, 8 );
ULONG id;
DWORD tmp = 0;
ssc.CDBByte[ 10 ] = DVD_REPORT_AGID | (*pi_agid << 6);
i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_START_SESSION,
&tmp, 4, &id, sizeof( id ), &tmp, NULL ) ? 0 : -1;
i_ret = WinSendSSC( i_fd, &ssc );
*pi_agid = p_buffer[ 7 ] >> 6;
}
*pi_agid = id;
#elif defined( __QNXNTO__ )
......@@ -723,38 +658,25 @@ int ioctl_ReportChallenge( int i_fd, int *pi_agid, uint8_t *p_challenge )
memcpy( p_challenge, dvdbs.challengeKeyValue, DVD_CHALLENGE_SIZE );
#elif defined( WIN32 )
if( WIN2K ) /* NT/2k/XP */
{
DWORD tmp;
uint8_t buffer[DVD_CHALLENGE_KEY_LENGTH] = { 0 };
PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
DWORD tmp;
uint8_t buffer[DVD_CHALLENGE_KEY_LENGTH] = { 0 };
PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
key->KeyLength = DVD_CHALLENGE_KEY_LENGTH;
key->SessionId = *pi_agid;
key->KeyType = DvdChallengeKey;
key->KeyFlags = 0;
key->KeyLength = DVD_CHALLENGE_KEY_LENGTH;
key->SessionId = *pi_agid;
key->KeyType = DvdChallengeKey;