-#define HCI_VENDOR_HDR_SIZE 5
-
-struct hci_vendor_hdr {
- __u8 type;
- __le16 snum;
- __le16 dlen;
-} __packed;
-
-static int bpa10x_recv(struct hci_dev *hdev, int queue, void *buf, int count)
-{
- struct bpa10x_data *data = hci_get_drvdata(hdev);
-
- BT_DBG("%s queue %d buffer %p count %d", hdev->name,
- queue, buf, count);
-
- if (queue < 0 || queue > 1)
- return -EILSEQ;
-
- hdev->stat.byte_rx += count;
-
- while (count) {
- struct sk_buff *skb = data->rx_skb[queue];
- struct { __u8 type; int expect; } *scb;
- int type, len = 0;
-
- if (!skb) {
- /* Start of the frame */
-
- type = *((__u8 *) buf);
- count--; buf++;
-
- switch (type) {
- case HCI_EVENT_PKT:
- if (count >= HCI_EVENT_HDR_SIZE) {
- struct hci_event_hdr *h = buf;
- 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 = buf;
- len = HCI_ACL_HDR_SIZE +
- __le16_to_cpu(h->dlen);
- } else
- return -EILSEQ;
- break;
-
- case HCI_SCODATA_PKT:
- if (count >= HCI_SCO_HDR_SIZE) {
- struct hci_sco_hdr *h = buf;
- len = HCI_SCO_HDR_SIZE + h->dlen;
- } else
- return -EILSEQ;
- break;
-
- case HCI_VENDOR_PKT:
- if (count >= HCI_VENDOR_HDR_SIZE) {
- struct hci_vendor_hdr *h = buf;
- len = HCI_VENDOR_HDR_SIZE +
- __le16_to_cpu(h->dlen);
- } else
- return -EILSEQ;
- break;
- }
-
- skb = bt_skb_alloc(len, GFP_ATOMIC);
- if (!skb) {
- BT_ERR("%s no memory for packet", hdev->name);
- return -ENOMEM;
- }
-
- data->rx_skb[queue] = skb;
-
- scb = (void *) skb->cb;
- scb->type = type;
- scb->expect = len;
- } else {
- /* Continuation */
-
- scb = (void *) skb->cb;
- len = scb->expect;
- }
-
- len = min(len, count);
-
- memcpy(skb_put(skb, len), buf, len);
-
- scb->expect -= len;
-
- if (scb->expect == 0) {
- /* Complete frame */
-
- data->rx_skb[queue] = NULL;
-
- bt_cb(skb)->pkt_type = scb->type;
- hci_recv_frame(hdev, skb);
- }
-
- count -= len; buf += len;
- }
-
- return 0;
-}
-