📄 marvell.c
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
#include <windows.h>
#include <ntddndis.h>
#include <nuiouser.h>
#include "zones.h"
extern BOOL g_HostWakeSet;
int SetPowerMode(HANDLE hNDisUIO, LPTSTR pszDeviceName, ULONG nPowerMode);
int QueryPowerMode(HANDLE hNDisUIO, LPTSTR pszDeviceName, PULONG pulPowerMode);
typedef enum
{ // card is in full power
PS_STATE_FULL_POWER,
// PS mode, but card is ready for TX
PS_STATE_WAKEUP,
// PS Mode, card is not ready for TX
PS_STATE_SLEEP,
// SLEEP event is already received, but have not sent confirm yet
PS_STATE_SLEEP_PENDING,
} PS_STATE;
typedef enum
{
HTWK_STATE_FULL_POWER,
HTWK_STATE_PRESLEEP,
HTWK_STATE_SLEEP,
} HTWK_STATE;
typedef struct _Mrvl_EthTypeEntry
{
USHORT AddressType;
USHORT EthType;
ULONG Ipv4Addr;
} MRVL_ETHTYPE_ENTRY, *PMRVL_ETHTYPE_ENTRY;
#pragma pack(1)
typedef struct _MrvlIEtypesHeader {
USHORT Type;
USHORT Len;
} MrvlIEtypesHeader_t;
typedef struct _OID_MRVL_DS_HOST_WAKEUP_FILTER
{
MrvlIEtypesHeader_t Header;
USHORT AddressType;
USHORT EthType;
ULONG Ipv4Addr;
} OID_MRVL_DS_HOST_WAKEUP_FILTER, *POID_MRVL_DS_HOST_WAKEUP_FILTER;
typedef struct _OID_MRVL_DS_HOST_WAKEUP
{
ULONG ulCriteria;
UCHAR ucGPIO;
UCHAR ucGap;
OID_MRVL_DS_HOST_WAKEUP_FILTER pFilter[1];
} OID_MRVL_DS_HOST_WAKEUP, *POID_MRVL_DS_HOST_WAKEUP;
typedef struct _OID_MRVL_DS_HOST_WAKEUP_STATUS
{
ULONG hwState;
ULONG psState;
} OID_MRVL_DS_HOST_WAKEUP_STATUS, *POID_MRVL_DS_HOST_WAKEUP_STATUS;
#pragma pack()
#define OID_MRVL_HOST_SLEEP_CFG 0xff010224
#define OID_MRVL_DEEP_SLEEP 0xff010220
#define OID_MRVL_HOST_SLEEP_STATUS 0xff010242
//
// This function removes the host wake configuration from the chipset firmware.
// With the configuration removed, the chip will not go into hostwake mode during
// suspend, unless it is set again. This is typically done when the device resumes
// from a suspended state, so that the hostwake feature will not interfere with
// the normal power save feature.
//
int RemoveHostWakeupEx(HANDLE hNDisUIO, LPTSTR pszDeviceName)
{
BOOL fRetVal = TRUE;
PNDISUIO_SET_OID pSetOid = NULL;
UCHAR SetBuffer[sizeof(NDISUIO_SET_OID) + sizeof(OID_MRVL_DS_HOST_WAKEUP)];
DWORD cbBuffer = 0;
DWORD cbDataSize = 0;
DWORD cbSize = 0;
DWORD dwBytesReturned = 0;
OID_MRVL_DS_HOST_WAKEUP HostWakeCfg;
// CmdLen field needs only the size of the Cmd Body.
// That is the size of everything minus the OID and the CmdLen field
memset(&HostWakeCfg, 0, sizeof(HostWakeCfg));
HostWakeCfg.ucGap = 0xF0;
HostWakeCfg.ucGPIO = 0x1;
HostWakeCfg.ulCriteria = 0xFFFFFFFF;
pSetOid = (PNDISUIO_SET_OID) & SetBuffer[0];
pSetOid->ptcDeviceName = (LPTSTR) (LPCTSTR) pszDeviceName;
pSetOid->Oid = OID_MRVL_HOST_SLEEP_CFG;
cbSize = sizeof(OID_MRVL_DS_HOST_WAKEUP) - sizeof(OID_MRVL_DS_HOST_WAKEUP_FILTER);
memcpy((pSetOid->Data), (UCHAR *) &HostWakeCfg, cbSize);
cbDataSize += cbSize;
cbBuffer = cbDataSize + sizeof(NDISUIO_SET_OID); // - sizeof(ULONG);
fRetVal = DeviceIoControl(hNDisUIO, IOCTL_NDISUIO_SET_OID_VALUE,
(LPVOID) pSetOid,
cbBuffer,
(LPVOID) pSetOid,
cbBuffer,
&dwBytesReturned, NULL);
if (fRetVal == 0)
{
DEBUGMSG(ZONE_ERROR, (TEXT("Ethman: RemoveHostWakeupEx DeviceIoControl failed. Err = %d\r\n"), GetLastError()));
return STATUS_UNSUCCESSFUL;
}
else
{
DEBUGMSG(ZONE_VERBOSE, (TEXT("Ethman: RemoveHostWakeupEx succeeded\r\n")));
g_HostWakeSet = FALSE;
}
return STATUS_SUCCESS;
}
//
// This function sets up the hostwake mode conviguration in the Wifi chipset firmware.
// Configuration involves specifying which wakeup filters are to be used and
// the criteria upon which the chip should wake up the host. Details about the
// criteria and parameters are mentioned in the Marvell documentation.
//
int SetHostWakeupEx(HANDLE hNDisUIO, LPTSTR pszDeviceName, DWORD dwIPAddress)
{
BOOL fRetVal = TRUE;
PNDISUIO_SET_OID pSetOid = NULL;
UCHAR SetBuffer[sizeof(NDISUIO_SET_OID) + sizeof(OID_MRVL_DS_HOST_WAKEUP) + sizeof(MRVL_ETHTYPE_ENTRY)];
DWORD cbBuffer = 0;
DWORD cbDataSize = 0;
DWORD cbSize = 0;
DWORD dwBytesReturned = 0;
MrvlIEtypesHeader_t EthTypeHeader;
MRVL_ETHTYPE_ENTRY EthTypeEntry[2];
OID_MRVL_DS_HOST_WAKEUP HostWakeCfg;
EthTypeHeader.Type = 0x0115;
EthTypeHeader.Len = 2 * sizeof(MRVL_ETHTYPE_ENTRY); // 2 EthTypeEntry items
EthTypeEntry[1].AddressType = 2; // unicast
EthTypeEntry[1].EthType = 0x0008; // IPv4 0x0800 in network byte order.
EthTypeEntry[1].Ipv4Addr = 0xFFFFFFFF ; // 'match all' IP address
EthTypeEntry[0].AddressType = 1; // broadcast
EthTypeEntry[0].EthType = 0x0608; // ARP 0x0806 in network byte order
EthTypeEntry[0].Ipv4Addr = dwIPAddress; // IP address, already in network byte order
HostWakeCfg.ucGap = 0xF0; // 240ms after wake
HostWakeCfg.ucGPIO = 1;
HostWakeCfg.ulCriteria = 0x3; // any broadcast (0x1) or unicast data (0x2)
pSetOid = (PNDISUIO_SET_OID) & SetBuffer[0];
pSetOid->ptcDeviceName = (LPTSTR) (LPCTSTR) pszDeviceName;
pSetOid->Oid = OID_MRVL_HOST_SLEEP_CFG;
cbSize = sizeof(OID_MRVL_DS_HOST_WAKEUP) - sizeof(OID_MRVL_DS_HOST_WAKEUP_FILTER);
memcpy((pSetOid->Data), (UCHAR *) &HostWakeCfg, cbSize);
cbDataSize += cbSize;
cbSize = sizeof(MrvlIEtypesHeader_t);
memcpy((pSetOid->Data + cbDataSize), (UCHAR *) &EthTypeHeader, cbSize);
cbDataSize += cbSize;
cbSize = sizeof(MRVL_ETHTYPE_ENTRY);
memcpy((pSetOid->Data + cbDataSize), (UCHAR *) &EthTypeEntry[0], cbSize);
cbDataSize += cbSize;
cbSize = sizeof(MRVL_ETHTYPE_ENTRY);
memcpy((pSetOid->Data + cbDataSize), (UCHAR *) &EthTypeEntry[1], cbSize);
cbDataSize += cbSize;
cbBuffer = sizeof(NDISUIO_SET_OID) + cbDataSize;
fRetVal = DeviceIoControl(hNDisUIO, IOCTL_NDISUIO_SET_OID_VALUE,
(LPVOID) pSetOid,
cbBuffer,
(LPVOID) pSetOid,
cbBuffer,
&dwBytesReturned, NULL);
if (fRetVal == 0)
{
DEBUGMSG(ZONE_ERROR, (TEXT("Ethman: SetHostWakeupEx DeviceIoControl failed. Err = %d\r\n"), GetLastError()));
return STATUS_UNSUCCESSFUL;
}
else
{
DEBUGMSG(ZONE_VERBOSE, (TEXT("Ethman: SetHostWakeupEx succeeded\r\n")));
g_HostWakeSet = TRUE;
}
return STATUS_SUCCESS;
}
int SetDeepSleep(HANDLE hNDisUIO, LPTSTR pszDeviceName, BOOL fSleep)
{
BOOL fRetVal = TRUE;
PNDISUIO_SET_OID pSetOid = NULL;
UCHAR SetBuffer[sizeof(NDISUIO_SET_OID) + sizeof(ULONG)];
DWORD dwBytesReturned = 0;
pSetOid = (PNDISUIO_SET_OID) & SetBuffer[0];
pSetOid->ptcDeviceName = (LPTSTR) (LPCTSTR) pszDeviceName;
pSetOid->Oid = OID_MRVL_DEEP_SLEEP;
*((ULONG *) (pSetOid->Data)) = fSleep ? 1 : 0;
fRetVal = DeviceIoControl(hNDisUIO,
IOCTL_NDISUIO_SET_OID_VALUE,
(LPVOID) pSetOid,
sizeof(NDISUIO_SET_OID) + sizeof(ULONG),
(LPVOID) pSetOid,
sizeof(NDISUIO_SET_OID) + sizeof(ULONG),
&dwBytesReturned,
NULL);
if (fRetVal == 0)
{
DEBUGMSG(ZONE_ERROR, (TEXT("Ethman: SetDeepSleep:: SetDeepSleep DeviceIoControl failed. Err = %d\r\n"), GetLastError()));
return STATUS_UNSUCCESSFUL;
}
return STATUS_SUCCESS;
}
int QueryHostWakeState(HANDLE hNDisUIO, LPTSTR pszDeviceName, POID_MRVL_DS_HOST_WAKEUP_STATUS phwStatus)
{
BOOL fRetVal = TRUE;
PNDISUIO_QUERY_OID pQueryOid = NULL;
UCHAR GetBuffer[sizeof(NDISUIO_QUERY_OID) + sizeof(POID_MRVL_DS_HOST_WAKEUP_STATUS)];
DWORD dwBytesReturned = 0;
POID_MRVL_DS_HOST_WAKEUP_STATUS phwStatusIn;
pQueryOid = (PNDISUIO_QUERY_OID) & GetBuffer[0];
pQueryOid->ptcDeviceName = (LPTSTR) (LPCTSTR) pszDeviceName;
pQueryOid->Oid = OID_MRVL_HOST_SLEEP_STATUS;
fRetVal = DeviceIoControl(hNDisUIO, IOCTL_NDISUIO_QUERY_OID_VALUE,
(LPVOID) pQueryOid, sizeof(NDISUIO_QUERY_OID) + sizeof(POID_MRVL_DS_HOST_WAKEUP_STATUS),
(LPVOID) pQueryOid, sizeof(NDISUIO_QUERY_OID) + sizeof(POID_MRVL_DS_HOST_WAKEUP_STATUS),
&dwBytesReturned, NULL);
if (fRetVal == 0)
return STATUS_UNSUCCESSFUL;
phwStatusIn = (POID_MRVL_DS_HOST_WAKEUP_STATUS) (pQueryOid->Data);
phwStatus->hwState = phwStatusIn->hwState;
phwStatus->psState = phwStatusIn->psState;
return STATUS_SUCCESS;
}
BOOL PrepareForHostSleep(HANDLE hNdisUio, LPTSTR pszDeviceName, DWORD dwIPAddress)
{
OID_MRVL_DS_HOST_WAKEUP_STATUS hwStatus;
int retryCount;
if (!dwIPAddress || NULL == pszDeviceName || TEXT('\0') == pszDeviceName[0])
{
DEBUGMSG(ZONE_ERROR, (TEXT("Ethman: PrepareForHostSleep:: Error - Invalid parameters\r\n")));
return FALSE;
}
SetPowerMode(hNdisUio, pszDeviceName, Ndis802_11PowerModeCAM);
retryCount = 128;
do
{
QueryHostWakeState(hNdisUio, pszDeviceName, &hwStatus);
Sleep(10);
}
while ((--retryCount) && (hwStatus.psState != PS_STATE_FULL_POWER));
if (retryCount == 0)
{
RETAILMSG(ZONE_ERROR, (TEXT("Ethman: PrepareForHostHostSleep:: Error - wait for PS_STATE_FULL_POWER timed out.\r\n")));
}
SetHostWakeupEx(hNdisUio, pszDeviceName, dwIPAddress);
retryCount = 128;
do
{
QueryHostWakeState(hNdisUio, pszDeviceName, &hwStatus);
Sleep(10);
}
while ((--retryCount) && (hwStatus.hwState != HTWK_STATE_SLEEP));
if (retryCount == 0)
{
RETAILMSG(ZONE_ERROR, (TEXT("Ethman: PrepareForHostHostSleep:: Error - wait for HTWK_STATE_SLEEP timed out.\r\n")));
}
SetPowerMode(hNdisUio, pszDeviceName, Ndis802_11PowerModeMAX_PSP);
retryCount = 128;
do
{
QueryHostWakeState(hNdisUio, pszDeviceName, &hwStatus);
Sleep(10);
}
while ((--retryCount) && (hwStatus.psState != PS_STATE_SLEEP));
if (retryCount == 0)
{
RETAILMSG(ZONE_ERROR, (TEXT("Ethman: PrepareForHostHostSleep:: Error - wait for PS_STATE_SLEEP timed out.\r\n")));
}
return TRUE;
}
BOOL RecoverFromHostSleep(HANDLE hNdisUio, LPTSTR pszDeviceName)
{
OID_MRVL_DS_HOST_WAKEUP_STATUS hwStatus;
int retryCount;
if (NULL == pszDeviceName || TEXT('\0') == pszDeviceName[0])
{
DEBUGMSG(ZONE_ERROR, (TEXT("Ethman: RecoverFromHostSleep:: Error - no device name.\r\n")));
return FALSE;
}
retryCount = 128;
do
{
QueryHostWakeState(hNdisUio, pszDeviceName, &hwStatus);
Sleep(10);
}
while ((--retryCount) && (hwStatus.hwState != HTWK_STATE_FULL_POWER));
if (retryCount == 0)
{
RETAILMSG(ZONE_ERROR, (TEXT("Ethman: RecoverFromHostSleep:: Error - wait for HTWK_STATE_FULL_POWER timed out.\r\n")));
}
RemoveHostWakeupEx(hNdisUio, pszDeviceName);
return TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -