diff options
author | Greg Kroah-Hartman <gregkh@suse.de> | 2011-05-30 14:13:32 +0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-05-30 14:13:32 +0800 |
commit | c7b7dc719d3c3184794f5419ca4074ee998f0ec1 (patch) | |
tree | 111fca1f67ae56ac9e17a91c74ff13cd4570a16f | |
parent | 1c258d2c9ace09fd43430a15b5f715d0849886a1 (diff) | |
download | stable-queue-c7b7dc719d3c3184794f5419ca4074ee998f0ec1.tar.gz |
.39 patches
27 files changed, 2968 insertions, 0 deletions
diff --git a/queue-2.6.39/bind-only-modem-at-command-endpoint-to-option-module.patch b/queue-2.6.39/bind-only-modem-at-command-endpoint-to-option-module.patch new file mode 100644 index 0000000000..82a6cd4a1b --- /dev/null +++ b/queue-2.6.39/bind-only-modem-at-command-endpoint-to-option-module.patch @@ -0,0 +1,44 @@ +From 15b2f3204a5c878c32939094775fb7349f707263 Mon Sep 17 00:00:00 2001 +From: "Marius B. Kotsbak" <marius@kotsbak.com> +Date: Mon, 21 Mar 2011 23:27:21 +0100 +Subject: Bind only modem AT command endpoint to option module. + +From: "Marius B. Kotsbak" <marius@kotsbak.com> + +commit 15b2f3204a5c878c32939094775fb7349f707263 upstream. + +Network interface is handled by upcoming gt_b3730 module. + +Removed "GT-B3710" from comment, it is another modem with another USB ID. + +Signed-off-by: Marius B. Kotsbak <marius@kotsbak.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/serial/option.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +--- a/drivers/usb/serial/option.c ++++ b/drivers/usb/serial/option.c +@@ -972,7 +972,7 @@ static const struct usb_device_id option + { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100) }, + { 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_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_GT_B3730, USB_CLASS_CDC_DATA, 0x00, 0x00) }, /* Samsung GT-B3730/GT-B3710 LTE USB modem.*/ ++ { USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_GT_B3730, USB_CLASS_CDC_DATA, 0x00, 0x00) }, /* Samsung GT-B3730 LTE USB modem.*/ + { } /* Terminating entry */ + }; + MODULE_DEVICE_TABLE(usb, option_ids); +@@ -1109,6 +1109,12 @@ static int option_probe(struct usb_seria + serial->interface->cur_altsetting->desc.bInterfaceNumber == 1) + return -ENODEV; + ++ /* Don't bind network interface on Samsung GT-B3730, it is handled by a separate module */ ++ if (serial->dev->descriptor.idVendor == SAMSUNG_VENDOR_ID && ++ serial->dev->descriptor.idProduct == SAMSUNG_PRODUCT_GT_B3730 && ++ serial->interface->cur_altsetting->desc.bInterfaceClass != USB_CLASS_CDC_DATA) ++ return -ENODEV; ++ + data = serial->private = kzalloc(sizeof(struct usb_wwan_intf_private), GFP_KERNEL); + + if (!data) diff --git a/queue-2.6.39/cx88-fix-locking-of-sub-driver-operations.patch b/queue-2.6.39/cx88-fix-locking-of-sub-driver-operations.patch new file mode 100644 index 0000000000..610fd58291 --- /dev/null +++ b/queue-2.6.39/cx88-fix-locking-of-sub-driver-operations.patch @@ -0,0 +1,116 @@ +From 1fe70e963028f34ba5e32488a7870ff4b410b19b Mon Sep 17 00:00:00 2001 +From: Jonathan Nieder <jrnieder@gmail.com> +Date: Sun, 1 May 2011 06:29:37 -0300 +Subject: [media] cx88: fix locking of sub-driver operations + +From: Jonathan Nieder <jrnieder@gmail.com> + +commit 1fe70e963028f34ba5e32488a7870ff4b410b19b upstream. + +The BKL conversion of this driver seems to have gone wrong. +Loading the cx88-blackbird driver deadlocks. + +The cause: mpeg_ops::open in the cx2388x blackbird driver acquires the +device lock and calls the sub-driver's request_acquire, which tries to +acquire the lock again. Fix it by clarifying the semantics of +request_acquire, request_release, advise_acquire, and advise_release: +now all will rely on the caller to acquire the device lock. + +Based on work by Ben Hutchings <ben@decadent.org.uk>. + +Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=31962 + +Reported-by: Andi Huber <hobrom@gmx.at> +Tested-by: Andi Huber <hobrom@gmx.at> +Tested-by: Marlon de Boer <marlon@hyves.nl> +Signed-off-by: Jonathan Nieder <jrnieder@gmail.com> +Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/media/video/cx88/cx88-blackbird.c | 4 ++-- + drivers/media/video/cx88/cx88-dvb.c | 3 +-- + drivers/media/video/cx88/cx88-mpeg.c | 4 ---- + drivers/media/video/cx88/cx88.h | 3 ++- + 4 files changed, 5 insertions(+), 9 deletions(-) + +--- a/drivers/media/video/cx88/cx88-blackbird.c ++++ b/drivers/media/video/cx88/cx88-blackbird.c +@@ -1125,13 +1125,13 @@ static int mpeg_release(struct file *fil + + /* Make sure we release the hardware */ + drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD); +- mutex_unlock(&dev->core->lock); +- + if (drv) + drv->request_release(drv); + + atomic_dec(&dev->core->mpeg_users); + ++ mutex_unlock(&dev->core->lock); ++ + return 0; + } + +--- a/drivers/media/video/cx88/cx88-dvb.c ++++ b/drivers/media/video/cx88/cx88-dvb.c +@@ -135,8 +135,6 @@ static int cx88_dvb_bus_ctrl(struct dvb_ + + mutex_lock(&dev->core->lock); + drv = cx8802_get_driver(dev, CX88_MPEG_DVB); +- mutex_unlock(&dev->core->lock); +- + if (drv) { + if (acquire){ + dev->frontends.active_fe_id = fe_id; +@@ -146,6 +144,7 @@ static int cx88_dvb_bus_ctrl(struct dvb_ + dev->frontends.active_fe_id = 0; + } + } ++ mutex_unlock(&dev->core->lock); + + return ret; + } +--- a/drivers/media/video/cx88/cx88-mpeg.c ++++ b/drivers/media/video/cx88/cx88-mpeg.c +@@ -624,13 +624,11 @@ static int cx8802_request_acquire(struct + + if (drv->advise_acquire) + { +- mutex_lock(&drv->core->lock); + core->active_ref++; + if (core->active_type_id == CX88_BOARD_NONE) { + core->active_type_id = drv->type_id; + drv->advise_acquire(drv); + } +- mutex_unlock(&drv->core->lock); + + mpeg_dbg(1,"%s() Post acquire GPIO=%x\n", __func__, cx_read(MO_GP0_IO)); + } +@@ -643,14 +641,12 @@ static int cx8802_request_release(struct + { + struct cx88_core *core = drv->core; + +- mutex_lock(&drv->core->lock); + if (drv->advise_release && --core->active_ref == 0) + { + drv->advise_release(drv); + core->active_type_id = CX88_BOARD_NONE; + mpeg_dbg(1,"%s() Post release GPIO=%x\n", __func__, cx_read(MO_GP0_IO)); + } +- mutex_unlock(&drv->core->lock); + + return 0; + } +--- a/drivers/media/video/cx88/cx88.h ++++ b/drivers/media/video/cx88/cx88.h +@@ -510,7 +510,8 @@ struct cx8802_driver { + /* Caller must _not_ hold core->lock */ + int (*probe)(struct cx8802_driver *drv); + +- /* Caller must hold core->lock */ ++ /* Callers to the following functions must hold core->lock */ ++ + int (*remove)(struct cx8802_driver *drv); + + /* MPEG 8802 -> mini driver - Access for hardware control */ diff --git a/queue-2.6.39/cx88-hold-device-lock-during-sub-driver.patch b/queue-2.6.39/cx88-hold-device-lock-during-sub-driver.patch new file mode 100644 index 0000000000..60243fe829 --- /dev/null +++ b/queue-2.6.39/cx88-hold-device-lock-during-sub-driver.patch @@ -0,0 +1,88 @@ +From 1d6213ab995c61f7d1d81cf6cf876acf15d6e714 Mon Sep 17 00:00:00 2001 +From: Jonathan Nieder <jrnieder@gmail.com> +Date: Sun, 1 May 2011 06:29:56 -0300 +Subject: [media] cx88: hold device lock during sub-driver + initialization + +From: Jonathan Nieder <jrnieder@gmail.com> + +commit 1d6213ab995c61f7d1d81cf6cf876acf15d6e714 upstream. + +cx8802_blackbird_probe makes a device node for the mpeg sub-device +before it has been added to dev->drvlist. If the device is opened +during that time, the open succeeds but request_acquire cannot be +called, so the reference count remains zero. Later, when the device +is closed, the reference count becomes negative --- uh oh. + +Close the race by holding core->lock during probe and not releasing +until the device is in drvlist and initialization finished. +Previously the BKL prevented this race. + +Reported-by: Andreas Huber <hobrom@gmx.at> +Tested-by: Andi Huber <hobrom@gmx.at> +Tested-by: Marlon de Boer <marlon@hyves.nl> +Signed-off-by: Jonathan Nieder <jrnieder@gmail.com> +Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/media/video/cx88/cx88-blackbird.c | 2 -- + drivers/media/video/cx88/cx88-mpeg.c | 5 ++--- + drivers/media/video/cx88/cx88.h | 7 ++----- + 3 files changed, 4 insertions(+), 10 deletions(-) + +--- a/drivers/media/video/cx88/cx88-blackbird.c ++++ b/drivers/media/video/cx88/cx88-blackbird.c +@@ -1335,11 +1335,9 @@ static int cx8802_blackbird_probe(struct + blackbird_register_video(dev); + + /* initial device configuration: needed ? */ +- mutex_lock(&dev->core->lock); + // init_controls(core); + cx88_set_tvnorm(core,core->tvnorm); + cx88_video_mux(core,0); +- mutex_unlock(&dev->core->lock); + + return 0; + +--- a/drivers/media/video/cx88/cx88-mpeg.c ++++ b/drivers/media/video/cx88/cx88-mpeg.c +@@ -709,18 +709,17 @@ int cx8802_register_driver(struct cx8802 + drv->request_release = cx8802_request_release; + memcpy(driver, drv, sizeof(*driver)); + ++ mutex_lock(&drv->core->lock); + err = drv->probe(driver); + if (err == 0) { + i++; +- mutex_lock(&drv->core->lock); + list_add_tail(&driver->drvlist, &dev->drvlist); +- mutex_unlock(&drv->core->lock); + } else { + printk(KERN_ERR + "%s/2: cx8802 probe failed, err = %d\n", + dev->core->name, err); + } +- ++ mutex_unlock(&drv->core->lock); + } + + return i ? 0 : -ENODEV; +--- a/drivers/media/video/cx88/cx88.h ++++ b/drivers/media/video/cx88/cx88.h +@@ -505,13 +505,10 @@ struct cx8802_driver { + int (*suspend)(struct pci_dev *pci_dev, pm_message_t state); + int (*resume)(struct pci_dev *pci_dev); + +- /* MPEG 8802 -> mini driver - Driver probe and configuration */ +- +- /* Caller must _not_ hold core->lock */ +- int (*probe)(struct cx8802_driver *drv); +- + /* Callers to the following functions must hold core->lock */ + ++ /* MPEG 8802 -> mini driver - Driver probe and configuration */ ++ int (*probe)(struct cx8802_driver *drv); + int (*remove)(struct cx8802_driver *drv); + + /* MPEG 8802 -> mini driver - Access for hardware control */ diff --git a/queue-2.6.39/cx88-protect-per-device-driver-list-with-device.patch b/queue-2.6.39/cx88-protect-per-device-driver-list-with-device.patch new file mode 100644 index 0000000000..062b0615d1 --- /dev/null +++ b/queue-2.6.39/cx88-protect-per-device-driver-list-with-device.patch @@ -0,0 +1,161 @@ +From 8a317a8760cfffa8185b56ff59fb4b6c58488d79 Mon Sep 17 00:00:00 2001 +From: Jonathan Nieder <jrnieder@gmail.com> +Date: Sun, 1 May 2011 06:29:16 -0300 +Subject: [media] cx88: protect per-device driver list with device + lock + +From: Jonathan Nieder <jrnieder@gmail.com> + +commit 8a317a8760cfffa8185b56ff59fb4b6c58488d79 upstream. + +The BKL conversion of this driver seems to have gone wrong. Various +uses of the sub-device and driver lists appear to be subject to race +conditions. + +In particular, some functions access drvlist without a relevant lock +held, which will race against removal of drivers. Let's start with +that --- clean up by consistently protecting dev->drvlist with +dev->core->lock, noting driver functions that require the device lock +to be held or not to be held. + +After this patch, there are still some races --- e.g., +cx8802_blackbird_remove can run between the time the blackbird driver +is acquired and the time it is used in mpeg_release, and there's a +similar race in cx88_dvb_bus_ctrl. Later patches will address the +remaining known races and the deadlock noticed by Andi. This patch +just makes the semantics clearer in preparation for those later +changes. + +Based on work by Ben Hutchings <ben@decadent.org.uk>. + +Tested-by: Andi Huber <hobrom@gmx.at> +Tested-by: Marlon de Boer <marlon@hyves.nl> +Signed-off-by: Jonathan Nieder <jrnieder@gmail.com> +Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/media/video/cx88/cx88-blackbird.c | 3 ++- + drivers/media/video/cx88/cx88-dvb.c | 3 +++ + drivers/media/video/cx88/cx88-mpeg.c | 11 +++++++---- + drivers/media/video/cx88/cx88.h | 9 ++++++++- + 4 files changed, 20 insertions(+), 6 deletions(-) + +--- a/drivers/media/video/cx88/cx88-blackbird.c ++++ b/drivers/media/video/cx88/cx88-blackbird.c +@@ -1122,10 +1122,11 @@ static int mpeg_release(struct file *fil + mutex_lock(&dev->core->lock); + file->private_data = NULL; + kfree(fh); +- mutex_unlock(&dev->core->lock); + + /* Make sure we release the hardware */ + drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD); ++ mutex_unlock(&dev->core->lock); ++ + if (drv) + drv->request_release(drv); + +--- a/drivers/media/video/cx88/cx88-dvb.c ++++ b/drivers/media/video/cx88/cx88-dvb.c +@@ -133,7 +133,10 @@ static int cx88_dvb_bus_ctrl(struct dvb_ + return -EINVAL; + } + ++ mutex_lock(&dev->core->lock); + drv = cx8802_get_driver(dev, CX88_MPEG_DVB); ++ mutex_unlock(&dev->core->lock); ++ + if (drv) { + if (acquire){ + dev->frontends.active_fe_id = fe_id; +--- a/drivers/media/video/cx88/cx88-mpeg.c ++++ b/drivers/media/video/cx88/cx88-mpeg.c +@@ -748,6 +748,8 @@ int cx8802_unregister_driver(struct cx88 + dev->pci->subsystem_device, dev->core->board.name, + dev->core->boardnr); + ++ mutex_lock(&dev->core->lock); ++ + list_for_each_entry_safe(d, dtmp, &dev->drvlist, drvlist) { + /* only unregister the correct driver type */ + if (d->type_id != drv->type_id) +@@ -755,15 +757,14 @@ int cx8802_unregister_driver(struct cx88 + + err = d->remove(d); + if (err == 0) { +- mutex_lock(&drv->core->lock); + list_del(&d->drvlist); +- mutex_unlock(&drv->core->lock); + kfree(d); + } else + printk(KERN_ERR "%s/2: cx8802 driver remove " + "failed (%d)\n", dev->core->name, err); + } + ++ mutex_unlock(&dev->core->lock); + } + + return err; +@@ -827,6 +828,8 @@ static void __devexit cx8802_remove(stru + + flush_request_modules(dev); + ++ mutex_lock(&dev->core->lock); ++ + if (!list_empty(&dev->drvlist)) { + struct cx8802_driver *drv, *tmp; + int err; +@@ -838,9 +841,7 @@ static void __devexit cx8802_remove(stru + list_for_each_entry_safe(drv, tmp, &dev->drvlist, drvlist) { + err = drv->remove(drv); + if (err == 0) { +- mutex_lock(&drv->core->lock); + list_del(&drv->drvlist); +- mutex_unlock(&drv->core->lock); + } else + printk(KERN_ERR "%s/2: cx8802 driver remove " + "failed (%d)\n", dev->core->name, err); +@@ -848,6 +849,8 @@ static void __devexit cx8802_remove(stru + } + } + ++ mutex_unlock(&dev->core->lock); ++ + /* Destroy any 8802 reference. */ + dev->core->dvbdev = NULL; + +--- a/drivers/media/video/cx88/cx88.h ++++ b/drivers/media/video/cx88/cx88.h +@@ -506,7 +506,11 @@ struct cx8802_driver { + int (*resume)(struct pci_dev *pci_dev); + + /* MPEG 8802 -> mini driver - Driver probe and configuration */ ++ ++ /* Caller must _not_ hold core->lock */ + int (*probe)(struct cx8802_driver *drv); ++ ++ /* Caller must hold core->lock */ + int (*remove)(struct cx8802_driver *drv); + + /* MPEG 8802 -> mini driver - Access for hardware control */ +@@ -561,8 +565,9 @@ struct cx8802_dev { + /* for switching modulation types */ + unsigned char ts_gen_cntrl; + +- /* List of attached drivers */ ++ /* List of attached drivers; must hold core->lock to access */ + struct list_head drvlist; ++ + struct work_struct request_module_wk; + }; + +@@ -685,6 +690,8 @@ int cx88_audio_thread(void *data); + + int cx8802_register_driver(struct cx8802_driver *drv); + int cx8802_unregister_driver(struct cx8802_driver *drv); ++ ++/* Caller must hold core->lock */ + struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype); + + /* ----------------------------------------------------------- */ diff --git a/queue-2.6.39/dibxxxx-get-rid-of-dma-buffer-on-stack.patch b/queue-2.6.39/dibxxxx-get-rid-of-dma-buffer-on-stack.patch new file mode 100644 index 0000000000..8643834125 --- /dev/null +++ b/queue-2.6.39/dibxxxx-get-rid-of-dma-buffer-on-stack.patch @@ -0,0 +1,1188 @@ +From 5a0deeed5741117ee8625d6305d0034e219f102c Mon Sep 17 00:00:00 2001 +From: Olivier Grenie <olivier.grenie@dibcom.fr> +Date: Tue, 3 May 2011 12:27:33 -0300 +Subject: [media] DiBxxxx: get rid of DMA buffer on stack + +From: Olivier Grenie <olivier.grenie@dibcom.fr> + +commit 5a0deeed5741117ee8625d6305d0034e219f102c upstream. + +This patch removes the remaining on-stack buffer for USB DMA transfer. +This patch also reduces the stack memory usage. + +Cc: Florian Mickler <florian@mickler.org> +Signed-off-by: Olivier Grenie <olivier.grenie@dibcom.fr> +Signed-off-by: Patrick Boettcher <patrick.boettcher@dibcom.fr> +Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/media/dvb/frontends/dib0070.c | 40 ++++-- + drivers/media/dvb/frontends/dib0090.c | 71 ++++++++--- + drivers/media/dvb/frontends/dib7000m.c | 47 ++++--- + drivers/media/dvb/frontends/dib7000p.c | 72 ++++++++--- + drivers/media/dvb/frontends/dib8000.c | 126 ++++++++++++++----- + drivers/media/dvb/frontends/dib9000.c | 172 +++++++++++++++++---------- + drivers/media/dvb/frontends/dibx000_common.c | 113 ++++++++++------- + drivers/media/dvb/frontends/dibx000_common.h | 5 + 8 files changed, 444 insertions(+), 202 deletions(-) + +--- a/drivers/media/dvb/frontends/dib0070.c ++++ b/drivers/media/dvb/frontends/dib0070.c +@@ -73,27 +73,47 @@ struct dib0070_state { + + u8 wbd_gain_current; + u16 wbd_offset_3_3[2]; ++ ++ /* for the I2C transfer */ ++ struct i2c_msg msg[2]; ++ u8 i2c_write_buffer[3]; ++ u8 i2c_read_buffer[2]; + }; + + static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg) + { +- u8 b[2]; +- struct i2c_msg msg[2] = { +- { .addr = state->cfg->i2c_address, .flags = 0, .buf = ®, .len = 1 }, +- { .addr = state->cfg->i2c_address, .flags = I2C_M_RD, .buf = b, .len = 2 }, +- }; +- if (i2c_transfer(state->i2c, msg, 2) != 2) { ++ state->i2c_write_buffer[0] = reg; ++ ++ memset(state->msg, 0, 2 * sizeof(struct i2c_msg)); ++ state->msg[0].addr = state->cfg->i2c_address; ++ state->msg[0].flags = 0; ++ state->msg[0].buf = state->i2c_write_buffer; ++ state->msg[0].len = 1; ++ state->msg[1].addr = state->cfg->i2c_address; ++ state->msg[1].flags = I2C_M_RD; ++ state->msg[1].buf = state->i2c_read_buffer; ++ state->msg[1].len = 2; ++ ++ if (i2c_transfer(state->i2c, state->msg, 2) != 2) { + printk(KERN_WARNING "DiB0070 I2C read failed\n"); + return 0; + } +- return (b[0] << 8) | b[1]; ++ return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; + } + + static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val) + { +- u8 b[3] = { reg, val >> 8, val & 0xff }; +- struct i2c_msg msg = { .addr = state->cfg->i2c_address, .flags = 0, .buf = b, .len = 3 }; +- if (i2c_transfer(state->i2c, &msg, 1) != 1) { ++ state->i2c_write_buffer[0] = reg; ++ state->i2c_write_buffer[1] = val >> 8; ++ state->i2c_write_buffer[2] = val & 0xff; ++ ++ memset(state->msg, 0, sizeof(struct i2c_msg)); ++ state->msg[0].addr = state->cfg->i2c_address; ++ state->msg[0].flags = 0; ++ state->msg[0].buf = state->i2c_write_buffer; ++ state->msg[0].len = 3; ++ ++ if (i2c_transfer(state->i2c, state->msg, 1) != 1) { + printk(KERN_WARNING "DiB0070 I2C write failed\n"); + return -EREMOTEIO; + } +--- a/drivers/media/dvb/frontends/dib0090.c ++++ b/drivers/media/dvb/frontends/dib0090.c +@@ -191,6 +191,11 @@ struct dib0090_state { + u8 wbd_calibration_gain; + const struct dib0090_wbd_slope *current_wbd_table; + u16 wbdmux; ++ ++ /* for the I2C transfer */ ++ struct i2c_msg msg[2]; ++ u8 i2c_write_buffer[3]; ++ u8 i2c_read_buffer[2]; + }; + + struct dib0090_fw_state { +@@ -198,27 +203,48 @@ struct dib0090_fw_state { + struct dvb_frontend *fe; + struct dib0090_identity identity; + const struct dib0090_config *config; ++ ++ /* for the I2C transfer */ ++ struct i2c_msg msg; ++ u8 i2c_write_buffer[2]; ++ u8 i2c_read_buffer[2]; + }; + + static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg) + { +- u8 b[2]; +- struct i2c_msg msg[2] = { +- {.addr = state->config->i2c_address, .flags = 0, .buf = ®, .len = 1}, +- {.addr = state->config->i2c_address, .flags = I2C_M_RD, .buf = b, .len = 2}, +- }; +- if (i2c_transfer(state->i2c, msg, 2) != 2) { ++ state->i2c_write_buffer[0] = reg; ++ ++ memset(state->msg, 0, 2 * sizeof(struct i2c_msg)); ++ state->msg[0].addr = state->config->i2c_address; ++ state->msg[0].flags = 0; ++ state->msg[0].buf = state->i2c_write_buffer; ++ state->msg[0].len = 1; ++ state->msg[1].addr = state->config->i2c_address; ++ state->msg[1].flags = I2C_M_RD; ++ state->msg[1].buf = state->i2c_read_buffer; ++ state->msg[1].len = 2; ++ ++ if (i2c_transfer(state->i2c, state->msg, 2) != 2) { + printk(KERN_WARNING "DiB0090 I2C read failed\n"); + return 0; + } +- return (b[0] << 8) | b[1]; ++ ++ return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; + } + + static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val) + { +- u8 b[3] = { reg & 0xff, val >> 8, val & 0xff }; +- struct i2c_msg msg = {.addr = state->config->i2c_address, .flags = 0, .buf = b, .len = 3 }; +- if (i2c_transfer(state->i2c, &msg, 1) != 1) { ++ state->i2c_write_buffer[0] = reg & 0xff; ++ state->i2c_write_buffer[1] = val >> 8; ++ state->i2c_write_buffer[2] = val & 0xff; ++ ++ memset(state->msg, 0, sizeof(struct i2c_msg)); ++ state->msg[0].addr = state->config->i2c_address; ++ state->msg[0].flags = 0; ++ state->msg[0].buf = state->i2c_write_buffer; ++ state->msg[0].len = 3; ++ ++ if (i2c_transfer(state->i2c, state->msg, 1) != 1) { + printk(KERN_WARNING "DiB0090 I2C write failed\n"); + return -EREMOTEIO; + } +@@ -227,20 +253,31 @@ static int dib0090_write_reg(struct dib0 + + static u16 dib0090_fw_read_reg(struct dib0090_fw_state *state, u8 reg) + { +- u8 b[2]; +- struct i2c_msg msg = {.addr = reg, .flags = I2C_M_RD, .buf = b, .len = 2 }; +- if (i2c_transfer(state->i2c, &msg, 1) != 1) { ++ state->i2c_write_buffer[0] = reg; ++ ++ memset(&state->msg, 0, sizeof(struct i2c_msg)); ++ state->msg.addr = reg; ++ state->msg.flags = I2C_M_RD; ++ state->msg.buf = state->i2c_read_buffer; ++ state->msg.len = 2; ++ if (i2c_transfer(state->i2c, &state->msg, 1) != 1) { + printk(KERN_WARNING "DiB0090 I2C read failed\n"); + return 0; + } +- return (b[0] << 8) | b[1]; ++ return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; + } + + static int dib0090_fw_write_reg(struct dib0090_fw_state *state, u8 reg, u16 val) + { +- u8 b[2] = { val >> 8, val & 0xff }; +- struct i2c_msg msg = {.addr = reg, .flags = 0, .buf = b, .len = 2 }; +- if (i2c_transfer(state->i2c, &msg, 1) != 1) { ++ state->i2c_write_buffer[0] = val >> 8; ++ state->i2c_write_buffer[1] = val & 0xff; ++ ++ memset(&state->msg, 0, sizeof(struct i2c_msg)); ++ state->msg.addr = reg; ++ state->msg.flags = 0; ++ state->msg.buf = state->i2c_write_buffer; ++ state->msg.len = 2; ++ if (i2c_transfer(state->i2c, &state->msg, 1) != 1) { + printk(KERN_WARNING "DiB0090 I2C write failed\n"); + return -EREMOTEIO; + } +--- a/drivers/media/dvb/frontends/dib7000m.c ++++ b/drivers/media/dvb/frontends/dib7000m.c +@@ -50,6 +50,11 @@ struct dib7000m_state { + u16 revision; + + u8 agc_state; ++ ++ /* for the I2C transfer */ ++ struct i2c_msg msg[2]; ++ u8 i2c_write_buffer[4]; ++ u8 i2c_read_buffer[2]; + }; + + enum dib7000m_power_mode { +@@ -64,29 +69,39 @@ enum dib7000m_power_mode { + + static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg) + { +- u8 wb[2] = { (reg >> 8) | 0x80, reg & 0xff }; +- u8 rb[2]; +- struct i2c_msg msg[2] = { +- { .addr = state->i2c_addr >> 1, .flags = 0, .buf = wb, .len = 2 }, +- { .addr = state->i2c_addr >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2 }, +- }; ++ state->i2c_write_buffer[0] = (reg >> 8) | 0x80; ++ state->i2c_write_buffer[1] = reg & 0xff; ++ ++ memset(state->msg, 0, 2 * sizeof(struct i2c_msg)); ++ state->msg[0].addr = state->i2c_addr >> 1; ++ state->msg[0].flags = 0; ++ state->msg[0].buf = state->i2c_write_buffer; ++ state->msg[0].len = 2; ++ state->msg[1].addr = state->i2c_addr >> 1; ++ state->msg[1].flags = I2C_M_RD; ++ state->msg[1].buf = state->i2c_read_buffer; ++ state->msg[1].len = 2; + +- if (i2c_transfer(state->i2c_adap, msg, 2) != 2) ++ if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2) + dprintk("i2c read error on %d",reg); + +- return (rb[0] << 8) | rb[1]; ++ return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; + } + + static int dib7000m_write_word(struct dib7000m_state *state, u16 reg, u16 val) + { +- u8 b[4] = { +- (reg >> 8) & 0xff, reg & 0xff, +- (val >> 8) & 0xff, val & 0xff, +- }; +- struct i2c_msg msg = { +- .addr = state->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4 +- }; +- return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; ++ state->i2c_write_buffer[0] = (reg >> 8) & 0xff; ++ state->i2c_write_buffer[1] = reg & 0xff; ++ state->i2c_write_buffer[2] = (val >> 8) & 0xff; ++ state->i2c_write_buffer[3] = val & 0xff; ++ ++ memset(&state->msg[0], 0, sizeof(struct i2c_msg)); ++ state->msg[0].addr = state->i2c_addr >> 1; ++ state->msg[0].flags = 0; ++ state->msg[0].buf = state->i2c_write_buffer; ++ state->msg[0].len = 4; ++ ++ return i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0; + } + static void dib7000m_write_tab(struct dib7000m_state *state, u16 *buf) + { +--- a/drivers/media/dvb/frontends/dib7000p.c ++++ b/drivers/media/dvb/frontends/dib7000p.c +@@ -63,6 +63,11 @@ struct dib7000p_state { + + u16 tuner_enable; + struct i2c_adapter dib7090_tuner_adap; ++ ++ /* for the I2C transfer */ ++ struct i2c_msg msg[2]; ++ u8 i2c_write_buffer[4]; ++ u8 i2c_read_buffer[2]; + }; + + enum dib7000p_power_mode { +@@ -76,29 +81,39 @@ static int dib7090_set_diversity_in(stru + + static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg) + { +- u8 wb[2] = { reg >> 8, reg & 0xff }; +- u8 rb[2]; +- struct i2c_msg msg[2] = { +- {.addr = state->i2c_addr >> 1, .flags = 0, .buf = wb, .len = 2}, +- {.addr = state->i2c_addr >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2}, +- }; ++ state->i2c_write_buffer[0] = reg >> 8; ++ state->i2c_write_buffer[1] = reg & 0xff; ++ ++ memset(state->msg, 0, 2 * sizeof(struct i2c_msg)); ++ state->msg[0].addr = state->i2c_addr >> 1; ++ state->msg[0].flags = 0; ++ state->msg[0].buf = state->i2c_write_buffer; ++ state->msg[0].len = 2; ++ state->msg[1].addr = state->i2c_addr >> 1; ++ state->msg[1].flags = I2C_M_RD; ++ state->msg[1].buf = state->i2c_read_buffer; ++ state->msg[1].len = 2; + +- if (i2c_transfer(state->i2c_adap, msg, 2) != 2) ++ if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2) + dprintk("i2c read error on %d", reg); + +- return (rb[0] << 8) | rb[1]; ++ return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; + } + + static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val) + { +- u8 b[4] = { +- (reg >> 8) & 0xff, reg & 0xff, +- (val >> 8) & 0xff, val & 0xff, +- }; +- struct i2c_msg msg = { +- .addr = state->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4 +- }; +- return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; ++ state->i2c_write_buffer[0] = (reg >> 8) & 0xff; ++ state->i2c_write_buffer[1] = reg & 0xff; ++ state->i2c_write_buffer[2] = (val >> 8) & 0xff; ++ state->i2c_write_buffer[3] = val & 0xff; ++ ++ memset(&state->msg[0], 0, sizeof(struct i2c_msg)); ++ state->msg[0].addr = state->i2c_addr >> 1; ++ state->msg[0].flags = 0; ++ state->msg[0].buf = state->i2c_write_buffer; ++ state->msg[0].len = 4; ++ ++ return i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0; + } + + static void dib7000p_write_tab(struct dib7000p_state *state, u16 * buf) +@@ -1550,11 +1565,24 @@ static void dib7000p_release(struct dvb_ + + int dib7000pc_detection(struct i2c_adapter *i2c_adap) + { +- u8 tx[2], rx[2]; ++ u8 *tx, *rx; + struct i2c_msg msg[2] = { +- {.addr = 18 >> 1, .flags = 0, .buf = tx, .len = 2}, +- {.addr = 18 >> 1, .flags = I2C_M_RD, .buf = rx, .len = 2}, ++ {.addr = 18 >> 1, .flags = 0, .len = 2}, ++ {.addr = 18 >> 1, .flags = I2C_M_RD, .len = 2}, + }; ++ int ret = 0; ++ ++ tx = kzalloc(2*sizeof(u8), GFP_KERNEL); ++ if (!tx) ++ return -ENOMEM; ++ rx = kzalloc(2*sizeof(u8), GFP_KERNEL); ++ if (!rx) { ++ goto rx_memory_error; ++ ret = -ENOMEM; ++ } ++ ++ msg[0].buf = tx; ++ msg[1].buf = rx; + + tx[0] = 0x03; + tx[1] = 0x00; +@@ -1574,7 +1602,11 @@ int dib7000pc_detection(struct i2c_adapt + } + + dprintk("-D- DiB7000PC not detected"); +- return 0; ++ ++ kfree(rx); ++rx_memory_error: ++ kfree(tx); ++ return ret; + } + EXPORT_SYMBOL(dib7000pc_detection); + +--- a/drivers/media/dvb/frontends/dib8000.c ++++ b/drivers/media/dvb/frontends/dib8000.c +@@ -35,6 +35,8 @@ MODULE_PARM_DESC(debug, "turn on debuggi + struct i2c_device { + struct i2c_adapter *adap; + u8 addr; ++ u8 *i2c_write_buffer; ++ u8 *i2c_read_buffer; + }; + + struct dib8000_state { +@@ -70,6 +72,11 @@ struct dib8000_state { + u32 status; + + struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS]; ++ ++ /* for the I2C transfer */ ++ struct i2c_msg msg[2]; ++ u8 i2c_write_buffer[4]; ++ u8 i2c_read_buffer[2]; + }; + + enum dib8000_power_mode { +@@ -79,22 +86,41 @@ enum dib8000_power_mode { + + static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg) + { +- u8 wb[2] = { reg >> 8, reg & 0xff }; +- u8 rb[2]; + struct i2c_msg msg[2] = { +- {.addr = i2c->addr >> 1,.flags = 0,.buf = wb,.len = 2}, +- {.addr = i2c->addr >> 1,.flags = I2C_M_RD,.buf = rb,.len = 2}, ++ {.addr = i2c->addr >> 1, .flags = 0, ++ .buf = i2c->i2c_write_buffer, .len = 2}, ++ {.addr = i2c->addr >> 1, .flags = I2C_M_RD, ++ .buf = i2c->i2c_read_buffer, .len = 2}, + }; + ++ msg[0].buf[0] = reg >> 8; ++ msg[0].buf[1] = reg & 0xff; ++ + if (i2c_transfer(i2c->adap, msg, 2) != 2) + dprintk("i2c read error on %d", reg); + +- return (rb[0] << 8) | rb[1]; ++ return (msg[1].buf[0] << 8) | msg[1].buf[1]; + } + + static u16 dib8000_read_word(struct dib8000_state *state, u16 reg) + { +- return dib8000_i2c_read16(&state->i2c, reg); ++ state->i2c_write_buffer[0] = reg >> 8; ++ state->i2c_write_buffer[1] = reg & 0xff; ++ ++ memset(state->msg, 0, 2 * sizeof(struct i2c_msg)); ++ state->msg[0].addr = state->i2c.addr >> 1; ++ state->msg[0].flags = 0; ++ state->msg[0].buf = state->i2c_write_buffer; ++ state->msg[0].len = 2; ++ state->msg[1].addr = state->i2c.addr >> 1; ++ state->msg[1].flags = I2C_M_RD; ++ state->msg[1].buf = state->i2c_read_buffer; ++ state->msg[1].len = 2; ++ ++ if (i2c_transfer(state->i2c.adap, state->msg, 2) != 2) ++ dprintk("i2c read error on %d", reg); ++ ++ return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; + } + + static u32 dib8000_read32(struct dib8000_state *state, u16 reg) +@@ -109,19 +135,34 @@ static u32 dib8000_read32(struct dib8000 + + static int dib8000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val) + { +- u8 b[4] = { +- (reg >> 8) & 0xff, reg & 0xff, +- (val >> 8) & 0xff, val & 0xff, +- }; +- struct i2c_msg msg = { +- .addr = i2c->addr >> 1,.flags = 0,.buf = b,.len = 4 +- }; +- return i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0; ++ struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0, ++ .buf = i2c->i2c_write_buffer, .len = 4}; ++ int ret = 0; ++ ++ msg.buf[0] = (reg >> 8) & 0xff; ++ msg.buf[1] = reg & 0xff; ++ msg.buf[2] = (val >> 8) & 0xff; ++ msg.buf[3] = val & 0xff; ++ ++ ret = i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0; ++ ++ return ret; + } + + static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val) + { +- return dib8000_i2c_write16(&state->i2c, reg, val); ++ state->i2c_write_buffer[0] = (reg >> 8) & 0xff; ++ state->i2c_write_buffer[1] = reg & 0xff; ++ state->i2c_write_buffer[2] = (val >> 8) & 0xff; ++ state->i2c_write_buffer[3] = val & 0xff; ++ ++ memset(&state->msg[0], 0, sizeof(struct i2c_msg)); ++ state->msg[0].addr = state->i2c.addr >> 1; ++ state->msg[0].flags = 0; ++ state->msg[0].buf = state->i2c_write_buffer; ++ state->msg[0].len = 4; ++ ++ return i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ? -EREMOTEIO : 0; + } + + static const s16 coeff_2k_sb_1seg_dqpsk[8] = { +@@ -980,30 +1021,31 @@ static void dib8000_update_timf(struct d + dprintk("Updated timing frequency: %d (default: %d)", state->timf, state->timf_default); + } + ++static const u16 adc_target_16dB[11] = { ++ (1 << 13) - 825 - 117, ++ (1 << 13) - 837 - 117, ++ (1 << 13) - 811 - 117, ++ (1 << 13) - 766 - 117, ++ (1 << 13) - 737 - 117, ++ (1 << 13) - 693 - 117, ++ (1 << 13) - 648 - 117, ++ (1 << 13) - 619 - 117, ++ (1 << 13) - 575 - 117, ++ (1 << 13) - 531 - 117, ++ (1 << 13) - 501 - 117 ++}; ++static const u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 }; ++ + static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosearching) + { + u16 mode, max_constellation, seg_diff_mask = 0, nbseg_diff = 0; + u8 guard, crate, constellation, timeI; +- u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 }; + u16 i, coeff[4], P_cfr_left_edge = 0, P_cfr_right_edge = 0, seg_mask13 = 0x1fff; // All 13 segments enabled + const s16 *ncoeff = NULL, *ana_fe; + u16 tmcc_pow = 0; + u16 coff_pow = 0x2800; + u16 init_prbs = 0xfff; + u16 ana_gain = 0; +- u16 adc_target_16dB[11] = { +- (1 << 13) - 825 - 117, +- (1 << 13) - 837 - 117, +- (1 << 13) - 811 - 117, +- (1 << 13) - 766 - 117, +- (1 << 13) - 737 - 117, +- (1 << 13) - 693 - 117, +- (1 << 13) - 648 - 117, +- (1 << 13) - 619 - 117, +- (1 << 13) - 575 - 117, +- (1 << 13) - 531 - 117, +- (1 << 13) - 501 - 117 +- }; + + if (state->ber_monitored_layer != LAYER_ALL) + dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & 0x60) | state->ber_monitored_layer); +@@ -2379,10 +2421,22 @@ EXPORT_SYMBOL(dib8000_get_slave_frontend + + int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr) + { +- int k = 0; ++ int k = 0, ret = 0; + u8 new_addr = 0; + struct i2c_device client = {.adap = host }; + ++ client.i2c_write_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL); ++ if (!client.i2c_write_buffer) { ++ dprintk("%s: not enough memory", __func__); ++ return -ENOMEM; ++ } ++ client.i2c_read_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL); ++ if (!client.i2c_read_buffer) { ++ dprintk("%s: not enough memory", __func__); ++ ret = -ENOMEM; ++ goto error_memory; ++ } ++ + for (k = no_of_demods - 1; k >= 0; k--) { + /* designated i2c address */ + new_addr = first_addr + (k << 1); +@@ -2394,7 +2448,8 @@ int dib8000_i2c_enumeration(struct i2c_a + client.addr = default_addr; + if (dib8000_identify(&client) == 0) { + dprintk("#%d: not identified", k); +- return -EINVAL; ++ ret = -EINVAL; ++ goto error; + } + } + +@@ -2420,7 +2475,12 @@ int dib8000_i2c_enumeration(struct i2c_a + dib8000_i2c_write16(&client, 1286, 0); + } + +- return 0; ++error: ++ kfree(client.i2c_read_buffer); ++error_memory: ++ kfree(client.i2c_write_buffer); ++ ++ return ret; + } + + EXPORT_SYMBOL(dib8000_i2c_enumeration); +@@ -2519,6 +2579,8 @@ struct dvb_frontend *dib8000_attach(stru + memcpy(&state->cfg, cfg, sizeof(struct dib8000_config)); + state->i2c.adap = i2c_adap; + state->i2c.addr = i2c_addr; ++ state->i2c.i2c_write_buffer = state->i2c_write_buffer; ++ state->i2c.i2c_read_buffer = state->i2c_read_buffer; + state->gpio_val = cfg->gpio_val; + state->gpio_dir = cfg->gpio_dir; + +--- a/drivers/media/dvb/frontends/dib9000.c ++++ b/drivers/media/dvb/frontends/dib9000.c +@@ -27,6 +27,8 @@ MODULE_PARM_DESC(debug, "turn on debuggi + struct i2c_device { + struct i2c_adapter *i2c_adap; + u8 i2c_addr; ++ u8 *i2c_read_buffer; ++ u8 *i2c_write_buffer; + }; + + /* lock */ +@@ -92,11 +94,16 @@ struct dib9000_state { + + struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS]; + u16 component_bus_speed; ++ ++ /* for the I2C transfer */ ++ struct i2c_msg msg[2]; ++ u8 i2c_write_buffer[255]; ++ u8 i2c_read_buffer[255]; + }; + +-u32 fe_info[44] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++static const u32 fe_info[44] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +- 0, 0, 0 ++ 0, 0, 0, 0, 0, 0, 0, 0 + }; + + enum dib9000_power_mode { +@@ -217,25 +224,33 @@ static u16 dib9000_read16_attr(struct di + u32 chunk_size = 126; + u32 l; + int ret; +- u8 wb[2] = { reg >> 8, reg & 0xff }; +- struct i2c_msg msg[2] = { +- {.addr = state->i2c.i2c_addr >> 1, .flags = 0, .buf = wb, .len = 2}, +- {.addr = state->i2c.i2c_addr >> 1, .flags = I2C_M_RD, .buf = b, .len = len}, +- }; + + if (state->platform.risc.fw_is_running && (reg < 1024)) + return dib9000_risc_apb_access_read(state, reg, attribute, NULL, 0, b, len); + ++ memset(state->msg, 0, 2 * sizeof(struct i2c_msg)); ++ state->msg[0].addr = state->i2c.i2c_addr >> 1; ++ state->msg[0].flags = 0; ++ state->msg[0].buf = state->i2c_write_buffer; ++ state->msg[0].len = 2; ++ state->msg[1].addr = state->i2c.i2c_addr >> 1; ++ state->msg[1].flags = I2C_M_RD; ++ state->msg[1].buf = b; ++ state->msg[1].len = len; ++ ++ state->i2c_write_buffer[0] = reg >> 8; ++ state->i2c_write_buffer[1] = reg & 0xff; ++ + if (attribute & DATA_BUS_ACCESS_MODE_8BIT) +- wb[0] |= (1 << 5); ++ state->i2c_write_buffer[0] |= (1 << 5); + if (attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT) +- wb[0] |= (1 << 4); ++ state->i2c_write_buffer[0] |= (1 << 4); + + do { + l = len < chunk_size ? len : chunk_size; +- msg[1].len = l; +- msg[1].buf = b; +- ret = i2c_transfer(state->i2c.i2c_adap, msg, 2) != 2 ? -EREMOTEIO : 0; ++ state->msg[1].len = l; ++ state->msg[1].buf = b; ++ ret = i2c_transfer(state->i2c.i2c_adap, state->msg, 2) != 2 ? -EREMOTEIO : 0; + if (ret != 0) { + dprintk("i2c read error on %d", reg); + return -EREMOTEIO; +@@ -253,50 +268,47 @@ static u16 dib9000_read16_attr(struct di + + static u16 dib9000_i2c_read16(struct i2c_device *i2c, u16 reg) + { +- u8 b[2]; +- u8 wb[2] = { reg >> 8, reg & 0xff }; + struct i2c_msg msg[2] = { +- {.addr = i2c->i2c_addr >> 1, .flags = 0, .buf = wb, .len = 2}, +- {.addr = i2c->i2c_addr >> 1, .flags = I2C_M_RD, .buf = b, .len = 2}, ++ {.addr = i2c->i2c_addr >> 1, .flags = 0, ++ .buf = i2c->i2c_write_buffer, .len = 2}, ++ {.addr = i2c->i2c_addr >> 1, .flags = I2C_M_RD, ++ .buf = i2c->i2c_read_buffer, .len = 2}, + }; + ++ i2c->i2c_write_buffer[0] = reg >> 8; ++ i2c->i2c_write_buffer[1] = reg & 0xff; ++ + if (i2c_transfer(i2c->i2c_adap, msg, 2) != 2) { + dprintk("read register %x error", reg); + return 0; + } + +- return (b[0] << 8) | b[1]; ++ return (i2c->i2c_read_buffer[0] << 8) | i2c->i2c_read_buffer[1]; + } + + static inline u16 dib9000_read_word(struct dib9000_state *state, u16 reg) + { +- u8 b[2]; +- if (dib9000_read16_attr(state, reg, b, 2, 0) != 0) ++ if (dib9000_read16_attr(state, reg, state->i2c_read_buffer, 2, 0) != 0) + return 0; +- return (b[0] << 8 | b[1]); ++ return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; + } + + static inline u16 dib9000_read_word_attr(struct dib9000_state *state, u16 reg, u16 attribute) + { +- u8 b[2]; +- if (dib9000_read16_attr(state, reg, b, 2, attribute) != 0) ++ if (dib9000_read16_attr(state, reg, state->i2c_read_buffer, 2, ++ attribute) != 0) + return 0; +- return (b[0] << 8 | b[1]); ++ return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; + } + + #define dib9000_read16_noinc_attr(state, reg, b, len, attribute) dib9000_read16_attr(state, reg, b, len, (attribute) | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT) + + static u16 dib9000_write16_attr(struct dib9000_state *state, u16 reg, const u8 * buf, u32 len, u16 attribute) + { +- u8 b[255]; + u32 chunk_size = 126; + u32 l; + int ret; + +- struct i2c_msg msg = { +- .addr = state->i2c.i2c_addr >> 1, .flags = 0, .buf = b, .len = len + 2 +- }; +- + if (state->platform.risc.fw_is_running && (reg < 1024)) { + if (dib9000_risc_apb_access_write + (state, reg, DATA_BUS_ACCESS_MODE_16BIT | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT | attribute, buf, len) != 0) +@@ -304,20 +316,26 @@ static u16 dib9000_write16_attr(struct d + return 0; + } + +- b[0] = (reg >> 8) & 0xff; +- b[1] = (reg) & 0xff; ++ memset(&state->msg[0], 0, sizeof(struct i2c_msg)); ++ state->msg[0].addr = state->i2c.i2c_addr >> 1; ++ state->msg[0].flags = 0; ++ state->msg[0].buf = state->i2c_write_buffer; ++ state->msg[0].len = len + 2; ++ ++ state->i2c_write_buffer[0] = (reg >> 8) & 0xff; ++ state->i2c_write_buffer[1] = (reg) & 0xff; + + if (attribute & DATA_BUS_ACCESS_MODE_8BIT) +- b[0] |= (1 << 5); ++ state->i2c_write_buffer[0] |= (1 << 5); + if (attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT) +- b[0] |= (1 << 4); ++ state->i2c_write_buffer[0] |= (1 << 4); + + do { + l = len < chunk_size ? len : chunk_size; +- msg.len = l + 2; +- memcpy(&b[2], buf, l); ++ state->msg[0].len = l + 2; ++ memcpy(&state->i2c_write_buffer[2], buf, l); + +- ret = i2c_transfer(state->i2c.i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; ++ ret = i2c_transfer(state->i2c.i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0; + + buf += l; + len -= l; +@@ -331,11 +349,16 @@ static u16 dib9000_write16_attr(struct d + + static int dib9000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val) + { +- u8 b[4] = { (reg >> 8) & 0xff, reg & 0xff, (val >> 8) & 0xff, val & 0xff }; + struct i2c_msg msg = { +- .addr = i2c->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4 ++ .addr = i2c->i2c_addr >> 1, .flags = 0, ++ .buf = i2c->i2c_write_buffer, .len = 4 + }; + ++ i2c->i2c_write_buffer[0] = (reg >> 8) & 0xff; ++ i2c->i2c_write_buffer[1] = reg & 0xff; ++ i2c->i2c_write_buffer[2] = (val >> 8) & 0xff; ++ i2c->i2c_write_buffer[3] = val & 0xff; ++ + return i2c_transfer(i2c->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; + } + +@@ -1015,8 +1038,8 @@ static int dib9000_fw_memmbx_sync(struct + return 0; + dib9000_risc_mem_write(state, FE_MM_RW_SYNC, &i); + do { +- dib9000_risc_mem_read(state, FE_MM_RW_SYNC, &i, 1); +- } while (i && index_loop--); ++ dib9000_risc_mem_read(state, FE_MM_RW_SYNC, state->i2c_read_buffer, 1); ++ } while (state->i2c_read_buffer[0] && index_loop--); + + if (index_loop > 0) + return 0; +@@ -1139,7 +1162,7 @@ static int dib9000_fw_get_channel(struct + + s8 intlv_native; + }; +- struct dibDVBTChannel ch; ++ struct dibDVBTChannel *ch; + int ret = 0; + + DibAcquireLock(&state->platform.risc.mem_mbx_lock); +@@ -1148,9 +1171,12 @@ static int dib9000_fw_get_channel(struct + ret = -EIO; + } + +- dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_UNION, (u8 *) &ch, sizeof(struct dibDVBTChannel)); ++ dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_UNION, ++ state->i2c_read_buffer, sizeof(struct dibDVBTChannel)); ++ ch = (struct dibDVBTChannel *)state->i2c_read_buffer; ++ + +- switch (ch.spectrum_inversion & 0x7) { ++ switch (ch->spectrum_inversion & 0x7) { + case 1: + state->fe[0]->dtv_property_cache.inversion = INVERSION_ON; + break; +@@ -1162,7 +1188,7 @@ static int dib9000_fw_get_channel(struct + state->fe[0]->dtv_property_cache.inversion = INVERSION_AUTO; + break; + } +- switch (ch.nfft) { ++ switch (ch->nfft) { + case 0: + state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_2K; + break; +@@ -1177,7 +1203,7 @@ static int dib9000_fw_get_channel(struct + state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_AUTO; + break; + } +- switch (ch.guard) { ++ switch (ch->guard) { + case 0: + state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_32; + break; +@@ -1195,7 +1221,7 @@ static int dib9000_fw_get_channel(struct + state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_AUTO; + break; + } +- switch (ch.constellation) { ++ switch (ch->constellation) { + case 2: + state->fe[0]->dtv_property_cache.modulation = QAM_64; + break; +@@ -1210,7 +1236,7 @@ static int dib9000_fw_get_channel(struct + state->fe[0]->dtv_property_cache.modulation = QAM_AUTO; + break; + } +- switch (ch.hrch) { ++ switch (ch->hrch) { + case 0: + state->fe[0]->dtv_property_cache.hierarchy = HIERARCHY_NONE; + break; +@@ -1222,7 +1248,7 @@ static int dib9000_fw_get_channel(struct + state->fe[0]->dtv_property_cache.hierarchy = HIERARCHY_AUTO; + break; + } +- switch (ch.code_rate_hp) { ++ switch (ch->code_rate_hp) { + case 1: + state->fe[0]->dtv_property_cache.code_rate_HP = FEC_1_2; + break; +@@ -1243,7 +1269,7 @@ static int dib9000_fw_get_channel(struct + state->fe[0]->dtv_property_cache.code_rate_HP = FEC_AUTO; + break; + } +- switch (ch.code_rate_lp) { ++ switch (ch->code_rate_lp) { + case 1: + state->fe[0]->dtv_property_cache.code_rate_LP = FEC_1_2; + break; +@@ -1439,9 +1465,10 @@ static int dib9000_fw_tune(struct dvb_fr + break; + case CT_DEMOD_STEP_1: + if (search) +- dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_SEARCH_STATE, (u8 *) &i, 1); ++ dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_SEARCH_STATE, state->i2c_read_buffer, 1); + else +- dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_TUNE_STATE, (u8 *) &i, 1); ++ dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_TUNE_STATE, state->i2c_read_buffer, 1); ++ i = (s8)state->i2c_read_buffer[0]; + switch (i) { /* something happened */ + case 0: + break; +@@ -2038,14 +2065,17 @@ static int dib9000_read_status(struct dv + static int dib9000_read_ber(struct dvb_frontend *fe, u32 * ber) + { + struct dib9000_state *state = fe->demodulator_priv; +- u16 c[16]; ++ u16 *c; + + DibAcquireLock(&state->platform.risc.mem_mbx_lock); + if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) + return -EIO; +- dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, sizeof(c)); ++ dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, ++ state->i2c_read_buffer, 16 * 2); + DibReleaseLock(&state->platform.risc.mem_mbx_lock); + ++ c = (u16 *)state->i2c_read_buffer; ++ + *ber = c[10] << 16 | c[11]; + return 0; + } +@@ -2054,7 +2084,7 @@ static int dib9000_read_signal_strength( + { + struct dib9000_state *state = fe->demodulator_priv; + u8 index_frontend; +- u16 c[16]; ++ u16 *c = (u16 *)state->i2c_read_buffer; + u16 val; + + *strength = 0; +@@ -2069,7 +2099,7 @@ static int dib9000_read_signal_strength( + DibAcquireLock(&state->platform.risc.mem_mbx_lock); + if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) + return -EIO; +- dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, sizeof(c)); ++ dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2); + DibReleaseLock(&state->platform.risc.mem_mbx_lock); + + val = 65535 - c[4]; +@@ -2083,14 +2113,14 @@ static int dib9000_read_signal_strength( + static u32 dib9000_get_snr(struct dvb_frontend *fe) + { + struct dib9000_state *state = fe->demodulator_priv; +- u16 c[16]; ++ u16 *c = (u16 *)state->i2c_read_buffer; + u32 n, s, exp; + u16 val; + + DibAcquireLock(&state->platform.risc.mem_mbx_lock); + if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) + return -EIO; +- dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, sizeof(c)); ++ dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2); + DibReleaseLock(&state->platform.risc.mem_mbx_lock); + + val = c[7]; +@@ -2137,12 +2167,12 @@ static int dib9000_read_snr(struct dvb_f + static int dib9000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc) + { + struct dib9000_state *state = fe->demodulator_priv; +- u16 c[16]; ++ u16 *c = (u16 *)state->i2c_read_buffer; + + DibAcquireLock(&state->platform.risc.mem_mbx_lock); + if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) + return -EIO; +- dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, sizeof(c)); ++ dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2); + DibReleaseLock(&state->platform.risc.mem_mbx_lock); + + *unc = c[12]; +@@ -2151,10 +2181,22 @@ static int dib9000_read_unc_blocks(struc + + int dib9000_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, u8 first_addr) + { +- int k = 0; ++ int k = 0, ret = 0; + u8 new_addr = 0; + struct i2c_device client = {.i2c_adap = i2c }; + ++ client.i2c_write_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL); ++ if (!client.i2c_write_buffer) { ++ dprintk("%s: not enough memory", __func__); ++ return -ENOMEM; ++ } ++ client.i2c_read_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL); ++ if (!client.i2c_read_buffer) { ++ dprintk("%s: not enough memory", __func__); ++ ret = -ENOMEM; ++ goto error_memory; ++ } ++ + client.i2c_addr = default_addr + 16; + dib9000_i2c_write16(&client, 1796, 0x0); + +@@ -2178,7 +2220,8 @@ int dib9000_i2c_enumeration(struct i2c_a + client.i2c_addr = default_addr; + if (dib9000_identify(&client) == 0) { + dprintk("DiB9000 #%d: not identified", k); +- return -EIO; ++ ret = -EIO; ++ goto error; + } + } + +@@ -2196,7 +2239,12 @@ int dib9000_i2c_enumeration(struct i2c_a + dib9000_i2c_write16(&client, 1795, 0); + } + +- return 0; ++error: ++ kfree(client.i2c_read_buffer); ++error_memory: ++ kfree(client.i2c_write_buffer); ++ ++ return ret; + } + EXPORT_SYMBOL(dib9000_i2c_enumeration); + +@@ -2261,6 +2309,8 @@ struct dvb_frontend *dib9000_attach(stru + memcpy(&st->chip.d9.cfg, cfg, sizeof(struct dib9000_config)); + st->i2c.i2c_adap = i2c_adap; + st->i2c.i2c_addr = i2c_addr; ++ st->i2c.i2c_write_buffer = st->i2c_write_buffer; ++ st->i2c.i2c_read_buffer = st->i2c_read_buffer; + + st->gpio_dir = DIB9000_GPIO_DEFAULT_DIRECTIONS; + st->gpio_val = DIB9000_GPIO_DEFAULT_VALUES; +--- a/drivers/media/dvb/frontends/dibx000_common.c ++++ b/drivers/media/dvb/frontends/dibx000_common.c +@@ -10,30 +10,39 @@ MODULE_PARM_DESC(debug, "turn on debuggi + + static int dibx000_write_word(struct dibx000_i2c_master *mst, u16 reg, u16 val) + { +- u8 b[4] = { +- (reg >> 8) & 0xff, reg & 0xff, +- (val >> 8) & 0xff, val & 0xff, +- }; +- struct i2c_msg msg = { +- .addr = mst->i2c_addr,.flags = 0,.buf = b,.len = 4 +- }; ++ mst->i2c_write_buffer[0] = (reg >> 8) & 0xff; ++ mst->i2c_write_buffer[1] = reg & 0xff; ++ mst->i2c_write_buffer[2] = (val >> 8) & 0xff; ++ mst->i2c_write_buffer[3] = val & 0xff; ++ ++ memset(mst->msg, 0, sizeof(struct i2c_msg)); ++ mst->msg[0].addr = mst->i2c_addr; ++ mst->msg[0].flags = 0; ++ mst->msg[0].buf = mst->i2c_write_buffer; ++ mst->msg[0].len = 4; + +- return i2c_transfer(mst->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; ++ return i2c_transfer(mst->i2c_adap, mst->msg, 1) != 1 ? -EREMOTEIO : 0; + } + + static u16 dibx000_read_word(struct dibx000_i2c_master *mst, u16 reg) + { +- u8 wb[2] = { reg >> 8, reg & 0xff }; +- u8 rb[2]; +- struct i2c_msg msg[2] = { +- {.addr = mst->i2c_addr, .flags = 0, .buf = wb, .len = 2}, +- {.addr = mst->i2c_addr, .flags = I2C_M_RD, .buf = rb, .len = 2}, +- }; ++ mst->i2c_write_buffer[0] = reg >> 8; ++ mst->i2c_write_buffer[1] = reg & 0xff; + +- if (i2c_transfer(mst->i2c_adap, msg, 2) != 2) ++ memset(mst->msg, 0, 2 * sizeof(struct i2c_msg)); ++ mst->msg[0].addr = mst->i2c_addr; ++ mst->msg[0].flags = 0; ++ mst->msg[0].buf = mst->i2c_write_buffer; ++ mst->msg[0].len = 2; ++ mst->msg[1].addr = mst->i2c_addr; ++ mst->msg[1].flags = I2C_M_RD; ++ mst->msg[1].buf = mst->i2c_read_buffer; ++ mst->msg[1].len = 2; ++ ++ if (i2c_transfer(mst->i2c_adap, mst->msg, 2) != 2) + dprintk("i2c read error on %d", reg); + +- return (rb[0] << 8) | rb[1]; ++ return (mst->i2c_read_buffer[0] << 8) | mst->i2c_read_buffer[1]; + } + + static int dibx000_is_i2c_done(struct dibx000_i2c_master *mst) +@@ -248,26 +257,32 @@ static int dibx000_i2c_gated_gpio67_xfer + struct i2c_msg msg[], int num) + { + struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap); +- struct i2c_msg m[2 + num]; +- u8 tx_open[4], tx_close[4]; + +- memset(m, 0, sizeof(struct i2c_msg) * (2 + num)); ++ if (num > 32) { ++ dprintk("%s: too much I2C message to be transmitted (%i).\ ++ Maximum is 32", __func__, num); ++ return -ENOMEM; ++ } ++ ++ memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num)); + + dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_6_7); + +- dibx000_i2c_gate_ctrl(mst, tx_open, msg[0].addr, 1); +- m[0].addr = mst->i2c_addr; +- m[0].buf = tx_open; +- m[0].len = 4; +- +- memcpy(&m[1], msg, sizeof(struct i2c_msg) * num); +- +- dibx000_i2c_gate_ctrl(mst, tx_close, 0, 0); +- m[num + 1].addr = mst->i2c_addr; +- m[num + 1].buf = tx_close; +- m[num + 1].len = 4; ++ /* open the gate */ ++ dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1); ++ mst->msg[0].addr = mst->i2c_addr; ++ mst->msg[0].buf = &mst->i2c_write_buffer[0]; ++ mst->msg[0].len = 4; ++ ++ memcpy(&mst->msg[1], msg, sizeof(struct i2c_msg) * num); ++ ++ /* close the gate */ ++ dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[4], 0, 0); ++ mst->msg[num + 1].addr = mst->i2c_addr; ++ mst->msg[num + 1].buf = &mst->i2c_write_buffer[4]; ++ mst->msg[num + 1].len = 4; + +- return i2c_transfer(mst->i2c_adap, m, 2 + num) == 2 + num ? num : -EIO; ++ return i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ? num : -EIO; + } + + static struct i2c_algorithm dibx000_i2c_gated_gpio67_algo = { +@@ -279,26 +294,32 @@ static int dibx000_i2c_gated_tuner_xfer( + struct i2c_msg msg[], int num) + { + struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap); +- struct i2c_msg m[2 + num]; +- u8 tx_open[4], tx_close[4]; + +- memset(m, 0, sizeof(struct i2c_msg) * (2 + num)); ++ if (num > 32) { ++ dprintk("%s: too much I2C message to be transmitted (%i).\ ++ Maximum is 32", __func__, num); ++ return -ENOMEM; ++ } ++ ++ memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num)); + + dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_TUNER); + +- dibx000_i2c_gate_ctrl(mst, tx_open, msg[0].addr, 1); +- m[0].addr = mst->i2c_addr; +- m[0].buf = tx_open; +- m[0].len = 4; +- +- memcpy(&m[1], msg, sizeof(struct i2c_msg) * num); +- +- dibx000_i2c_gate_ctrl(mst, tx_close, 0, 0); +- m[num + 1].addr = mst->i2c_addr; +- m[num + 1].buf = tx_close; +- m[num + 1].len = 4; ++ /* open the gate */ ++ dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1); ++ mst->msg[0].addr = mst->i2c_addr; ++ mst->msg[0].buf = &mst->i2c_write_buffer[0]; ++ mst->msg[0].len = 4; ++ ++ memcpy(&mst->msg[1], msg, sizeof(struct i2c_msg) * num); ++ ++ /* close the gate */ ++ dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[4], 0, 0); ++ mst->msg[num + 1].addr = mst->i2c_addr; ++ mst->msg[num + 1].buf = &mst->i2c_write_buffer[4]; ++ mst->msg[num + 1].len = 4; + +- return i2c_transfer(mst->i2c_adap, m, 2 + num) == 2 + num ? num : -EIO; ++ return i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ? num : -EIO; + } + + static struct i2c_algorithm dibx000_i2c_gated_tuner_algo = { +--- a/drivers/media/dvb/frontends/dibx000_common.h ++++ b/drivers/media/dvb/frontends/dibx000_common.h +@@ -28,6 +28,11 @@ struct dibx000_i2c_master { + u8 i2c_addr; + + u16 base_reg; ++ ++ /* for the I2C transfer */ ++ struct i2c_msg msg[34]; ++ u8 i2c_write_buffer[8]; ++ u8 i2c_read_buffer[2]; + }; + + extern int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, diff --git a/queue-2.6.39/ecryptfs-allow-2-scatterlist-entries-for-encrypted.patch b/queue-2.6.39/ecryptfs-allow-2-scatterlist-entries-for-encrypted.patch new file mode 100644 index 0000000000..7996ece1c1 --- /dev/null +++ b/queue-2.6.39/ecryptfs-allow-2-scatterlist-entries-for-encrypted.patch @@ -0,0 +1,143 @@ +From 8d08dab786ad5cc2aca2bf870de370144b78c85a Mon Sep 17 00:00:00 2001 +From: Tyler Hicks <tyhicks@linux.vnet.ibm.com> +Date: Tue, 17 May 2011 00:50:33 -0500 +Subject: eCryptfs: Allow 2 scatterlist entries for encrypted + filenames + +From: Tyler Hicks <tyhicks@linux.vnet.ibm.com> + +commit 8d08dab786ad5cc2aca2bf870de370144b78c85a upstream. + +The buffers allocated while encrypting and decrypting long filenames can +sometimes straddle two pages. In this situation, virt_to_scatterlist() +will return -ENOMEM, causing the operation to fail and the user will get +scary error messages in their logs: + +kernel: ecryptfs_write_tag_70_packet: Internal error whilst attempting +to convert filename memory to scatterlist; expected rc = 1; got rc = +[-12]. block_aligned_filename_size = [272] +kernel: ecryptfs_encrypt_filename: Error attempting to generate tag 70 +packet; rc = [-12] +kernel: ecryptfs_encrypt_and_encode_filename: Error attempting to +encrypt filename; rc = [-12] +kernel: ecryptfs_lookup: Error attempting to encrypt and encode +filename; rc = [-12] + +The solution is to allow up to 2 scatterlist entries to be used. + +Signed-off-by: Tyler Hicks <tyhicks@linux.vnet.ibm.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + fs/ecryptfs/keystore.c | 46 +++++++++++++++++++++------------------------- + 1 file changed, 21 insertions(+), 25 deletions(-) + +--- a/fs/ecryptfs/keystore.c ++++ b/fs/ecryptfs/keystore.c +@@ -599,8 +599,8 @@ struct ecryptfs_write_tag_70_packet_sill + struct mutex *tfm_mutex; + char *block_aligned_filename; + struct ecryptfs_auth_tok *auth_tok; +- struct scatterlist src_sg; +- struct scatterlist dst_sg; ++ struct scatterlist src_sg[2]; ++ struct scatterlist dst_sg[2]; + struct blkcipher_desc desc; + char iv[ECRYPTFS_MAX_IV_BYTES]; + char hash[ECRYPTFS_TAG_70_DIGEST_SIZE]; +@@ -816,23 +816,21 @@ ecryptfs_write_tag_70_packet(char *dest, + memcpy(&s->block_aligned_filename[s->num_rand_bytes], filename, + filename_size); + rc = virt_to_scatterlist(s->block_aligned_filename, +- s->block_aligned_filename_size, &s->src_sg, 1); +- if (rc != 1) { ++ s->block_aligned_filename_size, s->src_sg, 2); ++ if (rc < 1) { + printk(KERN_ERR "%s: Internal error whilst attempting to " +- "convert filename memory to scatterlist; " +- "expected rc = 1; got rc = [%d]. " ++ "convert filename memory to scatterlist; rc = [%d]. " + "block_aligned_filename_size = [%zd]\n", __func__, rc, + s->block_aligned_filename_size); + goto out_release_free_unlock; + } + rc = virt_to_scatterlist(&dest[s->i], s->block_aligned_filename_size, +- &s->dst_sg, 1); +- if (rc != 1) { ++ s->dst_sg, 2); ++ if (rc < 1) { + printk(KERN_ERR "%s: Internal error whilst attempting to " + "convert encrypted filename memory to scatterlist; " +- "expected rc = 1; got rc = [%d]. " +- "block_aligned_filename_size = [%zd]\n", __func__, rc, +- s->block_aligned_filename_size); ++ "rc = [%d]. block_aligned_filename_size = [%zd]\n", ++ __func__, rc, s->block_aligned_filename_size); + goto out_release_free_unlock; + } + /* The characters in the first block effectively do the job +@@ -855,7 +853,7 @@ ecryptfs_write_tag_70_packet(char *dest, + mount_crypt_stat->global_default_fn_cipher_key_bytes); + goto out_release_free_unlock; + } +- rc = crypto_blkcipher_encrypt_iv(&s->desc, &s->dst_sg, &s->src_sg, ++ rc = crypto_blkcipher_encrypt_iv(&s->desc, s->dst_sg, s->src_sg, + s->block_aligned_filename_size); + if (rc) { + printk(KERN_ERR "%s: Error attempting to encrypt filename; " +@@ -891,8 +889,8 @@ struct ecryptfs_parse_tag_70_packet_sill + struct mutex *tfm_mutex; + char *decrypted_filename; + struct ecryptfs_auth_tok *auth_tok; +- struct scatterlist src_sg; +- struct scatterlist dst_sg; ++ struct scatterlist src_sg[2]; ++ struct scatterlist dst_sg[2]; + struct blkcipher_desc desc; + char fnek_sig_hex[ECRYPTFS_SIG_SIZE_HEX + 1]; + char iv[ECRYPTFS_MAX_IV_BYTES]; +@@ -1008,13 +1006,12 @@ ecryptfs_parse_tag_70_packet(char **file + } + mutex_lock(s->tfm_mutex); + rc = virt_to_scatterlist(&data[(*packet_size)], +- s->block_aligned_filename_size, &s->src_sg, 1); +- if (rc != 1) { ++ s->block_aligned_filename_size, s->src_sg, 2); ++ if (rc < 1) { + printk(KERN_ERR "%s: Internal error whilst attempting to " + "convert encrypted filename memory to scatterlist; " +- "expected rc = 1; got rc = [%d]. " +- "block_aligned_filename_size = [%zd]\n", __func__, rc, +- s->block_aligned_filename_size); ++ "rc = [%d]. block_aligned_filename_size = [%zd]\n", ++ __func__, rc, s->block_aligned_filename_size); + goto out_unlock; + } + (*packet_size) += s->block_aligned_filename_size; +@@ -1028,13 +1025,12 @@ ecryptfs_parse_tag_70_packet(char **file + goto out_unlock; + } + rc = virt_to_scatterlist(s->decrypted_filename, +- s->block_aligned_filename_size, &s->dst_sg, 1); +- if (rc != 1) { ++ s->block_aligned_filename_size, s->dst_sg, 2); ++ if (rc < 1) { + printk(KERN_ERR "%s: Internal error whilst attempting to " + "convert decrypted filename memory to scatterlist; " +- "expected rc = 1; got rc = [%d]. " +- "block_aligned_filename_size = [%zd]\n", __func__, rc, +- s->block_aligned_filename_size); ++ "rc = [%d]. block_aligned_filename_size = [%zd]\n", ++ __func__, rc, s->block_aligned_filename_size); + goto out_free_unlock; + } + /* The characters in the first block effectively do the job of +@@ -1065,7 +1061,7 @@ ecryptfs_parse_tag_70_packet(char **file + mount_crypt_stat->global_default_fn_cipher_key_bytes); + goto out_free_unlock; + } +- rc = crypto_blkcipher_decrypt_iv(&s->desc, &s->dst_sg, &s->src_sg, ++ rc = crypto_blkcipher_decrypt_iv(&s->desc, s->dst_sg, s->src_sg, + s->block_aligned_filename_size); + if (rc) { + printk(KERN_ERR "%s: Error attempting to decrypt filename; " diff --git a/queue-2.6.39/ecryptfs-clear-i_nlink-in-rmdir.patch b/queue-2.6.39/ecryptfs-clear-i_nlink-in-rmdir.patch new file mode 100644 index 0000000000..491b7c2813 --- /dev/null +++ b/queue-2.6.39/ecryptfs-clear-i_nlink-in-rmdir.patch @@ -0,0 +1,33 @@ +From 07850552b92b3637fa56767b5e460b4238014447 Mon Sep 17 00:00:00 2001 +From: Tyler Hicks <tyhicks@linux.vnet.ibm.com> +Date: Fri, 29 Apr 2011 16:26:27 -0500 +Subject: eCryptfs: Clear i_nlink in rmdir + +From: Tyler Hicks <tyhicks@linux.vnet.ibm.com> + +commit 07850552b92b3637fa56767b5e460b4238014447 upstream. + +eCryptfs wasn't clearing the eCryptfs inode's i_nlink after a successful +vfs_rmdir() on the lower directory. This resulted in the inode evict and +destroy paths to be missed. + +https://bugs.launchpad.net/ecryptfs/+bug/723518 + +Signed-off-by: Tyler Hicks <tyhicks@linux.vnet.ibm.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + fs/ecryptfs/inode.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/fs/ecryptfs/inode.c ++++ b/fs/ecryptfs/inode.c +@@ -527,6 +527,8 @@ static int ecryptfs_rmdir(struct inode * + dget(lower_dentry); + rc = vfs_rmdir(lower_dir_dentry->d_inode, lower_dentry); + dput(lower_dentry); ++ if (!rc && dentry->d_inode) ++ clear_nlink(dentry->d_inode); + fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode); + dir->i_nlink = lower_dir_dentry->d_inode->i_nlink; + unlock_dir(lower_dir_dentry); diff --git a/queue-2.6.39/mfd-fix-omap-usbhs-crash-when-rmmoding-ehci-or-ohci.patch b/queue-2.6.39/mfd-fix-omap-usbhs-crash-when-rmmoding-ehci-or-ohci.patch new file mode 100644 index 0000000000..2f16127d6d --- /dev/null +++ b/queue-2.6.39/mfd-fix-omap-usbhs-crash-when-rmmoding-ehci-or-ohci.patch @@ -0,0 +1,67 @@ +From 6eb6fbbf3eca6dfba73e72de5ab2eeb52ae41f7a Mon Sep 17 00:00:00 2001 +From: Keshava Munegowda <Keshava_mgowda@ti.com> +Date: Mon, 16 May 2011 14:24:58 +0530 +Subject: mfd: Fix omap usbhs crash when rmmoding ehci or ohci + +From: Keshava Munegowda <Keshava_mgowda@ti.com> + +commit 6eb6fbbf3eca6dfba73e72de5ab2eeb52ae41f7a upstream. + +The disabling of clocks and freeing GPIO are changed +to fix the occurrence of the crash of rmmod of ehci and ohci +drivers. The GPIOs should be freed after the spin locks are +unlocked. + +Signed-off-by: Keshava Munegowda <keshava_mgowda@ti.com> +Acked-by: Felipe Balbi <balbi@ti.com> +Signed-off-by: Samuel Ortiz <sameo@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/mfd/omap-usb-host.c | 27 +++++++++++++++++++-------- + 1 file changed, 19 insertions(+), 8 deletions(-) + +--- a/drivers/mfd/omap-usb-host.c ++++ b/drivers/mfd/omap-usb-host.c +@@ -994,22 +994,33 @@ static void usbhs_disable(struct device + dev_dbg(dev, "operation timed out\n"); + } + +- if (pdata->ehci_data->phy_reset) { +- if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) +- gpio_free(pdata->ehci_data->reset_gpio_port[0]); +- +- if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) +- gpio_free(pdata->ehci_data->reset_gpio_port[1]); ++ if (is_omap_usbhs_rev2(omap)) { ++ if (is_ehci_tll_mode(pdata->port_mode[0])) ++ clk_enable(omap->usbtll_p1_fck); ++ if (is_ehci_tll_mode(pdata->port_mode[1])) ++ clk_enable(omap->usbtll_p2_fck); ++ clk_disable(omap->utmi_p2_fck); ++ clk_disable(omap->utmi_p1_fck); + } + +- clk_disable(omap->utmi_p2_fck); +- clk_disable(omap->utmi_p1_fck); + clk_disable(omap->usbtll_ick); + clk_disable(omap->usbtll_fck); + clk_disable(omap->usbhost_fs_fck); + clk_disable(omap->usbhost_hs_fck); + clk_disable(omap->usbhost_ick); + ++ /* The gpio_free migh sleep; so unlock the spinlock */ ++ spin_unlock_irqrestore(&omap->lock, flags); ++ ++ if (pdata->ehci_data->phy_reset) { ++ if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) ++ gpio_free(pdata->ehci_data->reset_gpio_port[0]); ++ ++ if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) ++ gpio_free(pdata->ehci_data->reset_gpio_port[1]); ++ } ++ return; ++ + end_disble: + spin_unlock_irqrestore(&omap->lock, flags); + } diff --git a/queue-2.6.39/ohci-fix-regression-caused-by-nvidia-shutdown-workaround.patch b/queue-2.6.39/ohci-fix-regression-caused-by-nvidia-shutdown-workaround.patch new file mode 100644 index 0000000000..a037f48311 --- /dev/null +++ b/queue-2.6.39/ohci-fix-regression-caused-by-nvidia-shutdown-workaround.patch @@ -0,0 +1,68 @@ +From 2b7aaf503d56216b847c8265421d2a7d9b42df3e Mon Sep 17 00:00:00 2001 +From: Alan Stern <stern@rowland.harvard.edu> +Date: Mon, 16 May 2011 12:15:19 -0400 +Subject: OHCI: fix regression caused by nVidia shutdown workaround + +From: Alan Stern <stern@rowland.harvard.edu> + +commit 2b7aaf503d56216b847c8265421d2a7d9b42df3e upstream. + +This patch (as1463) fixes a regression caused by commit +3df7169e73fc1d71a39cffeacc969f6840cdf52b (OHCI: work around for nVidia +shutdown problem). + +The original problem encountered by people using NVIDIA chipsets was +that USB devices were not turning off when the system shut down. For +example, the LED on an optical mouse would remain on, draining a +laptop's battery. The problem was caused by a bug in the chipset; an +OHCI controller in the Reset state would continue to drive a bus reset +signal even after system shutdown. The workaround was to put the +controllers into the Suspend state instead. + +It turns out that later NVIDIA chipsets do not suffer from this bug. +Instead some have the opposite bug: If a system is shut down while an +OHCI controller is in the Suspend state, USB devices remain powered! +On other systems, shutting down with a Suspended controller causes the +system to reboot immediately. Thus, working around the original bug +on some machines exposes other bugs on other machines. + +The best solution seems to be to limit the workaround to OHCI +controllers with a low-numbered PCI product ID. I don't know exactly +at what point NVIDIA changed their chipsets; the value used here is a +guess. So far it was worked out okay for all the people who have +tested it. + +This fixes Bugzilla #35032. + +Signed-off-by: Alan Stern <stern@rowland.harvard.edu> +Tested-by: Andre "Osku" Schmidt <andre.osku.schmidt@googlemail.com> +Tested-by: Yury Siamashka <yurand2@gmail.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/host/ohci-pci.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +--- a/drivers/usb/host/ohci-pci.c ++++ b/drivers/usb/host/ohci-pci.c +@@ -181,10 +181,18 @@ static int ohci_quirk_amd700(struct usb_ + */ + static int ohci_quirk_nvidia_shutdown(struct usb_hcd *hcd) + { ++ struct pci_dev *pdev = to_pci_dev(hcd->self.controller); + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + +- ohci->flags |= OHCI_QUIRK_SHUTDOWN; +- ohci_dbg(ohci, "enabled nVidia shutdown quirk\n"); ++ /* Evidently nVidia fixed their later hardware; this is a guess at ++ * the changeover point. ++ */ ++#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_USB 0x026d ++ ++ if (pdev->device < PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_USB) { ++ ohci->flags |= OHCI_QUIRK_SHUTDOWN; ++ ohci_dbg(ohci, "enabled nVidia shutdown quirk\n"); ++ } + + return 0; + } diff --git a/queue-2.6.39/p54usb-add-zoom-4410-usbid.patch b/queue-2.6.39/p54usb-add-zoom-4410-usbid.patch new file mode 100644 index 0000000000..979aaea9c1 --- /dev/null +++ b/queue-2.6.39/p54usb-add-zoom-4410-usbid.patch @@ -0,0 +1,28 @@ +From 9368a9a2378ab721f82f59430a135b4ce4ff5109 Mon Sep 17 00:00:00 2001 +From: Christian Lamparter <chunkeey@googlemail.com> +Date: Fri, 13 May 2011 21:47:23 +0200 +Subject: p54usb: add zoom 4410 usbid + +From: Christian Lamparter <chunkeey@googlemail.com> + +commit 9368a9a2378ab721f82f59430a135b4ce4ff5109 upstream. + +Reported-by: Mark Davis <marked86@gmail.com> +Signed-off-by: Christian Lamparter <chunkeey@googlemail.com> +Signed-off-by: John W. Linville <linville@tuxdriver.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/net/wireless/p54/p54usb.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/net/wireless/p54/p54usb.c ++++ b/drivers/net/wireless/p54/p54usb.c +@@ -82,6 +82,7 @@ static struct usb_device_id p54u_table[] + {USB_DEVICE(0x06b9, 0x0121)}, /* Thomson SpeedTouch 121g */ + {USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */ + {USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */ ++ {USB_DEVICE(0x083a, 0xc501)}, /* Zoom Wireless-G 4410 */ + {USB_DEVICE(0x083a, 0xf503)}, /* Accton FD7050E ver 1010ec */ + {USB_DEVICE(0x0846, 0x4240)}, /* Netgear WG111 (v2) */ + {USB_DEVICE(0x0915, 0x2000)}, /* Cohiba Proto board */ diff --git a/queue-2.6.39/series b/queue-2.6.39/series index 68a5444f5a..f222988a83 100644 --- a/queue-2.6.39/series +++ b/queue-2.6.39/series @@ -104,3 +104,29 @@ loop-limit-max_part-module-param-to-disk_max_parts.patch loop-handle-on-demand-devices-correctly.patch i2c-tegra-enable-new-slave-mode.patch i2c-writing-clients-fix-foo_driver.id_table.patch +usb-cp210x-add-4-device-ids-for-ac-services-devices.patch +usb-moto_modem-add-usb-identifier-for-the-motorola-ve240.patch +usb-serial-ftdi_sio-adding-support-for-tavir-stk500.patch +usb-gadget-g_multi-fixed-vendor-and-product-id-in-inf.patch +usb-gamin_gps-fix-for-data-transfer-problems-in-native.patch +bind-only-modem-at-command-endpoint-to-option-module.patch +usb-cdc_acm-fix-oops-when-droids-muin-lcd-is-connected.patch +xhci-fix-bug-in-control-transfer-cancellation.patch +usb-gadget-at91sam9g20-fix-end-point-max-packet-size.patch +usb-gadget-rndis-don-t-test-against-req-length.patch +xhci-fix-full-speed-binterval-encoding.patch +xhci-fix-memory-leak-in-ring-cache-deallocation.patch +xhci-fix-memory-leak-bug-when-dropping-endpoints.patch +usb-option-add-support-for-huawei-e353-device.patch +ohci-fix-regression-caused-by-nvidia-shutdown-workaround.patch +usb-remove-remaining-usages-of-hcd-state-from-usbcore-and.patch +dibxxxx-get-rid-of-dma-buffer-on-stack.patch +cx88-protect-per-device-driver-list-with-device.patch +cx88-fix-locking-of-sub-driver-operations.patch +cx88-hold-device-lock-during-sub-driver.patch +sh-clkfwk-fixup-clk_rate_table_build-parameter-in-div6.patch +sh-fixup-fpu.o-compile-order.patch +mfd-fix-omap-usbhs-crash-when-rmmoding-ehci-or-ohci.patch +p54usb-add-zoom-4410-usbid.patch +ecryptfs-clear-i_nlink-in-rmdir.patch +ecryptfs-allow-2-scatterlist-entries-for-encrypted.patch diff --git a/queue-2.6.39/sh-clkfwk-fixup-clk_rate_table_build-parameter-in-div6.patch b/queue-2.6.39/sh-clkfwk-fixup-clk_rate_table_build-parameter-in-div6.patch new file mode 100644 index 0000000000..4a78dfa440 --- /dev/null +++ b/queue-2.6.39/sh-clkfwk-fixup-clk_rate_table_build-parameter-in-div6.patch @@ -0,0 +1,33 @@ +From 52c10ad22b7e317960b4d411c9a9ddeaf3d5ae39 Mon Sep 17 00:00:00 2001 +From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> +Date: Thu, 14 Apr 2011 17:13:53 +0900 +Subject: sh: clkfwk: fixup clk_rate_table_build parameter in div6 + clock + +From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> + +commit 52c10ad22b7e317960b4d411c9a9ddeaf3d5ae39 upstream. + +div6 clock should not use arch_flags for clk_rate_table_build, +because SH_CLK_DIV6_EXT doesn't care .arch_flags. +clk->freq_table[] will be all CPUFREQ_ENTRY_INVALID without this patch. + +Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> +Signed-off-by: Paul Mundt <lethal@linux-sh.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/sh/clk/cpg.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/sh/clk/cpg.c ++++ b/drivers/sh/clk/cpg.c +@@ -105,7 +105,7 @@ static int sh_clk_div6_set_parent(struct + + /* Rebuild the frequency table */ + clk_rate_table_build(clk, clk->freq_table, table->nr_divisors, +- table, &clk->arch_flags); ++ table, NULL); + + return 0; + } diff --git a/queue-2.6.39/sh-fixup-fpu.o-compile-order.patch b/queue-2.6.39/sh-fixup-fpu.o-compile-order.patch new file mode 100644 index 0000000000..26f5fb484c --- /dev/null +++ b/queue-2.6.39/sh-fixup-fpu.o-compile-order.patch @@ -0,0 +1,38 @@ +From a375b15164dd9264f724ad941825e52c90145151 Mon Sep 17 00:00:00 2001 +From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> +Date: Fri, 15 Apr 2011 16:44:27 +0900 +Subject: sh: fixup fpu.o compile order + +From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> + +commit a375b15164dd9264f724ad941825e52c90145151 upstream. + +arch_ptrace() was modified to reference init_fpu() to fix up xstate +initialization, which overlooked the fact that there are configurations +that don't enable any of hard FPU support or emulation, resulting in +build errors on DSP parts. + +Given that init_fpu() simply sets up the xstate slab cache and is +side-stepped entirely for the DSP case, we can simply always build in the +helper and fix up the references. + +Reported-by: Nobuhiro Iwamatsu <iwamatsu@nigauri.org> +Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> +Signed-off-by: Paul Mundt <lethal@linux-sh.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + arch/sh/kernel/cpu/Makefile | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +--- a/arch/sh/kernel/cpu/Makefile ++++ b/arch/sh/kernel/cpu/Makefile +@@ -17,7 +17,5 @@ obj-$(CONFIG_ARCH_SHMOBILE) += shmobile/ + + obj-$(CONFIG_SH_ADC) += adc.o + obj-$(CONFIG_SH_CLK_CPG_LEGACY) += clock-cpg.o +-obj-$(CONFIG_SH_FPU) += fpu.o +-obj-$(CONFIG_SH_FPU_EMU) += fpu.o + +-obj-y += irq/ init.o clock.o hwblk.o proc.o ++obj-y += irq/ init.o clock.o fpu.o hwblk.o proc.o diff --git a/queue-2.6.39/usb-cdc_acm-fix-oops-when-droids-muin-lcd-is-connected.patch b/queue-2.6.39/usb-cdc_acm-fix-oops-when-droids-muin-lcd-is-connected.patch new file mode 100644 index 0000000000..b169b3b372 --- /dev/null +++ b/queue-2.6.39/usb-cdc_acm-fix-oops-when-droids-muin-lcd-is-connected.patch @@ -0,0 +1,70 @@ +From fd5054c169d29747a44b4e1419ff47f57ae82dbc Mon Sep 17 00:00:00 2001 +From: Erik Slagter <erik@slagter.name> +Date: Wed, 11 May 2011 12:06:55 +0200 +Subject: USB: cdc_acm: Fix oops when Droids MuIn LCD is connected + +From: Erik Slagter <erik@slagter.name> + +commit fd5054c169d29747a44b4e1419ff47f57ae82dbc upstream. + +The Droids MuIn LCD operates like a serial remote terminal. +Data received are displayed directly on the LCD. This patch +fixes the kernel null pointer oops when it is plugged in. + +Add NO_DATA_INTERFACE quirk to tell the driver that "control" +and "data" interfaces are not separated for this device, which +prevents dereferencing a null pointer in the device probe code. + +Signed-off-by: Erik Slagter <erik@slagter.name> +Signed-off-by: Maxin B. John <maxin.john@gmail.com> +Tested-by: Erik Slagter <erik@slagter.name> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/class/cdc-acm.c | 13 +++++++++++-- + drivers/usb/class/cdc-acm.h | 1 + + 2 files changed, 12 insertions(+), 2 deletions(-) + +--- a/drivers/usb/class/cdc-acm.c ++++ b/drivers/usb/class/cdc-acm.c +@@ -946,7 +946,7 @@ static int acm_probe(struct usb_interfac + u8 ac_management_function = 0; + u8 call_management_function = 0; + int call_interface_num = -1; +- int data_interface_num; ++ int data_interface_num = -1; + unsigned long quirks; + int num_rx_buf; + int i; +@@ -1030,7 +1030,11 @@ next_desc: + if (!union_header) { + if (call_interface_num > 0) { + dev_dbg(&intf->dev, "No union descriptor, using call management descriptor\n"); +- data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num)); ++ /* quirks for Droids MuIn LCD */ ++ if (quirks & NO_DATA_INTERFACE) ++ data_interface = usb_ifnum_to_if(usb_dev, 0); ++ else ++ data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num)); + control_interface = intf; + } else { + if (intf->cur_altsetting->desc.bNumEndpoints != 3) { +@@ -1622,6 +1626,11 @@ static const struct usb_device_id acm_id + .driver_info = NOT_A_MODEM, + }, + ++ /* Support for Droids MuIn LCD */ ++ { USB_DEVICE(0x04d8, 0x000b), ++ .driver_info = NO_DATA_INTERFACE, ++ }, ++ + /* control interfaces without any protocol set */ + { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, + USB_CDC_PROTO_NONE) }, +--- a/drivers/usb/class/cdc-acm.h ++++ b/drivers/usb/class/cdc-acm.h +@@ -137,3 +137,4 @@ struct acm { + #define SINGLE_RX_URB 2 + #define NO_CAP_LINE 4 + #define NOT_A_MODEM 8 ++#define NO_DATA_INTERFACE 16 diff --git a/queue-2.6.39/usb-cp210x-add-4-device-ids-for-ac-services-devices.patch b/queue-2.6.39/usb-cp210x-add-4-device-ids-for-ac-services-devices.patch new file mode 100644 index 0000000000..6c2b131b8d --- /dev/null +++ b/queue-2.6.39/usb-cp210x-add-4-device-ids-for-ac-services-devices.patch @@ -0,0 +1,32 @@ +From 4eff0b40a7174896b860312910e0db51f2dcc567 Mon Sep 17 00:00:00 2001 +From: Craig Shelley <craig@microtron.org.uk> +Date: Sun, 20 Mar 2011 13:51:13 +0000 +Subject: USB: CP210x Add 4 Device IDs for AC-Services Devices + +From: Craig Shelley <craig@microtron.org.uk> + +commit 4eff0b40a7174896b860312910e0db51f2dcc567 upstream. + +This patch adds 4 device IDs for CP2102 based devices manufactured by +AC-Services. See http://www.ac-services.eu for further info. + +Signed-off-by: Craig Shelley <craig@microtron.org.uk> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/serial/cp210x.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/usb/serial/cp210x.c ++++ b/drivers/usb/serial/cp210x.c +@@ -112,6 +112,10 @@ static const struct usb_device_id id_tab + { USB_DEVICE(0x10C4, 0x8418) }, /* IRZ Automation Teleport SG-10 GSM/GPRS Modem */ + { USB_DEVICE(0x10C4, 0x846E) }, /* BEI USB Sensor Interface (VCP) */ + { USB_DEVICE(0x10C4, 0x8477) }, /* Balluff RFID */ ++ { USB_DEVICE(0x10C4, 0x85EA) }, /* AC-Services IBUS-IF */ ++ { USB_DEVICE(0x10C4, 0x85EB) }, /* AC-Services CIS-IBUS */ ++ { USB_DEVICE(0x10C4, 0x8664) }, /* AC-Services CAN-IF */ ++ { USB_DEVICE(0x10C4, 0x8665) }, /* AC-Services OBD-IF */ + { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */ + { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */ + { USB_DEVICE(0x10C4, 0xEA71) }, /* Infinity GPS-MIC-1 Radio Monophone */ diff --git a/queue-2.6.39/usb-gadget-at91sam9g20-fix-end-point-max-packet-size.patch b/queue-2.6.39/usb-gadget-at91sam9g20-fix-end-point-max-packet-size.patch new file mode 100644 index 0000000000..e446d0558a --- /dev/null +++ b/queue-2.6.39/usb-gadget-at91sam9g20-fix-end-point-max-packet-size.patch @@ -0,0 +1,30 @@ +From bf1f0a05d472e33dda8e5e69525be1584cdbd03a Mon Sep 17 00:00:00 2001 +From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +Date: Fri, 13 May 2011 17:03:02 +0200 +Subject: usb/gadget: at91sam9g20 fix end point max packet size + +From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> + +commit bf1f0a05d472e33dda8e5e69525be1584cdbd03a upstream. + +on 9g20 they are the same as the 9260 + +Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/gadget/at91_udc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/usb/gadget/at91_udc.c ++++ b/drivers/usb/gadget/at91_udc.c +@@ -1767,7 +1767,7 @@ static int __init at91udc_probe(struct p + } + + /* newer chips have more FIFO memory than rm9200 */ +- if (cpu_is_at91sam9260()) { ++ if (cpu_is_at91sam9260() || cpu_is_at91sam9g20()) { + udc->ep[0].maxpacket = 64; + udc->ep[3].maxpacket = 64; + udc->ep[4].maxpacket = 512; diff --git a/queue-2.6.39/usb-gadget-g_multi-fixed-vendor-and-product-id-in-inf.patch b/queue-2.6.39/usb-gadget-g_multi-fixed-vendor-and-product-id-in-inf.patch new file mode 100644 index 0000000000..22802b2735 --- /dev/null +++ b/queue-2.6.39/usb-gadget-g_multi-fixed-vendor-and-product-id-in-inf.patch @@ -0,0 +1,60 @@ +From 7701846fd52f86dffe50715e0e63154088b7c982 Mon Sep 17 00:00:00 2001 +From: Michal Nazarewicz <mina86@mina86.com> +Date: Tue, 26 Apr 2011 19:08:36 +0200 +Subject: USB: gadget: g_multi: fixed vendor and product ID in inf + files + +From: Michal Nazarewicz <mina86@mina86.com> + +commit 7701846fd52f86dffe50715e0e63154088b7c982 upstream. + +Commit 1c6529e92b "USB: gadget: g_multi: fixed vendor and +product ID" replaced g_multi's vendor and product ID with +proper ID's from Linux Foundation. This commit now updates +INF files in the Documentation/usb directory which were +omitted in the original commit. + +Signed-off-by: Michal Nazarewicz <mina86@mina86.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + Documentation/usb/linux-cdc-acm.inf | 4 ++-- + Documentation/usb/linux.inf | 6 +++--- + 2 files changed, 5 insertions(+), 5 deletions(-) + +--- a/Documentation/usb/linux-cdc-acm.inf ++++ b/Documentation/usb/linux-cdc-acm.inf +@@ -90,10 +90,10 @@ ServiceBinary=%12%\USBSER.sys + [SourceDisksFiles] + [SourceDisksNames] + [DeviceList] +-%DESCRIPTION%=DriverInstall, USB\VID_0525&PID_A4A7, USB\VID_0525&PID_A4AB&MI_02 ++%DESCRIPTION%=DriverInstall, USB\VID_0525&PID_A4A7, USB\VID_1D6B&PID_0104&MI_02 + + [DeviceList.NTamd64] +-%DESCRIPTION%=DriverInstall, USB\VID_0525&PID_A4A7, USB\VID_0525&PID_A4AB&MI_02 ++%DESCRIPTION%=DriverInstall, USB\VID_0525&PID_A4A7, USB\VID_1D6B&PID_0104&MI_02 + + + ;------------------------------------------------------------------------------ +--- a/Documentation/usb/linux.inf ++++ b/Documentation/usb/linux.inf +@@ -18,15 +18,15 @@ DriverVer = 06/21/2006,6.0.600 + + ; Decoration for x86 architecture + [LinuxDevices.NTx86] +-%LinuxDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2, USB\VID_0525&PID_a4ab&MI_00 ++%LinuxDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2, USB\VID_1d6b&PID_0104&MI_00 + + ; Decoration for x64 architecture + [LinuxDevices.NTamd64] +-%LinuxDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2, USB\VID_0525&PID_a4ab&MI_00 ++%LinuxDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2, USB\VID_1d6b&PID_0104&MI_00 + + ; Decoration for ia64 architecture + [LinuxDevices.NTia64] +-%LinuxDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2, USB\VID_0525&PID_a4ab&MI_00 ++%LinuxDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2, USB\VID_1d6b&PID_0104&MI_00 + + ;@@@ This is the common setting for setup + [ControlFlags] diff --git a/queue-2.6.39/usb-gadget-rndis-don-t-test-against-req-length.patch b/queue-2.6.39/usb-gadget-rndis-don-t-test-against-req-length.patch new file mode 100644 index 0000000000..f878fa39c1 --- /dev/null +++ b/queue-2.6.39/usb-gadget-rndis-don-t-test-against-req-length.patch @@ -0,0 +1,38 @@ +From 472b91274a6c6857877b5caddb875dcb5ecdfcb8 Mon Sep 17 00:00:00 2001 +From: Felipe Balbi <balbi@ti.com> +Date: Fri, 13 May 2011 16:53:48 +0300 +Subject: usb: gadget: rndis: don't test against req->length + +From: Felipe Balbi <balbi@ti.com> + +commit 472b91274a6c6857877b5caddb875dcb5ecdfcb8 upstream. + +composite.c always sets req->length to zero +and expects function driver's setup handlers +to return the amount of bytes to be used +on req->length. If we test against req->length +w_length will always be greater than req->length +thus making us always stall that particular +SEND_ENCAPSULATED_COMMAND request. + +Tested against a Windows XP SP3. + +Signed-off-by: Felipe Balbi <balbi@ti.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/gadget/f_rndis.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +--- a/drivers/usb/gadget/f_rndis.c ++++ b/drivers/usb/gadget/f_rndis.c +@@ -420,8 +420,7 @@ rndis_setup(struct usb_function *f, cons + */ + case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8) + | USB_CDC_SEND_ENCAPSULATED_COMMAND: +- if (w_length > req->length || w_value +- || w_index != rndis->ctrl_id) ++ if (w_value || w_index != rndis->ctrl_id) + goto invalid; + /* read the request; process it later */ + value = w_length; diff --git a/queue-2.6.39/usb-gamin_gps-fix-for-data-transfer-problems-in-native.patch b/queue-2.6.39/usb-gamin_gps-fix-for-data-transfer-problems-in-native.patch new file mode 100644 index 0000000000..28031fbc4e --- /dev/null +++ b/queue-2.6.39/usb-gamin_gps-fix-for-data-transfer-problems-in-native.patch @@ -0,0 +1,115 @@ +From b4026c4584cd70858d4d3450abfb1cd0714d4f32 Mon Sep 17 00:00:00 2001 +From: Hermann Kneissel <herkne@gmx.de> +Date: Fri, 29 Apr 2011 08:58:43 +0200 +Subject: USB: gamin_gps: Fix for data transfer problems in native + mode + +From: Hermann Kneissel <herkne@gmx.de> + +commit b4026c4584cd70858d4d3450abfb1cd0714d4f32 upstream. + +This patch fixes a problem where data received from the gps is sometimes +transferred incompletely to the serial port. If used in native mode now +all data received via the bulk queue will be forwarded to the serial +port. + +Signed-off-by: Hermann Kneissel <herkne@gmx.de> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/serial/garmin_gps.c | 20 +++++++++++++------- + 1 file changed, 13 insertions(+), 7 deletions(-) + +--- a/drivers/usb/serial/garmin_gps.c ++++ b/drivers/usb/serial/garmin_gps.c +@@ -1,7 +1,7 @@ + /* + * Garmin GPS driver + * +- * Copyright (C) 2006-2009 Hermann Kneissel herkne@users.sourceforge.net ++ * Copyright (C) 2006-2011 Hermann Kneissel herkne@gmx.de + * + * The latest version of the driver can be found at + * http://sourceforge.net/projects/garmin-gps/ +@@ -51,7 +51,7 @@ static int debug; + */ + + #define VERSION_MAJOR 0 +-#define VERSION_MINOR 33 ++#define VERSION_MINOR 36 + + #define _STR(s) #s + #define _DRIVER_VERSION(a, b) "v" _STR(a) "." _STR(b) +@@ -410,6 +410,7 @@ static int gsp_send_ack(struct garmin_da + */ + static int gsp_rec_packet(struct garmin_data *garmin_data_p, int count) + { ++ unsigned long flags; + const __u8 *recpkt = garmin_data_p->inbuffer+GSP_INITIAL_OFFSET; + __le32 *usbdata = (__le32 *) garmin_data_p->inbuffer; + +@@ -458,7 +459,9 @@ static int gsp_rec_packet(struct garmin_ + /* if this was an abort-transfer command, flush all + queued data. */ + if (isAbortTrfCmnd(garmin_data_p->inbuffer)) { ++ spin_lock_irqsave(&garmin_data_p->lock, flags); + garmin_data_p->flags |= FLAGS_DROP_DATA; ++ spin_unlock_irqrestore(&garmin_data_p->lock, flags); + pkt_clear(garmin_data_p); + } + +@@ -943,7 +946,7 @@ static int garmin_open(struct tty_struct + spin_lock_irqsave(&garmin_data_p->lock, flags); + garmin_data_p->mode = initial_mode; + garmin_data_p->count = 0; +- garmin_data_p->flags = 0; ++ garmin_data_p->flags &= FLAGS_SESSION_REPLY1_SEEN; + spin_unlock_irqrestore(&garmin_data_p->lock, flags); + + /* shutdown any bulk reads that might be going on */ +@@ -1178,7 +1181,8 @@ static int garmin_write_room(struct tty_ + + + static void garmin_read_process(struct garmin_data *garmin_data_p, +- unsigned char *data, unsigned data_length) ++ unsigned char *data, unsigned data_length, ++ int bulk_data) + { + unsigned long flags; + +@@ -1193,7 +1197,8 @@ static void garmin_read_process(struct g + send it directly to the tty port */ + if (garmin_data_p->flags & FLAGS_QUEUING) { + pkt_add(garmin_data_p, data, data_length); +- } else if (getLayerId(data) == GARMIN_LAYERID_APPL) { ++ } else if (bulk_data || ++ getLayerId(data) == GARMIN_LAYERID_APPL) { + + spin_lock_irqsave(&garmin_data_p->lock, flags); + garmin_data_p->flags |= APP_RESP_SEEN; +@@ -1237,7 +1242,7 @@ static void garmin_read_bulk_callback(st + usb_serial_debug_data(debug, &port->dev, + __func__, urb->actual_length, data); + +- garmin_read_process(garmin_data_p, data, urb->actual_length); ++ garmin_read_process(garmin_data_p, data, urb->actual_length, 1); + + if (urb->actual_length == 0 && + 0 != (garmin_data_p->flags & FLAGS_BULK_IN_RESTART)) { +@@ -1346,7 +1351,7 @@ static void garmin_read_int_callback(str + __func__, garmin_data_p->serial_num); + } + +- garmin_read_process(garmin_data_p, data, urb->actual_length); ++ garmin_read_process(garmin_data_p, data, urb->actual_length, 0); + + port->interrupt_in_urb->dev = port->serial->dev; + retval = usb_submit_urb(urb, GFP_ATOMIC); +@@ -1461,6 +1466,7 @@ static int garmin_attach(struct usb_seri + garmin_data_p->timer.function = timeout_handler; + garmin_data_p->port = port; + garmin_data_p->state = 0; ++ garmin_data_p->flags = 0; + garmin_data_p->count = 0; + usb_set_serial_port_data(port, garmin_data_p); + diff --git a/queue-2.6.39/usb-moto_modem-add-usb-identifier-for-the-motorola-ve240.patch b/queue-2.6.39/usb-moto_modem-add-usb-identifier-for-the-motorola-ve240.patch new file mode 100644 index 0000000000..89380eec65 --- /dev/null +++ b/queue-2.6.39/usb-moto_modem-add-usb-identifier-for-the-motorola-ve240.patch @@ -0,0 +1,29 @@ +From 3938a0b32dc12229e76735679b37095bc2bc1578 Mon Sep 17 00:00:00 2001 +From: Elizabeth Jennifer Myers <elizabeth@sporksirc.net> +Date: Sat, 16 Apr 2011 14:49:51 -0400 +Subject: USB: moto_modem: Add USB identifier for the Motorola VE240. + +From: Elizabeth Jennifer Myers <elizabeth@sporksirc.net> + +commit 3938a0b32dc12229e76735679b37095bc2bc1578 upstream. + +Tested on my phone, the ttyUSB device is created and is fully +functional. + +Signed-off-by: Elizabeth Jennifer Myers <elizabeth@sporksirc.net> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/serial/moto_modem.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/usb/serial/moto_modem.c ++++ b/drivers/usb/serial/moto_modem.c +@@ -25,6 +25,7 @@ static const struct usb_device_id id_tab + { USB_DEVICE(0x05c6, 0x3197) }, /* unknown Motorola phone */ + { USB_DEVICE(0x0c44, 0x0022) }, /* unknown Mororola phone */ + { USB_DEVICE(0x22b8, 0x2a64) }, /* Motorola KRZR K1m */ ++ { USB_DEVICE(0x22b8, 0x2c84) }, /* Motorola VE240 phone */ + { USB_DEVICE(0x22b8, 0x2c64) }, /* Motorola V950 phone */ + { }, + }; diff --git a/queue-2.6.39/usb-option-add-support-for-huawei-e353-device.patch b/queue-2.6.39/usb-option-add-support-for-huawei-e353-device.patch new file mode 100644 index 0000000000..17a3cd877a --- /dev/null +++ b/queue-2.6.39/usb-option-add-support-for-huawei-e353-device.patch @@ -0,0 +1,46 @@ +From 610ba42f29c3dfa46a05ff8c2cadc29f544ff76d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marcin=20Ga=C5=82czy=C5=84ski?= <marcin@galczynski.pl> +Date: Sun, 15 May 2011 11:41:54 +0200 +Subject: USB: option: add support for Huawei E353 device +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: =?UTF-8?q?Marcin=20Ga=C5=82czy=C5=84ski?= <marcin@galczynski.pl> + +commit 610ba42f29c3dfa46a05ff8c2cadc29f544ff76d upstream. + +I am sharing patch to the devices/usb/serial/option.c. This allows +operation of Huawei E353 broadband modem using the “option” driver. The +patch simply adds new constant with proper product ID and an entry to +usb_device_id. I worked on the 2.6.38.6 sources. Tested on Dell inspiron +1764 (i3 core cpu) and brand new Huawei E353 modem, Fedora 15 beta. + +Looking at the type of change, i doubt it has potential to introduce +problems in other parts of kernel or the driver itself. + +Signed-off-by: Marcin Galczynski <marcin@galczynski.pl> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/serial/option.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/usb/serial/option.c ++++ b/drivers/usb/serial/option.c +@@ -149,6 +149,7 @@ static void option_instat_callback(struc + #define HUAWEI_PRODUCT_K3765 0x1465 + #define HUAWEI_PRODUCT_E14AC 0x14AC + #define HUAWEI_PRODUCT_ETS1220 0x1803 ++#define HUAWEI_PRODUCT_E353 0x1506 + + #define QUANTA_VENDOR_ID 0x0408 + #define QUANTA_PRODUCT_Q101 0xEA02 +@@ -532,6 +533,7 @@ static const struct usb_device_id option + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3765, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_ETS1220, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E14AC, 0xff, 0xff, 0xff) }, ++ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x01) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V640) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V620) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V740) }, diff --git a/queue-2.6.39/usb-remove-remaining-usages-of-hcd-state-from-usbcore-and.patch b/queue-2.6.39/usb-remove-remaining-usages-of-hcd-state-from-usbcore-and.patch new file mode 100644 index 0000000000..ac1bd1469d --- /dev/null +++ b/queue-2.6.39/usb-remove-remaining-usages-of-hcd-state-from-usbcore-and.patch @@ -0,0 +1,192 @@ +From 69fff59de4d844f8b4c2454c3c23d32b69dcbfd7 Mon Sep 17 00:00:00 2001 +From: Alan Stern <stern@rowland.harvard.edu> +Date: Tue, 17 May 2011 17:27:12 -0400 +Subject: USB: remove remaining usages of hcd->state from usbcore and + fix regression + +From: Alan Stern <stern@rowland.harvard.edu> + +commit 69fff59de4d844f8b4c2454c3c23d32b69dcbfd7 upstream. + +This patch (as1467) removes the last usages of hcd->state from +usbcore. We no longer check to see if an interrupt handler finds that +a controller has died; instead we rely on host controller drivers to +make an explicit call to usb_hc_died(). + +This fixes a regression introduced by commit +9b37596a2e860404503a3f2a6513db60c296bfdc (USB: move usbcore away from +hcd->state). It used to be that when a controller shared an IRQ with +another device and an interrupt arrived while hcd->state was set to +HC_STATE_HALT, the interrupt handler would be skipped. The commit +removed that test; as a result the current code doesn't skip calling +the handler and ends up believing the controller has died, even though +it's only temporarily stopped. The solution is to ignore HC_STATE_HALT +following the handler's return. + +As a consequence of this change, several of the host controller +drivers need to be modified. They can no longer implicitly rely on +usbcore realizing that a controller has died because of hcd->state. +The patch adds calls to usb_hc_died() in the appropriate places. + +The patch also changes a few of the interrupt handlers. They don't +expect to be called when hcd->state is equal to HC_STATE_HALT, even if +the controller is still alive. Early returns were added to avoid any +confusion. + +Signed-off-by: Alan Stern <stern@rowland.harvard.edu> +Tested-by: Manuel Lauss <manuel.lauss@googlemail.com> +CC: Rodolfo Giometti <giometti@linux.it> +CC: Olav Kongas <ok@artecdesign.ee> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/core/hcd.c | 5 +---- + drivers/usb/host/ehci-hcd.c | 4 +++- + drivers/usb/host/ehci-sched.c | 8 ++++++-- + drivers/usb/host/isp116x-hcd.c | 1 + + drivers/usb/host/ohci-hcd.c | 4 +++- + drivers/usb/host/oxu210hp-hcd.c | 6 +++++- + 6 files changed, 19 insertions(+), 9 deletions(-) + +--- a/drivers/usb/core/hcd.c ++++ b/drivers/usb/core/hcd.c +@@ -986,7 +986,7 @@ static int register_root_hub(struct usb_ + spin_unlock_irq (&hcd_root_hub_lock); + + /* Did the HC die before the root hub was registered? */ +- if (HCD_DEAD(hcd) || hcd->state == HC_STATE_HALT) ++ if (HCD_DEAD(hcd)) + usb_hc_died (hcd); /* This time clean up */ + } + +@@ -2128,9 +2128,6 @@ irqreturn_t usb_hcd_irq (int irq, void * + set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); + if (hcd->shared_hcd) + set_bit(HCD_FLAG_SAW_IRQ, &hcd->shared_hcd->flags); +- +- if (unlikely(hcd->state == HC_STATE_HALT)) +- usb_hc_died(hcd); + rc = IRQ_HANDLED; + } + +--- a/drivers/usb/host/ehci-hcd.c ++++ b/drivers/usb/host/ehci-hcd.c +@@ -777,8 +777,9 @@ static irqreturn_t ehci_irq (struct usb_ + goto dead; + } + ++ /* Shared IRQ? */ + masked_status = status & INTR_MASK; +- if (!masked_status) { /* irq sharing? */ ++ if (!masked_status || unlikely(hcd->state == HC_STATE_HALT)) { + spin_unlock(&ehci->lock); + return IRQ_NONE; + } +@@ -873,6 +874,7 @@ static irqreturn_t ehci_irq (struct usb_ + dead: + ehci_reset(ehci); + ehci_writel(ehci, 0, &ehci->regs->configured_flag); ++ usb_hc_died(hcd); + /* generic layer kills/unlinks all urbs, then + * uses ehci_stop to clean up the rest + */ +--- a/drivers/usb/host/ehci-sched.c ++++ b/drivers/usb/host/ehci-sched.c +@@ -471,8 +471,10 @@ static int enable_periodic (struct ehci_ + */ + status = handshake_on_error_set_halt(ehci, &ehci->regs->status, + STS_PSS, 0, 9 * 125); +- if (status) ++ if (status) { ++ usb_hc_died(ehci_to_hcd(ehci)); + return status; ++ } + + cmd = ehci_readl(ehci, &ehci->regs->command) | CMD_PSE; + ehci_writel(ehci, cmd, &ehci->regs->command); +@@ -510,8 +512,10 @@ static int disable_periodic (struct ehci + */ + status = handshake_on_error_set_halt(ehci, &ehci->regs->status, + STS_PSS, STS_PSS, 9 * 125); +- if (status) ++ if (status) { ++ usb_hc_died(ehci_to_hcd(ehci)); + return status; ++ } + + cmd = ehci_readl(ehci, &ehci->regs->command) & ~CMD_PSE; + ehci_writel(ehci, cmd, &ehci->regs->command); +--- a/drivers/usb/host/isp116x-hcd.c ++++ b/drivers/usb/host/isp116x-hcd.c +@@ -612,6 +612,7 @@ static irqreturn_t isp116x_irq(struct us + /* IRQ's are off, we do no DMA, + perfectly ready to die ... */ + hcd->state = HC_STATE_HALT; ++ usb_hc_died(hcd); + ret = IRQ_HANDLED; + goto done; + } +--- a/drivers/usb/host/ohci-hcd.c ++++ b/drivers/usb/host/ohci-hcd.c +@@ -764,6 +764,7 @@ static irqreturn_t ohci_irq (struct usb_ + if (ints == ~(u32)0) { + disable (ohci); + ohci_dbg (ohci, "device removed!\n"); ++ usb_hc_died(hcd); + return IRQ_HANDLED; + } + +@@ -771,7 +772,7 @@ static irqreturn_t ohci_irq (struct usb_ + ints &= ohci_readl(ohci, ®s->intrenable); + + /* interrupt for some other device? */ +- if (ints == 0) ++ if (ints == 0 || unlikely(hcd->state == HC_STATE_HALT)) + return IRQ_NOTMINE; + + if (ints & OHCI_INTR_UE) { +@@ -788,6 +789,7 @@ static irqreturn_t ohci_irq (struct usb_ + } else { + disable (ohci); + ohci_err (ohci, "OHCI Unrecoverable Error, disabled\n"); ++ usb_hc_died(hcd); + } + + ohci_dump (ohci, 1); +--- a/drivers/usb/host/oxu210hp-hcd.c ++++ b/drivers/usb/host/oxu210hp-hcd.c +@@ -1884,6 +1884,7 @@ static int enable_periodic(struct oxu_hc + status = handshake(oxu, &oxu->regs->status, STS_PSS, 0, 9 * 125); + if (status != 0) { + oxu_to_hcd(oxu)->state = HC_STATE_HALT; ++ usb_hc_died(oxu_to_hcd(oxu)); + return status; + } + +@@ -1909,6 +1910,7 @@ static int disable_periodic(struct oxu_h + status = handshake(oxu, &oxu->regs->status, STS_PSS, STS_PSS, 9 * 125); + if (status != 0) { + oxu_to_hcd(oxu)->state = HC_STATE_HALT; ++ usb_hc_died(oxu_to_hcd(oxu)); + return status; + } + +@@ -2449,8 +2451,9 @@ static irqreturn_t oxu210_hcd_irq(struct + goto dead; + } + ++ /* Shared IRQ? */ + status &= INTR_MASK; +- if (!status) { /* irq sharing? */ ++ if (!status || unlikely(hcd->state == HC_STATE_HALT)) { + spin_unlock(&oxu->lock); + return IRQ_NONE; + } +@@ -2516,6 +2519,7 @@ static irqreturn_t oxu210_hcd_irq(struct + dead: + ehci_reset(oxu); + writel(0, &oxu->regs->configured_flag); ++ usb_hc_died(hcd); + /* generic layer kills/unlinks all urbs, then + * uses oxu_stop to clean up the rest + */ diff --git a/queue-2.6.39/usb-serial-ftdi_sio-adding-support-for-tavir-stk500.patch b/queue-2.6.39/usb-serial-ftdi_sio-adding-support-for-tavir-stk500.patch new file mode 100644 index 0000000000..49316951d9 --- /dev/null +++ b/queue-2.6.39/usb-serial-ftdi_sio-adding-support-for-tavir-stk500.patch @@ -0,0 +1,47 @@ +From 37909fe588c9e09ab57cd267e98678a17ceda64a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Benedek=20L=C3=A1szl=C3=B3?= <benedekl@gmail.com> +Date: Wed, 20 Apr 2011 03:22:21 +0200 +Subject: USB: serial: ftdi_sio: adding support for TavIR STK500 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: =?UTF-8?q?Benedek=20L=C3=A1szl=C3=B3?= <benedekl@gmail.com> + +commit 37909fe588c9e09ab57cd267e98678a17ceda64a upstream. + +Adding support for the TavIR STK500 (id 0403:FA33) +Atmel AVR programmer device based on FTDI FT232RL. + +Signed-off-by: Benedek László <benedekl@gmail.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/serial/ftdi_sio.c | 1 + + drivers/usb/serial/ftdi_sio_ids.h | 5 +++++ + 2 files changed, 6 insertions(+) + +--- a/drivers/usb/serial/ftdi_sio.c ++++ b/drivers/usb/serial/ftdi_sio.c +@@ -566,6 +566,7 @@ static struct usb_device_id id_table_com + { USB_DEVICE(FTDI_VID, FTDI_IBS_APP70_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_IBS_PEDO_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_IBS_PROD_PID) }, ++ { USB_DEVICE(FTDI_VID, FTDI_TAVIR_STK500_PID) }, + /* + * ELV devices: + */ +--- a/drivers/usb/serial/ftdi_sio_ids.h ++++ b/drivers/usb/serial/ftdi_sio_ids.h +@@ -491,6 +491,11 @@ + /* www.canusb.com Lawicel CANUSB device (FTDI_VID) */ + #define FTDI_CANUSB_PID 0xFFA8 /* Product Id */ + ++/* ++ * TavIR AVR product ids (FTDI_VID) ++ */ ++#define FTDI_TAVIR_STK500_PID 0xFA33 /* STK500 AVR programmer */ ++ + + + /********************************/ diff --git a/queue-2.6.39/xhci-fix-bug-in-control-transfer-cancellation.patch b/queue-2.6.39/xhci-fix-bug-in-control-transfer-cancellation.patch new file mode 100644 index 0000000000..dcc90f4dff --- /dev/null +++ b/queue-2.6.39/xhci-fix-bug-in-control-transfer-cancellation.patch @@ -0,0 +1,84 @@ +From 3abeca998a44205cfd837fa0bf1f7c24f8294acb Mon Sep 17 00:00:00 2001 +From: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Date: Thu, 5 May 2011 19:08:09 -0700 +Subject: xhci: Fix bug in control transfer cancellation. + +From: Sarah Sharp <sarah.a.sharp@linux.intel.com> + +commit 3abeca998a44205cfd837fa0bf1f7c24f8294acb upstream. + +When the xHCI driver attempts to cancel a transfer, it issues a Stop +Endpoint command and waits for the host controller to indicate which TRB +it was in the middle of processing. The host will put an event TRB with +completion code COMP_STOP on the event ring if it stops on a control +transfer TRB (or other types of transfer TRBs). The ring handling code +is supposed to set ep->stopped_trb to the TRB that the host stopped on +when this happens. + +Unfortunately, there is a long-standing bug in the control transfer +completion code. It doesn't actually check to see if COMP_STOP is set +before attempting to process the transfer based on which part of the +control TD completed. So when we get an event on the data phase of the +control TRB with COMP_STOP set, it thinks it's a normal completion of +the transfer and doesn't set ep->stopped_td or ep->stopped_trb. + +When the ring handling code goes on to process the completion of the Stop +Endpoint command, it sees that ep->stopped_trb is not a part of the TD +it's trying to cancel. It thinks the hardware has its enqueue pointer +somewhere further up in the ring, and thinks it's safe to turn the control +TRBs into no-op TRBs. Since the hardware was in the middle of the control +TRBs to be cancelled, the proper software behavior is to issue a Set TR +dequeue pointer command. + +It turns out that the NEC host controllers can handle active TRBs being +set to no-op TRBs after a stop endpoint command, but other host +controllers have issues with this out-of-spec software behavior. Fix this +behavior. + +This patch should be backported to kernels as far back as 2.6.31, but it +may be a bit challenging, since process_ctrl_td() was introduced in some +refactoring done in 2.6.36, and some endian-safe patches added in 2.6.40 +that touch the same lines. + +Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/host/xhci-ring.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -1632,6 +1632,9 @@ static int process_ctrl_td(struct xhci_h + else + *status = 0; + break; ++ case COMP_STOP_INVAL: ++ case COMP_STOP: ++ return finish_td(xhci, td, event_trb, event, ep, status, false); + default: + if (!xhci_requires_manual_halt_cleanup(xhci, + ep_ctx, trb_comp_code)) +@@ -1676,15 +1679,12 @@ static int process_ctrl_td(struct xhci_h + } + } else { + /* Maybe the event was for the data stage? */ +- if (trb_comp_code != COMP_STOP_INVAL) { +- /* We didn't stop on a link TRB in the middle */ +- td->urb->actual_length = +- td->urb->transfer_buffer_length - +- TRB_LEN(event->transfer_len); +- xhci_dbg(xhci, "Waiting for status " +- "stage event\n"); +- return 0; +- } ++ td->urb->actual_length = ++ td->urb->transfer_buffer_length - ++ TRB_LEN(le32_to_cpu(event->transfer_len)); ++ xhci_dbg(xhci, "Waiting for status " ++ "stage event\n"); ++ return 0; + } + } + diff --git a/queue-2.6.39/xhci-fix-full-speed-binterval-encoding.patch b/queue-2.6.39/xhci-fix-full-speed-binterval-encoding.patch new file mode 100644 index 0000000000..88abcc7ee6 --- /dev/null +++ b/queue-2.6.39/xhci-fix-full-speed-binterval-encoding.patch @@ -0,0 +1,63 @@ +From b513d44751bfb609a3c20463f764c8ce822d63e9 Mon Sep 17 00:00:00 2001 +From: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Date: Fri, 13 May 2011 13:10:01 -0700 +Subject: xhci: Fix full speed bInterval encoding. + +From: Sarah Sharp <sarah.a.sharp@linux.intel.com> + +commit b513d44751bfb609a3c20463f764c8ce822d63e9 upstream. + +Dmitry's patch + +dfa49c4ad120a784ef1ff0717168aa79f55a483a USB: xhci - fix math in xhci_get_endpoint_interval() + +introduced a bug. The USB 2.0 spec says that full speed isochronous endpoints' +bInterval must be decoded as an exponent to a power of two (e.g. interval = +2^(bInterval - 1)). Full speed interrupt endpoints, on the other hand, don't +use exponents, and the interval in frames is encoded straight into bInterval. + +Dmitry's patch was supposed to fix up the full speed isochronous to parse +bInterval as an exponent, but instead it changed the *interrupt* endpoint +bInterval decoding. The isochronous endpoint encoding was the same. + +This caused full speed devices with interrupt endpoints (including mice, hubs, +and USB to ethernet devices) to fail under NEC 0.96 xHCI host controllers: + +[ 100.909818] xhci_hcd 0000:06:00.0: add ep 0x83, slot id 1, new drop flags = 0x0, new add flags = 0x99, new slot info = 0x38100000 +[ 100.909821] xhci_hcd 0000:06:00.0: xhci_check_bandwidth called for udev ffff88011f0ea000 +... +[ 100.910187] xhci_hcd 0000:06:00.0: ERROR: unexpected command completion code 0x11. +[ 100.910190] xhci_hcd 0000:06:00.0: xhci_reset_bandwidth called for udev ffff88011f0ea000 + +When the interrupt endpoint was added and a Configure Endpoint command was +issued to the host, the host controller would return a very odd error message +(0x11 means "Slot Not Enabled", which isn't true because the slot was enabled). +Probably the host controller was getting very confused with the bad encoding. + +Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Cc: Dmitry Torokhov <dtor@vmware.com> +Reported-by: Thomas Lindroth <thomas.lindroth@gmail.com> +Tested-by: Thomas Lindroth <thomas.lindroth@gmail.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/host/xhci-mem.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/usb/host/xhci-mem.c ++++ b/drivers/usb/host/xhci-mem.c +@@ -1046,12 +1046,12 @@ static unsigned int xhci_get_endpoint_in + break; + + case USB_SPEED_FULL: +- if (usb_endpoint_xfer_int(&ep->desc)) { ++ if (usb_endpoint_xfer_isoc(&ep->desc)) { + interval = xhci_parse_exponent_interval(udev, ep); + break; + } + /* +- * Fall through for isochronous endpoint interval decoding ++ * Fall through for interrupt endpoint interval decoding + * since it uses the same rules as low speed interrupt + * endpoints. + */ diff --git a/queue-2.6.39/xhci-fix-memory-leak-bug-when-dropping-endpoints.patch b/queue-2.6.39/xhci-fix-memory-leak-bug-when-dropping-endpoints.patch new file mode 100644 index 0000000000..9ea7c04504 --- /dev/null +++ b/queue-2.6.39/xhci-fix-memory-leak-bug-when-dropping-endpoints.patch @@ -0,0 +1,65 @@ +From 834cb0fc4712a3b21c6b8c5cb55bd13607191311 Mon Sep 17 00:00:00 2001 +From: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Date: Thu, 12 May 2011 18:06:37 -0700 +Subject: xhci: Fix memory leak bug when dropping endpoints + +From: Sarah Sharp <sarah.a.sharp@linux.intel.com> + +commit 834cb0fc4712a3b21c6b8c5cb55bd13607191311 upstream. + +When the USB core wants to change to an alternate interface setting that +doesn't include an active endpoint, or de-configuring the device, the xHCI +driver needs to issue a Configure Endpoint command to tell the host to +drop some endpoints from the schedule. After the command completes, the +xHCI driver needs to free rings for any endpoints that were dropped. + +Unfortunately, the xHCI driver wasn't actually freeing the endpoint rings +for dropped endpoints. The rings would be freed if the endpoint's +information was simply changed (and a new ring was installed), but dropped +endpoints never had their rings freed. This caused errors when the ring +segment DMA pool was freed when the xHCI driver was unloaded: + +[ 5582.883995] xhci_hcd 0000:06:00.0: dma_pool_destroy xHCI ring segments, ffff88003371d000 busy +[ 5582.884002] xhci_hcd 0000:06:00.0: dma_pool_destroy xHCI ring segments, ffff880033716000 busy +[ 5582.884011] xhci_hcd 0000:06:00.0: dma_pool_destroy xHCI ring segments, ffff880033455000 busy +[ 5582.884018] xhci_hcd 0000:06:00.0: Freed segment pool +[ 5582.884026] xhci_hcd 0000:06:00.0: Freed device context pool +[ 5582.884033] xhci_hcd 0000:06:00.0: Freed small stream array pool +[ 5582.884038] xhci_hcd 0000:06:00.0: Freed medium stream array pool +[ 5582.884048] xhci_hcd 0000:06:00.0: xhci_stop completed - status = 1 +[ 5582.884061] xhci_hcd 0000:06:00.0: USB bus 3 deregistered +[ 5582.884193] xhci_hcd 0000:06:00.0: PCI INT A disabled + +Fix this issue and free endpoint rings when their endpoints are +successfully dropped. + +This patch should be backported to kernels as old as 2.6.31. + +Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/host/xhci.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +--- a/drivers/usb/host/xhci.c ++++ b/drivers/usb/host/xhci.c +@@ -1692,8 +1692,17 @@ int xhci_check_bandwidth(struct usb_hcd + xhci_dbg_ctx(xhci, virt_dev->out_ctx, + LAST_CTX_TO_EP_NUM(slot_ctx->dev_info)); + ++ /* Free any rings that were dropped, but not changed. */ ++ for (i = 1; i < 31; ++i) { ++ if ((ctrl_ctx->drop_flags & (1 << (i + 1))) && ++ !(ctrl_ctx->add_flags & (1 << (i + 1)))) ++ xhci_free_or_cache_endpoint_ring(xhci, virt_dev, i); ++ } + xhci_zero_in_ctx(xhci, virt_dev); +- /* Install new rings and free or cache any old rings */ ++ /* ++ * Install any rings for completely new endpoints or changed endpoints, ++ * and free or cache any old rings from changed endpoints. ++ */ + for (i = 1; i < 31; ++i) { + if (!virt_dev->eps[i].new_ring) + continue; diff --git a/queue-2.6.39/xhci-fix-memory-leak-in-ring-cache-deallocation.patch b/queue-2.6.39/xhci-fix-memory-leak-in-ring-cache-deallocation.patch new file mode 100644 index 0000000000..b5c3756bb4 --- /dev/null +++ b/queue-2.6.39/xhci-fix-memory-leak-in-ring-cache-deallocation.patch @@ -0,0 +1,64 @@ +From 30f89ca021c3e584b61bc5a14eede89f74b2e826 Mon Sep 17 00:00:00 2001 +From: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Date: Mon, 16 May 2011 13:09:08 -0700 +Subject: xhci: Fix memory leak in ring cache deallocation. + +From: Sarah Sharp <sarah.a.sharp@linux.intel.com> + +commit 30f89ca021c3e584b61bc5a14eede89f74b2e826 upstream. + +When an endpoint ring is freed, it is either cached in a per-device ring +cache, or simply freed if the ring cache is full. If the ring was added +to the cache, then virt_dev->num_rings_cached is incremented. The cache +is designed to hold up to 31 endpoint rings, in array indexes 0 to 30. +When the device is freed (when the slot was disabled), +xhci_free_virt_device() is called, it would free the cached rings in +array indexes 0 to virt_dev->num_rings_cached. + +Unfortunately, the original code in xhci_free_or_cache_endpoint_ring() +would put the first entry into the ring cache in array index 1, instead of +array index 0. This was caused by the second assignment to rings_cached: + + rings_cached = virt_dev->num_rings_cached; + if (rings_cached < XHCI_MAX_RINGS_CACHED) { + virt_dev->num_rings_cached++; + rings_cached = virt_dev->num_rings_cached; + virt_dev->ring_cache[rings_cached] = + virt_dev->eps[ep_index].ring; + +This meant that when the device was freed, cached rings with indexes 0 to +N would be freed, and the last cached ring in index N+1 would not be +freed. When the driver was unloaded, this caused interesting messages +like: + +xhci_hcd 0000:06:00.0: dma_pool_destroy xHCI ring segments, ffff880063040000 busy + +This should be queued to stable kernels back to 2.6.33. + +Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/host/xhci-mem.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +--- a/drivers/usb/host/xhci-mem.c ++++ b/drivers/usb/host/xhci-mem.c +@@ -207,14 +207,13 @@ void xhci_free_or_cache_endpoint_ring(st + + rings_cached = virt_dev->num_rings_cached; + if (rings_cached < XHCI_MAX_RINGS_CACHED) { +- virt_dev->num_rings_cached++; +- rings_cached = virt_dev->num_rings_cached; + virt_dev->ring_cache[rings_cached] = + virt_dev->eps[ep_index].ring; ++ virt_dev->num_rings_cached++; + xhci_dbg(xhci, "Cached old ring, " + "%d ring%s cached\n", +- rings_cached, +- (rings_cached > 1) ? "s" : ""); ++ virt_dev->num_rings_cached, ++ (virt_dev->num_rings_cached > 1) ? "s" : ""); + } else { + xhci_ring_free(xhci, virt_dev->eps[ep_index].ring); + xhci_dbg(xhci, "Ring cache full (%d rings), " |