[kernel] r19663 - in dists/sid/linux/debian: . config patches patches/features/all/iguanair

Ben Hutchings benh at alioth.debian.org
Sat Dec 29 13:57:45 UTC 2012


Author: benh
Date: Sat Dec 29 13:57:44 2012
New Revision: 19663

Log:
media/rc: Add iguanair driver from Linux 3.7 (Closes: #696925)

Added:
   dists/sid/linux/debian/patches/features/all/iguanair/
   dists/sid/linux/debian/patches/features/all/iguanair/0001-media-Add-support-for-the-IguanaWorks-USB-IR-Transce.patch
   dists/sid/linux/debian/patches/features/all/iguanair/0002-media-iguanair-reuse-existing-urb-callback-for-comma.patch
   dists/sid/linux/debian/patches/features/all/iguanair/0003-media-iguanair-ignore-unsupported-firmware-versions.patch
   dists/sid/linux/debian/patches/features/all/iguanair/0004-media-iguanair-support-suspend-and-resume.patch
   dists/sid/linux/debian/patches/features/all/iguanair/0005-media-iguanair-fix-return-value-for-transmit.patch
   dists/sid/linux/debian/patches/features/all/iguanair/0006-media-iguanair-reset-the-IR-state-after-rx-overflow-.patch
   dists/sid/linux/debian/patches/features/all/iguanair/0007-media-iguanair-advertise-the-resolution-and-timeout-.patch
   dists/sid/linux/debian/patches/features/all/iguanair/0008-media-iguanair-fix-receiver-overflow.patch
   dists/sid/linux/debian/patches/features/all/iguanair/0009-media-rc-do-not-wake-up-rc-thread-unless-there-is-so.patch
   dists/sid/linux/debian/patches/features/all/iguanair/0010-media-iguanair-do-not-modify-transmit-buffer.patch
   dists/sid/linux/debian/patches/features/all/iguanair/0011-media-iguanair-cannot-send-data-from-the-stack.patch
Modified:
   dists/sid/linux/debian/changelog
   dists/sid/linux/debian/config/config
   dists/sid/linux/debian/patches/series

Modified: dists/sid/linux/debian/changelog
==============================================================================
--- dists/sid/linux/debian/changelog	Sat Dec 29 13:04:21 2012	(r19662)
+++ dists/sid/linux/debian/changelog	Sat Dec 29 13:57:44 2012	(r19663)
@@ -2,6 +2,7 @@
 
   [ Ben Hutchings ]
   * Input: wacom - fix touch support for Bamboo Fun CTH-461
+  * media/rc: Add iguanair driver from Linux 3.7 (Closes: #696925)
 
  -- Ben Hutchings <ben at decadent.org.uk>  Thu, 27 Dec 2012 02:17:44 +0100
 

Modified: dists/sid/linux/debian/config/config
==============================================================================
--- dists/sid/linux/debian/config/config	Sat Dec 29 13:04:21 2012	(r19662)
+++ dists/sid/linux/debian/config/config	Sat Dec 29 13:57:44 2012	(r19663)
@@ -1144,6 +1144,7 @@
 # CONFIG_IR_NUVOTON is not set
 CONFIG_IR_REDRAT3=m
 CONFIG_IR_STREAMZAP=m
+CONFIG_IR_IGUANA=m
 CONFIG_RC_LOOPBACK=m
 
 ##

Added: dists/sid/linux/debian/patches/features/all/iguanair/0001-media-Add-support-for-the-IguanaWorks-USB-IR-Transce.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux/debian/patches/features/all/iguanair/0001-media-Add-support-for-the-IguanaWorks-USB-IR-Transce.patch	Sat Dec 29 13:57:44 2012	(r19663)
@@ -0,0 +1,684 @@
+From: Sean Young <sean at mess.org>
+Date: Sun, 15 Jul 2012 13:31:00 -0300
+Subject: [01/11] [media] Add support for the IguanaWorks USB IR Transceiver
+
+commit 26ff63137c45886169ed102bddd6e90d6c27f00d upstream.
+
+Signed-off-by: Sean Young <sean at mess.org>
+Signed-off-by: Mauro Carvalho Chehab <mchehab at redhat.com>
+---
+ drivers/media/rc/Kconfig    |   11 +
+ drivers/media/rc/Makefile   |    1 +
+ drivers/media/rc/iguanair.c |  639 +++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 651 insertions(+)
+ create mode 100644 drivers/media/rc/iguanair.c
+
+--- a/drivers/media/rc/Kconfig
++++ b/drivers/media/rc/Kconfig
+@@ -243,6 +243,17 @@ config IR_WINBOND_CIR
+ 	   To compile this driver as a module, choose M here: the module will
+ 	   be called winbond_cir.
+ 
++config IR_IGUANA
++	tristate "IguanaWorks USB IR Transceiver"
++	depends on RC_CORE
++	select USB
++	---help---
++	   Say Y here if you want to use the IgaunaWorks USB IR Transceiver.
++	   Both infrared receive and send are supported.
++
++	   To compile this driver as a module, choose M here: the module will
++	   be called iguanair.
++
+ config RC_LOOPBACK
+ 	tristate "Remote Control Loopback Driver"
+ 	depends on RC_CORE
+--- a/drivers/media/rc/Makefile
++++ b/drivers/media/rc/Makefile
+@@ -25,3 +25,4 @@ obj-$(CONFIG_IR_REDRAT3) += redrat3.o
+ obj-$(CONFIG_IR_STREAMZAP) += streamzap.o
+ obj-$(CONFIG_IR_WINBOND_CIR) += winbond-cir.o
+ obj-$(CONFIG_RC_LOOPBACK) += rc-loopback.o
++obj-$(CONFIG_IR_IGUANA) += iguanair.o
+--- /dev/null
++++ b/drivers/media/rc/iguanair.c
+@@ -0,0 +1,639 @@
++/*
++ * IguanaWorks USB IR Transceiver support
++ *
++ * Copyright (C) 2012 Sean Young <sean at mess.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#include <linux/device.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/usb.h>
++#include <linux/usb/input.h>
++#include <linux/slab.h>
++#include <linux/completion.h>
++#include <media/rc-core.h>
++
++#define DRIVER_NAME "iguanair"
++
++struct iguanair {
++	struct rc_dev *rc;
++
++	struct device *dev;
++	struct usb_device *udev;
++
++	int pipe_in, pipe_out;
++	uint8_t bufsize;
++	uint8_t version[2];
++
++	struct mutex lock;
++
++	/* receiver support */
++	bool receiver_on;
++	dma_addr_t dma_in;
++	uint8_t *buf_in;
++	struct urb *urb_in;
++	struct completion completion;
++
++	/* transmit support */
++	bool tx_overflow;
++	uint32_t carrier;
++	uint8_t cycle_overhead;
++	uint8_t channels;
++	uint8_t busy4;
++	uint8_t busy7;
++
++	char name[64];
++	char phys[64];
++};
++
++#define CMD_GET_VERSION		0x01
++#define CMD_GET_BUFSIZE		0x11
++#define CMD_GET_FEATURES	0x10
++#define CMD_SEND		0x15
++#define CMD_EXECUTE		0x1f
++#define CMD_RX_OVERFLOW		0x31
++#define CMD_TX_OVERFLOW		0x32
++#define CMD_RECEIVER_ON		0x12
++#define CMD_RECEIVER_OFF	0x14
++
++#define DIR_IN			0xdc
++#define DIR_OUT			0xcd
++
++#define MAX_PACKET_SIZE		8u
++#define TIMEOUT			1000
++
++struct packet {
++	uint16_t start;
++	uint8_t direction;
++	uint8_t cmd;
++};
++
++struct response_packet {
++	struct packet header;
++	uint8_t data[4];
++};
++
++struct send_packet {
++	struct packet header;
++	uint8_t length;
++	uint8_t channels;
++	uint8_t busy7;
++	uint8_t busy4;
++	uint8_t payload[0];
++};
++
++static void process_ir_data(struct iguanair *ir, unsigned len)
++{
++	if (len >= 4 && ir->buf_in[0] == 0 && ir->buf_in[1] == 0) {
++		switch (ir->buf_in[3]) {
++		case CMD_TX_OVERFLOW:
++			ir->tx_overflow = true;
++		case CMD_RECEIVER_OFF:
++		case CMD_RECEIVER_ON:
++		case CMD_SEND:
++			complete(&ir->completion);
++			break;
++		case CMD_RX_OVERFLOW:
++			dev_warn(ir->dev, "receive overflow\n");
++			break;
++		default:
++			dev_warn(ir->dev, "control code %02x received\n",
++							ir->buf_in[3]);
++			break;
++		}
++	} else if (len >= 7) {
++		DEFINE_IR_RAW_EVENT(rawir);
++		unsigned i;
++
++		init_ir_raw_event(&rawir);
++
++		for (i = 0; i < 7; i++) {
++			if (ir->buf_in[i] == 0x80) {
++				rawir.pulse = false;
++				rawir.duration = US_TO_NS(21845);
++			} else {
++				rawir.pulse = (ir->buf_in[i] & 0x80) == 0;
++				rawir.duration = ((ir->buf_in[i] & 0x7f) + 1) *
++									 21330;
++			}
++
++			ir_raw_event_store_with_filter(ir->rc, &rawir);
++		}
++
++		ir_raw_event_handle(ir->rc);
++	}
++}
++
++static void iguanair_rx(struct urb *urb)
++{
++	struct iguanair *ir;
++
++	if (!urb)
++		return;
++
++	ir = urb->context;
++	if (!ir) {
++		usb_unlink_urb(urb);
++		return;
++	}
++
++	switch (urb->status) {
++	case 0:
++		process_ir_data(ir, urb->actual_length);
++		break;
++	case -ECONNRESET:
++	case -ENOENT:
++	case -ESHUTDOWN:
++		usb_unlink_urb(urb);
++		return;
++	case -EPIPE:
++	default:
++		dev_dbg(ir->dev, "Error: urb status = %d\n", urb->status);
++		break;
++	}
++
++	usb_submit_urb(urb, GFP_ATOMIC);
++}
++
++static int iguanair_send(struct iguanair *ir, void *data, unsigned size,
++			struct response_packet *response, unsigned *res_len)
++{
++	unsigned offset, len;
++	int rc, transferred;
++
++	for (offset = 0; offset < size; offset += MAX_PACKET_SIZE) {
++		len = min(size - offset, MAX_PACKET_SIZE);
++
++		if (ir->tx_overflow)
++			return -EOVERFLOW;
++
++		rc = usb_interrupt_msg(ir->udev, ir->pipe_out, data + offset,
++						len, &transferred, TIMEOUT);
++		if (rc)
++			return rc;
++
++		if (transferred != len)
++			return -EIO;
++	}
++
++	if (response) {
++		rc = usb_interrupt_msg(ir->udev, ir->pipe_in, response,
++					sizeof(*response), res_len, TIMEOUT);
++	}
++
++	return rc;
++}
++
++static int iguanair_get_features(struct iguanair *ir)
++{
++	struct packet packet;
++	struct response_packet response;
++	int rc, len;
++
++	packet.start = 0;
++	packet.direction = DIR_OUT;
++	packet.cmd = CMD_GET_VERSION;
++
++	rc = iguanair_send(ir, &packet, sizeof(packet), &response, &len);
++	if (rc) {
++		dev_info(ir->dev, "failed to get version\n");
++		goto out;
++	}
++
++	if (len != 6) {
++		dev_info(ir->dev, "failed to get version\n");
++		rc = -EIO;
++		goto out;
++	}
++
++	ir->version[0] = response.data[0];
++	ir->version[1] = response.data[1];
++	ir->bufsize = 150;
++	ir->cycle_overhead = 65;
++
++	packet.cmd = CMD_GET_BUFSIZE;
++
++	rc = iguanair_send(ir, &packet, sizeof(packet), &response, &len);
++	if (rc) {
++		dev_info(ir->dev, "failed to get buffer size\n");
++		goto out;
++	}
++
++	if (len != 5) {
++		dev_info(ir->dev, "failed to get buffer size\n");
++		rc = -EIO;
++		goto out;
++	}
++
++	ir->bufsize = response.data[0];
++
++	if (ir->version[0] == 0 || ir->version[1] == 0)
++		goto out;
++
++	packet.cmd = CMD_GET_FEATURES;
++
++	rc = iguanair_send(ir, &packet, sizeof(packet), &response, &len);
++	if (rc) {
++		dev_info(ir->dev, "failed to get features\n");
++		goto out;
++	}
++
++	if (len < 5) {
++		dev_info(ir->dev, "failed to get features\n");
++		rc = -EIO;
++		goto out;
++	}
++
++	if (len > 5 && ir->version[0] >= 4)
++		ir->cycle_overhead = response.data[1];
++
++out:
++	return rc;
++}
++
++static int iguanair_receiver(struct iguanair *ir, bool enable)
++{
++	struct packet packet = { 0, DIR_OUT, enable ?
++				CMD_RECEIVER_ON : CMD_RECEIVER_OFF };
++	int rc;
++
++	INIT_COMPLETION(ir->completion);
++
++	rc = iguanair_send(ir, &packet, sizeof(packet), NULL, NULL);
++	if (rc)
++		return rc;
++
++	wait_for_completion_timeout(&ir->completion, TIMEOUT);
++
++	return 0;
++}
++
++/*
++ * The iguana ir creates the carrier by busy spinning after each pulse or
++ * space. This is counted in CPU cycles, with the CPU running at 24MHz. It is
++ * broken down into 7-cycles and 4-cyles delays, with a preference for
++ * 4-cycle delays.
++ */
++static int iguanair_set_tx_carrier(struct rc_dev *dev, uint32_t carrier)
++{
++	struct iguanair *ir = dev->priv;
++
++	if (carrier < 25000 || carrier > 150000)
++		return -EINVAL;
++
++	mutex_lock(&ir->lock);
++
++	if (carrier != ir->carrier) {
++		uint32_t cycles, fours, sevens;
++
++		ir->carrier = carrier;
++
++		cycles = DIV_ROUND_CLOSEST(24000000, carrier * 2) -
++							ir->cycle_overhead;
++
++		/*  make up the the remainer of 4-cycle blocks */
++		switch (cycles & 3) {
++		case 0:
++			sevens = 0;
++			break;
++		case 1:
++			sevens = 3;
++			break;
++		case 2:
++			sevens = 2;
++			break;
++		case 3:
++			sevens = 1;
++			break;
++		}
++
++		fours = (cycles - sevens * 7) / 4;
++
++		/* magic happens here */
++		ir->busy7 = (4 - sevens) * 2;
++		ir->busy4 = 110 - fours;
++	}
++
++	mutex_unlock(&ir->lock);
++
++	return carrier;
++}
++
++static int iguanair_set_tx_mask(struct rc_dev *dev, uint32_t mask)
++{
++	struct iguanair *ir = dev->priv;
++
++	if (mask > 15)
++		return 4;
++
++	mutex_lock(&ir->lock);
++	ir->channels = mask;
++	mutex_unlock(&ir->lock);
++
++	return 0;
++}
++
++static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count)
++{
++	struct iguanair *ir = dev->priv;
++	uint8_t space, *payload;
++	unsigned i, size, rc;
++	struct send_packet *packet;
++
++	mutex_lock(&ir->lock);
++
++	/* convert from us to carrier periods */
++	for (i = size = 0; i < count; i++) {
++		txbuf[i] = DIV_ROUND_CLOSEST(txbuf[i] * ir->carrier, 1000000);
++		size += (txbuf[i] + 126) / 127;
++	}
++
++	packet = kmalloc(sizeof(*packet) + size, GFP_KERNEL);
++	if (!packet) {
++		rc = -ENOMEM;
++		goto out;
++	}
++
++	if (size > ir->bufsize) {
++		rc = -E2BIG;
++		goto out;
++	}
++
++	packet->header.start = 0;
++	packet->header.direction = DIR_OUT;
++	packet->header.cmd = CMD_SEND;
++	packet->length = size;
++	packet->channels = ir->channels << 4;
++	packet->busy7 = ir->busy7;
++	packet->busy4 = ir->busy4;
++
++	space = 0;
++	payload = packet->payload;
++
++	for (i = 0; i < count; i++) {
++		unsigned periods = txbuf[i];
++
++		while (periods > 127) {
++			*payload++ = 127 | space;
++			periods -= 127;
++		}
++
++		*payload++ = periods | space;
++		space ^= 0x80;
++	}
++
++	if (ir->receiver_on) {
++		rc = iguanair_receiver(ir, false);
++		if (rc) {
++			dev_warn(ir->dev, "disable receiver before transmit failed\n");
++			goto out;
++		}
++	}
++
++	ir->tx_overflow = false;
++
++	INIT_COMPLETION(ir->completion);
++
++	rc = iguanair_send(ir, packet, size + 8, NULL, NULL);
++
++	if (rc == 0) {
++		wait_for_completion_timeout(&ir->completion, TIMEOUT);
++		if (ir->tx_overflow)
++			rc = -EOVERFLOW;
++	}
++
++	ir->tx_overflow = false;
++
++	if (ir->receiver_on) {
++		if (iguanair_receiver(ir, true))
++			dev_warn(ir->dev, "re-enable receiver after transmit failed\n");
++	}
++
++out:
++	mutex_unlock(&ir->lock);
++	kfree(packet);
++
++	return rc;
++}
++
++static int iguanair_open(struct rc_dev *rdev)
++{
++	struct iguanair *ir = rdev->priv;
++	int rc;
++
++	mutex_lock(&ir->lock);
++
++	usb_submit_urb(ir->urb_in, GFP_KERNEL);
++
++	BUG_ON(ir->receiver_on);
++
++	rc = iguanair_receiver(ir, true);
++	if (rc == 0)
++		ir->receiver_on = true;
++
++	mutex_unlock(&ir->lock);
++
++	return rc;
++}
++
++static void iguanair_close(struct rc_dev *rdev)
++{
++	struct iguanair *ir = rdev->priv;
++	int rc;
++
++	mutex_lock(&ir->lock);
++
++	rc = iguanair_receiver(ir, false);
++	ir->receiver_on = false;
++	if (rc)
++		dev_warn(ir->dev, "failed to disable receiver: %d\n", rc);
++
++	usb_kill_urb(ir->urb_in);
++
++	mutex_unlock(&ir->lock);
++}
++
++static int __devinit iguanair_probe(struct usb_interface *intf,
++						const struct usb_device_id *id)
++{
++	struct usb_device *udev = interface_to_usbdev(intf);
++	struct iguanair *ir;
++	struct rc_dev *rc;
++	int ret;
++	struct usb_host_interface *idesc;
++
++	ir = kzalloc(sizeof(*ir), GFP_KERNEL);
++	rc = rc_allocate_device();
++	if (!ir || !rc) {
++		ret = ENOMEM;
++		goto out;
++	}
++
++	ir->buf_in = usb_alloc_coherent(udev, MAX_PACKET_SIZE, GFP_ATOMIC,
++								&ir->dma_in);
++	ir->urb_in = usb_alloc_urb(0, GFP_KERNEL);
++
++	if (!ir->buf_in || !ir->urb_in) {
++		ret = ENOMEM;
++		goto out;
++	}
++
++	idesc = intf->altsetting;
++
++	if (idesc->desc.bNumEndpoints < 2) {
++		ret = -ENODEV;
++		goto out;
++	}
++
++	ir->rc = rc;
++	ir->dev = &intf->dev;
++	ir->udev = udev;
++	ir->pipe_in = usb_rcvintpipe(udev,
++				idesc->endpoint[0].desc.bEndpointAddress);
++	ir->pipe_out = usb_sndintpipe(udev,
++				idesc->endpoint[1].desc.bEndpointAddress);
++	mutex_init(&ir->lock);
++	init_completion(&ir->completion);
++
++	ret = iguanair_get_features(ir);
++	if (ret) {
++		dev_warn(&intf->dev, "failed to get device features");
++		goto out;
++	}
++
++	usb_fill_int_urb(ir->urb_in, ir->udev, ir->pipe_in, ir->buf_in,
++		MAX_PACKET_SIZE, iguanair_rx, ir,
++		idesc->endpoint[0].desc.bInterval);
++	ir->urb_in->transfer_dma = ir->dma_in;
++	ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
++
++	snprintf(ir->name, sizeof(ir->name),
++		"IguanaWorks USB IR Transceiver version %d.%d",
++		ir->version[0], ir->version[1]);
++
++	usb_make_path(ir->udev, ir->phys, sizeof(ir->phys));
++
++	rc->input_name = ir->name;
++	rc->input_phys = ir->phys;
++	usb_to_input_id(ir->udev, &rc->input_id);
++	rc->dev.parent = &intf->dev;
++	rc->driver_type = RC_DRIVER_IR_RAW;
++	rc->allowed_protos = RC_TYPE_ALL;
++	rc->priv = ir;
++	rc->open = iguanair_open;
++	rc->close = iguanair_close;
++	rc->s_tx_mask = iguanair_set_tx_mask;
++	rc->s_tx_carrier = iguanair_set_tx_carrier;
++	rc->tx_ir = iguanair_tx;
++	rc->driver_name = DRIVER_NAME;
++	rc->map_name = RC_MAP_EMPTY;
++
++	iguanair_set_tx_carrier(rc, 38000);
++
++	ret = rc_register_device(rc);
++	if (ret < 0) {
++		dev_err(&intf->dev, "failed to register rc device %d", ret);
++		goto out;
++	}
++
++	usb_set_intfdata(intf, ir);
++
++	dev_info(&intf->dev, "Registered %s", ir->name);
++
++	return 0;
++out:
++	if (ir) {
++		usb_free_urb(ir->urb_in);
++		usb_free_coherent(udev, MAX_PACKET_SIZE, ir->buf_in,
++								ir->dma_in);
++	}
++	rc_free_device(rc);
++	kfree(ir);
++	return ret;
++}
++
++static void __devexit iguanair_disconnect(struct usb_interface *intf)
++{
++	struct iguanair *ir = usb_get_intfdata(intf);
++
++	usb_set_intfdata(intf, NULL);
++
++	usb_kill_urb(ir->urb_in);
++	usb_free_urb(ir->urb_in);
++	usb_free_coherent(ir->udev, MAX_PACKET_SIZE, ir->buf_in, ir->dma_in);
++	rc_unregister_device(ir->rc);
++	kfree(ir);
++}
++
++static int iguanair_suspend(struct usb_interface *intf, pm_message_t message)
++{
++	struct iguanair *ir = usb_get_intfdata(intf);
++	int rc = 0;
++
++	mutex_lock(&ir->lock);
++
++	if (ir->receiver_on) {
++		rc = iguanair_receiver(ir, false);
++		if (rc)
++			dev_warn(ir->dev, "failed to disable receiver for suspend\n");
++	}
++
++	mutex_unlock(&ir->lock);
++
++	return rc;
++}
++
++static int iguanair_resume(struct usb_interface *intf)
++{
++	struct iguanair *ir = usb_get_intfdata(intf);
++	int rc = 0;
++
++	mutex_lock(&ir->lock);
++
++	if (ir->receiver_on) {
++		rc = iguanair_receiver(ir, true);
++		if (rc)
++			dev_warn(ir->dev, "failed to enable receiver after resume\n");
++	}
++
++	mutex_unlock(&ir->lock);
++
++	return rc;
++}
++
++static const struct usb_device_id iguanair_table[] = {
++	{ USB_DEVICE(0x1781, 0x0938) },
++	{ }
++};
++
++static struct usb_driver iguanair_driver = {
++	.name =	DRIVER_NAME,
++	.probe = iguanair_probe,
++	.disconnect = __devexit_p(iguanair_disconnect),
++	.suspend = iguanair_suspend,
++	.resume = iguanair_resume,
++	.reset_resume = iguanair_resume,
++	.id_table = iguanair_table
++};
++
++module_usb_driver(iguanair_driver);
++
++MODULE_DESCRIPTION("IguanaWorks USB IR Transceiver");
++MODULE_AUTHOR("Sean Young <sean at mess.org>");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(usb, iguanair_table);
++

