1 /*****************************************************************************
2 * libdvdcss.c: DVD reading library.
3 *****************************************************************************
4 * Copyright (C) 1998-2001 VideoLAN
5 * $Id: libdvdcss.c,v 1.6 2001/07/12 23:06:54 gbazin Exp $
7 * Authors: Stéphane Borel <stef@via.ecp.fr>
8 * Samuel Hocevar <sam@zoy.org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
32 #include <sys/types.h>
42 # include "input_iovec.h"
44 # include <sys/uio.h> /* struct iovec */
50 #include "videolan/dvdcss.h"
51 #include "libdvdcss.h"
54 /*****************************************************************************
56 *****************************************************************************/
57 static int _dvdcss_open ( dvdcss_handle, char *psz_target );
58 static int _dvdcss_close ( dvdcss_handle );
59 static int _dvdcss_seek ( dvdcss_handle, int i_blocks );
60 static int _dvdcss_read ( dvdcss_handle, void *p_buffer, int i_blocks );
61 static int _dvdcss_readv ( dvdcss_handle, struct iovec *p_iovec, int i_blocks );
63 /*****************************************************************************
64 * Local prototypes, win32 specific
65 *****************************************************************************/
67 static int _win32_dvdcss_readv ( int i_fd, struct iovec *p_iovec,
69 static int _win32_dvdcss_aopen ( char c_drive, dvdcss_handle dvdcss );
70 static int _win32_dvdcss_aclose ( int i_fd );
71 static int _win32_dvdcss_aseek ( int i_fd, int i_blocks, int i_method );
72 static int _win32_dvdcss_aread ( int i_fd, void *p_data, int i_blocks );
75 /*****************************************************************************
76 * dvdcss_open: initialize library, open a DVD device, crack CSS key
77 *****************************************************************************/
78 extern dvdcss_handle dvdcss_open ( char *psz_target, int i_flags )
84 /* Allocate the library structure */
85 dvdcss = malloc( sizeof( struct dvdcss_s ) );
88 if( ! (i_flags & DVDCSS_INIT_QUIET) )
90 DVDCSS_ERROR( "could not initialize library" );
96 /* Initialize structure */
97 dvdcss->p_keys = NULL;
98 dvdcss->b_debug = i_flags & DVDCSS_INIT_DEBUG;
99 dvdcss->b_errors = !(i_flags & DVDCSS_INIT_QUIET);
100 dvdcss->psz_error = "no error";
102 i_ret = _dvdcss_open( dvdcss, psz_target );
109 i_ret = CSSTest( dvdcss );
112 _dvdcss_error( dvdcss, "css test failed" );
113 _dvdcss_close( dvdcss );
118 dvdcss->b_encrypted = i_ret;
120 /* If drive is encrypted, crack its key */
121 if( dvdcss->b_encrypted )
123 i_ret = CSSInit( dvdcss );
127 _dvdcss_close( dvdcss );
136 /*****************************************************************************
137 * dvdcss_error: return the last libdvdcss error message
138 *****************************************************************************/
139 extern char * dvdcss_error ( dvdcss_handle dvdcss )
141 return dvdcss->psz_error;
144 /*****************************************************************************
145 * dvdcss_seek: seek into the device
146 *****************************************************************************/
147 extern int dvdcss_seek ( dvdcss_handle dvdcss, int i_blocks )
149 return _dvdcss_seek( dvdcss, i_blocks );
152 /*****************************************************************************
153 * dvdcss_crack: crack the current title key
154 *****************************************************************************/
155 extern int dvdcss_crack ( dvdcss_handle dvdcss, int i_block )
157 title_key_t **pp_writekey;
158 title_key_t **pp_currentkey;
159 title_key_t *p_titlekey;
163 if( ! dvdcss->b_encrypted )
168 /* Check if we've already cracked this key */
169 p_titlekey = dvdcss->p_keys;
170 while( p_titlekey != NULL
171 && p_titlekey->p_next != NULL
172 && p_titlekey->p_next->i_startlb < i_block )
174 p_titlekey = p_titlekey->p_next;
177 if( p_titlekey != NULL && p_titlekey->i_startlb == i_block )
179 /* We've already cracked this key, nothing to do */
183 /* Crack CSS title key for current VTS */
184 i_ret = CSSGetKey( dvdcss, i_block, p_key );
188 _dvdcss_error( dvdcss, "fatal error in vts css key" );
193 _dvdcss_error( dvdcss, "decryption unavailable" );
197 /* Add key to keytable if it isn't empty */
198 if( p_key[0] || p_key[1] || p_key[2] || p_key[3] || p_key[4] )
200 /* Find our spot in the list */
201 pp_writekey = &(dvdcss->p_keys);
202 pp_currentkey = pp_writekey;
203 while( *pp_currentkey != NULL
204 && (*pp_currentkey)->i_startlb < i_block )
206 pp_writekey = pp_currentkey;
207 pp_currentkey = &((*pp_currentkey)->p_next);
210 /* Write in the new key */
211 p_titlekey = *pp_writekey;
212 *pp_writekey = malloc( sizeof( title_key_t ) );
213 (*pp_writekey)->i_startlb = i_block;
214 memcpy( (*pp_writekey)->p_key, p_key, KEY_SIZE );
215 (*pp_writekey)->p_next = p_titlekey;
221 /*****************************************************************************
222 * dvdcss_read: read data from the device, decrypt if requested
223 *****************************************************************************/
224 extern int dvdcss_read ( dvdcss_handle dvdcss, void *p_buffer,
228 title_key_t *p_current;
231 i_ret = _dvdcss_read( dvdcss, p_buffer, i_blocks );
234 || !dvdcss->b_encrypted
235 || !(i_flags & DVDCSS_READ_DECRYPT) )
241 p_current = dvdcss->p_keys;
242 while( p_current != NULL
244 && p_current->p_next->i_startlb < dvdcss->i_seekpos )
246 p_current = p_current->p_next;
249 if( p_current == NULL )
251 /* no css key found to use, so no decryption to do */
255 /* Decrypt the blocks we managed to read */
256 for( i_index = i_ret; i_index; i_index-- )
258 CSSDescrambleSector( p_current->p_key, p_buffer );
259 ((u8*)p_buffer)[0x14] &= 0x8f;
260 (u8*)p_buffer += DVDCSS_BLOCK_SIZE;
266 /*****************************************************************************
267 * dvdcss_readv: read data to an iovec structure, decrypt if reaquested
268 *****************************************************************************/
269 extern int dvdcss_readv ( dvdcss_handle dvdcss, void *p_iovec,
273 #define P_IOVEC ((struct iovec*)p_iovec)
274 title_key_t *p_current;
279 i_ret = _dvdcss_readv( dvdcss, P_IOVEC, i_blocks );
282 || !dvdcss->b_encrypted
283 || !(i_flags & DVDCSS_READ_DECRYPT) )
289 p_current = dvdcss->p_keys;
290 while( p_current != NULL
292 && p_current->p_next->i_startlb < dvdcss->i_seekpos )
294 p_current = p_current->p_next;
297 if( p_current == NULL )
299 /* no css key found to use, so no decryption to do */
304 /* Initialize loop for decryption */
305 iov_base = P_IOVEC->iov_base;
306 iov_len = P_IOVEC->iov_len;
308 /* Decrypt the blocks we managed to read */
309 for( i_index = i_ret; i_index; i_index-- )
311 /* Check that iov_len is a multiple of 2048 */
312 if( iov_len & 0x7ff )
317 while( iov_len == 0 )
320 iov_base = P_IOVEC->iov_base;
321 iov_len = P_IOVEC->iov_len;
324 CSSDescrambleSector( p_current->p_key, iov_base );
325 ((u8*)iov_base)[0x14] &= 0x8f;
327 (u8*)iov_base += DVDCSS_BLOCK_SIZE;
328 (u8*)iov_len -= DVDCSS_BLOCK_SIZE;
335 /*****************************************************************************
336 * dvdcss_close: close the DVD device and clean up the library
337 *****************************************************************************/
338 extern int dvdcss_close ( dvdcss_handle dvdcss )
340 title_key_t *p_currentkey;
343 /* Free our list of keys */
344 p_currentkey = dvdcss->p_keys;
345 while( p_currentkey )
347 title_key_t *p_tmpkey = p_currentkey->p_next;
348 free( p_currentkey );
349 p_currentkey = p_tmpkey;
352 i_ret = _dvdcss_close( dvdcss );
364 /* Following functions are local */
366 static int _dvdcss_open ( dvdcss_handle dvdcss, char *psz_target )
372 _snprintf( psz_dvd, 7, "\\\\.\\%c:", psz_target[0] );
373 (HANDLE) dvdcss->i_fd =
374 CreateFile( psz_dvd, GENERIC_READ | GENERIC_WRITE,
375 FILE_SHARE_READ | FILE_SHARE_WRITE,
376 NULL, OPEN_EXISTING, 0, NULL );
377 if( (HANDLE) dvdcss->i_fd == INVALID_HANDLE_VALUE )
379 _dvdcss_error( dvdcss, "failed opening device" );
385 dvdcss->i_fd = _win32_dvdcss_aopen( psz_target[0], dvdcss );
386 if( dvdcss->i_fd == -1 )
388 _dvdcss_error( dvdcss, "failed opening device" );
394 dvdcss->i_fd = open( psz_target, 0 );
396 if( dvdcss->i_fd == -1 )
398 _dvdcss_error( dvdcss, "failed opening device" );
407 static int _dvdcss_close ( dvdcss_handle dvdcss )
412 CloseHandle( (HANDLE) dvdcss->i_fd );
416 _win32_dvdcss_aclose( dvdcss->i_fd );
419 close( dvdcss->i_fd );
425 static int _dvdcss_seek ( dvdcss_handle dvdcss, int i_blocks )
430 LARGE_INTEGER li_read;
432 #ifndef INVALID_SET_FILE_POINTER
433 #define INVALID_SET_FILE_POINTER ((DWORD)-1)
436 li_read.QuadPart = (LONGLONG)i_blocks * DVDCSS_BLOCK_SIZE;
438 li_read.LowPart = SetFilePointer( (HANDLE) dvdcss->i_fd,
440 &li_read.HighPart, FILE_BEGIN );
441 if( (li_read.LowPart == INVALID_SET_FILE_POINTER)
442 && GetLastError() != NO_ERROR)
444 li_read.QuadPart = -DVDCSS_BLOCK_SIZE;
447 li_read.QuadPart /= DVDCSS_BLOCK_SIZE;
448 return (int)li_read.QuadPart;
452 return ( _win32_dvdcss_aseek( dvdcss->i_fd, i_blocks, SEEK_SET ) );
457 dvdcss->i_seekpos = i_blocks;
459 i_read = lseek( dvdcss->i_fd,
460 (off_t)i_blocks * (off_t)DVDCSS_BLOCK_SIZE, SEEK_SET );
462 return i_read / DVDCSS_BLOCK_SIZE;
467 static int _dvdcss_read ( dvdcss_handle dvdcss, void *p_buffer, int i_blocks )
474 if( !ReadFile( (HANDLE) dvdcss->i_fd, p_buffer,
475 i_blocks * DVDCSS_BLOCK_SIZE,
476 (LPDWORD)&i_bytes, NULL ) )
480 return i_bytes / DVDCSS_BLOCK_SIZE;
484 return _win32_dvdcss_aread( dvdcss->i_fd, p_buffer, i_blocks );
490 i_bytes = read( dvdcss->i_fd, p_buffer, (size_t)i_blocks * DVDCSS_BLOCK_SIZE );
491 return i_bytes / DVDCSS_BLOCK_SIZE;
496 static int _dvdcss_readv ( dvdcss_handle dvdcss, struct iovec *p_iovec, int i_blocks )
501 i_read = _win32_dvdcss_readv( dvdcss->i_fd, p_iovec, i_blocks );
504 i_read = readv( dvdcss->i_fd, p_iovec, i_blocks );
505 return i_read / DVDCSS_BLOCK_SIZE;
511 /*****************************************************************************
512 * _win32_dvdcss_readv: vectored read using ReadFile for Win2K and
513 * _win32_dvdcss_aread for win9x
514 *****************************************************************************/
515 static int _win32_dvdcss_readv( int i_fd, struct iovec *p_iovec,
518 int i_index, i_len, i_total = 0;
519 unsigned char *p_base;
524 for( i_index = i_num_buffers; i_index; i_index-- )
526 i_len = p_iovec->iov_len;
527 p_base = p_iovec->iov_base;
531 unsigned long int i_bytes;
532 if( !ReadFile( (HANDLE) i_fd, p_base, i_len, &i_bytes, NULL ) )
535 /* One of the reads failed, too bad.
536 We won't even bother returning the reads that went well,
537 and like in the posix spec the file postition is left
538 unspecified after a failure */
540 i_blocks = i_bytes / DVDCSS_BLOCK_SIZE;
544 if( i_blocks != (i_len / DVDCSS_BLOCK_SIZE) )
546 /* we reached the end of the file */
557 for( i_index = i_num_buffers; i_index; i_index-- )
559 i_len = p_iovec->iov_len / DVDCSS_BLOCK_SIZE;
560 p_base = p_iovec->iov_base;
564 i_blocks = _win32_dvdcss_aread( i_fd, p_base, i_len );
567 return -1; /* idem */
572 if( i_blocks != i_len )
574 /* we reached the end of the file or a signal interrupted
587 /*****************************************************************************
588 * _win32_dvdcss_aopen: open dvd drive (load aspi and init w32_aspidev
590 *****************************************************************************/
591 static int _win32_dvdcss_aopen( char c_drive, dvdcss_handle dvdcss )
595 struct w32_aspidev *fd;
596 int i, j, i_hostadapters;
597 long (*lpGetSupport)( void );
598 long (*lpSendCommand)( void* );
600 hASPI = LoadLibrary( "wnaspi32.dll" );
603 _dvdcss_error( dvdcss, "unable to load wnaspi32.dll" );
607 (FARPROC) lpGetSupport = GetProcAddress( hASPI, "GetASPI32SupportInfo" );
608 (FARPROC) lpSendCommand = GetProcAddress( hASPI, "SendASPI32Command" );
610 if(lpGetSupport == NULL || lpSendCommand == NULL )
612 _dvdcss_debug( dvdcss, "unable to get aspi function pointers" );
613 FreeLibrary( hASPI );
617 dwSupportInfo = lpGetSupport();
619 if( HIBYTE( LOWORD ( dwSupportInfo ) ) == SS_NO_ADAPTERS )
621 _dvdcss_debug( dvdcss, "no host adapters found (aspi)" );
622 FreeLibrary( hASPI );
626 if( HIBYTE( LOWORD ( dwSupportInfo ) ) != SS_COMP )
628 _dvdcss_error( dvdcss, "unable to initalize aspi layer" );
629 FreeLibrary( hASPI );
633 i_hostadapters = LOBYTE( LOWORD( dwSupportInfo ) );
634 if( i_hostadapters == 0 )
636 FreeLibrary( hASPI );
640 fd = malloc( sizeof( struct w32_aspidev ) );
643 FreeLibrary( hASPI );
648 fd->hASPI = (long) hASPI;
649 fd->lpSendCommand = lpSendCommand;
653 fd->i_sid = MAKEWORD( ASPI_HAID, ASPI_TARGET );
657 c_drive = c_drive > 'Z' ? c_drive - 'a' : c_drive - 'A';
659 for( i = 0; i < i_hostadapters; i++ )
661 for( j = 0; j < 15; j++ )
663 struct SRB_GetDiskInfo srbDiskInfo;
665 srbDiskInfo.SRB_Cmd = SC_GET_DISK_INFO;
666 srbDiskInfo.SRB_HaId = i;
667 srbDiskInfo.SRB_Flags = 0;
668 srbDiskInfo.SRB_Hdr_Rsvd = 0;
669 srbDiskInfo.SRB_Target = j;
670 srbDiskInfo.SRB_Lun = 0;
672 lpSendCommand( (void*) &srbDiskInfo );
674 if( srbDiskInfo.SRB_Status == SS_COMP &&
675 srbDiskInfo.SRB_Int13HDriveInfo == c_drive )
677 fd->i_sid = MAKEWORD( i, j );
684 FreeLibrary( hASPI );
685 _dvdcss_debug( dvdcss, "unable to get haid and target (aspi)" );
690 /*****************************************************************************
691 * _win32_dvdcss_aclose: close dvd drive (unload aspi and free w32_aspidev
693 *****************************************************************************/
694 static int _win32_dvdcss_aclose( int i_fd )
696 struct w32_aspidev *fd = (struct w32_aspidev *) i_fd;
698 FreeLibrary( (HMODULE) fd->hASPI );
699 free( (void*) i_fd );
704 /*****************************************************************************
705 * _win32_dvdcss_aseek: aspi version of _dvdcss_seek
707 * returns the number of blocks read.
708 *****************************************************************************/
709 static int _win32_dvdcss_aseek( int i_fd, int i_blocks, int i_method )
712 char sz_buf[ DVDCSS_BLOCK_SIZE ];
713 struct w32_aspidev *fd = (struct w32_aspidev *) i_fd;
715 i_old_blocks = fd->i_blocks;
716 fd->i_blocks = i_blocks;
718 if( _win32_dvdcss_aread( i_fd, sz_buf, 1 ) == -1 )
720 fd->i_blocks = i_old_blocks;
729 /*****************************************************************************
730 * _win32_dvdcss_aread: aspi version of _dvdcss_read
732 * returns the number of blocks read.
733 *****************************************************************************/
734 static int _win32_dvdcss_aread( int i_fd, void *p_data, int i_blocks )
737 DWORD dwStart, dwLen;
738 struct SRB_ExecSCSICmd ssc;
739 struct w32_aspidev *fd = (struct w32_aspidev *) i_fd;
741 memset( &ssc, 0, sizeof( ssc ) );
743 dwStart = fd->i_blocks;
746 hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
752 ssc.SRB_Cmd = SC_EXEC_SCSI_CMD;
753 ssc.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY;
754 ssc.SRB_HaId = LOBYTE( fd->i_sid );
755 ssc.SRB_Target = HIBYTE( fd->i_sid );
756 ssc.SRB_SenseLen = SENSE_LEN;
757 ssc.SRB_PostProc = (LPVOID) hEvent;
759 ssc.SRB_BufLen = dwLen * DVDCSS_BLOCK_SIZE;
760 ssc.SRB_BufPointer = p_data;
763 ssc.CDBByte[0] = 0xA8; /* RAW */
764 ssc.CDBByte[2] = (UCHAR) dwStart >> 24;
765 ssc.CDBByte[3] = (UCHAR) (dwStart >> 16) & 0xff;
766 ssc.CDBByte[4] = (UCHAR) (dwStart >> 8) & 0xff;
767 ssc.CDBByte[5] = (UCHAR) (dwStart) & 0xff;
768 ssc.CDBByte[6] = (UCHAR) dwLen >> 24;
769 ssc.CDBByte[7] = (UCHAR) (dwLen >> 16) & 0xff;
770 ssc.CDBByte[8] = (UCHAR) (dwLen >> 8) & 0xff;
771 ssc.CDBByte[9] = (UCHAR) (dwLen) & 0xff;
773 ResetEvent( hEvent );
774 if( fd->lpSendCommand( (void*) &ssc ) == SS_PENDING )
776 WaitForSingleObject( hEvent, INFINITE );
779 CloseHandle( hEvent );
781 if( ssc.SRB_Status != SS_COMP )
786 fd->i_blocks += i_blocks;