⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 client.cpp

📁 cayman提供的PXA270 wince下的bsp源码包
💻 CPP
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.

Module Name:  

    client.cpp

Abstract:  
    USB Client interface for Human Interface Device (HID) Class.

Functions:

Notes: 

--*/


#include "usbhid.h"


// Clear the stall feature on endpoint 0.
DWORD
ClearEndpointZeroStall(
    PUSBHID_CONTEXT pUsbHid
    )
{
    static const DWORD dwClearStallTimeout = 1000;
    DWORD dwErr;
    
    DEBUGCHK(pUsbHid != NULL);
    
    dwErr = ClearOrSetFeature( 
        pUsbHid->pUsbFuncs,
        pUsbHid->hUsbDevice,
        DefaultTransferComplete,
        pUsbHid->hEP0Event,
        USB_SEND_TO_ENDPOINT,
        USB_FEATURE_ENDPOINT_STALL,
        0, // Endpoint 0
        dwClearStallTimeout,
        FALSE);

    return dwErr;
}


// Regarding fSendToInterface.  The original HID spec said that the Hid
// descriptor would come after the interface and endpoint descriptors.
// It also said that class specific commands should be sent to the endpoint.
// The next spec said that the HID descriptor would come after the interface
// descriptor (not at the end) and that commands should be sent to the
// interface, not to the endpoint.  So, I'm assuming that if I find the
// Hid descriptor after the interface, the device is following the new spec
// and I should send commands to the interface.  Otherwise, I'll send them
// to the endpoint, as stated in the old spec.
void
DetermineDestination(
    PUSBHID_CONTEXT pUsbHid,
    BYTE *pbmRequestType,
    USHORT *pwIndex
    )
{
    DEBUGCHK(pUsbHid != NULL);
    DEBUGCHK(pbmRequestType != NULL);
    DEBUGCHK(pwIndex != NULL);

    // Do we send this to the endpoint or the interface?
    if (pUsbHid->fSendToInterface == TRUE) {
        *pbmRequestType = USB_REQUEST_FOR_INTERFACE;
        *pwIndex = pUsbHid->pUsbInterface->Descriptor.bInterfaceNumber;
    }
    else {
        *pbmRequestType = USB_REQUEST_FOR_ENDPOINT;
        *pwIndex = pUsbHid->InterruptIn.bIndex;
    }
}


// Get a report from the device. Note that this is not to be done for
// polling the device on a regular basis. Use GetInterruptReport for that.
// Returns the error values from IssueVendorTransfer.
DWORD
WINAPI
GetReport(
    HID_HANDLE       hDevice,
    HIDP_REPORT_TYPE type,
    PCHAR            pbBuffer,
    DWORD            cbBuffer,
    PDWORD           pcbTransferred,
    DWORD            dwTimeout
    )
{
    SETFNAME(_T("HidGetReport"));
    
    PUSBHID_CONTEXT pUsbHid = (PUSBHID_CONTEXT) hDevice;
    USB_DEVICE_REQUEST udr;
    BYTE bReportID;
    DWORD dwErr;
    BYTE bType = type + 1;
    USB_ERROR usbErr;

    if (VALID_CONTEXT(pUsbHid) == FALSE) {
        DEBUGMSG(ZONE_ERROR, (_T("%s: Invalid device handle\r\n"), pszFname));
        dwErr = ERROR_INVALID_HANDLE;
        goto EXIT;
    }

    if (pbBuffer == NULL || pcbTransferred == NULL) {
        DEBUGMSG(ZONE_ERROR, (_T("%s: Invalid parameter\r\n"), pszFname));
        dwErr = ERROR_INVALID_PARAMETER;
        goto EXIT;
    }

    if (cbBuffer > HID_MAX_REPORT_LENGTH) {
        cbBuffer = HID_MAX_REPORT_LENGTH;
    }
    
    DEBUGCHK(IsBadReadPtr(pbBuffer, cbBuffer) == FALSE);

    bReportID = *pbBuffer;

    DetermineDestination(pUsbHid, &udr.bmRequestType, &udr.wIndex);
    udr.bmRequestType |= USB_REQUEST_HOST_TO_DEVICE | USB_REQUEST_CLASS;

    udr.bRequest = USB_REQUEST_HID_GET_REPORT;
    udr.wValue   = ( (bType << 8) | bReportID);
    udr.wLength  = (USHORT) (cbBuffer - 1); // Do not receive the report ID

    dwErr = IssueVendorTransfer(
        pUsbHid->pUsbFuncs,
        pUsbHid->hUsbDevice,
        NULL, 
        NULL,
        USB_OUT_TRANSFER,
        &udr,
        pbBuffer + 1, // Do not receive the report ID
        0,
        pcbTransferred,
        dwTimeout,
        &usbErr);

    if (dwErr == ERROR_SUCCESS && usbErr == USB_NO_ERROR) {
        // Add in the report ID
        *pbBuffer = bReportID;
    }
    else if (usbErr == USB_STALL_ERROR) {
        // GET_REPORT is not required according to the HID spec. If it is not 
        // present, we might stall endpoint 0. If so, clear the stall feature.
        ClearEndpointZeroStall(pUsbHid);
        dwErr = ERROR_NOT_SUPPORTED;
    }
    else if (usbErr != ERROR_SUCCESS) {
        dwErr = ERROR_GEN_FAILURE;
    }

EXIT:
    if (dwErr != ERROR_SUCCESS) {
        SetLastError(dwErr);
//        NKDbgPrintfW("GetReport Error:%d",GetLastError());
    }

    return dwErr;
}


