📄 usbddrv.cpp
字号:
break;
}
} else
if (iFreePipe == gcMaxPipes)
iFreePipe = iPipe;
}
if (iFreePipe < gcMaxPipes) {
pDev->apPipes[iFreePipe] = pPipe;
LeaveCriticalSection(&pDev->csPipeLock);
DEBUGMSG(ZONE_API|ZONE_PIPE, (TEXT("-USBD:OpenPipe success, hPipe = %X\n"), pPipe));
return (USB_PIPE)pPipe;
}
LeaveCriticalSection(&pDev->csPipeLock);
}
// Some error occurred (error code set in HCD)
FreePipeObject(pPipe);
DEBUGMSG(ZONE_ERROR,(TEXT("!USBD:OpenPipe returning error\r\n")));
return NULL;
}
/*
* @func BOOL | ClosePipe | Close an open pipe handle.
* @rdesc Return TRUE if successful, FALSE if error.
* @comm Abort and close all transfers in progress on pipe, and free all
* resources associated with pipe. If transfers are in
* progress, will block until aborts complete.
*/
extern "C" BOOL
ClosePipe(
USB_PIPE hPipe) // @parm [IN] - Open pipe handle
{
BOOL fRet = TRUE;
SPipe * pPipe = (SPipe *)hPipe;
if (!ReferencePipeHandle(pPipe))
{
DEBUGMSG(ZONE_WARNING,(TEXT("!USBD:ClosePipe - Invalid handle\r\n")));
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
SDevice * pDev = pPipe->pDevice;
SHcd * pHcd = pDev->pHcd;
DEBUGMSG(ZONE_API|ZONE_PIPE,(TEXT("+USBD:ClosePipe, hPipe: 0x%X\r\n"),hPipe));
EnterCriticalSection(&pDev->csPipeLock);
#ifdef NEVER // try this with OHCI just for giggles (BUGBUG)
// old code relied on this always being true!
DEBUGCHK( pDev->apPipes[pPipe->iEndpointIndex] == pPipe );
#endif
for (UINT iPipe = 0; iPipe < gcMaxPipes; ++iPipe)
if (pDev->apPipes[iPipe] == pPipe)
break;
if (iPipe == gcMaxPipes) {
DEBUGMSG(ZONE_WARNING|ZONE_API|ZONE_PIPE, (TEXT("-USBD:ClosePipe, pipe is not open.\n")));
LeaveCriticalSection(&pDev->csPipeLock);
DereferencePipeHandle(pPipe);
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
pDev->apPipes[iPipe] = NULL;
LeaveCriticalSection(&pDev->csPipeLock);
// Mark pipe as going away - this will prevent any new transfers from
// being started, and will prevent any transfers in progress from blocking
// (since AddTransfer() will fail, and if AddTransfer() has already been called,
// we'll unblock the transfer in CloseTransfer()).
EnterCriticalSection(&pPipe->csTransferLock);
pPipe->dwSig = CLOSING_PIPE_SIG;
LeaveCriticalSection(&pPipe->csTransferLock);
if (pPipe->apTransfers)
{
for (UINT iTransfer = 0 ; iTransfer < pPipe->cAllocatedTransfers ;
++iTransfer)
{
if (pPipe->apTransfers[iTransfer])
CloseTransfer(pPipe->apTransfers[iTransfer]);
}
delete [] pPipe->apTransfers; // all transfers inside should be NULL
pPipe->apTransfers = NULL;
pPipe->cAllocatedTransfers = 0;
}
// Free all transfers on our free list
while (pPipe->pFreeTransferList)
{
STransfer *pTransfer = pPipe->pFreeTransferList;
pPipe->pFreeTransferList = pTransfer->pNext;
// Release memory and resources used by transfer struct
FreeTransferObjectMem(pTransfer);
}
UINT iEp = pPipe->iEndpointIndex;
// Put pipe struct on free list
DereferencePipeHandle(pPipe);
FreePipeObject(pPipe);
// Finally, call in to the HCD to clean up.
fRet = (*pHcd->pHcdFuncs->lpClosePipe)(pHcd->pvHcd, pDev->iDevice, iEp);
DEBUGMSG(ZONE_API|ZONE_PIPE,(TEXT("-USBD:ClosePipe\r\n")));
return fRet;
}
/*
* @func BOOL | ResetPipe | Reset an open USB pipe
* @rdesc Return TRUE if successful, or FALSE if error.
* @comm This request will clear the halted state of a pipe within the USB stack, and
* reset the data toggle state of the endpoint to DATA0. It does not reset the stalled
* state of the endpoint on the device; the device driver must accomplish this by
* sending the appropriate FEATURE request on the default pipe. To determine whether
* the endpoint is stalled on the device side, use the <f GetStatus> call.
*
* @xref <f IsPipeHalted> <f ClearFeature> <f GetStatus>
*/
extern "C" BOOL
ResetPipe(
USB_PIPE hPipe) // @parm [IN] - Open USB pipe handle
{
SPipe * pPipe = (SPipe *)hPipe;
BOOL fRet;
if (!ReferencePipeHandle(pPipe))
{
DEBUGMSG(ZONE_WARNING,(TEXT("!USBD:ResetPipe - Invalid handle\r\n")));
return FALSE;
}
SDevice * pDev = pPipe->pDevice;
SHcd * pHcd = pDev->pHcd;
LPHCD_RESET_PIPE pFunc = pHcd->pHcdFuncs->lpResetPipe;
DEBUGMSG(ZONE_API|ZONE_PIPE,(TEXT("+USBD:ResetPipe\r\n")));
fRet = (*pFunc)(pHcd->pvHcd, pDev->iDevice, pPipe->iEndpointIndex);
DereferencePipeHandle(pPipe);
return fRet;
}
/*
* @func BOOL | ResetDefaultPipe | Reset default (EP0) USB pipe
* @rdesc Return TRUE if successful, or FALSE if error.
* @comm This request will clear the halted state of the default pipe within the USB stack.
* Note: this function is only available in USBDI version 1.1 or later.
*
* @xref <f IsDefaultPipeHalted>
*/
extern "C" BOOL
ResetDefaultPipe(
USB_HANDLE hDevice) // @parm [IN] - USB device handle
{
SDevice *pDev = (SDevice *)hDevice;
if (!ValidateDeviceHandle(pDev))
{
DEBUGMSG(ZONE_WARNING,(TEXT("!USBD:ResetDefaultPipe - Invalid device handle\r\n")));
return FALSE;
}
SPipe *pDfltPipe;
EnterCriticalSection(&pDev->csPipeLock);
pDfltPipe = pDev->apPipes[gcEndpointZero];
LeaveCriticalSection(&pDev->csPipeLock);
return ResetPipe(pDfltPipe);
}
/*
* @func BOOL | AbortPipeTransfers | Abort all transfers on an open USB pipe
* @rdesc Return TRUE if successful, FALSE if error.
* @comm Will block until all transfers have been successfully cancelled on the
* endpoint, unless USB_NO_WAIT is specified, in which case, the transfers
* are flagged to be cancelled, but the function returns immediately.
*/
extern "C" BOOL
AbortPipeTransfers(
USB_PIPE hPipe, // @parm [IN] - Open USB pipe handle
DWORD dwFlags) // @parm [IN] - USB_NO_WAIT, or 0
{
SPipe * pPipe = (SPipe *)hPipe;
if (!ReferencePipeHandle(pPipe))
{
DEBUGMSG(ZONE_WARNING,(TEXT("!USBD:AbortPipeTransfers - Invalid handle\r\n")));
return FALSE;
}
SDevice * pDev = pPipe->pDevice;
SHcd * pHcd = pDev->pHcd;
UINT iTransfer;
STransfer * pTransfer;
DEBUGMSG(ZONE_API|ZONE_PIPE,
(TEXT("+USBD:AbortPipeTransfers, hPipe: 0x%X, flags: 0x%X, AllocatedTrans:%u\r\n"),
hPipe,dwFlags,pPipe->cAllocatedTransfers));
EnterCriticalSection(&pPipe->csTransferLock);
for (iTransfer=0;iTransfer<pPipe->cAllocatedTransfers;iTransfer++) {
pTransfer = pPipe->apTransfers[iTransfer];
LeaveCriticalSection(&pPipe->csTransferLock);
if (pTransfer)
AbortTransfer(pTransfer, dwFlags);
EnterCriticalSection(&pPipe->csTransferLock);
}
LeaveCriticalSection(&pPipe->csTransferLock);
DEBUGMSG(ZONE_PIPE,(TEXT("-USBD:AbortPipeTransfers\r\n")));
DereferencePipeHandle(pPipe);
return TRUE;
}
/* @topic USB Transfer functions | USB client drivers communicate with devices by issuing
* transfers. There are four basic type of transfers: Control, Bulk, Interrupt, and
* Isochronous. Several routines are also provided to issue control transfers for common
* device configuration and setup requests.
*
* All transfer routines have an optional callback parameter. If specified, the transfer
* routine will return immediately, and the callback function will be called when
* the transfer has completed, or been cancelled. If no callback is specified, then
* the function will block until the transfer is finished, unless the USB_NO_WAIT flag
* is specified. In this case, the function will return immediately, and no indication
* will be given when the transfer completes. This might be used by a client driver to
* queue up a list of requests, and only wait for the last one. Note that the client is
* still responsible for closing all transfer handles in this case.
*
* All transfer routines return a handle to a transfer, or NULL if an error occurs. In
* the latter case, client drivers may obtain further error information by calling the
* standard <f GetLastError> function. The following Win32 error codes are applicable to
* the USB transfer functions: <nl>
*
* ERROR_INVALID_HANDLE -- The pipe handle is invalid <nl>
* ERROR_OUTOFMEMORY -- Could not obtain required memory for operation <nl>
* ERROR_INVALID_USER_BUFFER -- Client buffer pointer is invalid <nl>
* ERROR_INVALID_PARAMETER -- (isoch only) The specified starting frame is invalid <nl>
*
* The USB (OHCI) hardware assumes a host page size of 4K bytes. Under Windows CE, many
* supported processors do not necessarily follow this assumption (1K page size is common).
* The issue here is that the underlying hardware can use scatter/gather DMA, but
* can handle at most 1 page transition per transfer. However, client buffers on systems
* with smaller page sizes may be scattered across several physically disjoint pages.
*
* In order to make this restriction transparent to client drivers, OHCD.DLL allocates
* a buffer from the system which is known to be contiguous within 4K sections.
* Then, DMA is done to the private buffers, and copied to the client buffer
* once the transfer is complete. For some client drivers, this extra copy may
* impose an unacceptable performance hit, however. So, the Windows CE transfer functions
* allow the client to pass in an optional physical memory address which is used directly
* for the DMA to/from the HC hardware. Because the HC accesses this buffer directly,
* the following two restrictions must be rigidly adhered to:
*
* 1) Physical buffer must be contiguous within 4K segments. How the client allocates
* this memory is beyond the scope of this document (e.g. may be through a platform
* specific call). The LockPages() call can be used to get physical page information.
*
* 2) Client must not access or free the buffer before the transfer has completed.
*
*
* @xref <f GetInterface> <f SetInterface> <f GetDescriptor> <f SetDescriptor> <f SetFeature>
* <f ClearFeature> <f GetStatus> <f SyncFrame> <f IssueVendorTransfer>
* <f IssueControlTransfer> <f IssueBulkTransfer> <f IssueInterruptTransfer>
* <f IssueIsochTransfer>
*/
/*
* @func USB_TRANSFER | GetInterface | Send a GET_INTERFACE request to USB device
* @rdesc Returns a USB_TRANSFER handle, or NULL if an error occurs.
* @comm Initiates a control transfer to USB device requesting the alternate
* setting selected for the given interface.
* @xref <f SetInterface> <f IsTransferComplete> <f GetTransferStatus> <f AbortTransfer>
*/
extern "C" USB_TRANSFER
GetInterface(
USB_HANDLE hDevice, // @parm [IN] - USB device handle
LPTRANSFER_NOTIFY_ROUTINE lpStartAddress, // @parm [IN] - Address of callback routine (may be NULL)
LPVOID lpvNotifyParameter, // @parm [IN] - Parameter to pass to callback routine
DWORD dwFlags, // @parm [IN] - USB_NO_WAIT, or 0
UCHAR bInterfaceNumber, // @parm [IN] - Interface number
PUCHAR lpbAlternateSetting) // @parm [OUT]- Filled in with current alternate setting value
{
USB_DEVICE_REQUEST DeviceRequest;
DEBUGMSG(ZONE_API|ZONE_CONFIG,(TEXT("+USBD:GetInterface\r\n")));
DeviceRequest.bmRequestType = USB_REQUEST_DEVICE_TO_HOST |
USB_REQUEST_STANDARD | USB_REQUEST_FOR_INTERFACE;
DeviceRequest.bRequest = USB_REQUEST_GET_INTERFACE;
DeviceRequest.wValue = 0;
DeviceRequest.wIndex = bInterfaceNumber;
DeviceRequest.wLength = 1;
dwFlags |= USB_IN_TRANSFER;
dwFlags &= ~USB_SHORT_TRANSFER_OK;
return IssueVendorTransfer(hDevice, lpStartAddress, lpvNotifyParameter,
dwFlags, &DeviceRequest, lpbAlternateSetting, 0);
}
/*
* @func USB_TRANSFER | SetInterface | Send a SET_INTERFACE request to USB device
* @rdesc Returns a USB_TRANSFER handle, or NULL if an error occurs.
* @comm Initiates a control transfer to USB device specifying the alternate
* setting to use for the given interface.
* @xref <f GetInterface> <f IsTransferComplete> <f GetTransferStatus> <f AbortTransfer>
*/
extern "C" USB_TRANSFER
SetInterface(
USB_HANDLE hDevice, // @parm [IN] - USB device handle
LPTRANSFER_NOTIFY_ROUTINE lpStartAddress, // @parm [IN] - Address of callback routine (should be NULL unless the USB_NO_WAIT flag is set)
LPVOID lpvNotifyParameter, // @parm [IN] - Parameter to pass to callback routine
DWORD dwFlags, // @parm [IN] - USB_NO_WAIT, or 0
UCHAR bInterfaceNumber, // @parm [IN] - Interface number
UCHAR bAlternateSetting) // @parm [IN] - Alternate setting number
{
USB_DEVICE_REQUEST DeviceRequest;
DEBUGMSG(ZONE_API|ZONE_CONFIG,(TEXT("+USBD:SetInterface\r\n")));
DeviceRequest.bmRequestType = USB_REQUEST_HOST_TO_DEVICE |
USB_REQUEST_STANDARD | USB_REQUEST_FOR_INTERFACE;
DeviceRequest.bRequest = USB_REQUEST_SET_INTERFACE;
DeviceRequest.wValue = bAlternateSetting;
DeviceRequest.wIndex = bInterfaceNumber;
DeviceRequest.wLength = 0;
dwFlags &= ~USB_IN_TRANSFER;
dwFlags &= ~USB_SHORT_TRANSFER_OK;
return IssueVendorTransfer(hDevice, lpStartAddress, lpvNotifyParameter,
dwFlags, &DeviceRequest, NULL, 0);
}
/*
* @func USB_TRANSFER | GetDescriptor | Send a GET_DESCRIPTOR request to USB device.
* @rdesc Returns a USB_TRANSFER handle, or NULL if an error occurs.
* @comm Initiates a control transfer to USB device requesting device
* descriptor information. The device will return the contents of the
* device descriptor starting at the index specified.
* @xref <f SetDescriptor> <f IsTransferComplete> <f GetTransferStatus> <f AbortTransfer>
*/
extern "C" USB_TRANSFER
GetDescriptor(
USB_HANDLE hDevice, // @parm [IN] - USB device handle
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -