Trying to figure out how to implement my WINC like compatibility layer. Going the emulation way is probably not so smart. We should not use the kernel but rather hook native functions in the Exec calls.
// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// Implementation of generic finite state machine state
//
//
/**
@file
@internalTechnology
*/
#include <f32file.h>
#include <testusbc.h>
#include "tstate.h"
#include "t_ms_main.h"
#include "scsicmdbuilder.h"
#include "cpropertywatch.h"
_LIT(KMsFs, "MassStorageFileSystem");
GLREF_D RFs fs;
GLREF_D TInt removalDrvNo;
GLREF_D TUint8 testLun;
GLDEF_D TBuf8<KCbwLength> cbwBuf;
GLDEF_D TBuf8<KCswLength> cswBuf;
GLDEF_D TInt dCBWTag = 1234567; // arbitrary, any number would do for this test.
GLDEF_D RDevTestUsbcClient usbcClient;
/**
Unmount FAT and mount MSFS.
@param driveNumber
*/
LOCAL_C void MountMsFs(TInt driveNumber)
{
test.Printf(_L("MountMsFs driveNumber=%d\n"), driveNumber);
TInt err = KErrNone;
TFileName oldFs;
err = fs.FileSystemName(oldFs, driveNumber);
test.Printf(_L("FAT file system name %S; error code %d\n"), &oldFs, err);
test(err == KErrNone || err == KErrNotFound);
if(err==KErrNone)
{
test.Printf(_L("Unmounting FAT FS %S\n"), &oldFs);
err = fs.DismountFileSystem(oldFs, driveNumber);
test.Printf(_L("%S Dismount %c: %d\n"), &oldFs,'A' + driveNumber, err);
test(err == KErrNone);
}
test.Printf(_L("Mounting MSFS\n"));
err = fs.MountFileSystem(KMsFs, driveNumber);
test.Printf(_L("MSFS Mount %c: %d\n"), 'A' + driveNumber, err);
}
/**
Unmount MSFS and mount FAT.
@param driveNumber
*/
LOCAL_C void UnmountMsFs(TInt driveNumber)
{
test.Printf(_L("UnmountMsFs driveNumber=%d\n"), driveNumber);
TInt err = fs.DismountFileSystem(KMsFs, driveNumber);
test.Printf(_L("MSFS Dismount:%d\n"), err);
test(err == KErrNone);
err = fs.MountFileSystem(_L("FAT"), driveNumber);
test.Printf(_L("FAT Mount: %d\n"), err);
}
LOCAL_C TBool SendAndReceive(TInt aStatus = 0)
{
test.Printf(_L("SendAndReceive\n"));
TRequestStatus status;
usbcClient.HostWrite(status, EEndpoint1, cbwBuf, KCbwLength);
User::WaitForRequest(status);
test(KErrNone == status.Int());
// Read CSW
test.Printf(_L("Reading CSW\n"));
usbcClient.HostRead(status, EEndpoint2, cswBuf, KCswLength);
User::WaitForRequest(status);
test(KErrNone == status.Int());
// Check dCSWTag
TInt recvedCBWTag = extractInt(&cswBuf[4]);
test(dCBWTag == recvedCBWTag);
// Check bCSWStatus
TInt bCSWStatus = cswBuf[KCswLength - 1];
test.Printf(_L("CSW status: %d\n"), bCSWStatus);
return(bCSWStatus == aStatus);
}
//////////////////////////////////////////////////////////////
void
TDisconnected::MoveTo(TInt aStateId) const
{
switch (aStateId)
{
case EUsbMsDriveState_Connecting:
MoveToConnecting();
break;
case EUsbMsDriveState_Connected:
MoveToConnected();
break;
default:
test.Printf(_L("Cannot reach %d from %d\n"), GetStateId(), aStateId);
test(EFalse);
}
}
void
TDisconnected::MoveToConnecting() const
{
test.Printf(_L("Moving to connecting state\n"));
MountMsFs(removalDrvNo);
// send test unit ready message
BuildTestUnitReady();
createCBW(cbwBuf, ++dCBWTag, 0, 0, scsiCmdBuf, testLun);
test(SendAndReceive(1)); // 1: the unit is not ready!
}
void
TDisconnected::MoveToConnected() const
{
test.Printf(_L("Moving to connected state\n"));
MountMsFs(removalDrvNo);
BuildTestUnitReady();
createCBW(cbwBuf, ++dCBWTag, 0, 0, scsiCmdBuf, testLun);
test(SendAndReceive(1));
}
//////////////////////////////////////////////////////////////
void
TConnecting::MoveTo(TInt aStateId) const
{
switch (aStateId)
{
case EUsbMsState_Written:
MoveToWritten();
break;
default:
test.Printf(_L("Cannot reach %d from %d\n"), GetStateId(), aStateId);
test(EFalse);
}
}
void TConnecting::MoveToWritten() const
{
test.Printf(_L("Moving to written state\n"));
// Mount MS file system
MountMsFs(removalDrvNo);
BuildTestUnitReady();
createCBW(cbwBuf, ++dCBWTag, 0, 0, scsiCmdBuf, testLun);
test(SendAndReceive(1));
// Write 1k bytes using testldd.
// 0x2A: opcode for write (10); 10: starting sector; 2: total sectors
BuildReadWrite(0x2A, 10, 2);
// 0: indicates host writing
createCBW(cbwBuf, ++dCBWTag, KKiloBytes, 0, scsiCmdBuf, testLun);
// Send write command
test.Printf(_L("Sending CBW write cmd\n"));
TRequestStatus status;
usbcClient.HostWrite(status, EEndpoint1, cbwBuf, KCbwLength);
User::WaitForRequest(status);
test(KErrNone == status.Int());
// Write actual data. We don't care the contents.
TBuf8<KKiloBytes> writeBuf;
writeBuf.SetLength(KKiloBytes);
usbcClient.HostWrite(status, EEndpoint1, writeBuf, KKiloBytes);
User::WaitForRequest(status);
test(KErrNone == status.Int());
// Check CSW status
// Read CSW
test.Printf(_L("Reading CSW\n"));
usbcClient.HostRead(status, EEndpoint2, cswBuf, KCswLength);
User::WaitForRequest(status);
test(KErrNone == status.Int());
// Check dCSWTag
TInt recvedCBWTag = extractInt(&cswBuf[4]);
test(dCBWTag == recvedCBWTag);
// Check bCSWStatus
TInt bCSWStatus = cswBuf[KCswLength - 1];
test.Printf(_L("CSW status: %d\n"), bCSWStatus);
test(bCSWStatus == 0);
}
//////////////////////////////////////////////////////////////
void
TConnected::MoveTo(TInt aStateId) const
{
switch (aStateId)
{
case EUsbMsDriveState_Active:
MoveToActive();
break;
default:
test.Printf(_L("Cannot reach %d from %d\n"), GetStateId(), aStateId);
test(EFalse);
}
}
void
TConnected::MoveToActive() const
{
test.Printf(_L("Moving to active state\n"));
// send prevent medium removal using testld
// 1: prevent medium removal
BuildMediumRemoval(1);
createCBW(cbwBuf, ++dCBWTag, 0, 0, scsiCmdBuf, testLun);
if(!SendAndReceive())
{
// Prevent Media Removal command not supported
test.Printf(_L("Prevent Media Removal command not supported, issuing read instead\n"));
// Read 1k bytes using testldd.
// 0x28: opcode for read (10); 10: starting sector; 2: total sectors
BuildReadWrite(0x28, 10, 2);
// 0x80: indicates host writing
createCBW(cbwBuf, ++dCBWTag, KKiloBytes, 0x80, scsiCmdBuf, testLun);
// Send read command
test.Printf(_L("Sending CBW read cmd\n"));
TRequestStatus status;
usbcClient.HostWrite(status, EEndpoint1, cbwBuf, KCbwLength);
User::WaitForRequest(status);
test(KErrNone == status.Int());
// Read actual data. We don't care the contents.
TBuf8<KKiloBytes> readBuf;
readBuf.SetLength(KKiloBytes);
usbcClient.HostRead(status, EEndpoint2, readBuf, KKiloBytes);
User::WaitForRequest(status);
test(KErrNone == status.Int());
// Check CSW status
// Read CSW
test.Printf(_L("Reading CSW\n"));
usbcClient.HostRead(status, EEndpoint2, cswBuf, KCswLength);
User::WaitForRequest(status);
test(KErrNone == status.Int());
// Check dCSWTag
TInt recvedCBWTag = extractInt(&cswBuf[4]);
test(dCBWTag == recvedCBWTag);
// Check bCSWStatus
TInt bCSWStatus = cswBuf[KCswLength - 1];
test.Printf(_L("CSW status: %d\n"), bCSWStatus);
test(bCSWStatus == 0);
}
}
//////////////////////////////////////////////////////////////
void
TActive::MoveTo(TInt aStateId) const
{
switch (aStateId)
{
case EUsbMsDriveState_Locked:
MoveToLocked();
break;
case EUsbMsDriveState_Disconnecting:
MoveToDisconnecting();
break;
default:
test.Printf(_L("Cannot reach %d from %d\n"), GetStateId(), aStateId);
test(EFalse);
}
}
void
TActive::MoveToLocked() const
{
test.Printf(_L("Moving to locked state\n"));
// To be implemented. Wait for lock defect fix
}
void
TActive::MoveToDisconnecting() const
{
test.Printf(_L("Moving to disconnecting state\n"));
// send allow medium removal using testld
// 0: allow medium removal
BuildMediumRemoval(0);
createCBW(cbwBuf, ++dCBWTag, 0, 0, scsiCmdBuf, testLun);
if(!SendAndReceive())
test.Printf(_L("Prevent Media Removal command not supported, no need to allow\n"));
// Now the state is connected, let's move to disconnecting state
// by sending a stop unit command
// 0: stop unit
BuildStartStopUnit(0);
createCBW(cbwBuf, ++dCBWTag, 0, 0, scsiCmdBuf, testLun);
test(SendAndReceive());
}
//////////////////////////////////////////////////////////////
void
TLocked::MoveTo(TInt aStateId) const
{
switch (aStateId)
{
case EUsbMsDriveState_Disconnecting:
MoveToDisconnecting();
break;
default:
test.Printf(_L("Cannot reach %d from %d\n"), GetStateId(), aStateId);
test(EFalse);
}
}
void
TLocked::MoveToDisconnecting() const
{
test.Printf(_L("Moving to disconnecting state\n"));
// To be implemented once lock issue is resolved
}
//////////////////////////////////////////////////////////////
void
TDisconnecting::MoveTo(TInt aStateId) const
{
switch (aStateId)
{
case EUsbMsDriveState_Disconnected:
MoveToDisconnected();
break;
default:
test.Printf(_L("Cannot reach %d from %d\n"), GetStateId(), aStateId);
test(EFalse);
}
}
void
TDisconnecting::MoveToDisconnected() const
{
test.Printf(_L("Moving to disconnected state\n"));
UnmountMsFs(removalDrvNo);
}
//////////////////////////////////////////////////////////////
void
TWritten::MoveTo(TInt aStateId) const
{
switch (aStateId)
{
case EUsbMsState_Read:
MoveToRead();
break;
default:
test.Printf(_L("Cannot reach %d from %d\n"), GetStateId(), aStateId);
test(EFalse);
}
}
void
TWritten::MoveToRead() const
{
test.Printf(_L("Moving to read state\n"));
// Read 1k bytes using testldd.
// 0x28: opcode for read (10); 10: starting sector; 2: total sectors
BuildReadWrite(0x28, 10, 2);
// 0x80: indicates host writing
createCBW(cbwBuf, ++dCBWTag, KKiloBytes, 0x80, scsiCmdBuf, testLun);
// Send read command
test.Printf(_L("Sending CBW read cmd\n"));
TRequestStatus status;
usbcClient.HostWrite(status, EEndpoint1, cbwBuf, KCbwLength);
User::WaitForRequest(status);
test(KErrNone == status.Int());
// Read actual data. We don't care the contents.
TBuf8<KKiloBytes> readBuf;
readBuf.SetLength(KKiloBytes);
usbcClient.HostRead(status, EEndpoint2, readBuf, KKiloBytes);
User::WaitForRequest(status);
test(KErrNone == status.Int());
// Check CSW status
// Read CSW
test.Printf(_L("Reading CSW\n"));
usbcClient.HostRead(status, EEndpoint2, cswBuf, KCswLength);
User::WaitForRequest(status);
test(KErrNone == status.Int());
// Check dCSWTag
TInt recvedCBWTag = extractInt(&cswBuf[4]);
test(dCBWTag == recvedCBWTag);
// Check bCSWStatus
TInt bCSWStatus = cswBuf[KCswLength - 1];
test.Printf(_L("CSW status: %d\n"), bCSWStatus);
test(bCSWStatus == 0);
}
//////////////////////////////////////////////////////////////
void
TRead::MoveTo(TInt aStateId) const
{
switch (aStateId)
{
case EUsbMsDriveState_Disconnected:
MoveToDisconnected();
break;
default:
test.Printf(_L("Cannot reach %d from %d\n"), GetStateId(), aStateId);
test(EFalse);
}
}
void
TRead::MoveToDisconnected() const
{
test.Printf(_L("Moving to disconnected state\n"));
UnmountMsFs(removalDrvNo);
}