// Copyright (c) 2008-2010 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:
//
/**
@file
@internalTechnology
*/
#include <e32std.h>
#include <f32file.h>
#include "rusbhostmsdevice.h"
#include "msgservice.h"
#include "OstTraceDefinitions.h"
#ifdef OST_TRACE_COMPILER_IN_USE
#include "rusbhostmsdeviceTraces.h"
#endif
_LIT(KFileSystem, "FAT");
TVersion RUsbHostMsDevice::Version() const
{
return(TVersion(KUsbHostMsSrvMajorVersionNumber,
KUsbHostMsSrvMinorVersionNumber,
KUsbHostMsSrvBuildVersionNumber));
}
TInt RUsbHostMsDevice::StartServer()
{
TInt r;
RProcess server;
const TUid KServerUid3={0x10286A83};
const TUidType serverUid(KNullUid,KNullUid,KServerUid3);
// Create the server process
if((r=server.Create(KUsbHostMsServerName,KNullDesC,serverUid)) != KErrNone)
{
OstTrace1(TRACE_SHOSTMASSSTORAGE_HOST, RUSBHOSTMSDEVICE_10,
"Server process create = %d", r);
return r;
}
// Create the rendezvous request with the server process
TRequestStatus stat;
server.Rendezvous(stat);
if (stat!=KRequestPending)
{
server.Kill(0); // If the outstanding request is not pending then kill the server
}
else
{
server.SetPriority(EPriorityHigh);
server.Resume(); // start the server
}
// Test whether the process has ended and if it has ended, return how it ended.
User::WaitForRequest(stat);
r=(server.ExitType()==EExitPanic) ? KErrGeneral : stat.Int();
server.Close();
return r;
}
EXPORT_C RUsbHostMsDevice::RUsbHostMsDevice()
{
// Intentionally left blank
}
/**
@internalAll
@prototype
Add the Mass Storage device to the MSC server. This API is asynchronous, upon
completion one could find the number of logical units present in the added
device by calling GetNumLun API. Calling the Remove API before completing this
asynchronous API will complete the pending request notification with KErrCancel.
@param aConfig [In] A constant reference object to
THostMassStorageConfig containing the confiquration values of
the massstorage device requested to add to the MSC
@param aStatus [In] A reference to TRequestStatus to be used for asynchronous
request completion
*/
EXPORT_C void RUsbHostMsDevice::Add(const THostMassStorageConfig& aConfig, TRequestStatus& aStatus)
{
TInt err = KErrNone;
err = CreateSession(KUsbHostMsServerName, Version(), 128, EIpcSession_GlobalSharable);
// Being a transient server, the first session creation would fail with if
// the server is not running
if(err != KErrNone)
{
// Find whether the session creation failed because server was not
// running
if (err==KErrNotFound || err==KErrServerTerminated)
{
// Start the server
err = StartServer();
if(err == KErrNone)
{
// Try session creation again
err = CreateSession(KUsbHostMsServerName, Version(), 128, EIpcSession_GlobalSharable);
}
}
}
TRequestStatus* statusPtr = &aStatus;
if(err == KErrNone)
{
// Create a session handle that can be passed via IPC to another process
// (also being shared by other threads in the current process)
err = ShareProtected();
if(err == KErrNone)
{
// synchronous call to register the interface
TPckg<THostMassStorageConfig> pckg(aConfig);
err = SendReceive(EUsbHostMsRegisterInterface, TIpcArgs(&pckg));
if(err != KErrNone)
{
User::RequestComplete(statusPtr, err);
}
else
{
// Asynchronous call to initialise the interface
SendReceive(EUsbHostMsInitialiseInterface, TIpcArgs(NULL), aStatus);
}
}
else
{
Close(); // Close the session handle
OstTrace1(TRACE_SHOSTMASSSTORAGE_HOST, RUSBHOSTMSDEVICE_11,
"Could not create a sharable session handle %d", err);
User::RequestComplete(statusPtr, err);
}
}
else
{
// Check whether the error is in starting the server or in creating the
// session
OstTrace1(TRACE_SHOSTMASSSTORAGE_HOST, RUSBHOSTMSDEVICE_12,
"Creating server/session failed with %d", err);
User::RequestComplete(statusPtr, err);
}
}
/**
@internalAll
@prototype
Remove the Mass Storage device from the MSC server.
*/
EXPORT_C void RUsbHostMsDevice::Remove()
{
// Note: Here, at present we use only the interface token. But we still take
// THostMassStorageConfig as parameter for future needs
_LIT(KUsbHostMsClientPanicCat, "usbhostmsclient");
TInt r = SendReceive(EUsbHostMsUnRegisterInterface);
r = SendReceive(EUsbHostMsFinalCleanup);
if(r != KErrNone)
{
User::Panic(KUsbHostMsClientPanicCat ,KErrCouldNotDisconnect);
}
Close(); // Close the session handle
}
/**
@internalAll
@prototype
Get the number of logical units suppoted by the device.
@param aNumLuns [Out] Outputs the number of logical units found in the
added Mass Storage device. A value of 'n' represents there are
'n' LUNs present in the device, where "n > 0"
@return TInt
*/
EXPORT_C TInt RUsbHostMsDevice::GetNumLun(TUint32& aNumLuns)
{
TPckg<TUint32> pckg(aNumLuns);
return SendReceive(EUsbHostMsGetNumLun,TIpcArgs(&pckg));
}
EXPORT_C TInt RUsbHostMsDevice::MountLun(TUint32 aLunId, TInt aDriveNum)
{
OstTraceExt2(TRACE_SHOSTMASSSTORAGE_MSDEV, RUSBHOSTMSDEVICE_13,
">>> RUsbHostMsDevice::MountLun Drv=%d LUN=%d", aDriveNum, aLunId);
RFs TheFs;
TInt r = TheFs.Connect();
if(r == KErrNone)
{
TPckgBuf<TMassStorageUnitInfo> unitPkg;
unitPkg().iLunID = aLunId;
r = TheFs.MountProxyDrive(aDriveNum, _L("usbhostms"), &unitPkg, *this);
OstTrace1(TRACE_SHOSTMASSSTORAGE_MSDEV, RUSBHOSTMSDEVICE_14,
"MountProxyDrive %d", r);
if(r >= KErrNone)
{
r = TheFs.MountFileSystem(KFileSystem, aDriveNum);
OstTrace1(TRACE_SHOSTMASSSTORAGE_MSDEV, RUSBHOSTMSDEVICE_15,
"MountFileSystem %d", r);
if(r != KErrNone && r != KErrNotReady && r != KErrCorrupt && r != KErrNotSupported)
{
TheFs.DismountFileSystem(KFileSystem, aDriveNum);
TheFs.DismountProxyDrive(aDriveNum);
}
}
TheFs.Close();
}
return r;
}
EXPORT_C TInt RUsbHostMsDevice::DismountLun(TInt aDriveNum)
{
OstTrace1(TRACE_SHOSTMASSSTORAGE_MSDEV, RUSBHOSTMSDEVICE_20,
">>> RUsbHostMsDevice::DismountLun Drv=%d", aDriveNum);
RFs TheFs;
TInt r;
r = TheFs.Connect();
if(r == KErrNone)
{
r = TheFs.DismountFileSystem(KFileSystem, aDriveNum);
if(r != KErrNone)
{
// dismount failed - attempt a forced dismount
TRequestStatus stat;
TheFs.NotifyDismount(aDriveNum, stat, EFsDismountForceDismount);
User::WaitForRequest(stat);
r = stat.Int();
}
if(r == KErrNone)
{
r = TheFs.DismountProxyDrive(aDriveNum);
}
TheFs.Close();
}
return r;
}