diff --git a/kernel/android-4.4/drivers/bluetooth/Kconfig b/kernel/android-4.4/drivers/bluetooth/Kconfig index ec6af15950..35952a9487 100644 --- a/kernel/android-4.4/drivers/bluetooth/Kconfig +++ b/kernel/android-4.4/drivers/bluetooth/Kconfig @@ -76,6 +76,12 @@ config BT_HCIUART Say Y here to compile support for Bluetooth UART devices into the kernel or say M to compile it as module (hci_uart). +config BT_HCIUART_SERDEV + bool + depends on SERIAL_DEV_BUS && BT_HCIUART + depends on SERIAL_DEV_BUS=y || SERIAL_DEV_BUS=BT_HCIUART + default y + config BT_HCIUART_H4 bool "UART (H4) protocol support" depends on BT_HCIUART @@ -86,6 +92,19 @@ config BT_HCIUART_H4 Say Y here to compile support for HCI UART (H4) protocol. +config BT_HCIUART_NOKIA + tristate "UART Nokia H4+ protocol support" + depends on BT_HCIUART + depends on BT_HCIUART_SERDEV + depends on PM + select BT_HCIUART_H4 + help + Nokia H4+ is serial protocol for communication between Bluetooth + device and host. This protocol is required for Bluetooth devices + with UART interface in Nokia devices. + + Say Y here to compile support for Nokia's H4+ protocol. + config BT_HCIUART_BCSP bool "BCSP protocol support" depends on BT_HCIUART @@ -113,7 +132,7 @@ config BT_HCIUART_ATH3K config BT_HCIUART_LL bool "HCILL protocol support" - depends on BT_HCIUART + depends on BT_HCIUART_SERDEV help HCILL (HCI Low Level) is a serial protocol for communication between Bluetooth device and host. This protocol is required for @@ -169,6 +188,28 @@ config BT_HCIUART_QCA Say Y here to compile support for QCA protocol. +config BT_HCIUART_AG6XX + bool "Intel AG6XX protocol support" + depends on BT_HCIUART + select BT_HCIUART_H4 + select BT_INTEL + help + The Intel/AG6XX protocol support enables Bluetooth HCI over serial + port interface for Intel ibt 2.1 Bluetooth controllers. + + Say Y here to compile support for Intel AG6XX protocol. + +config BT_HCIUART_MRVL + bool "Marvell protocol support" + depends on BT_HCIUART + select BT_HCIUART_H4 + help + Marvell is serial protocol for communication between Bluetooth + device and host. This protocol is required for most Marvell Bluetooth + devices with UART interface. + + Say Y here to compile support for HCI MRVL protocol. + config BT_HCIBCM203X tristate "HCI BCM203x USB driver" depends on USB @@ -320,4 +361,17 @@ config BT_WILINK Say Y here to compile support for Texas Instrument's WiLink7 driver into the kernel or say M to compile it as module (btwilink). +config BT_QCOMSMD + tristate "Qualcomm SMD based HCI support" + depends on RPMSG || (COMPILE_TEST && RPMSG=n) + depends on QCOM_WCNSS_CTRL || (COMPILE_TEST && QCOM_WCNSS_CTRL=n) + select BT_QCA + help + Qualcomm SMD based HCI driver. + This driver is used to bridge HCI data onto the shared memory + channels to the WCNSS core. + + Say Y here to compile support for HCI over Qualcomm SMD into the + kernel or say M to compile as a module. + endmenu diff --git a/kernel/android-4.4/drivers/bluetooth/Makefile b/kernel/android-4.4/drivers/bluetooth/Makefile index 07c9cf381e..1218bbbe5b 100644 --- a/kernel/android-4.4/drivers/bluetooth/Makefile +++ b/kernel/android-4.4/drivers/bluetooth/Makefile @@ -27,7 +27,7 @@ obj-$(CONFIG_BT_QCA) += btqca.o btmrvl-y := btmrvl_main.o btmrvl-$(CONFIG_DEBUG_FS) += btmrvl_debugfs.o -hci_uart-y := hci_ldisc.o +hci_uart-y := hci_ldisc.o hci_serdev.o hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o diff --git a/kernel/android-4.4/drivers/bluetooth/hci_ldisc.c b/kernel/android-4.4/drivers/bluetooth/hci_ldisc.c index 96bcec5598..e32a0a15f7 100644 --- a/kernel/android-4.4/drivers/bluetooth/hci_ldisc.c +++ b/kernel/android-4.4/drivers/bluetooth/hci_ldisc.c @@ -22,7 +22,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ - +#define DEBUG #include #include @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -41,6 +42,7 @@ #include #include #include +#include #include #include @@ -51,6 +53,10 @@ #define VERSION "2.3" +struct hci_ldisc_data { + unsigned long flags; + struct serdev_device *serdev; +}; static const struct hci_uart_proto *hup[HCI_UART_MAX_PROTO]; int hci_uart_register_proto(const struct hci_uart_proto *p) @@ -89,25 +95,24 @@ static const struct hci_uart_proto *hci_uart_get_proto(unsigned int id) return hup[id]; } -static inline void hci_uart_tx_complete(struct hci_uart *hu, int pkt_type) + +int hci_uart_tx_wakeup(struct hci_uart *hu) { - struct hci_dev *hdev = hu->hdev; + if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) + return 0; - /* Update HCI stat counters */ - switch (pkt_type) { - case HCI_COMMAND_PKT: - hdev->stat.cmd_tx++; - break; + if (test_and_set_bit(HCI_UART_SENDING, &hu->tx_state)) { + set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); + return 0; + } - case HCI_ACLDATA_PKT: - hdev->stat.acl_tx++; - break; + BT_DBG(""); - case HCI_SCODATA_PKT: - hdev->stat.sco_tx++; - break; - } + schedule_work(&hu->write_work); + + return 0; } +EXPORT_SYMBOL_GPL(hci_uart_tx_wakeup); static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu) { @@ -120,19 +125,24 @@ static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu) return skb; } - -int hci_uart_tx_wakeup(struct hci_uart *hu) +static inline void hci_uart_tx_complete(struct hci_uart *hu, int pkt_type) { - if (test_and_set_bit(HCI_UART_SENDING, &hu->tx_state)) { - set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); - return 0; - } + struct hci_dev *hdev = hu->hdev; - BT_DBG(""); + /* Update HCI stat counters */ + switch (pkt_type) { + case HCI_COMMAND_PKT: + hdev->stat.cmd_tx++; + break; - schedule_work(&hu->write_work); + case HCI_ACLDATA_PKT: + hdev->stat.acl_tx++; + break; - return 0; + case HCI_SCODATA_PKT: + hdev->stat.sco_tx++; + break; + } } static void hci_uart_write_work(struct work_struct *work) @@ -176,6 +186,7 @@ static void hci_uart_init_work(struct work_struct *work) { struct hci_uart *hu = container_of(work, struct hci_uart, init_ready); int err; + struct hci_dev *hdev; if (!test_and_clear_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags)) return; @@ -183,9 +194,12 @@ static void hci_uart_init_work(struct work_struct *work) err = hci_register_dev(hu->hdev); if (err < 0) { BT_ERR("Can't register HCI device"); - hci_free_dev(hu->hdev); + hdev = hu->hdev; hu->hdev = NULL; + hci_free_dev(hdev); + clear_bit(HCI_UART_PROTO_READY, &hu->flags); hu->proto->close(hu); + return; } set_bit(HCI_UART_REGISTERED, &hu->flags); @@ -458,16 +472,16 @@ static int hci_uart_tty_open(struct tty_struct *tty) hu->tty = tty; tty->receive_room = 65536; + /* disable alignment support by default */ + hu->alignment = 1; + hu->padding = 0; + INIT_WORK(&hu->init_ready, hci_uart_init_work); INIT_WORK(&hu->write_work, hci_uart_write_work); - /* Flush any pending characters in the driver and line discipline. */ + rwlock_init(&hu->proto_lock); - /* FIXME: why is this needed. Note don't use ldisc_ref here as the - open path is before the ldisc is referencable */ - - if (tty->ldisc->ops->flush_buffer) - tty->ldisc->ops->flush_buffer(tty); + /* Flush any pending characters in the driver */ tty_driver_flush_buffer(tty); return 0; @@ -482,6 +496,7 @@ static void hci_uart_tty_close(struct tty_struct *tty) { struct hci_uart *hu = tty->disc_data; struct hci_dev *hdev; + unsigned long flags; BT_DBG("tty %p", tty); @@ -497,7 +512,11 @@ static void hci_uart_tty_close(struct tty_struct *tty) cancel_work_sync(&hu->write_work); - if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) { + if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) { + write_lock_irqsave(&hu->proto_lock, flags); + clear_bit(HCI_UART_PROTO_READY, &hu->flags); + write_unlock_irqrestore(&hu->proto_lock, flags); + if (hdev) { if (test_bit(HCI_UART_REGISTERED, &hu->flags)) hci_unregister_dev(hdev); @@ -505,6 +524,7 @@ static void hci_uart_tty_close(struct tty_struct *tty) } hu->proto->close(hu); } + clear_bit(HCI_UART_PROTO_SET, &hu->flags); kfree(hu); } @@ -531,7 +551,7 @@ static void hci_uart_tty_wakeup(struct tty_struct *tty) if (tty != hu->tty) return; - if (test_bit(HCI_UART_PROTO_SET, &hu->flags)) + if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) hci_uart_tx_wakeup(hu); } @@ -555,13 +575,18 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, if (!hu || tty != hu->tty) return; - if (!test_bit(HCI_UART_PROTO_SET, &hu->flags)) + read_lock(&hu->proto_lock); + + if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) { + read_unlock(&hu->proto_lock); return; + } /* It does not need a lock here as it is already protected by a mutex in * tty caller */ hu->proto->recv(hu, data, count); + read_unlock(&hu->proto_lock); if (hu->hdev) hu->hdev->stat.byte_rx += count; @@ -620,6 +645,7 @@ static int hci_uart_register_dev(struct hci_uart *hu) if (hci_register_dev(hdev) < 0) { BT_ERR("Can't register HCI device"); + hu->hdev = NULL; hci_free_dev(hdev); return -ENODEV; } @@ -643,9 +669,11 @@ static int hci_uart_set_proto(struct hci_uart *hu, int id) return err; hu->proto = p; + set_bit(HCI_UART_PROTO_READY, &hu->flags); err = hci_uart_register_dev(hu); if (err) { + clear_bit(HCI_UART_PROTO_READY, &hu->flags); p->close(hu); return err; } @@ -686,48 +714,51 @@ static int hci_uart_set_flags(struct hci_uart *hu, unsigned long flags) static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { - struct hci_uart *hu = tty->disc_data; + struct hci_ldisc_data *ld_data = tty->disc_data; int err = 0; BT_DBG(""); /* Verify the status of the device */ - if (!hu) + if (!ld_data) return -EBADF; switch (cmd) { case HCIUARTSETPROTO: - if (!test_and_set_bit(HCI_UART_PROTO_SET, &hu->flags)) { - err = hci_uart_set_proto(hu, arg); - if (err) { - clear_bit(HCI_UART_PROTO_SET, &hu->flags); - return err; - } - } else - return -EBUSY; - break; + if (!test_and_set_bit(HCI_UART_PROTO_SET, &ld_data->flags)) { + struct serdev_device *serdev = ld_data->serdev; - case HCIUARTGETPROTO: - if (test_bit(HCI_UART_PROTO_SET, &hu->flags)) - return hu->proto->id; - return -EUNATCH; + if (arg == HCI_UART_LL) + serdev->driver_override = "hci-ti"; + + //HACK + serdev->dev.of_node = of_find_compatible_node(NULL, NULL, "ti,wl1835-st"); + err = serdev_device_add(serdev); + if (err) + clear_bit(HCI_UART_PROTO_SET, &ld_data->flags); + } else + err = -EBUSY; + break; +#if 0 case HCIUARTGETDEVICE: if (test_bit(HCI_UART_REGISTERED, &hu->flags)) - return hu->hdev->id; - return -EUNATCH; + err = hu->hdev->id; + else + err = -EUNATCH; + break; case HCIUARTSETFLAGS: if (test_bit(HCI_UART_PROTO_SET, &hu->flags)) - return -EBUSY; - err = hci_uart_set_flags(hu, arg); - if (err) - return err; + err = -EBUSY; + else + err = hci_uart_set_flags(hu, arg); break; case HCIUARTGETFLAGS: - return hu->hdev_flags; - + err = hu->hdev_flags; + break; +#endif default: err = n_tty_ioctl_helper(tty, file, cmd, arg); break; @@ -785,31 +816,6 @@ static int __init hci_uart_init(void) return err; } -#ifdef CONFIG_BT_HCIUART_H4 - h4_init(); -#endif -#ifdef CONFIG_BT_HCIUART_BCSP - bcsp_init(); -#endif -#ifdef CONFIG_BT_HCIUART_LL - ll_init(); -#endif -#ifdef CONFIG_BT_HCIUART_ATH3K - ath_init(); -#endif -#ifdef CONFIG_BT_HCIUART_3WIRE - h5_init(); -#endif -#ifdef CONFIG_BT_HCIUART_INTEL - intel_init(); -#endif -#ifdef CONFIG_BT_HCIUART_BCM - bcm_init(); -#endif -#ifdef CONFIG_BT_HCIUART_QCA - qca_init(); -#endif - return 0; } @@ -817,31 +823,6 @@ static void __exit hci_uart_exit(void) { int err; -#ifdef CONFIG_BT_HCIUART_H4 - h4_deinit(); -#endif -#ifdef CONFIG_BT_HCIUART_BCSP - bcsp_deinit(); -#endif -#ifdef CONFIG_BT_HCIUART_LL - ll_deinit(); -#endif -#ifdef CONFIG_BT_HCIUART_ATH3K - ath_deinit(); -#endif -#ifdef CONFIG_BT_HCIUART_3WIRE - h5_deinit(); -#endif -#ifdef CONFIG_BT_HCIUART_INTEL - intel_deinit(); -#endif -#ifdef CONFIG_BT_HCIUART_BCM - bcm_deinit(); -#endif -#ifdef CONFIG_BT_HCIUART_QCA - qca_deinit(); -#endif - /* Release tty registration of line discipline */ err = tty_unregister_ldisc(N_HCI); if (err) diff --git a/kernel/android-4.4/drivers/bluetooth/hci_ll.c b/kernel/android-4.4/drivers/bluetooth/hci_ll.c index 9ee24b075f..ff3830c2ab 100644 --- a/kernel/android-4.4/drivers/bluetooth/hci_ll.c +++ b/kernel/android-4.4/drivers/bluetooth/hci_ll.c @@ -34,20 +34,25 @@ #include #include #include +#include #include #include #include #include -#include #include #include #include #include +#include +#include #include +#include +#include #include #include +#include #include "hci_uart.h" @@ -76,6 +81,13 @@ struct hcill_cmd { u8 cmd; } __packed; +struct ll_device { + struct hci_uart hu; + struct serdev_device *serdev; + struct gpio_desc *enable_gpio; + struct clk *ext_clk; +}; + struct ll_struct { unsigned long rx_state; unsigned long rx_count; @@ -108,7 +120,7 @@ static int send_hcill_cmd(u8 cmd, struct hci_uart *hu) } /* prepare packet */ - hcill_packet = (struct hcill_cmd *) skb_put(skb, 1); + hcill_packet = skb_put(skb, 1); hcill_packet->cmd = cmd; /* send packet */ @@ -136,6 +148,13 @@ static int ll_open(struct hci_uart *hu) hu->priv = ll; + if (hu->serdev) { + struct ll_device *lldev = serdev_device_get_drvdata(hu->serdev); + serdev_device_open(hu->serdev); + if (!IS_ERR(lldev->ext_clk)) + clk_prepare_enable(lldev->ext_clk); + } + return 0; } @@ -164,6 +183,15 @@ static int ll_close(struct hci_uart *hu) kfree_skb(ll->rx_skb); + if (hu->serdev) { + struct ll_device *lldev = serdev_device_get_drvdata(hu->serdev); + gpiod_set_value_cansleep(lldev->enable_gpio, 0); + + clk_disable_unprepare(lldev->ext_clk); + + serdev_device_close(hu->serdev); + } + hu->priv = NULL; kfree(ll); @@ -386,6 +414,7 @@ static int ll_recv(struct hci_uart *hu, const void *data, int count) if (ll->rx_count) { len = min_t(unsigned int, ll->rx_count, count); memcpy(skb_put(ll->rx_skb, len), ptr, len); + ll->rx_count -= len; count -= len; ptr += len; if (ll->rx_count) @@ -505,9 +534,249 @@ static struct sk_buff *ll_dequeue(struct hci_uart *hu) return skb_dequeue(&ll->txq); } +static int read_local_version(struct hci_dev *hdev) +{ + int err = 0; + unsigned short version = 0; + struct sk_buff *skb; + struct hci_rp_read_local_version *ver; + + skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + bt_dev_err(hdev, "Reading TI version information failed (%ld)", + PTR_ERR(skb)); + return PTR_ERR(skb); + } + if (skb->len != sizeof(*ver)) { + err = -EILSEQ; + goto out; + } + + ver = (struct hci_rp_read_local_version *)skb->data; + if (le16_to_cpu(ver->manufacturer) != 13) { + err = -ENODEV; + goto out; + } + + version = le16_to_cpu(ver->lmp_subver); + +out: + if (err) bt_dev_err(hdev, "Failed to read TI version info: %d", err); + kfree_skb(skb); + return err ? err : version; +} + +/** + * download_firmware - + * internal function which parses through the .bts firmware + * script file intreprets SEND, DELAY actions only as of now + */ +static int download_firmware(struct ll_device *lldev) +{ + unsigned short chip, min_ver, maj_ver; + int version, err, len; + unsigned char *ptr, *action_ptr; + unsigned char bts_scr_name[40]; /* 40 char long bts scr name? */ + const struct firmware *fw; + struct sk_buff *skb; + struct hci_command *cmd; + + version = read_local_version(lldev->hu.hdev); + if (version < 0) + return version; + + chip = (version & 0x7C00) >> 10; + min_ver = (version & 0x007F); + maj_ver = (version & 0x0380) >> 7; + if (version & 0x8000) + maj_ver |= 0x0008; + + snprintf(bts_scr_name, sizeof(bts_scr_name), + "ti-connectivity/TIInit_%d.%d.%d.bts", + chip, maj_ver, min_ver); + + err = request_firmware(&fw, bts_scr_name, &lldev->serdev->dev); + if (err || !fw->data || !fw->size) { + bt_dev_err(lldev->hu.hdev, "request_firmware failed(errno %d) for %s", + err, bts_scr_name); + return -EINVAL; + } + ptr = (void *)fw->data; + len = fw->size; + /* bts_header to remove out magic number and + * version + */ + ptr += sizeof(struct bts_header); + len -= sizeof(struct bts_header); + + while (len > 0 && ptr) { + bt_dev_dbg(lldev->hu.hdev, " action size %d, type %d ", + ((struct bts_action *)ptr)->size, + ((struct bts_action *)ptr)->type); + + action_ptr = &(((struct bts_action *)ptr)->data[0]); + + switch (((struct bts_action *)ptr)->type) { + case ACTION_SEND_COMMAND: /* action send */ + bt_dev_dbg(lldev->hu.hdev, "S"); + cmd = (struct hci_command *)action_ptr; + if (cmd->opcode == 0xff36) { + /* ignore remote change + * baud rate HCI VS command */ + bt_dev_warn(lldev->hu.hdev, "change remote baud rate command in firmware"); + break; + } + if (cmd->prefix != 1) + bt_dev_dbg(lldev->hu.hdev, "command type %d\n", cmd->prefix); + + skb = __hci_cmd_sync(lldev->hu.hdev, cmd->opcode, cmd->plen, &cmd->speed, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + bt_dev_err(lldev->hu.hdev, "send command failed\n"); + err = PTR_ERR(skb); + goto out_rel_fw; + } + kfree_skb(skb); + break; + case ACTION_WAIT_EVENT: /* wait */ + /* no need to wait as command was synchronous */ + bt_dev_dbg(lldev->hu.hdev, "W"); + break; + case ACTION_DELAY: /* sleep */ + bt_dev_info(lldev->hu.hdev, "sleep command in scr"); + mdelay(((struct bts_action_delay *)action_ptr)->msec); + break; + } + len -= (sizeof(struct bts_action) + + ((struct bts_action *)ptr)->size); + ptr += sizeof(struct bts_action) + + ((struct bts_action *)ptr)->size; + } + +out_rel_fw: + /* fw download complete */ + release_firmware(fw); + return err; +} + +static int ll_setup(struct hci_uart *hu) +{ + int err, retry = 3; + struct ll_device *lldev; + struct serdev_device *serdev = hu->serdev; + u32 speed; + + if (!serdev) + return 0; + + lldev = serdev_device_get_drvdata(serdev); + + serdev_device_set_flow_control(serdev, true); + + do { + /* Configure BT_EN to HIGH state */ + gpiod_set_value_cansleep(lldev->enable_gpio, 0); + msleep(5); + gpiod_set_value_cansleep(lldev->enable_gpio, 1); + msleep(100); + + err = download_firmware(lldev); + if (!err) + break; + + /* Toggle BT_EN and retry */ + bt_dev_err(hu->hdev, "download firmware failed, retrying..."); + } while (retry--); + + if (err) + return err; + + /* Operational speed if any */ + if (hu->oper_speed) + speed = hu->oper_speed; + else if (hu->proto->oper_speed) + speed = hu->proto->oper_speed; + else + speed = 0; + + if (speed) { + struct sk_buff *skb = __hci_cmd_sync(hu->hdev, 0xff36, sizeof(speed), &speed, HCI_INIT_TIMEOUT); + if (!IS_ERR(skb)) { + kfree_skb(skb); + serdev_device_set_baudrate(serdev, speed); + } + } + + return 0; +} + +static const struct hci_uart_proto llp; + +static int hci_ti_probe(struct serdev_device *serdev) +{ + struct hci_uart *hu; + struct ll_device *lldev; + u32 max_speed = 3000000; + + lldev = devm_kzalloc(&serdev->dev, sizeof(struct ll_device), GFP_KERNEL); + if (!lldev) + return -ENOMEM; + hu = &lldev->hu; + + serdev_device_set_drvdata(serdev, lldev); + lldev->serdev = hu->serdev = serdev; + + lldev->enable_gpio = devm_gpiod_get_optional(&serdev->dev, "enable", GPIOD_OUT_LOW); + if (IS_ERR(lldev->enable_gpio)) + return PTR_ERR(lldev->enable_gpio); + + lldev->ext_clk = devm_clk_get(&serdev->dev, "ext_clock"); + if (IS_ERR(lldev->ext_clk) && PTR_ERR(lldev->ext_clk) != -ENOENT) + return PTR_ERR(lldev->ext_clk); + + of_property_read_u32(serdev->dev.of_node, "max-speed", &max_speed); + hci_uart_set_speeds(hu, 115200, max_speed); + + return hci_uart_register_device(hu, &llp); +} + +static void hci_ti_remove(struct serdev_device *serdev) +{ + struct ll_device *lldev = serdev_device_get_drvdata(serdev); + struct hci_uart *hu = &lldev->hu; + struct hci_dev *hdev = hu->hdev; + + hci_uart_unregister_device(hdev); +} + +static const struct of_device_id hci_ti_of_match[] = { + { .compatible = "ti,wl1271-st" }, + { .compatible = "ti,wl1273-st" }, + { .compatible = "ti,wl1281-st" }, + { .compatible = "ti,wl1283-st" }, + { .compatible = "ti,wl1285-st" }, + { .compatible = "ti,wl1801-st" }, + { .compatible = "ti,wl1805-st" }, + { .compatible = "ti,wl1807-st" }, + { .compatible = "ti,wl1831-st" }, + { .compatible = "ti,wl1835-st" }, + { .compatible = "ti,wl1837-st" }, + {}, +}; +MODULE_DEVICE_TABLE(of, hci_ti_of_match); + +static struct serdev_device_driver hci_ti_drv = { + .driver = { + .name = "hci-ti", + .of_match_table = of_match_ptr(hci_ti_of_match), + }, + .probe = hci_ti_probe, + .remove = hci_ti_remove, +}; + static const struct hci_uart_proto llp = { .id = HCI_UART_LL, .name = "LL", + .setup = ll_setup, .open = ll_open, .close = ll_close, .recv = ll_recv, @@ -516,12 +785,4 @@ static const struct hci_uart_proto llp = { .flush = ll_flush, }; -int __init ll_init(void) -{ - return hci_uart_register_proto(&llp); -} - -int __exit ll_deinit(void) -{ - return hci_uart_unregister_proto(&llp); -} +module_serdev_device_driver(hci_ti_drv); diff --git a/kernel/android-4.4/drivers/bluetooth/hci_uart.h b/kernel/android-4.4/drivers/bluetooth/hci_uart.h index 82c92f1b65..3beda2665b 100644 --- a/kernel/android-4.4/drivers/bluetooth/hci_uart.h +++ b/kernel/android-4.4/drivers/bluetooth/hci_uart.h @@ -55,6 +55,7 @@ #define HCI_UART_VND_DETECT 5 struct hci_uart; +struct serdev_device; struct hci_uart_proto { unsigned int id; @@ -74,6 +75,7 @@ struct hci_uart_proto { struct hci_uart { struct tty_struct *tty; + struct serdev_device *serdev; struct hci_dev *hdev; unsigned long flags; unsigned long hdev_flags; @@ -82,6 +84,7 @@ struct hci_uart { struct work_struct write_work; const struct hci_uart_proto *proto; + rwlock_t proto_lock; /* Stop work for proto close */ void *priv; struct sk_buff *tx_skb; @@ -89,11 +92,15 @@ struct hci_uart { unsigned int init_speed; unsigned int oper_speed; + + u8 alignment; + u8 padding; }; /* HCI_UART proto flag bits */ #define HCI_UART_PROTO_SET 0 #define HCI_UART_REGISTERED 1 +#define HCI_UART_PROTO_READY 2 /* TX states */ #define HCI_UART_SENDING 1 @@ -101,6 +108,9 @@ struct hci_uart { int hci_uart_register_proto(const struct hci_uart_proto *p); int hci_uart_unregister_proto(const struct hci_uart_proto *p); +int hci_uart_register_device(struct hci_uart *hu, const struct hci_uart_proto *p); +void hci_uart_unregister_device(struct hci_dev *hu); + int hci_uart_tx_wakeup(struct hci_uart *hu); int hci_uart_init_ready(struct hci_uart *hu); void hci_uart_init_tty(struct hci_uart *hu); diff --git a/kernel/android-4.4/drivers/char/Kconfig b/kernel/android-4.4/drivers/char/Kconfig index 3143db57ce..c6c5894f1d 100644 --- a/kernel/android-4.4/drivers/char/Kconfig +++ b/kernel/android-4.4/drivers/char/Kconfig @@ -47,6 +47,7 @@ config SGI_MBCS say Y or M here, otherwise say N. source "drivers/tty/serial/Kconfig" +source "drivers/tty/serdev/Kconfig" config TTY_PRINTK tristate "TTY driver to output user messages via printk" diff --git a/kernel/android-4.4/drivers/tty/Makefile b/kernel/android-4.4/drivers/tty/Makefile index 5817e23974..f2cdb264a6 100644 --- a/kernel/android-4.4/drivers/tty/Makefile +++ b/kernel/android-4.4/drivers/tty/Makefile @@ -13,7 +13,7 @@ obj-$(CONFIG_R3964) += n_r3964.o obj-y += vt/ obj-$(CONFIG_HVC_DRIVER) += hvc/ obj-y += serial/ - +obj-y += serdev/ # tty drivers obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o obj-$(CONFIG_BFIN_JTAG_COMM) += bfin_jtag_comm.o diff --git a/kernel/android-4.4/drivers/tty/tty_port.c b/kernel/android-4.4/drivers/tty/tty_port.c index 482f33f200..31671362d0 100644 --- a/kernel/android-4.4/drivers/tty/tty_port.c +++ b/kernel/android-4.4/drivers/tty/tty_port.c @@ -16,6 +16,45 @@ #include #include #include +#include + +static int tty_port_default_receive_buf(struct tty_port *port, + const unsigned char *p, + const unsigned char *f, size_t count) +{ + int ret; + struct tty_struct *tty; + struct tty_ldisc *disc; + + tty = READ_ONCE(port->itty); + if (!tty) + return 0; + + disc = tty_ldisc_ref(tty); + if (!disc) + return 0; + + ret = tty_ldisc_receive_buf(disc, p, (char *)f, count); + + tty_ldisc_deref(disc); + + return ret; +} + +static void tty_port_default_wakeup(struct tty_port *port) +{ + struct tty_struct *tty = tty_port_tty_get(port); + + if (tty) { + tty_wakeup(tty); + tty_kref_put(tty); + } +} + +static const struct tty_port_client_operations default_client_ops = { + .receive_buf = tty_port_default_receive_buf, + .write_wakeup = tty_port_default_wakeup, +}; void tty_port_init(struct tty_port *port) { @@ -28,6 +67,7 @@ void tty_port_init(struct tty_port *port) spin_lock_init(&port->lock); port->close_delay = (50 * HZ) / 100; port->closing_wait = (3000 * HZ) / 100; + port->client_ops = &default_client_ops; kref_init(&port->kref); } EXPORT_SYMBOL(tty_port_init); @@ -67,8 +107,7 @@ struct device *tty_port_register_device(struct tty_port *port, struct tty_driver *driver, unsigned index, struct device *device) { - tty_port_link_device(port, driver, index); - return tty_register_device(driver, index, device); + return tty_port_register_device_attr(port, driver, index, device, NULL, NULL); } EXPORT_SYMBOL_GPL(tty_port_register_device); @@ -96,6 +135,80 @@ struct device *tty_port_register_device_attr(struct tty_port *port, } EXPORT_SYMBOL_GPL(tty_port_register_device_attr); +/** + * tty_port_register_device_attr_serdev - register tty or serdev device + * @port: tty_port of the device + * @driver: tty_driver for this device + * @index: index of the tty + * @device: parent if exists, otherwise NULL + * @drvdata: driver data for the device + * @attr_grp: attribute group for the device + * + * Register a serdev or tty device depending on if the parent device has any + * defined serdev clients or not. + */ +struct device *tty_port_register_device_attr_serdev(struct tty_port *port, + struct tty_driver *driver, unsigned index, + struct device *device, void *drvdata, + const struct attribute_group **attr_grp) +{ + struct device *dev; + + tty_port_link_device(port, driver, index); + + dev = serdev_tty_port_register(port, device, driver, index); + if (PTR_ERR(dev) != -ENODEV) { + /* Skip creating cdev if we registered a serdev device */ + //return dev; + } + + return tty_register_device_attr(driver, index, device, drvdata, + attr_grp); +} +EXPORT_SYMBOL_GPL(tty_port_register_device_attr_serdev); + +/** + * tty_port_register_device_serdev - register tty or serdev device + * @port: tty_port of the device + * @driver: tty_driver for this device + * @index: index of the tty + * @device: parent if exists, otherwise NULL + * + * Register a serdev or tty device depending on if the parent device has any + * defined serdev clients or not. + */ +struct device *tty_port_register_device_serdev(struct tty_port *port, + struct tty_driver *driver, unsigned index, + struct device *device) +{ + return tty_port_register_device_attr_serdev(port, driver, index, + device, NULL, NULL); +} +EXPORT_SYMBOL_GPL(tty_port_register_device_serdev); + +/** + * tty_port_unregister_device - deregister a tty or serdev device + * @port: tty_port of the device + * @driver: tty_driver for this device + * @index: index of the tty + * + * If a tty or serdev device is registered with a call to + * tty_port_register_device_serdev() then this function must be called when + * the device is gone. + */ +void tty_port_unregister_device(struct tty_port *port, + struct tty_driver *driver, unsigned index) +{ + int ret; + + ret = serdev_tty_port_unregister(port); + if (ret == 0) + return; + + tty_unregister_device(driver, index); +} +EXPORT_SYMBOL_GPL(tty_port_unregister_device); + int tty_port_alloc_xmit_buf(struct tty_port *port) { /* We may sleep in get_zeroed_page() */ @@ -204,7 +317,8 @@ static void tty_port_shutdown(struct tty_port *port, struct tty_struct *tty) if (port->console) goto out; - if (test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags)) { + if (test_bit(ASYNCB_INITIALIZED, &port->flags)) { + set_bit(ASYNCB_INITIALIZED, &port->flags); /* * Drop DTR/RTS if HUPCL is set. This causes any attached * modem to hang up the line. @@ -272,12 +386,7 @@ EXPORT_SYMBOL_GPL(tty_port_tty_hangup); */ void tty_port_tty_wakeup(struct tty_port *port) { - struct tty_struct *tty = tty_port_tty_get(port); - - if (tty) { - tty_wakeup(tty); - tty_kref_put(tty); - } + port->client_ops->write_wakeup(port); } EXPORT_SYMBOL_GPL(tty_port_tty_wakeup); @@ -334,7 +443,7 @@ EXPORT_SYMBOL(tty_port_lower_dtr_rts); * tty_port_block_til_ready - Waiting logic for tty open * @port: the tty port being opened * @tty: the tty device being bound - * @filp: the file pointer of the opener + * @filp: the file pointer of the opener or NULL * * Implement the core POSIX/SuS tty behaviour when opening a tty device. * Handles: @@ -462,14 +571,13 @@ int tty_port_close_start(struct tty_port *port, spin_lock_irqsave(&port->lock, flags); if (tty->count == 1 && port->count != 1) { - printk(KERN_WARNING - "tty_port_close_start: tty->count = 1 port count = %d.\n", - port->count); + printk(KERN_ERR "%s: tty->count = 1 port count = %d\n", __func__, + port->count); port->count = 1; } if (--port->count < 0) { - printk(KERN_WARNING "tty_port_close_start: count = %d\n", - port->count); + printk(KERN_ERR "%s: bad port count (%d)\n", __func__, + port->count); port->count = 0; } @@ -537,6 +645,7 @@ void tty_port_close(struct tty_port *port, struct tty_struct *tty, set_bit(TTY_IO_ERROR, &tty->flags); tty_port_close_end(port, tty); tty_port_tty_set(port, NULL); + port->client_ops = &default_client_ops; } EXPORT_SYMBOL(tty_port_close);