// Set a report on the device.
// Returns the error values from IssueVendorTransfer.
DWORD
WINAPI
SetReport(
    HID_HANDLE       hDevice,
    HIDP_REPORT_TYPE type,
    PCHAR            pbBuffer,
    DWORD            cbBuffer,
    DWORD            dwTimeout
    )
{
    SETFNAME(_T("HidSetReport"));
    
    PHID_CLIENT_HANDLE pHidClient = (PHID_CLIENT_HANDLE) hDevice;
    PUSBHID_CONTEXT pUsbHid;
    USB_DEVICE_REQUEST udr;
    BYTE bReportID;
    DWORD dwBytesTransferred;
    DWORD dwErr;
    BYTE bType = type + 1;
    USB_ERROR usbErr;

    if (VALID_CLIENT_HANDLE(pHidClient) == FALSE) {
        DEBUGMSG(ZONE_ERROR, (_T("%s: Invalid device handle\r\n"), pszFname));
        dwErr = ERROR_INVALID_HANDLE;
        goto EXIT;
    }

    if (pbBuffer == NULL) {
        DEBUGMSG(ZONE_ERROR, (_T("%s: Invalid parameter\r\n"), pszFname));
        dwErr = ERROR_INVALID_PARAMETER;
        goto EXIT;
    }

    if (cbBuffer > HID_MAX_REPORT_LENGTH) {
        DEBUGMSG(ZONE_ERROR, (_T("%s: Buffer is too large\r\n"), pszFname));
        dwErr = ERROR_MESSAGE_EXCEEDS_MAX_SIZE;
        goto EXIT;
    }

    DEBUGCHK(IsBadReadPtr(pbBuffer, cbBuffer) == FALSE);

    ValidateClientHandle(pHidClient);
    pUsbHid = pHidClient->pUsbHid;
    ValidateHidContext(pUsbHid);

    bReportID = *pbBuffer;

    DetermineDestination(pUsbHid, &udr.bmRequestType, &udr.wIndex);

    udr.bmRequestType |= USB_REQUEST_HOST_TO_DEVICE | USB_REQUEST_CLASS;

    udr.bRequest = USB_REQUEST_HID_SET_REPORT;
    udr.wValue   = ( (bType << 8) | bReportID);
    udr.wLength  = (USHORT) (cbBuffer - 1); // Do not send the report ID

    dwErr = IssueVendorTransfer(
        pUsbHid->pUsbFuncs,
        pUsbHid->hUsbDevice,
        NULL, 
        NULL,
        USB_OUT_TRANSFER,
        &udr,
        pbBuffer + 1, // Do not send the report ID
        0,
        &dwBytesTransferred,
        dwTimeout,
        &usbErr);

    if (usbErr == USB_STALL_ERROR) {
        // SET_REPORT is not required according to the HID spec. If it is not 
        // present, we might stall endpoint 0. If so, clear the stall feature.
        ClearEndpointZeroStall(pUsbHid);
        dwErr = ERROR_NOT_SUPPORTED;
    }
    else if (usbErr != ERROR_SUCCESS) {
        dwErr = ERROR_GEN_FAILURE;
    }

EXIT:
    if (dwErr != ERROR_SUCCESS) {
        SetLastError(dwErr);
    }
//    NKDbgPrintfW("SetReport Error:%d",GetLastError());
    return dwErr;
}


// Get an interrupt report from the device.
// Returns ERROR_SUCCESS, ERROR_DEVICE_REMOVED, or ERROR_TIMEOUT.
DWORD
WINAPI 
GetInterruptReport(
    HID_HANDLE hDevice,
    PCHAR      pbBuffer,
    DWORD      cbBuffer, 
    PDWORD     pcbTransferred,
    HANDLE     hCancel,
    DWORD      dwTimeout
    )
{
    SETFNAME(_T("GetInterruptReport"));
    
    PHID_CLIENT_HANDLE pHidClient = (PHID_CLIENT_HANDLE) hDevice;
    DWORD dwErr;
    
    if (VALID_CLIENT_HANDLE(pHidClient) == FALSE) {
        DEBUGMSG(ZONE_ERROR, (_T("%s: Invalid device handle\r\n"), pszFname));
        dwErr = ERROR_INVALID_HANDLE;
        goto EXIT;
    }

    if (pbBuffer == NULL || pcbTransferred == NULL) {
        dwErr = ERROR_INVALID_PARAMETER;
        goto EXIT;
    }

    DEBUGCHK(IsBadWritePtr(pbBuffer, cbBuffer) == FALSE);
    DEBUGCHK(IsBadWritePtr(pcbTransferred, sizeof(*pcbTransferred)) == FALSE);

    ValidateClientHandle(pHidClient);

    dwErr = pHidClient->pQueue->Dequeue(pbBuffer, cbBuffer, pcbTransferred, 
        hCancel, dwTimeout);

EXIT:
    if (dwErr != ERROR_SUCCESS) {
        SetLastError(dwErr);
    }
//    NKDbgPrintfW("GetRInterruptReport Error:%d",GetLastError());
    return dwErr;
}


// Return a report descriptor given the ID.
static
PHIDP_REPORT_IDS
GetReportDesc(
    PHIDP_DEVICE_DESC phidpDeviceDesc,
    DWORD dwReportID
    )
{
    PHIDP_REPORT_IDS pReport = NULL;
    DWORD dwIdx;

    DEBUGCHK(phidpDeviceDesc != NULL);
    DEBUGCHK(phidpDeviceDesc->ReportIDs != NULL);
    
    for (dwIdx = 0; dwIdx < phidpDeviceDesc->ReportIDsLength; ++dwIdx)
    {
        PHIDP_REPORT_IDS pCurrReport = &phidpDeviceDesc->ReportIDs[dwIdx];
        DEBUGCHK(pCurrReport != NULL);
        
        if (pCurrReport->ReportID == dwReportID) {
            pReport = pCurrReport;
            break;
        }
    }

    DEBUGCHK(pReport != NULL);

    return pReport;        
}
    

// Return a collection decriptor given the collection number. Also returns the
// index of the collection in the device context's array.
static
PHIDP_COLLECTION_DESC
GetCollectionDesc(
    PHIDP_DEVICE_DESC phidpDeviceDesc,
    DWORD dwCollectionNumber,
    PDWORD pdwCollectionIndex
    )
{
    PHIDP_COLLECTION_DESC pColl = NULL;
    DWORD dwIdx;

    DEBUGCHK(phidpDeviceDesc != NULL);
    DEBUGCHK(phidpDeviceDesc->CollectionDesc != NULL);
    
    for (dwIdx = 0; dwIdx < phidpDeviceDesc->CollectionDescLength; ++dwIdx) 
    {
        PHIDP_COLLECTION_DESC pCurrColl = &phidpDeviceDesc->CollectionDesc[dwIdx];
        DEBUGCHK(pCurrColl != NULL);
        
        if (pCurrColl->CollectionNumber == dwCollectionNumber) {
            pColl = pCurrColl;
            break;
        }
    }

    DEBUGCHK(pColl != NULL);

    if (pdwCollectionIndex != NULL) {
        *pdwCollectionIndex = dwIdx;
    }

    return pColl;        
}    


