Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/padovan/bluetooth-next-2.6
This commit is contained in:
commit
bb411b4db2
@ -188,7 +188,7 @@ config BT_MRVL
|
||||
The core driver to support Marvell Bluetooth devices.
|
||||
|
||||
This driver is required if you want to support
|
||||
Marvell Bluetooth devices, such as 8688.
|
||||
Marvell Bluetooth devices, such as 8688/8787.
|
||||
|
||||
Say Y here to compile Marvell Bluetooth driver
|
||||
into the kernel or say M to compile it as module.
|
||||
@ -201,7 +201,7 @@ config BT_MRVL_SDIO
|
||||
The driver for Marvell Bluetooth chipsets with SDIO interface.
|
||||
|
||||
This driver is required if you want to use Marvell Bluetooth
|
||||
devices with SDIO interface. Currently only SD8688 chipset is
|
||||
devices with SDIO interface. Currently SD8688/SD8787 chipsets are
|
||||
supported.
|
||||
|
||||
Say Y here to compile support for Marvell BT-over-SDIO driver
|
||||
|
@ -138,9 +138,6 @@ static int ath3k_load_firmware(struct usb_device *udev,
|
||||
count -= size;
|
||||
}
|
||||
|
||||
kfree(send_buf);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
kfree(send_buf);
|
||||
return err;
|
||||
|
@ -49,15 +49,59 @@
|
||||
static u8 user_rmmod;
|
||||
static u8 sdio_ireg;
|
||||
|
||||
static const struct btmrvl_sdio_card_reg btmrvl_reg_8688 = {
|
||||
.cfg = 0x03,
|
||||
.host_int_mask = 0x04,
|
||||
.host_intstatus = 0x05,
|
||||
.card_status = 0x20,
|
||||
.sq_read_base_addr_a0 = 0x10,
|
||||
.sq_read_base_addr_a1 = 0x11,
|
||||
.card_fw_status0 = 0x40,
|
||||
.card_fw_status1 = 0x41,
|
||||
.card_rx_len = 0x42,
|
||||
.card_rx_unit = 0x43,
|
||||
.io_port_0 = 0x00,
|
||||
.io_port_1 = 0x01,
|
||||
.io_port_2 = 0x02,
|
||||
};
|
||||
static const struct btmrvl_sdio_card_reg btmrvl_reg_8787 = {
|
||||
.cfg = 0x00,
|
||||
.host_int_mask = 0x02,
|
||||
.host_intstatus = 0x03,
|
||||
.card_status = 0x30,
|
||||
.sq_read_base_addr_a0 = 0x40,
|
||||
.sq_read_base_addr_a1 = 0x41,
|
||||
.card_revision = 0x5c,
|
||||
.card_fw_status0 = 0x60,
|
||||
.card_fw_status1 = 0x61,
|
||||
.card_rx_len = 0x62,
|
||||
.card_rx_unit = 0x63,
|
||||
.io_port_0 = 0x78,
|
||||
.io_port_1 = 0x79,
|
||||
.io_port_2 = 0x7a,
|
||||
};
|
||||
|
||||
static const struct btmrvl_sdio_device btmrvl_sdio_sd6888 = {
|
||||
.helper = "sd8688_helper.bin",
|
||||
.firmware = "sd8688.bin",
|
||||
.reg = &btmrvl_reg_8688,
|
||||
.sd_blksz_fw_dl = 64,
|
||||
};
|
||||
|
||||
static const struct btmrvl_sdio_device btmrvl_sdio_sd8787 = {
|
||||
.helper = NULL,
|
||||
.firmware = "mrvl/sd8787_uapsta.bin",
|
||||
.reg = &btmrvl_reg_8787,
|
||||
.sd_blksz_fw_dl = 256,
|
||||
};
|
||||
|
||||
static const struct sdio_device_id btmrvl_sdio_ids[] = {
|
||||
/* Marvell SD8688 Bluetooth device */
|
||||
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9105),
|
||||
.driver_data = (unsigned long) &btmrvl_sdio_sd6888 },
|
||||
/* Marvell SD8787 Bluetooth device */
|
||||
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x911A),
|
||||
.driver_data = (unsigned long) &btmrvl_sdio_sd8787 },
|
||||
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
@ -69,7 +113,7 @@ static int btmrvl_sdio_get_rx_unit(struct btmrvl_sdio_card *card)
|
||||
u8 reg;
|
||||
int ret;
|
||||
|
||||
reg = sdio_readb(card->func, CARD_RX_UNIT_REG, &ret);
|
||||
reg = sdio_readb(card->func, card->reg->card_rx_unit, &ret);
|
||||
if (!ret)
|
||||
card->rx_unit = reg;
|
||||
|
||||
@ -83,11 +127,11 @@ static int btmrvl_sdio_read_fw_status(struct btmrvl_sdio_card *card, u16 *dat)
|
||||
|
||||
*dat = 0;
|
||||
|
||||
fws0 = sdio_readb(card->func, CARD_FW_STATUS0_REG, &ret);
|
||||
fws0 = sdio_readb(card->func, card->reg->card_fw_status0, &ret);
|
||||
if (ret)
|
||||
return -EIO;
|
||||
|
||||
fws1 = sdio_readb(card->func, CARD_FW_STATUS1_REG, &ret);
|
||||
fws1 = sdio_readb(card->func, card->reg->card_fw_status1, &ret);
|
||||
if (ret)
|
||||
return -EIO;
|
||||
|
||||
@ -101,7 +145,7 @@ static int btmrvl_sdio_read_rx_len(struct btmrvl_sdio_card *card, u16 *dat)
|
||||
u8 reg;
|
||||
int ret;
|
||||
|
||||
reg = sdio_readb(card->func, CARD_RX_LEN_REG, &ret);
|
||||
reg = sdio_readb(card->func, card->reg->card_rx_len, &ret);
|
||||
if (!ret)
|
||||
*dat = (u16) reg << card->rx_unit;
|
||||
|
||||
@ -113,7 +157,7 @@ static int btmrvl_sdio_enable_host_int_mask(struct btmrvl_sdio_card *card,
|
||||
{
|
||||
int ret;
|
||||
|
||||
sdio_writeb(card->func, mask, HOST_INT_MASK_REG, &ret);
|
||||
sdio_writeb(card->func, mask, card->reg->host_int_mask, &ret);
|
||||
if (ret) {
|
||||
BT_ERR("Unable to enable the host interrupt!");
|
||||
ret = -EIO;
|
||||
@ -128,13 +172,13 @@ static int btmrvl_sdio_disable_host_int_mask(struct btmrvl_sdio_card *card,
|
||||
u8 host_int_mask;
|
||||
int ret;
|
||||
|
||||
host_int_mask = sdio_readb(card->func, HOST_INT_MASK_REG, &ret);
|
||||
host_int_mask = sdio_readb(card->func, card->reg->host_int_mask, &ret);
|
||||
if (ret)
|
||||
return -EIO;
|
||||
|
||||
host_int_mask &= ~mask;
|
||||
|
||||
sdio_writeb(card->func, host_int_mask, HOST_INT_MASK_REG, &ret);
|
||||
sdio_writeb(card->func, host_int_mask, card->reg->host_int_mask, &ret);
|
||||
if (ret < 0) {
|
||||
BT_ERR("Unable to disable the host interrupt!");
|
||||
return -EIO;
|
||||
@ -150,7 +194,7 @@ static int btmrvl_sdio_poll_card_status(struct btmrvl_sdio_card *card, u8 bits)
|
||||
int ret;
|
||||
|
||||
for (tries = 0; tries < MAX_POLL_TRIES * 1000; tries++) {
|
||||
status = sdio_readb(card->func, CARD_STATUS_REG, &ret);
|
||||
status = sdio_readb(card->func, card->reg->card_status, &ret);
|
||||
if (ret)
|
||||
goto failed;
|
||||
if ((status & bits) == bits)
|
||||
@ -299,7 +343,7 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card)
|
||||
u8 base0, base1;
|
||||
void *tmpfwbuf = NULL;
|
||||
u8 *fwbuf;
|
||||
u16 len;
|
||||
u16 len, blksz_dl = card->sd_blksz_fw_dl;
|
||||
int txlen = 0, tx_blocks = 0, count = 0;
|
||||
|
||||
ret = request_firmware(&fw_firmware, card->firmware,
|
||||
@ -345,7 +389,7 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card)
|
||||
|
||||
for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
|
||||
base0 = sdio_readb(card->func,
|
||||
SQ_READ_BASE_ADDRESS_A0_REG, &ret);
|
||||
card->reg->sq_read_base_addr_a0, &ret);
|
||||
if (ret) {
|
||||
BT_ERR("BASE0 register read failed:"
|
||||
" base0 = 0x%04X(%d)."
|
||||
@ -355,7 +399,7 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card)
|
||||
goto done;
|
||||
}
|
||||
base1 = sdio_readb(card->func,
|
||||
SQ_READ_BASE_ADDRESS_A1_REG, &ret);
|
||||
card->reg->sq_read_base_addr_a1, &ret);
|
||||
if (ret) {
|
||||
BT_ERR("BASE1 register read failed:"
|
||||
" base1 = 0x%04X(%d)."
|
||||
@ -403,20 +447,19 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card)
|
||||
if (firmwarelen - offset < txlen)
|
||||
txlen = firmwarelen - offset;
|
||||
|
||||
tx_blocks =
|
||||
(txlen + SDIO_BLOCK_SIZE - 1) / SDIO_BLOCK_SIZE;
|
||||
tx_blocks = (txlen + blksz_dl - 1) / blksz_dl;
|
||||
|
||||
memcpy(fwbuf, &firmware[offset], txlen);
|
||||
}
|
||||
|
||||
ret = sdio_writesb(card->func, card->ioport, fwbuf,
|
||||
tx_blocks * SDIO_BLOCK_SIZE);
|
||||
tx_blocks * blksz_dl);
|
||||
|
||||
if (ret < 0) {
|
||||
BT_ERR("FW download, writesb(%d) failed @%d",
|
||||
count, offset);
|
||||
sdio_writeb(card->func, HOST_CMD53_FIN, CONFIG_REG,
|
||||
&ret);
|
||||
sdio_writeb(card->func, HOST_CMD53_FIN,
|
||||
card->reg->cfg, &ret);
|
||||
if (ret)
|
||||
BT_ERR("writeb failed (CFG)");
|
||||
}
|
||||
@ -597,7 +640,7 @@ static void btmrvl_sdio_interrupt(struct sdio_func *func)
|
||||
|
||||
priv = card->priv;
|
||||
|
||||
ireg = sdio_readb(card->func, HOST_INTSTATUS_REG, &ret);
|
||||
ireg = sdio_readb(card->func, card->reg->host_intstatus, &ret);
|
||||
if (ret) {
|
||||
BT_ERR("sdio_readb: read int status register failed");
|
||||
return;
|
||||
@ -613,7 +656,7 @@ static void btmrvl_sdio_interrupt(struct sdio_func *func)
|
||||
|
||||
sdio_writeb(card->func, ~(ireg) & (DN_LD_HOST_INT_STATUS |
|
||||
UP_LD_HOST_INT_STATUS),
|
||||
HOST_INTSTATUS_REG, &ret);
|
||||
card->reg->host_intstatus, &ret);
|
||||
if (ret) {
|
||||
BT_ERR("sdio_writeb: clear int status register failed");
|
||||
return;
|
||||
@ -664,7 +707,7 @@ static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card)
|
||||
goto release_irq;
|
||||
}
|
||||
|
||||
reg = sdio_readb(func, IO_PORT_0_REG, &ret);
|
||||
reg = sdio_readb(func, card->reg->io_port_0, &ret);
|
||||
if (ret < 0) {
|
||||
ret = -EIO;
|
||||
goto release_irq;
|
||||
@ -672,7 +715,7 @@ static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card)
|
||||
|
||||
card->ioport = reg;
|
||||
|
||||
reg = sdio_readb(func, IO_PORT_1_REG, &ret);
|
||||
reg = sdio_readb(func, card->reg->io_port_1, &ret);
|
||||
if (ret < 0) {
|
||||
ret = -EIO;
|
||||
goto release_irq;
|
||||
@ -680,7 +723,7 @@ static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card)
|
||||
|
||||
card->ioport |= (reg << 8);
|
||||
|
||||
reg = sdio_readb(func, IO_PORT_2_REG, &ret);
|
||||
reg = sdio_readb(func, card->reg->io_port_2, &ret);
|
||||
if (ret < 0) {
|
||||
ret = -EIO;
|
||||
goto release_irq;
|
||||
@ -815,6 +858,8 @@ exit:
|
||||
static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card)
|
||||
{
|
||||
int ret = 0;
|
||||
u8 fws0;
|
||||
int pollnum = MAX_POLL_TRIES;
|
||||
|
||||
if (!card || !card->func) {
|
||||
BT_ERR("card or function is NULL!");
|
||||
@ -827,20 +872,36 @@ static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card)
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = btmrvl_sdio_download_helper(card);
|
||||
/* Check if other function driver is downloading the firmware */
|
||||
fws0 = sdio_readb(card->func, card->reg->card_fw_status0, &ret);
|
||||
if (ret) {
|
||||
BT_ERR("Failed to download helper!");
|
||||
BT_ERR("Failed to read FW downloading status!");
|
||||
ret = -EIO;
|
||||
goto done;
|
||||
}
|
||||
if (fws0) {
|
||||
BT_DBG("BT not the winner (%#x). Skip FW downloading", fws0);
|
||||
|
||||
if (btmrvl_sdio_download_fw_w_helper(card)) {
|
||||
BT_ERR("Failed to download firmware!");
|
||||
ret = -EIO;
|
||||
goto done;
|
||||
/* Give other function more time to download the firmware */
|
||||
pollnum *= 10;
|
||||
} else {
|
||||
if (card->helper) {
|
||||
ret = btmrvl_sdio_download_helper(card);
|
||||
if (ret) {
|
||||
BT_ERR("Failed to download helper!");
|
||||
ret = -EIO;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if (btmrvl_sdio_download_fw_w_helper(card)) {
|
||||
BT_ERR("Failed to download firmware!");
|
||||
ret = -EIO;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if (btmrvl_sdio_verify_fw_download(card, MAX_POLL_TRIES)) {
|
||||
if (btmrvl_sdio_verify_fw_download(card, pollnum)) {
|
||||
BT_ERR("FW failed to be active in time!");
|
||||
ret = -ETIMEDOUT;
|
||||
goto done;
|
||||
@ -864,7 +925,7 @@ static int btmrvl_sdio_wakeup_fw(struct btmrvl_private *priv)
|
||||
|
||||
sdio_claim_host(card->func);
|
||||
|
||||
sdio_writeb(card->func, HOST_POWER_UP, CONFIG_REG, &ret);
|
||||
sdio_writeb(card->func, HOST_POWER_UP, card->reg->cfg, &ret);
|
||||
|
||||
sdio_release_host(card->func);
|
||||
|
||||
@ -893,8 +954,10 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
|
||||
|
||||
if (id->driver_data) {
|
||||
struct btmrvl_sdio_device *data = (void *) id->driver_data;
|
||||
card->helper = data->helper;
|
||||
card->helper = data->helper;
|
||||
card->firmware = data->firmware;
|
||||
card->reg = data->reg;
|
||||
card->sd_blksz_fw_dl = data->sd_blksz_fw_dl;
|
||||
}
|
||||
|
||||
if (btmrvl_sdio_register_dev(card) < 0) {
|
||||
@ -1011,3 +1074,4 @@ MODULE_VERSION(VERSION);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_FIRMWARE("sd8688_helper.bin");
|
||||
MODULE_FIRMWARE("sd8688.bin");
|
||||
MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin");
|
||||
|
@ -47,44 +47,46 @@
|
||||
/* Max retry number of CMD53 write */
|
||||
#define MAX_WRITE_IOMEM_RETRY 2
|
||||
|
||||
/* Host Control Registers */
|
||||
#define IO_PORT_0_REG 0x00
|
||||
#define IO_PORT_1_REG 0x01
|
||||
#define IO_PORT_2_REG 0x02
|
||||
/* register bitmasks */
|
||||
#define HOST_POWER_UP BIT(1)
|
||||
#define HOST_CMD53_FIN BIT(2)
|
||||
|
||||
#define CONFIG_REG 0x03
|
||||
#define HOST_POWER_UP BIT(1)
|
||||
#define HOST_CMD53_FIN BIT(2)
|
||||
#define HIM_DISABLE 0xff
|
||||
#define HIM_ENABLE (BIT(0) | BIT(1))
|
||||
|
||||
#define HOST_INT_MASK_REG 0x04
|
||||
#define HIM_DISABLE 0xff
|
||||
#define HIM_ENABLE (BIT(0) | BIT(1))
|
||||
#define UP_LD_HOST_INT_STATUS BIT(0)
|
||||
#define DN_LD_HOST_INT_STATUS BIT(1)
|
||||
|
||||
#define HOST_INTSTATUS_REG 0x05
|
||||
#define UP_LD_HOST_INT_STATUS BIT(0)
|
||||
#define DN_LD_HOST_INT_STATUS BIT(1)
|
||||
#define DN_LD_CARD_RDY BIT(0)
|
||||
#define CARD_IO_READY BIT(3)
|
||||
|
||||
/* Card Control Registers */
|
||||
#define SQ_READ_BASE_ADDRESS_A0_REG 0x10
|
||||
#define SQ_READ_BASE_ADDRESS_A1_REG 0x11
|
||||
#define FIRMWARE_READY 0xfedc
|
||||
|
||||
#define CARD_STATUS_REG 0x20
|
||||
#define DN_LD_CARD_RDY BIT(0)
|
||||
#define CARD_IO_READY BIT(3)
|
||||
|
||||
#define CARD_FW_STATUS0_REG 0x40
|
||||
#define CARD_FW_STATUS1_REG 0x41
|
||||
#define FIRMWARE_READY 0xfedc
|
||||
|
||||
#define CARD_RX_LEN_REG 0x42
|
||||
#define CARD_RX_UNIT_REG 0x43
|
||||
|
||||
struct btmrvl_sdio_card_reg {
|
||||
u8 cfg;
|
||||
u8 host_int_mask;
|
||||
u8 host_intstatus;
|
||||
u8 card_status;
|
||||
u8 sq_read_base_addr_a0;
|
||||
u8 sq_read_base_addr_a1;
|
||||
u8 card_revision;
|
||||
u8 card_fw_status0;
|
||||
u8 card_fw_status1;
|
||||
u8 card_rx_len;
|
||||
u8 card_rx_unit;
|
||||
u8 io_port_0;
|
||||
u8 io_port_1;
|
||||
u8 io_port_2;
|
||||
};
|
||||
|
||||
struct btmrvl_sdio_card {
|
||||
struct sdio_func *func;
|
||||
u32 ioport;
|
||||
const char *helper;
|
||||
const char *firmware;
|
||||
const struct btmrvl_sdio_card_reg *reg;
|
||||
u16 sd_blksz_fw_dl;
|
||||
u8 rx_unit;
|
||||
struct btmrvl_private *priv;
|
||||
};
|
||||
@ -92,6 +94,8 @@ struct btmrvl_sdio_card {
|
||||
struct btmrvl_sdio_device {
|
||||
const char *helper;
|
||||
const char *firmware;
|
||||
const struct btmrvl_sdio_card_reg *reg;
|
||||
u16 sd_blksz_fw_dl;
|
||||
};
|
||||
|
||||
|
||||
|
@ -201,8 +201,13 @@ static struct sk_buff *ath_dequeue(struct hci_uart *hu)
|
||||
/* Recv data */
|
||||
static int ath_recv(struct hci_uart *hu, void *data, int count)
|
||||
{
|
||||
if (hci_recv_stream_fragment(hu->hdev, data, count) < 0)
|
||||
int ret;
|
||||
|
||||
ret = hci_recv_stream_fragment(hu->hdev, data, count);
|
||||
if (ret < 0) {
|
||||
BT_ERR("Frame Reassembly Failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
@ -151,8 +151,13 @@ static inline int h4_check_data_len(struct h4_struct *h4, int len)
|
||||
/* Recv data */
|
||||
static int h4_recv(struct hci_uart *hu, void *data, int count)
|
||||
{
|
||||
if (hci_recv_stream_fragment(hu->hdev, data, count) < 0)
|
||||
int ret;
|
||||
|
||||
ret = hci_recv_stream_fragment(hu->hdev, data, count);
|
||||
if (ret < 0) {
|
||||
BT_ERR("Frame Reassembly Failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
@ -359,6 +359,7 @@ static void hci_uart_tty_wakeup(struct tty_struct *tty)
|
||||
*/
|
||||
static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *flags, int count)
|
||||
{
|
||||
int ret;
|
||||
struct hci_uart *hu = (void *)tty->disc_data;
|
||||
|
||||
if (!hu || tty != hu->tty)
|
||||
@ -368,8 +369,9 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *f
|
||||
return;
|
||||
|
||||
spin_lock(&hu->rx_lock);
|
||||
hu->proto->recv(hu, (void *) data, count);
|
||||
hu->hdev->stat.byte_rx += count;
|
||||
ret = hu->proto->recv(hu, (void *) data, count);
|
||||
if (ret > 0)
|
||||
hu->hdev->stat.byte_rx += count;
|
||||
spin_unlock(&hu->rx_lock);
|
||||
|
||||
tty_unthrottle(tty);
|
||||
|
@ -276,10 +276,52 @@ struct l2cap_conn_param_update_rsp {
|
||||
#define L2CAP_CONN_PARAM_ACCEPTED 0x0000
|
||||
#define L2CAP_CONN_PARAM_REJECTED 0x0001
|
||||
|
||||
/* ----- L2CAP connections ----- */
|
||||
struct l2cap_chan_list {
|
||||
struct sock *head;
|
||||
rwlock_t lock;
|
||||
/* ----- L2CAP channels and connections ----- */
|
||||
struct srej_list {
|
||||
__u8 tx_seq;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
struct l2cap_chan {
|
||||
struct sock *sk;
|
||||
__u8 ident;
|
||||
|
||||
__u8 conf_req[64];
|
||||
__u8 conf_len;
|
||||
__u8 num_conf_req;
|
||||
__u8 num_conf_rsp;
|
||||
|
||||
__u16 conn_state;
|
||||
|
||||
__u8 next_tx_seq;
|
||||
__u8 expected_ack_seq;
|
||||
__u8 expected_tx_seq;
|
||||
__u8 buffer_seq;
|
||||
__u8 buffer_seq_srej;
|
||||
__u8 srej_save_reqseq;
|
||||
__u8 frames_sent;
|
||||
__u8 unacked_frames;
|
||||
__u8 retry_count;
|
||||
__u8 num_acked;
|
||||
__u16 sdu_len;
|
||||
__u16 partial_sdu_len;
|
||||
struct sk_buff *sdu;
|
||||
|
||||
__u8 remote_tx_win;
|
||||
__u8 remote_max_tx;
|
||||
__u16 remote_mps;
|
||||
|
||||
struct timer_list retrans_timer;
|
||||
struct timer_list monitor_timer;
|
||||
struct timer_list ack_timer;
|
||||
struct sk_buff *tx_send_head;
|
||||
struct sk_buff_head tx_q;
|
||||
struct sk_buff_head srej_q;
|
||||
struct sk_buff_head busy_q;
|
||||
struct work_struct busy_work;
|
||||
struct list_head srej_l;
|
||||
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
struct l2cap_conn {
|
||||
@ -305,29 +347,16 @@ struct l2cap_conn {
|
||||
|
||||
__u8 disc_reason;
|
||||
|
||||
struct l2cap_chan_list chan_list;
|
||||
};
|
||||
|
||||
struct sock_del_list {
|
||||
struct sock *sk;
|
||||
struct list_head list;
|
||||
struct list_head chan_l;
|
||||
rwlock_t chan_lock;
|
||||
};
|
||||
|
||||
#define L2CAP_INFO_CL_MTU_REQ_SENT 0x01
|
||||
#define L2CAP_INFO_FEAT_MASK_REQ_SENT 0x04
|
||||
#define L2CAP_INFO_FEAT_MASK_REQ_DONE 0x08
|
||||
|
||||
/* ----- L2CAP channel and socket info ----- */
|
||||
/* ----- L2CAP socket info ----- */
|
||||
#define l2cap_pi(sk) ((struct l2cap_pinfo *) sk)
|
||||
#define TX_QUEUE(sk) (&l2cap_pi(sk)->tx_queue)
|
||||
#define SREJ_QUEUE(sk) (&l2cap_pi(sk)->srej_queue)
|
||||
#define BUSY_QUEUE(sk) (&l2cap_pi(sk)->busy_queue)
|
||||
#define SREJ_LIST(sk) (&l2cap_pi(sk)->srej_l.list)
|
||||
|
||||
struct srej_list {
|
||||
__u8 tx_seq;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
struct l2cap_pinfo {
|
||||
struct bt_sock bt;
|
||||
@ -339,8 +368,6 @@ struct l2cap_pinfo {
|
||||
__u16 omtu;
|
||||
__u16 flush_to;
|
||||
__u8 mode;
|
||||
__u8 num_conf_req;
|
||||
__u8 num_conf_rsp;
|
||||
|
||||
__u8 fcs;
|
||||
__u8 sec_level;
|
||||
@ -348,49 +375,18 @@ struct l2cap_pinfo {
|
||||
__u8 force_reliable;
|
||||
__u8 flushable;
|
||||
|
||||
__u8 conf_req[64];
|
||||
__u8 conf_len;
|
||||
__u8 conf_state;
|
||||
__u16 conn_state;
|
||||
|
||||
__u8 next_tx_seq;
|
||||
__u8 expected_ack_seq;
|
||||
__u8 expected_tx_seq;
|
||||
__u8 buffer_seq;
|
||||
__u8 buffer_seq_srej;
|
||||
__u8 srej_save_reqseq;
|
||||
__u8 frames_sent;
|
||||
__u8 unacked_frames;
|
||||
__u8 retry_count;
|
||||
__u8 num_acked;
|
||||
__u16 sdu_len;
|
||||
__u16 partial_sdu_len;
|
||||
struct sk_buff *sdu;
|
||||
|
||||
__u8 ident;
|
||||
|
||||
__u8 tx_win;
|
||||
__u8 max_tx;
|
||||
__u8 remote_tx_win;
|
||||
__u8 remote_max_tx;
|
||||
__u16 retrans_timeout;
|
||||
__u16 monitor_timeout;
|
||||
__u16 remote_mps;
|
||||
__u16 mps;
|
||||
|
||||
__le16 sport;
|
||||
|
||||
struct timer_list retrans_timer;
|
||||
struct timer_list monitor_timer;
|
||||
struct timer_list ack_timer;
|
||||
struct sk_buff_head tx_queue;
|
||||
struct sk_buff_head srej_queue;
|
||||
struct sk_buff_head busy_queue;
|
||||
struct work_struct busy_work;
|
||||
struct srej_list srej_l;
|
||||
struct l2cap_conn *conn;
|
||||
struct sock *next_c;
|
||||
struct sock *prev_c;
|
||||
struct l2cap_chan *chan;
|
||||
};
|
||||
|
||||
#define L2CAP_CONF_REQ_SENT 0x01
|
||||
@ -417,24 +413,23 @@ struct l2cap_pinfo {
|
||||
#define L2CAP_CONN_RNR_SENT 0x0200
|
||||
#define L2CAP_CONN_SAR_RETRY 0x0400
|
||||
|
||||
#define __mod_retrans_timer() mod_timer(&l2cap_pi(sk)->retrans_timer, \
|
||||
#define __mod_retrans_timer() mod_timer(&chan->retrans_timer, \
|
||||
jiffies + msecs_to_jiffies(L2CAP_DEFAULT_RETRANS_TO));
|
||||
#define __mod_monitor_timer() mod_timer(&l2cap_pi(sk)->monitor_timer, \
|
||||
#define __mod_monitor_timer() mod_timer(&chan->monitor_timer, \
|
||||
jiffies + msecs_to_jiffies(L2CAP_DEFAULT_MONITOR_TO));
|
||||
#define __mod_ack_timer() mod_timer(&l2cap_pi(sk)->ack_timer, \
|
||||
#define __mod_ack_timer() mod_timer(&chan->ack_timer, \
|
||||
jiffies + msecs_to_jiffies(L2CAP_DEFAULT_ACK_TO));
|
||||
|
||||
static inline int l2cap_tx_window_full(struct sock *sk)
|
||||
static inline int l2cap_tx_window_full(struct l2cap_chan *ch)
|
||||
{
|
||||
struct l2cap_pinfo *pi = l2cap_pi(sk);
|
||||
int sub;
|
||||
|
||||
sub = (pi->next_tx_seq - pi->expected_ack_seq) % 64;
|
||||
sub = (ch->next_tx_seq - ch->expected_ack_seq) % 64;
|
||||
|
||||
if (sub < 0)
|
||||
sub += 64;
|
||||
|
||||
return sub == pi->remote_tx_win;
|
||||
return sub == ch->remote_tx_win;
|
||||
}
|
||||
|
||||
#define __get_txseq(ctrl) (((ctrl) & L2CAP_CTRL_TXSEQ) >> 1)
|
||||
@ -450,18 +445,17 @@ extern struct bt_sock_list l2cap_sk_list;
|
||||
int l2cap_init_sockets(void);
|
||||
void l2cap_cleanup_sockets(void);
|
||||
|
||||
u8 l2cap_get_ident(struct l2cap_conn *conn);
|
||||
void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data);
|
||||
int l2cap_build_conf_req(struct sock *sk, void *data);
|
||||
void __l2cap_connect_rsp_defer(struct sock *sk);
|
||||
int __l2cap_wait_ack(struct sock *sk);
|
||||
|
||||
struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr *msg, size_t len);
|
||||
struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *msg, size_t len);
|
||||
struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, size_t len, u16 control, u16 sdulen);
|
||||
int l2cap_sar_segment_sdu(struct sock *sk, struct msghdr *msg, size_t len);
|
||||
int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len);
|
||||
void l2cap_do_send(struct sock *sk, struct sk_buff *skb);
|
||||
void l2cap_streaming_send(struct sock *sk);
|
||||
int l2cap_ertm_send(struct sock *sk);
|
||||
void l2cap_streaming_send(struct l2cap_chan *chan);
|
||||
int l2cap_ertm_send(struct l2cap_chan *chan);
|
||||
|
||||
void l2cap_sock_set_timer(struct sock *sk, long timeout);
|
||||
void l2cap_sock_clear_timer(struct sock *sk);
|
||||
@ -470,8 +464,8 @@ void l2cap_sock_kill(struct sock *sk);
|
||||
void l2cap_sock_init(struct sock *sk, struct sock *parent);
|
||||
struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
|
||||
int proto, gfp_t prio);
|
||||
void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int err);
|
||||
void l2cap_chan_del(struct sock *sk, int err);
|
||||
void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err);
|
||||
void l2cap_chan_del(struct l2cap_chan *chan, int err);
|
||||
int l2cap_do_connect(struct sock *sk);
|
||||
|
||||
#endif /* __L2CAP_H */
|
||||
|
@ -2497,6 +2497,9 @@ static inline void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
if (!test_bit(HCI_MGMT, &hdev->flags))
|
||||
goto unlock;
|
||||
|
||||
data = hci_find_remote_oob_data(hdev, &ev->bdaddr);
|
||||
if (data) {
|
||||
struct hci_cp_remote_oob_data_reply cp;
|
||||
@ -2515,6 +2518,7 @@ static inline void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
|
||||
&cp);
|
||||
}
|
||||
|
||||
unlock:
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -269,7 +269,7 @@ static int l2cap_sock_listen(struct socket *sock, int backlog)
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!l2cap_pi(sk)->psm && !l2cap_pi(sk)->dcid) {
|
||||
if (!l2cap_pi(sk)->psm && !l2cap_pi(sk)->scid) {
|
||||
bdaddr_t *src = &bt_sk(sk)->src;
|
||||
u16 psm;
|
||||
|
||||
@ -757,36 +757,38 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
|
||||
case L2CAP_MODE_ERTM:
|
||||
case L2CAP_MODE_STREAMING:
|
||||
/* Entire SDU fits into one PDU */
|
||||
if (len <= pi->remote_mps) {
|
||||
if (len <= pi->chan->remote_mps) {
|
||||
control = L2CAP_SDU_UNSEGMENTED;
|
||||
skb = l2cap_create_iframe_pdu(sk, msg, len, control, 0);
|
||||
if (IS_ERR(skb)) {
|
||||
err = PTR_ERR(skb);
|
||||
goto done;
|
||||
}
|
||||
__skb_queue_tail(TX_QUEUE(sk), skb);
|
||||
__skb_queue_tail(&pi->chan->tx_q, skb);
|
||||
|
||||
if (sk->sk_send_head == NULL)
|
||||
sk->sk_send_head = skb;
|
||||
if (pi->chan->tx_send_head == NULL)
|
||||
pi->chan->tx_send_head = skb;
|
||||
|
||||
} else {
|
||||
/* Segment SDU into multiples PDUs */
|
||||
err = l2cap_sar_segment_sdu(sk, msg, len);
|
||||
err = l2cap_sar_segment_sdu(pi->chan, msg, len);
|
||||
if (err < 0)
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (pi->mode == L2CAP_MODE_STREAMING) {
|
||||
l2cap_streaming_send(sk);
|
||||
} else {
|
||||
if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
|
||||
(pi->conn_state & L2CAP_CONN_WAIT_F)) {
|
||||
err = len;
|
||||
break;
|
||||
}
|
||||
err = l2cap_ertm_send(sk);
|
||||
l2cap_streaming_send(pi->chan);
|
||||
err = len;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((pi->chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
|
||||
(pi->chan->conn_state & L2CAP_CONN_WAIT_F)) {
|
||||
err = len;
|
||||
break;
|
||||
}
|
||||
err = l2cap_ertm_send(pi->chan);
|
||||
|
||||
if (err >= 0)
|
||||
err = len;
|
||||
break;
|
||||
@ -808,29 +810,7 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms
|
||||
lock_sock(sk);
|
||||
|
||||
if (sk->sk_state == BT_CONNECT2 && bt_sk(sk)->defer_setup) {
|
||||
struct l2cap_conn_rsp rsp;
|
||||
struct l2cap_conn *conn = l2cap_pi(sk)->conn;
|
||||
u8 buf[128];
|
||||
|
||||
sk->sk_state = BT_CONFIG;
|
||||
|
||||
rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid);
|
||||
rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
|
||||
rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
|
||||
rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
|
||||
l2cap_send_cmd(l2cap_pi(sk)->conn, l2cap_pi(sk)->ident,
|
||||
L2CAP_CONN_RSP, sizeof(rsp), &rsp);
|
||||
|
||||
if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) {
|
||||
release_sock(sk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
|
||||
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
|
||||
l2cap_build_conf_req(sk, buf), buf);
|
||||
l2cap_pi(sk)->num_conf_req++;
|
||||
|
||||
__l2cap_connect_rsp_defer(sk);
|
||||
release_sock(sk);
|
||||
return 0;
|
||||
}
|
||||
@ -886,6 +866,7 @@ static void l2cap_sock_cleanup_listen(struct sock *parent)
|
||||
void __l2cap_sock_close(struct sock *sk, int reason)
|
||||
{
|
||||
struct l2cap_conn *conn = l2cap_pi(sk)->conn;
|
||||
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
|
||||
|
||||
BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket);
|
||||
|
||||
@ -900,9 +881,9 @@ void __l2cap_sock_close(struct sock *sk, int reason)
|
||||
sk->sk_type == SOCK_STREAM) &&
|
||||
conn->hcon->type == ACL_LINK) {
|
||||
l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
|
||||
l2cap_send_disconn_req(conn, sk, reason);
|
||||
l2cap_send_disconn_req(conn, chan, reason);
|
||||
} else
|
||||
l2cap_chan_del(sk, reason);
|
||||
l2cap_chan_del(chan, reason);
|
||||
break;
|
||||
|
||||
case BT_CONNECT2:
|
||||
@ -921,16 +902,16 @@ void __l2cap_sock_close(struct sock *sk, int reason)
|
||||
rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
|
||||
rsp.result = cpu_to_le16(result);
|
||||
rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
|
||||
l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
|
||||
L2CAP_CONN_RSP, sizeof(rsp), &rsp);
|
||||
l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
|
||||
sizeof(rsp), &rsp);
|
||||
}
|
||||
|
||||
l2cap_chan_del(sk, reason);
|
||||
l2cap_chan_del(chan, reason);
|
||||
break;
|
||||
|
||||
case BT_CONNECT:
|
||||
case BT_DISCONN:
|
||||
l2cap_chan_del(sk, reason);
|
||||
l2cap_chan_del(chan, reason);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -1035,12 +1016,7 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent)
|
||||
}
|
||||
|
||||
/* Default config options */
|
||||
pi->conf_len = 0;
|
||||
pi->flush_to = L2CAP_DEFAULT_FLUSH_TO;
|
||||
skb_queue_head_init(TX_QUEUE(sk));
|
||||
skb_queue_head_init(SREJ_QUEUE(sk));
|
||||
skb_queue_head_init(BUSY_QUEUE(sk));
|
||||
INIT_LIST_HEAD(SREJ_LIST(sk));
|
||||
}
|
||||
|
||||
static struct proto l2cap_proto = {
|
||||
|
Loading…
Reference in New Issue
Block a user