Browse Source

Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/padovan/bluetooth-next-2.6

John W. Linville 14 years ago
parent
commit
bb411b4db2

+ 2 - 2
drivers/bluetooth/Kconfig

@@ -188,7 +188,7 @@ config BT_MRVL
 	  The core driver to support Marvell Bluetooth devices.
 	  The core driver to support Marvell Bluetooth devices.
 
 
 	  This driver is required if you want to support
 	  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
 	  Say Y here to compile Marvell Bluetooth driver
 	  into the kernel or say M to compile it as module.
 	  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.
 	  The driver for Marvell Bluetooth chipsets with SDIO interface.
 
 
 	  This driver is required if you want to use Marvell Bluetooth
 	  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.
 	  supported.
 
 
 	  Say Y here to compile support for Marvell BT-over-SDIO driver
 	  Say Y here to compile support for Marvell BT-over-SDIO driver

+ 0 - 3
drivers/bluetooth/ath3k.c

@@ -138,9 +138,6 @@ static int ath3k_load_firmware(struct usb_device *udev,
 		count -= size;
 		count -= size;
 	}
 	}
 
 
-	kfree(send_buf);
-	return 0;
-
 error:
 error:
 	kfree(send_buf);
 	kfree(send_buf);
 	return err;
 	return err;

+ 94 - 30
drivers/bluetooth/btmrvl_sdio.c

@@ -49,15 +49,59 @@
 static u8 user_rmmod;
 static u8 user_rmmod;
 static u8 sdio_ireg;
 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 = {
 static const struct btmrvl_sdio_device btmrvl_sdio_sd6888 = {
 	.helper		= "sd8688_helper.bin",
 	.helper		= "sd8688_helper.bin",
 	.firmware	= "sd8688.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[] = {
 static const struct sdio_device_id btmrvl_sdio_ids[] = {
 	/* Marvell SD8688 Bluetooth device */
 	/* Marvell SD8688 Bluetooth device */
 	{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9105),
 	{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9105),
 			.driver_data = (unsigned long) &btmrvl_sdio_sd6888 },
 			.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 */
 	{ }	/* Terminating entry */
 };
 };
@@ -69,7 +113,7 @@ static int btmrvl_sdio_get_rx_unit(struct btmrvl_sdio_card *card)
 	u8 reg;
 	u8 reg;
 	int ret;
 	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)
 	if (!ret)
 		card->rx_unit = reg;
 		card->rx_unit = reg;
 
 
@@ -83,11 +127,11 @@ static int btmrvl_sdio_read_fw_status(struct btmrvl_sdio_card *card, u16 *dat)
 
 
 	*dat = 0;
 	*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)
 	if (ret)
 		return -EIO;
 		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)
 	if (ret)
 		return -EIO;
 		return -EIO;
 
 
