Loading MAINTAINERS +6 −81 Original line number Diff line number Diff line Loading @@ -936,94 +936,19 @@ M: joern@lazybastard.org L: linux-mtd@lists.infradead.org S: Maintained BLUETOOTH SUBSYSTEM BLUETOOTH DRIVERS P: Marcel Holtmann M: marcel@holtmann.org P: Maxim Krasnyansky M: maxk@qualcomm.com L: linux-bluetooth@vger.kernel.org W: http://bluez.sf.net W: http://www.bluez.org W: http://www.holtmann.org/linux/bluetooth/ T: git kernel.org:/pub/scm/linux/kernel/git/holtmann/bluetooth-2.6.git S: Maintained BLUETOOTH RFCOMM LAYER P: Marcel Holtmann M: marcel@holtmann.org P: Maxim Krasnyansky M: maxk@qualcomm.com S: Maintained BLUETOOTH BNEP LAYER P: Marcel Holtmann M: marcel@holtmann.org P: Maxim Krasnyansky M: maxk@qualcomm.com S: Maintained BLUETOOTH CMTP LAYER P: Marcel Holtmann M: marcel@holtmann.org W: http://www.bluez.org/ S: Maintained BLUETOOTH HIDP LAYER P: Marcel Holtmann M: marcel@holtmann.org S: Maintained BLUETOOTH HCI UART DRIVER P: Marcel Holtmann M: marcel@holtmann.org P: Maxim Krasnyansky M: maxk@qualcomm.com S: Maintained BLUETOOTH HCI USB DRIVER P: Marcel Holtmann M: marcel@holtmann.org P: Maxim Krasnyansky M: maxk@qualcomm.com S: Maintained BLUETOOTH HCI BCM203X DRIVER P: Marcel Holtmann M: marcel@holtmann.org S: Maintained BLUETOOTH HCI BPA10X DRIVER P: Marcel Holtmann M: marcel@holtmann.org S: Maintained BLUETOOTH HCI BFUSB DRIVER P: Marcel Holtmann M: marcel@holtmann.org S: Maintained BLUETOOTH HCI DTL1 DRIVER P: Marcel Holtmann M: marcel@holtmann.org S: Maintained BLUETOOTH HCI BLUECARD DRIVER P: Marcel Holtmann M: marcel@holtmann.org S: Maintained BLUETOOTH HCI BT3C DRIVER P: Marcel Holtmann M: marcel@holtmann.org S: Maintained BLUETOOTH HCI BTUART DRIVER BLUETOOTH SUBSYSTEM P: Marcel Holtmann M: marcel@holtmann.org S: Maintained BLUETOOTH HCI VHCI DRIVER P: Maxim Krasnyansky M: maxk@qualcomm.com L: linux-bluetooth@vger.kernel.org W: http://www.bluez.org/ T: git kernel.org:/pub/scm/linux/kernel/git/holtmann/bluetooth-2.6.git S: Maintained BONDING DRIVER Loading drivers/bluetooth/Kconfig +4 −6 Original line number Diff line number Diff line Loading @@ -3,8 +3,8 @@ menu "Bluetooth device drivers" depends on BT config BT_HCIUSB tristate "HCI USB driver" depends on USB tristate "HCI USB driver (old version)" depends on USB && BT_HCIBTUSB=n help Bluetooth HCI USB driver. This driver is required if you want to use Bluetooth devices with Loading @@ -23,15 +23,13 @@ config BT_HCIUSB_SCO Say Y here to compile support for SCO over HCI USB. config BT_HCIBTUSB tristate "HCI USB driver (alternate version)" depends on USB && EXPERIMENTAL && BT_HCIUSB=n tristate "HCI USB driver" depends on USB help Bluetooth HCI USB driver. This driver is required if you want to use Bluetooth devices with USB interface. This driver is still experimental and has no SCO support. Say Y here to compile support for Bluetooth USB devices into the kernel or say M to compile it as module (btusb). Loading drivers/bluetooth/bt3c_cs.c +1 −1 Original line number Diff line number Diff line Loading @@ -60,7 +60,7 @@ /* ======================== Module parameters ======================== */ MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>, Jose Orlando Pereira <jop@di.uminho.pt>"); MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); MODULE_DESCRIPTION("Bluetooth driver for the 3Com Bluetooth PCMCIA card"); MODULE_LICENSE("GPL"); MODULE_FIRMWARE("BT3CPCC.bin"); Loading drivers/bluetooth/btusb.c +268 −14 Original line number Diff line number Diff line Loading @@ -2,7 +2,7 @@ * * Generic Bluetooth USB driver * * Copyright (C) 2005-2007 Marcel Holtmann <marcel@holtmann.org> * Copyright (C) 2005-2008 Marcel Holtmann <marcel@holtmann.org> * * * This program is free software; you can redistribute it and/or modify Loading Loading @@ -41,7 +41,7 @@ #define BT_DBG(D...) #endif #define VERSION "0.2" #define VERSION "0.3" static int ignore_dga; static int ignore_csr; Loading Loading @@ -160,12 +160,16 @@ static struct usb_device_id blacklist_table[] = { { } /* Terminating entry */ }; #define BTUSB_MAX_ISOC_FRAMES 10 #define BTUSB_INTR_RUNNING 0 #define BTUSB_BULK_RUNNING 1 #define BTUSB_ISOC_RUNNING 2 struct btusb_data { struct hci_dev *hdev; struct usb_device *udev; struct usb_interface *isoc; spinlock_t lock; Loading @@ -176,10 +180,15 @@ struct btusb_data { struct usb_anchor tx_anchor; struct usb_anchor intr_anchor; struct usb_anchor bulk_anchor; struct usb_anchor isoc_anchor; struct usb_endpoint_descriptor *intr_ep; struct usb_endpoint_descriptor *bulk_tx_ep; struct usb_endpoint_descriptor *bulk_rx_ep; struct usb_endpoint_descriptor *isoc_tx_ep; struct usb_endpoint_descriptor *isoc_rx_ep; int isoc_altsetting; }; static void btusb_intr_complete(struct urb *urb) Loading @@ -195,6 +204,8 @@ static void btusb_intr_complete(struct urb *urb) return; 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) { Loading @@ -216,7 +227,7 @@ static void btusb_intr_complete(struct urb *urb) } } static inline int btusb_submit_intr_urb(struct hci_dev *hdev) static int btusb_submit_intr_urb(struct hci_dev *hdev) { struct btusb_data *data = hdev->driver_data; struct urb *urb; Loading @@ -226,6 +237,9 @@ static inline int btusb_submit_intr_urb(struct hci_dev *hdev) BT_DBG("%s", hdev->name); if (!data->intr_ep) return -ENODEV; urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) return -ENOMEM; Loading Loading @@ -274,6 +288,8 @@ static void btusb_bulk_complete(struct urb *urb) return; 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) { Loading @@ -295,7 +311,7 @@ static void btusb_bulk_complete(struct urb *urb) } } static inline int btusb_submit_bulk_urb(struct hci_dev *hdev) static int btusb_submit_bulk_urb(struct hci_dev *hdev) { struct btusb_data *data = hdev->driver_data; struct urb *urb; Loading @@ -305,6 +321,9 @@ static inline int btusb_submit_bulk_urb(struct hci_dev *hdev) BT_DBG("%s", hdev->name); if (!data->bulk_rx_ep) return -ENODEV; urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb) return -ENOMEM; Loading Loading @@ -339,6 +358,127 @@ static inline int btusb_submit_bulk_urb(struct hci_dev *hdev) return err; } static void btusb_isoc_complete(struct urb *urb) { struct hci_dev *hdev = urb->context; struct btusb_data *data = hdev->driver_data; int i, err; 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; if (urb->status == 0) { for (i = 0; i < urb->number_of_packets; i++) { unsigned int offset = urb->iso_frame_desc[i].offset; unsigned int length = urb->iso_frame_desc[i].actual_length; if (urb->iso_frame_desc[i].status) continue; hdev->stat.byte_rx += length; if (hci_recv_fragment(hdev, HCI_SCODATA_PKT, urb->transfer_buffer + offset, length) < 0) { BT_ERR("%s corrupted SCO packet", hdev->name); hdev->stat.err_rx++; } } } if (!test_bit(BTUSB_ISOC_RUNNING, &data->flags)) return; usb_anchor_urb(urb, &data->isoc_anchor); err = usb_submit_urb(urb, GFP_ATOMIC); if (err < 0) { BT_ERR("%s urb %p failed to resubmit (%d)", hdev->name, urb, -err); usb_unanchor_urb(urb); } } static void inline __fill_isoc_descriptor(struct urb *urb, int len, int mtu) { int i, offset = 0; BT_DBG("len %d mtu %d", len, mtu); for (i = 0; i < BTUSB_MAX_ISOC_FRAMES && len >= mtu; i++, offset += mtu, len -= mtu) { urb->iso_frame_desc[i].offset = offset; urb->iso_frame_desc[i].length = mtu; } if (len && i < BTUSB_MAX_ISOC_FRAMES) { urb->iso_frame_desc[i].offset = offset; urb->iso_frame_desc[i].length = len; i++; } urb->number_of_packets = i; } static int btusb_submit_isoc_urb(struct hci_dev *hdev) { struct btusb_data *data = hdev->driver_data; struct urb *urb; unsigned char *buf; unsigned int pipe; int err, size; BT_DBG("%s", hdev->name); if (!data->isoc_rx_ep) return -ENODEV; urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, GFP_KERNEL); if (!urb) return -ENOMEM; size = le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize) * BTUSB_MAX_ISOC_FRAMES; buf = kmalloc(size, GFP_KERNEL); if (!buf) { usb_free_urb(urb); return -ENOMEM; } pipe = usb_rcvisocpipe(data->udev, data->isoc_rx_ep->bEndpointAddress); urb->dev = data->udev; urb->pipe = pipe; urb->context = hdev; urb->complete = btusb_isoc_complete; urb->interval = data->isoc_rx_ep->bInterval; urb->transfer_flags = URB_FREE_BUFFER | URB_ISO_ASAP; urb->transfer_buffer = buf; urb->transfer_buffer_length = size; __fill_isoc_descriptor(urb, size, le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize)); usb_anchor_urb(urb, &data->isoc_anchor); err = usb_submit_urb(urb, GFP_KERNEL); if (err < 0) { BT_ERR("%s urb %p submission failed (%d)", hdev->name, urb, -err); usb_unanchor_urb(urb); kfree(buf); } usb_free_urb(urb); return err; } static void btusb_tx_complete(struct urb *urb) { struct sk_buff *skb = urb->context; Loading Loading @@ -392,6 +532,9 @@ static int btusb_close(struct hci_dev *hdev) if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) return 0; clear_bit(BTUSB_ISOC_RUNNING, &data->flags); usb_kill_anchored_urbs(&data->intr_anchor); clear_bit(BTUSB_BULK_RUNNING, &data->flags); usb_kill_anchored_urbs(&data->bulk_anchor); Loading Loading @@ -453,6 +596,9 @@ static int btusb_send_frame(struct sk_buff *skb) break; case HCI_ACLDATA_PKT: if (!data->bulk_tx_ep || hdev->conn_hash.acl_num < 1) return -ENODEV; urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) return -ENOMEM; Loading @@ -467,9 +613,31 @@ static int btusb_send_frame(struct sk_buff *skb) break; case HCI_SCODATA_PKT: if (!data->isoc_tx_ep || hdev->conn_hash.sco_num < 1) return -ENODEV; urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, GFP_ATOMIC); if (!urb) return -ENOMEM; pipe = usb_sndisocpipe(data->udev, data->isoc_tx_ep->bEndpointAddress); urb->dev = data->udev; urb->pipe = pipe; urb->context = skb; urb->complete = btusb_tx_complete; urb->interval = data->isoc_tx_ep->bInterval; urb->transfer_flags = URB_ISO_ASAP; urb->transfer_buffer = skb->data; urb->transfer_buffer_length = skb->len; __fill_isoc_descriptor(urb, skb->len, le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize)); hdev->stat.sco_tx++; kfree_skb(skb); return 0; break; default: return -EILSEQ; Loading Loading @@ -508,22 +676,86 @@ static void btusb_notify(struct hci_dev *hdev, unsigned int evt) schedule_work(&data->work); } static int inline __set_isoc_interface(struct hci_dev *hdev, int altsetting) { struct btusb_data *data = hdev->driver_data; struct usb_interface *intf = data->isoc; struct usb_endpoint_descriptor *ep_desc; int i, err; if (!data->isoc) return -ENODEV; err = usb_set_interface(data->udev, 1, altsetting); if (err < 0) { BT_ERR("%s setting interface failed (%d)", hdev->name, -err); return err; } data->isoc_altsetting = altsetting; data->isoc_tx_ep = NULL; data->isoc_rx_ep = NULL; for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) { ep_desc = &intf->cur_altsetting->endpoint[i].desc; if (!data->isoc_tx_ep && usb_endpoint_is_isoc_out(ep_desc)) { data->isoc_tx_ep = ep_desc; continue; } if (!data->isoc_rx_ep && usb_endpoint_is_isoc_in(ep_desc)) { data->isoc_rx_ep = ep_desc; continue; } } if (!data->isoc_tx_ep || !data->isoc_rx_ep) { BT_ERR("%s invalid SCO descriptors", hdev->name); return -ENODEV; } return 0; } static void btusb_work(struct work_struct *work) { struct btusb_data *data = container_of(work, struct btusb_data, work); struct hci_dev *hdev = data->hdev; if (hdev->conn_hash.acl_num == 0) { if (hdev->conn_hash.acl_num > 0) { if (!test_and_set_bit(BTUSB_BULK_RUNNING, &data->flags)) { if (btusb_submit_bulk_urb(hdev) < 0) clear_bit(BTUSB_BULK_RUNNING, &data->flags); else btusb_submit_bulk_urb(hdev); } } else { clear_bit(BTUSB_BULK_RUNNING, &data->flags); usb_kill_anchored_urbs(&data->bulk_anchor); } if (hdev->conn_hash.sco_num > 0) { if (data->isoc_altsetting != 2) { clear_bit(BTUSB_ISOC_RUNNING, &data->flags); usb_kill_anchored_urbs(&data->isoc_anchor); if (__set_isoc_interface(hdev, 2) < 0) return; } if (!test_and_set_bit(BTUSB_BULK_RUNNING, &data->flags)) { if (btusb_submit_bulk_urb(hdev) < 0) clear_bit(BTUSB_BULK_RUNNING, &data->flags); if (!test_and_set_bit(BTUSB_ISOC_RUNNING, &data->flags)) { if (btusb_submit_isoc_urb(hdev) < 0) clear_bit(BTUSB_ISOC_RUNNING, &data->flags); else btusb_submit_bulk_urb(hdev); btusb_submit_isoc_urb(hdev); } } else { clear_bit(BTUSB_ISOC_RUNNING, &data->flags); usb_kill_anchored_urbs(&data->isoc_anchor); __set_isoc_interface(hdev, 0); } } Loading Loading @@ -597,6 +829,7 @@ static int btusb_probe(struct usb_interface *intf, init_usb_anchor(&data->tx_anchor); init_usb_anchor(&data->intr_anchor); init_usb_anchor(&data->bulk_anchor); init_usb_anchor(&data->isoc_anchor); hdev = hci_alloc_dev(); if (!hdev) { Loading @@ -620,6 +853,9 @@ static int btusb_probe(struct usb_interface *intf, hdev->owner = THIS_MODULE; /* interface numbers are hardcoded in the spec */ data->isoc = usb_ifnum_to_if(data->udev, 1); if (reset || id->driver_info & BTUSB_RESET) set_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks); Loading @@ -628,11 +864,16 @@ static int btusb_probe(struct usb_interface *intf, set_bit(HCI_QUIRK_FIXUP_BUFFER_SIZE, &hdev->quirks); } if (id->driver_info & BTUSB_BROKEN_ISOC) data->isoc = NULL; if (id->driver_info & BTUSB_SNIFFER) { struct usb_device *udev = interface_to_usbdev(intf); struct usb_device *udev = data->udev; if (le16_to_cpu(udev->descriptor.bcdDevice) > 0x997) set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks); data->isoc = NULL; } if (id->driver_info & BTUSB_BCM92035) { Loading @@ -646,6 +887,16 @@ static int btusb_probe(struct usb_interface *intf, } } if (data->isoc) { err = usb_driver_claim_interface(&btusb_driver, data->isoc, NULL); if (err < 0) { hci_free_dev(hdev); kfree(data); return err; } } err = hci_register_dev(hdev); if (err < 0) { hci_free_dev(hdev); Loading @@ -670,6 +921,9 @@ static void btusb_disconnect(struct usb_interface *intf) hdev = data->hdev; if (data->isoc) usb_driver_release_interface(&btusb_driver, data->isoc); usb_set_intfdata(intf, NULL); hci_unregister_dev(hdev); Loading drivers/bluetooth/hci_ldisc.c +1 −1 Original line number Diff line number Diff line Loading @@ -577,7 +577,7 @@ module_exit(hci_uart_exit); module_param(reset, bool, 0644); MODULE_PARM_DESC(reset, "Send HCI reset command on initialization"); MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>"); MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); MODULE_DESCRIPTION("Bluetooth HCI UART driver ver " VERSION); MODULE_VERSION(VERSION); MODULE_LICENSE("GPL"); Loading Loading
MAINTAINERS +6 −81 Original line number Diff line number Diff line Loading @@ -936,94 +936,19 @@ M: joern@lazybastard.org L: linux-mtd@lists.infradead.org S: Maintained BLUETOOTH SUBSYSTEM BLUETOOTH DRIVERS P: Marcel Holtmann M: marcel@holtmann.org P: Maxim Krasnyansky M: maxk@qualcomm.com L: linux-bluetooth@vger.kernel.org W: http://bluez.sf.net W: http://www.bluez.org W: http://www.holtmann.org/linux/bluetooth/ T: git kernel.org:/pub/scm/linux/kernel/git/holtmann/bluetooth-2.6.git S: Maintained BLUETOOTH RFCOMM LAYER P: Marcel Holtmann M: marcel@holtmann.org P: Maxim Krasnyansky M: maxk@qualcomm.com S: Maintained BLUETOOTH BNEP LAYER P: Marcel Holtmann M: marcel@holtmann.org P: Maxim Krasnyansky M: maxk@qualcomm.com S: Maintained BLUETOOTH CMTP LAYER P: Marcel Holtmann M: marcel@holtmann.org W: http://www.bluez.org/ S: Maintained BLUETOOTH HIDP LAYER P: Marcel Holtmann M: marcel@holtmann.org S: Maintained BLUETOOTH HCI UART DRIVER P: Marcel Holtmann M: marcel@holtmann.org P: Maxim Krasnyansky M: maxk@qualcomm.com S: Maintained BLUETOOTH HCI USB DRIVER P: Marcel Holtmann M: marcel@holtmann.org P: Maxim Krasnyansky M: maxk@qualcomm.com S: Maintained BLUETOOTH HCI BCM203X DRIVER P: Marcel Holtmann M: marcel@holtmann.org S: Maintained BLUETOOTH HCI BPA10X DRIVER P: Marcel Holtmann M: marcel@holtmann.org S: Maintained BLUETOOTH HCI BFUSB DRIVER P: Marcel Holtmann M: marcel@holtmann.org S: Maintained BLUETOOTH HCI DTL1 DRIVER P: Marcel Holtmann M: marcel@holtmann.org S: Maintained BLUETOOTH HCI BLUECARD DRIVER P: Marcel Holtmann M: marcel@holtmann.org S: Maintained BLUETOOTH HCI BT3C DRIVER P: Marcel Holtmann M: marcel@holtmann.org S: Maintained BLUETOOTH HCI BTUART DRIVER BLUETOOTH SUBSYSTEM P: Marcel Holtmann M: marcel@holtmann.org S: Maintained BLUETOOTH HCI VHCI DRIVER P: Maxim Krasnyansky M: maxk@qualcomm.com L: linux-bluetooth@vger.kernel.org W: http://www.bluez.org/ T: git kernel.org:/pub/scm/linux/kernel/git/holtmann/bluetooth-2.6.git S: Maintained BONDING DRIVER Loading
drivers/bluetooth/Kconfig +4 −6 Original line number Diff line number Diff line Loading @@ -3,8 +3,8 @@ menu "Bluetooth device drivers" depends on BT config BT_HCIUSB tristate "HCI USB driver" depends on USB tristate "HCI USB driver (old version)" depends on USB && BT_HCIBTUSB=n help Bluetooth HCI USB driver. This driver is required if you want to use Bluetooth devices with Loading @@ -23,15 +23,13 @@ config BT_HCIUSB_SCO Say Y here to compile support for SCO over HCI USB. config BT_HCIBTUSB tristate "HCI USB driver (alternate version)" depends on USB && EXPERIMENTAL && BT_HCIUSB=n tristate "HCI USB driver" depends on USB help Bluetooth HCI USB driver. This driver is required if you want to use Bluetooth devices with USB interface. This driver is still experimental and has no SCO support. Say Y here to compile support for Bluetooth USB devices into the kernel or say M to compile it as module (btusb). Loading
drivers/bluetooth/bt3c_cs.c +1 −1 Original line number Diff line number Diff line Loading @@ -60,7 +60,7 @@ /* ======================== Module parameters ======================== */ MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>, Jose Orlando Pereira <jop@di.uminho.pt>"); MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); MODULE_DESCRIPTION("Bluetooth driver for the 3Com Bluetooth PCMCIA card"); MODULE_LICENSE("GPL"); MODULE_FIRMWARE("BT3CPCC.bin"); Loading
drivers/bluetooth/btusb.c +268 −14 Original line number Diff line number Diff line Loading @@ -2,7 +2,7 @@ * * Generic Bluetooth USB driver * * Copyright (C) 2005-2007 Marcel Holtmann <marcel@holtmann.org> * Copyright (C) 2005-2008 Marcel Holtmann <marcel@holtmann.org> * * * This program is free software; you can redistribute it and/or modify Loading Loading @@ -41,7 +41,7 @@ #define BT_DBG(D...) #endif #define VERSION "0.2" #define VERSION "0.3" static int ignore_dga; static int ignore_csr; Loading Loading @@ -160,12 +160,16 @@ static struct usb_device_id blacklist_table[] = { { } /* Terminating entry */ }; #define BTUSB_MAX_ISOC_FRAMES 10 #define BTUSB_INTR_RUNNING 0 #define BTUSB_BULK_RUNNING 1 #define BTUSB_ISOC_RUNNING 2 struct btusb_data { struct hci_dev *hdev; struct usb_device *udev; struct usb_interface *isoc; spinlock_t lock; Loading @@ -176,10 +180,15 @@ struct btusb_data { struct usb_anchor tx_anchor; struct usb_anchor intr_anchor; struct usb_anchor bulk_anchor; struct usb_anchor isoc_anchor; struct usb_endpoint_descriptor *intr_ep; struct usb_endpoint_descriptor *bulk_tx_ep; struct usb_endpoint_descriptor *bulk_rx_ep; struct usb_endpoint_descriptor *isoc_tx_ep; struct usb_endpoint_descriptor *isoc_rx_ep; int isoc_altsetting; }; static void btusb_intr_complete(struct urb *urb) Loading @@ -195,6 +204,8 @@ static void btusb_intr_complete(struct urb *urb) return; 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) { Loading @@ -216,7 +227,7 @@ static void btusb_intr_complete(struct urb *urb) } } static inline int btusb_submit_intr_urb(struct hci_dev *hdev) static int btusb_submit_intr_urb(struct hci_dev *hdev) { struct btusb_data *data = hdev->driver_data; struct urb *urb; Loading @@ -226,6 +237,9 @@ static inline int btusb_submit_intr_urb(struct hci_dev *hdev) BT_DBG("%s", hdev->name); if (!data->intr_ep) return -ENODEV; urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) return -ENOMEM; Loading Loading @@ -274,6 +288,8 @@ static void btusb_bulk_complete(struct urb *urb) return; 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) { Loading @@ -295,7 +311,7 @@ static void btusb_bulk_complete(struct urb *urb) } } static inline int btusb_submit_bulk_urb(struct hci_dev *hdev) static int btusb_submit_bulk_urb(struct hci_dev *hdev) { struct btusb_data *data = hdev->driver_data; struct urb *urb; Loading @@ -305,6 +321,9 @@ static inline int btusb_submit_bulk_urb(struct hci_dev *hdev) BT_DBG("%s", hdev->name); if (!data->bulk_rx_ep) return -ENODEV; urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb) return -ENOMEM; Loading Loading @@ -339,6 +358,127 @@ static inline int btusb_submit_bulk_urb(struct hci_dev *hdev) return err; } static void btusb_isoc_complete(struct urb *urb) { struct hci_dev *hdev = urb->context; struct btusb_data *data = hdev->driver_data; int i, err; 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; if (urb->status == 0) { for (i = 0; i < urb->number_of_packets; i++) { unsigned int offset = urb->iso_frame_desc[i].offset; unsigned int length = urb->iso_frame_desc[i].actual_length; if (urb->iso_frame_desc[i].status) continue; hdev->stat.byte_rx += length; if (hci_recv_fragment(hdev, HCI_SCODATA_PKT, urb->transfer_buffer + offset, length) < 0) { BT_ERR("%s corrupted SCO packet", hdev->name); hdev->stat.err_rx++; } } } if (!test_bit(BTUSB_ISOC_RUNNING, &data->flags)) return; usb_anchor_urb(urb, &data->isoc_anchor); err = usb_submit_urb(urb, GFP_ATOMIC); if (err < 0) { BT_ERR("%s urb %p failed to resubmit (%d)", hdev->name, urb, -err); usb_unanchor_urb(urb); } } static void inline __fill_isoc_descriptor(struct urb *urb, int len, int mtu) { int i, offset = 0; BT_DBG("len %d mtu %d", len, mtu); for (i = 0; i < BTUSB_MAX_ISOC_FRAMES && len >= mtu; i++, offset += mtu, len -= mtu) { urb->iso_frame_desc[i].offset = offset; urb->iso_frame_desc[i].length = mtu; } if (len && i < BTUSB_MAX_ISOC_FRAMES) { urb->iso_frame_desc[i].offset = offset; urb->iso_frame_desc[i].length = len; i++; } urb->number_of_packets = i; } static int btusb_submit_isoc_urb(struct hci_dev *hdev) { struct btusb_data *data = hdev->driver_data; struct urb *urb; unsigned char *buf; unsigned int pipe; int err, size; BT_DBG("%s", hdev->name); if (!data->isoc_rx_ep) return -ENODEV; urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, GFP_KERNEL); if (!urb) return -ENOMEM; size = le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize) * BTUSB_MAX_ISOC_FRAMES; buf = kmalloc(size, GFP_KERNEL); if (!buf) { usb_free_urb(urb); return -ENOMEM; } pipe = usb_rcvisocpipe(data->udev, data->isoc_rx_ep->bEndpointAddress); urb->dev = data->udev; urb->pipe = pipe; urb->context = hdev; urb->complete = btusb_isoc_complete; urb->interval = data->isoc_rx_ep->bInterval; urb->transfer_flags = URB_FREE_BUFFER | URB_ISO_ASAP; urb->transfer_buffer = buf; urb->transfer_buffer_length = size; __fill_isoc_descriptor(urb, size, le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize)); usb_anchor_urb(urb, &data->isoc_anchor); err = usb_submit_urb(urb, GFP_KERNEL); if (err < 0) { BT_ERR("%s urb %p submission failed (%d)", hdev->name, urb, -err); usb_unanchor_urb(urb); kfree(buf); } usb_free_urb(urb); return err; } static void btusb_tx_complete(struct urb *urb) { struct sk_buff *skb = urb->context; Loading Loading @@ -392,6 +532,9 @@ static int btusb_close(struct hci_dev *hdev) if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) return 0; clear_bit(BTUSB_ISOC_RUNNING, &data->flags); usb_kill_anchored_urbs(&data->intr_anchor); clear_bit(BTUSB_BULK_RUNNING, &data->flags); usb_kill_anchored_urbs(&data->bulk_anchor); Loading Loading @@ -453,6 +596,9 @@ static int btusb_send_frame(struct sk_buff *skb) break; case HCI_ACLDATA_PKT: if (!data->bulk_tx_ep || hdev->conn_hash.acl_num < 1) return -ENODEV; urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) return -ENOMEM; Loading @@ -467,9 +613,31 @@ static int btusb_send_frame(struct sk_buff *skb) break; case HCI_SCODATA_PKT: if (!data->isoc_tx_ep || hdev->conn_hash.sco_num < 1) return -ENODEV; urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, GFP_ATOMIC); if (!urb) return -ENOMEM; pipe = usb_sndisocpipe(data->udev, data->isoc_tx_ep->bEndpointAddress); urb->dev = data->udev; urb->pipe = pipe; urb->context = skb; urb->complete = btusb_tx_complete; urb->interval = data->isoc_tx_ep->bInterval; urb->transfer_flags = URB_ISO_ASAP; urb->transfer_buffer = skb->data; urb->transfer_buffer_length = skb->len; __fill_isoc_descriptor(urb, skb->len, le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize)); hdev->stat.sco_tx++; kfree_skb(skb); return 0; break; default: return -EILSEQ; Loading Loading @@ -508,22 +676,86 @@ static void btusb_notify(struct hci_dev *hdev, unsigned int evt) schedule_work(&data->work); } static int inline __set_isoc_interface(struct hci_dev *hdev, int altsetting) { struct btusb_data *data = hdev->driver_data; struct usb_interface *intf = data->isoc; struct usb_endpoint_descriptor *ep_desc; int i, err; if (!data->isoc) return -ENODEV; err = usb_set_interface(data->udev, 1, altsetting); if (err < 0) { BT_ERR("%s setting interface failed (%d)", hdev->name, -err); return err; } data->isoc_altsetting = altsetting; data->isoc_tx_ep = NULL; data->isoc_rx_ep = NULL; for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) { ep_desc = &intf->cur_altsetting->endpoint[i].desc; if (!data->isoc_tx_ep && usb_endpoint_is_isoc_out(ep_desc)) { data->isoc_tx_ep = ep_desc; continue; } if (!data->isoc_rx_ep && usb_endpoint_is_isoc_in(ep_desc)) { data->isoc_rx_ep = ep_desc; continue; } } if (!data->isoc_tx_ep || !data->isoc_rx_ep) { BT_ERR("%s invalid SCO descriptors", hdev->name); return -ENODEV; } return 0; } static void btusb_work(struct work_struct *work) { struct btusb_data *data = container_of(work, struct btusb_data, work); struct hci_dev *hdev = data->hdev; if (hdev->conn_hash.acl_num == 0) { if (hdev->conn_hash.acl_num > 0) { if (!test_and_set_bit(BTUSB_BULK_RUNNING, &data->flags)) { if (btusb_submit_bulk_urb(hdev) < 0) clear_bit(BTUSB_BULK_RUNNING, &data->flags); else btusb_submit_bulk_urb(hdev); } } else { clear_bit(BTUSB_BULK_RUNNING, &data->flags); usb_kill_anchored_urbs(&data->bulk_anchor); } if (hdev->conn_hash.sco_num > 0) { if (data->isoc_altsetting != 2) { clear_bit(BTUSB_ISOC_RUNNING, &data->flags); usb_kill_anchored_urbs(&data->isoc_anchor); if (__set_isoc_interface(hdev, 2) < 0) return; } if (!test_and_set_bit(BTUSB_BULK_RUNNING, &data->flags)) { if (btusb_submit_bulk_urb(hdev) < 0) clear_bit(BTUSB_BULK_RUNNING, &data->flags); if (!test_and_set_bit(BTUSB_ISOC_RUNNING, &data->flags)) { if (btusb_submit_isoc_urb(hdev) < 0) clear_bit(BTUSB_ISOC_RUNNING, &data->flags); else btusb_submit_bulk_urb(hdev); btusb_submit_isoc_urb(hdev); } } else { clear_bit(BTUSB_ISOC_RUNNING, &data->flags); usb_kill_anchored_urbs(&data->isoc_anchor); __set_isoc_interface(hdev, 0); } } Loading Loading @@ -597,6 +829,7 @@ static int btusb_probe(struct usb_interface *intf, init_usb_anchor(&data->tx_anchor); init_usb_anchor(&data->intr_anchor); init_usb_anchor(&data->bulk_anchor); init_usb_anchor(&data->isoc_anchor); hdev = hci_alloc_dev(); if (!hdev) { Loading @@ -620,6 +853,9 @@ static int btusb_probe(struct usb_interface *intf, hdev->owner = THIS_MODULE; /* interface numbers are hardcoded in the spec */ data->isoc = usb_ifnum_to_if(data->udev, 1); if (reset || id->driver_info & BTUSB_RESET) set_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks); Loading @@ -628,11 +864,16 @@ static int btusb_probe(struct usb_interface *intf, set_bit(HCI_QUIRK_FIXUP_BUFFER_SIZE, &hdev->quirks); } if (id->driver_info & BTUSB_BROKEN_ISOC) data->isoc = NULL; if (id->driver_info & BTUSB_SNIFFER) { struct usb_device *udev = interface_to_usbdev(intf); struct usb_device *udev = data->udev; if (le16_to_cpu(udev->descriptor.bcdDevice) > 0x997) set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks); data->isoc = NULL; } if (id->driver_info & BTUSB_BCM92035) { Loading @@ -646,6 +887,16 @@ static int btusb_probe(struct usb_interface *intf, } } if (data->isoc) { err = usb_driver_claim_interface(&btusb_driver, data->isoc, NULL); if (err < 0) { hci_free_dev(hdev); kfree(data); return err; } } err = hci_register_dev(hdev); if (err < 0) { hci_free_dev(hdev); Loading @@ -670,6 +921,9 @@ static void btusb_disconnect(struct usb_interface *intf) hdev = data->hdev; if (data->isoc) usb_driver_release_interface(&btusb_driver, data->isoc); usb_set_intfdata(intf, NULL); hci_unregister_dev(hdev); Loading
drivers/bluetooth/hci_ldisc.c +1 −1 Original line number Diff line number Diff line Loading @@ -577,7 +577,7 @@ module_exit(hci_uart_exit); module_param(reset, bool, 0644); MODULE_PARM_DESC(reset, "Send HCI reset command on initialization"); MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>"); MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); MODULE_DESCRIPTION("Bluetooth HCI UART driver ver " VERSION); MODULE_VERSION(VERSION); MODULE_LICENSE("GPL"); Loading