Merge branch 'usb-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6
* 'usb-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6: (43 commits) Revert "USB: isp1760-hcd: move imask clear after pending work is done" xHCI: Implement AMD PLL quirk xhci: Tell USB core both roothubs lost power. usbcore: Bug fix: system can't suspend with USB3.0 device connected to USB3.0 hub USB: Fix unplug of device with active streams USB: xhci - also free streams when resetting devices xhci: Fix NULL pointer deref in handle_port_status() USB: xhci - fix math in xhci_get_endpoint_interval() USB: xhci: simplify logic of skipping missed isoc TDs USB: xhci - remove excessive 'inline' markings USB: xhci: unsigned char never equals -1 USB: xhci - fix unsafe macro definitions USB: fix formatting of SuperSpeed endpoints in /proc/bus/usb/devices USB: isp1760-hcd: move imask clear after pending work is done USB: fsl_qe_udc: send ZLP when zero flag and length % maxpacket == 0 usb: qcserial add missing errorpath kfrees usb: qcserial avoid pointing to freed memory usb: Fix qcserial memory leak on rmmod USB: ftdi_sio: add ids for Hameg HO720 and HO730 USB: option: Added support for Samsung GT-B3730/GT-B3710 LTE USB modem. ...
This commit is contained in:
commit
08150c533c
|
@ -6,7 +6,6 @@ config MICROBLAZE
|
||||||
select HAVE_FUNCTION_GRAPH_TRACER
|
select HAVE_FUNCTION_GRAPH_TRACER
|
||||||
select HAVE_DYNAMIC_FTRACE
|
select HAVE_DYNAMIC_FTRACE
|
||||||
select HAVE_FTRACE_MCOUNT_RECORD
|
select HAVE_FTRACE_MCOUNT_RECORD
|
||||||
select USB_ARCH_HAS_EHCI
|
|
||||||
select ARCH_WANT_OPTIONAL_GPIOLIB
|
select ARCH_WANT_OPTIONAL_GPIOLIB
|
||||||
select HAVE_OPROFILE
|
select HAVE_OPROFILE
|
||||||
select HAVE_ARCH_KGDB
|
select HAVE_ARCH_KGDB
|
||||||
|
|
|
@ -66,6 +66,7 @@ config USB_ARCH_HAS_EHCI
|
||||||
default y if ARCH_VT8500
|
default y if ARCH_VT8500
|
||||||
default y if PLAT_SPEAR
|
default y if PLAT_SPEAR
|
||||||
default y if ARCH_MSM
|
default y if ARCH_MSM
|
||||||
|
default y if MICROBLAZE
|
||||||
default PCI
|
default PCI
|
||||||
|
|
||||||
# ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
|
# ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
|
||||||
|
|
|
@ -221,7 +221,7 @@ static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end,
|
||||||
break;
|
break;
|
||||||
case USB_ENDPOINT_XFER_INT:
|
case USB_ENDPOINT_XFER_INT:
|
||||||
type = "Int.";
|
type = "Int.";
|
||||||
if (speed == USB_SPEED_HIGH)
|
if (speed == USB_SPEED_HIGH || speed == USB_SPEED_SUPER)
|
||||||
interval = 1 << (desc->bInterval - 1);
|
interval = 1 << (desc->bInterval - 1);
|
||||||
else
|
else
|
||||||
interval = desc->bInterval;
|
interval = desc->bInterval;
|
||||||
|
@ -229,7 +229,8 @@ static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end,
|
||||||
default: /* "can't happen" */
|
default: /* "can't happen" */
|
||||||
return start;
|
return start;
|
||||||
}
|
}
|
||||||
interval *= (speed == USB_SPEED_HIGH) ? 125 : 1000;
|
interval *= (speed == USB_SPEED_HIGH ||
|
||||||
|
speed == USB_SPEED_SUPER) ? 125 : 1000;
|
||||||
if (interval % 1000)
|
if (interval % 1000)
|
||||||
unit = 'u';
|
unit = 'u';
|
||||||
else {
|
else {
|
||||||
|
@ -542,8 +543,9 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes,
|
||||||
if (level == 0) {
|
if (level == 0) {
|
||||||
int max;
|
int max;
|
||||||
|
|
||||||
/* high speed reserves 80%, full/low reserves 90% */
|
/* super/high speed reserves 80%, full/low reserves 90% */
|
||||||
if (usbdev->speed == USB_SPEED_HIGH)
|
if (usbdev->speed == USB_SPEED_HIGH ||
|
||||||
|
usbdev->speed == USB_SPEED_SUPER)
|
||||||
max = 800;
|
max = 800;
|
||||||
else
|
else
|
||||||
max = FRAME_TIME_MAX_USECS_ALLOC;
|
max = FRAME_TIME_MAX_USECS_ALLOC;
|
||||||
|
|
|
@ -1908,7 +1908,7 @@ void usb_free_streams(struct usb_interface *interface,
|
||||||
|
|
||||||
/* Streams only apply to bulk endpoints. */
|
/* Streams only apply to bulk endpoints. */
|
||||||
for (i = 0; i < num_eps; i++)
|
for (i = 0; i < num_eps; i++)
|
||||||
if (!usb_endpoint_xfer_bulk(&eps[i]->desc))
|
if (!eps[i] || !usb_endpoint_xfer_bulk(&eps[i]->desc))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
hcd->driver->free_streams(hcd, dev, eps, num_eps, mem_flags);
|
hcd->driver->free_streams(hcd, dev, eps, num_eps, mem_flags);
|
||||||
|
|
|
@ -2285,7 +2285,17 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* see 7.1.7.6 */
|
/* see 7.1.7.6 */
|
||||||
status = set_port_feature(hub->hdev, port1, USB_PORT_FEAT_SUSPEND);
|
/* Clear PORT_POWER if it's a USB3.0 device connected to USB 3.0
|
||||||
|
* external hub.
|
||||||
|
* FIXME: this is a temporary workaround to make the system able
|
||||||
|
* to suspend/resume.
|
||||||
|
*/
|
||||||
|
if ((hub->hdev->parent != NULL) && hub_is_superspeed(hub->hdev))
|
||||||
|
status = clear_port_feature(hub->hdev, port1,
|
||||||
|
USB_PORT_FEAT_POWER);
|
||||||
|
else
|
||||||
|
status = set_port_feature(hub->hdev, port1,
|
||||||
|
USB_PORT_FEAT_SUSPEND);
|
||||||
if (status) {
|
if (status) {
|
||||||
dev_dbg(hub->intfdev, "can't suspend port %d, status %d\n",
|
dev_dbg(hub->intfdev, "can't suspend port %d, status %d\n",
|
||||||
port1, status);
|
port1, status);
|
||||||
|
|
|
@ -706,6 +706,7 @@ f_audio_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||||
struct f_audio *audio = func_to_audio(f);
|
struct f_audio *audio = func_to_audio(f);
|
||||||
|
|
||||||
usb_free_descriptors(f->descriptors);
|
usb_free_descriptors(f->descriptors);
|
||||||
|
usb_free_descriptors(f->hs_descriptors);
|
||||||
kfree(audio);
|
kfree(audio);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -314,6 +314,9 @@ eem_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||||
|
|
||||||
static void eem_cmd_complete(struct usb_ep *ep, struct usb_request *req)
|
static void eem_cmd_complete(struct usb_ep *ep, struct usb_request *req)
|
||||||
{
|
{
|
||||||
|
struct sk_buff *skb = (struct sk_buff *)req->context;
|
||||||
|
|
||||||
|
dev_kfree_skb_any(skb);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -428,10 +431,11 @@ static int eem_unwrap(struct gether *port,
|
||||||
skb_trim(skb2, len);
|
skb_trim(skb2, len);
|
||||||
put_unaligned_le16(BIT(15) | BIT(11) | len,
|
put_unaligned_le16(BIT(15) | BIT(11) | len,
|
||||||
skb_push(skb2, 2));
|
skb_push(skb2, 2));
|
||||||
skb_copy_bits(skb, 0, req->buf, skb->len);
|
skb_copy_bits(skb2, 0, req->buf, skb2->len);
|
||||||
req->length = skb->len;
|
req->length = skb2->len;
|
||||||
req->complete = eem_cmd_complete;
|
req->complete = eem_cmd_complete;
|
||||||
req->zero = 1;
|
req->zero = 1;
|
||||||
|
req->context = skb2;
|
||||||
if (usb_ep_queue(port->in_ep, req, GFP_ATOMIC))
|
if (usb_ep_queue(port->in_ep, req, GFP_ATOMIC))
|
||||||
DBG(cdev, "echo response queue fail\n");
|
DBG(cdev, "echo response queue fail\n");
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1148,6 +1148,12 @@ static int qe_ep_tx(struct qe_ep *ep, struct qe_frame *frame)
|
||||||
static int txcomplete(struct qe_ep *ep, unsigned char restart)
|
static int txcomplete(struct qe_ep *ep, unsigned char restart)
|
||||||
{
|
{
|
||||||
if (ep->tx_req != NULL) {
|
if (ep->tx_req != NULL) {
|
||||||
|
struct qe_req *req = ep->tx_req;
|
||||||
|
unsigned zlp = 0, last_len = 0;
|
||||||
|
|
||||||
|
last_len = min_t(unsigned, req->req.length - ep->sent,
|
||||||
|
ep->ep.maxpacket);
|
||||||
|
|
||||||
if (!restart) {
|
if (!restart) {
|
||||||
int asent = ep->last;
|
int asent = ep->last;
|
||||||
ep->sent += asent;
|
ep->sent += asent;
|
||||||
|
@ -1156,9 +1162,18 @@ static int txcomplete(struct qe_ep *ep, unsigned char restart)
|
||||||
ep->last = 0;
|
ep->last = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* zlp needed when req->re.zero is set */
|
||||||
|
if (req->req.zero) {
|
||||||
|
if (last_len == 0 ||
|
||||||
|
(req->req.length % ep->ep.maxpacket) != 0)
|
||||||
|
zlp = 0;
|
||||||
|
else
|
||||||
|
zlp = 1;
|
||||||
|
} else
|
||||||
|
zlp = 0;
|
||||||
|
|
||||||
/* a request already were transmitted completely */
|
/* a request already were transmitted completely */
|
||||||
if ((ep->tx_req->req.length - ep->sent) <= 0) {
|
if (((ep->tx_req->req.length - ep->sent) <= 0) && !zlp) {
|
||||||
ep->tx_req->req.actual = (unsigned int)ep->sent;
|
|
||||||
done(ep, ep->tx_req, 0);
|
done(ep, ep->tx_req, 0);
|
||||||
ep->tx_req = NULL;
|
ep->tx_req = NULL;
|
||||||
ep->last = 0;
|
ep->last = 0;
|
||||||
|
@ -1191,6 +1206,7 @@ static int qe_usb_senddata(struct qe_ep *ep, struct qe_frame *frame)
|
||||||
buf = (u8 *)ep->tx_req->req.buf + ep->sent;
|
buf = (u8 *)ep->tx_req->req.buf + ep->sent;
|
||||||
if (buf && size) {
|
if (buf && size) {
|
||||||
ep->last = size;
|
ep->last = size;
|
||||||
|
ep->tx_req->req.actual += size;
|
||||||
frame_set_data(frame, buf);
|
frame_set_data(frame, buf);
|
||||||
frame_set_length(frame, size);
|
frame_set_length(frame, size);
|
||||||
frame_set_status(frame, FRAME_OK);
|
frame_set_status(frame, FRAME_OK);
|
||||||
|
|
|
@ -386,8 +386,10 @@ ep_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
|
||||||
|
|
||||||
/* halt any endpoint by doing a "wrong direction" i/o call */
|
/* halt any endpoint by doing a "wrong direction" i/o call */
|
||||||
if (usb_endpoint_dir_in(&data->desc)) {
|
if (usb_endpoint_dir_in(&data->desc)) {
|
||||||
if (usb_endpoint_xfer_isoc(&data->desc))
|
if (usb_endpoint_xfer_isoc(&data->desc)) {
|
||||||
|
mutex_unlock(&data->lock);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
}
|
||||||
DBG (data->dev, "%s halt\n", data->name);
|
DBG (data->dev, "%s halt\n", data->name);
|
||||||
spin_lock_irq (&data->dev->lock);
|
spin_lock_irq (&data->dev->lock);
|
||||||
if (likely (data->ep != NULL))
|
if (likely (data->ep != NULL))
|
||||||
|
|
|
@ -1608,7 +1608,7 @@ static int pch_udc_pcd_queue(struct usb_ep *usbep, struct usb_request *usbreq,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (!dev->driver || (dev->gadget.speed == USB_SPEED_UNKNOWN))
|
if (!dev->driver || (dev->gadget.speed == USB_SPEED_UNKNOWN))
|
||||||
return -ESHUTDOWN;
|
return -ESHUTDOWN;
|
||||||
spin_lock_irqsave(&ep->dev->lock, iflags);
|
spin_lock_irqsave(&dev->lock, iflags);
|
||||||
/* map the buffer for dma */
|
/* map the buffer for dma */
|
||||||
if (usbreq->length &&
|
if (usbreq->length &&
|
||||||
((usbreq->dma == DMA_ADDR_INVALID) || !usbreq->dma)) {
|
((usbreq->dma == DMA_ADDR_INVALID) || !usbreq->dma)) {
|
||||||
|
@ -1625,8 +1625,10 @@ static int pch_udc_pcd_queue(struct usb_ep *usbep, struct usb_request *usbreq,
|
||||||
DMA_FROM_DEVICE);
|
DMA_FROM_DEVICE);
|
||||||
} else {
|
} else {
|
||||||
req->buf = kzalloc(usbreq->length, GFP_ATOMIC);
|
req->buf = kzalloc(usbreq->length, GFP_ATOMIC);
|
||||||
if (!req->buf)
|
if (!req->buf) {
|
||||||
return -ENOMEM;
|
retval = -ENOMEM;
|
||||||
|
goto probe_end;
|
||||||
|
}
|
||||||
if (ep->in) {
|
if (ep->in) {
|
||||||
memcpy(req->buf, usbreq->buf, usbreq->length);
|
memcpy(req->buf, usbreq->buf, usbreq->length);
|
||||||
req->dma = dma_map_single(&dev->pdev->dev,
|
req->dma = dma_map_single(&dev->pdev->dev,
|
||||||
|
|
|
@ -1083,7 +1083,9 @@ static void irq_device_state(struct r8a66597 *r8a66597)
|
||||||
|
|
||||||
if (dvsq == DS_DFLT) {
|
if (dvsq == DS_DFLT) {
|
||||||
/* bus reset */
|
/* bus reset */
|
||||||
|
spin_unlock(&r8a66597->lock);
|
||||||
r8a66597->driver->disconnect(&r8a66597->gadget);
|
r8a66597->driver->disconnect(&r8a66597->gadget);
|
||||||
|
spin_lock(&r8a66597->lock);
|
||||||
r8a66597_update_usb_speed(r8a66597);
|
r8a66597_update_usb_speed(r8a66597);
|
||||||
}
|
}
|
||||||
if (r8a66597->old_dvsq == DS_CNFG && dvsq != DS_CNFG)
|
if (r8a66597->old_dvsq == DS_CNFG && dvsq != DS_CNFG)
|
||||||
|
|
|
@ -1247,24 +1247,27 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
|
||||||
|
|
||||||
static void scan_async (struct ehci_hcd *ehci)
|
static void scan_async (struct ehci_hcd *ehci)
|
||||||
{
|
{
|
||||||
|
bool stopped;
|
||||||
struct ehci_qh *qh;
|
struct ehci_qh *qh;
|
||||||
enum ehci_timer_action action = TIMER_IO_WATCHDOG;
|
enum ehci_timer_action action = TIMER_IO_WATCHDOG;
|
||||||
|
|
||||||
ehci->stamp = ehci_readl(ehci, &ehci->regs->frame_index);
|
ehci->stamp = ehci_readl(ehci, &ehci->regs->frame_index);
|
||||||
timer_action_done (ehci, TIMER_ASYNC_SHRINK);
|
timer_action_done (ehci, TIMER_ASYNC_SHRINK);
|
||||||
rescan:
|
rescan:
|
||||||
|
stopped = !HC_IS_RUNNING(ehci_to_hcd(ehci)->state);
|
||||||
qh = ehci->async->qh_next.qh;
|
qh = ehci->async->qh_next.qh;
|
||||||
if (likely (qh != NULL)) {
|
if (likely (qh != NULL)) {
|
||||||
do {
|
do {
|
||||||
/* clean any finished work for this qh */
|
/* clean any finished work for this qh */
|
||||||
if (!list_empty (&qh->qtd_list)
|
if (!list_empty(&qh->qtd_list) && (stopped ||
|
||||||
&& qh->stamp != ehci->stamp) {
|
qh->stamp != ehci->stamp)) {
|
||||||
int temp;
|
int temp;
|
||||||
|
|
||||||
/* unlinks could happen here; completion
|
/* unlinks could happen here; completion
|
||||||
* reporting drops the lock. rescan using
|
* reporting drops the lock. rescan using
|
||||||
* the latest schedule, but don't rescan
|
* the latest schedule, but don't rescan
|
||||||
* qhs we already finished (no looping).
|
* qhs we already finished (no looping)
|
||||||
|
* unless the controller is stopped.
|
||||||
*/
|
*/
|
||||||
qh = qh_get (qh);
|
qh = qh_get (qh);
|
||||||
qh->stamp = ehci->stamp;
|
qh->stamp = ehci->stamp;
|
||||||
|
@ -1285,9 +1288,9 @@ rescan:
|
||||||
*/
|
*/
|
||||||
if (list_empty(&qh->qtd_list)
|
if (list_empty(&qh->qtd_list)
|
||||||
&& qh->qh_state == QH_STATE_LINKED) {
|
&& qh->qh_state == QH_STATE_LINKED) {
|
||||||
if (!ehci->reclaim
|
if (!ehci->reclaim && (stopped ||
|
||||||
&& ((ehci->stamp - qh->stamp) & 0x1fff)
|
((ehci->stamp - qh->stamp) & 0x1fff)
|
||||||
>= (EHCI_SHRINK_FRAMES * 8))
|
>= EHCI_SHRINK_FRAMES * 8))
|
||||||
start_unlink_async(ehci, qh);
|
start_unlink_async(ehci, qh);
|
||||||
else
|
else
|
||||||
action = TIMER_ASYNC_SHRINK;
|
action = TIMER_ASYNC_SHRINK;
|
||||||
|
|
|
@ -295,7 +295,7 @@ static void alloc_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_err(hcd->self.controller,
|
dev_err(hcd->self.controller,
|
||||||
"%s: Can not allocate %lu bytes of memory\n"
|
"%s: Cannot allocate %zu bytes of memory\n"
|
||||||
"Current memory map:\n",
|
"Current memory map:\n",
|
||||||
__func__, qtd->length);
|
__func__, qtd->length);
|
||||||
for (i = 0; i < BLOCKS; i++) {
|
for (i = 0; i < BLOCKS; i++) {
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
|
|
||||||
#ifdef __LITTLE_ENDIAN
|
#ifdef __LITTLE_ENDIAN
|
||||||
#define USBH_ENABLE_INIT (USBH_ENABLE_CE | USBH_ENABLE_E | USBH_ENABLE_C)
|
#define USBH_ENABLE_INIT (USBH_ENABLE_CE | USBH_ENABLE_E | USBH_ENABLE_C)
|
||||||
#elif __BIG_ENDIAN
|
#elif defined(__BIG_ENDIAN)
|
||||||
#define USBH_ENABLE_INIT (USBH_ENABLE_CE | USBH_ENABLE_E | USBH_ENABLE_C | \
|
#define USBH_ENABLE_INIT (USBH_ENABLE_CE | USBH_ENABLE_E | USBH_ENABLE_C | \
|
||||||
USBH_ENABLE_BE)
|
USBH_ENABLE_BE)
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -84,65 +84,92 @@ int usb_amd_find_chipset_info(void)
|
||||||
{
|
{
|
||||||
u8 rev = 0;
|
u8 rev = 0;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
struct amd_chipset_info info;
|
||||||
|
int ret;
|
||||||
|
|
||||||
spin_lock_irqsave(&amd_lock, flags);
|
spin_lock_irqsave(&amd_lock, flags);
|
||||||
|
|
||||||
amd_chipset.probe_count++;
|
|
||||||
/* probe only once */
|
/* probe only once */
|
||||||
if (amd_chipset.probe_count > 1) {
|
if (amd_chipset.probe_count > 0) {
|
||||||
|
amd_chipset.probe_count++;
|
||||||
spin_unlock_irqrestore(&amd_lock, flags);
|
spin_unlock_irqrestore(&amd_lock, flags);
|
||||||
return amd_chipset.probe_result;
|
return amd_chipset.probe_result;
|
||||||
}
|
}
|
||||||
|
memset(&info, 0, sizeof(info));
|
||||||
|
spin_unlock_irqrestore(&amd_lock, flags);
|
||||||
|
|
||||||
amd_chipset.smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI, 0x4385, NULL);
|
info.smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI, 0x4385, NULL);
|
||||||
if (amd_chipset.smbus_dev) {
|
if (info.smbus_dev) {
|
||||||
rev = amd_chipset.smbus_dev->revision;
|
rev = info.smbus_dev->revision;
|
||||||
if (rev >= 0x40)
|
if (rev >= 0x40)
|
||||||
amd_chipset.sb_type = 1;
|
info.sb_type = 1;
|
||||||
else if (rev >= 0x30 && rev <= 0x3b)
|
else if (rev >= 0x30 && rev <= 0x3b)
|
||||||
amd_chipset.sb_type = 3;
|
info.sb_type = 3;
|
||||||
} else {
|
} else {
|
||||||
amd_chipset.smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD,
|
info.smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD,
|
||||||
0x780b, NULL);
|
0x780b, NULL);
|
||||||
if (!amd_chipset.smbus_dev) {
|
if (!info.smbus_dev) {
|
||||||
spin_unlock_irqrestore(&amd_lock, flags);
|
ret = 0;
|
||||||
return 0;
|
goto commit;
|
||||||
}
|
}
|
||||||
rev = amd_chipset.smbus_dev->revision;
|
|
||||||
|
rev = info.smbus_dev->revision;
|
||||||
if (rev >= 0x11 && rev <= 0x18)
|
if (rev >= 0x11 && rev <= 0x18)
|
||||||
amd_chipset.sb_type = 2;
|
info.sb_type = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (amd_chipset.sb_type == 0) {
|
if (info.sb_type == 0) {
|
||||||
if (amd_chipset.smbus_dev) {
|
if (info.smbus_dev) {
|
||||||
pci_dev_put(amd_chipset.smbus_dev);
|
pci_dev_put(info.smbus_dev);
|
||||||
amd_chipset.smbus_dev = NULL;
|
info.smbus_dev = NULL;
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&amd_lock, flags);
|
ret = 0;
|
||||||
return 0;
|
goto commit;
|
||||||
}
|
}
|
||||||
|
|
||||||
amd_chipset.nb_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x9601, NULL);
|
info.nb_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x9601, NULL);
|
||||||
if (amd_chipset.nb_dev) {
|
if (info.nb_dev) {
|
||||||
amd_chipset.nb_type = 1;
|
info.nb_type = 1;
|
||||||
} else {
|
} else {
|
||||||
amd_chipset.nb_dev = pci_get_device(PCI_VENDOR_ID_AMD,
|
info.nb_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x1510, NULL);
|
||||||
0x1510, NULL);
|
if (info.nb_dev) {
|
||||||
if (amd_chipset.nb_dev) {
|
info.nb_type = 2;
|
||||||
amd_chipset.nb_type = 2;
|
} else {
|
||||||
} else {
|
info.nb_dev = pci_get_device(PCI_VENDOR_ID_AMD,
|
||||||
amd_chipset.nb_dev = pci_get_device(PCI_VENDOR_ID_AMD,
|
0x9600, NULL);
|
||||||
0x9600, NULL);
|
if (info.nb_dev)
|
||||||
if (amd_chipset.nb_dev)
|
info.nb_type = 3;
|
||||||
amd_chipset.nb_type = 3;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
amd_chipset.probe_result = 1;
|
ret = info.probe_result = 1;
|
||||||
printk(KERN_DEBUG "QUIRK: Enable AMD PLL fix\n");
|
printk(KERN_DEBUG "QUIRK: Enable AMD PLL fix\n");
|
||||||
|
|
||||||
spin_unlock_irqrestore(&amd_lock, flags);
|
commit:
|
||||||
return amd_chipset.probe_result;
|
|
||||||
|
spin_lock_irqsave(&amd_lock, flags);
|
||||||
|
if (amd_chipset.probe_count > 0) {
|
||||||
|
/* race - someone else was faster - drop devices */
|
||||||
|
|
||||||
|
/* Mark that we where here */
|
||||||
|
amd_chipset.probe_count++;
|
||||||
|
ret = amd_chipset.probe_result;
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&amd_lock, flags);
|
||||||
|
|
||||||
|
if (info.nb_dev)
|
||||||
|
pci_dev_put(info.nb_dev);
|
||||||
|
if (info.smbus_dev)
|
||||||
|
pci_dev_put(info.smbus_dev);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* no race - commit the result */
|
||||||
|
info.probe_count++;
|
||||||
|
amd_chipset = info;
|
||||||
|
spin_unlock_irqrestore(&amd_lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(usb_amd_find_chipset_info);
|
EXPORT_SYMBOL_GPL(usb_amd_find_chipset_info);
|
||||||
|
|
||||||
|
@ -284,6 +311,7 @@ EXPORT_SYMBOL_GPL(usb_amd_quirk_pll_enable);
|
||||||
|
|
||||||
void usb_amd_dev_put(void)
|
void usb_amd_dev_put(void)
|
||||||
{
|
{
|
||||||
|
struct pci_dev *nb, *smbus;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock_irqsave(&amd_lock, flags);
|
spin_lock_irqsave(&amd_lock, flags);
|
||||||
|
@ -294,20 +322,23 @@ void usb_amd_dev_put(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (amd_chipset.nb_dev) {
|
/* save them to pci_dev_put outside of spinlock */
|
||||||
pci_dev_put(amd_chipset.nb_dev);
|
nb = amd_chipset.nb_dev;
|
||||||
amd_chipset.nb_dev = NULL;
|
smbus = amd_chipset.smbus_dev;
|
||||||
}
|
|
||||||
if (amd_chipset.smbus_dev) {
|
amd_chipset.nb_dev = NULL;
|
||||||
pci_dev_put(amd_chipset.smbus_dev);
|
amd_chipset.smbus_dev = NULL;
|
||||||
amd_chipset.smbus_dev = NULL;
|
|
||||||
}
|
|
||||||
amd_chipset.nb_type = 0;
|
amd_chipset.nb_type = 0;
|
||||||
amd_chipset.sb_type = 0;
|
amd_chipset.sb_type = 0;
|
||||||
amd_chipset.isoc_reqs = 0;
|
amd_chipset.isoc_reqs = 0;
|
||||||
amd_chipset.probe_result = 0;
|
amd_chipset.probe_result = 0;
|
||||||
|
|
||||||
spin_unlock_irqrestore(&amd_lock, flags);
|
spin_unlock_irqrestore(&amd_lock, flags);
|
||||||
|
|
||||||
|
if (nb)
|
||||||
|
pci_dev_put(nb);
|
||||||
|
if (smbus)
|
||||||
|
pci_dev_put(smbus);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(usb_amd_dev_put);
|
EXPORT_SYMBOL_GPL(usb_amd_dev_put);
|
||||||
|
|
||||||
|
|
|
@ -846,7 +846,7 @@ static u32 xhci_find_real_port_number(struct xhci_hcd *xhci,
|
||||||
* Skip ports that don't have known speeds, or have duplicate
|
* Skip ports that don't have known speeds, or have duplicate
|
||||||
* Extended Capabilities port speed entries.
|
* Extended Capabilities port speed entries.
|
||||||
*/
|
*/
|
||||||
if (port_speed == 0 || port_speed == -1)
|
if (port_speed == 0 || port_speed == DUPLICATE_ENTRY)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -974,6 +974,47 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert interval expressed as 2^(bInterval - 1) == interval into
|
||||||
|
* straight exponent value 2^n == interval.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static unsigned int xhci_parse_exponent_interval(struct usb_device *udev,
|
||||||
|
struct usb_host_endpoint *ep)
|
||||||
|
{
|
||||||
|
unsigned int interval;
|
||||||
|
|
||||||
|
interval = clamp_val(ep->desc.bInterval, 1, 16) - 1;
|
||||||
|
if (interval != ep->desc.bInterval - 1)
|
||||||
|
dev_warn(&udev->dev,
|
||||||
|
"ep %#x - rounding interval to %d microframes\n",
|
||||||
|
ep->desc.bEndpointAddress,
|
||||||
|
1 << interval);
|
||||||
|
|
||||||
|
return interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert bInterval expressed in frames (in 1-255 range) to exponent of
|
||||||
|
* microframes, rounded down to nearest power of 2.
|
||||||
|
*/
|
||||||
|
static unsigned int xhci_parse_frame_interval(struct usb_device *udev,
|
||||||
|
struct usb_host_endpoint *ep)
|
||||||
|
{
|
||||||
|
unsigned int interval;
|
||||||
|
|
||||||
|
interval = fls(8 * ep->desc.bInterval) - 1;
|
||||||
|
interval = clamp_val(interval, 3, 10);
|
||||||
|
if ((1 << interval) != 8 * ep->desc.bInterval)
|
||||||
|
dev_warn(&udev->dev,
|
||||||
|
"ep %#x - rounding interval to %d microframes, ep desc says %d microframes\n",
|
||||||
|
ep->desc.bEndpointAddress,
|
||||||
|
1 << interval,
|
||||||
|
8 * ep->desc.bInterval);
|
||||||
|
|
||||||
|
return interval;
|
||||||
|
}
|
||||||
|
|
||||||
/* Return the polling or NAK interval.
|
/* Return the polling or NAK interval.
|
||||||
*
|
*
|
||||||
* The polling interval is expressed in "microframes". If xHCI's Interval field
|
* The polling interval is expressed in "microframes". If xHCI's Interval field
|
||||||
|
@ -982,7 +1023,7 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
|
||||||
* The NAK interval is one NAK per 1 to 255 microframes, or no NAKs if interval
|
* The NAK interval is one NAK per 1 to 255 microframes, or no NAKs if interval
|
||||||
* is set to 0.
|
* is set to 0.
|
||||||
*/
|
*/
|
||||||
static inline unsigned int xhci_get_endpoint_interval(struct usb_device *udev,
|
static unsigned int xhci_get_endpoint_interval(struct usb_device *udev,
|
||||||
struct usb_host_endpoint *ep)
|
struct usb_host_endpoint *ep)
|
||||||
{
|
{
|
||||||
unsigned int interval = 0;
|
unsigned int interval = 0;
|
||||||
|
@ -991,45 +1032,38 @@ static inline unsigned int xhci_get_endpoint_interval(struct usb_device *udev,
|
||||||
case USB_SPEED_HIGH:
|
case USB_SPEED_HIGH:
|
||||||
/* Max NAK rate */
|
/* Max NAK rate */
|
||||||
if (usb_endpoint_xfer_control(&ep->desc) ||
|
if (usb_endpoint_xfer_control(&ep->desc) ||
|
||||||
usb_endpoint_xfer_bulk(&ep->desc))
|
usb_endpoint_xfer_bulk(&ep->desc)) {
|
||||||
interval = ep->desc.bInterval;
|
interval = ep->desc.bInterval;
|
||||||
|
break;
|
||||||
|
}
|
||||||
/* Fall through - SS and HS isoc/int have same decoding */
|
/* Fall through - SS and HS isoc/int have same decoding */
|
||||||
|
|
||||||
case USB_SPEED_SUPER:
|
case USB_SPEED_SUPER:
|
||||||
if (usb_endpoint_xfer_int(&ep->desc) ||
|
if (usb_endpoint_xfer_int(&ep->desc) ||
|
||||||
usb_endpoint_xfer_isoc(&ep->desc)) {
|
usb_endpoint_xfer_isoc(&ep->desc)) {
|
||||||
if (ep->desc.bInterval == 0)
|
interval = xhci_parse_exponent_interval(udev, ep);
|
||||||
interval = 0;
|
|
||||||
else
|
|
||||||
interval = ep->desc.bInterval - 1;
|
|
||||||
if (interval > 15)
|
|
||||||
interval = 15;
|
|
||||||
if (interval != ep->desc.bInterval + 1)
|
|
||||||
dev_warn(&udev->dev, "ep %#x - rounding interval to %d microframes\n",
|
|
||||||
ep->desc.bEndpointAddress, 1 << interval);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
/* Convert bInterval (in 1-255 frames) to microframes and round down to
|
|
||||||
* nearest power of 2.
|
|
||||||
*/
|
|
||||||
case USB_SPEED_FULL:
|
case USB_SPEED_FULL:
|
||||||
|
if (usb_endpoint_xfer_int(&ep->desc)) {
|
||||||
|
interval = xhci_parse_exponent_interval(udev, ep);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Fall through for isochronous endpoint interval decoding
|
||||||
|
* since it uses the same rules as low speed interrupt
|
||||||
|
* endpoints.
|
||||||
|
*/
|
||||||
|
|
||||||
case USB_SPEED_LOW:
|
case USB_SPEED_LOW:
|
||||||
if (usb_endpoint_xfer_int(&ep->desc) ||
|
if (usb_endpoint_xfer_int(&ep->desc) ||
|
||||||
usb_endpoint_xfer_isoc(&ep->desc)) {
|
usb_endpoint_xfer_isoc(&ep->desc)) {
|
||||||
interval = fls(8*ep->desc.bInterval) - 1;
|
|
||||||
if (interval > 10)
|
interval = xhci_parse_frame_interval(udev, ep);
|
||||||
interval = 10;
|
|
||||||
if (interval < 3)
|
|
||||||
interval = 3;
|
|
||||||
if ((1 << interval) != 8*ep->desc.bInterval)
|
|
||||||
dev_warn(&udev->dev,
|
|
||||||
"ep %#x - rounding interval"
|
|
||||||
" to %d microframes, "
|
|
||||||
"ep desc says %d microframes\n",
|
|
||||||
ep->desc.bEndpointAddress,
|
|
||||||
1 << interval,
|
|
||||||
8*ep->desc.bInterval);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
BUG();
|
BUG();
|
||||||
}
|
}
|
||||||
|
@ -1041,7 +1075,7 @@ static inline unsigned int xhci_get_endpoint_interval(struct usb_device *udev,
|
||||||
* transaction opportunities per microframe", but that goes in the Max Burst
|
* transaction opportunities per microframe", but that goes in the Max Burst
|
||||||
* endpoint context field.
|
* endpoint context field.
|
||||||
*/
|
*/
|
||||||
static inline u32 xhci_get_endpoint_mult(struct usb_device *udev,
|
static u32 xhci_get_endpoint_mult(struct usb_device *udev,
|
||||||
struct usb_host_endpoint *ep)
|
struct usb_host_endpoint *ep)
|
||||||
{
|
{
|
||||||
if (udev->speed != USB_SPEED_SUPER ||
|
if (udev->speed != USB_SPEED_SUPER ||
|
||||||
|
@ -1050,7 +1084,7 @@ static inline u32 xhci_get_endpoint_mult(struct usb_device *udev,
|
||||||
return ep->ss_ep_comp.bmAttributes;
|
return ep->ss_ep_comp.bmAttributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u32 xhci_get_endpoint_type(struct usb_device *udev,
|
static u32 xhci_get_endpoint_type(struct usb_device *udev,
|
||||||
struct usb_host_endpoint *ep)
|
struct usb_host_endpoint *ep)
|
||||||
{
|
{
|
||||||
int in;
|
int in;
|
||||||
|
@ -1084,7 +1118,7 @@ static inline u32 xhci_get_endpoint_type(struct usb_device *udev,
|
||||||
* Basically, this is the maxpacket size, multiplied by the burst size
|
* Basically, this is the maxpacket size, multiplied by the burst size
|
||||||
* and mult size.
|
* and mult size.
|
||||||
*/
|
*/
|
||||||
static inline u32 xhci_get_max_esit_payload(struct xhci_hcd *xhci,
|
static u32 xhci_get_max_esit_payload(struct xhci_hcd *xhci,
|
||||||
struct usb_device *udev,
|
struct usb_device *udev,
|
||||||
struct usb_host_endpoint *ep)
|
struct usb_host_endpoint *ep)
|
||||||
{
|
{
|
||||||
|
@ -1727,12 +1761,12 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
|
||||||
* found a similar duplicate.
|
* found a similar duplicate.
|
||||||
*/
|
*/
|
||||||
if (xhci->port_array[i] != major_revision &&
|
if (xhci->port_array[i] != major_revision &&
|
||||||
xhci->port_array[i] != (u8) -1) {
|
xhci->port_array[i] != DUPLICATE_ENTRY) {
|
||||||
if (xhci->port_array[i] == 0x03)
|
if (xhci->port_array[i] == 0x03)
|
||||||
xhci->num_usb3_ports--;
|
xhci->num_usb3_ports--;
|
||||||
else
|
else
|
||||||
xhci->num_usb2_ports--;
|
xhci->num_usb2_ports--;
|
||||||
xhci->port_array[i] = (u8) -1;
|
xhci->port_array[i] = DUPLICATE_ENTRY;
|
||||||
}
|
}
|
||||||
/* FIXME: Should we disable the port? */
|
/* FIXME: Should we disable the port? */
|
||||||
continue;
|
continue;
|
||||||
|
@ -1831,7 +1865,7 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
|
||||||
for (i = 0; i < num_ports; i++) {
|
for (i = 0; i < num_ports; i++) {
|
||||||
if (xhci->port_array[i] == 0x03 ||
|
if (xhci->port_array[i] == 0x03 ||
|
||||||
xhci->port_array[i] == 0 ||
|
xhci->port_array[i] == 0 ||
|
||||||
xhci->port_array[i] == -1)
|
xhci->port_array[i] == DUPLICATE_ENTRY)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
xhci->usb2_ports[port_index] =
|
xhci->usb2_ports[port_index] =
|
||||||
|
|
|
@ -114,6 +114,10 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
|
||||||
if (pdev->vendor == PCI_VENDOR_ID_NEC)
|
if (pdev->vendor == PCI_VENDOR_ID_NEC)
|
||||||
xhci->quirks |= XHCI_NEC_HOST;
|
xhci->quirks |= XHCI_NEC_HOST;
|
||||||
|
|
||||||
|
/* AMD PLL quirk */
|
||||||
|
if (pdev->vendor == PCI_VENDOR_ID_AMD && usb_amd_find_chipset_info())
|
||||||
|
xhci->quirks |= XHCI_AMD_PLL_FIX;
|
||||||
|
|
||||||
/* Make sure the HC is halted. */
|
/* Make sure the HC is halted. */
|
||||||
retval = xhci_halt(xhci);
|
retval = xhci_halt(xhci);
|
||||||
if (retval)
|
if (retval)
|
||||||
|
|
|
@ -93,7 +93,7 @@ dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg,
|
||||||
/* Does this link TRB point to the first segment in a ring,
|
/* Does this link TRB point to the first segment in a ring,
|
||||||
* or was the previous TRB the last TRB on the last segment in the ERST?
|
* or was the previous TRB the last TRB on the last segment in the ERST?
|
||||||
*/
|
*/
|
||||||
static inline bool last_trb_on_last_seg(struct xhci_hcd *xhci, struct xhci_ring *ring,
|
static bool last_trb_on_last_seg(struct xhci_hcd *xhci, struct xhci_ring *ring,
|
||||||
struct xhci_segment *seg, union xhci_trb *trb)
|
struct xhci_segment *seg, union xhci_trb *trb)
|
||||||
{
|
{
|
||||||
if (ring == xhci->event_ring)
|
if (ring == xhci->event_ring)
|
||||||
|
@ -107,7 +107,7 @@ static inline bool last_trb_on_last_seg(struct xhci_hcd *xhci, struct xhci_ring
|
||||||
* segment? I.e. would the updated event TRB pointer step off the end of the
|
* segment? I.e. would the updated event TRB pointer step off the end of the
|
||||||
* event seg?
|
* event seg?
|
||||||
*/
|
*/
|
||||||
static inline int last_trb(struct xhci_hcd *xhci, struct xhci_ring *ring,
|
static int last_trb(struct xhci_hcd *xhci, struct xhci_ring *ring,
|
||||||
struct xhci_segment *seg, union xhci_trb *trb)
|
struct xhci_segment *seg, union xhci_trb *trb)
|
||||||
{
|
{
|
||||||
if (ring == xhci->event_ring)
|
if (ring == xhci->event_ring)
|
||||||
|
@ -116,7 +116,7 @@ static inline int last_trb(struct xhci_hcd *xhci, struct xhci_ring *ring,
|
||||||
return (trb->link.control & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK);
|
return (trb->link.control & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int enqueue_is_link_trb(struct xhci_ring *ring)
|
static int enqueue_is_link_trb(struct xhci_ring *ring)
|
||||||
{
|
{
|
||||||
struct xhci_link_trb *link = &ring->enqueue->link;
|
struct xhci_link_trb *link = &ring->enqueue->link;
|
||||||
return ((link->control & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK));
|
return ((link->control & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK));
|
||||||
|
@ -592,7 +592,7 @@ void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci,
|
||||||
ep->ep_state |= SET_DEQ_PENDING;
|
ep->ep_state |= SET_DEQ_PENDING;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void xhci_stop_watchdog_timer_in_irq(struct xhci_hcd *xhci,
|
static void xhci_stop_watchdog_timer_in_irq(struct xhci_hcd *xhci,
|
||||||
struct xhci_virt_ep *ep)
|
struct xhci_virt_ep *ep)
|
||||||
{
|
{
|
||||||
ep->ep_state &= ~EP_HALT_PENDING;
|
ep->ep_state &= ~EP_HALT_PENDING;
|
||||||
|
@ -619,6 +619,13 @@ static void xhci_giveback_urb_in_irq(struct xhci_hcd *xhci,
|
||||||
|
|
||||||
/* Only giveback urb when this is the last td in urb */
|
/* Only giveback urb when this is the last td in urb */
|
||||||
if (urb_priv->td_cnt == urb_priv->length) {
|
if (urb_priv->td_cnt == urb_priv->length) {
|
||||||
|
if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
|
||||||
|
xhci_to_hcd(xhci)->self.bandwidth_isoc_reqs--;
|
||||||
|
if (xhci_to_hcd(xhci)->self.bandwidth_isoc_reqs == 0) {
|
||||||
|
if (xhci->quirks & XHCI_AMD_PLL_FIX)
|
||||||
|
usb_amd_quirk_pll_enable();
|
||||||
|
}
|
||||||
|
}
|
||||||
usb_hcd_unlink_urb_from_ep(hcd, urb);
|
usb_hcd_unlink_urb_from_ep(hcd, urb);
|
||||||
xhci_dbg(xhci, "Giveback %s URB %p\n", adjective, urb);
|
xhci_dbg(xhci, "Giveback %s URB %p\n", adjective, urb);
|
||||||
|
|
||||||
|
@ -1209,7 +1216,7 @@ static unsigned int find_faked_portnum_from_hw_portnum(struct usb_hcd *hcd,
|
||||||
* Skip ports that don't have known speeds, or have duplicate
|
* Skip ports that don't have known speeds, or have duplicate
|
||||||
* Extended Capabilities port speed entries.
|
* Extended Capabilities port speed entries.
|
||||||
*/
|
*/
|
||||||
if (port_speed == 0 || port_speed == -1)
|
if (port_speed == 0 || port_speed == DUPLICATE_ENTRY)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1235,6 +1242,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
|
||||||
u8 major_revision;
|
u8 major_revision;
|
||||||
struct xhci_bus_state *bus_state;
|
struct xhci_bus_state *bus_state;
|
||||||
u32 __iomem **port_array;
|
u32 __iomem **port_array;
|
||||||
|
bool bogus_port_status = false;
|
||||||
|
|
||||||
/* Port status change events always have a successful completion code */
|
/* Port status change events always have a successful completion code */
|
||||||
if (GET_COMP_CODE(event->generic.field[2]) != COMP_SUCCESS) {
|
if (GET_COMP_CODE(event->generic.field[2]) != COMP_SUCCESS) {
|
||||||
|
@ -1247,6 +1255,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
|
||||||
max_ports = HCS_MAX_PORTS(xhci->hcs_params1);
|
max_ports = HCS_MAX_PORTS(xhci->hcs_params1);
|
||||||
if ((port_id <= 0) || (port_id > max_ports)) {
|
if ((port_id <= 0) || (port_id > max_ports)) {
|
||||||
xhci_warn(xhci, "Invalid port id %d\n", port_id);
|
xhci_warn(xhci, "Invalid port id %d\n", port_id);
|
||||||
|
bogus_port_status = true;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1258,12 +1267,14 @@ static void handle_port_status(struct xhci_hcd *xhci,
|
||||||
xhci_warn(xhci, "Event for port %u not in "
|
xhci_warn(xhci, "Event for port %u not in "
|
||||||
"Extended Capabilities, ignoring.\n",
|
"Extended Capabilities, ignoring.\n",
|
||||||
port_id);
|
port_id);
|
||||||
|
bogus_port_status = true;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
if (major_revision == (u8) -1) {
|
if (major_revision == DUPLICATE_ENTRY) {
|
||||||
xhci_warn(xhci, "Event for port %u duplicated in"
|
xhci_warn(xhci, "Event for port %u duplicated in"
|
||||||
"Extended Capabilities, ignoring.\n",
|
"Extended Capabilities, ignoring.\n",
|
||||||
port_id);
|
port_id);
|
||||||
|
bogus_port_status = true;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1335,6 +1346,13 @@ cleanup:
|
||||||
/* Update event ring dequeue pointer before dropping the lock */
|
/* Update event ring dequeue pointer before dropping the lock */
|
||||||
inc_deq(xhci, xhci->event_ring, true);
|
inc_deq(xhci, xhci->event_ring, true);
|
||||||
|
|
||||||
|
/* Don't make the USB core poll the roothub if we got a bad port status
|
||||||
|
* change event. Besides, at that point we can't tell which roothub
|
||||||
|
* (USB 2.0 or USB 3.0) to kick.
|
||||||
|
*/
|
||||||
|
if (bogus_port_status)
|
||||||
|
return;
|
||||||
|
|
||||||
spin_unlock(&xhci->lock);
|
spin_unlock(&xhci->lock);
|
||||||
/* Pass this up to the core */
|
/* Pass this up to the core */
|
||||||
usb_hcd_poll_rh_status(hcd);
|
usb_hcd_poll_rh_status(hcd);
|
||||||
|
@ -1554,8 +1572,17 @@ td_cleanup:
|
||||||
|
|
||||||
urb_priv->td_cnt++;
|
urb_priv->td_cnt++;
|
||||||
/* Giveback the urb when all the tds are completed */
|
/* Giveback the urb when all the tds are completed */
|
||||||
if (urb_priv->td_cnt == urb_priv->length)
|
if (urb_priv->td_cnt == urb_priv->length) {
|
||||||
ret = 1;
|
ret = 1;
|
||||||
|
if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
|
||||||
|
xhci_to_hcd(xhci)->self.bandwidth_isoc_reqs--;
|
||||||
|
if (xhci_to_hcd(xhci)->self.bandwidth_isoc_reqs
|
||||||
|
== 0) {
|
||||||
|
if (xhci->quirks & XHCI_AMD_PLL_FIX)
|
||||||
|
usb_amd_quirk_pll_enable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1675,71 +1702,52 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
|
||||||
struct urb_priv *urb_priv;
|
struct urb_priv *urb_priv;
|
||||||
int idx;
|
int idx;
|
||||||
int len = 0;
|
int len = 0;
|
||||||
int skip_td = 0;
|
|
||||||
union xhci_trb *cur_trb;
|
union xhci_trb *cur_trb;
|
||||||
struct xhci_segment *cur_seg;
|
struct xhci_segment *cur_seg;
|
||||||
|
struct usb_iso_packet_descriptor *frame;
|
||||||
u32 trb_comp_code;
|
u32 trb_comp_code;
|
||||||
|
bool skip_td = false;
|
||||||
|
|
||||||
ep_ring = xhci_dma_to_transfer_ring(ep, event->buffer);
|
ep_ring = xhci_dma_to_transfer_ring(ep, event->buffer);
|
||||||
trb_comp_code = GET_COMP_CODE(event->transfer_len);
|
trb_comp_code = GET_COMP_CODE(event->transfer_len);
|
||||||
urb_priv = td->urb->hcpriv;
|
urb_priv = td->urb->hcpriv;
|
||||||
idx = urb_priv->td_cnt;
|
idx = urb_priv->td_cnt;
|
||||||
|
frame = &td->urb->iso_frame_desc[idx];
|
||||||
|
|
||||||
if (ep->skip) {
|
/* handle completion code */
|
||||||
/* The transfer is partly done */
|
switch (trb_comp_code) {
|
||||||
*status = -EXDEV;
|
case COMP_SUCCESS:
|
||||||
td->urb->iso_frame_desc[idx].status = -EXDEV;
|
frame->status = 0;
|
||||||
} else {
|
xhci_dbg(xhci, "Successful isoc transfer!\n");
|
||||||
/* handle completion code */
|
break;
|
||||||
switch (trb_comp_code) {
|
case COMP_SHORT_TX:
|
||||||
case COMP_SUCCESS:
|
frame->status = td->urb->transfer_flags & URB_SHORT_NOT_OK ?
|
||||||
td->urb->iso_frame_desc[idx].status = 0;
|
-EREMOTEIO : 0;
|
||||||
xhci_dbg(xhci, "Successful isoc transfer!\n");
|
break;
|
||||||
break;
|
case COMP_BW_OVER:
|
||||||
case COMP_SHORT_TX:
|
frame->status = -ECOMM;
|
||||||
if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
|
skip_td = true;
|
||||||
td->urb->iso_frame_desc[idx].status =
|
break;
|
||||||
-EREMOTEIO;
|
case COMP_BUFF_OVER:
|
||||||
else
|
case COMP_BABBLE:
|
||||||
td->urb->iso_frame_desc[idx].status = 0;
|
frame->status = -EOVERFLOW;
|
||||||
break;
|
skip_td = true;
|
||||||
case COMP_BW_OVER:
|
break;
|
||||||
td->urb->iso_frame_desc[idx].status = -ECOMM;
|
case COMP_STALL:
|
||||||
skip_td = 1;
|
frame->status = -EPROTO;
|
||||||
break;
|
skip_td = true;
|
||||||
case COMP_BUFF_OVER:
|
break;
|
||||||
case COMP_BABBLE:
|
case COMP_STOP:
|
||||||
td->urb->iso_frame_desc[idx].status = -EOVERFLOW;
|
case COMP_STOP_INVAL:
|
||||||
skip_td = 1;
|
break;
|
||||||
break;
|
default:
|
||||||
case COMP_STALL:
|
frame->status = -1;
|
||||||
td->urb->iso_frame_desc[idx].status = -EPROTO;
|
break;
|
||||||
skip_td = 1;
|
|
||||||
break;
|
|
||||||
case COMP_STOP:
|
|
||||||
case COMP_STOP_INVAL:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
td->urb->iso_frame_desc[idx].status = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* calc actual length */
|
if (trb_comp_code == COMP_SUCCESS || skip_td) {
|
||||||
if (ep->skip) {
|
frame->actual_length = frame->length;
|
||||||
td->urb->iso_frame_desc[idx].actual_length = 0;
|
td->urb->actual_length += frame->length;
|
||||||
/* Update ring dequeue pointer */
|
|
||||||
while (ep_ring->dequeue != td->last_trb)
|
|
||||||
inc_deq(xhci, ep_ring, false);
|
|
||||||
inc_deq(xhci, ep_ring, false);
|
|
||||||
return finish_td(xhci, td, event_trb, event, ep, status, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (trb_comp_code == COMP_SUCCESS || skip_td == 1) {
|
|
||||||
td->urb->iso_frame_desc[idx].actual_length =
|
|
||||||
td->urb->iso_frame_desc[idx].length;
|
|
||||||
td->urb->actual_length +=
|
|
||||||
td->urb->iso_frame_desc[idx].length;
|
|
||||||
} else {
|
} else {
|
||||||
for (cur_trb = ep_ring->dequeue,
|
for (cur_trb = ep_ring->dequeue,
|
||||||
cur_seg = ep_ring->deq_seg; cur_trb != event_trb;
|
cur_seg = ep_ring->deq_seg; cur_trb != event_trb;
|
||||||
|
@ -1755,7 +1763,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
|
||||||
TRB_LEN(event->transfer_len);
|
TRB_LEN(event->transfer_len);
|
||||||
|
|
||||||
if (trb_comp_code != COMP_STOP_INVAL) {
|
if (trb_comp_code != COMP_STOP_INVAL) {
|
||||||
td->urb->iso_frame_desc[idx].actual_length = len;
|
frame->actual_length = len;
|
||||||
td->urb->actual_length += len;
|
td->urb->actual_length += len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1766,6 +1774,35 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
|
||||||
return finish_td(xhci, td, event_trb, event, ep, status, false);
|
return finish_td(xhci, td, event_trb, event, ep, status, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int skip_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
|
||||||
|
struct xhci_transfer_event *event,
|
||||||
|
struct xhci_virt_ep *ep, int *status)
|
||||||
|
{
|
||||||
|
struct xhci_ring *ep_ring;
|
||||||
|
struct urb_priv *urb_priv;
|
||||||
|
struct usb_iso_packet_descriptor *frame;
|
||||||
|
int idx;
|
||||||
|
|
||||||
|
ep_ring = xhci_dma_to_transfer_ring(ep, event->buffer);
|
||||||
|
urb_priv = td->urb->hcpriv;
|
||||||
|
idx = urb_priv->td_cnt;
|
||||||
|
frame = &td->urb->iso_frame_desc[idx];
|
||||||
|
|
||||||
|
/* The transfer is partly done */
|
||||||
|
*status = -EXDEV;
|
||||||
|
frame->status = -EXDEV;
|
||||||
|
|
||||||
|
/* calc actual length */
|
||||||
|
frame->actual_length = 0;
|
||||||
|
|
||||||
|
/* Update ring dequeue pointer */
|
||||||
|
while (ep_ring->dequeue != td->last_trb)
|
||||||
|
inc_deq(xhci, ep_ring, false);
|
||||||
|
inc_deq(xhci, ep_ring, false);
|
||||||
|
|
||||||
|
return finish_td(xhci, td, NULL, event, ep, status, true);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Process bulk and interrupt tds, update urb status and actual_length.
|
* Process bulk and interrupt tds, update urb status and actual_length.
|
||||||
*/
|
*/
|
||||||
|
@ -2024,36 +2061,42 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
||||||
}
|
}
|
||||||
|
|
||||||
td = list_entry(ep_ring->td_list.next, struct xhci_td, td_list);
|
td = list_entry(ep_ring->td_list.next, struct xhci_td, td_list);
|
||||||
|
|
||||||
/* Is this a TRB in the currently executing TD? */
|
/* Is this a TRB in the currently executing TD? */
|
||||||
event_seg = trb_in_td(ep_ring->deq_seg, ep_ring->dequeue,
|
event_seg = trb_in_td(ep_ring->deq_seg, ep_ring->dequeue,
|
||||||
td->last_trb, event_dma);
|
td->last_trb, event_dma);
|
||||||
if (event_seg && ep->skip) {
|
if (!event_seg) {
|
||||||
|
if (!ep->skip ||
|
||||||
|
!usb_endpoint_xfer_isoc(&td->urb->ep->desc)) {
|
||||||
|
/* HC is busted, give up! */
|
||||||
|
xhci_err(xhci,
|
||||||
|
"ERROR Transfer event TRB DMA ptr not "
|
||||||
|
"part of current TD\n");
|
||||||
|
return -ESHUTDOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = skip_isoc_td(xhci, td, event, ep, &status);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ep->skip) {
|
||||||
xhci_dbg(xhci, "Found td. Clear skip flag.\n");
|
xhci_dbg(xhci, "Found td. Clear skip flag.\n");
|
||||||
ep->skip = false;
|
ep->skip = false;
|
||||||
}
|
}
|
||||||
if (!event_seg &&
|
|
||||||
(!ep->skip || !usb_endpoint_xfer_isoc(&td->urb->ep->desc))) {
|
|
||||||
/* HC is busted, give up! */
|
|
||||||
xhci_err(xhci, "ERROR Transfer event TRB DMA ptr not "
|
|
||||||
"part of current TD\n");
|
|
||||||
return -ESHUTDOWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event_seg) {
|
event_trb = &event_seg->trbs[(event_dma - event_seg->dma) /
|
||||||
event_trb = &event_seg->trbs[(event_dma -
|
sizeof(*event_trb)];
|
||||||
event_seg->dma) / sizeof(*event_trb)];
|
/*
|
||||||
/*
|
* No-op TRB should not trigger interrupts.
|
||||||
* No-op TRB should not trigger interrupts.
|
* If event_trb is a no-op TRB, it means the
|
||||||
* If event_trb is a no-op TRB, it means the
|
* corresponding TD has been cancelled. Just ignore
|
||||||
* corresponding TD has been cancelled. Just ignore
|
* the TD.
|
||||||
* the TD.
|
*/
|
||||||
*/
|
if ((event_trb->generic.field[3] & TRB_TYPE_BITMASK)
|
||||||
if ((event_trb->generic.field[3] & TRB_TYPE_BITMASK)
|
== TRB_TYPE(TRB_TR_NOOP)) {
|
||||||
== TRB_TYPE(TRB_TR_NOOP)) {
|
xhci_dbg(xhci,
|
||||||
xhci_dbg(xhci, "event_trb is a no-op TRB. "
|
"event_trb is a no-op TRB. Skip it\n");
|
||||||
"Skip it\n");
|
goto cleanup;
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now update the urb's actual_length and give back to
|
/* Now update the urb's actual_length and give back to
|
||||||
|
@ -3126,6 +3169,12 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (xhci_to_hcd(xhci)->self.bandwidth_isoc_reqs == 0) {
|
||||||
|
if (xhci->quirks & XHCI_AMD_PLL_FIX)
|
||||||
|
usb_amd_quirk_pll_disable();
|
||||||
|
}
|
||||||
|
xhci_to_hcd(xhci)->self.bandwidth_isoc_reqs++;
|
||||||
|
|
||||||
giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id,
|
giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id,
|
||||||
start_cycle, start_trb);
|
start_cycle, start_trb);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -550,6 +550,9 @@ void xhci_stop(struct usb_hcd *hcd)
|
||||||
del_timer_sync(&xhci->event_ring_timer);
|
del_timer_sync(&xhci->event_ring_timer);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (xhci->quirks & XHCI_AMD_PLL_FIX)
|
||||||
|
usb_amd_dev_put();
|
||||||
|
|
||||||
xhci_dbg(xhci, "// Disabling event ring interrupts\n");
|
xhci_dbg(xhci, "// Disabling event ring interrupts\n");
|
||||||
temp = xhci_readl(xhci, &xhci->op_regs->status);
|
temp = xhci_readl(xhci, &xhci->op_regs->status);
|
||||||
xhci_writel(xhci, temp & ~STS_EINT, &xhci->op_regs->status);
|
xhci_writel(xhci, temp & ~STS_EINT, &xhci->op_regs->status);
|
||||||
|
@ -771,7 +774,9 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
|
||||||
|
|
||||||
/* If restore operation fails, re-initialize the HC during resume */
|
/* If restore operation fails, re-initialize the HC during resume */
|
||||||
if ((temp & STS_SRE) || hibernated) {
|
if ((temp & STS_SRE) || hibernated) {
|
||||||
usb_root_hub_lost_power(hcd->self.root_hub);
|
/* Let the USB core know _both_ roothubs lost power. */
|
||||||
|
usb_root_hub_lost_power(xhci->main_hcd->self.root_hub);
|
||||||
|
usb_root_hub_lost_power(xhci->shared_hcd->self.root_hub);
|
||||||
|
|
||||||
xhci_dbg(xhci, "Stop HCD\n");
|
xhci_dbg(xhci, "Stop HCD\n");
|
||||||
xhci_halt(xhci);
|
xhci_halt(xhci);
|
||||||
|
@ -2386,10 +2391,18 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
|
||||||
/* Everything but endpoint 0 is disabled, so free or cache the rings. */
|
/* Everything but endpoint 0 is disabled, so free or cache the rings. */
|
||||||
last_freed_endpoint = 1;
|
last_freed_endpoint = 1;
|
||||||
for (i = 1; i < 31; ++i) {
|
for (i = 1; i < 31; ++i) {
|
||||||
if (!virt_dev->eps[i].ring)
|
struct xhci_virt_ep *ep = &virt_dev->eps[i];
|
||||||
continue;
|
|
||||||
xhci_free_or_cache_endpoint_ring(xhci, virt_dev, i);
|
if (ep->ep_state & EP_HAS_STREAMS) {
|
||||||
last_freed_endpoint = i;
|
xhci_free_stream_info(xhci, ep->stream_info);
|
||||||
|
ep->stream_info = NULL;
|
||||||
|
ep->ep_state &= ~EP_HAS_STREAMS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ep->ring) {
|
||||||
|
xhci_free_or_cache_endpoint_ring(xhci, virt_dev, i);
|
||||||
|
last_freed_endpoint = i;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
xhci_dbg(xhci, "Output context after successful reset device cmd:\n");
|
xhci_dbg(xhci, "Output context after successful reset device cmd:\n");
|
||||||
xhci_dbg_ctx(xhci, virt_dev->out_ctx, last_freed_endpoint);
|
xhci_dbg_ctx(xhci, virt_dev->out_ctx, last_freed_endpoint);
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
|
|
||||||
/* Code sharing between pci-quirks and xhci hcd */
|
/* Code sharing between pci-quirks and xhci hcd */
|
||||||
#include "xhci-ext-caps.h"
|
#include "xhci-ext-caps.h"
|
||||||
|
#include "pci-quirks.h"
|
||||||
|
|
||||||
/* xHCI PCI Configuration Registers */
|
/* xHCI PCI Configuration Registers */
|
||||||
#define XHCI_SBRN_OFFSET (0x60)
|
#define XHCI_SBRN_OFFSET (0x60)
|
||||||
|
@ -232,7 +233,7 @@ struct xhci_op_regs {
|
||||||
* notification type that matches a bit set in this bit field.
|
* notification type that matches a bit set in this bit field.
|
||||||
*/
|
*/
|
||||||
#define DEV_NOTE_MASK (0xffff)
|
#define DEV_NOTE_MASK (0xffff)
|
||||||
#define ENABLE_DEV_NOTE(x) (1 << x)
|
#define ENABLE_DEV_NOTE(x) (1 << (x))
|
||||||
/* Most of the device notification types should only be used for debug.
|
/* Most of the device notification types should only be used for debug.
|
||||||
* SW does need to pay attention to function wake notifications.
|
* SW does need to pay attention to function wake notifications.
|
||||||
*/
|
*/
|
||||||
|
@ -348,6 +349,9 @@ struct xhci_op_regs {
|
||||||
/* Initiate a warm port reset - complete when PORT_WRC is '1' */
|
/* Initiate a warm port reset - complete when PORT_WRC is '1' */
|
||||||
#define PORT_WR (1 << 31)
|
#define PORT_WR (1 << 31)
|
||||||
|
|
||||||
|
/* We mark duplicate entries with -1 */
|
||||||
|
#define DUPLICATE_ENTRY ((u8)(-1))
|
||||||
|
|
||||||
/* Port Power Management Status and Control - port_power_base bitmasks */
|
/* Port Power Management Status and Control - port_power_base bitmasks */
|
||||||
/* Inactivity timer value for transitions into U1, in microseconds.
|
/* Inactivity timer value for transitions into U1, in microseconds.
|
||||||
* Timeout can be up to 127us. 0xFF means an infinite timeout.
|
* Timeout can be up to 127us. 0xFF means an infinite timeout.
|
||||||
|
@ -601,11 +605,11 @@ struct xhci_ep_ctx {
|
||||||
#define EP_STATE_STOPPED 3
|
#define EP_STATE_STOPPED 3
|
||||||
#define EP_STATE_ERROR 4
|
#define EP_STATE_ERROR 4
|
||||||
/* Mult - Max number of burtst within an interval, in EP companion desc. */
|
/* Mult - Max number of burtst within an interval, in EP companion desc. */
|
||||||
#define EP_MULT(p) ((p & 0x3) << 8)
|
#define EP_MULT(p) (((p) & 0x3) << 8)
|
||||||
/* bits 10:14 are Max Primary Streams */
|
/* bits 10:14 are Max Primary Streams */
|
||||||
/* bit 15 is Linear Stream Array */
|
/* bit 15 is Linear Stream Array */
|
||||||
/* Interval - period between requests to an endpoint - 125u increments. */
|
/* Interval - period between requests to an endpoint - 125u increments. */
|
||||||
#define EP_INTERVAL(p) ((p & 0xff) << 16)
|
#define EP_INTERVAL(p) (((p) & 0xff) << 16)
|
||||||
#define EP_INTERVAL_TO_UFRAMES(p) (1 << (((p) >> 16) & 0xff))
|
#define EP_INTERVAL_TO_UFRAMES(p) (1 << (((p) >> 16) & 0xff))
|
||||||
#define EP_MAXPSTREAMS_MASK (0x1f << 10)
|
#define EP_MAXPSTREAMS_MASK (0x1f << 10)
|
||||||
#define EP_MAXPSTREAMS(p) (((p) << 10) & EP_MAXPSTREAMS_MASK)
|
#define EP_MAXPSTREAMS(p) (((p) << 10) & EP_MAXPSTREAMS_MASK)
|
||||||
|
@ -1276,6 +1280,7 @@ struct xhci_hcd {
|
||||||
#define XHCI_LINK_TRB_QUIRK (1 << 0)
|
#define XHCI_LINK_TRB_QUIRK (1 << 0)
|
||||||
#define XHCI_RESET_EP_QUIRK (1 << 1)
|
#define XHCI_RESET_EP_QUIRK (1 << 1)
|
||||||
#define XHCI_NEC_HOST (1 << 2)
|
#define XHCI_NEC_HOST (1 << 2)
|
||||||
|
#define XHCI_AMD_PLL_FIX (1 << 3)
|
||||||
/* There are two roothubs to keep track of bus suspend info for */
|
/* There are two roothubs to keep track of bus suspend info for */
|
||||||
struct xhci_bus_state bus_state[2];
|
struct xhci_bus_state bus_state[2];
|
||||||
/* Is each xHCI roothub port a USB 3.0, USB 2.0, or USB 1.1 port? */
|
/* Is each xHCI roothub port a USB 3.0, USB 2.0, or USB 1.1 port? */
|
||||||
|
|
|
@ -14,7 +14,7 @@ config USB_MUSB_HDRC
|
||||||
select TWL4030_USB if MACH_OMAP_3430SDP
|
select TWL4030_USB if MACH_OMAP_3430SDP
|
||||||
select TWL6030_USB if MACH_OMAP_4430SDP || MACH_OMAP4_PANDA
|
select TWL6030_USB if MACH_OMAP_4430SDP || MACH_OMAP4_PANDA
|
||||||
select USB_OTG_UTILS
|
select USB_OTG_UTILS
|
||||||
tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
|
bool 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
|
||||||
help
|
help
|
||||||
Say Y here if your system has a dual role high speed USB
|
Say Y here if your system has a dual role high speed USB
|
||||||
controller based on the Mentor Graphics silicon IP. Then
|
controller based on the Mentor Graphics silicon IP. Then
|
||||||
|
@ -30,8 +30,8 @@ config USB_MUSB_HDRC
|
||||||
|
|
||||||
If you do not know what this is, please say N.
|
If you do not know what this is, please say N.
|
||||||
|
|
||||||
To compile this driver as a module, choose M here; the
|
# To compile this driver as a module, choose M here; the
|
||||||
module will be called "musb-hdrc".
|
# module will be called "musb-hdrc".
|
||||||
|
|
||||||
choice
|
choice
|
||||||
prompt "Platform Glue Layer"
|
prompt "Platform Glue Layer"
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include <asm/cacheflush.h>
|
#include <asm/cacheflush.h>
|
||||||
|
|
||||||
#include "musb_core.h"
|
#include "musb_core.h"
|
||||||
|
#include "musbhsdma.h"
|
||||||
#include "blackfin.h"
|
#include "blackfin.h"
|
||||||
|
|
||||||
struct bfin_glue {
|
struct bfin_glue {
|
||||||
|
@ -332,6 +333,27 @@ static int bfin_musb_set_mode(struct musb *musb, u8 musb_mode)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int bfin_musb_adjust_channel_params(struct dma_channel *channel,
|
||||||
|
u16 packet_sz, u8 *mode,
|
||||||
|
dma_addr_t *dma_addr, u32 *len)
|
||||||
|
{
|
||||||
|
struct musb_dma_channel *musb_channel = channel->private_data;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Anomaly 05000450 might cause data corruption when using DMA
|
||||||
|
* MODE 1 transmits with short packet. So to work around this,
|
||||||
|
* we truncate all MODE 1 transfers down to a multiple of the
|
||||||
|
* max packet size, and then do the last short packet transfer
|
||||||
|
* (if there is any) using MODE 0.
|
||||||
|
*/
|
||||||
|
if (ANOMALY_05000450) {
|
||||||
|
if (musb_channel->transmit && *mode == 1)
|
||||||
|
*len = *len - (*len % packet_sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void bfin_musb_reg_init(struct musb *musb)
|
static void bfin_musb_reg_init(struct musb *musb)
|
||||||
{
|
{
|
||||||
if (ANOMALY_05000346) {
|
if (ANOMALY_05000346) {
|
||||||
|
@ -430,6 +452,8 @@ static const struct musb_platform_ops bfin_ops = {
|
||||||
|
|
||||||
.vbus_status = bfin_musb_vbus_status,
|
.vbus_status = bfin_musb_vbus_status,
|
||||||
.set_vbus = bfin_musb_set_vbus,
|
.set_vbus = bfin_musb_set_vbus,
|
||||||
|
|
||||||
|
.adjust_channel_params = bfin_musb_adjust_channel_params,
|
||||||
};
|
};
|
||||||
|
|
||||||
static u64 bfin_dmamask = DMA_BIT_MASK(32);
|
static u64 bfin_dmamask = DMA_BIT_MASK(32);
|
||||||
|
|
|
@ -597,12 +597,12 @@ cppi_next_tx_segment(struct musb *musb, struct cppi_channel *tx)
|
||||||
length = min(n_bds * maxpacket, length);
|
length = min(n_bds * maxpacket, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
DBG(4, "TX DMA%d, pktSz %d %s bds %d dma 0x%x len %u\n",
|
DBG(4, "TX DMA%d, pktSz %d %s bds %d dma 0x%llx len %u\n",
|
||||||
tx->index,
|
tx->index,
|
||||||
maxpacket,
|
maxpacket,
|
||||||
rndis ? "rndis" : "transparent",
|
rndis ? "rndis" : "transparent",
|
||||||
n_bds,
|
n_bds,
|
||||||
addr, length);
|
(unsigned long long)addr, length);
|
||||||
|
|
||||||
cppi_rndis_update(tx, 0, musb->ctrl_base, rndis);
|
cppi_rndis_update(tx, 0, musb->ctrl_base, rndis);
|
||||||
|
|
||||||
|
@ -820,7 +820,7 @@ cppi_next_rx_segment(struct musb *musb, struct cppi_channel *rx, int onepacket)
|
||||||
length = min(n_bds * maxpacket, length);
|
length = min(n_bds * maxpacket, length);
|
||||||
|
|
||||||
DBG(4, "RX DMA%d seg, maxp %d %s bds %d (cnt %d) "
|
DBG(4, "RX DMA%d seg, maxp %d %s bds %d (cnt %d) "
|
||||||
"dma 0x%x len %u %u/%u\n",
|
"dma 0x%llx len %u %u/%u\n",
|
||||||
rx->index, maxpacket,
|
rx->index, maxpacket,
|
||||||
onepacket
|
onepacket
|
||||||
? (is_rndis ? "rndis" : "onepacket")
|
? (is_rndis ? "rndis" : "onepacket")
|
||||||
|
@ -829,7 +829,8 @@ cppi_next_rx_segment(struct musb *musb, struct cppi_channel *rx, int onepacket)
|
||||||
musb_readl(tibase,
|
musb_readl(tibase,
|
||||||
DAVINCI_RXCPPI_BUFCNT0_REG + (rx->index * 4))
|
DAVINCI_RXCPPI_BUFCNT0_REG + (rx->index * 4))
|
||||||
& 0xffff,
|
& 0xffff,
|
||||||
addr, length, rx->channel.actual_len, rx->buf_len);
|
(unsigned long long)addr, length,
|
||||||
|
rx->channel.actual_len, rx->buf_len);
|
||||||
|
|
||||||
/* only queue one segment at a time, since the hardware prevents
|
/* only queue one segment at a time, since the hardware prevents
|
||||||
* correct queue shutdown after unexpected short packets
|
* correct queue shutdown after unexpected short packets
|
||||||
|
@ -1039,9 +1040,9 @@ static bool cppi_rx_scan(struct cppi *cppi, unsigned ch)
|
||||||
if (!completed && (bd->hw_options & CPPI_OWN_SET))
|
if (!completed && (bd->hw_options & CPPI_OWN_SET))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
DBG(5, "C/RXBD %08x: nxt %08x buf %08x "
|
DBG(5, "C/RXBD %llx: nxt %08x buf %08x "
|
||||||
"off.len %08x opt.len %08x (%d)\n",
|
"off.len %08x opt.len %08x (%d)\n",
|
||||||
bd->dma, bd->hw_next, bd->hw_bufp,
|
(unsigned long long)bd->dma, bd->hw_next, bd->hw_bufp,
|
||||||
bd->hw_off_len, bd->hw_options,
|
bd->hw_off_len, bd->hw_options,
|
||||||
rx->channel.actual_len);
|
rx->channel.actual_len);
|
||||||
|
|
||||||
|
@ -1111,11 +1112,12 @@ static bool cppi_rx_scan(struct cppi *cppi, unsigned ch)
|
||||||
musb_ep_select(cppi->mregs, rx->index + 1);
|
musb_ep_select(cppi->mregs, rx->index + 1);
|
||||||
csr = musb_readw(regs, MUSB_RXCSR);
|
csr = musb_readw(regs, MUSB_RXCSR);
|
||||||
if (csr & MUSB_RXCSR_DMAENAB) {
|
if (csr & MUSB_RXCSR_DMAENAB) {
|
||||||
DBG(4, "list%d %p/%p, last %08x%s, csr %04x\n",
|
DBG(4, "list%d %p/%p, last %llx%s, csr %04x\n",
|
||||||
rx->index,
|
rx->index,
|
||||||
rx->head, rx->tail,
|
rx->head, rx->tail,
|
||||||
rx->last_processed
|
rx->last_processed
|
||||||
? rx->last_processed->dma
|
? (unsigned long long)
|
||||||
|
rx->last_processed->dma
|
||||||
: 0,
|
: 0,
|
||||||
completed ? ", completed" : "",
|
completed ? ", completed" : "",
|
||||||
csr);
|
csr);
|
||||||
|
@ -1167,8 +1169,11 @@ irqreturn_t cppi_interrupt(int irq, void *dev_id)
|
||||||
tx = musb_readl(tibase, DAVINCI_TXCPPI_MASKED_REG);
|
tx = musb_readl(tibase, DAVINCI_TXCPPI_MASKED_REG);
|
||||||
rx = musb_readl(tibase, DAVINCI_RXCPPI_MASKED_REG);
|
rx = musb_readl(tibase, DAVINCI_RXCPPI_MASKED_REG);
|
||||||
|
|
||||||
if (!tx && !rx)
|
if (!tx && !rx) {
|
||||||
|
if (cppi->irq)
|
||||||
|
spin_unlock_irqrestore(&musb->lock, flags);
|
||||||
return IRQ_NONE;
|
return IRQ_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
DBG(4, "CPPI IRQ Tx%x Rx%x\n", tx, rx);
|
DBG(4, "CPPI IRQ Tx%x Rx%x\n", tx, rx);
|
||||||
|
|
||||||
|
@ -1199,7 +1204,7 @@ irqreturn_t cppi_interrupt(int irq, void *dev_id)
|
||||||
*/
|
*/
|
||||||
if (NULL == bd) {
|
if (NULL == bd) {
|
||||||
DBG(1, "null BD\n");
|
DBG(1, "null BD\n");
|
||||||
tx_ram->tx_complete = 0;
|
musb_writel(&tx_ram->tx_complete, 0, 0);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1452,7 +1457,7 @@ static int cppi_channel_abort(struct dma_channel *channel)
|
||||||
* compare mode by writing 1 to the tx_complete register.
|
* compare mode by writing 1 to the tx_complete register.
|
||||||
*/
|
*/
|
||||||
cppi_reset_tx(tx_ram, 1);
|
cppi_reset_tx(tx_ram, 1);
|
||||||
cppi_ch->head = 0;
|
cppi_ch->head = NULL;
|
||||||
musb_writel(&tx_ram->tx_complete, 0, 1);
|
musb_writel(&tx_ram->tx_complete, 0, 1);
|
||||||
cppi_dump_tx(5, cppi_ch, " (done teardown)");
|
cppi_dump_tx(5, cppi_ch, " (done teardown)");
|
||||||
|
|
||||||
|
|
|
@ -1030,6 +1030,7 @@ static void musb_shutdown(struct platform_device *pdev)
|
||||||
struct musb *musb = dev_to_musb(&pdev->dev);
|
struct musb *musb = dev_to_musb(&pdev->dev);
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
|
pm_runtime_get_sync(musb->controller);
|
||||||
spin_lock_irqsave(&musb->lock, flags);
|
spin_lock_irqsave(&musb->lock, flags);
|
||||||
musb_platform_disable(musb);
|
musb_platform_disable(musb);
|
||||||
musb_generic_disable(musb);
|
musb_generic_disable(musb);
|
||||||
|
@ -1040,6 +1041,7 @@ static void musb_shutdown(struct platform_device *pdev)
|
||||||
musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
|
musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
|
||||||
musb_platform_exit(musb);
|
musb_platform_exit(musb);
|
||||||
|
|
||||||
|
pm_runtime_put(musb->controller);
|
||||||
/* FIXME power down */
|
/* FIXME power down */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -261,6 +261,7 @@ enum musb_g_ep0_state {
|
||||||
* @try_ilde: tries to idle the IP
|
* @try_ilde: tries to idle the IP
|
||||||
* @vbus_status: returns vbus status if possible
|
* @vbus_status: returns vbus status if possible
|
||||||
* @set_vbus: forces vbus status
|
* @set_vbus: forces vbus status
|
||||||
|
* @channel_program: pre check for standard dma channel_program func
|
||||||
*/
|
*/
|
||||||
struct musb_platform_ops {
|
struct musb_platform_ops {
|
||||||
int (*init)(struct musb *musb);
|
int (*init)(struct musb *musb);
|
||||||
|
@ -274,6 +275,10 @@ struct musb_platform_ops {
|
||||||
|
|
||||||
int (*vbus_status)(struct musb *musb);
|
int (*vbus_status)(struct musb *musb);
|
||||||
void (*set_vbus)(struct musb *musb, int on);
|
void (*set_vbus)(struct musb *musb, int on);
|
||||||
|
|
||||||
|
int (*adjust_channel_params)(struct dma_channel *channel,
|
||||||
|
u16 packet_sz, u8 *mode,
|
||||||
|
dma_addr_t *dma_addr, u32 *len);
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -535,7 +535,7 @@ void musb_g_tx(struct musb *musb, u8 epnum)
|
||||||
is_dma = 1;
|
is_dma = 1;
|
||||||
csr |= MUSB_TXCSR_P_WZC_BITS;
|
csr |= MUSB_TXCSR_P_WZC_BITS;
|
||||||
csr &= ~(MUSB_TXCSR_DMAENAB | MUSB_TXCSR_P_UNDERRUN |
|
csr &= ~(MUSB_TXCSR_DMAENAB | MUSB_TXCSR_P_UNDERRUN |
|
||||||
MUSB_TXCSR_TXPKTRDY);
|
MUSB_TXCSR_TXPKTRDY | MUSB_TXCSR_AUTOSET);
|
||||||
musb_writew(epio, MUSB_TXCSR, csr);
|
musb_writew(epio, MUSB_TXCSR, csr);
|
||||||
/* Ensure writebuffer is empty. */
|
/* Ensure writebuffer is empty. */
|
||||||
csr = musb_readw(epio, MUSB_TXCSR);
|
csr = musb_readw(epio, MUSB_TXCSR);
|
||||||
|
@ -1296,7 +1296,7 @@ static int musb_gadget_dequeue(struct usb_ep *ep, struct usb_request *request)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if the hardware doesn't have the request, easy ... */
|
/* if the hardware doesn't have the request, easy ... */
|
||||||
if (musb_ep->req_list.next != &request->list || musb_ep->busy)
|
if (musb_ep->req_list.next != &req->list || musb_ep->busy)
|
||||||
musb_g_giveback(musb_ep, request, -ECONNRESET);
|
musb_g_giveback(musb_ep, request, -ECONNRESET);
|
||||||
|
|
||||||
/* ... else abort the dma transfer ... */
|
/* ... else abort the dma transfer ... */
|
||||||
|
|
|
@ -169,6 +169,14 @@ static int dma_channel_program(struct dma_channel *channel,
|
||||||
BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN ||
|
BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN ||
|
||||||
channel->status == MUSB_DMA_STATUS_BUSY);
|
channel->status == MUSB_DMA_STATUS_BUSY);
|
||||||
|
|
||||||
|
/* Let targets check/tweak the arguments */
|
||||||
|
if (musb->ops->adjust_channel_params) {
|
||||||
|
int ret = musb->ops->adjust_channel_params(channel,
|
||||||
|
packet_sz, &mode, &dma_addr, &len);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The DMA engine in RTL1.8 and above cannot handle
|
* The DMA engine in RTL1.8 and above cannot handle
|
||||||
* DMA addresses that are not aligned to a 4 byte boundary.
|
* DMA addresses that are not aligned to a 4 byte boundary.
|
||||||
|
|
|
@ -259,9 +259,10 @@ static int musb_otg_notifications(struct notifier_block *nb,
|
||||||
case USB_EVENT_VBUS:
|
case USB_EVENT_VBUS:
|
||||||
DBG(4, "VBUS Connect\n");
|
DBG(4, "VBUS Connect\n");
|
||||||
|
|
||||||
|
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
|
||||||
if (musb->gadget_driver)
|
if (musb->gadget_driver)
|
||||||
pm_runtime_get_sync(musb->controller);
|
pm_runtime_get_sync(musb->controller);
|
||||||
|
#endif
|
||||||
otg_init(musb->xceiv);
|
otg_init(musb->xceiv);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -93,6 +93,8 @@ static int __init ux500_probe(struct platform_device *pdev)
|
||||||
}
|
}
|
||||||
|
|
||||||
musb->dev.parent = &pdev->dev;
|
musb->dev.parent = &pdev->dev;
|
||||||
|
musb->dev.dma_mask = pdev->dev.dma_mask;
|
||||||
|
musb->dev.coherent_dma_mask = pdev->dev.coherent_dma_mask;
|
||||||
|
|
||||||
glue->dev = &pdev->dev;
|
glue->dev = &pdev->dev;
|
||||||
glue->musb = musb;
|
glue->musb = musb;
|
||||||
|
|
|
@ -151,6 +151,8 @@ static struct ftdi_sio_quirk ftdi_stmclite_quirk = {
|
||||||
* /sys/bus/usb/ftdi_sio/new_id, then send patch/report!
|
* /sys/bus/usb/ftdi_sio/new_id, then send patch/report!
|
||||||
*/
|
*/
|
||||||
static struct usb_device_id id_table_combined [] = {
|
static struct usb_device_id id_table_combined [] = {
|
||||||
|
{ USB_DEVICE(FTDI_VID, FTDI_CTI_MINI_PID) },
|
||||||
|
{ USB_DEVICE(FTDI_VID, FTDI_CTI_NANO_PID) },
|
||||||
{ USB_DEVICE(FTDI_VID, FTDI_AMC232_PID) },
|
{ USB_DEVICE(FTDI_VID, FTDI_AMC232_PID) },
|
||||||
{ USB_DEVICE(FTDI_VID, FTDI_CANUSB_PID) },
|
{ USB_DEVICE(FTDI_VID, FTDI_CANUSB_PID) },
|
||||||
{ USB_DEVICE(FTDI_VID, FTDI_CANDAPTER_PID) },
|
{ USB_DEVICE(FTDI_VID, FTDI_CANDAPTER_PID) },
|
||||||
|
@ -525,6 +527,7 @@ static struct usb_device_id id_table_combined [] = {
|
||||||
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_8_PID) },
|
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_8_PID) },
|
||||||
{ USB_DEVICE(IDTECH_VID, IDTECH_IDT1221U_PID) },
|
{ USB_DEVICE(IDTECH_VID, IDTECH_IDT1221U_PID) },
|
||||||
{ USB_DEVICE(OCT_VID, OCT_US101_PID) },
|
{ USB_DEVICE(OCT_VID, OCT_US101_PID) },
|
||||||
|
{ USB_DEVICE(OCT_VID, OCT_DK201_PID) },
|
||||||
{ USB_DEVICE(FTDI_VID, FTDI_HE_TIRA1_PID),
|
{ USB_DEVICE(FTDI_VID, FTDI_HE_TIRA1_PID),
|
||||||
.driver_info = (kernel_ulong_t)&ftdi_HE_TIRA1_quirk },
|
.driver_info = (kernel_ulong_t)&ftdi_HE_TIRA1_quirk },
|
||||||
{ USB_DEVICE(FTDI_VID, FTDI_USB_UIRT_PID),
|
{ USB_DEVICE(FTDI_VID, FTDI_USB_UIRT_PID),
|
||||||
|
@ -787,6 +790,8 @@ static struct usb_device_id id_table_combined [] = {
|
||||||
{ USB_DEVICE(FTDI_VID, MARVELL_OPENRD_PID),
|
{ USB_DEVICE(FTDI_VID, MARVELL_OPENRD_PID),
|
||||||
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
|
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
|
||||||
{ USB_DEVICE(FTDI_VID, HAMEG_HO820_PID) },
|
{ USB_DEVICE(FTDI_VID, HAMEG_HO820_PID) },
|
||||||
|
{ USB_DEVICE(FTDI_VID, HAMEG_HO720_PID) },
|
||||||
|
{ USB_DEVICE(FTDI_VID, HAMEG_HO730_PID) },
|
||||||
{ USB_DEVICE(FTDI_VID, HAMEG_HO870_PID) },
|
{ USB_DEVICE(FTDI_VID, HAMEG_HO870_PID) },
|
||||||
{ USB_DEVICE(FTDI_VID, MJSG_GENERIC_PID) },
|
{ USB_DEVICE(FTDI_VID, MJSG_GENERIC_PID) },
|
||||||
{ USB_DEVICE(FTDI_VID, MJSG_SR_RADIO_PID) },
|
{ USB_DEVICE(FTDI_VID, MJSG_SR_RADIO_PID) },
|
||||||
|
|
|
@ -300,6 +300,8 @@
|
||||||
* Hameg HO820 and HO870 interface (using VID 0x0403)
|
* Hameg HO820 and HO870 interface (using VID 0x0403)
|
||||||
*/
|
*/
|
||||||
#define HAMEG_HO820_PID 0xed74
|
#define HAMEG_HO820_PID 0xed74
|
||||||
|
#define HAMEG_HO730_PID 0xed73
|
||||||
|
#define HAMEG_HO720_PID 0xed72
|
||||||
#define HAMEG_HO870_PID 0xed71
|
#define HAMEG_HO870_PID 0xed71
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -572,6 +574,7 @@
|
||||||
/* Note: OCT US101 is also rebadged as Dick Smith Electronics (NZ) XH6381 */
|
/* Note: OCT US101 is also rebadged as Dick Smith Electronics (NZ) XH6381 */
|
||||||
/* Also rebadged as Dick Smith Electronics (Aus) XH6451 */
|
/* Also rebadged as Dick Smith Electronics (Aus) XH6451 */
|
||||||
/* Also rebadged as SIIG Inc. model US2308 hardware version 1 */
|
/* Also rebadged as SIIG Inc. model US2308 hardware version 1 */
|
||||||
|
#define OCT_DK201_PID 0x0103 /* OCT DK201 USB docking station */
|
||||||
#define OCT_US101_PID 0x0421 /* OCT US101 USB to RS-232 */
|
#define OCT_US101_PID 0x0421 /* OCT US101 USB to RS-232 */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1141,3 +1144,12 @@
|
||||||
#define QIHARDWARE_VID 0x20B7
|
#define QIHARDWARE_VID 0x20B7
|
||||||
#define MILKYMISTONE_JTAGSERIAL_PID 0x0713
|
#define MILKYMISTONE_JTAGSERIAL_PID 0x0713
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CTI GmbH RS485 Converter http://www.cti-lean.com/
|
||||||
|
*/
|
||||||
|
/* USB-485-Mini*/
|
||||||
|
#define FTDI_CTI_MINI_PID 0xF608
|
||||||
|
/* USB-Nano-485*/
|
||||||
|
#define FTDI_CTI_NANO_PID 0xF60B
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -407,6 +407,10 @@ static void option_instat_callback(struct urb *urb);
|
||||||
/* ONDA MT825UP HSDPA 14.2 modem */
|
/* ONDA MT825UP HSDPA 14.2 modem */
|
||||||
#define ONDA_MT825UP 0x000b
|
#define ONDA_MT825UP 0x000b
|
||||||
|
|
||||||
|
/* Samsung products */
|
||||||
|
#define SAMSUNG_VENDOR_ID 0x04e8
|
||||||
|
#define SAMSUNG_PRODUCT_GT_B3730 0x6889
|
||||||
|
|
||||||
/* some devices interfaces need special handling due to a number of reasons */
|
/* some devices interfaces need special handling due to a number of reasons */
|
||||||
enum option_blacklist_reason {
|
enum option_blacklist_reason {
|
||||||
OPTION_BLACKLIST_NONE = 0,
|
OPTION_BLACKLIST_NONE = 0,
|
||||||
|
@ -968,6 +972,7 @@ static const struct usb_device_id option_ids[] = {
|
||||||
{ USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100) },
|
{ USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100) },
|
||||||
{ USB_DEVICE(CELOT_VENDOR_ID, CELOT_PRODUCT_CT680M) }, /* CT-650 CDMA 450 1xEVDO modem */
|
{ USB_DEVICE(CELOT_VENDOR_ID, CELOT_PRODUCT_CT680M) }, /* CT-650 CDMA 450 1xEVDO modem */
|
||||||
{ USB_DEVICE(ONDA_VENDOR_ID, ONDA_MT825UP) }, /* ONDA MT825UP modem */
|
{ USB_DEVICE(ONDA_VENDOR_ID, ONDA_MT825UP) }, /* ONDA MT825UP modem */
|
||||||
|
{ USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_GT_B3730, USB_CLASS_CDC_DATA, 0x00, 0x00) }, /* Samsung GT-B3730/GT-B3710 LTE USB modem.*/
|
||||||
{ } /* Terminating entry */
|
{ } /* Terminating entry */
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(usb, option_ids);
|
MODULE_DEVICE_TABLE(usb, option_ids);
|
||||||
|
|
|
@ -111,7 +111,7 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
|
||||||
ifnum = intf->desc.bInterfaceNumber;
|
ifnum = intf->desc.bInterfaceNumber;
|
||||||
dbg("This Interface = %d", ifnum);
|
dbg("This Interface = %d", ifnum);
|
||||||
|
|
||||||
data = serial->private = kzalloc(sizeof(struct usb_wwan_intf_private),
|
data = kzalloc(sizeof(struct usb_wwan_intf_private),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!data)
|
if (!data)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -134,8 +134,10 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
|
||||||
usb_endpoint_is_bulk_out(&intf->endpoint[1].desc)) {
|
usb_endpoint_is_bulk_out(&intf->endpoint[1].desc)) {
|
||||||
dbg("QDL port found");
|
dbg("QDL port found");
|
||||||
|
|
||||||
if (serial->interface->num_altsetting == 1)
|
if (serial->interface->num_altsetting == 1) {
|
||||||
return 0;
|
retval = 0; /* Success */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
retval = usb_set_interface(serial->dev, ifnum, 1);
|
retval = usb_set_interface(serial->dev, ifnum, 1);
|
||||||
if (retval < 0) {
|
if (retval < 0) {
|
||||||
|
@ -145,7 +147,6 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
|
||||||
retval = -ENODEV;
|
retval = -ENODEV;
|
||||||
kfree(data);
|
kfree(data);
|
||||||
}
|
}
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -166,6 +167,7 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
|
||||||
"Could not set interface, error %d\n",
|
"Could not set interface, error %d\n",
|
||||||
retval);
|
retval);
|
||||||
retval = -ENODEV;
|
retval = -ENODEV;
|
||||||
|
kfree(data);
|
||||||
}
|
}
|
||||||
} else if (ifnum == 2) {
|
} else if (ifnum == 2) {
|
||||||
dbg("Modem port found");
|
dbg("Modem port found");
|
||||||
|
@ -177,7 +179,6 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
|
||||||
retval = -ENODEV;
|
retval = -ENODEV;
|
||||||
kfree(data);
|
kfree(data);
|
||||||
}
|
}
|
||||||
return retval;
|
|
||||||
} else if (ifnum==3) {
|
} else if (ifnum==3) {
|
||||||
/*
|
/*
|
||||||
* NMEA (serial line 9600 8N1)
|
* NMEA (serial line 9600 8N1)
|
||||||
|
@ -191,6 +192,7 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
|
||||||
"Could not set interface, error %d\n",
|
"Could not set interface, error %d\n",
|
||||||
retval);
|
retval);
|
||||||
retval = -ENODEV;
|
retval = -ENODEV;
|
||||||
|
kfree(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -199,12 +201,27 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
|
||||||
dev_err(&serial->dev->dev,
|
dev_err(&serial->dev->dev,
|
||||||
"unknown number of interfaces: %d\n", nintf);
|
"unknown number of interfaces: %d\n", nintf);
|
||||||
kfree(data);
|
kfree(data);
|
||||||
return -ENODEV;
|
retval = -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set serial->private if not returning -ENODEV */
|
||||||
|
if (retval != -ENODEV)
|
||||||
|
usb_set_serial_data(serial, data);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void qc_release(struct usb_serial *serial)
|
||||||
|
{
|
||||||
|
struct usb_wwan_intf_private *priv = usb_get_serial_data(serial);
|
||||||
|
|
||||||
|
dbg("%s", __func__);
|
||||||
|
|
||||||
|
/* Call usb_wwan release & free the private data allocated in qcprobe */
|
||||||
|
usb_wwan_release(serial);
|
||||||
|
usb_set_serial_data(serial, NULL);
|
||||||
|
kfree(priv);
|
||||||
|
}
|
||||||
|
|
||||||
static struct usb_serial_driver qcdevice = {
|
static struct usb_serial_driver qcdevice = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
|
@ -222,7 +239,7 @@ static struct usb_serial_driver qcdevice = {
|
||||||
.chars_in_buffer = usb_wwan_chars_in_buffer,
|
.chars_in_buffer = usb_wwan_chars_in_buffer,
|
||||||
.attach = usb_wwan_startup,
|
.attach = usb_wwan_startup,
|
||||||
.disconnect = usb_wwan_disconnect,
|
.disconnect = usb_wwan_disconnect,
|
||||||
.release = usb_wwan_release,
|
.release = qc_release,
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
.suspend = usb_wwan_suspend,
|
.suspend = usb_wwan_suspend,
|
||||||
.resume = usb_wwan_resume,
|
.resume = usb_wwan_resume,
|
||||||
|
|
Loading…
Reference in New Issue