Hi,

I am working on a small program (in Windows) to control the Speed of a CD Drive. So far I have used some of the IOCTL_CDROM_... and IOCTL_STORAGE... Control codes to control the drive by opening/closing it etc. I have now developed a small piece to also control the Speed but I seem to have some troubles with it.
I used the IOCTL_CDROM_SET_SPEED Command in the DeviceIoControl Function but there is a problem with the code, anyways here is my code, first the BOOL function:

#include <stdio.h>
#include <winioctl.h>
#include <windows.h>
#include "ntddcdrm.h"


BOOL SetSpeed(CDROM_SET_SPEED *val)
{
	HANDLE hDevice;		//handle to the drive to be examined
	BOOL bResult;		//result flag
	DWORD junk;			//discard results

	hDevice  = CreateFile(TEXT("\\\\.\\D:"),	//Drive to open
					GENERIC_READ|GENERIC_WRITE,							//Access to the drive
					FILE_SHARE_READ|FILE_SHARE_WRITE, //Share mode
					NULL,						//Security
					OPEN_EXISTING,				//Disposition
					0,							//file attributes
					NULL);						// do not copy file attribution
	if (hDevice == INVALID_HANDLE_VALUE)		//Cannot open the drive
	{
		printf("Invalid Handle Value\n");
		return(FALSE);
	}

	bResult = DeviceIoControl(hDevice, 
				IOCTL_CDROM_SET_SPEED,		//operation to perform
				val, sizeof(*val),						//no input buffer
				NULL, 0,				//output buffer
				&junk,							//#bytes returned
				(LPOVERLAPPED) NULL);			//synchronous I/O		

	CloseHandle(hDevice);

	return (bResult);
}

(Most of the basic code is from a sample offered on the MSDN Website)
And inside my int main()

CDROM_SET_SPEED val;
	BOOL bResult;
	USHORT read=1500;
	USHORT write=1500;

        val.RequestType = CdromSetSpeed;
	val.RotationControl = CdromDefaultRotation;
	val.ReadSpeed=read;
	val.WriteSpeed=write;

	bResult = SetSpeed(&val);
	if(bResult)
	{
		printf("CD Drive is spinning up\n");
	}
	else
	{
		printf("SetSpeed failed. Error %ld.\n",GetLastError());
	}

I know for sure the problem is in calling the DeviceIoControl function because the BOOL returns a false. The CreateFile function executes successfully.
If anyone could give me any ideas of what might be the problem that would be greatly appreciated.

What is the upper range of USHORT on your system? (check limits.h, etc.) Could you be overflowing the upper limit of it, or of the CD drive?

According to the MSDN Library the CDROM_SET_SPEED Structure (already predefined in a Microsoft header file (ntddcdrm.h)) takes the USHORT variable as the speed of the drive in kbps so values of this magnitude should be working, but I have also tried with smaller values, and it still will not work.

P.S. The program compiles properly.

The obvious trouble shooting step seems to be to try the sample code from MSDN, just as it is, and then substitute various values for the speed.

For each value, find out if it's working correctly. Record all the values that you test - good or bad. Then use the good values only, as possible speeds for your program to set.

That's the next step for the software portion, but I'm not satisfied with your lack of info from the CD manufacturer. CD drives haven't changed much over the years, so even though your CD drive is old, the manufacturer should be able to tell you what speeds are possible, and how to set them for that speed, in your program.

If you want the answers to this, you're going to have to be aggressive in seeking it out. This isn't the kind of info that a software forum is likely to be able to provide, unless they have someone familiar with low level drivers.

Your code runs without error on my Win7/vs2010 system, although the cdrom drive doesn't seem to do anything.
This command is new. Your cdrom.sys driver may not have the new commands.

For explanation of system errors, I find the following function useful:

static inline void showError(const _TCHAR *source=0)
{
    DWORD e=GetLastError();
    LPTSTR buf=0;
    DWORD fmt= FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM
        ,0,e,0, (LPTSTR)&buf,1,0);
    if(fmt)
    {
        if(!source){_tprintf(L"%s\n",buf);}
        else _tprintf(TEXT("%s: %s\n"),source,buf);
    }
    else _tprintf(TEXT("problem formatting message code: %ld\n"),e);
    if(buf)LocalFree(buf);
}

Edited 3 Years Ago by Reverend Jim: Fixed formatting

Thanks for the responses.
When I run the code on my Win7 Laptop I get the same response. The code runs perfectly but no response from the Drive.
The getlasterror function returns error 50 (on an XP computer) which corresponds to
"The request is not supported" on one XP Computer and Error 1 "Incorrect function" on the other XP Computer.
Could it be possible that certain drives only work with specific speeds? (I mean every drive should be able to run at 1X (150 kbps))
Anyways, I will try to find more from the manufacturer (ASUS has been pretty hard to get to).

CDROM_SET_SPEED may only be useful for the same process reading or writing the data. I have had better luck with SET_STREAMING:


HANDLE hDevice= CreateFile(TEXT("\\\\.\\D:"),
GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,//Security
OPEN_EXISTING,
0,//file attributes
NULL);
CDROM_SET_STREAMING s;
s.RequestType=CdromSetStreaming;
s.ReadSize= 0x2000; // in kbytes (0xffff==optimal)
s.ReadTime= 1000; // in ms
s.WriteSize= 0xffff;
s.WriteTime=1000;
s.StartLba= ~0x0i64;
s.EndLba= ~0x0i64;
s.RotationControl=CdromDefaultRotation;
s.RestoreDefaults= false;
s.SetExact= false;
s.RandomAccess= false;
s.Persistent= true;

// results variables
BOOL bResult;
DWORD dwBytesReturned;

bResult = DeviceIoControl(hDevice
, IOCTL_CDROM_SET_SPEED
, &s, sizeof(s)
, NULL, 0
, &dwBytesReturned
, NULL // (blocking call)
);

Thank you for the idea, I am trying that code right now, what does the "Startlba" and "Endlab" mean and why are they the same address? How do you determine the Starting block?
Thanks

LBA==Logical Block Address, for commands that specify physical locations on the drive. I can't find any place that mentions if they are used for this command or not. I max them both out and it doesn't seem to matter.
If the "Persistent" flag is set, then the changes stay active even when you change media. The "RestoreDefaults" flag seems to ignore everything else and reset the device to its normal values.

I tried the SET_STREAMING Command on XP and still get the same error. It does seem to work in Vista and Windows 7 though. So there seems to be a compatibility problem with XP

This question has already been answered. Start a new discussion instead.