// If this report includes power events, perform them.
static
void
PerformPowerEvents(
    PHIDP_COLLECTION_DESC phidpCollection,
    BYTE *pbHidPacket,
    DWORD cbHidPacket
    )
{
    SETFNAME(_T("PerformPowerEvents"));
    
    NTSTATUS status;
    ULONG uPowerEvents = 0;
    
    DEBUGCHK(phidpCollection != NULL);
    DEBUGCHK(pbHidPacket != NULL);

    status = HidP_SysPowerEvent((PCHAR) pbHidPacket, (USHORT) cbHidPacket, 
        phidpCollection->PreparsedData, &uPowerEvents);
    
    if (NT_SUCCESS(status)) 
    {
        DEBUGMSG(ZONE_HID_DATA, (_T("%s: Received power event 0x%08x\r\n"), 
            pszFname, uPowerEvents));
        
        if ((uPowerEvents & (SYS_BUTTON_SLEEP | SYS_BUTTON_POWER)) != 0) {
            keybd_event(VK_OFF, 0, 0, 0);
            keybd_event(VK_OFF, 0, KEYEVENTF_KEYUP, 0);
        }
    }    
}


#ifdef DEBUG

// Print out the report received.
static
void
OutputReport(
    PBYTE pData,
    DWORD cbData,
    DWORD dwInterface
    )
{
    TCHAR szBuf[512];
    TCHAR *szCurr = szBuf;
    
    DEBUGCHK(dim(szBuf) > cbData * 3); // Overflow if failure

    if (dim(szBuf) > cbData * 3) 
    {
        for (DWORD dwByte = 0; dwByte < cbData; ++dwByte) {
            _stprintf(szCurr, _T("%02X "), pData[dwByte]);
            szCurr += 3;
        }
    }
    else {
        DEBUGCHK(FALSE); // Why does the buffer need to be bigger? 512 is plenty!
        szBuf[0] = 0;
    }
    
    DEBUGMSG(ZONE_HID_DATA, (_T("HID Interface %i report: %s\r\n"),
        dwInterface, szBuf));
}

#else

#define OutputReport(ptr, dw1, dw2)

#endif // DEBUG


// Process an incoming report from a device.
// The first byte of pData must contain a report ID even if
// the device would not normally include it (for ID 0).
void
ProcessReport(
    PUSBHID_CONTEXT pUsbHid,
    BYTE *pData,
    DWORD cbData
    )
{
    SETFNAME(_T("ProcessReport"));
    
    PHIDP_REPORT_IDS phidpReport;
    PHIDP_COLLECTION_DESC phidpCollection;
    DWORD dwReportID;
    DWORD dwCollectionIndex;
    PHID_CLIENT_HANDLE pClientHandle;
    HidTLCQueue *pQueue;
   
    DEBUGCHK(pUsbHid != NULL);
    DEBUGCHK(pData != NULL);

    // We always get a report ID.
    dwReportID = *pData;

    // Get the report and collection data structures
    phidpReport = GetReportDesc(pUsbHid->phidpDeviceDesc, dwReportID);
    DEBUGCHK(phidpReport != NULL);

    phidpCollection = GetCollectionDesc(pUsbHid->phidpDeviceDesc, 
        phidpReport->CollectionNumber, &dwCollectionIndex);
    DEBUGCHK(phidpCollection != NULL);
    DEBUGCHK(dwCollectionIndex < pUsbHid->phidpDeviceDesc->CollectionDescLength);

    OutputReport(pData, cbData, pUsbHid->pUsbInterface->Descriptor.bInterfaceNumber);
    
    // Perform any power events listed in this report
    PerformPowerEvents(phidpCollection, pData, cbData);

    // Send this HID packet to the proper client
    pClientHandle = &pUsbHid->pClientHandles[dwCollectionIndex];

    // Only queue this report if we have a client that will receive it.
    if (pClientHandle->hInst != NULL) 
    {
        pQueue = pClientHandle->pQueue;
        pQueue->Lock();
        if (pQueue->IsAccepting() == TRUE) {
            if (pQueue->IsFull() == FALSE) {
                BOOL fRet;
                fRet = pQueue->Enqueue((PCHAR) pData, cbData);
                DEBUGCHK(fRet);
            }
            else {
                DEBUGMSG(ZONE_ERROR, (_T("%s: Error: Queue is full. Dropping packet.\r\n"), pszFname));
            }
        }
        else {
            DEBUGMSG(ZONE_HID_DATA, (_T("%s: Queue not accepting input. Dropping packet.\r\n"), pszFname));
        }
        pQueue->Unlock();
    }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -