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