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

📄 hci_usb.c

📁 Linux下蓝牙驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
		return -EBUSY;	husb = (struct hci_usb *) hdev->driver_data;	BT_DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);	read_lock(&husb->completion_lock);	switch (skb->pkt_type) {	case HCI_COMMAND_PKT:		skb_queue_tail(&husb->cmd_q, skb);		hdev->stat.cmd_tx++;		break;	case HCI_ACLDATA_PKT:		skb_queue_tail(&husb->acl_q, skb);		hdev->stat.acl_tx++;		break;	case HCI_SCODATA_PKT:	default:		kfree_skb(skb);		break;	}	hci_usb_tx_wakeup(husb);	read_unlock(&husb->completion_lock);	return 0;}static void hci_usb_interrupt(struct urb *urb){	struct hci_usb *husb = (void *) urb->context;	struct hci_usb_scb *scb;	struct sk_buff *skb;	hci_event_hdr *eh;	__u8 *data = urb->transfer_buffer;	int count = urb->actual_length;	int len = HCI_EVENT_HDR_SIZE;	BT_DBG("%s urb %p count %d", husb->hdev.name, urb, count);	if (!test_bit(HCI_RUNNING, &husb->hdev.flags))		return;	if (urb->status || !count) {		BT_DBG("%s intr status %d, count %d", 				husb->hdev.name, urb->status, count);		return;	}	read_lock(&husb->completion_lock);		husb->hdev.stat.byte_rx += count;	if (!(skb = husb->intr_skb)) {		/* Start of the frame */		if (count < HCI_EVENT_HDR_SIZE)			goto bad_len;		eh  = (hci_event_hdr *) data;		len = eh->plen + HCI_EVENT_HDR_SIZE;		if (count > len)			goto bad_len;		skb = bluez_skb_alloc(len, GFP_ATOMIC);		if (!skb) {			BT_ERR("%s no memory for event packet", husb->hdev.name);			goto done;		}		scb = (void *) skb->cb;		skb->dev = (void *) &husb->hdev;		skb->pkt_type = HCI_EVENT_PKT;		husb->intr_skb = skb;		scb->intr_len  = len;	} else {		/* Continuation */		scb = (void *) skb->cb;		len = scb->intr_len;		if (count > len) {			husb->intr_skb = NULL;			kfree_skb(skb);			goto bad_len;		}	}	memcpy(skb_put(skb, count), data, count);	scb->intr_len -= count;	if (!scb->intr_len) {		/* Complete frame */		husb->intr_skb = NULL;		hci_recv_frame(skb);	}done:	read_unlock(&husb->completion_lock);	return;bad_len:	BT_ERR("%s bad frame len %d expected %d", husb->hdev.name, count, len);	husb->hdev.stat.err_rx++;	read_unlock(&husb->completion_lock);}static void hci_usb_tx_complete(struct urb *urb){	struct sk_buff *skb  = (struct sk_buff *) urb->context;	struct hci_dev *hdev = (struct hci_dev *) skb->dev;	struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;	BT_DBG("%s urb %p status %d flags %x", husb->hdev.name, urb,			urb->status, urb->transfer_flags);	if (urb->pipe == usb_sndctrlpipe(husb->udev, 0)) {		kfree(urb->setup_packet);		clear_bit(HCI_USB_CTRL_TX, &husb->state);	}	if (!test_bit(HCI_RUNNING, &hdev->flags))		return;	read_lock(&husb->completion_lock);		if (!urb->status)		husb->hdev.stat.byte_tx += skb->len;	else		husb->hdev.stat.err_tx++;	skb_unlink(skb);	skb_queue_tail(&husb->completed_q, skb);	hci_usb_tx_wakeup(husb);		read_unlock(&husb->completion_lock);	return;}static void hci_usb_rx_complete(struct urb *urb){	struct sk_buff *skb  = (struct sk_buff *) urb->context;	struct hci_dev *hdev = (struct hci_dev *) skb->dev;	struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;	int status, count = urb->actual_length;	hci_acl_hdr *ah;	int dlen, size;	BT_DBG("%s urb %p status %d count %d flags %x", husb->hdev.name, urb,			urb->status, count, urb->transfer_flags);	if (!test_bit(HCI_RUNNING, &hdev->flags))		return;	read_lock(&husb->completion_lock);	if (urb->status || !count)		goto resubmit;	husb->hdev.stat.byte_rx += count;	ah   = (hci_acl_hdr *) skb->data;	dlen = __le16_to_cpu(ah->dlen);	size = HCI_ACL_HDR_SIZE + dlen;	/* Verify frame len and completeness */	if (count != size) {		BT_ERR("%s corrupted ACL packet: count %d, dlen %d",				husb->hdev.name, count, dlen);		bluez_dump("hci_usb", skb->data, count);		husb->hdev.stat.err_rx++;		goto resubmit;	}	skb_unlink(skb);	skb_put(skb, count);	hci_recv_frame(skb);	hci_usb_rx_submit(husb, urb);	read_unlock(&husb->completion_lock);	return;		resubmit:	urb->dev = husb->udev;	status   = usb_submit_urb(urb);	BT_DBG("%s URB resubmit status %d", husb->hdev.name, status);	read_unlock(&husb->completion_lock);}static void hci_usb_destruct(struct hci_dev *hdev){	struct hci_usb *husb;	if (!hdev) return;	BT_DBG("%s", hdev->name);	husb = (struct hci_usb *) hdev->driver_data;	kfree(husb);}static void *hci_usb_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id){	struct usb_endpoint_descriptor *bulk_out_ep[HCI_MAX_IFACE_NUM];	struct usb_endpoint_descriptor *isoc_out_ep[HCI_MAX_IFACE_NUM];	struct usb_endpoint_descriptor *bulk_in_ep[HCI_MAX_IFACE_NUM];	struct usb_endpoint_descriptor *isoc_in_ep[HCI_MAX_IFACE_NUM];	struct usb_endpoint_descriptor *intr_in_ep[HCI_MAX_IFACE_NUM];	struct usb_interface_descriptor *uif;	struct usb_endpoint_descriptor *ep;	struct usb_interface *iface, *isoc_iface;	struct hci_usb *husb;	struct hci_dev *hdev;	int i, a, e, size, ifn, isoc_ifnum, isoc_alts;	BT_DBG("udev %p ifnum %d", udev, ifnum);	iface = &udev->actconfig->interface[0];	/* Check our black list */	if (usb_match_id(udev, iface, ignore_ids))		return NULL;	/* Check number of endpoints */	if (udev->actconfig->interface[ifnum].altsetting[0].bNumEndpoints < 3)		return NULL;	memset(bulk_out_ep, 0, sizeof(bulk_out_ep));	memset(isoc_out_ep, 0, sizeof(isoc_out_ep));	memset(bulk_in_ep,  0, sizeof(bulk_in_ep));	memset(isoc_in_ep,  0, sizeof(isoc_in_ep));	memset(intr_in_ep,  0, sizeof(intr_in_ep));	size = 0; 	isoc_iface = NULL;	isoc_alts  = isoc_ifnum = 0;		/* Find endpoints that we need */	ifn = MIN(udev->actconfig->bNumInterfaces, HCI_MAX_IFACE_NUM);	for (i = 0; i < ifn; i++) {		iface = &udev->actconfig->interface[i];		for (a = 0; a < iface->num_altsetting; a++) {			uif = &iface->altsetting[a];			for (e = 0; e < uif->bNumEndpoints; e++) {				ep = &uif->endpoint[e];				switch (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {				case USB_ENDPOINT_XFER_INT:					if (ep->bEndpointAddress & USB_DIR_IN)						intr_in_ep[i] = ep;					break;				case USB_ENDPOINT_XFER_BULK:					if (ep->bEndpointAddress & USB_DIR_IN)						bulk_in_ep[i]  = ep;					else						bulk_out_ep[i] = ep;					break;				case USB_ENDPOINT_XFER_ISOC:					if (ep->wMaxPacketSize < size)						break;					size = ep->wMaxPacketSize;					isoc_iface = iface;					isoc_alts  = a;					isoc_ifnum = i;					if (ep->bEndpointAddress & USB_DIR_IN)						isoc_in_ep[i]  = ep;					else						isoc_out_ep[i] = ep;					break;				}			}		}	}	if (!bulk_in_ep[0] || !bulk_out_ep[0] || !intr_in_ep[0]) {		BT_DBG("Bulk endpoints not found");		goto done;	}	if (!isoc_in_ep[1] || !isoc_out_ep[1]) {		BT_DBG("Isoc endpoints not found");		isoc_iface = NULL;	}	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[0]->bEndpointAddress;	husb->bulk_in_ep  = bulk_in_ep[0]->bEndpointAddress;	husb->intr_ep = intr_in_ep[0]->bEndpointAddress;	husb->intr_interval = intr_in_ep[0]->bInterval;	if (isoc_iface) {		if (usb_set_interface(udev, isoc_ifnum, isoc_alts)) {			BT_ERR("Can't set isoc interface settings");			isoc_iface = NULL;		}		usb_driver_claim_interface(&hci_usb_driver, isoc_iface, husb);		husb->isoc_iface  = isoc_iface;		husb->isoc_in_ep  = isoc_in_ep[1]->bEndpointAddress;		husb->isoc_out_ep = isoc_in_ep[1]->bEndpointAddress;	}	husb->completion_lock = RW_LOCK_UNLOCKED;		skb_queue_head_init(&husb->acl_q);	skb_queue_head_init(&husb->cmd_q);	skb_queue_head_init(&husb->pending_q);	skb_queue_head_init(&husb->completed_q);	/* Initialize and register HCI device */	hdev = &husb->hdev;	hdev->type = HCI_USB;	hdev->driver_data = husb;	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;	if (hci_register_dev(hdev) < 0) {		BT_ERR("Can't register HCI device");		goto probe_error;	}	return husb;probe_error:	kfree(husb);done:	return NULL;}static void hci_usb_disconnect(struct usb_device *udev, void *ptr){	struct hci_usb *husb = (struct hci_usb *) ptr;	struct hci_dev *hdev = &husb->hdev;	if (!husb)		return;	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);}static struct usb_driver hci_usb_driver = {	name:           "hci_usb",	probe:          hci_usb_probe,	disconnect:     hci_usb_disconnect,	id_table:       bluetooth_ids,};int hci_usb_init(void){	int err;	BT_INFO("BlueZ HCI USB driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",  		VERSION);	BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");	if ((err = usb_register(&hci_usb_driver)) < 0)		BT_ERR("Failed to register HCI USB driver");	return err;}void hci_usb_cleanup(void){	usb_deregister(&hci_usb_driver);}module_init(hci_usb_init);module_exit(hci_usb_cleanup);MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");MODULE_DESCRIPTION("BlueZ HCI USB driver ver " VERSION);MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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