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

📄 usbhid.cpp

📁 嵌入式操作系统WINCE5.0下的USB驱动程序
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//
// 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:  

    usbhid.cpp

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

Functions:

Notes: 

--*/

#include "usbhid.h"
#include <devload.h>


#define USB_HID_MAX_REPORT_LENGTH 0xFFFF // HID standard allows 2-byte transfer size


/*
 * DLL entry point
 */
extern "C" 
BOOL
DllEntry(
    HANDLE hDllHandle,
    DWORD dwReason, 
    LPVOID lpReserved
    )
{
    UNREFERENCED_PARAMETER(lpReserved);
    
    switch (dwReason) {
        case DLL_PROCESS_ATTACH:
            DEBUGREGISTER((HINSTANCE)hDllHandle);

            DEBUGMSG(ZONE_INIT, (_T("Hid DllEntry Attach\r\n")));
            DisableThreadLibraryCalls((HMODULE) hDllHandle);
            break;
            
        case DLL_PROCESS_DETACH:
            DEBUGMSG(ZONE_INIT, (_T("Hid DllEntry Detach\r\n")));
            break;
    }

    return HidMdd_DllEntry(dwReason);
}


/*
 * USBInstallDriver
 *
 *   USB driver install routine - set up client registry settings so we will be loaded
 *   by USBD for HID devices.  This function should not be called for systems in which the
 *   OEM ships the HID driver.
 *
 * Return value:
 *   Return TRUE if install succeeds, or FALSE if there is some error.
 */
extern "C" 
BOOL 
USBInstallDriver(
    LPCWSTR szDriverLibFile // Contains client driver DLL name
    )
{
    SETFNAME(_T("USBInstallDriver"));
    
    BOOL fRet = FALSE;

    USB_DRIVER_SETTINGS usbDriverSettings = { DRIVER_SETTINGS };

    REG_VALUE_DESCR rgUsbHidInstanceValues[] = {
        DEVLOAD_DLLNAME_VALNAME, DEVLOAD_DLLNAME_VALTYPE, 0, (PBYTE)(DRIVER_NAME),
        NULL, 0, 0, NULL
    };

    DWORD dwQueuedTransfers = DEFAULT_QUEUED_TRANSFERS;

    REG_VALUE_DESCR rgUsbHidPublicValues[] = {
        DEVLOAD_DLLNAME_VALNAME, DEVLOAD_DLLNAME_VALTYPE, 0, (PBYTE)(DRIVER_NAME),
        DEVLOAD_PREFIX_VALNAME,  DEVLOAD_PREFIX_VALTYPE,  0, (PBYTE)(DEVICE_PREFIX),
        QUEUED_TRANSFERS_SZ,     REG_DWORD,               0, (PBYTE)(&dwQueuedTransfers),
        NULL, 0, 0, NULL
    };

    DEBUGCHK(szDriverLibFile != NULL);
    
    DEBUGMSG(ZONE_INIT, (_T("%s: Install function called (driver: %s)\r\n"), 
        pszFname, szDriverLibFile));

    // register with USBD
    fRet = RegisterClientDriverID(CLASS_NAME_SZ);
    if (fRet == FALSE) {
        DEBUGMSG(ZONE_ERROR, (_T("%s: RegisterClientDriverID error:%d\r\n"), 
            pszFname, GetLastError()));
        goto EXIT;
    }

    fRet = RegisterClientSettings( szDriverLibFile,
                                   CLASS_NAME_SZ, 
                                   NULL, 
                                   &usbDriverSettings );
    
    if (fRet == FALSE) {
        UnRegisterClientDriverID(CLASS_NAME_SZ);
        DEBUGMSG(ZONE_ERROR, (_T("%s: RegisterClientSettings error:%d\r\n"), 
            pszFname, GetLastError()));
        goto EXIT;
    }
    
    // Add our default values to the reg
    if ( !GetSetKeyValues( HID_REGKEY_SZ,
                           rgUsbHidInstanceValues,
                           SET,
                           TRUE ) ) {
        DEBUGMSG(ZONE_ERROR, (_T("%s: GetSetKeyValues failed!\r\n"), pszFname));
        goto EXIT;
    }

    if ( !GetSetKeyValues( CLIENT_REGKEY_SZ,
                           rgUsbHidPublicValues,
                           SET,
                           TRUE ) ) {
        DEBUGMSG(ZONE_ERROR, (_T("%s: GetSetKeyValues failed!\r\n"), pszFname));
        goto EXIT;
    }

    fRet = TRUE;
 
EXIT:  
    return fRet;
}


