diff options
author | Marcel Holtmann <marcel@holtmann.org> | 2014-09-14 03:11:06 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2014-09-14 12:35:28 -0400 |
commit | 047b2ec8d3778a046d6985d4ad410c85211a86a4 (patch) | |
tree | 436d743621b934984bd60ddac6a3adc5bf602f08 /drivers/bluetooth/btusb.c | |
parent | e9753eff1b875d579dc04d675e72d6e31e866927 (diff) |
Bluetooth: btusb: Separate TX URB allocation and submission
The complete TX URB handling is done via a switch statement in the
btusb_send_frame function. To allow for more clear separation between
control, bulk and isoc URBs, split them into allocation and submission.
Previously the inc_tx function has been used for tracking in-flight
URB for HCI commands and ACL data packets. Convert that into a common
function that either submits the URB or queues it when needed.
This provides the flexibility to allow vendor specific hdev->send_frame
callbacks without having to duplicate the whole URB handling logic.
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Diffstat (limited to 'drivers/bluetooth/btusb.c')
-rw-r--r-- | drivers/bluetooth/btusb.c | 206 |
1 files changed, 125 insertions, 81 deletions
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index d696e68f326a..c89b330cfa9e 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c | |||
@@ -296,20 +296,6 @@ struct btusb_data { | |||
296 | int suspend_count; | 296 | int suspend_count; |
297 | }; | 297 | }; |
298 | 298 | ||
299 | static int inc_tx(struct btusb_data *data) | ||
300 | { | ||
301 | unsigned long flags; | ||
302 | int rv; | ||
303 | |||
304 | spin_lock_irqsave(&data->txlock, flags); | ||
305 | rv = test_bit(BTUSB_SUSPENDING, &data->flags); | ||
306 | if (!rv) | ||
307 | data->tx_in_flight++; | ||
308 | spin_unlock_irqrestore(&data->txlock, flags); | ||
309 | |||
310 | return rv; | ||
311 | } | ||
312 | |||
313 | static void btusb_intr_complete(struct urb *urb) | 299 | static void btusb_intr_complete(struct urb *urb) |
314 | { | 300 | { |
315 | struct hci_dev *hdev = urb->context; | 301 | struct hci_dev *hdev = urb->context; |
@@ -752,100 +738,96 @@ static int btusb_flush(struct hci_dev *hdev) | |||
752 | return 0; | 738 | return 0; |
753 | } | 739 | } |
754 | 740 | ||
755 | static int btusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb) | 741 | static struct urb *alloc_ctrl_urb(struct hci_dev *hdev, struct sk_buff *skb) |
756 | { | 742 | { |
757 | struct btusb_data *data = hci_get_drvdata(hdev); | 743 | struct btusb_data *data = hci_get_drvdata(hdev); |
758 | struct usb_ctrlrequest *dr; | 744 | struct usb_ctrlrequest *dr; |
759 | struct urb *urb; | 745 | struct urb *urb; |
760 | unsigned int pipe; | 746 | unsigned int pipe; |
761 | int err; | ||
762 | 747 | ||
763 | BT_DBG("%s", hdev->name); | 748 | urb = usb_alloc_urb(0, GFP_KERNEL); |
749 | if (!urb) | ||
750 | return ERR_PTR(-ENOMEM); | ||
764 | 751 | ||
765 | if (!test_bit(HCI_RUNNING, &hdev->flags)) | 752 | dr = kmalloc(sizeof(*dr), GFP_KERNEL); |
766 | return -EBUSY; | 753 | if (!dr) { |
754 | usb_free_urb(urb); | ||
755 | return ERR_PTR(-ENOMEM); | ||
756 | } | ||
767 | 757 | ||
768 | skb->dev = (void *) hdev; | 758 | dr->bRequestType = data->cmdreq_type; |
759 | dr->bRequest = 0; | ||
760 | dr->wIndex = 0; | ||
761 | dr->wValue = 0; | ||
762 | dr->wLength = __cpu_to_le16(skb->len); | ||
769 | 763 | ||
770 | switch (bt_cb(skb)->pkt_type) { | 764 | pipe = usb_sndctrlpipe(data->udev, 0x00); |
771 | case HCI_COMMAND_PKT: | ||
772 | urb = usb_alloc_urb(0, GFP_KERNEL); | ||
773 | if (!urb) | ||
774 | return -ENOMEM; | ||
775 | |||
776 | dr = kmalloc(sizeof(*dr), GFP_KERNEL); | ||
777 | if (!dr) { | ||
778 | usb_free_urb(urb); | ||
779 | return -ENOMEM; | ||
780 | } | ||
781 | 765 | ||
782 | dr->bRequestType = data->cmdreq_type; | 766 | usb_fill_control_urb(urb, data->udev, pipe, (void *) dr, |
783 | dr->bRequest = 0; | 767 | skb->data, skb->len, btusb_tx_complete, skb); |
784 | dr->wIndex = 0; | ||
785 | dr->wValue = 0; | ||
786 | dr->wLength = __cpu_to_le16(skb->len); | ||
787 | 768 | ||
788 | pipe = usb_sndctrlpipe(data->udev, 0x00); | 769 | skb->dev = (void *) hdev; |
789 | 770 | ||
790 | usb_fill_control_urb(urb, data->udev, pipe, (void *) dr, | 771 | return urb; |
791 | skb->data, skb->len, btusb_tx_complete, skb); | 772 | } |
792 | 773 | ||
793 | hdev->stat.cmd_tx++; | 774 | static struct urb *alloc_bulk_urb(struct hci_dev *hdev, struct sk_buff *skb) |
794 | break; | 775 | { |
776 | struct btusb_data *data = hci_get_drvdata(hdev); | ||
777 | struct urb *urb; | ||
778 | unsigned int pipe; | ||
795 | 779 | ||
796 | case HCI_ACLDATA_PKT: | 780 | if (!data->bulk_tx_ep) |
797 | if (!data->bulk_tx_ep) | 781 | return ERR_PTR(-ENODEV); |
798 | return -ENODEV; | ||
799 | 782 | ||
800 | urb = usb_alloc_urb(0, GFP_KERNEL); | 783 | urb = usb_alloc_urb(0, GFP_KERNEL); |
801 | if (!urb) | 784 | if (!urb) |
802 | return -ENOMEM; | 785 | return ERR_PTR(-ENOMEM); |
803 | 786 | ||
804 | pipe = usb_sndbulkpipe(data->udev, | 787 | pipe = usb_sndbulkpipe(data->udev, data->bulk_tx_ep->bEndpointAddress); |
805 | data->bulk_tx_ep->bEndpointAddress); | ||
806 | 788 | ||
807 | usb_fill_bulk_urb(urb, data->udev, pipe, | 789 | usb_fill_bulk_urb(urb, data->udev, pipe, |
808 | skb->data, skb->len, btusb_tx_complete, skb); | 790 | skb->data, skb->len, btusb_tx_complete, skb); |
809 | 791 | ||
810 | hdev->stat.acl_tx++; | 792 | skb->dev = (void *) hdev; |
811 | break; | ||
812 | 793 | ||
813 | case HCI_SCODATA_PKT: | 794 | return urb; |
814 | if (!data->isoc_tx_ep || hci_conn_num(hdev, SCO_LINK) < 1) | 795 | } |
815 | return -ENODEV; | ||
816 | 796 | ||
817 | urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, GFP_KERNEL); | 797 | static struct urb *alloc_isoc_urb(struct hci_dev *hdev, struct sk_buff *skb) |
818 | if (!urb) | 798 | { |
819 | return -ENOMEM; | 799 | struct btusb_data *data = hci_get_drvdata(hdev); |
800 | struct urb *urb; | ||
801 | unsigned int pipe; | ||
820 | 802 | ||
821 | pipe = usb_sndisocpipe(data->udev, | 803 | if (!data->isoc_tx_ep) |
822 | data->isoc_tx_ep->bEndpointAddress); | 804 | return ERR_PTR(-ENODEV); |
823 | 805 | ||
824 | usb_fill_int_urb(urb, data->udev, pipe, | 806 | urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, GFP_KERNEL); |
825 | skb->data, skb->len, btusb_isoc_tx_complete, | 807 | if (!urb) |
826 | skb, data->isoc_tx_ep->bInterval); | 808 | return ERR_PTR(-ENOMEM); |
827 | 809 | ||
828 | urb->transfer_flags = URB_ISO_ASAP; | 810 | pipe = usb_sndisocpipe(data->udev, data->isoc_tx_ep->bEndpointAddress); |
829 | 811 | ||
830 | __fill_isoc_descriptor(urb, skb->len, | 812 | usb_fill_int_urb(urb, data->udev, pipe, |
831 | le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize)); | 813 | skb->data, skb->len, btusb_isoc_tx_complete, |
814 | skb, data->isoc_tx_ep->bInterval); | ||
832 | 815 | ||
833 | hdev->stat.sco_tx++; | 816 | urb->transfer_flags = URB_ISO_ASAP; |
834 | goto skip_waking; | ||
835 | 817 | ||
836 | default: | 818 | __fill_isoc_descriptor(urb, skb->len, |
837 | return -EILSEQ; | 819 | le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize)); |
838 | } | ||
839 | 820 | ||
840 | err = inc_tx(data); | 821 | skb->dev = (void *) hdev; |
841 | if (err) { | 822 | |
842 | usb_anchor_urb(urb, &data->deferred); | 823 | return urb; |
843 | schedule_work(&data->waker); | 824 | } |
844 | err = 0; | 825 | |
845 | goto done; | 826 | static int submit_tx_urb(struct hci_dev *hdev, struct urb *urb) |
846 | } | 827 | { |
828 | struct btusb_data *data = hci_get_drvdata(hdev); | ||
829 | int err; | ||
847 | 830 | ||
848 | skip_waking: | ||
849 | usb_anchor_urb(urb, &data->tx_anchor); | 831 | usb_anchor_urb(urb, &data->tx_anchor); |
850 | 832 | ||
851 | err = usb_submit_urb(urb, GFP_KERNEL); | 833 | err = usb_submit_urb(urb, GFP_KERNEL); |
@@ -859,11 +841,73 @@ skip_waking: | |||
859 | usb_mark_last_busy(data->udev); | 841 | usb_mark_last_busy(data->udev); |
860 | } | 842 | } |
861 | 843 | ||
862 | done: | ||
863 | usb_free_urb(urb); | 844 | usb_free_urb(urb); |
864 | return err; | 845 | return err; |
865 | } | 846 | } |
866 | 847 | ||
848 | static int submit_or_queue_tx_urb(struct hci_dev *hdev, struct urb *urb) | ||
849 | { | ||
850 | struct btusb_data *data = hci_get_drvdata(hdev); | ||
851 | unsigned long flags; | ||
852 | bool suspending; | ||
853 | |||
854 | spin_lock_irqsave(&data->txlock, flags); | ||
855 | suspending = test_bit(BTUSB_SUSPENDING, &data->flags); | ||
856 | if (!suspending) | ||
857 | data->tx_in_flight++; | ||
858 | spin_unlock_irqrestore(&data->txlock, flags); | ||
859 | |||
860 | if (!suspending) | ||
861 | return submit_tx_urb(hdev, urb); | ||
862 | |||
863 | usb_anchor_urb(urb, &data->deferred); | ||
864 | schedule_work(&data->waker); | ||
865 | |||
866 | usb_free_urb(urb); | ||
867 | return 0; | ||
868 | } | ||
869 | |||
870 | static int btusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb) | ||
871 | { | ||
872 | struct urb *urb; | ||
873 | |||
874 | BT_DBG("%s", hdev->name); | ||
875 | |||
876 | if (!test_bit(HCI_RUNNING, &hdev->flags)) | ||
877 | return -EBUSY; | ||
878 | |||
879 | switch (bt_cb(skb)->pkt_type) { | ||
880 | case HCI_COMMAND_PKT: | ||
881 | urb = alloc_ctrl_urb(hdev, skb); | ||
882 | if (IS_ERR(urb)) | ||
883 | return PTR_ERR(urb); | ||
884 | |||
885 | hdev->stat.cmd_tx++; | ||
886 | return submit_or_queue_tx_urb(hdev, urb); | ||
887 | |||
888 | case HCI_ACLDATA_PKT: | ||
889 | urb = alloc_bulk_urb(hdev, skb); | ||
890 | if (IS_ERR(urb)) | ||
891 | return PTR_ERR(urb); | ||
892 | |||
893 | hdev->stat.acl_tx++; | ||
894 | return submit_or_queue_tx_urb(hdev, urb); | ||
895 | |||
896 | case HCI_SCODATA_PKT: | ||
897 | if (hci_conn_num(hdev, SCO_LINK) < 1) | ||
898 | return -ENODEV; | ||
899 | |||
900 | urb = alloc_isoc_urb(hdev, skb); | ||
901 | if (IS_ERR(urb)) | ||
902 | return PTR_ERR(urb); | ||
903 | |||
904 | hdev->stat.sco_tx++; | ||
905 | return submit_tx_urb(hdev, urb); | ||
906 | } | ||
907 | |||
908 | return -EILSEQ; | ||
909 | } | ||
910 | |||
867 | static void btusb_notify(struct hci_dev *hdev, unsigned int evt) | 911 | static void btusb_notify(struct hci_dev *hdev, unsigned int evt) |
868 | { | 912 | { |
869 | struct btusb_data *data = hci_get_drvdata(hdev); | 913 | struct btusb_data *data = hci_get_drvdata(hdev); |