2022-06-07 17:11:35 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2021-11-15 06:05:17 +03:00
/*
2009-06-03 01:29:35 +04:00
* Marvell Bluetooth driver
*
* Copyright ( C ) 2009 , Marvell International Ltd .
* */
2011-08-30 00:44:23 +04:00
# include <linux/module.h>
2013-11-02 02:28:24 +04:00
# include <linux/of.h>
2009-06-03 01:29:35 +04:00
# include <net/bluetooth/bluetooth.h>
# include <net/bluetooth/hci_core.h>
2014-11-24 13:40:53 +03:00
# include <linux/mmc/sdio_func.h>
2009-06-03 01:29:35 +04:00
# include "btmrvl_drv.h"
2014-03-29 01:54:39 +04:00
# include "btmrvl_sdio.h"
2009-06-03 01:29:35 +04:00
# define VERSION "1.0"
/*
* This function is called by interface specific interrupt handler .
* It updates Power Save & Host Sleep states , and wakes up the main
* thread .
*/
void btmrvl_interrupt ( struct btmrvl_private * priv )
{
priv - > adapter - > ps_state = PS_AWAKE ;
priv - > adapter - > wakeup_tries = 0 ;
priv - > adapter - > int_count + + ;
2014-11-19 12:28:34 +03:00
if ( priv - > adapter - > hs_state = = HS_ACTIVATED ) {
2014-11-24 13:40:52 +03:00
BT_DBG ( " BT: HS DEACTIVATED in ISR! " ) ;
2014-11-19 12:28:34 +03:00
priv - > adapter - > hs_state = HS_DEACTIVATED ;
}
2009-06-03 01:29:35 +04:00
wake_up_interruptible ( & priv - > main_thread . wait_q ) ;
}
EXPORT_SYMBOL_GPL ( btmrvl_interrupt ) ;
2012-06-13 14:35:44 +04:00
bool btmrvl_check_evtpkt ( struct btmrvl_private * priv , struct sk_buff * skb )
2009-06-03 01:29:35 +04:00
{
2009-06-09 18:00:22 +04:00
struct hci_event_hdr * hdr = ( void * ) skb - > data ;
2009-06-03 01:29:35 +04:00
if ( hdr - > evt = = HCI_EV_CMD_COMPLETE ) {
2012-07-09 14:57:18 +04:00
struct hci_ev_cmd_complete * ec ;
2013-11-01 02:08:31 +04:00
u16 opcode ;
2012-07-09 14:57:18 +04:00
2009-06-09 18:00:22 +04:00
ec = ( void * ) ( skb - > data + HCI_EVENT_HDR_SIZE ) ;
2009-06-03 01:29:35 +04:00
opcode = __le16_to_cpu ( ec - > opcode ) ;
2012-06-13 14:35:44 +04:00
2013-10-01 23:19:12 +04:00
if ( priv - > btmrvl_dev . sendcmdflag ) {
2009-06-03 01:29:35 +04:00
priv - > btmrvl_dev . sendcmdflag = false ;
priv - > adapter - > cmd_complete = true ;
wake_up_interruptible ( & priv - > adapter - > cmd_wait_q ) ;
2012-06-13 14:35:44 +04:00
2014-03-21 07:05:44 +04:00
if ( hci_opcode_ogf ( opcode ) = = 0x3F ) {
BT_DBG ( " vendor event skipped: opcode=%#4.4x " ,
opcode ) ;
kfree_skb ( skb ) ;
return false ;
}
2012-06-13 14:35:44 +04:00
}
2009-06-03 01:29:35 +04:00
}
2012-06-13 14:35:44 +04:00
return true ;
2009-06-03 01:29:35 +04:00
}
EXPORT_SYMBOL_GPL ( btmrvl_check_evtpkt ) ;
int btmrvl_process_event ( struct btmrvl_private * priv , struct sk_buff * skb )
{
struct btmrvl_adapter * adapter = priv - > adapter ;
struct btmrvl_event * event ;
2010-03-08 15:15:59 +03:00
int ret = 0 ;
2009-06-03 01:29:35 +04:00
event = ( struct btmrvl_event * ) skb - > data ;
if ( event - > ec ! = 0xff ) {
BT_DBG ( " Not Marvell Event=%x " , event - > ec ) ;
ret = - EINVAL ;
goto exit ;
}
switch ( event - > data [ 0 ] ) {
2013-11-01 02:08:31 +04:00
case BT_EVENT_AUTO_SLEEP_MODE :
2009-06-03 01:29:35 +04:00
if ( ! event - > data [ 2 ] ) {
if ( event - > data [ 1 ] = = BT_PS_ENABLE )
adapter - > psmode = 1 ;
else
adapter - > psmode = 0 ;
BT_DBG ( " PS Mode:%s " ,
( adapter - > psmode ) ? " Enable " : " Disable " ) ;
} else {
BT_DBG ( " PS Mode command failed " ) ;
}
break ;
2013-11-01 02:08:31 +04:00
case BT_EVENT_HOST_SLEEP_CONFIG :
2009-06-03 01:29:35 +04:00
if ( ! event - > data [ 3 ] )
BT_DBG ( " gpio=%x, gap=%x " , event - > data [ 1 ] ,
2009-06-09 18:00:22 +04:00
event - > data [ 2 ] ) ;
2009-06-03 01:29:35 +04:00
else
BT_DBG ( " HSCFG command failed " ) ;
break ;
2013-11-01 02:08:31 +04:00
case BT_EVENT_HOST_SLEEP_ENABLE :
2009-06-03 01:29:35 +04:00
if ( ! event - > data [ 1 ] ) {
adapter - > hs_state = HS_ACTIVATED ;
if ( adapter - > psmode )
adapter - > ps_state = PS_SLEEP ;
2014-07-02 01:00:14 +04:00
wake_up_interruptible ( & adapter - > event_hs_wait_q ) ;
2009-06-03 01:29:35 +04:00
BT_DBG ( " HS ACTIVATED! " ) ;
} else {
BT_DBG ( " HS Enable failed " ) ;
}
break ;
2013-11-01 02:08:31 +04:00
case BT_EVENT_MODULE_CFG_REQ :
2009-06-09 18:00:22 +04:00
if ( priv - > btmrvl_dev . sendcmdflag & &
event - > data [ 1 ] = = MODULE_BRINGUP_REQ ) {
2010-03-04 01:37:35 +03:00
BT_DBG ( " EVENT:%s " ,
( ( event - > data [ 2 ] = = MODULE_BROUGHT_UP ) | |
( event - > data [ 2 ] = = MODULE_ALREADY_UP ) ) ?
" Bring-up succeed " : " Bring-up failed " ) ;
2010-03-04 01:37:37 +03:00
2010-08-10 01:38:10 +04:00
if ( event - > length > 3 & & event - > data [ 3 ] )
priv - > btmrvl_dev . dev_type = HCI_AMP ;
2010-03-04 01:37:37 +03:00
else
2016-07-05 15:30:14 +03:00
priv - > btmrvl_dev . dev_type = HCI_PRIMARY ;
2010-03-04 01:37:37 +03:00
BT_DBG ( " dev_type: %d " , priv - > btmrvl_dev . dev_type ) ;
2009-06-09 18:00:22 +04:00
} else if ( priv - > btmrvl_dev . sendcmdflag & &
event - > data [ 1 ] = = MODULE_SHUTDOWN_REQ ) {
2009-06-03 01:29:35 +04:00
BT_DBG ( " EVENT:%s " , ( event - > data [ 2 ] ) ?
" Shutdown failed " : " Shutdown succeed " ) ;
} else {
BT_DBG ( " BT_CMD_MODULE_CFG_REQ resp for APP " ) ;
ret = - EINVAL ;
}
break ;
case BT_EVENT_POWER_STATE :
if ( event - > data [ 1 ] = = BT_PS_SLEEP )
adapter - > ps_state = PS_SLEEP ;
BT_DBG ( " EVENT:%s " ,
( adapter - > ps_state ) ? " PS_SLEEP " : " PS_AWAKE " ) ;
break ;
default :
BT_DBG ( " Unknown Event=%d " , event - > data [ 0 ] ) ;
ret = - EINVAL ;
break ;
}
exit :
if ( ! ret )
kfree_skb ( skb ) ;
return ret ;
}
EXPORT_SYMBOL_GPL ( btmrvl_process_event ) ;
2013-11-01 02:08:31 +04:00
static int btmrvl_send_sync_cmd ( struct btmrvl_private * priv , u16 opcode ,
2013-10-01 23:19:12 +04:00
const void * param , u8 len )
2009-06-03 01:29:35 +04:00
{
2009-06-09 18:00:22 +04:00
struct sk_buff * skb ;
2013-10-01 23:19:13 +04:00
struct hci_command_hdr * hdr ;
2009-06-03 01:29:35 +04:00
2015-01-01 11:13:41 +03:00
if ( priv - > surprise_removed ) {
BT_ERR ( " Card is removed " ) ;
return - EFAULT ;
}
2018-01-26 18:57:01 +03:00
skb = bt_skb_alloc ( HCI_COMMAND_HDR_SIZE + len , GFP_KERNEL ) ;
2015-09-25 12:03:14 +03:00
if ( ! skb ) {
2009-06-03 01:29:35 +04:00
BT_ERR ( " No free skb " ) ;
2009-06-13 09:40:18 +04:00
return - ENOMEM ;
2009-06-03 01:29:35 +04:00
}
networking: make skb_put & friends return void pointers
It seems like a historic accident that these return unsigned char *,
and in many places that means casts are required, more often than not.
Make these functions (skb_put, __skb_put and pskb_put) return void *
and remove all the casts across the tree, adding a (u8 *) cast only
where the unsigned char pointer was used directly, all done with the
following spatch:
@@
expression SKB, LEN;
typedef u8;
identifier fn = { skb_put, __skb_put };
@@
- *(fn(SKB, LEN))
+ *(u8 *)fn(SKB, LEN)
@@
expression E, SKB, LEN;
identifier fn = { skb_put, __skb_put };
type T;
@@
- E = ((T *)(fn(SKB, LEN)))
+ E = fn(SKB, LEN)
which actually doesn't cover pskb_put since there are only three
users overall.
A handful of stragglers were converted manually, notably a macro in
drivers/isdn/i4l/isdn_bsdcomp.c and, oddly enough, one of the many
instances in net/bluetooth/hci_sock.c. In the former file, I also
had to fix one whitespace problem spatch introduced.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-06-16 15:29:21 +03:00
hdr = skb_put ( skb , HCI_COMMAND_HDR_SIZE ) ;
2013-11-01 02:08:31 +04:00
hdr - > opcode = cpu_to_le16 ( opcode ) ;
2013-10-01 23:19:13 +04:00
hdr - > plen = len ;
2013-10-01 23:19:12 +04:00
if ( len )
networking: introduce and use skb_put_data()
A common pattern with skb_put() is to just want to memcpy()
some data into the new space, introduce skb_put_data() for
this.
An spatch similar to the one for skb_put_zero() converts many
of the places using it:
@@
identifier p, p2;
expression len, skb, data;
type t, t2;
@@
(
-p = skb_put(skb, len);
+p = skb_put_data(skb, data, len);
|
-p = (t)skb_put(skb, len);
+p = skb_put_data(skb, data, len);
)
(
p2 = (t2)p;
-memcpy(p2, data, len);
|
-memcpy(p, data, len);
)
@@
type t, t2;
identifier p, p2;
expression skb, data;
@@
t *p;
...
(
-p = skb_put(skb, sizeof(t));
+p = skb_put_data(skb, data, sizeof(t));
|
-p = (t *)skb_put(skb, sizeof(t));
+p = skb_put_data(skb, data, sizeof(t));
)
(
p2 = (t2)p;
-memcpy(p2, data, sizeof(*p));
|
-memcpy(p, data, sizeof(*p));
)
@@
expression skb, len, data;
@@
-memcpy(skb_put(skb, len), data, len);
+skb_put_data(skb, data, len);
(again, manually post-processed to retain some comments)
Reviewed-by: Stephen Hemminger <stephen@networkplumber.org>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-06-16 15:29:20 +03:00
skb_put_data ( skb , param , len ) ;
2009-06-03 01:29:35 +04:00
2015-11-05 09:33:56 +03:00
hci_skb_pkt_type ( skb ) = MRVL_VENDOR_PKT ;
2009-06-03 01:29:35 +04:00
skb_queue_head ( & priv - > adapter - > tx_queue , skb ) ;
priv - > btmrvl_dev . sendcmdflag = true ;
priv - > adapter - > cmd_complete = false ;
wake_up_interruptible ( & priv - > main_thread . wait_q ) ;
2009-06-09 18:00:22 +04:00
if ( ! wait_event_interruptible_timeout ( priv - > adapter - > cmd_wait_q ,
2015-01-07 08:36:56 +03:00
priv - > adapter - > cmd_complete | |
priv - > surprise_removed ,
2015-01-07 08:36:55 +03:00
WAIT_UNTIL_CMD_RESP ) )
2013-10-01 23:19:12 +04:00
return - ETIMEDOUT ;
2015-01-07 08:36:56 +03:00
if ( priv - > surprise_removed )
return - EFAULT ;
2013-10-01 23:19:12 +04:00
return 0 ;
}
2009-06-03 01:29:35 +04:00
2014-04-16 00:00:00 +04:00
int btmrvl_send_module_cfg_cmd ( struct btmrvl_private * priv , u8 subcmd )
2013-10-01 23:19:12 +04:00
{
int ret ;
ret = btmrvl_send_sync_cmd ( priv , BT_CMD_MODULE_CFG_REQ , & subcmd , 1 ) ;
if ( ret )
2014-11-24 13:40:52 +03:00
BT_ERR ( " module_cfg_cmd(%x) failed " , subcmd ) ;
2009-06-03 01:29:35 +04:00
return ret ;
}
EXPORT_SYMBOL_GPL ( btmrvl_send_module_cfg_cmd ) ;
2015-02-10 16:49:41 +03:00
static int btmrvl_enable_sco_routing_to_host ( struct btmrvl_private * priv )
{
int ret ;
u8 subcmd = 0 ;
ret = btmrvl_send_sync_cmd ( priv , BT_CMD_ROUTE_SCO_TO_HOST , & subcmd , 1 ) ;
if ( ret )
BT_ERR ( " BT_CMD_ROUTE_SCO_TO_HOST command failed: %#x " , ret ) ;
return ret ;
}
2014-04-01 01:41:44 +04:00
int btmrvl_pscan_window_reporting ( struct btmrvl_private * priv , u8 subcmd )
{
struct btmrvl_sdio_card * card = priv - > btmrvl_dev . card ;
int ret ;
if ( ! card - > support_pscan_win_report )
return 0 ;
ret = btmrvl_send_sync_cmd ( priv , BT_CMD_PSCAN_WIN_REPORT_ENABLE ,
& subcmd , 1 ) ;
if ( ret )
BT_ERR ( " PSCAN_WIN_REPORT_ENABLE command failed: %#x " , ret ) ;
return ret ;
}
EXPORT_SYMBOL_GPL ( btmrvl_pscan_window_reporting ) ;
2012-04-25 03:31:40 +04:00
int btmrvl_send_hscfg_cmd ( struct btmrvl_private * priv )
{
2013-10-01 23:19:12 +04:00
int ret ;
u8 param [ 2 ] ;
2012-04-25 03:31:40 +04:00
2013-10-01 23:19:12 +04:00
param [ 0 ] = ( priv - > btmrvl_dev . gpio_gap & 0xff00 ) > > 8 ;
param [ 1 ] = ( u8 ) ( priv - > btmrvl_dev . gpio_gap & 0x00ff ) ;
2012-04-25 03:31:40 +04:00
2013-10-01 23:19:12 +04:00
BT_DBG ( " Sending HSCFG Command, gpio=0x%x, gap=0x%x " ,
param [ 0 ] , param [ 1 ] ) ;
2012-04-25 03:31:40 +04:00
2013-10-01 23:19:12 +04:00
ret = btmrvl_send_sync_cmd ( priv , BT_CMD_HOST_SLEEP_CONFIG , param , 2 ) ;
if ( ret )
2014-11-24 13:40:52 +03:00
BT_ERR ( " HSCFG command failed " ) ;
2012-04-25 03:31:40 +04:00
2013-10-01 23:19:12 +04:00
return ret ;
2012-04-25 03:31:40 +04:00
}
EXPORT_SYMBOL_GPL ( btmrvl_send_hscfg_cmd ) ;
2009-09-30 22:18:30 +04:00
int btmrvl_enable_ps ( struct btmrvl_private * priv )
{
2013-10-01 23:19:12 +04:00
int ret ;
u8 param ;
2009-09-30 22:18:30 +04:00
if ( priv - > btmrvl_dev . psmode )
2013-10-01 23:19:12 +04:00
param = BT_PS_ENABLE ;
2009-09-30 22:18:30 +04:00
else
2013-10-01 23:19:12 +04:00
param = BT_PS_DISABLE ;
2009-09-30 22:18:30 +04:00
2013-10-01 23:19:12 +04:00
ret = btmrvl_send_sync_cmd ( priv , BT_CMD_AUTO_SLEEP_MODE , & param , 1 ) ;
if ( ret )
2014-11-24 13:40:52 +03:00
BT_ERR ( " PSMODE command failed " ) ;
2009-09-30 22:18:30 +04:00
return 0 ;
}
EXPORT_SYMBOL_GPL ( btmrvl_enable_ps ) ;
2012-04-25 22:43:54 +04:00
int btmrvl_enable_hs ( struct btmrvl_private * priv )
2009-06-03 01:29:35 +04:00
{
2014-07-02 01:00:14 +04:00
struct btmrvl_adapter * adapter = priv - > adapter ;
2013-10-01 23:19:12 +04:00
int ret ;
2009-06-03 01:29:35 +04:00
2013-10-01 23:19:12 +04:00
ret = btmrvl_send_sync_cmd ( priv , BT_CMD_HOST_SLEEP_ENABLE , NULL , 0 ) ;
2014-07-02 01:00:14 +04:00
if ( ret ) {
2014-11-24 13:40:52 +03:00
BT_ERR ( " Host sleep enable command failed " ) ;
2014-07-02 01:00:14 +04:00
return ret ;
}
ret = wait_event_interruptible_timeout ( adapter - > event_hs_wait_q ,
2015-01-07 08:36:56 +03:00
adapter - > hs_state | |
priv - > surprise_removed ,
2015-01-07 08:36:55 +03:00
WAIT_UNTIL_HS_STATE_CHANGED ) ;
2015-01-07 08:36:56 +03:00
if ( ret < 0 | | priv - > surprise_removed ) {
2014-07-02 01:00:14 +04:00
BT_ERR ( " event_hs_wait_q terminated (%d): %d,%d,%d " ,
ret , adapter - > hs_state , adapter - > ps_state ,
adapter - > wakeup_tries ) ;
} else if ( ! ret ) {
BT_ERR ( " hs_enable timeout: %d,%d,%d " , adapter - > hs_state ,
adapter - > ps_state , adapter - > wakeup_tries ) ;
ret = - ETIMEDOUT ;
} else {
BT_DBG ( " host sleep enabled: %d,%d,%d " , adapter - > hs_state ,
adapter - > ps_state , adapter - > wakeup_tries ) ;
ret = 0 ;
}
2009-06-03 01:29:35 +04:00
return ret ;
}
2012-04-25 22:43:54 +04:00
EXPORT_SYMBOL_GPL ( btmrvl_enable_hs ) ;
2009-06-03 01:29:35 +04:00
int btmrvl_prepare_command ( struct btmrvl_private * priv )
{
2009-06-13 09:40:18 +04:00
int ret = 0 ;
2009-06-03 01:29:35 +04:00
if ( priv - > btmrvl_dev . hscfgcmd ) {
priv - > btmrvl_dev . hscfgcmd = 0 ;
2012-04-25 03:31:40 +04:00
btmrvl_send_hscfg_cmd ( priv ) ;
2009-06-03 01:29:35 +04:00
}
if ( priv - > btmrvl_dev . pscmd ) {
priv - > btmrvl_dev . pscmd = 0 ;
2009-09-30 22:18:30 +04:00
btmrvl_enable_ps ( priv ) ;
2009-06-03 01:29:35 +04:00
}
if ( priv - > btmrvl_dev . hscmd ) {
priv - > btmrvl_dev . hscmd = 0 ;
if ( priv - > btmrvl_dev . hsmode ) {
ret = btmrvl_enable_hs ( priv ) ;
} else {
ret = priv - > hw_wakeup_firmware ( priv ) ;
priv - > adapter - > hs_state = HS_DEACTIVATED ;
2014-11-24 13:40:52 +03:00
BT_DBG ( " BT: HS DEACTIVATED due to host activity! " ) ;
2009-06-03 01:29:35 +04:00
}
}
return ret ;
}
static int btmrvl_tx_pkt ( struct btmrvl_private * priv , struct sk_buff * skb )
{
2009-06-13 09:40:18 +04:00
int ret = 0 ;
2009-06-03 01:29:35 +04:00
2009-06-13 09:40:18 +04:00
if ( ! skb | | ! skb - > data )
2009-06-03 01:29:35 +04:00
return - EINVAL ;
if ( ! skb - > len | | ( ( skb - > len + BTM_HEADER_LEN ) > BTM_UPLD_SIZE ) ) {
BT_ERR ( " Tx Error: Bad skb length %d : %d " ,
2009-06-09 18:00:22 +04:00
skb - > len , BTM_UPLD_SIZE ) ;
2009-06-03 01:29:35 +04:00
return - EINVAL ;
}
skb_push ( skb , BTM_HEADER_LEN ) ;
/* header type: byte[3]
* HCI_COMMAND = 1 , ACL_DATA = 2 , SCO_DATA = 3 , 0xFE = Vendor
* header length : byte [ 2 ] [ 1 ] [ 0 ]
*/
skb - > data [ 0 ] = ( skb - > len & 0x0000ff ) ;
skb - > data [ 1 ] = ( skb - > len & 0x00ff00 ) > > 8 ;
skb - > data [ 2 ] = ( skb - > len & 0xff0000 ) > > 16 ;
2015-11-05 09:33:56 +03:00
skb - > data [ 3 ] = hci_skb_pkt_type ( skb ) ;
2009-06-03 01:29:35 +04:00
if ( priv - > hw_host_to_card )
ret = priv - > hw_host_to_card ( priv , skb - > data , skb - > len ) ;
return ret ;
}
static void btmrvl_init_adapter ( struct btmrvl_private * priv )
{
2014-03-29 01:54:39 +04:00
int buf_size ;
2009-06-03 01:29:35 +04:00
skb_queue_head_init ( & priv - > adapter - > tx_queue ) ;
priv - > adapter - > ps_state = PS_AWAKE ;
2014-03-29 01:54:39 +04:00
buf_size = ALIGN_SZ ( SDIO_BLOCK_SIZE , BTSDIO_DMA_ALIGN ) ;
priv - > adapter - > hw_regs_buf = kzalloc ( buf_size , GFP_KERNEL ) ;
if ( ! priv - > adapter - > hw_regs_buf ) {
priv - > adapter - > hw_regs = NULL ;
BT_ERR ( " Unable to allocate buffer for hw_regs. " ) ;
} else {
priv - > adapter - > hw_regs =
( u8 * ) ALIGN_ADDR ( priv - > adapter - > hw_regs_buf ,
BTSDIO_DMA_ALIGN ) ;
BT_DBG ( " hw_regs_buf=%p hw_regs=%p " ,
priv - > adapter - > hw_regs_buf , priv - > adapter - > hw_regs ) ;
}
2009-06-03 01:29:35 +04:00
init_waitqueue_head ( & priv - > adapter - > cmd_wait_q ) ;
2014-07-02 01:00:14 +04:00
init_waitqueue_head ( & priv - > adapter - > event_hs_wait_q ) ;
2009-06-03 01:29:35 +04:00
}
static void btmrvl_free_adapter ( struct btmrvl_private * priv )
{
skb_queue_purge ( & priv - > adapter - > tx_queue ) ;
2014-03-29 01:54:39 +04:00
kfree ( priv - > adapter - > hw_regs_buf ) ;
2009-06-03 01:29:35 +04:00
kfree ( priv - > adapter ) ;
priv - > adapter = NULL ;
}
2013-10-11 17:19:18 +04:00
static int btmrvl_send_frame ( struct hci_dev * hdev , struct sk_buff * skb )
2009-06-03 01:29:35 +04:00
{
2013-10-11 18:01:00 +04:00
struct btmrvl_private * priv = hci_get_drvdata ( hdev ) ;
2009-06-03 01:29:35 +04:00
2015-11-05 09:33:56 +03:00
BT_DBG ( " type=%d, len=%d " , hci_skb_pkt_type ( skb ) , skb - > len ) ;
2009-06-03 01:29:35 +04:00
2016-01-06 17:34:38 +03:00
if ( priv - > adapter - > is_suspending | | priv - > adapter - > is_suspended ) {
BT_ERR ( " %s: Device is suspending or suspended " , __func__ ) ;
return - EBUSY ;
}
2015-11-05 09:33:56 +03:00
switch ( hci_skb_pkt_type ( skb ) ) {
2009-06-03 01:29:35 +04:00
case HCI_COMMAND_PKT :
hdev - > stat . cmd_tx + + ;
break ;
case HCI_ACLDATA_PKT :
hdev - > stat . acl_tx + + ;
break ;
case HCI_SCODATA_PKT :
hdev - > stat . sco_tx + + ;
break ;
}
skb_queue_tail ( & priv - > adapter - > tx_queue , skb ) ;
2016-01-06 17:34:38 +03:00
if ( ! priv - > adapter - > is_suspended )
wake_up_interruptible ( & priv - > main_thread . wait_q ) ;
2009-06-03 01:29:35 +04:00
return 0 ;
}
static int btmrvl_flush ( struct hci_dev * hdev )
{
2012-02-10 00:58:32 +04:00
struct btmrvl_private * priv = hci_get_drvdata ( hdev ) ;
2009-06-03 01:29:35 +04:00
skb_queue_purge ( & priv - > adapter - > tx_queue ) ;
return 0 ;
}
static int btmrvl_close ( struct hci_dev * hdev )
{
2012-02-10 00:58:32 +04:00
struct btmrvl_private * priv = hci_get_drvdata ( hdev ) ;
2009-06-03 01:29:35 +04:00
skb_queue_purge ( & priv - > adapter - > tx_queue ) ;
return 0 ;
}
static int btmrvl_open ( struct hci_dev * hdev )
{
return 0 ;
}
2013-11-02 02:28:24 +04:00
static int btmrvl_download_cal_data ( struct btmrvl_private * priv ,
2013-11-02 02:28:25 +04:00
u8 * data , int len )
2013-10-01 23:19:15 +04:00
{
2013-11-02 02:28:25 +04:00
int ret ;
2013-10-01 23:19:15 +04:00
data [ 0 ] = 0x00 ;
data [ 1 ] = 0x00 ;
data [ 2 ] = 0x00 ;
2013-11-02 02:28:25 +04:00
data [ 3 ] = len ;
2013-10-01 23:19:15 +04:00
print_hex_dump_bytes ( " Calibration data: " ,
2013-11-02 02:28:25 +04:00
DUMP_PREFIX_OFFSET , data , BT_CAL_HDR_LEN + len ) ;
2013-10-01 23:19:15 +04:00
ret = btmrvl_send_sync_cmd ( priv , BT_CMD_LOAD_CONFIG_DATA , data ,
2013-11-02 02:28:25 +04:00
BT_CAL_HDR_LEN + len ) ;
2013-10-01 23:19:15 +04:00
if ( ret )
2016-12-29 00:30:30 +03:00
BT_ERR ( " Failed to download calibration data " ) ;
2013-10-01 23:19:15 +04:00
return 0 ;
}
2014-11-19 12:28:33 +03:00
static int btmrvl_check_device_tree ( struct btmrvl_private * priv )
2013-10-01 23:19:15 +04:00
{
2013-11-02 02:28:24 +04:00
struct device_node * dt_node ;
2016-04-26 16:57:27 +03:00
struct btmrvl_sdio_card * card = priv - > btmrvl_dev . card ;
2013-11-02 02:28:25 +04:00
u8 cal_data [ BT_CAL_HDR_LEN + BT_CAL_DATA_SIZE ] ;
2016-04-26 16:57:27 +03:00
int ret = 0 ;
u16 gpio , gap ;
if ( card - > plt_of_node ) {
dt_node = card - > plt_of_node ;
ret = of_property_read_u16 ( dt_node , " marvell,wakeup-pin " ,
& gpio ) ;
if ( ret )
gpio = ( priv - > btmrvl_dev . gpio_gap & 0xff00 ) > > 8 ;
ret = of_property_read_u16 ( dt_node , " marvell,wakeup-gap-ms " ,
& gap ) ;
if ( ret )
gap = ( u8 ) ( priv - > btmrvl_dev . gpio_gap & 0x00ff ) ;
2013-10-01 23:19:15 +04:00
2016-04-26 16:57:27 +03:00
priv - > btmrvl_dev . gpio_gap = ( gpio < < 8 ) + gap ;
2014-11-19 12:28:33 +03:00
2016-04-26 16:57:27 +03:00
ret = of_property_read_u8_array ( dt_node , " marvell,cal-data " ,
2014-11-19 12:28:32 +03:00
cal_data + BT_CAL_HDR_LEN ,
BT_CAL_DATA_SIZE ) ;
2016-04-26 16:57:27 +03:00
if ( ret )
2014-11-19 12:28:32 +03:00
return ret ;
BT_DBG ( " Use cal data from device tree " ) ;
ret = btmrvl_download_cal_data ( priv , cal_data ,
BT_CAL_DATA_SIZE ) ;
2016-04-26 16:57:27 +03:00
if ( ret )
2014-11-19 12:28:32 +03:00
BT_ERR ( " Fail to download calibrate data " ) ;
2013-10-01 23:19:15 +04:00
}
2016-04-26 16:57:27 +03:00
return ret ;
2013-10-01 23:19:15 +04:00
}
2013-10-01 23:19:14 +04:00
static int btmrvl_setup ( struct hci_dev * hdev )
{
struct btmrvl_private * priv = hci_get_drvdata ( hdev ) ;
2015-01-01 11:13:40 +03:00
int ret ;
2013-10-01 23:19:14 +04:00
2015-01-01 11:13:40 +03:00
ret = btmrvl_send_module_cfg_cmd ( priv , MODULE_BRINGUP_REQ ) ;
if ( ret )
return ret ;
2013-10-01 23:19:14 +04:00
2016-01-06 17:34:37 +03:00
priv - > btmrvl_dev . gpio_gap = 0xfffe ;
2014-11-19 12:28:33 +03:00
btmrvl_check_device_tree ( priv ) ;
2013-10-01 23:19:15 +04:00
2015-02-10 16:49:41 +03:00
btmrvl_enable_sco_routing_to_host ( priv ) ;
2014-04-01 01:41:44 +04:00
btmrvl_pscan_window_reporting ( priv , 0x01 ) ;
2013-10-01 23:19:14 +04:00
priv - > btmrvl_dev . psmode = 1 ;
btmrvl_enable_ps ( priv ) ;
btmrvl_send_hscfg_cmd ( priv ) ;
return 0 ;
}
2014-07-19 01:47:07 +04:00
static int btmrvl_set_bdaddr ( struct hci_dev * hdev , const bdaddr_t * bdaddr )
{
struct sk_buff * skb ;
long ret ;
u8 buf [ 8 ] ;
buf [ 0 ] = MRVL_VENDOR_PKT ;
buf [ 1 ] = sizeof ( bdaddr_t ) ;
memcpy ( buf + 2 , bdaddr , sizeof ( bdaddr_t ) ) ;
skb = __hci_cmd_sync ( hdev , BT_CMD_SET_BDADDR , sizeof ( buf ) , buf ,
HCI_INIT_TIMEOUT ) ;
if ( IS_ERR ( skb ) ) {
ret = PTR_ERR ( skb ) ;
BT_ERR ( " %s: changing btmrvl device address failed (%ld) " ,
hdev - > name , ret ) ;
return ret ;
}
kfree_skb ( skb ) ;
return 0 ;
}
2021-10-01 23:22:31 +03:00
static bool btmrvl_wakeup ( struct hci_dev * hdev )
2020-06-11 04:53:54 +03:00
{
struct btmrvl_private * priv = hci_get_drvdata ( hdev ) ;
struct btmrvl_sdio_card * card = priv - > btmrvl_dev . card ;
2021-10-01 23:22:31 +03:00
return device_may_wakeup ( & card - > func - > dev ) ;
2020-06-11 04:53:54 +03:00
}
2009-06-03 01:29:35 +04:00
/*
* This function handles the event generated by firmware , rx data
* received from firmware , and tx data sent from kernel .
*/
static int btmrvl_service_main_thread ( void * data )
{
struct btmrvl_thread * thread = data ;
struct btmrvl_private * priv = thread - > priv ;
struct btmrvl_adapter * adapter = priv - > adapter ;
2017-06-20 13:06:13 +03:00
wait_queue_entry_t wait ;
2009-06-03 01:29:35 +04:00
struct sk_buff * skb ;
ulong flags ;
init_waitqueue_entry ( & wait , current ) ;
for ( ; ; ) {
add_wait_queue ( & thread - > wait_q , & wait ) ;
set_current_state ( TASK_INTERRUPTIBLE ) ;
2015-01-01 11:13:41 +03:00
if ( kthread_should_stop ( ) | | priv - > surprise_removed ) {
2013-06-11 23:40:20 +04:00
BT_DBG ( " main_thread: break from main thread " ) ;
break ;
}
2009-06-03 01:29:35 +04:00
if ( adapter - > wakeup_tries | |
2009-06-09 18:00:22 +04:00
( ( ! adapter - > int_count ) & &
( ! priv - > btmrvl_dev . tx_dnld_rdy | |
skb_queue_empty ( & adapter - > tx_queue ) ) ) ) {
2009-06-03 01:29:35 +04:00
BT_DBG ( " main_thread is sleeping... " ) ;
schedule ( ) ;
}
set_current_state ( TASK_RUNNING ) ;
remove_wait_queue ( & thread - > wait_q , & wait ) ;
BT_DBG ( " main_thread woke up " ) ;
2015-01-01 11:13:41 +03:00
if ( kthread_should_stop ( ) | | priv - > surprise_removed ) {
2015-01-01 11:13:39 +03:00
BT_DBG ( " main_thread: break from main thread " ) ;
break ;
}
2009-06-03 01:29:35 +04:00
spin_lock_irqsave ( & priv - > driver_lock , flags ) ;
if ( adapter - > int_count ) {
adapter - > int_count = 0 ;
2010-05-28 03:38:37 +04:00
spin_unlock_irqrestore ( & priv - > driver_lock , flags ) ;
priv - > hw_process_int_status ( priv ) ;
2009-06-09 18:00:22 +04:00
} else if ( adapter - > ps_state = = PS_SLEEP & &
! skb_queue_empty ( & adapter - > tx_queue ) ) {
2009-06-03 01:29:35 +04:00
spin_unlock_irqrestore ( & priv - > driver_lock , flags ) ;
adapter - > wakeup_tries + + ;
priv - > hw_wakeup_firmware ( priv ) ;
continue ;
2010-05-28 03:38:37 +04:00
} else {
spin_unlock_irqrestore ( & priv - > driver_lock , flags ) ;
2009-06-03 01:29:35 +04:00
}
if ( adapter - > ps_state = = PS_SLEEP )
continue ;
2016-01-06 17:34:38 +03:00
if ( ! priv - > btmrvl_dev . tx_dnld_rdy | |
priv - > adapter - > is_suspended )
2009-06-03 01:29:35 +04:00
continue ;
skb = skb_dequeue ( & adapter - > tx_queue ) ;
if ( skb ) {
if ( btmrvl_tx_pkt ( priv , skb ) )
priv - > btmrvl_dev . hcidev - > stat . err_tx + + ;
else
2009-06-09 18:00:22 +04:00
priv - > btmrvl_dev . hcidev - > stat . byte_tx + = skb - > len ;
2009-06-03 01:29:35 +04:00
kfree_skb ( skb ) ;
}
}
return 0 ;
}
2010-03-04 01:37:36 +03:00
int btmrvl_register_hdev ( struct btmrvl_private * priv )
2009-06-03 01:29:35 +04:00
{
struct hci_dev * hdev = NULL ;
2020-06-11 04:53:53 +03:00
struct btmrvl_sdio_card * card = priv - > btmrvl_dev . card ;
2009-06-03 01:29:35 +04:00
int ret ;
hdev = hci_alloc_dev ( ) ;
if ( ! hdev ) {
BT_ERR ( " Can not allocate HCI device " ) ;
goto err_hdev ;
}
priv - > btmrvl_dev . hcidev = hdev ;
2012-02-10 00:58:32 +04:00
hci_set_drvdata ( hdev , priv ) ;
2009-06-03 01:29:35 +04:00
2013-10-10 21:50:05 +04:00
hdev - > bus = HCI_SDIO ;
hdev - > open = btmrvl_open ;
2009-06-03 01:29:35 +04:00
hdev - > close = btmrvl_close ;
hdev - > flush = btmrvl_flush ;
2013-10-10 21:50:05 +04:00
hdev - > send = btmrvl_send_frame ;
2013-10-01 23:19:14 +04:00
hdev - > setup = btmrvl_setup ;
2014-07-19 01:47:07 +04:00
hdev - > set_bdaddr = btmrvl_set_bdaddr ;
2021-10-01 23:22:31 +03:00
hdev - > wakeup = btmrvl_wakeup ;
2020-06-11 04:53:53 +03:00
SET_HCIDEV_DEV ( hdev , & card - > func - > dev ) ;
2010-03-04 01:37:36 +03:00
2010-03-04 01:37:37 +03:00
hdev - > dev_type = priv - > btmrvl_dev . dev_type ;
2009-06-03 01:29:35 +04:00
ret = hci_register_dev ( hdev ) ;
if ( ret < 0 ) {
BT_ERR ( " Can not register HCI device " ) ;
goto err_hci_register_dev ;
}
2009-06-03 01:29:37 +04:00
# ifdef CONFIG_DEBUG_FS
btmrvl_debugfs_init ( hdev ) ;
# endif
2010-03-04 01:37:36 +03:00
return 0 ;
2009-06-03 01:29:35 +04:00
err_hci_register_dev :
hci_free_dev ( hdev ) ;
err_hdev :
2010-03-04 01:37:36 +03:00
/* Stop the thread servicing the interrupts */
kthread_stop ( priv - > main_thread . task ) ;
2009-06-03 01:29:35 +04:00
btmrvl_free_adapter ( priv ) ;
2010-03-04 01:37:36 +03:00
kfree ( priv ) ;
return - ENOMEM ;
}
EXPORT_SYMBOL_GPL ( btmrvl_register_hdev ) ;
struct btmrvl_private * btmrvl_add_card ( void * card )
{
struct btmrvl_private * priv ;
priv = kzalloc ( sizeof ( * priv ) , GFP_KERNEL ) ;
if ( ! priv ) {
BT_ERR ( " Can not allocate priv " ) ;
goto err_priv ;
}
priv - > adapter = kzalloc ( sizeof ( * priv - > adapter ) , GFP_KERNEL ) ;
if ( ! priv - > adapter ) {
BT_ERR ( " Allocate buffer for btmrvl_adapter failed! " ) ;
goto err_adapter ;
}
btmrvl_init_adapter ( priv ) ;
BT_DBG ( " Starting kthread... " ) ;
priv - > main_thread . priv = priv ;
spin_lock_init ( & priv - > driver_lock ) ;
init_waitqueue_head ( & priv - > main_thread . wait_q ) ;
priv - > main_thread . task = kthread_run ( btmrvl_service_main_thread ,
& priv - > main_thread , " btmrvl_main_service " ) ;
2014-07-31 02:57:03 +04:00
if ( IS_ERR ( priv - > main_thread . task ) )
goto err_thread ;
2010-03-04 01:37:36 +03:00
priv - > btmrvl_dev . card = card ;
priv - > btmrvl_dev . tx_dnld_rdy = true ;
return priv ;
2009-06-03 01:29:35 +04:00
2014-07-31 02:57:03 +04:00
err_thread :
btmrvl_free_adapter ( priv ) ;
2009-06-03 01:29:35 +04:00
err_adapter :
kfree ( priv ) ;
err_priv :
return NULL ;
}
EXPORT_SYMBOL_GPL ( btmrvl_add_card ) ;
int btmrvl_remove_card ( struct btmrvl_private * priv )
{
struct hci_dev * hdev ;
hdev = priv - > btmrvl_dev . hcidev ;
wake_up_interruptible ( & priv - > adapter - > cmd_wait_q ) ;
2014-07-02 01:00:14 +04:00
wake_up_interruptible ( & priv - > adapter - > event_hs_wait_q ) ;
2009-06-03 01:29:35 +04:00
kthread_stop ( priv - > main_thread . task ) ;
2009-06-03 01:29:37 +04:00
# ifdef CONFIG_DEBUG_FS
btmrvl_debugfs_remove ( hdev ) ;
# endif
2009-06-03 01:29:35 +04:00
hci_unregister_dev ( hdev ) ;
hci_free_dev ( hdev ) ;
priv - > btmrvl_dev . hcidev = NULL ;
btmrvl_free_adapter ( priv ) ;
kfree ( priv ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( btmrvl_remove_card ) ;
MODULE_AUTHOR ( " Marvell International Ltd. " ) ;
2009-06-09 23:45:04 +04:00
MODULE_DESCRIPTION ( " Marvell Bluetooth driver ver " VERSION ) ;
2009-06-03 01:29:35 +04:00
MODULE_VERSION ( VERSION ) ;
MODULE_LICENSE ( " GPL v2 " ) ;