Added: dists/sid/linux/debian/patches/features/all/iguanair/0002-media-iguanair-reuse-existing-urb-callback-for-comma.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux/debian/patches/features/all/iguanair/0002-media-iguanair-reuse-existing-urb-callback-for-comma.patch	Sat Dec 29 13:57:44 2012	(r19663)
@@ -0,0 +1,313 @@
+From: Sean Young <sean at mess.org>
+Date: Mon, 13 Aug 2012 08:59:39 -0300
+Subject: [02/11] [media] iguanair: reuse existing urb callback for command
+ responses
+
+commit e99a7cfe93fd9b853d80e7dda8b86ecca71c22bb upstream.
+
+Rather than using usb_interrupt_msg() to receive responses, reuse the
+urb callback we already have in place.
+
+Signed-off-by: Sean Young <sean at mess.org>
+Signed-off-by: Mauro Carvalho Chehab <mchehab at redhat.com>
+---
+ drivers/media/rc/iguanair.c |  147 +++++++++++++++++--------------------------
+ 1 file changed, 56 insertions(+), 91 deletions(-)
+
+diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c
+index 5e2eaf8..bdd526d 100644
+--- a/drivers/media/rc/iguanair.c
++++ b/drivers/media/rc/iguanair.c
+@@ -35,7 +35,7 @@ struct iguanair {
+ 	struct device *dev;
+ 	struct usb_device *udev;
+ 
+-	int pipe_in, pipe_out;
++	int pipe_out;
+ 	uint8_t bufsize;
+ 	uint8_t version[2];
+ 
+@@ -82,11 +82,6 @@ struct packet {
+ 	uint8_t cmd;
+ };
+ 
+-struct response_packet {
+-	struct packet header;
+-	uint8_t data[4];
+-};
+-
+ struct send_packet {
+ 	struct packet header;
+ 	uint8_t length;
+@@ -100,6 +95,26 @@ static void process_ir_data(struct iguanair *ir, unsigned len)
+ {
+ 	if (len >= 4 && ir->buf_in[0] == 0 && ir->buf_in[1] == 0) {
+ 		switch (ir->buf_in[3]) {
++		case CMD_GET_VERSION:
++			if (len == 6) {
++				ir->version[0] = ir->buf_in[4];
++				ir->version[1] = ir->buf_in[5];
++				complete(&ir->completion);
++			}
++			break;
++		case CMD_GET_BUFSIZE:
++			if (len >= 5) {
++				ir->bufsize = ir->buf_in[4];
++				complete(&ir->completion);
++			}
++			break;
++		case CMD_GET_FEATURES:
++			if (len > 5) {
++				if (ir->version[0] >= 4)
++					ir->cycle_overhead = ir->buf_in[5];
++				complete(&ir->completion);
++			}
++			break;
+ 		case CMD_TX_OVERFLOW:
+ 			ir->tx_overflow = true;
+ 		case CMD_RECEIVER_OFF:
+@@ -169,31 +184,22 @@ static void iguanair_rx(struct urb *urb)
+ 	usb_submit_urb(urb, GFP_ATOMIC);
+ }
+ 
+-static int iguanair_send(struct iguanair *ir, void *data, unsigned size,
+-			struct response_packet *response, unsigned *res_len)
++static int iguanair_send(struct iguanair *ir, void *data, unsigned size)
+ {
+-	unsigned offset, len;
+ 	int rc, transferred;
+ 
+-	for (offset = 0; offset < size; offset += MAX_PACKET_SIZE) {
+-		len = min(size - offset, MAX_PACKET_SIZE);
+-
+-		if (ir->tx_overflow)
+-			return -EOVERFLOW;
++	INIT_COMPLETION(ir->completion);
+ 
+-		rc = usb_interrupt_msg(ir->udev, ir->pipe_out, data + offset,
+-						len, &transferred, TIMEOUT);
+-		if (rc)
+-			return rc;
++	rc = usb_interrupt_msg(ir->udev, ir->pipe_out, data, size,
++							&transferred, TIMEOUT);
++	if (rc)
++		return rc;
+ 
+-		if (transferred != len)
+-			return -EIO;
+-	}
++	if (transferred != size)
++		return -EIO;
+ 
+-	if (response) {
+-		rc = usb_interrupt_msg(ir->udev, ir->pipe_in, response,
+-					sizeof(*response), res_len, TIMEOUT);
+-	}
++	if (wait_for_completion_timeout(&ir->completion, TIMEOUT) == 0)
++		return -ETIMEDOUT;
+ 
+ 	return rc;
+ }
+@@ -201,66 +207,40 @@ static int iguanair_send(struct iguanair *ir, void *data, unsigned size,
+ static int iguanair_get_features(struct iguanair *ir)
+ {
+ 	struct packet packet;
+-	struct response_packet response;
+-	int rc, len;
++	int rc;
+ 
+ 	packet.start = 0;
+ 	packet.direction = DIR_OUT;
+ 	packet.cmd = CMD_GET_VERSION;
+ 
+-	rc = iguanair_send(ir, &packet, sizeof(packet), &response, &len);
++	rc = iguanair_send(ir, &packet, sizeof(packet));
+ 	if (rc) {
+ 		dev_info(ir->dev, "failed to get version\n");
+ 		goto out;
+ 	}
+ 
+-	if (len != 6) {
+-		dev_info(ir->dev, "failed to get version\n");
+-		rc = -EIO;
+-		goto out;
+-	}
+-
+-	ir->version[0] = response.data[0];
+-	ir->version[1] = response.data[1];
+ 	ir->bufsize = 150;
+ 	ir->cycle_overhead = 65;
+ 
+ 	packet.cmd = CMD_GET_BUFSIZE;
+ 
+-	rc = iguanair_send(ir, &packet, sizeof(packet), &response, &len);
++	rc = iguanair_send(ir, &packet, sizeof(packet));
+ 	if (rc) {
+ 		dev_info(ir->dev, "failed to get buffer size\n");
+ 		goto out;
+ 	}
+ 
+-	if (len != 5) {
+-		dev_info(ir->dev, "failed to get buffer size\n");
+-		rc = -EIO;
+-		goto out;
+-	}
+-
+-	ir->bufsize = response.data[0];
+-
+ 	if (ir->version[0] == 0 || ir->version[1] == 0)
+ 		goto out;
+ 
+ 	packet.cmd = CMD_GET_FEATURES;
+ 
+-	rc = iguanair_send(ir, &packet, sizeof(packet), &response, &len);
++	rc = iguanair_send(ir, &packet, sizeof(packet));
+ 	if (rc) {
+ 		dev_info(ir->dev, "failed to get features\n");
+ 		goto out;
+ 	}
+ 
+-	if (len < 5) {
+-		dev_info(ir->dev, "failed to get features\n");
+-		rc = -EIO;
+-		goto out;
+-	}
+-
+-	if (len > 5 && ir->version[0] >= 4)
+-		ir->cycle_overhead = response.data[1];
+-
+ out:
+ 	return rc;
+ }
+@@ -269,17 +249,8 @@ static int iguanair_receiver(struct iguanair *ir, bool enable)
+ {
+ 	struct packet packet = { 0, DIR_OUT, enable ?
+ 				CMD_RECEIVER_ON : CMD_RECEIVER_OFF };
+-	int rc;
+-
+-	INIT_COMPLETION(ir->completion);
+-
+-	rc = iguanair_send(ir, &packet, sizeof(packet), NULL, NULL);
+-	if (rc)
+-		return rc;
+-
+-	wait_for_completion_timeout(&ir->completion, TIMEOUT);
+ 
+-	return 0;
++	return iguanair_send(ir, &packet, sizeof(packet));
+ }
+ 
+ /*
+@@ -406,17 +377,10 @@ static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count)
+ 
+ 	ir->tx_overflow = false;
+ 
+-	INIT_COMPLETION(ir->completion);
+-
+-	rc = iguanair_send(ir, packet, size + 8, NULL, NULL);
++	rc = iguanair_send(ir, packet, size + 8);
+ 
+-	if (rc == 0) {
+-		wait_for_completion_timeout(&ir->completion, TIMEOUT);
+-		if (ir->tx_overflow)
+-			rc = -EOVERFLOW;
+-	}
+-
+-	ir->tx_overflow = false;
++	if (rc == 0 && ir->tx_overflow)
++		rc = -EOVERFLOW;
+ 
+ 	if (ir->receiver_on) {
+ 		if (iguanair_receiver(ir, true))
+@@ -437,8 +401,6 @@ static int iguanair_open(struct rc_dev *rdev)
+ 
+ 	mutex_lock(&ir->lock);
+ 
+-	usb_submit_urb(ir->urb_in, GFP_KERNEL);
+-
+ 	BUG_ON(ir->receiver_on);
+ 
+ 	rc = iguanair_receiver(ir, true);
+@@ -462,8 +424,6 @@ static void iguanair_close(struct rc_dev *rdev)
+ 	if (rc)
+ 		dev_warn(ir->dev, "failed to disable receiver: %d\n", rc);
+ 
+-	usb_kill_urb(ir->urb_in);
+-
+ 	mutex_unlock(&ir->lock);
+ }
+ 
+@@ -473,7 +433,7 @@ static int __devinit iguanair_probe(struct usb_interface *intf,
+ 	struct usb_device *udev = interface_to_usbdev(intf);
+ 	struct iguanair *ir;
+ 	struct rc_dev *rc;
+-	int ret;
++	int ret, pipein;
+ 	struct usb_host_interface *idesc;
+ 
+ 	ir = kzalloc(sizeof(*ir), GFP_KERNEL);
+@@ -483,7 +443,7 @@ static int __devinit iguanair_probe(struct usb_interface *intf,
+ 		goto out;
+ 	}
+ 
+-	ir->buf_in = usb_alloc_coherent(udev, MAX_PACKET_SIZE, GFP_ATOMIC,
++	ir->buf_in = usb_alloc_coherent(udev, MAX_PACKET_SIZE, GFP_KERNEL,
+ 								&ir->dma_in);
+ 	ir->urb_in = usb_alloc_urb(0, GFP_KERNEL);
+ 
+@@ -502,25 +462,28 @@ static int __devinit iguanair_probe(struct usb_interface *intf,
+ 	ir->rc = rc;
+ 	ir->dev = &intf->dev;
+ 	ir->udev = udev;
+-	ir->pipe_in = usb_rcvintpipe(udev,
+-				idesc->endpoint[0].desc.bEndpointAddress);
+ 	ir->pipe_out = usb_sndintpipe(udev,
+ 				idesc->endpoint[1].desc.bEndpointAddress);
+ 	mutex_init(&ir->lock);
+ 	init_completion(&ir->completion);
+ 
+-	ret = iguanair_get_features(ir);
+-	if (ret) {
+-		dev_warn(&intf->dev, "failed to get device features");
+-		goto out;
+-	}
+-
+-	usb_fill_int_urb(ir->urb_in, ir->udev, ir->pipe_in, ir->buf_in,
++	pipein = usb_rcvintpipe(udev, idesc->endpoint[0].desc.bEndpointAddress);
++	usb_fill_int_urb(ir->urb_in, udev, pipein, ir->buf_in,
+ 		MAX_PACKET_SIZE, iguanair_rx, ir,
+ 		idesc->endpoint[0].desc.bInterval);
+ 	ir->urb_in->transfer_dma = ir->dma_in;
+ 	ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ 
++	ret = usb_submit_urb(ir->urb_in, GFP_KERNEL);
++	if (ret) {
++		dev_warn(&intf->dev, "failed to submit urb: %d\n", ret);
++		goto out;
++	}
++
++	ret = iguanair_get_features(ir);
++	if (ret)
++		goto out2;
++
+ 	snprintf(ir->name, sizeof(ir->name),
+ 		"IguanaWorks USB IR Transceiver version %d.%d",
+ 		ir->version[0], ir->version[1]);
+@@ -547,7 +510,7 @@ static int __devinit iguanair_probe(struct usb_interface *intf,
+ 	ret = rc_register_device(rc);
+ 	if (ret < 0) {
+ 		dev_err(&intf->dev, "failed to register rc device %d", ret);
+-		goto out;
++		goto out2;
+ 	}
+ 
+ 	usb_set_intfdata(intf, ir);
+@@ -555,6 +518,8 @@ static int __devinit iguanair_probe(struct usb_interface *intf,
+ 	dev_info(&intf->dev, "Registered %s", ir->name);
+ 
+ 	return 0;
++out2:
++	usb_kill_urb(ir->urb_in);
+ out:
+ 	if (ir) {
+ 		usb_free_urb(ir->urb_in);

Added: dists/sid/linux/debian/patches/features/all/iguanair/0003-media-iguanair-ignore-unsupported-firmware-versions.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux/debian/patches/features/all/iguanair/0003-media-iguanair-ignore-unsupported-firmware-versions.patch	Sat Dec 29 13:57:44 2012	(r19663)
@@ -0,0 +1,103 @@
+From: Sean Young <sean at mess.org>
+Date: Mon, 13 Aug 2012 08:59:40 -0300
+Subject: [03/11] [media] iguanair: ignore unsupported firmware versions
+
+commit 0797b4802b57ce88e9361c8d64b0980508370649 upstream.
+
+Firmware versions lower than 0x0205 use a different interface which is not
+supported. Also report the firmware version in the standard format.
+
+Signed-off-by: Sean Young <sean at mess.org>
+Signed-off-by: Mauro Carvalho Chehab <mchehab at redhat.com>
+---
+ drivers/media/rc/Kconfig    |    8 ++++++--
+ drivers/media/rc/iguanair.c |   21 +++++++++++----------
+ 2 files changed, 17 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
+index 5180390..2e91e66 100644
+--- a/drivers/media/rc/Kconfig
++++ b/drivers/media/rc/Kconfig
+@@ -264,8 +264,12 @@ config IR_IGUANA
+ 	depends on RC_CORE
+ 	select USB
+ 	---help---
+-	   Say Y here if you want to use the IgaunaWorks USB IR Transceiver.
+-	   Both infrared receive and send are supported.
++	   Say Y here if you want to use the IguanaWorks USB IR Transceiver.
++	   Both infrared receive and send are supported. If you want to
++	   change the ID or the pin config, use the user space driver from
++	   IguanaWorks.
++
++	   Only firmware 0x0205 and later is supported.
+ 
+ 	   To compile this driver as a module, choose M here: the module will
+ 	   be called iguanair.
+diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c
+index bdd526d..5885400 100644
+--- a/drivers/media/rc/iguanair.c
++++ b/drivers/media/rc/iguanair.c
+@@ -36,8 +36,8 @@ struct iguanair {
+ 	struct usb_device *udev;
+ 
+ 	int pipe_out;
++	uint16_t version;
+ 	uint8_t bufsize;
+-	uint8_t version[2];
+ 
+ 	struct mutex lock;
+ 
+@@ -97,8 +97,8 @@ static void process_ir_data(struct iguanair *ir, unsigned len)
+ 		switch (ir->buf_in[3]) {
+ 		case CMD_GET_VERSION:
+ 			if (len == 6) {
+-				ir->version[0] = ir->buf_in[4];
+-				ir->version[1] = ir->buf_in[5];
++				ir->version = (ir->buf_in[5] << 8) |
++							ir->buf_in[4];
+ 				complete(&ir->completion);
+ 			}
+ 			break;
+@@ -110,8 +110,7 @@ static void process_ir_data(struct iguanair *ir, unsigned len)
+ 			break;
+ 		case CMD_GET_FEATURES:
+ 			if (len > 5) {
+-				if (ir->version[0] >= 4)
+-					ir->cycle_overhead = ir->buf_in[5];
++				ir->cycle_overhead = ir->buf_in[5];
+ 				complete(&ir->completion);
+ 			}
+ 			break;
+@@ -219,6 +218,12 @@ static int iguanair_get_features(struct iguanair *ir)
+ 		goto out;
+ 	}
+ 
++	if (ir->version < 0x205) {
++		dev_err(ir->dev, "firmware 0x%04x is too old\n", ir->version);
++		rc = -ENODEV;
++		goto out;
++	}
++
+ 	ir->bufsize = 150;
+ 	ir->cycle_overhead = 65;
+ 
+@@ -230,9 +235,6 @@ static int iguanair_get_features(struct iguanair *ir)
+ 		goto out;
+ 	}
+ 
+-	if (ir->version[0] == 0 || ir->version[1] == 0)
+-		goto out;
+-
+ 	packet.cmd = CMD_GET_FEATURES;
+ 
+ 	rc = iguanair_send(ir, &packet, sizeof(packet));
+@@ -485,8 +487,7 @@ static int __devinit iguanair_probe(struct usb_interface *intf,
+ 		goto out2;
+ 
+ 	snprintf(ir->name, sizeof(ir->name),
+-		"IguanaWorks USB IR Transceiver version %d.%d",
+-		ir->version[0], ir->version[1]);
++		"IguanaWorks USB IR Transceiver version 0x%04x", ir->version);
+ 
+ 	usb_make_path(ir->udev, ir->phys, sizeof(ir->phys));
+ 

Added: dists/sid/linux/debian/patches/features/all/iguanair/0004-media-iguanair-support-suspend-and-resume.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux/debian/patches/features/all/iguanair/0004-media-iguanair-support-suspend-and-resume.patch	Sat Dec 29 13:57:44 2012	(r19663)
@@ -0,0 +1,99 @@
+From: Sean Young <sean at mess.org>
+Date: Mon, 13 Aug 2012 08:59:43 -0300
+Subject: [04/11] [media] iguanair: support suspend and resume
+
+commit 7c0bd96b767da250e5aa5ee135c530d87454d9fe upstream.
+
+Now unbind also stops the receiver.
+
+Signed-off-by: Sean Young <sean at mess.org>
+Signed-off-by: Mauro Carvalho Chehab <mchehab at redhat.com>
+---
+ drivers/media/rc/iguanair.c |   21 ++++++++++++++-------
+ 1 file changed, 14 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c
+index 5885400..f1c5846 100644
+--- a/drivers/media/rc/iguanair.c
++++ b/drivers/media/rc/iguanair.c
+@@ -155,6 +155,7 @@ static void process_ir_data(struct iguanair *ir, unsigned len)
+ static void iguanair_rx(struct urb *urb)
+ {
+ 	struct iguanair *ir;
++	int rc;
+ 
+ 	if (!urb)
+ 		return;
+@@ -180,7 +181,9 @@ static void iguanair_rx(struct urb *urb)
+ 		break;
+ 	}
+ 
+-	usb_submit_urb(urb, GFP_ATOMIC);
++	rc = usb_submit_urb(urb, GFP_ATOMIC);
++	if (rc && rc != -ENODEV)
++		dev_warn(ir->dev, "failed to resubmit urb: %d\n", rc);
+ }
+ 
+ static int iguanair_send(struct iguanair *ir, void *data, unsigned size)
+@@ -423,7 +426,7 @@ static void iguanair_close(struct rc_dev *rdev)
+ 
+ 	rc = iguanair_receiver(ir, false);
+ 	ir->receiver_on = false;
+-	if (rc)
++	if (rc && rc != -ENODEV)
+ 		dev_warn(ir->dev, "failed to disable receiver: %d\n", rc);
+ 
+ 	mutex_unlock(&ir->lock);
+@@ -516,8 +519,6 @@ static int __devinit iguanair_probe(struct usb_interface *intf,
+ 
+ 	usb_set_intfdata(intf, ir);
+ 
+-	dev_info(&intf->dev, "Registered %s", ir->name);
+-
+ 	return 0;
+ out2:
+ 	usb_kill_urb(ir->urb_in);
+@@ -536,12 +537,11 @@ static void __devexit iguanair_disconnect(struct usb_interface *intf)
+ {
+ 	struct iguanair *ir = usb_get_intfdata(intf);
+ 
++	rc_unregister_device(ir->rc);
+ 	usb_set_intfdata(intf, NULL);
+-
+ 	usb_kill_urb(ir->urb_in);
+ 	usb_free_urb(ir->urb_in);
+ 	usb_free_coherent(ir->udev, MAX_PACKET_SIZE, ir->buf_in, ir->dma_in);
+-	rc_unregister_device(ir->rc);
+ 	kfree(ir);
+ }
+ 
+@@ -558,6 +558,8 @@ static int iguanair_suspend(struct usb_interface *intf, pm_message_t message)
+ 			dev_warn(ir->dev, "failed to disable receiver for suspend\n");
+ 	}
+ 
++	usb_kill_urb(ir->urb_in);
++
+ 	mutex_unlock(&ir->lock);
+ 
+ 	return rc;
+@@ -570,6 +572,10 @@ static int iguanair_resume(struct usb_interface *intf)
+ 
+ 	mutex_lock(&ir->lock);
+ 
++	rc = usb_submit_urb(ir->urb_in, GFP_KERNEL);
++	if (rc)
++		dev_warn(&intf->dev, "failed to submit urb: %d\n", rc);
++
+ 	if (ir->receiver_on) {
+ 		rc = iguanair_receiver(ir, true);
+ 		if (rc)
+@@ -593,7 +599,8 @@ static struct usb_driver iguanair_driver = {
+ 	.suspend = iguanair_suspend,
+ 	.resume = iguanair_resume,
+ 	.reset_resume = iguanair_resume,
+-	.id_table = iguanair_table
++	.id_table = iguanair_table,
++	.soft_unbind = 1	/* we want to disable receiver on unbind */
+ };
+ 
+ module_usb_driver(iguanair_driver);

Added: dists/sid/linux/debian/patches/features/all/iguanair/0005-media-iguanair-fix-return-value-for-transmit.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux/debian/patches/features/all/iguanair/0005-media-iguanair-fix-return-value-for-transmit.patch	Sat Dec 29 13:57:44 2012	(r19663)
@@ -0,0 +1,98 @@
+From: Sean Young <sean at mess.org>
+Date: Mon, 13 Aug 2012 08:59:42 -0300
+Subject: [05/11] [media] iguanair: fix return value for transmit
+
+commit 884bfd08e3d4f694574e54bd1886cd8817d9b986 upstream.
+
+Also fix error codes returned from open.
+
+Signed-off-by: Sean Young <sean at mess.org>
+Signed-off-by: Mauro Carvalho Chehab <mchehab at redhat.com>
+---
+ drivers/media/rc/iguanair.c |   30 ++++++++++++++++++------------
+ 1 file changed, 18 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c
+index f1c5846..6817258 100644
+--- a/drivers/media/rc/iguanair.c
++++ b/drivers/media/rc/iguanair.c
+@@ -327,7 +327,7 @@ static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count)
+ {
+ 	struct iguanair *ir = dev->priv;
+ 	uint8_t space, *payload;
+-	unsigned i, size, rc;
++	unsigned i, size, rc, bytes;
+ 	struct send_packet *packet;
+ 
+ 	mutex_lock(&ir->lock);
+@@ -335,17 +335,22 @@ static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count)
+ 	/* convert from us to carrier periods */
+ 	for (i = size = 0; i < count; i++) {
+ 		txbuf[i] = DIV_ROUND_CLOSEST(txbuf[i] * ir->carrier, 1000000);
+-		size += (txbuf[i] + 126) / 127;
++		bytes = (txbuf[i] + 126) / 127;
++		if (size + bytes > ir->bufsize) {
++			count = i;
++			break;
++		}
++		size += bytes;
+ 	}
+ 
+-	packet = kmalloc(sizeof(*packet) + size, GFP_KERNEL);
+-	if (!packet) {
+-		rc = -ENOMEM;
++	if (count == 0) {
++		rc = -EINVAL;
+ 		goto out;
+ 	}
+ 
+-	if (size > ir->bufsize) {
+-		rc = -E2BIG;
++	packet = kmalloc(sizeof(*packet) + size, GFP_KERNEL);
++	if (!packet) {
++		rc = -ENOMEM;
+ 		goto out;
+ 	}
+ 
+@@ -376,7 +381,7 @@ static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count)
+ 		rc = iguanair_receiver(ir, false);
+ 		if (rc) {
+ 			dev_warn(ir->dev, "disable receiver before transmit failed\n");
+-			goto out;
++			goto out_kfree;
+ 		}
+ 	}
+ 
+@@ -392,11 +397,12 @@ static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count)
+ 			dev_warn(ir->dev, "re-enable receiver after transmit failed\n");
+ 	}
+ 
++out_kfree:
++	kfree(packet);
+ out:
+ 	mutex_unlock(&ir->lock);
+-	kfree(packet);
+ 
+-	return rc;
++	return rc ? rc : count;
+ }
+ 
+ static int iguanair_open(struct rc_dev *rdev)
+@@ -444,7 +450,7 @@ static int __devinit iguanair_probe(struct usb_interface *intf,
+ 	ir = kzalloc(sizeof(*ir), GFP_KERNEL);
+ 	rc = rc_allocate_device();
+ 	if (!ir || !rc) {
+-		ret = ENOMEM;
++		ret = -ENOMEM;
+ 		goto out;
+ 	}
+ 
+@@ -453,7 +459,7 @@ static int __devinit iguanair_probe(struct usb_interface *intf,
+ 	ir->urb_in = usb_alloc_urb(0, GFP_KERNEL);
+ 
+ 	if (!ir->buf_in || !ir->urb_in) {
+-		ret = ENOMEM;
++		ret = -ENOMEM;
+ 		goto out;
+ 	}
+ 

Added: dists/sid/linux/debian/patches/features/all/iguanair/0006-media-iguanair-reset-the-IR-state-after-rx-overflow-.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux/debian/patches/features/all/iguanair/0006-media-iguanair-reset-the-IR-state-after-rx-overflow-.patch	Sat Dec 29 13:57:44 2012	(r19663)
@@ -0,0 +1,35 @@
+From: Sean Young <sean at mess.org>
+Date: Mon, 13 Aug 2012 08:59:44 -0300
+Subject: [06/11] [media] iguanair: reset the IR state after rx overflow or
+ receiver enable
+
+commit 116e4f592a4d207031b2eaf9dacb57de587146ef upstream.
+
+Signed-off-by: Sean Young <sean at mess.org>
+Signed-off-by: Mauro Carvalho Chehab <mchehab at redhat.com>
+---
+ drivers/media/rc/iguanair.c |    4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c
+index 6817258..8de690a 100644
+--- a/drivers/media/rc/iguanair.c
++++ b/drivers/media/rc/iguanair.c
+@@ -123,6 +123,7 @@ static void process_ir_data(struct iguanair *ir, unsigned len)
+ 			break;
+ 		case CMD_RX_OVERFLOW:
+ 			dev_warn(ir->dev, "receive overflow\n");
++			ir_raw_event_reset(ir->rc);
+ 			break;
+ 		default:
+ 			dev_warn(ir->dev, "control code %02x received\n",
+@@ -255,6 +256,9 @@ static int iguanair_receiver(struct iguanair *ir, bool enable)
+ 	struct packet packet = { 0, DIR_OUT, enable ?
+ 				CMD_RECEIVER_ON : CMD_RECEIVER_OFF };
+ 
++	if (enable)
++		ir_raw_event_reset(ir->rc);
++
+ 	return iguanair_send(ir, &packet, sizeof(packet));
+ }
+ 

Added: dists/sid/linux/debian/patches/features/all/iguanair/0007-media-iguanair-advertise-the-resolution-and-timeout-.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux/debian/patches/features/all/iguanair/0007-media-iguanair-advertise-the-resolution-and-timeout-.patch	Sat Dec 29 13:57:44 2012	(r19663)
@@ -0,0 +1,48 @@
+From: Sean Young <sean at mess.org>
+Date: Mon, 13 Aug 2012 08:59:41 -0300
+Subject: [07/11] [media] iguanair: advertise the resolution and timeout
+ properly
+
+commit 2eec676cd3097bc37618e57c19b17cbeac13cdf4 upstream.
+
+With the timeout supplied the interface can go idle. The keymap is
+the same one as other drivers which do not come with a remote.
+
+Signed-off-by: Sean Young <sean at mess.org>
+Signed-off-by: Mauro Carvalho Chehab <mchehab at redhat.com>
+---
+ drivers/media/rc/iguanair.c |    7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c
+index 8de690a..9810008 100644
+--- a/drivers/media/rc/iguanair.c
++++ b/drivers/media/rc/iguanair.c
+@@ -75,6 +75,7 @@ struct iguanair {
+ 
+ #define MAX_PACKET_SIZE		8u
+ #define TIMEOUT			1000
++#define RX_RESOLUTION		21333
+ 
+ struct packet {
+ 	uint16_t start;
+@@ -143,7 +144,7 @@ static void process_ir_data(struct iguanair *ir, unsigned len)
+ 			} else {
+ 				rawir.pulse = (ir->buf_in[i] & 0x80) == 0;
+ 				rawir.duration = ((ir->buf_in[i] & 0x7f) + 1) *
+-									 21330;
++								 RX_RESOLUTION;
+ 			}
+ 
+ 			ir_raw_event_store_with_filter(ir->rc, &rawir);
+@@ -517,7 +518,9 @@ static int __devinit iguanair_probe(struct usb_interface *intf,
+ 	rc->s_tx_carrier = iguanair_set_tx_carrier;
+ 	rc->tx_ir = iguanair_tx;
+ 	rc->driver_name = DRIVER_NAME;
+-	rc->map_name = RC_MAP_EMPTY;
++	rc->map_name = RC_MAP_RC6_MCE;
++	rc->timeout = MS_TO_NS(100);
++	rc->rx_resolution = RX_RESOLUTION;
+ 
+ 	iguanair_set_tx_carrier(rc, 38000);
+ 

Added: dists/sid/linux/debian/patches/features/all/iguanair/0008-media-iguanair-fix-receiver-overflow.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux/debian/patches/features/all/iguanair/0008-media-iguanair-fix-receiver-overflow.patch	Sat Dec 29 13:57:44 2012	(r19663)
@@ -0,0 +1,36 @@
+From: Sean Young <sean at mess.org>
+Date: Mon, 13 Aug 2012 08:59:45 -0300
+Subject: [08/11] [media] iguanair: fix receiver overflow
+
+commit 640583836b9488c806349e3839c9d8b0f15da1fa upstream.
+
+The Pioneer CU-700 remote causes receiver overflows if you hold down any
+button. The remote does not send NEC IR repeats, it repeats the entire
+NEC code after 20ms.
+
+The iguanair hardware advertises an interval of 10 which just not enough;
+with 100 URBs per second and at most 7 edges per URB, we handle at most
+700 edges per second. The remote generates about 900.
+
+Signed-off-by: Sean Young <sean at mess.org>
+Signed-off-by: Mauro Carvalho Chehab <mchehab at redhat.com>
+---
+ drivers/media/rc/iguanair.c |    5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c
+index 9810008..6a09c2e 100644
+--- a/drivers/media/rc/iguanair.c
++++ b/drivers/media/rc/iguanair.c
+@@ -484,9 +484,8 @@ static int __devinit iguanair_probe(struct usb_interface *intf,
+ 	init_completion(&ir->completion);
+ 
+ 	pipein = usb_rcvintpipe(udev, idesc->endpoint[0].desc.bEndpointAddress);
+-	usb_fill_int_urb(ir->urb_in, udev, pipein, ir->buf_in,
+-		MAX_PACKET_SIZE, iguanair_rx, ir,
+-		idesc->endpoint[0].desc.bInterval);
++	usb_fill_int_urb(ir->urb_in, udev, pipein, ir->buf_in, MAX_PACKET_SIZE,
++							 iguanair_rx, ir, 1);
+ 	ir->urb_in->transfer_dma = ir->dma_in;
+ 	ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ 

Added: dists/sid/linux/debian/patches/features/all/iguanair/0009-media-rc-do-not-wake-up-rc-thread-unless-there-is-so.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux/debian/patches/features/all/iguanair/0009-media-rc-do-not-wake-up-rc-thread-unless-there-is-so.patch	Sat Dec 29 13:57:44 2012	(r19663)
@@ -0,0 +1,42 @@
+From: Sean Young <sean at mess.org>
+Date: Mon, 13 Aug 2012 08:59:47 -0300
+Subject: [09/12] [media] rc: do not wake up rc thread unless there is
+ something to do
+
+commit b83bfd1b0127b0963fcac39280280e365e7e04d8 upstream.
+
+The TechnoTrend USB IR Receiver sends 125 ISO URBs per second, even when
+there is no IR activity. Reduce the number of wake ups from the other
+drivers too.
+
+This saves about 0.25ms/s on a 2.4GHz Core 2 according to powertop.
+
+Signed-off-by: Sean Young <sean at mess.org>
+Signed-off-by: Mauro Carvalho Chehab <mchehab at redhat.com>
+[bwh: Restricted to iguanair driver]
+---
+--- a/drivers/media/rc/iguanair.c
++++ b/drivers/media/rc/iguanair.c
+@@ -134,6 +134,7 @@ static void process_ir_data(struct iguanair *ir, unsigned len)
+ 	} else if (len >= 7) {
+ 		DEFINE_IR_RAW_EVENT(rawir);
+ 		unsigned i;
++		bool event = false;
+ 
+ 		init_ir_raw_event(&rawir);
+ 
+@@ -147,10 +148,12 @@ static void process_ir_data(struct iguanair *ir, unsigned len)
+ 								 RX_RESOLUTION;
+ 			}
+ 
+-			ir_raw_event_store_with_filter(ir->rc, &rawir);
++			if (ir_raw_event_store_with_filter(ir->rc, &rawir))
++				event = true;
+ 		}
+ 
+-		ir_raw_event_handle(ir->rc);
++		if (event)
++			ir_raw_event_handle(ir->rc);
+ 	}
+ }
+ 

Added: dists/sid/linux/debian/patches/features/all/iguanair/0010-media-iguanair-do-not-modify-transmit-buffer.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux/debian/patches/features/all/iguanair/0010-media-iguanair-do-not-modify-transmit-buffer.patch	Sat Dec 29 13:57:44 2012	(r19663)
@@ -0,0 +1,112 @@
+From: Sean Young <sean at mess.org>
+Date: Sat, 25 Aug 2012 07:01:45 -0300
+Subject: [10/11] [media] iguanair: do not modify transmit buffer
+
+commit 3920631c4b8af70893fe70df53e94adb0cd66f71 upstream.
+
+Since commit "[media] rc-core: move timeout and checks to lirc", the
+incoming buffer is used after the driver transmits.
+
+Signed-off-by: Sean Young <sean at mess.org>
+Signed-off-by: Mauro Carvalho Chehab <mchehab at redhat.com>
+---
+ drivers/media/rc/iguanair.c |   51 ++++++++++++++++++-------------------------
+ 1 file changed, 21 insertions(+), 30 deletions(-)
+
+diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c
+index 66ba237..1e4c68a 100644
+--- a/drivers/media/rc/iguanair.c
++++ b/drivers/media/rc/iguanair.c
+@@ -334,21 +334,34 @@ static int iguanair_set_tx_mask(struct rc_dev *dev, uint32_t mask)
+ static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count)
+ {
+ 	struct iguanair *ir = dev->priv;
+-	uint8_t space, *payload;
+-	unsigned i, size, rc, bytes;
++	uint8_t space;
++	unsigned i, size, periods, bytes;
++	int rc;
+ 	struct send_packet *packet;
+ 
+ 	mutex_lock(&ir->lock);
+ 
++	packet = kmalloc(sizeof(*packet) + ir->bufsize, GFP_KERNEL);
++	if (!packet) {
++		rc = -ENOMEM;
++		goto out;
++	}
++
+ 	/* convert from us to carrier periods */
+-	for (i = size = 0; i < count; i++) {
+-		txbuf[i] = DIV_ROUND_CLOSEST(txbuf[i] * ir->carrier, 1000000);
+-		bytes = (txbuf[i] + 126) / 127;
++	for (i = space = size = 0; i < count; i++) {
++		periods = DIV_ROUND_CLOSEST(txbuf[i] * ir->carrier, 1000000);
++		bytes = DIV_ROUND_UP(periods, 127);
+ 		if (size + bytes > ir->bufsize) {
+ 			count = i;
+ 			break;
+ 		}
+-		size += bytes;
++		while (periods > 127) {
++			packet->payload[size++] = 127 | space;
++			periods -= 127;
++		}
++
++		packet->payload[size++] = periods | space;
++		space ^= 0x80;
+ 	}
+ 
+ 	if (count == 0) {
+@@ -356,12 +369,6 @@ static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count)
+ 		goto out;
+ 	}
+ 
+-	packet = kmalloc(sizeof(*packet) + size, GFP_KERNEL);
+-	if (!packet) {
+-		rc = -ENOMEM;
+-		goto out;
+-	}
+-
+ 	packet->header.start = 0;
+ 	packet->header.direction = DIR_OUT;
+ 	packet->header.cmd = CMD_SEND;
+@@ -370,26 +377,11 @@ static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count)
+ 	packet->busy7 = ir->busy7;
+ 	packet->busy4 = ir->busy4;
+ 
+-	space = 0;
+-	payload = packet->payload;
+-
+-	for (i = 0; i < count; i++) {
+-		unsigned periods = txbuf[i];
+-
+-		while (periods > 127) {
+-			*payload++ = 127 | space;
+-			periods -= 127;
+-		}
+-
+-		*payload++ = periods | space;
+-		space ^= 0x80;
+-	}
+-
+ 	if (ir->receiver_on) {
+ 		rc = iguanair_receiver(ir, false);
+ 		if (rc) {
+ 			dev_warn(ir->dev, "disable receiver before transmit failed\n");
+-			goto out_kfree;
++			goto out;
+ 		}
+ 	}
+ 
+@@ -405,9 +397,8 @@ static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count)
+ 			dev_warn(ir->dev, "re-enable receiver after transmit failed\n");
+ 	}
+ 
+-out_kfree:
+-	kfree(packet);
+ out:
++	kfree(packet);
+ 	mutex_unlock(&ir->lock);
+ 
+ 	return rc ? rc : count;

