Showing posts with label USB. Show all posts
Showing posts with label USB. Show all posts

Tuesday, 29 June 2010

Windows Embedded CE: USB memory stick fix part 2

Hi foks,

Following up on my previous post about USB memory stick fixes; here is another fix for direct access of USB memory sticks. Again, the files mentioned reside under _PUBLICROOT\COMMON\OAK\DRIVERS\USB\CLASS\STORAGE\DISK\SCSI2. Be sure to clone the respective files to your Platform before altering them!

4 issues with direct access USB memory sticks

In the function GetMediumInfo in disk.c there are some USB memory sticks that do not recover well from the call to either of the ScsiModeSense6/ScsiModeSense10 commands which are used to retrieve the device type as well as the state of the write protect bit. Neither of these commands are necessary according to the SCSI-2 specification, anyway.

Fix:

Since the working USB memory sticks seem to return 0x80 as the pDevice->MediumType we will also set the medium type to 0x80 for direct access USB memory sticks. In addition we need to disable the write protect bit.

Replace the if statement following the
// determine medium type
comment with:

// USB Memory Stick fix:
//

if (SCSI_DEVICE_UNKNOWN != pDevice->DeviceType &&
SCSI_MEDIUM_UNKNOWN == pDevice->MediumType )
{
if(SCSI_DEVICE_DIRECT_ACCESS == pDevice->DeviceType)
{
DEBUGMSG(ZONE_TRACE,
(TEXT("Device type: Direct Access => force medium type\n") ));
// set device type to 0x80
pDevice->MediumType = 0x80;
// disable write protect
pDevice->Flags.WriteProtect = 0;
}
else
{
dwErr = ScsiModeSense6(pDevice, Lun);

if (ERROR_SUCCESS != dwErr)
{
TRANSPORT_DATA tData;
UCHAR senseData[18];

tData.TransferLength = 0;
tData.RequestLength = sizeof(senseData);
tData.DataBlock = senseData;
memset(senseData,0,sizeof(senseData));

dwErr = ScsiRequestSense(pDevice, &tData, Lun);

dwErr = ScsiModeSense10(pDevice, Lun);

if (ERROR_SUCCESS != dwErr)
{
break;
}
}
}
}

Have fun!
Read more! Post this to a friend!

Wednesday, 16 June 2010

Windows Embedded CE: USB memory stick fix

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!

Friday, 11 July 2008

Windows CE: USB: Considerations when using EHCI and OHCI in the same image

If your device has a USB host controller with both EHCI (USB 2.0 host controller) and OHCI (USB 1.1 host controller) components (e.g. NEC 720101), communication always starts with EHCI and is handed over to OHCI if an OHCI device is detected.

Since the standard EHCI and the OHCI drivers both have the same load order in the registry, either one of them can load first. Both, EHCI and OHCI drivers have their own HubStatusChangeThread, which is responsible for detecting insertion and removal of USB devices. Normally, every attach (or detach) is handled by the EHCI driver. If the EHCI driver detects that the attached device is an OHCI device it hands it over to the OHCI driver to handle the attach.

A problem occurs when the OHCI driver loads before the EHCI driver. In that case the OHCI HubStatusChangeThread will also start first. If a device is attached to the USB host controller port before the EHCI HubStatusChangeThread is loaded, the OHCI driver will handle the attach. This behavior results in a slower boot time of the device or even a crash or freeze of the device while booting depending on whether the EHCI HubStatusChangeThread is loaded during the OHCI attach or after.

One approach to solve this dilemma is to stall the start of the OHCI HubStatusChangeThread until the EHCI HubStatusChangeThread is loaded. This can be done using a named event:

1. In the OHCI CHub::HubStatusChangeThreadStub create a named, non-signaled event and wait for that event with WaitForSingleObject right before the
return ((CHub*)context)->HubStatusChangeThread(); statement.
2. In the EHCI CHub::HubStatusChangeThreadStub create the same named, non-signaled event and signal the event with SetEvent right before the
return ((CHub*)context)->HubStatusChangeThread(); statement.


Have fun!
Read more! Post this to a friend!