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>
# 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 {
unsigned int rom_version ;
unsigned int build_version ;
unsigned int ram_version ;
unsigned char ref_clock ;
unsigned char reserved [ 0x07 ] ;
} ;
2010-01-06 16:34:15 +03:00
static struct usb_device_id ath3k_table [ ] = {
/* Atheros AR3011 */
{ USB_DEVICE ( 0x0CF3 , 0x3000 ) } ,
2010-11-26 15:05:46 +03:00
/* Atheros AR3011 with sflash firmware*/
{ 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 ) } ,
2011-07-13 19:04:29 +04:00
{ USB_DEVICE ( 0x0930 , 0x0215 ) } ,
2011-11-30 14:32:37 +04:00
{ USB_DEVICE ( 0x0489 , 0xE03D ) } ,
2012-11-06 23:19:11 +04:00
{ USB_DEVICE ( 0x0489 , 0xE027 ) } ,
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*/
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 ) } ,
2013-03-18 19:45:11 +04:00
{ USB_DEVICE ( 0x0CF3 , 0x817a ) } ,
2011-12-06 02:15:29 +04:00
{ USB_DEVICE ( 0x13d3 , 0x3375 ) } ,
2013-02-19 20:54:16 +04:00
{ USB_DEVICE ( 0x04CA , 0x3004 ) } ,
2012-03-28 06:25:36 +04:00
{ USB_DEVICE ( 0x04CA , 0x3005 ) } ,
2012-12-29 14:14:34 +04:00
{ USB_DEVICE ( 0x04CA , 0x3006 ) } ,
2013-01-10 04:06:55 +04:00
{ USB_DEVICE ( 0x04CA , 0x3008 ) } ,
2012-04-13 13:39:57 +04:00
{ USB_DEVICE ( 0x13d3 , 0x3362 ) } ,
2012-04-19 10:53:45 +04:00
{ USB_DEVICE ( 0x0CF3 , 0xE004 ) } ,
2012-06-10 10:33:11 +04:00
{ USB_DEVICE ( 0x0930 , 0x0219 ) } ,
2012-08-01 06:11:59 +04:00
{ USB_DEVICE ( 0x0489 , 0xe057 ) } ,
2012-12-11 07:41:20 +04:00
{ USB_DEVICE ( 0x13d3 , 0x3393 ) } ,
2013-01-03 08:24:59 +04:00
{ USB_DEVICE ( 0x0489 , 0xe04e ) } ,
2013-01-03 08:25:00 +04:00
{ USB_DEVICE ( 0x0489 , 0xe056 ) } ,
2013-03-24 18:41:10 +04:00
{ USB_DEVICE ( 0x0489 , 0xe04d ) } ,
2013-07-03 04:53:54 +04:00
{ USB_DEVICE ( 0x04c5 , 0x1330 ) } ,
2013-07-15 07:59:03 +04:00
{ USB_DEVICE ( 0x13d3 , 0x3402 ) } ,
2013-07-17 07:27:40 +04:00
{ USB_DEVICE ( 0x0cf3 , 0x3121 ) } ,
2013-06-20 09:38:45 +04:00
{ USB_DEVICE ( 0x0cf3 , 0xe003 ) } ,
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 */
{ USB_DEVICE ( 0x0489 , 0xE03C ) } ,
2012-08-07 18:18:10 +04:00
{ USB_DEVICE ( 0x0489 , 0xE036 ) } ,
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
* for AR3012 */
static struct usb_device_id ath3k_blist_tbl [ ] = {
/* Atheros AR3012 with sflash firmware*/
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 } ,
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 } ,
2013-07-03 04:53:54 +04:00
{ USB_DEVICE ( 0x04c5 , 0x1330 ) , . driver_info = BTUSB_ATH3012 } ,
2013-07-15 07:59:03 +04:00
{ USB_DEVICE ( 0x13d3 , 0x3402 ) , . driver_info = BTUSB_ATH3012 } ,
2013-07-17 07:27:40 +04:00
{ USB_DEVICE ( 0x0cf3 , 0x3121 ) , . driver_info = BTUSB_ATH3012 } ,
2013-06-20 09:38:45 +04:00
{ USB_DEVICE ( 0x0cf3 , 0xe003 ) , . 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 */
{ 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
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
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 ;
int err , pipe , len , 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 ) ;
if ( ( err = usb_control_msg ( udev , pipe ,
2010-01-06 16:34:15 +03:00
USB_REQ_DFU_DNLOAD ,
USB_TYPE_VENDOR , 0 , 0 ,
2010-11-22 23:09:01 +03:00
send_buf , 20 , USB_CTRL_SET_TIMEOUT ) ) < 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 ;
while ( count ) {
size = min_t ( uint , count , BULK_SIZE ) ;
2010-11-22 23:09:01 +03:00
pipe = usb_sndbulkpipe ( udev , 0x02 ) ;
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 ;
int err , pipe , len , size , count , sent = 0 ;
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 ;
while ( count ) {
size = min_t ( uint , count , BULK_SIZE ) ;
pipe = usb_sndbulkpipe ( udev , 0x02 ) ;
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 ;
struct ath3k_version fw_version , pt_version ;
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 " ,
fw_version . rom_version ) ;
ret = request_firmware ( & firmware , filename , & udev - > dev ) ;
if ( ret < 0 ) {
BT_ERR ( " Patch file not found %s " , filename ) ;
return ret ;
}
pt_version . rom_version = * ( int * ) ( firmware - > data + firmware - > size - 8 ) ;
pt_version . build_version = * ( int * )
( firmware - > data + firmware - > size - 4 ) ;
if ( ( pt_version . rom_version ! = fw_version . rom_version ) | |
( pt_version . build_version < = fw_version . build_version ) ) {
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 " ,
fw_version . rom_version , clk_value , " .dfu " ) ;
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 ;
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 ) ;