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

📄 hci_usb.c

📁 Linux下蓝牙驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
/*    BlueZ - Bluetooth protocol stack for Linux   Copyright (C) 2000-2001 Qualcomm Incorporated   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>   This program is free software; you can redistribute it and/or modify   it under the terms of the GNU General Public License version 2 as   published by the Free Software Foundation;   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,    COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS    SOFTWARE IS DISCLAIMED.*//* * BlueZ HCI USB driver. * Based on original USB Bluetooth driver for Linux kernel *    Copyright (c) 2000 Greg Kroah-Hartman        <greg@kroah.com> *    Copyright (c) 2000 Mark Douglas Corner       <mcorner@umich.edu> * * $Id: hci_usb.c,v 1.8 2002/07/18 17:23:09 maxk Exp $     */#define VERSION "2.1"#include <linux/config.h>#include <linux/module.h>#define __KERNEL_SYSCALLS__#include <linux/version.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/sched.h>#include <linux/unistd.h>#include <linux/types.h>#include <linux/interrupt.h>#include <linux/slab.h>#include <linux/errno.h>#include <linux/string.h>#include <linux/skbuff.h>#include <linux/kmod.h>#include <linux/usb.h>#include <net/bluetooth/bluetooth.h>#include <net/bluetooth/hci_core.h>#include "hci_usb.h"#define HCI_MAX_PENDING (HCI_MAX_BULK_RX + HCI_MAX_BULK_TX + 1)#ifndef HCI_USB_DEBUG#undef  BT_DBG#define BT_DBG( A... )#undef  BT_DMP#define BT_DMP( A... )#endif#ifndef CONFIG_BLUEZ_USB_ZERO_PACKET#undef  USB_ZERO_PACKET#define USB_ZERO_PACKET 0#endifstatic struct usb_driver hci_usb_driver; static struct usb_device_id bluetooth_ids[] = {	/* Generic Bluetooth USB device */	{ USB_DEVICE_INFO(HCI_DEV_CLASS, HCI_DEV_SUBCLASS, HCI_DEV_PROTOCOL) },	/* Ericsson with non-standard id */	{ USB_DEVICE(0x0bdb, 0x1002) },	{ }	/* Terminating entry */};MODULE_DEVICE_TABLE (usb, bluetooth_ids);static struct usb_device_id ignore_ids[] = {	/* Broadcom BCM2033 without firmware */	{ USB_DEVICE(0x0a5c, 0x2033) },	{ }	/* Terminating entry */};static void hci_usb_interrupt(struct urb *urb);static void hci_usb_rx_complete(struct urb *urb);static void hci_usb_tx_complete(struct urb *urb);static struct urb *hci_usb_get_completed(struct hci_usb *husb){	struct sk_buff *skb;	struct urb *urb = NULL;	skb = skb_dequeue(&husb->completed_q);	if (skb) {		urb = ((struct hci_usb_scb *) skb->cb)->urb;		kfree_skb(skb);	}	BT_DBG("%s urb %p", husb->hdev.name, urb);	return urb;}static int hci_usb_enable_intr(struct hci_usb *husb){	struct urb *urb;	int pipe, size;	void *buf;	BT_DBG("%s", husb->hdev.name); 	if (!(urb = usb_alloc_urb(0)))		return -ENOMEM;	if (!(buf = kmalloc(HCI_MAX_EVENT_SIZE, GFP_KERNEL))) {		usb_free_urb(urb);		return -ENOMEM;	}	husb->intr_urb = urb;	        pipe = usb_rcvintpipe(husb->udev, husb->intr_ep);        size = usb_maxpacket(husb->udev, pipe, usb_pipeout(pipe));	FILL_INT_URB(urb, husb->udev, pipe, buf, size, 			hci_usb_interrupt, husb, husb->intr_interval);		return usb_submit_urb(urb);}static int hci_usb_disable_intr(struct hci_usb *husb){	struct urb *urb = husb->intr_urb;	struct sk_buff *skb;	BT_DBG("%s", husb->hdev.name);	usb_unlink_urb(urb); usb_free_urb(urb);	husb->intr_urb = NULL;	skb = husb->intr_skb;	if (skb) {		husb->intr_skb = NULL;		kfree_skb(skb);	}	return 0;}static int hci_usb_rx_submit(struct hci_usb *husb, struct urb *urb){	struct hci_usb_scb *scb;	struct sk_buff *skb;	int    pipe, size, err;	if (!urb && !(urb = usb_alloc_urb(0)))		return -ENOMEM;        size = HCI_MAX_FRAME_SIZE;	if (!(skb = bluez_skb_alloc(size, GFP_ATOMIC))) {		usb_free_urb(urb);		return -ENOMEM;	}		BT_DBG("%s urb %p", husb->hdev.name, urb);	skb->dev = (void *) &husb->hdev;	skb->pkt_type = HCI_ACLDATA_PKT;	scb = (struct hci_usb_scb *) skb->cb;	scb->urb = urb;        pipe = usb_rcvbulkpipe(husb->udev, husb->bulk_in_ep);        FILL_BULK_URB(urb, husb->udev, pipe, skb->data, size, hci_usb_rx_complete, skb);        urb->transfer_flags = USB_QUEUE_BULK;	skb_queue_tail(&husb->pending_q, skb);	err = usb_submit_urb(urb);	if (err) {		BT_ERR("%s bulk rx submit failed urb %p err %d",				husb->hdev.name, urb, err);		skb_unlink(skb);		usb_free_urb(urb);	}	return err;}/* Initialize device */static int hci_usb_open(struct hci_dev *hdev){	struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;	int i, err;	unsigned long flags;	BT_DBG("%s", hdev->name);	if (test_and_set_bit(HCI_RUNNING, &hdev->flags))		return 0;	MOD_INC_USE_COUNT;	write_lock_irqsave(&husb->completion_lock, flags);	err = hci_usb_enable_intr(husb);	if (!err) {		for (i = 0; i < HCI_MAX_BULK_TX; i++)			hci_usb_rx_submit(husb, NULL);	} else {		clear_bit(HCI_RUNNING, &hdev->flags);		MOD_DEC_USE_COUNT;	}	write_unlock_irqrestore(&husb->completion_lock, flags);	return err;}/* Reset device */static int hci_usb_flush(struct hci_dev *hdev){	struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;	BT_DBG("%s", hdev->name);	skb_queue_purge(&husb->cmd_q);	skb_queue_purge(&husb->acl_q);	return 0;}static inline void hci_usb_unlink_urbs(struct hci_usb *husb){	struct sk_buff *skb;	struct urb *urb;	BT_DBG("%s", husb->hdev.name);	while ((skb = skb_dequeue(&husb->pending_q))) {		urb = ((struct hci_usb_scb *) skb->cb)->urb;		usb_unlink_urb(urb);		kfree_skb(skb);	}	while ((urb = hci_usb_get_completed(husb)))		usb_free_urb(urb);}/* Close device */static int hci_usb_close(struct hci_dev *hdev){	struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;	unsigned long flags;		if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))		return 0;	BT_DBG("%s", hdev->name);	write_lock_irqsave(&husb->completion_lock, flags);		hci_usb_disable_intr(husb);	hci_usb_unlink_urbs(husb);	hci_usb_flush(hdev);	write_unlock_irqrestore(&husb->completion_lock, flags);	MOD_DEC_USE_COUNT;	return 0;}static inline int hci_usb_send_ctrl(struct hci_usb *husb, struct sk_buff *skb){	struct hci_usb_scb *scb = (void *) skb->cb;	struct urb *urb = hci_usb_get_completed(husb);	struct usb_ctrlrequest *dr;	int pipe, err;	if (!urb && !(urb = usb_alloc_urb(0)))		return -ENOMEM;	if (!(dr = kmalloc(sizeof(*dr), GFP_ATOMIC))) {		usb_free_urb(urb);		return -ENOMEM;	}		pipe = usb_sndctrlpipe(husb->udev, 0);	dr->bRequestType = HCI_CTRL_REQ;	dr->bRequest = 0;	dr->wIndex   = 0;	dr->wValue   = 0;	dr->wLength  = __cpu_to_le16(skb->len);	FILL_CONTROL_URB(urb, husb->udev, pipe, (void *) dr,			skb->data, skb->len, hci_usb_tx_complete, skb);	BT_DBG("%s urb %p len %d", husb->hdev.name, urb, skb->len);	scb->urb = urb;	skb_queue_tail(&husb->pending_q, skb);	err = usb_submit_urb(urb);	if (err) {		BT_ERR("%s ctrl tx submit failed urb %p err %d", 				husb->hdev.name, urb, err);		skb_unlink(skb);		usb_free_urb(urb); kfree(dr);	}	return err;}static inline int hci_usb_send_bulk(struct hci_usb *husb, struct sk_buff *skb){	struct hci_usb_scb *scb = (void *) skb->cb;	struct urb *urb = hci_usb_get_completed(husb);	int pipe, err;	if (!urb && !(urb = usb_alloc_urb(0)))		return -ENOMEM;	pipe = usb_sndbulkpipe(husb->udev, husb->bulk_out_ep);        	FILL_BULK_URB(urb, husb->udev, pipe, skb->data, skb->len,	              hci_usb_tx_complete, skb);	urb->transfer_flags = USB_QUEUE_BULK | USB_ZERO_PACKET;	BT_DBG("%s urb %p len %d", husb->hdev.name, urb, skb->len);	scb->urb = urb;	skb_queue_tail(&husb->pending_q, skb);	err = usb_submit_urb(urb);	if (err) {		BT_ERR("%s bulk tx submit failed urb %p err %d", 				husb->hdev.name, urb, err);		skb_unlink(skb);		usb_free_urb(urb);	}	return err;}static void hci_usb_tx_process(struct hci_usb *husb){	struct sk_buff *skb;	BT_DBG("%s", husb->hdev.name);	do {		clear_bit(HCI_USB_TX_WAKEUP, &husb->state);				/* Process ACL queue */		while (skb_queue_len(&husb->pending_q) < HCI_MAX_PENDING &&				(skb = skb_dequeue(&husb->acl_q))) {			if (hci_usb_send_bulk(husb, skb) < 0) {				skb_queue_head(&husb->acl_q, skb);				break;			}		}		/* Process command queue */		if (!test_bit(HCI_USB_CTRL_TX, &husb->state) &&			(skb = skb_dequeue(&husb->cmd_q)) != NULL) {			set_bit(HCI_USB_CTRL_TX, &husb->state);			if (hci_usb_send_ctrl(husb, skb) < 0) {				skb_queue_head(&husb->cmd_q, skb);				clear_bit(HCI_USB_CTRL_TX, &husb->state);			}		}	} while(test_bit(HCI_USB_TX_WAKEUP, &husb->state));}static inline void hci_usb_tx_wakeup(struct hci_usb *husb){	/* Serialize TX queue processing to avoid data reordering */	if (!test_and_set_bit(HCI_USB_TX_PROCESS, &husb->state)) {		hci_usb_tx_process(husb);		clear_bit(HCI_USB_TX_PROCESS, &husb->state);	} else		set_bit(HCI_USB_TX_WAKEUP, &husb->state);}/* Send frames from HCI layer */int hci_usb_send_frame(struct sk_buff *skb){	struct hci_dev *hdev = (struct hci_dev *) skb->dev;	struct hci_usb *husb;	if (!hdev) {		BT_ERR("frame for uknown device (hdev=NULL)");		return -ENODEV;	}	if (!test_bit(HCI_RUNNING, &hdev->flags))

⌨️ 快捷键说明

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