/[pearpc]/src/system/osapi/win32/syscdrom.cc
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /src/system/osapi/win32/syscdrom.cc

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (hide annotations)
Wed Sep 5 17:11:21 2007 UTC (16 years, 7 months ago) by dpavlin
File size: 10874 byte(s)
import upstream CVS
1 dpavlin 1 /*
2     * PearPC
3     * syscdrom.cc
4     *
5     * Copyright (C) 2003 Sebastian Biallas (sb@biallas.net)
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 version 2 as
9     * published by the Free Software Foundation.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19     */
20    
21     #define WIN32_LEAN_AND_MEAN
22     #include <windows.h>
23     #include <windowsx.h>
24    
25     #ifdef FASTCALL
26     #undef FASTCALL
27     #endif
28    
29     #include <cstdio>
30     #include <cstring>
31     #include "errno.h"
32    
33     #include "debug/tracers.h"
34     #include "tools/data.h"
35     #include "io/ide/cd.h"
36     #include "aspi-win32.h"
37     #include "scsipt.h"
38     #include "scsitypes.h"
39    
40     #define SCSI_CMD_DIR_IN 1
41     #define SCSI_CMD_DIR_OUT 2
42    
43     /// SPTI CD-ROM implementation
44     class CDROMDeviceSPTI:public CDROMDeviceSCSI
45     {
46     private:
47     // HANDLE to device
48     HANDLE device;
49    
50     /// Opens a drive device
51     /// @author Alexander Stockinger
52     /// @date 07/18/2004
53     /// @param letter The drive letter of the drive to open
54     /// @return A file handle to the device
55     static HANDLE OpenDevice(char letter)
56     {
57    
58     // Generate the device name
59     char fname[16];
60     ht_snprintf(fname, sizeof fname, "\\\\.\\%c:", letter);
61    
62     // Handle access (different on NT / 2K / XP)
63     OSVERSIONINFO ver;
64     memset(&ver, 0, sizeof(ver));
65     ver.dwOSVersionInfoSize = sizeof(ver);
66     GetVersionEx(&ver);
67    
68     DWORD flags = GENERIC_READ;
69     if (ver.dwPlatformId == VER_PLATFORM_WIN32_NT
70     && ver.dwMajorVersion > 4)
71     flags |= GENERIC_WRITE;
72    
73     // Create the file handle
74     return CreateFile(fname, flags, FILE_SHARE_READ, NULL,
75     OPEN_EXISTING, 0, NULL);
76     }
77    
78    
79     protected:
80     /// SCSI command pass-through function
81     /// @author Alexander Stockinger
82     /// @date 07/18/2004
83     /// @param command The SCSI command to be sent
84     /// @param dir The data direcion flags
85     /// @param params byte[11] array containing command dependent parameters
86     /// @param buffer Buffer for data exchange
87     /// @param buffer_len The size of buffer in bytes
88     /// @return If the call could be executed it returns the status from the device, else it returns 0xff
89     virtual byte SCSI_ExecCmd(byte command, byte dir, byte params[11], byte *buffer, unsigned int buffer_len)
90     {
91     byte srb_dir;
92    
93     if (dir & SCSI_CMD_DIR_IN)
94     srb_dir = SCSI_IOCTL_DATA_IN;
95     else if (dir & SCSI_CMD_DIR_OUT)
96     srb_dir = SCSI_IOCTL_DATA_OUT;
97     else
98     srb_dir = SCSI_IOCTL_DATA_UNSPECIFIED;
99    
100     // Fill SPTDWB
101     SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER swb;
102    
103     memset(&swb, 0, sizeof(swb));
104     swb.spt.Length = sizeof(SCSI_PASS_THROUGH);
105     swb.spt.DataTransferLength = buffer_len;
106     swb.spt.DataBuffer = buffer;
107     swb.spt.TimeOutValue = 5;
108     swb.spt.SenseInfoOffset =
109     offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER,
110     ucSenseBuf);
111     swb.spt.DataIn = srb_dir;
112     if (command < 0x20) {
113     swb.spt.CdbLength = 6;
114     } else if (command < 0xa0) {
115     swb.spt.CdbLength = 10;
116     } else {
117     swb.spt.CdbLength = 12;
118     }
119     swb.spt.Cdb[0] = command;
120     for (int i=1; i < swb.spt.CdbLength; i++) {
121     swb.spt.Cdb[i] = params[i-1];
122     }
123    
124     // Send cmd
125     ULONG ret;
126     BOOL status = DeviceIoControl(device,
127     IOCTL_SCSI_PASS_THROUGH_DIRECT,
128     &swb,
129     sizeof(swb),
130     &swb,
131     sizeof(swb),
132     &ret,
133     NULL);
134    
135     // Done
136     if (!status) {
137     IO_IDE_WARN("SPTI: DeviceIoControl() returned error:\n");
138     IO_IDE_WARN("command: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x:\n",
139     command, params[0], params[1], params[2], params[3], params[4], params[5], params[6], params[7], params[8], params[9]);
140     char buffer[256];
141    
142     FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0,
143     GetLastError(), 0, buffer, sizeof buffer, 0);
144     IO_IDE_WARN("%s\n", buffer);
145     return 0xff;
146     }
147     return swb.spt.ScsiStatus;
148     }
149    
150    
151     public:
152     /// Constructor
153     /// @author Alexander Stockinger
154     /// @date 07/17/2004
155     /// @param name The name of the CDROM device
156     CDROMDeviceSPTI (const char *name):CDROMDeviceSCSI(name),
157     device(INVALID_HANDLE_VALUE)
158     {
159     }
160    
161     /// Destructor
162     /// @author Alexander Stockinger
163     /// @date 07/18/2004
164     virtual ~CDROMDeviceSPTI()
165     {
166     setLock(false);
167     if (device != INVALID_HANDLE_VALUE)
168     CloseHandle(device);
169     }
170    
171     /// Sets the drive letter of the real CD drive
172     /// @author Alexander Stockinger
173     /// @date 07/18/2004
174     /// @param name The drive letter, e.g. "e:" or "e:\"
175     /// @return A file handle to the device
176     void setDrive(const char *name)
177     {
178     // Check parameter
179     size_t len = strlen(name);
180    
181     if (len != 2 && len != 3)
182     IO_IDE_ERR("SPTI: Invalid drive name '%s'\n", name);
183    
184     if (name[1] != ':')
185     IO_IDE_ERR("SPTI: Invalid drive name '%s'\n", name);
186     if (len == 3 && name[2] != '\\')
187     IO_IDE_ERR("SPTI: Invalid drive name '%s'\n", name);
188    
189     char letter = name[0];
190    
191     if (letter >= 'a' && letter <= 'z')
192     letter -= ('a' - 'A');
193     if (letter < 'A' || letter > 'Z')
194     IO_IDE_ERR("SPTI: Invalid drive '%c:'\n", letter);
195    
196     // Open the device
197     device = OpenDevice(letter);
198     if (device == INVALID_HANDLE_VALUE)
199     IO_IDE_ERR("SPTI: Cannot open drive '%c:'\n", letter);
200     }
201    
202     };
203    
204    
205     /// ASPI CD-ROM implementation
206     class CDROMDeviceASPI:public CDROMDeviceSCSI
207     {
208     private:
209     /// Module handle to ASPI DLL
210     HMODULE hASPI;
211    
212     /// SCSI host adapter ID
213     unsigned int a;
214    
215     /// SCSI target ID
216     unsigned int t;
217    
218     /// SCSI lun ID
219     unsigned int l;
220    
221     protected:
222     /// SCSI command pass-trough function
223     /// @author Alexander Stockinger
224     /// @date 07/17/2004
225     /// @param command The SCSI command to be sent
226     /// @param dir The data direcion flags
227     /// @param params byte[8] array containing command dependent parameters
228     /// @param buffer Buffer for data exchange
229     /// @param buffer_len The size of buffer in bytes
230     /// @return If the call could be executed it returns the status from the device, else it returns 0xff
231     virtual byte SCSI_ExecCmd(byte command, byte dir, byte params[8],
232     byte *buffer, unsigned int buffer_len)
233     {
234     byte srb_dir;
235     if (dir & SCSI_CMD_DIR_IN)
236     srb_dir = SRB_DIR_IN;
237     else if (dir & SCSI_CMD_DIR_OUT)
238     srb_dir = SRB_DIR_OUT;
239     else
240     srb_dir = 0;
241    
242    
243     // Create event
244     HANDLE event = CreateEvent(NULL, TRUE, FALSE, NULL);
245     ResetEvent(event);
246    
247     // Prepare SRB
248     SRB_ExecSCSICmd cmd;
249     memset(&cmd, 0, sizeof(cmd));
250     cmd.SRB_Cmd = SC_EXEC_SCSI_CMD;
251     cmd.SRB_HaId = a;
252     cmd.SRB_Target = t;
253     cmd.SRB_Lun = l;
254     cmd.SRB_Flags = srb_dir | SRB_EVENT_NOTIFY;
255     cmd.SRB_SenseLen = SENSE_LEN;
256     cmd.SRB_PostProc = event;
257     cmd.SRB_BufPointer = buffer;
258     cmd.SRB_BufLen = buffer_len;
259     cmd.SRB_CDBLen = 10;
260     cmd.CDBByte[0] = command;
261     cmd.CDBByte[1] = params[0];
262     cmd.CDBByte[2] = params[1];
263     cmd.CDBByte[3] = params[2];
264     cmd.CDBByte[4] = params[3];
265     cmd.CDBByte[5] = params[4];
266     cmd.CDBByte[6] = params[5];
267     cmd.CDBByte[7] = params[6];
268     cmd.CDBByte[8] = params[7];
269    
270     // Send cmd and wait for event
271     DWORD status = SendASPI32Command((LPSRB) & cmd);
272     if (status == SS_PENDING)
273     WaitForSingleObject(event, 100000);
274    
275     // Clean up
276     CloseHandle(event);
277    
278     // Check error conditions
279     if (status != SS_COMP && status != SS_PENDING)
280     return 0xff;
281    
282     // Return error code
283     return cmd.SRB_TargStat;
284     }
285     public:
286     /// Constructor
287     /// @author Alexander Stockinger
288     /// @date 07/13/2004
289     /// @param name The name of the CDROM device
290     CDROMDeviceASPI(const char *name):CDROMDeviceSCSI(name)
291     {
292     // See if ASPI is available
293     hASPI = (HMODULE) LoadLibrary("wnaspi32.dll");
294     if (hASPI == INVALID_HANDLE_VALUE || hASPI == 0)
295     IO_IDE_ERR("No ASPI support (Could not load wnaspi32.dll).\n");
296    
297     // Load ASPI function addresses
298     SendASPI32Command =
299     (DWORD(*)(LPSRB)) GetProcAddress(hASPI,
300     "SendASPI32Command");
301     GetASPI32DLLVersion =
302     (DWORD(*)(void)) GetProcAddress(hASPI,
303     "GetASPI32DLLVersion");
304     GetASPI32SupportInfo =
305     (DWORD(*)(void)) GetProcAddress(hASPI,
306     "GetASPI32SupportInfo");
307    
308     if (!SendASPI32Command || !GetASPI32DLLVersion
309     || !GetASPI32SupportInfo)
310     IO_IDE_ERR("Error loading wnaspi32.dll\n");
311    
312     // Make sure the init function is being called
313     GetASPI32SupportInfo();
314     }
315    
316     /// Destructor
317     /// @author Alexander Stockinger
318     /// @date 07/13/2004
319     virtual ~CDROMDeviceASPI()
320     {
321     setLock(false);
322     if (hASPI != INVALID_HANDLE_VALUE)
323     FreeLibrary(hASPI);
324     }
325    
326     /// Checks if the ASPI device is a CD drive
327     /// @author Alexander Stockinger
328     /// @date 07/17/2004
329     /// @return true if the specified device is CD drive, else false
330     bool ASPI_IsDeviceCDROM()
331     {
332     // Get adapter cound
333     const DWORD info = GetASPI32SupportInfo();
334     const byte adapter_count LOBYTE(LOWORD(info));
335    
336     // Make sure the host adapter exists
337     if (a >= adapter_count)
338     return false;
339    
340     // Get device type
341     SRB_GDEVBlock desc;
342    
343     memset(&desc, 0, sizeof(desc));
344     desc.SRB_Cmd = SC_GET_DEV_TYPE;
345     desc.SRB_HaId = a;
346     desc.SRB_Target = t;
347     desc.SRB_Lun = l;
348     SendASPI32Command((LPSRB) & desc);
349    
350     // False on errors
351     if (desc.SRB_Status != SS_COMP)
352     return false;
353    
354     // Done
355     return desc.SRB_DeviceType == DTYPE_CDROM;
356     }
357    
358     /// Sets the SCSI target for the ASPI device
359     /// @author Alexander Stockinger
360     /// @date 07/13/2004
361     /// @param name The SCSI device id in the form "a,t,l"
362     void setSCSITarget(const char *name)
363     {
364     // Extract SCSI device info
365     char *spath = new char[strlen(name) + 1];
366    
367     strcpy(spath, name);
368     char *scsi[3] = { spath, 0, 0 };
369     int i = 0;
370    
371     for (char *c = spath; *c; c++) {
372     if (i == 3)
373     break;
374     if (*c == ',') {
375     i++;
376     *c = 0;
377     c++;
378     scsi[i] = c;
379     }
380     }
381    
382     if (scsi[1] == 0 || scsi[2] == 0)
383     IO_IDE_ERR("Invalid SCSI path: %s", name);
384    
385     a = atoi(scsi[0]);
386     t = atoi(scsi[1]);
387     l = atoi(scsi[2]);
388     delete[]spath;
389    
390     // Check device type
391     if (!ASPI_IsDeviceCDROM())
392     IO_IDE_WARN("SCSI device %d/%d/%d is not a CDROM drive.\n",
393     a, t, l);
394    
395     // Set initial ready state
396     isReady();
397     }
398     };
399    
400     /// Creates a native CDROM device
401     /// @param device_name The PearPC internal device name for the drive
402     /// @param image_name The image / device name to identify the real hardware
403     /// @return On success a pointer to a CDROMDevice is returned, else NULL
404     /// @author Alexander Stockinger
405     /// @date 07/19/2004
406     CDROMDevice *createNativeCDROMDevice(const char *device_name,
407     const char *image_name)
408     {
409     if (strlen(image_name) < 2)
410     return NULL;
411    
412     CDROMDevice *ret = NULL;
413    
414     if (image_name[1] == ':') {
415     CDROMDeviceSPTI *spti = new CDROMDeviceSPTI(device_name);
416    
417     spti->setDrive(image_name);
418     ret = spti;
419     } else {
420     CDROMDeviceASPI *aspi = new CDROMDeviceASPI(device_name);
421    
422     aspi->setSCSITarget(image_name);
423     ret = aspi;
424     }
425    
426     return ret;
427     }

  ViewVC Help
Powered by ViewVC 1.1.26