1/* 2 * 3 * Bluetooth HCI UART driver for Broadcom devices 4 * 5 * Copyright (C) 2015 Intel Corporation 6 * 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 * 22 */ 23 24#include <linux/kernel.h> 25#include <linux/errno.h> 26#include <linux/skbuff.h> 27 28#include <net/bluetooth/bluetooth.h> 29#include <net/bluetooth/hci_core.h> 30 31#include "btbcm.h" 32#include "hci_uart.h" 33 34struct bcm_data { 35 struct sk_buff *rx_skb; 36 struct sk_buff_head txq; 37}; 38 39static int bcm_open(struct hci_uart *hu) 40{ 41 struct bcm_data *bcm; 42 43 BT_DBG("hu %p", hu); 44 45 bcm = kzalloc(sizeof(*bcm), GFP_KERNEL); 46 if (!bcm) 47 return -ENOMEM; 48 49 skb_queue_head_init(&bcm->txq); 50 51 hu->priv = bcm; 52 return 0; 53} 54 55static int bcm_close(struct hci_uart *hu) 56{ 57 struct bcm_data *bcm = hu->priv; 58 59 BT_DBG("hu %p", hu); 60 61 skb_queue_purge(&bcm->txq); 62 kfree_skb(bcm->rx_skb); 63 kfree(bcm); 64 65 hu->priv = NULL; 66 return 0; 67} 68 69static int bcm_flush(struct hci_uart *hu) 70{ 71 struct bcm_data *bcm = hu->priv; 72 73 BT_DBG("hu %p", hu); 74 75 skb_queue_purge(&bcm->txq); 76 77 return 0; 78} 79 80static int bcm_setup(struct hci_uart *hu) 81{ 82 BT_DBG("hu %p", hu); 83 84 hu->hdev->set_bdaddr = btbcm_set_bdaddr; 85 86 return btbcm_setup_patchram(hu->hdev); 87} 88 89static const struct h4_recv_pkt bcm_recv_pkts[] = { 90 { H4_RECV_ACL, .recv = hci_recv_frame }, 91 { H4_RECV_SCO, .recv = hci_recv_frame }, 92 { H4_RECV_EVENT, .recv = hci_recv_frame }, 93}; 94 95static int bcm_recv(struct hci_uart *hu, const void *data, int count) 96{ 97 struct bcm_data *bcm = hu->priv; 98 99 if (!test_bit(HCI_UART_REGISTERED, &hu->flags)) 100 return -EUNATCH; 101 102 bcm->rx_skb = h4_recv_buf(hu->hdev, bcm->rx_skb, data, count, 103 bcm_recv_pkts, ARRAY_SIZE(bcm_recv_pkts)); 104 if (IS_ERR(bcm->rx_skb)) { 105 int err = PTR_ERR(bcm->rx_skb); 106 BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err); 107 return err; 108 } 109 110 return count; 111} 112 113static int bcm_enqueue(struct hci_uart *hu, struct sk_buff *skb) 114{ 115 struct bcm_data *bcm = hu->priv; 116 117 BT_DBG("hu %p skb %p", hu, skb); 118 119 /* Prepend skb with frame type */ 120 memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); 121 skb_queue_tail(&bcm->txq, skb); 122 123 return 0; 124} 125 126static struct sk_buff *bcm_dequeue(struct hci_uart *hu) 127{ 128 struct bcm_data *bcm = hu->priv; 129 130 return skb_dequeue(&bcm->txq); 131} 132 133static const struct hci_uart_proto bcm_proto = { 134 .id = HCI_UART_BCM, 135 .name = "BCM", 136 .open = bcm_open, 137 .close = bcm_close, 138 .flush = bcm_flush, 139 .setup = bcm_setup, 140 .recv = bcm_recv, 141 .enqueue = bcm_enqueue, 142 .dequeue = bcm_dequeue, 143}; 144 145int __init bcm_init(void) 146{ 147 return hci_uart_register_proto(&bcm_proto); 148} 149 150int __exit bcm_deinit(void) 151{ 152 return hci_uart_unregister_proto(&bcm_proto); 153} 154