--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <windows.h>
+#include <stdio.h>
+#include <powrprof.h>
+#include <winuser.h>
+
+#include "service.h"
+#include "convdevice.h"
+#include "devicelist.h"
+
+CConvDevice::CConvDevice(const wchar_t* path) : CDevice(path)
+{
+}
+
+/*virtual*/ CConvDevice::~CConvDevice()
+{
+}
+
+void CConvDevice::SetMode(DWORD new_mode)
+{
+ DisablePrompt();
+
+ CXenAgent::Log("New mode = %s\n", new_mode ? "Laptop" : "Slate");
+
+ for (;;) {
+ BYTE buffer(0);
+ DWORD current_mode(CCONV_DEVICE_UNKNOWN_MODE);
+
+ if (!GetMode(¤t_mode))
+ break;
+
+ CXenAgent::Log("Current mode = %s\n",
+ current_mode ? "Laptop" : "Slate");
+
+ if (current_mode == new_mode)
+ break;
+
+ Write(&buffer, sizeof(buffer));
+ Sleep(1000); // yield
+ }
+}
+
+bool CConvDevice::DisablePrompt()
+{
+ HKEY key;
+ LRESULT lr;
+ std::string path;
+
+ path = "System\\CurrentControlSet\\Control\\PriorityControl";
+
+ lr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, path.c_str(), 0, KEY_ALL_ACCESS,
+ &key);
+ if (lr != ERROR_SUCCESS)
+ goto fail1;
+
+ DWORD type(REG_DWORD);
+ DWORD val(0);
+ DWORD length;
+
+ length = sizeof(val);
+ lr = RegSetValueEx(key, "ConvertibleSlateModePromptPreference", NULL,
+ type, (LPBYTE)&val, length);
+ if (lr != ERROR_SUCCESS)
+ goto fail2;
+
+ RegCloseKey(key);
+
+ return true;
+
+fail2:
+ RegCloseKey(key);
+fail1:
+ return false;
+}
+
+bool CConvDevice::GetMode(DWORD *mode)
+{
+ HKEY key;
+ LRESULT lr;
+ std::string path;
+
+ path = "System\\CurrentControlSet\\Control\\PriorityControl";
+
+ lr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, path.c_str(), 0, KEY_READ, &key);
+ if (lr != ERROR_SUCCESS)
+ goto fail1;
+
+ DWORD type;
+ DWORD val;
+ DWORD length;
+
+ length = sizeof(val);
+ lr = RegQueryValueEx(key, "ConvertibleSlateMode", NULL, &type,
+ (LPBYTE)&val, &length);
+ if (lr != ERROR_SUCCESS || type != REG_DWORD)
+ goto fail2;
+
+ RegCloseKey(key);
+
+ *mode = val;
+ return true;
+
+fail2:
+ RegCloseKey(key);
+fail1:
+ return false;
+}
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __XENAGENT_CONVDEVICE_H__
+#define __XENAGENT_CONVDEVICE_H__
+
+#include <windows.h>
+#include <string>
+#include "devicelist.h"
+
+enum {
+ CCONV_DEVICE_SLATE_MODE,
+ CCONV_DEVICE_LAPTOP_MODE,
+ CCONV_DEVICE_UNKNOWN_MODE
+};
+
+class CConvDevice : public CDevice
+{
+public:
+ CConvDevice(const wchar_t* path);
+ virtual ~CConvDevice();
+
+public:
+ void SetMode(DWORD mode);
+
+private:
+ bool DisablePrompt();
+ bool GetMode(DWORD *mode);
+};
+
+#endif
m_handle = INVALID_HANDLE_VALUE;
}
+bool CDevice::Write(void *buf, DWORD bufsz, DWORD *bytes /* = NULL*/)
+{
+ if (m_handle == INVALID_HANDLE_VALUE)
+ return false;
+
+ DWORD _bytes;
+ if (!WriteFile(m_handle,
+ buf,
+ bufsz,
+ (bytes == NULL) ? &_bytes : bytes,
+ NULL))
+ return false;
+
+ return true;
+}
+
bool CDevice::Ioctl(DWORD ioctl, void* in, DWORD insz, void* out, DWORD outsz, DWORD* bytes /*= NULL*/)
{
if (m_handle == INVALID_HANDLE_VALUE)
void Close();
protected:
+ bool Write(void *buf, DWORD bufsz, DWORD *bytes = NULL);
bool Ioctl(DWORD ioctl, void* in, DWORD insz, void* out, DWORD outsz, DWORD* bytes = NULL);
private:
Language=English
The tools experienced an unexpected error.
.
+
+MessageId=0x0009
+Facility=System
+Severity=Informational
+SymbolicName=EVENT_XENUSER_MODE_SWITCH
+Language=English
+The tools requested a mode switch.
+.
CXenIfaceCreator::CXenIfaceCreator(CXenAgent& agent) :
m_devlist(GUID_INTERFACE_XENIFACE), m_device(NULL),
- m_ctxt_shutdown(NULL), m_ctxt_suspend(NULL), m_agent(agent)
+ m_ctxt_shutdown(NULL), m_ctxt_suspend(NULL),
+ m_ctxt_slate_mode(NULL), m_agent(agent)
{
m_evt_shutdown = CreateEvent(FALSE, NULL, NULL, FALSE);
m_evt_suspend = CreateEvent(FALSE, NULL, NULL, FALSE);
+ m_evt_slate_mode = CreateEvent(FALSE, NULL, NULL, FALSE);
m_count = 0;
InitializeCriticalSection(&m_crit);
CXenIfaceCreator::~CXenIfaceCreator()
{
+ CloseHandle(m_evt_slate_mode);
CloseHandle(m_evt_suspend);
CloseHandle(m_evt_shutdown);
m_device = (CXenIfaceDevice*)dev;
m_device->SuspendRegister(m_evt_suspend, &m_ctxt_suspend);
+
StartShutdownWatch();
+
+ if (m_agent.ConvDevicePresent())
+ StartSlateModeWatch();
+
SetXenTime();
}
}
m_device->SuspendDeregister(m_ctxt_suspend);
m_ctxt_suspend = NULL;
}
+
+ if (m_agent.ConvDevicePresent())
+ StopSlateModeWatch();
+
StopShutdownWatch();
m_device = NULL;
/*virtual*/ void CXenIfaceCreator::OnDeviceSuspend(CDevice* dev)
{
CXenAgent::Log("OnDeviceSuspend(%ws)\n", dev->Path());
+
+ if (m_agent.ConvDevicePresent())
+ StopSlateModeWatch();
+
StopShutdownWatch();
}
/*virtual*/ void CXenIfaceCreator::OnDeviceResume(CDevice* dev)
{
CXenAgent::Log("OnDeviceResume(%ws)\n", dev->Path());
+
StartShutdownWatch();
+
+ if (m_agent.ConvDevicePresent())
+ StartSlateModeWatch();
}
bool CXenIfaceCreator::CheckShutdown()
m_agent.EventLog(EVENT_XENUSER_UNSUSPENDED);
- // recreate shutdown watch, as suspending deactivated the watch
+ // recreate watches, as suspending deactivated the watch
+ if (m_agent.ConvDevicePresent())
+ StopSlateModeWatch();
+
StopShutdownWatch();
+
StartShutdownWatch();
+
+ if (m_agent.ConvDevicePresent())
+ StartSlateModeWatch();
+
SetXenTime();
m_count = count;
}
+bool CXenIfaceCreator::CheckSlateMode(std::string *mode)
+{
+ CCritSec crit(&m_crit);
+ if (m_device == NULL)
+ return false;
+
+ if (!m_device->StoreRead("control/laptop-slate-mode", *mode))
+ return false;
+
+ if (*mode != "")
+ m_device->StoreWrite("control/laptop-slate-mode", "");
+
+ return true;
+}
+
void CXenIfaceCreator::StartShutdownWatch()
{
if (m_ctxt_shutdown)
m_ctxt_shutdown = NULL;
}
+void CXenIfaceCreator::StartSlateModeWatch()
+{
+ if (m_ctxt_slate_mode)
+ return;
+
+ m_device->StoreAddWatch("control/laptop-slate-mode", m_evt_slate_mode, &m_ctxt_slate_mode);
+ m_device->StoreWrite("control/feature-laptop-slate-mode", "1");
+}
+
+void CXenIfaceCreator::StopSlateModeWatch()
+{
+ if (!m_ctxt_slate_mode)
+ return;
+
+ m_device->StoreRemove("control/feature-laptop-slate-mode");
+
+ m_device->StoreRemoveWatch(m_ctxt_slate_mode);
+ m_ctxt_slate_mode = NULL;
+}
+
void CXenIfaceCreator::AcquireShutdownPrivilege()
{
HANDLE token;
SetLocalTime(&sys);
}
+/* 317fc439-3f77-41c8-b09e-08ad63272aa3 */
+DEFINE_GUID(GUID_GPIOBUTTONS_LAPTOPSLATE_INTERFACE, \
+ 0x317fc439, 0x3f77, 0x41c8, 0xb0, 0x9e, 0x08, 0xad, 0x63, 0x27, 0x2a, 0xa3);
+
+CConvCreator::CConvCreator(CXenAgent& agent) :
+ m_devlist(GUID_GPIOBUTTONS_LAPTOPSLATE_INTERFACE), m_device(NULL),
+ m_agent(agent)
+{
+ InitializeCriticalSection(&m_crit);
+}
+
+CConvCreator::~CConvCreator()
+{
+ DeleteCriticalSection(&m_crit);
+}
+
+bool CConvCreator::Start(HANDLE svc)
+{
+ return m_devlist.Start(svc, this);
+}
+
+void CConvCreator::Stop()
+{
+ m_devlist.Stop();
+}
+
+void CConvCreator::OnDeviceEvent(DWORD evt, LPVOID data)
+{
+ m_devlist.OnDeviceEvent(evt, data);
+}
+
+void CConvCreator::OnPowerEvent(DWORD evt, LPVOID data)
+{
+ m_devlist.OnPowerEvent(evt, data);
+}
+
+void CConvCreator::SetSlateMode(std::string mode)
+{
+ CCritSec crit(&m_crit);
+ if (m_device == NULL)
+ return;
+
+ m_agent.EventLog(EVENT_XENUSER_MODE_SWITCH);
+
+ if (mode == "laptop")
+ m_device->SetMode(CCONV_DEVICE_LAPTOP_MODE);
+ else if (mode == "slate")
+ m_device->SetMode(CCONV_DEVICE_SLATE_MODE);
+}
+
+bool CConvCreator::DevicePresent()
+{
+ return m_device != NULL;
+}
+
+/*virtual*/ CDevice* CConvCreator::Create(const wchar_t* path)
+{
+ return new CConvDevice(path);
+}
+
+/*virtual*/ void CConvCreator::OnDeviceAdded(CDevice* dev)
+{
+ CXenAgent::Log("OnDeviceAdded(%ws)\n", dev->Path());
+
+ CCritSec crit(&m_crit);
+ if (m_device == NULL)
+ m_device = (CConvDevice*)dev;
+}
+
+/*virtual*/ void CConvCreator::OnDeviceRemoved(CDevice* dev)
+{
+ CXenAgent::Log("OnDeviceRemoved(%ws)\n", dev->Path());
+
+ CCritSec crit(&m_crit);
+ if (m_device == dev)
+ m_device = NULL;
+}
+
+/*virtual*/ void CConvCreator::OnDeviceSuspend(CDevice* dev)
+{
+ CXenAgent::Log("OnDeviceSuspend(%ws)\n", dev->Path());
+}
+
+/*virtual*/ void CConvCreator::OnDeviceResume(CDevice* dev)
+{
+ CXenAgent::Log("OnDeviceResume(%ws)\n", dev->Path());
+}
+
static CXenAgent s_service;
/*static*/ void CXenAgent::Log(const char* fmt, ...)
#pragma warning(push)
#pragma warning(disable:4355)
-CXenAgent::CXenAgent() : m_handle(NULL), m_evtlog(NULL), m_xeniface(*this)
+CXenAgent::CXenAgent() : m_handle(NULL), m_evtlog(NULL), m_xeniface(*this),
+ m_conv(*this)
{
m_status.dwServiceType = SERVICE_WIN32;
m_status.dwCurrentState = SERVICE_START_PENDING;
void CXenAgent::OnServiceStart()
{
CXenAgent::Log("OnServiceStart()\n");
+ m_conv.Start(m_handle);
m_xeniface.Start(m_handle);
}
{
CXenAgent::Log("OnServiceStop()\n");
m_xeniface.Stop();
+ m_conv.Stop();
}
void CXenAgent::OnDeviceEvent(DWORD evt, LPVOID data)
{
+ m_conv.OnDeviceEvent(evt, data);
m_xeniface.OnDeviceEvent(evt, data);
}
void CXenAgent::OnPowerEvent(DWORD evt, LPVOID data)
{
+ m_conv.OnPowerEvent(evt, data);
m_xeniface.OnPowerEvent(evt, data);
}
bool CXenAgent::ServiceMainLoop()
{
- HANDLE events[3] = { m_svc_stop, m_xeniface.m_evt_shutdown,
- m_xeniface.m_evt_suspend };
- DWORD wait = WaitForMultipleObjectsEx(3, events, FALSE, 60000, TRUE);
+ HANDLE events[] = { m_svc_stop,
+ m_xeniface.m_evt_shutdown,
+ m_xeniface.m_evt_suspend,
+ m_xeniface.m_evt_slate_mode };
+ DWORD wait = WaitForMultipleObjectsEx(4, events, FALSE, 60000, TRUE);
switch (wait) {
case WAIT_OBJECT_0:
m_xeniface.CheckSuspend();
return true; // continue loop
+ case WAIT_OBJECT_0+3: {
+ std::string mode;
+
+ if (m_xeniface.CheckSlateMode(&mode))
+ m_conv.SetSlateMode(mode);
+
+ return true; // continue loop
+ }
case WAIT_IO_COMPLETION:
case WAIT_TIMEOUT:
m_xeniface.CheckSuspend();
}
}
+bool CXenAgent::ConvDevicePresent()
+{
+ return m_conv.DevicePresent();
+}
+
void CXenAgent::SetServiceStatus(DWORD state, DWORD exit /*= 0*/, DWORD hint /*= 0*/)
{
m_status.dwCurrentState = state;
#include "devicelist.h"
#include "xenifacedevice.h"
+#include "convdevice.h"
class CXenAgent;
public:
bool CheckShutdown();
void CheckSuspend();
+ bool CheckSlateMode(std::string *mode);
public:
HANDLE m_evt_shutdown;
HANDLE m_evt_suspend;
+ HANDLE m_evt_slate_mode;
private:
void StartShutdownWatch();
void StopShutdownWatch();
+ void StartSlateModeWatch();
+ void StopSlateModeWatch();
void AcquireShutdownPrivilege();
bool IsHostTimeUTC();
void AdjustXenTimeToUTC(FILETIME* time);
CRITICAL_SECTION m_crit;
void* m_ctxt_shutdown;
void* m_ctxt_suspend;
+ void* m_ctxt_slate_mode;
DWORD m_count;
};
+class CConvCreator : public IDeviceCreator
+{
+public:
+ CConvCreator(CXenAgent&);
+ virtual ~CConvCreator();
+ CConvCreator& operator=(const CConvCreator&);
+
+ bool Start(HANDLE svc);
+ void Stop();
+ void OnDeviceEvent(DWORD evt, LPVOID data);
+ void OnPowerEvent(DWORD evt, LPVOID data);
+ void SetSlateMode(std::string mode);
+ bool DevicePresent();
+
+public:
+ virtual CDevice* Create(const wchar_t* path);
+ virtual void OnDeviceAdded(CDevice* dev);
+ virtual void OnDeviceRemoved(CDevice* dev);
+ virtual void OnDeviceSuspend(CDevice* dev);
+ virtual void OnDeviceResume(CDevice* dev);
+
+private:
+ CXenAgent& m_agent;
+ CDeviceList m_devlist;
+ CConvDevice* m_device;
+ CRITICAL_SECTION m_crit;
+};
+
class CXenAgent
{
public: // statics
public:
void EventLog(DWORD evt);
+public:
+ bool ConvDevicePresent();
+
private: // service events
void OnServiceStart();
void OnServiceStop();
HANDLE m_evtlog;
HANDLE m_svc_stop;
CXenIfaceCreator m_xeniface;
+ CConvCreator m_conv;
};
#endif
<ClCompile Include="..\..\src\xenagent\service.cpp"/>
<ClCompile Include="..\..\src\xenagent\devicelist.cpp"/>
<ClCompile Include="..\..\src\xenagent\xenifacedevice.cpp"/>
+ <ClCompile Include="..\..\src\xenagent\convdevice.cpp"/>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\src\xenagent\xenagent.rc" />
<ClCompile Include="..\..\src\xenagent\service.cpp"/>
<ClCompile Include="..\..\src\xenagent\devicelist.cpp"/>
<ClCompile Include="..\..\src\xenagent\xenifacedevice.cpp"/>
+ <ClCompile Include="..\..\src\xenagent\convdevice.cpp"/>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\src\xenagent\xenagent.rc" />
<ClCompile Include="..\..\src\xenagent\service.cpp"/>
<ClCompile Include="..\..\src\xenagent\devicelist.cpp"/>
<ClCompile Include="..\..\src\xenagent\xenifacedevice.cpp"/>
+ <ClCompile Include="..\..\src\xenagent\convdevice.cpp"/>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\src\xenagent\xenagent.rc" />