1*2154be65SJarod Wilson /* 2*2154be65SJarod Wilson * USB RedRat3 IR Transceiver rc-core driver 3*2154be65SJarod Wilson * 4*2154be65SJarod Wilson * Copyright (c) 2011 by Jarod Wilson <jarod@redhat.com> 5*2154be65SJarod Wilson * based heavily on the work of Stephen Cox, with additional 6*2154be65SJarod Wilson * help from RedRat Ltd. 7*2154be65SJarod Wilson * 8*2154be65SJarod Wilson * This driver began life based an an old version of the first-generation 9*2154be65SJarod Wilson * lirc_mceusb driver from the lirc 0.7.2 distribution. It was then 10*2154be65SJarod Wilson * significantly rewritten by Stephen Cox with the aid of RedRat Ltd's 11*2154be65SJarod Wilson * Chris Dodge. 12*2154be65SJarod Wilson * 13*2154be65SJarod Wilson * The driver was then ported to rc-core and significantly rewritten again, 14*2154be65SJarod Wilson * by Jarod, using the in-kernel mceusb driver as a guide, after an initial 15*2154be65SJarod Wilson * port effort was started by Stephen. 16*2154be65SJarod Wilson * 17*2154be65SJarod Wilson * TODO LIST: 18*2154be65SJarod Wilson * - fix lirc not showing repeats properly 19*2154be65SJarod Wilson * -- 20*2154be65SJarod Wilson * 21*2154be65SJarod Wilson * The RedRat3 is a USB transceiver with both send & receive, 22*2154be65SJarod Wilson * with 2 separate sensors available for receive to enable 23*2154be65SJarod Wilson * both good long range reception for general use, and good 24*2154be65SJarod Wilson * short range reception when required for learning a signal. 25*2154be65SJarod Wilson * 26*2154be65SJarod Wilson * http://www.redrat.co.uk/ 27*2154be65SJarod Wilson * 28*2154be65SJarod Wilson * It uses its own little protocol to communicate, the required 29*2154be65SJarod Wilson * parts of which are embedded within this driver. 30*2154be65SJarod Wilson * -- 31*2154be65SJarod Wilson * 32*2154be65SJarod Wilson * This program is free software; you can redistribute it and/or modify 33*2154be65SJarod Wilson * it under the terms of the GNU General Public License as published by 34*2154be65SJarod Wilson * the Free Software Foundation; either version 2 of the License, or 35*2154be65SJarod Wilson * (at your option) any later version. 36*2154be65SJarod Wilson * 37*2154be65SJarod Wilson * This program is distributed in the hope that it will be useful, 38*2154be65SJarod Wilson * but WITHOUT ANY WARRANTY; without even the implied warranty of 39*2154be65SJarod Wilson * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 40*2154be65SJarod Wilson * GNU General Public License for more details. 41*2154be65SJarod Wilson * 42*2154be65SJarod Wilson * You should have received a copy of the GNU General Public License 43*2154be65SJarod Wilson * along with this program; if not, write to the Free Software 44*2154be65SJarod Wilson * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 45*2154be65SJarod Wilson * 46*2154be65SJarod Wilson */ 47*2154be65SJarod Wilson 48*2154be65SJarod Wilson #include <linux/device.h> 49*2154be65SJarod Wilson #include <linux/module.h> 50*2154be65SJarod Wilson #include <linux/slab.h> 51*2154be65SJarod Wilson #include <linux/usb.h> 52*2154be65SJarod Wilson #include <linux/usb/input.h> 53*2154be65SJarod Wilson #include <media/rc-core.h> 54*2154be65SJarod Wilson 55*2154be65SJarod Wilson /* Driver Information */ 56*2154be65SJarod Wilson #define DRIVER_VERSION "0.70" 57*2154be65SJarod Wilson #define DRIVER_AUTHOR "Jarod Wilson <jarod@redhat.com>" 58*2154be65SJarod Wilson #define DRIVER_AUTHOR2 "The Dweller, Stephen Cox" 59*2154be65SJarod Wilson #define DRIVER_DESC "RedRat3 USB IR Transceiver Driver" 60*2154be65SJarod Wilson #define DRIVER_NAME "redrat3" 61*2154be65SJarod Wilson 62*2154be65SJarod Wilson /* module parameters */ 63*2154be65SJarod Wilson #ifdef CONFIG_USB_DEBUG 64*2154be65SJarod Wilson static int debug = 1; 65*2154be65SJarod Wilson #else 66*2154be65SJarod Wilson static int debug; 67*2154be65SJarod Wilson #endif 68*2154be65SJarod Wilson 69*2154be65SJarod Wilson #define RR3_DEBUG_STANDARD 0x1 70*2154be65SJarod Wilson #define RR3_DEBUG_FUNCTION_TRACE 0x2 71*2154be65SJarod Wilson 72*2154be65SJarod Wilson #define rr3_dbg(dev, fmt, ...) \ 73*2154be65SJarod Wilson do { \ 74*2154be65SJarod Wilson if (debug & RR3_DEBUG_STANDARD) \ 75*2154be65SJarod Wilson dev_info(dev, fmt, ## __VA_ARGS__); \ 76*2154be65SJarod Wilson } while (0) 77*2154be65SJarod Wilson 78*2154be65SJarod Wilson #define rr3_ftr(dev, fmt, ...) \ 79*2154be65SJarod Wilson do { \ 80*2154be65SJarod Wilson if (debug & RR3_DEBUG_FUNCTION_TRACE) \ 81*2154be65SJarod Wilson dev_info(dev, fmt, ## __VA_ARGS__); \ 82*2154be65SJarod Wilson } while (0) 83*2154be65SJarod Wilson 84*2154be65SJarod Wilson /* bulk data transfer types */ 85*2154be65SJarod Wilson #define RR3_ERROR 0x01 86*2154be65SJarod Wilson #define RR3_MOD_SIGNAL_IN 0x20 87*2154be65SJarod Wilson #define RR3_MOD_SIGNAL_OUT 0x21 88*2154be65SJarod Wilson 89*2154be65SJarod Wilson /* Get the RR firmware version */ 90*2154be65SJarod Wilson #define RR3_FW_VERSION 0xb1 91*2154be65SJarod Wilson #define RR3_FW_VERSION_LEN 64 92*2154be65SJarod Wilson /* Send encoded signal bulk-sent earlier*/ 93*2154be65SJarod Wilson #define RR3_TX_SEND_SIGNAL 0xb3 94*2154be65SJarod Wilson #define RR3_SET_IR_PARAM 0xb7 95*2154be65SJarod Wilson #define RR3_GET_IR_PARAM 0xb8 96*2154be65SJarod Wilson /* Blink the red LED on the device */ 97*2154be65SJarod Wilson #define RR3_BLINK_LED 0xb9 98*2154be65SJarod Wilson /* Read serial number of device */ 99*2154be65SJarod Wilson #define RR3_READ_SER_NO 0xba 100*2154be65SJarod Wilson #define RR3_SER_NO_LEN 4 101*2154be65SJarod Wilson /* Start capture with the RC receiver */ 102*2154be65SJarod Wilson #define RR3_RC_DET_ENABLE 0xbb 103*2154be65SJarod Wilson /* Stop capture with the RC receiver */ 104*2154be65SJarod Wilson #define RR3_RC_DET_DISABLE 0xbc 105*2154be65SJarod Wilson /* Return the status of RC detector capture */ 106*2154be65SJarod Wilson #define RR3_RC_DET_STATUS 0xbd 107*2154be65SJarod Wilson /* Reset redrat */ 108*2154be65SJarod Wilson #define RR3_RESET 0xa0 109*2154be65SJarod Wilson 110*2154be65SJarod Wilson /* Max number of lengths in the signal. */ 111*2154be65SJarod Wilson #define RR3_IR_IO_MAX_LENGTHS 0x01 112*2154be65SJarod Wilson /* Periods to measure mod. freq. */ 113*2154be65SJarod Wilson #define RR3_IR_IO_PERIODS_MF 0x02 114*2154be65SJarod Wilson /* Size of memory for main signal data */ 115*2154be65SJarod Wilson #define RR3_IR_IO_SIG_MEM_SIZE 0x03 116*2154be65SJarod Wilson /* Delta value when measuring lengths */ 117*2154be65SJarod Wilson #define RR3_IR_IO_LENGTH_FUZZ 0x04 118*2154be65SJarod Wilson /* Timeout for end of signal detection */ 119*2154be65SJarod Wilson #define RR3_IR_IO_SIG_TIMEOUT 0x05 120*2154be65SJarod Wilson /* Minumum value for pause recognition. */ 121*2154be65SJarod Wilson #define RR3_IR_IO_MIN_PAUSE 0x06 122*2154be65SJarod Wilson 123*2154be65SJarod Wilson /* Clock freq. of EZ-USB chip */ 124*2154be65SJarod Wilson #define RR3_CLK 24000000 125*2154be65SJarod Wilson /* Clock periods per timer count */ 126*2154be65SJarod Wilson #define RR3_CLK_PER_COUNT 12 127*2154be65SJarod Wilson /* (RR3_CLK / RR3_CLK_PER_COUNT) */ 128*2154be65SJarod Wilson #define RR3_CLK_CONV_FACTOR 2000000 129*2154be65SJarod Wilson /* USB bulk-in IR data endpoint address */ 130*2154be65SJarod Wilson #define RR3_BULK_IN_EP_ADDR 0x82 131*2154be65SJarod Wilson 132*2154be65SJarod Wilson /* Raw Modulated signal data value offsets */ 133*2154be65SJarod Wilson #define RR3_PAUSE_OFFSET 0 134*2154be65SJarod Wilson #define RR3_FREQ_COUNT_OFFSET 4 135*2154be65SJarod Wilson #define RR3_NUM_PERIOD_OFFSET 6 136*2154be65SJarod Wilson #define RR3_MAX_LENGTHS_OFFSET 8 137*2154be65SJarod Wilson #define RR3_NUM_LENGTHS_OFFSET 9 138*2154be65SJarod Wilson #define RR3_MAX_SIGS_OFFSET 10 139*2154be65SJarod Wilson #define RR3_NUM_SIGS_OFFSET 12 140*2154be65SJarod Wilson #define RR3_REPEATS_OFFSET 14 141*2154be65SJarod Wilson 142*2154be65SJarod Wilson /* Size of the fixed-length portion of the signal */ 143*2154be65SJarod Wilson #define RR3_HEADER_LENGTH 15 144*2154be65SJarod Wilson #define RR3_DRIVER_MAXLENS 128 145*2154be65SJarod Wilson #define RR3_MAX_SIG_SIZE 512 146*2154be65SJarod Wilson #define RR3_MAX_BUF_SIZE \ 147*2154be65SJarod Wilson ((2 * RR3_HEADER_LENGTH) + RR3_DRIVER_MAXLENS + RR3_MAX_SIG_SIZE) 148*2154be65SJarod Wilson #define RR3_TIME_UNIT 50 149*2154be65SJarod Wilson #define RR3_END_OF_SIGNAL 0x7f 150*2154be65SJarod Wilson #define RR3_TX_HEADER_OFFSET 4 151*2154be65SJarod Wilson #define RR3_TX_TRAILER_LEN 2 152*2154be65SJarod Wilson #define RR3_RX_MIN_TIMEOUT 5 153*2154be65SJarod Wilson #define RR3_RX_MAX_TIMEOUT 2000 154*2154be65SJarod Wilson 155*2154be65SJarod Wilson /* The 8051's CPUCS Register address */ 156*2154be65SJarod Wilson #define RR3_CPUCS_REG_ADDR 0x7f92 157*2154be65SJarod Wilson 158*2154be65SJarod Wilson #define USB_RR3USB_VENDOR_ID 0x112a 159*2154be65SJarod Wilson #define USB_RR3USB_PRODUCT_ID 0x0001 160*2154be65SJarod Wilson #define USB_RR3IIUSB_PRODUCT_ID 0x0005 161*2154be65SJarod Wilson 162*2154be65SJarod Wilson /* table of devices that work with this driver */ 163*2154be65SJarod Wilson static struct usb_device_id redrat3_dev_table[] = { 164*2154be65SJarod Wilson /* Original version of the RedRat3 */ 165*2154be65SJarod Wilson {USB_DEVICE(USB_RR3USB_VENDOR_ID, USB_RR3USB_PRODUCT_ID)}, 166*2154be65SJarod Wilson /* Second Version/release of the RedRat3 - RetRat3-II */ 167*2154be65SJarod Wilson {USB_DEVICE(USB_RR3USB_VENDOR_ID, USB_RR3IIUSB_PRODUCT_ID)}, 168*2154be65SJarod Wilson {} /* Terminating entry */ 169*2154be65SJarod Wilson }; 170*2154be65SJarod Wilson 171*2154be65SJarod Wilson /* Structure to hold all of our device specific stuff */ 172*2154be65SJarod Wilson struct redrat3_dev { 173*2154be65SJarod Wilson /* core device bits */ 174*2154be65SJarod Wilson struct rc_dev *rc; 175*2154be65SJarod Wilson struct device *dev; 176*2154be65SJarod Wilson 177*2154be65SJarod Wilson /* save off the usb device pointer */ 178*2154be65SJarod Wilson struct usb_device *udev; 179*2154be65SJarod Wilson 180*2154be65SJarod Wilson /* the receive endpoint */ 181*2154be65SJarod Wilson struct usb_endpoint_descriptor *ep_in; 182*2154be65SJarod Wilson /* the buffer to receive data */ 183*2154be65SJarod Wilson unsigned char *bulk_in_buf; 184*2154be65SJarod Wilson /* urb used to read ir data */ 185*2154be65SJarod Wilson struct urb *read_urb; 186*2154be65SJarod Wilson 187*2154be65SJarod Wilson /* the send endpoint */ 188*2154be65SJarod Wilson struct usb_endpoint_descriptor *ep_out; 189*2154be65SJarod Wilson /* the buffer to send data */ 190*2154be65SJarod Wilson unsigned char *bulk_out_buf; 191*2154be65SJarod Wilson /* the urb used to send data */ 192*2154be65SJarod Wilson struct urb *write_urb; 193*2154be65SJarod Wilson 194*2154be65SJarod Wilson /* usb dma */ 195*2154be65SJarod Wilson dma_addr_t dma_in; 196*2154be65SJarod Wilson dma_addr_t dma_out; 197*2154be65SJarod Wilson 198*2154be65SJarod Wilson /* true if write urb is busy */ 199*2154be65SJarod Wilson bool write_busy; 200*2154be65SJarod Wilson /* wait for the write to finish */ 201*2154be65SJarod Wilson struct completion write_finished; 202*2154be65SJarod Wilson 203*2154be65SJarod Wilson /* locks this structure */ 204*2154be65SJarod Wilson struct mutex lock; 205*2154be65SJarod Wilson 206*2154be65SJarod Wilson /* rx signal timeout timer */ 207*2154be65SJarod Wilson struct timer_list rx_timeout; 208*2154be65SJarod Wilson 209*2154be65SJarod Wilson /* Is the device currently receiving? */ 210*2154be65SJarod Wilson bool recv_in_progress; 211*2154be65SJarod Wilson /* is the detector enabled*/ 212*2154be65SJarod Wilson bool det_enabled; 213*2154be65SJarod Wilson /* Is the device currently transmitting?*/ 214*2154be65SJarod Wilson bool transmitting; 215*2154be65SJarod Wilson 216*2154be65SJarod Wilson /* store for current packet */ 217*2154be65SJarod Wilson char pbuf[RR3_MAX_BUF_SIZE]; 218*2154be65SJarod Wilson u16 pktlen; 219*2154be65SJarod Wilson u16 pkttype; 220*2154be65SJarod Wilson u16 bytes_read; 221*2154be65SJarod Wilson /* indicate whether we are going to reprocess 222*2154be65SJarod Wilson * the USB callback with a bigger buffer */ 223*2154be65SJarod Wilson int buftoosmall; 224*2154be65SJarod Wilson char *datap; 225*2154be65SJarod Wilson 226*2154be65SJarod Wilson u32 carrier; 227*2154be65SJarod Wilson 228*2154be65SJarod Wilson char name[128]; 229*2154be65SJarod Wilson char phys[64]; 230*2154be65SJarod Wilson }; 231*2154be65SJarod Wilson 232*2154be65SJarod Wilson /* All incoming data buffers adhere to a very specific data format */ 233*2154be65SJarod Wilson struct redrat3_signal_header { 234*2154be65SJarod Wilson u16 length; /* Length of data being transferred */ 235*2154be65SJarod Wilson u16 transfer_type; /* Type of data transferred */ 236*2154be65SJarod Wilson u32 pause; /* Pause between main and repeat signals */ 237*2154be65SJarod Wilson u16 mod_freq_count; /* Value of timer on mod. freq. measurement */ 238*2154be65SJarod Wilson u16 no_periods; /* No. of periods over which mod. freq. is measured */ 239*2154be65SJarod Wilson u8 max_lengths; /* Max no. of lengths (i.e. size of array) */ 240*2154be65SJarod Wilson u8 no_lengths; /* Actual no. of elements in lengths array */ 241*2154be65SJarod Wilson u16 max_sig_size; /* Max no. of values in signal data array */ 242*2154be65SJarod Wilson u16 sig_size; /* Acuto no. of values in signal data array */ 243*2154be65SJarod Wilson u8 no_repeats; /* No. of repeats of repeat signal section */ 244*2154be65SJarod Wilson /* Here forward is the lengths and signal data */ 245*2154be65SJarod Wilson }; 246*2154be65SJarod Wilson 247*2154be65SJarod Wilson static void redrat3_dump_signal_header(struct redrat3_signal_header *header) 248*2154be65SJarod Wilson { 249*2154be65SJarod Wilson pr_info("%s:\n", __func__); 250*2154be65SJarod Wilson pr_info(" * length: %u, transfer_type: 0x%02x\n", 251*2154be65SJarod Wilson header->length, header->transfer_type); 252*2154be65SJarod Wilson pr_info(" * pause: %u, freq_count: %u, no_periods: %u\n", 253*2154be65SJarod Wilson header->pause, header->mod_freq_count, header->no_periods); 254*2154be65SJarod Wilson pr_info(" * lengths: %u (max: %u)\n", 255*2154be65SJarod Wilson header->no_lengths, header->max_lengths); 256*2154be65SJarod Wilson pr_info(" * sig_size: %u (max: %u)\n", 257*2154be65SJarod Wilson header->sig_size, header->max_sig_size); 258*2154be65SJarod Wilson pr_info(" * repeats: %u\n", header->no_repeats); 259*2154be65SJarod Wilson } 260*2154be65SJarod Wilson 261*2154be65SJarod Wilson static void redrat3_dump_signal_data(char *buffer, u16 len) 262*2154be65SJarod Wilson { 263*2154be65SJarod Wilson int offset, i; 264*2154be65SJarod Wilson char *data_vals; 265*2154be65SJarod Wilson 266*2154be65SJarod Wilson pr_info("%s:", __func__); 267*2154be65SJarod Wilson 268*2154be65SJarod Wilson offset = RR3_TX_HEADER_OFFSET + RR3_HEADER_LENGTH 269*2154be65SJarod Wilson + (RR3_DRIVER_MAXLENS * sizeof(u16)); 270*2154be65SJarod Wilson 271*2154be65SJarod Wilson /* read RR3_DRIVER_MAXLENS from ctrl msg */ 272*2154be65SJarod Wilson data_vals = buffer + offset; 273*2154be65SJarod Wilson 274*2154be65SJarod Wilson for (i = 0; i < len; i++) { 275*2154be65SJarod Wilson if (i % 10 == 0) 276*2154be65SJarod Wilson pr_cont("\n * "); 277*2154be65SJarod Wilson pr_cont("%02x ", *data_vals++); 278*2154be65SJarod Wilson } 279*2154be65SJarod Wilson 280*2154be65SJarod Wilson pr_cont("\n"); 281*2154be65SJarod Wilson } 282*2154be65SJarod Wilson 283*2154be65SJarod Wilson /* 284*2154be65SJarod Wilson * redrat3_issue_async 285*2154be65SJarod Wilson * 286*2154be65SJarod Wilson * Issues an async read to the ir data in port.. 287*2154be65SJarod Wilson * sets the callback to be redrat3_handle_async 288*2154be65SJarod Wilson */ 289*2154be65SJarod Wilson static void redrat3_issue_async(struct redrat3_dev *rr3) 290*2154be65SJarod Wilson { 291*2154be65SJarod Wilson int res; 292*2154be65SJarod Wilson 293*2154be65SJarod Wilson rr3_ftr(rr3->dev, "Entering %s\n", __func__); 294*2154be65SJarod Wilson 295*2154be65SJarod Wilson if (!rr3->det_enabled) { 296*2154be65SJarod Wilson dev_warn(rr3->dev, "not issuing async read, " 297*2154be65SJarod Wilson "detector not enabled\n"); 298*2154be65SJarod Wilson return; 299*2154be65SJarod Wilson } 300*2154be65SJarod Wilson 301*2154be65SJarod Wilson memset(rr3->bulk_in_buf, 0, rr3->ep_in->wMaxPacketSize); 302*2154be65SJarod Wilson res = usb_submit_urb(rr3->read_urb, GFP_ATOMIC); 303*2154be65SJarod Wilson if (res) 304*2154be65SJarod Wilson rr3_dbg(rr3->dev, "%s: receive request FAILED! " 305*2154be65SJarod Wilson "(res %d, len %d)\n", __func__, res, 306*2154be65SJarod Wilson rr3->read_urb->transfer_buffer_length); 307*2154be65SJarod Wilson } 308*2154be65SJarod Wilson 309*2154be65SJarod Wilson static void redrat3_dump_fw_error(struct redrat3_dev *rr3, int code) 310*2154be65SJarod Wilson { 311*2154be65SJarod Wilson if (!rr3->transmitting && (code != 0x40)) 312*2154be65SJarod Wilson dev_info(rr3->dev, "fw error code 0x%02x: ", code); 313*2154be65SJarod Wilson 314*2154be65SJarod Wilson switch (code) { 315*2154be65SJarod Wilson case 0x00: 316*2154be65SJarod Wilson pr_cont("No Error\n"); 317*2154be65SJarod Wilson break; 318*2154be65SJarod Wilson 319*2154be65SJarod Wilson /* Codes 0x20 through 0x2f are IR Firmware Errors */ 320*2154be65SJarod Wilson case 0x20: 321*2154be65SJarod Wilson pr_cont("Initial signal pulse not long enough " 322*2154be65SJarod Wilson "to measure carrier frequency\n"); 323*2154be65SJarod Wilson break; 324*2154be65SJarod Wilson case 0x21: 325*2154be65SJarod Wilson pr_cont("Not enough length values allocated for signal\n"); 326*2154be65SJarod Wilson break; 327*2154be65SJarod Wilson case 0x22: 328*2154be65SJarod Wilson pr_cont("Not enough memory allocated for signal data\n"); 329*2154be65SJarod Wilson break; 330*2154be65SJarod Wilson case 0x23: 331*2154be65SJarod Wilson pr_cont("Too many signal repeats\n"); 332*2154be65SJarod Wilson break; 333*2154be65SJarod Wilson case 0x28: 334*2154be65SJarod Wilson pr_cont("Insufficient memory available for IR signal " 335*2154be65SJarod Wilson "data memory allocation\n"); 336*2154be65SJarod Wilson break; 337*2154be65SJarod Wilson case 0x29: 338*2154be65SJarod Wilson pr_cont("Insufficient memory available " 339*2154be65SJarod Wilson "for IrDa signal data memory allocation\n"); 340*2154be65SJarod Wilson break; 341*2154be65SJarod Wilson 342*2154be65SJarod Wilson /* Codes 0x30 through 0x3f are USB Firmware Errors */ 343*2154be65SJarod Wilson case 0x30: 344*2154be65SJarod Wilson pr_cont("Insufficient memory available for bulk " 345*2154be65SJarod Wilson "transfer structure\n"); 346*2154be65SJarod Wilson break; 347*2154be65SJarod Wilson 348*2154be65SJarod Wilson /* 349*2154be65SJarod Wilson * Other error codes... These are primarily errors that can occur in 350*2154be65SJarod Wilson * the control messages sent to the redrat 351*2154be65SJarod Wilson */ 352*2154be65SJarod Wilson case 0x40: 353*2154be65SJarod Wilson if (!rr3->transmitting) 354*2154be65SJarod Wilson pr_cont("Signal capture has been terminated\n"); 355*2154be65SJarod Wilson break; 356*2154be65SJarod Wilson case 0x41: 357*2154be65SJarod Wilson pr_cont("Attempt to set/get and unknown signal I/O " 358*2154be65SJarod Wilson "algorithm parameter\n"); 359*2154be65SJarod Wilson break; 360*2154be65SJarod Wilson case 0x42: 361*2154be65SJarod Wilson pr_cont("Signal capture already started\n"); 362*2154be65SJarod Wilson break; 363*2154be65SJarod Wilson 364*2154be65SJarod Wilson default: 365*2154be65SJarod Wilson pr_cont("Unknown Error\n"); 366*2154be65SJarod Wilson break; 367*2154be65SJarod Wilson } 368*2154be65SJarod Wilson } 369*2154be65SJarod Wilson 370*2154be65SJarod Wilson static u32 redrat3_val_to_mod_freq(struct redrat3_signal_header *ph) 371*2154be65SJarod Wilson { 372*2154be65SJarod Wilson u32 mod_freq = 0; 373*2154be65SJarod Wilson 374*2154be65SJarod Wilson if (ph->mod_freq_count != 0) 375*2154be65SJarod Wilson mod_freq = (RR3_CLK * ph->no_periods) / 376*2154be65SJarod Wilson (ph->mod_freq_count * RR3_CLK_PER_COUNT); 377*2154be65SJarod Wilson 378*2154be65SJarod Wilson return mod_freq; 379*2154be65SJarod Wilson } 380*2154be65SJarod Wilson 381*2154be65SJarod Wilson /* this function scales down the figures for the same result... */ 382*2154be65SJarod Wilson static u32 redrat3_len_to_us(u32 length) 383*2154be65SJarod Wilson { 384*2154be65SJarod Wilson u32 biglen = length * 1000; 385*2154be65SJarod Wilson u32 divisor = (RR3_CLK_CONV_FACTOR) / 1000; 386*2154be65SJarod Wilson u32 result = (u32) (biglen / divisor); 387*2154be65SJarod Wilson 388*2154be65SJarod Wilson /* don't allow zero lengths to go back, breaks lirc */ 389*2154be65SJarod Wilson return result ? result : 1; 390*2154be65SJarod Wilson } 391*2154be65SJarod Wilson 392*2154be65SJarod Wilson /* 393*2154be65SJarod Wilson * convert us back into redrat3 lengths 394*2154be65SJarod Wilson * 395*2154be65SJarod Wilson * length * 1000 length * 1000000 396*2154be65SJarod Wilson * ------------- = ---------------- = micro 397*2154be65SJarod Wilson * rr3clk / 1000 rr3clk 398*2154be65SJarod Wilson 399*2154be65SJarod Wilson * 6 * 2 4 * 3 micro * rr3clk micro * rr3clk / 1000 400*2154be65SJarod Wilson * ----- = 4 ----- = 6 -------------- = len --------------------- 401*2154be65SJarod Wilson * 3 2 1000000 1000 402*2154be65SJarod Wilson */ 403*2154be65SJarod Wilson static u32 redrat3_us_to_len(u32 microsec) 404*2154be65SJarod Wilson { 405*2154be65SJarod Wilson u32 result; 406*2154be65SJarod Wilson u32 divisor; 407*2154be65SJarod Wilson 408*2154be65SJarod Wilson microsec &= IR_MAX_DURATION; 409*2154be65SJarod Wilson divisor = (RR3_CLK_CONV_FACTOR / 1000); 410*2154be65SJarod Wilson result = (u32)(microsec * divisor) / 1000; 411*2154be65SJarod Wilson 412*2154be65SJarod Wilson /* don't allow zero lengths to go back, breaks lirc */ 413*2154be65SJarod Wilson return result ? result : 1; 414*2154be65SJarod Wilson 415*2154be65SJarod Wilson } 416*2154be65SJarod Wilson 417*2154be65SJarod Wilson /* timer callback to send long trailing space on receive timeout */ 418*2154be65SJarod Wilson static void redrat3_rx_timeout(unsigned long data) 419*2154be65SJarod Wilson { 420*2154be65SJarod Wilson struct redrat3_dev *rr3 = (struct redrat3_dev *)data; 421*2154be65SJarod Wilson DEFINE_IR_RAW_EVENT(rawir); 422*2154be65SJarod Wilson 423*2154be65SJarod Wilson rawir.pulse = false; 424*2154be65SJarod Wilson rawir.duration = rr3->rc->timeout; 425*2154be65SJarod Wilson rr3_dbg(rr3->dev, "storing trailing space with duration %d\n", 426*2154be65SJarod Wilson rawir.duration); 427*2154be65SJarod Wilson ir_raw_event_store_with_filter(rr3->rc, &rawir); 428*2154be65SJarod Wilson 429*2154be65SJarod Wilson rr3_dbg(rr3->dev, "calling ir_raw_event_handle\n"); 430*2154be65SJarod Wilson ir_raw_event_handle(rr3->rc); 431*2154be65SJarod Wilson 432*2154be65SJarod Wilson rr3_dbg(rr3->dev, "calling ir_raw_event_reset\n"); 433*2154be65SJarod Wilson ir_raw_event_reset(rr3->rc); 434*2154be65SJarod Wilson } 435*2154be65SJarod Wilson 436*2154be65SJarod Wilson static void redrat3_process_ir_data(struct redrat3_dev *rr3) 437*2154be65SJarod Wilson { 438*2154be65SJarod Wilson DEFINE_IR_RAW_EVENT(rawir); 439*2154be65SJarod Wilson struct redrat3_signal_header header; 440*2154be65SJarod Wilson struct device *dev; 441*2154be65SJarod Wilson int i; 442*2154be65SJarod Wilson unsigned long delay; 443*2154be65SJarod Wilson u32 mod_freq, single_len; 444*2154be65SJarod Wilson u16 *len_vals; 445*2154be65SJarod Wilson u8 *data_vals; 446*2154be65SJarod Wilson u32 tmp32; 447*2154be65SJarod Wilson u16 tmp16; 448*2154be65SJarod Wilson char *sig_data; 449*2154be65SJarod Wilson 450*2154be65SJarod Wilson if (!rr3) { 451*2154be65SJarod Wilson pr_err("%s called with no context!\n", __func__); 452*2154be65SJarod Wilson return; 453*2154be65SJarod Wilson } 454*2154be65SJarod Wilson 455*2154be65SJarod Wilson rr3_ftr(rr3->dev, "Entered %s\n", __func__); 456*2154be65SJarod Wilson 457*2154be65SJarod Wilson dev = rr3->dev; 458*2154be65SJarod Wilson sig_data = rr3->pbuf; 459*2154be65SJarod Wilson 460*2154be65SJarod Wilson header.length = rr3->pktlen; 461*2154be65SJarod Wilson header.transfer_type = rr3->pkttype; 462*2154be65SJarod Wilson 463*2154be65SJarod Wilson /* Sanity check */ 464*2154be65SJarod Wilson if (!(header.length >= RR3_HEADER_LENGTH)) 465*2154be65SJarod Wilson dev_warn(dev, "read returned less than rr3 header len\n"); 466*2154be65SJarod Wilson 467*2154be65SJarod Wilson delay = usecs_to_jiffies(rr3->rc->timeout / 1000); 468*2154be65SJarod Wilson mod_timer(&rr3->rx_timeout, jiffies + delay); 469*2154be65SJarod Wilson 470*2154be65SJarod Wilson memcpy(&tmp32, sig_data + RR3_PAUSE_OFFSET, sizeof(tmp32)); 471*2154be65SJarod Wilson header.pause = be32_to_cpu(tmp32); 472*2154be65SJarod Wilson 473*2154be65SJarod Wilson memcpy(&tmp16, sig_data + RR3_FREQ_COUNT_OFFSET, sizeof(tmp16)); 474*2154be65SJarod Wilson header.mod_freq_count = be16_to_cpu(tmp16); 475*2154be65SJarod Wilson 476*2154be65SJarod Wilson memcpy(&tmp16, sig_data + RR3_NUM_PERIOD_OFFSET, sizeof(tmp16)); 477*2154be65SJarod Wilson header.no_periods = be16_to_cpu(tmp16); 478*2154be65SJarod Wilson 479*2154be65SJarod Wilson header.max_lengths = sig_data[RR3_MAX_LENGTHS_OFFSET]; 480*2154be65SJarod Wilson header.no_lengths = sig_data[RR3_NUM_LENGTHS_OFFSET]; 481*2154be65SJarod Wilson 482*2154be65SJarod Wilson memcpy(&tmp16, sig_data + RR3_MAX_SIGS_OFFSET, sizeof(tmp16)); 483*2154be65SJarod Wilson header.max_sig_size = be16_to_cpu(tmp16); 484*2154be65SJarod Wilson 485*2154be65SJarod Wilson memcpy(&tmp16, sig_data + RR3_NUM_SIGS_OFFSET, sizeof(tmp16)); 486*2154be65SJarod Wilson header.sig_size = be16_to_cpu(tmp16); 487*2154be65SJarod Wilson 488*2154be65SJarod Wilson header.no_repeats= sig_data[RR3_REPEATS_OFFSET]; 489*2154be65SJarod Wilson 490*2154be65SJarod Wilson if (debug) { 491*2154be65SJarod Wilson redrat3_dump_signal_header(&header); 492*2154be65SJarod Wilson redrat3_dump_signal_data(sig_data, header.sig_size); 493*2154be65SJarod Wilson } 494*2154be65SJarod Wilson 495*2154be65SJarod Wilson mod_freq = redrat3_val_to_mod_freq(&header); 496*2154be65SJarod Wilson rr3_dbg(dev, "Got mod_freq of %u\n", mod_freq); 497*2154be65SJarod Wilson 498*2154be65SJarod Wilson /* Here we pull out the 'length' values from the signal */ 499*2154be65SJarod Wilson len_vals = (u16 *)(sig_data + RR3_HEADER_LENGTH); 500*2154be65SJarod Wilson 501*2154be65SJarod Wilson data_vals = sig_data + RR3_HEADER_LENGTH + 502*2154be65SJarod Wilson (header.max_lengths * sizeof(u16)); 503*2154be65SJarod Wilson 504*2154be65SJarod Wilson /* process each rr3 encoded byte into an int */ 505*2154be65SJarod Wilson for (i = 0; i < header.sig_size; i++) { 506*2154be65SJarod Wilson u16 val = len_vals[data_vals[i]]; 507*2154be65SJarod Wilson single_len = redrat3_len_to_us((u32)be16_to_cpu(val)); 508*2154be65SJarod Wilson 509*2154be65SJarod Wilson /* cap the value to IR_MAX_DURATION */ 510*2154be65SJarod Wilson single_len &= IR_MAX_DURATION; 511*2154be65SJarod Wilson 512*2154be65SJarod Wilson /* we should always get pulse/space/pulse/space samples */ 513*2154be65SJarod Wilson if (i % 2) 514*2154be65SJarod Wilson rawir.pulse = false; 515*2154be65SJarod Wilson else 516*2154be65SJarod Wilson rawir.pulse = true; 517*2154be65SJarod Wilson 518*2154be65SJarod Wilson rawir.duration = US_TO_NS(single_len); 519*2154be65SJarod Wilson rr3_dbg(dev, "storing %s with duration %d (i: %d)\n", 520*2154be65SJarod Wilson rawir.pulse ? "pulse" : "space", rawir.duration, i); 521*2154be65SJarod Wilson ir_raw_event_store_with_filter(rr3->rc, &rawir); 522*2154be65SJarod Wilson } 523*2154be65SJarod Wilson 524*2154be65SJarod Wilson /* add a trailing space, if need be */ 525*2154be65SJarod Wilson if (i % 2) { 526*2154be65SJarod Wilson rawir.pulse = false; 527*2154be65SJarod Wilson /* this duration is made up, and may not be ideal... */ 528*2154be65SJarod Wilson rawir.duration = rr3->rc->timeout / 2; 529*2154be65SJarod Wilson rr3_dbg(dev, "storing trailing space with duration %d\n", 530*2154be65SJarod Wilson rawir.duration); 531*2154be65SJarod Wilson ir_raw_event_store_with_filter(rr3->rc, &rawir); 532*2154be65SJarod Wilson } 533*2154be65SJarod Wilson 534*2154be65SJarod Wilson rr3_dbg(dev, "calling ir_raw_event_handle\n"); 535*2154be65SJarod Wilson ir_raw_event_handle(rr3->rc); 536*2154be65SJarod Wilson 537*2154be65SJarod Wilson return; 538*2154be65SJarod Wilson } 539*2154be65SJarod Wilson 540*2154be65SJarod Wilson /* Util fn to send rr3 cmds */ 541*2154be65SJarod Wilson static u8 redrat3_send_cmd(int cmd, struct redrat3_dev *rr3) 542*2154be65SJarod Wilson { 543*2154be65SJarod Wilson struct usb_device *udev; 544*2154be65SJarod Wilson u8 *data; 545*2154be65SJarod Wilson int res; 546*2154be65SJarod Wilson 547*2154be65SJarod Wilson data = kzalloc(sizeof(u8), GFP_KERNEL); 548*2154be65SJarod Wilson if (!data) 549*2154be65SJarod Wilson return -ENOMEM; 550*2154be65SJarod Wilson 551*2154be65SJarod Wilson udev = rr3->udev; 552*2154be65SJarod Wilson res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), cmd, 553*2154be65SJarod Wilson USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 554*2154be65SJarod Wilson 0x0000, 0x0000, data, sizeof(u8), HZ * 10); 555*2154be65SJarod Wilson 556*2154be65SJarod Wilson if (res < 0) { 557*2154be65SJarod Wilson dev_err(rr3->dev, "%s: Error sending rr3 cmd res %d, data %d", 558*2154be65SJarod Wilson __func__, res, *data); 559*2154be65SJarod Wilson res = -EIO; 560*2154be65SJarod Wilson } else 561*2154be65SJarod Wilson res = (u8)data[0]; 562*2154be65SJarod Wilson 563*2154be65SJarod Wilson kfree(data); 564*2154be65SJarod Wilson 565*2154be65SJarod Wilson return res; 566*2154be65SJarod Wilson } 567*2154be65SJarod Wilson 568*2154be65SJarod Wilson /* Enables the long range detector and starts async receive */ 569*2154be65SJarod Wilson static int redrat3_enable_detector(struct redrat3_dev *rr3) 570*2154be65SJarod Wilson { 571*2154be65SJarod Wilson struct device *dev = rr3->dev; 572*2154be65SJarod Wilson u8 ret; 573*2154be65SJarod Wilson 574*2154be65SJarod Wilson rr3_ftr(dev, "Entering %s\n", __func__); 575*2154be65SJarod Wilson 576*2154be65SJarod Wilson ret = redrat3_send_cmd(RR3_RC_DET_ENABLE, rr3); 577*2154be65SJarod Wilson if (ret != 0) 578*2154be65SJarod Wilson dev_dbg(dev, "%s: unexpected ret of %d\n", 579*2154be65SJarod Wilson __func__, ret); 580*2154be65SJarod Wilson 581*2154be65SJarod Wilson ret = redrat3_send_cmd(RR3_RC_DET_STATUS, rr3); 582*2154be65SJarod Wilson if (ret != 1) { 583*2154be65SJarod Wilson dev_err(dev, "%s: detector status: %d, should be 1\n", 584*2154be65SJarod Wilson __func__, ret); 585*2154be65SJarod Wilson return -EIO; 586*2154be65SJarod Wilson } 587*2154be65SJarod Wilson 588*2154be65SJarod Wilson rr3->det_enabled = true; 589*2154be65SJarod Wilson redrat3_issue_async(rr3); 590*2154be65SJarod Wilson 591*2154be65SJarod Wilson return 0; 592*2154be65SJarod Wilson } 593*2154be65SJarod Wilson 594*2154be65SJarod Wilson /* Disables the rr3 long range detector */ 595*2154be65SJarod Wilson static void redrat3_disable_detector(struct redrat3_dev *rr3) 596*2154be65SJarod Wilson { 597*2154be65SJarod Wilson struct device *dev = rr3->dev; 598*2154be65SJarod Wilson u8 ret; 599*2154be65SJarod Wilson 600*2154be65SJarod Wilson rr3_ftr(dev, "Entering %s\n", __func__); 601*2154be65SJarod Wilson 602*2154be65SJarod Wilson ret = redrat3_send_cmd(RR3_RC_DET_DISABLE, rr3); 603*2154be65SJarod Wilson if (ret != 0) 604*2154be65SJarod Wilson dev_err(dev, "%s: failure!\n", __func__); 605*2154be65SJarod Wilson 606*2154be65SJarod Wilson ret = redrat3_send_cmd(RR3_RC_DET_STATUS, rr3); 607*2154be65SJarod Wilson if (ret != 0) 608*2154be65SJarod Wilson dev_warn(dev, "%s: detector status: %d, should be 0\n", 609*2154be65SJarod Wilson __func__, ret); 610*2154be65SJarod Wilson 611*2154be65SJarod Wilson rr3->det_enabled = false; 612*2154be65SJarod Wilson } 613*2154be65SJarod Wilson 614*2154be65SJarod Wilson static inline void redrat3_delete(struct redrat3_dev *rr3, 615*2154be65SJarod Wilson struct usb_device *udev) 616*2154be65SJarod Wilson { 617*2154be65SJarod Wilson rr3_ftr(rr3->dev, "%s cleaning up\n", __func__); 618*2154be65SJarod Wilson usb_kill_urb(rr3->read_urb); 619*2154be65SJarod Wilson usb_kill_urb(rr3->write_urb); 620*2154be65SJarod Wilson 621*2154be65SJarod Wilson usb_free_urb(rr3->read_urb); 622*2154be65SJarod Wilson usb_free_urb(rr3->write_urb); 623*2154be65SJarod Wilson 624*2154be65SJarod Wilson usb_free_coherent(udev, rr3->ep_in->wMaxPacketSize, 625*2154be65SJarod Wilson rr3->bulk_in_buf, rr3->dma_in); 626*2154be65SJarod Wilson usb_free_coherent(udev, rr3->ep_out->wMaxPacketSize, 627*2154be65SJarod Wilson rr3->bulk_out_buf, rr3->dma_out); 628*2154be65SJarod Wilson 629*2154be65SJarod Wilson kfree(rr3); 630*2154be65SJarod Wilson } 631*2154be65SJarod Wilson 632*2154be65SJarod Wilson static u32 redrat3_get_timeout(struct device *dev, 633*2154be65SJarod Wilson struct rc_dev *rc, struct usb_device *udev) 634*2154be65SJarod Wilson { 635*2154be65SJarod Wilson u32 *tmp; 636*2154be65SJarod Wilson u32 timeout = MS_TO_NS(150); /* a sane default, if things go haywire */ 637*2154be65SJarod Wilson int len, ret, pipe; 638*2154be65SJarod Wilson 639*2154be65SJarod Wilson len = sizeof(*tmp); 640*2154be65SJarod Wilson tmp = kzalloc(len, GFP_KERNEL); 641*2154be65SJarod Wilson if (!tmp) { 642*2154be65SJarod Wilson dev_warn(dev, "Memory allocation faillure\n"); 643*2154be65SJarod Wilson return timeout; 644*2154be65SJarod Wilson } 645*2154be65SJarod Wilson 646*2154be65SJarod Wilson pipe = usb_rcvctrlpipe(udev, 0); 647*2154be65SJarod Wilson ret = usb_control_msg(udev, pipe, RR3_GET_IR_PARAM, 648*2154be65SJarod Wilson USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 649*2154be65SJarod Wilson RR3_IR_IO_SIG_TIMEOUT, 0, tmp, len, HZ * 5); 650*2154be65SJarod Wilson if (ret != len) { 651*2154be65SJarod Wilson dev_warn(dev, "Failed to read timeout from hardware\n"); 652*2154be65SJarod Wilson return timeout; 653*2154be65SJarod Wilson } 654*2154be65SJarod Wilson 655*2154be65SJarod Wilson timeout = US_TO_NS(redrat3_len_to_us(be32_to_cpu(*tmp))); 656*2154be65SJarod Wilson if (timeout < rc->min_timeout) 657*2154be65SJarod Wilson timeout = rc->min_timeout; 658*2154be65SJarod Wilson else if (timeout > rc->max_timeout) 659*2154be65SJarod Wilson timeout = rc->max_timeout; 660*2154be65SJarod Wilson 661*2154be65SJarod Wilson rr3_dbg(dev, "Got timeout of %d ms\n", timeout / (1000 * 1000)); 662*2154be65SJarod Wilson return timeout; 663*2154be65SJarod Wilson } 664*2154be65SJarod Wilson 665*2154be65SJarod Wilson static void redrat3_reset(struct redrat3_dev *rr3) 666*2154be65SJarod Wilson { 667*2154be65SJarod Wilson struct usb_device *udev = rr3->udev; 668*2154be65SJarod Wilson struct device *dev = rr3->dev; 669*2154be65SJarod Wilson int rc, rxpipe, txpipe; 670*2154be65SJarod Wilson u8 *val; 671*2154be65SJarod Wilson int len = sizeof(u8); 672*2154be65SJarod Wilson 673*2154be65SJarod Wilson rr3_ftr(dev, "Entering %s\n", __func__); 674*2154be65SJarod Wilson 675*2154be65SJarod Wilson rxpipe = usb_rcvctrlpipe(udev, 0); 676*2154be65SJarod Wilson txpipe = usb_sndctrlpipe(udev, 0); 677*2154be65SJarod Wilson 678*2154be65SJarod Wilson val = kzalloc(len, GFP_KERNEL); 679*2154be65SJarod Wilson if (!val) { 680*2154be65SJarod Wilson dev_err(dev, "Memory allocation failure\n"); 681*2154be65SJarod Wilson return; 682*2154be65SJarod Wilson } 683*2154be65SJarod Wilson 684*2154be65SJarod Wilson *val = 0x01; 685*2154be65SJarod Wilson rc = usb_control_msg(udev, rxpipe, RR3_RESET, 686*2154be65SJarod Wilson USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 687*2154be65SJarod Wilson RR3_CPUCS_REG_ADDR, 0, val, len, HZ * 25); 688*2154be65SJarod Wilson rr3_dbg(dev, "reset returned 0x%02x\n", rc); 689*2154be65SJarod Wilson 690*2154be65SJarod Wilson *val = 5; 691*2154be65SJarod Wilson rc = usb_control_msg(udev, txpipe, RR3_SET_IR_PARAM, 692*2154be65SJarod Wilson USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, 693*2154be65SJarod Wilson RR3_IR_IO_LENGTH_FUZZ, 0, val, len, HZ * 25); 694*2154be65SJarod Wilson rr3_dbg(dev, "set ir parm len fuzz %d rc 0x%02x\n", *val, rc); 695*2154be65SJarod Wilson 696*2154be65SJarod Wilson *val = RR3_DRIVER_MAXLENS; 697*2154be65SJarod Wilson rc = usb_control_msg(udev, txpipe, RR3_SET_IR_PARAM, 698*2154be65SJarod Wilson USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, 699*2154be65SJarod Wilson RR3_IR_IO_MAX_LENGTHS, 0, val, len, HZ * 25); 700*2154be65SJarod Wilson rr3_dbg(dev, "set ir parm max lens %d rc 0x%02x\n", *val, rc); 701*2154be65SJarod Wilson 702*2154be65SJarod Wilson kfree(val); 703*2154be65SJarod Wilson } 704*2154be65SJarod Wilson 705*2154be65SJarod Wilson static void redrat3_get_firmware_rev(struct redrat3_dev *rr3) 706*2154be65SJarod Wilson { 707*2154be65SJarod Wilson int rc = 0; 708*2154be65SJarod Wilson char *buffer; 709*2154be65SJarod Wilson 710*2154be65SJarod Wilson rr3_ftr(rr3->dev, "Entering %s\n", __func__); 711*2154be65SJarod Wilson 712*2154be65SJarod Wilson buffer = kzalloc(sizeof(char) * (RR3_FW_VERSION_LEN + 1), GFP_KERNEL); 713*2154be65SJarod Wilson if (!buffer) { 714*2154be65SJarod Wilson dev_err(rr3->dev, "Memory allocation failure\n"); 715*2154be65SJarod Wilson return; 716*2154be65SJarod Wilson } 717*2154be65SJarod Wilson 718*2154be65SJarod Wilson rc = usb_control_msg(rr3->udev, usb_rcvctrlpipe(rr3->udev, 0), 719*2154be65SJarod Wilson RR3_FW_VERSION, 720*2154be65SJarod Wilson USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 721*2154be65SJarod Wilson 0, 0, buffer, RR3_FW_VERSION_LEN, HZ * 5); 722*2154be65SJarod Wilson 723*2154be65SJarod Wilson if (rc >= 0) 724*2154be65SJarod Wilson dev_info(rr3->dev, "Firmware rev: %s", buffer); 725*2154be65SJarod Wilson else 726*2154be65SJarod Wilson dev_err(rr3->dev, "Problem fetching firmware ID\n"); 727*2154be65SJarod Wilson 728*2154be65SJarod Wilson kfree(buffer); 729*2154be65SJarod Wilson rr3_ftr(rr3->dev, "Exiting %s\n", __func__); 730*2154be65SJarod Wilson } 731*2154be65SJarod Wilson 732*2154be65SJarod Wilson static void redrat3_read_packet_start(struct redrat3_dev *rr3, int len) 733*2154be65SJarod Wilson { 734*2154be65SJarod Wilson u16 tx_error; 735*2154be65SJarod Wilson u16 hdrlen; 736*2154be65SJarod Wilson 737*2154be65SJarod Wilson rr3_ftr(rr3->dev, "Entering %s\n", __func__); 738*2154be65SJarod Wilson 739*2154be65SJarod Wilson /* grab the Length and type of transfer */ 740*2154be65SJarod Wilson memcpy(&(rr3->pktlen), (unsigned char *) rr3->bulk_in_buf, 741*2154be65SJarod Wilson sizeof(rr3->pktlen)); 742*2154be65SJarod Wilson memcpy(&(rr3->pkttype), ((unsigned char *) rr3->bulk_in_buf + 743*2154be65SJarod Wilson sizeof(rr3->pktlen)), 744*2154be65SJarod Wilson sizeof(rr3->pkttype)); 745*2154be65SJarod Wilson 746*2154be65SJarod Wilson /*data needs conversion to know what its real values are*/ 747*2154be65SJarod Wilson rr3->pktlen = be16_to_cpu(rr3->pktlen); 748*2154be65SJarod Wilson rr3->pkttype = be16_to_cpu(rr3->pkttype); 749*2154be65SJarod Wilson 750*2154be65SJarod Wilson switch (rr3->pkttype) { 751*2154be65SJarod Wilson case RR3_ERROR: 752*2154be65SJarod Wilson memcpy(&tx_error, ((unsigned char *)rr3->bulk_in_buf 753*2154be65SJarod Wilson + (sizeof(rr3->pktlen) + sizeof(rr3->pkttype))), 754*2154be65SJarod Wilson sizeof(tx_error)); 755*2154be65SJarod Wilson tx_error = be16_to_cpu(tx_error); 756*2154be65SJarod Wilson redrat3_dump_fw_error(rr3, tx_error); 757*2154be65SJarod Wilson break; 758*2154be65SJarod Wilson 759*2154be65SJarod Wilson case RR3_MOD_SIGNAL_IN: 760*2154be65SJarod Wilson hdrlen = sizeof(rr3->pktlen) + sizeof(rr3->pkttype); 761*2154be65SJarod Wilson rr3->bytes_read = len; 762*2154be65SJarod Wilson rr3->bytes_read -= hdrlen; 763*2154be65SJarod Wilson rr3->datap = &(rr3->pbuf[0]); 764*2154be65SJarod Wilson 765*2154be65SJarod Wilson memcpy(rr3->datap, ((unsigned char *)rr3->bulk_in_buf + hdrlen), 766*2154be65SJarod Wilson rr3->bytes_read); 767*2154be65SJarod Wilson rr3->datap += rr3->bytes_read; 768*2154be65SJarod Wilson rr3_dbg(rr3->dev, "bytes_read %d, pktlen %d\n", 769*2154be65SJarod Wilson rr3->bytes_read, rr3->pktlen); 770*2154be65SJarod Wilson break; 771*2154be65SJarod Wilson 772*2154be65SJarod Wilson default: 773*2154be65SJarod Wilson rr3_dbg(rr3->dev, "ignoring packet with type 0x%02x, " 774*2154be65SJarod Wilson "len of %d, 0x%02x\n", rr3->pkttype, len, rr3->pktlen); 775*2154be65SJarod Wilson break; 776*2154be65SJarod Wilson } 777*2154be65SJarod Wilson } 778*2154be65SJarod Wilson 779*2154be65SJarod Wilson static void redrat3_read_packet_continue(struct redrat3_dev *rr3, int len) 780*2154be65SJarod Wilson { 781*2154be65SJarod Wilson 782*2154be65SJarod Wilson rr3_ftr(rr3->dev, "Entering %s\n", __func__); 783*2154be65SJarod Wilson 784*2154be65SJarod Wilson memcpy(rr3->datap, (unsigned char *)rr3->bulk_in_buf, len); 785*2154be65SJarod Wilson rr3->datap += len; 786*2154be65SJarod Wilson 787*2154be65SJarod Wilson rr3->bytes_read += len; 788*2154be65SJarod Wilson rr3_dbg(rr3->dev, "bytes_read %d, pktlen %d\n", 789*2154be65SJarod Wilson rr3->bytes_read, rr3->pktlen); 790*2154be65SJarod Wilson } 791*2154be65SJarod Wilson 792*2154be65SJarod Wilson /* gather IR data from incoming urb, process it when we have enough */ 793*2154be65SJarod Wilson static int redrat3_get_ir_data(struct redrat3_dev *rr3, int len) 794*2154be65SJarod Wilson { 795*2154be65SJarod Wilson struct device *dev = rr3->dev; 796*2154be65SJarod Wilson int ret = 0; 797*2154be65SJarod Wilson 798*2154be65SJarod Wilson rr3_ftr(dev, "Entering %s\n", __func__); 799*2154be65SJarod Wilson 800*2154be65SJarod Wilson if (rr3->pktlen > RR3_MAX_BUF_SIZE) { 801*2154be65SJarod Wilson dev_err(rr3->dev, "error: packet larger than buffer\n"); 802*2154be65SJarod Wilson ret = -EINVAL; 803*2154be65SJarod Wilson goto out; 804*2154be65SJarod Wilson } 805*2154be65SJarod Wilson 806*2154be65SJarod Wilson if ((rr3->bytes_read == 0) && 807*2154be65SJarod Wilson (len >= (sizeof(rr3->pkttype) + sizeof(rr3->pktlen)))) { 808*2154be65SJarod Wilson redrat3_read_packet_start(rr3, len); 809*2154be65SJarod Wilson } else if (rr3->bytes_read != 0) { 810*2154be65SJarod Wilson redrat3_read_packet_continue(rr3, len); 811*2154be65SJarod Wilson } else if (rr3->bytes_read == 0) { 812*2154be65SJarod Wilson dev_err(dev, "error: no packet data read\n"); 813*2154be65SJarod Wilson ret = -ENODATA; 814*2154be65SJarod Wilson goto out; 815*2154be65SJarod Wilson } 816*2154be65SJarod Wilson 817*2154be65SJarod Wilson if (rr3->bytes_read > rr3->pktlen) { 818*2154be65SJarod Wilson dev_err(dev, "bytes_read (%d) greater than pktlen (%d)\n", 819*2154be65SJarod Wilson rr3->bytes_read, rr3->pktlen); 820*2154be65SJarod Wilson ret = -EINVAL; 821*2154be65SJarod Wilson goto out; 822*2154be65SJarod Wilson } else if (rr3->bytes_read < rr3->pktlen) 823*2154be65SJarod Wilson /* we're still accumulating data */ 824*2154be65SJarod Wilson return 0; 825*2154be65SJarod Wilson 826*2154be65SJarod Wilson /* if we get here, we've got IR data to decode */ 827*2154be65SJarod Wilson if (rr3->pkttype == RR3_MOD_SIGNAL_IN) 828*2154be65SJarod Wilson redrat3_process_ir_data(rr3); 829*2154be65SJarod Wilson else 830*2154be65SJarod Wilson rr3_dbg(dev, "discarding non-signal data packet " 831*2154be65SJarod Wilson "(type 0x%02x)\n", rr3->pkttype); 832*2154be65SJarod Wilson 833*2154be65SJarod Wilson out: 834*2154be65SJarod Wilson rr3->bytes_read = 0; 835*2154be65SJarod Wilson rr3->pktlen = 0; 836*2154be65SJarod Wilson rr3->pkttype = 0; 837*2154be65SJarod Wilson return ret; 838*2154be65SJarod Wilson } 839*2154be65SJarod Wilson 840*2154be65SJarod Wilson /* callback function from USB when async USB request has completed */ 841*2154be65SJarod Wilson static void redrat3_handle_async(struct urb *urb, struct pt_regs *regs) 842*2154be65SJarod Wilson { 843*2154be65SJarod Wilson struct redrat3_dev *rr3; 844*2154be65SJarod Wilson 845*2154be65SJarod Wilson if (!urb) 846*2154be65SJarod Wilson return; 847*2154be65SJarod Wilson 848*2154be65SJarod Wilson rr3 = urb->context; 849*2154be65SJarod Wilson if (!rr3) { 850*2154be65SJarod Wilson pr_err("%s called with invalid context!\n", __func__); 851*2154be65SJarod Wilson usb_unlink_urb(urb); 852*2154be65SJarod Wilson return; 853*2154be65SJarod Wilson } 854*2154be65SJarod Wilson 855*2154be65SJarod Wilson rr3_ftr(rr3->dev, "Entering %s\n", __func__); 856*2154be65SJarod Wilson 857*2154be65SJarod Wilson if (!rr3->det_enabled) { 858*2154be65SJarod Wilson rr3_dbg(rr3->dev, "received a read callback but detector " 859*2154be65SJarod Wilson "disabled - ignoring\n"); 860*2154be65SJarod Wilson return; 861*2154be65SJarod Wilson } 862*2154be65SJarod Wilson 863*2154be65SJarod Wilson switch (urb->status) { 864*2154be65SJarod Wilson case 0: 865*2154be65SJarod Wilson redrat3_get_ir_data(rr3, urb->actual_length); 866*2154be65SJarod Wilson break; 867*2154be65SJarod Wilson 868*2154be65SJarod Wilson case -ECONNRESET: 869*2154be65SJarod Wilson case -ENOENT: 870*2154be65SJarod Wilson case -ESHUTDOWN: 871*2154be65SJarod Wilson usb_unlink_urb(urb); 872*2154be65SJarod Wilson return; 873*2154be65SJarod Wilson 874*2154be65SJarod Wilson case -EPIPE: 875*2154be65SJarod Wilson default: 876*2154be65SJarod Wilson dev_warn(rr3->dev, "Error: urb status = %d\n", urb->status); 877*2154be65SJarod Wilson rr3->bytes_read = 0; 878*2154be65SJarod Wilson rr3->pktlen = 0; 879*2154be65SJarod Wilson rr3->pkttype = 0; 880*2154be65SJarod Wilson break; 881*2154be65SJarod Wilson } 882*2154be65SJarod Wilson 883*2154be65SJarod Wilson if (!rr3->transmitting) 884*2154be65SJarod Wilson redrat3_issue_async(rr3); 885*2154be65SJarod Wilson else 886*2154be65SJarod Wilson rr3_dbg(rr3->dev, "IR transmit in progress\n"); 887*2154be65SJarod Wilson } 888*2154be65SJarod Wilson 889*2154be65SJarod Wilson static void redrat3_write_bulk_callback(struct urb *urb, struct pt_regs *regs) 890*2154be65SJarod Wilson { 891*2154be65SJarod Wilson struct redrat3_dev *rr3; 892*2154be65SJarod Wilson int len; 893*2154be65SJarod Wilson 894*2154be65SJarod Wilson if (!urb) 895*2154be65SJarod Wilson return; 896*2154be65SJarod Wilson 897*2154be65SJarod Wilson rr3 = urb->context; 898*2154be65SJarod Wilson if (rr3) { 899*2154be65SJarod Wilson len = urb->actual_length; 900*2154be65SJarod Wilson rr3_ftr(rr3->dev, "%s: called (status=%d len=%d)\n", 901*2154be65SJarod Wilson __func__, urb->status, len); 902*2154be65SJarod Wilson } 903*2154be65SJarod Wilson } 904*2154be65SJarod Wilson 905*2154be65SJarod Wilson static u16 mod_freq_to_val(unsigned int mod_freq) 906*2154be65SJarod Wilson { 907*2154be65SJarod Wilson int mult = 6000000; 908*2154be65SJarod Wilson 909*2154be65SJarod Wilson /* Clk used in mod. freq. generation is CLK24/4. */ 910*2154be65SJarod Wilson return (u16)(65536 - (mult / mod_freq)); 911*2154be65SJarod Wilson } 912*2154be65SJarod Wilson 913*2154be65SJarod Wilson static int redrat3_set_tx_carrier(struct rc_dev *dev, u32 carrier) 914*2154be65SJarod Wilson { 915*2154be65SJarod Wilson struct redrat3_dev *rr3 = dev->priv; 916*2154be65SJarod Wilson 917*2154be65SJarod Wilson rr3->carrier = carrier; 918*2154be65SJarod Wilson 919*2154be65SJarod Wilson return carrier; 920*2154be65SJarod Wilson } 921*2154be65SJarod Wilson 922*2154be65SJarod Wilson static int redrat3_transmit_ir(struct rc_dev *rcdev, int *txbuf, u32 n) 923*2154be65SJarod Wilson { 924*2154be65SJarod Wilson struct redrat3_dev *rr3 = rcdev->priv; 925*2154be65SJarod Wilson struct device *dev = rr3->dev; 926*2154be65SJarod Wilson struct redrat3_signal_header header; 927*2154be65SJarod Wilson int i, j, count, ret, ret_len, offset; 928*2154be65SJarod Wilson int lencheck, cur_sample_len, pipe; 929*2154be65SJarod Wilson char *buffer = NULL, *sigdata = NULL; 930*2154be65SJarod Wilson int *sample_lens = NULL; 931*2154be65SJarod Wilson u32 tmpi; 932*2154be65SJarod Wilson u16 tmps; 933*2154be65SJarod Wilson u8 *datap; 934*2154be65SJarod Wilson u8 curlencheck = 0; 935*2154be65SJarod Wilson u16 *lengths_ptr; 936*2154be65SJarod Wilson int sendbuf_len; 937*2154be65SJarod Wilson 938*2154be65SJarod Wilson rr3_ftr(dev, "Entering %s\n", __func__); 939*2154be65SJarod Wilson 940*2154be65SJarod Wilson if (rr3->transmitting) { 941*2154be65SJarod Wilson dev_warn(dev, "%s: transmitter already in use\n", __func__); 942*2154be65SJarod Wilson return -EAGAIN; 943*2154be65SJarod Wilson } 944*2154be65SJarod Wilson 945*2154be65SJarod Wilson count = n / sizeof(int); 946*2154be65SJarod Wilson if (count > (RR3_DRIVER_MAXLENS * 2)) 947*2154be65SJarod Wilson return -EINVAL; 948*2154be65SJarod Wilson 949*2154be65SJarod Wilson rr3->transmitting = true; 950*2154be65SJarod Wilson 951*2154be65SJarod Wilson redrat3_disable_detector(rr3); 952*2154be65SJarod Wilson 953*2154be65SJarod Wilson if (rr3->det_enabled) { 954*2154be65SJarod Wilson dev_err(dev, "%s: cannot tx while rx is enabled\n", __func__); 955*2154be65SJarod Wilson ret = -EIO; 956*2154be65SJarod Wilson goto out; 957*2154be65SJarod Wilson } 958*2154be65SJarod Wilson 959*2154be65SJarod Wilson sample_lens = kzalloc(sizeof(int) * RR3_DRIVER_MAXLENS, GFP_KERNEL); 960*2154be65SJarod Wilson if (!sample_lens) { 961*2154be65SJarod Wilson ret = -ENOMEM; 962*2154be65SJarod Wilson goto out; 963*2154be65SJarod Wilson } 964*2154be65SJarod Wilson 965*2154be65SJarod Wilson for (i = 0; i < count; i++) { 966*2154be65SJarod Wilson for (lencheck = 0; lencheck < curlencheck; lencheck++) { 967*2154be65SJarod Wilson cur_sample_len = redrat3_us_to_len(txbuf[i]); 968*2154be65SJarod Wilson if (sample_lens[lencheck] == cur_sample_len) 969*2154be65SJarod Wilson break; 970*2154be65SJarod Wilson } 971*2154be65SJarod Wilson if (lencheck == curlencheck) { 972*2154be65SJarod Wilson cur_sample_len = redrat3_us_to_len(txbuf[i]); 973*2154be65SJarod Wilson rr3_dbg(dev, "txbuf[%d]=%u, pos %d, enc %u\n", 974*2154be65SJarod Wilson i, txbuf[i], curlencheck, cur_sample_len); 975*2154be65SJarod Wilson if (curlencheck < 255) { 976*2154be65SJarod Wilson /* now convert the value to a proper 977*2154be65SJarod Wilson * rr3 value.. */ 978*2154be65SJarod Wilson sample_lens[curlencheck] = cur_sample_len; 979*2154be65SJarod Wilson curlencheck++; 980*2154be65SJarod Wilson } else { 981*2154be65SJarod Wilson dev_err(dev, "signal too long\n"); 982*2154be65SJarod Wilson ret = -EINVAL; 983*2154be65SJarod Wilson goto out; 984*2154be65SJarod Wilson } 985*2154be65SJarod Wilson } 986*2154be65SJarod Wilson } 987*2154be65SJarod Wilson 988*2154be65SJarod Wilson sigdata = kzalloc((count + RR3_TX_TRAILER_LEN), GFP_KERNEL); 989*2154be65SJarod Wilson if (!sigdata) { 990*2154be65SJarod Wilson ret = -ENOMEM; 991*2154be65SJarod Wilson goto out; 992*2154be65SJarod Wilson } 993*2154be65SJarod Wilson 994*2154be65SJarod Wilson sigdata[count] = RR3_END_OF_SIGNAL; 995*2154be65SJarod Wilson sigdata[count + 1] = RR3_END_OF_SIGNAL; 996*2154be65SJarod Wilson for (i = 0; i < count; i++) { 997*2154be65SJarod Wilson for (j = 0; j < curlencheck; j++) { 998*2154be65SJarod Wilson if (sample_lens[j] == redrat3_us_to_len(txbuf[i])) 999*2154be65SJarod Wilson sigdata[i] = j; 1000*2154be65SJarod Wilson } 1001*2154be65SJarod Wilson } 1002*2154be65SJarod Wilson 1003*2154be65SJarod Wilson offset = RR3_TX_HEADER_OFFSET; 1004*2154be65SJarod Wilson sendbuf_len = RR3_HEADER_LENGTH + (sizeof(u16) * RR3_DRIVER_MAXLENS) 1005*2154be65SJarod Wilson + count + RR3_TX_TRAILER_LEN + offset; 1006*2154be65SJarod Wilson 1007*2154be65SJarod Wilson buffer = kzalloc(sendbuf_len, GFP_KERNEL); 1008*2154be65SJarod Wilson if (!buffer) { 1009*2154be65SJarod Wilson ret = -ENOMEM; 1010*2154be65SJarod Wilson goto out; 1011*2154be65SJarod Wilson } 1012*2154be65SJarod Wilson 1013*2154be65SJarod Wilson /* fill in our packet header */ 1014*2154be65SJarod Wilson header.length = sendbuf_len - offset; 1015*2154be65SJarod Wilson header.transfer_type = RR3_MOD_SIGNAL_OUT; 1016*2154be65SJarod Wilson header.pause = redrat3_len_to_us(100); 1017*2154be65SJarod Wilson header.mod_freq_count = mod_freq_to_val(rr3->carrier); 1018*2154be65SJarod Wilson header.no_periods = 0; /* n/a to transmit */ 1019*2154be65SJarod Wilson header.max_lengths = RR3_DRIVER_MAXLENS; 1020*2154be65SJarod Wilson header.no_lengths = curlencheck; 1021*2154be65SJarod Wilson header.max_sig_size = RR3_MAX_SIG_SIZE; 1022*2154be65SJarod Wilson header.sig_size = count + RR3_TX_TRAILER_LEN; 1023*2154be65SJarod Wilson /* we currently rely on repeat handling in the IR encoding source */ 1024*2154be65SJarod Wilson header.no_repeats = 0; 1025*2154be65SJarod Wilson 1026*2154be65SJarod Wilson tmps = cpu_to_be16(header.length); 1027*2154be65SJarod Wilson memcpy(buffer, &tmps, 2); 1028*2154be65SJarod Wilson 1029*2154be65SJarod Wilson tmps = cpu_to_be16(header.transfer_type); 1030*2154be65SJarod Wilson memcpy(buffer + 2, &tmps, 2); 1031*2154be65SJarod Wilson 1032*2154be65SJarod Wilson tmpi = cpu_to_be32(header.pause); 1033*2154be65SJarod Wilson memcpy(buffer + offset, &tmpi, sizeof(tmpi)); 1034*2154be65SJarod Wilson 1035*2154be65SJarod Wilson tmps = cpu_to_be16(header.mod_freq_count); 1036*2154be65SJarod Wilson memcpy(buffer + offset + RR3_FREQ_COUNT_OFFSET, &tmps, 2); 1037*2154be65SJarod Wilson 1038*2154be65SJarod Wilson buffer[offset + RR3_NUM_LENGTHS_OFFSET] = header.no_lengths; 1039*2154be65SJarod Wilson 1040*2154be65SJarod Wilson tmps = cpu_to_be16(header.sig_size); 1041*2154be65SJarod Wilson memcpy(buffer + offset + RR3_NUM_SIGS_OFFSET, &tmps, 2); 1042*2154be65SJarod Wilson 1043*2154be65SJarod Wilson buffer[offset + RR3_REPEATS_OFFSET] = header.no_repeats; 1044*2154be65SJarod Wilson 1045*2154be65SJarod Wilson lengths_ptr = (u16 *)(buffer + offset + RR3_HEADER_LENGTH); 1046*2154be65SJarod Wilson for (i = 0; i < curlencheck; ++i) 1047*2154be65SJarod Wilson lengths_ptr[i] = cpu_to_be16(sample_lens[i]); 1048*2154be65SJarod Wilson 1049*2154be65SJarod Wilson datap = (u8 *)(buffer + offset + RR3_HEADER_LENGTH + 1050*2154be65SJarod Wilson (sizeof(u16) * RR3_DRIVER_MAXLENS)); 1051*2154be65SJarod Wilson memcpy(datap, sigdata, (count + RR3_TX_TRAILER_LEN)); 1052*2154be65SJarod Wilson 1053*2154be65SJarod Wilson if (debug) { 1054*2154be65SJarod Wilson redrat3_dump_signal_header(&header); 1055*2154be65SJarod Wilson redrat3_dump_signal_data(buffer, header.sig_size); 1056*2154be65SJarod Wilson } 1057*2154be65SJarod Wilson 1058*2154be65SJarod Wilson pipe = usb_sndbulkpipe(rr3->udev, rr3->ep_out->bEndpointAddress); 1059*2154be65SJarod Wilson tmps = usb_bulk_msg(rr3->udev, pipe, buffer, 1060*2154be65SJarod Wilson sendbuf_len, &ret_len, 10 * HZ); 1061*2154be65SJarod Wilson rr3_dbg(dev, "sent %d bytes, (ret %d)\n", ret_len, tmps); 1062*2154be65SJarod Wilson 1063*2154be65SJarod Wilson /* now tell the hardware to transmit what we sent it */ 1064*2154be65SJarod Wilson pipe = usb_rcvctrlpipe(rr3->udev, 0); 1065*2154be65SJarod Wilson ret = usb_control_msg(rr3->udev, pipe, RR3_TX_SEND_SIGNAL, 1066*2154be65SJarod Wilson USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 1067*2154be65SJarod Wilson 0, 0, buffer, 2, HZ * 10); 1068*2154be65SJarod Wilson 1069*2154be65SJarod Wilson if (ret < 0) 1070*2154be65SJarod Wilson dev_err(dev, "Error: control msg send failed, rc %d\n", ret); 1071*2154be65SJarod Wilson else 1072*2154be65SJarod Wilson ret = n; 1073*2154be65SJarod Wilson 1074*2154be65SJarod Wilson out: 1075*2154be65SJarod Wilson kfree(sample_lens); 1076*2154be65SJarod Wilson kfree(buffer); 1077*2154be65SJarod Wilson kfree(sigdata); 1078*2154be65SJarod Wilson 1079*2154be65SJarod Wilson rr3->transmitting = false; 1080*2154be65SJarod Wilson 1081*2154be65SJarod Wilson redrat3_enable_detector(rr3); 1082*2154be65SJarod Wilson 1083*2154be65SJarod Wilson return ret; 1084*2154be65SJarod Wilson } 1085*2154be65SJarod Wilson 1086*2154be65SJarod Wilson static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3) 1087*2154be65SJarod Wilson { 1088*2154be65SJarod Wilson struct device *dev = rr3->dev; 1089*2154be65SJarod Wilson struct rc_dev *rc; 1090*2154be65SJarod Wilson int ret = -ENODEV; 1091*2154be65SJarod Wilson u16 prod = le16_to_cpu(rr3->udev->descriptor.idProduct); 1092*2154be65SJarod Wilson 1093*2154be65SJarod Wilson rc = rc_allocate_device(); 1094*2154be65SJarod Wilson if (!rc) { 1095*2154be65SJarod Wilson dev_err(dev, "remote input dev allocation failed\n"); 1096*2154be65SJarod Wilson goto out; 1097*2154be65SJarod Wilson } 1098*2154be65SJarod Wilson 1099*2154be65SJarod Wilson snprintf(rr3->name, sizeof(rr3->name), "RedRat3%s " 1100*2154be65SJarod Wilson "Infrared Remote Transceiver (%04x:%04x)", 1101*2154be65SJarod Wilson prod == USB_RR3IIUSB_PRODUCT_ID ? "-II" : "", 1102*2154be65SJarod Wilson le16_to_cpu(rr3->udev->descriptor.idVendor), prod); 1103*2154be65SJarod Wilson 1104*2154be65SJarod Wilson usb_make_path(rr3->udev, rr3->phys, sizeof(rr3->phys)); 1105*2154be65SJarod Wilson 1106*2154be65SJarod Wilson rc->input_name = rr3->name; 1107*2154be65SJarod Wilson rc->input_phys = rr3->phys; 1108*2154be65SJarod Wilson usb_to_input_id(rr3->udev, &rc->input_id); 1109*2154be65SJarod Wilson rc->dev.parent = dev; 1110*2154be65SJarod Wilson rc->priv = rr3; 1111*2154be65SJarod Wilson rc->driver_type = RC_DRIVER_IR_RAW; 1112*2154be65SJarod Wilson rc->allowed_protos = RC_TYPE_ALL; 1113*2154be65SJarod Wilson rc->min_timeout = MS_TO_NS(RR3_RX_MIN_TIMEOUT); 1114*2154be65SJarod Wilson rc->max_timeout = MS_TO_NS(RR3_RX_MAX_TIMEOUT); 1115*2154be65SJarod Wilson rc->timeout = redrat3_get_timeout(dev, rc, rr3->udev); 1116*2154be65SJarod Wilson rc->tx_ir = redrat3_transmit_ir; 1117*2154be65SJarod Wilson rc->s_tx_carrier = redrat3_set_tx_carrier; 1118*2154be65SJarod Wilson rc->driver_name = DRIVER_NAME; 1119*2154be65SJarod Wilson rc->map_name = RC_MAP_HAUPPAUGE; 1120*2154be65SJarod Wilson 1121*2154be65SJarod Wilson ret = rc_register_device(rc); 1122*2154be65SJarod Wilson if (ret < 0) { 1123*2154be65SJarod Wilson dev_err(dev, "remote dev registration failed\n"); 1124*2154be65SJarod Wilson goto out; 1125*2154be65SJarod Wilson } 1126*2154be65SJarod Wilson 1127*2154be65SJarod Wilson return rc; 1128*2154be65SJarod Wilson 1129*2154be65SJarod Wilson out: 1130*2154be65SJarod Wilson rc_free_device(rc); 1131*2154be65SJarod Wilson return NULL; 1132*2154be65SJarod Wilson } 1133*2154be65SJarod Wilson 1134*2154be65SJarod Wilson static int __devinit redrat3_dev_probe(struct usb_interface *intf, 1135*2154be65SJarod Wilson const struct usb_device_id *id) 1136*2154be65SJarod Wilson { 1137*2154be65SJarod Wilson struct usb_device *udev = interface_to_usbdev(intf); 1138*2154be65SJarod Wilson struct device *dev = &intf->dev; 1139*2154be65SJarod Wilson struct usb_host_interface *uhi; 1140*2154be65SJarod Wilson struct redrat3_dev *rr3; 1141*2154be65SJarod Wilson struct usb_endpoint_descriptor *ep; 1142*2154be65SJarod Wilson struct usb_endpoint_descriptor *ep_in = NULL; 1143*2154be65SJarod Wilson struct usb_endpoint_descriptor *ep_out = NULL; 1144*2154be65SJarod Wilson u8 addr, attrs; 1145*2154be65SJarod Wilson int pipe, i; 1146*2154be65SJarod Wilson int retval = -ENOMEM; 1147*2154be65SJarod Wilson 1148*2154be65SJarod Wilson rr3_ftr(dev, "%s called\n", __func__); 1149*2154be65SJarod Wilson 1150*2154be65SJarod Wilson uhi = intf->cur_altsetting; 1151*2154be65SJarod Wilson 1152*2154be65SJarod Wilson /* find our bulk-in and bulk-out endpoints */ 1153*2154be65SJarod Wilson for (i = 0; i < uhi->desc.bNumEndpoints; ++i) { 1154*2154be65SJarod Wilson ep = &uhi->endpoint[i].desc; 1155*2154be65SJarod Wilson addr = ep->bEndpointAddress; 1156*2154be65SJarod Wilson attrs = ep->bmAttributes; 1157*2154be65SJarod Wilson 1158*2154be65SJarod Wilson if ((ep_in == NULL) && 1159*2154be65SJarod Wilson ((addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) && 1160*2154be65SJarod Wilson ((attrs & USB_ENDPOINT_XFERTYPE_MASK) == 1161*2154be65SJarod Wilson USB_ENDPOINT_XFER_BULK)) { 1162*2154be65SJarod Wilson rr3_dbg(dev, "found bulk-in endpoint at 0x%02x\n", 1163*2154be65SJarod Wilson ep->bEndpointAddress); 1164*2154be65SJarod Wilson /* data comes in on 0x82, 0x81 is for other data... */ 1165*2154be65SJarod Wilson if (ep->bEndpointAddress == RR3_BULK_IN_EP_ADDR) 1166*2154be65SJarod Wilson ep_in = ep; 1167*2154be65SJarod Wilson } 1168*2154be65SJarod Wilson 1169*2154be65SJarod Wilson if ((ep_out == NULL) && 1170*2154be65SJarod Wilson ((addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) && 1171*2154be65SJarod Wilson ((attrs & USB_ENDPOINT_XFERTYPE_MASK) == 1172*2154be65SJarod Wilson USB_ENDPOINT_XFER_BULK)) { 1173*2154be65SJarod Wilson rr3_dbg(dev, "found bulk-out endpoint at 0x%02x\n", 1174*2154be65SJarod Wilson ep->bEndpointAddress); 1175*2154be65SJarod Wilson ep_out = ep; 1176*2154be65SJarod Wilson } 1177*2154be65SJarod Wilson } 1178*2154be65SJarod Wilson 1179*2154be65SJarod Wilson if (!ep_in || !ep_out) { 1180*2154be65SJarod Wilson dev_err(dev, "Couldn't find both in and out endpoints\n"); 1181*2154be65SJarod Wilson retval = -ENODEV; 1182*2154be65SJarod Wilson goto no_endpoints; 1183*2154be65SJarod Wilson } 1184*2154be65SJarod Wilson 1185*2154be65SJarod Wilson /* allocate memory for our device state and initialize it */ 1186*2154be65SJarod Wilson rr3 = kzalloc(sizeof(*rr3), GFP_KERNEL); 1187*2154be65SJarod Wilson if (rr3 == NULL) { 1188*2154be65SJarod Wilson dev_err(dev, "Memory allocation failure\n"); 1189*2154be65SJarod Wilson goto error; 1190*2154be65SJarod Wilson } 1191*2154be65SJarod Wilson 1192*2154be65SJarod Wilson rr3->dev = &intf->dev; 1193*2154be65SJarod Wilson 1194*2154be65SJarod Wilson /* set up bulk-in endpoint */ 1195*2154be65SJarod Wilson rr3->read_urb = usb_alloc_urb(0, GFP_KERNEL); 1196*2154be65SJarod Wilson if (!rr3->read_urb) { 1197*2154be65SJarod Wilson dev_err(dev, "Read urb allocation failure\n"); 1198*2154be65SJarod Wilson goto error; 1199*2154be65SJarod Wilson } 1200*2154be65SJarod Wilson 1201*2154be65SJarod Wilson rr3->ep_in = ep_in; 1202*2154be65SJarod Wilson rr3->bulk_in_buf = usb_alloc_coherent(udev, ep_in->wMaxPacketSize, 1203*2154be65SJarod Wilson GFP_ATOMIC, &rr3->dma_in); 1204*2154be65SJarod Wilson if (!rr3->bulk_in_buf) { 1205*2154be65SJarod Wilson dev_err(dev, "Read buffer allocation failure\n"); 1206*2154be65SJarod Wilson goto error; 1207*2154be65SJarod Wilson } 1208*2154be65SJarod Wilson 1209*2154be65SJarod Wilson pipe = usb_rcvbulkpipe(udev, ep_in->bEndpointAddress); 1210*2154be65SJarod Wilson usb_fill_bulk_urb(rr3->read_urb, udev, pipe, 1211*2154be65SJarod Wilson rr3->bulk_in_buf, ep_in->wMaxPacketSize, 1212*2154be65SJarod Wilson (usb_complete_t)redrat3_handle_async, rr3); 1213*2154be65SJarod Wilson 1214*2154be65SJarod Wilson /* set up bulk-out endpoint*/ 1215*2154be65SJarod Wilson rr3->write_urb = usb_alloc_urb(0, GFP_KERNEL); 1216*2154be65SJarod Wilson if (!rr3->write_urb) { 1217*2154be65SJarod Wilson dev_err(dev, "Write urb allocation failure\n"); 1218*2154be65SJarod Wilson goto error; 1219*2154be65SJarod Wilson } 1220*2154be65SJarod Wilson 1221*2154be65SJarod Wilson rr3->ep_out = ep_out; 1222*2154be65SJarod Wilson rr3->bulk_out_buf = usb_alloc_coherent(udev, ep_out->wMaxPacketSize, 1223*2154be65SJarod Wilson GFP_ATOMIC, &rr3->dma_out); 1224*2154be65SJarod Wilson if (!rr3->bulk_out_buf) { 1225*2154be65SJarod Wilson dev_err(dev, "Write buffer allocation failure\n"); 1226*2154be65SJarod Wilson goto error; 1227*2154be65SJarod Wilson } 1228*2154be65SJarod Wilson 1229*2154be65SJarod Wilson pipe = usb_sndbulkpipe(udev, ep_out->bEndpointAddress); 1230*2154be65SJarod Wilson usb_fill_bulk_urb(rr3->write_urb, udev, pipe, 1231*2154be65SJarod Wilson rr3->bulk_out_buf, ep_out->wMaxPacketSize, 1232*2154be65SJarod Wilson (usb_complete_t)redrat3_write_bulk_callback, rr3); 1233*2154be65SJarod Wilson 1234*2154be65SJarod Wilson mutex_init(&rr3->lock); 1235*2154be65SJarod Wilson rr3->udev = udev; 1236*2154be65SJarod Wilson 1237*2154be65SJarod Wilson redrat3_reset(rr3); 1238*2154be65SJarod Wilson redrat3_get_firmware_rev(rr3); 1239*2154be65SJarod Wilson 1240*2154be65SJarod Wilson /* might be all we need to do? */ 1241*2154be65SJarod Wilson retval = redrat3_enable_detector(rr3); 1242*2154be65SJarod Wilson if (retval < 0) 1243*2154be65SJarod Wilson goto error; 1244*2154be65SJarod Wilson 1245*2154be65SJarod Wilson /* default.. will get overridden by any sends with a freq defined */ 1246*2154be65SJarod Wilson rr3->carrier = 38000; 1247*2154be65SJarod Wilson 1248*2154be65SJarod Wilson rr3->rc = redrat3_init_rc_dev(rr3); 1249*2154be65SJarod Wilson if (!rr3->rc) 1250*2154be65SJarod Wilson goto error; 1251*2154be65SJarod Wilson 1252*2154be65SJarod Wilson setup_timer(&rr3->rx_timeout, redrat3_rx_timeout, (unsigned long)rr3); 1253*2154be65SJarod Wilson 1254*2154be65SJarod Wilson /* we can register the device now, as it is ready */ 1255*2154be65SJarod Wilson usb_set_intfdata(intf, rr3); 1256*2154be65SJarod Wilson 1257*2154be65SJarod Wilson rr3_ftr(dev, "Exiting %s\n", __func__); 1258*2154be65SJarod Wilson return 0; 1259*2154be65SJarod Wilson 1260*2154be65SJarod Wilson error: 1261*2154be65SJarod Wilson redrat3_delete(rr3, rr3->udev); 1262*2154be65SJarod Wilson 1263*2154be65SJarod Wilson no_endpoints: 1264*2154be65SJarod Wilson dev_err(dev, "%s: retval = %x", __func__, retval); 1265*2154be65SJarod Wilson 1266*2154be65SJarod Wilson return retval; 1267*2154be65SJarod Wilson } 1268*2154be65SJarod Wilson 1269*2154be65SJarod Wilson static void __devexit redrat3_dev_disconnect(struct usb_interface *intf) 1270*2154be65SJarod Wilson { 1271*2154be65SJarod Wilson struct usb_device *udev = interface_to_usbdev(intf); 1272*2154be65SJarod Wilson struct redrat3_dev *rr3 = usb_get_intfdata(intf); 1273*2154be65SJarod Wilson 1274*2154be65SJarod Wilson rr3_ftr(&intf->dev, "Entering %s\n", __func__); 1275*2154be65SJarod Wilson 1276*2154be65SJarod Wilson if (!rr3) 1277*2154be65SJarod Wilson return; 1278*2154be65SJarod Wilson 1279*2154be65SJarod Wilson redrat3_disable_detector(rr3); 1280*2154be65SJarod Wilson 1281*2154be65SJarod Wilson usb_set_intfdata(intf, NULL); 1282*2154be65SJarod Wilson rc_unregister_device(rr3->rc); 1283*2154be65SJarod Wilson redrat3_delete(rr3, udev); 1284*2154be65SJarod Wilson 1285*2154be65SJarod Wilson rr3_ftr(&intf->dev, "RedRat3 IR Transceiver now disconnected\n"); 1286*2154be65SJarod Wilson } 1287*2154be65SJarod Wilson 1288*2154be65SJarod Wilson static int redrat3_dev_suspend(struct usb_interface *intf, pm_message_t message) 1289*2154be65SJarod Wilson { 1290*2154be65SJarod Wilson struct redrat3_dev *rr3 = usb_get_intfdata(intf); 1291*2154be65SJarod Wilson rr3_ftr(rr3->dev, "suspend\n"); 1292*2154be65SJarod Wilson usb_kill_urb(rr3->read_urb); 1293*2154be65SJarod Wilson return 0; 1294*2154be65SJarod Wilson } 1295*2154be65SJarod Wilson 1296*2154be65SJarod Wilson static int redrat3_dev_resume(struct usb_interface *intf) 1297*2154be65SJarod Wilson { 1298*2154be65SJarod Wilson struct redrat3_dev *rr3 = usb_get_intfdata(intf); 1299*2154be65SJarod Wilson rr3_ftr(rr3->dev, "resume\n"); 1300*2154be65SJarod Wilson if (usb_submit_urb(rr3->read_urb, GFP_ATOMIC)) 1301*2154be65SJarod Wilson return -EIO; 1302*2154be65SJarod Wilson return 0; 1303*2154be65SJarod Wilson } 1304*2154be65SJarod Wilson 1305*2154be65SJarod Wilson static struct usb_driver redrat3_dev_driver = { 1306*2154be65SJarod Wilson .name = DRIVER_NAME, 1307*2154be65SJarod Wilson .probe = redrat3_dev_probe, 1308*2154be65SJarod Wilson .disconnect = redrat3_dev_disconnect, 1309*2154be65SJarod Wilson .suspend = redrat3_dev_suspend, 1310*2154be65SJarod Wilson .resume = redrat3_dev_resume, 1311*2154be65SJarod Wilson .reset_resume = redrat3_dev_resume, 1312*2154be65SJarod Wilson .id_table = redrat3_dev_table 1313*2154be65SJarod Wilson }; 1314*2154be65SJarod Wilson 1315*2154be65SJarod Wilson static int __init redrat3_dev_init(void) 1316*2154be65SJarod Wilson { 1317*2154be65SJarod Wilson int ret; 1318*2154be65SJarod Wilson 1319*2154be65SJarod Wilson ret = usb_register(&redrat3_dev_driver); 1320*2154be65SJarod Wilson if (ret < 0) 1321*2154be65SJarod Wilson pr_err(DRIVER_NAME 1322*2154be65SJarod Wilson ": usb register failed, result = %d\n", ret); 1323*2154be65SJarod Wilson 1324*2154be65SJarod Wilson return ret; 1325*2154be65SJarod Wilson } 1326*2154be65SJarod Wilson 1327*2154be65SJarod Wilson static void __exit redrat3_dev_exit(void) 1328*2154be65SJarod Wilson { 1329*2154be65SJarod Wilson usb_deregister(&redrat3_dev_driver); 1330*2154be65SJarod Wilson } 1331*2154be65SJarod Wilson 1332*2154be65SJarod Wilson module_init(redrat3_dev_init); 1333*2154be65SJarod Wilson module_exit(redrat3_dev_exit); 1334*2154be65SJarod Wilson 1335*2154be65SJarod Wilson MODULE_DESCRIPTION(DRIVER_DESC); 1336*2154be65SJarod Wilson MODULE_AUTHOR(DRIVER_AUTHOR); 1337*2154be65SJarod Wilson MODULE_AUTHOR(DRIVER_AUTHOR2); 1338*2154be65SJarod Wilson MODULE_LICENSE("GPL"); 1339*2154be65SJarod Wilson MODULE_DEVICE_TABLE(usb, redrat3_dev_table); 1340*2154be65SJarod Wilson 1341*2154be65SJarod Wilson module_param(debug, int, S_IRUGO | S_IWUSR); 1342*2154be65SJarod Wilson MODULE_PARM_DESC(debug, "Enable module debug spew. 0 = no debugging (default) " 1343*2154be65SJarod Wilson "0x1 = standard debug messages, 0x2 = function tracing debug. " 1344*2154be65SJarod Wilson "Flag bits are addative (i.e., 0x3 for both debug types)."); 1345