?? usbddriver.c
字號:
/* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support
* ----------------------------------------------------------------------------
* Copyright (c) 2008, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ----------------------------------------------------------------------------
*/
//------------------------------------------------------------------------------
// Headers
//------------------------------------------------------------------------------
#include "USBDDriver.h"
#include "USBDDriverCallbacks.h"
#include "USBD.h"
#include <board.h>
#include <utility/trace.h>
#include <usb/common/core/USBGenericDescriptor.h>
#include <usb/common/core/USBDeviceDescriptor.h>
#include <usb/common/core/USBConfigurationDescriptor.h>
#include <usb/common/core/USBDeviceQualifierDescriptor.h>
#include <usb/common/core/USBEndpointDescriptor.h>
#include <usb/common/core/USBFeatureRequest.h>
#include <usb/common/core/USBSetAddressRequest.h>
#include <usb/common/core/USBGetDescriptorRequest.h>
#include <usb/common/core/USBSetConfigurationRequest.h>
#include <usb/common/core/USBInterfaceRequest.h>
#include <string.h>
//------------------------------------------------------------------------------
// Local functions
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
/// Configures the device by setting it into the Configured state and
/// initializing all endpoints.
/// \param pDriver Pointer to a USBDDriver instance.
/// \param cfgnum Configuration number to set.
//------------------------------------------------------------------------------
static void SetConfiguration(USBDDriver *pDriver, unsigned char cfgnum)
{
USBEndpointDescriptor *pEndpoints[BOARD_USB_NUMENDPOINTS+1];
const USBConfigurationDescriptor *pConfiguration;
// Use different descriptor depending on device speed
if (USBD_IsHighSpeed()) {
pConfiguration = pDriver->pDescriptors->pHsConfiguration;
}
else {
pConfiguration = pDriver->pDescriptors->pFsConfiguration;
}
// Set & save the desired configuration
USBD_SetConfiguration(cfgnum);
pDriver->cfgnum = cfgnum;
// If the configuration is not 0, configure endpoints
if (cfgnum != 0) {
// Parse configuration to get endpoint descriptors
USBConfigurationDescriptor_Parse(pConfiguration, 0, pEndpoints, 0);
// Configure endpoints
int i = 0;
while (pEndpoints[i] != 0) {
USBD_ConfigureEndpoint(pEndpoints[i]);
i++;
}
}
// Should be done before send the ZLP
USBDDriverCallbacks_ConfigurationChanged(cfgnum);
// Acknowledge the request
USBD_Write(0, // Endpoint #0
0, // No data buffer
0, // No data buffer
(TransferCallback) 0,
(void *) 0);
}
//------------------------------------------------------------------------------
/// Sends the current configuration number to the host.
/// \param pDriver Pointer to a USBDDriver instance.
//------------------------------------------------------------------------------
static void GetConfiguration(const USBDDriver *pDriver)
{
USBD_Write(0, &(pDriver->cfgnum), 1, 0, 0);
}
//------------------------------------------------------------------------------
/// Sends the current status of the device to the host.
/// \param pDriver Pointer to a USBDDriver instance.
//------------------------------------------------------------------------------
static void GetDeviceStatus(const USBDDriver *pDriver)
{
unsigned short data = 0;
const USBConfigurationDescriptor *pConfiguration;
// Use different configuration depending on device speed
if (USBD_IsHighSpeed()) {
pConfiguration = pDriver->pDescriptors->pHsConfiguration;
}
else {
pConfiguration = pDriver->pDescriptors->pFsConfiguration;
}
// Check current configuration for power mode (if device is configured)
if (pDriver->cfgnum != 0) {
if (USBConfigurationDescriptor_IsSelfPowered(pConfiguration)) {
data |= 1;
}
}
// Check if remote wake-up is enabled
if (pDriver->isRemoteWakeUpEnabled) {
data |= 2;
}
// Send the device status
USBD_Write(0, &data, 2, 0, 0);
}
//------------------------------------------------------------------------------
/// Sends the current status of an endpoints to the USB host.
/// \param bEndpoint Endpoint number.
//------------------------------------------------------------------------------
static void GetEndpointStatus(unsigned char bEndpoint)
{
unsigned short data = 0;
// Check if the endpoint exists
if (bEndpoint > BOARD_USB_NUMENDPOINTS) {
USBD_Stall(0);
}
else {
// Check if the endpoint if currently halted
if (USBD_IsHalted(bEndpoint)) {
data = 1;
}
// Send the endpoint status
USBD_Write(0, &data, 2, 0, 0);
}
}
//------------------------------------------------------------------------------
/// Sends the requested USB descriptor to the host if available, or STALLs the
/// request.
/// \param pDriver Pointer to a USBDDriver instance.
/// \param type Type of the requested descriptor
/// \param index Index of the requested descriptor.
/// \param length Maximum number of bytes to return.
//------------------------------------------------------------------------------
static void GetDescriptor(
const USBDDriver *pDriver,
unsigned char type,
unsigned char index,
unsigned int length)
{
const USBDeviceDescriptor *pDevice;
const USBConfigurationDescriptor *pConfiguration;
const USBDeviceQualifierDescriptor *pQualifier;
const USBConfigurationDescriptor *pOtherSpeed;
const USBGenericDescriptor **pStrings =
(const USBGenericDescriptor **) pDriver->pDescriptors->pStrings;
unsigned char numStrings = pDriver->pDescriptors->numStrings;
const USBGenericDescriptor *pString;
// Use different set of descriptors depending on device speed
if (USBD_IsHighSpeed()) {
TRACE_DEBUG("HS ");
pDevice = pDriver->pDescriptors->pHsDevice;
pConfiguration = pDriver->pDescriptors->pHsConfiguration;
pQualifier = pDriver->pDescriptors->pHsQualifier;
pOtherSpeed = pDriver->pDescriptors->pHsOtherSpeed;
}
else {
TRACE_DEBUG("FS ");
pDevice = pDriver->pDescriptors->pFsDevice;
pConfiguration = pDriver->pDescriptors->pFsConfiguration;
pQualifier = pDriver->pDescriptors->pFsQualifier;
pOtherSpeed = pDriver->pDescriptors->pFsOtherSpeed;
}
// Check the descriptor type
switch (type) {
case USBGenericDescriptor_DEVICE:
TRACE_INFO_WP("Dev ");
// Adjust length and send descriptor
if (length > USBGenericDescriptor_GetLength((USBGenericDescriptor *) pDevice)) {
length = USBGenericDescriptor_GetLength((USBGenericDescriptor *) pDevice);
}
USBD_Write(0, pDevice, length, 0, 0);
break;
case USBGenericDescriptor_CONFIGURATION:
TRACE_INFO_WP("Cfg ");
// Adjust length and send descriptor
if (length > USBConfigurationDescriptor_GetTotalLength(pConfiguration)) {
length = USBConfigurationDescriptor_GetTotalLength(pConfiguration);
}
USBD_Write(0, pConfiguration, length, 0, 0);
break;
case USBGenericDescriptor_DEVICEQUALIFIER:
TRACE_INFO_WP("Qua ");
// Check if descriptor exists
if (!pQualifier) {
USBD_Stall(0);
}
else {
// Adjust length and send descriptor
if (length > USBGenericDescriptor_GetLength((USBGenericDescriptor *) pQualifier)) {
length = USBGenericDescriptor_GetLength((USBGenericDescriptor *) pQualifier);
}
USBD_Write(0, pQualifier, length, 0, 0);
}
break;
case USBGenericDescriptor_OTHERSPEEDCONFIGURATION:
TRACE_INFO_WP("OSC ");
// Check if descriptor exists
if (!pOtherSpeed) {
USBD_Stall(0);
}
else {
// Adjust length and send descriptor
if (length > USBConfigurationDescriptor_GetTotalLength(pOtherSpeed)) {
length = USBConfigurationDescriptor_GetTotalLength(pOtherSpeed);
}
USBD_Write(0, pOtherSpeed, length, 0, 0);
}
break;
case USBGenericDescriptor_STRING:
TRACE_INFO_WP("Str%d ", index);
// Check if descriptor exists
if (index > numStrings) {
USBD_Stall(0);
}
else {
pString = pStrings[index];
// Adjust length and send descriptor
if (length > USBGenericDescriptor_GetLength(pString)) {
length = USBGenericDescriptor_GetLength(pString);
}
USBD_Write(0, pString, length, 0, 0);
}
break;
default:
TRACE_WARNING(
"USBDDriver_GetDescriptor: Unknown descriptor type (%d)\n\r",
type);
USBD_Stall(0);
}
}
//------------------------------------------------------------------------------
/// Sets the active setting of the given interface if the configuration supports
/// it; otherwise, the control pipe is STALLed. If the setting of an interface
/// changes.
/// \parma pDriver Pointer to a USBDDriver instance.
/// \parma infnum Interface number.
/// \parma setting New active setting for the interface.
//------------------------------------------------------------------------------
static void SetInterface(
USBDDriver *pDriver,
unsigned char infnum,
unsigned char setting)
{
// Make sure alternate settings are supported
if (!pDriver->pInterfaces) {
USBD_Stall(0);
}
else {
// Change the current setting of the interface and trigger the callback
// if necessary
if (pDriver->pInterfaces[infnum] != setting) {
pDriver->pInterfaces[infnum] = setting;
USBDDriverCallbacks_InterfaceSettingChanged(infnum, setting);
}
// Acknowledge the request
USBD_Write(0, 0, 0, 0, 0);
}
}
//------------------------------------------------------------------------------
/// Sends the currently active setting of the given interface to the USB
/// host. If alternate settings are not supported, this function STALLs the
/// control pipe.
/// \param pDriver Pointer to a USBDDriver instance.
/// \param infnum Interface number.
//------------------------------------------------------------------------------
static void GetInterface(
const USBDDriver *pDriver,
unsigned char infnum)
{
// Make sure alternate settings are supported, or STALL the control pipe
if (!pDriver->pInterfaces) {
USBD_Stall(0);
}
else {
// Sends the current interface setting to the host
USBD_Write(0, &(pDriver->pInterfaces[infnum]), 1, 0, 0);
}
}
#ifdef BOARD_USB_UDPHS
//------------------------------------------------------------------------------
// Performs the selected test on the USB device (high-speed only).
// \param test Test selector value.
//------------------------------------------------------------------------------
static void USBDDriver_Test(unsigned char test)
{
TRACE_DEBUG("UDPHS_Test\n\r");
// the lower byte of wIndex must be zero
// the most significant byte of wIndex is used to specify the specific test mode
switch (test) {
case USBFeatureRequest_TESTPACKET:
//Test mode Test_Packet:
//Upon command, a port must repetitively transmit the following test packet until
//the exit action is taken. This enables the testing of rise and fall times, eye
//patterns, jitter, and any other dynamic waveform specifications.
//The test packet is made up by concatenating the following strings.
//(Note: For J/K NRZI data, and for NRZ data, the bit on the left is the first one
//transmitted. 揝
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -