SCSI command 0xAD (GPCMD_READ_DVD_STRUCTURE) with the eighth byte of the command set to 0x00 (DVD_STRUCT_PHYSICAL) returns physical disc information for DVDs and blu-rays. On success, the command returns status 0, and for ordinary CDs, the command returns the error status 0x02 (SAM_STAT_CHECK_CONDITION). The format of the data returned is different for blu-rays than for DVDs, and the second byte of the command indicates whether to return DVD information or blu-ray information. (My LG WH16NS40 drive actually ignores the second byte when there is a DVD in the drive, but it returns SAM_STAT_CHECK_CONDITION when there is a blu-ray in the drive and the second byte is not 0x01.) Windows does not distinguish between DVDs and blu-rays in IOCTL_DISK_GET_MEDIA_TYPES, so if the SCSI command succeeds for either disc type, report FILE_DEVICE_DVD.
More specific media information is still not implemented.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=57790
-- v5: ntdll: Detect the optical disc type on Linux using a SCSI command.
From: Alex Henrie alexhenrie24@gmail.com
SCSI command 0x46 (GPCMD_GET_CONFIGURATION) returns in the seventh and eighth bytes the "profile" that the disc drive is currently using, which corresponds to the physical type of the disc in the drive. Profile numbers 16 and up are used for DVDs and blu-rays, and Windows does not distinguish between the two.
The GET CONFIGURATION request format, response format, and profile numbers are defined on pages 1, 2, and 7 of https://www.t10.org/ftp/t10/document.97/97-263r0.pdf and pages 66-71 of https://www.t10.org/ftp/t10/document.05/05-206r0.pdf.
More specific media information is still not implemented.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=57790 --- dlls/ntdll/unix/cdrom.c | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-)
diff --git a/dlls/ntdll/unix/cdrom.c b/dlls/ntdll/unix/cdrom.c index 5a700940ceb..af98aabb9f2 100644 --- a/dlls/ntdll/unix/cdrom.c +++ b/dlls/ntdll/unix/cdrom.c @@ -758,11 +758,37 @@ static NTSTATUS CDROM_GetDriveGeometry(int dev, int fd, DISK_GEOMETRY* dg) * CDROM_GetMediaType * */ -static NTSTATUS CDROM_GetMediaType(int dev, GET_MEDIA_TYPES* medtype) +static NTSTATUS CDROM_GetMediaType(int dev, int fd, GET_MEDIA_TYPES* medtype) { - FIXME(": faking success\n"); + FIXME("semi-stub\n"); medtype->DeviceType = FILE_DEVICE_CD_ROM; medtype->MediaInfoCount = 0; + +#if defined(HAVE_SG_IO_HDR_T_INTERFACE_ID) && defined(HAVE_LINUX_CDROM_H) + { + unsigned char drive_config[8]; + unsigned char get_config_cmd[10] = { GPCMD_GET_CONFIGURATION, 0, 0xff, 0xff, + 0, 0, 0, 0, sizeof(drive_config), 0 }; + sg_io_hdr_t iocmd = + { + .interface_id = 'S', + .dxfer_direction = SG_DXFER_FROM_DEV, + .cmd_len = sizeof(get_config_cmd), + .dxfer_len = sizeof(drive_config), + .dxferp = drive_config, + .cmdp = get_config_cmd, + .timeout = 1000, + }; + int err; + + if ((err = ioctl(fd, SG_IO, &iocmd))) + return CDROM_GetStatusCode(err); + + if (iocmd.status == 0 && (drive_config[6] || drive_config[7] >= 0x10)) + medtype->DeviceType = FILE_DEVICE_DVD; + } +#endif + return STATUS_SUCCESS; }
@@ -2908,7 +2934,7 @@ NTSTATUS cdrom_DeviceIoControl( HANDLE device, HANDLE event, PIO_APC_ROUTINE apc sz = sizeof(GET_MEDIA_TYPES); if (in_buffer != NULL || in_size != 0) status = STATUS_INVALID_PARAMETER; else if (out_size < sz) status = STATUS_BUFFER_TOO_SMALL; - else status = CDROM_GetMediaType(dev, out_buffer); + else status = CDROM_GetMediaType(dev, fd, out_buffer); break;
case IOCTL_STORAGE_GET_DEVICE_NUMBER:
On Thu Jul 10 05:49:23 2025 +0000, Alexandre Julliard wrote:
It should be possible to use a more appropriate SCSI command to do this, like GET_CONFIGURATION.
Thanks for the clarification. I've updated the patch to use GPCMD_GET_CONFIGURATION instead of GPCMD_READ_DVD_STRUCTURE.