static void ibs_wq_serial_rx_clock_vote_off(struct work_struct *work) { struct ibs_struct *ibs = container_of(work, struct ibs_struct, ws_rx_vote_off); struct hci_uart *hu = (struct hci_uart *)ibs->ibs_hu; BT_DBG(" %p ", hu); ibs_msm_serial_clock_vote(HCI_IBS_RX_VOTE_CLOCK_OFF, hu); }
/* * Called upon wake-up-acknowledgement from the device */ static void ibs_device_woke_up(struct hci_uart *hu) { unsigned long flags; struct ibs_struct *ibs = hu->priv; struct sk_buff *skb = NULL; BT_DBG("hu %p", hu); /* lock hci_ibs state */ spin_lock_irqsave(&ibs->hci_ibs_lock, flags); /* debug */ ibs->ibs_recv_wacks++; //Add check for rx_ibs_state when receive HCI_IBS_WAKE_ACK just after HCI_IBS_SLEEP_IND. if(ibs->rx_ibs_state == HCI_IBS_RX_ASLEEP) { ibs_msm_serial_clock_vote(HCI_IBS_RX_VOTE_CLOCK_ON, hu); ibs->rx_ibs_state = HCI_IBS_RX_AWAKE; } switch (ibs->tx_ibs_state) { case HCI_IBS_TX_ASLEEP: /* This could be spurrious rx wake on the BT chip. * Send it another SLEEP othwise it will stay awake. */ default: BT_ERR("received HCI_IBS_WAKE_ACK in tx state %ld", ibs->tx_ibs_state); break; case HCI_IBS_TX_AWAKE: /* expect one if we send 2 WAKEs */ BT_DBG("received HCI_IBS_WAKE_ACK in tx state %ld", ibs->tx_ibs_state); break; case HCI_IBS_TX_WAKING: /* send pending packets */ while ((skb = skb_dequeue(&ibs->tx_wait_q))) skb_queue_tail(&ibs->txq, skb); /* switch timers and change state to HCI_IBS_TX_AWAKE */ del_timer(&ibs->wake_retrans_timer); mod_timer(&ibs->tx_idle_timer, jiffies + tx_idle_delay); ibs->tx_ibs_state = HCI_IBS_TX_AWAKE; } spin_unlock_irqrestore(&ibs->hci_ibs_lock, flags); /* actually send the packets */ hci_uart_tx_wakeup(hu); }
static void ibs_wq_serial_tx_clock_vote_off(struct work_struct *work) { struct ibs_struct *ibs = container_of(work, struct ibs_struct, ws_tx_vote_off); struct hci_uart *hu = (struct hci_uart *)ibs->ibs_hu; BT_DBG(" %p ", hu); hci_uart_tx_wakeup(hu); /* run HCI tx handling unlocked */ /* now that message queued to tty driver, vote for tty clocks off */ /* It is up to the tty driver to pend the clocks off until tx done. */ ibs_msm_serial_clock_vote(HCI_IBS_TX_VOTE_CLOCK_OFF, hu); }
/* * Called upon a wake-up-indication from the device */ static void ibs_device_want_to_wakeup(struct hci_uart *hu) { unsigned long flags; struct ibs_struct *ibs = hu->priv; BT_DBG("hu %p", hu); /* lock hci_ibs state */ spin_lock_irqsave(&ibs->hci_ibs_lock, flags); /* debug */ ibs->ibs_recv_wakes++; switch (ibs->rx_ibs_state) { case HCI_IBS_RX_ASLEEP: /* Make sure clock is on - we may have turned clock off since * receiving the wake up indicator */ ibs_msm_serial_clock_vote(HCI_IBS_RX_VOTE_CLOCK_ON, hu); ibs->rx_ibs_state = HCI_IBS_RX_AWAKE; /* deliberate fall-through */ case HCI_IBS_RX_AWAKE: /* Always acknowledge device wake up, * sending IBS message doesn't count as TX ON. */ if (send_hci_ibs_cmd(HCI_IBS_WAKE_ACK, hu) < 0) { BT_ERR("cannot acknowledge device wake up"); goto out; } ibs->ibs_sent_wacks++; /* debug */ break; default: /* any other state is illegal */ BT_ERR("received HCI_IBS_WAKE_IND in rx state %ld", ibs->rx_ibs_state); break; } out: spin_unlock_irqrestore(&ibs->hci_ibs_lock, flags); /* actually send the packets */ hci_uart_tx_wakeup(hu); }
static void hci_ibs_tx_idle_timeout(unsigned long arg) { struct hci_uart *hu = (struct hci_uart *) arg; struct ibs_struct *ibs = hu->priv; unsigned long flags; unsigned long vote_tx_sleep = 0; BT_DBG("hu %p idle timeout in %lu state", hu, ibs->tx_ibs_state); spin_lock_irqsave_nested(&ibs->hci_ibs_lock, flags, SINGLE_DEPTH_NESTING); switch (ibs->tx_ibs_state) { default: case HCI_IBS_TX_ASLEEP: case HCI_IBS_TX_WAKING: BT_ERR("spurrious timeout in tx state %ld", ibs->tx_ibs_state); goto out; case HCI_IBS_TX_AWAKE: /* TX_IDLE, go to SLEEP */ if (send_hci_ibs_cmd(HCI_IBS_SLEEP_IND, hu) < 0) { BT_ERR("cannot send SLEEP to device"); goto out; } ibs->tx_ibs_state = HCI_IBS_TX_ASLEEP; ibs->ibs_sent_slps++; /* debug */ vote_tx_sleep = 1; break; } spin_unlock_irqrestore(&ibs->hci_ibs_lock, flags); hci_uart_tx_wakeup(hu); /* run HCI tx handling unlocked */ if (!vote_tx_sleep) return; /* now that message queued to tty driver, vote for tty clocks off */ /* It is up to the tty driver to pend the clocks off until tx done. */ spin_lock_irqsave_nested(&ibs->hci_ibs_lock, flags, SINGLE_DEPTH_NESTING); ibs_msm_serial_clock_vote(HCI_IBS_TX_VOTE_CLOCK_OFF, hu); out: spin_unlock_irqrestore(&ibs->hci_ibs_lock, flags); }
/* Close protocol */ static int ibs_close(struct hci_uart *hu) { struct ibs_struct *ibs = hu->priv; BT_DBG("hu %p", hu); ibs_msm_serial_clock_vote(HCI_IBS_VOTE_STATS_UPDATE, hu); ibs_log_local_stats(ibs); skb_queue_purge(&ibs->tx_wait_q); skb_queue_purge(&ibs->txq); del_timer(&ibs->tx_idle_timer); del_timer(&ibs->wake_retrans_timer); kfree_skb(ibs->rx_skb); hu->priv = NULL; kfree(ibs); return 0; }
static void ibs_wq_awake_device(struct work_struct *work) { struct ibs_struct *ibs = container_of(work, struct ibs_struct, ws_awake_device); struct hci_uart *hu = (struct hci_uart *)ibs->ibs_hu; BT_DBG(" %p ", hu); /* Vote for serial clock */ ibs_msm_serial_clock_vote(HCI_IBS_TX_VOTE_CLOCK_ON, hu); spin_lock(&ibs->hci_ibs_lock); /* send wake indication to device */ if (send_hci_ibs_cmd(HCI_IBS_WAKE_IND, hu) < 0) BT_ERR("cannot send WAKE to device"); ibs->ibs_sent_wakes++; /* debug */ /* start retransmit timer */ mod_timer(&ibs->wake_retrans_timer, jiffies + wake_retrans); spin_unlock(&ibs->hci_ibs_lock); }