Changelog: * configure, configure.ac, include/config.h.in, dlls/ntdll/cdrom.c, files/drive.c: Implemented IOCTL_SCSI_GET_ADDRESS for non true scsi cdrom drives (only on linux). Added code to initialize registry under HKEY_LOCAL_MACHINE/HARDWARE/DEVICEMAP/Scsi which is usually read by programs after calling IOCTL_SCSI_GET_ADDRESS Also sets up that the already defined IOCTL_CDROM_MEDIA_REMOVAL invokes the code which already handles IOCTL_DISK_MEDIA_REMOVAL, IOCTL_STORAGE_MEDIA_REMOVAL and IOCTL_STORAGE_EJECTION_CONTROL File ntddscsi.h is where the needed defines are. It is the same as submitted by Laurent Pinchart in his SafeDisc patch.
Index: configure =================================================================== RCS file: /home/wine/wine/configure,v retrieving revision 1.284 diff -u -u -r1.284 configure --- configure 30 Apr 2002 21:16:39 -0000 1.284 +++ configure 1 May 2002 00:19:02 -0000 @@ -10466,6 +10466,9 @@ + + + for ac_header in \ arpa/inet.h \ arpa/nameser.h \ @@ -10482,6 +10485,8 @@ linux/joystick.h \ linux/serial.h \ linux/ucdrom.h \ + linux/major.h \ + linux/hdreg.h \ net/if.h \ netdb.h \ netinet/in.h \ @@ -10491,6 +10496,7 @@ pty.h \ resolv.h \ sched.h \ + scsi/sg.h \ socket.h \ stdint.h \ strings.h \ Index: configure.ac =================================================================== RCS file: /home/wine/wine/configure.ac,v retrieving revision 1.27 diff -u -u -r1.27 configure.ac --- configure.ac 30 Apr 2002 21:16:39 -0000 1.27 +++ configure.ac 1 May 2002 00:19:06 -0000 @@ -917,6 +917,8 @@ linux/joystick.h \ linux/serial.h \ linux/ucdrom.h \ + linux/major.h \ + linux/hdreg.h \ net/if.h \ netdb.h \ netinet/in.h \ @@ -926,6 +928,7 @@ pty.h \ resolv.h \ sched.h \ + scsi/sg.h \ socket.h \ stdint.h \ strings.h \ Index: dlls/ntdll/cdrom.c =================================================================== RCS file: /home/wine/wine/dlls/ntdll/cdrom.c,v retrieving revision 1.7 diff -u -u -r1.7 cdrom.c --- dlls/ntdll/cdrom.c 2 Apr 2002 19:19:49 -0000 1.7 +++ dlls/ntdll/cdrom.c 1 May 2002 00:19:09 -0000 @@ -27,14 +27,23 @@ #include <unistd.h> #include <fcntl.h> #include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/types.h> #include "ntddk.h" #include "winioctl.h" #include "ntddstor.h" #include "ntddcdrm.h" +#include "ntddscsi.h" #include "drive.h" #include "file.h" #include "wine/debug.h" +#ifdef HAVE_SCSI_SG_H +# include <scsi/sg.h> +#endif +#ifdef HAVE_LINUX_MAJOR_H +# include <linux/major.h> +#endif #ifdef HAVE_LINUX_CDROM_H # include <linux/cdrom.h> #endif @@ -57,6 +66,52 @@ static struct cdrom_cache cdrom_cache[26]; /****************************************************************** + * CDROM_GetIdeInterface + * + * Determines the ide interface (the number after the ide), and the + * number of the device on that interface for ide cdroms. + * Returns false if the info could not be get + * + * NOTE: this function is used in CDROM_InitRegistry and CDROM_GetAddress + */ +int CDROM_GetIdeInterface(int dev, int* iface, int* device) { +#if defined(linux) + { + struct stat st; + if (ioctl(dev, SG_EMULATED_HOST) != -1) { + FIXME("not implemented for true scsi drives\n"); + return 0; + } + if ( fstat(dev, &st) == -1 || ! S_ISBLK(st.st_mode)) { + FIXME("cdrom not a block device!!!\n"); + return 0; + } + switch (major(st.st_rdev)) { + case IDE0_MAJOR: *iface = 0; break; + case IDE1_MAJOR: *iface = 1; break; + case IDE2_MAJOR: *iface = 2; break; + case IDE3_MAJOR: *iface = 3; break; + case IDE4_MAJOR: *iface = 4; break; + case IDE5_MAJOR: *iface = 5; break; + case IDE6_MAJOR: *iface = 6; break; + case IDE7_MAJOR: *iface = 7; break; + default: + FIXME("major %d not supported\n", major(st.st_rdev)); + } + *device = (minor(st.st_rdev) == 63 ? 1 : 0); + return 1; + } +#elif defined(__FreeBSD__) || defined(__NetBSD__) + FIXME("not implemented for BSD\n"); + return 0; +#else + FIXME("not implemented for nonlinux\n"); + return 0; +#endif +} + + +/****************************************************************** * CDROM_Open * * @@ -830,6 +885,26 @@ } /****************************************************************** + * CDROM_GetAddress + * + * implements IOCTL_SCSI_GET_ADDRESS + */ +static DWORD CDROM_GetAddress(int dev, SCSI_ADDRESS* address) +{ + int portnum, targetid; + + address->Length = sizeof(SCSI_ADDRESS); + address->PathId = 0; /* bus number */ + address->Lun = 0; + if ( ! CDROM_GetIdeInterface(dev, &portnum, &targetid)) + return STATUS_NOT_SUPPORTED; + + address->PortNumber = portnum; + address->TargetId = targetid; + return 0; +} + +/****************************************************************** * CDROM_DeviceIoControl * * @@ -892,6 +967,7 @@ else error = CDROM_SetTray(dev, TRUE); break; + case IOCTL_CDROM_MEDIA_REMOVAL: case IOCTL_DISK_MEDIA_REMOVAL: case IOCTL_STORAGE_MEDIA_REMOVAL: case IOCTL_STORAGE_EJECTION_CONTROL: @@ -1008,6 +1084,12 @@ else if (lpOutBuffer == NULL) error = STATUS_BUFFER_TOO_SMALL; else error = CDROM_RawRead(dev, (const RAW_READ_INFO*)lpInBuffer, lpOutBuffer, nOutBufferSize, &sz); + break; + case IOCTL_SCSI_GET_ADDRESS: + sz = sizeof(SCSI_ADDRESS); + if (lpInBuffer != NULL || nInBufferSize != 0) error = STATUS_INVALID_PARAMETER; + else if (nOutBufferSize < sz) error = STATUS_BUFFER_TOO_SMALL; + else error = CDROM_GetAddress(dev, (SCSI_ADDRESS*)lpOutBuffer); break; default: FIXME("Unsupported IOCTL %lx\n", dwIoControlCode); Index: files/drive.c =================================================================== RCS file: /home/wine/wine/files/drive.c,v retrieving revision 1.68 diff -u -u -r1.68 drive.c --- files/drive.c 22 Apr 2002 22:34:00 -0000 1.68 +++ files/drive.c 1 May 2002 00:19:20 -0000 @@ -31,12 +31,16 @@ #include <string.h> #include <stdio.h> #include <stdlib.h> +#include <sys/ioctl.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <errno.h> #include <unistd.h> +#ifdef HAVE_LINUX_HDREG_H +# include <linux/hdreg.h> +#endif #ifdef HAVE_SYS_PARAM_H # include <sys/param.h> #endif @@ -166,6 +170,136 @@ return DRIVE_CASE_PRESERVING; } +extern int CDROM_GetIdeInterface(int dev, int* iface, int* device); + +/****************************************************************** + * CDROM_InitRegistry + * + * Initializes registry to contain scsi info about the cdrom in NT. + * All devices (even not real scsi ones) have this info in NT. + * TODO: for now it only works for non scsi devices + * NOTE: programs usually read these registry entries after sending the + * IOCTL_SCSI_GET_ADDRESS ioctl to the cdrom + */ +static void CDROM_InitRegistry(int dev) { + int portnum, targetid; + int dma; + OBJECT_ATTRIBUTES attr; + UNICODE_STRING nameW; + WCHAR dataW[50]; + DWORD lenW; + char buffer[40]; + DWORD value; + const char *data; + HKEY scsiKey; + HKEY portKey; + HKEY busKey; + HKEY targetKey; + DWORD disp; + + attr.Length = sizeof(attr); + attr.RootDirectory = HKEY_LOCAL_MACHINE; + attr.ObjectName = &nameW; + attr.Attributes = 0; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + + if ( ! CDROM_GetIdeInterface(dev, &portnum, &targetid)) + return; + + /* Ensure there is Scsi key */ + if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "HARDWARE\\DEVICEMAP\\Scsi" ) || + NtCreateKey( &scsiKey, KEY_ALL_ACCESS, &attr, 0, + NULL, REG_OPTION_VOLATILE, &disp )) + { + ERR("Cannot create DEVICEMAP\\Scsi registry key\n" ); + return; + } + RtlFreeUnicodeString( &nameW ); + + snprintf(buffer,40,"Scsi Port %d",portnum); + attr.RootDirectory = scsiKey; + if (!RtlCreateUnicodeStringFromAsciiz( &nameW, buffer ) || + NtCreateKey( &portKey, KEY_ALL_ACCESS, &attr, 0, + NULL, REG_OPTION_VOLATILE, &disp )) + { + ERR("Cannot create DEVICEMAP\\Scsi Port registry key\n" ); + return; + } + + RtlCreateUnicodeStringFromAsciiz( &nameW, "Driver" ); + data = "atapi"; + RtlMultiByteToUnicodeN( dataW, 50, &lenW, data, strlen(data)); + NtSetValueKey( portKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW ); + RtlFreeUnicodeString( &nameW ); + value = 10; + RtlCreateUnicodeStringFromAsciiz( &nameW, "FirstBusTimeScanInMs" ); + NtSetValueKey( portKey,&nameW, 0, REG_DWORD, (BYTE *)&value, sizeof(DWORD)); + RtlFreeUnicodeString( &nameW ); + value = 0; + if (ioctl(dev,HDIO_GET_DMA, &dma) != -1) { + value = dma; + TRACE("setting dma to %lx\n", value); + } + RtlCreateUnicodeStringFromAsciiz( &nameW, "DMAEnabled" ); + NtSetValueKey( portKey,&nameW, 0, REG_DWORD, (BYTE *)&value, sizeof(DWORD)); + RtlFreeUnicodeString( &nameW ); + + attr.RootDirectory = portKey; + if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Scsi Bus 0" ) || + NtCreateKey( &busKey, KEY_ALL_ACCESS, &attr, 0, + NULL, REG_OPTION_VOLATILE, &disp )) + { + ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus registry key\n" ); + return; + } + RtlFreeUnicodeString( &nameW ); + + attr.RootDirectory = busKey; + if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Initiator Id 255" ) || + NtCreateKey( &targetKey, KEY_ALL_ACCESS, &attr, 0, + NULL, REG_OPTION_VOLATILE, &disp )) + { + ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus\\Initiator Id 255 registry key\n" ); + return; + } + RtlFreeUnicodeString( &nameW ); + NtClose( targetKey ); + + snprintf(buffer,40,"Target Id %d", targetid); + attr.RootDirectory = busKey; + if (!RtlCreateUnicodeStringFromAsciiz( &nameW, buffer ) || + NtCreateKey( &targetKey, KEY_ALL_ACCESS, &attr, 0, + NULL, REG_OPTION_VOLATILE, &disp )) + { + ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus 0\\Target Id registry key\n" ); + return; + } + RtlFreeUnicodeString( &nameW ); + + RtlCreateUnicodeStringFromAsciiz( &nameW, "Type" ); + data = "CdRomPeripheral"; + RtlMultiByteToUnicodeN( dataW, 50, &lenW, data, strlen(data)); + NtSetValueKey( targetKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW ); + RtlFreeUnicodeString( &nameW ); + /* FIXME - maybe read the real identifier?? */ + RtlCreateUnicodeStringFromAsciiz( &nameW, "Identifier" ); + data = "Wine CDROM"; + RtlMultiByteToUnicodeN( dataW, 50, &lenW, data, strlen(data)); + NtSetValueKey( targetKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW ); + RtlFreeUnicodeString( &nameW ); + /* FIXME - we always use Cdrom0 - do not know about the nt behaviour */ + RtlCreateUnicodeStringFromAsciiz( &nameW, "DeviceName" ); + data = "Cdrom0"; + RtlMultiByteToUnicodeN( dataW, 50, &lenW, data, strlen(data)); + NtSetValueKey( targetKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW ); + RtlFreeUnicodeString( &nameW ); + + NtClose( targetKey ); + NtClose( busKey ); + NtClose( portKey ); + NtClose( scsiKey ); +} /*********************************************************************** * DRIVE_Init @@ -250,9 +384,17 @@ buffer, sizeof(buffer) ); if (buffer[0]) { + int cd_fd; drive->device = heap_strdup( buffer ); if (PROFILE_GetWineIniBool( name, "ReadVolInfo", 1)) drive->flags |= DRIVE_READ_VOL_INFO; + if (drive->type == DRIVE_CDROM) + { + if ((cd_fd = open(buffer,O_RDONLY|O_NONBLOCK)) != -1) { + CDROM_InitRegistry(cd_fd); + close(cd_fd); + } + } } /* Get the FailReadOnly flag */ Index: include/config.h.in =================================================================== RCS file: /home/wine/wine/include/config.h.in,v retrieving revision 1.110 diff -u -u -r1.110 config.h.in --- include/config.h.in 26 Apr 2002 19:05:17 -0000 1.110 +++ include/config.h.in 1 May 2002 00:19:28 -0000 @@ -242,12 +242,18 @@ /* Define if Linux-style gethostbyname_r and gethostbyaddr_r are available */ #undef HAVE_LINUX_GETHOSTBYNAME_R_6 +/* Define to 1 if you have the <linux/hdreg.h> header file. */ +#undef HAVE_LINUX_HDREG_H + /* Define to 1 if you have the <linux/input.h> header file. */ #undef HAVE_LINUX_INPUT_H /* 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/major.h> header file. */ +#undef HAVE_LINUX_MAJOR_H + /* Define to 1 if you have the <linux/serial.h> header file. */ #undef HAVE_LINUX_SERIAL_H @@ -346,6 +352,9 @@ /* Define to 1 if you have the <sched.h> header file. */ #undef HAVE_SCHED_H + +/* Define to 1 if you have the <scsi/sg.h> header file. */ +#undef HAVE_SCSI_SG_H /* Define to 1 if you have the `select' function. */ #undef HAVE_SELECT
/* * 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_ */