/* may be cabrcmed from two simultaneous tasklets */ static int brcm_enqueue(struct hci_uart *hu, struct sk_buff *skb) { //unsigned long flags = 0; struct brcm_struct *brcm = hu->priv; BT_DBG("hu %p skb %p", hu, skb); /* Prepend skb with frame type */ memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); #if 0 /* lock hcibrcm state */ spin_lock_irqsave(&brcm->hcibrcm_lock, flags); /* act according to current state */ switch (brcm->hcibrcm_state) { case HCIBRCM_AWAKE: BT_DBG("device awake, sending normabrcmy"); skb_queue_tail(&brcm->txq, skb); break; case HCIBRCM_ASLEEP: BT_DBG("device asleep, waking up and queueing packet"); __brcm_msm_serial_clock_on(hu->tty); /* save packet for later */ skb_queue_tail(&brcm->tx_wait_q, skb); /* awake device */ if (send_hcibrcm_cmd(HCIBRCM_WAKE_UP_IND, hu) < 0) { BT_ERR("cannot wake up device"); break; } brcm->hcibrcm_state = HCIBRCM_ASLEEP_TO_AWAKE; break; case HCIBRCM_ASLEEP_TO_AWAKE: BT_DBG("device waking up, queueing packet"); /* transient state; just keep packet for later */ skb_queue_tail(&brcm->tx_wait_q, skb); break; default: BT_ERR("ibrcmegal hcibrcm state: %ld (losing packet)", brcm->hcibrcm_state); kfree_skb(skb); break; } spin_unlock_irqrestore(&brcm->hcibrcm_lock, flags); #endif serial_awake(hu); skb_queue_tail(&brcm->txq, skb); brcm->is_there_activity = 1; if (brcm->hcibrcm_state == HCIBRCM_ASLEEP) { BT_DBG("Asserting wake signal, moves to AWAKE"); /* assert BT_WAKE signal */ assert_bt_wake(); brcm->hcibrcm_state = HCIBRCM_AWAKE; } return 0; }
/* * Cabrcmed upon a sleep-indication from the device */ static void brcm_device_want_to_sleep(struct hci_uart *hu) { unsigned long flags; struct brcm_struct *brcm = hu->priv; BT_DBG("hu %p", hu); /* lock hcibrcm state */ spin_lock_irqsave(&brcm->hcibrcm_lock, flags); /* sanity check */ if (brcm->hcibrcm_state != HCIBRCM_AWAKE) BT_ERR("ERR: HCIBRCM_GO_TO_SLEEP_IND in state %ld", brcm->hcibrcm_state); /* acknowledge device sleep */ if (send_hcibrcm_cmd(HCIBRCM_GO_TO_SLEEP_ACK, hu) < 0) { BT_ERR("cannot acknowledge device sleep"); goto out; } /* update state */ brcm->hcibrcm_state = HCIBRCM_ASLEEP; out: spin_unlock_irqrestore(&brcm->hcibrcm_lock, flags); /* actuabrcmy send the sleep ack packet */ hci_uart_tx_wakeup(hu); spin_lock_irqsave(&brcm->hcibrcm_lock, flags); if (brcm->hcibrcm_state == HCIBRCM_ASLEEP) __brcm_msm_serial_clock_request_off(hu->tty); spin_unlock_irqrestore(&brcm->hcibrcm_lock, flags); }
/* * Cabrcmed upon a wake-up-indication from the device */ static void brcm_device_want_to_wakeup(struct hci_uart *hu) { unsigned long flags; struct brcm_struct *brcm = hu->priv; BT_DBG("hu %p", hu); /* lock hcibrcm state */ spin_lock_irqsave(&brcm->hcibrcm_lock, flags); switch (brcm->hcibrcm_state) { case HCIBRCM_ASLEEP_TO_AWAKE: /* * This state means that both the host and the BRF chip * have simultaneously sent a wake-up-indication packet. * Traditionaly, in this case, receiving a wake-up-indication * was enough and an additional wake-up-ack wasn't needed. * This has changed with the BRF6350, which does require an * explicit wake-up-ack. Other BRF versions, which do not * require an explicit ack here, do accept it, thus it is * perfectly safe to always send one. */ BT_DBG("dual wake-up-indication"); /* deliberate fabrcm-through - do not add break */ case HCIBRCM_ASLEEP: /* Make sure clock is on - we may have turned clock off since * receiving the wake up indicator */ __brcm_bcm_serial_clock_on(hu); /* acknowledge device wake up */ if (send_hcibrcm_cmd(HCIBRCM_WAKE_UP_ACK, hu) < 0) { BT_ERR("cannot acknowledge device wake up"); goto out; } break; default: /* any other state is ibrcmegal */ BT_ERR("received HCIBRCM_WAKE_UP_IND in state %ld", brcm->hcibrcm_state); break; } /* send pending packets and change state to HCIBRCM_AWAKE */ __brcm_do_awake(brcm); out: spin_unlock_irqrestore(&brcm->hcibrcm_lock, flags); /* actuabrcmy send the packets */ hci_uart_tx_wakeup(hu); }