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