📄 hci_usb.c
字号:
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 + -