@@ -101,7 +145,7 @@ static int btmrvl_sdio_read_rx_len(struct btmrvl_sdio_card *card, u16 *dat)
 	u8 reg;
 	u8 reg;
 	int ret;
 	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)
 	if (!ret)
 		*dat = (u16) reg << card->rx_unit;
 		*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;
 	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) {
 	if (ret) {
 		BT_ERR("Unable to enable the host interrupt!");
 		BT_ERR("Unable to enable the host interrupt!");
 		ret = -EIO;
 		ret = -EIO;
@@ -128,13 +172,13 @@ static int btmrvl_sdio_disable_host_int_mask(struct btmrvl_sdio_card *card,
 	u8 host_int_mask;
 	u8 host_int_mask;
 	int ret;
 	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)
 	if (ret)
 		return -EIO;
 		return -EIO;
 
 
 	host_int_mask &= ~mask;
 	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) {
 	if (ret < 0) {
 		BT_ERR("Unable to disable the host interrupt!");
 		BT_ERR("Unable to disable the host interrupt!");
 		return -EIO;
 		return -EIO;
@@ -150,7 +194,7 @@ static int btmrvl_sdio_poll_card_status(struct btmrvl_sdio_card *card, u8 bits)
 	int ret;
 	int ret;
 
 
 	for (tries = 0; tries < MAX_POLL_TRIES * 1000; tries++) {
 	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)
 		if (ret)
 			goto failed;
 			goto failed;
 		if ((status & bits) == bits)
 		if ((status & bits) == bits)
@@ -299,7 +343,7 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card)
 	u8 base0, base1;
 	u8 base0, base1;
 	void *tmpfwbuf = NULL;
 	void *tmpfwbuf = NULL;
 	u8 *fwbuf;
 	u8 *fwbuf;
-	u16 len;
+	u16 len, blksz_dl = card->sd_blksz_fw_dl;
 	int txlen = 0, tx_blocks = 0, count = 0;
 	int txlen = 0, tx_blocks = 0, count = 0;
 
 
 	ret = request_firmware(&fw_firmware, card->firmware,
 	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++) {
 		for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
 			base0 = sdio_readb(card->func,
 			base0 = sdio_readb(card->func,
-					SQ_READ_BASE_ADDRESS_A0_REG, &ret);
+					card->reg->sq_read_base_addr_a0, &ret);
 			if (ret) {
 			if (ret) {
 				BT_ERR("BASE0 register read failed:"
 				BT_ERR("BASE0 register read failed:"
 					" base0 = 0x%04X(%d)."
 					" base0 = 0x%04X(%d)."
@@ -355,7 +399,7 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card)
 				goto done;
 				goto done;
 			}
 			}
 			base1 = sdio_readb(card->func,
 			base1 = sdio_readb(card->func,
-					SQ_READ_BASE_ADDRESS_A1_REG, &ret);
+					card->reg->sq_read_base_addr_a1, &ret);
 			if (ret) {
 			if (ret) {
 				BT_ERR("BASE1 register read failed:"
 				BT_ERR("BASE1 register read failed:"
 					" base1 = 0x%04X(%d)."
 					" 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)
 			if (firmwarelen - offset < txlen)
 				txlen = firmwarelen - offset;
 				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);
 			memcpy(fwbuf, &firmware[offset], txlen);
 		}
 		}
 
 
 		ret = sdio_writesb(card->func, card->ioport, fwbuf,
 		ret = sdio_writesb(card->func, card->ioport, fwbuf,
-					tx_blocks * SDIO_BLOCK_SIZE);
+						tx_blocks * blksz_dl);
 
 
 		if (ret < 0) {
 		if (ret < 0) {
 			BT_ERR("FW download, writesb(%d) failed @%d",
 			BT_ERR("FW download, writesb(%d) failed @%d",
 							count, offset);
 							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)
 			if (ret)
 				BT_ERR("writeb failed (CFG)");
 				BT_ERR("writeb failed (CFG)");
 		}
 		}
@@ -597,7 +640,7 @@ static void btmrvl_sdio_interrupt(struct sdio_func *func)
 
 
 	priv = card->priv;
 	priv = card->priv;
 
 
-	ireg = sdio_readb(card->func, HOST_INTSTATUS_REG, &ret);
+	ireg = sdio_readb(card->func, card->reg->host_intstatus, &ret);
 	if (ret) {
 	if (ret) {
 		BT_ERR("sdio_readb: read int status register failed");
 		BT_ERR("sdio_readb: read int status register failed");
 		return;
 		return;
@@ -613,7 +656,7 @@ static void btmrvl_sdio_interrupt(struct sdio_func *func)
 
 
 		sdio_writeb(card->func, ~(ireg) & (DN_LD_HOST_INT_STATUS |
 		sdio_writeb(card->func, ~(ireg) & (DN_LD_HOST_INT_STATUS |
 					UP_LD_HOST_INT_STATUS),
 					UP_LD_HOST_INT_STATUS),
-				HOST_INTSTATUS_REG, &ret);
+				card->reg->host_intstatus, &ret);
 		if (ret) {
 		if (ret) {
 			BT_ERR("sdio_writeb: clear int status register failed");
 			BT_ERR("sdio_writeb: clear int status register failed");
 			return;
 			return;
@@ -664,7 +707,7 @@ static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card)
 		goto release_irq;
 		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) {
 	if (ret < 0) {
 		ret = -EIO;
 		ret = -EIO;
 		goto release_irq;
 		goto release_irq;
@@ -672,7 +715,7 @@ static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card)
 
 
 	card->ioport = reg;
 	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) {
 	if (ret < 0) {
 		ret = -EIO;
 		ret = -EIO;
 		goto release_irq;
 		goto release_irq;
@@ -680,7 +723,7 @@ static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card)
 
 
 	card->ioport |= (reg << 8);
 	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) {
 	if (ret < 0) {
 		ret = -EIO;
 		ret = -EIO;
 		goto release_irq;
 		goto release_irq;
@@ -815,6 +858,8 @@ exit:
 static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card)
 static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card)
 {
 {
 	int ret = 0;
 	int ret = 0;
+	u8 fws0;
+	int pollnum = MAX_POLL_TRIES;
 
 
 	if (!card || !card->func) {
 	if (!card || !card->func) {
 		BT_ERR("card or function is NULL!");
 		BT_ERR("card or function is NULL!");
@@ -827,20 +872,36 @@ static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card)
 		goto done;
 		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) {
 	if (ret) {
-		BT_ERR("Failed to download helper!");
+		BT_ERR("Failed to read FW downloading status!");
 		ret = -EIO;
 		ret = -EIO;
 		goto done;
 		goto done;
 	}
 	}
+	if (fws0) {
+		BT_DBG("BT not the winner (%#x). Skip FW downloading", fws0);
+
+		/* 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_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!");
 		BT_ERR("FW failed to be active in time!");
 		ret = -ETIMEDOUT;
 		ret = -ETIMEDOUT;
 		goto done;
 		goto done;
@@ -864,7 +925,7 @@ static int btmrvl_sdio_wakeup_fw(struct btmrvl_private *priv)
 
 
 	sdio_claim_host(card->func);
 	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);
 	sdio_release_host(card->func);
 
 
@@ -893,8 +954,10 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
 
 
 	if (id->driver_data) {
 	if (id->driver_data) {
 		struct btmrvl_sdio_device *data = (void *) 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->firmware = data->firmware;
+		card->reg = data->reg;
+		card->sd_blksz_fw_dl = data->sd_blksz_fw_dl;
 	}
 	}
 
 
 	if (btmrvl_sdio_register_dev(card) < 0) {
 	if (btmrvl_sdio_register_dev(card) < 0) {
@@ -1011,3 +1074,4 @@ MODULE_VERSION(VERSION);
 MODULE_LICENSE("GPL v2");
 MODULE_LICENSE("GPL v2");
 MODULE_FIRMWARE("sd8688_helper.bin");
 MODULE_FIRMWARE("sd8688_helper.bin");
 MODULE_FIRMWARE("sd8688.bin");
 MODULE_FIRMWARE("sd8688.bin");
+MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin");

+ 36 - 32
drivers/bluetooth/btmrvl_sdio.h

@@ -47,44 +47,46 @@
 /* Max retry number of CMD53 write */
 /* Max retry number of CMD53 write */
 #define MAX_WRITE_IOMEM_RETRY		2
 #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
-
-#define CONFIG_REG			0x03
-#define HOST_POWER_UP			BIT(1)
-#define HOST_CMD53_FIN			BIT(2)
-
-#define HOST_INT_MASK_REG		0x04
-#define HIM_DISABLE			0xff
-#define HIM_ENABLE			(BIT(0) | BIT(1))
-
-#define HOST_INTSTATUS_REG		0x05
-#define UP_LD_HOST_INT_STATUS		BIT(0)
-#define DN_LD_HOST_INT_STATUS		BIT(1)
-
-/* Card Control Registers */
-#define SQ_READ_BASE_ADDRESS_A0_REG  	0x10
-#define SQ_READ_BASE_ADDRESS_A1_REG  	0x11
-
-#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
-
+/* register bitmasks */
+#define HOST_POWER_UP				BIT(1)
+#define HOST_CMD53_FIN				BIT(2)
+
+#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 DN_LD_CARD_RDY				BIT(0)
+#define CARD_IO_READY				BIT(3)
+
+#define FIRMWARE_READY				0xfedc
+
+
+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 btmrvl_sdio_card {
 	struct sdio_func *func;
 	struct sdio_func *func;
 	u32 ioport;
 	u32 ioport;
 	const char *helper;
 	const char *helper;
 	const char *firmware;
 	const char *firmware;
+	const struct btmrvl_sdio_card_reg *reg;
+	u16 sd_blksz_fw_dl;
 	u8 rx_unit;
 	u8 rx_unit;
 	struct btmrvl_private *priv;
 	struct btmrvl_private *priv;
 };
 };
@@ -92,6 +94,8 @@ struct btmrvl_sdio_card {
 struct btmrvl_sdio_device {
 struct btmrvl_sdio_device {
 	const char *helper;
 	const char *helper;
 	const char *firmware;
 	const char *firmware;
+	const struct btmrvl_sdio_card_reg *reg;
+	u16 sd_blksz_fw_dl;
 };
 };
 
 
 
 

+ 6 - 1
drivers/bluetooth/hci_ath.c

@@ -201,8 +201,13 @@ static struct sk_buff *ath_dequeue(struct hci_uart *hu)
 /* Recv data */
 /* Recv data */
 static int ath_recv(struct hci_uart *hu, void *data, int count)
 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");
 		BT_ERR("Frame Reassembly Failed");
+		return ret;
+	}
 
 
 	return count;
 	return count;
 }
 }

+ 6 - 1
drivers/bluetooth/hci_h4.c

@@ -151,8 +151,13 @@ static inline int h4_check_data_len(struct h4_struct *h4, int len)
 /* Recv data */
 /* Recv data */
 static int h4_recv(struct hci_uart *hu, void *data, int count)
 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");
 		BT_ERR("Frame Reassembly Failed");
+		return ret;
+	}
 
 
 	return count;
 	return count;
 }
 }

+ 4 - 2
drivers/bluetooth/hci_ldisc.c

@@ -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)
 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;
 	struct hci_uart *hu = (void *)tty->disc_data;
 
 
 	if (!hu || tty != hu->tty)
 	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;
 		return;
 
 
 	spin_lock(&hu->rx_lock);
 	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);
 	spin_unlock(&hu->rx_lock);
 
 
 	tty_unthrottle(tty);
 	tty_unthrottle(tty);

+ 62 - 68
include/net/bluetooth/l2cap.h

@@ -276,10 +276,52 @@ struct l2cap_conn_param_update_rsp {
 #define L2CAP_CONN_PARAM_ACCEPTED	0x0000
 #define L2CAP_CONN_PARAM_ACCEPTED	0x0000
 #define L2CAP_CONN_PARAM_REJECTED	0x0001
 #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 {
 struct l2cap_conn {
@@ -305,29 +347,16 @@ struct l2cap_conn {
 
 
 	__u8		disc_reason;
 	__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_CL_MTU_REQ_SENT	0x01
 #define L2CAP_INFO_FEAT_MASK_REQ_SENT	0x04
 #define L2CAP_INFO_FEAT_MASK_REQ_SENT	0x04
 #define L2CAP_INFO_FEAT_MASK_REQ_DONE	0x08
 #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 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 l2cap_pinfo {
 	struct bt_sock	bt;
 	struct bt_sock	bt;
@@ -339,8 +368,6 @@ struct l2cap_pinfo {
 	__u16		omtu;
 	__u16		omtu;
 	__u16		flush_to;
 	__u16		flush_to;
 	__u8		mode;
 	__u8		mode;
-	__u8		num_conf_req;
-	__u8		num_conf_rsp;
 
 
 	__u8		fcs;
 	__u8		fcs;
 	__u8		sec_level;
 	__u8		sec_level;
@@ -348,49 +375,18 @@ struct l2cap_pinfo {
 	__u8		force_reliable;
 	__u8		force_reliable;
 	__u8		flushable;
 	__u8		flushable;
 
 
-	__u8		conf_req[64];
-	__u8		conf_len;
 	__u8		conf_state;
 	__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		tx_win;
 	__u8		max_tx;
 	__u8		max_tx;
-	__u8		remote_tx_win;
-	__u8		remote_max_tx;
 	__u16		retrans_timeout;
 	__u16		retrans_timeout;
 	__u16		monitor_timeout;
 	__u16		monitor_timeout;
-	__u16		remote_mps;
 	__u16		mps;
 	__u16		mps;
 
 
 	__le16		sport;
 	__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 l2cap_conn	*conn;
-	struct sock		*next_c;
-	struct sock		*prev_c;
+	struct l2cap_chan	*chan;
 };
 };
 
 
 #define L2CAP_CONF_REQ_SENT       0x01
 #define L2CAP_CONF_REQ_SENT       0x01
@@ -417,24 +413,23 @@ struct l2cap_pinfo {
 #define L2CAP_CONN_RNR_SENT        0x0200
 #define L2CAP_CONN_RNR_SENT        0x0200
 #define L2CAP_CONN_SAR_RETRY       0x0400
 #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));
 		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));
 		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));
 		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;
 	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)
 	if (sub < 0)
 		sub += 64;
 		sub += 64;
 
 
-	return sub == pi->remote_tx_win;
+	return sub == ch->remote_tx_win;
 }
 }
 
 
 #define __get_txseq(ctrl)	(((ctrl) & L2CAP_CTRL_TXSEQ) >> 1)
 #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);
 int l2cap_init_sockets(void);
 void l2cap_cleanup_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);
 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);
 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_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_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);
 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_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_set_timer(struct sock *sk, long timeout);
 void l2cap_sock_clear_timer(struct sock *sk);
 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);
 void l2cap_sock_init(struct sock *sk, struct sock *parent);
 struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
 struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
 							int proto, gfp_t prio);
 							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);
 int l2cap_do_connect(struct sock *sk);
 
 
 #endif /* __L2CAP_H */
 #endif /* __L2CAP_H */

