embeddedsw/XilinxProcessorIPLib/drivers/usbps/examples/xusbps_ch9.c
Jagannadha Sutradharudu Teki 2c8f92039d embeddesw: Add initial code support
Added initial support Xilinx Embedded Software.

Signed-off-by: Jagannadha Sutradharudu Teki <jaganna@xilinx.com>
2014-06-24 16:45:01 +05:30

641 lines
17 KiB
C
Executable file

/******************************************************************************
*
* Copyright (C) 2010 - 2014 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
/*****************************************************************************/
/**
* @file xusbps_ch9.c
*
* This file contains the implementation of the chapter 9 code for the example.
*
*<pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- -------- ---------------------------------------------------------
* 1.00a jz 10/10/10 First release
* 1.04a nm 02/05/13 Fixed CR# 696550.
* Added template code for Vendor request.
* 1.04a nm 03/04/13 Fixed CR# 704022. Implemented TEST_MODE Feature.
* 1.06a kpc 11/11/13 Always use global memory for dma operations
* 2.1 kpc 4/29/14 Align dma buffers to cache line boundary
*</pre>
******************************************************************************/
/***************************** Include Files *********************************/
#include "xparameters.h" /* XPAR parameters */
#include "xusbps.h" /* USB controller driver */
#include "xusbps_hw.h" /* USB controller driver */
#include "xusbps_ch9.h"
#include "xil_printf.h"
#include "xil_cache.h"
/*default class is storage class */
#include "xusbps_class_storage.h"
#include "sleep.h"
/* #define CH9_DEBUG */
#ifdef CH9_DEBUG
#include <stdio.h>
#define printf xil_printf
#endif
/************************** Constant Definitions *****************************/
/**************************** Type Definitions *******************************/
/***************** Macros (Inline Functions) Definitions *********************/
/************************** Function Prototypes ******************************/
static void XUsbPs_StdDevReq(XUsbPs *InstancePtr,
XUsbPs_SetupData *SetupData);
static int XUsbPs_HandleVendorReq(XUsbPs *InstancePtr,
XUsbPs_SetupData *SetupData);
/************************** Variable Definitions *****************************/
static u8 Response ALIGNMENT_CACHELINE;
/*****************************************************************************/
/**
* This function handles a Setup Data packet from the host.
*
* @param InstancePtr is a pointer to XUsbPs instance of the controller.
* @param SetupData is the structure containing the setup request.
*
* @return
* - XST_SUCCESS if the function is successful.
* - XST_FAILURE if an Error occured.
*
* @note None.
*
******************************************************************************/
int XUsbPs_Ch9HandleSetupPacket(XUsbPs *InstancePtr,
XUsbPs_SetupData *SetupData)
{
int Status = XST_SUCCESS;
#ifdef CH9_DEBUG
printf("Handle setup packet\n");
#endif
switch (SetupData->bmRequestType & XUSBPS_REQ_TYPE_MASK) {
case XUSBPS_CMD_STDREQ:
XUsbPs_StdDevReq(InstancePtr, SetupData);
break;
case XUSBPS_CMD_CLASSREQ:
XUsbPs_ClassReq(InstancePtr, SetupData);
break;
case XUSBPS_CMD_VENDREQ:
#ifdef CH9_DEBUG
printf("vendor request %x\n", SetupData->bRequest);
#endif
Status = XUsbPs_HandleVendorReq(InstancePtr, SetupData);
break;
default:
/* Stall on Endpoint 0 */
#ifdef CH9_DEBUG
printf("unknown class req, stall 0 in out\n");
#endif
XUsbPs_EpStall(InstancePtr, 0, XUSBPS_EP_DIRECTION_IN |
XUSBPS_EP_DIRECTION_OUT);
break;
}
return Status;
}
/*****************************************************************************/
/**
* This function handles a standard device request.
*
* @param InstancePtr is a pointer to XUsbPs instance of the controller.
* @param SetupData is a pointer to the data structure containing the
* setup request.
*
* @return None.
*
* @note None.
*
******************************************************************************/
static void XUsbPs_StdDevReq(XUsbPs *InstancePtr,
XUsbPs_SetupData *SetupData)
{
int Status;
int Error = 0;
XUsbPs_Local *UsbLocalPtr;
int ReplyLen;
static u8 Reply[XUSBPS_REQ_REPLY_LEN] ALIGNMENT_CACHELINE;
/* Check that the requested reply length is not bigger than our reply
* buffer. This should never happen...
*/
if (SetupData->wLength > XUSBPS_REQ_REPLY_LEN) {
return;
}
UsbLocalPtr = (XUsbPs_Local *) InstancePtr->UserDataPtr;
#ifdef CH9_DEBUG
printf("std dev req %d\n", SetupData->bRequest);
#endif
switch (SetupData->bRequest) {
case XUSBPS_REQ_GET_STATUS:
switch(SetupData->bmRequestType & XUSBPS_STATUS_MASK) {
case XUSBPS_STATUS_DEVICE:
/* It seems we do not have to worry about zeroing out the rest
* of the reply buffer even though we are only using the first
* two bytes.
*/
*((u16 *) &Reply[0]) = 0x0100; /* Self powered */
break;
case XUSBPS_STATUS_INTERFACE:
*((u16 *) &Reply[0]) = 0x0;
break;
case XUSBPS_STATUS_ENDPOINT:
{
u32 Status;
int EpNum = SetupData->wIndex;
Status = XUsbPs_ReadReg(InstancePtr->Config.BaseAddress,
XUSBPS_EPCRn_OFFSET(EpNum & 0xF));
if(EpNum & 0x80) { /* In EP */
if(Status & XUSBPS_EPCR_TXS_MASK) {
*((u16 *) &Reply[0]) = 0x0100;
}else {
*((u16 *) &Reply[0]) = 0x0000;
}
} else { /* Out EP */
if(Status & XUSBPS_EPCR_RXS_MASK) {
*((u16 *) &Reply[0]) = 0x0100;
}else {
*((u16 *) &Reply[0]) = 0x0000;
}
}
break;
}
default:
;
#ifdef CH9_DEBUG
printf("unknown request for status %x\n", SetupData->bmRequestType);
#endif
}
XUsbPs_EpBufferSend(InstancePtr, 0, Reply, SetupData->wLength);
break;
case XUSBPS_REQ_SET_ADDRESS:
/* With bit 24 set the address value is held in a shadow
* register until the status phase is acked. At which point it
* address value is written into the address register.
*/
XUsbPs_SetDeviceAddress(InstancePtr, SetupData->wValue);
#ifdef CH9_DEBUG
printf("Set address %d\n", SetupData->wValue);
#endif
/* There is no data phase so ack the transaction by sending a
* zero length packet.
*/
XUsbPs_EpBufferSend(InstancePtr, 0, NULL, 0);
break;
case XUSBPS_REQ_GET_INTERFACE:
#ifdef CH9_DEBUG
printf("Get interface %d/%d/%d\n",
SetupData->wIndex, SetupData->wLength,
InstancePtr->CurrentAltSetting);
#endif
Response = (u8)InstancePtr->CurrentAltSetting;
/* Ack the host */
XUsbPs_EpBufferSend(InstancePtr, 0, &Response, 1);
break;
case XUSBPS_REQ_GET_DESCRIPTOR:
#ifdef CH9_DEBUG
printf("Get desc %x/%d\n", (SetupData->wValue >> 8) & 0xff,
SetupData->wLength);
#endif
/* Get descriptor type. */
switch ((SetupData->wValue >> 8) & 0xff) {
case XUSBPS_TYPE_DEVICE_DESC:
case XUSBPS_TYPE_DEVICE_QUALIFIER:
/* Set up the reply buffer with the device descriptor
* data.
*/
ReplyLen = XUsbPs_Ch9SetupDevDescReply(
Reply, XUSBPS_REQ_REPLY_LEN);
ReplyLen = ReplyLen > SetupData->wLength ?
SetupData->wLength : ReplyLen;
if(((SetupData->wValue >> 8) & 0xff) ==
XUSBPS_TYPE_DEVICE_QUALIFIER) {
Reply[0] = (u8)ReplyLen;
Reply[1] = (u8)0x6;
Reply[2] = (u8)0x0;
Reply[3] = (u8)0x2;
Reply[4] = (u8)0xFF;
Reply[5] = (u8)0x00;
Reply[6] = (u8)0x0;
Reply[7] = (u8)0x10;
Reply[8] = (u8)0;
Reply[9] = (u8)0x0;
}
Status = XUsbPs_EpBufferSend(InstancePtr, 0,
Reply, ReplyLen);
if (XST_SUCCESS != Status) {
/* Failure case needs to be handled */
for (;;);
}
break;
case XUSBPS_TYPE_CONFIG_DESC:
/* Set up the reply buffer with the configuration
* descriptor data.
*/
ReplyLen = XUsbPs_Ch9SetupCfgDescReply(
Reply, XUSBPS_REQ_REPLY_LEN);
#ifdef CH9_DEBUG
printf("get config %d/%d\n", ReplyLen, SetupData->wLength);
#endif
ReplyLen = ReplyLen > SetupData->wLength ?
SetupData->wLength : ReplyLen;
Status = XUsbPs_EpBufferSend(InstancePtr, 0,
Reply, ReplyLen);
if (XST_SUCCESS != Status) {
/* Failure case needs to be handled */
for (;;);
}
break;
case XUSBPS_TYPE_STRING_DESC:
/* Set up the reply buffer with the string descriptor
* data.
*/
ReplyLen = XUsbPs_Ch9SetupStrDescReply(
Reply, XUSBPS_REQ_REPLY_LEN,
SetupData->wValue & 0xFF);
ReplyLen = ReplyLen > SetupData->wLength ?
SetupData->wLength : ReplyLen;
Status = XUsbPs_EpBufferSend(InstancePtr, 0,
Reply, ReplyLen);
if (XST_SUCCESS != Status) {
/* Failure case needs to be handled */
for (;;);
}
break;
#ifdef MOUSE_SIMULATION
case XUSBPS_TYPE_HID_DESC:
/* Set up the reply buffer with the HID descriptor
* data.
*/
ReplyLen = XUsbPs_Ch9SetupHidDescReply(
Reply, XUSBPS_REQ_REPLY_LEN);
ReplyLen = ReplyLen > SetupData->wLength ?
SetupData->wLength : ReplyLen;
Status = XUsbPs_EpBufferSend(InstancePtr, 0,
Reply, ReplyLen);
if (XST_SUCCESS != Status) {
/* Failure case needs to be handled */
for (;;);
}
break;
case XUSBPS_TYPE_REPORT_DESC:
/* Set up the reply buffer with the report descriptor
* data.
*/
ReplyLen = XUsbPs_Ch9SetupReportDescReply(
Reply, XUSBPS_REQ_REPLY_LEN);
#ifdef CH9_DEBUG
printf("report desc len %d\n", ReplyLen);
#endif
ReplyLen = ReplyLen > SetupData->wLength ?
SetupData->wLength : ReplyLen;
Status = XUsbPs_EpBufferSend(InstancePtr, 0,
Reply, ReplyLen);
if (XST_SUCCESS != Status) {
/* Failure case needs to be handled */
for (;;);
}
break;
#endif /* MOUSE_SIMULATION */
default:
Error = 1;
break;
}
break;
case XUSBPS_REQ_SET_CONFIGURATION:
/*
* Only allow configuration index 1 as this is the only one we
* have.
*/
if ((SetupData->wValue & 0xff) != 1) {
Error = 1;
break;
}
UsbLocalPtr->CurrentConfig = SetupData->wValue & 0xff;
/* Call the application specific configuration function to
* apply the configuration with the given configuration index.
*/
XUsbPs_SetConfiguration(InstancePtr,
UsbLocalPtr->CurrentConfig);
/* There is no data phase so ack the transaction by sending a
* zero length packet.
*/
XUsbPs_EpBufferSend(InstancePtr, 0, NULL, 0);
break;
case XUSBPS_REQ_GET_CONFIGURATION:
Response = (u8)InstancePtr->CurrentAltSetting;
XUsbPs_EpBufferSend(InstancePtr, 0,
&Response, 1);
break;
case XUSBPS_REQ_CLEAR_FEATURE:
switch(SetupData->bmRequestType & XUSBPS_STATUS_MASK) {
case XUSBPS_STATUS_ENDPOINT:
if(SetupData->wValue == XUSBPS_ENDPOINT_HALT) {
int EpNum = SetupData->wIndex;
if(EpNum & 0x80) { /* In ep */
XUsbPs_ClrBits(InstancePtr,
XUSBPS_EPCRn_OFFSET(EpNum & 0xF),
XUSBPS_EPCR_TXS_MASK);
}else { /* Out ep */
XUsbPs_ClrBits(InstancePtr,
XUSBPS_EPCRn_OFFSET(EpNum),
XUSBPS_EPCR_RXS_MASK);
}
}
/* Ack the host ? */
XUsbPs_EpBufferSend(InstancePtr, 0, NULL, 0);
break;
default:
Error = 1;
break;
}
break;
case XUSBPS_REQ_SET_FEATURE:
switch(SetupData->bmRequestType & XUSBPS_STATUS_MASK) {
case XUSBPS_STATUS_ENDPOINT:
if(SetupData->wValue == XUSBPS_ENDPOINT_HALT) {
int EpNum = SetupData->wIndex;
if(EpNum & 0x80) { /* In ep */
XUsbPs_SetBits(InstancePtr,
XUSBPS_EPCRn_OFFSET(EpNum & 0xF),
XUSBPS_EPCR_TXS_MASK);
}else { /* Out ep */
XUsbPs_SetBits(InstancePtr,
XUSBPS_EPCRn_OFFSET(EpNum),
XUSBPS_EPCR_RXS_MASK);
}
}
/* Ack the host ? */
XUsbPs_EpBufferSend(InstancePtr, 0, NULL, 0);
break;
case XUSBPS_STATUS_DEVICE:
if (SetupData->wValue == XUSBPS_TEST_MODE) {
int TestSel = (SetupData->wIndex >> 8) & 0xFF;
/* Ack the host, the transition must happen
after status stage and < 3ms */
XUsbPs_EpBufferSend(InstancePtr, 0, NULL, 0);
usleep(1000);
switch (TestSel) {
case XUSBPS_TEST_J:
case XUSBPS_TEST_K:
case XUSBPS_TEST_SE0_NAK:
case XUSBPS_TEST_PACKET:
case XUSBPS_TEST_FORCE_ENABLE:
XUsbPs_SetBits(InstancePtr, \
XUSBPS_PORTSCR1_OFFSET, \
TestSel << 16);
break;
default:
/* Unsupported test selector */
break;
}
break;
}
default:
Error = 1;
break;
}
break;
/* For set interface, check the alt setting host wants */
case XUSBPS_REQ_SET_INTERFACE:
#ifdef CH9_DEBUG
printf("set interface %d/%d\n", SetupData->wValue, SetupData->wIndex);
#endif
/* Not supported */
/* XUsbPs_SetInterface(InstancePtr, SetupData->wValue, SetupData->wIndex); */
/* Ack the host after device finishes the operation */
Error = XUsbPs_EpBufferSend(InstancePtr, 0, NULL, 0);
if(Error) {
#ifdef CH9_DEBUG
printf("EpBufferSend failed %d\n", Error);
#endif
}
break;
default:
Error = 1;
break;
}
/* Set the send stall bit if there was an error */
if (Error) {
#ifdef CH9_DEBUG
printf("std dev req %d/%d error, stall 0 in out\n",
SetupData->bRequest, (SetupData->wValue >> 8) & 0xff);
#endif
XUsbPs_EpStall(InstancePtr, 0, XUSBPS_EP_DIRECTION_IN |
XUSBPS_EP_DIRECTION_OUT);
}
}
/*****************************************************************************/
/**
* This function handles a vendor request.
*
* @param InstancePtr is a pointer to XUsbPs instance of the controller.
* @param SetupData is a pointer to the data structure containing the
* setup request.
*
* @return
* - XST_SUCCESS if successful.
* - XST_FAILURE if an Error occured.
*
* @note
* This function is a template to handle vendor request for control
* IN and control OUT endpoints. The control OUT endpoint can
* receive only 64 bytes of data per dTD. For receiving more than
* 64 bytes of vendor data on control OUT endpoint, change the
* buffer size of the control OUT endpoint. Otherwise the results
* are unexpected.
*
******************************************************************************/
static int XUsbPs_HandleVendorReq(XUsbPs *InstancePtr,
XUsbPs_SetupData *SetupData)
{
u8 *BufferPtr;
u32 BufferLen;
u32 Handle;
u32 Reg;
const static u8 Reply[8] ALIGNMENT_CACHELINE =
{0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17};
u8 EpNum = 0;
int Status;
int Direction;
int Timeout;
/* Check the direction, USB 2.0 section 9.3 */
Direction = SetupData->bmRequestType & (1 << 7);
if (!Direction) {
/* Control OUT vendor request */
if (SetupData->wLength > 0) {
/* Re-Prime the endpoint to receive Setup DATA */
XUsbPs_EpPrime(InstancePtr, 0, XUSBPS_EP_DIRECTION_OUT);
/* Check whether EP prime is successful or not */
Timeout = XUSBPS_TIMEOUT_COUNTER;
do {
Reg = XUsbPs_ReadReg(InstancePtr->Config.BaseAddress,
XUSBPS_EPPRIME_OFFSET);
} while(((Reg & (1 << EpNum)) == 1) && --Timeout);
if (!Timeout) {
return XST_FAILURE;
}
/* Get the Setup DATA, don't wait for the interrupt */
Timeout = XUSBPS_TIMEOUT_COUNTER;
do {
Status = XUsbPs_EpBufferReceive(InstancePtr,
EpNum, &BufferPtr, &BufferLen, &Handle);
} while((Status != XST_SUCCESS) && --Timeout);
if (!Timeout) {
return XST_FAILURE;
}
Xil_DCacheInvalidateRange((unsigned int)BufferPtr,
BufferLen);
#ifdef CH9_DEBUG
int Len;
xil_printf("Vendor data:\r\n");
for(Len = 0;Len < BufferLen;Len++)
xil_printf("%02x ",BufferPtr[Len]);
#endif
if (Status == XST_SUCCESS) {
/* Zero length ACK */
Status = XUsbPs_EpBufferSend(InstancePtr, EpNum,
NULL, 0);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
}
}
} else {
if (SetupData->wLength > 0) {
/* Control IN vendor request */
Status = XUsbPs_EpBufferSend(InstancePtr, EpNum, Reply,
SetupData->wLength);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
}
}
return XST_SUCCESS;
}