📄 msclass.c
字号:
/*----------------------------------------------------------------------------------
*
* COPYRIGHT (c) 2001 by Singing Electrons, Inc. All rights reserved.
*
*
* Module Name : C:\se\adi\hidclass\Source\HidClass.c
*
* Description : The HID Class implementation - contains routines that implment the HID Class device
*
*
* Revision History : At bottom of the file.
*
*---------------------------------------------------------------------------------*/
/** include files **/
#include <sys/exception.h>
#include <sys/excause.h>
#include <defBF535.h>
#include "dtype.h"
#include "usb.h"
#include "usbdriver.h"
#include "msclass.h"
#include "dprintf.h"
#include "scsi.h"
/** local definitions **/
typedef enum {
STATE_IDLE = 0,
STATE_WAITFOR_CBW,
STATE_WAITFOR_DATA,
STATE_SEND_DATA,
STATE_EP_FOR_IN_STALLED,
STATE_CSW_SENT
}COMMAND_STATUS_STATE;
typedef struct tagCBW{
ULONG signature;
ULONG tag;
ULONG dataTransferLength;
UCHAR flags;
UCHAR lun;
UCHAR wcbLength;
UCHAR wcb[CBW_WCB_LEN];
}CBW, *PCBW;
typedef struct tagCSW{
ULONG signature;
ULONG tag;
ULONG dataResidue;
UCHAR status;
}CSW, *PCSW;
/* default settings */
#define CONTROL_PIPE_MAX_TRANSFER_LENGTH 64
#define INTERFACE_FOR_BULKONLY 0
#define ALTSETTING_FOR_BULKONLY 0
#define BULKEP_MAX_PACKET_SIZE 64
#define BULKEP_MAX_TRANSFER_SIZE 512
#define EP_FOR_IN_TRANSFERS EP1
#define EP_FOR_OUT_TRANSFERS EP2
#define MAX_LUN 0
#include "descriptors.h"
/** external functions **/
/** external data **/
/** internal functions **/
/** public data **/
bool gIsTransferActive;
/** private data **/
static PSUSPENDPROC gpOnSuspend;
static PRESUMEPROC gpOnResume;
static PRESETPROC gpOnReset;
static bool gIsDeviceConfigured = false;
COMMAND_STATUS_STATE gCommandStatusState;
CBW gCurrentCBW;
ULONG gRemainingDataToComeIn;
ULONG gRemainingDataToShipUp;
ULONG gResidue;
void *gpDataToShipUp;
/** public functions **/
/** private functions **/
bool ProcessCBW (PCBW pCBW);
bool IsCBWMeaningful (PCBW pCBW);
void ShipDataUp (void);
bool ExtractCBW (PCBW pCBW, UCHAR *pBuffer);
void BuildCSW (UCHAR *pBuffer, ULONG tag, ULONG dataResidue, UCHAR status);
/** callback functions **/
static bool OnSetupRequest (UCHAR endpointNumber, PUSB_SETUP_DATA pSetupData, void *buffer,
PUINT pNumBytesToTransfer);
static bool OnGetDeviceDescriptor (void *buffer, PUINT pNumBytesToTransfer);
static bool OnGetConfigDescriptor (void *buffer, PUINT pNumBytesToTransfer);
static bool OnGetStringDescriptor (UCHAR stringIndex, USHORT langID, void *buffer, PUINT pNumBytesToTransfer);
static void OnInTransferComplete (UCHAR endpointNumber);
static bool OnOutTransferComplete (UCHAR endpointNumber, void *buffer, UINT numBytesReceived, bool wasPCAsserted);
static void OnNAKSent (UCHAR endpointNumber);
static bool OnConfigRequest (UCHAR newConfiguration, UCHAR newInterface, UCHAR newAltSetting);
static void OnSuspend (void);
static void OnResume (void);
static void OnReset (void);
static void OnSOF (void);
/*------------------------------------------------------------
* MSCLASS_Init
*
* Parameters:
*
* Globals Used:
* gpOnResume, gpOnReset, gUseINEP, gpTheReportDescriptor, gTheReportDescriptorSize
* gTheDeviceDescriptor, gTheConfigDescriptor, gIsTransferActive, gIsDeviceConfigured,
* gCommandStatusState
*
* Description:
* This is the main initialization routine. The client provides the vendor id, device id,
* revision, and a bunch of pointers to routines to be calleld under various conditions.
* This routine also calls the init routine for the SCSI device implementation code.
*
* Returns:
* true on success, false on failure.
*
*------------------------------------------------------------*/
bool MSCLASS_Init (uint16 vid, uint16 pid, uint16 rel, PSUSPENDPROC pOnSuspendProc,
PRESUMEPROC pOnResumeProc, PRESETPROC pOnResetProc)
{
SCSI_Init();
//Initialize the state variables
gIsTransferActive = false;
gIsDeviceConfigured = false;
gCommandStatusState = STATE_IDLE;
/*
gDebugNumTransfers = 0;
gDebugTotalTransferLength = 0;
*/
//Save the callback addresses
gpOnSuspend = pOnSuspendProc;
gpOnResume = pOnResumeProc;
gpOnReset = pOnResetProc;
//Update the VID and PID
memcpy (&gTheDeviceDescriptor[OFFSET_VENDOR_ID], &vid, sizeof (uint16));
memcpy (&gTheDeviceDescriptor[OFFSET_PRODUCT_ID], &pid, sizeof (uint16));
memcpy (&gTheDeviceDescriptor[OFFSET_RELEASE], &rel, sizeof (uint16));
//Things to do before setting up endpoints
if (!USBDriver_PreInit ())
return false;
USBDriver_SetupEndpoint (EP_FOR_IN_TRANSFERS, ALTSETTING_FOR_BULKONLY,
INTERFACE_FOR_BULKONLY, EP_CONFIG1, EP_IN,
EP_BULK, BULKEP_MAX_PACKET_SIZE);
USBDriver_SetupEndpoint (EP_FOR_OUT_TRANSFERS, ALTSETTING_FOR_BULKONLY,
INTERFACE_FOR_BULKONLY, EP_CONFIG1, EP_OUT,
EP_BULK, BULKEP_MAX_PACKET_SIZE);
return USBDriver_CompleteInit (OnSetupRequest, OnGetDeviceDescriptor,
OnGetConfigDescriptor, OnGetStringDescriptor,
OnInTransferComplete, OnOutTransferComplete, OnNAKSent,
OnSuspend, OnResume, OnReset, OnConfigRequest, OnSOF, CONTROL_PIPE_MAX_TRANSFER_LENGTH);
}
/*------------------------------------------------------------
* MSReset
*
* Parameters:
* None
*
* Globals Used:
* gCommandStatusState, gRemainingDataToShipUp, gRemainingDataToComeIn
*
* Description:
* This is called to reset the state of the Command Status protocol, and
* to reset the endpoints - preparing them for transfers
*
* Returns:
* Nothing
*
*------------------------------------------------------------*/
void MSReset (void)
{
//Setup and Arm our endpoint
ActivateEndpoint (EP_FOR_OUT_TRANSFERS, USBD_TYP_BULK, BULKEP_MAX_PACKET_SIZE, CBW_LENGTH);
PrepareOUTEPForXFer (EP_FOR_OUT_TRANSFERS);
ArmEndpoint (EP_FOR_OUT_TRANSFERS, EP_OUT);
//Disarm the IN endpoint
DisarmEndpoint (EP_FOR_IN_TRANSFERS, EP_IN);
UnprepareEP (EP_FOR_IN_TRANSFERS);
Dprintf ("MSReset: Will wait for next CBW");
gCommandStatusState = STATE_WAITFOR_CBW;
gRemainingDataToComeIn = 0;
gRemainingDataToShipUp = 0;
}
/*------------------------------------------------------------
* OnSetupRequest
*
* Parameters:
* endpointNumber - the endpoint on which this request was received
* pSetupData - points to a structure cantaining the SETUP DATA(0)
* buffer - points to a buffer where the setup data is available, or should be placed.
* pNumBytesToTransfer - points to a location where the number of bytes
* to be sent back should be stored.
* Globals Used:
* None
*
* Description:
* This routine is called by the USB driver to handle a special setup request,
* that is not a GET DEVICE, GET CONFIG, or GET STRING descriptor
*
* Based on the request type, this routine reads/writes to the buffer
* provided.
*
* Returns:
* true to succeed the request, false to stall the request
*
*------------------------------------------------------------*/
bool OnSetupRequest (UCHAR endpointNumber, PUSB_SETUP_DATA pSetupData, void *buffer,
PUINT pNumBytesToTransfer)
{
bool retVal = false; //stall
bool validRequest = false;
//Need to handle the class specific requests
if (endpointNumber == EP0)
{
if ((USB_CONTROL_REQUEST_GET_TYPE (pSetupData->bmRequestType) == USB_CONTROL_REQUEST_TYPE_CLASS) &&
(USB_CONTROL_REQUEST_GET_RECIPIENT (pSetupData->bmRequestType) == USB_CONTROL_REQUEST_TYPE_INTERFACE) &&
(LOBYTE (pSetupData->wIndex) == INTERFACE_FOR_BULKONLY))
{
if ((USB_CONTROL_REQUEST_GET_DIRECTION(pSetupData->bmRequestType) == USB_CONTROL_REQUEST_TYPE_OUT) &&
(pSetupData->bRequest == USBMS_REQUEST_RESET) && (pSetupData->wValue == 0) && (pSetupData->wLength == 0))
{
validRequest = true;
retVal = true;
MSReset ();
}
else if ((USB_CONTROL_REQUEST_GET_DIRECTION(pSetupData->bmRequestType) == USB_CONTROL_REQUEST_TYPE_IN) &&
(pSetupData->bRequest == USBMS_REQUEST_GET_MAX_LUN) && (pSetupData->wValue == 0) && (pSetupData->wLength == 1))
{
validRequest = true;
*(PUCHAR)buffer = MAX_LUN;
*pNumBytesToTransfer = 1;
retVal = true;
}
}
}
if (!validRequest)
{
Dprintf1 ("Unknown setup request: %02x", pSetupData->bmRequestType);
Dprintf3 ("Dir = %02x, Type = %02x, Rec = %02x", USB_CONTROL_REQUEST_GET_DIRECTION (pSetupData->bmRequestType),
USB_CONTROL_REQUEST_GET_TYPE (pSetupData->bmRequestType),
USB_CONTROL_REQUEST_GET_RECIPIENT (pSetupData->bmRequestType));
Dprintf1 ("bRequest = %02x", pSetupData->bRequest);
}
return (retVal);
}
/*------------------------------------------------------------
* OnGetDeviceDescriptor
*
* Parameters:
* buffer - location (DMA buffer) where the descriptor data is to
* be put.
* pNumBytesToTransfer - points to a location where the original wLength
* is stored. This routine should update this location to indicate
* the actual number of bytes transferred to the buffer.
*
* Globals Used:
* gTheDeviceDescriptor
*
* Description:
* This routine is in response to a GET DEVICE DESCRIPTOR
* setup request. This routine fills in the required data
*
* Returns:
* true - always!
*
*------------------------------------------------------------*/
bool OnGetDeviceDescriptor (void *buffer, PUINT pNumBytesToTransfer)
{
if (*pNumBytesToTransfer < sizeof (gTheDeviceDescriptor))
memcpy (buffer, &gTheDeviceDescriptor, *pNumBytesToTransfer);
else
{
memcpy (buffer, &gTheDeviceDescriptor, sizeof (gTheDeviceDescriptor));
*pNumBytesToTransfer = sizeof (gTheDeviceDescriptor);
}
return(true);
}
/*------------------------------------------------------------
* OnGetConfigDescriptor
*
* Parameters:
* buffer - location (DMA buffer) where the descriptor data is to
* be put.
* pNumBytesToTransfer - points to a location where the original wLength
* is stored. This routine should update this location to indicate
* the actual number of bytes transferred to the buffer.
*
* Globals Used:
* gTheConfigDescriptor
*
* Description:
* This routine is in response to a GET CONFIG DESCRIPTOR
* setup request. This routine fills in the required data
*
* Returns:
* true - always!
*
*------------------------------------------------------------*/
bool OnGetConfigDescriptor (void *buffer, PUINT pNumBytesToTransfer)
{
if (*pNumBytesToTransfer < sizeof(gTheConfigDescriptor))
memcpy (buffer, &gTheConfigDescriptor, *pNumBytesToTransfer);
else
{
memcpy (buffer, &gTheConfigDescriptor, sizeof (gTheConfigDescriptor));
*pNumBytesToTransfer = sizeof (gTheConfigDescriptor);
}
return (true);
}
/*------------------------------------------------------------
* OnGetStringDescriptor
*
* Parameters:
* wValue - the string to be retrieved
* buffer - location (DMA buffer) where the descriptor data is to
* be put.
* pNumBytesToTransfer - points to a location where the original wLength
* is stored. This routine should update this location to indicate
* the actual number of bytes transferred to the buffer.
*
* Globals Used:
* Not Yet!
*
* Description:
* This routine is in response to a GET STRING DESCRIPTOR
* setup request. This routine fills in the required data
*
* Returns:
* true - always!
*
*------------------------------------------------------------*/
bool OnGetStringDescriptor (UCHAR stringIndex, USHORT langID, void *buffer, PUINT pNumBytesToTransfer)
{
bool retVal = false;
UINT neededSpace = 0;
UINT maxBytesToTransfer = 0;
UINT outIndex = 0, charIndex = 0;
if (stringIndex == 0)
{
//Need to return a langid array here!
if (*pNumBytesToTransfer < sizeof (gTheLangIDArray))
memcpy (buffer, &gTheLangIDArray, *pNumBytesToTransfer);
else
{
memcpy (buffer, &gTheLangIDArray, sizeof (gTheLangIDArray));
*pNumBytesToTransfer = sizeof (gTheLangIDArray);
}
retVal = true;
}
else if ((stringIndex < TOTAL_STRING_DESCRIPTORS) && (stringIndex > 0))
{
//Convert this to a zero based index
stringIndex--;
neededSpace = (strlen (gTheStringDescriptors[stringIndex]) + 1) * 2;
if (neededSpace > *pNumBytesToTransfer)
maxBytesToTransfer = *pNumBytesToTransfer;
else
maxBytesToTransfer = *pNumBytesToTransfer = neededSpace;
//Transfer as many as we can
((char *)buffer)[outIndex++] = neededSpace;
((char *)buffer)[outIndex++] = USB_STRING_DESCRIPTOR;
while ((outIndex + 1) < maxBytesToTransfer)
{
((char *)buffer)[outIndex++] = gTheStringDescriptors[stringIndex][charIndex++];
((char *)buffer)[outIndex++] = 0;
}
retVal = true;
}
//Don't have any strings yet!
return(retVal);
}
/*------------------------------------------------------------
* OnConfigRequest
*
* Parameters:
* newConfiguration - the new configuration after Config request.
* newInterface - the new interface after Config(Set Interface) request.
* newAltSetting - the new alt setting after Config(Set Interface) request
*
* Globals Used:
* gIsDeviceConfigured
*
* Description:
* This routien is called in response to a configuration change - i.e.
* after receiving a Set Config or a Set Interface request.
*
* Returns:
* true - always
*
*------------------------------------------------------------*/
bool OnConfigRequest (UCHAR newConfiguration, UCHAR newInterface, UCHAR newAltSetting)
{
//Dprintf3 ("Audio Dev Config Request: %02x, %02x, %02x!", (UINT)newConfiguration, (UINT)newInterface, (UINT)newAltSetting);
if ((newConfiguration == EP_CONFIG1) && (newInterface == INTERFACE_FOR_BULKONLY) &&
(newAltSetting == ALTSETTING_FOR_BULKONLY))
{
if (!gIsDeviceConfigured)
{
//Looks like we're in, setup our endpoints
Dprintf ("Mass Storage Device Configured!");
MSReset ();
gIsDeviceConfigured = true;
}
}
else
{
//Disarm the endpoints
DisarmEndpoint (EP_FOR_IN_TRANSFERS, EP_IN);
UnprepareEP (EP_FOR_IN_TRANSFERS);
DisarmEndpoint (EP_FOR_OUT_TRANSFERS, EP_OUT);
UnprepareEP (EP_FOR_OUT_TRANSFERS);
gIsDeviceConfigured = false;
}
return true;
}
/*------------------------------------------------------------
* OnInTransferComplete
*
* Parameters:
* endpointNumber - the endpoint on which the transfer was completed.
*
* Globals Used:
* gCommandStatusState
*
* Description:
* This routine is called when a IN transfer is completed on one of the
* endpoints.
*
* Returns:
* Nothing
*
*------------------------------------------------------------*/
void OnInTransferComplete (UCHAR endpointNumber)
{
if (endpointNumber == EP_FOR_IN_TRANSFERS)
{
//Disarm the IN endpoint
//DisarmEndpoint (EP_FOR_IN_TRANSFERS, EP_IN);
//UnprepareEP (EP_FOR_IN_TRANSFERS);
//Dprintf1 ("InTransferComplete: %02x", gCommandStatusState);
switch (gCommandStatusState)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -