Hi folks,
those of you who have done some work with the Windows Embedded CE USB host controller know that countless hours/days/weeks/month can be spent improving it.
One problem that I have often heard about is the USB stick support, or the lack of it. Initially about 50% of USB sticks do not work. But with these simple improvements up to about 90% of the USB sticks will work. All the mentioned files reside under
_PUBLICROOT\COMMON\OAK\DRIVERS\USB\CLASS\STORAGE\DISK\SCSI2. Be sure to
clone the respective files to your Platform before altering them.
1 Sending commands to device before it is available:
In most cases, the problem seems to be that the HCD tries to communicate with the device before it is available. This can be tested by inserting the device just enough for the power LED to blink, then after waiting a short time inserting the device fully. The device should work now.
The
MediaChangeThread in
disk.c polls for presence of USB devices, but it seems that in this case commands are sent to the device before
pDevice->Flags.MediumPresent is set by the
MediaChangeThread.
Fix:
There is a bug in
disk.c: in the function
DSK_IOControl in the
DISK_IOCTL_GETINFO case in the
if (pDevice->Flags.MediumPresent == FALSE) statement the
memset statement has the last 2 parameters switched:
if (pDevice->Flags.MediumPresent == FALSE)
{
DEBUGMSG(ZONE_ERR,
(TEXT( "Usbdisk6!DSK_IOControl> IOCTL_GET_INFO;
media not present\r\n"
)));
// USB Memory Stick fix:
//
// BUG: last 2 parameters of memset were switched
memset((PVOID)&pDevice->DiskInfo, 0, sizeof(DISK_INFO));
memcpy((PVOID)pBuf, (PVOID)&pDevice->DiskInfo,
sizeof(DISK_INFO));
bRc = TRUE;
}
Also in
disk.c, the function
GetMediumInfo should return immediately if no device is present (
if (!pDevice->Flags.MediumPresent)):
if (!pDevice->Flags.MediumPresent)
{
// USB Memory Stick fix:
//
// return here immediately since it will
// probably fail anyway
// but some devices do not recover well here!
break;
/*
DISK_INFO di = {0};
dwErr = ScsiReadCapacity(pDevice, &di, Lun);
if (ERROR_SUCCESS != dwErr)
break;
*/
}
Last but not least in the function
ScsiTestUnitReady in
scsi2.c,
ScsiGetSenseData needs to be recalled upon failure after waiting a couple of milliseconds:
DWORD dwCount;
…
// USB Memory Stick fix:
for(dwCount = 0; dwCount < 50; dwCount ++)
{
dwErr = ScsiGetSenseData( pDevice, Lun );
DEBUGMSG(ZONE_ERR,(TEXT
("ScsiTestUnitReady ERROR:%d\n"), dwErr));
SetLastError(dwErr);
if ( dwErr == ERROR_SUCCESS )
{
break;
}
Sleep(50);
}
NOTE:
It should be enough to retry
ScsiGetSenseData once, since it will return the error state of the last command forcing the second call to succeed.
2 Unhandled case in SENSE_UNIT_ATTENTION:
In the function
ScsiGetSenseData in
scsi2.c, some devices report an unhandled
ASC in the
SENSE_UNIT_ATTENTION case. The Unhandled
ASC is
0x3A which is the code for
ASC_MEDIUM_NOT_PRESENT. The spec does not state this as a valid responds to the
SENSE_UNIT_ATTENTION command, nevertheless some devices report it.
Fix:
To take this behaviour into account, add the code used for the
ASC_MEDIUM_NOT_PRESENT case to
SENSE_UNIT_ATTENTION from the
SENSE_NOT_READY command:
case ASC_MEDIUM_NOT_PRESENT :
pDevice->Flags.MediumPresent = FALSE;
pDevice->Flags.MediumChanged = TRUE;
pDevice->MediumType = SCSI_MEDIUM_UNKNOWN;
memset(&pDevice->DiskInfo, 0, sizeof(DISK_INFO) );
dwErr = DISK_REMOVED_ERROR;
break;
This causes the function
ScsiTestUnitReady to retry the operation which is not according to spec at this point.
3 The length field of the SCSI_MODE_SENSE6 command is 0
In
scsi.c in the function
ScsiModeSense6, the length field (
bCDB[4]) of the
SCSI_MODE_SENSE6 command is not set and therefore 0. All devices except Sony and Freecom accept or ignore this fact.
Fix:
Set
bCDB[4] for the
SCSI_MODE_SENSE6 command. But setting it to:
bCDB[4] = sizeof(bDataBlock) will result in
0x200 which is a
0 byte.
So better set it to something like:
bCDB[4] = 0xFF;
See also my post "Windows Embedded CE: USB memory stick fix part 2".
Have fun!
Read more!
Post this to a friend!