diff options
author | Ajay Kumar Gupta <ajay.gupta@ti.com> | 2008-10-29 09:10:31 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2008-11-13 17:45:00 -0500 |
commit | f82a689faeb328ba7c194782f42cc438519d508e (patch) | |
tree | 82f8847b5162267e05e89edc01d0633d8c550def /drivers/usb/musb | |
parent | 352d026338378b1f13f044e33c1047da6e470056 (diff) |
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>
Diffstat (limited to 'drivers/usb/musb')
-rw-r--r-- | drivers/usb/musb/musb_host.c | 77 |
1 files changed, 57 insertions, 20 deletions
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 3133990f04ec..981d49738ec5 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c | |||
@@ -1507,10 +1507,29 @@ void musb_host_rx(struct musb *musb, u8 epnum) | |||
1507 | musb_writew(hw_ep->regs, MUSB_RXCSR, val); | 1507 | musb_writew(hw_ep->regs, MUSB_RXCSR, val); |
1508 | 1508 | ||
1509 | #ifdef CONFIG_USB_INVENTRA_DMA | 1509 | #ifdef CONFIG_USB_INVENTRA_DMA |
1510 | if (usb_pipeisoc(pipe)) { | ||
1511 | struct usb_iso_packet_descriptor *d; | ||
1512 | |||
1513 | d = urb->iso_frame_desc + qh->iso_idx; | ||
1514 | d->actual_length = xfer_len; | ||
1515 | |||
1516 | /* even if there was an error, we did the dma | ||
1517 | * for iso_frame_desc->length | ||
1518 | */ | ||
1519 | if (d->status != EILSEQ && d->status != -EOVERFLOW) | ||
1520 | d->status = 0; | ||
1521 | |||
1522 | if (++qh->iso_idx >= urb->number_of_packets) | ||
1523 | done = true; | ||
1524 | else | ||
1525 | done = false; | ||
1526 | |||
1527 | } else { | ||
1510 | /* done if urb buffer is full or short packet is recd */ | 1528 | /* done if urb buffer is full or short packet is recd */ |
1511 | done = (urb->actual_length + xfer_len >= | 1529 | done = (urb->actual_length + xfer_len >= |
1512 | urb->transfer_buffer_length | 1530 | urb->transfer_buffer_length |
1513 | || dma->actual_len < qh->maxpacket); | 1531 | || dma->actual_len < qh->maxpacket); |
1532 | } | ||
1514 | 1533 | ||
1515 | /* send IN token for next packet, without AUTOREQ */ | 1534 | /* send IN token for next packet, without AUTOREQ */ |
1516 | if (!done) { | 1535 | if (!done) { |
@@ -1547,7 +1566,8 @@ void musb_host_rx(struct musb *musb, u8 epnum) | |||
1547 | if (dma) { | 1566 | if (dma) { |
1548 | struct dma_controller *c; | 1567 | struct dma_controller *c; |
1549 | u16 rx_count; | 1568 | u16 rx_count; |
1550 | int ret; | 1569 | int ret, length; |
1570 | dma_addr_t buf; | ||
1551 | 1571 | ||
1552 | rx_count = musb_readw(epio, MUSB_RXCOUNT); | 1572 | rx_count = musb_readw(epio, MUSB_RXCOUNT); |
1553 | 1573 | ||
@@ -1560,6 +1580,35 @@ void musb_host_rx(struct musb *musb, u8 epnum) | |||
1560 | 1580 | ||
1561 | c = musb->dma_controller; | 1581 | c = musb->dma_controller; |
1562 | 1582 | ||
1583 | if (usb_pipeisoc(pipe)) { | ||
1584 | int status = 0; | ||
1585 | struct usb_iso_packet_descriptor *d; | ||
1586 | |||
1587 | d = urb->iso_frame_desc + qh->iso_idx; | ||
1588 | |||
1589 | if (iso_err) { | ||
1590 | status = -EILSEQ; | ||
1591 | urb->error_count++; | ||
1592 | } | ||
1593 | if (rx_count > d->length) { | ||
1594 | if (status == 0) { | ||
1595 | status = -EOVERFLOW; | ||
1596 | urb->error_count++; | ||
1597 | } | ||
1598 | DBG(2, "** OVERFLOW %d into %d\n",\ | ||
1599 | rx_count, d->length); | ||
1600 | |||
1601 | length = d->length; | ||
1602 | } else | ||
1603 | length = rx_count; | ||
1604 | d->status = status; | ||
1605 | buf = urb->transfer_dma + d->offset; | ||
1606 | } else { | ||
1607 | length = rx_count; | ||
1608 | buf = urb->transfer_dma + | ||
1609 | urb->actual_length; | ||
1610 | } | ||
1611 | |||
1563 | dma->desired_mode = 0; | 1612 | dma->desired_mode = 0; |
1564 | #ifdef USE_MODE1 | 1613 | #ifdef USE_MODE1 |
1565 | /* because of the issue below, mode 1 will | 1614 | /* because of the issue below, mode 1 will |
@@ -1571,6 +1620,12 @@ void musb_host_rx(struct musb *musb, u8 epnum) | |||
1571 | urb->actual_length) | 1620 | urb->actual_length) |
1572 | > qh->maxpacket) | 1621 | > qh->maxpacket) |
1573 | dma->desired_mode = 1; | 1622 | dma->desired_mode = 1; |
1623 | if (rx_count < hw_ep->max_packet_sz_rx) { | ||
1624 | length = rx_count; | ||
1625 | dma->bDesiredMode = 0; | ||
1626 | } else { | ||
1627 | length = urb->transfer_buffer_length; | ||
1628 | } | ||
1574 | #endif | 1629 | #endif |
1575 | 1630 | ||
1576 | /* Disadvantage of using mode 1: | 1631 | /* Disadvantage of using mode 1: |
@@ -1608,12 +1663,7 @@ void musb_host_rx(struct musb *musb, u8 epnum) | |||
1608 | */ | 1663 | */ |
1609 | ret = c->channel_program( | 1664 | ret = c->channel_program( |
1610 | dma, qh->maxpacket, | 1665 | dma, qh->maxpacket, |
1611 | dma->desired_mode, | 1666 | dma->desired_mode, buf, length); |
1612 | urb->transfer_dma | ||
1613 | + urb->actual_length, | ||
1614 | (dma->desired_mode == 0) | ||
1615 | ? rx_count | ||
1616 | : urb->transfer_buffer_length); | ||
1617 | 1667 | ||
1618 | if (!ret) { | 1668 | if (!ret) { |
1619 | c->channel_release(dma); | 1669 | c->channel_release(dma); |
@@ -1631,19 +1681,6 @@ void musb_host_rx(struct musb *musb, u8 epnum) | |||
1631 | } | 1681 | } |
1632 | } | 1682 | } |
1633 | 1683 | ||
1634 | if (dma && usb_pipeisoc(pipe)) { | ||
1635 | struct usb_iso_packet_descriptor *d; | ||
1636 | int iso_stat = status; | ||
1637 | |||
1638 | d = urb->iso_frame_desc + qh->iso_idx; | ||
1639 | d->actual_length += xfer_len; | ||
1640 | if (iso_err) { | ||
1641 | iso_stat = -EILSEQ; | ||
1642 | urb->error_count++; | ||
1643 | } | ||
1644 | d->status = iso_stat; | ||
1645 | } | ||
1646 | |||
1647 | finish: | 1684 | finish: |
1648 | urb->actual_length += xfer_len; | 1685 | urb->actual_length += xfer_len; |
1649 | qh->offset += xfer_len; | 1686 | qh->offset += xfer_len; |