linux/drivers/bluetooth/btrsi.c
<<
>>
Prefs
   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
  28struct rsi_hci_adapter {
  29        void *priv;
  30        struct rsi_proto_ops *proto_ops;
  31        struct hci_dev *hdev;
  32};
  33
  34static int rsi_hci_open(struct hci_dev *hdev)
  35{
  36        return 0;
  37}
  38
  39static int rsi_hci_close(struct hci_dev *hdev)
  40{
  41        return 0;
  42}
  43
  44static int rsi_hci_flush(struct hci_dev *hdev)
  45{
  46        return 0;
  47}
  48
  49static 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
  90static 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
 110static 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;
 152err:
 153        h_adapter->hdev = NULL;
 154        kfree(h_adapter);
 155        return -EINVAL;
 156}
 157
 158static 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
 176const 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};
 181EXPORT_SYMBOL(rsi_bt_ops);
 182
 183static int rsi_91x_bt_module_init(void)
 184{
 185        return 0;
 186}
 187
 188static void rsi_91x_bt_module_exit(void)
 189{
 190        return;
 191}
 192
 193module_init(rsi_91x_bt_module_init);
 194module_exit(rsi_91x_bt_module_exit);
 195MODULE_AUTHOR("Redpine Signals Inc");
 196MODULE_DESCRIPTION("RSI BT driver");
 197MODULE_LICENSE("Dual BSD/GPL");
 198