/*
 * USBUnInstallDriver
 *
 *   This function can be called by a client driver to deregister itself
 *   with USBD.
 */
extern "C"
BOOL 
USBUnInstallDriver(
    VOID
    )
{
    SETFNAME(_T("USBUnInstallDriver"));
    
    BOOL fRet = FALSE;
    const WCHAR szUsbDeviceID[] = CLASS_NAME_SZ;
    USB_DRIVER_SETTINGS usbDriverSettings = { DRIVER_SETTINGS };

    DEBUGMSG(ZONE_INIT, (_T("%s: Uninstall function called\r\n"), pszFname));

    fRet = UnRegisterClientSettings( szUsbDeviceID,
                                     NULL,
                                     &usbDriverSettings );

    if (fRet == TRUE) {
        fRet = UnRegisterClientDriverID(szUsbDeviceID);
    }

    return fRet;
}



/*
 * USBDeviceNotifications
 *
 *    Process notifications from USBD.  Currently, the only notification
 *    supported is a device removal.  Unused parameters are reserved for
 *    future use.
 */
extern "C" 
BOOL 
USBDeviceNotifications(
    LPVOID    lpvNotifyParameter,
    DWORD     dwCode,
    LPDWORD * dwInfo1,
    LPDWORD * dwInfo2,
    LPDWORD * dwInfo3,
    LPDWORD * dwInfo4
    )
{
    SETFNAME(_T("USBDeviceNotifications"));
    
    BOOL fRet = FALSE;
    PUSBHID_CONTEXT pUsbHid = (PUSBHID_CONTEXT) lpvNotifyParameter;
    
    UNREFERENCED_PARAMETER(dwInfo1);
    UNREFERENCED_PARAMETER(dwInfo2);
    UNREFERENCED_PARAMETER(dwInfo3);
    UNREFERENCED_PARAMETER(dwInfo4);

    DEBUGCHK(pUsbHid != NULL);

    ValidateUsbHidContext(pUsbHid);
    
    switch(dwCode)
    {
        case USB_CLOSE_DEVICE:
            DEBUGMSG(ZONE_INIT, (_T("%s: USB_CLOSE_DEVICE\r\n"), pszFname));
            // Remove and free the device context;
            RemoveDeviceContext(pUsbHid);            
            fRet = TRUE;
            break;

        default:
            DEBUGMSG(ZONE_ERROR, (_T("%s: Unhandled code:%d\n"), 
                pszFname, dwCode));
            break;
    }
    
    return fRet;
}


/*
 *  USBDeviceAttach 
 * 
 *    USB device attach routine.  This function is called by USBD when a device is attached
 *    to the USB, and a matching registry key is found off the LoadClients registry key. 
 *    We must determine whether the device may be controlled by this driver, and load 
 *    drivers for any uncontrolled interfaces.
 *
 *  Return Value:
 *    Return TRUE upon success, or FALSE if an error occurs.
 */