+ 4 - 0
net/bluetooth/hci_event.c

@@ -2497,6 +2497,9 @@ static inline void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
 
 
 	hci_dev_lock(hdev);
 	hci_dev_lock(hdev);
 
 
+	if (!test_bit(HCI_MGMT, &hdev->flags))
+		goto unlock;
+
 	data = hci_find_remote_oob_data(hdev, &ev->bdaddr);
 	data = hci_find_remote_oob_data(hdev, &ev->bdaddr);
 	if (data) {
 	if (data) {
 		struct hci_cp_remote_oob_data_reply cp;
 		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);
 									&cp);
 	}
 	}
 
 
+unlock:
 	hci_dev_unlock(hdev);
 	hci_dev_unlock(hdev);
 }
 }
 
 

File diff suppressed because it is too large
+ 251 - 223
net/bluetooth/l2cap_core.c


+ 24 - 48
net/bluetooth/l2cap_sock.c

@@ -269,7 +269,7 @@ static int l2cap_sock_listen(struct socket *sock, int backlog)
 		goto done;
 		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;
 		bdaddr_t *src = &bt_sk(sk)->src;
 		u16 psm;
 		u16 psm;
 
 
@@ -757,35 +757,37 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
 	case L2CAP_MODE_ERTM:
 	case L2CAP_MODE_ERTM:
 	case L2CAP_MODE_STREAMING:
 	case L2CAP_MODE_STREAMING:
 		/* Entire SDU fits into one PDU */
 		/* Entire SDU fits into one PDU */
-		if (len <= pi->remote_mps) {
+		if (len <= pi->chan->remote_mps) {
 			control = L2CAP_SDU_UNSEGMENTED;
 			control = L2CAP_SDU_UNSEGMENTED;
 			skb = l2cap_create_iframe_pdu(sk, msg, len, control, 0);
 			skb = l2cap_create_iframe_pdu(sk, msg, len, control, 0);
 			if (IS_ERR(skb)) {
 			if (IS_ERR(skb)) {
 				err = PTR_ERR(skb);
 				err = PTR_ERR(skb);
 				goto done;
 				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 {
 		} else {
 		/* Segment SDU into multiples PDUs */
 		/* 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)
 			if (err < 0)
 				goto done;
 				goto done;
 		}
 		}
 
 
 		if (pi->mode == L2CAP_MODE_STREAMING) {
 		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)
 		if (err >= 0)
 			err = len;
 			err = len;
@@ -808,29 +810,7 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms
 	lock_sock(sk);
 	lock_sock(sk);
 
 
 	if (sk->sk_state == BT_CONNECT2 && bt_sk(sk)->defer_setup) {
 	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);
 		release_sock(sk);
 		return 0;
 		return 0;
 	}
 	}
@@ -886,6 +866,7 @@ static void l2cap_sock_cleanup_listen(struct sock *parent)
 void __l2cap_sock_close(struct sock *sk, int reason)
 void __l2cap_sock_close(struct sock *sk, int reason)
 {
 {
 	struct l2cap_conn *conn = l2cap_pi(sk)->conn;
 	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);
 	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) &&
 					sk->sk_type == SOCK_STREAM) &&
 					conn->hcon->type == ACL_LINK) {
 					conn->hcon->type == ACL_LINK) {
 			l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
 			l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
-			l2cap_send_disconn_req(conn, sk, reason);
+			l2cap_send_disconn_req(conn, chan, reason);
 		} else
 		} else
-			l2cap_chan_del(sk, reason);
+			l2cap_chan_del(chan, reason);
 		break;
 		break;
 
 
 	case BT_CONNECT2:
 	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.dcid   = cpu_to_le16(l2cap_pi(sk)->scid);
 			rsp.result = cpu_to_le16(result);
 			rsp.result = cpu_to_le16(result);
 			rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
 			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;
 		break;
 
 
 	case BT_CONNECT:
 	case BT_CONNECT:
 	case BT_DISCONN:
 	case BT_DISCONN:
-		l2cap_chan_del(sk, reason);
+		l2cap_chan_del(chan, reason);
 		break;
 		break;
 
 
 	default:
 	default:
@@ -1035,12 +1016,7 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent)
 	}
 	}
 
 
 	/* Default config options */
 	/* Default config options */
-	pi->conf_len = 0;
 	pi->flush_to = L2CAP_DEFAULT_FLUSH_TO;
 	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 = {
 static struct proto l2cap_proto = {

Some files were not shown because too many files changed in this diff