Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8b66a454 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6

* 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
parents 55ab9756 3b009c63
Loading
Loading
Loading
Loading
+2 −1
Original line number Original line Diff line number Diff line
@@ -30,7 +30,8 @@
static const struct usb_device_id usb_quirk_list[] = {
static const struct usb_device_id usb_quirk_list[] = {
	/* HP 5300/5370C scanner */
	/* HP 5300/5370C scanner */
	{ USB_DEVICE(0x03f0, 0x0701), .driver_info = USB_QUIRK_STRING_FETCH_255 },
	{ 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) */
	/* Elsa MicroLink 56k (V.250) */
	{ USB_DEVICE(0x05cc, 0x2267), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
	{ USB_DEVICE(0x05cc, 0x2267), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },


+93 −10
Original line number Original line Diff line number Diff line
@@ -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 *
static void *
omap_alloc_buffer(
omap_alloc_buffer(
	struct usb_ep	*_ep,
	struct usb_ep	*_ep,
@@ -307,6 +316,9 @@ omap_alloc_buffer(
	void		*retval;
	void		*retval;
	struct omap_ep	*ep;
	struct omap_ep	*ep;


	if (!_ep)
		return NULL;

	ep = container_of(_ep, struct omap_ep, ep);
	ep = container_of(_ep, struct omap_ep, ep);
	if (use_dma && ep->has_dma) {
	if (use_dma && ep->has_dma) {
		static int	warned;
		static int	warned;
@@ -326,6 +338,35 @@ omap_alloc_buffer(
	return retval;
	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(
static void omap_free_buffer(
	struct usb_ep	*_ep,
	struct usb_ep	*_ep,
	void		*buf,
	void		*buf,
@@ -333,12 +374,28 @@ static void omap_free_buffer(
	unsigned	bytes
	unsigned	bytes
)
)
{
{
	if (!_ep) {
		WARN_ON(1);
		return;
	}

	/* free memory into the right allocator */
	if (dma != DMA_ADDR_INVALID) {
		struct omap_ep		*ep;
		struct omap_ep		*ep;
		struct free_record	*rec = buf;
		unsigned long		flags;


		ep = container_of(_ep, struct omap_ep, ep);
		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);
		rec->dev = ep->udc->gadget.dev.parent;
	else
		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);
		kfree(buf);
}
}


@@ -1691,12 +1748,38 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
			udc->ep0_pending = 0;
			udc->ep0_pending = 0;
			break;
			break;
		case USB_REQ_GET_STATUS:
		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,
			/* return interface status.  if we were pedantic,
			 * we'd detect non-existent interfaces, and stall.
			 * we'd detect non-existent interfaces, and stall.
			 */
			 */
			if (u.r.bRequestType
			if (u.r.bRequestType
					!= (USB_DIR_IN|USB_RECIP_INTERFACE))
					!= (USB_DIR_IN|USB_RECIP_INTERFACE))
				goto delegate;
				goto delegate;

zero_status:
			/* return two zero bytes */
			/* return two zero bytes */
			UDC_EP_NUM_REG = UDC_EP_SEL|UDC_EP_DIR;
			UDC_EP_NUM_REG = UDC_EP_SEL|UDC_EP_DIR;
			UDC_DATA_REG = 0;
			UDC_DATA_REG = 0;
@@ -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()
	return (machine_is_omap_innovator()
		|| machine_is_omap_osk()
		|| machine_is_omap_osk()
@@ -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;
	/* boards that don't have VBUS sensing can't autogate 48MHz;
	 * can't enter deep sleep while a gadget driver is active.
	 * 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);
		omap_vbus_session(&udc->gadget, 1);


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


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


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


		if (machine_is_omap_innovator() || machine_is_sx1()) {
		if (machine_without_vbus_sense()) {
			/* just set up software VBUS detect, and then
			/* just set up software VBUS detect, and then
			 * later rig it so we always report VBUS.
			 * later rig it so we always report VBUS.
			 * FIXME without really sensing VBUS, we can't
			 * FIXME without really sensing VBUS, we can't
+15 −11
Original line number Original line Diff line number Diff line
@@ -145,7 +145,8 @@ static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space)
	return out - buf;
	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;
	char *out = buf;
	int i, nurbs;
	int i, nurbs;
@@ -190,6 +191,9 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)


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


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


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


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


		qh = uhci->skelqh[i];
		qh = uhci->skelqh[i];
		out += sprintf(out, "- skel_%s_qh\n", qh_names[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 */
		/* Last QH is the Terminating QH, it's different */
		if (i == SKEL_TERM) {
		if (i == SKEL_TERM) {
			if (qh_element(qh) != LINK_TO_TD(uhci->term_td))
			if (qh_element(qh) != LINK_TO_TD(uhci->term_td))
				out += sprintf(out, "    skel_term_qh element is not set to term_td!\n");
				out += sprintf(out, "    skel_term_qh element is not set to term_td!\n");
			if (link == LINK_TO_QH(uhci->skel_term_qh))
			link = fsbr_link;
			if (!link)
				link = LINK_TO_QH(uhci->skel_term_qh);
			goto check_qh_link;
			goto check_qh_link;
			continue;
		}
		}


		head = &qh->node;
		head = &qh->node;
@@ -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);
			qh = list_entry(tmp, struct uhci_qh, node);
			tmp = tmp->next;
			tmp = tmp->next;
			if (++cnt <= 10)
			if (++cnt <= 10)
				out += uhci_show_qh(qh, out,
				out += uhci_show_qh(uhci, qh, out,
						len - (out - buf), 4);
						len - (out - buf), 4);
			if (!fsbr_link && qh->skel >= SKEL_FSBR)
			if (!fsbr_link && qh->skel >= SKEL_FSBR)
				fsbr_link = LINK_TO_QH(qh);
				fsbr_link = LINK_TO_QH(qh);
@@ -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);
			link = LINK_TO_QH(uhci->skel_async_qh);
		else if (!uhci->fsbr_is_on)
		else if (!uhci->fsbr_is_on)
			;
			;
		else if (fsbr_link)
			link = fsbr_link;
		else
		else
			link = LINK_TO_QH(uhci->skel_term_qh);
			link = LINK_TO_QH(uhci->skel_term_qh);
check_qh_link:
check_qh_link:
@@ -573,8 +577,8 @@ static const struct file_operations uhci_debug_operations = {
static inline void lprintk(char *buf)
static inline void lprintk(char *buf)
{}
{}


static inline int uhci_show_qh(struct uhci_qh *qh, char *buf,
static inline int uhci_show_qh(struct uhci_hcd *uhci,
		int len, int space)
		struct uhci_qh *qh, char *buf, int len, int space)
{
{
	return 0;
	return 0;
}
}
+2 −1
Original line number Original line Diff line number Diff line
@@ -632,7 +632,8 @@ static int uhci_start(struct usb_hcd *hcd)
	 */
	 */
	for (i = SKEL_ISO + 1; i < SKEL_ASYNC; ++i)
	for (i = SKEL_ISO + 1; i < SKEL_ASYNC; ++i)
		uhci->skelqh[i]->link = LINK_TO_QH(uhci->skel_async_qh);
		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 */
	/* This dummy TD is to work around a bug in Intel PIIX controllers */
	uhci_fill_td(uhci->term_td, 0, uhci_explen(0) |
	uhci_fill_td(uhci->term_td, 0, uhci_explen(0) |
+24 −70
Original line number Original line Diff line number Diff line
@@ -45,43 +45,27 @@ static inline void uhci_clear_next_interrupt(struct uhci_hcd *uhci)
 */
 */
static void uhci_fsbr_on(struct uhci_hcd *uhci)
static void uhci_fsbr_on(struct uhci_hcd *uhci)
{
{
	struct uhci_qh *fsbr_qh, *lqh, *tqh;
	struct uhci_qh *lqh;


	/* The terminating skeleton QH always points back to the first
	 * FSBR QH.  Make the last async QH point to the terminating
	 * skeleton QH. */
	uhci->fsbr_is_on = 1;
	uhci->fsbr_is_on = 1;
	lqh = list_entry(uhci->skel_async_qh->node.prev,
	lqh = list_entry(uhci->skel_async_qh->node.prev,
			struct uhci_qh, node);
			struct uhci_qh, node);

	lqh->link = LINK_TO_QH(uhci->skel_term_qh);
	/* Find the first FSBR QH.  Linear search through the list is
	 * acceptable because normally FSBR gets turned on as soon as
	 * one QH needs it. */
	fsbr_qh = NULL;
	list_for_each_entry_reverse(tqh, &uhci->skel_async_qh->node, node) {
		if (tqh->skel < SKEL_FSBR)
			break;
		fsbr_qh = tqh;
	}

	/* No FSBR QH means we must insert the terminating skeleton QH */
	if (!fsbr_qh) {
		uhci->skel_term_qh->link = LINK_TO_QH(uhci->skel_term_qh);
		wmb();
		lqh->link = uhci->skel_term_qh->link;

	/* Otherwise loop the last QH to the first FSBR QH */
	} else
		lqh->link = LINK_TO_QH(fsbr_qh);
}
}


static void uhci_fsbr_off(struct uhci_hcd *uhci)
static void uhci_fsbr_off(struct uhci_hcd *uhci)
{
{
	struct uhci_qh *lqh;
	struct uhci_qh *lqh;


	/* Remove the link from the last async QH to the terminating
	 * skeleton QH. */
	uhci->fsbr_is_on = 0;
	uhci->fsbr_is_on = 0;
	lqh = list_entry(uhci->skel_async_qh->node.prev,
	lqh = list_entry(uhci->skel_async_qh->node.prev,
			struct uhci_qh, node);
			struct uhci_qh, node);

	lqh->link = UHCI_PTR_TERM;
	/* End the async list normally and unlink the terminating QH */
	lqh->link = uhci->skel_term_qh->link = UHCI_PTR_TERM;
}
}


static void uhci_add_fsbr(struct uhci_hcd *uhci, struct urb *urb)
static void uhci_add_fsbr(struct uhci_hcd *uhci, struct urb *urb)
@@ -464,9 +448,8 @@ static void link_interrupt(struct uhci_hcd *uhci, struct uhci_qh *qh)
 */
 */
static void link_async(struct uhci_hcd *uhci, struct uhci_qh *qh)
static void link_async(struct uhci_hcd *uhci, struct uhci_qh *qh)
{
{
	struct uhci_qh *pqh, *lqh;
	struct uhci_qh *pqh;
	__le32 link_to_new_qh;
	__le32 link_to_new_qh;
	__le32 *extra_link = &link_to_new_qh;


	/* Find the predecessor QH for our new one and insert it in the list.
	/* Find the predecessor QH for our new one and insert it in the list.
	 * The list of QHs is expected to be short, so linear search won't
	 * The list of QHs is expected to be short, so linear search won't
@@ -476,31 +459,17 @@ static void link_async(struct uhci_hcd *uhci, struct uhci_qh *qh)
			break;
			break;
	}
	}
	list_add(&qh->node, &pqh->node);
	list_add(&qh->node, &pqh->node);
	qh->link = pqh->link;

	link_to_new_qh = LINK_TO_QH(qh);

	/* If this is now the first FSBR QH, take special action */
	if (uhci->fsbr_is_on && pqh->skel < SKEL_FSBR &&
			qh->skel >= SKEL_FSBR) {
		lqh = list_entry(uhci->skel_async_qh->node.prev,
				struct uhci_qh, node);

		/* If the new QH is also the last one, we must unlink
		 * the terminating skeleton QH and make the new QH point
		 * back to itself. */
		if (qh == lqh) {
			qh->link = link_to_new_qh;
			extra_link = &uhci->skel_term_qh->link;

		/* Otherwise the last QH must point to the new QH */
		} else
			extra_link = &lqh->link;
	}


	/* Link it into the schedule */
	/* Link it into the schedule */
	qh->link = pqh->link;
	wmb();
	wmb();
	*extra_link = pqh->link = link_to_new_qh;
	link_to_new_qh = LINK_TO_QH(qh);
	pqh->link = link_to_new_qh;

	/* If this is now the first FSBR QH, link the terminating skeleton
	 * QH to it. */
	if (pqh->skel < SKEL_FSBR && qh->skel >= SKEL_FSBR)
		uhci->skel_term_qh->link = link_to_new_qh;
}
}


/*
/*
@@ -561,31 +530,16 @@ static void unlink_interrupt(struct uhci_hcd *uhci, struct uhci_qh *qh)
 */
 */
static void unlink_async(struct uhci_hcd *uhci, struct uhci_qh *qh)
static void unlink_async(struct uhci_hcd *uhci, struct uhci_qh *qh)
{
{
	struct uhci_qh *pqh, *lqh;
	struct uhci_qh *pqh;
	__le32 link_to_next_qh = qh->link;
	__le32 link_to_next_qh = qh->link;


	pqh = list_entry(qh->node.prev, struct uhci_qh, node);
	pqh = list_entry(qh->node.prev, struct uhci_qh, node);
	pqh->link = link_to_next_qh;


	/* If this is the first FSBQ QH, take special action */
	/* If this was the old first FSBR QH, link the terminating skeleton
	if (uhci->fsbr_is_on && pqh->skel < SKEL_FSBR &&
	 * QH to the next (new first FSBR) QH. */
			qh->skel >= SKEL_FSBR) {
	if (pqh->skel < SKEL_FSBR && qh->skel >= SKEL_FSBR)
		lqh = list_entry(uhci->skel_async_qh->node.prev,
				struct uhci_qh, node);

		/* If this QH is also the last one, we must link in
		 * the terminating skeleton QH. */
		if (qh == lqh) {
			link_to_next_qh = LINK_TO_QH(uhci->skel_term_qh);
		uhci->skel_term_qh->link = link_to_next_qh;
		uhci->skel_term_qh->link = link_to_next_qh;
			wmb();
			qh->link = link_to_next_qh;

		/* Otherwise the last QH must point to the new first FSBR QH */
		} else
			lqh->link = link_to_next_qh;
	}

	pqh->link = link_to_next_qh;
	mb();
	mb();
}
}


@@ -1217,7 +1171,7 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)


				if (debug > 1 && errbuf) {
				if (debug > 1 && errbuf) {
					/* Print the chain for debugging */
					/* Print the chain for debugging */
					uhci_show_qh(urbp->qh, errbuf,
					uhci_show_qh(uhci, urbp->qh, errbuf,
							ERRBUF_LEN, 0);
							ERRBUF_LEN, 0);
					lprintk(errbuf);
					lprintk(errbuf);
				}
				}
Loading