extern "C" 
BOOL 
USBDeviceAttach(
    USB_HANDLE hDevice,           // USB device handle
    LPCUSB_FUNCS UsbFuncs,        // Pointer to USBDI function table.
    LPCUSB_INTERFACE UsbInterface,// If client is being loaded as an interface driver, contains a pointer to the USB_INTERFACE
                                  // structure that contains interface information. If client is not loaded for a specific interface,
                                  // this parameter will be NULL.
    LPCWSTR UniqueDriverId,       // Contains client driver id string.
    LPBOOL AcceptControl,         // Filled in with TRUE if we accept control of the device, 
                                  // or FALSE if USBD should continue to try to load client drivers.
    LPCUSB_DRIVER_SETTINGS UsbDriverSettings,// Contains pointer to USB_DRIVER_SETTINGS struct that indicates how we were loaded.
    DWORD Unused                  // Reserved for use with future versions of USBD
    )
{
    SETFNAME(_T("USBDeviceAttach"));

    BOOL fRet = FALSE;
    LPCUSB_INTERFACE pUsbInterface = NULL;
    PUSBHID_CONTEXT pUsbHid = NULL;
    
    DEBUGMSG(ZONE_INIT, (_T("+%s: 0x%x, %s\r\n"), pszFname, hDevice, 
        UniqueDriverId));

    UNREFERENCED_PARAMETER(UniqueDriverId);
    UNREFERENCED_PARAMETER(UsbDriverSettings);
    UNREFERENCED_PARAMETER(Unused);

    PREFAST_DEBUGCHK(UsbFuncs != NULL);
    DEBUGCHK(UniqueDriverId != NULL);
    PREFAST_DEBUGCHK(AcceptControl != NULL);
    DEBUGCHK(UsbDriverSettings != NULL);

    // Determine if we control this USB peripheral...
    *AcceptControl = FALSE;

    pUsbInterface = ParseUsbDescriptors(UsbInterface);

    if (pUsbInterface == NULL) {
        goto EXIT;
    }

    // Tell USBD to stop looking for drivers
    *AcceptControl = TRUE;

    // We found a device and interface we control, so create our device context.
    pUsbHid = CreateUsbHidDevice(hDevice, UsbFuncs, pUsbInterface);
    if (pUsbHid == NULL) {
        goto EXIT;
    }

    // Register to receive notifications regarding this device from USB.
    (*UsbFuncs->lpRegisterNotificationRoutine)(hDevice, 
        USBDeviceNotifications, pUsbHid);

    fRet = TRUE;
    
EXIT:
    if (fRet == FALSE) {
        if (pUsbHid != NULL) {
            RemoveDeviceContext(pUsbHid);
        }
    }
    
    DEBUGMSG(ZONE_INIT, (_T("-%s\r\n"), pszFname));
    return fRet;
}


