mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 11:11:45 -04:00
USB patches for 4.7-rc1
Here's the big pull request for USB and PHY drivers for 4.7-rc1 Full details in the shortlog, but it's the normal major gadget driver updates, phy updates, new usbip code, as well as a bit of lots of other stuff. All have been in linux-next with no reported issues. Signed-off-by: Greg Kroah-Hartman <[email protected]> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iEYEABECAAYFAlc/0P8ACgkQMUfUDdst+ykkFQCg0kJlxIiCU1FYBZYriqo4vX3F 9N8AoM/8nO8Y6vMpF2LWnamafYgqscTE =ZuCh -----END PGP SIGNATURE----- Merge tag 'usb-4.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb Pull USB updates from Greg KH: "Here's the big pull request for USB and PHY drivers for 4.7-rc1 Full details in the shortlog, but it's the normal major gadget driver updates, phy updates, new usbip code, as well as a bit of lots of other stuff. All have been in linux-next with no reported issues" * tag 'usb-4.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (164 commits) USB: serial: ti_usb_3410_5052: add MOXA UPORT 11x0 support USB: serial: fix minor-number allocation USB: serial: quatech2: fix use-after-free in probe error path USB: serial: mxuport: fix use-after-free in probe error path USB: serial: keyspan: fix debug and error messages USB: serial: keyspan: fix URB unlink USB: serial: keyspan: fix use-after-free in probe error path USB: serial: io_edgeport: fix memory leaks in probe error path USB: serial: io_edgeport: fix memory leaks in attach error path usb: Remove unnecessary space before operator ','. usb: Remove unnecessary space before open square bracket. USB: FHCI: avoid redundant condition usb: host: xhci-rcar: Avoid long wait in xhci_reset() usb/host/fotg210: remove dead code in create_sysfs_files usb: wusbcore: Do not initialise statics to 0. usb: wusbcore: Remove space before ',' and '(' . USB: serial: cp210x: clean up CRTSCTS flag code USB: serial: cp210x: get rid of magic numbers in CRTSCTS flag code USB: serial: cp210x: fix hardware flow-control disable USB: serial: option: add even more ZTE device ids ...
This commit is contained in:
commit
19e36ad292
182 changed files with 7630 additions and 2525 deletions
|
|
@ -31,8 +31,6 @@ if USB_SUPPORT
|
|||
|
||||
config USB_COMMON
|
||||
tristate
|
||||
default y
|
||||
depends on USB || USB_GADGET
|
||||
|
||||
config USB_ARCH_HAS_HCD
|
||||
def_bool y
|
||||
|
|
@ -41,6 +39,7 @@ config USB_ARCH_HAS_HCD
|
|||
config USB
|
||||
tristate "Support for Host-side USB"
|
||||
depends on USB_ARCH_HAS_HCD
|
||||
select USB_COMMON
|
||||
select NLS # for UTF-8 strings
|
||||
---help---
|
||||
Universal Serial Bus (USB) is a specification for a serial bus
|
||||
|
|
|
|||
|
|
@ -173,10 +173,10 @@ struct uea_softc {
|
|||
const struct firmware *dsp_firm;
|
||||
struct urb *urb_int;
|
||||
|
||||
void (*dispatch_cmv) (struct uea_softc *, struct intr_pkt *);
|
||||
void (*schedule_load_page) (struct uea_softc *, struct intr_pkt *);
|
||||
int (*stat) (struct uea_softc *);
|
||||
int (*send_cmvs) (struct uea_softc *);
|
||||
void (*dispatch_cmv)(struct uea_softc *, struct intr_pkt *);
|
||||
void (*schedule_load_page)(struct uea_softc *, struct intr_pkt *);
|
||||
int (*stat)(struct uea_softc *);
|
||||
int (*send_cmvs)(struct uea_softc *);
|
||||
|
||||
/* keep in sync with eaglectl */
|
||||
struct uea_stats {
|
||||
|
|
@ -2454,7 +2454,7 @@ UEA_ATTR(firmid, 0);
|
|||
|
||||
/* Retrieve the device End System Identifier (MAC) */
|
||||
|
||||
static int uea_getesi(struct uea_softc *sc, u_char * esi)
|
||||
static int uea_getesi(struct uea_softc *sc, u_char *esi)
|
||||
{
|
||||
unsigned char mac_str[2 * ETH_ALEN + 1];
|
||||
int i;
|
||||
|
|
|
|||
|
|
@ -292,10 +292,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
|
|||
if (pdata.flags & CI_HDRC_SUPPORTS_RUNTIME_PM)
|
||||
data->supports_runtime_pm = true;
|
||||
|
||||
ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
|
||||
if (ret)
|
||||
goto err_clk;
|
||||
|
||||
ret = imx_usbmisc_init(data->usbmisc_data);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "usbmisc init failed, ret=%d\n", ret);
|
||||
|
|
|
|||
|
|
@ -61,8 +61,6 @@ static int otg_set_protocol(struct otg_fsm *fsm, int protocol)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int state_changed;
|
||||
|
||||
/* Called when leaving a state. Do state clean up jobs here */
|
||||
static void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state)
|
||||
{
|
||||
|
|
@ -208,7 +206,6 @@ static void otg_start_hnp_polling(struct otg_fsm *fsm)
|
|||
/* Called when entering a state */
|
||||
static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
|
||||
{
|
||||
state_changed = 1;
|
||||
if (fsm->otg->state == new_state)
|
||||
return 0;
|
||||
VDBG("Set state: %s\n", usb_otg_state_string(new_state));
|
||||
|
|
@ -324,6 +321,7 @@ static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
|
|||
}
|
||||
|
||||
fsm->otg->state = new_state;
|
||||
fsm->state_changed = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -335,7 +333,7 @@ int otg_statemachine(struct otg_fsm *fsm)
|
|||
mutex_lock(&fsm->lock);
|
||||
|
||||
state = fsm->otg->state;
|
||||
state_changed = 0;
|
||||
fsm->state_changed = 0;
|
||||
/* State machine state change judgement */
|
||||
|
||||
switch (state) {
|
||||
|
|
@ -448,7 +446,7 @@ int otg_statemachine(struct otg_fsm *fsm)
|
|||
}
|
||||
mutex_unlock(&fsm->lock);
|
||||
|
||||
VDBG("quit statemachine, changed = %d\n", state_changed);
|
||||
return state_changed;
|
||||
VDBG("quit statemachine, changed = %d\n", fsm->state_changed);
|
||||
return fsm->state_changed;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(otg_statemachine);
|
||||
|
|
|
|||
|
|
@ -122,6 +122,9 @@ void *hcd_buffer_alloc(
|
|||
struct usb_hcd *hcd = bus_to_hcd(bus);
|
||||
int i;
|
||||
|
||||
if (size == 0)
|
||||
return NULL;
|
||||
|
||||
/* some USB hosts just use PIO */
|
||||
if (!IS_ENABLED(CONFIG_HAS_DMA) ||
|
||||
(!bus->controller->dma_mask &&
|
||||
|
|
|
|||
|
|
@ -216,7 +216,7 @@ static void usbdev_vm_close(struct vm_area_struct *vma)
|
|||
dec_usb_memory_use_count(usbm, &usbm->vma_use_count);
|
||||
}
|
||||
|
||||
struct vm_operations_struct usbdev_vm_ops = {
|
||||
static struct vm_operations_struct usbdev_vm_ops = {
|
||||
.open = usbdev_vm_open,
|
||||
.close = usbdev_vm_close
|
||||
};
|
||||
|
|
@ -1316,10 +1316,11 @@ static int proc_getdriver(struct usb_dev_state *ps, void __user *arg)
|
|||
|
||||
static int proc_connectinfo(struct usb_dev_state *ps, void __user *arg)
|
||||
{
|
||||
struct usbdevfs_connectinfo ci = {
|
||||
.devnum = ps->dev->devnum,
|
||||
.slow = ps->dev->speed == USB_SPEED_LOW
|
||||
};
|
||||
struct usbdevfs_connectinfo ci;
|
||||
|
||||
memset(&ci, 0, sizeof(ci));
|
||||
ci.devnum = ps->dev->devnum;
|
||||
ci.slow = ps->dev->speed == USB_SPEED_LOW;
|
||||
|
||||
if (copy_to_user(arg, &ci, sizeof(ci)))
|
||||
return -EFAULT;
|
||||
|
|
|
|||
|
|
@ -284,7 +284,7 @@ static int usb_probe_interface(struct device *dev)
|
|||
struct usb_device *udev = interface_to_usbdev(intf);
|
||||
const struct usb_device_id *id;
|
||||
int error = -ENODEV;
|
||||
int lpm_disable_error;
|
||||
int lpm_disable_error = -ENODEV;
|
||||
|
||||
dev_dbg(dev, "%s\n", __func__);
|
||||
|
||||
|
|
@ -336,12 +336,14 @@ static int usb_probe_interface(struct device *dev)
|
|||
* setting during probe, that should also be fine. usb_set_interface()
|
||||
* will attempt to disable LPM, and fail if it can't disable it.
|
||||
*/
|
||||
lpm_disable_error = usb_unlocked_disable_lpm(udev);
|
||||
if (lpm_disable_error && driver->disable_hub_initiated_lpm) {
|
||||
dev_err(&intf->dev, "%s Failed to disable LPM for driver %s\n.",
|
||||
__func__, driver->name);
|
||||
error = lpm_disable_error;
|
||||
goto err;
|
||||
if (driver->disable_hub_initiated_lpm) {
|
||||
lpm_disable_error = usb_unlocked_disable_lpm(udev);
|
||||
if (lpm_disable_error) {
|
||||
dev_err(&intf->dev, "%s Failed to disable LPM for driver %s\n.",
|
||||
__func__, driver->name);
|
||||
error = lpm_disable_error;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
/* Carry out a deferred switch to altsetting 0 */
|
||||
|
|
@ -391,7 +393,8 @@ static int usb_unbind_interface(struct device *dev)
|
|||
struct usb_interface *intf = to_usb_interface(dev);
|
||||
struct usb_host_endpoint *ep, **eps = NULL;
|
||||
struct usb_device *udev;
|
||||
int i, j, error, r, lpm_disable_error;
|
||||
int i, j, error, r;
|
||||
int lpm_disable_error = -ENODEV;
|
||||
|
||||
intf->condition = USB_INTERFACE_UNBINDING;
|
||||
|
||||
|
|
@ -399,12 +402,13 @@ static int usb_unbind_interface(struct device *dev)
|
|||
udev = interface_to_usbdev(intf);
|
||||
error = usb_autoresume_device(udev);
|
||||
|
||||
/* Hub-initiated LPM policy may change, so attempt to disable LPM until
|
||||
/* If hub-initiated LPM policy may change, attempt to disable LPM until
|
||||
* the driver is unbound. If LPM isn't disabled, that's fine because it
|
||||
* wouldn't be enabled unless all the bound interfaces supported
|
||||
* hub-initiated LPM.
|
||||
*/
|
||||
lpm_disable_error = usb_unlocked_disable_lpm(udev);
|
||||
if (driver->disable_hub_initiated_lpm)
|
||||
lpm_disable_error = usb_unlocked_disable_lpm(udev);
|
||||
|
||||
/*
|
||||
* Terminate all URBs for this interface unless the driver
|
||||
|
|
@ -505,7 +509,7 @@ int usb_driver_claim_interface(struct usb_driver *driver,
|
|||
struct device *dev;
|
||||
struct usb_device *udev;
|
||||
int retval = 0;
|
||||
int lpm_disable_error;
|
||||
int lpm_disable_error = -ENODEV;
|
||||
|
||||
if (!iface)
|
||||
return -ENODEV;
|
||||
|
|
@ -526,12 +530,14 @@ int usb_driver_claim_interface(struct usb_driver *driver,
|
|||
|
||||
iface->condition = USB_INTERFACE_BOUND;
|
||||
|
||||
/* Disable LPM until this driver is bound. */
|
||||
lpm_disable_error = usb_unlocked_disable_lpm(udev);
|
||||
if (lpm_disable_error && driver->disable_hub_initiated_lpm) {
|
||||
dev_err(&iface->dev, "%s Failed to disable LPM for driver %s\n.",
|
||||
__func__, driver->name);
|
||||
return -ENOMEM;
|
||||
/* See the comment about disabling LPM in usb_probe_interface(). */
|
||||
if (driver->disable_hub_initiated_lpm) {
|
||||
lpm_disable_error = usb_unlocked_disable_lpm(udev);
|
||||
if (lpm_disable_error) {
|
||||
dev_err(&iface->dev, "%s Failed to disable LPM for driver %s\n.",
|
||||
__func__, driver->name);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
/* Claimed interfaces are initially inactive (suspended) and
|
||||
|
|
|
|||
|
|
@ -994,7 +994,7 @@ static void usb_bus_init (struct usb_bus *bus)
|
|||
bus->bandwidth_allocated = 0;
|
||||
bus->bandwidth_int_reqs = 0;
|
||||
bus->bandwidth_isoc_reqs = 0;
|
||||
mutex_init(&bus->usb_address0_mutex);
|
||||
mutex_init(&bus->devnum_next_mutex);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
|
@ -1118,6 +1118,7 @@ static int register_root_hub(struct usb_hcd *hcd)
|
|||
/* Did the HC die before the root hub was registered? */
|
||||
if (HCD_DEAD(hcd))
|
||||
usb_hc_died (hcd); /* This time clean up */
|
||||
usb_dev->dev.of_node = parent_dev->of_node;
|
||||
}
|
||||
mutex_unlock(&usb_bus_idr_lock);
|
||||
|
||||
|
|
@ -2521,6 +2522,14 @@ struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
|
|||
return NULL;
|
||||
}
|
||||
if (primary_hcd == NULL) {
|
||||
hcd->address0_mutex = kmalloc(sizeof(*hcd->address0_mutex),
|
||||
GFP_KERNEL);
|
||||
if (!hcd->address0_mutex) {
|
||||
kfree(hcd);
|
||||
dev_dbg(dev, "hcd address0 mutex alloc failed\n");
|
||||
return NULL;
|
||||
}
|
||||
mutex_init(hcd->address0_mutex);
|
||||
hcd->bandwidth_mutex = kmalloc(sizeof(*hcd->bandwidth_mutex),
|
||||
GFP_KERNEL);
|
||||
if (!hcd->bandwidth_mutex) {
|
||||
|
|
@ -2532,6 +2541,7 @@ struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
|
|||
dev_set_drvdata(dev, hcd);
|
||||
} else {
|
||||
mutex_lock(&usb_port_peer_mutex);
|
||||
hcd->address0_mutex = primary_hcd->address0_mutex;
|
||||
hcd->bandwidth_mutex = primary_hcd->bandwidth_mutex;
|
||||
hcd->primary_hcd = primary_hcd;
|
||||
primary_hcd->primary_hcd = primary_hcd;
|
||||
|
|
@ -2598,8 +2608,10 @@ static void hcd_release(struct kref *kref)
|
|||
struct usb_hcd *hcd = container_of (kref, struct usb_hcd, kref);
|
||||
|
||||
mutex_lock(&usb_port_peer_mutex);
|
||||
if (usb_hcd_is_primary_hcd(hcd))
|
||||
if (usb_hcd_is_primary_hcd(hcd)) {
|
||||
kfree(hcd->address0_mutex);
|
||||
kfree(hcd->bandwidth_mutex);
|
||||
}
|
||||
if (hcd->shared_hcd) {
|
||||
struct usb_hcd *peer = hcd->shared_hcd;
|
||||
|
||||
|
|
|
|||
|
|
@ -104,6 +104,8 @@ static int usb_reset_and_verify_device(struct usb_device *udev);
|
|||
|
||||
static inline char *portspeed(struct usb_hub *hub, int portstatus)
|
||||
{
|
||||
if (hub_is_superspeedplus(hub->hdev))
|
||||
return "10.0 Gb/s";
|
||||
if (hub_is_superspeed(hub->hdev))
|
||||
return "5.0 Gb/s";
|
||||
if (portstatus & USB_PORT_STAT_HIGH_SPEED)
|
||||
|
|
@ -2080,7 +2082,7 @@ static void choose_devnum(struct usb_device *udev)
|
|||
struct usb_bus *bus = udev->bus;
|
||||
|
||||
/* be safe when more hub events are proceed in parallel */
|
||||
mutex_lock(&bus->usb_address0_mutex);
|
||||
mutex_lock(&bus->devnum_next_mutex);
|
||||
if (udev->wusb) {
|
||||
devnum = udev->portnum + 1;
|
||||
BUG_ON(test_bit(devnum, bus->devmap.devicemap));
|
||||
|
|
@ -2098,7 +2100,7 @@ static void choose_devnum(struct usb_device *udev)
|
|||
set_bit(devnum, bus->devmap.devicemap);
|
||||
udev->devnum = devnum;
|
||||
}
|
||||
mutex_unlock(&bus->usb_address0_mutex);
|
||||
mutex_unlock(&bus->devnum_next_mutex);
|
||||
}
|
||||
|
||||
static void release_devnum(struct usb_device *udev)
|
||||
|
|
@ -4364,7 +4366,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
|
|||
if (oldspeed == USB_SPEED_LOW)
|
||||
delay = HUB_LONG_RESET_TIME;
|
||||
|
||||
mutex_lock(&hdev->bus->usb_address0_mutex);
|
||||
mutex_lock(hcd->address0_mutex);
|
||||
|
||||
/* Reset the device; full speed may morph to high speed */
|
||||
/* FIXME a USB 2.0 device may morph into SuperSpeed on reset. */
|
||||
|
|
@ -4650,7 +4652,7 @@ fail:
|
|||
hub_port_disable(hub, port1, 0);
|
||||
update_devnum(udev, devnum); /* for disconnect processing */
|
||||
}
|
||||
mutex_unlock(&hdev->bus->usb_address0_mutex);
|
||||
mutex_unlock(hcd->address0_mutex);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -302,9 +302,10 @@ static void sg_complete(struct urb *urb)
|
|||
*/
|
||||
spin_unlock(&io->lock);
|
||||
for (i = 0, found = 0; i < io->entries; i++) {
|
||||
if (!io->urbs[i] || !io->urbs[i]->dev)
|
||||
if (!io->urbs[i])
|
||||
continue;
|
||||
if (found) {
|
||||
usb_block_urb(io->urbs[i]);
|
||||
retval = usb_unlink_urb(io->urbs[i]);
|
||||
if (retval != -EINPROGRESS &&
|
||||
retval != -ENODEV &&
|
||||
|
|
@ -515,12 +516,10 @@ void usb_sg_wait(struct usb_sg_request *io)
|
|||
int retval;
|
||||
|
||||
io->urbs[i]->dev = io->dev;
|
||||
retval = usb_submit_urb(io->urbs[i], GFP_ATOMIC);
|
||||
|
||||
/* after we submit, let completions or cancellations fire;
|
||||
* we handshake using io->status.
|
||||
*/
|
||||
spin_unlock_irq(&io->lock);
|
||||
|
||||
retval = usb_submit_urb(io->urbs[i], GFP_NOIO);
|
||||
|
||||
switch (retval) {
|
||||
/* maybe we retrying will recover */
|
||||
case -ENXIO: /* hc didn't queue this one */
|
||||
|
|
@ -578,31 +577,28 @@ EXPORT_SYMBOL_GPL(usb_sg_wait);
|
|||
void usb_sg_cancel(struct usb_sg_request *io)
|
||||
{
|
||||
unsigned long flags;
|
||||
int i, retval;
|
||||
|
||||
spin_lock_irqsave(&io->lock, flags);
|
||||
|
||||
/* shut everything down, if it didn't already */
|
||||
if (!io->status) {
|
||||
int i;
|
||||
|
||||
io->status = -ECONNRESET;
|
||||
spin_unlock(&io->lock);
|
||||
for (i = 0; i < io->entries; i++) {
|
||||
int retval;
|
||||
|
||||
if (!io->urbs[i]->dev)
|
||||
continue;
|
||||
retval = usb_unlink_urb(io->urbs[i]);
|
||||
if (retval != -EINPROGRESS
|
||||
&& retval != -ENODEV
|
||||
&& retval != -EBUSY
|
||||
&& retval != -EIDRM)
|
||||
dev_warn(&io->dev->dev, "%s, unlink --> %d\n",
|
||||
__func__, retval);
|
||||
}
|
||||
spin_lock(&io->lock);
|
||||
if (io->status) {
|
||||
spin_unlock_irqrestore(&io->lock, flags);
|
||||
return;
|
||||
}
|
||||
/* shut everything down */
|
||||
io->status = -ECONNRESET;
|
||||
spin_unlock_irqrestore(&io->lock, flags);
|
||||
|
||||
for (i = io->entries - 1; i >= 0; --i) {
|
||||
usb_block_urb(io->urbs[i]);
|
||||
|
||||
retval = usb_unlink_urb(io->urbs[i]);
|
||||
if (retval != -EINPROGRESS
|
||||
&& retval != -ENODEV
|
||||
&& retval != -EBUSY
|
||||
&& retval != -EIDRM)
|
||||
dev_warn(&io->dev->dev, "%s, unlink --> %d\n",
|
||||
__func__, retval);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_sg_cancel);
|
||||
|
||||
|
|
|
|||
|
|
@ -466,7 +466,6 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
|
|||
dev->route = 0;
|
||||
|
||||
dev->dev.parent = bus->controller;
|
||||
dev->dev.of_node = bus->controller->of_node;
|
||||
dev_set_name(&dev->dev, "usb%d", bus->busnum);
|
||||
root_hub = 1;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -2425,6 +2425,9 @@ static irqreturn_t dwc2_hsotg_irq(int irq, void *pw)
|
|||
u32 gintsts;
|
||||
u32 gintmsk;
|
||||
|
||||
if (!dwc2_is_device_mode(hsotg))
|
||||
return IRQ_NONE;
|
||||
|
||||
spin_lock(&hsotg->lock);
|
||||
irq_retry:
|
||||
gintsts = dwc2_readl(hsotg->regs + GINTSTS);
|
||||
|
|
@ -2631,7 +2634,10 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep,
|
|||
desc->wMaxPacketSize, desc->bInterval);
|
||||
|
||||
/* not to be called for EP0 */
|
||||
WARN_ON(index == 0);
|
||||
if (index == 0) {
|
||||
dev_err(hsotg->dev, "%s: called for EP 0\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dir_in = (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? 1 : 0;
|
||||
if (dir_in != hs_ep->dir_in) {
|
||||
|
|
|
|||
|
|
@ -4703,6 +4703,7 @@ fail2:
|
|||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||
urb->hcpriv = NULL;
|
||||
kfree(qtd);
|
||||
qtd = NULL;
|
||||
fail1:
|
||||
if (qh_allocated) {
|
||||
struct dwc2_qtd *qtd2, *qtd2_tmp;
|
||||
|
|
|
|||
|
|
@ -552,6 +552,7 @@ static inline void dwc2_hcd_qtd_unlink_and_free(struct dwc2_hsotg *hsotg,
|
|||
{
|
||||
list_del(&qtd->qtd_list_entry);
|
||||
kfree(qtd);
|
||||
qtd = NULL;
|
||||
}
|
||||
|
||||
/* Descriptor DMA support functions */
|
||||
|
|
|
|||
|
|
@ -1709,7 +1709,8 @@ void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
|
|||
|
||||
dwc2_deschedule_periodic(hsotg, qh);
|
||||
hsotg->periodic_qh_count--;
|
||||
if (!hsotg->periodic_qh_count) {
|
||||
if (!hsotg->periodic_qh_count &&
|
||||
hsotg->core_params->dma_desc_enable <= 0) {
|
||||
intr_mask = dwc2_readl(hsotg->regs + GINTMSK);
|
||||
intr_mask &= ~GINTSTS_SOF;
|
||||
dwc2_writel(intr_mask, hsotg->regs + GINTMSK);
|
||||
|
|
|
|||
|
|
@ -562,7 +562,7 @@ static int dwc2_driver_probe(struct platform_device *dev)
|
|||
|
||||
retval = dwc2_get_dr_mode(hsotg);
|
||||
if (retval)
|
||||
return retval;
|
||||
goto error;
|
||||
|
||||
/*
|
||||
* Reset before dwc2_get_hwparams() then it could get power-on real
|
||||
|
|
|
|||
|
|
@ -60,6 +60,20 @@ void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
|
|||
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
|
||||
}
|
||||
|
||||
u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type)
|
||||
{
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
u32 reg;
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_GDBGFIFOSPACE,
|
||||
DWC3_GDBGFIFOSPACE_NUM(dep->number) |
|
||||
DWC3_GDBGFIFOSPACE_TYPE(type));
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GDBGFIFOSPACE);
|
||||
|
||||
return DWC3_GDBGFIFOSPACE_SPACE_AVAILABLE(reg);
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc3_core_soft_reset - Issues core soft reset and PHY reset
|
||||
* @dwc: pointer to our context structure
|
||||
|
|
@ -203,13 +217,10 @@ static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc,
|
|||
static void dwc3_free_event_buffers(struct dwc3 *dwc)
|
||||
{
|
||||
struct dwc3_event_buffer *evt;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < dwc->num_event_buffers; i++) {
|
||||
evt = dwc->ev_buffs[i];
|
||||
if (evt)
|
||||
dwc3_free_one_event_buffer(dwc, evt);
|
||||
}
|
||||
evt = dwc->ev_buf;
|
||||
if (evt)
|
||||
dwc3_free_one_event_buffer(dwc, evt);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -222,27 +233,14 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc)
|
|||
*/
|
||||
static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
|
||||
{
|
||||
int num;
|
||||
int i;
|
||||
struct dwc3_event_buffer *evt;
|
||||
|
||||
num = DWC3_NUM_INT(dwc->hwparams.hwparams1);
|
||||
dwc->num_event_buffers = num;
|
||||
|
||||
dwc->ev_buffs = devm_kzalloc(dwc->dev, sizeof(*dwc->ev_buffs) * num,
|
||||
GFP_KERNEL);
|
||||
if (!dwc->ev_buffs)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
struct dwc3_event_buffer *evt;
|
||||
|
||||
evt = dwc3_alloc_one_event_buffer(dwc, length);
|
||||
if (IS_ERR(evt)) {
|
||||
dev_err(dwc->dev, "can't allocate event buffer\n");
|
||||
return PTR_ERR(evt);
|
||||
}
|
||||
dwc->ev_buffs[i] = evt;
|
||||
evt = dwc3_alloc_one_event_buffer(dwc, length);
|
||||
if (IS_ERR(evt)) {
|
||||
dev_err(dwc->dev, "can't allocate event buffer\n");
|
||||
return PTR_ERR(evt);
|
||||
}
|
||||
dwc->ev_buf = evt;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -256,25 +254,22 @@ static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
|
|||
static int dwc3_event_buffers_setup(struct dwc3 *dwc)
|
||||
{
|
||||
struct dwc3_event_buffer *evt;
|
||||
int n;
|
||||
|
||||
for (n = 0; n < dwc->num_event_buffers; n++) {
|
||||
evt = dwc->ev_buffs[n];
|
||||
dwc3_trace(trace_dwc3_core,
|
||||
"Event buf %p dma %08llx length %d\n",
|
||||
evt->buf, (unsigned long long) evt->dma,
|
||||
evt->length);
|
||||
evt = dwc->ev_buf;
|
||||
dwc3_trace(trace_dwc3_core,
|
||||
"Event buf %p dma %08llx length %d\n",
|
||||
evt->buf, (unsigned long long) evt->dma,
|
||||
evt->length);
|
||||
|
||||
evt->lpos = 0;
|
||||
evt->lpos = 0;
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n),
|
||||
lower_32_bits(evt->dma));
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n),
|
||||
upper_32_bits(evt->dma));
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n),
|
||||
DWC3_GEVNTSIZ_SIZE(evt->length));
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
|
||||
}
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(0),
|
||||
lower_32_bits(evt->dma));
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(0),
|
||||
upper_32_bits(evt->dma));
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0),
|
||||
DWC3_GEVNTSIZ_SIZE(evt->length));
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -282,19 +277,16 @@ static int dwc3_event_buffers_setup(struct dwc3 *dwc)
|
|||
static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
|
||||
{
|
||||
struct dwc3_event_buffer *evt;
|
||||
int n;
|
||||
|
||||
for (n = 0; n < dwc->num_event_buffers; n++) {
|
||||
evt = dwc->ev_buffs[n];
|
||||
evt = dwc->ev_buf;
|
||||
|
||||
evt->lpos = 0;
|
||||
evt->lpos = 0;
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0);
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0);
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), DWC3_GEVNTSIZ_INTMASK
|
||||
| DWC3_GEVNTSIZ_SIZE(0));
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
|
||||
}
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(0), 0);
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(0), 0);
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), DWC3_GEVNTSIZ_INTMASK
|
||||
| DWC3_GEVNTSIZ_SIZE(0));
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0);
|
||||
}
|
||||
|
||||
static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc)
|
||||
|
|
@ -434,6 +426,9 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
|
|||
if (dwc->u2ss_inp3_quirk)
|
||||
reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK;
|
||||
|
||||
if (dwc->dis_rxdet_inp3_quirk)
|
||||
reg |= DWC3_GUSB3PIPECTL_DISRXDETINP3;
|
||||
|
||||
if (dwc->req_p1p2p3_quirk)
|
||||
reg |= DWC3_GUSB3PIPECTL_REQP1P2P3;
|
||||
|
||||
|
|
@ -882,9 +877,6 @@ static int dwc3_probe(struct platform_device *pdev)
|
|||
dwc->usb3_lpm_capable = device_property_read_bool(dev,
|
||||
"snps,usb3_lpm_capable");
|
||||
|
||||
dwc->needs_fifo_resize = device_property_read_bool(dev,
|
||||
"tx-fifo-resize");
|
||||
|
||||
dwc->disable_scramble_quirk = device_property_read_bool(dev,
|
||||
"snps,disable_scramble_quirk");
|
||||
dwc->u2exit_lfps_quirk = device_property_read_bool(dev,
|
||||
|
|
@ -907,6 +899,8 @@ static int dwc3_probe(struct platform_device *pdev)
|
|||
"snps,dis_u2_susphy_quirk");
|
||||
dwc->dis_enblslpm_quirk = device_property_read_bool(dev,
|
||||
"snps,dis_enblslpm_quirk");
|
||||
dwc->dis_rxdet_inp3_quirk = device_property_read_bool(dev,
|
||||
"snps,dis_rxdet_inp3_quirk");
|
||||
|
||||
dwc->tx_de_emphasis_quirk = device_property_read_bool(dev,
|
||||
"snps,tx_de_emphasis_quirk");
|
||||
|
|
@ -926,7 +920,6 @@ static int dwc3_probe(struct platform_device *pdev)
|
|||
if (pdata->hird_threshold)
|
||||
hird_threshold = pdata->hird_threshold;
|
||||
|
||||
dwc->needs_fifo_resize = pdata->tx_fifo_resize;
|
||||
dwc->usb3_lpm_capable = pdata->usb3_lpm_capable;
|
||||
dwc->dr_mode = pdata->dr_mode;
|
||||
|
||||
|
|
@ -941,6 +934,7 @@ static int dwc3_probe(struct platform_device *pdev)
|
|||
dwc->dis_u3_susphy_quirk = pdata->dis_u3_susphy_quirk;
|
||||
dwc->dis_u2_susphy_quirk = pdata->dis_u2_susphy_quirk;
|
||||
dwc->dis_enblslpm_quirk = pdata->dis_enblslpm_quirk;
|
||||
dwc->dis_rxdet_inp3_quirk = pdata->dis_rxdet_inp3_quirk;
|
||||
|
||||
dwc->tx_de_emphasis_quirk = pdata->tx_de_emphasis_quirk;
|
||||
if (pdata->tx_de_emphasis)
|
||||
|
|
@ -1050,19 +1044,11 @@ static int dwc3_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
goto err5;
|
||||
|
||||
ret = dwc3_debugfs_init(dwc);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to initialize debugfs\n");
|
||||
goto err6;
|
||||
}
|
||||
|
||||
dwc3_debugfs_init(dwc);
|
||||
pm_runtime_allow(dev);
|
||||
|
||||
return 0;
|
||||
|
||||
err6:
|
||||
dwc3_core_exit_mode(dwc);
|
||||
|
||||
err5:
|
||||
dwc3_event_buffers_cleanup(dwc);
|
||||
|
||||
|
|
|
|||
|
|
@ -152,6 +152,24 @@
|
|||
|
||||
/* Bit fields */
|
||||
|
||||
/* Global Debug Queue/FIFO Space Available Register */
|
||||
#define DWC3_GDBGFIFOSPACE_NUM(n) ((n) & 0x1f)
|
||||
#define DWC3_GDBGFIFOSPACE_TYPE(n) (((n) << 5) & 0x1e0)
|
||||
#define DWC3_GDBGFIFOSPACE_SPACE_AVAILABLE(n) (((n) >> 16) & 0xffff)
|
||||
|
||||
#define DWC3_TXFIFOQ 1
|
||||
#define DWC3_RXFIFOQ 3
|
||||
#define DWC3_TXREQQ 5
|
||||
#define DWC3_RXREQQ 7
|
||||
#define DWC3_RXINFOQ 9
|
||||
#define DWC3_DESCFETCHQ 13
|
||||
#define DWC3_EVENTQ 15
|
||||
|
||||
/* Global RX Threshold Configuration Register */
|
||||
#define DWC3_GRXTHRCFG_MAXRXBURSTSIZE(n) (((n) & 0x1f) << 19)
|
||||
#define DWC3_GRXTHRCFG_RXPKTCNT(n) (((n) & 0xf) << 24)
|
||||
#define DWC3_GRXTHRCFG_PKTCNTSEL (1 << 29)
|
||||
|
||||
/* Global Configuration Register */
|
||||
#define DWC3_GCTL_PWRDNSCALE(n) ((n) << 19)
|
||||
#define DWC3_GCTL_U2RSTECN (1 << 16)
|
||||
|
|
@ -193,6 +211,7 @@
|
|||
/* Global USB3 PIPE Control Register */
|
||||
#define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31)
|
||||
#define DWC3_GUSB3PIPECTL_U2SSINP3OK (1 << 29)
|
||||
#define DWC3_GUSB3PIPECTL_DISRXDETINP3 (1 << 28)
|
||||
#define DWC3_GUSB3PIPECTL_REQP1P2P3 (1 << 24)
|
||||
#define DWC3_GUSB3PIPECTL_DEP1P2P3(n) ((n) << 19)
|
||||
#define DWC3_GUSB3PIPECTL_DEP1P2P3_MASK DWC3_GUSB3PIPECTL_DEP1P2P3(7)
|
||||
|
|
@ -257,6 +276,9 @@
|
|||
#define DWC3_DCFG_LOWSPEED (2 << 0)
|
||||
#define DWC3_DCFG_FULLSPEED1 (3 << 0)
|
||||
|
||||
#define DWC3_DCFG_NUMP_SHIFT 17
|
||||
#define DWC3_DCFG_NUMP(n) (((n) >> DWC3_DCFG_NUMP_SHIFT) & 0x1f)
|
||||
#define DWC3_DCFG_NUMP_MASK (0x1f << DWC3_DCFG_NUMP_SHIFT)
|
||||
#define DWC3_DCFG_LPM_CAP (1 << 22)
|
||||
|
||||
/* Device Control Register */
|
||||
|
|
@ -438,18 +460,17 @@ struct dwc3_event_buffer {
|
|||
#define DWC3_EP_DIRECTION_TX true
|
||||
#define DWC3_EP_DIRECTION_RX false
|
||||
|
||||
#define DWC3_TRB_NUM 32
|
||||
#define DWC3_TRB_MASK (DWC3_TRB_NUM - 1)
|
||||
#define DWC3_TRB_NUM 256
|
||||
|
||||
/**
|
||||
* struct dwc3_ep - device side endpoint representation
|
||||
* @endpoint: usb endpoint
|
||||
* @request_list: list of requests for this endpoint
|
||||
* @req_queued: list of requests on this ep which have TRBs setup
|
||||
* @pending_list: list of pending requests for this endpoint
|
||||
* @started_list: list of started requests on this endpoint
|
||||
* @trb_pool: array of transaction buffers
|
||||
* @trb_pool_dma: dma address of @trb_pool
|
||||
* @free_slot: next slot which is going to be used
|
||||
* @busy_slot: first slot which is owned by HW
|
||||
* @trb_enqueue: enqueue 'pointer' into TRB array
|
||||
* @trb_dequeue: dequeue 'pointer' into TRB array
|
||||
* @desc: usb_endpoint_descriptor pointer
|
||||
* @dwc: pointer to DWC controller
|
||||
* @saved_state: ep state saved during hibernation
|
||||
|
|
@ -464,13 +485,11 @@ struct dwc3_event_buffer {
|
|||
*/
|
||||
struct dwc3_ep {
|
||||
struct usb_ep endpoint;
|
||||
struct list_head request_list;
|
||||
struct list_head req_queued;
|
||||
struct list_head pending_list;
|
||||
struct list_head started_list;
|
||||
|
||||
struct dwc3_trb *trb_pool;
|
||||
dma_addr_t trb_pool_dma;
|
||||
u32 free_slot;
|
||||
u32 busy_slot;
|
||||
const struct usb_ss_ep_comp_descriptor *comp_desc;
|
||||
struct dwc3 *dwc;
|
||||
|
||||
|
|
@ -486,6 +505,18 @@ struct dwc3_ep {
|
|||
/* This last one is specific to EP0 */
|
||||
#define DWC3_EP0_DIR_IN (1 << 31)
|
||||
|
||||
/*
|
||||
* IMPORTANT: we *know* we have 256 TRBs in our @trb_pool, so we will
|
||||
* use a u8 type here. If anybody decides to increase number of TRBs to
|
||||
* anything larger than 256 - I can't see why people would want to do
|
||||
* this though - then this type needs to be changed.
|
||||
*
|
||||
* By using u8 types we ensure that our % operator when incrementing
|
||||
* enqueue and dequeue get optimized away by the compiler.
|
||||
*/
|
||||
u8 trb_enqueue;
|
||||
u8 trb_dequeue;
|
||||
|
||||
u8 number;
|
||||
u8 type;
|
||||
u8 resource_index;
|
||||
|
|
@ -557,6 +588,7 @@ enum dwc3_link_state {
|
|||
#define DWC3_TRB_CTRL_IOC (1 << 11)
|
||||
#define DWC3_TRB_CTRL_SID_SOFN(n) (((n) & 0xffff) << 14)
|
||||
|
||||
#define DWC3_TRBCTL_TYPE(n) ((n) & (0x3f << 4))
|
||||
#define DWC3_TRBCTL_NORMAL DWC3_TRB_CTRL_TRBCTL(1)
|
||||
#define DWC3_TRBCTL_CONTROL_SETUP DWC3_TRB_CTRL_TRBCTL(2)
|
||||
#define DWC3_TRBCTL_CONTROL_STATUS2 DWC3_TRB_CTRL_TRBCTL(3)
|
||||
|
|
@ -623,19 +655,32 @@ struct dwc3_hwparams {
|
|||
/* HWPARAMS7 */
|
||||
#define DWC3_RAM1_DEPTH(n) ((n) & 0xffff)
|
||||
|
||||
/**
|
||||
* struct dwc3_request - representation of a transfer request
|
||||
* @request: struct usb_request to be transferred
|
||||
* @list: a list_head used for request queueing
|
||||
* @dep: struct dwc3_ep owning this request
|
||||
* @first_trb_index: index to first trb used by this request
|
||||
* @epnum: endpoint number to which this request refers
|
||||
* @trb: pointer to struct dwc3_trb
|
||||
* @trb_dma: DMA address of @trb
|
||||
* @direction: IN or OUT direction flag
|
||||
* @mapped: true when request has been dma-mapped
|
||||
* @queued: true when request has been queued to HW
|
||||
*/
|
||||
struct dwc3_request {
|
||||
struct usb_request request;
|
||||
struct list_head list;
|
||||
struct dwc3_ep *dep;
|
||||
u32 start_slot;
|
||||
|
||||
u8 first_trb_index;
|
||||
u8 epnum;
|
||||
struct dwc3_trb *trb;
|
||||
dma_addr_t trb_dma;
|
||||
|
||||
unsigned direction:1;
|
||||
unsigned mapped:1;
|
||||
unsigned queued:1;
|
||||
unsigned started:1;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -667,7 +712,6 @@ struct dwc3_scratchpad_array {
|
|||
* @regs: base address for our registers
|
||||
* @regs_size: address space size
|
||||
* @nr_scratch: number of scratch buffers
|
||||
* @num_event_buffers: calculated number of event buffers
|
||||
* @u1u2: only used on revisions <1.83a for workaround
|
||||
* @maximum_speed: maximum speed requested (mainly for testing purposes)
|
||||
* @revision: revision register contents
|
||||
|
|
@ -709,9 +753,7 @@ struct dwc3_scratchpad_array {
|
|||
* 0 - utmi_sleep_n
|
||||
* 1 - utmi_l1_suspend_n
|
||||
* @is_fpga: true when we are using the FPGA board
|
||||
* @needs_fifo_resize: not all users might want fifo resizing, flag it
|
||||
* @pullups_connected: true when Run/Stop bit is set
|
||||
* @resize_fifos: tells us it's ok to reconfigure our TxFIFO sizes.
|
||||
* @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround
|
||||
* @start_config_issued: true when StartConfig command has been issued
|
||||
* @three_stage_setup: set if we perform a three phase setup
|
||||
|
|
@ -756,7 +798,7 @@ struct dwc3 {
|
|||
struct platform_device *xhci;
|
||||
struct resource xhci_resources[DWC3_XHCI_RESOURCES_NUM];
|
||||
|
||||
struct dwc3_event_buffer **ev_buffs;
|
||||
struct dwc3_event_buffer *ev_buf;
|
||||
struct dwc3_ep *eps[DWC3_ENDPOINTS_NUM];
|
||||
|
||||
struct usb_gadget gadget;
|
||||
|
|
@ -780,7 +822,6 @@ struct dwc3 {
|
|||
u32 gctl;
|
||||
|
||||
u32 nr_scratch;
|
||||
u32 num_event_buffers;
|
||||
u32 u1u2;
|
||||
u32 maximum_speed;
|
||||
|
||||
|
|
@ -855,9 +896,7 @@ struct dwc3 {
|
|||
unsigned has_lpm_erratum:1;
|
||||
unsigned is_utmi_l1_suspend:1;
|
||||
unsigned is_fpga:1;
|
||||
unsigned needs_fifo_resize:1;
|
||||
unsigned pullups_connected:1;
|
||||
unsigned resize_fifos:1;
|
||||
unsigned setup_packet_pending:1;
|
||||
unsigned three_stage_setup:1;
|
||||
unsigned usb3_lpm_capable:1;
|
||||
|
|
@ -873,6 +912,7 @@ struct dwc3 {
|
|||
unsigned dis_u3_susphy_quirk:1;
|
||||
unsigned dis_u2_susphy_quirk:1;
|
||||
unsigned dis_enblslpm_quirk:1;
|
||||
unsigned dis_rxdet_inp3_quirk:1;
|
||||
|
||||
unsigned tx_de_emphasis_quirk:1;
|
||||
unsigned tx_de_emphasis:2;
|
||||
|
|
@ -938,6 +978,10 @@ struct dwc3_event_depevt {
|
|||
#define DEPEVT_STATUS_CONTROL_DATA 1
|
||||
#define DEPEVT_STATUS_CONTROL_STATUS 2
|
||||
|
||||
/* In response to Start Transfer */
|
||||
#define DEPEVT_TRANSFER_NO_RESOURCE 1
|
||||
#define DEPEVT_TRANSFER_BUS_EXPIRY 2
|
||||
|
||||
u32 parameters:16;
|
||||
} __packed;
|
||||
|
||||
|
|
@ -1025,7 +1069,7 @@ struct dwc3_gadget_ep_cmd_params {
|
|||
|
||||
/* prototypes */
|
||||
void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
|
||||
int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc);
|
||||
u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type);
|
||||
|
||||
/* check whether we are on the DWC_usb31 core */
|
||||
static inline bool dwc3_is_usb31(struct dwc3 *dwc)
|
||||
|
|
|
|||
|
|
@ -217,11 +217,11 @@ static inline const char *dwc3_gadget_event_type_string(u8 event)
|
|||
void dwc3_trace(void (*trace)(struct va_format *), const char *fmt, ...);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
extern int dwc3_debugfs_init(struct dwc3 *);
|
||||
extern void dwc3_debugfs_init(struct dwc3 *);
|
||||
extern void dwc3_debugfs_exit(struct dwc3 *);
|
||||
#else
|
||||
static inline int dwc3_debugfs_init(struct dwc3 *d)
|
||||
{ return 0; }
|
||||
static inline void dwc3_debugfs_init(struct dwc3 *d)
|
||||
{ }
|
||||
static inline void dwc3_debugfs_exit(struct dwc3 *d)
|
||||
{ }
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -618,24 +618,323 @@ static const struct file_operations dwc3_link_state_fops = {
|
|||
.release = single_release,
|
||||
};
|
||||
|
||||
int dwc3_debugfs_init(struct dwc3 *dwc)
|
||||
{
|
||||
struct dentry *root;
|
||||
struct dentry *file;
|
||||
int ret;
|
||||
struct dwc3_ep_file_map {
|
||||
char name[25];
|
||||
int (*show)(struct seq_file *s, void *unused);
|
||||
};
|
||||
|
||||
root = debugfs_create_dir(dev_name(dwc->dev), NULL);
|
||||
if (!root) {
|
||||
ret = -ENOMEM;
|
||||
goto err0;
|
||||
static int dwc3_tx_fifo_queue_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct dwc3_ep *dep = s->private;
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
val = dwc3_core_fifo_space(dep, DWC3_TXFIFOQ);
|
||||
seq_printf(s, "%u\n", val);
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_rx_fifo_queue_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct dwc3_ep *dep = s->private;
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
val = dwc3_core_fifo_space(dep, DWC3_RXFIFOQ);
|
||||
seq_printf(s, "%u\n", val);
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_tx_request_queue_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct dwc3_ep *dep = s->private;
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
val = dwc3_core_fifo_space(dep, DWC3_TXREQQ);
|
||||
seq_printf(s, "%u\n", val);
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_rx_request_queue_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct dwc3_ep *dep = s->private;
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
val = dwc3_core_fifo_space(dep, DWC3_RXREQQ);
|
||||
seq_printf(s, "%u\n", val);
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_rx_info_queue_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct dwc3_ep *dep = s->private;
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
val = dwc3_core_fifo_space(dep, DWC3_RXINFOQ);
|
||||
seq_printf(s, "%u\n", val);
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_descriptor_fetch_queue_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct dwc3_ep *dep = s->private;
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
val = dwc3_core_fifo_space(dep, DWC3_DESCFETCHQ);
|
||||
seq_printf(s, "%u\n", val);
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_event_queue_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct dwc3_ep *dep = s->private;
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
val = dwc3_core_fifo_space(dep, DWC3_EVENTQ);
|
||||
seq_printf(s, "%u\n", val);
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_ep_transfer_type_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct dwc3_ep *dep = s->private;
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
if (!(dep->flags & DWC3_EP_ENABLED) ||
|
||||
!dep->endpoint.desc) {
|
||||
seq_printf(s, "--\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch (usb_endpoint_type(dep->endpoint.desc)) {
|
||||
case USB_ENDPOINT_XFER_CONTROL:
|
||||
seq_printf(s, "control\n");
|
||||
break;
|
||||
case USB_ENDPOINT_XFER_ISOC:
|
||||
seq_printf(s, "isochronous\n");
|
||||
break;
|
||||
case USB_ENDPOINT_XFER_BULK:
|
||||
seq_printf(s, "bulk\n");
|
||||
break;
|
||||
case USB_ENDPOINT_XFER_INT:
|
||||
seq_printf(s, "interrupt\n");
|
||||
break;
|
||||
default:
|
||||
seq_printf(s, "--\n");
|
||||
}
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline const char *dwc3_trb_type_string(struct dwc3_trb *trb)
|
||||
{
|
||||
switch (DWC3_TRBCTL_TYPE(trb->ctrl)) {
|
||||
case DWC3_TRBCTL_NORMAL:
|
||||
return "normal";
|
||||
case DWC3_TRBCTL_CONTROL_SETUP:
|
||||
return "control-setup";
|
||||
case DWC3_TRBCTL_CONTROL_STATUS2:
|
||||
return "control-status2";
|
||||
case DWC3_TRBCTL_CONTROL_STATUS3:
|
||||
return "control-status3";
|
||||
case DWC3_TRBCTL_CONTROL_DATA:
|
||||
return "control-data";
|
||||
case DWC3_TRBCTL_ISOCHRONOUS_FIRST:
|
||||
return "isoc-first";
|
||||
case DWC3_TRBCTL_ISOCHRONOUS:
|
||||
return "isoc";
|
||||
case DWC3_TRBCTL_LINK_TRB:
|
||||
return "link";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
static int dwc3_ep_trb_ring_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct dwc3_ep *dep = s->private;
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
if (dep->number <= 1) {
|
||||
seq_printf(s, "--\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
seq_printf(s, "enqueue pointer %d\n", dep->trb_enqueue);
|
||||
seq_printf(s, "dequeue pointer %d\n", dep->trb_dequeue);
|
||||
seq_printf(s, "\n--------------------------------------------------\n\n");
|
||||
seq_printf(s, "buffer_addr,size,type,ioc,isp_imi,csp,chn,lst,hwo\n");
|
||||
|
||||
for (i = 0; i < DWC3_TRB_NUM; i++) {
|
||||
struct dwc3_trb *trb = &dep->trb_pool[i];
|
||||
|
||||
seq_printf(s, "%08x%08x,%d,%s,%d,%d,%d,%d,%d,%d\n",
|
||||
trb->bph, trb->bpl, trb->size,
|
||||
dwc3_trb_type_string(trb),
|
||||
!!(trb->ctrl & DWC3_TRB_CTRL_IOC),
|
||||
!!(trb->ctrl & DWC3_TRB_CTRL_ISP_IMI),
|
||||
!!(trb->ctrl & DWC3_TRB_CTRL_CSP),
|
||||
!!(trb->ctrl & DWC3_TRB_CTRL_CHN),
|
||||
!!(trb->ctrl & DWC3_TRB_CTRL_LST),
|
||||
!!(trb->ctrl & DWC3_TRB_CTRL_HWO));
|
||||
}
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dwc3_ep_file_map map[] = {
|
||||
{ "tx_fifo_queue", dwc3_tx_fifo_queue_show, },
|
||||
{ "rx_fifo_queue", dwc3_rx_fifo_queue_show, },
|
||||
{ "tx_request_queue", dwc3_tx_request_queue_show, },
|
||||
{ "rx_request_queue", dwc3_rx_request_queue_show, },
|
||||
{ "rx_info_queue", dwc3_rx_info_queue_show, },
|
||||
{ "descriptor_fetch_queue", dwc3_descriptor_fetch_queue_show, },
|
||||
{ "event_queue", dwc3_event_queue_show, },
|
||||
{ "transfer_type", dwc3_ep_transfer_type_show, },
|
||||
{ "trb_ring", dwc3_ep_trb_ring_show, },
|
||||
};
|
||||
|
||||
static int dwc3_endpoint_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
const char *file_name = file_dentry(file)->d_iname;
|
||||
struct dwc3_ep_file_map *f_map;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(map); i++) {
|
||||
f_map = &map[i];
|
||||
|
||||
if (strcmp(f_map->name, file_name) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return single_open(file, f_map->show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations dwc3_endpoint_fops = {
|
||||
.open = dwc3_endpoint_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static void dwc3_debugfs_create_endpoint_file(struct dwc3_ep *dep,
|
||||
struct dentry *parent, int type)
|
||||
{
|
||||
struct dentry *file;
|
||||
struct dwc3_ep_file_map *ep_file = &map[type];
|
||||
|
||||
file = debugfs_create_file(ep_file->name, S_IRUGO, parent, dep,
|
||||
&dwc3_endpoint_fops);
|
||||
}
|
||||
|
||||
static void dwc3_debugfs_create_endpoint_files(struct dwc3_ep *dep,
|
||||
struct dentry *parent)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(map); i++)
|
||||
dwc3_debugfs_create_endpoint_file(dep, parent, i);
|
||||
}
|
||||
|
||||
static void dwc3_debugfs_create_endpoint_dir(struct dwc3_ep *dep,
|
||||
struct dentry *parent)
|
||||
{
|
||||
struct dentry *dir;
|
||||
|
||||
dir = debugfs_create_dir(dep->name, parent);
|
||||
if (IS_ERR_OR_NULL(dir))
|
||||
return;
|
||||
|
||||
dwc3_debugfs_create_endpoint_files(dep, dir);
|
||||
}
|
||||
|
||||
static void dwc3_debugfs_create_endpoint_dirs(struct dwc3 *dwc,
|
||||
struct dentry *parent)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < dwc->num_in_eps; i++) {
|
||||
u8 epnum = (i << 1) | 1;
|
||||
struct dwc3_ep *dep = dwc->eps[epnum];
|
||||
|
||||
if (!dep)
|
||||
continue;
|
||||
|
||||
dwc3_debugfs_create_endpoint_dir(dep, parent);
|
||||
}
|
||||
|
||||
for (i = 0; i < dwc->num_out_eps; i++) {
|
||||
u8 epnum = (i << 1);
|
||||
struct dwc3_ep *dep = dwc->eps[epnum];
|
||||
|
||||
if (!dep)
|
||||
continue;
|
||||
|
||||
dwc3_debugfs_create_endpoint_dir(dep, parent);
|
||||
}
|
||||
}
|
||||
|
||||
void dwc3_debugfs_init(struct dwc3 *dwc)
|
||||
{
|
||||
struct dentry *root;
|
||||
struct dentry *file;
|
||||
|
||||
root = debugfs_create_dir(dev_name(dwc->dev), NULL);
|
||||
if (IS_ERR_OR_NULL(root)) {
|
||||
if (!root)
|
||||
dev_err(dwc->dev, "Can't create debugfs root\n");
|
||||
return;
|
||||
}
|
||||
dwc->root = root;
|
||||
|
||||
dwc->regset = kzalloc(sizeof(*dwc->regset), GFP_KERNEL);
|
||||
if (!dwc->regset) {
|
||||
ret = -ENOMEM;
|
||||
goto err1;
|
||||
debugfs_remove_recursive(root);
|
||||
return;
|
||||
}
|
||||
|
||||
dwc->regset->regs = dwc3_regs;
|
||||
|
|
@ -643,47 +942,30 @@ int dwc3_debugfs_init(struct dwc3 *dwc)
|
|||
dwc->regset->base = dwc->regs;
|
||||
|
||||
file = debugfs_create_regset32("regdump", S_IRUGO, root, dwc->regset);
|
||||
if (!file) {
|
||||
ret = -ENOMEM;
|
||||
goto err2;
|
||||
}
|
||||
if (!file)
|
||||
dev_dbg(dwc->dev, "Can't create debugfs regdump\n");
|
||||
|
||||
if (IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)) {
|
||||
file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root,
|
||||
dwc, &dwc3_mode_fops);
|
||||
if (!file) {
|
||||
ret = -ENOMEM;
|
||||
goto err2;
|
||||
}
|
||||
if (!file)
|
||||
dev_dbg(dwc->dev, "Can't create debugfs mode\n");
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE) ||
|
||||
IS_ENABLED(CONFIG_USB_DWC3_GADGET)) {
|
||||
file = debugfs_create_file("testmode", S_IRUGO | S_IWUSR, root,
|
||||
dwc, &dwc3_testmode_fops);
|
||||
if (!file) {
|
||||
ret = -ENOMEM;
|
||||
goto err2;
|
||||
}
|
||||
if (!file)
|
||||
dev_dbg(dwc->dev, "Can't create debugfs testmode\n");
|
||||
|
||||
file = debugfs_create_file("link_state", S_IRUGO | S_IWUSR, root,
|
||||
dwc, &dwc3_link_state_fops);
|
||||
if (!file) {
|
||||
ret = -ENOMEM;
|
||||
goto err2;
|
||||
}
|
||||
file = debugfs_create_file("link_state", S_IRUGO | S_IWUSR,
|
||||
root, dwc, &dwc3_link_state_fops);
|
||||
if (!file)
|
||||
dev_dbg(dwc->dev, "Can't create debugfs link_state\n");
|
||||
|
||||
dwc3_debugfs_create_endpoint_dirs(dwc, root);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
kfree(dwc->regset);
|
||||
|
||||
err1:
|
||||
debugfs_remove_recursive(root);
|
||||
|
||||
err0:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void dwc3_debugfs_exit(struct dwc3 *dwc)
|
||||
|
|
|
|||
|
|
@ -126,8 +126,6 @@ struct dwc3_omap {
|
|||
u32 debug_offset;
|
||||
u32 irq0_offset;
|
||||
|
||||
u32 dma_status:1;
|
||||
|
||||
struct extcon_dev *edev;
|
||||
struct notifier_block vbus_nb;
|
||||
struct notifier_block id_nb;
|
||||
|
|
@ -277,9 +275,6 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
|
|||
|
||||
reg = dwc3_omap_read_irqmisc_status(omap);
|
||||
|
||||
if (reg & USBOTGSS_IRQMISC_DMADISABLECLR)
|
||||
omap->dma_status = false;
|
||||
|
||||
dwc3_omap_write_irqmisc_status(omap, reg);
|
||||
|
||||
reg = dwc3_omap_read_irq0_status(omap);
|
||||
|
|
@ -331,8 +326,6 @@ static void dwc3_omap_disable_irqs(struct dwc3_omap *omap)
|
|||
dwc3_omap_write_irqmisc_clr(omap, reg);
|
||||
}
|
||||
|
||||
static u64 dwc3_omap_dma_mask = DMA_BIT_MASK(32);
|
||||
|
||||
static int dwc3_omap_id_notifier(struct notifier_block *nb,
|
||||
unsigned long event, void *ptr)
|
||||
{
|
||||
|
|
@ -490,7 +483,6 @@ static int dwc3_omap_probe(struct platform_device *pdev)
|
|||
omap->irq = irq;
|
||||
omap->base = base;
|
||||
omap->vbus_reg = vbus_reg;
|
||||
dev->dma_mask = &dwc3_omap_dma_mask;
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
ret = pm_runtime_get_sync(dev);
|
||||
|
|
@ -504,7 +496,6 @@ static int dwc3_omap_probe(struct platform_device *pdev)
|
|||
|
||||
/* check the DMA Status */
|
||||
reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG);
|
||||
omap->dma_status = !!(reg & USBOTGSS_SYSCONFIG_DMADISABLE);
|
||||
|
||||
ret = devm_request_irq(dev, omap->irq, dwc3_omap_interrupt, 0,
|
||||
"dwc3-omap", omap);
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ static const struct acpi_gpio_mapping acpi_dwc3_byt_gpios[] = {
|
|||
{ },
|
||||
};
|
||||
|
||||
static int dwc3_pci_quirks(struct pci_dev *pdev)
|
||||
static int dwc3_pci_quirks(struct pci_dev *pdev, struct platform_device *dwc3)
|
||||
{
|
||||
if (pdev->vendor == PCI_VENDOR_ID_AMD &&
|
||||
pdev->device == PCI_DEVICE_ID_AMD_NL_USB) {
|
||||
|
|
@ -77,8 +77,7 @@ static int dwc3_pci_quirks(struct pci_dev *pdev)
|
|||
pdata.dis_u3_susphy_quirk = true;
|
||||
pdata.dis_u2_susphy_quirk = true;
|
||||
|
||||
return platform_device_add_data(pci_get_drvdata(pdev), &pdata,
|
||||
sizeof(pdata));
|
||||
return platform_device_add_data(dwc3, &pdata, sizeof(pdata));
|
||||
}
|
||||
|
||||
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
|
||||
|
|
@ -123,8 +122,7 @@ static int dwc3_pci_quirks(struct pci_dev *pdev)
|
|||
pdata.has_lpm_erratum = true;
|
||||
pdata.dis_enblslpm_quirk = true;
|
||||
|
||||
return platform_device_add_data(pci_get_drvdata(pdev), &pdata,
|
||||
sizeof(pdata));
|
||||
return platform_device_add_data(dwc3, &pdata, sizeof(pdata));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -169,20 +167,20 @@ static int dwc3_pci_probe(struct pci_dev *pci,
|
|||
return ret;
|
||||
}
|
||||
|
||||
pci_set_drvdata(pci, dwc3);
|
||||
ret = dwc3_pci_quirks(pci);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
dwc3->dev.parent = dev;
|
||||
ACPI_COMPANION_SET(&dwc3->dev, ACPI_COMPANION(dev));
|
||||
|
||||
ret = dwc3_pci_quirks(pci, dwc3);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = platform_device_add(dwc3);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to register dwc3 device\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
pci_set_drvdata(pci, dwc3);
|
||||
return 0;
|
||||
err:
|
||||
platform_device_put(dwc3);
|
||||
|
|
|
|||
|
|
@ -70,10 +70,10 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
|
|||
return 0;
|
||||
}
|
||||
|
||||
trb = &dwc->ep0_trb[dep->free_slot];
|
||||
trb = &dwc->ep0_trb[dep->trb_enqueue];
|
||||
|
||||
if (chain)
|
||||
dep->free_slot++;
|
||||
dep->trb_enqueue++;
|
||||
|
||||
trb->bpl = lower_32_bits(buf_dma);
|
||||
trb->bph = upper_32_bits(buf_dma);
|
||||
|
|
@ -124,7 +124,7 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,
|
|||
req->request.status = -EINPROGRESS;
|
||||
req->epnum = dep->number;
|
||||
|
||||
list_add_tail(&req->list, &dep->request_list);
|
||||
list_add_tail(&req->list, &dep->pending_list);
|
||||
|
||||
/*
|
||||
* Gadget driver might not be quick enough to queue a request
|
||||
|
|
@ -240,7 +240,7 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
|
|||
}
|
||||
|
||||
/* we share one TRB for ep0/1 */
|
||||
if (!list_empty(&dep->request_list)) {
|
||||
if (!list_empty(&dep->pending_list)) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -272,10 +272,10 @@ static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc)
|
|||
dep->flags = DWC3_EP_ENABLED;
|
||||
dwc->delayed_status = false;
|
||||
|
||||
if (!list_empty(&dep->request_list)) {
|
||||
if (!list_empty(&dep->pending_list)) {
|
||||
struct dwc3_request *req;
|
||||
|
||||
req = next_request(&dep->request_list);
|
||||
req = next_request(&dep->pending_list);
|
||||
dwc3_gadget_giveback(dep, req, -ECONNRESET);
|
||||
}
|
||||
|
||||
|
|
@ -463,8 +463,18 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
|
|||
if (!set)
|
||||
return -EINVAL;
|
||||
|
||||
dwc->test_mode_nr = wIndex >> 8;
|
||||
dwc->test_mode = true;
|
||||
switch (wIndex >> 8) {
|
||||
case TEST_J:
|
||||
case TEST_K:
|
||||
case TEST_SE0_NAK:
|
||||
case TEST_PACKET:
|
||||
case TEST_FORCE_EN:
|
||||
dwc->test_mode_nr = wIndex >> 8;
|
||||
dwc->test_mode = true;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
|
@ -586,9 +596,6 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
|
|||
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
|
||||
reg |= (DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA);
|
||||
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
|
||||
|
||||
dwc->resize_fifos = true;
|
||||
dwc3_trace(trace_dwc3_ep0, "resize FIFOs flag SET");
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -809,7 +816,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
|
|||
|
||||
trace_dwc3_complete_trb(ep0, trb);
|
||||
|
||||
r = next_request(&ep0->request_list);
|
||||
r = next_request(&ep0->pending_list);
|
||||
if (!r)
|
||||
return;
|
||||
|
||||
|
|
@ -848,7 +855,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
|
|||
trb++;
|
||||
length = trb->size & DWC3_TRB_SIZE_MASK;
|
||||
|
||||
ep0->free_slot = 0;
|
||||
ep0->trb_enqueue = 0;
|
||||
}
|
||||
|
||||
transfer_size = roundup((ur->length - transfer_size),
|
||||
|
|
@ -897,8 +904,8 @@ static void dwc3_ep0_complete_status(struct dwc3 *dwc,
|
|||
|
||||
trace_dwc3_complete_trb(dep, trb);
|
||||
|
||||
if (!list_empty(&dep->request_list)) {
|
||||
r = next_request(&dep->request_list);
|
||||
if (!list_empty(&dep->pending_list)) {
|
||||
r = next_request(&dep->pending_list);
|
||||
|
||||
dwc3_gadget_giveback(dep, r, 0);
|
||||
}
|
||||
|
|
@ -1027,12 +1034,6 @@ static int dwc3_ep0_start_control_status(struct dwc3_ep *dep)
|
|||
|
||||
static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep)
|
||||
{
|
||||
if (dwc->resize_fifos) {
|
||||
dwc3_trace(trace_dwc3_ep0, "Resizing FIFOs");
|
||||
dwc3_gadget_resize_tx_fifos(dwc);
|
||||
dwc->resize_fifos = 0;
|
||||
}
|
||||
|
||||
WARN_ON(dwc3_ep0_start_control_status(dep));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -145,90 +145,21 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
|
|||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc3_gadget_resize_tx_fifos - reallocate fifo spaces for current use-case
|
||||
* @dwc: pointer to our context structure
|
||||
*
|
||||
* This function will a best effort FIFO allocation in order
|
||||
* to improve FIFO usage and throughput, while still allowing
|
||||
* us to enable as many endpoints as possible.
|
||||
*
|
||||
* Keep in mind that this operation will be highly dependent
|
||||
* on the configured size for RAM1 - which contains TxFifo -,
|
||||
* the amount of endpoints enabled on coreConsultant tool, and
|
||||
* the width of the Master Bus.
|
||||
*
|
||||
* In the ideal world, we would always be able to satisfy the
|
||||
* following equation:
|
||||
*
|
||||
* ((512 + 2 * MDWIDTH-Bytes) + (Number of IN Endpoints - 1) * \
|
||||
* (3 * (1024 + MDWIDTH-Bytes) + MDWIDTH-Bytes)) / MDWIDTH-Bytes
|
||||
*
|
||||
* Unfortunately, due to many variables that's not always the case.
|
||||
*/
|
||||
int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc)
|
||||
static void dwc3_ep_inc_enq(struct dwc3_ep *dep)
|
||||
{
|
||||
int last_fifo_depth = 0;
|
||||
int ram1_depth;
|
||||
int fifo_size;
|
||||
int mdwidth;
|
||||
int num;
|
||||
dep->trb_enqueue++;
|
||||
dep->trb_enqueue %= DWC3_TRB_NUM;
|
||||
}
|
||||
|
||||
if (!dwc->needs_fifo_resize)
|
||||
return 0;
|
||||
static void dwc3_ep_inc_deq(struct dwc3_ep *dep)
|
||||
{
|
||||
dep->trb_dequeue++;
|
||||
dep->trb_dequeue %= DWC3_TRB_NUM;
|
||||
}
|
||||
|
||||
ram1_depth = DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7);
|
||||
mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0);
|
||||
|
||||
/* MDWIDTH is represented in bits, we need it in bytes */
|
||||
mdwidth >>= 3;
|
||||
|
||||
/*
|
||||
* FIXME For now we will only allocate 1 wMaxPacketSize space
|
||||
* for each enabled endpoint, later patches will come to
|
||||
* improve this algorithm so that we better use the internal
|
||||
* FIFO space
|
||||
*/
|
||||
for (num = 0; num < dwc->num_in_eps; num++) {
|
||||
/* bit0 indicates direction; 1 means IN ep */
|
||||
struct dwc3_ep *dep = dwc->eps[(num << 1) | 1];
|
||||
int mult = 1;
|
||||
int tmp;
|
||||
|
||||
if (!(dep->flags & DWC3_EP_ENABLED))
|
||||
continue;
|
||||
|
||||
if (usb_endpoint_xfer_bulk(dep->endpoint.desc)
|
||||
|| usb_endpoint_xfer_isoc(dep->endpoint.desc))
|
||||
mult = 3;
|
||||
|
||||
/*
|
||||
* REVISIT: the following assumes we will always have enough
|
||||
* space available on the FIFO RAM for all possible use cases.
|
||||
* Make sure that's true somehow and change FIFO allocation
|
||||
* accordingly.
|
||||
*
|
||||
* If we have Bulk or Isochronous endpoints, we want
|
||||
* them to be able to be very, very fast. So we're giving
|
||||
* those endpoints a fifo_size which is enough for 3 full
|
||||
* packets
|
||||
*/
|
||||
tmp = mult * (dep->endpoint.maxpacket + mdwidth);
|
||||
tmp += mdwidth;
|
||||
|
||||
fifo_size = DIV_ROUND_UP(tmp, mdwidth);
|
||||
|
||||
fifo_size |= (last_fifo_depth << 16);
|
||||
|
||||
dwc3_trace(trace_dwc3_gadget, "%s: Fifo Addr %04x Size %d",
|
||||
dep->name, last_fifo_depth, fifo_size & 0xffff);
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(num), fifo_size);
|
||||
|
||||
last_fifo_depth += (fifo_size & 0xffff);
|
||||
}
|
||||
|
||||
return 0;
|
||||
static int dwc3_ep_is_last_trb(unsigned int index)
|
||||
{
|
||||
return index == DWC3_TRB_NUM - 1;
|
||||
}
|
||||
|
||||
void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
|
||||
|
|
@ -237,21 +168,19 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
|
|||
struct dwc3 *dwc = dep->dwc;
|
||||
int i;
|
||||
|
||||
if (req->queued) {
|
||||
if (req->started) {
|
||||
i = 0;
|
||||
do {
|
||||
dep->busy_slot++;
|
||||
dwc3_ep_inc_deq(dep);
|
||||
/*
|
||||
* Skip LINK TRB. We can't use req->trb and check for
|
||||
* DWC3_TRBCTL_LINK_TRB because it points the TRB we
|
||||
* just completed (not the LINK TRB).
|
||||
*/
|
||||
if (((dep->busy_slot & DWC3_TRB_MASK) ==
|
||||
DWC3_TRB_NUM- 1) &&
|
||||
usb_endpoint_xfer_isoc(dep->endpoint.desc))
|
||||
dep->busy_slot++;
|
||||
if (dwc3_ep_is_last_trb(dep->trb_dequeue))
|
||||
dwc3_ep_inc_deq(dep);
|
||||
} while(++i < req->request.num_mapped_sgs);
|
||||
req->queued = false;
|
||||
req->started = false;
|
||||
}
|
||||
list_del(&req->list);
|
||||
req->trb = NULL;
|
||||
|
|
@ -307,6 +236,8 @@ int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param)
|
|||
} while (1);
|
||||
}
|
||||
|
||||
static int __dwc3_gadget_wakeup(struct dwc3 *dwc);
|
||||
|
||||
int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
|
||||
unsigned cmd, struct dwc3_gadget_ep_cmd_params *params)
|
||||
{
|
||||
|
|
@ -314,8 +245,40 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
|
|||
u32 timeout = 500;
|
||||
u32 reg;
|
||||
|
||||
int susphy = false;
|
||||
int ret = -EINVAL;
|
||||
|
||||
trace_dwc3_gadget_ep_cmd(dep, cmd, params);
|
||||
|
||||
/*
|
||||
* Synopsys Databook 2.60a states, on section 6.3.2.5.[1-8], that if
|
||||
* we're issuing an endpoint command, we must check if
|
||||
* GUSB2PHYCFG.SUSPHY bit is set. If it is, then we need to clear it.
|
||||
*
|
||||
* We will also set SUSPHY bit to what it was before returning as stated
|
||||
* by the same section on Synopsys databook.
|
||||
*/
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
|
||||
if (unlikely(reg & DWC3_GUSB2PHYCFG_SUSPHY)) {
|
||||
susphy = true;
|
||||
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
|
||||
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
|
||||
}
|
||||
|
||||
if (cmd == DWC3_DEPCMD_STARTTRANSFER) {
|
||||
int needs_wakeup;
|
||||
|
||||
needs_wakeup = (dwc->link_state == DWC3_LINK_STATE_U1 ||
|
||||
dwc->link_state == DWC3_LINK_STATE_U2 ||
|
||||
dwc->link_state == DWC3_LINK_STATE_U3);
|
||||
|
||||
if (unlikely(needs_wakeup)) {
|
||||
ret = __dwc3_gadget_wakeup(dwc);
|
||||
dev_WARN_ONCE(dwc->dev, ret, "wakeup failed --> %d\n",
|
||||
ret);
|
||||
}
|
||||
}
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_DEPCMDPAR0(ep), params->param0);
|
||||
dwc3_writel(dwc->regs, DWC3_DEPCMDPAR1(ep), params->param1);
|
||||
dwc3_writel(dwc->regs, DWC3_DEPCMDPAR2(ep), params->param2);
|
||||
|
|
@ -324,12 +287,40 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
|
|||
do {
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DEPCMD(ep));
|
||||
if (!(reg & DWC3_DEPCMD_CMDACT)) {
|
||||
int cmd_status = DWC3_DEPCMD_STATUS(reg);
|
||||
|
||||
dwc3_trace(trace_dwc3_gadget,
|
||||
"Command Complete --> %d",
|
||||
DWC3_DEPCMD_STATUS(reg));
|
||||
if (DWC3_DEPCMD_STATUS(reg))
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
cmd_status);
|
||||
|
||||
switch (cmd_status) {
|
||||
case 0:
|
||||
ret = 0;
|
||||
break;
|
||||
case DEPEVT_TRANSFER_NO_RESOURCE:
|
||||
dwc3_trace(trace_dwc3_gadget, "%s: no resource available");
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
case DEPEVT_TRANSFER_BUS_EXPIRY:
|
||||
/*
|
||||
* SW issues START TRANSFER command to
|
||||
* isochronous ep with future frame interval. If
|
||||
* future interval time has already passed when
|
||||
* core receives the command, it will respond
|
||||
* with an error status of 'Bus Expiry'.
|
||||
*
|
||||
* Instead of always returning -EINVAL, let's
|
||||
* give a hint to the gadget driver that this is
|
||||
* the case by returning -EAGAIN.
|
||||
*/
|
||||
dwc3_trace(trace_dwc3_gadget, "%s: bus expiry");
|
||||
ret = -EAGAIN;
|
||||
break;
|
||||
default:
|
||||
dev_WARN(dwc->dev, "UNKNOWN cmd status\n");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -340,11 +331,20 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
|
|||
if (!timeout) {
|
||||
dwc3_trace(trace_dwc3_gadget,
|
||||
"Command Timed Out");
|
||||
return -ETIMEDOUT;
|
||||
ret = -ETIMEDOUT;
|
||||
break;
|
||||
}
|
||||
|
||||
udelay(1);
|
||||
} while (1);
|
||||
|
||||
if (unlikely(susphy)) {
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
|
||||
reg |= DWC3_GUSB2PHYCFG_SUSPHY;
|
||||
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
|
||||
|
|
@ -464,9 +464,19 @@ static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
|
|||
|
||||
/* Burst size is only needed in SuperSpeed mode */
|
||||
if (dwc->gadget.speed >= USB_SPEED_SUPER) {
|
||||
u32 burst = dep->endpoint.maxburst - 1;
|
||||
u32 burst = dep->endpoint.maxburst;
|
||||
u32 nump;
|
||||
u32 reg;
|
||||
|
||||
params.param0 |= DWC3_DEPCFG_BURST_SIZE(burst);
|
||||
/* update NumP */
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
|
||||
nump = DWC3_DCFG_NUMP(reg);
|
||||
nump = max(nump, burst);
|
||||
reg &= ~DWC3_DCFG_NUMP_MASK;
|
||||
reg |= nump << DWC3_DCFG_NUMP_SHIFT;
|
||||
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
|
||||
|
||||
params.param0 |= DWC3_DEPCFG_BURST_SIZE(burst - 1);
|
||||
}
|
||||
|
||||
if (ignore)
|
||||
|
|
@ -567,10 +577,10 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
|
|||
reg |= DWC3_DALEPENA_EP(dep->number);
|
||||
dwc3_writel(dwc->regs, DWC3_DALEPENA, reg);
|
||||
|
||||
if (!usb_endpoint_xfer_isoc(desc))
|
||||
if (usb_endpoint_xfer_control(desc))
|
||||
goto out;
|
||||
|
||||
/* Link TRB for ISOC. The HWO bit is never reset */
|
||||
/* Link TRB. The HWO bit is never reset */
|
||||
trb_st_hw = &dep->trb_pool[0];
|
||||
|
||||
trb_link = &dep->trb_pool[DWC3_TRB_NUM - 1];
|
||||
|
|
@ -608,19 +618,19 @@ static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)
|
|||
{
|
||||
struct dwc3_request *req;
|
||||
|
||||
if (!list_empty(&dep->req_queued)) {
|
||||
if (!list_empty(&dep->started_list)) {
|
||||
dwc3_stop_active_transfer(dwc, dep->number, true);
|
||||
|
||||
/* - giveback all requests to gadget driver */
|
||||
while (!list_empty(&dep->req_queued)) {
|
||||
req = next_request(&dep->req_queued);
|
||||
while (!list_empty(&dep->started_list)) {
|
||||
req = next_request(&dep->started_list);
|
||||
|
||||
dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
|
||||
}
|
||||
}
|
||||
|
||||
while (!list_empty(&dep->request_list)) {
|
||||
req = next_request(&dep->request_list);
|
||||
while (!list_empty(&dep->pending_list)) {
|
||||
req = next_request(&dep->pending_list);
|
||||
|
||||
dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
|
||||
}
|
||||
|
|
@ -783,20 +793,19 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
|
|||
chain ? " chain" : "");
|
||||
|
||||
|
||||
trb = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
|
||||
trb = &dep->trb_pool[dep->trb_enqueue];
|
||||
|
||||
if (!req->trb) {
|
||||
dwc3_gadget_move_request_queued(req);
|
||||
dwc3_gadget_move_started_request(req);
|
||||
req->trb = trb;
|
||||
req->trb_dma = dwc3_trb_dma_offset(dep, trb);
|
||||
req->start_slot = dep->free_slot & DWC3_TRB_MASK;
|
||||
req->first_trb_index = dep->trb_enqueue;
|
||||
}
|
||||
|
||||
dep->free_slot++;
|
||||
/* Skip the LINK-TRB on ISOC */
|
||||
if (((dep->free_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
|
||||
usb_endpoint_xfer_isoc(dep->endpoint.desc))
|
||||
dep->free_slot++;
|
||||
dwc3_ep_inc_enq(dep);
|
||||
/* Skip the LINK-TRB */
|
||||
if (dwc3_ep_is_last_trb(dep->trb_enqueue))
|
||||
dwc3_ep_inc_enq(dep);
|
||||
|
||||
trb->size = DWC3_TRB_SIZE_LENGTH(length);
|
||||
trb->bpl = lower_32_bits(dma);
|
||||
|
|
@ -812,6 +821,9 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
|
|||
trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
|
||||
else
|
||||
trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS;
|
||||
|
||||
/* always enable Interrupt on Missed ISOC */
|
||||
trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI;
|
||||
break;
|
||||
|
||||
case USB_ENDPOINT_XFER_BULK:
|
||||
|
|
@ -826,15 +838,14 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
|
|||
BUG();
|
||||
}
|
||||
|
||||
if (!req->request.no_interrupt && !chain)
|
||||
trb->ctrl |= DWC3_TRB_CTRL_IOC;
|
||||
/* always enable Continue on Short Packet */
|
||||
trb->ctrl |= DWC3_TRB_CTRL_CSP;
|
||||
|
||||
if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
|
||||
trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI;
|
||||
trb->ctrl |= DWC3_TRB_CTRL_CSP;
|
||||
} else if (last) {
|
||||
if (!req->request.no_interrupt && !chain)
|
||||
trb->ctrl |= DWC3_TRB_CTRL_IOC | DWC3_TRB_CTRL_ISP_IMI;
|
||||
|
||||
if (last)
|
||||
trb->ctrl |= DWC3_TRB_CTRL_LST;
|
||||
}
|
||||
|
||||
if (chain)
|
||||
trb->ctrl |= DWC3_TRB_CTRL_CHN;
|
||||
|
|
@ -860,55 +871,29 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
|
|||
{
|
||||
struct dwc3_request *req, *n;
|
||||
u32 trbs_left;
|
||||
u32 max;
|
||||
unsigned int last_one = 0;
|
||||
|
||||
BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);
|
||||
|
||||
/* the first request must not be queued */
|
||||
trbs_left = (dep->busy_slot - dep->free_slot) & DWC3_TRB_MASK;
|
||||
|
||||
/* Can't wrap around on a non-isoc EP since there's no link TRB */
|
||||
if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
|
||||
max = DWC3_TRB_NUM - (dep->free_slot & DWC3_TRB_MASK);
|
||||
if (trbs_left > max)
|
||||
trbs_left = max;
|
||||
}
|
||||
trbs_left = dep->trb_dequeue - dep->trb_enqueue;
|
||||
|
||||
/*
|
||||
* If busy & slot are equal than it is either full or empty. If we are
|
||||
* starting to process requests then we are empty. Otherwise we are
|
||||
* If enqueue & dequeue are equal than it is either full or empty. If we
|
||||
* are starting to process requests then we are empty. Otherwise we are
|
||||
* full and don't do anything
|
||||
*/
|
||||
if (!trbs_left) {
|
||||
if (!starting)
|
||||
return;
|
||||
|
||||
trbs_left = DWC3_TRB_NUM;
|
||||
/*
|
||||
* In case we start from scratch, we queue the ISOC requests
|
||||
* starting from slot 1. This is done because we use ring
|
||||
* buffer and have no LST bit to stop us. Instead, we place
|
||||
* IOC bit every TRB_NUM/4. We try to avoid having an interrupt
|
||||
* after the first request so we start at slot 1 and have
|
||||
* 7 requests proceed before we hit the first IOC.
|
||||
* Other transfer types don't use the ring buffer and are
|
||||
* processed from the first TRB until the last one. Since we
|
||||
* don't wrap around we have to start at the beginning.
|
||||
*/
|
||||
if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
|
||||
dep->busy_slot = 1;
|
||||
dep->free_slot = 1;
|
||||
} else {
|
||||
dep->busy_slot = 0;
|
||||
dep->free_slot = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* The last TRB is a link TRB, not used for xfer */
|
||||
if ((trbs_left <= 1) && usb_endpoint_xfer_isoc(dep->endpoint.desc))
|
||||
if (trbs_left <= 1)
|
||||
return;
|
||||
|
||||
list_for_each_entry_safe(req, n, &dep->request_list, list) {
|
||||
list_for_each_entry_safe(req, n, &dep->pending_list, list) {
|
||||
unsigned length;
|
||||
dma_addr_t dma;
|
||||
last_one = false;
|
||||
|
|
@ -927,7 +912,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
|
|||
|
||||
if (i == (request->num_mapped_sgs - 1) ||
|
||||
sg_is_last(s)) {
|
||||
if (list_empty(&dep->request_list))
|
||||
if (list_empty(&dep->pending_list))
|
||||
last_one = true;
|
||||
chain = false;
|
||||
}
|
||||
|
|
@ -957,7 +942,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
|
|||
last_one = 1;
|
||||
|
||||
/* Is this the last request? */
|
||||
if (list_is_last(&req->list, &dep->request_list))
|
||||
if (list_is_last(&req->list, &dep->pending_list))
|
||||
last_one = 1;
|
||||
|
||||
dwc3_prepare_one_trb(dep, req, dma, length,
|
||||
|
|
@ -988,18 +973,18 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
|
|||
* new requests as we try to set the IOC bit only on the last request.
|
||||
*/
|
||||
if (start_new) {
|
||||
if (list_empty(&dep->req_queued))
|
||||
if (list_empty(&dep->started_list))
|
||||
dwc3_prepare_trbs(dep, start_new);
|
||||
|
||||
/* req points to the first request which will be sent */
|
||||
req = next_request(&dep->req_queued);
|
||||
req = next_request(&dep->started_list);
|
||||
} else {
|
||||
dwc3_prepare_trbs(dep, start_new);
|
||||
|
||||
/*
|
||||
* req points to the first request where HWO changed from 0 to 1
|
||||
*/
|
||||
req = next_request(&dep->req_queued);
|
||||
req = next_request(&dep->started_list);
|
||||
}
|
||||
if (!req) {
|
||||
dep->flags |= DWC3_EP_PENDING_REQUEST;
|
||||
|
|
@ -1046,7 +1031,7 @@ static void __dwc3_gadget_start_isoc(struct dwc3 *dwc,
|
|||
{
|
||||
u32 uf;
|
||||
|
||||
if (list_empty(&dep->request_list)) {
|
||||
if (list_empty(&dep->pending_list)) {
|
||||
dwc3_trace(trace_dwc3_gadget,
|
||||
"ISOC ep %s run out for requests",
|
||||
dep->name);
|
||||
|
|
@ -1114,7 +1099,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
list_add_tail(&req->list, &dep->request_list);
|
||||
list_add_tail(&req->list, &dep->pending_list);
|
||||
|
||||
/*
|
||||
* If there are no pending requests and the endpoint isn't already
|
||||
|
|
@ -1149,7 +1134,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
|
|||
* notion of current microframe.
|
||||
*/
|
||||
if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
|
||||
if (list_empty(&dep->req_queued)) {
|
||||
if (list_empty(&dep->started_list)) {
|
||||
dwc3_stop_active_transfer(dwc, dep->number, true);
|
||||
dep->flags = DWC3_EP_ENABLED;
|
||||
}
|
||||
|
|
@ -1267,13 +1252,13 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
|
|||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
|
||||
list_for_each_entry(r, &dep->request_list, list) {
|
||||
list_for_each_entry(r, &dep->pending_list, list) {
|
||||
if (r == req)
|
||||
break;
|
||||
}
|
||||
|
||||
if (r != req) {
|
||||
list_for_each_entry(r, &dep->req_queued, list) {
|
||||
list_for_each_entry(r, &dep->started_list, list) {
|
||||
if (r == req)
|
||||
break;
|
||||
}
|
||||
|
|
@ -1313,10 +1298,10 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol)
|
|||
|
||||
if (value) {
|
||||
if (!protocol && ((dep->direction && dep->flags & DWC3_EP_BUSY) ||
|
||||
(!list_empty(&dep->req_queued) ||
|
||||
!list_empty(&dep->request_list)))) {
|
||||
(!list_empty(&dep->started_list) ||
|
||||
!list_empty(&dep->pending_list)))) {
|
||||
dwc3_trace(trace_dwc3_gadget,
|
||||
"%s: pending request, cannot halt\n",
|
||||
"%s: pending request, cannot halt",
|
||||
dep->name);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
|
@ -1417,22 +1402,16 @@ static int dwc3_gadget_get_frame(struct usb_gadget *g)
|
|||
return DWC3_DSTS_SOFFN(reg);
|
||||
}
|
||||
|
||||
static int dwc3_gadget_wakeup(struct usb_gadget *g)
|
||||
static int __dwc3_gadget_wakeup(struct dwc3 *dwc)
|
||||
{
|
||||
struct dwc3 *dwc = gadget_to_dwc(g);
|
||||
|
||||
unsigned long timeout;
|
||||
unsigned long flags;
|
||||
|
||||
int ret;
|
||||
u32 reg;
|
||||
|
||||
int ret = 0;
|
||||
|
||||
u8 link_state;
|
||||
u8 speed;
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
|
||||
/*
|
||||
* According to the Databook Remote wakeup request should
|
||||
* be issued only when the device is in early suspend state.
|
||||
|
|
@ -1445,8 +1424,7 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g)
|
|||
if ((speed == DWC3_DSTS_SUPERSPEED) ||
|
||||
(speed == DWC3_DSTS_SUPERSPEED_PLUS)) {
|
||||
dwc3_trace(trace_dwc3_gadget, "no wakeup on SuperSpeed\n");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
link_state = DWC3_DSTS_USBLNKST(reg);
|
||||
|
|
@ -1459,14 +1437,13 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g)
|
|||
dwc3_trace(trace_dwc3_gadget,
|
||||
"can't wakeup from '%s'\n",
|
||||
dwc3_gadget_link_string(link_state));
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = dwc3_gadget_set_link_state(dwc, DWC3_LINK_STATE_RECOV);
|
||||
if (ret < 0) {
|
||||
dev_err(dwc->dev, "failed to put link in Recovery\n");
|
||||
goto out;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Recent versions do this automatically */
|
||||
|
|
@ -1490,10 +1467,20 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g)
|
|||
|
||||
if (DWC3_DSTS_USBLNKST(reg) != DWC3_LINK_STATE_U0) {
|
||||
dev_err(dwc->dev, "failed to send remote wakeup\n");
|
||||
ret = -EINVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_gadget_wakeup(struct usb_gadget *g)
|
||||
{
|
||||
struct dwc3 *dwc = gadget_to_dwc(g);
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
ret = __dwc3_gadget_wakeup(dwc);
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
return ret;
|
||||
|
|
@ -1620,7 +1607,7 @@ static int dwc3_gadget_start(struct usb_gadget *g,
|
|||
|
||||
irq = platform_get_irq(to_platform_device(dwc->dev), 0);
|
||||
ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt,
|
||||
IRQF_SHARED, "dwc3", dwc);
|
||||
IRQF_SHARED, "dwc3", dwc->ev_buf);
|
||||
if (ret) {
|
||||
dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
|
||||
irq, ret);
|
||||
|
|
@ -1682,6 +1669,17 @@ static int dwc3_gadget_start(struct usb_gadget *g,
|
|||
}
|
||||
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
|
||||
|
||||
/*
|
||||
* We are telling dwc3 that we want to use DCFG.NUMP as ACK TP's NUMP
|
||||
* field instead of letting dwc3 itself calculate that automatically.
|
||||
*
|
||||
* This way, we maximize the chances that we'll be able to get several
|
||||
* bursts of data without going through any sort of endpoint throttling.
|
||||
*/
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GRXTHRCFG);
|
||||
reg &= ~DWC3_GRXTHRCFG_PKTCNTSEL;
|
||||
dwc3_writel(dwc->regs, DWC3_GRXTHRCFG, reg);
|
||||
|
||||
/* Start with SuperSpeed Default */
|
||||
dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
|
||||
|
||||
|
|
@ -1720,7 +1718,7 @@ err2:
|
|||
err1:
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
free_irq(irq, dwc);
|
||||
free_irq(irq, dwc->ev_buf);
|
||||
|
||||
err0:
|
||||
return ret;
|
||||
|
|
@ -1743,7 +1741,7 @@ static int dwc3_gadget_stop(struct usb_gadget *g)
|
|||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
irq = platform_get_irq(to_platform_device(dwc->dev), 0);
|
||||
free_irq(irq, dwc);
|
||||
free_irq(irq, dwc->ev_buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1815,8 +1813,8 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
|
|||
dep->endpoint.caps.dir_in = !!direction;
|
||||
dep->endpoint.caps.dir_out = !direction;
|
||||
|
||||
INIT_LIST_HEAD(&dep->request_list);
|
||||
INIT_LIST_HEAD(&dep->req_queued);
|
||||
INIT_LIST_HEAD(&dep->pending_list);
|
||||
INIT_LIST_HEAD(&dep->started_list);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -1913,11 +1911,11 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep,
|
|||
* If there are still queued request
|
||||
* then wait, do not issue either END
|
||||
* or UPDATE TRANSFER, just attach next
|
||||
* request in request_list during
|
||||
* request in pending_list during
|
||||
* giveback.If any future queued request
|
||||
* is successfully transferred then we
|
||||
* will issue UPDATE TRANSFER for all
|
||||
* request in the request_list.
|
||||
* request in the pending_list.
|
||||
*/
|
||||
dep->flags |= DWC3_EP_MISSED_ISOC;
|
||||
} else {
|
||||
|
|
@ -1963,15 +1961,14 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
|
|||
int ret;
|
||||
|
||||
do {
|
||||
req = next_request(&dep->req_queued);
|
||||
req = next_request(&dep->started_list);
|
||||
if (WARN_ON_ONCE(!req))
|
||||
return 1;
|
||||
|
||||
i = 0;
|
||||
do {
|
||||
slot = req->start_slot + i;
|
||||
if ((slot == DWC3_TRB_NUM - 1) &&
|
||||
usb_endpoint_xfer_isoc(dep->endpoint.desc))
|
||||
slot = req->first_trb_index + i;
|
||||
if (slot == DWC3_TRB_NUM - 1)
|
||||
slot++;
|
||||
slot %= DWC3_TRB_NUM;
|
||||
trb = &dep->trb_pool[slot];
|
||||
|
|
@ -1989,8 +1986,8 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
|
|||
} while (1);
|
||||
|
||||
if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
|
||||
list_empty(&dep->req_queued)) {
|
||||
if (list_empty(&dep->request_list)) {
|
||||
list_empty(&dep->started_list)) {
|
||||
if (list_empty(&dep->pending_list)) {
|
||||
/*
|
||||
* If there is no entry in request list then do
|
||||
* not issue END TRANSFER now. Just set PENDING
|
||||
|
|
@ -2039,7 +2036,7 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
|
|||
if (!(dep->flags & DWC3_EP_ENABLED))
|
||||
continue;
|
||||
|
||||
if (!list_empty(&dep->req_queued))
|
||||
if (!list_empty(&dep->started_list))
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -2686,14 +2683,13 @@ static void dwc3_process_event_entry(struct dwc3 *dwc,
|
|||
}
|
||||
}
|
||||
|
||||
static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
|
||||
static irqreturn_t dwc3_process_event_buf(struct dwc3_event_buffer *evt)
|
||||
{
|
||||
struct dwc3_event_buffer *evt;
|
||||
struct dwc3 *dwc = evt->dwc;
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
int left;
|
||||
u32 reg;
|
||||
|
||||
evt = dwc->ev_buffs[buf];
|
||||
left = evt->count;
|
||||
|
||||
if (!(evt->flags & DWC3_EVENT_PENDING))
|
||||
|
|
@ -2718,7 +2714,7 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
|
|||
evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE;
|
||||
left -= 4;
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), 4);
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 4);
|
||||
}
|
||||
|
||||
evt->count = 0;
|
||||
|
|
@ -2726,39 +2722,34 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
|
|||
ret = IRQ_HANDLED;
|
||||
|
||||
/* Unmask interrupt */
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(buf));
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(0));
|
||||
reg &= ~DWC3_GEVNTSIZ_INTMASK;
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(buf), reg);
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), reg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc)
|
||||
static irqreturn_t dwc3_thread_interrupt(int irq, void *_evt)
|
||||
{
|
||||
struct dwc3 *dwc = _dwc;
|
||||
struct dwc3_event_buffer *evt = _evt;
|
||||
struct dwc3 *dwc = evt->dwc;
|
||||
unsigned long flags;
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
int i;
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
|
||||
for (i = 0; i < dwc->num_event_buffers; i++)
|
||||
ret |= dwc3_process_event_buf(dwc, i);
|
||||
|
||||
ret = dwc3_process_event_buf(evt);
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t dwc3_check_event_buf(struct dwc3 *dwc, u32 buf)
|
||||
static irqreturn_t dwc3_check_event_buf(struct dwc3_event_buffer *evt)
|
||||
{
|
||||
struct dwc3_event_buffer *evt;
|
||||
struct dwc3 *dwc = evt->dwc;
|
||||
u32 count;
|
||||
u32 reg;
|
||||
|
||||
evt = dwc->ev_buffs[buf];
|
||||
|
||||
count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(buf));
|
||||
count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(0));
|
||||
count &= DWC3_GEVNTCOUNT_MASK;
|
||||
if (!count)
|
||||
return IRQ_NONE;
|
||||
|
|
@ -2767,28 +2758,18 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3 *dwc, u32 buf)
|
|||
evt->flags |= DWC3_EVENT_PENDING;
|
||||
|
||||
/* Mask interrupt */
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(buf));
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(0));
|
||||
reg |= DWC3_GEVNTSIZ_INTMASK;
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(buf), reg);
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), reg);
|
||||
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
|
||||
static irqreturn_t dwc3_interrupt(int irq, void *_evt)
|
||||
{
|
||||
struct dwc3 *dwc = _dwc;
|
||||
int i;
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
struct dwc3_event_buffer *evt = _evt;
|
||||
|
||||
for (i = 0; i < dwc->num_event_buffers; i++) {
|
||||
irqreturn_t status;
|
||||
|
||||
status = dwc3_check_event_buf(dwc, i);
|
||||
if (status == IRQ_WAKE_THREAD)
|
||||
ret = status;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return dwc3_check_event_buf(evt);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -68,12 +68,12 @@ static inline struct dwc3_request *next_request(struct list_head *list)
|
|||
return list_first_entry(list, struct dwc3_request, list);
|
||||
}
|
||||
|
||||
static inline void dwc3_gadget_move_request_queued(struct dwc3_request *req)
|
||||
static inline void dwc3_gadget_move_started_request(struct dwc3_request *req)
|
||||
{
|
||||
struct dwc3_ep *dep = req->dep;
|
||||
|
||||
req->queued = true;
|
||||
list_move_tail(&req->list, &dep->req_queued);
|
||||
req->started = true;
|
||||
list_move_tail(&req->list, &dep->started_list);
|
||||
}
|
||||
|
||||
void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@
|
|||
struct dwc3_platform_data {
|
||||
enum usb_device_speed maximum_speed;
|
||||
enum usb_dr_mode dr_mode;
|
||||
bool tx_fifo_resize;
|
||||
bool usb3_lpm_capable;
|
||||
|
||||
unsigned is_utmi_l1_suspend:1;
|
||||
|
|
@ -43,6 +42,7 @@ struct dwc3_platform_data {
|
|||
unsigned dis_u3_susphy_quirk:1;
|
||||
unsigned dis_u2_susphy_quirk:1;
|
||||
unsigned dis_enblslpm_quirk:1;
|
||||
unsigned dis_rxdet_inp3_quirk:1;
|
||||
|
||||
unsigned tx_de_emphasis_quirk:1;
|
||||
unsigned tx_de_emphasis:2;
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
menuconfig USB_GADGET
|
||||
tristate "USB Gadget Support"
|
||||
select USB_COMMON
|
||||
select NLS
|
||||
help
|
||||
USB is a master/slave protocol, organized with one master
|
||||
|
|
|
|||
|
|
@ -66,20 +66,36 @@ function_descriptors(struct usb_function *f,
|
|||
{
|
||||
struct usb_descriptor_header **descriptors;
|
||||
|
||||
/*
|
||||
* NOTE: we try to help gadget drivers which might not be setting
|
||||
* max_speed appropriately.
|
||||
*/
|
||||
|
||||
switch (speed) {
|
||||
case USB_SPEED_SUPER_PLUS:
|
||||
descriptors = f->ssp_descriptors;
|
||||
break;
|
||||
if (descriptors)
|
||||
break;
|
||||
/* FALLTHROUGH */
|
||||
case USB_SPEED_SUPER:
|
||||
descriptors = f->ss_descriptors;
|
||||
break;
|
||||
if (descriptors)
|
||||
break;
|
||||
/* FALLTHROUGH */
|
||||
case USB_SPEED_HIGH:
|
||||
descriptors = f->hs_descriptors;
|
||||
break;
|
||||
if (descriptors)
|
||||
break;
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
descriptors = f->fs_descriptors;
|
||||
}
|
||||
|
||||
/*
|
||||
* if we can't find any descriptors at all, then this gadget deserves to
|
||||
* Oops with a NULL pointer dereference
|
||||
*/
|
||||
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -651,7 +651,7 @@ static void ffs_user_copy_worker(struct work_struct *work)
|
|||
if (io_data->read && ret > 0) {
|
||||
use_mm(io_data->mm);
|
||||
ret = copy_to_iter(io_data->buf, ret, &io_data->data);
|
||||
if (iov_iter_count(&io_data->data))
|
||||
if (ret != io_data->req->actual && iov_iter_count(&io_data->data))
|
||||
ret = -EFAULT;
|
||||
unuse_mm(io_data->mm);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2977,25 +2977,6 @@ void fsg_common_set_inquiry_string(struct fsg_common *common, const char *vn,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(fsg_common_set_inquiry_string);
|
||||
|
||||
int fsg_common_run_thread(struct fsg_common *common)
|
||||
{
|
||||
common->state = FSG_STATE_IDLE;
|
||||
/* Tell the thread to start working */
|
||||
common->thread_task =
|
||||
kthread_create(fsg_main_thread, common, "file-storage");
|
||||
if (IS_ERR(common->thread_task)) {
|
||||
common->state = FSG_STATE_TERMINATED;
|
||||
return PTR_ERR(common->thread_task);
|
||||
}
|
||||
|
||||
DBG(common, "I/O thread pid: %d\n", task_pid_nr(common->thread_task));
|
||||
|
||||
wake_up_process(common->thread_task);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fsg_common_run_thread);
|
||||
|
||||
static void fsg_common_release(struct kref *ref)
|
||||
{
|
||||
struct fsg_common *common = container_of(ref, struct fsg_common, ref);
|
||||
|
|
@ -3005,6 +2986,7 @@ static void fsg_common_release(struct kref *ref)
|
|||
if (common->state != FSG_STATE_TERMINATED) {
|
||||
raise_exception(common, FSG_STATE_EXIT);
|
||||
wait_for_completion(&common->thread_notifier);
|
||||
common->thread_task = NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(common->luns); ++i) {
|
||||
|
|
@ -3050,9 +3032,21 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
if (ret)
|
||||
return ret;
|
||||
fsg_common_set_inquiry_string(fsg->common, NULL, NULL);
|
||||
ret = fsg_common_run_thread(fsg->common);
|
||||
if (ret)
|
||||
}
|
||||
|
||||
if (!common->thread_task) {
|
||||
common->state = FSG_STATE_IDLE;
|
||||
common->thread_task =
|
||||
kthread_create(fsg_main_thread, common, "file-storage");
|
||||
if (IS_ERR(common->thread_task)) {
|
||||
int ret = PTR_ERR(common->thread_task);
|
||||
common->thread_task = NULL;
|
||||
common->state = FSG_STATE_TERMINATED;
|
||||
return ret;
|
||||
}
|
||||
DBG(common, "I/O thread pid: %d\n",
|
||||
task_pid_nr(common->thread_task));
|
||||
wake_up_process(common->thread_task);
|
||||
}
|
||||
|
||||
fsg->gadget = gadget;
|
||||
|
|
|
|||
|
|
@ -153,8 +153,6 @@ int fsg_common_create_luns(struct fsg_common *common, struct fsg_config *cfg);
|
|||
void fsg_common_set_inquiry_string(struct fsg_common *common, const char *vn,
|
||||
const char *pn);
|
||||
|
||||
int fsg_common_run_thread(struct fsg_common *common);
|
||||
|
||||
void fsg_config_from_params(struct fsg_config *cfg,
|
||||
const struct fsg_module_parameters *params,
|
||||
unsigned int fsg_num_buffers);
|
||||
|
|
|
|||
|
|
@ -133,10 +133,6 @@ static int acm_ms_do_config(struct usb_configuration *c)
|
|||
if (status < 0)
|
||||
goto put_msg;
|
||||
|
||||
status = fsg_common_run_thread(opts->common);
|
||||
if (status)
|
||||
goto remove_acm;
|
||||
|
||||
status = usb_add_function(c, f_msg);
|
||||
if (status)
|
||||
goto remove_acm;
|
||||
|
|
|
|||
|
|
@ -132,10 +132,6 @@ static int msg_do_config(struct usb_configuration *c)
|
|||
if (IS_ERR(f_msg))
|
||||
return PTR_ERR(f_msg);
|
||||
|
||||
ret = fsg_common_run_thread(opts->common);
|
||||
if (ret)
|
||||
goto put_func;
|
||||
|
||||
ret = usb_add_function(c, f_msg);
|
||||
if (ret)
|
||||
goto put_func;
|
||||
|
|
|
|||
|
|
@ -137,7 +137,6 @@ static struct usb_function *f_msg_rndis;
|
|||
|
||||
static int rndis_do_config(struct usb_configuration *c)
|
||||
{
|
||||
struct fsg_opts *fsg_opts;
|
||||
int ret;
|
||||
|
||||
if (gadget_is_otg(c->cdev->gadget)) {
|
||||
|
|
@ -169,11 +168,6 @@ static int rndis_do_config(struct usb_configuration *c)
|
|||
goto err_fsg;
|
||||
}
|
||||
|
||||
fsg_opts = fsg_opts_from_func_inst(fi_msg);
|
||||
ret = fsg_common_run_thread(fsg_opts->common);
|
||||
if (ret)
|
||||
goto err_run;
|
||||
|
||||
ret = usb_add_function(c, f_msg_rndis);
|
||||
if (ret)
|
||||
goto err_run;
|
||||
|
|
@ -225,7 +219,6 @@ static struct usb_function *f_msg_multi;
|
|||
|
||||
static int cdc_do_config(struct usb_configuration *c)
|
||||
{
|
||||
struct fsg_opts *fsg_opts;
|
||||
int ret;
|
||||
|
||||
if (gadget_is_otg(c->cdev->gadget)) {
|
||||
|
|
@ -258,11 +251,6 @@ static int cdc_do_config(struct usb_configuration *c)
|
|||
goto err_fsg;
|
||||
}
|
||||
|
||||
fsg_opts = fsg_opts_from_func_inst(fi_msg);
|
||||
ret = fsg_common_run_thread(fsg_opts->common);
|
||||
if (ret)
|
||||
goto err_run;
|
||||
|
||||
ret = usb_add_function(c, f_msg_multi);
|
||||
if (ret)
|
||||
goto err_run;
|
||||
|
|
|
|||
|
|
@ -152,7 +152,6 @@ static int nokia_bind_config(struct usb_configuration *c)
|
|||
struct usb_function *f_ecm;
|
||||
struct usb_function *f_obex2 = NULL;
|
||||
struct usb_function *f_msg;
|
||||
struct fsg_opts *fsg_opts;
|
||||
int status = 0;
|
||||
int obex1_stat = -1;
|
||||
int obex2_stat = -1;
|
||||
|
|
@ -222,12 +221,6 @@ static int nokia_bind_config(struct usb_configuration *c)
|
|||
goto err_ecm;
|
||||
}
|
||||
|
||||
fsg_opts = fsg_opts_from_func_inst(fi_msg);
|
||||
|
||||
status = fsg_common_run_thread(fsg_opts->common);
|
||||
if (status)
|
||||
goto err_msg;
|
||||
|
||||
status = usb_add_function(c, f_msg);
|
||||
if (status)
|
||||
goto err_msg;
|
||||
|
|
|
|||
|
|
@ -1726,10 +1726,7 @@ static int at91sam9261_udc_init(struct at91_udc *udc)
|
|||
|
||||
udc->matrix = syscon_regmap_lookup_by_phandle(udc->pdev->dev.of_node,
|
||||
"atmel,matrix");
|
||||
if (IS_ERR(udc->matrix))
|
||||
return PTR_ERR(udc->matrix);
|
||||
|
||||
return 0;
|
||||
return PTR_ERR_OR_ZERO(udc->matrix);
|
||||
}
|
||||
|
||||
static void at91sam9261_udc_pullup(struct at91_udc *udc, int is_on)
|
||||
|
|
|
|||
|
|
@ -325,11 +325,8 @@ struct pch_vbus_gpio_data {
|
|||
* @pdev: reference to the PCI device
|
||||
* @ep: array of endpoints
|
||||
* @lock: protects all state
|
||||
* @active: enabled the PCI device
|
||||
* @stall: stall requested
|
||||
* @prot_stall: protcol stall requested
|
||||
* @irq_registered: irq registered with system
|
||||
* @mem_region: device memory mapped
|
||||
* @registered: driver registered with system
|
||||
* @suspended: driver in suspended state
|
||||
* @connected: gadget driver associated
|
||||
|
|
@ -339,12 +336,8 @@ struct pch_vbus_gpio_data {
|
|||
* @data_requests: DMA pool for data requests
|
||||
* @stp_requests: DMA pool for setup requests
|
||||
* @dma_addr: DMA pool for received
|
||||
* @ep0out_buf: Buffer for DMA
|
||||
* @setup_data: Received setup data
|
||||
* @phys_addr: of device memory
|
||||
* @base_addr: for mapped device memory
|
||||
* @bar: Indicates which PCI BAR for USB regs
|
||||
* @irq: IRQ line for the device
|
||||
* @cfg_data: current cfg, intf, and alt in use
|
||||
* @vbus_gpio: GPIO informaton for detecting VBUS
|
||||
*/
|
||||
|
|
@ -354,11 +347,9 @@ struct pch_udc_dev {
|
|||
struct pci_dev *pdev;
|
||||
struct pch_udc_ep ep[PCH_UDC_EP_NUM];
|
||||
spinlock_t lock; /* protects all state */
|
||||
unsigned active:1,
|
||||
unsigned
|
||||
stall:1,
|
||||
prot_stall:1,
|
||||
irq_registered:1,
|
||||
mem_region:1,
|
||||
suspended:1,
|
||||
connected:1,
|
||||
vbus_session:1,
|
||||
|
|
@ -367,12 +358,8 @@ struct pch_udc_dev {
|
|||
struct pci_pool *data_requests;
|
||||
struct pci_pool *stp_requests;
|
||||
dma_addr_t dma_addr;
|
||||
void *ep0out_buf;
|
||||
struct usb_ctrlrequest setup_data;
|
||||
unsigned long phys_addr;
|
||||
void __iomem *base_addr;
|
||||
unsigned bar;
|
||||
unsigned irq;
|
||||
struct pch_udc_cfg_data cfg_data;
|
||||
struct pch_vbus_gpio_data vbus_gpio;
|
||||
};
|
||||
|
|
@ -380,8 +367,10 @@ struct pch_udc_dev {
|
|||
|
||||
#define PCH_UDC_PCI_BAR_QUARK_X1000 0
|
||||
#define PCH_UDC_PCI_BAR 1
|
||||
#define PCI_DEVICE_ID_INTEL_EG20T_UDC 0x8808
|
||||
|
||||
#define PCI_DEVICE_ID_INTEL_QUARK_X1000_UDC 0x0939
|
||||
#define PCI_DEVICE_ID_INTEL_EG20T_UDC 0x8808
|
||||
|
||||
#define PCI_VENDOR_ID_ROHM 0x10DB
|
||||
#define PCI_DEVICE_ID_ML7213_IOH_UDC 0x801D
|
||||
#define PCI_DEVICE_ID_ML7831_IOH_UDC 0x8808
|
||||
|
|
@ -1732,14 +1721,12 @@ static int pch_udc_pcd_ep_enable(struct usb_ep *usbep,
|
|||
static int pch_udc_pcd_ep_disable(struct usb_ep *usbep)
|
||||
{
|
||||
struct pch_udc_ep *ep;
|
||||
struct pch_udc_dev *dev;
|
||||
unsigned long iflags;
|
||||
|
||||
if (!usbep)
|
||||
return -EINVAL;
|
||||
|
||||
ep = container_of(usbep, struct pch_udc_ep, ep);
|
||||
dev = ep->dev;
|
||||
if ((usbep->name == ep0_string) || !ep->ep.desc)
|
||||
return -EINVAL;
|
||||
|
||||
|
|
@ -1770,12 +1757,10 @@ static struct usb_request *pch_udc_alloc_request(struct usb_ep *usbep,
|
|||
struct pch_udc_request *req;
|
||||
struct pch_udc_ep *ep;
|
||||
struct pch_udc_data_dma_desc *dma_desc;
|
||||
struct pch_udc_dev *dev;
|
||||
|
||||
if (!usbep)
|
||||
return NULL;
|
||||
ep = container_of(usbep, struct pch_udc_ep, ep);
|
||||
dev = ep->dev;
|
||||
req = kzalloc(sizeof *req, gfp);
|
||||
if (!req)
|
||||
return NULL;
|
||||
|
|
@ -1948,12 +1933,10 @@ static int pch_udc_pcd_dequeue(struct usb_ep *usbep,
|
|||
{
|
||||
struct pch_udc_ep *ep;
|
||||
struct pch_udc_request *req;
|
||||
struct pch_udc_dev *dev;
|
||||
unsigned long flags;
|
||||
int ret = -EINVAL;
|
||||
|
||||
ep = container_of(usbep, struct pch_udc_ep, ep);
|
||||
dev = ep->dev;
|
||||
if (!usbep || !usbreq || (!ep->ep.desc && ep->num))
|
||||
return ret;
|
||||
req = container_of(usbreq, struct pch_udc_request, req);
|
||||
|
|
@ -1985,14 +1968,12 @@ static int pch_udc_pcd_dequeue(struct usb_ep *usbep,
|
|||
static int pch_udc_pcd_set_halt(struct usb_ep *usbep, int halt)
|
||||
{
|
||||
struct pch_udc_ep *ep;
|
||||
struct pch_udc_dev *dev;
|
||||
unsigned long iflags;
|
||||
int ret;
|
||||
|
||||
if (!usbep)
|
||||
return -EINVAL;
|
||||
ep = container_of(usbep, struct pch_udc_ep, ep);
|
||||
dev = ep->dev;
|
||||
if (!ep->ep.desc && !ep->num)
|
||||
return -EINVAL;
|
||||
if (!ep->dev->driver || (ep->dev->gadget.speed == USB_SPEED_UNKNOWN))
|
||||
|
|
@ -2030,14 +2011,12 @@ static int pch_udc_pcd_set_halt(struct usb_ep *usbep, int halt)
|
|||
static int pch_udc_pcd_set_wedge(struct usb_ep *usbep)
|
||||
{
|
||||
struct pch_udc_ep *ep;
|
||||
struct pch_udc_dev *dev;
|
||||
unsigned long iflags;
|
||||
int ret;
|
||||
|
||||
if (!usbep)
|
||||
return -EINVAL;
|
||||
ep = container_of(usbep, struct pch_udc_ep, ep);
|
||||
dev = ep->dev;
|
||||
if (!ep->ep.desc && !ep->num)
|
||||
return -EINVAL;
|
||||
if (!ep->dev->driver || (ep->dev->gadget.speed == USB_SPEED_UNKNOWN))
|
||||
|
|
@ -2647,7 +2626,7 @@ static void pch_udc_svc_enum_interrupt(struct pch_udc_dev *dev)
|
|||
static void pch_udc_svc_intf_interrupt(struct pch_udc_dev *dev)
|
||||
{
|
||||
u32 reg, dev_stat = 0;
|
||||
int i, ret;
|
||||
int i;
|
||||
|
||||
dev_stat = pch_udc_read_device_status(dev);
|
||||
dev->cfg_data.cur_intf = (dev_stat & UDC_DEVSTS_INTF_MASK) >>
|
||||
|
|
@ -2676,7 +2655,7 @@ static void pch_udc_svc_intf_interrupt(struct pch_udc_dev *dev)
|
|||
}
|
||||
dev->stall = 0;
|
||||
spin_lock(&dev->lock);
|
||||
ret = dev->driver->setup(&dev->gadget, &dev->setup_data);
|
||||
dev->driver->setup(&dev->gadget, &dev->setup_data);
|
||||
spin_unlock(&dev->lock);
|
||||
}
|
||||
|
||||
|
|
@ -2687,7 +2666,7 @@ static void pch_udc_svc_intf_interrupt(struct pch_udc_dev *dev)
|
|||
*/
|
||||
static void pch_udc_svc_cfg_interrupt(struct pch_udc_dev *dev)
|
||||
{
|
||||
int i, ret;
|
||||
int i;
|
||||
u32 reg, dev_stat = 0;
|
||||
|
||||
dev_stat = pch_udc_read_device_status(dev);
|
||||
|
|
@ -2713,7 +2692,7 @@ static void pch_udc_svc_cfg_interrupt(struct pch_udc_dev *dev)
|
|||
|
||||
/* call gadget zero with setup data received */
|
||||
spin_lock(&dev->lock);
|
||||
ret = dev->driver->setup(&dev->gadget, &dev->setup_data);
|
||||
dev->driver->setup(&dev->gadget, &dev->setup_data);
|
||||
spin_unlock(&dev->lock);
|
||||
}
|
||||
|
||||
|
|
@ -2855,17 +2834,6 @@ static void pch_udc_setup_ep0(struct pch_udc_dev *dev)
|
|||
UDC_DEVINT_SI | UDC_DEVINT_SC);
|
||||
}
|
||||
|
||||
/**
|
||||
* gadget_release() - Free the gadget driver private data
|
||||
* @pdev reference to struct pci_dev
|
||||
*/
|
||||
static void gadget_release(struct device *pdev)
|
||||
{
|
||||
struct pch_udc_dev *dev = dev_get_drvdata(pdev);
|
||||
|
||||
kfree(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* pch_udc_pcd_reinit() - This API initializes the endpoint structures
|
||||
* @dev: Reference to the driver structure
|
||||
|
|
@ -2949,6 +2917,7 @@ static int init_dma_pools(struct pch_udc_dev *dev)
|
|||
{
|
||||
struct pch_udc_stp_dma_desc *td_stp;
|
||||
struct pch_udc_data_dma_desc *td_data;
|
||||
void *ep0out_buf;
|
||||
|
||||
/* DMA setup */
|
||||
dev->data_requests = pci_pool_create("data_requests", dev->pdev,
|
||||
|
|
@ -2991,10 +2960,11 @@ static int init_dma_pools(struct pch_udc_dev *dev)
|
|||
dev->ep[UDC_EP0IN_IDX].td_data = NULL;
|
||||
dev->ep[UDC_EP0IN_IDX].td_data_phys = 0;
|
||||
|
||||
dev->ep0out_buf = kzalloc(UDC_EP0OUT_BUFF_SIZE * 4, GFP_KERNEL);
|
||||
if (!dev->ep0out_buf)
|
||||
ep0out_buf = devm_kzalloc(&dev->pdev->dev, UDC_EP0OUT_BUFF_SIZE * 4,
|
||||
GFP_KERNEL);
|
||||
if (!ep0out_buf)
|
||||
return -ENOMEM;
|
||||
dev->dma_addr = dma_map_single(&dev->pdev->dev, dev->ep0out_buf,
|
||||
dev->dma_addr = dma_map_single(&dev->pdev->dev, ep0out_buf,
|
||||
UDC_EP0OUT_BUFF_SIZE * 4,
|
||||
DMA_FROM_DEVICE);
|
||||
return 0;
|
||||
|
|
@ -3078,129 +3048,80 @@ static void pch_udc_remove(struct pci_dev *pdev)
|
|||
if (dev->dma_addr)
|
||||
dma_unmap_single(&dev->pdev->dev, dev->dma_addr,
|
||||
UDC_EP0OUT_BUFF_SIZE * 4, DMA_FROM_DEVICE);
|
||||
kfree(dev->ep0out_buf);
|
||||
|
||||
pch_vbus_gpio_free(dev);
|
||||
|
||||
pch_udc_exit(dev);
|
||||
|
||||
if (dev->irq_registered)
|
||||
free_irq(pdev->irq, dev);
|
||||
if (dev->base_addr)
|
||||
iounmap(dev->base_addr);
|
||||
if (dev->mem_region)
|
||||
release_mem_region(dev->phys_addr,
|
||||
pci_resource_len(pdev, dev->bar));
|
||||
if (dev->active)
|
||||
pci_disable_device(pdev);
|
||||
kfree(dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int pch_udc_suspend(struct pci_dev *pdev, pm_message_t state)
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int pch_udc_suspend(struct device *d)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(d);
|
||||
struct pch_udc_dev *dev = pci_get_drvdata(pdev);
|
||||
|
||||
pch_udc_disable_interrupts(dev, UDC_DEVINT_MSK);
|
||||
pch_udc_disable_ep_interrupts(dev, UDC_EPINT_MSK_DISABLE_ALL);
|
||||
|
||||
pci_disable_device(pdev);
|
||||
pci_enable_wake(pdev, PCI_D3hot, 0);
|
||||
|
||||
if (pci_save_state(pdev)) {
|
||||
dev_err(&pdev->dev,
|
||||
"%s: could not save PCI config state\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
pci_set_power_state(pdev, pci_choose_state(pdev, state));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pch_udc_resume(struct pci_dev *pdev)
|
||||
static int pch_udc_resume(struct device *d)
|
||||
{
|
||||
int ret;
|
||||
|
||||
pci_set_power_state(pdev, PCI_D0);
|
||||
pci_restore_state(pdev);
|
||||
ret = pci_enable_device(pdev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "%s: pci_enable_device failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
pci_enable_wake(pdev, PCI_D3hot, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(pch_udc_pm, pch_udc_suspend, pch_udc_resume);
|
||||
#define PCH_UDC_PM_OPS (&pch_udc_pm)
|
||||
#else
|
||||
#define pch_udc_suspend NULL
|
||||
#define pch_udc_resume NULL
|
||||
#endif /* CONFIG_PM */
|
||||
#define PCH_UDC_PM_OPS NULL
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
static int pch_udc_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
unsigned long resource;
|
||||
unsigned long len;
|
||||
int bar;
|
||||
int retval;
|
||||
struct pch_udc_dev *dev;
|
||||
|
||||
/* init */
|
||||
dev = kzalloc(sizeof *dev, GFP_KERNEL);
|
||||
if (!dev) {
|
||||
pr_err("%s: no memory for device structure\n", __func__);
|
||||
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* pci setup */
|
||||
if (pci_enable_device(pdev) < 0) {
|
||||
kfree(dev);
|
||||
pr_err("%s: pci_enable_device failed\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
dev->active = 1;
|
||||
retval = pcim_enable_device(pdev);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
pci_set_drvdata(pdev, dev);
|
||||
|
||||
/* Determine BAR based on PCI ID */
|
||||
if (id->device == PCI_DEVICE_ID_INTEL_QUARK_X1000_UDC)
|
||||
dev->bar = PCH_UDC_PCI_BAR_QUARK_X1000;
|
||||
bar = PCH_UDC_PCI_BAR_QUARK_X1000;
|
||||
else
|
||||
dev->bar = PCH_UDC_PCI_BAR;
|
||||
bar = PCH_UDC_PCI_BAR;
|
||||
|
||||
/* PCI resource allocation */
|
||||
resource = pci_resource_start(pdev, dev->bar);
|
||||
len = pci_resource_len(pdev, dev->bar);
|
||||
retval = pcim_iomap_regions(pdev, 1 << bar, pci_name(pdev));
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (!request_mem_region(resource, len, KBUILD_MODNAME)) {
|
||||
dev_err(&pdev->dev, "%s: pci device used already\n", __func__);
|
||||
retval = -EBUSY;
|
||||
goto finished;
|
||||
}
|
||||
dev->phys_addr = resource;
|
||||
dev->mem_region = 1;
|
||||
dev->base_addr = pcim_iomap_table(pdev)[bar];
|
||||
|
||||
dev->base_addr = ioremap_nocache(resource, len);
|
||||
if (!dev->base_addr) {
|
||||
pr_err("%s: device memory cannot be mapped\n", __func__);
|
||||
retval = -ENOMEM;
|
||||
goto finished;
|
||||
}
|
||||
if (!pdev->irq) {
|
||||
dev_err(&pdev->dev, "%s: irq not set\n", __func__);
|
||||
retval = -ENODEV;
|
||||
goto finished;
|
||||
}
|
||||
/* initialize the hardware */
|
||||
if (pch_udc_pcd_init(dev)) {
|
||||
retval = -ENODEV;
|
||||
goto finished;
|
||||
}
|
||||
if (request_irq(pdev->irq, pch_udc_isr, IRQF_SHARED, KBUILD_MODNAME,
|
||||
dev)) {
|
||||
if (pch_udc_pcd_init(dev))
|
||||
return -ENODEV;
|
||||
|
||||
pci_enable_msi(pdev);
|
||||
|
||||
retval = devm_request_irq(&pdev->dev, pdev->irq, pch_udc_isr,
|
||||
IRQF_SHARED, KBUILD_MODNAME, dev);
|
||||
if (retval) {
|
||||
dev_err(&pdev->dev, "%s: request_irq(%d) fail\n", __func__,
|
||||
pdev->irq);
|
||||
retval = -ENODEV;
|
||||
goto finished;
|
||||
}
|
||||
dev->irq = pdev->irq;
|
||||
dev->irq_registered = 1;
|
||||
|
||||
pci_set_master(pdev);
|
||||
pci_try_set_mwi(pdev);
|
||||
|
|
@ -3219,8 +3140,7 @@ static int pch_udc_probe(struct pci_dev *pdev,
|
|||
|
||||
/* Put the device in disconnected state till a driver is bound */
|
||||
pch_udc_set_disconnect(dev);
|
||||
retval = usb_add_gadget_udc_release(&pdev->dev, &dev->gadget,
|
||||
gadget_release);
|
||||
retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
|
||||
if (retval)
|
||||
goto finished;
|
||||
return 0;
|
||||
|
|
@ -3262,9 +3182,10 @@ static struct pci_driver pch_udc_driver = {
|
|||
.id_table = pch_udc_pcidev_id,
|
||||
.probe = pch_udc_probe,
|
||||
.remove = pch_udc_remove,
|
||||
.suspend = pch_udc_suspend,
|
||||
.resume = pch_udc_resume,
|
||||
.shutdown = pch_udc_shutdown,
|
||||
.driver = {
|
||||
.pm = PCH_UDC_PM_OPS,
|
||||
},
|
||||
};
|
||||
|
||||
module_pci_driver(pch_udc_driver);
|
||||
|
|
|
|||
|
|
@ -296,7 +296,7 @@ static void r8a66597_change_curpipe(struct r8a66597 *r8a66597, u16 pipenum,
|
|||
} while ((tmp & mask) != loop);
|
||||
}
|
||||
|
||||
static inline void pipe_change(struct r8a66597 *r8a66597, u16 pipenum)
|
||||
static void pipe_change(struct r8a66597 *r8a66597, u16 pipenum)
|
||||
{
|
||||
struct r8a66597_ep *ep = r8a66597->pipenum2ep[pipenum];
|
||||
|
||||
|
|
|
|||
|
|
@ -61,11 +61,9 @@ static int udc_bind_to_driver(struct usb_udc *udc,
|
|||
|
||||
#ifdef CONFIG_HAS_DMA
|
||||
|
||||
int usb_gadget_map_request(struct usb_gadget *gadget,
|
||||
int usb_gadget_map_request_by_dev(struct device *dev,
|
||||
struct usb_request *req, int is_in)
|
||||
{
|
||||
struct device *dev = gadget->dev.parent;
|
||||
|
||||
if (req->length == 0)
|
||||
return 0;
|
||||
|
||||
|
|
@ -75,7 +73,7 @@ int usb_gadget_map_request(struct usb_gadget *gadget,
|
|||
mapped = dma_map_sg(dev, req->sg, req->num_sgs,
|
||||
is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
|
||||
if (mapped == 0) {
|
||||
dev_err(&gadget->dev, "failed to map SGs\n");
|
||||
dev_err(dev, "failed to map SGs\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
|
|
@ -92,24 +90,38 @@ int usb_gadget_map_request(struct usb_gadget *gadget,
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_gadget_map_request_by_dev);
|
||||
|
||||
int usb_gadget_map_request(struct usb_gadget *gadget,
|
||||
struct usb_request *req, int is_in)
|
||||
{
|
||||
return usb_gadget_map_request_by_dev(gadget->dev.parent, req, is_in);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_gadget_map_request);
|
||||
|
||||
void usb_gadget_unmap_request(struct usb_gadget *gadget,
|
||||
void usb_gadget_unmap_request_by_dev(struct device *dev,
|
||||
struct usb_request *req, int is_in)
|
||||
{
|
||||
if (req->length == 0)
|
||||
return;
|
||||
|
||||
if (req->num_mapped_sgs) {
|
||||
dma_unmap_sg(gadget->dev.parent, req->sg, req->num_mapped_sgs,
|
||||
dma_unmap_sg(dev, req->sg, req->num_mapped_sgs,
|
||||
is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
|
||||
|
||||
req->num_mapped_sgs = 0;
|
||||
} else {
|
||||
dma_unmap_single(gadget->dev.parent, req->dma, req->length,
|
||||
dma_unmap_single(dev, req->dma, req->length,
|
||||
is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_gadget_unmap_request_by_dev);
|
||||
|
||||
void usb_gadget_unmap_request(struct usb_gadget *gadget,
|
||||
struct usb_request *req, int is_in)
|
||||
{
|
||||
usb_gadget_unmap_request_by_dev(gadget->dev.parent, req, is_in);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_gadget_unmap_request);
|
||||
|
||||
#endif /* CONFIG_HAS_DMA */
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ config USB_XHCI_PCI
|
|||
|
||||
config USB_XHCI_PLATFORM
|
||||
tristate "Generic xHCI driver for a platform device"
|
||||
select USB_XHCI_RCAR if ARCH_RENESAS
|
||||
---help---
|
||||
Adds an xHCI host driver for a generic platform device, which
|
||||
provides a memory space and an irq.
|
||||
|
|
@ -63,7 +64,7 @@ config USB_XHCI_MVEBU
|
|||
|
||||
config USB_XHCI_RCAR
|
||||
tristate "xHCI support for Renesas R-Car SoCs"
|
||||
select USB_XHCI_PLATFORM
|
||||
depends on USB_XHCI_PLATFORM
|
||||
depends on ARCH_RENESAS || COMPILE_TEST
|
||||
---help---
|
||||
Say 'Y' to enable the support for the xHCI host controller
|
||||
|
|
|
|||
|
|
@ -352,10 +352,8 @@ static int bcma_hcd_probe(struct bcma_device *core)
|
|||
usb_dev->core = core;
|
||||
|
||||
if (core->dev.of_node)
|
||||
usb_dev->gpio_desc = devm_get_gpiod_from_child(&core->dev, "vcc",
|
||||
&core->dev.of_node->fwnode);
|
||||
if (!IS_ERR_OR_NULL(usb_dev->gpio_desc))
|
||||
gpiod_direction_output(usb_dev->gpio_desc, 1);
|
||||
usb_dev->gpio_desc = devm_gpiod_get(&core->dev, "vcc",
|
||||
GPIOD_OUT_HIGH);
|
||||
|
||||
switch (core->id.id) {
|
||||
case BCMA_CORE_USB20_HOST:
|
||||
|
|
|
|||
|
|
@ -52,13 +52,6 @@ static void dbg_hcs_params(struct ehci_hcd *ehci, char *label)
|
|||
ehci_dbg(ehci, "%s portroute %s\n", label, buf);
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
static inline void dbg_hcs_params(struct ehci_hcd *ehci, char *label) {}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DYNAMIC_DEBUG
|
||||
|
||||
/*
|
||||
* check the values in the HCCPARAMS register
|
||||
|
|
@ -92,13 +85,6 @@ static void dbg_hcc_params(struct ehci_hcd *ehci, char *label)
|
|||
" 32 periodic list" : "");
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
static inline void dbg_hcc_params(struct ehci_hcd *ehci, char *label) {}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DYNAMIC_DEBUG
|
||||
|
||||
static void __maybe_unused
|
||||
dbg_qtd(const char *label, struct ehci_hcd *ehci, struct ehci_qtd *qtd)
|
||||
|
|
@ -281,37 +267,6 @@ dbg_port_buf(char *buf, unsigned len, const char *label, int port, u32 status)
|
|||
(status & PORT_CONNECT) ? " CONNECT" : "");
|
||||
}
|
||||
|
||||
#else
|
||||
static inline void __maybe_unused
|
||||
dbg_qh(char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
|
||||
{}
|
||||
|
||||
static inline int __maybe_unused
|
||||
dbg_status_buf(char *buf, unsigned len, const char *label, u32 status)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int __maybe_unused
|
||||
dbg_command_buf(char *buf, unsigned len, const char *label, u32 command)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int __maybe_unused
|
||||
dbg_intr_buf(char *buf, unsigned len, const char *label, u32 enable)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int __maybe_unused
|
||||
dbg_port_buf(char *buf, unsigned len, const char *label, int port, u32 status)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_DYNAMIC_DEBUG */
|
||||
|
||||
static inline void
|
||||
dbg_status(struct ehci_hcd *ehci, const char *label, u32 status)
|
||||
{
|
||||
|
|
@ -341,13 +296,6 @@ dbg_port(struct ehci_hcd *ehci, const char *label, int port, u32 status)
|
|||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef CONFIG_DYNAMIC_DEBUG
|
||||
|
||||
static inline void create_debug_files(struct ehci_hcd *bus) { }
|
||||
static inline void remove_debug_files(struct ehci_hcd *bus) { }
|
||||
|
||||
#else
|
||||
|
||||
/* troubleshooting help: expose state in debugfs */
|
||||
|
||||
static int debug_async_open(struct inode *, struct file *);
|
||||
|
|
@ -1120,4 +1068,38 @@ static inline void remove_debug_files(struct ehci_hcd *ehci)
|
|||
debugfs_remove_recursive(ehci->debug_dir);
|
||||
}
|
||||
|
||||
#else /* CONFIG_DYNAMIC_DEBUG */
|
||||
|
||||
static inline void dbg_hcs_params(struct ehci_hcd *ehci, char *label) { }
|
||||
static inline void dbg_hcc_params(struct ehci_hcd *ehci, char *label) { }
|
||||
|
||||
static inline void __maybe_unused dbg_qh(const char *label,
|
||||
struct ehci_hcd *ehci, struct ehci_qh *qh) { }
|
||||
|
||||
static inline int __maybe_unused dbg_status_buf(const char *buf,
|
||||
unsigned int len, const char *label, u32 status)
|
||||
{ return 0; }
|
||||
|
||||
static inline int __maybe_unused dbg_command_buf(const char *buf,
|
||||
unsigned int len, const char *label, u32 command)
|
||||
{ return 0; }
|
||||
|
||||
static inline int __maybe_unused dbg_intr_buf(const char *buf,
|
||||
unsigned int len, const char *label, u32 enable)
|
||||
{ return 0; }
|
||||
|
||||
static inline int __maybe_unused dbg_port_buf(char *buf,
|
||||
unsigned int len, const char *label, int port, u32 status)
|
||||
{ return 0; }
|
||||
|
||||
static inline void dbg_status(struct ehci_hcd *ehci, const char *label,
|
||||
u32 status) { }
|
||||
static inline void dbg_cmd(struct ehci_hcd *ehci, const char *label,
|
||||
u32 command) { }
|
||||
static inline void dbg_port(struct ehci_hcd *ehci, const char *label,
|
||||
int port, u32 status) { }
|
||||
|
||||
static inline void create_debug_files(struct ehci_hcd *bus) { }
|
||||
static inline void remove_debug_files(struct ehci_hcd *bus) { }
|
||||
|
||||
#endif /* CONFIG_DYNAMIC_DEBUG */
|
||||
|
|
|
|||
|
|
@ -321,7 +321,7 @@ static struct platform_driver exynos_ehci_driver = {
|
|||
.of_match_table = of_match_ptr(exynos_ehci_match),
|
||||
}
|
||||
};
|
||||
static const struct ehci_driver_overrides exynos_overrides __initdata = {
|
||||
static const struct ehci_driver_overrides exynos_overrides __initconst = {
|
||||
.extra_priv_size = sizeof(struct exynos_ehci_hcd),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -229,7 +229,7 @@ static struct platform_driver ehci_msm_driver = {
|
|||
},
|
||||
};
|
||||
|
||||
static const struct ehci_driver_overrides msm_overrides __initdata = {
|
||||
static const struct ehci_driver_overrides msm_overrides __initconst = {
|
||||
.reset = ehci_msm_reset,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ static inline u32 ehci_read(void __iomem *base, u32 reg)
|
|||
|
||||
static struct hc_driver __read_mostly ehci_omap_hc_driver;
|
||||
|
||||
static const struct ehci_driver_overrides ehci_omap_overrides __initdata = {
|
||||
static const struct ehci_driver_overrides ehci_omap_overrides __initconst = {
|
||||
.extra_priv_size = sizeof(struct omap_hcd),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@ static struct platform_driver spear_ehci_hcd_driver = {
|
|||
}
|
||||
};
|
||||
|
||||
static const struct ehci_driver_overrides spear_overrides __initdata = {
|
||||
static const struct ehci_driver_overrides spear_overrides __initconst = {
|
||||
.extra_priv_size = sizeof(struct spear_ehci),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -288,7 +288,7 @@ static int scan_ed_list(struct fhci_usb *usb,
|
|||
list_for_each_entry(ed, list, node) {
|
||||
td = ed->td_head;
|
||||
|
||||
if (!td || (td && td->status == USB_TD_INPROGRESS))
|
||||
if (!td || td->status == USB_TD_INPROGRESS)
|
||||
continue;
|
||||
|
||||
if (ed->state != FHCI_ED_OPER) {
|
||||
|
|
|
|||
|
|
@ -4795,14 +4795,8 @@ static DEVICE_ATTR(uframe_periodic_max, 0644, show_uframe_periodic_max,
|
|||
static inline int create_sysfs_files(struct fotg210_hcd *fotg210)
|
||||
{
|
||||
struct device *controller = fotg210_to_hcd(fotg210)->self.controller;
|
||||
int i = 0;
|
||||
|
||||
if (i)
|
||||
goto out;
|
||||
|
||||
i = device_create_file(controller, &dev_attr_uframe_periodic_max);
|
||||
out:
|
||||
return i;
|
||||
return device_create_file(controller, &dev_attr_uframe_periodic_max);
|
||||
}
|
||||
|
||||
static inline void remove_sysfs_files(struct fotg210_hcd *fotg210)
|
||||
|
|
|
|||
|
|
@ -257,14 +257,14 @@ static int whc_probe(struct umc_dev *umc)
|
|||
|
||||
ret = whc_init(whc);
|
||||
if (ret)
|
||||
goto error;
|
||||
goto error_whc_init;
|
||||
|
||||
wusbhc->dev = dev;
|
||||
wusbhc->uwb_rc = uwb_rc_get_by_grandpa(umc->dev.parent);
|
||||
if (!wusbhc->uwb_rc) {
|
||||
ret = -ENODEV;
|
||||
dev_err(dev, "cannot get radio controller\n");
|
||||
goto error;
|
||||
goto error_uwb_rc;
|
||||
}
|
||||
|
||||
if (whc->n_devices > USB_MAXCHILDREN) {
|
||||
|
|
@ -311,8 +311,9 @@ error_usb_add_hcd:
|
|||
wusbhc_destroy(wusbhc);
|
||||
error_wusbhc_create:
|
||||
uwb_rc_put(wusbhc->uwb_rc);
|
||||
error:
|
||||
error_uwb_rc:
|
||||
whc_clean_up(whc);
|
||||
error_whc_init:
|
||||
usb_put_hcd(usb_hcd);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -314,7 +314,7 @@ void qset_free_std(struct whc *whc, struct whc_std *std)
|
|||
kfree(std->bounce_buf);
|
||||
}
|
||||
if (std->pl_virt) {
|
||||
if (std->dma_addr)
|
||||
if (!dma_mapping_error(whc->wusbhc.dev, std->dma_addr))
|
||||
dma_unmap_single(whc->wusbhc.dev, std->dma_addr,
|
||||
std->num_pointers * sizeof(struct whc_page_list_entry),
|
||||
DMA_TO_DEVICE);
|
||||
|
|
@ -535,9 +535,11 @@ static int qset_add_urb_sg(struct whc *whc, struct whc_qset *qset, struct urb *u
|
|||
list_for_each_entry(std, &qset->stds, list_node) {
|
||||
if (std->ntds_remaining == -1) {
|
||||
pl_len = std->num_pointers * sizeof(struct whc_page_list_entry);
|
||||
std->ntds_remaining = ntds--;
|
||||
std->dma_addr = dma_map_single(whc->wusbhc.dev, std->pl_virt,
|
||||
pl_len, DMA_TO_DEVICE);
|
||||
if (dma_mapping_error(whc->wusbhc.dev, std->dma_addr))
|
||||
return -EFAULT;
|
||||
std->ntds_remaining = ntds--;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
|
@ -618,6 +620,8 @@ static int qset_add_urb_sg_linearize(struct whc *whc, struct whc_qset *qset,
|
|||
|
||||
std->dma_addr = dma_map_single(&whc->umc->dev, std->bounce_buf, std->len,
|
||||
is_out ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
|
||||
if (dma_mapping_error(&whc->umc->dev, std->dma_addr))
|
||||
return -EFAULT;
|
||||
|
||||
if (qset_fill_page_list(whc, std, mem_flags) < 0)
|
||||
return -ENOMEM;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@
|
|||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
#include "xhci-mvebu.h"
|
||||
|
||||
#define USB3_MAX_WINDOWS 4
|
||||
|
|
@ -41,8 +44,10 @@ static void xhci_mvebu_mbus_config(void __iomem *base,
|
|||
}
|
||||
}
|
||||
|
||||
int xhci_mvebu_mbus_init_quirk(struct platform_device *pdev)
|
||||
int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd)
|
||||
{
|
||||
struct device *dev = hcd->self.controller;
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct resource *res;
|
||||
void __iomem *base;
|
||||
const struct mbus_dram_target_info *dram;
|
||||
|
|
|
|||
|
|
@ -10,10 +10,13 @@
|
|||
|
||||
#ifndef __LINUX_XHCI_MVEBU_H
|
||||
#define __LINUX_XHCI_MVEBU_H
|
||||
|
||||
struct usb_hcd;
|
||||
|
||||
#if IS_ENABLED(CONFIG_USB_XHCI_MVEBU)
|
||||
int xhci_mvebu_mbus_init_quirk(struct platform_device *pdev);
|
||||
int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd);
|
||||
#else
|
||||
static inline int xhci_mvebu_mbus_init_quirk(struct platform_device *pdev)
|
||||
static inline int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,27 +37,32 @@ static const struct xhci_driver_overrides xhci_plat_overrides __initconst = {
|
|||
.start = xhci_plat_start,
|
||||
};
|
||||
|
||||
static void xhci_priv_plat_start(struct usb_hcd *hcd)
|
||||
{
|
||||
struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
|
||||
|
||||
if (priv->plat_start)
|
||||
priv->plat_start(hcd);
|
||||
}
|
||||
|
||||
static int xhci_priv_init_quirk(struct usb_hcd *hcd)
|
||||
{
|
||||
struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
|
||||
|
||||
if (!priv->init_quirk)
|
||||
return 0;
|
||||
|
||||
return priv->init_quirk(hcd);
|
||||
}
|
||||
|
||||
static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci)
|
||||
{
|
||||
struct usb_hcd *hcd = xhci_to_hcd(xhci);
|
||||
|
||||
/*
|
||||
* As of now platform drivers don't provide MSI support so we ensure
|
||||
* here that the generic code does not try to make a pci_dev from our
|
||||
* dev struct in order to setup MSI
|
||||
*/
|
||||
xhci->quirks |= XHCI_PLAT;
|
||||
|
||||
/*
|
||||
* On R-Car Gen2 and Gen3, the AC64 bit (bit 0) of HCCPARAMS1 is set
|
||||
* to 1. However, these SoCs don't support 64-bit address memory
|
||||
* pointers. So, this driver clears the AC64 bit of xhci->hcc_params
|
||||
* to call dma_set_coherent_mask(dev, DMA_BIT_MASK(32)) in
|
||||
* xhci_gen_setup().
|
||||
*/
|
||||
if (xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_RENESAS_RCAR_GEN2) ||
|
||||
xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_RENESAS_RCAR_GEN3))
|
||||
xhci->quirks |= XHCI_NO_64BIT_SUPPORT;
|
||||
}
|
||||
|
||||
/* called during probe() after chip reset completes */
|
||||
|
|
@ -65,38 +70,35 @@ static int xhci_plat_setup(struct usb_hcd *hcd)
|
|||
{
|
||||
int ret;
|
||||
|
||||
if (xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_RENESAS_RCAR_GEN2) ||
|
||||
xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_RENESAS_RCAR_GEN3)) {
|
||||
ret = xhci_rcar_init_quirk(hcd);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = xhci_priv_init_quirk(hcd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return xhci_gen_setup(hcd, xhci_plat_quirks);
|
||||
}
|
||||
|
||||
static int xhci_plat_start(struct usb_hcd *hcd)
|
||||
{
|
||||
if (xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_RENESAS_RCAR_GEN2) ||
|
||||
xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_RENESAS_RCAR_GEN3))
|
||||
xhci_rcar_start(hcd);
|
||||
|
||||
xhci_priv_plat_start(hcd);
|
||||
return xhci_run(hcd);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct xhci_plat_priv xhci_plat_marvell_armada = {
|
||||
.type = XHCI_PLAT_TYPE_MARVELL_ARMADA,
|
||||
.init_quirk = xhci_mvebu_mbus_init_quirk,
|
||||
};
|
||||
|
||||
static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen2 = {
|
||||
.type = XHCI_PLAT_TYPE_RENESAS_RCAR_GEN2,
|
||||
.firmware_name = XHCI_RCAR_FIRMWARE_NAME_V1,
|
||||
.init_quirk = xhci_rcar_init_quirk,
|
||||
.plat_start = xhci_rcar_start,
|
||||
};
|
||||
|
||||
static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen3 = {
|
||||
.type = XHCI_PLAT_TYPE_RENESAS_RCAR_GEN3,
|
||||
.firmware_name = XHCI_RCAR_FIRMWARE_NAME_V2,
|
||||
.init_quirk = xhci_rcar_init_quirk,
|
||||
.plat_start = xhci_rcar_start,
|
||||
};
|
||||
|
||||
static const struct of_device_id usb_xhci_of_match[] = {
|
||||
|
|
@ -207,12 +209,6 @@ static int xhci_plat_probe(struct platform_device *pdev)
|
|||
*priv = *priv_match;
|
||||
}
|
||||
|
||||
if (xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_MARVELL_ARMADA)) {
|
||||
ret = xhci_mvebu_mbus_init_quirk(pdev);
|
||||
if (ret)
|
||||
goto disable_clk;
|
||||
}
|
||||
|
||||
device_wakeup_enable(hcd->self.controller);
|
||||
|
||||
xhci->clk = clk;
|
||||
|
|
|
|||
|
|
@ -13,27 +13,11 @@
|
|||
|
||||
#include "xhci.h" /* for hcd_to_xhci() */
|
||||
|
||||
enum xhci_plat_type {
|
||||
XHCI_PLAT_TYPE_MARVELL_ARMADA = 1,
|
||||
XHCI_PLAT_TYPE_RENESAS_RCAR_GEN2,
|
||||
XHCI_PLAT_TYPE_RENESAS_RCAR_GEN3,
|
||||
};
|
||||
|
||||
struct xhci_plat_priv {
|
||||
enum xhci_plat_type type;
|
||||
const char *firmware_name;
|
||||
void (*plat_start)(struct usb_hcd *);
|
||||
int (*init_quirk)(struct usb_hcd *);
|
||||
};
|
||||
|
||||
#define hcd_to_xhci_priv(h) ((struct xhci_plat_priv *)hcd_to_xhci(h)->priv)
|
||||
|
||||
static inline bool xhci_plat_type_is(struct usb_hcd *hcd,
|
||||
enum xhci_plat_type type)
|
||||
{
|
||||
struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
|
||||
|
||||
if (priv && priv->type == type)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
#endif /* _XHCI_PLAT_H */
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <linux/firmware.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/usb/phy.h>
|
||||
|
||||
#include "xhci.h"
|
||||
|
|
@ -76,6 +77,24 @@ static void xhci_rcar_start_gen2(struct usb_hcd *hcd)
|
|||
writel(RCAR_USB3_TX_POL_VAL, hcd->regs + RCAR_USB3_TX_POL);
|
||||
}
|
||||
|
||||
static int xhci_rcar_is_gen2(struct device *dev)
|
||||
{
|
||||
struct device_node *node = dev->of_node;
|
||||
|
||||
return of_device_is_compatible(node, "renesas,xhci-r8a7790") ||
|
||||
of_device_is_compatible(node, "renesas,xhci-r8a7791") ||
|
||||
of_device_is_compatible(node, "renesas,xhci-r8a7793") ||
|
||||
of_device_is_compatible(node, "renensas,rcar-gen2-xhci");
|
||||
}
|
||||
|
||||
static int xhci_rcar_is_gen3(struct device *dev)
|
||||
{
|
||||
struct device_node *node = dev->of_node;
|
||||
|
||||
return of_device_is_compatible(node, "renesas,xhci-r8a7795") ||
|
||||
of_device_is_compatible(node, "renesas,rcar-gen3-xhci");
|
||||
}
|
||||
|
||||
void xhci_rcar_start(struct usb_hcd *hcd)
|
||||
{
|
||||
u32 temp;
|
||||
|
|
@ -85,7 +104,7 @@ void xhci_rcar_start(struct usb_hcd *hcd)
|
|||
temp = readl(hcd->regs + RCAR_USB3_INT_ENA);
|
||||
temp |= RCAR_USB3_INT_ENA_VAL;
|
||||
writel(temp, hcd->regs + RCAR_USB3_INT_ENA);
|
||||
if (xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_RENESAS_RCAR_GEN2))
|
||||
if (xhci_rcar_is_gen2(hcd->self.controller))
|
||||
xhci_rcar_start_gen2(hcd);
|
||||
}
|
||||
}
|
||||
|
|
@ -156,9 +175,22 @@ static int xhci_rcar_download_firmware(struct usb_hcd *hcd)
|
|||
/* This function needs to initialize a "phy" of usb before */
|
||||
int xhci_rcar_init_quirk(struct usb_hcd *hcd)
|
||||
{
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
|
||||
/* If hcd->regs is NULL, we don't just call the following function */
|
||||
if (!hcd->regs)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* On R-Car Gen2 and Gen3, the AC64 bit (bit 0) of HCCPARAMS1 is set
|
||||
* to 1. However, these SoCs don't support 64-bit address memory
|
||||
* pointers. So, this driver clears the AC64 bit of xhci->hcc_params
|
||||
* to call dma_set_coherent_mask(dev, DMA_BIT_MASK(32)) in
|
||||
* xhci_gen_setup().
|
||||
*/
|
||||
if (xhci_rcar_is_gen2(hcd->self.controller) ||
|
||||
xhci_rcar_is_gen3(hcd->self.controller))
|
||||
xhci->quirks |= XHCI_NO_64BIT_SUPPORT;
|
||||
|
||||
return xhci_rcar_download_firmware(hcd);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -373,7 +373,11 @@ static void ring_doorbell_for_active_rings(struct xhci_hcd *xhci,
|
|||
}
|
||||
}
|
||||
|
||||
static struct xhci_ring *xhci_triad_to_transfer_ring(struct xhci_hcd *xhci,
|
||||
/* Get the right ring for the given slot_id, ep_index and stream_id.
|
||||
* If the endpoint supports streams, boundary check the URB's stream ID.
|
||||
* If the endpoint doesn't support streams, return the singular endpoint ring.
|
||||
*/
|
||||
struct xhci_ring *xhci_triad_to_transfer_ring(struct xhci_hcd *xhci,
|
||||
unsigned int slot_id, unsigned int ep_index,
|
||||
unsigned int stream_id)
|
||||
{
|
||||
|
|
@ -405,17 +409,6 @@ static struct xhci_ring *xhci_triad_to_transfer_ring(struct xhci_hcd *xhci,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* Get the right ring for the given URB.
|
||||
* If the endpoint supports streams, boundary check the URB's stream ID.
|
||||
* If the endpoint doesn't support streams, return the singular endpoint ring.
|
||||
*/
|
||||
static struct xhci_ring *xhci_urb_to_transfer_ring(struct xhci_hcd *xhci,
|
||||
struct urb *urb)
|
||||
{
|
||||
return xhci_triad_to_transfer_ring(xhci, urb->dev->slot_id,
|
||||
xhci_get_endpoint_index(&urb->ep->desc), urb->stream_id);
|
||||
}
|
||||
|
||||
/*
|
||||
* Move the xHC's endpoint ring dequeue pointer past cur_td.
|
||||
* Record the new state of the xHC's endpoint ring dequeue segment,
|
||||
|
|
@ -1768,7 +1761,7 @@ static int xhci_requires_manual_halt_cleanup(struct xhci_hcd *xhci,
|
|||
if (trb_comp_code == COMP_TX_ERR ||
|
||||
trb_comp_code == COMP_BABBLE ||
|
||||
trb_comp_code == COMP_SPLIT_ERR)
|
||||
/* The 0.96 spec says a babbling control endpoint
|
||||
/* The 0.95 spec says a babbling control endpoint
|
||||
* is not halted. The 0.96 spec says it is. Some HW
|
||||
* claims to be 0.95 compliant, but it halts the control
|
||||
* endpoint anyway. Check if a babble halted the
|
||||
|
|
@ -2938,46 +2931,55 @@ static int prepare_transfer(struct xhci_hcd *xhci,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int count_sg_trbs_needed(struct xhci_hcd *xhci, struct urb *urb)
|
||||
static unsigned int count_trbs(u64 addr, u64 len)
|
||||
{
|
||||
int num_sgs, num_trbs, running_total, temp, i;
|
||||
struct scatterlist *sg;
|
||||
unsigned int num_trbs;
|
||||
|
||||
sg = NULL;
|
||||
num_sgs = urb->num_mapped_sgs;
|
||||
temp = urb->transfer_buffer_length;
|
||||
num_trbs = DIV_ROUND_UP(len + (addr & (TRB_MAX_BUFF_SIZE - 1)),
|
||||
TRB_MAX_BUFF_SIZE);
|
||||
if (num_trbs == 0)
|
||||
num_trbs++;
|
||||
|
||||
num_trbs = 0;
|
||||
for_each_sg(urb->sg, sg, num_sgs, i) {
|
||||
unsigned int len = sg_dma_len(sg);
|
||||
|
||||
/* Scatter gather list entries may cross 64KB boundaries */
|
||||
running_total = TRB_MAX_BUFF_SIZE -
|
||||
(sg_dma_address(sg) & (TRB_MAX_BUFF_SIZE - 1));
|
||||
running_total &= TRB_MAX_BUFF_SIZE - 1;
|
||||
if (running_total != 0)
|
||||
num_trbs++;
|
||||
|
||||
/* How many more 64KB chunks to transfer, how many more TRBs? */
|
||||
while (running_total < sg_dma_len(sg) && running_total < temp) {
|
||||
num_trbs++;
|
||||
running_total += TRB_MAX_BUFF_SIZE;
|
||||
}
|
||||
len = min_t(int, len, temp);
|
||||
temp -= len;
|
||||
if (temp == 0)
|
||||
break;
|
||||
}
|
||||
return num_trbs;
|
||||
}
|
||||
|
||||
static void check_trb_math(struct urb *urb, int num_trbs, int running_total)
|
||||
static inline unsigned int count_trbs_needed(struct urb *urb)
|
||||
{
|
||||
if (num_trbs != 0)
|
||||
dev_err(&urb->dev->dev, "%s - ep %#x - Miscalculated number of "
|
||||
"TRBs, %d left\n", __func__,
|
||||
urb->ep->desc.bEndpointAddress, num_trbs);
|
||||
if (running_total != urb->transfer_buffer_length)
|
||||
return count_trbs(urb->transfer_dma, urb->transfer_buffer_length);
|
||||
}
|
||||
|
||||
static unsigned int count_sg_trbs_needed(struct urb *urb)
|
||||
{
|
||||
struct scatterlist *sg;
|
||||
unsigned int i, len, full_len, num_trbs = 0;
|
||||
|
||||
full_len = urb->transfer_buffer_length;
|
||||
|
||||
for_each_sg(urb->sg, sg, urb->num_mapped_sgs, i) {
|
||||
len = sg_dma_len(sg);
|
||||
num_trbs += count_trbs(sg_dma_address(sg), len);
|
||||
len = min_t(unsigned int, len, full_len);
|
||||
full_len -= len;
|
||||
if (full_len == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return num_trbs;
|
||||
}
|
||||
|
||||
static unsigned int count_isoc_trbs_needed(struct urb *urb, int i)
|
||||
{
|
||||
u64 addr, len;
|
||||
|
||||
addr = (u64) (urb->transfer_dma + urb->iso_frame_desc[i].offset);
|
||||
len = urb->iso_frame_desc[i].length;
|
||||
|
||||
return count_trbs(addr, len);
|
||||
}
|
||||
|
||||
static void check_trb_math(struct urb *urb, int running_total)
|
||||
{
|
||||
if (unlikely(running_total != urb->transfer_buffer_length))
|
||||
dev_err(&urb->dev->dev, "%s - ep %#x - Miscalculated tx length, "
|
||||
"queued %#x (%d), asked for %#x (%d)\n",
|
||||
__func__,
|
||||
|
|
@ -3003,26 +3005,20 @@ static void giveback_first_trb(struct xhci_hcd *xhci, int slot_id,
|
|||
xhci_ring_ep_doorbell(xhci, slot_id, ep_index, stream_id);
|
||||
}
|
||||
|
||||
/*
|
||||
* xHCI uses normal TRBs for both bulk and interrupt. When the interrupt
|
||||
* endpoint is to be serviced, the xHC will consume (at most) one TD. A TD
|
||||
* (comprised of sg list entries) can take several service intervals to
|
||||
* transmit.
|
||||
*/
|
||||
int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
||||
struct urb *urb, int slot_id, unsigned int ep_index)
|
||||
static void check_interval(struct xhci_hcd *xhci, struct urb *urb,
|
||||
struct xhci_ep_ctx *ep_ctx)
|
||||
{
|
||||
struct xhci_ep_ctx *ep_ctx = xhci_get_ep_ctx(xhci,
|
||||
xhci->devs[slot_id]->out_ctx, ep_index);
|
||||
int xhci_interval;
|
||||
int ep_interval;
|
||||
|
||||
xhci_interval = EP_INTERVAL_TO_UFRAMES(le32_to_cpu(ep_ctx->ep_info));
|
||||
ep_interval = urb->interval;
|
||||
|
||||
/* Convert to microframes */
|
||||
if (urb->dev->speed == USB_SPEED_LOW ||
|
||||
urb->dev->speed == USB_SPEED_FULL)
|
||||
ep_interval *= 8;
|
||||
|
||||
/* FIXME change this to a warning and a suggestion to use the new API
|
||||
* to set the polling interval (once the API is added).
|
||||
*/
|
||||
|
|
@ -3037,6 +3033,22 @@ int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
|||
urb->dev->speed == USB_SPEED_FULL)
|
||||
urb->interval /= 8;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* xHCI uses normal TRBs for both bulk and interrupt. When the interrupt
|
||||
* endpoint is to be serviced, the xHC will consume (at most) one TD. A TD
|
||||
* (comprised of sg list entries) can take several service intervals to
|
||||
* transmit.
|
||||
*/
|
||||
int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
||||
struct urb *urb, int slot_id, unsigned int ep_index)
|
||||
{
|
||||
struct xhci_ep_ctx *ep_ctx;
|
||||
|
||||
ep_ctx = xhci_get_ep_ctx(xhci, xhci->devs[slot_id]->out_ctx, ep_index);
|
||||
check_interval(xhci, urb, ep_ctx);
|
||||
|
||||
return xhci_queue_bulk_tx(xhci, mem_flags, urb, slot_id, ep_index);
|
||||
}
|
||||
|
||||
|
|
@ -3086,177 +3098,6 @@ static u32 xhci_td_remainder(struct xhci_hcd *xhci, int transferred,
|
|||
return (total_packet_count - ((transferred + trb_buff_len) / maxp));
|
||||
}
|
||||
|
||||
|
||||
static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
||||
struct urb *urb, int slot_id, unsigned int ep_index)
|
||||
{
|
||||
struct xhci_ring *ep_ring;
|
||||
unsigned int num_trbs;
|
||||
struct urb_priv *urb_priv;
|
||||
struct xhci_td *td;
|
||||
struct scatterlist *sg;
|
||||
int num_sgs;
|
||||
int trb_buff_len, this_sg_len, running_total, ret;
|
||||
unsigned int total_packet_count;
|
||||
bool zero_length_needed;
|
||||
bool first_trb;
|
||||
int last_trb_num;
|
||||
u64 addr;
|
||||
bool more_trbs_coming;
|
||||
|
||||
struct xhci_generic_trb *start_trb;
|
||||
int start_cycle;
|
||||
|
||||
ep_ring = xhci_urb_to_transfer_ring(xhci, urb);
|
||||
if (!ep_ring)
|
||||
return -EINVAL;
|
||||
|
||||
num_trbs = count_sg_trbs_needed(xhci, urb);
|
||||
num_sgs = urb->num_mapped_sgs;
|
||||
total_packet_count = DIV_ROUND_UP(urb->transfer_buffer_length,
|
||||
usb_endpoint_maxp(&urb->ep->desc));
|
||||
|
||||
ret = prepare_transfer(xhci, xhci->devs[slot_id],
|
||||
ep_index, urb->stream_id,
|
||||
num_trbs, urb, 0, mem_flags);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
urb_priv = urb->hcpriv;
|
||||
|
||||
/* Deal with URB_ZERO_PACKET - need one more td/trb */
|
||||
zero_length_needed = urb->transfer_flags & URB_ZERO_PACKET &&
|
||||
urb_priv->length == 2;
|
||||
if (zero_length_needed) {
|
||||
num_trbs++;
|
||||
xhci_dbg(xhci, "Creating zero length td.\n");
|
||||
ret = prepare_transfer(xhci, xhci->devs[slot_id],
|
||||
ep_index, urb->stream_id,
|
||||
1, urb, 1, mem_flags);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
td = urb_priv->td[0];
|
||||
|
||||
/*
|
||||
* Don't give the first TRB to the hardware (by toggling the cycle bit)
|
||||
* until we've finished creating all the other TRBs. The ring's cycle
|
||||
* state may change as we enqueue the other TRBs, so save it too.
|
||||
*/
|
||||
start_trb = &ep_ring->enqueue->generic;
|
||||
start_cycle = ep_ring->cycle_state;
|
||||
|
||||
running_total = 0;
|
||||
/*
|
||||
* How much data is in the first TRB?
|
||||
*
|
||||
* There are three forces at work for TRB buffer pointers and lengths:
|
||||
* 1. We don't want to walk off the end of this sg-list entry buffer.
|
||||
* 2. The transfer length that the driver requested may be smaller than
|
||||
* the amount of memory allocated for this scatter-gather list.
|
||||
* 3. TRBs buffers can't cross 64KB boundaries.
|
||||
*/
|
||||
sg = urb->sg;
|
||||
addr = (u64) sg_dma_address(sg);
|
||||
this_sg_len = sg_dma_len(sg);
|
||||
trb_buff_len = TRB_MAX_BUFF_SIZE - (addr & (TRB_MAX_BUFF_SIZE - 1));
|
||||
trb_buff_len = min_t(int, trb_buff_len, this_sg_len);
|
||||
if (trb_buff_len > urb->transfer_buffer_length)
|
||||
trb_buff_len = urb->transfer_buffer_length;
|
||||
|
||||
first_trb = true;
|
||||
last_trb_num = zero_length_needed ? 2 : 1;
|
||||
/* Queue the first TRB, even if it's zero-length */
|
||||
do {
|
||||
u32 field = 0;
|
||||
u32 length_field = 0;
|
||||
u32 remainder = 0;
|
||||
|
||||
/* Don't change the cycle bit of the first TRB until later */
|
||||
if (first_trb) {
|
||||
first_trb = false;
|
||||
if (start_cycle == 0)
|
||||
field |= 0x1;
|
||||
} else
|
||||
field |= ep_ring->cycle_state;
|
||||
|
||||
/* Chain all the TRBs together; clear the chain bit in the last
|
||||
* TRB to indicate it's the last TRB in the chain.
|
||||
*/
|
||||
if (num_trbs > last_trb_num) {
|
||||
field |= TRB_CHAIN;
|
||||
} else if (num_trbs == last_trb_num) {
|
||||
td->last_trb = ep_ring->enqueue;
|
||||
field |= TRB_IOC;
|
||||
} else if (zero_length_needed && num_trbs == 1) {
|
||||
trb_buff_len = 0;
|
||||
urb_priv->td[1]->last_trb = ep_ring->enqueue;
|
||||
field |= TRB_IOC;
|
||||
}
|
||||
|
||||
/* Only set interrupt on short packet for IN endpoints */
|
||||
if (usb_urb_dir_in(urb))
|
||||
field |= TRB_ISP;
|
||||
|
||||
if (TRB_MAX_BUFF_SIZE -
|
||||
(addr & (TRB_MAX_BUFF_SIZE - 1)) < trb_buff_len) {
|
||||
xhci_warn(xhci, "WARN: sg dma xfer crosses 64KB boundaries!\n");
|
||||
xhci_dbg(xhci, "Next boundary at %#x, end dma = %#x\n",
|
||||
(unsigned int) (addr + TRB_MAX_BUFF_SIZE) & ~(TRB_MAX_BUFF_SIZE - 1),
|
||||
(unsigned int) addr + trb_buff_len);
|
||||
}
|
||||
|
||||
/* Set the TRB length, TD size, and interrupter fields. */
|
||||
remainder = xhci_td_remainder(xhci, running_total, trb_buff_len,
|
||||
urb->transfer_buffer_length,
|
||||
urb, num_trbs - 1);
|
||||
|
||||
length_field = TRB_LEN(trb_buff_len) |
|
||||
TRB_TD_SIZE(remainder) |
|
||||
TRB_INTR_TARGET(0);
|
||||
|
||||
if (num_trbs > 1)
|
||||
more_trbs_coming = true;
|
||||
else
|
||||
more_trbs_coming = false;
|
||||
queue_trb(xhci, ep_ring, more_trbs_coming,
|
||||
lower_32_bits(addr),
|
||||
upper_32_bits(addr),
|
||||
length_field,
|
||||
field | TRB_TYPE(TRB_NORMAL));
|
||||
--num_trbs;
|
||||
running_total += trb_buff_len;
|
||||
|
||||
/* Calculate length for next transfer --
|
||||
* Are we done queueing all the TRBs for this sg entry?
|
||||
*/
|
||||
this_sg_len -= trb_buff_len;
|
||||
if (this_sg_len == 0) {
|
||||
--num_sgs;
|
||||
if (num_sgs == 0)
|
||||
break;
|
||||
sg = sg_next(sg);
|
||||
addr = (u64) sg_dma_address(sg);
|
||||
this_sg_len = sg_dma_len(sg);
|
||||
} else {
|
||||
addr += trb_buff_len;
|
||||
}
|
||||
|
||||
trb_buff_len = TRB_MAX_BUFF_SIZE -
|
||||
(addr & (TRB_MAX_BUFF_SIZE - 1));
|
||||
trb_buff_len = min_t(int, trb_buff_len, this_sg_len);
|
||||
if (running_total + trb_buff_len > urb->transfer_buffer_length)
|
||||
trb_buff_len =
|
||||
urb->transfer_buffer_length - running_total;
|
||||
} while (num_trbs > 0);
|
||||
|
||||
check_trb_math(urb, num_trbs, running_total);
|
||||
giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id,
|
||||
start_cycle, start_trb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This is very similar to what ehci-q.c qtd_fill() does */
|
||||
int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
||||
struct urb *urb, int slot_id, unsigned int ep_index)
|
||||
|
|
@ -3264,51 +3105,40 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
|||
struct xhci_ring *ep_ring;
|
||||
struct urb_priv *urb_priv;
|
||||
struct xhci_td *td;
|
||||
int num_trbs;
|
||||
struct xhci_generic_trb *start_trb;
|
||||
bool first_trb;
|
||||
int last_trb_num;
|
||||
struct scatterlist *sg = NULL;
|
||||
bool more_trbs_coming;
|
||||
bool zero_length_needed;
|
||||
int start_cycle;
|
||||
u32 field, length_field;
|
||||
|
||||
int running_total, trb_buff_len, ret;
|
||||
unsigned int total_packet_count;
|
||||
unsigned int num_trbs, last_trb_num, i;
|
||||
unsigned int start_cycle, num_sgs = 0;
|
||||
unsigned int running_total, block_len, trb_buff_len;
|
||||
unsigned int full_len;
|
||||
int ret;
|
||||
u32 field, length_field, remainder;
|
||||
u64 addr;
|
||||
|
||||
if (urb->num_sgs)
|
||||
return queue_bulk_sg_tx(xhci, mem_flags, urb, slot_id, ep_index);
|
||||
|
||||
ep_ring = xhci_urb_to_transfer_ring(xhci, urb);
|
||||
if (!ep_ring)
|
||||
return -EINVAL;
|
||||
|
||||
num_trbs = 0;
|
||||
/* How much data is (potentially) left before the 64KB boundary? */
|
||||
running_total = TRB_MAX_BUFF_SIZE -
|
||||
(urb->transfer_dma & (TRB_MAX_BUFF_SIZE - 1));
|
||||
running_total &= TRB_MAX_BUFF_SIZE - 1;
|
||||
|
||||
/* If there's some data on this 64KB chunk, or we have to send a
|
||||
* zero-length transfer, we need at least one TRB
|
||||
*/
|
||||
if (running_total != 0 || urb->transfer_buffer_length == 0)
|
||||
num_trbs++;
|
||||
/* How many more 64KB chunks to transfer, how many more TRBs? */
|
||||
while (running_total < urb->transfer_buffer_length) {
|
||||
num_trbs++;
|
||||
running_total += TRB_MAX_BUFF_SIZE;
|
||||
}
|
||||
/* If we have scatter/gather list, we use it. */
|
||||
if (urb->num_sgs) {
|
||||
num_sgs = urb->num_mapped_sgs;
|
||||
sg = urb->sg;
|
||||
num_trbs = count_sg_trbs_needed(urb);
|
||||
} else
|
||||
num_trbs = count_trbs_needed(urb);
|
||||
|
||||
ret = prepare_transfer(xhci, xhci->devs[slot_id],
|
||||
ep_index, urb->stream_id,
|
||||
num_trbs, urb, 0, mem_flags);
|
||||
if (ret < 0)
|
||||
if (unlikely(ret < 0))
|
||||
return ret;
|
||||
|
||||
urb_priv = urb->hcpriv;
|
||||
|
||||
last_trb_num = num_trbs - 1;
|
||||
|
||||
/* Deal with URB_ZERO_PACKET - need one more td/trb */
|
||||
zero_length_needed = urb->transfer_flags & URB_ZERO_PACKET &&
|
||||
urb_priv->length == 2;
|
||||
|
|
@ -3318,7 +3148,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
|||
ret = prepare_transfer(xhci, xhci->devs[slot_id],
|
||||
ep_index, urb->stream_id,
|
||||
1, urb, 1, mem_flags);
|
||||
if (ret < 0)
|
||||
if (unlikely(ret < 0))
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -3332,43 +3162,58 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
|||
start_trb = &ep_ring->enqueue->generic;
|
||||
start_cycle = ep_ring->cycle_state;
|
||||
|
||||
full_len = urb->transfer_buffer_length;
|
||||
running_total = 0;
|
||||
total_packet_count = DIV_ROUND_UP(urb->transfer_buffer_length,
|
||||
usb_endpoint_maxp(&urb->ep->desc));
|
||||
/* How much data is in the first TRB? */
|
||||
addr = (u64) urb->transfer_dma;
|
||||
trb_buff_len = TRB_MAX_BUFF_SIZE -
|
||||
(urb->transfer_dma & (TRB_MAX_BUFF_SIZE - 1));
|
||||
if (trb_buff_len > urb->transfer_buffer_length)
|
||||
trb_buff_len = urb->transfer_buffer_length;
|
||||
block_len = 0;
|
||||
|
||||
first_trb = true;
|
||||
last_trb_num = zero_length_needed ? 2 : 1;
|
||||
/* Queue the first TRB, even if it's zero-length */
|
||||
do {
|
||||
u32 remainder = 0;
|
||||
field = 0;
|
||||
/* Queue the TRBs, even if they are zero-length */
|
||||
for (i = 0; i < num_trbs; i++) {
|
||||
field = TRB_TYPE(TRB_NORMAL);
|
||||
|
||||
if (block_len == 0) {
|
||||
/* A new contiguous block. */
|
||||
if (sg) {
|
||||
addr = (u64) sg_dma_address(sg);
|
||||
block_len = sg_dma_len(sg);
|
||||
} else {
|
||||
addr = (u64) urb->transfer_dma;
|
||||
block_len = full_len;
|
||||
}
|
||||
/* TRB buffer should not cross 64KB boundaries */
|
||||
trb_buff_len = TRB_BUFF_LEN_UP_TO_BOUNDARY(addr);
|
||||
trb_buff_len = min_t(unsigned int,
|
||||
trb_buff_len,
|
||||
block_len);
|
||||
} else {
|
||||
/* Further through the contiguous block. */
|
||||
trb_buff_len = block_len;
|
||||
if (trb_buff_len > TRB_MAX_BUFF_SIZE)
|
||||
trb_buff_len = TRB_MAX_BUFF_SIZE;
|
||||
}
|
||||
|
||||
if (running_total + trb_buff_len > full_len)
|
||||
trb_buff_len = full_len - running_total;
|
||||
|
||||
/* Don't change the cycle bit of the first TRB until later */
|
||||
if (first_trb) {
|
||||
first_trb = false;
|
||||
if (i == 0) {
|
||||
if (start_cycle == 0)
|
||||
field |= 0x1;
|
||||
field |= TRB_CYCLE;
|
||||
} else
|
||||
field |= ep_ring->cycle_state;
|
||||
|
||||
/* Chain all the TRBs together; clear the chain bit in the last
|
||||
* TRB to indicate it's the last TRB in the chain.
|
||||
*/
|
||||
if (num_trbs > last_trb_num) {
|
||||
if (i < last_trb_num) {
|
||||
field |= TRB_CHAIN;
|
||||
} else if (num_trbs == last_trb_num) {
|
||||
td->last_trb = ep_ring->enqueue;
|
||||
field |= TRB_IOC;
|
||||
} else if (zero_length_needed && num_trbs == 1) {
|
||||
trb_buff_len = 0;
|
||||
urb_priv->td[1]->last_trb = ep_ring->enqueue;
|
||||
} else {
|
||||
field |= TRB_IOC;
|
||||
if (i == last_trb_num)
|
||||
td->last_trb = ep_ring->enqueue;
|
||||
else if (zero_length_needed) {
|
||||
trb_buff_len = 0;
|
||||
urb_priv->td[1]->last_trb = ep_ring->enqueue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Only set interrupt on short packet for IN endpoints */
|
||||
|
|
@ -3376,15 +3221,15 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
|||
field |= TRB_ISP;
|
||||
|
||||
/* Set the TRB length, TD size, and interrupter fields. */
|
||||
remainder = xhci_td_remainder(xhci, running_total, trb_buff_len,
|
||||
urb->transfer_buffer_length,
|
||||
urb, num_trbs - 1);
|
||||
remainder = xhci_td_remainder(xhci, running_total,
|
||||
trb_buff_len, full_len,
|
||||
urb, num_trbs - i - 1);
|
||||
|
||||
length_field = TRB_LEN(trb_buff_len) |
|
||||
TRB_TD_SIZE(remainder) |
|
||||
TRB_INTR_TARGET(0);
|
||||
|
||||
if (num_trbs > 1)
|
||||
if (i < num_trbs - 1)
|
||||
more_trbs_coming = true;
|
||||
else
|
||||
more_trbs_coming = false;
|
||||
|
|
@ -3392,18 +3237,24 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
|||
lower_32_bits(addr),
|
||||
upper_32_bits(addr),
|
||||
length_field,
|
||||
field | TRB_TYPE(TRB_NORMAL));
|
||||
--num_trbs;
|
||||
field);
|
||||
|
||||
running_total += trb_buff_len;
|
||||
|
||||
/* Calculate length for next transfer */
|
||||
addr += trb_buff_len;
|
||||
trb_buff_len = urb->transfer_buffer_length - running_total;
|
||||
if (trb_buff_len > TRB_MAX_BUFF_SIZE)
|
||||
trb_buff_len = TRB_MAX_BUFF_SIZE;
|
||||
} while (num_trbs > 0);
|
||||
block_len -= trb_buff_len;
|
||||
|
||||
check_trb_math(urb, num_trbs, running_total);
|
||||
if (sg) {
|
||||
if (block_len == 0) {
|
||||
/* New sg entry */
|
||||
--num_sgs;
|
||||
if (num_sgs == 0)
|
||||
break;
|
||||
sg = sg_next(sg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
check_trb_math(urb, running_total);
|
||||
giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id,
|
||||
start_cycle, start_trb);
|
||||
return 0;
|
||||
|
|
@ -3532,23 +3383,6 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int count_isoc_trbs_needed(struct xhci_hcd *xhci,
|
||||
struct urb *urb, int i)
|
||||
{
|
||||
int num_trbs = 0;
|
||||
u64 addr, td_len;
|
||||
|
||||
addr = (u64) (urb->transfer_dma + urb->iso_frame_desc[i].offset);
|
||||
td_len = urb->iso_frame_desc[i].length;
|
||||
|
||||
num_trbs = DIV_ROUND_UP(td_len + (addr & (TRB_MAX_BUFF_SIZE - 1)),
|
||||
TRB_MAX_BUFF_SIZE);
|
||||
if (num_trbs == 0)
|
||||
num_trbs++;
|
||||
|
||||
return num_trbs;
|
||||
}
|
||||
|
||||
/*
|
||||
* The transfer burst count field of the isochronous TRB defines the number of
|
||||
* bursts that are required to move all packets in this TD. Only SuperSpeed
|
||||
|
|
@ -3746,7 +3580,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
|||
last_burst_pkt_count = xhci_get_last_burst_packet_count(xhci,
|
||||
urb, total_pkt_count);
|
||||
|
||||
trbs_per_td = count_isoc_trbs_needed(xhci, urb, i);
|
||||
trbs_per_td = count_isoc_trbs_needed(urb, i);
|
||||
|
||||
ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index,
|
||||
urb->stream_id, trbs_per_td, urb, i, mem_flags);
|
||||
|
|
@ -3807,8 +3641,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
|||
field |= TRB_BEI;
|
||||
}
|
||||
/* Calculate TRB length */
|
||||
trb_buff_len = TRB_MAX_BUFF_SIZE -
|
||||
(addr & ((1 << TRB_MAX_BUFF_SHIFT) - 1));
|
||||
trb_buff_len = TRB_BUFF_LEN_UP_TO_BOUNDARY(addr);
|
||||
if (trb_buff_len > td_remain_len)
|
||||
trb_buff_len = td_remain_len;
|
||||
|
||||
|
|
@ -3897,8 +3730,6 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags,
|
|||
struct xhci_ring *ep_ring;
|
||||
struct xhci_ep_ctx *ep_ctx;
|
||||
int start_frame;
|
||||
int xhci_interval;
|
||||
int ep_interval;
|
||||
int num_tds, num_trbs, i;
|
||||
int ret;
|
||||
struct xhci_virt_ep *xep;
|
||||
|
|
@ -3912,7 +3743,7 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags,
|
|||
num_trbs = 0;
|
||||
num_tds = urb->number_of_packets;
|
||||
for (i = 0; i < num_tds; i++)
|
||||
num_trbs += count_isoc_trbs_needed(xhci, urb, i);
|
||||
num_trbs += count_isoc_trbs_needed(urb, i);
|
||||
|
||||
/* Check the ring to guarantee there is enough room for the whole urb.
|
||||
* Do not insert any td of the urb to the ring if the check failed.
|
||||
|
|
@ -3926,26 +3757,7 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags,
|
|||
* Check interval value. This should be done before we start to
|
||||
* calculate the start frame value.
|
||||
*/
|
||||
xhci_interval = EP_INTERVAL_TO_UFRAMES(le32_to_cpu(ep_ctx->ep_info));
|
||||
ep_interval = urb->interval;
|
||||
/* Convert to microframes */
|
||||
if (urb->dev->speed == USB_SPEED_LOW ||
|
||||
urb->dev->speed == USB_SPEED_FULL)
|
||||
ep_interval *= 8;
|
||||
/* FIXME change this to a warning and a suggestion to use the new API
|
||||
* to set the polling interval (once the API is added).
|
||||
*/
|
||||
if (xhci_interval != ep_interval) {
|
||||
dev_dbg_ratelimited(&urb->dev->dev,
|
||||
"Driver uses different interval (%d microframe%s) than xHCI (%d microframe%s)\n",
|
||||
ep_interval, ep_interval == 1 ? "" : "s",
|
||||
xhci_interval, xhci_interval == 1 ? "" : "s");
|
||||
urb->interval = xhci_interval;
|
||||
/* Convert back to frames for LS/FS devices */
|
||||
if (urb->dev->speed == USB_SPEED_LOW ||
|
||||
urb->dev->speed == USB_SPEED_FULL)
|
||||
urb->interval /= 8;
|
||||
}
|
||||
check_interval(xhci, urb, ep_ctx);
|
||||
|
||||
/* Calculate the start frame and put it in urb->start_frame. */
|
||||
if (HCC_CFC(xhci->hcc_params) && !list_empty(&ep_ring->td_list)) {
|
||||
|
|
|
|||
|
|
@ -1459,47 +1459,6 @@ free_priv:
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Get the right ring for the given URB.
|
||||
* If the endpoint supports streams, boundary check the URB's stream ID.
|
||||
* If the endpoint doesn't support streams, return the singular endpoint ring.
|
||||
*/
|
||||
static struct xhci_ring *xhci_urb_to_transfer_ring(struct xhci_hcd *xhci,
|
||||
struct urb *urb)
|
||||
{
|
||||
unsigned int slot_id;
|
||||
unsigned int ep_index;
|
||||
unsigned int stream_id;
|
||||
struct xhci_virt_ep *ep;
|
||||
|
||||
slot_id = urb->dev->slot_id;
|
||||
ep_index = xhci_get_endpoint_index(&urb->ep->desc);
|
||||
stream_id = urb->stream_id;
|
||||
ep = &xhci->devs[slot_id]->eps[ep_index];
|
||||
/* Common case: no streams */
|
||||
if (!(ep->ep_state & EP_HAS_STREAMS))
|
||||
return ep->ring;
|
||||
|
||||
if (stream_id == 0) {
|
||||
xhci_warn(xhci,
|
||||
"WARN: Slot ID %u, ep index %u has streams, "
|
||||
"but URB has no stream ID.\n",
|
||||
slot_id, ep_index);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (stream_id < ep->stream_info->num_streams)
|
||||
return ep->stream_info->stream_rings[stream_id];
|
||||
|
||||
xhci_warn(xhci,
|
||||
"WARN: Slot ID %u, ep index %u has "
|
||||
"stream IDs 1 to %u allocated, "
|
||||
"but stream ID %u is requested.\n",
|
||||
slot_id, ep_index,
|
||||
ep->stream_info->num_streams - 1,
|
||||
stream_id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the URB's TD from the endpoint ring. This may cause the HC to stop
|
||||
* USB transfers, potentially stopping in the middle of a TRB buffer. The HC
|
||||
|
|
|
|||
|
|
@ -1338,6 +1338,9 @@ union xhci_trb {
|
|||
/* TRB buffer pointers can't cross 64KB boundaries */
|
||||
#define TRB_MAX_BUFF_SHIFT 16
|
||||
#define TRB_MAX_BUFF_SIZE (1 << TRB_MAX_BUFF_SHIFT)
|
||||
/* How much data is left before the 64KB boundary? */
|
||||
#define TRB_BUFF_LEN_UP_TO_BOUNDARY(addr) (TRB_MAX_BUFF_SIZE - \
|
||||
(addr & (TRB_MAX_BUFF_SIZE - 1)))
|
||||
|
||||
struct xhci_segment {
|
||||
union xhci_trb *trbs;
|
||||
|
|
@ -1965,4 +1968,15 @@ struct xhci_input_control_ctx *xhci_get_input_control_ctx(struct xhci_container_
|
|||
struct xhci_slot_ctx *xhci_get_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx);
|
||||
struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, unsigned int ep_index);
|
||||
|
||||
struct xhci_ring *xhci_triad_to_transfer_ring(struct xhci_hcd *xhci,
|
||||
unsigned int slot_id, unsigned int ep_index,
|
||||
unsigned int stream_id);
|
||||
static inline struct xhci_ring *xhci_urb_to_transfer_ring(struct xhci_hcd *xhci,
|
||||
struct urb *urb)
|
||||
{
|
||||
return xhci_triad_to_transfer_ring(xhci, urb->dev->slot_id,
|
||||
xhci_get_endpoint_index(&urb->ep->desc),
|
||||
urb->stream_id);
|
||||
}
|
||||
|
||||
#endif /* __LINUX_XHCI_HCD_H */
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@ static void isp1761_pci_shutdown(struct pci_dev *dev)
|
|||
printk(KERN_ERR "ips1761_pci_shutdown\n");
|
||||
}
|
||||
|
||||
static const struct pci_device_id isp1760_plx [] = {
|
||||
static const struct pci_device_id isp1760_plx[] = {
|
||||
{
|
||||
.class = PCI_CLASS_BRIDGE_OTHER << 8,
|
||||
.class_mask = ~0,
|
||||
|
|
|
|||
|
|
@ -268,3 +268,29 @@ config USB_CHAOSKEY
|
|||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called chaoskey.
|
||||
|
||||
config UCSI
|
||||
tristate "USB Type-C Connector System Software Interface driver"
|
||||
depends on ACPI
|
||||
help
|
||||
UCSI driver is meant to be used as a convenience tool for desktop and
|
||||
server systems that are not equipped to handle USB in device mode. It
|
||||
will always select USB host role for the USB Type-C ports on systems
|
||||
that provide UCSI interface.
|
||||
|
||||
USB Type-C Connector System Software Interface (UCSI) is a
|
||||
specification for an interface that allows the Operating System to
|
||||
control the USB Type-C ports on a system. Things the need controlling
|
||||
include the USB Data Role (host or device), and when USB Power
|
||||
Delivery is supported, the Power Role (source or sink). With USB
|
||||
Type-C connectors, when two dual role capable devices are attached
|
||||
together, the data role is selected randomly. Therefore it is
|
||||
important to give the OS a way to select the role. Otherwise the user
|
||||
would have to unplug and replug in order in order to attempt to swap
|
||||
the data and power roles.
|
||||
|
||||
The UCSI specification can be downloaded from:
|
||||
http://www.intel.com/content/www/us/en/io/universal-serial-bus/usb-type-c-ucsi-spec.html
|
||||
|
||||
To compile the driver as a module, choose M here: the module will be
|
||||
called ucsi.
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ obj-$(CONFIG_USB_SEVSEG) += usbsevseg.o
|
|||
obj-$(CONFIG_USB_YUREX) += yurex.o
|
||||
obj-$(CONFIG_USB_HSIC_USB3503) += usb3503.o
|
||||
obj-$(CONFIG_USB_CHAOSKEY) += chaoskey.o
|
||||
obj-$(CONFIG_UCSI) += ucsi.o
|
||||
|
||||
obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/
|
||||
obj-$(CONFIG_USB_LINK_LAYER_TEST) += lvstest.o
|
||||
|
|
|
|||
|
|
@ -2420,7 +2420,7 @@ static int sisusb_open(struct inode *inode, struct file *file)
|
|||
|
||||
if (!sisusb->devinit) {
|
||||
if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH ||
|
||||
sisusb->sisusb_dev->speed == USB_SPEED_SUPER) {
|
||||
sisusb->sisusb_dev->speed >= USB_SPEED_SUPER) {
|
||||
if (sisusb_init_gfxdevice(sisusb, 0)) {
|
||||
mutex_unlock(&sisusb->lock);
|
||||
dev_err(&sisusb->sisusb_dev->dev,
|
||||
|
|
@ -3127,7 +3127,7 @@ static int sisusb_probe(struct usb_interface *intf,
|
|||
|
||||
sisusb->present = 1;
|
||||
|
||||
if (dev->speed == USB_SPEED_HIGH || dev->speed == USB_SPEED_SUPER) {
|
||||
if (dev->speed == USB_SPEED_HIGH || dev->speed >= USB_SPEED_SUPER) {
|
||||
int initscreen = 1;
|
||||
#ifdef INCL_SISUSB_CON
|
||||
if (sisusb_first_vc > 0 && sisusb_last_vc > 0 &&
|
||||
|
|
|
|||
478
drivers/usb/misc/ucsi.c
Normal file
478
drivers/usb/misc/ucsi.c
Normal file
|
|
@ -0,0 +1,478 @@
|
|||
/*
|
||||
* USB Type-C Connector System Software Interface driver
|
||||
*
|
||||
* Copyright (C) 2016, Intel Corporation
|
||||
* Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/acpi.h>
|
||||
|
||||
#include "ucsi.h"
|
||||
|
||||
/* Double the time defined by MIN_TIME_TO_RESPOND_WITH_BUSY */
|
||||
#define UCSI_TIMEOUT_MS 20
|
||||
|
||||
enum ucsi_status {
|
||||
UCSI_IDLE = 0,
|
||||
UCSI_BUSY,
|
||||
UCSI_ERROR,
|
||||
};
|
||||
|
||||
struct ucsi_connector {
|
||||
int num;
|
||||
struct ucsi *ucsi;
|
||||
struct work_struct work;
|
||||
struct ucsi_connector_capability cap;
|
||||
};
|
||||
|
||||
struct ucsi {
|
||||
struct device *dev;
|
||||
struct ucsi_data __iomem *data;
|
||||
|
||||
enum ucsi_status status;
|
||||
struct completion complete;
|
||||
struct ucsi_capability cap;
|
||||
struct ucsi_connector *connector;
|
||||
|
||||
/* device lock */
|
||||
spinlock_t dev_lock;
|
||||
|
||||
/* PPM Communication lock */
|
||||
struct mutex ppm_lock;
|
||||
|
||||
/* PPM communication flags */
|
||||
unsigned long flags;
|
||||
#define EVENT_PENDING 0
|
||||
#define COMMAND_PENDING 1
|
||||
};
|
||||
|
||||
static int ucsi_acpi_cmd(struct ucsi *ucsi, struct ucsi_control *ctrl)
|
||||
{
|
||||
uuid_le uuid = UUID_LE(0x6f8398c2, 0x7ca4, 0x11e4,
|
||||
0xad, 0x36, 0x63, 0x10, 0x42, 0xb5, 0x00, 0x8f);
|
||||
union acpi_object *obj;
|
||||
|
||||
ucsi->data->ctrl.raw_cmd = ctrl->raw_cmd;
|
||||
|
||||
obj = acpi_evaluate_dsm(ACPI_HANDLE(ucsi->dev), uuid.b, 1, 1, NULL);
|
||||
if (!obj) {
|
||||
dev_err(ucsi->dev, "%s: failed to evaluate _DSM\n", __func__);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ACPI_FREE(obj);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ucsi_acpi_notify(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct ucsi *ucsi = data;
|
||||
struct ucsi_cci *cci;
|
||||
|
||||
spin_lock(&ucsi->dev_lock);
|
||||
|
||||
ucsi->status = UCSI_IDLE;
|
||||
cci = &ucsi->data->cci;
|
||||
|
||||
/*
|
||||
* REVISIT: This is not documented behavior, but all known PPMs ACK
|
||||
* asynchronous events by sending notification with cleared CCI.
|
||||
*/
|
||||
if (!ucsi->data->raw_cci) {
|
||||
if (test_bit(EVENT_PENDING, &ucsi->flags))
|
||||
complete(&ucsi->complete);
|
||||
else
|
||||
dev_WARN(ucsi->dev, "spurious notification\n");
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (test_bit(COMMAND_PENDING, &ucsi->flags)) {
|
||||
if (cci->busy) {
|
||||
ucsi->status = UCSI_BUSY;
|
||||
complete(&ucsi->complete);
|
||||
|
||||
goto out_unlock;
|
||||
} else if (cci->ack_complete || cci->cmd_complete) {
|
||||
/* Error Indication is only valid with commands */
|
||||
if (cci->error && cci->cmd_complete)
|
||||
ucsi->status = UCSI_ERROR;
|
||||
|
||||
ucsi->data->ctrl.raw_cmd = 0;
|
||||
complete(&ucsi->complete);
|
||||
}
|
||||
}
|
||||
|
||||
if (cci->connector_change) {
|
||||
struct ucsi_connector *con;
|
||||
|
||||
/*
|
||||
* This is workaround for buggy PPMs that create asynchronous
|
||||
* event notifications before OPM has enabled them.
|
||||
*/
|
||||
if (!ucsi->connector)
|
||||
goto out_unlock;
|
||||
|
||||
con = ucsi->connector + (cci->connector_change - 1);
|
||||
|
||||
/*
|
||||
* PPM will not clear the connector specific bit in Connector
|
||||
* Change Indication field of CCI until the driver has ACK it,
|
||||
* and the driver can not ACK it before it has been processed.
|
||||
* The PPM will not generate new events before the first has
|
||||
* been acknowledged, even if they are for an other connector.
|
||||
* So only one event at a time.
|
||||
*/
|
||||
if (!test_and_set_bit(EVENT_PENDING, &ucsi->flags))
|
||||
schedule_work(&con->work);
|
||||
}
|
||||
out_unlock:
|
||||
spin_unlock(&ucsi->dev_lock);
|
||||
}
|
||||
|
||||
static int ucsi_ack(struct ucsi *ucsi, u8 cmd)
|
||||
{
|
||||
struct ucsi_control ctrl;
|
||||
int ret;
|
||||
|
||||
ctrl.cmd.cmd = UCSI_ACK_CC_CI;
|
||||
ctrl.cmd.length = 0;
|
||||
ctrl.cmd.data = cmd;
|
||||
ret = ucsi_acpi_cmd(ucsi, &ctrl);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Waiting for ACK also with ACK CMD for now */
|
||||
ret = wait_for_completion_timeout(&ucsi->complete,
|
||||
msecs_to_jiffies(UCSI_TIMEOUT_MS));
|
||||
if (!ret)
|
||||
return -ETIMEDOUT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ucsi_run_cmd(struct ucsi *ucsi, struct ucsi_control *ctrl,
|
||||
void *data, size_t size)
|
||||
{
|
||||
u16 err_value = 0;
|
||||
int ret;
|
||||
|
||||
set_bit(COMMAND_PENDING, &ucsi->flags);
|
||||
|
||||
ret = ucsi_acpi_cmd(ucsi, ctrl);
|
||||
if (ret)
|
||||
goto err_clear_flag;
|
||||
|
||||
ret = wait_for_completion_timeout(&ucsi->complete,
|
||||
msecs_to_jiffies(UCSI_TIMEOUT_MS));
|
||||
if (!ret) {
|
||||
ret = -ETIMEDOUT;
|
||||
goto err_clear_flag;
|
||||
}
|
||||
|
||||
switch (ucsi->status) {
|
||||
case UCSI_IDLE:
|
||||
if (data)
|
||||
memcpy(data, ucsi->data->message_in, size);
|
||||
|
||||
ret = ucsi_ack(ucsi, UCSI_ACK_CMD);
|
||||
break;
|
||||
case UCSI_BUSY:
|
||||
/* The caller decides whether to cancel or not */
|
||||
ret = -EBUSY;
|
||||
goto err_clear_flag;
|
||||
case UCSI_ERROR:
|
||||
ret = ucsi_ack(ucsi, UCSI_ACK_CMD);
|
||||
if (ret)
|
||||
goto err_clear_flag;
|
||||
|
||||
ctrl->cmd.cmd = UCSI_GET_ERROR_STATUS;
|
||||
ctrl->cmd.length = 0;
|
||||
ctrl->cmd.data = 0;
|
||||
ret = ucsi_acpi_cmd(ucsi, ctrl);
|
||||
if (ret)
|
||||
goto err_clear_flag;
|
||||
|
||||
ret = wait_for_completion_timeout(&ucsi->complete,
|
||||
msecs_to_jiffies(UCSI_TIMEOUT_MS));
|
||||
if (!ret) {
|
||||
ret = -ETIMEDOUT;
|
||||
goto err_clear_flag;
|
||||
}
|
||||
|
||||
memcpy(&err_value, ucsi->data->message_in, sizeof(err_value));
|
||||
|
||||
/* Something has really gone wrong */
|
||||
if (WARN_ON(ucsi->status == UCSI_ERROR)) {
|
||||
ret = -ENODEV;
|
||||
goto err_clear_flag;
|
||||
}
|
||||
|
||||
ret = ucsi_ack(ucsi, UCSI_ACK_CMD);
|
||||
if (ret)
|
||||
goto err_clear_flag;
|
||||
|
||||
switch (err_value) {
|
||||
case UCSI_ERROR_INCOMPATIBLE_PARTNER:
|
||||
ret = -EOPNOTSUPP;
|
||||
break;
|
||||
case UCSI_ERROR_CC_COMMUNICATION_ERR:
|
||||
ret = -ECOMM;
|
||||
break;
|
||||
case UCSI_ERROR_CONTRACT_NEGOTIATION_FAIL:
|
||||
ret = -EIO;
|
||||
break;
|
||||
case UCSI_ERROR_DEAD_BATTERY:
|
||||
dev_warn(ucsi->dev, "Dead battery condition!\n");
|
||||
ret = -EPERM;
|
||||
break;
|
||||
/* The following mean a bug in this driver */
|
||||
case UCSI_ERROR_INVALID_CON_NUM:
|
||||
case UCSI_ERROR_UNREGONIZED_CMD:
|
||||
case UCSI_ERROR_INVALID_CMD_ARGUMENT:
|
||||
default:
|
||||
dev_warn(ucsi->dev,
|
||||
"%s: possible UCSI driver bug - error %hu\n",
|
||||
__func__, err_value);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
ctrl->raw_cmd = 0;
|
||||
err_clear_flag:
|
||||
clear_bit(COMMAND_PENDING, &ucsi->flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ucsi_connector_change(struct work_struct *work)
|
||||
{
|
||||
struct ucsi_connector *con = container_of(work, struct ucsi_connector,
|
||||
work);
|
||||
struct ucsi_connector_status constat;
|
||||
struct ucsi *ucsi = con->ucsi;
|
||||
struct ucsi_control ctrl;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&ucsi->ppm_lock);
|
||||
|
||||
ctrl.cmd.cmd = UCSI_GET_CONNECTOR_STATUS;
|
||||
ctrl.cmd.length = 0;
|
||||
ctrl.cmd.data = con->num;
|
||||
ret = ucsi_run_cmd(con->ucsi, &ctrl, &constat, sizeof(constat));
|
||||
if (ret) {
|
||||
dev_err(ucsi->dev, "%s: failed to read connector status (%d)\n",
|
||||
__func__, ret);
|
||||
goto out_ack_event;
|
||||
}
|
||||
|
||||
/* Ignoring disconnections and Alternate Modes */
|
||||
if (!constat.connected || !(constat.change &
|
||||
(UCSI_CONSTAT_PARTNER_CHANGE | UCSI_CONSTAT_CONNECT_CHANGE)) ||
|
||||
constat.partner_flags & UCSI_CONSTAT_PARTNER_FLAG_ALT_MODE)
|
||||
goto out_ack_event;
|
||||
|
||||
/* If the partner got USB Host role, attempting swap */
|
||||
if (constat.partner_type & UCSI_CONSTAT_PARTNER_TYPE_DFP) {
|
||||
ctrl.uor.cmd = UCSI_SET_UOR;
|
||||
ctrl.uor.con_num = con->num;
|
||||
ctrl.uor.role = UCSI_UOR_ROLE_DFP;
|
||||
|
||||
ret = ucsi_run_cmd(con->ucsi, &ctrl, NULL, 0);
|
||||
if (ret)
|
||||
dev_err(ucsi->dev, "%s: failed to swap role (%d)\n",
|
||||
__func__, ret);
|
||||
}
|
||||
out_ack_event:
|
||||
ucsi_ack(ucsi, UCSI_ACK_EVENT);
|
||||
clear_bit(EVENT_PENDING, &ucsi->flags);
|
||||
mutex_unlock(&ucsi->ppm_lock);
|
||||
}
|
||||
|
||||
static int ucsi_reset_ppm(struct ucsi *ucsi)
|
||||
{
|
||||
int timeout = UCSI_TIMEOUT_MS;
|
||||
struct ucsi_control ctrl;
|
||||
int ret;
|
||||
|
||||
memset(&ctrl, 0, sizeof(ctrl));
|
||||
ctrl.cmd.cmd = UCSI_PPM_RESET;
|
||||
ret = ucsi_acpi_cmd(ucsi, &ctrl);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* There is no quarantee the PPM will ever set the RESET_COMPLETE bit */
|
||||
while (!ucsi->data->cci.reset_complete && timeout--)
|
||||
usleep_range(1000, 2000);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ucsi_init(struct ucsi *ucsi)
|
||||
{
|
||||
struct ucsi_connector *con;
|
||||
struct ucsi_control ctrl;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
init_completion(&ucsi->complete);
|
||||
spin_lock_init(&ucsi->dev_lock);
|
||||
mutex_init(&ucsi->ppm_lock);
|
||||
|
||||
/* Reset the PPM */
|
||||
ret = ucsi_reset_ppm(ucsi);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* REVISIT: Executing second reset to WA an issue seen on some of the
|
||||
* Broxton based platforms, where the first reset puts the PPM into a
|
||||
* state where it's unable to recognise some of the commands.
|
||||
*/
|
||||
ret = ucsi_reset_ppm(ucsi);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&ucsi->ppm_lock);
|
||||
|
||||
/* Enable basic notifications */
|
||||
ctrl.cmd.cmd = UCSI_SET_NOTIFICATION_ENABLE;
|
||||
ctrl.cmd.length = 0;
|
||||
ctrl.cmd.data = UCSI_ENABLE_NTFY_CMD_COMPLETE | UCSI_ENABLE_NTFY_ERROR;
|
||||
ret = ucsi_run_cmd(ucsi, &ctrl, NULL, 0);
|
||||
if (ret)
|
||||
goto err_reset;
|
||||
|
||||
/* Get PPM capabilities */
|
||||
ctrl.cmd.cmd = UCSI_GET_CAPABILITY;
|
||||
ret = ucsi_run_cmd(ucsi, &ctrl, &ucsi->cap, sizeof(ucsi->cap));
|
||||
if (ret)
|
||||
goto err_reset;
|
||||
|
||||
if (!ucsi->cap.num_connectors) {
|
||||
ret = -ENODEV;
|
||||
goto err_reset;
|
||||
}
|
||||
|
||||
ucsi->connector = devm_kcalloc(ucsi->dev, ucsi->cap.num_connectors,
|
||||
sizeof(*ucsi->connector), GFP_KERNEL);
|
||||
if (!ucsi->connector) {
|
||||
ret = -ENOMEM;
|
||||
goto err_reset;
|
||||
}
|
||||
|
||||
for (i = 1, con = ucsi->connector; i < ucsi->cap.num_connectors + 1;
|
||||
i++, con++) {
|
||||
/* Get connector capability */
|
||||
ctrl.cmd.cmd = UCSI_GET_CONNECTOR_CAPABILITY;
|
||||
ctrl.cmd.data = i;
|
||||
ret = ucsi_run_cmd(ucsi, &ctrl, &con->cap, sizeof(con->cap));
|
||||
if (ret)
|
||||
goto err_reset;
|
||||
|
||||
con->num = i;
|
||||
con->ucsi = ucsi;
|
||||
INIT_WORK(&con->work, ucsi_connector_change);
|
||||
}
|
||||
|
||||
/* Enable all notifications */
|
||||
ctrl.cmd.cmd = UCSI_SET_NOTIFICATION_ENABLE;
|
||||
ctrl.cmd.data = UCSI_ENABLE_NTFY_ALL;
|
||||
ret = ucsi_run_cmd(ucsi, &ctrl, NULL, 0);
|
||||
if (ret < 0)
|
||||
goto err_reset;
|
||||
|
||||
mutex_unlock(&ucsi->ppm_lock);
|
||||
return 0;
|
||||
err_reset:
|
||||
ucsi_reset_ppm(ucsi);
|
||||
mutex_unlock(&ucsi->ppm_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ucsi_acpi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
acpi_status status;
|
||||
struct ucsi *ucsi;
|
||||
int ret;
|
||||
|
||||
ucsi = devm_kzalloc(&pdev->dev, sizeof(*ucsi), GFP_KERNEL);
|
||||
if (!ucsi)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "missing memory resource\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: ACPI has claimed the memory region as it's also an Operation
|
||||
* Region. It's not possible to request it in the driver.
|
||||
*/
|
||||
ucsi->data = devm_ioremap(&pdev->dev, res->start, resource_size(res));
|
||||
if (!ucsi->data)
|
||||
return -ENOMEM;
|
||||
|
||||
ucsi->dev = &pdev->dev;
|
||||
|
||||
status = acpi_install_notify_handler(ACPI_HANDLE(&pdev->dev),
|
||||
ACPI_ALL_NOTIFY,
|
||||
ucsi_acpi_notify, ucsi);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -ENODEV;
|
||||
|
||||
ret = ucsi_init(ucsi);
|
||||
if (ret) {
|
||||
acpi_remove_notify_handler(ACPI_HANDLE(&pdev->dev),
|
||||
ACPI_ALL_NOTIFY,
|
||||
ucsi_acpi_notify);
|
||||
return ret;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, ucsi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ucsi_acpi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ucsi *ucsi = platform_get_drvdata(pdev);
|
||||
|
||||
acpi_remove_notify_handler(ACPI_HANDLE(&pdev->dev),
|
||||
ACPI_ALL_NOTIFY, ucsi_acpi_notify);
|
||||
|
||||
/* Make sure there are no events in the middle of being processed */
|
||||
if (wait_on_bit_timeout(&ucsi->flags, EVENT_PENDING,
|
||||
TASK_UNINTERRUPTIBLE,
|
||||
msecs_to_jiffies(UCSI_TIMEOUT_MS)))
|
||||
dev_WARN(ucsi->dev, "%s: Events still pending\n", __func__);
|
||||
|
||||
ucsi_reset_ppm(ucsi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct acpi_device_id ucsi_acpi_match[] = {
|
||||
{ "PNP0CA0", 0 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, ucsi_acpi_match);
|
||||
|
||||
static struct platform_driver ucsi_acpi_platform_driver = {
|
||||
.driver = {
|
||||
.name = "ucsi_acpi",
|
||||
.acpi_match_table = ACPI_PTR(ucsi_acpi_match),
|
||||
},
|
||||
.probe = ucsi_acpi_probe,
|
||||
.remove = ucsi_acpi_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(ucsi_acpi_platform_driver);
|
||||
|
||||
MODULE_AUTHOR("Heikki Krogerus <[email protected]>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("USB Type-C System Software Interface (UCSI) driver");
|
||||
215
drivers/usb/misc/ucsi.h
Normal file
215
drivers/usb/misc/ucsi.h
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
|
||||
#include <linux/types.h>
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/* Command Status and Connector Change Indication (CCI) data structure */
|
||||
struct ucsi_cci {
|
||||
unsigned int RESERVED1:1;
|
||||
unsigned int connector_change:7;
|
||||
u8 data_length;
|
||||
unsigned int RESERVED9:9;
|
||||
unsigned int not_supported:1;
|
||||
unsigned int cancel_complete:1;
|
||||
unsigned int reset_complete:1;
|
||||
unsigned int busy:1;
|
||||
unsigned int ack_complete:1;
|
||||
unsigned int error:1;
|
||||
unsigned int cmd_complete:1;
|
||||
} __packed;
|
||||
|
||||
/* Default fields in CONTROL data structure */
|
||||
struct ucsi_command {
|
||||
u8 cmd;
|
||||
u8 length;
|
||||
u64 data:48;
|
||||
} __packed;
|
||||
|
||||
/* Set USB Operation Mode Command structure */
|
||||
struct ucsi_uor_cmd {
|
||||
u8 cmd;
|
||||
u8 length;
|
||||
u64 con_num:7;
|
||||
u64 role:3;
|
||||
#define UCSI_UOR_ROLE_DFP BIT(0)
|
||||
#define UCSI_UOR_ROLE_UFP BIT(1)
|
||||
#define UCSI_UOR_ROLE_DRP BIT(2)
|
||||
u64 data:38;
|
||||
} __packed;
|
||||
|
||||
struct ucsi_control {
|
||||
union {
|
||||
u64 raw_cmd;
|
||||
struct ucsi_command cmd;
|
||||
struct ucsi_uor_cmd uor;
|
||||
};
|
||||
};
|
||||
|
||||
struct ucsi_data {
|
||||
u16 version;
|
||||
u16 RESERVED;
|
||||
union {
|
||||
u32 raw_cci;
|
||||
struct ucsi_cci cci;
|
||||
};
|
||||
struct ucsi_control ctrl;
|
||||
u32 message_in[4];
|
||||
u32 message_out[4];
|
||||
} __packed;
|
||||
|
||||
/* Commands */
|
||||
#define UCSI_PPM_RESET 0x01
|
||||
#define UCSI_CANCEL 0x02
|
||||
#define UCSI_CONNECTOR_RESET 0x03
|
||||
#define UCSI_ACK_CC_CI 0x04
|
||||
#define UCSI_SET_NOTIFICATION_ENABLE 0x05
|
||||
#define UCSI_GET_CAPABILITY 0x06
|
||||
#define UCSI_GET_CONNECTOR_CAPABILITY 0x07
|
||||
#define UCSI_SET_UOM 0x08
|
||||
#define UCSI_SET_UOR 0x09
|
||||
#define UCSI_SET_PDM 0x0A
|
||||
#define UCSI_SET_PDR 0x0B
|
||||
#define UCSI_GET_ALTERNATE_MODES 0x0C
|
||||
#define UCSI_GET_CAM_SUPPORTED 0x0D
|
||||
#define UCSI_GET_CURRENT_CAM 0x0E
|
||||
#define UCSI_SET_NEW_CAM 0x0F
|
||||
#define UCSI_GET_PDOS 0x10
|
||||
#define UCSI_GET_CABLE_PROPERTY 0x11
|
||||
#define UCSI_GET_CONNECTOR_STATUS 0x12
|
||||
#define UCSI_GET_ERROR_STATUS 0x13
|
||||
|
||||
/* ACK_CC_CI commands */
|
||||
#define UCSI_ACK_EVENT 1
|
||||
#define UCSI_ACK_CMD 2
|
||||
|
||||
/* Bits for SET_NOTIFICATION_ENABLE command */
|
||||
#define UCSI_ENABLE_NTFY_CMD_COMPLETE BIT(0)
|
||||
#define UCSI_ENABLE_NTFY_EXT_PWR_SRC_CHANGE BIT(1)
|
||||
#define UCSI_ENABLE_NTFY_PWR_OPMODE_CHANGE BIT(2)
|
||||
#define UCSI_ENABLE_NTFY_CAP_CHANGE BIT(5)
|
||||
#define UCSI_ENABLE_NTFY_PWR_LEVEL_CHANGE BIT(6)
|
||||
#define UCSI_ENABLE_NTFY_PD_RESET_COMPLETE BIT(7)
|
||||
#define UCSI_ENABLE_NTFY_CAM_CHANGE BIT(8)
|
||||
#define UCSI_ENABLE_NTFY_BAT_STATUS_CHANGE BIT(9)
|
||||
#define UCSI_ENABLE_NTFY_PARTNER_CHANGE BIT(11)
|
||||
#define UCSI_ENABLE_NTFY_PWR_DIR_CHANGE BIT(12)
|
||||
#define UCSI_ENABLE_NTFY_CONNECTOR_CHANGE BIT(14)
|
||||
#define UCSI_ENABLE_NTFY_ERROR BIT(15)
|
||||
#define UCSI_ENABLE_NTFY_ALL 0xdbe7
|
||||
|
||||
/* Error information returned by PPM in response to GET_ERROR_STATUS command. */
|
||||
#define UCSI_ERROR_UNREGONIZED_CMD BIT(0)
|
||||
#define UCSI_ERROR_INVALID_CON_NUM BIT(1)
|
||||
#define UCSI_ERROR_INVALID_CMD_ARGUMENT BIT(2)
|
||||
#define UCSI_ERROR_INCOMPATIBLE_PARTNER BIT(3)
|
||||
#define UCSI_ERROR_CC_COMMUNICATION_ERR BIT(4)
|
||||
#define UCSI_ERROR_DEAD_BATTERY BIT(5)
|
||||
#define UCSI_ERROR_CONTRACT_NEGOTIATION_FAIL BIT(6)
|
||||
|
||||
/* Data structure filled by PPM in response to GET_CAPABILITY command. */
|
||||
struct ucsi_capability {
|
||||
u32 attributes;
|
||||
#define UCSI_CAP_ATTR_DISABLE_STATE BIT(0)
|
||||
#define UCSI_CAP_ATTR_BATTERY_CHARGING BIT(1)
|
||||
#define UCSI_CAP_ATTR_USB_PD BIT(2)
|
||||
#define UCSI_CAP_ATTR_TYPEC_CURRENT BIT(6)
|
||||
#define UCSI_CAP_ATTR_POWER_AC_SUPPLY BIT(8)
|
||||
#define UCSI_CAP_ATTR_POWER_OTHER BIT(10)
|
||||
#define UCSI_CAP_ATTR_POWER_VBUS BIT(14)
|
||||
u8 num_connectors;
|
||||
u32 features:24;
|
||||
#define UCSI_CAP_SET_UOM BIT(0)
|
||||
#define UCSI_CAP_SET_PDM BIT(1)
|
||||
#define UCSI_CAP_ALT_MODE_DETAILS BIT(2)
|
||||
#define UCSI_CAP_ALT_MODE_OVERRIDE BIT(3)
|
||||
#define UCSI_CAP_PDO_DETAILS BIT(4)
|
||||
#define UCSI_CAP_CABLE_DETAILS BIT(5)
|
||||
#define UCSI_CAP_EXT_SUPPLY_NOTIFICATIONS BIT(6)
|
||||
#define UCSI_CAP_PD_RESET BIT(7)
|
||||
u8 num_alt_modes;
|
||||
u8 RESERVED;
|
||||
u16 bc_version;
|
||||
u16 pd_version;
|
||||
u16 typec_version;
|
||||
} __packed;
|
||||
|
||||
/* Data structure filled by PPM in response to GET_CONNECTOR_CAPABILITY cmd. */
|
||||
struct ucsi_connector_capability {
|
||||
u8 op_mode;
|
||||
#define UCSI_CONCAP_OPMODE_DFP BIT(0)
|
||||
#define UCSI_CONCAP_OPMODE_UFP BIT(1)
|
||||
#define UCSI_CONCAP_OPMODE_DRP BIT(2)
|
||||
#define UCSI_CONCAP_OPMODE_AUDIO_ACCESSORY BIT(3)
|
||||
#define UCSI_CONCAP_OPMODE_DEBUG_ACCESSORY BIT(4)
|
||||
#define UCSI_CONCAP_OPMODE_USB2 BIT(5)
|
||||
#define UCSI_CONCAP_OPMODE_USB3 BIT(6)
|
||||
#define UCSI_CONCAP_OPMODE_ALT_MODE BIT(7)
|
||||
u8 provider:1;
|
||||
u8 consumer:1;
|
||||
} __packed;
|
||||
|
||||
/* Data structure filled by PPM in response to GET_CABLE_PROPERTY command. */
|
||||
struct ucsi_cable_property {
|
||||
u16 speed_supported;
|
||||
u8 current_capability;
|
||||
u8 vbus_in_cable:1;
|
||||
u8 active_cable:1;
|
||||
u8 directionality:1;
|
||||
u8 plug_type:2;
|
||||
#define UCSI_CABLE_PROPERTY_PLUG_TYPE_A 0
|
||||
#define UCSI_CABLE_PROPERTY_PLUG_TYPE_B 1
|
||||
#define UCSI_CABLE_PROPERTY_PLUG_TYPE_C 2
|
||||
#define UCSI_CABLE_PROPERTY_PLUG_OTHER 3
|
||||
u8 mode_support:1;
|
||||
u8 RESERVED_2:2;
|
||||
u8 latency:4;
|
||||
u8 RESERVED_4:4;
|
||||
} __packed;
|
||||
|
||||
/* Data structure filled by PPM in response to GET_CONNECTOR_STATUS command. */
|
||||
struct ucsi_connector_status {
|
||||
u16 change;
|
||||
#define UCSI_CONSTAT_EXT_SUPPLY_CHANGE BIT(1)
|
||||
#define UCSI_CONSTAT_POWER_OPMODE_CHANGE BIT(2)
|
||||
#define UCSI_CONSTAT_PDOS_CHANGE BIT(5)
|
||||
#define UCSI_CONSTAT_POWER_LEVEL_CHANGE BIT(6)
|
||||
#define UCSI_CONSTAT_PD_RESET_COMPLETE BIT(7)
|
||||
#define UCSI_CONSTAT_CAM_CHANGE BIT(8)
|
||||
#define UCSI_CONSTAT_BC_CHANGE BIT(9)
|
||||
#define UCSI_CONSTAT_PARTNER_CHANGE BIT(11)
|
||||
#define UCSI_CONSTAT_POWER_DIR_CHANGE BIT(12)
|
||||
#define UCSI_CONSTAT_CONNECT_CHANGE BIT(14)
|
||||
#define UCSI_CONSTAT_ERROR BIT(15)
|
||||
u16 pwr_op_mode:3;
|
||||
#define UCSI_CONSTAT_PWR_OPMODE_NONE 0
|
||||
#define UCSI_CONSTAT_PWR_OPMODE_DEFAULT 1
|
||||
#define UCSI_CONSTAT_PWR_OPMODE_BC 2
|
||||
#define UCSI_CONSTAT_PWR_OPMODE_PD 3
|
||||
#define UCSI_CONSTAT_PWR_OPMODE_TYPEC1_3 4
|
||||
#define UCSI_CONSTAT_PWR_OPMODE_TYPEC3_0 5
|
||||
u16 connected:1;
|
||||
u16 pwr_dir:1;
|
||||
u16 partner_flags:8;
|
||||
#define UCSI_CONSTAT_PARTNER_FLAG_USB BIT(0)
|
||||
#define UCSI_CONSTAT_PARTNER_FLAG_ALT_MODE BIT(1)
|
||||
u16 partner_type:3;
|
||||
#define UCSI_CONSTAT_PARTNER_TYPE_DFP 1
|
||||
#define UCSI_CONSTAT_PARTNER_TYPE_UFP 2
|
||||
#define UCSI_CONSTAT_PARTNER_TYPE_CABLE_NO_UFP 3 /* Powered Cable */
|
||||
#define UCSI_CONSTAT_PARTNER_TYPE_CABLE_AND_UFP 4 /* Powered Cable */
|
||||
#define UCSI_CONSTAT_PARTNER_TYPE_DEBUG 5
|
||||
#define UCSI_CONSTAT_PARTNER_TYPE_AUDIO 6
|
||||
u32 request_data_obj;
|
||||
u8 bc_status:2;
|
||||
#define UCSI_CONSTAT_BC_NOT_CHARGING 0
|
||||
#define UCSI_CONSTAT_BC_NOMINAL_CHARGING 1
|
||||
#define UCSI_CONSTAT_BC_SLOW_CHARGING 2
|
||||
#define UCSI_CONSTAT_BC_TRICKLE_CHARGING 3
|
||||
u8 provider_cap_limit_reason:4;
|
||||
#define UCSI_CONSTAT_CAP_PWR_LOWERED 0
|
||||
#define UCSI_CONSTAT_CAP_PWR_BUDGET_LIMIT 1
|
||||
u8 RESERVED:2;
|
||||
} __packed;
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
|
|
@ -287,6 +287,9 @@ static struct urb *usbtest_alloc_urb(
|
|||
if (usb_pipein(pipe))
|
||||
urb->transfer_flags |= URB_SHORT_NOT_OK;
|
||||
|
||||
if ((bytes + offset) == 0)
|
||||
return urb;
|
||||
|
||||
if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
|
||||
urb->transfer_buffer = usb_alloc_coherent(udev, bytes + offset,
|
||||
GFP_KERNEL, &urb->transfer_dma);
|
||||
|
|
@ -529,6 +532,7 @@ static struct scatterlist *
|
|||
alloc_sglist(int nents, int max, int vary, struct usbtest_dev *dev, int pipe)
|
||||
{
|
||||
struct scatterlist *sg;
|
||||
unsigned int n_size = 0;
|
||||
unsigned i;
|
||||
unsigned size = max;
|
||||
unsigned maxpacket =
|
||||
|
|
@ -561,7 +565,8 @@ alloc_sglist(int nents, int max, int vary, struct usbtest_dev *dev, int pipe)
|
|||
break;
|
||||
case 1:
|
||||
for (j = 0; j < size; j++)
|
||||
*buf++ = (u8) ((j % maxpacket) % 63);
|
||||
*buf++ = (u8) (((j + n_size) % maxpacket) % 63);
|
||||
n_size += size;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -240,10 +240,7 @@ static int phy_8x16_read_devicetree(struct phy_8x16 *qphy)
|
|||
|
||||
qphy->switch_gpio = devm_gpiod_get_optional(dev, "switch",
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(qphy->switch_gpio))
|
||||
return PTR_ERR(qphy->switch_gpio);
|
||||
|
||||
return 0;
|
||||
return PTR_ERR_OR_ZERO(qphy->switch_gpio);
|
||||
}
|
||||
|
||||
static int phy_8x16_reboot_notify(struct notifier_block *this,
|
||||
|
|
|
|||
|
|
@ -155,13 +155,13 @@ static int twl6030_start_srp(struct phy_companion *comparator)
|
|||
static int twl6030_usb_ldo_init(struct twl6030_usb *twl)
|
||||
{
|
||||
/* Set to OTG_REV 1.3 and turn on the ID_WAKEUP_COMP */
|
||||
twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x1, TWL6030_BACKUP_REG);
|
||||
twl6030_writeb(twl, TWL6030_MODULE_ID0, 0x1, TWL6030_BACKUP_REG);
|
||||
|
||||
/* Program CFG_LDO_PD2 register and set VUSB bit */
|
||||
twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x1, TWL6030_CFG_LDO_PD2);
|
||||
twl6030_writeb(twl, TWL6030_MODULE_ID0, 0x1, TWL6030_CFG_LDO_PD2);
|
||||
|
||||
/* Program MISC2 register and set bit VUSB_IN_VBAT */
|
||||
twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x10, TWL6030_MISC2);
|
||||
twl6030_writeb(twl, TWL6030_MODULE_ID0, 0x10, TWL6030_MISC2);
|
||||
|
||||
twl->usb3v3 = regulator_get(twl->dev, twl->regulator);
|
||||
if (IS_ERR(twl->usb3v3))
|
||||
|
|
@ -301,10 +301,10 @@ static void otg_set_vbus_work(struct work_struct *data)
|
|||
*/
|
||||
|
||||
if (twl->vbus_enable)
|
||||
twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE , 0x40,
|
||||
twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE, 0x40,
|
||||
CHARGERUSB_CTRL1);
|
||||
else
|
||||
twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE , 0x00,
|
||||
twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE, 0x00,
|
||||
CHARGERUSB_CTRL1);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -799,8 +799,10 @@ static int __usbhsf_dma_map_ctrl(struct usbhs_pkt *pkt, int map)
|
|||
struct usbhs_pipe *pipe = pkt->pipe;
|
||||
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
|
||||
struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv);
|
||||
struct usbhs_fifo *fifo = usbhs_pipe_to_fifo(pipe);
|
||||
struct dma_chan *chan = usbhsf_dma_chan_get(fifo, pkt);
|
||||
|
||||
return info->dma_map_ctrl(pkt, map);
|
||||
return info->dma_map_ctrl(chan->device->dev, pkt, map);
|
||||
}
|
||||
|
||||
static void usbhsf_dma_complete(void *arg);
|
||||
|
|
@ -881,12 +883,12 @@ static int usbhsf_dma_prepare_push(struct usbhs_pkt *pkt, int *is_done)
|
|||
if (!fifo)
|
||||
goto usbhsf_pio_prepare_push;
|
||||
|
||||
if (usbhsf_dma_map(pkt) < 0)
|
||||
goto usbhsf_pio_prepare_push;
|
||||
|
||||
ret = usbhsf_fifo_select(pipe, fifo, 0);
|
||||
if (ret < 0)
|
||||
goto usbhsf_pio_prepare_push_unmap;
|
||||
goto usbhsf_pio_prepare_push;
|
||||
|
||||
if (usbhsf_dma_map(pkt) < 0)
|
||||
goto usbhsf_pio_prepare_push_unselect;
|
||||
|
||||
pkt->trans = len;
|
||||
|
||||
|
|
@ -896,8 +898,8 @@ static int usbhsf_dma_prepare_push(struct usbhs_pkt *pkt, int *is_done)
|
|||
|
||||
return 0;
|
||||
|
||||
usbhsf_pio_prepare_push_unmap:
|
||||
usbhsf_dma_unmap(pkt);
|
||||
usbhsf_pio_prepare_push_unselect:
|
||||
usbhsf_fifo_unselect(pipe, fifo);
|
||||
usbhsf_pio_prepare_push:
|
||||
/*
|
||||
* change handler to PIO
|
||||
|
|
|
|||
|
|
@ -191,13 +191,12 @@ static void usbhsg_queue_push(struct usbhsg_uep *uep,
|
|||
/*
|
||||
* dma map/unmap
|
||||
*/
|
||||
static int usbhsg_dma_map_ctrl(struct usbhs_pkt *pkt, int map)
|
||||
static int usbhsg_dma_map_ctrl(struct device *dma_dev, struct usbhs_pkt *pkt,
|
||||
int map)
|
||||
{
|
||||
struct usbhsg_request *ureq = usbhsg_pkt_to_ureq(pkt);
|
||||
struct usb_request *req = &ureq->req;
|
||||
struct usbhs_pipe *pipe = pkt->pipe;
|
||||
struct usbhsg_uep *uep = usbhsg_pipe_to_uep(pipe);
|
||||
struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep);
|
||||
enum dma_data_direction dir;
|
||||
int ret = 0;
|
||||
|
||||
|
|
@ -207,13 +206,13 @@ static int usbhsg_dma_map_ctrl(struct usbhs_pkt *pkt, int map)
|
|||
/* it can not use scatter/gather */
|
||||
WARN_ON(req->num_sgs);
|
||||
|
||||
ret = usb_gadget_map_request(&gpriv->gadget, req, dir);
|
||||
ret = usb_gadget_map_request_by_dev(dma_dev, req, dir);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
pkt->dma = req->dma;
|
||||
} else {
|
||||
usb_gadget_unmap_request(&gpriv->gadget, req, dir);
|
||||
usb_gadget_unmap_request_by_dev(dma_dev, req, dir);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -929,7 +929,8 @@ static int usbhsh_dcp_queue_push(struct usb_hcd *hcd,
|
|||
/*
|
||||
* dma map functions
|
||||
*/
|
||||
static int usbhsh_dma_map_ctrl(struct usbhs_pkt *pkt, int map)
|
||||
static int usbhsh_dma_map_ctrl(struct device *dma_dev, struct usbhs_pkt *pkt,
|
||||
int map)
|
||||
{
|
||||
if (map) {
|
||||
struct usbhsh_request *ureq = usbhsh_pkt_to_ureq(pkt);
|
||||
|
|
|
|||
|
|
@ -391,9 +391,8 @@ void usbhs_pipe_set_trans_count_if_bulk(struct usbhs_pipe *pipe, int len)
|
|||
/*
|
||||
* pipe setup
|
||||
*/
|
||||
static u16 usbhsp_setup_pipecfg(struct usbhs_pipe *pipe,
|
||||
int is_host,
|
||||
int dir_in)
|
||||
static int usbhsp_setup_pipecfg(struct usbhs_pipe *pipe, int is_host,
|
||||
int dir_in, u16 *pipecfg)
|
||||
{
|
||||
u16 type = 0;
|
||||
u16 bfre = 0;
|
||||
|
|
@ -451,14 +450,14 @@ static u16 usbhsp_setup_pipecfg(struct usbhs_pipe *pipe,
|
|||
|
||||
/* EPNUM */
|
||||
epnum = 0; /* see usbhs_pipe_config_update() */
|
||||
|
||||
return type |
|
||||
bfre |
|
||||
dblb |
|
||||
cntmd |
|
||||
dir |
|
||||
shtnak |
|
||||
epnum;
|
||||
*pipecfg = type |
|
||||
bfre |
|
||||
dblb |
|
||||
cntmd |
|
||||
dir |
|
||||
shtnak |
|
||||
epnum;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u16 usbhsp_setup_pipebuff(struct usbhs_pipe *pipe)
|
||||
|
|
@ -655,7 +654,8 @@ static void usbhsp_put_pipe(struct usbhs_pipe *pipe)
|
|||
}
|
||||
|
||||
void usbhs_pipe_init(struct usbhs_priv *priv,
|
||||
int (*dma_map_ctrl)(struct usbhs_pkt *pkt, int map))
|
||||
int (*dma_map_ctrl)(struct device *dma_dev,
|
||||
struct usbhs_pkt *pkt, int map))
|
||||
{
|
||||
struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv);
|
||||
struct usbhs_pipe *pipe;
|
||||
|
|
@ -702,7 +702,11 @@ struct usbhs_pipe *usbhs_pipe_malloc(struct usbhs_priv *priv,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
pipecfg = usbhsp_setup_pipecfg(pipe, is_host, dir_in);
|
||||
if (usbhsp_setup_pipecfg(pipe, is_host, dir_in, &pipecfg)) {
|
||||
dev_err(dev, "can't setup pipe\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pipebuf = usbhsp_setup_pipebuff(pipe);
|
||||
|
||||
usbhsp_pipe_select(pipe);
|
||||
|
|
|
|||
|
|
@ -47,7 +47,8 @@ struct usbhs_pipe_info {
|
|||
struct usbhs_pipe *pipe;
|
||||
int size; /* array size of "pipe" */
|
||||
|
||||
int (*dma_map_ctrl)(struct usbhs_pkt *pkt, int map);
|
||||
int (*dma_map_ctrl)(struct device *dma_dev, struct usbhs_pkt *pkt,
|
||||
int map);
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -84,7 +85,8 @@ int usbhs_pipe_is_running(struct usbhs_pipe *pipe);
|
|||
void usbhs_pipe_running(struct usbhs_pipe *pipe, int running);
|
||||
|
||||
void usbhs_pipe_init(struct usbhs_priv *priv,
|
||||
int (*dma_map_ctrl)(struct usbhs_pkt *pkt, int map));
|
||||
int (*dma_map_ctrl)(struct device *dma_dev,
|
||||
struct usbhs_pkt *pkt, int map));
|
||||
int usbhs_pipe_get_maxpacket(struct usbhs_pipe *pipe);
|
||||
void usbhs_pipe_clear(struct usbhs_pipe *pipe);
|
||||
int usbhs_pipe_is_accessible(struct usbhs_pipe *pipe);
|
||||
|
|
|
|||
|
|
@ -331,6 +331,42 @@ struct cp210x_comm_status {
|
|||
*/
|
||||
#define PURGE_ALL 0x000f
|
||||
|
||||
/* CP210X_GET_FLOW/CP210X_SET_FLOW read/write these 0x10 bytes */
|
||||
struct cp210x_flow_ctl {
|
||||
__le32 ulControlHandshake;
|
||||
__le32 ulFlowReplace;
|
||||
__le32 ulXonLimit;
|
||||
__le32 ulXoffLimit;
|
||||
} __packed;
|
||||
|
||||
/* cp210x_flow_ctl::ulControlHandshake */
|
||||
#define CP210X_SERIAL_DTR_MASK GENMASK(1, 0)
|
||||
#define CP210X_SERIAL_DTR_SHIFT(_mode) (_mode)
|
||||
#define CP210X_SERIAL_CTS_HANDSHAKE BIT(3)
|
||||
#define CP210X_SERIAL_DSR_HANDSHAKE BIT(4)
|
||||
#define CP210X_SERIAL_DCD_HANDSHAKE BIT(5)
|
||||
#define CP210X_SERIAL_DSR_SENSITIVITY BIT(6)
|
||||
|
||||
/* values for cp210x_flow_ctl::ulControlHandshake::CP210X_SERIAL_DTR_MASK */
|
||||
#define CP210X_SERIAL_DTR_INACTIVE 0
|
||||
#define CP210X_SERIAL_DTR_ACTIVE 1
|
||||
#define CP210X_SERIAL_DTR_FLOW_CTL 2
|
||||
|
||||
/* cp210x_flow_ctl::ulFlowReplace */
|
||||
#define CP210X_SERIAL_AUTO_TRANSMIT BIT(0)
|
||||
#define CP210X_SERIAL_AUTO_RECEIVE BIT(1)
|
||||
#define CP210X_SERIAL_ERROR_CHAR BIT(2)
|
||||
#define CP210X_SERIAL_NULL_STRIPPING BIT(3)
|
||||
#define CP210X_SERIAL_BREAK_CHAR BIT(4)
|
||||
#define CP210X_SERIAL_RTS_MASK GENMASK(7, 6)
|
||||
#define CP210X_SERIAL_RTS_SHIFT(_mode) (_mode << 6)
|
||||
#define CP210X_SERIAL_XOFF_CONTINUE BIT(31)
|
||||
|
||||
/* values for cp210x_flow_ctl::ulFlowReplace::CP210X_SERIAL_RTS_MASK */
|
||||
#define CP210X_SERIAL_RTS_INACTIVE 0
|
||||
#define CP210X_SERIAL_RTS_ACTIVE 1
|
||||
#define CP210X_SERIAL_RTS_FLOW_CTL 2
|
||||
|
||||
/*
|
||||
* Reads a variable-sized block of CP210X_ registers, identified by req.
|
||||
* Returns data into buf in native USB byte order.
|
||||
|
|
@ -698,9 +734,10 @@ static void cp210x_get_termios_port(struct usb_serial_port *port,
|
|||
{
|
||||
struct device *dev = &port->dev;
|
||||
unsigned int cflag;
|
||||
u8 modem_ctl[16];
|
||||
struct cp210x_flow_ctl flow_ctl;
|
||||
u32 baud;
|
||||
u16 bits;
|
||||
u32 ctl_hs;
|
||||
|
||||
cp210x_read_u32_reg(port, CP210X_GET_BAUDRATE, &baud);
|
||||
|
||||
|
|
@ -796,9 +833,10 @@ static void cp210x_get_termios_port(struct usb_serial_port *port,
|
|||
break;
|
||||
}
|
||||
|
||||
cp210x_read_reg_block(port, CP210X_GET_FLOW, modem_ctl,
|
||||
sizeof(modem_ctl));
|
||||
if (modem_ctl[0] & 0x08) {
|
||||
cp210x_read_reg_block(port, CP210X_GET_FLOW, &flow_ctl,
|
||||
sizeof(flow_ctl));
|
||||
ctl_hs = le32_to_cpu(flow_ctl.ulControlHandshake);
|
||||
if (ctl_hs & CP210X_SERIAL_CTS_HANDSHAKE) {
|
||||
dev_dbg(dev, "%s - flow control = CRTSCTS\n", __func__);
|
||||
cflag |= CRTSCTS;
|
||||
} else {
|
||||
|
|
@ -867,7 +905,6 @@ static void cp210x_set_termios(struct tty_struct *tty,
|
|||
struct device *dev = &port->dev;
|
||||
unsigned int cflag, old_cflag;
|
||||
u16 bits;
|
||||
u8 modem_ctl[16];
|
||||
|
||||
cflag = tty->termios.c_cflag;
|
||||
old_cflag = old_termios->c_cflag;
|
||||
|
|
@ -951,35 +988,44 @@ static void cp210x_set_termios(struct tty_struct *tty,
|
|||
}
|
||||
|
||||
if ((cflag & CRTSCTS) != (old_cflag & CRTSCTS)) {
|
||||
struct cp210x_flow_ctl flow_ctl;
|
||||
u32 ctl_hs;
|
||||
u32 flow_repl;
|
||||
|
||||
/* Only bytes 0, 4 and 7 out of first 8 have functional bits */
|
||||
|
||||
cp210x_read_reg_block(port, CP210X_GET_FLOW, modem_ctl,
|
||||
sizeof(modem_ctl));
|
||||
dev_dbg(dev, "%s - read modem controls = %02x .. .. .. %02x .. .. %02x\n",
|
||||
__func__, modem_ctl[0], modem_ctl[4], modem_ctl[7]);
|
||||
cp210x_read_reg_block(port, CP210X_GET_FLOW, &flow_ctl,
|
||||
sizeof(flow_ctl));
|
||||
ctl_hs = le32_to_cpu(flow_ctl.ulControlHandshake);
|
||||
flow_repl = le32_to_cpu(flow_ctl.ulFlowReplace);
|
||||
dev_dbg(dev, "%s - read ulControlHandshake=0x%08x, ulFlowReplace=0x%08x\n",
|
||||
__func__, ctl_hs, flow_repl);
|
||||
|
||||
ctl_hs &= ~CP210X_SERIAL_DSR_HANDSHAKE;
|
||||
ctl_hs &= ~CP210X_SERIAL_DCD_HANDSHAKE;
|
||||
ctl_hs &= ~CP210X_SERIAL_DSR_SENSITIVITY;
|
||||
ctl_hs &= ~CP210X_SERIAL_DTR_MASK;
|
||||
ctl_hs |= CP210X_SERIAL_DTR_SHIFT(CP210X_SERIAL_DTR_ACTIVE);
|
||||
if (cflag & CRTSCTS) {
|
||||
modem_ctl[0] &= ~0x7B;
|
||||
modem_ctl[0] |= 0x09;
|
||||
modem_ctl[4] = 0x80;
|
||||
/* FIXME - why clear reserved bits just read? */
|
||||
modem_ctl[5] = 0;
|
||||
modem_ctl[6] = 0;
|
||||
modem_ctl[7] = 0;
|
||||
ctl_hs |= CP210X_SERIAL_CTS_HANDSHAKE;
|
||||
|
||||
flow_repl &= ~CP210X_SERIAL_RTS_MASK;
|
||||
flow_repl |= CP210X_SERIAL_RTS_SHIFT(
|
||||
CP210X_SERIAL_RTS_FLOW_CTL);
|
||||
dev_dbg(dev, "%s - flow control = CRTSCTS\n", __func__);
|
||||
} else {
|
||||
modem_ctl[0] &= ~0x7B;
|
||||
modem_ctl[0] |= 0x01;
|
||||
/* FIXME - OR here instead of assignment looks wrong */
|
||||
modem_ctl[4] |= 0x40;
|
||||
ctl_hs &= ~CP210X_SERIAL_CTS_HANDSHAKE;
|
||||
|
||||
flow_repl &= ~CP210X_SERIAL_RTS_MASK;
|
||||
flow_repl |= CP210X_SERIAL_RTS_SHIFT(
|
||||
CP210X_SERIAL_RTS_ACTIVE);
|
||||
dev_dbg(dev, "%s - flow control = NONE\n", __func__);
|
||||
}
|
||||
|
||||
dev_dbg(dev, "%s - write modem controls = %02x .. .. .. %02x .. .. %02x\n",
|
||||
__func__, modem_ctl[0], modem_ctl[4], modem_ctl[7]);
|
||||
cp210x_write_reg_block(port, CP210X_SET_FLOW, modem_ctl,
|
||||
sizeof(modem_ctl));
|
||||
dev_dbg(dev, "%s - write ulControlHandshake=0x%08x, ulFlowReplace=0x%08x\n",
|
||||
__func__, ctl_hs, flow_repl);
|
||||
flow_ctl.ulControlHandshake = cpu_to_le32(ctl_hs);
|
||||
flow_ctl.ulFlowReplace = cpu_to_le32(flow_repl);
|
||||
cp210x_write_reg_block(port, CP210X_SET_FLOW, &flow_ctl,
|
||||
sizeof(flow_ctl));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,27 +93,27 @@ static int ftdi_8u2232c_probe(struct usb_serial *serial);
|
|||
static void ftdi_USB_UIRT_setup(struct ftdi_private *priv);
|
||||
static void ftdi_HE_TIRA1_setup(struct ftdi_private *priv);
|
||||
|
||||
static struct ftdi_sio_quirk ftdi_jtag_quirk = {
|
||||
static const struct ftdi_sio_quirk ftdi_jtag_quirk = {
|
||||
.probe = ftdi_jtag_probe,
|
||||
};
|
||||
|
||||
static struct ftdi_sio_quirk ftdi_NDI_device_quirk = {
|
||||
static const struct ftdi_sio_quirk ftdi_NDI_device_quirk = {
|
||||
.probe = ftdi_NDI_device_setup,
|
||||
};
|
||||
|
||||
static struct ftdi_sio_quirk ftdi_USB_UIRT_quirk = {
|
||||
static const struct ftdi_sio_quirk ftdi_USB_UIRT_quirk = {
|
||||
.port_probe = ftdi_USB_UIRT_setup,
|
||||
};
|
||||
|
||||
static struct ftdi_sio_quirk ftdi_HE_TIRA1_quirk = {
|
||||
static const struct ftdi_sio_quirk ftdi_HE_TIRA1_quirk = {
|
||||
.port_probe = ftdi_HE_TIRA1_setup,
|
||||
};
|
||||
|
||||
static struct ftdi_sio_quirk ftdi_stmclite_quirk = {
|
||||
static const struct ftdi_sio_quirk ftdi_stmclite_quirk = {
|
||||
.probe = ftdi_stmclite_probe,
|
||||
};
|
||||
|
||||
static struct ftdi_sio_quirk ftdi_8u2232c_quirk = {
|
||||
static const struct ftdi_sio_quirk ftdi_8u2232c_quirk = {
|
||||
.probe = ftdi_8u2232c_probe,
|
||||
};
|
||||
|
||||
|
|
@ -1775,7 +1775,7 @@ static void remove_sysfs_attrs(struct usb_serial_port *port)
|
|||
static int ftdi_sio_probe(struct usb_serial *serial,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct ftdi_sio_quirk *quirk =
|
||||
const struct ftdi_sio_quirk *quirk =
|
||||
(struct ftdi_sio_quirk *)id->driver_info;
|
||||
|
||||
if (quirk && quirk->probe) {
|
||||
|
|
@ -1792,7 +1792,7 @@ static int ftdi_sio_probe(struct usb_serial *serial,
|
|||
static int ftdi_sio_port_probe(struct usb_serial_port *port)
|
||||
{
|
||||
struct ftdi_private *priv;
|
||||
struct ftdi_sio_quirk *quirk = usb_get_serial_data(port->serial);
|
||||
const struct ftdi_sio_quirk *quirk = usb_get_serial_data(port->serial);
|
||||
|
||||
|
||||
priv = kzalloc(sizeof(struct ftdi_private), GFP_KERNEL);
|
||||
|
|
|
|||
|
|
@ -2849,14 +2849,16 @@ static int edge_startup(struct usb_serial *serial)
|
|||
/* not set up yet, so do it now */
|
||||
edge_serial->interrupt_read_urb =
|
||||
usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!edge_serial->interrupt_read_urb)
|
||||
return -ENOMEM;
|
||||
if (!edge_serial->interrupt_read_urb) {
|
||||
response = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
edge_serial->interrupt_in_buffer =
|
||||
kmalloc(buffer_size, GFP_KERNEL);
|
||||
if (!edge_serial->interrupt_in_buffer) {
|
||||
usb_free_urb(edge_serial->interrupt_read_urb);
|
||||
return -ENOMEM;
|
||||
response = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
edge_serial->interrupt_in_endpoint =
|
||||
endpoint->bEndpointAddress;
|
||||
|
|
@ -2884,14 +2886,16 @@ static int edge_startup(struct usb_serial *serial)
|
|||
/* not set up yet, so do it now */
|
||||
edge_serial->read_urb =
|
||||
usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!edge_serial->read_urb)
|
||||
return -ENOMEM;
|
||||
if (!edge_serial->read_urb) {
|
||||
response = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
edge_serial->bulk_in_buffer =
|
||||
kmalloc(buffer_size, GFP_KERNEL);
|
||||
if (!edge_serial->bulk_in_buffer) {
|
||||
usb_free_urb(edge_serial->read_urb);
|
||||
return -ENOMEM;
|
||||
response = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
edge_serial->bulk_in_endpoint =
|
||||
endpoint->bEndpointAddress;
|
||||
|
|
@ -2917,9 +2921,22 @@ static int edge_startup(struct usb_serial *serial)
|
|||
}
|
||||
}
|
||||
|
||||
if (!interrupt_in_found || !bulk_in_found || !bulk_out_found) {
|
||||
dev_err(ddev, "Error - the proper endpoints were not found!\n");
|
||||
return -ENODEV;
|
||||
if (response || !interrupt_in_found || !bulk_in_found ||
|
||||
!bulk_out_found) {
|
||||
if (!response) {
|
||||
dev_err(ddev, "expected endpoints not found\n");
|
||||
response = -ENODEV;
|
||||
}
|
||||
|
||||
usb_free_urb(edge_serial->interrupt_read_urb);
|
||||
kfree(edge_serial->interrupt_in_buffer);
|
||||
|
||||
usb_free_urb(edge_serial->read_urb);
|
||||
kfree(edge_serial->bulk_in_buffer);
|
||||
|
||||
kfree(edge_serial);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/* start interrupt read for this edgeport this interrupt will
|
||||
|
|
@ -2942,16 +2959,9 @@ static void edge_disconnect(struct usb_serial *serial)
|
|||
{
|
||||
struct edgeport_serial *edge_serial = usb_get_serial_data(serial);
|
||||
|
||||
/* stop reads and writes on all ports */
|
||||
/* free up our endpoint stuff */
|
||||
if (edge_serial->is_epic) {
|
||||
usb_kill_urb(edge_serial->interrupt_read_urb);
|
||||
usb_free_urb(edge_serial->interrupt_read_urb);
|
||||
kfree(edge_serial->interrupt_in_buffer);
|
||||
|
||||
usb_kill_urb(edge_serial->read_urb);
|
||||
usb_free_urb(edge_serial->read_urb);
|
||||
kfree(edge_serial->bulk_in_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2964,6 +2974,16 @@ static void edge_release(struct usb_serial *serial)
|
|||
{
|
||||
struct edgeport_serial *edge_serial = usb_get_serial_data(serial);
|
||||
|
||||
if (edge_serial->is_epic) {
|
||||
usb_kill_urb(edge_serial->interrupt_read_urb);
|
||||
usb_free_urb(edge_serial->interrupt_read_urb);
|
||||
kfree(edge_serial->interrupt_in_buffer);
|
||||
|
||||
usb_kill_urb(edge_serial->read_urb);
|
||||
usb_free_urb(edge_serial->read_urb);
|
||||
kfree(edge_serial->bulk_in_buffer);
|
||||
}
|
||||
|
||||
kfree(edge_serial);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -255,7 +255,7 @@ static int keyspan_write(struct tty_struct *tty,
|
|||
return count;
|
||||
}
|
||||
|
||||
dev_dbg(&port->dev, "%s - endpoint %d flip %d\n",
|
||||
dev_dbg(&port->dev, "%s - endpoint %x flip %d\n",
|
||||
__func__, usb_pipeendpoint(this_urb->pipe), flip);
|
||||
|
||||
if (this_urb->status == -EINPROGRESS) {
|
||||
|
|
@ -300,7 +300,7 @@ static void usa26_indat_callback(struct urb *urb)
|
|||
endpoint = usb_pipeendpoint(urb->pipe);
|
||||
|
||||
if (status) {
|
||||
dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
|
||||
dev_dbg(&urb->dev->dev, "%s - nonzero status %d on endpoint %x\n",
|
||||
__func__, status, endpoint);
|
||||
return;
|
||||
}
|
||||
|
|
@ -393,7 +393,8 @@ static void usa26_instat_callback(struct urb *urb)
|
|||
serial = urb->context;
|
||||
|
||||
if (status) {
|
||||
dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
|
||||
dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n",
|
||||
__func__, status);
|
||||
return;
|
||||
}
|
||||
if (urb->actual_length != 9) {
|
||||
|
|
@ -452,7 +453,7 @@ static void usa28_indat_callback(struct urb *urb)
|
|||
|
||||
do {
|
||||
if (status) {
|
||||
dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
|
||||
dev_dbg(&urb->dev->dev, "%s - nonzero status %d on endpoint %x\n",
|
||||
__func__, status, usb_pipeendpoint(urb->pipe));
|
||||
return;
|
||||
}
|
||||
|
|
@ -511,7 +512,8 @@ static void usa28_instat_callback(struct urb *urb)
|
|||
serial = urb->context;
|
||||
|
||||
if (status) {
|
||||
dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
|
||||
dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n",
|
||||
__func__, status);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -591,7 +593,8 @@ static void usa49_instat_callback(struct urb *urb)
|
|||
serial = urb->context;
|
||||
|
||||
if (status) {
|
||||
dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
|
||||
dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n",
|
||||
__func__, status);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -646,7 +649,7 @@ static void usa49_indat_callback(struct urb *urb)
|
|||
endpoint = usb_pipeendpoint(urb->pipe);
|
||||
|
||||
if (status) {
|
||||
dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
|
||||
dev_dbg(&urb->dev->dev, "%s - nonzero status %d on endpoint %x\n",
|
||||
__func__, status, endpoint);
|
||||
return;
|
||||
}
|
||||
|
|
@ -698,7 +701,8 @@ static void usa49wg_indat_callback(struct urb *urb)
|
|||
serial = urb->context;
|
||||
|
||||
if (status) {
|
||||
dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
|
||||
dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n",
|
||||
__func__, status);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -774,8 +778,8 @@ static void usa90_indat_callback(struct urb *urb)
|
|||
endpoint = usb_pipeendpoint(urb->pipe);
|
||||
|
||||
if (status) {
|
||||
dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
|
||||
__func__, status, endpoint);
|
||||
dev_dbg(&urb->dev->dev, "%s - nonzero status %d on endpoint %x\n",
|
||||
__func__, status, endpoint);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -847,7 +851,8 @@ static void usa90_instat_callback(struct urb *urb)
|
|||
serial = urb->context;
|
||||
|
||||
if (status) {
|
||||
dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
|
||||
dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n",
|
||||
__func__, status);
|
||||
return;
|
||||
}
|
||||
if (urb->actual_length < 14) {
|
||||
|
|
@ -912,7 +917,8 @@ static void usa67_instat_callback(struct urb *urb)
|
|||
serial = urb->context;
|
||||
|
||||
if (status) {
|
||||
dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
|
||||
dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n",
|
||||
__func__, status);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1082,12 +1088,6 @@ static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline void stop_urb(struct urb *urb)
|
||||
{
|
||||
if (urb && urb->status == -EINPROGRESS)
|
||||
usb_kill_urb(urb);
|
||||
}
|
||||
|
||||
static void keyspan_dtr_rts(struct usb_serial_port *port, int on)
|
||||
{
|
||||
struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
|
||||
|
|
@ -1114,10 +1114,10 @@ static void keyspan_close(struct usb_serial_port *port)
|
|||
p_priv->out_flip = 0;
|
||||
p_priv->in_flip = 0;
|
||||
|
||||
stop_urb(p_priv->inack_urb);
|
||||
usb_kill_urb(p_priv->inack_urb);
|
||||
for (i = 0; i < 2; i++) {
|
||||
stop_urb(p_priv->in_urbs[i]);
|
||||
stop_urb(p_priv->out_urbs[i]);
|
||||
usb_kill_urb(p_priv->in_urbs[i]);
|
||||
usb_kill_urb(p_priv->out_urbs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1221,8 +1221,8 @@ static struct usb_endpoint_descriptor const *find_ep(struct usb_serial const *se
|
|||
if (ep->bEndpointAddress == endpoint)
|
||||
return ep;
|
||||
}
|
||||
dev_warn(&serial->interface->dev, "found no endpoint descriptor for "
|
||||
"endpoint %x\n", endpoint);
|
||||
dev_warn(&serial->interface->dev, "found no endpoint descriptor for endpoint %x\n",
|
||||
endpoint);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -1237,7 +1237,8 @@ static struct urb *keyspan_setup_urb(struct usb_serial *serial, int endpoint,
|
|||
if (endpoint == -1)
|
||||
return NULL; /* endpoint not needed */
|
||||
|
||||
dev_dbg(&serial->interface->dev, "%s - alloc for endpoint %d.\n", __func__, endpoint);
|
||||
dev_dbg(&serial->interface->dev, "%s - alloc for endpoint %x\n",
|
||||
__func__, endpoint);
|
||||
urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
|
||||
if (!urb)
|
||||
return NULL;
|
||||
|
|
@ -1572,7 +1573,8 @@ static int keyspan_usa26_send_setup(struct usb_serial *serial,
|
|||
return -1;
|
||||
}
|
||||
|
||||
dev_dbg(&port->dev, "%s - endpoint %d\n", __func__, usb_pipeendpoint(this_urb->pipe));
|
||||
dev_dbg(&port->dev, "%s - endpoint %x\n",
|
||||
__func__, usb_pipeendpoint(this_urb->pipe));
|
||||
|
||||
/* Save reset port val for resend.
|
||||
Don't overwrite resend for open/close condition. */
|
||||
|
|
@ -1838,7 +1840,7 @@ static int keyspan_usa49_send_setup(struct usb_serial *serial,
|
|||
return -1;
|
||||
}
|
||||
|
||||
dev_dbg(&port->dev, "%s - endpoint %d (%d)\n",
|
||||
dev_dbg(&port->dev, "%s - endpoint %x (%d)\n",
|
||||
__func__, usb_pipeendpoint(this_urb->pipe), device_port);
|
||||
|
||||
/* Save reset port val for resend.
|
||||
|
|
@ -2365,9 +2367,9 @@ static void keyspan_disconnect(struct usb_serial *serial)
|
|||
|
||||
s_priv = usb_get_serial_data(serial);
|
||||
|
||||
stop_urb(s_priv->instat_urb);
|
||||
stop_urb(s_priv->glocont_urb);
|
||||
stop_urb(s_priv->indat_urb);
|
||||
usb_kill_urb(s_priv->instat_urb);
|
||||
usb_kill_urb(s_priv->glocont_urb);
|
||||
usb_kill_urb(s_priv->indat_urb);
|
||||
}
|
||||
|
||||
static void keyspan_release(struct usb_serial *serial)
|
||||
|
|
@ -2376,6 +2378,10 @@ static void keyspan_release(struct usb_serial *serial)
|
|||
|
||||
s_priv = usb_get_serial_data(serial);
|
||||
|
||||
/* Make sure to unlink the URBs submitted in attach. */
|
||||
usb_kill_urb(s_priv->instat_urb);
|
||||
usb_kill_urb(s_priv->indat_urb);
|
||||
|
||||
usb_free_urb(s_priv->instat_urb);
|
||||
usb_free_urb(s_priv->indat_urb);
|
||||
usb_free_urb(s_priv->glocont_urb);
|
||||
|
|
@ -2491,11 +2497,11 @@ static int keyspan_port_remove(struct usb_serial_port *port)
|
|||
|
||||
p_priv = usb_get_serial_port_data(port);
|
||||
|
||||
stop_urb(p_priv->inack_urb);
|
||||
stop_urb(p_priv->outcont_urb);
|
||||
usb_kill_urb(p_priv->inack_urb);
|
||||
usb_kill_urb(p_priv->outcont_urb);
|
||||
for (i = 0; i < 2; i++) {
|
||||
stop_urb(p_priv->in_urbs[i]);
|
||||
stop_urb(p_priv->out_urbs[i]);
|
||||
usb_kill_urb(p_priv->in_urbs[i]);
|
||||
usb_kill_urb(p_priv->out_urbs[i]);
|
||||
}
|
||||
|
||||
usb_free_urb(p_priv->inack_urb);
|
||||
|
|
|
|||
|
|
@ -1259,6 +1259,15 @@ static int mxuport_attach(struct usb_serial *serial)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void mxuport_release(struct usb_serial *serial)
|
||||
{
|
||||
struct usb_serial_port *port0 = serial->port[0];
|
||||
struct usb_serial_port *port1 = serial->port[1];
|
||||
|
||||
usb_serial_generic_close(port1);
|
||||
usb_serial_generic_close(port0);
|
||||
}
|
||||
|
||||
static int mxuport_open(struct tty_struct *tty, struct usb_serial_port *port)
|
||||
{
|
||||
struct mxuport_port *mxport = usb_get_serial_port_data(port);
|
||||
|
|
@ -1361,6 +1370,7 @@ static struct usb_serial_driver mxuport_device = {
|
|||
.probe = mxuport_probe,
|
||||
.port_probe = mxuport_port_probe,
|
||||
.attach = mxuport_attach,
|
||||
.release = mxuport_release,
|
||||
.calc_num_ports = mxuport_calc_num_ports,
|
||||
.open = mxuport_open,
|
||||
.close = mxuport_close,
|
||||
|
|
|
|||
|
|
@ -375,18 +375,22 @@ static void option_instat_callback(struct urb *urb);
|
|||
#define HAIER_PRODUCT_CE81B 0x10f8
|
||||
#define HAIER_PRODUCT_CE100 0x2009
|
||||
|
||||
/* Cinterion (formerly Siemens) products */
|
||||
#define SIEMENS_VENDOR_ID 0x0681
|
||||
#define CINTERION_VENDOR_ID 0x1e2d
|
||||
/* Gemalto's Cinterion products (formerly Siemens) */
|
||||
#define SIEMENS_VENDOR_ID 0x0681
|
||||
#define CINTERION_VENDOR_ID 0x1e2d
|
||||
#define CINTERION_PRODUCT_HC25_MDMNET 0x0040
|
||||
#define CINTERION_PRODUCT_HC25_MDM 0x0047
|
||||
#define CINTERION_PRODUCT_HC25_MDMNET 0x0040
|
||||
#define CINTERION_PRODUCT_HC28_MDMNET 0x004A /* same for HC28J */
|
||||
#define CINTERION_PRODUCT_HC28_MDM 0x004C
|
||||
#define CINTERION_PRODUCT_HC28_MDMNET 0x004A /* same for HC28J */
|
||||
#define CINTERION_PRODUCT_EU3_E 0x0051
|
||||
#define CINTERION_PRODUCT_EU3_P 0x0052
|
||||
#define CINTERION_PRODUCT_PH8 0x0053
|
||||
#define CINTERION_PRODUCT_AHXX 0x0055
|
||||
#define CINTERION_PRODUCT_PLXX 0x0060
|
||||
#define CINTERION_PRODUCT_PH8_2RMNET 0x0082
|
||||
#define CINTERION_PRODUCT_PH8_AUDIO 0x0083
|
||||
#define CINTERION_PRODUCT_AHXX_2RMNET 0x0084
|
||||
#define CINTERION_PRODUCT_AHXX_AUDIO 0x0085
|
||||
|
||||
/* Olivetti products */
|
||||
#define OLIVETTI_VENDOR_ID 0x0b3c
|
||||
|
|
@ -633,6 +637,10 @@ static const struct option_blacklist_info telit_le922_blacklist_usbcfg3 = {
|
|||
.reserved = BIT(1) | BIT(2) | BIT(3),
|
||||
};
|
||||
|
||||
static const struct option_blacklist_info cinterion_rmnet2_blacklist = {
|
||||
.reserved = BIT(4) | BIT(5),
|
||||
};
|
||||
|
||||
static const struct usb_device_id option_ids[] = {
|
||||
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
|
||||
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
|
||||
|
|
@ -1602,7 +1610,79 @@ static const struct usb_device_id option_ids[] = {
|
|||
.driver_info = (kernel_ulong_t)&net_intf3_blacklist },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0178, 0xff, 0xff, 0xff),
|
||||
.driver_info = (kernel_ulong_t)&net_intf3_blacklist },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffe9, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff42, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff43, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff44, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff45, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff46, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff47, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff48, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff49, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff4a, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff4b, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff4c, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff4d, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff4e, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff4f, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff50, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff51, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff52, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff53, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff54, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff55, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff56, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff57, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff58, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff59, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff5a, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff5b, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff5c, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff5d, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff5e, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff5f, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff60, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff61, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff62, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff63, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff64, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff65, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff66, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff67, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff68, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff69, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff6a, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff6b, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff6c, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff6d, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff6e, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff6f, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff70, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff71, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff72, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff73, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff74, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff75, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff76, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff77, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff78, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff79, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff7a, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff7b, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff7c, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff7d, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff7e, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff7f, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff80, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff81, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff82, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff83, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff84, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff85, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff86, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff87, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff88, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff89, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8a, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8b, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8c, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8d, 0xff, 0xff, 0xff) },
|
||||
|
|
@ -1613,6 +1693,61 @@ static const struct usb_device_id option_ids[] = {
|
|||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff92, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff93, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff94, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff9f, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffa0, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffa1, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffa2, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffa3, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffa4, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffa5, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffa6, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffa7, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffa8, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffa9, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffaa, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffab, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffac, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffae, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffaf, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffb0, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffb1, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffb2, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffb3, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffb4, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffb5, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffb6, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffb7, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffb8, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffb9, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffba, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffbb, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffbc, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffbd, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffbe, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffbf, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffc0, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffc1, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffc2, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffc3, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffc4, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffc5, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffc6, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffc7, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffc8, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffc9, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffca, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffcb, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffcc, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffcd, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffce, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffcf, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffd0, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffd1, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffd2, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffd3, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffd4, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffd5, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffe9, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffec, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffee, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xfff6, 0xff, 0xff, 0xff) },
|
||||
|
|
@ -1712,7 +1847,13 @@ static const struct usb_device_id option_ids[] = {
|
|||
{ USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX, 0xff) },
|
||||
{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PLXX),
|
||||
.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
|
||||
{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) },
|
||||
{ USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8_2RMNET, 0xff),
|
||||
.driver_info = (kernel_ulong_t)&cinterion_rmnet2_blacklist },
|
||||
{ USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8_AUDIO, 0xff),
|
||||
.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
|
||||
{ USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX_2RMNET, 0xff) },
|
||||
{ USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX_AUDIO, 0xff) },
|
||||
{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) },
|
||||
{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDMNET) },
|
||||
{ USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC25_MDM) },
|
||||
{ USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC25_MDMNET) },
|
||||
|
|
|
|||
|
|
@ -141,6 +141,7 @@ static void qt2_release(struct usb_serial *serial)
|
|||
|
||||
serial_priv = usb_get_serial_data(serial);
|
||||
|
||||
usb_kill_urb(serial_priv->read_urb);
|
||||
usb_free_urb(serial_priv->read_urb);
|
||||
kfree(serial_priv->read_buffer);
|
||||
kfree(serial_priv);
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ struct ti_device {
|
|||
int td_open_port_count;
|
||||
struct usb_serial *td_serial;
|
||||
int td_is_3410;
|
||||
bool td_rs485_only;
|
||||
int td_urb_error;
|
||||
};
|
||||
|
||||
|
|
@ -160,6 +161,11 @@ static const struct usb_device_id ti_id_table_3410[] = {
|
|||
{ USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STRIP_PORT_ID) },
|
||||
{ USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) },
|
||||
{ USB_DEVICE(HONEYWELL_VENDOR_ID, HONEYWELL_HGI80_PRODUCT_ID) },
|
||||
{ USB_DEVICE(MXU1_VENDOR_ID, MXU1_1110_PRODUCT_ID) },
|
||||
{ USB_DEVICE(MXU1_VENDOR_ID, MXU1_1130_PRODUCT_ID) },
|
||||
{ USB_DEVICE(MXU1_VENDOR_ID, MXU1_1131_PRODUCT_ID) },
|
||||
{ USB_DEVICE(MXU1_VENDOR_ID, MXU1_1150_PRODUCT_ID) },
|
||||
{ USB_DEVICE(MXU1_VENDOR_ID, MXU1_1151_PRODUCT_ID) },
|
||||
{ } /* terminator */
|
||||
};
|
||||
|
||||
|
|
@ -193,6 +199,11 @@ static const struct usb_device_id ti_id_table_combined[] = {
|
|||
{ USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STRIP_PORT_ID) },
|
||||
{ USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) },
|
||||
{ USB_DEVICE(HONEYWELL_VENDOR_ID, HONEYWELL_HGI80_PRODUCT_ID) },
|
||||
{ USB_DEVICE(MXU1_VENDOR_ID, MXU1_1110_PRODUCT_ID) },
|
||||
{ USB_DEVICE(MXU1_VENDOR_ID, MXU1_1130_PRODUCT_ID) },
|
||||
{ USB_DEVICE(MXU1_VENDOR_ID, MXU1_1131_PRODUCT_ID) },
|
||||
{ USB_DEVICE(MXU1_VENDOR_ID, MXU1_1150_PRODUCT_ID) },
|
||||
{ USB_DEVICE(MXU1_VENDOR_ID, MXU1_1151_PRODUCT_ID) },
|
||||
{ } /* terminator */
|
||||
};
|
||||
|
||||
|
|
@ -277,6 +288,11 @@ MODULE_FIRMWARE("mts_gsm.fw");
|
|||
MODULE_FIRMWARE("mts_edge.fw");
|
||||
MODULE_FIRMWARE("mts_mt9234mu.fw");
|
||||
MODULE_FIRMWARE("mts_mt9234zba.fw");
|
||||
MODULE_FIRMWARE("moxa/moxa-1110.fw");
|
||||
MODULE_FIRMWARE("moxa/moxa-1130.fw");
|
||||
MODULE_FIRMWARE("moxa/moxa-1131.fw");
|
||||
MODULE_FIRMWARE("moxa/moxa-1150.fw");
|
||||
MODULE_FIRMWARE("moxa/moxa-1151.fw");
|
||||
|
||||
module_param(closing_wait, int, S_IRUGO | S_IWUSR);
|
||||
MODULE_PARM_DESC(closing_wait,
|
||||
|
|
@ -292,6 +308,9 @@ static int ti_startup(struct usb_serial *serial)
|
|||
{
|
||||
struct ti_device *tdev;
|
||||
struct usb_device *dev = serial->dev;
|
||||
struct usb_host_interface *cur_altsetting;
|
||||
int num_endpoints;
|
||||
u16 vid, pid;
|
||||
int status;
|
||||
|
||||
dev_dbg(&dev->dev,
|
||||
|
|
@ -315,8 +334,22 @@ static int ti_startup(struct usb_serial *serial)
|
|||
dev_dbg(&dev->dev, "%s - device type is %s\n", __func__,
|
||||
tdev->td_is_3410 ? "3410" : "5052");
|
||||
|
||||
/* if we have only 1 configuration, download firmware */
|
||||
if (dev->descriptor.bNumConfigurations == 1) {
|
||||
vid = le16_to_cpu(dev->descriptor.idVendor);
|
||||
pid = le16_to_cpu(dev->descriptor.idProduct);
|
||||
if (vid == MXU1_VENDOR_ID) {
|
||||
switch (pid) {
|
||||
case MXU1_1130_PRODUCT_ID:
|
||||
case MXU1_1131_PRODUCT_ID:
|
||||
tdev->td_rs485_only = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cur_altsetting = serial->interface->cur_altsetting;
|
||||
num_endpoints = cur_altsetting->desc.bNumEndpoints;
|
||||
|
||||
/* if we have only 1 configuration and 1 endpoint, download firmware */
|
||||
if (dev->descriptor.bNumConfigurations == 1 && num_endpoints == 1) {
|
||||
status = ti_download_firmware(tdev);
|
||||
|
||||
if (status != 0)
|
||||
|
|
@ -371,7 +404,11 @@ static int ti_port_probe(struct usb_serial_port *port)
|
|||
port->port.closing_wait = msecs_to_jiffies(10 * closing_wait);
|
||||
tport->tp_port = port;
|
||||
tport->tp_tdev = usb_get_serial_data(port->serial);
|
||||
tport->tp_uart_mode = 0; /* default is RS232 */
|
||||
|
||||
if (tport->tp_tdev->td_rs485_only)
|
||||
tport->tp_uart_mode = TI_UART_485_RECEIVER_DISABLED;
|
||||
else
|
||||
tport->tp_uart_mode = TI_UART_232;
|
||||
|
||||
usb_set_serial_port_data(port, tport);
|
||||
|
||||
|
|
@ -1450,6 +1487,16 @@ static int ti_download_firmware(struct ti_device *tdev)
|
|||
const struct firmware *fw_p;
|
||||
char buf[32];
|
||||
|
||||
if (le16_to_cpu(dev->descriptor.idVendor) == MXU1_VENDOR_ID) {
|
||||
snprintf(buf,
|
||||
sizeof(buf),
|
||||
"moxa/moxa-%04x.fw",
|
||||
le16_to_cpu(dev->descriptor.idProduct));
|
||||
|
||||
status = request_firmware(&fw_p, buf, &dev->dev);
|
||||
goto check_firmware;
|
||||
}
|
||||
|
||||
/* try ID specific firmware first, then try generic firmware */
|
||||
sprintf(buf, "ti_usb-v%04x-p%04x.fw",
|
||||
le16_to_cpu(dev->descriptor.idVendor),
|
||||
|
|
@ -1487,6 +1534,8 @@ static int ti_download_firmware(struct ti_device *tdev)
|
|||
}
|
||||
status = request_firmware(&fw_p, buf, &dev->dev);
|
||||
}
|
||||
|
||||
check_firmware:
|
||||
if (status) {
|
||||
dev_err(&dev->dev, "%s - firmware not found\n", __func__);
|
||||
return -ENOENT;
|
||||
|
|
|
|||
|
|
@ -60,6 +60,14 @@
|
|||
#define HONEYWELL_VENDOR_ID 0x10ac
|
||||
#define HONEYWELL_HGI80_PRODUCT_ID 0x0102 /* Honeywell HGI80 */
|
||||
|
||||
/* Moxa UPORT 11x0 vendor and product IDs */
|
||||
#define MXU1_VENDOR_ID 0x110a
|
||||
#define MXU1_1110_PRODUCT_ID 0x1110
|
||||
#define MXU1_1130_PRODUCT_ID 0x1130
|
||||
#define MXU1_1131_PRODUCT_ID 0x1131
|
||||
#define MXU1_1150_PRODUCT_ID 0x1150
|
||||
#define MXU1_1151_PRODUCT_ID 0x1151
|
||||
|
||||
/* Commands */
|
||||
#define TI_GET_VERSION 0x01
|
||||
#define TI_GET_PORT_STATUS 0x02
|
||||
|
|
|
|||
|
|
@ -96,7 +96,8 @@ static int allocate_minors(struct usb_serial *serial, int num_ports)
|
|||
mutex_lock(&table_lock);
|
||||
for (i = 0; i < num_ports; ++i) {
|
||||
port = serial->port[i];
|
||||
minor = idr_alloc(&serial_minors, port, 0, 0, GFP_KERNEL);
|
||||
minor = idr_alloc(&serial_minors, port, 0,
|
||||
USB_SERIAL_TTY_MINORS, GFP_KERNEL);
|
||||
if (minor < 0)
|
||||
goto error;
|
||||
port->minor = minor;
|
||||
|
|
@ -815,7 +816,7 @@ static int usb_serial_probe(struct usb_interface *interface,
|
|||
}
|
||||
}
|
||||
|
||||
#if defined(CONFIG_USB_SERIAL_PL2303) || defined(CONFIG_USB_SERIAL_PL2303_MODULE)
|
||||
#if IS_ENABLED(CONFIG_USB_SERIAL_PL2303)
|
||||
/* BEGIN HORRIBLE HACK FOR PL2303 */
|
||||
/* this is needed due to the looney way its endpoints are set up */
|
||||
if (((le16_to_cpu(dev->descriptor.idVendor) == PL2303_VENDOR_ID) &&
|
||||
|
|
|
|||
|
|
@ -829,8 +829,10 @@ static int alauda_write_lba(struct us_data *us, u16 lba,
|
|||
|
||||
pba = MEDIA_INFO(us).lba_to_pba[zone][lba_offset];
|
||||
if (pba == 1) {
|
||||
/* Maybe it is impossible to write to PBA 1.
|
||||
Fake success, but don't do anything. */
|
||||
/*
|
||||
* Maybe it is impossible to write to PBA 1.
|
||||
* Fake success, but don't do anything.
|
||||
*/
|
||||
printk(KERN_WARNING
|
||||
"alauda_write_lba: avoid writing to pba 1\n");
|
||||
return USB_STOR_TRANSPORT_GOOD;
|
||||
|
|
@ -977,10 +979,12 @@ static int alauda_read_data(struct us_data *us, unsigned long address,
|
|||
usb_stor_dbg(us, "Read %d zero pages (LBA %d) page %d\n",
|
||||
pages, lba, page);
|
||||
|
||||
/* This is not really an error. It just means
|
||||
that the block has never been written.
|
||||
Instead of returning USB_STOR_TRANSPORT_ERROR
|
||||
it is better to return all zero data. */
|
||||
/*
|
||||
* This is not really an error. It just means
|
||||
* that the block has never been written.
|
||||
* Instead of returning USB_STOR_TRANSPORT_ERROR
|
||||
* it is better to return all zero data.
|
||||
*/
|
||||
|
||||
memset(buffer, 0, len);
|
||||
} else {
|
||||
|
|
@ -1222,8 +1226,10 @@ static int alauda_transport(struct scsi_cmnd *srb, struct us_data *us)
|
|||
}
|
||||
|
||||
if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) {
|
||||
/* sure. whatever. not like we can stop the user from popping
|
||||
the media out of the device (no locking doors, etc) */
|
||||
/*
|
||||
* sure. whatever. not like we can stop the user from popping
|
||||
* the media out of the device (no locking doors, etc)
|
||||
*/
|
||||
return USB_STOR_TRANSPORT_GOOD;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -110,13 +110,17 @@ static void cypress_atacb_passthrough(struct scsi_cmnd *srb, struct us_data *us)
|
|||
/* first build the ATACB command */
|
||||
srb->cmd_len = 16;
|
||||
|
||||
srb->cmnd[0] = 0x24; /* bVSCBSignature : vendor-specific command
|
||||
this value can change, but most(all ?) manufacturers
|
||||
keep the cypress default : 0x24 */
|
||||
srb->cmnd[0] = 0x24; /*
|
||||
* bVSCBSignature : vendor-specific command
|
||||
* this value can change, but most(all ?) manufacturers
|
||||
* keep the cypress default : 0x24
|
||||
*/
|
||||
srb->cmnd[1] = 0x24; /* bVSCBSubCommand : 0x24 for ATACB */
|
||||
|
||||
srb->cmnd[3] = 0xff - 1; /* features, sector count, lba low, lba med
|
||||
lba high, device, command are valid */
|
||||
srb->cmnd[3] = 0xff - 1; /*
|
||||
* features, sector count, lba low, lba med
|
||||
* lba high, device, command are valid
|
||||
*/
|
||||
srb->cmnd[4] = 1; /* TransferBlockCount : 512 */
|
||||
|
||||
if (save_cmnd[0] == ATA_16) {
|
||||
|
|
@ -155,8 +159,7 @@ static void cypress_atacb_passthrough(struct scsi_cmnd *srb, struct us_data *us)
|
|||
|
||||
usb_stor_transparent_scsi_command(srb, us);
|
||||
|
||||
/* if the device doesn't support ATACB
|
||||
*/
|
||||
/* if the device doesn't support ATACB */
|
||||
if (srb->result == SAM_STAT_CHECK_CONDITION &&
|
||||
memcmp(srb->sense_buffer, usb_stor_sense_invalidCDB,
|
||||
sizeof(usb_stor_sense_invalidCDB)) == 0) {
|
||||
|
|
@ -164,7 +167,8 @@ static void cypress_atacb_passthrough(struct scsi_cmnd *srb, struct us_data *us)
|
|||
goto end;
|
||||
}
|
||||
|
||||
/* if ck_cond flags is set, and there wasn't critical error,
|
||||
/*
|
||||
* if ck_cond flags is set, and there wasn't critical error,
|
||||
* build the special sense
|
||||
*/
|
||||
if ((srb->result != (DID_ERROR << 16) &&
|
||||
|
|
@ -176,11 +180,11 @@ static void cypress_atacb_passthrough(struct scsi_cmnd *srb, struct us_data *us)
|
|||
unsigned char *desc = sb + 8;
|
||||
int tmp_result;
|
||||
|
||||
/* build the command for
|
||||
* reading the ATA registers */
|
||||
/* build the command for reading the ATA registers */
|
||||
scsi_eh_prep_cmnd(srb, &ses, NULL, 0, sizeof(regs));
|
||||
|
||||
/* we use the same command as before, but we set
|
||||
/*
|
||||
* we use the same command as before, but we set
|
||||
* the read taskfile bit, for not executing atacb command,
|
||||
* but reading register selected in srb->cmnd[4]
|
||||
*/
|
||||
|
|
@ -204,10 +208,11 @@ static void cypress_atacb_passthrough(struct scsi_cmnd *srb, struct us_data *us)
|
|||
sb[2] = 0; /* ATA PASS THROUGH INFORMATION AVAILABLE */
|
||||
sb[3] = 0x1D;
|
||||
|
||||
/* XXX we should generate sk, asc, ascq from status and error
|
||||
/*
|
||||
* XXX we should generate sk, asc, ascq from status and error
|
||||
* regs
|
||||
* (see 11.1 Error translation ATA device error to SCSI error
|
||||
* map, and ata_to_sense_error from libata.)
|
||||
* map, and ata_to_sense_error from libata.)
|
||||
*/
|
||||
|
||||
/* Sense data is current and format is descriptor. */
|
||||
|
|
@ -258,7 +263,8 @@ static int cypress_probe(struct usb_interface *intf,
|
|||
if (result)
|
||||
return result;
|
||||
|
||||
/* Among CY7C68300 chips, the A revision does not support Cypress ATACB
|
||||
/*
|
||||
* Among CY7C68300 chips, the A revision does not support Cypress ATACB
|
||||
* Filter out this revision from EEPROM default descriptor values
|
||||
*/
|
||||
device = interface_to_usbdev(intf);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* Driver for Datafab USB Compact Flash reader
|
||||
/*
|
||||
* Driver for Datafab USB Compact Flash reader
|
||||
*
|
||||
* datafab driver v0.1:
|
||||
*
|
||||
|
|
@ -693,18 +694,23 @@ static int datafab_transport(struct scsi_cmnd *srb, struct us_data *us)
|
|||
}
|
||||
|
||||
if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) {
|
||||
// sure. whatever. not like we can stop the user from
|
||||
// popping the media out of the device (no locking doors, etc)
|
||||
//
|
||||
/*
|
||||
* sure. whatever. not like we can stop the user from
|
||||
* popping the media out of the device (no locking doors, etc)
|
||||
*/
|
||||
return USB_STOR_TRANSPORT_GOOD;
|
||||
}
|
||||
|
||||
if (srb->cmnd[0] == START_STOP) {
|
||||
/* this is used by sd.c'check_scsidisk_media_change to detect
|
||||
media change */
|
||||
/*
|
||||
* this is used by sd.c'check_scsidisk_media_change to detect
|
||||
* media change
|
||||
*/
|
||||
usb_stor_dbg(us, "START_STOP\n");
|
||||
/* the first datafab_id_device after a media change returns
|
||||
an error (determined experimentally) */
|
||||
/*
|
||||
* the first datafab_id_device after a media change returns
|
||||
* an error (determined experimentally)
|
||||
*/
|
||||
rc = datafab_id_device(us, info);
|
||||
if (rc == USB_STOR_TRANSPORT_GOOD) {
|
||||
info->sense_key = NO_SENSE;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* Driver for USB Mass Storage compliant devices
|
||||
/*
|
||||
* Driver for USB Mass Storage compliant devices
|
||||
* Debugging Functions Source Code File
|
||||
*
|
||||
* Current development and maintenance by:
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* Driver for USB Mass Storage compliant devices
|
||||
/*
|
||||
* Driver for USB Mass Storage compliant devices
|
||||
* Debugging Functions Header File
|
||||
*
|
||||
* Current development and maintenance by:
|
||||
|
|
|
|||
|
|
@ -560,8 +560,10 @@ static int ene_send_scsi_cmd(struct us_data *us, u8 fDir, void *buf, int use_sg)
|
|||
/* check bulk status */
|
||||
residue = le32_to_cpu(bcs->Residue);
|
||||
|
||||
/* try to compute the actual residue, based on how much data
|
||||
* was really transferred and what the device tells us */
|
||||
/*
|
||||
* try to compute the actual residue, based on how much data
|
||||
* was really transferred and what the device tells us
|
||||
*/
|
||||
if (residue && !(us->fflags & US_FL_IGNORE_RESIDUE)) {
|
||||
residue = min(residue, transfer_length);
|
||||
if (us->srb != NULL)
|
||||
|
|
@ -862,9 +864,6 @@ static int ms_read_readpage(struct us_data *us, u32 PhyBlockAddr,
|
|||
u8 ExtBuf[4];
|
||||
u32 bn = PhyBlockAddr * 0x20 + PageNum;
|
||||
|
||||
/* printk(KERN_INFO "MS --- MS_ReaderReadPage,
|
||||
PhyBlockAddr = %x, PageNum = %x\n", PhyBlockAddr, PageNum); */
|
||||
|
||||
result = ene_load_bincode(us, MS_RW_PATTERN);
|
||||
if (result != USB_STOR_XFER_GOOD)
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
|
|
@ -1141,8 +1140,6 @@ static int ms_read_copyblock(struct us_data *us, u16 oldphy, u16 newphy,
|
|||
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
|
||||
int result;
|
||||
|
||||
/* printk(KERN_INFO "MS_ReaderCopyBlock --- PhyBlockAddr = %x,
|
||||
PageNum = %x\n", PhyBlockAddr, PageNum); */
|
||||
result = ene_load_bincode(us, MS_RW_PATTERN);
|
||||
if (result != USB_STOR_XFER_GOOD)
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
|
|
@ -1176,8 +1173,6 @@ static int ms_read_eraseblock(struct us_data *us, u32 PhyBlockAddr)
|
|||
int result;
|
||||
u32 bn = PhyBlockAddr;
|
||||
|
||||
/* printk(KERN_INFO "MS --- ms_read_eraseblock,
|
||||
PhyBlockAddr = %x\n", PhyBlockAddr); */
|
||||
result = ene_load_bincode(us, MS_RW_PATTERN);
|
||||
if (result != USB_STOR_XFER_GOOD)
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
|
|
@ -1255,8 +1250,6 @@ static int ms_lib_overwrite_extra(struct us_data *us, u32 PhyBlockAddr,
|
|||
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
|
||||
int result;
|
||||
|
||||
/* printk("MS --- MS_LibOverwriteExtra,
|
||||
PhyBlockAddr = %x, PageNum = %x\n", PhyBlockAddr, PageNum); */
|
||||
result = ene_load_bincode(us, MS_RW_PATTERN);
|
||||
if (result != USB_STOR_XFER_GOOD)
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
|
|
@ -1342,7 +1335,6 @@ static int ms_lib_read_extra(struct us_data *us, u32 PhyBlock,
|
|||
int result;
|
||||
u8 ExtBuf[4];
|
||||
|
||||
/* printk("MS_LibReadExtra --- PhyBlock = %x, PageNum = %x\n", PhyBlock, PageNum); */
|
||||
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
|
||||
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
|
||||
bcb->DataTransferLength = 0x4;
|
||||
|
|
@ -1541,9 +1533,6 @@ static int ms_lib_read_extrablock(struct us_data *us, u32 PhyBlock,
|
|||
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
|
||||
int result;
|
||||
|
||||
/* printk("MS_LibReadExtraBlock --- PhyBlock = %x,
|
||||
PageNum = %x, blen = %x\n", PhyBlock, PageNum, blen); */
|
||||
|
||||
/* Read Extra Data */
|
||||
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
|
||||
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
|
||||
|
|
@ -2390,8 +2379,10 @@ static int ene_ub6250_reset_resume(struct usb_interface *iface)
|
|||
/* Report the reset to the SCSI core */
|
||||
usb_stor_reset_resume(iface);
|
||||
|
||||
/* FIXME: Notify the subdrivers that they need to reinitialize
|
||||
* the device */
|
||||
/*
|
||||
* FIXME: Notify the subdrivers that they need to reinitialize
|
||||
* the device
|
||||
*/
|
||||
info->Power_IsResum = true;
|
||||
/*info->SD_Status.Ready = 0; */
|
||||
info->SD_Status = *(struct SD_STATUS *)&tmp;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* Driver for Freecom USB/IDE adaptor
|
||||
/*
|
||||
* Driver for Freecom USB/IDE adaptor
|
||||
*
|
||||
* Freecom v0.1:
|
||||
*
|
||||
|
|
@ -84,25 +85,33 @@ struct freecom_status {
|
|||
u8 Pad[60];
|
||||
};
|
||||
|
||||
/* Freecom stuffs the interrupt status in the INDEX_STAT bit of the ide
|
||||
* register. */
|
||||
/*
|
||||
* Freecom stuffs the interrupt status in the INDEX_STAT bit of the ide
|
||||
* register.
|
||||
*/
|
||||
#define FCM_INT_STATUS 0x02 /* INDEX_STAT */
|
||||
#define FCM_STATUS_BUSY 0x80
|
||||
|
||||
/* These are the packet types. The low bit indicates that this command
|
||||
* should wait for an interrupt. */
|
||||
/*
|
||||
* These are the packet types. The low bit indicates that this command
|
||||
* should wait for an interrupt.
|
||||
*/
|
||||
#define FCM_PACKET_ATAPI 0x21
|
||||
#define FCM_PACKET_STATUS 0x20
|
||||
|
||||
/* Receive data from the IDE interface. The ATAPI packet has already
|
||||
* waited, so the data should be immediately available. */
|
||||
/*
|
||||
* Receive data from the IDE interface. The ATAPI packet has already
|
||||
* waited, so the data should be immediately available.
|
||||
*/
|
||||
#define FCM_PACKET_INPUT 0x81
|
||||
|
||||
/* Send data to the IDE interface. */
|
||||
#define FCM_PACKET_OUTPUT 0x01
|
||||
|
||||
/* Write a value to an ide register. Or the ide register to write after
|
||||
* munging the address a bit. */
|
||||
/*
|
||||
* Write a value to an ide register. Or the ide register to write after
|
||||
* munging the address a bit.
|
||||
*/
|
||||
#define FCM_PACKET_IDE_WRITE 0x40
|
||||
#define FCM_PACKET_IDE_READ 0xC0
|
||||
|
||||
|
|
@ -251,16 +260,20 @@ static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
|
|||
result = usb_stor_bulk_transfer_buf (us, opipe, fcb,
|
||||
FCM_PACKET_LENGTH, NULL);
|
||||
|
||||
/* The Freecom device will only fail if there is something wrong in
|
||||
/*
|
||||
* The Freecom device will only fail if there is something wrong in
|
||||
* USB land. It returns the status in its own registers, which
|
||||
* come back in the bulk pipe. */
|
||||
* come back in the bulk pipe.
|
||||
*/
|
||||
if (result != USB_STOR_XFER_GOOD) {
|
||||
usb_stor_dbg(us, "freecom transport error\n");
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
}
|
||||
|
||||
/* There are times we can optimize out this status read, but it
|
||||
* doesn't hurt us to always do it now. */
|
||||
/*
|
||||
* There are times we can optimize out this status read, but it
|
||||
* doesn't hurt us to always do it now.
|
||||
*/
|
||||
result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
|
||||
FCM_STATUS_PACKET_LENGTH, &partial);
|
||||
usb_stor_dbg(us, "foo Status result %d %u\n", result, partial);
|
||||
|
|
@ -269,7 +282,8 @@ static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
|
|||
|
||||
US_DEBUG(pdump(us, (void *)fst, partial));
|
||||
|
||||
/* The firmware will time-out commands after 20 seconds. Some commands
|
||||
/*
|
||||
* The firmware will time-out commands after 20 seconds. Some commands
|
||||
* can legitimately take longer than this, so we use a different
|
||||
* command that only waits for the interrupt and then sends status,
|
||||
* without having to send a new ATAPI command to the device.
|
||||
|
|
@ -291,7 +305,8 @@ static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
|
|||
result = usb_stor_bulk_transfer_buf (us, opipe, fcb,
|
||||
FCM_PACKET_LENGTH, NULL);
|
||||
|
||||
/* The Freecom device will only fail if there is something
|
||||
/*
|
||||
* The Freecom device will only fail if there is something
|
||||
* wrong in USB land. It returns the status in its own
|
||||
* registers, which come back in the bulk pipe.
|
||||
*/
|
||||
|
|
@ -318,9 +333,11 @@ static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
|
|||
return USB_STOR_TRANSPORT_FAILED;
|
||||
}
|
||||
|
||||
/* The device might not have as much data available as we
|
||||
/*
|
||||
* The device might not have as much data available as we
|
||||
* requested. If you ask for more than the device has, this reads
|
||||
* and such will hang. */
|
||||
* and such will hang.
|
||||
*/
|
||||
usb_stor_dbg(us, "Device indicates that it has %d bytes available\n",
|
||||
le16_to_cpu(fst->Count));
|
||||
usb_stor_dbg(us, "SCSI requested %d\n", scsi_bufflen(srb));
|
||||
|
|
@ -344,16 +361,20 @@ static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
|
|||
length);
|
||||
}
|
||||
|
||||
/* What we do now depends on what direction the data is supposed to
|
||||
* move in. */
|
||||
/*
|
||||
* What we do now depends on what direction the data is supposed to
|
||||
* move in.
|
||||
*/
|
||||
|
||||
switch (us->srb->sc_data_direction) {
|
||||
case DMA_FROM_DEVICE:
|
||||
/* catch bogus "read 0 length" case */
|
||||
if (!length)
|
||||
break;
|
||||
/* Make sure that the status indicates that the device
|
||||
* wants data as well. */
|
||||
/*
|
||||
* Make sure that the status indicates that the device
|
||||
* wants data as well.
|
||||
*/
|
||||
if ((fst->Status & DRQ_STAT) == 0 || (fst->Reason & 3) != 2) {
|
||||
usb_stor_dbg(us, "SCSI wants data, drive doesn't have any\n");
|
||||
return USB_STOR_TRANSPORT_FAILED;
|
||||
|
|
@ -384,8 +405,10 @@ static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
|
|||
/* catch bogus "write 0 length" case */
|
||||
if (!length)
|
||||
break;
|
||||
/* Make sure the status indicates that the device wants to
|
||||
* send us data. */
|
||||
/*
|
||||
* Make sure the status indicates that the device wants to
|
||||
* send us data.
|
||||
*/
|
||||
/* !!IMPLEMENT!! */
|
||||
result = freecom_writedata (srb, us, ipipe, opipe, length);
|
||||
if (result != USB_STOR_TRANSPORT_GOOD)
|
||||
|
|
@ -431,7 +454,8 @@ static int init_freecom(struct us_data *us)
|
|||
int result;
|
||||
char *buffer = us->iobuf;
|
||||
|
||||
/* The DMA-mapped I/O buffer is 64 bytes long, just right for
|
||||
/*
|
||||
* The DMA-mapped I/O buffer is 64 bytes long, just right for
|
||||
* all our packets. No need to allocate any extra buffer space.
|
||||
*/
|
||||
|
||||
|
|
@ -440,7 +464,8 @@ static int init_freecom(struct us_data *us)
|
|||
buffer[32] = '\0';
|
||||
usb_stor_dbg(us, "String returned from FC init is: %s\n", buffer);
|
||||
|
||||
/* Special thanks to the people at Freecom for providing me with
|
||||
/*
|
||||
* Special thanks to the people at Freecom for providing me with
|
||||
* this "magic sequence", which they use in their Windows and MacOS
|
||||
* drivers to make sure that all the attached perhiperals are
|
||||
* properly reset.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* Special Initializers for certain USB Mass Storage devices
|
||||
/*
|
||||
* Special Initializers for certain USB Mass Storage devices
|
||||
*
|
||||
* Current development and maintenance by:
|
||||
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
|
||||
|
|
@ -42,8 +43,10 @@
|
|||
#include "debug.h"
|
||||
#include "transport.h"
|
||||
|
||||
/* This places the Shuttle/SCM USB<->SCSI bridge devices in multi-target
|
||||
* mode */
|
||||
/*
|
||||
* This places the Shuttle/SCM USB<->SCSI bridge devices in multi-target
|
||||
* mode
|
||||
*/
|
||||
int usb_stor_euscsi_init(struct us_data *us)
|
||||
{
|
||||
int result;
|
||||
|
|
@ -57,8 +60,10 @@ int usb_stor_euscsi_init(struct us_data *us)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* This function is required to activate all four slots on the UCR-61S2B
|
||||
* flash reader */
|
||||
/*
|
||||
* This function is required to activate all four slots on the UCR-61S2B
|
||||
* flash reader
|
||||
*/
|
||||
int usb_stor_ucr61s2b_init(struct us_data *us)
|
||||
{
|
||||
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap*) us->iobuf;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* Header file for Special Initializers for certain USB Mass Storage devices
|
||||
/*
|
||||
* Header file for Special Initializers for certain USB Mass Storage devices
|
||||
*
|
||||
* Current development and maintenance by:
|
||||
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
|
||||
|
|
@ -38,12 +39,16 @@
|
|||
#include "usb.h"
|
||||
#include "transport.h"
|
||||
|
||||
/* This places the Shuttle/SCM USB<->SCSI bridge devices in multi-target
|
||||
* mode */
|
||||
/*
|
||||
* This places the Shuttle/SCM USB<->SCSI bridge devices in multi-target
|
||||
* mode
|
||||
*/
|
||||
int usb_stor_euscsi_init(struct us_data *us);
|
||||
|
||||
/* This function is required to activate all four slots on the UCR-61S2B
|
||||
* flash reader */
|
||||
/*
|
||||
* This function is required to activate all four slots on the UCR-61S2B
|
||||
* flash reader
|
||||
*/
|
||||
int usb_stor_ucr61s2b_init(struct us_data *us);
|
||||
|
||||
/* This places the HUAWEI E220 devices in multi-port mode */
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* Transport & Protocol Driver for In-System Design, Inc. ISD200 ASIC
|
||||
/*
|
||||
* Transport & Protocol Driver for In-System Design, Inc. ISD200 ASIC
|
||||
*
|
||||
* Current development and maintenance:
|
||||
* (C) 2001-2002 Björn Stenberg (bjorn@haxx.se)
|
||||
|
|
@ -628,7 +629,8 @@ static void isd200_invoke_transport( struct us_data *us,
|
|||
srb->cmd_len = sizeof(ataCdb->generic);
|
||||
transferStatus = usb_stor_Bulk_transport(srb, us);
|
||||
|
||||
/* if the command gets aborted by the higher layers, we need to
|
||||
/*
|
||||
* if the command gets aborted by the higher layers, we need to
|
||||
* short-circuit all other processing
|
||||
*/
|
||||
if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) {
|
||||
|
|
@ -695,15 +697,18 @@ static void isd200_invoke_transport( struct us_data *us,
|
|||
}
|
||||
}
|
||||
|
||||
/* Regardless of auto-sense, if we _know_ we have an error
|
||||
/*
|
||||
* Regardless of auto-sense, if we _know_ we have an error
|
||||
* condition, show that in the result code
|
||||
*/
|
||||
if (transferStatus == USB_STOR_TRANSPORT_FAILED)
|
||||
srb->result = SAM_STAT_CHECK_CONDITION;
|
||||
return;
|
||||
|
||||
/* abort processing: the bulk-only transport requires a reset
|
||||
* following an abort */
|
||||
/*
|
||||
* abort processing: the bulk-only transport requires a reset
|
||||
* following an abort
|
||||
*/
|
||||
Handle_Abort:
|
||||
srb->result = DID_ABORT << 16;
|
||||
|
||||
|
|
@ -965,20 +970,22 @@ static int isd200_try_enum(struct us_data *us, unsigned char master_slave,
|
|||
info->DeviceHead = master_slave;
|
||||
break;
|
||||
}
|
||||
/* check Cylinder High/Low to
|
||||
determine if it is an ATAPI device
|
||||
*/
|
||||
/*
|
||||
* check Cylinder High/Low to
|
||||
* determine if it is an ATAPI device
|
||||
*/
|
||||
else if (regs[ATA_REG_HCYL_OFFSET] == 0xEB &&
|
||||
regs[ATA_REG_LCYL_OFFSET] == 0x14) {
|
||||
/* It seems that the RICOH
|
||||
MP6200A CD/RW drive will
|
||||
report itself okay as a
|
||||
slave when it is really a
|
||||
master. So this check again
|
||||
as a master device just to
|
||||
make sure it doesn't report
|
||||
itself okay as a master also
|
||||
*/
|
||||
/*
|
||||
* It seems that the RICOH
|
||||
* MP6200A CD/RW drive will
|
||||
* report itself okay as a
|
||||
* slave when it is really a
|
||||
* master. So this check again
|
||||
* as a master device just to
|
||||
* make sure it doesn't report
|
||||
* itself okay as a master also
|
||||
*/
|
||||
if ((master_slave & ATA_ADDRESS_DEVHEAD_SLAVE) &&
|
||||
!recheckAsMaster) {
|
||||
usb_stor_dbg(us, " Identified ATAPI device as slave. Rechecking again as master\n");
|
||||
|
|
@ -1176,9 +1183,11 @@ static int isd200_get_inquiry_data( struct us_data *us )
|
|||
if (id[ATA_ID_COMMAND_SET_2] & COMMANDSET_MEDIA_STATUS) {
|
||||
usb_stor_dbg(us, " Device supports Media Status Notification\n");
|
||||
|
||||
/* Indicate that it is enabled, even though it is not
|
||||
* This allows the lock/unlock of the media to work
|
||||
* correctly.
|
||||
/*
|
||||
* Indicate that it is enabled, even
|
||||
* though it is not.
|
||||
* This allows the lock/unlock of the
|
||||
* media to work correctly.
|
||||
*/
|
||||
info->DeviceFlags |= DF_MEDIA_STATUS_ENABLED;
|
||||
}
|
||||
|
|
@ -1197,7 +1206,7 @@ static int isd200_get_inquiry_data( struct us_data *us )
|
|||
usb_stor_dbg(us, "Protocol changed to: %s\n",
|
||||
us->protocol_name);
|
||||
|
||||
/* Free driver structure */
|
||||
/* Free driver structure */
|
||||
us->extra_destructor(info);
|
||||
kfree(info);
|
||||
us->extra = NULL;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* Driver for Lexar "Jumpshot" Compact Flash reader
|
||||
/*
|
||||
* Driver for Lexar "Jumpshot" Compact Flash reader
|
||||
*
|
||||
* jumpshot driver v0.1:
|
||||
*
|
||||
|
|
@ -618,18 +619,23 @@ static int jumpshot_transport(struct scsi_cmnd *srb, struct us_data *us)
|
|||
}
|
||||
|
||||
if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) {
|
||||
// sure. whatever. not like we can stop the user from popping
|
||||
// the media out of the device (no locking doors, etc)
|
||||
//
|
||||
/*
|
||||
* sure. whatever. not like we can stop the user from popping
|
||||
* the media out of the device (no locking doors, etc)
|
||||
*/
|
||||
return USB_STOR_TRANSPORT_GOOD;
|
||||
}
|
||||
|
||||
if (srb->cmnd[0] == START_STOP) {
|
||||
/* this is used by sd.c'check_scsidisk_media_change to detect
|
||||
media change */
|
||||
/*
|
||||
* this is used by sd.c'check_scsidisk_media_change to detect
|
||||
* media change
|
||||
*/
|
||||
usb_stor_dbg(us, "START_STOP\n");
|
||||
/* the first jumpshot_id_device after a media change returns
|
||||
an error (determined experimentally) */
|
||||
/*
|
||||
* the first jumpshot_id_device after a media change returns
|
||||
* an error (determined experimentally)
|
||||
*/
|
||||
rc = jumpshot_id_device(us, info);
|
||||
if (rc == USB_STOR_TRANSPORT_GOOD) {
|
||||
info->sense_key = NO_SENSE;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* Driver for Rio Karma
|
||||
/*
|
||||
* Driver for Rio Karma
|
||||
*
|
||||
* (c) 2006 Bob Copeland <me@bobcopeland.com>
|
||||
* (c) 2006 Keith Bennett <keith@mcs.st-and.ac.uk>
|
||||
|
|
|
|||
|
|
@ -65,7 +65,8 @@ static int option_rezero(struct us_data *us)
|
|||
goto out;
|
||||
}
|
||||
|
||||
/* Some of the devices need to be asked for a response, but we don't
|
||||
/*
|
||||
* Some of the devices need to be asked for a response, but we don't
|
||||
* care what that response is.
|
||||
*/
|
||||
usb_stor_bulk_transfer_buf(us,
|
||||
|
|
@ -140,7 +141,8 @@ int option_ms_init(struct us_data *us)
|
|||
|
||||
usb_stor_dbg(us, "Option MS: %s\n", "option_ms_init called");
|
||||
|
||||
/* Additional test for vendor information via INQUIRY,
|
||||
/*
|
||||
* Additional test for vendor information via INQUIRY,
|
||||
* because some vendor/product IDs are ambiguous
|
||||
*/
|
||||
result = option_inquiry(us);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* Driver for USB Mass Storage compliant devices
|
||||
/*
|
||||
* Driver for USB Mass Storage compliant devices
|
||||
*
|
||||
* Current development and maintenance by:
|
||||
* (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
|
||||
|
|
@ -75,7 +76,8 @@ void usb_stor_pad12_command(struct scsi_cmnd *srb, struct us_data *us)
|
|||
|
||||
void usb_stor_ufi_command(struct scsi_cmnd *srb, struct us_data *us)
|
||||
{
|
||||
/* fix some commands -- this is a form of mode translation
|
||||
/*
|
||||
* fix some commands -- this is a form of mode translation
|
||||
* UFI devices only accept 12 byte long commands
|
||||
*
|
||||
* NOTE: This only works because a scsi_cmnd struct field contains
|
||||
|
|
@ -127,7 +129,8 @@ EXPORT_SYMBOL_GPL(usb_stor_transparent_scsi_command);
|
|||
* Scatter-gather transfer buffer access routines
|
||||
***********************************************************************/
|
||||
|
||||
/* Copy a buffer of length buflen to/from the srb's transfer buffer.
|
||||
/*
|
||||
* Copy a buffer of length buflen to/from the srb's transfer buffer.
|
||||
* Update the **sgptr and *offset variables so that the next copy will
|
||||
* pick up from where this one left off.
|
||||
*/
|
||||
|
|
@ -175,7 +178,8 @@ unsigned int usb_stor_access_xfer_buf(unsigned char *buffer,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(usb_stor_access_xfer_buf);
|
||||
|
||||
/* Store the contents of buffer into srb's transfer buffer and set the
|
||||
/*
|
||||
* Store the contents of buffer into srb's transfer buffer and set the
|
||||
* SCSI residue.
|
||||
*/
|
||||
void usb_stor_set_xfer_buf(unsigned char *buffer,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* Driver for USB Mass Storage compliant devices
|
||||
/*
|
||||
* Driver for USB Mass Storage compliant devices
|
||||
* Protocol Functions Header File
|
||||
*
|
||||
* Current development and maintenance by:
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* Driver for Realtek RTS51xx USB card reader
|
||||
/*
|
||||
* Driver for Realtek RTS51xx USB card reader
|
||||
*
|
||||
* Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved.
|
||||
*
|
||||
|
|
@ -267,8 +268,10 @@ static int rts51x_bulk_transport(struct us_data *us, u8 lun,
|
|||
if (bcs->Tag != us->tag)
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
|
||||
/* try to compute the actual residue, based on how much data
|
||||
* was really transferred and what the device tells us */
|
||||
/*
|
||||
* try to compute the actual residue, based on how much data
|
||||
* was really transferred and what the device tells us
|
||||
*/
|
||||
if (residue)
|
||||
residue = residue < buf_len ? residue : buf_len;
|
||||
|
||||
|
|
@ -286,7 +289,8 @@ static int rts51x_bulk_transport(struct us_data *us, u8 lun,
|
|||
return USB_STOR_TRANSPORT_FAILED;
|
||||
|
||||
case US_BULK_STAT_PHASE:
|
||||
/* phase error -- note that a transport reset will be
|
||||
/*
|
||||
* phase error -- note that a transport reset will be
|
||||
* invoked by the invoke_transport() function
|
||||
*/
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* Driver for USB Mass Storage compliant devices
|
||||
/*
|
||||
* Driver for USB Mass Storage compliant devices
|
||||
* SCSI layer glue code
|
||||
*
|
||||
* Current development and maintenance by:
|
||||
|
|
@ -58,7 +59,8 @@
|
|||
#include "transport.h"
|
||||
#include "protocol.h"
|
||||
|
||||
/* Vendor IDs for companies that seem to include the READ CAPACITY bug
|
||||
/*
|
||||
* Vendor IDs for companies that seem to include the READ CAPACITY bug
|
||||
* in all their devices
|
||||
*/
|
||||
#define VENDOR_ID_NOKIA 0x0421
|
||||
|
|
@ -87,7 +89,8 @@ static int slave_alloc (struct scsi_device *sdev)
|
|||
*/
|
||||
sdev->inquiry_len = 36;
|
||||
|
||||
/* USB has unusual DMA-alignment requirements: Although the
|
||||
/*
|
||||
* USB has unusual DMA-alignment requirements: Although the
|
||||
* starting address of each scatter-gather element doesn't matter,
|
||||
* the length of each element except the last must be divisible
|
||||
* by the Bulk maxpacket value. There's currently no way to
|
||||
|
|
@ -115,7 +118,8 @@ static int slave_configure(struct scsi_device *sdev)
|
|||
{
|
||||
struct us_data *us = host_to_us(sdev->host);
|
||||
|
||||
/* Many devices have trouble transferring more than 32KB at a time,
|
||||
/*
|
||||
* Many devices have trouble transferring more than 32KB at a time,
|
||||
* while others have trouble with more than 64K. At this time we
|
||||
* are limiting both to 32K (64 sectores).
|
||||
*/
|
||||
|
|
@ -128,14 +132,22 @@ static int slave_configure(struct scsi_device *sdev)
|
|||
blk_queue_max_hw_sectors(sdev->request_queue,
|
||||
max_sectors);
|
||||
} else if (sdev->type == TYPE_TAPE) {
|
||||
/* Tapes need much higher max_sector limits, so just
|
||||
/*
|
||||
* Tapes need much higher max_sector limits, so just
|
||||
* raise it to the maximum possible (4 GB / 512) and
|
||||
* let the queue segment size sort out the real limit.
|
||||
*/
|
||||
blk_queue_max_hw_sectors(sdev->request_queue, 0x7FFFFF);
|
||||
} else if (us->pusb_dev->speed >= USB_SPEED_SUPER) {
|
||||
/*
|
||||
* USB3 devices will be limited to 2048 sectors. This gives us
|
||||
* better throughput on most devices.
|
||||
*/
|
||||
blk_queue_max_hw_sectors(sdev->request_queue, 2048);
|
||||
}
|
||||
|
||||
/* Some USB host controllers can't do DMA; they have to use PIO.
|
||||
/*
|
||||
* Some USB host controllers can't do DMA; they have to use PIO.
|
||||
* They indicate this by setting their dma_mask to NULL. For
|
||||
* such controllers we need to make sure the block layer sets
|
||||
* up bounce buffers in addressable memory.
|
||||
|
|
@ -143,17 +155,21 @@ static int slave_configure(struct scsi_device *sdev)
|
|||
if (!us->pusb_dev->bus->controller->dma_mask)
|
||||
blk_queue_bounce_limit(sdev->request_queue, BLK_BOUNCE_HIGH);
|
||||
|
||||
/* We can't put these settings in slave_alloc() because that gets
|
||||
/*
|
||||
* We can't put these settings in slave_alloc() because that gets
|
||||
* called before the device type is known. Consequently these
|
||||
* settings can't be overridden via the scsi devinfo mechanism. */
|
||||
* settings can't be overridden via the scsi devinfo mechanism.
|
||||
*/
|
||||
if (sdev->type == TYPE_DISK) {
|
||||
|
||||
/* Some vendors seem to put the READ CAPACITY bug into
|
||||
/*
|
||||
* Some vendors seem to put the READ CAPACITY bug into
|
||||
* all their devices -- primarily makers of cell phones
|
||||
* and digital cameras. Since these devices always use
|
||||
* flash media and can be expected to have an even number
|
||||
* of sectors, we will always enable the CAPACITY_HEURISTICS
|
||||
* flag unless told otherwise. */
|
||||
* flag unless told otherwise.
|
||||
*/
|
||||
switch (le16_to_cpu(us->pusb_dev->descriptor.idVendor)) {
|
||||
case VENDOR_ID_NOKIA:
|
||||
case VENDOR_ID_NIKON:
|
||||
|
|
@ -165,28 +181,36 @@ static int slave_configure(struct scsi_device *sdev)
|
|||
break;
|
||||
}
|
||||
|
||||
/* Disk-type devices use MODE SENSE(6) if the protocol
|
||||
/*
|
||||
* Disk-type devices use MODE SENSE(6) if the protocol
|
||||
* (SubClass) is Transparent SCSI, otherwise they use
|
||||
* MODE SENSE(10). */
|
||||
* MODE SENSE(10).
|
||||
*/
|
||||
if (us->subclass != USB_SC_SCSI && us->subclass != USB_SC_CYP_ATACB)
|
||||
sdev->use_10_for_ms = 1;
|
||||
|
||||
/* Many disks only accept MODE SENSE transfer lengths of
|
||||
* 192 bytes (that's what Windows uses). */
|
||||
/*
|
||||
*Many disks only accept MODE SENSE transfer lengths of
|
||||
* 192 bytes (that's what Windows uses).
|
||||
*/
|
||||
sdev->use_192_bytes_for_3f = 1;
|
||||
|
||||
/* Some devices don't like MODE SENSE with page=0x3f,
|
||||
/*
|
||||
* Some devices don't like MODE SENSE with page=0x3f,
|
||||
* which is the command used for checking if a device
|
||||
* is write-protected. Now that we tell the sd driver
|
||||
* to do a 192-byte transfer with this command the
|
||||
* majority of devices work fine, but a few still can't
|
||||
* handle it. The sd driver will simply assume those
|
||||
* devices are write-enabled. */
|
||||
* devices are write-enabled.
|
||||
*/
|
||||
if (us->fflags & US_FL_NO_WP_DETECT)
|
||||
sdev->skip_ms_page_3f = 1;
|
||||
|
||||
/* A number of devices have problems with MODE SENSE for
|
||||
* page x08, so we will skip it. */
|
||||
/*
|
||||
* A number of devices have problems with MODE SENSE for
|
||||
* page x08, so we will skip it.
|
||||
*/
|
||||
sdev->skip_ms_page_8 = 1;
|
||||
|
||||
/* Some devices don't handle VPD pages correctly */
|
||||
|
|
@ -198,15 +222,19 @@ static int slave_configure(struct scsi_device *sdev)
|
|||
/* Do not attempt to use WRITE SAME */
|
||||
sdev->no_write_same = 1;
|
||||
|
||||
/* Some disks return the total number of blocks in response
|
||||
/*
|
||||
* Some disks return the total number of blocks in response
|
||||
* to READ CAPACITY rather than the highest block number.
|
||||
* If this device makes that mistake, tell the sd driver. */
|
||||
* If this device makes that mistake, tell the sd driver.
|
||||
*/
|
||||
if (us->fflags & US_FL_FIX_CAPACITY)
|
||||
sdev->fix_capacity = 1;
|
||||
|
||||
/* A few disks have two indistinguishable version, one of
|
||||
/*
|
||||
* A few disks have two indistinguishable version, one of
|
||||
* which reports the correct capacity and the other does not.
|
||||
* The sd driver has to guess which is the case. */
|
||||
* The sd driver has to guess which is the case.
|
||||
*/
|
||||
if (us->fflags & US_FL_CAPACITY_HEURISTICS)
|
||||
sdev->guess_capacity = 1;
|
||||
|
||||
|
|
@ -227,26 +255,34 @@ static int slave_configure(struct scsi_device *sdev)
|
|||
if (sdev->scsi_level > SCSI_SPC_2)
|
||||
us->fflags |= US_FL_SANE_SENSE;
|
||||
|
||||
/* USB-IDE bridges tend to report SK = 0x04 (Non-recoverable
|
||||
/*
|
||||
* USB-IDE bridges tend to report SK = 0x04 (Non-recoverable
|
||||
* Hardware Error) when any low-level error occurs,
|
||||
* recoverable or not. Setting this flag tells the SCSI
|
||||
* midlayer to retry such commands, which frequently will
|
||||
* succeed and fix the error. The worst this can lead to
|
||||
* is an occasional series of retries that will all fail. */
|
||||
* is an occasional series of retries that will all fail.
|
||||
*/
|
||||
sdev->retry_hwerror = 1;
|
||||
|
||||
/* USB disks should allow restart. Some drives spin down
|
||||
* automatically, requiring a START-STOP UNIT command. */
|
||||
/*
|
||||
* USB disks should allow restart. Some drives spin down
|
||||
* automatically, requiring a START-STOP UNIT command.
|
||||
*/
|
||||
sdev->allow_restart = 1;
|
||||
|
||||
/* Some USB cardreaders have trouble reading an sdcard's last
|
||||
/*
|
||||
* Some USB cardreaders have trouble reading an sdcard's last
|
||||
* sector in a larger then 1 sector read, since the performance
|
||||
* impact is negligible we set this flag for all USB disks */
|
||||
* impact is negligible we set this flag for all USB disks
|
||||
*/
|
||||
sdev->last_sector_bug = 1;
|
||||
|
||||
/* Enable last-sector hacks for single-target devices using
|
||||
/*
|
||||
* Enable last-sector hacks for single-target devices using
|
||||
* the Bulk-only transport, unless we already know the
|
||||
* capacity will be decremented or is correct. */
|
||||
* capacity will be decremented or is correct.
|
||||
*/
|
||||
if (!(us->fflags & (US_FL_FIX_CAPACITY | US_FL_CAPACITY_OK |
|
||||
US_FL_SCM_MULT_TARG)) &&
|
||||
us->protocol == USB_PR_BULK)
|
||||
|
|
@ -262,9 +298,11 @@ static int slave_configure(struct scsi_device *sdev)
|
|||
|
||||
} else {
|
||||
|
||||
/* Non-disk-type devices don't need to blacklist any pages
|
||||
/*
|
||||
* Non-disk-type devices don't need to blacklist any pages
|
||||
* or to force 192-byte transfer lengths for MODE SENSE.
|
||||
* But they do need to use MODE SENSE(10). */
|
||||
* But they do need to use MODE SENSE(10).
|
||||
*/
|
||||
sdev->use_10_for_ms = 1;
|
||||
|
||||
/* Some (fake) usb cdrom devices don't like READ_DISC_INFO */
|
||||
|
|
@ -272,7 +310,8 @@ static int slave_configure(struct scsi_device *sdev)
|
|||
sdev->no_read_disc_info = 1;
|
||||
}
|
||||
|
||||
/* The CB and CBI transports have no way to pass LUN values
|
||||
/*
|
||||
* The CB and CBI transports have no way to pass LUN values
|
||||
* other than the bits in the second byte of a CDB. But those
|
||||
* bits don't get set to the LUN value if the device reports
|
||||
* scsi_level == 0 (UNKNOWN). Hence such devices must necessarily
|
||||
|
|
@ -282,13 +321,17 @@ static int slave_configure(struct scsi_device *sdev)
|
|||
sdev->scsi_level == SCSI_UNKNOWN)
|
||||
us->max_lun = 0;
|
||||
|
||||
/* Some devices choke when they receive a PREVENT-ALLOW MEDIUM
|
||||
* REMOVAL command, so suppress those commands. */
|
||||
/*
|
||||
* Some devices choke when they receive a PREVENT-ALLOW MEDIUM
|
||||
* REMOVAL command, so suppress those commands.
|
||||
*/
|
||||
if (us->fflags & US_FL_NOT_LOCKABLE)
|
||||
sdev->lockable = 0;
|
||||
|
||||
/* this is to satisfy the compiler, tho I don't think the
|
||||
* return code is ever checked anywhere. */
|
||||
/*
|
||||
* this is to satisfy the compiler, tho I don't think the
|
||||
* return code is ever checked anywhere.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -362,8 +405,10 @@ static int command_abort(struct scsi_cmnd *srb)
|
|||
|
||||
usb_stor_dbg(us, "%s called\n", __func__);
|
||||
|
||||
/* us->srb together with the TIMED_OUT, RESETTING, and ABORTING
|
||||
* bits are protected by the host lock. */
|
||||
/*
|
||||
* us->srb together with the TIMED_OUT, RESETTING, and ABORTING
|
||||
* bits are protected by the host lock.
|
||||
*/
|
||||
scsi_lock(us_to_host(us));
|
||||
|
||||
/* Is this command still active? */
|
||||
|
|
@ -373,11 +418,13 @@ static int command_abort(struct scsi_cmnd *srb)
|
|||
return FAILED;
|
||||
}
|
||||
|
||||
/* Set the TIMED_OUT bit. Also set the ABORTING bit, but only if
|
||||
/*
|
||||
* Set the TIMED_OUT bit. Also set the ABORTING bit, but only if
|
||||
* a device reset isn't already in progress (to avoid interfering
|
||||
* with the reset). Note that we must retain the host lock while
|
||||
* calling usb_stor_stop_transport(); otherwise it might interfere
|
||||
* with an auto-reset that begins as soon as we release the lock. */
|
||||
* with an auto-reset that begins as soon as we release the lock.
|
||||
*/
|
||||
set_bit(US_FLIDX_TIMED_OUT, &us->dflags);
|
||||
if (!test_bit(US_FLIDX_RESETTING, &us->dflags)) {
|
||||
set_bit(US_FLIDX_ABORTING, &us->dflags);
|
||||
|
|
@ -390,8 +437,10 @@ static int command_abort(struct scsi_cmnd *srb)
|
|||
return SUCCESS;
|
||||
}
|
||||
|
||||
/* This invokes the transport reset mechanism to reset the state of the
|
||||
* device */
|
||||
/*
|
||||
* This invokes the transport reset mechanism to reset the state of the
|
||||
* device
|
||||
*/
|
||||
static int device_reset(struct scsi_cmnd *srb)
|
||||
{
|
||||
struct us_data *us = host_to_us(srb->device->host);
|
||||
|
|
@ -419,9 +468,11 @@ static int bus_reset(struct scsi_cmnd *srb)
|
|||
return result < 0 ? FAILED : SUCCESS;
|
||||
}
|
||||
|
||||
/* Report a driver-initiated device reset to the SCSI layer.
|
||||
/*
|
||||
* Report a driver-initiated device reset to the SCSI layer.
|
||||
* Calling this for a SCSI-initiated reset is unnecessary but harmless.
|
||||
* The caller must own the SCSI host lock. */
|
||||
* The caller must own the SCSI host lock.
|
||||
*/
|
||||
void usb_stor_report_device_reset(struct us_data *us)
|
||||
{
|
||||
int i;
|
||||
|
|
@ -434,9 +485,11 @@ void usb_stor_report_device_reset(struct us_data *us)
|
|||
}
|
||||
}
|
||||
|
||||
/* Report a driver-initiated bus reset to the SCSI layer.
|
||||
/*
|
||||
* Report a driver-initiated bus reset to the SCSI layer.
|
||||
* Calling this for a SCSI-initiated reset is unnecessary but harmless.
|
||||
* The caller must not own the SCSI host lock. */
|
||||
* The caller must not own the SCSI host lock.
|
||||
*/
|
||||
void usb_stor_report_bus_reset(struct us_data *us)
|
||||
{
|
||||
struct Scsi_Host *host = us_to_host(us);
|
||||
|
|
@ -565,10 +618,28 @@ static const struct scsi_host_template usb_stor_host_template = {
|
|||
/* lots of sg segments can be handled */
|
||||
.sg_tablesize = SG_MAX_SEGMENTS,
|
||||
|
||||
/* limit the total size of a transfer to 120 KB */
|
||||
|
||||
/*
|
||||
* Limit the total size of a transfer to 120 KB.
|
||||
*
|
||||
* Some devices are known to choke with anything larger. It seems like
|
||||
* the problem stems from the fact that original IDE controllers had
|
||||
* only an 8-bit register to hold the number of sectors in one transfer
|
||||
* and even those couldn't handle a full 256 sectors.
|
||||
*
|
||||
* Because we want to make sure we interoperate with as many devices as
|
||||
* possible, we will maintain a 240 sector transfer size limit for USB
|
||||
* Mass Storage devices.
|
||||
*
|
||||
* Tests show that other operating have similar limits with Microsoft
|
||||
* Windows 7 limiting transfers to 128 sectors for both USB2 and USB3
|
||||
* and Apple Mac OS X 10.11 limiting transfers to 256 sectors for USB2
|
||||
* and 2048 for USB3 devices.
|
||||
*/
|
||||
.max_sectors = 240,
|
||||
|
||||
/* merge commands... this seems to help performance, but
|
||||
/*
|
||||
* merge commands... this seems to help performance, but
|
||||
* periodically someone should test to see which setting is more
|
||||
* optimal.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* Driver for USB Mass Storage compliant devices
|
||||
/*
|
||||
* Driver for USB Mass Storage compliant devices
|
||||
* SCSI Connecting Glue Header File
|
||||
*
|
||||
* Current development and maintenance by:
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue