2010-01-06 16:34:15 +03:00
/*
* Copyright ( c ) 2008 - 2009 Atheros Communications Inc .
*
* 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/kernel.h>
# include <linux/init.h>
# include <linux/slab.h>
# include <linux/types.h>
# include <linux/errno.h>
# include <linux/device.h>
# include <linux/firmware.h>
# include <linux/usb.h>
2014-07-20 19:29:59 +04:00
# include <asm/unaligned.h>
2010-01-06 16:34:15 +03:00
# include <net/bluetooth/bluetooth.h>
# define VERSION "1.0"
2011-10-29 21:52:49 +04:00
# define ATH3K_FIRMWARE "ath3k-1.fw"
2010-01-06 16:34:15 +03:00
2011-02-11 13:08:53 +03:00
# define ATH3K_DNLOAD 0x01
# define ATH3K_GETSTATE 0x05
# define ATH3K_SET_NORMAL_MODE 0x07
# define ATH3K_GETVERSION 0x09
# define USB_REG_SWITCH_VID_PID 0x0a
# define ATH3K_MODE_MASK 0x3F
# define ATH3K_NORMAL_MODE 0x0E
# define ATH3K_PATCH_UPDATE 0x80
# define ATH3K_SYSCFG_UPDATE 0x40
# define ATH3K_XTAL_FREQ_26M 0x00
# define ATH3K_XTAL_FREQ_40M 0x01
# define ATH3K_XTAL_FREQ_19P2 0x02
# define ATH3K_NAME_LEN 0xFF
struct ath3k_version {
2014-07-20 19:29:59 +04:00
__le32 rom_version ;
__le32 build_version ;
__le32 ram_version ;
__u8 ref_clock ;
__u8 reserved [ 7 ] ;
} __packed ;
2010-01-06 16:34:15 +03:00
2013-10-11 18:46:21 +04:00
static const struct usb_device_id ath3k_table [ ] = {
2010-01-06 16:34:15 +03:00
/* Atheros AR3011 */
{ USB_DEVICE ( 0x0CF3 , 0x3000 ) } ,
2010-11-26 15:05:46 +03:00
/* Atheros AR3011 with sflash firmware*/
2014-02-18 20:26:19 +04:00
{ USB_DEVICE ( 0x0489 , 0xE027 ) } ,
{ USB_DEVICE ( 0x0489 , 0xE03D ) } ,
2015-02-13 22:05:11 +03:00
{ USB_DEVICE ( 0x04F2 , 0xAFF1 ) } ,
2014-02-18 20:26:19 +04:00
{ USB_DEVICE ( 0x0930 , 0x0215 ) } ,
2010-11-26 15:05:46 +03:00
{ USB_DEVICE ( 0x0CF3 , 0x3002 ) } ,
2012-06-08 16:32:50 +04:00
{ USB_DEVICE ( 0x0CF3 , 0xE019 ) } ,
2011-05-10 03:11:16 +04:00
{ USB_DEVICE ( 0x13d3 , 0x3304 ) } ,
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 ) } ,
2011-02-11 13:08:53 +03:00
/* Atheros AR3012 with sflash firmware*/
2014-02-18 20:26:19 +04:00
{ USB_DEVICE ( 0x0489 , 0xe04d ) } ,
{ USB_DEVICE ( 0x0489 , 0xe04e ) } ,
{ USB_DEVICE ( 0x0489 , 0xe057 ) } ,
{ USB_DEVICE ( 0x0489 , 0xe056 ) } ,
{ USB_DEVICE ( 0x0489 , 0xe05f ) } ,
2015-06-06 20:25:40 +03:00
{ USB_DEVICE ( 0x0489 , 0xe076 ) } ,
2014-10-06 15:01:49 +04:00
{ USB_DEVICE ( 0x0489 , 0xe078 ) } ,
2016-02-10 00:49:11 +03:00
{ USB_DEVICE ( 0x0489 , 0xe095 ) } ,
2014-02-18 20:26:19 +04:00
{ USB_DEVICE ( 0x04c5 , 0x1330 ) } ,
{ USB_DEVICE ( 0x04CA , 0x3004 ) } ,
{ USB_DEVICE ( 0x04CA , 0x3005 ) } ,
{ USB_DEVICE ( 0x04CA , 0x3006 ) } ,
2014-04-17 22:37:13 +04:00
{ USB_DEVICE ( 0x04CA , 0x3007 ) } ,
2014-02-18 20:26:19 +04:00
{ USB_DEVICE ( 0x04CA , 0x3008 ) } ,
{ USB_DEVICE ( 0x04CA , 0x300b ) } ,
2015-06-18 20:41:51 +03:00
{ USB_DEVICE ( 0x04CA , 0x300d ) } ,
2015-05-02 13:36:58 +03:00
{ USB_DEVICE ( 0x04CA , 0x300f ) } ,
2014-12-09 08:44:51 +03:00
{ USB_DEVICE ( 0x04CA , 0x3010 ) } ,
2016-02-28 11:04:06 +03:00
{ USB_DEVICE ( 0x04CA , 0x3014 ) } ,
2017-01-05 13:19:53 +03:00
{ USB_DEVICE ( 0x04CA , 0x3018 ) } ,
2014-02-18 20:26:19 +04:00
{ USB_DEVICE ( 0x0930 , 0x0219 ) } ,
2015-10-05 19:29:33 +03:00
{ USB_DEVICE ( 0x0930 , 0x021c ) } ,
2014-02-18 20:26:19 +04:00
{ USB_DEVICE ( 0x0930 , 0x0220 ) } ,
2014-08-08 15:33:56 +04:00
{ USB_DEVICE ( 0x0930 , 0x0227 ) } ,
2014-02-18 20:26:20 +04:00
{ USB_DEVICE ( 0x0b05 , 0x17d0 ) } ,
2013-03-15 07:00:39 +04:00
{ USB_DEVICE ( 0x0CF3 , 0x0036 ) } ,
2011-02-11 13:08:53 +03:00
{ USB_DEVICE ( 0x0CF3 , 0x3004 ) } ,
2013-03-11 23:41:58 +04:00
{ USB_DEVICE ( 0x0CF3 , 0x3008 ) } ,
2012-03-15 00:01:21 +04:00
{ USB_DEVICE ( 0x0CF3 , 0x311D ) } ,
2014-01-16 18:37:11 +04:00
{ USB_DEVICE ( 0x0CF3 , 0x311E ) } ,
2014-01-16 19:02:58 +04:00
{ USB_DEVICE ( 0x0CF3 , 0x311F ) } ,
2014-02-18 20:26:19 +04:00
{ USB_DEVICE ( 0x0cf3 , 0x3121 ) } ,
2013-03-18 19:45:11 +04:00
{ USB_DEVICE ( 0x0CF3 , 0x817a ) } ,
2015-10-16 11:45:26 +03:00
{ USB_DEVICE ( 0x0CF3 , 0x817b ) } ,
2014-02-18 20:26:19 +04:00
{ USB_DEVICE ( 0x0cf3 , 0xe003 ) } ,
2012-04-19 10:53:45 +04:00
{ USB_DEVICE ( 0x0CF3 , 0xE004 ) } ,
2013-08-30 13:41:40 +04:00
{ USB_DEVICE ( 0x0CF3 , 0xE005 ) } ,
2015-05-13 06:39:24 +03:00
{ USB_DEVICE ( 0x0CF3 , 0xE006 ) } ,
2014-02-18 20:26:19 +04:00
{ USB_DEVICE ( 0x13d3 , 0x3362 ) } ,
{ USB_DEVICE ( 0x13d3 , 0x3375 ) } ,
2012-12-11 07:41:20 +04:00
{ USB_DEVICE ( 0x13d3 , 0x3393 ) } ,
2016-02-10 15:33:17 +03:00
{ USB_DEVICE ( 0x13d3 , 0x3395 ) } ,
2013-07-15 07:59:03 +04:00
{ USB_DEVICE ( 0x13d3 , 0x3402 ) } ,
2014-11-25 20:19:52 +03:00
{ USB_DEVICE ( 0x13d3 , 0x3408 ) } ,
2015-01-18 00:16:51 +03:00
{ USB_DEVICE ( 0x13d3 , 0x3423 ) } ,
2014-07-08 17:55:08 +04:00
{ USB_DEVICE ( 0x13d3 , 0x3432 ) } ,
2016-03-04 01:32:19 +03:00
{ USB_DEVICE ( 0x13d3 , 0x3472 ) } ,
2015-06-06 20:29:25 +03:00
{ USB_DEVICE ( 0x13d3 , 0x3474 ) } ,
2016-05-09 23:36:11 +03:00
{ USB_DEVICE ( 0x13d3 , 0x3487 ) } ,
2016-07-12 01:35:18 +03:00
{ USB_DEVICE ( 0x13d3 , 0x3490 ) } ,
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 ) } ,
2011-02-19 01:03:41 +03:00
2012-05-03 00:33:40 +04:00
/* Atheros AR5BBU22 with sflash firmware */
2012-08-07 18:18:10 +04:00
{ USB_DEVICE ( 0x0489 , 0xE036 ) } ,
2014-02-18 20:26:19 +04:00
{ USB_DEVICE ( 0x0489 , 0xE03C ) } ,
2012-05-03 00:33:40 +04:00
2010-01-06 16:34:15 +03:00
{ } /* Terminating entry */
} ;
MODULE_DEVICE_TABLE ( usb , ath3k_table ) ;
2011-02-11 13:08:53 +03:00
# define BTUSB_ATH3012 0x80
/* This table is to load patch and sysconfig files
2017-07-22 04:47:07 +03:00
* for AR3012
*/
2013-10-11 18:46:21 +04:00
static const struct usb_device_id ath3k_blist_tbl [ ] = {
2011-02-11 13:08:53 +03:00
/* Atheros AR3012 with sflash firmware*/
2014-02-18 20:26:19 +04:00
{ USB_DEVICE ( 0x0489 , 0xe04e ) , . driver_info = BTUSB_ATH3012 } ,
{ USB_DEVICE ( 0x0489 , 0xe04d ) , . driver_info = BTUSB_ATH3012 } ,
{ USB_DEVICE ( 0x0489 , 0xe056 ) , . driver_info = BTUSB_ATH3012 } ,
{ USB_DEVICE ( 0x0489 , 0xe057 ) , . driver_info = BTUSB_ATH3012 } ,
{ USB_DEVICE ( 0x0489 , 0xe05f ) , . driver_info = BTUSB_ATH3012 } ,
2015-06-06 20:25:40 +03:00
{ USB_DEVICE ( 0x0489 , 0xe076 ) , . driver_info = BTUSB_ATH3012 } ,
2014-10-06 15:01:49 +04:00
{ USB_DEVICE ( 0x0489 , 0xe078 ) , . driver_info = BTUSB_ATH3012 } ,
2016-02-10 00:49:11 +03:00
{ USB_DEVICE ( 0x0489 , 0xe095 ) , . driver_info = BTUSB_ATH3012 } ,
2014-02-18 20:26:19 +04:00
{ USB_DEVICE ( 0x04c5 , 0x1330 ) , . driver_info = BTUSB_ATH3012 } ,
{ USB_DEVICE ( 0x04ca , 0x3004 ) , . driver_info = BTUSB_ATH3012 } ,
{ USB_DEVICE ( 0x04ca , 0x3005 ) , . driver_info = BTUSB_ATH3012 } ,
{ USB_DEVICE ( 0x04ca , 0x3006 ) , . driver_info = BTUSB_ATH3012 } ,
2014-04-17 22:37:13 +04:00
{ USB_DEVICE ( 0x04ca , 0x3007 ) , . driver_info = BTUSB_ATH3012 } ,
2014-02-18 20:26:19 +04:00
{ USB_DEVICE ( 0x04ca , 0x3008 ) , . driver_info = BTUSB_ATH3012 } ,
{ USB_DEVICE ( 0x04ca , 0x300b ) , . driver_info = BTUSB_ATH3012 } ,
2015-06-18 20:41:51 +03:00
{ USB_DEVICE ( 0x04ca , 0x300d ) , . driver_info = BTUSB_ATH3012 } ,
2015-05-02 13:36:58 +03:00
{ USB_DEVICE ( 0x04ca , 0x300f ) , . driver_info = BTUSB_ATH3012 } ,
2014-12-09 08:44:51 +03:00
{ USB_DEVICE ( 0x04ca , 0x3010 ) , . driver_info = BTUSB_ATH3012 } ,
2016-02-28 11:04:06 +03:00
{ USB_DEVICE ( 0x04ca , 0x3014 ) , . driver_info = BTUSB_ATH3012 } ,
2017-01-05 13:19:53 +03:00
{ USB_DEVICE ( 0x04ca , 0x3018 ) , . driver_info = BTUSB_ATH3012 } ,
2014-02-18 20:26:19 +04:00
{ USB_DEVICE ( 0x0930 , 0x0219 ) , . driver_info = BTUSB_ATH3012 } ,
2015-10-05 19:29:33 +03:00
{ USB_DEVICE ( 0x0930 , 0x021c ) , . driver_info = BTUSB_ATH3012 } ,
2014-02-18 20:26:19 +04:00
{ USB_DEVICE ( 0x0930 , 0x0220 ) , . driver_info = BTUSB_ATH3012 } ,
2014-08-08 15:33:56 +04:00
{ USB_DEVICE ( 0x0930 , 0x0227 ) , . driver_info = BTUSB_ATH3012 } ,
2014-02-18 20:26:20 +04:00
{ USB_DEVICE ( 0x0b05 , 0x17d0 ) , . driver_info = BTUSB_ATH3012 } ,
2013-03-15 07:00:39 +04:00
{ USB_DEVICE ( 0x0CF3 , 0x0036 ) , . driver_info = BTUSB_ATH3012 } ,
2011-02-11 13:08:53 +03: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 } ,
2014-01-16 18:37:11 +04:00
{ USB_DEVICE ( 0x0cf3 , 0x311E ) , . driver_info = BTUSB_ATH3012 } ,
2014-01-16 19:02:58 +04:00
{ USB_DEVICE ( 0x0cf3 , 0x311F ) , . driver_info = BTUSB_ATH3012 } ,
2014-02-18 20:26:19 +04:00
{ USB_DEVICE ( 0x0cf3 , 0x3121 ) , . driver_info = BTUSB_ATH3012 } ,
2013-03-18 19:45:11 +04:00
{ USB_DEVICE ( 0x0CF3 , 0x817a ) , . driver_info = BTUSB_ATH3012 } ,
2015-10-16 11:45:26 +03:00
{ USB_DEVICE ( 0x0CF3 , 0x817b ) , . driver_info = BTUSB_ATH3012 } ,
2012-04-19 10:53:45 +04:00
{ USB_DEVICE ( 0x0cf3 , 0xe004 ) , . driver_info = BTUSB_ATH3012 } ,
2013-08-30 13:41:40 +04:00
{ USB_DEVICE ( 0x0cf3 , 0xe005 ) , . driver_info = BTUSB_ATH3012 } ,
2015-05-13 06:39:24 +03:00
{ USB_DEVICE ( 0x0cf3 , 0xe006 ) , . driver_info = BTUSB_ATH3012 } ,
2014-02-18 20:26:19 +04:00
{ USB_DEVICE ( 0x0cf3 , 0xe003 ) , . driver_info = BTUSB_ATH3012 } ,
{ USB_DEVICE ( 0x13d3 , 0x3362 ) , . driver_info = BTUSB_ATH3012 } ,
{ USB_DEVICE ( 0x13d3 , 0x3375 ) , . driver_info = BTUSB_ATH3012 } ,
2012-12-11 07:41:20 +04:00
{ USB_DEVICE ( 0x13d3 , 0x3393 ) , . driver_info = BTUSB_ATH3012 } ,
2016-02-10 15:33:17 +03:00
{ USB_DEVICE ( 0x13d3 , 0x3395 ) , . driver_info = BTUSB_ATH3012 } ,
2013-07-15 07:59:03 +04:00
{ USB_DEVICE ( 0x13d3 , 0x3402 ) , . driver_info = BTUSB_ATH3012 } ,
2014-11-25 20:19:52 +03:00
{ USB_DEVICE ( 0x13d3 , 0x3408 ) , . driver_info = BTUSB_ATH3012 } ,
2015-01-18 00:16:51 +03:00
{ USB_DEVICE ( 0x13d3 , 0x3423 ) , . driver_info = BTUSB_ATH3012 } ,
2014-07-08 17:55:08 +04:00
{ USB_DEVICE ( 0x13d3 , 0x3432 ) , . driver_info = BTUSB_ATH3012 } ,
2016-03-04 01:32:19 +03:00
{ USB_DEVICE ( 0x13d3 , 0x3472 ) , . driver_info = BTUSB_ATH3012 } ,
2015-06-06 20:29:25 +03:00
{ USB_DEVICE ( 0x13d3 , 0x3474 ) , . driver_info = BTUSB_ATH3012 } ,
2016-05-09 23:36:11 +03:00
{ USB_DEVICE ( 0x13d3 , 0x3487 ) , . driver_info = BTUSB_ATH3012 } ,
2016-07-12 01:35:18 +03:00
{ USB_DEVICE ( 0x13d3 , 0x3490 ) , . driver_info = BTUSB_ATH3012 } ,
2011-02-11 13:08:53 +03:00
2012-05-03 00:33:40 +04:00
/* Atheros AR5BBU22 with sflash firmware */
2012-08-07 18:18:10 +04:00
{ USB_DEVICE ( 0x0489 , 0xE036 ) , . driver_info = BTUSB_ATH3012 } ,
2014-02-18 20:26:19 +04:00
{ USB_DEVICE ( 0x0489 , 0xE03C ) , . driver_info = BTUSB_ATH3012 } ,
2012-05-03 00:33:40 +04:00
2011-02-11 13:08:53 +03:00
{ } /* Terminating entry */
} ;
2010-01-06 16:34:15 +03:00
# define USB_REQ_DFU_DNLOAD 1
# define BULK_SIZE 4096
2011-02-11 13:08:53 +03:00
# define FW_HDR_SIZE 20
2015-01-28 23:30:27 +03:00
# define TIMEGAP_USEC_MIN 50
# define TIMEGAP_USEC_MAX 100
2010-01-06 16:34:15 +03:00
2010-11-22 23:09:01 +03:00
static int ath3k_load_firmware ( struct usb_device * udev ,
const struct firmware * firmware )
2010-01-06 16:34:15 +03:00
{
u8 * send_buf ;
2016-04-22 13:02:55 +03:00
int len = 0 ;
int err , pipe , size , sent = 0 ;
2010-11-22 23:09:01 +03:00
int count = firmware - > size ;
2010-01-06 16:34:15 +03:00
2010-11-22 23:09:01 +03:00
BT_DBG ( " udev %p " , udev ) ;
2010-01-06 16:34:15 +03:00
2010-11-22 23:09:01 +03:00
pipe = usb_sndctrlpipe ( udev , 0 ) ;
2010-01-06 16:34:15 +03:00
2011-10-25 14:09:52 +04:00
send_buf = kmalloc ( BULK_SIZE , GFP_KERNEL ) ;
2010-11-22 23:09:01 +03:00
if ( ! send_buf ) {
BT_ERR ( " Can't allocate memory chunk for firmware " ) ;
return - ENOMEM ;
}
memcpy ( send_buf , firmware - > data , 20 ) ;
2013-08-12 19:46:00 +04:00
err = usb_control_msg ( udev , pipe , USB_REQ_DFU_DNLOAD , USB_TYPE_VENDOR ,
0 , 0 , send_buf , 20 , USB_CTRL_SET_TIMEOUT ) ;
if ( err < 0 ) {
2010-01-06 16:34:15 +03:00
BT_ERR ( " Can't change to loading configuration err " ) ;
2010-11-22 23:09:01 +03:00
goto error ;
2010-01-06 16:34:15 +03:00
}
sent + = 20 ;
count - = 20 ;
2014-05-27 09:49:07 +04:00
pipe = usb_sndbulkpipe ( udev , 0x02 ) ;
2010-01-06 16:34:15 +03:00
while ( count ) {
2015-01-28 23:30:27 +03:00
/* workaround the compatibility issue with xHCI controller*/
usleep_range ( TIMEGAP_USEC_MIN , TIMEGAP_USEC_MAX ) ;
2010-01-06 16:34:15 +03:00
size = min_t ( uint , count , BULK_SIZE ) ;
2010-11-22 23:09:01 +03:00
memcpy ( send_buf , firmware - > data + sent , size ) ;
2010-01-06 16:34:15 +03:00
2010-11-22 23:09:01 +03:00
err = usb_bulk_msg ( udev , pipe , send_buf , size ,
2010-01-06 16:34:15 +03:00
& len , 3000 ) ;
if ( err | | ( len ! = size ) ) {
BT_ERR ( " Error in firmware loading err = %d, "
" len = %d, size = %d " , err , len , size ) ;
goto error ;
}
sent + = size ;
count - = size ;
}
error :
kfree ( send_buf ) ;
return err ;
}
2011-02-11 13:08:53 +03:00
static int ath3k_get_state ( struct usb_device * udev , unsigned char * state )
{
2013-07-08 12:27:23 +04:00
int ret , pipe = 0 ;
char * buf ;
buf = kmalloc ( sizeof ( * buf ) , GFP_KERNEL ) ;
if ( ! buf )
return - ENOMEM ;
2011-02-11 13:08:53 +03:00
pipe = usb_rcvctrlpipe ( udev , 0 ) ;
2013-07-08 12:27:23 +04:00
ret = usb_control_msg ( udev , pipe , ATH3K_GETSTATE ,
USB_TYPE_VENDOR | USB_DIR_IN , 0 , 0 ,
buf , sizeof ( * buf ) , USB_CTRL_SET_TIMEOUT ) ;
* state = * buf ;
kfree ( buf ) ;
return ret ;
2011-02-11 13:08:53 +03:00
}
static int ath3k_get_version ( struct usb_device * udev ,
struct ath3k_version * version )
{
2013-07-08 12:27:23 +04:00
int ret , pipe = 0 ;
struct ath3k_version * buf ;
const int size = sizeof ( * buf ) ;
buf = kmalloc ( size , GFP_KERNEL ) ;
if ( ! buf )
return - ENOMEM ;
2011-02-11 13:08:53 +03:00
pipe = usb_rcvctrlpipe ( udev , 0 ) ;
2013-07-08 12:27:23 +04:00
ret = usb_control_msg ( udev , pipe , ATH3K_GETVERSION ,
USB_TYPE_VENDOR | USB_DIR_IN , 0 , 0 ,
buf , size , USB_CTRL_SET_TIMEOUT ) ;
memcpy ( version , buf , size ) ;
kfree ( buf ) ;
return ret ;
2011-02-11 13:08:53 +03:00
}
static int ath3k_load_fwfile ( struct usb_device * udev ,
const struct firmware * firmware )
{
u8 * send_buf ;
2016-04-22 13:02:55 +03:00
int len = 0 ;
int err , pipe , size , count , sent = 0 ;
2011-02-11 13:08:53 +03:00
int ret ;
count = firmware - > size ;
2011-10-25 14:09:52 +04:00
send_buf = kmalloc ( BULK_SIZE , GFP_KERNEL ) ;
2011-02-11 13:08:53 +03:00
if ( ! send_buf ) {
BT_ERR ( " Can't allocate memory chunk for firmware " ) ;
return - ENOMEM ;
}
size = min_t ( uint , count , FW_HDR_SIZE ) ;
memcpy ( send_buf , firmware - > data , size ) ;
pipe = usb_sndctrlpipe ( udev , 0 ) ;
ret = usb_control_msg ( udev , pipe , ATH3K_DNLOAD ,
USB_TYPE_VENDOR , 0 , 0 , send_buf ,
size , USB_CTRL_SET_TIMEOUT ) ;
if ( ret < 0 ) {
BT_ERR ( " Can't change to loading configuration err " ) ;
kfree ( send_buf ) ;
return ret ;
}
sent + = size ;
count - = size ;
2014-06-05 17:47:44 +04:00
pipe = usb_sndbulkpipe ( udev , 0x02 ) ;
2011-02-11 13:08:53 +03:00
while ( count ) {
2015-01-28 23:30:27 +03:00
/* workaround the compatibility issue with xHCI controller*/
usleep_range ( TIMEGAP_USEC_MIN , TIMEGAP_USEC_MAX ) ;
2011-02-11 13:08:53 +03:00
size = min_t ( uint , count , BULK_SIZE ) ;
memcpy ( send_buf , firmware - > data + sent , size ) ;
err = usb_bulk_msg ( udev , pipe , send_buf , size ,
& len , 3000 ) ;
if ( err | | ( len ! = size ) ) {
BT_ERR ( " Error in firmware loading err = %d, "
" len = %d, size = %d " , err , len , size ) ;
kfree ( send_buf ) ;
return err ;
}
sent + = size ;
count - = size ;
}
kfree ( send_buf ) ;
return 0 ;
}
static int ath3k_switch_pid ( struct usb_device * udev )
{
int pipe = 0 ;
pipe = usb_sndctrlpipe ( udev , 0 ) ;
return usb_control_msg ( udev , pipe , USB_REG_SWITCH_VID_PID ,
USB_TYPE_VENDOR , 0 , 0 ,
NULL , 0 , USB_CTRL_SET_TIMEOUT ) ;
}
static int ath3k_set_normal_mode ( struct usb_device * udev )
{
unsigned char fw_state ;
int pipe = 0 , ret ;
ret = ath3k_get_state ( udev , & fw_state ) ;
if ( ret < 0 ) {
BT_ERR ( " Can't get state to change to normal mode err " ) ;
return ret ;
}
if ( ( fw_state & ATH3K_MODE_MASK ) = = ATH3K_NORMAL_MODE ) {
BT_DBG ( " firmware was already in normal mode " ) ;
return 0 ;
}
pipe = usb_sndctrlpipe ( udev , 0 ) ;
return usb_control_msg ( udev , pipe , ATH3K_SET_NORMAL_MODE ,
USB_TYPE_VENDOR , 0 , 0 ,
NULL , 0 , USB_CTRL_SET_TIMEOUT ) ;
}
static int ath3k_load_patch ( struct usb_device * udev )
{
unsigned char fw_state ;
char filename [ ATH3K_NAME_LEN ] = { 0 } ;
const struct firmware * firmware ;
2014-07-20 19:29:59 +04:00
struct ath3k_version fw_version ;
__u32 pt_rom_version , pt_build_version ;
2011-02-11 13:08:53 +03:00
int ret ;
ret = ath3k_get_state ( udev , & fw_state ) ;
if ( ret < 0 ) {
BT_ERR ( " Can't get state to change to load ram patch err " ) ;
return ret ;
}
if ( fw_state & ATH3K_PATCH_UPDATE ) {
BT_DBG ( " Patch was already downloaded " ) ;
return 0 ;
}
ret = ath3k_get_version ( udev , & fw_version ) ;
if ( ret < 0 ) {
BT_ERR ( " Can't get version to change to load ram patch err " ) ;
return ret ;
}
snprintf ( filename , ATH3K_NAME_LEN , " ar3k/AthrBT_0x%08x.dfu " ,
2014-07-20 19:29:59 +04:00
le32_to_cpu ( fw_version . rom_version ) ) ;
2011-02-11 13:08:53 +03:00
ret = request_firmware ( & firmware , filename , & udev - > dev ) ;
if ( ret < 0 ) {
BT_ERR ( " Patch file not found %s " , filename ) ;
return ret ;
}
2014-07-20 19:29:59 +04:00
pt_rom_version = get_unaligned_le32 ( firmware - > data +
firmware - > size - 8 ) ;
pt_build_version = get_unaligned_le32 ( firmware - > data +
firmware - > size - 4 ) ;
2011-02-11 13:08:53 +03:00
2014-07-20 19:29:59 +04:00
if ( pt_rom_version ! = le32_to_cpu ( fw_version . rom_version ) | |
pt_build_version < = le32_to_cpu ( fw_version . build_version ) ) {
2011-02-11 13:08:53 +03:00
BT_ERR ( " Patch file version did not match with firmware " ) ;
release_firmware ( firmware ) ;
return - EINVAL ;
}
ret = ath3k_load_fwfile ( udev , firmware ) ;
release_firmware ( firmware ) ;
return ret ;
}
static int ath3k_load_syscfg ( struct usb_device * udev )
{
unsigned char fw_state ;
char filename [ ATH3K_NAME_LEN ] = { 0 } ;
const struct firmware * firmware ;
struct ath3k_version fw_version ;
int clk_value , ret ;
ret = ath3k_get_state ( udev , & fw_state ) ;
if ( ret < 0 ) {
2012-12-28 21:00:09 +04:00
BT_ERR ( " Can't get state to change to load configuration err " ) ;
2011-02-11 13:08:53 +03:00
return - EBUSY ;
}
ret = ath3k_get_version ( udev , & fw_version ) ;
if ( ret < 0 ) {
BT_ERR ( " Can't get version to change to load ram patch err " ) ;
return ret ;
}
switch ( fw_version . ref_clock ) {
case ATH3K_XTAL_FREQ_26M :
clk_value = 26 ;
break ;
case ATH3K_XTAL_FREQ_40M :
clk_value = 40 ;
break ;
case ATH3K_XTAL_FREQ_19P2 :
clk_value = 19 ;
break ;
default :
clk_value = 0 ;
break ;
}
snprintf ( filename , ATH3K_NAME_LEN , " ar3k/ramps_0x%08x_%d%s " ,
2012-09-06 15:30:43 +04:00
le32_to_cpu ( fw_version . rom_version ) , clk_value , " .dfu " ) ;
2011-02-11 13:08:53 +03:00
ret = request_firmware ( & firmware , filename , & udev - > dev ) ;
if ( ret < 0 ) {
BT_ERR ( " Configuration file not found %s " , filename ) ;
return ret ;
}
ret = ath3k_load_fwfile ( udev , firmware ) ;
release_firmware ( firmware ) ;
return ret ;
}
2010-01-06 16:34:15 +03:00
static int ath3k_probe ( struct usb_interface * intf ,
const struct usb_device_id * id )
{
const struct firmware * firmware ;
struct usb_device * udev = interface_to_usbdev ( intf ) ;
2011-02-03 06:42:05 +03:00
int ret ;
2010-01-06 16:34:15 +03:00
BT_DBG ( " intf %p id %p " , intf , id ) ;
if ( intf - > cur_altsetting - > desc . bInterfaceNumber ! = 0 )
return - ENODEV ;
2011-02-11 13:08:53 +03:00
/* match device ID in ath3k blacklist table */
if ( ! id - > driver_info ) {
const struct usb_device_id * match ;
2016-01-12 19:40:15 +03:00
2011-02-11 13:08:53 +03:00
match = usb_match_id ( intf , ath3k_blist_tbl ) ;
if ( match )
id = match ;
}
/* load patch and sysconfig files for AR3012 */
if ( id - > driver_info & BTUSB_ATH3012 ) {
2011-07-01 10:02:36 +04:00
/* New firmware with patch and sysconfig files already loaded */
if ( le16_to_cpu ( udev - > descriptor . bcdDevice ) > 0x0001 )
return - ENODEV ;
2011-02-11 13:08:53 +03:00
ret = ath3k_load_patch ( udev ) ;
if ( ret < 0 ) {
BT_ERR ( " Loading patch file failed " ) ;
return ret ;
}
ret = ath3k_load_syscfg ( udev ) ;
if ( ret < 0 ) {
BT_ERR ( " Loading sysconfig file failed " ) ;
return ret ;
}
ret = ath3k_set_normal_mode ( udev ) ;
if ( ret < 0 ) {
BT_ERR ( " Set normal mode failed " ) ;
return ret ;
}
ath3k_switch_pid ( udev ) ;
return 0 ;
}
2011-10-29 21:52:49 +04:00
ret = request_firmware ( & firmware , ATH3K_FIRMWARE , & udev - > dev ) ;
if ( ret < 0 ) {
if ( ret = = - ENOENT )
BT_ERR ( " Firmware file \" %s \" not found " ,
ATH3K_FIRMWARE ) ;
else
BT_ERR ( " Firmware file \" %s \" request failed (err=%d) " ,
ATH3K_FIRMWARE , ret ) ;
return ret ;
2010-01-06 16:34:15 +03:00
}
2011-02-03 06:42:05 +03:00
ret = ath3k_load_firmware ( udev , firmware ) ;
2010-11-22 23:09:01 +03:00
release_firmware ( firmware ) ;
2010-01-06 16:34:15 +03:00
2011-02-03 06:42:05 +03:00
return ret ;
2010-01-06 16:34:15 +03:00
}
static void ath3k_disconnect ( struct usb_interface * intf )
{
BT_DBG ( " ath3k_disconnect intf %p " , intf ) ;
}
static struct usb_driver ath3k_driver = {
. name = " ath3k " ,
. probe = ath3k_probe ,
. disconnect = ath3k_disconnect ,
. id_table = ath3k_table ,
2012-04-23 21:08:51 +04:00
. disable_hub_initiated_lpm = 1 ,
2010-01-06 16:34:15 +03:00
} ;
2011-11-18 21:47:34 +04:00
module_usb_driver ( ath3k_driver ) ;
2010-01-06 16:34:15 +03:00
MODULE_AUTHOR ( " Atheros Communications " ) ;
MODULE_DESCRIPTION ( " Atheros AR30xx firmware driver " ) ;
MODULE_VERSION ( VERSION ) ;
MODULE_LICENSE ( " GPL " ) ;
2011-10-29 21:52:49 +04:00
MODULE_FIRMWARE ( ATH3K_FIRMWARE ) ;