Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 61931
b: refs/heads/master
c: 1b4cd43
h: refs/heads/master
i:
  61929: e000a81
  61927: 6ad6e37
v: v3
  • Loading branch information
Alan Stern authored and Greg Kroah-Hartman committed Jul 20, 2007
1 parent 4d3175b commit c02b474
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 102 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 10e485221edd2799dc495e4cde98fe74aeb292b1
refs/heads/master: 1b4cd43bd3f9aa7a794e29b80b0d984a8e144df4
187 changes: 86 additions & 101 deletions trunk/drivers/usb/host/isp116x-hcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,6 @@ static void preproc_atl_queue(struct isp116x *isp116x)
struct urb, urb_list);
ptd = &ep->ptd;
len = ep->length;
spin_lock(&urb->lock);
ep->data = (unsigned char *)urb->transfer_buffer
+ urb->actual_length;

Expand Down Expand Up @@ -264,7 +263,6 @@ static void preproc_atl_queue(struct isp116x *isp116x)
| PTD_EP(ep->epnum);
ptd->len = PTD_LEN(len) | PTD_DIR(dir);
ptd->faddr = PTD_FA(usb_pipedevice(urb->pipe));
spin_unlock(&urb->lock);
if (!ep->active) {
ptd->mps |= PTD_LAST_MSK;
isp116x->atl_last_dir = dir;
Expand All @@ -274,6 +272,61 @@ static void preproc_atl_queue(struct isp116x *isp116x)
}
}

/*
Take done or failed requests out of schedule. Give back
processed urbs.
*/
static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep,
struct urb *urb)
__releases(isp116x->lock) __acquires(isp116x->lock)
{
unsigned i;

urb->hcpriv = NULL;
ep->error_count = 0;

if (usb_pipecontrol(urb->pipe))
ep->nextpid = USB_PID_SETUP;

urb_dbg(urb, "Finish");

spin_unlock(&isp116x->lock);
usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb);
spin_lock(&isp116x->lock);

/* take idle endpoints out of the schedule */
if (!list_empty(&ep->hep->urb_list))
return;

/* async deschedule */
if (!list_empty(&ep->schedule)) {
list_del_init(&ep->schedule);
return;
}

/* periodic deschedule */
DBG("deschedule qh%d/%p branch %d\n", ep->period, ep, ep->branch);
for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) {
struct isp116x_ep *temp;
struct isp116x_ep **prev = &isp116x->periodic[i];

while (*prev && ((temp = *prev) != ep))
prev = &temp->next;
if (*prev)
*prev = ep->next;
isp116x->load[i] -= ep->load;
}
ep->branch = PERIODIC_SIZE;
isp116x_to_hcd(isp116x)->self.bandwidth_allocated -=
ep->load / ep->period;

/* switch irq type? */
if (!--isp116x->periodic_count) {
isp116x->irqenb &= ~HCuPINT_SOF;
isp116x->irqenb |= HCuPINT_ATL;
}
}

/*
Analyze transfer results, handle partial transfers and errors
*/
Expand All @@ -284,6 +337,7 @@ static void postproc_atl_queue(struct isp116x *isp116x)
struct usb_device *udev;
struct ptd *ptd;
int short_not_ok;
int status;
u8 cc;

for (ep = isp116x->atl_active; ep; ep = ep->active) {
Expand All @@ -294,55 +348,44 @@ static void postproc_atl_queue(struct isp116x *isp116x)
ptd = &ep->ptd;
cc = PTD_GET_CC(ptd);
short_not_ok = 1;
spin_lock(&urb->lock);
status = -EINPROGRESS;

/* Data underrun is special. For allowed underrun
we clear the error and continue as normal. For
forbidden underrun we finish the DATA stage
immediately while for control transfer,
we do a STATUS stage. */
if (cc == TD_DATAUNDERRUN) {
if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) {
DBG("Allowed data underrun\n");
if (!(urb->transfer_flags & URB_SHORT_NOT_OK) ||
usb_pipecontrol(urb->pipe)) {
DBG("Allowed or control data underrun\n");
cc = TD_CC_NOERROR;
short_not_ok = 0;
} else {
ep->error_count = 1;
if (usb_pipecontrol(urb->pipe))
ep->nextpid = USB_PID_ACK;
else
usb_settoggle(udev, ep->epnum,
ep->nextpid ==
USB_PID_OUT,
PTD_GET_TOGGLE(ptd));
usb_settoggle(udev, ep->epnum,
ep->nextpid == USB_PID_OUT,
PTD_GET_TOGGLE(ptd));
urb->actual_length += PTD_GET_COUNT(ptd);
urb->status = cc_to_error[TD_DATAUNDERRUN];
spin_unlock(&urb->lock);
continue;
status = cc_to_error[TD_DATAUNDERRUN];
goto done;
}
}
/* Keep underrun error through the STATUS stage */
if (urb->status == cc_to_error[TD_DATAUNDERRUN])
cc = TD_DATAUNDERRUN;

if (cc != TD_CC_NOERROR && cc != TD_NOTACCESSED
&& (++ep->error_count >= 3 || cc == TD_CC_STALL
|| cc == TD_DATAOVERRUN)) {
if (urb->status == -EINPROGRESS)
urb->status = cc_to_error[cc];
status = cc_to_error[cc];
if (ep->nextpid == USB_PID_ACK)
ep->nextpid = 0;
spin_unlock(&urb->lock);
continue;
goto done;
}
/* According to usb spec, zero-length Int transfer signals
finishing of the urb. Hey, does this apply only
for IN endpoints? */
if (usb_pipeint(urb->pipe) && !PTD_GET_LEN(ptd)) {
if (urb->status == -EINPROGRESS)
urb->status = 0;
spin_unlock(&urb->lock);
continue;
status = 0;
goto done;
}

/* Relax after previously failed, but later succeeded
Expand Down Expand Up @@ -381,8 +424,8 @@ static void postproc_atl_queue(struct isp116x *isp116x)
/* All data for this URB is transferred, let's finish */
if (usb_pipecontrol(urb->pipe))
ep->nextpid = USB_PID_ACK;
else if (urb->status == -EINPROGRESS)
urb->status = 0;
else
status = 0;
break;
case USB_PID_SETUP:
if (PTD_GET_ACTIVE(ptd)
Expand All @@ -402,69 +445,27 @@ static void postproc_atl_queue(struct isp116x *isp116x)
if (PTD_GET_ACTIVE(ptd)
|| (cc != TD_CC_NOERROR && cc < 0x0E))
break;
if (urb->status == -EINPROGRESS)
urb->status = 0;
if ((urb->transfer_flags & URB_SHORT_NOT_OK) &&
urb->actual_length <
urb->transfer_buffer_length)
status = -EREMOTEIO;
else
status = 0;
ep->nextpid = 0;
break;
default:
BUG();
}
spin_unlock(&urb->lock);
}
}

