Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6:
  USB: gadget: Fix EEM driver comments and VID/PID
  usb-storage: Workaround devices with bogus sense size
  USB: ehci: Fix IST boundary checking interval math.
  USB: option: Support for AIRPLUS MCD650 Datacard
  USB: whci-hcd: always do an update after processing a halted qTD
  USB: whci-hcd: handle early deletion of endpoints
  USB: wusb: don't use the stack to read security descriptor
  USB: rename Documentation/ABI/.../sysfs-class-usb_host
This commit is contained in:
Linus Torvalds 2009-10-15 15:05:33 -07:00
commit 59c0b586ae
8 changed files with 82 additions and 52 deletions

View File

@ -1,4 +1,4 @@
What: /sys/class/usb_host/usb_hostN/wusb_chid What: /sys/class/uwb_rc/uwbN/wusbhc/wusb_chid
Date: July 2008 Date: July 2008
KernelVersion: 2.6.27 KernelVersion: 2.6.27
Contact: David Vrabel <david.vrabel@csr.com> Contact: David Vrabel <david.vrabel@csr.com>
@ -9,7 +9,7 @@ Description:
Set an all zero CHID to stop the host controller. Set an all zero CHID to stop the host controller.
What: /sys/class/usb_host/usb_hostN/wusb_trust_timeout What: /sys/class/uwb_rc/uwbN/wusbhc/wusb_trust_timeout
Date: July 2008 Date: July 2008
KernelVersion: 2.6.27 KernelVersion: 2.6.27
Contact: David Vrabel <david.vrabel@csr.com> Contact: David Vrabel <david.vrabel@csr.com>

View File

@ -61,11 +61,6 @@
* simpler, Microsoft pushes their own approach: RNDIS. The published * simpler, Microsoft pushes their own approach: RNDIS. The published
* RNDIS specs are ambiguous and appear to be incomplete, and are also * RNDIS specs are ambiguous and appear to be incomplete, and are also
* needlessly complex. They borrow more from CDC ACM than CDC ECM. * needlessly complex. They borrow more from CDC ACM than CDC ECM.
*
* While CDC ECM, CDC Subset, and RNDIS are designed to extend the ethernet
* interface to the target, CDC EEM was designed to use ethernet over the USB
* link between the host and target. CDC EEM is implemented as an alternative
* to those other protocols when that communication model is more appropriate
*/ */
#define DRIVER_DESC "Ethernet Gadget" #define DRIVER_DESC "Ethernet Gadget"
@ -157,8 +152,8 @@ static inline bool has_rndis(void)
#define RNDIS_PRODUCT_NUM 0xa4a2 /* Ethernet/RNDIS Gadget */ #define RNDIS_PRODUCT_NUM 0xa4a2 /* Ethernet/RNDIS Gadget */
/* For EEM gadgets */ /* For EEM gadgets */
#define EEM_VENDOR_NUM 0x0525 /* INVALID - NEEDS TO BE ALLOCATED */ #define EEM_VENDOR_NUM 0x1d6b /* Linux Foundation */
#define EEM_PRODUCT_NUM 0xa4a1 /* INVALID - NEEDS TO BE ALLOCATED */ #define EEM_PRODUCT_NUM 0x0102 /* EEM Gadget */
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/

View File

