📄 serial_dl.cpp
字号:
//
// 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.
//
//------------------------------------------------------------------------------
//
// File: serial_dl.c
//
// This is a hardware-independent USB Serial Client driver. It will interpret
// and respond to standard USB Host requests, as well as serial-specific
// Host requests during initialization.
//
// This code is meant to provide the minimal set of routines necessary for USB
// transfers, and is targeted for the boot-loader and small code size.
#include <windows.h>
#include <usbfntypes.h>
#include <usbfn.h>
#include <oal.h>
#include <oal_blserial.h>
//------------------------------------------------------------------------------
//
// Entry points for calling application
//
extern "C" BOOL USBSerialInit();
static BOOL g_USBSerialInitialized = FALSE;
//------------------------------------------------------------------------------
//
// Exit points to USB Function driver. Using the UFN MDD/PDD interfaces, reused
// from OS driver. PDD Interface receives transfer information in 'STransfer's
//
UFN_MDD_INTERFACE_INFO g_mddInterface;
UFN_PDD_INTERFACE_INFO g_pddInterface;
STransfer g_EP0Transfer; // EP0
STransfer g_EP1Transfer; // Bulk out
STransfer g_EP2Transfer; // Bulk in
//------------------------------------------------------------------------------
//
// Type: DEVICE_STATE, g_DeviceState
//
// Keep track of the USB state - Cable detatched, attached, initialized, etc.
//
enum DEVICE_STATE {
DS_DETACHED = 0,
DS_ATTACHED,
DS_POWERED,
DS_DEFAULT,
DS_ADDRESSED,
DS_CONFIGURED,
DS_SUSPENDED,
};
enum DEVICE_STATE g_DeviceState = DS_DETACHED;
//------------------------------------------------------------------------------
//
// Type: TRANSFER_STATE
//
// USB Serial defines 3 endpoints, hold the current state of each endpoint
// 0: Control
// 1: Receive Packets
// 2: Send Packets
//
//
enum TRANSFER_STATE {
TS_IDLE=0,
TS_RECEIVING_MESSAGE,
TS_SENDING_MESSAGE,
TS_RECEIVING_PACKET,
TS_SENDING_PACKET,
TS_SENDING_PACKET_TERMINATOR
};
enum TRANSFER_STATE g_EP0State = TS_IDLE;
enum TRANSFER_STATE g_EP1State = TS_IDLE;
enum TRANSFER_STATE g_EP2State = TS_IDLE;
//------------------------------------------------------------------------------
//
// Endpoint 0 Transfer types
//
// Necessary for constructing Host responses and issuing them to hardware
typedef enum {
EP0Setup = 0,
EP0Out,
EP0In
} EP0_DIR;
typedef struct _EP0_REQUEST EP0_REQUEST, *PEP0_REQUEST;
struct _EP0_REQUEST
{
EP0_DIR eDir;
UCHAR *pucData;
DWORD dwExpectedSize;
DWORD dwActualSize;
VOID (*pfnNotification)(EP0_REQUEST *pRequest, PVOID pvUser);
PVOID pvUser;
DWORD dwProcessed;
BOOL fCompleted;
};
//------------------------------------------------------------------------------
//
// Receive buffer managment routines
//
// This wrapper will buffer data coming from the hardware line, and provide
// it to the application on request.
//
#define RECV_BUFFER_SIZE 1750 // Must be at least KITL_MTU + 1
#define SPACE_IN_BUFFER(head,tail) \
(tail >= head ? tail-head : RECV_BUFFER_SIZE - head + tail)
#define SPACE_UNTIL_WRAP(tail) (RECV_BUFFER_SIZE - tail)
BYTE g_RecvBuffer[RECV_BUFFER_SIZE];
USHORT g_RecvBufferHead = 0;
USHORT g_RecvBufferTail = 0;
//------------------------------------------------------------------------------
//
// USB Serial session descriptors
//
// Data needed by the USB Host to initialize a USB Serial session
//
#define EP0MaxSize 16
#define EPMaxSize 64
#define CFGLEN 32 // Length of configuration descriptor
#define iCONF 18 // Index in gs_pucUSBDescriptors for Configuration Descriptors
#define iINF 27 // Index in gs_pucUsBDescriptors for Interface Descriptors
static USB_DEVICE_DESCRIPTOR deviceDescriptor;
static UFN_ENDPOINT rgEndPoints[3];
static UFN_INTERFACE Interface;
static UFN_CONFIGURATION deviceConfiguration;
static UFN_BUS_SPEED busSpeed;
///////////////////////////////
// Serial USB Descriptor Set //
///////////////////////////////
static UCHAR gs_pucUSBDescriptors[]= {
/////////////////////////////////////////////
// Standard Device Descriptor (One Device) //
/////////////////////////////////////////////
/* 0 */ 18, // bLength
/* 1 */ USB_DEVICE_DESCRIPTOR_TYPE,
/* 2 */ 0, 1, // bcdUSB
/* 4 */ 0xff, // bDeviceClass (0xFF = Vendor Specific)
/* 5 */ 0xff, // bDeviceSubClass
/* 6 */ 0xff, // bDeviceProtocol
/* 7 */ EP0MaxSize, // bMaxPacketSize0
/* 8 */ 0x5E, 0x04, // idVendor (Microsoft Vendor ID)
#if USING_USBSER
/* 10 */ 0x79, 0x00, // idProduct
/* 12 */ 0x90, 0, // bcdDevice
#else
/* 10 */ 0xCE, 0x00, // idProduct
/* 12 */ 0, 0, // bcdDevice
#endif
/* 14 */ 0, // iManufacturer - index of Manf String Descriptor
/* 15 */ 0, // iProduct - index of Product String Descriptor
/* 16 */ 0, // iSerialNumber - Index of Serial Number String
/* 17 */ 1, // bNumConfigurations
///////////////////////////////////////////////////////////
// Standard Configuration Descriptor (One Configuration) //
///////////////////////////////////////////////////////////
/* 18 */ 9, // bLength
/* 19 */ USB_CONFIGURATION_DESCRIPTOR_TYPE,
/* 20 */ CFGLEN%256,CFGLEN/256, // wTotalLength
/* 22 */ 1, // bNumInterfaces
/* 23 */ 1, // bConfigurationValue
/* 24 */ 0, // iConfiguration
/* 25 */ 0x40, // bmAttributes (self powered)
/* 26 */ 1, // MaxPower (x2 mA)
///////////////////////////////////////////////////
// Standard Interface Descriptor (One Interface) //
///////////////////////////////////////////////////
/* 27 */ 9, // bLength
/* 28 */ USB_INTERFACE_DESCRIPTOR_TYPE,
/* 29 */ 0, // bInterfaceNumber
/* 30 */ 0, // bAlternateSetting
/* 31 */ 2, // bNumEndpoints (number endpoints used, excluding EP0)
/* 32 */ 0xff, // bInterfaceClass
/* 33 */ 0xff, // bInterfaceSubClass
/* 34 */ 0xff, // bInterfaceProtocol
/* 35 */ 0, // ilInterface (Index of this interface string desc.)
///////////////////////////////////////////////////
// Standard Endpoint Descriptor (EP1 - BULK OUT) //
///////////////////////////////////////////////////
/* 36 */ 7, // bLength
/* 37 */ USB_ENDPOINT_DESCRIPTOR_TYPE,
/* 38 */ 0x01, // bEndpointAddress (EP 1, OUT)
/* 39 */ 2, // bmAttributes (0010 = Bulk)
/* 40 */ EPMaxSize, 0, // wMaxPacketSize
/* 42 */ 0, // bInterval (ignored for Bulk)
//////////////////////////////////////////////////
// Standard Endpoint Descriptor (EP2 - BULK IN) //
//////////////////////////////////////////////////
/* 43 */ 7, // bLength
/* 44 */ USB_ENDPOINT_DESCRIPTOR_TYPE,
/* 45 */ 0x82, // bEndpointAddress (EP 2, IN)
/* 46 */ 2, // bmAttributes (0010 = Bulk)
/* 47 */ EPMaxSize, 0, // wMaxPacketSize
/* 49 */ 0 // bInterval (ignored for Bulk)
};
// Device specific request
#define SET_CONTROL_LINE_STATE 0x22
//------------------------------------------------------------------------------
//
// Function: Interrupt Thread
//
// Entry to PDD interrupt thread. This will be called repeatedly (bootloader uses polling)
//
extern "C" DWORD InterruptThread(VOID *pPddContext);
extern "C" BOOL InitializeHardware(); // Hook for board-specific init (GPIO's, clocks, etc)
extern "C" void msWait(UINT32 msVal);
//------------------------------------------------------------------------------
//
// Function: HandleUSBDeviceRegistration
//
// Negotiate for physical bulk endpoints for send/receive. Negotiate hardware's
// maxPacketSizes and update our descriptors to reflect hardware capabilities.
//
static void HandleUSBDeviceRegistration()
{
DWORD dwRet;
DWORD logicalEndPoint;
DWORD physicalEndPoint;
BOOL logEndPointTaken[4] = {FALSE, FALSE, FALSE, FALSE};
BOOL physEndPointTaken[16] = {FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE };
USB_CONFIGURATION_DESCRIPTOR *pUsbConfDesc = (USB_CONFIGURATION_DESCRIPTOR*)&gs_pucUSBDescriptors[iCONF];
USB_INTERFACE_DESCRIPTOR *pUsbInfDesc = (USB_INTERFACE_DESCRIPTOR*)&gs_pucUSBDescriptors[iINF];
// Fill descriptors that the PDD will use to register configuration and interface
deviceConfiguration.pInterfaces = &Interface;
deviceConfiguration.Descriptor.bNumInterfaces = 1;
Interface.pEndpoints = rgEndPoints;
Interface.Descriptor.bNumEndpoints = 2;
deviceDescriptor.bMaxPacketSize0 = EP0MaxSize;
busSpeed = BS_FULL_SPEED;
// Fill endpoint descriptors with some initial values, and negotiate them with PDD
// Logical EP0
rgEndPoints[0].Descriptor.bEndpointAddress = 0x00;
rgEndPoints[0].Descriptor.wMaxPacketSize = EP0MaxSize;
rgEndPoints[0].Descriptor.bmAttributes = USB_ENDPOINT_TYPE_CONTROL;
// Logical EP1
rgEndPoints[1].Descriptor.bEndpointAddress = 0x01; // EP1, OUT (BULK)
rgEndPoints[1].Descriptor.wMaxPacketSize = EPMaxSize;
rgEndPoints[1].Descriptor.bmAttributes = USB_ENDPOINT_TYPE_BULK;
// Logical EP2
rgEndPoints[2].Descriptor.bEndpointAddress = 0x82; // EP2, IN (BULK)
rgEndPoints[2].Descriptor.wMaxPacketSize = EPMaxSize;
rgEndPoints[2].Descriptor.bmAttributes = USB_ENDPOINT_TYPE_BULK;
// Ensure that the specified endpoint 0 can be supported
dwRet = g_pddInterface.pfnIsEndpointSupportable(
g_pddInterface.pvPddContext, 0, busSpeed, &rgEndPoints[0].Descriptor, 0,0,0);
if( dwRet != ERROR_SUCCESS )
{
OALMSG(OAL_ETHER&&OAL_FUNC, (L"ERROR: PDD cannot support endpoint 0\r\n"));
}
// Setup remaining endpoints (Logical endpoints 1 and 2 for Serial)
for( logicalEndPoint = 1; logicalEndPoint <=2; logicalEndPoint++)
{
for( physicalEndPoint=1; physicalEndPoint<16; physicalEndPoint++ )
{
if( !physEndPointTaken[physicalEndPoint] )
{
rgEndPoints[logicalEndPoint].Descriptor.bEndpointAddress &= ~0x7F;
rgEndPoints[logicalEndPoint].Descriptor.bEndpointAddress |= physicalEndPoint;
dwRet = g_pddInterface.pfnIsEndpointSupportable(
g_pddInterface.pvPddContext,
physicalEndPoint, busSpeed, &rgEndPoints[logicalEndPoint].Descriptor,
pUsbConfDesc->bConfigurationValue,
pUsbInfDesc->bInterfaceNumber, pUsbInfDesc->bAlternateSetting);
if( dwRet == ERROR_SUCCESS )
{
OALMSG(OAL_ETHER&&OAL_FUNC, (L"Mapping %d to %d\r\n", logicalEndPoint, physicalEndPoint));
physEndPointTaken[physicalEndPoint] = TRUE;
logEndPointTaken[logicalEndPoint] = TRUE;
break;
}
}
}
if( !logEndPointTaken[logicalEndPoint])
{
OALMSG(OAL_ETHER&&OAL_FUNC, (L"ERROR: PDD cannot support logical endpoint %d\r\n", logicalEndPoint));
break;
}
}
// Update master descriptor with negotiated values.
// Logical EP1
gs_pucUSBDescriptors[38] = rgEndPoints[1].Descriptor.bEndpointAddress;
gs_pucUSBDescriptors[40] = (UCHAR)((rgEndPoints[1].Descriptor.wMaxPacketSize >> 0) & 0xFF);
gs_pucUSBDescriptors[41] = (UCHAR)((rgEndPoints[1].Descriptor.wMaxPacketSize >> 8) & 0xFF);
// Logical EP2
gs_pucUSBDescriptors[45] = rgEndPoints[2].Descriptor.bEndpointAddress;
gs_pucUSBDescriptors[47] = (UCHAR)((rgEndPoints[2].Descriptor.wMaxPacketSize >> 0) & 0xFF);
gs_pucUSBDescriptors[48] = (UCHAR)((rgEndPoints[2].Descriptor.wMaxPacketSize >> 8) & 0xFF);
// We assume knowledge of the RegisterDevice function implementation and pass very simplified arguments
g_pddInterface.pfnRegisterDevice( g_pddInterface.pvPddContext,
NULL, NULL, NULL,
&deviceDescriptor, &deviceConfiguration, NULL,
NULL, 0 );
}
//------------------------------------------------------------------------------
//
// Function: HandleClassRequest
//
// Called by HandleSetupPkt when type is USB_REQUEST_CLASS.
// This is serial-function specific stuff that updates modem status
//
void HandleClassRequest(USB_DEVICE_REQUEST *pUdr, EP0_REQUEST *pRequest)
{
if (pUdr->bmRequestType == (USB_REQUEST_CLASS | USB_REQUEST_FOR_INTERFACE | USB_REQUEST_HOST_TO_DEVICE) )
{
if( pUdr->bRequest == SET_CONTROL_LINE_STATE )
{
// Fill out pRequest structure such that a handshake is sent
// and ignore any line status data
pRequest->eDir = EP0Setup;
pRequest->pucData = NULL;
pRequest->dwExpectedSize = 0;
pRequest->dwActualSize = 0;
pRequest->pfnNotification = NULL;
pRequest->pvUser = NULL;
}
else ASSERT(!"Host indicated an unsupported SET Class Request");
}
else
{
ASSERT(!"Host sent unhandled request type!");
}
}
//------------------------------------------------------------------------------
//
// Function: HandleGetDescriptor
//
// Called by HandleSetupPkt when type is USB_REQUEST_GET_DESCRIPTOR.
// Will manage transmission of descriptors, strings, etc.
//
void HandleGetDescriptor(USB_DEVICE_REQUEST *pUdr, EP0_REQUEST *pRequest)
{
UCHAR *pucData;
WORD wLength;
switch(HIBYTE(pUdr->wValue))
{
case USB_DEVICE_DESCRIPTOR_TYPE:
pucData = (UCHAR *)gs_pucUSBDescriptors;
wLength = gs_pucUSBDescriptors[0];
break;
case USB_CONFIGURATION_DESCRIPTOR_TYPE:
pucData = (UCHAR *)&gs_pucUSBDescriptors[iCONF];
wLength = CFGLEN;
break;
case USB_STRING_DESCRIPTOR_TYPE:
pucData = NULL;
wLength = 0;
break;
default:
ASSERT(!"Unhandled Get DESCRIPTOR_TYPE!");
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -