This resolves a merge issue with the option.c USB serial driver.
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
CLK(NULL, "usbhost_48m_fck", &usbhost_48m_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK(NULL, "usbhost_ick", &usbhost_ick, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK("usbhs_omap", "usbhost_ick", &usbhost_ick, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
- CLK("usbhs_omap", "utmi_p1_gfclk", &dummy_ck, CK_3XXX),
- CLK("usbhs_omap", "utmi_p2_gfclk", &dummy_ck, CK_3XXX),
- CLK("usbhs_omap", "xclk60mhsp1_ck", &dummy_ck, CK_3XXX),
- CLK("usbhs_omap", "xclk60mhsp2_ck", &dummy_ck, CK_3XXX),
- CLK("usbhs_omap", "usb_host_hs_utmi_p1_clk", &dummy_ck, CK_3XXX),
- CLK("usbhs_omap", "usb_host_hs_utmi_p2_clk", &dummy_ck, CK_3XXX),
+ CLK(NULL, "utmi_p1_gfclk", &dummy_ck, CK_3XXX),
+ CLK(NULL, "utmi_p2_gfclk", &dummy_ck, CK_3XXX),
+ CLK(NULL, "xclk60mhsp1_ck", &dummy_ck, CK_3XXX),
+ CLK(NULL, "xclk60mhsp2_ck", &dummy_ck, CK_3XXX),
+ CLK(NULL, "usb_host_hs_utmi_p1_clk", &dummy_ck, CK_3XXX),
+ CLK(NULL, "usb_host_hs_utmi_p2_clk", &dummy_ck, CK_3XXX),
CLK("usbhs_omap", "usb_tll_hs_usb_ch0_clk", &dummy_ck, CK_3XXX),
CLK("usbhs_omap", "usb_tll_hs_usb_ch1_clk", &dummy_ck, CK_3XXX),
- CLK("usbhs_omap", "init_60m_fclk", &dummy_ck, CK_3XXX),
+ CLK(NULL, "init_60m_fclk", &dummy_ck, CK_3XXX),
CLK(NULL, "usim_fck", &usim_fck, CK_3430ES2PLUS | CK_36XX),
CLK(NULL, "gpt1_fck", &gpt1_fck, CK_3XXX),
CLK(NULL, "wkup_32k_fck", &wkup_32k_fck, CK_3XXX),
#define DRIVER_AUTHOR "Oliver Neukum"
#define DRIVER_DESC "USB Abstract Control Model driver for USB WCM Device Management"
-#define HUAWEI_VENDOR_ID 0x12D1
-
static const struct usb_device_id wdm_ids[] = {
{
.match_flags = USB_DEVICE_ID_MATCH_INT_CLASS |
.bInterfaceClass = USB_CLASS_COMM,
.bInterfaceSubClass = USB_CDC_SUBCLASS_DMM
},
- {
- /*
- * Huawei E392, E398 and possibly other Qualcomm based modems
- * embed the Qualcomm QMI protocol inside CDC on CDC ECM like
- * control interfaces. Userspace access to this is required
- * to configure the accompanying data interface
- */
- .match_flags = USB_DEVICE_ID_MATCH_VENDOR |
- USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = HUAWEI_VENDOR_ID,
- .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 9, /* NOTE: CDC ECM control interface! */
- },
- {
- /* Vodafone/Huawei K5005 (12d1:14c8) and similar modems */
- .match_flags = USB_DEVICE_ID_MATCH_VENDOR |
- USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = HUAWEI_VENDOR_ID,
- .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 57, /* NOTE: CDC ECM control interface! */
- },
{ }
};
return error;
err:
+ usb_set_intfdata(intf, NULL);
intf->needs_remote_wakeup = 0;
intf->condition = USB_INTERFACE_UNBOUND;
usb_cancel_queued_reset(intf);
if (!usb_match_device(dev, id))
return 0;
- /* The interface class, subclass, and protocol should never be
+ /* The interface class, subclass, protocol and number should never be
* checked for a match if the device class is Vendor Specific,
* unless the match record specifies the Vendor ID. */
if (dev->descriptor.bDeviceClass == USB_CLASS_VENDOR_SPEC &&
!(id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
(id->match_flags & (USB_DEVICE_ID_MATCH_INT_CLASS |
USB_DEVICE_ID_MATCH_INT_SUBCLASS |
- USB_DEVICE_ID_MATCH_INT_PROTOCOL)))
+ USB_DEVICE_ID_MATCH_INT_PROTOCOL |
+ USB_DEVICE_ID_MATCH_INT_NUMBER)))
return 0;
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) &&
(id->bInterfaceProtocol != intf->desc.bInterfaceProtocol))
return 0;
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_NUMBER) &&
+ (id->bInterfaceNumber != intf->desc.bInterfaceNumber))
+ return 0;
+
return 1;
}
EXPORT_SYMBOL_GPL(usb_match_one_id);
}
kref_init(&usb_class->kref);
- usb_class->class = class_create(THIS_MODULE, "usb");
+ usb_class->class = class_create(THIS_MODULE, "usbmisc");
if (IS_ERR(usb_class->class)) {
result = IS_ERR(usb_class->class);
printk(KERN_ERR "class_create failed for usb devices\n");
if (add_uevent_var(env,
"MODALIAS=usb:"
- "v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X",
+ "v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02Xin%02X",
le16_to_cpu(usb_dev->descriptor.idVendor),
le16_to_cpu(usb_dev->descriptor.idProduct),
le16_to_cpu(usb_dev->descriptor.bcdDevice),
usb_dev->descriptor.bDeviceProtocol,
alt->desc.bInterfaceClass,
alt->desc.bInterfaceSubClass,
- alt->desc.bInterfaceProtocol))
+ alt->desc.bInterfaceProtocol,
+ alt->desc.bInterfaceNumber))
return -ENOMEM;
return 0;
alt = intf->cur_altsetting;
return sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02X"
- "ic%02Xisc%02Xip%02X\n",
+ "ic%02Xisc%02Xip%02Xin%02X\n",
le16_to_cpu(udev->descriptor.idVendor),
le16_to_cpu(udev->descriptor.idProduct),
le16_to_cpu(udev->descriptor.bcdDevice),
udev->descriptor.bDeviceProtocol,
alt->desc.bInterfaceClass,
alt->desc.bInterfaceSubClass,
- alt->desc.bInterfaceProtocol);
+ alt->desc.bInterfaceProtocol,
+ alt->desc.bInterfaceNumber);
}
static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
int ret;
read = (requesttype & USB_DIR_IN) != 0;
- if (size > (read ? DBGP_MAX_PACKET:0))
+ if (size > (read ? DBGP_MAX_PACKET : 0))
return -1;
/* Compute the control message */
select USB_OHCI_HCD_PLATFORM if USB_OHCI_HCD
select USB_EHCI_HCD_PLATFORM if USB_EHCI_HCD
help
- Enbale support for the EHCI and OCHI host controller on an bcma bus.
+ Enable support for the EHCI and OCHI host controller on an bcma bus.
It converts the bcma driver into two platform device drivers
for ehci and ohci.
select USB_OHCI_HCD_PLATFORM if USB_OHCI_HCD
select USB_EHCI_HCD_PLATFORM if USB_EHCI_HCD
help
- Enbale support for the EHCI and OCHI host controller on an bcma bus.
+ Enable support for the EHCI and OCHI host controller on an bcma bus.
It converts the bcma driver into two platform device drivers
for ehci and ohci.
if (pdata->operating_mode == FSL_USB2_DR_OTG) {
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
- ehci->transceiver = usb_get_transceiver();
- dev_dbg(&pdev->dev, "hcd=0x%p ehci=0x%p, transceiver=0x%p\n",
- hcd, ehci, ehci->transceiver);
+ hcd->phy = usb_get_transceiver();
+ dev_dbg(&pdev->dev, "hcd=0x%p ehci=0x%p, phy=0x%p\n",
+ hcd, ehci, hcd->phy);
- if (ehci->transceiver) {
- retval = otg_set_host(ehci->transceiver->otg,
+ if (hcd->phy) {
+ retval = otg_set_host(hcd->phy->otg,
&ehci_to_hcd(ehci)->self);
if (retval) {
- usb_put_transceiver(ehci->transceiver);
+ usb_put_transceiver(hcd->phy);
goto err4;
}
} else {
- dev_err(&pdev->dev, "can't find transceiver\n");
+ dev_err(&pdev->dev, "can't find phy\n");
retval = -ENODEV;
goto err4;
}
struct platform_device *pdev)
{
struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
- struct ehci_hcd *ehci = hcd_to_ehci(hcd);
- if (ehci->transceiver) {
- otg_set_host(ehci->transceiver->otg, NULL);
- usb_put_transceiver(ehci->transceiver);
+ if (hcd->phy) {
+ otg_set_host(hcd->phy->otg, NULL);
+ usb_put_transceiver(hcd->phy);
}
usb_remove_hcd(hcd);
/* check TDI/ARC silicon is in host mode */
static int tdi_in_host_mode (struct ehci_hcd *ehci)
{
- u32 __iomem *reg_ptr;
u32 tmp;
- reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + USBMODE);
- tmp = ehci_readl(ehci, reg_ptr);
+ tmp = ehci_readl(ehci, &ehci->regs->usbmode);
return (tmp & 3) == USBMODE_CM_HC;
}
/* put TDI/ARC silicon into EHCI mode */
static void tdi_reset (struct ehci_hcd *ehci)
{
- u32 __iomem *reg_ptr;
u32 tmp;
- reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + USBMODE);
- tmp = ehci_readl(ehci, reg_ptr);
+ tmp = ehci_readl(ehci, &ehci->regs->usbmode);
tmp |= USBMODE_CM_HC;
/* The default byte access to MMR space is LE after
* controller reset. Set the required endian mode
*/
if (ehci_big_endian_mmio(ehci))
tmp |= USBMODE_BE;
- ehci_writel(ehci, tmp, reg_ptr);
+ ehci_writel(ehci, tmp, &ehci->regs->usbmode);
}
/* reset a non-running (STS_HALT == 1) controller */
if (ehci->has_hostpc) {
ehci_writel(ehci, USBMODE_EX_HC | USBMODE_EX_VBPS,
- (u32 __iomem *)(((u8 *)ehci->regs) + USBMODE_EX));
- ehci_writel(ehci, TXFIFO_DEFAULT,
- (u32 __iomem *)(((u8 *)ehci->regs) + TXFILLTUNING));
+ &ehci->regs->usbmode_ex);
+ ehci_writel(ehci, TXFIFO_DEFAULT, &ehci->regs->txfill_tuning);
}
if (retval)
return retval;
if (ehci->has_hostpc) {
port = HCS_N_PORTS(ehci->hcs_params);
while (port--) {
- u32 __iomem *hostpc_reg;
+ u32 __iomem *hostpc_reg = &ehci->regs->hostpc[port];
- hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs
- + HOSTPC0 + 4 * port);
temp = ehci_readl(ehci, hostpc_reg);
ehci_writel(ehci, temp & ~HOSTPC_PHCD, hostpc_reg);
}
if (ehci->has_hostpc) {
port = HCS_N_PORTS(ehci->hcs_params);
while (port--) {
- u32 __iomem *hostpc_reg;
+ u32 __iomem *hostpc_reg = &ehci->regs->hostpc[port];
- hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs
- + HOSTPC0 + 4 * port);
temp = ehci_readl(ehci, hostpc_reg);
ehci_writel(ehci, temp | HOSTPC_PHCD, hostpc_reg);
}
port = HCS_N_PORTS(ehci->hcs_params);
while (port--) {
- u32 __iomem *hostpc_reg;
+ u32 __iomem *hostpc_reg = &ehci->regs->hostpc[port];
u32 t3;
- hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs
- + HOSTPC0 + 4 * port);
t3 = ehci_readl(ehci, hostpc_reg);
ehci_writel(ehci, t3 | HOSTPC_PHCD, hostpc_reg);
t3 = ehci_readl(ehci, hostpc_reg);
i = HCS_N_PORTS(ehci->hcs_params);
while (i--) {
if (test_bit(i, &ehci->bus_suspended)) {
- u32 __iomem *hostpc_reg;
+ u32 __iomem *hostpc_reg =
+ &ehci->regs->hostpc[i];
- hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs
- + HOSTPC0 + 4 * i);
temp = ehci_readl(ehci, hostpc_reg);
ehci_writel(ehci, temp & ~HOSTPC_PHCD,
hostpc_reg);
int ports = HCS_N_PORTS (ehci->hcs_params);
u32 __iomem *status_reg = &ehci->regs->port_status[
(wIndex & 0xff) - 1];
- u32 __iomem *hostpc_reg = NULL;
+ u32 __iomem *hostpc_reg = &ehci->regs->hostpc[(wIndex & 0xff) - 1];
u32 temp, temp1, status;
unsigned long flags;
int retval = 0;
* power, "this is the one", etc. EHCI spec supports this.
*/
- if (ehci->has_hostpc)
- hostpc_reg = (u32 __iomem *)((u8 *)ehci->regs
- + HOSTPC0 + 4 * ((wIndex & 0xff) - 1));
spin_lock_irqsave (&ehci->lock, flags);
switch (typeReq) {
case ClearHubFeature:
#ifdef CONFIG_USB_OTG
if ((hcd->self.otg_port == (wIndex + 1))
&& hcd->self.b_hnp_enable) {
- otg_start_hnp(ehci->transceiver->otg);
+ otg_start_hnp(hcd->phy->otg);
break;
}
#endif
goto error;
/* clear phy low-power mode before resume */
- if (hostpc_reg) {
+ if (ehci->has_hostpc) {
temp1 = ehci_readl(ehci, hostpc_reg);
ehci_writel(ehci, temp1 & ~HOSTPC_PHCD,
hostpc_reg);
temp &= ~PORT_WKCONN_E;
temp |= PORT_WKDISC_E | PORT_WKOC_E;
ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
- if (hostpc_reg) {
+ if (ehci->has_hostpc) {
spin_unlock_irqrestore(&ehci->lock, flags);
msleep(5);/* 5ms for HCD enter low pwr mode */
spin_lock_irqsave(&ehci->lock, flags);
ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (ret) {
dev_err(dev, "failed to add hcd with err %d\n", ret);
- goto err_add_hcd;
+ goto err_pm_runtime;
}
/* root ports should always stay powered */
clk_put(utmi_p1_fck);
err_add_hcd:
+ usb_remove_hcd(hcd);
+
+err_pm_runtime:
disable_put_regulator(pdata);
pm_runtime_put_sync(dev);
+ usb_put_hcd(hcd);
err_io:
iounmap(regs);
#ifdef DEBUG
struct dentry *debug_dir;
#endif
- /*
- * OTG controllers and transceivers need software interaction
- */
- struct usb_phy *transceiver;
};
/* convert between an HCD pointer and the corresponding EHCI_HCD */
static int fhci_dfs_regs_show(struct seq_file *s, void *v)
{
struct fhci_hcd *fhci = s->private;
- struct fhci_regs __iomem *regs = fhci->regs;
+ struct qe_usb_ctlr __iomem *regs = fhci->regs;
seq_printf(s,
"mode: 0x%x\n" "addr: 0x%x\n"
"status: 0x%x\n" "SOF timer: %d\n"
"frame number: %d\n"
"lines status: 0x%x\n",
- in_8(®s->usb_mod), in_8(®s->usb_addr),
- in_8(®s->usb_comm), in_be16(®s->usb_ep[0]),
- in_be16(®s->usb_event), in_be16(®s->usb_mask),
- in_8(®s->usb_status), in_be16(®s->usb_sof_tmr),
- in_be16(®s->usb_frame_num),
+ in_8(®s->usb_usmod), in_8(®s->usb_usadr),
+ in_8(®s->usb_uscom), in_be16(®s->usb_usep[0]),
+ in_be16(®s->usb_usber), in_be16(®s->usb_usbmr),
+ in_8(®s->usb_usbs), in_be16(®s->usb_ussft),
+ in_be16(®s->usb_usfrn),
fhci_ioports_check_bus_state(fhci));
return 0;
/* clear frame_n */
out_be16(&fhci->pram->frame_num, 0);
- out_be16(&fhci->regs->usb_sof_tmr, 0);
- setbits8(&fhci->regs->usb_mod, USB_MODE_SFTE);
+ out_be16(&fhci->regs->usb_ussft, 0);
+ setbits8(&fhci->regs->usb_usmod, USB_MODE_SFTE);
fhci_dbg(fhci, "<- %s\n", __func__);
}
{
fhci_dbg(fhci, "-> %s\n", __func__);
- clrbits8(&fhci->regs->usb_mod, USB_MODE_SFTE);
+ clrbits8(&fhci->regs->usb_usmod, USB_MODE_SFTE);
gtm_stop_timer16(fhci->timer);
fhci_dbg(fhci, "<- %s\n", __func__);
u16 fhci_get_sof_timer_count(struct fhci_usb *usb)
{
- return be16_to_cpu(in_be16(&usb->fhci->regs->usb_sof_tmr) / 12);
+ return be16_to_cpu(in_be16(&usb->fhci->regs->usb_ussft) / 12);
}
/* initialize the endpoint zero */
enable_irq(fhci_to_hcd(fhci)->irq);
/* initialize the event register and mask register */
- out_be16(&usb->fhci->regs->usb_event, 0xffff);
- out_be16(&usb->fhci->regs->usb_mask, usb->saved_msk);
+ out_be16(&usb->fhci->regs->usb_usber, 0xffff);
+ out_be16(&usb->fhci->regs->usb_usbmr, usb->saved_msk);
/* enable the timer interrupts */
enable_irq(fhci->timer->irq);
/* disable the usb interrupt */
disable_irq_nosync(fhci_to_hcd(fhci)->irq);
- out_be16(&usb->fhci->regs->usb_mask, 0);
+ out_be16(&usb->fhci->regs->usb_usbmr, 0);
}
usb->intr_nesting_cnt++;
}
{
struct fhci_usb *usb = fhci->usb_lld;
- out_be16(&usb->fhci->regs->usb_event, 0xffff);
- out_be16(&usb->fhci->regs->usb_mask, usb->saved_msk);
- setbits8(&usb->fhci->regs->usb_mod, USB_MODE_EN);
+ out_be16(&usb->fhci->regs->usb_usber, 0xffff);
+ out_be16(&usb->fhci->regs->usb_usbmr, usb->saved_msk);
+ setbits8(&usb->fhci->regs->usb_usmod, USB_MODE_EN);
mdelay(100);
usb->port_status == FHCI_PORT_LOW)
fhci_device_disconnected_interrupt(fhci);
- clrbits8(&usb->fhci->regs->usb_mod, USB_MODE_EN);
+ clrbits8(&usb->fhci->regs->usb_usmod, USB_MODE_EN);
return 0;
}
USB_E_IDLE_MASK |
USB_E_RESET_MASK | USB_E_SFT_MASK | USB_E_MSF_MASK);
- out_8(&usb->fhci->regs->usb_mod, USB_MODE_HOST | USB_MODE_EN);
+ out_8(&usb->fhci->regs->usb_usmod, USB_MODE_HOST | USB_MODE_EN);
/* clearing the mask register */
- out_be16(&usb->fhci->regs->usb_mask, 0);
+ out_be16(&usb->fhci->regs->usb_usbmr, 0);
/* initialing the event register */
- out_be16(&usb->fhci->regs->usb_event, 0xffff);
+ out_be16(&usb->fhci->regs->usb_usber, 0xffff);
if (endpoint_zero_init(usb, DEFAULT_DATA_MEM, DEFAULT_RING_LEN) != 0) {
fhci_usb_free(usb);
}
/* Clear and disable any pending interrupts. */
- out_be16(&fhci->regs->usb_event, 0xffff);
- out_be16(&fhci->regs->usb_mask, 0);
+ out_be16(&fhci->regs->usb_usber, 0xffff);
+ out_be16(&fhci->regs->usb_usbmr, 0);
ret = usb_add_hcd(hcd, usb_irq, 0);
if (ret < 0)
/* Enable IDLE since we want to know if something comes along */
usb->saved_msk |= USB_E_IDLE_MASK;
- out_be16(&usb->fhci->regs->usb_mask, usb->saved_msk);
+ out_be16(&usb->fhci->regs->usb_usbmr, usb->saved_msk);
/* check if during the disconnection process attached new device */
if (port_status == FHCI_PORT_WAITING)
fhci_stop_sof_timer(fhci);
/* disable the USB controller */
- mode = in_8(&fhci->regs->usb_mod);
- out_8(&fhci->regs->usb_mod, mode & (~USB_MODE_EN));
+ mode = in_8(&fhci->regs->usb_usmod);
+ out_8(&fhci->regs->usb_usmod, mode & (~USB_MODE_EN));
/* disable idle interrupts */
- mask = in_be16(&fhci->regs->usb_mask);
- out_be16(&fhci->regs->usb_mask, mask & (~USB_E_IDLE_MASK));
+ mask = in_be16(&fhci->regs->usb_usbmr);
+ out_be16(&fhci->regs->usb_usbmr, mask & (~USB_E_IDLE_MASK));
fhci_io_port_generate_reset(fhci);
/* enable interrupt on this endpoint */
- out_be16(&fhci->regs->usb_mask, mask);
+ out_be16(&fhci->regs->usb_usbmr, mask);
/* enable the USB controller */
- mode = in_8(&fhci->regs->usb_mod);
- out_8(&fhci->regs->usb_mod, mode | USB_MODE_EN);
+ mode = in_8(&fhci->regs->usb_usmod);
+ out_8(&fhci->regs->usb_usmod, mode | USB_MODE_EN);
fhci_start_sof_timer(fhci);
fhci_dbg(fhci, "<- %s\n", __func__);
u8 mode;
struct td *td;
- mode = in_8(&usb->fhci->regs->usb_mod);
- clrbits8(&usb->fhci->regs->usb_mod, USB_MODE_EN);
+ mode = in_8(&usb->fhci->regs->usb_usmod);
+ clrbits8(&usb->fhci->regs->usb_usmod, USB_MODE_EN);
fhci_flush_bds(usb);
usb->actual_frame->frame_status = FRAME_END_TRANSMISSION;
/* reset the event register */
- out_be16(&usb->fhci->regs->usb_event, 0xffff);
+ out_be16(&usb->fhci->regs->usb_usber, 0xffff);
/* enable the USB controller */
- out_8(&usb->fhci->regs->usb_mod, mode | USB_MODE_EN);
+ out_8(&usb->fhci->regs->usb_usmod, mode | USB_MODE_EN);
}
/*
usb->port_status = FHCI_PORT_FULL;
/* Disable IDLE */
usb->saved_msk &= ~USB_E_IDLE_MASK;
- out_be16(&usb->fhci->regs->usb_mask, usb->saved_msk);
+ out_be16(&usb->fhci->regs->usb_usbmr, usb->saved_msk);
}
gtm_set_exact_timer16(fhci->timer, usb->max_frame_usage, false);
fhci_dbg(fhci, "-> %s\n", __func__);
fhci_usb_disable_interrupt(usb);
- clrbits8(&usb->fhci->regs->usb_mod, USB_MODE_LSS);
+ clrbits8(&usb->fhci->regs->usb_usmod, USB_MODE_LSS);
usb->port_status = FHCI_PORT_DISABLED;
fhci_stop_sof_timer(fhci);
/* Enable IDLE since we want to know if something comes along */
usb->saved_msk |= USB_E_IDLE_MASK;
- out_be16(&usb->fhci->regs->usb_mask, usb->saved_msk);
+ out_be16(&usb->fhci->regs->usb_usbmr, usb->saved_msk);
usb->vroot_hub->port.wPortStatus &= ~USB_PORT_STAT_CONNECTION;
usb->vroot_hub->port.wPortChange |= USB_PORT_STAT_C_CONNECTION;
}
usb->port_status = FHCI_PORT_LOW;
- setbits8(&usb->fhci->regs->usb_mod, USB_MODE_LSS);
+ setbits8(&usb->fhci->regs->usb_usmod, USB_MODE_LSS);
usb->vroot_hub->port.wPortStatus |=
(USB_PORT_STAT_LOW_SPEED |
USB_PORT_STAT_CONNECTION);
}
usb->port_status = FHCI_PORT_FULL;
- clrbits8(&usb->fhci->regs->usb_mod, USB_MODE_LSS);
+ clrbits8(&usb->fhci->regs->usb_usmod, USB_MODE_LSS);
usb->vroot_hub->port.wPortStatus &=
~USB_PORT_STAT_LOW_SPEED;
usb->vroot_hub->port.wPortStatus |=
/* issue stop Tx command */
qe_issue_cmd(QE_USB_STOP_TX, QE_CR_SUBBLOCK_USB, EP_ZERO, 0);
/* flush Tx FIFOs */
- out_8(&usb->fhci->regs->usb_comm, USB_CMD_FLUSH_FIFO | EP_ZERO);
+ out_8(&usb->fhci->regs->usb_uscom, USB_CMD_FLUSH_FIFO | EP_ZERO);
udelay(1000);
/* reset Tx BDs */
fhci_flush_bds(usb);
usb = fhci->usb_lld;
- usb_er |= in_be16(&usb->fhci->regs->usb_event) &
- in_be16(&usb->fhci->regs->usb_mask);
+ usb_er |= in_be16(&usb->fhci->regs->usb_usber) &
+ in_be16(&usb->fhci->regs->usb_usbmr);
/* clear event bits for next time */
- out_be16(&usb->fhci->regs->usb_event, usb_er);
+ out_be16(&usb->fhci->regs->usb_usber, usb_er);
fhci_dbg_isr(fhci, usb_er);
/* Turn on IDLE since we want to disconnect */
usb->saved_msk |= USB_E_IDLE_MASK;
- out_be16(&usb->fhci->regs->usb_event,
+ out_be16(&usb->fhci->regs->usb_usber,
usb->saved_msk);
} else if (usb->port_status == FHCI_PORT_DISABLED) {
if (fhci_ioports_check_bus_state(fhci) == 1)
/* XXX usb->port_status = FHCI_PORT_WAITING; */
/* Disable IDLE */
usb->saved_msk &= ~USB_E_IDLE_MASK;
- out_be16(&usb->fhci->regs->usb_mask,
+ out_be16(&usb->fhci->regs->usb_usbmr,
usb->saved_msk);
} else {
fhci_dbg_isr(fhci, -1);
u8 rt;
/* set the endpoint registers according to the endpoint */
- out_be16(&usb->fhci->regs->usb_ep[0],
+ out_be16(&usb->fhci->regs->usb_usep[0],
USB_TRANS_CTR | USB_EP_MF | USB_EP_RTE);
out_be16(&usb->fhci->pram->ep_ptr[0],
cpm_muram_offset(ep->ep_pram_ptr));
cq_put(&ep->conf_frame_Q, pkt);
if (cq_howmany(&ep->conf_frame_Q) == 1)
- out_8(&usb->fhci->regs->usb_comm, USB_CMD_STR_FIFO);
+ out_8(&usb->fhci->regs->usb_uscom, USB_CMD_STR_FIFO);
return 0;
}
struct endpoint *ep = usb->ep0;
/* disable the USB controller */
- mode = in_8(&usb->fhci->regs->usb_mod);
- out_8(&usb->fhci->regs->usb_mod, mode & ~USB_MODE_EN);
+ mode = in_8(&usb->fhci->regs->usb_usmod);
+ out_8(&usb->fhci->regs->usb_usmod, mode & ~USB_MODE_EN);
tb_ptr = in_be16(&ep->ep_pram_ptr->tx_bd_ptr);
td = cpm_muram_addr(tb_ptr);
usb->actual_frame->frame_status = FRAME_TIMER_END_TRANSMISSION;
/* reset the event register */
- out_be16(&usb->fhci->regs->usb_event, 0xffff);
+ out_be16(&usb->fhci->regs->usb_usber, 0xffff);
/* enable the USB controller */
- out_8(&usb->fhci->regs->usb_mod, mode | USB_MODE_EN);
+ out_8(&usb->fhci->regs->usb_usmod, mode | USB_MODE_EN);
}
/* handles Tx confirm and Tx error interrupt */
/* start transmit only if we have something in the TDs */
if (in_be16(&td->status) & TD_R)
- out_8(&usb->fhci->regs->usb_comm, USB_CMD_STR_FIFO);
+ out_8(&usb->fhci->regs->usb_uscom, USB_CMD_STR_FIFO);
if (in_be32(&ep->conf_td->buf_ptr) == DUMMY_BD_BUFFER) {
out_be32(&old_td->buf_ptr, 0);
#include <linux/usb.h>
#include <linux/usb/hcd.h>
#include <asm/qe.h>
+#include <asm/immap_qe.h>
#define USB_CLOCK 48000000
#define USB_E_TXB_MASK 0x0002
#define USB_E_RXB_MASK 0x0001
-/* Freescale USB Host controller registers */
-struct fhci_regs {
- u8 usb_mod; /* mode register */
- u8 usb_addr; /* address register */
- u8 usb_comm; /* command register */
- u8 reserved1[1];
- __be16 usb_ep[4]; /* endpoint register */
- u8 reserved2[4];
- __be16 usb_event; /* event register */
- u8 reserved3[2];
- __be16 usb_mask; /* mask register */
- u8 reserved4[1];
- u8 usb_status; /* status register */
- __be16 usb_sof_tmr; /* Start Of Frame timer */
- u8 reserved5[2];
- __be16 usb_frame_num; /* frame number register */
- u8 reserved6[1];
-};
-
/* Freescale USB HOST */
struct fhci_pram {
__be16 ep_ptr[4]; /* Endpoint porter reg */
int gpios[NUM_GPIOS];
bool alow_gpios[NUM_GPIOS];
- struct fhci_regs __iomem *regs; /* I/O memory used to communicate */
+ struct qe_usb_ctlr __iomem *regs; /* I/O memory used to communicate */
struct fhci_pram __iomem *pram; /* Parameter RAM */
struct gtm_timer *timer;
#define USB_HOST_NEED_CLK_EN (1 << 21)
#define PAD_CONTROL_LAST_DRIVEN (1 << 19)
-#define USB_OTG_CLK_CTRL IO_ADDRESS(USB_CONFIG_BASE + 0xFF4)
-#define USB_OTG_CLK_STAT IO_ADDRESS(USB_CONFIG_BASE + 0xFF8)
-
-/* USB_OTG_CLK_CTRL bit defines */
-#define AHB_M_CLOCK_ON (1 << 4)
-#define OTG_CLOCK_ON (1 << 3)
-#define I2C_CLOCK_ON (1 << 2)
-#define DEV_CLOCK_ON (1 << 1)
-#define HOST_CLOCK_ON (1 << 0)
-
#define USB_OTG_STAT_CONTROL IO_ADDRESS(USB_CONFIG_BASE + 0x110)
/* USB_OTG_STAT_CONTROL bit defines */
extern int usb_disabled(void);
-static struct clk *usb_clk;
+static struct clk *usb_pll_clk;
+static struct clk *usb_dev_clk;
+static struct clk *usb_otg_clk;
static void isp1301_configure_pnx4008(void)
{
.start_port_reset = ohci_start_port_reset,
};
-#define USB_CLOCK_MASK (AHB_M_CLOCK_ON| OTG_CLOCK_ON | HOST_CLOCK_ON | I2C_CLOCK_ON)
-
static void nxp_set_usb_bits(void)
{
if (machine_is_pnx4008()) {
/* Enable AHB slave USB clock, needed for further USB clock control */
__raw_writel(USB_SLAVE_HCLK_EN | PAD_CONTROL_LAST_DRIVEN, USB_CTRL);
- isp1301_configure();
-
/* Enable USB PLL */
- usb_clk = clk_get(&pdev->dev, "ck_pll5");
- if (IS_ERR(usb_clk)) {
+ usb_pll_clk = clk_get(&pdev->dev, "ck_pll5");
+ if (IS_ERR(usb_pll_clk)) {
dev_err(&pdev->dev, "failed to acquire USB PLL\n");
- ret = PTR_ERR(usb_clk);
+ ret = PTR_ERR(usb_pll_clk);
goto out1;
}
- ret = clk_enable(usb_clk);
+ ret = clk_enable(usb_pll_clk);
if (ret < 0) {
dev_err(&pdev->dev, "failed to start USB PLL\n");
goto out2;
}
- ret = clk_set_rate(usb_clk, 48000);
+ ret = clk_set_rate(usb_pll_clk, 48000);
if (ret < 0) {
dev_err(&pdev->dev, "failed to set USB clock rate\n");
goto out3;
}
+ /* Enable USB device clock */
+ usb_dev_clk = clk_get(&pdev->dev, "ck_usbd");
+ if (IS_ERR(usb_dev_clk)) {
+ dev_err(&pdev->dev, "failed to acquire USB DEV Clock\n");
+ ret = PTR_ERR(usb_dev_clk);
+ goto out4;
+ }
+
+ ret = clk_enable(usb_dev_clk);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to start USB DEV Clock\n");
+ goto out5;
+ }
+
+ /* Enable USB otg clocks */
+ usb_otg_clk = clk_get(&pdev->dev, "ck_usb_otg");
+ if (IS_ERR(usb_otg_clk)) {
+ dev_err(&pdev->dev, "failed to acquire USB DEV Clock\n");
+ ret = PTR_ERR(usb_dev_clk);
+ goto out6;
+ }
+
__raw_writel(__raw_readl(USB_CTRL) | USB_HOST_NEED_CLK_EN, USB_CTRL);
- /* Set to enable all needed USB clocks */
- __raw_writel(USB_CLOCK_MASK, USB_OTG_CLK_CTRL);
+ ret = clk_enable(usb_otg_clk);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to start USB DEV Clock\n");
+ goto out7;
+ }
- while ((__raw_readl(USB_OTG_CLK_STAT) & USB_CLOCK_MASK) !=
- USB_CLOCK_MASK) ;
+ isp1301_configure();
hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
if (!hcd) {
dev_err(&pdev->dev, "Failed to allocate HC buffer\n");
ret = -ENOMEM;
- goto out3;
+ goto out8;
}
/* Set all USB bits in the Start Enable register */
if (!res) {
dev_err(&pdev->dev, "Failed to get MEM resource\n");
ret = -ENOMEM;
- goto out4;
+ goto out8;
}
hcd->regs = devm_request_and_ioremap(&pdev->dev, res);
if (!hcd->regs) {
dev_err(&pdev->dev, "Failed to devm_request_and_ioremap\n");
ret = -ENOMEM;
- goto out4;
+ goto out8;
}
hcd->rsrc_start = res->start;
hcd->rsrc_len = resource_size(res);
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
ret = -ENXIO;
- goto out4;
+ goto out8;
}
nxp_start_hc();
return ret;
nxp_stop_hc();
-out4:
+out8:
nxp_unset_usb_bits();
usb_put_hcd(hcd);
+out7:
+ clk_disable(usb_otg_clk);
+out6:
+ clk_put(usb_otg_clk);
+out5:
+ clk_disable(usb_dev_clk);
+out4:
+ clk_put(usb_dev_clk);
out3:
- clk_disable(usb_clk);
+ clk_disable(usb_pll_clk);
out2:
- clk_put(usb_clk);
+ clk_put(usb_pll_clk);
out1:
isp1301_i2c_client = NULL;
out:
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd);
nxp_unset_usb_bits();
- clk_disable(usb_clk);
- clk_put(usb_clk);
+ clk_disable(usb_pll_clk);
+ clk_put(usb_pll_clk);
+ clk_disable(usb_dev_clk);
+ clk_put(usb_dev_clk);
i2c_unregister_device(isp1301_i2c_client);
isp1301_i2c_client = NULL;
static void start_hnp(struct ohci_hcd *ohci)
{
- const unsigned port = ohci_to_hcd(ohci)->self.otg_port - 1;
+ struct usb_hcd *hcd = ohci_to_hcd(ohci);
+ const unsigned port = hcd->self.otg_port - 1;
unsigned long flags;
u32 l;
- otg_start_hnp(ohci->transceiver->otg);
+ otg_start_hnp(hcd->phy->otg);
local_irq_save(flags);
- ohci->transceiver->state = OTG_STATE_A_SUSPEND;
+ hcd->phy->state = OTG_STATE_A_SUSPEND;
writel (RH_PS_PSS, &ohci->regs->roothub.portstatus [port]);
l = omap_readl(OTG_CTRL);
l &= ~OTG_A_BUSREQ;
#ifdef CONFIG_USB_OTG
if (need_transceiver) {
- ohci->transceiver = usb_get_transceiver();
- if (ohci->transceiver) {
- int status = otg_set_host(ohci->transceiver->otg,
+ hcd->phy = usb_get_transceiver();
+ if (hcd->phy) {
+ int status = otg_set_host(hcd->phy->otg,
&ohci_to_hcd(ohci)->self);
- dev_dbg(hcd->self.controller, "init %s transceiver, status %d\n",
- ohci->transceiver->label, status);
+ dev_dbg(hcd->self.controller, "init %s phy, status %d\n",
+ hcd->phy->label, status);
if (status) {
- usb_put_transceiver(ohci->transceiver);
+ usb_put_transceiver(hcd->phy);
return status;
}
} else {
- dev_err(hcd->self.controller, "can't find transceiver\n");
+ dev_err(hcd->self.controller, "can't find phy\n");
return -ENODEV;
}
ohci->start_hnp = start_hnp;
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
usb_remove_hcd(hcd);
- if (ohci->transceiver) {
- (void) otg_set_host(ohci->transceiver->otg, 0);
- usb_put_transceiver(ohci->transceiver);
+ if (hcd->phy) {
+ (void) otg_set_host(hcd->phy->otg, 0);
+ usb_put_transceiver(hcd->phy);
}
if (machine_is_omap_osk())
gpio_free(9);
struct ed *ed_controltail; /* last in ctrl list */
struct ed *periodic [NUM_INTS]; /* shadow int_table */
- /*
- * OTG controllers and transceivers need software interaction;
- * other external transceivers should be software-transparent
- */
- struct usb_phy *transceiver;
void (*start_hnp)(struct ohci_hcd *ohci);
/*
static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct keyspan_port_private *p_priv;
- struct keyspan_serial_private *s_priv;
- struct usb_serial *serial = port->serial;
const struct keyspan_device_details *d_details;
int i, err;
int baud_rate, device_port;
struct urb *urb;
unsigned int cflag = 0;
- s_priv = usb_get_serial_data(serial);
p_priv = usb_get_serial_port_data(port);
d_details = p_priv->device_details;
{
int i;
struct usb_serial *serial = port->serial;
- struct keyspan_serial_private *s_priv;
struct keyspan_port_private *p_priv;
- s_priv = usb_get_serial_data(serial);
p_priv = usb_get_serial_port_data(port);
p_priv->rts_state = 0;
static bool debug;
+struct option_private {
+ u8 bInterfaceNumber;
+};
+
module_usb_serial_driver(serial_drivers, option_ids);
static bool is_blacklisted(const u8 ifnum, enum option_blacklist_reason reason,
const struct usb_device_id *id)
{
struct usb_wwan_intf_private *data;
-
- /* D-Link DWM 652 still exposes CD-Rom emulation interface in modem mode */
- if (serial->dev->descriptor.idVendor == DLINK_VENDOR_ID &&
- serial->dev->descriptor.idProduct == DLINK_PRODUCT_DWM_652 &&
- serial->interface->cur_altsetting->desc.bInterfaceClass == 0x8)
+ struct option_private *priv;
+ struct usb_interface_descriptor *iface_desc =
+ &serial->interface->cur_altsetting->desc;
+ struct usb_device_descriptor *dev_desc = &serial->dev->descriptor;
+
+ /*
+ * D-Link DWM 652 still exposes CD-Rom emulation interface in modem
+ * mode.
+ */
+ if (dev_desc->idVendor == DLINK_VENDOR_ID &&
+ dev_desc->idProduct == DLINK_PRODUCT_DWM_652 &&
+ iface_desc->bInterfaceClass == 0x08)
return -ENODEV;
/* Bandrich modem and AT command interface is 0xff */
- if ((serial->dev->descriptor.idVendor == BANDRICH_VENDOR_ID ||
- serial->dev->descriptor.idVendor == PIRELLI_VENDOR_ID) &&
- serial->interface->cur_altsetting->desc.bInterfaceClass != 0xff)
+ if ((dev_desc->idVendor == BANDRICH_VENDOR_ID ||
+ dev_desc->idVendor == PIRELLI_VENDOR_ID) &&
+ iface_desc->bInterfaceClass != 0xff)
return -ENODEV;
-
- /* Don't bind reserved interfaces (like network ones) which often have
+ /*
+ * Don't bind reserved interfaces (like network ones) which often have
* the same class/subclass/protocol as the serial interfaces. Look at
* the Windows driver .INF files for reserved interface numbers.
*/
if (is_blacklisted(
- serial->interface->cur_altsetting->desc.bInterfaceNumber,
+ iface_desc->bInterfaceNumber,
OPTION_BLACKLIST_RESERVED_IF,
(const struct option_blacklist_info *) id->driver_info))
return -ENODEV;
-
- /* Don't bind network interface on Samsung GT-B3730, it is handled by a separate module */
- if (serial->dev->descriptor.idVendor == SAMSUNG_VENDOR_ID &&
- serial->dev->descriptor.idProduct == SAMSUNG_PRODUCT_GT_B3730 &&
- serial->interface->cur_altsetting->desc.bInterfaceClass != USB_CLASS_CDC_DATA)
+ /*
+ * Don't bind network interface on Samsung GT-B3730, it is handled by
+ * a separate module.
+ */
+ if (dev_desc->idVendor == SAMSUNG_VENDOR_ID &&
+ dev_desc->idProduct == SAMSUNG_PRODUCT_GT_B3730 &&
+ iface_desc->bInterfaceClass != USB_CLASS_CDC_DATA)
return -ENODEV;
- data = serial->private = kzalloc(sizeof(struct usb_wwan_intf_private), GFP_KERNEL);
+ data = kzalloc(sizeof(struct usb_wwan_intf_private), GFP_KERNEL);
if (!data)
return -ENOMEM;
- data->send_setup = option_send_setup;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ kfree(data);
+ return -ENOMEM;
+ }
+
+ priv->bInterfaceNumber = iface_desc->bInterfaceNumber;
+ data->private = priv;
+
+ if (!is_blacklisted(iface_desc->bInterfaceNumber,
+ OPTION_BLACKLIST_SENDSETUP,
+ (struct option_blacklist_info *)id->driver_info)) {
+ data->send_setup = option_send_setup;
+ }
spin_lock_init(&data->susp_lock);
- data->private = (void *)id->driver_info;
+
+ usb_set_serial_data(serial, data);
+
return 0;
}
static void option_release(struct usb_serial *serial)
{
- struct usb_wwan_intf_private *priv = usb_get_serial_data(serial);
+ struct usb_wwan_intf_private *intfdata = usb_get_serial_data(serial);
+ struct option_private *priv = intfdata->private;
usb_wwan_release(serial);
kfree(priv);
+ kfree(intfdata);
}
static void option_instat_callback(struct urb *urb)
static int option_send_setup(struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
- struct usb_wwan_intf_private *intfdata =
- (struct usb_wwan_intf_private *) serial->private;
+ struct usb_wwan_intf_private *intfdata = usb_get_serial_data(serial);
+ struct option_private *priv = intfdata->private;
struct usb_wwan_port_private *portdata;
- int ifNum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
int val = 0;
- if (is_blacklisted(ifNum, OPTION_BLACKLIST_SENDSETUP,
- (struct option_blacklist_info *) intfdata->private)) {
- dbg("No send_setup on blacklisted interface #%d\n", ifNum);
- return -EIO;
- }
-
portdata = usb_get_serial_port_data(port);
if (portdata->dtr_state)
if (portdata->rts_state)
val |= 0x02;
- return usb_control_msg(serial->dev,
- usb_rcvctrlpipe(serial->dev, 0),
- 0x22, 0x21, val, ifNum, NULL, 0, USB_CTRL_SET_TIMEOUT);
+ return usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+ 0x22, 0x21, val, priv->bInterfaceNumber, NULL,
+ 0, USB_CTRL_SET_TIMEOUT);
}
MODULE_AUTHOR(DRIVER_AUTHOR);
static int qt2_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct usb_serial *serial;
- struct qt2_serial_private *serial_priv;
struct qt2_port_private *port_priv;
u8 *data;
u16 device_port;
serial = port->serial;
port_priv = usb_get_serial_port_data(port);
- serial_priv = usb_get_serial_data(serial);
/* set the port to RS232 mode */
status = qt2_control_msg(serial->dev, QT2_GET_SET_QMCR,
static void qt2_close(struct usb_serial_port *port)
{
struct usb_serial *serial;
- struct qt2_serial_private *serial_priv;
struct qt2_port_private *port_priv;
unsigned long flags;
int i;
serial = port->serial;
- serial_priv = usb_get_serial_data(serial);
port_priv = usb_get_serial_port_data(port);
port_priv->is_open = false;
* NOTE: This only works because a scsi_cmnd struct field contains
* a unsigned char cmnd[16], so we know we have storage available
*/
- for (; srb->cmd_len<12; srb->cmd_len++)
+ for (; srb->cmd_len < 12; srb->cmd_len++)
srb->cmnd[srb->cmd_len] = 0;
/* send the command to the transport layer */
void usb_stor_ufi_command(struct scsi_cmnd *srb, struct us_data *us)
{
/* fix some commands -- this is a form of mode translation
- * UFI devices only accept 12 byte long commands
+ * UFI devices only accept 12 byte long commands
*
* NOTE: This only works because a scsi_cmnd struct field contains
* a unsigned char cmnd[16], so we know we have storage available
*/
/* Pad the ATAPI command with zeros */
- for (; srb->cmd_len<12; srb->cmd_len++)
+ for (; srb->cmd_len < 12; srb->cmd_len++)
srb->cmnd[srb->cmd_len] = 0;
/* set command length to 12 bytes (this affects the transport layer) */
struct uas_dev_info {
struct usb_interface *intf;
struct usb_device *udev;
- int qdepth;
+ struct usb_anchor sense_urbs;
+ struct usb_anchor data_urbs;
+ int qdepth, resetting;
+ struct response_ui response;
unsigned cmd_pipe, status_pipe, data_in_pipe, data_out_pipe;
unsigned use_streams:1;
unsigned uas_sense_old:1;
struct scsi_cmnd *cmnd;
- struct urb *status_urb; /* used only if stream support is available */
};
enum {
- ALLOC_STATUS_URB = (1 << 0),
SUBMIT_STATUS_URB = (1 << 1),
ALLOC_DATA_IN_URB = (1 << 2),
SUBMIT_DATA_IN_URB = (1 << 3),
SUBMIT_DATA_OUT_URB = (1 << 5),
ALLOC_CMD_URB = (1 << 6),
SUBMIT_CMD_URB = (1 << 7),
- COMPLETED_DATA_IN = (1 << 8),
- COMPLETED_DATA_OUT = (1 << 9),
- DATA_COMPLETES_CMD = (1 << 10),
+ COMMAND_INFLIGHT = (1 << 8),
+ DATA_IN_URB_INFLIGHT = (1 << 9),
+ DATA_OUT_URB_INFLIGHT = (1 << 10),
+ COMMAND_COMPLETED = (1 << 11),
};
/* Overrides scsi_pointer */
struct uas_cmd_info {
unsigned int state;
unsigned int stream;
+ unsigned int aborted;
struct urb *cmd_urb;
- /* status_urb is used only if stream support isn't available */
- struct urb *status_urb;
struct urb *data_in_urb;
struct urb *data_out_urb;
struct list_head list;
{
struct sense_iu *sense_iu = urb->transfer_buffer;
struct scsi_device *sdev = cmnd->device;
- struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
if (urb->actual_length > 16) {
unsigned len = be16_to_cpup(&sense_iu->len);
}
cmnd->result = sense_iu->status;
- if (!(cmdinfo->state & DATA_COMPLETES_CMD))
- cmnd->scsi_done(cmnd);
}
static void uas_sense_old(struct urb *urb, struct scsi_cmnd *cmnd)
{
struct sense_iu_old *sense_iu = urb->transfer_buffer;
struct scsi_device *sdev = cmnd->device;
- struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
if (urb->actual_length > 8) {
unsigned len = be16_to_cpup(&sense_iu->len) - 2;
}
cmnd->result = sense_iu->status;
- if (!(cmdinfo->state & DATA_COMPLETES_CMD))
- cmnd->scsi_done(cmnd);
+}
+
+static void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *caller)
+{
+ struct uas_cmd_info *ci = (void *)&cmnd->SCp;
+
+ scmd_printk(KERN_INFO, cmnd, "%s %p tag %d, inflight:"
+ "%s%s%s%s%s%s%s%s%s%s%s\n",
+ caller, cmnd, cmnd->request->tag,
+ (ci->state & SUBMIT_STATUS_URB) ? " s-st" : "",
+ (ci->state & ALLOC_DATA_IN_URB) ? " a-in" : "",
+ (ci->state & SUBMIT_DATA_IN_URB) ? " s-in" : "",
+ (ci->state & ALLOC_DATA_OUT_URB) ? " a-out" : "",
+ (ci->state & SUBMIT_DATA_OUT_URB) ? " s-out" : "",
+ (ci->state & ALLOC_CMD_URB) ? " a-cmd" : "",
+ (ci->state & SUBMIT_CMD_URB) ? " s-cmd" : "",
+ (ci->state & COMMAND_INFLIGHT) ? " CMD" : "",
+ (ci->state & DATA_IN_URB_INFLIGHT) ? " IN" : "",
+ (ci->state & DATA_OUT_URB_INFLIGHT) ? " OUT" : "",
+ (ci->state & COMMAND_COMPLETED) ? " done" : "");
+}
+
+static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller)
+{
+ struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
+
+ if (cmdinfo->state & (COMMAND_INFLIGHT |
+ DATA_IN_URB_INFLIGHT |
+ DATA_OUT_URB_INFLIGHT))
+ return -EBUSY;
+ BUG_ON(cmdinfo->state & COMMAND_COMPLETED);
+ cmdinfo->state |= COMMAND_COMPLETED;
+ usb_free_urb(cmdinfo->data_in_urb);
+ usb_free_urb(cmdinfo->data_out_urb);
+ cmnd->scsi_done(cmnd);
+ return 0;
}
static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd,
- unsigned direction)
+ unsigned direction)
{
struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
int err;
- cmdinfo->state = direction;
+ cmdinfo->state |= direction | SUBMIT_STATUS_URB;
err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC);
if (err) {
spin_lock(&uas_work_lock);
struct scsi_cmnd *cmnd;
struct uas_cmd_info *cmdinfo;
u16 tag;
- int ret;
if (urb->status) {
dev_err(&urb->dev->dev, "URB BAD STATUS %d\n", urb->status);
- if (devinfo->use_streams)
- usb_free_urb(urb);
+ usb_free_urb(urb);
+ return;
+ }
+
+ if (devinfo->resetting) {
+ usb_free_urb(urb);
return;
}
else
cmnd = scsi_host_find_tag(shost, tag - 1);
if (!cmnd) {
- if (devinfo->use_streams) {
+ if (iu->iu_id != IU_ID_RESPONSE) {
usb_free_urb(urb);
return;
}
- ret = usb_submit_urb(urb, GFP_ATOMIC);
- if (ret)
- dev_err(&urb->dev->dev, "failed submit status urb\n");
- return;
+ } else {
+ cmdinfo = (void *)&cmnd->SCp;
}
- cmdinfo = (void *)&cmnd->SCp;
switch (iu->iu_id) {
case IU_ID_STATUS:
if (devinfo->cmnd == cmnd)
devinfo->cmnd = NULL;
- if (!(cmdinfo->state & COMPLETED_DATA_IN) &&
- cmdinfo->data_in_urb) {
- if (devinfo->use_streams) {
- cmdinfo->state |= DATA_COMPLETES_CMD;
- usb_unlink_urb(cmdinfo->data_in_urb);
- } else {
- usb_free_urb(cmdinfo->data_in_urb);
- }
- }
- if (!(cmdinfo->state & COMPLETED_DATA_OUT) &&
- cmdinfo->data_out_urb) {
- if (devinfo->use_streams) {
- cmdinfo->state |= DATA_COMPLETES_CMD;
- usb_unlink_urb(cmdinfo->data_in_urb);
- } else {
- usb_free_urb(cmdinfo->data_out_urb);
- }
- }
-
if (urb->actual_length < 16)
devinfo->uas_sense_old = 1;
if (devinfo->uas_sense_old)
uas_sense_old(urb, cmnd);
else
uas_sense(urb, cmnd);
+ if (cmnd->result != 0) {
+ /* cancel data transfers on error */
+ if (cmdinfo->state & DATA_IN_URB_INFLIGHT)
+ usb_unlink_urb(cmdinfo->data_in_urb);
+ if (cmdinfo->state & DATA_OUT_URB_INFLIGHT)
+ usb_unlink_urb(cmdinfo->data_out_urb);
+ }
+ cmdinfo->state &= ~COMMAND_INFLIGHT;
+ uas_try_complete(cmnd, __func__);
break;
case IU_ID_READ_READY:
uas_xfer_data(urb, cmnd, SUBMIT_DATA_IN_URB);
case IU_ID_WRITE_READY:
uas_xfer_data(urb, cmnd, SUBMIT_DATA_OUT_URB);
break;
+ case IU_ID_RESPONSE:
+ /* store results for uas_eh_task_mgmt() */
+ memcpy(&devinfo->response, iu, sizeof(devinfo->response));
+ break;
default:
scmd_printk(KERN_ERR, cmnd,
"Bogus IU (%d) received on status pipe\n", iu->iu_id);
}
-
- if (devinfo->use_streams) {
- usb_free_urb(urb);
- return;
- }
-
- ret = usb_submit_urb(urb, GFP_ATOMIC);
- if (ret)
- dev_err(&urb->dev->dev, "failed submit status urb\n");
-}
-
-static void uas_data_out_cmplt(struct urb *urb)
-{
- struct scsi_cmnd *cmnd = urb->context;
- struct scsi_data_buffer *sdb = scsi_out(cmnd);
- struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
-
- cmdinfo->state |= COMPLETED_DATA_OUT;
-
- sdb->resid = sdb->length - urb->actual_length;
usb_free_urb(urb);
-
- if (cmdinfo->state & DATA_COMPLETES_CMD)
- cmnd->scsi_done(cmnd);
}
-static void uas_data_in_cmplt(struct urb *urb)
+static void uas_data_cmplt(struct urb *urb)
{
struct scsi_cmnd *cmnd = urb->context;
- struct scsi_data_buffer *sdb = scsi_in(cmnd);
struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
+ struct scsi_data_buffer *sdb = NULL;
- cmdinfo->state |= COMPLETED_DATA_IN;
-
- sdb->resid = sdb->length - urb->actual_length;
- usb_free_urb(urb);
-
- if (cmdinfo->state & DATA_COMPLETES_CMD)
- cmnd->scsi_done(cmnd);
+ if (cmdinfo->data_in_urb == urb) {
+ sdb = scsi_in(cmnd);
+ cmdinfo->state &= ~DATA_IN_URB_INFLIGHT;
+ } else if (cmdinfo->data_out_urb == urb) {
+ sdb = scsi_out(cmnd);
+ cmdinfo->state &= ~DATA_OUT_URB_INFLIGHT;
+ }
+ BUG_ON(sdb == NULL);
+ if (urb->status) {
+ /* error: no data transfered */
+ sdb->resid = sdb->length;
+ } else {
+ sdb->resid = sdb->length - urb->actual_length;
+ }
+ if (cmdinfo->aborted) {
+ return;
+ }
+ uas_try_complete(cmnd, __func__);
}
static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp,
- unsigned int pipe, struct scsi_cmnd *cmnd,
- enum dma_data_direction dir)
+ unsigned int pipe, u16 stream_id,
+ struct scsi_cmnd *cmnd,
+ enum dma_data_direction dir)
{
- struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
struct usb_device *udev = devinfo->udev;
struct urb *urb = usb_alloc_urb(0, gfp);
- struct scsi_data_buffer *sdb;
- usb_complete_t complete_fn;
- u16 stream_id = cmdinfo->stream;
+ struct scsi_data_buffer *sdb = (dir == DMA_FROM_DEVICE)
+ ? scsi_in(cmnd) : scsi_out(cmnd);
if (!urb)
goto out;
- if (dir == DMA_FROM_DEVICE) {
- sdb = scsi_in(cmnd);
- complete_fn = uas_data_in_cmplt;
- } else {
- sdb = scsi_out(cmnd);
- complete_fn = uas_data_out_cmplt;
- }
usb_fill_bulk_urb(urb, udev, pipe, NULL, sdb->length,
- complete_fn, cmnd);
- urb->stream_id = stream_id;
+ uas_data_cmplt, cmnd);
+ if (devinfo->use_streams)
+ urb->stream_id = stream_id;
urb->num_sgs = udev->bus->sg_tablesize ? sdb->table.nents : 0;
urb->sg = sdb->table.sgl;
out:
}
static struct urb *uas_alloc_sense_urb(struct uas_dev_info *devinfo, gfp_t gfp,
- struct Scsi_Host *shost, u16 stream_id)
+ struct Scsi_Host *shost, u16 stream_id)
{
struct usb_device *udev = devinfo->udev;
struct urb *urb = usb_alloc_urb(0, gfp);
return NULL;
}
+static int uas_submit_task_urb(struct scsi_cmnd *cmnd, gfp_t gfp,
+ u8 function, u16 stream_id)
+{
+ struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
+ struct usb_device *udev = devinfo->udev;
+ struct urb *urb = usb_alloc_urb(0, gfp);
+ struct task_mgmt_iu *iu;
+ int err = -ENOMEM;
+
+ if (!urb)
+ goto err;
+
+ iu = kzalloc(sizeof(*iu), gfp);
+ if (!iu)
+ goto err;
+
+ iu->iu_id = IU_ID_TASK_MGMT;
+ iu->tag = cpu_to_be16(stream_id);
+ int_to_scsilun(cmnd->device->lun, &iu->lun);
+
+ iu->function = function;
+ switch (function) {
+ case TMF_ABORT_TASK:
+ if (blk_rq_tagged(cmnd->request))
+ iu->task_tag = cpu_to_be16(cmnd->request->tag + 2);
+ else
+ iu->task_tag = cpu_to_be16(1);
+ break;
+ }
+
+ usb_fill_bulk_urb(urb, udev, devinfo->cmd_pipe, iu, sizeof(*iu),
+ usb_free_urb, NULL);
+ urb->transfer_flags |= URB_FREE_BUFFER;
+
+ err = usb_submit_urb(urb, gfp);
+ if (err)
+ goto err;
+
+ return 0;
+
+err:
+ usb_free_urb(urb);
+ return err;
+}
+
/*
* Why should I request the Status IU before sending the Command IU? Spec
* says to, but also says the device may receive them in any order. Seems
* daft to me.
*/
-static int uas_submit_urbs(struct scsi_cmnd *cmnd,
- struct uas_dev_info *devinfo, gfp_t gfp)
+static int uas_submit_sense_urb(struct Scsi_Host *shost,
+ gfp_t gfp, unsigned int stream)
{
- struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
+ struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
+ struct urb *urb;
- if (cmdinfo->state & ALLOC_STATUS_URB) {
- cmdinfo->status_urb = uas_alloc_sense_urb(devinfo, gfp,
- cmnd->device->host, cmdinfo->stream);
- if (!cmdinfo->status_urb)
- return SCSI_MLQUEUE_DEVICE_BUSY;
- cmdinfo->state &= ~ALLOC_STATUS_URB;
+ urb = uas_alloc_sense_urb(devinfo, gfp, shost, stream);
+ if (!urb)
+ return SCSI_MLQUEUE_DEVICE_BUSY;
+ if (usb_submit_urb(urb, gfp)) {
+ shost_printk(KERN_INFO, shost,
+ "sense urb submission failure\n");
+ usb_free_urb(urb);
+ return SCSI_MLQUEUE_DEVICE_BUSY;
}
+ usb_anchor_urb(urb, &devinfo->sense_urbs);
+ return 0;
+}
+
+static int uas_submit_urbs(struct scsi_cmnd *cmnd,
+ struct uas_dev_info *devinfo, gfp_t gfp)
+{
+ struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
+ int err;
if (cmdinfo->state & SUBMIT_STATUS_URB) {
- if (usb_submit_urb(cmdinfo->status_urb, gfp)) {
- scmd_printk(KERN_INFO, cmnd,
- "sense urb submission failure\n");
- return SCSI_MLQUEUE_DEVICE_BUSY;
+ err = uas_submit_sense_urb(cmnd->device->host, gfp,
+ cmdinfo->stream);
+ if (err) {
+ return err;
}
cmdinfo->state &= ~SUBMIT_STATUS_URB;
}
if (cmdinfo->state & ALLOC_DATA_IN_URB) {
cmdinfo->data_in_urb = uas_alloc_data_urb(devinfo, gfp,
- devinfo->data_in_pipe, cmnd,
- DMA_FROM_DEVICE);
+ devinfo->data_in_pipe, cmdinfo->stream,
+ cmnd, DMA_FROM_DEVICE);
if (!cmdinfo->data_in_urb)
return SCSI_MLQUEUE_DEVICE_BUSY;
cmdinfo->state &= ~ALLOC_DATA_IN_URB;
return SCSI_MLQUEUE_DEVICE_BUSY;
}
cmdinfo->state &= ~SUBMIT_DATA_IN_URB;
+ cmdinfo->state |= DATA_IN_URB_INFLIGHT;
+ usb_anchor_urb(cmdinfo->data_in_urb, &devinfo->data_urbs);
}
if (cmdinfo->state & ALLOC_DATA_OUT_URB) {
cmdinfo->data_out_urb = uas_alloc_data_urb(devinfo, gfp,
- devinfo->data_out_pipe, cmnd,
- DMA_TO_DEVICE);
+ devinfo->data_out_pipe, cmdinfo->stream,
+ cmnd, DMA_TO_DEVICE);
if (!cmdinfo->data_out_urb)
return SCSI_MLQUEUE_DEVICE_BUSY;
cmdinfo->state &= ~ALLOC_DATA_OUT_URB;
return SCSI_MLQUEUE_DEVICE_BUSY;
}
cmdinfo->state &= ~SUBMIT_DATA_OUT_URB;
+ cmdinfo->state |= DATA_OUT_URB_INFLIGHT;
+ usb_anchor_urb(cmdinfo->data_out_urb, &devinfo->data_urbs);
}
if (cmdinfo->state & ALLOC_CMD_URB) {
return SCSI_MLQUEUE_DEVICE_BUSY;
}
cmdinfo->state &= ~SUBMIT_CMD_URB;
+ cmdinfo->state |= COMMAND_INFLIGHT;
}
return 0;
cmnd->scsi_done = done;
- cmdinfo->state = ALLOC_STATUS_URB | SUBMIT_STATUS_URB |
+ cmdinfo->state = SUBMIT_STATUS_URB |
ALLOC_CMD_URB | SUBMIT_CMD_URB;
+ cmdinfo->aborted = 0;
switch (cmnd->sc_data_direction) {
case DMA_FROM_DEVICE:
}
if (!devinfo->use_streams) {
- cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB |
- ALLOC_STATUS_URB | SUBMIT_STATUS_URB);
+ cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB);
cmdinfo->stream = 0;
}
if (err) {
/* If we did nothing, give up now */
if (cmdinfo->state & SUBMIT_STATUS_URB) {
- usb_free_urb(cmdinfo->status_urb);
return SCSI_MLQUEUE_DEVICE_BUSY;
}
spin_lock(&uas_work_lock);
static DEF_SCSI_QCMD(uas_queuecommand)
-static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
+static int uas_eh_task_mgmt(struct scsi_cmnd *cmnd,
+ const char *fname, u8 function)
{
- struct scsi_device *sdev = cmnd->device;
- sdev_printk(KERN_INFO, sdev, "%s tag %d\n", __func__,
- cmnd->request->tag);
-
-/* XXX: Send ABORT TASK Task Management command */
- return FAILED;
+ struct Scsi_Host *shost = cmnd->device->host;
+ struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
+ u16 tag = 9999; /* FIXME */
+
+ memset(&devinfo->response, 0, sizeof(devinfo->response));
+ if (uas_submit_sense_urb(shost, GFP_NOIO, tag)) {
+ shost_printk(KERN_INFO, shost,
+ "%s: %s: submit sense urb failed\n",
+ __func__, fname);
+ return FAILED;
+ }
+ if (uas_submit_task_urb(cmnd, GFP_NOIO, function, tag)) {
+ shost_printk(KERN_INFO, shost,
+ "%s: %s: submit task mgmt urb failed\n",
+ __func__, fname);
+ return FAILED;
+ }
+ if (0 == usb_wait_anchor_empty_timeout(&devinfo->sense_urbs, 3000)) {
+ shost_printk(KERN_INFO, shost,
+ "%s: %s timed out\n", __func__, fname);
+ return FAILED;
+ }
+ if (be16_to_cpu(devinfo->response.tag) != tag) {
+ shost_printk(KERN_INFO, shost,
+ "%s: %s failed (wrong tag %d/%d)\n", __func__,
+ fname, be16_to_cpu(devinfo->response.tag), tag);
+ return FAILED;
+ }
+ if (devinfo->response.response_code != RC_TMF_COMPLETE) {
+ shost_printk(KERN_INFO, shost,
+ "%s: %s failed (rc 0x%x)\n", __func__,
+ fname, devinfo->response.response_code);
+ return FAILED;
+ }
+ return SUCCESS;
}
-static int uas_eh_device_reset_handler(struct scsi_cmnd *cmnd)
+static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
{
- struct scsi_device *sdev = cmnd->device;
- sdev_printk(KERN_INFO, sdev, "%s tag %d\n", __func__,
- cmnd->request->tag);
+ struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
+ int ret;
-/* XXX: Send LOGICAL UNIT RESET Task Management command */
- return FAILED;
+ uas_log_cmd_state(cmnd, __func__);
+ cmdinfo->aborted = 1;
+ ret = uas_eh_task_mgmt(cmnd, "ABORT TASK", TMF_ABORT_TASK);
+ if (cmdinfo->state & DATA_IN_URB_INFLIGHT)
+ usb_kill_urb(cmdinfo->data_in_urb);
+ if (cmdinfo->state & DATA_OUT_URB_INFLIGHT)
+ usb_kill_urb(cmdinfo->data_out_urb);
+ return ret;
}
-static int uas_eh_target_reset_handler(struct scsi_cmnd *cmnd)
+static int uas_eh_device_reset_handler(struct scsi_cmnd *cmnd)
{
- struct scsi_device *sdev = cmnd->device;
- sdev_printk(KERN_INFO, sdev, "%s tag %d\n", __func__,
- cmnd->request->tag);
-
-/* XXX: Can we reset just the one USB interface?
- * Would calling usb_set_interface() have the right effect?
- */
- return FAILED;
+ sdev_printk(KERN_INFO, cmnd->device, "%s\n", __func__);
+ return uas_eh_task_mgmt(cmnd, "LOGICAL UNIT RESET",
+ TMF_LOGICAL_UNIT_RESET);
}
static int uas_eh_bus_reset_handler(struct scsi_cmnd *cmnd)
struct scsi_device *sdev = cmnd->device;
struct uas_dev_info *devinfo = sdev->hostdata;
struct usb_device *udev = devinfo->udev;
+ int err;
- sdev_printk(KERN_INFO, sdev, "%s tag %d\n", __func__,
- cmnd->request->tag);
+ devinfo->resetting = 1;
+ usb_kill_anchored_urbs(&devinfo->sense_urbs);
+ usb_kill_anchored_urbs(&devinfo->data_urbs);
+ err = usb_reset_device(udev);
+ devinfo->resetting = 0;
- if (usb_reset_device(udev))
- return SUCCESS;
+ if (err) {
+ shost_printk(KERN_INFO, sdev->host, "%s FAILED\n", __func__);
+ return FAILED;
+ }
- return FAILED;
+ shost_printk(KERN_INFO, sdev->host, "%s success\n", __func__);
+ return SUCCESS;
}
static int uas_slave_alloc(struct scsi_device *sdev)
.slave_configure = uas_slave_configure,
.eh_abort_handler = uas_eh_abort_handler,
.eh_device_reset_handler = uas_eh_device_reset_handler,
- .eh_target_reset_handler = uas_eh_target_reset_handler,
.eh_bus_reset_handler = uas_eh_bus_reset_handler,
.can_queue = 65536, /* Is there a limit on the _host_ ? */
.this_id = -1,
}
}
-static int uas_alloc_status_urb(struct uas_dev_info *devinfo,
- struct Scsi_Host *shost)
-{
- if (devinfo->use_streams) {
- devinfo->status_urb = NULL;
- return 0;
- }
-
- devinfo->status_urb = uas_alloc_sense_urb(devinfo, GFP_KERNEL,
- shost, 0);
- if (!devinfo->status_urb)
- goto err_s_urb;
-
- if (usb_submit_urb(devinfo->status_urb, GFP_KERNEL))
- goto err_submit_urb;
-
- return 0;
-err_submit_urb:
- usb_free_urb(devinfo->status_urb);
-err_s_urb:
- return -ENOMEM;
-}
-
static void uas_free_streams(struct uas_dev_info *devinfo)
{
struct usb_device *udev = devinfo->udev;
devinfo->intf = intf;
devinfo->udev = udev;
+ devinfo->resetting = 0;
+ init_usb_anchor(&devinfo->sense_urbs);
+ init_usb_anchor(&devinfo->data_urbs);
uas_configure_endpoints(devinfo);
result = scsi_init_shared_tag_map(shost, devinfo->qdepth - 2);
shost->hostdata[0] = (unsigned long)devinfo;
- result = uas_alloc_status_urb(devinfo, shost);
- if (result)
- goto err_alloc_status;
-
scsi_scan_host(shost);
usb_set_intfdata(intf, shost);
return result;
-err_alloc_status:
- scsi_remove_host(shost);
- shost = NULL;
deconfig_eps:
uas_free_streams(devinfo);
free:
struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
scsi_remove_host(shost);
- usb_kill_urb(devinfo->status_urb);
- usb_free_urb(devinfo->status_urb);
+ usb_kill_anchored_urbs(&devinfo->sense_urbs);
+ usb_kill_anchored_urbs(&devinfo->data_urbs);
uas_free_streams(devinfo);
kfree(devinfo);
}
* of a given interface; other interfaces may support other classes.
* @bInterfaceSubClass: Subclass of interface; associated with bInterfaceClass.
* @bInterfaceProtocol: Protocol of interface; associated with bInterfaceClass.
+ * @bInterfaceNumber: Number of interface; composite devices may use
+ * fixed interface numbers to differentiate between vendor-specific
+ * interfaces.
* @driver_info: Holds information used by the driver. Usually it holds
* a pointer to a descriptor understood by the driver, or perhaps
* device flags.
__u8 bInterfaceSubClass;
__u8 bInterfaceProtocol;
+ /* Used for vendor-specific interface matches */
+ __u8 bInterfaceNumber;
+
/* not matched against */
- kernel_ulong_t driver_info;
+ kernel_ulong_t driver_info
+ __attribute__((aligned(sizeof(kernel_ulong_t))));
};
/* Some useful macros to use to create struct usb_device_id */
#define USB_DEVICE_ID_MATCH_INT_CLASS 0x0080
#define USB_DEVICE_ID_MATCH_INT_SUBCLASS 0x0100
#define USB_DEVICE_ID_MATCH_INT_PROTOCOL 0x0200
+#define USB_DEVICE_ID_MATCH_INT_NUMBER 0x0400
#define HID_ANY_ID (~0)
#define HID_BUS_ANY 0xffff
.idProduct = (prod), \
.bInterfaceProtocol = (pr)
+/**
+ * USB_DEVICE_INTERFACE_NUMBER - describe a usb device with a specific interface number
+ * @vend: the 16 bit USB Vendor ID
+ * @prod: the 16 bit USB Product ID
+ * @num: bInterfaceNumber value
+ *
+ * This macro is used to create a struct usb_device_id that matches a
+ * specific interface number of devices.
+ */
+#define USB_DEVICE_INTERFACE_NUMBER(vend, prod, num) \
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
+ USB_DEVICE_ID_MATCH_INT_NUMBER, \
+ .idVendor = (vend), \
+ .idProduct = (prod), \
+ .bInterfaceNumber = (num)
+
/**
* USB_DEVICE_INFO - macro used to describe a class of usb devices
* @cl: bDeviceClass value
/* ASYNCLISTADDR: offset 0x18 */
u32 async_next; /* address of next async queue head */
- u32 reserved[9];
+ u32 reserved1[2];
+
+ /* TXFILLTUNING: offset 0x24 */
+ u32 txfill_tuning; /* TX FIFO Tuning register */
+#define TXFIFO_DEFAULT (8<<16) /* FIFO burst threshold 8 */
+
+ u32 reserved2[6];
/* CONFIGFLAG: offset 0x40 */
u32 configured_flag;
#define PORT_CSC (1<<1) /* connect status change */
#define PORT_CONNECT (1<<0) /* device connected */
#define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC)
-};
-#define USBMODE 0x68 /* USB Device mode */
+ u32 reserved3[9];
+
+ /* USBMODE: offset 0x68 */
+ u32 usbmode; /* USB Device mode */
#define USBMODE_SDIS (1<<3) /* Stream disable */
#define USBMODE_BE (1<<2) /* BE/LE endianness select */
#define USBMODE_CM_HC (3<<0) /* host controller mode */
#define USBMODE_CM_IDLE (0<<0) /* idle state */
+ u32 reserved4[7];
+
/* Moorestown has some non-standard registers, partially due to the fact that
* its EHCI controller has both TT and LPM support. HOSTPCx are extensions to
* PORTSCx
*/
-#define HOSTPC0 0x84 /* HOSTPC extension */
+ /* HOSTPC: offset 0x84 */
+ u32 hostpc[0]; /* HOSTPC extension */
#define HOSTPC_PHCD (1<<22) /* Phy clock disable */
#define HOSTPC_PSPD (3<<25) /* Port speed detection */
-#define USBMODE_EX 0xc8 /* USB Device mode extension */
+
+ u32 reserved5[17];
+
+ /* USBMODE_EX: offset 0xc8 */
+ u32 usbmode_ex; /* USB Device mode extension */
#define USBMODE_EX_VBPS (1<<5) /* VBus Power Select On */
#define USBMODE_EX_HC (3<<0) /* host controller mode */
-#define TXFILLTUNING 0x24 /* TX FIFO Tuning register */
-#define TXFIFO_DEFAULT (8<<16) /* FIFO burst threshold 8 */
+};
/* Appendix C, Debug port ... intended for use with special "debug devices"
* that can help if there's no serial console. (nonstandard enumeration.)
*/
const struct hc_driver *driver; /* hw-specific hooks */
+ /*
+ * OTG and some Host controllers need software interaction with phys;
+ * other external phys should be software-transparent
+ */
+ struct usb_phy *phy;
+
/* Flags that need to be manipulated atomically because they can
* change while the host controller is running. Always use
* set_bit() or clear_bit() to change their values.
* option:
*
* dma id for dmaengine
+ * The data transfer direction on D0FIFO/D1FIFO should be
+ * fixed for keeping consistency.
+ * So, the platform id settings will be..
+ * .d0_tx_id = xx_TX,
+ * .d1_rx_id = xx_RX,
+ * or
+ * .d1_tx_id = xx_TX,
+ * .d0_rx_id = xx_RX,
*/
int d0_tx_id;
int d0_rx_id;
IU_ID_WRITE_READY = 0x07,
};
+enum {
+ TMF_ABORT_TASK = 0x01,
+ TMF_ABORT_TASK_SET = 0x02,
+ TMF_CLEAR_TASK_SET = 0x04,
+ TMF_LOGICAL_UNIT_RESET = 0x08,
+ TMF_I_T_NEXUS_RESET = 0x10,
+ TMF_CLEAR_ACA = 0x40,
+ TMF_QUERY_TASK = 0x80,
+ TMF_QUERY_TASK_SET = 0x81,
+ TMF_QUERY_ASYNC_EVENT = 0x82,
+};
+
+enum {
+ RC_TMF_COMPLETE = 0x00,
+ RC_INVALID_INFO_UNIT = 0x02,
+ RC_TMF_NOT_SUPPORTED = 0x04,
+ RC_TMF_FAILED = 0x05,
+ RC_TMF_SUCCEEDED = 0x08,
+ RC_INCORRECT_LUN = 0x09,
+ RC_OVERLAPPED_TAG = 0x0a,
+};
+
struct command_iu {
__u8 iu_id;
__u8 rsvd1;
__u8 cdb[16]; /* XXX: Overflow-checking tools may misunderstand */
};
+struct task_mgmt_iu {
+ __u8 iu_id;
+ __u8 rsvd1;
+ __be16 tag;
+ __u8 function;
+ __u8 rsvd2;
+ __be16 task_tag;
+ struct scsi_lun lun;
+};
+
/*
* Also used for the Read Ready and Write Ready IUs since they have the
* same first four bytes
__u8 sense[SCSI_SENSE_BUFFERSIZE];
};
+struct response_ui {
+ __u8 iu_id;
+ __u8 rsvd1;
+ __be16 tag;
+ __be16 add_response_info;
+ __u8 response_code;
+};
+
struct usb_pipe_usage_descriptor {
__u8 bLength;
__u8 bDescriptorType;
}
/* USB is special because the bcdDevice can be matched against a numeric range */
-/* Looks like "usb:vNpNdNdcNdscNdpNicNiscNipN" */
+/* Looks like "usb:vNpNdNdcNdscNdpNicNiscNipNinN" */
static void do_usb_entry(struct usb_device_id *id,
unsigned int bcdDevice_initial, int bcdDevice_initial_digits,
unsigned char range_lo, unsigned char range_hi,
ADD(alias, "ip",
id->match_flags&USB_DEVICE_ID_MATCH_INT_PROTOCOL,
id->bInterfaceProtocol);
+ ADD(alias, "in",
+ id->match_flags&USB_DEVICE_ID_MATCH_INT_NUMBER,
+ id->bInterfaceNumber);
add_wildcard(alias);
buf_printf(&mod->dev_table_buf,
/* for easy use when hotplugging */
device = getenv ("DEVICE");
- while ((c = getopt (argc, argv, "D:aA:c:g:hns:t:v:")) != EOF)
+ while ((c = getopt (argc, argv, "D:aA:c:g:hlns:t:v:")) != EOF)
switch (c) {
case 'D': /* device, if only one */
device = optarg;
case 'h':
default:
usage:
- fprintf (stderr, "usage: %s [-n] [-D dev | -a | -A usbfs-dir]\n"
- "\t[-c iterations] [-t testnum]\n"
- "\t[-s packetsize] [-g sglen] [-v vary]\n",
- argv [0]);
+ fprintf (stderr,
+ "usage: %s [options]\n"
+ "Options:\n"
+ "\t-D dev only test specific device\n"
+ "\t-A usbfs-dir\n"
+ "\t-a test all recognized devices\n"
+ "\t-l loop forever(for stress test)\n"
+ "\t-t testnum only run specified case\n"
+ "\t-n no test running, show devices to be tested\n"
+ "Case arguments:\n"
+ "\t-c iterations default 1000\n"
+ "\t-s packetsize default 512\n"
+ "\t-g sglen default 32\n"
+ "\t-v vary default 512\n",
+ argv[0]);
return 1;
}
if (optind != argc)