Commit b19d69c7 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'usb-3.13-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb

Pull USB fixes from Greg KH:
 "Here are a bunch of USB fixes for 3.13-rc3.

  Nothing major, but we seem to have an argument about a XHCI fix, so
  I'm not including a revert that Sarah requested, because that breaks a
  USB network driver, and I can't revert the USB network driver fix
  without reintroducing other bugs that it fixed.  So as it is,
  everything should now be working.  Worse case, I can revert the XHCI
  fix before 3.13-final is out, but it seems to work well here with my
  testing, so all should be good.

  Other than that, some driver updates based on reports"

* tag 'usb-3.13-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (40 commits)
  usb: hub: Use correct reset for wedged USB3 devices that are NOTATTACHED
  usb: ohci-pxa27x: include linux/dma-mapping.h
  USB: cdc-acm: Added support for the Lenovo RD02-D400 USB Modem
  usb: tools: fix a regression issue that gcc can't link to pthread
  USB: switch maintainership of chipidea to Peter
  USB: pl2303: fixed handling of CS5 setting
  USB: ftdi_sio: fixed handling of unsupported CSIZE setting
  USB: mos7840: correct handling of CS5 setting
  USB: spcp8x5: correct handling of CS5 setting
  usb: wusbcore: fix deadlock in wusbhc_gtk_rekey
  usb: wusbcore: do device lookup while holding the hc mutex
  usb: wusbcore: send keepalives to unauthenticated devices
  USB: option: support new huawei devices
  USB: serial: option: blacklist interface 1 for Huawei E173s-6
  usb: xhci: Link TRB must not occur within a USB payload burst
  usb: gadget: f_mass_storage: call try_to_freeze only when its safe
  usb: gadget: tcm_usb_gadget: mark bot_cleanup_old_alt static
  usb: gadget: ffs: fix sparse warning
  usb: gadget: zero: module parameters can be static
  usb: gadget: storage: fix sparse warning
  ...
