root/drivers/bluetooth/btrsi.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rsi_hci_open
  2. rsi_hci_close
  3. rsi_hci_flush
  4. rsi_hci_send_pkt
  5. rsi_hci_recv_pkt
  6. rsi_hci_attach
  7. rsi_hci_detach
  8. rsi_91x_bt_module_init
  9. rsi_91x_bt_module_exit

   1 /**
   2  * Copyright (c) 2017 Redpine Signals Inc.
   3  *
   4  * Permission to use, copy, modify, and/or distribute this software for any
   5  * purpose with or without fee is hereby granted, provided that the above
   6  * copyright notice and this permission notice appear in all copies.
   7  *
   8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15  */
  16 #include <linux/module.h>
  17 #include <linux/kernel.h>
  18 #include <net/bluetooth/bluetooth.h>
  19 #include <net/bluetooth/hci_core.h>
  20 #include <asm/unaligned.h>
  21 #include <net/rsi_91x.h>
  22 #include <net/genetlink.h>
  23 
  24 #define RSI_DMA_ALIGN   8
  25 #define RSI_FRAME_DESC_SIZE     16
  26 #define RSI_HEADROOM_FOR_BT_HAL (RSI_FRAME_DESC_SIZE + RSI_DMA_ALIGN)
  27 
  28 struct rsi_hci_adapter {
  29         void *priv;
  30         struct rsi_proto_ops *proto_ops;
  31         struct hci_dev *hdev;
  32 };
  33 
  34 static int rsi_hci_open(struct hci_dev *hdev)
  35 {
  36         return 0;
  37 }
  38 
  39 static int rsi_hci_close(struct hci_dev *hdev)
  40 {
  41         return 0;
  42 }
  43 
  44 static int rsi_hci_flush(struct hci_dev *hdev)
  45 {
  46         return 0;
  47 }
  48 
  49 static int rsi_hci_send_pkt(struct hci_dev *hdev, struct sk_buff *skb)
  50 {
  51         struct rsi_hci_adapter *h_adapter = hci_get_drvdata(hdev);
  52         struct sk_buff *new_skb = NULL;
  53 
  54         switch (hci_skb_pkt_type(skb)) {
  55         case HCI_COMMAND_PKT:
  56                 hdev->stat.cmd_tx++;
  57                 break;
  58         case HCI_ACLDATA_PKT:
  59                 hdev->stat.acl_tx++;
  60                 break;
  61         case HCI_SCODATA_PKT:
  62                 hdev->stat.sco_tx++;
  63                 break;
  64         }
  65 
  66         if (skb_headroom(skb) < RSI_HEADROOM_FOR_BT_HAL) {
  67                 /* Insufficient skb headroom - allocate a new skb */
  68                 new_skb = skb_realloc_headroom(skb, RSI_HEADROOM_FOR_BT_HAL);
  69                 if (unlikely(!new_skb))
  70                         return -ENOMEM;
  71                 bt_cb(new_skb)->pkt_type = hci_skb_pkt_type(skb);
  72                 kfree_skb(skb);
  73                 skb = new_skb;
  74                 if (!IS_ALIGNED((unsigned long)skb->data, RSI_DMA_ALIGN)) {
  75                         u8 *skb_data = skb->data;
  76                         int skb_len = skb->len;
  77 
  78                         skb_push(skb, RSI_DMA_ALIGN);
  79                         skb_pull(skb, PTR_ALIGN(skb->data,
  80                                                 RSI_DMA_ALIGN) - skb->data);
  81                         memmove(skb->data, skb_data, skb_len);
  82                         skb_trim(skb, skb_len);
  83                 }
  84         }
  85 
  86         return h_adapter->proto_ops->coex_send_pkt(h_adapter->priv, skb,
  87                                                    RSI_BT_Q);
  88 }
  89 
  90 static int rsi_hci_recv_pkt(void *priv, const u8 *pkt)
  91 {
  92         struct rsi_hci_adapter *h_adapter = priv;
  93         struct hci_dev *hdev = h_adapter->hdev;
  94         struct sk_buff *skb;
  95         int pkt_len = get_unaligned_le16(pkt) & 0x0fff;
  96 
  97         skb = dev_alloc_skb(pkt_len);
  98         if (!skb)
  99                 return -ENOMEM;
 100 
 101         memcpy(skb->data, pkt + RSI_FRAME_DESC_SIZE, pkt_len);
 102         skb_put(skb, pkt_len);
 103         h_adapter->hdev->stat.byte_rx += skb->len;
 104 
 105         hci_skb_pkt_type(skb) = pkt[14];
 106 
 107         return hci_recv_frame(hdev, skb);
 108 }
 109 
 110 static int rsi_hci_attach(void *priv, struct rsi_proto_ops *ops)
 111 {
 112         struct rsi_hci_adapter *h_adapter = NULL;
 113         struct hci_dev *hdev;
 114         int err = 0;
 115 
 116         h_adapter = kzalloc(sizeof(*h_adapter), GFP_KERNEL);
 117         if (!h_adapter)
 118                 return -ENOMEM;
 119 
 120         h_adapter->priv = priv;
 121         ops->set_bt_context(priv, h_adapter);
 122         h_adapter->proto_ops = ops;
 123 
 124         hdev = hci_alloc_dev();
 125         if (!hdev) {
 126                 BT_ERR("Failed to alloc HCI device");
 127                 goto err;
 128         }
 129 
 130         h_adapter->hdev = hdev;
 131 
 132         if (ops->get_host_intf(priv) == RSI_HOST_INTF_SDIO)
 133                 hdev->bus = HCI_SDIO;
 134         else
 135                 hdev->bus = HCI_USB;
 136 
 137         hci_set_drvdata(hdev, h_adapter);
 138         hdev->dev_type = HCI_PRIMARY;
 139         hdev->open = rsi_hci_open;
 140         hdev->close = rsi_hci_close;
 141         hdev->flush = rsi_hci_flush;
 142         hdev->send = rsi_hci_send_pkt;
 143 
 144         err = hci_register_dev(hdev);
 145         if (err < 0) {
 146                 BT_ERR("HCI registration failed with errcode %d", err);
 147                 hci_free_dev(hdev);
 148                 goto err;
 149         }
 150 
 151         return 0;
 152 err:
 153         h_adapter->hdev = NULL;
 154         kfree(h_adapter);
 155         return -EINVAL;
 156 }
 157 
 158 static void rsi_hci_detach(void *priv)
 159 {
 160         struct rsi_hci_adapter *h_adapter = priv;
 161         struct hci_dev *hdev;
 162 
 163         if (!h_adapter)
 164                 return;
 165 
 166         hdev = h_adapter->hdev;
 167         if (hdev) {
 168                 hci_unregister_dev(hdev);
 169                 hci_free_dev(hdev);
 170                 h_adapter->hdev = NULL;
 171         }
 172 
 173         kfree(h_adapter);
 174 }
 175 
 176 const struct rsi_mod_ops rsi_bt_ops = {
 177         .attach = rsi_hci_attach,
 178         .detach = rsi_hci_detach,
 179         .recv_pkt = rsi_hci_recv_pkt,
 180 };
 181 EXPORT_SYMBOL(rsi_bt_ops);
 182 
 183 static int rsi_91x_bt_module_init(void)
 184 {
 185         return 0;
 186 }
 187 
 188 static void rsi_91x_bt_module_exit(void)
 189 {
 190         return;
 191 }
 192 
 193 module_init(rsi_91x_bt_module_init);
 194 module_exit(rsi_91x_bt_module_exit);
 195 MODULE_AUTHOR("Redpine Signals Inc");
 196 MODULE_DESCRIPTION("RSI BT driver");
 197 MODULE_SUPPORTED_DEVICE("RSI-BT");
 198 MODULE_LICENSE("Dual BSD/GPL");

/* [<][>][^][v][top][bottom][index][help] */