Merge pull request #5039 from CEikermann/patch-1
[vuplus_xbmc] / xbmc / storage / IoSupport.cpp
1 /*
2  *      Copyright (c) 2002 Frodo
3  *      Portions Copyright (c) by the authors of ffmpeg and xvid
4  *      Copyright (C) 2002-2013 Team XBMC
5  *      http://xbmc.org
6  *
7  *  This Program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2, or (at your option)
10  *  any later version.
11  *
12  *  This Program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with XBMC; see the file COPYING.  If not, see
19  *  <http://www.gnu.org/licenses/>.
20  *
21  */
22
23 // IoSupport.cpp: implementation of the CIoSupport class.
24 //
25 //////////////////////////////////////////////////////////////////////
26
27 #include "system.h"
28 #include "IoSupport.h"
29 #include "utils/log.h"
30 #ifdef TARGET_WINDOWS
31 #include "my_ntddcdrm.h"
32 #include "WIN32Util.h"
33 #include "utils/CharsetConverter.h"
34 #endif
35 #if defined(TARGET_LINUX)
36 #include <linux/limits.h>
37 #include <sys/types.h>
38 #include <sys/ioctl.h>
39 #include <unistd.h>
40 #include <fcntl.h>
41 #include <linux/cdrom.h>
42 #endif
43 #if defined(TARGET_DARWIN)
44 #include <sys/param.h>
45 #include <mach-o/dyld.h>
46 #if defined(TARGET_DARWIN_OSX)
47 #include <IOKit/IOKitLib.h>
48 #include <IOKit/IOBSD.h>
49 #include <IOKit/storage/IOCDTypes.h>
50 #include <IOKit/storage/IODVDTypes.h>
51 #include <IOKit/storage/IOMedia.h>
52 #include <IOKit/storage/IOCDMedia.h>
53 #include <IOKit/storage/IODVDMedia.h>
54 #include <IOKit/storage/IOCDMediaBSDClient.h>
55 #include <IOKit/storage/IODVDMediaBSDClient.h>
56 #include <IOKit/storage/IOStorageDeviceCharacteristics.h>
57 #endif
58 #endif
59 #ifdef TARGET_FREEBSD
60 #include <sys/syslimits.h>
61 #endif
62 #include "cdioSupport.h"
63 #include "filesystem/iso9660.h"
64 #include "MediaManager.h"
65 #ifdef TARGET_POSIX
66 #include "XHandle.h"
67 #endif
68
69
70 PVOID CIoSupport::m_rawXferBuffer;
71
72 HANDLE CIoSupport::OpenCDROM()
73 {
74   HANDLE hDevice = 0;
75
76 #ifdef HAS_DVD_DRIVE
77 #if defined(TARGET_POSIX)
78   int fd = open(CLibcdio::GetInstance()->GetDeviceFileName(), O_RDONLY | O_NONBLOCK);
79   hDevice = new CXHandle(CXHandle::HND_FILE);
80   hDevice->fd = fd;
81   hDevice->m_bCDROM = true;
82 #elif defined(TARGET_WINDOWS)
83   hDevice = CreateFile(g_mediaManager.TranslateDevicePath("",true), GENERIC_READ, FILE_SHARE_READ,
84                        NULL, OPEN_EXISTING,
85                        FILE_FLAG_RANDOM_ACCESS, NULL );
86 #else
87
88   hDevice = CreateFile("\\\\.\\Cdrom0", GENERIC_READ, FILE_SHARE_READ,
89                        NULL, OPEN_EXISTING,
90                        FILE_FLAG_RANDOM_ACCESS, NULL );
91
92 #endif
93 #endif
94   return hDevice;
95 }
96
97 void CIoSupport::AllocReadBuffer()
98 {
99 #ifndef TARGET_POSIX
100   m_rawXferBuffer = GlobalAlloc(GPTR, RAW_SECTOR_SIZE);
101 #endif
102 }
103
104 void CIoSupport::FreeReadBuffer()
105 {
106 #ifndef TARGET_POSIX
107   GlobalFree(m_rawXferBuffer);
108 #endif
109 }
110
111 INT CIoSupport::ReadSector(HANDLE hDevice, DWORD dwSector, LPSTR lpczBuffer)
112
113 {
114   DWORD dwRead;
115   DWORD dwSectorSize = 2048;
116
117 #if defined(TARGET_DARWIN) && defined(HAS_DVD_DRIVE)
118   dk_cd_read_t cd_read;
119   memset( &cd_read, 0, sizeof(cd_read) );
120
121   cd_read.sectorArea  = kCDSectorAreaUser;
122   cd_read.buffer      = lpczBuffer;
123
124   cd_read.sectorType  = kCDSectorTypeMode1;
125   cd_read.offset      = dwSector * kCDSectorSizeMode1;
126
127   cd_read.bufferLength = 2048;
128
129   if( ioctl(hDevice->fd, DKIOCCDREAD, &cd_read ) == -1 )
130   {
131     return -1;
132   }
133   return 2048;
134 #elif defined(TARGET_POSIX)
135   if (hDevice->m_bCDROM)
136   {
137     int fd = hDevice->fd;
138
139     // seek to requested sector
140     off_t offset = (off_t)dwSector * (off_t)MODE1_DATA_SIZE;
141
142     if (lseek(fd, offset, SEEK_SET) < 0)
143     {
144       CLog::Log(LOGERROR, "CD: ReadSector Request to read sector %d\n", (int)dwSector);
145       CLog::Log(LOGERROR, "CD: ReadSector error: %s\n", strerror(errno));
146       OutputDebugString("CD Read error\n");
147       return (-1);
148     }
149
150     // read data block of this sector
151     while (read(fd, lpczBuffer, MODE1_DATA_SIZE) < 0)
152     {
153       // read was interrupted - try again
154       if (errno == EINTR)
155         continue;
156
157       // error reading sector
158       CLog::Log(LOGERROR, "CD: ReadSector Request to read sector %d\n", (int)dwSector);
159       CLog::Log(LOGERROR, "CD: ReadSector error: %s\n", strerror(errno));
160       OutputDebugString("CD Read error\n");
161       return (-1);
162     }
163
164     return MODE1_DATA_SIZE;
165   }
166 #endif
167   LARGE_INTEGER Displacement;
168   Displacement.QuadPart = ((INT64)dwSector) * dwSectorSize;
169
170   for (int i = 0; i < 5; i++)
171   {
172     if (SetFilePointer(hDevice, Displacement.u.LowPart, &Displacement.u.HighPart, FILE_BEGIN) != (DWORD)-1)
173     {
174       if (ReadFile(hDevice, m_rawXferBuffer, dwSectorSize, &dwRead, NULL))
175       {
176         memcpy(lpczBuffer, m_rawXferBuffer, dwSectorSize);
177         return dwRead;
178       }
179     }
180   }
181
182   OutputDebugString("CD Read error\n");
183   return -1;
184 }
185
186
187 INT CIoSupport::ReadSectorMode2(HANDLE hDevice, DWORD dwSector, LPSTR lpczBuffer)
188 {
189 #ifdef HAS_DVD_DRIVE
190 #if defined(TARGET_DARWIN)
191   dk_cd_read_t cd_read;
192
193   memset( &cd_read, 0, sizeof(cd_read) );
194
195   cd_read.sectorArea = kCDSectorAreaUser;
196   cd_read.buffer = lpczBuffer;
197
198   cd_read.offset       = dwSector * kCDSectorSizeMode2Form2;
199   cd_read.sectorType   = kCDSectorTypeMode2Form2;
200   cd_read.bufferLength = kCDSectorSizeMode2Form2;
201
202   if( ioctl( hDevice->fd, DKIOCCDREAD, &cd_read ) == -1 )
203   {
204     return -1;
205   }
206   return MODE2_DATA_SIZE;
207 #elif defined(TARGET_FREEBSD)
208   // NYI
209 #elif defined(TARGET_POSIX)
210   if (hDevice->m_bCDROM)
211   {
212     int fd = hDevice->fd;
213     int lba = (dwSector + CD_MSF_OFFSET) ;
214     int m,s,f;
215     union
216     {
217       struct cdrom_msf msf;
218       char buffer[2356];
219     } arg;
220
221     // convert sector offset to minute, second, frame format
222     // since that is what the 'ioctl' requires as input
223     f = lba % CD_FRAMES;
224     lba /= CD_FRAMES;
225     s = lba % CD_SECS;
226     lba /= CD_SECS;
227     m = lba;
228
229     arg.msf.cdmsf_min0 = m;
230     arg.msf.cdmsf_sec0 = s;
231     arg.msf.cdmsf_frame0 = f;
232
233     int ret = ioctl(fd, CDROMREADMODE2, &arg);
234     if (ret==0)
235     {
236       memcpy(lpczBuffer, arg.buffer, MODE2_DATA_SIZE); // don't think offset is needed here
237       return MODE2_DATA_SIZE;
238     }
239     CLog::Log(LOGERROR, "CD: ReadSectorMode2 Request to read sector %d\n", (int)dwSector);
240     CLog::Log(LOGERROR, "CD: ReadSectorMode2 error: %s\n", strerror(errno));
241     CLog::Log(LOGERROR, "CD: ReadSectorMode2 minute %d, second %d, frame %d\n", m, s, f);
242     OutputDebugString("CD Read error\n");
243     return -1;
244   }
245 #else
246   DWORD dwBytesReturned;
247   RAW_READ_INFO rawRead = {0};
248
249   // Oddly enough, DiskOffset uses the Red Book sector size
250   rawRead.DiskOffset.QuadPart = 2048 * dwSector;
251   rawRead.SectorCount = 1;
252   rawRead.TrackMode = XAForm2;
253
254
255   for (int i = 0; i < 5; i++)
256   {
257     if ( DeviceIoControl( hDevice,
258                           IOCTL_CDROM_RAW_READ,
259                           &rawRead,
260                           sizeof(RAW_READ_INFO),
261                           m_rawXferBuffer,
262                           RAW_SECTOR_SIZE,
263                           &dwBytesReturned,
264                           NULL ) != 0 )
265     {
266       memcpy(lpczBuffer, (char*)m_rawXferBuffer+MODE2_DATA_START, MODE2_DATA_SIZE);
267       return MODE2_DATA_SIZE;
268     }
269     else
270     {
271       int iErr = GetLastError();
272     }
273   }
274 #endif
275 #endif
276   return -1;
277 }
278
279 INT CIoSupport::ReadSectorCDDA(HANDLE hDevice, DWORD dwSector, LPSTR lpczBuffer)
280 {
281   return -1;
282 }
283
284 VOID CIoSupport::CloseCDROM(HANDLE hDevice)
285 {
286   CloseHandle(hDevice);
287 }
288