// Clear the stall feature on endpoint 0.
static
DWORD
ClearEndpointZeroStall(
    PUSBHID_CONTEXT pUsbHid
    )
{
    DWORD dwErr;
    
    PREFAST_DEBUGCHK(pUsbHid != NULL);
    
    dwErr = ClearOrSetFeature( 
        pUsbHid->pUsbFuncs,
        pUsbHid->hUsbDevice,
        NULL,
        NULL,
        USB_SEND_TO_ENDPOINT,
        USB_FEATURE_ENDPOINT_STALL,
        0, // Endpoint 0
        0,
        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
    )
{
    PREFAST_DEBUGCHK(pUsbHid != NULL);
    PREFAST_DEBUGCHK(pbmRequestType != NULL);
    PREFAST_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 an Input, Output, or Feature report from the device. This is not to be
// be used for recurring interrupt reports. The PDD calls into the MDD with 
// HidMdd_ProcessReport for that.
DWORD
WINAPI
HidPdd_GetReport(
    HID_PDD_HANDLE   hPddDevice,
    HIDP_REPORT_TYPE type,
    PCHAR            pbBuffer,
    DWORD            cbBuffer,
    PDWORD           pcbTransferred,
    DWORD            dwTimeout,
    BYTE             bReportID
    )
{
    SETFNAME(_T("HidPdd_GetReport"));

    PUSBHID_CONTEXT pUsbHid = (PUSBHID_CONTEXT) hPddDevice;

    USB_DEVICE_REQUEST udr;
    DWORD dwErr = ERROR_SUCCESS;
    LPTRANSFER_NOTIFY_ROUTINE pfnNotify = NULL;
    HANDLE hEvent = NULL;
    USB_ERROR usbErr;

    PREFAST_DEBUGCHK(VALID_CONTEXT(pUsbHid));
    ValidateUsbHidContext(pUsbHid);

    // Mdd guarantees the following
    DEBUGCHK(pbBuffer != NULL);
    DEBUGCHK(pcbTransferred != NULL);
    DEBUGCHK(IS_HID_REPORT_TYPE_VALID(type) == TRUE);

    if (cbBuffer > USB_HID_MAX_REPORT_LENGTH) {
        // Reduce to maximum possible value.
        cbBuffer = USB_HID_MAX_REPORT_LENGTH;
    }

    if (dwTimeout != INFINITE) {
        // Set up the wait variables.
        hEvent = CreateEvent(NULL, MANUAL_RESET_EVENT, FALSE, NULL);
        if (hEvent == NULL) {
            dwErr = GetLastError();
            DEBUGMSG(ZONE_ERROR, (_T("%s: CreateEvent error:%d\r\n"), 
                pszFname, dwErr));
            goto EXIT;
        }

        pfnNotify = DefaultTransferComplete;

        if (dwTimeout == 0) {
            // IssueVendorTransfer has a special case for 0 so change it to 1.
            dwTimeout = 1; 
        }
    }

    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   = USB_DESCRIPTOR_MAKE_TYPE_AND_INDEX(type, bReportID);
    udr.wLength  = (USHORT) cbBuffer;

    dwErr = IssueVendorTransfer(
        pUsbHid->pUsbFuncs,
        pUsbHid->hUsbDevice,
        pfnNotify, 
        hEvent,
        USB_OUT_TRANSFER,
        &udr,
        pbBuffer,
        0,
        pcbTransferred,
        dwTimeout,
        &usbErr);

    if (dwErr == ERROR_SUCCESS) {
        if (usbErr == USB_STALL_ERROR) {
            // GET_REPORT is not required according to the HID spec. If it is not 
            // present, the device may return a stall handshake.
            dwErr = ERROR_NOT_SUPPORTED;
        }
        else if (usbErr != USB_NO_ERROR) {
            dwErr = ERROR_GEN_FAILURE;
        }
    }

EXIT:
    if (hEvent != NULL) CloseHandle(hEvent);

    return dwErr;
}


// Set an Input, Output, or Feature report on the device.
DWORD
WINAPI
HidPdd_SetReport(
    HID_PDD_HANDLE   hPddDevice,
    HIDP_REPORT_TYPE type,
    PCHAR            pbBuffer,
    DWORD            cbBuffer,
    DWORD            dwTimeout,
    BYTE             bReportID
    )
{
    SETFNAME(_T("HidPdd_SetReport"));

    PUSBHID_CONTEXT pUsbHid = (PUSBHID_CONTEXT) hPddDevice;
    USB_DEVICE_REQUEST udr;
    DWORD dwBytesTransferred;
    DWORD dwErr = ERROR_SUCCESS;
    LPTRANSFER_NOTIFY_ROUTINE pfnNotify = NULL;
    HANDLE hEvent = NULL;
    USB_ERROR usbErr;

    PREFAST_DEBUGCHK(VALID_CONTEXT(pUsbHid));
    ValidateUsbHidContext(pUsbHid);

    // Mdd guarantees the following
    DEBUGCHK(pbBuffer != NULL);
    DEBUGCHK(IS_HID_REPORT_TYPE_VALID(type) == TRUE);

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

    if (dwTimeout != INFINITE) {
        // Set up the wait variables.
        hEvent = CreateEvent(NULL, MANUAL_RESET_EVENT, FALSE, NULL);
        if (hEvent == NULL) {
            dwErr = GetLastError();
            DEBUGMSG(ZONE_ERROR, (_T("%s: CreateEvent error:%d\r\n"), 
                pszFname, dwErr));
            goto EXIT;
        }

        pfnNotify = DefaultTransferComplete;

        if (dwTimeout == 0) {
            // IssueVendorTransfer has a special case for 0 so change it to 1.
            dwTimeout = 1; 
        }
    }


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

⌨️ 快捷键说明

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