static int btusb_send_frame(struct sk_buff *skb) { struct hci_dev *hdev = (struct hci_dev *) skb->dev; struct btusb_data *data = hci_get_drvdata(hdev); struct usb_ctrlrequest *dr; struct urb *urb; unsigned int pipe; int err; BT_DBG("%s", hdev->name); if (!test_bit(HCI_RUNNING, &hdev->flags)) return -EBUSY; switch (bt_cb(skb)->pkt_type) { case HCI_COMMAND_PKT: urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) return -ENOMEM; dr = kmalloc(sizeof(*dr), GFP_ATOMIC); if (!dr) { usb_free_urb(urb); return -ENOMEM; } dr->bRequestType = data->cmdreq_type; dr->bRequest = 0; dr->wIndex = 0; dr->wValue = 0; dr->wLength = __cpu_to_le16(skb->len); pipe = usb_sndctrlpipe(data->udev, 0x00); usb_fill_control_urb(urb, data->udev, pipe, (void *) dr, skb->data, skb->len, btusb_tx_complete, skb); hdev->stat.cmd_tx++; break; case HCI_ACLDATA_PKT: if (!data->bulk_tx_ep) return -ENODEV; urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) return -ENOMEM; pipe = usb_sndbulkpipe(data->udev, data->bulk_tx_ep->bEndpointAddress); usb_fill_bulk_urb(urb, data->udev, pipe, skb->data, skb->len, btusb_tx_complete, skb); hdev->stat.acl_tx++; break; case HCI_SCODATA_PKT: if (!data->isoc_tx_ep || hdev->conn_hash.sco_num < 1) return -ENODEV; urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, GFP_ATOMIC); if (!urb) return -ENOMEM; pipe = usb_sndisocpipe(data->udev, data->isoc_tx_ep->bEndpointAddress); usb_fill_int_urb(urb, data->udev, pipe, skb->data, skb->len, btusb_isoc_tx_complete, skb, data->isoc_tx_ep->bInterval); urb->transfer_flags = URB_ISO_ASAP; __fill_isoc_descriptor(urb, skb->len, le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize)); hdev->stat.sco_tx++; goto skip_waking; default: return -EILSEQ; } err = inc_tx(data); if (err) { usb_anchor_urb(urb, &data->deferred); schedule_work(&data->waker); err = 0; goto done; } skip_waking: usb_anchor_urb(urb, &data->tx_anchor); err = usb_submit_urb(urb, GFP_ATOMIC); if (err < 0) { if (err != -EPERM && err != -ENODEV) BT_ERR("%s urb %p submission failed (%d)", hdev->name, urb, -err); kfree(urb->setup_packet); usb_unanchor_urb(urb); } else { usb_mark_last_busy(data->udev); } done: usb_free_urb(urb); return err; }
static void bluecard_write_wakeup(bluecard_info_t *info) { if (!info) { BT_ERR("Unknown device"); return; } if (!test_bit(XMIT_SENDING_READY, &(info->tx_state))) return; if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) { set_bit(XMIT_WAKEUP, &(info->tx_state)); return; } do { register unsigned int iobase = info->p_dev->resource[0]->start; register unsigned int offset; register unsigned char command; register unsigned long ready_bit; register struct sk_buff *skb; register int len; clear_bit(XMIT_WAKEUP, &(info->tx_state)); if (!pcmcia_dev_present(info->p_dev)) return; if (test_bit(XMIT_BUFFER_NUMBER, &(info->tx_state))) { if (!test_bit(XMIT_BUF_TWO_READY, &(info->tx_state))) break; offset = 0x10; command = REG_COMMAND_TX_BUF_TWO; ready_bit = XMIT_BUF_TWO_READY; } else { if (!test_bit(XMIT_BUF_ONE_READY, &(info->tx_state))) break; offset = 0x00; command = REG_COMMAND_TX_BUF_ONE; ready_bit = XMIT_BUF_ONE_READY; } if (!(skb = skb_dequeue(&(info->txq)))) break; if (bt_cb(skb)->pkt_type & 0x80) { /* Disable RTS */ info->ctrl_reg |= REG_CONTROL_RTS; outb(info->ctrl_reg, iobase + REG_CONTROL); } /* Activate LED */ bluecard_enable_activity_led(info); /* Send frame */ len = bluecard_write(iobase, offset, skb->data, skb->len); /* Tell the FPGA to send the data */ outb_p(command, iobase + REG_COMMAND); /* Mark the buffer as dirty */ clear_bit(ready_bit, &(info->tx_state)); if (bt_cb(skb)->pkt_type & 0x80) { DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); DEFINE_WAIT(wait); unsigned char baud_reg; switch (bt_cb(skb)->pkt_type) { case PKT_BAUD_RATE_460800: baud_reg = REG_CONTROL_BAUD_RATE_460800; break; case PKT_BAUD_RATE_230400: baud_reg = REG_CONTROL_BAUD_RATE_230400; break; case PKT_BAUD_RATE_115200: baud_reg = REG_CONTROL_BAUD_RATE_115200; break; case PKT_BAUD_RATE_57600: /* Fall through... */ default: baud_reg = REG_CONTROL_BAUD_RATE_57600; break; } /* Wait until the command reaches the baseband */ prepare_to_wait(&wq, &wait, TASK_INTERRUPTIBLE); schedule_timeout(HZ/10); finish_wait(&wq, &wait); /* Set baud on baseband */ info->ctrl_reg &= ~0x03; info->ctrl_reg |= baud_reg; outb(info->ctrl_reg, iobase + REG_CONTROL); /* Enable RTS */ info->ctrl_reg &= ~REG_CONTROL_RTS; outb(info->ctrl_reg, iobase + REG_CONTROL); /* Wait before the next HCI packet can be send */ prepare_to_wait(&wq, &wait, TASK_INTERRUPTIBLE); schedule_timeout(HZ); finish_wait(&wq, &wait); } if (len == skb->len) { kfree_skb(skb); } else { skb_pull(skb, len); skb_queue_head(&(info->txq), skb); } info->hdev->stat.byte_tx += len; /* Change buffer */ change_bit(XMIT_BUFFER_NUMBER, &(info->tx_state)); } while (test_bit(XMIT_WAKEUP, &(info->tx_state))); clear_bit(XMIT_SENDING, &(info->tx_state)); }
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; } iobase = info->p_dev->resource[0]->start; 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; }
/** * st_int_recv - ST's internal receive function. * Decodes received RAW data and forwards to corresponding * client drivers (Bluetooth,FM,GPS..etc). * This can receive various types of packets, * HCI-Events, ACL, SCO, 4 types of HCI-LL PM packets * CH-8 packets from FM, CH-9 packets from GPS cores. */ 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_debug("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_debug("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; } }
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); }
/* 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"); hci_recv_frame(h4->rx_skb); h4->rx_state = H4_W4_PACKET_TYPE; h4->rx_skb = NULL; 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, 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, 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, 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 -ENOMEM; } h4->rx_skb->dev = (void *) hu->hdev; bt_cb(h4->rx_skb)->pkt_type = type; }
/* 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); 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->btwake_gpio, brcm->lqos_node, hu->tty); brcm->hcibrcm_state = HCIBRCM_AWAKE; mod_timer(&sleep_timer, jiffies + msecs_to_jiffies(TIMER_PERIOD)); } 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: //("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) { 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 */ dlen = 0; 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); } if (!dlen) { /* No more data, complete frame */ (&pkts[i])->recv(hdev, skb); skb = NULL; } } else { /* Complete frame */ (&pkts[i])->recv(hdev, skb); skb = NULL; } } return skb; }