blob: 74d6adb83a5e04fed50e66a626787fbdeeae6a8c [file] [log] [blame]
/* ==========================================================================
* $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd.c $
* $Revision: #101 $
* $Date: 2012/08/10 $
* $Change: 2047372 $
*
* Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
* "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
* otherwise expressly agreed to in writing between Synopsys and you.
*
* The Software IS NOT an item of Licensed Software or Licensed Product under
* any End User Software License Agreement or Agreement for Licensed Product
* with Synopsys or any supplement thereto. You are permitted to use and
* redistribute this Software in source and binary forms, with or without
* modification, provided that redistributions of source code must retain this
* notice. You may not view, use, disclose, copy or distribute this file or
* any information contained herein except pursuant to this license grant from
* Synopsys. If you do not agree with this notice, including the disclaimer
* below, then you are not authorized to use the Software.
*
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
* ========================================================================== */
#ifndef DWC_HOST_ONLY
/** @file
* This file implements PCD Core. All code in this file is portable and doesn't
* use any OS specific functions.
* PCD Core provides Interface, defined in <code><dwc_otg_pcd_if.h></code>
* header file, which can be used to implement OS specific PCD interface.
*
* An important function of the PCD is managing interrupts generated
* by the DWC_otg controller. The implementation of the DWC_otg device
* mode interrupt service routines is in dwc_otg_pcd_intr.c.
*
* @todo Add Device Mode test modes (Test J mode, Test K mode, etc).
* @todo Does it work when the request size is greater than DEPTSIZ
* transfer size
*
*/
#include "global.h"
#include "dwc_otg_pcd.h"
__align(4) const dwc_device_descriptor_t device_desc =
{
sizeof(dwc_device_descriptor_t),
DEVICE_DESCRIPTOR,
0x0200, // usb 2.0 //usb 1.1
0x00,
0x00,
0x00,
CONTROL_64, // ×î´ó°ü8×Ö½Ú
USB_VENDOR_ID,
USB_PRODUCT_ID,
PRODUCT_RELEASE_NUMBER,
0x01, // manufacturer descriptionË÷ÒýºÅ
0x02, // product descriptionË÷ÒýºÅ
0x03, // serial number descriptionË÷ÒýºÅ
0x01 // ÅäÖÃÊý
};
__align(4) const dwc_dev_qual_descriptor_t dev_qual_desc =
{
sizeof(dwc_dev_qual_descriptor_t),
0x06,
0x0200, // usb 2.0
VERDOR_SPECIFIC,
0x00,
0x00,
64,
0x01, // ÅäÖÃÊý
0x0
};
__align(4) const dwc_langid_descriptor_t tLanguage=
{
STRING_DESCRIPTOR_SIZE(1),
STRING_DESCRIPTOR,
LANGID_US_ENGLISH
};
__align(4) const dwc_string_descriptor_t tManufacture=
{
STRING_DESCRIPTOR_SIZE(11),
STRING_DESCRIPTOR,
UNICODE('Z'), UNICODE('T'), UNICODE('E'), UNICODE(' '), UNICODE('C'),
UNICODE('o'), UNICODE(','), UNICODE('L'), UNICODE('t'), UNICODE('d'),
UNICODE('.'),
};
__align(4) const dwc_string_descriptor_t tProduct=
{
STRING_DESCRIPTOR_SIZE(14),
STRING_DESCRIPTOR,
UNICODE('Z'), UNICODE('T'), UNICODE('E'), UNICODE(' '), UNICODE('B'),
UNICODE('o'), UNICODE('o'), UNICODE('t'), UNICODE('L'), UNICODE('o'),
UNICODE('a'), UNICODE('d'), UNICODE('e'), UNICODE('r')
};
__align(4) const dwc_string_descriptor_t tSN=
{
STRING_DESCRIPTOR_SIZE(16),
STRING_DESCRIPTOR,
UNICODE('z'), UNICODE('t'), UNICODE('e'), UNICODE('&'), UNICODE('u'),
UNICODE('s'), UNICODE('b'), UNICODE('B'), UNICODE('o'), UNICODE('o'),
UNICODE('t'), UNICODE('l'), UNICODE('o'), UNICODE('d'), UNICODE('e'),
UNICODE('r')
};
__align(4) const dwc_string_descriptor_t tIfc0Name=
{
STRING_DESCRIPTOR_SIZE(9),
STRING_DESCRIPTOR,
UNICODE('B'), UNICODE('o'), UNICODE('o'), UNICODE('t'), UNICODE('l'),
UNICODE('o'), UNICODE('d'), UNICODE('e'), UNICODE('r')
};
__align(4) const dwc_string_descriptor_t tIfc1Name=
{
STRING_DESCRIPTOR_SIZE(6),
STRING_DESCRIPTOR,
UNICODE('S'), UNICODE('e'), UNICODE('r'), UNICODE('i'), UNICODE('a'),
UNICODE('l')
};
__align(4) const dwc_string_descriptor_t * const pStrDescIdx[]=
{
(dwc_string_descriptor_t *)(&tLanguage),
(dwc_string_descriptor_t *)&tManufacture,
(dwc_string_descriptor_t *)&tProduct,
(dwc_string_descriptor_t *)&tSN,
(dwc_string_descriptor_t *)&tIfc0Name,
(dwc_string_descriptor_t *)&tIfc1Name,
};
static void do_get_descriptor(dwc_otg_pcd_t * pcd,uint32_t *buff,uint32_t len)
{
dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
pcd->ep0_pending = 1;
ep0->dwc_ep.start_xfer_buff =(uint8_t*) buff;
ep0->dwc_ep.xfer_buff =(uint8_t*)buff;
ep0->dwc_ep.xfer_len = len;
ep0->dwc_ep.xfer_count = 0;
ep0->dwc_ep.total_len = ep0->dwc_ep.xfer_len;
dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), &ep0->dwc_ep);
}
extern void ep0_do_stall(dwc_otg_pcd_t * pcd, const int err_val);
int dwc_setup(dwc_otg_pcd_t * pcd, usb_device_request_t * ctrl)
{
uint8_t byIdx;
uint32_t len = 0;
uint16_t value;
byIdx = (uint8_t)(ctrl->wValue &0xff);
value = ctrl->wValue>>8;
if( USB_DT_DEVICE ==value )
{
len = MIN( sizeof(dwc_device_descriptor_t), ctrl->wLength);
do_get_descriptor(pcd,(uint32_t*)&device_desc,len);
}
else if( USB_DT_CONFIG==value )
{
len = MIN( sizeof(dwc_config_all_t), ctrl->wLength);
do_get_descriptor(pcd,(uint32_t*)&g_config_desc,len);
}
else if( USB_DT_STRING ==value)
{
len = MIN(((dwc_string_descriptor_t*)(pStrDescIdx[byIdx]))->bLength, ctrl->wLength);
do_get_descriptor(pcd,(uint32_t*)pStrDescIdx[byIdx],len);
}
else if( USB_DT_INTERFACE == value)
{
len = MIN(((dwc_string_descriptor_t*)(pStrDescIdx[byIdx]))->bLength, ctrl->wLength);
do_get_descriptor(pcd,(uint32_t*)pStrDescIdx[byIdx],len);
}
else if( ENDPOINT_DESCRIPTOR == value)
{
len = MIN(((dwc_string_descriptor_t*)(pStrDescIdx[byIdx]))->bLength, ctrl->wLength);
do_get_descriptor(pcd,(uint32_t*)pStrDescIdx[byIdx],len);
}
else if( USB_DT_DEVICE_QUALIFIER ==value)
{
len = MIN(sizeof(dwc_dev_qual_descriptor_t),ctrl->wLength);
do_get_descriptor(pcd,(uint32_t*)&dev_qual_desc,len);
}
else
{
ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
}
return 0;
}
static void dwc_otg_pcd_init_ep(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * pcd_ep,
uint32_t is_in, uint32_t ep_num)
{
/* Init EP structure */
pcd_ep->desc = 0;
pcd_ep->pcd = pcd;
pcd_ep->stopped = 1;
pcd_ep->queue_sof = 0;
/* Init DWC ep structure */
pcd_ep->dwc_ep.is_in = is_in;
pcd_ep->dwc_ep.num = ep_num;
pcd_ep->dwc_ep.active = 0;
pcd_ep->dwc_ep.tx_fifo_num = 0;
/* Control until ep is actvated */
pcd_ep->dwc_ep.type = DWC_OTG_EP_TYPE_BULK;
pcd_ep->dwc_ep.maxpacket = 512;
pcd_ep->dwc_ep.maxxfer = 65536;
pcd_ep->dwc_ep.start_xfer_buff = 0;
pcd_ep->dwc_ep.xfer_buff = 0;
pcd_ep->dwc_ep.xfer_len = 0;
pcd_ep->dwc_ep.xfer_count = 0;
pcd_ep->dwc_ep.sent_zlp = 0;
pcd_ep->dwc_ep.total_len = 0;
}
/**
* Initialize ep's
*/
static void dwc_otg_pcd_reinit(dwc_otg_pcd_t * pcd)
{
int i;
uint32_t hwcfg1;
dwc_otg_pcd_ep_t *ep;
int in_ep_cntr, out_ep_cntr;
uint32_t num_in_eps = (GET_CORE_IF(pcd))->dev_if->num_in_eps;
uint32_t num_out_eps = (GET_CORE_IF(pcd))->dev_if->num_out_eps;
/**
* Initialize the EP0 structure.
*/
pcd->ep0.dwc_ep.pPara = (void*)(&global.g_in_pPara[1]);
ep = &pcd->ep0;
dwc_otg_pcd_init_ep(pcd, ep, 0, 0);
in_ep_cntr = 0;
hwcfg1 = (GET_CORE_IF(pcd))->hwcfg1.d32 >> 3;
for (i = 1; in_ep_cntr < num_in_eps; i++)
{
if ((hwcfg1 & 0x1) == 0)
{
pcd->in_ep[in_ep_cntr].dwc_ep.pPara = (void*)(&global.g_in_pPara[in_ep_cntr]);
ep = &pcd->in_ep[in_ep_cntr];
in_ep_cntr++;
/**
* @todo NGS: Add direction to EP, based on contents
* of HWCFG1. Need a copy of HWCFG1 in pcd structure?
* sprintf(";r
*/
dwc_otg_pcd_init_ep(pcd, ep, 1 /* IN */ , i);
}
hwcfg1 >>= 2;
}
out_ep_cntr = 0;
hwcfg1 = (GET_CORE_IF(pcd))->hwcfg1.d32 >> 2;
for (i = 1; out_ep_cntr < num_out_eps; i++)
{
if ((hwcfg1 & 0x1) == 0)
{
pcd->out_ep[out_ep_cntr].dwc_ep.pPara = (void*)(&global.g_out_pPara[out_ep_cntr]);
ep = &pcd->out_ep[out_ep_cntr];
out_ep_cntr++;
/**
* @todo NGS: Add direction to EP, based on contents
* of HWCFG1. Need a copy of HWCFG1 in pcd structure?
* sprintf(";r
*/
dwc_otg_pcd_init_ep(pcd, ep, 0 /* OUT */ , i);
}
hwcfg1 >>= 2;
}
if(NEED_ENUM == global.g_enum)
{
pcd->ep0state = EP0_DISCONNECT;
}
else
{
pcd->ep0state = EP0_IDLE;
}
pcd->ep0.dwc_ep.maxpacket = MAX_EP0_SIZE;
pcd->ep0.dwc_ep.type = 0;
}
/**
* This function initialized the PCD portion of the driver.
*
*/
dwc_otg_pcd_t *dwc_otg_pcd_init(dwc_otg_core_if_t * core_if)
{
dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *)&global.g_dwc_otg_pcd_tp;
int i;
uint8_t* pt_dwc_otg_pcd_t = (uint8_t*)&global.g_dwc_otg_pcd_tp;
for(i = 0;i<sizeof(dwc_otg_pcd_t);i++)
{
pt_dwc_otg_pcd_t[i] = 0;
}
pcd->core_if = core_if;
pcd->setup_pkt = global.g_u_setup_pkt;
pcd->status_buf = &global.g_status_buf;
dwc_otg_pcd_reinit(pcd);
return pcd;
}
/******************************************************************************/
#endif /* DWC_HOST_ONLY */