diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-03 14:04:18 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-03 14:04:18 -0700 |
commit | 5bb053bef82523a8fd78d650bca81c9f114fa276 (patch) | |
tree | 58c2fe47f60bb69230bb05d57a6c9e3f47f7b1fe /drivers/bluetooth | |
parent | bb2407a7219760926760f0448fddf00d625e5aec (diff) | |
parent | 159f02977b2feb18a4bece5e586c838a6d26d44b (diff) | |
download | linux-5bb053bef82523a8fd78d650bca81c9f114fa276.tar.bz2 |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
Pull networking updates from David Miller:
1) Support offloading wireless authentication to userspace via
NL80211_CMD_EXTERNAL_AUTH, from Srinivas Dasari.
2) A lot of work on network namespace setup/teardown from Kirill Tkhai.
Setup and cleanup of namespaces now all run asynchronously and thus
performance is significantly increased.
3) Add rx/tx timestamping support to mv88e6xxx driver, from Brandon
Streiff.
4) Support zerocopy on RDS sockets, from Sowmini Varadhan.
5) Use denser instruction encoding in x86 eBPF JIT, from Daniel
Borkmann.
6) Support hw offload of vlan filtering in mvpp2 dreiver, from Maxime
Chevallier.
7) Support grafting of child qdiscs in mlxsw driver, from Nogah
Frankel.
8) Add packet forwarding tests to selftests, from Ido Schimmel.
9) Deal with sub-optimal GSO packets better in BBR congestion control,
from Eric Dumazet.
10) Support 5-tuple hashing in ipv6 multipath routing, from David Ahern.
11) Add path MTU tests to selftests, from Stefano Brivio.
12) Various bits of IPSEC offloading support for mlx5, from Aviad
Yehezkel, Yossi Kuperman, and Saeed Mahameed.
13) Support RSS spreading on ntuple filters in SFC driver, from Edward
Cree.
14) Lots of sockmap work from John Fastabend. Applications can use eBPF
to filter sendmsg and sendpage operations.
15) In-kernel receive TLS support, from Dave Watson.
16) Add XDP support to ixgbevf, this is significant because it should
allow optimized XDP usage in various cloud environments. From Tony
Nguyen.
17) Add new Intel E800 series "ice" ethernet driver, from Anirudh
Venkataramanan et al.
18) IP fragmentation match offload support in nfp driver, from Pieter
Jansen van Vuuren.
19) Support XDP redirect in i40e driver, from Björn Töpel.
20) Add BPF_RAW_TRACEPOINT program type for accessing the arguments of
tracepoints in their raw form, from Alexei Starovoitov.
21) Lots of striding RQ improvements to mlx5 driver with many
performance improvements, from Tariq Toukan.
22) Use rhashtable for inet frag reassembly, from Eric Dumazet.
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (1678 commits)
net: mvneta: improve suspend/resume
net: mvneta: split rxq/txq init and txq deinit into SW and HW parts
ipv6: frags: fix /proc/sys/net/ipv6/ip6frag_low_thresh
net: bgmac: Fix endian access in bgmac_dma_tx_ring_free()
net: bgmac: Correctly annotate register space
route: check sysctl_fib_multipath_use_neigh earlier than hash
fix typo in command value in drivers/net/phy/mdio-bitbang.
sky2: Increase D3 delay to sky2 stops working after suspend
net/mlx5e: Set EQE based as default TX interrupt moderation mode
ibmvnic: Disable irqs before exiting reset from closed state
net: sched: do not emit messages while holding spinlock
vlan: also check phy_driver ts_info for vlan's real device
Bluetooth: Mark expected switch fall-throughs
Bluetooth: Set HCI_QUIRK_SIMULTANEOUS_DISCOVERY for BTUSB_QCA_ROME
Bluetooth: btrsi: remove unused including <linux/version.h>
Bluetooth: hci_bcm: Remove DMI quirk for the MINIX Z83-4
sh_eth: kill useless check in __sh_eth_get_regs()
sh_eth: add sh_eth_cpu_data::no_xdfar flag
ipv6: factorize sk_wmem_alloc updates done by __ip6_append_data()
ipv4: factorize sk_wmem_alloc updates done by __ip_append_data()
...
Diffstat (limited to 'drivers/bluetooth')
-rw-r--r-- | drivers/bluetooth/Kconfig | 30 | ||||
-rw-r--r-- | drivers/bluetooth/Makefile | 3 | ||||
-rw-r--r-- | drivers/bluetooth/ath3k.c | 28 | ||||
-rw-r--r-- | drivers/bluetooth/bpa10x.c | 2 | ||||
-rw-r--r-- | drivers/bluetooth/btmrvl_main.c | 2 | ||||
-rw-r--r-- | drivers/bluetooth/btmrvl_sdio.c | 4 | ||||
-rw-r--r-- | drivers/bluetooth/btrsi.c | 187 | ||||
-rw-r--r-- | drivers/bluetooth/btrtl.c | 119 | ||||
-rw-r--r-- | drivers/bluetooth/btuart_cs.c | 675 | ||||
-rw-r--r-- | drivers/bluetooth/btusb.c | 14 | ||||
-rw-r--r-- | drivers/bluetooth/h4_recv.h | 160 | ||||
-rw-r--r-- | drivers/bluetooth/hci_ath.c | 4 | ||||
-rw-r--r-- | drivers/bluetooth/hci_bcm.c | 305 | ||||
-rw-r--r-- | drivers/bluetooth/hci_ll.c | 224 |
14 files changed, 784 insertions, 973 deletions
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 07e55cd8f8c8..010f5f579e68 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -147,6 +147,7 @@ config BT_HCIUART_ATH3K config BT_HCIUART_LL bool "HCILL protocol support" depends on BT_HCIUART_SERDEV + select BT_HCIUART_H4 help HCILL (HCI Low Level) is a serial protocol for communication between Bluetooth device and host. This protocol is required for @@ -242,8 +243,7 @@ config BT_HCIBCM203X config BT_HCIBPA10X tristate "HCI BPA10x USB driver" - depends on USB && BT_HCIUART - select BT_HCIUART_H4 + depends on USB help Bluetooth HCI BPA10x USB driver. This driver provides support for the Digianswer BPA 100/105 Bluetooth @@ -305,22 +305,6 @@ config BT_HCIBLUECARD Say Y here to compile support for HCI BlueCard devices into the kernel or say M to compile it as module (bluecard_cs). -config BT_HCIBTUART - tristate "HCI UART (PC Card) device driver" - depends on PCMCIA - help - Bluetooth HCI UART (PC Card) driver. - This driver provides support for Bluetooth PCMCIA devices with - an UART interface: - Xircom CreditCard Bluetooth Adapter - Xircom RealPort2 Bluetooth Adapter - Sphinx PICO Card - H-Soft blue+Card - Cyber-blue Compact Flash Card - - Say Y here to compile support for HCI UART devices into the - kernel or say M to compile it as module (btuart_cs). - config BT_HCIVHCI tristate "HCI VHCI (Virtual HCI device) driver" help @@ -392,4 +376,14 @@ config BT_QCOMSMD Say Y here to compile support for HCI over Qualcomm SMD into the kernel or say M to compile as a module. +config BT_HCIRSI + tristate + help + Redpine BT driver. + This driver handles BT traffic from upper layers and pass + to the RSI_91x coex module for further scheduling to device + + Say Y here to compile support for HCI over Redpine into the + kernel or say M to compile as a module. + endmenu diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile index 4e4e44d09796..ec16c55eb6e9 100644 --- a/drivers/bluetooth/Makefile +++ b/drivers/bluetooth/Makefile @@ -11,7 +11,6 @@ obj-$(CONFIG_BT_HCIBFUSB) += bfusb.o obj-$(CONFIG_BT_HCIDTL1) += dtl1_cs.o 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 @@ -28,6 +27,8 @@ obj-$(CONFIG_BT_QCA) += btqca.o obj-$(CONFIG_BT_HCIUART_NOKIA) += hci_nokia.o +obj-$(CONFIG_BT_HCIRSI) += btrsi.o + btmrvl-y := btmrvl_main.o btmrvl-$(CONFIG_DEBUG_FS) += btmrvl_debugfs.o diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 204afe66de92..3d7a5c149af3 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -203,6 +203,12 @@ static const struct usb_device_id ath3k_blist_tbl[] = { { } /* Terminating entry */ }; +static inline void ath3k_log_failed_loading(int err, int len, int size) +{ + BT_ERR("Error in firmware loading err = %d, len = %d, size = %d", + err, len, size); +} + #define USB_REQ_DFU_DNLOAD 1 #define BULK_SIZE 4096 #define FW_HDR_SIZE 20 @@ -227,15 +233,16 @@ static int ath3k_load_firmware(struct usb_device *udev, return -ENOMEM; } - memcpy(send_buf, firmware->data, 20); + memcpy(send_buf, firmware->data, FW_HDR_SIZE); err = usb_control_msg(udev, pipe, USB_REQ_DFU_DNLOAD, USB_TYPE_VENDOR, - 0, 0, send_buf, 20, USB_CTRL_SET_TIMEOUT); + 0, 0, send_buf, FW_HDR_SIZE, + USB_CTRL_SET_TIMEOUT); if (err < 0) { BT_ERR("Can't change to loading configuration err"); goto error; } - sent += 20; - count -= 20; + sent += FW_HDR_SIZE; + count -= FW_HDR_SIZE; pipe = usb_sndbulkpipe(udev, 0x02); @@ -250,8 +257,7 @@ static int ath3k_load_firmware(struct usb_device *udev, &len, 3000); if (err || (len != size)) { - BT_ERR("Error in firmware loading err = %d," - "len = %d, size = %d", err, len, size); + ath3k_log_failed_loading(err, len, size); goto error; } @@ -350,8 +356,7 @@ static int ath3k_load_fwfile(struct usb_device *udev, err = usb_bulk_msg(udev, pipe, send_buf, size, &len, 3000); if (err || (len != size)) { - BT_ERR("Error in firmware loading err = %d," - "len = %d, size = %d", err, len, size); + ath3k_log_failed_loading(err, len, size); kfree(send_buf); return err; } @@ -398,7 +403,7 @@ static int ath3k_set_normal_mode(struct usb_device *udev) static int ath3k_load_patch(struct usb_device *udev) { unsigned char fw_state; - char filename[ATH3K_NAME_LEN] = {0}; + char filename[ATH3K_NAME_LEN]; const struct firmware *firmware; struct ath3k_version fw_version; __u32 pt_rom_version, pt_build_version; @@ -451,7 +456,7 @@ static int ath3k_load_patch(struct usb_device *udev) static int ath3k_load_syscfg(struct usb_device *udev) { unsigned char fw_state; - char filename[ATH3K_NAME_LEN] = {0}; + char filename[ATH3K_NAME_LEN]; const struct firmware *firmware; struct ath3k_version fw_version; int clk_value, ret; @@ -522,7 +527,6 @@ static int ath3k_probe(struct usb_interface *intf, /* load patch and sysconfig files for AR3012 */ if (id->driver_info & BTUSB_ATH3012) { - /* New firmware with patch and sysconfig files already loaded */ if (le16_to_cpu(udev->descriptor.bcdDevice) > 0x0001) return -ENODEV; @@ -565,7 +569,7 @@ static int ath3k_probe(struct usb_interface *intf, static void ath3k_disconnect(struct usb_interface *intf) { - BT_DBG("ath3k_disconnect intf %p", intf); + BT_DBG("%s intf %p", __func__, intf); } static struct usb_driver ath3k_driver = { diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c index 801ea4ca65e4..c6f7cc57db14 100644 --- a/drivers/bluetooth/bpa10x.c +++ b/drivers/bluetooth/bpa10x.c @@ -35,7 +35,7 @@ #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> -#include "hci_uart.h" +#include "h4_recv.h" #define VERSION "0.11" diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index b280d466f05b..f6c694a1b9b0 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -183,7 +183,7 @@ static int btmrvl_send_sync_cmd(struct btmrvl_private *priv, u16 opcode, return -EFAULT; } - skb = bt_skb_alloc(HCI_COMMAND_HDR_SIZE + len, GFP_ATOMIC); + skb = bt_skb_alloc(HCI_COMMAND_HDR_SIZE + len, GFP_KERNEL); if (!skb) { BT_ERR("No free skb"); return -ENOMEM; diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index 7dbb4463b539..6f99b9f3d57f 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -689,7 +689,7 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv) int ret, num_blocks, blksz; struct sk_buff *skb = NULL; u32 type; - u8 *payload = NULL; + u8 *payload; struct hci_dev *hdev = priv->btmrvl_dev.hcidev; struct btmrvl_sdio_card *card = priv->btmrvl_dev.card; @@ -920,7 +920,7 @@ static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card) { struct sdio_func *func; u8 reg; - int ret = 0; + int ret; if (!card || !card->func) { BT_ERR("Error: card or function is NULL!"); diff --git a/drivers/bluetooth/btrsi.c b/drivers/bluetooth/btrsi.c new file mode 100644 index 000000000000..60d1419590ba --- /dev/null +++ b/drivers/bluetooth/btrsi.c @@ -0,0 +1,187 @@ +/** + * Copyright (c) 2017 Redpine Signals Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <net/bluetooth/bluetooth.h> +#include <net/bluetooth/hci_core.h> +#include <asm/unaligned.h> +#include <net/rsi_91x.h> +#include <net/genetlink.h> + +#define RSI_HEADROOM_FOR_BT_HAL 16 +#define RSI_FRAME_DESC_SIZE 16 + +struct rsi_hci_adapter { + void *priv; + struct rsi_proto_ops *proto_ops; + struct hci_dev *hdev; +}; + +static int rsi_hci_open(struct hci_dev *hdev) +{ + return 0; +} + +static int rsi_hci_close(struct hci_dev *hdev) +{ + return 0; +} + +static int rsi_hci_flush(struct hci_dev *hdev) +{ + return 0; +} + +static int rsi_hci_send_pkt(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct rsi_hci_adapter *h_adapter = hci_get_drvdata(hdev); + struct sk_buff *new_skb = NULL; + + switch (hci_skb_pkt_type(skb)) { + 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; + } + + if (skb_headroom(skb) < RSI_HEADROOM_FOR_BT_HAL) { + /* Insufficient skb headroom - allocate a new skb */ + new_skb = skb_realloc_headroom(skb, RSI_HEADROOM_FOR_BT_HAL); + if (unlikely(!new_skb)) + return -ENOMEM; + bt_cb(new_skb)->pkt_type = hci_skb_pkt_type(skb); + kfree_skb(skb); + skb = new_skb; + } + + return h_adapter->proto_ops->coex_send_pkt(h_adapter->priv, skb, + RSI_BT_Q); +} + +static int rsi_hci_recv_pkt(void *priv, const u8 *pkt) +{ + struct rsi_hci_adapter *h_adapter = priv; + struct hci_dev *hdev = h_adapter->hdev; + struct sk_buff *skb; + int pkt_len = get_unaligned_le16(pkt) & 0x0fff; + + skb = dev_alloc_skb(pkt_len); + if (!skb) + return -ENOMEM; + + memcpy(skb->data, pkt + RSI_FRAME_DESC_SIZE, pkt_len); + skb_put(skb, pkt_len); + h_adapter->hdev->stat.byte_rx += skb->len; + + hci_skb_pkt_type(skb) = pkt[14]; + + return hci_recv_frame(hdev, skb); +} + +static int rsi_hci_attach(void *priv, struct rsi_proto_ops *ops) +{ + struct rsi_hci_adapter *h_adapter = NULL; + struct hci_dev *hdev; + int err = 0; + + h_adapter = kzalloc(sizeof(*h_adapter), GFP_KERNEL); + if (!h_adapter) + return -ENOMEM; + + h_adapter->priv = priv; + ops->set_bt_context(priv, h_adapter); + h_adapter->proto_ops = ops; + + hdev = hci_alloc_dev(); + if (!hdev) { + BT_ERR("Failed to alloc HCI device"); + goto err; + } + + h_adapter->hdev = hdev; + + if (ops->get_host_intf(priv) == RSI_HOST_INTF_SDIO) + hdev->bus = HCI_SDIO; + else + hdev->bus = HCI_USB; + + hci_set_drvdata(hdev, h_adapter); + hdev->dev_type = HCI_PRIMARY; + hdev->open = rsi_hci_open; + hdev->close = rsi_hci_close; + hdev->flush = rsi_hci_flush; + hdev->send = rsi_hci_send_pkt; + + err = hci_register_dev(hdev); + if (err < 0) { + BT_ERR("HCI registration failed with errcode %d", err); + hci_free_dev(hdev); + goto err; + } + + return 0; +err: + h_adapter->hdev = NULL; + kfree(h_adapter); + return -EINVAL; +} + +static void rsi_hci_detach(void *priv) +{ + struct rsi_hci_adapter *h_adapter = priv; + struct hci_dev *hdev; + + if (!h_adapter) + return; + + hdev = h_adapter->hdev; + if (hdev) { + hci_unregister_dev(hdev); + hci_free_dev(hdev); + h_adapter->hdev = NULL; + } + + kfree(h_adapter); +} + +const struct rsi_mod_ops rsi_bt_ops = { + .attach = rsi_hci_attach, + .detach = rsi_hci_detach, + .recv_pkt = rsi_hci_recv_pkt, +}; +EXPORT_SYMBOL(rsi_bt_ops); + +static int rsi_91x_bt_module_init(void) +{ + return 0; +} + +static void rsi_91x_bt_module_exit(void) +{ + return; +} + +module_init(rsi_91x_bt_module_init); +module_exit(rsi_91x_bt_module_exit); +MODULE_AUTHOR("Redpine Signals Inc"); +MODULE_DESCRIPTION("RSI BT driver"); +MODULE_SUPPORTED_DEVICE("RSI-BT"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c index 6e2ad748abba..437f080deaab 100644 --- a/drivers/bluetooth/btrtl.c +++ b/drivers/bluetooth/btrtl.c @@ -35,6 +35,60 @@ #define RTL_ROM_LMP_8761A 0x8761 #define RTL_ROM_LMP_8822B 0x8822 +#define IC_MATCH_FL_LMPSUBV (1 << 0) +#define IC_MATCH_FL_HCIREV (1 << 1) +#define IC_INFO(lmps, hcir) \ + .match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_HCIREV, \ + .lmp_subver = (lmps), \ + .hci_rev = (hcir) + +struct id_table { + __u16 match_flags; + __u16 lmp_subver; + __u16 hci_rev; + bool config_needed; + char *fw_name; + char *cfg_name; +}; + +static const struct id_table ic_id_table[] = { + /* 8723B */ + { IC_INFO(RTL_ROM_LMP_8723B, 0xb), + .config_needed = false, + .fw_name = "rtl_bt/rtl8723b_fw.bin", + .cfg_name = "rtl_bt/rtl8723b_config.bin" }, + + /* 8723D */ + { IC_INFO(RTL_ROM_LMP_8723B, 0xd), + .config_needed = true, + .fw_name = "rtl_bt/rtl8723d_fw.bin", + .cfg_name = "rtl_bt/rtl8723d_config.bin" }, + + /* 8821A */ + { IC_INFO(RTL_ROM_LMP_8821A, 0xa), + .config_needed = false, + .fw_name = "rtl_bt/rtl8821a_fw.bin", + .cfg_name = "rtl_bt/rtl8821a_config.bin" }, + + /* 8821C */ + { IC_INFO(RTL_ROM_LMP_8821A, 0xc), + .config_needed = false, + .fw_name = "rtl_bt/rtl8821c_fw.bin", + .cfg_name = "rtl_bt/rtl8821c_config.bin" }, + + /* 8761A */ + { IC_MATCH_FL_LMPSUBV, RTL_ROM_LMP_8761A, 0x0, + .config_needed = false, + .fw_name = "rtl_bt/rtl8761a_fw.bin", + .cfg_name = "rtl_bt/rtl8761a_config.bin" }, + + /* 8822B */ + { IC_INFO(RTL_ROM_LMP_8822B, 0xb), + .config_needed = true, + .fw_name = "rtl_bt/rtl8822b_fw.bin", + .cfg_name = "rtl_bt/rtl8822b_config.bin" }, + }; + static int rtl_read_rom_version(struct hci_dev *hdev, u8 *version) { struct rtl_rom_version_evt *rom_version; @@ -64,9 +118,9 @@ static int rtl_read_rom_version(struct hci_dev *hdev, u8 *version) return 0; } -static int rtl8723b_parse_firmware(struct hci_dev *hdev, u16 lmp_subver, - const struct firmware *fw, - unsigned char **_buf) +static int rtlbt_parse_firmware(struct hci_dev *hdev, u16 lmp_subver, + const struct firmware *fw, + unsigned char **_buf) { const u8 extension_sig[] = { 0x51, 0x04, 0xfd, 0x77 }; struct rtl_epatch_header *epatch_info; @@ -88,6 +142,8 @@ static int rtl8723b_parse_firmware(struct hci_dev *hdev, u16 lmp_subver, { RTL_ROM_LMP_8821A, 2 }, { RTL_ROM_LMP_8761A, 3 }, { RTL_ROM_LMP_8822B, 8 }, + { RTL_ROM_LMP_8723B, 9 }, /* 8723D */ + { RTL_ROM_LMP_8821A, 10 }, /* 8821C */ }; ret = rtl_read_rom_version(hdev, &rom_version); @@ -320,8 +376,8 @@ out: return ret; } -static int btrtl_setup_rtl8723b(struct hci_dev *hdev, u16 lmp_subver, - const char *fw_name) +static int btrtl_setup_rtl8723b(struct hci_dev *hdev, u16 hci_rev, + u16 lmp_subver) { unsigned char *fw_data = NULL; const struct firmware *fw; @@ -330,39 +386,40 @@ static int btrtl_setup_rtl8723b(struct hci_dev *hdev, u16 lmp_subver, u8 *cfg_buff = NULL; u8 *tbuff; char *cfg_name = NULL; - bool config_needed = false; + char *fw_name = NULL; + int i; + + for (i = 0; i < ARRAY_SIZE(ic_id_table); i++) { + if ((ic_id_table[i].match_flags & IC_MATCH_FL_LMPSUBV) && + (ic_id_table[i].lmp_subver != lmp_subver)) + continue; + if ((ic_id_table[i].match_flags & IC_MATCH_FL_HCIREV) && + (ic_id_table[i].hci_rev != hci_rev)) + continue; - switch (lmp_subver) { - case RTL_ROM_LMP_8723B: - cfg_name = "rtl_bt/rtl8723b_config.bin"; - break; - case RTL_ROM_LMP_8821A: - cfg_name = "rtl_bt/rtl8821a_config.bin"; - break; - case RTL_ROM_LMP_8761A: - cfg_name = "rtl_bt/rtl8761a_config.bin"; - break; - case RTL_ROM_LMP_8822B: - cfg_name = "rtl_bt/rtl8822b_config.bin"; - config_needed = true; - break; - default: - BT_ERR("%s: rtl: no config according to lmp_subver %04x", - hdev->name, lmp_subver); break; } + if (i >= ARRAY_SIZE(ic_id_table)) { + BT_ERR("%s: unknown IC info, lmp subver %04x, hci rev %04x", + hdev->name, lmp_subver, hci_rev); + return -EINVAL; + } + + cfg_name = ic_id_table[i].cfg_name; + if (cfg_name) { cfg_sz = rtl_load_config(hdev, cfg_name, &cfg_buff); if (cfg_sz < 0) { cfg_sz = 0; - if (config_needed) + if (ic_id_table[i].config_needed) BT_ERR("Necessary config file %s not found\n", cfg_name); } } else cfg_sz = 0; + fw_name = ic_id_table[i].fw_name; bt_dev_info(hdev, "rtl: loading %s", fw_name); ret = request_firmware(&fw, fw_name, &hdev->dev); if (ret < 0) { @@ -370,7 +427,7 @@ static int btrtl_setup_rtl8723b(struct hci_dev *hdev, u16 lmp_subver, goto err_req_fw; } - ret = rtl8723b_parse_firmware(hdev, lmp_subver, fw, &fw_data); + ret = rtlbt_parse_firmware(hdev, lmp_subver, fw, &fw_data); if (ret < 0) goto out; @@ -429,7 +486,7 @@ int btrtl_setup_realtek(struct hci_dev *hdev) { struct sk_buff *skb; struct hci_rp_read_local_version *resp; - u16 lmp_subver; + u16 hci_rev, lmp_subver; skb = btrtl_read_local_version(hdev); if (IS_ERR(skb)) @@ -441,6 +498,7 @@ int btrtl_setup_realtek(struct hci_dev *hdev) resp->hci_ver, resp->hci_rev, resp->lmp_ver, resp->lmp_subver); + hci_rev = le16_to_cpu(resp->hci_rev); lmp_subver = le16_to_cpu(resp->lmp_subver); kfree_skb(skb); @@ -455,17 +513,10 @@ int btrtl_setup_realtek(struct hci_dev *hdev) case RTL_ROM_LMP_3499: return btrtl_setup_rtl8723a(hdev); case RTL_ROM_LMP_8723B: - return btrtl_setup_rtl8723b(hdev, lmp_subver, - "rtl_bt/rtl8723b_fw.bin"); case RTL_ROM_LMP_8821A: - return btrtl_setup_rtl8723b(hdev, lmp_subver, - "rtl_bt/rtl8821a_fw.bin"); case RTL_ROM_LMP_8761A: - return btrtl_setup_rtl8723b(hdev, lmp_subver, - "rtl_bt/rtl8761a_fw.bin"); case RTL_ROM_LMP_8822B: - return btrtl_setup_rtl8723b(hdev, lmp_subver, - "rtl_bt/rtl8822b_fw.bin"); + return btrtl_setup_rtl8723b(hdev, hci_rev, lmp_subver); default: bt_dev_info(hdev, "rtl: assuming no firmware upload needed"); return 0; diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c deleted file mode 100644 index 310e9c2e09b6..000000000000 --- a/drivers/bluetooth/btuart_cs.c +++ /dev/null @@ -1,675 +0,0 @@ -/* - * - * Driver for Bluetooth PCMCIA cards with HCI UART interface - * - * Copyright (C) 2001-2002 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 version 2 as - * published by the Free Software Foundation; - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The initial developer of the original code is David A. Hinds - * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds - * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. - * - */ - -#include <linux/module.h> - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/types.h> -#include <linux/delay.h> -#include <linux/errno.h> -#include <linux/ptrace.h> -#include <linux/ioport.h> -#include <linux/spinlock.h> -#include <linux/moduleparam.h> - -#include <linux/skbuff.h> -#include <linux/string.h> -#include <linux/serial.h> -#include <linux/serial_reg.h> -#include <linux/bitops.h> -#include <linux/io.h> - -#include <pcmcia/cistpl.h> -#include <pcmcia/ciscode.h> -#include <pcmcia/ds.h> -#include <pcmcia/cisreg.h> - -#include <net/bluetooth/bluetooth.h> -#include <net/bluetooth/hci_core.h> - - - -/* ======================== Module parameters ======================== */ - - -MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); -MODULE_DESCRIPTION("Bluetooth driver for Bluetooth PCMCIA cards with HCI UART interface"); -MODULE_LICENSE("GPL"); - - - -/* ======================== Local structures ======================== */ - - -struct btuart_info { - struct pcmcia_device *p_dev; - - struct hci_dev *hdev; - - spinlock_t lock; /* For serializing operations */ - - struct sk_buff_head txq; - unsigned long tx_state; - - unsigned long rx_state; - unsigned long rx_count; - struct sk_buff *rx_skb; -}; - - -static int btuart_config(struct pcmcia_device *link); -static void btuart_release(struct pcmcia_device *link); - -static void btuart_detach(struct pcmcia_device *p_dev); - - -/* Maximum baud rate */ -#define SPEED_MAX 115200 - -/* Default baud rate: 57600, 115200, 230400 or 460800 */ -#define DEFAULT_BAUD_RATE 115200 - - -/* Transmit states */ -#define XMIT_SENDING 1 -#define XMIT_WAKEUP 2 -#define XMIT_WAITING 8 - -/* Receiver states */ -#define RECV_WAIT_PACKET_TYPE 0 -#define RECV_WAIT_EVENT_HEADER 1 -#define RECV_WAIT_ACL_HEADER 2 -#define RECV_WAIT_SCO_HEADER 3 -#define RECV_WAIT_DATA 4 - - - -/* ======================== Interrupt handling ======================== */ - - -static int btuart_write(unsigned int iobase, int fifo_size, __u8 *buf, int len) -{ - int actual = 0; - - /* Tx FIFO should be empty */ - if (!(inb(iobase + UART_LSR) & UART_LSR_THRE)) - return 0; - - /* Fill FIFO with current frame */ - while ((fifo_size-- > 0) && (actual < len)) { - /* Transmit next byte */ - outb(buf[actual], iobase + UART_TX); - actual++; - } - - return actual; -} - - -static void btuart_write_wakeup(struct btuart_info *info) -{ - if (!info) { - BT_ERR("Unknown device"); - return; - } - - if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) { - set_bit(XMIT_WAKEUP, &(info->tx_state)); - return; - } - - do { - unsigned int iobase = info->p_dev->resource[0]->start; - register struct sk_buff *skb; - int len; - - clear_bit(XMIT_WAKEUP, &(info->tx_state)); - - if (!pcmcia_dev_present(info->p_dev)) - return; - - skb = skb_dequeue(&(info->txq)); - if (!skb) - break; - - /* Send frame */ - len = btuart_write(iobase, 16, skb->data, skb->len); - set_bit(XMIT_WAKEUP, &(info->tx_state)); - - if (len == skb->len) { - kfree_skb(skb); - } else { - skb_pull(skb, len); - skb_queue_head(&(info->txq), skb); - } - - info->hdev->stat.byte_tx += len; - - } while (test_bit(XMIT_WAKEUP, &(info->tx_state))); - - clear_bit(XMIT_SENDING, &(info->tx_state)); -} - - -static void btuart_receive(struct btuart_info *info) -{ - unsigned int iobase; - int boguscount = 0; - - if (!info) { - BT_ERR("Unknown device"); - return; - } - - iobase = info->p_dev->resource[0]->start; - - do { - info->hdev->stat.byte_rx++; - - /* Allocate packet */ - if (!info->rx_skb) { - info->rx_state = RECV_WAIT_PACKET_TYPE; - info->rx_count = 0; - info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC); - if (!info->rx_skb) { - BT_ERR("Can't allocate mem for new packet"); - return; - } - } - - if (info->rx_state == RECV_WAIT_PACKET_TYPE) { - - hci_skb_pkt_type(info->rx_skb) = inb(iobase + UART_RX); - - switch (hci_skb_pkt_type(info->rx_skb)) { - - case HCI_EVENT_PKT: - info->rx_state = RECV_WAIT_EVENT_HEADER; - info->rx_count = HCI_EVENT_HDR_SIZE; - break; - - case HCI_ACLDATA_PKT: - info->rx_state = RECV_WAIT_ACL_HEADER; - info->rx_count = HCI_ACL_HDR_SIZE; - break; - - case HCI_SCODATA_PKT: - info->rx_state = RECV_WAIT_SCO_HEADER; - info->rx_count = HCI_SCO_HDR_SIZE; - break; - - default: - /* Unknown packet */ - BT_ERR("Unknown HCI packet with type 0x%02x received", - hci_skb_pkt_type(info->rx_skb)); - info->hdev->stat.err_rx++; - - kfree_skb(info->rx_skb); - info->rx_skb = NULL; - break; - - } - - } else { - - skb_put_u8(info->rx_skb, inb(iobase + UART_RX)); - info->rx_count--; - - if (info->rx_count == 0) { - - int dlen; - struct hci_event_hdr *eh; - struct hci_acl_hdr *ah; - struct hci_sco_hdr *sh; - - - switch (info->rx_state) { - - case RECV_WAIT_EVENT_HEADER: - eh = hci_event_hdr(info->rx_skb); - info->rx_state = RECV_WAIT_DATA; - info->rx_count = eh->plen; - break; - - case RECV_WAIT_ACL_HEADER: - ah = hci_acl_hdr(info->rx_skb); - dlen = __le16_to_cpu(ah->dlen); - info->rx_state = RECV_WAIT_DATA; - info->rx_count = dlen; - break; - - case RECV_WAIT_SCO_HEADER: - sh = hci_sco_hdr(info->rx_skb); - info->rx_state = RECV_WAIT_DATA; - info->rx_count = sh->dlen; - break; - - case RECV_WAIT_DATA: - hci_recv_frame(info->hdev, info->rx_skb); - info->rx_skb = NULL; - break; - - } - - } - - } - - /* Make sure we don't stay here too long */ - if (boguscount++ > 16) - break; - - } while (inb(iobase + UART_LSR) & UART_LSR_DR); -} - - -static irqreturn_t btuart_interrupt(int irq, void *dev_inst) -{ - struct btuart_info *info = dev_inst; - unsigned int iobase; - int boguscount = 0; - int iir, lsr; - irqreturn_t r = IRQ_NONE; - - if (!info || !info->hdev) - /* our irq handler is shared */ - return IRQ_NONE; - - iobase = info->p_dev->resource[0]->start; - - spin_lock(&(info->lock)); - - iir = inb(iobase + UART_IIR) & UART_IIR_ID; - while (iir) { - r = IRQ_HANDLED; - - /* Clear interrupt */ - lsr = inb(iobase + UART_LSR); - - switch (iir) { - case UART_IIR_RLSI: - BT_ERR("RLSI"); - break; - case UART_IIR_RDI: - /* Receive interrupt */ - btuart_receive(info); - break; - case UART_IIR_THRI: - if (lsr & UART_LSR_THRE) { - /* Transmitter ready for data */ - btuart_write_wakeup(info); - } - break; - default: - BT_ERR("Unhandled IIR=%#x", iir); - break; - } - - /* Make sure we don't stay here too long */ - if (boguscount++ > 100) - break; - - iir = inb(iobase + UART_IIR) & UART_IIR_ID; - - } - - spin_unlock(&(info->lock)); - - return r; -} - - -static void btuart_change_speed(struct btuart_info *info, - unsigned int speed) -{ - unsigned long flags; - unsigned int iobase; - int fcr; /* FIFO control reg */ - int lcr; /* Line control reg */ - int divisor; - - if (!info) { - BT_ERR("Unknown device"); - return; - } - - iobase = info->p_dev->resource[0]->start; - - spin_lock_irqsave(&(info->lock), flags); - - /* Turn off interrupts */ - outb(0, iobase + UART_IER); - - divisor = SPEED_MAX / speed; - - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT; - - /* - * Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and - * almost 1,7 ms at 19200 bps. At speeds above that we can just forget - * about this timeout since it will always be fast enough. - */ - - if (speed < 38400) - fcr |= UART_FCR_TRIGGER_1; - else - fcr |= UART_FCR_TRIGGER_14; - - /* Bluetooth cards use 8N1 */ - lcr = UART_LCR_WLEN8; - - outb(UART_LCR_DLAB | lcr, iobase + UART_LCR); /* Set DLAB */ - outb(divisor & 0xff, iobase + UART_DLL); /* Set speed */ - outb(divisor >> 8, iobase + UART_DLM); - outb(lcr, iobase + UART_LCR); /* Set 8N1 */ - outb(fcr, iobase + UART_FCR); /* Enable FIFO's */ - - /* Turn on interrupts */ - outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER); - - spin_unlock_irqrestore(&(info->lock), flags); -} - - - -/* ======================== HCI interface ======================== */ - - -static int btuart_hci_flush(struct hci_dev *hdev) -{ - struct btuart_info *info = hci_get_drvdata(hdev); - - /* Drop TX queue */ - skb_queue_purge(&(info->txq)); - - return 0; -} - - -static int btuart_hci_open(struct hci_dev *hdev) -{ - return 0; -} - - -static int btuart_hci_close(struct hci_dev *hdev) -{ - btuart_hci_flush(hdev); - - return 0; -} - - -static int btuart_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) -{ - struct btuart_info *info = hci_get_drvdata(hdev); - - switch (hci_skb_pkt_type(skb)) { - 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; - } - - /* Prepend skb with frame type */ - memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1); - skb_queue_tail(&(info->txq), skb); - - btuart_write_wakeup(info); - - return 0; -} - - - -/* ======================== Card services HCI interaction ======================== */ - - -static int btuart_open(struct btuart_info *info) -{ - unsigned long flags; - unsigned int iobase = info->p_dev->resource[0]->start; - struct hci_dev *hdev; - - spin_lock_init(&(info->lock)); - - skb_queue_head_init(&(info->txq)); - - info->rx_state = RECV_WAIT_PACKET_TYPE; - info->rx_count = 0; - info->rx_skb = NULL; - - /* Initialize HCI device */ - hdev = hci_alloc_dev(); - if (!hdev) { - BT_ERR("Can't allocate HCI device"); - return -ENOMEM; - } - - info->hdev = hdev; - - hdev->bus = HCI_PCCARD; - hci_set_drvdata(hdev, info); - SET_HCIDEV_DEV(hdev, &info->p_dev->dev); - - hdev->open = btuart_hci_open; - hdev->close = btuart_hci_close; - hdev->flush = btuart_hci_flush; - hdev->send = btuart_hci_send_frame; - - spin_lock_irqsave(&(info->lock), flags); - - /* Reset UART */ - outb(0, iobase + UART_MCR); - - /* Turn off interrupts */ - outb(0, iobase + UART_IER); - - /* Initialize UART */ - outb(UART_LCR_WLEN8, iobase + UART_LCR); /* Reset DLAB */ - outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR); - - /* Turn on interrupts */ - // outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER); - - spin_unlock_irqrestore(&(info->lock), flags); - - btuart_change_speed(info, DEFAULT_BAUD_RATE); - - /* Timeout before it is safe to send the first HCI packet */ - msleep(1000); - - /* Register HCI device */ - if (hci_register_dev(hdev) < 0) { - BT_ERR("Can't register HCI device"); - info->hdev = NULL; - hci_free_dev(hdev); - return -ENODEV; - } - - return 0; -} - - -static int btuart_close(struct btuart_info *info) -{ - unsigned long flags; - unsigned int iobase = info->p_dev->resource[0]->start; - struct hci_dev *hdev = info->hdev; - - if (!hdev) - return -ENODEV; - - btuart_hci_close(hdev); - - spin_lock_irqsave(&(info->lock), flags); - - /* Reset UART */ - outb(0, iobase + UART_MCR); - - /* Turn off interrupts */ - outb(0, iobase + UART_IER); - - spin_unlock_irqrestore(&(info->lock), flags); - - hci_unregister_dev(hdev); - hci_free_dev(hdev); - - return 0; -} - -static int btuart_probe(struct pcmcia_device *link) -{ - struct btuart_info *info; - - /* Create new info device */ - info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL); - if (!info) - return -ENOMEM; - - info->p_dev = link; - link->priv = info; - - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_VPP | - CONF_AUTO_SET_IO; - - return btuart_config(link); -} - - -static void btuart_detach(struct pcmcia_device *link) -{ - btuart_release(link); -} - -static int btuart_check_config(struct pcmcia_device *p_dev, void *priv_data) -{ - int *try = priv_data; - - if (!try) - p_dev->io_lines = 16; - - if ((p_dev->resource[0]->end != 8) || (p_dev->resource[0]->start == 0)) - return -EINVAL; - - p_dev->resource[0]->end = 8; - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; - - return pcmcia_request_io(p_dev); -} - -static int btuart_check_config_notpicky(struct pcmcia_device *p_dev, - void *priv_data) -{ - static unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; - int j; - - if (p_dev->io_lines > 3) - return -ENODEV; - - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; - p_dev->resource[0]->end = 8; - - for (j = 0; j < 5; j++) { - p_dev->resource[0]->start = base[j]; - p_dev->io_lines = base[j] ? 16 : 3; - if (!pcmcia_request_io(p_dev)) - return 0; - } - return -ENODEV; -} - -static int btuart_config(struct pcmcia_device *link) -{ - struct btuart_info *info = link->priv; - int i; - int try; - - /* First pass: look for a config entry that looks normal. - * Two tries: without IO aliases, then with aliases - */ - for (try = 0; try < 2; try++) - if (!pcmcia_loop_config(link, btuart_check_config, &try)) - goto found_port; - - /* Second pass: try to find an entry that isn't picky about - * its base address, then try to grab any standard serial port - * address, and finally try to get any free port. - */ - if (!pcmcia_loop_config(link, btuart_check_config_notpicky, NULL)) - goto found_port; - - BT_ERR("No usable port range found"); - goto failed; - -found_port: - i = pcmcia_request_irq(link, btuart_interrupt); - if (i != 0) - goto failed; - - i = pcmcia_enable_device(link); - if (i != 0) - goto failed; - - if (btuart_open(info) != 0) - goto failed; - - return 0; - -failed: - btuart_release(link); - return -ENODEV; -} - - -static void btuart_release(struct pcmcia_device *link) -{ - struct btuart_info *info = link->priv; - - btuart_close(info); - - pcmcia_disable_device(link); -} - -static const struct pcmcia_device_id btuart_ids[] = { - /* don't use this driver. Use serial_cs + hci_uart instead */ - PCMCIA_DEVICE_NULL -}; -MODULE_DEVICE_TABLE(pcmcia, btuart_ids); - -static struct pcmcia_driver btuart_driver = { - .owner = THIS_MODULE, - .name = "btuart_cs", - .probe = btuart_probe, - .remove = btuart_detach, - .id_table = btuart_ids, -}; -module_pcmcia_driver(btuart_driver); diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 366a49c7c08f..c8c8b0b8d333 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -340,6 +340,7 @@ static const struct usb_device_id blacklist_table[] = { /* Intel Bluetooth devices */ { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_NEW }, + { USB_DEVICE(0x8087, 0x0026), .driver_info = BTUSB_INTEL_NEW }, { USB_DEVICE(0x8087, 0x07da), .driver_info = BTUSB_CSR }, { USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL }, { USB_DEVICE(0x8087, 0x0a2a), .driver_info = BTUSB_INTEL }, @@ -367,6 +368,9 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x13d3, 0x3459), .driver_info = BTUSB_REALTEK }, { USB_DEVICE(0x13d3, 0x3494), .driver_info = BTUSB_REALTEK }, + /* Additional Realtek 8723BU Bluetooth devices */ + { USB_DEVICE(0x7392, 0xa611), .driver_info = BTUSB_REALTEK }, + /* Additional Realtek 8821AE Bluetooth devices */ { USB_DEVICE(0x0b05, 0x17dc), .driver_info = BTUSB_REALTEK }, { USB_DEVICE(0x13d3, 0x3414), .driver_info = BTUSB_REALTEK }, @@ -374,6 +378,9 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x13d3, 0x3461), .driver_info = BTUSB_REALTEK }, { USB_DEVICE(0x13d3, 0x3462), .driver_info = BTUSB_REALTEK }, + /* Additional Realtek 8822BE Bluetooth devices */ + { USB_DEVICE(0x0b05, 0x185c), .driver_info = BTUSB_REALTEK }, + /* Silicon Wave based devices */ { USB_DEVICE(0x0c10, 0x0000), .driver_info = BTUSB_SWAVE }, @@ -2073,6 +2080,8 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) case 0x0c: /* WsP */ case 0x11: /* JfP */ case 0x12: /* ThP */ + case 0x13: /* HrP */ + case 0x14: /* QnJ, IcP */ break; default: BT_ERR("%s: Unsupported Intel hardware variant (%u)", @@ -2165,6 +2174,8 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) break; case 0x11: /* JfP */ case 0x12: /* ThP */ + case 0x13: /* HrP */ + case 0x14: /* QnJ, IcP */ snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u-%u.sfi", le16_to_cpu(ver.hw_variant), le16_to_cpu(ver.hw_revision), @@ -2196,6 +2207,8 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) break; case 0x11: /* JfP */ case 0x12: /* ThP */ + case 0x13: /* HrP */ + case 0x14: /* QnJ, IcP */ snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u-%u.ddc", le16_to_cpu(ver.hw_variant), le16_to_cpu(ver.hw_revision), @@ -3050,6 +3063,7 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_QCA_ROME) { data->setup_on_usb = btusb_setup_qca; hdev->set_bdaddr = btusb_set_bdaddr_ath3012; + set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks); } #ifdef CONFIG_BT_HCIBTUSB_RTL diff --git a/drivers/bluetooth/h4_recv.h b/drivers/bluetooth/h4_recv.h new file mode 100644 index 000000000000..b432651f8236 --- /dev/null +++ b/drivers/bluetooth/h4_recv.h @@ -0,0 +1,160 @@ +/* + * + * Generic Bluetooth HCI UART driver + * + * Copyright (C) 2015-2018 Intel Corporation + * + * + * 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 <asm/unaligned.h> + +struct h4_recv_pkt { + u8 type; /* Packet type */ + u8 hlen; /* Header length */ + u8 loff; /* Data length offset in header */ + u8 lsize; /* Data length field size */ + u16 maxlen; /* Max overall packet length */ + int (*recv)(struct hci_dev *hdev, struct sk_buff *skb); +}; + +#define H4_RECV_ACL \ + .type = HCI_ACLDATA_PKT, \ + .hlen = HCI_ACL_HDR_SIZE, \ + .loff = 2, \ + .lsize = 2, \ + .maxlen = HCI_MAX_FRAME_SIZE \ + +#define H4_RECV_SCO \ + .type = HCI_SCODATA_PKT, \ + .hlen = HCI_SCO_HDR_SIZE, \ + .loff = 2, \ + .lsize = 1, \ + .maxlen = HCI_MAX_SCO_SIZE + +#define H4_RECV_EVENT \ + .type = HCI_EVENT_PKT, \ + .hlen = HCI_EVENT_HDR_SIZE, \ + .loff = 1, \ + .lsize = 1, \ + .maxlen = HCI_MAX_EVENT_SIZE + +static inline struct sk_buff *h4_recv_buf(struct hci_dev *hdev, + struct sk_buff *skb, + const unsigned char *buffer, + int count, + const struct h4_recv_pkt *pkts, + int pkts_count) +{ + while (count) { + int i, len; + + if (!count) + break; + + if (!skb) { + for (i = 0; i < pkts_count; i++) { + if (buffer[0] != (&pkts[i])->type) + continue; + + skb = bt_skb_alloc((&pkts[i])->maxlen, + GFP_ATOMIC); + if (!skb) + return ERR_PTR(-ENOMEM); + + hci_skb_pkt_type(skb) = (&pkts[i])->type; + hci_skb_expect(skb) = (&pkts[i])->hlen; + break; + } + + /* Check for invalid packet type */ + if (!skb) + return ERR_PTR(-EILSEQ); + + count -= 1; + buffer += 1; + } + + len = min_t(uint, hci_skb_expect(skb) - skb->len, count); + skb_put_data(skb, buffer, len); + + count -= len; + buffer += len; + + /* Check for partial packet */ + if (skb->len < hci_skb_expect(skb)) + continue; + + for (i = 0; i < pkts_count; i++) { + if (hci_skb_pkt_type(skb) == (&pkts[i])->type) + break; + } + + if (i >= pkts_count) { + kfree_skb(skb); + return ERR_PTR(-EILSEQ); + } + + if (skb->len == (&pkts[i])->hlen) { + u16 dlen; + + switch ((&pkts[i])->lsize) { + case 0: + /* No variable data length */ + dlen = 0; + break; + case 1: + /* Single octet variable length */ + dlen = skb->data[(&pkts[i])->loff]; + hci_skb_expect(skb) += dlen; + + if (skb_tailroom(skb) < dlen) { + kfree_skb(skb); + return ERR_PTR(-EMSGSIZE); + } + break; + case 2: + /* Double octet variable length */ + dlen = get_unaligned_le16(skb->data + + (&pkts[i])->loff); + hci_skb_expect(skb) += dlen; + + if (skb_tailroom(skb) < dlen) { + kfree_skb(skb); + return ERR_PTR(-EMSGSIZE); + } + break; + default: + /* Unsupported variable length */ + kfree_skb(skb); + return ERR_PTR(-EILSEQ); + } + + if (!dlen) { + /* No more data, complete frame */ + (&pkts[i])->recv(hdev, skb); + skb = NULL; + } + } else { + /* Complete frame */ + (&pkts[i])->recv(hdev, skb); + skb = NULL; + } + } + + return skb; +} diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c index 14ae7ee88acb..d568fbd94d6c 100644 --- a/drivers/bluetooth/hci_ath.c +++ b/drivers/bluetooth/hci_ath.c @@ -71,12 +71,12 @@ static int ath_wakeup_ar3k(struct tty_struct *tty) /* Clear RTS first */ tty->driver->ops->tiocmget(tty); tty->driver->ops->tiocmset(tty, 0x00, TIOCM_RTS); - mdelay(20); + msleep(20); /* Set RTS, wake up board */ tty->driver->ops->tiocmget(tty); tty->driver->ops->tiocmset(tty, TIOCM_RTS, 0x00); - mdelay(20); + msleep(20); status = tty->driver->ops->tiocmget(tty); return status; diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c index 40b9fb247010..441f5e1deb11 100644 --- a/drivers/bluetooth/hci_bcm.c +++ b/drivers/bluetooth/hci_bcm.c @@ -98,6 +98,8 @@ struct bcm_device { int (*set_shutdown)(struct bcm_device *, bool); #ifdef CONFIG_ACPI acpi_handle btlp, btpu, btpd; + int gpio_count; + int gpio_int_idx; #endif struct clk *clk; @@ -126,6 +128,10 @@ struct bcm_data { static DEFINE_MUTEX(bcm_device_lock); static LIST_HEAD(bcm_device_list); +static int irq_polarity = -1; +module_param(irq_polarity, int, 0444); +MODULE_PARM_DESC(irq_polarity, "IRQ polarity 0: active-high 1: active-low"); + static inline void host_set_baudrate(struct hci_uart *hu, unsigned int speed) { if (hu->serdev) @@ -770,47 +776,27 @@ unlock: } #endif -static const struct acpi_gpio_params int_last_device_wakeup_gpios = { 0, 0, false }; -static const struct acpi_gpio_params int_last_shutdown_gpios = { 1, 0, false }; -static const struct acpi_gpio_params int_last_host_wakeup_gpios = { 2, 0, false }; +static const struct acpi_gpio_params first_gpio = { 0, 0, false }; +static const struct acpi_gpio_params second_gpio = { 1, 0, false }; +static const struct acpi_gpio_params third_gpio = { 2, 0, false }; static const struct acpi_gpio_mapping acpi_bcm_int_last_gpios[] = { - { "device-wakeup-gpios", &int_last_device_wakeup_gpios, 1 }, - { "shutdown-gpios", &int_last_shutdown_gpios, 1 }, - { "host-wakeup-gpios", &int_last_host_wakeup_gpios, 1 }, + { "device-wakeup-gpios", &first_gpio, 1 }, + { "shutdown-gpios", &second_gpio, 1 }, + { "host-wakeup-gpios", &third_gpio, 1 }, { }, }; -static const struct acpi_gpio_params int_first_host_wakeup_gpios = { 0, 0, false }; -static const struct acpi_gpio_params int_first_device_wakeup_gpios = { 1, 0, false }; -static const struct acpi_gpio_params int_first_shutdown_gpios = { 2, 0, false }; - static const struct acpi_gpio_mapping acpi_bcm_int_first_gpios[] = { - { "device-wakeup-gpios", &int_first_device_wakeup_gpios, 1 }, - { "shutdown-gpios", &int_first_shutdown_gpios, 1 }, - { "host-wakeup-gpios", &int_first_host_wakeup_gpios, 1 }, + { "host-wakeup-gpios", &first_gpio, 1 }, + { "device-wakeup-gpios", &second_gpio, 1 }, + { "shutdown-gpios", &third_gpio, 1 }, { }, }; #ifdef CONFIG_ACPI /* IRQ polarity of some chipsets are not defined correctly in ACPI table. */ static const struct dmi_system_id bcm_active_low_irq_dmi_table[] = { - { - .ident = "Asus T100TA", - .matches = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, - "ASUSTeK COMPUTER INC."), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TA"), - }, - }, - { - .ident = "Asus T100CHI", - .matches = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, - "ASUSTeK COMPUTER INC."), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100CHI"), - }, - }, { /* Handle ThinkPad 8 tablets with BCM2E55 chipset ACPI ID */ .ident = "Lenovo ThinkPad 8", .matches = { @@ -818,13 +804,6 @@ static const struct dmi_system_id bcm_active_low_irq_dmi_table[] = { DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "ThinkPad 8"), }, }, - { - .ident = "MINIX Z83-4", - .matches = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "MINIX"), - DMI_MATCH(DMI_PRODUCT_NAME, "Z83-4"), - }, - }, { } }; @@ -838,13 +817,18 @@ static int bcm_resource(struct acpi_resource *ares, void *data) switch (ares->type) { case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: irq = &ares->data.extended_irq; - dev->irq_active_low = irq->polarity == ACPI_ACTIVE_LOW; + if (irq->polarity != ACPI_ACTIVE_LOW) + dev_info(dev->dev, "ACPI Interrupt resource is active-high, this is usually wrong, treating the IRQ as active-low\n"); + dev->irq_active_low = true; break; case ACPI_RESOURCE_TYPE_GPIO: gpio = &ares->data.gpio; - if (gpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT) + if (gpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT) { + dev->gpio_int_idx = dev->gpio_count; dev->irq_active_low = gpio->polarity == ACPI_ACTIVE_LOW; + } + dev->gpio_count++; break; case ACPI_RESOURCE_TYPE_SERIAL_BUS: @@ -908,13 +892,13 @@ static inline int bcm_apple_get_resources(struct bcm_device *dev) static int bcm_gpio_set_device_wakeup(struct bcm_device *dev, bool awake) { - gpiod_set_value(dev->device_wakeup, awake); + gpiod_set_value_cansleep(dev->device_wakeup, awake); return 0; } static int bcm_gpio_set_shutdown(struct bcm_device *dev, bool powered) { - gpiod_set_value(dev->shutdown, powered); + gpiod_set_value_cansleep(dev->shutdown, powered); return 0; } @@ -962,20 +946,11 @@ static int bcm_acpi_probe(struct bcm_device *dev) LIST_HEAD(resources); const struct dmi_system_id *dmi_id; const struct acpi_gpio_mapping *gpio_mapping = acpi_bcm_int_last_gpios; - const struct acpi_device_id *id; struct resource_entry *entry; int ret; - /* Retrieve GPIO data */ - id = acpi_match_device(dev->dev->driver->acpi_match_table, dev->dev); - if (id) - gpio_mapping = (const struct acpi_gpio_mapping *) id->driver_data; - - ret = devm_acpi_dev_add_driver_gpios(dev->dev, gpio_mapping); - if (ret) - return ret; - /* Retrieve UART ACPI info */ + dev->gpio_int_idx = -1; ret = acpi_dev_get_resources(ACPI_COMPANION(dev->dev), &resources, bcm_resource, dev); if (ret < 0) @@ -989,11 +964,40 @@ static int bcm_acpi_probe(struct bcm_device *dev) } acpi_dev_free_resource_list(&resources); - dmi_id = dmi_first_match(bcm_active_low_irq_dmi_table); - if (dmi_id) { - dev_warn(dev->dev, "%s: Overwriting IRQ polarity to active low", - dmi_id->ident); - dev->irq_active_low = true; + /* If the DSDT uses an Interrupt resource for the IRQ, then there are + * only 2 GPIO resources, we use the irq-last mapping for this, since + * we already have an irq the 3th / last mapping will not be used. + */ + if (dev->irq) + gpio_mapping = acpi_bcm_int_last_gpios; + else if (dev->gpio_int_idx == 0) + gpio_mapping = acpi_bcm_int_first_gpios; + else if (dev->gpio_int_idx == 2) + gpio_mapping = acpi_bcm_int_last_gpios; + else + dev_warn(dev->dev, "Unexpected ACPI gpio_int_idx: %d\n", + dev->gpio_int_idx); + + /* Warn if our expectations are not met. */ + if (dev->gpio_count != (dev->irq ? 2 : 3)) + dev_warn(dev->dev, "Unexpected number of ACPI GPIOs: %d\n", + dev->gpio_count); + + ret = devm_acpi_dev_add_driver_gpios(dev->dev, gpio_mapping); + if (ret) + return ret; + + if (irq_polarity != -1) { + dev->irq_active_low = irq_polarity; + dev_warn(dev->dev, "Overwriting IRQ polarity to active %s by module-param\n", + dev->irq_active_low ? "low" : "high"); + } else { + dmi_id = dmi_first_match(bcm_active_low_irq_dmi_table); + if (dmi_id) { + dev_warn(dev->dev, "%s: Overwriting IRQ polarity to active low", + dmi_id->ident); + dev->irq_active_low = true; + } } return 0; @@ -1079,25 +1083,172 @@ static const struct hci_uart_proto bcm_proto = { #ifdef CONFIG_ACPI static const struct acpi_device_id bcm_acpi_match[] = { - { "BCM2E1A", (kernel_ulong_t)&acpi_bcm_int_last_gpios }, - { "BCM2E39", (kernel_ulong_t)&acpi_bcm_int_last_gpios }, - { "BCM2E3A", (kernel_ulong_t)&acpi_bcm_int_last_gpios }, - { "BCM2E3D", (kernel_ulong_t)&acpi_bcm_int_last_gpios }, - { "BCM2E3F", (kernel_ulong_t)&acpi_bcm_int_last_gpios }, - { "BCM2E40", (kernel_ulong_t)&acpi_bcm_int_last_gpios }, - { "BCM2E54", (kernel_ulong_t)&acpi_bcm_int_last_gpios }, - { "BCM2E55", (kernel_ulong_t)&acpi_bcm_int_last_gpios }, - { "BCM2E64", (kernel_ulong_t)&acpi_bcm_int_last_gpios }, - { "BCM2E65", (kernel_ulong_t)&acpi_bcm_int_last_gpios }, - { "BCM2E67", (kernel_ulong_t)&acpi_bcm_int_last_gpios }, - { "BCM2E71", (kernel_ulong_t)&acpi_bcm_int_last_gpios }, - { "BCM2E72", (kernel_ulong_t)&acpi_bcm_int_last_gpios }, - { "BCM2E7B", (kernel_ulong_t)&acpi_bcm_int_last_gpios }, - { "BCM2E7C", (kernel_ulong_t)&acpi_bcm_int_last_gpios }, - { "BCM2E7E", (kernel_ulong_t)&acpi_bcm_int_first_gpios }, - { "BCM2E95", (kernel_ulong_t)&acpi_bcm_int_first_gpios }, - { "BCM2E96", (kernel_ulong_t)&acpi_bcm_int_first_gpios }, - { "BCM2EA4", (kernel_ulong_t)&acpi_bcm_int_first_gpios }, + { "BCM2E00" }, + { "BCM2E01" }, + { "BCM2E02" }, + { "BCM2E03" }, + { "BCM2E04" }, + { "BCM2E05" }, + { "BCM2E06" }, + { "BCM2E07" }, + { "BCM2E08" }, + { "BCM2E09" }, + { "BCM2E0A" }, + { "BCM2E0B" }, + { "BCM2E0C" }, + { "BCM2E0D" }, + { "BCM2E0E" }, + { "BCM2E0F" }, + { "BCM2E10" }, + { "BCM2E11" }, + { "BCM2E12" }, + { "BCM2E13" }, + { "BCM2E14" }, + { "BCM2E15" }, + { "BCM2E16" }, + { "BCM2E17" }, + { "BCM2E18" }, + { "BCM2E19" }, + { "BCM2E1A" }, + { "BCM2E1B" }, + { "BCM2E1C" }, + { "BCM2E1D" }, + { "BCM2E1F" }, + { "BCM2E20" }, + { "BCM2E21" }, + { "BCM2E22" }, + { "BCM2E23" }, + { "BCM2E24" }, + { "BCM2E25" }, + { "BCM2E26" }, + { "BCM2E27" }, + { "BCM2E28" }, + { "BCM2E29" }, + { "BCM2E2A" }, + { "BCM2E2B" }, + { "BCM2E2C" }, + { "BCM2E2D" }, + { "BCM2E2E" }, + { "BCM2E2F" }, + { "BCM2E30" }, + { "BCM2E31" }, + { "BCM2E32" }, + { "BCM2E33" }, + { "BCM2E34" }, + { "BCM2E35" }, + { "BCM2E36" }, + { "BCM2E37" }, + { "BCM2E38" }, + { "BCM2E39" }, + { "BCM2E3A" }, + { "BCM2E3B" }, + { "BCM2E3C" }, + { "BCM2E3D" }, + { "BCM2E3E" }, + { "BCM2E3F" }, + { "BCM2E40" }, + { "BCM2E41" }, + { "BCM2E42" }, + { "BCM2E43" }, + { "BCM2E44" }, + { "BCM2E45" }, + { "BCM2E46" }, + { "BCM2E47" }, + { "BCM2E48" }, + { "BCM2E49" }, + { "BCM2E4A" }, + { "BCM2E4B" }, + { "BCM2E4C" }, + { "BCM2E4D" }, + { "BCM2E4E" }, + { "BCM2E4F" }, + { "BCM2E50" }, + { "BCM2E51" }, + { "BCM2E52" }, + { "BCM2E53" }, + { "BCM2E54" }, + { "BCM2E55" }, + { "BCM2E56" }, + { "BCM2E57" }, + { "BCM2E58" }, + { "BCM2E59" }, + { "BCM2E5A" }, + { "BCM2E5B" }, + { "BCM2E5C" }, + { "BCM2E5D" }, + { "BCM2E5E" }, + { "BCM2E5F" }, + { "BCM2E60" }, + { "BCM2E61" }, + { "BCM2E62" }, + { "BCM2E63" }, + { "BCM2E64" }, + { "BCM2E65" }, + { "BCM2E66" }, + { "BCM2E67" }, + { "BCM2E68" }, + { "BCM2E69" }, + { "BCM2E6B" }, + { "BCM2E6D" }, + { "BCM2E6E" }, + { "BCM2E6F" }, + { "BCM2E70" }, + { "BCM2E71" }, + { "BCM2E72" }, + { "BCM2E73" }, + { "BCM2E74" }, + { "BCM2E75" }, + { "BCM2E76" }, + { "BCM2E77" }, + { "BCM2E78" }, + { "BCM2E79" }, + { "BCM2E7A" }, + { "BCM2E7B" }, + { "BCM2E7C" }, + { "BCM2E7D" }, + { "BCM2E7E" }, + { "BCM2E7F" }, + { "BCM2E80" }, + { "BCM2E81" }, + { "BCM2E82" }, + { "BCM2E83" }, + { "BCM2E84" }, + { "BCM2E85" }, + { "BCM2E86" }, + { "BCM2E87" }, + { "BCM2E88" }, + { "BCM2E89" }, + { "BCM2E8A" }, + { "BCM2E8B" }, + { "BCM2E8C" }, + { "BCM2E8D" }, + { "BCM2E8E" }, + { "BCM2E90" }, + { "BCM2E92" }, + { "BCM2E93" }, + { "BCM2E94" }, + { "BCM2E95" }, + { "BCM2E96" }, + { "BCM2E97" }, + { "BCM2E98" }, + { "BCM2E99" }, + { "BCM2E9A" }, + { "BCM2E9B" }, + { "BCM2E9C" }, + { "BCM2E9D" }, + { "BCM2EA0" }, + { "BCM2EA1" }, + { "BCM2EA2" }, + { "BCM2EA3" }, + { "BCM2EA4" }, + { "BCM2EA5" }, + { "BCM2EA6" }, + { "BCM2EA7" }, + { "BCM2EA8" }, + { "BCM2EA9" }, + { "BCM2EAA" }, + { "BCM2EAB" }, + { "BCM2EAC" }, { }, }; MODULE_DEVICE_TABLE(acpi, bcm_acpi_match); @@ -1146,6 +1297,12 @@ static int bcm_serdev_probe(struct serdev_device *serdev) if (err) return err; + if (!bcmdev->shutdown) { + dev_warn(&serdev->dev, + "No reset resource, using default baud rate\n"); + bcmdev->oper_speed = bcmdev->init_speed; + } + err = bcm_gpio_set_power(bcmdev, false); if (err) dev_err(&serdev->dev, "Failed to power down\n"); diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c index 1b4417a623a4..27e414b4e3a2 100644 --- a/drivers/bluetooth/hci_ll.c +++ b/drivers/bluetooth/hci_ll.c @@ -67,13 +67,6 @@ #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, @@ -82,10 +75,6 @@ enum hcill_states_e { HCILL_AWAKE_TO_ASLEEP }; -struct hcill_cmd { - u8 cmd; -} __packed; - struct ll_device { struct hci_uart hu; struct serdev_device *serdev; @@ -95,8 +84,6 @@ struct ll_device { }; 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 */ @@ -113,7 +100,6 @@ 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); @@ -126,8 +112,7 @@ static int send_hcill_cmd(u8 cmd, struct hci_uart *hu) } /* prepare packet */ - hcill_packet = skb_put(skb, 1); - hcill_packet->cmd = cmd; + skb_put_u8(skb, cmd); /* send packet */ skb_queue_tail(&ll->txq, skb); @@ -379,155 +364,88 @@ static int ll_enqueue(struct hci_uart *hu, struct sk_buff *skb) return 0; } -static inline int ll_check_data_len(struct hci_dev *hdev, struct ll_struct *ll, int len) +static int ll_recv_frame(struct hci_dev *hdev, struct sk_buff *skb) { - int room = skb_tailroom(ll->rx_skb); - - BT_DBG("len %d room %d", len, room); + struct hci_uart *hu = hci_get_drvdata(hdev); + struct ll_struct *ll = hu->priv; - if (!len) { - hci_recv_frame(hdev, 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; + switch (hci_skb_pkt_type(skb)) { + case HCILL_GO_TO_SLEEP_IND: + BT_DBG("HCILL_GO_TO_SLEEP_IND packet"); + ll_device_want_to_sleep(hu); + break; + case HCILL_GO_TO_SLEEP_ACK: + /* shouldn't happen */ + bt_dev_err(hdev, "received HCILL_GO_TO_SLEEP_ACK in state %ld", + ll->hcill_state); + break; + case HCILL_WAKE_UP_IND: + BT_DBG("HCILL_WAKE_UP_IND packet"); + ll_device_want_to_wakeup(hu); + break; + case HCILL_WAKE_UP_ACK: + BT_DBG("HCILL_WAKE_UP_ACK packet"); + ll_device_woke_up(hu); + break; } - ll->rx_state = HCILL_W4_PACKET_TYPE; - ll->rx_skb = NULL; - ll->rx_count = 0; - + kfree_skb(skb); return 0; } +#define LL_RECV_SLEEP_IND \ + .type = HCILL_GO_TO_SLEEP_IND, \ + .hlen = 0, \ + .loff = 0, \ + .lsize = 0, \ + .maxlen = 0 + +#define LL_RECV_SLEEP_ACK \ + .type = HCILL_GO_TO_SLEEP_ACK, \ + .hlen = 0, \ + .loff = 0, \ + .lsize = 0, \ + .maxlen = 0 + +#define LL_RECV_WAKE_IND \ + .type = HCILL_WAKE_UP_IND, \ + .hlen = 0, \ + .loff = 0, \ + .lsize = 0, \ + .maxlen = 0 + +#define LL_RECV_WAKE_ACK \ + .type = HCILL_WAKE_UP_ACK, \ + .hlen = 0, \ + .loff = 0, \ + .lsize = 0, \ + .maxlen = 0 + +static const struct h4_recv_pkt ll_recv_pkts[] = { + { H4_RECV_ACL, .recv = hci_recv_frame }, + { H4_RECV_SCO, .recv = hci_recv_frame }, + { H4_RECV_EVENT, .recv = hci_recv_frame }, + { LL_RECV_SLEEP_IND, .recv = ll_recv_frame }, + { LL_RECV_SLEEP_ACK, .recv = ll_recv_frame }, + { LL_RECV_WAKE_IND, .recv = ll_recv_frame }, + { LL_RECV_WAKE_ACK, .recv = ll_recv_frame }, +}; + /* Recv data */ static int ll_recv(struct hci_uart *hu, const void *data, int count) { struct ll_struct *ll = hu->priv; - const char *ptr; - struct hci_event_hdr *eh; - struct hci_acl_hdr *ah; - struct hci_sco_hdr *sh; - 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); - skb_put_data(ll->rx_skb, 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(hu->hdev, ll->rx_skb); - - ll->rx_state = HCILL_W4_PACKET_TYPE; - ll->rx_skb = NULL; - continue; - - case HCILL_W4_EVENT_HDR: - eh = hci_event_hdr(ll->rx_skb); - - BT_DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen); - ll_check_data_len(hu->hdev, ll, eh->plen); - continue; + if (!test_bit(HCI_UART_REGISTERED, &hu->flags)) + return -EUNATCH; - case HCILL_W4_ACL_HDR: - ah = hci_acl_hdr(ll->rx_skb); - dlen = __le16_to_cpu(ah->dlen); - - BT_DBG("ACL header: dlen %d", dlen); - - ll_check_data_len(hu->hdev, ll, dlen); - continue; - - case HCILL_W4_SCO_HDR: - sh = hci_sco_hdr(ll->rx_skb); - - BT_DBG("SCO header: dlen %d", sh->dlen); - - ll_check_data_len(hu->hdev, 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 -ENOMEM; - } - - hci_skb_pkt_type(ll->rx_skb) = type; + ll->rx_skb = h4_recv_buf(hu->hdev, ll->rx_skb, data, count, + ll_recv_pkts, ARRAY_SIZE(ll_recv_pkts)); + if (IS_ERR(ll->rx_skb)) { + int err = PTR_ERR(ll->rx_skb); + bt_dev_err(hu->hdev, "Frame reassembly failed (%d)", err); + ll->rx_skb = NULL; + return err; } return count; @@ -650,7 +568,7 @@ static int download_firmware(struct ll_device *lldev) break; case ACTION_DELAY: /* sleep */ bt_dev_info(lldev->hu.hdev, "sleep command in scr"); - mdelay(((struct bts_action_delay *)action_ptr)->msec); + msleep(((struct bts_action_delay *)action_ptr)->msec); break; } len -= (sizeof(struct bts_action) + |