Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next
This commit is contained in:
commit
30d3c071a6
12 changed files with 539 additions and 252 deletions
|
@ -152,6 +152,7 @@ F: drivers/scsi/53c700*
|
||||||
|
|
||||||
6LOWPAN GENERIC (BTLE/IEEE 802.15.4)
|
6LOWPAN GENERIC (BTLE/IEEE 802.15.4)
|
||||||
M: Alexander Aring <alex.aring@gmail.com>
|
M: Alexander Aring <alex.aring@gmail.com>
|
||||||
|
M: Jukka Rissanen <jukka.rissanen@linux.intel.com>
|
||||||
L: linux-bluetooth@vger.kernel.org
|
L: linux-bluetooth@vger.kernel.org
|
||||||
L: linux-wpan@vger.kernel.org
|
L: linux-wpan@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
|
|
|
@ -275,13 +275,19 @@ struct btusb_data {
|
||||||
struct work_struct work;
|
struct work_struct work;
|
||||||
struct work_struct waker;
|
struct work_struct waker;
|
||||||
|
|
||||||
|
struct usb_anchor deferred;
|
||||||
struct usb_anchor tx_anchor;
|
struct usb_anchor tx_anchor;
|
||||||
|
int tx_in_flight;
|
||||||
|
spinlock_t txlock;
|
||||||
|
|
||||||
struct usb_anchor intr_anchor;
|
struct usb_anchor intr_anchor;
|
||||||
struct usb_anchor bulk_anchor;
|
struct usb_anchor bulk_anchor;
|
||||||
struct usb_anchor isoc_anchor;
|
struct usb_anchor isoc_anchor;
|
||||||
struct usb_anchor deferred;
|
spinlock_t rxlock;
|
||||||
int tx_in_flight;
|
|
||||||
spinlock_t txlock;
|
struct sk_buff *evt_skb;
|
||||||
|
struct sk_buff *acl_skb;
|
||||||
|
struct sk_buff *sco_skb;
|
||||||
|
|
||||||
struct usb_endpoint_descriptor *intr_ep;
|
struct usb_endpoint_descriptor *intr_ep;
|
||||||
struct usb_endpoint_descriptor *bulk_tx_ep;
|
struct usb_endpoint_descriptor *bulk_tx_ep;
|
||||||
|
@ -296,18 +302,189 @@ struct btusb_data {
|
||||||
int suspend_count;
|
int suspend_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int inc_tx(struct btusb_data *data)
|
static inline void btusb_free_frags(struct btusb_data *data)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int rv;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&data->txlock, flags);
|
spin_lock_irqsave(&data->rxlock, flags);
|
||||||
rv = test_bit(BTUSB_SUSPENDING, &data->flags);
|
|
||||||
if (!rv)
|
|
||||||
data->tx_in_flight++;
|
|
||||||
spin_unlock_irqrestore(&data->txlock, flags);
|
|
||||||
|
|
||||||
return rv;
|
kfree_skb(data->evt_skb);
|
||||||
|
data->evt_skb = NULL;
|
||||||
|
|
||||||
|
kfree_skb(data->acl_skb);
|
||||||
|
data->acl_skb = NULL;
|
||||||
|
|
||||||
|
kfree_skb(data->sco_skb);
|
||||||
|
data->sco_skb = NULL;
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&data->rxlock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int btusb_recv_intr(struct btusb_data *data, void *buffer, int count)
|
||||||
|
{
|
||||||
|
struct sk_buff *skb;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
spin_lock(&data->rxlock);
|
||||||
|
skb = data->evt_skb;
|
||||||
|
|
||||||
|
while (count) {
|
||||||
|
int len;
|
||||||
|
|
||||||
|
if (!skb) {
|
||||||
|
skb = bt_skb_alloc(HCI_MAX_EVENT_SIZE, GFP_ATOMIC);
|
||||||
|
if (!skb) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bt_cb(skb)->pkt_type = HCI_EVENT_PKT;
|
||||||
|
bt_cb(skb)->expect = HCI_EVENT_HDR_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = min_t(uint, bt_cb(skb)->expect, count);
|
||||||
|
memcpy(skb_put(skb, len), buffer, len);
|
||||||
|
|
||||||
|
count -= len;
|
||||||
|
buffer += len;
|
||||||
|
bt_cb(skb)->expect -= len;
|
||||||
|
|
||||||
|
if (skb->len == HCI_EVENT_HDR_SIZE) {
|
||||||
|
/* Complete event header */
|
||||||
|
bt_cb(skb)->expect = hci_event_hdr(skb)->plen;
|
||||||
|
|
||||||
|
if (skb_tailroom(skb) < bt_cb(skb)->expect) {
|
||||||
|
kfree_skb(skb);
|
||||||
|
skb = NULL;
|
||||||
|
|
||||||
|
err = -EILSEQ;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bt_cb(skb)->expect == 0) {
|
||||||
|
/* Complete frame */
|
||||||
|
hci_recv_frame(data->hdev, skb);
|
||||||
|
skb = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data->evt_skb = skb;
|
||||||
|
spin_unlock(&data->rxlock);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int btusb_recv_bulk(struct btusb_data *data, void *buffer, int count)
|
||||||
|
{
|
||||||
|
struct sk_buff *skb;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
spin_lock(&data->rxlock);
|
||||||
|
skb = data->acl_skb;
|
||||||
|
|
||||||
|
while (count) {
|
||||||
|
int len;
|
||||||
|
|
||||||
|
if (!skb) {
|
||||||
|
skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
|
||||||
|
if (!skb) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
|
||||||
|
bt_cb(skb)->expect = HCI_ACL_HDR_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = min_t(uint, bt_cb(skb)->expect, count);
|
||||||
|
memcpy(skb_put(skb, len), buffer, len);
|
||||||
|
|
||||||
|
count -= len;
|
||||||
|
buffer += len;
|
||||||
|
bt_cb(skb)->expect -= len;
|
||||||
|
|
||||||
|
if (skb->len == HCI_ACL_HDR_SIZE) {
|
||||||
|
__le16 dlen = hci_acl_hdr(skb)->dlen;
|
||||||
|
|
||||||
|
/* Complete ACL header */
|
||||||
|
bt_cb(skb)->expect = __le16_to_cpu(dlen);
|
||||||
|
|
||||||
|
if (skb_tailroom(skb) < bt_cb(skb)->expect) {
|
||||||
|
kfree_skb(skb);
|
||||||
|
skb = NULL;
|
||||||
|
|
||||||
|
err = -EILSEQ;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bt_cb(skb)->expect == 0) {
|
||||||
|
/* Complete frame */
|
||||||
|
hci_recv_frame(data->hdev, skb);
|
||||||
|
skb = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data->acl_skb = skb;
|
||||||
|
spin_unlock(&data->rxlock);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int btusb_recv_isoc(struct btusb_data *data, void *buffer, int count)
|
||||||
|
{
|
||||||
|
struct sk_buff *skb;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
spin_lock(&data->rxlock);
|
||||||
|
skb = data->sco_skb;
|
||||||
|
|
||||||
|
while (count) {
|
||||||
|
int len;
|
||||||
|
|
||||||
|
if (!skb) {
|
||||||
|
skb = bt_skb_alloc(HCI_MAX_SCO_SIZE, GFP_ATOMIC);
|
||||||
|
if (!skb) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bt_cb(skb)->pkt_type = HCI_SCODATA_PKT;
|
||||||
|
bt_cb(skb)->expect = HCI_SCO_HDR_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = min_t(uint, bt_cb(skb)->expect, count);
|
||||||
|
memcpy(skb_put(skb, len), buffer, len);
|
||||||
|
|
||||||
|
count -= len;
|
||||||
|
buffer += len;
|
||||||
|
bt_cb(skb)->expect -= len;
|
||||||
|
|
||||||
|
if (skb->len == HCI_SCO_HDR_SIZE) {
|
||||||
|
/* Complete SCO header */
|
||||||
|
bt_cb(skb)->expect = hci_sco_hdr(skb)->dlen;
|
||||||
|
|
||||||
|
if (skb_tailroom(skb) < bt_cb(skb)->expect) {
|
||||||
|
kfree_skb(skb);
|
||||||
|
skb = NULL;
|
||||||
|
|
||||||
|
err = -EILSEQ;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bt_cb(skb)->expect == 0) {
|
||||||
|
/* Complete frame */
|
||||||
|
hci_recv_frame(data->hdev, skb);
|
||||||
|
skb = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data->sco_skb = skb;
|
||||||
|
spin_unlock(&data->rxlock);
|
||||||
|
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void btusb_intr_complete(struct urb *urb)
|
static void btusb_intr_complete(struct urb *urb)
|
||||||
|
@ -316,8 +493,8 @@ static void btusb_intr_complete(struct urb *urb)
|
||||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
BT_DBG("%s urb %p status %d count %d", hdev->name,
|
BT_DBG("%s urb %p status %d count %d", hdev->name, urb, urb->status,
|
||||||
urb, urb->status, urb->actual_length);
|
urb->actual_length);
|
||||||
|
|
||||||
if (!test_bit(HCI_RUNNING, &hdev->flags))
|
if (!test_bit(HCI_RUNNING, &hdev->flags))
|
||||||
return;
|
return;
|
||||||
|
@ -325,8 +502,7 @@ static void btusb_intr_complete(struct urb *urb)
|
||||||
if (urb->status == 0) {
|
if (urb->status == 0) {
|
||||||
hdev->stat.byte_rx += urb->actual_length;
|
hdev->stat.byte_rx += urb->actual_length;
|
||||||
|
|
||||||
if (hci_recv_fragment(hdev, HCI_EVENT_PKT,
|
if (btusb_recv_intr(data, urb->transfer_buffer,
|
||||||
urb->transfer_buffer,
|
|
||||||
urb->actual_length) < 0) {
|
urb->actual_length) < 0) {
|
||||||
BT_ERR("%s corrupted event packet", hdev->name);
|
BT_ERR("%s corrupted event packet", hdev->name);
|
||||||
hdev->stat.err_rx++;
|
hdev->stat.err_rx++;
|
||||||
|
@ -381,8 +557,7 @@ static int btusb_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags)
|
||||||
pipe = usb_rcvintpipe(data->udev, data->intr_ep->bEndpointAddress);
|
pipe = usb_rcvintpipe(data->udev, data->intr_ep->bEndpointAddress);
|
||||||
|
|
||||||
usb_fill_int_urb(urb, data->udev, pipe, buf, size,
|
usb_fill_int_urb(urb, data->udev, pipe, buf, size,
|
||||||
btusb_intr_complete, hdev,
|
btusb_intr_complete, hdev, data->intr_ep->bInterval);
|
||||||
data->intr_ep->bInterval);
|
|
||||||
|
|
||||||
urb->transfer_flags |= URB_FREE_BUFFER;
|
urb->transfer_flags |= URB_FREE_BUFFER;
|
||||||
|
|
||||||
|
@ -407,8 +582,8 @@ static void btusb_bulk_complete(struct urb *urb)
|
||||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
BT_DBG("%s urb %p status %d count %d", hdev->name,
|
BT_DBG("%s urb %p status %d count %d", hdev->name, urb, urb->status,
|
||||||
urb, urb->status, urb->actual_length);
|
urb->actual_length);
|
||||||
|
|
||||||
if (!test_bit(HCI_RUNNING, &hdev->flags))
|
if (!test_bit(HCI_RUNNING, &hdev->flags))
|
||||||
return;
|
return;
|
||||||
|
@ -416,8 +591,7 @@ static void btusb_bulk_complete(struct urb *urb)
|
||||||
if (urb->status == 0) {
|
if (urb->status == 0) {
|
||||||
hdev->stat.byte_rx += urb->actual_length;
|
hdev->stat.byte_rx += urb->actual_length;
|
||||||
|
|
||||||
if (hci_recv_fragment(hdev, HCI_ACLDATA_PKT,
|
if (btusb_recv_bulk(data, urb->transfer_buffer,
|
||||||
urb->transfer_buffer,
|
|
||||||
urb->actual_length) < 0) {
|
urb->actual_length) < 0) {
|
||||||
BT_ERR("%s corrupted ACL packet", hdev->name);
|
BT_ERR("%s corrupted ACL packet", hdev->name);
|
||||||
hdev->stat.err_rx++;
|
hdev->stat.err_rx++;
|
||||||
|
@ -469,8 +643,8 @@ static int btusb_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags)
|
||||||
|
|
||||||
pipe = usb_rcvbulkpipe(data->udev, data->bulk_rx_ep->bEndpointAddress);
|
pipe = usb_rcvbulkpipe(data->udev, data->bulk_rx_ep->bEndpointAddress);
|
||||||
|
|
||||||
usb_fill_bulk_urb(urb, data->udev, pipe,
|
usb_fill_bulk_urb(urb, data->udev, pipe, buf, size,
|
||||||
buf, size, btusb_bulk_complete, hdev);
|
btusb_bulk_complete, hdev);
|
||||||
|
|
||||||
urb->transfer_flags |= URB_FREE_BUFFER;
|
urb->transfer_flags |= URB_FREE_BUFFER;
|
||||||
|
|
||||||
|
@ -496,8 +670,8 @@ static void btusb_isoc_complete(struct urb *urb)
|
||||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||||
int i, err;
|
int i, err;
|
||||||
|
|
||||||
BT_DBG("%s urb %p status %d count %d", hdev->name,
|
BT_DBG("%s urb %p status %d count %d", hdev->name, urb, urb->status,
|
||||||
urb, urb->status, urb->actual_length);
|
urb->actual_length);
|
||||||
|
|
||||||
if (!test_bit(HCI_RUNNING, &hdev->flags))
|
if (!test_bit(HCI_RUNNING, &hdev->flags))
|
||||||
return;
|
return;
|
||||||
|
@ -512,8 +686,7 @@ static void btusb_isoc_complete(struct urb *urb)
|
||||||
|
|
||||||
hdev->stat.byte_rx += length;
|
hdev->stat.byte_rx += length;
|
||||||
|
|
||||||
if (hci_recv_fragment(hdev, HCI_SCODATA_PKT,
|
if (btusb_recv_isoc(data, urb->transfer_buffer + offset,
|
||||||
urb->transfer_buffer + offset,
|
|
||||||
length) < 0) {
|
length) < 0) {
|
||||||
BT_ERR("%s corrupted SCO packet", hdev->name);
|
BT_ERR("%s corrupted SCO packet", hdev->name);
|
||||||
hdev->stat.err_rx++;
|
hdev->stat.err_rx++;
|
||||||
|
@ -615,11 +788,11 @@ static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags)
|
||||||
static void btusb_tx_complete(struct urb *urb)
|
static void btusb_tx_complete(struct urb *urb)
|
||||||
{
|
{
|
||||||
struct sk_buff *skb = urb->context;
|
struct sk_buff *skb = urb->context;
|
||||||
struct hci_dev *hdev = (struct hci_dev *) skb->dev;
|
struct hci_dev *hdev = (struct hci_dev *)skb->dev;
|
||||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||||
|
|
||||||
BT_DBG("%s urb %p status %d count %d", hdev->name,
|
BT_DBG("%s urb %p status %d count %d", hdev->name, urb, urb->status,
|
||||||
urb, urb->status, urb->actual_length);
|
urb->actual_length);
|
||||||
|
|
||||||
if (!test_bit(HCI_RUNNING, &hdev->flags))
|
if (!test_bit(HCI_RUNNING, &hdev->flags))
|
||||||
goto done;
|
goto done;
|
||||||
|
@ -642,10 +815,10 @@ done:
|
||||||
static void btusb_isoc_tx_complete(struct urb *urb)
|
static void btusb_isoc_tx_complete(struct urb *urb)
|
||||||
{
|
{
|
||||||
struct sk_buff *skb = urb->context;
|
struct sk_buff *skb = urb->context;
|
||||||
struct hci_dev *hdev = (struct hci_dev *) skb->dev;
|
struct hci_dev *hdev = (struct hci_dev *)skb->dev;
|
||||||
|
|
||||||
BT_DBG("%s urb %p status %d count %d", hdev->name,
|
BT_DBG("%s urb %p status %d count %d", hdev->name, urb, urb->status,
|
||||||
urb, urb->status, urb->actual_length);
|
urb->actual_length);
|
||||||
|
|
||||||
if (!test_bit(HCI_RUNNING, &hdev->flags))
|
if (!test_bit(HCI_RUNNING, &hdev->flags))
|
||||||
goto done;
|
goto done;
|
||||||
|
@ -729,6 +902,8 @@ static int btusb_close(struct hci_dev *hdev)
|
||||||
clear_bit(BTUSB_INTR_RUNNING, &data->flags);
|
clear_bit(BTUSB_INTR_RUNNING, &data->flags);
|
||||||
|
|
||||||
btusb_stop_traffic(data);
|
btusb_stop_traffic(data);
|
||||||
|
btusb_free_frags(data);
|
||||||
|
|
||||||
err = usb_autopm_get_interface(data->intf);
|
err = usb_autopm_get_interface(data->intf);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto failed;
|
goto failed;
|
||||||
|
@ -748,35 +923,26 @@ static int btusb_flush(struct hci_dev *hdev)
|
||||||
BT_DBG("%s", hdev->name);
|
BT_DBG("%s", hdev->name);
|
||||||
|
|
||||||
usb_kill_anchored_urbs(&data->tx_anchor);
|
usb_kill_anchored_urbs(&data->tx_anchor);
|
||||||
|
btusb_free_frags(data);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int btusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
static struct urb *alloc_ctrl_urb(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||||
struct usb_ctrlrequest *dr;
|
struct usb_ctrlrequest *dr;
|
||||||
struct urb *urb;
|
struct urb *urb;
|
||||||
unsigned int pipe;
|
unsigned int pipe;
|
||||||
int err;
|
|
||||||
|
|
||||||
BT_DBG("%s", hdev->name);
|
urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||||
|
|
||||||
if (!test_bit(HCI_RUNNING, &hdev->flags))
|
|
||||||
return -EBUSY;
|
|
||||||
|
|
||||||
skb->dev = (void *) hdev;
|
|
||||||
|
|
||||||
switch (bt_cb(skb)->pkt_type) {
|
|
||||||
case HCI_COMMAND_PKT:
|
|
||||||
urb = usb_alloc_urb(0, GFP_ATOMIC);
|
|
||||||
if (!urb)
|
if (!urb)
|
||||||
return -ENOMEM;
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
dr = kmalloc(sizeof(*dr), GFP_ATOMIC);
|
dr = kmalloc(sizeof(*dr), GFP_KERNEL);
|
||||||
if (!dr) {
|
if (!dr) {
|
||||||
usb_free_urb(urb);
|
usb_free_urb(urb);
|
||||||
return -ENOMEM;
|
return ERR_PTR(-ENOMEM);
|
||||||
}
|
}
|
||||||
|
|
||||||
dr->bRequestType = data->cmdreq_type;
|
dr->bRequestType = data->cmdreq_type;
|
||||||
|
@ -787,39 +953,51 @@ static int btusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
|
|
||||||
pipe = usb_sndctrlpipe(data->udev, 0x00);
|
pipe = usb_sndctrlpipe(data->udev, 0x00);
|
||||||
|
|
||||||
usb_fill_control_urb(urb, data->udev, pipe, (void *) dr,
|
usb_fill_control_urb(urb, data->udev, pipe, (void *)dr,
|
||||||
skb->data, skb->len, btusb_tx_complete, skb);
|
skb->data, skb->len, btusb_tx_complete, skb);
|
||||||
|
|
||||||
hdev->stat.cmd_tx++;
|
skb->dev = (void *)hdev;
|
||||||
break;
|
|
||||||
|
return urb;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct urb *alloc_bulk_urb(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||||
|
struct urb *urb;
|
||||||
|
unsigned int pipe;
|
||||||
|
|
||||||
case HCI_ACLDATA_PKT:
|
|
||||||
if (!data->bulk_tx_ep)
|
if (!data->bulk_tx_ep)
|
||||||
return -ENODEV;
|
return ERR_PTR(-ENODEV);
|
||||||
|
|
||||||
urb = usb_alloc_urb(0, GFP_ATOMIC);
|
urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||||
if (!urb)
|
if (!urb)
|
||||||
return -ENOMEM;
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
pipe = usb_sndbulkpipe(data->udev,
|
pipe = usb_sndbulkpipe(data->udev, data->bulk_tx_ep->bEndpointAddress);
|
||||||
data->bulk_tx_ep->bEndpointAddress);
|
|
||||||
|
|
||||||
usb_fill_bulk_urb(urb, data->udev, pipe,
|
usb_fill_bulk_urb(urb, data->udev, pipe,
|
||||||
skb->data, skb->len, btusb_tx_complete, skb);
|
skb->data, skb->len, btusb_tx_complete, skb);
|
||||||
|
|
||||||
hdev->stat.acl_tx++;
|
skb->dev = (void *)hdev;
|
||||||
break;
|
|
||||||
|
|
||||||
case HCI_SCODATA_PKT:
|
return urb;
|
||||||
if (!data->isoc_tx_ep || hci_conn_num(hdev, SCO_LINK) < 1)
|
}
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, GFP_ATOMIC);
|
static struct urb *alloc_isoc_urb(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||||
|
struct urb *urb;
|
||||||
|
unsigned int pipe;
|
||||||
|
|
||||||
|
if (!data->isoc_tx_ep)
|
||||||
|
return ERR_PTR(-ENODEV);
|
||||||
|
|
||||||
|
urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, GFP_KERNEL);
|
||||||
if (!urb)
|
if (!urb)
|
||||||
return -ENOMEM;
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
pipe = usb_sndisocpipe(data->udev,
|
pipe = usb_sndisocpipe(data->udev, data->isoc_tx_ep->bEndpointAddress);
|
||||||
data->isoc_tx_ep->bEndpointAddress);
|
|
||||||
|
|
||||||
usb_fill_int_urb(urb, data->udev, pipe,
|
usb_fill_int_urb(urb, data->udev, pipe,
|
||||||
skb->data, skb->len, btusb_isoc_tx_complete,
|
skb->data, skb->len, btusb_isoc_tx_complete,
|
||||||
|
@ -830,25 +1008,19 @@ static int btusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
__fill_isoc_descriptor(urb, skb->len,
|
__fill_isoc_descriptor(urb, skb->len,
|
||||||
le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize));
|
le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize));
|
||||||
|
|
||||||
hdev->stat.sco_tx++;
|
skb->dev = (void *)hdev;
|
||||||
goto skip_waking;
|
|
||||||
|
|
||||||
default:
|
return urb;
|
||||||
return -EILSEQ;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
err = inc_tx(data);
|
static int submit_tx_urb(struct hci_dev *hdev, struct urb *urb)
|
||||||
if (err) {
|
{
|
||||||
usb_anchor_urb(urb, &data->deferred);
|
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||||
schedule_work(&data->waker);
|
int err;
|
||||||
err = 0;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
skip_waking:
|
|
||||||
usb_anchor_urb(urb, &data->tx_anchor);
|
usb_anchor_urb(urb, &data->tx_anchor);
|
||||||
|
|
||||||
err = usb_submit_urb(urb, GFP_ATOMIC);
|
err = usb_submit_urb(urb, GFP_KERNEL);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
if (err != -EPERM && err != -ENODEV)
|
if (err != -EPERM && err != -ENODEV)
|
||||||
BT_ERR("%s urb %p submission failed (%d)",
|
BT_ERR("%s urb %p submission failed (%d)",
|
||||||
|
@ -859,11 +1031,73 @@ skip_waking:
|
||||||
usb_mark_last_busy(data->udev);
|
usb_mark_last_busy(data->udev);
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
|
||||||
usb_free_urb(urb);
|
usb_free_urb(urb);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int submit_or_queue_tx_urb(struct hci_dev *hdev, struct urb *urb)
|
||||||
|
{
|
||||||
|
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||||
|
unsigned long flags;
|
||||||
|
bool suspending;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&data->txlock, flags);
|
||||||
|
suspending = test_bit(BTUSB_SUSPENDING, &data->flags);
|
||||||
|
if (!suspending)
|
||||||
|
data->tx_in_flight++;
|
||||||
|
spin_unlock_irqrestore(&data->txlock, flags);
|
||||||
|
|
||||||
|
if (!suspending)
|
||||||
|
return submit_tx_urb(hdev, urb);
|
||||||
|
|
||||||
|
usb_anchor_urb(urb, &data->deferred);
|
||||||
|
schedule_work(&data->waker);
|
||||||
|
|
||||||
|
usb_free_urb(urb);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int btusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
struct urb *urb;
|
||||||
|
|
||||||
|
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 = alloc_ctrl_urb(hdev, skb);
|
||||||
|
if (IS_ERR(urb))
|
||||||
|
return PTR_ERR(urb);
|
||||||
|
|
||||||
|
hdev->stat.cmd_tx++;
|
||||||
|
return submit_or_queue_tx_urb(hdev, urb);
|
||||||
|
|
||||||
|
case HCI_ACLDATA_PKT:
|
||||||
|
urb = alloc_bulk_urb(hdev, skb);
|
||||||
|
if (IS_ERR(urb))
|
||||||
|
return PTR_ERR(urb);
|
||||||
|
|
||||||
|
hdev->stat.acl_tx++;
|
||||||
|
return submit_or_queue_tx_urb(hdev, urb);
|
||||||
|
|
||||||
|
case HCI_SCODATA_PKT:
|
||||||
|
if (hci_conn_num(hdev, SCO_LINK) < 1)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
urb = alloc_isoc_urb(hdev, skb);
|
||||||
|
if (IS_ERR(urb))
|
||||||
|
return PTR_ERR(urb);
|
||||||
|
|
||||||
|
hdev->stat.sco_tx++;
|
||||||
|
return submit_tx_urb(hdev, urb);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -EILSEQ;
|
||||||
|
}
|
||||||
|
|
||||||
static void btusb_notify(struct hci_dev *hdev, unsigned int evt)
|
static void btusb_notify(struct hci_dev *hdev, unsigned int evt)
|
||||||
{
|
{
|
||||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||||
|
@ -940,6 +1174,7 @@ static void btusb_work(struct work_struct *work)
|
||||||
|
|
||||||
if (hdev->voice_setting & 0x0020) {
|
if (hdev->voice_setting & 0x0020) {
|
||||||
static const int alts[3] = { 2, 4, 5 };
|
static const int alts[3] = { 2, 4, 5 };
|
||||||
|
|
||||||
new_alts = alts[data->sco_num - 1];
|
new_alts = alts[data->sco_num - 1];
|
||||||
} else {
|
} else {
|
||||||
new_alts = data->sco_num;
|
new_alts = data->sco_num;
|
||||||
|
@ -1012,7 +1247,7 @@ static int btusb_setup_csr(struct hci_dev *hdev)
|
||||||
return -PTR_ERR(skb);
|
return -PTR_ERR(skb);
|
||||||
}
|
}
|
||||||
|
|
||||||
rp = (struct hci_rp_read_local_version *) skb->data;
|
rp = (struct hci_rp_read_local_version *)skb->data;
|
||||||
|
|
||||||
if (!rp->status) {
|
if (!rp->status) {
|
||||||
if (le16_to_cpu(rp->manufacturer) != 10) {
|
if (le16_to_cpu(rp->manufacturer) != 10) {
|
||||||
|
@ -1226,7 +1461,7 @@ static int btusb_check_bdaddr_intel(struct hci_dev *hdev)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
rp = (struct hci_rp_read_bd_addr *) skb->data;
|
rp = (struct hci_rp_read_bd_addr *)skb->data;
|
||||||
if (rp->status) {
|
if (rp->status) {
|
||||||
BT_ERR("%s Intel device address result failed (%02x)",
|
BT_ERR("%s Intel device address result failed (%02x)",
|
||||||
hdev->name, rp->status);
|
hdev->name, rp->status);
|
||||||
|
@ -1356,6 +1591,7 @@ static int btusb_setup_intel(struct hci_dev *hdev)
|
||||||
|
|
||||||
if (skb->data[0]) {
|
if (skb->data[0]) {
|
||||||
u8 evt_status = skb->data[0];
|
u8 evt_status = skb->data[0];
|
||||||
|
|
||||||
BT_ERR("%s enable Intel manufacturer mode event failed (%02x)",
|
BT_ERR("%s enable Intel manufacturer mode event failed (%02x)",
|
||||||
hdev->name, evt_status);
|
hdev->name, evt_status);
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
|
@ -1552,7 +1788,7 @@ static int btusb_setup_bcm_patchram(struct hci_dev *hdev)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
ver = (struct hci_rp_read_local_version *) skb->data;
|
ver = (struct hci_rp_read_local_version *)skb->data;
|
||||||
BT_INFO("%s: BCM: patching hci_ver=%02x hci_rev=%04x lmp_ver=%02x "
|
BT_INFO("%s: BCM: patching hci_ver=%02x hci_rev=%04x lmp_ver=%02x "
|
||||||
"lmp_subver=%04x", hdev->name, ver->hci_ver, ver->hci_rev,
|
"lmp_subver=%04x", hdev->name, ver->hci_ver, ver->hci_rev,
|
||||||
ver->lmp_ver, ver->lmp_subver);
|
ver->lmp_ver, ver->lmp_subver);
|
||||||
|
@ -1575,7 +1811,7 @@ static int btusb_setup_bcm_patchram(struct hci_dev *hdev)
|
||||||
fw_size = fw->size;
|
fw_size = fw->size;
|
||||||
|
|
||||||
while (fw_size >= sizeof(*cmd)) {
|
while (fw_size >= sizeof(*cmd)) {
|
||||||
cmd = (struct hci_command_hdr *) fw_ptr;
|
cmd = (struct hci_command_hdr *)fw_ptr;
|
||||||
fw_ptr += sizeof(*cmd);
|
fw_ptr += sizeof(*cmd);
|
||||||
fw_size -= sizeof(*cmd);
|
fw_size -= sizeof(*cmd);
|
||||||
|
|
||||||
|
@ -1634,7 +1870,7 @@ reset_fw:
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
ver = (struct hci_rp_read_local_version *) skb->data;
|
ver = (struct hci_rp_read_local_version *)skb->data;
|
||||||
BT_INFO("%s: BCM: firmware hci_ver=%02x hci_rev=%04x lmp_ver=%02x "
|
BT_INFO("%s: BCM: firmware hci_ver=%02x hci_rev=%04x lmp_ver=%02x "
|
||||||
"lmp_subver=%04x", hdev->name, ver->hci_ver, ver->hci_rev,
|
"lmp_subver=%04x", hdev->name, ver->hci_ver, ver->hci_rev,
|
||||||
ver->lmp_ver, ver->lmp_subver);
|
ver->lmp_ver, ver->lmp_subver);
|
||||||
|
@ -1658,7 +1894,7 @@ reset_fw:
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
bda = (struct hci_rp_read_bd_addr *) skb->data;
|
bda = (struct hci_rp_read_bd_addr *)skb->data;
|
||||||
if (bda->status) {
|
if (bda->status) {
|
||||||
BT_ERR("%s: HCI_OP_READ_BD_ADDR error status (%02x)",
|
BT_ERR("%s: HCI_OP_READ_BD_ADDR error status (%02x)",
|
||||||
hdev->name, bda->status);
|
hdev->name, bda->status);
|
||||||
|
@ -1717,6 +1953,7 @@ static int btusb_probe(struct usb_interface *intf,
|
||||||
|
|
||||||
if (!id->driver_info) {
|
if (!id->driver_info) {
|
||||||
const struct usb_device_id *match;
|
const struct usb_device_id *match;
|
||||||
|
|
||||||
match = usb_match_id(intf, blacklist_table);
|
match = usb_match_id(intf, blacklist_table);
|
||||||
if (match)
|
if (match)
|
||||||
id = match;
|
id = match;
|
||||||
|
@ -1769,13 +2006,14 @@ static int btusb_probe(struct usb_interface *intf,
|
||||||
|
|
||||||
INIT_WORK(&data->work, btusb_work);
|
INIT_WORK(&data->work, btusb_work);
|
||||||
INIT_WORK(&data->waker, btusb_waker);
|
INIT_WORK(&data->waker, btusb_waker);
|
||||||
|
init_usb_anchor(&data->deferred);
|
||||||
|
init_usb_anchor(&data->tx_anchor);
|
||||||
spin_lock_init(&data->txlock);
|
spin_lock_init(&data->txlock);
|
||||||
|
|
||||||
init_usb_anchor(&data->tx_anchor);
|
|
||||||
init_usb_anchor(&data->intr_anchor);
|
init_usb_anchor(&data->intr_anchor);
|
||||||
init_usb_anchor(&data->bulk_anchor);
|
init_usb_anchor(&data->bulk_anchor);
|
||||||
init_usb_anchor(&data->isoc_anchor);
|
init_usb_anchor(&data->isoc_anchor);
|
||||||
init_usb_anchor(&data->deferred);
|
spin_lock_init(&data->rxlock);
|
||||||
|
|
||||||
hdev = hci_alloc_dev();
|
hdev = hci_alloc_dev();
|
||||||
if (!hdev)
|
if (!hdev)
|
||||||
|
@ -1908,6 +2146,7 @@ static void btusb_disconnect(struct usb_interface *intf)
|
||||||
else if (data->isoc)
|
else if (data->isoc)
|
||||||
usb_driver_release_interface(&btusb_driver, data->isoc);
|
usb_driver_release_interface(&btusb_driver, data->isoc);
|
||||||
|
|
||||||
|
btusb_free_frags(data);
|
||||||
hci_free_dev(hdev);
|
hci_free_dev(hdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -323,7 +323,7 @@ static int mrf24j40_read_rx_buf(struct mrf24j40 *devrec,
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
print_hex_dump(KERN_DEBUG, "mrf24j40 rx: ",
|
print_hex_dump(KERN_DEBUG, "mrf24j40 rx: ",
|
||||||
DUMP_PREFIX_OFFSET, 16, 1, data, *len, 0);
|
DUMP_PREFIX_OFFSET, 16, 1, data, *len, 0);
|
||||||
printk(KERN_DEBUG "mrf24j40 rx: lqi: %02hhx rssi: %02hhx\n",
|
pr_debug("mrf24j40 rx: lqi: %02hhx rssi: %02hhx\n",
|
||||||
lqi_rssi[0], lqi_rssi[1]);
|
lqi_rssi[0], lqi_rssi[1]);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -385,7 +385,7 @@ err:
|
||||||
static int mrf24j40_ed(struct ieee802154_dev *dev, u8 *level)
|
static int mrf24j40_ed(struct ieee802154_dev *dev, u8 *level)
|
||||||
{
|
{
|
||||||
/* TODO: */
|
/* TODO: */
|
||||||
printk(KERN_WARNING "mrf24j40: ed not implemented\n");
|
pr_warn("mrf24j40: ed not implemented\n");
|
||||||
*level = 0;
|
*level = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -412,6 +412,7 @@ static void mrf24j40_stop(struct ieee802154_dev *dev)
|
||||||
struct mrf24j40 *devrec = dev->priv;
|
struct mrf24j40 *devrec = dev->priv;
|
||||||
u8 val;
|
u8 val;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
dev_dbg(printdev(devrec), "stop\n");
|
dev_dbg(printdev(devrec), "stop\n");
|
||||||
|
|
||||||
ret = read_short_reg(devrec, REG_INTCON, &val);
|
ret = read_short_reg(devrec, REG_INTCON, &val);
|
||||||
|
@ -419,8 +420,6 @@ static void mrf24j40_stop(struct ieee802154_dev *dev)
|
||||||
return;
|
return;
|
||||||
val |= 0x1|0x8; /* Set TXNIE and RXIE. Disable Interrupts */
|
val |= 0x1|0x8; /* Set TXNIE and RXIE. Disable Interrupts */
|
||||||
write_short_reg(devrec, REG_INTCON, val);
|
write_short_reg(devrec, REG_INTCON, val);
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mrf24j40_set_channel(struct ieee802154_dev *dev,
|
static int mrf24j40_set_channel(struct ieee802154_dev *dev,
|
||||||
|
@ -465,6 +464,7 @@ static int mrf24j40_filter(struct ieee802154_dev *dev,
|
||||||
if (changed & IEEE802515_AFILT_SADDR_CHANGED) {
|
if (changed & IEEE802515_AFILT_SADDR_CHANGED) {
|
||||||
/* Short Addr */
|
/* Short Addr */
|
||||||
u8 addrh, addrl;
|
u8 addrh, addrl;
|
||||||
|
|
||||||
addrh = le16_to_cpu(filt->short_addr) >> 8 & 0xff;
|
addrh = le16_to_cpu(filt->short_addr) >> 8 & 0xff;
|
||||||
addrl = le16_to_cpu(filt->short_addr) & 0xff;
|
addrl = le16_to_cpu(filt->short_addr) & 0xff;
|
||||||
|
|
||||||
|
@ -483,16 +483,17 @@ static int mrf24j40_filter(struct ieee802154_dev *dev,
|
||||||
write_short_reg(devrec, REG_EADR0 + i, addr[i]);
|
write_short_reg(devrec, REG_EADR0 + i, addr[i]);
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
printk(KERN_DEBUG "Set long addr to: ");
|
pr_debug("Set long addr to: ");
|
||||||
for (i = 0; i < 8; i++)
|
for (i = 0; i < 8; i++)
|
||||||
printk("%02hhx ", addr[7 - i]);
|
pr_debug("%02hhx ", addr[7 - i]);
|
||||||
printk(KERN_DEBUG "\n");
|
pr_debug("\n");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changed & IEEE802515_AFILT_PANID_CHANGED) {
|
if (changed & IEEE802515_AFILT_PANID_CHANGED) {
|
||||||
/* PAN ID */
|
/* PAN ID */
|
||||||
u8 panidl, panidh;
|
u8 panidl, panidh;
|
||||||
|
|
||||||
panidh = le16_to_cpu(filt->pan_id) >> 8 & 0xff;
|
panidh = le16_to_cpu(filt->pan_id) >> 8 & 0xff;
|
||||||
panidl = le16_to_cpu(filt->pan_id) & 0xff;
|
panidl = le16_to_cpu(filt->pan_id) & 0xff;
|
||||||
write_short_reg(devrec, REG_PANIDH, panidh);
|
write_short_reg(devrec, REG_PANIDH, panidh);
|
||||||
|
@ -701,7 +702,7 @@ static int mrf24j40_probe(struct spi_device *spi)
|
||||||
int ret = -ENOMEM;
|
int ret = -ENOMEM;
|
||||||
struct mrf24j40 *devrec;
|
struct mrf24j40 *devrec;
|
||||||
|
|
||||||
printk(KERN_INFO "mrf24j40: probe(). IRQ: %d\n", spi->irq);
|
dev_info(&spi->dev, "probe(). IRQ: %d\n", spi->irq);
|
||||||
|
|
||||||
devrec = devm_kzalloc(&spi->dev, sizeof(struct mrf24j40), GFP_KERNEL);
|
devrec = devm_kzalloc(&spi->dev, sizeof(struct mrf24j40), GFP_KERNEL);
|
||||||
if (!devrec)
|
if (!devrec)
|
||||||
|
|
|
@ -120,9 +120,9 @@ struct bt_voice {
|
||||||
#define BT_RCVMTU 13
|
#define BT_RCVMTU 13
|
||||||
|
|
||||||
__printf(1, 2)
|
__printf(1, 2)
|
||||||
int bt_info(const char *fmt, ...);
|
void bt_info(const char *fmt, ...);
|
||||||
__printf(1, 2)
|
__printf(1, 2)
|
||||||
int bt_err(const char *fmt, ...);
|
void bt_err(const char *fmt, ...);
|
||||||
|
|
||||||
#define BT_INFO(fmt, ...) bt_info(fmt "\n", ##__VA_ARGS__)
|
#define BT_INFO(fmt, ...) bt_info(fmt "\n", ##__VA_ARGS__)
|
||||||
#define BT_ERR(fmt, ...) bt_err(fmt "\n", ##__VA_ARGS__)
|
#define BT_ERR(fmt, ...) bt_err(fmt "\n", ##__VA_ARGS__)
|
||||||
|
@ -284,6 +284,7 @@ struct hci_req_ctrl {
|
||||||
struct bt_skb_cb {
|
struct bt_skb_cb {
|
||||||
__u8 pkt_type;
|
__u8 pkt_type;
|
||||||
__u8 incoming;
|
__u8 incoming;
|
||||||
|
__u16 opcode;
|
||||||
__u16 expect;
|
__u16 expect;
|
||||||
__u8 force_active;
|
__u8 force_active;
|
||||||
struct l2cap_chan *chan;
|
struct l2cap_chan *chan;
|
||||||
|
|
|
@ -385,6 +385,7 @@ enum {
|
||||||
#define HCI_ERROR_AUTH_FAILURE 0x05
|
#define HCI_ERROR_AUTH_FAILURE 0x05
|
||||||
#define HCI_ERROR_MEMORY_EXCEEDED 0x07
|
#define HCI_ERROR_MEMORY_EXCEEDED 0x07
|
||||||
#define HCI_ERROR_CONNECTION_TIMEOUT 0x08
|
#define HCI_ERROR_CONNECTION_TIMEOUT 0x08
|
||||||
|
#define HCI_ERROR_REJ_LIMITED_RESOURCES 0x0d
|
||||||
#define HCI_ERROR_REJ_BAD_ADDR 0x0f
|
#define HCI_ERROR_REJ_BAD_ADDR 0x0f
|
||||||
#define HCI_ERROR_REMOTE_USER_TERM 0x13
|
#define HCI_ERROR_REMOTE_USER_TERM 0x13
|
||||||
#define HCI_ERROR_REMOTE_LOW_RESOURCES 0x14
|
#define HCI_ERROR_REMOTE_LOW_RESOURCES 0x14
|
||||||
|
|
|
@ -926,7 +926,6 @@ int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr);
|
||||||
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
|
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
|
||||||
|
|
||||||
int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb);
|
int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb);
|
||||||
int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count);
|
|
||||||
int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count);
|
int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count);
|
||||||
|
|
||||||
void hci_init_sysfs(struct hci_dev *hdev);
|
void hci_init_sysfs(struct hci_dev *hdev);
|
||||||
|
|
|
@ -709,8 +709,11 @@ EXPORT_SYMBOL_GPL(bt_debugfs);
|
||||||
|
|
||||||
static int __init bt_init(void)
|
static int __init bt_init(void)
|
||||||
{
|
{
|
||||||
|
struct sk_buff *skb;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
BUILD_BUG_ON(sizeof(struct bt_skb_cb) > sizeof(skb->cb));
|
||||||
|
|
||||||
BT_INFO("Core ver %s", VERSION);
|
BT_INFO("Core ver %s", VERSION);
|
||||||
|
|
||||||
bt_debugfs = debugfs_create_dir("bluetooth", NULL);
|
bt_debugfs = debugfs_create_dir("bluetooth", NULL);
|
||||||
|
|
|
@ -36,19 +36,25 @@
|
||||||
struct sco_param {
|
struct sco_param {
|
||||||
u16 pkt_type;
|
u16 pkt_type;
|
||||||
u16 max_latency;
|
u16 max_latency;
|
||||||
|
u8 retrans_effort;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct sco_param esco_param_cvsd[] = {
|
||||||
|
{ EDR_ESCO_MASK & ~ESCO_2EV3, 0x000a, 0x01 }, /* S3 */
|
||||||
|
{ EDR_ESCO_MASK & ~ESCO_2EV3, 0x0007, 0x01 }, /* S2 */
|
||||||
|
{ EDR_ESCO_MASK | ESCO_EV3, 0x0007, 0x01 }, /* S1 */
|
||||||
|
{ EDR_ESCO_MASK | ESCO_HV3, 0xffff, 0x01 }, /* D1 */
|
||||||
|
{ EDR_ESCO_MASK | ESCO_HV1, 0xffff, 0x01 }, /* D0 */
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct sco_param sco_param_cvsd[] = {
|
static const struct sco_param sco_param_cvsd[] = {
|
||||||
{ EDR_ESCO_MASK & ~ESCO_2EV3, 0x000a }, /* S3 */
|
{ EDR_ESCO_MASK | ESCO_HV3, 0xffff, 0xff }, /* D1 */
|
||||||
{ EDR_ESCO_MASK & ~ESCO_2EV3, 0x0007 }, /* S2 */
|
{ EDR_ESCO_MASK | ESCO_HV1, 0xffff, 0xff }, /* D0 */
|
||||||
{ EDR_ESCO_MASK | ESCO_EV3, 0x0007 }, /* S1 */
|
|
||||||
{ EDR_ESCO_MASK | ESCO_HV3, 0xffff }, /* D1 */
|
|
||||||
{ EDR_ESCO_MASK | ESCO_HV1, 0xffff }, /* D0 */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct sco_param sco_param_wideband[] = {
|
static const struct sco_param esco_param_msbc[] = {
|
||||||
{ EDR_ESCO_MASK & ~ESCO_2EV3, 0x000d }, /* T2 */
|
{ EDR_ESCO_MASK & ~ESCO_2EV3, 0x000d, 0x02 }, /* T2 */
|
||||||
{ EDR_ESCO_MASK | ESCO_EV3, 0x0008 }, /* T1 */
|
{ EDR_ESCO_MASK | ESCO_EV3, 0x0008, 0x02 }, /* T1 */
|
||||||
};
|
};
|
||||||
|
|
||||||
static void hci_le_create_connection_cancel(struct hci_conn *conn)
|
static void hci_le_create_connection_cancel(struct hci_conn *conn)
|
||||||
|
@ -116,7 +122,7 @@ static void hci_reject_sco(struct hci_conn *conn)
|
||||||
{
|
{
|
||||||
struct hci_cp_reject_sync_conn_req cp;
|
struct hci_cp_reject_sync_conn_req cp;
|
||||||
|
|
||||||
cp.reason = HCI_ERROR_REMOTE_USER_TERM;
|
cp.reason = HCI_ERROR_REJ_LIMITED_RESOURCES;
|
||||||
bacpy(&cp.bdaddr, &conn->dst);
|
bacpy(&cp.bdaddr, &conn->dst);
|
||||||
|
|
||||||
hci_send_cmd(conn->hdev, HCI_OP_REJECT_SYNC_CONN_REQ, sizeof(cp), &cp);
|
hci_send_cmd(conn->hdev, HCI_OP_REJECT_SYNC_CONN_REQ, sizeof(cp), &cp);
|
||||||
|
@ -201,21 +207,26 @@ bool hci_setup_sync(struct hci_conn *conn, __u16 handle)
|
||||||
|
|
||||||
switch (conn->setting & SCO_AIRMODE_MASK) {
|
switch (conn->setting & SCO_AIRMODE_MASK) {
|
||||||
case SCO_AIRMODE_TRANSP:
|
case SCO_AIRMODE_TRANSP:
|
||||||
if (conn->attempt > ARRAY_SIZE(sco_param_wideband))
|
if (conn->attempt > ARRAY_SIZE(esco_param_msbc))
|
||||||
return false;
|
return false;
|
||||||
cp.retrans_effort = 0x02;
|
param = &esco_param_msbc[conn->attempt - 1];
|
||||||
param = &sco_param_wideband[conn->attempt - 1];
|
|
||||||
break;
|
break;
|
||||||
case SCO_AIRMODE_CVSD:
|
case SCO_AIRMODE_CVSD:
|
||||||
|
if (lmp_esco_capable(conn->link)) {
|
||||||
|
if (conn->attempt > ARRAY_SIZE(esco_param_cvsd))
|
||||||
|
return false;
|
||||||
|
param = &esco_param_cvsd[conn->attempt - 1];
|
||||||
|
} else {
|
||||||
if (conn->attempt > ARRAY_SIZE(sco_param_cvsd))
|
if (conn->attempt > ARRAY_SIZE(sco_param_cvsd))
|
||||||
return false;
|
return false;
|
||||||
cp.retrans_effort = 0x01;
|
|
||||||
param = &sco_param_cvsd[conn->attempt - 1];
|
param = &sco_param_cvsd[conn->attempt - 1];
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cp.retrans_effort = param->retrans_effort;
|
||||||
cp.pkt_type = __cpu_to_le16(param->pkt_type);
|
cp.pkt_type = __cpu_to_le16(param->pkt_type);
|
||||||
cp.max_latency = __cpu_to_le16(param->max_latency);
|
cp.max_latency = __cpu_to_le16(param->max_latency);
|
||||||
|
|
||||||
|
|
|
@ -4374,26 +4374,6 @@ static int hci_reassembly(struct hci_dev *hdev, int type, void *data,
|
||||||
return remain;
|
return remain;
|
||||||
}
|
}
|
||||||
|
|
||||||
int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count)
|
|
||||||
{
|
|
||||||
int rem = 0;
|
|
||||||
|
|
||||||
if (type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT)
|
|
||||||
return -EILSEQ;
|
|
||||||
|
|
||||||
while (count) {
|
|
||||||
rem = hci_reassembly(hdev, type, data, count, type - 1);
|
|
||||||
if (rem < 0)
|
|
||||||
return rem;
|
|
||||||
|
|
||||||
data += (count - rem);
|
|
||||||
count = rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rem;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(hci_recv_fragment);
|
|
||||||
|
|
||||||
#define STREAM_REASSEMBLY 0
|
#define STREAM_REASSEMBLY 0
|
||||||
|
|
||||||
int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count)
|
int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count)
|
||||||
|
@ -4547,6 +4527,7 @@ static struct sk_buff *hci_prepare_cmd(struct hci_dev *hdev, u16 opcode,
|
||||||
BT_DBG("skb len %d", skb->len);
|
BT_DBG("skb len %d", skb->len);
|
||||||
|
|
||||||
bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;
|
bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;
|
||||||
|
bt_cb(skb)->opcode = opcode;
|
||||||
|
|
||||||
return skb;
|
return skb;
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,40 +135,34 @@ int bt_to_errno(__u16 code)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(bt_to_errno);
|
EXPORT_SYMBOL(bt_to_errno);
|
||||||
|
|
||||||
int bt_info(const char *format, ...)
|
void bt_info(const char *format, ...)
|
||||||
{
|
{
|
||||||
struct va_format vaf;
|
struct va_format vaf;
|
||||||
va_list args;
|
va_list args;
|
||||||
int r;
|
|
||||||
|
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
|
|
||||||
vaf.fmt = format;
|
vaf.fmt = format;
|
||||||
vaf.va = &args;
|
vaf.va = &args;
|
||||||
|
|
||||||
r = pr_info("%pV", &vaf);
|
pr_info("%pV", &vaf);
|
||||||
|
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(bt_info);
|
EXPORT_SYMBOL(bt_info);
|
||||||
|
|
||||||
int bt_err(const char *format, ...)
|
void bt_err(const char *format, ...)
|
||||||
{
|
{
|
||||||
struct va_format vaf;
|
struct va_format vaf;
|
||||||
va_list args;
|
va_list args;
|
||||||
int r;
|
|
||||||
|
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
|
|
||||||
vaf.fmt = format;
|
vaf.fmt = format;
|
||||||
vaf.va = &args;
|
vaf.va = &args;
|
||||||
|
|
||||||
r = pr_err("%pV", &vaf);
|
pr_err("%pV", &vaf);
|
||||||
|
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(bt_err);
|
EXPORT_SYMBOL(bt_err);
|
||||||
|
|
|
@ -494,8 +494,11 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Not Just Works/Confirm results in MITM Authentication */
|
/* Not Just Works/Confirm results in MITM Authentication */
|
||||||
if (method != JUST_CFM)
|
if (method != JUST_CFM) {
|
||||||
set_bit(SMP_FLAG_MITM_AUTH, &smp->flags);
|
set_bit(SMP_FLAG_MITM_AUTH, &smp->flags);
|
||||||
|
if (hcon->pending_sec_level < BT_SECURITY_HIGH)
|
||||||
|
hcon->pending_sec_level = BT_SECURITY_HIGH;
|
||||||
|
}
|
||||||
|
|
||||||
/* If both devices have Keyoard-Display I/O, the master
|
/* If both devices have Keyoard-Display I/O, the master
|
||||||
* Confirms and the slave Enters the passkey.
|
* Confirms and the slave Enters the passkey.
|
||||||
|
|
|
@ -71,20 +71,42 @@ struct lowpan_dev_record {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* don't save pan id, it's intra pan */
|
||||||
|
struct lowpan_addr {
|
||||||
|
u8 mode;
|
||||||
|
union {
|
||||||
|
/* IPv6 needs big endian here */
|
||||||
|
__be64 extended_addr;
|
||||||
|
__be16 short_addr;
|
||||||
|
} u;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct lowpan_addr_info {
|
||||||
|
struct lowpan_addr daddr;
|
||||||
|
struct lowpan_addr saddr;
|
||||||
|
};
|
||||||
|
|
||||||
static inline struct
|
static inline struct
|
||||||
lowpan_dev_info *lowpan_dev_info(const struct net_device *dev)
|
lowpan_dev_info *lowpan_dev_info(const struct net_device *dev)
|
||||||
{
|
{
|
||||||
return netdev_priv(dev);
|
return netdev_priv(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline struct
|
||||||
|
lowpan_addr_info *lowpan_skb_priv(const struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
WARN_ON_ONCE(skb_headroom(skb) < sizeof(struct lowpan_addr_info));
|
||||||
|
return (struct lowpan_addr_info *)(skb->data -
|
||||||
|
sizeof(struct lowpan_addr_info));
|
||||||
|
}
|
||||||
|
|
||||||
static int lowpan_header_create(struct sk_buff *skb, struct net_device *dev,
|
static int lowpan_header_create(struct sk_buff *skb, struct net_device *dev,
|
||||||
unsigned short type, const void *_daddr,
|
unsigned short type, const void *_daddr,
|
||||||
const void *_saddr, unsigned int len)
|
const void *_saddr, unsigned int len)
|
||||||
{
|
{
|
||||||
const u8 *saddr = _saddr;
|
const u8 *saddr = _saddr;
|
||||||
const u8 *daddr = _daddr;
|
const u8 *daddr = _daddr;
|
||||||
struct ieee802154_addr sa, da;
|
struct lowpan_addr_info *info;
|
||||||
struct ieee802154_mac_cb *cb = mac_cb_init(skb);
|
|
||||||
|
|
||||||
/* TODO:
|
/* TODO:
|
||||||
* if this package isn't ipv6 one, where should it be routed?
|
* if this package isn't ipv6 one, where should it be routed?
|
||||||
|
@ -98,41 +120,17 @@ static int lowpan_header_create(struct sk_buff *skb, struct net_device *dev,
|
||||||
raw_dump_inline(__func__, "saddr", (unsigned char *)saddr, 8);
|
raw_dump_inline(__func__, "saddr", (unsigned char *)saddr, 8);
|
||||||
raw_dump_inline(__func__, "daddr", (unsigned char *)daddr, 8);
|
raw_dump_inline(__func__, "daddr", (unsigned char *)daddr, 8);
|
||||||
|
|
||||||
lowpan_header_compress(skb, dev, type, daddr, saddr, len);
|
info = lowpan_skb_priv(skb);
|
||||||
|
|
||||||
/* NOTE1: I'm still unsure about the fact that compression and WPAN
|
/* TODO: Currently we only support extended_addr */
|
||||||
* header are created here and not later in the xmit. So wait for
|
info->daddr.mode = IEEE802154_ADDR_LONG;
|
||||||
* an opinion of net maintainers.
|
memcpy(&info->daddr.u.extended_addr, daddr,
|
||||||
*/
|
sizeof(info->daddr.u.extended_addr));
|
||||||
/* NOTE2: to be absolutely correct, we must derive PANid information
|
info->saddr.mode = IEEE802154_ADDR_LONG;
|
||||||
* from MAC subif of the 'dev' and 'real_dev' network devices, but
|
memcpy(&info->saddr.u.extended_addr, saddr,
|
||||||
* this isn't implemented in mainline yet, so currently we assign 0xff
|
sizeof(info->daddr.u.extended_addr));
|
||||||
*/
|
|
||||||
cb->type = IEEE802154_FC_TYPE_DATA;
|
|
||||||
|
|
||||||
/* prepare wpan address data */
|
return 0;
|
||||||
sa.mode = IEEE802154_ADDR_LONG;
|
|
||||||
sa.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
|
|
||||||
sa.extended_addr = ieee802154_devaddr_from_raw(saddr);
|
|
||||||
|
|
||||||
/* intra-PAN communications */
|
|
||||||
da.pan_id = sa.pan_id;
|
|
||||||
|
|
||||||
/* if the destination address is the broadcast address, use the
|
|
||||||
* corresponding short address
|
|
||||||
*/
|
|
||||||
if (lowpan_is_addr_broadcast(daddr)) {
|
|
||||||
da.mode = IEEE802154_ADDR_SHORT;
|
|
||||||
da.short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
|
|
||||||
} else {
|
|
||||||
da.mode = IEEE802154_ADDR_LONG;
|
|
||||||
da.extended_addr = ieee802154_devaddr_from_raw(daddr);
|
|
||||||
}
|
|
||||||
|
|
||||||
cb->ackreq = !lowpan_is_addr_broadcast(daddr);
|
|
||||||
|
|
||||||
return dev_hard_header(skb, lowpan_dev_info(dev)->real_dev,
|
|
||||||
type, (void *)&da, (void *)&sa, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lowpan_give_skb_to_devices(struct sk_buff *skb,
|
static int lowpan_give_skb_to_devices(struct sk_buff *skb,
|
||||||
|
@ -330,13 +328,68 @@ err:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int lowpan_header(struct sk_buff *skb, struct net_device *dev)
|
||||||
|
{
|
||||||
|
struct ieee802154_addr sa, da;
|
||||||
|
struct ieee802154_mac_cb *cb = mac_cb_init(skb);
|
||||||
|
struct lowpan_addr_info info;
|
||||||
|
void *daddr, *saddr;
|
||||||
|
|
||||||
|
memcpy(&info, lowpan_skb_priv(skb), sizeof(info));
|
||||||
|
|
||||||
|
/* TODO: Currently we only support extended_addr */
|
||||||
|
daddr = &info.daddr.u.extended_addr;
|
||||||
|
saddr = &info.saddr.u.extended_addr;
|
||||||
|
|
||||||
|
lowpan_header_compress(skb, dev, ETH_P_IPV6, daddr, saddr, skb->len);
|
||||||
|
|
||||||
|
cb->type = IEEE802154_FC_TYPE_DATA;
|
||||||
|
|
||||||
|
/* prepare wpan address data */
|
||||||
|
sa.mode = IEEE802154_ADDR_LONG;
|
||||||
|
sa.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
|
||||||
|
sa.extended_addr = ieee802154_devaddr_from_raw(saddr);
|
||||||
|
|
||||||
|
/* intra-PAN communications */
|
||||||
|
da.pan_id = sa.pan_id;
|
||||||
|
|
||||||
|
/* if the destination address is the broadcast address, use the
|
||||||
|
* corresponding short address
|
||||||
|
*/
|
||||||
|
if (lowpan_is_addr_broadcast((const u8 *)daddr)) {
|
||||||
|
da.mode = IEEE802154_ADDR_SHORT;
|
||||||
|
da.short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
|
||||||
|
cb->ackreq = false;
|
||||||
|
} else {
|
||||||
|
da.mode = IEEE802154_ADDR_LONG;
|
||||||
|
da.extended_addr = ieee802154_devaddr_from_raw(daddr);
|
||||||
|
cb->ackreq = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dev_hard_header(skb, lowpan_dev_info(dev)->real_dev,
|
||||||
|
ETH_P_IPV6, (void *)&da, (void *)&sa, 0);
|
||||||
|
}
|
||||||
|
|
||||||
static netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *dev)
|
static netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||||
{
|
{
|
||||||
struct ieee802154_hdr wpan_hdr;
|
struct ieee802154_hdr wpan_hdr;
|
||||||
int max_single;
|
int max_single, ret;
|
||||||
|
|
||||||
pr_debug("package xmit\n");
|
pr_debug("package xmit\n");
|
||||||
|
|
||||||
|
/* We must take a copy of the skb before we modify/replace the ipv6
|
||||||
|
* header as the header could be used elsewhere
|
||||||
|
*/
|
||||||
|
skb = skb_unshare(skb, GFP_ATOMIC);
|
||||||
|
if (!skb)
|
||||||
|
return NET_XMIT_DROP;
|
||||||
|
|
||||||
|
ret = lowpan_header(skb, dev);
|
||||||
|
if (ret < 0) {
|
||||||
|
kfree_skb(skb);
|
||||||
|
return NET_XMIT_DROP;
|
||||||
|
}
|
||||||
|
|
||||||
if (ieee802154_hdr_peek(skb, &wpan_hdr) < 0) {
|
if (ieee802154_hdr_peek(skb, &wpan_hdr) < 0) {
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
return NET_XMIT_DROP;
|
return NET_XMIT_DROP;
|
||||||
|
|
Loading…
Add table
Reference in a new issue