mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 11:11:45 -04:00
USB patches for 4.12-rc1
Here is the big USB patchset for 4.12-rc1. Lots of good stuff here, after many many many attempts, the kernel finally has a working typeC interface, many thanks to the Heikki and Guenter and others who have taken the time to get this merged. It wasn't an easy path for them at all. There's also a staging driver that uses this new api, which is why it's coming in through this tree. Along with that, there's the usual huge number of changes for gadget drivers, xhci, and other stuff. Johan also finally refactored pretty much every driver that was looking at USB endpoints to do it in a common way, which will help prevent any "badly-formed" devices from causing problems in drivers. That too wasn't a simple task. All of these have been in linux-next for a while with no reported issues. Signed-off-by: Greg Kroah-Hartman <[email protected]> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCWQvEIQ8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+yny4gCePCXxnrQdMWE+IMXf1H1hMubLkVkAn0ZWgQkq BspgO7ZmGb+9Fpf6YvNz =nwAu -----END PGP SIGNATURE----- Merge tag 'usb-4.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb Pull USB updates from Greg KH: "Here is the big USB patchset for 4.12-rc1. Lots of good stuff here, after many many many attempts, the kernel finally has a working typeC interface, many thanks to Heikki and Guenter and others who have taken the time to get this merged. It wasn't an easy path for them at all. There's also a staging driver that uses this new api, which is why it's coming in through this tree. Along with that, there's the usual huge number of changes for gadget drivers, xhci, and other stuff. Johan also finally refactored pretty much every driver that was looking at USB endpoints to do it in a common way, which will help prevent any "badly-formed" devices from causing problems in drivers. That too wasn't a simple task. All of these have been in linux-next for a while with no reported issues" * tag 'usb-4.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (263 commits) staging: typec: Fairchild FUSB302 Type-c chip driver staging: typec: Type-C Port Controller Interface driver (tcpci) staging: typec: USB Type-C Port Manager (tcpm) usb: host: xhci: remove #ifdef around PM functions usb: musb: don't mark of_dev_auxdata as initdata usb: misc: legousbtower: Fix buffers on stack USB: Revert "cdc-wdm: fix "out-of-sync" due to missing notifications" usb: Make sure usb/phy/of gets built-in USB: storage: e-mail update in drivers/usb/storage/unusual_devs.h usb: host: xhci: print correct command ring address usb: host: xhci: delete sp_dma_buffers for scratchpad usb: host: xhci: using correct specification chapter reference for DCBAAP xhci: switch to pci_alloc_irq_vectors usb: host: xhci-plat: set resume_quirk() for R-Car controllers usb: host: xhci-plat: add resume_quirk() usb: host: xhci-plat: enable clk in resume timing usb: host: plat: Enable xHCI plat runtime PM USB: serial: ftdi_sio: add device ID for Microsemi/Arrow SF2PLUS Dev Kit USB: serial: constify static arrays usb: fix some references for /proc/bus/usb ...
This commit is contained in:
commit
8f28472a73
230 changed files with 15570 additions and 3809 deletions
|
|
@ -35,7 +35,6 @@ config USB_COMMON
|
|||
config USB_ARCH_HAS_HCD
|
||||
def_bool y
|
||||
|
||||
# ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
|
||||
config USB
|
||||
tristate "Support for Host-side USB"
|
||||
depends on USB_ARCH_HAS_HCD
|
||||
|
|
@ -73,6 +72,17 @@ config USB
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called usbcore.
|
||||
|
||||
config USB_PCI
|
||||
bool "PCI based USB host interface"
|
||||
depends on PCI
|
||||
default y
|
||||
---help---
|
||||
A lot of embeded system SOC (e.g. freescale T2080) have both
|
||||
PCI and USB modules. But USB module is controlled by registers
|
||||
directly, it have no relationship with PCI module.
|
||||
|
||||
When say N here it will not build PCI related code in USB driver.
|
||||
|
||||
if USB
|
||||
|
||||
source "drivers/usb/core/Kconfig"
|
||||
|
|
@ -152,6 +162,8 @@ source "drivers/usb/phy/Kconfig"
|
|||
|
||||
source "drivers/usb/gadget/Kconfig"
|
||||
|
||||
source "drivers/usb/typec/Kconfig"
|
||||
|
||||
config USB_LED_TRIG
|
||||
bool "USB LED Triggers"
|
||||
depends on LEDS_CLASS && LEDS_TRIGGERS
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ obj-$(CONFIG_USB_ISP1760) += isp1760/
|
|||
obj-$(CONFIG_USB_MON) += mon/
|
||||
obj-$(CONFIG_USB_MTU3) += mtu3/
|
||||
|
||||
obj-$(CONFIG_PCI) += host/
|
||||
obj-$(CONFIG_USB_PCI) += host/
|
||||
obj-$(CONFIG_USB_EHCI_HCD) += host/
|
||||
obj-$(CONFIG_USB_ISP116X_HCD) += host/
|
||||
obj-$(CONFIG_USB_OHCI_HCD) += host/
|
||||
|
|
@ -62,3 +62,5 @@ obj-$(CONFIG_USB_GADGET) += gadget/
|
|||
obj-$(CONFIG_USB_COMMON) += common/
|
||||
|
||||
obj-$(CONFIG_USBIP_CORE) += usbip/
|
||||
|
||||
obj-$(CONFIG_TYPEC) += typec/
|
||||
|
|
|
|||
|
|
@ -474,7 +474,7 @@ static ssize_t cxacru_sysfs_store_adsl_config(struct device *dev,
|
|||
ret = sscanf(buf + pos, "%x=%x%n", &index, &value, &tmp);
|
||||
if (ret < 2)
|
||||
return -EINVAL;
|
||||
if (index < 0 || index > 0x7f)
|
||||
if (index > 0x7f)
|
||||
return -EINVAL;
|
||||
if (tmp < 0 || tmp > len - pos)
|
||||
return -EINVAL;
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ config USB_CHIPIDEA_OF
|
|||
|
||||
config USB_CHIPIDEA_PCI
|
||||
tristate
|
||||
depends on PCI
|
||||
depends on USB_PCI
|
||||
depends on NOP_USB_XCEIV
|
||||
default USB_CHIPIDEA
|
||||
|
||||
|
|
|
|||
|
|
@ -177,6 +177,7 @@ struct hw_bank {
|
|||
* @td_pool: allocation pool for transfer descriptors
|
||||
* @gadget: device side representation for peripheral controller
|
||||
* @driver: gadget driver
|
||||
* @resume_state: save the state of gadget suspend from
|
||||
* @hw_ep_max: total number of endpoints supported by hardware
|
||||
* @ci_hw_ep: array of endpoints
|
||||
* @ep0_dir: ep0 direction
|
||||
|
|
@ -227,6 +228,7 @@ struct ci_hdrc {
|
|||
|
||||
struct usb_gadget gadget;
|
||||
struct usb_gadget_driver *driver;
|
||||
enum usb_device_state resume_state;
|
||||
unsigned hw_ep_max;
|
||||
struct ci_hw_ep ci_hw_ep[ENDPT_MAX];
|
||||
u32 ep0_dir;
|
||||
|
|
|
|||
|
|
@ -783,9 +783,6 @@ struct platform_device *ci_hdrc_add_device(struct device *dev,
|
|||
}
|
||||
|
||||
pdev->dev.parent = dev;
|
||||
pdev->dev.dma_mask = dev->dma_mask;
|
||||
pdev->dev.dma_parms = dev->dma_parms;
|
||||
dma_set_coherent_mask(&pdev->dev, dev->coherent_dma_mask);
|
||||
|
||||
ret = platform_device_add_resources(pdev, res, nres);
|
||||
if (ret)
|
||||
|
|
@ -841,6 +838,56 @@ static void ci_get_otg_capable(struct ci_hdrc *ci)
|
|||
}
|
||||
}
|
||||
|
||||
static ssize_t ci_role_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct ci_hdrc *ci = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%s\n", ci_role(ci)->name);
|
||||
}
|
||||
|
||||
static ssize_t ci_role_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t n)
|
||||
{
|
||||
struct ci_hdrc *ci = dev_get_drvdata(dev);
|
||||
enum ci_role role;
|
||||
int ret;
|
||||
|
||||
if (!(ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET])) {
|
||||
dev_warn(dev, "Current configuration is not dual-role, quit\n");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
for (role = CI_ROLE_HOST; role < CI_ROLE_END; role++)
|
||||
if (!strncmp(buf, ci->roles[role]->name,
|
||||
strlen(ci->roles[role]->name)))
|
||||
break;
|
||||
|
||||
if (role == CI_ROLE_END || role == ci->role)
|
||||
return -EINVAL;
|
||||
|
||||
pm_runtime_get_sync(dev);
|
||||
disable_irq(ci->irq);
|
||||
ci_role_stop(ci);
|
||||
ret = ci_role_start(ci, role);
|
||||
if (!ret && ci->role == CI_ROLE_GADGET)
|
||||
ci_handle_vbus_change(ci);
|
||||
enable_irq(ci->irq);
|
||||
pm_runtime_put_sync(dev);
|
||||
|
||||
return (ret == 0) ? n : ret;
|
||||
}
|
||||
static DEVICE_ATTR(role, 0644, ci_role_show, ci_role_store);
|
||||
|
||||
static struct attribute *ci_attrs[] = {
|
||||
&dev_attr_role.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group ci_attr_group = {
|
||||
.attrs = ci_attrs,
|
||||
};
|
||||
|
||||
static int ci_hdrc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
|
|
@ -1007,11 +1054,18 @@ static int ci_hdrc_probe(struct platform_device *pdev)
|
|||
ci_hdrc_otg_fsm_start(ci);
|
||||
|
||||
device_set_wakeup_capable(&pdev->dev, true);
|
||||
|
||||
ret = dbg_create_files(ci);
|
||||
if (!ret)
|
||||
return 0;
|
||||
if (ret)
|
||||
goto stop;
|
||||
|
||||
ret = sysfs_create_group(&dev->kobj, &ci_attr_group);
|
||||
if (ret)
|
||||
goto remove_debug;
|
||||
|
||||
return 0;
|
||||
|
||||
remove_debug:
|
||||
dbg_remove_files(ci);
|
||||
stop:
|
||||
ci_role_destroy(ci);
|
||||
deinit_phy:
|
||||
|
|
@ -1033,6 +1087,7 @@ static int ci_hdrc_remove(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
dbg_remove_files(ci);
|
||||
sysfs_remove_group(&ci->dev->kobj, &ci_attr_group);
|
||||
ci_role_destroy(ci);
|
||||
ci_hdrc_enter_lpm(ci, true);
|
||||
ci_usb_phy_exit(ci);
|
||||
|
|
|
|||
|
|
@ -123,7 +123,8 @@ static int host_start(struct ci_hdrc *ci)
|
|||
if (usb_disabled())
|
||||
return -ENODEV;
|
||||
|
||||
hcd = usb_create_hcd(&ci_ehci_hc_driver, ci->dev, dev_name(ci->dev));
|
||||
hcd = __usb_create_hcd(&ci_ehci_hc_driver, ci->dev->parent,
|
||||
ci->dev, dev_name(ci->dev), NULL);
|
||||
if (!hcd)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
|
|||
|
|
@ -423,7 +423,8 @@ static int _hardware_enqueue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
|
|||
|
||||
hwreq->req.status = -EALREADY;
|
||||
|
||||
ret = usb_gadget_map_request(&ci->gadget, &hwreq->req, hwep->dir);
|
||||
ret = usb_gadget_map_request_by_dev(ci->dev->parent,
|
||||
&hwreq->req, hwep->dir);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -603,7 +604,8 @@ static int _hardware_dequeue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
|
|||
list_del_init(&node->td);
|
||||
}
|
||||
|
||||
usb_gadget_unmap_request(&hwep->ci->gadget, &hwreq->req, hwep->dir);
|
||||
usb_gadget_unmap_request_by_dev(hwep->ci->dev->parent,
|
||||
&hwreq->req, hwep->dir);
|
||||
|
||||
hwreq->req.actual += actual;
|
||||
|
||||
|
|
@ -1845,27 +1847,32 @@ static irqreturn_t udc_irq(struct ci_hdrc *ci)
|
|||
if (USBi_PCI & intr) {
|
||||
ci->gadget.speed = hw_port_is_high_speed(ci) ?
|
||||
USB_SPEED_HIGH : USB_SPEED_FULL;
|
||||
if (ci->suspended && ci->driver->resume) {
|
||||
spin_unlock(&ci->lock);
|
||||
ci->driver->resume(&ci->gadget);
|
||||
spin_lock(&ci->lock);
|
||||
if (ci->suspended) {
|
||||
if (ci->driver->resume) {
|
||||
spin_unlock(&ci->lock);
|
||||
ci->driver->resume(&ci->gadget);
|
||||
spin_lock(&ci->lock);
|
||||
}
|
||||
ci->suspended = 0;
|
||||
usb_gadget_set_state(&ci->gadget,
|
||||
ci->resume_state);
|
||||
}
|
||||
}
|
||||
|
||||
if (USBi_UI & intr)
|
||||
isr_tr_complete_handler(ci);
|
||||
|
||||
if (USBi_SLI & intr) {
|
||||
if ((USBi_SLI & intr) && !(ci->suspended)) {
|
||||
ci->suspended = 1;
|
||||
ci->resume_state = ci->gadget.state;
|
||||
if (ci->gadget.speed != USB_SPEED_UNKNOWN &&
|
||||
ci->driver->suspend) {
|
||||
ci->suspended = 1;
|
||||
spin_unlock(&ci->lock);
|
||||
ci->driver->suspend(&ci->gadget);
|
||||
usb_gadget_set_state(&ci->gadget,
|
||||
USB_STATE_SUSPENDED);
|
||||
spin_lock(&ci->lock);
|
||||
}
|
||||
usb_gadget_set_state(&ci->gadget,
|
||||
USB_STATE_SUSPENDED);
|
||||
}
|
||||
retval = IRQ_HANDLED;
|
||||
} else {
|
||||
|
|
@ -1899,13 +1906,13 @@ static int udc_start(struct ci_hdrc *ci)
|
|||
INIT_LIST_HEAD(&ci->gadget.ep_list);
|
||||
|
||||
/* alloc resources */
|
||||
ci->qh_pool = dma_pool_create("ci_hw_qh", dev,
|
||||
ci->qh_pool = dma_pool_create("ci_hw_qh", dev->parent,
|
||||
sizeof(struct ci_hw_qh),
|
||||
64, CI_HDRC_PAGE_SIZE);
|
||||
if (ci->qh_pool == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
ci->td_pool = dma_pool_create("ci_hw_td", dev,
|
||||
ci->td_pool = dma_pool_create("ci_hw_td", dev->parent,
|
||||
sizeof(struct ci_hw_td),
|
||||
64, CI_HDRC_PAGE_SIZE);
|
||||
if (ci->td_pool == NULL) {
|
||||
|
|
@ -1973,6 +1980,8 @@ static void udc_id_switch_for_host(struct ci_hdrc *ci)
|
|||
*/
|
||||
if (ci->is_otg)
|
||||
hw_write_otgsc(ci, OTGSC_BSVIE | OTGSC_BSVIS, OTGSC_BSVIS);
|
||||
|
||||
ci->vbus_active = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ config USB_ACM
|
|||
Please read <file:Documentation/usb/acm.txt> for details.
|
||||
|
||||
If your modem only reports "Cls=ff(vend.)" in the descriptors in
|
||||
/proc/bus/usb/devices, then your modem will not work with this
|
||||
/sys/kernel/debug/usb/devices, then your modem will not work with this
|
||||
driver.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/tty_driver.h>
|
||||
|
|
@ -283,39 +284,13 @@ static DEVICE_ATTR(iCountryCodeRelDate, S_IRUGO, show_country_rel_date, NULL);
|
|||
* Interrupt handlers for various ACM device responses
|
||||
*/
|
||||
|
||||
/* control interface reports status changes with "interrupt" transfers */
|
||||
static void acm_ctrl_irq(struct urb *urb)
|
||||
static void acm_process_notification(struct acm *acm, unsigned char *buf)
|
||||
{
|
||||
struct acm *acm = urb->context;
|
||||
struct usb_cdc_notification *dr = urb->transfer_buffer;
|
||||
unsigned char *data;
|
||||
int newctrl;
|
||||
int difference;
|
||||
int retval;
|
||||
int status = urb->status;
|
||||
struct usb_cdc_notification *dr = (struct usb_cdc_notification *)buf;
|
||||
unsigned char *data = buf + sizeof(struct usb_cdc_notification);
|
||||
|
||||
switch (status) {
|
||||
case 0:
|
||||
/* success */
|
||||
break;
|
||||
case -ECONNRESET:
|
||||
case -ENOENT:
|
||||
case -ESHUTDOWN:
|
||||
/* this urb is terminated, clean up */
|
||||
dev_dbg(&acm->control->dev,
|
||||
"%s - urb shutting down with status: %d\n",
|
||||
__func__, status);
|
||||
return;
|
||||
default:
|
||||
dev_dbg(&acm->control->dev,
|
||||
"%s - nonzero urb status received: %d\n",
|
||||
__func__, status);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
usb_mark_last_busy(acm->dev);
|
||||
|
||||
data = (unsigned char *)(dr + 1);
|
||||
switch (dr->bNotificationType) {
|
||||
case USB_CDC_NOTIFY_NETWORK_CONNECTION:
|
||||
dev_dbg(&acm->control->dev,
|
||||
|
|
@ -323,7 +298,15 @@ static void acm_ctrl_irq(struct urb *urb)
|
|||
break;
|
||||
|
||||
case USB_CDC_NOTIFY_SERIAL_STATE:
|
||||
if (le16_to_cpu(dr->wLength) != 2) {
|
||||
dev_dbg(&acm->control->dev,
|
||||
"%s - malformed serial state\n", __func__);
|
||||
break;
|
||||
}
|
||||
|
||||
newctrl = get_unaligned_le16(data);
|
||||
dev_dbg(&acm->control->dev,
|
||||
"%s - serial state: 0x%x\n", __func__, newctrl);
|
||||
|
||||
if (!acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
|
||||
dev_dbg(&acm->control->dev,
|
||||
|
|
@ -359,13 +342,86 @@ static void acm_ctrl_irq(struct urb *urb)
|
|||
|
||||
default:
|
||||
dev_dbg(&acm->control->dev,
|
||||
"%s - unknown notification %d received: index %d "
|
||||
"len %d data0 %d data1 %d\n",
|
||||
"%s - unknown notification %d received: index %d len %d\n",
|
||||
__func__,
|
||||
dr->bNotificationType, dr->wIndex,
|
||||
dr->wLength, data[0], data[1]);
|
||||
break;
|
||||
dr->bNotificationType, dr->wIndex, dr->wLength);
|
||||
}
|
||||
}
|
||||
|
||||
/* control interface reports status changes with "interrupt" transfers */
|
||||
static void acm_ctrl_irq(struct urb *urb)
|
||||
{
|
||||
struct acm *acm = urb->context;
|
||||
struct usb_cdc_notification *dr = urb->transfer_buffer;
|
||||
unsigned int current_size = urb->actual_length;
|
||||
unsigned int expected_size, copy_size, alloc_size;
|
||||
int retval;
|
||||
int status = urb->status;
|
||||
|
||||
switch (status) {
|
||||
case 0:
|
||||
/* success */
|
||||
break;
|
||||
case -ECONNRESET:
|
||||
case -ENOENT:
|
||||
case -ESHUTDOWN:
|
||||
/* this urb is terminated, clean up */
|
||||
acm->nb_index = 0;
|
||||
dev_dbg(&acm->control->dev,
|
||||
"%s - urb shutting down with status: %d\n",
|
||||
__func__, status);
|
||||
return;
|
||||
default:
|
||||
dev_dbg(&acm->control->dev,
|
||||
"%s - nonzero urb status received: %d\n",
|
||||
__func__, status);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
usb_mark_last_busy(acm->dev);
|
||||
|
||||
if (acm->nb_index)
|
||||
dr = (struct usb_cdc_notification *)acm->notification_buffer;
|
||||
|
||||
/* size = notification-header + (optional) data */
|
||||
expected_size = sizeof(struct usb_cdc_notification) +
|
||||
le16_to_cpu(dr->wLength);
|
||||
|
||||
if (current_size < expected_size) {
|
||||
/* notification is transmitted fragmented, reassemble */
|
||||
if (acm->nb_size < expected_size) {
|
||||
if (acm->nb_size) {
|
||||
kfree(acm->notification_buffer);
|
||||
acm->nb_size = 0;
|
||||
}
|
||||
alloc_size = roundup_pow_of_two(expected_size);
|
||||
/*
|
||||
* kmalloc ensures a valid notification_buffer after a
|
||||
* use of kfree in case the previous allocation was too
|
||||
* small. Final freeing is done on disconnect.
|
||||
*/
|
||||
acm->notification_buffer =
|
||||
kmalloc(alloc_size, GFP_ATOMIC);
|
||||
if (!acm->notification_buffer)
|
||||
goto exit;
|
||||
acm->nb_size = alloc_size;
|
||||
}
|
||||
|
||||
copy_size = min(current_size,
|
||||
expected_size - acm->nb_index);
|
||||
|
||||
memcpy(&acm->notification_buffer[acm->nb_index],
|
||||
urb->transfer_buffer, copy_size);
|
||||
acm->nb_index += copy_size;
|
||||
current_size = acm->nb_index;
|
||||
}
|
||||
|
||||
if (current_size >= expected_size) {
|
||||
/* notification complete */
|
||||
acm_process_notification(acm, (unsigned char *)dr);
|
||||
acm->nb_index = 0;
|
||||
}
|
||||
|
||||
exit:
|
||||
retval = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (retval && retval != -EPERM)
|
||||
|
|
@ -1174,6 +1230,7 @@ static int acm_probe(struct usb_interface *intf,
|
|||
int combined_interfaces = 0;
|
||||
struct device *tty_dev;
|
||||
int rv = -ENOMEM;
|
||||
int res;
|
||||
|
||||
/* normal quirks */
|
||||
quirks = (unsigned long)id->driver_info;
|
||||
|
|
@ -1274,23 +1331,12 @@ static int acm_probe(struct usb_interface *intf,
|
|||
return -EINVAL;
|
||||
}
|
||||
look_for_collapsed_interface:
|
||||
for (i = 0; i < 3; i++) {
|
||||
struct usb_endpoint_descriptor *ep;
|
||||
ep = &data_interface->cur_altsetting->endpoint[i].desc;
|
||||
res = usb_find_common_endpoints(data_interface->cur_altsetting,
|
||||
&epread, &epwrite, &epctrl, NULL);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
if (usb_endpoint_is_int_in(ep))
|
||||
epctrl = ep;
|
||||
else if (usb_endpoint_is_bulk_out(ep))
|
||||
epwrite = ep;
|
||||
else if (usb_endpoint_is_bulk_in(ep))
|
||||
epread = ep;
|
||||
else
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!epctrl || !epread || !epwrite)
|
||||
return -ENODEV;
|
||||
else
|
||||
goto made_compressed_probe;
|
||||
goto made_compressed_probe;
|
||||
}
|
||||
|
||||
skip_normal_probe:
|
||||
|
|
@ -1488,6 +1534,9 @@ skip_countries:
|
|||
epctrl->bInterval ? epctrl->bInterval : 16);
|
||||
acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
acm->ctrlurb->transfer_dma = acm->ctrl_dma;
|
||||
acm->notification_buffer = NULL;
|
||||
acm->nb_index = 0;
|
||||
acm->nb_size = 0;
|
||||
|
||||
dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);
|
||||
|
||||
|
|
@ -1580,6 +1629,8 @@ static void acm_disconnect(struct usb_interface *intf)
|
|||
usb_free_coherent(acm->dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
|
||||
acm_read_buffers_free(acm);
|
||||
|
||||
kfree(acm->notification_buffer);
|
||||
|
||||
if (!acm->combined_interfaces)
|
||||
usb_driver_release_interface(&acm_driver, intf == acm->control ?
|
||||
acm->data : acm->control);
|
||||
|
|
|
|||
|
|
@ -98,7 +98,9 @@ struct acm {
|
|||
struct acm_wb *putbuffer; /* for acm_tty_put_char() */
|
||||
int rx_buflimit;
|
||||
spinlock_t read_lock;
|
||||
int write_used; /* number of non-empty write buffers */
|
||||
u8 *notification_buffer; /* to reassemble fragmented notifications */
|
||||
unsigned int nb_index;
|
||||
unsigned int nb_size;
|
||||
int transmitting;
|
||||
spinlock_t write_lock;
|
||||
struct mutex mutex;
|
||||
|
|
|
|||
|
|
@ -58,7 +58,6 @@ MODULE_DEVICE_TABLE (usb, wdm_ids);
|
|||
#define WDM_SUSPENDING 8
|
||||
#define WDM_RESETTING 9
|
||||
#define WDM_OVERFLOW 10
|
||||
#define WDM_DRAIN_ON_OPEN 11
|
||||
|
||||
#define WDM_MAX 16
|
||||
|
||||
|
|
@ -182,7 +181,7 @@ static void wdm_in_callback(struct urb *urb)
|
|||
"nonzero urb status received: -ESHUTDOWN\n");
|
||||
goto skip_error;
|
||||
case -EPIPE:
|
||||
dev_dbg(&desc->intf->dev,
|
||||
dev_err(&desc->intf->dev,
|
||||
"nonzero urb status received: -EPIPE\n");
|
||||
break;
|
||||
default:
|
||||
|
|
@ -210,25 +209,6 @@ static void wdm_in_callback(struct urb *urb)
|
|||
desc->reslength = length;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Handling devices with the WDM_DRAIN_ON_OPEN flag set:
|
||||
* If desc->resp_count is unset, then the urb was submitted
|
||||
* without a prior notification. If the device returned any
|
||||
* data, then this implies that it had messages queued without
|
||||
* notifying us. Continue reading until that queue is flushed.
|
||||
*/
|
||||
if (!desc->resp_count) {
|
||||
if (!length) {
|
||||
/* do not propagate the expected -EPIPE */
|
||||
desc->rerr = 0;
|
||||
goto unlock;
|
||||
}
|
||||
dev_dbg(&desc->intf->dev, "got %d bytes without notification\n", length);
|
||||
set_bit(WDM_RESPONDING, &desc->flags);
|
||||
usb_submit_urb(desc->response, GFP_ATOMIC);
|
||||
}
|
||||
|
||||
skip_error:
|
||||
set_bit(WDM_READ, &desc->flags);
|
||||
wake_up(&desc->wait);
|
||||
|
|
@ -243,7 +223,6 @@ skip_error:
|
|||
service_outstanding_interrupt(desc);
|
||||
}
|
||||
|
||||
unlock:
|
||||
spin_unlock(&desc->iuspin);
|
||||
}
|
||||
|
||||
|
|
@ -686,17 +665,6 @@ static int wdm_open(struct inode *inode, struct file *file)
|
|||
dev_err(&desc->intf->dev,
|
||||
"Error submitting int urb - %d\n", rv);
|
||||
rv = usb_translate_errors(rv);
|
||||
} else if (test_bit(WDM_DRAIN_ON_OPEN, &desc->flags)) {
|
||||
/*
|
||||
* Some devices keep pending messages queued
|
||||
* without resending notifications. We must
|
||||
* flush the message queue before we can
|
||||
* assume a one-to-one relationship between
|
||||
* notifications and messages in the queue
|
||||
*/
|
||||
dev_dbg(&desc->intf->dev, "draining queued data\n");
|
||||
set_bit(WDM_RESPONDING, &desc->flags);
|
||||
rv = usb_submit_urb(desc->response, GFP_KERNEL);
|
||||
}
|
||||
} else {
|
||||
rv = 0;
|
||||
|
|
@ -803,8 +771,7 @@ static void wdm_rxwork(struct work_struct *work)
|
|||
/* --- hotplug --- */
|
||||
|
||||
static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor *ep,
|
||||
u16 bufsize, int (*manage_power)(struct usb_interface *, int),
|
||||
bool drain_on_open)
|
||||
u16 bufsize, int (*manage_power)(struct usb_interface *, int))
|
||||
{
|
||||
int rv = -ENOMEM;
|
||||
struct wdm_device *desc;
|
||||
|
|
@ -891,68 +858,6 @@ static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor
|
|||
|
||||
desc->manage_power = manage_power;
|
||||
|
||||
/*
|
||||
* "drain_on_open" enables a hack to work around a firmware
|
||||
* issue observed on network functions, in particular MBIM
|
||||
* functions.
|
||||
*
|
||||
* Quoting section 7 of the CDC-WMC r1.1 specification:
|
||||
*
|
||||
* "The firmware shall interpret GetEncapsulatedResponse as a
|
||||
* request to read response bytes. The firmware shall send
|
||||
* the next wLength bytes from the response. The firmware
|
||||
* shall allow the host to retrieve data using any number of
|
||||
* GetEncapsulatedResponse requests. The firmware shall
|
||||
* return a zero- length reply if there are no data bytes
|
||||
* available.
|
||||
*
|
||||
* The firmware shall send ResponseAvailable notifications
|
||||
* periodically, using any appropriate algorithm, to inform
|
||||
* the host that there is data available in the reply
|
||||
* buffer. The firmware is allowed to send ResponseAvailable
|
||||
* notifications even if there is no data available, but
|
||||
* this will obviously reduce overall performance."
|
||||
*
|
||||
* These requirements, although they make equally sense, are
|
||||
* often not implemented by network functions. Some firmwares
|
||||
* will queue data indefinitely, without ever resending a
|
||||
* notification. The result is that the driver and firmware
|
||||
* loses "syncronization" if the driver ever fails to respond
|
||||
* to a single notification, something which easily can happen
|
||||
* on release(). When this happens, the driver will appear to
|
||||
* never receive notifications for the most current data. Each
|
||||
* notification will only cause a single read, which returns
|
||||
* the oldest data in the firmware's queue.
|
||||
*
|
||||
* The "drain_on_open" hack resolves the situation by draining
|
||||
* data from the firmware until none is returned, without a
|
||||
* prior notification.
|
||||
*
|
||||
* This will inevitably race with the firmware, risking that
|
||||
* we read data from the device before handling the associated
|
||||
* notification. To make things worse, some of the devices
|
||||
* needing the hack do not implement the "return zero if no
|
||||
* data is available" requirement either. Instead they return
|
||||
* an error on the subsequent read in this case. This means
|
||||
* that "winning" the race can cause an unexpected EIO to
|
||||
* userspace.
|
||||
*
|
||||
* "winning" the race is more likely on resume() than on
|
||||
* open(), and the unexpected error is more harmful in the
|
||||
* middle of an open session. The hack is therefore only
|
||||
* applied on open(), and not on resume() where it logically
|
||||
* would be equally necessary. So we define open() as the only
|
||||
* driver <-> device "syncronization point". Should we happen
|
||||
* to lose a notification after open(), then syncronization
|
||||
* will be lost until release()
|
||||
*
|
||||
* The hack should not be enabled for CDC WDM devices
|
||||
* conforming to the CDC-WMC r1.1 specification. This is
|
||||
* ensured by setting drain_on_open to false in wdm_probe().
|
||||
*/
|
||||
if (drain_on_open)
|
||||
set_bit(WDM_DRAIN_ON_OPEN, &desc->flags);
|
||||
|
||||
spin_lock(&wdm_device_list_lock);
|
||||
list_add(&desc->device_list, &wdm_device_list);
|
||||
spin_unlock(&wdm_device_list_lock);
|
||||
|
|
@ -1006,7 +911,7 @@ static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
|||
goto err;
|
||||
ep = &iface->endpoint[0].desc;
|
||||
|
||||
rv = wdm_create(intf, ep, maxcom, &wdm_manage_power, false);
|
||||
rv = wdm_create(intf, ep, maxcom, &wdm_manage_power);
|
||||
|
||||
err:
|
||||
return rv;
|
||||
|
|
@ -1038,7 +943,7 @@ struct usb_driver *usb_cdc_wdm_register(struct usb_interface *intf,
|
|||
{
|
||||
int rv = -EINVAL;
|
||||
|
||||
rv = wdm_create(intf, ep, bufsize, manage_power, true);
|
||||
rv = wdm_create(intf, ep, bufsize, manage_power);
|
||||
if (rv < 0)
|
||||
goto err;
|
||||
|
||||
|
|
|
|||
|
|
@ -294,7 +294,7 @@ static int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, i
|
|||
|
||||
/*
|
||||
* See the description for usblp_select_alts() below for the usage
|
||||
* explanation. Look into your /proc/bus/usb/devices and dmesg in
|
||||
* explanation. Look into your /sys/kernel/debug/usb/devices and dmesg in
|
||||
* case of any trouble.
|
||||
*/
|
||||
static int proto_bias = -1;
|
||||
|
|
@ -1239,8 +1239,9 @@ static int usblp_select_alts(struct usblp *usblp)
|
|||
{
|
||||
struct usb_interface *if_alt;
|
||||
struct usb_host_interface *ifd;
|
||||
struct usb_endpoint_descriptor *epd, *epwrite, *epread;
|
||||
int p, i, e;
|
||||
struct usb_endpoint_descriptor *epwrite, *epread;
|
||||
int p, i;
|
||||
int res;
|
||||
|
||||
if_alt = usblp->intf;
|
||||
|
||||
|
|
@ -1260,31 +1261,21 @@ static int usblp_select_alts(struct usblp *usblp)
|
|||
ifd->desc.bInterfaceProtocol > USBLP_LAST_PROTOCOL)
|
||||
continue;
|
||||
|
||||
/* Look for bulk OUT and IN endpoints. */
|
||||
epwrite = epread = NULL;
|
||||
for (e = 0; e < ifd->desc.bNumEndpoints; e++) {
|
||||
epd = &ifd->endpoint[e].desc;
|
||||
|
||||
if (usb_endpoint_is_bulk_out(epd))
|
||||
if (!epwrite)
|
||||
epwrite = epd;
|
||||
|
||||
if (usb_endpoint_is_bulk_in(epd))
|
||||
if (!epread)
|
||||
epread = epd;
|
||||
/* Look for the expected bulk endpoints. */
|
||||
if (ifd->desc.bInterfaceProtocol > 1) {
|
||||
res = usb_find_common_endpoints(ifd,
|
||||
&epread, &epwrite, NULL, NULL);
|
||||
} else {
|
||||
epread = NULL;
|
||||
res = usb_find_bulk_out_endpoint(ifd, &epwrite);
|
||||
}
|
||||
|
||||
/* Ignore buggy hardware without the right endpoints. */
|
||||
if (!epwrite || (ifd->desc.bInterfaceProtocol > 1 && !epread))
|
||||
if (res)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Turn off reads for USB_CLASS_PRINTER/1/1 (unidirectional)
|
||||
* interfaces and buggy bidirectional printers.
|
||||
*/
|
||||
if (ifd->desc.bInterfaceProtocol == 1) {
|
||||
epread = NULL;
|
||||
} else if (usblp->quirks & USBLP_QUIRK_BIDIR) {
|
||||
/* Turn off reads for buggy bidirectional printers. */
|
||||
if (usblp->quirks & USBLP_QUIRK_BIDIR) {
|
||||
printk(KERN_INFO "usblp%d: Disabling reads from "
|
||||
"problematic bidirectional printer\n",
|
||||
usblp->minor);
|
||||
|
|
|
|||
|
|
@ -1375,7 +1375,7 @@ static int usbtmc_probe(struct usb_interface *intf,
|
|||
{
|
||||
struct usbtmc_device_data *data;
|
||||
struct usb_host_interface *iface_desc;
|
||||
struct usb_endpoint_descriptor *endpoint;
|
||||
struct usb_endpoint_descriptor *bulk_in, *bulk_out, *int_in;
|
||||
int n;
|
||||
int retcode;
|
||||
|
||||
|
|
@ -1421,49 +1421,29 @@ static int usbtmc_probe(struct usb_interface *intf,
|
|||
iface_desc = data->intf->cur_altsetting;
|
||||
data->ifnum = iface_desc->desc.bInterfaceNumber;
|
||||
|
||||
/* Find bulk in endpoint */
|
||||
for (n = 0; n < iface_desc->desc.bNumEndpoints; n++) {
|
||||
endpoint = &iface_desc->endpoint[n].desc;
|
||||
|
||||
if (usb_endpoint_is_bulk_in(endpoint)) {
|
||||
data->bulk_in = endpoint->bEndpointAddress;
|
||||
dev_dbg(&intf->dev, "Found bulk in endpoint at %u\n",
|
||||
data->bulk_in);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Find bulk out endpoint */
|
||||
for (n = 0; n < iface_desc->desc.bNumEndpoints; n++) {
|
||||
endpoint = &iface_desc->endpoint[n].desc;
|
||||
|
||||
if (usb_endpoint_is_bulk_out(endpoint)) {
|
||||
data->bulk_out = endpoint->bEndpointAddress;
|
||||
dev_dbg(&intf->dev, "Found Bulk out endpoint at %u\n",
|
||||
data->bulk_out);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!data->bulk_out || !data->bulk_in) {
|
||||
/* Find bulk endpoints */
|
||||
retcode = usb_find_common_endpoints(iface_desc,
|
||||
&bulk_in, &bulk_out, NULL, NULL);
|
||||
if (retcode) {
|
||||
dev_err(&intf->dev, "bulk endpoints not found\n");
|
||||
retcode = -ENODEV;
|
||||
goto err_put;
|
||||
}
|
||||
|
||||
/* Find int endpoint */
|
||||
for (n = 0; n < iface_desc->desc.bNumEndpoints; n++) {
|
||||
endpoint = &iface_desc->endpoint[n].desc;
|
||||
data->bulk_in = bulk_in->bEndpointAddress;
|
||||
dev_dbg(&intf->dev, "Found bulk in endpoint at %u\n", data->bulk_in);
|
||||
|
||||
if (usb_endpoint_is_int_in(endpoint)) {
|
||||
data->iin_ep_present = 1;
|
||||
data->iin_ep = endpoint->bEndpointAddress;
|
||||
data->iin_wMaxPacketSize = usb_endpoint_maxp(endpoint);
|
||||
data->iin_interval = endpoint->bInterval;
|
||||
dev_dbg(&intf->dev, "Found Int in endpoint at %u\n",
|
||||
data->bulk_out = bulk_out->bEndpointAddress;
|
||||
dev_dbg(&intf->dev, "Found Bulk out endpoint at %u\n", data->bulk_out);
|
||||
|
||||
/* Find int endpoint */
|
||||
retcode = usb_find_int_in_endpoint(iface_desc, &int_in);
|
||||
if (!retcode) {
|
||||
data->iin_ep_present = 1;
|
||||
data->iin_ep = int_in->bEndpointAddress;
|
||||
data->iin_wMaxPacketSize = usb_endpoint_maxp(int_in);
|
||||
data->iin_interval = int_in->bInterval;
|
||||
dev_dbg(&intf->dev, "Found Int in endpoint at %u\n",
|
||||
data->iin_ep);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
retcode = get_capabilities(data);
|
||||
|
|
|
|||
|
|
@ -31,6 +31,13 @@
|
|||
#include <linux/usb/otg.h>
|
||||
#include <linux/usb/otg-fsm.h>
|
||||
|
||||
#ifdef VERBOSE
|
||||
#define VDBG(fmt, args...) pr_debug("[%s] " fmt, \
|
||||
__func__, ## args)
|
||||
#else
|
||||
#define VDBG(stuff...) do {} while (0)
|
||||
#endif
|
||||
|
||||
/* Change USB protocol when there is a protocol change */
|
||||
static int otg_set_protocol(struct otg_fsm *fsm, int protocol)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ usbcore-y += devio.o notify.o generic.o quirks.o devices.o
|
|||
usbcore-y += port.o
|
||||
|
||||
usbcore-$(CONFIG_OF) += of.o
|
||||
usbcore-$(CONFIG_PCI) += hcd-pci.o
|
||||
usbcore-$(CONFIG_USB_PCI) += hcd-pci.o
|
||||
usbcore-$(CONFIG_ACPI) += usb-acpi.o
|
||||
|
||||
obj-$(CONFIG_USB) += usbcore.o
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ int hcd_buffer_create(struct usb_hcd *hcd)
|
|||
int i, size;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_HAS_DMA) ||
|
||||
(!hcd->self.controller->dma_mask &&
|
||||
(!is_device_dma_capable(hcd->self.sysdev) &&
|
||||
!(hcd->driver->flags & HCD_LOCAL_MEM)))
|
||||
return 0;
|
||||
|
||||
|
|
@ -75,7 +75,7 @@ int hcd_buffer_create(struct usb_hcd *hcd)
|
|||
if (!size)
|
||||
continue;
|
||||
snprintf(name, sizeof(name), "buffer-%d", size);
|
||||
hcd->pool[i] = dma_pool_create(name, hcd->self.controller,
|
||||
hcd->pool[i] = dma_pool_create(name, hcd->self.sysdev,
|
||||
size, size, 0);
|
||||
if (!hcd->pool[i]) {
|
||||
hcd_buffer_destroy(hcd);
|
||||
|
|
@ -130,7 +130,7 @@ void *hcd_buffer_alloc(
|
|||
|
||||
/* some USB hosts just use PIO */
|
||||
if (!IS_ENABLED(CONFIG_HAS_DMA) ||
|
||||
(!bus->controller->dma_mask &&
|
||||
(!is_device_dma_capable(bus->sysdev) &&
|
||||
!(hcd->driver->flags & HCD_LOCAL_MEM))) {
|
||||
*dma = ~(dma_addr_t) 0;
|
||||
return kmalloc(size, mem_flags);
|
||||
|
|
@ -140,7 +140,7 @@ void *hcd_buffer_alloc(
|
|||
if (size <= pool_max[i])
|
||||
return dma_pool_alloc(hcd->pool[i], mem_flags, dma);
|
||||
}
|
||||
return dma_alloc_coherent(hcd->self.controller, size, dma, mem_flags);
|
||||
return dma_alloc_coherent(hcd->self.sysdev, size, dma, mem_flags);
|
||||
}
|
||||
|
||||
void hcd_buffer_free(
|
||||
|
|
@ -157,7 +157,7 @@ void hcd_buffer_free(
|
|||
return;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_HAS_DMA) ||
|
||||
(!bus->controller->dma_mask &&
|
||||
(!is_device_dma_capable(bus->sysdev) &&
|
||||
!(hcd->driver->flags & HCD_LOCAL_MEM))) {
|
||||
kfree(addr);
|
||||
return;
|
||||
|
|
@ -169,5 +169,5 @@ void hcd_buffer_free(
|
|||
return;
|
||||
}
|
||||
}
|
||||
dma_free_coherent(hcd->self.controller, size, addr, dma);
|
||||
dma_free_coherent(hcd->self.sysdev, size, addr, dma);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
* <mountpoint>/devices contains USB topology, device, config, class,
|
||||
* interface, & endpoint data.
|
||||
*
|
||||
* I considered using /proc/bus/usb/devices/device# for each device
|
||||
* I considered using /dev/bus/usb/device# for each device
|
||||
* as it is attached or detached, but I didn't like this for some
|
||||
* reason -- maybe it's just too deep of a directory structure.
|
||||
* I also don't like looking in multiple places to gather and view
|
||||
|
|
@ -40,7 +40,7 @@
|
|||
* Converted the whole proc stuff to real
|
||||
* read methods. Now not the whole device list needs to fit
|
||||
* into one page, only the device list for one bus.
|
||||
* Added a poll method to /proc/bus/usb/devices, to wake
|
||||
* Added a poll method to /sys/kernel/debug/usb/devices, to wake
|
||||
* up an eventual usbd
|
||||
* 2000-01-04: Thomas Sailer <sailer@ife.ee.ethz.ch>
|
||||
* Turned into its own filesystem
|
||||
|
|
|
|||
|
|
@ -1331,6 +1331,24 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
|
|||
*/
|
||||
if (udev->parent && !PMSG_IS_AUTO(msg))
|
||||
status = 0;
|
||||
|
||||
/*
|
||||
* If the device is inaccessible, don't try to resume
|
||||
* suspended interfaces and just return the error.
|
||||
*/
|
||||
if (status && status != -EBUSY) {
|
||||
int err;
|
||||
u16 devstat;
|
||||
|
||||
err = usb_get_status(udev, USB_RECIP_DEVICE, 0,
|
||||
&devstat);
|
||||
if (err) {
|
||||
dev_err(&udev->dev,
|
||||
"Failed to suspend device, error %d\n",
|
||||
status);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If the suspend failed, resume interfaces that did get suspended */
|
||||
|
|
@ -1763,6 +1781,9 @@ static int autosuspend_check(struct usb_device *udev)
|
|||
int w, i;
|
||||
struct usb_interface *intf;
|
||||
|
||||
if (udev->state == USB_STATE_NOTATTACHED)
|
||||
return -ENODEV;
|
||||
|
||||
/* Fail if autosuspend is disabled, or any interfaces are in use, or
|
||||
* any interface drivers require remote wakeup but it isn't available.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#define MAX_USB_MINORS 256
|
||||
static const struct file_operations *usb_minors[MAX_USB_MINORS];
|
||||
static DECLARE_RWSEM(minor_rwsem);
|
||||
static DEFINE_MUTEX(init_usb_class_mutex);
|
||||
|
||||
static int usb_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
|
|
@ -111,8 +112,9 @@ static void release_usb_class(struct kref *kref)
|
|||
|
||||
static void destroy_usb_class(void)
|
||||
{
|
||||
if (usb_class)
|
||||
kref_put(&usb_class->kref, release_usb_class);
|
||||
mutex_lock(&init_usb_class_mutex);
|
||||
kref_put(&usb_class->kref, release_usb_class);
|
||||
mutex_unlock(&init_usb_class_mutex);
|
||||
}
|
||||
|
||||
int usb_major_init(void)
|
||||
|
|
@ -173,7 +175,10 @@ int usb_register_dev(struct usb_interface *intf,
|
|||
if (intf->minor >= 0)
|
||||
return -EADDRINUSE;
|
||||
|
||||
mutex_lock(&init_usb_class_mutex);
|
||||
retval = init_usb_class();
|
||||
mutex_unlock(&init_usb_class_mutex);
|
||||
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
|
|
|
|||
|
|
@ -1076,6 +1076,7 @@ static void usb_deregister_bus (struct usb_bus *bus)
|
|||
static int register_root_hub(struct usb_hcd *hcd)
|
||||
{
|
||||
struct device *parent_dev = hcd->self.controller;
|
||||
struct device *sysdev = hcd->self.sysdev;
|
||||
struct usb_device *usb_dev = hcd->self.root_hub;
|
||||
const int devnum = 1;
|
||||
int retval;
|
||||
|
|
@ -1122,7 +1123,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;
|
||||
usb_dev->dev.of_node = sysdev->of_node;
|
||||
}
|
||||
mutex_unlock(&usb_bus_idr_lock);
|
||||
|
||||
|
|
@ -1435,7 +1436,7 @@ void usb_hcd_unmap_urb_setup_for_dma(struct usb_hcd *hcd, struct urb *urb)
|
|||
{
|
||||
if (IS_ENABLED(CONFIG_HAS_DMA) &&
|
||||
(urb->transfer_flags & URB_SETUP_MAP_SINGLE))
|
||||
dma_unmap_single(hcd->self.controller,
|
||||
dma_unmap_single(hcd->self.sysdev,
|
||||
urb->setup_dma,
|
||||
sizeof(struct usb_ctrlrequest),
|
||||
DMA_TO_DEVICE);
|
||||
|
|
@ -1468,19 +1469,19 @@ void usb_hcd_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
|
|||
dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
|
||||
if (IS_ENABLED(CONFIG_HAS_DMA) &&
|
||||
(urb->transfer_flags & URB_DMA_MAP_SG))
|
||||
dma_unmap_sg(hcd->self.controller,
|
||||
dma_unmap_sg(hcd->self.sysdev,
|
||||
urb->sg,
|
||||
urb->num_sgs,
|
||||
dir);
|
||||
else if (IS_ENABLED(CONFIG_HAS_DMA) &&
|
||||
(urb->transfer_flags & URB_DMA_MAP_PAGE))
|
||||
dma_unmap_page(hcd->self.controller,
|
||||
dma_unmap_page(hcd->self.sysdev,
|
||||
urb->transfer_dma,
|
||||
urb->transfer_buffer_length,
|
||||
dir);
|
||||
else if (IS_ENABLED(CONFIG_HAS_DMA) &&
|
||||
(urb->transfer_flags & URB_DMA_MAP_SINGLE))
|
||||
dma_unmap_single(hcd->self.controller,
|
||||
dma_unmap_single(hcd->self.sysdev,
|
||||
urb->transfer_dma,
|
||||
urb->transfer_buffer_length,
|
||||
dir);
|
||||
|
|
@ -1523,11 +1524,11 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
|
|||
return ret;
|
||||
if (IS_ENABLED(CONFIG_HAS_DMA) && hcd->self.uses_dma) {
|
||||
urb->setup_dma = dma_map_single(
|
||||
hcd->self.controller,
|
||||
hcd->self.sysdev,
|
||||
urb->setup_packet,
|
||||
sizeof(struct usb_ctrlrequest),
|
||||
DMA_TO_DEVICE);
|
||||
if (dma_mapping_error(hcd->self.controller,
|
||||
if (dma_mapping_error(hcd->self.sysdev,
|
||||
urb->setup_dma))
|
||||
return -EAGAIN;
|
||||
urb->transfer_flags |= URB_SETUP_MAP_SINGLE;
|
||||
|
|
@ -1558,7 +1559,7 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
|
|||
}
|
||||
|
||||
n = dma_map_sg(
|
||||
hcd->self.controller,
|
||||
hcd->self.sysdev,
|
||||
urb->sg,
|
||||
urb->num_sgs,
|
||||
dir);
|
||||
|
|
@ -1573,12 +1574,12 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
|
|||
} else if (urb->sg) {
|
||||
struct scatterlist *sg = urb->sg;
|
||||
urb->transfer_dma = dma_map_page(
|
||||
hcd->self.controller,
|
||||
hcd->self.sysdev,
|
||||
sg_page(sg),
|
||||
sg->offset,
|
||||
urb->transfer_buffer_length,
|
||||
dir);
|
||||
if (dma_mapping_error(hcd->self.controller,
|
||||
if (dma_mapping_error(hcd->self.sysdev,
|
||||
urb->transfer_dma))
|
||||
ret = -EAGAIN;
|
||||
else
|
||||
|
|
@ -1588,11 +1589,11 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
|
|||
ret = -EAGAIN;
|
||||
} else {
|
||||
urb->transfer_dma = dma_map_single(
|
||||
hcd->self.controller,
|
||||
hcd->self.sysdev,
|
||||
urb->transfer_buffer,
|
||||
urb->transfer_buffer_length,
|
||||
dir);
|
||||
if (dma_mapping_error(hcd->self.controller,
|
||||
if (dma_mapping_error(hcd->self.sysdev,
|
||||
urb->transfer_dma))
|
||||
ret = -EAGAIN;
|
||||
else
|
||||
|
|
@ -2498,24 +2499,8 @@ static void init_giveback_urb_bh(struct giveback_urb_bh *bh)
|
|||
tasklet_init(&bh->bh, usb_giveback_urb_bh, (unsigned long)bh);
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_create_shared_hcd - create and initialize an HCD structure
|
||||
* @driver: HC driver that will use this hcd
|
||||
* @dev: device for this HC, stored in hcd->self.controller
|
||||
* @bus_name: value to store in hcd->self.bus_name
|
||||
* @primary_hcd: a pointer to the usb_hcd structure that is sharing the
|
||||
* PCI device. Only allocate certain resources for the primary HCD
|
||||
* Context: !in_interrupt()
|
||||
*
|
||||
* Allocate a struct usb_hcd, with extra space at the end for the
|
||||
* HC driver's private data. Initialize the generic members of the
|
||||
* hcd structure.
|
||||
*
|
||||
* Return: On success, a pointer to the created and initialized HCD structure.
|
||||
* On failure (e.g. if memory is unavailable), %NULL.
|
||||
*/
|
||||
struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
|
||||
struct device *dev, const char *bus_name,
|
||||
struct usb_hcd *__usb_create_hcd(const struct hc_driver *driver,
|
||||
struct device *sysdev, struct device *dev, const char *bus_name,
|
||||
struct usb_hcd *primary_hcd)
|
||||
{
|
||||
struct usb_hcd *hcd;
|
||||
|
|
@ -2556,8 +2541,9 @@ struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
|
|||
|
||||
usb_bus_init(&hcd->self);
|
||||
hcd->self.controller = dev;
|
||||
hcd->self.sysdev = sysdev;
|
||||
hcd->self.bus_name = bus_name;
|
||||
hcd->self.uses_dma = (dev->dma_mask != NULL);
|
||||
hcd->self.uses_dma = (sysdev->dma_mask != NULL);
|
||||
|
||||
init_timer(&hcd->rh_timer);
|
||||
hcd->rh_timer.function = rh_timer_func;
|
||||
|
|
@ -2572,6 +2558,30 @@ struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
|
|||
"USB Host Controller";
|
||||
return hcd;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__usb_create_hcd);
|
||||
|
||||
/**
|
||||
* usb_create_shared_hcd - create and initialize an HCD structure
|
||||
* @driver: HC driver that will use this hcd
|
||||
* @dev: device for this HC, stored in hcd->self.controller
|
||||
* @bus_name: value to store in hcd->self.bus_name
|
||||
* @primary_hcd: a pointer to the usb_hcd structure that is sharing the
|
||||
* PCI device. Only allocate certain resources for the primary HCD
|
||||
* Context: !in_interrupt()
|
||||
*
|
||||
* Allocate a struct usb_hcd, with extra space at the end for the
|
||||
* HC driver's private data. Initialize the generic members of the
|
||||
* hcd structure.
|
||||
*
|
||||
* Return: On success, a pointer to the created and initialized HCD structure.
|
||||
* On failure (e.g. if memory is unavailable), %NULL.
|
||||
*/
|
||||
struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
|
||||
struct device *dev, const char *bus_name,
|
||||
struct usb_hcd *primary_hcd)
|
||||
{
|
||||
return __usb_create_hcd(driver, dev, dev, bus_name, primary_hcd);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_create_shared_hcd);
|
||||
|
||||
/**
|
||||
|
|
@ -2591,7 +2601,7 @@ EXPORT_SYMBOL_GPL(usb_create_shared_hcd);
|
|||
struct usb_hcd *usb_create_hcd(const struct hc_driver *driver,
|
||||
struct device *dev, const char *bus_name)
|
||||
{
|
||||
return usb_create_shared_hcd(driver, dev, bus_name, NULL);
|
||||
return __usb_create_hcd(driver, dev, dev, bus_name, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_create_hcd);
|
||||
|
||||
|
|
@ -2718,7 +2728,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
|
|||
struct usb_device *rhdev;
|
||||
|
||||
if (IS_ENABLED(CONFIG_USB_PHY) && !hcd->usb_phy) {
|
||||
struct usb_phy *phy = usb_get_phy_dev(hcd->self.controller, 0);
|
||||
struct usb_phy *phy = usb_get_phy_dev(hcd->self.sysdev, 0);
|
||||
|
||||
if (IS_ERR(phy)) {
|
||||
retval = PTR_ERR(phy);
|
||||
|
|
@ -2736,7 +2746,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
|
|||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_GENERIC_PHY) && !hcd->phy) {
|
||||
struct phy *phy = phy_get(hcd->self.controller, "usb");
|
||||
struct phy *phy = phy_get(hcd->self.sysdev, "usb");
|
||||
|
||||
if (IS_ERR(phy)) {
|
||||
retval = PTR_ERR(phy);
|
||||
|
|
@ -2784,7 +2794,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
|
|||
*/
|
||||
retval = hcd_buffer_create(hcd);
|
||||
if (retval != 0) {
|
||||
dev_dbg(hcd->self.controller, "pool alloc failed\n");
|
||||
dev_dbg(hcd->self.sysdev, "pool alloc failed\n");
|
||||
goto err_create_buf;
|
||||
}
|
||||
|
||||
|
|
@ -2794,7 +2804,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
|
|||
|
||||
rhdev = usb_alloc_dev(NULL, &hcd->self, 0);
|
||||
if (rhdev == NULL) {
|
||||
dev_err(hcd->self.controller, "unable to allocate root hub\n");
|
||||
dev_err(hcd->self.sysdev, "unable to allocate root hub\n");
|
||||
retval = -ENOMEM;
|
||||
goto err_allocate_root_hub;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1066,6 +1066,9 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
|
|||
|
||||
portstatus = portchange = 0;
|
||||
status = hub_port_status(hub, port1, &portstatus, &portchange);
|
||||
if (status)
|
||||
goto abort;
|
||||
|
||||
if (udev || (portstatus & USB_PORT_STAT_CONNECTION))
|
||||
dev_dbg(&port_dev->dev, "status %04x change %04x\n",
|
||||
portstatus, portchange);
|
||||
|
|
@ -1198,7 +1201,7 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
|
|||
|
||||
/* Scan all ports that need attention */
|
||||
kick_hub_wq(hub);
|
||||
|
||||
abort:
|
||||
if (type == HUB_INIT2 || type == HUB_INIT3) {
|
||||
/* Allow autosuspend if it was suppressed */
|
||||
disconnected:
|
||||
|
|
@ -2084,6 +2087,12 @@ void usb_disconnect(struct usb_device **pdev)
|
|||
dev_info(&udev->dev, "USB disconnect, device number %d\n",
|
||||
udev->devnum);
|
||||
|
||||
/*
|
||||
* Ensure that the pm runtime code knows that the USB device
|
||||
* is in the process of being disconnected.
|
||||
*/
|
||||
pm_runtime_barrier(&udev->dev);
|
||||
|
||||
usb_lock_device(udev);
|
||||
|
||||
hub_disconnect_children(udev);
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/usb/of.h>
|
||||
|
||||
/**
|
||||
|
|
@ -46,3 +47,25 @@ struct device_node *usb_of_get_child_node(struct device_node *parent,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(usb_of_get_child_node);
|
||||
|
||||
/**
|
||||
* usb_of_get_companion_dev - Find the companion device
|
||||
* @dev: the device pointer to find a companion
|
||||
*
|
||||
* Find the companion device from platform bus.
|
||||
*
|
||||
* Return: On success, a pointer to the companion device, %NULL on failure.
|
||||
*/
|
||||
struct device *usb_of_get_companion_dev(struct device *dev)
|
||||
{
|
||||
struct device_node *node;
|
||||
struct platform_device *pdev = NULL;
|
||||
|
||||
node = of_parse_phandle(dev->of_node, "companion", 0);
|
||||
if (node)
|
||||
pdev = of_find_device_by_node(node);
|
||||
|
||||
of_node_put(node);
|
||||
|
||||
return pdev ? &pdev->dev : NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_of_get_companion_dev);
|
||||
|
|
|
|||
|
|
@ -74,6 +74,140 @@ MODULE_PARM_DESC(autosuspend, "default autosuspend delay");
|
|||
#define usb_autosuspend_delay 0
|
||||
#endif
|
||||
|
||||
static bool match_endpoint(struct usb_endpoint_descriptor *epd,
|
||||
struct usb_endpoint_descriptor **bulk_in,
|
||||
struct usb_endpoint_descriptor **bulk_out,
|
||||
struct usb_endpoint_descriptor **int_in,
|
||||
struct usb_endpoint_descriptor **int_out)
|
||||
{
|
||||
switch (usb_endpoint_type(epd)) {
|
||||
case USB_ENDPOINT_XFER_BULK:
|
||||
if (usb_endpoint_dir_in(epd)) {
|
||||
if (bulk_in && !*bulk_in) {
|
||||
*bulk_in = epd;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (bulk_out && !*bulk_out) {
|
||||
*bulk_out = epd;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
case USB_ENDPOINT_XFER_INT:
|
||||
if (usb_endpoint_dir_in(epd)) {
|
||||
if (int_in && !*int_in) {
|
||||
*int_in = epd;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (int_out && !*int_out) {
|
||||
*int_out = epd;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return (!bulk_in || *bulk_in) && (!bulk_out || *bulk_out) &&
|
||||
(!int_in || *int_in) && (!int_out || *int_out);
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_find_common_endpoints() -- look up common endpoint descriptors
|
||||
* @alt: alternate setting to search
|
||||
* @bulk_in: pointer to descriptor pointer, or NULL
|
||||
* @bulk_out: pointer to descriptor pointer, or NULL
|
||||
* @int_in: pointer to descriptor pointer, or NULL
|
||||
* @int_out: pointer to descriptor pointer, or NULL
|
||||
*
|
||||
* Search the alternate setting's endpoint descriptors for the first bulk-in,
|
||||
* bulk-out, interrupt-in and interrupt-out endpoints and return them in the
|
||||
* provided pointers (unless they are NULL).
|
||||
*
|
||||
* If a requested endpoint is not found, the corresponding pointer is set to
|
||||
* NULL.
|
||||
*
|
||||
* Return: Zero if all requested descriptors were found, or -ENXIO otherwise.
|
||||
*/
|
||||
int usb_find_common_endpoints(struct usb_host_interface *alt,
|
||||
struct usb_endpoint_descriptor **bulk_in,
|
||||
struct usb_endpoint_descriptor **bulk_out,
|
||||
struct usb_endpoint_descriptor **int_in,
|
||||
struct usb_endpoint_descriptor **int_out)
|
||||
{
|
||||
struct usb_endpoint_descriptor *epd;
|
||||
int i;
|
||||
|
||||
if (bulk_in)
|
||||
*bulk_in = NULL;
|
||||
if (bulk_out)
|
||||
*bulk_out = NULL;
|
||||
if (int_in)
|
||||
*int_in = NULL;
|
||||
if (int_out)
|
||||
*int_out = NULL;
|
||||
|
||||
for (i = 0; i < alt->desc.bNumEndpoints; ++i) {
|
||||
epd = &alt->endpoint[i].desc;
|
||||
|
||||
if (match_endpoint(epd, bulk_in, bulk_out, int_in, int_out))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENXIO;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_find_common_endpoints);
|
||||
|
||||
/**
|
||||
* usb_find_common_endpoints_reverse() -- look up common endpoint descriptors
|
||||
* @alt: alternate setting to search
|
||||
* @bulk_in: pointer to descriptor pointer, or NULL
|
||||
* @bulk_out: pointer to descriptor pointer, or NULL
|
||||
* @int_in: pointer to descriptor pointer, or NULL
|
||||
* @int_out: pointer to descriptor pointer, or NULL
|
||||
*
|
||||
* Search the alternate setting's endpoint descriptors for the last bulk-in,
|
||||
* bulk-out, interrupt-in and interrupt-out endpoints and return them in the
|
||||
* provided pointers (unless they are NULL).
|
||||
*
|
||||
* If a requested endpoint is not found, the corresponding pointer is set to
|
||||
* NULL.
|
||||
*
|
||||
* Return: Zero if all requested descriptors were found, or -ENXIO otherwise.
|
||||
*/
|
||||
int usb_find_common_endpoints_reverse(struct usb_host_interface *alt,
|
||||
struct usb_endpoint_descriptor **bulk_in,
|
||||
struct usb_endpoint_descriptor **bulk_out,
|
||||
struct usb_endpoint_descriptor **int_in,
|
||||
struct usb_endpoint_descriptor **int_out)
|
||||
{
|
||||
struct usb_endpoint_descriptor *epd;
|
||||
int i;
|
||||
|
||||
if (bulk_in)
|
||||
*bulk_in = NULL;
|
||||
if (bulk_out)
|
||||
*bulk_out = NULL;
|
||||
if (int_in)
|
||||
*int_in = NULL;
|
||||
if (int_out)
|
||||
*int_out = NULL;
|
||||
|
||||
for (i = alt->desc.bNumEndpoints - 1; i >= 0; --i) {
|
||||
epd = &alt->endpoint[i].desc;
|
||||
|
||||
if (match_endpoint(epd, bulk_in, bulk_out, int_in, int_out))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENXIO;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_find_common_endpoints_reverse);
|
||||
|
||||
/**
|
||||
* usb_find_alt_setting() - Given a configuration, find the alternate setting
|
||||
|
|
@ -453,9 +587,9 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
|
|||
* Note: calling dma_set_mask() on a USB device would set the
|
||||
* mask for the entire HCD, so don't do that.
|
||||
*/
|
||||
dev->dev.dma_mask = bus->controller->dma_mask;
|
||||
dev->dev.dma_pfn_offset = bus->controller->dma_pfn_offset;
|
||||
set_dev_node(&dev->dev, dev_to_node(bus->controller));
|
||||
dev->dev.dma_mask = bus->sysdev->dma_mask;
|
||||
dev->dev.dma_pfn_offset = bus->sysdev->dma_pfn_offset;
|
||||
set_dev_node(&dev->dev, dev_to_node(bus->sysdev));
|
||||
dev->state = USB_STATE_ATTACHED;
|
||||
dev->lpm_disable_count = 1;
|
||||
atomic_set(&dev->urbnum, 0);
|
||||
|
|
@ -803,7 +937,7 @@ struct urb *usb_buffer_map(struct urb *urb)
|
|||
if (!urb
|
||||
|| !urb->dev
|
||||
|| !(bus = urb->dev->bus)
|
||||
|| !(controller = bus->controller))
|
||||
|| !(controller = bus->sysdev))
|
||||
return NULL;
|
||||
|
||||
if (controller->dma_mask) {
|
||||
|
|
@ -841,7 +975,7 @@ void usb_buffer_dmasync(struct urb *urb)
|
|||
|| !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
|
||||
|| !urb->dev
|
||||
|| !(bus = urb->dev->bus)
|
||||
|| !(controller = bus->controller))
|
||||
|| !(controller = bus->sysdev))
|
||||
return;
|
||||
|
||||
if (controller->dma_mask) {
|
||||
|
|
@ -875,7 +1009,7 @@ void usb_buffer_unmap(struct urb *urb)
|
|||
|| !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
|
||||
|| !urb->dev
|
||||
|| !(bus = urb->dev->bus)
|
||||
|| !(controller = bus->controller))
|
||||
|| !(controller = bus->sysdev))
|
||||
return;
|
||||
|
||||
if (controller->dma_mask) {
|
||||
|
|
@ -925,7 +1059,7 @@ int usb_buffer_map_sg(const struct usb_device *dev, int is_in,
|
|||
|
||||
if (!dev
|
||||
|| !(bus = dev->bus)
|
||||
|| !(controller = bus->controller)
|
||||
|| !(controller = bus->sysdev)
|
||||
|| !controller->dma_mask)
|
||||
return -EINVAL;
|
||||
|
||||
|
|
@ -961,7 +1095,7 @@ void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in,
|
|||
|
||||
if (!dev
|
||||
|| !(bus = dev->bus)
|
||||
|| !(controller = bus->controller)
|
||||
|| !(controller = bus->sysdev)
|
||||
|| !controller->dma_mask)
|
||||
return;
|
||||
|
||||
|
|
@ -989,7 +1123,7 @@ void usb_buffer_unmap_sg(const struct usb_device *dev, int is_in,
|
|||
|
||||
if (!dev
|
||||
|| !(bus = dev->bus)
|
||||
|| !(controller = bus->controller)
|
||||
|| !(controller = bus->sysdev)
|
||||
|| !controller->dma_mask)
|
||||
return;
|
||||
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ endchoice
|
|||
|
||||
config USB_DWC2_PCI
|
||||
tristate "DWC2 PCI"
|
||||
depends on PCI
|
||||
depends on USB_PCI
|
||||
depends on USB_GADGET || !USB_GADGET
|
||||
default n
|
||||
select NOP_USB_XCEIV
|
||||
|
|
|
|||
|
|
@ -423,6 +423,10 @@ enum dwc2_ep0_state {
|
|||
* needed.
|
||||
* 0 - No (default)
|
||||
* 1 - Yes
|
||||
* @activate_stm_fs_transceiver: Activate internal transceiver using GGPIO
|
||||
* register.
|
||||
* 0 - Deactivate the transceiver (default)
|
||||
* 1 - Activate the transceiver
|
||||
* @g_dma: Enables gadget dma usage (default: autodetect).
|
||||
* @g_dma_desc: Enables gadget descriptor DMA (default: autodetect).
|
||||
* @g_rx_fifo_size: The periodic rx fifo size for the device, in
|
||||
|
|
@ -477,6 +481,7 @@ struct dwc2_core_params {
|
|||
bool uframe_sched;
|
||||
bool external_id_pin_ctl;
|
||||
bool hibernation;
|
||||
bool activate_stm_fs_transceiver;
|
||||
u16 max_packet_count;
|
||||
u32 max_transfer_size;
|
||||
u32 ahbcfg;
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ static void dwc2_init_fs_ls_pclk_sel(struct dwc2_hsotg *hsotg)
|
|||
|
||||
static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
|
||||
{
|
||||
u32 usbcfg, i2cctl;
|
||||
u32 usbcfg, ggpio, i2cctl;
|
||||
int retval = 0;
|
||||
|
||||
/*
|
||||
|
|
@ -145,6 +145,19 @@ static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
|
|||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
if (hsotg->params.activate_stm_fs_transceiver) {
|
||||
ggpio = dwc2_readl(hsotg->regs + GGPIO);
|
||||
if (!(ggpio & GGPIO_STM32_OTG_GCCFG_PWRDWN)) {
|
||||
dev_dbg(hsotg->dev, "Activating transceiver\n");
|
||||
/*
|
||||
* STM32F4x9 uses the GGPIO register as general
|
||||
* core configuration register.
|
||||
*/
|
||||
ggpio |= GGPIO_STM32_OTG_GCCFG_PWRDWN;
|
||||
dwc2_writel(ggpio, hsotg->regs + GGPIO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -3264,6 +3277,7 @@ static void dwc2_conn_id_status_change(struct work_struct *work)
|
|||
dwc2_core_init(hsotg, false);
|
||||
dwc2_enable_global_interrupts(hsotg);
|
||||
spin_lock_irqsave(&hsotg->lock, flags);
|
||||
dwc2_hsotg_disconnect(hsotg);
|
||||
dwc2_hsotg_core_init_disconnected(hsotg, false);
|
||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||
dwc2_hsotg_core_connect(hsotg);
|
||||
|
|
|
|||
|
|
@ -225,6 +225,8 @@
|
|||
|
||||
#define GPVNDCTL HSOTG_REG(0x0034)
|
||||
#define GGPIO HSOTG_REG(0x0038)
|
||||
#define GGPIO_STM32_OTG_GCCFG_PWRDWN BIT(16)
|
||||
|
||||
#define GUID HSOTG_REG(0x003c)
|
||||
#define GSNPSID HSOTG_REG(0x0040)
|
||||
#define GHWCFG1 HSOTG_REG(0x0044)
|
||||
|
|
|
|||
|
|
@ -120,6 +120,22 @@ static void dwc2_set_amcc_params(struct dwc2_hsotg *hsotg)
|
|||
p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << GAHBCFG_HBSTLEN_SHIFT;
|
||||
}
|
||||
|
||||
static void dwc2_set_stm32f4x9_fsotg_params(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
struct dwc2_core_params *p = &hsotg->params;
|
||||
|
||||
p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE;
|
||||
p->speed = DWC2_SPEED_PARAM_FULL;
|
||||
p->host_rx_fifo_size = 128;
|
||||
p->host_nperio_tx_fifo_size = 96;
|
||||
p->host_perio_tx_fifo_size = 96;
|
||||
p->max_packet_count = 256;
|
||||
p->phy_type = DWC2_PHY_TYPE_PARAM_FS;
|
||||
p->i2c_enable = false;
|
||||
p->uframe_sched = false;
|
||||
p->activate_stm_fs_transceiver = true;
|
||||
}
|
||||
|
||||
const struct of_device_id dwc2_of_match_table[] = {
|
||||
{ .compatible = "brcm,bcm2835-usb", .data = dwc2_set_bcm_params },
|
||||
{ .compatible = "hisilicon,hi6220-usb", .data = dwc2_set_his_params },
|
||||
|
|
@ -133,6 +149,9 @@ const struct of_device_id dwc2_of_match_table[] = {
|
|||
{ .compatible = "amlogic,meson-gxbb-usb",
|
||||
.data = dwc2_set_amlogic_params },
|
||||
{ .compatible = "amcc,dwc-otg", .data = dwc2_set_amcc_params },
|
||||
{ .compatible = "st,stm32f4x9-fsotg",
|
||||
.data = dwc2_set_stm32f4x9_fsotg_params },
|
||||
{ .compatible = "st,stm32f4x9-hsotg" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, dwc2_of_match_table);
|
||||
|
|
|
|||
|
|
@ -214,20 +214,11 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg)
|
|||
hsotg->reset = devm_reset_control_get_optional(hsotg->dev, "dwc2");
|
||||
if (IS_ERR(hsotg->reset)) {
|
||||
ret = PTR_ERR(hsotg->reset);
|
||||
switch (ret) {
|
||||
case -ENOENT:
|
||||
case -ENOTSUPP:
|
||||
hsotg->reset = NULL;
|
||||
break;
|
||||
default:
|
||||
dev_err(hsotg->dev, "error getting reset control %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
dev_err(hsotg->dev, "error getting reset control %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (hsotg->reset)
|
||||
reset_control_deassert(hsotg->reset);
|
||||
reset_control_deassert(hsotg->reset);
|
||||
|
||||
/* Set default UTMI width */
|
||||
hsotg->phyif = GUSBCFG_PHYIF16;
|
||||
|
|
@ -326,8 +317,7 @@ static int dwc2_driver_remove(struct platform_device *dev)
|
|||
if (hsotg->ll_hw_enabled)
|
||||
dwc2_lowlevel_hw_disable(hsotg);
|
||||
|
||||
if (hsotg->reset)
|
||||
reset_control_assert(hsotg->reset);
|
||||
reset_control_assert(hsotg->reset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ config USB_DWC3_GADGET
|
|||
config USB_DWC3_DUAL_ROLE
|
||||
bool "Dual Role mode"
|
||||
depends on ((USB=y || USB=USB_DWC3) && (USB_GADGET=y || USB_GADGET=USB_DWC3))
|
||||
depends on (EXTCON=y || EXTCON=USB_DWC3)
|
||||
help
|
||||
This is the default mode of working of DWC3 controller where
|
||||
both host and gadget features are enabled.
|
||||
|
|
@ -70,7 +71,7 @@ config USB_DWC3_EXYNOS
|
|||
|
||||
config USB_DWC3_PCI
|
||||
tristate "PCIe-based Platforms"
|
||||
depends on PCI && ACPI
|
||||
depends on USB_PCI && ACPI
|
||||
default USB_DWC3
|
||||
help
|
||||
If you're using the DesignWare Core IP with a PCIe, please say
|
||||
|
|
|
|||
|
|
@ -17,6 +17,10 @@ ifneq ($(filter y,$(CONFIG_USB_DWC3_GADGET) $(CONFIG_USB_DWC3_DUAL_ROLE)),)
|
|||
dwc3-y += gadget.o ep0.o
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_USB_DWC3_DUAL_ROLE),)
|
||||
dwc3-y += drd.o
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_USB_DWC3_ULPI),)
|
||||
dwc3-y += ulpi.o
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -100,7 +100,10 @@ static int dwc3_get_dr_mode(struct dwc3 *dwc)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
|
||||
static void dwc3_event_buffers_cleanup(struct dwc3 *dwc);
|
||||
static int dwc3_event_buffers_setup(struct dwc3 *dwc);
|
||||
|
||||
static void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
|
|
@ -110,6 +113,69 @@ void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
|
|||
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
|
||||
}
|
||||
|
||||
static void __dwc3_set_mode(struct work_struct *work)
|
||||
{
|
||||
struct dwc3 *dwc = work_to_dwc(work);
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
if (!dwc->desired_dr_role)
|
||||
return;
|
||||
|
||||
if (dwc->desired_dr_role == dwc->current_dr_role)
|
||||
return;
|
||||
|
||||
if (dwc->dr_mode != USB_DR_MODE_OTG)
|
||||
return;
|
||||
|
||||
switch (dwc->current_dr_role) {
|
||||
case DWC3_GCTL_PRTCAP_HOST:
|
||||
dwc3_host_exit(dwc);
|
||||
break;
|
||||
case DWC3_GCTL_PRTCAP_DEVICE:
|
||||
dwc3_gadget_exit(dwc);
|
||||
dwc3_event_buffers_cleanup(dwc);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
|
||||
dwc3_set_prtcap(dwc, dwc->desired_dr_role);
|
||||
|
||||
dwc->current_dr_role = dwc->desired_dr_role;
|
||||
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
switch (dwc->desired_dr_role) {
|
||||
case DWC3_GCTL_PRTCAP_HOST:
|
||||
ret = dwc3_host_init(dwc);
|
||||
if (ret)
|
||||
dev_err(dwc->dev, "failed to initialize host\n");
|
||||
break;
|
||||
case DWC3_GCTL_PRTCAP_DEVICE:
|
||||
dwc3_event_buffers_setup(dwc);
|
||||
ret = dwc3_gadget_init(dwc);
|
||||
if (ret)
|
||||
dev_err(dwc->dev, "failed to initialize peripheral\n");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
dwc->desired_dr_role = mode;
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
queue_work(system_power_efficient_wq, &dwc->drd_work);
|
||||
}
|
||||
|
||||
u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type)
|
||||
{
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
|
|
@ -397,8 +463,7 @@ static void dwc3_core_num_eps(struct dwc3 *dwc)
|
|||
{
|
||||
struct dwc3_hwparams *parms = &dwc->hwparams;
|
||||
|
||||
dwc->num_in_eps = DWC3_NUM_IN_EPS(parms);
|
||||
dwc->num_out_eps = DWC3_NUM_EPS(parms) - dwc->num_in_eps;
|
||||
dwc->num_eps = DWC3_NUM_EPS(parms);
|
||||
}
|
||||
|
||||
static void dwc3_cache_hwparams(struct dwc3 *dwc)
|
||||
|
|
@ -431,6 +496,12 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
|
|||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
|
||||
|
||||
/*
|
||||
* Make sure UX_EXIT_PX is cleared as that causes issues with some
|
||||
* PHYs. Also, this bit is not supposed to be used in normal operation.
|
||||
*/
|
||||
reg &= ~DWC3_GUSB3PIPECTL_UX_EXIT_PX;
|
||||
|
||||
/*
|
||||
* Above 1.94a, it is recommended to set DWC3_GUSB3PIPECTL_SUSPHY
|
||||
* to '0' during coreConsultant configuration. So default value
|
||||
|
|
@ -714,21 +785,6 @@ static int dwc3_core_init(struct dwc3 *dwc)
|
|||
goto err4;
|
||||
}
|
||||
|
||||
switch (dwc->dr_mode) {
|
||||
case USB_DR_MODE_PERIPHERAL:
|
||||
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
|
||||
break;
|
||||
case USB_DR_MODE_HOST:
|
||||
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
|
||||
break;
|
||||
case USB_DR_MODE_OTG:
|
||||
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
|
||||
break;
|
||||
default:
|
||||
dev_warn(dwc->dev, "Unsupported mode %d\n", dwc->dr_mode);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* ENDXFER polling is available on version 3.10a and later of
|
||||
* the DWC_usb3 controller. It is NOT available in the
|
||||
|
|
@ -846,6 +902,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
|
|||
|
||||
switch (dwc->dr_mode) {
|
||||
case USB_DR_MODE_PERIPHERAL:
|
||||
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
|
||||
ret = dwc3_gadget_init(dwc);
|
||||
if (ret) {
|
||||
if (ret != -EPROBE_DEFER)
|
||||
|
|
@ -854,6 +911,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
|
|||
}
|
||||
break;
|
||||
case USB_DR_MODE_HOST:
|
||||
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
|
||||
ret = dwc3_host_init(dwc);
|
||||
if (ret) {
|
||||
if (ret != -EPROBE_DEFER)
|
||||
|
|
@ -862,17 +920,11 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
|
|||
}
|
||||
break;
|
||||
case USB_DR_MODE_OTG:
|
||||
ret = dwc3_host_init(dwc);
|
||||
INIT_WORK(&dwc->drd_work, __dwc3_set_mode);
|
||||
ret = dwc3_drd_init(dwc);
|
||||
if (ret) {
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "failed to initialize host\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = dwc3_gadget_init(dwc);
|
||||
if (ret) {
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "failed to initialize gadget\n");
|
||||
dev_err(dev, "failed to initialize dual-role\n");
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
|
|
@ -894,8 +946,7 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc)
|
|||
dwc3_host_exit(dwc);
|
||||
break;
|
||||
case USB_DR_MODE_OTG:
|
||||
dwc3_host_exit(dwc);
|
||||
dwc3_gadget_exit(dwc);
|
||||
dwc3_drd_exit(dwc);
|
||||
break;
|
||||
default:
|
||||
/* do nothing */
|
||||
|
|
|
|||
|
|
@ -23,10 +23,12 @@
|
|||
#include <linux/spinlock.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
|
|
@ -39,9 +41,8 @@
|
|||
|
||||
/* Global constants */
|
||||
#define DWC3_PULL_UP_TIMEOUT 500 /* ms */
|
||||
#define DWC3_ZLP_BUF_SIZE 1024 /* size of a superspeed bulk */
|
||||
#define DWC3_BOUNCE_SIZE 1024 /* size of a superspeed bulk */
|
||||
#define DWC3_EP0_BOUNCE_SIZE 512
|
||||
#define DWC3_EP0_SETUP_SIZE 512
|
||||
#define DWC3_ENDPOINTS_NUM 32
|
||||
#define DWC3_XHCI_RESOURCES_NUM 2
|
||||
|
||||
|
|
@ -66,7 +67,7 @@
|
|||
#define DWC3_DEVICE_EVENT_OVERFLOW 11
|
||||
|
||||
#define DWC3_GEVNTCOUNT_MASK 0xfffc
|
||||
#define DWC3_GEVNTCOUNT_EHB (1 << 31)
|
||||
#define DWC3_GEVNTCOUNT_EHB BIT(31)
|
||||
#define DWC3_GSNPSID_MASK 0xffff0000
|
||||
#define DWC3_GSNPSREV_MASK 0xffff
|
||||
|
||||
|
|
@ -116,20 +117,20 @@
|
|||
#define DWC3_VER_NUMBER 0xc1a0
|
||||
#define DWC3_VER_TYPE 0xc1a4
|
||||
|
||||
#define DWC3_GUSB2PHYCFG(n) (0xc200 + (n * 0x04))
|
||||
#define DWC3_GUSB2I2CCTL(n) (0xc240 + (n * 0x04))
|
||||
#define DWC3_GUSB2PHYCFG(n) (0xc200 + ((n) * 0x04))
|
||||
#define DWC3_GUSB2I2CCTL(n) (0xc240 + ((n) * 0x04))
|
||||
|
||||
#define DWC3_GUSB2PHYACC(n) (0xc280 + (n * 0x04))
|
||||
#define DWC3_GUSB2PHYACC(n) (0xc280 + ((n) * 0x04))
|
||||
|
||||
#define DWC3_GUSB3PIPECTL(n) (0xc2c0 + (n * 0x04))
|
||||
#define DWC3_GUSB3PIPECTL(n) (0xc2c0 + ((n) * 0x04))
|
||||
|
||||
#define DWC3_GTXFIFOSIZ(n) (0xc300 + (n * 0x04))
|
||||
#define DWC3_GRXFIFOSIZ(n) (0xc380 + (n * 0x04))
|
||||
#define DWC3_GTXFIFOSIZ(n) (0xc300 + ((n) * 0x04))
|
||||
#define DWC3_GRXFIFOSIZ(n) (0xc380 + ((n) * 0x04))
|
||||
|
||||
#define DWC3_GEVNTADRLO(n) (0xc400 + (n * 0x10))
|
||||
#define DWC3_GEVNTADRHI(n) (0xc404 + (n * 0x10))
|
||||
#define DWC3_GEVNTSIZ(n) (0xc408 + (n * 0x10))
|
||||
#define DWC3_GEVNTCOUNT(n) (0xc40c + (n * 0x10))
|
||||
#define DWC3_GEVNTADRLO(n) (0xc400 + ((n) * 0x10))
|
||||
#define DWC3_GEVNTADRHI(n) (0xc404 + ((n) * 0x10))
|
||||
#define DWC3_GEVNTSIZ(n) (0xc408 + ((n) * 0x10))
|
||||
#define DWC3_GEVNTCOUNT(n) (0xc40c + ((n) * 0x10))
|
||||
|
||||
#define DWC3_GHWPARAMS8 0xc600
|
||||
#define DWC3_GFLADJ 0xc630
|
||||
|
|
@ -143,13 +144,13 @@
|
|||
#define DWC3_DGCMD 0xc714
|
||||
#define DWC3_DALEPENA 0xc720
|
||||
|
||||
#define DWC3_DEP_BASE(n) (0xc800 + (n * 0x10))
|
||||
#define DWC3_DEP_BASE(n) (0xc800 + ((n) * 0x10))
|
||||
#define DWC3_DEPCMDPAR2 0x00
|
||||
#define DWC3_DEPCMDPAR1 0x04
|
||||
#define DWC3_DEPCMDPAR0 0x08
|
||||
#define DWC3_DEPCMD 0x0c
|
||||
|
||||
#define DWC3_DEV_IMOD(n) (0xca00 + (n * 0x4))
|
||||
#define DWC3_DEV_IMOD(n) (0xca00 + ((n) * 0x4))
|
||||
|
||||
/* OTG Registers */
|
||||
#define DWC3_OCFG 0xcc00
|
||||
|
|
@ -176,11 +177,11 @@
|
|||
/* 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)
|
||||
#define DWC3_GRXTHRCFG_PKTCNTSEL BIT(29)
|
||||
|
||||
/* Global Configuration Register */
|
||||
#define DWC3_GCTL_PWRDNSCALE(n) ((n) << 19)
|
||||
#define DWC3_GCTL_U2RSTECN (1 << 16)
|
||||
#define DWC3_GCTL_U2RSTECN BIT(16)
|
||||
#define DWC3_GCTL_RAMCLKSEL(x) (((x) & DWC3_GCTL_CLK_MASK) << 6)
|
||||
#define DWC3_GCTL_CLK_BUS (0)
|
||||
#define DWC3_GCTL_CLK_PIPE (1)
|
||||
|
|
@ -193,24 +194,24 @@
|
|||
#define DWC3_GCTL_PRTCAP_DEVICE 2
|
||||
#define DWC3_GCTL_PRTCAP_OTG 3
|
||||
|
||||
#define DWC3_GCTL_CORESOFTRESET (1 << 11)
|
||||
#define DWC3_GCTL_SOFITPSYNC (1 << 10)
|
||||
#define DWC3_GCTL_CORESOFTRESET BIT(11)
|
||||
#define DWC3_GCTL_SOFITPSYNC BIT(10)
|
||||
#define DWC3_GCTL_SCALEDOWN(n) ((n) << 4)
|
||||
#define DWC3_GCTL_SCALEDOWN_MASK DWC3_GCTL_SCALEDOWN(3)
|
||||
#define DWC3_GCTL_DISSCRAMBLE (1 << 3)
|
||||
#define DWC3_GCTL_U2EXIT_LFPS (1 << 2)
|
||||
#define DWC3_GCTL_GBLHIBERNATIONEN (1 << 1)
|
||||
#define DWC3_GCTL_DSBLCLKGTNG (1 << 0)
|
||||
#define DWC3_GCTL_DISSCRAMBLE BIT(3)
|
||||
#define DWC3_GCTL_U2EXIT_LFPS BIT(2)
|
||||
#define DWC3_GCTL_GBLHIBERNATIONEN BIT(1)
|
||||
#define DWC3_GCTL_DSBLCLKGTNG BIT(0)
|
||||
|
||||
/* Global User Control 1 Register */
|
||||
#define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW (1 << 24)
|
||||
#define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW BIT(24)
|
||||
|
||||
/* Global USB2 PHY Configuration Register */
|
||||
#define DWC3_GUSB2PHYCFG_PHYSOFTRST (1 << 31)
|
||||
#define DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS (1 << 30)
|
||||
#define DWC3_GUSB2PHYCFG_SUSPHY (1 << 6)
|
||||
#define DWC3_GUSB2PHYCFG_ULPI_UTMI (1 << 4)
|
||||
#define DWC3_GUSB2PHYCFG_ENBLSLPM (1 << 8)
|
||||
#define DWC3_GUSB2PHYCFG_PHYSOFTRST BIT(31)
|
||||
#define DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS BIT(30)
|
||||
#define DWC3_GUSB2PHYCFG_SUSPHY BIT(6)
|
||||
#define DWC3_GUSB2PHYCFG_ULPI_UTMI BIT(4)
|
||||
#define DWC3_GUSB2PHYCFG_ENBLSLPM BIT(8)
|
||||
#define DWC3_GUSB2PHYCFG_PHYIF(n) (n << 3)
|
||||
#define DWC3_GUSB2PHYCFG_PHYIF_MASK DWC3_GUSB2PHYCFG_PHYIF(1)
|
||||
#define DWC3_GUSB2PHYCFG_USBTRDTIM(n) (n << 10)
|
||||
|
|
@ -221,25 +222,26 @@
|
|||
#define UTMI_PHYIF_8_BIT 0
|
||||
|
||||
/* Global USB2 PHY Vendor Control Register */
|
||||
#define DWC3_GUSB2PHYACC_NEWREGREQ (1 << 25)
|
||||
#define DWC3_GUSB2PHYACC_BUSY (1 << 23)
|
||||
#define DWC3_GUSB2PHYACC_WRITE (1 << 22)
|
||||
#define DWC3_GUSB2PHYACC_NEWREGREQ BIT(25)
|
||||
#define DWC3_GUSB2PHYACC_BUSY BIT(23)
|
||||
#define DWC3_GUSB2PHYACC_WRITE BIT(22)
|
||||
#define DWC3_GUSB2PHYACC_ADDR(n) (n << 16)
|
||||
#define DWC3_GUSB2PHYACC_EXTEND_ADDR(n) (n << 8)
|
||||
#define DWC3_GUSB2PHYACC_DATA(n) (n & 0xff)
|
||||
|
||||
/* 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_PHYSOFTRST BIT(31)
|
||||
#define DWC3_GUSB3PIPECTL_U2SSINP3OK BIT(29)
|
||||
#define DWC3_GUSB3PIPECTL_DISRXDETINP3 BIT(28)
|
||||
#define DWC3_GUSB3PIPECTL_UX_EXIT_PX BIT(27)
|
||||
#define DWC3_GUSB3PIPECTL_REQP1P2P3 BIT(24)
|
||||
#define DWC3_GUSB3PIPECTL_DEP1P2P3(n) ((n) << 19)
|
||||
#define DWC3_GUSB3PIPECTL_DEP1P2P3_MASK DWC3_GUSB3PIPECTL_DEP1P2P3(7)
|
||||
#define DWC3_GUSB3PIPECTL_DEP1P2P3_EN DWC3_GUSB3PIPECTL_DEP1P2P3(1)
|
||||
#define DWC3_GUSB3PIPECTL_DEPOCHANGE (1 << 18)
|
||||
#define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17)
|
||||
#define DWC3_GUSB3PIPECTL_LFPSFILT (1 << 9)
|
||||
#define DWC3_GUSB3PIPECTL_RX_DETOPOLL (1 << 8)
|
||||
#define DWC3_GUSB3PIPECTL_DEPOCHANGE BIT(18)
|
||||
#define DWC3_GUSB3PIPECTL_SUSPHY BIT(17)
|
||||
#define DWC3_GUSB3PIPECTL_LFPSFILT BIT(9)
|
||||
#define DWC3_GUSB3PIPECTL_RX_DETOPOLL BIT(8)
|
||||
#define DWC3_GUSB3PIPECTL_TX_DEEPH_MASK DWC3_GUSB3PIPECTL_TX_DEEPH(3)
|
||||
#define DWC3_GUSB3PIPECTL_TX_DEEPH(n) ((n) << 1)
|
||||
|
||||
|
|
@ -248,7 +250,7 @@
|
|||
#define DWC3_GTXFIFOSIZ_TXFSTADDR(n) ((n) & 0xffff0000)
|
||||
|
||||
/* Global Event Size Registers */
|
||||
#define DWC3_GEVNTSIZ_INTMASK (1 << 31)
|
||||
#define DWC3_GEVNTSIZ_INTMASK BIT(31)
|
||||
#define DWC3_GEVNTSIZ_SIZE(n) ((n) & 0xffff)
|
||||
|
||||
/* Global HWPARAMS0 Register */
|
||||
|
|
@ -289,18 +291,18 @@
|
|||
#define DWC3_MAX_HIBER_SCRATCHBUFS 15
|
||||
|
||||
/* Global HWPARAMS6 Register */
|
||||
#define DWC3_GHWPARAMS6_EN_FPGA (1 << 7)
|
||||
#define DWC3_GHWPARAMS6_EN_FPGA BIT(7)
|
||||
|
||||
/* Global HWPARAMS7 Register */
|
||||
#define DWC3_GHWPARAMS7_RAM1_DEPTH(n) ((n) & 0xffff)
|
||||
#define DWC3_GHWPARAMS7_RAM2_DEPTH(n) (((n) >> 16) & 0xffff)
|
||||
|
||||
/* Global Frame Length Adjustment Register */
|
||||
#define DWC3_GFLADJ_30MHZ_SDBND_SEL (1 << 7)
|
||||
#define DWC3_GFLADJ_30MHZ_SDBND_SEL BIT(7)
|
||||
#define DWC3_GFLADJ_30MHZ_MASK 0x3f
|
||||
|
||||
/* Global User Control Register 2 */
|
||||
#define DWC3_GUCTL2_RST_ACTBITLATER (1 << 14)
|
||||
#define DWC3_GUCTL2_RST_ACTBITLATER BIT(14)
|
||||
|
||||
/* Device Configuration Register */
|
||||
#define DWC3_DCFG_DEVADDR(addr) ((addr) << 3)
|
||||
|
|
@ -310,23 +312,23 @@
|
|||
#define DWC3_DCFG_SUPERSPEED_PLUS (5 << 0) /* DWC_usb31 only */
|
||||
#define DWC3_DCFG_SUPERSPEED (4 << 0)
|
||||
#define DWC3_DCFG_HIGHSPEED (0 << 0)
|
||||
#define DWC3_DCFG_FULLSPEED (1 << 0)
|
||||
#define DWC3_DCFG_FULLSPEED BIT(0)
|
||||
#define DWC3_DCFG_LOWSPEED (2 << 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)
|
||||
#define DWC3_DCFG_LPM_CAP BIT(22)
|
||||
|
||||
/* Device Control Register */
|
||||
#define DWC3_DCTL_RUN_STOP (1 << 31)
|
||||
#define DWC3_DCTL_CSFTRST (1 << 30)
|
||||
#define DWC3_DCTL_LSFTRST (1 << 29)
|
||||
#define DWC3_DCTL_RUN_STOP BIT(31)
|
||||
#define DWC3_DCTL_CSFTRST BIT(30)
|
||||
#define DWC3_DCTL_LSFTRST BIT(29)
|
||||
|
||||
#define DWC3_DCTL_HIRD_THRES_MASK (0x1f << 24)
|
||||
#define DWC3_DCTL_HIRD_THRES(n) ((n) << 24)
|
||||
|
||||
#define DWC3_DCTL_APPL1RES (1 << 23)
|
||||
#define DWC3_DCTL_APPL1RES BIT(23)
|
||||
|
||||
/* These apply for core versions 1.87a and earlier */
|
||||
#define DWC3_DCTL_TRGTULST_MASK (0x0f << 17)
|
||||
|
|
@ -341,15 +343,15 @@
|
|||
#define DWC3_DCTL_LPM_ERRATA_MASK DWC3_DCTL_LPM_ERRATA(0xf)
|
||||
#define DWC3_DCTL_LPM_ERRATA(n) ((n) << 20)
|
||||
|
||||
#define DWC3_DCTL_KEEP_CONNECT (1 << 19)
|
||||
#define DWC3_DCTL_L1_HIBER_EN (1 << 18)
|
||||
#define DWC3_DCTL_CRS (1 << 17)
|
||||
#define DWC3_DCTL_CSS (1 << 16)
|
||||
#define DWC3_DCTL_KEEP_CONNECT BIT(19)
|
||||
#define DWC3_DCTL_L1_HIBER_EN BIT(18)
|
||||
#define DWC3_DCTL_CRS BIT(17)
|
||||
#define DWC3_DCTL_CSS BIT(16)
|
||||
|
||||
#define DWC3_DCTL_INITU2ENA (1 << 12)
|
||||
#define DWC3_DCTL_ACCEPTU2ENA (1 << 11)
|
||||
#define DWC3_DCTL_INITU1ENA (1 << 10)
|
||||
#define DWC3_DCTL_ACCEPTU1ENA (1 << 9)
|
||||
#define DWC3_DCTL_INITU2ENA BIT(12)
|
||||
#define DWC3_DCTL_ACCEPTU2ENA BIT(11)
|
||||
#define DWC3_DCTL_INITU1ENA BIT(10)
|
||||
#define DWC3_DCTL_ACCEPTU1ENA BIT(9)
|
||||
#define DWC3_DCTL_TSTCTRL_MASK (0xf << 1)
|
||||
|
||||
#define DWC3_DCTL_ULSTCHNGREQ_MASK (0x0f << 5)
|
||||
|
|
@ -364,36 +366,36 @@
|
|||
#define DWC3_DCTL_ULSTCHNG_LOOPBACK (DWC3_DCTL_ULSTCHNGREQ(11))
|
||||
|
||||
/* Device Event Enable Register */
|
||||
#define DWC3_DEVTEN_VNDRDEVTSTRCVEDEN (1 << 12)
|
||||
#define DWC3_DEVTEN_EVNTOVERFLOWEN (1 << 11)
|
||||
#define DWC3_DEVTEN_CMDCMPLTEN (1 << 10)
|
||||
#define DWC3_DEVTEN_ERRTICERREN (1 << 9)
|
||||
#define DWC3_DEVTEN_SOFEN (1 << 7)
|
||||
#define DWC3_DEVTEN_EOPFEN (1 << 6)
|
||||
#define DWC3_DEVTEN_HIBERNATIONREQEVTEN (1 << 5)
|
||||
#define DWC3_DEVTEN_WKUPEVTEN (1 << 4)
|
||||
#define DWC3_DEVTEN_ULSTCNGEN (1 << 3)
|
||||
#define DWC3_DEVTEN_CONNECTDONEEN (1 << 2)
|
||||
#define DWC3_DEVTEN_USBRSTEN (1 << 1)
|
||||
#define DWC3_DEVTEN_DISCONNEVTEN (1 << 0)
|
||||
#define DWC3_DEVTEN_VNDRDEVTSTRCVEDEN BIT(12)
|
||||
#define DWC3_DEVTEN_EVNTOVERFLOWEN BIT(11)
|
||||
#define DWC3_DEVTEN_CMDCMPLTEN BIT(10)
|
||||
#define DWC3_DEVTEN_ERRTICERREN BIT(9)
|
||||
#define DWC3_DEVTEN_SOFEN BIT(7)
|
||||
#define DWC3_DEVTEN_EOPFEN BIT(6)
|
||||
#define DWC3_DEVTEN_HIBERNATIONREQEVTEN BIT(5)
|
||||
#define DWC3_DEVTEN_WKUPEVTEN BIT(4)
|
||||
#define DWC3_DEVTEN_ULSTCNGEN BIT(3)
|
||||
#define DWC3_DEVTEN_CONNECTDONEEN BIT(2)
|
||||
#define DWC3_DEVTEN_USBRSTEN BIT(1)
|
||||
#define DWC3_DEVTEN_DISCONNEVTEN BIT(0)
|
||||
|
||||
/* Device Status Register */
|
||||
#define DWC3_DSTS_DCNRD (1 << 29)
|
||||
#define DWC3_DSTS_DCNRD BIT(29)
|
||||
|
||||
/* This applies for core versions 1.87a and earlier */
|
||||
#define DWC3_DSTS_PWRUPREQ (1 << 24)
|
||||
#define DWC3_DSTS_PWRUPREQ BIT(24)
|
||||
|
||||
/* These apply for core versions 1.94a and later */
|
||||
#define DWC3_DSTS_RSS (1 << 25)
|
||||
#define DWC3_DSTS_SSS (1 << 24)
|
||||
#define DWC3_DSTS_RSS BIT(25)
|
||||
#define DWC3_DSTS_SSS BIT(24)
|
||||
|
||||
#define DWC3_DSTS_COREIDLE (1 << 23)
|
||||
#define DWC3_DSTS_DEVCTRLHLT (1 << 22)
|
||||
#define DWC3_DSTS_COREIDLE BIT(23)
|
||||
#define DWC3_DSTS_DEVCTRLHLT BIT(22)
|
||||
|
||||
#define DWC3_DSTS_USBLNKST_MASK (0x0f << 18)
|
||||
#define DWC3_DSTS_USBLNKST(n) (((n) & DWC3_DSTS_USBLNKST_MASK) >> 18)
|
||||
|
||||
#define DWC3_DSTS_RXFIFOEMPTY (1 << 17)
|
||||
#define DWC3_DSTS_RXFIFOEMPTY BIT(17)
|
||||
|
||||
#define DWC3_DSTS_SOFFN_MASK (0x3fff << 3)
|
||||
#define DWC3_DSTS_SOFFN(n) (((n) & DWC3_DSTS_SOFFN_MASK) >> 3)
|
||||
|
|
@ -403,7 +405,7 @@
|
|||
#define DWC3_DSTS_SUPERSPEED_PLUS (5 << 0) /* DWC_usb31 only */
|
||||
#define DWC3_DSTS_SUPERSPEED (4 << 0)
|
||||
#define DWC3_DSTS_HIGHSPEED (0 << 0)
|
||||
#define DWC3_DSTS_FULLSPEED (1 << 0)
|
||||
#define DWC3_DSTS_FULLSPEED BIT(0)
|
||||
#define DWC3_DSTS_LOWSPEED (2 << 0)
|
||||
|
||||
/* Device Generic Command Register */
|
||||
|
|
@ -421,26 +423,26 @@
|
|||
#define DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK 0x10
|
||||
|
||||
#define DWC3_DGCMD_STATUS(n) (((n) >> 12) & 0x0F)
|
||||
#define DWC3_DGCMD_CMDACT (1 << 10)
|
||||
#define DWC3_DGCMD_CMDIOC (1 << 8)
|
||||
#define DWC3_DGCMD_CMDACT BIT(10)
|
||||
#define DWC3_DGCMD_CMDIOC BIT(8)
|
||||
|
||||
/* Device Generic Command Parameter Register */
|
||||
#define DWC3_DGCMDPAR_FORCE_LINKPM_ACCEPT (1 << 0)
|
||||
#define DWC3_DGCMDPAR_FORCE_LINKPM_ACCEPT BIT(0)
|
||||
#define DWC3_DGCMDPAR_FIFO_NUM(n) ((n) << 0)
|
||||
#define DWC3_DGCMDPAR_RX_FIFO (0 << 5)
|
||||
#define DWC3_DGCMDPAR_TX_FIFO (1 << 5)
|
||||
#define DWC3_DGCMDPAR_TX_FIFO BIT(5)
|
||||
#define DWC3_DGCMDPAR_LOOPBACK_DIS (0 << 0)
|
||||
#define DWC3_DGCMDPAR_LOOPBACK_ENA (1 << 0)
|
||||
#define DWC3_DGCMDPAR_LOOPBACK_ENA BIT(0)
|
||||
|
||||
/* Device Endpoint Command Register */
|
||||
#define DWC3_DEPCMD_PARAM_SHIFT 16
|
||||
#define DWC3_DEPCMD_PARAM(x) ((x) << DWC3_DEPCMD_PARAM_SHIFT)
|
||||
#define DWC3_DEPCMD_GET_RSC_IDX(x) (((x) >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f)
|
||||
#define DWC3_DEPCMD_STATUS(x) (((x) >> 12) & 0x0F)
|
||||
#define DWC3_DEPCMD_HIPRI_FORCERM (1 << 11)
|
||||
#define DWC3_DEPCMD_CLEARPENDIN (1 << 11)
|
||||
#define DWC3_DEPCMD_CMDACT (1 << 10)
|
||||
#define DWC3_DEPCMD_CMDIOC (1 << 8)
|
||||
#define DWC3_DEPCMD_HIPRI_FORCERM BIT(11)
|
||||
#define DWC3_DEPCMD_CLEARPENDIN BIT(11)
|
||||
#define DWC3_DEPCMD_CMDACT BIT(10)
|
||||
#define DWC3_DEPCMD_CMDIOC BIT(8)
|
||||
|
||||
#define DWC3_DEPCMD_DEPSTARTCFG (0x09 << 0)
|
||||
#define DWC3_DEPCMD_ENDTRANSFER (0x08 << 0)
|
||||
|
|
@ -458,7 +460,7 @@
|
|||
#define DWC3_DEPCMD_CMD(x) ((x) & 0xf)
|
||||
|
||||
/* The EP number goes 0..31 so ep0 is always out and ep1 is always in */
|
||||
#define DWC3_DALEPENA_EP(n) (1 << n)
|
||||
#define DWC3_DALEPENA_EP(n) BIT(n)
|
||||
|
||||
#define DWC3_DEPCMD_TYPE_CONTROL 0
|
||||
#define DWC3_DEPCMD_TYPE_ISOC 1
|
||||
|
|
@ -500,8 +502,8 @@ struct dwc3_event_buffer {
|
|||
struct dwc3 *dwc;
|
||||
};
|
||||
|
||||
#define DWC3_EP_FLAG_STALLED (1 << 0)
|
||||
#define DWC3_EP_FLAG_WEDGED (1 << 1)
|
||||
#define DWC3_EP_FLAG_STALLED BIT(0)
|
||||
#define DWC3_EP_FLAG_WEDGED BIT(1)
|
||||
|
||||
#define DWC3_EP_DIRECTION_TX true
|
||||
#define DWC3_EP_DIRECTION_RX false
|
||||
|
|
@ -550,17 +552,17 @@ struct dwc3_ep {
|
|||
|
||||
u32 saved_state;
|
||||
unsigned flags;
|
||||
#define DWC3_EP_ENABLED (1 << 0)
|
||||
#define DWC3_EP_STALL (1 << 1)
|
||||
#define DWC3_EP_WEDGE (1 << 2)
|
||||
#define DWC3_EP_BUSY (1 << 4)
|
||||
#define DWC3_EP_PENDING_REQUEST (1 << 5)
|
||||
#define DWC3_EP_MISSED_ISOC (1 << 6)
|
||||
#define DWC3_EP_END_TRANSFER_PENDING (1 << 7)
|
||||
#define DWC3_EP_TRANSFER_STARTED (1 << 8)
|
||||
#define DWC3_EP_ENABLED BIT(0)
|
||||
#define DWC3_EP_STALL BIT(1)
|
||||
#define DWC3_EP_WEDGE BIT(2)
|
||||
#define DWC3_EP_BUSY BIT(4)
|
||||
#define DWC3_EP_PENDING_REQUEST BIT(5)
|
||||
#define DWC3_EP_MISSED_ISOC BIT(6)
|
||||
#define DWC3_EP_END_TRANSFER_PENDING BIT(7)
|
||||
#define DWC3_EP_TRANSFER_STARTED BIT(8)
|
||||
|
||||
/* This last one is specific to EP0 */
|
||||
#define DWC3_EP0_DIR_IN (1 << 31)
|
||||
#define DWC3_EP0_DIR_IN BIT(31)
|
||||
|
||||
/*
|
||||
* IMPORTANT: we *know* we have 256 TRBs in our @trb_pool, so we will
|
||||
|
|
@ -638,13 +640,13 @@ enum dwc3_link_state {
|
|||
#define DWC3_TRB_STS_XFER_IN_PROG 4
|
||||
|
||||
/* TRB Control */
|
||||
#define DWC3_TRB_CTRL_HWO (1 << 0)
|
||||
#define DWC3_TRB_CTRL_LST (1 << 1)
|
||||
#define DWC3_TRB_CTRL_CHN (1 << 2)
|
||||
#define DWC3_TRB_CTRL_CSP (1 << 3)
|
||||
#define DWC3_TRB_CTRL_HWO BIT(0)
|
||||
#define DWC3_TRB_CTRL_LST BIT(1)
|
||||
#define DWC3_TRB_CTRL_CHN BIT(2)
|
||||
#define DWC3_TRB_CTRL_CSP BIT(3)
|
||||
#define DWC3_TRB_CTRL_TRBCTL(n) (((n) & 0x3f) << 4)
|
||||
#define DWC3_TRB_CTRL_ISP_IMI (1 << 10)
|
||||
#define DWC3_TRB_CTRL_IOC (1 << 11)
|
||||
#define DWC3_TRB_CTRL_ISP_IMI BIT(10)
|
||||
#define DWC3_TRB_CTRL_IOC BIT(11)
|
||||
#define DWC3_TRB_CTRL_SID_SOFN(n) (((n) & 0xffff) << 14)
|
||||
|
||||
#define DWC3_TRBCTL_TYPE(n) ((n) & (0x3f << 4))
|
||||
|
|
@ -746,6 +748,7 @@ struct dwc3_request {
|
|||
unsigned direction:1;
|
||||
unsigned mapped:1;
|
||||
unsigned started:1;
|
||||
unsigned zero:1;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -758,15 +761,11 @@ struct dwc3_scratchpad_array {
|
|||
|
||||
/**
|
||||
* struct dwc3 - representation of our controller
|
||||
* @ctrl_req: usb control request which is used for ep0
|
||||
* @drd_work - workqueue used for role swapping
|
||||
* @ep0_trb: trb which is used for the ctrl_req
|
||||
* @ep0_bounce: bounce buffer for ep0
|
||||
* @zlp_buf: used when request->zero is set
|
||||
* @setup_buf: used while precessing STD USB requests
|
||||
* @ctrl_req_addr: dma address of ctrl_req
|
||||
* @ep0_trb: dma address of ep0_trb
|
||||
* @ep0_usb_req: dummy req used while handling STD USB requests
|
||||
* @ep0_bounce_addr: dma address of ep0_bounce
|
||||
* @scratch_addr: dma address of scratchbuf
|
||||
* @ep0_in_setup: one control transfer is completed and enter setup phase
|
||||
* @lock: for synchronizing
|
||||
|
|
@ -784,6 +783,10 @@ struct dwc3_scratchpad_array {
|
|||
* @maximum_speed: maximum speed requested (mainly for testing purposes)
|
||||
* @revision: revision register contents
|
||||
* @dr_mode: requested mode of operation
|
||||
* @current_dr_role: current role of operation when in dual-role mode
|
||||
* @desired_dr_role: desired role of operation when in dual-role mode
|
||||
* @edev: extcon handle
|
||||
* @edev_nb: extcon notifier
|
||||
* @hsphy_mode: UTMI phy mode, one of following:
|
||||
* - USBPHY_INTERFACE_MODE_UTMI
|
||||
* - USBPHY_INTERFACE_MODE_UTMIW
|
||||
|
|
@ -799,8 +802,7 @@ struct dwc3_scratchpad_array {
|
|||
* @u2pel: parameter from Set SEL request.
|
||||
* @u1sel: parameter from Set SEL request.
|
||||
* @u1pel: parameter from Set SEL request.
|
||||
* @num_out_eps: number of out endpoints
|
||||
* @num_in_eps: number of in endpoints
|
||||
* @num_eps: number of endpoints
|
||||
* @ep0_next_event: hold the next expected event
|
||||
* @ep0state: state of endpoint zero
|
||||
* @link_state: link state
|
||||
|
|
@ -858,17 +860,13 @@ struct dwc3_scratchpad_array {
|
|||
* increments or 0 to disable.
|
||||
*/
|
||||
struct dwc3 {
|
||||
struct usb_ctrlrequest *ctrl_req;
|
||||
struct work_struct drd_work;
|
||||
struct dwc3_trb *ep0_trb;
|
||||
void *bounce;
|
||||
void *ep0_bounce;
|
||||
void *zlp_buf;
|
||||
void *scratchbuf;
|
||||
u8 *setup_buf;
|
||||
dma_addr_t ctrl_req_addr;
|
||||
dma_addr_t ep0_trb_addr;
|
||||
dma_addr_t bounce_addr;
|
||||
dma_addr_t ep0_bounce_addr;
|
||||
dma_addr_t scratch_addr;
|
||||
struct dwc3_request ep0_usb_req;
|
||||
struct completion ep0_in_setup;
|
||||
|
|
@ -900,6 +898,10 @@ struct dwc3 {
|
|||
size_t regs_size;
|
||||
|
||||
enum usb_dr_mode dr_mode;
|
||||
u32 current_dr_role;
|
||||
u32 desired_dr_role;
|
||||
struct extcon_dev *edev;
|
||||
struct notifier_block edev_nb;
|
||||
enum usb_phy_interface hsphy_mode;
|
||||
|
||||
u32 fladj;
|
||||
|
|
@ -960,8 +962,7 @@ struct dwc3 {
|
|||
|
||||
u8 speed;
|
||||
|
||||
u8 num_out_eps;
|
||||
u8 num_in_eps;
|
||||
u8 num_eps;
|
||||
|
||||
struct dwc3_hwparams hwparams;
|
||||
struct dentry *root;
|
||||
|
|
@ -1010,7 +1011,7 @@ struct dwc3 {
|
|||
u16 imod_interval;
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
#define work_to_dwc(w) (container_of((w), struct dwc3, drd_work))
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
|
|
@ -1054,13 +1055,13 @@ struct dwc3_event_depevt {
|
|||
u32 status:4;
|
||||
|
||||
/* Within XferNotReady */
|
||||
#define DEPEVT_STATUS_TRANSFER_ACTIVE (1 << 3)
|
||||
#define DEPEVT_STATUS_TRANSFER_ACTIVE BIT(3)
|
||||
|
||||
/* Within XferComplete */
|
||||
#define DEPEVT_STATUS_BUSERR (1 << 0)
|
||||
#define DEPEVT_STATUS_SHORT (1 << 1)
|
||||
#define DEPEVT_STATUS_IOC (1 << 2)
|
||||
#define DEPEVT_STATUS_LST (1 << 3)
|
||||
#define DEPEVT_STATUS_BUSERR BIT(0)
|
||||
#define DEPEVT_STATUS_SHORT BIT(1)
|
||||
#define DEPEVT_STATUS_IOC BIT(2)
|
||||
#define DEPEVT_STATUS_LST BIT(3)
|
||||
|
||||
/* Stream event only */
|
||||
#define DEPEVT_STREAMEVT_FOUND 1
|
||||
|
|
@ -1221,6 +1222,16 @@ static inline int dwc3_send_gadget_generic_command(struct dwc3 *dwc,
|
|||
{ return 0; }
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
|
||||
int dwc3_drd_init(struct dwc3 *dwc);
|
||||
void dwc3_drd_exit(struct dwc3 *dwc);
|
||||
#else
|
||||
static inline int dwc3_drd_init(struct dwc3 *dwc)
|
||||
{ return 0; }
|
||||
static inline void dwc3_drd_exit(struct dwc3 *dwc)
|
||||
{ }
|
||||
#endif
|
||||
|
||||
/* power management interface */
|
||||
#if !IS_ENABLED(CONFIG_USB_DWC3_HOST)
|
||||
int dwc3_gadget_suspend(struct dwc3 *dwc);
|
||||
|
|
|
|||
|
|
@ -124,6 +124,34 @@ dwc3_gadget_link_string(enum dwc3_link_state link_state)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc3_trb_type_string - returns TRB type as a string
|
||||
* @type: the type of the TRB
|
||||
*/
|
||||
static inline const char *dwc3_trb_type_string(unsigned int type)
|
||||
{
|
||||
switch (type) {
|
||||
case DWC3_TRBCTL_NORMAL:
|
||||
return "normal";
|
||||
case DWC3_TRBCTL_CONTROL_SETUP:
|
||||
return "setup";
|
||||
case DWC3_TRBCTL_CONTROL_STATUS2:
|
||||
return "status2";
|
||||
case DWC3_TRBCTL_CONTROL_STATUS3:
|
||||
return "status3";
|
||||
case DWC3_TRBCTL_CONTROL_DATA:
|
||||
return "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 inline const char *dwc3_ep0_state_string(enum dwc3_ep0_state state)
|
||||
{
|
||||
switch (state) {
|
||||
|
|
|
|||
|
|
@ -300,7 +300,7 @@ static int dwc3_mode_show(struct seq_file *s, void *unused)
|
|||
seq_printf(s, "device\n");
|
||||
break;
|
||||
case DWC3_GCTL_PRTCAP_OTG:
|
||||
seq_printf(s, "OTG\n");
|
||||
seq_printf(s, "otg\n");
|
||||
break;
|
||||
default:
|
||||
seq_printf(s, "UNKNOWN %08x\n", DWC3_GCTL_PRTCAP(reg));
|
||||
|
|
@ -319,7 +319,6 @@ static ssize_t dwc3_mode_write(struct file *file,
|
|||
{
|
||||
struct seq_file *s = file->private_data;
|
||||
struct dwc3 *dwc = s->private;
|
||||
unsigned long flags;
|
||||
u32 mode = 0;
|
||||
char buf[32];
|
||||
|
||||
|
|
@ -327,19 +326,16 @@ static ssize_t dwc3_mode_write(struct file *file,
|
|||
return -EFAULT;
|
||||
|
||||
if (!strncmp(buf, "host", 4))
|
||||
mode |= DWC3_GCTL_PRTCAP_HOST;
|
||||
mode = DWC3_GCTL_PRTCAP_HOST;
|
||||
|
||||
if (!strncmp(buf, "device", 6))
|
||||
mode |= DWC3_GCTL_PRTCAP_DEVICE;
|
||||
mode = DWC3_GCTL_PRTCAP_DEVICE;
|
||||
|
||||
if (!strncmp(buf, "otg", 3))
|
||||
mode |= DWC3_GCTL_PRTCAP_OTG;
|
||||
mode = DWC3_GCTL_PRTCAP_OTG;
|
||||
|
||||
dwc3_set_mode(dwc, mode);
|
||||
|
||||
if (mode) {
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
dwc3_set_mode(dwc, mode);
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
|
@ -446,52 +442,7 @@ static int dwc3_link_state_show(struct seq_file *s, void *unused)
|
|||
state = DWC3_DSTS_USBLNKST(reg);
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
switch (state) {
|
||||
case DWC3_LINK_STATE_U0:
|
||||
seq_printf(s, "U0\n");
|
||||
break;
|
||||
case DWC3_LINK_STATE_U1:
|
||||
seq_printf(s, "U1\n");
|
||||
break;
|
||||
case DWC3_LINK_STATE_U2:
|
||||
seq_printf(s, "U2\n");
|
||||
break;
|
||||
case DWC3_LINK_STATE_U3:
|
||||
seq_printf(s, "U3\n");
|
||||
break;
|
||||
case DWC3_LINK_STATE_SS_DIS:
|
||||
seq_printf(s, "SS.Disabled\n");
|
||||
break;
|
||||
case DWC3_LINK_STATE_RX_DET:
|
||||
seq_printf(s, "Rx.Detect\n");
|
||||
break;
|
||||
case DWC3_LINK_STATE_SS_INACT:
|
||||
seq_printf(s, "SS.Inactive\n");
|
||||
break;
|
||||
case DWC3_LINK_STATE_POLL:
|
||||
seq_printf(s, "Poll\n");
|
||||
break;
|
||||
case DWC3_LINK_STATE_RECOV:
|
||||
seq_printf(s, "Recovery\n");
|
||||
break;
|
||||
case DWC3_LINK_STATE_HRESET:
|
||||
seq_printf(s, "HRESET\n");
|
||||
break;
|
||||
case DWC3_LINK_STATE_CMPLY:
|
||||
seq_printf(s, "Compliance\n");
|
||||
break;
|
||||
case DWC3_LINK_STATE_LPBK:
|
||||
seq_printf(s, "Loopback\n");
|
||||
break;
|
||||
case DWC3_LINK_STATE_RESET:
|
||||
seq_printf(s, "Reset\n");
|
||||
break;
|
||||
case DWC3_LINK_STATE_RESUME:
|
||||
seq_printf(s, "Resume\n");
|
||||
break;
|
||||
default:
|
||||
seq_printf(s, "UNKNOWN %d\n", state);
|
||||
}
|
||||
seq_printf(s, "%s\n", dwc3_gadget_link_string(state));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -689,30 +640,6 @@ out:
|
|||
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;
|
||||
|
|
@ -733,10 +660,11 @@ static int dwc3_ep_trb_ring_show(struct seq_file *s, void *unused)
|
|||
|
||||
for (i = 0; i < DWC3_TRB_NUM; i++) {
|
||||
struct dwc3_trb *trb = &dep->trb_pool[i];
|
||||
unsigned int type = DWC3_TRBCTL_TYPE(trb->ctrl);
|
||||
|
||||
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),
|
||||
dwc3_trb_type_string(type),
|
||||
!!(trb->ctrl & DWC3_TRB_CTRL_IOC),
|
||||
!!(trb->ctrl & DWC3_TRB_CTRL_ISP_IMI),
|
||||
!!(trb->ctrl & DWC3_TRB_CTRL_CSP),
|
||||
|
|
@ -822,19 +750,8 @@ static void dwc3_debugfs_create_endpoint_dirs(struct dwc3 *dwc,
|
|||
{
|
||||
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];
|
||||
for (i = 0; i < dwc->num_eps; i++) {
|
||||
struct dwc3_ep *dep = dwc->eps[i];
|
||||
|
||||
if (!dep)
|
||||
continue;
|
||||
|
|
|
|||
85
drivers/usb/dwc3/drd.c
Normal file
85
drivers/usb/dwc3/drd.c
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/**
|
||||
* drd.c - DesignWare USB3 DRD Controller Dual-role support
|
||||
*
|
||||
* Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com
|
||||
*
|
||||
* Authors: Roger Quadros <rogerq@ti.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 of
|
||||
* the License as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/extcon.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "core.h"
|
||||
#include "gadget.h"
|
||||
|
||||
static void dwc3_drd_update(struct dwc3 *dwc)
|
||||
{
|
||||
int id;
|
||||
|
||||
id = extcon_get_state(dwc->edev, EXTCON_USB_HOST);
|
||||
if (id < 0)
|
||||
id = 0;
|
||||
|
||||
dwc3_set_mode(dwc, id ?
|
||||
DWC3_GCTL_PRTCAP_HOST :
|
||||
DWC3_GCTL_PRTCAP_DEVICE);
|
||||
}
|
||||
|
||||
static int dwc3_drd_notifier(struct notifier_block *nb,
|
||||
unsigned long event, void *ptr)
|
||||
{
|
||||
struct dwc3 *dwc = container_of(nb, struct dwc3, edev_nb);
|
||||
|
||||
dwc3_set_mode(dwc, event ?
|
||||
DWC3_GCTL_PRTCAP_HOST :
|
||||
DWC3_GCTL_PRTCAP_DEVICE);
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
int dwc3_drd_init(struct dwc3 *dwc)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (dwc->dev->of_node) {
|
||||
if (of_property_read_bool(dwc->dev->of_node, "extcon"))
|
||||
dwc->edev = extcon_get_edev_by_phandle(dwc->dev, 0);
|
||||
|
||||
if (IS_ERR(dwc->edev))
|
||||
return PTR_ERR(dwc->edev);
|
||||
|
||||
dwc->edev_nb.notifier_call = dwc3_drd_notifier;
|
||||
ret = extcon_register_notifier(dwc->edev, EXTCON_USB_HOST,
|
||||
&dwc->edev_nb);
|
||||
if (ret < 0) {
|
||||
dev_err(dwc->dev, "couldn't register cable notifier\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
dwc3_drd_update(dwc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dwc3_drd_exit(struct dwc3 *dwc)
|
||||
{
|
||||
extcon_unregister_notifier(dwc->edev, EXTCON_USB_HOST,
|
||||
&dwc->edev_nb);
|
||||
|
||||
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
|
||||
flush_work(&dwc->drd_work);
|
||||
dwc3_gadget_exit(dwc);
|
||||
}
|
||||
|
|
@ -147,53 +147,53 @@ static int dwc3_exynos_probe(struct platform_device *pdev)
|
|||
exynos->vdd33 = devm_regulator_get(dev, "vdd33");
|
||||
if (IS_ERR(exynos->vdd33)) {
|
||||
ret = PTR_ERR(exynos->vdd33);
|
||||
goto err2;
|
||||
goto vdd33_err;
|
||||
}
|
||||
ret = regulator_enable(exynos->vdd33);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to enable VDD33 supply\n");
|
||||
goto err2;
|
||||
goto vdd33_err;
|
||||
}
|
||||
|
||||
exynos->vdd10 = devm_regulator_get(dev, "vdd10");
|
||||
if (IS_ERR(exynos->vdd10)) {
|
||||
ret = PTR_ERR(exynos->vdd10);
|
||||
goto err3;
|
||||
goto vdd10_err;
|
||||
}
|
||||
ret = regulator_enable(exynos->vdd10);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to enable VDD10 supply\n");
|
||||
goto err3;
|
||||
goto vdd10_err;
|
||||
}
|
||||
|
||||
ret = dwc3_exynos_register_phys(exynos);
|
||||
if (ret) {
|
||||
dev_err(dev, "couldn't register PHYs\n");
|
||||
goto err4;
|
||||
goto phys_err;
|
||||
}
|
||||
|
||||
if (node) {
|
||||
ret = of_platform_populate(node, NULL, NULL, dev);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to add dwc3 core\n");
|
||||
goto err5;
|
||||
goto populate_err;
|
||||
}
|
||||
} else {
|
||||
dev_err(dev, "no device node, failed to add dwc3 core\n");
|
||||
ret = -ENODEV;
|
||||
goto err5;
|
||||
goto populate_err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err5:
|
||||
populate_err:
|
||||
platform_device_unregister(exynos->usb2_phy);
|
||||
platform_device_unregister(exynos->usb3_phy);
|
||||
err4:
|
||||
phys_err:
|
||||
regulator_disable(exynos->vdd10);
|
||||
err3:
|
||||
vdd10_err:
|
||||
regulator_disable(exynos->vdd33);
|
||||
err2:
|
||||
vdd33_err:
|
||||
clk_disable_unprepare(exynos->axius_clk);
|
||||
axius_clk_err:
|
||||
clk_disable_unprepare(exynos->susp_clk);
|
||||
|
|
|
|||
|
|
@ -79,40 +79,40 @@
|
|||
#define USBOTGSS_DEBUG_OFFSET 0x0600
|
||||
|
||||
/* SYSCONFIG REGISTER */
|
||||
#define USBOTGSS_SYSCONFIG_DMADISABLE (1 << 16)
|
||||
#define USBOTGSS_SYSCONFIG_DMADISABLE BIT(16)
|
||||
|
||||
/* IRQ_EOI REGISTER */
|
||||
#define USBOTGSS_IRQ_EOI_LINE_NUMBER (1 << 0)
|
||||
#define USBOTGSS_IRQ_EOI_LINE_NUMBER BIT(0)
|
||||
|
||||
/* IRQS0 BITS */
|
||||
#define USBOTGSS_IRQO_COREIRQ_ST (1 << 0)
|
||||
#define USBOTGSS_IRQO_COREIRQ_ST BIT(0)
|
||||
|
||||
/* IRQMISC BITS */
|
||||
#define USBOTGSS_IRQMISC_DMADISABLECLR (1 << 17)
|
||||
#define USBOTGSS_IRQMISC_OEVT (1 << 16)
|
||||
#define USBOTGSS_IRQMISC_DRVVBUS_RISE (1 << 13)
|
||||
#define USBOTGSS_IRQMISC_CHRGVBUS_RISE (1 << 12)
|
||||
#define USBOTGSS_IRQMISC_DISCHRGVBUS_RISE (1 << 11)
|
||||
#define USBOTGSS_IRQMISC_IDPULLUP_RISE (1 << 8)
|
||||
#define USBOTGSS_IRQMISC_DRVVBUS_FALL (1 << 5)
|
||||
#define USBOTGSS_IRQMISC_CHRGVBUS_FALL (1 << 4)
|
||||
#define USBOTGSS_IRQMISC_DISCHRGVBUS_FALL (1 << 3)
|
||||
#define USBOTGSS_IRQMISC_IDPULLUP_FALL (1 << 0)
|
||||
#define USBOTGSS_IRQMISC_DMADISABLECLR BIT(17)
|
||||
#define USBOTGSS_IRQMISC_OEVT BIT(16)
|
||||
#define USBOTGSS_IRQMISC_DRVVBUS_RISE BIT(13)
|
||||
#define USBOTGSS_IRQMISC_CHRGVBUS_RISE BIT(12)
|
||||
#define USBOTGSS_IRQMISC_DISCHRGVBUS_RISE BIT(11)
|
||||
#define USBOTGSS_IRQMISC_IDPULLUP_RISE BIT(8)
|
||||
#define USBOTGSS_IRQMISC_DRVVBUS_FALL BIT(5)
|
||||
#define USBOTGSS_IRQMISC_CHRGVBUS_FALL BIT(4)
|
||||
#define USBOTGSS_IRQMISC_DISCHRGVBUS_FALL BIT(3)
|
||||
#define USBOTGSS_IRQMISC_IDPULLUP_FALL BIT(0)
|
||||
|
||||
/* UTMI_OTG_STATUS REGISTER */
|
||||
#define USBOTGSS_UTMI_OTG_STATUS_DRVVBUS (1 << 5)
|
||||
#define USBOTGSS_UTMI_OTG_STATUS_CHRGVBUS (1 << 4)
|
||||
#define USBOTGSS_UTMI_OTG_STATUS_DISCHRGVBUS (1 << 3)
|
||||
#define USBOTGSS_UTMI_OTG_STATUS_IDPULLUP (1 << 0)
|
||||
#define USBOTGSS_UTMI_OTG_STATUS_DRVVBUS BIT(5)
|
||||
#define USBOTGSS_UTMI_OTG_STATUS_CHRGVBUS BIT(4)
|
||||
#define USBOTGSS_UTMI_OTG_STATUS_DISCHRGVBUS BIT(3)
|
||||
#define USBOTGSS_UTMI_OTG_STATUS_IDPULLUP BIT(0)
|
||||
|
||||
/* UTMI_OTG_CTRL REGISTER */
|
||||
#define USBOTGSS_UTMI_OTG_CTRL_SW_MODE (1 << 31)
|
||||
#define USBOTGSS_UTMI_OTG_CTRL_POWERPRESENT (1 << 9)
|
||||
#define USBOTGSS_UTMI_OTG_CTRL_TXBITSTUFFENABLE (1 << 8)
|
||||
#define USBOTGSS_UTMI_OTG_CTRL_IDDIG (1 << 4)
|
||||
#define USBOTGSS_UTMI_OTG_CTRL_SESSEND (1 << 3)
|
||||
#define USBOTGSS_UTMI_OTG_CTRL_SESSVALID (1 << 2)
|
||||
#define USBOTGSS_UTMI_OTG_CTRL_VBUSVALID (1 << 1)
|
||||
#define USBOTGSS_UTMI_OTG_CTRL_SW_MODE BIT(31)
|
||||
#define USBOTGSS_UTMI_OTG_CTRL_POWERPRESENT BIT(9)
|
||||
#define USBOTGSS_UTMI_OTG_CTRL_TXBITSTUFFENABLE BIT(8)
|
||||
#define USBOTGSS_UTMI_OTG_CTRL_IDDIG BIT(4)
|
||||
#define USBOTGSS_UTMI_OTG_CTRL_SESSEND BIT(3)
|
||||
#define USBOTGSS_UTMI_OTG_CTRL_SESSVALID BIT(2)
|
||||
#define USBOTGSS_UTMI_OTG_CTRL_VBUSVALID BIT(1)
|
||||
|
||||
struct dwc3_omap {
|
||||
struct device *dev;
|
||||
|
|
|
|||
|
|
@ -39,14 +39,13 @@ static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep);
|
|||
static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
|
||||
struct dwc3_ep *dep, struct dwc3_request *req);
|
||||
|
||||
static void dwc3_ep0_prepare_one_trb(struct dwc3 *dwc, u8 epnum,
|
||||
static void dwc3_ep0_prepare_one_trb(struct dwc3_ep *dep,
|
||||
dma_addr_t buf_dma, u32 len, u32 type, bool chain)
|
||||
{
|
||||
struct dwc3_trb *trb;
|
||||
struct dwc3_ep *dep;
|
||||
|
||||
dep = dwc->eps[epnum];
|
||||
struct dwc3 *dwc;
|
||||
|
||||
dwc = dep->dwc;
|
||||
trb = &dwc->ep0_trb[dep->trb_enqueue];
|
||||
|
||||
if (chain)
|
||||
|
|
@ -69,16 +68,17 @@ static void dwc3_ep0_prepare_one_trb(struct dwc3 *dwc, u8 epnum,
|
|||
trace_dwc3_prepare_trb(dep, trb);
|
||||
}
|
||||
|
||||
static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum)
|
||||
static int dwc3_ep0_start_trans(struct dwc3_ep *dep)
|
||||
{
|
||||
struct dwc3_gadget_ep_cmd_params params;
|
||||
struct dwc3_ep *dep;
|
||||
struct dwc3 *dwc;
|
||||
int ret;
|
||||
|
||||
dep = dwc->eps[epnum];
|
||||
if (dep->flags & DWC3_EP_BUSY)
|
||||
return 0;
|
||||
|
||||
dwc = dep->dwc;
|
||||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
params.param0 = upper_32_bits(dwc->ep0_trb_addr);
|
||||
params.param1 = lower_32_bits(dwc->ep0_trb_addr);
|
||||
|
|
@ -279,13 +279,15 @@ int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value)
|
|||
|
||||
void dwc3_ep0_out_start(struct dwc3 *dwc)
|
||||
{
|
||||
struct dwc3_ep *dep;
|
||||
int ret;
|
||||
|
||||
complete(&dwc->ep0_in_setup);
|
||||
|
||||
dwc3_ep0_prepare_one_trb(dwc, 0, dwc->ctrl_req_addr, 8,
|
||||
dep = dwc->eps[0];
|
||||
dwc3_ep0_prepare_one_trb(dep, dwc->ep0_trb_addr, 8,
|
||||
DWC3_TRBCTL_CONTROL_SETUP, false);
|
||||
ret = dwc3_ep0_start_trans(dwc, 0);
|
||||
ret = dwc3_ep0_start_trans(dep);
|
||||
WARN_ON(ret < 0);
|
||||
}
|
||||
|
||||
|
|
@ -794,7 +796,7 @@ static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
|
|||
static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,
|
||||
const struct dwc3_event_depevt *event)
|
||||
{
|
||||
struct usb_ctrlrequest *ctrl = dwc->ctrl_req;
|
||||
struct usb_ctrlrequest *ctrl = (void *) dwc->ep0_trb;
|
||||
int ret = -EINVAL;
|
||||
u32 len;
|
||||
|
||||
|
|
@ -834,7 +836,6 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
|
|||
struct usb_request *ur;
|
||||
struct dwc3_trb *trb;
|
||||
struct dwc3_ep *ep0;
|
||||
unsigned transfer_size = 0;
|
||||
unsigned maxp;
|
||||
unsigned remaining_ur_length;
|
||||
void *buf;
|
||||
|
|
@ -847,9 +848,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
|
|||
ep0 = dwc->eps[0];
|
||||
|
||||
dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS;
|
||||
|
||||
trb = dwc->ep0_trb;
|
||||
|
||||
trace_dwc3_complete_trb(ep0, trb);
|
||||
|
||||
r = next_request(&ep0->pending_list);
|
||||
|
|
@ -870,58 +869,23 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
|
|||
remaining_ur_length = ur->length;
|
||||
|
||||
length = trb->size & DWC3_TRB_SIZE_MASK;
|
||||
|
||||
maxp = ep0->endpoint.maxpacket;
|
||||
|
||||
if (dwc->ep0_bounced) {
|
||||
/*
|
||||
* Handle the first TRB before handling the bounce buffer if
|
||||
* the request length is greater than the bounce buffer size
|
||||
*/
|
||||
if (ur->length > DWC3_EP0_BOUNCE_SIZE) {
|
||||
transfer_size = ALIGN(ur->length - maxp, maxp);
|
||||
transferred = transfer_size - length;
|
||||
buf = (u8 *)buf + transferred;
|
||||
ur->actual += transferred;
|
||||
remaining_ur_length -= transferred;
|
||||
|
||||
trb++;
|
||||
length = trb->size & DWC3_TRB_SIZE_MASK;
|
||||
|
||||
ep0->trb_enqueue = 0;
|
||||
}
|
||||
|
||||
transfer_size = roundup((ur->length - transfer_size),
|
||||
maxp);
|
||||
|
||||
transferred = min_t(u32, remaining_ur_length,
|
||||
transfer_size - length);
|
||||
memcpy(buf, dwc->ep0_bounce, transferred);
|
||||
} else {
|
||||
transferred = ur->length - length;
|
||||
}
|
||||
|
||||
transferred = ur->length - length;
|
||||
ur->actual += transferred;
|
||||
|
||||
if ((epnum & 1) && ur->actual < ur->length) {
|
||||
/* for some reason we did not get everything out */
|
||||
|
||||
dwc3_ep0_stall_and_restart(dwc);
|
||||
} else {
|
||||
dwc3_gadget_giveback(ep0, r, 0);
|
||||
|
||||
if (IS_ALIGNED(ur->length, ep0->endpoint.maxpacket) &&
|
||||
ur->length && ur->zero) {
|
||||
int ret;
|
||||
|
||||
dwc->ep0_next_event = DWC3_EP0_COMPLETE;
|
||||
|
||||
dwc3_ep0_prepare_one_trb(dwc, epnum, dwc->ctrl_req_addr,
|
||||
0, DWC3_TRBCTL_CONTROL_DATA, false);
|
||||
ret = dwc3_ep0_start_trans(dwc, epnum);
|
||||
WARN_ON(ret < 0);
|
||||
}
|
||||
if ((IS_ALIGNED(ur->length, ep0->endpoint.maxpacket) &&
|
||||
ur->length && ur->zero) || dwc->ep0_bounced) {
|
||||
trb++;
|
||||
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
|
||||
trace_dwc3_complete_trb(ep0, trb);
|
||||
ep0->trb_enqueue = 0;
|
||||
dwc->ep0_bounced = false;
|
||||
}
|
||||
|
||||
if ((epnum & 1) && ur->actual < ur->length)
|
||||
dwc3_ep0_stall_and_restart(dwc);
|
||||
else
|
||||
dwc3_gadget_giveback(ep0, r, 0);
|
||||
}
|
||||
|
||||
static void dwc3_ep0_complete_status(struct dwc3 *dwc,
|
||||
|
|
@ -997,14 +961,13 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
|
|||
req->direction = !!dep->number;
|
||||
|
||||
if (req->request.length == 0) {
|
||||
dwc3_ep0_prepare_one_trb(dwc, dep->number,
|
||||
dwc->ctrl_req_addr, 0,
|
||||
dwc3_ep0_prepare_one_trb(dep, dwc->ep0_trb_addr, 0,
|
||||
DWC3_TRBCTL_CONTROL_DATA, false);
|
||||
ret = dwc3_ep0_start_trans(dwc, dep->number);
|
||||
ret = dwc3_ep0_start_trans(dep);
|
||||
} else if (!IS_ALIGNED(req->request.length, dep->endpoint.maxpacket)
|
||||
&& (dep->number == 0)) {
|
||||
u32 transfer_size = 0;
|
||||
u32 maxpacket;
|
||||
u32 rem;
|
||||
|
||||
ret = usb_gadget_map_request_by_dev(dwc->sysdev,
|
||||
&req->request, dep->number);
|
||||
|
|
@ -1012,36 +975,55 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
|
|||
return;
|
||||
|
||||
maxpacket = dep->endpoint.maxpacket;
|
||||
|
||||
if (req->request.length > DWC3_EP0_BOUNCE_SIZE) {
|
||||
transfer_size = ALIGN(req->request.length - maxpacket,
|
||||
maxpacket);
|
||||
dwc3_ep0_prepare_one_trb(dwc, dep->number,
|
||||
req->request.dma,
|
||||
transfer_size,
|
||||
DWC3_TRBCTL_CONTROL_DATA,
|
||||
true);
|
||||
}
|
||||
|
||||
transfer_size = roundup((req->request.length - transfer_size),
|
||||
maxpacket);
|
||||
|
||||
rem = req->request.length % maxpacket;
|
||||
dwc->ep0_bounced = true;
|
||||
|
||||
dwc3_ep0_prepare_one_trb(dwc, dep->number,
|
||||
dwc->ep0_bounce_addr, transfer_size,
|
||||
DWC3_TRBCTL_CONTROL_DATA, false);
|
||||
ret = dwc3_ep0_start_trans(dwc, dep->number);
|
||||
/* prepare normal TRB */
|
||||
dwc3_ep0_prepare_one_trb(dep, req->request.dma,
|
||||
req->request.length,
|
||||
DWC3_TRBCTL_CONTROL_DATA,
|
||||
true);
|
||||
|
||||
/* Now prepare one extra TRB to align transfer size */
|
||||
dwc3_ep0_prepare_one_trb(dep, dwc->bounce_addr,
|
||||
maxpacket - rem,
|
||||
DWC3_TRBCTL_CONTROL_DATA,
|
||||
false);
|
||||
ret = dwc3_ep0_start_trans(dep);
|
||||
} else if (IS_ALIGNED(req->request.length, dep->endpoint.maxpacket) &&
|
||||
req->request.length && req->request.zero) {
|
||||
u32 maxpacket;
|
||||
u32 rem;
|
||||
|
||||
ret = usb_gadget_map_request_by_dev(dwc->sysdev,
|
||||
&req->request, dep->number);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
maxpacket = dep->endpoint.maxpacket;
|
||||
rem = req->request.length % maxpacket;
|
||||
|
||||
/* prepare normal TRB */
|
||||
dwc3_ep0_prepare_one_trb(dep, req->request.dma,
|
||||
req->request.length,
|
||||
DWC3_TRBCTL_CONTROL_DATA,
|
||||
true);
|
||||
|
||||
/* Now prepare one extra TRB to align transfer size */
|
||||
dwc3_ep0_prepare_one_trb(dep, dwc->bounce_addr,
|
||||
0, DWC3_TRBCTL_CONTROL_DATA,
|
||||
false);
|
||||
ret = dwc3_ep0_start_trans(dep);
|
||||
} else {
|
||||
ret = usb_gadget_map_request_by_dev(dwc->sysdev,
|
||||
&req->request, dep->number);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
dwc3_ep0_prepare_one_trb(dwc, dep->number, req->request.dma,
|
||||
dwc3_ep0_prepare_one_trb(dep, req->request.dma,
|
||||
req->request.length, DWC3_TRBCTL_CONTROL_DATA,
|
||||
false);
|
||||
ret = dwc3_ep0_start_trans(dwc, dep->number);
|
||||
ret = dwc3_ep0_start_trans(dep);
|
||||
}
|
||||
|
||||
WARN_ON(ret < 0);
|
||||
|
|
@ -1055,9 +1037,8 @@ static int dwc3_ep0_start_control_status(struct dwc3_ep *dep)
|
|||
type = dwc->three_stage_setup ? DWC3_TRBCTL_CONTROL_STATUS3
|
||||
: DWC3_TRBCTL_CONTROL_STATUS2;
|
||||
|
||||
dwc3_ep0_prepare_one_trb(dwc, dep->number,
|
||||
dwc->ctrl_req_addr, 0, type, false);
|
||||
return dwc3_ep0_start_trans(dwc, dep->number);
|
||||
dwc3_ep0_prepare_one_trb(dep, dwc->ep0_trb_addr, 0, type, false);
|
||||
return dwc3_ep0_start_trans(dep);
|
||||
}
|
||||
|
||||
static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep)
|
||||
|
|
|
|||
|
|
@ -171,7 +171,6 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
|
|||
int status)
|
||||
{
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
unsigned int unmap_after_complete = false;
|
||||
|
||||
req->started = false;
|
||||
list_del(&req->list);
|
||||
|
|
@ -181,19 +180,8 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
|
|||
if (req->request.status == -EINPROGRESS)
|
||||
req->request.status = status;
|
||||
|
||||
/*
|
||||
* NOTICE we don't want to unmap before calling ->complete() if we're
|
||||
* dealing with a bounced ep0 request. If we unmap it here, we would end
|
||||
* up overwritting the contents of req->buf and this could confuse the
|
||||
* gadget driver.
|
||||
*/
|
||||
if (dwc->ep0_bounced && dep->number <= 1) {
|
||||
dwc->ep0_bounced = false;
|
||||
unmap_after_complete = true;
|
||||
} else {
|
||||
usb_gadget_unmap_request_by_dev(dwc->sysdev,
|
||||
&req->request, req->direction);
|
||||
}
|
||||
usb_gadget_unmap_request_by_dev(dwc->sysdev,
|
||||
&req->request, req->direction);
|
||||
|
||||
trace_dwc3_gadget_giveback(req);
|
||||
|
||||
|
|
@ -201,10 +189,6 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
|
|||
usb_gadget_giveback_request(&dep->endpoint, &req->request);
|
||||
spin_lock(&dwc->lock);
|
||||
|
||||
if (unmap_after_complete)
|
||||
usb_gadget_unmap_request_by_dev(dwc->sysdev,
|
||||
&req->request, req->direction);
|
||||
|
||||
if (dep->number > 1)
|
||||
pm_runtime_put(dwc->dev);
|
||||
}
|
||||
|
|
@ -1060,6 +1044,22 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep,
|
|||
false, 0, req->request.stream_id,
|
||||
req->request.short_not_ok,
|
||||
req->request.no_interrupt);
|
||||
} else if (req->request.zero && req->request.length &&
|
||||
(IS_ALIGNED(req->request.length,dep->endpoint.maxpacket))) {
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
struct dwc3_trb *trb;
|
||||
|
||||
req->zero = true;
|
||||
|
||||
/* prepare normal TRB */
|
||||
dwc3_prepare_one_trb(dep, req, true, 0);
|
||||
|
||||
/* Now prepare one extra TRB to handle ZLP */
|
||||
trb = &dep->trb_pool[dep->trb_enqueue];
|
||||
__dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr, 0,
|
||||
false, 0, req->request.stream_id,
|
||||
req->request.short_not_ok,
|
||||
req->request.no_interrupt);
|
||||
} else {
|
||||
dwc3_prepare_one_trb(dep, req, false, 0);
|
||||
}
|
||||
|
|
@ -1184,8 +1184,11 @@ static void __dwc3_gadget_start_isoc(struct dwc3 *dwc,
|
|||
return;
|
||||
}
|
||||
|
||||
/* 4 micro frames in the future */
|
||||
uf = cur_uf + dep->interval * 4;
|
||||
/*
|
||||
* Schedule the first trb for one interval in the future or at
|
||||
* least 4 microframes.
|
||||
*/
|
||||
uf = cur_uf + max_t(u32, 4, dep->interval);
|
||||
|
||||
__dwc3_gadget_kick_transfer(dep, uf);
|
||||
}
|
||||
|
|
@ -1272,31 +1275,6 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void __dwc3_gadget_ep_zlp_complete(struct usb_ep *ep,
|
||||
struct usb_request *request)
|
||||
{
|
||||
dwc3_gadget_ep_free_request(ep, request);
|
||||
}
|
||||
|
||||
static int __dwc3_gadget_ep_queue_zlp(struct dwc3 *dwc, struct dwc3_ep *dep)
|
||||
{
|
||||
struct dwc3_request *req;
|
||||
struct usb_request *request;
|
||||
struct usb_ep *ep = &dep->endpoint;
|
||||
|
||||
request = dwc3_gadget_ep_alloc_request(ep, GFP_ATOMIC);
|
||||
if (!request)
|
||||
return -ENOMEM;
|
||||
|
||||
request->length = 0;
|
||||
request->buf = dwc->zlp_buf;
|
||||
request->complete = __dwc3_gadget_ep_zlp_complete;
|
||||
|
||||
req = to_dwc3_request(request);
|
||||
|
||||
return __dwc3_gadget_ep_queue(dep, req);
|
||||
}
|
||||
|
||||
static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
|
||||
gfp_t gfp_flags)
|
||||
{
|
||||
|
|
@ -1310,17 +1288,6 @@ static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
|
|||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
ret = __dwc3_gadget_ep_queue(dep, req);
|
||||
|
||||
/*
|
||||
* Okay, here's the thing, if gadget driver has requested for a ZLP by
|
||||
* setting request->zero, instead of doing magic, we will just queue an
|
||||
* extra usb_request ourselves so that it gets handled the same way as
|
||||
* any other request.
|
||||
*/
|
||||
if (ret == 0 && request->zero && request->length &&
|
||||
(request->length % ep->maxpacket == 0))
|
||||
ret = __dwc3_gadget_ep_queue_zlp(dwc, dep);
|
||||
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
return ret;
|
||||
|
|
@ -1400,7 +1367,7 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
|
|||
dwc3_ep_inc_deq(dep);
|
||||
}
|
||||
|
||||
if (r->unaligned) {
|
||||
if (r->unaligned || r->zero) {
|
||||
trb = r->trb + r->num_pending_sgs + 1;
|
||||
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
|
||||
dwc3_ep_inc_deq(dep);
|
||||
|
|
@ -1411,7 +1378,7 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
|
|||
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
|
||||
dwc3_ep_inc_deq(dep);
|
||||
|
||||
if (r->unaligned) {
|
||||
if (r->unaligned || r->zero) {
|
||||
trb = r->trb + 1;
|
||||
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
|
||||
dwc3_ep_inc_deq(dep);
|
||||
|
|
@ -2006,14 +1973,15 @@ static const struct usb_gadget_ops dwc3_gadget_ops = {
|
|||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
|
||||
u8 num, u32 direction)
|
||||
static int dwc3_gadget_init_endpoints(struct dwc3 *dwc, u8 num)
|
||||
{
|
||||
struct dwc3_ep *dep;
|
||||
u8 i;
|
||||
u8 epnum;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
u8 epnum = (i << 1) | (direction ? 1 : 0);
|
||||
INIT_LIST_HEAD(&dwc->gadget.ep_list);
|
||||
|
||||
for (epnum = 0; epnum < num; epnum++) {
|
||||
bool direction = epnum & 1;
|
||||
|
||||
dep = kzalloc(sizeof(*dep), GFP_KERNEL);
|
||||
if (!dep)
|
||||
|
|
@ -2021,12 +1989,12 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
|
|||
|
||||
dep->dwc = dwc;
|
||||
dep->number = epnum;
|
||||
dep->direction = !!direction;
|
||||
dep->direction = direction;
|
||||
dep->regs = dwc->regs + DWC3_DEP_BASE(epnum);
|
||||
dwc->eps[epnum] = dep;
|
||||
|
||||
snprintf(dep->name, sizeof(dep->name), "ep%d%s", epnum >> 1,
|
||||
(epnum & 1) ? "in" : "out");
|
||||
direction ? "in" : "out");
|
||||
|
||||
dep->endpoint.name = dep->name;
|
||||
|
||||
|
|
@ -2053,7 +2021,7 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
|
|||
/* MDWIDTH is represented in bits, we need it in bytes */
|
||||
mdwidth /= 8;
|
||||
|
||||
size = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(i));
|
||||
size = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(epnum >> 1));
|
||||
size = DWC3_GTXFIFOSIZ_TXFDEF(size);
|
||||
|
||||
/* FIFO Depth is in MDWDITH bytes. Multiply */
|
||||
|
|
@ -2103,7 +2071,7 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
|
|||
dep->endpoint.caps.type_int = true;
|
||||
}
|
||||
|
||||
dep->endpoint.caps.dir_in = !!direction;
|
||||
dep->endpoint.caps.dir_in = direction;
|
||||
dep->endpoint.caps.dir_out = !direction;
|
||||
|
||||
INIT_LIST_HEAD(&dep->pending_list);
|
||||
|
|
@ -2113,27 +2081,6 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_gadget_init_endpoints(struct dwc3 *dwc)
|
||||
{
|
||||
int ret;
|
||||
|
||||
INIT_LIST_HEAD(&dwc->gadget.ep_list);
|
||||
|
||||
ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_out_eps, 0);
|
||||
if (ret < 0) {
|
||||
dev_err(dwc->dev, "failed to initialize OUT endpoints\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_in_eps, 1);
|
||||
if (ret < 0) {
|
||||
dev_err(dwc->dev, "failed to initialize IN endpoints\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dwc3_gadget_free_endpoints(struct dwc3 *dwc)
|
||||
{
|
||||
struct dwc3_ep *dep;
|
||||
|
|
@ -2197,7 +2144,7 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep,
|
|||
* with one TRB pending in the ring. We need to manually clear HWO bit
|
||||
* from that TRB.
|
||||
*/
|
||||
if (req->unaligned && (trb->ctrl & DWC3_TRB_CTRL_HWO)) {
|
||||
if ((req->zero || req->unaligned) && (trb->ctrl & DWC3_TRB_CTRL_HWO)) {
|
||||
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -2291,11 +2238,12 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
|
|||
event, status, chain);
|
||||
}
|
||||
|
||||
if (req->unaligned) {
|
||||
if (req->unaligned || req->zero) {
|
||||
trb = &dep->trb_pool[dep->trb_dequeue];
|
||||
ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb,
|
||||
event, status, false);
|
||||
req->unaligned = false;
|
||||
req->zero = false;
|
||||
}
|
||||
|
||||
req->request.actual = length - req->remaining;
|
||||
|
|
@ -3161,49 +3109,26 @@ int dwc3_gadget_init(struct dwc3 *dwc)
|
|||
|
||||
dwc->irq_gadget = irq;
|
||||
|
||||
dwc->ctrl_req = dma_alloc_coherent(dwc->sysdev, sizeof(*dwc->ctrl_req),
|
||||
&dwc->ctrl_req_addr, GFP_KERNEL);
|
||||
if (!dwc->ctrl_req) {
|
||||
dev_err(dwc->dev, "failed to allocate ctrl request\n");
|
||||
ret = -ENOMEM;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
dwc->ep0_trb = dma_alloc_coherent(dwc->sysdev,
|
||||
sizeof(*dwc->ep0_trb) * 2,
|
||||
&dwc->ep0_trb_addr, GFP_KERNEL);
|
||||
if (!dwc->ep0_trb) {
|
||||
dev_err(dwc->dev, "failed to allocate ep0 trb\n");
|
||||
ret = -ENOMEM;
|
||||
goto err1;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
dwc->setup_buf = kzalloc(DWC3_EP0_BOUNCE_SIZE, GFP_KERNEL);
|
||||
dwc->setup_buf = kzalloc(DWC3_EP0_SETUP_SIZE, GFP_KERNEL);
|
||||
if (!dwc->setup_buf) {
|
||||
ret = -ENOMEM;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
dwc->ep0_bounce = dma_alloc_coherent(dwc->sysdev,
|
||||
DWC3_EP0_BOUNCE_SIZE, &dwc->ep0_bounce_addr,
|
||||
GFP_KERNEL);
|
||||
if (!dwc->ep0_bounce) {
|
||||
dev_err(dwc->dev, "failed to allocate ep0 bounce buffer\n");
|
||||
ret = -ENOMEM;
|
||||
goto err3;
|
||||
}
|
||||
|
||||
dwc->zlp_buf = kzalloc(DWC3_ZLP_BUF_SIZE, GFP_KERNEL);
|
||||
if (!dwc->zlp_buf) {
|
||||
ret = -ENOMEM;
|
||||
goto err4;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
dwc->bounce = dma_alloc_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE,
|
||||
&dwc->bounce_addr, GFP_KERNEL);
|
||||
if (!dwc->bounce) {
|
||||
ret = -ENOMEM;
|
||||
goto err5;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
init_completion(&dwc->ep0_in_setup);
|
||||
|
|
@ -3241,39 +3166,31 @@ int dwc3_gadget_init(struct dwc3 *dwc)
|
|||
* sure we're starting from a well known location.
|
||||
*/
|
||||
|
||||
ret = dwc3_gadget_init_endpoints(dwc);
|
||||
ret = dwc3_gadget_init_endpoints(dwc, dwc->num_eps);
|
||||
if (ret)
|
||||
goto err6;
|
||||
goto err3;
|
||||
|
||||
ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget);
|
||||
if (ret) {
|
||||
dev_err(dwc->dev, "failed to register udc\n");
|
||||
goto err6;
|
||||
goto err4;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err6:
|
||||
dma_free_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE, dwc->bounce,
|
||||
dwc->bounce_addr);
|
||||
|
||||
err5:
|
||||
kfree(dwc->zlp_buf);
|
||||
|
||||
err4:
|
||||
dwc3_gadget_free_endpoints(dwc);
|
||||
dma_free_coherent(dwc->sysdev, DWC3_EP0_BOUNCE_SIZE,
|
||||
dwc->ep0_bounce, dwc->ep0_bounce_addr);
|
||||
|
||||
err3:
|
||||
kfree(dwc->setup_buf);
|
||||
dma_free_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE, dwc->bounce,
|
||||
dwc->bounce_addr);
|
||||
|
||||
err2:
|
||||
dma_free_coherent(dwc->sysdev, sizeof(*dwc->ep0_trb) * 2,
|
||||
dwc->ep0_trb, dwc->ep0_trb_addr);
|
||||
kfree(dwc->setup_buf);
|
||||
|
||||
err1:
|
||||
dma_free_coherent(dwc->sysdev, sizeof(*dwc->ctrl_req),
|
||||
dwc->ctrl_req, dwc->ctrl_req_addr);
|
||||
dma_free_coherent(dwc->sysdev, sizeof(*dwc->ep0_trb) * 2,
|
||||
dwc->ep0_trb, dwc->ep0_trb_addr);
|
||||
|
||||
err0:
|
||||
return ret;
|
||||
|
|
@ -3284,22 +3201,12 @@ err0:
|
|||
void dwc3_gadget_exit(struct dwc3 *dwc)
|
||||
{
|
||||
usb_del_gadget_udc(&dwc->gadget);
|
||||
|
||||
dwc3_gadget_free_endpoints(dwc);
|
||||
|
||||
dma_free_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE, dwc->bounce,
|
||||
dwc->bounce_addr);
|
||||
dma_free_coherent(dwc->sysdev, DWC3_EP0_BOUNCE_SIZE,
|
||||
dwc->ep0_bounce, dwc->ep0_bounce_addr);
|
||||
|
||||
dwc->bounce_addr);
|
||||
kfree(dwc->setup_buf);
|
||||
kfree(dwc->zlp_buf);
|
||||
|
||||
dma_free_coherent(dwc->sysdev, sizeof(*dwc->ep0_trb) * 2,
|
||||
dwc->ep0_trb, dwc->ep0_trb_addr);
|
||||
|
||||
dma_free_coherent(dwc->sysdev, sizeof(*dwc->ctrl_req),
|
||||
dwc->ctrl_req, dwc->ctrl_req_addr);
|
||||
dwc->ep0_trb, dwc->ep0_trb_addr);
|
||||
}
|
||||
|
||||
int dwc3_gadget_suspend(struct dwc3 *dwc)
|
||||
|
|
|
|||
|
|
@ -29,16 +29,16 @@ struct dwc3;
|
|||
|
||||
/* DEPCFG parameter 1 */
|
||||
#define DWC3_DEPCFG_INT_NUM(n) (((n) & 0x1f) << 0)
|
||||
#define DWC3_DEPCFG_XFER_COMPLETE_EN (1 << 8)
|
||||
#define DWC3_DEPCFG_XFER_IN_PROGRESS_EN (1 << 9)
|
||||
#define DWC3_DEPCFG_XFER_NOT_READY_EN (1 << 10)
|
||||
#define DWC3_DEPCFG_FIFO_ERROR_EN (1 << 11)
|
||||
#define DWC3_DEPCFG_STREAM_EVENT_EN (1 << 13)
|
||||
#define DWC3_DEPCFG_XFER_COMPLETE_EN BIT(8)
|
||||
#define DWC3_DEPCFG_XFER_IN_PROGRESS_EN BIT(9)
|
||||
#define DWC3_DEPCFG_XFER_NOT_READY_EN BIT(10)
|
||||
#define DWC3_DEPCFG_FIFO_ERROR_EN BIT(11)
|
||||
#define DWC3_DEPCFG_STREAM_EVENT_EN BIT(12)
|
||||
#define DWC3_DEPCFG_BINTERVAL_M1(n) (((n) & 0xff) << 16)
|
||||
#define DWC3_DEPCFG_STREAM_CAPABLE (1 << 24)
|
||||
#define DWC3_DEPCFG_STREAM_CAPABLE BIT(24)
|
||||
#define DWC3_DEPCFG_EP_NUMBER(n) (((n) & 0x1f) << 25)
|
||||
#define DWC3_DEPCFG_BULK_BASED (1 << 30)
|
||||
#define DWC3_DEPCFG_FIFO_BASED (1 << 31)
|
||||
#define DWC3_DEPCFG_BULK_BASED BIT(30)
|
||||
#define DWC3_DEPCFG_FIFO_BASED BIT(31)
|
||||
|
||||
/* DEPCFG parameter 0 */
|
||||
#define DWC3_DEPCFG_EP_TYPE(n) (((n) & 0x3) << 1)
|
||||
|
|
@ -47,10 +47,10 @@ struct dwc3;
|
|||
#define DWC3_DEPCFG_BURST_SIZE(n) (((n) & 0xf) << 22)
|
||||
#define DWC3_DEPCFG_DATA_SEQ_NUM(n) ((n) << 26)
|
||||
/* This applies for core versions earlier than 1.94a */
|
||||
#define DWC3_DEPCFG_IGN_SEQ_NUM (1 << 31)
|
||||
#define DWC3_DEPCFG_IGN_SEQ_NUM BIT(31)
|
||||
/* These apply for core versions 1.94a and later */
|
||||
#define DWC3_DEPCFG_ACTION_INIT (0 << 30)
|
||||
#define DWC3_DEPCFG_ACTION_RESTORE (1 << 30)
|
||||
#define DWC3_DEPCFG_ACTION_RESTORE BIT(30)
|
||||
#define DWC3_DEPCFG_ACTION_MODIFY (2 << 30)
|
||||
|
||||
/* DEPXFERCFG parameter 0 */
|
||||
|
|
|
|||
|
|
@ -27,31 +27,6 @@
|
|||
#include "core.h"
|
||||
#include "debug.h"
|
||||
|
||||
DECLARE_EVENT_CLASS(dwc3_log_msg,
|
||||
TP_PROTO(struct va_format *vaf),
|
||||
TP_ARGS(vaf),
|
||||
TP_STRUCT__entry(__dynamic_array(char, msg, DWC3_MSG_MAX)),
|
||||
TP_fast_assign(
|
||||
vsnprintf(__get_str(msg), DWC3_MSG_MAX, vaf->fmt, *vaf->va);
|
||||
),
|
||||
TP_printk("%s", __get_str(msg))
|
||||
);
|
||||
|
||||
DEFINE_EVENT(dwc3_log_msg, dwc3_gadget,
|
||||
TP_PROTO(struct va_format *vaf),
|
||||
TP_ARGS(vaf)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(dwc3_log_msg, dwc3_core,
|
||||
TP_PROTO(struct va_format *vaf),
|
||||
TP_ARGS(vaf)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(dwc3_log_msg, dwc3_ep0,
|
||||
TP_PROTO(struct va_format *vaf),
|
||||
TP_ARGS(vaf)
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(dwc3_log_io,
|
||||
TP_PROTO(void *base, u32 offset, u32 value),
|
||||
TP_ARGS(base, offset, value),
|
||||
|
|
@ -198,7 +173,7 @@ DECLARE_EVENT_CLASS(dwc3_log_generic_cmd,
|
|||
__entry->param = param;
|
||||
__entry->status = status;
|
||||
),
|
||||
TP_printk("cmd '%s' [%d] param %08x --> status: %s",
|
||||
TP_printk("cmd '%s' [%x] param %08x --> status: %s",
|
||||
dwc3_gadget_generic_cmd_string(__entry->cmd),
|
||||
__entry->cmd, __entry->param,
|
||||
dwc3_gadget_generic_cmd_status_string(__entry->status)
|
||||
|
|
@ -298,36 +273,7 @@ DECLARE_EVENT_CLASS(dwc3_log_trb,
|
|||
__entry->ctrl & DWC3_TRB_CTRL_CSP ? 'S' : 's',
|
||||
__entry->ctrl & DWC3_TRB_CTRL_ISP_IMI ? 'S' : 's',
|
||||
__entry->ctrl & DWC3_TRB_CTRL_IOC ? 'C' : 'c',
|
||||
({char *s;
|
||||
switch (__entry->ctrl & 0x3f0) {
|
||||
case DWC3_TRBCTL_NORMAL:
|
||||
s = "normal";
|
||||
break;
|
||||
case DWC3_TRBCTL_CONTROL_SETUP:
|
||||
s = "setup";
|
||||
break;
|
||||
case DWC3_TRBCTL_CONTROL_STATUS2:
|
||||
s = "status2";
|
||||
break;
|
||||
case DWC3_TRBCTL_CONTROL_STATUS3:
|
||||
s = "status3";
|
||||
break;
|
||||
case DWC3_TRBCTL_CONTROL_DATA:
|
||||
s = "data";
|
||||
break;
|
||||
case DWC3_TRBCTL_ISOCHRONOUS_FIRST:
|
||||
s = "isoc-first";
|
||||
break;
|
||||
case DWC3_TRBCTL_ISOCHRONOUS:
|
||||
s = "isoc";
|
||||
break;
|
||||
case DWC3_TRBCTL_LINK_TRB:
|
||||
s = "link";
|
||||
break;
|
||||
default:
|
||||
s = "UNKNOWN";
|
||||
break;
|
||||
} s; })
|
||||
dwc3_trb_type_string(DWC3_TRBCTL_TYPE(__entry->ctrl))
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ config USB_F_TCM
|
|||
# this first set of drivers all depend on bulk-capable hardware.
|
||||
|
||||
config USB_CONFIGFS
|
||||
tristate "USB functions configurable through configfs"
|
||||
tristate "USB Gadget functions configurable through configfs"
|
||||
select USB_LIBCOMPOSITE
|
||||
help
|
||||
A Linux USB "gadget" can be set up through configfs.
|
||||
|
|
@ -458,8 +458,9 @@ config USB_CONFIGFS_F_TCM
|
|||
UAS utilizes the USB 3.0 feature called streams support.
|
||||
|
||||
choice
|
||||
tristate "USB Gadget Drivers"
|
||||
tristate "USB Gadget precomposed configurations"
|
||||
default USB_ETH
|
||||
optional
|
||||
help
|
||||
A Linux "Gadget Driver" talks to the USB Peripheral Controller
|
||||
driver through the abstract "gadget" API. Some other operating
|
||||
|
|
@ -476,6 +477,12 @@ choice
|
|||
not be able work with that controller, or might need to implement
|
||||
a less common variant of a device class protocol.
|
||||
|
||||
The available choices each represent a single precomposed USB
|
||||
gadget configuration. In the device model, each option contains
|
||||
both the device instantiation as a child for a USB gadget
|
||||
controller, and the relevant drivers for each function declared
|
||||
by the device.
|
||||
|
||||
source "drivers/usb/gadget/legacy/Kconfig"
|
||||
|
||||
endchoice
|
||||
|
|
|
|||
|
|
@ -246,7 +246,6 @@ EXPORT_SYMBOL_GPL(ffs_lock);
|
|||
|
||||
static struct ffs_dev *_ffs_find_dev(const char *name);
|
||||
static struct ffs_dev *_ffs_alloc_dev(void);
|
||||
static int _ffs_name_dev(struct ffs_dev *dev, const char *name);
|
||||
static void _ffs_free_dev(struct ffs_dev *dev);
|
||||
static void *ffs_acquire_dev(const char *dev_name);
|
||||
static void ffs_release_dev(struct ffs_data *ffs_data);
|
||||
|
|
@ -1571,14 +1570,14 @@ static void ffs_data_get(struct ffs_data *ffs)
|
|||
{
|
||||
ENTER();
|
||||
|
||||
atomic_inc(&ffs->ref);
|
||||
refcount_inc(&ffs->ref);
|
||||
}
|
||||
|
||||
static void ffs_data_opened(struct ffs_data *ffs)
|
||||
{
|
||||
ENTER();
|
||||
|
||||
atomic_inc(&ffs->ref);
|
||||
refcount_inc(&ffs->ref);
|
||||
if (atomic_add_return(1, &ffs->opened) == 1 &&
|
||||
ffs->state == FFS_DEACTIVATED) {
|
||||
ffs->state = FFS_CLOSING;
|
||||
|
|
@ -1590,7 +1589,7 @@ static void ffs_data_put(struct ffs_data *ffs)
|
|||
{
|
||||
ENTER();
|
||||
|
||||
if (unlikely(atomic_dec_and_test(&ffs->ref))) {
|
||||
if (unlikely(refcount_dec_and_test(&ffs->ref))) {
|
||||
pr_info("%s(): freeing\n", __func__);
|
||||
ffs_data_clear(ffs);
|
||||
BUG_ON(waitqueue_active(&ffs->ev.waitq) ||
|
||||
|
|
@ -1635,7 +1634,7 @@ static struct ffs_data *ffs_data_new(void)
|
|||
|
||||
ENTER();
|
||||
|
||||
atomic_set(&ffs->ref, 1);
|
||||
refcount_set(&ffs->ref, 1);
|
||||
atomic_set(&ffs->opened, 0);
|
||||
ffs->state = FFS_READ_DESCRIPTORS;
|
||||
mutex_init(&ffs->mutex);
|
||||
|
|
@ -3302,9 +3301,10 @@ static struct ffs_dev *_ffs_do_find_dev(const char *name)
|
|||
{
|
||||
struct ffs_dev *dev;
|
||||
|
||||
if (!name)
|
||||
return NULL;
|
||||
|
||||
list_for_each_entry(dev, &ffs_devices, entry) {
|
||||
if (!dev->name || !name)
|
||||
continue;
|
||||
if (strcmp(dev->name, name) == 0)
|
||||
return dev;
|
||||
}
|
||||
|
|
@ -3380,42 +3380,11 @@ static void ffs_free_inst(struct usb_function_instance *f)
|
|||
kfree(opts);
|
||||
}
|
||||
|
||||
#define MAX_INST_NAME_LEN 40
|
||||
|
||||
static int ffs_set_inst_name(struct usb_function_instance *fi, const char *name)
|
||||
{
|
||||
struct f_fs_opts *opts;
|
||||
char *ptr;
|
||||
const char *tmp;
|
||||
int name_len, ret;
|
||||
|
||||
name_len = strlen(name) + 1;
|
||||
if (name_len > MAX_INST_NAME_LEN)
|
||||
if (strlen(name) >= FIELD_SIZEOF(struct ffs_dev, name))
|
||||
return -ENAMETOOLONG;
|
||||
|
||||
ptr = kstrndup(name, name_len, GFP_KERNEL);
|
||||
if (!ptr)
|
||||
return -ENOMEM;
|
||||
|
||||
opts = to_f_fs_opts(fi);
|
||||
tmp = NULL;
|
||||
|
||||
ffs_dev_lock();
|
||||
|
||||
tmp = opts->dev->name_allocated ? opts->dev->name : NULL;
|
||||
ret = _ffs_name_dev(opts->dev, ptr);
|
||||
if (ret) {
|
||||
kfree(ptr);
|
||||
ffs_dev_unlock();
|
||||
return ret;
|
||||
}
|
||||
opts->dev->name_allocated = true;
|
||||
|
||||
ffs_dev_unlock();
|
||||
|
||||
kfree(tmp);
|
||||
|
||||
return 0;
|
||||
return ffs_name_dev(to_f_fs_opts(fi)->dev, name);
|
||||
}
|
||||
|
||||
static struct usb_function_instance *ffs_alloc_inst(void)
|
||||
|
|
@ -3545,32 +3514,19 @@ static struct ffs_dev *_ffs_alloc_dev(void)
|
|||
return dev;
|
||||
}
|
||||
|
||||
/*
|
||||
* ffs_lock must be taken by the caller of this function
|
||||
* The caller is responsible for "name" being available whenever f_fs needs it
|
||||
*/
|
||||
static int _ffs_name_dev(struct ffs_dev *dev, const char *name)
|
||||
{
|
||||
struct ffs_dev *existing;
|
||||
|
||||
existing = _ffs_do_find_dev(name);
|
||||
if (existing)
|
||||
return -EBUSY;
|
||||
|
||||
dev->name = name;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The caller is responsible for "name" being available whenever f_fs needs it
|
||||
*/
|
||||
int ffs_name_dev(struct ffs_dev *dev, const char *name)
|
||||
{
|
||||
int ret;
|
||||
struct ffs_dev *existing;
|
||||
int ret = 0;
|
||||
|
||||
ffs_dev_lock();
|
||||
ret = _ffs_name_dev(dev, name);
|
||||
|
||||
existing = _ffs_do_find_dev(name);
|
||||
if (!existing)
|
||||
strlcpy(dev->name, name, ARRAY_SIZE(dev->name));
|
||||
else if (existing != dev)
|
||||
ret = -EBUSY;
|
||||
|
||||
ffs_dev_unlock();
|
||||
|
||||
return ret;
|
||||
|
|
@ -3600,8 +3556,6 @@ EXPORT_SYMBOL_GPL(ffs_single_dev);
|
|||
static void _ffs_free_dev(struct ffs_dev *dev)
|
||||
{
|
||||
list_del(&dev->entry);
|
||||
if (dev->name_allocated)
|
||||
kfree(dev->name);
|
||||
|
||||
/* Clear the private_data pointer to stop incorrect dev access */
|
||||
if (dev->ffs_data)
|
||||
|
|
|
|||
|
|
@ -178,6 +178,7 @@ static void rx_complete(struct usb_ep *ep, struct usb_request *req);
|
|||
static int
|
||||
rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
|
||||
{
|
||||
struct usb_gadget *g = dev->gadget;
|
||||
struct sk_buff *skb;
|
||||
int retval = -ENOMEM;
|
||||
size_t size = 0;
|
||||
|
|
@ -209,8 +210,11 @@ rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
|
|||
*/
|
||||
size += sizeof(struct ethhdr) + dev->net->mtu + RX_EXTRA;
|
||||
size += dev->port_usb->header_len;
|
||||
size += out->maxpacket - 1;
|
||||
size -= size % out->maxpacket;
|
||||
|
||||
if (g->quirk_ep_out_aligned_size) {
|
||||
size += out->maxpacket - 1;
|
||||
size -= size % out->maxpacket;
|
||||
}
|
||||
|
||||
if (dev->port_usb->is_fixed)
|
||||
size = max_t(size_t, size, dev->port_usb->fixed_out_len);
|
||||
|
|
@ -401,13 +405,12 @@ done:
|
|||
static void rx_fill(struct eth_dev *dev, gfp_t gfp_flags)
|
||||
{
|
||||
struct usb_request *req;
|
||||
struct usb_request *tmp;
|
||||
unsigned long flags;
|
||||
|
||||
/* fill unused rxq slots with some skb */
|
||||
spin_lock_irqsave(&dev->req_lock, flags);
|
||||
while (!list_empty(&dev->rx_reqs)) {
|
||||
req = container_of(dev->rx_reqs.next,
|
||||
struct usb_request, list);
|
||||
list_for_each_entry_safe(req, tmp, &dev->rx_reqs, list) {
|
||||
list_del_init(&req->list);
|
||||
spin_unlock_irqrestore(&dev->req_lock, flags);
|
||||
|
||||
|
|
@ -527,7 +530,7 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
|
|||
return NETDEV_TX_BUSY;
|
||||
}
|
||||
|
||||
req = container_of(dev->tx_reqs.next, struct usb_request, list);
|
||||
req = list_first_entry(&dev->tx_reqs, struct usb_request, list);
|
||||
list_del(&req->list);
|
||||
|
||||
/* temporarily stop TX queue when the freelist empties */
|
||||
|
|
@ -1122,6 +1125,7 @@ void gether_disconnect(struct gether *link)
|
|||
{
|
||||
struct eth_dev *dev = link->ioport;
|
||||
struct usb_request *req;
|
||||
struct usb_request *tmp;
|
||||
|
||||
WARN_ON(!dev);
|
||||
if (!dev)
|
||||
|
|
@ -1138,9 +1142,7 @@ void gether_disconnect(struct gether *link)
|
|||
*/
|
||||
usb_ep_disable(link->in_ep);
|
||||
spin_lock(&dev->req_lock);
|
||||
while (!list_empty(&dev->tx_reqs)) {
|
||||
req = container_of(dev->tx_reqs.next,
|
||||
struct usb_request, list);
|
||||
list_for_each_entry_safe(req, tmp, &dev->tx_reqs, list) {
|
||||
list_del(&req->list);
|
||||
|
||||
spin_unlock(&dev->req_lock);
|
||||
|
|
@ -1152,9 +1154,7 @@ void gether_disconnect(struct gether *link)
|
|||
|
||||
usb_ep_disable(link->out_ep);
|
||||
spin_lock(&dev->req_lock);
|
||||
while (!list_empty(&dev->rx_reqs)) {
|
||||
req = container_of(dev->rx_reqs.next,
|
||||
struct usb_request, list);
|
||||
list_for_each_entry_safe(req, tmp, &dev->rx_reqs, list) {
|
||||
list_del(&req->list);
|
||||
|
||||
spin_unlock(&dev->req_lock);
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/list.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/refcount.h>
|
||||
|
||||
#ifdef VERBOSE_DEBUG
|
||||
#ifndef pr_vdebug
|
||||
|
|
@ -39,15 +40,16 @@
|
|||
struct f_fs_opts;
|
||||
|
||||
struct ffs_dev {
|
||||
const char *name;
|
||||
bool name_allocated;
|
||||
bool mounted;
|
||||
bool desc_ready;
|
||||
bool single;
|
||||
struct ffs_data *ffs_data;
|
||||
struct f_fs_opts *opts;
|
||||
struct list_head entry;
|
||||
|
||||
char name[41];
|
||||
|
||||
bool mounted;
|
||||
bool desc_ready;
|
||||
bool single;
|
||||
|
||||
int (*ffs_ready_callback)(struct ffs_data *ffs);
|
||||
void (*ffs_closed_callback)(struct ffs_data *ffs);
|
||||
void *(*ffs_acquire_dev_callback)(struct ffs_dev *dev);
|
||||
|
|
@ -177,7 +179,7 @@ struct ffs_data {
|
|||
struct completion ep0req_completion; /* P: mutex */
|
||||
|
||||
/* reference counter */
|
||||
atomic_t ref;
|
||||
refcount_t ref;
|
||||
/* how many files are opened (EP0 and others) */
|
||||
atomic_t opened;
|
||||
|
||||
|
|
|
|||
|
|
@ -2125,7 +2125,7 @@ static struct configfs_item_operations uvc_item_ops = {
|
|||
.release = uvc_attr_release,
|
||||
};
|
||||
|
||||
#define UVCG_OPTS_ATTR(cname, conv, str2u, uxx, vnoc, limit) \
|
||||
#define UVCG_OPTS_ATTR(cname, aname, conv, str2u, uxx, vnoc, limit) \
|
||||
static ssize_t f_uvc_opts_##cname##_show( \
|
||||
struct config_item *item, char *page) \
|
||||
{ \
|
||||
|
|
@ -2168,16 +2168,16 @@ end: \
|
|||
return ret; \
|
||||
} \
|
||||
\
|
||||
UVC_ATTR(f_uvc_opts_, cname, aname)
|
||||
UVC_ATTR(f_uvc_opts_, cname, cname)
|
||||
|
||||
#define identity_conv(x) (x)
|
||||
|
||||
UVCG_OPTS_ATTR(streaming_interval, identity_conv, kstrtou8, u8, identity_conv,
|
||||
16);
|
||||
UVCG_OPTS_ATTR(streaming_maxpacket, le16_to_cpu, kstrtou16, u16, le16_to_cpu,
|
||||
3072);
|
||||
UVCG_OPTS_ATTR(streaming_maxburst, identity_conv, kstrtou8, u8, identity_conv,
|
||||
15);
|
||||
UVCG_OPTS_ATTR(streaming_interval, streaming_interval, identity_conv,
|
||||
kstrtou8, u8, identity_conv, 16);
|
||||
UVCG_OPTS_ATTR(streaming_maxpacket, streaming_maxpacket, le16_to_cpu,
|
||||
kstrtou16, u16, le16_to_cpu, 3072);
|
||||
UVCG_OPTS_ATTR(streaming_maxburst, streaming_maxburst, identity_conv,
|
||||
kstrtou8, u8, identity_conv, 15);
|
||||
|
||||
#undef identity_conv
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include <linux/mmu_context.h>
|
||||
#include <linux/aio.h>
|
||||
#include <linux/uio.h>
|
||||
#include <linux/refcount.h>
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/moduleparam.h>
|
||||
|
|
@ -114,7 +115,7 @@ enum ep0_state {
|
|||
|
||||
struct dev_data {
|
||||
spinlock_t lock;
|
||||
atomic_t count;
|
||||
refcount_t count;
|
||||
enum ep0_state state; /* P: lock */
|
||||
struct usb_gadgetfs_event event [N_EVENT];
|
||||
unsigned ev_next;
|
||||
|
|
@ -150,12 +151,12 @@ struct dev_data {
|
|||
|
||||
static inline void get_dev (struct dev_data *data)
|
||||
{
|
||||
atomic_inc (&data->count);
|
||||
refcount_inc (&data->count);
|
||||
}
|
||||
|
||||
static void put_dev (struct dev_data *data)
|
||||
{
|
||||
if (likely (!atomic_dec_and_test (&data->count)))
|
||||
if (likely (!refcount_dec_and_test (&data->count)))
|
||||
return;
|
||||
/* needs no more cleanup */
|
||||
BUG_ON (waitqueue_active (&data->wait));
|
||||
|
|
@ -170,7 +171,7 @@ static struct dev_data *dev_new (void)
|
|||
if (!dev)
|
||||
return NULL;
|
||||
dev->state = STATE_DEV_DISABLED;
|
||||
atomic_set (&dev->count, 1);
|
||||
refcount_set (&dev->count, 1);
|
||||
spin_lock_init (&dev->lock);
|
||||
INIT_LIST_HEAD (&dev->epfiles);
|
||||
init_waitqueue_head (&dev->wait);
|
||||
|
|
@ -190,7 +191,7 @@ enum ep_state {
|
|||
struct ep_data {
|
||||
struct mutex lock;
|
||||
enum ep_state state;
|
||||
atomic_t count;
|
||||
refcount_t count;
|
||||
struct dev_data *dev;
|
||||
/* must hold dev->lock before accessing ep or req */
|
||||
struct usb_ep *ep;
|
||||
|
|
@ -205,12 +206,12 @@ struct ep_data {
|
|||
|
||||
static inline void get_ep (struct ep_data *data)
|
||||
{
|
||||
atomic_inc (&data->count);
|
||||
refcount_inc (&data->count);
|
||||
}
|
||||
|
||||
static void put_ep (struct ep_data *data)
|
||||
{
|
||||
if (likely (!atomic_dec_and_test (&data->count)))
|
||||
if (likely (!refcount_dec_and_test (&data->count)))
|
||||
return;
|
||||
put_dev (data->dev);
|
||||
/* needs no more cleanup */
|
||||
|
|
@ -1561,7 +1562,7 @@ static int activate_ep_files (struct dev_data *dev)
|
|||
init_waitqueue_head (&data->wait);
|
||||
|
||||
strncpy (data->name, ep->name, sizeof (data->name) - 1);
|
||||
atomic_set (&data->count, 1);
|
||||
refcount_set (&data->count, 1);
|
||||
data->dev = dev;
|
||||
get_dev (dev);
|
||||
|
||||
|
|
|
|||
|
|
@ -62,8 +62,9 @@ config USB_ATMEL_USBA
|
|||
|
||||
The fifo_mode parameter is used to select endpoint allocation mode.
|
||||
fifo_mode = 0 is used to let the driver autoconfigure the endpoints.
|
||||
In this case 2 banks are allocated for isochronous endpoints and
|
||||
only one bank is allocated for the rest of the endpoints.
|
||||
In this case, for ep1 2 banks are allocated if it works in isochronous
|
||||
mode and only 1 bank otherwise. For the rest of the endpoints
|
||||
only 1 bank is allocated.
|
||||
|
||||
fifo_mode = 1 is a generic maximum fifo size (1024 bytes) configuration
|
||||
allowing the usage of ep1 - ep6
|
||||
|
|
@ -191,6 +192,7 @@ config USB_RENESAS_USBHS_UDC
|
|||
config USB_RENESAS_USB3
|
||||
tristate 'Renesas USB3.0 Peripheral controller'
|
||||
depends on ARCH_RENESAS || COMPILE_TEST
|
||||
depends on EXTCON
|
||||
help
|
||||
Renesas USB3.0 Peripheral controller is a USB peripheral controller
|
||||
that supports super, high, and full speed USB 3.0 data transfers.
|
||||
|
|
@ -253,6 +255,20 @@ config USB_MV_U3D
|
|||
MARVELL PXA2128 Processor series include a super speed USB3.0 device
|
||||
controller, which support super speed USB peripheral.
|
||||
|
||||
config USB_SNP_CORE
|
||||
depends on USB_AMD5536UDC
|
||||
tristate
|
||||
help
|
||||
This enables core driver support for Synopsys USB 2.0 Device
|
||||
controller.
|
||||
|
||||
This will be enabled when PCI or Platform driver for this UDC is
|
||||
selected. Currently, this will be enabled by USB_SNP_UDC_PLAT or
|
||||
USB_AMD5536UDC options.
|
||||
|
||||
This IP is different to the High Speed OTG IP that can be enabled
|
||||
by selecting USB_DWC2 or USB_DWC3 options.
|
||||
|
||||
#
|
||||
# Controllers available in both integrated and discrete versions
|
||||
#
|
||||
|
|
@ -277,7 +293,8 @@ source "drivers/usb/gadget/udc/bdc/Kconfig"
|
|||
|
||||
config USB_AMD5536UDC
|
||||
tristate "AMD5536 UDC"
|
||||
depends on PCI
|
||||
depends on USB_PCI
|
||||
select USB_SNP_CORE
|
||||
help
|
||||
The AMD5536 UDC is part of the AMD Geode CS5536, an x86 southbridge.
|
||||
It is a USB Highspeed DMA capable USB device controller. Beside ep0
|
||||
|
|
@ -285,6 +302,9 @@ config USB_AMD5536UDC
|
|||
The UDC port supports OTG operation, and may be used as a host port
|
||||
if it's not being used to implement peripheral or OTG roles.
|
||||
|
||||
This UDC is based on Synopsys USB device controller IP and selects
|
||||
CONFIG_USB_SNP_CORE option to build the core driver.
|
||||
|
||||
Say "y" to link the driver statically, or "m" to build a
|
||||
dynamically linked module called "amd5536udc" and force all
|
||||
gadget drivers to also be dynamically linked.
|
||||
|
|
@ -327,7 +347,7 @@ config USB_NET2272_DMA
|
|||
|
||||
config USB_NET2280
|
||||
tristate "NetChip NET228x / PLX USB3x8x"
|
||||
depends on PCI
|
||||
depends on USB_PCI
|
||||
help
|
||||
NetChip 2280 / 2282 is a PCI based USB peripheral controller which
|
||||
supports both full and high speed USB 2.0 data transfers.
|
||||
|
|
@ -352,7 +372,7 @@ config USB_NET2280
|
|||
|
||||
config USB_GOKU
|
||||
tristate "Toshiba TC86C001 'Goku-S'"
|
||||
depends on PCI
|
||||
depends on USB_PCI
|
||||
help
|
||||
The Toshiba TC86C001 is a PCI device which includes controllers
|
||||
for full speed USB devices, IDE, I2C, SIO, plus a USB host (OHCI).
|
||||
|
|
@ -366,7 +386,7 @@ config USB_GOKU
|
|||
|
||||
config USB_EG20T
|
||||
tristate "Intel QUARK X1000/EG20T PCH/LAPIS Semiconductor IOH(ML7213/ML7831) UDC"
|
||||
depends on PCI
|
||||
depends on USB_PCI
|
||||
help
|
||||
This is a USB device driver for EG20T PCH.
|
||||
EG20T PCH is the platform controller hub that is used in Intel's
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@ obj-$(CONFIG_USB_GADGET) += udc-core.o
|
|||
obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o
|
||||
obj-$(CONFIG_USB_NET2272) += net2272.o
|
||||
obj-$(CONFIG_USB_NET2280) += net2280.o
|
||||
obj-$(CONFIG_USB_AMD5536UDC) += amd5536udc.o
|
||||
obj-$(CONFIG_USB_SNP_CORE) += amd5536udc.o
|
||||
obj-$(CONFIG_USB_AMD5536UDC) += amd5536udc_pci.o
|
||||
obj-$(CONFIG_USB_PXA25X) += pxa25x_udc.o
|
||||
obj-$(CONFIG_USB_PXA27X) += pxa27x_udc.o
|
||||
obj-$(CONFIG_USB_GOKU) += goku_udc.o
|
||||
|
|
|
|||
|
|
@ -11,27 +11,15 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* The AMD5536 UDC is part of the x86 southbridge AMD Geode CS5536.
|
||||
* It is a USB Highspeed DMA capable USB device controller. Beside ep0 it
|
||||
* provides 4 IN and 4 OUT endpoints (bulk or interrupt type).
|
||||
*
|
||||
* Make sure that UDC is assigned to port 4 by BIOS settings (port can also
|
||||
* be used as host port) and UOC bits PAD_EN and APU are set (should be done
|
||||
* by BIOS init).
|
||||
*
|
||||
* UDC DMA requires 32-bit aligned buffers so DMA with gadget ether does not
|
||||
* work without updating NET_IP_ALIGN. Or PIO mode (module param "use_dma=0")
|
||||
* can be used with gadget ether.
|
||||
* This file does the core driver implementation for the UDC that is based
|
||||
* on Synopsys device controller IP (different than HS OTG IP) that is either
|
||||
* connected through PCI bus or integrated to SoC platforms.
|
||||
*/
|
||||
|
||||
/* debug control */
|
||||
/* #define UDC_VERBOSE */
|
||||
|
||||
/* Driver strings */
|
||||
#define UDC_MOD_DESCRIPTION "AMD 5536 UDC - USB Device Controller"
|
||||
#define UDC_MOD_DESCRIPTION "Synopsys USB Device Controller"
|
||||
#define UDC_DRIVER_VERSION_STRING "01.00.0206"
|
||||
|
||||
/* system */
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/kernel.h>
|
||||
|
|
@ -46,23 +34,12 @@
|
|||
#include <linux/ioctl.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/dmapool.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/prefetch.h>
|
||||
|
||||
#include <linux/moduleparam.h>
|
||||
#include <asm/byteorder.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
/* gadget stack */
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
|
||||
/* udc specific */
|
||||
#include "amd5536udc.h"
|
||||
|
||||
|
||||
static void udc_tasklet_disconnect(unsigned long);
|
||||
static void empty_req_queue(struct udc_ep *);
|
||||
static void udc_setup_endpoints(struct udc *dev);
|
||||
|
|
@ -72,7 +49,7 @@ static void udc_free_request(struct usb_ep *usbep, struct usb_request *usbreq);
|
|||
|
||||
/* description */
|
||||
static const char mod_desc[] = UDC_MOD_DESCRIPTION;
|
||||
static const char name[] = "amd5536udc";
|
||||
static const char name[] = "udc";
|
||||
|
||||
/* structure to hold endpoint function pointers */
|
||||
static const struct usb_ep_ops udc_ep_ops;
|
||||
|
|
@ -208,30 +185,11 @@ static const struct {
|
|||
#undef EP_INFO
|
||||
};
|
||||
|
||||
/* DMA usage flag */
|
||||
static bool use_dma = 1;
|
||||
/* packet per buffer dma */
|
||||
static bool use_dma_ppb = 1;
|
||||
/* with per descr. update */
|
||||
static bool use_dma_ppb_du;
|
||||
/* buffer fill mode */
|
||||
static int use_dma_bufferfill_mode;
|
||||
/* full speed only mode */
|
||||
static bool use_fullspeed;
|
||||
/* tx buffer size for high speed */
|
||||
static unsigned long hs_tx_buf = UDC_EPIN_BUFF_SIZE;
|
||||
|
||||
/* module parameters */
|
||||
module_param(use_dma, bool, S_IRUGO);
|
||||
MODULE_PARM_DESC(use_dma, "true for DMA");
|
||||
module_param(use_dma_ppb, bool, S_IRUGO);
|
||||
MODULE_PARM_DESC(use_dma_ppb, "true for DMA in packet per buffer mode");
|
||||
module_param(use_dma_ppb_du, bool, S_IRUGO);
|
||||
MODULE_PARM_DESC(use_dma_ppb_du,
|
||||
"true for DMA in packet per buffer mode with descriptor update");
|
||||
module_param(use_fullspeed, bool, S_IRUGO);
|
||||
MODULE_PARM_DESC(use_fullspeed, "true for fullspeed only");
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Prints UDC device registers and endpoint irq registers */
|
||||
static void print_regs(struct udc *dev)
|
||||
|
|
@ -267,7 +225,7 @@ static void print_regs(struct udc *dev)
|
|||
}
|
||||
|
||||
/* Masks unused interrupts */
|
||||
static int udc_mask_unused_interrupts(struct udc *dev)
|
||||
int udc_mask_unused_interrupts(struct udc *dev)
|
||||
{
|
||||
u32 tmp;
|
||||
|
||||
|
|
@ -287,6 +245,7 @@ static int udc_mask_unused_interrupts(struct udc *dev)
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(udc_mask_unused_interrupts);
|
||||
|
||||
/* Enables endpoint 0 interrupts */
|
||||
static int udc_enable_ep0_interrupts(struct udc *dev)
|
||||
|
|
@ -306,7 +265,7 @@ static int udc_enable_ep0_interrupts(struct udc *dev)
|
|||
}
|
||||
|
||||
/* Enables device interrupts for SET_INTF and SET_CONFIG */
|
||||
static int udc_enable_dev_setup_interrupts(struct udc *dev)
|
||||
int udc_enable_dev_setup_interrupts(struct udc *dev)
|
||||
{
|
||||
u32 tmp;
|
||||
|
||||
|
|
@ -325,6 +284,7 @@ static int udc_enable_dev_setup_interrupts(struct udc *dev)
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(udc_enable_dev_setup_interrupts);
|
||||
|
||||
/* Calculates fifo start of endpoint based on preceding endpoints */
|
||||
static int udc_set_txfifo_addr(struct udc_ep *ep)
|
||||
|
|
@ -583,7 +543,7 @@ udc_alloc_request(struct usb_ep *usbep, gfp_t gfp)
|
|||
|
||||
if (ep->dma) {
|
||||
/* ep0 in requests are allocated from data pool here */
|
||||
dma_desc = pci_pool_alloc(ep->dev->data_requests, gfp,
|
||||
dma_desc = dma_pool_alloc(ep->dev->data_requests, gfp,
|
||||
&req->td_phys);
|
||||
if (!dma_desc) {
|
||||
kfree(req);
|
||||
|
|
@ -608,27 +568,23 @@ udc_alloc_request(struct usb_ep *usbep, gfp_t gfp)
|
|||
}
|
||||
|
||||
/* frees pci pool descriptors of a DMA chain */
|
||||
static int udc_free_dma_chain(struct udc *dev, struct udc_request *req)
|
||||
static void udc_free_dma_chain(struct udc *dev, struct udc_request *req)
|
||||
{
|
||||
int ret_val = 0;
|
||||
struct udc_data_dma *td;
|
||||
struct udc_data_dma *td_last = NULL;
|
||||
struct udc_data_dma *td = req->td_data;
|
||||
unsigned int i;
|
||||
|
||||
dma_addr_t addr_next = 0x00;
|
||||
dma_addr_t addr = (dma_addr_t)td->next;
|
||||
|
||||
DBG(dev, "free chain req = %p\n", req);
|
||||
|
||||
/* do not free first desc., will be done by free for request */
|
||||
td_last = req->td_data;
|
||||
td = phys_to_virt(td_last->next);
|
||||
|
||||
for (i = 1; i < req->chain_len; i++) {
|
||||
pci_pool_free(dev->data_requests, td,
|
||||
(dma_addr_t)td_last->next);
|
||||
td_last = td;
|
||||
td = phys_to_virt(td_last->next);
|
||||
td = phys_to_virt(addr);
|
||||
addr_next = (dma_addr_t)td->next;
|
||||
dma_pool_free(dev->data_requests, td, addr);
|
||||
addr = addr_next;
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/* Frees request packet, called by gadget driver */
|
||||
|
|
@ -652,7 +608,7 @@ udc_free_request(struct usb_ep *usbep, struct usb_request *usbreq)
|
|||
if (req->chain_len > 1)
|
||||
udc_free_dma_chain(ep->dev, req);
|
||||
|
||||
pci_pool_free(ep->dev->data_requests, req->td_data,
|
||||
dma_pool_free(ep->dev->data_requests, req->td_data,
|
||||
req->td_phys);
|
||||
}
|
||||
kfree(req);
|
||||
|
|
@ -847,7 +803,7 @@ static int udc_create_dma_chain(
|
|||
for (i = buf_len; i < bytes; i += buf_len) {
|
||||
/* create or determine next desc. */
|
||||
if (create_new_chain) {
|
||||
td = pci_pool_alloc(ep->dev->data_requests,
|
||||
td = dma_pool_alloc(ep->dev->data_requests,
|
||||
gfp_flags, &dma_addr);
|
||||
if (!td)
|
||||
return -ENOMEM;
|
||||
|
|
@ -1507,7 +1463,7 @@ static void make_ep_lists(struct udc *dev)
|
|||
}
|
||||
|
||||
/* Inits UDC context */
|
||||
static void udc_basic_init(struct udc *dev)
|
||||
void udc_basic_init(struct udc *dev)
|
||||
{
|
||||
u32 tmp;
|
||||
|
||||
|
|
@ -1543,6 +1499,7 @@ static void udc_basic_init(struct udc *dev)
|
|||
dev->data_ep_enabled = 0;
|
||||
dev->data_ep_queued = 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(udc_basic_init);
|
||||
|
||||
/* init registers at driver load time */
|
||||
static int startup_registers(struct udc *dev)
|
||||
|
|
@ -3031,7 +2988,7 @@ __acquires(dev->lock)
|
|||
}
|
||||
|
||||
/* Interrupt Service Routine, see Linux Kernel Doc for parameters */
|
||||
static irqreturn_t udc_irq(int irq, void *pdev)
|
||||
irqreturn_t udc_irq(int irq, void *pdev)
|
||||
{
|
||||
struct udc *dev = pdev;
|
||||
u32 reg;
|
||||
|
|
@ -3083,16 +3040,18 @@ static irqreturn_t udc_irq(int irq, void *pdev)
|
|||
spin_unlock(&dev->lock);
|
||||
return ret_val;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(udc_irq);
|
||||
|
||||
/* Tears down device */
|
||||
static void gadget_release(struct device *pdev)
|
||||
void gadget_release(struct device *pdev)
|
||||
{
|
||||
struct amd5536udc *dev = dev_get_drvdata(pdev);
|
||||
kfree(dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gadget_release);
|
||||
|
||||
/* Cleanup on device remove */
|
||||
static void udc_remove(struct udc *dev)
|
||||
void udc_remove(struct udc *dev)
|
||||
{
|
||||
/* remove timer */
|
||||
stop_timer++;
|
||||
|
|
@ -3108,9 +3067,10 @@ static void udc_remove(struct udc *dev)
|
|||
del_timer_sync(&udc_pollstall_timer);
|
||||
udc = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(udc_remove);
|
||||
|
||||
/* free all the dma pools */
|
||||
static void free_dma_pools(struct udc *dev)
|
||||
void free_dma_pools(struct udc *dev)
|
||||
{
|
||||
dma_pool_free(dev->stp_requests, dev->ep[UDC_EP0OUT_IX].td,
|
||||
dev->ep[UDC_EP0OUT_IX].td_phys);
|
||||
|
|
@ -3119,35 +3079,10 @@ static void free_dma_pools(struct udc *dev)
|
|||
dma_pool_destroy(dev->stp_requests);
|
||||
dma_pool_destroy(dev->data_requests);
|
||||
}
|
||||
|
||||
/* Reset all pci context */
|
||||
static void udc_pci_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct udc *dev;
|
||||
|
||||
dev = pci_get_drvdata(pdev);
|
||||
|
||||
usb_del_gadget_udc(&udc->gadget);
|
||||
/* gadget driver must not be registered */
|
||||
if (WARN_ON(dev->driver))
|
||||
return;
|
||||
|
||||
/* dma pool cleanup */
|
||||
free_dma_pools(dev);
|
||||
|
||||
/* reset controller */
|
||||
writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg);
|
||||
free_irq(pdev->irq, dev);
|
||||
iounmap(dev->virt_addr);
|
||||
release_mem_region(pci_resource_start(pdev, 0),
|
||||
pci_resource_len(pdev, 0));
|
||||
pci_disable_device(pdev);
|
||||
|
||||
udc_remove(dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(free_dma_pools);
|
||||
|
||||
/* create dma pools on init */
|
||||
static int init_dma_pools(struct udc *dev)
|
||||
int init_dma_pools(struct udc *dev)
|
||||
{
|
||||
struct udc_stp_dma *td_stp;
|
||||
struct udc_data_dma *td_data;
|
||||
|
|
@ -3210,9 +3145,10 @@ err_create_dma_pool:
|
|||
dev->data_requests = NULL;
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(init_dma_pools);
|
||||
|
||||
/* general probe */
|
||||
static int udc_probe(struct udc *dev)
|
||||
int udc_probe(struct udc *dev)
|
||||
{
|
||||
char tmp[128];
|
||||
u32 reg;
|
||||
|
|
@ -3276,137 +3212,7 @@ static int udc_probe(struct udc *dev)
|
|||
finished:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Called by pci bus driver to init pci context */
|
||||
static int udc_pci_probe(
|
||||
struct pci_dev *pdev,
|
||||
const struct pci_device_id *id
|
||||
)
|
||||
{
|
||||
struct udc *dev;
|
||||
unsigned long resource;
|
||||
unsigned long len;
|
||||
int retval = 0;
|
||||
|
||||
/* one udc only */
|
||||
if (udc) {
|
||||
dev_dbg(&pdev->dev, "already probed\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* init */
|
||||
dev = kzalloc(sizeof(struct udc), GFP_KERNEL);
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
|
||||
/* pci setup */
|
||||
if (pci_enable_device(pdev) < 0) {
|
||||
retval = -ENODEV;
|
||||
goto err_pcidev;
|
||||
}
|
||||
|
||||
/* PCI resource allocation */
|
||||
resource = pci_resource_start(pdev, 0);
|
||||
len = pci_resource_len(pdev, 0);
|
||||
|
||||
if (!request_mem_region(resource, len, name)) {
|
||||
dev_dbg(&pdev->dev, "pci device used already\n");
|
||||
retval = -EBUSY;
|
||||
goto err_memreg;
|
||||
}
|
||||
|
||||
dev->virt_addr = ioremap_nocache(resource, len);
|
||||
if (!dev->virt_addr) {
|
||||
dev_dbg(&pdev->dev, "start address cannot be mapped\n");
|
||||
retval = -EFAULT;
|
||||
goto err_ioremap;
|
||||
}
|
||||
|
||||
if (!pdev->irq) {
|
||||
dev_err(&pdev->dev, "irq not set\n");
|
||||
retval = -ENODEV;
|
||||
goto err_irq;
|
||||
}
|
||||
|
||||
spin_lock_init(&dev->lock);
|
||||
/* udc csr registers base */
|
||||
dev->csr = dev->virt_addr + UDC_CSR_ADDR;
|
||||
/* dev registers base */
|
||||
dev->regs = dev->virt_addr + UDC_DEVCFG_ADDR;
|
||||
/* ep registers base */
|
||||
dev->ep_regs = dev->virt_addr + UDC_EPREGS_ADDR;
|
||||
/* fifo's base */
|
||||
dev->rxfifo = (u32 __iomem *)(dev->virt_addr + UDC_RXFIFO_ADDR);
|
||||
dev->txfifo = (u32 __iomem *)(dev->virt_addr + UDC_TXFIFO_ADDR);
|
||||
|
||||
if (request_irq(pdev->irq, udc_irq, IRQF_SHARED, name, dev) != 0) {
|
||||
dev_dbg(&pdev->dev, "request_irq(%d) fail\n", pdev->irq);
|
||||
retval = -EBUSY;
|
||||
goto err_irq;
|
||||
}
|
||||
|
||||
pci_set_drvdata(pdev, dev);
|
||||
|
||||
/* chip revision for Hs AMD5536 */
|
||||
dev->chiprev = pdev->revision;
|
||||
|
||||
pci_set_master(pdev);
|
||||
pci_try_set_mwi(pdev);
|
||||
|
||||
/* init dma pools */
|
||||
if (use_dma) {
|
||||
retval = init_dma_pools(dev);
|
||||
if (retval != 0)
|
||||
goto err_dma;
|
||||
}
|
||||
|
||||
dev->phys_addr = resource;
|
||||
dev->irq = pdev->irq;
|
||||
dev->pdev = pdev;
|
||||
|
||||
/* general probing */
|
||||
if (udc_probe(dev)) {
|
||||
retval = -ENODEV;
|
||||
goto err_probe;
|
||||
}
|
||||
return 0;
|
||||
|
||||
err_probe:
|
||||
if (use_dma)
|
||||
free_dma_pools(dev);
|
||||
err_dma:
|
||||
free_irq(pdev->irq, dev);
|
||||
err_irq:
|
||||
iounmap(dev->virt_addr);
|
||||
err_ioremap:
|
||||
release_mem_region(resource, len);
|
||||
err_memreg:
|
||||
pci_disable_device(pdev);
|
||||
err_pcidev:
|
||||
kfree(dev);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* PCI device parameters */
|
||||
static const struct pci_device_id pci_id[] = {
|
||||
{
|
||||
PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x2096),
|
||||
.class = PCI_CLASS_SERIAL_USB_DEVICE,
|
||||
.class_mask = 0xffffffff,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, pci_id);
|
||||
|
||||
/* PCI functions */
|
||||
static struct pci_driver udc_pci_driver = {
|
||||
.name = (char *) name,
|
||||
.id_table = pci_id,
|
||||
.probe = udc_pci_probe,
|
||||
.remove = udc_pci_remove,
|
||||
};
|
||||
|
||||
module_pci_driver(udc_pci_driver);
|
||||
EXPORT_SYMBOL_GPL(udc_probe);
|
||||
|
||||
MODULE_DESCRIPTION(UDC_MOD_DESCRIPTION);
|
||||
MODULE_AUTHOR("Thomas Dahlmann");
|
||||
|
|
|
|||
|
|
@ -13,6 +13,12 @@
|
|||
#ifndef AMD5536UDC_H
|
||||
#define AMD5536UDC_H
|
||||
|
||||
/* debug control */
|
||||
/* #define UDC_VERBOSE */
|
||||
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
|
||||
/* various constants */
|
||||
#define UDC_RDE_TIMER_SECONDS 1
|
||||
#define UDC_RDE_TIMER_DIV 10
|
||||
|
|
@ -545,8 +551,8 @@ struct udc {
|
|||
u32 __iomem *txfifo;
|
||||
|
||||
/* DMA desc pools */
|
||||
struct pci_pool *data_requests;
|
||||
struct pci_pool *stp_requests;
|
||||
struct dma_pool *data_requests;
|
||||
struct dma_pool *stp_requests;
|
||||
|
||||
/* device data */
|
||||
unsigned long phys_addr;
|
||||
|
|
@ -567,6 +573,36 @@ union udc_setup_data {
|
|||
struct usb_ctrlrequest request;
|
||||
};
|
||||
|
||||
/* Function declarations */
|
||||
int udc_enable_dev_setup_interrupts(struct udc *dev);
|
||||
int udc_mask_unused_interrupts(struct udc *dev);
|
||||
irqreturn_t udc_irq(int irq, void *pdev);
|
||||
void gadget_release(struct device *pdev);
|
||||
void udc_basic_init(struct udc *dev);
|
||||
void free_dma_pools(struct udc *dev);
|
||||
int init_dma_pools(struct udc *dev);
|
||||
void udc_remove(struct udc *dev);
|
||||
int udc_probe(struct udc *dev);
|
||||
|
||||
/* DMA usage flag */
|
||||
static bool use_dma = 1;
|
||||
/* packet per buffer dma */
|
||||
static bool use_dma_ppb = 1;
|
||||
/* with per descr. update */
|
||||
static bool use_dma_ppb_du;
|
||||
/* full speed only mode */
|
||||
static bool use_fullspeed;
|
||||
|
||||
/* module parameters */
|
||||
module_param(use_dma, bool, S_IRUGO);
|
||||
MODULE_PARM_DESC(use_dma, "true for DMA");
|
||||
module_param(use_dma_ppb, bool, S_IRUGO);
|
||||
MODULE_PARM_DESC(use_dma_ppb, "true for DMA in packet per buffer mode");
|
||||
module_param(use_dma_ppb_du, bool, S_IRUGO);
|
||||
MODULE_PARM_DESC(use_dma_ppb_du,
|
||||
"true for DMA in packet per buffer mode with descriptor update");
|
||||
module_param(use_fullspeed, bool, S_IRUGO);
|
||||
MODULE_PARM_DESC(use_fullspeed, "true for fullspeed only");
|
||||
/*
|
||||
*---------------------------------------------------------------------------
|
||||
* SET and GET bitfields in u32 values
|
||||
|
|
|
|||
217
drivers/usb/gadget/udc/amd5536udc_pci.c
Normal file
217
drivers/usb/gadget/udc/amd5536udc_pci.c
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
/*
|
||||
* amd5536udc_pci.c -- AMD 5536 UDC high/full speed USB device controller
|
||||
*
|
||||
* Copyright (C) 2005-2007 AMD (http://www.amd.com)
|
||||
* Author: Thomas Dahlmann
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The AMD5536 UDC is part of the x86 southbridge AMD Geode CS5536.
|
||||
* It is a USB Highspeed DMA capable USB device controller. Beside ep0 it
|
||||
* provides 4 IN and 4 OUT endpoints (bulk or interrupt type).
|
||||
*
|
||||
* Make sure that UDC is assigned to port 4 by BIOS settings (port can also
|
||||
* be used as host port) and UOC bits PAD_EN and APU are set (should be done
|
||||
* by BIOS init).
|
||||
*
|
||||
* UDC DMA requires 32-bit aligned buffers so DMA with gadget ether does not
|
||||
* work without updating NET_IP_ALIGN. Or PIO mode (module param "use_dma=0")
|
||||
* can be used with gadget ether.
|
||||
*
|
||||
* This file does pci device registration, and the core driver implementation
|
||||
* is done in amd5536udc.c
|
||||
*
|
||||
* The driver is split so as to use the core UDC driver which is based on
|
||||
* Synopsys device controller IP (different than HS OTG IP) in UDCs
|
||||
* integrated to SoC platforms.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Driver strings */
|
||||
#define UDC_MOD_DESCRIPTION "AMD 5536 UDC - USB Device Controller"
|
||||
|
||||
/* system */
|
||||
#include <linux/device.h>
|
||||
#include <linux/dmapool.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/prefetch.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
/* udc specific */
|
||||
#include "amd5536udc.h"
|
||||
|
||||
/* pointer to device object */
|
||||
static struct udc *udc;
|
||||
|
||||
/* description */
|
||||
static const char mod_desc[] = UDC_MOD_DESCRIPTION;
|
||||
static const char name[] = "amd5536udc-pci";
|
||||
|
||||
/* Reset all pci context */
|
||||
static void udc_pci_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct udc *dev;
|
||||
|
||||
dev = pci_get_drvdata(pdev);
|
||||
|
||||
usb_del_gadget_udc(&udc->gadget);
|
||||
/* gadget driver must not be registered */
|
||||
if (WARN_ON(dev->driver))
|
||||
return;
|
||||
|
||||
/* dma pool cleanup */
|
||||
free_dma_pools(dev);
|
||||
|
||||
/* reset controller */
|
||||
writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg);
|
||||
free_irq(pdev->irq, dev);
|
||||
iounmap(dev->virt_addr);
|
||||
release_mem_region(pci_resource_start(pdev, 0),
|
||||
pci_resource_len(pdev, 0));
|
||||
pci_disable_device(pdev);
|
||||
|
||||
udc_remove(dev);
|
||||
}
|
||||
|
||||
/* Called by pci bus driver to init pci context */
|
||||
static int udc_pci_probe(
|
||||
struct pci_dev *pdev,
|
||||
const struct pci_device_id *id
|
||||
)
|
||||
{
|
||||
struct udc *dev;
|
||||
unsigned long resource;
|
||||
unsigned long len;
|
||||
int retval = 0;
|
||||
|
||||
/* one udc only */
|
||||
if (udc) {
|
||||
dev_dbg(&pdev->dev, "already probed\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* init */
|
||||
dev = kzalloc(sizeof(struct udc), GFP_KERNEL);
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
|
||||
/* pci setup */
|
||||
if (pci_enable_device(pdev) < 0) {
|
||||
retval = -ENODEV;
|
||||
goto err_pcidev;
|
||||
}
|
||||
|
||||
/* PCI resource allocation */
|
||||
resource = pci_resource_start(pdev, 0);
|
||||
len = pci_resource_len(pdev, 0);
|
||||
|
||||
if (!request_mem_region(resource, len, name)) {
|
||||
dev_dbg(&pdev->dev, "pci device used already\n");
|
||||
retval = -EBUSY;
|
||||
goto err_memreg;
|
||||
}
|
||||
|
||||
dev->virt_addr = ioremap_nocache(resource, len);
|
||||
if (!dev->virt_addr) {
|
||||
dev_dbg(&pdev->dev, "start address cannot be mapped\n");
|
||||
retval = -EFAULT;
|
||||
goto err_ioremap;
|
||||
}
|
||||
|
||||
if (!pdev->irq) {
|
||||
dev_err(&pdev->dev, "irq not set\n");
|
||||
retval = -ENODEV;
|
||||
goto err_irq;
|
||||
}
|
||||
|
||||
spin_lock_init(&dev->lock);
|
||||
/* udc csr registers base */
|
||||
dev->csr = dev->virt_addr + UDC_CSR_ADDR;
|
||||
/* dev registers base */
|
||||
dev->regs = dev->virt_addr + UDC_DEVCFG_ADDR;
|
||||
/* ep registers base */
|
||||
dev->ep_regs = dev->virt_addr + UDC_EPREGS_ADDR;
|
||||
/* fifo's base */
|
||||
dev->rxfifo = (u32 __iomem *)(dev->virt_addr + UDC_RXFIFO_ADDR);
|
||||
dev->txfifo = (u32 __iomem *)(dev->virt_addr + UDC_TXFIFO_ADDR);
|
||||
|
||||
if (request_irq(pdev->irq, udc_irq, IRQF_SHARED, name, dev) != 0) {
|
||||
dev_dbg(&pdev->dev, "request_irq(%d) fail\n", pdev->irq);
|
||||
retval = -EBUSY;
|
||||
goto err_irq;
|
||||
}
|
||||
|
||||
pci_set_drvdata(pdev, dev);
|
||||
|
||||
/* chip revision for Hs AMD5536 */
|
||||
dev->chiprev = pdev->revision;
|
||||
|
||||
pci_set_master(pdev);
|
||||
pci_try_set_mwi(pdev);
|
||||
|
||||
/* init dma pools */
|
||||
if (use_dma) {
|
||||
retval = init_dma_pools(dev);
|
||||
if (retval != 0)
|
||||
goto err_dma;
|
||||
}
|
||||
|
||||
dev->phys_addr = resource;
|
||||
dev->irq = pdev->irq;
|
||||
dev->pdev = pdev;
|
||||
|
||||
/* general probing */
|
||||
if (udc_probe(dev)) {
|
||||
retval = -ENODEV;
|
||||
goto err_probe;
|
||||
}
|
||||
return 0;
|
||||
|
||||
err_probe:
|
||||
if (use_dma)
|
||||
free_dma_pools(dev);
|
||||
err_dma:
|
||||
free_irq(pdev->irq, dev);
|
||||
err_irq:
|
||||
iounmap(dev->virt_addr);
|
||||
err_ioremap:
|
||||
release_mem_region(resource, len);
|
||||
err_memreg:
|
||||
pci_disable_device(pdev);
|
||||
err_pcidev:
|
||||
kfree(dev);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* PCI device parameters */
|
||||
static const struct pci_device_id pci_id[] = {
|
||||
{
|
||||
PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x2096),
|
||||
.class = PCI_CLASS_SERIAL_USB_DEVICE,
|
||||
.class_mask = 0xffffffff,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, pci_id);
|
||||
|
||||
/* PCI functions */
|
||||
static struct pci_driver udc_pci_driver = {
|
||||
.name = (char *) name,
|
||||
.id_table = pci_id,
|
||||
.probe = udc_pci_probe,
|
||||
.remove = udc_pci_remove,
|
||||
};
|
||||
module_pci_driver(udc_pci_driver);
|
||||
|
||||
MODULE_DESCRIPTION(UDC_MOD_DESCRIPTION);
|
||||
MODULE_AUTHOR("Thomas Dahlmann");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
@ -321,7 +321,6 @@ static inline void usba_cleanup_debugfs(struct usba_udc *udc)
|
|||
|
||||
static ushort fifo_mode;
|
||||
|
||||
/* "modprobe ... fifo_mode=1" etc */
|
||||
module_param(fifo_mode, ushort, 0x0);
|
||||
MODULE_PARM_DESC(fifo_mode, "Endpoint configuration mode");
|
||||
|
||||
|
|
@ -371,7 +370,7 @@ static struct usba_fifo_cfg mode_4_cfg[] = {
|
|||
};
|
||||
/* Add additional configurations here */
|
||||
|
||||
int usba_config_fifo_table(struct usba_udc *udc)
|
||||
static int usba_config_fifo_table(struct usba_udc *udc)
|
||||
{
|
||||
int n;
|
||||
|
||||
|
|
@ -1076,11 +1075,9 @@ static int atmel_usba_start(struct usb_gadget *gadget,
|
|||
struct usb_gadget_driver *driver);
|
||||
static int atmel_usba_stop(struct usb_gadget *gadget);
|
||||
|
||||
static struct usb_ep *atmel_usba_match_ep(
|
||||
struct usb_gadget *gadget,
|
||||
struct usb_endpoint_descriptor *desc,
|
||||
struct usb_ss_ep_comp_descriptor *ep_comp
|
||||
)
|
||||
static struct usb_ep *atmel_usba_match_ep(struct usb_gadget *gadget,
|
||||
struct usb_endpoint_descriptor *desc,
|
||||
struct usb_ss_ep_comp_descriptor *ep_comp)
|
||||
{
|
||||
struct usb_ep *_ep;
|
||||
struct usba_ep *ep;
|
||||
|
|
@ -1100,7 +1097,6 @@ found_ep:
|
|||
ep = to_usba_ep(_ep);
|
||||
|
||||
switch (usb_endpoint_type(desc)) {
|
||||
|
||||
case USB_ENDPOINT_XFER_CONTROL:
|
||||
break;
|
||||
|
||||
|
|
@ -1141,7 +1137,7 @@ found_ep:
|
|||
ep->udc->configured_ep++;
|
||||
}
|
||||
|
||||
return _ep;
|
||||
return _ep;
|
||||
}
|
||||
|
||||
static const struct usb_gadget_ops usba_udc_ops = {
|
||||
|
|
@ -1855,8 +1851,8 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
|
|||
* but it's clearly harmless...
|
||||
*/
|
||||
if (!(usba_ep_readl(ep0, CFG) & USBA_EPT_MAPPED))
|
||||
dev_dbg(&udc->pdev->dev,
|
||||
"ODD: EP0 configuration is invalid!\n");
|
||||
dev_err(&udc->pdev->dev,
|
||||
"ODD: EP0 configuration is invalid!\n");
|
||||
|
||||
/* Preallocate other endpoints */
|
||||
n = fifo_mode ? udc->num_ep : udc->configured_ep;
|
||||
|
|
@ -1864,8 +1860,8 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
|
|||
ep = &udc->usba_ep[i];
|
||||
usba_ep_writel(ep, CFG, ep->ept_cfg);
|
||||
if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED))
|
||||
dev_dbg(&udc->pdev->dev,
|
||||
"ODD: EP%d configuration is invalid!\n", i);
|
||||
dev_err(&udc->pdev->dev,
|
||||
"ODD: EP%d configuration is invalid!\n", i);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2089,8 +2085,9 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
|
|||
while ((pp = of_get_next_child(np, pp)))
|
||||
udc->num_ep++;
|
||||
udc->configured_ep = 1;
|
||||
} else
|
||||
} else {
|
||||
udc->num_ep = usba_config_fifo_table(udc);
|
||||
}
|
||||
|
||||
eps = devm_kzalloc(&pdev->dev, sizeof(struct usba_ep) * udc->num_ep,
|
||||
GFP_KERNEL);
|
||||
|
|
@ -2118,14 +2115,34 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
|
|||
dev_err(&pdev->dev, "of_probe: fifo-size error(%d)\n", ret);
|
||||
goto err;
|
||||
}
|
||||
ep->fifo_size = fifo_mode ? udc->fifo_cfg[i].fifo_size : val;
|
||||
if (fifo_mode) {
|
||||
if (val < udc->fifo_cfg[i].fifo_size) {
|
||||
dev_warn(&pdev->dev,
|
||||
"Using max fifo-size value from DT\n");
|
||||
ep->fifo_size = val;
|
||||
} else {
|
||||
ep->fifo_size = udc->fifo_cfg[i].fifo_size;
|
||||
}
|
||||
} else {
|
||||
ep->fifo_size = val;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(pp, "atmel,nb-banks", &val);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "of_probe: nb-banks error(%d)\n", ret);
|
||||
goto err;
|
||||
}
|
||||
ep->nr_banks = fifo_mode ? udc->fifo_cfg[i].nr_banks : val;
|
||||
if (fifo_mode) {
|
||||
if (val < udc->fifo_cfg[i].nr_banks) {
|
||||
dev_warn(&pdev->dev,
|
||||
"Using max nb-banks value from DT\n");
|
||||
ep->nr_banks = val;
|
||||
} else {
|
||||
ep->nr_banks = udc->fifo_cfg[i].nr_banks;
|
||||
}
|
||||
} else {
|
||||
ep->nr_banks = val;
|
||||
}
|
||||
|
||||
ep->can_dma = of_property_read_bool(pp, "atmel,can-dma");
|
||||
ep->can_isoc = of_property_read_bool(pp, "atmel,can-isoc");
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ if USB_BDC_UDC
|
|||
comment "Platform Support"
|
||||
config USB_BDC_PCI
|
||||
tristate "BDC support for PCIe based platforms"
|
||||
depends on PCI
|
||||
depends on USB_PCI
|
||||
default USB_BDC_UDC
|
||||
help
|
||||
Enable support for platforms which have BDC connected through PCIe, such as Lego3 FPGA platform.
|
||||
|
|
|
|||
|
|
@ -1273,6 +1273,7 @@ void usb_del_gadget_udc(struct usb_gadget *gadget)
|
|||
flush_work(&gadget->work);
|
||||
device_unregister(&udc->dev);
|
||||
device_unregister(&gadget->dev);
|
||||
memset(&gadget->dev, 0x00, sizeof(gadget->dev));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_del_gadget_udc);
|
||||
|
||||
|
|
|
|||
|
|
@ -2062,16 +2062,13 @@ static int dummy_hub_control(
|
|||
}
|
||||
break;
|
||||
case USB_PORT_FEAT_POWER:
|
||||
if (hcd->speed == HCD_USB3) {
|
||||
if (dum_hcd->port_status & USB_PORT_STAT_POWER)
|
||||
dev_dbg(dummy_dev(dum_hcd),
|
||||
"power-off\n");
|
||||
} else
|
||||
if (dum_hcd->port_status &
|
||||
USB_SS_PORT_STAT_POWER)
|
||||
dev_dbg(dummy_dev(dum_hcd),
|
||||
"power-off\n");
|
||||
/* FALLS THROUGH */
|
||||
dev_dbg(dummy_dev(dum_hcd), "power-off\n");
|
||||
if (hcd->speed == HCD_USB3)
|
||||
dum_hcd->port_status &= ~USB_SS_PORT_STAT_POWER;
|
||||
else
|
||||
dum_hcd->port_status &= ~USB_PORT_STAT_POWER;
|
||||
set_link_state(dum_hcd);
|
||||
break;
|
||||
default:
|
||||
dum_hcd->port_status &= ~(1 << wValue);
|
||||
set_link_state(dum_hcd);
|
||||
|
|
@ -2242,14 +2239,13 @@ static int dummy_hub_control(
|
|||
if ((dum_hcd->port_status &
|
||||
USB_SS_PORT_STAT_POWER) != 0) {
|
||||
dum_hcd->port_status |= (1 << wValue);
|
||||
set_link_state(dum_hcd);
|
||||
}
|
||||
} else
|
||||
if ((dum_hcd->port_status &
|
||||
USB_PORT_STAT_POWER) != 0) {
|
||||
dum_hcd->port_status |= (1 << wValue);
|
||||
set_link_state(dum_hcd);
|
||||
}
|
||||
set_link_state(dum_hcd);
|
||||
}
|
||||
break;
|
||||
case GetPortErrorCount:
|
||||
|
|
|
|||
|
|
@ -2675,6 +2675,8 @@ static const struct platform_device_id fsl_udc_devtype[] = {
|
|||
.name = "imx-udc-mx27",
|
||||
}, {
|
||||
.name = "imx-udc-mx51",
|
||||
}, {
|
||||
.name = "fsl-usb2-udc",
|
||||
}, {
|
||||
/* sentinel */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1835,13 +1835,18 @@ static int mv_u3d_probe(struct platform_device *dev)
|
|||
}
|
||||
|
||||
/* we will access controller register, so enable the u3d controller */
|
||||
clk_enable(u3d->clk);
|
||||
retval = clk_enable(u3d->clk);
|
||||
if (retval) {
|
||||
dev_err(&dev->dev, "clk_enable error %d\n", retval);
|
||||
goto err_u3d_enable;
|
||||
}
|
||||
|
||||
if (pdata->phy_init) {
|
||||
retval = pdata->phy_init(u3d->phy_regs);
|
||||
if (retval) {
|
||||
dev_err(&dev->dev, "init phy error %d\n", retval);
|
||||
goto err_u3d_enable;
|
||||
clk_disable(u3d->clk);
|
||||
goto err_phy_init;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1974,15 +1979,13 @@ err_alloc_trb_pool:
|
|||
dma_free_coherent(&dev->dev, u3d->ep_context_size,
|
||||
u3d->ep_context, u3d->ep_context_dma);
|
||||
err_alloc_ep_context:
|
||||
if (pdata->phy_deinit)
|
||||
pdata->phy_deinit(u3d->phy_regs);
|
||||
clk_disable(u3d->clk);
|
||||
err_phy_init:
|
||||
err_u3d_enable:
|
||||
iounmap(u3d->cap_regs);
|
||||
err_map_cap_regs:
|
||||
err_get_cap_regs:
|
||||
err_get_clk:
|
||||
clk_put(u3d->clk);
|
||||
err_get_clk:
|
||||
kfree(u3d);
|
||||
err_alloc_private:
|
||||
err_pdata:
|
||||
|
|
|
|||
|
|
@ -445,7 +445,8 @@ static int mv_ep_enable(struct usb_ep *_ep,
|
|||
struct mv_dqh *dqh;
|
||||
u16 max = 0;
|
||||
u32 bit_pos, epctrlx, direction;
|
||||
unsigned char zlt = 0, ios = 0, mult = 0;
|
||||
const unsigned char zlt = 1;
|
||||
unsigned char ios, mult;
|
||||
unsigned long flags;
|
||||
|
||||
ep = container_of(_ep, struct mv_ep, ep);
|
||||
|
|
@ -465,8 +466,6 @@ static int mv_ep_enable(struct usb_ep *_ep,
|
|||
* disable HW zero length termination select
|
||||
* driver handles zero length packet through req->req.zero
|
||||
*/
|
||||
zlt = 1;
|
||||
|
||||
bit_pos = 1 << ((direction == EP_DIR_OUT ? 0 : 16) + ep->ep_num);
|
||||
|
||||
/* Check if the Endpoint is Primed */
|
||||
|
|
@ -481,16 +480,16 @@ static int mv_ep_enable(struct usb_ep *_ep,
|
|||
(unsigned)bit_pos);
|
||||
goto en_done;
|
||||
}
|
||||
|
||||
/* Set the max packet length, interrupt on Setup and Mult fields */
|
||||
ios = 0;
|
||||
mult = 0;
|
||||
switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
|
||||
case USB_ENDPOINT_XFER_BULK:
|
||||
zlt = 1;
|
||||
mult = 0;
|
||||
case USB_ENDPOINT_XFER_INT:
|
||||
break;
|
||||
case USB_ENDPOINT_XFER_CONTROL:
|
||||
ios = 1;
|
||||
case USB_ENDPOINT_XFER_INT:
|
||||
mult = 0;
|
||||
break;
|
||||
case USB_ENDPOINT_XFER_ISOC:
|
||||
/* Calculate transactions needed for high bandwidth iso */
|
||||
|
|
|
|||
|
|
@ -653,7 +653,7 @@ net2272_request_dma(struct net2272 *dev, unsigned ep, u32 buf,
|
|||
dev->dma_busy = 1;
|
||||
|
||||
/* initialize platform's dma */
|
||||
#ifdef CONFIG_PCI
|
||||
#ifdef CONFIG_USB_PCI
|
||||
/* NET2272 addr, buffer addr, length, etc. */
|
||||
switch (dev->dev_id) {
|
||||
case PCI_DEVICE_ID_RDK1:
|
||||
|
|
@ -701,7 +701,7 @@ static void
|
|||
net2272_start_dma(struct net2272 *dev)
|
||||
{
|
||||
/* start platform's dma controller */
|
||||
#ifdef CONFIG_PCI
|
||||
#ifdef CONFIG_USB_PCI
|
||||
switch (dev->dev_id) {
|
||||
case PCI_DEVICE_ID_RDK1:
|
||||
writeb((1 << CHANNEL_ENABLE) | (1 << CHANNEL_START),
|
||||
|
|
@ -797,7 +797,7 @@ net2272_kick_dma(struct net2272_ep *ep, struct net2272_request *req)
|
|||
|
||||
static void net2272_cancel_dma(struct net2272 *dev)
|
||||
{
|
||||
#ifdef CONFIG_PCI
|
||||
#ifdef CONFIG_USB_PCI
|
||||
switch (dev->dev_id) {
|
||||
case PCI_DEVICE_ID_RDK1:
|
||||
writeb(0, dev->rdk1.plx9054_base_addr + DMACSR0);
|
||||
|
|
@ -2306,7 +2306,7 @@ err_add_udc:
|
|||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
#ifdef CONFIG_USB_PCI
|
||||
|
||||
/*
|
||||
* wrap this driver around the specified device, but
|
||||
|
|
|
|||
|
|
@ -472,7 +472,7 @@ struct net2272 {
|
|||
unsigned int base_shift;
|
||||
u16 __iomem *base_addr;
|
||||
union {
|
||||
#ifdef CONFIG_PCI
|
||||
#ifdef CONFIG_USB_PCI
|
||||
struct {
|
||||
void __iomem *plx9054_base_addr;
|
||||
void __iomem *epld_base_addr;
|
||||
|
|
|
|||
|
|
@ -569,7 +569,7 @@ static struct usb_request
|
|||
if (ep->dma) {
|
||||
struct net2280_dma *td;
|
||||
|
||||
td = pci_pool_alloc(ep->dev->requests, gfp_flags,
|
||||
td = dma_pool_alloc(ep->dev->requests, gfp_flags,
|
||||
&req->td_dma);
|
||||
if (!td) {
|
||||
kfree(req);
|
||||
|
|
@ -597,7 +597,7 @@ static void net2280_free_request(struct usb_ep *_ep, struct usb_request *_req)
|
|||
req = container_of(_req, struct net2280_request, req);
|
||||
WARN_ON(!list_empty(&req->queue));
|
||||
if (req->td)
|
||||
pci_pool_free(ep->dev->requests, req->td, req->td_dma);
|
||||
dma_pool_free(ep->dev->requests, req->td, req->td_dma);
|
||||
kfree(req);
|
||||
}
|
||||
|
||||
|
|
@ -3579,10 +3579,10 @@ static void net2280_remove(struct pci_dev *pdev)
|
|||
for (i = 1; i < 5; i++) {
|
||||
if (!dev->ep[i].dummy)
|
||||
continue;
|
||||
pci_pool_free(dev->requests, dev->ep[i].dummy,
|
||||
dma_pool_free(dev->requests, dev->ep[i].dummy,
|
||||
dev->ep[i].td_dma);
|
||||
}
|
||||
pci_pool_destroy(dev->requests);
|
||||
dma_pool_destroy(dev->requests);
|
||||
}
|
||||
if (dev->got_irq)
|
||||
free_irq(pdev->irq, dev);
|
||||
|
|
@ -3724,7 +3724,7 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
|
||||
/* DMA setup */
|
||||
/* NOTE: we know only the 32 LSBs of dma addresses may be nonzero */
|
||||
dev->requests = pci_pool_create("requests", pdev,
|
||||
dev->requests = dma_pool_create("requests", &pdev->dev,
|
||||
sizeof(struct net2280_dma),
|
||||
0 /* no alignment requirements */,
|
||||
0 /* or page-crossing issues */);
|
||||
|
|
@ -3736,7 +3736,7 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
for (i = 1; i < 5; i++) {
|
||||
struct net2280_dma *td;
|
||||
|
||||
td = pci_pool_alloc(dev->requests, GFP_KERNEL,
|
||||
td = dma_pool_alloc(dev->requests, GFP_KERNEL,
|
||||
&dev->ep[i].td_dma);
|
||||
if (!td) {
|
||||
ep_dbg(dev, "can't get dummy %d\n", i);
|
||||
|
|
|
|||
|
|
@ -187,7 +187,7 @@ struct net2280 {
|
|||
struct usb338x_ll_chi_regs __iomem *ll_chicken_reg;
|
||||
struct usb338x_pl_regs __iomem *plregs;
|
||||
|
||||
struct pci_pool *requests;
|
||||
struct dma_pool *requests;
|
||||
/* statistics...*/
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -355,8 +355,8 @@ struct pch_udc_dev {
|
|||
vbus_session:1,
|
||||
set_cfg_not_acked:1,
|
||||
waiting_zlp_ack:1;
|
||||
struct pci_pool *data_requests;
|
||||
struct pci_pool *stp_requests;
|
||||
struct dma_pool *data_requests;
|
||||
struct dma_pool *stp_requests;
|
||||
dma_addr_t dma_addr;
|
||||
struct usb_ctrlrequest setup_data;
|
||||
void __iomem *base_addr;
|
||||
|
|
@ -1522,7 +1522,8 @@ static void pch_udc_free_dma_chain(struct pch_udc_dev *dev,
|
|||
/* do not free first desc., will be done by free for request */
|
||||
td = phys_to_virt(addr);
|
||||
addr2 = (dma_addr_t)td->next;
|
||||
pci_pool_free(dev->data_requests, td, addr);
|
||||
dma_pool_free(dev->data_requests, td, addr);
|
||||
td->next = 0x00;
|
||||
addr = addr2;
|
||||
}
|
||||
req->chain_len = 1;
|
||||
|
|
@ -1538,7 +1539,7 @@ static void pch_udc_free_dma_chain(struct pch_udc_dev *dev,
|
|||
*
|
||||
* Return codes:
|
||||
* 0: success,
|
||||
* -ENOMEM: pci_pool_alloc invocation fails
|
||||
* -ENOMEM: dma_pool_alloc invocation fails
|
||||
*/
|
||||
static int pch_udc_create_dma_chain(struct pch_udc_ep *ep,
|
||||
struct pch_udc_request *req,
|
||||
|
|
@ -1564,7 +1565,7 @@ static int pch_udc_create_dma_chain(struct pch_udc_ep *ep,
|
|||
if (bytes <= buf_len)
|
||||
break;
|
||||
last = td;
|
||||
td = pci_pool_alloc(ep->dev->data_requests, gfp_flags,
|
||||
td = dma_pool_alloc(ep->dev->data_requests, gfp_flags,
|
||||
&dma_addr);
|
||||
if (!td)
|
||||
goto nomem;
|
||||
|
|
@ -1769,7 +1770,7 @@ static struct usb_request *pch_udc_alloc_request(struct usb_ep *usbep,
|
|||
if (!ep->dev->dma_addr)
|
||||
return &req->req;
|
||||
/* ep0 in requests are allocated from data pool here */
|
||||
dma_desc = pci_pool_alloc(ep->dev->data_requests, gfp,
|
||||
dma_desc = dma_pool_alloc(ep->dev->data_requests, gfp,
|
||||
&req->td_data_phys);
|
||||
if (NULL == dma_desc) {
|
||||
kfree(req);
|
||||
|
|
@ -1808,7 +1809,7 @@ static void pch_udc_free_request(struct usb_ep *usbep,
|
|||
if (req->td_data != NULL) {
|
||||
if (req->chain_len > 1)
|
||||
pch_udc_free_dma_chain(ep->dev, req);
|
||||
pci_pool_free(ep->dev->data_requests, req->td_data,
|
||||
dma_pool_free(ep->dev->data_requests, req->td_data,
|
||||
req->td_data_phys);
|
||||
}
|
||||
kfree(req);
|
||||
|
|
@ -2913,7 +2914,7 @@ static int init_dma_pools(struct pch_udc_dev *dev)
|
|||
void *ep0out_buf;
|
||||
|
||||
/* DMA setup */
|
||||
dev->data_requests = pci_pool_create("data_requests", dev->pdev,
|
||||
dev->data_requests = dma_pool_create("data_requests", &dev->pdev->dev,
|
||||
sizeof(struct pch_udc_data_dma_desc), 0, 0);
|
||||
if (!dev->data_requests) {
|
||||
dev_err(&dev->pdev->dev, "%s: can't get request data pool\n",
|
||||
|
|
@ -2922,7 +2923,7 @@ static int init_dma_pools(struct pch_udc_dev *dev)
|
|||
}
|
||||
|
||||
/* dma desc for setup data */
|
||||
dev->stp_requests = pci_pool_create("setup requests", dev->pdev,
|
||||
dev->stp_requests = dma_pool_create("setup requests", &dev->pdev->dev,
|
||||
sizeof(struct pch_udc_stp_dma_desc), 0, 0);
|
||||
if (!dev->stp_requests) {
|
||||
dev_err(&dev->pdev->dev, "%s: can't get setup request pool\n",
|
||||
|
|
@ -2930,7 +2931,7 @@ static int init_dma_pools(struct pch_udc_dev *dev)
|
|||
return -ENOMEM;
|
||||
}
|
||||
/* setup */
|
||||
td_stp = pci_pool_alloc(dev->stp_requests, GFP_KERNEL,
|
||||
td_stp = dma_pool_alloc(dev->stp_requests, GFP_KERNEL,
|
||||
&dev->ep[UDC_EP0OUT_IDX].td_stp_phys);
|
||||
if (!td_stp) {
|
||||
dev_err(&dev->pdev->dev,
|
||||
|
|
@ -2940,7 +2941,7 @@ static int init_dma_pools(struct pch_udc_dev *dev)
|
|||
dev->ep[UDC_EP0OUT_IDX].td_stp = td_stp;
|
||||
|
||||
/* data: 0 packets !? */
|
||||
td_data = pci_pool_alloc(dev->data_requests, GFP_KERNEL,
|
||||
td_data = dma_pool_alloc(dev->data_requests, GFP_KERNEL,
|
||||
&dev->ep[UDC_EP0OUT_IDX].td_data_phys);
|
||||
if (!td_data) {
|
||||
dev_err(&dev->pdev->dev,
|
||||
|
|
@ -3020,22 +3021,21 @@ static void pch_udc_remove(struct pci_dev *pdev)
|
|||
dev_err(&pdev->dev,
|
||||
"%s: gadget driver still bound!!!\n", __func__);
|
||||
/* dma pool cleanup */
|
||||
if (dev->data_requests)
|
||||
pci_pool_destroy(dev->data_requests);
|
||||
dma_pool_destroy(dev->data_requests);
|
||||
|
||||
if (dev->stp_requests) {
|
||||
/* cleanup DMA desc's for ep0in */
|
||||
if (dev->ep[UDC_EP0OUT_IDX].td_stp) {
|
||||
pci_pool_free(dev->stp_requests,
|
||||
dma_pool_free(dev->stp_requests,
|
||||
dev->ep[UDC_EP0OUT_IDX].td_stp,
|
||||
dev->ep[UDC_EP0OUT_IDX].td_stp_phys);
|
||||
}
|
||||
if (dev->ep[UDC_EP0OUT_IDX].td_data) {
|
||||
pci_pool_free(dev->stp_requests,
|
||||
dma_pool_free(dev->stp_requests,
|
||||
dev->ep[UDC_EP0OUT_IDX].td_data,
|
||||
dev->ep[UDC_EP0OUT_IDX].td_data_phys);
|
||||
}
|
||||
pci_pool_destroy(dev->stp_requests);
|
||||
dma_pool_destroy(dev->stp_requests);
|
||||
}
|
||||
|
||||
if (dev->dma_addr)
|
||||
|
|
|
|||
|
|
@ -1608,9 +1608,6 @@ static int pxa_udc_pullup(struct usb_gadget *_gadget, int is_active)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void udc_enable(struct pxa_udc *udc);
|
||||
static void udc_disable(struct pxa_udc *udc);
|
||||
|
||||
/**
|
||||
* pxa_udc_vbus_session - Called by external transceiver to enable/disable udc
|
||||
* @_gadget: usb gadget
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/extcon.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
|
|
@ -37,6 +38,9 @@
|
|||
#define USB3_USB_INT_ENA_2 0x22c
|
||||
#define USB3_STUP_DAT_0 0x230
|
||||
#define USB3_STUP_DAT_1 0x234
|
||||
#define USB3_USB_OTG_STA 0x268
|
||||
#define USB3_USB_OTG_INT_STA 0x26c
|
||||
#define USB3_USB_OTG_INT_ENA 0x270
|
||||
#define USB3_P0_MOD 0x280
|
||||
#define USB3_P0_CON 0x288
|
||||
#define USB3_P0_STA 0x28c
|
||||
|
|
@ -124,6 +128,9 @@
|
|||
/* USB_INT_ENA_2 and USB_INT_STA_2 */
|
||||
#define USB_INT_2_PIPE(n) BIT(n)
|
||||
|
||||
/* USB_OTG_STA, USB_OTG_INT_STA and USB_OTG_INT_ENA */
|
||||
#define USB_OTG_IDMON BIT(4)
|
||||
|
||||
/* P0_MOD */
|
||||
#define P0_MOD_DIR BIT(6)
|
||||
|
||||
|
|
@ -257,6 +264,8 @@ struct renesas_usb3 {
|
|||
|
||||
struct usb_gadget gadget;
|
||||
struct usb_gadget_driver *driver;
|
||||
struct extcon_dev *extcon;
|
||||
struct work_struct extcon_work;
|
||||
|
||||
struct renesas_usb3_ep *usb3_ep;
|
||||
int num_usb3_eps;
|
||||
|
|
@ -269,6 +278,8 @@ struct renesas_usb3 {
|
|||
u8 ep0_buf[USB3_EP0_BUF_SIZE];
|
||||
bool softconnect;
|
||||
bool workaround_for_vbus;
|
||||
bool extcon_host; /* check id and set EXTCON_USB_HOST */
|
||||
bool extcon_usb; /* check vbus and set EXTCON_USB */
|
||||
};
|
||||
|
||||
#define gadget_to_renesas_usb3(_gadget) \
|
||||
|
|
@ -332,6 +343,15 @@ static int usb3_wait(struct renesas_usb3 *usb3, u32 reg, u32 mask,
|
|||
return -EBUSY;
|
||||
}
|
||||
|
||||
static void renesas_usb3_extcon_work(struct work_struct *work)
|
||||
{
|
||||
struct renesas_usb3 *usb3 = container_of(work, struct renesas_usb3,
|
||||
extcon_work);
|
||||
|
||||
extcon_set_state_sync(usb3->extcon, EXTCON_USB_HOST, usb3->extcon_host);
|
||||
extcon_set_state_sync(usb3->extcon, EXTCON_USB, usb3->extcon_usb);
|
||||
}
|
||||
|
||||
static void usb3_enable_irq_1(struct renesas_usb3 *usb3, u32 bits)
|
||||
{
|
||||
usb3_set_bit(usb3, bits, USB3_USB_INT_ENA_1);
|
||||
|
|
@ -352,6 +372,11 @@ static void usb3_disable_pipe_irq(struct renesas_usb3 *usb3, int num)
|
|||
usb3_clear_bit(usb3, USB_INT_2_PIPE(num), USB3_USB_INT_ENA_2);
|
||||
}
|
||||
|
||||
static bool usb3_is_host(struct renesas_usb3 *usb3)
|
||||
{
|
||||
return !(usb3_read(usb3, USB3_DRD_CON) & DRD_CON_PERI_CON);
|
||||
}
|
||||
|
||||
static void usb3_init_axi_bridge(struct renesas_usb3 *usb3)
|
||||
{
|
||||
/* Set AXI_INT */
|
||||
|
|
@ -362,10 +387,6 @@ static void usb3_init_axi_bridge(struct renesas_usb3 *usb3)
|
|||
|
||||
static void usb3_init_epc_registers(struct renesas_usb3 *usb3)
|
||||
{
|
||||
/* FIXME: How to change host / peripheral mode as well? */
|
||||
usb3_set_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON);
|
||||
usb3_clear_bit(usb3, DRD_CON_VBOUT, USB3_DRD_CON);
|
||||
|
||||
usb3_write(usb3, ~0, USB3_USB_INT_STA_1);
|
||||
usb3_enable_irq_1(usb3, USB_INT_1_VBUS_CNG);
|
||||
}
|
||||
|
|
@ -531,18 +552,70 @@ static void usb3_check_vbus(struct renesas_usb3 *usb3)
|
|||
if (usb3->workaround_for_vbus) {
|
||||
usb3_connect(usb3);
|
||||
} else {
|
||||
if (usb3_read(usb3, USB3_USB_STA) & USB_STA_VBUS_STA)
|
||||
usb3->extcon_usb = !!(usb3_read(usb3, USB3_USB_STA) &
|
||||
USB_STA_VBUS_STA);
|
||||
if (usb3->extcon_usb)
|
||||
usb3_connect(usb3);
|
||||
else
|
||||
usb3_disconnect(usb3);
|
||||
|
||||
schedule_work(&usb3->extcon_work);
|
||||
}
|
||||
}
|
||||
|
||||
static void usb3_set_mode(struct renesas_usb3 *usb3, bool host)
|
||||
{
|
||||
if (host)
|
||||
usb3_clear_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON);
|
||||
else
|
||||
usb3_set_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON);
|
||||
}
|
||||
|
||||
static void usb3_vbus_out(struct renesas_usb3 *usb3, bool enable)
|
||||
{
|
||||
if (enable)
|
||||
usb3_set_bit(usb3, DRD_CON_VBOUT, USB3_DRD_CON);
|
||||
else
|
||||
usb3_clear_bit(usb3, DRD_CON_VBOUT, USB3_DRD_CON);
|
||||
}
|
||||
|
||||
static void usb3_mode_config(struct renesas_usb3 *usb3, bool host, bool a_dev)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&usb3->lock, flags);
|
||||
usb3_set_mode(usb3, host);
|
||||
usb3_vbus_out(usb3, a_dev);
|
||||
if (!host && a_dev) /* for A-Peripheral */
|
||||
usb3_connect(usb3);
|
||||
spin_unlock_irqrestore(&usb3->lock, flags);
|
||||
}
|
||||
|
||||
static bool usb3_is_a_device(struct renesas_usb3 *usb3)
|
||||
{
|
||||
return !(usb3_read(usb3, USB3_USB_OTG_STA) & USB_OTG_IDMON);
|
||||
}
|
||||
|
||||
static void usb3_check_id(struct renesas_usb3 *usb3)
|
||||
{
|
||||
usb3->extcon_host = usb3_is_a_device(usb3);
|
||||
|
||||
if (usb3->extcon_host)
|
||||
usb3_mode_config(usb3, true, true);
|
||||
else
|
||||
usb3_mode_config(usb3, false, false);
|
||||
|
||||
schedule_work(&usb3->extcon_work);
|
||||
}
|
||||
|
||||
static void renesas_usb3_init_controller(struct renesas_usb3 *usb3)
|
||||
{
|
||||
usb3_init_axi_bridge(usb3);
|
||||
usb3_init_epc_registers(usb3);
|
||||
usb3_write(usb3, USB_OTG_IDMON, USB3_USB_OTG_INT_STA);
|
||||
usb3_write(usb3, USB_OTG_IDMON, USB3_USB_OTG_INT_ENA);
|
||||
|
||||
usb3_check_id(usb3);
|
||||
usb3_check_vbus(usb3);
|
||||
}
|
||||
|
||||
|
|
@ -551,6 +624,7 @@ static void renesas_usb3_stop_controller(struct renesas_usb3 *usb3)
|
|||
usb3_disconnect(usb3);
|
||||
usb3_write(usb3, 0, USB3_P0_INT_ENA);
|
||||
usb3_write(usb3, 0, USB3_PN_INT_ENA);
|
||||
usb3_write(usb3, 0, USB3_USB_OTG_INT_ENA);
|
||||
usb3_write(usb3, 0, USB3_USB_INT_ENA_1);
|
||||
usb3_write(usb3, 0, USB3_USB_INT_ENA_2);
|
||||
usb3_write(usb3, 0, USB3_AXI_INT_ENA);
|
||||
|
|
@ -1474,10 +1548,22 @@ static void usb3_irq_epc_int_2(struct renesas_usb3 *usb3, u32 int_sta_2)
|
|||
}
|
||||
}
|
||||
|
||||
static void usb3_irq_idmon_change(struct renesas_usb3 *usb3)
|
||||
{
|
||||
usb3_check_id(usb3);
|
||||
}
|
||||
|
||||
static void usb3_irq_otg_int(struct renesas_usb3 *usb3, u32 otg_int_sta)
|
||||
{
|
||||
if (otg_int_sta & USB_OTG_IDMON)
|
||||
usb3_irq_idmon_change(usb3);
|
||||
}
|
||||
|
||||
static void usb3_irq_epc(struct renesas_usb3 *usb3)
|
||||
{
|
||||
u32 int_sta_1 = usb3_read(usb3, USB3_USB_INT_STA_1);
|
||||
u32 int_sta_2 = usb3_read(usb3, USB3_USB_INT_STA_2);
|
||||
u32 otg_int_sta = usb3_read(usb3, USB3_USB_OTG_INT_STA);
|
||||
|
||||
int_sta_1 &= usb3_read(usb3, USB3_USB_INT_ENA_1);
|
||||
if (int_sta_1) {
|
||||
|
|
@ -1488,6 +1574,12 @@ static void usb3_irq_epc(struct renesas_usb3 *usb3)
|
|||
int_sta_2 &= usb3_read(usb3, USB3_USB_INT_ENA_2);
|
||||
if (int_sta_2)
|
||||
usb3_irq_epc_int_2(usb3, int_sta_2);
|
||||
|
||||
otg_int_sta &= usb3_read(usb3, USB3_USB_OTG_INT_ENA);
|
||||
if (otg_int_sta) {
|
||||
usb3_write(usb3, otg_int_sta, USB3_USB_OTG_INT_STA);
|
||||
usb3_irq_otg_int(usb3, otg_int_sta);
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t renesas_usb3_irq(int irq, void *_usb3)
|
||||
|
|
@ -1756,11 +1848,49 @@ static const struct usb_gadget_ops renesas_usb3_gadget_ops = {
|
|||
.set_selfpowered = renesas_usb3_set_selfpowered,
|
||||
};
|
||||
|
||||
static ssize_t role_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct renesas_usb3 *usb3 = dev_get_drvdata(dev);
|
||||
bool new_mode_is_host;
|
||||
|
||||
if (!usb3->driver)
|
||||
return -ENODEV;
|
||||
|
||||
if (!strncmp(buf, "host", strlen("host")))
|
||||
new_mode_is_host = true;
|
||||
else if (!strncmp(buf, "peripheral", strlen("peripheral")))
|
||||
new_mode_is_host = false;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
if (new_mode_is_host == usb3_is_host(usb3))
|
||||
return -EINVAL;
|
||||
|
||||
usb3_mode_config(usb3, new_mode_is_host, usb3_is_a_device(usb3));
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t role_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct renesas_usb3 *usb3 = dev_get_drvdata(dev);
|
||||
|
||||
if (!usb3->driver)
|
||||
return -ENODEV;
|
||||
|
||||
return sprintf(buf, "%s\n", usb3_is_host(usb3) ? "host" : "peripheral");
|
||||
}
|
||||
static DEVICE_ATTR_RW(role);
|
||||
|
||||
/*------- platform_driver ------------------------------------------------*/
|
||||
static int renesas_usb3_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct renesas_usb3 *usb3 = platform_get_drvdata(pdev);
|
||||
|
||||
device_remove_file(&pdev->dev, &dev_attr_role);
|
||||
|
||||
pm_runtime_put(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
|
|
@ -1894,6 +2024,12 @@ static const struct of_device_id usb3_of_match[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(of, usb3_of_match);
|
||||
|
||||
static const unsigned int renesas_usb3_cable[] = {
|
||||
EXTCON_USB,
|
||||
EXTCON_USB_HOST,
|
||||
EXTCON_NONE,
|
||||
};
|
||||
|
||||
static int renesas_usb3_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct renesas_usb3 *usb3;
|
||||
|
|
@ -1937,6 +2073,17 @@ static int renesas_usb3_probe(struct platform_device *pdev)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
INIT_WORK(&usb3->extcon_work, renesas_usb3_extcon_work);
|
||||
usb3->extcon = devm_extcon_dev_allocate(&pdev->dev, renesas_usb3_cable);
|
||||
if (IS_ERR(usb3->extcon))
|
||||
return PTR_ERR(usb3->extcon);
|
||||
|
||||
ret = devm_extcon_dev_register(&pdev->dev, usb3->extcon);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to register extcon\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* for ep0 handling */
|
||||
usb3->ep0_req = __renesas_usb3_ep_alloc_request(GFP_KERNEL);
|
||||
if (!usb3->ep0_req)
|
||||
|
|
@ -1946,6 +2093,10 @@ static int renesas_usb3_probe(struct platform_device *pdev)
|
|||
if (ret < 0)
|
||||
goto err_add_udc;
|
||||
|
||||
ret = device_create_file(&pdev->dev, &dev_attr_role);
|
||||
if (ret < 0)
|
||||
goto err_dev_create;
|
||||
|
||||
usb3->workaround_for_vbus = priv->workaround_for_vbus;
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
|
@ -1955,6 +2106,9 @@ static int renesas_usb3_probe(struct platform_device *pdev)
|
|||
|
||||
return 0;
|
||||
|
||||
err_dev_create:
|
||||
usb_del_gadget_udc(&usb3->gadget);
|
||||
|
||||
err_add_udc:
|
||||
__renesas_usb3_ep_free_request(usb3->ep0_req);
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ if USB_XHCI_HCD
|
|||
|
||||
config USB_XHCI_PCI
|
||||
tristate
|
||||
depends on PCI
|
||||
depends on USB_PCI
|
||||
default y
|
||||
|
||||
config USB_XHCI_PLATFORM
|
||||
|
|
@ -139,7 +139,7 @@ if USB_EHCI_HCD
|
|||
|
||||
config USB_EHCI_PCI
|
||||
tristate
|
||||
depends on PCI
|
||||
depends on USB_PCI
|
||||
default y
|
||||
|
||||
config USB_EHCI_HCD_PMC_MSP
|
||||
|
|
@ -188,7 +188,7 @@ config USB_EHCI_HCD_OMAP
|
|||
|
||||
config USB_EHCI_HCD_ORION
|
||||
tristate "Support for Marvell EBU on-chip EHCI USB controller"
|
||||
depends on USB_EHCI_HCD && PLAT_ORION
|
||||
depends on USB_EHCI_HCD && (PLAT_ORION || ARCH_MVEBU)
|
||||
default y
|
||||
---help---
|
||||
Enables support for the on-chip EHCI controller on Marvell's
|
||||
|
|
@ -525,7 +525,7 @@ config USB_OHCI_HCD_PPC_OF
|
|||
|
||||
config USB_OHCI_HCD_PCI
|
||||
tristate "OHCI support for PCI-bus USB controllers"
|
||||
depends on PCI
|
||||
depends on USB_PCI
|
||||
default y
|
||||
select USB_OHCI_LITTLE_ENDIAN
|
||||
---help---
|
||||
|
|
@ -606,7 +606,7 @@ endif # USB_OHCI_HCD
|
|||
|
||||
config USB_UHCI_HCD
|
||||
tristate "UHCI HCD (most Intel and VIA) support"
|
||||
depends on PCI || USB_UHCI_SUPPORT_NON_PCI_HC
|
||||
depends on USB_PCI || USB_UHCI_SUPPORT_NON_PCI_HC
|
||||
---help---
|
||||
The Universal Host Controller Interface is a standard by Intel for
|
||||
accessing the USB hardware in the PC (which is also called the USB
|
||||
|
|
@ -739,7 +739,7 @@ config USB_RENESAS_USBHS_HCD
|
|||
|
||||
config USB_WHCI_HCD
|
||||
tristate "Wireless USB Host Controller Interface (WHCI) driver"
|
||||
depends on PCI && USB && UWB
|
||||
depends on USB_PCI && USB && UWB
|
||||
select USB_WUSB
|
||||
select UWB_WHCI
|
||||
help
|
||||
|
|
|
|||
|
|
@ -27,9 +27,7 @@ endif
|
|||
|
||||
obj-$(CONFIG_USB_WHCI_HCD) += whci/
|
||||
|
||||
ifneq ($(CONFIG_USB), )
|
||||
obj-$(CONFIG_PCI) += pci-quirks.o
|
||||
endif
|
||||
obj-$(CONFIG_USB_PCI) += pci-quirks.o
|
||||
|
||||
obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o
|
||||
obj-$(CONFIG_USB_EHCI_PCI) += ehci-pci.o
|
||||
|
|
|
|||
|
|
@ -803,7 +803,7 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
|
|||
size -= temp;
|
||||
next += temp;
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
#ifdef CONFIG_USB_PCI
|
||||
/* EHCI 0.96 and later may have "extended capabilities" */
|
||||
if (dev_is_pci(hcd->self.controller)) {
|
||||
struct pci_dev *pdev;
|
||||
|
|
|
|||
|
|
@ -96,8 +96,8 @@ static int fsl_ehci_drv_probe(struct platform_device *pdev)
|
|||
}
|
||||
irq = res->start;
|
||||
|
||||
hcd = usb_create_hcd(&fsl_ehci_hc_driver, &pdev->dev,
|
||||
dev_name(&pdev->dev));
|
||||
hcd = __usb_create_hcd(&fsl_ehci_hc_driver, pdev->dev.parent,
|
||||
&pdev->dev, dev_name(&pdev->dev), NULL);
|
||||
if (!hcd) {
|
||||
retval = -ENOMEM;
|
||||
goto err1;
|
||||
|
|
|
|||
|
|
@ -597,7 +597,7 @@ static int ehci_run (struct usb_hcd *hcd)
|
|||
/*
|
||||
* hcc_params controls whether ehci->regs->segment must (!!!)
|
||||
* be used; it constrains QH/ITD/SITD and QTD locations.
|
||||
* pci_pool consistent memory always uses segment zero.
|
||||
* dma_pool consistent memory always uses segment zero.
|
||||
* streaming mappings for I/O buffers, like pci_map_single(),
|
||||
* can return segments above 4GB, if the device allows.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ static void ehci_mem_cleanup (struct ehci_hcd *ehci)
|
|||
ehci->sitd_pool = NULL;
|
||||
|
||||
if (ehci->periodic)
|
||||
dma_free_coherent (ehci_to_hcd(ehci)->self.controller,
|
||||
dma_free_coherent(ehci_to_hcd(ehci)->self.sysdev,
|
||||
ehci->periodic_size * sizeof (u32),
|
||||
ehci->periodic, ehci->periodic_dma);
|
||||
ehci->periodic = NULL;
|
||||
|
|
@ -155,7 +155,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
|
|||
|
||||
/* QTDs for control/bulk/intr transfers */
|
||||
ehci->qtd_pool = dma_pool_create ("ehci_qtd",
|
||||
ehci_to_hcd(ehci)->self.controller,
|
||||
ehci_to_hcd(ehci)->self.sysdev,
|
||||
sizeof (struct ehci_qtd),
|
||||
32 /* byte alignment (for hw parts) */,
|
||||
4096 /* can't cross 4K */);
|
||||
|
|
@ -165,7 +165,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
|
|||
|
||||
/* QHs for control/bulk/intr transfers */
|
||||
ehci->qh_pool = dma_pool_create ("ehci_qh",
|
||||
ehci_to_hcd(ehci)->self.controller,
|
||||
ehci_to_hcd(ehci)->self.sysdev,
|
||||
sizeof(struct ehci_qh_hw),
|
||||
32 /* byte alignment (for hw parts) */,
|
||||
4096 /* can't cross 4K */);
|
||||
|
|
@ -179,7 +179,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
|
|||
|
||||
/* ITD for high speed ISO transfers */
|
||||
ehci->itd_pool = dma_pool_create ("ehci_itd",
|
||||
ehci_to_hcd(ehci)->self.controller,
|
||||
ehci_to_hcd(ehci)->self.sysdev,
|
||||
sizeof (struct ehci_itd),
|
||||
32 /* byte alignment (for hw parts) */,
|
||||
4096 /* can't cross 4K */);
|
||||
|
|
@ -189,7 +189,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
|
|||
|
||||
/* SITD for full/low speed split ISO transfers */
|
||||
ehci->sitd_pool = dma_pool_create ("ehci_sitd",
|
||||
ehci_to_hcd(ehci)->self.controller,
|
||||
ehci_to_hcd(ehci)->self.sysdev,
|
||||
sizeof (struct ehci_sitd),
|
||||
32 /* byte alignment (for hw parts) */,
|
||||
4096 /* can't cross 4K */);
|
||||
|
|
@ -199,7 +199,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
|
|||
|
||||
/* Hardware periodic table */
|
||||
ehci->periodic = (__le32 *)
|
||||
dma_alloc_coherent (ehci_to_hcd(ehci)->self.controller,
|
||||
dma_alloc_coherent(ehci_to_hcd(ehci)->self.sysdev,
|
||||
ehci->periodic_size * sizeof(__le32),
|
||||
&ehci->periodic_dma, flags);
|
||||
if (ehci->periodic == NULL) {
|
||||
|
|
|
|||
|
|
@ -47,6 +47,18 @@
|
|||
#define USB_PHY_IVREF_CTRL 0x440
|
||||
#define USB_PHY_TST_GRP_CTRL 0x450
|
||||
|
||||
#define USB_SBUSCFG 0x90
|
||||
|
||||
/* BAWR = BARD = 3 : Align read/write bursts packets larger than 128 bytes */
|
||||
#define USB_SBUSCFG_BAWR_ALIGN_128B (0x3 << 6)
|
||||
#define USB_SBUSCFG_BARD_ALIGN_128B (0x3 << 3)
|
||||
/* AHBBRST = 3 : Align AHB Burst to INCR16 (64 bytes) */
|
||||
#define USB_SBUSCFG_AHBBRST_INCR16 (0x3 << 0)
|
||||
|
||||
#define USB_SBUSCFG_DEF_VAL (USB_SBUSCFG_BAWR_ALIGN_128B \
|
||||
| USB_SBUSCFG_BARD_ALIGN_128B \
|
||||
| USB_SBUSCFG_AHBBRST_INCR16)
|
||||
|
||||
#define DRIVER_DESC "EHCI orion driver"
|
||||
|
||||
#define hcd_to_orion_priv(h) ((struct orion_ehci_hcd *)hcd_to_ehci(h)->priv)
|
||||
|
|
@ -151,8 +163,31 @@ ehci_orion_conf_mbus_windows(struct usb_hcd *hcd,
|
|||
}
|
||||
}
|
||||
|
||||
static int ehci_orion_drv_reset(struct usb_hcd *hcd)
|
||||
{
|
||||
struct device *dev = hcd->self.controller;
|
||||
int ret;
|
||||
|
||||
ret = ehci_setup(hcd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* For SoC without hlock, need to program sbuscfg value to guarantee
|
||||
* AHB master's burst would not overrun or underrun FIFO.
|
||||
*
|
||||
* sbuscfg reg has to be set after usb controller reset, otherwise
|
||||
* the value would be override to 0.
|
||||
*/
|
||||
if (of_device_is_compatible(dev->of_node, "marvell,armada-3700-ehci"))
|
||||
wrl(USB_SBUSCFG, USB_SBUSCFG_DEF_VAL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct ehci_driver_overrides orion_overrides __initconst = {
|
||||
.extra_priv_size = sizeof(struct orion_ehci_hcd),
|
||||
.reset = ehci_orion_drv_reset,
|
||||
};
|
||||
|
||||
static int ehci_orion_drv_probe(struct platform_device *pdev)
|
||||
|
|
@ -310,6 +345,7 @@ static int ehci_orion_drv_remove(struct platform_device *pdev)
|
|||
|
||||
static const struct of_device_id ehci_orion_dt_ids[] = {
|
||||
{ .compatible = "marvell,orion-ehci", },
|
||||
{ .compatible = "marvell,armada-3700-ehci", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ehci_orion_dt_ids);
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include <linux/usb.h>
|
||||
#include <linux/usb/hcd.h>
|
||||
#include <linux/usb/ehci_pdriver.h>
|
||||
#include <linux/usb/of.h>
|
||||
|
||||
#include "ehci.h"
|
||||
|
||||
|
|
@ -220,6 +221,9 @@ static int ehci_platform_probe(struct platform_device *dev)
|
|||
if (IS_ERR(priv->phys[phy_num])) {
|
||||
err = PTR_ERR(priv->phys[phy_num]);
|
||||
goto err_put_hcd;
|
||||
} else if (!hcd->phy) {
|
||||
/* Avoiding phy_get() in usb_add_hcd() */
|
||||
hcd->phy = priv->phys[phy_num];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -297,6 +301,7 @@ static int ehci_platform_probe(struct platform_device *dev)
|
|||
goto err_power;
|
||||
|
||||
device_wakeup_enable(hcd->self.controller);
|
||||
device_enable_async_suspend(hcd->self.controller);
|
||||
platform_set_drvdata(dev, hcd);
|
||||
|
||||
return err;
|
||||
|
|
@ -370,6 +375,7 @@ static int ehci_platform_resume(struct device *dev)
|
|||
struct usb_ehci_pdata *pdata = dev_get_platdata(dev);
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd);
|
||||
struct device *companion_dev;
|
||||
|
||||
if (pdata->power_on) {
|
||||
int err = pdata->power_on(pdev);
|
||||
|
|
@ -377,6 +383,10 @@ static int ehci_platform_resume(struct device *dev)
|
|||
return err;
|
||||
}
|
||||
|
||||
companion_dev = usb_of_get_companion_dev(hcd->self.controller);
|
||||
if (companion_dev)
|
||||
device_pm_wait_for_dev(hcd->self.controller, companion_dev);
|
||||
|
||||
ehci_resume(hcd, priv->reset_on_resume);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5047,7 +5047,7 @@ static int fotg210_run(struct usb_hcd *hcd)
|
|||
/*
|
||||
* hcc_params controls whether fotg210->regs->segment must (!!!)
|
||||
* be used; it constrains QH/ITD/SITD and QTD locations.
|
||||
* pci_pool consistent memory always uses segment zero.
|
||||
* dma_pool consistent memory always uses segment zero.
|
||||
* streaming mappings for I/O buffers, like pci_map_single(),
|
||||
* can return segments above 4GB, if the device allows.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -231,7 +231,8 @@ static int ohci_urb_enqueue (
|
|||
|
||||
/* Start up the I/O watchdog timer, if it's not running */
|
||||
if (!timer_pending(&ohci->io_watchdog) &&
|
||||
list_empty(&ohci->eds_in_use)) {
|
||||
list_empty(&ohci->eds_in_use) &&
|
||||
!(ohci->flags & OHCI_QUIRK_QEMU)) {
|
||||
ohci->prev_frame_no = ohci_frame_no(ohci);
|
||||
mod_timer(&ohci->io_watchdog,
|
||||
jiffies + IO_WATCHDOG_DELAY);
|
||||
|
|
@ -994,7 +995,7 @@ static void ohci_stop (struct usb_hcd *hcd)
|
|||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#if defined(CONFIG_PM) || defined(CONFIG_PCI)
|
||||
#if defined(CONFIG_PM) || defined(CONFIG_USB_PCI)
|
||||
|
||||
/* must not be called from interrupt context */
|
||||
int ohci_restart(struct ohci_hcd *ohci)
|
||||
|
|
|
|||
|
|
@ -164,6 +164,15 @@ static int ohci_quirk_amd700(struct usb_hcd *hcd)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ohci_quirk_qemu(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
|
||||
|
||||
ohci->flags |= OHCI_QUIRK_QEMU;
|
||||
ohci_dbg(ohci, "enabled qemu quirk\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* List of quirks for OHCI */
|
||||
static const struct pci_device_id ohci_pci_quirks[] = {
|
||||
{
|
||||
|
|
@ -214,6 +223,13 @@ static const struct pci_device_id ohci_pci_quirks[] = {
|
|||
PCI_DEVICE(PCI_VENDOR_ID_ATI, 0x4399),
|
||||
.driver_data = (unsigned long)ohci_quirk_amd700,
|
||||
},
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_APPLE,
|
||||
.device = 0x003f,
|
||||
.subvendor = PCI_SUBVENDOR_ID_REDHAT_QUMRANET,
|
||||
.subdevice = PCI_SUBDEVICE_ID_QEMU,
|
||||
.driver_data = (unsigned long)ohci_quirk_qemu,
|
||||
},
|
||||
|
||||
/* FIXME for some of the early AMD 760 southbridges, OHCI
|
||||
* won't work at all. blacklist them.
|
||||
|
|
|
|||
|
|
@ -183,6 +183,9 @@ static int ohci_platform_probe(struct platform_device *dev)
|
|||
if (IS_ERR(priv->phys[phy_num])) {
|
||||
err = PTR_ERR(priv->phys[phy_num]);
|
||||
goto err_put_hcd;
|
||||
} else if (!hcd->phy) {
|
||||
/* Avoiding phy_get() in usb_add_hcd() */
|
||||
hcd->phy = priv->phys[phy_num];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -418,6 +418,7 @@ struct ohci_hcd {
|
|||
#define OHCI_QUIRK_AMD_PLL 0x200 /* AMD PLL quirk*/
|
||||
#define OHCI_QUIRK_AMD_PREFETCH 0x400 /* pre-fetch for ISO transfer */
|
||||
#define OHCI_QUIRK_GLOBAL_SUSPEND 0x800 /* must suspend ports */
|
||||
#define OHCI_QUIRK_QEMU 0x1000 /* relax timing expectations */
|
||||
|
||||
// there are also chip quirks/bugs in init logic
|
||||
|
||||
|
|
@ -438,7 +439,7 @@ struct ohci_hcd {
|
|||
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
#ifdef CONFIG_USB_PCI
|
||||
static inline int quirk_nec(struct ohci_hcd *ohci)
|
||||
{
|
||||
return ohci->flags & OHCI_QUIRK_NEC;
|
||||
|
|
|
|||
|
|
@ -2708,7 +2708,7 @@ static int oxu_run(struct usb_hcd *hcd)
|
|||
|
||||
/* hcc_params controls whether oxu->regs->segment must (!!!)
|
||||
* be used; it constrains QH/ITD/SITD and QTD locations.
|
||||
* pci_pool consistent memory always uses segment zero.
|
||||
* dma_pool consistent memory always uses segment zero.
|
||||
* streaming mappings for I/O buffers, like pci_map_single(),
|
||||
* can return segments above 4GB, if the device allows.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef __LINUX_USB_PCI_QUIRKS_H
|
||||
#define __LINUX_USB_PCI_QUIRKS_H
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
#ifdef CONFIG_USB_PCI
|
||||
void uhci_reset_hc(struct pci_dev *pdev, unsigned long base);
|
||||
int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base);
|
||||
int usb_amd_find_chipset_info(void);
|
||||
|
|
@ -21,6 +21,6 @@ static inline void usb_amd_quirk_pll_enable(void) {}
|
|||
static inline void usb_amd_dev_put(void) {}
|
||||
static inline void usb_disable_xhci_ports(struct pci_dev *xhci_pdev) {}
|
||||
static inline void sb800_prefetch(struct device *dev, int on) {}
|
||||
#endif /* CONFIG_PCI */
|
||||
#endif /* CONFIG_USB_PCI */
|
||||
|
||||
#endif /* __LINUX_USB_PCI_QUIRKS_H */
|
||||
|
|
|
|||
|
|
@ -837,7 +837,7 @@ static int uhci_count_ports(struct usb_hcd *hcd)
|
|||
|
||||
static const char hcd_name[] = "uhci_hcd";
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
#ifdef CONFIG_USB_PCI
|
||||
#include "uhci-pci.c"
|
||||
#define PCI_DRIVER uhci_pci_driver
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -530,7 +530,7 @@ static inline void uhci_writeb(const struct uhci_hcd *uhci, u8 val, int reg)
|
|||
|
||||
#else
|
||||
/* Support non-PCI host controllers */
|
||||
#ifdef CONFIG_PCI
|
||||
#ifdef CONFIG_USB_PCI
|
||||
/* Support PCI and non-PCI host controllers */
|
||||
#define uhci_has_pci_registers(u) ((u)->io_addr != 0)
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -254,157 +254,6 @@ void xhci_print_registers(struct xhci_hcd *xhci)
|
|||
xhci_print_ports(xhci);
|
||||
}
|
||||
|
||||
void xhci_print_trb_offsets(struct xhci_hcd *xhci, union xhci_trb *trb)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 4; i++)
|
||||
xhci_dbg(xhci, "Offset 0x%x = 0x%x\n",
|
||||
i*4, trb->generic.field[i]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Debug a transfer request block (TRB).
|
||||
*/
|
||||
void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb)
|
||||
{
|
||||
u64 address;
|
||||
u32 type = le32_to_cpu(trb->link.control) & TRB_TYPE_BITMASK;
|
||||
|
||||
switch (type) {
|
||||
case TRB_TYPE(TRB_LINK):
|
||||
xhci_dbg(xhci, "Link TRB:\n");
|
||||
xhci_print_trb_offsets(xhci, trb);
|
||||
|
||||
address = le64_to_cpu(trb->link.segment_ptr);
|
||||
xhci_dbg(xhci, "Next ring segment DMA address = 0x%llx\n", address);
|
||||
|
||||
xhci_dbg(xhci, "Interrupter target = 0x%x\n",
|
||||
GET_INTR_TARGET(le32_to_cpu(trb->link.intr_target)));
|
||||
xhci_dbg(xhci, "Cycle bit = %u\n",
|
||||
le32_to_cpu(trb->link.control) & TRB_CYCLE);
|
||||
xhci_dbg(xhci, "Toggle cycle bit = %u\n",
|
||||
le32_to_cpu(trb->link.control) & LINK_TOGGLE);
|
||||
xhci_dbg(xhci, "No Snoop bit = %u\n",
|
||||
le32_to_cpu(trb->link.control) & TRB_NO_SNOOP);
|
||||
break;
|
||||
case TRB_TYPE(TRB_TRANSFER):
|
||||
address = le64_to_cpu(trb->trans_event.buffer);
|
||||
/*
|
||||
* FIXME: look at flags to figure out if it's an address or if
|
||||
* the data is directly in the buffer field.
|
||||
*/
|
||||
xhci_dbg(xhci, "DMA address or buffer contents= %llu\n", address);
|
||||
break;
|
||||
case TRB_TYPE(TRB_COMPLETION):
|
||||
address = le64_to_cpu(trb->event_cmd.cmd_trb);
|
||||
xhci_dbg(xhci, "Command TRB pointer = %llu\n", address);
|
||||
xhci_dbg(xhci, "Completion status = %u\n",
|
||||
GET_COMP_CODE(le32_to_cpu(trb->event_cmd.status)));
|
||||
xhci_dbg(xhci, "Flags = 0x%x\n",
|
||||
le32_to_cpu(trb->event_cmd.flags));
|
||||
break;
|
||||
default:
|
||||
xhci_dbg(xhci, "Unknown TRB with TRB type ID %u\n",
|
||||
(unsigned int) type>>10);
|
||||
xhci_print_trb_offsets(xhci, trb);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Debug a segment with an xHCI ring.
|
||||
*
|
||||
* @return The Link TRB of the segment, or NULL if there is no Link TRB
|
||||
* (which is a bug, since all segments must have a Link TRB).
|
||||
*
|
||||
* Prints out all TRBs in the segment, even those after the Link TRB.
|
||||
*
|
||||
* XXX: should we print out TRBs that the HC owns? As long as we don't
|
||||
* write, that should be fine... We shouldn't expect that the memory pointed to
|
||||
* by the TRB is valid at all. Do we care about ones the HC owns? Probably,
|
||||
* for HC debugging.
|
||||
*/
|
||||
void xhci_debug_segment(struct xhci_hcd *xhci, struct xhci_segment *seg)
|
||||
{
|
||||
int i;
|
||||
u64 addr = seg->dma;
|
||||
union xhci_trb *trb = seg->trbs;
|
||||
|
||||
for (i = 0; i < TRBS_PER_SEGMENT; i++) {
|
||||
trb = &seg->trbs[i];
|
||||
xhci_dbg(xhci, "@%016llx %08x %08x %08x %08x\n", addr,
|
||||
lower_32_bits(le64_to_cpu(trb->link.segment_ptr)),
|
||||
upper_32_bits(le64_to_cpu(trb->link.segment_ptr)),
|
||||
le32_to_cpu(trb->link.intr_target),
|
||||
le32_to_cpu(trb->link.control));
|
||||
addr += sizeof(*trb);
|
||||
}
|
||||
}
|
||||
|
||||
void xhci_dbg_ring_ptrs(struct xhci_hcd *xhci, struct xhci_ring *ring)
|
||||
{
|
||||
xhci_dbg(xhci, "Ring deq = %p (virt), 0x%llx (dma)\n",
|
||||
ring->dequeue,
|
||||
(unsigned long long)xhci_trb_virt_to_dma(ring->deq_seg,
|
||||
ring->dequeue));
|
||||
xhci_dbg(xhci, "Ring deq updated %u times\n",
|
||||
ring->deq_updates);
|
||||
xhci_dbg(xhci, "Ring enq = %p (virt), 0x%llx (dma)\n",
|
||||
ring->enqueue,
|
||||
(unsigned long long)xhci_trb_virt_to_dma(ring->enq_seg,
|
||||
ring->enqueue));
|
||||
xhci_dbg(xhci, "Ring enq updated %u times\n",
|
||||
ring->enq_updates);
|
||||
}
|
||||
|
||||
/**
|
||||
* Debugging for an xHCI ring, which is a queue broken into multiple segments.
|
||||
*
|
||||
* Print out each segment in the ring. Check that the DMA address in
|
||||
* each link segment actually matches the segment's stored DMA address.
|
||||
* Check that the link end bit is only set at the end of the ring.
|
||||
* Check that the dequeue and enqueue pointers point to real data in this ring
|
||||
* (not some other ring).
|
||||
*/
|
||||
void xhci_debug_ring(struct xhci_hcd *xhci, struct xhci_ring *ring)
|
||||
{
|
||||
/* FIXME: Throw an error if any segment doesn't have a Link TRB */
|
||||
struct xhci_segment *seg;
|
||||
struct xhci_segment *first_seg = ring->first_seg;
|
||||
xhci_debug_segment(xhci, first_seg);
|
||||
|
||||
if (!ring->enq_updates && !ring->deq_updates) {
|
||||
xhci_dbg(xhci, " Ring has not been updated\n");
|
||||
return;
|
||||
}
|
||||
for (seg = first_seg->next; seg != first_seg; seg = seg->next)
|
||||
xhci_debug_segment(xhci, seg);
|
||||
}
|
||||
|
||||
void xhci_dbg_ep_rings(struct xhci_hcd *xhci,
|
||||
unsigned int slot_id, unsigned int ep_index,
|
||||
struct xhci_virt_ep *ep)
|
||||
{
|
||||
int i;
|
||||
struct xhci_ring *ring;
|
||||
|
||||
if (ep->ep_state & EP_HAS_STREAMS) {
|
||||
for (i = 1; i < ep->stream_info->num_streams; i++) {
|
||||
ring = ep->stream_info->stream_rings[i];
|
||||
xhci_dbg(xhci, "Dev %d endpoint %d stream ID %d:\n",
|
||||
slot_id, ep_index, i);
|
||||
xhci_debug_segment(xhci, ring->deq_seg);
|
||||
}
|
||||
} else {
|
||||
ring = ep->ring;
|
||||
if (!ring)
|
||||
return;
|
||||
xhci_dbg(xhci, "Dev %d endpoint ring %d:\n",
|
||||
slot_id, ep_index);
|
||||
xhci_debug_segment(xhci, ring->deq_seg);
|
||||
}
|
||||
}
|
||||
|
||||
void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst)
|
||||
{
|
||||
u64 addr = erst->erst_dma_addr;
|
||||
|
|
@ -434,166 +283,13 @@ void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci)
|
|||
upper_32_bits(val));
|
||||
}
|
||||
|
||||
/* Print the last 32 bytes for 64-byte contexts */
|
||||
static void dbg_rsvd64(struct xhci_hcd *xhci, u64 *ctx, dma_addr_t dma)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 4; i++) {
|
||||
xhci_dbg(xhci, "@%p (virt) @%08llx "
|
||||
"(dma) %#08llx - rsvd64[%d]\n",
|
||||
&ctx[4 + i], (unsigned long long)dma,
|
||||
ctx[4 + i], i);
|
||||
dma += 8;
|
||||
}
|
||||
}
|
||||
|
||||
char *xhci_get_slot_state(struct xhci_hcd *xhci,
|
||||
struct xhci_container_ctx *ctx)
|
||||
{
|
||||
struct xhci_slot_ctx *slot_ctx = xhci_get_slot_ctx(xhci, ctx);
|
||||
int state = GET_SLOT_STATE(le32_to_cpu(slot_ctx->dev_state));
|
||||
|
||||
switch (GET_SLOT_STATE(le32_to_cpu(slot_ctx->dev_state))) {
|
||||
case SLOT_STATE_ENABLED:
|
||||
return "enabled/disabled";
|
||||
case SLOT_STATE_DEFAULT:
|
||||
return "default";
|
||||
case SLOT_STATE_ADDRESSED:
|
||||
return "addressed";
|
||||
case SLOT_STATE_CONFIGURED:
|
||||
return "configured";
|
||||
default:
|
||||
return "reserved";
|
||||
}
|
||||
}
|
||||
|
||||
static void xhci_dbg_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx)
|
||||
{
|
||||
/* Fields are 32 bits wide, DMA addresses are in bytes */
|
||||
int field_size = 32 / 8;
|
||||
int i;
|
||||
|
||||
struct xhci_slot_ctx *slot_ctx = xhci_get_slot_ctx(xhci, ctx);
|
||||
dma_addr_t dma = ctx->dma +
|
||||
((unsigned long)slot_ctx - (unsigned long)ctx->bytes);
|
||||
int csz = HCC_64BYTE_CONTEXT(xhci->hcc_params);
|
||||
|
||||
xhci_dbg(xhci, "Slot Context:\n");
|
||||
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_info\n",
|
||||
&slot_ctx->dev_info,
|
||||
(unsigned long long)dma, slot_ctx->dev_info);
|
||||
dma += field_size;
|
||||
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_info2\n",
|
||||
&slot_ctx->dev_info2,
|
||||
(unsigned long long)dma, slot_ctx->dev_info2);
|
||||
dma += field_size;
|
||||
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - tt_info\n",
|
||||
&slot_ctx->tt_info,
|
||||
(unsigned long long)dma, slot_ctx->tt_info);
|
||||
dma += field_size;
|
||||
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_state\n",
|
||||
&slot_ctx->dev_state,
|
||||
(unsigned long long)dma, slot_ctx->dev_state);
|
||||
dma += field_size;
|
||||
for (i = 0; i < 4; i++) {
|
||||
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n",
|
||||
&slot_ctx->reserved[i], (unsigned long long)dma,
|
||||
slot_ctx->reserved[i], i);
|
||||
dma += field_size;
|
||||
}
|
||||
|
||||
if (csz)
|
||||
dbg_rsvd64(xhci, (u64 *)slot_ctx, dma);
|
||||
}
|
||||
|
||||
static void xhci_dbg_ep_ctx(struct xhci_hcd *xhci,
|
||||
struct xhci_container_ctx *ctx,
|
||||
unsigned int last_ep)
|
||||
{
|
||||
int i, j;
|
||||
int last_ep_ctx = 31;
|
||||
/* Fields are 32 bits wide, DMA addresses are in bytes */
|
||||
int field_size = 32 / 8;
|
||||
int csz = HCC_64BYTE_CONTEXT(xhci->hcc_params);
|
||||
|
||||
if (last_ep < 31)
|
||||
last_ep_ctx = last_ep + 1;
|
||||
for (i = 0; i < last_ep_ctx; i++) {
|
||||
unsigned int epaddr = xhci_get_endpoint_address(i);
|
||||
struct xhci_ep_ctx *ep_ctx = xhci_get_ep_ctx(xhci, ctx, i);
|
||||
dma_addr_t dma = ctx->dma +
|
||||
((unsigned long)ep_ctx - (unsigned long)ctx->bytes);
|
||||
|
||||
xhci_dbg(xhci, "%s Endpoint %02d Context (ep_index %02d):\n",
|
||||
usb_endpoint_out(epaddr) ? "OUT" : "IN",
|
||||
epaddr & USB_ENDPOINT_NUMBER_MASK, i);
|
||||
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - ep_info\n",
|
||||
&ep_ctx->ep_info,
|
||||
(unsigned long long)dma, ep_ctx->ep_info);
|
||||
dma += field_size;
|
||||
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - ep_info2\n",
|
||||
&ep_ctx->ep_info2,
|
||||
(unsigned long long)dma, ep_ctx->ep_info2);
|
||||
dma += field_size;
|
||||
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08llx - deq\n",
|
||||
&ep_ctx->deq,
|
||||
(unsigned long long)dma, ep_ctx->deq);
|
||||
dma += 2*field_size;
|
||||
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - tx_info\n",
|
||||
&ep_ctx->tx_info,
|
||||
(unsigned long long)dma, ep_ctx->tx_info);
|
||||
dma += field_size;
|
||||
for (j = 0; j < 3; j++) {
|
||||
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n",
|
||||
&ep_ctx->reserved[j],
|
||||
(unsigned long long)dma,
|
||||
ep_ctx->reserved[j], j);
|
||||
dma += field_size;
|
||||
}
|
||||
|
||||
if (csz)
|
||||
dbg_rsvd64(xhci, (u64 *)ep_ctx, dma);
|
||||
}
|
||||
}
|
||||
|
||||
void xhci_dbg_ctx(struct xhci_hcd *xhci,
|
||||
struct xhci_container_ctx *ctx,
|
||||
unsigned int last_ep)
|
||||
{
|
||||
int i;
|
||||
/* Fields are 32 bits wide, DMA addresses are in bytes */
|
||||
int field_size = 32 / 8;
|
||||
dma_addr_t dma = ctx->dma;
|
||||
int csz = HCC_64BYTE_CONTEXT(xhci->hcc_params);
|
||||
|
||||
if (ctx->type == XHCI_CTX_TYPE_INPUT) {
|
||||
struct xhci_input_control_ctx *ctrl_ctx =
|
||||
xhci_get_input_control_ctx(ctx);
|
||||
if (!ctrl_ctx) {
|
||||
xhci_warn(xhci, "Could not get input context, bad type.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - drop flags\n",
|
||||
&ctrl_ctx->drop_flags, (unsigned long long)dma,
|
||||
ctrl_ctx->drop_flags);
|
||||
dma += field_size;
|
||||
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - add flags\n",
|
||||
&ctrl_ctx->add_flags, (unsigned long long)dma,
|
||||
ctrl_ctx->add_flags);
|
||||
dma += field_size;
|
||||
for (i = 0; i < 6; i++) {
|
||||
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd2[%d]\n",
|
||||
&ctrl_ctx->rsvd2[i], (unsigned long long)dma,
|
||||
ctrl_ctx->rsvd2[i], i);
|
||||
dma += field_size;
|
||||
}
|
||||
|
||||
if (csz)
|
||||
dbg_rsvd64(xhci, (u64 *)ctrl_ctx, dma);
|
||||
}
|
||||
|
||||
xhci_dbg_slot_ctx(xhci, ctx);
|
||||
xhci_dbg_ep_ctx(xhci, ctx, last_ep);
|
||||
return xhci_slot_state_string(state);
|
||||
}
|
||||
|
||||
void xhci_dbg_trace(struct xhci_hcd *xhci, void (*trace)(struct va_format *),
|
||||
|
|
|
|||
|
|
@ -392,10 +392,8 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend)
|
|||
trace_xhci_stop_device(virt_dev);
|
||||
|
||||
cmd = xhci_alloc_command(xhci, false, true, GFP_NOIO);
|
||||
if (!cmd) {
|
||||
xhci_dbg(xhci, "Couldn't allocate command structure.\n");
|
||||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
for (i = LAST_EP_INDEX; i > 0; i--) {
|
||||
|
|
@ -540,6 +538,119 @@ static int xhci_get_ports(struct usb_hcd *hcd, __le32 __iomem ***port_array)
|
|||
return max_ports;
|
||||
}
|
||||
|
||||
static __le32 __iomem *xhci_get_port_io_addr(struct usb_hcd *hcd, int index)
|
||||
{
|
||||
__le32 __iomem **port_array;
|
||||
|
||||
xhci_get_ports(hcd, &port_array);
|
||||
return port_array[index];
|
||||
}
|
||||
|
||||
/*
|
||||
* xhci_set_port_power() must be called with xhci->lock held.
|
||||
* It will release and re-aquire the lock while calling ACPI
|
||||
* method.
|
||||
*/
|
||||
static void xhci_set_port_power(struct xhci_hcd *xhci, struct usb_hcd *hcd,
|
||||
u16 index, bool on, unsigned long *flags)
|
||||
{
|
||||
__le32 __iomem *addr;
|
||||
u32 temp;
|
||||
|
||||
addr = xhci_get_port_io_addr(hcd, index);
|
||||
temp = readl(addr);
|
||||
temp = xhci_port_state_to_neutral(temp);
|
||||
if (on) {
|
||||
/* Power on */
|
||||
writel(temp | PORT_POWER, addr);
|
||||
temp = readl(addr);
|
||||
xhci_dbg(xhci, "set port power, actual port %d status = 0x%x\n",
|
||||
index, temp);
|
||||
} else {
|
||||
/* Power off */
|
||||
writel(temp & ~PORT_POWER, addr);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&xhci->lock, *flags);
|
||||
temp = usb_acpi_power_manageable(hcd->self.root_hub,
|
||||
index);
|
||||
if (temp)
|
||||
usb_acpi_set_power_state(hcd->self.root_hub,
|
||||
index, on);
|
||||
spin_lock_irqsave(&xhci->lock, *flags);
|
||||
}
|
||||
|
||||
static void xhci_port_set_test_mode(struct xhci_hcd *xhci,
|
||||
u16 test_mode, u16 wIndex)
|
||||
{
|
||||
u32 temp;
|
||||
__le32 __iomem *addr;
|
||||
|
||||
/* xhci only supports test mode for usb2 ports, i.e. xhci->main_hcd */
|
||||
addr = xhci_get_port_io_addr(xhci->main_hcd, wIndex);
|
||||
temp = readl(addr + PORTPMSC);
|
||||
temp |= test_mode << PORT_TEST_MODE_SHIFT;
|
||||
writel(temp, addr + PORTPMSC);
|
||||
xhci->test_mode = test_mode;
|
||||
if (test_mode == TEST_FORCE_EN)
|
||||
xhci_start(xhci);
|
||||
}
|
||||
|
||||
static int xhci_enter_test_mode(struct xhci_hcd *xhci,
|
||||
u16 test_mode, u16 wIndex, unsigned long *flags)
|
||||
{
|
||||
int i, retval;
|
||||
|
||||
/* Disable all Device Slots */
|
||||
xhci_dbg(xhci, "Disable all slots\n");
|
||||
for (i = 1; i <= HCS_MAX_SLOTS(xhci->hcs_params1); i++) {
|
||||
retval = xhci_disable_slot(xhci, NULL, i);
|
||||
if (retval)
|
||||
xhci_err(xhci, "Failed to disable slot %d, %d. Enter test mode anyway\n",
|
||||
i, retval);
|
||||
}
|
||||
/* Put all ports to the Disable state by clear PP */
|
||||
xhci_dbg(xhci, "Disable all port (PP = 0)\n");
|
||||
/* Power off USB3 ports*/
|
||||
for (i = 0; i < xhci->num_usb3_ports; i++)
|
||||
xhci_set_port_power(xhci, xhci->shared_hcd, i, false, flags);
|
||||
/* Power off USB2 ports*/
|
||||
for (i = 0; i < xhci->num_usb2_ports; i++)
|
||||
xhci_set_port_power(xhci, xhci->main_hcd, i, false, flags);
|
||||
/* Stop the controller */
|
||||
xhci_dbg(xhci, "Stop controller\n");
|
||||
retval = xhci_halt(xhci);
|
||||
if (retval)
|
||||
return retval;
|
||||
/* Disable runtime PM for test mode */
|
||||
pm_runtime_forbid(xhci_to_hcd(xhci)->self.controller);
|
||||
/* Set PORTPMSC.PTC field to enter selected test mode */
|
||||
/* Port is selected by wIndex. port_id = wIndex + 1 */
|
||||
xhci_dbg(xhci, "Enter Test Mode: %d, Port_id=%d\n",
|
||||
test_mode, wIndex + 1);
|
||||
xhci_port_set_test_mode(xhci, test_mode, wIndex);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int xhci_exit_test_mode(struct xhci_hcd *xhci)
|
||||
{
|
||||
int retval;
|
||||
|
||||
if (!xhci->test_mode) {
|
||||
xhci_err(xhci, "Not in test mode, do nothing.\n");
|
||||
return 0;
|
||||
}
|
||||
if (xhci->test_mode == TEST_FORCE_EN &&
|
||||
!(xhci->xhc_state & XHCI_STATE_HALTED)) {
|
||||
retval = xhci_halt(xhci);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
pm_runtime_allow(xhci_to_hcd(xhci)->self.controller);
|
||||
xhci->test_mode = 0;
|
||||
return xhci_reset(xhci);
|
||||
}
|
||||
|
||||
void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array,
|
||||
int port_id, u32 link_state)
|
||||
{
|
||||
|
|
@ -895,6 +1006,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
u16 link_state = 0;
|
||||
u16 wake_mask = 0;
|
||||
u16 timeout = 0;
|
||||
u16 test_mode = 0;
|
||||
|
||||
max_ports = xhci_get_ports(hcd, &port_array);
|
||||
bus_state = &xhci->bus_state[hcd_index(hcd)];
|
||||
|
|
@ -935,7 +1047,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
goto error;
|
||||
wIndex--;
|
||||
temp = readl(port_array[wIndex]);
|
||||
if (temp == 0xffffffff) {
|
||||
if (temp == ~(u32)0) {
|
||||
xhci_hc_died(xhci);
|
||||
retval = -ENODEV;
|
||||
break;
|
||||
}
|
||||
|
|
@ -968,6 +1081,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
link_state = (wIndex & 0xff00) >> 3;
|
||||
if (wValue == USB_PORT_FEAT_REMOTE_WAKE_MASK)
|
||||
wake_mask = wIndex & 0xff00;
|
||||
if (wValue == USB_PORT_FEAT_TEST)
|
||||
test_mode = (wIndex & 0xff00) >> 8;
|
||||
/* The MSB of wIndex is the U1/U2 timeout */
|
||||
timeout = (wIndex & 0xff00) >> 8;
|
||||
wIndex &= 0xff;
|
||||
|
|
@ -975,7 +1090,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
goto error;
|
||||
wIndex--;
|
||||
temp = readl(port_array[wIndex]);
|
||||
if (temp == 0xffffffff) {
|
||||
if (temp == ~(u32)0) {
|
||||
xhci_hc_died(xhci);
|
||||
retval = -ENODEV;
|
||||
break;
|
||||
}
|
||||
|
|
@ -1092,18 +1208,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
* However, hub_wq will ignore the roothub events until
|
||||
* the roothub is registered.
|
||||
*/
|
||||
writel(temp | PORT_POWER, port_array[wIndex]);
|
||||
|
||||
temp = readl(port_array[wIndex]);
|
||||
xhci_dbg(xhci, "set port power, actual port %d status = 0x%x\n", wIndex, temp);
|
||||
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
temp = usb_acpi_power_manageable(hcd->self.root_hub,
|
||||
wIndex);
|
||||
if (temp)
|
||||
usb_acpi_set_power_state(hcd->self.root_hub,
|
||||
wIndex, true);
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
xhci_set_port_power(xhci, hcd, wIndex, true, &flags);
|
||||
break;
|
||||
case USB_PORT_FEAT_RESET:
|
||||
temp = (temp | PORT_RESET);
|
||||
|
|
@ -1142,6 +1247,15 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
temp |= PORT_U2_TIMEOUT(timeout);
|
||||
writel(temp, port_array[wIndex] + PORTPMSC);
|
||||
break;
|
||||
case USB_PORT_FEAT_TEST:
|
||||
/* 4.19.6 Port Test Modes (USB2 Test Mode) */
|
||||
if (hcd->speed != HCD_USB2)
|
||||
goto error;
|
||||
if (test_mode > TEST_FORCE_EN || test_mode < TEST_J)
|
||||
goto error;
|
||||
retval = xhci_enter_test_mode(xhci, test_mode, wIndex,
|
||||
&flags);
|
||||
break;
|
||||
default:
|
||||
goto error;
|
||||
}
|
||||
|
|
@ -1153,7 +1267,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
goto error;
|
||||
wIndex--;
|
||||
temp = readl(port_array[wIndex]);
|
||||
if (temp == 0xffffffff) {
|
||||
if (temp == ~(u32)0) {
|
||||
xhci_hc_died(xhci);
|
||||
retval = -ENODEV;
|
||||
break;
|
||||
}
|
||||
|
|
@ -1207,15 +1322,10 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
port_array[wIndex], temp);
|
||||
break;
|
||||
case USB_PORT_FEAT_POWER:
|
||||
writel(temp & ~PORT_POWER, port_array[wIndex]);
|
||||
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
temp = usb_acpi_power_manageable(hcd->self.root_hub,
|
||||
wIndex);
|
||||
if (temp)
|
||||
usb_acpi_set_power_state(hcd->self.root_hub,
|
||||
wIndex, false);
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
xhci_set_port_power(xhci, hcd, wIndex, false, &flags);
|
||||
break;
|
||||
case USB_PORT_FEAT_TEST:
|
||||
retval = xhci_exit_test_mode(xhci);
|
||||
break;
|
||||
default:
|
||||
goto error;
|
||||
|
|
@ -1269,7 +1379,8 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
|
|||
/* For each port, did anything change? If so, set that bit in buf. */
|
||||
for (i = 0; i < max_ports; i++) {
|
||||
temp = readl(port_array[i]);
|
||||
if (temp == 0xffffffff) {
|
||||
if (temp == ~(u32)0) {
|
||||
xhci_hc_died(xhci);
|
||||
retval = -ENODEV;
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -288,6 +288,8 @@ void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring)
|
|||
if (!ring)
|
||||
return;
|
||||
|
||||
trace_xhci_ring_free(ring);
|
||||
|
||||
if (ring->first_seg) {
|
||||
if (ring->type == TYPE_STREAM)
|
||||
xhci_remove_stream_mapping(ring);
|
||||
|
|
@ -313,9 +315,6 @@ static void xhci_initialize_ring_info(struct xhci_ring *ring,
|
|||
* handling ring expansion, set the cycle state equal to the old ring.
|
||||
*/
|
||||
ring->cycle_state = cycle_state;
|
||||
/* Not necessary for new rings, but needed for re-initialized rings */
|
||||
ring->enq_updates = 0;
|
||||
ring->deq_updates = 0;
|
||||
|
||||
/*
|
||||
* Each segment has a link TRB, and leave an extra TRB for SW
|
||||
|
|
@ -400,6 +399,7 @@ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
|
|||
cpu_to_le32(LINK_TOGGLE);
|
||||
}
|
||||
xhci_initialize_ring_info(ring, cycle_state);
|
||||
trace_xhci_ring_alloc(ring);
|
||||
return ring;
|
||||
|
||||
fail:
|
||||
|
|
@ -504,6 +504,7 @@ int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring,
|
|||
}
|
||||
|
||||
xhci_link_rings(xhci, ring, first, last, num_segs);
|
||||
trace_xhci_ring_expansion(ring);
|
||||
xhci_dbg_trace(xhci, trace_xhci_dbg_ring_expansion,
|
||||
"ring expansion succeed, now has %d segments",
|
||||
ring->num_segs);
|
||||
|
|
@ -586,7 +587,7 @@ static void xhci_free_stream_ctx(struct xhci_hcd *xhci,
|
|||
unsigned int num_stream_ctxs,
|
||||
struct xhci_stream_ctx *stream_ctx, dma_addr_t dma)
|
||||
{
|
||||
struct device *dev = xhci_to_hcd(xhci)->self.controller;
|
||||
struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
|
||||
size_t size = sizeof(struct xhci_stream_ctx) * num_stream_ctxs;
|
||||
|
||||
if (size > MEDIUM_STREAM_ARRAY_SIZE)
|
||||
|
|
@ -614,7 +615,7 @@ static struct xhci_stream_ctx *xhci_alloc_stream_ctx(struct xhci_hcd *xhci,
|
|||
unsigned int num_stream_ctxs, dma_addr_t *dma,
|
||||
gfp_t mem_flags)
|
||||
{
|
||||
struct device *dev = xhci_to_hcd(xhci)->self.controller;
|
||||
struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
|
||||
size_t size = sizeof(struct xhci_stream_ctx) * num_stream_ctxs;
|
||||
|
||||
if (size > MEDIUM_STREAM_ARRAY_SIZE)
|
||||
|
|
@ -1502,6 +1503,17 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
|
|||
*/
|
||||
max_esit_payload = xhci_get_max_esit_payload(udev, ep);
|
||||
interval = xhci_get_endpoint_interval(udev, ep);
|
||||
|
||||
/* Periodic endpoint bInterval limit quirk */
|
||||
if (usb_endpoint_xfer_int(&ep->desc) ||
|
||||
usb_endpoint_xfer_isoc(&ep->desc)) {
|
||||
if ((xhci->quirks & XHCI_LIMIT_ENDPOINT_INTERVAL_7) &&
|
||||
udev->speed >= USB_SPEED_HIGH &&
|
||||
interval >= 7) {
|
||||
interval = 6;
|
||||
}
|
||||
}
|
||||
|
||||
mult = xhci_get_endpoint_mult(udev, ep);
|
||||
max_packet = usb_endpoint_maxp(&ep->desc);
|
||||
max_burst = xhci_get_endpoint_max_burst(udev, ep);
|
||||
|
|
@ -1686,7 +1698,7 @@ void xhci_slot_copy(struct xhci_hcd *xhci,
|
|||
static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags)
|
||||
{
|
||||
int i;
|
||||
struct device *dev = xhci_to_hcd(xhci)->self.controller;
|
||||
struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
|
||||
int num_sp = HCS_MAX_SCRATCHPAD(xhci->hcs_params2);
|
||||
|
||||
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
|
||||
|
|
@ -1709,36 +1721,27 @@ static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags)
|
|||
if (!xhci->scratchpad->sp_buffers)
|
||||
goto fail_sp3;
|
||||
|
||||
xhci->scratchpad->sp_dma_buffers =
|
||||
kzalloc(sizeof(dma_addr_t) * num_sp, flags);
|
||||
|
||||
if (!xhci->scratchpad->sp_dma_buffers)
|
||||
goto fail_sp4;
|
||||
|
||||
xhci->dcbaa->dev_context_ptrs[0] = cpu_to_le64(xhci->scratchpad->sp_dma);
|
||||
for (i = 0; i < num_sp; i++) {
|
||||
dma_addr_t dma;
|
||||
void *buf = dma_alloc_coherent(dev, xhci->page_size, &dma,
|
||||
flags);
|
||||
if (!buf)
|
||||
goto fail_sp5;
|
||||
goto fail_sp4;
|
||||
|
||||
xhci->scratchpad->sp_array[i] = dma;
|
||||
xhci->scratchpad->sp_buffers[i] = buf;
|
||||
xhci->scratchpad->sp_dma_buffers[i] = dma;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail_sp5:
|
||||
fail_sp4:
|
||||
for (i = i - 1; i >= 0; i--) {
|
||||
dma_free_coherent(dev, xhci->page_size,
|
||||
xhci->scratchpad->sp_buffers[i],
|
||||
xhci->scratchpad->sp_dma_buffers[i]);
|
||||
xhci->scratchpad->sp_array[i]);
|
||||
}
|
||||
kfree(xhci->scratchpad->sp_dma_buffers);
|
||||
|
||||
fail_sp4:
|
||||
kfree(xhci->scratchpad->sp_buffers);
|
||||
|
||||
fail_sp3:
|
||||
|
|
@ -1758,7 +1761,7 @@ static void scratchpad_free(struct xhci_hcd *xhci)
|
|||
{
|
||||
int num_sp;
|
||||
int i;
|
||||
struct device *dev = xhci_to_hcd(xhci)->self.controller;
|
||||
struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
|
||||
|
||||
if (!xhci->scratchpad)
|
||||
return;
|
||||
|
|
@ -1768,9 +1771,8 @@ static void scratchpad_free(struct xhci_hcd *xhci)
|
|||
for (i = 0; i < num_sp; i++) {
|
||||
dma_free_coherent(dev, xhci->page_size,
|
||||
xhci->scratchpad->sp_buffers[i],
|
||||
xhci->scratchpad->sp_dma_buffers[i]);
|
||||
xhci->scratchpad->sp_array[i]);
|
||||
}
|
||||
kfree(xhci->scratchpad->sp_dma_buffers);
|
||||
kfree(xhci->scratchpad->sp_buffers);
|
||||
dma_free_coherent(dev, num_sp * sizeof(u64),
|
||||
xhci->scratchpad->sp_array,
|
||||
|
|
@ -1831,7 +1833,7 @@ void xhci_free_command(struct xhci_hcd *xhci,
|
|||
|
||||
void xhci_mem_cleanup(struct xhci_hcd *xhci)
|
||||
{
|
||||
struct device *dev = xhci_to_hcd(xhci)->self.controller;
|
||||
struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
|
||||
int size;
|
||||
int i, j, num_ports;
|
||||
|
||||
|
|
@ -2373,7 +2375,7 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
|
|||
int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
|
||||
{
|
||||
dma_addr_t dma;
|
||||
struct device *dev = xhci_to_hcd(xhci)->self.controller;
|
||||
struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
|
||||
unsigned int val, val2;
|
||||
u64 val_64;
|
||||
struct xhci_segment *seg;
|
||||
|
|
@ -2419,7 +2421,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
|
|||
writel(val, &xhci->op_regs->config_reg);
|
||||
|
||||
/*
|
||||
* Section 5.4.8 - doorbell array must be
|
||||
* xHCI section 5.4.6 - doorbell array must be
|
||||
* "physically contiguous and 64-byte (cache line) aligned".
|
||||
*/
|
||||
xhci->dcbaa = dma_alloc_coherent(dev, sizeof(*xhci->dcbaa), &dma,
|
||||
|
|
@ -2480,7 +2482,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
|
|||
(xhci->cmd_ring->first_seg->dma & (u64) ~CMD_RING_RSVD_BITS) |
|
||||
xhci->cmd_ring->cycle_state;
|
||||
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
|
||||
"// Setting command ring address to 0x%x", val);
|
||||
"// Setting command ring address to 0x%016llx", val_64);
|
||||
xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring);
|
||||
xhci_dbg_cmd_ptrs(xhci);
|
||||
|
||||
|
|
@ -2601,7 +2603,6 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
|
|||
return 0;
|
||||
|
||||
fail:
|
||||
xhci_warn(xhci, "Couldn't initialize memory\n");
|
||||
xhci_halt(xhci);
|
||||
xhci_reset(xhci);
|
||||
xhci_mem_cleanup(xhci);
|
||||
|
|
|
|||
|
|
@ -199,6 +199,9 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
|
|||
pdev->device == 0x1042)
|
||||
xhci->quirks |= XHCI_BROKEN_STREAMS;
|
||||
|
||||
if (pdev->vendor == PCI_VENDOR_ID_TI && pdev->device == 0x8241)
|
||||
xhci->quirks |= XHCI_LIMIT_ENDPOINT_INTERVAL_7;
|
||||
|
||||
if (xhci->quirks & XHCI_RESET_ON_RESUME)
|
||||
xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
|
||||
"QUIRK: Resetting on resume");
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include <linux/clk.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/usb/phy.h>
|
||||
|
|
@ -54,6 +55,16 @@ static int xhci_priv_init_quirk(struct usb_hcd *hcd)
|
|||
return priv->init_quirk(hcd);
|
||||
}
|
||||
|
||||
static int xhci_priv_resume_quirk(struct usb_hcd *hcd)
|
||||
{
|
||||
struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
|
||||
|
||||
if (!priv->resume_quirk)
|
||||
return 0;
|
||||
|
||||
return priv->resume_quirk(hcd);
|
||||
}
|
||||
|
||||
static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci)
|
||||
{
|
||||
/*
|
||||
|
|
@ -92,18 +103,21 @@ static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen2 = {
|
|||
.firmware_name = XHCI_RCAR_FIRMWARE_NAME_V1,
|
||||
.init_quirk = xhci_rcar_init_quirk,
|
||||
.plat_start = xhci_rcar_start,
|
||||
.resume_quirk = xhci_rcar_resume_quirk,
|
||||
};
|
||||
|
||||
static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen3 = {
|
||||
.firmware_name = XHCI_RCAR_FIRMWARE_NAME_V2,
|
||||
.init_quirk = xhci_rcar_init_quirk,
|
||||
.plat_start = xhci_rcar_start,
|
||||
.resume_quirk = xhci_rcar_resume_quirk,
|
||||
};
|
||||
|
||||
static const struct xhci_plat_priv xhci_plat_renesas_rcar_r8a7796 = {
|
||||
.firmware_name = XHCI_RCAR_FIRMWARE_NAME_V3,
|
||||
.init_quirk = xhci_rcar_init_quirk,
|
||||
.plat_start = xhci_rcar_start,
|
||||
.resume_quirk = xhci_rcar_resume_quirk,
|
||||
};
|
||||
|
||||
static const struct of_device_id usb_xhci_of_match[] = {
|
||||
|
|
@ -148,6 +162,7 @@ static int xhci_plat_probe(struct platform_device *pdev)
|
|||
{
|
||||
const struct of_device_id *match;
|
||||
const struct hc_driver *driver;
|
||||
struct device *sysdev;
|
||||
struct xhci_hcd *xhci;
|
||||
struct resource *res;
|
||||
struct usb_hcd *hcd;
|
||||
|
|
@ -164,24 +179,47 @@ static int xhci_plat_probe(struct platform_device *pdev)
|
|||
if (irq < 0)
|
||||
return -ENODEV;
|
||||
|
||||
/*
|
||||
* sysdev must point to a device that is known to the system firmware
|
||||
* or PCI hardware. We handle these three cases here:
|
||||
* 1. xhci_plat comes from firmware
|
||||
* 2. xhci_plat is child of a device from firmware (dwc3-plat)
|
||||
* 3. xhci_plat is grandchild of a pci device (dwc3-pci)
|
||||
*/
|
||||
sysdev = &pdev->dev;
|
||||
if (sysdev->parent && !sysdev->of_node && sysdev->parent->of_node)
|
||||
sysdev = sysdev->parent;
|
||||
#ifdef CONFIG_PCI
|
||||
else if (sysdev->parent && sysdev->parent->parent &&
|
||||
sysdev->parent->parent->bus == &pci_bus_type)
|
||||
sysdev = sysdev->parent->parent;
|
||||
#endif
|
||||
|
||||
/* Try to set 64-bit DMA first */
|
||||
if (!pdev->dev.dma_mask)
|
||||
if (WARN_ON(!sysdev->dma_mask))
|
||||
/* Platform did not initialize dma_mask */
|
||||
ret = dma_coerce_mask_and_coherent(&pdev->dev,
|
||||
ret = dma_coerce_mask_and_coherent(sysdev,
|
||||
DMA_BIT_MASK(64));
|
||||
else
|
||||
ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
|
||||
ret = dma_set_mask_and_coherent(sysdev, DMA_BIT_MASK(64));
|
||||
|
||||
/* If seting 64-bit DMA mask fails, fall back to 32-bit DMA mask */
|
||||
if (ret) {
|
||||
ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
|
||||
ret = dma_set_mask_and_coherent(sysdev, DMA_BIT_MASK(32));
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
|
||||
if (!hcd)
|
||||
return -ENOMEM;
|
||||
pm_runtime_set_active(&pdev->dev);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
pm_runtime_get_noresume(&pdev->dev);
|
||||
|
||||
hcd = __usb_create_hcd(driver, sysdev, &pdev->dev,
|
||||
dev_name(&pdev->dev), NULL);
|
||||
if (!hcd) {
|
||||
ret = -ENOMEM;
|
||||
goto disable_runtime;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
hcd->regs = devm_ioremap_resource(&pdev->dev, res);
|
||||
|
|
@ -222,20 +260,20 @@ static int xhci_plat_probe(struct platform_device *pdev)
|
|||
|
||||
xhci->clk = clk;
|
||||
xhci->main_hcd = hcd;
|
||||
xhci->shared_hcd = usb_create_shared_hcd(driver, &pdev->dev,
|
||||
xhci->shared_hcd = __usb_create_hcd(driver, sysdev, &pdev->dev,
|
||||
dev_name(&pdev->dev), hcd);
|
||||
if (!xhci->shared_hcd) {
|
||||
ret = -ENOMEM;
|
||||
goto disable_clk;
|
||||
}
|
||||
|
||||
if (device_property_read_bool(&pdev->dev, "usb3-lpm-capable"))
|
||||
if (device_property_read_bool(sysdev, "usb3-lpm-capable"))
|
||||
xhci->quirks |= XHCI_LPM_SUPPORT;
|
||||
|
||||
if (device_property_read_bool(&pdev->dev, "quirk-broken-port-ped"))
|
||||
xhci->quirks |= XHCI_BROKEN_PORT_PED;
|
||||
|
||||
hcd->usb_phy = devm_usb_get_phy_by_phandle(&pdev->dev, "usb-phy", 0);
|
||||
hcd->usb_phy = devm_usb_get_phy_by_phandle(sysdev, "usb-phy", 0);
|
||||
if (IS_ERR(hcd->usb_phy)) {
|
||||
ret = PTR_ERR(hcd->usb_phy);
|
||||
if (ret == -EPROBE_DEFER)
|
||||
|
|
@ -258,6 +296,15 @@ static int xhci_plat_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
goto dealloc_usb2_hcd;
|
||||
|
||||
device_enable_async_suspend(&pdev->dev);
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
|
||||
/*
|
||||
* Prevent runtime pm from being on as default, users should enable
|
||||
* runtime pm using power/control in sysfs.
|
||||
*/
|
||||
pm_runtime_forbid(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
|
|
@ -277,6 +324,10 @@ disable_clk:
|
|||
put_hcd:
|
||||
usb_put_hcd(hcd);
|
||||
|
||||
disable_runtime:
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -298,14 +349,17 @@ static int xhci_plat_remove(struct platform_device *dev)
|
|||
clk_disable_unprepare(clk);
|
||||
usb_put_hcd(hcd);
|
||||
|
||||
pm_runtime_set_suspended(&dev->dev);
|
||||
pm_runtime_disable(&dev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int xhci_plat_suspend(struct device *dev)
|
||||
static int __maybe_unused xhci_plat_suspend(struct device *dev)
|
||||
{
|
||||
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* xhci_suspend() needs `do_wakeup` to know whether host is allowed
|
||||
|
|
@ -315,24 +369,53 @@ static int xhci_plat_suspend(struct device *dev)
|
|||
* reconsider this when xhci_plat_suspend enlarges its scope, e.g.,
|
||||
* also applies to runtime suspend.
|
||||
*/
|
||||
return xhci_suspend(xhci, device_may_wakeup(dev));
|
||||
ret = xhci_suspend(xhci, device_may_wakeup(dev));
|
||||
|
||||
if (!device_may_wakeup(dev) && !IS_ERR(xhci->clk))
|
||||
clk_disable_unprepare(xhci->clk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int xhci_plat_resume(struct device *dev)
|
||||
static int __maybe_unused xhci_plat_resume(struct device *dev)
|
||||
{
|
||||
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
int ret;
|
||||
|
||||
if (!device_may_wakeup(dev) && !IS_ERR(xhci->clk))
|
||||
clk_prepare_enable(xhci->clk);
|
||||
|
||||
ret = xhci_priv_resume_quirk(hcd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return xhci_resume(xhci, 0);
|
||||
}
|
||||
|
||||
static int __maybe_unused xhci_plat_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
|
||||
return xhci_suspend(xhci, true);
|
||||
}
|
||||
|
||||
static int __maybe_unused xhci_plat_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
|
||||
return xhci_resume(xhci, 0);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops xhci_plat_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(xhci_plat_suspend, xhci_plat_resume)
|
||||
|
||||
SET_RUNTIME_PM_OPS(xhci_plat_runtime_suspend,
|
||||
xhci_plat_runtime_resume,
|
||||
NULL)
|
||||
};
|
||||
#define DEV_PM_OPS (&xhci_plat_pm_ops)
|
||||
#else
|
||||
#define DEV_PM_OPS NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static const struct acpi_device_id usb_xhci_acpi_match[] = {
|
||||
/* XHCI-compliant USB Controller */
|
||||
|
|
@ -347,7 +430,7 @@ static struct platform_driver usb_xhci_driver = {
|
|||
.shutdown = usb_hcd_platform_shutdown,
|
||||
.driver = {
|
||||
.name = "xhci-hcd",
|
||||
.pm = DEV_PM_OPS,
|
||||
.pm = &xhci_plat_pm_ops,
|
||||
.of_match_table = of_match_ptr(usb_xhci_of_match),
|
||||
.acpi_match_table = ACPI_PTR(usb_xhci_acpi_match),
|
||||
},
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ struct xhci_plat_priv {
|
|||
const char *firmware_name;
|
||||
void (*plat_start)(struct usb_hcd *);
|
||||
int (*init_quirk)(struct usb_hcd *);
|
||||
int (*resume_quirk)(struct usb_hcd *);
|
||||
};
|
||||
|
||||
#define hcd_to_xhci_priv(h) ((struct xhci_plat_priv *)hcd_to_xhci(h)->priv)
|
||||
|
|
|
|||
|
|
@ -198,3 +198,14 @@ int xhci_rcar_init_quirk(struct usb_hcd *hcd)
|
|||
|
||||
return xhci_rcar_download_firmware(hcd);
|
||||
}
|
||||
|
||||
int xhci_rcar_resume_quirk(struct usb_hcd *hcd)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = xhci_rcar_download_firmware(hcd);
|
||||
if (!ret)
|
||||
xhci_rcar_start(hcd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#if IS_ENABLED(CONFIG_USB_XHCI_RCAR)
|
||||
void xhci_rcar_start(struct usb_hcd *hcd);
|
||||
int xhci_rcar_init_quirk(struct usb_hcd *hcd);
|
||||
int xhci_rcar_resume_quirk(struct usb_hcd *hcd);
|
||||
#else
|
||||
static inline void xhci_rcar_start(struct usb_hcd *hcd)
|
||||
{
|
||||
|
|
@ -27,5 +28,10 @@ static inline int xhci_rcar_init_quirk(struct usb_hcd *hcd)
|
|||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int xhci_rcar_resume_quirk(struct usb_hcd *hcd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#endif /* _XHCI_RCAR_H */
|
||||
|
|
|
|||
|
|
@ -167,8 +167,6 @@ static void next_trb(struct xhci_hcd *xhci,
|
|||
*/
|
||||
static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring)
|
||||
{
|
||||
ring->deq_updates++;
|
||||
|
||||
/* event ring doesn't have link trbs, check for last trb */
|
||||
if (ring->type == TYPE_EVENT) {
|
||||
if (!last_trb_on_seg(ring->deq_seg, ring->dequeue)) {
|
||||
|
|
@ -191,6 +189,9 @@ static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring)
|
|||
ring->deq_seg = ring->deq_seg->next;
|
||||
ring->dequeue = ring->deq_seg->trbs;
|
||||
}
|
||||
|
||||
trace_xhci_inc_deq(ring);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -223,7 +224,6 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring,
|
|||
ring->num_trbs_free--;
|
||||
next = ++(ring->enqueue);
|
||||
|
||||
ring->enq_updates++;
|
||||
/* Update the dequeue pointer further if that was a link TRB */
|
||||
while (trb_is_link(next)) {
|
||||
|
||||
|
|
@ -259,6 +259,8 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring,
|
|||
ring->enqueue = ring->enq_seg->trbs;
|
||||
next = ring->enqueue;
|
||||
}
|
||||
|
||||
trace_xhci_inc_enq(ring);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -359,21 +361,19 @@ static int xhci_abort_cmd_ring(struct xhci_hcd *xhci, unsigned long flags)
|
|||
xhci_write_64(xhci, temp_64 | CMD_RING_ABORT,
|
||||
&xhci->op_regs->cmd_ring);
|
||||
|
||||
/* Section 4.6.1.2 of xHCI 1.0 spec says software should
|
||||
* time the completion od all xHCI commands, including
|
||||
* the Command Abort operation. If software doesn't see
|
||||
* CRR negated in a timely manner (e.g. longer than 5
|
||||
* seconds), then it should assume that the there are
|
||||
* larger problems with the xHC and assert HCRST.
|
||||
/* Section 4.6.1.2 of xHCI 1.0 spec says software should also time the
|
||||
* completion of the Command Abort operation. If CRR is not negated in 5
|
||||
* seconds then driver handles it as if host died (-ENODEV).
|
||||
* In the future we should distinguish between -ENODEV and -ETIMEDOUT
|
||||
* and try to recover a -ETIMEDOUT with a host controller reset.
|
||||
*/
|
||||
ret = xhci_handshake(&xhci->op_regs->cmd_ring,
|
||||
CMD_RING_RUNNING, 0, 5 * 1000 * 1000);
|
||||
if (ret < 0) {
|
||||
xhci_err(xhci,
|
||||
"Stop command ring failed, maybe the host is dead\n");
|
||||
xhci->xhc_state |= XHCI_STATE_DYING;
|
||||
xhci_err(xhci, "Abort failed to stop command ring: %d\n", ret);
|
||||
xhci_halt(xhci);
|
||||
return -ESHUTDOWN;
|
||||
xhci_hc_died(xhci);
|
||||
return ret;
|
||||
}
|
||||
/*
|
||||
* Writing the CMD_RING_ABORT bit should cause a cmd completion event,
|
||||
|
|
@ -689,6 +689,8 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id,
|
|||
struct xhci_virt_ep *ep;
|
||||
struct xhci_td *cur_td = NULL;
|
||||
struct xhci_td *last_unlinked_td;
|
||||
struct xhci_ep_ctx *ep_ctx;
|
||||
struct xhci_virt_device *vdev;
|
||||
|
||||
struct xhci_dequeue_state deq_state;
|
||||
|
||||
|
|
@ -702,6 +704,11 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id,
|
|||
|
||||
memset(&deq_state, 0, sizeof(deq_state));
|
||||
ep_index = TRB_TO_EP_INDEX(le32_to_cpu(trb->generic.field[3]));
|
||||
|
||||
vdev = xhci->devs[slot_id];
|
||||
ep_ctx = xhci_get_ep_ctx(xhci, vdev->out_ctx, ep_index);
|
||||
trace_xhci_handle_cmd_stop_ep(ep_ctx);
|
||||
|
||||
ep = &xhci->devs[slot_id]->eps[ep_index];
|
||||
last_unlinked_td = list_last_entry(&ep->cancelled_td_list,
|
||||
struct xhci_td, cancelled_td_list);
|
||||
|
|
@ -866,6 +873,40 @@ static void xhci_kill_endpoint_urbs(struct xhci_hcd *xhci,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* host controller died, register read returns 0xffffffff
|
||||
* Complete pending commands, mark them ABORTED.
|
||||
* URBs need to be given back as usb core might be waiting with device locks
|
||||
* held for the URBs to finish during device disconnect, blocking host remove.
|
||||
*
|
||||
* Call with xhci->lock held.
|
||||
* lock is relased and re-acquired while giving back urb.
|
||||
*/
|
||||
void xhci_hc_died(struct xhci_hcd *xhci)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
if (xhci->xhc_state & XHCI_STATE_DYING)
|
||||
return;
|
||||
|
||||
xhci_err(xhci, "xHCI host controller not responding, assume dead\n");
|
||||
xhci->xhc_state |= XHCI_STATE_DYING;
|
||||
|
||||
xhci_cleanup_command_queue(xhci);
|
||||
|
||||
/* return any pending urbs, remove may be waiting for them */
|
||||
for (i = 0; i <= HCS_MAX_SLOTS(xhci->hcs_params1); i++) {
|
||||
if (!xhci->devs[i])
|
||||
continue;
|
||||
for (j = 0; j < 31; j++)
|
||||
xhci_kill_endpoint_urbs(xhci, i, j);
|
||||
}
|
||||
|
||||
/* inform usb core hc died if PCI remove isn't already handling it */
|
||||
if (!(xhci->xhc_state & XHCI_STATE_REMOVING))
|
||||
usb_hc_died(xhci_to_hcd(xhci));
|
||||
}
|
||||
|
||||
/* Watchdog timer function for when a stop endpoint command fails to complete.
|
||||
* In this case, we assume the host controller is broken or dying or dead. The
|
||||
* host may still be completing some other events, so we have to be careful to
|
||||
|
|
@ -887,7 +928,6 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg)
|
|||
{
|
||||
struct xhci_hcd *xhci;
|
||||
struct xhci_virt_ep *ep;
|
||||
int ret, i, j;
|
||||
unsigned long flags;
|
||||
|
||||
ep = (struct xhci_virt_ep *) arg;
|
||||
|
|
@ -904,52 +944,22 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg)
|
|||
}
|
||||
|
||||
xhci_warn(xhci, "xHCI host not responding to stop endpoint command.\n");
|
||||
xhci_warn(xhci, "Assuming host is dying, halting host.\n");
|
||||
/* Oops, HC is dead or dying or at least not responding to the stop
|
||||
* endpoint command.
|
||||
*/
|
||||
|
||||
xhci->xhc_state |= XHCI_STATE_DYING;
|
||||
ep->ep_state &= ~EP_STOP_CMD_PENDING;
|
||||
|
||||
/* Disable interrupts from the host controller and start halting it */
|
||||
xhci_quiesce(xhci);
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
xhci_halt(xhci);
|
||||
|
||||
ret = xhci_halt(xhci);
|
||||
/*
|
||||
* handle a stop endpoint cmd timeout as if host died (-ENODEV).
|
||||
* In the future we could distinguish between -ENODEV and -ETIMEDOUT
|
||||
* and try to recover a -ETIMEDOUT with a host controller reset
|
||||
*/
|
||||
xhci_hc_died(xhci);
|
||||
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
if (ret < 0) {
|
||||
/* This is bad; the host is not responding to commands and it's
|
||||
* not allowing itself to be halted. At least interrupts are
|
||||
* disabled. If we call usb_hc_died(), it will attempt to
|
||||
* disconnect all device drivers under this host. Those
|
||||
* disconnect() methods will wait for all URBs to be unlinked,
|
||||
* so we must complete them.
|
||||
*/
|
||||
xhci_warn(xhci, "Non-responsive xHCI host is not halting.\n");
|
||||
xhci_warn(xhci, "Completing active URBs anyway.\n");
|
||||
/* We could turn all TDs on the rings to no-ops. This won't
|
||||
* help if the host has cached part of the ring, and is slow if
|
||||
* we want to preserve the cycle bit. Skip it and hope the host
|
||||
* doesn't touch the memory.
|
||||
*/
|
||||
}
|
||||
for (i = 0; i < MAX_HC_SLOTS; i++) {
|
||||
if (!xhci->devs[i])
|
||||
continue;
|
||||
for (j = 0; j < 31; j++)
|
||||
xhci_kill_endpoint_urbs(xhci, i, j);
|
||||
}
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
|
||||
"Calling usb_hc_died()");
|
||||
usb_hc_died(xhci_to_hcd(xhci));
|
||||
xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
|
||||
"xHCI host controller is dead.");
|
||||
}
|
||||
|
||||
|
||||
static void update_ring_for_set_deq_completion(struct xhci_hcd *xhci,
|
||||
struct xhci_virt_device *dev,
|
||||
struct xhci_ring *ep_ring,
|
||||
|
|
@ -1029,6 +1039,8 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id,
|
|||
|
||||
ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index);
|
||||
slot_ctx = xhci_get_slot_ctx(xhci, dev->out_ctx);
|
||||
trace_xhci_handle_cmd_set_deq(slot_ctx);
|
||||
trace_xhci_handle_cmd_set_deq_ep(ep_ctx);
|
||||
|
||||
if (cmd_comp_code != COMP_SUCCESS) {
|
||||
unsigned int ep_state;
|
||||
|
|
@ -1099,9 +1111,15 @@ cleanup:
|
|||
static void xhci_handle_cmd_reset_ep(struct xhci_hcd *xhci, int slot_id,
|
||||
union xhci_trb *trb, u32 cmd_comp_code)
|
||||
{
|
||||
struct xhci_virt_device *vdev;
|
||||
struct xhci_ep_ctx *ep_ctx;
|
||||
unsigned int ep_index;
|
||||
|
||||
ep_index = TRB_TO_EP_INDEX(le32_to_cpu(trb->generic.field[3]));
|
||||
vdev = xhci->devs[slot_id];
|
||||
ep_ctx = xhci_get_ep_ctx(xhci, vdev->out_ctx, ep_index);
|
||||
trace_xhci_handle_cmd_reset_ep(ep_ctx);
|
||||
|
||||
/* This command will only fail if the endpoint wasn't halted,
|
||||
* but we don't care.
|
||||
*/
|
||||
|
|
@ -1114,11 +1132,11 @@ static void xhci_handle_cmd_reset_ep(struct xhci_hcd *xhci, int slot_id,
|
|||
*/
|
||||
if (xhci->quirks & XHCI_RESET_EP_QUIRK) {
|
||||
struct xhci_command *command;
|
||||
|
||||
command = xhci_alloc_command(xhci, false, false, GFP_ATOMIC);
|
||||
if (!command) {
|
||||
xhci_warn(xhci, "WARN Cannot submit cfg ep: ENOMEM\n");
|
||||
if (!command)
|
||||
return;
|
||||
}
|
||||
|
||||
xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
|
||||
"Queueing configure endpoint command");
|
||||
xhci_queue_configure_endpoint(xhci, command,
|
||||
|
|
@ -1143,10 +1161,15 @@ static void xhci_handle_cmd_enable_slot(struct xhci_hcd *xhci, int slot_id,
|
|||
static void xhci_handle_cmd_disable_slot(struct xhci_hcd *xhci, int slot_id)
|
||||
{
|
||||
struct xhci_virt_device *virt_dev;
|
||||
struct xhci_slot_ctx *slot_ctx;
|
||||
|
||||
virt_dev = xhci->devs[slot_id];
|
||||
if (!virt_dev)
|
||||
return;
|
||||
|
||||
slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->out_ctx);
|
||||
trace_xhci_handle_cmd_disable_slot(slot_ctx);
|
||||
|
||||
if (xhci->quirks & XHCI_EP_LIMIT_QUIRK)
|
||||
/* Delete default control endpoint resources */
|
||||
xhci_free_device_endpoint_resources(xhci, virt_dev, true);
|
||||
|
|
@ -1158,6 +1181,7 @@ static void xhci_handle_cmd_config_ep(struct xhci_hcd *xhci, int slot_id,
|
|||
{
|
||||
struct xhci_virt_device *virt_dev;
|
||||
struct xhci_input_control_ctx *ctrl_ctx;
|
||||
struct xhci_ep_ctx *ep_ctx;
|
||||
unsigned int ep_index;
|
||||
unsigned int ep_state;
|
||||
u32 add_flags, drop_flags;
|
||||
|
|
@ -1182,6 +1206,9 @@ static void xhci_handle_cmd_config_ep(struct xhci_hcd *xhci, int slot_id,
|
|||
/* Input ctx add_flags are the endpoint index plus one */
|
||||
ep_index = xhci_last_valid_endpoint(add_flags) - 1;
|
||||
|
||||
ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->out_ctx, ep_index);
|
||||
trace_xhci_handle_cmd_config_ep(ep_ctx);
|
||||
|
||||
/* A usb_set_interface() call directly after clearing a halted
|
||||
* condition may race on this quirky hardware. Not worth
|
||||
* worrying about, since this is prototype hardware. Not sure
|
||||
|
|
@ -1206,9 +1233,26 @@ static void xhci_handle_cmd_config_ep(struct xhci_hcd *xhci, int slot_id,
|
|||
return;
|
||||
}
|
||||
|
||||
static void xhci_handle_cmd_addr_dev(struct xhci_hcd *xhci, int slot_id)
|
||||
{
|
||||
struct xhci_virt_device *vdev;
|
||||
struct xhci_slot_ctx *slot_ctx;
|
||||
|
||||
vdev = xhci->devs[slot_id];
|
||||
slot_ctx = xhci_get_slot_ctx(xhci, vdev->out_ctx);
|
||||
trace_xhci_handle_cmd_addr_dev(slot_ctx);
|
||||
}
|
||||
|
||||
static void xhci_handle_cmd_reset_dev(struct xhci_hcd *xhci, int slot_id,
|
||||
struct xhci_event_cmd *event)
|
||||
{
|
||||
struct xhci_virt_device *vdev;
|
||||
struct xhci_slot_ctx *slot_ctx;
|
||||
|
||||
vdev = xhci->devs[slot_id];
|
||||
slot_ctx = xhci_get_slot_ctx(xhci, vdev->out_ctx);
|
||||
trace_xhci_handle_cmd_reset_dev(slot_ctx);
|
||||
|
||||
xhci_dbg(xhci, "Completed reset device command.\n");
|
||||
if (!xhci->devs[slot_id])
|
||||
xhci_warn(xhci, "Reset device command completion "
|
||||
|
|
@ -1250,7 +1294,6 @@ void xhci_cleanup_command_queue(struct xhci_hcd *xhci)
|
|||
void xhci_handle_command_timeout(struct work_struct *work)
|
||||
{
|
||||
struct xhci_hcd *xhci;
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
u64 hw_ring_state;
|
||||
|
||||
|
|
@ -1271,22 +1314,17 @@ void xhci_handle_command_timeout(struct work_struct *work)
|
|||
|
||||
/* Make sure command ring is running before aborting it */
|
||||
hw_ring_state = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
|
||||
if (hw_ring_state == ~(u64)0) {
|
||||
xhci_hc_died(xhci);
|
||||
goto time_out_completed;
|
||||
}
|
||||
|
||||
if ((xhci->cmd_ring_state & CMD_RING_STATE_RUNNING) &&
|
||||
(hw_ring_state & CMD_RING_RUNNING)) {
|
||||
/* Prevent new doorbell, and start command abort */
|
||||
xhci->cmd_ring_state = CMD_RING_STATE_ABORTED;
|
||||
xhci_dbg(xhci, "Command timeout\n");
|
||||
ret = xhci_abort_cmd_ring(xhci, flags);
|
||||
if (unlikely(ret == -ESHUTDOWN)) {
|
||||
xhci_err(xhci, "Abort command ring failed\n");
|
||||
xhci_cleanup_command_queue(xhci);
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
usb_hc_died(xhci_to_hcd(xhci)->primary_hcd);
|
||||
xhci_dbg(xhci, "xHCI host controller is dead.\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
xhci_abort_cmd_ring(xhci, flags);
|
||||
goto time_out_completed;
|
||||
}
|
||||
|
||||
|
|
@ -1384,6 +1422,7 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
|
|||
case TRB_EVAL_CONTEXT:
|
||||
break;
|
||||
case TRB_ADDR_DEV:
|
||||
xhci_handle_cmd_addr_dev(xhci, slot_id);
|
||||
break;
|
||||
case TRB_STOP_RING:
|
||||
WARN_ON(slot_id != TRB_TO_SLOT_ID(
|
||||
|
|
@ -2243,7 +2282,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
|||
slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags));
|
||||
xdev = xhci->devs[slot_id];
|
||||
if (!xdev) {
|
||||
xhci_err(xhci, "ERROR Transfer event pointed to bad slot\n");
|
||||
xhci_err(xhci, "ERROR Transfer event pointed to bad slot %u\n",
|
||||
slot_id);
|
||||
xhci_err(xhci, "@%016llx %08x %08x %08x %08x\n",
|
||||
(unsigned long long) xhci_trb_virt_to_dma(
|
||||
xhci->event_ring->deq_seg,
|
||||
|
|
@ -2252,8 +2292,6 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
|||
upper_32_bits(le64_to_cpu(event->buffer)),
|
||||
le32_to_cpu(event->transfer_len),
|
||||
le32_to_cpu(event->flags));
|
||||
xhci_dbg(xhci, "Event ring:\n");
|
||||
xhci_debug_segment(xhci, xhci->event_ring->deq_seg);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
|
@ -2263,8 +2301,9 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
|||
ep_ring = xhci_dma_to_transfer_ring(ep, le64_to_cpu(event->buffer));
|
||||
ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index);
|
||||
if (!ep_ring || GET_EP_CTX_STATE(ep_ctx) == EP_STATE_DISABLED) {
|
||||
xhci_err(xhci, "ERROR Transfer event for disabled endpoint "
|
||||
"or incorrect stream ring\n");
|
||||
xhci_err(xhci,
|
||||
"ERROR Transfer event for disabled endpoint slot %u ep %u or incorrect stream ring\n",
|
||||
slot_id, ep_index);
|
||||
xhci_err(xhci, "@%016llx %08x %08x %08x %08x\n",
|
||||
(unsigned long long) xhci_trb_virt_to_dma(
|
||||
xhci->event_ring->deq_seg,
|
||||
|
|
@ -2273,8 +2312,6 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
|||
upper_32_bits(le64_to_cpu(event->buffer)),
|
||||
le32_to_cpu(event->transfer_len),
|
||||
le32_to_cpu(event->flags));
|
||||
xhci_dbg(xhci, "Event ring:\n");
|
||||
xhci_debug_segment(xhci, xhci->event_ring->deq_seg);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
|
@ -2298,45 +2335,62 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
|||
trb_comp_code = COMP_SHORT_PACKET;
|
||||
else
|
||||
xhci_warn_ratelimited(xhci,
|
||||
"WARN Successful completion on short TX: needs XHCI_TRUST_TX_LENGTH quirk?\n");
|
||||
"WARN Successful completion on short TX for slot %u ep %u: needs XHCI_TRUST_TX_LENGTH quirk?\n",
|
||||
slot_id, ep_index);
|
||||
case COMP_SHORT_PACKET:
|
||||
break;
|
||||
case COMP_STOPPED:
|
||||
xhci_dbg(xhci, "Stopped on Transfer TRB\n");
|
||||
xhci_dbg(xhci, "Stopped on Transfer TRB for slot %u ep %u\n",
|
||||
slot_id, ep_index);
|
||||
break;
|
||||
case COMP_STOPPED_LENGTH_INVALID:
|
||||
xhci_dbg(xhci, "Stopped on No-op or Link TRB\n");
|
||||
xhci_dbg(xhci,
|
||||
"Stopped on No-op or Link TRB for slot %u ep %u\n",
|
||||
slot_id, ep_index);
|
||||
break;
|
||||
case COMP_STOPPED_SHORT_PACKET:
|
||||
xhci_dbg(xhci, "Stopped with short packet transfer detected\n");
|
||||
xhci_dbg(xhci,
|
||||
"Stopped with short packet transfer detected for slot %u ep %u\n",
|
||||
slot_id, ep_index);
|
||||
break;
|
||||
case COMP_STALL_ERROR:
|
||||
xhci_dbg(xhci, "Stalled endpoint\n");
|
||||
xhci_dbg(xhci, "Stalled endpoint for slot %u ep %u\n", slot_id,
|
||||
ep_index);
|
||||
ep->ep_state |= EP_HALTED;
|
||||
status = -EPIPE;
|
||||
break;
|
||||
case COMP_TRB_ERROR:
|
||||
xhci_warn(xhci, "WARN: TRB error on endpoint\n");
|
||||
xhci_warn(xhci,
|
||||
"WARN: TRB error for slot %u ep %u on endpoint\n",
|
||||
slot_id, ep_index);
|
||||
status = -EILSEQ;
|
||||
break;
|
||||
case COMP_SPLIT_TRANSACTION_ERROR:
|
||||
case COMP_USB_TRANSACTION_ERROR:
|
||||
xhci_dbg(xhci, "Transfer error on endpoint\n");
|
||||
xhci_dbg(xhci, "Transfer error for slot %u ep %u on endpoint\n",
|
||||
slot_id, ep_index);
|
||||
status = -EPROTO;
|
||||
break;
|
||||
case COMP_BABBLE_DETECTED_ERROR:
|
||||
xhci_dbg(xhci, "Babble error on endpoint\n");
|
||||
xhci_dbg(xhci, "Babble error for slot %u ep %u on endpoint\n",
|
||||
slot_id, ep_index);
|
||||
status = -EOVERFLOW;
|
||||
break;
|
||||
case COMP_DATA_BUFFER_ERROR:
|
||||
xhci_warn(xhci, "WARN: HC couldn't access mem fast enough\n");
|
||||
xhci_warn(xhci,
|
||||
"WARN: HC couldn't access mem fast enough for slot %u ep %u\n",
|
||||
slot_id, ep_index);
|
||||
status = -ENOSR;
|
||||
break;
|
||||
case COMP_BANDWIDTH_OVERRUN_ERROR:
|
||||
xhci_warn(xhci, "WARN: bandwidth overrun event on endpoint\n");
|
||||
xhci_warn(xhci,
|
||||
"WARN: bandwidth overrun event for slot %u ep %u on endpoint\n",
|
||||
slot_id, ep_index);
|
||||
break;
|
||||
case COMP_ISOCH_BUFFER_OVERRUN:
|
||||
xhci_warn(xhci, "WARN: buffer overrun event on endpoint\n");
|
||||
xhci_warn(xhci,
|
||||
"WARN: buffer overrun event for slot %u ep %u on endpoint",
|
||||
slot_id, ep_index);
|
||||
break;
|
||||
case COMP_RING_UNDERRUN:
|
||||
/*
|
||||
|
|
@ -2360,7 +2414,9 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
|||
ep_index);
|
||||
goto cleanup;
|
||||
case COMP_INCOMPATIBLE_DEVICE_ERROR:
|
||||
xhci_warn(xhci, "WARN: detect an incompatible device");
|
||||
xhci_warn(xhci,
|
||||
"WARN: detect an incompatible device for slot %u ep %u",
|
||||
slot_id, ep_index);
|
||||
status = -EPROTO;
|
||||
break;
|
||||
case COMP_MISSED_SERVICE_ERROR:
|
||||
|
|
@ -2371,19 +2427,24 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
|||
* short transfer when process the ep_ring next time.
|
||||
*/
|
||||
ep->skip = true;
|
||||
xhci_dbg(xhci, "Miss service interval error, set skip flag\n");
|
||||
xhci_dbg(xhci,
|
||||
"Miss service interval error for slot %u ep %u, set skip flag\n",
|
||||
slot_id, ep_index);
|
||||
goto cleanup;
|
||||
case COMP_NO_PING_RESPONSE_ERROR:
|
||||
ep->skip = true;
|
||||
xhci_dbg(xhci, "No Ping response error, Skip one Isoc TD\n");
|
||||
xhci_dbg(xhci,
|
||||
"No Ping response error for slot %u ep %u, Skip one Isoc TD\n",
|
||||
slot_id, ep_index);
|
||||
goto cleanup;
|
||||
default:
|
||||
if (xhci_is_vendor_info_code(xhci, trb_comp_code)) {
|
||||
status = 0;
|
||||
break;
|
||||
}
|
||||
xhci_warn(xhci, "ERROR Unknown event condition %u, HC probably busted\n",
|
||||
trb_comp_code);
|
||||
xhci_warn(xhci,
|
||||
"ERROR Unknown event condition %u for slot %u ep %u , HC probably busted\n",
|
||||
trb_comp_code, slot_id, ep_index);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
|
@ -2402,15 +2463,11 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
|||
xhci_warn(xhci, "WARN Event TRB for slot %d ep %d with no TDs queued?\n",
|
||||
TRB_TO_SLOT_ID(le32_to_cpu(event->flags)),
|
||||
ep_index);
|
||||
xhci_dbg(xhci, "Event TRB with TRB type ID %u\n",
|
||||
(le32_to_cpu(event->flags) &
|
||||
TRB_TYPE_BITMASK)>>10);
|
||||
xhci_print_trb_offsets(xhci, (union xhci_trb *) event);
|
||||
}
|
||||
if (ep->skip) {
|
||||
ep->skip = false;
|
||||
xhci_dbg(xhci, "td_list is empty while skip "
|
||||
"flag set. Clear skip flag.\n");
|
||||
xhci_dbg(xhci, "td_list is empty while skip flag set. Clear skip flag for slot %u ep %u.\n",
|
||||
slot_id, ep_index);
|
||||
}
|
||||
goto cleanup;
|
||||
}
|
||||
|
|
@ -2418,8 +2475,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
|||
/* We've skipped all the TDs on the ep ring when ep->skip set */
|
||||
if (ep->skip && td_num == 0) {
|
||||
ep->skip = false;
|
||||
xhci_dbg(xhci, "All tds on the ep_ring skipped. "
|
||||
"Clear skip flag.\n");
|
||||
xhci_dbg(xhci, "All tds on the ep_ring skipped. Clear skip flag for slot %u ep %u.\n",
|
||||
slot_id, ep_index);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
|
@ -2478,7 +2535,9 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
|||
ep_ring->last_td_was_short = false;
|
||||
|
||||
if (ep->skip) {
|
||||
xhci_dbg(xhci, "Found td. Clear skip flag.\n");
|
||||
xhci_dbg(xhci,
|
||||
"Found td. Clear skip flag for slot %u ep %u.\n",
|
||||
slot_id, ep_index);
|
||||
ep->skip = false;
|
||||
}
|
||||
|
||||
|
|
@ -2495,7 +2554,9 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
|||
* the TD.
|
||||
*/
|
||||
if (trb_is_noop(ep_trb)) {
|
||||
xhci_dbg(xhci, "ep_trb is a no-op TRB. Skip it\n");
|
||||
xhci_dbg(xhci,
|
||||
"ep_trb is a no-op TRB. Skip it for slot %u ep %u\n",
|
||||
slot_id, ep_index);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
|
@ -2623,7 +2684,8 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
|
|||
spin_lock(&xhci->lock);
|
||||
/* Check if the xHC generated the interrupt, or the irq is shared */
|
||||
status = readl(&xhci->op_regs->status);
|
||||
if (status == 0xffffffff) {
|
||||
if (status == ~(u32)0) {
|
||||
xhci_hc_died(xhci);
|
||||
ret = IRQ_HANDLED;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -3942,10 +4004,8 @@ void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci,
|
|||
|
||||
/* This function gets called from contexts where it cannot sleep */
|
||||
cmd = xhci_alloc_command(xhci, false, false, GFP_ATOMIC);
|
||||
if (!cmd) {
|
||||
xhci_warn(xhci, "WARN Cannot submit Set TR Deq Ptr: ENOMEM\n");
|
||||
if (!cmd)
|
||||
return;
|
||||
}
|
||||
|
||||
ep->queued_deq_seg = deq_state->new_deq_seg;
|
||||
ep->queued_deq_ptr = deq_state->new_deq_ptr;
|
||||
|
|
|
|||
|
|
@ -231,6 +231,7 @@ DECLARE_EVENT_CLASS(xhci_log_urb,
|
|||
__field(int, epnum)
|
||||
__field(int, dir_in)
|
||||
__field(int, type)
|
||||
__field(int, slot_id)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->urb = urb;
|
||||
|
|
@ -245,8 +246,9 @@ DECLARE_EVENT_CLASS(xhci_log_urb,
|
|||
__entry->epnum = usb_endpoint_num(&urb->ep->desc);
|
||||
__entry->dir_in = usb_endpoint_dir_in(&urb->ep->desc);
|
||||
__entry->type = usb_endpoint_type(&urb->ep->desc);
|
||||
__entry->slot_id = urb->dev->slot_id;
|
||||
),
|
||||
TP_printk("ep%d%s-%s: urb %p pipe %u length %d/%d sgs %d/%d stream %d flags %08x",
|
||||
TP_printk("ep%d%s-%s: urb %p pipe %u slot %d length %d/%d sgs %d/%d stream %d flags %08x",
|
||||
__entry->epnum, __entry->dir_in ? "in" : "out",
|
||||
({ char *s;
|
||||
switch (__entry->type) {
|
||||
|
|
@ -264,8 +266,8 @@ DECLARE_EVENT_CLASS(xhci_log_urb,
|
|||
break;
|
||||
default:
|
||||
s = "UNKNOWN";
|
||||
} s; }), __entry->urb, __entry->pipe, __entry->actual,
|
||||
__entry->length, __entry->num_mapped_sgs,
|
||||
} s; }), __entry->urb, __entry->pipe, __entry->slot_id,
|
||||
__entry->actual, __entry->length, __entry->num_mapped_sgs,
|
||||
__entry->num_sgs, __entry->stream, __entry->flags
|
||||
)
|
||||
);
|
||||
|
|
@ -285,6 +287,172 @@ DEFINE_EVENT(xhci_log_urb, xhci_urb_dequeue,
|
|||
TP_ARGS(urb)
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(xhci_log_ep_ctx,
|
||||
TP_PROTO(struct xhci_ep_ctx *ctx),
|
||||
TP_ARGS(ctx),
|
||||
TP_STRUCT__entry(
|
||||
__field(u32, info)
|
||||
__field(u32, info2)
|
||||
__field(u64, deq)
|
||||
__field(u32, tx_info)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->info = le32_to_cpu(ctx->ep_info);
|
||||
__entry->info2 = le32_to_cpu(ctx->ep_info2);
|
||||
__entry->deq = le64_to_cpu(ctx->deq);
|
||||
__entry->tx_info = le32_to_cpu(ctx->tx_info);
|
||||
),
|
||||
TP_printk("%s", xhci_decode_ep_context(__entry->info,
|
||||
__entry->info2, __entry->deq, __entry->tx_info)
|
||||
)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(xhci_log_ep_ctx, xhci_handle_cmd_stop_ep,
|
||||
TP_PROTO(struct xhci_ep_ctx *ctx),
|
||||
TP_ARGS(ctx)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(xhci_log_ep_ctx, xhci_handle_cmd_set_deq_ep,
|
||||
TP_PROTO(struct xhci_ep_ctx *ctx),
|
||||
TP_ARGS(ctx)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(xhci_log_ep_ctx, xhci_handle_cmd_reset_ep,
|
||||
TP_PROTO(struct xhci_ep_ctx *ctx),
|
||||
TP_ARGS(ctx)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(xhci_log_ep_ctx, xhci_handle_cmd_config_ep,
|
||||
TP_PROTO(struct xhci_ep_ctx *ctx),
|
||||
TP_ARGS(ctx)
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(xhci_log_slot_ctx,
|
||||
TP_PROTO(struct xhci_slot_ctx *ctx),
|
||||
TP_ARGS(ctx),
|
||||
TP_STRUCT__entry(
|
||||
__field(u32, info)
|
||||
__field(u32, info2)
|
||||
__field(u32, tt_info)
|
||||
__field(u32, state)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->info = le32_to_cpu(ctx->dev_info);
|
||||
__entry->info2 = le32_to_cpu(ctx->dev_info2);
|
||||
__entry->tt_info = le64_to_cpu(ctx->tt_info);
|
||||
__entry->state = le32_to_cpu(ctx->dev_state);
|
||||
),
|
||||
TP_printk("%s", xhci_decode_slot_context(__entry->info,
|
||||
__entry->info2, __entry->tt_info,
|
||||
__entry->state)
|
||||
)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(xhci_log_slot_ctx, xhci_alloc_dev,
|
||||
TP_PROTO(struct xhci_slot_ctx *ctx),
|
||||
TP_ARGS(ctx)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(xhci_log_slot_ctx, xhci_free_dev,
|
||||
TP_PROTO(struct xhci_slot_ctx *ctx),
|
||||
TP_ARGS(ctx)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(xhci_log_slot_ctx, xhci_handle_cmd_disable_slot,
|
||||
TP_PROTO(struct xhci_slot_ctx *ctx),
|
||||
TP_ARGS(ctx)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(xhci_log_slot_ctx, xhci_discover_or_reset_device,
|
||||
TP_PROTO(struct xhci_slot_ctx *ctx),
|
||||
TP_ARGS(ctx)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(xhci_log_slot_ctx, xhci_setup_device_slot,
|
||||
TP_PROTO(struct xhci_slot_ctx *ctx),
|
||||
TP_ARGS(ctx)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(xhci_log_slot_ctx, xhci_handle_cmd_addr_dev,
|
||||
TP_PROTO(struct xhci_slot_ctx *ctx),
|
||||
TP_ARGS(ctx)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(xhci_log_slot_ctx, xhci_handle_cmd_reset_dev,
|
||||
TP_PROTO(struct xhci_slot_ctx *ctx),
|
||||
TP_ARGS(ctx)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(xhci_log_slot_ctx, xhci_handle_cmd_set_deq,
|
||||
TP_PROTO(struct xhci_slot_ctx *ctx),
|
||||
TP_ARGS(ctx)
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(xhci_log_ring,
|
||||
TP_PROTO(struct xhci_ring *ring),
|
||||
TP_ARGS(ring),
|
||||
TP_STRUCT__entry(
|
||||
__field(u32, type)
|
||||
__field(void *, ring)
|
||||
__field(dma_addr_t, enq)
|
||||
__field(dma_addr_t, deq)
|
||||
__field(dma_addr_t, enq_seg)
|
||||
__field(dma_addr_t, deq_seg)
|
||||
__field(unsigned int, num_segs)
|
||||
__field(unsigned int, stream_id)
|
||||
__field(unsigned int, cycle_state)
|
||||
__field(unsigned int, num_trbs_free)
|
||||
__field(unsigned int, bounce_buf_len)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->ring = ring;
|
||||
__entry->type = ring->type;
|
||||
__entry->num_segs = ring->num_segs;
|
||||
__entry->stream_id = ring->stream_id;
|
||||
__entry->enq_seg = ring->enq_seg->dma;
|
||||
__entry->deq_seg = ring->deq_seg->dma;
|
||||
__entry->cycle_state = ring->cycle_state;
|
||||
__entry->num_trbs_free = ring->num_trbs_free;
|
||||
__entry->bounce_buf_len = ring->bounce_buf_len;
|
||||
__entry->enq = xhci_trb_virt_to_dma(ring->enq_seg, ring->enqueue);
|
||||
__entry->deq = xhci_trb_virt_to_dma(ring->deq_seg, ring->dequeue);
|
||||
),
|
||||
TP_printk("%s %p: enq %pad(%pad) deq %pad(%pad) segs %d stream %d free_trbs %d bounce %d cycle %d",
|
||||
xhci_ring_type_string(__entry->type), __entry->ring,
|
||||
&__entry->enq, &__entry->enq_seg,
|
||||
&__entry->deq, &__entry->deq_seg,
|
||||
__entry->num_segs,
|
||||
__entry->stream_id,
|
||||
__entry->num_trbs_free,
|
||||
__entry->bounce_buf_len,
|
||||
__entry->cycle_state
|
||||
)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(xhci_log_ring, xhci_ring_alloc,
|
||||
TP_PROTO(struct xhci_ring *ring),
|
||||
TP_ARGS(ring)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(xhci_log_ring, xhci_ring_free,
|
||||
TP_PROTO(struct xhci_ring *ring),
|
||||
TP_ARGS(ring)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(xhci_log_ring, xhci_ring_expansion,
|
||||
TP_PROTO(struct xhci_ring *ring),
|
||||
TP_ARGS(ring)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(xhci_log_ring, xhci_inc_enq,
|
||||
TP_PROTO(struct xhci_ring *ring),
|
||||
TP_ARGS(ring)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(xhci_log_ring, xhci_inc_deq,
|
||||
TP_PROTO(struct xhci_ring *ring),
|
||||
TP_ARGS(ring)
|
||||
);
|
||||
#endif /* __XHCI_TRACE_H */
|
||||
|
||||
/* this part must be outside header guard */
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ int xhci_halt(struct xhci_hcd *xhci)
|
|||
/*
|
||||
* Set the run bit and wait for the host to be running.
|
||||
*/
|
||||
static int xhci_start(struct xhci_hcd *xhci)
|
||||
int xhci_start(struct xhci_hcd *xhci)
|
||||
{
|
||||
u32 temp;
|
||||
int ret;
|
||||
|
|
@ -216,31 +216,21 @@ int xhci_reset(struct xhci_hcd *xhci)
|
|||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
static int xhci_free_msi(struct xhci_hcd *xhci)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!xhci->msix_entries)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < xhci->msix_count; i++)
|
||||
if (xhci->msix_entries[i].vector)
|
||||
free_irq(xhci->msix_entries[i].vector,
|
||||
xhci_to_hcd(xhci));
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_PCI
|
||||
/*
|
||||
* Set up MSI
|
||||
*/
|
||||
static int xhci_setup_msi(struct xhci_hcd *xhci)
|
||||
{
|
||||
int ret;
|
||||
/*
|
||||
* TODO:Check with MSI Soc for sysdev
|
||||
*/
|
||||
struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
|
||||
|
||||
ret = pci_enable_msi(pdev);
|
||||
if (ret) {
|
||||
ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI);
|
||||
if (ret < 0) {
|
||||
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
|
||||
"failed to allocate MSI entry");
|
||||
return ret;
|
||||
|
|
@ -251,34 +241,12 @@ static int xhci_setup_msi(struct xhci_hcd *xhci)
|
|||
if (ret) {
|
||||
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
|
||||
"disable MSI interrupt");
|
||||
pci_disable_msi(pdev);
|
||||
pci_free_irq_vectors(pdev);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free IRQs
|
||||
* free all IRQs request
|
||||
*/
|
||||
static void xhci_free_irq(struct xhci_hcd *xhci)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
|
||||
int ret;
|
||||
|
||||
/* return if using legacy interrupt */
|
||||
if (xhci_to_hcd(xhci)->irq > 0)
|
||||
return;
|
||||
|
||||
ret = xhci_free_msi(xhci);
|
||||
if (!ret)
|
||||
return;
|
||||
if (pdev->irq > 0)
|
||||
free_irq(pdev->irq, xhci_to_hcd(xhci));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up MSI-X
|
||||
*/
|
||||
|
|
@ -298,28 +266,17 @@ static int xhci_setup_msix(struct xhci_hcd *xhci)
|
|||
xhci->msix_count = min(num_online_cpus() + 1,
|
||||
HCS_MAX_INTRS(xhci->hcs_params1));
|
||||
|
||||
xhci->msix_entries =
|
||||
kmalloc((sizeof(struct msix_entry))*xhci->msix_count,
|
||||
GFP_KERNEL);
|
||||
if (!xhci->msix_entries)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < xhci->msix_count; i++) {
|
||||
xhci->msix_entries[i].entry = i;
|
||||
xhci->msix_entries[i].vector = 0;
|
||||
}
|
||||
|
||||
ret = pci_enable_msix_exact(pdev, xhci->msix_entries, xhci->msix_count);
|
||||
if (ret) {
|
||||
ret = pci_alloc_irq_vectors(pdev, xhci->msix_count, xhci->msix_count,
|
||||
PCI_IRQ_MSIX);
|
||||
if (ret < 0) {
|
||||
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
|
||||
"Failed to enable MSI-X");
|
||||
goto free_entries;
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < xhci->msix_count; i++) {
|
||||
ret = request_irq(xhci->msix_entries[i].vector,
|
||||
xhci_msi_irq,
|
||||
0, "xhci_hcd", xhci_to_hcd(xhci));
|
||||
ret = request_irq(pci_irq_vector(pdev, i), xhci_msi_irq, 0,
|
||||
"xhci_hcd", xhci_to_hcd(xhci));
|
||||
if (ret)
|
||||
goto disable_msix;
|
||||
}
|
||||
|
|
@ -329,11 +286,9 @@ static int xhci_setup_msix(struct xhci_hcd *xhci)
|
|||
|
||||
disable_msix:
|
||||
xhci_dbg_trace(xhci, trace_xhci_dbg_init, "disable MSI-X interrupt");
|
||||
xhci_free_irq(xhci);
|
||||
pci_disable_msix(pdev);
|
||||
free_entries:
|
||||
kfree(xhci->msix_entries);
|
||||
xhci->msix_entries = NULL;
|
||||
while (--i >= 0)
|
||||
free_irq(pci_irq_vector(pdev, i), xhci_to_hcd(xhci));
|
||||
pci_free_irq_vectors(pdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -346,27 +301,33 @@ static void xhci_cleanup_msix(struct xhci_hcd *xhci)
|
|||
if (xhci->quirks & XHCI_PLAT)
|
||||
return;
|
||||
|
||||
xhci_free_irq(xhci);
|
||||
/* return if using legacy interrupt */
|
||||
if (hcd->irq > 0)
|
||||
return;
|
||||
|
||||
if (xhci->msix_entries) {
|
||||
pci_disable_msix(pdev);
|
||||
kfree(xhci->msix_entries);
|
||||
xhci->msix_entries = NULL;
|
||||
if (hcd->msix_enabled) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < xhci->msix_count; i++)
|
||||
free_irq(pci_irq_vector(pdev, i), xhci_to_hcd(xhci));
|
||||
} else {
|
||||
pci_disable_msi(pdev);
|
||||
free_irq(pci_irq_vector(pdev, 0), xhci_to_hcd(xhci));
|
||||
}
|
||||
|
||||
pci_free_irq_vectors(pdev);
|
||||
hcd->msix_enabled = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
static void __maybe_unused xhci_msix_sync_irqs(struct xhci_hcd *xhci)
|
||||
{
|
||||
int i;
|
||||
struct usb_hcd *hcd = xhci_to_hcd(xhci);
|
||||
|
||||
if (hcd->msix_enabled) {
|
||||
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
|
||||
int i;
|
||||
|
||||
if (xhci->msix_entries) {
|
||||
for (i = 0; i < xhci->msix_count; i++)
|
||||
synchronize_irq(xhci->msix_entries[i].vector);
|
||||
synchronize_irq(pci_irq_vector(pdev, i));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -539,7 +500,7 @@ static int xhci_all_ports_seen_u0(struct xhci_hcd *xhci)
|
|||
* device contexts (?), set up a command ring segment (or two?), create event
|
||||
* ring (one for now).
|
||||
*/
|
||||
int xhci_init(struct usb_hcd *hcd)
|
||||
static int xhci_init(struct usb_hcd *hcd)
|
||||
{
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
int retval = 0;
|
||||
|
|
@ -619,16 +580,10 @@ int xhci_run(struct usb_hcd *hcd)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
xhci_dbg(xhci, "Command ring memory map follows:\n");
|
||||
xhci_debug_ring(xhci, xhci->cmd_ring);
|
||||
xhci_dbg_ring_ptrs(xhci, xhci->cmd_ring);
|
||||
xhci_dbg_cmd_ptrs(xhci);
|
||||
|
||||
xhci_dbg(xhci, "ERST memory map follows:\n");
|
||||
xhci_dbg_erst(xhci, &xhci->erst);
|
||||
xhci_dbg(xhci, "Event ring:\n");
|
||||
xhci_debug_ring(xhci, xhci->event_ring);
|
||||
xhci_dbg_ring_ptrs(xhci, xhci->event_ring);
|
||||
temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
|
||||
temp_64 &= ~ERST_PTR_MASK;
|
||||
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
|
||||
|
|
@ -661,9 +616,11 @@ int xhci_run(struct usb_hcd *hcd)
|
|||
|
||||
if (xhci->quirks & XHCI_NEC_HOST) {
|
||||
struct xhci_command *command;
|
||||
|
||||
command = xhci_alloc_command(xhci, false, false, GFP_KERNEL);
|
||||
if (!command)
|
||||
return -ENOMEM;
|
||||
|
||||
xhci_queue_vendor_command(xhci, command, 0, 0, 0,
|
||||
TRB_TYPE(TRB_NEC_GET_FW));
|
||||
}
|
||||
|
|
@ -682,28 +639,28 @@ EXPORT_SYMBOL_GPL(xhci_run);
|
|||
* Disable device contexts, disable IRQs, and quiesce the HC.
|
||||
* Reset the HC, finish any completed transactions, and cleanup memory.
|
||||
*/
|
||||
void xhci_stop(struct usb_hcd *hcd)
|
||||
static void xhci_stop(struct usb_hcd *hcd)
|
||||
{
|
||||
u32 temp;
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
|
||||
mutex_lock(&xhci->mutex);
|
||||
|
||||
if (!(xhci->xhc_state & XHCI_STATE_HALTED)) {
|
||||
spin_lock_irq(&xhci->lock);
|
||||
|
||||
xhci->xhc_state |= XHCI_STATE_HALTED;
|
||||
xhci->cmd_ring_state = CMD_RING_STATE_STOPPED;
|
||||
xhci_halt(xhci);
|
||||
xhci_reset(xhci);
|
||||
spin_unlock_irq(&xhci->lock);
|
||||
}
|
||||
|
||||
/* Only halt host and free memory after both hcds are removed */
|
||||
if (!usb_hcd_is_primary_hcd(hcd)) {
|
||||
/* usb core will free this hcd shortly, unset pointer */
|
||||
xhci->shared_hcd = NULL;
|
||||
mutex_unlock(&xhci->mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock_irq(&xhci->lock);
|
||||
xhci->xhc_state |= XHCI_STATE_HALTED;
|
||||
xhci->cmd_ring_state = CMD_RING_STATE_STOPPED;
|
||||
xhci_halt(xhci);
|
||||
xhci_reset(xhci);
|
||||
spin_unlock_irq(&xhci->lock);
|
||||
|
||||
xhci_cleanup_msix(xhci);
|
||||
|
||||
/* Deleting Compliance Mode Recovery Timer */
|
||||
|
|
@ -721,7 +678,7 @@ void xhci_stop(struct usb_hcd *hcd)
|
|||
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
|
||||
"// Disabling event ring interrupts");
|
||||
temp = readl(&xhci->op_regs->status);
|
||||
writel(temp & ~STS_EINT, &xhci->op_regs->status);
|
||||
writel((temp & ~0x1fff) | STS_EINT, &xhci->op_regs->status);
|
||||
temp = readl(&xhci->ir_set->irq_pending);
|
||||
writel(ER_IRQ_DISABLE(temp), &xhci->ir_set->irq_pending);
|
||||
xhci_print_ir_set(xhci, 0);
|
||||
|
|
@ -743,12 +700,12 @@ void xhci_stop(struct usb_hcd *hcd)
|
|||
*
|
||||
* This will only ever be called with the main usb_hcd (the USB3 roothub).
|
||||
*/
|
||||
void xhci_shutdown(struct usb_hcd *hcd)
|
||||
static void xhci_shutdown(struct usb_hcd *hcd)
|
||||
{
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
|
||||
if (xhci->quirks & XHCI_SPURIOUS_REBOOT)
|
||||
usb_disable_xhci_ports(to_pci_dev(hcd->self.controller));
|
||||
usb_disable_xhci_ports(to_pci_dev(hcd->self.sysdev));
|
||||
|
||||
spin_lock_irq(&xhci->lock);
|
||||
xhci_halt(xhci);
|
||||
|
|
@ -765,7 +722,7 @@ void xhci_shutdown(struct usb_hcd *hcd)
|
|||
|
||||
/* Yet another workaround for spurious wakeups at shutdown with HSW */
|
||||
if (xhci->quirks & XHCI_SPURIOUS_WAKEUP)
|
||||
pci_set_power_state(to_pci_dev(hcd->self.controller), PCI_D3hot);
|
||||
pci_set_power_state(to_pci_dev(hcd->self.sysdev), PCI_D3hot);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
|
@ -1054,7 +1011,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
|
|||
|
||||
xhci_dbg(xhci, "// Disabling event ring interrupts\n");
|
||||
temp = readl(&xhci->op_regs->status);
|
||||
writel(temp & ~STS_EINT, &xhci->op_regs->status);
|
||||
writel((temp & ~0x1fff) | STS_EINT, &xhci->op_regs->status);
|
||||
temp = readl(&xhci->ir_set->irq_pending);
|
||||
writel(ER_IRQ_DISABLE(temp), &xhci->ir_set->irq_pending);
|
||||
xhci_print_ir_set(xhci, 0);
|
||||
|
|
@ -1176,7 +1133,7 @@ unsigned int xhci_get_endpoint_address(unsigned int ep_index)
|
|||
* endpoint index to create a bitmask. The slot context is bit 0, endpoint 0 is
|
||||
* bit 1, etc.
|
||||
*/
|
||||
unsigned int xhci_get_endpoint_flag(struct usb_endpoint_descriptor *desc)
|
||||
static unsigned int xhci_get_endpoint_flag(struct usb_endpoint_descriptor *desc)
|
||||
{
|
||||
return 1 << (xhci_get_endpoint_index(desc) + 1);
|
||||
}
|
||||
|
|
@ -1185,7 +1142,7 @@ unsigned int xhci_get_endpoint_flag(struct usb_endpoint_descriptor *desc)
|
|||
* endpoint index to create a bitmask. The slot context is bit 0, endpoint 0 is
|
||||
* bit 1, etc.
|
||||
*/
|
||||
unsigned int xhci_get_endpoint_flag_from_index(unsigned int ep_index)
|
||||
static unsigned int xhci_get_endpoint_flag_from_index(unsigned int ep_index)
|
||||
{
|
||||
return 1 << (ep_index + 1);
|
||||
}
|
||||
|
|
@ -1306,11 +1263,6 @@ static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id,
|
|||
ctrl_ctx->add_flags = cpu_to_le32(EP0_FLAG);
|
||||
ctrl_ctx->drop_flags = 0;
|
||||
|
||||
xhci_dbg(xhci, "Slot %d input context\n", slot_id);
|
||||
xhci_dbg_ctx(xhci, command->in_ctx, ep_index);
|
||||
xhci_dbg(xhci, "Slot %d output context\n", slot_id);
|
||||
xhci_dbg_ctx(xhci, out_ctx, ep_index);
|
||||
|
||||
ret = xhci_configure_endpoint(xhci, urb->dev, command,
|
||||
true, false);
|
||||
|
||||
|
|
@ -1329,7 +1281,7 @@ command_cleanup:
|
|||
* non-error returns are a promise to giveback() the urb later
|
||||
* we drop ownership so next owner (or urb unlink) can get it
|
||||
*/
|
||||
int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
|
||||
static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
|
||||
{
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
unsigned long flags;
|
||||
|
|
@ -1465,7 +1417,7 @@ free_priv:
|
|||
* Note that this function can be called in any context, or so says
|
||||
* usb_hcd_unlink_urb()
|
||||
*/
|
||||
int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
|
||||
static int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
|
||||
{
|
||||
unsigned long flags;
|
||||
int ret, i;
|
||||
|
|
@ -1501,10 +1453,16 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
|
|||
if (!ep || !ep_ring)
|
||||
goto err_giveback;
|
||||
|
||||
/* If xHC is dead take it down and return ALL URBs in xhci_hc_died() */
|
||||
temp = readl(&xhci->op_regs->status);
|
||||
if (temp == 0xffffffff || (xhci->xhc_state & XHCI_STATE_HALTED)) {
|
||||
if (temp == ~(u32)0 || xhci->xhc_state & XHCI_STATE_DYING) {
|
||||
xhci_hc_died(xhci);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (xhci->xhc_state & XHCI_STATE_HALTED) {
|
||||
xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
|
||||
"HW died, freeing TD.");
|
||||
"HC halted, freeing TD manually.");
|
||||
for (i = urb_priv->num_tds_done;
|
||||
i < urb_priv->num_tds;
|
||||
i++) {
|
||||
|
|
@ -1576,7 +1534,7 @@ err_giveback:
|
|||
* disabled, so there's no need for mutual exclusion to protect
|
||||
* the xhci->devs[slot_id] structure.
|
||||
*/
|
||||
int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
|
||||
static int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
|
||||
struct usb_host_endpoint *ep)
|
||||
{
|
||||
struct xhci_hcd *xhci;
|
||||
|
|
@ -1659,7 +1617,7 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
|
|||
* configuration or alt setting is installed in the device, so there's no need
|
||||
* for mutual exclusion to protect the xhci->devs[slot_id] structure.
|
||||
*/
|
||||
int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
|
||||
static int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
|
||||
struct usb_host_endpoint *ep)
|
||||
{
|
||||
struct xhci_hcd *xhci;
|
||||
|
|
@ -1852,7 +1810,6 @@ static int xhci_evaluate_context_result(struct xhci_hcd *xhci,
|
|||
struct usb_device *udev, u32 *cmd_status)
|
||||
{
|
||||
int ret;
|
||||
struct xhci_virt_device *virt_dev = xhci->devs[udev->slot_id];
|
||||
|
||||
switch (*cmd_status) {
|
||||
case COMP_COMMAND_ABORTED:
|
||||
|
|
@ -1873,7 +1830,6 @@ static int xhci_evaluate_context_result(struct xhci_hcd *xhci,
|
|||
case COMP_CONTEXT_STATE_ERROR:
|
||||
dev_warn(&udev->dev,
|
||||
"WARN: invalid context state for evaluate context command.\n");
|
||||
xhci_dbg_ctx(xhci, virt_dev->out_ctx, 1);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
case COMP_INCOMPATIBLE_DEVICE_ERROR:
|
||||
|
|
@ -2330,7 +2286,7 @@ static unsigned int xhci_get_ss_bw_consumed(struct xhci_bw_info *ep_bw)
|
|||
|
||||
}
|
||||
|
||||
void xhci_drop_ep_from_interval_table(struct xhci_hcd *xhci,
|
||||
static void xhci_drop_ep_from_interval_table(struct xhci_hcd *xhci,
|
||||
struct xhci_bw_info *ep_bw,
|
||||
struct xhci_interval_bw_table *bw_table,
|
||||
struct usb_device *udev,
|
||||
|
|
@ -2595,6 +2551,12 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
|
|||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
|
||||
if (xhci->xhc_state & XHCI_STATE_DYING) {
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
return -ESHUTDOWN;
|
||||
}
|
||||
|
||||
virt_dev = xhci->devs[udev->slot_id];
|
||||
|
||||
ctrl_ctx = xhci_get_input_control_ctx(command->in_ctx);
|
||||
|
|
@ -2689,7 +2651,7 @@ static void xhci_check_bw_drop_ep_streams(struct xhci_hcd *xhci,
|
|||
* else should be touching the xhci->devs[slot_id] structure, so we
|
||||
* don't need to take the xhci->lock for manipulating that.
|
||||
*/
|
||||
int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
|
||||
static int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
|
||||
{
|
||||
int i;
|
||||
int ret = 0;
|
||||
|
|
@ -2746,9 +2708,6 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
|
|||
break;
|
||||
}
|
||||
}
|
||||
xhci_dbg(xhci, "New Input Control Context:\n");
|
||||
xhci_dbg_ctx(xhci, virt_dev->in_ctx,
|
||||
LAST_CTX_TO_EP_NUM(le32_to_cpu(slot_ctx->dev_info)));
|
||||
|
||||
ret = xhci_configure_endpoint(xhci, udev, command,
|
||||
false, false);
|
||||
|
|
@ -2756,10 +2715,6 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
|
|||
/* Callee should call reset_bandwidth() */
|
||||
goto command_cleanup;
|
||||
|
||||
xhci_dbg(xhci, "Output context after successful config ep cmd:\n");
|
||||
xhci_dbg_ctx(xhci, virt_dev->out_ctx,
|
||||
LAST_CTX_TO_EP_NUM(le32_to_cpu(slot_ctx->dev_info)));
|
||||
|
||||
/* Free any rings that were dropped, but not changed. */
|
||||
for (i = 1; i < 31; i++) {
|
||||
if ((le32_to_cpu(ctrl_ctx->drop_flags) & (1 << (i + 1))) &&
|
||||
|
|
@ -2793,7 +2748,7 @@ command_cleanup:
|
|||
return ret;
|
||||
}
|
||||
|
||||
void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
|
||||
static void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
|
||||
{
|
||||
struct xhci_hcd *xhci;
|
||||
struct xhci_virt_device *virt_dev;
|
||||
|
|
@ -2826,9 +2781,6 @@ static void xhci_setup_input_ctx_for_config_ep(struct xhci_hcd *xhci,
|
|||
ctrl_ctx->drop_flags = cpu_to_le32(drop_flags);
|
||||
xhci_slot_copy(xhci, in_ctx, out_ctx);
|
||||
ctrl_ctx->add_flags |= cpu_to_le32(SLOT_FLAG);
|
||||
|
||||
xhci_dbg(xhci, "Input Context:\n");
|
||||
xhci_dbg_ctx(xhci, in_ctx, xhci_last_valid_endpoint(add_flags));
|
||||
}
|
||||
|
||||
static void xhci_setup_input_ctx_for_quirk(struct xhci_hcd *xhci,
|
||||
|
|
@ -2919,7 +2871,7 @@ void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci,
|
|||
* Context: in_interrupt
|
||||
*/
|
||||
|
||||
void xhci_endpoint_reset(struct usb_hcd *hcd,
|
||||
static void xhci_endpoint_reset(struct usb_hcd *hcd,
|
||||
struct usb_host_endpoint *ep)
|
||||
{
|
||||
struct xhci_hcd *xhci;
|
||||
|
|
@ -3095,7 +3047,7 @@ static u32 xhci_calculate_no_streams_bitmask(struct xhci_hcd *xhci,
|
|||
* hardware or endpoints claim they can't support the number of requested
|
||||
* stream IDs.
|
||||
*/
|
||||
int xhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev,
|
||||
static int xhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev,
|
||||
struct usb_host_endpoint **eps, unsigned int num_eps,
|
||||
unsigned int num_streams, gfp_t mem_flags)
|
||||
{
|
||||
|
|
@ -3129,10 +3081,9 @@ int xhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev,
|
|||
}
|
||||
|
||||
config_cmd = xhci_alloc_command(xhci, true, true, mem_flags);
|
||||
if (!config_cmd) {
|
||||
xhci_dbg(xhci, "Could not allocate xHCI command structure.\n");
|
||||
if (!config_cmd)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ctrl_ctx = xhci_get_input_control_ctx(config_cmd->in_ctx);
|
||||
if (!ctrl_ctx) {
|
||||
xhci_warn(xhci, "%s: Could not get input context, bad type.\n",
|
||||
|
|
@ -3259,7 +3210,7 @@ cleanup:
|
|||
* Modify the endpoint context state, submit a configure endpoint command,
|
||||
* and free all endpoint rings for streams if that completes successfully.
|
||||
*/
|
||||
int xhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
|
||||
static int xhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
|
||||
struct usb_host_endpoint **eps, unsigned int num_eps,
|
||||
gfp_t mem_flags)
|
||||
{
|
||||
|
|
@ -3391,7 +3342,8 @@ void xhci_free_device_endpoint_resources(struct xhci_hcd *xhci,
|
|||
* re-initialization during S3/S4. In this case, call xhci_alloc_dev() to
|
||||
* re-allocate the device.
|
||||
*/
|
||||
int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
|
||||
static int xhci_discover_or_reset_device(struct usb_hcd *hcd,
|
||||
struct usb_device *udev)
|
||||
{
|
||||
int ret, i;
|
||||
unsigned long flags;
|
||||
|
|
@ -3443,6 +3395,8 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
|
|||
SLOT_STATE_DISABLED)
|
||||
return 0;
|
||||
|
||||
trace_xhci_discover_or_reset_device(slot_ctx);
|
||||
|
||||
xhci_dbg(xhci, "Resetting device with slot ID %u\n", slot_id);
|
||||
/* Allocate the command structure that holds the struct completion.
|
||||
* Assume we're in process context, since the normal device reset
|
||||
|
|
@ -3539,9 +3493,6 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
|
|||
}
|
||||
/* If necessary, update the number of active TTs on this root port */
|
||||
xhci_update_tt_active_eps(xhci, virt_dev, old_active_eps);
|
||||
|
||||
xhci_dbg(xhci, "Output context after successful reset device cmd:\n");
|
||||
xhci_dbg_ctx(xhci, virt_dev->out_ctx, last_freed_endpoint);
|
||||
ret = 0;
|
||||
|
||||
command_cleanup:
|
||||
|
|
@ -3554,12 +3505,11 @@ command_cleanup:
|
|||
* disconnected, and all traffic has been stopped and the endpoints have been
|
||||
* disabled. Free any HC data structures associated with that device.
|
||||
*/
|
||||
void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
|
||||
static void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
|
||||
{
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
struct xhci_virt_device *virt_dev;
|
||||
unsigned long flags;
|
||||
u32 state;
|
||||
struct xhci_slot_ctx *slot_ctx;
|
||||
int i, ret;
|
||||
struct xhci_command *command;
|
||||
|
||||
|
|
@ -3587,6 +3537,8 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
|
|||
}
|
||||
|
||||
virt_dev = xhci->devs[udev->slot_id];
|
||||
slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->out_ctx);
|
||||
trace_xhci_free_dev(slot_ctx);
|
||||
|
||||
/* Stop any wayward timer functions (which may grab the lock) */
|
||||
for (i = 0; i < 31; i++) {
|
||||
|
|
@ -3594,30 +3546,50 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
|
|||
del_timer_sync(&virt_dev->eps[i].stop_cmd_timer);
|
||||
}
|
||||
|
||||
xhci_disable_slot(xhci, command, udev->slot_id);
|
||||
/*
|
||||
* Event command completion handler will free any data structures
|
||||
* associated with the slot. XXX Can free sleep?
|
||||
*/
|
||||
}
|
||||
|
||||
int xhci_disable_slot(struct xhci_hcd *xhci, struct xhci_command *command,
|
||||
u32 slot_id)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 state;
|
||||
int ret = 0;
|
||||
struct xhci_virt_device *virt_dev;
|
||||
|
||||
virt_dev = xhci->devs[slot_id];
|
||||
if (!virt_dev)
|
||||
return -EINVAL;
|
||||
if (!command)
|
||||
command = xhci_alloc_command(xhci, false, false, GFP_KERNEL);
|
||||
if (!command)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
/* Don't disable the slot if the host controller is dead. */
|
||||
state = readl(&xhci->op_regs->status);
|
||||
if (state == 0xffffffff || (xhci->xhc_state & XHCI_STATE_DYING) ||
|
||||
(xhci->xhc_state & XHCI_STATE_HALTED)) {
|
||||
xhci_free_virt_device(xhci, udev->slot_id);
|
||||
xhci_free_virt_device(xhci, slot_id);
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
kfree(command);
|
||||
return;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (xhci_queue_slot_control(xhci, command, TRB_DISABLE_SLOT,
|
||||
udev->slot_id)) {
|
||||
ret = xhci_queue_slot_control(xhci, command, TRB_DISABLE_SLOT,
|
||||
slot_id);
|
||||
if (ret) {
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
xhci_dbg(xhci, "FIXME: allocate a command ring segment\n");
|
||||
return;
|
||||
return ret;
|
||||
}
|
||||
xhci_ring_cmd_db(xhci);
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
|
||||
/*
|
||||
* Event command completion handler will free any data structures
|
||||
* associated with the slot. XXX Can free sleep?
|
||||
*/
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -3650,6 +3622,8 @@ static int xhci_reserve_host_control_ep_resources(struct xhci_hcd *xhci)
|
|||
int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
|
||||
{
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
struct xhci_virt_device *vdev;
|
||||
struct xhci_slot_ctx *slot_ctx;
|
||||
unsigned long flags;
|
||||
int ret, slot_id;
|
||||
struct xhci_command *command;
|
||||
|
|
@ -3705,6 +3679,10 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
|
|||
xhci_warn(xhci, "Could not allocate xHCI USB device data structures\n");
|
||||
goto disable_slot;
|
||||
}
|
||||
vdev = xhci->devs[slot_id];
|
||||
slot_ctx = xhci_get_slot_ctx(xhci, vdev->out_ctx);
|
||||
trace_xhci_alloc_dev(slot_ctx);
|
||||
|
||||
udev->slot_id = slot_id;
|
||||
|
||||
#ifndef CONFIG_USB_DEFAULT_PERSIST
|
||||
|
|
@ -3724,15 +3702,10 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
|
|||
|
||||
disable_slot:
|
||||
/* Disable slot, if we can do it without mem alloc */
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
kfree(command->completion);
|
||||
command->completion = NULL;
|
||||
command->status = 0;
|
||||
if (!xhci_queue_slot_control(xhci, command, TRB_DISABLE_SLOT,
|
||||
udev->slot_id))
|
||||
xhci_ring_cmd_db(xhci);
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
return 0;
|
||||
return xhci_disable_slot(xhci, command, udev->slot_id);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -3779,9 +3752,10 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
|
|||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->out_ctx);
|
||||
trace_xhci_setup_device_slot(slot_ctx);
|
||||
|
||||
if (setup == SETUP_CONTEXT_ONLY) {
|
||||
slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->out_ctx);
|
||||
if (GET_SLOT_STATE(le32_to_cpu(slot_ctx->dev_state)) ==
|
||||
SLOT_STATE_DEFAULT) {
|
||||
xhci_dbg(xhci, "Slot already in default state\n");
|
||||
|
|
@ -3818,8 +3792,6 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
|
|||
ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG | EP0_FLAG);
|
||||
ctrl_ctx->drop_flags = 0;
|
||||
|
||||
xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id);
|
||||
xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2);
|
||||
trace_xhci_address_ctx(xhci, virt_dev->in_ctx,
|
||||
le32_to_cpu(slot_ctx->dev_info) >> 27);
|
||||
|
||||
|
|
@ -3872,8 +3844,6 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
|
|||
xhci_err(xhci,
|
||||
"ERROR: unexpected setup %s command completion code 0x%x.\n",
|
||||
act, command->status);
|
||||
xhci_dbg(xhci, "Slot ID %d Output Context:\n", udev->slot_id);
|
||||
xhci_dbg_ctx(xhci, virt_dev->out_ctx, 2);
|
||||
trace_xhci_address_ctx(xhci, virt_dev->out_ctx, 1);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
|
|
@ -3892,17 +3862,12 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
|
|||
xhci_dbg_trace(xhci, trace_xhci_dbg_address,
|
||||
"Output Context DMA address = %#08llx",
|
||||
(unsigned long long)virt_dev->out_ctx->dma);
|
||||
xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id);
|
||||
xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2);
|
||||
trace_xhci_address_ctx(xhci, virt_dev->in_ctx,
|
||||
le32_to_cpu(slot_ctx->dev_info) >> 27);
|
||||
xhci_dbg(xhci, "Slot ID %d Output Context:\n", udev->slot_id);
|
||||
xhci_dbg_ctx(xhci, virt_dev->out_ctx, 2);
|
||||
/*
|
||||
* USB core uses address 1 for the roothubs, so we add one to the
|
||||
* address given back to us by the HC.
|
||||
*/
|
||||
slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->out_ctx);
|
||||
trace_xhci_address_ctx(xhci, virt_dev->out_ctx,
|
||||
le32_to_cpu(slot_ctx->dev_info) >> 27);
|
||||
/* Zero the input context control for later use */
|
||||
|
|
@ -3921,12 +3886,12 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
|
||||
static int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
|
||||
{
|
||||
return xhci_setup_device(hcd, udev, SETUP_CONTEXT_ADDRESS);
|
||||
}
|
||||
|
||||
int xhci_enable_device(struct usb_hcd *hcd, struct usb_device *udev)
|
||||
static int xhci_enable_device(struct usb_hcd *hcd, struct usb_device *udev)
|
||||
{
|
||||
return xhci_setup_device(hcd, udev, SETUP_CONTEXT_ONLY);
|
||||
}
|
||||
|
|
@ -4003,14 +3968,10 @@ static int __maybe_unused xhci_change_max_exit_latency(struct xhci_hcd *xhci,
|
|||
|
||||
xhci_dbg_trace(xhci, trace_xhci_dbg_context_change,
|
||||
"Set up evaluate context for LPM MEL change.");
|
||||
xhci_dbg(xhci, "Slot %u Input Context:\n", udev->slot_id);
|
||||
xhci_dbg_ctx(xhci, command->in_ctx, 0);
|
||||
|
||||
/* Issue and wait for the evaluate context command. */
|
||||
ret = xhci_configure_endpoint(xhci, udev, command,
|
||||
true, true);
|
||||
xhci_dbg(xhci, "Slot %u Output Context:\n", udev->slot_id);
|
||||
xhci_dbg_ctx(xhci, virt_dev->out_ctx, 0);
|
||||
|
||||
if (!ret) {
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
|
|
@ -4083,7 +4044,7 @@ static int xhci_calculate_usb2_hw_lpm_params(struct usb_device *udev)
|
|||
return PORT_BESLD(besld) | PORT_L1_TIMEOUT(l1) | PORT_HIRDM(hirdm);
|
||||
}
|
||||
|
||||
int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
|
||||
static int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
|
||||
struct usb_device *udev, int enable)
|
||||
{
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
|
|
@ -4207,7 +4168,7 @@ static int xhci_check_usb2_port_capability(struct xhci_hcd *xhci, int port,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev)
|
||||
static int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev)
|
||||
{
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
int portnum = udev->portnum - 1;
|
||||
|
|
@ -4616,7 +4577,7 @@ static int calculate_max_exit_latency(struct usb_device *udev,
|
|||
}
|
||||
|
||||
/* Returns the USB3 hub-encoded value for the U1/U2 timeout. */
|
||||
int xhci_enable_usb3_lpm_timeout(struct usb_hcd *hcd,
|
||||
static int xhci_enable_usb3_lpm_timeout(struct usb_hcd *hcd,
|
||||
struct usb_device *udev, enum usb3_link_state state)
|
||||
{
|
||||
struct xhci_hcd *xhci;
|
||||
|
|
@ -4647,7 +4608,7 @@ int xhci_enable_usb3_lpm_timeout(struct usb_hcd *hcd,
|
|||
return hub_encoded_timeout;
|
||||
}
|
||||
|
||||
int xhci_disable_usb3_lpm_timeout(struct usb_hcd *hcd,
|
||||
static int xhci_disable_usb3_lpm_timeout(struct usb_hcd *hcd,
|
||||
struct usb_device *udev, enum usb3_link_state state)
|
||||
{
|
||||
struct xhci_hcd *xhci;
|
||||
|
|
@ -4663,24 +4624,24 @@ int xhci_disable_usb3_lpm_timeout(struct usb_hcd *hcd,
|
|||
}
|
||||
#else /* CONFIG_PM */
|
||||
|
||||
int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
|
||||
static int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
|
||||
struct usb_device *udev, int enable)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev)
|
||||
static int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xhci_enable_usb3_lpm_timeout(struct usb_hcd *hcd,
|
||||
static int xhci_enable_usb3_lpm_timeout(struct usb_hcd *hcd,
|
||||
struct usb_device *udev, enum usb3_link_state state)
|
||||
{
|
||||
return USB3_LPM_DISABLED;
|
||||
}
|
||||
|
||||
int xhci_disable_usb3_lpm_timeout(struct usb_hcd *hcd,
|
||||
static int xhci_disable_usb3_lpm_timeout(struct usb_hcd *hcd,
|
||||
struct usb_device *udev, enum usb3_link_state state)
|
||||
{
|
||||
return 0;
|
||||
|
|
@ -4692,7 +4653,7 @@ int xhci_disable_usb3_lpm_timeout(struct usb_hcd *hcd,
|
|||
/* Once a hub descriptor is fetched for a device, we need to update the xHC's
|
||||
* internal data structures for the device.
|
||||
*/
|
||||
int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
|
||||
static int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
|
||||
struct usb_tt *tt, gfp_t mem_flags)
|
||||
{
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
|
|
@ -4713,11 +4674,11 @@ int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
|
|||
xhci_warn(xhci, "Cannot update hub desc for unknown device.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
config_cmd = xhci_alloc_command(xhci, true, true, mem_flags);
|
||||
if (!config_cmd) {
|
||||
xhci_dbg(xhci, "Could not allocate xHCI command structure.\n");
|
||||
if (!config_cmd)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ctrl_ctx = xhci_get_input_control_ctx(config_cmd->in_ctx);
|
||||
if (!ctrl_ctx) {
|
||||
xhci_warn(xhci, "%s: Could not get input context, bad type.\n",
|
||||
|
|
@ -4778,8 +4739,6 @@ int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
|
|||
xhci_dbg(xhci, "Set up %s for hub device.\n",
|
||||
(xhci->hci_version > 0x95) ?
|
||||
"configure endpoint" : "evaluate context");
|
||||
xhci_dbg(xhci, "Slot %u Input Context:\n", hdev->slot_id);
|
||||
xhci_dbg_ctx(xhci, config_cmd->in_ctx, 0);
|
||||
|
||||
/* Issue and wait for the configure endpoint or
|
||||
* evaluate context command.
|
||||
|
|
@ -4791,14 +4750,11 @@ int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
|
|||
ret = xhci_configure_endpoint(xhci, hdev, config_cmd,
|
||||
true, false);
|
||||
|
||||
xhci_dbg(xhci, "Slot %u Output Context:\n", hdev->slot_id);
|
||||
xhci_dbg_ctx(xhci, vdev->out_ctx, 0);
|
||||
|
||||
xhci_free_command(xhci, config_cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xhci_get_frame(struct usb_hcd *hcd)
|
||||
static int xhci_get_frame(struct usb_hcd *hcd)
|
||||
{
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
/* EHCI mods by the periodic size. Why? */
|
||||
|
|
@ -4808,7 +4764,11 @@ int xhci_get_frame(struct usb_hcd *hcd)
|
|||
int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
|
||||
{
|
||||
struct xhci_hcd *xhci;
|
||||
struct device *dev = hcd->self.controller;
|
||||
/*
|
||||
* TODO: Check with DWC3 clients for sysdev according to
|
||||
* quirks
|
||||
*/
|
||||
struct device *dev = hcd->self.sysdev;
|
||||
int retval;
|
||||
|
||||
/* Accept arbitrarily long scatter-gather lists */
|
||||
|
|
|
|||
|
|
@ -425,6 +425,7 @@ struct xhci_op_regs {
|
|||
#define PORT_L1DS_MASK (0xff << 8)
|
||||
#define PORT_L1DS(p) (((p) & 0xff) << 8)
|
||||
#define PORT_HLE (1 << 16)
|
||||
#define PORT_TEST_MODE_SHIFT 28
|
||||
|
||||
/* USB3 Protocol PORTLI Port Link Information */
|
||||
#define PORT_RX_LANES(p) (((p) >> 16) & 0xf)
|
||||
|
|
@ -617,6 +618,7 @@ struct xhci_slot_ctx {
|
|||
#define ROUTE_STRING_MASK (0xfffff)
|
||||
/* Device speed - values defined by PORTSC Device Speed field - 20:23 */
|
||||
#define DEV_SPEED (0xf << 20)
|
||||
#define GET_DEV_SPEED(n) (((n) & DEV_SPEED) >> 20)
|
||||
/* bit 24 reserved */
|
||||
/* Is this LS/FS device connected through a HS hub? - bit 25 */
|
||||
#define DEV_MTT (0x1 << 25)
|
||||
|
|
@ -637,6 +639,7 @@ struct xhci_slot_ctx {
|
|||
#define DEVINFO_TO_ROOT_HUB_PORT(p) (((p) >> 16) & 0xff)
|
||||
/* Maximum number of ports under a hub device */
|
||||
#define XHCI_MAX_PORTS(p) (((p) & 0xff) << 24)
|
||||
#define DEVINFO_TO_MAX_PORTS(p) (((p) & (0xff << 24)) >> 24)
|
||||
|
||||
/* tt_info bitmasks */
|
||||
/*
|
||||
|
|
@ -651,6 +654,7 @@ struct xhci_slot_ctx {
|
|||
*/
|
||||
#define TT_PORT (0xff << 8)
|
||||
#define TT_THINK_TIME(p) (((p) & 0x3) << 16)
|
||||
#define GET_TT_THINK_TIME(p) (((p) & (0x3 << 16)) >> 16)
|
||||
|
||||
/* dev_state bitmasks */
|
||||
/* USB device address - assigned by the HC */
|
||||
|
|
@ -1562,10 +1566,8 @@ struct xhci_ring {
|
|||
struct xhci_segment *last_seg;
|
||||
union xhci_trb *enqueue;
|
||||
struct xhci_segment *enq_seg;
|
||||
unsigned int enq_updates;
|
||||
union xhci_trb *dequeue;
|
||||
struct xhci_segment *deq_seg;
|
||||
unsigned int deq_updates;
|
||||
struct list_head td_list;
|
||||
/*
|
||||
* Write the cycle state into the TRB cycle field to give ownership of
|
||||
|
|
@ -1604,7 +1606,6 @@ struct xhci_scratchpad {
|
|||
u64 *sp_array;
|
||||
dma_addr_t sp_dma;
|
||||
void **sp_buffers;
|
||||
dma_addr_t *sp_dma_buffers;
|
||||
};
|
||||
|
||||
struct urb_priv {
|
||||
|
|
@ -1722,7 +1723,6 @@ struct xhci_hcd {
|
|||
int page_shift;
|
||||
/* msi-x vectors */
|
||||
int msix_count;
|
||||
struct msix_entry *msix_entries;
|
||||
/* optional clock */
|
||||
struct clk *clk;
|
||||
/* data structures */
|
||||
|
|
@ -1818,6 +1818,7 @@ struct xhci_hcd {
|
|||
#define XHCI_MISSING_CAS (1 << 24)
|
||||
/* For controller with a broken Port Disable implementation */
|
||||
#define XHCI_BROKEN_PORT_PED (1 << 25)
|
||||
#define XHCI_LIMIT_ENDPOINT_INTERVAL_7 (1 << 26)
|
||||
|
||||
unsigned int num_active_eps;
|
||||
unsigned int limit_active_eps;
|
||||
|
|
@ -1843,6 +1844,7 @@ struct xhci_hcd {
|
|||
/* Compliance Mode Recovery Data */
|
||||
struct timer_list comp_mode_recovery_timer;
|
||||
u32 port_status_u0;
|
||||
u16 test_mode;
|
||||
/* Compliance Mode Timer Triggered every 2 seconds */
|
||||
#define COMP_MODE_RCVRY_MSECS 2000
|
||||
|
||||
|
|
@ -1918,19 +1920,10 @@ void xhci_print_ir_set(struct xhci_hcd *xhci, int set_num);
|
|||
void xhci_print_registers(struct xhci_hcd *xhci);
|
||||
void xhci_dbg_regs(struct xhci_hcd *xhci);
|
||||
void xhci_print_run_regs(struct xhci_hcd *xhci);
|
||||
void xhci_print_trb_offsets(struct xhci_hcd *xhci, union xhci_trb *trb);
|
||||
void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb);
|
||||
void xhci_debug_segment(struct xhci_hcd *xhci, struct xhci_segment *seg);
|
||||
void xhci_debug_ring(struct xhci_hcd *xhci, struct xhci_ring *ring);
|
||||
void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst);
|
||||
void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci);
|
||||
void xhci_dbg_ring_ptrs(struct xhci_hcd *xhci, struct xhci_ring *ring);
|
||||
void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, unsigned int last_ep);
|
||||
char *xhci_get_slot_state(struct xhci_hcd *xhci,
|
||||
struct xhci_container_ctx *ctx);
|
||||
void xhci_dbg_ep_rings(struct xhci_hcd *xhci,
|
||||
unsigned int slot_id, unsigned int ep_index,
|
||||
struct xhci_virt_ep *ep);
|
||||
void xhci_dbg_trace(struct xhci_hcd *xhci, void (*trace)(struct va_format *),
|
||||
const char *fmt, ...);
|
||||
|
||||
|
|
@ -1944,16 +1937,8 @@ void xhci_copy_ep0_dequeue_into_input_ctx(struct xhci_hcd *xhci,
|
|||
struct usb_device *udev);
|
||||
unsigned int xhci_get_endpoint_index(struct usb_endpoint_descriptor *desc);
|
||||
unsigned int xhci_get_endpoint_address(unsigned int ep_index);
|
||||
unsigned int xhci_get_endpoint_flag(struct usb_endpoint_descriptor *desc);
|
||||
unsigned int xhci_get_endpoint_flag_from_index(unsigned int ep_index);
|
||||
unsigned int xhci_last_valid_endpoint(u32 added_ctxs);
|
||||
void xhci_endpoint_zero(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, struct usb_host_endpoint *ep);
|
||||
void xhci_drop_ep_from_interval_table(struct xhci_hcd *xhci,
|
||||
struct xhci_bw_info *ep_bw,
|
||||
struct xhci_interval_bw_table *bw_table,
|
||||
struct usb_device *udev,
|
||||
struct xhci_virt_ep *virt_ep,
|
||||
struct xhci_tt_bw_info *tt_info);
|
||||
void xhci_update_tt_active_eps(struct xhci_hcd *xhci,
|
||||
struct xhci_virt_device *virt_dev,
|
||||
int old_active_eps);
|
||||
|
|
@ -2010,53 +1995,25 @@ typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *);
|
|||
int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, int usec);
|
||||
void xhci_quiesce(struct xhci_hcd *xhci);
|
||||
int xhci_halt(struct xhci_hcd *xhci);
|
||||
int xhci_start(struct xhci_hcd *xhci);
|
||||
int xhci_reset(struct xhci_hcd *xhci);
|
||||
int xhci_init(struct usb_hcd *hcd);
|
||||
int xhci_run(struct usb_hcd *hcd);
|
||||
void xhci_stop(struct usb_hcd *hcd);
|
||||
void xhci_shutdown(struct usb_hcd *hcd);
|
||||
int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks);
|
||||
void xhci_init_driver(struct hc_driver *drv,
|
||||
const struct xhci_driver_overrides *over);
|
||||
int xhci_disable_slot(struct xhci_hcd *xhci,
|
||||
struct xhci_command *command, u32 slot_id);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup);
|
||||
int xhci_resume(struct xhci_hcd *xhci, bool hibernated);
|
||||
#else
|
||||
#define xhci_suspend NULL
|
||||
#define xhci_resume NULL
|
||||
#endif
|
||||
|
||||
int xhci_get_frame(struct usb_hcd *hcd);
|
||||
irqreturn_t xhci_irq(struct usb_hcd *hcd);
|
||||
irqreturn_t xhci_msi_irq(int irq, void *hcd);
|
||||
int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev);
|
||||
void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev);
|
||||
int xhci_alloc_tt_info(struct xhci_hcd *xhci,
|
||||
struct xhci_virt_device *virt_dev,
|
||||
struct usb_device *hdev,
|
||||
struct usb_tt *tt, gfp_t mem_flags);
|
||||
int xhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev,
|
||||
struct usb_host_endpoint **eps, unsigned int num_eps,
|
||||
unsigned int num_streams, gfp_t mem_flags);
|
||||
int xhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
|
||||
struct usb_host_endpoint **eps, unsigned int num_eps,
|
||||
gfp_t mem_flags);
|
||||
int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev);
|
||||
int xhci_enable_device(struct usb_hcd *hcd, struct usb_device *udev);
|
||||
int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev);
|
||||
int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
|
||||
struct usb_device *udev, int enable);
|
||||
int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
|
||||
struct usb_tt *tt, gfp_t mem_flags);
|
||||
int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags);
|
||||
int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status);
|
||||
int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep);
|
||||
int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep);
|
||||
void xhci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep);
|
||||
int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev);
|
||||
int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
|
||||
void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
|
||||
|
||||
/* xHCI ring, segment, TRB, and TD functions */
|
||||
dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg, union xhci_trb *trb);
|
||||
|
|
@ -2100,9 +2057,6 @@ void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci,
|
|||
struct xhci_dequeue_state *deq_state);
|
||||
void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci,
|
||||
unsigned int ep_index, struct xhci_td *td);
|
||||
void xhci_queue_config_ep_quirk(struct xhci_hcd *xhci,
|
||||
unsigned int slot_id, unsigned int ep_index,
|
||||
struct xhci_dequeue_state *deq_state);
|
||||
void xhci_stop_endpoint_command_watchdog(unsigned long arg);
|
||||
void xhci_handle_command_timeout(struct work_struct *work);
|
||||
|
||||
|
|
@ -2113,16 +2067,13 @@ void xhci_cleanup_command_queue(struct xhci_hcd *xhci);
|
|||
/* xHCI roothub code */
|
||||
void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array,
|
||||
int port_id, u32 link_state);
|
||||
int xhci_enable_usb3_lpm_timeout(struct usb_hcd *hcd,
|
||||
struct usb_device *udev, enum usb3_link_state state);
|
||||
int xhci_disable_usb3_lpm_timeout(struct usb_hcd *hcd,
|
||||
struct usb_device *udev, enum usb3_link_state state);
|
||||
void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,
|
||||
int port_id, u32 port_bit);
|
||||
int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,
|
||||
char *buf, u16 wLength);
|
||||
int xhci_hub_status_data(struct usb_hcd *hcd, char *buf);
|
||||
int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1);
|
||||
void xhci_hc_died(struct xhci_hcd *xhci);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
int xhci_bus_suspend(struct usb_hcd *hcd);
|
||||
|
|
@ -2153,6 +2104,22 @@ static inline struct xhci_ring *xhci_urb_to_transfer_ring(struct xhci_hcd *xhci,
|
|||
urb->stream_id);
|
||||
}
|
||||
|
||||
static inline char *xhci_slot_state_string(u32 state)
|
||||
{
|
||||
switch (state) {
|
||||
case SLOT_STATE_ENABLED:
|
||||
return "enabled/disabled";
|
||||
case SLOT_STATE_DEFAULT:
|
||||
return "default";
|
||||
case SLOT_STATE_ADDRESSED:
|
||||
return "addressed";
|
||||
case SLOT_STATE_CONFIGURED:
|
||||
return "configured";
|
||||
default:
|
||||
return "reserved";
|
||||
}
|
||||
}
|
||||
|
||||
static inline const char *xhci_decode_trb(u32 field0, u32 field1, u32 field2,
|
||||
u32 field3)
|
||||
{
|
||||
|
|
@ -2162,14 +2129,12 @@ static inline const char *xhci_decode_trb(u32 field0, u32 field1, u32 field2,
|
|||
switch (type) {
|
||||
case TRB_LINK:
|
||||
sprintf(str,
|
||||
"TRB %08x%08x status '%s' len %d slot %d ep %d type '%s' flags %c:%c",
|
||||
field1, field0,
|
||||
xhci_trb_comp_code_string(GET_COMP_CODE(field2)),
|
||||
EVENT_TRB_LEN(field2), TRB_TO_SLOT_ID(field3),
|
||||
/* Macro decrements 1, maybe it shouldn't?!? */
|
||||
TRB_TO_EP_INDEX(field3) + 1,
|
||||
xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)),
|
||||
field3 & EVENT_DATA ? 'E' : 'e',
|
||||
"LINK %08x%08x intr %d type '%s' flags %c:%c:%c:%c",
|
||||
field1, field0, GET_INTR_TARGET(field2),
|
||||
xhci_trb_type_string(type),
|
||||
field3 & TRB_IOC ? 'I' : 'i',
|
||||
field3 & TRB_CHAIN ? 'C' : 'c',
|
||||
field3 & TRB_TC ? 'T' : 't',
|
||||
field3 & TRB_CYCLE ? 'C' : 'c');
|
||||
break;
|
||||
case TRB_TRANSFER:
|
||||
|
|
@ -2187,37 +2152,52 @@ static inline const char *xhci_decode_trb(u32 field0, u32 field1, u32 field2,
|
|||
EVENT_TRB_LEN(field2), TRB_TO_SLOT_ID(field3),
|
||||
/* Macro decrements 1, maybe it shouldn't?!? */
|
||||
TRB_TO_EP_INDEX(field3) + 1,
|
||||
xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)),
|
||||
xhci_trb_type_string(type),
|
||||
field3 & EVENT_DATA ? 'E' : 'e',
|
||||
field3 & TRB_CYCLE ? 'C' : 'c');
|
||||
|
||||
break;
|
||||
case TRB_SETUP:
|
||||
sprintf(str,
|
||||
"bRequestType %02x bRequest %02x wValue %02x%02x wIndex %02x%02x wLength %d length %d TD size %d intr %d type '%s' flags %c:%c:%c:%c:%c:%c:%c:%c",
|
||||
field0 & 0xff,
|
||||
(field0 & 0xff00) >> 8,
|
||||
(field0 & 0xff000000) >> 24,
|
||||
(field0 & 0xff0000) >> 16,
|
||||
(field1 & 0xff00) >> 8,
|
||||
field1 & 0xff,
|
||||
(field1 & 0xff000000) >> 16 |
|
||||
(field1 & 0xff0000) >> 16,
|
||||
TRB_LEN(field2), GET_TD_SIZE(field2),
|
||||
GET_INTR_TARGET(field2),
|
||||
xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)),
|
||||
field3 & TRB_BEI ? 'B' : 'b',
|
||||
field3 & TRB_IDT ? 'I' : 'i',
|
||||
field3 & TRB_IOC ? 'I' : 'i',
|
||||
field3 & TRB_CHAIN ? 'C' : 'c',
|
||||
field3 & TRB_NO_SNOOP ? 'S' : 's',
|
||||
field3 & TRB_ISP ? 'I' : 'i',
|
||||
field3 & TRB_ENT ? 'E' : 'e',
|
||||
field3 & TRB_CYCLE ? 'C' : 'c');
|
||||
sprintf(str, "bRequestType %02x bRequest %02x wValue %02x%02x wIndex %02x%02x wLength %d length %d TD size %d intr %d type '%s' flags %c:%c:%c",
|
||||
field0 & 0xff,
|
||||
(field0 & 0xff00) >> 8,
|
||||
(field0 & 0xff000000) >> 24,
|
||||
(field0 & 0xff0000) >> 16,
|
||||
(field1 & 0xff00) >> 8,
|
||||
field1 & 0xff,
|
||||
(field1 & 0xff000000) >> 16 |
|
||||
(field1 & 0xff0000) >> 16,
|
||||
TRB_LEN(field2), GET_TD_SIZE(field2),
|
||||
GET_INTR_TARGET(field2),
|
||||
xhci_trb_type_string(type),
|
||||
field3 & TRB_IDT ? 'I' : 'i',
|
||||
field3 & TRB_IOC ? 'I' : 'i',
|
||||
field3 & TRB_CYCLE ? 'C' : 'c');
|
||||
break;
|
||||
case TRB_DATA:
|
||||
sprintf(str, "Buffer %08x%08x length %d TD size %d intr %d type '%s' flags %c:%c:%c:%c:%c:%c:%c",
|
||||
field1, field0, TRB_LEN(field2), GET_TD_SIZE(field2),
|
||||
GET_INTR_TARGET(field2),
|
||||
xhci_trb_type_string(type),
|
||||
field3 & TRB_IDT ? 'I' : 'i',
|
||||
field3 & TRB_IOC ? 'I' : 'i',
|
||||
field3 & TRB_CHAIN ? 'C' : 'c',
|
||||
field3 & TRB_NO_SNOOP ? 'S' : 's',
|
||||
field3 & TRB_ISP ? 'I' : 'i',
|
||||
field3 & TRB_ENT ? 'E' : 'e',
|
||||
field3 & TRB_CYCLE ? 'C' : 'c');
|
||||
break;
|
||||
case TRB_STATUS:
|
||||
sprintf(str, "Buffer %08x%08x length %d TD size %d intr %d type '%s' flags %c:%c:%c:%c",
|
||||
field1, field0, TRB_LEN(field2), GET_TD_SIZE(field2),
|
||||
GET_INTR_TARGET(field2),
|
||||
xhci_trb_type_string(type),
|
||||
field3 & TRB_IOC ? 'I' : 'i',
|
||||
field3 & TRB_CHAIN ? 'C' : 'c',
|
||||
field3 & TRB_ENT ? 'E' : 'e',
|
||||
field3 & TRB_CYCLE ? 'C' : 'c');
|
||||
break;
|
||||
case TRB_NORMAL:
|
||||
case TRB_DATA:
|
||||
case TRB_STATUS:
|
||||
case TRB_ISOC:
|
||||
case TRB_EVENT_DATA:
|
||||
case TRB_TR_NOOP:
|
||||
|
|
@ -2225,7 +2205,7 @@ static inline const char *xhci_decode_trb(u32 field0, u32 field1, u32 field2,
|
|||
"Buffer %08x%08x length %d TD size %d intr %d type '%s' flags %c:%c:%c:%c:%c:%c:%c:%c",
|
||||
field1, field0, TRB_LEN(field2), GET_TD_SIZE(field2),
|
||||
GET_INTR_TARGET(field2),
|
||||
xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)),
|
||||
xhci_trb_type_string(type),
|
||||
field3 & TRB_BEI ? 'B' : 'b',
|
||||
field3 & TRB_IDT ? 'I' : 'i',
|
||||
field3 & TRB_IOC ? 'I' : 'i',
|
||||
|
|
@ -2240,21 +2220,21 @@ static inline const char *xhci_decode_trb(u32 field0, u32 field1, u32 field2,
|
|||
case TRB_ENABLE_SLOT:
|
||||
sprintf(str,
|
||||
"%s: flags %c",
|
||||
xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)),
|
||||
xhci_trb_type_string(type),
|
||||
field3 & TRB_CYCLE ? 'C' : 'c');
|
||||
break;
|
||||
case TRB_DISABLE_SLOT:
|
||||
case TRB_NEG_BANDWIDTH:
|
||||
sprintf(str,
|
||||
"%s: slot %d flags %c",
|
||||
xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)),
|
||||
xhci_trb_type_string(type),
|
||||
TRB_TO_SLOT_ID(field3),
|
||||
field3 & TRB_CYCLE ? 'C' : 'c');
|
||||
break;
|
||||
case TRB_ADDR_DEV:
|
||||
sprintf(str,
|
||||
"%s: ctx %08x%08x slot %d flags %c:%c",
|
||||
xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)),
|
||||
xhci_trb_type_string(type),
|
||||
field1, field0,
|
||||
TRB_TO_SLOT_ID(field3),
|
||||
field3 & TRB_BSR ? 'B' : 'b',
|
||||
|
|
@ -2263,7 +2243,7 @@ static inline const char *xhci_decode_trb(u32 field0, u32 field1, u32 field2,
|
|||
case TRB_CONFIG_EP:
|
||||
sprintf(str,
|
||||
"%s: ctx %08x%08x slot %d flags %c:%c",
|
||||
xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)),
|
||||
xhci_trb_type_string(type),
|
||||
field1, field0,
|
||||
TRB_TO_SLOT_ID(field3),
|
||||
field3 & TRB_DC ? 'D' : 'd',
|
||||
|
|
@ -2272,7 +2252,7 @@ static inline const char *xhci_decode_trb(u32 field0, u32 field1, u32 field2,
|
|||
case TRB_EVAL_CONTEXT:
|
||||
sprintf(str,
|
||||
"%s: ctx %08x%08x slot %d flags %c",
|
||||
xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)),
|
||||
xhci_trb_type_string(type),
|
||||
field1, field0,
|
||||
TRB_TO_SLOT_ID(field3),
|
||||
field3 & TRB_CYCLE ? 'C' : 'c');
|
||||
|
|
@ -2280,7 +2260,7 @@ static inline const char *xhci_decode_trb(u32 field0, u32 field1, u32 field2,
|
|||
case TRB_RESET_EP:
|
||||
sprintf(str,
|
||||
"%s: ctx %08x%08x slot %d ep %d flags %c",
|
||||
xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)),
|
||||
xhci_trb_type_string(type),
|
||||
field1, field0,
|
||||
TRB_TO_SLOT_ID(field3),
|
||||
/* Macro decrements 1, maybe it shouldn't?!? */
|
||||
|
|
@ -2290,7 +2270,7 @@ static inline const char *xhci_decode_trb(u32 field0, u32 field1, u32 field2,
|
|||
case TRB_STOP_RING:
|
||||
sprintf(str,
|
||||
"%s: slot %d sp %d ep %d flags %c",
|
||||
xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)),
|
||||
xhci_trb_type_string(type),
|
||||
TRB_TO_SLOT_ID(field3),
|
||||
TRB_TO_SUSPEND_PORT(field3),
|
||||
/* Macro decrements 1, maybe it shouldn't?!? */
|
||||
|
|
@ -2300,7 +2280,7 @@ static inline const char *xhci_decode_trb(u32 field0, u32 field1, u32 field2,
|
|||
case TRB_SET_DEQ:
|
||||
sprintf(str,
|
||||
"%s: deq %08x%08x stream %d slot %d ep %d flags %c",
|
||||
xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)),
|
||||
xhci_trb_type_string(type),
|
||||
field1, field0,
|
||||
TRB_TO_STREAM_ID(field2),
|
||||
TRB_TO_SLOT_ID(field3),
|
||||
|
|
@ -2311,14 +2291,14 @@ static inline const char *xhci_decode_trb(u32 field0, u32 field1, u32 field2,
|
|||
case TRB_RESET_DEV:
|
||||
sprintf(str,
|
||||
"%s: slot %d flags %c",
|
||||
xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)),
|
||||
xhci_trb_type_string(type),
|
||||
TRB_TO_SLOT_ID(field3),
|
||||
field3 & TRB_CYCLE ? 'C' : 'c');
|
||||
break;
|
||||
case TRB_FORCE_EVENT:
|
||||
sprintf(str,
|
||||
"%s: event %08x%08x vf intr %d vf id %d flags %c",
|
||||
xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)),
|
||||
xhci_trb_type_string(type),
|
||||
field1, field0,
|
||||
TRB_TO_VF_INTR_TARGET(field2),
|
||||
TRB_TO_VF_ID(field3),
|
||||
|
|
@ -2327,14 +2307,14 @@ static inline const char *xhci_decode_trb(u32 field0, u32 field1, u32 field2,
|
|||
case TRB_SET_LT:
|
||||
sprintf(str,
|
||||
"%s: belt %d flags %c",
|
||||
xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)),
|
||||
xhci_trb_type_string(type),
|
||||
TRB_TO_BELT(field3),
|
||||
field3 & TRB_CYCLE ? 'C' : 'c');
|
||||
break;
|
||||
case TRB_GET_BW:
|
||||
sprintf(str,
|
||||
"%s: ctx %08x%08x slot %d speed %d flags %c",
|
||||
xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)),
|
||||
xhci_trb_type_string(type),
|
||||
field1, field0,
|
||||
TRB_TO_SLOT_ID(field3),
|
||||
TRB_TO_DEV_SPEED(field3),
|
||||
|
|
@ -2343,7 +2323,7 @@ static inline const char *xhci_decode_trb(u32 field0, u32 field1, u32 field2,
|
|||
case TRB_FORCE_HEADER:
|
||||
sprintf(str,
|
||||
"%s: info %08x%08x%08x pkt type %d roothub port %d flags %c",
|
||||
xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)),
|
||||
xhci_trb_type_string(type),
|
||||
field2, field1, field0 & 0xffffffe0,
|
||||
TRB_TO_PACKET_TYPE(field0),
|
||||
TRB_TO_ROOTHUB_PORT(field3),
|
||||
|
|
@ -2352,12 +2332,155 @@ static inline const char *xhci_decode_trb(u32 field0, u32 field1, u32 field2,
|
|||
default:
|
||||
sprintf(str,
|
||||
"type '%s' -> raw %08x %08x %08x %08x",
|
||||
xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)),
|
||||
xhci_trb_type_string(type),
|
||||
field0, field1, field2, field3);
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static inline const char *xhci_decode_slot_context(u32 info, u32 info2,
|
||||
u32 tt_info, u32 state)
|
||||
{
|
||||
static char str[1024];
|
||||
u32 speed;
|
||||
u32 hub;
|
||||
u32 mtt;
|
||||
int ret = 0;
|
||||
|
||||
speed = info & DEV_SPEED;
|
||||
hub = info & DEV_HUB;
|
||||
mtt = info & DEV_MTT;
|
||||
|
||||
ret = sprintf(str, "RS %05x %s%s%s Ctx Entries %d MEL %d us Port# %d/%d",
|
||||
info & ROUTE_STRING_MASK,
|
||||
({ char *s;
|
||||
switch (speed) {
|
||||
case SLOT_SPEED_FS:
|
||||
s = "full-speed";
|
||||
break;
|
||||
case SLOT_SPEED_LS:
|
||||
s = "low-speed";
|
||||
break;
|
||||
case SLOT_SPEED_HS:
|
||||
s = "high-speed";
|
||||
break;
|
||||
case SLOT_SPEED_SS:
|
||||
s = "super-speed";
|
||||
break;
|
||||
case SLOT_SPEED_SSP:
|
||||
s = "super-speed plus";
|
||||
break;
|
||||
default:
|
||||
s = "UNKNOWN speed";
|
||||
} s; }),
|
||||
mtt ? " multi-TT" : "",
|
||||
hub ? " Hub" : "",
|
||||
(info & LAST_CTX_MASK) >> 27,
|
||||
info2 & MAX_EXIT,
|
||||
DEVINFO_TO_ROOT_HUB_PORT(info2),
|
||||
DEVINFO_TO_MAX_PORTS(info2));
|
||||
|
||||
ret += sprintf(str + ret, " [TT Slot %d Port# %d TTT %d Intr %d] Addr %d State %s",
|
||||
tt_info & TT_SLOT, (tt_info & TT_PORT) >> 8,
|
||||
GET_TT_THINK_TIME(tt_info), GET_INTR_TARGET(tt_info),
|
||||
state & DEV_ADDR_MASK,
|
||||
xhci_slot_state_string(GET_SLOT_STATE(state)));
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static inline const char *xhci_ep_state_string(u8 state)
|
||||
{
|
||||
switch (state) {
|
||||
case EP_STATE_DISABLED:
|
||||
return "disabled";
|
||||
case EP_STATE_RUNNING:
|
||||
return "running";
|
||||
case EP_STATE_HALTED:
|
||||
return "halted";
|
||||
case EP_STATE_STOPPED:
|
||||
return "stopped";
|
||||
case EP_STATE_ERROR:
|
||||
return "error";
|
||||
default:
|
||||
return "INVALID";
|
||||
}
|
||||
}
|
||||
|
||||
static inline const char *xhci_ep_type_string(u8 type)
|
||||
{
|
||||
switch (type) {
|
||||
case ISOC_OUT_EP:
|
||||
return "Isoc OUT";
|
||||
case BULK_OUT_EP:
|
||||
return "Bulk OUT";
|
||||
case INT_OUT_EP:
|
||||
return "Int OUT";
|
||||
case CTRL_EP:
|
||||
return "Ctrl";
|
||||
case ISOC_IN_EP:
|
||||
return "Isoc IN";
|
||||
case BULK_IN_EP:
|
||||
return "Bulk IN";
|
||||
case INT_IN_EP:
|
||||
return "Int IN";
|
||||
default:
|
||||
return "INVALID";
|
||||
}
|
||||
}
|
||||
|
||||
static inline const char *xhci_decode_ep_context(u32 info, u32 info2, u64 deq,
|
||||
u32 tx_info)
|
||||
{
|
||||
static char str[1024];
|
||||
int ret;
|
||||
|
||||
u32 esit;
|
||||
u16 maxp;
|
||||
u16 avg;
|
||||
|
||||
u8 max_pstr;
|
||||
u8 ep_state;
|
||||
u8 interval;
|
||||
u8 ep_type;
|
||||
u8 burst;
|
||||
u8 cerr;
|
||||
u8 mult;
|
||||
u8 lsa;
|
||||
u8 hid;
|
||||
|
||||
esit = EP_MAX_ESIT_PAYLOAD_HI(info) << 16 |
|
||||
EP_MAX_ESIT_PAYLOAD_LO(tx_info);
|
||||
|
||||
ep_state = info & EP_STATE_MASK;
|
||||
max_pstr = info & EP_MAXPSTREAMS_MASK;
|
||||
interval = CTX_TO_EP_INTERVAL(info);
|
||||
mult = CTX_TO_EP_MULT(info) + 1;
|
||||
lsa = info & EP_HAS_LSA;
|
||||
|
||||
cerr = (info2 & (3 << 1)) >> 1;
|
||||
ep_type = CTX_TO_EP_TYPE(info2);
|
||||
hid = info2 & (1 << 7);
|
||||
burst = CTX_TO_MAX_BURST(info2);
|
||||
maxp = MAX_PACKET_DECODED(info2);
|
||||
|
||||
avg = EP_AVG_TRB_LENGTH(tx_info);
|
||||
|
||||
ret = sprintf(str, "State %s mult %d max P. Streams %d %s",
|
||||
xhci_ep_state_string(ep_state), mult,
|
||||
max_pstr, lsa ? "LSA " : "");
|
||||
|
||||
ret += sprintf(str + ret, "interval %d us max ESIT payload %d CErr %d ",
|
||||
(1 << interval) * 125, esit, cerr);
|
||||
|
||||
ret += sprintf(str + ret, "Type %s %sburst %d maxp %d deq %016llx ",
|
||||
xhci_ep_type_string(ep_type), hid ? "HID" : "",
|
||||
burst, maxp, deq);
|
||||
|
||||
ret += sprintf(str + ret, "avg trb len %d", avg);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
#endif /* __LINUX_XHCI_HCD_H */
|
||||
|
|
|
|||
|
|
@ -21,11 +21,11 @@
|
|||
#include "isp1760-core.h"
|
||||
#include "isp1760-regs.h"
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
#ifdef CONFIG_USB_PCI
|
||||
#include <linux/pci.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
#ifdef CONFIG_USB_PCI
|
||||
static int isp1761_pci_init(struct pci_dev *dev)
|
||||
{
|
||||
resource_size_t mem_start;
|
||||
|
|
@ -286,7 +286,7 @@ static int __init isp1760_init(void)
|
|||
ret = platform_driver_register(&isp1760_plat_driver);
|
||||
if (!ret)
|
||||
any_ret = 0;
|
||||
#ifdef CONFIG_PCI
|
||||
#ifdef CONFIG_USB_PCI
|
||||
ret = pci_register_driver(&isp1761_pci_driver);
|
||||
if (!ret)
|
||||
any_ret = 0;
|
||||
|
|
@ -301,7 +301,7 @@ module_init(isp1760_init);
|
|||
static void __exit isp1760_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&isp1760_plat_driver);
|
||||
#ifdef CONFIG_PCI
|
||||
#ifdef CONFIG_USB_PCI
|
||||
pci_unregister_driver(&isp1761_pci_driver);
|
||||
#endif
|
||||
isp1760_deinit_kmem_cache();
|
||||
|
|
|
|||
|
|
@ -655,24 +655,15 @@ static int adu_probe(struct usb_interface *interface,
|
|||
{
|
||||
struct usb_device *udev = interface_to_usbdev(interface);
|
||||
struct adu_device *dev = NULL;
|
||||
struct usb_host_interface *iface_desc;
|
||||
struct usb_endpoint_descriptor *endpoint;
|
||||
int retval = -ENODEV;
|
||||
int retval = -ENOMEM;
|
||||
int in_end_size;
|
||||
int out_end_size;
|
||||
int i;
|
||||
|
||||
if (udev == NULL) {
|
||||
dev_err(&interface->dev, "udev is NULL.\n");
|
||||
goto exit;
|
||||
}
|
||||
int res;
|
||||
|
||||
/* allocate memory for our device state and initialize it */
|
||||
dev = kzalloc(sizeof(struct adu_device), GFP_KERNEL);
|
||||
if (!dev) {
|
||||
retval = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&dev->mtx);
|
||||
spin_lock_init(&dev->buflock);
|
||||
|
|
@ -680,24 +671,13 @@ static int adu_probe(struct usb_interface *interface,
|
|||
init_waitqueue_head(&dev->read_wait);
|
||||
init_waitqueue_head(&dev->write_wait);
|
||||
|
||||
iface_desc = &interface->altsetting[0];
|
||||
|
||||
/* set up the endpoint information */
|
||||
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
|
||||
endpoint = &iface_desc->endpoint[i].desc;
|
||||
|
||||
if (usb_endpoint_is_int_in(endpoint))
|
||||
dev->interrupt_in_endpoint = endpoint;
|
||||
|
||||
if (usb_endpoint_is_int_out(endpoint))
|
||||
dev->interrupt_out_endpoint = endpoint;
|
||||
}
|
||||
if (dev->interrupt_in_endpoint == NULL) {
|
||||
dev_err(&interface->dev, "interrupt in endpoint not found\n");
|
||||
goto error;
|
||||
}
|
||||
if (dev->interrupt_out_endpoint == NULL) {
|
||||
dev_err(&interface->dev, "interrupt out endpoint not found\n");
|
||||
res = usb_find_common_endpoints_reverse(&interface->altsetting[0],
|
||||
NULL, NULL,
|
||||
&dev->interrupt_in_endpoint,
|
||||
&dev->interrupt_out_endpoint);
|
||||
if (res) {
|
||||
dev_err(&interface->dev, "interrupt endpoints not found\n");
|
||||
retval = res;
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
|
@ -705,10 +685,8 @@ static int adu_probe(struct usb_interface *interface,
|
|||
out_end_size = usb_endpoint_maxp(dev->interrupt_out_endpoint);
|
||||
|
||||
dev->read_buffer_primary = kmalloc((4 * in_end_size), GFP_KERNEL);
|
||||
if (!dev->read_buffer_primary) {
|
||||
retval = -ENOMEM;
|
||||
if (!dev->read_buffer_primary)
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* debug code prime the buffer */
|
||||
memset(dev->read_buffer_primary, 'a', in_end_size);
|
||||
|
|
@ -717,10 +695,8 @@ static int adu_probe(struct usb_interface *interface,
|
|||
memset(dev->read_buffer_primary + (3 * in_end_size), 'd', in_end_size);
|
||||
|
||||
dev->read_buffer_secondary = kmalloc((4 * in_end_size), GFP_KERNEL);
|
||||
if (!dev->read_buffer_secondary) {
|
||||
retval = -ENOMEM;
|
||||
if (!dev->read_buffer_secondary)
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* debug code prime the buffer */
|
||||
memset(dev->read_buffer_secondary, 'e', in_end_size);
|
||||
|
|
@ -748,6 +724,7 @@ static int adu_probe(struct usb_interface *interface,
|
|||
if (!usb_string(udev, udev->descriptor.iSerialNumber, dev->serial_number,
|
||||
sizeof(dev->serial_number))) {
|
||||
dev_err(&interface->dev, "Could not retrieve serial number\n");
|
||||
retval = -EIO;
|
||||
goto error;
|
||||
}
|
||||
dev_dbg(&interface->dev,"serial_number=%s", dev->serial_number);
|
||||
|
|
@ -770,8 +747,8 @@ static int adu_probe(struct usb_interface *interface,
|
|||
dev_info(&interface->dev, "ADU%d %s now attached to /dev/usb/adutux%d\n",
|
||||
le16_to_cpu(udev->descriptor.idProduct), dev->serial_number,
|
||||
(dev->minor - ADU_MINOR_BASE));
|
||||
exit:
|
||||
return retval;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
adu_delete(dev);
|
||||
|
|
|
|||
|
|
@ -212,28 +212,21 @@ static int appledisplay_probe(struct usb_interface *iface,
|
|||
struct backlight_properties props;
|
||||
struct appledisplay *pdata;
|
||||
struct usb_device *udev = interface_to_usbdev(iface);
|
||||
struct usb_host_interface *iface_desc;
|
||||
struct usb_endpoint_descriptor *endpoint;
|
||||
int int_in_endpointAddr = 0;
|
||||
int i, retval = -ENOMEM, brightness;
|
||||
int retval, brightness;
|
||||
char bl_name[20];
|
||||
|
||||
/* set up the endpoint information */
|
||||
/* use only the first interrupt-in endpoint */
|
||||
iface_desc = iface->cur_altsetting;
|
||||
for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
|
||||
endpoint = &iface_desc->endpoint[i].desc;
|
||||
if (!int_in_endpointAddr && usb_endpoint_is_int_in(endpoint)) {
|
||||
/* we found an interrupt in endpoint */
|
||||
int_in_endpointAddr = endpoint->bEndpointAddress;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!int_in_endpointAddr) {
|
||||
retval = usb_find_int_in_endpoint(iface->cur_altsetting, &endpoint);
|
||||
if (retval) {
|
||||
dev_err(&iface->dev, "Could not find int-in endpoint\n");
|
||||
return -EIO;
|
||||
return retval;
|
||||
}
|
||||
|
||||
int_in_endpointAddr = endpoint->bEndpointAddress;
|
||||
|
||||
/* allocate memory for our device state and initialize it */
|
||||
pdata = kzalloc(sizeof(struct appledisplay), GFP_KERNEL);
|
||||
if (!pdata) {
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue