usb: musb: Fix for isochronous IN transfer

Fixes blurred capture images in dma mode. Isochronous error field in
urb and source data buffer pointer were not updated properly in dma
mode.

Signed-off-by: Ajay Kumar Gupta <ajay.gupta@ti.com>
Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Ajay Kumar Gupta 2008-10-29 15:10:31 +02:00 committed by Greg Kroah-Hartman
parent 352d026338
commit f82a689fae
1 changed files with 57 additions and 20 deletions

View File

@ -1507,10 +1507,29 @@ void musb_host_rx(struct musb *musb, u8 epnum)
musb_writew(hw_ep->regs, MUSB_RXCSR, val); musb_writew(hw_ep->regs, MUSB_RXCSR, val);
#ifdef CONFIG_USB_INVENTRA_DMA #ifdef CONFIG_USB_INVENTRA_DMA
if (usb_pipeisoc(pipe)) {
struct usb_iso_packet_descriptor *d;
d = urb->iso_frame_desc + qh->iso_idx;
d->actual_length = xfer_len;
/* even if there was an error, we did the dma
* for iso_frame_desc->length
*/
if (d->status != EILSEQ && d->status != -EOVERFLOW)
d->status = 0;
if (++qh->iso_idx >= urb->number_of_packets)
done = true;
else
done = false;
} else {
/* done if urb buffer is full or short packet is recd */ /* done if urb buffer is full or short packet is recd */
done = (urb->actual_length + xfer_len >= done = (urb->actual_length + xfer_len >=
urb->transfer_buffer_length urb->transfer_buffer_length
|| dma->actual_len < qh->maxpacket); || dma->actual_len < qh->maxpacket);
}
/* send IN token for next packet, without AUTOREQ */ /* send IN token for next packet, without AUTOREQ */
if (!done) { if (!done) {
@ -1547,7 +1566,8 @@ void musb_host_rx(struct musb *musb, u8 epnum)
if (dma) { if (dma) {
struct dma_controller *c; struct dma_controller *c;
u16 rx_count; u16 rx_count;
int ret; int ret, length;
dma_addr_t buf;
rx_count = musb_readw(epio, MUSB_RXCOUNT); rx_count = musb_readw(epio, MUSB_RXCOUNT);
@ -1560,6 +1580,35 @@ void musb_host_rx(struct musb *musb, u8 epnum)
c = musb->dma_controller; c = musb->dma_controller;
if (usb_pipeisoc(pipe)) {
int status = 0;
struct usb_iso_packet_descriptor *d;
d = urb->iso_frame_desc + qh->iso_idx;
if (iso_err) {
status = -EILSEQ;
urb->error_count++;
}
if (rx_count > d->length) {
if (status == 0) {
status = -EOVERFLOW;
urb->error_count++;
}
DBG(2, "** OVERFLOW %d into %d\n",\
rx_count, d->length);
length = d->length;
} else
length = rx_count;
d->status = status;
buf = urb->transfer_dma + d->offset;
} else {
length = rx_count;
buf = urb->transfer_dma +
urb->actual_length;
}
dma->desired_mode = 0; dma->desired_mode = 0;
#ifdef USE_MODE1 #ifdef USE_MODE1
/* because of the issue below, mode 1 will /* because of the issue below, mode 1 will
@ -1571,6 +1620,12 @@ void musb_host_rx(struct musb *musb, u8 epnum)
urb->actual_length) urb->actual_length)
> qh->maxpacket) > qh->maxpacket)
dma->desired_mode = 1; dma->desired_mode = 1;
if (rx_count < hw_ep->max_packet_sz_rx) {
length = rx_count;
dma->bDesiredMode = 0;
} else {
length = urb->transfer_buffer_length;
}
#endif #endif
/* Disadvantage of using mode 1: /* Disadvantage of using mode 1:
@ -1608,12 +1663,7 @@ void musb_host_rx(struct musb *musb, u8 epnum)
*/ */
ret = c->channel_program( ret = c->channel_program(
dma, qh->maxpacket, dma, qh->maxpacket,
dma->desired_mode, dma->desired_mode, buf, length);
urb->transfer_dma
+ urb->actual_length,
(dma->desired_mode == 0)
? rx_count
: urb->transfer_buffer_length);
if (!ret) { if (!ret) {
c->channel_release(dma); c->channel_release(dma);
@ -1631,19 +1681,6 @@ void musb_host_rx(struct musb *musb, u8 epnum)
} }
} }
if (dma && usb_pipeisoc(pipe)) {
struct usb_iso_packet_descriptor *d;
int iso_stat = status;
d = urb->iso_frame_desc + qh->iso_idx;
d->actual_length += xfer_len;
if (iso_err) {
iso_stat = -EILSEQ;
urb->error_count++;
}
d->status = iso_stat;
}
finish: finish:
urb->actual_length += xfer_len; urb->actual_length += xfer_len;
qh->offset += xfer_len; qh->offset += xfer_len;