xt/html; charset=UTF-8
Last-Modified: Fri, 17 Jul 2026 14:54:14 GMT
Expires: Mon, 14 Jul 2036 14:54:14 GMT
litmus2008.git - [ARCHIVE] Old LITMUS^RT 2008 version (for reference).
%p urb %p", bfusb, urb);
if (!urb && !(urb = usb_alloc_urb(0, GFP_ATOMIC)))
return -ENOMEM;
if (!(skb = bt_skb_alloc(size, GFP_ATOMIC))) {
usb_free_urb(urb);
return -ENOMEM;
}
skb->dev = (void *) bfusb;
scb = (struct bfusb_scb *) skb->cb;
scb->urb = urb;
pipe = usb_rcvbulkpipe(bfusb->udev, bfusb->bulk_in_ep);
usb_fill_bulk_urb(urb, bfusb->udev, pipe, skb->data, size,
bfusb_rx_complete, skb);
skb_queue_tail(&bfusb->pending_q, skb);
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err) {
BT_ERR("%s bulk rx submit failed urb %p err %d",
bfusb->hdev->name, urb, err);
skb_unlink(skb, &bfusb->pending_q);
kfree_skb(skb);
usb_free_urb(urb);
}
return err;
}
static inline int bfusb_recv_block(struct bfusb *bfusb, int hdr, unsigned char *data, int len)
{
BT_DBG("bfusb %p hdr 0x%02x data %p len %d", bfusb, hdr, data, len);
if (hdr & 0x10) {
BT_ERR("%s error in block", bfusb->hdev->name);
if (bfusb->reassembly)
kfree_skb(bfusb->reassembly);
bfusb->reassembly = NULL;
return -EIO;
}
if (hdr & 0x04) {
struct sk_buff *skb;
unsigned char pkt_type;
int pkt_len = 0;
if (bfusb->reassembly) {
BT_ERR("%s unexpected start block", bfusb->hdev->name);
kfree_skb(bfusb->reassembly);
bfusb->reassembly = NULL;
}
if (len < 1) {
BT_ERR("%s no packet type found", bfusb->hdev->name);
return -EPROTO;
}
pkt_type = *data++; len--;
switch (pkt_type) {
case HCI_EVENT_PKT:
if (len >= HCI_EVENT_HDR_SIZE) {
struct hci_event_hdr *hdr = (struct hci_event_hdr *) data;
pkt_len = HCI_EVENT_HDR_SIZE + hdr->plen;
} else {
BT_ERR("%s event block is too short", bfusb->hdev->name);
return -EILSEQ;
}
break;
case HCI_ACLDATA_PKT:
if (len >= HCI_ACL_HDR_SIZE) {
struct hci_acl_hdr *hdr = (struct hci_acl_hdr *) data;
pkt_len = HCI_ACL_HDR_SIZE + __le16_to_cpu(hdr->dlen);
} else {
BT_ERR("%s data block is too short", bfusb->hdev->name);
return -EILSEQ;
}
break;
case HCI_SCODATA_PKT:
if (len >= HCI_SCO_HDR_SIZE) {
struct hci_sco_hdr *hdr = (struct hci_sco_hdr *) data;
pkt_len = HCI_SCO_HDR_SIZE + hdr->dlen;
} else {
BT_ERR("%s audio block is too short", bfusb->hdev->name);
return -EILSEQ;
}
break;
}
skb = bt_skb_alloc(pkt_len, GFP_ATOMIC);
if (!skb) {
BT_ERR("%s no memory for the packet", bfusb->hdev->name);
return -ENOMEM;
}
skb->dev = (void *) bfusb->hdev;
bt_cb(skb)->pkt_type = pkt_type;
bfusb->reassembly = skb;
} else {
if (!bfusb->reassembly) {
BT_ERR("%s unexpected continuation block", bfusb->hdev->name);
return -EIO;
}
}
if (len > 0