Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
* 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6: (30 commits) [IPSEC] IPV6: Fix to add tunnel mode SA correctly. [NET]: Cut off the queue_mapping field from sk_buff [NET]: Hide the queue_mapping field inside netif_subqueue_stopped [NET]: Make and use skb_get_queue_mapping [NET]: Use the skb_set_queue_mapping where appropriate [INET]: Use MODULE_ALIAS_NET_PF_PROTO_TYPE where possible. [INET]: Let inet_diag and friends autoload [NIU]: Cleanup PAGE_SIZE checks a bit [NET]: Fix SKB_WITH_OVERHEAD calculation [ATM]: Fix clip module reload crash. [TG3]: Update version to 3.85 [TG3]: PCI command adjustment [TG3]: Add management FW version to ethtool report [TG3]: Add 5723 support [Bluetooth] Convert RFCOMM to use kthread API [Bluetooth] Add constant for Bluetooth socket options level [Bluetooth] Add support for handling simple eSCO links [Bluetooth] Add address and channel attribute to RFCOMM TTY device [Bluetooth] Fix wrong argument in debug code of HIDP [Bluetooth] Add generic driver for Bluetooth USB devices ...
This commit is contained in:
commit
f09cc910fe
@ -22,6 +22,30 @@ config BT_HCIUSB_SCO
|
||||
|
||||
Say Y here to compile support for SCO over HCI USB.
|
||||
|
||||
config BT_HCIBTUSB
|
||||
tristate "HCI USB driver (alternate version)"
|
||||
depends on USB && EXPERIMENTAL && BT_HCIUSB=n
|
||||
help
|
||||
Bluetooth HCI USB driver.
|
||||
This driver is required if you want to use Bluetooth devices with
|
||||
USB interface.
|
||||
|
||||
This driver is still experimental and has no SCO support.
|
||||
|
||||
Say Y here to compile support for Bluetooth USB devices into the
|
||||
kernel or say M to compile it as module (btusb).
|
||||
|
||||
config BT_HCIBTSDIO
|
||||
tristate "HCI SDIO driver"
|
||||
depends on MMC
|
||||
help
|
||||
Bluetooth HCI SDIO driver.
|
||||
This driver is required if you want to use Bluetooth device with
|
||||
SDIO interface.
|
||||
|
||||
Say Y here to compile support for Bluetooth SDIO devices into the
|
||||
kernel or say M to compile it as module (btsdio).
|
||||
|
||||
config BT_HCIUART
|
||||
tristate "HCI UART driver"
|
||||
help
|
||||
@ -55,6 +79,17 @@ config BT_HCIUART_BCSP
|
||||
|
||||
Say Y here to compile support for HCI BCSP protocol.
|
||||
|
||||
config BT_HCIUART_LL
|
||||
bool "HCILL protocol support"
|
||||
depends on BT_HCIUART
|
||||
help
|
||||
HCILL (HCI Low Level) is a serial protocol for communication
|
||||
between Bluetooth device and host. This protocol is required for
|
||||
serial Bluetooth devices that are based on Texas Instruments'
|
||||
BRF chips.
|
||||
|
||||
Say Y here to compile support for HCILL protocol.
|
||||
|
||||
config BT_HCIBCM203X
|
||||
tristate "HCI BCM203x USB driver"
|
||||
depends on USB
|
||||
|
@ -13,7 +13,11 @@ obj-$(CONFIG_BT_HCIBT3C) += bt3c_cs.o
|
||||
obj-$(CONFIG_BT_HCIBLUECARD) += bluecard_cs.o
|
||||
obj-$(CONFIG_BT_HCIBTUART) += btuart_cs.o
|
||||
|
||||
obj-$(CONFIG_BT_HCIBTUSB) += btusb.o
|
||||
obj-$(CONFIG_BT_HCIBTSDIO) += btsdio.o
|
||||
|
||||
hci_uart-y := hci_ldisc.o
|
||||
hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o
|
||||
hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o
|
||||
hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o
|
||||
hci_uart-objs := $(hci_uart-y)
|
||||
|
@ -503,10 +503,7 @@ static irqreturn_t bluecard_interrupt(int irq, void *dev_inst)
|
||||
unsigned int iobase;
|
||||
unsigned char reg;
|
||||
|
||||
if (!info || !info->hdev) {
|
||||
BT_ERR("Call of irq %d for unknown device", irq);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
BUG_ON(!info->hdev);
|
||||
|
||||
if (!test_bit(CARD_READY, &(info->hw_state)))
|
||||
return IRQ_HANDLED;
|
||||
|
@ -2,7 +2,7 @@
|
||||
*
|
||||
* Digianswer Bluetooth USB driver
|
||||
*
|
||||
* Copyright (C) 2004-2005 Marcel Holtmann <marcel@holtmann.org>
|
||||
* Copyright (C) 2004-2007 Marcel Holtmann <marcel@holtmann.org>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@ -21,13 +21,14 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
@ -39,7 +40,7 @@
|
||||
#define BT_DBG(D...)
|
||||
#endif
|
||||
|
||||
#define VERSION "0.8"
|
||||
#define VERSION "0.9"
|
||||
|
||||
static int ignore = 0;
|
||||
|
||||
@ -52,393 +53,285 @@ static struct usb_device_id bpa10x_table[] = {
|
||||
|
||||
MODULE_DEVICE_TABLE(usb, bpa10x_table);
|
||||
|
||||
#define BPA10X_CMD_EP 0x00
|
||||
#define BPA10X_EVT_EP 0x81
|
||||
#define BPA10X_TX_EP 0x02
|
||||
#define BPA10X_RX_EP 0x82
|
||||
|
||||
#define BPA10X_CMD_BUF_SIZE 252
|
||||
#define BPA10X_EVT_BUF_SIZE 16
|
||||
#define BPA10X_TX_BUF_SIZE 384
|
||||
#define BPA10X_RX_BUF_SIZE 384
|
||||
|
||||
struct bpa10x_data {
|
||||
struct hci_dev *hdev;
|
||||
struct usb_device *udev;
|
||||
struct hci_dev *hdev;
|
||||
struct usb_device *udev;
|
||||
|
||||
rwlock_t lock;
|
||||
struct usb_anchor tx_anchor;
|
||||
struct usb_anchor rx_anchor;
|
||||
|
||||
struct sk_buff_head cmd_queue;
|
||||
struct urb *cmd_urb;
|
||||
struct urb *evt_urb;
|
||||
struct sk_buff *evt_skb;
|
||||
unsigned int evt_len;
|
||||
|
||||
struct sk_buff_head tx_queue;
|
||||
struct urb *tx_urb;
|
||||
struct urb *rx_urb;
|
||||
struct sk_buff *rx_skb[2];
|
||||
};
|
||||
|
||||
#define HCI_VENDOR_HDR_SIZE 5
|
||||
#define HCI_VENDOR_HDR_SIZE 5
|
||||
|
||||
struct hci_vendor_hdr {
|
||||
__u8 type;
|
||||
__le16 snum;
|
||||
__le16 dlen;
|
||||
__u8 type;
|
||||
__le16 snum;
|
||||
__le16 dlen;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
static void bpa10x_recv_bulk(struct bpa10x_data *data, unsigned char *buf, int count)
|
||||
static int bpa10x_recv(struct hci_dev *hdev, int queue, void *buf, int count)
|
||||
{
|
||||
struct hci_acl_hdr *ah;
|
||||
struct hci_sco_hdr *sh;
|
||||
struct hci_vendor_hdr *vh;
|
||||
struct sk_buff *skb;
|
||||
int len;
|
||||
struct bpa10x_data *data = hdev->driver_data;
|
||||
|
||||
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) {
|
||||
switch (*buf++) {
|
||||
case HCI_ACLDATA_PKT:
|
||||
ah = (struct hci_acl_hdr *) buf;
|
||||
len = HCI_ACL_HDR_SIZE + __le16_to_cpu(ah->dlen);
|
||||
skb = bt_skb_alloc(len, GFP_ATOMIC);
|
||||
if (skb) {
|
||||
memcpy(skb_put(skb, len), buf, len);
|
||||
skb->dev = (void *) data->hdev;
|
||||
bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
|
||||
hci_recv_frame(skb);
|
||||
}
|
||||
break;
|
||||
struct sk_buff *skb = data->rx_skb[queue];
|
||||
struct { __u8 type; int expect; } *scb;
|
||||
int type, len = 0;
|
||||
|
||||
case HCI_SCODATA_PKT:
|
||||
sh = (struct hci_sco_hdr *) buf;
|
||||
len = HCI_SCO_HDR_SIZE + sh->dlen;
|
||||
skb = bt_skb_alloc(len, GFP_ATOMIC);
|
||||
if (skb) {
|
||||
memcpy(skb_put(skb, len), buf, len);
|
||||
skb->dev = (void *) data->hdev;
|
||||
bt_cb(skb)->pkt_type = HCI_SCODATA_PKT;
|
||||
hci_recv_frame(skb);
|
||||
}
|
||||
break;
|
||||
|
||||
case HCI_VENDOR_PKT:
|
||||
vh = (struct hci_vendor_hdr *) buf;
|
||||
len = HCI_VENDOR_HDR_SIZE + __le16_to_cpu(vh->dlen);
|
||||
skb = bt_skb_alloc(len, GFP_ATOMIC);
|
||||
if (skb) {
|
||||
memcpy(skb_put(skb, len), buf, len);
|
||||
skb->dev = (void *) data->hdev;
|
||||
bt_cb(skb)->pkt_type = HCI_VENDOR_PKT;
|
||||
hci_recv_frame(skb);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
len = count - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
buf += len;
|
||||
count -= (len + 1);
|
||||
}
|
||||
}
|
||||
|
||||
static int bpa10x_recv_event(struct bpa10x_data *data, unsigned char *buf, int size)
|
||||
{
|
||||
BT_DBG("data %p buf %p size %d", data, buf, size);
|
||||
|
||||
if (data->evt_skb) {
|
||||
struct sk_buff *skb = data->evt_skb;
|
||||
|
||||
memcpy(skb_put(skb, size), buf, size);
|
||||
|
||||
if (skb->len == data->evt_len) {
|
||||
data->evt_skb = NULL;
|
||||
data->evt_len = 0;
|
||||
hci_recv_frame(skb);
|
||||
}
|
||||
} else {
|
||||
struct sk_buff *skb;
|
||||
struct hci_event_hdr *hdr;
|
||||
unsigned char pkt_type;
|
||||
int pkt_len = 0;
|
||||
|
||||
if (size < HCI_EVENT_HDR_SIZE + 1) {
|
||||
BT_ERR("%s event packet block with size %d is too short",
|
||||
data->hdev->name, size);
|
||||
return -EILSEQ;
|
||||
}
|
||||
|
||||
pkt_type = *buf++;
|
||||
size--;
|
||||
|
||||
if (pkt_type != HCI_EVENT_PKT) {
|
||||
BT_ERR("%s unexpected event packet start byte 0x%02x",
|
||||
data->hdev->name, pkt_type);
|
||||
return -EPROTO;
|
||||
}
|
||||
|
||||
hdr = (struct hci_event_hdr *) buf;
|
||||
pkt_len = HCI_EVENT_HDR_SIZE + hdr->plen;
|
||||
|
||||
skb = bt_skb_alloc(pkt_len, GFP_ATOMIC);
|
||||
if (!skb) {
|
||||
BT_ERR("%s no memory for new event packet",
|
||||
data->hdev->name);
|
||||
return -ENOMEM;
|
||||
}
|
||||
/* Start of the frame */
|
||||
|
||||
skb->dev = (void *) data->hdev;
|
||||
bt_cb(skb)->pkt_type = pkt_type;
|
||||
type = *((__u8 *) buf);
|
||||
count--; buf++;
|
||||
|
||||
memcpy(skb_put(skb, size), buf, size);
|
||||
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;
|
||||
|
||||
if (pkt_len == size) {
|
||||
hci_recv_frame(skb);
|
||||
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 {
|
||||
data->evt_skb = skb;
|
||||
data->evt_len = pkt_len;
|
||||
/* 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 void bpa10x_wakeup(struct bpa10x_data *data)
|
||||
static void bpa10x_tx_complete(struct urb *urb)
|
||||
{
|
||||
struct urb *urb;
|
||||
struct sk_buff *skb;
|
||||
struct sk_buff *skb = urb->context;
|
||||
struct hci_dev *hdev = (struct hci_dev *) skb->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))
|
||||
goto done;
|
||||
|
||||
if (!urb->status)
|
||||
hdev->stat.byte_tx += urb->transfer_buffer_length;
|
||||
else
|
||||
hdev->stat.err_tx++;
|
||||
|
||||
done:
|
||||
kfree(urb->setup_packet);
|
||||
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
static void bpa10x_rx_complete(struct urb *urb)
|
||||
{
|
||||
struct hci_dev *hdev = urb->context;
|
||||
struct bpa10x_data *data = hdev->driver_data;
|
||||
int err;
|
||||
|
||||
BT_DBG("data %p", data);
|
||||
BT_DBG("%s urb %p status %d count %d", hdev->name,
|
||||
urb, urb->status, urb->actual_length);
|
||||
|
||||
urb = data->cmd_urb;
|
||||
if (urb->status == -EINPROGRESS)
|
||||
skb = NULL;
|
||||
else
|
||||
skb = skb_dequeue(&data->cmd_queue);
|
||||
|
||||
if (skb) {
|
||||
struct usb_ctrlrequest *cr;
|
||||
|
||||
if (skb->len > BPA10X_CMD_BUF_SIZE) {
|
||||
BT_ERR("%s command packet with size %d is too big",
|
||||
data->hdev->name, skb->len);
|
||||
kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
cr = (struct usb_ctrlrequest *) urb->setup_packet;
|
||||
cr->wLength = __cpu_to_le16(skb->len);
|
||||
|
||||
skb_copy_from_linear_data(skb, urb->transfer_buffer, skb->len);
|
||||
urb->transfer_buffer_length = skb->len;
|
||||
|
||||
err = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (err < 0 && err != -ENODEV) {
|
||||
BT_ERR("%s submit failed for command urb %p with error %d",
|
||||
data->hdev->name, urb, err);
|
||||
skb_queue_head(&data->cmd_queue, skb);
|
||||
} else
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
urb = data->tx_urb;
|
||||
if (urb->status == -EINPROGRESS)
|
||||
skb = NULL;
|
||||
else
|
||||
skb = skb_dequeue(&data->tx_queue);
|
||||
|
||||
if (skb) {
|
||||
skb_copy_from_linear_data(skb, urb->transfer_buffer, skb->len);
|
||||
urb->transfer_buffer_length = skb->len;
|
||||
|
||||
err = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (err < 0 && err != -ENODEV) {
|
||||
BT_ERR("%s submit failed for command urb %p with error %d",
|
||||
data->hdev->name, urb, err);
|
||||
skb_queue_head(&data->tx_queue, skb);
|
||||
} else
|
||||
kfree_skb(skb);
|
||||
}
|
||||
}
|
||||
|
||||
static void bpa10x_complete(struct urb *urb)
|
||||
{
|
||||
struct bpa10x_data *data = urb->context;
|
||||
unsigned char *buf = urb->transfer_buffer;
|
||||
int err, count = urb->actual_length;
|
||||
|
||||
BT_DBG("data %p urb %p buf %p count %d", data, urb, buf, count);
|
||||
|
||||
read_lock(&data->lock);
|
||||
|
||||
if (!test_bit(HCI_RUNNING, &data->hdev->flags))
|
||||
goto unlock;
|
||||
|
||||
if (urb->status < 0 || !count)
|
||||
goto resubmit;
|
||||
|
||||
if (usb_pipein(urb->pipe)) {
|
||||
data->hdev->stat.byte_rx += count;
|
||||
|
||||
if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)
|
||||
bpa10x_recv_event(data, buf, count);
|
||||
|
||||
if (usb_pipetype(urb->pipe) == PIPE_BULK)
|
||||
bpa10x_recv_bulk(data, buf, count);
|
||||
} else {
|
||||
data->hdev->stat.byte_tx += count;
|
||||
|
||||
bpa10x_wakeup(data);
|
||||
}
|
||||
|
||||
resubmit:
|
||||
if (usb_pipein(urb->pipe)) {
|
||||
err = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (err < 0 && err != -ENODEV) {
|
||||
BT_ERR("%s urb %p type %d resubmit status %d",
|
||||
data->hdev->name, urb, usb_pipetype(urb->pipe), err);
|
||||
}
|
||||
}
|
||||
|
||||
unlock:
|
||||
read_unlock(&data->lock);
|
||||
}
|
||||
|
||||
static inline struct urb *bpa10x_alloc_urb(struct usb_device *udev, unsigned int pipe,
|
||||
size_t size, gfp_t flags, void *data)
|
||||
{
|
||||
struct urb *urb;
|
||||
struct usb_ctrlrequest *cr;
|
||||
unsigned char *buf;
|
||||
|
||||
BT_DBG("udev %p data %p", udev, data);
|
||||
|
||||
urb = usb_alloc_urb(0, flags);
|
||||
if (!urb)
|
||||
return NULL;
|
||||
|
||||
buf = kmalloc(size, flags);
|
||||
if (!buf) {
|
||||
usb_free_urb(urb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (usb_pipetype(pipe)) {
|
||||
case PIPE_CONTROL:
|
||||
cr = kmalloc(sizeof(*cr), flags);
|
||||
if (!cr) {
|
||||
kfree(buf);
|
||||
usb_free_urb(urb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cr->bRequestType = USB_TYPE_VENDOR;
|
||||
cr->bRequest = 0;
|
||||
cr->wIndex = 0;
|
||||
cr->wValue = 0;
|
||||
cr->wLength = __cpu_to_le16(0);
|
||||
|
||||
usb_fill_control_urb(urb, udev, pipe, (void *) cr, buf, 0, bpa10x_complete, data);
|
||||
break;
|
||||
|
||||
case PIPE_INTERRUPT:
|
||||
usb_fill_int_urb(urb, udev, pipe, buf, size, bpa10x_complete, data, 1);
|
||||
break;
|
||||
|
||||
case PIPE_BULK:
|
||||
usb_fill_bulk_urb(urb, udev, pipe, buf, size, bpa10x_complete, data);
|
||||
break;
|
||||
|
||||
default:
|
||||
kfree(buf);
|
||||
usb_free_urb(urb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return urb;
|
||||
}
|
||||
|
||||
static inline void bpa10x_free_urb(struct urb *urb)
|
||||
{
|
||||
BT_DBG("urb %p", urb);
|
||||
|
||||
if (!urb)
|
||||
if (!test_bit(HCI_RUNNING, &hdev->flags))
|
||||
return;
|
||||
|
||||
kfree(urb->setup_packet);
|
||||
kfree(urb->transfer_buffer);
|
||||
if (urb->status == 0) {
|
||||
if (bpa10x_recv(hdev, usb_pipebulk(urb->pipe),
|
||||
urb->transfer_buffer,
|
||||
urb->actual_length) < 0) {
|
||||
BT_ERR("%s corrupted event packet", hdev->name);
|
||||
hdev->stat.err_rx++;
|
||||
}
|
||||
}
|
||||
|
||||
usb_anchor_urb(urb, &data->rx_anchor);
|
||||
|
||||
err = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (err < 0) {
|
||||
BT_ERR("%s urb %p failed to resubmit (%d)",
|
||||
hdev->name, urb, -err);
|
||||
usb_unanchor_urb(urb);
|
||||
}
|
||||
}
|
||||
|
||||
static inline int bpa10x_submit_intr_urb(struct hci_dev *hdev)
|
||||
{
|
||||
struct bpa10x_data *data = hdev->driver_data;
|
||||
struct urb *urb;
|
||||
unsigned char *buf;
|
||||
unsigned int pipe;
|
||||
int err, size = 16;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!urb)
|
||||
return -ENOMEM;
|
||||
|
||||
buf = kmalloc(size, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
usb_free_urb(urb);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pipe = usb_rcvintpipe(data->udev, 0x81);
|
||||
|
||||
usb_fill_int_urb(urb, data->udev, pipe, buf, size,
|
||||
bpa10x_rx_complete, hdev, 1);
|
||||
|
||||
urb->transfer_flags |= URB_FREE_BUFFER;
|
||||
|
||||
usb_anchor_urb(urb, &data->rx_anchor);
|
||||
|
||||
err = usb_submit_urb(urb, GFP_KERNEL);
|
||||
if (err < 0) {
|
||||
BT_ERR("%s urb %p submission failed (%d)",
|
||||
hdev->name, urb, -err);
|
||||
usb_unanchor_urb(urb);
|
||||
kfree(buf);
|
||||
}
|
||||
|
||||
usb_free_urb(urb);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline int bpa10x_submit_bulk_urb(struct hci_dev *hdev)
|
||||
{
|
||||
struct bpa10x_data *data = hdev->driver_data;
|
||||
struct urb *urb;
|
||||
unsigned char *buf;
|
||||
unsigned int pipe;
|
||||
int err, size = 64;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!urb)
|
||||
return -ENOMEM;
|
||||
|
||||
buf = kmalloc(size, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
usb_free_urb(urb);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pipe = usb_rcvbulkpipe(data->udev, 0x82);
|
||||
|
||||
usb_fill_bulk_urb(urb, data->udev, pipe,
|
||||
buf, size, bpa10x_rx_complete, hdev);
|
||||
|
||||
urb->transfer_flags |= URB_FREE_BUFFER;
|
||||
|
||||
usb_anchor_urb(urb, &data->rx_anchor);
|
||||
|
||||
err = usb_submit_urb(urb, GFP_KERNEL);
|
||||
if (err < 0) {
|
||||
BT_ERR("%s urb %p submission failed (%d)",
|
||||
hdev->name, urb, -err);
|
||||
usb_unanchor_urb(urb);
|
||||
kfree(buf);
|
||||
}
|
||||
|
||||
usb_free_urb(urb);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int bpa10x_open(struct hci_dev *hdev)
|
||||
{
|
||||
struct bpa10x_data *data = hdev->driver_data;
|
||||
struct usb_device *udev = data->udev;
|
||||
unsigned long flags;
|
||||
int err;
|
||||
|
||||
BT_DBG("hdev %p data %p", hdev, data);
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
|
||||
return 0;
|
||||
|
||||
data->cmd_urb = bpa10x_alloc_urb(udev, usb_sndctrlpipe(udev, BPA10X_CMD_EP),
|
||||
BPA10X_CMD_BUF_SIZE, GFP_KERNEL, data);
|
||||
if (!data->cmd_urb) {
|
||||
err = -ENOMEM;
|
||||
goto done;
|
||||
}
|
||||
|
||||
data->evt_urb = bpa10x_alloc_urb(udev, usb_rcvintpipe(udev, BPA10X_EVT_EP),
|
||||
BPA10X_EVT_BUF_SIZE, GFP_KERNEL, data);
|
||||
if (!data->evt_urb) {
|
||||
bpa10x_free_urb(data->cmd_urb);
|
||||
err = -ENOMEM;
|
||||
goto done;
|
||||
}
|
||||
|
||||
data->rx_urb = bpa10x_alloc_urb(udev, usb_rcvbulkpipe(udev, BPA10X_RX_EP),
|
||||
BPA10X_RX_BUF_SIZE, GFP_KERNEL, data);
|
||||
if (!data->rx_urb) {
|
||||
bpa10x_free_urb(data->evt_urb);
|
||||
bpa10x_free_urb(data->cmd_urb);
|
||||
err = -ENOMEM;
|
||||
goto done;
|
||||
}
|
||||
|
||||
data->tx_urb = bpa10x_alloc_urb(udev, usb_sndbulkpipe(udev, BPA10X_TX_EP),
|
||||
BPA10X_TX_BUF_SIZE, GFP_KERNEL, data);
|
||||
if (!data->rx_urb) {
|
||||
bpa10x_free_urb(data->rx_urb);
|
||||
bpa10x_free_urb(data->evt_urb);
|
||||
bpa10x_free_urb(data->cmd_urb);
|
||||
err = -ENOMEM;
|
||||
goto done;
|
||||
}
|
||||
|
||||
write_lock_irqsave(&data->lock, flags);
|
||||
|
||||
err = usb_submit_urb(data->evt_urb, GFP_ATOMIC);
|
||||
if (err < 0) {
|
||||
BT_ERR("%s submit failed for event urb %p with error %d",
|
||||
data->hdev->name, data->evt_urb, err);
|
||||
} else {
|
||||
err = usb_submit_urb(data->rx_urb, GFP_ATOMIC);
|
||||
if (err < 0) {
|
||||
BT_ERR("%s submit failed for rx urb %p with error %d",
|
||||
data->hdev->name, data->evt_urb, err);
|
||||
usb_kill_urb(data->evt_urb);
|
||||
}
|
||||
}
|
||||
|
||||
write_unlock_irqrestore(&data->lock, flags);
|
||||
|
||||
done:
|
||||
err = bpa10x_submit_intr_urb(hdev);
|
||||
if (err < 0)
|
||||
clear_bit(HCI_RUNNING, &hdev->flags);
|
||||
goto error;
|
||||
|
||||
err = bpa10x_submit_bulk_urb(hdev);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
usb_kill_anchored_urbs(&data->rx_anchor);
|
||||
|
||||
clear_bit(HCI_RUNNING, &hdev->flags);
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -446,27 +339,13 @@ static int bpa10x_open(struct hci_dev *hdev)
|
||||
static int bpa10x_close(struct hci_dev *hdev)
|
||||
{
|
||||
struct bpa10x_data *data = hdev->driver_data;
|
||||
unsigned long flags;
|
||||
|
||||
BT_DBG("hdev %p data %p", hdev, data);
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
|
||||
return 0;
|
||||
|
||||
write_lock_irqsave(&data->lock, flags);
|
||||
|
||||
skb_queue_purge(&data->cmd_queue);
|
||||
usb_kill_urb(data->cmd_urb);
|
||||
usb_kill_urb(data->evt_urb);
|
||||
usb_kill_urb(data->rx_urb);
|
||||
usb_kill_urb(data->tx_urb);
|
||||
|
||||
write_unlock_irqrestore(&data->lock, flags);
|
||||
|
||||
bpa10x_free_urb(data->cmd_urb);
|
||||
bpa10x_free_urb(data->evt_urb);
|
||||
bpa10x_free_urb(data->rx_urb);
|
||||
bpa10x_free_urb(data->tx_urb);
|
||||
usb_kill_anchored_urbs(&data->rx_anchor);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -475,9 +354,9 @@ static int bpa10x_flush(struct hci_dev *hdev)
|
||||
{
|
||||
struct bpa10x_data *data = hdev->driver_data;
|
||||
|
||||
BT_DBG("hdev %p data %p", hdev, data);
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
skb_queue_purge(&data->cmd_queue);
|
||||
usb_kill_anchored_urbs(&data->tx_anchor);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -485,45 +364,78 @@ static int bpa10x_flush(struct hci_dev *hdev)
|
||||
static int bpa10x_send_frame(struct sk_buff *skb)
|
||||
{
|
||||
struct hci_dev *hdev = (struct hci_dev *) skb->dev;
|
||||
struct bpa10x_data *data;
|
||||
struct bpa10x_data *data = hdev->driver_data;
|
||||
struct usb_ctrlrequest *dr;
|
||||
struct urb *urb;
|
||||
unsigned int pipe;
|
||||
int err;
|
||||
|
||||
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");
|
||||
return -ENODEV;
|
||||
}
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
if (!test_bit(HCI_RUNNING, &hdev->flags))
|
||||
return -EBUSY;
|
||||
|
||||
data = hdev->driver_data;
|
||||
urb = usb_alloc_urb(0, GFP_ATOMIC);
|
||||
if (!urb)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Prepend skb with frame type */
|
||||
memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
|
||||
*skb_push(skb, 1) = bt_cb(skb)->pkt_type;
|
||||
|
||||
switch (bt_cb(skb)->pkt_type) {
|
||||
case HCI_COMMAND_PKT:
|
||||
dr = kmalloc(sizeof(*dr), GFP_ATOMIC);
|
||||
if (!dr) {
|
||||
usb_free_urb(urb);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dr->bRequestType = USB_TYPE_VENDOR;
|
||||
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, bpa10x_tx_complete, skb);
|
||||
|
||||
hdev->stat.cmd_tx++;
|
||||
skb_queue_tail(&data->cmd_queue, skb);
|
||||
break;
|
||||
|
||||
case HCI_ACLDATA_PKT:
|
||||
pipe = usb_sndbulkpipe(data->udev, 0x02);
|
||||
|
||||
usb_fill_bulk_urb(urb, data->udev, pipe,
|
||||
skb->data, skb->len, bpa10x_tx_complete, skb);
|
||||
|
||||
hdev->stat.acl_tx++;
|
||||
skb_queue_tail(&data->tx_queue, skb);
|
||||
break;
|
||||
|
||||
case HCI_SCODATA_PKT:
|
||||
pipe = usb_sndbulkpipe(data->udev, 0x02);
|
||||
|
||||
usb_fill_bulk_urb(urb, data->udev, pipe,
|
||||
skb->data, skb->len, bpa10x_tx_complete, skb);
|
||||
|
||||
hdev->stat.sco_tx++;
|
||||
skb_queue_tail(&data->tx_queue, skb);
|
||||
break;
|
||||
};
|
||||
|
||||
read_lock(&data->lock);
|
||||
default:
|
||||
return -EILSEQ;
|
||||
}
|
||||
|
||||
bpa10x_wakeup(data);
|
||||
usb_anchor_urb(urb, &data->tx_anchor);
|
||||
|
||||
read_unlock(&data->lock);
|
||||
err = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (err < 0) {
|
||||
BT_ERR("%s urb %p submission failed", hdev->name, urb);
|
||||
kfree(urb->setup_packet);
|
||||
usb_unanchor_urb(urb);
|
||||
}
|
||||
|
||||
usb_free_urb(urb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -532,16 +444,17 @@ static void bpa10x_destruct(struct hci_dev *hdev)
|
||||
{
|
||||
struct bpa10x_data *data = hdev->driver_data;
|
||||
|
||||
BT_DBG("hdev %p data %p", hdev, data);
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
kfree(data->rx_skb[0]);
|
||||
kfree(data->rx_skb[1]);
|
||||
kfree(data);
|
||||
}
|
||||
|
||||
static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_device *udev = interface_to_usbdev(intf);
|
||||
struct hci_dev *hdev;
|
||||
struct bpa10x_data *data;
|
||||
struct hci_dev *hdev;
|
||||
int err;
|
||||
|
||||
BT_DBG("intf %p id %p", intf, id);
|
||||
@ -549,48 +462,43 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *
|
||||
if (ignore)
|
||||
return -ENODEV;
|
||||
|
||||
if (intf->cur_altsetting->desc.bInterfaceNumber > 0)
|
||||
if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
|
||||
return -ENODEV;
|
||||
|
||||
data = kzalloc(sizeof(*data), GFP_KERNEL);
|
||||
if (!data) {
|
||||
BT_ERR("Can't allocate data structure");
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
data->udev = udev;
|
||||
data->udev = interface_to_usbdev(intf);
|
||||
|
||||
rwlock_init(&data->lock);
|
||||
|
||||
skb_queue_head_init(&data->cmd_queue);
|
||||
skb_queue_head_init(&data->tx_queue);
|
||||
init_usb_anchor(&data->tx_anchor);
|
||||
init_usb_anchor(&data->rx_anchor);
|
||||
|
||||
hdev = hci_alloc_dev();
|
||||
if (!hdev) {
|
||||
BT_ERR("Can't allocate HCI device");
|
||||
kfree(data);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
data->hdev = hdev;
|
||||
|
||||
hdev->type = HCI_USB;
|
||||
hdev->driver_data = data;
|
||||
|
||||
data->hdev = hdev;
|
||||
|
||||
SET_HCIDEV_DEV(hdev, &intf->dev);
|
||||
|
||||
hdev->open = bpa10x_open;
|
||||
hdev->close = bpa10x_close;
|
||||
hdev->flush = bpa10x_flush;
|
||||
hdev->send = bpa10x_send_frame;
|
||||
hdev->destruct = bpa10x_destruct;
|
||||
hdev->open = bpa10x_open;
|
||||
hdev->close = bpa10x_close;
|
||||
hdev->flush = bpa10x_flush;
|
||||
hdev->send = bpa10x_send_frame;
|
||||
hdev->destruct = bpa10x_destruct;
|
||||
|
||||
hdev->owner = THIS_MODULE;
|
||||
|
||||
err = hci_register_dev(hdev);
|
||||
if (err < 0) {
|
||||
BT_ERR("Can't register HCI device");
|
||||
kfree(data);
|
||||
hci_free_dev(hdev);
|
||||
kfree(data);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -602,19 +510,17 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *
|
||||
static void bpa10x_disconnect(struct usb_interface *intf)
|
||||
{
|
||||
struct bpa10x_data *data = usb_get_intfdata(intf);
|
||||
struct hci_dev *hdev = data->hdev;
|
||||
|
||||
BT_DBG("intf %p", intf);
|
||||
|
||||
if (!hdev)
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
usb_set_intfdata(intf, NULL);
|
||||
|
||||
if (hci_unregister_dev(hdev) < 0)
|
||||
BT_ERR("Can't unregister HCI device %s", hdev->name);
|
||||
hci_unregister_dev(data->hdev);
|
||||
|
||||
hci_free_dev(hdev);
|
||||
hci_free_dev(data->hdev);
|
||||
}
|
||||
|
||||
static struct usb_driver bpa10x_driver = {
|
||||
@ -626,15 +532,9 @@ static struct usb_driver bpa10x_driver = {
|
||||
|
||||
static int __init bpa10x_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
BT_INFO("Digianswer Bluetooth USB driver ver %s", VERSION);
|
||||
|
||||
err = usb_register(&bpa10x_driver);
|
||||
if (err < 0)
|
||||
BT_ERR("Failed to register USB driver");
|
||||
|
||||
return err;
|
||||
return usb_register(&bpa10x_driver);
|
||||
}
|
||||
|
||||
static void __exit bpa10x_exit(void)
|
||||
|
@ -344,10 +344,7 @@ static irqreturn_t bt3c_interrupt(int irq, void *dev_inst)
|
||||
unsigned int iobase;
|
||||
int iir;
|
||||
|
||||
if (!info || !info->hdev) {
|
||||
BT_ERR("Call of irq %d for unknown device", irq);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
BUG_ON(!info->hdev);
|
||||
|
||||
iobase = info->p_dev->io.BasePort1;
|
||||
|
||||
|
406
drivers/bluetooth/btsdio.c
Normal file
406
drivers/bluetooth/btsdio.c
Normal file
@ -0,0 +1,406 @@
|
||||
/*
|
||||
*
|
||||
* Generic Bluetooth SDIO driver
|
||||
*
|
||||
* Copyright (C) 2007 Cambridge Silicon Radio Ltd.
|
||||
* Copyright (C) 2007 Marcel Holtmann <marcel@holtmann.org>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
#include <linux/mmc/sdio_ids.h>
|
||||
#include <linux/mmc/sdio_func.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
|
||||
#ifndef CONFIG_BT_HCIBTSDIO_DEBUG
|
||||
#undef BT_DBG
|
||||
#define BT_DBG(D...)
|
||||
#endif
|
||||
|
||||
#define VERSION "0.1"
|
||||
|
||||
static const struct sdio_device_id btsdio_table[] = {
|
||||
/* Generic Bluetooth Type-A SDIO device */
|
||||
{ SDIO_DEVICE_CLASS(SDIO_CLASS_BT_A) },
|
||||
|
||||
/* Generic Bluetooth Type-B SDIO device */
|
||||
{ SDIO_DEVICE_CLASS(SDIO_CLASS_BT_B) },
|
||||
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(sdio, btsdio_table);
|
||||
|
||||
struct btsdio_data {
|
||||
struct hci_dev *hdev;
|
||||
struct sdio_func *func;
|
||||
|
||||
struct work_struct work;
|
||||
|
||||
struct sk_buff_head txq;
|
||||
};
|
||||
|
||||
#define REG_RDAT 0x00 /* Receiver Data */
|
||||
#define REG_TDAT 0x00 /* Transmitter Data */
|
||||
#define REG_PC_RRT 0x10 /* Read Packet Control */
|
||||
#define REG_PC_WRT 0x11 /* Write Packet Control */
|
||||
#define REG_RTC_STAT 0x12 /* Retry Control Status */
|
||||
#define REG_RTC_SET 0x12 /* Retry Control Set */
|
||||
#define REG_INTRD 0x13 /* Interrupt Indication */
|
||||
#define REG_CL_INTRD 0x13 /* Interrupt Clear */
|
||||
#define REG_EN_INTRD 0x14 /* Interrupt Enable */
|
||||
#define REG_MD_STAT 0x20 /* Bluetooth Mode Status */
|
||||
|
||||
static int btsdio_tx_packet(struct btsdio_data *data, struct sk_buff *skb)
|
||||
{
|
||||
int err;
|
||||
|
||||
BT_DBG("%s", data->hdev->name);
|
||||
|
||||
/* Prepend Type-A header */
|
||||
skb_push(skb, 4);
|
||||
skb->data[0] = (skb->len & 0x0000ff);
|
||||
skb->data[1] = (skb->len & 0x00ff00) >> 8;
|
||||
skb->data[2] = (skb->len & 0xff0000) >> 16;
|
||||
skb->data[3] = bt_cb(skb)->pkt_type;
|
||||
|
||||
err = sdio_writesb(data->func, REG_TDAT, skb->data, skb->len);
|
||||
if (err < 0) {
|
||||
sdio_writeb(data->func, 0x01, REG_PC_WRT, NULL);
|
||||
return err;
|
||||
}
|
||||
|
||||
data->hdev->stat.byte_tx += skb->len;
|
||||
|
||||
kfree_skb(skb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void btsdio_work(struct work_struct *work)
|
||||
{
|
||||
struct btsdio_data *data = container_of(work, struct btsdio_data, work);
|
||||
struct sk_buff *skb;
|
||||
int err;
|
||||
|
||||
BT_DBG("%s", data->hdev->name);
|
||||
|
||||
sdio_claim_host(data->func);
|
||||
|
||||
while ((skb = skb_dequeue(&data->txq))) {
|
||||
err = btsdio_tx_packet(data, skb);
|
||||
if (err < 0) {
|
||||
data->hdev->stat.err_tx++;
|
||||
skb_queue_head(&data->txq, skb);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sdio_release_host(data->func);
|
||||
}
|
||||
|
||||
static int btsdio_rx_packet(struct btsdio_data *data)
|
||||
{
|
||||
u8 hdr[4] __attribute__ ((aligned(4)));
|
||||
struct sk_buff *skb;
|
||||
int err, len;
|
||||
|
||||
BT_DBG("%s", data->hdev->name);
|
||||
|
||||
err = sdio_readsb(data->func, hdr, REG_RDAT, 4);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
len = hdr[0] | (hdr[1] << 8) | (hdr[2] << 16);
|
||||
if (len < 4 || len > 65543)
|
||||
return -EILSEQ;
|
||||
|
||||
skb = bt_skb_alloc(len - 4, GFP_KERNEL);
|
||||
if (!skb) {
|
||||
/* Out of memory. Prepare a read retry and just
|
||||
* return with the expectation that the next time
|
||||
* we're called we'll have more memory. */
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
skb_put(skb, len - 4);
|
||||
|
||||
err = sdio_readsb(data->func, skb->data, REG_RDAT, len - 4);
|
||||
if (err < 0) {
|
||||
kfree(skb);
|
||||
return err;
|
||||
}
|
||||
|
||||
data->hdev->stat.byte_rx += len;
|
||||
|
||||
skb->dev = (void *) data->hdev;
|
||||
bt_cb(skb)->pkt_type = hdr[3];
|
||||
|
||||
err = hci_recv_frame(skb);
|
||||
if (err < 0) {
|
||||
kfree(skb);
|
||||
return err;
|
||||
}
|
||||
|
||||
sdio_writeb(data->func, 0x00, REG_PC_RRT, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void btsdio_interrupt(struct sdio_func *func)
|
||||
{
|
||||
struct btsdio_data *data = sdio_get_drvdata(func);
|
||||
int intrd;
|
||||
|
||||
BT_DBG("%s", data->hdev->name);
|
||||
|
||||
intrd = sdio_readb(func, REG_INTRD, NULL);
|
||||
if (intrd & 0x01) {
|
||||
sdio_writeb(func, 0x01, REG_CL_INTRD, NULL);
|
||||
|
||||
if (btsdio_rx_packet(data) < 0) {
|
||||
data->hdev->stat.err_rx++;
|
||||
sdio_writeb(data->func, 0x01, REG_PC_RRT, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int btsdio_open(struct hci_dev *hdev)
|
||||
{
|
||||
struct btsdio_data *data = hdev->driver_data;
|
||||
int err;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
|
||||
return 0;
|
||||
|
||||
sdio_claim_host(data->func);
|
||||
|
||||
err = sdio_enable_func(data->func);
|
||||
if (err < 0) {
|
||||
clear_bit(HCI_RUNNING, &hdev->flags);
|
||||
goto release;
|
||||
}
|
||||
|
||||
err = sdio_claim_irq(data->func, btsdio_interrupt);
|
||||
if (err < 0) {
|
||||
sdio_disable_func(data->func);
|
||||
clear_bit(HCI_RUNNING, &hdev->flags);
|
||||
goto release;
|
||||
}
|
||||
|
||||
if (data->func->class == SDIO_CLASS_BT_B)
|
||||
sdio_writeb(data->func, 0x00, REG_MD_STAT, NULL);
|
||||
|
||||
sdio_writeb(data->func, 0x01, REG_EN_INTRD, NULL);
|
||||
|
||||
release:
|
||||
sdio_release_host(data->func);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int btsdio_close(struct hci_dev *hdev)
|
||||
{
|
||||
struct btsdio_data *data = hdev->driver_data;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
|
||||
return 0;
|
||||
|
||||
sdio_claim_host(data->func);
|
||||
|
||||
sdio_writeb(data->func, 0x00, REG_EN_INTRD, NULL);
|
||||
|
||||
sdio_release_irq(data->func);
|
||||
sdio_disable_func(data->func);
|
||||
|
||||
sdio_release_host(data->func);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btsdio_flush(struct hci_dev *hdev)
|
||||
{
|
||||
struct btsdio_data *data = hdev->driver_data;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
skb_queue_purge(&data->txq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btsdio_send_frame(struct sk_buff *skb)
|
||||
{
|
||||
struct hci_dev *hdev = (struct hci_dev *) skb->dev;
|
||||
struct btsdio_data *data = hdev->driver_data;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
if (!test_bit(HCI_RUNNING, &hdev->flags))
|
||||
return -EBUSY;
|
||||
|
||||
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;
|
||||
|
||||
default:
|
||||
return -EILSEQ;
|
||||
}
|
||||
|
||||
skb_queue_tail(&data->txq, skb);
|
||||
|
||||
schedule_work(&data->work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void btsdio_destruct(struct hci_dev *hdev)
|
||||
{
|
||||
struct btsdio_data *data = hdev->driver_data;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
kfree(data);
|
||||
}
|
||||
|
||||
static int btsdio_probe(struct sdio_func *func,
|
||||
const struct sdio_device_id *id)
|
||||
{
|
||||
struct btsdio_data *data;
|
||||
struct hci_dev *hdev;
|
||||
struct sdio_func_tuple *tuple = func->tuples;
|
||||
int err;
|
||||
|
||||
BT_DBG("func %p id %p class 0x%04x", func, id, func->class);
|
||||
|
||||
while (tuple) {
|
||||
BT_DBG("code 0x%x size %d", tuple->code, tuple->size);
|
||||
tuple = tuple->next;
|
||||
}
|
||||
|
||||
data = kzalloc(sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
data->func = func;
|
||||
|
||||
INIT_WORK(&data->work, btsdio_work);
|
||||
|
||||
skb_queue_head_init(&data->txq);
|
||||
|
||||
hdev = hci_alloc_dev();
|
||||
if (!hdev) {
|
||||
kfree(data);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
hdev->type = HCI_SDIO;
|
||||
hdev->driver_data = data;
|
||||
|
||||
data->hdev = hdev;
|
||||
|
||||
SET_HCIDEV_DEV(hdev, &func->dev);
|
||||
|
||||
hdev->open = btsdio_open;
|
||||
hdev->close = btsdio_close;
|
||||
hdev->flush = btsdio_flush;
|
||||
hdev->send = btsdio_send_frame;
|
||||
hdev->destruct = btsdio_destruct;
|
||||
|
||||
hdev->owner = THIS_MODULE;
|
||||
|
||||
err = hci_register_dev(hdev);
|
||||
if (err < 0) {
|
||||
hci_free_dev(hdev);
|
||||
kfree(data);
|
||||
return err;
|
||||
}
|
||||
|
||||
sdio_set_drvdata(func, data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void btsdio_remove(struct sdio_func *func)
|
||||
{
|
||||
struct btsdio_data *data = sdio_get_drvdata(func);
|
||||
struct hci_dev *hdev;
|
||||
|
||||
BT_DBG("func %p", func);
|
||||
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
hdev = data->hdev;
|
||||
|
||||
sdio_set_drvdata(func, NULL);
|
||||
|
||||
hci_unregister_dev(hdev);
|
||||
|
||||
hci_free_dev(hdev);
|
||||
}
|
||||
|
||||
static struct sdio_driver btsdio_driver = {
|
||||
.name = "btsdio",
|
||||
.probe = btsdio_probe,
|
||||
.remove = btsdio_remove,
|
||||
.id_table = btsdio_table,
|
||||
};
|
||||
|
||||
static int __init btsdio_init(void)
|
||||
{
|
||||
BT_INFO("Generic Bluetooth SDIO driver ver %s", VERSION);
|
||||
|
||||
return sdio_register_driver(&btsdio_driver);
|
||||
}
|
||||
|
||||
static void __exit btsdio_exit(void)
|
||||
{
|
||||
sdio_unregister_driver(&btsdio_driver);
|
||||
}
|
||||
|
||||
module_init(btsdio_init);
|
||||
module_exit(btsdio_exit);
|
||||
|
||||
MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
|
||||
MODULE_DESCRIPTION("Generic Bluetooth SDIO driver ver " VERSION);
|
||||
MODULE_VERSION(VERSION);
|
||||
MODULE_LICENSE("GPL");
|
@ -294,10 +294,7 @@ static irqreturn_t btuart_interrupt(int irq, void *dev_inst)
|
||||
int boguscount = 0;
|
||||
int iir, lsr;
|
||||
|
||||
if (!info || !info->hdev) {
|
||||
BT_ERR("Call of irq %d for unknown device", irq);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
BUG_ON(!info->hdev);
|
||||
|
||||
iobase = info->p_dev->io.BasePort1;
|
||||
|
||||
|
564
drivers/bluetooth/btusb.c
Normal file
564
drivers/bluetooth/btusb.c
Normal file
@ -0,0 +1,564 @@
|
||||
/*
|
||||
*
|
||||
* Generic Bluetooth USB driver
|
||||
*
|
||||
* Copyright (C) 2005-2007 Marcel Holtmann <marcel@holtmann.org>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
|
||||
//#define CONFIG_BT_HCIBTUSB_DEBUG
|
||||
#ifndef CONFIG_BT_HCIBTUSB_DEBUG
|
||||
#undef BT_DBG
|
||||
#define BT_DBG(D...)
|
||||
#endif
|
||||
|
||||
#define VERSION "0.1"
|
||||
|
||||
static struct usb_device_id btusb_table[] = {
|
||||
/* Generic Bluetooth USB device */
|
||||
{ USB_DEVICE_INFO(0xe0, 0x01, 0x01) },
|
||||
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(usb, btusb_table);
|
||||
|
||||
static struct usb_device_id blacklist_table[] = {
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
|
||||
#define BTUSB_INTR_RUNNING 0
|
||||
#define BTUSB_BULK_RUNNING 1
|
||||
|
||||
struct btusb_data {
|
||||
struct hci_dev *hdev;
|
||||
struct usb_device *udev;
|
||||
|
||||
spinlock_t lock;
|
||||
|
||||
unsigned long flags;
|
||||
|
||||
struct work_struct work;
|
||||
|
||||
struct usb_anchor tx_anchor;
|
||||
struct usb_anchor intr_anchor;
|
||||
struct usb_anchor bulk_anchor;
|
||||
|
||||
struct usb_endpoint_descriptor *intr_ep;
|
||||
struct usb_endpoint_descriptor *bulk_tx_ep;
|
||||
struct usb_endpoint_descriptor *bulk_rx_ep;
|
||||
};
|
||||
|
||||
static void btusb_intr_complete(struct urb *urb)
|
||||
{
|
||||
struct hci_dev *hdev = urb->context;
|
||||
struct btusb_data *data = hdev->driver_data;
|
||||
int 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) {
|
||||
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_anchor_urb(urb, &data->intr_anchor);
|
||||
|
||||
err = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (err < 0) {
|
||||
BT_ERR("%s urb %p failed to resubmit (%d)",
|
||||
hdev->name, urb, -err);
|
||||
usb_unanchor_urb(urb);
|
||||
}
|
||||
}
|
||||
|
||||
static inline int btusb_submit_intr_urb(struct hci_dev *hdev)
|
||||
{
|
||||
struct btusb_data *data = hdev->driver_data;
|
||||
struct urb *urb;
|
||||
unsigned char *buf;
|
||||
unsigned int pipe;
|
||||
int err, size;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
urb = usb_alloc_urb(0, GFP_ATOMIC);
|
||||
if (!urb)
|
||||
return -ENOMEM;
|
||||
|
||||
size = le16_to_cpu(data->intr_ep->wMaxPacketSize);
|
||||
|
||||
buf = kmalloc(size, GFP_ATOMIC);
|
||||
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, GFP_ATOMIC);
|
||||
if (err < 0) {
|
||||
BT_ERR("%s urb %p submission failed (%d)",
|
||||
hdev->name, urb, -err);
|
||||
usb_unanchor_urb(urb);
|
||||
kfree(buf);
|
||||
}
|
||||
|
||||
usb_free_urb(urb);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void btusb_bulk_complete(struct urb *urb)
|
||||
{
|
||||
struct hci_dev *hdev = urb->context;
|
||||
struct btusb_data *data = hdev->driver_data;
|
||||
int 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) {
|
||||
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);
|
||||
|
||||
err = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (err < 0) {
|
||||
BT_ERR("%s urb %p failed to resubmit (%d)",
|
||||
hdev->name, urb, -err);
|
||||
usb_unanchor_urb(urb);
|
||||
}
|
||||
}
|
||||
|
||||
static inline int btusb_submit_bulk_urb(struct hci_dev *hdev)
|
||||
{
|
||||
struct btusb_data *data = hdev->driver_data;
|
||||
struct urb *urb;
|
||||
unsigned char *buf;
|
||||
unsigned int pipe;
|
||||
int err, size;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!urb)
|
||||
return -ENOMEM;
|
||||
|
||||
size = le16_to_cpu(data->bulk_rx_ep->wMaxPacketSize);
|
||||
|
||||
buf = kmalloc(size, GFP_KERNEL);
|
||||
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_anchor_urb(urb, &data->bulk_anchor);
|
||||
|
||||
err = usb_submit_urb(urb, GFP_KERNEL);
|
||||
if (err < 0) {
|
||||
BT_ERR("%s urb %p submission failed (%d)",
|
||||
hdev->name, urb, -err);
|
||||
usb_unanchor_urb(urb);
|
||||
kfree(buf);
|
||||
}
|
||||
|
||||
usb_free_urb(urb);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void btusb_tx_complete(struct urb *urb)
|
||||
{
|
||||
struct sk_buff *skb = urb->context;
|
||||
struct hci_dev *hdev = (struct hci_dev *) skb->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))
|
||||
goto done;
|
||||
|
||||
if (!urb->status)
|
||||
hdev->stat.byte_tx += urb->transfer_buffer_length;
|
||||
else
|
||||
hdev->stat.err_tx++;
|
||||
|
||||
done:
|
||||
kfree(urb->setup_packet);
|
||||
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
static int btusb_open(struct hci_dev *hdev)
|
||||
{
|
||||
struct btusb_data *data = hdev->driver_data;
|
||||
int err;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
|
||||
return 0;
|
||||
|
||||
if (test_and_set_bit(BTUSB_INTR_RUNNING, &data->flags))
|
||||
return 0;
|
||||
|
||||
err = btusb_submit_intr_urb(hdev);
|
||||
if (err < 0) {
|
||||
clear_bit(BTUSB_INTR_RUNNING, &hdev->flags);
|
||||
clear_bit(HCI_RUNNING, &hdev->flags);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int btusb_close(struct hci_dev *hdev)
|
||||
{
|
||||
struct btusb_data *data = hdev->driver_data;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
|
||||
return 0;
|
||||
|
||||
clear_bit(BTUSB_BULK_RUNNING, &data->flags);
|
||||
usb_kill_anchored_urbs(&data->bulk_anchor);
|
||||
|
||||
clear_bit(BTUSB_INTR_RUNNING, &data->flags);
|
||||
usb_kill_anchored_urbs(&data->intr_anchor);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btusb_flush(struct hci_dev *hdev)
|
||||
{
|
||||
struct btusb_data *data = hdev->driver_data;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
usb_kill_anchored_urbs(&data->tx_anchor);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btusb_send_frame(struct sk_buff *skb)
|
||||
{
|
||||
struct hci_dev *hdev = (struct hci_dev *) skb->dev;
|
||||
struct btusb_data *data = hdev->driver_data;
|
||||
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 = USB_TYPE_CLASS;
|
||||
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:
|
||||
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:
|
||||
hdev->stat.sco_tx++;
|
||||
kfree_skb(skb);
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return -EILSEQ;
|
||||
}
|
||||
|
||||
usb_anchor_urb(urb, &data->tx_anchor);
|
||||
|
||||
err = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (err < 0) {
|
||||
BT_ERR("%s urb %p submission failed", hdev->name, urb);
|
||||
kfree(urb->setup_packet);
|
||||
usb_unanchor_urb(urb);
|
||||
}
|
||||
|
||||
usb_free_urb(urb);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void btusb_destruct(struct hci_dev *hdev)
|
||||
{
|
||||
struct btusb_data *data = hdev->driver_data;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
kfree(data);
|
||||
}
|
||||
|
||||
static void btusb_notify(struct hci_dev *hdev, unsigned int evt)
|
||||
{
|
||||
struct btusb_data *data = hdev->driver_data;
|
||||
|
||||
BT_DBG("%s evt %d", hdev->name, evt);
|
||||
|
||||
if (evt == HCI_NOTIFY_CONN_ADD || evt == HCI_NOTIFY_CONN_DEL)
|
||||
schedule_work(&data->work);
|
||||
}
|
||||
|
||||
static void btusb_work(struct work_struct *work)
|
||||
{
|
||||
struct btusb_data *data = container_of(work, struct btusb_data, work);
|
||||
struct hci_dev *hdev = data->hdev;
|
||||
|
||||
if (hdev->conn_hash.acl_num == 0) {
|
||||
clear_bit(BTUSB_BULK_RUNNING, &data->flags);
|
||||
usb_kill_anchored_urbs(&data->bulk_anchor);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!test_and_set_bit(BTUSB_BULK_RUNNING, &data->flags)) {
|
||||
if (btusb_submit_bulk_urb(hdev) < 0)
|
||||
clear_bit(BTUSB_BULK_RUNNING, &data->flags);
|
||||
else
|
||||
btusb_submit_bulk_urb(hdev);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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->udev = interface_to_usbdev(intf);
|
||||
|
||||
spin_lock_init(&data->lock);
|
||||
|
||||
INIT_WORK(&data->work, btusb_work);
|
||||
|
||||
init_usb_anchor(&data->tx_anchor);
|
||||
init_usb_anchor(&data->intr_anchor);
|
||||
init_usb_anchor(&data->bulk_anchor);
|
||||
|
||||
hdev = hci_alloc_dev();
|
||||
if (!hdev) {
|
||||
kfree(data);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
hdev->type = 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;
|
||||
|
||||
set_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks);
|
||||
|
||||
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 btusb_disconnect(struct usb_interface *intf)
|
||||
{
|
||||
struct btusb_data *data = usb_get_intfdata(intf);
|
||||
struct hci_dev *hdev;
|
||||
|
||||
BT_DBG("intf %p", intf);
|
||||
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
hdev = data->hdev;
|
||||
|
||||
usb_set_intfdata(intf, NULL);
|
||||
|
||||
hci_unregister_dev(hdev);
|
||||
|
||||
hci_free_dev(hdev);
|
||||
}
|
||||
|
||||
static struct usb_driver btusb_driver = {
|
||||
.name = "btusb",
|
||||
.probe = btusb_probe,
|
||||
.disconnect = btusb_disconnect,
|
||||
.id_table = btusb_table,
|
||||
};
|
||||
|
||||
static int __init btusb_init(void)
|
||||
{
|
||||
BT_INFO("Generic Bluetooth USB driver ver %s", VERSION);
|
||||
|
||||
return usb_register(&btusb_driver);
|
||||
}
|
||||
|
||||
static void __exit btusb_exit(void)
|
||||
{
|
||||
usb_deregister(&btusb_driver);
|
||||
}
|
||||
|
||||
module_init(btusb_init);
|
||||
module_exit(btusb_exit);
|
||||
|
||||
MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
|
||||
MODULE_DESCRIPTION("Generic Bluetooth USB driver ver " VERSION);
|
||||
MODULE_VERSION(VERSION);
|
||||
MODULE_LICENSE("GPL");
|
@ -298,10 +298,7 @@ static irqreturn_t dtl1_interrupt(int irq, void *dev_inst)
|
||||
int boguscount = 0;
|
||||
int iir, lsr;
|
||||
|
||||
if (!info || !info->hdev) {
|
||||
BT_ERR("Call of irq %d for unknown device", irq);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
BUG_ON(!info->hdev);
|
||||
|
||||
iobase = info->p_dev->io.BasePort1;
|
||||
|
||||
|
@ -237,7 +237,8 @@ static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data,
|
||||
if (hciextn && chan == 5) {
|
||||
struct hci_command_hdr *hdr = (struct hci_command_hdr *) data;
|
||||
|
||||
if (hci_opcode_ogf(__le16_to_cpu(hdr->opcode)) == OGF_VENDOR_CMD) {
|
||||
/* Vendor specific commands */
|
||||
if (hci_opcode_ogf(__le16_to_cpu(hdr->opcode)) == 0x3f) {
|
||||
u8 desc = *(data + HCI_COMMAND_HDR_SIZE);
|
||||
if ((desc & 0xf0) == 0xc0) {
|
||||
data += HCI_COMMAND_HDR_SIZE + 1;
|
||||
|
@ -549,7 +549,10 @@ static int __init hci_uart_init(void)
|
||||
#ifdef CONFIG_BT_HCIUART_BCSP
|
||||
bcsp_init();
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_HCIUART_LL
|
||||
ll_init();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -563,6 +566,9 @@ static void __exit hci_uart_exit(void)
|
||||
#ifdef CONFIG_BT_HCIUART_BCSP
|
||||
bcsp_deinit();
|
||||
#endif
|
||||
#ifdef CONFIG_BT_HCIUART_LL
|
||||
ll_deinit();
|
||||
#endif
|
||||
|
||||
/* Release tty registration of line discipline */
|
||||
if ((err = tty_unregister_ldisc(N_HCI)))
|
||||
|
531
drivers/bluetooth/hci_ll.c
Normal file
531
drivers/bluetooth/hci_ll.c
Normal file
@ -0,0 +1,531 @@
|
||||
/*
|
||||
* Texas Instruments' Bluetooth HCILL UART protocol
|
||||
*
|
||||
* HCILL (HCI Low Level) is a Texas Instruments' power management
|
||||
* protocol extension to H4.
|
||||
*
|
||||
* Copyright (C) 2007 Texas Instruments, Inc.
|
||||
*
|
||||
* Written by Ohad Ben-Cohen <ohad@bencohen.org>
|
||||
*
|
||||
* Acknowledgements:
|
||||
* This file is based on hci_h4.c, which was written
|
||||
* by Maxim Krasnyansky and Marcel Holtmann.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/poll.h>
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
|
||||
#include "hci_uart.h"
|
||||
|
||||
/* HCILL commands */
|
||||
#define HCILL_GO_TO_SLEEP_IND 0x30
|
||||
#define HCILL_GO_TO_SLEEP_ACK 0x31
|
||||
#define HCILL_WAKE_UP_IND 0x32
|
||||
#define HCILL_WAKE_UP_ACK 0x33
|
||||
|
||||
/* HCILL receiver States */
|
||||
#define HCILL_W4_PACKET_TYPE 0
|
||||
#define HCILL_W4_EVENT_HDR 1
|
||||
#define HCILL_W4_ACL_HDR 2
|
||||
#define HCILL_W4_SCO_HDR 3
|
||||
#define HCILL_W4_DATA 4
|
||||
|
||||
/* HCILL states */
|
||||
enum hcill_states_e {
|
||||
HCILL_ASLEEP,
|
||||
HCILL_ASLEEP_TO_AWAKE,
|
||||
HCILL_AWAKE,
|
||||
HCILL_AWAKE_TO_ASLEEP
|
||||
};
|
||||
|
||||
struct hcill_cmd {
|
||||
u8 cmd;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct ll_struct {
|
||||
unsigned long rx_state;
|
||||
unsigned long rx_count;
|
||||
struct sk_buff *rx_skb;
|
||||
struct sk_buff_head txq;
|
||||
spinlock_t hcill_lock; /* HCILL state lock */
|
||||
unsigned long hcill_state; /* HCILL power state */
|
||||
struct sk_buff_head tx_wait_q; /* HCILL wait queue */
|
||||
};
|
||||
|
||||
/*
|
||||
* Builds and sends an HCILL command packet.
|
||||
* These are very simple packets with only 1 cmd byte
|
||||
*/
|
||||
static int send_hcill_cmd(u8 cmd, struct hci_uart *hu)
|
||||
{
|
||||
int err = 0;
|
||||
struct sk_buff *skb = NULL;
|
||||
struct ll_struct *ll = hu->priv;
|
||||
struct hcill_cmd *hcill_packet;
|
||||
|
||||
BT_DBG("hu %p cmd 0x%x", hu, cmd);
|
||||
|
||||
/* allocate packet */
|
||||
skb = bt_skb_alloc(1, GFP_ATOMIC);
|
||||
if (!skb) {
|
||||
BT_ERR("cannot allocate memory for HCILL packet");
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* prepare packet */
|
||||
hcill_packet = (struct hcill_cmd *) skb_put(skb, 1);
|
||||
hcill_packet->cmd = cmd;
|
||||
skb->dev = (void *) hu->hdev;
|
||||
|
||||
/* send packet */
|
||||
skb_queue_tail(&ll->txq, skb);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Initialize protocol */
|
||||
static int ll_open(struct hci_uart *hu)
|
||||
{
|
||||
struct ll_struct *ll;
|
||||
|
||||
BT_DBG("hu %p", hu);
|
||||
|
||||
ll = kzalloc(sizeof(*ll), GFP_ATOMIC);
|
||||
if (!ll)
|
||||
return -ENOMEM;
|
||||
|
||||
skb_queue_head_init(&ll->txq);
|
||||
skb_queue_head_init(&ll->tx_wait_q);
|
||||
spin_lock_init(&ll->hcill_lock);
|
||||
|
||||
ll->hcill_state = HCILL_AWAKE;
|
||||
|
||||
hu->priv = ll;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Flush protocol data */
|
||||
static int ll_flush(struct hci_uart *hu)
|
||||
{
|
||||
struct ll_struct *ll = hu->priv;
|
||||
|
||||
BT_DBG("hu %p", hu);
|
||||
|
||||
skb_queue_purge(&ll->tx_wait_q);
|
||||
skb_queue_purge(&ll->txq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Close protocol */
|
||||
static int ll_close(struct hci_uart *hu)
|
||||
{
|
||||
struct ll_struct *ll = hu->priv;
|
||||
|
||||
BT_DBG("hu %p", hu);
|
||||
|
||||
skb_queue_purge(&ll->tx_wait_q);
|
||||
skb_queue_purge(&ll->txq);
|
||||
|
||||
if (ll->rx_skb)
|
||||
kfree_skb(ll->rx_skb);
|
||||
|
||||
hu->priv = NULL;
|
||||
|
||||
kfree(ll);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* internal function, which does common work of the device wake up process:
|
||||
* 1. places all pending packets (waiting in tx_wait_q list) in txq list.
|
||||
* 2. changes internal state to HCILL_AWAKE.
|
||||
* Note: assumes that hcill_lock spinlock is taken,
|
||||
* shouldn't be called otherwise!
|
||||
*/
|
||||
static void __ll_do_awake(struct ll_struct *ll)
|
||||
{
|
||||
struct sk_buff *skb = NULL;
|
||||
|
||||
while ((skb = skb_dequeue(&ll->tx_wait_q)))
|
||||
skb_queue_tail(&ll->txq, skb);
|
||||
|
||||
ll->hcill_state = HCILL_AWAKE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called upon a wake-up-indication from the device
|
||||
*/
|
||||
static void ll_device_want_to_wakeup(struct hci_uart *hu)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct ll_struct *ll = hu->priv;
|
||||
|
||||
BT_DBG("hu %p", hu);
|
||||
|
||||
/* lock hcill state */
|
||||
spin_lock_irqsave(&ll->hcill_lock, flags);
|
||||
|
||||
switch (ll->hcill_state) {
|
||||
case HCILL_ASLEEP:
|
||||
/* acknowledge device wake up */
|
||||
if (send_hcill_cmd(HCILL_WAKE_UP_ACK, hu) < 0) {
|
||||
BT_ERR("cannot acknowledge device wake up");
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
case HCILL_ASLEEP_TO_AWAKE:
|
||||
/*
|
||||
* this state means that a wake-up-indication
|
||||
* is already on its way to the device,
|
||||
* and will serve as the required wake-up-ack
|
||||
*/
|
||||
BT_DBG("dual wake-up-indication");
|
||||
break;
|
||||
default:
|
||||
/* any other state are illegal */
|
||||
BT_ERR("received HCILL_WAKE_UP_IND in state %ld", ll->hcill_state);
|
||||
break;
|
||||
}
|
||||
|
||||
/* send pending packets and change state to HCILL_AWAKE */
|
||||
__ll_do_awake(ll);
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&ll->hcill_lock, flags);
|
||||
|
||||
/* actually send the packets */
|
||||
hci_uart_tx_wakeup(hu);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called upon a sleep-indication from the device
|
||||
*/
|
||||
static void ll_device_want_to_sleep(struct hci_uart *hu)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct ll_struct *ll = hu->priv;
|
||||
|
||||
BT_DBG("hu %p", hu);
|
||||
|
||||
/* lock hcill state */
|
||||
spin_lock_irqsave(&ll->hcill_lock, flags);
|
||||
|
||||
/* sanity check */
|
||||
if (ll->hcill_state != HCILL_AWAKE)
|
||||
BT_ERR("ERR: HCILL_GO_TO_SLEEP_IND in state %ld", ll->hcill_state);
|
||||
|
||||
/* acknowledge device sleep */
|
||||
if (send_hcill_cmd(HCILL_GO_TO_SLEEP_ACK, hu) < 0) {
|
||||
BT_ERR("cannot acknowledge device sleep");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* update state */
|
||||
ll->hcill_state = HCILL_ASLEEP;
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&ll->hcill_lock, flags);
|
||||
|
||||
/* actually send the sleep ack packet */
|
||||
hci_uart_tx_wakeup(hu);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called upon wake-up-acknowledgement from the device
|
||||
*/
|
||||
static void ll_device_woke_up(struct hci_uart *hu)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct ll_struct *ll = hu->priv;
|
||||
|
||||
BT_DBG("hu %p", hu);
|
||||
|
||||
/* lock hcill state */
|
||||
spin_lock_irqsave(&ll->hcill_lock, flags);
|
||||
|
||||
/* sanity check */
|
||||
if (ll->hcill_state != HCILL_ASLEEP_TO_AWAKE)
|
||||
BT_ERR("received HCILL_WAKE_UP_ACK in state %ld", ll->hcill_state);
|
||||
|
||||
/* send pending packets and change state to HCILL_AWAKE */
|
||||
__ll_do_awake(ll);
|
||||
|
||||
spin_unlock_irqrestore(&ll->hcill_lock, flags);
|
||||
|
||||
/* actually send the packets */
|
||||
hci_uart_tx_wakeup(hu);
|
||||
}
|
||||
|
||||
/* Enqueue frame for transmittion (padding, crc, etc) */
|
||||
/* may be called from two simultaneous tasklets */
|
||||
static int ll_enqueue(struct hci_uart *hu, struct sk_buff *skb)
|
||||
{
|
||||
unsigned long flags = 0;
|
||||
struct ll_struct *ll = hu->priv;
|
||||
|
||||
BT_DBG("hu %p skb %p", hu, skb);
|
||||
|
||||
/* Prepend skb with frame type */
|
||||
memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
|
||||
|
||||
/* lock hcill state */
|
||||
spin_lock_irqsave(&ll->hcill_lock, flags);
|
||||
|
||||
/* act according to current state */
|
||||
switch (ll->hcill_state) {
|
||||
case HCILL_AWAKE:
|
||||
BT_DBG("device awake, sending normally");
|
||||
skb_queue_tail(&ll->txq, skb);
|
||||
break;
|
||||
case HCILL_ASLEEP:
|
||||
BT_DBG("device asleep, waking up and queueing packet");
|
||||
/* save packet for later */
|
||||
skb_queue_tail(&ll->tx_wait_q, skb);
|
||||
/* awake device */
|
||||
if (send_hcill_cmd(HCILL_WAKE_UP_IND, hu) < 0) {
|
||||
BT_ERR("cannot wake up device");
|
||||
break;
|
||||
}
|
||||
ll->hcill_state = HCILL_ASLEEP_TO_AWAKE;
|
||||
break;
|
||||
case HCILL_ASLEEP_TO_AWAKE:
|
||||
BT_DBG("device waking up, queueing packet");
|
||||
/* transient state; just keep packet for later */
|
||||
skb_queue_tail(&ll->tx_wait_q, skb);
|
||||
break;
|
||||
default:
|
||||
BT_ERR("illegal hcill state: %ld (losing packet)", ll->hcill_state);
|
||||
kfree_skb(skb);
|
||||
break;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&ll->hcill_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ll_check_data_len(struct ll_struct *ll, int len)
|
||||
{
|
||||
register int room = skb_tailroom(ll->rx_skb);
|
||||
|
||||
BT_DBG("len %d room %d", len, room);
|
||||
|
||||
if (!len) {
|
||||
hci_recv_frame(ll->rx_skb);
|
||||
} else if (len > room) {
|
||||
BT_ERR("Data length is too large");
|
||||
kfree_skb(ll->rx_skb);
|
||||
} else {
|
||||
ll->rx_state = HCILL_W4_DATA;
|
||||
ll->rx_count = len;
|
||||
return len;
|
||||
}
|
||||
|
||||
ll->rx_state = HCILL_W4_PACKET_TYPE;
|
||||
ll->rx_skb = NULL;
|
||||
ll->rx_count = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Recv data */
|
||||
static int ll_recv(struct hci_uart *hu, void *data, int count)
|
||||
{
|
||||
struct ll_struct *ll = 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, 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(ll->rx_skb);
|
||||
|
||||
ll->rx_state = HCILL_W4_PACKET_TYPE;
|
||||
ll->rx_skb = NULL;
|
||||
continue;
|
||||
|
||||
case HCILL_W4_EVENT_HDR:
|
||||
eh = (struct hci_event_hdr *) ll->rx_skb->data;
|
||||
|
||||
BT_DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen);
|
||||
|
||||
ll_check_data_len(ll, eh->plen);
|
||||
continue;
|
||||
|
||||
case HCILL_W4_ACL_HDR:
|
||||
ah = (struct hci_acl_hdr *) ll->rx_skb->data;
|
||||
dlen = __le16_to_cpu(ah->dlen);
|
||||
|
||||
BT_DBG("ACL header: dlen %d", dlen);
|
||||
|
||||
ll_check_data_len(ll, dlen);
|
||||
continue;
|
||||
|
||||
case HCILL_W4_SCO_HDR:
|
||||
sh = (struct hci_sco_hdr *) ll->rx_skb->data;
|
||||
|
||||
BT_DBG("SCO header: dlen %d", sh->dlen);
|
||||
|
||||
ll_check_data_len(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 0;
|
||||
}
|
||||
|
||||
ll->rx_skb->dev = (void *) hu->hdev;
|
||||
bt_cb(ll->rx_skb)->pkt_type = type;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct sk_buff *ll_dequeue(struct hci_uart *hu)
|
||||
{
|
||||
struct ll_struct *ll = hu->priv;
|
||||
return skb_dequeue(&ll->txq);
|
||||
}
|
||||
|
||||
static struct hci_uart_proto llp = {
|
||||
.id = HCI_UART_LL,
|
||||
.open = ll_open,
|
||||
.close = ll_close,
|
||||
.recv = ll_recv,
|
||||
.enqueue = ll_enqueue,
|
||||
.dequeue = ll_dequeue,
|
||||
.flush = ll_flush,
|
||||
};
|
||||
|
||||
int ll_init(void)
|
||||
{
|
||||
int err = hci_uart_register_proto(&llp);
|
||||
|
||||
if (!err)
|
||||
BT_INFO("HCILL protocol initialized");
|
||||
else
|
||||
BT_ERR("HCILL protocol registration failed");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int ll_deinit(void)
|
||||
{
|
||||
return hci_uart_unregister_proto(&llp);
|
||||
}
|
@ -33,12 +33,13 @@
|
||||
#define HCIUARTGETDEVICE _IOR('U', 202, int)
|
||||
|
||||
/* UART protocols */
|
||||
#define HCI_UART_MAX_PROTO 4
|
||||
#define HCI_UART_MAX_PROTO 5
|
||||
|
||||
#define HCI_UART_H4 0
|
||||
#define HCI_UART_BCSP 1
|
||||
#define HCI_UART_3WIRE 2
|
||||
#define HCI_UART_H4DS 3
|
||||
#define HCI_UART_LL 4
|
||||
|
||||
struct hci_uart;
|
||||
|
||||
@ -85,3 +86,8 @@ int h4_deinit(void);
|
||||
int bcsp_init(void);
|
||||
int bcsp_deinit(void);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_HCIUART_LL
|
||||
int ll_init(void);
|
||||
int ll_deinit(void);
|
||||
#endif
|
||||
|
@ -471,7 +471,7 @@ static int cpmac_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
}
|
||||
|
||||
len = max(skb->len, ETH_ZLEN);
|
||||
queue = skb->queue_mapping;
|
||||
queue = skb_get_queue_mapping(skb);
|
||||
#ifdef CONFIG_NETDEVICES_MULTIQUEUE
|
||||
netif_stop_subqueue(dev, queue);
|
||||
#else
|
||||
|
@ -3103,31 +3103,12 @@ static int niu_alloc_tx_ring_info(struct niu *np,
|
||||
|
||||
static void niu_size_rbr(struct niu *np, struct rx_ring_info *rp)
|
||||
{
|
||||
u16 bs;
|
||||
u16 bss;
|
||||
|
||||
switch (PAGE_SIZE) {
|
||||
case 4 * 1024:
|
||||
case 8 * 1024:
|
||||
case 16 * 1024:
|
||||
case 32 * 1024:
|
||||
rp->rbr_block_size = PAGE_SIZE;
|
||||
rp->rbr_blocks_per_page = 1;
|
||||
break;
|
||||
bss = min(PAGE_SHIFT, 15);
|
||||
|
||||
default:
|
||||
if (PAGE_SIZE % (32 * 1024) == 0)
|
||||
bs = 32 * 1024;
|
||||
else if (PAGE_SIZE % (16 * 1024) == 0)
|
||||
bs = 16 * 1024;
|
||||
else if (PAGE_SIZE % (8 * 1024) == 0)
|
||||
bs = 8 * 1024;
|
||||
else if (PAGE_SIZE % (4 * 1024) == 0)
|
||||
bs = 4 * 1024;
|
||||
else
|
||||
BUG();
|
||||
rp->rbr_block_size = bs;
|
||||
rp->rbr_blocks_per_page = PAGE_SIZE / bs;
|
||||
}
|
||||
rp->rbr_block_size = 1 << bss;
|
||||
rp->rbr_blocks_per_page = 1 << (PAGE_SHIFT-bss);
|
||||
|
||||
rp->rbr_sizes[0] = 256;
|
||||
rp->rbr_sizes[1] = 1024;
|
||||
@ -7902,12 +7883,7 @@ static int __init niu_init(void)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
BUILD_BUG_ON((PAGE_SIZE < 4 * 1024) ||
|
||||
((PAGE_SIZE > 32 * 1024) &&
|
||||
((PAGE_SIZE % (32 * 1024)) != 0 &&
|
||||
(PAGE_SIZE % (16 * 1024)) != 0 &&
|
||||
(PAGE_SIZE % (8 * 1024)) != 0 &&
|
||||
(PAGE_SIZE % (4 * 1024)) != 0)));
|
||||
BUILD_BUG_ON(PAGE_SIZE < 4 * 1024);
|
||||
|
||||
niu_debug = netif_msg_init(debug, NIU_MSG_DEFAULT);
|
||||
|
||||
|
@ -64,8 +64,8 @@
|
||||
|
||||
#define DRV_MODULE_NAME "tg3"
|
||||
#define PFX DRV_MODULE_NAME ": "
|
||||
#define DRV_MODULE_VERSION "3.84"
|
||||
#define DRV_MODULE_RELDATE "October 12, 2007"
|
||||
#define DRV_MODULE_VERSION "3.85"
|
||||
#define DRV_MODULE_RELDATE "October 18, 2007"
|
||||
|
||||
#define TG3_DEF_MAC_MODE 0
|
||||
#define TG3_DEF_RX_MODE 0
|
||||
@ -200,6 +200,7 @@ static struct pci_device_id tg3_pci_tbl[] = {
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5906M)},
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5784)},
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5764)},
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5723)},
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761)},
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761E)},
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX)},
|
||||
@ -5028,10 +5029,7 @@ static int tg3_poll_fw(struct tg3 *tp)
|
||||
/* Save PCI command register before chip reset */
|
||||
static void tg3_save_pci_state(struct tg3 *tp)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
pci_read_config_dword(tp->pdev, TG3PCI_COMMAND, &val);
|
||||
tp->pci_cmd = val;
|
||||
pci_read_config_word(tp->pdev, PCI_COMMAND, &tp->pci_cmd);
|
||||
}
|
||||
|
||||
/* Restore PCI state after chip reset */
|
||||
@ -5054,7 +5052,7 @@ static void tg3_restore_pci_state(struct tg3 *tp)
|
||||
PCISTATE_ALLOW_APE_SHMEM_WR;
|
||||
pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, val);
|
||||
|
||||
pci_write_config_dword(tp->pdev, TG3PCI_COMMAND, tp->pci_cmd);
|
||||
pci_write_config_word(tp->pdev, PCI_COMMAND, tp->pci_cmd);
|
||||
|
||||
if (!(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)) {
|
||||
pci_write_config_byte(tp->pdev, PCI_CACHE_LINE_SIZE,
|
||||
@ -10820,9 +10818,24 @@ static void __devinit tg3_read_partno(struct tg3 *tp)
|
||||
strcpy(tp->board_part_number, "none");
|
||||
}
|
||||
|
||||
static int __devinit tg3_fw_img_is_valid(struct tg3 *tp, u32 offset)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
if (tg3_nvram_read_swab(tp, offset, &val) ||
|
||||
(val & 0xfc000000) != 0x0c000000 ||
|
||||
tg3_nvram_read_swab(tp, offset + 4, &val) ||
|
||||
val != 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void __devinit tg3_read_fw_ver(struct tg3 *tp)
|
||||
{
|
||||
u32 val, offset, start;
|
||||
u32 ver_offset;
|
||||
int i, bcnt;
|
||||
|
||||
if (tg3_nvram_read_swab(tp, 0, &val))
|
||||
return;
|
||||
@ -10835,29 +10848,71 @@ static void __devinit tg3_read_fw_ver(struct tg3 *tp)
|
||||
return;
|
||||
|
||||
offset = tg3_nvram_logical_addr(tp, offset);
|
||||
if (tg3_nvram_read_swab(tp, offset, &val))
|
||||
|
||||
if (!tg3_fw_img_is_valid(tp, offset) ||
|
||||
tg3_nvram_read_swab(tp, offset + 8, &ver_offset))
|
||||
return;
|
||||
|
||||
if ((val & 0xfc000000) == 0x0c000000) {
|
||||
u32 ver_offset, addr;
|
||||
int i;
|
||||
|
||||
if (tg3_nvram_read_swab(tp, offset + 4, &val) ||
|
||||
tg3_nvram_read_swab(tp, offset + 8, &ver_offset))
|
||||
offset = offset + ver_offset - start;
|
||||
for (i = 0; i < 16; i += 4) {
|
||||
if (tg3_nvram_read(tp, offset + i, &val))
|
||||
return;
|
||||
|
||||
if (val != 0)
|
||||
return;
|
||||
|
||||
addr = offset + ver_offset - start;
|
||||
for (i = 0; i < 16; i += 4) {
|
||||
if (tg3_nvram_read(tp, addr + i, &val))
|
||||
return;
|
||||
|
||||
val = cpu_to_le32(val);
|
||||
memcpy(tp->fw_ver + i, &val, 4);
|
||||
}
|
||||
val = le32_to_cpu(val);
|
||||
memcpy(tp->fw_ver + i, &val, 4);
|
||||
}
|
||||
|
||||
if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF) ||
|
||||
(tp->tg3_flags & TG3_FLG3_ENABLE_APE))
|
||||
return;
|
||||
|
||||
for (offset = TG3_NVM_DIR_START;
|
||||
offset < TG3_NVM_DIR_END;
|
||||
offset += TG3_NVM_DIRENT_SIZE) {
|
||||
if (tg3_nvram_read_swab(tp, offset, &val))
|
||||
return;
|
||||
|
||||
if ((val >> TG3_NVM_DIRTYPE_SHIFT) == TG3_NVM_DIRTYPE_ASFINI)
|
||||
break;
|
||||
}
|
||||
|
||||
if (offset == TG3_NVM_DIR_END)
|
||||
return;
|
||||
|
||||
if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
|
||||
start = 0x08000000;
|
||||
else if (tg3_nvram_read_swab(tp, offset - 4, &start))
|
||||
return;
|
||||
|
||||
if (tg3_nvram_read_swab(tp, offset + 4, &offset) ||
|
||||
!tg3_fw_img_is_valid(tp, offset) ||
|
||||
tg3_nvram_read_swab(tp, offset + 8, &val))
|
||||
return;
|
||||
|
||||
offset += val - start;
|
||||
|
||||
bcnt = strlen(tp->fw_ver);
|
||||
|
||||
tp->fw_ver[bcnt++] = ',';
|
||||
tp->fw_ver[bcnt++] = ' ';
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (tg3_nvram_read(tp, offset, &val))
|
||||
return;
|
||||
|
||||
val = le32_to_cpu(val);
|
||||
offset += sizeof(val);
|
||||
|
||||
if (bcnt > TG3_VER_SIZE - sizeof(val)) {
|
||||
memcpy(&tp->fw_ver[bcnt], &val, TG3_VER_SIZE - bcnt);
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(&tp->fw_ver[bcnt], &val, sizeof(val));
|
||||
bcnt += sizeof(val);
|
||||
}
|
||||
|
||||
tp->fw_ver[TG3_VER_SIZE - 1] = 0;
|
||||
}
|
||||
|
||||
static struct pci_dev * __devinit tg3_find_peer(struct tg3 *);
|
||||
|
@ -1540,6 +1540,12 @@
|
||||
#define TG3_EEPROM_MAGIC_HW 0xabcd
|
||||
#define TG3_EEPROM_MAGIC_HW_MSK 0xffff
|
||||
|
||||
#define TG3_NVM_DIR_START 0x18
|
||||
#define TG3_NVM_DIR_END 0x78
|
||||
#define TG3_NVM_DIRENT_SIZE 0xc
|
||||
#define TG3_NVM_DIRTYPE_SHIFT 24
|
||||
#define TG3_NVM_DIRTYPE_ASFINI 1
|
||||
|
||||
/* 32K Window into NIC internal memory */
|
||||
#define NIC_SRAM_WIN_BASE 0x00008000
|
||||
|
||||
@ -2415,10 +2421,11 @@ struct tg3 {
|
||||
#define PHY_REV_BCM5411_X0 0x1 /* Found on Netgear GA302T */
|
||||
|
||||
u32 led_ctrl;
|
||||
u32 pci_cmd;
|
||||
u16 pci_cmd;
|
||||
|
||||
char board_part_number[24];
|
||||
char fw_ver[16];
|
||||
#define TG3_VER_SIZE 32
|
||||
char fw_ver[TG3_VER_SIZE];
|
||||
u32 nic_sram_data_cfg;
|
||||
u32 pci_clock_ctrl;
|
||||
struct pci_dev *pdev_peer;
|
||||
|
@ -313,6 +313,10 @@ static const struct proto_ops name##_ops = { \
|
||||
#define MODULE_ALIAS_NET_PF_PROTO(pf, proto) \
|
||||
MODULE_ALIAS("net-pf-" __stringify(pf) "-proto-" __stringify(proto))
|
||||
|
||||
#define MODULE_ALIAS_NET_PF_PROTO_TYPE(pf, proto, type) \
|
||||
MODULE_ALIAS("net-pf-" __stringify(pf) "-proto-" __stringify(proto) \
|
||||
"-type-" __stringify(type))
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
#include <linux/sysctl.h>
|
||||
extern ctl_table net_table[];
|
||||
|
@ -996,7 +996,7 @@ static inline void netif_stop_subqueue(struct net_device *dev, u16 queue_index)
|
||||
*
|
||||
* Check individual transmit queue of a device with multiple transmit queues.
|
||||
*/
|
||||
static inline int netif_subqueue_stopped(const struct net_device *dev,
|
||||
static inline int __netif_subqueue_stopped(const struct net_device *dev,
|
||||
u16 queue_index)
|
||||
{
|
||||
#ifdef CONFIG_NETDEVICES_MULTIQUEUE
|
||||
@ -1007,6 +1007,11 @@ static inline int netif_subqueue_stopped(const struct net_device *dev,
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int netif_subqueue_stopped(const struct net_device *dev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
return __netif_subqueue_stopped(dev, skb_get_queue_mapping(skb));
|
||||
}
|
||||
|
||||
/**
|
||||
* netif_wake_subqueue - allow sending packets on subqueue
|
||||
|
@ -1943,6 +1943,7 @@
|
||||
#define PCI_DEVICE_ID_TIGON3_5720 0x1658
|
||||
#define PCI_DEVICE_ID_TIGON3_5721 0x1659
|
||||
#define PCI_DEVICE_ID_TIGON3_5722 0x165a
|
||||
#define PCI_DEVICE_ID_TIGON3_5723 0x165b
|
||||
#define PCI_DEVICE_ID_TIGON3_5705M 0x165d
|
||||
#define PCI_DEVICE_ID_TIGON3_5705M_2 0x165e
|
||||
#define PCI_DEVICE_ID_TIGON3_5714 0x1668
|
||||
|
@ -41,8 +41,7 @@
|
||||
#define SKB_DATA_ALIGN(X) (((X) + (SMP_CACHE_BYTES - 1)) & \
|
||||
~(SMP_CACHE_BYTES - 1))
|
||||
#define SKB_WITH_OVERHEAD(X) \
|
||||
(((X) - sizeof(struct skb_shared_info)) & \
|
||||
~(SMP_CACHE_BYTES - 1))
|
||||
((X) - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
|
||||
#define SKB_MAX_ORDER(X, ORDER) \
|
||||
SKB_WITH_OVERHEAD((PAGE_SIZE << (ORDER)) - (X))
|
||||
#define SKB_MAX_HEAD(X) (SKB_MAX_ORDER((X), 0))
|
||||
@ -301,8 +300,9 @@ struct sk_buff {
|
||||
#endif
|
||||
|
||||
int iif;
|
||||
#ifdef CONFIG_NETDEVICES_MULTIQUEUE
|
||||
__u16 queue_mapping;
|
||||
|
||||
#endif
|
||||
#ifdef CONFIG_NET_SCHED
|
||||
__u16 tc_index; /* traffic control index */
|
||||
#ifdef CONFIG_NET_CLS_ACT
|
||||
@ -1770,6 +1770,15 @@ static inline void skb_set_queue_mapping(struct sk_buff *skb, u16 queue_mapping)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline u16 skb_get_queue_mapping(struct sk_buff *skb)
|
||||
{
|
||||
#ifdef CONFIG_NETDEVICES_MULTIQUEUE
|
||||
return skb->queue_mapping;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void skb_copy_queue_mapping(struct sk_buff *to, const struct sk_buff *from)
|
||||
{
|
||||
#ifdef CONFIG_NETDEVICES_MULTIQUEUE
|
||||
|
@ -291,6 +291,7 @@ struct ucred {
|
||||
#define SOL_TIPC 271
|
||||
#define SOL_RXRPC 272
|
||||
#define SOL_PPPOL2TP 273
|
||||
#define SOL_BLUETOOTH 274
|
||||
|
||||
/* IPX options */
|
||||
#define IPX_TYPE 1
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -71,7 +71,10 @@ struct hci_dev {
|
||||
__u16 id;
|
||||
__u8 type;
|
||||
bdaddr_t bdaddr;
|
||||
__u8 dev_name[248];
|
||||
__u8 dev_class[3];
|
||||
__u8 features[8];
|
||||
__u8 commands[64];
|
||||
__u8 hci_ver;
|
||||
__u16 hci_rev;
|
||||
__u16 manufacturer;
|
||||
@ -310,10 +313,12 @@ static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
|
||||
void hci_acl_connect(struct hci_conn *conn);
|
||||
void hci_acl_disconn(struct hci_conn *conn, __u8 reason);
|
||||
void hci_add_sco(struct hci_conn *conn, __u16 handle);
|
||||
void hci_setup_sync(struct hci_conn *conn, __u16 handle);
|
||||
|
||||
struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst);
|
||||
int hci_conn_del(struct hci_conn *conn);
|
||||
void hci_conn_hash_flush(struct hci_dev *hdev);
|
||||
int hci_conn_del(struct hci_conn *conn);
|
||||
void hci_conn_hash_flush(struct hci_dev *hdev);
|
||||
void hci_conn_check_pending(struct hci_dev *hdev);
|
||||
|
||||
struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *src);
|
||||
int hci_conn_auth(struct hci_conn *conn);
|
||||
@ -617,11 +622,11 @@ int hci_unregister_cb(struct hci_cb *hcb);
|
||||
int hci_register_notifier(struct notifier_block *nb);
|
||||
int hci_unregister_notifier(struct notifier_block *nb);
|
||||
|
||||
int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *param);
|
||||
int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param);
|
||||
int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
|
||||
int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
|
||||
|
||||
void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf);
|
||||
void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode);
|
||||
|
||||
void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data);
|
||||
|
||||
|
@ -29,7 +29,8 @@
|
||||
#define L2CAP_DEFAULT_MTU 672
|
||||
#define L2CAP_DEFAULT_FLUSH_TO 0xFFFF
|
||||
|
||||
#define L2CAP_CONN_TIMEOUT (HZ * 40)
|
||||
#define L2CAP_CONN_TIMEOUT (40000) /* 40 seconds */
|
||||
#define L2CAP_INFO_TIMEOUT (4000) /* 4 seconds */
|
||||
|
||||
/* L2CAP socket address */
|
||||
struct sockaddr_l2 {
|
||||
@ -148,6 +149,19 @@ struct l2cap_conf_opt {
|
||||
|
||||
#define L2CAP_CONF_MAX_SIZE 22
|
||||
|
||||
struct l2cap_conf_rfc {
|
||||
__u8 mode;
|
||||
__u8 txwin_size;
|
||||
__u8 max_transmit;
|
||||
__le16 retrans_timeout;
|
||||
__le16 monitor_timeout;
|
||||
__le16 max_pdu_size;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define L2CAP_MODE_BASIC 0x00
|
||||
#define L2CAP_MODE_RETRANS 0x01
|
||||
#define L2CAP_MODE_FLOWCTL 0x02
|
||||
|
||||
struct l2cap_disconn_req {
|
||||
__le16 dcid;
|
||||
__le16 scid;
|
||||
@ -160,7 +174,6 @@ struct l2cap_disconn_rsp {
|
||||
|
||||
struct l2cap_info_req {
|
||||
__le16 type;
|
||||
__u8 data[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct l2cap_info_rsp {
|
||||
@ -192,6 +205,13 @@ struct l2cap_conn {
|
||||
|
||||
unsigned int mtu;
|
||||
|
||||
__u32 feat_mask;
|
||||
|
||||
__u8 info_state;
|
||||
__u8 info_ident;
|
||||
|
||||
struct timer_list info_timer;
|
||||
|
||||
spinlock_t lock;
|
||||
|
||||
struct sk_buff *rx_skb;
|
||||
@ -202,6 +222,9 @@ struct l2cap_conn {
|
||||
struct l2cap_chan_list chan_list;
|
||||
};
|
||||
|
||||
#define L2CAP_INFO_CL_MTU_REQ_SENT 0x01
|
||||
#define L2CAP_INFO_FEAT_MASK_REQ_SENT 0x02
|
||||
|
||||
/* ----- L2CAP channel and socket info ----- */
|
||||
#define l2cap_pi(sk) ((struct l2cap_pinfo *) sk)
|
||||
|
||||
@ -221,7 +244,6 @@ struct l2cap_pinfo {
|
||||
__u8 conf_len;
|
||||
__u8 conf_state;
|
||||
__u8 conf_retry;
|
||||
__u16 conf_mtu;
|
||||
|
||||
__u8 ident;
|
||||
|
||||
@ -232,10 +254,11 @@ struct l2cap_pinfo {
|
||||
struct sock *prev_c;
|
||||
};
|
||||
|
||||
#define L2CAP_CONF_REQ_SENT 0x01
|
||||
#define L2CAP_CONF_INPUT_DONE 0x02
|
||||
#define L2CAP_CONF_OUTPUT_DONE 0x04
|
||||
#define L2CAP_CONF_MAX_RETRIES 2
|
||||
#define L2CAP_CONF_REQ_SENT 0x01
|
||||
#define L2CAP_CONF_INPUT_DONE 0x02
|
||||
#define L2CAP_CONF_OUTPUT_DONE 0x04
|
||||
|
||||
#define L2CAP_CONF_MAX_RETRIES 2
|
||||
|
||||
void l2cap_load(void);
|
||||
|
||||
|
@ -78,11 +78,11 @@ void hci_acl_connect(struct hci_conn *conn)
|
||||
|
||||
cp.pkt_type = cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK);
|
||||
if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER))
|
||||
cp.role_switch = 0x01;
|
||||
cp.role_switch = 0x01;
|
||||
else
|
||||
cp.role_switch = 0x00;
|
||||
cp.role_switch = 0x00;
|
||||
|
||||
hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CREATE_CONN, sizeof(cp), &cp);
|
||||
hci_send_cmd(hdev, HCI_OP_CREATE_CONN, sizeof(cp), &cp);
|
||||
}
|
||||
|
||||
static void hci_acl_connect_cancel(struct hci_conn *conn)
|
||||
@ -95,8 +95,7 @@ static void hci_acl_connect_cancel(struct hci_conn *conn)
|
||||
return;
|
||||
|
||||
bacpy(&cp.bdaddr, &conn->dst);
|
||||
hci_send_cmd(conn->hdev, OGF_LINK_CTL,
|
||||
OCF_CREATE_CONN_CANCEL, sizeof(cp), &cp);
|
||||
hci_send_cmd(conn->hdev, HCI_OP_CREATE_CONN_CANCEL, sizeof(cp), &cp);
|
||||
}
|
||||
|
||||
void hci_acl_disconn(struct hci_conn *conn, __u8 reason)
|
||||
@ -109,8 +108,7 @@ void hci_acl_disconn(struct hci_conn *conn, __u8 reason)
|
||||
|
||||
cp.handle = cpu_to_le16(conn->handle);
|
||||
cp.reason = reason;
|
||||
hci_send_cmd(conn->hdev, OGF_LINK_CTL,
|
||||
OCF_DISCONNECT, sizeof(cp), &cp);
|
||||
hci_send_cmd(conn->hdev, HCI_OP_DISCONNECT, sizeof(cp), &cp);
|
||||
}
|
||||
|
||||
void hci_add_sco(struct hci_conn *conn, __u16 handle)
|
||||
@ -126,7 +124,29 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle)
|
||||
cp.handle = cpu_to_le16(handle);
|
||||
cp.pkt_type = cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);
|
||||
|
||||
hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ADD_SCO, sizeof(cp), &cp);
|
||||
hci_send_cmd(hdev, HCI_OP_ADD_SCO, sizeof(cp), &cp);
|
||||
}
|
||||
|
||||
void hci_setup_sync(struct hci_conn *conn, __u16 handle)
|
||||
{
|
||||
struct hci_dev *hdev = conn->hdev;
|
||||
struct hci_cp_setup_sync_conn cp;
|
||||
|
||||
BT_DBG("%p", conn);
|
||||
|
||||
conn->state = BT_CONNECT;
|
||||
conn->out = 1;
|
||||
|
||||
cp.handle = cpu_to_le16(handle);
|
||||
cp.pkt_type = cpu_to_le16(hdev->esco_type);
|
||||
|
||||
cp.tx_bandwidth = cpu_to_le32(0x00001f40);
|
||||
cp.rx_bandwidth = cpu_to_le32(0x00001f40);
|
||||
cp.max_latency = cpu_to_le16(0xffff);
|
||||
cp.voice_setting = cpu_to_le16(hdev->voice_setting);
|
||||
cp.retrans_effort = 0xff;
|
||||
|
||||
hci_send_cmd(hdev, HCI_OP_SETUP_SYNC_CONN, sizeof(cp), &cp);
|
||||
}
|
||||
|
||||
static void hci_conn_timeout(unsigned long arg)
|
||||
@ -143,7 +163,10 @@ static void hci_conn_timeout(unsigned long arg)
|
||||
|
||||
switch (conn->state) {
|
||||
case BT_CONNECT:
|
||||
hci_acl_connect_cancel(conn);
|
||||
if (conn->type == ACL_LINK)
|
||||
hci_acl_connect_cancel(conn);
|
||||
else
|
||||
hci_acl_disconn(conn, 0x13);
|
||||
break;
|
||||
case BT_CONNECTED:
|
||||
hci_acl_disconn(conn, 0x13);
|
||||
@ -330,8 +353,12 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst)
|
||||
hci_conn_hold(sco);
|
||||
|
||||
if (acl->state == BT_CONNECTED &&
|
||||
(sco->state == BT_OPEN || sco->state == BT_CLOSED))
|
||||
hci_add_sco(sco, acl->handle);
|
||||
(sco->state == BT_OPEN || sco->state == BT_CLOSED)) {
|
||||
if (lmp_esco_capable(hdev))
|
||||
hci_setup_sync(sco, acl->handle);
|
||||
else
|
||||
hci_add_sco(sco, acl->handle);
|
||||
}
|
||||
|
||||
return sco;
|
||||
}
|
||||
@ -348,7 +375,7 @@ int hci_conn_auth(struct hci_conn *conn)
|
||||
if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
|
||||
struct hci_cp_auth_requested cp;
|
||||
cp.handle = cpu_to_le16(conn->handle);
|
||||
hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_AUTH_REQUESTED, sizeof(cp), &cp);
|
||||
hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -369,7 +396,7 @@ int hci_conn_encrypt(struct hci_conn *conn)
|
||||
struct hci_cp_set_conn_encrypt cp;
|
||||
cp.handle = cpu_to_le16(conn->handle);
|
||||
cp.encrypt = 1;
|
||||
hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_SET_CONN_ENCRYPT, sizeof(cp), &cp);
|
||||
hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp), &cp);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -383,7 +410,7 @@ int hci_conn_change_link_key(struct hci_conn *conn)
|
||||
if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
|
||||
struct hci_cp_change_conn_link_key cp;
|
||||
cp.handle = cpu_to_le16(conn->handle);
|
||||
hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_CHANGE_CONN_LINK_KEY, sizeof(cp), &cp);
|
||||
hci_send_cmd(conn->hdev, HCI_OP_CHANGE_CONN_LINK_KEY, sizeof(cp), &cp);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -401,7 +428,7 @@ int hci_conn_switch_role(struct hci_conn *conn, uint8_t role)
|
||||
struct hci_cp_switch_role cp;
|
||||
bacpy(&cp.bdaddr, &conn->dst);
|
||||
cp.role = role;
|
||||
hci_send_cmd(conn->hdev, OGF_LINK_POLICY, OCF_SWITCH_ROLE, sizeof(cp), &cp);
|
||||
hci_send_cmd(conn->hdev, HCI_OP_SWITCH_ROLE, sizeof(cp), &cp);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -423,8 +450,7 @@ void hci_conn_enter_active_mode(struct hci_conn *conn)
|
||||
if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
|
||||
struct hci_cp_exit_sniff_mode cp;
|
||||
cp.handle = cpu_to_le16(conn->handle);
|
||||
hci_send_cmd(hdev, OGF_LINK_POLICY,
|
||||
OCF_EXIT_SNIFF_MODE, sizeof(cp), &cp);
|
||||
hci_send_cmd(hdev, HCI_OP_EXIT_SNIFF_MODE, sizeof(cp), &cp);
|
||||
}
|
||||
|
||||
timer:
|
||||
@ -455,8 +481,7 @@ void hci_conn_enter_sniff_mode(struct hci_conn *conn)
|
||||
cp.max_latency = cpu_to_le16(0);
|
||||
cp.min_remote_timeout = cpu_to_le16(0);
|
||||
cp.min_local_timeout = cpu_to_le16(0);
|
||||
hci_send_cmd(hdev, OGF_LINK_POLICY,
|
||||
OCF_SNIFF_SUBRATE, sizeof(cp), &cp);
|
||||
hci_send_cmd(hdev, HCI_OP_SNIFF_SUBRATE, sizeof(cp), &cp);
|
||||
}
|
||||
|
||||
if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
|
||||
@ -466,8 +491,7 @@ void hci_conn_enter_sniff_mode(struct hci_conn *conn)
|
||||
cp.min_interval = cpu_to_le16(hdev->sniff_min_interval);
|
||||
cp.attempt = cpu_to_le16(4);
|
||||
cp.timeout = cpu_to_le16(1);
|
||||
hci_send_cmd(hdev, OGF_LINK_POLICY,
|
||||
OCF_SNIFF_MODE, sizeof(cp), &cp);
|
||||
hci_send_cmd(hdev, HCI_OP_SNIFF_MODE, sizeof(cp), &cp);
|
||||
}
|
||||
}
|
||||
|
||||
@ -493,6 +517,22 @@ void hci_conn_hash_flush(struct hci_dev *hdev)
|
||||
}
|
||||
}
|
||||
|
||||
/* Check pending connect attempts */
|
||||
void hci_conn_check_pending(struct hci_dev *hdev)
|
||||
{
|
||||
struct hci_conn *conn;
|
||||
|
||||
BT_DBG("hdev %s", hdev->name);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
conn = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2);
|
||||
if (conn)
|
||||
hci_acl_connect(conn);
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
int hci_get_conn_list(void __user *arg)
|
||||
{
|
||||
struct hci_conn_list_req req, *cl;
|
||||
|
@ -176,7 +176,7 @@ static void hci_reset_req(struct hci_dev *hdev, unsigned long opt)
|
||||
BT_DBG("%s %ld", hdev->name, opt);
|
||||
|
||||
/* Reset device */
|
||||
hci_send_cmd(hdev, OGF_HOST_CTL, OCF_RESET, 0, NULL);
|
||||
hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
|
||||
}
|
||||
|
||||
static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
|
||||
@ -202,16 +202,16 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
|
||||
|
||||
/* Reset */
|
||||
if (test_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks))
|
||||
hci_send_cmd(hdev, OGF_HOST_CTL, OCF_RESET, 0, NULL);
|
||||
hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
|
||||
|
||||
/* Read Local Supported Features */
|
||||
hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_LOCAL_FEATURES, 0, NULL);
|
||||
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_FEATURES, 0, NULL);
|
||||
|
||||
/* Read Local Version */
|
||||
hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_LOCAL_VERSION, 0, NULL);
|
||||
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL);
|
||||
|
||||
/* Read Buffer Size (ACL mtu, max pkt, etc.) */
|
||||
hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_BUFFER_SIZE, 0, NULL);
|
||||
hci_send_cmd(hdev, HCI_OP_READ_BUFFER_SIZE, 0, NULL);
|
||||
|
||||
#if 0
|
||||
/* Host buffer size */
|
||||
@ -221,29 +221,35 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
|
||||
cp.sco_mtu = HCI_MAX_SCO_SIZE;
|
||||
cp.acl_max_pkt = cpu_to_le16(0xffff);
|
||||
cp.sco_max_pkt = cpu_to_le16(0xffff);
|
||||
hci_send_cmd(hdev, OGF_HOST_CTL, OCF_HOST_BUFFER_SIZE, sizeof(cp), &cp);
|
||||
hci_send_cmd(hdev, HCI_OP_HOST_BUFFER_SIZE, sizeof(cp), &cp);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Read BD Address */
|
||||
hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_BD_ADDR, 0, NULL);
|
||||
hci_send_cmd(hdev, HCI_OP_READ_BD_ADDR, 0, NULL);
|
||||
|
||||
/* Read Class of Device */
|
||||
hci_send_cmd(hdev, HCI_OP_READ_CLASS_OF_DEV, 0, NULL);
|
||||
|
||||
/* Read Local Name */
|
||||
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_NAME, 0, NULL);
|
||||
|
||||
/* Read Voice Setting */
|
||||
hci_send_cmd(hdev, OGF_HOST_CTL, OCF_READ_VOICE_SETTING, 0, NULL);
|
||||
hci_send_cmd(hdev, HCI_OP_READ_VOICE_SETTING, 0, NULL);
|
||||
|
||||
/* Optional initialization */
|
||||
|
||||
/* Clear Event Filters */
|
||||
flt_type = HCI_FLT_CLEAR_ALL;
|
||||
hci_send_cmd(hdev, OGF_HOST_CTL, OCF_SET_EVENT_FLT, 1, &flt_type);
|
||||
hci_send_cmd(hdev, HCI_OP_SET_EVENT_FLT, 1, &flt_type);
|
||||
|
||||
/* Page timeout ~20 secs */
|
||||
param = cpu_to_le16(0x8000);
|
||||
hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_PG_TIMEOUT, 2, ¶m);
|
||||
hci_send_cmd(hdev, HCI_OP_WRITE_PG_TIMEOUT, 2, ¶m);
|
||||
|
||||
/* Connection accept timeout ~20 secs */
|
||||
param = cpu_to_le16(0x7d00);
|
||||
hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_CA_TIMEOUT, 2, ¶m);
|
||||
hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, ¶m);
|
||||
}
|
||||
|
||||
static void hci_scan_req(struct hci_dev *hdev, unsigned long opt)
|
||||
@ -253,7 +259,7 @@ static void hci_scan_req(struct hci_dev *hdev, unsigned long opt)
|
||||
BT_DBG("%s %x", hdev->name, scan);
|
||||
|
||||
/* Inquiry and Page scans */
|
||||
hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE, 1, &scan);
|
||||
hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
|
||||
}
|
||||
|
||||
static void hci_auth_req(struct hci_dev *hdev, unsigned long opt)
|
||||
@ -263,7 +269,7 @@ static void hci_auth_req(struct hci_dev *hdev, unsigned long opt)
|
||||
BT_DBG("%s %x", hdev->name, auth);
|
||||
|
||||
/* Authentication */
|
||||
hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE, 1, &auth);
|
||||
hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, 1, &auth);
|
||||
}
|
||||
|
||||
static void hci_encrypt_req(struct hci_dev *hdev, unsigned long opt)
|
||||
@ -273,7 +279,7 @@ static void hci_encrypt_req(struct hci_dev *hdev, unsigned long opt)
|
||||
BT_DBG("%s %x", hdev->name, encrypt);
|
||||
|
||||
/* Authentication */
|
||||
hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_ENCRYPT_MODE, 1, &encrypt);
|
||||
hci_send_cmd(hdev, HCI_OP_WRITE_ENCRYPT_MODE, 1, &encrypt);
|
||||
}
|
||||
|
||||
/* Get HCI device by index.
|
||||
@ -384,7 +390,7 @@ static void hci_inq_req(struct hci_dev *hdev, unsigned long opt)
|
||||
memcpy(&cp.lap, &ir->lap, 3);
|
||||
cp.length = ir->length;
|
||||
cp.num_rsp = ir->num_rsp;
|
||||
hci_send_cmd(hdev, OGF_LINK_CTL, OCF_INQUIRY, sizeof(cp), &cp);
|
||||
hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
|
||||
}
|
||||
|
||||
int hci_inquiry(void __user *arg)
|
||||
@ -1111,13 +1117,13 @@ static int hci_send_frame(struct sk_buff *skb)
|
||||
}
|
||||
|
||||
/* Send HCI command */
|
||||
int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *param)
|
||||
int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param)
|
||||
{
|
||||
int len = HCI_COMMAND_HDR_SIZE + plen;
|
||||
struct hci_command_hdr *hdr;
|
||||
struct sk_buff *skb;
|
||||
|
||||
BT_DBG("%s ogf 0x%x ocf 0x%x plen %d", hdev->name, ogf, ocf, plen);
|
||||
BT_DBG("%s opcode 0x%x plen %d", hdev->name, opcode, plen);
|
||||
|
||||
skb = bt_skb_alloc(len, GFP_ATOMIC);
|
||||
if (!skb) {
|
||||
@ -1126,7 +1132,7 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *p
|
||||
}
|
||||
|
||||
hdr = (struct hci_command_hdr *) skb_put(skb, HCI_COMMAND_HDR_SIZE);
|
||||
hdr->opcode = cpu_to_le16(hci_opcode_pack(ogf, ocf));
|
||||
hdr->opcode = cpu_to_le16(opcode);
|
||||
hdr->plen = plen;
|
||||
|
||||
if (plen)
|
||||
@ -1143,7 +1149,7 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *p
|
||||
}
|
||||
|
||||
/* Get data from the previously sent command */
|
||||
void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf)
|
||||
void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode)
|
||||
{
|
||||
struct hci_command_hdr *hdr;
|
||||
|
||||
@ -1152,10 +1158,10 @@ void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf)
|
||||
|
||||
hdr = (void *) hdev->sent_cmd->data;
|
||||
|
||||
if (hdr->opcode != cpu_to_le16(hci_opcode_pack(ogf, ocf)))
|
||||
if (hdr->opcode != cpu_to_le16(opcode))
|
||||
return NULL;
|
||||
|
||||
BT_DBG("%s ogf 0x%x ocf 0x%x", hdev->name, ogf, ocf);
|
||||
BT_DBG("%s opcode 0x%x", hdev->name, opcode);
|
||||
|
||||
return hdev->sent_cmd->data + HCI_COMMAND_HDR_SIZE;
|
||||
}
|
||||
@ -1355,6 +1361,26 @@ static inline void hci_sched_sco(struct hci_dev *hdev)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void hci_sched_esco(struct hci_dev *hdev)
|
||||
{
|
||||
struct hci_conn *conn;
|
||||
struct sk_buff *skb;
|
||||
int quote;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
while (hdev->sco_cnt && (conn = hci_low_sent(hdev, ESCO_LINK, "e))) {
|
||||
while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
|
||||
BT_DBG("skb %p len %d", skb, skb->len);
|
||||
hci_send_frame(skb);
|
||||
|
||||
conn->sent++;
|
||||
if (conn->sent == ~0)
|
||||
conn->sent = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void hci_tx_task(unsigned long arg)
|
||||
{
|
||||
struct hci_dev *hdev = (struct hci_dev *) arg;
|
||||
@ -1370,6 +1396,8 @@ static void hci_tx_task(unsigned long arg)
|
||||
|
||||
hci_sched_sco(hdev);
|
||||
|
||||
hci_sched_esco(hdev);
|
||||
|
||||
/* Send next queued raw (unknown type) packet */
|
||||
while ((skb = skb_dequeue(&hdev->raw_q)))
|
||||
hci_send_frame(skb);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -451,7 +451,7 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
|
||||
goto drop;
|
||||
}
|
||||
|
||||
if (test_bit(HCI_RAW, &hdev->flags) || (ogf == OGF_VENDOR_CMD)) {
|
||||
if (test_bit(HCI_RAW, &hdev->flags) || (ogf == 0x3f)) {
|
||||
skb_queue_tail(&hdev->raw_q, skb);
|
||||
hci_sched_tx(hdev);
|
||||
} else {
|
||||
|
@ -41,6 +41,26 @@ static ssize_t show_type(struct device *dev, struct device_attribute *attr, char
|
||||
return sprintf(buf, "%s\n", typetostr(hdev->type));
|
||||
}
|
||||
|
||||
static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hci_dev *hdev = dev_get_drvdata(dev);
|
||||
char name[249];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 248; i++)
|
||||
name[i] = hdev->dev_name[i];
|
||||
|
||||
name[248] = '\0';
|
||||
return sprintf(buf, "%s\n", name);
|
||||
}
|
||||
|
||||
static ssize_t show_class(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hci_dev *hdev = dev_get_drvdata(dev);
|
||||
return sprintf(buf, "0x%.2x%.2x%.2x\n",
|
||||
hdev->dev_class[2], hdev->dev_class[1], hdev->dev_class[0]);
|
||||
}
|
||||
|
||||
static ssize_t show_address(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hci_dev *hdev = dev_get_drvdata(dev);
|
||||
@ -49,6 +69,17 @@ static ssize_t show_address(struct device *dev, struct device_attribute *attr, c
|
||||
return sprintf(buf, "%s\n", batostr(&bdaddr));
|
||||
}
|
||||
|
||||
static ssize_t show_features(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hci_dev *hdev = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
|
||||
hdev->features[0], hdev->features[1],
|
||||
hdev->features[2], hdev->features[3],
|
||||
hdev->features[4], hdev->features[5],
|
||||
hdev->features[6], hdev->features[7]);
|
||||
}
|
||||
|
||||
static ssize_t show_manufacturer(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hci_dev *hdev = dev_get_drvdata(dev);
|
||||
@ -170,7 +201,10 @@ static ssize_t store_sniff_min_interval(struct device *dev, struct device_attrib
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(type, S_IRUGO, show_type, NULL);
|
||||
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
|
||||
static DEVICE_ATTR(class, S_IRUGO, show_class, NULL);
|
||||
static DEVICE_ATTR(address, S_IRUGO, show_address, NULL);
|
||||
static DEVICE_ATTR(features, S_IRUGO, show_features, NULL);
|
||||
static DEVICE_ATTR(manufacturer, S_IRUGO, show_manufacturer, NULL);
|
||||
static DEVICE_ATTR(hci_version, S_IRUGO, show_hci_version, NULL);
|
||||
static DEVICE_ATTR(hci_revision, S_IRUGO, show_hci_revision, NULL);
|
||||
@ -185,7 +219,10 @@ static DEVICE_ATTR(sniff_min_interval, S_IRUGO | S_IWUSR,
|
||||
|
||||
static struct device_attribute *bt_attrs[] = {
|
||||
&dev_attr_type,
|
||||
&dev_attr_name,
|
||||
&dev_attr_class,
|
||||
&dev_attr_address,
|
||||
&dev_attr_features,
|
||||
&dev_attr_manufacturer,
|
||||
&dev_attr_hci_version,
|
||||
&dev_attr_hci_revision,
|
||||
|
@ -247,7 +247,7 @@ static inline int hidp_queue_report(struct hidp_session *session, unsigned char
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
BT_DBG("session %p hid %p data %p size %d", session, device, data, size);
|
||||
BT_DBG("session %p hid %p data %p size %d", session, session->hid, data, size);
|
||||
|
||||
if (!(skb = alloc_skb(size + 1, GFP_ATOMIC))) {
|
||||
BT_ERR("Can't allocate memory for new frame");
|
||||
|
@ -55,7 +55,9 @@
|
||||
#define BT_DBG(D...)
|
||||
#endif
|
||||
|
||||
#define VERSION "2.8"
|
||||
#define VERSION "2.9"
|
||||
|
||||
static u32 l2cap_feat_mask = 0x0000;
|
||||
|
||||
static const struct proto_ops l2cap_sock_ops;
|
||||
|
||||
@ -258,7 +260,119 @@ static void l2cap_chan_del(struct sock *sk, int err)
|
||||
sk->sk_state_change(sk);
|
||||
}
|
||||
|
||||
static inline u8 l2cap_get_ident(struct l2cap_conn *conn)
|
||||
{
|
||||
u8 id;
|
||||
|
||||
/* Get next available identificator.
|
||||
* 1 - 128 are used by kernel.
|
||||
* 129 - 199 are reserved.
|
||||
* 200 - 254 are used by utilities like l2ping, etc.
|
||||
*/
|
||||
|
||||
spin_lock_bh(&conn->lock);
|
||||
|
||||
if (++conn->tx_ident > 128)
|
||||
conn->tx_ident = 1;
|
||||
|
||||
id = conn->tx_ident;
|
||||
|
||||
spin_unlock_bh(&conn->lock);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
static inline int l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
|
||||
{
|
||||
struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
|
||||
|
||||
BT_DBG("code 0x%2.2x", code);
|
||||
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
return hci_send_acl(conn->hcon, skb, 0);
|
||||
}
|
||||
|
||||
/* ---- L2CAP connections ---- */
|
||||
static void l2cap_conn_start(struct l2cap_conn *conn)
|
||||
{
|
||||
struct l2cap_chan_list *l = &conn->chan_list;
|
||||
struct sock *sk;
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
|
||||
read_lock(&l->lock);
|
||||
|
||||
for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
|
||||
bh_lock_sock(sk);
|
||||
|
||||
if (sk->sk_type != SOCK_SEQPACKET) {
|
||||
l2cap_sock_clear_timer(sk);
|
||||
sk->sk_state = BT_CONNECTED;
|
||||
sk->sk_state_change(sk);
|
||||
} else if (sk->sk_state == BT_CONNECT) {
|
||||
struct l2cap_conn_req req;
|
||||
l2cap_pi(sk)->ident = l2cap_get_ident(conn);
|
||||
req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
|
||||
req.psm = l2cap_pi(sk)->psm;
|
||||
l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
|
||||
L2CAP_CONN_REQ, sizeof(req), &req);
|
||||
}
|
||||
|
||||
bh_unlock_sock(sk);
|
||||
}
|
||||
|
||||
read_unlock(&l->lock);
|
||||
}
|
||||
|
||||
static void l2cap_conn_ready(struct l2cap_conn *conn)
|
||||
{
|
||||
BT_DBG("conn %p", conn);
|
||||
|
||||
if (conn->chan_list.head || !hlist_empty(&l2cap_sk_list.head)) {
|
||||
struct l2cap_info_req req;
|
||||
|
||||
req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
|
||||
|
||||
conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
|
||||
conn->info_ident = l2cap_get_ident(conn);
|
||||
|
||||
mod_timer(&conn->info_timer,
|
||||
jiffies + msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
|
||||
|
||||
l2cap_send_cmd(conn, conn->info_ident,
|
||||
L2CAP_INFO_REQ, sizeof(req), &req);
|
||||
}
|
||||
}
|
||||
|
||||
/* Notify sockets that we cannot guaranty reliability anymore */
|
||||
static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
|
||||
{
|
||||
struct l2cap_chan_list *l = &conn->chan_list;
|
||||
struct sock *sk;
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
|
||||
read_lock(&l->lock);
|
||||
|
||||
for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
|
||||
if (l2cap_pi(sk)->link_mode & L2CAP_LM_RELIABLE)
|
||||
sk->sk_err = err;
|
||||
}
|
||||
|
||||
read_unlock(&l->lock);
|
||||
}
|
||||
|
||||
static void l2cap_info_timeout(unsigned long arg)
|
||||
{
|
||||
struct l2cap_conn *conn = (void *) arg;
|
||||
|
||||
conn->info_ident = 0;
|
||||
|
||||
l2cap_conn_start(conn);
|
||||
}
|
||||
|
||||
static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
|
||||
{
|
||||
struct l2cap_conn *conn = hcon->l2cap_data;
|
||||
@ -279,6 +393,12 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
|
||||
conn->src = &hcon->hdev->bdaddr;
|
||||
conn->dst = &hcon->dst;
|
||||
|
||||
conn->feat_mask = 0;
|
||||
|
||||
init_timer(&conn->info_timer);
|
||||
conn->info_timer.function = l2cap_info_timeout;
|
||||
conn->info_timer.data = (unsigned long) conn;
|
||||
|
||||
spin_lock_init(&conn->lock);
|
||||
rwlock_init(&conn->chan_list.lock);
|
||||
|
||||
@ -318,40 +438,6 @@ static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, stru
|
||||
write_unlock_bh(&l->lock);
|
||||
}
|
||||
|
||||
static inline u8 l2cap_get_ident(struct l2cap_conn *conn)
|
||||
{
|
||||
u8 id;
|
||||
|
||||
/* Get next available identificator.
|
||||
* 1 - 128 are used by kernel.
|
||||
* 129 - 199 are reserved.
|
||||
* 200 - 254 are used by utilities like l2ping, etc.
|
||||
*/
|
||||
|
||||
spin_lock_bh(&conn->lock);
|
||||
|
||||
if (++conn->tx_ident > 128)
|
||||
conn->tx_ident = 1;
|
||||
|
||||
id = conn->tx_ident;
|
||||
|
||||
spin_unlock_bh(&conn->lock);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
static inline int l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
|
||||
{
|
||||
struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
|
||||
|
||||
BT_DBG("code 0x%2.2x", code);
|
||||
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
return hci_send_acl(conn->hcon, skb, 0);
|
||||
}
|
||||
|
||||
/* ---- Socket interface ---- */
|
||||
static struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src)
|
||||
{
|
||||
@ -508,7 +594,6 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
|
||||
|
||||
/* Default config options */
|
||||
pi->conf_len = 0;
|
||||
pi->conf_mtu = L2CAP_DEFAULT_MTU;
|
||||
pi->flush_to = L2CAP_DEFAULT_FLUSH_TO;
|
||||
}
|
||||
|
||||
@ -530,7 +615,7 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int p
|
||||
INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
|
||||
|
||||
sk->sk_destruct = l2cap_sock_destruct;
|
||||
sk->sk_sndtimeo = L2CAP_CONN_TIMEOUT;
|
||||
sk->sk_sndtimeo = msecs_to_jiffies(L2CAP_CONN_TIMEOUT);
|
||||
|
||||
sock_reset_flag(sk, SOCK_ZAPPED);
|
||||
|
||||
@ -650,6 +735,11 @@ static int l2cap_do_connect(struct sock *sk)
|
||||
l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
|
||||
|
||||
if (hcon->state == BT_CONNECTED) {
|
||||
if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)) {
|
||||
l2cap_conn_ready(conn);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (sk->sk_type == SOCK_SEQPACKET) {
|
||||
struct l2cap_conn_req req;
|
||||
l2cap_pi(sk)->ident = l2cap_get_ident(conn);
|
||||
@ -958,7 +1048,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
|
||||
opts.imtu = l2cap_pi(sk)->imtu;
|
||||
opts.omtu = l2cap_pi(sk)->omtu;
|
||||
opts.flush_to = l2cap_pi(sk)->flush_to;
|
||||
opts.mode = 0x00;
|
||||
opts.mode = L2CAP_MODE_BASIC;
|
||||
|
||||
len = min_t(unsigned int, sizeof(opts), optlen);
|
||||
if (copy_from_user((char *) &opts, optval, len)) {
|
||||
@ -1007,7 +1097,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
|
||||
opts.imtu = l2cap_pi(sk)->imtu;
|
||||
opts.omtu = l2cap_pi(sk)->omtu;
|
||||
opts.flush_to = l2cap_pi(sk)->flush_to;
|
||||
opts.mode = 0x00;
|
||||
opts.mode = L2CAP_MODE_BASIC;
|
||||
|
||||
len = min_t(unsigned int, len, sizeof(opts));
|
||||
if (copy_to_user(optval, (char *) &opts, len))
|
||||
@ -1084,52 +1174,6 @@ static int l2cap_sock_release(struct socket *sock)
|
||||
return err;
|
||||
}
|
||||
|
||||
static void l2cap_conn_ready(struct l2cap_conn *conn)
|
||||
{
|
||||
struct l2cap_chan_list *l = &conn->chan_list;
|
||||
struct sock *sk;
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
|
||||
read_lock(&l->lock);
|
||||
|
||||
for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
|
||||
bh_lock_sock(sk);
|
||||
|
||||
if (sk->sk_type != SOCK_SEQPACKET) {
|
||||
l2cap_sock_clear_timer(sk);
|
||||
sk->sk_state = BT_CONNECTED;
|
||||
sk->sk_state_change(sk);
|
||||
} else if (sk->sk_state == BT_CONNECT) {
|
||||
struct l2cap_conn_req req;
|
||||
l2cap_pi(sk)->ident = l2cap_get_ident(conn);
|
||||
req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
|
||||
req.psm = l2cap_pi(sk)->psm;
|
||||
l2cap_send_cmd(conn, l2cap_pi(sk)->ident, L2CAP_CONN_REQ, sizeof(req), &req);
|
||||
}
|
||||
|
||||
bh_unlock_sock(sk);
|
||||
}
|
||||
|
||||
read_unlock(&l->lock);
|
||||
}
|
||||
|
||||
/* Notify sockets that we cannot guaranty reliability anymore */
|
||||
static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
|
||||
{
|
||||
struct l2cap_chan_list *l = &conn->chan_list;
|
||||
struct sock *sk;
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
|
||||
read_lock(&l->lock);
|
||||
for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
|
||||
if (l2cap_pi(sk)->link_mode & L2CAP_LM_RELIABLE)
|
||||
sk->sk_err = err;
|
||||
}
|
||||
read_unlock(&l->lock);
|
||||
}
|
||||
|
||||
static void l2cap_chan_ready(struct sock *sk)
|
||||
{
|
||||
struct sock *parent = bt_sk(sk)->parent;
|
||||
@ -1256,11 +1300,11 @@ static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned
|
||||
break;
|
||||
|
||||
case 2:
|
||||
*val = __le16_to_cpu(*((__le16 *)opt->val));
|
||||
*val = __le16_to_cpu(*((__le16 *) opt->val));
|
||||
break;
|
||||
|
||||
case 4:
|
||||
*val = __le32_to_cpu(*((__le32 *)opt->val));
|
||||
*val = __le32_to_cpu(*((__le32 *) opt->val));
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -1332,6 +1376,8 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data)
|
||||
int len = pi->conf_len;
|
||||
int type, hint, olen;
|
||||
unsigned long val;
|
||||
struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
|
||||
u16 mtu = L2CAP_DEFAULT_MTU;
|
||||
u16 result = L2CAP_CONF_SUCCESS;
|
||||
|
||||
BT_DBG("sk %p", sk);
|
||||
@ -1344,7 +1390,7 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data)
|
||||
|
||||
switch (type) {
|
||||
case L2CAP_CONF_MTU:
|
||||
pi->conf_mtu = val;
|
||||
mtu = val;
|
||||
break;
|
||||
|
||||
case L2CAP_CONF_FLUSH_TO:
|
||||
@ -1354,6 +1400,11 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data)
|
||||
case L2CAP_CONF_QOS:
|
||||
break;
|
||||
|
||||
case L2CAP_CONF_RFC:
|
||||
if (olen == sizeof(rfc))
|
||||
memcpy(&rfc, (void *) val, olen);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (hint)
|
||||
break;
|
||||
@ -1368,12 +1419,24 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data)
|
||||
/* Configure output options and let the other side know
|
||||
* which ones we don't like. */
|
||||
|
||||
if (pi->conf_mtu < pi->omtu)
|
||||
result = L2CAP_CONF_UNACCEPT;
|
||||
else
|
||||
pi->omtu = pi->conf_mtu;
|
||||
if (rfc.mode == L2CAP_MODE_BASIC) {
|
||||
if (mtu < pi->omtu)
|
||||
result = L2CAP_CONF_UNACCEPT;
|
||||
else {
|
||||
pi->omtu = mtu;
|
||||
pi->conf_state |= L2CAP_CONF_OUTPUT_DONE;
|
||||
}
|
||||
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->omtu);
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->omtu);
|
||||
} else {
|
||||
result = L2CAP_CONF_UNACCEPT;
|
||||
|
||||
memset(&rfc, 0, sizeof(rfc));
|
||||
rfc.mode = L2CAP_MODE_BASIC;
|
||||
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
|
||||
sizeof(rfc), (unsigned long) &rfc);
|
||||
}
|
||||
}
|
||||
|
||||
rsp->scid = cpu_to_le16(pi->dcid);
|
||||
@ -1397,6 +1460,23 @@ static int l2cap_build_conf_rsp(struct sock *sk, void *data, u16 result, u16 fla
|
||||
return ptr - data;
|
||||
}
|
||||
|
||||
static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
|
||||
{
|
||||
struct l2cap_cmd_rej *rej = (struct l2cap_cmd_rej *) data;
|
||||
|
||||
if (rej->reason != 0x0000)
|
||||
return 0;
|
||||
|
||||
if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
|
||||
cmd->ident == conn->info_ident) {
|
||||
conn->info_ident = 0;
|
||||
del_timer(&conn->info_timer);
|
||||
l2cap_conn_start(conn);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
|
||||
{
|
||||
struct l2cap_chan_list *list = &conn->chan_list;
|
||||
@ -1577,16 +1657,19 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
|
||||
|
||||
l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
|
||||
|
||||
/* Output config done. */
|
||||
l2cap_pi(sk)->conf_state |= L2CAP_CONF_OUTPUT_DONE;
|
||||
|
||||
/* Reset config buffer. */
|
||||
l2cap_pi(sk)->conf_len = 0;
|
||||
|
||||
if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE))
|
||||
goto unlock;
|
||||
|
||||
if (l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE) {
|
||||
sk->sk_state = BT_CONNECTED;
|
||||
l2cap_chan_ready(sk);
|
||||
} else if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)) {
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)) {
|
||||
u8 req[64];
|
||||
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
|
||||
l2cap_build_conf_req(sk, req), req);
|
||||
@ -1646,7 +1729,6 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
|
||||
if (flags & 0x01)
|
||||
goto done;
|
||||
|
||||
/* Input config done */
|
||||
l2cap_pi(sk)->conf_state |= L2CAP_CONF_INPUT_DONE;
|
||||
|
||||
if (l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE) {
|
||||
@ -1711,16 +1793,27 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
|
||||
static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
|
||||
{
|
||||
struct l2cap_info_req *req = (struct l2cap_info_req *) data;
|
||||
struct l2cap_info_rsp rsp;
|
||||
u16 type;
|
||||
|
||||
type = __le16_to_cpu(req->type);
|
||||
|
||||
BT_DBG("type 0x%4.4x", type);
|
||||
|
||||
rsp.type = cpu_to_le16(type);
|
||||
rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
|
||||
l2cap_send_cmd(conn, cmd->ident, L2CAP_INFO_RSP, sizeof(rsp), &rsp);
|
||||
if (type == L2CAP_IT_FEAT_MASK) {
|
||||
u8 buf[8];
|
||||
struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
|
||||
rsp->type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
|
||||
rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
|
||||
put_unaligned(cpu_to_le32(l2cap_feat_mask), (__le32 *) rsp->data);
|
||||
l2cap_send_cmd(conn, cmd->ident,
|
||||
L2CAP_INFO_RSP, sizeof(buf), buf);
|
||||
} else {
|
||||
struct l2cap_info_rsp rsp;
|
||||
rsp.type = cpu_to_le16(type);
|
||||
rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
|
||||
l2cap_send_cmd(conn, cmd->ident,
|
||||
L2CAP_INFO_RSP, sizeof(rsp), &rsp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1735,6 +1828,15 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
|
||||
|
||||
BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
|
||||
|
||||
conn->info_ident = 0;
|
||||
|
||||
del_timer(&conn->info_timer);
|
||||
|
||||
if (type == L2CAP_IT_FEAT_MASK)
|
||||
conn->feat_mask = __le32_to_cpu(get_unaligned((__le32 *) rsp->data));
|
||||
|
||||
l2cap_conn_start(conn);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1764,7 +1866,7 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *sk
|
||||
|
||||
switch (cmd.code) {
|
||||
case L2CAP_COMMAND_REJ:
|
||||
/* FIXME: We should process this */
|
||||
l2cap_command_rej(conn, &cmd, data);
|
||||
break;
|
||||
|
||||
case L2CAP_CONN_REQ:
|
||||
|
@ -33,11 +33,11 @@
|
||||
#include <linux/sched.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/freezer.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/kthread.h>
|
||||
|
||||
#include <net/sock.h>
|
||||
#include <asm/uaccess.h>
|
||||
@ -68,7 +68,6 @@ static DEFINE_MUTEX(rfcomm_mutex);
|
||||
static unsigned long rfcomm_event;
|
||||
|
||||
static LIST_HEAD(session_list);
|
||||
static atomic_t terminate, running;
|
||||
|
||||
static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len);
|
||||
static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci);
|
||||
@ -1850,26 +1849,6 @@ static inline void rfcomm_process_sessions(void)
|
||||
rfcomm_unlock();
|
||||
}
|
||||
|
||||
static void rfcomm_worker(void)
|
||||
{
|
||||
BT_DBG("");
|
||||
|
||||
while (!atomic_read(&terminate)) {
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
if (!test_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event)) {
|
||||
/* No pending events. Let's sleep.
|
||||
* Incoming connections and data will wake us up. */
|
||||
schedule();
|
||||
}
|
||||
set_current_state(TASK_RUNNING);
|
||||
|
||||
/* Process stuff */
|
||||
clear_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event);
|
||||
rfcomm_process_sessions();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static int rfcomm_add_listener(bdaddr_t *ba)
|
||||
{
|
||||
struct sockaddr_l2 addr;
|
||||
@ -1935,22 +1914,28 @@ static void rfcomm_kill_listener(void)
|
||||
|
||||
static int rfcomm_run(void *unused)
|
||||
{
|
||||
rfcomm_thread = current;
|
||||
|
||||
atomic_inc(&running);
|
||||
|
||||
daemonize("krfcommd");
|
||||
set_user_nice(current, -10);
|
||||
|
||||
BT_DBG("");
|
||||
|
||||
set_user_nice(current, -10);
|
||||
|
||||
rfcomm_add_listener(BDADDR_ANY);
|
||||
|
||||
rfcomm_worker();
|
||||
while (!kthread_should_stop()) {
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
if (!test_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event)) {
|
||||
/* No pending events. Let's sleep.
|
||||
* Incoming connections and data will wake us up. */
|
||||
schedule();
|
||||
}
|
||||
set_current_state(TASK_RUNNING);
|
||||
|
||||
/* Process stuff */
|
||||
clear_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event);
|
||||
rfcomm_process_sessions();
|
||||
}
|
||||
|
||||
rfcomm_kill_listener();
|
||||
|
||||
atomic_dec(&running);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2059,7 +2044,11 @@ static int __init rfcomm_init(void)
|
||||
|
||||
hci_register_cb(&rfcomm_cb);
|
||||
|
||||
kernel_thread(rfcomm_run, NULL, CLONE_KERNEL);
|
||||
rfcomm_thread = kthread_run(rfcomm_run, NULL, "krfcommd");
|
||||
if (IS_ERR(rfcomm_thread)) {
|
||||
hci_unregister_cb(&rfcomm_cb);
|
||||
return PTR_ERR(rfcomm_thread);
|
||||
}
|
||||
|
||||
if (class_create_file(bt_class, &class_attr_rfcomm_dlc) < 0)
|
||||
BT_ERR("Failed to create RFCOMM info file");
|
||||
@ -2081,14 +2070,7 @@ static void __exit rfcomm_exit(void)
|
||||
|
||||
hci_unregister_cb(&rfcomm_cb);
|
||||
|
||||
/* Terminate working thread.
|
||||
* ie. Set terminate flag and wake it up */
|
||||
atomic_inc(&terminate);
|
||||
rfcomm_schedule(RFCOMM_SCHED_STATE);
|
||||
|
||||
/* Wait until thread is running */
|
||||
while (atomic_read(&running))
|
||||
schedule();
|
||||
kthread_stop(rfcomm_thread);
|
||||
|
||||
#ifdef CONFIG_BT_RFCOMM_TTY
|
||||
rfcomm_cleanup_ttys();
|
||||
|
@ -189,6 +189,23 @@ static struct device *rfcomm_get_device(struct rfcomm_dev *dev)
|
||||
return conn ? &conn->dev : NULL;
|
||||
}
|
||||
|
||||
static ssize_t show_address(struct device *tty_dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct rfcomm_dev *dev = dev_get_drvdata(tty_dev);
|
||||
bdaddr_t bdaddr;
|
||||
baswap(&bdaddr, &dev->dst);
|
||||
return sprintf(buf, "%s\n", batostr(&bdaddr));
|
||||
}
|
||||
|
||||
static ssize_t show_channel(struct device *tty_dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct rfcomm_dev *dev = dev_get_drvdata(tty_dev);
|
||||
return sprintf(buf, "%d\n", dev->channel);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(address, S_IRUGO, show_address, NULL);
|
||||
static DEVICE_ATTR(channel, S_IRUGO, show_channel, NULL);
|
||||
|
||||
static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
|
||||
{
|
||||
struct rfcomm_dev *dev;
|
||||
@ -281,6 +298,14 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
|
||||
return err;
|
||||
}
|
||||
|
||||
dev_set_drvdata(dev->tty_dev, dev);
|
||||
|
||||
if (device_create_file(dev->tty_dev, &dev_attr_address) < 0)
|
||||
BT_ERR("Failed to create address attribute");
|
||||
|
||||
if (device_create_file(dev->tty_dev, &dev_attr_channel) < 0)
|
||||
BT_ERR("Failed to create channel attribute");
|
||||
|
||||
return dev->id;
|
||||
}
|
||||
|
||||
|
@ -189,7 +189,7 @@ static int sco_connect(struct sock *sk)
|
||||
struct sco_conn *conn;
|
||||
struct hci_conn *hcon;
|
||||
struct hci_dev *hdev;
|
||||
int err = 0;
|
||||
int err, type;
|
||||
|
||||
BT_DBG("%s -> %s", batostr(src), batostr(dst));
|
||||
|
||||
@ -200,7 +200,9 @@ static int sco_connect(struct sock *sk)
|
||||
|
||||
err = -ENOMEM;
|
||||
|
||||
hcon = hci_connect(hdev, SCO_LINK, dst);
|
||||
type = lmp_esco_capable(hdev) ? ESCO_LINK : SCO_LINK;
|
||||
|
||||
hcon = hci_connect(hdev, type, dst);
|
||||
if (!hcon)
|
||||
goto done;
|
||||
|
||||
@ -224,6 +226,7 @@ static int sco_connect(struct sock *sk)
|
||||
sk->sk_state = BT_CONNECT;
|
||||
sco_sock_set_timer(sk, sk->sk_sndtimeo);
|
||||
}
|
||||
|
||||
done:
|
||||
hci_dev_unlock_bh(hdev);
|
||||
hci_dev_put(hdev);
|
||||
@ -846,7 +849,7 @@ static int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
|
||||
{
|
||||
BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
|
||||
|
||||
if (hcon->type != SCO_LINK)
|
||||
if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK)
|
||||
return 0;
|
||||
|
||||
if (!status) {
|
||||
@ -865,10 +868,11 @@ static int sco_disconn_ind(struct hci_conn *hcon, __u8 reason)
|
||||
{
|
||||
BT_DBG("hcon %p reason %d", hcon, reason);
|
||||
|
||||
if (hcon->type != SCO_LINK)
|
||||
if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK)
|
||||
return 0;
|
||||
|
||||
sco_conn_del(hcon, bt_err(reason));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1553,7 +1553,7 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
return rc;
|
||||
}
|
||||
if (unlikely((netif_queue_stopped(dev) ||
|
||||
netif_subqueue_stopped(dev, skb->queue_mapping)) &&
|
||||
netif_subqueue_stopped(dev, skb)) &&
|
||||
skb->next))
|
||||
return NETDEV_TX_BUSY;
|
||||
} while (skb->next);
|
||||
@ -1661,7 +1661,7 @@ int dev_queue_xmit(struct sk_buff *skb)
|
||||
q = dev->qdisc;
|
||||
if (q->enqueue) {
|
||||
/* reset queue_mapping to zero */
|
||||
skb->queue_mapping = 0;
|
||||
skb_set_queue_mapping(skb, 0);
|
||||
rc = q->enqueue(skb, q);
|
||||
qdisc_run(dev);
|
||||
spin_unlock(&dev->queue_lock);
|
||||
@ -1692,7 +1692,7 @@ int dev_queue_xmit(struct sk_buff *skb)
|
||||
HARD_TX_LOCK(dev, cpu);
|
||||
|
||||
if (!netif_queue_stopped(dev) &&
|
||||
!netif_subqueue_stopped(dev, skb->queue_mapping)) {
|
||||
!netif_subqueue_stopped(dev, skb)) {
|
||||
rc = 0;
|
||||
if (!dev_hard_start_xmit(skb, dev)) {
|
||||
HARD_TX_UNLOCK(dev);
|
||||
|
@ -1438,6 +1438,9 @@ int neigh_table_clear(struct neigh_table *tbl)
|
||||
free_percpu(tbl->stats);
|
||||
tbl->stats = NULL;
|
||||
|
||||
kmem_cache_destroy(tbl->kmem_cachep);
|
||||
tbl->kmem_cachep = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -67,7 +67,7 @@ static void queue_process(struct work_struct *work)
|
||||
local_irq_save(flags);
|
||||
netif_tx_lock(dev);
|
||||
if ((netif_queue_stopped(dev) ||
|
||||
netif_subqueue_stopped(dev, skb->queue_mapping)) ||
|
||||
netif_subqueue_stopped(dev, skb)) ||
|
||||
dev->hard_start_xmit(skb, dev) != NETDEV_TX_OK) {
|
||||
skb_queue_head(&npinfo->txq, skb);
|
||||
netif_tx_unlock(dev);
|
||||
@ -269,7 +269,7 @@ static void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
|
||||
tries > 0; --tries) {
|
||||
if (netif_tx_trylock(dev)) {
|
||||
if (!netif_queue_stopped(dev) &&
|
||||
!netif_subqueue_stopped(dev, skb->queue_mapping))
|
||||
!netif_subqueue_stopped(dev, skb))
|
||||
status = dev->hard_start_xmit(skb, dev);
|
||||
netif_tx_unlock(dev);
|
||||
|
||||
|
@ -2603,8 +2603,7 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
|
||||
skb->network_header = skb->tail;
|
||||
skb->transport_header = skb->network_header + sizeof(struct iphdr);
|
||||
skb_put(skb, sizeof(struct iphdr) + sizeof(struct udphdr));
|
||||
skb->queue_mapping = pkt_dev->cur_queue_map;
|
||||
|
||||
skb_set_queue_mapping(skb, pkt_dev->cur_queue_map);
|
||||
iph = ip_hdr(skb);
|
||||
udph = udp_hdr(skb);
|
||||
|
||||
@ -2941,8 +2940,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
|
||||
skb->network_header = skb->tail;
|
||||
skb->transport_header = skb->network_header + sizeof(struct ipv6hdr);
|
||||
skb_put(skb, sizeof(struct ipv6hdr) + sizeof(struct udphdr));
|
||||
skb->queue_mapping = pkt_dev->cur_queue_map;
|
||||
|
||||
skb_set_queue_mapping(skb, pkt_dev->cur_queue_map);
|
||||
iph = ipv6_hdr(skb);
|
||||
udph = udp_hdr(skb);
|
||||
|
||||
@ -3385,7 +3383,7 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
|
||||
|
||||
if ((netif_queue_stopped(odev) ||
|
||||
(pkt_dev->skb &&
|
||||
netif_subqueue_stopped(odev, pkt_dev->skb->queue_mapping))) ||
|
||||
netif_subqueue_stopped(odev, pkt_dev->skb))) ||
|
||||
need_resched()) {
|
||||
idle_start = getCurUs();
|
||||
|
||||
@ -3402,7 +3400,7 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
|
||||
pkt_dev->idle_acc += getCurUs() - idle_start;
|
||||
|
||||
if (netif_queue_stopped(odev) ||
|
||||
netif_subqueue_stopped(odev, pkt_dev->skb->queue_mapping)) {
|
||||
netif_subqueue_stopped(odev, pkt_dev->skb)) {
|
||||
pkt_dev->next_tx_us = getCurUs(); /* TODO */
|
||||
pkt_dev->next_tx_ns = 0;
|
||||
goto out; /* Try the next interface */
|
||||
@ -3431,7 +3429,7 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
|
||||
|
||||
netif_tx_lock_bh(odev);
|
||||
if (!netif_queue_stopped(odev) &&
|
||||
!netif_subqueue_stopped(odev, pkt_dev->skb->queue_mapping)) {
|
||||
!netif_subqueue_stopped(odev, pkt_dev->skb)) {
|
||||
|
||||
atomic_inc(&(pkt_dev->skb->users));
|
||||
retry_now:
|
||||
|
@ -68,3 +68,4 @@ module_exit(dccp_diag_fini);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>");
|
||||
MODULE_DESCRIPTION("DCCP inet_diag handler");
|
||||
MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_INET_DIAG, DCCPDIAG_GETSOCK);
|
||||
|
@ -1037,8 +1037,8 @@ module_exit(dccp_v4_exit);
|
||||
* values directly, Also cover the case where the protocol is not specified,
|
||||
* i.e. net-pf-PF_INET-proto-0-type-SOCK_DCCP
|
||||
*/
|
||||
MODULE_ALIAS("net-pf-" __stringify(PF_INET) "-proto-33-type-6");
|
||||
MODULE_ALIAS("net-pf-" __stringify(PF_INET) "-proto-0-type-6");
|
||||
MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET, 33, 6);
|
||||
MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET, 0, 6);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>");
|
||||
MODULE_DESCRIPTION("DCCP - Datagram Congestion Controlled Protocol");
|
||||
|
@ -1219,8 +1219,8 @@ module_exit(dccp_v6_exit);
|
||||
* values directly, Also cover the case where the protocol is not specified,
|
||||
* i.e. net-pf-PF_INET6-proto-0-type-SOCK_DCCP
|
||||
*/
|
||||
MODULE_ALIAS("net-pf-" __stringify(PF_INET6) "-proto-33-type-6");
|
||||
MODULE_ALIAS("net-pf-" __stringify(PF_INET6) "-proto-0-type-6");
|
||||
MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 33, 6);
|
||||
MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 0, 6);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>");
|
||||
MODULE_DESCRIPTION("DCCPv6 - Datagram Congestion Controlled Protocol");
|
||||
|
@ -815,6 +815,12 @@ static int inet_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||
nlmsg_len(nlh) < hdrlen)
|
||||
return -EINVAL;
|
||||
|
||||
#ifdef CONFIG_KMOD
|
||||
if (inet_diag_table[nlh->nlmsg_type] == NULL)
|
||||
request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK,
|
||||
NETLINK_INET_DIAG, nlh->nlmsg_type);
|
||||
#endif
|
||||
|
||||
if (inet_diag_table[nlh->nlmsg_type] == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
@ -914,3 +920,4 @@ static void __exit inet_diag_exit(void)
|
||||
module_init(inet_diag_init);
|
||||
module_exit(inet_diag_exit);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_INET_DIAG);
|
||||
|
@ -56,3 +56,4 @@ static void __exit tcp_diag_exit(void)
|
||||
module_init(tcp_diag_init);
|
||||
module_exit(tcp_diag_exit);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_INET_DIAG, TCPDIAG_GETSOCK);
|
||||
|
@ -483,6 +483,7 @@ static int ah6_init_state(struct xfrm_state *x)
|
||||
break;
|
||||
case XFRM_MODE_TUNNEL:
|
||||
x->props.header_len += sizeof(struct ipv6hdr);
|
||||
break;
|
||||
default:
|
||||
goto error;
|
||||
}
|
||||
|
@ -360,6 +360,7 @@ static int esp6_init_state(struct xfrm_state *x)
|
||||
break;
|
||||
case XFRM_MODE_TUNNEL:
|
||||
x->props.header_len += sizeof(struct ipv6hdr);
|
||||
break;
|
||||
default:
|
||||
goto error;
|
||||
}
|
||||
|
@ -266,7 +266,7 @@ static int teql_master_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
int busy;
|
||||
int nores;
|
||||
int len = skb->len;
|
||||
int subq = skb->queue_mapping;
|
||||
int subq = skb_get_queue_mapping(skb);
|
||||
struct sk_buff *skb_res = NULL;
|
||||
|
||||
start = master->slaves;
|
||||
@ -284,7 +284,7 @@ static int teql_master_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
if (slave->qdisc_sleeping != q)
|
||||
continue;
|
||||
if (netif_queue_stopped(slave) ||
|
||||
netif_subqueue_stopped(slave, subq) ||
|
||||
__netif_subqueue_stopped(slave, subq) ||
|
||||
!netif_running(slave)) {
|
||||
busy = 1;
|
||||
continue;
|
||||
@ -294,7 +294,7 @@ static int teql_master_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
case 0:
|
||||
if (netif_tx_trylock(slave)) {
|
||||
if (!netif_queue_stopped(slave) &&
|
||||
!netif_subqueue_stopped(slave, subq) &&
|
||||
!__netif_subqueue_stopped(slave, subq) &&
|
||||
slave->hard_start_xmit(skb, slave) == 0) {
|
||||
netif_tx_unlock(slave);
|
||||
master->slaves = NEXT_SLAVE(q);
|
||||
|
Loading…
Reference in New Issue
Block a user