162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci *  AVM BlueFRITZ! USB driver
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci *  Copyright (C) 2003-2006  Marcel Holtmann <marcel@holtmann.org>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/module.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/kernel.h>
1262306a36Sopenharmony_ci#include <linux/init.h>
1362306a36Sopenharmony_ci#include <linux/slab.h>
1462306a36Sopenharmony_ci#include <linux/types.h>
1562306a36Sopenharmony_ci#include <linux/errno.h>
1662306a36Sopenharmony_ci#include <linux/skbuff.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include <linux/device.h>
1962306a36Sopenharmony_ci#include <linux/firmware.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include <linux/usb.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include <net/bluetooth/bluetooth.h>
2462306a36Sopenharmony_ci#include <net/bluetooth/hci_core.h>
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define VERSION "1.2"
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic struct usb_driver bfusb_driver;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistatic const struct usb_device_id bfusb_table[] = {
3162306a36Sopenharmony_ci	/* AVM BlueFRITZ! USB */
3262306a36Sopenharmony_ci	{ USB_DEVICE(0x057c, 0x2200) },
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	{ }	/* Terminating entry */
3562306a36Sopenharmony_ci};
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, bfusb_table);
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci#define BFUSB_MAX_BLOCK_SIZE	256
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#define BFUSB_BLOCK_TIMEOUT	3000
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#define BFUSB_TX_PROCESS	1
4462306a36Sopenharmony_ci#define BFUSB_TX_WAKEUP		2
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci#define BFUSB_MAX_BULK_TX	2
4762306a36Sopenharmony_ci#define BFUSB_MAX_BULK_RX	2
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistruct bfusb_data {
5062306a36Sopenharmony_ci	struct hci_dev		*hdev;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	unsigned long		state;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	struct usb_device	*udev;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	unsigned int		bulk_in_ep;
5762306a36Sopenharmony_ci	unsigned int		bulk_out_ep;
5862306a36Sopenharmony_ci	unsigned int		bulk_pkt_size;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	rwlock_t		lock;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	struct sk_buff_head	transmit_q;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	struct sk_buff		*reassembly;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	atomic_t		pending_tx;
6762306a36Sopenharmony_ci	struct sk_buff_head	pending_q;
6862306a36Sopenharmony_ci	struct sk_buff_head	completed_q;
6962306a36Sopenharmony_ci};
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistruct bfusb_data_scb {
7262306a36Sopenharmony_ci	struct urb *urb;
7362306a36Sopenharmony_ci};
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistatic void bfusb_tx_complete(struct urb *urb);
7662306a36Sopenharmony_cistatic void bfusb_rx_complete(struct urb *urb);
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic struct urb *bfusb_get_completed(struct bfusb_data *data)
7962306a36Sopenharmony_ci{
8062306a36Sopenharmony_ci	struct sk_buff *skb;
8162306a36Sopenharmony_ci	struct urb *urb = NULL;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	BT_DBG("bfusb %p", data);
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	skb = skb_dequeue(&data->completed_q);
8662306a36Sopenharmony_ci	if (skb) {
8762306a36Sopenharmony_ci		urb = ((struct bfusb_data_scb *) skb->cb)->urb;
8862306a36Sopenharmony_ci		kfree_skb(skb);
8962306a36Sopenharmony_ci	}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	return urb;
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistatic void bfusb_unlink_urbs(struct bfusb_data *data)
9562306a36Sopenharmony_ci{
9662306a36Sopenharmony_ci	struct sk_buff *skb;
9762306a36Sopenharmony_ci	struct urb *urb;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	BT_DBG("bfusb %p", data);
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	while ((skb = skb_dequeue(&data->pending_q))) {
10262306a36Sopenharmony_ci		urb = ((struct bfusb_data_scb *) skb->cb)->urb;
10362306a36Sopenharmony_ci		usb_kill_urb(urb);
10462306a36Sopenharmony_ci		skb_queue_tail(&data->completed_q, skb);
10562306a36Sopenharmony_ci	}
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	while ((urb = bfusb_get_completed(data)))
10862306a36Sopenharmony_ci		usb_free_urb(urb);
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistatic int bfusb_send_bulk(struct bfusb_data *data, struct sk_buff *skb)
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	struct bfusb_data_scb *scb = (void *) skb->cb;
11462306a36Sopenharmony_ci	struct urb *urb = bfusb_get_completed(data);
11562306a36Sopenharmony_ci	int err, pipe;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	BT_DBG("bfusb %p skb %p len %d", data, skb, skb->len);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	if (!urb) {
12062306a36Sopenharmony_ci		urb = usb_alloc_urb(0, GFP_ATOMIC);
12162306a36Sopenharmony_ci		if (!urb)
12262306a36Sopenharmony_ci			return -ENOMEM;
12362306a36Sopenharmony_ci	}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	pipe = usb_sndbulkpipe(data->udev, data->bulk_out_ep);
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	usb_fill_bulk_urb(urb, data->udev, pipe, skb->data, skb->len,
12862306a36Sopenharmony_ci			bfusb_tx_complete, skb);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	scb->urb = urb;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	skb_queue_tail(&data->pending_q, skb);
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	err = usb_submit_urb(urb, GFP_ATOMIC);
13562306a36Sopenharmony_ci	if (err) {
13662306a36Sopenharmony_ci		bt_dev_err(data->hdev, "bulk tx submit failed urb %p err %d",
13762306a36Sopenharmony_ci			   urb, err);
13862306a36Sopenharmony_ci		skb_unlink(skb, &data->pending_q);
13962306a36Sopenharmony_ci		usb_free_urb(urb);
14062306a36Sopenharmony_ci	} else
14162306a36Sopenharmony_ci		atomic_inc(&data->pending_tx);
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	return err;
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_cistatic void bfusb_tx_wakeup(struct bfusb_data *data)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	struct sk_buff *skb;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	BT_DBG("bfusb %p", data);
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	if (test_and_set_bit(BFUSB_TX_PROCESS, &data->state)) {
15362306a36Sopenharmony_ci		set_bit(BFUSB_TX_WAKEUP, &data->state);
15462306a36Sopenharmony_ci		return;
15562306a36Sopenharmony_ci	}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	do {
15862306a36Sopenharmony_ci		clear_bit(BFUSB_TX_WAKEUP, &data->state);
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci		while ((atomic_read(&data->pending_tx) < BFUSB_MAX_BULK_TX) &&
16162306a36Sopenharmony_ci				(skb = skb_dequeue(&data->transmit_q))) {
16262306a36Sopenharmony_ci			if (bfusb_send_bulk(data, skb) < 0) {
16362306a36Sopenharmony_ci				skb_queue_head(&data->transmit_q, skb);
16462306a36Sopenharmony_ci				break;
16562306a36Sopenharmony_ci			}
16662306a36Sopenharmony_ci		}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	} while (test_bit(BFUSB_TX_WAKEUP, &data->state));
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	clear_bit(BFUSB_TX_PROCESS, &data->state);
17162306a36Sopenharmony_ci}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_cistatic void bfusb_tx_complete(struct urb *urb)
17462306a36Sopenharmony_ci{
17562306a36Sopenharmony_ci	struct sk_buff *skb = (struct sk_buff *) urb->context;
17662306a36Sopenharmony_ci	struct bfusb_data *data = (struct bfusb_data *) skb->dev;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	BT_DBG("bfusb %p urb %p skb %p len %d", data, urb, skb, skb->len);
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	atomic_dec(&data->pending_tx);
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	if (!test_bit(HCI_RUNNING, &data->hdev->flags))
18362306a36Sopenharmony_ci		return;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	if (!urb->status)
18662306a36Sopenharmony_ci		data->hdev->stat.byte_tx += skb->len;
18762306a36Sopenharmony_ci	else
18862306a36Sopenharmony_ci		data->hdev->stat.err_tx++;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	read_lock(&data->lock);
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	skb_unlink(skb, &data->pending_q);
19362306a36Sopenharmony_ci	skb_queue_tail(&data->completed_q, skb);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	bfusb_tx_wakeup(data);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	read_unlock(&data->lock);
19862306a36Sopenharmony_ci}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_cistatic int bfusb_rx_submit(struct bfusb_data *data, struct urb *urb)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	struct bfusb_data_scb *scb;
20462306a36Sopenharmony_ci	struct sk_buff *skb;
20562306a36Sopenharmony_ci	int err, pipe, size = HCI_MAX_FRAME_SIZE + 32;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	BT_DBG("bfusb %p urb %p", data, urb);
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	if (!urb) {
21062306a36Sopenharmony_ci		urb = usb_alloc_urb(0, GFP_ATOMIC);
21162306a36Sopenharmony_ci		if (!urb)
21262306a36Sopenharmony_ci			return -ENOMEM;
21362306a36Sopenharmony_ci	}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	skb = bt_skb_alloc(size, GFP_ATOMIC);
21662306a36Sopenharmony_ci	if (!skb) {
21762306a36Sopenharmony_ci		usb_free_urb(urb);
21862306a36Sopenharmony_ci		return -ENOMEM;
21962306a36Sopenharmony_ci	}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	skb->dev = (void *) data;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	scb = (struct bfusb_data_scb *) skb->cb;
22462306a36Sopenharmony_ci	scb->urb = urb;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	pipe = usb_rcvbulkpipe(data->udev, data->bulk_in_ep);
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	usb_fill_bulk_urb(urb, data->udev, pipe, skb->data, size,
22962306a36Sopenharmony_ci			bfusb_rx_complete, skb);
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	skb_queue_tail(&data->pending_q, skb);
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	err = usb_submit_urb(urb, GFP_ATOMIC);
23462306a36Sopenharmony_ci	if (err) {
23562306a36Sopenharmony_ci		bt_dev_err(data->hdev, "bulk rx submit failed urb %p err %d",
23662306a36Sopenharmony_ci			   urb, err);
23762306a36Sopenharmony_ci		skb_unlink(skb, &data->pending_q);
23862306a36Sopenharmony_ci		kfree_skb(skb);
23962306a36Sopenharmony_ci		usb_free_urb(urb);
24062306a36Sopenharmony_ci	}
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	return err;
24362306a36Sopenharmony_ci}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_cistatic inline int bfusb_recv_block(struct bfusb_data *data, int hdr, unsigned char *buf, int len)
24662306a36Sopenharmony_ci{
24762306a36Sopenharmony_ci	BT_DBG("bfusb %p hdr 0x%02x data %p len %d", data, hdr, buf, len);
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	if (hdr & 0x10) {
25062306a36Sopenharmony_ci		bt_dev_err(data->hdev, "error in block");
25162306a36Sopenharmony_ci		kfree_skb(data->reassembly);
25262306a36Sopenharmony_ci		data->reassembly = NULL;
25362306a36Sopenharmony_ci		return -EIO;
25462306a36Sopenharmony_ci	}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	if (hdr & 0x04) {
25762306a36Sopenharmony_ci		struct sk_buff *skb;
25862306a36Sopenharmony_ci		unsigned char pkt_type;
25962306a36Sopenharmony_ci		int pkt_len = 0;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci		if (data->reassembly) {
26262306a36Sopenharmony_ci			bt_dev_err(data->hdev, "unexpected start block");
26362306a36Sopenharmony_ci			kfree_skb(data->reassembly);
26462306a36Sopenharmony_ci			data->reassembly = NULL;
26562306a36Sopenharmony_ci		}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci		if (len < 1) {
26862306a36Sopenharmony_ci			bt_dev_err(data->hdev, "no packet type found");
26962306a36Sopenharmony_ci			return -EPROTO;
27062306a36Sopenharmony_ci		}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci		pkt_type = *buf++; len--;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci		switch (pkt_type) {
27562306a36Sopenharmony_ci		case HCI_EVENT_PKT:
27662306a36Sopenharmony_ci			if (len >= HCI_EVENT_HDR_SIZE) {
27762306a36Sopenharmony_ci				struct hci_event_hdr *hdr = (struct hci_event_hdr *) buf;
27862306a36Sopenharmony_ci				pkt_len = HCI_EVENT_HDR_SIZE + hdr->plen;
27962306a36Sopenharmony_ci			} else {
28062306a36Sopenharmony_ci				bt_dev_err(data->hdev, "event block is too short");
28162306a36Sopenharmony_ci				return -EILSEQ;
28262306a36Sopenharmony_ci			}
28362306a36Sopenharmony_ci			break;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci		case HCI_ACLDATA_PKT:
28662306a36Sopenharmony_ci			if (len >= HCI_ACL_HDR_SIZE) {
28762306a36Sopenharmony_ci				struct hci_acl_hdr *hdr = (struct hci_acl_hdr *) buf;
28862306a36Sopenharmony_ci				pkt_len = HCI_ACL_HDR_SIZE + __le16_to_cpu(hdr->dlen);
28962306a36Sopenharmony_ci			} else {
29062306a36Sopenharmony_ci				bt_dev_err(data->hdev, "data block is too short");
29162306a36Sopenharmony_ci				return -EILSEQ;
29262306a36Sopenharmony_ci			}
29362306a36Sopenharmony_ci			break;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci		case HCI_SCODATA_PKT:
29662306a36Sopenharmony_ci			if (len >= HCI_SCO_HDR_SIZE) {
29762306a36Sopenharmony_ci				struct hci_sco_hdr *hdr = (struct hci_sco_hdr *) buf;
29862306a36Sopenharmony_ci				pkt_len = HCI_SCO_HDR_SIZE + hdr->dlen;
29962306a36Sopenharmony_ci			} else {
30062306a36Sopenharmony_ci				bt_dev_err(data->hdev, "audio block is too short");
30162306a36Sopenharmony_ci				return -EILSEQ;
30262306a36Sopenharmony_ci			}
30362306a36Sopenharmony_ci			break;
30462306a36Sopenharmony_ci		}
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci		skb = bt_skb_alloc(pkt_len, GFP_ATOMIC);
30762306a36Sopenharmony_ci		if (!skb) {
30862306a36Sopenharmony_ci			bt_dev_err(data->hdev, "no memory for the packet");
30962306a36Sopenharmony_ci			return -ENOMEM;
31062306a36Sopenharmony_ci		}
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci		hci_skb_pkt_type(skb) = pkt_type;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci		data->reassembly = skb;
31562306a36Sopenharmony_ci	} else {
31662306a36Sopenharmony_ci		if (!data->reassembly) {
31762306a36Sopenharmony_ci			bt_dev_err(data->hdev, "unexpected continuation block");
31862306a36Sopenharmony_ci			return -EIO;
31962306a36Sopenharmony_ci		}
32062306a36Sopenharmony_ci	}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	if (len > 0)
32362306a36Sopenharmony_ci		skb_put_data(data->reassembly, buf, len);
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	if (hdr & 0x08) {
32662306a36Sopenharmony_ci		hci_recv_frame(data->hdev, data->reassembly);
32762306a36Sopenharmony_ci		data->reassembly = NULL;
32862306a36Sopenharmony_ci	}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	return 0;
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_cistatic void bfusb_rx_complete(struct urb *urb)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	struct sk_buff *skb = (struct sk_buff *) urb->context;
33662306a36Sopenharmony_ci	struct bfusb_data *data = (struct bfusb_data *) skb->dev;
33762306a36Sopenharmony_ci	unsigned char *buf = urb->transfer_buffer;
33862306a36Sopenharmony_ci	int count = urb->actual_length;
33962306a36Sopenharmony_ci	int err, hdr, len;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	BT_DBG("bfusb %p urb %p skb %p len %d", data, urb, skb, skb->len);
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	read_lock(&data->lock);
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	if (!test_bit(HCI_RUNNING, &data->hdev->flags))
34662306a36Sopenharmony_ci		goto unlock;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	if (urb->status || !count)
34962306a36Sopenharmony_ci		goto resubmit;
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	data->hdev->stat.byte_rx += count;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	skb_put(skb, count);
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	while (count) {
35662306a36Sopenharmony_ci		hdr = buf[0] | (buf[1] << 8);
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci		if (hdr & 0x4000) {
35962306a36Sopenharmony_ci			len = 0;
36062306a36Sopenharmony_ci			count -= 2;
36162306a36Sopenharmony_ci			buf   += 2;
36262306a36Sopenharmony_ci		} else {
36362306a36Sopenharmony_ci			len = (buf[2] == 0) ? 256 : buf[2];
36462306a36Sopenharmony_ci			count -= 3;
36562306a36Sopenharmony_ci			buf   += 3;
36662306a36Sopenharmony_ci		}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci		if (count < len) {
36962306a36Sopenharmony_ci			bt_dev_err(data->hdev, "block extends over URB buffer ranges");
37062306a36Sopenharmony_ci		}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci		if ((hdr & 0xe1) == 0xc1)
37362306a36Sopenharmony_ci			bfusb_recv_block(data, hdr, buf, len);
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci		count -= len;
37662306a36Sopenharmony_ci		buf   += len;
37762306a36Sopenharmony_ci	}
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	skb_unlink(skb, &data->pending_q);
38062306a36Sopenharmony_ci	kfree_skb(skb);
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	bfusb_rx_submit(data, urb);
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	read_unlock(&data->lock);
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	return;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ciresubmit:
38962306a36Sopenharmony_ci	urb->dev = data->udev;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	err = usb_submit_urb(urb, GFP_ATOMIC);
39262306a36Sopenharmony_ci	if (err) {
39362306a36Sopenharmony_ci		bt_dev_err(data->hdev, "bulk resubmit failed urb %p err %d",
39462306a36Sopenharmony_ci			   urb, err);
39562306a36Sopenharmony_ci	}
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ciunlock:
39862306a36Sopenharmony_ci	read_unlock(&data->lock);
39962306a36Sopenharmony_ci}
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_cistatic int bfusb_open(struct hci_dev *hdev)
40262306a36Sopenharmony_ci{
40362306a36Sopenharmony_ci	struct bfusb_data *data = hci_get_drvdata(hdev);
40462306a36Sopenharmony_ci	unsigned long flags;
40562306a36Sopenharmony_ci	int i, err;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	BT_DBG("hdev %p bfusb %p", hdev, data);
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	write_lock_irqsave(&data->lock, flags);
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	err = bfusb_rx_submit(data, NULL);
41262306a36Sopenharmony_ci	if (!err) {
41362306a36Sopenharmony_ci		for (i = 1; i < BFUSB_MAX_BULK_RX; i++)
41462306a36Sopenharmony_ci			bfusb_rx_submit(data, NULL);
41562306a36Sopenharmony_ci	}
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	write_unlock_irqrestore(&data->lock, flags);
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	return err;
42062306a36Sopenharmony_ci}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_cistatic int bfusb_flush(struct hci_dev *hdev)
42362306a36Sopenharmony_ci{
42462306a36Sopenharmony_ci	struct bfusb_data *data = hci_get_drvdata(hdev);
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	BT_DBG("hdev %p bfusb %p", hdev, data);
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	skb_queue_purge(&data->transmit_q);
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	return 0;
43162306a36Sopenharmony_ci}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_cistatic int bfusb_close(struct hci_dev *hdev)
43462306a36Sopenharmony_ci{
43562306a36Sopenharmony_ci	struct bfusb_data *data = hci_get_drvdata(hdev);
43662306a36Sopenharmony_ci	unsigned long flags;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	BT_DBG("hdev %p bfusb %p", hdev, data);
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	write_lock_irqsave(&data->lock, flags);
44162306a36Sopenharmony_ci	write_unlock_irqrestore(&data->lock, flags);
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	bfusb_unlink_urbs(data);
44462306a36Sopenharmony_ci	bfusb_flush(hdev);
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	return 0;
44762306a36Sopenharmony_ci}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_cistatic int bfusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	struct bfusb_data *data = hci_get_drvdata(hdev);
45262306a36Sopenharmony_ci	struct sk_buff *nskb;
45362306a36Sopenharmony_ci	unsigned char buf[3];
45462306a36Sopenharmony_ci	int sent = 0, size, count;
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	BT_DBG("hdev %p skb %p type %d len %d", hdev, skb,
45762306a36Sopenharmony_ci	       hci_skb_pkt_type(skb), skb->len);
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	switch (hci_skb_pkt_type(skb)) {
46062306a36Sopenharmony_ci	case HCI_COMMAND_PKT:
46162306a36Sopenharmony_ci		hdev->stat.cmd_tx++;
46262306a36Sopenharmony_ci		break;
46362306a36Sopenharmony_ci	case HCI_ACLDATA_PKT:
46462306a36Sopenharmony_ci		hdev->stat.acl_tx++;
46562306a36Sopenharmony_ci		break;
46662306a36Sopenharmony_ci	case HCI_SCODATA_PKT:
46762306a36Sopenharmony_ci		hdev->stat.sco_tx++;
46862306a36Sopenharmony_ci		break;
46962306a36Sopenharmony_ci	}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	/* Prepend skb with frame type */
47262306a36Sopenharmony_ci	memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1);
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	count = skb->len;
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	/* Max HCI frame size seems to be 1511 + 1 */
47762306a36Sopenharmony_ci	nskb = bt_skb_alloc(count + 32, GFP_KERNEL);
47862306a36Sopenharmony_ci	if (!nskb) {
47962306a36Sopenharmony_ci		bt_dev_err(hdev, "Can't allocate memory for new packet");
48062306a36Sopenharmony_ci		return -ENOMEM;
48162306a36Sopenharmony_ci	}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	nskb->dev = (void *) data;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	while (count) {
48662306a36Sopenharmony_ci		size = min_t(uint, count, BFUSB_MAX_BLOCK_SIZE);
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci		buf[0] = 0xc1 | ((sent == 0) ? 0x04 : 0) | ((count == size) ? 0x08 : 0);
48962306a36Sopenharmony_ci		buf[1] = 0x00;
49062306a36Sopenharmony_ci		buf[2] = (size == BFUSB_MAX_BLOCK_SIZE) ? 0 : size;
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci		skb_put_data(nskb, buf, 3);
49362306a36Sopenharmony_ci		skb_copy_from_linear_data_offset(skb, sent, skb_put(nskb, size), size);
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci		sent  += size;
49662306a36Sopenharmony_ci		count -= size;
49762306a36Sopenharmony_ci	}
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	/* Don't send frame with multiple size of bulk max packet */
50062306a36Sopenharmony_ci	if ((nskb->len % data->bulk_pkt_size) == 0) {
50162306a36Sopenharmony_ci		buf[0] = 0xdd;
50262306a36Sopenharmony_ci		buf[1] = 0x00;
50362306a36Sopenharmony_ci		skb_put_data(nskb, buf, 2);
50462306a36Sopenharmony_ci	}
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	read_lock(&data->lock);
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	skb_queue_tail(&data->transmit_q, nskb);
50962306a36Sopenharmony_ci	bfusb_tx_wakeup(data);
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	read_unlock(&data->lock);
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	kfree_skb(skb);
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	return 0;
51662306a36Sopenharmony_ci}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_cistatic int bfusb_load_firmware(struct bfusb_data *data,
51962306a36Sopenharmony_ci			       const unsigned char *firmware, int count)
52062306a36Sopenharmony_ci{
52162306a36Sopenharmony_ci	unsigned char *buf;
52262306a36Sopenharmony_ci	int err, pipe, len, size, sent = 0;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	BT_DBG("bfusb %p udev %p", data, data->udev);
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	BT_INFO("BlueFRITZ! USB loading firmware");
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	buf = kmalloc(BFUSB_MAX_BLOCK_SIZE + 3, GFP_KERNEL);
52962306a36Sopenharmony_ci	if (!buf) {
53062306a36Sopenharmony_ci		BT_ERR("Can't allocate memory chunk for firmware");
53162306a36Sopenharmony_ci		return -ENOMEM;
53262306a36Sopenharmony_ci	}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	pipe = usb_sndctrlpipe(data->udev, 0);
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	if (usb_control_msg(data->udev, pipe, USB_REQ_SET_CONFIGURATION,
53762306a36Sopenharmony_ci				0, 1, 0, NULL, 0, USB_CTRL_SET_TIMEOUT) < 0) {
53862306a36Sopenharmony_ci		BT_ERR("Can't change to loading configuration");
53962306a36Sopenharmony_ci		kfree(buf);
54062306a36Sopenharmony_ci		return -EBUSY;
54162306a36Sopenharmony_ci	}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	data->udev->toggle[0] = data->udev->toggle[1] = 0;
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	pipe = usb_sndbulkpipe(data->udev, data->bulk_out_ep);
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	while (count) {
54862306a36Sopenharmony_ci		size = min_t(uint, count, BFUSB_MAX_BLOCK_SIZE + 3);
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci		memcpy(buf, firmware + sent, size);
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci		err = usb_bulk_msg(data->udev, pipe, buf, size,
55362306a36Sopenharmony_ci					&len, BFUSB_BLOCK_TIMEOUT);
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci		if (err || (len != size)) {
55662306a36Sopenharmony_ci			BT_ERR("Error in firmware loading");
55762306a36Sopenharmony_ci			goto error;
55862306a36Sopenharmony_ci		}
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci		sent  += size;
56162306a36Sopenharmony_ci		count -= size;
56262306a36Sopenharmony_ci	}
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	err = usb_bulk_msg(data->udev, pipe, NULL, 0,
56562306a36Sopenharmony_ci					&len, BFUSB_BLOCK_TIMEOUT);
56662306a36Sopenharmony_ci	if (err < 0) {
56762306a36Sopenharmony_ci		BT_ERR("Error in null packet request");
56862306a36Sopenharmony_ci		goto error;
56962306a36Sopenharmony_ci	}
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	pipe = usb_sndctrlpipe(data->udev, 0);
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	err = usb_control_msg(data->udev, pipe, USB_REQ_SET_CONFIGURATION,
57462306a36Sopenharmony_ci				0, 2, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
57562306a36Sopenharmony_ci	if (err < 0) {
57662306a36Sopenharmony_ci		BT_ERR("Can't change to running configuration");
57762306a36Sopenharmony_ci		goto error;
57862306a36Sopenharmony_ci	}
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	data->udev->toggle[0] = data->udev->toggle[1] = 0;
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	BT_INFO("BlueFRITZ! USB device ready");
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	kfree(buf);
58562306a36Sopenharmony_ci	return 0;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_cierror:
58862306a36Sopenharmony_ci	kfree(buf);
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	pipe = usb_sndctrlpipe(data->udev, 0);
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	usb_control_msg(data->udev, pipe, USB_REQ_SET_CONFIGURATION,
59362306a36Sopenharmony_ci				0, 0, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	return err;
59662306a36Sopenharmony_ci}
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_cistatic int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *id)
59962306a36Sopenharmony_ci{
60062306a36Sopenharmony_ci	const struct firmware *firmware;
60162306a36Sopenharmony_ci	struct usb_device *udev = interface_to_usbdev(intf);
60262306a36Sopenharmony_ci	struct usb_host_endpoint *bulk_out_ep;
60362306a36Sopenharmony_ci	struct usb_host_endpoint *bulk_in_ep;
60462306a36Sopenharmony_ci	struct hci_dev *hdev;
60562306a36Sopenharmony_ci	struct bfusb_data *data;
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	BT_DBG("intf %p id %p", intf, id);
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	/* Check number of endpoints */
61062306a36Sopenharmony_ci	if (intf->cur_altsetting->desc.bNumEndpoints < 2)
61162306a36Sopenharmony_ci		return -EIO;
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	bulk_out_ep = &intf->cur_altsetting->endpoint[0];
61462306a36Sopenharmony_ci	bulk_in_ep  = &intf->cur_altsetting->endpoint[1];
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	if (!bulk_out_ep || !bulk_in_ep) {
61762306a36Sopenharmony_ci		BT_ERR("Bulk endpoints not found");
61862306a36Sopenharmony_ci		goto done;
61962306a36Sopenharmony_ci	}
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	/* Initialize control structure and load firmware */
62262306a36Sopenharmony_ci	data = devm_kzalloc(&intf->dev, sizeof(struct bfusb_data), GFP_KERNEL);
62362306a36Sopenharmony_ci	if (!data)
62462306a36Sopenharmony_ci		return -ENOMEM;
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	data->udev = udev;
62762306a36Sopenharmony_ci	data->bulk_in_ep    = bulk_in_ep->desc.bEndpointAddress;
62862306a36Sopenharmony_ci	data->bulk_out_ep   = bulk_out_ep->desc.bEndpointAddress;
62962306a36Sopenharmony_ci	data->bulk_pkt_size = le16_to_cpu(bulk_out_ep->desc.wMaxPacketSize);
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	if (!data->bulk_pkt_size)
63262306a36Sopenharmony_ci		goto done;
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	rwlock_init(&data->lock);
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	data->reassembly = NULL;
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	skb_queue_head_init(&data->transmit_q);
63962306a36Sopenharmony_ci	skb_queue_head_init(&data->pending_q);
64062306a36Sopenharmony_ci	skb_queue_head_init(&data->completed_q);
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	if (request_firmware(&firmware, "bfubase.frm", &udev->dev) < 0) {
64362306a36Sopenharmony_ci		BT_ERR("Firmware request failed");
64462306a36Sopenharmony_ci		goto done;
64562306a36Sopenharmony_ci	}
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	BT_DBG("firmware data %p size %zu", firmware->data, firmware->size);
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	if (bfusb_load_firmware(data, firmware->data, firmware->size) < 0) {
65062306a36Sopenharmony_ci		BT_ERR("Firmware loading failed");
65162306a36Sopenharmony_ci		goto release;
65262306a36Sopenharmony_ci	}
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	release_firmware(firmware);
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	/* Initialize and register HCI device */
65762306a36Sopenharmony_ci	hdev = hci_alloc_dev();
65862306a36Sopenharmony_ci	if (!hdev) {
65962306a36Sopenharmony_ci		BT_ERR("Can't allocate HCI device");
66062306a36Sopenharmony_ci		goto done;
66162306a36Sopenharmony_ci	}
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	data->hdev = hdev;
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	hdev->bus = HCI_USB;
66662306a36Sopenharmony_ci	hci_set_drvdata(hdev, data);
66762306a36Sopenharmony_ci	SET_HCIDEV_DEV(hdev, &intf->dev);
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	hdev->open  = bfusb_open;
67062306a36Sopenharmony_ci	hdev->close = bfusb_close;
67162306a36Sopenharmony_ci	hdev->flush = bfusb_flush;
67262306a36Sopenharmony_ci	hdev->send  = bfusb_send_frame;
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	set_bit(HCI_QUIRK_BROKEN_LOCAL_COMMANDS, &hdev->quirks);
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	if (hci_register_dev(hdev) < 0) {
67762306a36Sopenharmony_ci		BT_ERR("Can't register HCI device");
67862306a36Sopenharmony_ci		hci_free_dev(hdev);
67962306a36Sopenharmony_ci		goto done;
68062306a36Sopenharmony_ci	}
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	usb_set_intfdata(intf, data);
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	return 0;
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_cirelease:
68762306a36Sopenharmony_ci	release_firmware(firmware);
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_cidone:
69062306a36Sopenharmony_ci	return -EIO;
69162306a36Sopenharmony_ci}
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_cistatic void bfusb_disconnect(struct usb_interface *intf)
69462306a36Sopenharmony_ci{
69562306a36Sopenharmony_ci	struct bfusb_data *data = usb_get_intfdata(intf);
69662306a36Sopenharmony_ci	struct hci_dev *hdev = data->hdev;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	BT_DBG("intf %p", intf);
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	if (!hdev)
70162306a36Sopenharmony_ci		return;
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	usb_set_intfdata(intf, NULL);
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	bfusb_close(hdev);
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	hci_unregister_dev(hdev);
70862306a36Sopenharmony_ci	hci_free_dev(hdev);
70962306a36Sopenharmony_ci}
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_cistatic struct usb_driver bfusb_driver = {
71262306a36Sopenharmony_ci	.name		= "bfusb",
71362306a36Sopenharmony_ci	.probe		= bfusb_probe,
71462306a36Sopenharmony_ci	.disconnect	= bfusb_disconnect,
71562306a36Sopenharmony_ci	.id_table	= bfusb_table,
71662306a36Sopenharmony_ci	.disable_hub_initiated_lpm = 1,
71762306a36Sopenharmony_ci};
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_cimodule_usb_driver(bfusb_driver);
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ciMODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
72262306a36Sopenharmony_ciMODULE_DESCRIPTION("BlueFRITZ! USB driver ver " VERSION);
72362306a36Sopenharmony_ciMODULE_VERSION(VERSION);
72462306a36Sopenharmony_ciMODULE_LICENSE("GPL");
72562306a36Sopenharmony_ciMODULE_FIRMWARE("bfubase.frm");
726