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 program 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 program 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
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, 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>
68 #include "dvdcss/dvdcss.h"
72 #include "libdvdcss.h"
76 /*****************************************************************************
77 * Device reading prototypes
78 *****************************************************************************/
79 static int libc_open ( dvdcss_t
, char const * );
80 static int libc_seek ( dvdcss_t
, int );
81 static int libc_read ( dvdcss_t
, void *, int );
82 static int libc_readv ( dvdcss_t
, struct iovec
*, int );
85 static int win2k_open ( dvdcss_t
, char const * );
86 static int aspi_open ( dvdcss_t
, char const * );
87 static int win2k_seek ( dvdcss_t
, int );
88 static int aspi_seek ( dvdcss_t
, int );
89 static int win2k_read ( dvdcss_t
, void *, int );
90 static int aspi_read ( dvdcss_t
, void *, int );
91 static int win_readv ( dvdcss_t
, struct iovec
*, int );
93 static int aspi_read_internal ( int, void *, int );
96 int _dvdcss_use_ioctls( dvdcss_t dvdcss
)
104 /* FIXME: implement this for Windows */
114 struct stat fileinfo
;
117 ret
= fstat( dvdcss
->i_fd
, &fileinfo
);
120 return 1; /* What to do? Be conservative and try to use the ioctls */
123 /* Complete this list and check that we test for the right things
124 * (I've assumed for all OSs that 'r', (raw) device, are char devices
125 * and those that don't contain/use an 'r' in the name are block devices)
127 * Linux needs a block device
128 * Solaris needs a char device
129 * Darwin needs a char device
130 * OpenBSD needs a char device
131 * NetBSD needs a char device
132 * FreeBSD can use either the block or the char device
133 * BSD/OS can use either the block or the char device
136 /* Check if this is a block/char device */
137 if( S_ISBLK( fileinfo
.st_mode
) ||
138 S_ISCHR( fileinfo
.st_mode
) )
149 void _dvdcss_check ( dvdcss_t dvdcss
)
154 #elif defined( DARWIN_DVD_IOCTL )
155 io_object_t next_media
;
156 mach_port_t master_port
;
157 kern_return_t kern_result
;
158 io_iterator_t media_iterator
;
159 CFMutableDictionaryRef classes_to_match
;
161 char *ppsz_devices
[] = { "/dev/dvd", "/dev/cdrom", "/dev/hdc", NULL
};
165 /* If the device name is non-null, return */
166 if( dvdcss
->psz_device
[0] )
172 drives
= GetLogicalDrives();
174 for( i
= 0; drives
; i
++ )
180 if( (drives
& cur
) == 0 )
186 sprintf( psz_device
, "%c:\\", 'A' + i
);
187 i_ret
= GetDriveType( psz_device
);
188 if( i_ret
!= DRIVE_CDROM
)
193 /* Remove trailing backslash */
194 psz_device
[2] = '\0';
196 /* FIXME: we want to differenciate between CD and DVD drives
197 * using DeviceIoControl() */
198 print_debug( dvdcss
, "defaulting to drive `%s'", psz_device
);
199 free( dvdcss
->psz_device
);
200 dvdcss
->psz_device
= strdup( psz_device
);
203 #elif defined( DARWIN_DVD_IOCTL )
205 kern_result
= IOMasterPort( MACH_PORT_NULL
, &master_port
);
206 if( kern_result
!= KERN_SUCCESS
)
211 classes_to_match
= IOServiceMatching( kIODVDMediaClass
);
212 if( classes_to_match
== NULL
)
217 CFDictionarySetValue( classes_to_match
, CFSTR( kIOMediaEjectableKey
),
220 kern_result
= IOServiceGetMatchingServices( master_port
, classes_to_match
,
222 if( kern_result
!= KERN_SUCCESS
)
227 next_media
= IOIteratorNext( media_iterator
);
234 next_media
= IOIteratorNext( media_iterator
);
235 if( next_media
== 0 )
240 psz_path
= IORegistryEntryCreateCFProperty( next_media
,
241 CFSTR( kIOBSDNameKey
),
244 if( psz_path
== NULL
)
246 IOObjectRelease( next_media
);
250 snprintf( psz_buf
, sizeof(psz_buf
), "%s%c", _PATH_DEV
, 'r' );
251 i_pathlen
= strlen( psz_buf
);
253 if( CFStringGetCString( psz_path
,
254 (char*)&psz_buf
+ i_pathlen
,
255 sizeof(psz_buf
) - i_pathlen
,
256 kCFStringEncodingASCII
) )
258 print_debug( dvdcss
, "defaulting to drive `%s'", psz_buf
);
259 CFRelease( psz_path
);
260 IOObjectRelease( next_media
);
261 IOObjectRelease( media_iterator
);
262 free( dvdcss
->psz_device
);
263 dvdcss
->psz_device
= strdup( psz_buf
);
267 CFRelease( psz_path
);
269 IOObjectRelease( next_media
);
272 IOObjectRelease( media_iterator
);
274 for( i
= 0; ppsz_devices
[i
]; i
++ )
276 i_fd
= open( ppsz_devices
[i
], 0 );
279 print_debug( dvdcss
, "defaulting to drive `%s'", ppsz_devices
[i
] );
281 free( dvdcss
->psz_device
);
282 dvdcss
->psz_device
= strdup( ppsz_devices
[i
] );
288 print_error( dvdcss
, "could not find a suitable default drive" );
291 int _dvdcss_open ( dvdcss_t dvdcss
)
293 char const *psz_device
= dvdcss
->psz_device
;
295 print_debug( dvdcss
, "opening target `%s'", psz_device
);
299 /* If device is "X:" or "X:\", we are not actually opening a file. */
300 if (psz_device
[0] && psz_device
[1] == ':' &&
301 (!psz_device
[2] || (psz_device
[2] == '\\' && !psz_device
[3])))
304 /* Initialize readv temporary buffer */
305 dvdcss
->p_readv_buffer
= NULL
;
306 dvdcss
->i_readv_buf_size
= 0;
308 if( !dvdcss
->b_file
&& WIN2K
)
310 print_debug( dvdcss
, "using Win2K API for access" );
311 dvdcss
->pf_seek
= win2k_seek
;
312 dvdcss
->pf_read
= win2k_read
;
313 dvdcss
->pf_readv
= win_readv
;
314 return win2k_open( dvdcss
, psz_device
);
316 else if( !dvdcss
->b_file
)
318 print_debug( dvdcss
, "using ASPI for access" );
319 dvdcss
->pf_seek
= aspi_seek
;
320 dvdcss
->pf_read
= aspi_read
;
321 dvdcss
->pf_readv
= win_readv
;
322 return aspi_open( dvdcss
, psz_device
);
327 print_debug( dvdcss
, "using libc for access" );
328 dvdcss
->pf_seek
= libc_seek
;
329 dvdcss
->pf_read
= libc_read
;
330 dvdcss
->pf_readv
= libc_readv
;
331 return libc_open( dvdcss
, psz_device
);
336 int _dvdcss_raw_open ( dvdcss_t dvdcss
, char const *psz_device
)
338 dvdcss
->i_raw_fd
= open( psz_device
, 0 );
340 if( dvdcss
->i_raw_fd
== -1 )
342 print_debug( dvdcss
, "cannot open %s (%s)",
343 psz_device
, strerror(errno
) );
344 print_error( dvdcss
, "failed to open raw device, but continuing" );
349 dvdcss
->i_read_fd
= dvdcss
->i_raw_fd
;
356 int _dvdcss_close ( dvdcss_t dvdcss
)
361 close( dvdcss
->i_fd
);
365 CloseHandle( (HANDLE
) dvdcss
->i_fd
);
369 struct w32_aspidev
*fd
= (struct w32_aspidev
*) dvdcss
->i_fd
;
371 /* Unload aspi and free w32_aspidev structure */
372 FreeLibrary( (HMODULE
) fd
->hASPI
);
373 free( (void*) dvdcss
->i_fd
);
376 /* Free readv temporary buffer */
377 if( dvdcss
->p_readv_buffer
)
379 free( dvdcss
->p_readv_buffer
);
380 dvdcss
->p_readv_buffer
= NULL
;
381 dvdcss
->i_readv_buf_size
= 0;
386 close( dvdcss
->i_fd
);
388 if( dvdcss
->i_raw_fd
>= 0 )
390 close( dvdcss
->i_raw_fd
);
391 dvdcss
->i_raw_fd
= -1;
398 /* Following functions are local */
400 /*****************************************************************************
402 *****************************************************************************/
403 static int libc_open ( dvdcss_t dvdcss
, char const *psz_device
)
405 #if !defined( WIN32 )
406 dvdcss
->i_fd
= dvdcss
->i_read_fd
= open( psz_device
, 0 );
408 dvdcss
->i_fd
= dvdcss
->i_read_fd
= open( psz_device
, O_BINARY
);
411 if( dvdcss
->i_fd
== -1 )
413 print_debug( dvdcss
, "cannot open %s (%s)",
414 psz_device
, strerror(errno
) );
415 print_error( dvdcss
, "failed to open device" );
425 static int win2k_open ( dvdcss_t dvdcss
, char const *psz_device
)
428 _snprintf( psz_dvd
, 7, "\\\\.\\%c:", psz_device
[0] );
430 /* To work around an M$ bug in IOCTL_DVD_READ_STRUCTURE, we need read
431 * _and_ write access to the device (so we can make SCSI Pass Through
432 * Requests). Unfortunately this is only allowed if you have
433 * administrator priviledges so we allow for a fallback method with
434 * only read access to the device (in this case ioctl_ReadCopyright()
435 * won't send back the right result).
436 * (See Microsoft Q241374: Read and Write Access Required for SCSI
437 * Pass Through Requests) */
439 CreateFile( psz_dvd
, GENERIC_READ
| GENERIC_WRITE
,
440 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
442 FILE_FLAG_RANDOM_ACCESS
, NULL
);
444 if( (HANDLE
) dvdcss
->i_fd
== INVALID_HANDLE_VALUE
)
446 CreateFile( psz_dvd
, GENERIC_READ
, FILE_SHARE_READ
,
448 FILE_FLAG_RANDOM_ACCESS
, NULL
);
450 if( (HANDLE
) dvdcss
->i_fd
== INVALID_HANDLE_VALUE
)
452 print_error( dvdcss
, "failed opening device" );
461 static int aspi_open( dvdcss_t dvdcss
, char const * psz_device
)
465 struct w32_aspidev
*fd
;
466 int i
, j
, i_hostadapters
;
467 GETASPI32SUPPORTINFO lpGetSupport
;
468 SENDASPI32COMMAND lpSendCommand
;
469 char c_drive
= psz_device
[0];
471 /* load aspi and init w32_aspidev structure */
472 hASPI
= LoadLibrary( "wnaspi32.dll" );
475 print_error( dvdcss
, "unable to load wnaspi32.dll" );
479 lpGetSupport
= (GETASPI32SUPPORTINFO
) GetProcAddress( hASPI
, "GetASPI32SupportInfo" );
480 lpSendCommand
= (SENDASPI32COMMAND
) GetProcAddress( hASPI
, "SendASPI32Command" );
482 if(lpGetSupport
== NULL
|| lpSendCommand
== NULL
)
484 print_error( dvdcss
, "unable to get aspi function pointers" );
485 FreeLibrary( hASPI
);
489 dwSupportInfo
= lpGetSupport();
491 if( HIBYTE( LOWORD ( dwSupportInfo
) ) == SS_NO_ADAPTERS
)
493 print_error( dvdcss
, "no ASPI adapters found" );
494 FreeLibrary( hASPI
);
498 if( HIBYTE( LOWORD ( dwSupportInfo
) ) != SS_COMP
)
500 print_error( dvdcss
, "unable to initalize aspi layer" );
501 FreeLibrary( hASPI
);
505 i_hostadapters
= LOBYTE( LOWORD( dwSupportInfo
) );
506 if( i_hostadapters
== 0 )
508 print_error( dvdcss
, "no ASPI adapters ready" );
509 FreeLibrary( hASPI
);
513 fd
= malloc( sizeof( struct w32_aspidev
) );
516 print_error( dvdcss
, "not enough memory" );
517 FreeLibrary( hASPI
);
522 fd
->hASPI
= (long) hASPI
;
523 fd
->lpSendCommand
= lpSendCommand
;
525 c_drive
= c_drive
> 'Z' ? c_drive
- 'a' : c_drive
- 'A';
527 for( i
= 0; i
< i_hostadapters
; i
++ )
529 for( j
= 0; j
< 15; j
++ )
531 struct SRB_GetDiskInfo srbDiskInfo
;
533 srbDiskInfo
.SRB_Cmd
= SC_GET_DISK_INFO
;
534 srbDiskInfo
.SRB_HaId
= i
;
535 srbDiskInfo
.SRB_Flags
= 0;
536 srbDiskInfo
.SRB_Hdr_Rsvd
= 0;
537 srbDiskInfo
.SRB_Target
= j
;
538 srbDiskInfo
.SRB_Lun
= 0;
540 lpSendCommand( (void*) &srbDiskInfo
);
542 if( (srbDiskInfo
.SRB_Status
== SS_COMP
) &&
543 (srbDiskInfo
.SRB_Int13HDriveInfo
== c_drive
) )
545 /* Make sure this is a cdrom device */
546 struct SRB_GDEVBlock srbGDEVBlock
;
548 memset( &srbGDEVBlock
, 0, sizeof(struct SRB_GDEVBlock
) );
549 srbGDEVBlock
.SRB_Cmd
= SC_GET_DEV_TYPE
;
550 srbGDEVBlock
.SRB_HaId
= i
;
551 srbGDEVBlock
.SRB_Target
= j
;
553 lpSendCommand( (void*) &srbGDEVBlock
);
555 if( ( srbGDEVBlock
.SRB_Status
== SS_COMP
) &&
556 ( srbGDEVBlock
.SRB_DeviceType
== DTYPE_CDROM
) )
558 fd
->i_sid
= MAKEWORD( i
, j
);
559 dvdcss
->i_fd
= (int) fd
;
566 FreeLibrary( hASPI
);
567 print_error( dvdcss
,"this is not a cdrom drive" );
575 FreeLibrary( hASPI
);
576 print_error( dvdcss
, "unable to get haid and target (aspi)" );
581 /*****************************************************************************
583 *****************************************************************************/
584 static int libc_seek( dvdcss_t dvdcss
, int i_blocks
)
588 if( dvdcss
->i_pos
== i_blocks
)
590 /* We are already in position */
594 i_seek
= (off_t
)i_blocks
* (off_t
)DVDCSS_BLOCK_SIZE
;
595 i_seek
= lseek( dvdcss
->i_read_fd
, i_seek
, SEEK_SET
);
599 print_error( dvdcss
, "seek error" );
604 dvdcss
->i_pos
= i_seek
/ DVDCSS_BLOCK_SIZE
;
606 return dvdcss
->i_pos
;
610 static int win2k_seek( dvdcss_t dvdcss
, int i_blocks
)
612 LARGE_INTEGER li_seek
;
614 #ifndef INVALID_SET_FILE_POINTER
615 # define INVALID_SET_FILE_POINTER ((DWORD)-1)
618 if( dvdcss
->i_pos
== i_blocks
)
620 /* We are already in position */
624 li_seek
.QuadPart
= (LONGLONG
)i_blocks
* DVDCSS_BLOCK_SIZE
;
626 li_seek
.LowPart
= SetFilePointer( (HANDLE
) dvdcss
->i_fd
,
628 &li_seek
.HighPart
, FILE_BEGIN
);
629 if( (li_seek
.LowPart
== INVALID_SET_FILE_POINTER
)
630 && GetLastError() != NO_ERROR
)
636 dvdcss
->i_pos
= li_seek
.QuadPart
/ DVDCSS_BLOCK_SIZE
;
638 return dvdcss
->i_pos
;
641 static int aspi_seek( dvdcss_t dvdcss
, int i_blocks
)
644 char sz_buf
[ DVDCSS_BLOCK_SIZE
];
645 struct w32_aspidev
*fd
= (struct w32_aspidev
*) dvdcss
->i_fd
;
647 if( dvdcss
->i_pos
== i_blocks
)
649 /* We are already in position */
653 i_old_blocks
= fd
->i_blocks
;
654 fd
->i_blocks
= i_blocks
;
656 if( aspi_read_internal( dvdcss
->i_fd
, sz_buf
, 1 ) == -1 )
658 fd
->i_blocks
= i_old_blocks
;
665 dvdcss
->i_pos
= fd
->i_blocks
;
667 return dvdcss
->i_pos
;
671 /*****************************************************************************
673 *****************************************************************************/
674 static int libc_read ( dvdcss_t dvdcss
, void *p_buffer
, int i_blocks
)
678 i_size
= (off_t
)i_blocks
* (off_t
)DVDCSS_BLOCK_SIZE
;
679 i_ret
= read( dvdcss
->i_read_fd
, p_buffer
, i_size
);
683 print_error( dvdcss
, "read error" );
688 /* Handle partial reads */
689 if( i_ret
!= i_size
)
694 i_seek
= libc_seek( dvdcss
, i_ret
/ DVDCSS_BLOCK_SIZE
);
700 /* We have to return now so that i_pos isn't clobbered */
701 return i_ret
/ DVDCSS_BLOCK_SIZE
;
704 dvdcss
->i_pos
+= i_ret
/ DVDCSS_BLOCK_SIZE
;
705 return i_ret
/ DVDCSS_BLOCK_SIZE
;
709 static int win2k_read ( dvdcss_t dvdcss
, void *p_buffer
, int i_blocks
)
713 if( !ReadFile( (HANDLE
) dvdcss
->i_fd
, p_buffer
,
714 i_blocks
* DVDCSS_BLOCK_SIZE
,
715 (LPDWORD
)&i_bytes
, NULL
) )
721 dvdcss
->i_pos
+= i_bytes
/ DVDCSS_BLOCK_SIZE
;
722 return i_bytes
/ DVDCSS_BLOCK_SIZE
;
725 static int aspi_read ( dvdcss_t dvdcss
, void *p_buffer
, int i_blocks
)
727 int i_read
= aspi_read_internal( dvdcss
->i_fd
, p_buffer
, i_blocks
);
735 dvdcss
->i_pos
+= i_read
;
740 /*****************************************************************************
742 *****************************************************************************/
743 static int libc_readv ( dvdcss_t dvdcss
, struct iovec
*p_iovec
, int i_blocks
)
746 int i_index
, i_len
, i_total
= 0;
747 unsigned char *p_base
;
750 for( i_index
= i_blocks
;
752 i_index
--, p_iovec
++ )
754 i_len
= p_iovec
->iov_len
;
755 p_base
= p_iovec
->iov_base
;
762 i_bytes
= read( dvdcss
->i_fd
, p_base
, i_len
);
766 /* One of the reads failed, too bad.
767 * We won't even bother returning the reads that went ok,
768 * and as in the posix spec the file postition is left
769 * unspecified after a failure */
776 if( i_bytes
!= i_len
)
778 /* We reached the end of the file or a signal interrupted
779 * the read. Return a partial read. */
783 i_seek
= libc_seek( dvdcss
, i_total
/ DVDCSS_BLOCK_SIZE
);
789 /* We have to return now so that i_pos isn't clobbered */
790 return i_total
/ DVDCSS_BLOCK_SIZE
;
794 dvdcss
->i_pos
+= i_total
/ DVDCSS_BLOCK_SIZE
;
795 return i_total
/ DVDCSS_BLOCK_SIZE
;
797 int i_read
= readv( dvdcss
->i_read_fd
, p_iovec
, i_blocks
);
805 dvdcss
->i_pos
+= i_read
/ DVDCSS_BLOCK_SIZE
;
806 return i_read
/ DVDCSS_BLOCK_SIZE
;
811 /*****************************************************************************
812 * win_readv: vectored read using ReadFile for Win2K and ASPI for win9x
813 *****************************************************************************/
814 static int win_readv ( dvdcss_t dvdcss
, struct iovec
*p_iovec
, int i_blocks
)
817 int i_blocks_read
, i_blocks_total
= 0;
819 /* Check the size of the readv temp buffer, just in case we need to
820 * realloc something bigger */
821 if( dvdcss
->i_readv_buf_size
< i_blocks
* DVDCSS_BLOCK_SIZE
)
823 dvdcss
->i_readv_buf_size
= i_blocks
* DVDCSS_BLOCK_SIZE
;
825 if( dvdcss
->p_readv_buffer
) free( dvdcss
->p_readv_buffer
);
827 /* Allocate a buffer which will be used as a temporary storage
829 dvdcss
->p_readv_buffer
= malloc( dvdcss
->i_readv_buf_size
);
830 if( !dvdcss
->p_readv_buffer
)
832 print_error( dvdcss
, " failed (readv)" );
838 for( i_index
= i_blocks
; i_index
; i_index
-- )
840 i_blocks_total
+= p_iovec
[i_index
-1].iov_len
;
843 if( i_blocks_total
<= 0 ) return 0;
845 i_blocks_total
/= DVDCSS_BLOCK_SIZE
;
849 unsigned long int i_bytes
;
850 if( !ReadFile( (HANDLE
)dvdcss
->i_fd
, dvdcss
->p_readv_buffer
,
851 i_blocks_total
* DVDCSS_BLOCK_SIZE
, &i_bytes
, NULL
) )
853 /* The read failed... too bad.
854 * As in the posix spec the file postition is left
855 * unspecified after a failure */
859 i_blocks_read
= i_bytes
/ DVDCSS_BLOCK_SIZE
;
863 i_blocks_read
= aspi_read_internal( dvdcss
->i_fd
,
864 dvdcss
->p_readv_buffer
,
866 if( i_blocks_read
< 0 )
874 /* We just have to copy the content of the temp buffer into the iovecs */
875 for( i_index
= 0, i_blocks_total
= i_blocks_read
;
879 memcpy( p_iovec
[i_index
].iov_base
,
880 dvdcss
->p_readv_buffer
+ (i_blocks_read
- i_blocks_total
)
882 p_iovec
[i_index
].iov_len
);
883 /* if we read less blocks than asked, we'll just end up copying
884 * garbage, this isn't an issue as we return the number of
885 * blocks actually read */
886 i_blocks_total
-= ( p_iovec
[i_index
].iov_len
/ DVDCSS_BLOCK_SIZE
);
889 dvdcss
->i_pos
+= i_blocks_read
;
890 return i_blocks_read
;
893 static int aspi_read_internal( int i_fd
, void *p_data
, int i_blocks
)
896 struct SRB_ExecSCSICmd ssc
;
897 struct w32_aspidev
*fd
= (struct w32_aspidev
*) i_fd
;
899 /* Create the transfer completion event */
900 hEvent
= CreateEvent( NULL
, TRUE
, FALSE
, NULL
);
906 memset( &ssc
, 0, sizeof( ssc
) );
908 ssc
.SRB_Cmd
= SC_EXEC_SCSI_CMD
;
909 ssc
.SRB_Flags
= SRB_DIR_IN
| SRB_EVENT_NOTIFY
;
910 ssc
.SRB_HaId
= LOBYTE( fd
->i_sid
);
911 ssc
.SRB_Target
= HIBYTE( fd
->i_sid
);
912 ssc
.SRB_SenseLen
= SENSE_LEN
;
914 ssc
.SRB_PostProc
= (LPVOID
) hEvent
;
915 ssc
.SRB_BufPointer
= p_data
;
918 ssc
.CDBByte
[0] = 0xA8; /* RAW */
919 ssc
.CDBByte
[2] = (UCHAR
) (fd
->i_blocks
>> 24);
920 ssc
.CDBByte
[3] = (UCHAR
) (fd
->i_blocks
>> 16) & 0xff;
921 ssc
.CDBByte
[4] = (UCHAR
) (fd
->i_blocks
>> 8) & 0xff;
922 ssc
.CDBByte
[5] = (UCHAR
) (fd
->i_blocks
) & 0xff;
924 /* We have to break down the reads into 64kb pieces (ASPI restriction) */
927 ssc
.SRB_BufLen
= 32 * DVDCSS_BLOCK_SIZE
;
931 /* Initiate transfer */
932 ResetEvent( hEvent
);
933 fd
->lpSendCommand( (void*) &ssc
);
935 /* transfer the next 64kb (aspi_read_internal is called recursively)
936 * We need to check the status of the read on return */
937 if( aspi_read_internal( i_fd
,
938 (uint8_t*) p_data
+ 32 * DVDCSS_BLOCK_SIZE
,
946 /* This is the last transfer */
947 ssc
.SRB_BufLen
= i_blocks
* DVDCSS_BLOCK_SIZE
;
948 ssc
.CDBByte
[9] = (UCHAR
) i_blocks
;
949 fd
->i_blocks
+= i_blocks
;
951 /* Initiate transfer */
952 ResetEvent( hEvent
);
953 fd
->lpSendCommand( (void*) &ssc
);
957 /* If the command has still not been processed, wait until it's finished */
958 if( ssc
.SRB_Status
== SS_PENDING
)
960 WaitForSingleObject( hEvent
, INFINITE
);
962 CloseHandle( hEvent
);
964 /* check that the transfer went as planned */
965 if( ssc
.SRB_Status
!= SS_COMP
)