static void btusb_tx_complete(struct urb *urb)
{
    struct sk_buff *skb = urb->context;
    struct hci_dev *hdev = (struct hci_dev *) skb->dev;
    struct btusb_data *data = GET_DRV_DATA(hdev);

//	RTKBT_DBG("btusb_tx_complete %s urb %p status %d count %d", hdev->name,
//					urb, urb->status, urb->actual_length);

    if (!test_bit(HCI_RUNNING, &hdev->flags))
        goto done;

    if (!urb->status)
        hdev->stat.byte_tx += urb->transfer_buffer_length;
    else
        hdev->stat.err_tx++;

done:
    spin_lock(&data->txlock);
    data->tx_in_flight--;
    spin_unlock(&data->txlock);

    kfree(urb->setup_packet);

    kfree_skb(skb);
}
Пример #2
0
int hci_uart_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
#endif
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
	struct hci_dev *hdev = (struct hci_dev *)skb->dev;
#endif
	struct hci_uart *hu;

	if (!hdev) {
		BT_ERR("Frame for unknown device (hdev=NULL)");
		return -ENODEV;
	}

	if (!test_bit(HCI_RUNNING, &hdev->flags))
		return -EBUSY;

	hu = GET_DRV_DATA(hdev);	//(struct hci_uart *) hdev->driver_data;

	BT_DBG("%s: type %d len %d", hdev->name, bt_cb(skb)->pkt_type,
	       skb->len);

#ifdef BTCOEX
	if (bt_cb(skb)->pkt_type == HCI_COMMAND_PKT)
		rtk_btcoex_parse_cmd(skb->data, skb->len);
	if (bt_cb(skb)->pkt_type == HCI_ACLDATA_PKT)
		rtk_btcoex_parse_l2cap_data_tx(skb->data, skb->len);