@ -1400,6 +1400,10 @@ iso_stream_schedule (
goto fail; goto fail;
} }
period = urb->interval;
if (!stream->highspeed)
period <<= 3;
now = ehci_readl(ehci, &ehci->regs->frame_index) % mod; now = ehci_readl(ehci, &ehci->regs->frame_index) % mod;
/* when's the last uframe this urb could start? */ /* when's the last uframe this urb could start? */
@ -1417,8 +1421,8 @@ iso_stream_schedule (
/* Fell behind (by up to twice the slop amount)? */ /* Fell behind (by up to twice the slop amount)? */
if (start >= max - 2 * 8 * SCHEDULE_SLOP) if (start >= max - 2 * 8 * SCHEDULE_SLOP)
start += stream->interval * DIV_ROUND_UP( start += period * DIV_ROUND_UP(
max - start, stream->interval) - mod; max - start, period) - mod;
/* Tried to schedule too far into the future? */ /* Tried to schedule too far into the future? */
if (unlikely((start + sched->span) >= max)) { if (unlikely((start + sched->span) >= max)) {
@ -1441,10 +1445,6 @@ iso_stream_schedule (
/* NOTE: assumes URB_ISO_ASAP, to limit complexity/bugs */ /* NOTE: assumes URB_ISO_ASAP, to limit complexity/bugs */
period = urb->interval;
if (!stream->highspeed)
period <<= 3;
/* find a uframe slot with enough bandwidth */ /* find a uframe slot with enough bandwidth */
for (; start < (stream->next_uframe + period); start++) { for (; start < (stream->next_uframe + period); start++) {
int enough_space; int enough_space;

View File

@ -115,6 +115,10 @@ static uint32_t process_qset(struct whc *whc, struct whc_qset *qset)
if (status & QTD_STS_HALTED) { if (status & QTD_STS_HALTED) {
/* Ug, an error. */ /* Ug, an error. */
process_halted_qtd(whc, qset, td); process_halted_qtd(whc, qset, td);
/* A halted qTD always triggers an update
because the qset was either removed or
reactivated. */
update |= WHC_UPDATE_UPDATED;
goto done; goto done;
} }
@ -305,6 +309,7 @@ int asl_urb_dequeue(struct whc *whc, struct urb *urb, int status)
struct whc_urb *wurb = urb->hcpriv; struct whc_urb *wurb = urb->hcpriv;
struct whc_qset *qset = wurb->qset; struct whc_qset *qset = wurb->qset;
struct whc_std *std, *t; struct whc_std *std, *t;
bool has_qtd = false;
int ret; int ret;
unsigned long flags; unsigned long flags;
@ -315,17 +320,21 @@ int asl_urb_dequeue(struct whc *whc, struct urb *urb, int status)
goto out; goto out;
list_for_each_entry_safe(std, t, &qset->stds, list_node) { list_for_each_entry_safe(std, t, &qset->stds, list_node) {
if (std->urb == urb) if (std->urb == urb) {
if (std->qtd)
has_qtd = true;
qset_free_std(whc, std); qset_free_std(whc, std);
else } else
std->qtd = NULL; /* so this std is re-added when the qset is */ std->qtd = NULL; /* so this std is re-added when the qset is */
} }
asl_qset_remove(whc, qset); if (has_qtd) {
wurb->status = status; asl_qset_remove(whc, qset);
wurb->is_async = true; wurb->status = status;
queue_work(whc->workqueue, &wurb->dequeue_work); wurb->is_async = true;
queue_work(whc->workqueue, &wurb->dequeue_work);
} else
qset_remove_urb(whc, qset, urb, status);
out: out:
spin_unlock_irqrestore(&whc->lock, flags); spin_unlock_irqrestore(&whc->lock, flags);

View File

@ -121,6 +121,10 @@ static enum whc_update pzl_process_qset(struct whc *whc, struct whc_qset *qset)
if (status & QTD_STS_HALTED) { if (status & QTD_STS_HALTED) {
/* Ug, an error. */ /* Ug, an error. */
process_halted_qtd(whc, qset, td); process_halted_qtd(whc, qset, td);
/* A halted qTD always triggers an update
because the qset was either removed or
reactivated. */
update |= WHC_UPDATE_UPDATED;
goto done; goto done;
} }
@ -333,6 +337,7 @@ int pzl_urb_dequeue(struct whc *whc, struct urb *urb, int status)
struct whc_urb *wurb = urb->hcpriv; struct whc_urb *wurb = urb->hcpriv;
struct whc_qset *qset = wurb->qset; struct whc_qset *qset = wurb->qset;
struct whc_std *std, *t; struct whc_std *std, *t;
bool has_qtd = false;
int ret; int ret;
unsigned long flags; unsigned long flags;
@ -343,17 +348,22 @@ int pzl_urb_dequeue(struct whc *whc, struct urb *urb, int status)
goto out; goto out;
list_for_each_entry_safe(std, t, &qset->stds, list_node) { list_for_each_entry_safe(std, t, &qset->stds, list_node) {
if (std->urb == urb) if (std->urb == urb) {
if (std->qtd)
has_qtd = true;
qset_free_std(whc, std); qset_free_std(whc, std);
else } else
std->qtd = NULL; /* so this std is re-added when the qset is */ std->qtd = NULL; /* so this std is re-added when the qset is */
} }
pzl_qset_remove(whc, qset); if (has_qtd) {
wurb->status = status; pzl_qset_remove(whc, qset);
wurb->is_async = false; update_pzl_hw_view(whc);
queue_work(whc->workqueue, &wurb->dequeue_work); wurb->status = status;
wurb->is_async = false;
queue_work(whc->workqueue, &wurb->dequeue_work);
} else
qset_remove_urb(whc, qset, urb, status);
out: out:
spin_unlock_irqrestore(&whc->lock, flags); spin_unlock_irqrestore(&whc->lock, flags);

View File

@ -328,6 +328,9 @@ static int option_resume(struct usb_serial *serial);
#define ALCATEL_VENDOR_ID 0x1bbb #define ALCATEL_VENDOR_ID 0x1bbb
#define ALCATEL_PRODUCT_X060S 0x0000 #define ALCATEL_PRODUCT_X060S 0x0000
/* Airplus products */
#define AIRPLUS_VENDOR_ID 0x1011
#define AIRPLUS_PRODUCT_MCD650 0x3198
static struct usb_device_id option_ids[] = { static struct usb_device_id option_ids[] = {
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
@ -589,6 +592,7 @@ static struct usb_device_id option_ids[] = {
{ USB_DEVICE(ALINK_VENDOR_ID, 0x9000) }, { USB_DEVICE(ALINK_VENDOR_ID, 0x9000) },
{ USB_DEVICE_AND_INTERFACE_INFO(ALINK_VENDOR_ID, ALINK_PRODUCT_3GU, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ALINK_VENDOR_ID, ALINK_PRODUCT_3GU, 0xff, 0xff, 0xff) },
{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S) }, { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S) },
{ USB_DEVICE(AIRPLUS_VENDOR_ID, AIRPLUS_PRODUCT_MCD650) },
{ } /* Terminating entry */ { } /* Terminating entry */
}; };
MODULE_DEVICE_TABLE(usb, option_ids); MODULE_DEVICE_TABLE(usb, option_ids);

View File

@ -696,7 +696,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
/* device supports and needs bigger sense buffer */ /* device supports and needs bigger sense buffer */
if (us->fflags & US_FL_SANE_SENSE) if (us->fflags & US_FL_SANE_SENSE)
sense_size = ~0; sense_size = ~0;
Retry_Sense:
US_DEBUGP("Issuing auto-REQUEST_SENSE\n"); US_DEBUGP("Issuing auto-REQUEST_SENSE\n");
scsi_eh_prep_cmnd(srb, &ses, NULL, 0, sense_size); scsi_eh_prep_cmnd(srb, &ses, NULL, 0, sense_size);
@ -720,6 +720,21 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
srb->result = DID_ABORT << 16; srb->result = DID_ABORT << 16;
goto Handle_Errors; goto Handle_Errors;
} }
/* Some devices claim to support larger sense but fail when
* trying to request it. When a transport failure happens
* using US_FS_SANE_SENSE, we always retry with a standard
* (small) sense request. This fixes some USB GSM modems
*/
if (temp_result == USB_STOR_TRANSPORT_FAILED &&
(us->fflags & US_FL_SANE_SENSE) &&
sense_size != US_SENSE_SIZE) {
US_DEBUGP("-- auto-sense failure, retry small sense\n");
sense_size = US_SENSE_SIZE;
goto Retry_Sense;
}
/* Other failures */
if (temp_result != USB_STOR_TRANSPORT_GOOD) { if (temp_result != USB_STOR_TRANSPORT_GOOD) {
US_DEBUGP("-- auto-sense failure\n"); US_DEBUGP("-- auto-sense failure\n");

View File

@ -200,35 +200,40 @@ int wusb_dev_sec_add(struct wusbhc *wusbhc,
{ {
int result, bytes, secd_size; int result, bytes, secd_size;
struct device *dev = &usb_dev->dev; struct device *dev = &usb_dev->dev;
struct usb_security_descriptor secd; struct usb_security_descriptor *secd;
const struct usb_encryption_descriptor *etd, *ccm1_etd = NULL; const struct usb_encryption_descriptor *etd, *ccm1_etd = NULL;
void *secd_buf;
const void *itr, *top; const void *itr, *top;
char buf[64]; char buf[64];
secd = kmalloc(sizeof(struct usb_security_descriptor), GFP_KERNEL);
if (secd == NULL) {
result = -ENOMEM;
goto out;
}
result = usb_get_descriptor(usb_dev, USB_DT_SECURITY, result = usb_get_descriptor(usb_dev, USB_DT_SECURITY,
0, &secd, sizeof(secd)); 0, secd, sizeof(struct usb_security_descriptor));
if (result < sizeof(secd)) { if (result < sizeof(secd)) {
dev_err(dev, "Can't read security descriptor or " dev_err(dev, "Can't read security descriptor or "
"not enough data: %d\n", result); "not enough data: %d\n", result);
goto error_secd; goto out;
} }
secd_size = le16_to_cpu(secd.wTotalLength); secd_size = le16_to_cpu(secd->wTotalLength);
secd_buf = kmalloc(secd_size, GFP_KERNEL); secd = krealloc(secd, secd_size, GFP_KERNEL);
if (secd_buf == NULL) { if (secd == NULL) {
dev_err(dev, "Can't allocate space for security descriptors\n"); dev_err(dev, "Can't allocate space for security descriptors\n");
goto error_secd_alloc; goto out;
} }
result = usb_get_descriptor(usb_dev, USB_DT_SECURITY, result = usb_get_descriptor(usb_dev, USB_DT_SECURITY,
0, secd_buf, secd_size); 0, secd, secd_size);
if (result < secd_size) { if (result < secd_size) {
dev_err(dev, "Can't read security descriptor or " dev_err(dev, "Can't read security descriptor or "
"not enough data: %d\n", result); "not enough data: %d\n", result);
goto error_secd_all; goto out;
} }
bytes = 0; bytes = 0;
itr = secd_buf + sizeof(secd); itr = &secd[1];
top = secd_buf + result; top = (void *)secd + result;
while (itr < top) { while (itr < top) {
etd = itr; etd = itr;
if (top - itr < sizeof(*etd)) { if (top - itr < sizeof(*etd)) {
@ -259,24 +264,16 @@ int wusb_dev_sec_add(struct wusbhc *wusbhc,
dev_err(dev, "WUSB device doesn't support CCM1 encryption, " dev_err(dev, "WUSB device doesn't support CCM1 encryption, "
"can't use!\n"); "can't use!\n");
result = -EINVAL; result = -EINVAL;
goto error_no_ccm1; goto out;
} }
wusb_dev->ccm1_etd = *ccm1_etd; wusb_dev->ccm1_etd = *ccm1_etd;
dev_dbg(dev, "supported encryption: %s; using %s (0x%02x/%02x)\n", dev_dbg(dev, "supported encryption: %s; using %s (0x%02x/%02x)\n",
buf, wusb_et_name(ccm1_etd->bEncryptionType), buf, wusb_et_name(ccm1_etd->bEncryptionType),
ccm1_etd->bEncryptionValue, ccm1_etd->bAuthKeyIndex); ccm1_etd->bEncryptionValue, ccm1_etd->bAuthKeyIndex);
result = 0; result = 0;
kfree(secd_buf);
out: out:
kfree(secd);
return result; return result;
error_no_ccm1:
error_secd_all:
kfree(secd_buf);
error_secd_alloc:
error_secd:
goto out;
} }
void wusb_dev_sec_rm(struct wusb_dev *wusb_dev) void wusb_dev_sec_rm(struct wusb_dev *wusb_dev)