--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetoothengine/bthid/bthidserver/src/bthidserver.cpp Mon Jan 18 20:28:57 2010 +0200
@@ -0,0 +1,1631 @@
+/*
+* Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "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: This is the implementation of application class
+ *
+*/
+
+#include <e32svr.h>
+#include <s32file.h>
+#include <bt_sock.h>
+#include <sysutil.h>
+//#include <hal.h> // for checking the MachineUID. also link to hal.lib
+#include <e32std.h>
+//#include <btmanclient.h>
+#include <btnotif.h>
+#include "bthidserver.h"
+#include "bthidsession.h"
+#include "bthidclientsrv.h"
+#include "bthidconnection.h"
+#include "socketlistener.h"
+#include "bthidtypes.h"
+#include "bthiddevice.h"
+#include "hiddescriptorlist.h"
+#include "hiddescriptor.h"
+#include "bthidserver.pan"
+#include "debug.h"
+#include "debugconfig.h"
+#include "hidgeneric.h"
+#include "hidlayoutids.h"
+#include "bthidPsKey.h"
+
+
+#ifndef DBG
+#ifdef _DEBUG
+#define DBG(a) a
+#else
+#define DBG(a)
+#endif
+#endif
+
+//File store location
+_LIT(KFileStore,"C:\\private\\2001E301\\bthiddevices.dat");
+
+/** PubSub key read and write policies */
+_LIT_SECURITY_POLICY_C2( KBTHIDPSKeyReadPolicy,
+ ECapabilityLocalServices, ECapabilityReadDeviceData );
+_LIT_SECURITY_POLICY_C2( KBTHIDPSKeyWritePolicy,
+ ECapabilityLocalServices, ECapabilityWriteDeviceData );
+
+// A version number to use when storing device information
+// Only for future proofing.
+const TInt KDataFileVersionNumber = 1;
+
+CBTHidServer::CBTHidServer() :
+ CGenericServer(CActive::EPriorityStandard)
+ {
+ // Implementation not required
+ }
+
+CBTHidServer::~CBTHidServer()
+ {
+ delete iShutDownTimer;
+
+ delete iControlListener;
+
+ delete iInterruptListener;
+
+ delete iBTConnIndex;
+
+ delete iMasterContIndex; // Causes deletion of iBTConnContainer
+
+ if (iTempInterrupt)
+ {
+ iTempInterrupt->Close();
+ delete iTempInterrupt;
+ }
+
+ if (iTempControl)
+ {
+ iTempControl->Close();
+ delete iTempControl;
+ }
+
+ iFs.Close();
+ iSocketServ.Close();
+
+ iReqs.ResetAndDestroy();
+
+ delete iGenHID;
+
+ RProperty::Delete( KPSUidBthidSrv, KBTMouseCursorState );
+ }
+
+CBTHidServer* CBTHidServer::NewL()
+ {
+ CBTHidServer* self = CBTHidServer::NewLC();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+CBTHidServer* CBTHidServer::NewLC()
+ {
+ CBTHidServer* self = new (ELeave) CBTHidServer;
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ return self;
+ }
+
+const TInt KShutdownDelay = 5000000;
+
+void CBTHidServer::StartShutdownTimerIfNoSession()
+ {
+ if (!ConnectionCount()
+ && (!iShutDownTimer || !iShutDownTimer->IsActive()))
+ {
+ if (!iShutDownTimer)TRAP_IGNORE(iShutDownTimer = CPeriodic::NewL(CActive::EPriorityStandard));
+ if (iShutDownTimer)
+ iShutDownTimer->Start(KShutdownDelay, 0, TCallBack(
+ CBTHidServer::TimerFired, this));
+ TRACE_FUNC
+ }
+ }
+
+TInt CBTHidServer::TimerFired(TAny* /*aThis*/)
+ {
+ TRACE_STATIC_FUNC
+ CActiveScheduler::Stop();
+ return KErrNone;
+ }
+
+void CBTHidServer::CancelShutdownTimer()
+ {
+ TRACE_FUNC
+ delete iShutDownTimer;
+ iShutDownTimer = NULL;
+ }
+
+void CBTHidServer::ConstructL()
+ {
+
+ TRACE_INFO(_L("CBTHidServer::ConstructL()..."));
+ iMasterContIndex = CObjectConIx::NewL();
+
+ iBTConnContainer = iMasterContIndex->CreateL();
+
+ iBTConnIndex = CObjectIx::NewL();
+
+ // Connect to the file server
+ TRACE_INFO(_L("[BTHID]\tCBTHidServer::ConstructL(): Connecting to file server"));
+ User::LeaveIfError(iFs.Connect());
+
+ // Make the data storage path (if it doesn't exist)
+ // If we can't create it, we can still make connections. They just won't
+ // persist.
+ iFs.MkDirAll(KFileStore);
+ // Connect to the socket server.
+ TRACE_INFO(_L("[BTHID]\tCBTHidServer::ConstructL(): Connecting to socket server"));
+ User::LeaveIfError(iSocketServ.Connect());
+
+ // Create initial sockets to accept a connection on the control
+ // and interrupt channels
+ iTempControl = new (ELeave) RSocket;
+ iTempInterrupt = new (ELeave) RSocket;
+
+ // Set the security required for incoming connections on the
+ // control and interrupt channels. This is handled in socket level now.
+
+ // Create Socket listeners for the control and interrupt channel
+ // ETrue, authorisation from user for incoming connection is asked
+ iControlListener = CSocketListener::NewL(iSocketServ, KL2CAPHidControl,
+ *this, ETrue);
+
+ //no authorisation needs to be asked,
+ //since it is asked during Control channel re-connection.
+ iInterruptListener = CSocketListener::NewL(iSocketServ,
+ KL2CAPHidInterrupt, *this, EFalse);
+
+ // Request to accept connections into the sockets just created
+ TRACE_INFO(_L("[BTHID]\tCBTHidServer::ConstructL(): AcceptingConnections..."));
+ User::LeaveIfError(iControlListener->AcceptConnection(*iTempControl));
+ User::LeaveIfError(iInterruptListener->AcceptConnection(*iTempInterrupt));
+
+ // Create the generic HID:
+ TRACE_INFO(_L("[BTHID]\tCBTHidServer::ConstructL(): Creating Generic HID"));
+ iGenHID = CGenericHid::NewL(this);
+
+ // Load details of any virtually-cabled devices.
+ // Trap the error, but we can live with failure to load stored
+ // information. The file may be corrupt and we don't want this
+ // to prevent us using the application
+ TRACE_INFO(_L("[BTHID]\tCBTHidServer::ConstructL(): Loading virtually cabled devices"));
+ TRAPD( err, LoadVirtuallyCabledDevicesL(KFileStore) );
+ if (KErrNone != err)
+ {
+ err = err;
+ TRACE_INFO(_L("[BTHID]\tCBTHidServer::ConstructL(): Loading virtually cabled devices FAILED"));
+ }
+
+ TRACE_INFO(_L("[BTHID]\tCBTHidServer::ConstructL(): Starting the server"));
+
+ User::LeaveIfError( RProperty::Define( KPSUidBthidSrv,
+ KBTMouseCursorState,
+ RProperty::EInt,
+ KBTHIDPSKeyReadPolicy,
+ KBTHIDPSKeyWritePolicy) );
+
+ StartL(KBTHidSrvName);
+
+ iActiveState = EFalse;
+
+ TRACE_INFO(_L("[BTHID]\tCBTHidServer::ConstructL(): Server Started."));
+
+ }
+
+CSession2* CBTHidServer::NewSessionL(const TVersion& aVersion,
+ const RMessage2& /*aMessage*/) const
+ {
+ // check we're the right version
+ if (!User::QueryVersionSupported(TVersion(KBTHIDServMajorVersionNumber,
+ KBTHIDServMinorVersionNumber, KBTHIDServBuildVersionNumber),
+ aVersion))
+ {
+ User::Leave(KErrNotSupported);
+ }
+ const_cast<CBTHidServer*> (this)->CancelShutdownTimer();
+ // make new session
+ return CBTHidServerSession::NewL(*const_cast<CBTHidServer*> (this));
+ }
+
+void CBTHidServer::InformClientsOfStatusChange(
+ const CBTHidDevice& aDeviceDetails, TBTHidConnState aState)
+ {
+ TRACE_INFO( (_L("[BTHID]\tCBTHidServer::InformClientsOfStatusChange, state=%d"),aState) );
+ if (aState == EBTDeviceConnected || aState == EBTDeviceLinkRestored
+ || aState == EBTDeviceLinkLost || aState == EBTDeviceDisconnected)
+ {
+ iLastUsedAddr = aDeviceDetails.iAddress;
+ iActiveState = ETrue;
+ }
+ else
+ {
+ iActiveState = EFalse;
+ }
+ InformStatusChange(aDeviceDetails.iAddress, aState);
+ GlobalNotify(aDeviceDetails.iAddress, aState);
+ }
+
+void CBTHidServer::InformStatusChange(const TBTDevAddr& aAddress,
+ TBTHidConnState aState)
+ {
+ TRACE_INFO( (_L("[BTHID]\tCBTHidServer::InformStatusChange, state=%d"),aState) );
+ THIDStateUpdateBuf updateBuf;
+ THIDStateUpdate& update = updateBuf();
+
+ update.iDeviceAddress = aAddress;
+ update.iState = aState;
+
+ // Send to all clients
+ iSessionIter.SetToFirst();
+ for (;;)
+ {
+ CBTHidServerSession* session;
+ session = reinterpret_cast<CBTHidServerSession*> (iSessionIter++);
+ if (!session)
+ {
+ break;
+ }
+
+ session->InformStatusChange(updateBuf);
+ }
+ }
+
+void CBTHidServer::GlobalNotify(const TBTDevAddr& aDeviceAddr,
+ TBTHidConnState aState)
+ {
+ switch (aState)
+ {
+ case EBTDeviceLinkRestored:
+ {
+ HandleAsyncRequest(aDeviceAddr, EBTConnected);
+ break;
+ }
+
+ case EBTDeviceLinkLost:
+ case EBTDeviceDisconnected:
+ case EBTDeviceUnplugged:
+ {
+ HandleAsyncRequest(aDeviceAddr, EBTDisconnected);
+ break;
+ }
+ default:
+ //No need to bother
+ break;
+ }
+ }
+
+TInt CBTHidServer::HandleAsyncRequest(const TBTDevAddr& aDeviceAddr,
+ TInt aNote)
+ {
+ TRAPD(err, HandleAsyncRequestL(aDeviceAddr, aNote));
+ return err;
+ }
+
+void CBTHidServer::HandleAsyncRequestL(const TBTDevAddr& aDeviceAddr,
+ TInt aNote)
+ {
+ CBTHidNotifierHelper* notifier = CBTHidNotifierHelper::NewL(*this, aNote, aDeviceAddr);
+ CleanupStack::PushL(notifier);
+
+ iReqs.AppendL(notifier);
+ CleanupStack::Pop(notifier);
+
+ if (iReqs.Count() == 1) // only display our notifier if there's nothing already showing
+ {
+ notifier->Start();
+ }
+ }
+
+void CBTHidServer::NotifierRequestCompleted()
+ {
+ delete iReqs[0];
+ iReqs.Remove(0);
+
+ if (iReqs.Count())
+ {
+ iReqs[0]->Start();
+ }
+ }
+
+void CBTHidServer::GenericHIDConnectL(CBTHidConnection* aConnection,
+ TBool aStartDriver)
+ {
+ TRACE_INFO(_L("[BTHID]\tCBTHidServer::GenericHIDConnectL"));
+ CBTHidDevice& devDetails = aConnection->DeviceDetails();
+
+ // Search for the first report descriptor and give this
+ // to Generic HID
+ TBool foundRepDesc = EFalse;
+ TInt i = 0;
+ while ((i < devDetails.iDescList->DescriptorCount()) && (!foundRepDesc))
+ {
+ // Get the next descriptor.
+ const CHidDescriptor& desc =
+ (*(aConnection->DeviceDetails().iDescList))[i];
+
+ if (desc.DescriptorType() == CHidDescriptor::EReportDescriptor)
+ {
+ foundRepDesc = ETrue;
+ User::LeaveIfError(iGenHID->ConnectedL(aConnection->ConnID(),
+ desc.RawData()));
+
+ // Try to start the driver if required.
+ if (aStartDriver)
+ {
+ User::LeaveIfError(iGenHID->DriverActive(
+ aConnection->ConnID(), CHidTransport::EActive));
+ }
+ }
+
+ i++;
+ }
+
+ // If we didn't find a report descriptor, the device information is corrupt
+ if (!foundRepDesc)
+ {
+ User::Leave(KErrCorrupt);
+ }
+ }
+
+void CBTHidServer::IncrementSessions()
+ {
+ iSessionCount++;
+ CancelShutdownTimer();
+ }
+
+void CBTHidServer::DecrementSessions()
+ {
+ iSessionCount--;
+ __ASSERT_DEBUG(iSessionCount >= 0, PanicServer(EMainSchedulerError));
+
+ if (iSessionCount <= 0)
+ {
+ iSessionCount = 0;
+ StartShutdownTimerIfNoSession();
+ }
+ }
+
+TInt CBTHidServer::RunError(TInt aError)
+ {
+ if (aError == KErrBadDescriptor)
+ {
+ // A bad descriptor error implies a badly programmed client,
+ // so panic it;
+ // otherwise report the error to the client
+ PanicClient(Message(), EBadDescriptor);
+ }
+ else
+ {
+ Message().Complete(aError);
+ }
+
+ // The leave will result in an early return from CServer::RunL(), skipping
+ // the call to request another message. So do that now in order to keep the
+ // server running.
+ ReStart();
+
+ return KErrNone; // handled the error fully
+ }
+
+void CBTHidServer::PanicClient(const RMessage2& aMessage, TInt aPanic)
+ {
+ TRACE_INFO( (_L("[BTHID]\tCBTHidServer::PanicClient(%d)"), aPanic) );
+ aMessage.Panic(KBTHIDServer, aPanic);
+ }
+
+void CBTHidServer::PanicServer(TInt aPanic)
+ {
+ TRACE_INFO( (_L("[BTHID]\tCBTHidServer::PanicServer( %d )"), aPanic) );
+ User::Panic(KBTHIDServer, aPanic);
+ }
+
+void CBTHidServer::ShutdownListeners(TInt aError)
+ {
+ // Shutdown listeners and close accepting sockets
+ TRACE_INFO( (_L("[BTHID]\tCBTHidServer::ShutdownListeners(%d)"), aError) )
+
+ (void) aError;
+
+ iControlListener->Cancel();
+ iInterruptListener->Cancel();
+
+ if (iTempInterrupt)
+ {
+ iTempInterrupt->Close();
+ }
+
+ if (iTempControl)
+ {
+ iTempControl->Close();
+ }
+ }
+
+TUint CBTHidServer::ConnectionCount()
+ {
+ return iBTConnContainer->Count();
+ }
+
+CBTHidDevice& CBTHidServer::ConnectionDetailsL(TInt aConnID)
+ {
+ CBTHidConnection *connection = IdentifyConnectionL(aConnID);
+
+ return connection->DeviceDetails();
+ }
+
+TBTEngConnectionStatus CBTHidServer::ConnectStatus(const TBTDevAddr& aAddress)
+ {
+ TInt i = 0;
+ TBool foundItem = EFalse;
+ TBTEngConnectionStatus retVal = EBTEngNotConnected;
+ TInt BTConnectionObjCount = iBTConnContainer->Count();
+
+ TRACE_INFO(_L("[BTHID]\tCBTHidServer::ConnectStatus()"));
+ while ((i < BTConnectionObjCount) && (!foundItem))
+ {
+ CBTHidConnection *connection =
+ static_cast<CBTHidConnection*> ((*iBTConnContainer)[i]);
+
+ if (connection)
+ {
+ CBTHidDevice& devDetails = connection->DeviceDetails();
+
+ if (devDetails.iAddress == aAddress)
+ {
+ foundItem = ETrue;
+ TBTConnectionState HidConnectionStatus =
+ connection->ConnectStatus();
+ if (EFirstConnection == HidConnectionStatus || EConnecting
+ == HidConnectionStatus || EHIDReconnecting
+ == HidConnectionStatus || EHostReconnecting
+ == HidConnectionStatus)
+ {
+ retVal = EBTEngConnecting;
+ }
+ if (EConnected == HidConnectionStatus)
+ {
+ retVal = EBTEngConnected;
+ }
+ }
+ }
+
+ i++;
+ }
+
+ return retVal;
+ }
+
+TBool CBTHidServer::GetConnectionAddress(TDes8& aAddressBuf)
+ {
+ TInt i = 0;
+ TBool retVal = EFalse;
+ TInt BTConnectionObjCount = iBTConnContainer->Count();
+ TRACE_INFO(_L("[BTHID]\tCBTHidServer::IsAllowToConnect()"));
+ while ((i < BTConnectionObjCount))
+ {
+ CBTHidConnection *connection =
+ static_cast<CBTHidConnection*> ((*iBTConnContainer)[i]);
+
+ if (connection)
+ {
+ CBTHidDevice& devDetails = connection->DeviceDetails();
+ if (connection->IsConnected())
+ {
+ retVal = ETrue;
+ aAddressBuf.Append((devDetails.iAddress).Des());
+ if (aAddressBuf.Length() == KBTDevAddrSize * 2)
+ break;
+ }
+ }
+ i++;
+ }
+
+ return retVal;
+ }
+
+TBool CBTHidServer::IsAllowToConnectFromServerSide(TUint aDeviceSubClass)
+ {
+ TInt i = 0;
+ TBool retVal = ETrue;
+ TInt BTConnectionObjCount = iBTConnContainer->Count();
+
+ TRACE_INFO(_L("[BTHID]\tCBTHidServer::IsAllowToConnectFromServerSide()"));
+ while ((i < BTConnectionObjCount) && retVal)
+ {
+ CBTHidConnection *connection =
+ static_cast<CBTHidConnection*> ((*iBTConnContainer)[i]);
+
+ if (connection)
+ {
+ CBTHidDevice& devDetails = connection->DeviceDetails();
+ TBTConnectionState HidConnectionStatus =
+ connection->ConnectStatus();
+ if (connection->IsConnected() || HidConnectionStatus
+ == EHIDReconnecting)
+ {
+ if ((IsKeyboard(aDeviceSubClass) && IsKeyboard(
+ devDetails.iDeviceSubClass)) || (IsPointer(
+ aDeviceSubClass) && IsPointer(
+ devDetails.iDeviceSubClass)))
+ {
+ retVal = EFalse;
+ iConflictAddr = devDetails.iAddress;
+ }
+ }
+ }
+ i++;
+ }
+
+ return retVal;
+ }
+
+TBool CBTHidServer::IsKeyboard(TUint aDeviceSubClass)
+ {
+ TUint deviceSubClass = aDeviceSubClass;
+ TBool retVal = EFalse;
+ if ((deviceSubClass >> 2) & EMinorDevicePeripheralKeyboard)
+ {
+ retVal = ETrue;
+ }
+ return retVal;
+ }
+
+TBool CBTHidServer::IsPointer(TUint aDeviceSubClass)
+ {
+ TUint deviceSubClass = aDeviceSubClass;
+ TBool retVal = EFalse;
+ if ((deviceSubClass >> 2) & EMinorDevicePeripheralPointer)
+ {
+ retVal = ETrue;
+ }
+ return retVal;
+ }
+
+TBool CBTHidServer::IsAllowToConnectFromClientSide(TBTDevAddr aDevAddr)
+ {
+ TInt i = 0;
+ TBool retVal = ETrue;
+ TInt BTConnectionObjCount = iBTConnContainer->Count();
+
+ TUint deviceSubClass = GetDeviceSubClass(aDevAddr);
+ TRACE_INFO(_L("[BTHID]\tCBTHidServer::IsAllowToConnectFromClientSide()"));
+ while ((i < BTConnectionObjCount) && retVal)
+ {
+ CBTHidConnection *connection =
+ static_cast<CBTHidConnection*> ((*iBTConnContainer)[i]);
+
+ if (connection)
+ {
+ CBTHidDevice& devDetails = connection->DeviceDetails();
+ TBTConnectionState HidConnectionStatus =
+ connection->ConnectStatus();
+ if (connection->IsConnected() || HidConnectionStatus
+ == EConnecting)
+ {
+ if (devDetails.iAddress != aDevAddr)
+ {
+ if ((IsKeyboard(deviceSubClass) && IsKeyboard(
+ devDetails.iDeviceSubClass)) || (IsPointer(
+ deviceSubClass) && IsPointer(
+ devDetails.iDeviceSubClass)))
+ {
+ retVal = EFalse;
+ iConflictAddr = devDetails.iAddress;
+ }
+ }
+ }
+ }
+ i++;
+ }
+
+ return retVal;
+ }
+
+TUint CBTHidServer::GetDeviceSubClass(TBTDevAddr aDevAddr)
+ {
+ TInt i = 0;
+ TUint deviceSubClass = 0;
+ TInt BTConnectionObjCount = iBTConnContainer->Count();
+
+ TRACE_INFO(_L("[BTHID]\tCBTHidServer::GetMinorDeviceClass()"));
+ while (i < BTConnectionObjCount)
+ {
+ CBTHidConnection *connection =
+ static_cast<CBTHidConnection*> ((*iBTConnContainer)[i]);
+
+ if (connection)
+ {
+ CBTHidDevice& devDetails = connection->DeviceDetails();
+
+ if (devDetails.iAddress == aDevAddr)
+ {
+ deviceSubClass = devDetails.iDeviceSubClass;
+ }
+ }
+ i++;
+ }
+ return deviceSubClass;
+ }
+
+TBTDevAddr CBTHidServer::ConflictAddress()
+ {
+ return iConflictAddr;
+ }
+
+void CBTHidServer::CleanOldConnection(TInt aConnID)
+ {
+ TInt i = 0;
+ TBTDevAddr currentAddr;
+ TRACE_INFO( (_L("[BTHID]\tCBTHidServer::CleanOldConnection() aConnID[%d]"), aConnID) );
+ CBTHidConnection* connection =
+ static_cast<CBTHidConnection*>(iBTConnIndex->At(aConnID));
+ TRACE_INFO( (_L("[BTHID]\tCBTHidServer::CleanOldConnection() aConnID[%d]"), aConnID) );
+ __ASSERT_ALWAYS(connection, PanicServer(EInvalidHandle));
+
+ if (connection)
+ {
+ TRACE_INFO( _L("[BTHID]\tCBTHidServer::CleanOldConnection() if ") );
+ CBTHidDevice& currentDetails = connection->DeviceDetails();
+ currentAddr = currentDetails.iAddress;
+ TRACE_INFO( _L("[BTHID]\tCBTHidServer::CleanOldConnection() if 1") );
+ while (i < iBTConnContainer->Count())
+ {
+ TRACE_INFO( (_L("[BTHID]\tCBTHidServer::CleanOldConnection() i = [%d]"), i) );
+ connection = static_cast<CBTHidConnection*> ((*iBTConnContainer)[i]);
+
+ if (connection)
+ {
+ CBTHidDevice& devDetails = connection->DeviceDetails();
+ if (devDetails.iAddress == currentAddr && !(connection->IsConnected()))
+ {
+ TRACE_INFO( _L("[BTHID]\tCBTHidServer::CleanOldConnection() if 2") );
+ iGenHID->Disconnected(connection->ConnID());
+ iBTConnIndex->Remove(connection->ConnID());
+ }
+ }
+ i++;
+ }
+ }
+
+ return;
+ }
+
+TInt CBTHidServer::NewConnectionL()
+ {
+ TRACE_INFO(_L("[BTHID]\tCBTHidServer::NewConnectionL"));
+ CBTHidConnection *connection = CBTHidConnection::NewLC(iSocketServ,
+ *this, EConnecting);
+ // Add to the connection container object.
+ iBTConnContainer->AddL(connection);
+ CleanupStack::Pop(); // connection
+
+ // Now add the object to the index to get an id.
+ // We can't let this just leave since we have already inserted the
+ // connection object into the container.
+ TInt id = 0;
+ TRAPD( res,
+ id = iBTConnIndex->AddL(connection);
+ connection->SetConnID(id);
+ )
+
+ if (res != KErrNone)
+ {
+ // Couldn't make an index entry.
+ // Close the connection object, causing it to be removed from the
+ // container
+ connection->Close();
+ User::Leave(res);
+ }
+
+ return id;
+ }
+
+void CBTHidServer::DoFirstConnectionL(TInt aConnID)
+ {
+ TRACE_INFO(_L("[BTHID]\tCBTHidServer::DoFirstConnectionL"));
+ CBTHidConnection *connection = IdentifyConnectionL(aConnID);
+
+ CBTHidDevice &devDetails = ConnectionDetailsL(aConnID);
+ DBG(TUint DeviceClass = devDetails.iDeviceSubClass;
+
+ DBG(RDebug::Print(_L("[BTHID]\tCBTHidServer::DoFirstConnectionL iDeviceSubClass = %d"), DeviceClass));
+ )
+
+
+
+ if (!IsAllowToConnectFromServerSide(devDetails.iDeviceSubClass))
+ {
+ User::Leave(KErrAlreadyExists);
+ }
+
+ connection->ConnectL();
+ }
+
+void CBTHidServer::DeleteNewConnection(TInt aConnID)
+ {
+ TRACE_INFO(_L("[BTHID]\tCBTHidServer::DeleteNewConnection"));
+ iBTConnIndex->Remove(aConnID);
+ }
+
+/*Asks the server to disconnect (virtual cable unplug) a device totally,
+ * remove the connection entry from the connection container.
+ */
+void CBTHidServer::CloseBluetoothConnection(const TBTDevAddr& aAddress)
+
+ {
+ TInt i = 0;
+ TBool foundItem = EFalse;
+
+ TRACE_INFO(_L("[BTHID]\tCBTHidServer::CloseBluetoothConnection"));
+ while ((i < iBTConnContainer->Count()) && (!foundItem))
+ {
+ CBTHidConnection *connection =
+ static_cast<CBTHidConnection*> ((*iBTConnContainer)[i]);
+
+ CBTHidDevice& devDetails = connection->DeviceDetails();
+
+ if (devDetails.iAddress == aAddress)
+ {
+ foundItem = ETrue;
+ // Inform the Generic HID of the disconnection.
+ iGenHID->Disconnected(connection->ConnID());
+
+ // Get it to disconnect if its connected.
+ connection->Disconnect();
+
+ // Delete the connection object.
+ iBTConnIndex->Remove(connection->ConnID());
+
+ // Update the stored devices, as we could have power off
+ // and no clean shutdown.
+ // Use the non-leaving version.
+ StoreVirtuallyCabledDevices(KFileStore);
+ }
+
+ i++;
+ }
+
+ }
+
+/*Asks the server to disconnect all the devices totally,
+ * remove the connection entries from the connection container.
+ */
+void CBTHidServer::CloseAllBluetoothConnection()
+ {
+ TInt i = 0;
+
+ TRACE_INFO(_L("[BTHID]\tCBTHidServer::CloseAllBluetoothConnection"));
+
+ while (i < iBTConnContainer->Count())
+ {
+ CBTHidConnection *connection =
+ static_cast<CBTHidConnection*> ((*iBTConnContainer)[i]);
+ if (connection)
+ {
+ if (connection->IsConnected())
+ {
+ // Inform the Generic HID of the disconnection.
+ iGenHID->Disconnected(connection->ConnID());
+
+ // Get it to disconnect if its connected.
+ connection->Disconnect();
+
+ // Delete the connection object.
+ iBTConnIndex->Remove(connection->ConnID());
+
+ // Update the stored devices, as we could have power off
+ // and no clean shutdown.
+ // Use the non-leaving version.
+ StoreVirtuallyCabledDevices(KFileStore);
+ }
+ }
+
+ i++;
+ }
+ }
+
+void CBTHidServer::DisconnectDeviceL(const TBTDevAddr& aAddress)
+ {
+ TInt i = 0;
+ TBool foundItem = EFalse;
+
+ TRACE_INFO(_L("[BTHID]\tCBTHidServer::DisconnectDeviceL"));
+ while ((i < iBTConnContainer->Count()) && (!foundItem))
+ {
+ CBTHidConnection *connection =
+ static_cast<CBTHidConnection*> ((*iBTConnContainer)[i]);
+
+ CBTHidDevice& devDetails = connection->DeviceDetails();
+
+ if (devDetails.iAddress == aAddress)
+ {
+ foundItem = ETrue;
+
+ // Drop the bluetooth connection.
+ connection->DropConnection();
+
+ // Stop the driver.
+ iGenHID->DriverActive(connection->ConnID(),
+ CHidTransport::ESuspend);
+
+ InformClientsOfStatusChange(connection->DeviceDetails(),
+ EBTDeviceDisconnected);
+ //Microsoft Keyboard & other "Unsecure" devices
+ CheckAndSetControlListenerSecurityL(
+ connection->DeviceDetails().iUseSecurity);
+ }
+
+ i++;
+ }
+ }
+
+void CBTHidServer::DisconnectAllDeviceL()
+ {
+ TInt i = 0;
+
+ TRACE_INFO(_L("[BTHID]\tCBTHidServer::DisconnectAllDeviceL"));
+ while (i < iBTConnContainer->Count())
+ {
+ CBTHidConnection *connection =
+ static_cast<CBTHidConnection*> ((*iBTConnContainer)[i]);
+
+ if (connection)
+ {
+ if (connection->IsConnected())
+ {
+ CBTHidDevice& devDetails = connection->DeviceDetails();
+
+ // Drop the bluetooth connection.
+ connection->DropConnection();
+
+ // Stop the driver.
+ iGenHID->DriverActive(connection->ConnID(),
+ CHidTransport::ESuspend);
+
+ InformClientsOfStatusChange(devDetails,
+ EBTDeviceDisconnected);
+ //Microsoft Keyboard & other "Unsecure" devices
+ CheckAndSetControlListenerSecurityL(
+ devDetails.iUseSecurity);
+ }
+
+ i++;
+ }
+ }
+ }
+
+void CBTHidServer::CheckAndSetControlListenerSecurityL(TBool aSec)
+ {
+
+ TRACE_INFO( (_L("[BTHID]\tCBTHidServer::CheckAndSetControlListenerSecurityL(%d)"), aSec) );
+
+ //Checking for Microsoft Keyboard & other "Unsecure" devices
+
+ if (!aSec) //Security is set on in Constructor of listener. This overrides that setting.
+ {
+ delete iControlListener;
+ iControlListener = NULL;
+ if (iTempControl)
+ iTempControl->Close();
+ iControlListener = CSocketListener::NewL(iSocketServ,
+ KL2CAPHidControl, *this, EFalse); //iAuthorisationFlag); We need authorisation, unless otherwise stated.
+ User::LeaveIfError(iControlListener->AcceptConnection(*iTempControl));
+ }
+
+ }
+
+// from MBTConnectionObserver
+void CBTHidServer::HandleControlData(TInt aConnID, const TDesC8& aBuffer)
+ {
+ iGenHID->DataIn(aConnID, CHidTransport::EHidChannelCtrl, aBuffer);
+ }
+
+void CBTHidServer::HandleCommandAck(TInt aConnID, TInt aStatus)
+ {
+ iGenHID->CommandResult(aConnID, aStatus);
+ }
+
+void CBTHidServer::HandleInterruptData(TInt aConnID, const TDesC8& aBuffer)
+ {
+ iGenHID->DataIn(aConnID, CHidTransport::EHidChannelInt, aBuffer);
+ }
+
+void CBTHidServer::FirstTimeConnectionComplete(TInt aConnID, TInt aStatus)
+ {
+ TRACE_INFO( (_L("[BTHID]\tCBTHidServer::FirstTimeConnectionComplete(%d)"), aStatus));
+ TInt error = aStatus;
+
+ CBTHidConnection* connection =
+ static_cast<CBTHidConnection*> (iBTConnIndex->At(aConnID));
+ __ASSERT_ALWAYS(connection, PanicServer(EInvalidHandle));
+
+ if (error == KErrNone)
+ {
+ TBool genHidConnected = EFalse;
+
+ TRAP( error,
+ // Inform the Generic HID of the Connection
+ GenericHIDConnectL(connection, ETrue);
+
+ // Record that we got as far as informing the Generic HID.
+ genHidConnected = ETrue;
+
+ // Try to start monitoring the channels.
+ connection->StartMonitoringChannelsL();
+ )
+
+ if (error != KErrNone)
+ {
+ // If we informed the Generic HID of the connection, then
+ // we must also disconnect.
+ if (genHidConnected)
+ {
+ iGenHID->Disconnected(aConnID);
+ }
+
+ // Delete the connection object.
+ iBTConnIndex->Remove(aConnID);
+ }
+ else
+ {
+ // Update the stored devices, as we could have power off
+ // and no clean shutdown.
+ // Use the non-leaving version.
+ TRACE_INFO( _L("[BTHID]\tCBTHidServer::FirstTimeConnectionComplete() before CleanOldConnection") );
+ CleanOldConnection(aConnID);
+ TRACE_INFO( _L("[BTHID]\tCBTHidServer::FirstTimeConnectionComplete() after CleanOldConnection") );
+ StoreVirtuallyCabledDevices(KFileStore);
+ }
+ }
+ else
+ {
+ iBTConnIndex->Remove(aConnID);
+ }
+
+ // Report the connection result to the sessions.
+ iSessionIter.SetToFirst();
+ for (;;)
+ {
+ CBTHidServerSession* session;
+ session = reinterpret_cast<CBTHidServerSession*> (iSessionIter++);
+ if (!session)
+ {
+ break;
+ }
+
+ session->InformConnectionResult(aConnID, error);
+ }
+ }
+
+void CBTHidServer::LinkLost(TInt aConnID)
+ {
+ TRACE_INFO( (_L("[BTHID]\tCBTHidServer::LinkLost(%d)"), aConnID));
+ // Stop the driver.
+ iGenHID->DriverActive(aConnID, CHidTransport::ESuspend);
+
+ CBTHidConnection* connection =
+ static_cast<CBTHidConnection*> (iBTConnIndex->At(aConnID));
+ __ASSERT_ALWAYS(connection, PanicServer(EInvalidHandle));
+
+ // Inform clients of the change in status of this connection.
+ InformClientsOfStatusChange(connection->DeviceDetails(),
+ EBTDeviceLinkLost);
+ }
+
+void CBTHidServer::LinkRestored(TInt aConnID)
+ {
+ CBTHidConnection* connection =
+ static_cast<CBTHidConnection*> (iBTConnIndex->At(aConnID));
+ __ASSERT_ALWAYS(connection, PanicServer(EInvalidHandle));
+
+ // Inform the Generic HID of the reconnection
+ TInt error = iGenHID->DriverActive(aConnID, CHidTransport::EActive);
+
+ // If there was no error, try to start monitoring the channels.
+ if (error == KErrNone)
+ {
+ // Try to start monitoring channels.
+ TRAP( error, connection->StartMonitoringChannelsL(); )
+ }
+
+ // Report new connection status.
+ if (error == KErrNone)
+ {
+ InformClientsOfStatusChange(connection->DeviceDetails(),
+ EBTDeviceLinkRestored);
+ }
+ else
+ {
+ InformClientsOfStatusChange(connection->DeviceDetails(),
+ EBTDeviceUnplugged);
+ // Inform the Generic HID of the disconnection.
+ iGenHID->Disconnected(aConnID);
+ // Delete the connection object.
+ iBTConnIndex->Remove(aConnID);
+
+ // Update the stored devices, as we could have power off
+ // and no clean shutdown.
+ // Use the non-leaving version.
+ StoreVirtuallyCabledDevices(KFileStore);
+ }
+ }
+
+void CBTHidServer::Disconnected(TInt aConnID)
+ {
+ CBTHidConnection *connection =
+ static_cast<CBTHidConnection*> (iBTConnIndex->At(aConnID));
+ __ASSERT_ALWAYS(connection, PanicServer(EInvalidHandle));
+
+ // Stop the driver.
+ iGenHID->DriverActive(aConnID, CHidTransport::ESuspend);
+
+ // Report new connection status.
+ InformClientsOfStatusChange(connection->DeviceDetails(),
+ EBTDeviceDisconnected);
+
+ //Check if no security is needed for listening socket
+ //Microsoft Keyboard & other "Unsecure" devices need this.
+
+ // possible leave is sign of severe problems in BT stack. So no reason to handle leave.
+ TRAP_IGNORE( CheckAndSetControlListenerSecurityL(connection->DeviceDetails().iUseSecurity) );
+
+ }
+
+void CBTHidServer::Unplugged(TInt aConnID)
+ {
+ CBTHidConnection *connection =
+ static_cast<CBTHidConnection*> (iBTConnIndex->At(aConnID));
+ __ASSERT_ALWAYS(connection, PanicServer(EInvalidHandle));
+
+ // Report new connection status.
+ InformClientsOfStatusChange(connection->DeviceDetails(),
+ EBTDeviceUnplugged);
+
+ // Inform the Generic HID of the disconnection.
+ iGenHID->Disconnected(aConnID);
+
+ iBTConnIndex->Remove(aConnID);
+
+ // Update the stored devices, as we could have power off
+ // and no clean shutdown.
+ // Use the non-leaving version.
+ StoreVirtuallyCabledDevices(KFileStore);
+ }
+
+//from MListenerObserver
+void CBTHidServer::SocketAccepted(TUint aPort, TInt aErrorCode)
+ {
+ TBTSockAddr sockAddr;
+ TBTDevAddr devAddr;
+
+ TRACE_INFO( (_L("[BTHID]\tCBTHidServer::SocketAccepted, port=%d, error code=%d"), aPort, aErrorCode) );
+
+ // Check error code
+ if (aErrorCode != KErrNone)
+ {
+ // If we do get an error there isn't much we can about it.
+ // Just tidy up.
+
+ ShutdownListeners(aErrorCode);
+ }
+ else
+ {
+ TInt i = 0;
+ TInt count = iBTConnContainer->Count();
+ TInt err = KErrNone;
+
+ // Check which port has accepted a connection
+ switch (aPort)
+ {
+ // The HID Control Channel
+ case KL2CAPHidControl:
+ // Get the BT address of the device that has connected
+ iTempControl->RemoteName(sockAddr);
+ devAddr = sockAddr.BTAddr();
+ if (IsAllowToConnectFromClientSide(devAddr))
+ {
+ while ((i < count) && (iTempControl))
+ {
+ CBTHidConnection
+ * connection =
+ static_cast<CBTHidConnection*> ((*iBTConnContainer)[i]);
+ __ASSERT_ALWAYS(connection, PanicServer(EInvalidHandle));
+ connection->OfferControlSocket(devAddr, iTempControl);
+ i++;
+ }
+
+ }
+ else
+ {
+ InformStatusChange(devAddr, EBTDeviceAnotherExist);
+ }
+
+ // The next socket to accept into
+ if (iTempControl)
+ {
+ // Reuse this socket
+ iTempControl->Close();
+ err = KErrNone;
+ }
+ else
+ {
+ // Socket ownership has been transferred so create a new
+ // socket
+ //TRAP( err, iTempControl = new (ELeave) RSocket; )
+ iTempControl = new RSocket;
+ }
+
+ // Created a socket to accept into so accept next connection
+ if (err == KErrNone)
+ {
+ err = iControlListener->AcceptConnection(*iTempControl);
+ }
+
+ // If we failed to allocate a new RSocket or failed
+ // in the AcceptConnectionL call it means we can no longer
+ // accept connections from a device.
+ if (err != KErrNone)
+ {
+ TRACE_INFO(_L("[BTHID]\tCBTHidServer::SocketAccepted, control channel failed, shutdown listener"));
+ ShutdownListeners(err);
+ }
+
+ break;
+
+ // The HID Interrupt Channel
+ case KL2CAPHidInterrupt:
+ // Get the BT address of the device that has connected
+ iTempInterrupt->RemoteName(sockAddr);
+ devAddr = sockAddr.BTAddr();
+ if (IsAllowToConnectFromClientSide(devAddr))
+ {
+ while ((i < count) && (iTempInterrupt))
+ {
+ CBTHidConnection
+ *connection =
+ static_cast<CBTHidConnection*> ((*iBTConnContainer)[i]);
+ __ASSERT_ALWAYS(connection, PanicServer(EInvalidHandle));
+ connection->OfferInterruptSocket(devAddr,
+ iTempInterrupt);
+ i++;
+ }
+ }
+ else
+ {
+ //Commented for avoiding display the same notes twice for same device
+ //because of two channels(Control+Interrupt) has been rejected
+ //InformStatusChange(devAddr, EBTDeviceAnotherExist);
+ }
+
+ // The next socket to accept into
+ if (iTempInterrupt)
+ {
+ // Reuse this socket
+ iTempInterrupt->Close();
+ err = KErrNone;
+ }
+ else
+ {
+ // Socket ownership has been transferred so create a new
+ // socket
+ //TRAP( err, iTempInterrupt = new (ELeave) RSocket; )
+ iTempInterrupt = new RSocket;
+ }
+
+ // Created a socket to accept into so accept next connection
+ if (err == KErrNone)
+ {
+ err = iInterruptListener->AcceptConnection(
+ *iTempInterrupt);
+ }
+
+ // If we failed to allocate a new RSocket or failed
+ // in the AcceptConnectionL call it means we can no longer
+ // accept connections from a device.
+ if (err != KErrNone)
+ {
+ TRACE_INFO(_L("[BTHID]\tCBTHidServer::SocketAccepted, interrupt channel failed, shutdown listener"));
+ ShutdownListeners(err);
+ }
+ break;
+
+ default:
+ PanicServer(EInvalidHandle);
+ break;
+ }
+ }
+
+ }
+
+//from MTransportLayer
+TUint CBTHidServer::CountryCodeL(TInt aConnID)
+ {
+ // Identify the connection object.
+ CBTHidConnection* conn = IdentifyConnectionL(aConnID);
+ // Retrieve its device details.
+ const CBTHidDevice& device = conn->DeviceDetails();
+
+ //return the country code
+ return device.iCountryCode;
+ }
+
+TUint CBTHidServer::VendorIdL(TInt aConnID)
+ {
+ // Identify the connection object.
+ CBTHidConnection* conn = IdentifyConnectionL(aConnID);
+ // Retrieve its device details.
+ const CBTHidDevice& device = conn->DeviceDetails();
+
+ //return the Vendor Id.
+ return device.iVendorID;
+ }
+
+TUint CBTHidServer::ProductIdL(TInt aConnID)
+ {
+ // Identify the connection object.
+ CBTHidConnection* conn = IdentifyConnectionL(aConnID);
+ // Retrieve its device details.
+ const CBTHidDevice& device = conn->DeviceDetails();
+
+ //return the Product Id.
+ return device.iProductID;
+ }
+
+void CBTHidServer::GetProtocolL(TInt aConnID, TUint16 /*aInterface*/)
+ {
+ CBTHidConnection *connection = IdentifyConnectionL(aConnID);
+
+ // Bluetooth HID only has one interface. We don't need the interface param.
+ connection->GetProtocolL();
+ }
+
+void CBTHidServer::SetProtocolL(TInt aConnID, TUint16 aValue, TUint16 /*aInterface*/)
+ {
+ CBTHidConnection *connection = IdentifyConnectionL(aConnID);
+
+ // Bluetooth HID only has one interface. We don't need the interface param.
+ connection->SetProtocolL(aValue);
+ }
+
+void CBTHidServer::GetReportL(TInt aConnID, TUint8 aReportType,
+ TUint8 aReportID, TUint16 /*aInterface*/, TUint16 aLength)
+ {
+ CBTHidConnection *connection = IdentifyConnectionL(aConnID);
+
+ // Bluetooth HID only has one interface. We don't need the interface param.
+ connection->GetReportL(aReportType, aReportID, aLength);
+ }
+
+void CBTHidServer::SetReportL(TInt aConnID, TUint8 aReportType,
+ TUint8 aReportID, TUint16 /*aInterface*/, const TDesC8& aReport)
+ {
+ CBTHidConnection *connection = IdentifyConnectionL(aConnID);
+
+ // Bluetooth HID only has one interface. We don't need the interface param
+ connection->SetReportL(aReportType, aReportID, aReport);
+ }
+
+void CBTHidServer::DataOutL(TInt aConnID, TUint8 aReportID,
+ TUint16 /*aInterface*/, const TDesC8& aReport)
+ {
+ CBTHidConnection *connection = IdentifyConnectionL(aConnID);
+
+ // Bluetooth HID only has one interface. We don't need the interface param
+ connection->DataOutL(aReportID, aReport); //we disregard DATA Input, DATA Feature and DATA Other
+ }
+
+void CBTHidServer::GetIdleL(TInt aConnID, TUint8 /*aReportID*/, TUint16 /*aInterface*/)
+ {
+ CBTHidConnection *connection = IdentifyConnectionL(aConnID);
+
+ // Bluetooth HID only has one interface. We don't need the interface param.
+ // Bluetooth HID doesn't specify Report ID.
+ connection->GetIdleL();
+ }
+
+void CBTHidServer::SetIdleL(TInt aConnID, TUint8 aDuration,
+ TUint8 /*aReportID*/, TUint16 /*aInterface*/)
+ {
+ CBTHidConnection *connection = IdentifyConnectionL(aConnID);
+
+ // Bluetooth HID only has one interface. We don't need the interface param.
+ // Bluetooth HID doesn't specify Report ID.
+ connection->SetIdleL(aDuration);
+ }
+
+CBTHidConnection* CBTHidServer::IdentifyConnectionL(TInt aConnID) const
+ {
+ CBTHidConnection *connection =
+ static_cast<CBTHidConnection*> (iBTConnIndex->At(aConnID));
+
+ if (!connection)
+ {
+ User::Leave(KErrNotFound);
+ }
+
+ return connection;
+ }
+
+void CBTHidServer::LoadVirtuallyCabledDevicesL(const TDesC& aStoreName)
+ {
+ TRACE_INFO(_L("[BTHID]\tCBTHidServer::LoadVirtuallyCabledDevicesL"));
+ // Create the parsed name and open the store
+ TParse parsedName;
+ User::LeaveIfError(iFs.Parse(aStoreName, parsedName));
+
+ CFileStore* store = CDirectFileStore::OpenLC(iFs, parsedName.FullName(),
+ EFileRead);
+
+ // Open the data stream inside the store
+ RStoreReadStream stream;
+ stream.OpenLC(*store, store->Root());
+
+ // Read the version number of the data file.
+ // Its not used in this version.
+ stream.ReadInt32L();
+
+ // Get the number of devices to load.
+ TInt count = stream.ReadInt32L();
+ TInt i;
+ for (i = 0; i < count; i++)
+ {
+ // Create the connection object. Ok to leave.
+ CBTHidConnection* connection = CBTHidConnection::NewLC(iSocketServ,
+ *this, ENotConnected);
+
+ stream >> connection->DeviceDetails();
+ // Check if no security is needed, then override earlier Control listener with unsecure one.
+ // This is needed for Microsoft Keyboard fix.
+ CheckAndSetControlListenerSecurityL(
+ connection->DeviceDetails().iUseSecurity);
+
+ // Add to the connection container object.
+ iBTConnContainer->AddL(connection);
+ CleanupStack::Pop(); // connection
+
+ // We can't let this just leave since we have already inserted the
+ // connection object into the container.
+ TBool connectionIndexed = EFalse;
+ TRAPD( res,
+ // Now add the object to the index to get an id.
+ TInt id = iBTConnIndex->AddL(connection);
+ connection->SetConnID(id);
+ connectionIndexed = ETrue;
+ connection->ReconnectL();
+
+ // Inform the Generic HID of the connection, but don't
+ // start the driver yet. This will be done in LinkRestored.
+ GenericHIDConnectL(connection, EFalse);
+ )
+
+ if (res != KErrNone)
+ {
+ if (connectionIndexed)
+ {
+ // Connection object was added to the index, but reconnection
+ // failed.
+ iBTConnIndex->Remove(connection->ConnID());
+ }
+ else
+ {
+ // Couldn't make an index entry.
+ // Close the connection object, causing it to be removed from
+ // the container.
+ connection->Close();
+ }
+ }
+ }
+
+ // Delete all the remaining stuff on the cleanup stack
+ // (store and stream)
+ CleanupStack::PopAndDestroy(2);
+ }
+
+void CBTHidServer::StoreVirtuallyCabledDevicesL(const TDesC& aStoreName)
+ {
+ TRACE_INFO(_L("[BTHID]\tCBTHidServer::StoreVirtuallyCabledDevicesL"));
+ // Parse the filestore name into a usable version.
+ TParse parsedName;
+ User::LeaveIfError(iFs.Parse(aStoreName, parsedName));
+
+ // Count the number of devices that we will need to store.
+ // Also count the accumulated disk size require for each one.
+ TInt numVirtuallyCabled = 0;
+ TInt requiredDiskSize = 0;
+
+ TInt i;
+
+ for (i = 0; i < iBTConnContainer->Count(); i++)
+ {
+ CBTHidConnection *connection =
+ static_cast<CBTHidConnection*> ((*iBTConnContainer)[i]);
+
+ if (connection)
+ {
+ CBTHidDevice &device = connection->DeviceDetails();
+ if (device.iVirtuallyCabled)
+ {
+ numVirtuallyCabled++;
+ // Increase the required size.
+ requiredDiskSize += device.DiskSize();
+ }
+ }
+ }
+
+ // Check for required disk size
+ // NOTE !! Be careful when changing functionality in here
+
+ // We have the number of bytes required to store all the device objects
+ // we want to store
+
+ // First thing written will be the file version which is 4 bytes
+ // Then the number of virtually cabled devices which is 4 bytes
+ requiredDiskSize += 8;
+
+ TRACE_INFO( (_L("[BTHID]\tCBTHidServer::StoreVirtuallyCabledDevicesL: Required disk size %d bytes"),
+ requiredDiskSize) );
+ // Now check that the required number of bytes will not take us into
+ // the critical disk space area.
+ if (SysUtil::DiskSpaceBelowCriticalLevelL(&iFs, requiredDiskSize, EDriveC))
+ {
+ User::Leave(KErrDiskFull);
+ }
+
+ // Start the write for real.
+
+ CFileStore* store = CDirectFileStore::ReplaceLC(iFs,
+ parsedName.FullName(), EFileWrite);
+ store->SetTypeL(KDirectFileStoreLayoutUid);
+
+ // Create the stream
+ RStoreWriteStream stream;
+ TStreamId id = stream.CreateLC(*store);
+
+ // Write the version number of the data file
+ stream.WriteInt32L(KDataFileVersionNumber);
+
+ // Write the number of devices we are going to store.
+ stream.WriteInt32L(numVirtuallyCabled);
+
+ // Externalise each device object that is virtually cabled.
+ for (i = 0; i < iBTConnContainer->Count(); i++)
+ {
+ CBTHidConnection *connection =
+ static_cast<CBTHidConnection*> ((*iBTConnContainer)[i]);
+
+ if (connection)
+ {
+ CBTHidDevice &device = connection->DeviceDetails();
+ if (device.iVirtuallyCabled)
+ {
+ stream << device;
+ }
+ }
+
+ }
+
+ // Commit the changes to the stream
+ stream.CommitL();
+ CleanupStack::PopAndDestroy();
+
+ // Set the stream in the store and commit the store
+ store->SetRootL(id);
+ store->CommitL();
+ CleanupStack::PopAndDestroy();
+ }
+
+void CBTHidServer::StoreVirtuallyCabledDevices(const TDesC& aStoreName)
+ {
+ TRAP_IGNORE( StoreVirtuallyCabledDevicesL(aStoreName);)
+ }
+
+void RunServerL()
+ {
+ TRACE_FUNC_ENTRY
+ User::RenameThread(KBTHidSrvName);
+ // Create and install the active scheduler for this thread.
+ CActiveScheduler* scheduler = new (ELeave) CActiveScheduler();
+ CleanupStack::PushL(scheduler);
+ CActiveScheduler::Install(scheduler);
+ // create the server (leave it on the cleanup stack)
+ CBTHidServer* btHidServer = CBTHidServer::NewLC();
+ // Initialisation complete, now signal the client
+ RProcess::Rendezvous(KErrNone);
+ // The server is not up and running.
+ TRACE_INFO( ( _L( "[BTHID]\t BTHID server now up and running" ) ) )
+ // The active scheduler runs during the lifetime of this thread.
+ CActiveScheduler::Start();
+ // Cleanup the server and scheduler.
+ CleanupStack::PopAndDestroy(btHidServer);
+ CleanupStack::PopAndDestroy(scheduler);
+ TRACE_FUNC_EXIT
+ }
+
+GLDEF_C TInt E32Main()
+ {
+ __UHEAP_MARK;
+ TRACE_FUNC_ENTRY
+ CTrapCleanup* cleanup = CTrapCleanup::New();
+ TInt err = KErrNoMemory;
+ if (cleanup)
+ {
+ TRAP( err, RunServerL() );
+ delete cleanup;
+ }
+ __UHEAP_MARKEND;
+ return err;
+ }
+
+// CBTHidNotifierHelper
+
+CBTHidNotifierHelper* CBTHidNotifierHelper::NewL(CBTHidServer& aHidServer, TInt aNote, const TBTDevAddr& aDeviceAddr)
+ {
+ CBTHidNotifierHelper* self = new(ELeave) CBTHidNotifierHelper(aHidServer, aNote, aDeviceAddr);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+CBTHidNotifierHelper::~CBTHidNotifierHelper()
+ {
+ Cancel();
+ iNotifier.Close();
+ }
+
+void CBTHidNotifierHelper::Start()
+ {
+ TRACE_INFO(_L("CBTHidNotifierHelper::Start()..."));
+
+ // Simple async handling
+ iNotifier.StartNotifierAndGetResponse(iStatus,
+ KBTGenericInfoNotifierUid, iGenericInfoNotifierType,
+ iNoResult);
+
+ // assert object is not already active
+ __ASSERT_DEBUG(!IsActive(), CBTHidServer::PanicServer(ENotifierAlreadyActive));
+
+ SetActive();
+ }
+
+void CBTHidNotifierHelper::DoCancel()
+ {
+ TRACE_INFO(_L("CBTHidNotifierHelper::DoCancel()..."));
+
+ iNotifier.CancelNotifier(KBTGenericInfoNotifierUid);
+ }
+
+CBTHidNotifierHelper::CBTHidNotifierHelper(CBTHidServer& aHidServer, TInt aNote, const TBTDevAddr& aDeviceAddr)
+ : CActive(CActive::EPriorityStandard),
+ iHidServer(aHidServer)
+ {
+ TRACE_INFO(_L("CBTHidNotifierHelper::CBTHidNotifierHelper()..."));
+
+ iGenericInfoNotifierType().iMessageType = (TBTGenericInfoNoteType) aNote;
+ iGenericInfoNotifierType().iRemoteAddr.Copy(aDeviceAddr.Des());
+
+ CActiveScheduler::Add(this);
+ }
+
+void CBTHidNotifierHelper::ConstructL()
+ {
+ TRACE_INFO(_L("CBTHidNotifierHelper::ConstructL()..."));
+
+ User::LeaveIfError(iNotifier.Connect());
+ }
+
+void CBTHidNotifierHelper::RunL()
+ {
+ TRACE_INFO(_L("CBTHidNotifierHelper::RunL()..."));
+
+ iHidServer.NotifierRequestCompleted();
+ }