Implementation of IOCTL_SCSI_PASS_THROUGH and
IOCTL_SCSI_PASS_THROUGH_DIRECT.
diff --git a/configure b/configure
index 8339bea..cdf3eb8 100755
--- a/configure
+++ b/configure
@@ -10466,6 +10466,7 @@
+
for ac_header in \
arpa/inet.h \
arpa/nameser.h \
@@ -10480,6 +10481,7 @@
linux/cdrom.h \
linux/input.h \
linux/joystick.h \
+ linux/param.h \
linux/serial.h \
linux/ucdrom.h \
net/if.h \
diff --git a/configure.ac b/configure.ac
index 91267fc..b36fb68 100644
--- a/configure.ac
+++ b/configure.ac
@@ -915,6 +915,7 @@
linux/cdrom.h \
linux/input.h \
linux/joystick.h \
+ linux/param.h \
linux/serial.h \
linux/ucdrom.h \
net/if.h \
diff --git a/dlls/ntdll/cdrom.c b/dlls/ntdll/cdrom.c
index 79137c9..63360c8 100644
--- a/dlls/ntdll/cdrom.c
+++ b/dlls/ntdll/cdrom.c
@@ -31,10 +31,14 @@
#include "winioctl.h"
#include "ntddstor.h"
#include "ntddcdrm.h"
+#include "ntddscsi.h"
#include "drive.h"
#include "file.h"
#include "wine/debug.h"
+#ifdef HAVE_LINUX_PARAM_H
+# include <linux/param.h>
+#endif
#ifdef HAVE_LINUX_CDROM_H
# include <linux/cdrom.h>
#endif
@@ -830,6 +834,159 @@
}
/******************************************************************
+ * CDROM_ScsiPassThroughDirect
+ *
+ *
+ */
+static DWORD CDROM_ScsiPassThroughDirect(int dev, PSCSI_PASS_THROUGH_DIRECT pPacket)
+{
+ int ret = STATUS_NOT_SUPPORTED;
+#if defined(linux)
+ struct cdrom_generic_command cmd;
+ struct request_sense sense;
+ int io;
+
+ if (pPacket->Length < sizeof(SCSI_PASS_THROUGH_DIRECT))
+ return STATUS_BUFFER_TOO_SMALL;
+
+ if (pPacket->CdbLength > 12)
+ return STATUS_INVALID_PARAMETER;
+
+ if (pPacket->SenseInfoLength > sizeof(sense))
+ return STATUS_INVALID_PARAMETER;
+
+ memset(&cmd, 0, sizeof(cmd));
+ memset(&sense, 0, sizeof(sense));
+
+ memcpy(&(cmd.cmd), &(pPacket->Cdb), pPacket->CdbLength);
+
+ cmd.buffer = pPacket->DataBuffer;
+ cmd.buflen = pPacket->DataTransferLength;
+ cmd.sense = &sense;
+ cmd.quiet = 0;
+ cmd.timeout = pPacket->TimeOutValue*HZ;
+
+ switch (pPacket->DataIn)
+ {
+ case SCSI_IOCTL_DATA_OUT:
+ cmd.data_direction = CGC_DATA_WRITE;
+ break;
+ case SCSI_IOCTL_DATA_IN:
+ cmd.data_direction = CGC_DATA_READ;
+ break;
+ case SCSI_IOCTL_DATA_UNSPECIFIED:
+ cmd.data_direction = CGC_DATA_NONE;
+ break;
+ default:
+ return STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ io = ioctl(dev, CDROM_SEND_PACKET, &cmd);
+
+ if (pPacket->SenseInfoLength != 0)
+ {
+ memcpy((char*)pPacket + pPacket->SenseInfoOffset,
+ &sense, pPacket->SenseInfoLength);
+ }
+
+ pPacket->ScsiStatus = cmd.stat;
+
+ ret = CDROM_GetStatusCode(io);
+#endif
+ return ret;
+}
+
+/******************************************************************
+ * CDROM_ScsiPassThrough
+ *
+ *
+ */
+static DWORD CDROM_ScsiPassThrough(int dev, PSCSI_PASS_THROUGH pPacket)
+{
+ int ret = STATUS_NOT_SUPPORTED;
+#if defined(linux)
+ struct cdrom_generic_command cmd;
+ struct request_sense sense;
+ int io;
+
+ if (pPacket->Length < sizeof(SCSI_PASS_THROUGH))
+ return STATUS_BUFFER_TOO_SMALL;
+
+ if (pPacket->CdbLength > 12)
+ return STATUS_INVALID_PARAMETER;
+
+ if (pPacket->SenseInfoLength > sizeof(sense))
+ return STATUS_INVALID_PARAMETER;
+
+ memset(&cmd, 0, sizeof(cmd));
+ memset(&sense, 0, sizeof(sense));
+
+ memcpy(&(cmd.cmd), &(pPacket->Cdb), pPacket->CdbLength);
+
+ if ( pPacket->DataBufferOffset > 0x1000 )
+ {
+ cmd.buffer = (void*)pPacket->DataBufferOffset;
+ }
+ else
+ {
+ cmd.buffer = ((void*)pPacket) + pPacket->DataBufferOffset;
+ }
+ cmd.buflen = pPacket->DataTransferLength;
+ cmd.sense = &sense;
+ cmd.quiet = 0;
+ cmd.timeout = pPacket->TimeOutValue*HZ;
+
+ switch (pPacket->DataIn)
+ {
+ case SCSI_IOCTL_DATA_OUT:
+ cmd.data_direction = CGC_DATA_WRITE;
+ break;
+ case SCSI_IOCTL_DATA_IN:
+ cmd.data_direction = CGC_DATA_READ;
+ break;
+ case SCSI_IOCTL_DATA_UNSPECIFIED:
+ cmd.data_direction = CGC_DATA_NONE;
+ break;
+ default:
+ return STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ io = ioctl(dev, CDROM_SEND_PACKET, &cmd);
+
+ if (pPacket->SenseInfoLength != 0)
+ {
+ memcpy((char*)pPacket + pPacket->SenseInfoOffset,
+ &sense, pPacket->SenseInfoLength);
+ }
+
+ pPacket->ScsiStatus = cmd.stat;
+
+ ret = CDROM_GetStatusCode(io);
+#endif
+ return ret;
+}
+
+/******************************************************************
+ * CDROM_ScsiGetAddress
+ *
+ *
+ */
+static DWORD CDROM_ScsiGetAddress(int dev, PSCSI_ADDRESS addr)
+{
+ FIXME("IOCTL_SCSI_GET_ADDRESS: stub\n");
+
+ addr->Length = sizeof(SCSI_ADDRESS);
+ addr->PortNumber = 0;
+ addr->PathId = 0;
+ addr->TargetId = 1;
+ addr->Lun = 0;
+
+ return 0;
+}
+
+/******************************************************************
* CDROM_DeviceIoControl
*
*
@@ -892,6 +1049,12 @@
else error = CDROM_SetTray(dev, TRUE);
break;
+ case IOCTL_CDROM_MEDIA_REMOVAL:
+ FIXME("IOCTL_CDROM_MEDIA_REMOVAL: stub\n");
+ sz = 0;
+ error = 0;
+ break;
+
case IOCTL_DISK_MEDIA_REMOVAL:
case IOCTL_STORAGE_MEDIA_REMOVAL:
case IOCTL_STORAGE_EJECTION_CONTROL:
@@ -1009,6 +1172,26 @@
else error = CDROM_RawRead(dev, (const RAW_READ_INFO*)lpInBuffer,
lpOutBuffer, nOutBufferSize, &sz);
break;
+
+ case IOCTL_SCSI_PASS_THROUGH_DIRECT:
+ sz = sizeof(SCSI_PASS_THROUGH_DIRECT);
+ if (lpOutBuffer == NULL) error = STATUS_INVALID_PARAMETER;
+ else if (nOutBufferSize < sizeof(SCSI_PASS_THROUGH_DIRECT)) error = STATUS_BUFFER_TOO_SMALL;
+ else error = CDROM_ScsiPassThroughDirect(dev, (PSCSI_PASS_THROUGH_DIRECT)lpOutBuffer);
+ break;
+ case IOCTL_SCSI_PASS_THROUGH:
+ sz = sizeof(SCSI_PASS_THROUGH);
+ if (lpOutBuffer == NULL) error = STATUS_INVALID_PARAMETER;
+ else if (nOutBufferSize < sizeof(SCSI_PASS_THROUGH)) error = STATUS_BUFFER_TOO_SMALL;
+ else error = CDROM_ScsiPassThrough(dev, (PSCSI_PASS_THROUGH)lpOutBuffer);
+ break;
+ case IOCTL_SCSI_GET_ADDRESS:
+ sz = 0;
+ if (lpOutBuffer == NULL) error = STATUS_INVALID_PARAMETER;
+ else if (nOutBufferSize < sizeof(SCSI_ADDRESS)) error = STATUS_BUFFER_TOO_SMALL;
+ else error = CDROM_ScsiGetAddress(dev, (PSCSI_ADDRESS)lpOutBuffer);
+ break;
+
default:
FIXME("Unsupported IOCTL %lx\n", dwIoControlCode);
sz = 0;
diff --git a/include/config.h.in b/include/config.h.in
index 5f744ef..4da1baf 100644
--- a/include/config.h.in
+++ b/include/config.h.in
@@ -248,6 +248,9 @@
/* Define to 1 if you have the <linux/joystick.h> header file. */
#undef HAVE_LINUX_JOYSTICK_H
+/* Define to 1 if you have the <linux/param.h> header file. */
+#undef HAVE_LINUX_PARAM_H
+
/* Define to 1 if you have the <linux/serial.h> header file. */
#undef HAVE_LINUX_SERIAL_H
diff --git a/include/ntddscsi.h b/include/ntddscsi.h
new file mode 100644
index 0000000..01fd5fc
--- /dev/null
+++ b/include/ntddscsi.h
@@ -0,0 +1,89 @@
+/*
+ * DDK definitions for scsi media access
+ *
+ * Copyright (C) 2002 Laurent Pinchart
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _NTDDSCSI_H_
+#define _NTDDSCSI_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define IOCTL_SCSI_BASE FILE_DEVICE_CONTROLLER
+
+#define IOCTL_SCSI_PASS_THROUGH CTL_CODE(IOCTL_SCSI_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_SCSI_MINIPORT CTL_CODE(IOCTL_SCSI_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_SCSI_GET_INQUIRY_DATA CTL_CODE(IOCTL_SCSI_BASE, 0x0403, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_SCSI_GET_CAPABILITIES CTL_CODE(IOCTL_SCSI_BASE, 0x0404, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_SCSI_PASS_THROUGH_DIRECT CTL_CODE(IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_SCSI_GET_ADDRESS CTL_CODE(IOCTL_SCSI_BASE, 0x0406, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_SCSI_RESCAN_BUS CTL_CODE(IOCTL_SCSI_BASE, 0x0407, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_SCSI_GET_DUMP_POINTERS CTL_CODE(IOCTL_SCSI_BASE, 0x0408, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_SCSI_FREE_DUMP_POINTERS CTL_CODE(IOCTL_SCSI_BASE, 0x0409, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_IDE_PASS_THROUGH CTL_CODE(IOCTL_SCSI_BASE, 0x040a, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+#define SCSI_IOCTL_DATA_OUT 0
+#define SCSI_IOCTL_DATA_IN 1
+#define SCSI_IOCTL_DATA_UNSPECIFIED 2
+
+typedef struct _SCSI_PASS_THROUGH {
+ USHORT Length;
+ UCHAR ScsiStatus;
+ UCHAR PathId;
+ UCHAR TargetId;
+ UCHAR Lun;
+ UCHAR CdbLength;
+ UCHAR SenseInfoLength;
+ UCHAR DataIn;
+ ULONG DataTransferLength;
+ ULONG TimeOutValue;
+ ULONG_PTR DataBufferOffset;
+ ULONG SenseInfoOffset;
+ UCHAR Cdb[16];
+} SCSI_PASS_THROUGH, *PSCSI_PASS_THROUGH;
+
+typedef struct _SCSI_PASS_THROUGH_DIRECT {
+ USHORT Length;
+ UCHAR ScsiStatus;
+ UCHAR PathId;
+ UCHAR TargetId;
+ UCHAR Lun;
+ UCHAR CdbLength;
+ UCHAR SenseInfoLength;
+ UCHAR DataIn;
+ ULONG DataTransferLength;
+ ULONG TimeOutValue;
+ PVOID DataBuffer;
+ ULONG SenseInfoOffset;
+ UCHAR Cdb[16];
+} SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT;
+
+typedef struct _SCSI_ADDRESS {
+ ULONG Length;
+ UCHAR PortNumber;
+ UCHAR PathId;
+ UCHAR TargetId;
+ UCHAR Lun;
+} SCSI_ADDRESS, *PSCSI_ADDRESS;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _NTDDSCSI_H_ */