From 0df36de5305936ab678d1eab352e0dc06bf76675 Mon Sep 17 00:00:00 2001 From: Vitaliy Margolen Date: Wed, 10 Aug 2005 10:52:22 +0000 Subject: [PATCH] Make use of now full and correct HKLM\HARDWARE\DEVICES\Scsi. --- dlls/winaspi/Makefile.in | 1 + dlls/winaspi/aspi.c | 543 ++++++++------------------------------- dlls/winaspi/winescsi.h | 5 +- 3 files changed, 111 insertions(+), 438 deletions(-) diff --git a/dlls/winaspi/Makefile.in b/dlls/winaspi/Makefile.in index d8109ec42f0..9ae9023c9e6 100644 --- a/dlls/winaspi/Makefile.in +++ b/dlls/winaspi/Makefile.in @@ -5,6 +5,7 @@ VPATH = @srcdir@ MODULE = wnaspi32.dll IMPORTLIB = libwnaspi32.$(IMPLIBEXT) IMPORTS = advapi32 kernel32 +EXTRALIBS = $(LIBUNICODE) C_SRCS = \ aspi.c \ diff --git a/dlls/winaspi/aspi.c b/dlls/winaspi/aspi.c index 91601458ba4..a87c7a16422 100644 --- a/dlls/winaspi/aspi.c +++ b/dlls/winaspi/aspi.c @@ -1,6 +1,7 @@ /************************************************************************** * ASPI routines * Copyright (C) 2000 David Elliott + * Copyright (C) 2005 Vitaliy Margolen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,7 +21,6 @@ /* These routines are to be called from either WNASPI32 or WINASPI */ /* FIXME: - * - Registry format is stupid for now.. fix that later * - No way to override automatic /proc detection, maybe provide an * HKEY_LOCAL_MACHINE\Software\Wine\Wine\Scsi regkey * - Somewhat debating an #ifdef linux... technically all this code will @@ -29,13 +29,6 @@ * aspi controllers, e-mail me if you need help. */ -/* -Registry format is currently: -HKEY_DYN_DATA - WineScsi - (default)=number of host adapters - hHHcCCtTTdDD=linux device name -*/ #include "config.h" #include "wine/port.h" @@ -61,18 +54,10 @@ HKEY_DYN_DATA #include "winescsi.h" #include "wine/debug.h" +#include "wine/unicode.h" WINE_DEFAULT_DEBUG_CHANNEL(aspi); -/* Internal function prototypes */ -static void -SCSI_GetProcinfo(void); - -#ifdef linux -static void -SCSI_MapHCtoController(void); -#endif - static void set_last_error(void) { int save_errno = errno; /* errno gets overwritten by printf */ @@ -126,78 +111,62 @@ static void set_last_error(void) errno = save_errno; } +static const WCHAR wDevicemapScsi[] = {'H','A','R','D','W','A','R','E','\\','D','E','V','I','C','E','M','A','P','\\','S','c','s','i',0}; + /* Exported functions */ -void -SCSI_Init() +int ASPI_GetNumControllers() { - /* For now we just call SCSI_GetProcinfo */ - SCSI_GetProcinfo(); -#ifdef linux - SCSI_MapHCtoController(); -#endif + HKEY hkeyScsi, hkeyPort; + DWORD i = 0, numPorts, num_ha = 0; + WCHAR wPortName[11]; + + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wDevicemapScsi, 0, + KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hkeyScsi) != ERROR_SUCCESS ) + { + ERR("Could not open HKLM\\%s\n", debugstr_w(wDevicemapScsi)); + return 0; + } + while (RegEnumKeyW(hkeyScsi, i++, wPortName, sizeof(wPortName)) == ERROR_SUCCESS) + { + if (RegOpenKeyExW(hkeyScsi, wPortName, 0, KEY_QUERY_VALUE, &hkeyPort) == ERROR_SUCCESS) + { + if (RegQueryInfoKeyW(hkeyPort, NULL, NULL, NULL, &numPorts, NULL, NULL, + NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) + { + num_ha += numPorts; + } + RegCloseKey(hkeyPort); + } + } + + RegCloseKey(hkeyScsi); + TRACE("Returning %ld host adapters\n", num_ha ); + return num_ha; } -int -ASPI_GetNumControllers() +BOOL SCSI_GetDeviceName( int h, int c, int t, int d, LPSTR devstr, LPDWORD lpcbData ) { - HKEY hkeyScsi; - HKEY hkeyControllerMap; - DWORD error; - DWORD type = REG_DWORD; - DWORD num_ha = 0; - DWORD cbData = sizeof(num_ha); + char buffer[200]; + HKEY hkeyScsi; + DWORD type; - if( RegOpenKeyExA(HKEY_DYN_DATA, KEYNAME_SCSI, 0, KEY_ALL_ACCESS, &hkeyScsi ) != ERROR_SUCCESS ) - { - ERR("Could not open HKEY_DYN_DATA\\%s\n",KEYNAME_SCSI); - return 0; - } + snprintf(buffer, sizeof(buffer), KEYNAME_SCSI, h, c, t, d); + if( RegOpenKeyExA(HKEY_LOCAL_MACHINE, buffer, 0, KEY_ALL_ACCESS, &hkeyScsi ) != ERROR_SUCCESS ) + { + ERR("Could not open HKLM\\%s\n", buffer); + return FALSE; + } - if( (error=RegOpenKeyExA(hkeyScsi, KEYNAME_SCSI_CONTROLLERMAP, 0, KEY_ALL_ACCESS, &hkeyControllerMap )) != ERROR_SUCCESS ) - { - ERR("Could not open HKEY_DYN_DATA\\%s\\%s\n", KEYNAME_SCSI, KEYNAME_SCSI_CONTROLLERMAP); - RegCloseKey(hkeyScsi); - SetLastError(error); - return 0; - } - if( RegQueryValueExA(hkeyControllerMap, NULL, NULL, &type, (LPBYTE)&num_ha, &cbData ) != ERROR_SUCCESS ) - { - ERR("Could not query value HKEY_DYN_DATA\\%s\n",KEYNAME_SCSI); - num_ha=0; - } - RegCloseKey(hkeyControllerMap); - RegCloseKey(hkeyScsi); - TRACE("Returning %ld host adapters\n", num_ha ); - return num_ha; -} + if( RegQueryValueExA(hkeyScsi, "UnixDeviceName", NULL, &type, (LPBYTE)devstr, lpcbData) != ERROR_SUCCESS ) + { + WARN("Could not query value HKLM\\%s\\UnixDeviceName\n", buffer); + RegCloseKey(hkeyScsi); + return FALSE; + } + RegCloseKey(hkeyScsi); -BOOL -SCSI_GetDeviceName( int h, int c, int t, int d, LPSTR devstr, LPDWORD lpcbData ) -{ - - char idstr[20]; - HKEY hkeyScsi; - DWORD type; - - if( RegOpenKeyExA(HKEY_DYN_DATA, KEYNAME_SCSI, 0, KEY_ALL_ACCESS, &hkeyScsi ) != ERROR_SUCCESS ) - { - ERR("Could not open HKEY_DYN_DATA\\%s\n",KEYNAME_SCSI); - return FALSE; - } - - - sprintf(idstr, "h%02dc%02dt%02dd%02d", h, c, t, d); - - if( RegQueryValueExA(hkeyScsi, idstr, NULL, &type, (LPBYTE)devstr, lpcbData) != ERROR_SUCCESS ) - { - WARN("Could not query value HKEY_DYN_DATA\\%s\\%s\n",KEYNAME_SCSI, idstr); - RegCloseKey(hkeyScsi); - return FALSE; - } - RegCloseKey(hkeyScsi); - - TRACE("scsi %s: Device name: %s\n",idstr,devstr); - return TRUE; + TRACE("Device name: %s\n", devstr); + return TRUE; } /* SCSI_GetHCforController @@ -205,99 +174,69 @@ SCSI_GetDeviceName( int h, int c, int t, int d, LPSTR devstr, LPDWORD lpcbData ) * HIWORD: Host Adapter * LOWORD: Channel */ -DWORD -ASPI_GetHCforController( int controller ) +DWORD ASPI_GetHCforController( int controller ) { - DWORD hc = 0xFFFFFFFF; - char cstr[20]; - DWORD error; - HKEY hkeyScsi; - HKEY hkeyControllerMap; - DWORD type = REG_DWORD; - DWORD cbData = sizeof(DWORD); - DWORD disposition; -#if 0 - FIXME("Please fix to map each channel of each host adapter to the proper ASPI controller number!\n"); - hc = (controller << 16); - return hc; -#endif - if( (error=RegCreateKeyExA(HKEY_DYN_DATA, KEYNAME_SCSI, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkeyScsi, &disposition )) != ERROR_SUCCESS ) - { - ERR("Could not open HKEY_DYN_DATA\\%s\n",KEYNAME_SCSI); - SetLastError(error); - return hc; - } - if( disposition != REG_OPENED_EXISTING_KEY ) - { - WARN("Created HKEY_DYN_DATA\\%s\n",KEYNAME_SCSI); - } - if( (error=RegCreateKeyExA(hkeyScsi, KEYNAME_SCSI_CONTROLLERMAP, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkeyControllerMap, &disposition )) != ERROR_SUCCESS ) - { - ERR("Could not open HKEY_DYN_DATA\\%s\\%s\n", KEYNAME_SCSI, KEYNAME_SCSI_CONTROLLERMAP); - RegCloseKey(hkeyScsi); - SetLastError(error); - return hc; - } - if( disposition != REG_OPENED_EXISTING_KEY ) - { - WARN("Created HKEY_DYN_DATA\\%s\\%s\n",KEYNAME_SCSI, KEYNAME_SCSI_CONTROLLERMAP); - } + HKEY hkeyScsi, hkeyPort; + DWORD i = 0, numPorts; + int num_ha = controller + 1; + WCHAR wPortName[11]; - sprintf(cstr, "c%02d", controller); - if( (error=RegQueryValueExA( hkeyControllerMap, cstr, 0, &type, (LPBYTE)&hc, &cbData)) != ERROR_SUCCESS ) - { - ERR("Could not open HKEY_DYN_DATA\\%s\\%s\\%s, error=%lx\n", KEYNAME_SCSI, KEYNAME_SCSI_CONTROLLERMAP, cstr, error ); - SetLastError( error ); - } - RegCloseKey(hkeyControllerMap); - RegCloseKey(hkeyScsi); - return hc; + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wDevicemapScsi, 0, + KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hkeyScsi) != ERROR_SUCCESS ) + { + ERR("Could not open HKLM\\%s\n", debugstr_w(wDevicemapScsi)); + return 0xFFFFFFFF; + } + while (RegEnumKeyW(hkeyScsi, i++, wPortName, sizeof(wPortName)) == ERROR_SUCCESS) + { + if (RegOpenKeyExW(hkeyScsi, wPortName, 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, + &hkeyPort) == ERROR_SUCCESS) + { + if (RegQueryInfoKeyW(hkeyPort, NULL, NULL, NULL, &numPorts, NULL, NULL, + NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) + { + num_ha -= numPorts; + if (num_ha <= 0) break; + } + else + RegCloseKey(hkeyPort); + } + } + RegCloseKey(hkeyScsi); + if (num_ha > 0) + { + ERR("Invalid controller(%d)\n", controller); + return 0xFFFFFFFF; + } + + if (RegEnumKeyW(hkeyPort, -num_ha, wPortName, sizeof(wPortName)) != ERROR_SUCCESS) + { + ERR("Failed to enumerate keys\n"); + RegCloseKey(hkeyPort); + return 0xFFFFFFFF; + } + RegCloseKey(hkeyPort); + + return ((--i) << 16) + atoiW(&wPortName[9]); }; -int -SCSI_OpenDevice( int h, int c, int t, int d ) +int SCSI_OpenDevice( int h, int c, int t, int d ) { - char devstr[20]; - DWORD cbData = 20; - int fd = -1; - char dainbread_linux_hack = 1; + char devstr[20]; + DWORD cbData = 20; + int fd = -1; - if(!SCSI_GetDeviceName( h, c, t, d, devstr, &cbData )) - { - WARN("Could not get device name for h%02dc%02dt%02dd%02d\n", h, c, t, d); - return -1; - } + if(!SCSI_GetDeviceName( h, c, t, d, devstr, &cbData )) + { + WARN("Could not get device name for h%02dc%02dt%02dd%02d\n", h, c, t, d); + return -1; + } -linux_hack: - TRACE("Opening device %s mode O_RDWR\n",devstr); - fd = open(devstr, O_RDWR); + TRACE("Opening device %s mode O_RDWR\n",devstr); + fd = open(devstr, O_RDWR); - if( fd < 0 ) - { - int len = strlen(devstr); - set_last_error(); /* SetLastError() to errno */ - TRACE("Open failed (%s)\n", strerror(errno)); - - /* in case of "/dev/sgX", convert from sga to sg0 - * and the other way around. - * FIXME: remove it if the distributions - * finally manage to agree on something. - * The best would probably be a complete - * rewrite of the Linux SCSI layer - * to use CAM + devfs :-) */ - if ( (dainbread_linux_hack) && - (len >= 3) && - (devstr[len-3] == 's') && (devstr[len-2] == 'g') ) - { - char *p = &devstr[len-1]; - *p = (*p >= 'a') ? *p - 'a' + '0' : *p - '0' + 'a'; - dainbread_linux_hack = 0; - TRACE("Retry with \"equivalent\" Linux device '%s'\n", devstr); - goto linux_hack; - } - } - return fd; + return fd; } #ifdef linux @@ -382,187 +321,7 @@ SCSI_LinuxDeviceIo( int fd, return TRUE; } -/* Internal functions */ -struct LinuxProcScsiDevice -{ - int host; - int channel; - int target; - int lun; - char vendor[9]; - char model[17]; - char rev[5]; - char type[33]; - int ansirev; -}; - -/* - * we need to declare white spaces explicitly via %*1[ ], - * as there are very dainbread CD-ROM devices out there - * which have their manufacturer name blanked out via spaces, - * which confuses fscanf's parsing (skips all blank spaces) - */ -static int -SCSI_getprocentry( FILE * procfile, struct LinuxProcScsiDevice * dev ) -{ - int result; - result = fscanf( procfile, - "Host:%*1[ ]scsi%d%*1[ ]Channel:%*1[ ]%d%*1[ ]Id:%*1[ ]%d%*1[ ]Lun:%*1[ ]%d\n", - &dev->host, - &dev->channel, - &dev->target, - &dev->lun ); - if( result == EOF ) - { - /* "end of entries" return, so no TRACE() here */ - return EOF; - } - if( result != 4 ) - { - ERR("bus id line scan count error\n"); - return 0; - } - result = fscanf( procfile, - " Vendor:%*1[ ]%8c%*1[ ]Model:%*1[ ]%16c%*1[ ]Rev:%*1[ ]%4c\n", - dev->vendor, - dev->model, - dev->rev ); - if( result != 3 ) - { - ERR("model line scan count error\n"); - return 0; - } - - result = fscanf( procfile, - " Type:%*3[ ]%32c%*1[ ]ANSI%*1[ ]SCSI%*1[ ]revision:%*1[ ]%d\n", - dev->type, - &dev->ansirev ); - if( result != 2 ) - { - ERR("SCSI type line scan count error\n"); - return 0; - } - /* Since we fscanf with %XXc instead of %s.. put a NULL at end */ - dev->vendor[8] = 0; - dev->model[16] = 0; - dev->rev[4] = 0; - dev->type[32] = 0; - - return 1; -} - -static void -SCSI_printprocentry( const struct LinuxProcScsiDevice * dev ) -{ - TRACE( "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n", - dev->host, - dev->channel, - dev->target, - dev->lun ); - TRACE( " Vendor: %s Model: %s Rev: %s\n", - dev->vendor, - dev->model, - dev->rev ); - TRACE( " Type: %s ANSI SCSI revision: %02d\n", - dev->type, - dev->ansirev ); -} - -static BOOL -SCSI_PutRegControllerMap( HKEY hkeyControllerMap, int num_controller, int ha, int chan) -{ - DWORD error; - char cstr[20]; - DWORD hc; - hc = (ha << 16) + chan; - sprintf(cstr, "c%02d", num_controller); - if( (error=RegSetValueExA( hkeyControllerMap, cstr, 0, REG_DWORD, (LPBYTE)&hc, sizeof(DWORD))) != ERROR_SUCCESS ) - { - ERR("Could not create HKEY_DYN_DATA\\%s\\%s\\%s\n", KEYNAME_SCSI, KEYNAME_SCSI_CONTROLLERMAP, cstr ); - } - return error; -} - -static void -SCSI_MapHCtoController() -{ - HKEY hkeyScsi; - HKEY hkeyControllerMap; - DWORD disposition; - - char idstr[20]; - DWORD cbIdStr; - int i = 0; - DWORD type = 0; - DWORD error; - - DWORD num_controller = 0; - int last_ha = -1; - int last_chan = -1; - - int ha = 0; - int chan = 0; - - if( RegCreateKeyExA(HKEY_DYN_DATA, KEYNAME_SCSI, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkeyScsi, &disposition ) != ERROR_SUCCESS ) - { - ERR("Could not open HKEY_DYN_DATA\\%s\n",KEYNAME_SCSI); - return; - } - if( disposition != REG_OPENED_EXISTING_KEY ) - { - WARN("Created HKEY_DYN_DATA\\%s\n",KEYNAME_SCSI); - } - if( RegCreateKeyExA(hkeyScsi, KEYNAME_SCSI_CONTROLLERMAP, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkeyControllerMap, &disposition ) != ERROR_SUCCESS ) - { - ERR("Could not create HKEY_DYN_DATA\\%s\\%s\n", KEYNAME_SCSI, KEYNAME_SCSI_CONTROLLERMAP); - RegCloseKey(hkeyScsi); - return; - } - - for( i=0; cbIdStr = sizeof(idstr), (error=RegEnumValueA( hkeyScsi, i, idstr, &cbIdStr, NULL, &type, NULL, NULL )) == ERROR_SUCCESS; i++ ) - { - if(idstr[0] == '\0') continue; /* skip the default value */ - - if(sscanf(idstr, "h%02dc%02dt%*02dd%*02d", &ha, &chan) != 2) { - ERR("incorrect reg. value %s\n", debugstr_a(idstr)); - continue; - } - - if( last_ha < ha ) - { /* Next HA */ - last_ha = ha; - last_chan = chan; - SCSI_PutRegControllerMap( hkeyControllerMap, num_controller, ha, chan); - num_controller++; - } - else if( last_ha > ha ) - { - FIXME("Expected registry to be sorted\n"); - } - /* last_ha == ha */ - else if( last_chan < chan ) - { - last_chan = chan; - SCSI_PutRegControllerMap( hkeyControllerMap, num_controller, ha, chan); - num_controller++; - } - else if( last_chan > chan ) - { - FIXME("Expected registry to be sorted\n"); - } - /* else last_ha == ha && last_chan == chan so do nothing */ - } - /* Set (default) value to number of controllers */ - if( RegSetValueExA(hkeyControllerMap, NULL, 0, REG_DWORD, (LPBYTE)&num_controller, sizeof(DWORD) ) != ERROR_SUCCESS ) - { - ERR("Could not set value HKEY_DYN_DATA\\%s\\%s\n",KEYNAME_SCSI, KEYNAME_SCSI_CONTROLLERMAP); - } - RegCloseKey(hkeyControllerMap); - RegCloseKey(hkeyScsi); - return; -} - -static int SCSI_Linux_CheckDevices(void) +static void SCSI_Linux_CheckDevices(void) { DIR *devdir; struct dirent *dent = NULL; @@ -578,100 +337,14 @@ static int SCSI_Linux_CheckDevices(void) if (dent == NULL) { TRACE("WARNING: You don't have any /dev/sgX generic scsi devices ! \"man MAKEDEV\" !\n"); - return 0; + return; } - return 1; } #endif -static void -SCSI_GetProcinfo() -/* I'll admit, this function is somewhat of a mess... it was originally - * designed to make some sort of linked list then I realized that - * HKEY_DYN_DATA would be a lot less messy - */ +void SCSI_Init(void) { #ifdef linux - static const char procname[] = "/proc/scsi/scsi"; - FILE * procfile = NULL; - - char read_line[40], read1[10] = "\0", read2[10] = "\0"; - int result = 0; - - struct LinuxProcScsiDevice dev; - - char idstr[20]; - char devstr[20]; - - int devnum=0; - int num_ha = 0; - - HKEY hkeyScsi; - DWORD disposition; - - /* Check whether user has generic scsi devices at all */ - if (!(SCSI_Linux_CheckDevices())) - return; - - procfile = fopen( procname, "r" ); - if( !procfile ) - { - ERR("Could not open %s\n", procname); - return; - } - - fgets(read_line, 40, procfile); - sscanf( read_line, "Attached %9s %9s", read1, read2); - - if(strcmp(read1, "devices:")) - { - ERR("Incorrect %s format\n", procname); - return; - } - - if(!(strcmp(read2, "none"))) - { - ERR("No devices found in %s. Make sure you loaded your SCSI driver or set up ide-scsi emulation for your IDE device if this app needs it !\n", procname); - return; - } - - if( RegCreateKeyExA(HKEY_DYN_DATA, KEYNAME_SCSI, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkeyScsi, &disposition ) != ERROR_SUCCESS ) - { - ERR("Could not create HKEY_DYN_DATA\\%s\n",KEYNAME_SCSI); - return; - } - - /* Read info for one device */ - while( (result = SCSI_getprocentry(procfile, &dev)) > 0 ) - { - /* Add to registry */ - - sprintf(idstr, "h%02dc%02dt%02dd%02d", dev.host, dev.channel, dev.target, dev.lun); - sprintf(devstr, "/dev/sg%c", 'a'+devnum); - if( RegSetValueExA(hkeyScsi, idstr, 0, REG_SZ, (LPBYTE)devstr, strlen(devstr)+1 ) != ERROR_SUCCESS ) - { - ERR("Could not set value HKEY_DYN_DATA\\%s\\%s\n",KEYNAME_SCSI, idstr); - } - - /* Debug output */ - SCSI_printprocentry( &dev ); - - /* FIXME: We *REALLY* need number of controllers.. not ha */ - /* num of hostadapters is highest ha + 1 */ - if( dev.host >= num_ha ) - num_ha = dev.host+1; - devnum++; - } /* while(1) */ - if( result != EOF ) - { - ERR("Sorry, incorrect %s format\n", procname); - } - fclose( procfile ); - if( RegSetValueExA(hkeyScsi, NULL, 0, REG_DWORD, (LPBYTE)&num_ha, sizeof(num_ha) ) != ERROR_SUCCESS ) - { - ERR("Could not set value HKEY_DYN_DATA\\%s\n",KEYNAME_SCSI); - } - RegCloseKey(hkeyScsi); - return; + SCSI_Linux_CheckDevices(); #endif } diff --git a/dlls/winaspi/winescsi.h b/dlls/winaspi/winescsi.h index aeb12b007b3..67aad6391a2 100644 --- a/dlls/winaspi/winescsi.h +++ b/dlls/winaspi/winescsi.h @@ -52,9 +52,8 @@ struct sg_header #endif -/* RegKey used for SCSI info under HKEY_DYN_DATA */ -#define KEYNAME_SCSI "WineScsi" -#define KEYNAME_SCSI_CONTROLLERMAP "ControllerMap" +/* RegKey used for SCSI info under HKLM */ +#define KEYNAME_SCSI "HARDWARE\\DEVICEMAP\\Scsi\\Scsi Port %d\\Scsi Bus %d\\Target Id %d\\Logical Unit Id %d" /* Function prototypes from dlls/wnaspi32/aspi.c */ void