⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 btusb.c

📁 Linux环境下的蓝牙模块驱动程序源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * *  Generic Bluetooth USB driver * *  Copyright (C) 2005-2008  Marcel Holtmann <marcel@holtmann.org> * * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation; either version 2 of the License, or *  (at your option) any later version. * *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. * *  You should have received a copy of the GNU General Public License *  along with this program; if not, write to the Free Software *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA * */#include <linux/kernel.h>#include <linux/module.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/types.h>#include <linux/sched.h>#include <linux/errno.h>#include <linux/skbuff.h>#include <linux/usb.h>#include <net/bluetooth/bluetooth.h>#include <net/bluetooth/hci_core.h>#define VERSION "0.4"static int ignore_dga;static int ignore_csr;static int ignore_sniffer;static int disable_scofix;static int force_scofix;static int reset = 1;static struct usb_driver btusb_driver;#define BTUSB_IGNORE		0x01#define BTUSB_DIGIANSWER	0x02#define BTUSB_CSR		0x04#define BTUSB_SNIFFER		0x08#define BTUSB_BCM92035		0x10#define BTUSB_BROKEN_ISOC	0x20#define BTUSB_WRONG_SCO_MTU	0x40static struct usb_device_id btusb_table[] = {	/* Generic Bluetooth USB device */	{ USB_DEVICE_INFO(0xe0, 0x01, 0x01) },	/* AVM BlueFRITZ! USB v2.0 */	{ USB_DEVICE(0x057c, 0x3800) },	/* Bluetooth Ultraport Module from IBM */	{ USB_DEVICE(0x04bf, 0x030a) },	/* ALPS Modules with non-standard id */	{ USB_DEVICE(0x044e, 0x3001) },	{ USB_DEVICE(0x044e, 0x3002) },	/* Ericsson with non-standard id */	{ USB_DEVICE(0x0bdb, 0x1002) },	/* Canyon CN-BTU1 with HID interfaces */	{ USB_DEVICE(0x0c10, 0x0000) },	{ }	/* Terminating entry */};MODULE_DEVICE_TABLE(usb, btusb_table);static struct usb_device_id blacklist_table[] = {	/* CSR BlueCore devices */	{ USB_DEVICE(0x0a12, 0x0001), .driver_info = BTUSB_CSR },	/* Broadcom BCM2033 without firmware */	{ USB_DEVICE(0x0a5c, 0x2033), .driver_info = BTUSB_IGNORE },	/* Broadcom BCM2035 */	{ USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU },	{ USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU },	{ USB_DEVICE(0x0a5c, 0x2009), .driver_info = BTUSB_BCM92035 },	/* Broadcom BCM2045 */	{ USB_DEVICE(0x0a5c, 0x2039), .driver_info = BTUSB_WRONG_SCO_MTU },	{ USB_DEVICE(0x0a5c, 0x2101), .driver_info = BTUSB_WRONG_SCO_MTU },	/* IBM/Lenovo ThinkPad with Broadcom chip */	{ USB_DEVICE(0x0a5c, 0x201e), .driver_info = BTUSB_WRONG_SCO_MTU },	{ USB_DEVICE(0x0a5c, 0x2110), .driver_info = BTUSB_WRONG_SCO_MTU },	/* HP laptop with Broadcom chip */	{ USB_DEVICE(0x03f0, 0x171d), .driver_info = BTUSB_WRONG_SCO_MTU },	/* Dell laptop with Broadcom chip */	{ USB_DEVICE(0x413c, 0x8126), .driver_info = BTUSB_WRONG_SCO_MTU },	/* Dell Wireless 370 and 410 devices */	{ USB_DEVICE(0x413c, 0x8152), .driver_info = BTUSB_WRONG_SCO_MTU },	{ USB_DEVICE(0x413c, 0x8156), .driver_info = BTUSB_WRONG_SCO_MTU },	/* Belkin F8T012 and F8T013 devices */	{ USB_DEVICE(0x050d, 0x0012), .driver_info = BTUSB_WRONG_SCO_MTU },	{ USB_DEVICE(0x050d, 0x0013), .driver_info = BTUSB_WRONG_SCO_MTU },	/* Asus WL-BTD202 device */	{ USB_DEVICE(0x0b05, 0x1715), .driver_info = BTUSB_WRONG_SCO_MTU },	/* Kensington Bluetooth USB adapter */	{ USB_DEVICE(0x047d, 0x105e), .driver_info = BTUSB_WRONG_SCO_MTU },	/* RTX Telecom based adapters with buggy SCO support */	{ USB_DEVICE(0x0400, 0x0807), .driver_info = BTUSB_BROKEN_ISOC },	{ USB_DEVICE(0x0400, 0x080a), .driver_info = BTUSB_BROKEN_ISOC },	/* CONWISE Technology based adapters with buggy SCO support */	{ USB_DEVICE(0x0e5e, 0x6622), .driver_info = BTUSB_BROKEN_ISOC },	/* Digianswer devices */	{ USB_DEVICE(0x08fd, 0x0001), .driver_info = BTUSB_DIGIANSWER },	{ USB_DEVICE(0x08fd, 0x0002), .driver_info = BTUSB_IGNORE },	/* CSR BlueCore Bluetooth Sniffer */	{ USB_DEVICE(0x0a12, 0x0002), .driver_info = BTUSB_SNIFFER },	/* Frontline ComProbe Bluetooth Sniffer */	{ USB_DEVICE(0x16d3, 0x0002), .driver_info = BTUSB_SNIFFER },	{ }	/* Terminating entry */};#define BTUSB_MAX_ISOC_FRAMES	10#define BTUSB_INTR_RUNNING	0#define BTUSB_BULK_RUNNING	1#define BTUSB_ISOC_RUNNING	2struct btusb_data {	struct hci_dev       *hdev;	struct usb_device    *udev;	struct usb_interface *intf;	struct usb_interface *isoc;	spinlock_t lock;	unsigned long flags;	struct work_struct work;	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;	__u8 cmdreq_type;	int isoc_altsetting;	int suspend_count;};static void btusb_intr_complete(struct urb *urb){	struct hci_dev *hdev = urb->context;	struct btusb_data *data = hdev->driver_data;	int 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) {		hdev->stat.byte_rx += urb->actual_length;		if (hci_recv_fragment(hdev, HCI_EVENT_PKT,						urb->transfer_buffer,						urb->actual_length) < 0) {			BT_ERR("%s corrupted event packet", hdev->name);			hdev->stat.err_rx++;		}	}	if (!test_bit(BTUSB_INTR_RUNNING, &data->flags))		return;	usb_anchor_urb(urb, &data->intr_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 int btusb_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags){	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->intr_ep)		return -ENODEV;	urb = usb_alloc_urb(0, mem_flags);	if (!urb)		return -ENOMEM;	size = le16_to_cpu(data->intr_ep->wMaxPacketSize);	buf = kmalloc(size, mem_flags);	if (!buf) {		usb_free_urb(urb);		return -ENOMEM;	}	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);	urb->transfer_flags |= URB_FREE_BUFFER;	usb_anchor_urb(urb, &data->intr_anchor);	err = usb_submit_urb(urb, mem_flags);	if (err < 0) {		BT_ERR("%s urb %p submission failed (%d)",						hdev->name, urb, -err);		usb_unanchor_urb(urb);	}	usb_free_urb(urb);	return err;}static void btusb_bulk_complete(struct urb *urb){	struct hci_dev *hdev = urb->context;	struct btusb_data *data = hdev->driver_data;	int 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) {		hdev->stat.byte_rx += urb->actual_length;		if (hci_recv_fragment(hdev, HCI_ACLDATA_PKT,						urb->transfer_buffer,						urb->actual_length) < 0) {			BT_ERR("%s corrupted ACL packet", hdev->name);			hdev->stat.err_rx++;		}	}	if (!test_bit(BTUSB_BULK_RUNNING, &data->flags))		return;	usb_anchor_urb(urb, &data->bulk_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 int btusb_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags){	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->bulk_rx_ep)		return -ENODEV;	urb = usb_alloc_urb(0, mem_flags);	if (!urb)		return -ENOMEM;	size = le16_to_cpu(data->bulk_rx_ep->wMaxPacketSize);	buf = kmalloc(size, mem_flags);	if (!buf) {		usb_free_urb(urb);		return -ENOMEM;	}	pipe = usb_rcvbulkpipe(data->udev, data->bulk_rx_ep->bEndpointAddress);	usb_fill_bulk_urb(urb, data->udev, pipe,					buf, size, btusb_bulk_complete, hdev);	urb->transfer_flags |= URB_FREE_BUFFER;	usb_anchor_urb(urb, &data->bulk_anchor);	err = usb_submit_urb(urb, mem_flags);	if (err < 0) {		BT_ERR("%s urb %p submission failed (%d)",						hdev->name, urb, -err);		usb_unanchor_urb(urb);	}	usb_free_urb(urb);	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, gfp_t mem_flags){	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, mem_flags);	if (!urb)		return -ENOMEM;	size = le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize) *						BTUSB_MAX_ISOC_FRAMES;	buf = kmalloc(size, mem_flags);	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, mem_flags);	if (err < 0) {		BT_ERR("%s urb %p submission failed (%d)",						hdev->name, urb, -err);		usb_unanchor_urb(urb);	}	usb_free_urb(urb);	return err;}static void btusb_tx_complete(struct urb *urb){	struct sk_buff *skb = urb->context;	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);	if (!test_bit(HCI_RUNNING, &hdev->flags))		goto done;	if (!urb->status)		hdev->stat.byte_tx += urb->transfer_buffer_length;	else		hdev->stat.err_tx++;done:	kfree(urb->setup_packet);	kfree_skb(skb);}static int btusb_open(struct hci_dev *hdev){	struct btusb_data *data = hdev->driver_data;	int err;	BT_DBG("%s", hdev->name);	if (test_and_set_bit(HCI_RUNNING, &hdev->flags))		return 0;	if (test_and_set_bit(BTUSB_INTR_RUNNING, &data->flags))		return 0;	err = btusb_submit_intr_urb(hdev, GFP_KERNEL);	if (err < 0) {		clear_bit(BTUSB_INTR_RUNNING, &data->flags);		clear_bit(HCI_RUNNING, &hdev->flags);	}	return err;}static int btusb_close(struct hci_dev *hdev){	struct btusb_data *data = hdev->driver_data;	BT_DBG("%s", hdev->name);	if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))		return 0;	cancel_work_sync(&data->work);	clear_bit(BTUSB_ISOC_RUNNING, &data->flags);	usb_kill_anchored_urbs(&data->isoc_anchor);	clear_bit(BTUSB_BULK_RUNNING, &data->flags);	usb_kill_anchored_urbs(&data->bulk_anchor);	clear_bit(BTUSB_INTR_RUNNING, &data->flags);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -