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

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
...@@ -30,7 +30,8 @@ ...@@ -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 },
......
...@@ -296,6 +296,15 @@ omap_free_request(struct usb_ep *ep, struct usb_request *_req) ...@@ -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( ...@@ -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( ...@@ -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,13 +374,29 @@ static void omap_free_buffer( ...@@ -333,13 +374,29 @@ static void omap_free_buffer(
unsigned bytes unsigned bytes
) )
{ {
struct omap_ep *ep; if (!_ep) {
WARN_ON(1);
return;
}
ep = container_of(_ep, struct omap_ep, ep); /* free memory into the right allocator */
if (use_dma && _ep && ep->has_dma) if (dma != DMA_ADDR_INVALID) {
dma_free_coherent(ep->udc->gadget.dev.parent, bytes, buf, dma); struct omap_ep *ep;
else struct free_record *rec = buf;
kfree (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);
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -1691,12 +1748,38 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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
......
...@@ -145,7 +145,8 @@ static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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;
goto check_qh_link; if (!link)
continue; link = LINK_TO_QH(uhci->skel_term_qh);
goto check_qh_link;
} }
head = &qh->node; head = &qh->node;
...@@ -448,7 +454,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) ...@@ -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) ...@@ -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 = { ...@@ -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;
} }
......
...@@ -632,7 +632,8 @@ static int uhci_start(struct usb_hcd *hcd) ...@@ -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) |
......
...@@ -45,43 +45,27 @@ static inline void uhci_clear_next_interrupt(struct uhci_hcd *uhci) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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);
/* If this is the first FSBQ 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 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;
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; pqh->link = link_to_next_qh;
/* If this was the old first FSBR QH, link the terminating skeleton
* QH to the next (new first FSBR) QH. */
if (pqh->skel < SKEL_FSBR && qh->skel >= SKEL_FSBR)
uhci->skel_term_qh->link = link_to_next_qh;
mb(); mb();
} }
...@@ -1217,7 +1171,7 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb) ...@@ -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);
} }
......
...@@ -18,7 +18,6 @@ ...@@ -18,7 +18,6 @@
static struct usb_device_id id_table [] = { static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x0c88, 0x17da) }, /* Kyocera Wireless KPC650/Passport */ { USB_DEVICE(0x0c88, 0x17da) }, /* Kyocera Wireless KPC650/Passport */
{ USB_DEVICE(0x1410, 0x1100) }, /* ExpressCard34 Qualcomm 3G CDMA */
{ USB_DEVICE(0x413c, 0x8115) }, /* Dell Wireless HSDPA 5500 */ { USB_DEVICE(0x413c, 0x8115) }, /* Dell Wireless HSDPA 5500 */
{ }, { },
}; };
......
...@@ -879,6 +879,7 @@ static __u32 get_ftdi_divisor(struct usb_serial_port * port) ...@@ -879,6 +879,7 @@ static __u32 get_ftdi_divisor(struct usb_serial_port * port)
break; break;
case FT232BM: /* FT232BM chip */ case FT232BM: /* FT232BM chip */
case FT2232C: /* FT2232C chip */ case FT2232C: /* FT2232C chip */
case FT232RL:
if (baud <= 3000000) { if (baud <= 3000000) {
div_value = ftdi_232bm_baud_to_divisor(baud); div_value = ftdi_232bm_baud_to_divisor(baud);
} else { } else {
...@@ -1021,9 +1022,12 @@ static void ftdi_determine_type(struct usb_serial_port *port) ...@@ -1021,9 +1022,12 @@ static void ftdi_determine_type(struct usb_serial_port *port)
/* (It might be a BM because of the iSerialNumber bug, /* (It might be a BM because of the iSerialNumber bug,
* but it will still work as an AM device.) */ * but it will still work as an AM device.) */
priv->chip_type = FT8U232AM; priv->chip_type = FT8U232AM;
} else { } else if (version < 0x600) {
/* Assume its an FT232BM (or FT245BM) */ /* Assume its an FT232BM (or FT245BM) */
priv->chip_type = FT232BM; priv->chip_type = FT232BM;
} else {
/* Assume its an FT232R */
priv->chip_type = FT232RL;
} }
info("Detected %s", ftdi_chip_name[priv->chip_type]); info("Detected %s", ftdi_chip_name[priv->chip_type]);
} }
......
...@@ -20,13 +20,14 @@ ...@@ -20,13 +20,14 @@
#include <linux/usb/serial.h> #include <linux/usb/serial.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
static int generic_probe(struct usb_interface *interface,
const struct usb_device_id *id);
static int debug; static int debug;
#ifdef CONFIG_USB_SERIAL_GENERIC #ifdef CONFIG_USB_SERIAL_GENERIC
static int generic_probe(struct usb_interface *interface,
const struct usb_device_id *id);
static __u16 vendor = 0x05f9; static __u16 vendor = 0x05f9;
static __u16 product = 0xffff; static __u16 product = 0xffff;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment