// SPDX-License-Identifier: GPL-2.0-or-later /* * USB RedRat3 IR Transceiver rc-core driver * * Copyright (c) 2011 by Jarod Wilson <jarod@redhat.com> * based heavily on the work of Stephen Cox, with additional * help from RedRat Ltd. * * This driver began life based on an old version of the first-generation * lirc_mceusb driver from the lirc 0.7.2 distribution. It was then * significantly rewritten by Stephen Cox with the aid of RedRat Ltd's * Chris Dodge. * * The driver was then ported to rc-core and significantly rewritten again, * by Jarod, using the in-kernel mceusb driver as a guide, after an initial * port effort was started by Stephen. * * TODO LIST: * - fix lirc not showing repeats properly * -- * * The RedRat3 is a USB transceiver with both send & receive, * with 2 separate sensors available for receive to enable * both good long range reception for general use, and good * short range reception when required for learning a signal. * * http://www.redrat.co.uk/ * * It uses its own little protocol to communicate, the required * parts of which are embedded within this driver. * --
*/
/* Driver Information */ #define DRIVER_AUTHOR "Jarod Wilson " #define DRIVER_AUTHOR2 "The Dweller, Stephen Cox" #define DRIVER_DESC "RedRat3 USB IR Transceiver Driver" #define DRIVER_NAME "redrat3"
/* bulk data transfer types */ #define RR3_ERROR 0x01 #define RR3_MOD_SIGNAL_IN 0x20 #define RR3_MOD_SIGNAL_OUT 0x21
/* Get the RR firmware version */ #define RR3_FW_VERSION 0xb1 #define RR3_FW_VERSION_LEN 64 /* Send encoded signal bulk-sent earlier*/ #define RR3_TX_SEND_SIGNAL 0xb3 #define RR3_SET_IR_PARAM 0xb7 #define RR3_GET_IR_PARAM 0xb8 /* Blink the red LED on the device */ #define RR3_BLINK_LED 0xb9 /* Read serial number of device */ #define RR3_READ_SER_NO 0xba #define RR3_SER_NO_LEN 4 /* Start capture with the RC receiver */ #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 */ #define RR3_RESET 0xa0
/* Max number of lengths in the signal. */ #define RR3_IR_IO_MAX_LENGTHS 0x01 /* Periods to measure mod. freq. */ #define RR3_IR_IO_PERIODS_MF 0x02 /* Size of memory for main signal data */ #define RR3_IR_IO_SIG_MEM_SIZE 0x03 /* Delta value when measuring lengths */ #define RR3_IR_IO_LENGTH_FUZZ 0x04 /* Timeout for end of signal detection */ #define RR3_IR_IO_SIG_TIMEOUT 0x05 /* Minimum value for pause recognition. */ #define RR3_IR_IO_MIN_PAUSE 0x06
/* Clock freq. of EZ-USB chip */ #define RR3_CLK 24000000 /* Clock periods per timer count */ #define RR3_CLK_PER_COUNT 12 /* (RR3_CLK / RR3_CLK_PER_COUNT) */ #define RR3_CLK_CONV_FACTOR 2000000 /* 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 255 #define RR3_MAX_SIG_SIZE 512 #define RR3_TIME_UNIT 50 #define RR3_END_OF_SIGNAL 0x7f #define RR3_TX_TRAILER_LEN 2 #define RR3_RX_MIN_TIMEOUT 5 #define RR3_RX_MAX_TIMEOUT 2000
/* The 8051's CPUCS Register address */ #define RR3_CPUCS_REG_ADDR 0x7f92
/* * The redrat3 encodes an IR signal as set of different lengths and a set * of indices into those lengths. This sets how much two lengths must * differ before they are considered distinct, the value is specified * in microseconds. * Default 5, value 0 to 127.
*/ staticint length_fuzz = 5;
module_param(length_fuzz, uint, 0644);
MODULE_PARM_DESC(length_fuzz, "Length Fuzz (0-127)");
/* * When receiving a continuous ir stream (for example when a user is * holding a button down on a remote), this specifies the minimum size * of a space when the redrat3 sends a irdata packet to the host. Specified * in milliseconds. Default value 18ms. * The value can be between 2 and 30 inclusive.
*/ staticint minimum_pause = 18;
module_param(minimum_pause, uint, 0644);
MODULE_PARM_DESC(minimum_pause, "Minimum Pause in ms (2-30)");
/* * The carrier frequency is measured during the first pulse of the IR * signal. The larger the number of periods used To measure, the more * accurate the result is likely to be, however some signals have short * initial pulses, so in some case it may be necessary to reduce this value. * Default 8, value 1 to 255.
*/ staticint periods_measure_carrier = 8;
module_param(periods_measure_carrier, uint, 0644);
MODULE_PARM_DESC(periods_measure_carrier, "Number of Periods to Measure Carrier (1-255)");
/* table of devices that work with this driver */ staticconststruct usb_device_id redrat3_dev_table[] = { /* Original version of the RedRat3 */
{USB_DEVICE(USB_RR3USB_VENDOR_ID, USB_RR3USB_PRODUCT_ID)}, /* Second Version/release of the RedRat3 - RetRat3-II */
{USB_DEVICE(USB_RR3USB_VENDOR_ID, USB_RR3IIUSB_PRODUCT_ID)},
{} /* Terminating entry */
};
/* Structure to hold all of our device specific stuff */ struct redrat3_dev { /* core device bits */ struct rc_dev *rc; struct device *dev;
/* led control */ struct led_classdev led;
atomic_t flash; struct usb_ctrlrequest flash_control; struct urb *flash_urb;
u8 flash_in_buf;
/* save off the usb device pointer */ struct usb_device *udev;
/* the receive endpoint */ struct usb_endpoint_descriptor *ep_narrow; /* the buffer to receive data */ void *bulk_in_buf; /* urb used to read ir data */ struct urb *narrow_urb; struct urb *wide_urb;
/* the send endpoint */ struct usb_endpoint_descriptor *ep_out;
/* usb dma */
dma_addr_t dma_in;
/* Is the device currently transmitting?*/ bool transmitting;
/* store for current packet */ struct redrat3_irdata irdata;
u16 bytes_read;
u32 carrier;
char name[64]; char phys[64];
};
staticvoid redrat3_dump_fw_error(struct redrat3_dev *rr3, int code)
{ if (!rr3->transmitting && (code != 0x40))
dev_info(rr3->dev, "fw error code 0x%02x: ", code);
switch (code) { case 0x00:
pr_cont("No Error\n"); break;
/* Codes 0x20 through 0x2f are IR Firmware Errors */ case 0x20:
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"); break; case 0x22:
pr_cont("Not enough memory allocated for signal data\n"); break; case 0x23:
pr_cont("Too many signal repeats\n"); break; case 0x28:
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"); break;
/* Codes 0x30 through 0x3f are USB Firmware Errors */ case 0x30:
pr_cont("Insufficient memory available for bulk transfer structure\n"); break;
/* * Other error codes... These are primarily errors that can occur in * the control messages sent to the redrat
*/ case 0x40: if (!rr3->transmitting)
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"); break; case 0x42:
pr_cont("Signal capture already started\n"); break;
/* this function scales down the figures for the same result... */ static u32 redrat3_len_to_us(u32 length)
{
u32 biglen = length * 1000;
u32 divisor = (RR3_CLK_CONV_FACTOR) / 1000;
u32 result = (u32) (biglen / divisor);
/* don't allow zero lengths to go back, breaks lirc */ return result ? result : 1;
}
/* * convert us back into redrat3 lengths * * length * 1000 length * 1000000 * ------------- = ---------------- = micro * rr3clk / 1000 rr3clk
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) { struct ir_raw_event ev = {
.carrier_report = 1,
.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); for (i = 0; i < sig_size; i++) {
offset = rr3->irdata.sigdata[i];
val = get_unaligned_be16(&rr3->irdata.lens[offset]);
/* we should always get pulse/space/pulse/space samples */ if (i % 2)
rawir.pulse = false; else
rawir.pulse = true;
rawir.duration = redrat3_len_to_us(val); /* cap the value to IR_MAX_DURATION */
rawir.duration = (rawir.duration > IR_MAX_DURATION) ?
IR_MAX_DURATION : rawir.duration;
if (res < 0) {
dev_err(rr3->dev, "%s: Error sending rr3 cmd res %d, data %d",
__func__, res, *data);
res = -EIO;
} else
res = data[0];
kfree(data);
return res;
}
/* Enables the long range detector and starts async receive */ staticint redrat3_enable_detector(struct redrat3_dev *rr3)
{ struct device *dev = rr3->dev; int ret;
ret = redrat3_send_cmd(RR3_RC_DET_ENABLE, rr3); if (ret != 0)
dev_dbg(dev, "%s: unexpected ret of %d\n",
__func__, ret);
ret = redrat3_send_cmd(RR3_RC_DET_STATUS, rr3); if (ret != 1) {
dev_err(dev, "%s: detector status: %d, should be 1\n",
__func__, ret); return -EIO;
}
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);
static u32 redrat3_get_timeout(struct redrat3_dev *rr3)
{
__be32 *tmp;
u32 timeout = MS_TO_US(150); /* a sane default, if things go haywire */ int len, ret, pipe;
len = sizeof(*tmp);
tmp = kzalloc(len, GFP_KERNEL); if (!tmp) return timeout;
pipe = usb_rcvctrlpipe(rr3->udev, 0);
ret = usb_control_msg(rr3->udev, pipe, RR3_GET_IR_PARAM,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
RR3_IR_IO_SIG_TIMEOUT, 0, tmp, len, 5000); if (ret != len)
dev_warn(rr3->dev, "Failed to read timeout from hardware\n"); else {
timeout = redrat3_len_to_us(be32_to_cpup(tmp));
dev_dbg(rr3->dev, "Got timeout of %d ms\n", timeout / 1000);
}
/* gather IR data from incoming urb, process it when we have enough */ staticint redrat3_get_ir_data(struct redrat3_dev *rr3, unsigned len)
{ struct device *dev = rr3->dev; unsigned pkttype; int ret = 0;
if (rr3->bytes_read == 0 && len >= sizeof(struct redrat3_header)) {
redrat3_read_packet_start(rr3, len);
} elseif (rr3->bytes_read != 0) {
redrat3_read_packet_continue(rr3, len);
} elseif (rr3->bytes_read == 0) {
dev_err(dev, "error: no packet data read\n");
ret = -ENODATA; goto out;
}
if (rr3->bytes_read < be16_to_cpu(rr3->irdata.header.length) + sizeof(struct redrat3_header)) /* we're still accumulating data */ return 0;
/* if we get here, we've got IR data to decode */
pkttype = be16_to_cpu(rr3->irdata.header.transfer_type); if (pkttype == RR3_MOD_SIGNAL_IN)
redrat3_process_ir_data(rr3); else
dev_dbg(dev, "discarding non-signal data packet (type 0x%02x)\n",
pkttype);
out:
rr3->bytes_read = 0; return ret;
}
/* callback function from USB when async USB request has completed */ staticvoid redrat3_handle_async(struct urb *urb)
{ struct redrat3_dev *rr3 = urb->context; int ret;
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 */
ret = usb_submit_urb(urb, GFP_ATOMIC); if (ret)
dev_err(rr3->dev, "Failed to resubmit urb: %d",
ret);
} break;
case -ECONNRESET: case -ENOENT: case -ESHUTDOWN:
usb_unlink_urb(urb); return;
case -EPIPE: default:
dev_warn(rr3->dev, "Error: urb status = %d\n", urb->status);
rr3->bytes_read = 0; break;
}
}
static u16 mod_freq_to_val(unsignedint mod_freq)
{ int mult = 6000000;
/* Clk used in mod. freq. generation is CLK24/4. */ return 65536 - (mult / mod_freq);
}
/* now tell the hardware to transmit what we sent it */
pipe = usb_rcvctrlpipe(rr3->udev, 0);
ret = usb_control_msg(rr3->udev, pipe, RR3_TX_SEND_SIGNAL,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
0, 0, irdata, 2, 10000);
if (ret < 0)
dev_err(dev, "Error: control msg send failed, rc %d\n", ret); else
ret = count;
out:
kfree(irdata);
kfree(sample_lens);
rr3->transmitting = false; /* rr3 re-enables rc detector because it was enabled before */
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;
}
}
switch (urb->status) { case 0: break; case -ECONNRESET: case -ENOENT: case -ESHUTDOWN:
usb_unlink_urb(urb); return; case -EPIPE: default:
dev_dbg(rr3->dev, "Error: urb status = %d\n", urb->status); break;
}
/* find our bulk-in and bulk-out endpoints */ for (i = 0; i < uhi->desc.bNumEndpoints; ++i) {
ep = &uhi->endpoint[i].desc;
addr = ep->bEndpointAddress;
attrs = ep->bmAttributes;
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 learning */ if (ep->bEndpointAddress == RR3_NARROW_IN_EP_ADDR)
ep_narrow = ep; if (ep->bEndpointAddress == RR3_WIDE_IN_EP_ADDR)
ep_wide = ep;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.