Merge remote-tracking branch 'stable/linux-3.0.y' into develop-3.0
[firefly-linux-kernel-4.4.55.git] / drivers / bluetooth / hci_h4.c
old mode 100644 (file)
new mode 100755 (executable)
index 2fcd8b3..12eb9ee
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 
+#if defined(CONFIG_MT5931_MT6622)
+#include "../mtk_wcn_bt/bt_hwctl.h"
+#if 0//def BT_DBG
+#undef BT_DBG
+#define BT_DBG(fmt, arg...) printk(KERN_INFO "%s" fmt "\n", __FUNCTION__, ##arg)
+#endif
+#endif
+
 #include "hci_uart.h"
 
 #define VERSION "1.2"
@@ -53,6 +61,15 @@ struct h4_struct {
        unsigned long rx_count;
        struct sk_buff *rx_skb;
        struct sk_buff_head txq;
+
+#if defined(CONFIG_MT5931_MT6622)
+       /* add for MT6622 */
+       int rxAck;
+       struct timer_list rxTime;
+       unsigned long last_jiffies;
+       unsigned long ulMagic;
+       spinlock_t ack_lock;
+#endif
 };
 
 /* H4 receiver States */
@@ -62,6 +79,7 @@ struct h4_struct {
 #define H4_W4_SCO_HDR          3
 #define H4_W4_DATA             4
 
+
 /* Initialize protocol */
 static int h4_open(struct hci_uart *hu)
 {
@@ -114,9 +132,55 @@ static int h4_close(struct hci_uart *hu)
 static int h4_enqueue(struct hci_uart *hu, struct sk_buff *skb)
 {
        struct h4_struct *h4 = hu->priv;
-
+#if defined(CONFIG_MT5931_MT6622)
+       unsigned long lCurrentTime = 0; /* in msec */
+       struct sk_buff *skbMagic = NULL; /* used to store magic skb */
+       unsigned char ucMagic = 0xFF;
+#endif
        BT_DBG("hu %p skb %p", hu, skb);
 
+#if defined(CONFIG_MT5931_MT6622)
+       if(bt_cb(skb)->pkt_type == 1){
+               unsigned short usOpCode = 0;
+               usOpCode = (((unsigned short)(skb->data[1])) << 8) | 
+                        ((unsigned short)(skb->data[0]));
+
+               BT_DBG("Command 0x%04x\n", (int)usOpCode);
+
+               if(usOpCode == 0xFCC1){
+                       /* Prepend skb with frame type */
+                       memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
+                       skb_queue_head(&h4->txq, skb);
+
+                       /* because controller has waken host. Host assume device is ready to process. */
+                       clear_bit(1, &h4->ulMagic); /* allow TX to run */
+                       return 0;
+               }
+       }
+
+       /* wake up device */
+       lCurrentTime = jiffies_to_msecs(h4->last_jiffies);
+
+       if((jiffies_to_msecs(jiffies) - lCurrentTime) > 4 * 1000){
+               BT_DBG(" h4_enqueue idle more than 4s 0x%08lx 0x%08lx\n", 
+                       jiffies, h4->last_jiffies);
+
+               /* Allocate packet */
+               skbMagic = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC); /* only 0xFF is required */
+
+               if (!skbMagic) {
+                       BT_ERR("Can't allocate mem for new packet"); /* how to handle? */
+                       return 0;
+               }
+               skbMagic->pkt_type = 1;
+               skbMagic->dev = (void *) hu->hdev;
+
+               memcpy(skb_put(skbMagic, 1), &ucMagic, 1);
+               skb_queue_tail(&h4->txq, skbMagic);
+       }
+       h4->last_jiffies = jiffies;
+#endif
+
        /* Prepend skb with frame type */
        memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
        skb_queue_tail(&h4->txq, skb);
@@ -140,7 +204,6 @@ static inline int h4_check_data_len(struct h4_struct *h4, int len)
                h4->rx_count = len;
                return len;
        }
-
        h4->rx_state = H4_W4_PACKET_TYPE;
        h4->rx_skb   = NULL;
        h4->rx_count = 0;
@@ -151,6 +214,7 @@ static inline int h4_check_data_len(struct h4_struct *h4, int len)
 /* Recv data */
 static int h4_recv(struct hci_uart *hu, void *data, int count)
 {
+#if !defined(CONFIG_MT5931_MT6622)
        int ret;
 
        ret = hci_recv_stream_fragment(hu->hdev, data, count);
@@ -160,12 +224,172 @@ static int h4_recv(struct hci_uart *hu, void *data, int count)
        }
 
        return count;
+#else
+       struct h4_struct *h4 = hu->priv;
+       register char *ptr;
+       struct hci_event_hdr *eh;
+       struct hci_acl_hdr   *ah;
+       struct hci_sco_hdr   *sh;
+       register int len, type, dlen;
+       int iDiscard = 0;
+       int while_count = 0;
+
+       BT_DBG("hu %p count %d rx_state %ld rx_count %ld", 
+               hu, count, h4->rx_state, h4->rx_count);
+
+       ptr = data;
+       while (count) {
+               while_count ++;
+
+               if(while_count > 5000){
+                       BT_ERR("h4_recv while_count %d\n", while_count);
+               }
+
+               if (h4->rx_count) {
+                       len = min_t(unsigned int, h4->rx_count, count);
+                       memcpy(skb_put(h4->rx_skb, len), ptr, len);
+                       h4->rx_count -= len; count -= len; ptr += len;
+
+                       if (h4->rx_count)
+                               continue;
+
+                       switch (h4->rx_state) {
+                       case H4_W4_DATA:
+                               iDiscard = 0; /* default not to drop packet */
+                               if(HCI_EVENT_PKT == bt_cb(h4->rx_skb)->pkt_type){
+                                       unsigned short usOpCode = 0;
+
+                                       eh = hci_event_hdr(h4->rx_skb);
+                   
+                                       switch(eh->evt){
+                                       case HCI_EV_CMD_COMPLETE:
+                                               usOpCode = (((unsigned short)(h4->rx_skb->data[4])) << 8) | 
+                                                       ((unsigned short)(h4->rx_skb->data[3]));
+
+                                               if(usOpCode == 0xFCC0){
+                                                       iDiscard = 1;
+                                                       clear_bit(1, &h4->ulMagic); /* allow TX to run */
+                                                       BT_DBG("recv event 0x%04x\n", (int)usOpCode);
+                                                       /* flag is cleared. we may resume TX. or later? */
+                                                       hci_uart_tx_wakeup(hu);
+                                               }
+
+                                               if(usOpCode == 0xFCC1){                        
+                                                       BT_DBG("recv host awake command event 0x%04x\n", (int)usOpCode);
+                                                       //mt_bt_enable_irq();
+                                               }
+                                               break;
+                                       }
+                               }
+
+                               if(!iDiscard){
+                                   hci_recv_frame(h4->rx_skb);
+                               }
+                               else{ 
+                                   kfree_skb(h4->rx_skb);
+                               }
+
+                               h4->rx_state = H4_W4_PACKET_TYPE;
+                               h4->rx_skb = NULL;
+                               continue;
+
+                       case H4_W4_EVENT_HDR:
+                               eh = hci_event_hdr(h4->rx_skb);
+
+                               BT_DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen);
+
+                               h4_check_data_len(h4, eh->plen);
+                               continue;
+
+                       case H4_W4_ACL_HDR:
+                               ah = hci_acl_hdr(h4->rx_skb);
+                               dlen = __le16_to_cpu(ah->dlen);
+
+                               BT_DBG("ACL header: dlen %d", dlen);
+                               h4_check_data_len(h4, dlen);
+                               continue;
+
+                       case H4_W4_SCO_HDR:
+                               sh = hci_sco_hdr(h4->rx_skb);
+
+                               BT_DBG("SCO header: dlen %d", sh->dlen);
+
+                               h4_check_data_len(h4, sh->dlen);
+                               continue;
+                       }
+               }
+
+               /* H4_W4_PACKET_TYPE */
+               switch (*ptr) {
+               case HCI_EVENT_PKT:
+                       BT_DBG("Event packet");
+                       h4->rx_state = H4_W4_EVENT_HDR;
+                       h4->rx_count = HCI_EVENT_HDR_SIZE;
+                       type = HCI_EVENT_PKT;
+                       break;
+
+               case HCI_ACLDATA_PKT:
+                       BT_DBG("ACL packet");
+                       h4->rx_state = H4_W4_ACL_HDR;
+                       h4->rx_count = HCI_ACL_HDR_SIZE;
+                       type = HCI_ACLDATA_PKT;
+                       break;
+
+               case HCI_SCODATA_PKT:
+                       BT_DBG("SCO packet");
+                       h4->rx_state = H4_W4_SCO_HDR;
+                       h4->rx_count = HCI_SCO_HDR_SIZE;
+                       type = HCI_SCODATA_PKT;
+                       break;
+
+               default:
+                       BT_ERR("Unknown HCI packet type %2.2x", (__u8)*ptr);
+                       hu->hdev->stat.err_rx++;
+                       ptr++; count--;
+                       continue;
+               };
+
+               ptr++; count--;
+               /* Allocate packet */
+               h4->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
+               if (!h4->rx_skb) {
+                       BT_ERR("Can't allocate mem for new packet");
+                       h4->rx_state = H4_W4_PACKET_TYPE;
+                       h4->rx_count = 0;
+                       return 0;
+               }
+
+               h4->rx_skb->dev = (void *) hu->hdev;
+               bt_cb(h4->rx_skb)->pkt_type = type;
+       }
+
+       return count;
+#endif
 }
 
 static struct sk_buff *h4_dequeue(struct hci_uart *hu)
 {
        struct h4_struct *h4 = hu->priv;
+#if !defined(CONFIG_MT5931_MT6622)
        return skb_dequeue(&h4->txq);
+#else
+       struct sk_buff *skb = NULL;
+
+       if(test_bit(1, &h4->ulMagic)){
+               BT_DBG("magic number is being performed\n");
+               return NULL;
+       }
+
+       skb = skb_dequeue(&h4->txq);
+
+       if(skb){
+               if((skb->pkt_type == 1) && (skb->len == 1) && (skb->data[0] == 0xFF)){
+                       BT_DBG("h4_dequeue magic number\n");
+                       set_bit(1, &h4->ulMagic);
+               }
+       }
+       return skb;
+#endif
 }
 
 static struct hci_uart_proto h4p = {