parents 7d49efe2 2d51f3cd
...@@ -2138,7 +2138,8 @@ S: Maintained ...@@ -2138,7 +2138,8 @@ S: Maintained
F: Documentation/zh_CN/ F: Documentation/zh_CN/
CHIPIDEA USB HIGH SPEED DUAL ROLE CONTROLLER CHIPIDEA USB HIGH SPEED DUAL ROLE CONTROLLER
M: Alexander Shishkin <alexander.shishkin@linux.intel.com> M: Peter Chen <Peter.Chen@freescale.com>
T: git://github.com/hzpeterchen/linux-usb.git
L: linux-usb@vger.kernel.org L: linux-usb@vger.kernel.org
S: Maintained S: Maintained
F: drivers/usb/chipidea/ F: drivers/usb/chipidea/
......
...@@ -1515,6 +1515,8 @@ static int acm_reset_resume(struct usb_interface *intf) ...@@ -1515,6 +1515,8 @@ static int acm_reset_resume(struct usb_interface *intf)
static const struct usb_device_id acm_ids[] = { static const struct usb_device_id acm_ids[] = {
/* quirky and broken devices */ /* quirky and broken devices */
{ USB_DEVICE(0x17ef, 0x7000), /* Lenovo USB modem */
.driver_info = NO_UNION_NORMAL, },/* has no union descriptor */
{ USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */ { USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */
.driver_info = NO_UNION_NORMAL, /* has no union descriptor */ .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
}, },
......
...@@ -4832,8 +4832,9 @@ static void hub_events(void) ...@@ -4832,8 +4832,9 @@ static void hub_events(void)
hub->ports[i - 1]->child; hub->ports[i - 1]->child;
dev_dbg(hub_dev, "warm reset port %d\n", i); dev_dbg(hub_dev, "warm reset port %d\n", i);
if (!udev || !(portstatus & if (!udev ||
USB_PORT_STAT_CONNECTION)) { !(portstatus & USB_PORT_STAT_CONNECTION) ||
udev->state == USB_STATE_NOTATTACHED) {
status = hub_port_reset(hub, i, status = hub_port_reset(hub, i,
NULL, HUB_BH_RESET_TIME, NULL, HUB_BH_RESET_TIME,
true); true);
......
...@@ -459,6 +459,8 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc, ...@@ -459,6 +459,8 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
dep = dwc3_wIndex_to_dep(dwc, wIndex); dep = dwc3_wIndex_to_dep(dwc, wIndex);
if (!dep) if (!dep)
return -EINVAL; return -EINVAL;
if (set == 0 && (dep->flags & DWC3_EP_WEDGE))
break;
ret = __dwc3_gadget_ep_set_halt(dep, set); ret = __dwc3_gadget_ep_set_halt(dep, set);
if (ret) if (ret)
return -EINVAL; return -EINVAL;
......
...@@ -1200,9 +1200,6 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value) ...@@ -1200,9 +1200,6 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value)
else else
dep->flags |= DWC3_EP_STALL; dep->flags |= DWC3_EP_STALL;
} else { } else {
if (dep->flags & DWC3_EP_WEDGE)
return 0;
ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
DWC3_DEPCMD_CLEARSTALL, &params); DWC3_DEPCMD_CLEARSTALL, &params);
if (ret) if (ret)
...@@ -1210,7 +1207,7 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value) ...@@ -1210,7 +1207,7 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value)
value ? "set" : "clear", value ? "set" : "clear",
dep->name); dep->name);
else else
dep->flags &= ~DWC3_EP_STALL; dep->flags &= ~(DWC3_EP_STALL | DWC3_EP_WEDGE);
} }
return ret; return ret;
......
...@@ -682,6 +682,7 @@ config USB_CONFIGFS_PHONET ...@@ -682,6 +682,7 @@ config USB_CONFIGFS_PHONET
config USB_CONFIGFS_MASS_STORAGE config USB_CONFIGFS_MASS_STORAGE
boolean "Mass storage" boolean "Mass storage"
depends on USB_CONFIGFS depends on USB_CONFIGFS
depends on BLOCK
select USB_F_MASS_STORAGE select USB_F_MASS_STORAGE
help help
The Mass Storage Gadget acts as a USB Mass Storage disk drive. The Mass Storage Gadget acts as a USB Mass Storage disk drive.
......
...@@ -593,6 +593,7 @@ static void reset_config(struct usb_composite_dev *cdev) ...@@ -593,6 +593,7 @@ static void reset_config(struct usb_composite_dev *cdev)
bitmap_zero(f->endpoints, 32); bitmap_zero(f->endpoints, 32);
} }
cdev->config = NULL; cdev->config = NULL;
cdev->delayed_status = 0;
} }
static int set_config(struct usb_composite_dev *cdev, static int set_config(struct usb_composite_dev *cdev,
......
...@@ -1304,7 +1304,7 @@ static struct ffs_data *ffs_data_new(void) ...@@ -1304,7 +1304,7 @@ static struct ffs_data *ffs_data_new(void)
{ {
struct ffs_data *ffs = kzalloc(sizeof *ffs, GFP_KERNEL); struct ffs_data *ffs = kzalloc(sizeof *ffs, GFP_KERNEL);
if (unlikely(!ffs)) if (unlikely(!ffs))
return 0; return NULL;
ENTER(); ENTER();
......
...@@ -523,7 +523,7 @@ static int fsg_setup(struct usb_function *f, ...@@ -523,7 +523,7 @@ static int fsg_setup(struct usb_function *f,
*/ */
DBG(fsg, "bulk reset request\n"); DBG(fsg, "bulk reset request\n");
raise_exception(fsg->common, FSG_STATE_RESET); raise_exception(fsg->common, FSG_STATE_RESET);
return DELAYED_STATUS; return USB_GADGET_DELAYED_STATUS;
case US_BULK_GET_MAX_LUN: case US_BULK_GET_MAX_LUN:
if (ctrl->bRequestType != if (ctrl->bRequestType !=
...@@ -602,13 +602,14 @@ static bool start_out_transfer(struct fsg_common *common, struct fsg_buffhd *bh) ...@@ -602,13 +602,14 @@ static bool start_out_transfer(struct fsg_common *common, struct fsg_buffhd *bh)
return true; return true;
} }
static int sleep_thread(struct fsg_common *common) static int sleep_thread(struct fsg_common *common, bool can_freeze)
{ {
int rc = 0; int rc = 0;
/* Wait until a signal arrives or we are woken up */ /* Wait until a signal arrives or we are woken up */
for (;;) { for (;;) {
try_to_freeze(); if (can_freeze)
try_to_freeze();
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
if (signal_pending(current)) { if (signal_pending(current)) {
rc = -EINTR; rc = -EINTR;
...@@ -682,7 +683,7 @@ static int do_read(struct fsg_common *common) ...@@ -682,7 +683,7 @@ static int do_read(struct fsg_common *common)
/* Wait for the next buffer to become available */ /* Wait for the next buffer to become available */
bh = common->next_buffhd_to_fill; bh = common->next_buffhd_to_fill;
while (bh->state != BUF_STATE_EMPTY) { while (bh->state != BUF_STATE_EMPTY) {
rc = sleep_thread(common); rc = sleep_thread(common, false);
if (rc) if (rc)
return rc; return rc;
} }
...@@ -937,7 +938,7 @@ static int do_write(struct fsg_common *common) ...@@ -937,7 +938,7 @@ static int do_write(struct fsg_common *common)
} }
/* Wait for something to happen */ /* Wait for something to happen */
rc = sleep_thread(common); rc = sleep_thread(common, false);
if (rc) if (rc)
return rc; return rc;
} }
...@@ -1504,7 +1505,7 @@ static int throw_away_data(struct fsg_common *common) ...@@ -1504,7 +1505,7 @@ static int throw_away_data(struct fsg_common *common)
} }
/* Otherwise wait for something to happen */ /* Otherwise wait for something to happen */
rc = sleep_thread(common); rc = sleep_thread(common, true);
if (rc) if (rc)
return rc; return rc;
} }
...@@ -1625,7 +1626,7 @@ static int send_status(struct fsg_common *common) ...@@ -1625,7 +1626,7 @@ static int send_status(struct fsg_common *common)
/* Wait for the next buffer to become available */ /* Wait for the next buffer to become available */
bh = common->next_buffhd_to_fill; bh = common->next_buffhd_to_fill;
while (bh->state != BUF_STATE_EMPTY) { while (bh->state != BUF_STATE_EMPTY) {
rc = sleep_thread(common); rc = sleep_thread(common, true);
if (rc) if (rc)
return rc; return rc;
} }
...@@ -1828,7 +1829,7 @@ static int do_scsi_command(struct fsg_common *common) ...@@ -1828,7 +1829,7 @@ static int do_scsi_command(struct fsg_common *common)
bh = common->next_buffhd_to_fill; bh = common->next_buffhd_to_fill;
common->next_buffhd_to_drain = bh; common->next_buffhd_to_drain = bh;
while (bh->state != BUF_STATE_EMPTY) { while (bh->state != BUF_STATE_EMPTY) {
rc = sleep_thread(common); rc = sleep_thread(common, true);
if (rc) if (rc)
return rc; return rc;
} }
...@@ -2174,7 +2175,7 @@ static int get_next_command(struct fsg_common *common) ...@@ -2174,7 +2175,7 @@ static int get_next_command(struct fsg_common *common)
/* Wait for the next buffer to become available */ /* Wait for the next buffer to become available */
bh = common->next_buffhd_to_fill; bh = common->next_buffhd_to_fill;
while (bh->state != BUF_STATE_EMPTY) { while (bh->state != BUF_STATE_EMPTY) {
rc = sleep_thread(common); rc = sleep_thread(common, true);
if (rc) if (rc)
return rc; return rc;
} }
...@@ -2193,7 +2194,7 @@ static int get_next_command(struct fsg_common *common) ...@@ -2193,7 +2194,7 @@ static int get_next_command(struct fsg_common *common)
/* Wait for the CBW to arrive */ /* Wait for the CBW to arrive */
while (bh->state != BUF_STATE_FULL) { while (bh->state != BUF_STATE_FULL) {
rc = sleep_thread(common); rc = sleep_thread(common, true);
if (rc) if (rc)
return rc; return rc;
} }
...@@ -2379,7 +2380,7 @@ static void handle_exception(struct fsg_common *common) ...@@ -2379,7 +2380,7 @@ static void handle_exception(struct fsg_common *common)
} }
if (num_active == 0) if (num_active == 0)
break; break;
if (sleep_thread(common)) if (sleep_thread(common, true))
return; return;
} }
...@@ -2516,7 +2517,7 @@ static int fsg_main_thread(void *common_) ...@@ -2516,7 +2517,7 @@ static int fsg_main_thread(void *common_)
} }
if (!common->running) { if (!common->running) {
sleep_thread(common); sleep_thread(common, true);
continue; continue;
} }
...@@ -3111,7 +3112,7 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f) ...@@ -3111,7 +3112,7 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
fsg->common->can_stall); fsg->common->can_stall);
if (ret) if (ret)
return ret; return ret;
fsg_common_set_inquiry_string(fsg->common, 0, 0); fsg_common_set_inquiry_string(fsg->common, NULL, NULL);
ret = fsg_common_run_thread(fsg->common); ret = fsg_common_run_thread(fsg->common);
if (ret) if (ret)
return ret; return ret;
......
...@@ -54,6 +54,7 @@ ...@@ -54,6 +54,7 @@
*/ */
#ifdef CONFIG_ARCH_PXA #ifdef CONFIG_ARCH_PXA
#include <mach/pxa25x-udc.h> #include <mach/pxa25x-udc.h>
#include <mach/hardware.h>
#endif #endif
#ifdef CONFIG_ARCH_LUBBOCK #ifdef CONFIG_ARCH_LUBBOCK
......
...@@ -1180,6 +1180,7 @@ static int s3c_hsotg_process_req_feature(struct s3c_hsotg *hsotg, ...@@ -1180,6 +1180,7 @@ static int s3c_hsotg_process_req_feature(struct s3c_hsotg *hsotg,
} }
static void s3c_hsotg_enqueue_setup(struct s3c_hsotg *hsotg); static void s3c_hsotg_enqueue_setup(struct s3c_hsotg *hsotg);
static void s3c_hsotg_disconnect(struct s3c_hsotg *hsotg);
/** /**
* s3c_hsotg_process_control - process a control request * s3c_hsotg_process_control - process a control request
...@@ -1221,6 +1222,7 @@ static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg, ...@@ -1221,6 +1222,7 @@ static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg,
if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
switch (ctrl->bRequest) { switch (ctrl->bRequest) {
case USB_REQ_SET_ADDRESS: case USB_REQ_SET_ADDRESS:
s3c_hsotg_disconnect(hsotg);
dcfg = readl(hsotg->regs + DCFG); dcfg = readl(hsotg->regs + DCFG);
dcfg &= ~DCFG_DevAddr_MASK; dcfg &= ~DCFG_DevAddr_MASK;
dcfg |= ctrl->wValue << DCFG_DevAddr_SHIFT; dcfg |= ctrl->wValue << DCFG_DevAddr_SHIFT;
...@@ -1245,7 +1247,9 @@ static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg, ...@@ -1245,7 +1247,9 @@ static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg,
/* as a fallback, try delivering it to the driver to deal with */ /* as a fallback, try delivering it to the driver to deal with */
if (ret == 0 && hsotg->driver) { if (ret == 0 && hsotg->driver) {
spin_unlock(&hsotg->lock);
ret = hsotg->driver->setup(&hsotg->gadget, ctrl); ret = hsotg->driver->setup(&hsotg->gadget, ctrl);
spin_lock(&hsotg->lock);
if (ret < 0) if (ret < 0)
dev_dbg(hsotg->dev, "driver->setup() ret %d\n", ret); dev_dbg(hsotg->dev, "driver->setup() ret %d\n", ret);
} }
...@@ -1308,10 +1312,12 @@ static void s3c_hsotg_complete_setup(struct usb_ep *ep, ...@@ -1308,10 +1312,12 @@ static void s3c_hsotg_complete_setup(struct usb_ep *ep,
return; return;
} }
spin_lock(&hsotg->lock);
if (req->actual == 0) if (req->actual == 0)
s3c_hsotg_enqueue_setup(hsotg); s3c_hsotg_enqueue_setup(hsotg);
else else
s3c_hsotg_process_control(hsotg, req->buf); s3c_hsotg_process_control(hsotg, req->buf);
spin_unlock(&hsotg->lock);
} }
/** /**
...@@ -2533,7 +2539,6 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw) ...@@ -2533,7 +2539,6 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw)
writel(GINTSTS_USBSusp, hsotg->regs + GINTSTS); writel(GINTSTS_USBSusp, hsotg->regs + GINTSTS);
call_gadget(hsotg, suspend); call_gadget(hsotg, suspend);
s3c_hsotg_disconnect(hsotg);
} }
if (gintsts & GINTSTS_WkUpInt) { if (gintsts & GINTSTS_WkUpInt) {
......
...@@ -119,10 +119,6 @@ static inline bool fsg_lun_is_open(struct fsg_lun *curlun) ...@@ -119,10 +119,6 @@ static inline bool fsg_lun_is_open(struct fsg_lun *curlun)
return curlun->filp != NULL; return curlun->filp != NULL;
} }
/* Big enough to hold our biggest descriptor */
#define EP0_BUFSIZE 256
#define DELAYED_STATUS (EP0_BUFSIZE + 999) /* An impossibly large value */
/* Default size of buffer length. */ /* Default size of buffer length. */
#define FSG_BUFLEN ((u32)16384) #define FSG_BUFLEN ((u32)16384)
......
...@@ -370,7 +370,7 @@ static int bot_prepare_reqs(struct f_uas *fu) ...@@ -370,7 +370,7 @@ static int bot_prepare_reqs(struct f_uas *fu)
return -ENOMEM; return -ENOMEM;
} }
void bot_cleanup_old_alt(struct f_uas *fu) static void bot_cleanup_old_alt(struct f_uas *fu)
{ {
if (!(fu->flags & USBG_ENABLED)) if (!(fu->flags & USBG_ENABLED))
return; return;
......
...@@ -91,17 +91,17 @@ static struct usb_zero_options gzero_options = { ...@@ -91,17 +91,17 @@ static struct usb_zero_options gzero_options = {
* functional coverage for the "USBCV" test harness from USB-IF. * functional coverage for the "USBCV" test harness from USB-IF.
* It's always set if OTG mode is enabled. * It's always set if OTG mode is enabled.
*/ */
unsigned autoresume = DEFAULT_AUTORESUME; static unsigned autoresume = DEFAULT_AUTORESUME;
module_param(autoresume, uint, S_IRUGO); module_param(autoresume, uint, S_IRUGO);
MODULE_PARM_DESC(autoresume, "zero, or seconds before remote wakeup"); MODULE_PARM_DESC(autoresume, "zero, or seconds before remote wakeup");
/* Maximum Autoresume time */ /* Maximum Autoresume time */
unsigned max_autoresume; static unsigned max_autoresume;
module_param(max_autoresume, uint, S_IRUGO); module_param(max_autoresume, uint, S_IRUGO);
MODULE_PARM_DESC(max_autoresume, "maximum seconds before remote wakeup"); MODULE_PARM_DESC(max_autoresume, "maximum seconds before remote wakeup");
/* Interval between two remote wakeups */ /* Interval between two remote wakeups */
unsigned autoresume_interval_ms; static unsigned autoresume_interval_ms;
module_param(autoresume_interval_ms, uint, S_IRUGO); module_param(autoresume_interval_ms, uint, S_IRUGO);
MODULE_PARM_DESC(autoresume_interval_ms, MODULE_PARM_DESC(autoresume_interval_ms,
"milliseconds to increase successive wakeup delays"); "milliseconds to increase successive wakeup delays");
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
......
...@@ -2973,8 +2973,58 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring, ...@@ -2973,8 +2973,58 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
} }
while (1) { while (1) {
if (room_on_ring(xhci, ep_ring, num_trbs)) if (room_on_ring(xhci, ep_ring, num_trbs)) {
break; union xhci_trb *trb = ep_ring->enqueue;
unsigned int usable = ep_ring->enq_seg->trbs +
TRBS_PER_SEGMENT - 1 - trb;
u32 nop_cmd;
/*
* Section 4.11.7.1 TD Fragments states that a link
* TRB must only occur at the boundary between
* data bursts (eg 512 bytes for 480M).
* While it is possible to split a large fragment
* we don't know the size yet.
* Simplest solution is to fill the trb before the
* LINK with nop commands.
*/
if (num_trbs == 1 || num_trbs <= usable || usable == 0)
break;
if (ep_ring->type != TYPE_BULK)
/*
* While isoc transfers might have a buffer that
* crosses a 64k boundary it is unlikely.
* Since we can't add NOPs without generating
* gaps in the traffic just hope it never
* happens at the end of the ring.
* This could be fixed by writing a LINK TRB
* instead of the first NOP - however the
* TRB_TYPE_LINK_LE32() calls would all need
* changing to check the ring length.
*/
break;
if (num_trbs >= TRBS_PER_SEGMENT) {
xhci_err(xhci, "Too many fragments %d, max %d\n",
num_trbs, TRBS_PER_SEGMENT - 1);
return -ENOMEM;
}
nop_cmd = cpu_to_le32(TRB_TYPE(TRB_TR_NOOP) |
ep_ring->cycle_state);
ep_ring->num_trbs_free -= usable;
do {
trb->generic.field[0] = 0;
trb->generic.field[1] = 0;
trb->generic.field[2] = 0;
trb->generic.field[3] = nop_cmd;
trb++;
} while (--usable);
ep_ring->enqueue = trb;
if (room_on_ring(xhci, ep_ring, num_trbs))
break;
}
if (ep_ring == xhci->cmd_ring) { if (ep_ring == xhci->cmd_ring) {
xhci_err(xhci, "Do not support expand command ring\n"); xhci_err(xhci, "Do not support expand command ring\n");
......
...@@ -1809,7 +1809,6 @@ static void musb_free(struct musb *musb) ...@@ -1809,7 +1809,6 @@ static void musb_free(struct musb *musb)
disable_irq_wake(musb->nIrq); disable_irq_wake(musb->nIrq);
free_irq(musb->nIrq, musb); free_irq(musb->nIrq, musb);
} }
cancel_work_sync(&musb->irq_work);
musb_host_free(musb); musb_host_free(musb);
} }
...@@ -1896,6 +1895,9 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) ...@@ -1896,6 +1895,9 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
musb_platform_disable(musb); musb_platform_disable(musb);
musb_generic_disable(musb); musb_generic_disable(musb);
/* Init IRQ workqueue before request_irq */
INIT_WORK(&musb->irq_work, musb_irq_work);
/* setup musb parts of the core (especially endpoints) */ /* setup musb parts of the core (especially endpoints) */
status = musb_core_init(plat->config->multipoint status = musb_core_init(plat->config->multipoint
? MUSB_CONTROLLER_MHDRC ? MUSB_CONTROLLER_MHDRC
...@@ -1905,9 +1907,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) ...@@ -1905,9 +1907,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
setup_timer(&musb->otg_timer, musb_otg_timer_func, (unsigned long) musb); setup_timer(&musb->otg_timer, musb_otg_timer_func, (unsigned long) musb);
/* Init IRQ workqueue before request_irq */
INIT_WORK(&musb->irq_work, musb_irq_work);
/* attach to the IRQ */ /* attach to the IRQ */
if (request_irq(nIrq, musb->isr, 0, dev_name(dev), musb)) { if (request_irq(nIrq, musb->isr, 0, dev_name(dev), musb)) {
dev_err(dev, "request_irq %d failed!\n", nIrq); dev_err(dev, "request_irq %d failed!\n", nIrq);
...@@ -1981,6 +1980,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) ...@@ -1981,6 +1980,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
musb_host_cleanup(musb); musb_host_cleanup(musb);
fail3: fail3:
cancel_work_sync(&musb->irq_work);
if (musb->dma_controller) if (musb->dma_controller)
dma_controller_destroy(musb->dma_controller); dma_controller_destroy(musb->dma_controller);
fail2_5: fail2_5:
...@@ -2043,6 +2043,7 @@ static int musb_remove(struct platform_device *pdev) ...@@ -2043,6 +2043,7 @@ static int musb_remove(struct platform_device *pdev)
if (musb->dma_controller) if (musb->dma_controller)
dma_controller_destroy(musb->dma_controller); dma_controller_destroy(musb->dma_controller);
cancel_work_sync(&musb->irq_work);
musb_free(musb); musb_free(musb);
device_init_wakeup(dev, 0); device_init_wakeup(dev, 0);
return 0; return 0;
......
...@@ -38,6 +38,7 @@ struct cppi41_dma_channel { ...@@ -38,6 +38,7 @@ struct cppi41_dma_channel {
u32 prog_len; u32 prog_len;
u32 transferred; u32 transferred;
u32 packet_sz; u32 packet_sz;
struct list_head tx_check;
}; };
#define MUSB_DMA_NUM_CHANNELS 15 #define MUSB_DMA_NUM_CHANNELS 15
...@@ -47,6 +48,8 @@ struct cppi41_dma_controller { ...@@ -47,6 +48,8 @@ struct cppi41_dma_controller {
struct cppi41_dma_channel rx_channel[MUSB_DMA_NUM_CHANNELS]; struct cppi41_dma_channel rx_channel[MUSB_DMA_NUM_CHANNELS];
struct cppi41_dma_channel tx_channel[MUSB_DMA_NUM_CHANNELS]; struct cppi41_dma_channel tx_channel[MUSB_DMA_NUM_CHANNELS];
struct musb *musb; struct musb *musb;
struct hrtimer early_tx;
struct list_head early_tx_list;
u32 rx_mode; u32 rx_mode;
u32 tx_mode; u32 tx_mode;
u32 auto_req; u32 auto_req;
...@@ -96,31 +99,27 @@ static void update_rx_toggle(struct cppi41_dma_channel *cppi41_channel) ...@@ -96,31 +99,27 @@ static void update_rx_toggle(struct cppi41_dma_channel *cppi41_channel)
cppi41_channel->usb_toggle = toggle; cppi41_channel->usb_toggle = toggle;
} }
static void cppi41_dma_callback(void *private_data) static bool musb_is_tx_fifo_empty(struct musb_hw_ep *hw_ep)
{ {
struct dma_channel *channel = private_data; u8 epnum = hw_ep->epnum;
struct cppi41_dma_channel *cppi41_channel = channel->private_data; struct musb *musb = hw_ep->musb;
struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep; void __iomem *epio = musb->endpoints[epnum].regs;
struct musb *musb = hw_ep->musb; u16 csr;
unsigned long flags;
struct dma_tx_state txstate;
u32 transferred;
spin_lock_irqsave(&musb->lock, flags); csr = musb_readw(epio, MUSB_TXCSR);
if (csr & MUSB_TXCSR_TXPKTRDY)
return false;
return true;
}
dmaengine_tx_status(cppi41_channel->dc, cppi41_channel->cookie, static void cppi41_dma_callback(void *private_data);
&txstate);
transferred = cppi41_channel->prog_len - txstate.residue;
cppi41_channel->transferred += transferred;
dev_dbg(musb->controller, "DMA transfer done on hw_ep=%d bytes=%d/%d\n", static void cppi41_trans_done(struct cppi41_dma_channel *cppi41_channel)
hw_ep->epnum, cppi41_channel->transferred, {
cppi41_channel->total_len); struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep;
struct musb *musb = hw_ep->musb;
update_rx_toggle(cppi41_channel); if (!cppi41_channel->prog_len) {
if (cppi41_channel->transferred == cppi41_channel->total_len ||
transferred < cppi41_channel->packet_sz) {
/* done, complete */ /* done, complete */
cppi41_channel->channel.actual_len = cppi41_channel->channel.actual_len =
...@@ -150,13 +149,11 @@ static void cppi41_dma_callback(void *private_data) ...@@ -150,13 +149,11 @@ static void cppi41_dma_callback(void *private_data)
remain_bytes, remain_bytes,
direction, direction,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK); DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (WARN_ON(!dma_desc)) { if (WARN_ON(!dma_desc))
spin_unlock_irqrestore(&musb->lock, flags);
return; return;
}
dma_desc->callback = cppi41_dma_callback; dma_desc->callback = cppi41_dma_callback;
dma_desc->callback_param = channel; dma_desc->callback_param = &cppi41_channel->channel;
cppi41_channel->cookie = dma_desc->tx_submit(dma_desc); cppi41_channel->cookie = dma_desc->tx_submit(dma_desc);
dma_async_issue_pending(dc); dma_async_issue_pending(dc);
...@@ -166,6 +163,117 @@ static void cppi41_dma_callback(void *private_data) ...@@ -166,6 +163,117 @@ static void cppi41_dma_callback(void *private_data)
musb_writew(epio, MUSB_RXCSR, csr); musb_writew(epio, MUSB_RXCSR, csr);
} }
} }
}
static enum hrtimer_restart cppi41_recheck_tx_req(struct hrtimer *timer)
{
struct cppi41_dma_controller *controller;
struct cppi41_dma_channel *cppi41_channel, *n;
struct musb *musb;
unsigned long flags;
enum hrtimer_restart ret = HRTIMER_NORESTART;
controller = container_of(timer, struct cppi41_dma_controller,
early_tx);
musb = controller->musb;
spin_lock_irqsave(&musb->lock, flags);
list_for_each_entry_safe(cppi41_channel, n, &controller->early_tx_list,
tx_check) {
bool empty;
struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep;
empty = musb_is_tx_fifo_empty(hw_ep);
if (empty) {
list_del_init(&cppi41_channel->tx_check);
cppi41_trans_done(cppi41_channel);
}
}
if (!list_empty(&controller->early_tx_list)) {
ret = HRTIMER_RESTART;
hrtimer_forward_now(&controller->early_tx,
ktime_set(0, 150 * NSEC_PER_USEC));
}
spin_unlock_irqrestore(&musb->lock, flags);
return ret;
}
static void cppi41_dma_callback(void *private_data)
{
struct dma_channel *channel = private_data;
struct cppi41_dma_channel *cppi41_channel = channel->private_data;
struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep;
struct musb *musb = hw_ep->musb;
unsigned long flags;
struct dma_tx_state txstate;
u32 transferred;
bool empty;
spin_lock_irqsave(&musb->lock, flags);
dmaengine_tx_status(cppi41_channel->dc, cppi41_channel->cookie,
&txstate);
transferred = cppi41_channel->prog_len - txstate.residue;
cppi41_channel->transferred += transferred;
dev_dbg(musb->controller, "DMA transfer done on hw_ep=%d bytes=%d/%d\n",
hw_ep->epnum, cppi41_channel->transferred,
cppi41_channel->total_len);
update_rx_toggle(cppi41_channel);
if (cppi41_channel->transferred == cppi41_channel->total_len ||
transferred < cppi41_channel->packet_sz)
cppi41_channel->prog_len = 0;
empty = musb_is_tx_fifo_empty(hw_ep);
if (empty) {
cppi41_trans_done(cppi41_channel);
} else {
struct cppi41_dma_controller *controller;
/*
* On AM335x it has been observed that the TX interrupt fires
* too early that means the TXFIFO is not yet empty but the DMA
* engine says that it is done with the transfer. We don't
* receive a FIFO empty interrupt so the only thing we can do is
* to poll for the bit. On HS it usually takes 2us, on FS around
* 110us - 150us depending on the transfer size.
* We spin on HS (no longer than than 25us and setup a timer on
* FS to check for the bit and complete the transfer.
*/
controller = cppi41_channel->controller;
if (musb->g.speed == USB_SPEED_HIGH) {
unsigned wait = 25;
do {
empty = musb_is_tx_fifo_empty(hw_ep);
if (empty)
break;
wait--;
if (!wait)
break;
udelay(1);
} while (1);
empty = musb_is_tx_fifo_empty(hw_ep);
if (empty) {
cppi41_trans_done(cppi41_channel);
goto out;
}
}
list_add_tail(&cppi41_channel->tx_check,
&controller->early_tx_list);
if (!hrtimer_active(&controller->early_tx)) {
hrtimer_start_range_ns(&controller->early_tx,
ktime_set(0, 140 * NSEC_PER_USEC),
40 * NSEC_PER_USEC,
HRTIMER_MODE_REL);
}
}
out:
spin_unlock_irqrestore(&musb->lock, flags); spin_unlock_irqrestore(&musb->lock, flags);
} }
...@@ -364,6 +472,8 @@ static int cppi41_is_compatible(struct dma_channel *channel, u16 maxpacket, ...@@ -364,6 +472,8 @@ static int cppi41_is_compatible(struct dma_channel *channel, u16 maxpacket,
WARN_ON(1); WARN_ON(1);
return 1; return 1;
} }
if (cppi41_channel->hw_ep->ep_in.type != USB_ENDPOINT_XFER_BULK)
return 0;
if (cppi41_channel->is_tx) if (cppi41_channel->is_tx)
return 1; return 1;
/* AM335x Advisory 1.0.13. No workaround for device RX mode */ /* AM335x Advisory 1.0.13. No workaround for device RX mode */
...@@ -388,6 +498,7 @@ static int cppi41_dma_channel_abort(struct dma_channel *channel) ...@@ -388,6 +498,7 @@ static int cppi41_dma_channel_abort(struct dma_channel *channel)
if (cppi41_channel->channel.status == MUSB_DMA_STATUS_FREE) if (cppi41_channel->channel.status == MUSB_DMA_STATUS_FREE)
return 0; return 0;
list_del_init(&cppi41_channel->tx_check);
if (is_tx) { if (is_tx) {
csr = musb_readw(epio, MUSB_TXCSR); csr = musb_readw(epio, MUSB_TXCSR);
csr &= ~MUSB_TXCSR_DMAENAB; csr &= ~MUSB_TXCSR_DMAENAB;
...@@ -495,6 +606,7 @@ static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller) ...@@ -495,6 +606,7 @@ static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller)
cppi41_channel->controller = controller; cppi41_channel->controller = controller;
cppi41_channel->port_num = port; cppi41_channel->port_num = port;
cppi41_channel->is_tx = is_tx; cppi41_channel->is_tx = is_tx;
INIT_LIST_HEAD(&cppi41_channel->tx_check);
musb_dma = &cppi41_channel->channel; musb_dma = &cppi41_channel->channel;
musb_dma->private_data = cppi41_channel; musb_dma->private_data = cppi41_channel;
...@@ -520,6 +632,7 @@ void dma_controller_destroy(struct dma_controller *c) ...@@ -520,6 +632,7 @@ void dma_controller_destroy(struct dma_controller *c)
struct cppi41_dma_controller *controller = container_of(c, struct cppi41_dma_controller *controller = container_of(c,
struct cppi41_dma_controller, controller); struct cppi41_dma_controller, controller);
hrtimer_cancel(&controller->early_tx);
cppi41_dma_controller_stop(controller); cppi41_dma_controller_stop(controller);
kfree(controller); kfree(controller);
} }
...@@ -539,6 +652,9 @@ struct dma_controller *dma_controller_create(struct musb *musb, ...@@ -539,6 +652,9 @@ struct dma_controller *dma_controller_create(struct musb *musb,
if (!controller) if (!controller)
goto kzalloc_fail; goto kzalloc_fail;
hrtimer_init(&controller->early_tx, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
controller->early_tx.function = cppi41_recheck_tx_req;
INIT_LIST_HEAD(&controller->early_tx_list);
controller->musb = musb; controller->musb = musb;
controller->controller.channel_alloc = cppi41_dma_channel_allocate; controller->controller.channel_alloc = cppi41_dma_channel_allocate;
......
...@@ -1796,7 +1796,11 @@ int musb_gadget_setup(struct musb *musb) ...@@ -1796,7 +1796,11 @@ int musb_gadget_setup(struct musb *musb)
/* this "gadget" abstracts/virtualizes the controller */ /* this "gadget" abstracts/virtualizes the controller */
musb->g.name = musb_driver_name; musb->g.name = musb_driver_name;
#if IS_ENABLED(CONFIG_USB_MUSB_DUAL_ROLE)
musb->g.is_otg = 1; musb->g.is_otg = 1;
#elif IS_ENABLED(CONFIG_USB_MUSB_GADGET)
musb->g.is_otg = 0;
#endif
musb_g_init_endpoints(musb); musb_g_init_endpoints(musb);
......
...@@ -52,8 +52,7 @@ static int am335x_phy_probe(struct platform_device *pdev) ...@@ -52,8 +52,7 @@ static int am335x_phy_probe(struct platform_device *pdev)
return am_phy->id; return am_phy->id;
} }
ret = usb_phy_gen_create_phy(dev, &am_phy->usb_phy_gen, ret = usb_phy_gen_create_phy(dev, &am_phy->usb_phy_gen, NULL);
USB_PHY_TYPE_USB2, 0, false);
if (ret) if (ret)
return ret; return ret;
...@@ -66,8 +65,6 @@ static int am335x_phy_probe(struct platform_device *pdev) ...@@ -66,8 +65,6 @@ static int am335x_phy_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, am_phy); platform_set_drvdata(pdev, am_phy);
return 0; return 0;
return ret;
} }
static int am335x_phy_remove(struct platform_device *pdev) static int am335x_phy_remove(struct platform_device *pdev)
......
...@@ -48,8 +48,9 @@ void usb_nop_xceiv_register(void) ...@@ -48,8 +48,9 @@ void usb_nop_xceiv_register(void)
if (pd) if (pd)
return; return;
pd = platform_device_register_simple("usb_phy_gen_xceiv", -1, NULL, 0); pd = platform_device_register_simple("usb_phy_gen_xceiv", -1, NULL, 0);
if (!pd) { if (IS_ERR(pd)) {
pr_err("Unable to register generic usb transceiver\n"); pr_err("Unable to register generic usb transceiver\n");
pd = NULL;
return; return;
} }
} }
...@@ -150,10 +151,40 @@ static int nop_set_host(struct usb_otg *otg, struct usb_bus *host) ...@@ -150,10 +151,40 @@ static int nop_set_host(struct usb_otg *otg, struct usb_bus *host)
} }
int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop, int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop,
enum usb_phy_type type, u32 clk_rate, bool needs_vcc) struct usb_phy_gen_xceiv_platform_data *pdata)
{ {
enum usb_phy_type type = USB_PHY_TYPE_USB2;
int err; int err;
u32 clk_rate = 0;
bool needs_vcc = false;
nop->reset_active_low = true; /* default behaviour */
if (dev->of_node) {
struct device_node *node = dev->of_node;
enum of_gpio_flags flags = 0;
if (of_property_read_u32(node, "clock-frequency", &clk_rate))
clk_rate = 0;
needs_vcc = of_property_read_bool(node, "vcc-supply");
nop->gpio_reset = of_get_named_gpio_flags(node, "reset-gpios",
0, &flags);
if (nop->gpio_reset == -EPROBE_DEFER)
return -EPROBE_DEFER;
nop->reset_active_low = flags & OF_GPIO_ACTIVE_LOW;
} else if (pdata) {
type = pdata->type;
clk_rate = pdata->clk_rate;
needs_vcc = pdata->needs_vcc;
nop->gpio_reset = pdata->gpio_reset;
} else {
nop->gpio_reset = -1;
}
nop->phy.otg = devm_kzalloc(dev, sizeof(*nop->phy.otg), nop->phy.otg = devm_kzalloc(dev, sizeof(*nop->phy.otg),
GFP_KERNEL); GFP_KERNEL);
if (!nop->phy.otg) if (!nop->phy.otg)
...@@ -218,43 +249,14 @@ EXPORT_SYMBOL_GPL(usb_phy_gen_create_phy); ...@@ -218,43 +249,14 @@ EXPORT_SYMBOL_GPL(usb_phy_gen_create_phy);
static int usb_phy_gen_xceiv_probe(struct platform_device *pdev) static int usb_phy_gen_xceiv_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct usb_phy_gen_xceiv_platform_data *pdata =
dev_get_platdata(&pdev->dev);
struct usb_phy_gen_xceiv *nop; struct usb_phy_gen_xceiv *nop;
enum usb_phy_type type = USB_PHY_TYPE_USB2;
int err; int err;
u32 clk_rate = 0;
bool needs_vcc = false;
nop = devm_kzalloc(dev, sizeof(*nop), GFP_KERNEL); nop = devm_kzalloc(dev, sizeof(*nop), GFP_KERNEL);
if (!nop) if (!nop)
return -ENOMEM; return -ENOMEM;
nop->reset_active_low = true; /* default behaviour */ err = usb_phy_gen_create_phy(dev, nop, dev_get_platdata(&pdev->dev));
if (dev->of_node) {
struct device_node *node = dev->of_node;
enum of_gpio_flags flags;
if (of_property_read_u32(node, "clock-frequency", &clk_rate))
clk_rate = 0;
needs_vcc = of_property_read_bool(node, "vcc-supply");
nop->gpio_reset = of_get_named_gpio_flags(node, "reset-gpios",
0, &flags);
if (nop->gpio_reset == -EPROBE_DEFER)
return -EPROBE_DEFER;
nop->reset_active_low = flags & OF_GPIO_ACTIVE_LOW;
} else if (pdata) {
type = pdata->type;
clk_rate = pdata->clk_rate;
needs_vcc = pdata->needs_vcc;
nop->gpio_reset = pdata->gpio_reset;
}
err = usb_phy_gen_create_phy(dev, nop, type, clk_rate, needs_vcc);
if (err) if (err)
return err; return err;
...@@ -271,8 +273,6 @@ static int usb_phy_gen_xceiv_probe(struct platform_device *pdev) ...@@ -271,8 +273,6 @@ static int usb_phy_gen_xceiv_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, nop); platform_set_drvdata(pdev, nop);
return 0; return 0;
return err;
} }
static int usb_phy_gen_xceiv_remove(struct platform_device *pdev) static int usb_phy_gen_xceiv_remove(struct platform_device *pdev)
......
#ifndef _PHY_GENERIC_H_ #ifndef _PHY_GENERIC_H_
#define _PHY_GENERIC_H_ #define _PHY_GENERIC_H_
#include <linux/usb/usb_phy_gen_xceiv.h>
struct usb_phy_gen_xceiv { struct usb_phy_gen_xceiv {
struct usb_phy phy; struct usb_phy phy;
struct device *dev; struct device *dev;
...@@ -14,6 +16,6 @@ int usb_gen_phy_init(struct usb_phy *phy); ...@@ -14,6 +16,6 @@ int usb_gen_phy_init(struct usb_phy *phy);
void usb_gen_phy_shutdown(struct usb_phy *phy); void usb_gen_phy_shutdown(struct usb_phy *phy);
int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop, int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop,
enum usb_phy_type type, u32 clk_rate, bool needs_vcc); struct usb_phy_gen_xceiv_platform_data *pdata);
#endif #endif
...@@ -164,7 +164,7 @@ static int mxs_phy_probe(struct platform_device *pdev) ...@@ -164,7 +164,7 @@ static int mxs_phy_probe(struct platform_device *pdev)
mxs_phy->clk = clk; mxs_phy->clk = clk;
platform_set_drvdata(pdev, &mxs_phy->phy); platform_set_drvdata(pdev, mxs_phy);
ret = usb_add_phy_dev(&mxs_phy->phy); ret = usb_add_phy_dev(&mxs_phy->phy);
if (ret) if (ret)
......
...@@ -107,10 +107,10 @@ static void __rcar_gen2_usb_phy_init(struct rcar_gen2_usb_phy_priv *priv) ...@@ -107,10 +107,10 @@ static void __rcar_gen2_usb_phy_init(struct rcar_gen2_usb_phy_priv *priv)
clk_prepare_enable(priv->clk); clk_prepare_enable(priv->clk);
/* Set USB channels in the USBHS UGCTRL2 register */ /* Set USB channels in the USBHS UGCTRL2 register */
val = ioread32(priv->base); val = ioread32(priv->base + USBHS_UGCTRL2_REG);
val &= ~(USBHS_UGCTRL2_USB0_HS | USBHS_UGCTRL2_USB2_SS); val &= ~(USBHS_UGCTRL2_USB0_HS | USBHS_UGCTRL2_USB2_SS);
val |= priv->ugctrl2; val |= priv->ugctrl2;
iowrite32(val, priv->base); iowrite32(val, priv->base + USBHS_UGCTRL2_REG);
} }
/* Shutdown USB channels */ /* Shutdown USB channels */
......
...@@ -2123,6 +2123,20 @@ static void ftdi_set_termios(struct tty_struct *tty, ...@@ -2123,6 +2123,20 @@ static void ftdi_set_termios(struct tty_struct *tty,
termios->c_cflag |= CRTSCTS; termios->c_cflag |= CRTSCTS;
} }
/*
* All FTDI UART chips are limited to CS7/8. We won't pretend to
* support CS5/6 and revert the CSIZE setting instead.
*/
if ((C_CSIZE(tty) != CS8) && (C_CSIZE(tty) != CS7)) {
dev_warn(ddev, "requested CSIZE setting not supported\n");
termios->c_cflag &= ~CSIZE;
if (old_termios)
termios->c_cflag |= old_termios->c_cflag & CSIZE;
else
termios->c_cflag |= CS8;
}
cflag = termios->c_cflag; cflag = termios->c_cflag;
if (!old_termios) if (!old_termios)
...@@ -2159,19 +2173,16 @@ static void ftdi_set_termios(struct tty_struct *tty, ...@@ -2159,19 +2173,16 @@ static void ftdi_set_termios(struct tty_struct *tty,
} else { } else {
urb_value |= FTDI_SIO_SET_DATA_PARITY_NONE; urb_value |= FTDI_SIO_SET_DATA_PARITY_NONE;
} }
if (cflag & CSIZE) { switch (cflag & CSIZE) {
switch (cflag & CSIZE) { case CS7:
case CS7: urb_value |= 7;
urb_value |= 7; dev_dbg(ddev, "Setting CS7\n");
dev_dbg(ddev, "Setting CS7\n"); break;
break; default:
case CS8: case CS8:
urb_value |= 8; urb_value |= 8;
dev_dbg(ddev, "Setting CS8\n"); dev_dbg(ddev, "Setting CS8\n");
break; break;
default:
dev_err(ddev, "CSIZE was set but not CS7-CS8\n");
}
} }
/* This is needed by the break command since it uses the same command /* This is needed by the break command since it uses the same command
......
...@@ -173,16 +173,8 @@ int usb_serial_generic_write_start(struct usb_serial_port *port, ...@@ -173,16 +173,8 @@ int usb_serial_generic_write_start(struct usb_serial_port *port,
clear_bit_unlock(USB_SERIAL_WRITE_BUSY, &port->flags); clear_bit_unlock(USB_SERIAL_WRITE_BUSY, &port->flags);
return result; return result;
} }
/*
* Try sending off another urb, unless called from completion handler
* (in which case there will be no free urb or no data).
*/
if (mem_flags != GFP_ATOMIC)
goto retry;
clear_bit_unlock(USB_SERIAL_WRITE_BUSY, &port->flags); goto retry; /* try sending off another urb */
return 0;
} }
EXPORT_SYMBOL_GPL(usb_serial_generic_write_start); EXPORT_SYMBOL_GPL(usb_serial_generic_write_start);
...@@ -208,7 +200,7 @@ int usb_serial_generic_write(struct tty_struct *tty, ...@@ -208,7 +200,7 @@ int usb_serial_generic_write(struct tty_struct *tty,
return 0; return 0;
count = kfifo_in_locked(&port->write_fifo, buf, count, &port->lock); count = kfifo_in_locked(&port->write_fifo, buf, count, &port->lock);
result = usb_serial_generic_write_start(port, GFP_KERNEL); result = usb_serial_generic_write_start(port, GFP_ATOMIC);
if (result) if (result)
return result; return result;
......
...@@ -1813,25 +1813,25 @@ static void mos7840_change_port_settings(struct tty_struct *tty, ...@@ -1813,25 +1813,25 @@ static void mos7840_change_port_settings(struct tty_struct *tty,
iflag = tty->termios.c_iflag; iflag = tty->termios.c_iflag;
/* Change the number of bits */ /* Change the number of bits */
if (cflag & CSIZE) { switch (cflag & CSIZE) {
switch (cflag & CSIZE) { case CS5:
case CS5: lData = LCR_BITS_5;
lData = LCR_BITS_5; break;
break;
case CS6: case CS6:
lData = LCR_BITS_6; lData = LCR_BITS_6;
break; break;
case CS7: case CS7:
lData = LCR_BITS_7; lData = LCR_BITS_7;
break; break;
default:
case CS8: default:
lData = LCR_BITS_8; case CS8:
break; lData = LCR_BITS_8;
} break;
} }
/* Change the Parity bit */ /* Change the Parity bit */
if (cflag & PARENB) { if (cflag & PARENB) {
if (cflag & PARODD) { if (cflag & PARODD) {
......
...@@ -85,6 +85,7 @@ static void option_instat_callback(struct urb *urb); ...@@ -85,6 +85,7 @@ static void option_instat_callback(struct urb *urb);
#define HUAWEI_PRODUCT_K4505 0x1464 #define HUAWEI_PRODUCT_K4505 0x1464
#define HUAWEI_PRODUCT_K3765 0x1465 #define HUAWEI_PRODUCT_K3765 0x1465
#define HUAWEI_PRODUCT_K4605 0x14C6 #define HUAWEI_PRODUCT_K4605 0x14C6
#define HUAWEI_PRODUCT_E173S6 0x1C07
#define QUANTA_VENDOR_ID 0x0408 #define QUANTA_VENDOR_ID 0x0408
#define QUANTA_PRODUCT_Q101 0xEA02 #define QUANTA_PRODUCT_Q101 0xEA02
...@@ -572,6 +573,8 @@ static const struct usb_device_id option_ids[] = { ...@@ -572,6 +573,8 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c23, USB_CLASS_COMM, 0x02, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c23, USB_CLASS_COMM, 0x02, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E173, 0xff, 0xff, 0xff), { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E173, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t) &net_intf1_blacklist }, .driver_info = (kernel_ulong_t) &net_intf1_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E173S6, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t) &net_intf1_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1750, 0xff, 0xff, 0xff), { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1750, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t) &net_intf2_blacklist }, .driver_info = (kernel_ulong_t) &net_intf2_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1441, USB_CLASS_COMM, 0x02, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1441, USB_CLASS_COMM, 0x02, 0xff) },
...@@ -634,6 +637,10 @@ static const struct usb_device_id option_ids[] = { ...@@ -634,6 +637,10 @@ static const struct usb_device_id option_ids[] = {
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x6D) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x6D) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x6E) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x6E) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x6F) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x6F) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x72) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x73) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x74) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x75) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x78) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x78) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x79) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x79) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x7A) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x7A) },
...@@ -688,6 +695,10 @@ static const struct usb_device_id option_ids[] = { ...@@ -688,6 +695,10 @@ static const struct usb_device_id option_ids[] = {
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x6D) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x6D) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x6E) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x6E) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x6F) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x6F) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x72) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x73) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x74) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x75) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x78) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x78) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x79) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x79) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x7A) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x7A) },
...@@ -742,6 +753,10 @@ static const struct usb_device_id option_ids[] = { ...@@ -742,6 +753,10 @@ static const struct usb_device_id option_ids[] = {
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6D) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6D) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6E) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6E) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6F) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6F) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x72) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x73) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x74) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x75) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x78) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x78) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x79) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x79) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x7A) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x7A) },
...@@ -796,6 +811,10 @@ static const struct usb_device_id option_ids[] = { ...@@ -796,6 +811,10 @@ static const struct usb_device_id option_ids[] = {
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6D) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6D) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6E) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6E) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6F) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6F) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x72) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x73) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x74) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x75) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x78) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x78) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x79) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x79) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x7A) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x7A) },
...@@ -850,6 +869,10 @@ static const struct usb_device_id option_ids[] = { ...@@ -850,6 +869,10 @@ static const struct usb_device_id option_ids[] = {
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6D) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6D) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6E) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6E) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6F) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6F) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x72) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x73) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x74) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x75) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x78) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x78) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x79) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x79) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x7A) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x7A) },
...@@ -904,6 +927,10 @@ static const struct usb_device_id option_ids[] = { ...@@ -904,6 +927,10 @@ static const struct usb_device_id option_ids[] = {
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6D) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6D) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6E) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6E) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6F) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6F) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x72) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x73) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x74) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x75) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x78) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x78) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x79) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x79) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x7A) }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x7A) },
......
...@@ -361,23 +361,21 @@ static void pl2303_set_termios(struct tty_struct *tty, ...@@ -361,23 +361,21 @@ static void pl2303_set_termios(struct tty_struct *tty,
0, 0, buf, 7, 100); 0, 0, buf, 7, 100);
dev_dbg(&port->dev, "0xa1:0x21:0:0 %d - %7ph\n", i, buf); dev_dbg(&port->dev, "0xa1:0x21:0:0 %d - %7ph\n", i, buf);
if (C_CSIZE(tty)) { switch (C_CSIZE(tty)) {
switch (C_CSIZE(tty)) { case CS5:
case CS5: buf[6] = 5;
buf[6] = 5; break;
break; case CS6:
case CS6: buf[6] = 6;
buf[6] = 6; break;
break; case CS7:
case CS7: buf[6] = 7;
buf[6] = 7; break;
break; default:
default: case CS8:
case CS8: buf[6] = 8;
buf[6] = 8;
}
dev_dbg(&port->dev, "data bits = %d\n", buf[6]);
} }
dev_dbg(&port->dev, "data bits = %d\n", buf[6]);
/* For reference buf[0]:buf[3] baud rate value */ /* For reference buf[0]:buf[3] baud rate value */
pl2303_encode_baudrate(tty, port, &buf[0]); pl2303_encode_baudrate(tty, port, &buf[0]);
......
...@@ -348,22 +348,20 @@ static void spcp8x5_set_termios(struct tty_struct *tty, ...@@ -348,22 +348,20 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
} }
/* Set Data Length : 00:5bit, 01:6bit, 10:7bit, 11:8bit */ /* Set Data Length : 00:5bit, 01:6bit, 10:7bit, 11:8bit */
if (cflag & CSIZE) { switch (cflag & CSIZE) {
switch (cflag & CSIZE) { case CS5:
case CS5: buf[1] |= SET_UART_FORMAT_SIZE_5;
buf[1] |= SET_UART_FORMAT_SIZE_5; break;
break; case CS6:
case CS6: buf[1] |= SET_UART_FORMAT_SIZE_6;
buf[1] |= SET_UART_FORMAT_SIZE_6; break;
break; case CS7:
case CS7: buf[1] |= SET_UART_FORMAT_SIZE_7;
buf[1] |= SET_UART_FORMAT_SIZE_7; break;
break; default:
default: case CS8:
case CS8: buf[1] |= SET_UART_FORMAT_SIZE_8;
buf[1] |= SET_UART_FORMAT_SIZE_8; break;
break;
}
} }
/* Set Stop bit2 : 0:1bit 1:2bit */ /* Set Stop bit2 : 0:1bit 1:2bit */
......
...@@ -97,18 +97,12 @@ static void wusbhc_devconnect_acked_work(struct work_struct *work); ...@@ -97,18 +97,12 @@ static void wusbhc_devconnect_acked_work(struct work_struct *work);
static void wusb_dev_free(struct wusb_dev *wusb_dev) static void wusb_dev_free(struct wusb_dev *wusb_dev)
{ {
if (wusb_dev) { kfree(wusb_dev);
kfree(wusb_dev->set_gtk_req);
usb_free_urb(wusb_dev->set_gtk_urb);
kfree(wusb_dev);
}
} }
static struct wusb_dev *wusb_dev_alloc(struct wusbhc *wusbhc) static struct wusb_dev *wusb_dev_alloc(struct wusbhc *wusbhc)
{ {
struct wusb_dev *wusb_dev; struct wusb_dev *wusb_dev;
struct urb *urb;
struct usb_ctrlrequest *req;
wusb_dev = kzalloc(sizeof(*wusb_dev), GFP_KERNEL); wusb_dev = kzalloc(sizeof(*wusb_dev), GFP_KERNEL);
if (wusb_dev == NULL) if (wusb_dev == NULL)
...@@ -118,22 +112,6 @@ static struct wusb_dev *wusb_dev_alloc(struct wusbhc *wusbhc) ...@@ -118,22 +112,6 @@ static struct wusb_dev *wusb_dev_alloc(struct wusbhc *wusbhc)
INIT_WORK(&wusb_dev->devconnect_acked_work, wusbhc_devconnect_acked_work); INIT_WORK(&wusb_dev->devconnect_acked_work, wusbhc_devconnect_acked_work);
urb = usb_alloc_urb(0, GFP_KERNEL);
if (urb == NULL)
goto err;
wusb_dev->set_gtk_urb = urb;
req = kmalloc(sizeof(*req), GFP_KERNEL);
if (req == NULL)
goto err;
wusb_dev->set_gtk_req = req;
req->bRequestType = USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
req->bRequest = USB_REQ_SET_DESCRIPTOR;
req->wValue = cpu_to_le16(USB_DT_KEY << 8 | wusbhc->gtk_index);
req->wIndex = 0;
req->wLength = cpu_to_le16(wusbhc->gtk.descr.bLength);
return wusb_dev; return wusb_dev;
err: err:
wusb_dev_free(wusb_dev); wusb_dev_free(wusb_dev);
...@@ -411,9 +389,6 @@ static void __wusbhc_dev_disconnect(struct wusbhc *wusbhc, ...@@ -411,9 +389,6 @@ static void __wusbhc_dev_disconnect(struct wusbhc *wusbhc,
/* /*
* Refresh the list of keep alives to emit in the MMC * Refresh the list of keep alives to emit in the MMC
* *
* Some devices don't respond to keep alives unless they've been
* authenticated, so skip unauthenticated devices.
*
* We only publish the first four devices that have a coming timeout * We only publish the first four devices that have a coming timeout
* condition. Then when we are done processing those, we go for the * condition. Then when we are done processing those, we go for the
* next ones. We ignore the ones that have timed out already (they'll * next ones. We ignore the ones that have timed out already (they'll
...@@ -448,7 +423,7 @@ static void __wusbhc_keep_alive(struct wusbhc *wusbhc) ...@@ -448,7 +423,7 @@ static void __wusbhc_keep_alive(struct wusbhc *wusbhc)
if (wusb_dev == NULL) if (wusb_dev == NULL)
continue; continue;
if (wusb_dev->usb_dev == NULL || !wusb_dev->usb_dev->authenticated) if (wusb_dev->usb_dev == NULL)
continue; continue;
if (time_after(jiffies, wusb_dev->entry_ts + tt)) { if (time_after(jiffies, wusb_dev->entry_ts + tt)) {
...@@ -524,11 +499,19 @@ static struct wusb_dev *wusbhc_find_dev_by_addr(struct wusbhc *wusbhc, u8 addr) ...@@ -524,11 +499,19 @@ static struct wusb_dev *wusbhc_find_dev_by_addr(struct wusbhc *wusbhc, u8 addr)
* *
* @wusbhc shall be referenced and unlocked * @wusbhc shall be referenced and unlocked
*/ */
static void wusbhc_handle_dn_alive(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev) static void wusbhc_handle_dn_alive(struct wusbhc *wusbhc, u8 srcaddr)
{ {
struct wusb_dev *wusb_dev;
mutex_lock(&wusbhc->mutex); mutex_lock(&wusbhc->mutex);
wusb_dev->entry_ts = jiffies; wusb_dev = wusbhc_find_dev_by_addr(wusbhc, srcaddr);
__wusbhc_keep_alive(wusbhc); if (wusb_dev == NULL) {
dev_dbg(wusbhc->dev, "ignoring DN_Alive from unconnected device %02x\n",
srcaddr);
} else {
wusb_dev->entry_ts = jiffies;
__wusbhc_keep_alive(wusbhc);
}
mutex_unlock(&wusbhc->mutex); mutex_unlock(&wusbhc->mutex);
} }
...@@ -582,14 +565,22 @@ static void wusbhc_handle_dn_connect(struct wusbhc *wusbhc, ...@@ -582,14 +565,22 @@ static void wusbhc_handle_dn_connect(struct wusbhc *wusbhc,
* *
* @wusbhc shall be referenced and unlocked * @wusbhc shall be referenced and unlocked
*/ */
static void wusbhc_handle_dn_disconnect(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev) static void wusbhc_handle_dn_disconnect(struct wusbhc *wusbhc, u8 srcaddr)
{ {
struct device *dev = wusbhc->dev; struct device *dev = wusbhc->dev;
struct wusb_dev *wusb_dev;
dev_info(dev, "DN DISCONNECT: device 0x%02x going down\n", wusb_dev->addr);
mutex_lock(&wusbhc->mutex); mutex_lock(&wusbhc->mutex);
__wusbhc_dev_disconnect(wusbhc, wusb_port_by_idx(wusbhc, wusb_dev->port_idx)); wusb_dev = wusbhc_find_dev_by_addr(wusbhc, srcaddr);
if (wusb_dev == NULL) {
dev_dbg(dev, "ignoring DN DISCONNECT from unconnected device %02x\n",
srcaddr);
} else {
dev_info(dev, "DN DISCONNECT: device 0x%02x going down\n",
wusb_dev->addr);
__wusbhc_dev_disconnect(wusbhc, wusb_port_by_idx(wusbhc,
wusb_dev->port_idx));
}
mutex_unlock(&wusbhc->mutex); mutex_unlock(&wusbhc->mutex);
} }
...@@ -611,30 +602,21 @@ void wusbhc_handle_dn(struct wusbhc *wusbhc, u8 srcaddr, ...@@ -611,30 +602,21 @@ void wusbhc_handle_dn(struct wusbhc *wusbhc, u8 srcaddr,
struct wusb_dn_hdr *dn_hdr, size_t size) struct wusb_dn_hdr *dn_hdr, size_t size)
{ {
struct device *dev = wusbhc->dev; struct device *dev = wusbhc->dev;
struct wusb_dev *wusb_dev;
if (size < sizeof(struct wusb_dn_hdr)) { if (size < sizeof(struct wusb_dn_hdr)) {
dev_err(dev, "DN data shorter than DN header (%d < %d)\n", dev_err(dev, "DN data shorter than DN header (%d < %d)\n",
(int)size, (int)sizeof(struct wusb_dn_hdr)); (int)size, (int)sizeof(struct wusb_dn_hdr));
return; return;
} }
wusb_dev = wusbhc_find_dev_by_addr(wusbhc, srcaddr);
if (wusb_dev == NULL && dn_hdr->bType != WUSB_DN_CONNECT) {
dev_dbg(dev, "ignoring DN %d from unconnected device %02x\n",
dn_hdr->bType, srcaddr);
return;
}
switch (dn_hdr->bType) { switch (dn_hdr->bType) {
case WUSB_DN_CONNECT: case WUSB_DN_CONNECT:
wusbhc_handle_dn_connect(wusbhc, dn_hdr, size); wusbhc_handle_dn_connect(wusbhc, dn_hdr, size);
break; break;
case WUSB_DN_ALIVE: case WUSB_DN_ALIVE:
wusbhc_handle_dn_alive(wusbhc, wusb_dev); wusbhc_handle_dn_alive(wusbhc, srcaddr);
break; break;
case WUSB_DN_DISCONNECT: case WUSB_DN_DISCONNECT:
wusbhc_handle_dn_disconnect(wusbhc, wusb_dev); wusbhc_handle_dn_disconnect(wusbhc, srcaddr);
break; break;
case WUSB_DN_MASAVAILCHANGED: case WUSB_DN_MASAVAILCHANGED:
case WUSB_DN_RWAKE: case WUSB_DN_RWAKE:
......
...@@ -29,19 +29,16 @@ ...@@ -29,19 +29,16 @@
#include <linux/export.h> #include <linux/export.h>
#include "wusbhc.h" #include "wusbhc.h"
static void wusbhc_set_gtk_callback(struct urb *urb); static void wusbhc_gtk_rekey_work(struct work_struct *work);
static void wusbhc_gtk_rekey_done_work(struct work_struct *work);
int wusbhc_sec_create(struct wusbhc *wusbhc) int wusbhc_sec_create(struct wusbhc *wusbhc)
{ {
wusbhc->gtk.descr.bLength = sizeof(wusbhc->gtk.descr) + sizeof(wusbhc->gtk.data); wusbhc->gtk.descr.bLength = sizeof(wusbhc->gtk.descr) + sizeof(wusbhc->gtk.data);
wusbhc->gtk.descr.bDescriptorType = USB_DT_KEY; wusbhc->gtk.descr.bDescriptorType = USB_DT_KEY;
wusbhc->gtk.descr.bReserved = 0; wusbhc->gtk.descr.bReserved = 0;
wusbhc->gtk_index = 0;
wusbhc->gtk_index = wusb_key_index(0, WUSB_KEY_INDEX_TYPE_GTK, INIT_WORK(&wusbhc->gtk_rekey_work, wusbhc_gtk_rekey_work);
WUSB_KEY_INDEX_ORIGINATOR_HOST);
INIT_WORK(&wusbhc->gtk_rekey_done_work, wusbhc_gtk_rekey_done_work);
return 0; return 0;
} }
...@@ -113,7 +110,7 @@ int wusbhc_sec_start(struct wusbhc *wusbhc) ...@@ -113,7 +110,7 @@ int wusbhc_sec_start(struct wusbhc *wusbhc)
wusbhc_generate_gtk(wusbhc); wusbhc_generate_gtk(wusbhc);
result = wusbhc->set_gtk(wusbhc, wusbhc->gtk_tkid, result = wusbhc->set_gtk(wusbhc, wusbhc->gtk_tkid,
&wusbhc->gtk.descr.bKeyData, key_size); &wusbhc->gtk.descr.bKeyData, key_size);
if (result < 0) if (result < 0)
dev_err(wusbhc->dev, "cannot set GTK for the host: %d\n", dev_err(wusbhc->dev, "cannot set GTK for the host: %d\n",
result); result);
...@@ -129,7 +126,7 @@ int wusbhc_sec_start(struct wusbhc *wusbhc) ...@@ -129,7 +126,7 @@ int wusbhc_sec_start(struct wusbhc *wusbhc)
*/ */
void wusbhc_sec_stop(struct wusbhc *wusbhc) void wusbhc_sec_stop(struct wusbhc *wusbhc)
{ {
cancel_work_sync(&wusbhc->gtk_rekey_done_work); cancel_work_sync(&wusbhc->gtk_rekey_work);
} }
...@@ -185,12 +182,14 @@ static int wusb_dev_set_encryption(struct usb_device *usb_dev, int value) ...@@ -185,12 +182,14 @@ static int wusb_dev_set_encryption(struct usb_device *usb_dev, int value)
static int wusb_dev_set_gtk(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev) static int wusb_dev_set_gtk(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)
{ {
struct usb_device *usb_dev = wusb_dev->usb_dev; struct usb_device *usb_dev = wusb_dev->usb_dev;
u8 key_index = wusb_key_index(wusbhc->gtk_index,
WUSB_KEY_INDEX_TYPE_GTK, WUSB_KEY_INDEX_ORIGINATOR_HOST);
return usb_control_msg( return usb_control_msg(
usb_dev, usb_sndctrlpipe(usb_dev, 0), usb_dev, usb_sndctrlpipe(usb_dev, 0),
USB_REQ_SET_DESCRIPTOR, USB_REQ_SET_DESCRIPTOR,
USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE, USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
USB_DT_KEY << 8 | wusbhc->gtk_index, 0, USB_DT_KEY << 8 | key_index, 0,
&wusbhc->gtk.descr, wusbhc->gtk.descr.bLength, &wusbhc->gtk.descr, wusbhc->gtk.descr.bLength,
1000); 1000);
} }
...@@ -520,24 +519,55 @@ int wusb_dev_4way_handshake(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev, ...@@ -520,24 +519,55 @@ int wusb_dev_4way_handshake(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev,
* Once all connected and authenticated devices have received the new * Once all connected and authenticated devices have received the new
* GTK, switch the host to using it. * GTK, switch the host to using it.
*/ */
static void wusbhc_gtk_rekey_done_work(struct work_struct *work) static void wusbhc_gtk_rekey_work(struct work_struct *work)
{ {
struct wusbhc *wusbhc = container_of(work, struct wusbhc, gtk_rekey_done_work); struct wusbhc *wusbhc = container_of(work,
struct wusbhc, gtk_rekey_work);
size_t key_size = sizeof(wusbhc->gtk.data); size_t key_size = sizeof(wusbhc->gtk.data);
int port_idx;
struct wusb_dev *wusb_dev, *wusb_dev_next;
LIST_HEAD(rekey_list);
mutex_lock(&wusbhc->mutex); mutex_lock(&wusbhc->mutex);
/* generate the new key */
wusbhc_generate_gtk(wusbhc);
/* roll the gtk index. */
wusbhc->gtk_index = (wusbhc->gtk_index + 1) % (WUSB_KEY_INDEX_MAX + 1);
/*
* Save all connected devices on a list while holding wusbhc->mutex and
* take a reference to each one. Then submit the set key request to
* them after releasing the lock in order to avoid a deadlock.
*/
for (port_idx = 0; port_idx < wusbhc->ports_max; port_idx++) {
wusb_dev = wusbhc->port[port_idx].wusb_dev;
if (!wusb_dev || !wusb_dev->usb_dev
|| !wusb_dev->usb_dev->authenticated)
continue;
if (--wusbhc->pending_set_gtks == 0) wusb_dev_get(wusb_dev);
wusbhc->set_gtk(wusbhc, wusbhc->gtk_tkid, &wusbhc->gtk.descr.bKeyData, key_size); list_add_tail(&wusb_dev->rekey_node, &rekey_list);
}
mutex_unlock(&wusbhc->mutex); mutex_unlock(&wusbhc->mutex);
}
static void wusbhc_set_gtk_callback(struct urb *urb) /* Submit the rekey requests without holding wusbhc->mutex. */
{ list_for_each_entry_safe(wusb_dev, wusb_dev_next, &rekey_list,
struct wusbhc *wusbhc = urb->context; rekey_node) {
list_del_init(&wusb_dev->rekey_node);
dev_dbg(&wusb_dev->usb_dev->dev, "%s: rekey device at port %d\n",
__func__, wusb_dev->port_idx);
if (wusb_dev_set_gtk(wusbhc, wusb_dev) < 0) {
dev_err(&wusb_dev->usb_dev->dev, "%s: rekey device at port %d failed\n",
__func__, wusb_dev->port_idx);
}
wusb_dev_put(wusb_dev);
}
queue_work(wusbd, &wusbhc->gtk_rekey_done_work); /* Switch the host controller to use the new GTK. */
mutex_lock(&wusbhc->mutex);
wusbhc->set_gtk(wusbhc, wusbhc->gtk_tkid,
&wusbhc->gtk.descr.bKeyData, key_size);
mutex_unlock(&wusbhc->mutex);
} }
/** /**
...@@ -553,26 +583,12 @@ static void wusbhc_set_gtk_callback(struct urb *urb) ...@@ -553,26 +583,12 @@ static void wusbhc_set_gtk_callback(struct urb *urb)
*/ */
void wusbhc_gtk_rekey(struct wusbhc *wusbhc) void wusbhc_gtk_rekey(struct wusbhc *wusbhc)
{ {
static const size_t key_size = sizeof(wusbhc->gtk.data); /*
int p; * We need to submit a URB to the downstream WUSB devices in order to
* change the group key. This can't be done while holding the
wusbhc_generate_gtk(wusbhc); * wusbhc->mutex since that is also taken in the urb_enqueue routine
* and will cause a deadlock. Instead, queue a work item to do
for (p = 0; p < wusbhc->ports_max; p++) { * it when the lock is not held
struct wusb_dev *wusb_dev; */
queue_work(wusbd, &wusbhc->gtk_rekey_work);
wusb_dev = wusbhc->port[p].wusb_dev;
if (!wusb_dev || !wusb_dev->usb_dev || !wusb_dev->usb_dev->authenticated)
continue;
usb_fill_control_urb(wusb_dev->set_gtk_urb, wusb_dev->usb_dev,
usb_sndctrlpipe(wusb_dev->usb_dev, 0),
(void *)wusb_dev->set_gtk_req,
&wusbhc->gtk.descr, wusbhc->gtk.descr.bLength,
wusbhc_set_gtk_callback, wusbhc);
if (usb_submit_urb(wusb_dev->set_gtk_urb, GFP_KERNEL) == 0)
wusbhc->pending_set_gtks++;
}
if (wusbhc->pending_set_gtks == 0)
wusbhc->set_gtk(wusbhc, wusbhc->gtk_tkid, &wusbhc->gtk.descr.bKeyData, key_size);
} }
...@@ -97,6 +97,7 @@ struct wusb_dev { ...@@ -97,6 +97,7 @@ struct wusb_dev {
struct kref refcnt; struct kref refcnt;
struct wusbhc *wusbhc; struct wusbhc *wusbhc;
struct list_head cack_node; /* Connect-Ack list */ struct list_head cack_node; /* Connect-Ack list */
struct list_head rekey_node; /* GTK rekey list */
u8 port_idx; u8 port_idx;
u8 addr; u8 addr;
u8 beacon_type:4; u8 beacon_type:4;
...@@ -107,8 +108,6 @@ struct wusb_dev { ...@@ -107,8 +108,6 @@ struct wusb_dev {
struct usb_wireless_cap_descriptor *wusb_cap_descr; struct usb_wireless_cap_descriptor *wusb_cap_descr;
struct uwb_mas_bm availability; struct uwb_mas_bm availability;
struct work_struct devconnect_acked_work; struct work_struct devconnect_acked_work;
struct urb *set_gtk_urb;
struct usb_ctrlrequest *set_gtk_req;
struct usb_device *usb_dev; struct usb_device *usb_dev;
}; };
...@@ -296,8 +295,7 @@ struct wusbhc { ...@@ -296,8 +295,7 @@ struct wusbhc {
} __attribute__((packed)) gtk; } __attribute__((packed)) gtk;
u8 gtk_index; u8 gtk_index;
u32 gtk_tkid; u32 gtk_tkid;
struct work_struct gtk_rekey_done_work; struct work_struct gtk_rekey_work;
int pending_set_gtks;
struct usb_encryption_descriptor *ccm1_etd; struct usb_encryption_descriptor *ccm1_etd;
}; };
......
...@@ -1264,6 +1264,8 @@ typedef void (*usb_complete_t)(struct urb *); ...@@ -1264,6 +1264,8 @@ typedef void (*usb_complete_t)(struct urb *);
* @sg: scatter gather buffer list, the buffer size of each element in * @sg: scatter gather buffer list, the buffer size of each element in
* the list (except the last) must be divisible by the endpoint's * the list (except the last) must be divisible by the endpoint's
* max packet size if no_sg_constraint isn't set in 'struct usb_bus' * max packet size if no_sg_constraint isn't set in 'struct usb_bus'
* (FIXME: scatter-gather under xHCI is broken for periodic transfers.
* Do not use urb->sg for interrupt endpoints for now, only bulk.)
* @num_mapped_sgs: (internal) number of mapped sg entries * @num_mapped_sgs: (internal) number of mapped sg entries
* @num_sgs: number of entries in the sg list * @num_sgs: number of entries in the sg list
* @transfer_buffer_length: How big is transfer_buffer. The transfer may * @transfer_buffer_length: How big is transfer_buffer. The transfer may
......
...@@ -271,6 +271,8 @@ static inline u8 wusb_key_index(int index, int type, int originator) ...@@ -271,6 +271,8 @@ static inline u8 wusb_key_index(int index, int type, int originator)
#define WUSB_KEY_INDEX_TYPE_GTK 2 #define WUSB_KEY_INDEX_TYPE_GTK 2
#define WUSB_KEY_INDEX_ORIGINATOR_HOST 0 #define WUSB_KEY_INDEX_ORIGINATOR_HOST 0
#define WUSB_KEY_INDEX_ORIGINATOR_DEVICE 1 #define WUSB_KEY_INDEX_ORIGINATOR_DEVICE 1
/* bits 0-3 used for the key index. */
#define WUSB_KEY_INDEX_MAX 15
/* A CCM Nonce, defined in WUSB1.0[6.4.1] */ /* A CCM Nonce, defined in WUSB1.0[6.4.1] */
struct aes_ccm_nonce { struct aes_ccm_nonce {
......
...@@ -3,11 +3,12 @@ ...@@ -3,11 +3,12 @@
CC = $(CROSS_COMPILE)gcc CC = $(CROSS_COMPILE)gcc
PTHREAD_LIBS = -lpthread PTHREAD_LIBS = -lpthread
WARNINGS = -Wall -Wextra WARNINGS = -Wall -Wextra
CFLAGS = $(WARNINGS) -g $(PTHREAD_LIBS) -I../include CFLAGS = $(WARNINGS) -g -I../include
LDFLAGS = $(PTHREAD_LIBS)
all: testusb ffs-test all: testusb ffs-test
%: %.c %: %.c
$(CC) $(CFLAGS) -o $@ $^ $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
clean: clean:
$(RM) testusb ffs-test $(RM) testusb ffs-test
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