All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/9] Various IR fixes
@ 2016-10-31 17:52 Sean Young
  2016-10-31 17:52 ` [PATCH 1/9] [media] winbond-cir: use name without space for pnp driver Sean Young
                   ` (8 more replies)
  0 siblings, 9 replies; 12+ messages in thread
From: Sean Young @ 2016-10-31 17:52 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: linux-media

Teach the redrat3 driver how to use the wideband receiver, also fix
some very nasty crashes if you disconnect a lirc device while
reading from it.

Sean Young (9):
  [media] winbond-cir: use name without space for pnp driver
  [media] redrat3: don't include vendor/product id in name
  [media] redrat3: remove dead code and pointless messages
  [media] redrat3: fix error paths in probe
  [media] redrat3: enable carrier reports using wideband receiver
  [media] redrat3: increase set size for lengths to maximum
  [media] lirc: might sleep error in lirc_dev_fop_read
  [media] lirc: prevent use-after free
  [media] lirc: use-after free while reading from device and unplugging

 drivers/media/rc/lirc_dev.c    |  18 +--
 drivers/media/rc/redrat3.c     | 283 +++++++++++++++++++++++++----------------
 drivers/media/rc/winbond-cir.c |   2 +-
 3 files changed, 181 insertions(+), 122 deletions(-)

-- 
2.7.4


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 1/9] [media] winbond-cir: use name without space for pnp driver
  2016-10-31 17:52 [PATCH 0/9] Various IR fixes Sean Young
@ 2016-10-31 17:52 ` Sean Young
  2016-10-31 17:52 ` [PATCH 2/9] [media] redrat3: don't include vendor/product id in name Sean Young
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 12+ messages in thread
From: Sean Young @ 2016-10-31 17:52 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: linux-media

Rename the pnp driver in sysfs from /sys/bus/pnp/drivers/Winbond CIR
to /sys/bus/pnp/drivers/winbond-cir

Signed-off-by: Sean Young <sean@mess.org>
---
 drivers/media/rc/winbond-cir.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c
