aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/bluetooth/btusb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/bluetooth/btusb.c')
-rw-r--r--drivers/bluetooth/btusb.c525
1 files changed, 385 insertions, 140 deletions
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 292c38e8aa17..edfc17bfcd44 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -165,6 +165,7 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0930, 0x0227), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0x0036), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
@@ -267,20 +268,24 @@ struct btusb_data {
struct usb_interface *intf;
struct usb_interface *isoc;
- spinlock_t lock;
-
unsigned long flags;
struct work_struct work;
struct work_struct waker;
+ struct usb_anchor deferred;
struct usb_anchor tx_anchor;
+ int tx_in_flight;
+ spinlock_t txlock;
+
struct usb_anchor intr_anchor;
struct usb_anchor bulk_anchor;
struct usb_anchor isoc_anchor;
- struct usb_anchor deferred;
- int tx_in_flight;
- spinlock_t txlock;
+ spinlock_t rxlock;
+
+ struct sk_buff *evt_skb;
+ struct sk_buff *acl_skb;
+ struct sk_buff *sco_skb;
struct usb_endpoint_descriptor *intr_ep;
struct usb_endpoint_descriptor *bulk_tx_ep;
@@ -295,18 +300,189 @@ struct btusb_data {
int suspend_count;
};
-static int inc_tx(struct btusb_data *data)
+static inline void btusb_free_frags(struct btusb_data *data)
{
unsigned long flags;
- int rv;
- spin_lock_irqsave(&data->txlock, flags);
- rv = test_bit(BTUSB_SUSPENDING, &data->flags);
- if (!rv)
- data->tx_in_flight++;
- spin_unlock_irqrestore(&data->txlock, flags);
+ spin_lock_irqsave(&data->rxlock, flags);
+
+ kfree_skb(data->evt_skb);
+ data->evt_skb = NULL;
+
+ kfree_skb(data->acl_skb);
+ data->acl_skb = NULL;
+
+ kfree_skb(data->sco_skb);
+ data->sco_skb = NULL;
+
+ spin_unlock_irqrestore(&data->rxlock, flags);
+}
+
+static int btusb_recv_intr(struct btusb_data *data, void *buffer, int count)
+{
+ struct sk_buff *skb;
+ int err = 0;
+
+ spin_lock(&data->rxlock);
+ skb = data->evt_skb;
+
+ while (count) {
+ int len;
+
+ if (!skb) {
+ skb = bt_skb_alloc(HCI_MAX_EVENT_SIZE, GFP_ATOMIC);
+ if (!skb) {
+ err = -ENOMEM;
+ break;
+ }
+
+ bt_cb(skb)->pkt_type = HCI_EVENT_PKT;
+ bt_cb(skb)->expect = HCI_EVENT_HDR_SIZE;
+ }
+
+ len = min_t(uint, bt_cb(skb)->expect, count);
+ memcpy(skb_put(skb, len), buffer, len);
+
+ count -= len;
+ buffer += len;
+ bt_cb(skb)->expect -= len;
+
+ if (skb->len == HCI_EVENT_HDR_SIZE) {
+ /* Complete event header */
+ bt_cb(skb)->expect = hci_event_hdr(skb)->plen;
+
+ if (skb_tailroom(skb) < bt_cb(skb)->expect) {
+ kfree_skb(skb);
+ skb = NULL;
+
+ err = -EILSEQ;
+ break;
+ }
+ }
+
+ if (bt_cb(skb)->expect == 0) {
+ /* Complete frame */
+ hci_recv_frame(data->hdev, skb);
+ skb = NULL;
+ }
+ }
+
+ data->evt_skb = skb;
+ spin_unlock(&data->rxlock);
- return rv;
+ return err;
+}
+
+static int btusb_recv_bulk(struct btusb_data *data, void *buffer, int count)
+{
+ struct sk_buff *skb;
+ int err = 0;
+
+ spin_lock(&data->rxlock);
+ skb = data->acl_skb;
+
+ while (count) {
+ int len;
+
+ if (!skb) {
+ skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
+ if (!skb) {
+ err = -ENOMEM;
+ break;
+ }
+
+ bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
+ bt_cb(skb)->expect = HCI_ACL_HDR_SIZE;
+ }
+
+ len = min_t(uint, bt_cb(skb)->expect, count);
+ memcpy(skb_put(skb, len), buffer, len);
+
+ count -= len;
+ buffer += len;
+ bt_cb(skb)->expect -= len;
+
+ if (skb->len == HCI_ACL_HDR_SIZE) {
+ __le16 dlen = hci_acl_hdr(skb)->dlen;
+
+ /* Complete ACL header */
+ bt_cb(skb)->expect = __le16_to_cpu(dlen);
+
+ if (skb_tailroom(skb) < bt_cb(skb)->expect) {
+ kfree_skb(skb);
+ skb = NULL;
+
+ err = -EILSEQ;
+ break;
+ }
+ }
+
+ if (bt_cb(skb)->expect == 0) {
+ /* Complete frame */
+ hci_recv_frame(data->hdev, skb);
+ skb = NULL;
+ }
+ }
+
+ data->acl_skb = skb;
+ spin_unlock(&data->rxlock);
+
+ return err;
+}
+
+static int btusb_recv_isoc(struct btusb_data *data, void *buffer, int count)
+{
+ struct sk_buff *skb;
+ int err = 0;
+
+ spin_lock(&data->rxlock);
+ skb = data->sco_skb;
+
+ while (count) {
+ int len;
+
+ if (!skb) {
+ skb = bt_skb_alloc(HCI_MAX_SCO_SIZE, GFP_ATOMIC);
+ if (!skb) {
+ err = -ENOMEM;
+ break;
+ }
+
+ bt_cb(skb)->pkt_type = HCI_SCODATA_PKT;
+ bt_cb(skb)->expect = HCI_SCO_HDR_SIZE;
+ }
+
+ len = min_t(uint, bt_cb(skb)->expect, count);
+ memcpy(skb_put(skb, len), buffer, len);
+
+ count -= len;
+ buffer += len;
+ bt_cb(skb)->expect -= len;
+
+ if (skb->len == HCI_SCO_HDR_SIZE) {
+ /* Complete SCO header */
+ bt_cb(skb)->expect = hci_sco_hdr(skb)->dlen;
+
+ if (skb_tailroom(skb) < bt_cb(skb)->expect) {
+ kfree_skb(skb);
+ skb = NULL;
+
+ err = -EILSEQ;
+ break;
+ }
+ }
+
+ if (bt_cb(skb)->expect == 0) {
+ /* Complete frame */
+ hci_recv_frame(data->hdev, skb);
+ skb = NULL;
+ }
+ }
+
+ data->sco_skb = skb;
+ spin_unlock(&data->rxlock);
+
+ return err;
}
static void btusb_intr_complete(struct urb *urb)
@@ -315,8 +491,8 @@ static void btusb_intr_complete(struct urb *urb)
struct btusb_data *data = hci_get_drvdata(hdev);
int err;
- BT_DBG("%s urb %p status %d count %d", hdev->name,
- urb, urb->status, urb->actual_length);
+ BT_DBG("%s urb %p status %d count %d", hdev->name, urb, urb->status,
+ urb->actual_length);
if (!test_bit(HCI_RUNNING, &hdev->flags))
return;
@@ -324,12 +500,14 @@ static void btusb_intr_complete(struct urb *urb)
if (urb->status == 0) {
hdev->stat.byte_rx += urb->actual_length;
- if (hci_recv_fragment(hdev, HCI_EVENT_PKT,
- urb->transfer_buffer,
- urb->actual_length) < 0) {
+ if (btusb_recv_intr(data, urb->transfer_buffer,
+ urb->actual_length) < 0) {
BT_ERR("%s corrupted event packet", hdev->name);
hdev->stat.err_rx++;
}
+ } else if (urb->status == -ENOENT) {
+ /* Avoid suspend failed when usb_kill_urb */
+ return;
}
if (!test_bit(BTUSB_INTR_RUNNING, &data->flags))
@@ -344,7 +522,7 @@ static void btusb_intr_complete(struct urb *urb)
* -ENODEV: device got disconnected */
if (err != -EPERM && err != -ENODEV)
BT_ERR("%s urb %p failed to resubmit (%d)",
- hdev->name, urb, -err);
+ hdev->name, urb, -err);
usb_unanchor_urb(urb);
}
}
@@ -377,8 +555,7 @@ static int btusb_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags)
pipe = usb_rcvintpipe(data->udev, data->intr_ep->bEndpointAddress);
usb_fill_int_urb(urb, data->udev, pipe, buf, size,
- btusb_intr_complete, hdev,
- data->intr_ep->bInterval);
+ btusb_intr_complete, hdev, data->intr_ep->bInterval);
urb->transfer_flags |= URB_FREE_BUFFER;
@@ -388,7 +565,7 @@ static int btusb_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags)
if (err < 0) {
if (err != -EPERM && err != -ENODEV)
BT_ERR("%s urb %p submission failed (%d)",
- hdev->name, urb, -err);
+ hdev->name, urb, -err);
usb_unanchor_urb(urb);
}
@@ -403,8 +580,8 @@ static void btusb_bulk_complete(struct urb *urb)
struct btusb_data *data = hci_get_drvdata(hdev);
int err;
- BT_DBG("%s urb %p status %d count %d", hdev->name,
- urb, urb->status, urb->actual_length);
+ BT_DBG("%s urb %p status %d count %d", hdev->name, urb, urb->status,
+ urb->actual_length);
if (!test_bit(HCI_RUNNING, &hdev->flags))
return;
@@ -412,12 +589,14 @@ static void btusb_bulk_complete(struct urb *urb)
if (urb->status == 0) {
hdev->stat.byte_rx += urb->actual_length;
- if (hci_recv_fragment(hdev, HCI_ACLDATA_PKT,
- urb->transfer_buffer,
- urb->actual_length) < 0) {
+ if (btusb_recv_bulk(data, urb->transfer_buffer,
+ urb->actual_length) < 0) {
BT_ERR("%s corrupted ACL packet", hdev->name);
hdev->stat.err_rx++;
}
+ } else if (urb->status == -ENOENT) {
+ /* Avoid suspend failed when usb_kill_urb */
+ return;
}
if (!test_bit(BTUSB_BULK_RUNNING, &data->flags))
@@ -432,7 +611,7 @@ static void btusb_bulk_complete(struct urb *urb)
* -ENODEV: device got disconnected */
if (err != -EPERM && err != -ENODEV)
BT_ERR("%s urb %p failed to resubmit (%d)",
- hdev->name, urb, -err);
+ hdev->name, urb, -err);
usb_unanchor_urb(urb);
}
}
@@ -462,8 +641,8 @@ static int btusb_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags)
pipe = usb_rcvbulkpipe(data->udev, data->bulk_rx_ep->bEndpointAddress);
- usb_fill_bulk_urb(urb, data->udev, pipe,
- buf, size, btusb_bulk_complete, hdev);
+ usb_fill_bulk_urb(urb, data->udev, pipe, buf, size,
+ btusb_bulk_complete, hdev);
urb->transfer_flags |= URB_FREE_BUFFER;
@@ -474,7 +653,7 @@ static int btusb_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags)
if (err < 0) {
if (err != -EPERM && err != -ENODEV)
BT_ERR("%s urb %p submission failed (%d)",
- hdev->name, urb, -err);
+ hdev->name, urb, -err);
usb_unanchor_urb(urb);
}
@@ -489,8 +668,8 @@ static void btusb_isoc_complete(struct urb *urb)
struct btusb_data *data = hci_get_drvdata(hdev);
int i, err;
- BT_DBG("%s urb %p status %d count %d", hdev->name,
- urb, urb->status, urb->actual_length);
+ BT_DBG("%s urb %p status %d count %d", hdev->name, urb, urb->status,
+ urb->actual_length);
if (!test_bit(HCI_RUNNING, &hdev->flags))
return;
@@ -505,13 +684,15 @@ static void btusb_isoc_complete(struct urb *urb)
hdev->stat.byte_rx += length;
- if (hci_recv_fragment(hdev, HCI_SCODATA_PKT,
- urb->transfer_buffer + offset,
- length) < 0) {
+ if (btusb_recv_isoc(data, urb->transfer_buffer + offset,
+ length) < 0) {
BT_ERR("%s corrupted SCO packet", hdev->name);
hdev->stat.err_rx++;
}
}
+ } else if (urb->status == -ENOENT) {
+ /* Avoid suspend failed when usb_kill_urb */
+ return;
}
if (!test_bit(BTUSB_ISOC_RUNNING, &data->flags))
@@ -525,7 +706,7 @@ static void btusb_isoc_complete(struct urb *urb)
* -ENODEV: device got disconnected */
if (err != -EPERM && err != -ENODEV)
BT_ERR("%s urb %p failed to resubmit (%d)",
- hdev->name, urb, -err);
+ hdev->name, urb, -err);
usb_unanchor_urb(urb);
}
}
@@ -580,12 +761,12 @@ static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags)
pipe = usb_rcvisocpipe(data->udev, data->isoc_rx_ep->bEndpointAddress);
usb_fill_int_urb(urb, data->udev, pipe, buf, size, btusb_isoc_complete,
- hdev, data->isoc_rx_ep->bInterval);
+ hdev, data->isoc_rx_ep->bInterval);
- urb->transfer_flags = URB_FREE_BUFFER | URB_ISO_ASAP;
+ urb->transfer_flags = URB_FREE_BUFFER | URB_ISO_ASAP;
__fill_isoc_descriptor(urb, size,
- le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize));
+ le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize));
usb_anchor_urb(urb, &data->isoc_anchor);
@@ -593,7 +774,7 @@ static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags)
if (err < 0) {
if (err != -EPERM && err != -ENODEV)
BT_ERR("%s urb %p submission failed (%d)",
- hdev->name, urb, -err);
+ hdev->name, urb, -err);
usb_unanchor_urb(urb);
}
@@ -605,11 +786,11 @@ static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags)
static void btusb_tx_complete(struct urb *urb)
{
struct sk_buff *skb = urb->context;
- struct hci_dev *hdev = (struct hci_dev *) skb->dev;
+ struct hci_dev *hdev = (struct hci_dev *)skb->dev;
struct btusb_data *data = hci_get_drvdata(hdev);
- BT_DBG("%s urb %p status %d count %d", hdev->name,
- urb, urb->status, urb->actual_length);
+ BT_DBG("%s urb %p status %d count %d", hdev->name, urb, urb->status,
+ urb->actual_length);
if (!test_bit(HCI_RUNNING, &hdev->flags))
goto done;
@@ -632,10 +813,10 @@ done:
static void btusb_isoc_tx_complete(struct urb *urb)
{
struct sk_buff *skb = urb->context;
- struct hci_dev *hdev = (struct hci_dev *) skb->dev;
+ struct hci_dev *hdev = (struct hci_dev *)skb->dev;
- BT_DBG("%s urb %p status %d count %d", hdev->name,
- urb, urb->status, urb->actual_length);
+ BT_DBG("%s urb %p status %d count %d", hdev->name, urb, urb->status,
+ urb->actual_length);
if (!test_bit(HCI_RUNNING, &hdev->flags))
goto done;
@@ -719,6 +900,8 @@ static int btusb_close(struct hci_dev *hdev)
clear_bit(BTUSB_INTR_RUNNING, &data->flags);
btusb_stop_traffic(data);
+ btusb_free_frags(data);
+
err = usb_autopm_get_interface(data->intf);
if (err < 0)
goto failed;
@@ -738,122 +921,181 @@ static int btusb_flush(struct hci_dev *hdev)
BT_DBG("%s", hdev->name);
usb_kill_anchored_urbs(&data->tx_anchor);
+ btusb_free_frags(data);
return 0;
}
-static int btusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
+static struct urb *alloc_ctrl_urb(struct hci_dev *hdev, struct sk_buff *skb)
{
struct btusb_data *data = hci_get_drvdata(hdev);
struct usb_ctrlrequest *dr;
struct urb *urb;
unsigned int pipe;
- int err;
- BT_DBG("%s", hdev->name);
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb)
+ return ERR_PTR(-ENOMEM);
- if (!test_bit(HCI_RUNNING, &hdev->flags))
- return -EBUSY;
+ dr = kmalloc(sizeof(*dr), GFP_KERNEL);
+ if (!dr) {
+ usb_free_urb(urb);
+ return ERR_PTR(-ENOMEM);
+ }
- skb->dev = (void *) hdev;
+ dr->bRequestType = data->cmdreq_type;
+ dr->bRequest = 0;
+ dr->wIndex = 0;
+ dr->wValue = 0;
+ dr->wLength = __cpu_to_le16(skb->len);
- switch (bt_cb(skb)->pkt_type) {
- case HCI_COMMAND_PKT:
- urb = usb_alloc_urb(0, GFP_ATOMIC);
- if (!urb)
- return -ENOMEM;
-
- dr = kmalloc(sizeof(*dr), GFP_ATOMIC);
- if (!dr) {
- usb_free_urb(urb);
- return -ENOMEM;
- }
+ pipe = usb_sndctrlpipe(data->udev, 0x00);
- dr->bRequestType = data->cmdreq_type;
- dr->bRequest = 0;
- dr->wIndex = 0;
- dr->wValue = 0;
- dr->wLength = __cpu_to_le16(skb->len);
+ usb_fill_control_urb(urb, data->udev, pipe, (void *)dr,
+ skb->data, skb->len, btusb_tx_complete, skb);
- pipe = usb_sndctrlpipe(data->udev, 0x00);
+ skb->dev = (void *)hdev;
- usb_fill_control_urb(urb, data->udev, pipe, (void *) dr,
- skb->data, skb->len, btusb_tx_complete, skb);
+ return urb;
+}
- hdev->stat.cmd_tx++;
- break;
+static struct urb *alloc_bulk_urb(struct hci_dev *hdev, struct sk_buff *skb)
+{
+ struct btusb_data *data = hci_get_drvdata(hdev);
+ struct urb *urb;
+ unsigned int pipe;
- case HCI_ACLDATA_PKT:
- if (!data->bulk_tx_ep)
- return -ENODEV;
+ if (!data->bulk_tx_ep)
+ return ERR_PTR(-ENODEV);
+
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb)
+ return ERR_PTR(-ENOMEM);
- urb = usb_alloc_urb(0, GFP_ATOMIC);
- if (!urb)
- return -ENOMEM;
+ pipe = usb_sndbulkpipe(data->udev, data->bulk_tx_ep->bEndpointAddress);
- pipe = usb_sndbulkpipe(data->udev,
- data->bulk_tx_ep->bEndpointAddress);
+ usb_fill_bulk_urb(urb, data->udev, pipe,
+ skb->data, skb->len, btusb_tx_complete, skb);
- usb_fill_bulk_urb(urb, data->udev, pipe,
- skb->data, skb->len, btusb_tx_complete, skb);
+ skb->dev = (void *)hdev;
- hdev->stat.acl_tx++;
- break;
+ return urb;
+}
- case HCI_SCODATA_PKT:
- if (!data->isoc_tx_ep || hci_conn_num(hdev, SCO_LINK) < 1)
- return -ENODEV;
+static struct urb *alloc_isoc_urb(struct hci_dev *hdev, struct sk_buff *skb)
+{
+ struct btusb_data *data = hci_get_drvdata(hdev);
+ struct urb *urb;
+ unsigned int pipe;
- urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, GFP_ATOMIC);
- if (!urb)
- return -ENOMEM;
+ if (!data->isoc_tx_ep)
+ return ERR_PTR(-ENODEV);
- pipe = usb_sndisocpipe(data->udev,
- data->isoc_tx_ep->bEndpointAddress);
+ urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, GFP_KERNEL);
+ if (!urb)
+ return ERR_PTR(-ENOMEM);
- usb_fill_int_urb(urb, data->udev, pipe,
- skb->data, skb->len, btusb_isoc_tx_complete,
- skb, data->isoc_tx_ep->bInterval);
+ pipe = usb_sndisocpipe(data->udev, data->isoc_tx_ep->bEndpointAddress);
- urb->transfer_flags = URB_ISO_ASAP;
+ usb_fill_int_urb(urb, data->udev, pipe,
+ skb->data, skb->len, btusb_isoc_tx_complete,
+ skb, data->isoc_tx_ep->bInterval);
- __fill_isoc_descriptor(urb, skb->len,
- le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize));
+ urb->transfer_flags = URB_ISO_ASAP;
- hdev->stat.sco_tx++;
- goto skip_waking;
+ __fill_isoc_descriptor(urb, skb->len,
+ le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize));
- default:
- return -EILSEQ;
- }
+ skb->dev = (void *)hdev;
- err = inc_tx(data);
- if (err) {
- usb_anchor_urb(urb, &data->deferred);
- schedule_work(&data->waker);
- err = 0;
- goto done;
- }
+ return urb;
+}
+
+static int submit_tx_urb(struct hci_dev *hdev, struct urb *urb)
+{
+ struct btusb_data *data = hci_get_drvdata(hdev);
+ int err;
-skip_waking:
usb_anchor_urb(urb, &data->tx_anchor);
- err = usb_submit_urb(urb, GFP_ATOMIC);
+ err = usb_submit_urb(urb, GFP_KERNEL);
if (err < 0) {
if (err != -EPERM && err != -ENODEV)
BT_ERR("%s urb %p submission failed (%d)",
- hdev->name, urb, -err);
+ hdev->name, urb, -err);
kfree(urb->setup_packet);
usb_unanchor_urb(urb);
} else {
usb_mark_last_busy(data->udev);
}
-done:
usb_free_urb(urb);
return err;
}
+static int submit_or_queue_tx_urb(struct hci_dev *hdev, struct urb *urb)
+{
+ struct btusb_data *data = hci_get_drvdata(hdev);
+ unsigned long flags;
+ bool suspending;
+
+ spin_lock_irqsave(&data->txlock, flags);
+ suspending = test_bit(BTUSB_SUSPENDING, &data->flags);
+ if (!suspending)
+ data->tx_in_flight++;
+ spin_unlock_irqrestore(&data->txlock, flags);
+
+ if (!suspending)
+ return submit_tx_urb(hdev, urb);
+
+ usb_anchor_urb(urb, &data->deferred);
+ schedule_work(&data->waker);
+
+ usb_free_urb(urb);
+ return 0;
+}
+
+static int btusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
+{
+ struct urb *urb;
+
+ BT_DBG("%s", hdev->name);
+
+ if (!test_bit(HCI_RUNNING, &hdev->flags))
+ return -EBUSY;
+
+ switch (bt_cb(skb)->pkt_type) {
+ case HCI_COMMAND_PKT:
+ urb = alloc_ctrl_urb(hdev, skb);
+ if (IS_ERR(urb))
+ return PTR_ERR(urb);
+
+ hdev->stat.cmd_tx++;
+ return submit_or_queue_tx_urb(hdev, urb);
+
+ case HCI_ACLDATA_PKT:
+ urb = alloc_bulk_urb(hdev, skb);
+ if (IS_ERR(urb))
+ return PTR_ERR(urb);
+
+ hdev->stat.acl_tx++;
+ return submit_or_queue_tx_urb(hdev, urb);
+
+ case HCI_SCODATA_PKT:
+ if (hci_conn_num(hdev, SCO_LINK) < 1)
+ return -ENODEV;
+
+ urb = alloc_isoc_urb(hdev, skb);
+ if (IS_ERR(urb))
+ return PTR_ERR(urb);
+
+ hdev->stat.sco_tx++;
+ return submit_tx_urb(hdev, urb);
+ }
+
+ return -EILSEQ;
+}
+
static void btusb_notify(struct hci_dev *hdev, unsigned int evt)
{
struct btusb_data *data = hci_get_drvdata(hdev);
@@ -930,6 +1172,7 @@ static void btusb_work(struct work_struct *work)
if (hdev->voice_setting & 0x0020) {
static const int alts[3] = { 2, 4, 5 };
+
new_alts = alts[data->sco_num - 1];
} else {
new_alts = data->sco_num;
@@ -1002,7 +1245,7 @@ static int btusb_setup_csr(struct hci_dev *hdev)
return -PTR_ERR(skb);
}
- rp = (struct hci_rp_read_local_version *) skb->data;
+ rp = (struct hci_rp_read_local_version *)skb->data;
if (!rp->status) {
if (le16_to_cpu(rp->manufacturer) != 10) {
@@ -1040,7 +1283,7 @@ struct intel_version {
} __packed;
static const struct firmware *btusb_setup_intel_get_fw(struct hci_dev *hdev,
- struct intel_version *ver)
+ struct intel_version *ver)
{
const struct firmware *fw;
char fwname[64];
@@ -1216,7 +1459,7 @@ static int btusb_check_bdaddr_intel(struct hci_dev *hdev)
return -EIO;
}
- rp = (struct hci_rp_read_bd_addr *) skb->data;
+ rp = (struct hci_rp_read_bd_addr *)skb->data;
if (rp->status) {
BT_ERR("%s Intel device address result failed (%02x)",
hdev->name, rp->status);
@@ -1346,6 +1589,7 @@ static int btusb_setup_intel(struct hci_dev *hdev)
if (skb->data[0]) {
u8 evt_status = skb->data[0];
+
BT_ERR("%s enable Intel manufacturer mode event failed (%02x)",
hdev->name, evt_status);
kfree_skb(skb);
@@ -1455,7 +1699,7 @@ static int btusb_set_bdaddr_intel(struct hci_dev *hdev, const bdaddr_t *bdaddr)
if (IS_ERR(skb)) {
ret = PTR_ERR(skb);
BT_ERR("%s: changing Intel device address failed (%ld)",
- hdev->name, ret);
+ hdev->name, ret);
return ret;
}
kfree_skb(skb);
@@ -1530,19 +1774,19 @@ static int btusb_setup_bcm_patchram(struct hci_dev *hdev)
if (IS_ERR(skb)) {
ret = PTR_ERR(skb);
BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION failed (%ld)",
- hdev->name, ret);
+ hdev->name, ret);
goto done;
}
if (skb->len != sizeof(*ver)) {
BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION event length mismatch",
- hdev->name);
+ hdev->name);
kfree_skb(skb);
ret = -EIO;
goto done;
}
- ver = (struct hci_rp_read_local_version *) skb->data;
+ ver = (struct hci_rp_read_local_version *)skb->data;
BT_INFO("%s: BCM: patching hci_ver=%02x hci_rev=%04x lmp_ver=%02x "
"lmp_subver=%04x", hdev->name, ver->hci_ver, ver->hci_rev,
ver->lmp_ver, ver->lmp_subver);
@@ -1553,7 +1797,7 @@ static int btusb_setup_bcm_patchram(struct hci_dev *hdev)
if (IS_ERR(skb)) {
ret = PTR_ERR(skb);
BT_ERR("%s: BCM: Download Minidrv command failed (%ld)",
- hdev->name, ret);
+ hdev->name, ret);
goto reset_fw;
}
kfree_skb(skb);
@@ -1565,13 +1809,13 @@ static int btusb_setup_bcm_patchram(struct hci_dev *hdev)
fw_size = fw->size;
while (fw_size >= sizeof(*cmd)) {
- cmd = (struct hci_command_hdr *) fw_ptr;
+ cmd = (struct hci_command_hdr *)fw_ptr;
fw_ptr += sizeof(*cmd);
fw_size -= sizeof(*cmd);
if (fw_size < cmd->plen) {
BT_ERR("%s: BCM: patch %s is corrupted",
- hdev->name, fw_name);
+ hdev->name, fw_name);
ret = -EINVAL;
goto reset_fw;
}
@@ -1587,7 +1831,7 @@ static int btusb_setup_bcm_patchram(struct hci_dev *hdev)
if (IS_ERR(skb)) {
ret = PTR_ERR(skb);
BT_ERR("%s: BCM: patch command %04x failed (%ld)",
- hdev->name, opcode, ret);
+ hdev->name, opcode, ret);
goto reset_fw;
}
kfree_skb(skb);
@@ -1612,19 +1856,19 @@ reset_fw:
if (IS_ERR(skb)) {
ret = PTR_ERR(skb);
BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION failed (%ld)",
- hdev->name, ret);
+ hdev->name, ret);
goto done;
}
if (skb->len != sizeof(*ver)) {
BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION event length mismatch",
- hdev->name);
+ hdev->name);
kfree_skb(skb);
ret = -EIO;
goto done;
}
- ver = (struct hci_rp_read_local_version *) skb->data;
+ ver = (struct hci_rp_read_local_version *)skb->data;
BT_INFO("%s: BCM: firmware hci_ver=%02x hci_rev=%04x lmp_ver=%02x "
"lmp_subver=%04x", hdev->name, ver->hci_ver, ver->hci_rev,
ver->lmp_ver, ver->lmp_subver);
@@ -1636,19 +1880,19 @@ reset_fw:
if (IS_ERR(skb)) {
ret = PTR_ERR(skb);
BT_ERR("%s: HCI_OP_READ_BD_ADDR failed (%ld)",
- hdev->name, ret);
+ hdev->name, ret);
goto done;
}
if (skb->len != sizeof(*bda)) {
BT_ERR("%s: HCI_OP_READ_BD_ADDR event length mismatch",
- hdev->name);
+ hdev->name);
kfree_skb(skb);
ret = -EIO;
goto done;
}
- bda = (struct hci_rp_read_bd_addr *) skb->data;
+ bda = (struct hci_rp_read_bd_addr *)skb->data;
if (bda->status) {
BT_ERR("%s: HCI_OP_READ_BD_ADDR error status (%02x)",
hdev->name, bda->status);
@@ -1683,7 +1927,7 @@ static int btusb_set_bdaddr_bcm(struct hci_dev *hdev, const bdaddr_t *bdaddr)
if (IS_ERR(skb)) {
ret = PTR_ERR(skb);
BT_ERR("%s: BCM: Change address command failed (%ld)",
- hdev->name, ret);
+ hdev->name, ret);
return ret;
}
kfree_skb(skb);
@@ -1692,7 +1936,7 @@ static int btusb_set_bdaddr_bcm(struct hci_dev *hdev, const bdaddr_t *bdaddr)
}
static int btusb_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
+ const struct usb_device_id *id)
{
struct usb_endpoint_descriptor *ep_desc;
struct btusb_data *data;
@@ -1707,6 +1951,7 @@ static int btusb_probe(struct usb_interface *intf,
if (!id->driver_info) {
const struct usb_device_id *match;
+
match = usb_match_id(intf, blacklist_table);
if (match)
id = match;
@@ -1755,17 +2000,16 @@ static int btusb_probe(struct usb_interface *intf,
data->udev = interface_to_usbdev(intf);
data->intf = intf;
- spin_lock_init(&data->lock);
-
INIT_WORK(&data->work, btusb_work);
INIT_WORK(&data->waker, btusb_waker);
+ init_usb_anchor(&data->deferred);
+ init_usb_anchor(&data->tx_anchor);
spin_lock_init(&data->txlock);
- init_usb_anchor(&data->tx_anchor);
init_usb_anchor(&data->intr_anchor);
init_usb_anchor(&data->bulk_anchor);
init_usb_anchor(&data->isoc_anchor);
- init_usb_anchor(&data->deferred);
+ spin_lock_init(&data->rxlock);
hdev = hci_alloc_dev();
if (!hdev)
@@ -1857,7 +2101,7 @@ static int btusb_probe(struct usb_interface *intf,
if (data->isoc) {
err = usb_driver_claim_interface(&btusb_driver,
- data->isoc, data);
+ data->isoc, data);
if (err < 0) {
hci_free_dev(hdev);
return err;
@@ -1898,6 +2142,7 @@ static void btusb_disconnect(struct usb_interface *intf)
else if (data->isoc)
usb_driver_release_interface(&btusb_driver, data->isoc);
+ btusb_free_frags(data);
hci_free_dev(hdev);
}