Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Branch: android-samsun…
Fetching contributors…

Cannot retrieve contributors at this time

709 lines (596 sloc) 19.327 kB
/****************************************************************************
* (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
*
* @file s3c-otg-hcdi-hcd.c
* @brief implementation of structure hc_drive \n
* @version
* -# Jun 11,2008 v1.0 by SeungSoo Yang (ss1.yang@samsung.com) \n
* : Creating the initial version of this code \n
* -# Jul 15,2008 v1.2 by SeungSoo Yang (ss1.yang@samsung.com) \n
* : Optimizing for performance \n
* -# Aug 18,2008 v1.3 by SeungSoo Yang (ss1.yang@samsung.com) \n
* : Modifying for successful rmmod & disconnecting \n
* @see None
****************************************************************************/
/****************************************************************************
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
****************************************************************************/
#include "s3c-otg-hcdi-hcd.h"
/**
* otg_hcd_init_modules(struct sec_otghost *otghost)
*
* @brief call other modules' init functions
*
* @return PASS : If success \n
* FAIL : If fail \n
*/
int otg_hcd_init_modules(struct sec_otghost *otghost)
{
unsigned long spin_lock_flag = 0;
otg_dbg(OTG_DBG_OTGHCDI_HCD, "otg_hcd_init_modules\n");
spin_lock_init(&otghost->lock);
spin_lock_irq_save_otg(&otghost->lock, spin_lock_flag);
init_transfer();
init_scheduler();
oci_init(otghost);
spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
return USB_ERR_SUCCESS;
};
/**
* void otg_hcd_deinit_modules(struct sec_otghost *otghost)
*
* @brief call other modules' de-init functions
*
* @return PASS : If success \n
* FAIL : If fail \n
*/
void otg_hcd_deinit_modules(struct sec_otghost *otghost)
{
unsigned long spin_lock_flag = 0;
otg_dbg(OTG_DBG_OTGHCDI_HCD, "otg_hcd_deinit_modules \n");
spin_lock_irq_save_otg(&otghost->lock, spin_lock_flag);
deinit_transfer(otghost);
spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
}
/**
* irqreturn_t (*s5pc110_otghcd_irq) (struct usb_hcd *hcd)
*
* @brief interrupt handler of otg irq
*
* @param [in] hcd : pointer of usb_hcd
*
* @return IRQ_HANDLED \n
*/
irqreturn_t s5pc110_otghcd_irq(struct usb_hcd *hcd)
{
struct sec_otghost *otghost = hcd_to_sec_otghost(hcd);
otg_dbg(OTG_DBG_OTGHCDI_HCD, "s5pc110_otghcd_irq \n");
spin_lock_otg(&otghost->lock);
otg_handle_interrupt(hcd);
spin_unlock_otg(&otghost->lock);
return IRQ_HANDLED;
}
/**
* int s5pc110_otghcd_start(struct usb_hcd *hcd)
*
* @brief initialize and start otg hcd
*
* @param [in] usb_hcd_p : pointer of usb_hcd
*
* @return USB_ERR_SUCCESS : If success \n
* USB_ERR_FAIL : If call fail \n
*/
int s5pc110_otghcd_start(struct usb_hcd *usb_hcd_p)
{
struct usb_bus *usb_bus_p;
struct sec_otghost *otghost = hcd_to_sec_otghost(usb_hcd_p);
otg_dbg(OTG_DBG_OTGHCDI_HCD, "s5pc110_otghcd_start \n");
usb_bus_p = hcd_to_bus(usb_hcd_p);
/* Initialize and connect root hub if one is not already attached */
if (usb_bus_p->root_hub) {
otg_dbg(OTG_DBG_OTGHCDI_HCD, "OTG HCD Has Root Hub\n");
/* Inform the HUB driver to resume. */
otg_usbcore_resume_roothub();
} else {
otg_err(OTG_DBG_OTGHCDI_HCD,
"OTG HCD Does Not Have Root Hub\n");
return USB_ERR_FAIL;
}
set_bit(HCD_FLAG_POLL_RH,&usb_hcd_p->flags);
usb_hcd_p->uses_new_polling = 1;
/* init bus state before enable irq */
usb_hcd_p->state = HC_STATE_RUNNING;
oci_start(otghost); /* enable irq */
return USB_ERR_SUCCESS;
}
/**
* void s5pc110_otghcd_stop(struct usb_hcd *hcd)
*
* @brief deinitialize and stop otg hcd
*
* @param [in] hcd : pointer of usb_hcd
*
*/
void s5pc110_otghcd_stop(struct usb_hcd *hcd)
{
unsigned long spin_lock_flag = 0;
struct sec_otghost *otghost = hcd_to_sec_otghost(hcd);
otg_dbg(OTG_DBG_OTGHCDI_HCD, "s5pc110_otghcd_stop \n");
otg_hcd_deinit_modules(otghost);
spin_lock_irq_save_otg(&otghost->lock, spin_lock_flag);
oci_stop(otghost);
root_hub_feature(hcd, 0, ClearPortFeature, USB_PORT_FEAT_POWER, NULL);
spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
}
/**
* void s5pc110_otghcd_shutdown(struct usb_hcd *hcd)
*
* @brief shutdown otg hcd
*
* @param [in] usb_hcd_p : pointer of usb_hcd
*
*/
void s5pc110_otghcd_shutdown(struct usb_hcd *usb_hcd_p)
{
unsigned long spin_lock_flag = 0;
struct sec_otghost *otghost = hcd_to_sec_otghost(usb_hcd_p);
otg_dbg(OTG_DBG_OTGHCDI_HCD, "s5pc110_otghcd_shutdown \n");
otg_hcd_deinit_modules(otghost);
spin_lock_irq_save_otg(&otghost->lock, spin_lock_flag);
oci_stop(otghost);
root_hub_feature(usb_hcd_p, 0, ClearPortFeature, USB_PORT_FEAT_POWER, NULL);
spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
free_irq(IRQ_OTG, usb_hcd_p);
usb_hcd_p->state = HC_STATE_HALT;
otg_usbcore_hc_died();
}
/**
* int s5pc110_otghcd_get_frame_number(struct usb_hcd *hcd)
*
* @brief get currnet frame number
*
* @param [in] hcd : pointer of usb_hcd
*
* @return ret : frame number \n
*/
int s5pc110_otghcd_get_frame_number(struct usb_hcd *hcd)
{
int ret = 0;
unsigned long spin_lock_flag = 0;
struct sec_otghost *otghost = hcd_to_sec_otghost(hcd);
otg_dbg(OTG_DBG_OTGHCDI_HCD, "s5pc110_otghcd_get_frame_number \n");
spin_lock_irq_save_otg(&otghost->lock, spin_lock_flag);
ret = oci_get_frame_num();
spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
return ret;
}
/**
* int s5pc110_otghcd_urb_enqueue()
*
* @brief enqueue a urb to otg hcd
*
* @param [in] hcd : pointer of usb_hcd
* [in] ep : pointer of usb_host_endpoint
* [in] urb : pointer of urb
* [in] mem_flags : type of gfp_t
*
* @return USB_ERR_SUCCESS : If success \n
* USB_ERR_FAIL : If call fail \n
*/
int s5pc110_otghcd_urb_enqueue (struct usb_hcd *hcd,
struct urb *urb,
gfp_t mem_flags)
{
int ret_val = 0;
u32 trans_flag = 0;
u32 return_td_addr = 0;
u8 dev_speed, ed_type = 0, additional_multi_count;
u16 max_packet_size;
u8 dev_addr = 0;
u8 ep_num = 0;
bool f_is_ep_in = true;
u8 interval = 0;
u32 sched_frame = 0;
u8 hub_addr = 0;
u8 hub_port = 0;
bool f_is_do_split = false;
ed_t *target_ed = NULL;
isoch_packet_desc_t *new_isoch_packet_desc = NULL;
unsigned long spin_lock_flag = 0;
struct sec_otghost *otghost = hcd_to_sec_otghost(hcd);
if (!otghost->port_flag.b.port_connect_status) {
printk(KERN_ERR"%s %d\n", __func__, __LINE__);
return USB_ERR_NOIO;
}
spin_lock_irq_save_otg(&otghost->lock, spin_lock_flag);
otg_dbg(OTG_DBG_OTGHCDI_HCD, "s5pc110_otghcd_urb_enqueue \n");
/* check ep has ed_t or not */
if(!(urb->ep->hcpriv)) {
/* for getting dev_speed */
switch (urb->dev->speed) {
case USB_SPEED_HIGH :
otg_dbg(OTG_DBG_OTGHCDI_HCD, "HS_OTG \n");
dev_speed = HIGH_SPEED_OTG;
break;
case USB_SPEED_FULL :
otg_dbg(OTG_DBG_OTGHCDI_HCD, "FS_OTG \n");
dev_speed = FULL_SPEED_OTG;
break;
case USB_SPEED_LOW :
otg_dbg(OTG_DBG_OTGHCDI_HCD, "LS_OTG \n");
dev_speed = LOW_SPEED_OTG;
break;
default:
otg_err(OTG_DBG_OTGHCDI_HCD,
"unKnown Device Speed \n");
spin_unlock_irq_save_otg(&otghost->lock,
spin_lock_flag);
return USB_ERR_FAIL;
}
/* for getting ed_type */
switch (usb_pipetype(urb->pipe)) {
case PIPE_BULK :
otg_dbg(OTG_DBG_OTGHCDI_HCD, "bulk transfer \n");
ed_type = BULK_TRANSFER;
break;
case PIPE_INTERRUPT :
otg_dbg(OTG_DBG_OTGHCDI_HCD, "interrupt transfer \n");
ed_type = INT_TRANSFER;
break;
case PIPE_CONTROL :
otg_dbg(OTG_DBG_OTGHCDI_HCD, "control transfer \n");
ed_type = CONTROL_TRANSFER;
break;
case PIPE_ISOCHRONOUS :
otg_dbg(OTG_DBG_OTGHCDI_HCD, "isochronous transfer \n");
ed_type = ISOCH_TRANSFER;
break;
default:
otg_err(OTG_DBG_OTGHCDI_HCD, "unKnown ep type \n");
spin_unlock_irq_save_otg(&otghost->lock,
spin_lock_flag);
return USB_ERR_FAIL;
}
max_packet_size = usb_maxpacket(urb->dev, urb->pipe,
!(usb_pipein(urb->pipe)));
additional_multi_count = ((max_packet_size) >> 11) & 0x03;
dev_addr = usb_pipedevice(urb->pipe);
ep_num = usb_pipeendpoint(urb->pipe);
f_is_ep_in = usb_pipein(urb->pipe) ? true : false;
interval = (u8)(urb->interval);
sched_frame = (u8)(urb->start_frame);
/* check */
if(urb->dev->tt == NULL) {
otg_dbg(OTG_DBG_OTGHCDI_HCD, "urb->dev->tt == NULL\n");
hub_port = 0; /* u8 hub_port */
hub_addr = 0; /* u8 hub_addr */
}
else {
hub_port = (u8)(urb->dev->ttport);
if (urb->dev->tt->hub) {
if (((dev_speed == FULL_SPEED_OTG) ||
(dev_speed == LOW_SPEED_OTG)) &&
(urb->dev->tt) && (urb->dev->tt->hub->devnum != 1)) {
if (otghost->is_hs) // only allow split transactions in HS mode
f_is_do_split = true;
}
hub_addr = (u8)(urb->dev->tt->hub->devnum);
}
if (urb->dev->tt->multi) {
hub_addr = 0x80;
}
}
otg_dbg(OTG_DBG_OTGHCDI_HCD,
"dev_spped =%d, hub_port=%d, hub_addr=%d\n",
dev_speed, hub_port, hub_addr);
ret_val = create_ed(&target_ed);
if(ret_val != USB_ERR_SUCCESS) {
otg_err(OTG_DBG_OTGHCDI_HCD,
"fail to create_ed() \n");
spin_unlock_irq_save_otg(&otghost->lock,
spin_lock_flag);
return ret_val;
}
ret_val = init_ed( target_ed,
dev_addr,
ep_num,
f_is_ep_in,
dev_speed,
ed_type,
max_packet_size,
additional_multi_count,
interval,
sched_frame,
hub_addr,
hub_port,
f_is_do_split,
(void *)urb->ep);
if(ret_val != USB_ERR_SUCCESS) {
otg_err(OTG_DBG_OTGHCDI_HCD,
"fail to init_ed() :err = %d \n",(int)ret_val);
otg_mem_free(target_ed);
spin_unlock_irq_save_otg(&otghost->lock,
spin_lock_flag);
return USB_ERR_FAIL;
}
urb->ep->hcpriv = (void *)(target_ed);
} /* if(!(ep->hcpriv)) */
else {
dev_addr = usb_pipedevice(urb->pipe);
if(((ed_t *)(urb->ep->hcpriv))->ed_desc.device_addr != dev_addr) {
((ed_t *)urb->ep->hcpriv)->ed_desc.device_addr = dev_addr;
}
}
target_ed = (ed_t *)urb->ep->hcpriv;
if(urb->transfer_flags & URB_SHORT_NOT_OK)
trans_flag += USB_TRANS_FLAG_NOT_SHORT;
if (urb->transfer_flags & URB_ISO_ASAP)
trans_flag += USB_TRANS_FLAG_ISO_ASYNCH;
if(ed_type == ISOCH_TRANSFER) {
otg_err(OTG_DBG_OTGHCDI_HCD, "ISO not yet supported \n");
spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
return USB_ERR_FAIL;
}
if (!HC_IS_RUNNING(hcd->state)) {
otg_err(OTG_DBG_OTGHCDI_HCD, "!HC_IS_RUNNING(hcd->state) \n");
spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
return -USB_ERR_NODEV;
}
/* in case of unlink-during-submit */
if (urb->status != -EINPROGRESS) {
otg_err(OTG_DBG_OTGHCDI_HCD, "urb->status is -EINPROGRESS\n");
urb->hcpriv = NULL;
spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
usb_hcd_giveback_urb(hcd, urb, urb->status);
return USB_ERR_SUCCESS;
}
ret_val = issue_transfer(otghost, target_ed, (void *)NULL, (void *)NULL,
trans_flag,
(usb_pipetype(urb->pipe) == PIPE_CONTROL)?true:false,
(u32)urb->setup_packet, (u32)urb->setup_dma,
(u32)urb->transfer_buffer, (u32)urb->transfer_dma,
(u32)urb->transfer_buffer_length,
(u32)urb->start_frame,(u32)urb->number_of_packets,
new_isoch_packet_desc, (void *)urb, &return_td_addr);
if(ret_val != USB_ERR_SUCCESS) {
otg_err(OTG_DBG_OTGHCDI_HCD, "fail to issue_transfer() \n");
spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
return USB_ERR_FAIL;
}
urb->hcpriv = (void *)return_td_addr;
spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
return USB_ERR_SUCCESS;
}
/**
* int s5pc110_otghcd_urb_dequeue(struct usb_hcd *_hcd, struct urb *_urb )
*
* @brief dequeue a urb to otg
*
* @param [in] _hcd : pointer of usb_hcd
* [in] _urb : pointer of urb
*
* @return USB_ERR_SUCCESS : If success \n
* USB_ERR_FAIL : If call fail \n
*/
int s5pc110_otghcd_urb_dequeue(
struct usb_hcd *_hcd, struct urb *_urb, int status)
{
int ret_val = 0;
struct sec_otghost *otghost = hcd_to_sec_otghost(_hcd);
unsigned long spin_lock_flag = 0;
td_t *cancel_td;
spin_lock_irq_save_otg(&otghost->lock, spin_lock_flag);
otg_dbg(OTG_DBG_OTGHCDI_HCD, "s5pc110_otghcd_urb_dequeue \n");
/* Dequeue should be performed only if endpoint is enabled */
if (_urb->ep->enabled == 0) {
spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
usb_hcd_giveback_urb(_hcd, _urb, status);
return USB_ERR_SUCCESS;
}
//kevinh read this from inside the spinlock
cancel_td = (td_t *)_urb->hcpriv;
if (cancel_td == NULL) {
otg_err(OTG_DBG_OTGHCDI_HCD, "cancel_td is NULL\n");
spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
return USB_ERR_FAIL;
}
otg_dbg(OTG_DBG_OTGHCDI_HCD,
"s5pc110_otghcd_urb_dequeue, status = %d\n", status);
ret_val = usb_hcd_check_unlink_urb(_hcd, _urb, status);
if( (ret_val) && (ret_val != -EIDRM) ) {
otg_dbg(OTG_DBG_OTGHCDI_HCD, "ret_val = %d\n", ret_val);
spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
usb_hcd_giveback_urb(_hcd, _urb, status);
return ret_val;
}
if (!HC_IS_RUNNING(_hcd->state)) {
otg_err(OTG_DBG_OTGHCDI_HCD, "!HC_IS_RUNNING(hcd->state) \n");
spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
otg_usbcore_giveback(cancel_td);
return USB_ERR_SUCCESS;
}
ret_val = cancel_transfer(otghost, cancel_td->parent_ed_p, cancel_td);
if(ret_val != USB_ERR_DEQUEUED && ret_val != USB_ERR_NOELEMENT) {
otg_err(OTG_DBG_OTGHCDI_HCD, "fail to cancel_transfer() \n");
otg_usbcore_giveback(cancel_td);
spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
return USB_ERR_FAIL;
}
otg_usbcore_giveback(cancel_td);
delete_td(otghost, cancel_td);
spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
return USB_ERR_SUCCESS;
}
/**
* void s5pc110_otghcd_endpoint_disable(
* struct usb_hcd *hcd,
* struct usb_host_endpoint *ep)
*
* @brief disable a endpoint
*
* @param [in] hcd : pointer of usb_hcd
* [in] ep : pointer of usb_host_endpoint
*/
void s5pc110_otghcd_endpoint_disable(
struct usb_hcd *hcd,
struct usb_host_endpoint *ep)
{
int ret_val = 0;
unsigned long spin_lock_flag = 0;
struct sec_otghost *otghost = hcd_to_sec_otghost(hcd);
otg_dbg(OTG_DBG_OTGHCDI_HCD, "s5pc110_otghcd_endpoint_disable \n");
if(!((ed_t *)ep->hcpriv))
return;
spin_lock_irq_save_otg(&otghost->lock, spin_lock_flag);
ret_val = delete_ed(otghost, (ed_t *)ep->hcpriv);
spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
if(ret_val != USB_ERR_SUCCESS) {
otg_err(OTG_DBG_OTGHCDI_HCD, "fail to delete_ed() \n");
return ;
}
/* ep->hcpriv = NULL; delete_ed coveres it */
}
/**
* int s5pc110_otghcd_hub_status_data(struct usb_hcd *_hcd, char *_buf)
*
* @brief get status of root hub
*
* @param [in] _hcd : pointer of usb_hcd
* [inout] _buf : pointer of buffer for write a status data
*
* @return ret_val : return port status \n
*/
int s5pc110_otghcd_hub_status_data(struct usb_hcd *_hcd, char *_buf)
{
int ret_val = 0;
unsigned long spin_lock_flag = 0;
struct sec_otghost *otghost = hcd_to_sec_otghost(_hcd);
/* otg_dbg(OTG_DBG_OTGHCDI_HCD, "s5pc110_otghcd_hub_status_data \n"); */
/* if !USB_SUSPEND, root hub timers won't get shut down ... */
if (!HC_IS_RUNNING(_hcd->state)) {
otg_dbg(OTG_DBG_OTGHCDI_HCD,
"_hcd->state is NOT HC_IS_RUNNING \n");
return 0;
}
spin_lock_irq_save_otg(&otghost->lock, spin_lock_flag);
ret_val = get_otg_port_status(_hcd, OTG_PORT_NUMBER, _buf);
spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
return (int)ret_val;
}
/**
* int s5pc110_otghcd_hub_control()
*
* @brief control root hub
*
* @param [in] hcd : pointer of usb_hcd
* [in] typeReq : type of control request
* [in] value : value
* [in] index : index
* [in] buf_p : pointer of urb
* [in] length : type of gfp_t
*
* @return ret_val : return root_hub_feature \n
*/
int
s5pc110_otghcd_hub_control (
struct usb_hcd *hcd,
u16 typeReq,
u16 value,
u16 index,
char* buf_p,
u16 length
)
{
int ret_val = 0;
unsigned long spin_lock_flag = 0;
struct sec_otghost *otghost = hcd_to_sec_otghost(hcd);
otg_dbg(OTG_DBG_OTGHCDI_HCD, "s5pc110_otghcd_hub_control \n");
spin_lock_irq_save_otg(&otghost->lock, spin_lock_flag);
ret_val = root_hub_feature(hcd, OTG_PORT_NUMBER,
typeReq, value, (void *)buf_p);
spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
if(ret_val != USB_ERR_SUCCESS) {
otg_err(OTG_DBG_OTGHCDI_HCD, "fail to root_hub_feature() \n");
return ret_val;
}
return (int)ret_val;
}
/**
* int s5pc110_otghcd_bus_suspend(struct usb_hcd *hcd)
*
* @brief suspend otg hcd
*
* @param [in] hcd : pointer of usb_hcd
*
* @return USB_ERR_SUCCESS \n
*/
int s5pc110_otghcd_bus_suspend(struct usb_hcd *hcd)
{
unsigned long spin_lock_flag = 0;
struct sec_otghost *otghost = hcd_to_sec_otghost(hcd);
otg_dbg(OTG_DBG_OTGHCDI_HCD, "s5pc110_otghcd_bus_suspend \n");
spin_lock_irq_save_otg(&otghost->lock, spin_lock_flag);
bus_suspend();
spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
return USB_ERR_SUCCESS;
}
/**
* int s5pc110_otghcd_bus_resume(struct usb_hcd *hcd)
*
* @brief resume otg hcd
*
* @param [in] hcd : pointer of usb_hcd
*
* @return USB_ERR_SUCCESS \n
*/
int s5pc110_otghcd_bus_resume(struct usb_hcd *hcd)
{
unsigned long spin_lock_flag = 0;
struct sec_otghost *otghost = hcd_to_sec_otghost(hcd);
otg_dbg(OTG_DBG_OTGHCDI_HCD, "s5pc110_otghcd_bus_resume \n");
spin_lock_irq_save_otg(&otghost->lock, spin_lock_flag);
if(bus_resume(otghost) != USB_ERR_SUCCESS) {
return USB_ERR_FAIL;
}
spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
return USB_ERR_SUCCESS;
}
/**
* int s5pc110_otghcd_start_port_reset(struct usb_hcd *hcd, unsigned port)
*
* @brief reset otg port
*
* @param [in] hcd : pointer of usb_hcd
* [in] port : number of port
*
* @return USB_ERR_SUCCESS : If success \n
* ret_val : If call fail \n
*/
int s5pc110_otghcd_start_port_reset(struct usb_hcd *hcd, unsigned port)
{
int ret_val = 0;
unsigned long spin_lock_flag = 0;
struct sec_otghost *otghost = hcd_to_sec_otghost(hcd);
otg_dbg(OTG_DBG_OTGHCDI_HCD, "s5pc110_otghcd_start_port_reset \n");
spin_lock_irq_save_otg(&otghost->lock, spin_lock_flag);
ret_val = reset_and_enable_port(hcd, OTG_PORT_NUMBER);
spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
if(ret_val != USB_ERR_SUCCESS) {
otg_err(OTG_DBG_OTGHCDI_HCD,
"fail to reset_and_enable_port() \n");
return ret_val;
}
return USB_ERR_SUCCESS;
}
Jump to Line
Something went wrong with that request. Please try again.