diff options
author | David S. Miller <davem@davemloft.net> | 2014-10-05 21:34:39 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-10-05 21:34:39 -0400 |
commit | a4b4a2b7f98a45c71a906b1126cabea6446a9905 (patch) | |
tree | 0d501e78aeb9df90172a9435d673f31bf89290eb /drivers/bluetooth | |
parent | 61b37d2f54961b336a47a501e797a05df20c3b30 (diff) | |
parent | 3f08e47291879fb047d7d4464d2beaedfea4eb63 (diff) |
Merge tag 'master-2014-10-02' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next
John W. Linville says:
====================
pull request: wireless-next 2014-10-03
Please pull tihs batch of updates intended for the 3.18 stream!
For the iwlwifi bits, Emmanuel says:
"I have here a few things that depend on the latest mac80211's changes:
RRM, TPC, Quiet Period etc... Eyal keeps improving our rate control
and we have a new device ID. This last patch should probably have
gone to wireless.git, but at that stage, I preferred to send it to
-next and CC stable."
For (most of) the Atheros bits, Kalle says:
"The only new feature is testmode support from me. Ben added a new method
to crash the firmware with an assert for debug purposes. As usual, we
have lots of smaller fixes from Michal. Matteo fixed a Kconfig
dependency with debugfs. I fixed some warnings recently added to
checkpatch."
For the NFC bits, Samuel says:
"We've had major updates for TI and ST Microelectronics drivers, and a
few NCI related changes.
For TI's trf7970a driver:
- Target mode support for trf7970a
- Suspend/resume support for trf7970a
- DT properties additions to handle different quirks
- A bunch of fixes for smartphone IOP related issues
For ST Microelectronics' ST21NFCA and ST21NFCB drivers:
- ISO15693 support for st21nfcb
- checkpatch and sparse related warning fixes
- Code cleanups and a few minor fixes
Finally, Marvell added ISO15693 support to the NCI stack, together with a
couple of NCI fixes."
For the Bluetooth bits, Johan says:
"This 3.18 pull request replaces the one I did on Monday ("bluetooth-next
2014-09-22", which hasn't been pulled yet). The additions since the last
request are:
- SCO connection fix for devices not supporting eSCO
- Cleanups regarding the SCO establishment logic
- Remove unnecessary return value from logging functions
- Header compression fix for 6lowpan
- Cleanups to the ieee802154/mrf24j40 driver
Here's a copy from previous request that this one replaces:
'
Here are some more patches for 3.18. They include various fixes to the
btusb HCI driver, a fix for LE SMP, as well as adding Jukka to the
MAINTAINERS file for generic 6LoWPAN (as requested by Alexander Aring).
I've held on to this pull request a bit since we were waiting for a SCO
related fix to get sorted out first. However, since the merge window is
getting closer I decided not to wait for it. If we do get the fix sorted
out there'll probably be a second small pull request later this week.
'"
And,
"Unless 3.17 gets delayed this will probably be our last -next pull request for
3.18. We've got:
- New Marvell hardware supportr
- Multicast support for 6lowpan
- Several of 6lowpan fixes & cleanups
- Fix for a (false-positive) lockdep warning in L2CAP
- Minor btusb cleanup"
On top of all that comes the usual sort of updates to ath5k, ath9k,
ath10k, brcmfmac, mwifiex, and wil6210. This time around there are
also a number of rtlwifi updates to enable some new hardware and
to reconcile the in-kernel drivers with some newer releases of the
Realtek vendor drivers. Also of note is some device tree work for
the bcma bus.
Please let me know if there are problems!
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/bluetooth')
-rw-r--r-- | drivers/bluetooth/Kconfig | 4 | ||||
-rw-r--r-- | drivers/bluetooth/btmrvl_sdio.c | 36 | ||||
-rw-r--r-- | drivers/bluetooth/btusb.c | 515 |
3 files changed, 411 insertions, 144 deletions
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index fa7fd62ddffa..4547dc238fc7 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -201,7 +201,7 @@ config BT_MRVL The core driver to support Marvell Bluetooth devices. This driver is required if you want to support - Marvell Bluetooth devices, such as 8688/8787/8797/8897. + Marvell Bluetooth devices, such as 8688/8787/8797/8887/8897. Say Y here to compile Marvell Bluetooth driver into the kernel or say M to compile it as module. @@ -214,7 +214,7 @@ config BT_MRVL_SDIO The driver for Marvell Bluetooth chipsets with SDIO interface. This driver is required if you want to use Marvell Bluetooth - devices with SDIO interface. Currently SD8688/SD8787/SD8797/SD8897 + devices with SDIO interface. Currently SD8688/SD8787/SD8797/SD8887/SD8897 chipsets are supported. Say Y here to compile support for Marvell BT-over-SDIO driver diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index 3e683b153259..550bce089fa6 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -84,7 +84,27 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_87xx = { .int_read_to_clear = false, }; -static const struct btmrvl_sdio_card_reg btmrvl_reg_88xx = { +static const struct btmrvl_sdio_card_reg btmrvl_reg_8887 = { + .cfg = 0x00, + .host_int_mask = 0x08, + .host_intstatus = 0x0C, + .card_status = 0x5C, + .sq_read_base_addr_a0 = 0x6C, + .sq_read_base_addr_a1 = 0x6D, + .card_revision = 0xC8, + .card_fw_status0 = 0x88, + .card_fw_status1 = 0x89, + .card_rx_len = 0x8A, + .card_rx_unit = 0x8B, + .io_port_0 = 0xE4, + .io_port_1 = 0xE5, + .io_port_2 = 0xE6, + .int_read_to_clear = true, + .host_int_rsr = 0x04, + .card_misc_cfg = 0xD8, +}; + +static const struct btmrvl_sdio_card_reg btmrvl_reg_8897 = { .cfg = 0x00, .host_int_mask = 0x02, .host_intstatus = 0x03, @@ -128,10 +148,18 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8797 = { .sd_blksz_fw_dl = 256, }; +static const struct btmrvl_sdio_device btmrvl_sdio_sd8887 = { + .helper = NULL, + .firmware = "mrvl/sd8887_uapsta.bin", + .reg = &btmrvl_reg_8887, + .support_pscan_win_report = true, + .sd_blksz_fw_dl = 256, +}; + static const struct btmrvl_sdio_device btmrvl_sdio_sd8897 = { .helper = NULL, .firmware = "mrvl/sd8897_uapsta.bin", - .reg = &btmrvl_reg_88xx, + .reg = &btmrvl_reg_8897, .support_pscan_win_report = true, .sd_blksz_fw_dl = 256, }; @@ -149,6 +177,9 @@ static const struct sdio_device_id btmrvl_sdio_ids[] = { /* Marvell SD8797 Bluetooth device */ { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912A), .driver_data = (unsigned long) &btmrvl_sdio_sd8797 }, + /* Marvell SD8887 Bluetooth device */ + { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9136), + .driver_data = (unsigned long)&btmrvl_sdio_sd8887 }, /* Marvell SD8897 Bluetooth device */ { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912E), .driver_data = (unsigned long) &btmrvl_sdio_sd8897 }, @@ -1280,4 +1311,5 @@ MODULE_FIRMWARE("mrvl/sd8688_helper.bin"); MODULE_FIRMWARE("mrvl/sd8688.bin"); MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin"); MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin"); +MODULE_FIRMWARE("mrvl/sd8887_uapsta.bin"); MODULE_FIRMWARE("mrvl/sd8897_uapsta.bin"); diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index a79d657c0845..edfc17bfcd44 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -268,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; @@ -296,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 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; - return rv; + 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) @@ -316,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; @@ -325,9 +500,8 @@ 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++; } @@ -348,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); } } @@ -381,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; @@ -392,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); } @@ -407,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; @@ -416,9 +589,8 @@ 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++; } @@ -439,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); } } @@ -469,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; @@ -481,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); } @@ -496,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; @@ -512,9 +684,8 @@ 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++; } @@ -535,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); } } @@ -590,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); @@ -603,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); } @@ -615,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; @@ -642,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; @@ -729,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; @@ -748,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_ATOMIC); - if (!urb) - return -ENOMEM; + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) + return ERR_PTR(-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); - hdev->stat.acl_tx++; - break; + skb->dev = (void *)hdev; - case HCI_SCODATA_PKT: - if (!data->isoc_tx_ep || hci_conn_num(hdev, SCO_LINK) < 1) - return -ENODEV; + return urb; +} - urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, GFP_ATOMIC); - if (!urb) - return -ENOMEM; +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; - pipe = usb_sndisocpipe(data->udev, - data->isoc_tx_ep->bEndpointAddress); + if (!data->isoc_tx_ep) + return ERR_PTR(-ENODEV); - usb_fill_int_urb(urb, data->udev, pipe, - skb->data, skb->len, btusb_isoc_tx_complete, - skb, data->isoc_tx_ep->bInterval); + urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, GFP_KERNEL); + if (!urb) + return ERR_PTR(-ENOMEM); - urb->transfer_flags = URB_ISO_ASAP; + pipe = usb_sndisocpipe(data->udev, data->isoc_tx_ep->bEndpointAddress); - __fill_isoc_descriptor(urb, skb->len, - le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize)); + usb_fill_int_urb(urb, data->udev, pipe, + skb->data, skb->len, btusb_isoc_tx_complete, + skb, data->isoc_tx_ep->bInterval); - hdev->stat.sco_tx++; - goto skip_waking; + urb->transfer_flags = URB_ISO_ASAP; - default: - return -EILSEQ; - } + __fill_isoc_descriptor(urb, skb->len, + le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize)); - err = inc_tx(data); - if (err) { - usb_anchor_urb(urb, &data->deferred); - schedule_work(&data->waker); - err = 0; - goto done; - } + skb->dev = (void *)hdev; + + 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); @@ -940,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; @@ -1012,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) { @@ -1050,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]; @@ -1226,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); @@ -1356,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); @@ -1465,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); @@ -1540,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); @@ -1563,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); @@ -1575,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; } @@ -1597,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); @@ -1622,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); @@ -1646,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); @@ -1693,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); @@ -1702,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; @@ -1717,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; @@ -1765,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) @@ -1867,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; @@ -1908,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); } |