/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (show 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 /*
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