Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dcdcf63e authored by Marcel Holtmann's avatar Marcel Holtmann Committed by David S. Miller
Browse files

[Bluetooth] Add suspend/resume support to the HCI USB driver



This patch implements the suspend/resume methods for the HCI USB
driver by killing all outstanding URBs on suspend, and re-issuing
them on resume.

Signed-off-by: default avatarJohannes Berg <johannes@sipsolutions.net>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent 2b86ad21
Loading
Loading
Loading
Loading
+71 −0
Original line number Diff line number Diff line
@@ -1045,10 +1045,81 @@ static void hci_usb_disconnect(struct usb_interface *intf)
	hci_free_dev(hdev);
}

static int hci_usb_suspend(struct usb_interface *intf, pm_message_t message)
{
	struct hci_usb *husb = usb_get_intfdata(intf);
	struct list_head killed;
	unsigned long flags;
	int i;

	if (!husb || intf == husb->isoc_iface)
		return 0;

	hci_suspend_dev(husb->hdev);

	INIT_LIST_HEAD(&killed);

	for (i = 0; i < 4; i++) {
		struct _urb_queue *q = &husb->pending_q[i];
		struct _urb *_urb, *_tmp;

		while ((_urb = _urb_dequeue(q))) {
			/* reset queue since _urb_dequeue sets it to NULL */
			_urb->queue = q;
			usb_kill_urb(&_urb->urb);
			list_add(&_urb->list, &killed);
		}

		spin_lock_irqsave(&q->lock, flags);

		list_for_each_entry_safe(_urb, _tmp, &killed, list) {
			list_move_tail(&_urb->list, &q->head);
		}

		spin_unlock_irqrestore(&q->lock, flags);
	}

	return 0;
}

static int hci_usb_resume(struct usb_interface *intf)
{
	struct hci_usb *husb = usb_get_intfdata(intf);
	unsigned long flags;
	int i, err = 0;

	if (!husb || intf == husb->isoc_iface)
		return 0;
	
	for (i = 0; i < 4; i++) {
		struct _urb_queue *q = &husb->pending_q[i];
		struct _urb *_urb;

		spin_lock_irqsave(&q->lock, flags);

		list_for_each_entry(_urb, &q->head, list) {
			err = usb_submit_urb(&_urb->urb, GFP_ATOMIC);
			if (err)
				break;
		}

		spin_unlock_irqrestore(&q->lock, flags);

		if (err)
			return -EIO;
	}

	hci_resume_dev(husb->hdev);

	return 0;
}

static struct usb_driver hci_usb_driver = {
	.name		= "hci_usb",
	.probe		= hci_usb_probe,
	.disconnect	= hci_usb_disconnect,
	.suspend	= hci_usb_suspend,
	.resume		= hci_usb_resume,
	.id_table	= bluetooth_ids,
};