Merge tag 'dt-5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
[linux-2.6-microblaze.git] / drivers / bluetooth / btrsi.c
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_LICENSE("Dual BSD/GPL");