diff options
Diffstat (limited to 'drivers/media/rc/redrat3.c')
-rw-r--r-- | drivers/media/rc/redrat3.c | 327 |
1 files changed, 190 insertions, 137 deletions
diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index 05ba47bc0b61..2784f5dae398 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,11 +107,13 @@ #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 +#define RR3_DRIVER_MAXLENS 255 #define RR3_MAX_SIG_SIZE 512 #define RR3_TIME_UNIT 50 #define RR3_END_OF_SIGNAL 0x7f @@ -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)) @@ -265,8 +259,7 @@ static void redrat3_dump_fw_error(struct redrat3_dev *rr3, int code) /* Codes 0x20 through 0x2f are IR Firmware Errors */ case 0x20: - pr_cont("Initial signal pulse not long enough " - "to measure carrier frequency\n"); + pr_cont("Initial signal pulse not long enough to measure carrier frequency\n"); break; case 0x21: pr_cont("Not enough length values allocated for signal\n"); @@ -278,18 +271,15 @@ static void redrat3_dump_fw_error(struct redrat3_dev *rr3, int code) pr_cont("Too many signal repeats\n"); break; case 0x28: - pr_cont("Insufficient memory available for IR signal " - "data memory allocation\n"); + pr_cont("Insufficient memory available for IR signal data memory allocation\n"); break; case 0x29: - pr_cont("Insufficient memory available " - "for IrDa signal data memory allocation\n"); + pr_cont("Insufficient memory available for IrDa signal data memory allocation\n"); break; /* Codes 0x30 through 0x3f are USB Firmware Errors */ case 0x30: - pr_cont("Insufficient memory available for bulk " - "transfer structure\n"); + pr_cont("Insufficient memory available for bulk transfer structure\n"); break; /* @@ -301,8 +291,7 @@ static void redrat3_dump_fw_error(struct redrat3_dev *rr3, int code) pr_cont("Signal capture has been terminated\n"); break; case 0x41: - pr_cont("Attempt to set/get and unknown signal I/O " - "algorithm parameter\n"); + pr_cont("Attempt to set/get and unknown signal I/O algorithm parameter\n"); break; case 0x42: pr_cont("Signal capture already started\n"); @@ -368,15 +357,18 @@ 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); 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); @@ -459,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; + } + + ret = usb_submit_urb(rr3->wide_urb, GFP_KERNEL); + if (ret) + dev_err(rr3->dev, "wide band urb failed: %d", ret); - return 0; + 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); @@ -485,10 +489,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, @@ -543,16 +545,14 @@ static void redrat3_reset(struct redrat3_dev *rr3) struct device *dev = rr3->dev; int rc, rxpipe, txpipe; u8 *val; - int len = sizeof(u8); + size_t const len = sizeof(*val); rxpipe = usb_rcvctrlpipe(udev, 0); 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, @@ -590,14 +590,12 @@ static void redrat3_reset(struct redrat3_dev *rr3) static void redrat3_get_firmware_rev(struct redrat3_dev *rr3) { - int rc = 0; + int rc; char *buffer; - buffer = kzalloc(sizeof(char) * (RR3_FW_VERSION_LEN + 1), GFP_KERNEL); - if (!buffer) { - dev_err(rr3->dev, "Memory allocation failure\n"); + buffer = kcalloc(RR3_FW_VERSION_LEN + 1, sizeof(*buffer), GFP_KERNEL); + if (!buffer) return; - } rc = usb_control_msg(rr3->udev, usb_rcvctrlpipe(rr3->udev, 0), RR3_FW_VERSION, @@ -704,25 +702,25 @@ out: /* 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); + 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; @@ -785,11 +783,11 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf, /* rr3 will disable rc detector on transmit */ rr3->transmitting = true; - sample_lens = kzalloc(sizeof(int) * RR3_DRIVER_MAXLENS, GFP_KERNEL); - if (!sample_lens) { - ret = -ENOMEM; - goto out; - } + sample_lens = kcalloc(RR3_DRIVER_MAXLENS, + sizeof(*sample_lens), + GFP_KERNEL); + if (!sample_lens) + return -ENOMEM; irdata = kzalloc(sizeof(*irdata), GFP_KERNEL); if (!irdata) { @@ -857,8 +855,8 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf, ret = count; out: - kfree(sample_lens); kfree(irdata); + kfree(sample_lens); rr3->transmitting = false; /* rr3 re-enables rc detector because it was enabled before */ @@ -882,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; @@ -908,19 +942,16 @@ static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3) { struct device *dev = rr3->dev; struct rc_dev *rc; - int ret = -ENODEV; + int ret; u16 prod = le16_to_cpu(rr3->udev->descriptor.idProduct); rc = rc_allocate_device(); - if (!rc) { - dev_err(dev, "remote input dev allocation failed\n"); - goto out; - } + if (!rc) + return NULL; - 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)); @@ -937,6 +968,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; @@ -962,7 +994,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; @@ -976,15 +1009,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) && @@ -997,68 +1031,76 @@ 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; } /* 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) goto no_endpoints; - } rr3->dev = &intf->dev; + 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) - goto error; + rr3->narrow_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!rr3->narrow_urb) + 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) { - dev_err(dev, "Read buffer allocation failure\n"); - goto error; - } - - 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; + rr3->wide_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!rr3->wide_urb) + goto redrat_free; - rr3->ep_out = ep_out; - rr3->udev = udev; + rr3->bulk_in_buf = usb_alloc_coherent(udev, + le16_to_cpu(ep_narrow->wMaxPacketSize), + GFP_KERNEL, &rr3->dma_in); + if (!rr3->bulk_in_buf) + goto redrat_free; + + 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); - /* 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; + + /* 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; @@ -1070,25 +1112,36 @@ 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: - dev_err(dev, "%s: retval = %x", __func__, retval); - return retval; } @@ -1097,9 +1150,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); @@ -1111,7 +1161,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; } @@ -1120,7 +1171,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; |