index cdcd6e3..1ccb6bb 100644
--- a/drivers/media/rc/winbond-cir.c
+++ b/drivers/media/rc/winbond-cir.c
@@ -1185,7 +1185,7 @@ static const struct pnp_device_id wbcir_ids[] = {
 MODULE_DEVICE_TABLE(pnp, wbcir_ids);
 
 static struct pnp_driver wbcir_driver = {
-	.name     = WBCIR_NAME,
+	.name     = DRVNAME,
 	.id_table = wbcir_ids,
 	.probe    = wbcir_probe,
 	.remove   = wbcir_remove,
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 2/9] [media] redrat3: don't include vendor/product id in name
  2016-10-31 17:52 [PATCH 0/9] Various IR fixes Sean Young
  2016-10-31 17:52 ` [PATCH 1/9] [media] winbond-cir: use name without space for pnp driver Sean Young
@ 2016-10-31 17:52 ` Sean Young
  2016-10-31 17:52 ` [PATCH 3/9] [media] redrat3: remove dead code and pointless messages Sean Young
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 12+ messages in thread
From: Sean Young @ 2016-10-31 17:52 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: linux-media

No need to duplicate these in the rc name.

Signed-off-by: Sean Young <sean@mess.org>
---
 drivers/media/rc/redrat3.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c
index 3b0ed1c..de40e58 100644
--- a/drivers/media/rc/redrat3.c
+++ b/drivers/media/rc/redrat3.c
@@ -912,9 +912,9 @@ static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3)
 		goto out;
 	}
 
-	snprintf(rr3->name, sizeof(rr3->name), "RedRat3%s Infrared Remote Transceiver (%04x:%04x)",
-		 prod == USB_RR3IIUSB_PRODUCT_ID ? "-II" : "",
-		 le16_to_cpu(rr3->udev->descriptor.idVendor), prod);
+	snprintf(rr3->name, sizeof(rr3->name),
+		 "RedRat3%s Infrared Remote Transceiver",
+		 prod == USB_RR3IIUSB_PRODUCT_ID ? "-II" : "");
 
 	usb_make_path(rr3->udev, rr3->phys, sizeof(rr3->phys));
 
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 3/9] [media] redrat3: remove dead code and pointless messages
  2016-10-31 17:52 [PATCH 0/9] Various IR fixes Sean Young
  2016-10-31 17:52 ` [PATCH 1/9] [media] winbond-cir: use name without space for pnp driver Sean Young
  2016-10-31 17:52 ` [PATCH 2/9] [media] redrat3: don't include vendor/product id in name Sean Young
@ 2016-10-31 17:52 ` Sean Young
  2016-10-31 17:52 ` [PATCH 4/9] [media] redrat3: fix error paths in probe Sean Young
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 12+ messages in thread
From: Sean Young @ 2016-10-31 17:52 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: linux-media

No need to log kmalloc failures.

Signed-off-by: Sean Young <sean@mess.org>
---
 drivers/media/rc/redrat3.c | 42 ++++++------------------------------------
 1 file changed, 6 insertions(+), 36 deletions(-)

diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c
index de40e58..23180ec 100644
--- a/drivers/media/rc/redrat3.c
+++ b/drivers/media/rc/redrat3.c
@@ -363,11 +363,6 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3)
 	unsigned int i, sig_size, single_len, offset, val;
 	u32 mod_freq;
 
-	if (!rr3) {
-		pr_err("%s called with no context!\n", __func__);
-		return;
-	}
-
 	dev = rr3->dev;
 
 	mod_freq = redrat3_val_to_mod_freq(&rr3->irdata);
@@ -480,10 +475,8 @@ static u32 redrat3_get_timeout(struct redrat3_dev *rr3)
 
 	len = sizeof(*tmp);
 	tmp = kzalloc(len, GFP_KERNEL);
-	if (!tmp) {
-		dev_warn(rr3->dev, "Memory allocation faillure\n");
+	if (!tmp)
 		return timeout;
-	}
 
 	pipe = usb_rcvctrlpipe(rr3->udev, 0);
 	ret = usb_control_msg(rr3->udev, pipe, RR3_GET_IR_PARAM,
@@ -544,10 +537,8 @@ static void redrat3_reset(struct redrat3_dev *rr3)
 	txpipe = usb_sndctrlpipe(udev, 0);
 
 	val = kmalloc(len, GFP_KERNEL);
-	if (!val) {
-		dev_err(dev, "Memory allocation failure\n");
+	if (!val)
 		return;
-	}
 
 	*val = 0x01;
 	rc = usb_control_msg(udev, rxpipe, RR3_RESET,
@@ -589,10 +580,8 @@ static void redrat3_get_firmware_rev(struct redrat3_dev *rr3)
 	char *buffer;
 
 	buffer = kzalloc(sizeof(char) * (RR3_FW_VERSION_LEN + 1), GFP_KERNEL);
-	if (!buffer) {
-		dev_err(rr3->dev, "Memory allocation failure\n");
+	if (!buffer)
 		return;
-	}
 
 	rc = usb_control_msg(rr3->udev, usb_rcvctrlpipe(rr3->udev, 0),
 			     RR3_FW_VERSION,
@@ -699,19 +688,9 @@ static int redrat3_get_ir_data(struct redrat3_dev *rr3, unsigned len)
 /* callback function from USB when async USB request has completed */
 static void redrat3_handle_async(struct urb *urb)
 {
-	struct redrat3_dev *rr3;
+	struct redrat3_dev *rr3 = urb->context;
 	int ret;
 
-	if (!urb)
-		return;
-
-	rr3 = urb->context;
-	if (!rr3) {
-		pr_err("%s called with invalid context!\n", __func__);
-		usb_unlink_urb(urb);
-		return;
-	}
-
 	switch (urb->status) {
 	case 0:
 		ret = redrat3_get_ir_data(rr3, urb->actual_length);
@@ -999,10 +978,8 @@ static int redrat3_dev_probe(struct usb_interface *intf,
 
 	/* allocate memory for our device state and initialize it */
 	rr3 = kzalloc(sizeof(*rr3), GFP_KERNEL);
-	if (rr3 == NULL) {
-		dev_err(dev, "Memory allocation failure\n");
+	if (rr3 == NULL)
 		goto no_endpoints;
-	}
 
 	rr3->dev = &intf->dev;
 
@@ -1014,10 +991,8 @@ static int redrat3_dev_probe(struct usb_interface *intf,
 	rr3->ep_in = ep_in;
 	rr3->bulk_in_buf = usb_alloc_coherent(udev,
 		le16_to_cpu(ep_in->wMaxPacketSize), GFP_KERNEL, &rr3->dma_in);
-	if (!rr3->bulk_in_buf) {
-		dev_err(dev, "Read buffer allocation failure\n");
+	if (!rr3->bulk_in_buf)
 		goto error;
-	}
 
 	pipe = usb_rcvbulkpipe(udev, ep_in->bEndpointAddress);
 	usb_fill_bulk_urb(rr3->read_urb, udev, pipe, rr3->bulk_in_buf,
@@ -1081,8 +1056,6 @@ static int redrat3_dev_probe(struct usb_interface *intf,
 	redrat3_delete(rr3, rr3->udev);
 
 no_endpoints:
-	dev_err(dev, "%s: retval = %x", __func__, retval);
-
 	return retval;
 }
 
@@ -1091,9 +1064,6 @@ static void redrat3_dev_disconnect(struct usb_interface *intf)
 	struct usb_device *udev = interface_to_usbdev(intf);
 	struct redrat3_dev *rr3 = usb_get_intfdata(intf);
 
-	if (!rr3)
-		return;
-
 	usb_set_intfdata(intf, NULL);
 	rc_unregister_device(rr3->rc);
 	led_classdev_unregister(&rr3->led);
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 4/9] [media] redrat3: fix error paths in probe
  2016-10-31 17:52 [PATCH 0/9] Various IR fixes Sean Young
                   ` (2 preceding siblings ...)
  2016-10-31 17:52 ` [PATCH 3/9] [media] redrat3: remove dead code and pointless messages Sean Young
@ 2016-10-31 17:52 ` Sean Young
  2016-10-31 17:52 ` [PATCH 5/9] [media] redrat3: enable carrier reports using wideband receiver Sean Young
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 12+ messages in thread
From: Sean Young @ 2016-10-31 17:52 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: linux-media

If redrat3_delete() is called, ensure ep_in and udev members are set
up so we don't dereference null in the error path. Also ensure that
rc dev device exists before we enable the receiver and that the
led urb exists before we create the led device.

Signed-off-by: Sean Young <sean@mess.org>
---
 drivers/media/rc/redrat3.c | 49 ++++++++++++++++++++++------------------------
 1 file changed, 23 insertions(+), 26 deletions(-)

diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c
index 23180ec..eaf374d 100644
--- a/drivers/media/rc/redrat3.c
+++ b/drivers/media/rc/redrat3.c
@@ -982,17 +982,19 @@ static int redrat3_dev_probe(struct usb_interface *intf,
 		goto no_endpoints;
 
 	rr3->dev = &intf->dev;
+	rr3->ep_in = ep_in;
+	rr3->ep_out = ep_out;
+	rr3->udev = udev;
 
 	/* set up bulk-in endpoint */
 	rr3->read_urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!rr3->read_urb)
-		goto error;
+		goto redrat_free;
 
-	rr3->ep_in = ep_in;
 	rr3->bulk_in_buf = usb_alloc_coherent(udev,
 		le16_to_cpu(ep_in->wMaxPacketSize), GFP_KERNEL, &rr3->dma_in);
 	if (!rr3->bulk_in_buf)
-		goto error;
+		goto redrat_free;
 
 	pipe = usb_rcvbulkpipe(udev, ep_in->bEndpointAddress);
 	usb_fill_bulk_urb(rr3->read_urb, udev, pipe, rr3->bulk_in_buf,
@@ -1000,34 +1002,16 @@ static int redrat3_dev_probe(struct usb_interface *intf,
 	rr3->read_urb->transfer_dma = rr3->dma_in;
 	rr3->read_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 
-	rr3->ep_out = ep_out;
-	rr3->udev = udev;
-
 	redrat3_reset(rr3);
 	redrat3_get_firmware_rev(rr3);
 
-	/* might be all we need to do? */
-	retval = redrat3_enable_detector(rr3);
-	if (retval < 0)
-		goto error;
-
 	/* default.. will get overridden by any sends with a freq defined */
 	rr3->carrier = 38000;
 
-	/* led control */
-	rr3->led.name = "redrat3:red:feedback";
-	rr3->led.default_trigger = "rc-feedback";
-	rr3->led.brightness_set = redrat3_brightness_set;
-	retval = led_classdev_register(&intf->dev, &rr3->led);
-	if (retval)
-		goto error;
-
 	atomic_set(&rr3->flash, 0);
 	rr3->flash_urb = usb_alloc_urb(0, GFP_KERNEL);
-	if (!rr3->flash_urb) {
-		retval = -ENOMEM;
-		goto led_free_error;
-	}
+	if (!rr3->flash_urb)
+		goto redrat_free;
 
 	/* setup packet is 'c0 b9 0000 0000 0001' */
 	rr3->flash_control.bRequestType = 0xc0;
@@ -1039,20 +1023,33 @@ static int redrat3_dev_probe(struct usb_interface *intf,
 			&rr3->flash_in_buf, sizeof(rr3->flash_in_buf),
 			redrat3_led_complete, rr3);
 
+	/* led control */
+	rr3->led.name = "redrat3:red:feedback";
+	rr3->led.default_trigger = "rc-feedback";
+	rr3->led.brightness_set = redrat3_brightness_set;
+	retval = led_classdev_register(&intf->dev, &rr3->led);
+	if (retval)
+		goto redrat_free;
+
 	rr3->rc = redrat3_init_rc_dev(rr3);
 	if (!rr3->rc) {
 		retval = -ENOMEM;
-		goto led_free_error;
+		goto led_free;
 	}
 
+	/* might be all we need to do? */
+	retval = redrat3_enable_detector(rr3);
+	if (retval < 0)
+		goto led_free;
+
 	/* we can register the device now, as it is ready */
 	usb_set_intfdata(intf, rr3);
 
 	return 0;
 
-led_free_error:
+led_free:
 	led_classdev_unregister(&rr3->led);
-error:
+redrat_free:
 	redrat3_delete(rr3, rr3->udev);
 
 no_endpoints:
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 5/9] [media] redrat3: enable carrier reports using wideband receiver
  2016-10-31 17:52 [PATCH 0/9] Various IR fixes Sean Young
                   ` (3 preceding siblings ...)
  2016-10-31 17:52 ` [PATCH 4/9] [media] redrat3: fix error paths in probe Sean Young
@ 2016-10-31 17:52 ` Sean Young
  2016-10-31 19:06   ` kbuild test robot
  2016-10-31 17:52 ` [PATCH 6/9] [media] redrat3: increase set size for lengths to maximum Sean Young
                   ` (3 subsequent siblings)
  8 siblings, 1 reply; 12+ messages in thread
From: Sean Young @ 2016-10-31 17:52 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: linux-media

The wideband receiver is a little awkward on the redrat3. Data arrives
on a different endpoint, and the learning command must be reissued
every time data is learned.

Signed-off-by: Sean Young <sean@mess.org>
---
 drivers/media/rc/redrat3.c | 184 ++++++++++++++++++++++++++++++++++-----------
 1 file changed, 140 insertions(+), 44 deletions(-)

diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c
index eaf374d..4370d21 100644
--- a/drivers/media/rc/redrat3.c
+++ b/drivers/media/rc/redrat3.c
@@ -81,6 +81,8 @@
 #define RR3_RC_DET_ENABLE	0xbb
 /* Stop capture with the RC receiver */
 #define RR3_RC_DET_DISABLE	0xbc
+/* Start capture with the wideband receiver */
+#define RR3_MODSIG_CAPTURE     0xb2
 /* Return the status of RC detector capture */
 #define RR3_RC_DET_STATUS	0xbd
 /* Reset redrat */
@@ -105,8 +107,10 @@
 #define RR3_CLK_PER_COUNT	12
 /* (RR3_CLK / RR3_CLK_PER_COUNT) */
 #define RR3_CLK_CONV_FACTOR	2000000
-/* USB bulk-in IR data endpoint address */
-#define RR3_BULK_IN_EP_ADDR	0x82
+/* USB bulk-in wideband IR data endpoint address */
+#define RR3_WIDE_IN_EP_ADDR	0x81
+/* USB bulk-in narrowband IR data endpoint address */
+#define RR3_NARROW_IN_EP_ADDR	0x82
 
 /* Size of the fixed-length portion of the signal */
 #define RR3_DRIVER_MAXLENS	128
@@ -207,15 +211,22 @@ struct redrat3_dev {
 	struct urb *flash_urb;
 	u8 flash_in_buf;
 
+	/* learning */
+	bool wideband;
+	struct usb_ctrlrequest learn_control;
+	struct urb *learn_urb;
+	u8 learn_buf;
+
 	/* save off the usb device pointer */
 	struct usb_device *udev;
 
 	/* the receive endpoint */
-	struct usb_endpoint_descriptor *ep_in;
+	struct usb_endpoint_descriptor *ep_narrow;
 	/* the buffer to receive data */
 	void *bulk_in_buf;
 	/* urb used to read ir data */
-	struct urb *read_urb;
+	struct urb *narrow_urb;
+	struct urb *wide_urb;
 
 	/* the send endpoint */
 	struct usb_endpoint_descriptor *ep_out;
@@ -236,23 +247,6 @@ struct redrat3_dev {
 	char phys[64];
 };
 
-/*
- * redrat3_issue_async
- *
- *  Issues an async read to the ir data in port..
- *  sets the callback to be redrat3_handle_async
- */
-static void redrat3_issue_async(struct redrat3_dev *rr3)
-{
-	int res;
-
-	res = usb_submit_urb(rr3->read_urb, GFP_ATOMIC);
-	if (res)
-		dev_dbg(rr3->dev,
-			"%s: receive request FAILED! (res %d, len %d)\n",
-			__func__, res, rr3->read_urb->transfer_buffer_length);
-}
-
 static void redrat3_dump_fw_error(struct redrat3_dev *rr3, int code)
 {
 	if (!rr3->transmitting && (code != 0x40))
@@ -367,6 +361,14 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3)
 
 	mod_freq = redrat3_val_to_mod_freq(&rr3->irdata);
 	dev_dbg(dev, "Got mod_freq of %u\n", mod_freq);
+	if (mod_freq && rr3->wideband) {
+		DEFINE_IR_RAW_EVENT(ev);
+
+		ev.carrier_report = 1;
+		ev.carrier = mod_freq;
+
+		ir_raw_event_store(rr3->rc, &ev);
+	}
 
 	/* process each rr3 encoded byte into an int */
 	sig_size = be16_to_cpu(rr3->irdata.sig_size);
@@ -449,19 +451,31 @@ static int redrat3_enable_detector(struct redrat3_dev *rr3)
 		return -EIO;
 	}
 
-	redrat3_issue_async(rr3);
+	ret = usb_submit_urb(rr3->narrow_urb, GFP_KERNEL);
+	if (ret) {
+		dev_err(rr3->dev, "narrow band urb failed: %d", ret);
+		return ret;
+	}
 
-	return 0;
+	ret = usb_submit_urb(rr3->wide_urb, GFP_KERNEL);
+	if (ret)
+		dev_err(rr3->dev, "wide band urb failed: %d", ret);
+
+	return ret;
 }
 
 static inline void redrat3_delete(struct redrat3_dev *rr3,
 				  struct usb_device *udev)
 {
-	usb_kill_urb(rr3->read_urb);
+	usb_kill_urb(rr3->narrow_urb);
+	usb_kill_urb(rr3->wide_urb);
 	usb_kill_urb(rr3->flash_urb);
-	usb_free_urb(rr3->read_urb);
+	usb_kill_urb(rr3->learn_urb);
+	usb_free_urb(rr3->narrow_urb);
+	usb_free_urb(rr3->wide_urb);
 	usb_free_urb(rr3->flash_urb);
-	usb_free_coherent(udev, le16_to_cpu(rr3->ep_in->wMaxPacketSize),
+	usb_free_urb(rr3->learn_urb);
+	usb_free_coherent(udev, le16_to_cpu(rr3->ep_narrow->wMaxPacketSize),
 			  rr3->bulk_in_buf, rr3->dma_in);
 
 	kfree(rr3);
@@ -694,9 +708,19 @@ static void redrat3_handle_async(struct urb *urb)
 	switch (urb->status) {
 	case 0:
 		ret = redrat3_get_ir_data(rr3, urb->actual_length);
+		if (!ret && rr3->wideband && !rr3->learn_urb->hcpriv) {
+			ret = usb_submit_urb(rr3->learn_urb, GFP_ATOMIC);
+			if (ret)
+				dev_err(rr3->dev, "Failed to submit learning urb: %d",
+									ret);
+		}
+
 		if (!ret) {
 			/* no error, prepare to read more */
-			redrat3_issue_async(rr3);
+			ret = usb_submit_urb(urb, GFP_ATOMIC);
+			if (ret)
+				dev_err(rr3->dev, "Failed to resubmit urb: %d",
+									ret);
 		}
 		break;
 
@@ -856,6 +880,43 @@ static void redrat3_brightness_set(struct led_classdev *led_dev, enum
 	}
 }
 
+static int redrat3_wideband_receiver(struct rc_dev *rcdev, int enable)
+{
+	struct redrat3_dev *rr3 = rcdev->priv;
+	int ret = 0;
+
+	rr3->wideband = enable != 0;
+
+	if (enable) {
+		ret = usb_submit_urb(rr3->learn_urb, GFP_KERNEL);
+		if (ret)
+			dev_err(rr3->dev, "Failed to submit learning urb: %d",
+									ret);
+	}
+
+	return ret;
+}
+
+static void redrat3_learn_complete(struct urb *urb)
+{
+	struct redrat3_dev *rr3 = urb->context;
+	int ret;
+
+	switch (urb->status) {
+	case 0:
+		break;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		usb_unlink_urb(urb);
+		return;
+	case -EPIPE:
+	default:
+		dev_err(rr3->dev, "Error: learn urb status = %d", urb->status);
+		break;
+	}
+}
+
 static void redrat3_led_complete(struct urb *urb)
 {
 	struct redrat3_dev *rr3 = urb->context;
@@ -910,6 +971,7 @@ static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3)
 	rc->s_timeout = redrat3_set_timeout;
 	rc->tx_ir = redrat3_transmit_ir;
 	rc->s_tx_carrier = redrat3_set_tx_carrier;
+	rc->s_carrier_report = redrat3_wideband_receiver;
 	rc->driver_name = DRIVER_NAME;
 	rc->rx_resolution = US_TO_NS(2);
 	rc->map_name = RC_MAP_HAUPPAUGE;
@@ -935,7 +997,8 @@ static int redrat3_dev_probe(struct usb_interface *intf,
 	struct usb_host_interface *uhi;
 	struct redrat3_dev *rr3;
 	struct usb_endpoint_descriptor *ep;
-	struct usb_endpoint_descriptor *ep_in = NULL;
+	struct usb_endpoint_descriptor *ep_narrow = NULL;
+	struct usb_endpoint_descriptor *ep_wide = NULL;
 	struct usb_endpoint_descriptor *ep_out = NULL;
 	u8 addr, attrs;
 	int pipe, i;
@@ -949,15 +1012,17 @@ static int redrat3_dev_probe(struct usb_interface *intf,
 		addr = ep->bEndpointAddress;
 		attrs = ep->bmAttributes;
 
-		if ((ep_in == NULL) &&
+		if ((ep_narrow == NULL) &&
 		    ((addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) &&
 		    ((attrs & USB_ENDPOINT_XFERTYPE_MASK) ==
 		     USB_ENDPOINT_XFER_BULK)) {
 			dev_dbg(dev, "found bulk-in endpoint at 0x%02x\n",
 				ep->bEndpointAddress);
 			/* data comes in on 0x82, 0x81 is for other data... */
-			if (ep->bEndpointAddress == RR3_BULK_IN_EP_ADDR)
-				ep_in = ep;
+			if (ep->bEndpointAddress == RR3_NARROW_IN_EP_ADDR)
+				ep_narrow = ep;
+			if (ep->bEndpointAddress == RR3_WIDE_IN_EP_ADDR)
+				ep_wide = ep;
 		}
 
 		if ((ep_out == NULL) &&
@@ -970,8 +1035,8 @@ static int redrat3_dev_probe(struct usb_interface *intf,
 		}
 	}
 
-	if (!ep_in || !ep_out) {
-		dev_err(dev, "Couldn't find both in and out endpoints\n");
+	if (!ep_narrow || !ep_out || !ep_wide) {
+		dev_err(dev, "Couldn't find all endpoints\n");
 		retval = -ENODEV;
 		goto no_endpoints;
 	}
@@ -982,25 +1047,38 @@ static int redrat3_dev_probe(struct usb_interface *intf,
 		goto no_endpoints;
 
 	rr3->dev = &intf->dev;
-	rr3->ep_in = ep_in;
+	rr3->ep_narrow = ep_narrow;
 	rr3->ep_out = ep_out;
 	rr3->udev = udev;
 
 	/* set up bulk-in endpoint */
-	rr3->read_urb = usb_alloc_urb(0, GFP_KERNEL);
-	if (!rr3->read_urb)
+	rr3->narrow_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!rr3->narrow_urb)
+		goto redrat_free;
+
+	rr3->wide_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!rr3->wide_urb)
 		goto redrat_free;
 
 	rr3->bulk_in_buf = usb_alloc_coherent(udev,
-		le16_to_cpu(ep_in->wMaxPacketSize), GFP_KERNEL, &rr3->dma_in);
+		le16_to_cpu(ep_narrow->wMaxPacketSize),
+		GFP_KERNEL, &rr3->dma_in);
 	if (!rr3->bulk_in_buf)
 		goto redrat_free;
 
-	pipe = usb_rcvbulkpipe(udev, ep_in->bEndpointAddress);
-	usb_fill_bulk_urb(rr3->read_urb, udev, pipe, rr3->bulk_in_buf,
-		le16_to_cpu(ep_in->wMaxPacketSize), redrat3_handle_async, rr3);
-	rr3->read_urb->transfer_dma = rr3->dma_in;
-	rr3->read_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+	pipe = usb_rcvbulkpipe(udev, ep_narrow->bEndpointAddress);
+	usb_fill_bulk_urb(rr3->narrow_urb, udev, pipe, rr3->bulk_in_buf,
+		le16_to_cpu(ep_narrow->wMaxPacketSize),
+		redrat3_handle_async, rr3);
+	rr3->narrow_urb->transfer_dma = rr3->dma_in;
+	rr3->narrow_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	pipe = usb_rcvbulkpipe(udev, ep_wide->bEndpointAddress);
+	usb_fill_bulk_urb(rr3->wide_urb, udev, pipe, rr3->bulk_in_buf,
+		le16_to_cpu(ep_narrow->wMaxPacketSize),
+		redrat3_handle_async, rr3);
+	rr3->wide_urb->transfer_dma = rr3->dma_in;
+	rr3->wide_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 
 	redrat3_reset(rr3);
 	redrat3_get_firmware_rev(rr3);
@@ -1013,6 +1091,21 @@ static int redrat3_dev_probe(struct usb_interface *intf,
 	if (!rr3->flash_urb)
 		goto redrat_free;
 
+	/* learn urb */
+	rr3->learn_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!rr3->learn_urb)
+		goto redrat_free;
+
+	/* setup packet is 'c0 b2 0000 0000 0001' */
+	rr3->learn_control.bRequestType = 0xc0;
+	rr3->learn_control.bRequest = RR3_MODSIG_CAPTURE;
+	rr3->learn_control.wLength = cpu_to_le16(1);
+
+	usb_fill_control_urb(rr3->learn_urb, udev, usb_rcvctrlpipe(udev, 0),
+			(unsigned char *)&rr3->learn_control,
+			&rr3->learn_buf, sizeof(rr3->learn_buf),
+			redrat3_learn_complete, rr3);
+
 	/* setup packet is 'c0 b9 0000 0000 0001' */
 	rr3->flash_control.bRequestType = 0xc0;
 	rr3->flash_control.bRequest = RR3_BLINK_LED;
@@ -1072,7 +1165,8 @@ static int redrat3_dev_suspend(struct usb_interface *intf, pm_message_t message)
 	struct redrat3_dev *rr3 = usb_get_intfdata(intf);
 
 	led_classdev_suspend(&rr3->led);
-	usb_kill_urb(rr3->read_urb);
+	usb_kill_urb(rr3->narrow_urb);
+	usb_kill_urb(rr3->wide_urb);
 	usb_kill_urb(rr3->flash_urb);
 	return 0;
 }
@@ -1081,7 +1175,9 @@ static int redrat3_dev_resume(struct usb_interface *intf)
 {
 	struct redrat3_dev *rr3 = usb_get_intfdata(intf);
 
-	if (usb_submit_urb(rr3->read_urb, GFP_ATOMIC))
+	if (usb_submit_urb(rr3->narrow_urb, GFP_ATOMIC))
+		return -EIO;
+	if (usb_submit_urb(rr3->wide_urb, GFP_ATOMIC))
 		return -EIO;
 	led_classdev_resume(&rr3->led);
 	return 0;
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 6/9] [media] redrat3: increase set size for lengths to maximum
  2016-10-31 17:52 [PATCH 0/9] Various IR fixes Sean Young
                   ` (4 preceding siblings ...)
  2016-10-31 17:52 ` [PATCH 5/9] [media] redrat3: enable carrier reports using wideband receiver Sean Young
@ 2016-10-31 17:52 ` Sean Young
  2016-10-31 17:52 ` [PATCH 7/9] [media] lirc: might sleep error in lirc_dev_fop_read Sean Young
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 12+ messages in thread
From: Sean Young @ 2016-10-31 17:52 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: linux-media

In learning mode, you can get much longer messages which can run out
of lengths. The usb message will slightly larger.

Signed-off-by: Sean Young <sean@mess.org>
---
 drivers/media/rc/redrat3.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c
index 4370d21..12e299f 100644
--- a/drivers/media/rc/redrat3.c
+++ b/drivers/media/rc/redrat3.c
@@ -113,7 +113,7 @@
 #define RR3_NARROW_IN_EP_ADDR	0x82
 
 /* Size of the fixed-length portion of the signal */
-#define RR3_DRIVER_MAXLENS	128
+#define RR3_DRIVER_MAXLENS	255
 #define RR3_MAX_SIG_SIZE	512
 #define RR3_TIME_UNIT		50
 #define RR3_END_OF_SIGNAL	0x7f
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 7/9] [media] lirc: might sleep error in lirc_dev_fop_read
  2016-10-31 17:52 [PATCH 0/9] Various IR fixes Sean Young
                   ` (5 preceding siblings ...)
  2016-10-31 17:52 ` [PATCH 6/9] [media] redrat3: increase set size for lengths to maximum Sean Young
@ 2016-10-31 17:52 ` Sean Young
  2016-10-31 17:52 ` [PATCH 8/9] [media] lirc: prevent use-after free Sean Young
  2016-10-31 17:52 ` [PATCH 9/9] [media] lirc: use-after free while reading from device and unplugging Sean Young
  8 siblings, 0 replies; 12+ messages in thread
From: Sean Young @ 2016-10-31 17:52 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: linux-media

[  101.457944] ------------[ cut here ]------------
[  101.457954] WARNING: CPU: 3 PID: 1819 at kernel/sched/core.c:7708 __might_sleep+0x7e/0x80
[  101.457960] do not call blocking ops when !TASK_RUNNING; state=1 set at [<ffffffffc0364bc2>] lirc_dev_fop_read+0x292/0x4e0 [lirc_dev]

Signed-off-by: Sean Young <sean@mess.org>
---
 drivers/media/rc/lirc_dev.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c
index 91f9bb8..bf4309f 100644
--- a/drivers/media/rc/lirc_dev.c
+++ b/drivers/media/rc/lirc_dev.c
@@ -684,7 +684,6 @@ ssize_t lirc_dev_fop_read(struct file *file,
 	 * between while condition checking and scheduling)
 	 */
 	add_wait_queue(&ir->buf->wait_poll, &wait);
-	set_current_state(TASK_INTERRUPTIBLE);
 
 	/*
 	 * while we didn't provide 'length' bytes, device is opened in blocking
@@ -709,13 +708,13 @@ ssize_t lirc_dev_fop_read(struct file *file,
 			}
 
 			mutex_unlock(&ir->irctl_lock);
-			schedule();
 			set_current_state(TASK_INTERRUPTIBLE);
+			schedule();
+			set_current_state(TASK_RUNNING);
 
 			if (mutex_lock_interruptible(&ir->irctl_lock)) {
 				ret = -ERESTARTSYS;
 				remove_wait_queue(&ir->buf->wait_poll, &wait);
-				set_current_state(TASK_RUNNING);
 				goto out_unlocked;
 			}
 
@@ -735,7 +734,6 @@ ssize_t lirc_dev_fop_read(struct file *file,
 	}
 
 	remove_wait_queue(&ir->buf->wait_poll, &wait);
-	set_current_state(TASK_RUNNING);
 
 out_locked:
 	mutex_unlock(&ir->irctl_lock);
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 8/9] [media] lirc: prevent use-after free
  2016-10-31 17:52 [PATCH 0/9] Various IR fixes Sean Young
                   ` (6 preceding siblings ...)
  2016-10-31 17:52 ` [PATCH 7/9] [media] lirc: might sleep error in lirc_dev_fop_read Sean Young
@ 2016-10-31 17:52 ` Sean Young
  2016-10-31 17:52 ` [PATCH 9/9] [media] lirc: use-after free while reading from device and unplugging Sean Young
  8 siblings, 0 replies; 12+ messages in thread
From: Sean Young @ 2016-10-31 17:52 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: linux-media

If you unplug an lirc device while reading from it, you will get an
use after free as the cdev is freed while still in use.

Signed-off-by: Sean Young <sean@mess.org>
---
 drivers/media/rc/lirc_dev.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c
index bf4309f..60fd106 100644
--- a/drivers/media/rc/lirc_dev.c
+++ b/drivers/media/rc/lirc_dev.c
@@ -164,15 +164,15 @@ static int lirc_cdev_add(struct irctl *ir)
 	struct lirc_driver *d = &ir->d;
 	struct cdev *cdev;
 
-	cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
+	cdev = cdev_alloc();
 	if (!cdev)
 		goto err_out;
 
 	if (d->fops) {
-		cdev_init(cdev, d->fops);
+		cdev->ops = d->fops;
 		cdev->owner = d->owner;
 	} else {
-		cdev_init(cdev, &lirc_dev_fops);
+		cdev->ops = &lirc_dev_fops;
 		cdev->owner = THIS_MODULE;
 	}
 	retval = kobject_set_name(&cdev->kobj, "lirc%d", d->minor);
@@ -190,7 +190,7 @@ static int lirc_cdev_add(struct irctl *ir)
 	return 0;
 
 err_out:
-	kfree(cdev);
+	cdev_del(cdev);
 	return retval;
 }
 
@@ -420,7 +420,6 @@ int lirc_unregister_driver(int minor)
 	} else {
 		lirc_irctl_cleanup(ir);
 		cdev_del(cdev);
-		kfree(cdev);
 		kfree(ir);
 		irctls[minor] = NULL;
 	}
@@ -521,7 +520,6 @@ int lirc_dev_fop_close(struct inode *inode, struct file *file)
 		lirc_irctl_cleanup(ir);
 		cdev_del(cdev);
 		irctls[ir->d.minor] = NULL;
-		kfree(cdev);
 		kfree(ir);
 	}
 
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 9/9] [media] lirc: use-after free while reading from device and unplugging
  2016-10-31 17:52 [PATCH 0/9] Various IR fixes Sean Young
                   ` (7 preceding siblings ...)
  2016-10-31 17:52 ` [PATCH 8/9] [media] lirc: prevent use-after free Sean Young
@ 2016-10-31 17:52 ` Sean Young
  8 siblings, 0 replies; 12+ messages in thread
From: Sean Young @ 2016-10-31 17:52 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: linux-media

Many lirc drivers have their own receive buffers which are freed on
unplug (e.g. ir_lirc_unregister). This means that ir->buf->wait_poll
will be freed directly after unplug so do not remove yourself from the
wait queue.

Signed-off-by: Sean Young <sean@mess.org>
---
 drivers/media/rc/lirc_dev.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c
index 60fd106..b0c79a5 100644
--- a/drivers/media/rc/lirc_dev.c
+++ b/drivers/media/rc/lirc_dev.c
@@ -718,7 +718,7 @@ ssize_t lirc_dev_fop_read(struct file *file,
 
 			if (!ir->attached) {
 				ret = -ENODEV;
-				break;
+				goto out_locked;
 			}
 		} else {
 			lirc_buffer_read(ir->buf, buf);
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH 5/9] [media] redrat3: enable carrier reports using wideband receiver
  2016-10-31 17:52 ` [PATCH 5/9] [media] redrat3: enable carrier reports using wideband receiver Sean Young
@ 2016-10-31 19:06   ` kbuild test robot
  2016-10-31 21:13     ` Sean Young
  0 siblings, 1 reply; 12+ messages in thread
From: kbuild test robot @ 2016-10-31 19:06 UTC (permalink / raw)
  To: Sean Young; +Cc: kbuild-all, Mauro Carvalho Chehab, linux-media

[-- Attachment #1: Type: text/plain, Size: 1841 bytes --]

Hi Sean,

[auto build test WARNING on linuxtv-media/master]
[also build test WARNING on next-20161028]
[cannot apply to v4.9-rc3]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
[Suggest to use git(>=2.9.0) format-patch --base=<commit> (or --base=auto for convenience) to record what (public, well-known) commit your patch series was built on]
[Check https://git-scm.com/docs/git-format-patch for more information]

url:    https://github.com/0day-ci/linux/commits/Sean-Young/Various-IR-fixes/20161101-023658
base:   git://linuxtv.org/media_tree.git master
config: x86_64-randconfig-x014-201644 (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

All warnings (new ones prefixed by >>):

   drivers/media/rc/redrat3.c: In function 'redrat3_learn_complete':
>> drivers/media/rc/redrat3.c:903:6: warning: unused variable 'ret' [-Wunused-variable]
     int ret;
         ^~~

vim +/ret +903 drivers/media/rc/redrat3.c

   887	
   888		rr3->wideband = enable != 0;
   889	
   890		if (enable) {
   891			ret = usb_submit_urb(rr3->learn_urb, GFP_KERNEL);
   892			if (ret)
   893				dev_err(rr3->dev, "Failed to submit learning urb: %d",
   894										ret);
   895		}
   896	
   897		return ret;
   898	}
   899	
   900	static void redrat3_learn_complete(struct urb *urb)
   901	{
   902		struct redrat3_dev *rr3 = urb->context;
 > 903		int ret;
   904	
   905		switch (urb->status) {
   906		case 0:
   907			break;
   908		case -ECONNRESET:
   909		case -ENOENT:
   910		case -ESHUTDOWN:
   911			usb_unlink_urb(urb);

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 33953 bytes --]

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 5/9] [media] redrat3: enable carrier reports using wideband receiver
  2016-10-31 19:06   ` kbuild test robot
@ 2016-10-31 21:13     ` Sean Young
  0 siblings, 0 replies; 12+ messages in thread
From: Sean Young @ 2016-10-31 21:13 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: linux-media, Chris Dodge

The wideband receiver is a little awkward on the redrat3. Data arrives
on a different endpoint, and the learning command must be reissued
every time data is learned.

Signed-off-by: Sean Young <sean@mess.org>
---
 drivers/media/rc/redrat3.c | 186 ++++++++++++++++++++++++++++++++++-----------
 1 file changed, 140 insertions(+), 46 deletions(-)

diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c
index eaf374d..1882712 100644
--- a/drivers/media/rc/redrat3.c
+++ b/drivers/media/rc/redrat3.c
@@ -81,6 +81,8 @@
 #define RR3_RC_DET_ENABLE	0xbb
 /* Stop capture with the RC receiver */
 #define RR3_RC_DET_DISABLE	0xbc
+/* Start capture with the wideband receiver */
+#define RR3_MODSIG_CAPTURE     0xb2
 /* Return the status of RC detector capture */
 #define RR3_RC_DET_STATUS	0xbd
 /* Reset redrat */
@@ -105,8 +107,10 @@
 #define RR3_CLK_PER_COUNT	12
 /* (RR3_CLK / RR3_CLK_PER_COUNT) */
 #define RR3_CLK_CONV_FACTOR	2000000
-/* USB bulk-in IR data endpoint address */
-#define RR3_BULK_IN_EP_ADDR	0x82
+/* USB bulk-in wideband IR data endpoint address */
+#define RR3_WIDE_IN_EP_ADDR	0x81
+/* USB bulk-in narrowband IR data endpoint address */
+#define RR3_NARROW_IN_EP_ADDR	0x82
 
 /* Size of the fixed-length portion of the signal */
 #define RR3_DRIVER_MAXLENS	128
@@ -207,15 +211,22 @@ struct redrat3_dev {
 	struct urb *flash_urb;
 	u8 flash_in_buf;
 
+	/* learning */
+	bool wideband;
+	struct usb_ctrlrequest learn_control;
+	struct urb *learn_urb;
+	u8 learn_buf;
+
 	/* save off the usb device pointer */
 	struct usb_device *udev;
 
 	/* the receive endpoint */
-	struct usb_endpoint_descriptor *ep_in;
+	struct usb_endpoint_descriptor *ep_narrow;
 	/* the buffer to receive data */
 	void *bulk_in_buf;
 	/* urb used to read ir data */
-	struct urb *read_urb;
+	struct urb *narrow_urb;
+	struct urb *wide_urb;
 
 	/* the send endpoint */
 	struct usb_endpoint_descriptor *ep_out;
@@ -236,23 +247,6 @@ struct redrat3_dev {
 	char phys[64];
 };
 
-/*
- * redrat3_issue_async
- *
- *  Issues an async read to the ir data in port..
- *  sets the callback to be redrat3_handle_async
- */
-static void redrat3_issue_async(struct redrat3_dev *rr3)
-{
-	int res;
-
-	res = usb_submit_urb(rr3->read_urb, GFP_ATOMIC);
-	if (res)
-		dev_dbg(rr3->dev,
-			"%s: receive request FAILED! (res %d, len %d)\n",
-			__func__, res, rr3->read_urb->transfer_buffer_length);
-}
-
 static void redrat3_dump_fw_error(struct redrat3_dev *rr3, int code)
 {
 	if (!rr3->transmitting && (code != 0x40))
@@ -367,6 +361,14 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3)
 
 	mod_freq = redrat3_val_to_mod_freq(&rr3->irdata);
 	dev_dbg(dev, "Got mod_freq of %u\n", mod_freq);
+	if (mod_freq && rr3->wideband) {
+		DEFINE_IR_RAW_EVENT(ev);
+
+		ev.carrier_report = 1;
+		ev.carrier = mod_freq;
+
+		ir_raw_event_store(rr3->rc, &ev);
+	}
 
 	/* process each rr3 encoded byte into an int */
 	sig_size = be16_to_cpu(rr3->irdata.sig_size);
@@ -449,19 +451,31 @@ static int redrat3_enable_detector(struct redrat3_dev *rr3)
 		return -EIO;
 	}
 
-	redrat3_issue_async(rr3);
+	ret = usb_submit_urb(rr3->narrow_urb, GFP_KERNEL);
+	if (ret) {
+		dev_err(rr3->dev, "narrow band urb failed: %d", ret);
+		return ret;
+	}
 
-	return 0;
+	ret = usb_submit_urb(rr3->wide_urb, GFP_KERNEL);
+	if (ret)
+		dev_err(rr3->dev, "wide band urb failed: %d", ret);
+
+	return ret;
 }
 
 static inline void redrat3_delete(struct redrat3_dev *rr3,
 				  struct usb_device *udev)
 {
-	usb_kill_urb(rr3->read_urb);
+	usb_kill_urb(rr3->narrow_urb);
+	usb_kill_urb(rr3->wide_urb);
 	usb_kill_urb(rr3->flash_urb);
-	usb_free_urb(rr3->read_urb);
+	usb_kill_urb(rr3->learn_urb);
+	usb_free_urb(rr3->narrow_urb);
+	usb_free_urb(rr3->wide_urb);
 	usb_free_urb(rr3->flash_urb);
-	usb_free_coherent(udev, le16_to_cpu(rr3->ep_in->wMaxPacketSize),
+	usb_free_urb(rr3->learn_urb);
+	usb_free_coherent(udev, le16_to_cpu(rr3->ep_narrow->wMaxPacketSize),
 			  rr3->bulk_in_buf, rr3->dma_in);
 
 	kfree(rr3);
@@ -694,9 +708,19 @@ static void redrat3_handle_async(struct urb *urb)
 	switch (urb->status) {
 	case 0:
 		ret = redrat3_get_ir_data(rr3, urb->actual_length);
+		if (!ret && rr3->wideband && !rr3->learn_urb->hcpriv) {
+			ret = usb_submit_urb(rr3->learn_urb, GFP_ATOMIC);
+			if (ret)
+				dev_err(rr3->dev, "Failed to submit learning urb: %d",
+									ret);
+		}
+
 		if (!ret) {
 			/* no error, prepare to read more */
-			redrat3_issue_async(rr3);
+			ret = usb_submit_urb(urb, GFP_ATOMIC);
+			if (ret)
+				dev_err(rr3->dev, "Failed to resubmit urb: %d",
+									ret);
 		}
 		break;
 
@@ -856,6 +880,42 @@ static void redrat3_brightness_set(struct led_classdev *led_dev, enum
 	}
 }
 
+static int redrat3_wideband_receiver(struct rc_dev *rcdev, int enable)
+{
+	struct redrat3_dev *rr3 = rcdev->priv;
+	int ret = 0;
+
+	rr3->wideband = enable != 0;
+
+	if (enable) {
+		ret = usb_submit_urb(rr3->learn_urb, GFP_KERNEL);
+		if (ret)
+			dev_err(rr3->dev, "Failed to submit learning urb: %d",
+									ret);
+	}
+
+	return ret;
+}
+
+static void redrat3_learn_complete(struct urb *urb)
+{
+	struct redrat3_dev *rr3 = urb->context;
+
+	switch (urb->status) {
+	case 0:
+		break;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		usb_unlink_urb(urb);
+		return;
+	case -EPIPE:
+	default:
+		dev_err(rr3->dev, "Error: learn urb status = %d", urb->status);
+		break;
+	}
+}
+
 static void redrat3_led_complete(struct urb *urb)
 {
 	struct redrat3_dev *rr3 = urb->context;
@@ -910,6 +970,7 @@ static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3)
 	rc->s_timeout = redrat3_set_timeout;
 	rc->tx_ir = redrat3_transmit_ir;
 	rc->s_tx_carrier = redrat3_set_tx_carrier;
+	rc->s_carrier_report = redrat3_wideband_receiver;
 	rc->driver_name = DRIVER_NAME;
 	rc->rx_resolution = US_TO_NS(2);
 	rc->map_name = RC_MAP_HAUPPAUGE;
@@ -935,7 +996,8 @@ static int redrat3_dev_probe(struct usb_interface *intf,
 	struct usb_host_interface *uhi;
 	struct redrat3_dev *rr3;
 	struct usb_endpoint_descriptor *ep;
-	struct usb_endpoint_descriptor *ep_in = NULL;
+	struct usb_endpoint_descriptor *ep_narrow = NULL;
+	struct usb_endpoint_descriptor *ep_wide = NULL;
 	struct usb_endpoint_descriptor *ep_out = NULL;
 	u8 addr, attrs;
 	int pipe, i;
@@ -949,15 +1011,16 @@ static int redrat3_dev_probe(struct usb_interface *intf,
 		addr = ep->bEndpointAddress;
 		attrs = ep->bmAttributes;
 
-		if ((ep_in == NULL) &&
-		    ((addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) &&
+		if (((addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) &&
 		    ((attrs & USB_ENDPOINT_XFERTYPE_MASK) ==
 		     USB_ENDPOINT_XFER_BULK)) {
 			dev_dbg(dev, "found bulk-in endpoint at 0x%02x\n",
 				ep->bEndpointAddress);
-			/* data comes in on 0x82, 0x81 is for other data... */
-			if (ep->bEndpointAddress == RR3_BULK_IN_EP_ADDR)
-				ep_in = ep;
+			/* data comes in on 0x82, 0x81 is for learning */
+			if (ep->bEndpointAddress == RR3_NARROW_IN_EP_ADDR)
+				ep_narrow = ep;
+			if (ep->bEndpointAddress == RR3_WIDE_IN_EP_ADDR)
+				ep_wide = ep;
 		}
 
 		if ((ep_out == NULL) &&
@@ -970,8 +1033,8 @@ static int redrat3_dev_probe(struct usb_interface *intf,
 		}
 	}
 
-	if (!ep_in || !ep_out) {
-		dev_err(dev, "Couldn't find both in and out endpoints\n");
+	if (!ep_narrow || !ep_out || !ep_wide) {
+		dev_err(dev, "Couldn't find all endpoints\n");
 		retval = -ENODEV;
 		goto no_endpoints;
 	}
@@ -982,25 +1045,38 @@ static int redrat3_dev_probe(struct usb_interface *intf,
 		goto no_endpoints;
 
 	rr3->dev = &intf->dev;
-	rr3->ep_in = ep_in;
+	rr3->ep_narrow = ep_narrow;
 	rr3->ep_out = ep_out;
 	rr3->udev = udev;
 
 	/* set up bulk-in endpoint */
-	rr3->read_urb = usb_alloc_urb(0, GFP_KERNEL);
-	if (!rr3->read_urb)
+	rr3->narrow_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!rr3->narrow_urb)
+		goto redrat_free;
+
+	rr3->wide_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!rr3->wide_urb)
 		goto redrat_free;
 
 	rr3->bulk_in_buf = usb_alloc_coherent(udev,
-		le16_to_cpu(ep_in->wMaxPacketSize), GFP_KERNEL, &rr3->dma_in);
+		le16_to_cpu(ep_narrow->wMaxPacketSize),
+		GFP_KERNEL, &rr3->dma_in);
 	if (!rr3->bulk_in_buf)
 		goto redrat_free;
 
-	pipe = usb_rcvbulkpipe(udev, ep_in->bEndpointAddress);
-	usb_fill_bulk_urb(rr3->read_urb, udev, pipe, rr3->bulk_in_buf,
-		le16_to_cpu(ep_in->wMaxPacketSize), redrat3_handle_async, rr3);
-	rr3->read_urb->transfer_dma = rr3->dma_in;
-	rr3->read_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+	pipe = usb_rcvbulkpipe(udev, ep_narrow->bEndpointAddress);
+	usb_fill_bulk_urb(rr3->narrow_urb, udev, pipe, rr3->bulk_in_buf,
+		le16_to_cpu(ep_narrow->wMaxPacketSize),
+		redrat3_handle_async, rr3);
+	rr3->narrow_urb->transfer_dma = rr3->dma_in;
+	rr3->narrow_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	pipe = usb_rcvbulkpipe(udev, ep_wide->bEndpointAddress);
+	usb_fill_bulk_urb(rr3->wide_urb, udev, pipe, rr3->bulk_in_buf,
+		le16_to_cpu(ep_narrow->wMaxPacketSize),
+		redrat3_handle_async, rr3);
+	rr3->wide_urb->transfer_dma = rr3->dma_in;
+	rr3->wide_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 
 	redrat3_reset(rr3);
 	redrat3_get_firmware_rev(rr3);
@@ -1013,6 +1089,21 @@ static int redrat3_dev_probe(struct usb_interface *intf,
 	if (!rr3->flash_urb)
 		goto redrat_free;
 
+	/* learn urb */
+	rr3->learn_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!rr3->learn_urb)
+		goto redrat_free;
+
+	/* setup packet is 'c0 b2 0000 0000 0001' */
+	rr3->learn_control.bRequestType = 0xc0;
+	rr3->learn_control.bRequest = RR3_MODSIG_CAPTURE;
+	rr3->learn_control.wLength = cpu_to_le16(1);
+
+	usb_fill_control_urb(rr3->learn_urb, udev, usb_rcvctrlpipe(udev, 0),
+			(unsigned char *)&rr3->learn_control,
+			&rr3->learn_buf, sizeof(rr3->learn_buf),
+			redrat3_learn_complete, rr3);
+
 	/* setup packet is 'c0 b9 0000 0000 0001' */
 	rr3->flash_control.bRequestType = 0xc0;
 	rr3->flash_control.bRequest = RR3_BLINK_LED;
@@ -1072,7 +1163,8 @@ static int redrat3_dev_suspend(struct usb_interface *intf, pm_message_t message)
 	struct redrat3_dev *rr3 = usb_get_intfdata(intf);
 
 	led_classdev_suspend(&rr3->led);
-	usb_kill_urb(rr3->read_urb);
+	usb_kill_urb(rr3->narrow_urb);
+	usb_kill_urb(rr3->wide_urb);
 	usb_kill_urb(rr3->flash_urb);
 	return 0;
 }
@@ -1081,7 +1173,9 @@ static int redrat3_dev_resume(struct usb_interface *intf)
 {
 	struct redrat3_dev *rr3 = usb_get_intfdata(intf);
 
-	if (usb_submit_urb(rr3->read_urb, GFP_ATOMIC))
+	if (usb_submit_urb(rr3->narrow_urb, GFP_ATOMIC))
+		return -EIO;
+	if (usb_submit_urb(rr3->wide_urb, GFP_ATOMIC))
 		return -EIO;
 	led_classdev_resume(&rr3->led);
 	return 0;
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2016-10-31 21:13 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-10-31 17:52 [PATCH 0/9] Various IR fixes Sean Young
2016-10-31 17:52 ` [PATCH 1/9] [media] winbond-cir: use name without space for pnp driver Sean Young
2016-10-31 17:52 ` [PATCH 2/9] [media] redrat3: don't include vendor/product id in name Sean Young
2016-10-31 17:52 ` [PATCH 3/9] [media] redrat3: remove dead code and pointless messages Sean Young
2016-10-31 17:52 ` [PATCH 4/9] [media] redrat3: fix error paths in probe Sean Young
2016-10-31 17:52 ` [PATCH 5/9] [media] redrat3: enable carrier reports using wideband receiver Sean Young
2016-10-31 19:06   ` kbuild test robot
2016-10-31 21:13     ` Sean Young
2016-10-31 17:52 ` [PATCH 6/9] [media] redrat3: increase set size for lengths to maximum Sean Young
2016-10-31 17:52 ` [PATCH 7/9] [media] lirc: might sleep error in lirc_dev_fop_read Sean Young
2016-10-31 17:52 ` [PATCH 8/9] [media] lirc: prevent use-after free Sean Young
2016-10-31 17:52 ` [PATCH 9/9] [media] lirc: use-after free while reading from device and unplugging Sean Young

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.