aboutsummaryrefslogtreecommitdiffstats
path: root/usb
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@suse.de>2006-03-09 17:34:20 -0800
committerGreg Kroah-Hartman <gregkh@suse.de>2006-03-09 17:34:20 -0800
commit98a563c02de8d4199da0ed1b422d2b5ac93040af (patch)
tree35752a234ce6561e8cf7b7e6a2e5a2f7ac8c809f /usb
parente777bbc09f0785f314aae0367fdc8f9e3e1f28a7 (diff)
downloadpatches-98a563c02de8d4199da0ed1b422d2b5ac93040af.tar.gz
more usb patches
Diffstat (limited to 'usb')
-rw-r--r--usb/always-announce-new-usb-devices.patch6
-rw-r--r--usb/usb-ub-01-remove-first_open.patch71
-rw-r--r--usb/usb-ub-02-remove-diag.patch395
-rw-r--r--usb/usb-ub-03-drop-stall-clearing.patch45
-rw-r--r--usb/usb-usbcore-don-t-assume-a-usb-configuration-includes-any-interfaces.patch66
-rw-r--r--usb/usb-usbcore-usb_set_configuration-oops.patch43
6 files changed, 623 insertions, 3 deletions
diff --git a/usb/always-announce-new-usb-devices.patch b/usb/always-announce-new-usb-devices.patch
index 87fc956b748fa6..d3e74cc6260fff 100644
--- a/usb/always-announce-new-usb-devices.patch
+++ b/usb/always-announce-new-usb-devices.patch
@@ -14,7 +14,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
--- gregkh-2.6.orig/drivers/usb/core/hub.c
+++ gregkh-2.6/drivers/usb/core/hub.c
-@@ -1257,7 +1257,6 @@ static int choose_configuration(struct u
+@@ -1261,7 +1261,6 @@ static int choose_configuration(struct u
return i;
}
@@ -22,7 +22,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
static void show_string(struct usb_device *udev, char *id, char *string)
{
if (!string)
-@@ -1265,10 +1264,6 @@ static void show_string(struct usb_devic
+@@ -1269,10 +1268,6 @@ static void show_string(struct usb_devic
dev_printk(KERN_INFO, &udev->dev, "%s: %s\n", id, string);
}
@@ -33,7 +33,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
#ifdef CONFIG_USB_OTG
-@@ -1313,7 +1308,10 @@ int usb_new_device(struct usb_device *ud
+@@ -1317,7 +1312,10 @@ int usb_new_device(struct usb_device *ud
udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
/* Tell the world! */
diff --git a/usb/usb-ub-01-remove-first_open.patch b/usb/usb-ub-01-remove-first_open.patch
new file mode 100644
index 00000000000000..494b3f51bba3b0
--- /dev/null
+++ b/usb/usb-ub-01-remove-first_open.patch
@@ -0,0 +1,71 @@
+From zaitcev@redhat.com Thu Mar 2 16:36:30 2006
+Date: Thu, 2 Mar 2006 16:36:09 -0800
+From: Pete Zaitcev <zaitcev@redhat.com>
+To: greg@kroah.com
+Cc: zaitcev@redhat.com, linux-usb-devel@lists.sourceforge.net
+Subject: USB: ub 01 remove first_open
+Message-Id: <20060302163609.21b4236a.zaitcev@redhat.com>
+
+The first_open was long overdue for removal, but I wanted to keep this
+separate for other changes in case of regressions.
+
+Signed-off-by: Pete Zaitcev <zaitcev@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/block/ub.c | 23 -----------------------
+ 1 file changed, 23 deletions(-)
+
+--- gregkh-2.6.orig/drivers/block/ub.c
++++ gregkh-2.6/drivers/block/ub.c
+@@ -8,7 +8,6 @@
+ * and is not licensed separately. See file COPYING for details.
+ *
+ * TODO (sorted by decreasing priority)
+- * -- Kill first_open (Al Viro fixed the block layer now)
+ * -- set readonly flag for CDs, set removable flag for CF readers
+ * -- do inquiry and verify we got a disk and not a tape (for LUN mismatch)
+ * -- special case some senses, e.g. 3a/0 -> no media present, reduce retries
+@@ -334,7 +333,6 @@ struct ub_lun {
+ int changed; /* Media was changed */
+ int removable;
+ int readonly;
+- int first_open; /* Kludge. See ub_bd_open. */
+
+ struct ub_request urq;
+
+@@ -1849,26 +1847,6 @@ static int ub_bd_open(struct inode *inod
+ sc->openc++;
+ spin_unlock_irqrestore(&ub_lock, flags);
+
+- /*
+- * This is a workaround for a specific problem in our block layer.
+- * In 2.6.9, register_disk duplicates the code from rescan_partitions.
+- * However, if we do add_disk with a device which persistently reports
+- * a changed media, add_disk calls register_disk, which does do_open,
+- * which will call rescan_paritions for changed media. After that,
+- * register_disk attempts to do it all again and causes double kobject
+- * registration and a eventually an oops on module removal.
+- *
+- * The bottom line is, Al Viro says that we should not allow
+- * bdev->bd_invalidated to be set when doing add_disk no matter what.
+- */
+- if (lun->first_open) {
+- lun->first_open = 0;
+- if (lun->changed) {
+- rc = -ENOMEDIUM;
+- goto err_open;
+- }
+- }
+-
+ if (lun->removable || lun->readonly)
+ check_disk_change(inode->i_bdev);
+
+@@ -2537,7 +2515,6 @@ static int ub_probe_lun(struct ub_dev *s
+
+ lun->removable = 1; /* XXX Query this from the device */
+ lun->changed = 1; /* ub_revalidate clears only */
+- lun->first_open = 1;
+ ub_revalidate(sc, lun);
+
+ rc = -ENOMEM;
diff --git a/usb/usb-ub-02-remove-diag.patch b/usb/usb-ub-02-remove-diag.patch
new file mode 100644
index 00000000000000..85b976ec588306
--- /dev/null
+++ b/usb/usb-ub-02-remove-diag.patch
@@ -0,0 +1,395 @@
+From zaitcev@redhat.com Thu Mar 2 16:43:23 2006
+Date: Thu, 2 Mar 2006 16:42:59 -0800
+From: Pete Zaitcev <zaitcev@redhat.com>
+To: greg@kroah.com
+Cc: zaitcev@redhat.com, linux-usb-devel@lists.sourceforge.net, viro@www.linux.org.uk
+Subject: USB: ub 02 remove diag
+Message-Id: <20060302164259.095ab85b.zaitcev@redhat.com>
+
+Remove the "diag" file from the sysfs. The usbmon is good enough these days
+so I do not need this feature anymore. Also, sysfs is a pain. Al Viro caught
+a race in this, which I thought too bothersome to fix.
+
+Signed-off-by: Pete Zaitcev <zaitcev@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/block/ub.c | 197 +----------------------------------------------------
+ 1 file changed, 4 insertions(+), 193 deletions(-)
+
+--- gregkh-2.6.orig/drivers/block/ub.c
++++ gregkh-2.6/drivers/block/ub.c
+@@ -180,6 +180,7 @@ struct ub_dev;
+ #define UB_DIR_ILLEGAL2 2
+ #define UB_DIR_WRITE 3
+
++/* P3 */
+ #define UB_DIR_CHAR(c) (((c)==UB_DIR_WRITE)? 'w': \
+ (((c)==UB_DIR_READ)? 'r': 'n'))
+
+@@ -195,24 +196,11 @@ enum ub_scsi_cmd_state {
+ UB_CMDST_DONE /* Final state */
+ };
+
+-static char *ub_scsi_cmd_stname[] = {
+- ". ",
+- "Cmd",
+- "dat",
+- "c2s",
+- "sts",
+- "clr",
+- "crs",
+- "Sen",
+- "fin"
+-};
+-
+ struct ub_scsi_cmd {
+ unsigned char cdb[UB_MAX_CDB_SIZE];
+ unsigned char cdb_len;
+
+ unsigned char dir; /* 0 - none, 1 - read, 3 - write. */
+- unsigned char trace_index;
+ enum ub_scsi_cmd_state state;
+ unsigned int tag;
+ struct ub_scsi_cmd *next;
+@@ -249,28 +237,6 @@ struct ub_capacity {
+ };
+
+ /*
+- * The SCSI command tracing structure.
+- */
+-
+-#define SCMD_ST_HIST_SZ 8
+-#define SCMD_TRACE_SZ 63 /* Less than 4KB of 61-byte lines */
+-
+-struct ub_scsi_cmd_trace {
+- int hcur;
+- unsigned int tag;
+- unsigned int req_size, act_size;
+- unsigned char op;
+- unsigned char dir;
+- unsigned char key, asc, ascq;
+- char st_hst[SCMD_ST_HIST_SZ];
+-};
+-
+-struct ub_scsi_trace {
+- int cur;
+- struct ub_scsi_cmd_trace vec[SCMD_TRACE_SZ];
+-};
+-
+-/*
+ * This is a direct take-off from linux/include/completion.h
+ * The difference is that I do not wait on this thing, just poll.
+ * When I want to wait (ub_probe), I just use the stock completion.
+@@ -388,7 +354,6 @@ struct ub_dev {
+ wait_queue_head_t reset_wait;
+
+ int sg_stat[6];
+- struct ub_scsi_trace tr;
+ };
+
+ /*
+@@ -458,137 +423,6 @@ static int ub_qlock_next = 0;
+ static DEFINE_SPINLOCK(ub_lock); /* Locks globals and ->openc */
+
+ /*
+- * The SCSI command tracing procedures.
+- */
+-
+-static void ub_cmdtr_new(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
+-{
+- int n;
+- struct ub_scsi_cmd_trace *t;
+-
+- if ((n = sc->tr.cur + 1) == SCMD_TRACE_SZ) n = 0;
+- t = &sc->tr.vec[n];
+-
+- memset(t, 0, sizeof(struct ub_scsi_cmd_trace));
+- t->tag = cmd->tag;
+- t->op = cmd->cdb[0];
+- t->dir = cmd->dir;
+- t->req_size = cmd->len;
+- t->st_hst[0] = cmd->state;
+-
+- sc->tr.cur = n;
+- cmd->trace_index = n;
+-}
+-
+-static void ub_cmdtr_state(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
+-{
+- int n;
+- struct ub_scsi_cmd_trace *t;
+-
+- t = &sc->tr.vec[cmd->trace_index];
+- if (t->tag == cmd->tag) {
+- if ((n = t->hcur + 1) == SCMD_ST_HIST_SZ) n = 0;
+- t->st_hst[n] = cmd->state;
+- t->hcur = n;
+- }
+-}
+-
+-static void ub_cmdtr_act_len(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
+-{
+- struct ub_scsi_cmd_trace *t;
+-
+- t = &sc->tr.vec[cmd->trace_index];
+- if (t->tag == cmd->tag)
+- t->act_size = cmd->act_len;
+-}
+-
+-static void ub_cmdtr_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
+- unsigned char *sense)
+-{
+- struct ub_scsi_cmd_trace *t;
+-
+- t = &sc->tr.vec[cmd->trace_index];
+- if (t->tag == cmd->tag) {
+- t->key = sense[2] & 0x0F;
+- t->asc = sense[12];
+- t->ascq = sense[13];
+- }
+-}
+-
+-static ssize_t ub_diag_show(struct device *dev, struct device_attribute *attr,
+- char *page)
+-{
+- struct usb_interface *intf;
+- struct ub_dev *sc;
+- struct list_head *p;
+- struct ub_lun *lun;
+- int cnt;
+- unsigned long flags;
+- int nc, nh;
+- int i, j;
+- struct ub_scsi_cmd_trace *t;
+-
+- intf = to_usb_interface(dev);
+- sc = usb_get_intfdata(intf);
+- if (sc == NULL)
+- return 0;
+-
+- cnt = 0;
+- spin_lock_irqsave(sc->lock, flags);
+-
+- cnt += sprintf(page + cnt,
+- "poison %d reset %d\n",
+- atomic_read(&sc->poison), sc->reset);
+- cnt += sprintf(page + cnt,
+- "qlen %d qmax %d\n",
+- sc->cmd_queue.qlen, sc->cmd_queue.qmax);
+- cnt += sprintf(page + cnt,
+- "sg %d %d %d %d %d .. %d\n",
+- sc->sg_stat[0],
+- sc->sg_stat[1],
+- sc->sg_stat[2],
+- sc->sg_stat[3],
+- sc->sg_stat[4],
+- sc->sg_stat[5]);
+-
+- list_for_each (p, &sc->luns) {
+- lun = list_entry(p, struct ub_lun, link);
+- cnt += sprintf(page + cnt,
+- "lun %u changed %d removable %d readonly %d\n",
+- lun->num, lun->changed, lun->removable, lun->readonly);
+- }
+-
+- if ((nc = sc->tr.cur + 1) == SCMD_TRACE_SZ) nc = 0;
+- for (j = 0; j < SCMD_TRACE_SZ; j++) {
+- t = &sc->tr.vec[nc];
+-
+- cnt += sprintf(page + cnt, "%08x %02x", t->tag, t->op);
+- if (t->op == REQUEST_SENSE) {
+- cnt += sprintf(page + cnt, " [sense %x %02x %02x]",
+- t->key, t->asc, t->ascq);
+- } else {
+- cnt += sprintf(page + cnt, " %c", UB_DIR_CHAR(t->dir));
+- cnt += sprintf(page + cnt, " [%5d %5d]",
+- t->req_size, t->act_size);
+- }
+- if ((nh = t->hcur + 1) == SCMD_ST_HIST_SZ) nh = 0;
+- for (i = 0; i < SCMD_ST_HIST_SZ; i++) {
+- cnt += sprintf(page + cnt, " %s",
+- ub_scsi_cmd_stname[(int)t->st_hst[nh]]);
+- if (++nh == SCMD_ST_HIST_SZ) nh = 0;
+- }
+- cnt += sprintf(page + cnt, "\n");
+-
+- if (++nc == SCMD_TRACE_SZ) nc = 0;
+- }
+-
+- spin_unlock_irqrestore(sc->lock, flags);
+- return cnt;
+-}
+-
+-static DEVICE_ATTR(diag, S_IRUGO, ub_diag_show, NULL); /* N.B. World readable */
+-
+-/*
+ * The id allocator.
+ *
+ * This also stores the host for indexing by minor, which is somewhat dirty.
+@@ -1090,7 +924,6 @@ static int ub_scsi_cmd_start(struct ub_d
+ add_timer(&sc->work_timer);
+
+ cmd->state = UB_CMDST_CMD;
+- ub_cmdtr_state(sc, cmd);
+ return 0;
+ }
+
+@@ -1143,12 +976,10 @@ static void ub_scsi_dispatch(struct ub_d
+ ub_cmdq_pop(sc);
+ (*cmd->done)(sc, cmd);
+ } else if (cmd->state == UB_CMDST_INIT) {
+- ub_cmdtr_new(sc, cmd);
+ if ((rc = ub_scsi_cmd_start(sc, cmd)) == 0)
+ break;
+ cmd->error = rc;
+ cmd->state = UB_CMDST_DONE;
+- ub_cmdtr_state(sc, cmd);
+ } else {
+ if (!ub_is_completed(&sc->work_done))
+ break;
+@@ -1245,7 +1076,6 @@ static void ub_scsi_urb_compl(struct ub_
+ return;
+ }
+ cmd->state = UB_CMDST_CLEAR;
+- ub_cmdtr_state(sc, cmd);
+ return;
+ case -ESHUTDOWN: /* unplug */
+ case -EILSEQ: /* unplug timeout on uhci */
+@@ -1277,7 +1107,6 @@ static void ub_scsi_urb_compl(struct ub_
+ return;
+ }
+ cmd->state = UB_CMDST_CLR2STS;
+- ub_cmdtr_state(sc, cmd);
+ return;
+ }
+ if (urb->status == -EOVERFLOW) {
+@@ -1302,7 +1131,6 @@ static void ub_scsi_urb_compl(struct ub_
+ if (urb->status != 0 ||
+ len != cmd->sgv[cmd->current_sg].length) {
+ cmd->act_len += len;
+- ub_cmdtr_act_len(sc, cmd);
+
+ cmd->error = -EIO;
+ ub_state_stat(sc, cmd);
+@@ -1329,7 +1157,6 @@ static void ub_scsi_urb_compl(struct ub_
+ }
+
+ cmd->act_len += urb->actual_length;
+- ub_cmdtr_act_len(sc, cmd);
+
+ if (++cmd->current_sg < cmd->nsg) {
+ ub_data_start(sc, cmd);
+@@ -1355,7 +1182,6 @@ static void ub_scsi_urb_compl(struct ub_
+ cmd->error = -EIO; /* A cheap trick... */
+
+ cmd->state = UB_CMDST_CLRRS;
+- ub_cmdtr_state(sc, cmd);
+ return;
+ }
+
+@@ -1439,7 +1265,6 @@ static void ub_scsi_urb_compl(struct ub_
+ return;
+ }
+ cmd->state = UB_CMDST_DONE;
+- ub_cmdtr_state(sc, cmd);
+ ub_cmdq_pop(sc);
+ (*cmd->done)(sc, cmd);
+
+@@ -1494,7 +1319,6 @@ static void ub_data_start(struct ub_dev
+ add_timer(&sc->work_timer);
+
+ cmd->state = UB_CMDST_DATA;
+- ub_cmdtr_state(sc, cmd);
+ }
+
+ /*
+@@ -1506,7 +1330,6 @@ static void ub_state_done(struct ub_dev
+
+ cmd->error = rc;
+ cmd->state = UB_CMDST_DONE;
+- ub_cmdtr_state(sc, cmd);
+ ub_cmdq_pop(sc);
+ (*cmd->done)(sc, cmd);
+ }
+@@ -1552,7 +1375,6 @@ static void ub_state_stat(struct ub_dev
+
+ cmd->stat_count = 0;
+ cmd->state = UB_CMDST_STAT;
+- ub_cmdtr_state(sc, cmd);
+ }
+
+ /*
+@@ -1571,7 +1393,6 @@ static void ub_state_stat_counted(struct
+ return;
+
+ cmd->state = UB_CMDST_STAT;
+- ub_cmdtr_state(sc, cmd);
+ }
+
+ /*
+@@ -1609,7 +1430,6 @@ static void ub_state_sense(struct ub_dev
+ scmd->tag = sc->tagcnt++;
+
+ cmd->state = UB_CMDST_SENSE;
+- ub_cmdtr_state(sc, cmd);
+
+ ub_cmdq_insert(sc, scmd);
+ return;
+@@ -1666,11 +1486,6 @@ static void ub_top_sense_done(struct ub_
+ struct ub_scsi_cmd *cmd;
+
+ /*
+- * Ignoring scmd->act_len, because the buffer was pre-zeroed.
+- */
+- ub_cmdtr_sense(sc, scmd, sense);
+-
+- /*
+ * Find the command which triggered the unit attention or a check,
+ * save the sense into it, and advance its state machine.
+ */
+@@ -1691,6 +1506,9 @@ static void ub_top_sense_done(struct ub_
+ return;
+ }
+
++ /*
++ * Ignoring scmd->act_len, because the buffer was pre-zeroed.
++ */
+ cmd->key = sense[2] & 0x0F;
+ cmd->asc = sense[12];
+ cmd->ascq = sense[13];
+@@ -2413,9 +2231,6 @@ static int ub_probe(struct usb_interface
+ if (ub_get_pipes(sc, sc->dev, intf) != 0)
+ goto err_dev_desc;
+
+- if (device_create_file(&sc->intf->dev, &dev_attr_diag) != 0)
+- goto err_diag;
+-
+ /*
+ * At this point, all USB initialization is done, do upper layer.
+ * We really hate halfway initialized structures, so from the
+@@ -2480,8 +2295,6 @@ static int ub_probe(struct usb_interface
+ }
+ return 0;
+
+- /* device_remove_file(&sc->intf->dev, &dev_attr_diag); */
+-err_diag:
+ err_dev_desc:
+ usb_set_intfdata(intf, NULL);
+ // usb_put_intf(sc->intf);
+@@ -2609,7 +2422,6 @@ static void ub_disconnect(struct usb_int
+ while ((cmd = ub_cmdq_peek(sc)) != NULL) {
+ cmd->error = -ENOTCONN;
+ cmd->state = UB_CMDST_DONE;
+- ub_cmdtr_state(sc, cmd);
+ ub_cmdq_pop(sc);
+ (*cmd->done)(sc, cmd);
+ cnt++;
+@@ -2660,7 +2472,6 @@ static void ub_disconnect(struct usb_int
+ * and no URBs left in transit.
+ */
+
+- device_remove_file(&sc->intf->dev, &dev_attr_diag);
+ usb_set_intfdata(intf, NULL);
+ // usb_put_intf(sc->intf);
+ sc->intf = NULL;
diff --git a/usb/usb-ub-03-drop-stall-clearing.patch b/usb/usb-ub-03-drop-stall-clearing.patch
new file mode 100644
index 00000000000000..8f98647bb621b7
--- /dev/null
+++ b/usb/usb-ub-03-drop-stall-clearing.patch
@@ -0,0 +1,45 @@
+From zaitcev@redhat.com Thu Mar 2 16:53:17 2006
+Date: Thu, 2 Mar 2006 16:53:00 -0800
+From: Pete Zaitcev <zaitcev@redhat.com>
+To: greg@kroah.com
+Cc: zaitcev@redhat.com, linux-usb-devel@lists.sourceforge.net
+Subject: USB: ub 03 drop stall clearing
+Message-Id: <20060302165300.211eb11c.zaitcev@redhat.com>
+
+Matt mentioned that a very old ZIP-100 actually does need this, but I am
+yet to see anyone who actually has one still working and uses ub with it.
+He/she must be a retrocomputing geek, who can easily bias it to usb-storage
+with libusual, if needed. Meanwhile, common folks have trouble with poorly
+designed USB keys and some el-cheapo European music players. I think we
+better drop this for now.
+
+Signed-off-by: Pete Zaitcev <zaitcev@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/block/ub.c | 13 +------------
+ 1 file changed, 1 insertion(+), 12 deletions(-)
+
+--- gregkh-2.6.orig/drivers/block/ub.c
++++ gregkh-2.6/drivers/block/ub.c
+@@ -2270,19 +2270,8 @@ static int ub_probe(struct usb_interface
+
+ nluns = 1;
+ for (i = 0; i < 3; i++) {
+- if ((rc = ub_sync_getmaxlun(sc)) < 0) {
+- /*
+- * This segment is taken from usb-storage. They say
+- * that ZIP-100 needs this, but my own ZIP-100 works
+- * fine without this.
+- * Still, it does not seem to hurt anything.
+- */
+- if (rc == -EPIPE) {
+- ub_probe_clear_stall(sc, sc->recv_bulk_pipe);
+- ub_probe_clear_stall(sc, sc->send_bulk_pipe);
+- }
++ if ((rc = ub_sync_getmaxlun(sc)) < 0)
+ break;
+- }
+ if (rc != 0) {
+ nluns = rc;
+ break;
diff --git a/usb/usb-usbcore-don-t-assume-a-usb-configuration-includes-any-interfaces.patch b/usb/usb-usbcore-don-t-assume-a-usb-configuration-includes-any-interfaces.patch
new file mode 100644
index 00000000000000..87289923538524
--- /dev/null
+++ b/usb/usb-usbcore-don-t-assume-a-usb-configuration-includes-any-interfaces.patch
@@ -0,0 +1,66 @@
+From stern@rowland.harvard.edu Wed Mar 8 12:14:14 2006
+Date: Wed, 8 Mar 2006 15:14:09 -0500 (EST)
+From: Alan Stern <stern@rowland.harvard.edu>
+To: David Brownell <david-b@pacbell.net>
+cc: Greg KH <greg@kroah.com>, Andrew Morton <akpm@osdl.org>, Linus Torvalds <torvalds@osdl.org>, <mingo@elte.hu>
+Subject: USB: usbcore: Don't assume a USB configuration includes any interfaces
+Message-ID: <Pine.LNX.4.44L0.0603081509100.5360-100000@iolanthe.rowland.org>
+
+In a couple of places, usbcore assumes that a USB device configuration
+will have a nonzero number of interfaces. Having no interfaces may or
+may not be allowed by the USB spec; in any event we shouldn't die if we
+encounter such a thing. This patch (as662) removes the assumptions.
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/core/hub.c | 16 ++++++++++------
+ 1 file changed, 10 insertions(+), 6 deletions(-)
+
+--- gregkh-2.6.orig/drivers/usb/core/hub.c
++++ gregkh-2.6/drivers/usb/core/hub.c
+@@ -1179,8 +1179,11 @@ static int choose_configuration(struct u
+ c = udev->config;
+ num_configs = udev->descriptor.bNumConfigurations;
+ for (i = 0; i < num_configs; (i++, c++)) {
+- struct usb_interface_descriptor *desc =
+- &c->intf_cache[0]->altsetting->desc;
++ struct usb_interface_descriptor *desc = NULL;
++
++ /* It's possible that a config has no interfaces! */
++ if (c->desc.bNumInterfaces > 0)
++ desc = &c->intf_cache[0]->altsetting->desc;
+
+ /*
+ * HP's USB bus-powered keyboard has only one configuration
+@@ -1215,7 +1218,8 @@ static int choose_configuration(struct u
+ /* If the first config's first interface is COMM/2/0xff
+ * (MSFT RNDIS), rule it out unless Linux has host-side
+ * RNDIS support. */
+- if (i == 0 && desc->bInterfaceClass == USB_CLASS_COMM
++ if (i == 0 && desc
++ && desc->bInterfaceClass == USB_CLASS_COMM
+ && desc->bInterfaceSubClass == 2
+ && desc->bInterfaceProtocol == 0xff) {
+ #ifndef CONFIG_USB_NET_RNDIS
+@@ -1231,8 +1235,8 @@ static int choose_configuration(struct u
+ * than a vendor-specific driver. */
+ else if (udev->descriptor.bDeviceClass !=
+ USB_CLASS_VENDOR_SPEC &&
+- desc->bInterfaceClass !=
+- USB_CLASS_VENDOR_SPEC) {
++ (!desc || desc->bInterfaceClass !=
++ USB_CLASS_VENDOR_SPEC)) {
+ best = c;
+ break;
+ }
+@@ -3024,7 +3028,7 @@ int usb_reset_device(struct usb_device *
+ parent_hub = hdev_to_hub(parent_hdev);
+
+ /* If we're resetting an active hub, take some special actions */
+- if (udev->actconfig &&
++ if (udev->actconfig && udev->actconfig->desc.bNumInterfaces > 0 &&
+ udev->actconfig->interface[0]->dev.driver ==
+ &hub_driver.driver &&
+ (hub = hdev_to_hub(udev)) != NULL) {
diff --git a/usb/usb-usbcore-usb_set_configuration-oops.patch b/usb/usb-usbcore-usb_set_configuration-oops.patch
new file mode 100644
index 00000000000000..057dfe1016baaa
--- /dev/null
+++ b/usb/usb-usbcore-usb_set_configuration-oops.patch
@@ -0,0 +1,43 @@
+From horst@schirmeier.com Thu Mar 9 05:10:56 2006
+Date: Thu, 9 Mar 2006 14:10:49 +0100
+From: Horst Schirmeier <horst@schirmeier.com>
+To: Alan Stern <stern@rowland.harvard.edu>
+Cc: Greg KH <greg@kroah.com>
+Subject: USB: usbcore: usb_set_configuration oops (NULL ptr dereference)
+Message-ID: <20060309131048.GL22994@quickstop.soohrt.org>
+Content-Disposition: inline
+
+When trying to deconfigure a device via usb_set_configuration(dev, 0),
+2.6.16-rc kernels after 55c527187c9d78f840b284d596a0b298bc1493af oops
+with "Unable to handle NULL pointer dereference at...". This is due to
+an unchecked dereference of cp in the power budget part.
+
+Signed-off-by: Horst Schirmeier <horst@schirmeier.com>
+Acked-by: Alan Stern <stern@rowland.harvard.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/core/message.c | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+--- gregkh-2.6.orig/drivers/usb/core/message.c
++++ gregkh-2.6/drivers/usb/core/message.c
+@@ -1388,11 +1388,13 @@ free_interfaces:
+ if (dev->state != USB_STATE_ADDRESS)
+ usb_disable_device (dev, 1); // Skip ep0
+
+- i = dev->bus_mA - cp->desc.bMaxPower * 2;
+- if (i < 0)
+- dev_warn(&dev->dev, "new config #%d exceeds power "
+- "limit by %dmA\n",
+- configuration, -i);
++ if (cp) {
++ i = dev->bus_mA - cp->desc.bMaxPower * 2;
++ if (i < 0)
++ dev_warn(&dev->dev, "new config #%d exceeds power "
++ "limit by %dmA\n",
++ configuration, -i);
++ }
+
+ if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_SET_CONFIGURATION, 0, configuration, 0,