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