static void hci_usb_bulk_read(struct urb *urb) { struct hci_usb *husb = (struct hci_usb *) urb->context; unsigned char *data = urb->transfer_buffer; int count = urb->actual_length, status; struct sk_buff *skb; hci_acl_hdr *ah; register __u16 dlen; if (!husb) return; DBG("%s status %d, count %d, flags %x", husb->hdev.name, urb->status, count, urb->transfer_flags); if (urb->status) { /* Do not re-submit URB on critical errors */ switch (urb->status) { case -ENOENT: return; default: goto resubmit; }; } if (!count) goto resubmit; DMP(data, count); ah = (hci_acl_hdr *) data; dlen = le16_to_cpu(ah->dlen); /* Verify frame len and completeness */ if ((count - HCI_ACL_HDR_SIZE) != dlen) { ERR("%s corrupted ACL packet: count %d, plen %d", husb->hdev.name, count, dlen); goto resubmit; } /* Allocate packet */ if (!(skb = bluez_skb_alloc(count, GFP_ATOMIC))) { ERR("Can't allocate mem for new packet"); goto resubmit; } memcpy(skb_put(skb, count), data, count); skb->dev = (void *) &husb->hdev; skb->pkt_type = HCI_ACLDATA_PKT; husb->hdev.stat.byte_rx += skb->len; hci_recv_frame(skb); resubmit: husb->read_urb->dev = husb->udev; if ((status = usb_submit_urb(husb->read_urb))) DBG("%s read URB submit failed %d", husb->hdev.name, status); DBG("%s read URB re-submited", husb->hdev.name); }
int n_hci_tx_wakeup(struct n_hci *n_hci) { register struct tty_struct *tty = n_hci->tty; if (test_and_set_bit(TRANS_SENDING, &n_hci->tx_state)) { set_bit(TRANS_WAKEUP, &n_hci->tx_state); return 0; } DBG(""); do { register struct sk_buff *skb; register int len; clear_bit(TRANS_WAKEUP, &n_hci->tx_state); if (!(skb = skb_dequeue(&n_hci->txq))) break; DMP(skb->data, skb->len); /* Send frame to TTY driver */ tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); len = tty->driver.write(tty, 0, skb->data, skb->len); n_hci->hdev.stat.byte_tx += len; DBG("sent %d", len); if (len == skb->len) { /* Full frame was sent */ kfree_skb(skb); } else { /* Subtract sent part and requeue */ skb_pull(skb, len); skb_queue_head(&n_hci->txq, skb); } } while (test_bit(TRANS_WAKEUP, &n_hci->tx_state)); clear_bit(TRANS_SENDING, &n_hci->tx_state); return 0; }
static inline int n_hci_check_data_len(struct n_hci *n_hci, int len) { register int room = skb_tailroom(n_hci->rx_skb); DBG("len %d room %d", len, room); if (!len) { DMP(n_hci->rx_skb->data, n_hci->rx_skb->len); hci_recv_frame(n_hci->rx_skb); } else if (len > room) { ERR("Data length is to large"); kfree_skb(n_hci->rx_skb); n_hci->hdev.stat.err_rx++; } else { n_hci->rx_state = WAIT_DATA; n_hci->rx_count = len; return len; } n_hci->rx_state = WAIT_PACKET_TYPE; n_hci->rx_skb = NULL; n_hci->rx_count = 0; return 0; }
// Parse RAW data and store internally rr_ret rr_parse(rr_ctx *ctx, UInt32 len, UInt8 *d) { rr_ret ret; UInt32 n, m; UInt32 (*fn)(rr_ctx *, UInt32, UInt8 *); int nextState; n = 0; while (n < len && !ctx->done) { switch (ctx->state) { case DDS_INIT: DMP("INIT\n"); fn = rr_init; nextState = DDS_INTERSPACE; break; case DDS_INTERSPACE: DMP("INTERSPACE\n"); fn = rr_interspace; nextState = DDS_PULSE; break; case DDS_PULSE: DMP("PULSE\n"); fn = rr_pulse; nextState = DDS_SPACE; break; case DDS_SPACE: DMP("SPACE\n"); fn = rr_space; nextState = DDS_PULSE; break; default: fn = NULL; } m = fn(ctx, len - n, &d[n]); ctx->state = nextState; if (m > len - n) break; n += m; } ret.n = n; if (ctx->done) { ret.done = 1; if (ret.n >= 2) { ret.m = (ctx->done == 1 ? n - 2 : n); // partial } else { ret.m = ret.n; } ret.d[0] = ret.d[1] = 0; // 0 inter-space delay ctx->state = DDS_INIT; ctx->done = 0; } else { ret.done = 0; ret.m = ret.n; } return ret; }
static void hci_usb_intr(struct urb *urb) { struct hci_usb *husb = (struct hci_usb *) urb->context; unsigned char *data = urb->transfer_buffer; register int count = urb->actual_length; register struct sk_buff *skb = husb->intr_skb; hci_event_hdr *eh; register int len; if (!husb) return; DBG("%s count %d", husb->hdev.name, count); if (urb->status || !count) { DBG("%s intr status %d, count %d", husb->hdev.name, urb->status, count); return; } /* Do we really have to handle continuations here ? */ if (!skb) { /* New frame */ if (count < HCI_EVENT_HDR_SIZE) { DBG("%s bad frame len %d", husb->hdev.name, count); return; } eh = (hci_event_hdr *) data; len = eh->plen + HCI_EVENT_HDR_SIZE; if (count > len) { DBG("%s corrupted frame, len %d", husb->hdev.name, count); return; } /* Allocate skb */ if (!(skb = bluez_skb_alloc(len, GFP_ATOMIC))) { ERR("Can't allocate mem for new packet"); return; } skb->dev = (void *) &husb->hdev; skb->pkt_type = HCI_EVENT_PKT; husb->intr_skb = skb; husb->intr_count = len; } else { /* Continuation */ if (count > husb->intr_count) { ERR("%s bad frame len %d (expected %d)", husb->hdev.name, count, husb->intr_count); kfree_skb(skb); husb->intr_skb = NULL; husb->intr_count = 0; return; } } memcpy(skb_put(skb, count), data, count); husb->intr_count -= count; DMP(data, count); if (!husb->intr_count) { /* Got complete frame */ husb->hdev.stat.byte_rx += skb->len; hci_recv_frame(skb); husb->intr_skb = NULL; } }
static inline void n_hci_rx(struct n_hci *n_hci, const __u8 * data, char *flags, int count) { register const char *ptr; hci_event_hdr *eh; hci_acl_hdr *ah; hci_sco_hdr *sh; register int len, type, dlen; DBG("count %d state %ld rx_count %ld", count, n_hci->rx_state, n_hci->rx_count); n_hci->hdev.stat.byte_rx += count; ptr = data; while (count) { if (n_hci->rx_count) { len = MIN(n_hci->rx_count, count); memcpy(skb_put(n_hci->rx_skb, len), ptr, len); n_hci->rx_count -= len; count -= len; ptr += len; if (n_hci->rx_count) continue; switch (n_hci->rx_state) { case WAIT_DATA: DBG("Complete data"); DMP(n_hci->rx_skb->data, n_hci->rx_skb->len); hci_recv_frame(n_hci->rx_skb); n_hci->rx_state = WAIT_PACKET_TYPE; n_hci->rx_skb = NULL; continue; case WAIT_EVENT_HDR: eh = (hci_event_hdr *) n_hci->rx_skb->data; DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen); n_hci_check_data_len(n_hci, eh->plen); continue; case WAIT_ACL_HDR: ah = (hci_acl_hdr *) n_hci->rx_skb->data; dlen = __le16_to_cpu(ah->dlen); DBG("ACL header: dlen %d", dlen); n_hci_check_data_len(n_hci, dlen); continue; case WAIT_SCO_HDR: sh = (hci_sco_hdr *) n_hci->rx_skb->data; DBG("SCO header: dlen %d", sh->dlen); n_hci_check_data_len(n_hci, sh->dlen); continue; }; } /* WAIT_PACKET_TYPE */ switch (*ptr) { case HCI_EVENT_PKT: DBG("Event packet"); n_hci->rx_state = WAIT_EVENT_HDR; n_hci->rx_count = HCI_EVENT_HDR_SIZE; type = HCI_EVENT_PKT; break; case HCI_ACLDATA_PKT: DBG("ACL packet"); n_hci->rx_state = WAIT_ACL_HDR; n_hci->rx_count = HCI_ACL_HDR_SIZE; type = HCI_ACLDATA_PKT; break; case HCI_SCODATA_PKT: DBG("SCO packet"); n_hci->rx_state = WAIT_SCO_HDR; n_hci->rx_count = HCI_SCO_HDR_SIZE; type = HCI_SCODATA_PKT; break; default: ERR("Unknown HCI packet type %2.2x", (__u8)*ptr); n_hci->hdev.stat.err_rx++; ptr++; count--; continue; }; ptr++; count--; /* Allocate packet */ if (!(n_hci->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { ERR("Can't allocate mem for new packet"); n_hci->rx_state = WAIT_PACKET_TYPE; n_hci->rx_count = 0; return; } n_hci->rx_skb->dev = (void *) &n_hci->hdev; n_hci->rx_skb->pkt_type = type; } }