static void btuart_receive(btuart_info_t *info) { unsigned int iobase; int boguscount = 0; if (!info) { BT_ERR("Unknown device"); return; } iobase = info->p_dev->resource[0]->start; do { info->hdev->stat.byte_rx++; /* Allocate packet */ if (info->rx_skb == NULL) { info->rx_state = RECV_WAIT_PACKET_TYPE; info->rx_count = 0; if (!(info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { BT_ERR("Can't allocate mem for new packet"); return; } } if (info->rx_state == RECV_WAIT_PACKET_TYPE) { info->rx_skb->dev = (void *) info->hdev; bt_cb(info->rx_skb)->pkt_type = inb(iobase + UART_RX); switch (bt_cb(info->rx_skb)->pkt_type) { case HCI_EVENT_PKT: info->rx_state = RECV_WAIT_EVENT_HEADER; info->rx_count = HCI_EVENT_HDR_SIZE; break; case HCI_ACLDATA_PKT: info->rx_state = RECV_WAIT_ACL_HEADER; info->rx_count = HCI_ACL_HDR_SIZE; break; case HCI_SCODATA_PKT: info->rx_state = RECV_WAIT_SCO_HEADER; info->rx_count = HCI_SCO_HDR_SIZE; break; default: /* Unknown packet */ BT_ERR("Unknown HCI packet with type 0x%02x received", bt_cb(info->rx_skb)->pkt_type); info->hdev->stat.err_rx++; clear_bit(HCI_RUNNING, &(info->hdev->flags)); kfree_skb(info->rx_skb); info->rx_skb = NULL; break; } } else { *skb_put(info->rx_skb, 1) = inb(iobase + UART_RX); info->rx_count--; if (info->rx_count == 0) { int dlen; struct hci_event_hdr *eh; struct hci_acl_hdr *ah; struct hci_sco_hdr *sh; switch (info->rx_state) { case RECV_WAIT_EVENT_HEADER: eh = hci_event_hdr(info->rx_skb); info->rx_state = RECV_WAIT_DATA; info->rx_count = eh->plen; break; case RECV_WAIT_ACL_HEADER: ah = hci_acl_hdr(info->rx_skb); dlen = __le16_to_cpu(ah->dlen); info->rx_state = RECV_WAIT_DATA; info->rx_count = dlen; break; case RECV_WAIT_SCO_HEADER: sh = hci_sco_hdr(info->rx_skb); info->rx_state = RECV_WAIT_DATA; info->rx_count = sh->dlen; break; case RECV_WAIT_DATA: hci_recv_frame(info->rx_skb); info->rx_skb = NULL; break; } } } /* Make sure we don't stay here too long */ if (boguscount++ > 16) break; } while (inb(iobase + UART_LSR) & UART_LSR_DR); }
static inline ssize_t vhci_get_user(struct vhci_data *data, const char __user *buf, size_t count) { struct sk_buff *skb; __u8 pkt_type, dev_type; int ret; if (count < 2 || count > HCI_MAX_FRAME_SIZE) return -EINVAL; skb = bt_skb_alloc(count, GFP_KERNEL); if (!skb) return -ENOMEM; if (copy_from_user(skb_put(skb, count), buf, count)) { kfree_skb(skb); return -EFAULT; } pkt_type = *((__u8 *) skb->data); skb_pull(skb, 1); switch (pkt_type) { case HCI_EVENT_PKT: case HCI_ACLDATA_PKT: case HCI_SCODATA_PKT: if (!data->hdev) { kfree_skb(skb); return -ENODEV; } bt_cb(skb)->pkt_type = pkt_type; ret = hci_recv_frame(data->hdev, skb); break; case HCI_VENDOR_PKT: if (data->hdev) { kfree_skb(skb); return -EBADFD; } cancel_delayed_work_sync(&data->open_timeout); dev_type = *((__u8 *) skb->data); skb_pull(skb, 1); if (skb->len > 0) { kfree_skb(skb); return -EINVAL; } kfree_skb(skb); if (dev_type != HCI_BREDR && dev_type != HCI_AMP) return -EINVAL; ret = vhci_create_device(data, dev_type); break; default: kfree_skb(skb); return -EINVAL; } return (ret < 0) ? ret : count; }
static void bluecard_receive(bluecard_info_t *info, unsigned int offset) { unsigned int iobase; unsigned char buf[31]; int i, len; if (!info) { BT_ERR("Unknown device"); return; } #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)) iobase = info->p_dev->resource[0]->start; #else iobase = info->p_dev->io.BasePort1; #endif if (test_bit(XMIT_SENDING_READY, &(info->tx_state))) bluecard_enable_activity_led(info); len = bluecard_read(iobase, offset, buf, sizeof(buf)); for (i = 0; i < len; i++) { /* Allocate packet */ if (info->rx_skb == NULL) { info->rx_state = RECV_WAIT_PACKET_TYPE; info->rx_count = 0; if (!(info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { BT_ERR("Can't allocate mem for new packet"); return; } } if (info->rx_state == RECV_WAIT_PACKET_TYPE) { info->rx_skb->dev = (void *) info->hdev; bt_cb(info->rx_skb)->pkt_type = buf[i]; switch (bt_cb(info->rx_skb)->pkt_type) { case 0x00: /* init packet */ if (offset != 0x00) { set_bit(XMIT_BUF_ONE_READY, &(info->tx_state)); set_bit(XMIT_BUF_TWO_READY, &(info->tx_state)); set_bit(XMIT_SENDING_READY, &(info->tx_state)); bluecard_write_wakeup(info); } kfree_skb(info->rx_skb); info->rx_skb = NULL; break; case HCI_EVENT_PKT: info->rx_state = RECV_WAIT_EVENT_HEADER; info->rx_count = HCI_EVENT_HDR_SIZE; break; case HCI_ACLDATA_PKT: info->rx_state = RECV_WAIT_ACL_HEADER; info->rx_count = HCI_ACL_HDR_SIZE; break; case HCI_SCODATA_PKT: info->rx_state = RECV_WAIT_SCO_HEADER; info->rx_count = HCI_SCO_HDR_SIZE; break; default: /* unknown packet */ BT_ERR("Unknown HCI packet with type 0x%02x received", bt_cb(info->rx_skb)->pkt_type); info->hdev->stat.err_rx++; kfree_skb(info->rx_skb); info->rx_skb = NULL; break; } } else { *skb_put(info->rx_skb, 1) = buf[i]; info->rx_count--; if (info->rx_count == 0) { int dlen; struct hci_event_hdr *eh; struct hci_acl_hdr *ah; struct hci_sco_hdr *sh; switch (info->rx_state) { case RECV_WAIT_EVENT_HEADER: eh = hci_event_hdr(info->rx_skb); info->rx_state = RECV_WAIT_DATA; info->rx_count = eh->plen; break; case RECV_WAIT_ACL_HEADER: ah = hci_acl_hdr(info->rx_skb); dlen = __le16_to_cpu(ah->dlen); info->rx_state = RECV_WAIT_DATA; info->rx_count = dlen; break; case RECV_WAIT_SCO_HEADER: sh = hci_sco_hdr(info->rx_skb); info->rx_state = RECV_WAIT_DATA; info->rx_count = sh->dlen; break; case RECV_WAIT_DATA: hci_recv_frame(info->rx_skb); info->rx_skb = NULL; break; } } } } info->hdev->stat.byte_rx += len; }
/* Decodes received RAW data and forwards to corresponding * client drivers (Bluetooth,FM,GPS..etc). * */ void st_int_recv(void *disc_data, const unsigned char *data, long count) { register char *ptr; struct hci_event_hdr *eh; struct hci_acl_hdr *ah; struct hci_sco_hdr *sh; struct fm_event_hdr *fm; struct gps_event_hdr *gps; register int len = 0, type = 0, dlen = 0; static enum proto_type protoid = ST_MAX; struct st_data_s *st_gdata = (struct st_data_s *)disc_data; ptr = (char *)data; /* tty_receive sent null ? */ if (unlikely(ptr == NULL) || (st_gdata == NULL)) { pr_err(" received null from TTY "); return; } pr_info("count %ld rx_state %ld" "rx_count %ld", count, st_gdata->rx_state, st_gdata->rx_count); /* Decode received bytes here */ while (count) { if (st_gdata->rx_count) { len = min_t(unsigned int, st_gdata->rx_count, count); memcpy(skb_put(st_gdata->rx_skb, len), ptr, len); st_gdata->rx_count -= len; count -= len; ptr += len; if (st_gdata->rx_count) continue; /* Check ST RX state machine , where are we? */ switch (st_gdata->rx_state) { /* Waiting for complete packet ? */ case ST_BT_W4_DATA: pr_info("Complete pkt received"); /* Ask ST CORE to forward * the packet to protocol driver */ st_send_frame(protoid, st_gdata); st_gdata->rx_state = ST_W4_PACKET_TYPE; st_gdata->rx_skb = NULL; protoid = ST_MAX; /* is this required ? */ continue; /* Waiting for Bluetooth event header ? */ case ST_BT_W4_EVENT_HDR: eh = (struct hci_event_hdr *)st_gdata->rx_skb-> data; pr_info("Event header: evt 0x%2.2x" "plen %d", eh->evt, eh->plen); st_check_data_len(st_gdata, protoid, eh->plen); continue; /* Waiting for Bluetooth acl header ? */ case ST_BT_W4_ACL_HDR: ah = (struct hci_acl_hdr *)st_gdata->rx_skb-> data; dlen = __le16_to_cpu(ah->dlen); pr_info("ACL header: dlen %d", dlen); st_check_data_len(st_gdata, protoid, dlen); continue; /* Waiting for Bluetooth sco header ? */ case ST_BT_W4_SCO_HDR: sh = (struct hci_sco_hdr *)st_gdata->rx_skb-> data; pr_info("SCO header: dlen %d", sh->dlen); st_check_data_len(st_gdata, protoid, sh->dlen); continue; case ST_FM_W4_EVENT_HDR: fm = (struct fm_event_hdr *)st_gdata->rx_skb-> data; pr_info("FM Header: "); st_check_data_len(st_gdata, ST_FM, fm->plen); continue; /* TODO : Add GPS packet machine logic here */ case ST_GPS_W4_EVENT_HDR: /* [0x09 pkt hdr][R/W byte][2 byte len] */ gps = (struct gps_event_hdr *)st_gdata->rx_skb-> data; pr_info("GPS Header: "); st_check_data_len(st_gdata, ST_GPS, gps->plen); continue; } /* end of switch rx_state */ } /* end of if rx_count */ /* Check first byte of packet and identify module * owner (BT/FM/GPS) */ switch (*ptr) { /* Bluetooth event packet? */ case HCI_EVENT_PKT: pr_info("Event packet"); st_gdata->rx_state = ST_BT_W4_EVENT_HDR; st_gdata->rx_count = HCI_EVENT_HDR_SIZE; type = HCI_EVENT_PKT; protoid = ST_BT; break; /* Bluetooth acl packet? */ case HCI_ACLDATA_PKT: pr_info("ACL packet"); st_gdata->rx_state = ST_BT_W4_ACL_HDR; st_gdata->rx_count = HCI_ACL_HDR_SIZE; type = HCI_ACLDATA_PKT; protoid = ST_BT; break; /* Bluetooth sco packet? */ case HCI_SCODATA_PKT: pr_info("SCO packet"); st_gdata->rx_state = ST_BT_W4_SCO_HDR; st_gdata->rx_count = HCI_SCO_HDR_SIZE; type = HCI_SCODATA_PKT; protoid = ST_BT; break; /* Channel 8(FM) packet? */ case ST_FM_CH8_PKT: pr_info("FM CH8 packet"); type = ST_FM_CH8_PKT; st_gdata->rx_state = ST_FM_W4_EVENT_HDR; st_gdata->rx_count = FM_EVENT_HDR_SIZE; protoid = ST_FM; break; /* Channel 9(GPS) packet? */ case 0x9: /*ST_LL_GPS_CH9_PKT */ pr_info("GPS CH9 packet"); type = 0x9; /* ST_LL_GPS_CH9_PKT; */ protoid = ST_GPS; st_gdata->rx_state = ST_GPS_W4_EVENT_HDR; st_gdata->rx_count = 3; /* GPS_EVENT_HDR_SIZE -1*/ break; case LL_SLEEP_IND: case LL_SLEEP_ACK: case LL_WAKE_UP_IND: pr_info("PM packet"); /* this takes appropriate action based on * sleep state received -- */ st_ll_sleep_state(st_gdata, *ptr); ptr++; count--; continue; case LL_WAKE_UP_ACK: pr_info("PM packet"); /* wake up ack received */ st_wakeup_ack(st_gdata, *ptr); ptr++; count--; continue; /* Unknow packet? */ default: pr_err("Unknown packet type %2.2x", (__u8) *ptr); ptr++; count--; continue; }; ptr++; count--; switch (protoid) { case ST_BT: /* Allocate new packet to hold received data */ st_gdata->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC); if (!st_gdata->rx_skb) { pr_err("Can't allocate mem for new packet"); st_gdata->rx_state = ST_W4_PACKET_TYPE; st_gdata->rx_count = 0; return; } bt_cb(st_gdata->rx_skb)->pkt_type = type; break; case ST_FM: /* for FM */ st_gdata->rx_skb = alloc_skb(FM_MAX_FRAME_SIZE, GFP_ATOMIC); if (!st_gdata->rx_skb) { pr_err("Can't allocate mem for new packet"); st_gdata->rx_state = ST_W4_PACKET_TYPE; st_gdata->rx_count = 0; return; } /* place holder 0x08 */ skb_reserve(st_gdata->rx_skb, 1); st_gdata->rx_skb->cb[0] = ST_FM_CH8_PKT; break; case ST_GPS: /* for GPS */ st_gdata->rx_skb = alloc_skb(100 /*GPS_MAX_FRAME_SIZE */ , GFP_ATOMIC); if (!st_gdata->rx_skb) { pr_err("Can't allocate mem for new packet"); st_gdata->rx_state = ST_W4_PACKET_TYPE; st_gdata->rx_count = 0; return; } /* place holder 0x09 */ skb_reserve(st_gdata->rx_skb, 1); st_gdata->rx_skb->cb[0] = 0x09; /*ST_GPS_CH9_PKT; */ break; case ST_MAX: break; } }
/* Recv data */ static int ibs_recv(struct hci_uart *hu, void *data, int count) { struct ibs_struct *ibs = hu->priv; register char *ptr; struct hci_event_hdr *eh; struct hci_acl_hdr *ah; struct hci_sco_hdr *sh; register int len, type, dlen; BT_DBG("hu %p count %d rx_state %ld rx_count %ld", hu, count, ibs->rx_state, ibs->rx_count); ptr = data; while (count) { if (ibs->rx_count) { len = min_t(unsigned int, ibs->rx_count, count); memcpy(skb_put(ibs->rx_skb, len), ptr, len); ibs->rx_count -= len; count -= len; ptr += len; if (ibs->rx_count) continue; switch (ibs->rx_state) { case HCI_IBS_W4_DATA: BT_DBG("Complete data"); hci_recv_frame(ibs->rx_skb); ibs->rx_state = HCI_IBS_W4_PACKET_TYPE; ibs->rx_skb = NULL; continue; case HCI_IBS_W4_EVENT_HDR: eh = (struct hci_event_hdr *) ibs->rx_skb->data; BT_DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen); ibs_check_data_len(ibs, eh->plen); continue; case HCI_IBS_W4_ACL_HDR: ah = (struct hci_acl_hdr *) ibs->rx_skb->data; dlen = __le16_to_cpu(ah->dlen); BT_DBG("ACL header: dlen %d", dlen); ibs_check_data_len(ibs, dlen); continue; case HCI_IBS_W4_SCO_HDR: sh = (struct hci_sco_hdr *) ibs->rx_skb->data; BT_DBG("SCO header: dlen %d", sh->dlen); ibs_check_data_len(ibs, sh->dlen); continue; } } /* HCI_IBS_W4_PACKET_TYPE */ switch (*ptr) { case HCI_EVENT_PKT: BT_DBG("Event packet"); ibs->rx_state = HCI_IBS_W4_EVENT_HDR; ibs->rx_count = HCI_EVENT_HDR_SIZE; type = HCI_EVENT_PKT; break; case HCI_ACLDATA_PKT: BT_DBG("ACL packet"); ibs->rx_state = HCI_IBS_W4_ACL_HDR; ibs->rx_count = HCI_ACL_HDR_SIZE; type = HCI_ACLDATA_PKT; break; case HCI_SCODATA_PKT: BT_DBG("SCO packet"); ibs->rx_state = HCI_IBS_W4_SCO_HDR; ibs->rx_count = HCI_SCO_HDR_SIZE; type = HCI_SCODATA_PKT; break; /* HCI_IBS signals */ case HCI_IBS_SLEEP_IND: BT_DBG("HCI_IBS_SLEEP_IND packet"); ibs_device_want_to_sleep(hu); ptr++; count--; continue; case HCI_IBS_WAKE_IND: BT_DBG("HCI_IBS_WAKE_IND packet"); ibs_device_want_to_wakeup(hu); ptr++; count--; continue; case HCI_IBS_WAKE_ACK: BT_DBG("HCI_IBS_WAKE_ACK packet"); ibs_device_woke_up(hu); ptr++; count--; continue; default: BT_ERR("Unknown HCI packet type %2.2x", (__u8)*ptr); hu->hdev->stat.err_rx++; ptr++; count--; continue; }; ptr++; count--; /* Allocate packet */ ibs->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC); if (!ibs->rx_skb) { BT_ERR("Can't allocate mem for new packet"); ibs->rx_state = HCI_IBS_W4_PACKET_TYPE; ibs->rx_count = 0; return 0; } ibs->rx_skb->dev = (void *) hu->hdev; bt_cb(ibs->rx_skb)->pkt_type = type; }
static int vhci_create_device(struct vhci_data *data, __u8 opcode) { struct hci_dev *hdev; struct sk_buff *skb; __u8 dev_type; /* bits 0-1 are dev_type (BR/EDR or AMP) */ dev_type = opcode & 0x03; if (dev_type != HCI_BREDR && dev_type != HCI_AMP) return -EINVAL; /* bits 2-5 are reserved (must be zero) */ if (opcode & 0x3c) return -EINVAL; skb = bt_skb_alloc(4, GFP_KERNEL); if (!skb) return -ENOMEM; hdev = hci_alloc_dev(); if (!hdev) { kfree_skb(skb); return -ENOMEM; } data->hdev = hdev; hdev->bus = HCI_VIRTUAL; hdev->dev_type = dev_type; hci_set_drvdata(hdev, data); hdev->open = vhci_open_dev; hdev->close = vhci_close_dev; hdev->flush = vhci_flush; hdev->send = vhci_send_frame; /* bit 6 is for external configuration */ if (opcode & 0x40) set_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks); /* bit 7 is for raw device */ if (opcode & 0x80) set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks); if (hci_register_dev(hdev) < 0) { BT_ERR("Can't register HCI device"); hci_free_dev(hdev); data->hdev = NULL; kfree_skb(skb); return -EBUSY; } bt_cb(skb)->pkt_type = HCI_VENDOR_PKT; *skb_put(skb, 1) = 0xff; *skb_put(skb, 1) = opcode; put_unaligned_le16(hdev->id, skb_put(skb, 2)); skb_queue_tail(&data->readq, skb); wake_up_interruptible(&data->read_wait); return 0; }
static inline int bfusb_recv_block(struct bfusb_data *data, int hdr, unsigned char *buf, int len) { BT_DBG("bfusb %p hdr 0x%02x data %p len %d", data, hdr, buf, len); if (hdr & 0x10) { BT_ERR("%s error in block", data->hdev->name); kfree_skb(data->reassembly); data->reassembly = NULL; return -EIO; } if (hdr & 0x04) { struct sk_buff *skb; unsigned char pkt_type; int pkt_len = 0; if (data->reassembly) { BT_ERR("%s unexpected start block", data->hdev->name); kfree_skb(data->reassembly); data->reassembly = NULL; } if (len < 1) { BT_ERR("%s no packet type found", data->hdev->name); return -EPROTO; } pkt_type = *buf++; len--; switch (pkt_type) { case HCI_EVENT_PKT: if (len >= HCI_EVENT_HDR_SIZE) { struct hci_event_hdr *hdr = (struct hci_event_hdr *) buf; pkt_len = HCI_EVENT_HDR_SIZE + hdr->plen; } else { BT_ERR("%s event block is too short", data->hdev->name); return -EILSEQ; } break; case HCI_ACLDATA_PKT: if (len >= HCI_ACL_HDR_SIZE) { struct hci_acl_hdr *hdr = (struct hci_acl_hdr *) buf; pkt_len = HCI_ACL_HDR_SIZE + __le16_to_cpu(hdr->dlen); } else { BT_ERR("%s data block is too short", data->hdev->name); return -EILSEQ; } break; case HCI_SCODATA_PKT: if (len >= HCI_SCO_HDR_SIZE) { struct hci_sco_hdr *hdr = (struct hci_sco_hdr *) buf; pkt_len = HCI_SCO_HDR_SIZE + hdr->dlen; } else { BT_ERR("%s audio block is too short", data->hdev->name); return -EILSEQ; } break; } skb = bt_skb_alloc(pkt_len, GFP_ATOMIC); if (!skb) { BT_ERR("%s no memory for the packet", data->hdev->name); return -ENOMEM; } skb->dev = (void *) data->hdev; bt_cb(skb)->pkt_type = pkt_type; data->reassembly = skb; } else { if (!data->reassembly) { BT_ERR("%s unexpected continuation block", data->hdev->name); return -EIO; } } if (len > 0) memcpy(skb_put(data->reassembly, len), buf, len); if (hdr & 0x08) { hci_recv_frame(data->reassembly); data->reassembly = NULL; } return 0; }
struct sk_buff *h4_recv_buf(struct hci_dev *hdev, struct sk_buff *skb, const unsigned char *buffer, int count, const struct h4_recv_pkt *pkts, int pkts_count) { while (count) { int i, len; if (!skb) { for (i = 0; i < pkts_count; i++) { if (buffer[0] != (&pkts[i])->type) continue; skb = bt_skb_alloc((&pkts[i])->maxlen, GFP_ATOMIC); if (!skb) return ERR_PTR(-ENOMEM); bt_cb(skb)->pkt_type = (&pkts[i])->type; bt_cb(skb)->expect = (&pkts[i])->hlen; break; } /* Check for invalid packet type */ if (!skb) return ERR_PTR(-EILSEQ); count -= 1; buffer += 1; } len = min_t(uint, bt_cb(skb)->expect - skb->len, count); memcpy(skb_put(skb, len), buffer, len); count -= len; buffer += len; /* Check for partial packet */ if (skb->len < bt_cb(skb)->expect) continue; for (i = 0; i < pkts_count; i++) { if (bt_cb(skb)->pkt_type == (&pkts[i])->type) break; } if (i >= pkts_count) { kfree_skb(skb); return ERR_PTR(-EILSEQ); } if (skb->len == (&pkts[i])->hlen) { u16 dlen; switch ((&pkts[i])->lsize) { case 0: /* No variable data length */ (&pkts[i])->recv(hdev, skb); skb = NULL; break; case 1: /* Single octet variable length */ dlen = skb->data[(&pkts[i])->loff]; bt_cb(skb)->expect += dlen; if (skb_tailroom(skb) < dlen) { kfree_skb(skb); return ERR_PTR(-EMSGSIZE); } break; case 2: /* Double octet variable length */ dlen = get_unaligned_le16(skb->data + (&pkts[i])->loff); bt_cb(skb)->expect += dlen; if (skb_tailroom(skb) < dlen) { kfree_skb(skb); return ERR_PTR(-EMSGSIZE); } break; default: /* Unsupported variable length */ kfree_skb(skb); return ERR_PTR(-EILSEQ); } } else { /* Complete frame */ (&pkts[i])->recv(hdev, skb); skb = NULL; } } return skb; }
void* tdsp_bt_skb_alloc_atomic(unsigned long size) { return (void*)(bt_skb_alloc(size, GFP_ATOMIC)); }
int rtbt_hci_dev_receive(void *bt_dev, int pkt_type, char *buf, int len) { //struct hci_event_hdr hdr; //struct hci_dev *hdev = (struct hci_dev *)skb->dev; struct hci_dev *hdev = 0; struct sk_buff *skb; int status; //int pkt_len; //printk("-->%s(): receive info: pkt_type=%d(%s), len=%d!\n", __FUNCTION__, pkt_type, pkt_type <= 5 ? pkt_type_str[pkt_type] : "ErrPktType", len); switch (pkt_type) { case HCI_EVENT_PKT: if (len < HCI_EVENT_HDR_SIZE) { BT_ERR("event block is too short"); return -EILSEQ; } break; case HCI_ACLDATA_PKT: if (len < HCI_ACL_HDR_SIZE) { BT_ERR("data block is too short"); return -EILSEQ; } break; case HCI_SCODATA_PKT: if (len < HCI_SCO_HDR_SIZE) { BT_ERR("audio block is too short"); return -EILSEQ; } break; } skb = bt_skb_alloc(len, GFP_ATOMIC); if (!skb) { printk("%s no memory for the packet", ((struct hci_dev *)bt_dev)->name); return -ENOMEM; } skb->dev = g_hdev; rtbt_set_pkt_type(skb, pkt_type); memcpy(skb_put(skb, len), buf, len); if (pkt_type == HCI_SCODATA_PKT) printk("-->%s(): send sco data to OS, time=0x%lx\n", __FUNCTION__, jiffies); hdev = (struct hci_dev *)skb->dev; if(hdev){ hdev->stat.byte_rx += len; } #if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,7) status = hci_recv_frame(skb); #else status = hci_recv_frame(hdev, skb); #endif //printk("<--%s()\n", __FUNCTION__); return status; }
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; } skb->dev = (void *) hdev; 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(skb); } count -= len; buf += len; } return 0; }
static inline void brf6150_rx(struct brf6150_info *info) { u8 byte; NBT_DBG_TRANSFER("rx_tasklet woke up\ndata "); while (brf6150_inb(info, UART_LSR) & UART_LSR_DR) { if (info->rx_skb == NULL) { info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC); if (!info->rx_skb) { printk(KERN_WARNING "brf6150: Can't allocate memory for new packet\n"); return; } info->rx_state = WAIT_FOR_PKT_TYPE; info->rx_skb->dev = (void *)info->hdev; brf6150_disable_pm_rx(info); clk_enable(info->uart_ck); } byte = brf6150_inb(info, UART_RX); if (info->garbage_bytes) { info->garbage_bytes--; info->hdev->stat.err_rx++; continue; } info->hdev->stat.byte_rx++; NBT_DBG_TRANSFER_NF("0x%.2x ", byte); switch (info->rx_state) { case WAIT_FOR_PKT_TYPE: bt_cb(info->rx_skb)->pkt_type = byte; info->rx_count = brf6150_get_hdr_len(byte); if (info->rx_count >= 0) { info->rx_state = WAIT_FOR_HEADER; } else { info->hdev->stat.err_rx++; kfree_skb(info->rx_skb); info->rx_skb = NULL; clk_disable(info->uart_ck); } break; case WAIT_FOR_HEADER: info->rx_count--; *skb_put(info->rx_skb, 1) = byte; if (info->rx_count == 0) { info->rx_count = brf6150_get_data_len(info, info->rx_skb); if (info->rx_count > skb_tailroom(info->rx_skb)) { printk(KERN_WARNING "brf6150: Frame is %ld bytes too long.\n", info->rx_count - skb_tailroom(info->rx_skb)); info->rx_skb = NULL; info->garbage_bytes = info->rx_count - skb_tailroom(info->rx_skb); clk_disable(info->uart_ck); break; } info->rx_state = WAIT_FOR_DATA; if (bt_cb(info->rx_skb)->pkt_type == H4_NEG_PKT) { brf6150_negotiation_packet(info, info->rx_skb); info->rx_skb = NULL; clk_disable(info->uart_ck); return; } if (bt_cb(info->rx_skb)->pkt_type == H4_ALIVE_PKT) { brf6150_alive_packet(info, info->rx_skb); info->rx_skb = NULL; clk_disable(info->uart_ck); return; } } break; case WAIT_FOR_DATA: info->rx_count--; *skb_put(info->rx_skb, 1) = byte; if (info->rx_count == 0) { brf6150_recv_frame(info, info->rx_skb); info->rx_skb = NULL; clk_disable(info->uart_ck); } break; default: WARN_ON(1); break; } } NBT_DBG_TRANSFER_NF("\n"); }
/* receive function called during firmware download * - firmware download responses on different UART drivers * have been observed to come in bursts of different * tty_receive and hence the logic */ void kim_int_recv(const unsigned char *data, long count) { register char *ptr; struct hci_event_hdr *eh; register int len = 0, type = 0; ST_KIM_DBG("%s", __func__); /* Decode received bytes here */ ptr = (char *)data; if (unlikely(ptr == NULL)) { ST_KIM_ERR(" received null from TTY "); return; } while (count) { if (kim_gdata->rx_count) { len = min_t(unsigned int, kim_gdata->rx_count, count); memcpy(skb_put(kim_gdata->rx_skb, len), ptr, len); kim_gdata->rx_count -= len; count -= len; ptr += len; if (kim_gdata->rx_count) continue; /* Check ST RX state machine , where are we? */ switch (kim_gdata->rx_state) { /* Waiting for complete packet ? */ case ST_BT_W4_DATA: ST_KIM_DBG("Complete pkt received"); validate_firmware_response(kim_gdata->rx_skb); kim_gdata->rx_state = ST_W4_PACKET_TYPE; kim_gdata->rx_skb = NULL; continue; /* Waiting for Bluetooth event header ? */ case ST_BT_W4_EVENT_HDR: eh = (struct hci_event_hdr *)kim_gdata-> rx_skb->data; ST_KIM_DBG("Event header: evt 0x%2.2x " "plen %d", eh->evt, eh->plen); kim_check_data_len(eh->plen); continue; } /* end of switch */ } /* end of if rx_state */ switch (*ptr) { /* Bluetooth event packet? */ case HCI_EVENT_PKT: ST_KIM_DBG("Event packet"); kim_gdata->rx_state = ST_BT_W4_EVENT_HDR; kim_gdata->rx_count = HCI_EVENT_HDR_SIZE; type = HCI_EVENT_PKT; break; default: ST_KIM_DBG("unknown packet"); ptr++; count--; continue; } /* end of switch *ptr */ ptr++; count--; kim_gdata->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC); if (!kim_gdata->rx_skb) { ST_KIM_ERR("can't allocate mem for new packet"); kim_gdata->rx_state = ST_W4_PACKET_TYPE; kim_gdata->rx_count = 0; return; } /* not necessary in this case */ bt_cb(kim_gdata->rx_skb)->pkt_type = type; } /* end of while count */
static int nokia_send_negotiation(struct hci_uart *hu) { struct nokia_bt_dev *btdev = hu->priv; struct device *dev = &btdev->serdev->dev; struct hci_nokia_neg_cmd *neg_cmd; struct hci_nokia_neg_hdr *neg_hdr; struct sk_buff *skb; int len, err; u16 baud = DIV_ROUND_CLOSEST(btdev->sysclk_speed * 10, SETUP_BAUD_RATE); int sysclk = btdev->sysclk_speed / 1000; len = H4_TYPE_SIZE + sizeof(*neg_hdr) + sizeof(*neg_cmd); skb = bt_skb_alloc(len, GFP_KERNEL); if (!skb) return -ENOMEM; hci_skb_pkt_type(skb) = HCI_NOKIA_NEG_PKT; neg_hdr = skb_put(skb, sizeof(*neg_hdr)); neg_hdr->dlen = sizeof(*neg_cmd); neg_cmd = skb_put(skb, sizeof(*neg_cmd)); neg_cmd->ack = NOKIA_NEG_REQ; neg_cmd->baud = cpu_to_le16(baud); neg_cmd->unused1 = 0x0000; neg_cmd->proto = NOKIA_PROTO_BYTE; neg_cmd->sys_clk = cpu_to_le16(sysclk); neg_cmd->unused2 = 0x0000; btdev->init_error = 0; init_completion(&btdev->init_completion); nokia_enqueue(hu, skb); hci_uart_tx_wakeup(hu); dev_dbg(dev, "Negotiation sent"); if (!wait_for_completion_interruptible_timeout(&btdev->init_completion, msecs_to_jiffies(10000))) { return -ETIMEDOUT; } if (btdev->init_error < 0) return btdev->init_error; /* Change to previously negotiated speed. Flow Control * is disabled until bluetooth adapter is ready to avoid * broken bytes being received. */ nokia_flow_control(btdev->serdev, false); serdev_device_set_baudrate(btdev->serdev, SETUP_BAUD_RATE); err = serdev_device_wait_for_cts(btdev->serdev, true, 200); if (err < 0) { dev_err(dev, "CTS not received: %d", err); return err; } nokia_flow_control(btdev->serdev, true); dev_dbg(dev, "Negotiation successful"); return 0; }
/** * @brief This function reads data from the card. * * @param priv A pointer to bt_private structure * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE */ static int sd_card_to_host(bt_private *priv) { int ret = BT_STATUS_SUCCESS; u16 buf_len = 0; int buf_block_len; int blksz; struct sk_buff *skb = NULL; u32 type; u8 *payload = NULL; struct mbt_dev *mbt_dev = NULL; struct m_dev *mdev_bt = &(priv->bt_dev.m_dev[BT_SEQ]); struct m_dev *mdev_fm = &(priv->bt_dev.m_dev[FM_SEQ]); struct m_dev *mdev_nfc = &(priv->bt_dev.m_dev[NFC_SEQ]); struct nfc_dev *nfc_dev = (struct nfc_dev *)priv->bt_dev.m_dev[NFC_SEQ].dev_pointer; struct fm_dev *fm_dev = (struct fm_dev *)priv->bt_dev.m_dev[FM_SEQ].dev_pointer; struct m_dev *mdev_debug = &(priv->bt_dev.m_dev[DEBUG_SEQ]); struct debug_dev *debug_dev = (struct debug_dev *)priv->bt_dev.m_dev[DEBUG_SEQ].dev_pointer; struct sdio_mmc_card *card = priv->bt_dev.card; ENTER(); if (priv->bt_dev.m_dev[BT_SEQ].spec_type != BLUEZ_SPEC) mbt_dev = (struct mbt_dev *)priv->bt_dev.m_dev[BT_SEQ].dev_pointer; if (!card || !card->func) { PRINTM(ERROR, "BT: card or function is NULL!\n"); ret = BT_STATUS_FAILURE; goto exit; } /* Read the length of data to be transferred */ ret = sd_read_rx_len(priv, &buf_len); if (ret < 0) { PRINTM(ERROR, "BT: card_to_host, read scratch reg failed\n"); ret = BT_STATUS_FAILURE; goto exit; } /* Allocate buffer */ blksz = SD_BLOCK_SIZE; buf_block_len = (buf_len + blksz - 1) / blksz; if (buf_len <= BT_HEADER_LEN || (buf_block_len * blksz) > ALLOC_BUF_SIZE) { PRINTM(ERROR, "BT: card_to_host, invalid packet length: %d\n", buf_len); ret = BT_STATUS_FAILURE; goto exit; } skb = bt_skb_alloc(buf_block_len * blksz + DMA_ALIGNMENT, GFP_ATOMIC); if (skb == NULL) { PRINTM(WARN, "BT: No free skb\n"); goto exit; } if ((t_ptr)skb->data & (DMA_ALIGNMENT - 1)) { skb_put(skb, DMA_ALIGNMENT - ((t_ptr)skb->data & (DMA_ALIGNMENT - 1))); skb_pull(skb, DMA_ALIGNMENT - ((t_ptr)skb->data & (DMA_ALIGNMENT - 1))); } payload = skb->data; ret = sdio_readsb(card->func, payload, priv->bt_dev.ioport, buf_block_len * blksz); if (ret < 0) { PRINTM(ERROR, "BT: card_to_host, read iomem failed: %d\n", ret); kfree_skb(skb); skb = NULL; ret = BT_STATUS_FAILURE; goto exit; } /* This is SDIO specific header length: byte[2][1][0], * type: byte[3] (HCI_COMMAND = 1, ACL_DATA = 2, SCO_DATA = 3, 0xFE = Vendor) */ buf_len = payload[0]; buf_len |= (u16) payload[1] << 8; type = payload[3]; PRINTM(DATA, "BT: SDIO Blk Rd %s: len=%d type=%d\n", mbt_dev->name, buf_len, type); if (buf_len > buf_block_len * blksz) { PRINTM(ERROR, "BT: Drop invalid rx pkt, len in hdr=%d, cmd53 length=%d\n", buf_len, buf_block_len * blksz); ret = BT_STATUS_FAILURE; kfree_skb(skb); skb = NULL; goto exit; } DBG_HEXDUMP(DAT_D, "BT: SDIO Blk Rd", payload, buf_len); switch (type) { case HCI_ACLDATA_PKT: bt_cb(skb)->pkt_type = type; skb_put(skb, buf_len); skb_pull(skb, BT_HEADER_LEN); if (mbt_dev) { skb->dev = (void *)mdev_bt; mdev_recv_frame(skb); mdev_bt->stat.byte_rx += buf_len; } break; case HCI_SCODATA_PKT: bt_cb(skb)->pkt_type = type; skb_put(skb, buf_len); skb_pull(skb, BT_HEADER_LEN); if (mbt_dev) { skb->dev = (void *)mdev_bt; mdev_recv_frame(skb); mdev_bt->stat.byte_rx += buf_len; } break; case HCI_EVENT_PKT: /** add EVT Demux */ bt_cb(skb)->pkt_type = type; skb_put(skb, buf_len); skb_pull(skb, BT_HEADER_LEN); if (BT_STATUS_SUCCESS == check_evtpkt(priv, skb)) break; switch (skb->data[0]) { case 0x0E: /** cmd complete */ if (priv->debug_device_pending) { if (priv->debug_ocf_ogf[0] == skb->data[3] && priv->debug_ocf_ogf[1] == skb->data[4]) { priv->debug_device_pending = 0; priv->debug_ocf_ogf[0] = 0; priv->debug_ocf_ogf[1] = 0; /** debug cmd complete */ if (debug_dev) { skb->dev = (void *)mdev_debug; mdev_recv_frame(skb); mdev_debug->stat.byte_rx += buf_len; } break; } } if (skb->data[3] == 0x80 && skb->data[4] == 0xFE) { /** FM cmd complete */ if (fm_dev) { skb->dev = (void *)mdev_fm; mdev_recv_frame(skb); mdev_fm->stat.byte_rx += buf_len; } } else if (skb->data[3] == 0x81 && skb->data[4] == 0xFE) { /** NFC cmd complete */ if (nfc_dev) { skb->dev = (void *)mdev_nfc; mdev_recv_frame(skb); mdev_nfc->stat.byte_rx += buf_len; } } else { if (mbt_dev) { skb->dev = (void *)mdev_bt; mdev_recv_frame(skb); mdev_bt->stat.byte_rx += buf_len; } } break; case 0x0F: /** cmd status */ if (skb->data[4] == 0x80 && skb->data[5] == 0xFE) { /** FM cmd ststus */ if (fm_dev) { skb->dev = (void *)mdev_fm; mdev_recv_frame(skb); mdev_fm->stat.byte_rx += buf_len; } } else if (skb->data[4] == 0x81 && skb->data[5] == 0xFE) { /** NFC cmd ststus */ if (nfc_dev) { skb->dev = (void *)mdev_nfc; mdev_recv_frame(skb); mdev_nfc->stat.byte_rx += buf_len; } } else { /** BT cmd status */ if (mbt_dev) { skb->dev = (void *)mdev_bt; mdev_recv_frame(skb); mdev_bt->stat.byte_rx += buf_len; } } break; case 0xFF: /** Vendor specific pkt */ if (skb->data[2] == 0xC0) { /** NFC EVT */ if (nfc_dev) { skb->dev = (void *)mdev_nfc; mdev_recv_frame(skb); mdev_nfc->stat.byte_rx += buf_len; } } else if (skb->data[2] >= 0x80 && skb->data[2] <= 0xAF) { /** FM EVT */ if (fm_dev) { skb->dev = (void *)mdev_fm; mdev_recv_frame(skb); mdev_fm->stat.byte_rx += buf_len; } } else { /** BT EVT */ if (mbt_dev) { skb->dev = (void *)mdev_bt; mdev_recv_frame(skb); mdev_bt->stat.byte_rx += buf_len; } } break; default: /** BT EVT */ if (mbt_dev) { skb->dev = (void *)mdev_bt; mdev_recv_frame(skb); mdev_bt->stat.byte_rx += buf_len; } break; } break; case MRVL_VENDOR_PKT: /* Just think here need to back compatible FM */ bt_cb(skb)->pkt_type = HCI_VENDOR_PKT; skb_put(skb, buf_len); skb_pull(skb, BT_HEADER_LEN); if (mbt_dev) { if (BT_STATUS_SUCCESS != bt_process_event(priv, skb)) { skb->dev = (void *)mdev_bt; mdev_recv_frame(skb); mdev_bt->stat.byte_rx += buf_len; } } break; default: /* Driver specified event and command resp should be handle here */ PRINTM(INFO, "BT: Unknown PKT type:%d\n", type); kfree_skb(skb); skb = NULL; break; } exit: if (ret) { if (mbt_dev) mdev_bt->stat.err_rx++; PRINTM(ERROR, "error when recv pkt!\n"); } LEAVE(); return ret; }
/* Recv data */ static int h4_recv(struct hci_uart *hu, void *data, int count) { #ifdef CONFIG_RADIO_BCM4343S struct h4_struct *h4 = hu->priv; register char *ptr; struct hci_event_hdr *eh; struct hci_acl_hdr *ah; struct hci_sco_hdr *sh; struct fm_event_hdr *fm; register int len, type, dlen; static enum proto_type protoid = PROTO_SH_MAX; BT_DBG("hu %p count %d rx_state %ld rx_count %ld", hu, count, h4->rx_state, h4->rx_count); ptr = (char *)data; while (count) { if (h4->rx_count) { len = min_t(unsigned int, h4->rx_count, count); memcpy(skb_put(h4->rx_skb, len), ptr, len); h4->rx_count -= len; count -= len; ptr += len; if (h4->rx_count) continue; switch (h4->rx_state) { case H4_W4_DATA: BT_DBG("%2x %2x %2x %2x",h4->rx_skb->data[0], h4->rx_skb->data[1], h4->rx_skb->data[2], h4->rx_skb->data[3]); BT_DBG("%2x %2x %2x %2x",h4->rx_skb->data[4], h4->rx_skb->data[5], h4->rx_skb->data[6], h4->rx_skb->data[7]); BT_DBG("Complete data"); if ( ( h4->rx_skb->data[3] == 0x15 && h4->rx_skb->data[4] == 0xfc ) || ( h4->rx_skb->data[0] == 0xff && h4->rx_skb->data[1] == 0x01 && h4->rx_skb->data[2] == 0x08 ) ) { BT_DBG("FM Event change to FM CH8 packet"); type = FM_CH8_PKT; h4->rx_skb->cb[0] = FM_CH8_PKT; h4->rx_state = FM_W4_EVENT_HDR; protoid = PROTO_SH_FM; } hci_uart_route_frame(protoid, hu, h4->rx_skb); h4->rx_state = H4_W4_PACKET_TYPE; h4->rx_skb = NULL; protoid = PROTO_SH_MAX; continue; case H4_W4_EVENT_HDR: eh = hci_event_hdr(h4->rx_skb); BT_DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen); h4_check_data_len(h4, hu, protoid, eh->plen); continue; case H4_W4_ACL_HDR: ah = hci_acl_hdr(h4->rx_skb); dlen = __le16_to_cpu(ah->dlen); BT_DBG("ACL header: dlen %d", dlen); h4_check_data_len(h4, hu, protoid, dlen); continue; case H4_W4_SCO_HDR: sh = hci_sco_hdr(h4->rx_skb); BT_DBG("SCO header: dlen %d", sh->dlen); h4_check_data_len(h4, hu, protoid, sh->dlen); continue; case FM_W4_EVENT_HDR: fm = (struct fm_event_hdr *)h4->rx_skb->data; BT_DBG("FM Header: evt 0x%2.2x plen %d", fm->event, fm->plen); h4_check_data_len(h4, hu, PROTO_SH_FM, fm->plen); continue; } } /* H4_W4_PACKET_TYPE */ switch (*ptr) { case HCI_EVENT_PKT: BT_DBG("Event packet"); BT_DBG("%2x %2x %2x %2x",ptr[0], ptr[1], ptr[2], ptr[3]); BT_DBG("%2x %2x %2x %2x",ptr[4], ptr[5], ptr[6], ptr[7]); if ( ptr[4] == 0x15 && ptr[5] == 0xfc ) { BT_DBG("FM Event change to FM CH8 packet"); type = FM_CH8_PKT; h4->rx_state = FM_W4_EVENT_HDR; h4->rx_count = FM_EVENT_HDR_SIZE; protoid = PROTO_SH_FM; } else { BT_DBG("FM Event is not detected"); h4->rx_state = H4_W4_EVENT_HDR; h4->rx_count = HCI_EVENT_HDR_SIZE; type = HCI_EVENT_PKT; protoid = PROTO_SH_BT; } break; case HCI_ACLDATA_PKT: BT_DBG("ACL packet"); h4->rx_state = H4_W4_ACL_HDR; h4->rx_count = HCI_ACL_HDR_SIZE; type = HCI_ACLDATA_PKT; protoid = PROTO_SH_BT; break; case HCI_SCODATA_PKT: BT_DBG("SCO packet"); h4->rx_state = H4_W4_SCO_HDR; h4->rx_count = HCI_SCO_HDR_SIZE; type = HCI_SCODATA_PKT; protoid = PROTO_SH_BT; break; /* Channel 8(FM) packet */ case FM_CH8_PKT: BT_DBG("FM CH8 packet"); type = FM_CH8_PKT; h4->rx_state = FM_W4_EVENT_HDR; h4->rx_count = FM_EVENT_HDR_SIZE; protoid = PROTO_SH_FM; break; default: BT_ERR("Unknown HCI packet type %2.2x", (__u8)*ptr); hu->hdev->stat.err_rx++; ptr++; count--; continue; }; ptr++; count--; switch (protoid) { case PROTO_SH_BT: case PROTO_SH_FM: /* Allocate new packet to hold received data */ h4->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC); if (!h4->rx_skb) { BT_ERR("Can't allocate mem for new packet"); h4->rx_state = H4_W4_PACKET_TYPE; h4->rx_count = 0; return -ENOMEM; } h4->rx_skb->dev = (void *) hu->hdev; sh_ldisc_cb(h4->rx_skb)->pkt_type = type; break; #if 0 case PROTO_SH_FM: /* for FM */ h4->rx_skb = bt_skb_alloc(FM_MAX_FRAME_SIZE, GFP_ATOMIC); if (!h4->rx_skb) { BT_ERR("Can't allocate mem for new packet"); h4->rx_state = H4_W4_PACKET_TYPE; h4->rx_count = 0; return -ENOMEM; } /* place holder 0x08 */ /* skb_reserve(h4->rx_skb, 1); */ sh_ldisc_cb(h4->rx_skb)->pkt_type = FM_CH8_PKT; break; #endif case PROTO_SH_MAX: case PROTO_SH_GPS: break; } }
static inline ssize_t vhci_get_user(struct vhci_data *data, struct iov_iter *from) { size_t len = iov_iter_count(from); struct sk_buff *skb; __u8 pkt_type, opcode; int ret; #else static inline ssize_t vhci_get_user(struct vhci_data *data, const struct iovec *iov, unsigned long count) { size_t len = iov_length(iov, count); struct sk_buff *skb; __u8 pkt_type, opcode; unsigned long i; int ret; #endif if (len < 2 || len > HCI_MAX_FRAME_SIZE) return -EINVAL; skb = bt_skb_alloc(len, GFP_KERNEL); if (!skb) return -ENOMEM; #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,18,0) if (copy_from_iter(skb_put(skb, len), len, from) != len) { kfree_skb(skb); return -EFAULT; } #else for (i = 0; i < count; i++) { if (copy_from_user(skb_put(skb, iov[i].iov_len), iov[i].iov_base, iov[i].iov_len)) { kfree_skb(skb); return -EFAULT; } } #endif pkt_type = *((__u8 *) skb->data); skb_pull(skb, 1); switch (pkt_type) { case HCI_EVENT_PKT: case HCI_ACLDATA_PKT: case HCI_SCODATA_PKT: if (!data->hdev) { kfree_skb(skb); return -ENODEV; } bt_cb(skb)->pkt_type = pkt_type; ret = hci_recv_frame(data->hdev, skb); break; case HCI_VENDOR_PKT: if (data->hdev) { kfree_skb(skb); return -EBADFD; } cancel_delayed_work_sync(&data->open_timeout); opcode = *((__u8 *) skb->data); skb_pull(skb, 1); if (skb->len > 0) { kfree_skb(skb); return -EINVAL; } kfree_skb(skb); ret = vhci_create_device(data, opcode); break; default: kfree_skb(skb); return -EINVAL; } return (ret < 0) ? ret : len; }
/** * @brief This function reads data from the card. * * @param priv A pointer to bt_private structure * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE */ static int sd_card_to_host(bt_private * priv) { int ret = BT_STATUS_SUCCESS; u16 buf_len = 0; int buf_block_len; int blksz; struct sk_buff *skb = NULL; u32 type; u8 *payload = NULL; struct hci_dev *hdev = priv->bt_dev.hcidev; struct sdio_mmc_card *card = priv->bt_dev.card; ENTER(); if (!card || !card->func) { PRINTM(ERROR, "BT: card or function is NULL!\n"); ret = BT_STATUS_FAILURE; goto exit; } /* Read the length of data to be transferred */ ret = sd_read_rx_len(priv, &buf_len); if (ret < 0) { PRINTM(ERROR, "BT: card_to_host, read scratch reg failed\n"); ret = BT_STATUS_FAILURE; goto exit; } /* Allocate buffer */ blksz = SD_BLOCK_SIZE; buf_block_len = (buf_len + blksz - 1) / blksz; if (buf_len <= BT_HEADER_LEN || (buf_block_len * blksz) > ALLOC_BUF_SIZE) { PRINTM(ERROR, "BT: card_to_host, invalid packet length: %d\n", buf_len); ret = BT_STATUS_FAILURE; goto exit; } skb = bt_skb_alloc(buf_block_len * blksz + DMA_ALIGNMENT, GFP_ATOMIC); if (skb == NULL) { PRINTM(WARN, "BT: No free skb\n"); goto exit; } if ((u32) skb->data & (DMA_ALIGNMENT - 1)) { skb_put(skb, DMA_ALIGNMENT - ((u32) skb->data & (DMA_ALIGNMENT - 1))); skb_pull(skb, DMA_ALIGNMENT - ((u32) skb->data & (DMA_ALIGNMENT - 1))); } payload = skb->tail; ret = sdio_readsb(card->func, payload, priv->bt_dev.ioport, buf_block_len * blksz); if (ret < 0) { PRINTM(ERROR, "BT: card_to_host, read iomem failed: %d\n", ret); kfree_skb(skb); skb = NULL; ret = BT_STATUS_FAILURE; goto exit; } /* This is SDIO specific header length: byte[2][1][0], type: byte[3] (HCI_COMMAND = 1, ACL_DATA = 2, SCO_DATA = 3, 0xFE = Vendor) */ buf_len = payload[0]; buf_len |= (u16) payload[1] << 8; type = payload[3]; PRINTM(DATA, "BT: SDIO Blk Rd %s: len=%d type=%d\n", hdev->name, buf_len, type); if (buf_len > buf_block_len * blksz) { PRINTM(ERROR, "BT: Drop invalid rx pkt, len in hdr=%d, cmd53 length=%d\n", buf_len, buf_block_len * blksz); ret = BT_STATUS_FAILURE; kfree_skb(skb); skb = NULL; goto exit; } DBG_HEXDUMP(DAT_D, "BT: SDIO Blk Rd", payload, buf_len); switch (type) { case HCI_ACLDATA_PKT: case HCI_SCODATA_PKT: case HCI_EVENT_PKT: bt_cb(skb)->pkt_type = type; skb->dev = (void *) hdev; skb_put(skb, buf_len); skb_pull(skb, BT_HEADER_LEN); if (type == HCI_EVENT_PKT) { if (BT_STATUS_SUCCESS == check_evtpkt(priv, skb)) break; } hci_recv_frame(skb); hdev->stat.byte_rx += buf_len; break; case MRVL_VENDOR_PKT: bt_cb(skb)->pkt_type = HCI_VENDOR_PKT; skb->dev = (void *) hdev; skb_put(skb, buf_len); skb_pull(skb, BT_HEADER_LEN); if (BT_STATUS_SUCCESS != bt_process_event(priv, skb)) hci_recv_frame(skb); hdev->stat.byte_rx += buf_len; break; default: /* Driver specified event and command resp should be handle here */ PRINTM(INFO, "BT: Unknown PKT type:%d\n", type); kfree_skb(skb); skb = NULL; break; } exit: if (ret) { hdev->stat.err_rx++; } LEAVE(); return ret; }
static void bt3c_receive(bt3c_info_t *info) { unsigned int iobase; int size = 0, avail; if (!info) { printk(KERN_WARNING "bt3c_cs: Call of receive for unknown device.\n"); return; } iobase = info->link.io.BasePort1; avail = bt3c_read(iobase, 0x7006); //printk("bt3c_cs: receiving %d bytes\n", avail); bt3c_address(iobase, 0x7480); while (size < avail) { size++; info->hdev.stat.byte_rx++; /* Allocate packet */ if (info->rx_skb == NULL) { info->rx_state = RECV_WAIT_PACKET_TYPE; info->rx_count = 0; if (!(info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { printk(KERN_WARNING "bt3c_cs: Can't allocate mem for new packet.\n"); return; } } if (info->rx_state == RECV_WAIT_PACKET_TYPE) { info->rx_skb->dev = (void *)&(info->hdev); info->rx_skb->pkt_type = inb(iobase + DATA_L); inb(iobase + DATA_H); //printk("bt3c: PACKET_TYPE=%02x\n", info->rx_skb->pkt_type); switch (info->rx_skb->pkt_type) { case HCI_EVENT_PKT: info->rx_state = RECV_WAIT_EVENT_HEADER; info->rx_count = HCI_EVENT_HDR_SIZE; break; case HCI_ACLDATA_PKT: info->rx_state = RECV_WAIT_ACL_HEADER; info->rx_count = HCI_ACL_HDR_SIZE; break; case HCI_SCODATA_PKT: info->rx_state = RECV_WAIT_SCO_HEADER; info->rx_count = HCI_SCO_HDR_SIZE; break; default: /* Unknown packet */ printk(KERN_WARNING "bt3c_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type); info->hdev.stat.err_rx++; clear_bit(HCI_RUNNING, &(info->hdev.flags)); dev_kfree_skb_any(info->rx_skb); info->rx_skb = NULL; break; } } else { __u8 x = inb(iobase + DATA_L); *skb_put(info->rx_skb, 1) = x; inb(iobase + DATA_H); info->rx_count--; if (info->rx_count == 0) { int dlen; struct hci_event_hdr *eh; struct hci_acl_hdr *ah; struct hci_sco_hdr *sh; switch (info->rx_state) { case RECV_WAIT_EVENT_HEADER: eh = (struct hci_event_hdr *)(info->rx_skb->data); info->rx_state = RECV_WAIT_DATA; info->rx_count = eh->plen; break; case RECV_WAIT_ACL_HEADER: ah = (struct hci_acl_hdr *)(info->rx_skb->data); dlen = __le16_to_cpu(ah->dlen); info->rx_state = RECV_WAIT_DATA; info->rx_count = dlen; break; case RECV_WAIT_SCO_HEADER: sh = (struct hci_sco_hdr *)(info->rx_skb->data); info->rx_state = RECV_WAIT_DATA; info->rx_count = sh->dlen; break; case RECV_WAIT_DATA: hci_recv_frame(info->rx_skb); info->rx_skb = NULL; break; } } } } bt3c_io_write(iobase, 0x7006, 0x0000); }
/* Recv data */ static int h4_recv(struct hci_uart *hu, void *data, int count) { struct h4_struct *h4 = hu->priv; register char *ptr; struct hci_event_hdr *eh; struct hci_acl_hdr *ah; struct hci_sco_hdr *sh; register int len, type, dlen; BT_DBG("hu %p count %d rx_state %ld rx_count %ld", hu, count, h4->rx_state, h4->rx_count); ptr = data; while (count) { if (h4->rx_count) { len = min_t(unsigned int, h4->rx_count, count); memcpy(skb_put(h4->rx_skb, len), ptr, len); h4->rx_count -= len; count -= len; ptr += len; if (h4->rx_count) continue; switch (h4->rx_state) { case H4_W4_DATA: BT_DBG("Complete data"); BT_DMP(h4->rx_skb->data, h4->rx_skb->len); hci_recv_frame(h4->rx_skb); h4->rx_state = H4_W4_PACKET_TYPE; h4->rx_skb = NULL; continue; case H4_W4_EVENT_HDR: eh = (struct hci_event_hdr *) h4->rx_skb->data; BT_DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen); h4_check_data_len(h4, eh->plen); continue; case H4_W4_ACL_HDR: ah = (struct hci_acl_hdr *) h4->rx_skb->data; dlen = __le16_to_cpu(ah->dlen); BT_DBG("ACL header: dlen %d", dlen); h4_check_data_len(h4, dlen); continue; case H4_W4_SCO_HDR: sh = (struct hci_sco_hdr *) h4->rx_skb->data; BT_DBG("SCO header: dlen %d", sh->dlen); h4_check_data_len(h4, sh->dlen); continue; } } /* H4_W4_PACKET_TYPE */ switch (*ptr) { case HCI_EVENT_PKT: BT_DBG("Event packet"); h4->rx_state = H4_W4_EVENT_HDR; h4->rx_count = HCI_EVENT_HDR_SIZE; type = HCI_EVENT_PKT; break; case HCI_ACLDATA_PKT: BT_DBG("ACL packet"); h4->rx_state = H4_W4_ACL_HDR; h4->rx_count = HCI_ACL_HDR_SIZE; type = HCI_ACLDATA_PKT; break; case HCI_SCODATA_PKT: BT_DBG("SCO packet"); h4->rx_state = H4_W4_SCO_HDR; h4->rx_count = HCI_SCO_HDR_SIZE; type = HCI_SCODATA_PKT; break; default: BT_ERR("Unknown HCI packet type %2.2x", (__u8)*ptr); hu->hdev->stat.err_rx++; ptr++; count--; continue; }; ptr++; count--; /* Allocate packet */ h4->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC); if (!h4->rx_skb) { BT_ERR("Can't allocate mem for new packet"); h4->rx_state = H4_W4_PACKET_TYPE; h4->rx_count = 0; return 0; } h4->rx_skb->dev = (void *) hu->hdev; h4->rx_skb->pkt_type = type; }
static int bfusb_send_frame(struct sk_buff *skb) { struct hci_dev *hdev = (struct hci_dev *) skb->dev; struct bfusb_data *data; struct sk_buff *nskb; unsigned char buf[3]; int sent = 0, size, count; BT_DBG("hdev %p skb %p type %d len %d", hdev, skb, bt_cb(skb)->pkt_type, skb->len); if (!hdev) { BT_ERR("Frame for unknown HCI device (hdev=NULL)"); return -ENODEV; } if (!test_bit(HCI_RUNNING, &hdev->flags)) return -EBUSY; data = hdev->driver_data; switch (bt_cb(skb)->pkt_type) { case HCI_COMMAND_PKT: hdev->stat.cmd_tx++; break; case HCI_ACLDATA_PKT: hdev->stat.acl_tx++; break; case HCI_SCODATA_PKT: hdev->stat.sco_tx++; break; }; /* Prepend skb with frame type */ memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); count = skb->len; /* Max HCI frame size seems to be 1511 + 1 */ nskb = bt_skb_alloc(count + 32, GFP_ATOMIC); if (!nskb) { BT_ERR("Can't allocate memory for new packet"); return -ENOMEM; } nskb->dev = (void *) data; while (count) { size = min_t(uint, count, BFUSB_MAX_BLOCK_SIZE); buf[0] = 0xc1 | ((sent == 0) ? 0x04 : 0) | ((count == size) ? 0x08 : 0); buf[1] = 0x00; buf[2] = (size == BFUSB_MAX_BLOCK_SIZE) ? 0 : size; memcpy(skb_put(nskb, 3), buf, 3); skb_copy_from_linear_data_offset(skb, sent, skb_put(nskb, size), size); sent += size; count -= size; } /* Don't send frame with multiple size of bulk max packet */ if ((nskb->len % data->bulk_pkt_size) == 0) { buf[0] = 0xdd; buf[1] = 0x00; memcpy(skb_put(nskb, 2), buf, 2); } read_lock(&data->lock); skb_queue_tail(&data->transmit_q, nskb); bfusb_tx_wakeup(data); read_unlock(&data->lock); kfree_skb(skb); return 0; }
/* Recv data */ static int ll_recv(struct hci_uart *hu, void *data, int count) { struct ll_struct *ll = hu->priv; char *ptr; struct hci_event_hdr *eh; struct hci_acl_hdr *ah; struct hci_sco_hdr *sh; int len, type, dlen; BT_DBG("hu %p count %d rx_state %ld rx_count %ld", hu, count, ll->rx_state, ll->rx_count); ptr = data; while (count) { if (ll->rx_count) { len = min_t(unsigned int, ll->rx_count, count); memcpy(skb_put(ll->rx_skb, len), ptr, len); ll->rx_count -= len; count -= len; ptr += len; if (ll->rx_count) continue; switch (ll->rx_state) { case HCILL_W4_DATA: BT_DBG("Complete data"); hci_recv_frame(hu->hdev, ll->rx_skb); ll->rx_state = HCILL_W4_PACKET_TYPE; ll->rx_skb = NULL; continue; case HCILL_W4_EVENT_HDR: eh = hci_event_hdr(ll->rx_skb); BT_DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen); ll_check_data_len(hu->hdev, ll, eh->plen); continue; case HCILL_W4_ACL_HDR: ah = hci_acl_hdr(ll->rx_skb); dlen = __le16_to_cpu(ah->dlen); BT_DBG("ACL header: dlen %d", dlen); ll_check_data_len(hu->hdev, ll, dlen); continue; case HCILL_W4_SCO_HDR: sh = hci_sco_hdr(ll->rx_skb); BT_DBG("SCO header: dlen %d", sh->dlen); ll_check_data_len(hu->hdev, ll, sh->dlen); continue; } } /* HCILL_W4_PACKET_TYPE */ switch (*ptr) { case HCI_EVENT_PKT: BT_DBG("Event packet"); ll->rx_state = HCILL_W4_EVENT_HDR; ll->rx_count = HCI_EVENT_HDR_SIZE; type = HCI_EVENT_PKT; break; case HCI_ACLDATA_PKT: BT_DBG("ACL packet"); ll->rx_state = HCILL_W4_ACL_HDR; ll->rx_count = HCI_ACL_HDR_SIZE; type = HCI_ACLDATA_PKT; break; case HCI_SCODATA_PKT: BT_DBG("SCO packet"); ll->rx_state = HCILL_W4_SCO_HDR; ll->rx_count = HCI_SCO_HDR_SIZE; type = HCI_SCODATA_PKT; break; /* HCILL signals */ case HCILL_GO_TO_SLEEP_IND: BT_DBG("HCILL_GO_TO_SLEEP_IND packet"); ll_device_want_to_sleep(hu); ptr++; count--; continue; case HCILL_GO_TO_SLEEP_ACK: /* shouldn't happen */ BT_ERR("received HCILL_GO_TO_SLEEP_ACK (in state %ld)", ll->hcill_state); ptr++; count--; continue; case HCILL_WAKE_UP_IND: BT_DBG("HCILL_WAKE_UP_IND packet"); ll_device_want_to_wakeup(hu); ptr++; count--; continue; case HCILL_WAKE_UP_ACK: BT_DBG("HCILL_WAKE_UP_ACK packet"); ll_device_woke_up(hu); ptr++; count--; continue; default: BT_ERR("Unknown HCI packet type %2.2x", (__u8)*ptr); hu->hdev->stat.err_rx++; ptr++; count--; continue; } ptr++; count--; /* Allocate packet */ ll->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC); if (!ll->rx_skb) { BT_ERR("Can't allocate mem for new packet"); ll->rx_state = HCILL_W4_PACKET_TYPE; ll->rx_count = 0; return -ENOMEM; } bt_cb(ll->rx_skb)->pkt_type = type; }
static int btusb_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_endpoint_descriptor *ep_desc; struct btusb_data *data; struct hci_dev *hdev; int i, err; BT_DBG("intf %p id %p", intf, id); /* interface numbers are hardcoded in the spec */ if (intf->cur_altsetting->desc.bInterfaceNumber != 0) return -ENODEV; if (!id->driver_info) { const struct usb_device_id *match; match = usb_match_id(intf, blacklist_table); if (match) id = match; } if (id->driver_info == BTUSB_IGNORE) return -ENODEV; if (ignore_dga && id->driver_info & BTUSB_DIGIANSWER) return -ENODEV; if (ignore_csr && id->driver_info & BTUSB_CSR) return -ENODEV; if (ignore_sniffer && id->driver_info & BTUSB_SNIFFER) return -ENODEV; data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) { ep_desc = &intf->cur_altsetting->endpoint[i].desc; if (!data->intr_ep && usb_endpoint_is_int_in(ep_desc)) { data->intr_ep = ep_desc; continue; } if (!data->bulk_tx_ep && usb_endpoint_is_bulk_out(ep_desc)) { data->bulk_tx_ep = ep_desc; continue; } if (!data->bulk_rx_ep && usb_endpoint_is_bulk_in(ep_desc)) { data->bulk_rx_ep = ep_desc; continue; } } if (!data->intr_ep || !data->bulk_tx_ep || !data->bulk_rx_ep) { kfree(data); return -ENODEV; } data->cmdreq_type = USB_TYPE_CLASS; data->udev = interface_to_usbdev(intf); data->intf = intf; spin_lock_init(&data->lock); INIT_WORK(&data->work, btusb_work); INIT_WORK(&data->waker, btusb_waker); spin_lock_init(&data->txlock); init_usb_anchor(&data->tx_anchor); init_usb_anchor(&data->intr_anchor); init_usb_anchor(&data->bulk_anchor); init_usb_anchor(&data->isoc_anchor); init_usb_anchor(&data->deferred); hdev = hci_alloc_dev(); if (!hdev) { kfree(data); return -ENOMEM; } hdev->bus = HCI_USB; hdev->driver_data = data; data->hdev = hdev; SET_HCIDEV_DEV(hdev, &intf->dev); hdev->open = btusb_open; hdev->close = btusb_close; hdev->flush = btusb_flush; hdev->send = btusb_send_frame; hdev->destruct = btusb_destruct; hdev->notify = btusb_notify; hdev->owner = THIS_MODULE; /* Interface numbers are hardcoded in the specification */ data->isoc = usb_ifnum_to_if(data->udev, 1); if (!reset) set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks); if (force_scofix || id->driver_info & BTUSB_WRONG_SCO_MTU) { if (!disable_scofix) set_bit(HCI_QUIRK_FIXUP_BUFFER_SIZE, &hdev->quirks); } if (id->driver_info & BTUSB_BROKEN_ISOC) data->isoc = NULL; if (id->driver_info & BTUSB_DIGIANSWER) { data->cmdreq_type = USB_TYPE_VENDOR; set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks); } if (id->driver_info & BTUSB_CSR) { struct usb_device *udev = data->udev; /* Old firmware would otherwise execute USB reset */ if (le16_to_cpu(udev->descriptor.bcdDevice) < 0x117) set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks); } if (id->driver_info & BTUSB_SNIFFER) { struct usb_device *udev = data->udev; /* New sniffer firmware has crippled HCI interface */ if (le16_to_cpu(udev->descriptor.bcdDevice) > 0x997) set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks); data->isoc = NULL; } if (id->driver_info & BTUSB_BCM92035) { unsigned char cmd[] = { 0x3b, 0xfc, 0x01, 0x00 }; struct sk_buff *skb; skb = bt_skb_alloc(sizeof(cmd), GFP_KERNEL); if (skb) { memcpy(skb_put(skb, sizeof(cmd)), cmd, sizeof(cmd)); skb_queue_tail(&hdev->driver_init, skb); } } if (data->isoc) { err = usb_driver_claim_interface(&btusb_driver, data->isoc, data); if (err < 0) { hci_free_dev(hdev); kfree(data); return err; } } err = hci_register_dev(hdev); if (err < 0) { hci_free_dev(hdev); kfree(data); return err; } usb_set_intfdata(intf, data); return 0; }
static void dtl1_receive(struct dtl1_info *info) { unsigned int iobase; struct nsh *nsh; int boguscount = 0; if (!info) { BT_ERR("Unknown device"); return; } iobase = info->p_dev->resource[0]->start; do { info->hdev->stat.byte_rx++; /* Allocate packet */ if (info->rx_skb == NULL) { info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC); if (!info->rx_skb) { BT_ERR("Can't allocate mem for new packet"); info->rx_state = RECV_WAIT_NSH; info->rx_count = NSHL; return; } } *skb_put(info->rx_skb, 1) = inb(iobase + UART_RX); nsh = (struct nsh *)info->rx_skb->data; info->rx_count--; if (info->rx_count == 0) { switch (info->rx_state) { case RECV_WAIT_NSH: info->rx_state = RECV_WAIT_DATA; info->rx_count = nsh->len + (nsh->len & 0x0001); break; case RECV_WAIT_DATA: bt_cb(info->rx_skb)->pkt_type = nsh->type; /* remove PAD byte if it exists */ if (nsh->len & 0x0001) { info->rx_skb->tail--; info->rx_skb->len--; } /* remove NSH */ skb_pull(info->rx_skb, NSHL); switch (bt_cb(info->rx_skb)->pkt_type) { case 0x80: /* control data for the Nokia Card */ dtl1_control(info, info->rx_skb); break; case 0x82: case 0x83: case 0x84: /* send frame to the HCI layer */ bt_cb(info->rx_skb)->pkt_type &= 0x0f; hci_recv_frame(info->hdev, info->rx_skb); break; default: /* unknown packet */ BT_ERR("Unknown HCI packet with type 0x%02x received", bt_cb(info->rx_skb)->pkt_type); kfree_skb(info->rx_skb); break; } info->rx_state = RECV_WAIT_NSH; info->rx_count = NSHL; info->rx_skb = NULL; break; } } /* Make sure we don't stay here too long */ if (boguscount++ > 32) break; } while (inb(iobase + UART_LSR) & UART_LSR_DR); }
/* Recv data */ static int brcm_recv(struct hci_uart *hu, void *data, int count) { struct brcm_struct *brcm = hu->priv; register char *ptr; struct hci_event_hdr *eh; struct hci_acl_hdr *ah; struct hci_sco_hdr *sh; register int len, type, dlen; BT_DBG("hu %p count %d rx_state %ld rx_count %ld", hu, count, brcm->rx_state, brcm->rx_count); serial_awake(hu); brcm->is_there_activity = 1; if (brcm->hcibrcm_state == HCIBRCM_ASLEEP) { BT_DBG("Assert wake signal, moves to AWAKE"); /* assert BT_WAKE signal */ assert_bt_wake(); brcm->hcibrcm_state = HCIBRCM_AWAKE; } ptr = data; while (count) { if (brcm->rx_count) { len = min_t(unsigned int, brcm->rx_count, count); memcpy(skb_put(brcm->rx_skb, len), ptr, len); brcm->rx_count -= len; count -= len; ptr += len; if (brcm->rx_count) continue; switch (brcm->rx_state) { case HCIBRCM_W4_DATA: BT_DBG("Complete data"); hci_recv_frame(brcm->rx_skb); brcm->rx_state = HCIBRCM_W4_PACKET_TYPE; brcm->rx_skb = NULL; continue; case HCIBRCM_W4_EVENT_HDR: eh = (struct hci_event_hdr *) brcm->rx_skb->data; BT_DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen); brcm_check_data_len(brcm, eh->plen); continue; case HCIBRCM_W4_ACL_HDR: ah = (struct hci_acl_hdr *) brcm->rx_skb->data; dlen = __le16_to_cpu(ah->dlen); BT_DBG("ACL header: dlen %d", dlen); brcm_check_data_len(brcm, dlen); continue; case HCIBRCM_W4_SCO_HDR: sh = (struct hci_sco_hdr *) brcm->rx_skb->data; BT_DBG("SCO header: dlen %d", sh->dlen); brcm_check_data_len(brcm, sh->dlen); continue; } } /* HCIBRCM_W4_PACKET_TYPE */ switch (*ptr) { case HCI_EVENT_PKT: BT_DBG("Event packet"); brcm->rx_state = HCIBRCM_W4_EVENT_HDR; brcm->rx_count = HCI_EVENT_HDR_SIZE; type = HCI_EVENT_PKT; break; case HCI_ACLDATA_PKT: BT_DBG("ACL packet"); brcm->rx_state = HCIBRCM_W4_ACL_HDR; brcm->rx_count = HCI_ACL_HDR_SIZE; type = HCI_ACLDATA_PKT; break; case HCI_SCODATA_PKT: BT_DBG("SCO packet"); brcm->rx_state = HCIBRCM_W4_SCO_HDR; brcm->rx_count = HCI_SCO_HDR_SIZE; type = HCI_SCODATA_PKT; break; /* HCIBRCM signals */ case HCIBRCM_GO_TO_SLEEP_IND: BT_DBG("HCIBRCM_GO_TO_SLEEP_IND packet"); brcm_device_want_to_sleep(hu); ptr++; count--; continue; case HCIBRCM_GO_TO_SLEEP_ACK: /* shouldn't happen */ BT_ERR("received HCIBRCM_GO_TO_SLEEP_ACK (in state %ld)", brcm->hcibrcm_state); ptr++; count--; continue; case HCIBRCM_WAKE_UP_IND: BT_DBG("HCIBRCM_WAKE_UP_IND packet"); brcm_device_want_to_wakeup(hu); ptr++; count--; continue; case HCIBRCM_WAKE_UP_ACK: BT_DBG("HCIBRCM_WAKE_UP_ACK packet"); brcm_device_woke_up(hu); ptr++; count--; continue; default: BT_ERR("Unknown HCI packet type %2.2x", (__u8)*ptr); hu->hdev->stat.err_rx++; ptr++; count--; continue; }; ptr++; count--; /* Abrcmocate packet */ brcm->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC); if (!brcm->rx_skb) { BT_ERR("Can't allocate mem for new packet"); brcm->rx_state = HCIBRCM_W4_PACKET_TYPE; brcm->rx_count = 0; return 0; } brcm->rx_skb->dev = (void *) hu->hdev; bt_cb(brcm->rx_skb)->pkt_type = type; }
struct sk_buff *h4_recv_buf(struct hci_dev *hdev, struct sk_buff *skb, const unsigned char *buffer, int count, const struct h4_recv_pkt *pkts, int pkts_count) { struct hci_uart *hu = hci_get_drvdata(hdev); u8 alignment = hu->alignment ? hu->alignment : 1; while (count) { int i, len; /* remove padding bytes from buffer */ for (; hu->padding && count > 0; hu->padding--) { count--; buffer++; } if (!count) break; if (!skb) { for (i = 0; i < pkts_count; i++) { if (buffer[0] != (&pkts[i])->type) continue; skb = bt_skb_alloc((&pkts[i])->maxlen, GFP_ATOMIC); if (!skb) return ERR_PTR(-ENOMEM); hci_skb_pkt_type(skb) = (&pkts[i])->type; hci_skb_expect(skb) = (&pkts[i])->hlen; break; } /* Check for invalid packet type */ if (!skb) return ERR_PTR(-EILSEQ); count -= 1; buffer += 1; } len = min_t(uint, hci_skb_expect(skb) - skb->len, count); skb_put_data(skb, buffer, len); count -= len; buffer += len; /* Check for partial packet */ if (skb->len < hci_skb_expect(skb)) continue; for (i = 0; i < pkts_count; i++) { if (hci_skb_pkt_type(skb) == (&pkts[i])->type) break; } if (i >= pkts_count) { kfree_skb(skb); return ERR_PTR(-EILSEQ); } if (skb->len == (&pkts[i])->hlen) { u16 dlen; switch ((&pkts[i])->lsize) { case 0: /* No variable data length */ dlen = 0; break; case 1: /* Single octet variable length */ dlen = skb->data[(&pkts[i])->loff]; hci_skb_expect(skb) += dlen; if (skb_tailroom(skb) < dlen) { kfree_skb(skb); return ERR_PTR(-EMSGSIZE); } break; case 2: /* Double octet variable length */ dlen = get_unaligned_le16(skb->data + (&pkts[i])->loff); hci_skb_expect(skb) += dlen; if (skb_tailroom(skb) < dlen) { kfree_skb(skb); return ERR_PTR(-EMSGSIZE); } break; default: /* Unsupported variable length */ kfree_skb(skb); return ERR_PTR(-EILSEQ); } if (!dlen) { hu->padding = (skb->len - 1) % alignment; hu->padding = (alignment - hu->padding) % alignment; /* No more data, complete frame */ (&pkts[i])->recv(hdev, skb); skb = NULL; } } else { hu->padding = (skb->len - 1) % alignment; hu->padding = (alignment - hu->padding) % alignment; /* Complete frame */ (&pkts[i])->recv(hdev, skb); skb = NULL; } } return skb; }