2012-07-15 20:31:00 +04:00
/*
* IguanaWorks USB IR Transceiver support
*
* Copyright ( C ) 2012 Sean Young < sean @ mess . org >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*/
# include <linux/device.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/usb.h>
# include <linux/usb/input.h>
# include <linux/slab.h>
# include <linux/completion.h>
# include <media/rc-core.h>
# define DRIVER_NAME "iguanair"
2012-09-28 11:44:29 +04:00
# define BUF_SIZE 152
2012-07-15 20:31:00 +04:00
struct iguanair {
struct rc_dev * rc ;
struct device * dev ;
struct usb_device * udev ;
2012-08-13 15:59:40 +04:00
uint16_t version ;
2012-07-15 20:31:00 +04:00
uint8_t bufsize ;
2012-09-28 11:44:29 +04:00
uint8_t cycle_overhead ;
2012-07-15 20:31:00 +04:00
struct mutex lock ;
/* receiver support */
bool receiver_on ;
2012-09-28 11:44:29 +04:00
dma_addr_t dma_in , dma_out ;
2012-07-15 20:31:00 +04:00
uint8_t * buf_in ;
2012-09-28 11:44:29 +04:00
struct urb * urb_in , * urb_out ;
2012-07-15 20:31:00 +04:00
struct completion completion ;
/* transmit support */
bool tx_overflow ;
uint32_t carrier ;
2012-09-28 11:44:29 +04:00
struct send_packet * packet ;
2012-07-15 20:31:00 +04:00
char name [ 64 ] ;
char phys [ 64 ] ;
} ;
2013-01-14 12:51:44 +04:00
# define CMD_NOP 0x00
2012-07-15 20:31:00 +04:00
# define CMD_GET_VERSION 0x01
# define CMD_GET_BUFSIZE 0x11
# define CMD_GET_FEATURES 0x10
# define CMD_SEND 0x15
# define CMD_EXECUTE 0x1f
# define CMD_RX_OVERFLOW 0x31
# define CMD_TX_OVERFLOW 0x32
# define CMD_RECEIVER_ON 0x12
# define CMD_RECEIVER_OFF 0x14
# define DIR_IN 0xdc
# define DIR_OUT 0xcd
2012-09-28 11:44:29 +04:00
# define MAX_IN_PACKET 8u
# define MAX_OUT_PACKET (sizeof(struct send_packet) + BUF_SIZE)
2012-07-15 20:31:00 +04:00
# define TIMEOUT 1000
2012-08-13 15:59:41 +04:00
# define RX_RESOLUTION 21333
2012-07-15 20:31:00 +04:00
struct packet {
uint16_t start ;
uint8_t direction ;
uint8_t cmd ;
} ;
struct send_packet {
struct packet header ;
uint8_t length ;
uint8_t channels ;
uint8_t busy7 ;
uint8_t busy4 ;
uint8_t payload [ 0 ] ;
} ;
static void process_ir_data ( struct iguanair * ir , unsigned len )
{
if ( len > = 4 & & ir - > buf_in [ 0 ] = = 0 & & ir - > buf_in [ 1 ] = = 0 ) {
switch ( ir - > buf_in [ 3 ] ) {
2012-08-13 15:59:39 +04:00
case CMD_GET_VERSION :
if ( len = = 6 ) {
2012-08-13 15:59:40 +04:00
ir - > version = ( ir - > buf_in [ 5 ] < < 8 ) |
ir - > buf_in [ 4 ] ;
2012-08-13 15:59:39 +04:00
complete ( & ir - > completion ) ;
}
break ;
case CMD_GET_BUFSIZE :
if ( len > = 5 ) {
ir - > bufsize = ir - > buf_in [ 4 ] ;
complete ( & ir - > completion ) ;
}
break ;
case CMD_GET_FEATURES :
if ( len > 5 ) {
2012-08-13 15:59:40 +04:00
ir - > cycle_overhead = ir - > buf_in [ 5 ] ;
2012-08-13 15:59:39 +04:00
complete ( & ir - > completion ) ;
}
break ;
2012-07-15 20:31:00 +04:00
case CMD_TX_OVERFLOW :
ir - > tx_overflow = true ;
2017-05-18 14:13:28 +03:00
/* fall through */
2012-07-15 20:31:00 +04:00
case CMD_RECEIVER_OFF :
case CMD_RECEIVER_ON :
case CMD_SEND :
complete ( & ir - > completion ) ;
break ;
case CMD_RX_OVERFLOW :
dev_warn ( ir - > dev , " receive overflow \n " ) ;
2012-08-13 15:59:44 +04:00
ir_raw_event_reset ( ir - > rc ) ;
2012-07-15 20:31:00 +04:00
break ;
default :
dev_warn ( ir - > dev , " control code %02x received \n " ,
ir - > buf_in [ 3 ] ) ;
break ;
}
} else if ( len > = 7 ) {
DEFINE_IR_RAW_EVENT ( rawir ) ;
unsigned i ;
2012-08-13 15:59:47 +04:00
bool event = false ;
2012-07-15 20:31:00 +04:00
init_ir_raw_event ( & rawir ) ;
for ( i = 0 ; i < 7 ; i + + ) {
if ( ir - > buf_in [ i ] = = 0x80 ) {
rawir . pulse = false ;
rawir . duration = US_TO_NS ( 21845 ) ;
} else {
rawir . pulse = ( ir - > buf_in [ i ] & 0x80 ) = = 0 ;
rawir . duration = ( ( ir - > buf_in [ i ] & 0x7f ) + 1 ) *
2012-08-13 15:59:41 +04:00
RX_RESOLUTION ;
2012-07-15 20:31:00 +04:00
}
2012-08-13 15:59:47 +04:00
if ( ir_raw_event_store_with_filter ( ir - > rc , & rawir ) )
event = true ;
2012-07-15 20:31:00 +04:00
}
2012-08-13 15:59:47 +04:00
if ( event )
ir_raw_event_handle ( ir - > rc ) ;
2012-07-15 20:31:00 +04:00
}
}
static void iguanair_rx ( struct urb * urb )
{
struct iguanair * ir ;
2012-08-13 15:59:43 +04:00
int rc ;
2012-07-15 20:31:00 +04:00
if ( ! urb )
return ;
ir = urb - > context ;
if ( ! ir ) {
usb_unlink_urb ( urb ) ;
return ;
}
switch ( urb - > status ) {
case 0 :
process_ir_data ( ir , urb - > actual_length ) ;
break ;
case - ECONNRESET :
case - ENOENT :
case - ESHUTDOWN :
usb_unlink_urb ( urb ) ;
return ;
case - EPIPE :
default :
dev_dbg ( ir - > dev , " Error: urb status = %d \n " , urb - > status ) ;
break ;
}
2012-08-13 15:59:43 +04:00
rc = usb_submit_urb ( urb , GFP_ATOMIC ) ;
if ( rc & & rc ! = - ENODEV )
dev_warn ( ir - > dev , " failed to resubmit urb: %d \n " , rc ) ;
2012-07-15 20:31:00 +04:00
}
2012-09-28 11:44:29 +04:00
static void iguanair_irq_out ( struct urb * urb )
2012-07-15 20:31:00 +04:00
{
2012-09-28 11:44:29 +04:00
struct iguanair * ir = urb - > context ;
if ( urb - > status )
dev_dbg ( ir - > dev , " Error: out urb status = %d \n " , urb - > status ) ;
2013-01-14 12:51:44 +04:00
/* if we sent an nop packet, do not expect a response */
if ( urb - > status = = 0 & & ir - > packet - > header . cmd = = CMD_NOP )
complete ( & ir - > completion ) ;
2012-09-28 11:44:29 +04:00
}
static int iguanair_send ( struct iguanair * ir , unsigned size )
{
int rc ;
2012-07-15 20:31:00 +04:00
2013-11-15 02:32:02 +04:00
reinit_completion ( & ir - > completion ) ;
2012-07-15 20:31:00 +04:00
2012-09-28 11:44:29 +04:00
ir - > urb_out - > transfer_buffer_length = size ;
rc = usb_submit_urb ( ir - > urb_out , GFP_KERNEL ) ;
2012-08-13 15:59:39 +04:00
if ( rc )
return rc ;
2012-07-15 20:31:00 +04:00
2012-08-13 15:59:39 +04:00
if ( wait_for_completion_timeout ( & ir - > completion , TIMEOUT ) = = 0 )
return - ETIMEDOUT ;
2012-07-15 20:31:00 +04:00
return rc ;
}
static int iguanair_get_features ( struct iguanair * ir )
{
2012-08-13 15:59:39 +04:00
int rc ;
2012-07-15 20:31:00 +04:00
2013-01-14 12:51:44 +04:00
/*
* On cold boot , the iguanair initializes on the first packet
* received but does not process that packet . Send an empty
* packet .
*/
2012-09-28 11:44:29 +04:00
ir - > packet - > header . start = 0 ;
ir - > packet - > header . direction = DIR_OUT ;
2013-01-14 12:51:44 +04:00
ir - > packet - > header . cmd = CMD_NOP ;
iguanair_send ( ir , sizeof ( ir - > packet - > header ) ) ;
2012-07-15 20:31:00 +04:00
2013-01-14 12:51:44 +04:00
ir - > packet - > header . cmd = CMD_GET_VERSION ;
2012-09-28 11:44:29 +04:00
rc = iguanair_send ( ir , sizeof ( ir - > packet - > header ) ) ;
2012-07-15 20:31:00 +04:00
if ( rc ) {
dev_info ( ir - > dev , " failed to get version \n " ) ;
goto out ;
}
2012-08-13 15:59:40 +04:00
if ( ir - > version < 0x205 ) {
dev_err ( ir - > dev , " firmware 0x%04x is too old \n " , ir - > version ) ;
rc = - ENODEV ;
goto out ;
}
2012-07-15 20:31:00 +04:00
ir - > bufsize = 150 ;
ir - > cycle_overhead = 65 ;
2012-09-28 11:44:29 +04:00
ir - > packet - > header . cmd = CMD_GET_BUFSIZE ;
2012-07-15 20:31:00 +04:00
2012-09-28 11:44:29 +04:00
rc = iguanair_send ( ir , sizeof ( ir - > packet - > header ) ) ;
2012-07-15 20:31:00 +04:00
if ( rc ) {
dev_info ( ir - > dev , " failed to get buffer size \n " ) ;
goto out ;
}
2012-09-28 11:44:29 +04:00
if ( ir - > bufsize > BUF_SIZE ) {
dev_info ( ir - > dev , " buffer size %u larger than expected \n " ,
ir - > bufsize ) ;
ir - > bufsize = BUF_SIZE ;
}
ir - > packet - > header . cmd = CMD_GET_FEATURES ;
2012-07-15 20:31:00 +04:00
2012-09-28 11:44:29 +04:00
rc = iguanair_send ( ir , sizeof ( ir - > packet - > header ) ) ;
2013-01-14 12:51:44 +04:00
if ( rc )
2012-07-15 20:31:00 +04:00
dev_info ( ir - > dev , " failed to get features \n " ) ;
out :
return rc ;
}
static int iguanair_receiver ( struct iguanair * ir , bool enable )
{
2012-09-28 11:44:29 +04:00
ir - > packet - > header . start = 0 ;
ir - > packet - > header . direction = DIR_OUT ;
ir - > packet - > header . cmd = enable ? CMD_RECEIVER_ON : CMD_RECEIVER_OFF ;
2012-07-15 20:31:00 +04:00
2012-08-13 15:59:44 +04:00
if ( enable )
ir_raw_event_reset ( ir - > rc ) ;
2013-01-14 12:51:44 +04:00
return iguanair_send ( ir , sizeof ( ir - > packet - > header ) ) ;
2012-07-15 20:31:00 +04:00
}
/*
2014-01-21 02:10:38 +04:00
* The iguanair creates the carrier by busy spinning after each half period .
* This is counted in CPU cycles , with the CPU running at 24 MHz . It is
2012-07-15 20:31:00 +04:00
* broken down into 7 - cycles and 4 - cyles delays , with a preference for
2014-01-21 02:10:38 +04:00
* 4 - cycle delays , minus the overhead of the loop itself ( cycle_overhead ) .
2012-07-15 20:31:00 +04:00
*/
static int iguanair_set_tx_carrier ( struct rc_dev * dev , uint32_t carrier )
{
struct iguanair * ir = dev - > priv ;
if ( carrier < 25000 | | carrier > 150000 )
return - EINVAL ;
mutex_lock ( & ir - > lock ) ;
if ( carrier ! = ir - > carrier ) {
uint32_t cycles , fours , sevens ;
ir - > carrier = carrier ;
cycles = DIV_ROUND_CLOSEST ( 24000000 , carrier * 2 ) -
ir - > cycle_overhead ;
2013-11-04 02:13:57 +04:00
/*
* Calculate minimum number of 7 cycles needed so
* we are left with a multiple of 4 ; so we want to have
* ( sevens * 7 ) & 3 = = cycles & 3
*/
sevens = ( 4 - cycles ) & 3 ;
2012-07-15 20:31:00 +04:00
fours = ( cycles - sevens * 7 ) / 4 ;
2014-01-21 02:10:38 +04:00
/*
* The firmware interprets these values as a relative offset
* for a branch . Immediately following the branches , there
* 4 instructions of 7 cycles ( 2 bytes each ) and 110
* instructions of 4 cycles ( 1 byte each ) . A relative branch
* of 0 will execute all of them , branch further for less
* cycle burning .
*/
2012-09-28 11:44:29 +04:00
ir - > packet - > busy7 = ( 4 - sevens ) * 2 ;
ir - > packet - > busy4 = 110 - fours ;
2012-07-15 20:31:00 +04:00
}
mutex_unlock ( & ir - > lock ) ;
2016-07-10 19:34:33 +03:00
return 0 ;
2012-07-15 20:31:00 +04:00
}
static int iguanair_set_tx_mask ( struct rc_dev * dev , uint32_t mask )
{
struct iguanair * ir = dev - > priv ;
if ( mask > 15 )
return 4 ;
mutex_lock ( & ir - > lock ) ;
2012-09-28 11:44:29 +04:00
ir - > packet - > channels = mask < < 4 ;
2012-07-15 20:31:00 +04:00
mutex_unlock ( & ir - > lock ) ;
return 0 ;
}
static int iguanair_tx ( struct rc_dev * dev , unsigned * txbuf , unsigned count )
{
struct iguanair * ir = dev - > priv ;
2012-08-25 14:01:45 +04:00
uint8_t space ;
unsigned i , size , periods , bytes ;
int rc ;
2012-07-15 20:31:00 +04:00
mutex_lock ( & ir - > lock ) ;
/* convert from us to carrier periods */
2012-08-25 14:01:45 +04:00
for ( i = space = size = 0 ; i < count ; i + + ) {
periods = DIV_ROUND_CLOSEST ( txbuf [ i ] * ir - > carrier , 1000000 ) ;
bytes = DIV_ROUND_UP ( periods , 127 ) ;
2012-08-13 15:59:42 +04:00
if ( size + bytes > ir - > bufsize ) {
2013-07-09 00:33:09 +04:00
rc = - EINVAL ;
goto out ;
2012-08-13 15:59:42 +04:00
}
2014-01-21 02:10:39 +04:00
while ( periods ) {
unsigned p = min ( periods , 127u ) ;
ir - > packet - > payload [ size + + ] = p | space ;
periods - = p ;
2012-08-25 14:01:45 +04:00
}
space ^ = 0x80 ;
2012-07-15 20:31:00 +04:00
}
2012-09-28 11:44:29 +04:00
ir - > packet - > header . start = 0 ;
ir - > packet - > header . direction = DIR_OUT ;
ir - > packet - > header . cmd = CMD_SEND ;
ir - > packet - > length = size ;
2012-07-15 20:31:00 +04:00
ir - > tx_overflow = false ;
2012-09-28 11:44:29 +04:00
rc = iguanair_send ( ir , sizeof ( * ir - > packet ) + size ) ;
2012-07-15 20:31:00 +04:00
2012-08-13 15:59:39 +04:00
if ( rc = = 0 & & ir - > tx_overflow )
rc = - EOVERFLOW ;
2012-07-15 20:31:00 +04:00
out :
mutex_unlock ( & ir - > lock ) ;
2012-08-13 15:59:42 +04:00
return rc ? rc : count ;
2012-07-15 20:31:00 +04:00
}
static int iguanair_open ( struct rc_dev * rdev )
{
struct iguanair * ir = rdev - > priv ;
int rc ;
mutex_lock ( & ir - > lock ) ;
rc = iguanair_receiver ( ir , true ) ;
if ( rc = = 0 )
ir - > receiver_on = true ;
mutex_unlock ( & ir - > lock ) ;
return rc ;
}
static void iguanair_close ( struct rc_dev * rdev )
{
struct iguanair * ir = rdev - > priv ;
int rc ;
mutex_lock ( & ir - > lock ) ;
rc = iguanair_receiver ( ir , false ) ;
ir - > receiver_on = false ;
2012-08-13 15:59:43 +04:00
if ( rc & & rc ! = - ENODEV )
2012-07-15 20:31:00 +04:00
dev_warn ( ir - > dev , " failed to disable receiver: %d \n " , rc ) ;
mutex_unlock ( & ir - > lock ) ;
}
2012-12-22 01:17:53 +04:00
static int iguanair_probe ( struct usb_interface * intf ,
const struct usb_device_id * id )
2012-07-15 20:31:00 +04:00
{
struct usb_device * udev = interface_to_usbdev ( intf ) ;
struct iguanair * ir ;
struct rc_dev * rc ;
2012-09-28 11:44:29 +04:00
int ret , pipein , pipeout ;
2012-07-15 20:31:00 +04:00
struct usb_host_interface * idesc ;
ir = kzalloc ( sizeof ( * ir ) , GFP_KERNEL ) ;
2016-12-16 11:50:58 +03:00
rc = rc_allocate_device ( RC_DRIVER_IR_RAW ) ;
2012-07-15 20:31:00 +04:00
if ( ! ir | | ! rc ) {
2012-08-13 15:59:42 +04:00
ret = - ENOMEM ;
2012-07-15 20:31:00 +04:00
goto out ;
}
2012-09-28 11:44:29 +04:00
ir - > buf_in = usb_alloc_coherent ( udev , MAX_IN_PACKET , GFP_KERNEL ,
2012-07-15 20:31:00 +04:00
& ir - > dma_in ) ;
2012-09-28 11:44:29 +04:00
ir - > packet = usb_alloc_coherent ( udev , MAX_OUT_PACKET , GFP_KERNEL ,
& ir - > dma_out ) ;
2012-07-15 20:31:00 +04:00
ir - > urb_in = usb_alloc_urb ( 0 , GFP_KERNEL ) ;
2012-09-28 11:44:29 +04:00
ir - > urb_out = usb_alloc_urb ( 0 , GFP_KERNEL ) ;
2012-07-15 20:31:00 +04:00
2012-09-28 11:44:29 +04:00
if ( ! ir - > buf_in | | ! ir - > packet | | ! ir - > urb_in | | ! ir - > urb_out ) {
2012-08-13 15:59:42 +04:00
ret = - ENOMEM ;
2012-07-15 20:31:00 +04:00
goto out ;
}
idesc = intf - > altsetting ;
if ( idesc - > desc . bNumEndpoints < 2 ) {
ret = - ENODEV ;
goto out ;
}
ir - > rc = rc ;
ir - > dev = & intf - > dev ;
ir - > udev = udev ;
mutex_init ( & ir - > lock ) ;
2012-09-28 11:44:29 +04:00
2012-07-15 20:31:00 +04:00
init_completion ( & ir - > completion ) ;
2012-09-28 11:44:29 +04:00
pipeout = usb_sndintpipe ( udev ,
idesc - > endpoint [ 1 ] . desc . bEndpointAddress ) ;
usb_fill_int_urb ( ir - > urb_out , udev , pipeout , ir - > packet , MAX_OUT_PACKET ,
iguanair_irq_out , ir , 1 ) ;
ir - > urb_out - > transfer_dma = ir - > dma_out ;
ir - > urb_out - > transfer_flags | = URB_NO_TRANSFER_DMA_MAP ;
2012-07-15 20:31:00 +04:00
2012-08-13 15:59:39 +04:00
pipein = usb_rcvintpipe ( udev , idesc - > endpoint [ 0 ] . desc . bEndpointAddress ) ;
2012-09-28 11:44:29 +04:00
usb_fill_int_urb ( ir - > urb_in , udev , pipein , ir - > buf_in , MAX_IN_PACKET ,
2012-08-13 15:59:45 +04:00
iguanair_rx , ir , 1 ) ;
2012-07-15 20:31:00 +04:00
ir - > urb_in - > transfer_dma = ir - > dma_in ;
ir - > urb_in - > transfer_flags | = URB_NO_TRANSFER_DMA_MAP ;
2012-08-13 15:59:39 +04:00
ret = usb_submit_urb ( ir - > urb_in , GFP_KERNEL ) ;
if ( ret ) {
dev_warn ( & intf - > dev , " failed to submit urb: %d \n " , ret ) ;
goto out ;
}
ret = iguanair_get_features ( ir ) ;
if ( ret )
goto out2 ;
2012-07-15 20:31:00 +04:00
snprintf ( ir - > name , sizeof ( ir - > name ) ,
2012-08-13 15:59:40 +04:00
" IguanaWorks USB IR Transceiver version 0x%04x " , ir - > version ) ;
2012-07-15 20:31:00 +04:00
usb_make_path ( ir - > udev , ir - > phys , sizeof ( ir - > phys ) ) ;
2017-07-01 19:13:19 +03:00
rc - > device_name = ir - > name ;
2012-07-15 20:31:00 +04:00
rc - > input_phys = ir - > phys ;
usb_to_input_id ( ir - > udev , & rc - > input_id ) ;
rc - > dev . parent = & intf - > dev ;
2017-08-07 23:20:58 +03:00
rc - > allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER ;
2012-07-15 20:31:00 +04:00
rc - > priv = ir ;
rc - > open = iguanair_open ;
rc - > close = iguanair_close ;
rc - > s_tx_mask = iguanair_set_tx_mask ;
rc - > s_tx_carrier = iguanair_set_tx_carrier ;
rc - > tx_ir = iguanair_tx ;
rc - > driver_name = DRIVER_NAME ;
2012-08-13 15:59:41 +04:00
rc - > map_name = RC_MAP_RC6_MCE ;
2016-12-02 20:16:12 +03:00
rc - > min_timeout = 1 ;
rc - > timeout = IR_DEFAULT_TIMEOUT ;
rc - > max_timeout = 10 * IR_DEFAULT_TIMEOUT ;
2012-08-13 15:59:41 +04:00
rc - > rx_resolution = RX_RESOLUTION ;
2012-07-15 20:31:00 +04:00
iguanair_set_tx_carrier ( rc , 38000 ) ;
2013-01-06 20:19:44 +04:00
iguanair_set_tx_mask ( rc , 0 ) ;
2012-07-15 20:31:00 +04:00
ret = rc_register_device ( rc ) ;
if ( ret < 0 ) {
dev_err ( & intf - > dev , " failed to register rc device %d " , ret ) ;
2012-08-13 15:59:39 +04:00
goto out2 ;
2012-07-15 20:31:00 +04:00
}
usb_set_intfdata ( intf , ir ) ;
return 0 ;
2012-08-13 15:59:39 +04:00
out2 :
usb_kill_urb ( ir - > urb_in ) ;
2012-09-28 11:44:29 +04:00
usb_kill_urb ( ir - > urb_out ) ;
2012-07-15 20:31:00 +04:00
out :
if ( ir ) {
usb_free_urb ( ir - > urb_in ) ;
2012-09-28 11:44:29 +04:00
usb_free_urb ( ir - > urb_out ) ;
usb_free_coherent ( udev , MAX_IN_PACKET , ir - > buf_in , ir - > dma_in ) ;
usb_free_coherent ( udev , MAX_OUT_PACKET , ir - > packet ,
ir - > dma_out ) ;
2012-07-15 20:31:00 +04:00
}
rc_free_device ( rc ) ;
kfree ( ir ) ;
return ret ;
}
2012-12-22 01:17:53 +04:00
static void iguanair_disconnect ( struct usb_interface * intf )
2012-07-15 20:31:00 +04:00
{
struct iguanair * ir = usb_get_intfdata ( intf ) ;
2012-08-13 15:59:43 +04:00
rc_unregister_device ( ir - > rc ) ;
2012-07-15 20:31:00 +04:00
usb_set_intfdata ( intf , NULL ) ;
usb_kill_urb ( ir - > urb_in ) ;
2012-09-28 11:44:29 +04:00
usb_kill_urb ( ir - > urb_out ) ;
2012-07-15 20:31:00 +04:00
usb_free_urb ( ir - > urb_in ) ;
2012-09-28 11:44:29 +04:00
usb_free_urb ( ir - > urb_out ) ;
usb_free_coherent ( ir - > udev , MAX_IN_PACKET , ir - > buf_in , ir - > dma_in ) ;
usb_free_coherent ( ir - > udev , MAX_OUT_PACKET , ir - > packet , ir - > dma_out ) ;
2012-07-15 20:31:00 +04:00
kfree ( ir ) ;
}
static int iguanair_suspend ( struct usb_interface * intf , pm_message_t message )
{
struct iguanair * ir = usb_get_intfdata ( intf ) ;
int rc = 0 ;
mutex_lock ( & ir - > lock ) ;
if ( ir - > receiver_on ) {
rc = iguanair_receiver ( ir , false ) ;
if ( rc )
dev_warn ( ir - > dev , " failed to disable receiver for suspend \n " ) ;
}
2012-08-13 15:59:43 +04:00
usb_kill_urb ( ir - > urb_in ) ;
2012-09-28 11:44:29 +04:00
usb_kill_urb ( ir - > urb_out ) ;
2012-08-13 15:59:43 +04:00
2012-07-15 20:31:00 +04:00
mutex_unlock ( & ir - > lock ) ;
return rc ;
}
static int iguanair_resume ( struct usb_interface * intf )
{
struct iguanair * ir = usb_get_intfdata ( intf ) ;
int rc = 0 ;
mutex_lock ( & ir - > lock ) ;
2012-08-13 15:59:43 +04:00
rc = usb_submit_urb ( ir - > urb_in , GFP_KERNEL ) ;
if ( rc )
dev_warn ( & intf - > dev , " failed to submit urb: %d \n " , rc ) ;
2012-07-15 20:31:00 +04:00
if ( ir - > receiver_on ) {
rc = iguanair_receiver ( ir , true ) ;
if ( rc )
dev_warn ( ir - > dev , " failed to enable receiver after resume \n " ) ;
}
mutex_unlock ( & ir - > lock ) ;
return rc ;
}
static const struct usb_device_id iguanair_table [ ] = {
{ USB_DEVICE ( 0x1781 , 0x0938 ) } ,
{ }
} ;
static struct usb_driver iguanair_driver = {
. name = DRIVER_NAME ,
. probe = iguanair_probe ,
2012-12-22 01:17:53 +04:00
. disconnect = iguanair_disconnect ,
2012-07-15 20:31:00 +04:00
. suspend = iguanair_suspend ,
. resume = iguanair_resume ,
. reset_resume = iguanair_resume ,
2012-08-13 15:59:43 +04:00
. id_table = iguanair_table ,
. soft_unbind = 1 /* we want to disable receiver on unbind */
2012-07-15 20:31:00 +04:00
} ;
module_usb_driver ( iguanair_driver ) ;
MODULE_DESCRIPTION ( " IguanaWorks USB IR Transceiver " ) ;
MODULE_AUTHOR ( " Sean Young <sean@mess.org> " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DEVICE_TABLE ( usb , iguanair_table ) ;