mirror of
https://github.com/followmsi/android_kernel_google_msm.git
synced 2024-11-06 23:17:41 +00:00
Bluetooth: Added SSR state machine in hci_smd sriver
This is to handle back to back SSR and also spurious notifications from the smd and the BT on/off or Airplane mode toggling while SSR is in progress. CRs-fixed: 425768 Change-Id: I851d8d785c2ff5445d3b8aa95225f1cb63654002 Signed-off-by: Bhasker Neti <bneti@codeaurora.org> Signed-off-by: Mallikarjuna GB <gbmalli@codeaurora.org>
This commit is contained in:
parent
07e1499c08
commit
cdd2f80725
1 changed files with 132 additions and 38 deletions
|
@ -44,6 +44,19 @@
|
|||
#define RX_Q_MONITOR (500) /* 500 milli second */
|
||||
#define HCI_REGISTER_SET 0
|
||||
|
||||
/* SSR state machine to take care of back to back SSR requests
|
||||
* and handling the incomming BT on/off,Airplane mode toggling and
|
||||
* also spuriour SMD open notification while one SSr is in progress
|
||||
*/
|
||||
#define STATE_SSR_ON 0x1
|
||||
#define STATE_SSR_START 0x02
|
||||
#define STATE_SSR_CHANNEL_OPEN_PENDING 0x04
|
||||
#define STATE_SSR_PENDING_INIT 0x08
|
||||
#define STATE_SSR_COMPLETE 0x00
|
||||
#define STATE_SSR_OFF STATE_SSR_COMPLETE
|
||||
|
||||
static int ssr_state = STATE_SSR_OFF;
|
||||
|
||||
|
||||
static int hcismd_set;
|
||||
static DEFINE_SEMAPHORE(hci_smd_enable);
|
||||
|
@ -341,25 +354,47 @@ static void hci_smd_notify_event(void *data, unsigned int event)
|
|||
break;
|
||||
case SMD_EVENT_OPEN:
|
||||
BT_INFO("opening HCI-SMD channel :%s", EVENT_CHANNEL);
|
||||
BT_DBG("SSR state is : %x", ssr_state);
|
||||
if ((ssr_state == STATE_SSR_OFF) ||
|
||||
(ssr_state == STATE_SSR_CHANNEL_OPEN_PENDING)) {
|
||||
|
||||
hci_smd_open(hdev);
|
||||
open_worker = kzalloc(sizeof(*open_worker), GFP_ATOMIC);
|
||||
if (!open_worker) {
|
||||
BT_ERR("Out of memory");
|
||||
break;
|
||||
}
|
||||
if (ssr_state == STATE_SSR_CHANNEL_OPEN_PENDING) {
|
||||
ssr_state = STATE_SSR_PENDING_INIT;
|
||||
BT_INFO("SSR state is : %x", ssr_state);
|
||||
}
|
||||
INIT_WORK(open_worker, hci_dev_smd_open);
|
||||
schedule_work(open_worker);
|
||||
|
||||
}
|
||||
break;
|
||||
case SMD_EVENT_CLOSE:
|
||||
BT_INFO("Closing HCI-SMD channel :%s", EVENT_CHANNEL);
|
||||
BT_DBG("SSR state is : %x", ssr_state);
|
||||
if ((ssr_state == STATE_SSR_OFF) ||
|
||||
(ssr_state == (STATE_SSR_PENDING_INIT))) {
|
||||
|
||||
hci_smd_close(hdev);
|
||||
reset_worker = kzalloc(sizeof(*reset_worker), GFP_ATOMIC);
|
||||
reset_worker = kzalloc(sizeof(*reset_worker),
|
||||
GFP_ATOMIC);
|
||||
if (!reset_worker) {
|
||||
BT_ERR("Out of memory");
|
||||
break;
|
||||
}
|
||||
ssr_state = STATE_SSR_ON;
|
||||
BT_INFO("SSR state is : %x", ssr_state);
|
||||
INIT_WORK(reset_worker, hci_dev_restart);
|
||||
schedule_work(reset_worker);
|
||||
|
||||
} else if (ssr_state & STATE_SSR_ON) {
|
||||
BT_ERR("SSR state is : %x", ssr_state);
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -403,7 +438,19 @@ static int hci_smd_hci_register_dev(struct hci_smd_data *hsmd)
|
|||
{
|
||||
struct hci_dev *hdev;
|
||||
|
||||
if (hsmd->hdev)
|
||||
hdev = hsmd->hdev;
|
||||
else {
|
||||
BT_ERR("hdev is NULL");
|
||||
return 0;
|
||||
}
|
||||
/* Allow the incomming SSR even the prev one at PENDING INIT STATE
|
||||
* since clenup need to be started again from the beging and ignore
|
||||
* or bypass the prev one
|
||||
*/
|
||||
if ((ssr_state == STATE_SSR_OFF) ||
|
||||
(ssr_state == STATE_SSR_PENDING_INIT)) {
|
||||
|
||||
if (test_and_set_bit(HCI_REGISTER_SET, &hsmd->flags)) {
|
||||
BT_ERR("HCI device registered already");
|
||||
return 0;
|
||||
|
@ -416,6 +463,12 @@ static int hci_smd_hci_register_dev(struct hci_smd_data *hsmd)
|
|||
clear_bit(HCI_REGISTER_SET, &hsmd->flags);
|
||||
return -ENODEV;
|
||||
}
|
||||
if (ssr_state == STATE_SSR_PENDING_INIT) {
|
||||
ssr_state = STATE_SSR_COMPLETE;
|
||||
BT_INFO("SSR state is : %x", ssr_state);
|
||||
}
|
||||
} else if (ssr_state)
|
||||
BT_ERR("Registration called in invalid context");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -449,7 +502,10 @@ static int hci_smd_register_smd(struct hci_smd_data *hsmd)
|
|||
*/
|
||||
setup_timer(&hsmd->rx_q_timer, schedule_timer,
|
||||
(unsigned long) hsmd->hdev);
|
||||
|
||||
if (ssr_state == STATE_SSR_START) {
|
||||
ssr_state = STATE_SSR_CHANNEL_OPEN_PENDING;
|
||||
BT_INFO("SSR state is : %x", ssr_state);
|
||||
}
|
||||
/* Open the SMD Channel and device and register the callback function */
|
||||
rc = smd_named_open_on_edge(EVENT_CHANNEL, SMD_APPS_WCNSS,
|
||||
&hsmd->event_channel, hdev, hci_smd_notify_event);
|
||||
|
@ -478,12 +534,16 @@ static int hci_smd_register_smd(struct hci_smd_data *hsmd)
|
|||
static void hci_smd_deregister_dev(struct hci_smd_data *hsmd)
|
||||
{
|
||||
tasklet_kill(&hs.rx_task);
|
||||
|
||||
if (ssr_state)
|
||||
BT_DBG("SSR state is : %x", ssr_state);
|
||||
/* Though the hci_smd driver is not registered with the hci
|
||||
* need to close the opened channels as a part of cleaup
|
||||
*/
|
||||
if (!test_and_clear_bit(HCI_REGISTER_SET, &hsmd->flags)) {
|
||||
BT_ERR("HCI device un-registered already");
|
||||
return;
|
||||
} else
|
||||
} else {
|
||||
BT_INFO("HCI device un-registration going on");
|
||||
|
||||
if (hsmd->hdev) {
|
||||
if (hci_unregister_dev(hsmd->hdev) < 0)
|
||||
BT_ERR("Can't unregister HCI device %s",
|
||||
|
@ -492,7 +552,7 @@ static void hci_smd_deregister_dev(struct hci_smd_data *hsmd)
|
|||
hci_free_dev(hsmd->hdev);
|
||||
hsmd->hdev = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
smd_close(hs.event_channel);
|
||||
smd_close(hs.data_channel);
|
||||
|
||||
|
@ -513,23 +573,47 @@ static void hci_dev_restart(struct work_struct *worker)
|
|||
{
|
||||
down(&hci_smd_enable);
|
||||
restart_in_progress = 1;
|
||||
BT_DBG("SSR state is : %x", ssr_state);
|
||||
|
||||
if (ssr_state == STATE_SSR_ON) {
|
||||
ssr_state = STATE_SSR_START;
|
||||
BT_INFO("SSR state is : %x", ssr_state);
|
||||
} else {
|
||||
BT_ERR("restart triggered in wrong context");
|
||||
up(&hci_smd_enable);
|
||||
kfree(worker);
|
||||
return;
|
||||
}
|
||||
hci_smd_deregister_dev(&hs);
|
||||
hci_smd_register_smd(&hs);
|
||||
up(&hci_smd_enable);
|
||||
kfree(worker);
|
||||
|
||||
}
|
||||
|
||||
static void hci_dev_smd_open(struct work_struct *worker)
|
||||
{
|
||||
down(&hci_smd_enable);
|
||||
if (ssr_state)
|
||||
BT_DBG("SSR state is : %x", ssr_state);
|
||||
|
||||
if ((ssr_state != STATE_SSR_OFF) &&
|
||||
(ssr_state != (STATE_SSR_PENDING_INIT))) {
|
||||
up(&hci_smd_enable);
|
||||
kfree(worker);
|
||||
return;
|
||||
}
|
||||
|
||||
if (restart_in_progress == 1) {
|
||||
/* Allow wcnss to initialize */
|
||||
restart_in_progress = 0;
|
||||
msleep(10000);
|
||||
}
|
||||
|
||||
hci_smd_hci_register_dev(&hs);
|
||||
up(&hci_smd_enable);
|
||||
kfree(worker);
|
||||
|
||||
}
|
||||
|
||||
static int hcismd_set_enable(const char *val, struct kernel_param *kp)
|
||||
|
@ -545,14 +629,23 @@ static int hcismd_set_enable(const char *val, struct kernel_param *kp)
|
|||
if (ret)
|
||||
goto done;
|
||||
|
||||
/* Ignore the all incomming register de-register requests in case of
|
||||
* SSR is in-progress
|
||||
*/
|
||||
switch (hcismd_set) {
|
||||
|
||||
case 1:
|
||||
if (hs.hdev == NULL)
|
||||
if ((hs.hdev == NULL) && (ssr_state == STATE_SSR_OFF))
|
||||
hci_smd_register_smd(&hs);
|
||||
else if (ssr_state)
|
||||
BT_ERR("SSR is in progress,state is : %x", ssr_state);
|
||||
|
||||
break;
|
||||
case 0:
|
||||
if (ssr_state == STATE_SSR_OFF)
|
||||
hci_smd_deregister_dev(&hs);
|
||||
else if (ssr_state)
|
||||
BT_ERR("SSR is in progress,state is : %x", ssr_state);
|
||||
break;
|
||||
default:
|
||||
ret = -EFAULT;
|
||||
|
@ -569,6 +662,7 @@ static int __init hci_smd_init(void)
|
|||
wake_lock_init(&hs.wake_lock_tx, WAKE_LOCK_SUSPEND,
|
||||
"msm_smd_Tx");
|
||||
restart_in_progress = 0;
|
||||
ssr_state = STATE_SSR_OFF;
|
||||
hs.hdev = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue