1 /*****************************************************************************
2 * device.h: DVD device access
3 *****************************************************************************
4 * Copyright (C) 1998-2006 VideoLAN
7 * Authors: Stéphane Borel <stef@via.ecp.fr>
8 * Sam Hocevar <sam@zoy.org>
9 * Håkan Hjort <d95hjort@dtek.chalmers.se>
11 * This library is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License along
22 * with this library; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 *****************************************************************************/
26 /*****************************************************************************
28 *****************************************************************************/
37 #include <sys/types.h>
39 #ifdef HAVE_SYS_PARAM_H
40 # include <sys/param.h>
52 #if defined( WIN32 ) && !defined( SYS_CYGWIN )
53 # include <io.h> /* read() */
55 # include <sys/uio.h> /* struct iovec */
58 #ifdef DARWIN_DVD_IOCTL
60 # include <CoreFoundation/CoreFoundation.h>
61 # include <IOKit/IOKitLib.h>
62 # include <IOKit/IOBSD.h>
63 # include <IOKit/storage/IOMedia.h>
64 # include <IOKit/storage/IOCDMedia.h>
65 # include <IOKit/storage/IODVDMedia.h>
70 # define INCL_DOSDEVIOCTL
72 # include <io.h> /* setmode() */
73 # include <fcntl.h> /* O_BINARY */
76 #include "dvdcss/dvdcss.h"
80 #include "libdvdcss.h"
84 /*****************************************************************************
85 * Device reading prototypes
86 *****************************************************************************/
87 static int libc_open ( dvdcss_t
, char const * );
88 static int libc_seek ( dvdcss_t
, int );
89 static int libc_read ( dvdcss_t
, void *, int );
90 static int libc_readv ( dvdcss_t
, struct iovec
*, int );
93 static int win2k_open ( dvdcss_t
, char const * );
94 static int aspi_open ( dvdcss_t
, char const * );
95 static int win2k_seek ( dvdcss_t
, int );
96 static int aspi_seek ( dvdcss_t
, int );
97 static int win2k_read ( dvdcss_t
, void *, int );
98 static int aspi_read ( dvdcss_t
, void *, int );
99 static int win_readv ( dvdcss_t
, struct iovec
*, int );
101 static int aspi_read_internal ( int, void *, int );
102 #elif defined( SYS_OS2 )
103 static int os2_open ( dvdcss_t
, char const * );
104 /* just use macros for libc */
105 # define os2_seek libc_seek
106 # define os2_read libc_read
107 # define os2_readv libc_readv
110 int _dvdcss_use_ioctls( dvdcss_t dvdcss
)
118 /* FIXME: implement this for Windows */
127 #elif defined( SYS_OS2 )
130 if( DosQueryFHState( dvdcss
->i_fd
, &ulMode
) != 0 )
131 return 1; /* What to do? Be conservative and try to use the ioctls */
133 if( ulMode
& OPEN_FLAGS_DASD
)
138 struct stat fileinfo
;
141 ret
= fstat( dvdcss
->i_fd
, &fileinfo
);
144 return 1; /* What to do? Be conservative and try to use the ioctls */
147 /* Complete this list and check that we test for the right things
148 * (I've assumed for all OSs that 'r', (raw) device, are char devices
149 * and those that don't contain/use an 'r' in the name are block devices)
151 * Linux needs a block device
152 * Solaris needs a char device
153 * Darwin needs a char device
154 * OpenBSD needs a char device
155 * NetBSD needs a char device
156 * FreeBSD can use either the block or the char device
157 * BSD/OS can use either the block or the char device
160 /* Check if this is a block/char device */
161 if( S_ISBLK( fileinfo
.st_mode
) ||
162 S_ISCHR( fileinfo
.st_mode
) )
173 void _dvdcss_check ( dvdcss_t dvdcss
)
178 #elif defined( DARWIN_DVD_IOCTL )
179 io_object_t next_media
;
180 mach_port_t master_port
;
181 kern_return_t kern_result
;
182 io_iterator_t media_iterator
;
183 CFMutableDictionaryRef classes_to_match
;
184 #elif defined( SYS_OS2 )
207 char *ppsz_devices
[] = { "/dev/dvd", "/dev/cdrom", "/dev/hdc", NULL
};
211 /* If the device name is non-null, return */
212 if( dvdcss
->psz_device
[0] )
218 drives
= GetLogicalDrives();
220 for( i
= 0; drives
; i
++ )
226 if( (drives
& cur
) == 0 )
232 sprintf( psz_device
, "%c:\\", 'A' + i
);
233 i_ret
= GetDriveType( psz_device
);
234 if( i_ret
!= DRIVE_CDROM
)
239 /* Remove trailing backslash */
240 psz_device
[2] = '\0';
242 /* FIXME: we want to differenciate between CD and DVD drives
243 * using DeviceIoControl() */
244 print_debug( dvdcss
, "defaulting to drive `%s'", psz_device
);
245 free( dvdcss
->psz_device
);
246 dvdcss
->psz_device
= strdup( psz_device
);
249 #elif defined( DARWIN_DVD_IOCTL )
251 kern_result
= IOMasterPort( MACH_PORT_NULL
, &master_port
);
252 if( kern_result
!= KERN_SUCCESS
)
257 classes_to_match
= IOServiceMatching( kIODVDMediaClass
);
258 if( classes_to_match
== NULL
)
263 CFDictionarySetValue( classes_to_match
, CFSTR( kIOMediaEjectableKey
),
266 kern_result
= IOServiceGetMatchingServices( master_port
, classes_to_match
,
268 if( kern_result
!= KERN_SUCCESS
)
273 next_media
= IOIteratorNext( media_iterator
);
280 next_media
= IOIteratorNext( media_iterator
);
281 if( next_media
== 0 )
286 psz_path
= IORegistryEntryCreateCFProperty( next_media
,
287 CFSTR( kIOBSDNameKey
),
290 if( psz_path
== NULL
)
292 IOObjectRelease( next_media
);
296 snprintf( psz_buf
, sizeof(psz_buf
), "%s%c", _PATH_DEV
, 'r' );
297 i_pathlen
= strlen( psz_buf
);
299 if( CFStringGetCString( psz_path
,
300 (char*)&psz_buf
+ i_pathlen
,
301 sizeof(psz_buf
) - i_pathlen
,
302 kCFStringEncodingASCII
) )
304 print_debug( dvdcss
, "defaulting to drive `%s'", psz_buf
);
305 CFRelease( psz_path
);
306 IOObjectRelease( next_media
);
307 IOObjectRelease( media_iterator
);
308 free( dvdcss
->psz_device
);
309 dvdcss
->psz_device
= strdup( psz_buf
);
313 CFRelease( psz_path
);
315 IOObjectRelease( next_media
);
318 IOObjectRelease( media_iterator
);
319 #elif defined( SYS_OS2 )
320 for( i
= 0; i
< 26; i
++ )
325 rc
= DosDevIOCtl( ( HFILE
)-1, IOCTL_DISK
, DSK_GETDEVICEPARAMS
,
326 ¶m
, sizeof( param
), &ulParamLen
,
327 &data
, sizeof( data
), &ulDataLen
);
331 /* Check for removable and for cylinders */
332 if( ( data
.usDevAttr
& 1 ) == 0 && data
.usCylinders
== 0xFFFF )
334 char psz_dvd
[] = "A:";
338 print_debug( dvdcss
, "defaulting to drive `%s'", psz_dvd
);
339 free( dvdcss
->psz_device
);
340 dvdcss
->psz_device
= strdup( psz_dvd
);
346 for( i
= 0; ppsz_devices
[i
]; i
++ )
348 i_fd
= open( ppsz_devices
[i
], 0 );
351 print_debug( dvdcss
, "defaulting to drive `%s'", ppsz_devices
[i
] );
353 free( dvdcss
->psz_device
);
354 dvdcss
->psz_device
= strdup( ppsz_devices
[i
] );
360 print_error( dvdcss
, "could not find a suitable default drive" );
363 int _dvdcss_open ( dvdcss_t dvdcss
)
365 char const *psz_device
= dvdcss
->psz_device
;
367 print_debug( dvdcss
, "opening target `%s'", psz_device
);
371 /* If device is "X:" or "X:\", we are not actually opening a file. */
372 if (psz_device
[0] && psz_device
[1] == ':' &&
373 (!psz_device
[2] || (psz_device
[2] == '\\' && !psz_device
[3])))
376 /* Initialize readv temporary buffer */
377 dvdcss
->p_readv_buffer
= NULL
;
378 dvdcss
->i_readv_buf_size
= 0;
380 if( !dvdcss
->b_file
&& WIN2K
)
382 print_debug( dvdcss
, "using Win2K API for access" );
383 dvdcss
->pf_seek
= win2k_seek
;
384 dvdcss
->pf_read
= win2k_read
;
385 dvdcss
->pf_readv
= win_readv
;
386 return win2k_open( dvdcss
, psz_device
);
388 else if( !dvdcss
->b_file
)
390 print_debug( dvdcss
, "using ASPI for access" );
391 dvdcss
->pf_seek
= aspi_seek
;
392 dvdcss
->pf_read
= aspi_read
;
393 dvdcss
->pf_readv
= win_readv
;
394 return aspi_open( dvdcss
, psz_device
);
397 #elif defined( SYS_OS2 )
398 /* If device is "X:" or "X:\", we are not actually opening a file. */
399 if( psz_device
[0] && psz_device
[1] == ':' &&
400 ( !psz_device
[2] || ( psz_device
[2] == '\\' && !psz_device
[3] ) ) )
402 print_debug( dvdcss
, "using OS2 API for access" );
403 dvdcss
->pf_seek
= os2_seek
;
404 dvdcss
->pf_read
= os2_read
;
405 dvdcss
->pf_readv
= os2_readv
;
406 return os2_open( dvdcss
, psz_device
);
411 print_debug( dvdcss
, "using libc for access" );
412 dvdcss
->pf_seek
= libc_seek
;
413 dvdcss
->pf_read
= libc_read
;
414 dvdcss
->pf_readv
= libc_readv
;
415 return libc_open( dvdcss
, psz_device
);
419 #if !defined(WIN32) && !defined(SYS_OS2)
420 int _dvdcss_raw_open ( dvdcss_t dvdcss
, char const *psz_device
)
422 dvdcss
->i_raw_fd
= open( psz_device
, 0 );
424 if( dvdcss
->i_raw_fd
== -1 )
426 print_debug( dvdcss
, "cannot open %s (%s)",
427 psz_device
, strerror(errno
) );
428 print_error( dvdcss
, "failed to open raw device, but continuing" );
433 dvdcss
->i_read_fd
= dvdcss
->i_raw_fd
;
440 int _dvdcss_close ( dvdcss_t dvdcss
)
445 close( dvdcss
->i_fd
);
449 CloseHandle( (HANDLE
) dvdcss
->i_fd
);
453 struct w32_aspidev
*fd
= (struct w32_aspidev
*) dvdcss
->i_fd
;
455 /* Unload aspi and free w32_aspidev structure */
456 FreeLibrary( (HMODULE
) fd
->hASPI
);
457 free( (void*) dvdcss
->i_fd
);
460 /* Free readv temporary buffer */
461 if( dvdcss
->p_readv_buffer
)
463 free( dvdcss
->p_readv_buffer
);
464 dvdcss
->p_readv_buffer
= NULL
;
465 dvdcss
->i_readv_buf_size
= 0;
470 close( dvdcss
->i_fd
);
473 if( dvdcss
->i_raw_fd
>= 0 )
475 close( dvdcss
->i_raw_fd
);
476 dvdcss
->i_raw_fd
= -1;
484 /* Following functions are local */
486 /*****************************************************************************
488 *****************************************************************************/
489 static int libc_open ( dvdcss_t dvdcss
, char const *psz_device
)
491 #if !defined( WIN32 ) && !defined( SYS_OS2 )
492 dvdcss
->i_fd
= dvdcss
->i_read_fd
= open( psz_device
, 0 );
494 dvdcss
->i_fd
= dvdcss
->i_read_fd
= open( psz_device
, O_BINARY
);
497 if( dvdcss
->i_fd
== -1 )
499 print_debug( dvdcss
, "cannot open %s (%s)",
500 psz_device
, strerror(errno
) );
501 print_error( dvdcss
, "failed to open device" );
511 static int win2k_open ( dvdcss_t dvdcss
, char const *psz_device
)
514 _snprintf( psz_dvd
, 7, "\\\\.\\%c:", psz_device
[0] );
516 /* To work around an M$ bug in IOCTL_DVD_READ_STRUCTURE, we need read
517 * _and_ write access to the device (so we can make SCSI Pass Through
518 * Requests). Unfortunately this is only allowed if you have
519 * administrator priviledges so we allow for a fallback method with
520 * only read access to the device (in this case ioctl_ReadCopyright()
521 * won't send back the right result).
522 * (See Microsoft Q241374: Read and Write Access Required for SCSI
523 * Pass Through Requests) */
525 CreateFile( psz_dvd
, GENERIC_READ
| GENERIC_WRITE
,
526 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
528 FILE_FLAG_RANDOM_ACCESS
, NULL
);
530 if( (HANDLE
) dvdcss
->i_fd
== INVALID_HANDLE_VALUE
)
532 CreateFile( psz_dvd
, GENERIC_READ
, FILE_SHARE_READ
,
534 FILE_FLAG_RANDOM_ACCESS
, NULL
);
536 if( (HANDLE
) dvdcss
->i_fd
== INVALID_HANDLE_VALUE
)
538 print_error( dvdcss
, "failed opening device" );
547 static int aspi_open( dvdcss_t dvdcss
, char const * psz_device
)
551 struct w32_aspidev
*fd
;
552 int i
, j
, i_hostadapters
;
553 GETASPI32SUPPORTINFO lpGetSupport
;
554 SENDASPI32COMMAND lpSendCommand
;
555 char c_drive
= psz_device
[0];
557 /* load aspi and init w32_aspidev structure */
558 hASPI
= LoadLibrary( "wnaspi32.dll" );
561 print_error( dvdcss
, "unable to load wnaspi32.dll" );
565 lpGetSupport
= (GETASPI32SUPPORTINFO
) GetProcAddress( hASPI
, "GetASPI32SupportInfo" );
566 lpSendCommand
= (SENDASPI32COMMAND
) GetProcAddress( hASPI
, "SendASPI32Command" );
568 if(lpGetSupport
== NULL
|| lpSendCommand
== NULL
)
570 print_error( dvdcss
, "unable to get aspi function pointers" );
571 FreeLibrary( hASPI
);
575 dwSupportInfo
= lpGetSupport();
577 if( HIBYTE( LOWORD ( dwSupportInfo
) ) == SS_NO_ADAPTERS
)
579 print_error( dvdcss
, "no ASPI adapters found" );
580 FreeLibrary( hASPI
);
584 if( HIBYTE( LOWORD ( dwSupportInfo
) ) != SS_COMP
)
586 print_error( dvdcss
, "unable to initalize aspi layer" );
587 FreeLibrary( hASPI
);
591 i_hostadapters
= LOBYTE( LOWORD( dwSupportInfo
) );
592 if( i_hostadapters
== 0 )
594 print_error( dvdcss
, "no ASPI adapters ready" );
595 FreeLibrary( hASPI
);
599 fd
= malloc( sizeof( struct w32_aspidev
) );
602 print_error( dvdcss
, "not enough memory" );
603 FreeLibrary( hASPI
);
608 fd
->hASPI
= (long) hASPI
;
609 fd
->lpSendCommand
= lpSendCommand
;
611 c_drive
= c_drive
> 'Z' ? c_drive
- 'a' : c_drive
- 'A';
613 for( i
= 0; i
< i_hostadapters
; i
++ )
615 for( j
= 0; j
< 15; j
++ )
617 struct SRB_GetDiskInfo srbDiskInfo
;
619 srbDiskInfo
.SRB_Cmd
= SC_GET_DISK_INFO
;
620 srbDiskInfo
.SRB_HaId
= i
;
621 srbDiskInfo
.SRB_Flags
= 0;
622 srbDiskInfo
.SRB_Hdr_Rsvd
= 0;
623 srbDiskInfo
.SRB_Target
= j
;
624 srbDiskInfo
.SRB_Lun
= 0;
626 lpSendCommand( (void*) &srbDiskInfo
);
628 if( (srbDiskInfo
.SRB_Status
== SS_COMP
) &&
629 (srbDiskInfo
.SRB_Int13HDriveInfo
== c_drive
) )
631 /* Make sure this is a cdrom device */
632 struct SRB_GDEVBlock srbGDEVBlock
;
634 memset( &srbGDEVBlock
, 0, sizeof(struct SRB_GDEVBlock
) );
635 srbGDEVBlock
.SRB_Cmd
= SC_GET_DEV_TYPE
;
636 srbGDEVBlock
.SRB_HaId
= i
;
637 srbGDEVBlock
.SRB_Target
= j
;
639 lpSendCommand( (void*) &srbGDEVBlock
);
641 if( ( srbGDEVBlock
.SRB_Status
== SS_COMP
) &&
642 ( srbGDEVBlock
.SRB_DeviceType
== DTYPE_CDROM
) )
644 fd
->i_sid
= MAKEWORD( i
, j
);
645 dvdcss
->i_fd
= (int) fd
;
652 FreeLibrary( hASPI
);
653 print_error( dvdcss
,"this is not a cdrom drive" );
661 FreeLibrary( hASPI
);
662 print_error( dvdcss
, "unable to get haid and target (aspi)" );
668 static int os2_open ( dvdcss_t dvdcss
, char const *psz_device
)
670 char psz_dvd
[] = "X:";
675 psz_dvd
[0] = psz_device
[0];
677 rc
= DosOpenL( ( PSZ
)psz_dvd
, &hfile
, &ulAction
, 0, FILE_NORMAL
,
678 OPEN_ACTION_OPEN_IF_EXISTS
| OPEN_ACTION_FAIL_IF_NEW
,
679 OPEN_ACCESS_READONLY
| OPEN_SHARE_DENYNONE
| OPEN_FLAGS_DASD
,
684 print_error( dvdcss
, "failed to open device" );
688 setmode( hfile
, O_BINARY
);
690 dvdcss
->i_fd
= dvdcss
->i_read_fd
= hfile
;
698 /*****************************************************************************
700 *****************************************************************************/
701 static int libc_seek( dvdcss_t dvdcss
, int i_blocks
)
705 if( dvdcss
->i_pos
== i_blocks
)
707 /* We are already in position */
711 i_seek
= (off_t
)i_blocks
* (off_t
)DVDCSS_BLOCK_SIZE
;
712 i_seek
= lseek( dvdcss
->i_read_fd
, i_seek
, SEEK_SET
);
716 print_error( dvdcss
, "seek error" );
721 dvdcss
->i_pos
= i_seek
/ DVDCSS_BLOCK_SIZE
;
723 return dvdcss
->i_pos
;
727 static int win2k_seek( dvdcss_t dvdcss
, int i_blocks
)
729 LARGE_INTEGER li_seek
;
731 #ifndef INVALID_SET_FILE_POINTER
732 # define INVALID_SET_FILE_POINTER ((DWORD)-1)
735 if( dvdcss
->i_pos
== i_blocks
)
737 /* We are already in position */
741 li_seek
.QuadPart
= (LONGLONG
)i_blocks
* DVDCSS_BLOCK_SIZE
;
743 li_seek
.LowPart
= SetFilePointer( (HANDLE
) dvdcss
->i_fd
,
745 &li_seek
.HighPart
, FILE_BEGIN
);
746 if( (li_seek
.LowPart
== INVALID_SET_FILE_POINTER
)
747 && GetLastError() != NO_ERROR
)
753 dvdcss
->i_pos
= li_seek
.QuadPart
/ DVDCSS_BLOCK_SIZE
;
755 return dvdcss
->i_pos
;
758 static int aspi_seek( dvdcss_t dvdcss
, int i_blocks
)
761 char sz_buf
[ DVDCSS_BLOCK_SIZE
];
762 struct w32_aspidev
*fd
= (struct w32_aspidev
*) dvdcss
->i_fd
;
764 if( dvdcss
->i_pos
== i_blocks
)
766 /* We are already in position */
770 i_old_blocks
= fd
->i_blocks
;
771 fd
->i_blocks
= i_blocks
;
773 if( aspi_read_internal( dvdcss
->i_fd
, sz_buf
, 1 ) == -1 )
775 fd
->i_blocks
= i_old_blocks
;
782 dvdcss
->i_pos
= fd
->i_blocks
;
784 return dvdcss
->i_pos
;
788 /*****************************************************************************
790 *****************************************************************************/
791 static int libc_read ( dvdcss_t dvdcss
, void *p_buffer
, int i_blocks
)
795 i_size
= (off_t
)i_blocks
* (off_t
)DVDCSS_BLOCK_SIZE
;
796 i_ret
= read( dvdcss
->i_read_fd
, p_buffer
, i_size
);
800 print_error( dvdcss
, "read error" );
805 /* Handle partial reads */
806 if( i_ret
!= i_size
)
811 i_seek
= libc_seek( dvdcss
, i_ret
/ DVDCSS_BLOCK_SIZE
);
817 /* We have to return now so that i_pos isn't clobbered */
818 return i_ret
/ DVDCSS_BLOCK_SIZE
;
821 dvdcss
->i_pos
+= i_ret
/ DVDCSS_BLOCK_SIZE
;
822 return i_ret
/ DVDCSS_BLOCK_SIZE
;
826 static int win2k_read ( dvdcss_t dvdcss
, void *p_buffer
, int i_blocks
)
830 if( !ReadFile( (HANDLE
) dvdcss
->i_fd
, p_buffer
,
831 i_blocks
* DVDCSS_BLOCK_SIZE
,
832 (LPDWORD
)&i_bytes
, NULL
) )
838 dvdcss
->i_pos
+= i_bytes
/ DVDCSS_BLOCK_SIZE
;
839 return i_bytes
/ DVDCSS_BLOCK_SIZE
;
842 static int aspi_read ( dvdcss_t dvdcss
, void *p_buffer
, int i_blocks
)
844 int i_read
= aspi_read_internal( dvdcss
->i_fd
, p_buffer
, i_blocks
);
852 dvdcss
->i_pos
+= i_read
;
857 /*****************************************************************************
859 *****************************************************************************/
860 static int libc_readv ( dvdcss_t dvdcss
, struct iovec
*p_iovec
, int i_blocks
)
863 int i_index
, i_len
, i_total
= 0;
864 unsigned char *p_base
;
867 for( i_index
= i_blocks
;
869 i_index
--, p_iovec
++ )
871 i_len
= p_iovec
->iov_len
;
872 p_base
= p_iovec
->iov_base
;
879 i_bytes
= read( dvdcss
->i_fd
, p_base
, i_len
);
883 /* One of the reads failed, too bad.
884 * We won't even bother returning the reads that went ok,
885 * and as in the posix spec the file postition is left
886 * unspecified after a failure */
893 if( i_bytes
!= i_len
)
895 /* We reached the end of the file or a signal interrupted
896 * the read. Return a partial read. */
900 i_seek
= libc_seek( dvdcss
, i_total
/ DVDCSS_BLOCK_SIZE
);
906 /* We have to return now so that i_pos isn't clobbered */
907 return i_total
/ DVDCSS_BLOCK_SIZE
;
911 dvdcss
->i_pos
+= i_total
/ DVDCSS_BLOCK_SIZE
;
912 return i_total
/ DVDCSS_BLOCK_SIZE
;
914 int i_read
= readv( dvdcss
->i_read_fd
, p_iovec
, i_blocks
);
922 dvdcss
->i_pos
+= i_read
/ DVDCSS_BLOCK_SIZE
;
923 return i_read
/ DVDCSS_BLOCK_SIZE
;
928 /*****************************************************************************
929 * win_readv: vectored read using ReadFile for Win2K and ASPI for win9x
930 *****************************************************************************/
931 static int win_readv ( dvdcss_t dvdcss
, struct iovec
*p_iovec
, int i_blocks
)
934 int i_blocks_read
, i_blocks_total
= 0;
936 /* Check the size of the readv temp buffer, just in case we need to
937 * realloc something bigger */
938 if( dvdcss
->i_readv_buf_size
< i_blocks
* DVDCSS_BLOCK_SIZE
)
940 dvdcss
->i_readv_buf_size
= i_blocks
* DVDCSS_BLOCK_SIZE
;
942 if( dvdcss
->p_readv_buffer
) free( dvdcss
->p_readv_buffer
);
944 /* Allocate a buffer which will be used as a temporary storage
946 dvdcss
->p_readv_buffer
= malloc( dvdcss
->i_readv_buf_size
);
947 if( !dvdcss
->p_readv_buffer
)
949 print_error( dvdcss
, " failed (readv)" );
955 for( i_index
= i_blocks
; i_index
; i_index
-- )
957 i_blocks_total
+= p_iovec
[i_index
-1].iov_len
;
960 if( i_blocks_total
<= 0 ) return 0;
962 i_blocks_total
/= DVDCSS_BLOCK_SIZE
;
966 unsigned long int i_bytes
;
967 if( !ReadFile( (HANDLE
)dvdcss
->i_fd
, dvdcss
->p_readv_buffer
,
968 i_blocks_total
* DVDCSS_BLOCK_SIZE
, &i_bytes
, NULL
) )
970 /* The read failed... too bad.
971 * As in the posix spec the file postition is left
972 * unspecified after a failure */
976 i_blocks_read
= i_bytes
/ DVDCSS_BLOCK_SIZE
;
980 i_blocks_read
= aspi_read_internal( dvdcss
->i_fd
,
981 dvdcss
->p_readv_buffer
,
983 if( i_blocks_read
< 0 )
991 /* We just have to copy the content of the temp buffer into the iovecs */
992 for( i_index
= 0, i_blocks_total
= i_blocks_read
;
996 memcpy( p_iovec
[i_index
].iov_base
,
997 dvdcss
->p_readv_buffer
+ (i_blocks_read
- i_blocks_total
)
999 p_iovec
[i_index
].iov_len
);
1000 /* if we read less blocks than asked, we'll just end up copying
1001 * garbage, this isn't an issue as we return the number of
1002 * blocks actually read */
1003 i_blocks_total
-= ( p_iovec
[i_index
].iov_len
/ DVDCSS_BLOCK_SIZE
);
1006 dvdcss
->i_pos
+= i_blocks_read
;
1007 return i_blocks_read
;
1010 static int aspi_read_internal( int i_fd
, void *p_data
, int i_blocks
)
1013 struct SRB_ExecSCSICmd ssc
;
1014 struct w32_aspidev
*fd
= (struct w32_aspidev
*) i_fd
;
1016 /* Create the transfer completion event */
1017 hEvent
= CreateEvent( NULL
, TRUE
, FALSE
, NULL
);
1018 if( hEvent
== NULL
)
1023 memset( &ssc
, 0, sizeof( ssc
) );
1025 ssc
.SRB_Cmd
= SC_EXEC_SCSI_CMD
;
1026 ssc
.SRB_Flags
= SRB_DIR_IN
| SRB_EVENT_NOTIFY
;
1027 ssc
.SRB_HaId
= LOBYTE( fd
->i_sid
);
1028 ssc
.SRB_Target
= HIBYTE( fd
->i_sid
);
1029 ssc
.SRB_SenseLen
= SENSE_LEN
;
1031 ssc
.SRB_PostProc
= (LPVOID
) hEvent
;
1032 ssc
.SRB_BufPointer
= p_data
;
1033 ssc
.SRB_CDBLen
= 12;
1035 ssc
.CDBByte
[0] = 0xA8; /* RAW */
1036 ssc
.CDBByte
[2] = (UCHAR
) (fd
->i_blocks
>> 24);
1037 ssc
.CDBByte
[3] = (UCHAR
) (fd
->i_blocks
>> 16) & 0xff;
1038 ssc
.CDBByte
[4] = (UCHAR
) (fd
->i_blocks
>> 8) & 0xff;
1039 ssc
.CDBByte
[5] = (UCHAR
) (fd
->i_blocks
) & 0xff;
1041 /* We have to break down the reads into 64kb pieces (ASPI restriction) */
1044 ssc
.SRB_BufLen
= 32 * DVDCSS_BLOCK_SIZE
;
1045 ssc
.CDBByte
[9] = 32;
1048 /* Initiate transfer */
1049 ResetEvent( hEvent
);
1050 fd
->lpSendCommand( (void*) &ssc
);
1052 /* transfer the next 64kb (aspi_read_internal is called recursively)
1053 * We need to check the status of the read on return */
1054 if( aspi_read_internal( i_fd
,
1055 (uint8_t*) p_data
+ 32 * DVDCSS_BLOCK_SIZE
,
1056 i_blocks
- 32) < 0 )
1063 /* This is the last transfer */
1064 ssc
.SRB_BufLen
= i_blocks
* DVDCSS_BLOCK_SIZE
;
1065 ssc
.CDBByte
[9] = (UCHAR
) i_blocks
;
1066 fd
->i_blocks
+= i_blocks
;
1068 /* Initiate transfer */
1069 ResetEvent( hEvent
);
1070 fd
->lpSendCommand( (void*) &ssc
);
1074 /* If the command has still not been processed, wait until it's finished */
1075 if( ssc
.SRB_Status
== SS_PENDING
)
1077 WaitForSingleObject( hEvent
, INFINITE
);
1079 CloseHandle( hEvent
);
1081 /* check that the transfer went as planned */
1082 if( ssc
.SRB_Status
!= SS_COMP
)