Added: dists/sid/linux/debian/patches/features/all/iguanair/0011-media-iguanair-cannot-send-data-from-the-stack.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux/debian/patches/features/all/iguanair/0011-media-iguanair-cannot-send-data-from-the-stack.patch	Sat Dec 29 13:57:44 2012	(r19663)
@@ -0,0 +1,359 @@
+From: Sean Young <sean at mess.org>
+Date: Fri, 28 Sep 2012 04:44:29 -0300
+Subject: [11/11] [media] iguanair: cannot send data from the stack
+
+commit 48b0fa6afa7ee6a274e060564d2389ffea413762 upstream.
+
+Note that the firmware already disables the receiver before transmit,
+there is no need to do this from the driver.
+
+Reported-by: Fengguang Wu <fengguang.wu at intel.com>
+Signed-off-by: Sean Young <sean at mess.org>
+Signed-off-by: Mauro Carvalho Chehab <mchehab at redhat.com>
+---
+ drivers/media/rc/iguanair.c |  147 ++++++++++++++++++++++---------------------
+ 1 file changed, 75 insertions(+), 72 deletions(-)
+
+diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c
+index 1e4c68a..51d7057 100644
+--- a/drivers/media/rc/iguanair.c
++++ b/drivers/media/rc/iguanair.c
+@@ -28,6 +28,7 @@
+ #include <media/rc-core.h>
+ 
+ #define DRIVER_NAME "iguanair"
++#define BUF_SIZE 152
+ 
+ struct iguanair {
+ 	struct rc_dev *rc;
+@@ -35,26 +36,23 @@ struct iguanair {
+ 	struct device *dev;
+ 	struct usb_device *udev;
+ 
+-	int pipe_out;
+ 	uint16_t version;
+ 	uint8_t bufsize;
++	uint8_t cycle_overhead;
+ 
+ 	struct mutex lock;
+ 
+ 	/* receiver support */
+ 	bool receiver_on;
+-	dma_addr_t dma_in;
++	dma_addr_t dma_in, dma_out;
+ 	uint8_t *buf_in;
+-	struct urb *urb_in;
++	struct urb *urb_in, *urb_out;
+ 	struct completion completion;
+ 
+ 	/* transmit support */
+ 	bool tx_overflow;
+ 	uint32_t carrier;
+-	uint8_t cycle_overhead;
+-	uint8_t channels;
+-	uint8_t busy4;
+-	uint8_t busy7;
++	struct send_packet *packet;
+ 
+ 	char name[64];
+ 	char phys[64];
+@@ -73,7 +71,8 @@ struct iguanair {
+ #define DIR_IN			0xdc
+ #define DIR_OUT			0xcd
+ 
+-#define MAX_PACKET_SIZE		8u
++#define MAX_IN_PACKET		8u
++#define MAX_OUT_PACKET		(sizeof(struct send_packet) + BUF_SIZE)
+ #define TIMEOUT			1000
+ #define RX_RESOLUTION		21333
+ 
+@@ -191,20 +190,25 @@ static void iguanair_rx(struct urb *urb)
+ 		dev_warn(ir->dev, "failed to resubmit urb: %d\n", rc);
+ }
+ 
+-static int iguanair_send(struct iguanair *ir, void *data, unsigned size)
++static void iguanair_irq_out(struct urb *urb)
+ {
+-	int rc, transferred;
++	struct iguanair *ir = urb->context;
++
++	if (urb->status)
++		dev_dbg(ir->dev, "Error: out urb status = %d\n", urb->status);
++}
++
++static int iguanair_send(struct iguanair *ir, unsigned size)
++{
++	int rc;
+ 
+ 	INIT_COMPLETION(ir->completion);
+ 
+-	rc = usb_interrupt_msg(ir->udev, ir->pipe_out, data, size,
+-							&transferred, TIMEOUT);
++	ir->urb_out->transfer_buffer_length = size;
++	rc = usb_submit_urb(ir->urb_out, GFP_KERNEL);
+ 	if (rc)
+ 		return rc;
+ 
+-	if (transferred != size)
+-		return -EIO;
+-
+ 	if (wait_for_completion_timeout(&ir->completion, TIMEOUT) == 0)
+ 		return -ETIMEDOUT;
+ 
+@@ -213,14 +217,13 @@ static int iguanair_send(struct iguanair *ir, void *data, unsigned size)
+ 
+ static int iguanair_get_features(struct iguanair *ir)
+ {
+-	struct packet packet;
+ 	int rc;
+ 
+-	packet.start = 0;
+-	packet.direction = DIR_OUT;
+-	packet.cmd = CMD_GET_VERSION;
++	ir->packet->header.start = 0;
++	ir->packet->header.direction = DIR_OUT;
++	ir->packet->header.cmd = CMD_GET_VERSION;
+ 
+-	rc = iguanair_send(ir, &packet, sizeof(packet));
++	rc = iguanair_send(ir, sizeof(ir->packet->header));
+ 	if (rc) {
+ 		dev_info(ir->dev, "failed to get version\n");
+ 		goto out;
+@@ -235,17 +238,23 @@ static int iguanair_get_features(struct iguanair *ir)
+ 	ir->bufsize = 150;
+ 	ir->cycle_overhead = 65;
+ 
+-	packet.cmd = CMD_GET_BUFSIZE;
++	ir->packet->header.cmd = CMD_GET_BUFSIZE;
+ 
+-	rc = iguanair_send(ir, &packet, sizeof(packet));
++	rc = iguanair_send(ir, sizeof(ir->packet->header));
+ 	if (rc) {
+ 		dev_info(ir->dev, "failed to get buffer size\n");
+ 		goto out;
+ 	}
+ 
+-	packet.cmd = CMD_GET_FEATURES;
++	if (ir->bufsize > BUF_SIZE) {
++		dev_info(ir->dev, "buffer size %u larger than expected\n",
++								ir->bufsize);
++		ir->bufsize = BUF_SIZE;
++	}
++
++	ir->packet->header.cmd = CMD_GET_FEATURES;
+ 
+-	rc = iguanair_send(ir, &packet, sizeof(packet));
++	rc = iguanair_send(ir, sizeof(ir->packet->header));
+ 	if (rc) {
+ 		dev_info(ir->dev, "failed to get features\n");
+ 		goto out;
+@@ -257,13 +266,18 @@ out:
+ 
+ static int iguanair_receiver(struct iguanair *ir, bool enable)
+ {
+-	struct packet packet = { 0, DIR_OUT, enable ?
+-				CMD_RECEIVER_ON : CMD_RECEIVER_OFF };
++	int rc;
++
++	ir->packet->header.start = 0;
++	ir->packet->header.direction = DIR_OUT;
++	ir->packet->header.cmd = enable ? CMD_RECEIVER_ON : CMD_RECEIVER_OFF;
+ 
+ 	if (enable)
+ 		ir_raw_event_reset(ir->rc);
+ 
+-	return iguanair_send(ir, &packet, sizeof(packet));
++	rc = iguanair_send(ir, sizeof(ir->packet->header));
++
++	return rc;
+ }
+ 
+ /*
+@@ -308,8 +322,8 @@ static int iguanair_set_tx_carrier(struct rc_dev *dev, uint32_t carrier)
+ 		fours = (cycles - sevens * 7) / 4;
+ 
+ 		/* magic happens here */
+-		ir->busy7 = (4 - sevens) * 2;
+-		ir->busy4 = 110 - fours;
++		ir->packet->busy7 = (4 - sevens) * 2;
++		ir->packet->busy4 = 110 - fours;
+ 	}
+ 
+ 	mutex_unlock(&ir->lock);
+@@ -325,7 +339,7 @@ static int iguanair_set_tx_mask(struct rc_dev *dev, uint32_t mask)
+ 		return 4;
+ 
+ 	mutex_lock(&ir->lock);
+-	ir->channels = mask;
++	ir->packet->channels = mask << 4;
+ 	mutex_unlock(&ir->lock);
+ 
+ 	return 0;
+@@ -337,16 +351,9 @@ static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count)
+ 	uint8_t space;
+ 	unsigned i, size, periods, bytes;
+ 	int rc;
+-	struct send_packet *packet;
+ 
+ 	mutex_lock(&ir->lock);
+ 
+-	packet = kmalloc(sizeof(*packet) + ir->bufsize, GFP_KERNEL);
+-	if (!packet) {
+-		rc = -ENOMEM;
+-		goto out;
+-	}
+-
+ 	/* convert from us to carrier periods */
+ 	for (i = space = size = 0; i < count; i++) {
+ 		periods = DIV_ROUND_CLOSEST(txbuf[i] * ir->carrier, 1000000);
+@@ -356,11 +363,11 @@ static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count)
+ 			break;
+ 		}
+ 		while (periods > 127) {
+-			packet->payload[size++] = 127 | space;
++			ir->packet->payload[size++] = 127 | space;
+ 			periods -= 127;
+ 		}
+ 
+-		packet->payload[size++] = periods | space;
++		ir->packet->payload[size++] = periods | space;
+ 		space ^= 0x80;
+ 	}
+ 
+@@ -369,36 +376,19 @@ static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count)
+ 		goto out;
+ 	}
+ 
+-	packet->header.start = 0;
+-	packet->header.direction = DIR_OUT;
+-	packet->header.cmd = CMD_SEND;
+-	packet->length = size;
+-	packet->channels = ir->channels << 4;
+-	packet->busy7 = ir->busy7;
+-	packet->busy4 = ir->busy4;
+-
+-	if (ir->receiver_on) {
+-		rc = iguanair_receiver(ir, false);
+-		if (rc) {
+-			dev_warn(ir->dev, "disable receiver before transmit failed\n");
+-			goto out;
+-		}
+-	}
++	ir->packet->header.start = 0;
++	ir->packet->header.direction = DIR_OUT;
++	ir->packet->header.cmd = CMD_SEND;
++	ir->packet->length = size;
+ 
+ 	ir->tx_overflow = false;
+ 
+-	rc = iguanair_send(ir, packet, size + 8);
++	rc = iguanair_send(ir, sizeof(*ir->packet) + size);
+ 
+ 	if (rc == 0 && ir->tx_overflow)
+ 		rc = -EOVERFLOW;
+ 
+-	if (ir->receiver_on) {
+-		if (iguanair_receiver(ir, true))
+-			dev_warn(ir->dev, "re-enable receiver after transmit failed\n");
+-	}
+-
+ out:
+-	kfree(packet);
+ 	mutex_unlock(&ir->lock);
+ 
+ 	return rc ? rc : count;
+@@ -411,8 +401,6 @@ static int iguanair_open(struct rc_dev *rdev)
+ 
+ 	mutex_lock(&ir->lock);
+ 
+-	BUG_ON(ir->receiver_on);
+-
+ 	rc = iguanair_receiver(ir, true);
+ 	if (rc == 0)
+ 		ir->receiver_on = true;
+@@ -443,7 +431,7 @@ static int __devinit iguanair_probe(struct usb_interface *intf,
+ 	struct usb_device *udev = interface_to_usbdev(intf);
+ 	struct iguanair *ir;
+ 	struct rc_dev *rc;
+-	int ret, pipein;
++	int ret, pipein, pipeout;
+ 	struct usb_host_interface *idesc;
+ 
+ 	ir = kzalloc(sizeof(*ir), GFP_KERNEL);
+@@ -453,11 +441,14 @@ static int __devinit iguanair_probe(struct usb_interface *intf,
+ 		goto out;
+ 	}
+ 
+-	ir->buf_in = usb_alloc_coherent(udev, MAX_PACKET_SIZE, GFP_KERNEL,
++	ir->buf_in = usb_alloc_coherent(udev, MAX_IN_PACKET, GFP_KERNEL,
+ 								&ir->dma_in);
++	ir->packet = usb_alloc_coherent(udev, MAX_OUT_PACKET, GFP_KERNEL,
++								&ir->dma_out);
+ 	ir->urb_in = usb_alloc_urb(0, GFP_KERNEL);
++	ir->urb_out = usb_alloc_urb(0, GFP_KERNEL);
+ 
+-	if (!ir->buf_in || !ir->urb_in) {
++	if (!ir->buf_in || !ir->packet || !ir->urb_in || !ir->urb_out) {
+ 		ret = -ENOMEM;
+ 		goto out;
+ 	}
+@@ -472,13 +463,18 @@ static int __devinit iguanair_probe(struct usb_interface *intf,
+ 	ir->rc = rc;
+ 	ir->dev = &intf->dev;
+ 	ir->udev = udev;
+-	ir->pipe_out = usb_sndintpipe(udev,
+-				idesc->endpoint[1].desc.bEndpointAddress);
+ 	mutex_init(&ir->lock);
++
+ 	init_completion(&ir->completion);
++	pipeout = usb_sndintpipe(udev,
++				idesc->endpoint[1].desc.bEndpointAddress);
++	usb_fill_int_urb(ir->urb_out, udev, pipeout, ir->packet, MAX_OUT_PACKET,
++						iguanair_irq_out, ir, 1);
++	ir->urb_out->transfer_dma = ir->dma_out;
++	ir->urb_out->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ 
+ 	pipein = usb_rcvintpipe(udev, idesc->endpoint[0].desc.bEndpointAddress);
+-	usb_fill_int_urb(ir->urb_in, udev, pipein, ir->buf_in, MAX_PACKET_SIZE,
++	usb_fill_int_urb(ir->urb_in, udev, pipein, ir->buf_in, MAX_IN_PACKET,
+ 							 iguanair_rx, ir, 1);
+ 	ir->urb_in->transfer_dma = ir->dma_in;
+ 	ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+@@ -528,11 +524,14 @@ static int __devinit iguanair_probe(struct usb_interface *intf,
+ 	return 0;
+ out2:
+ 	usb_kill_urb(ir->urb_in);
++	usb_kill_urb(ir->urb_out);
+ out:
+ 	if (ir) {
+ 		usb_free_urb(ir->urb_in);
+-		usb_free_coherent(udev, MAX_PACKET_SIZE, ir->buf_in,
+-								ir->dma_in);
++		usb_free_urb(ir->urb_out);
++		usb_free_coherent(udev, MAX_IN_PACKET, ir->buf_in, ir->dma_in);
++		usb_free_coherent(udev, MAX_OUT_PACKET, ir->packet,
++								ir->dma_out);
+ 	}
+ 	rc_free_device(rc);
+ 	kfree(ir);
+@@ -546,8 +545,11 @@ static void __devexit iguanair_disconnect(struct usb_interface *intf)
+ 	rc_unregister_device(ir->rc);
+ 	usb_set_intfdata(intf, NULL);
+ 	usb_kill_urb(ir->urb_in);
++	usb_kill_urb(ir->urb_out);
+ 	usb_free_urb(ir->urb_in);
+-	usb_free_coherent(ir->udev, MAX_PACKET_SIZE, ir->buf_in, ir->dma_in);
++	usb_free_urb(ir->urb_out);
++	usb_free_coherent(ir->udev, MAX_IN_PACKET, ir->buf_in, ir->dma_in);
++	usb_free_coherent(ir->udev, MAX_OUT_PACKET, ir->packet, ir->dma_out);
+ 	kfree(ir);
+ }
+ 
+@@ -565,6 +567,7 @@ static int iguanair_suspend(struct usb_interface *intf, pm_message_t message)
+ 	}
+ 
+ 	usb_kill_urb(ir->urb_in);
++	usb_kill_urb(ir->urb_out);
+ 
+ 	mutex_unlock(&ir->lock);
+ 

Modified: dists/sid/linux/debian/patches/series
==============================================================================
--- dists/sid/linux/debian/patches/series	Sat Dec 29 13:04:21 2012	(r19662)
+++ dists/sid/linux/debian/patches/series	Sat Dec 29 13:57:44 2012	(r19663)
@@ -440,3 +440,16 @@
 features/all/I2C-Add-helper-macro-for-i2c_driver-boilerplate.patch
 features/all/USB-Add-helper-macro-for-usb_driver-boilerplate.patch
 features/all/PCI-Add-helper-macro-for-pci_register_driver-boilerp.patch
+
+# iguanair driver from 3.7
+features/all/iguanair/0001-media-Add-support-for-the-IguanaWorks-USB-IR-Transce.patch
+features/all/iguanair/0002-media-iguanair-reuse-existing-urb-callback-for-comma.patch
+features/all/iguanair/0003-media-iguanair-ignore-unsupported-firmware-versions.patch
+features/all/iguanair/0004-media-iguanair-support-suspend-and-resume.patch
+features/all/iguanair/0005-media-iguanair-fix-return-value-for-transmit.patch
+features/all/iguanair/0006-media-iguanair-reset-the-IR-state-after-rx-overflow-.patch
+features/all/iguanair/0007-media-iguanair-advertise-the-resolution-and-timeout-.patch
+features/all/iguanair/0008-media-iguanair-fix-receiver-overflow.patch
+features/all/iguanair/0009-media-rc-do-not-wake-up-rc-thread-unless-there-is-so.patch
+features/all/iguanair/0010-media-iguanair-do-not-modify-transmit-buffer.patch
+features/all/iguanair/0011-media-iguanair-cannot-send-data-from-the-stack.patch



More information about the Kernel-svn-changes mailing list