| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * |
|---|
| 3 | 4 | * Bluetooth HCI UART driver |
|---|
| .. | .. |
|---|
| 5 | 6 | * Copyright (C) 2000-2001 Qualcomm Incorporated |
|---|
| 6 | 7 | * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com> |
|---|
| 7 | 8 | * Copyright (C) 2004-2005 Marcel Holtmann <marcel@holtmann.org> |
|---|
| 8 | | - * |
|---|
| 9 | | - * |
|---|
| 10 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 11 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 12 | | - * the Free Software Foundation; either version 2 of the License, or |
|---|
| 13 | | - * (at your option) any later version. |
|---|
| 14 | | - * |
|---|
| 15 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 16 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 17 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 18 | | - * GNU General Public License for more details. |
|---|
| 19 | | - * |
|---|
| 20 | | - * You should have received a copy of the GNU General Public License |
|---|
| 21 | | - * along with this program; if not, write to the Free Software |
|---|
| 22 | | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|---|
| 23 | | - * |
|---|
| 24 | 9 | */ |
|---|
| 25 | 10 | |
|---|
| 26 | 11 | #include <linux/module.h> |
|---|
| .. | .. |
|---|
| 142 | 127 | if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) |
|---|
| 143 | 128 | goto no_schedule; |
|---|
| 144 | 129 | |
|---|
| 145 | | - if (test_and_set_bit(HCI_UART_SENDING, &hu->tx_state)) { |
|---|
| 146 | | - set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); |
|---|
| 130 | + set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); |
|---|
| 131 | + if (test_and_set_bit(HCI_UART_SENDING, &hu->tx_state)) |
|---|
| 147 | 132 | goto no_schedule; |
|---|
| 148 | | - } |
|---|
| 149 | 133 | |
|---|
| 150 | 134 | BT_DBG(""); |
|---|
| 151 | 135 | |
|---|
| .. | .. |
|---|
| 194 | 178 | kfree_skb(skb); |
|---|
| 195 | 179 | } |
|---|
| 196 | 180 | |
|---|
| 181 | + clear_bit(HCI_UART_SENDING, &hu->tx_state); |
|---|
| 197 | 182 | if (test_bit(HCI_UART_TX_WAKEUP, &hu->tx_state)) |
|---|
| 198 | 183 | goto restart; |
|---|
| 199 | 184 | |
|---|
| 200 | | - clear_bit(HCI_UART_SENDING, &hu->tx_state); |
|---|
| 185 | + wake_up_bit(&hu->tx_state, HCI_UART_SENDING); |
|---|
| 201 | 186 | } |
|---|
| 202 | 187 | |
|---|
| 203 | 188 | void hci_uart_init_work(struct work_struct *work) |
|---|
| .. | .. |
|---|
| 231 | 216 | schedule_work(&hu->init_ready); |
|---|
| 232 | 217 | |
|---|
| 233 | 218 | return 0; |
|---|
| 219 | +} |
|---|
| 220 | + |
|---|
| 221 | +int hci_uart_wait_until_sent(struct hci_uart *hu) |
|---|
| 222 | +{ |
|---|
| 223 | + return wait_on_bit_timeout(&hu->tx_state, HCI_UART_SENDING, |
|---|
| 224 | + TASK_INTERRUPTIBLE, |
|---|
| 225 | + msecs_to_jiffies(2000)); |
|---|
| 234 | 226 | } |
|---|
| 235 | 227 | |
|---|
| 236 | 228 | /* ------- Interface to HCI layer ------ */ |
|---|
| .. | .. |
|---|
| 295 | 287 | percpu_up_read(&hu->proto_lock); |
|---|
| 296 | 288 | return -EUNATCH; |
|---|
| 297 | 289 | } |
|---|
| 298 | | - |
|---|
| 299 | | - if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) |
|---|
| 300 | | - return -EUNATCH; |
|---|
| 301 | 290 | |
|---|
| 302 | 291 | hu->proto->enqueue(hu, skb); |
|---|
| 303 | 292 | percpu_up_read(&hu->proto_lock); |
|---|
| .. | .. |
|---|
| 506 | 495 | BT_ERR("Can't allocate control structure"); |
|---|
| 507 | 496 | return -ENFILE; |
|---|
| 508 | 497 | } |
|---|
| 498 | + if (percpu_init_rwsem(&hu->proto_lock)) { |
|---|
| 499 | + BT_ERR("Can't allocate semaphore structure"); |
|---|
| 500 | + kfree(hu); |
|---|
| 501 | + return -ENOMEM; |
|---|
| 502 | + } |
|---|
| 509 | 503 | |
|---|
| 510 | 504 | tty->disc_data = hu; |
|---|
| 511 | 505 | hu->tty = tty; |
|---|
| .. | .. |
|---|
| 517 | 511 | |
|---|
| 518 | 512 | INIT_WORK(&hu->init_ready, hci_uart_init_work); |
|---|
| 519 | 513 | INIT_WORK(&hu->write_work, hci_uart_write_work); |
|---|
| 520 | | - |
|---|
| 521 | | - percpu_init_rwsem(&hu->proto_lock); |
|---|
| 522 | 514 | |
|---|
| 523 | 515 | /* Flush any pending characters in the driver */ |
|---|
| 524 | 516 | tty_driver_flush_buffer(tty); |
|---|
| .. | .. |
|---|
| 817 | 809 | * We don't provide read/write/poll interface for user space. |
|---|
| 818 | 810 | */ |
|---|
| 819 | 811 | static ssize_t hci_uart_tty_read(struct tty_struct *tty, struct file *file, |
|---|
| 820 | | - unsigned char __user *buf, size_t nr) |
|---|
| 812 | + unsigned char *buf, size_t nr, |
|---|
| 813 | + void **cookie, unsigned long offset) |
|---|
| 821 | 814 | { |
|---|
| 822 | 815 | return 0; |
|---|
| 823 | 816 | } |
|---|
| .. | .. |
|---|
| 834 | 827 | return 0; |
|---|
| 835 | 828 | } |
|---|
| 836 | 829 | |
|---|
| 830 | +static struct tty_ldisc_ops hci_uart_ldisc = { |
|---|
| 831 | + .owner = THIS_MODULE, |
|---|
| 832 | + .magic = TTY_LDISC_MAGIC, |
|---|
| 833 | + .name = "n_hci", |
|---|
| 834 | + .open = hci_uart_tty_open, |
|---|
| 835 | + .close = hci_uart_tty_close, |
|---|
| 836 | + .read = hci_uart_tty_read, |
|---|
| 837 | + .write = hci_uart_tty_write, |
|---|
| 838 | + .ioctl = hci_uart_tty_ioctl, |
|---|
| 839 | + .compat_ioctl = hci_uart_tty_ioctl, |
|---|
| 840 | + .poll = hci_uart_tty_poll, |
|---|
| 841 | + .receive_buf = hci_uart_tty_receive, |
|---|
| 842 | + .write_wakeup = hci_uart_tty_wakeup, |
|---|
| 843 | +}; |
|---|
| 844 | + |
|---|
| 837 | 845 | static int __init hci_uart_init(void) |
|---|
| 838 | 846 | { |
|---|
| 839 | | - static struct tty_ldisc_ops hci_uart_ldisc; |
|---|
| 840 | 847 | int err; |
|---|
| 841 | 848 | |
|---|
| 842 | 849 | BT_INFO("HCI UART driver ver %s", VERSION); |
|---|
| 843 | 850 | |
|---|
| 844 | 851 | /* Register the tty discipline */ |
|---|
| 845 | | - |
|---|
| 846 | | - memset(&hci_uart_ldisc, 0, sizeof(hci_uart_ldisc)); |
|---|
| 847 | | - hci_uart_ldisc.magic = TTY_LDISC_MAGIC; |
|---|
| 848 | | - hci_uart_ldisc.name = "n_hci"; |
|---|
| 849 | | - hci_uart_ldisc.open = hci_uart_tty_open; |
|---|
| 850 | | - hci_uart_ldisc.close = hci_uart_tty_close; |
|---|
| 851 | | - hci_uart_ldisc.read = hci_uart_tty_read; |
|---|
| 852 | | - hci_uart_ldisc.write = hci_uart_tty_write; |
|---|
| 853 | | - hci_uart_ldisc.ioctl = hci_uart_tty_ioctl; |
|---|
| 854 | | - hci_uart_ldisc.poll = hci_uart_tty_poll; |
|---|
| 855 | | - hci_uart_ldisc.receive_buf = hci_uart_tty_receive; |
|---|
| 856 | | - hci_uart_ldisc.write_wakeup = hci_uart_tty_wakeup; |
|---|
| 857 | | - hci_uart_ldisc.owner = THIS_MODULE; |
|---|
| 858 | | - |
|---|
| 859 | 852 | err = tty_register_ldisc(N_HCI, &hci_uart_ldisc); |
|---|
| 860 | 853 | if (err) { |
|---|
| 861 | 854 | BT_ERR("HCI line discipline registration failed. (%d)", err); |
|---|