Skip to content

Commit

Permalink
Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6
Browse files Browse the repository at this point in the history
* master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6:
  USB: fix usb-serial/ftdi build warning
  USB: fix usb-serial/generic build warning
  USB: another entry for the quirk list
  USB: remove duplicated device id in airprime driver
  USB: omap_udc: workaround dma_free_coherent() bogosity
  UHCI: Fix problem caused by lack of terminating QH
  • Loading branch information
Linus Torvalds committed Mar 26, 2007
2 parents 55ab975 + 3b009c6 commit 8b66a45
Show file tree
Hide file tree
Showing 8 changed files with 145 additions and 98 deletions.
3 changes: 2 additions & 1 deletion drivers/usb/core/quirks.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
static const struct usb_device_id usb_quirk_list[] = {
/* HP 5300/5370C scanner */
{ USB_DEVICE(0x03f0, 0x0701), .driver_info = USB_QUIRK_STRING_FETCH_255 },

/* Seiko Epson Corp - Perfection 1670 */
{ USB_DEVICE(0x04b8, 0x011f), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
/* Elsa MicroLink 56k (V.250) */
{ USB_DEVICE(0x05cc, 0x2267), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },

Expand Down
103 changes: 93 additions & 10 deletions drivers/usb/gadget/omap_udc.c
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,15 @@ omap_free_request(struct usb_ep *ep, struct usb_request *_req)

/*-------------------------------------------------------------------------*/

/*
* dma-coherent memory allocation (for dma-capable endpoints)
*
* NOTE: the dma_*_coherent() API calls suck. Most implementations are
* (a) page-oriented, so small buffers lose big; and (b) asymmetric with
* respect to calls with irqs disabled: alloc is safe, free is not.
* We currently work around (b), but not (a).
*/

static void *
omap_alloc_buffer(
struct usb_ep *_ep,
Expand All @@ -307,6 +316,9 @@ omap_alloc_buffer(
void *retval;
struct omap_ep *ep;

if (!_ep)
return NULL;

ep = container_of(_ep, struct omap_ep, ep);
if (use_dma && ep->has_dma) {
static int warned;
Expand All @@ -326,20 +338,65 @@ omap_alloc_buffer(
return retval;
}

static DEFINE_SPINLOCK(buflock);
static LIST_HEAD(buffers);

struct free_record {
struct list_head list;
struct device *dev;
unsigned bytes;
dma_addr_t dma;
};

static void do_free(unsigned long ignored)
{
spin_lock_irq(&buflock);
while (!list_empty(&buffers)) {
struct free_record *buf;

buf = list_entry(buffers.next, struct free_record, list);
list_del(&buf->list);
spin_unlock_irq(&buflock);

dma_free_coherent(buf->dev, buf->bytes, buf, buf->dma);

spin_lock_irq(&buflock);
}
spin_unlock_irq(&buflock);
}

static DECLARE_TASKLET(deferred_free, do_free, 0);

static void omap_free_buffer(
struct usb_ep *_ep,
void *buf,
dma_addr_t dma,
unsigned bytes
)
{
struct omap_ep *ep;
if (!_ep) {
WARN_ON(1);
return;
}

ep = container_of(_ep, struct omap_ep, ep);
if (use_dma && _ep && ep->has_dma)
dma_free_coherent(ep->udc->gadget.dev.parent, bytes, buf, dma);
else
kfree (buf);
/* free memory into the right allocator */
if (dma != DMA_ADDR_INVALID) {
struct omap_ep *ep;
struct free_record *rec = buf;
unsigned long flags;

ep = container_of(_ep, struct omap_ep, ep);

rec->dev = ep->udc->gadget.dev.parent;
rec->bytes = bytes;
rec->dma = dma;

spin_lock_irqsave(&buflock, flags);
list_add_tail(&rec->list, &buffers);
tasklet_schedule(&deferred_free);
spin_unlock_irqrestore(&buflock, flags);
} else
kfree(buf);
}

/*-------------------------------------------------------------------------*/
Expand Down Expand Up @@ -1691,12 +1748,38 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
udc->ep0_pending = 0;
break;
case USB_REQ_GET_STATUS:
/* USB_ENDPOINT_HALT status? */
if (u.r.bRequestType != (USB_DIR_IN|USB_RECIP_ENDPOINT))
goto intf_status;

/* ep0 never stalls */
if (!(w_index & 0xf))
goto zero_status;

/* only active endpoints count */
ep = &udc->ep[w_index & 0xf];
if (w_index & USB_DIR_IN)
ep += 16;
if (!ep->desc)
goto do_stall;

/* iso never stalls */
if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC)
goto zero_status;

/* FIXME don't assume non-halted endpoints!! */
ERR("%s status, can't report\n", ep->ep.name);
goto do_stall;

intf_status:
/* return interface status. if we were pedantic,
* we'd detect non-existent interfaces, and stall.
*/
if (u.r.bRequestType
!= (USB_DIR_IN|USB_RECIP_INTERFACE))
goto delegate;

zero_status:
/* return two zero bytes */
UDC_EP_NUM_REG = UDC_EP_SEL|UDC_EP_DIR;
UDC_DATA_REG = 0;
Expand Down Expand Up @@ -2068,7 +2151,7 @@ static irqreturn_t omap_udc_iso_irq(int irq, void *_dev)

/*-------------------------------------------------------------------------*/

static inline int machine_needs_vbus_session(void)
static inline int machine_without_vbus_sense(void)
{
return (machine_is_omap_innovator()
|| machine_is_omap_osk()
Expand Down Expand Up @@ -2156,7 +2239,7 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
/* boards that don't have VBUS sensing can't autogate 48MHz;
* can't enter deep sleep while a gadget driver is active.
*/
if (machine_needs_vbus_session())
if (machine_without_vbus_sense())
omap_vbus_session(&udc->gadget, 1);

done:
Expand All @@ -2179,7 +2262,7 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
if (udc->dc_clk != NULL)
omap_udc_enable_clock(1);

if (machine_needs_vbus_session())
if (machine_without_vbus_sense())
omap_vbus_session(&udc->gadget, 0);

if (udc->transceiver)
Expand Down Expand Up @@ -2822,7 +2905,7 @@ static int __init omap_udc_probe(struct platform_device *pdev)
hmc = HMC_1510;
type = "(unknown)";

if (machine_is_omap_innovator() || machine_is_sx1()) {
if (machine_without_vbus_sense()) {
/* just set up software VBUS detect, and then
* later rig it so we always report VBUS.
* FIXME without really sensing VBUS, we can't
Expand Down
26 changes: 15 additions & 11 deletions drivers/usb/host/uhci-debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,8 @@ static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space)
return out - buf;
}

static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
static int uhci_show_qh(struct uhci_hcd *uhci,
struct uhci_qh *qh, char *buf, int len, int space)
{
char *out = buf;
int i, nurbs;
Expand Down Expand Up @@ -190,6 +191,9 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)

if (list_empty(&qh->queue)) {
out += sprintf(out, "%*s queue is empty\n", space, "");
if (qh == uhci->skel_async_qh)
out += uhci_show_td(uhci->term_td, out,
len - (out - buf), 0);
} else {
struct urb_priv *urbp = list_entry(qh->queue.next,
struct urb_priv, node);
Expand Down Expand Up @@ -343,6 +347,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
struct list_head *tmp, *head;
int nframes, nerrs;
__le32 link;
__le32 fsbr_link;

static const char * const qh_names[] = {
"unlink", "iso", "int128", "int64", "int32", "int16",
Expand Down Expand Up @@ -424,21 +429,22 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)

out += sprintf(out, "Skeleton QHs\n");

fsbr_link = 0;
for (i = 0; i < UHCI_NUM_SKELQH; ++i) {
int cnt = 0;
__le32 fsbr_link = 0;

qh = uhci->skelqh[i];
out += sprintf(out, "- skel_%s_qh\n", qh_names[i]); \
out += uhci_show_qh(qh, out, len - (out - buf), 4);
out += uhci_show_qh(uhci, qh, out, len - (out - buf), 4);

/* Last QH is the Terminating QH, it's different */
if (i == SKEL_TERM) {
if (qh_element(qh) != LINK_TO_TD(uhci->term_td))
out += sprintf(out, " skel_term_qh element is not set to term_td!\n");
if (link == LINK_TO_QH(uhci->skel_term_qh))
goto check_qh_link;
continue;
link = fsbr_link;
if (!link)
link = LINK_TO_QH(uhci->skel_term_qh);
goto check_qh_link;
}

head = &qh->node;
Expand All @@ -448,7 +454,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
qh = list_entry(tmp, struct uhci_qh, node);
tmp = tmp->next;
if (++cnt <= 10)
out += uhci_show_qh(qh, out,
out += uhci_show_qh(uhci, qh, out,
len - (out - buf), 4);
if (!fsbr_link && qh->skel >= SKEL_FSBR)
fsbr_link = LINK_TO_QH(qh);
Expand All @@ -463,8 +469,6 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
link = LINK_TO_QH(uhci->skel_async_qh);
else if (!uhci->fsbr_is_on)
;
else if (fsbr_link)
link = fsbr_link;
else
link = LINK_TO_QH(uhci->skel_term_qh);
check_qh_link:
Expand Down Expand Up @@ -573,8 +577,8 @@ static const struct file_operations uhci_debug_operations = {
static inline void lprintk(char *buf)
{}

static inline int uhci_show_qh(struct uhci_qh *qh, char *buf,
int len, int space)
static inline int uhci_show_qh(struct uhci_hcd *uhci,
struct uhci_qh *qh, char *buf, int len, int space)
{
return 0;
}
Expand Down
3 changes: 2 additions & 1 deletion drivers/usb/host/uhci-hcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -632,7 +632,8 @@ static int uhci_start(struct usb_hcd *hcd)
*/
for (i = SKEL_ISO + 1; i < SKEL_ASYNC; ++i)
uhci->skelqh[i]->link = LINK_TO_QH(uhci->skel_async_qh);
uhci->skel_async_qh->link = uhci->skel_term_qh->link = UHCI_PTR_TERM;
uhci->skel_async_qh->link = UHCI_PTR_TERM;
uhci->skel_term_qh->link = LINK_TO_QH(uhci->skel_term_qh);

/* This dummy TD is to work around a bug in Intel PIIX controllers */
uhci_fill_td(uhci->term_td, 0, uhci_explen(0) |
Expand Down
Loading

0 comments on commit 8b66a45

Please sign in to comment.