diff --git a/dlls/kernel/oldconfig.c b/dlls/kernel/oldconfig.c index 2756e7c8eeb..3f612c87459 100644 --- a/dlls/kernel/oldconfig.c +++ b/dlls/kernel/oldconfig.c @@ -25,12 +25,14 @@ #include "wine/port.h" #include +#include #include #include #ifdef HAVE_SYS_STAT_H # include #endif #include +#include #ifdef HAVE_SYS_IOCTL_H #include #endif @@ -88,18 +90,20 @@ static ULONG allocate_default_keys(void) return dispos; } - /****************************************************************** - * init_cdrom_registry + * create_scsi_entry * * 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 init_cdrom_registry( HANDLE handle ) +static void create_scsi_entry( PSCSI_ADDRESS scsi_addr, LPSTR lpDriver, UINT uDriveType, + LPSTR lpDriveName, LPSTR lpUnixDeviceName ) { + static UCHAR uCdromNumber = 0; + static UCHAR uTapeNumber = 0; + OBJECT_ATTRIBUTES attr; UNICODE_STRING nameW; WCHAR dataW[50]; @@ -111,13 +115,8 @@ static void init_cdrom_registry( HANDLE handle ) HANDLE portKey; HANDLE busKey; HANDLE targetKey; + HANDLE lunKey; DWORD disp; - IO_STATUS_BLOCK io; - SCSI_ADDRESS scsi_addr; - - if (NtDeviceIoControlFile( handle, 0, NULL, NULL, &io, IOCTL_SCSI_GET_ADDRESS, - NULL, 0, &scsi_addr, sizeof(scsi_addr) )) - return; attr.Length = sizeof(attr); attr.RootDirectory = 0; @@ -136,7 +135,7 @@ static void init_cdrom_registry( HANDLE handle ) } RtlFreeUnicodeString( &nameW ); - snprintf(buffer,sizeof(buffer),"Scsi Port %d",scsi_addr.PortNumber); + snprintf(buffer,sizeof(buffer),"Scsi Port %d",scsi_addr->PortNumber); attr.RootDirectory = scsiKey; if (!RtlCreateUnicodeStringFromAsciiz( &nameW, buffer ) || NtCreateKey( &portKey, KEY_ALL_ACCESS, &attr, 0, @@ -148,30 +147,34 @@ static void init_cdrom_registry( HANDLE handle ) RtlFreeUnicodeString( &nameW ); RtlCreateUnicodeStringFromAsciiz( &nameW, "Driver" ); - data = "atapi"; - RtlMultiByteToUnicodeN( dataW, 50, &lenW, data, strlen(data)); + RtlMultiByteToUnicodeN( dataW, sizeof(dataW), &lenW, lpDriver, strlen(lpDriver)); 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; -#ifdef HDIO_GET_DMA - { - int fd, dma; - if (!wine_server_handle_to_fd( handle, 0, &fd, NULL )) - { - if (ioctl(fd,HDIO_GET_DMA, &dma) != -1) value = dma; - wine_server_release_fd( handle, fd ); - } - } -#endif - RtlCreateUnicodeStringFromAsciiz( &nameW, "DMAEnabled" ); - NtSetValueKey( portKey,&nameW, 0, REG_DWORD, (BYTE *)&value, sizeof(DWORD)); - RtlFreeUnicodeString( &nameW ); - snprintf(buffer,40,"Scsi Bus %d", scsi_addr.PathId); + value = 0; + if (strcmp(lpDriver, "atapi") == 0) + { +#ifdef HDIO_GET_DMA + int fd, dma; + + fd = open(lpUnixDeviceName, O_RDONLY|O_NONBLOCK); + if (fd) + { + if (ioctl(fd, HDIO_GET_DMA, &dma) != -1) value = dma; + close(fd); + }else + ERR("Can't open %s", buffer); +#endif + RtlCreateUnicodeStringFromAsciiz( &nameW, "DMAEnabled" ); + NtSetValueKey( portKey,&nameW, 0, REG_DWORD, (BYTE *)&value, sizeof(DWORD)); + RtlFreeUnicodeString( &nameW ); + } + + snprintf(buffer, sizeof(buffer),"Scsi Bus %d", scsi_addr->PathId); attr.RootDirectory = portKey; if (!RtlCreateUnicodeStringFromAsciiz( &nameW, buffer ) || NtCreateKey( &busKey, KEY_ALL_ACCESS, &attr, 0, @@ -183,6 +186,7 @@ static void init_cdrom_registry( HANDLE handle ) RtlFreeUnicodeString( &nameW ); attr.RootDirectory = busKey; + /* FIXME: get real controller Id for SCSI */ if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Initiator Id 255" ) || NtCreateKey( &targetKey, KEY_ALL_ACCESS, &attr, 0, NULL, REG_OPTION_VOLATILE, &disp )) @@ -193,7 +197,7 @@ static void init_cdrom_registry( HANDLE handle ) RtlFreeUnicodeString( &nameW ); NtClose( targetKey ); - snprintf(buffer,40,"Target Id %d", scsi_addr.TargetId); + snprintf(buffer, sizeof(buffer),"Target Id %d", scsi_addr->TargetId); attr.RootDirectory = busKey; if (!RtlCreateUnicodeStringFromAsciiz( &nameW, buffer ) || NtCreateKey( &targetKey, KEY_ALL_ACCESS, &attr, 0, @@ -204,47 +208,249 @@ static void init_cdrom_registry( HANDLE handle ) } 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 ); + snprintf(buffer, sizeof(buffer),"Logical Unit Id %d", scsi_addr->Lun); + attr.RootDirectory = targetKey; + if (!RtlCreateUnicodeStringFromAsciiz( &nameW, buffer ) || + NtCreateKey( &lunKey, KEY_ALL_ACCESS, &attr, 0, + NULL, REG_OPTION_VOLATILE, &disp )) + { + ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus 0\\Target Id registry key\\Logical Unit Id\n" ); + return; + } RtlFreeUnicodeString( &nameW ); + switch (uDriveType) + { + case DRIVE_NO_ROOT_DIR: + default: + data = "OtherPeripheral"; break; + case DRIVE_FIXED: + data = "DiskPeripheral"; break; + case DRIVE_REMOVABLE: + data = "TapePeripheral"; + snprintf(buffer, sizeof(buffer), "Tape%d", uTapeNumber++); + break; + case DRIVE_CDROM: + data = "CdRomPeripheral"; + snprintf(buffer, sizeof(buffer), "Cdrom%d", uCdromNumber++); + break; + } + RtlCreateUnicodeStringFromAsciiz( &nameW, "Type" ); + RtlMultiByteToUnicodeN( dataW, sizeof(dataW), &lenW, data, strlen(data)); + NtSetValueKey( lunKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW ); + RtlFreeUnicodeString( &nameW ); + + RtlCreateUnicodeStringFromAsciiz( &nameW, "Identifier" ); + RtlMultiByteToUnicodeN( dataW, sizeof(dataW), &lenW, lpDriveName, strlen(lpDriveName)); + NtSetValueKey( lunKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW ); + RtlFreeUnicodeString( &nameW ); + + if (uDriveType == DRIVE_CDROM || uDriveType == DRIVE_REMOVABLE) + { + RtlCreateUnicodeStringFromAsciiz( &nameW, "DeviceName" ); + RtlMultiByteToUnicodeN( dataW, sizeof(dataW), &lenW, buffer, strlen(buffer)); + NtSetValueKey( lunKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW ); + RtlFreeUnicodeString( &nameW ); + } + + RtlCreateUnicodeStringFromAsciiz( &nameW, "UnixDeviceName" ); + RtlMultiByteToUnicodeN( dataW, sizeof(dataW), &lenW, lpUnixDeviceName, strlen(lpUnixDeviceName)); + NtSetValueKey( lunKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW ); + RtlFreeUnicodeString( &nameW ); + + NtClose( lunKey ); NtClose( targetKey ); NtClose( busKey ); NtClose( portKey ); NtClose( scsiKey ); } +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; +} + /* create the hardware registry branch */ static void create_hardware_branch(void) { - int i; - HANDLE handle; - char drive[] = "\\\\.\\A:"; +#ifdef linux + static const char procname_ide_media[] = "/proc/ide/%s/media"; + static const char procname_ide_model[] = "/proc/ide/%s/model"; + static const char procname_scsi[] = "/proc/scsi/scsi"; + DIR *idedir; + struct dirent *dent = NULL; + FILE *procfile = NULL; + char cStr[40], cDevModel[40], cUnixDeviceName[40], read1[10] = "\0", read2[10] = "\0"; + SCSI_ADDRESS scsi_addr; + UINT nType; + struct LinuxProcScsiDevice dev; + int result = 0, nSgNumber = 0; + UCHAR uFirstSCSIPort = 0; - /* create entries for cdroms (skipping A: and B:) */ - for (i = 2; i < 26; i++) + /* Enumerate all ide devices first */ + idedir = opendir("/proc/ide"); + for (dent=readdir(idedir); dent; dent = readdir(idedir)) { - drive[4] = 'A' + i; - handle = CreateFileA( drive, 0, 0, NULL, OPEN_EXISTING, 0, 0 ); - if (handle == INVALID_HANDLE_VALUE) continue; - init_cdrom_registry( handle ); - CloseHandle( handle ); + if (strncmp(dent->d_name, "hd", 2) == 0) + { + sprintf(cStr, procname_ide_media, dent->d_name); + procfile = fopen(cStr, "r"); + if (!procfile) + { + ERR("Could not open %s\n", cStr); + continue; + } else { + fgets(cStr, sizeof(cStr), procfile); + fclose(procfile); + nType = DRIVE_UNKNOWN; + if (strncasecmp(cStr, "disk", 4) == 0) nType = DRIVE_FIXED; + if (strncasecmp(cStr, "cdrom", 5) == 0) nType = DRIVE_CDROM; + + if (nType == DRIVE_UNKNOWN) continue; + } + + sprintf(cStr, procname_ide_model, dent->d_name); + procfile = fopen(cStr, "r"); + if (!procfile) + { + ERR("Could not open %s\n", cStr); + switch (nType) + { + case DRIVE_FIXED: strcpy(cDevModel, "Wine harddisk"); break; + case DRIVE_CDROM: strcpy(cDevModel, "Wine CDROM"); break; + } + } else { + fgets(cDevModel, sizeof(cDevModel), procfile); + fclose(procfile); + cDevModel[strlen(cDevModel) - 1] = 0; + } + + sprintf(cUnixDeviceName, "/dev/%s", dent->d_name); + scsi_addr.PortNumber = (dent->d_name[2] - 'a') / 2; + scsi_addr.PathId = 0; + scsi_addr.TargetId = (dent->d_name[2] - 'a') % 2; + scsi_addr.Lun = 0; + if (scsi_addr.PortNumber + 1 > uFirstSCSIPort) + uFirstSCSIPort = scsi_addr.PortNumber + 1; + + create_scsi_entry(&scsi_addr, "atapi", nType, cDevModel, cUnixDeviceName); + } } + closedir(idedir); + + /* Now goes SCSI */ + procfile = fopen(procname_scsi, "r"); + if (!procfile) + { + TRACE("Could not open %s\n", procname_scsi); + return; + } + fgets(cStr, 40, procfile); + sscanf(cStr, "Attached %9s %9s", read1, read2); + + if (strcmp(read1, "devices:") != 0) + { + WARN("Incorrect %s format\n", procname_scsi); + fclose( procfile ); + return; + } + if (strcmp(read2, "none") == 0) + { + TRACE("No SCSI devices found in %s.\n", procname_scsi); + fclose( procfile ); + return; + } + + /* Read info for one device */ + while ((result = SCSI_getprocentry(procfile, &dev)) > 0) + { + scsi_addr.PortNumber = dev.host; + scsi_addr.PathId = dev.channel; + scsi_addr.TargetId = dev.target; + scsi_addr.Lun = dev.lun; + + scsi_addr.PortNumber += uFirstSCSIPort; + if (strncmp(dev.type, "Direct-Access", 13) == 0) nType = DRIVE_FIXED; + else if (strncmp(dev.type, "Sequential-Access", 17) == 0) nType = DRIVE_REMOVABLE; + else if (strncmp(dev.type, "CD-ROM", 6) == 0) nType = DRIVE_CDROM; + else if (strncmp(dev.type, "Processor", 9) == 0) nType = DRIVE_NO_ROOT_DIR; + else continue; + + strcpy(cDevModel, dev.vendor); + strcat(cDevModel, dev.model); + strcat(cDevModel, dev.rev); + sprintf(cUnixDeviceName, "/dev/sg%d", nSgNumber++); + /* FIXME: get real driver name */ + create_scsi_entry(&scsi_addr, "WINE SCSI", nType, cDevModel, cUnixDeviceName); + } + if( result != EOF ) + WARN("Incorrect %s format\n", procname_scsi); + fclose( procfile ); +#endif }