2007-10-20 16:12:34 +04:00
/*
*
* Generic Bluetooth USB driver
*
2008-08-18 15:23:52 +04:00
* Copyright ( C ) 2005 - 2008 Marcel Holtmann < marcel @ holtmann . org >
2007-10-20 16:12:34 +04:00
*
*
* 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 .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*
*/
# include <linux/module.h>
# include <linux/usb.h>
2013-04-19 20:57:43 +04:00
# include <linux/firmware.h>
2007-10-20 16:12:34 +04:00
# include <net/bluetooth/bluetooth.h>
# include <net/bluetooth/hci_core.h>
2009-08-25 01:44:59 +04:00
# define VERSION "0.6"
2008-08-08 00:26:56 +04:00
2012-01-13 03:02:20 +04:00
static bool ignore_dga ;
static bool ignore_csr ;
static bool ignore_sniffer ;
static bool disable_scofix ;
static bool force_scofix ;
2008-11-30 14:17:26 +03:00
2012-01-13 03:02:20 +04:00
static bool reset = 1 ;
2008-08-08 00:26:56 +04:00
static struct usb_driver btusb_driver ;
# define BTUSB_IGNORE 0x01
2008-11-30 14:17:26 +03:00
# define BTUSB_DIGIANSWER 0x02
# define BTUSB_CSR 0x04
# define BTUSB_SNIFFER 0x08
# define BTUSB_BCM92035 0x10
# define BTUSB_BROKEN_ISOC 0x20
# define BTUSB_WRONG_SCO_MTU 0x40
2011-07-01 10:02:36 +04:00
# define BTUSB_ATH3012 0x80
2013-04-19 20:57:43 +04:00
# define BTUSB_INTEL 0x100
2007-10-20 16:12:34 +04:00
static struct usb_device_id btusb_table [ ] = {
/* Generic Bluetooth USB device */
{ USB_DEVICE_INFO ( 0xe0 , 0x01 , 0x01 ) } ,
2012-08-25 21:28:06 +04:00
/* Apple-specific (Broadcom) devices */
{ USB_VENDOR_AND_INTERFACE_INFO ( 0x05ac , 0xff , 0x01 , 0x01 ) } ,
2013-06-04 17:40:26 +04:00
/* MediaTek MT76x0E */
{ USB_DEVICE ( 0x0e8d , 0x763f ) } ,
2011-09-21 13:41:45 +04:00
/* Broadcom SoftSailing reporting vendor specific */
2012-03-29 00:41:11 +04:00
{ USB_DEVICE ( 0x0a5c , 0x21e1 ) } ,
2011-09-21 13:41:45 +04:00
2010-08-20 11:24:07 +04:00
/* Apple MacBookPro 7,1 */
{ USB_DEVICE ( 0x05ac , 0x8213 ) } ,
2010-07-14 10:29:27 +04:00
/* Apple iMac11,1 */
{ USB_DEVICE ( 0x05ac , 0x8215 ) } ,
2010-08-20 11:24:06 +04:00
/* Apple MacBookPro6,2 */
{ USB_DEVICE ( 0x05ac , 0x8218 ) } ,
2010-11-04 10:04:33 +03:00
/* Apple MacBookAir3,1, MacBookAir3,2 */
{ USB_DEVICE ( 0x05ac , 0x821b ) } ,
2011-09-07 10:28:10 +04:00
/* Apple MacBookAir4,1 */
{ USB_DEVICE ( 0x05ac , 0x821f ) } ,
2011-03-24 20:51:21 +03:00
/* Apple MacBookPro8,2 */
{ USB_DEVICE ( 0x05ac , 0x821a ) } ,
2011-09-04 20:01:42 +04:00
/* Apple MacMini5,1 */
{ USB_DEVICE ( 0x05ac , 0x8281 ) } ,
2008-08-08 00:26:56 +04:00
/* AVM BlueFRITZ! USB v2.0 */
{ USB_DEVICE ( 0x057c , 0x3800 ) } ,
/* Bluetooth Ultraport Module from IBM */
{ USB_DEVICE ( 0x04bf , 0x030a ) } ,
/* ALPS Modules with non-standard id */
{ USB_DEVICE ( 0x044e , 0x3001 ) } ,
{ USB_DEVICE ( 0x044e , 0x3002 ) } ,
/* Ericsson with non-standard id */
{ USB_DEVICE ( 0x0bdb , 0x1002 ) } ,
/* Canyon CN-BTU1 with HID interfaces */
2008-11-30 14:17:26 +03:00
{ USB_DEVICE ( 0x0c10 , 0x0000 ) } ,
2008-08-08 00:26:56 +04:00
2011-11-08 10:30:22 +04:00
/* Broadcom BCM20702A0 */
2012-11-10 03:39:48 +04:00
{ USB_DEVICE ( 0x0b05 , 0x17b5 ) } ,
2012-09-11 13:25:32 +04:00
{ USB_DEVICE ( 0x04ca , 0x2003 ) } ,
2012-04-09 18:22:28 +04:00
{ USB_DEVICE ( 0x0489 , 0xe042 ) } ,
2011-11-08 10:30:22 +04:00
{ USB_DEVICE ( 0x413c , 0x8197 ) } ,
2012-04-13 22:45:55 +04:00
/* Foxconn - Hon Hai */
2012-08-15 08:38:11 +04:00
{ USB_VENDOR_AND_INTERFACE_INFO ( 0x0489 , 0xff , 0x01 , 0x01 ) } ,
2012-04-13 22:45:55 +04:00
2012-08-06 22:36:49 +04:00
/*Broadcom devices with vendor specific id */
{ USB_VENDOR_AND_INTERFACE_INFO ( 0x0a5c , 0xff , 0x01 , 0x01 ) } ,
2007-10-20 16:12:34 +04:00
{ } /* Terminating entry */
} ;
MODULE_DEVICE_TABLE ( usb , btusb_table ) ;
static struct usb_device_id blacklist_table [ ] = {
2008-08-08 00:26:56 +04:00
/* CSR BlueCore devices */
{ USB_DEVICE ( 0x0a12 , 0x0001 ) , . driver_info = BTUSB_CSR } ,
/* Broadcom BCM2033 without firmware */
{ USB_DEVICE ( 0x0a5c , 0x2033 ) , . driver_info = BTUSB_IGNORE } ,
2010-11-26 15:05:46 +03:00
/* Atheros 3011 with sflash firmware */
{ USB_DEVICE ( 0x0cf3 , 0x3002 ) , . driver_info = BTUSB_IGNORE } ,
2012-06-08 16:32:50 +04:00
{ USB_DEVICE ( 0x0cf3 , 0xe019 ) , . driver_info = BTUSB_IGNORE } ,
2011-05-10 03:11:16 +04:00
{ USB_DEVICE ( 0x13d3 , 0x3304 ) , . driver_info = BTUSB_IGNORE } ,
2011-07-13 19:04:29 +04:00
{ USB_DEVICE ( 0x0930 , 0x0215 ) , . driver_info = BTUSB_IGNORE } ,
2011-11-30 14:32:37 +04:00
{ USB_DEVICE ( 0x0489 , 0xe03d ) , . driver_info = BTUSB_IGNORE } ,
2012-11-06 23:19:11 +04:00
{ USB_DEVICE ( 0x0489 , 0xe027 ) , . driver_info = BTUSB_IGNORE } ,
2010-11-26 15:05:46 +03:00
2011-01-26 12:10:59 +03:00
/* Atheros AR9285 Malbec with sflash firmware */
{ USB_DEVICE ( 0x03f0 , 0x311d ) , . driver_info = BTUSB_IGNORE } ,
2011-02-11 13:08:53 +03:00
/* Atheros 3012 with sflash firmware */
2013-03-15 07:00:39 +04:00
{ USB_DEVICE ( 0x0cf3 , 0x0036 ) , . driver_info = BTUSB_ATH3012 } ,
2011-07-01 10:02:36 +04:00
{ USB_DEVICE ( 0x0cf3 , 0x3004 ) , . driver_info = BTUSB_ATH3012 } ,
2013-03-11 23:41:58 +04:00
{ USB_DEVICE ( 0x0cf3 , 0x3008 ) , . driver_info = BTUSB_ATH3012 } ,
2012-03-15 00:01:21 +04:00
{ USB_DEVICE ( 0x0cf3 , 0x311d ) , . driver_info = BTUSB_ATH3012 } ,
2013-03-18 19:45:11 +04:00
{ USB_DEVICE ( 0x0cf3 , 0x817a ) , . driver_info = BTUSB_ATH3012 } ,
2011-12-06 02:15:29 +04:00
{ USB_DEVICE ( 0x13d3 , 0x3375 ) , . driver_info = BTUSB_ATH3012 } ,
2013-02-19 20:54:16 +04:00
{ USB_DEVICE ( 0x04ca , 0x3004 ) , . driver_info = BTUSB_ATH3012 } ,
2012-03-28 06:25:36 +04:00
{ USB_DEVICE ( 0x04ca , 0x3005 ) , . driver_info = BTUSB_ATH3012 } ,
2012-12-29 14:14:34 +04:00
{ USB_DEVICE ( 0x04ca , 0x3006 ) , . driver_info = BTUSB_ATH3012 } ,
2013-01-10 04:06:55 +04:00
{ USB_DEVICE ( 0x04ca , 0x3008 ) , . driver_info = BTUSB_ATH3012 } ,
2012-04-13 13:39:57 +04:00
{ USB_DEVICE ( 0x13d3 , 0x3362 ) , . driver_info = BTUSB_ATH3012 } ,
2012-04-19 10:53:45 +04:00
{ USB_DEVICE ( 0x0cf3 , 0xe004 ) , . driver_info = BTUSB_ATH3012 } ,
2012-06-10 10:33:11 +04:00
{ USB_DEVICE ( 0x0930 , 0x0219 ) , . driver_info = BTUSB_ATH3012 } ,
2012-08-01 06:11:59 +04:00
{ USB_DEVICE ( 0x0489 , 0xe057 ) , . driver_info = BTUSB_ATH3012 } ,
2012-12-11 07:41:20 +04:00
{ USB_DEVICE ( 0x13d3 , 0x3393 ) , . driver_info = BTUSB_ATH3012 } ,
2013-01-03 08:24:59 +04:00
{ USB_DEVICE ( 0x0489 , 0xe04e ) , . driver_info = BTUSB_ATH3012 } ,
2013-01-03 08:25:00 +04:00
{ USB_DEVICE ( 0x0489 , 0xe056 ) , . driver_info = BTUSB_ATH3012 } ,
2013-03-24 18:41:10 +04:00
{ USB_DEVICE ( 0x0489 , 0xe04d ) , . driver_info = BTUSB_ATH3012 } ,
2011-02-11 13:08:53 +03:00
2011-02-15 05:20:07 +03:00
/* Atheros AR5BBU12 with sflash firmware */
{ USB_DEVICE ( 0x0489 , 0xe02c ) , . driver_info = BTUSB_IGNORE } ,
2012-05-03 00:33:40 +04:00
/* Atheros AR5BBU12 with sflash firmware */
{ USB_DEVICE ( 0x0489 , 0xe03c ) , . driver_info = BTUSB_ATH3012 } ,
2012-08-07 18:18:10 +04:00
{ USB_DEVICE ( 0x0489 , 0xe036 ) , . driver_info = BTUSB_ATH3012 } ,
2012-05-03 00:33:40 +04:00
2008-08-08 00:26:56 +04:00
/* Broadcom BCM2035 */
2008-11-30 14:17:26 +03:00
{ USB_DEVICE ( 0x0a5c , 0x2035 ) , . driver_info = BTUSB_WRONG_SCO_MTU } ,
{ USB_DEVICE ( 0x0a5c , 0x200a ) , . driver_info = BTUSB_WRONG_SCO_MTU } ,
{ USB_DEVICE ( 0x0a5c , 0x2009 ) , . driver_info = BTUSB_BCM92035 } ,
2008-08-08 00:26:56 +04:00
/* Broadcom BCM2045 */
2008-11-30 14:17:26 +03:00
{ USB_DEVICE ( 0x0a5c , 0x2039 ) , . driver_info = BTUSB_WRONG_SCO_MTU } ,
{ USB_DEVICE ( 0x0a5c , 0x2101 ) , . driver_info = BTUSB_WRONG_SCO_MTU } ,
2008-09-23 02:16:35 +04:00
2008-08-08 00:26:56 +04:00
/* IBM/Lenovo ThinkPad with Broadcom chip */
2008-11-30 14:17:26 +03:00
{ USB_DEVICE ( 0x0a5c , 0x201e ) , . driver_info = BTUSB_WRONG_SCO_MTU } ,
{ USB_DEVICE ( 0x0a5c , 0x2110 ) , . driver_info = BTUSB_WRONG_SCO_MTU } ,
2008-08-08 00:26:56 +04:00
/* HP laptop with Broadcom chip */
2008-11-30 14:17:26 +03:00
{ USB_DEVICE ( 0x03f0 , 0x171d ) , . driver_info = BTUSB_WRONG_SCO_MTU } ,
2008-08-08 00:26:56 +04:00
/* Dell laptop with Broadcom chip */
2008-11-30 14:17:26 +03:00
{ USB_DEVICE ( 0x413c , 0x8126 ) , . driver_info = BTUSB_WRONG_SCO_MTU } ,
2008-08-08 00:26:56 +04:00
2008-11-30 14:17:27 +03:00
/* Dell Wireless 370 and 410 devices */
2008-11-30 14:17:26 +03:00
{ USB_DEVICE ( 0x413c , 0x8152 ) , . driver_info = BTUSB_WRONG_SCO_MTU } ,
2008-11-30 14:17:27 +03:00
{ USB_DEVICE ( 0x413c , 0x8156 ) , . driver_info = BTUSB_WRONG_SCO_MTU } ,
2008-08-08 00:26:56 +04:00
2008-11-30 14:17:26 +03:00
/* Belkin F8T012 and F8T013 devices */
{ USB_DEVICE ( 0x050d , 0x0012 ) , . driver_info = BTUSB_WRONG_SCO_MTU } ,
{ USB_DEVICE ( 0x050d , 0x0013 ) , . driver_info = BTUSB_WRONG_SCO_MTU } ,
2008-08-08 00:26:56 +04:00
2008-11-30 14:17:27 +03:00
/* Asus WL-BTD202 device */
{ USB_DEVICE ( 0x0b05 , 0x1715 ) , . driver_info = BTUSB_WRONG_SCO_MTU } ,
/* Kensington Bluetooth USB adapter */
{ USB_DEVICE ( 0x047d , 0x105e ) , . driver_info = BTUSB_WRONG_SCO_MTU } ,
2008-08-08 00:26:56 +04:00
/* RTX Telecom based adapters with buggy SCO support */
{ USB_DEVICE ( 0x0400 , 0x0807 ) , . driver_info = BTUSB_BROKEN_ISOC } ,
{ USB_DEVICE ( 0x0400 , 0x080a ) , . driver_info = BTUSB_BROKEN_ISOC } ,
/* CONWISE Technology based adapters with buggy SCO support */
{ USB_DEVICE ( 0x0e5e , 0x6622 ) , . driver_info = BTUSB_BROKEN_ISOC } ,
/* Digianswer devices */
{ USB_DEVICE ( 0x08fd , 0x0001 ) , . driver_info = BTUSB_DIGIANSWER } ,
{ USB_DEVICE ( 0x08fd , 0x0002 ) , . driver_info = BTUSB_IGNORE } ,
/* CSR BlueCore Bluetooth Sniffer */
{ USB_DEVICE ( 0x0a12 , 0x0002 ) , . driver_info = BTUSB_SNIFFER } ,
/* Frontline ComProbe Bluetooth Sniffer */
{ USB_DEVICE ( 0x16d3 , 0x0002 ) , . driver_info = BTUSB_SNIFFER } ,
2013-04-19 20:57:43 +04:00
/* Intel Bluetooth device */
{ USB_DEVICE ( 0x8087 , 0x07dc ) , . driver_info = BTUSB_INTEL } ,
2007-10-20 16:12:34 +04:00
{ } /* Terminating entry */
} ;
2008-08-18 15:23:52 +04:00
# define BTUSB_MAX_ISOC_FRAMES 10
2007-10-20 16:12:34 +04:00
# define BTUSB_INTR_RUNNING 0
# define BTUSB_BULK_RUNNING 1
2008-08-18 15:23:52 +04:00
# define BTUSB_ISOC_RUNNING 2
2009-08-25 01:44:59 +04:00
# define BTUSB_SUSPENDING 3
2010-07-17 00:20:33 +04:00
# define BTUSB_DID_ISO_RESUME 4
2007-10-20 16:12:34 +04:00
struct btusb_data {
struct hci_dev * hdev ;
struct usb_device * udev ;
2008-09-23 02:16:36 +04:00
struct usb_interface * intf ;
2008-08-18 15:23:52 +04:00
struct usb_interface * isoc ;
2007-10-20 16:12:34 +04:00
spinlock_t lock ;
unsigned long flags ;
struct work_struct work ;
2009-08-25 01:44:59 +04:00
struct work_struct waker ;
2007-10-20 16:12:34 +04:00
struct usb_anchor tx_anchor ;
struct usb_anchor intr_anchor ;
struct usb_anchor bulk_anchor ;
2008-08-18 15:23:52 +04:00
struct usb_anchor isoc_anchor ;
2009-08-25 01:44:59 +04:00
struct usb_anchor deferred ;
int tx_in_flight ;
spinlock_t txlock ;
2007-10-20 16:12:34 +04:00
struct usb_endpoint_descriptor * intr_ep ;
struct usb_endpoint_descriptor * bulk_tx_ep ;
struct usb_endpoint_descriptor * bulk_rx_ep ;
2008-08-18 15:23:52 +04:00
struct usb_endpoint_descriptor * isoc_tx_ep ;
struct usb_endpoint_descriptor * isoc_rx_ep ;
2008-11-30 14:17:26 +03:00
__u8 cmdreq_type ;
2009-02-04 19:41:38 +03:00
unsigned int sco_num ;
2008-08-18 15:23:52 +04:00
int isoc_altsetting ;
2008-11-30 14:17:14 +03:00
int suspend_count ;
2007-10-20 16:12:34 +04:00
} ;
2009-08-25 01:44:59 +04:00
static int inc_tx ( struct btusb_data * data )
{
unsigned long flags ;
int rv ;
spin_lock_irqsave ( & data - > txlock , flags ) ;
rv = test_bit ( BTUSB_SUSPENDING , & data - > flags ) ;
if ( ! rv )
data - > tx_in_flight + + ;
spin_unlock_irqrestore ( & data - > txlock , flags ) ;
return rv ;
}
2007-10-20 16:12:34 +04:00
static void btusb_intr_complete ( struct urb * urb )
{
struct hci_dev * hdev = urb - > context ;
2012-02-10 00:58:32 +04:00
struct btusb_data * data = hci_get_drvdata ( hdev ) ;
2007-10-20 16:12:34 +04:00
int err ;
BT_DBG ( " %s urb %p status %d count %d " , hdev - > name ,
urb , urb - > status , urb - > actual_length ) ;
if ( ! test_bit ( HCI_RUNNING , & hdev - > flags ) )
return ;
if ( urb - > status = = 0 ) {
2008-08-18 15:23:52 +04:00
hdev - > stat . byte_rx + = urb - > actual_length ;
2007-10-20 16:12:34 +04:00
if ( hci_recv_fragment ( hdev , HCI_EVENT_PKT ,
urb - > transfer_buffer ,
urb - > actual_length ) < 0 ) {
BT_ERR ( " %s corrupted event packet " , hdev - > name ) ;
hdev - > stat . err_rx + + ;
}
}
if ( ! test_bit ( BTUSB_INTR_RUNNING , & data - > flags ) )
return ;
2009-08-25 01:44:59 +04:00
usb_mark_last_busy ( data - > udev ) ;
2007-10-20 16:12:34 +04:00
usb_anchor_urb ( urb , & data - > intr_anchor ) ;
err = usb_submit_urb ( urb , GFP_ATOMIC ) ;
if ( err < 0 ) {
2011-08-09 19:16:28 +04:00
/* -EPERM: urb is being killed;
* - ENODEV : device got disconnected */
if ( err ! = - EPERM & & err ! = - ENODEV )
2010-11-30 23:49:08 +03:00
BT_ERR ( " %s urb %p failed to resubmit (%d) " ,
2007-10-20 16:12:34 +04:00
hdev - > name , urb , - err ) ;
usb_unanchor_urb ( urb ) ;
}
}
2008-11-30 14:17:10 +03:00
static int btusb_submit_intr_urb ( struct hci_dev * hdev , gfp_t mem_flags )
2007-10-20 16:12:34 +04:00
{
2012-02-10 00:58:32 +04:00
struct btusb_data * data = hci_get_drvdata ( hdev ) ;
2007-10-20 16:12:34 +04:00
struct urb * urb ;
unsigned char * buf ;
unsigned int pipe ;
int err , size ;
BT_DBG ( " %s " , hdev - > name ) ;
2008-08-18 15:23:52 +04:00
if ( ! data - > intr_ep )
return - ENODEV ;
2008-11-30 14:17:10 +03:00
urb = usb_alloc_urb ( 0 , mem_flags ) ;
2007-10-20 16:12:34 +04:00
if ( ! urb )
return - ENOMEM ;
size = le16_to_cpu ( data - > intr_ep - > wMaxPacketSize ) ;
2008-11-30 14:17:10 +03:00
buf = kmalloc ( size , mem_flags ) ;
2007-10-20 16:12:34 +04:00
if ( ! buf ) {
usb_free_urb ( urb ) ;
return - ENOMEM ;
}
pipe = usb_rcvintpipe ( data - > udev , data - > intr_ep - > bEndpointAddress ) ;
usb_fill_int_urb ( urb , data - > udev , pipe , buf , size ,
btusb_intr_complete , hdev ,
data - > intr_ep - > bInterval ) ;
urb - > transfer_flags | = URB_FREE_BUFFER ;
usb_anchor_urb ( urb , & data - > intr_anchor ) ;
2008-11-30 14:17:10 +03:00
err = usb_submit_urb ( urb , mem_flags ) ;
2007-10-20 16:12:34 +04:00
if ( err < 0 ) {
2011-10-09 14:12:22 +04:00
if ( err ! = - EPERM & & err ! = - ENODEV )
BT_ERR ( " %s urb %p submission failed (%d) " ,
2007-10-20 16:12:34 +04:00
hdev - > name , urb , - err ) ;
usb_unanchor_urb ( urb ) ;
}
usb_free_urb ( urb ) ;
return err ;
}
static void btusb_bulk_complete ( struct urb * urb )
{
struct hci_dev * hdev = urb - > context ;
2012-02-10 00:58:32 +04:00
struct btusb_data * data = hci_get_drvdata ( hdev ) ;
2007-10-20 16:12:34 +04:00
int err ;
BT_DBG ( " %s urb %p status %d count %d " , hdev - > name ,
urb , urb - > status , urb - > actual_length ) ;
if ( ! test_bit ( HCI_RUNNING , & hdev - > flags ) )
return ;
if ( urb - > status = = 0 ) {
2008-08-18 15:23:52 +04:00
hdev - > stat . byte_rx + = urb - > actual_length ;
2007-10-20 16:12:34 +04:00
if ( hci_recv_fragment ( hdev , HCI_ACLDATA_PKT ,
urb - > transfer_buffer ,
urb - > actual_length ) < 0 ) {
BT_ERR ( " %s corrupted ACL packet " , hdev - > name ) ;
hdev - > stat . err_rx + + ;
}
}
if ( ! test_bit ( BTUSB_BULK_RUNNING , & data - > flags ) )
return ;
usb_anchor_urb ( urb , & data - > bulk_anchor ) ;
2009-12-16 21:23:43 +03:00
usb_mark_last_busy ( data - > udev ) ;
2007-10-20 16:12:34 +04:00
err = usb_submit_urb ( urb , GFP_ATOMIC ) ;
if ( err < 0 ) {
2011-08-09 19:16:28 +04:00
/* -EPERM: urb is being killed;
* - ENODEV : device got disconnected */
if ( err ! = - EPERM & & err ! = - ENODEV )
2010-11-30 23:49:08 +03:00
BT_ERR ( " %s urb %p failed to resubmit (%d) " ,
2007-10-20 16:12:34 +04:00
hdev - > name , urb , - err ) ;
usb_unanchor_urb ( urb ) ;
}
}
2008-11-30 14:17:10 +03:00
static int btusb_submit_bulk_urb ( struct hci_dev * hdev , gfp_t mem_flags )
2007-10-20 16:12:34 +04:00
{
2012-02-10 00:58:32 +04:00
struct btusb_data * data = hci_get_drvdata ( hdev ) ;
2007-10-20 16:12:34 +04:00
struct urb * urb ;
unsigned char * buf ;
unsigned int pipe ;
2009-07-02 13:01:59 +04:00
int err , size = HCI_MAX_FRAME_SIZE ;
2007-10-20 16:12:34 +04:00
BT_DBG ( " %s " , hdev - > name ) ;
2008-08-18 15:23:52 +04:00
if ( ! data - > bulk_rx_ep )
return - ENODEV ;
2008-11-30 14:17:10 +03:00
urb = usb_alloc_urb ( 0 , mem_flags ) ;
2007-10-20 16:12:34 +04:00
if ( ! urb )
return - ENOMEM ;
2008-11-30 14:17:10 +03:00
buf = kmalloc ( size , mem_flags ) ;
2007-10-20 16:12:34 +04:00
if ( ! buf ) {
usb_free_urb ( urb ) ;
return - ENOMEM ;
}
pipe = usb_rcvbulkpipe ( data - > udev , data - > bulk_rx_ep - > bEndpointAddress ) ;
usb_fill_bulk_urb ( urb , data - > udev , pipe ,
buf , size , btusb_bulk_complete , hdev ) ;
urb - > transfer_flags | = URB_FREE_BUFFER ;
2009-08-25 01:44:59 +04:00
usb_mark_last_busy ( data - > udev ) ;
2007-10-20 16:12:34 +04:00
usb_anchor_urb ( urb , & data - > bulk_anchor ) ;
2008-11-30 14:17:10 +03:00
err = usb_submit_urb ( urb , mem_flags ) ;
2007-10-20 16:12:34 +04:00
if ( err < 0 ) {
2011-10-09 14:12:22 +04:00
if ( err ! = - EPERM & & err ! = - ENODEV )
BT_ERR ( " %s urb %p submission failed (%d) " ,
2007-10-20 16:12:34 +04:00
hdev - > name , urb , - err ) ;
usb_unanchor_urb ( urb ) ;
}
usb_free_urb ( urb ) ;
return err ;
}
2008-08-18 15:23:52 +04:00
static void btusb_isoc_complete ( struct urb * urb )
{
struct hci_dev * hdev = urb - > context ;
2012-02-10 00:58:32 +04:00
struct btusb_data * data = hci_get_drvdata ( hdev ) ;
2008-08-18 15:23:52 +04:00
int i , err ;
BT_DBG ( " %s urb %p status %d count %d " , hdev - > name ,
urb , urb - > status , urb - > actual_length ) ;
if ( ! test_bit ( HCI_RUNNING , & hdev - > flags ) )
return ;
if ( urb - > status = = 0 ) {
for ( i = 0 ; i < urb - > number_of_packets ; i + + ) {
unsigned int offset = urb - > iso_frame_desc [ i ] . offset ;
unsigned int length = urb - > iso_frame_desc [ i ] . actual_length ;
if ( urb - > iso_frame_desc [ i ] . status )
continue ;
hdev - > stat . byte_rx + = length ;
if ( hci_recv_fragment ( hdev , HCI_SCODATA_PKT ,
urb - > transfer_buffer + offset ,
length ) < 0 ) {
BT_ERR ( " %s corrupted SCO packet " , hdev - > name ) ;
hdev - > stat . err_rx + + ;
}
}
}
if ( ! test_bit ( BTUSB_ISOC_RUNNING , & data - > flags ) )
return ;
usb_anchor_urb ( urb , & data - > isoc_anchor ) ;
err = usb_submit_urb ( urb , GFP_ATOMIC ) ;
if ( err < 0 ) {
2011-08-09 19:16:28 +04:00
/* -EPERM: urb is being killed;
* - ENODEV : device got disconnected */
if ( err ! = - EPERM & & err ! = - ENODEV )
2010-11-30 23:49:08 +03:00
BT_ERR ( " %s urb %p failed to resubmit (%d) " ,
2008-08-18 15:23:52 +04:00
hdev - > name , urb , - err ) ;
usb_unanchor_urb ( urb ) ;
}
}
2011-01-17 02:09:38 +03:00
static inline void __fill_isoc_descriptor ( struct urb * urb , int len , int mtu )
2008-08-18 15:23:52 +04:00
{
int i , offset = 0 ;
BT_DBG ( " len %d mtu %d " , len , mtu ) ;
for ( i = 0 ; i < BTUSB_MAX_ISOC_FRAMES & & len > = mtu ;
i + + , offset + = mtu , len - = mtu ) {
urb - > iso_frame_desc [ i ] . offset = offset ;
urb - > iso_frame_desc [ i ] . length = mtu ;
}
if ( len & & i < BTUSB_MAX_ISOC_FRAMES ) {
urb - > iso_frame_desc [ i ] . offset = offset ;
urb - > iso_frame_desc [ i ] . length = len ;
i + + ;
}
urb - > number_of_packets = i ;
}
2008-11-30 14:17:10 +03:00
static int btusb_submit_isoc_urb ( struct hci_dev * hdev , gfp_t mem_flags )
2008-08-18 15:23:52 +04:00
{
2012-02-10 00:58:32 +04:00
struct btusb_data * data = hci_get_drvdata ( hdev ) ;
2008-08-18 15:23:52 +04:00
struct urb * urb ;
unsigned char * buf ;
unsigned int pipe ;
int err , size ;
BT_DBG ( " %s " , hdev - > name ) ;
if ( ! data - > isoc_rx_ep )
return - ENODEV ;
2008-11-30 14:17:10 +03:00
urb = usb_alloc_urb ( BTUSB_MAX_ISOC_FRAMES , mem_flags ) ;
2008-08-18 15:23:52 +04:00
if ( ! urb )
return - ENOMEM ;
size = le16_to_cpu ( data - > isoc_rx_ep - > wMaxPacketSize ) *
BTUSB_MAX_ISOC_FRAMES ;
2008-11-30 14:17:10 +03:00
buf = kmalloc ( size , mem_flags ) ;
2008-08-18 15:23:52 +04:00
if ( ! buf ) {
usb_free_urb ( urb ) ;
return - ENOMEM ;
}
pipe = usb_rcvisocpipe ( data - > udev , data - > isoc_rx_ep - > bEndpointAddress ) ;
2011-12-21 06:19:00 +04:00
usb_fill_int_urb ( urb , data - > udev , pipe , buf , size , btusb_isoc_complete ,
hdev , data - > isoc_rx_ep - > bInterval ) ;
2008-08-18 15:23:52 +04:00
urb - > transfer_flags = URB_FREE_BUFFER | URB_ISO_ASAP ;
__fill_isoc_descriptor ( urb , size ,
le16_to_cpu ( data - > isoc_rx_ep - > wMaxPacketSize ) ) ;
usb_anchor_urb ( urb , & data - > isoc_anchor ) ;
2008-11-30 14:17:10 +03:00
err = usb_submit_urb ( urb , mem_flags ) ;
2008-08-18 15:23:52 +04:00
if ( err < 0 ) {
2011-10-09 14:12:22 +04:00
if ( err ! = - EPERM & & err ! = - ENODEV )
BT_ERR ( " %s urb %p submission failed (%d) " ,
2008-08-18 15:23:52 +04:00
hdev - > name , urb , - err ) ;
usb_unanchor_urb ( urb ) ;
}
usb_free_urb ( urb ) ;
return err ;
}
2007-10-20 16:12:34 +04:00
static void btusb_tx_complete ( struct urb * urb )
2009-08-25 01:44:59 +04:00
{
struct sk_buff * skb = urb - > context ;
struct hci_dev * hdev = ( struct hci_dev * ) skb - > dev ;
2012-02-10 00:58:32 +04:00
struct btusb_data * data = hci_get_drvdata ( hdev ) ;
2009-08-25 01:44:59 +04:00
BT_DBG ( " %s urb %p status %d count %d " , hdev - > name ,
urb , urb - > status , urb - > actual_length ) ;
if ( ! test_bit ( HCI_RUNNING , & hdev - > flags ) )
goto done ;
if ( ! urb - > status )
hdev - > stat . byte_tx + = urb - > transfer_buffer_length ;
else
hdev - > stat . err_tx + + ;
done :
spin_lock ( & data - > txlock ) ;
data - > tx_in_flight - - ;
spin_unlock ( & data - > txlock ) ;
kfree ( urb - > setup_packet ) ;
kfree_skb ( skb ) ;
}
static void btusb_isoc_tx_complete ( struct urb * urb )
2007-10-20 16:12:34 +04:00
{
struct sk_buff * skb = urb - > context ;
struct hci_dev * hdev = ( struct hci_dev * ) skb - > dev ;
BT_DBG ( " %s urb %p status %d count %d " , hdev - > name ,
urb , urb - > status , urb - > actual_length ) ;
if ( ! test_bit ( HCI_RUNNING , & hdev - > flags ) )
goto done ;
if ( ! urb - > status )
hdev - > stat . byte_tx + = urb - > transfer_buffer_length ;
else
hdev - > stat . err_tx + + ;
done :
kfree ( urb - > setup_packet ) ;
kfree_skb ( skb ) ;
}
static int btusb_open ( struct hci_dev * hdev )
{
2012-02-10 00:58:32 +04:00
struct btusb_data * data = hci_get_drvdata ( hdev ) ;
2007-10-20 16:12:34 +04:00
int err ;
BT_DBG ( " %s " , hdev - > name ) ;
2009-08-25 01:44:59 +04:00
err = usb_autopm_get_interface ( data - > intf ) ;
if ( err < 0 )
return err ;
data - > intf - > needs_remote_wakeup = 1 ;
2007-10-20 16:12:34 +04:00
if ( test_and_set_bit ( HCI_RUNNING , & hdev - > flags ) )
2009-08-25 01:44:59 +04:00
goto done ;
2007-10-20 16:12:34 +04:00
if ( test_and_set_bit ( BTUSB_INTR_RUNNING , & data - > flags ) )
2009-08-25 01:44:59 +04:00
goto done ;
2007-10-20 16:12:34 +04:00
2008-11-30 14:17:10 +03:00
err = btusb_submit_intr_urb ( hdev , GFP_KERNEL ) ;
2009-02-04 19:41:38 +03:00
if ( err < 0 )
goto failed ;
err = btusb_submit_bulk_urb ( hdev , GFP_KERNEL ) ;
2007-10-20 16:12:34 +04:00
if ( err < 0 ) {
2009-02-04 19:41:38 +03:00
usb_kill_anchored_urbs ( & data - > intr_anchor ) ;
goto failed ;
2007-10-20 16:12:34 +04:00
}
2009-02-04 19:41:38 +03:00
set_bit ( BTUSB_BULK_RUNNING , & data - > flags ) ;
btusb_submit_bulk_urb ( hdev , GFP_KERNEL ) ;
2009-08-25 01:44:59 +04:00
done :
usb_autopm_put_interface ( data - > intf ) ;
2009-02-04 19:41:38 +03:00
return 0 ;
failed :
clear_bit ( BTUSB_INTR_RUNNING , & data - > flags ) ;
clear_bit ( HCI_RUNNING , & hdev - > flags ) ;
2009-08-25 01:44:59 +04:00
usb_autopm_put_interface ( data - > intf ) ;
2007-10-20 16:12:34 +04:00
return err ;
}
2009-08-25 01:44:59 +04:00
static void btusb_stop_traffic ( struct btusb_data * data )
{
usb_kill_anchored_urbs ( & data - > intr_anchor ) ;
usb_kill_anchored_urbs ( & data - > bulk_anchor ) ;
usb_kill_anchored_urbs ( & data - > isoc_anchor ) ;
}
2007-10-20 16:12:34 +04:00
static int btusb_close ( struct hci_dev * hdev )
{
2012-02-10 00:58:32 +04:00
struct btusb_data * data = hci_get_drvdata ( hdev ) ;
2009-08-25 01:44:59 +04:00
int err ;
2007-10-20 16:12:34 +04:00
BT_DBG ( " %s " , hdev - > name ) ;
if ( ! test_and_clear_bit ( HCI_RUNNING , & hdev - > flags ) )
return 0 ;
2008-09-23 02:16:36 +04:00
cancel_work_sync ( & data - > work ) ;
2009-11-12 00:32:29 +03:00
cancel_work_sync ( & data - > waker ) ;
2008-09-23 02:16:36 +04:00
2008-08-18 15:23:52 +04:00
clear_bit ( BTUSB_ISOC_RUNNING , & data - > flags ) ;
2007-10-20 16:12:34 +04:00
clear_bit ( BTUSB_BULK_RUNNING , & data - > flags ) ;
clear_bit ( BTUSB_INTR_RUNNING , & data - > flags ) ;
2009-08-25 01:44:59 +04:00
btusb_stop_traffic ( data ) ;
err = usb_autopm_get_interface ( data - > intf ) ;
if ( err < 0 )
2009-11-13 16:26:23 +03:00
goto failed ;
2009-08-25 01:44:59 +04:00
data - > intf - > needs_remote_wakeup = 0 ;
usb_autopm_put_interface ( data - > intf ) ;
2007-10-20 16:12:34 +04:00
2009-11-13 16:26:23 +03:00
failed :
usb_scuttle_anchored_urbs ( & data - > deferred ) ;
2007-10-20 16:12:34 +04:00
return 0 ;
}
static int btusb_flush ( struct hci_dev * hdev )
{
2012-02-10 00:58:32 +04:00
struct btusb_data * data = hci_get_drvdata ( hdev ) ;
2007-10-20 16:12:34 +04:00
BT_DBG ( " %s " , hdev - > name ) ;
usb_kill_anchored_urbs ( & data - > tx_anchor ) ;
return 0 ;
}
static int btusb_send_frame ( struct sk_buff * skb )
{
struct hci_dev * hdev = ( struct hci_dev * ) skb - > dev ;
2012-02-10 00:58:32 +04:00
struct btusb_data * data = hci_get_drvdata ( hdev ) ;
2007-10-20 16:12:34 +04:00
struct usb_ctrlrequest * dr ;
struct urb * urb ;
unsigned int pipe ;
int err ;
BT_DBG ( " %s " , hdev - > name ) ;
if ( ! test_bit ( HCI_RUNNING , & hdev - > flags ) )
return - EBUSY ;
switch ( bt_cb ( skb ) - > pkt_type ) {
case HCI_COMMAND_PKT :
urb = usb_alloc_urb ( 0 , GFP_ATOMIC ) ;
if ( ! urb )
return - ENOMEM ;
dr = kmalloc ( sizeof ( * dr ) , GFP_ATOMIC ) ;
if ( ! dr ) {
usb_free_urb ( urb ) ;
return - ENOMEM ;
}
2008-11-30 14:17:26 +03:00
dr - > bRequestType = data - > cmdreq_type ;
2007-10-20 16:12:34 +04:00
dr - > bRequest = 0 ;
dr - > wIndex = 0 ;
dr - > wValue = 0 ;
dr - > wLength = __cpu_to_le16 ( skb - > len ) ;
pipe = usb_sndctrlpipe ( data - > udev , 0x00 ) ;
usb_fill_control_urb ( urb , data - > udev , pipe , ( void * ) dr ,
skb - > data , skb - > len , btusb_tx_complete , skb ) ;
hdev - > stat . cmd_tx + + ;
break ;
case HCI_ACLDATA_PKT :
2011-07-14 16:48:32 +04:00
if ( ! data - > bulk_tx_ep )
2008-08-18 15:23:52 +04:00
return - ENODEV ;
2007-10-20 16:12:34 +04:00
urb = usb_alloc_urb ( 0 , GFP_ATOMIC ) ;
if ( ! urb )
return - ENOMEM ;
pipe = usb_sndbulkpipe ( data - > udev ,
data - > bulk_tx_ep - > bEndpointAddress ) ;
usb_fill_bulk_urb ( urb , data - > udev , pipe ,
skb - > data , skb - > len , btusb_tx_complete , skb ) ;
hdev - > stat . acl_tx + + ;
break ;
case HCI_SCODATA_PKT :
2008-08-18 15:23:52 +04:00
if ( ! data - > isoc_tx_ep | | hdev - > conn_hash . sco_num < 1 )
return - ENODEV ;
urb = usb_alloc_urb ( BTUSB_MAX_ISOC_FRAMES , GFP_ATOMIC ) ;
if ( ! urb )
return - ENOMEM ;
pipe = usb_sndisocpipe ( data - > udev ,
data - > isoc_tx_ep - > bEndpointAddress ) ;
2011-02-15 00:53:43 +03:00
usb_fill_int_urb ( urb , data - > udev , pipe ,
skb - > data , skb - > len , btusb_isoc_tx_complete ,
skb , data - > isoc_tx_ep - > bInterval ) ;
2008-08-18 15:23:52 +04:00
urb - > transfer_flags = URB_ISO_ASAP ;
__fill_isoc_descriptor ( urb , skb - > len ,
le16_to_cpu ( data - > isoc_tx_ep - > wMaxPacketSize ) ) ;
2007-10-20 16:12:34 +04:00
hdev - > stat . sco_tx + + ;
2009-08-25 01:44:59 +04:00
goto skip_waking ;
2007-10-20 16:12:34 +04:00
default :
return - EILSEQ ;
}
2009-08-25 01:44:59 +04:00
err = inc_tx ( data ) ;
if ( err ) {
usb_anchor_urb ( urb , & data - > deferred ) ;
schedule_work ( & data - > waker ) ;
err = 0 ;
goto done ;
}
skip_waking :
2007-10-20 16:12:34 +04:00
usb_anchor_urb ( urb , & data - > tx_anchor ) ;
err = usb_submit_urb ( urb , GFP_ATOMIC ) ;
if ( err < 0 ) {
2011-10-09 14:12:16 +04:00
if ( err ! = - EPERM & & err ! = - ENODEV )
BT_ERR ( " %s urb %p submission failed (%d) " ,
hdev - > name , urb , - err ) ;
2007-10-20 16:12:34 +04:00
kfree ( urb - > setup_packet ) ;
usb_unanchor_urb ( urb ) ;
2009-08-25 01:44:59 +04:00
} else {
usb_mark_last_busy ( data - > udev ) ;
2007-10-20 16:12:34 +04:00
}
2009-08-25 01:44:59 +04:00
done :
2011-11-22 05:32:57 +04:00
usb_free_urb ( urb ) ;
2007-10-20 16:12:34 +04:00
return err ;
}
static void btusb_notify ( struct hci_dev * hdev , unsigned int evt )
{
2012-02-10 00:58:32 +04:00
struct btusb_data * data = hci_get_drvdata ( hdev ) ;
2007-10-20 16:12:34 +04:00
BT_DBG ( " %s evt %d " , hdev - > name , evt ) ;
2009-02-04 19:41:38 +03:00
if ( hdev - > conn_hash . sco_num ! = data - > sco_num ) {
data - > sco_num = hdev - > conn_hash . sco_num ;
schedule_work ( & data - > work ) ;
2008-11-30 14:17:12 +03:00
}
2007-10-20 16:12:34 +04:00
}
2011-01-17 02:09:38 +03:00
static inline int __set_isoc_interface ( struct hci_dev * hdev , int altsetting )
2008-08-18 15:23:52 +04:00
{
2012-02-10 00:58:32 +04:00
struct btusb_data * data = hci_get_drvdata ( hdev ) ;
2008-08-18 15:23:52 +04:00
struct usb_interface * intf = data - > isoc ;
struct usb_endpoint_descriptor * ep_desc ;
int i , err ;
if ( ! data - > isoc )
return - ENODEV ;
err = usb_set_interface ( data - > udev , 1 , altsetting ) ;
if ( err < 0 ) {
BT_ERR ( " %s setting interface failed (%d) " , hdev - > name , - err ) ;
return err ;
}
data - > isoc_altsetting = altsetting ;
data - > isoc_tx_ep = NULL ;
data - > isoc_rx_ep = NULL ;
for ( i = 0 ; i < intf - > cur_altsetting - > desc . bNumEndpoints ; i + + ) {
ep_desc = & intf - > cur_altsetting - > endpoint [ i ] . desc ;
if ( ! data - > isoc_tx_ep & & usb_endpoint_is_isoc_out ( ep_desc ) ) {
data - > isoc_tx_ep = ep_desc ;
continue ;
}
if ( ! data - > isoc_rx_ep & & usb_endpoint_is_isoc_in ( ep_desc ) ) {
data - > isoc_rx_ep = ep_desc ;
continue ;
}
}
if ( ! data - > isoc_tx_ep | | ! data - > isoc_rx_ep ) {
BT_ERR ( " %s invalid SCO descriptors " , hdev - > name ) ;
return - ENODEV ;
}
return 0 ;
}
2007-10-20 16:12:34 +04:00
static void btusb_work ( struct work_struct * work )
{
struct btusb_data * data = container_of ( work , struct btusb_data , work ) ;
struct hci_dev * hdev = data - > hdev ;
2012-04-11 10:48:51 +04:00
int new_alts ;
2009-08-25 01:44:59 +04:00
int err ;
2007-10-20 16:12:34 +04:00
2008-08-18 15:23:52 +04:00
if ( hdev - > conn_hash . sco_num > 0 ) {
2010-07-17 00:20:33 +04:00
if ( ! test_bit ( BTUSB_DID_ISO_RESUME , & data - > flags ) ) {
2011-02-11 15:00:06 +03:00
err = usb_autopm_get_interface ( data - > isoc ? data - > isoc : data - > intf ) ;
2009-08-25 01:44:59 +04:00
if ( err < 0 ) {
clear_bit ( BTUSB_ISOC_RUNNING , & data - > flags ) ;
usb_kill_anchored_urbs ( & data - > isoc_anchor ) ;
return ;
}
2010-07-17 00:20:33 +04:00
set_bit ( BTUSB_DID_ISO_RESUME , & data - > flags ) ;
2009-08-25 01:44:59 +04:00
}
2012-04-11 10:48:51 +04:00
if ( hdev - > voice_setting & 0x0020 ) {
static const int alts [ 3 ] = { 2 , 4 , 5 } ;
new_alts = alts [ hdev - > conn_hash . sco_num - 1 ] ;
} else {
new_alts = hdev - > conn_hash . sco_num ;
}
if ( data - > isoc_altsetting ! = new_alts ) {
2008-08-18 15:23:52 +04:00
clear_bit ( BTUSB_ISOC_RUNNING , & data - > flags ) ;
usb_kill_anchored_urbs ( & data - > isoc_anchor ) ;
2012-04-11 10:48:51 +04:00
if ( __set_isoc_interface ( hdev , new_alts ) < 0 )
2008-08-18 15:23:52 +04:00
return ;
}
if ( ! test_and_set_bit ( BTUSB_ISOC_RUNNING , & data - > flags ) ) {
2008-11-30 14:17:10 +03:00
if ( btusb_submit_isoc_urb ( hdev , GFP_KERNEL ) < 0 )
2008-08-18 15:23:52 +04:00
clear_bit ( BTUSB_ISOC_RUNNING , & data - > flags ) ;
else
2008-11-30 14:17:10 +03:00
btusb_submit_isoc_urb ( hdev , GFP_KERNEL ) ;
2008-08-18 15:23:52 +04:00
}
} else {
clear_bit ( BTUSB_ISOC_RUNNING , & data - > flags ) ;
usb_kill_anchored_urbs ( & data - > isoc_anchor ) ;
__set_isoc_interface ( hdev , 0 ) ;
2010-07-17 00:20:33 +04:00
if ( test_and_clear_bit ( BTUSB_DID_ISO_RESUME , & data - > flags ) )
2011-02-11 15:00:06 +03:00
usb_autopm_put_interface ( data - > isoc ? data - > isoc : data - > intf ) ;
2007-10-20 16:12:34 +04:00
}
}
2009-08-25 01:44:59 +04:00
static void btusb_waker ( struct work_struct * work )
{
struct btusb_data * data = container_of ( work , struct btusb_data , waker ) ;
int err ;
err = usb_autopm_get_interface ( data - > intf ) ;
if ( err < 0 )
return ;
usb_autopm_put_interface ( data - > intf ) ;
}
2013-04-10 19:11:35 +04:00
static int btusb_setup_bcm92035 ( struct hci_dev * hdev )
{
struct sk_buff * skb ;
u8 val = 0x00 ;
BT_DBG ( " %s " , hdev - > name ) ;
skb = __hci_cmd_sync ( hdev , 0xfc3b , 1 , & val , HCI_INIT_TIMEOUT ) ;
if ( IS_ERR ( skb ) )
BT_ERR ( " BCM92035 command failed (%ld) " , - PTR_ERR ( skb ) ) ;
else
kfree_skb ( skb ) ;
return 0 ;
}
2013-04-19 20:57:43 +04:00
struct intel_version {
u8 status ;
u8 hw_platform ;
u8 hw_variant ;
u8 hw_revision ;
u8 fw_variant ;
u8 fw_revision ;
u8 fw_build_num ;
u8 fw_build_ww ;
u8 fw_build_yy ;
u8 fw_patch_num ;
} __packed ;
static const struct firmware * btusb_setup_intel_get_fw ( struct hci_dev * hdev ,
struct intel_version * ver )
{
const struct firmware * fw ;
char fwname [ 64 ] ;
int ret ;
snprintf ( fwname , sizeof ( fwname ) ,
" intel/ibt-hw-%x.%x.%x-fw-%x.%x.%x.%x.%x.bseq " ,
ver - > hw_platform , ver - > hw_variant , ver - > hw_revision ,
ver - > fw_variant , ver - > fw_revision , ver - > fw_build_num ,
ver - > fw_build_ww , ver - > fw_build_yy ) ;
ret = request_firmware ( & fw , fwname , & hdev - > dev ) ;
if ( ret < 0 ) {
if ( ret = = - EINVAL ) {
BT_ERR ( " %s Intel firmware file request failed (%d) " ,
hdev - > name , ret ) ;
return NULL ;
}
BT_ERR ( " %s failed to open Intel firmware file: %s(%d) " ,
hdev - > name , fwname , ret ) ;
/* If the correct firmware patch file is not found, use the
* default firmware patch file instead
*/
snprintf ( fwname , sizeof ( fwname ) , " intel/ibt-hw-%x.%x.bseq " ,
ver - > hw_platform , ver - > hw_variant ) ;
if ( request_firmware ( & fw , fwname , & hdev - > dev ) < 0 ) {
BT_ERR ( " %s failed to open default Intel fw file: %s " ,
hdev - > name , fwname ) ;
return NULL ;
}
}
BT_INFO ( " %s: Intel Bluetooth firmware file: %s " , hdev - > name , fwname ) ;
return fw ;
}
static int btusb_setup_intel_patching ( struct hci_dev * hdev ,
const struct firmware * fw ,
const u8 * * fw_ptr , int * disable_patch )
{
struct sk_buff * skb ;
struct hci_command_hdr * cmd ;
const u8 * cmd_param ;
struct hci_event_hdr * evt = NULL ;
const u8 * evt_param = NULL ;
int remain = fw - > size - ( * fw_ptr - fw - > data ) ;
/* The first byte indicates the types of the patch command or event.
* 0x01 means HCI command and 0x02 is HCI event . If the first bytes
* in the current firmware buffer doesn ' t start with 0x01 or
* the size of remain buffer is smaller than HCI command header ,
* the firmware file is corrupted and it should stop the patching
* process .
*/
if ( remain > HCI_COMMAND_HDR_SIZE & & * fw_ptr [ 0 ] ! = 0x01 ) {
BT_ERR ( " %s Intel fw corrupted: invalid cmd read " , hdev - > name ) ;
return - EINVAL ;
}
( * fw_ptr ) + + ;
remain - - ;
cmd = ( struct hci_command_hdr * ) ( * fw_ptr ) ;
* fw_ptr + = sizeof ( * cmd ) ;
remain - = sizeof ( * cmd ) ;
/* Ensure that the remain firmware data is long enough than the length
* of command parameter . If not , the firmware file is corrupted .
*/
if ( remain < cmd - > plen ) {
BT_ERR ( " %s Intel fw corrupted: invalid cmd len " , hdev - > name ) ;
return - EFAULT ;
}
/* If there is a command that loads a patch in the firmware
* file , then enable the patch upon success , otherwise just
* disable the manufacturer mode , for example patch activation
* is not required when the default firmware patch file is used
* because there are no patch data to load .
*/
if ( * disable_patch & & le16_to_cpu ( cmd - > opcode ) = = 0xfc8e )
* disable_patch = 0 ;
cmd_param = * fw_ptr ;
* fw_ptr + = cmd - > plen ;
remain - = cmd - > plen ;
/* This reads the expected events when the above command is sent to the
* device . Some vendor commands expects more than one events , for
* example command status event followed by vendor specific event .
* For this case , it only keeps the last expected event . so the command
* can be sent with __hci_cmd_sync_ev ( ) which returns the sk_buff of
* last expected event .
*/
while ( remain > HCI_EVENT_HDR_SIZE & & * fw_ptr [ 0 ] = = 0x02 ) {
( * fw_ptr ) + + ;
remain - - ;
evt = ( struct hci_event_hdr * ) ( * fw_ptr ) ;
* fw_ptr + = sizeof ( * evt ) ;
remain - = sizeof ( * evt ) ;
if ( remain < evt - > plen ) {
BT_ERR ( " %s Intel fw corrupted: invalid evt len " ,
hdev - > name ) ;
return - EFAULT ;
}
evt_param = * fw_ptr ;
* fw_ptr + = evt - > plen ;
remain - = evt - > plen ;
}
/* Every HCI commands in the firmware file has its correspond event.
* If event is not found or remain is smaller than zero , the firmware
* file is corrupted .
*/
if ( ! evt | | ! evt_param | | remain < 0 ) {
BT_ERR ( " %s Intel fw corrupted: invalid evt read " , hdev - > name ) ;
return - EFAULT ;
}
skb = __hci_cmd_sync_ev ( hdev , le16_to_cpu ( cmd - > opcode ) , cmd - > plen ,
cmd_param , evt - > evt , HCI_INIT_TIMEOUT ) ;
if ( IS_ERR ( skb ) ) {
BT_ERR ( " %s sending Intel patch command (0x%4.4x) failed (%ld) " ,
hdev - > name , cmd - > opcode , PTR_ERR ( skb ) ) ;
return - PTR_ERR ( skb ) ;
}
/* It ensures that the returned event matches the event data read from
* the firmware file . At fist , it checks the length and then
* the contents of the event .
*/
if ( skb - > len ! = evt - > plen ) {
BT_ERR ( " %s mismatch event length (opcode 0x%4.4x) " , hdev - > name ,
le16_to_cpu ( cmd - > opcode ) ) ;
kfree_skb ( skb ) ;
return - EFAULT ;
}
if ( memcmp ( skb - > data , evt_param , evt - > plen ) ) {
BT_ERR ( " %s mismatch event parameter (opcode 0x%4.4x) " ,
hdev - > name , le16_to_cpu ( cmd - > opcode ) ) ;
kfree_skb ( skb ) ;
return - EFAULT ;
}
kfree_skb ( skb ) ;
return 0 ;
}
static int btusb_setup_intel ( struct hci_dev * hdev )
{
struct sk_buff * skb ;
const struct firmware * fw ;
const u8 * fw_ptr ;
int disable_patch ;
struct intel_version * ver ;
const u8 mfg_enable [ ] = { 0x01 , 0x00 } ;
const u8 mfg_disable [ ] = { 0x00 , 0x00 } ;
const u8 mfg_reset_deactivate [ ] = { 0x00 , 0x01 } ;
const u8 mfg_reset_activate [ ] = { 0x00 , 0x02 } ;
BT_DBG ( " %s " , hdev - > name ) ;
/* The controller has a bug with the first HCI command sent to it
* returning number of completed commands as zero . This would stall the
* command processing in the Bluetooth core .
*
* As a workaround , send HCI Reset command first which will reset the
* number of completed commands and allow normal command processing
* from now on .
*/
skb = __hci_cmd_sync ( hdev , HCI_OP_RESET , 0 , NULL , HCI_INIT_TIMEOUT ) ;
if ( IS_ERR ( skb ) ) {
BT_ERR ( " %s sending initial HCI reset command failed (%ld) " ,
hdev - > name , PTR_ERR ( skb ) ) ;
return - PTR_ERR ( skb ) ;
}
kfree_skb ( skb ) ;
/* Read Intel specific controller version first to allow selection of
* which firmware file to load .
*
* The returned information are hardware variant and revision plus
* firmware variant , revision and build number .
*/
skb = __hci_cmd_sync ( hdev , 0xfc05 , 0 , NULL , HCI_INIT_TIMEOUT ) ;
if ( IS_ERR ( skb ) ) {
BT_ERR ( " %s reading Intel fw version command failed (%ld) " ,
hdev - > name , PTR_ERR ( skb ) ) ;
return - PTR_ERR ( skb ) ;
}
if ( skb - > len ! = sizeof ( * ver ) ) {
BT_ERR ( " %s Intel version event length mismatch " , hdev - > name ) ;
kfree_skb ( skb ) ;
return - EIO ;
}
ver = ( struct intel_version * ) skb - > data ;
if ( ver - > status ) {
BT_ERR ( " %s Intel fw version event failed (%02x) " , hdev - > name ,
ver - > status ) ;
kfree_skb ( skb ) ;
return - bt_to_errno ( ver - > status ) ;
}
BT_INFO ( " %s: read Intel version: %02x%02x%02x%02x%02x%02x%02x%02x%02x " ,
hdev - > name , ver - > hw_platform , ver - > hw_variant ,
ver - > hw_revision , ver - > fw_variant , ver - > fw_revision ,
ver - > fw_build_num , ver - > fw_build_ww , ver - > fw_build_yy ,
ver - > fw_patch_num ) ;
/* fw_patch_num indicates the version of patch the device currently
* have . If there is no patch data in the device , it is always 0x00 .
* So , if it is other than 0x00 , no need to patch the deivce again .
*/
if ( ver - > fw_patch_num ) {
BT_INFO ( " %s: Intel device is already patched. patch num: %02x " ,
hdev - > name , ver - > fw_patch_num ) ;
kfree_skb ( skb ) ;
return 0 ;
}
/* Opens the firmware patch file based on the firmware version read
* from the controller . If it fails to open the matching firmware
* patch file , it tries to open the default firmware patch file .
* If no patch file is found , allow the device to operate without
* a patch .
*/
fw = btusb_setup_intel_get_fw ( hdev , ver ) ;
if ( ! fw ) {
kfree_skb ( skb ) ;
return 0 ;
}
fw_ptr = fw - > data ;
/* This Intel specific command enables the manufacturer mode of the
* controller .
*
* Only while this mode is enabled , the driver can download the
* firmware patch data and configuration parameters .
*/
skb = __hci_cmd_sync ( hdev , 0xfc11 , 2 , mfg_enable , HCI_INIT_TIMEOUT ) ;
if ( IS_ERR ( skb ) ) {
BT_ERR ( " %s entering Intel manufacturer mode failed (%ld) " ,
hdev - > name , PTR_ERR ( skb ) ) ;
release_firmware ( fw ) ;
return - PTR_ERR ( skb ) ;
}
if ( skb - > data [ 0 ] ) {
u8 evt_status = skb - > data [ 0 ] ;
BT_ERR ( " %s enable Intel manufacturer mode event failed (%02x) " ,
hdev - > name , evt_status ) ;
kfree_skb ( skb ) ;
release_firmware ( fw ) ;
return - bt_to_errno ( evt_status ) ;
}
kfree_skb ( skb ) ;
disable_patch = 1 ;
/* The firmware data file consists of list of Intel specific HCI
* commands and its expected events . The first byte indicates the
* type of the message , either HCI command or HCI event .
*
* It reads the command and its expected event from the firmware file ,
* and send to the controller . Once __hci_cmd_sync_ev ( ) returns ,
* the returned event is compared with the event read from the firmware
* file and it will continue until all the messages are downloaded to
* the controller .
*
* Once the firmware patching is completed successfully ,
* the manufacturer mode is disabled with reset and activating the
* downloaded patch .
*
* If the firmware patching fails , the manufacturer mode is
* disabled with reset and deactivating the patch .
*
* If the default patch file is used , no reset is done when disabling
* the manufacturer .
*/
while ( fw - > size > fw_ptr - fw - > data ) {
int ret ;
ret = btusb_setup_intel_patching ( hdev , fw , & fw_ptr ,
& disable_patch ) ;
if ( ret < 0 )
goto exit_mfg_deactivate ;
}
release_firmware ( fw ) ;
if ( disable_patch )
goto exit_mfg_disable ;
/* Patching completed successfully and disable the manufacturer mode
* with reset and activate the downloaded firmware patches .
*/
skb = __hci_cmd_sync ( hdev , 0xfc11 , sizeof ( mfg_reset_activate ) ,
mfg_reset_activate , HCI_INIT_TIMEOUT ) ;
if ( IS_ERR ( skb ) ) {
BT_ERR ( " %s exiting Intel manufacturer mode failed (%ld) " ,
hdev - > name , PTR_ERR ( skb ) ) ;
return - PTR_ERR ( skb ) ;
}
kfree_skb ( skb ) ;
BT_INFO ( " %s: Intel Bluetooth firmware patch completed and activated " ,
hdev - > name ) ;
return 0 ;
exit_mfg_disable :
/* Disable the manufacturer mode without reset */
skb = __hci_cmd_sync ( hdev , 0xfc11 , sizeof ( mfg_disable ) , mfg_disable ,
HCI_INIT_TIMEOUT ) ;
if ( IS_ERR ( skb ) ) {
BT_ERR ( " %s exiting Intel manufacturer mode failed (%ld) " ,
hdev - > name , PTR_ERR ( skb ) ) ;
return - PTR_ERR ( skb ) ;
}
kfree_skb ( skb ) ;
BT_INFO ( " %s: Intel Bluetooth firmware patch completed " , hdev - > name ) ;
return 0 ;
exit_mfg_deactivate :
release_firmware ( fw ) ;
/* Patching failed. Disable the manufacturer mode with reset and
* deactivate the downloaded firmware patches .
*/
skb = __hci_cmd_sync ( hdev , 0xfc11 , sizeof ( mfg_reset_deactivate ) ,
mfg_reset_deactivate , HCI_INIT_TIMEOUT ) ;
if ( IS_ERR ( skb ) ) {
BT_ERR ( " %s exiting Intel manufacturer mode failed (%ld) " ,
hdev - > name , PTR_ERR ( skb ) ) ;
return - PTR_ERR ( skb ) ;
}
kfree_skb ( skb ) ;
BT_INFO ( " %s: Intel Bluetooth firmware patch completed and deactivated " ,
hdev - > name ) ;
return 0 ;
}
2007-10-20 16:12:34 +04:00
static int btusb_probe ( struct usb_interface * intf ,
const struct usb_device_id * id )
{
struct usb_endpoint_descriptor * ep_desc ;
struct btusb_data * data ;
struct hci_dev * hdev ;
int i , err ;
BT_DBG ( " intf %p id %p " , intf , id ) ;
2008-08-08 00:26:56 +04:00
/* interface numbers are hardcoded in the spec */
2007-10-20 16:12:34 +04:00
if ( intf - > cur_altsetting - > desc . bInterfaceNumber ! = 0 )
return - ENODEV ;
if ( ! id - > driver_info ) {
const struct usb_device_id * match ;
match = usb_match_id ( intf , blacklist_table ) ;
if ( match )
id = match ;
}
2008-08-08 00:26:56 +04:00
if ( id - > driver_info = = BTUSB_IGNORE )
return - ENODEV ;
if ( ignore_dga & & id - > driver_info & BTUSB_DIGIANSWER )
return - ENODEV ;
if ( ignore_csr & & id - > driver_info & BTUSB_CSR )
return - ENODEV ;
if ( ignore_sniffer & & id - > driver_info & BTUSB_SNIFFER )
return - ENODEV ;
2011-07-01 10:02:36 +04:00
if ( id - > driver_info & BTUSB_ATH3012 ) {
struct usb_device * udev = interface_to_usbdev ( intf ) ;
/* Old firmware would otherwise let ath3k driver load
* patch and sysconfig files */
if ( le16_to_cpu ( udev - > descriptor . bcdDevice ) < = 0x0001 )
return - ENODEV ;
}
2012-07-27 11:08:39 +04:00
data = devm_kzalloc ( & intf - > dev , sizeof ( * data ) , GFP_KERNEL ) ;
2007-10-20 16:12:34 +04:00
if ( ! data )
return - ENOMEM ;
for ( i = 0 ; i < intf - > cur_altsetting - > desc . bNumEndpoints ; i + + ) {
ep_desc = & intf - > cur_altsetting - > endpoint [ i ] . desc ;
if ( ! data - > intr_ep & & usb_endpoint_is_int_in ( ep_desc ) ) {
data - > intr_ep = ep_desc ;
continue ;
}
if ( ! data - > bulk_tx_ep & & usb_endpoint_is_bulk_out ( ep_desc ) ) {
data - > bulk_tx_ep = ep_desc ;
continue ;
}
if ( ! data - > bulk_rx_ep & & usb_endpoint_is_bulk_in ( ep_desc ) ) {
data - > bulk_rx_ep = ep_desc ;
continue ;
}
}
2012-07-27 11:08:39 +04:00
if ( ! data - > intr_ep | | ! data - > bulk_tx_ep | | ! data - > bulk_rx_ep )
2007-10-20 16:12:34 +04:00
return - ENODEV ;
2008-11-30 14:17:26 +03:00
data - > cmdreq_type = USB_TYPE_CLASS ;
2007-10-20 16:12:34 +04:00
data - > udev = interface_to_usbdev ( intf ) ;
2008-09-23 02:16:36 +04:00
data - > intf = intf ;
2007-10-20 16:12:34 +04:00
spin_lock_init ( & data - > lock ) ;
INIT_WORK ( & data - > work , btusb_work ) ;
2009-08-25 01:44:59 +04:00
INIT_WORK ( & data - > waker , btusb_waker ) ;
spin_lock_init ( & data - > txlock ) ;
2007-10-20 16:12:34 +04:00
init_usb_anchor ( & data - > tx_anchor ) ;
init_usb_anchor ( & data - > intr_anchor ) ;
init_usb_anchor ( & data - > bulk_anchor ) ;
2008-08-18 15:23:52 +04:00
init_usb_anchor ( & data - > isoc_anchor ) ;
2009-08-25 01:44:59 +04:00
init_usb_anchor ( & data - > deferred ) ;
2007-10-20 16:12:34 +04:00
hdev = hci_alloc_dev ( ) ;
2012-07-27 11:08:39 +04:00
if ( ! hdev )
2007-10-20 16:12:34 +04:00
return - ENOMEM ;
2010-02-08 17:27:07 +03:00
hdev - > bus = HCI_USB ;
2012-02-10 00:58:32 +04:00
hci_set_drvdata ( hdev , data ) ;
2007-10-20 16:12:34 +04:00
data - > hdev = hdev ;
SET_HCIDEV_DEV ( hdev , & intf - > dev ) ;
2013-04-10 19:11:35 +04:00
hdev - > open = btusb_open ;
hdev - > close = btusb_close ;
hdev - > flush = btusb_flush ;
hdev - > send = btusb_send_frame ;
hdev - > notify = btusb_notify ;
if ( id - > driver_info & BTUSB_BCM92035 )
hdev - > setup = btusb_setup_bcm92035 ;
2007-10-20 16:12:34 +04:00
2013-04-19 20:57:43 +04:00
if ( id - > driver_info & BTUSB_INTEL )
hdev - > setup = btusb_setup_intel ;
2008-11-30 14:17:26 +03:00
/* Interface numbers are hardcoded in the specification */
2008-08-18 15:23:52 +04:00
data - > isoc = usb_ifnum_to_if ( data - > udev , 1 ) ;
2008-11-30 14:17:26 +03:00
if ( ! reset )
2012-05-23 14:35:46 +04:00
set_bit ( HCI_QUIRK_RESET_ON_CLOSE , & hdev - > quirks ) ;
2008-08-08 00:26:56 +04:00
if ( force_scofix | | id - > driver_info & BTUSB_WRONG_SCO_MTU ) {
if ( ! disable_scofix )
set_bit ( HCI_QUIRK_FIXUP_BUFFER_SIZE , & hdev - > quirks ) ;
}
2008-08-18 15:23:52 +04:00
if ( id - > driver_info & BTUSB_BROKEN_ISOC )
data - > isoc = NULL ;
2008-11-30 14:17:26 +03:00
if ( id - > driver_info & BTUSB_DIGIANSWER ) {
data - > cmdreq_type = USB_TYPE_VENDOR ;
2012-05-23 14:35:46 +04:00
set_bit ( HCI_QUIRK_RESET_ON_CLOSE , & hdev - > quirks ) ;
2008-11-30 14:17:26 +03:00
}
if ( id - > driver_info & BTUSB_CSR ) {
struct usb_device * udev = data - > udev ;
/* Old firmware would otherwise execute USB reset */
if ( le16_to_cpu ( udev - > descriptor . bcdDevice ) < 0x117 )
2012-05-23 14:35:46 +04:00
set_bit ( HCI_QUIRK_RESET_ON_CLOSE , & hdev - > quirks ) ;
2008-11-30 14:17:26 +03:00
}
2008-08-08 00:26:56 +04:00
if ( id - > driver_info & BTUSB_SNIFFER ) {
2008-08-18 15:23:52 +04:00
struct usb_device * udev = data - > udev ;
2008-08-08 00:26:56 +04:00
2008-11-30 14:17:26 +03:00
/* New sniffer firmware has crippled HCI interface */
2008-08-08 00:26:56 +04:00
if ( le16_to_cpu ( udev - > descriptor . bcdDevice ) > 0x997 )
set_bit ( HCI_QUIRK_RAW_DEVICE , & hdev - > quirks ) ;
2008-08-18 15:23:52 +04:00
data - > isoc = NULL ;
2008-08-08 00:26:56 +04:00
}
2008-08-18 15:23:52 +04:00
if ( data - > isoc ) {
err = usb_driver_claim_interface ( & btusb_driver ,
2008-09-23 02:16:36 +04:00
data - > isoc , data ) ;
2008-08-18 15:23:52 +04:00
if ( err < 0 ) {
hci_free_dev ( hdev ) ;
return err ;
}
}
2007-10-20 16:12:34 +04:00
err = hci_register_dev ( hdev ) ;
if ( err < 0 ) {
hci_free_dev ( hdev ) ;
return err ;
}
usb_set_intfdata ( intf , data ) ;
return 0 ;
}
static void btusb_disconnect ( struct usb_interface * intf )
{
struct btusb_data * data = usb_get_intfdata ( intf ) ;
struct hci_dev * hdev ;
BT_DBG ( " intf %p " , intf ) ;
if ( ! data )
return ;
hdev = data - > hdev ;
2008-09-23 02:16:36 +04:00
usb_set_intfdata ( data - > intf , NULL ) ;
if ( data - > isoc )
usb_set_intfdata ( data - > isoc , NULL ) ;
2007-10-20 16:12:34 +04:00
hci_unregister_dev ( hdev ) ;
2008-09-23 02:16:36 +04:00
if ( intf = = data - > isoc )
usb_driver_release_interface ( & btusb_driver , data - > intf ) ;
else if ( data - > isoc )
usb_driver_release_interface ( & btusb_driver , data - > isoc ) ;
2007-10-20 16:12:34 +04:00
hci_free_dev ( hdev ) ;
}
2009-08-25 01:44:59 +04:00
# ifdef CONFIG_PM
2008-11-30 14:17:14 +03:00
static int btusb_suspend ( struct usb_interface * intf , pm_message_t message )
{
struct btusb_data * data = usb_get_intfdata ( intf ) ;
BT_DBG ( " intf %p " , intf ) ;
if ( data - > suspend_count + + )
return 0 ;
2009-08-25 01:44:59 +04:00
spin_lock_irq ( & data - > txlock ) ;
2011-08-20 01:49:48 +04:00
if ( ! ( PMSG_IS_AUTO ( message ) & & data - > tx_in_flight ) ) {
2009-08-25 01:44:59 +04:00
set_bit ( BTUSB_SUSPENDING , & data - > flags ) ;
spin_unlock_irq ( & data - > txlock ) ;
} else {
spin_unlock_irq ( & data - > txlock ) ;
data - > suspend_count - - ;
return - EBUSY ;
}
2008-11-30 14:17:14 +03:00
cancel_work_sync ( & data - > work ) ;
2009-08-25 01:44:59 +04:00
btusb_stop_traffic ( data ) ;
2008-11-30 14:17:14 +03:00
usb_kill_anchored_urbs ( & data - > tx_anchor ) ;
return 0 ;
}
2009-08-25 01:44:59 +04:00
static void play_deferred ( struct btusb_data * data )
{
struct urb * urb ;
int err ;
while ( ( urb = usb_get_from_anchor ( & data - > deferred ) ) ) {
err = usb_submit_urb ( urb , GFP_ATOMIC ) ;
if ( err < 0 )
break ;
data - > tx_in_flight + + ;
}
usb_scuttle_anchored_urbs ( & data - > deferred ) ;
}
2008-11-30 14:17:14 +03:00
static int btusb_resume ( struct usb_interface * intf )
{
struct btusb_data * data = usb_get_intfdata ( intf ) ;
struct hci_dev * hdev = data - > hdev ;
2009-08-25 01:44:59 +04:00
int err = 0 ;
2008-11-30 14:17:14 +03:00
BT_DBG ( " intf %p " , intf ) ;
if ( - - data - > suspend_count )
return 0 ;
if ( ! test_bit ( HCI_RUNNING , & hdev - > flags ) )
2009-08-25 01:44:59 +04:00
goto done ;
2008-11-30 14:17:14 +03:00
if ( test_bit ( BTUSB_INTR_RUNNING , & data - > flags ) ) {
err = btusb_submit_intr_urb ( hdev , GFP_NOIO ) ;
if ( err < 0 ) {
clear_bit ( BTUSB_INTR_RUNNING , & data - > flags ) ;
2009-08-25 01:44:59 +04:00
goto failed ;
2008-11-30 14:17:14 +03:00
}
}
if ( test_bit ( BTUSB_BULK_RUNNING , & data - > flags ) ) {
2009-02-04 19:41:38 +03:00
err = btusb_submit_bulk_urb ( hdev , GFP_NOIO ) ;
if ( err < 0 ) {
2008-11-30 14:17:14 +03:00
clear_bit ( BTUSB_BULK_RUNNING , & data - > flags ) ;
2009-08-25 01:44:59 +04:00
goto failed ;
}
btusb_submit_bulk_urb ( hdev , GFP_NOIO ) ;
2008-11-30 14:17:14 +03:00
}
if ( test_bit ( BTUSB_ISOC_RUNNING , & data - > flags ) ) {
if ( btusb_submit_isoc_urb ( hdev , GFP_NOIO ) < 0 )
clear_bit ( BTUSB_ISOC_RUNNING , & data - > flags ) ;
else
btusb_submit_isoc_urb ( hdev , GFP_NOIO ) ;
}
2009-08-25 01:44:59 +04:00
spin_lock_irq ( & data - > txlock ) ;
play_deferred ( data ) ;
clear_bit ( BTUSB_SUSPENDING , & data - > flags ) ;
spin_unlock_irq ( & data - > txlock ) ;
schedule_work ( & data - > work ) ;
2008-11-30 14:17:14 +03:00
return 0 ;
2009-08-25 01:44:59 +04:00
failed :
usb_scuttle_anchored_urbs ( & data - > deferred ) ;
done :
spin_lock_irq ( & data - > txlock ) ;
clear_bit ( BTUSB_SUSPENDING , & data - > flags ) ;
spin_unlock_irq ( & data - > txlock ) ;
return err ;
2008-11-30 14:17:14 +03:00
}
2009-08-25 01:44:59 +04:00
# endif
2008-11-30 14:17:14 +03:00
2007-10-20 16:12:34 +04:00
static struct usb_driver btusb_driver = {
. name = " btusb " ,
. probe = btusb_probe ,
. disconnect = btusb_disconnect ,
2009-08-25 01:44:59 +04:00
# ifdef CONFIG_PM
2008-11-30 14:17:14 +03:00
. suspend = btusb_suspend ,
. resume = btusb_resume ,
2013-05-21 19:32:06 +04:00
. reset_resume = btusb_resume ,
2009-08-25 01:44:59 +04:00
# endif
2007-10-20 16:12:34 +04:00
. id_table = btusb_table ,
2009-08-25 01:44:59 +04:00
. supports_autosuspend = 1 ,
2012-04-23 21:08:51 +04:00
. disable_hub_initiated_lpm = 1 ,
2007-10-20 16:12:34 +04:00
} ;
2011-11-18 21:47:34 +04:00
module_usb_driver ( btusb_driver ) ;
2007-10-20 16:12:34 +04:00
2008-08-08 00:26:56 +04:00
module_param ( ignore_dga , bool , 0644 ) ;
MODULE_PARM_DESC ( ignore_dga , " Ignore devices with id 08fd:0001 " ) ;
module_param ( ignore_csr , bool , 0644 ) ;
MODULE_PARM_DESC ( ignore_csr , " Ignore devices with id 0a12:0001 " ) ;
module_param ( ignore_sniffer , bool , 0644 ) ;
MODULE_PARM_DESC ( ignore_sniffer , " Ignore devices with id 0a12:0002 " ) ;
module_param ( disable_scofix , bool , 0644 ) ;
MODULE_PARM_DESC ( disable_scofix , " Disable fixup of wrong SCO buffer size " ) ;
module_param ( force_scofix , bool , 0644 ) ;
MODULE_PARM_DESC ( force_scofix , " Force fixup of wrong SCO buffers size " ) ;
module_param ( reset , bool , 0644 ) ;
MODULE_PARM_DESC ( reset , " Send HCI reset command on initialization " ) ;
2007-10-20 16:12:34 +04:00
MODULE_AUTHOR ( " Marcel Holtmann <marcel@holtmann.org> " ) ;
MODULE_DESCRIPTION ( " Generic Bluetooth USB driver ver " VERSION ) ;
MODULE_VERSION ( VERSION ) ;
MODULE_LICENSE ( " GPL " ) ;