1/*
2 *
3 *  Bluetooth support 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/module.h>
25#include <linux/firmware.h>
26#include <asm/unaligned.h>
27
28#include <net/bluetooth/bluetooth.h>
29#include <net/bluetooth/hci_core.h>
30
31#include "btbcm.h"
32
33#define VERSION "0.1"
34
35#define BDADDR_BCM20702A0 (&(bdaddr_t) {{0x00, 0xa0, 0x02, 0x70, 0x20, 0x00}})
36
37int btbcm_check_bdaddr(struct hci_dev *hdev)
38{
39	struct hci_rp_read_bd_addr *bda;
40	struct sk_buff *skb;
41
42	skb = __hci_cmd_sync(hdev, HCI_OP_READ_BD_ADDR, 0, NULL,
43			     HCI_INIT_TIMEOUT);
44	if (IS_ERR(skb)) {
45		int err = PTR_ERR(skb);
46		BT_ERR("%s: BCM: Reading device address failed (%d)",
47		       hdev->name, err);
48		return err;
49	}
50
51	if (skb->len != sizeof(*bda)) {
52		BT_ERR("%s: BCM: Device address length mismatch", hdev->name);
53		kfree_skb(skb);
54		return -EIO;
55	}
56
57	bda = (struct hci_rp_read_bd_addr *)skb->data;
58	if (bda->status) {
59		BT_ERR("%s: BCM: Device address result failed (%02x)",
60		       hdev->name, bda->status);
61		kfree_skb(skb);
62		return -bt_to_errno(bda->status);
63	}
64
65	/* The address 00:20:70:02:A0:00 indicates a BCM20702A0 controller
66	 * with no configured address.
67	 */
68	if (!bacmp(&bda->bdaddr, BDADDR_BCM20702A0)) {
69		BT_INFO("%s: BCM: Using default device address (%pMR)",
70			hdev->name, &bda->bdaddr);
71		set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
72	}
73
74	kfree_skb(skb);
75
76	return 0;
77}
78EXPORT_SYMBOL_GPL(btbcm_check_bdaddr);
79
80int btbcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
81{
82	struct sk_buff *skb;
83	int err;
84
85	skb = __hci_cmd_sync(hdev, 0xfc01, 6, bdaddr, HCI_INIT_TIMEOUT);
86	if (IS_ERR(skb)) {
87		err = PTR_ERR(skb);
88		BT_ERR("%s: BCM: Change address command failed (%d)",
89		       hdev->name, err);
90		return err;
91	}
92	kfree_skb(skb);
93
94	return 0;
95}
96EXPORT_SYMBOL_GPL(btbcm_set_bdaddr);
97
98int btbcm_patchram(struct hci_dev *hdev, const char *firmware)
99{
100	const struct hci_command_hdr *cmd;
101	const struct firmware *fw;
102	const u8 *fw_ptr;
103	size_t fw_size;
104	struct sk_buff *skb;
105	u16 opcode;
106	int err;
107
108	err = request_firmware(&fw, firmware, &hdev->dev);
109	if (err < 0) {
110		BT_INFO("%s: BCM: Patch %s not found", hdev->name, firmware);
111		return err;
112	}
113
114	/* Start Download */
115	skb = __hci_cmd_sync(hdev, 0xfc2e, 0, NULL, HCI_INIT_TIMEOUT);
116	if (IS_ERR(skb)) {
117		err = PTR_ERR(skb);
118		BT_ERR("%s: BCM: Download Minidrv command failed (%d)",
119		       hdev->name, err);
120		goto done;
121	}
122	kfree_skb(skb);
123
124	/* 50 msec delay after Download Minidrv completes */
125	msleep(50);
126
127	fw_ptr = fw->data;
128	fw_size = fw->size;
129
130	while (fw_size >= sizeof(*cmd)) {
131		const u8 *cmd_param;
132
133		cmd = (struct hci_command_hdr *)fw_ptr;
134		fw_ptr += sizeof(*cmd);
135		fw_size -= sizeof(*cmd);
136
137		if (fw_size < cmd->plen) {
138			BT_ERR("%s: BCM: Patch %s is corrupted", hdev->name,
139			       firmware);
140			err = -EINVAL;
141			goto done;
142		}
143
144		cmd_param = fw_ptr;
145		fw_ptr += cmd->plen;
146		fw_size -= cmd->plen;
147
148		opcode = le16_to_cpu(cmd->opcode);
149
150		skb = __hci_cmd_sync(hdev, opcode, cmd->plen, cmd_param,
151				     HCI_INIT_TIMEOUT);
152		if (IS_ERR(skb)) {
153			err = PTR_ERR(skb);
154			BT_ERR("%s: BCM: Patch command %04x failed (%d)",
155			       hdev->name, opcode, err);
156			goto done;
157		}
158		kfree_skb(skb);
159	}
160
161	/* 250 msec delay after Launch Ram completes */
162	msleep(250);
163
164done:
165	release_firmware(fw);
166	return err;
167}
168EXPORT_SYMBOL(btbcm_patchram);
169
170static int btbcm_reset(struct hci_dev *hdev)
171{
172	struct sk_buff *skb;
173
174	skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
175	if (IS_ERR(skb)) {
176		int err = PTR_ERR(skb);
177		BT_ERR("%s: BCM: Reset failed (%d)", hdev->name, err);
178		return err;
179	}
180	kfree_skb(skb);
181
182	return 0;
183}
184
185static struct sk_buff *btbcm_read_local_version(struct hci_dev *hdev)
186{
187	struct sk_buff *skb;
188
189	skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL,
190			     HCI_INIT_TIMEOUT);
191	if (IS_ERR(skb)) {
192		BT_ERR("%s: BCM: Reading local version info failed (%ld)",
193		       hdev->name, PTR_ERR(skb));
194		return skb;
195	}
196
197	if (skb->len != sizeof(struct hci_rp_read_local_version)) {
198		BT_ERR("%s: BCM: Local version length mismatch", hdev->name);
199		kfree_skb(skb);
200		return ERR_PTR(-EIO);
201	}
202
203	return skb;
204}
205
206static struct sk_buff *btbcm_read_verbose_config(struct hci_dev *hdev)
207{
208	struct sk_buff *skb;
209
210	skb = __hci_cmd_sync(hdev, 0xfc79, 0, NULL, HCI_INIT_TIMEOUT);
211	if (IS_ERR(skb)) {
212		BT_ERR("%s: BCM: Read verbose config info failed (%ld)",
213		       hdev->name, PTR_ERR(skb));
214		return skb;
215	}
216
217	if (skb->len != 7) {
218		BT_ERR("%s: BCM: Verbose config length mismatch", hdev->name);
219		kfree_skb(skb);
220		return ERR_PTR(-EIO);
221	}
222
223	return skb;
224}
225
226static struct sk_buff *btbcm_read_usb_product(struct hci_dev *hdev)
227{
228	struct sk_buff *skb;
229
230	skb = __hci_cmd_sync(hdev, 0xfc5a, 0, NULL, HCI_INIT_TIMEOUT);
231	if (IS_ERR(skb)) {
232		BT_ERR("%s: BCM: Read USB product info failed (%ld)",
233		       hdev->name, PTR_ERR(skb));
234		return skb;
235	}
236
237	if (skb->len != 5) {
238		BT_ERR("%s: BCM: USB product length mismatch", hdev->name);
239		kfree_skb(skb);
240		return ERR_PTR(-EIO);
241	}
242
243	return skb;
244}
245
246static const struct {
247	u16 subver;
248	const char *name;
249} bcm_uart_subver_table[] = {
250	{ 0x410e, "BCM43341B0"	},	/* 002.001.014 */
251	{ }
252};
253
254static const struct {
255	u16 subver;
256	const char *name;
257} bcm_usb_subver_table[] = {
258	{ 0x210b, "BCM43142A0"	},	/* 001.001.011 */
259	{ 0x2112, "BCM4314A0"	},	/* 001.001.018 */
260	{ 0x2118, "BCM20702A0"	},	/* 001.001.024 */
261	{ 0x2126, "BCM4335A0"	},	/* 001.001.038 */
262	{ 0x220e, "BCM20702A1"	},	/* 001.002.014 */
263	{ 0x230f, "BCM4354A2"	},	/* 001.003.015 */
264	{ 0x4106, "BCM4335B0"	},	/* 002.001.006 */
265	{ 0x410e, "BCM20702B0"	},	/* 002.001.014 */
266	{ 0x6109, "BCM4335C0"	},	/* 003.001.009 */
267	{ 0x610c, "BCM4354"	},	/* 003.001.012 */
268	{ }
269};
270
271int btbcm_setup_patchram(struct hci_dev *hdev)
272{
273	char fw_name[64];
274	u16 subver, rev, pid, vid;
275	const char *hw_name = NULL;
276	struct sk_buff *skb;
277	struct hci_rp_read_local_version *ver;
278	int i, err;
279
280	/* Reset */
281	err = btbcm_reset(hdev);
282	if (err)
283		return err;
284
285	/* Read Local Version Info */
286	skb = btbcm_read_local_version(hdev);
287	if (IS_ERR(skb))
288		return PTR_ERR(skb);
289
290	ver = (struct hci_rp_read_local_version *)skb->data;
291	rev = le16_to_cpu(ver->hci_rev);
292	subver = le16_to_cpu(ver->lmp_subver);
293	kfree_skb(skb);
294
295	/* Read Verbose Config Version Info */
296	skb = btbcm_read_verbose_config(hdev);
297	if (IS_ERR(skb))
298		return PTR_ERR(skb);
299
300	BT_INFO("%s: BCM: chip id %u", hdev->name, skb->data[1]);
301	kfree_skb(skb);
302
303	switch ((rev & 0xf000) >> 12) {
304	case 0:
305		for (i = 0; bcm_uart_subver_table[i].name; i++) {
306			if (subver == bcm_uart_subver_table[i].subver) {
307				hw_name = bcm_uart_subver_table[i].name;
308				break;
309			}
310		}
311
312		snprintf(fw_name, sizeof(fw_name), "brcm/%s.hcd",
313			 hw_name ? : "BCM");
314		break;
315	case 1:
316	case 2:
317		/* Read USB Product Info */
318		skb = btbcm_read_usb_product(hdev);
319		if (IS_ERR(skb))
320			return PTR_ERR(skb);
321
322		vid = get_unaligned_le16(skb->data + 1);
323		pid = get_unaligned_le16(skb->data + 3);
324		kfree_skb(skb);
325
326		for (i = 0; bcm_usb_subver_table[i].name; i++) {
327			if (subver == bcm_usb_subver_table[i].subver) {
328				hw_name = bcm_usb_subver_table[i].name;
329				break;
330			}
331		}
332
333		snprintf(fw_name, sizeof(fw_name), "brcm/%s-%4.4x-%4.4x.hcd",
334			 hw_name ? : "BCM", vid, pid);
335		break;
336	default:
337		return 0;
338	}
339
340	BT_INFO("%s: %s (%3.3u.%3.3u.%3.3u) build %4.4u", hdev->name,
341		hw_name ? : "BCM", (subver & 0x7000) >> 13,
342		(subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff);
343
344	err = btbcm_patchram(hdev, fw_name);
345	if (err == -ENOENT)
346		return 0;
347
348	/* Reset */
349	err = btbcm_reset(hdev);
350	if (err)
351		return err;
352
353	/* Read Local Version Info */
354	skb = btbcm_read_local_version(hdev);
355	if (IS_ERR(skb))
356		return PTR_ERR(skb);
357
358	ver = (struct hci_rp_read_local_version *)skb->data;
359	rev = le16_to_cpu(ver->hci_rev);
360	subver = le16_to_cpu(ver->lmp_subver);
361	kfree_skb(skb);
362
363	BT_INFO("%s: %s (%3.3u.%3.3u.%3.3u) build %4.4u", hdev->name,
364		hw_name ? : "BCM", (subver & 0x7000) >> 13,
365		(subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff);
366
367	btbcm_check_bdaddr(hdev);
368
369	set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
370
371	return 0;
372}
373EXPORT_SYMBOL_GPL(btbcm_setup_patchram);
374
375int btbcm_setup_apple(struct hci_dev *hdev)
376{
377	struct sk_buff *skb;
378
379	/* Read Verbose Config Version Info */
380	skb = btbcm_read_verbose_config(hdev);
381	if (!IS_ERR(skb)) {
382		BT_INFO("%s: BCM: chip id %u build %4.4u", hdev->name, skb->data[1],
383			get_unaligned_le16(skb->data + 5));
384		kfree_skb(skb);
385	}
386
387	set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
388
389	return 0;
390}
391EXPORT_SYMBOL_GPL(btbcm_setup_apple);
392
393MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
394MODULE_DESCRIPTION("Bluetooth support for Broadcom devices ver " VERSION);
395MODULE_VERSION(VERSION);
396MODULE_LICENSE("GPL");
397