2 * Copyright (c) 2017 Redpine Signals Inc.
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.
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.
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>
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)
28 struct rsi_hci_adapter
{
30 struct rsi_proto_ops
*proto_ops
;
34 static int rsi_hci_open(struct hci_dev
*hdev
)
39 static int rsi_hci_close(struct hci_dev
*hdev
)
44 static int rsi_hci_flush(struct hci_dev
*hdev
)
49 static int rsi_hci_send_pkt(struct hci_dev
*hdev
, struct sk_buff
*skb
)
51 struct rsi_hci_adapter
*h_adapter
= hci_get_drvdata(hdev
);
52 struct sk_buff
*new_skb
= NULL
;
54 switch (hci_skb_pkt_type(skb
)) {
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
))
71 bt_cb(new_skb
)->pkt_type
= hci_skb_pkt_type(skb
);
74 if (!IS_ALIGNED((unsigned long)skb
->data
, RSI_DMA_ALIGN
)) {
75 u8
*skb_data
= skb
->data
;
76 int skb_len
= skb
->len
;
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
);
86 return h_adapter
->proto_ops
->coex_send_pkt(h_adapter
->priv
, skb
,
90 static int rsi_hci_recv_pkt(void *priv
, const u8
*pkt
)
92 struct rsi_hci_adapter
*h_adapter
= priv
;
93 struct hci_dev
*hdev
= h_adapter
->hdev
;
95 int pkt_len
= get_unaligned_le16(pkt
) & 0x0fff;
97 skb
= dev_alloc_skb(pkt_len
);
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
;
105 hci_skb_pkt_type(skb
) = pkt
[14];
107 return hci_recv_frame(hdev
, skb
);
110 static int rsi_hci_attach(void *priv
, struct rsi_proto_ops
*ops
)
112 struct rsi_hci_adapter
*h_adapter
= NULL
;
113 struct hci_dev
*hdev
;
116 h_adapter
= kzalloc(sizeof(*h_adapter
), GFP_KERNEL
);
120 h_adapter
->priv
= priv
;
121 ops
->set_bt_context(priv
, h_adapter
);
122 h_adapter
->proto_ops
= ops
;
124 hdev
= hci_alloc_dev();
126 BT_ERR("Failed to alloc HCI device");
130 h_adapter
->hdev
= hdev
;
132 if (ops
->get_host_intf(priv
) == RSI_HOST_INTF_SDIO
)
133 hdev
->bus
= HCI_SDIO
;
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
;
144 err
= hci_register_dev(hdev
);
146 BT_ERR("HCI registration failed with errcode %d", err
);
153 h_adapter
->hdev
= NULL
;
158 static void rsi_hci_detach(void *priv
)
160 struct rsi_hci_adapter
*h_adapter
= priv
;
161 struct hci_dev
*hdev
;
166 hdev
= h_adapter
->hdev
;
168 hci_unregister_dev(hdev
);
170 h_adapter
->hdev
= NULL
;
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
,
181 EXPORT_SYMBOL(rsi_bt_ops
);
183 static int rsi_91x_bt_module_init(void)
188 static void rsi_91x_bt_module_exit(void)
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");