#endif

	hu->proto->enqueue(hu, skb);

	hci_uart_tx_wakeup(hu);

	return 0;
}
static int btusb_open(struct hci_dev *hdev)
{
    struct btusb_data *data = GET_DRV_DATA(hdev);
    int err;

    err = usb_autopm_get_interface(data->intf);
    if (err < 0)
        return err;

    data->intf->needs_remote_wakeup = 1;
    RTKBT_DBG("%s start pm_usage_cnt(0x%x)",__FUNCTION__,atomic_read(&(data->intf ->pm_usage_cnt)));

    /*******************************/
    if (0 == atomic_read(&hdev->promisc))
    {
        RTKBT_DBG("btusb_open hdev->promisc ==0");
        err = -1;
        //goto failed;
    }
    err = download_patch(data->intf);
    if (err < 0) goto failed;
    /*******************************/

    if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
        goto done;

    if (test_and_set_bit(BTUSB_INTR_RUNNING, &data->flags))
        goto done;

    err = btusb_submit_intr_urb(hdev, GFP_KERNEL);
    if (err < 0)
        goto failed;

    err = btusb_submit_bulk_urb(hdev, GFP_KERNEL);
    if (err < 0) {
        mdelay(URB_CANCELING_DELAY_MS);      // Added by Realtek
        usb_kill_anchored_urbs(&data->intr_anchor);
        goto failed;
    }

    set_bit(BTUSB_BULK_RUNNING, &data->flags);
    btusb_submit_bulk_urb(hdev, GFP_KERNEL);

done:
    usb_autopm_put_interface(data->intf);
    RTKBT_DBG("%s end  pm_usage_cnt(0x%x)",__FUNCTION__,atomic_read(&(data->intf ->pm_usage_cnt)));

    return 0;

failed:
    clear_bit(BTUSB_INTR_RUNNING, &data->flags);
    clear_bit(HCI_RUNNING, &hdev->flags);
    usb_autopm_put_interface(data->intf);
    RTKBT_DBG("%s failed  pm_usage_cnt(0x%x)",__FUNCTION__,atomic_read(&(data->intf ->pm_usage_cnt)));
    return err;
}
static int btusb_flush(struct hci_dev *hdev)
{
    struct btusb_data *data = GET_DRV_DATA(hdev);

    RTKBT_DBG("%s add delay ",__FUNCTION__);
    mdelay(URB_CANCELING_DELAY_MS);     // Added by Realtek
    usb_kill_anchored_urbs(&data->tx_anchor);

    return 0;
}
static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags)
{
    struct btusb_data *data = GET_DRV_DATA(hdev);
    struct urb *urb;
    unsigned char *buf;
    unsigned int pipe;
    int err, size;

    BT_DBG("%s", hdev->name);

    if (!data->isoc_rx_ep)
        return -ENODEV;

    urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, mem_flags);
    if (!urb)
        return -ENOMEM;

    size = le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize) *
           BTUSB_MAX_ISOC_FRAMES;

    buf = kmalloc(size, mem_flags);
    if (!buf) {
        usb_free_urb(urb);
        return -ENOMEM;
    }

    pipe = usb_rcvisocpipe(data->udev, data->isoc_rx_ep->bEndpointAddress);

    urb->dev      = data->udev;
    urb->pipe     = pipe;
    urb->context  = hdev;
    urb->complete = btusb_isoc_complete;
    urb->interval = data->isoc_rx_ep->bInterval;

    urb->transfer_flags  = URB_FREE_BUFFER | URB_ISO_ASAP;
    urb->transfer_buffer = buf;
    urb->transfer_buffer_length = size;

    __fill_isoc_descriptor(urb, size,
                           le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize));

    usb_anchor_urb(urb, &data->isoc_anchor);

    err = usb_submit_urb(urb, mem_flags);
    if (err < 0) {
        BT_ERR("btusb_submit_isoc_urb %s urb %p submission failed (%d)",
               hdev->name, urb, -err);
        usb_unanchor_urb(urb);
    }

    usb_free_urb(urb);

    return err;
}
static void btusb_notify(struct hci_dev *hdev, unsigned int evt)
{
    struct btusb_data *data = GET_DRV_DATA(hdev);

    BT_DBG("%s evt %d", hdev->name, evt);
    RTKBT_DBG("btusb_notify : %s evt %d", hdev->name, evt);

    if (hdev->conn_hash.sco_num != data->sco_num) {
        data->sco_num = hdev->conn_hash.sco_num;
        schedule_work(&data->work);
    }
}
static void btusb_intr_complete(struct urb *urb)
{
    struct hci_dev *hdev = urb->context;
    struct btusb_data *data = GET_DRV_DATA(hdev);
    int err;

    /*	struct usb_device    *dev ;
    	u8* opcode = (u8*)(urb->transfer_buffer);
    	uint wlength = urb->actual_length;
    	uint icount=0;


    	RTKBT_DBG("btusb_intr_complete %s urb %p status %d count %d ", hdev->name,
    					urb, urb->status, urb->actual_length);

    	for(icount=0;icount <wlength;icount++)
    	{
    	   		printk("0x%x ",*(opcode+icount) );
    	}
    */
    if (!test_bit(HCI_RUNNING, &hdev->flags))
        return;

    if (urb->status == 0) {
        hdev->stat.byte_rx += urb->actual_length;

        if (hci_recv_fragment(hdev, HCI_EVENT_PKT,
                              urb->transfer_buffer,
                              urb->actual_length) < 0) {
            BT_ERR("%s corrupted event packet", hdev->name);
            hdev->stat.err_rx++;
        }
    }

    if (!test_bit(BTUSB_INTR_RUNNING, &data->flags))
        return;

    usb_mark_last_busy(data->udev);
    usb_anchor_urb(urb, &data->intr_anchor);

    err = usb_submit_urb(urb, GFP_ATOMIC);
    if (err < 0) {
        /* -EPERM: urb is being killed;
         * -ENODEV: device got disconnected */
        if (err != -EPERM && err != -ENODEV)
            BT_ERR("btusb_intr_complete %s urb %p failed to resubmit (%d)",
                   hdev->name, urb, -err);
        usb_unanchor_urb(urb);
        //	dev = urb->dev;
        //	RTKBT_DBG("dev->state = %d ",dev->state);
    }
}
static void btusb_isoc_complete(struct urb *urb)
{
    struct hci_dev *hdev = urb->context;
    struct btusb_data *data = GET_DRV_DATA(hdev);
    int i, err;

    BT_DBG("%s urb %p status %d count %d", hdev->name,
           urb, urb->status, urb->actual_length);

    if (!test_bit(HCI_RUNNING, &hdev->flags))
        return;

    if (urb->status == 0) {
        for (i = 0; i < urb->number_of_packets; i++) {
            unsigned int offset = urb->iso_frame_desc[i].offset;
            unsigned int length = urb->iso_frame_desc[i].actual_length;

            if (urb->iso_frame_desc[i].status)
                continue;

            hdev->stat.byte_rx += length;

            if (hci_recv_fragment(hdev, HCI_SCODATA_PKT,
                                  urb->transfer_buffer + offset,
                                  length) < 0) {
                BT_ERR("%s corrupted SCO packet", hdev->name);
                hdev->stat.err_rx++;
            }
        }
    }

    if (!test_bit(BTUSB_ISOC_RUNNING, &data->flags))
        return;

    usb_anchor_urb(urb, &data->isoc_anchor);

    err = usb_submit_urb(urb, GFP_ATOMIC);
    if (err < 0) {
        /* -EPERM: urb is being killed;
         * -ENODEV: device got disconnected */
        if (err != -EPERM && err != -ENODEV)
            BT_ERR("btusb_isoc_complete %s urb %p failed to resubmit (%d)",
                   hdev->name, urb, -err);
        usb_unanchor_urb(urb);
    }
}
static int btusb_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags)
{
    struct btusb_data *data = GET_DRV_DATA(hdev);
    struct urb *urb;
    unsigned char *buf;
    unsigned int pipe;
    int err, size;

    BT_DBG("%s", hdev->name);

    if (!data->intr_ep)
        return -ENODEV;

    urb = usb_alloc_urb(0, mem_flags);
    if (!urb)
        return -ENOMEM;

    size = le16_to_cpu(data->intr_ep->wMaxPacketSize);

    buf = kmalloc(size, mem_flags);
    if (!buf) {
        usb_free_urb(urb);
        return -ENOMEM;
    }

    pipe = usb_rcvintpipe(data->udev, data->intr_ep->bEndpointAddress);

    usb_fill_int_urb(urb, data->udev, pipe, buf, size,
                     btusb_intr_complete, hdev,
                     data->intr_ep->bInterval);

    urb->transfer_flags |= URB_FREE_BUFFER;

    usb_anchor_urb(urb, &data->intr_anchor);

    err = usb_submit_urb(urb, mem_flags);
    if (err < 0) {
        BT_ERR("btusb_submit_intr_urb %s urb %p submission failed (%d)",
               hdev->name, urb, -err);
        usb_unanchor_urb(urb);
    }

    usb_free_urb(urb);

    return err;
}
static int btusb_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags)
{
    struct btusb_data *data = GET_DRV_DATA(hdev);
    struct urb *urb;
    unsigned char *buf;
    unsigned int pipe;
    int err, size = HCI_MAX_FRAME_SIZE;

    BT_DBG("%s", hdev->name);

    if (!data->bulk_rx_ep)
        return -ENODEV;

    urb = usb_alloc_urb(0, mem_flags);
    if (!urb)
        return -ENOMEM;

    buf = kmalloc(size, mem_flags);
    if (!buf) {
        usb_free_urb(urb);
        return -ENOMEM;
    }

    pipe = usb_rcvbulkpipe(data->udev, data->bulk_rx_ep->bEndpointAddress);

    usb_fill_bulk_urb(urb, data->udev, pipe,
                      buf, size, btusb_bulk_complete, hdev);

    urb->transfer_flags |= URB_FREE_BUFFER;

    usb_mark_last_busy(data->udev);
    usb_anchor_urb(urb, &data->bulk_anchor);

    err = usb_submit_urb(urb, mem_flags);
    if (err < 0) {
        BT_ERR("btusb_submit_bulk_urb %s urb %p submission failed (%d)",
               hdev->name, urb, -err);
        usb_unanchor_urb(urb);
    }

    usb_free_urb(urb);

    return err;
}
static inline int __set_isoc_interface(struct hci_dev *hdev, int altsetting)
{
    struct btusb_data *data = GET_DRV_DATA(hdev);
    struct usb_interface *intf = data->isoc;
    struct usb_endpoint_descriptor *ep_desc;
    int i, err;

    if (!data->isoc)
        return -ENODEV;

    err = usb_set_interface(data->udev, 1, altsetting);
    if (err < 0) {
        BT_ERR("%s setting interface failed (%d)", hdev->name, -err);
        return err;
    }

    data->isoc_altsetting = altsetting;

    data->isoc_tx_ep = NULL;
    data->isoc_rx_ep = NULL;

    for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
        ep_desc = &intf->cur_altsetting->endpoint[i].desc;

        if (!data->isoc_tx_ep && usb_endpoint_is_isoc_out(ep_desc)) {
            data->isoc_tx_ep = ep_desc;
            continue;
        }

        if (!data->isoc_rx_ep && usb_endpoint_is_isoc_in(ep_desc)) {
            data->isoc_rx_ep = ep_desc;
            continue;
        }
    }

    if (!data->isoc_tx_ep || !data->isoc_rx_ep) {
        BT_ERR("%s invalid SCO descriptors", hdev->name);
        return -ENODEV;
    }

    return 0;
}
Пример #12
0
/* Reset device */
static int hci_uart_flush(struct hci_dev *hdev)
{
	struct hci_uart *hu  = GET_DRV_DATA(hdev);//(struct hci_uart *) hdev->driver_data;
	struct tty_struct *tty = hu->tty;

	BT_DBG("hdev %p tty %p", hdev, tty);

	if (hu->tx_skb) {
		kfree_skb(hu->tx_skb); hu->tx_skb = NULL;
	}

	/* Flush any pending characters in the driver and discipline. */
	tty_ldisc_flush(tty);
	tty_driver_flush_buffer(tty);

	if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
		hu->proto->flush(hu);

	return 0;
}
static void btusb_bulk_complete(struct urb *urb)
{
    struct hci_dev *hdev = urb->context;
    struct btusb_data *data = GET_DRV_DATA(hdev);
    int err;
    //struct usb_device    *dev ;
    BT_DBG("%s urb %p status %d count %d", hdev->name,
           urb, urb->status, urb->actual_length);

    if (!test_bit(HCI_RUNNING, &hdev->flags))
        return;

    if (urb->status == 0) {
        hdev->stat.byte_rx += urb->actual_length;

        if (hci_recv_fragment(hdev, HCI_ACLDATA_PKT,
                              urb->transfer_buffer,
                              urb->actual_length) < 0) {
            BT_ERR("%s corrupted ACL packet", hdev->name);
            hdev->stat.err_rx++;
        }
    }

    if (!test_bit(BTUSB_BULK_RUNNING, &data->flags))
        return;

    usb_anchor_urb(urb, &data->bulk_anchor);
    usb_mark_last_busy(data->udev);

    err = usb_submit_urb(urb, GFP_ATOMIC);
    if (err < 0) {
        /* -EPERM: urb is being killed;
         * -ENODEV: device got disconnected */
        if (err != -EPERM && err != -ENODEV)
            BT_ERR("btusb_bulk_complete %s urb %p failed to resubmit (%d)",
                   hdev->name, urb, -err);
        usb_unanchor_urb(urb);
        //	dev = urb->dev;
        //	RTKBT_DBG("dev->state = %d ",dev->state);
    }
}
static int btusb_close(struct hci_dev *hdev)
{
    struct btusb_data *data = GET_DRV_DATA(hdev);
    int i,err;

    if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
        return 0;

    RTKBT_DBG("btusb_close");
    /*******************************/
    for (i = 0; i < NUM_REASSEMBLY; i++)
    {
        if(hdev->reassembly[i])
        {
            kfree_skb(hdev->reassembly[i]);
            hdev->reassembly[i] = NULL;
            RTKBT_DBG("%s free ressembly i=%d",__FUNCTION__,i);
        }
    }
    /*******************************/
    cancel_work_sync(&data->work);
    cancel_work_sync(&data->waker);

    clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
    clear_bit(BTUSB_BULK_RUNNING, &data->flags);
    clear_bit(BTUSB_INTR_RUNNING, &data->flags);

    btusb_stop_traffic(data);
    err = usb_autopm_get_interface(data->intf);
    if (err < 0)
        goto failed;

    data->intf->needs_remote_wakeup = 0;
    usb_autopm_put_interface(data->intf);

failed:
    mdelay(URB_CANCELING_DELAY_MS);     // Added by Realtek
    usb_scuttle_anchored_urbs(&data->deferred);
    return 0;
}
static int btusb_send_frame(struct sk_buff *skb)
{
    struct hci_dev *hdev = (struct hci_dev *) skb->dev;
    struct btusb_data *data = GET_DRV_DATA(hdev);
    struct usb_ctrlrequest *dr;
    struct urb *urb;
    unsigned int pipe;
    int err;

    /*	u16* opcode = (u16*)(skb->data);
    	uint wlength = skb->len;
    	uint icount=0;

    	 RTKBT_DBG("==========%s opcode=0x%x,wlength = %d",__FUNCTION__,*opcode,wlength );
    		printk("==========wlength=%d \n",wlength);
    		for(icount=0;icount <wlength;icount++)
    		{
    	   		printk("0x%x ",*(opcode+icount) );
    		}
    		printk("\n==========");
    */

    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) {
        BT_ERR("btusb_send_frame %s urb %p submission failed", hdev->name, urb);
        kfree(urb->setup_packet);
        usb_unanchor_urb(urb);
    } else {
        usb_mark_last_busy(data->udev);
    }
    usb_free_urb(urb);

done:
    return err;
}