@@ -41,6 +41,13 @@ config BT_HCIBTUSB_AUTOSUSPEND
This can be overridden by passing btusb.enable_autosuspend=[y|n]
on the kernel commandline.
+config BT_HCIBTUSB_INTERVAL
+ bool "Enable notification of USB polling interval"
+ depends on BT_HCIBTUSB
+ help
+ Say Y here to enable notification of USB polling interval for
+ Bluetooth USB devices by default.
+
config BT_HCIBTUSB_BCM
bool "Broadcom protocol support"
depends on BT_HCIBTUSB
@@ -30,7 +30,7 @@
static bool disable_scofix;
static bool force_scofix;
static bool enable_autosuspend = IS_ENABLED(CONFIG_BT_HCIBTUSB_AUTOSUSPEND);
-
+static bool enable_interval = IS_ENABLED(CONFIG_BT_HCIBTUSB_INTERVAL);
static bool reset = true;
static struct usb_driver btusb_driver;
@@ -519,8 +519,13 @@ struct btusb_data {
unsigned long flags;
- struct work_struct work;
- struct work_struct waker;
+ int intr_interval;
+ struct work_struct work;
+ struct work_struct waker;
+ struct delayed_work rx_work;
+
+ struct sk_buff_head acl_q;
+ struct sk_buff_head evt_q;
struct usb_anchor deferred;
struct usb_anchor tx_anchor;
@@ -557,7 +562,7 @@ struct btusb_data {
int isoc_altsetting;
int suspend_count;
- int (*recv_event)(struct hci_dev *hdev, struct sk_buff *skb);
+ int (*recv_event)(struct btusb_data *data, struct sk_buff *skb);
int (*recv_bulk)(struct btusb_data *data, void *buffer, int count);
int (*setup_on_usb)(struct hci_dev *hdev);
@@ -707,7 +712,7 @@ static int btusb_recv_intr(struct btusb_data *data, void *buffer, int count)
if (!hci_skb_expect(skb)) {
/* Complete frame */
- data->recv_event(data->hdev, skb);
+ data->recv_event(data, skb);
skb = NULL;
}
}
@@ -718,6 +723,25 @@ static int btusb_recv_intr(struct btusb_data *data, void *buffer, int count)
return err;
}
+static int btusb_rx_queue(struct btusb_data *data, struct sk_buff *skb,
+ struct sk_buff_head *queue, unsigned int interval)
+{
+ skb_queue_tail(queue, skb);
+
+ schedule_delayed_work(&data->rx_work, interval);
+
+ return 0;
+}
+
+static int btusb_recv_acl(struct btusb_data *data, struct sk_buff *skb)
+{
+ if (!enable_interval)
+ return hci_recv_frame(data->hdev, skb);
+
+ return btusb_rx_queue(data, skb, &data->acl_q,
+ usecs_to_jiffies(data->intr_interval));
+}
+
static int btusb_recv_bulk(struct btusb_data *data, void *buffer, int count)
{
struct sk_buff *skb;
@@ -765,7 +789,7 @@ static int btusb_recv_bulk(struct btusb_data *data, void *buffer, int count)
if (!hci_skb_expect(skb)) {
/* Complete frame */
- hci_recv_frame(data->hdev, skb);
+ btusb_recv_acl(data, skb);
skb = NULL;
}
}
@@ -917,6 +941,19 @@ static int btusb_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags)
usb_unanchor_urb(urb);
}
+ /* The units are frames (milliseconds) for full and low speed devices,
+ * and microframes (1/8 millisecond) for highspeed and SuperSpeed
+ * devices.
+ */
+ switch (urb->dev->speed) {
+ case USB_SPEED_SUPER_PLUS:
+ case USB_SPEED_SUPER: /* units are 125us */
+ data->intr_interval = urb->interval * 125;
+ break;
+ default:
+ data->intr_interval = urb->interval * 1000;
+ }
+
usb_free_urb(urb);
return err;
@@ -1383,9 +1420,13 @@ static int btusb_close(struct hci_dev *hdev)
BT_DBG("%s", hdev->name);
+ cancel_delayed_work(&data->rx_work);
cancel_work_sync(&data->work);
cancel_work_sync(&data->waker);
+ skb_queue_purge(&data->acl_q);
+ skb_queue_purge(&data->evt_q);
+
clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
clear_bit(BTUSB_BULK_RUNNING, &data->flags);
clear_bit(BTUSB_INTR_RUNNING, &data->flags);
@@ -1417,6 +1458,11 @@ static int btusb_flush(struct hci_dev *hdev)
BT_DBG("%s", hdev->name);
+ cancel_delayed_work(&data->rx_work);
+
+ skb_queue_purge(&data->acl_q);
+ skb_queue_purge(&data->evt_q);
+
usb_kill_anchored_urbs(&data->tx_anchor);
btusb_free_frags(data);
@@ -1769,6 +1815,25 @@ static void btusb_waker(struct work_struct *work)
usb_autopm_put_interface(data->intf);
}
+static void btusb_rx_dequeue(struct btusb_data *data,
+ struct sk_buff_head *queue)
+{
+ struct sk_buff *skb;
+
+ while ((skb = skb_dequeue(queue)))
+ hci_recv_frame(data->hdev, skb);
+}
+
+static void btusb_rx_work(struct work_struct *work)
+{
+ struct btusb_data *data = container_of(work, struct btusb_data,
+ rx_work.work);
+
+ /* Process HCI event packets so states changes are synchronized first */
+ btusb_rx_dequeue(data, &data->evt_q);
+ btusb_rx_dequeue(data, &data->acl_q);
+}
+
static int btusb_setup_bcm92035(struct hci_dev *hdev)
{
struct sk_buff *skb;
@@ -2304,10 +2369,8 @@ static void btusb_intel_secure_send_result(struct btusb_data *data,
wake_up_bit(&data->flags, BTUSB_DOWNLOADING);
}
-static int btusb_recv_event_intel(struct hci_dev *hdev, struct sk_buff *skb)
+static int btusb_recv_event_intel(struct btusb_data *data, struct sk_buff *skb)
{
- struct btusb_data *data = hci_get_drvdata(hdev);
-
if (test_bit(BTUSB_BOOTLOADER, &data->flags)) {
struct hci_event_hdr *hdr = (void *)skb->data;
@@ -2336,7 +2399,7 @@ static int btusb_recv_event_intel(struct hci_dev *hdev, struct sk_buff *skb)
}
}
- return hci_recv_frame(hdev, skb);
+ return hci_recv_frame(data->hdev, skb);
}
static int btusb_send_frame_intel(struct hci_dev *hdev, struct sk_buff *skb)
@@ -4279,6 +4342,15 @@ static int btusb_shutdown_qca(struct hci_dev *hdev)
return 0;
}
+static int btusb_recv_evt(struct btusb_data *data, struct sk_buff *skb)
+{
+ if (!enable_interval)
+ return hci_recv_frame(data->hdev, skb);
+
+ /* Don't delay event processing */
+ return btusb_rx_queue(data, skb, &data->evt_q, 0);
+}
+
static int btusb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
@@ -4362,6 +4434,11 @@ static int btusb_probe(struct usb_interface *intf,
INIT_WORK(&data->work, btusb_work);
INIT_WORK(&data->waker, btusb_waker);
+ INIT_DELAYED_WORK(&data->rx_work, btusb_rx_work);
+
+ skb_queue_head_init(&data->acl_q);
+ skb_queue_head_init(&data->evt_q);
+
init_usb_anchor(&data->deferred);
init_usb_anchor(&data->tx_anchor);
spin_lock_init(&data->txlock);
@@ -4378,7 +4455,7 @@ static int btusb_probe(struct usb_interface *intf,
data->recv_bulk = btusb_recv_bulk_intel;
set_bit(BTUSB_BOOTLOADER, &data->flags);
} else {
- data->recv_event = hci_recv_frame;
+ data->recv_event = btusb_recv_evt;
data->recv_bulk = btusb_recv_bulk;
}
@@ -4867,6 +4944,9 @@ MODULE_PARM_DESC(force_scofix, "Force fixup of wrong SCO buffers size");
module_param(enable_autosuspend, bool, 0644);
MODULE_PARM_DESC(enable_autosuspend, "Enable USB autosuspend by default");
+module_param(enable_interval, bool, 0644);
+MODULE_PARM_DESC(enable_interval, "Enable USB polling interval by default");
+
module_param(reset, bool, 0644);
MODULE_PARM_DESC(reset, "Send HCI reset command on initialization");