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

📄 hci_usb.c

📁 嵌入式Linux的蓝牙模块驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
	urb->transfer_buffer = skb->data;	urb->transfer_buffer_length = skb->len;	__fill_isoc_desc(urb, skb->len, husb->isoc_out_ep->desc.wMaxPacketSize);	_urb->priv = skb;	return __tx_submit(husb, _urb);}#endifstatic void hci_usb_tx_process(struct hci_usb *husb){	struct sk_buff_head *q;	struct sk_buff *skb;	BT_DBG("%s", husb->hdev->name);	do {		clear_bit(HCI_USB_TX_WAKEUP, &husb->state);		/* Process command queue */		q = __transmit_q(husb, HCI_COMMAND_PKT);		if (!atomic_read(__pending_tx(husb, HCI_COMMAND_PKT)) &&				(skb = skb_dequeue(q))) {			if (hci_usb_send_ctrl(husb, skb) < 0)				skb_queue_head(q, skb);		}#ifdef CONFIG_BT_HCIUSB_SCO		/* Process SCO queue */		q = __transmit_q(husb, HCI_SCODATA_PKT);		if (atomic_read(__pending_tx(husb, HCI_SCODATA_PKT)) < HCI_MAX_ISOC_TX &&				(skb = skb_dequeue(q))) {			if (hci_usb_send_isoc(husb, skb) < 0)				skb_queue_head(q, skb);		}#endif		/* Process ACL queue */		q = __transmit_q(husb, HCI_ACLDATA_PKT);		while (atomic_read(__pending_tx(husb, HCI_ACLDATA_PKT)) < HCI_MAX_BULK_TX &&				(skb = skb_dequeue(q))) {			if (hci_usb_send_bulk(husb, skb) < 0) {				skb_queue_head(q, skb);				break;			}		}	} 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 */static 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))		return -EBUSY;	BT_DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);	husb = (struct hci_usb *) hdev->driver_data;	switch (skb->pkt_type) {	case HCI_COMMAND_PKT:		hdev->stat.cmd_tx++;		break;	case HCI_ACLDATA_PKT:		hdev->stat.acl_tx++;		break;#ifdef CONFIG_BT_HCIUSB_SCO	case HCI_SCODATA_PKT:		hdev->stat.sco_tx++;		break;#endif	default:		kfree_skb(skb);		return 0;	}	read_lock(&husb->completion_lock);	skb_queue_tail(__transmit_q(husb, skb->pkt_type), skb);	hci_usb_tx_wakeup(husb);	read_unlock(&husb->completion_lock);	return 0;}static inline int __recv_frame(struct hci_usb *husb, int type, void *data, int count){	BT_DBG("%s type %d data %p count %d", husb->hdev->name, type, data, count);	husb->hdev->stat.byte_rx += count;	while (count) {		struct sk_buff *skb = __reassembly(husb, type);		struct { int expect; } *scb;		int len = 0;			if (!skb) {			/* Start of the frame */			switch (type) {			case HCI_EVENT_PKT:				if (count >= HCI_EVENT_HDR_SIZE) {					struct hci_event_hdr *h = data;					len = HCI_EVENT_HDR_SIZE + h->plen;				} else					return -EILSEQ;				break;			case HCI_ACLDATA_PKT:				if (count >= HCI_ACL_HDR_SIZE) {					struct hci_acl_hdr *h = data;					len = HCI_ACL_HDR_SIZE + __le16_to_cpu(h->dlen);				} else					return -EILSEQ;				break;#ifdef CONFIG_BT_HCIUSB_SCO			case HCI_SCODATA_PKT:				if (count >= HCI_SCO_HDR_SIZE) {					struct hci_sco_hdr *h = data;					len = HCI_SCO_HDR_SIZE + h->dlen;				} else					return -EILSEQ;				break;#endif			}			BT_DBG("new packet len %d", len);			skb = bt_skb_alloc(len, GFP_ATOMIC);			if (!skb) {				BT_ERR("%s no memory for the packet", husb->hdev->name);				return -ENOMEM;			}			skb->dev = (void *) husb->hdev;			skb->pkt_type = type;				__reassembly(husb, type) = skb;			scb = (void *) skb->cb;			scb->expect = len;		} else {			/* Continuation */			scb = (void *) skb->cb;			len = scb->expect;		}		len = min(len, count);				memcpy(skb_put(skb, len), data, len);		scb->expect -= len;		if (!scb->expect) {			/* Complete frame */			__reassembly(husb, type) = NULL;			hci_recv_frame(skb);		}		count -= len; data += len;	}	return 0;}static void hci_usb_rx_complete(struct urb *urb, struct pt_regs *regs){	struct _urb *_urb = container_of(urb, struct _urb, urb);	struct hci_usb *husb = (void *) urb->context;	struct hci_dev *hdev = husb->hdev;	int err, count = urb->actual_length;	BT_DBG("%s urb %p type %d status %d count %d flags %x", hdev->name, urb,			_urb->type, urb->status, count, urb->transfer_flags);	read_lock(&husb->completion_lock);	if (!test_bit(HCI_RUNNING, &hdev->flags))		goto unlock;	if (urb->status || !count)		goto resubmit;	if (_urb->type == HCI_SCODATA_PKT) {#ifdef CONFIG_BT_HCIUSB_SCO		int i;		for (i=0; i < urb->number_of_packets; i++) {			BT_DBG("desc %d status %d offset %d len %d", i,					urb->iso_frame_desc[i].status,					urb->iso_frame_desc[i].offset,					urb->iso_frame_desc[i].actual_length);				if (!urb->iso_frame_desc[i].status)				__recv_frame(husb, _urb->type, 					urb->transfer_buffer + urb->iso_frame_desc[i].offset,					urb->iso_frame_desc[i].actual_length);		}#else		;#endif	} else {		err = __recv_frame(husb, _urb->type, urb->transfer_buffer, count);		if (err < 0) { 			BT_ERR("%s corrupted packet: type %d count %d",					husb->hdev->name, _urb->type, count);			hdev->stat.err_rx++;		}	}resubmit:	urb->dev = husb->udev;	err = usb_submit_urb(urb, GFP_ATOMIC);	BT_DBG("%s urb %p type %d resubmit status %d", hdev->name, urb,			_urb->type, err);unlock:	read_unlock(&husb->completion_lock);}static void hci_usb_tx_complete(struct urb *urb, struct pt_regs *regs){	struct _urb *_urb = container_of(urb, struct _urb, urb);	struct hci_usb *husb = (void *) urb->context;	struct hci_dev *hdev = husb->hdev;	BT_DBG("%s urb %p status %d flags %x", hdev->name, urb,			urb->status, urb->transfer_flags);	atomic_dec(__pending_tx(husb, _urb->type));	urb->transfer_buffer = NULL;	kfree_skb((struct sk_buff *) _urb->priv);	if (!test_bit(HCI_RUNNING, &hdev->flags))		return;	if (!urb->status)		hdev->stat.byte_tx += urb->transfer_buffer_length;	else		hdev->stat.err_tx++;	read_lock(&husb->completion_lock);	_urb_unlink(_urb);	_urb_queue_tail(__completed_q(husb, _urb->type), _urb);	hci_usb_tx_wakeup(husb);	read_unlock(&husb->completion_lock);}static void hci_usb_destruct(struct hci_dev *hdev){	struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;	BT_DBG("%s", hdev->name);	kfree(husb);}int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id){	struct usb_device *udev = interface_to_usbdev(intf);	struct usb_host_endpoint *bulk_out_ep = NULL;	struct usb_host_endpoint *bulk_in_ep = NULL;	struct usb_host_endpoint *intr_in_ep = NULL;	struct usb_host_endpoint  *ep;	struct usb_host_interface *uif;	struct usb_interface *isoc_iface;	struct hci_usb *husb;	struct hci_dev *hdev;	int i, e, size, isoc_ifnum, isoc_alts;	BT_DBG("udev %p intf %p", udev, intf);	if (!id->driver_info) {		const struct usb_device_id *match;		match = usb_match_id(intf, blacklist_ids);		if (match)			id = match;	}	if (id->driver_info & HCI_IGNORE)		return -ENODEV;	if (intf->cur_altsetting->desc.bInterfaceNumber > 0)		return -ENODEV;	/* Find endpoints that we need */	uif = intf->cur_altsetting;	for (e = 0; e < uif->desc.bNumEndpoints; e++) {		ep = &uif->endpoint[e];		switch (ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {		case USB_ENDPOINT_XFER_INT:			if (ep->desc.bEndpointAddress & USB_DIR_IN)				intr_in_ep = ep;			break;		case USB_ENDPOINT_XFER_BULK:			if (ep->desc.bEndpointAddress & USB_DIR_IN)				bulk_in_ep  = ep;			else				bulk_out_ep = ep;			break;		}	}	if (!bulk_in_ep || !bulk_out_ep || !intr_in_ep) {		BT_DBG("Bulk endpoints not found");		goto done;	}	if (!(husb = kmalloc(sizeof(struct hci_usb), GFP_KERNEL))) {		BT_ERR("Can't allocate: control structure");		goto done;	}	memset(husb, 0, sizeof(struct hci_usb));	husb->udev = udev;	husb->bulk_out_ep = bulk_out_ep;	husb->bulk_in_ep  = bulk_in_ep;	husb->intr_in_ep  = intr_in_ep;	if (id->driver_info & HCI_DIGIANSWER)		husb->ctrl_req = HCI_DIGI_REQ;	else		husb->ctrl_req = HCI_CTRL_REQ;	/* Find isochronous endpoints that we can use */	size = 0; 	isoc_iface = NULL;	isoc_alts  = 0;	isoc_ifnum = 1;#ifdef CONFIG_BT_HCIUSB_SCO	if (!(id->driver_info & HCI_BROKEN_ISOC))		isoc_iface = usb_ifnum_to_if(udev, isoc_ifnum);	if (isoc_iface) {		int a;		struct usb_host_endpoint *isoc_out_ep = NULL;		struct usb_host_endpoint *isoc_in_ep = NULL;		for (a = 0; a < isoc_iface->num_altsetting; a++) {			uif = &isoc_iface->altsetting[a];			for (e = 0; e < uif->desc.bNumEndpoints; e++) {				ep = &uif->endpoint[e];				switch (ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {				case USB_ENDPOINT_XFER_ISOC:					if (ep->desc.wMaxPacketSize < size ||							uif->desc.bAlternateSetting > 2)						break;					size = ep->desc.wMaxPacketSize;					isoc_alts = uif->desc.bAlternateSetting;					if (ep->desc.bEndpointAddress & USB_DIR_IN)						isoc_in_ep  = ep;					else						isoc_out_ep = ep;					break;				}			}		}		if (!isoc_in_ep || !isoc_out_ep)			BT_DBG("Isoc endpoints not found");		else {			BT_DBG("isoc ifnum %d alts %d", isoc_ifnum, isoc_alts);			if (usb_driver_claim_interface(&hci_usb_driver, isoc_iface, husb) != 0)				BT_ERR("Can't claim isoc interface");			else if (usb_set_interface(udev, isoc_ifnum, isoc_alts)) {				BT_ERR("Can't set isoc interface settings");				usb_driver_release_interface(&hci_usb_driver, isoc_iface);			} else {				husb->isoc_iface  = isoc_iface;				husb->isoc_in_ep  = isoc_in_ep;				husb->isoc_out_ep = isoc_out_ep;			}		}	}#endif	husb->completion_lock = RW_LOCK_UNLOCKED;	for (i = 0; i < 4; i++) {		skb_queue_head_init(&husb->transmit_q[i]);		_urb_queue_init(&husb->pending_q[i]);		_urb_queue_init(&husb->completed_q[i]);	}	/* Initialize and register HCI device */	hdev = hci_alloc_dev();	if (!hdev) {		BT_ERR("Can't allocate HCI device");		goto probe_error;	}	husb->hdev = hdev;	hdev->type = HCI_USB;	hdev->driver_data = husb;	SET_HCIDEV_DEV(hdev, &intf->dev);	hdev->open     = hci_usb_open;	hdev->close    = hci_usb_close;	hdev->flush    = hci_usb_flush;	hdev->send     = hci_usb_send_frame;	hdev->destruct = hci_usb_destruct;	hdev->owner = THIS_MODULE;	if (id->driver_info & HCI_RESET)		set_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks);	if (hci_register_dev(hdev) < 0) {		BT_ERR("Can't register HCI device");		hci_free_dev(hdev);		goto probe_error;	}	usb_set_intfdata(intf, husb);	return 0;probe_error:	if (husb->isoc_iface)		usb_driver_release_interface(&hci_usb_driver, husb->isoc_iface);	kfree(husb);done:	return -EIO;}static void hci_usb_disconnect(struct usb_interface *intf){	struct hci_usb *husb = usb_get_intfdata(intf);	struct hci_dev *hdev;	if (!husb || intf == husb->isoc_iface)		return;	usb_set_intfdata(intf, NULL);	hdev = husb->hdev;	BT_DBG("%s", hdev->name);	hci_usb_close(hdev);	if (husb->isoc_iface)		usb_driver_release_interface(&hci_usb_driver, husb->isoc_iface);	if (hci_unregister_dev(hdev) < 0)		BT_ERR("Can't unregister HCI device %s", hdev->name);	hci_free_dev(hdev);}static struct usb_driver hci_usb_driver = {	.owner		= THIS_MODULE,	.name		= "hci_usb",	.probe		= hci_usb_probe,	.disconnect	= hci_usb_disconnect,	.id_table	= bluetooth_ids,};static int __init hci_usb_init(void){	int err;	BT_INFO("HCI USB driver ver %s", VERSION);	if ((err = usb_register(&hci_usb_driver)) < 0)		BT_ERR("Failed to register HCI USB driver");	return err;}static void __exit hci_usb_exit(void){	usb_deregister(&hci_usb_driver);}module_init(hci_usb_init);module_exit(hci_usb_exit);MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");MODULE_DESCRIPTION("Bluetooth HCI USB driver ver " VERSION);MODULE_VERSION(VERSION);MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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