/*
Take done or failed requests out of schedule. Give back
processed urbs.
*/
static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep,
struct urb *urb)
__releases(isp116x->lock) __acquires(isp116x->lock)
{
unsigned i;

urb->hcpriv = NULL;
ep->error_count = 0;

if (usb_pipecontrol(urb->pipe))
ep->nextpid = USB_PID_SETUP;

urb_dbg(urb, "Finish");

spin_unlock(&isp116x->lock);
usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb);
spin_lock(&isp116x->lock);

/* take idle endpoints out of the schedule */
if (!list_empty(&ep->hep->urb_list))
return;

/* async deschedule */
if (!list_empty(&ep->schedule)) {
list_del_init(&ep->schedule);
return;
}

/* periodic deschedule */
DBG("deschedule qh%d/%p branch %d\n", ep->period, ep, ep->branch);
for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) {
struct isp116x_ep *temp;
struct isp116x_ep **prev = &isp116x->periodic[i];

while (*prev && ((temp = *prev) != ep))
prev = &temp->next;
if (*prev)
*prev = ep->next;
isp116x->load[i] -= ep->load;
}
ep->branch = PERIODIC_SIZE;
isp116x_to_hcd(isp116x)->self.bandwidth_allocated -=
ep->load / ep->period;

/* switch irq type? */
if (!--isp116x->periodic_count) {
isp116x->irqenb &= ~HCuPINT_SOF;
isp116x->irqenb |= HCuPINT_ATL;
done:
if (status != -EINPROGRESS) {
spin_lock(&urb->lock);
if (urb->status == -EINPROGRESS)
urb->status = status;
spin_unlock(&urb->lock);
}
if (urb->status != -EINPROGRESS)
finish_request(isp116x, ep, urb);
}
}

Expand Down Expand Up @@ -570,9 +571,6 @@ static void start_atl_transfers(struct isp116x *isp116x)
*/
static void finish_atl_transfers(struct isp116x *isp116x)
{
struct isp116x_ep *ep;
struct urb *urb;

if (!isp116x->atl_active)
return;
/* Fifo not ready? */
Expand All @@ -582,16 +580,6 @@ static void finish_atl_transfers(struct isp116x *isp116x)
atomic_inc(&isp116x->atl_finishing);
unpack_fifo(isp116x);
postproc_atl_queue(isp116x);
for (ep = isp116x->atl_active; ep; ep = ep->active) {
urb =
container_of(ep->hep->urb_list.next, struct urb, urb_list);
/* USB_PID_ACK check here avoids finishing of
control transfers, for which TD_DATAUNDERRUN
occured, while URB_SHORT_NOT_OK was set */
if (urb && urb->status != -EINPROGRESS
&& ep->nextpid != USB_PID_ACK)
finish_request(isp116x, ep, urb);
}
atomic_dec(&isp116x->atl_finishing);
}

Expand Down Expand Up @@ -821,15 +809,12 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
}

/* in case of unlink-during-submit */
spin_lock(&urb->lock);
if (urb->status != -EINPROGRESS) {
spin_unlock(&urb->lock);
finish_request(isp116x, ep, urb);
ret = 0;
goto fail;
}
urb->hcpriv = hep;
spin_unlock(&urb->lock);
start_atl_transfers(isp116x);

fail:
Expand Down

0 comments on commit c02b474

Please sign in to comment.