162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Bluetooth HCI UART driver 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2000-2001 Qualcomm Incorporated 762306a36Sopenharmony_ci * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com> 862306a36Sopenharmony_ci * Copyright (C) 2004-2005 Marcel Holtmann <marcel@holtmann.org> 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/kernel.h> 1462306a36Sopenharmony_ci#include <linux/init.h> 1562306a36Sopenharmony_ci#include <linux/types.h> 1662306a36Sopenharmony_ci#include <linux/fcntl.h> 1762306a36Sopenharmony_ci#include <linux/interrupt.h> 1862306a36Sopenharmony_ci#include <linux/ptrace.h> 1962306a36Sopenharmony_ci#include <linux/poll.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include <linux/slab.h> 2262306a36Sopenharmony_ci#include <linux/tty.h> 2362306a36Sopenharmony_ci#include <linux/errno.h> 2462306a36Sopenharmony_ci#include <linux/string.h> 2562306a36Sopenharmony_ci#include <linux/signal.h> 2662306a36Sopenharmony_ci#include <linux/ioctl.h> 2762306a36Sopenharmony_ci#include <linux/skbuff.h> 2862306a36Sopenharmony_ci#include <linux/firmware.h> 2962306a36Sopenharmony_ci#include <linux/serdev.h> 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#include <net/bluetooth/bluetooth.h> 3262306a36Sopenharmony_ci#include <net/bluetooth/hci_core.h> 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#include "btintel.h" 3562306a36Sopenharmony_ci#include "btbcm.h" 3662306a36Sopenharmony_ci#include "hci_uart.h" 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#define VERSION "2.3" 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic const struct hci_uart_proto *hup[HCI_UART_MAX_PROTO]; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ciint hci_uart_register_proto(const struct hci_uart_proto *p) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci if (p->id >= HCI_UART_MAX_PROTO) 4562306a36Sopenharmony_ci return -EINVAL; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci if (hup[p->id]) 4862306a36Sopenharmony_ci return -EEXIST; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci hup[p->id] = p; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci BT_INFO("HCI UART protocol %s registered", p->name); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci return 0; 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ciint hci_uart_unregister_proto(const struct hci_uart_proto *p) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci if (p->id >= HCI_UART_MAX_PROTO) 6062306a36Sopenharmony_ci return -EINVAL; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci if (!hup[p->id]) 6362306a36Sopenharmony_ci return -EINVAL; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci hup[p->id] = NULL; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci return 0; 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic const struct hci_uart_proto *hci_uart_get_proto(unsigned int id) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci if (id >= HCI_UART_MAX_PROTO) 7362306a36Sopenharmony_ci return NULL; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci return hup[id]; 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic inline void hci_uart_tx_complete(struct hci_uart *hu, int pkt_type) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci struct hci_dev *hdev = hu->hdev; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci /* Update HCI stat counters */ 8362306a36Sopenharmony_ci switch (pkt_type) { 8462306a36Sopenharmony_ci case HCI_COMMAND_PKT: 8562306a36Sopenharmony_ci hdev->stat.cmd_tx++; 8662306a36Sopenharmony_ci break; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci case HCI_ACLDATA_PKT: 8962306a36Sopenharmony_ci hdev->stat.acl_tx++; 9062306a36Sopenharmony_ci break; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci case HCI_SCODATA_PKT: 9362306a36Sopenharmony_ci hdev->stat.sco_tx++; 9462306a36Sopenharmony_ci break; 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci struct sk_buff *skb = hu->tx_skb; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci if (!skb) { 10362306a36Sopenharmony_ci percpu_down_read(&hu->proto_lock); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) 10662306a36Sopenharmony_ci skb = hu->proto->dequeue(hu); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci percpu_up_read(&hu->proto_lock); 10962306a36Sopenharmony_ci } else { 11062306a36Sopenharmony_ci hu->tx_skb = NULL; 11162306a36Sopenharmony_ci } 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci return skb; 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ciint hci_uart_tx_wakeup(struct hci_uart *hu) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci /* This may be called in an IRQ context, so we can't sleep. Therefore 11962306a36Sopenharmony_ci * we try to acquire the lock only, and if that fails we assume the 12062306a36Sopenharmony_ci * tty is being closed because that is the only time the write lock is 12162306a36Sopenharmony_ci * acquired. If, however, at some point in the future the write lock 12262306a36Sopenharmony_ci * is also acquired in other situations, then this must be revisited. 12362306a36Sopenharmony_ci */ 12462306a36Sopenharmony_ci if (!percpu_down_read_trylock(&hu->proto_lock)) 12562306a36Sopenharmony_ci return 0; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) 12862306a36Sopenharmony_ci goto no_schedule; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); 13162306a36Sopenharmony_ci if (test_and_set_bit(HCI_UART_SENDING, &hu->tx_state)) 13262306a36Sopenharmony_ci goto no_schedule; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci BT_DBG(""); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci schedule_work(&hu->write_work); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cino_schedule: 13962306a36Sopenharmony_ci percpu_up_read(&hu->proto_lock); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci return 0; 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(hci_uart_tx_wakeup); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic void hci_uart_write_work(struct work_struct *work) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci struct hci_uart *hu = container_of(work, struct hci_uart, write_work); 14862306a36Sopenharmony_ci struct tty_struct *tty = hu->tty; 14962306a36Sopenharmony_ci struct hci_dev *hdev = hu->hdev; 15062306a36Sopenharmony_ci struct sk_buff *skb; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci /* REVISIT: should we cope with bad skbs or ->write() returning 15362306a36Sopenharmony_ci * and error value ? 15462306a36Sopenharmony_ci */ 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_cirestart: 15762306a36Sopenharmony_ci clear_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci while ((skb = hci_uart_dequeue(hu))) { 16062306a36Sopenharmony_ci int len; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); 16362306a36Sopenharmony_ci len = tty->ops->write(tty, skb->data, skb->len); 16462306a36Sopenharmony_ci hdev->stat.byte_tx += len; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci skb_pull(skb, len); 16762306a36Sopenharmony_ci if (skb->len) { 16862306a36Sopenharmony_ci hu->tx_skb = skb; 16962306a36Sopenharmony_ci break; 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci hci_uart_tx_complete(hu, hci_skb_pkt_type(skb)); 17362306a36Sopenharmony_ci kfree_skb(skb); 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci clear_bit(HCI_UART_SENDING, &hu->tx_state); 17762306a36Sopenharmony_ci if (test_bit(HCI_UART_TX_WAKEUP, &hu->tx_state)) 17862306a36Sopenharmony_ci goto restart; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci wake_up_bit(&hu->tx_state, HCI_UART_SENDING); 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_civoid hci_uart_init_work(struct work_struct *work) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci struct hci_uart *hu = container_of(work, struct hci_uart, init_ready); 18662306a36Sopenharmony_ci int err; 18762306a36Sopenharmony_ci struct hci_dev *hdev; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci if (!test_and_clear_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags)) 19062306a36Sopenharmony_ci return; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci err = hci_register_dev(hu->hdev); 19362306a36Sopenharmony_ci if (err < 0) { 19462306a36Sopenharmony_ci BT_ERR("Can't register HCI device"); 19562306a36Sopenharmony_ci clear_bit(HCI_UART_PROTO_READY, &hu->flags); 19662306a36Sopenharmony_ci hu->proto->close(hu); 19762306a36Sopenharmony_ci hdev = hu->hdev; 19862306a36Sopenharmony_ci hu->hdev = NULL; 19962306a36Sopenharmony_ci hci_free_dev(hdev); 20062306a36Sopenharmony_ci return; 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci set_bit(HCI_UART_REGISTERED, &hu->flags); 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ciint hci_uart_init_ready(struct hci_uart *hu) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci if (!test_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags)) 20962306a36Sopenharmony_ci return -EALREADY; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci schedule_work(&hu->init_ready); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci return 0; 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ciint hci_uart_wait_until_sent(struct hci_uart *hu) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci return wait_on_bit_timeout(&hu->tx_state, HCI_UART_SENDING, 21962306a36Sopenharmony_ci TASK_INTERRUPTIBLE, 22062306a36Sopenharmony_ci msecs_to_jiffies(2000)); 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci/* ------- Interface to HCI layer ------ */ 22462306a36Sopenharmony_ci/* Reset device */ 22562306a36Sopenharmony_cistatic int hci_uart_flush(struct hci_dev *hdev) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci struct hci_uart *hu = hci_get_drvdata(hdev); 22862306a36Sopenharmony_ci struct tty_struct *tty = hu->tty; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci BT_DBG("hdev %p tty %p", hdev, tty); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci if (hu->tx_skb) { 23362306a36Sopenharmony_ci kfree_skb(hu->tx_skb); hu->tx_skb = NULL; 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci /* Flush any pending characters in the driver and discipline. */ 23762306a36Sopenharmony_ci tty_ldisc_flush(tty); 23862306a36Sopenharmony_ci tty_driver_flush_buffer(tty); 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci percpu_down_read(&hu->proto_lock); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) 24362306a36Sopenharmony_ci hu->proto->flush(hu); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci percpu_up_read(&hu->proto_lock); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci return 0; 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci/* Initialize device */ 25162306a36Sopenharmony_cistatic int hci_uart_open(struct hci_dev *hdev) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci BT_DBG("%s %p", hdev->name, hdev); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci /* Undo clearing this from hci_uart_close() */ 25662306a36Sopenharmony_ci hdev->flush = hci_uart_flush; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci return 0; 25962306a36Sopenharmony_ci} 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci/* Close device */ 26262306a36Sopenharmony_cistatic int hci_uart_close(struct hci_dev *hdev) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci BT_DBG("hdev %p", hdev); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci hci_uart_flush(hdev); 26762306a36Sopenharmony_ci hdev->flush = NULL; 26862306a36Sopenharmony_ci return 0; 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci/* Send frames from HCI layer */ 27262306a36Sopenharmony_cistatic int hci_uart_send_frame(struct hci_dev *hdev, struct sk_buff *skb) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci struct hci_uart *hu = hci_get_drvdata(hdev); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci BT_DBG("%s: type %d len %d", hdev->name, hci_skb_pkt_type(skb), 27762306a36Sopenharmony_ci skb->len); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci percpu_down_read(&hu->proto_lock); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) { 28262306a36Sopenharmony_ci percpu_up_read(&hu->proto_lock); 28362306a36Sopenharmony_ci return -EUNATCH; 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci hu->proto->enqueue(hu, skb); 28762306a36Sopenharmony_ci percpu_up_read(&hu->proto_lock); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci hci_uart_tx_wakeup(hu); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci return 0; 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci/* Check the underlying device or tty has flow control support */ 29562306a36Sopenharmony_cibool hci_uart_has_flow_control(struct hci_uart *hu) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci /* serdev nodes check if the needed operations are present */ 29862306a36Sopenharmony_ci if (hu->serdev) 29962306a36Sopenharmony_ci return true; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci if (hu->tty->driver->ops->tiocmget && hu->tty->driver->ops->tiocmset) 30262306a36Sopenharmony_ci return true; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci return false; 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci/* Flow control or un-flow control the device */ 30862306a36Sopenharmony_civoid hci_uart_set_flow_control(struct hci_uart *hu, bool enable) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci struct tty_struct *tty = hu->tty; 31162306a36Sopenharmony_ci struct ktermios ktermios; 31262306a36Sopenharmony_ci int status; 31362306a36Sopenharmony_ci unsigned int set = 0; 31462306a36Sopenharmony_ci unsigned int clear = 0; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci if (hu->serdev) { 31762306a36Sopenharmony_ci serdev_device_set_flow_control(hu->serdev, !enable); 31862306a36Sopenharmony_ci serdev_device_set_rts(hu->serdev, !enable); 31962306a36Sopenharmony_ci return; 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci if (enable) { 32362306a36Sopenharmony_ci /* Disable hardware flow control */ 32462306a36Sopenharmony_ci ktermios = tty->termios; 32562306a36Sopenharmony_ci ktermios.c_cflag &= ~CRTSCTS; 32662306a36Sopenharmony_ci tty_set_termios(tty, &ktermios); 32762306a36Sopenharmony_ci BT_DBG("Disabling hardware flow control: %s", 32862306a36Sopenharmony_ci (tty->termios.c_cflag & CRTSCTS) ? "failed" : "success"); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci /* Clear RTS to prevent the device from sending */ 33162306a36Sopenharmony_ci /* Most UARTs need OUT2 to enable interrupts */ 33262306a36Sopenharmony_ci status = tty->driver->ops->tiocmget(tty); 33362306a36Sopenharmony_ci BT_DBG("Current tiocm 0x%x", status); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci set &= ~(TIOCM_OUT2 | TIOCM_RTS); 33662306a36Sopenharmony_ci clear = ~set; 33762306a36Sopenharmony_ci set &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 | 33862306a36Sopenharmony_ci TIOCM_OUT2 | TIOCM_LOOP; 33962306a36Sopenharmony_ci clear &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 | 34062306a36Sopenharmony_ci TIOCM_OUT2 | TIOCM_LOOP; 34162306a36Sopenharmony_ci status = tty->driver->ops->tiocmset(tty, set, clear); 34262306a36Sopenharmony_ci BT_DBG("Clearing RTS: %s", status ? "failed" : "success"); 34362306a36Sopenharmony_ci } else { 34462306a36Sopenharmony_ci /* Set RTS to allow the device to send again */ 34562306a36Sopenharmony_ci status = tty->driver->ops->tiocmget(tty); 34662306a36Sopenharmony_ci BT_DBG("Current tiocm 0x%x", status); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci set |= (TIOCM_OUT2 | TIOCM_RTS); 34962306a36Sopenharmony_ci clear = ~set; 35062306a36Sopenharmony_ci set &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 | 35162306a36Sopenharmony_ci TIOCM_OUT2 | TIOCM_LOOP; 35262306a36Sopenharmony_ci clear &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 | 35362306a36Sopenharmony_ci TIOCM_OUT2 | TIOCM_LOOP; 35462306a36Sopenharmony_ci status = tty->driver->ops->tiocmset(tty, set, clear); 35562306a36Sopenharmony_ci BT_DBG("Setting RTS: %s", status ? "failed" : "success"); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci /* Re-enable hardware flow control */ 35862306a36Sopenharmony_ci ktermios = tty->termios; 35962306a36Sopenharmony_ci ktermios.c_cflag |= CRTSCTS; 36062306a36Sopenharmony_ci tty_set_termios(tty, &ktermios); 36162306a36Sopenharmony_ci BT_DBG("Enabling hardware flow control: %s", 36262306a36Sopenharmony_ci !(tty->termios.c_cflag & CRTSCTS) ? "failed" : "success"); 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci} 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_civoid hci_uart_set_speeds(struct hci_uart *hu, unsigned int init_speed, 36762306a36Sopenharmony_ci unsigned int oper_speed) 36862306a36Sopenharmony_ci{ 36962306a36Sopenharmony_ci hu->init_speed = init_speed; 37062306a36Sopenharmony_ci hu->oper_speed = oper_speed; 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_civoid hci_uart_set_baudrate(struct hci_uart *hu, unsigned int speed) 37462306a36Sopenharmony_ci{ 37562306a36Sopenharmony_ci struct tty_struct *tty = hu->tty; 37662306a36Sopenharmony_ci struct ktermios ktermios; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci ktermios = tty->termios; 37962306a36Sopenharmony_ci ktermios.c_cflag &= ~CBAUD; 38062306a36Sopenharmony_ci tty_termios_encode_baud_rate(&ktermios, speed, speed); 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci /* tty_set_termios() return not checked as it is always 0 */ 38362306a36Sopenharmony_ci tty_set_termios(tty, &ktermios); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci BT_DBG("%s: New tty speeds: %d/%d", hu->hdev->name, 38662306a36Sopenharmony_ci tty->termios.c_ispeed, tty->termios.c_ospeed); 38762306a36Sopenharmony_ci} 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_cistatic int hci_uart_setup(struct hci_dev *hdev) 39062306a36Sopenharmony_ci{ 39162306a36Sopenharmony_ci struct hci_uart *hu = hci_get_drvdata(hdev); 39262306a36Sopenharmony_ci struct hci_rp_read_local_version *ver; 39362306a36Sopenharmony_ci struct sk_buff *skb; 39462306a36Sopenharmony_ci unsigned int speed; 39562306a36Sopenharmony_ci int err; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci /* Init speed if any */ 39862306a36Sopenharmony_ci if (hu->init_speed) 39962306a36Sopenharmony_ci speed = hu->init_speed; 40062306a36Sopenharmony_ci else if (hu->proto->init_speed) 40162306a36Sopenharmony_ci speed = hu->proto->init_speed; 40262306a36Sopenharmony_ci else 40362306a36Sopenharmony_ci speed = 0; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci if (speed) 40662306a36Sopenharmony_ci hci_uart_set_baudrate(hu, speed); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci /* Operational speed if any */ 40962306a36Sopenharmony_ci if (hu->oper_speed) 41062306a36Sopenharmony_ci speed = hu->oper_speed; 41162306a36Sopenharmony_ci else if (hu->proto->oper_speed) 41262306a36Sopenharmony_ci speed = hu->proto->oper_speed; 41362306a36Sopenharmony_ci else 41462306a36Sopenharmony_ci speed = 0; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci if (hu->proto->set_baudrate && speed) { 41762306a36Sopenharmony_ci err = hu->proto->set_baudrate(hu, speed); 41862306a36Sopenharmony_ci if (!err) 41962306a36Sopenharmony_ci hci_uart_set_baudrate(hu, speed); 42062306a36Sopenharmony_ci } 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci if (hu->proto->setup) 42362306a36Sopenharmony_ci return hu->proto->setup(hu); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci if (!test_bit(HCI_UART_VND_DETECT, &hu->hdev_flags)) 42662306a36Sopenharmony_ci return 0; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL, 42962306a36Sopenharmony_ci HCI_INIT_TIMEOUT); 43062306a36Sopenharmony_ci if (IS_ERR(skb)) { 43162306a36Sopenharmony_ci BT_ERR("%s: Reading local version information failed (%ld)", 43262306a36Sopenharmony_ci hdev->name, PTR_ERR(skb)); 43362306a36Sopenharmony_ci return 0; 43462306a36Sopenharmony_ci } 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci if (skb->len != sizeof(*ver)) { 43762306a36Sopenharmony_ci BT_ERR("%s: Event length mismatch for version information", 43862306a36Sopenharmony_ci hdev->name); 43962306a36Sopenharmony_ci goto done; 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci ver = (struct hci_rp_read_local_version *)skb->data; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci switch (le16_to_cpu(ver->manufacturer)) { 44562306a36Sopenharmony_ci#ifdef CONFIG_BT_HCIUART_INTEL 44662306a36Sopenharmony_ci case 2: 44762306a36Sopenharmony_ci hdev->set_bdaddr = btintel_set_bdaddr; 44862306a36Sopenharmony_ci btintel_check_bdaddr(hdev); 44962306a36Sopenharmony_ci break; 45062306a36Sopenharmony_ci#endif 45162306a36Sopenharmony_ci#ifdef CONFIG_BT_HCIUART_BCM 45262306a36Sopenharmony_ci case 15: 45362306a36Sopenharmony_ci hdev->set_bdaddr = btbcm_set_bdaddr; 45462306a36Sopenharmony_ci btbcm_check_bdaddr(hdev); 45562306a36Sopenharmony_ci break; 45662306a36Sopenharmony_ci#endif 45762306a36Sopenharmony_ci default: 45862306a36Sopenharmony_ci break; 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_cidone: 46262306a36Sopenharmony_ci kfree_skb(skb); 46362306a36Sopenharmony_ci return 0; 46462306a36Sopenharmony_ci} 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci/* ------ LDISC part ------ */ 46762306a36Sopenharmony_ci/* hci_uart_tty_open 46862306a36Sopenharmony_ci * 46962306a36Sopenharmony_ci * Called when line discipline changed to HCI_UART. 47062306a36Sopenharmony_ci * 47162306a36Sopenharmony_ci * Arguments: 47262306a36Sopenharmony_ci * tty pointer to tty info structure 47362306a36Sopenharmony_ci * Return Value: 47462306a36Sopenharmony_ci * 0 if success, otherwise error code 47562306a36Sopenharmony_ci */ 47662306a36Sopenharmony_cistatic int hci_uart_tty_open(struct tty_struct *tty) 47762306a36Sopenharmony_ci{ 47862306a36Sopenharmony_ci struct hci_uart *hu; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci BT_DBG("tty %p", tty); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci if (!capable(CAP_NET_ADMIN)) 48362306a36Sopenharmony_ci return -EPERM; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci /* Error if the tty has no write op instead of leaving an exploitable 48662306a36Sopenharmony_ci * hole 48762306a36Sopenharmony_ci */ 48862306a36Sopenharmony_ci if (tty->ops->write == NULL) 48962306a36Sopenharmony_ci return -EOPNOTSUPP; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci hu = kzalloc(sizeof(struct hci_uart), GFP_KERNEL); 49262306a36Sopenharmony_ci if (!hu) { 49362306a36Sopenharmony_ci BT_ERR("Can't allocate control structure"); 49462306a36Sopenharmony_ci return -ENFILE; 49562306a36Sopenharmony_ci } 49662306a36Sopenharmony_ci if (percpu_init_rwsem(&hu->proto_lock)) { 49762306a36Sopenharmony_ci BT_ERR("Can't allocate semaphore structure"); 49862306a36Sopenharmony_ci kfree(hu); 49962306a36Sopenharmony_ci return -ENOMEM; 50062306a36Sopenharmony_ci } 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci tty->disc_data = hu; 50362306a36Sopenharmony_ci hu->tty = tty; 50462306a36Sopenharmony_ci tty->receive_room = 65536; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci /* disable alignment support by default */ 50762306a36Sopenharmony_ci hu->alignment = 1; 50862306a36Sopenharmony_ci hu->padding = 0; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci INIT_WORK(&hu->init_ready, hci_uart_init_work); 51162306a36Sopenharmony_ci INIT_WORK(&hu->write_work, hci_uart_write_work); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci /* Flush any pending characters in the driver */ 51462306a36Sopenharmony_ci tty_driver_flush_buffer(tty); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci return 0; 51762306a36Sopenharmony_ci} 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci/* hci_uart_tty_close() 52062306a36Sopenharmony_ci * 52162306a36Sopenharmony_ci * Called when the line discipline is changed to something 52262306a36Sopenharmony_ci * else, the tty is closed, or the tty detects a hangup. 52362306a36Sopenharmony_ci */ 52462306a36Sopenharmony_cistatic void hci_uart_tty_close(struct tty_struct *tty) 52562306a36Sopenharmony_ci{ 52662306a36Sopenharmony_ci struct hci_uart *hu = tty->disc_data; 52762306a36Sopenharmony_ci struct hci_dev *hdev; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci BT_DBG("tty %p", tty); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci /* Detach from the tty */ 53262306a36Sopenharmony_ci tty->disc_data = NULL; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci if (!hu) 53562306a36Sopenharmony_ci return; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci hdev = hu->hdev; 53862306a36Sopenharmony_ci if (hdev) 53962306a36Sopenharmony_ci hci_uart_close(hdev); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) { 54262306a36Sopenharmony_ci percpu_down_write(&hu->proto_lock); 54362306a36Sopenharmony_ci clear_bit(HCI_UART_PROTO_READY, &hu->flags); 54462306a36Sopenharmony_ci percpu_up_write(&hu->proto_lock); 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci cancel_work_sync(&hu->init_ready); 54762306a36Sopenharmony_ci cancel_work_sync(&hu->write_work); 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci if (hdev) { 55062306a36Sopenharmony_ci if (test_bit(HCI_UART_REGISTERED, &hu->flags)) 55162306a36Sopenharmony_ci hci_unregister_dev(hdev); 55262306a36Sopenharmony_ci hci_free_dev(hdev); 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci hu->proto->close(hu); 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci clear_bit(HCI_UART_PROTO_SET, &hu->flags); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci percpu_free_rwsem(&hu->proto_lock); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci kfree(hu); 56162306a36Sopenharmony_ci} 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci/* hci_uart_tty_wakeup() 56462306a36Sopenharmony_ci * 56562306a36Sopenharmony_ci * Callback for transmit wakeup. Called when low level 56662306a36Sopenharmony_ci * device driver can accept more send data. 56762306a36Sopenharmony_ci * 56862306a36Sopenharmony_ci * Arguments: tty pointer to associated tty instance data 56962306a36Sopenharmony_ci * Return Value: None 57062306a36Sopenharmony_ci */ 57162306a36Sopenharmony_cistatic void hci_uart_tty_wakeup(struct tty_struct *tty) 57262306a36Sopenharmony_ci{ 57362306a36Sopenharmony_ci struct hci_uart *hu = tty->disc_data; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci BT_DBG(""); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci if (!hu) 57862306a36Sopenharmony_ci return; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci if (tty != hu->tty) 58362306a36Sopenharmony_ci return; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) 58662306a36Sopenharmony_ci hci_uart_tx_wakeup(hu); 58762306a36Sopenharmony_ci} 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci/* hci_uart_tty_receive() 59062306a36Sopenharmony_ci * 59162306a36Sopenharmony_ci * Called by tty low level driver when receive data is 59262306a36Sopenharmony_ci * available. 59362306a36Sopenharmony_ci * 59462306a36Sopenharmony_ci * Arguments: tty pointer to tty isntance data 59562306a36Sopenharmony_ci * data pointer to received data 59662306a36Sopenharmony_ci * flags pointer to flags for data 59762306a36Sopenharmony_ci * count count of received data in bytes 59862306a36Sopenharmony_ci * 59962306a36Sopenharmony_ci * Return Value: None 60062306a36Sopenharmony_ci */ 60162306a36Sopenharmony_cistatic void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, 60262306a36Sopenharmony_ci const u8 *flags, size_t count) 60362306a36Sopenharmony_ci{ 60462306a36Sopenharmony_ci struct hci_uart *hu = tty->disc_data; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci if (!hu || tty != hu->tty) 60762306a36Sopenharmony_ci return; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci percpu_down_read(&hu->proto_lock); 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) { 61262306a36Sopenharmony_ci percpu_up_read(&hu->proto_lock); 61362306a36Sopenharmony_ci return; 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci /* It does not need a lock here as it is already protected by a mutex in 61762306a36Sopenharmony_ci * tty caller 61862306a36Sopenharmony_ci */ 61962306a36Sopenharmony_ci hu->proto->recv(hu, data, count); 62062306a36Sopenharmony_ci percpu_up_read(&hu->proto_lock); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci if (hu->hdev) 62362306a36Sopenharmony_ci hu->hdev->stat.byte_rx += count; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci tty_unthrottle(tty); 62662306a36Sopenharmony_ci} 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_cistatic int hci_uart_register_dev(struct hci_uart *hu) 62962306a36Sopenharmony_ci{ 63062306a36Sopenharmony_ci struct hci_dev *hdev; 63162306a36Sopenharmony_ci int err; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci BT_DBG(""); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci /* Initialize and register HCI device */ 63662306a36Sopenharmony_ci hdev = hci_alloc_dev(); 63762306a36Sopenharmony_ci if (!hdev) { 63862306a36Sopenharmony_ci BT_ERR("Can't allocate HCI device"); 63962306a36Sopenharmony_ci return -ENOMEM; 64062306a36Sopenharmony_ci } 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci hu->hdev = hdev; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci hdev->bus = HCI_UART; 64562306a36Sopenharmony_ci hci_set_drvdata(hdev, hu); 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci /* Only when vendor specific setup callback is provided, consider 64862306a36Sopenharmony_ci * the manufacturer information valid. This avoids filling in the 64962306a36Sopenharmony_ci * value for Ericsson when nothing is specified. 65062306a36Sopenharmony_ci */ 65162306a36Sopenharmony_ci if (hu->proto->setup) 65262306a36Sopenharmony_ci hdev->manufacturer = hu->proto->manufacturer; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci hdev->open = hci_uart_open; 65562306a36Sopenharmony_ci hdev->close = hci_uart_close; 65662306a36Sopenharmony_ci hdev->flush = hci_uart_flush; 65762306a36Sopenharmony_ci hdev->send = hci_uart_send_frame; 65862306a36Sopenharmony_ci hdev->setup = hci_uart_setup; 65962306a36Sopenharmony_ci SET_HCIDEV_DEV(hdev, hu->tty->dev); 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci if (test_bit(HCI_UART_RAW_DEVICE, &hu->hdev_flags)) 66262306a36Sopenharmony_ci set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks); 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci if (test_bit(HCI_UART_EXT_CONFIG, &hu->hdev_flags)) 66562306a36Sopenharmony_ci set_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks); 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci if (!test_bit(HCI_UART_RESET_ON_INIT, &hu->hdev_flags)) 66862306a36Sopenharmony_ci set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci if (test_bit(HCI_UART_CREATE_AMP, &hu->hdev_flags)) 67162306a36Sopenharmony_ci hdev->dev_type = HCI_AMP; 67262306a36Sopenharmony_ci else 67362306a36Sopenharmony_ci hdev->dev_type = HCI_PRIMARY; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci /* Only call open() for the protocol after hdev is fully initialized as 67662306a36Sopenharmony_ci * open() (or a timer/workqueue it starts) may attempt to reference it. 67762306a36Sopenharmony_ci */ 67862306a36Sopenharmony_ci err = hu->proto->open(hu); 67962306a36Sopenharmony_ci if (err) { 68062306a36Sopenharmony_ci hu->hdev = NULL; 68162306a36Sopenharmony_ci hci_free_dev(hdev); 68262306a36Sopenharmony_ci return err; 68362306a36Sopenharmony_ci } 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci if (test_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags)) 68662306a36Sopenharmony_ci return 0; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci if (hci_register_dev(hdev) < 0) { 68962306a36Sopenharmony_ci BT_ERR("Can't register HCI device"); 69062306a36Sopenharmony_ci hu->proto->close(hu); 69162306a36Sopenharmony_ci hu->hdev = NULL; 69262306a36Sopenharmony_ci hci_free_dev(hdev); 69362306a36Sopenharmony_ci return -ENODEV; 69462306a36Sopenharmony_ci } 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci set_bit(HCI_UART_REGISTERED, &hu->flags); 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci return 0; 69962306a36Sopenharmony_ci} 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_cistatic int hci_uart_set_proto(struct hci_uart *hu, int id) 70262306a36Sopenharmony_ci{ 70362306a36Sopenharmony_ci const struct hci_uart_proto *p; 70462306a36Sopenharmony_ci int err; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci p = hci_uart_get_proto(id); 70762306a36Sopenharmony_ci if (!p) 70862306a36Sopenharmony_ci return -EPROTONOSUPPORT; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci hu->proto = p; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci err = hci_uart_register_dev(hu); 71362306a36Sopenharmony_ci if (err) { 71462306a36Sopenharmony_ci return err; 71562306a36Sopenharmony_ci } 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci set_bit(HCI_UART_PROTO_READY, &hu->flags); 71862306a36Sopenharmony_ci return 0; 71962306a36Sopenharmony_ci} 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_cistatic int hci_uart_set_flags(struct hci_uart *hu, unsigned long flags) 72262306a36Sopenharmony_ci{ 72362306a36Sopenharmony_ci unsigned long valid_flags = BIT(HCI_UART_RAW_DEVICE) | 72462306a36Sopenharmony_ci BIT(HCI_UART_RESET_ON_INIT) | 72562306a36Sopenharmony_ci BIT(HCI_UART_CREATE_AMP) | 72662306a36Sopenharmony_ci BIT(HCI_UART_INIT_PENDING) | 72762306a36Sopenharmony_ci BIT(HCI_UART_EXT_CONFIG) | 72862306a36Sopenharmony_ci BIT(HCI_UART_VND_DETECT); 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci if (flags & ~valid_flags) 73162306a36Sopenharmony_ci return -EINVAL; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci hu->hdev_flags = flags; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci return 0; 73662306a36Sopenharmony_ci} 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci/* hci_uart_tty_ioctl() 73962306a36Sopenharmony_ci * 74062306a36Sopenharmony_ci * Process IOCTL system call for the tty device. 74162306a36Sopenharmony_ci * 74262306a36Sopenharmony_ci * Arguments: 74362306a36Sopenharmony_ci * 74462306a36Sopenharmony_ci * tty pointer to tty instance data 74562306a36Sopenharmony_ci * cmd IOCTL command code 74662306a36Sopenharmony_ci * arg argument for IOCTL call (cmd dependent) 74762306a36Sopenharmony_ci * 74862306a36Sopenharmony_ci * Return Value: Command dependent 74962306a36Sopenharmony_ci */ 75062306a36Sopenharmony_cistatic int hci_uart_tty_ioctl(struct tty_struct *tty, unsigned int cmd, 75162306a36Sopenharmony_ci unsigned long arg) 75262306a36Sopenharmony_ci{ 75362306a36Sopenharmony_ci struct hci_uart *hu = tty->disc_data; 75462306a36Sopenharmony_ci int err = 0; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci BT_DBG(""); 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci /* Verify the status of the device */ 75962306a36Sopenharmony_ci if (!hu) 76062306a36Sopenharmony_ci return -EBADF; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci switch (cmd) { 76362306a36Sopenharmony_ci case HCIUARTSETPROTO: 76462306a36Sopenharmony_ci if (!test_and_set_bit(HCI_UART_PROTO_SET, &hu->flags)) { 76562306a36Sopenharmony_ci err = hci_uart_set_proto(hu, arg); 76662306a36Sopenharmony_ci if (err) 76762306a36Sopenharmony_ci clear_bit(HCI_UART_PROTO_SET, &hu->flags); 76862306a36Sopenharmony_ci } else 76962306a36Sopenharmony_ci err = -EBUSY; 77062306a36Sopenharmony_ci break; 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci case HCIUARTGETPROTO: 77362306a36Sopenharmony_ci if (test_bit(HCI_UART_PROTO_SET, &hu->flags) && 77462306a36Sopenharmony_ci test_bit(HCI_UART_PROTO_READY, &hu->flags)) 77562306a36Sopenharmony_ci err = hu->proto->id; 77662306a36Sopenharmony_ci else 77762306a36Sopenharmony_ci err = -EUNATCH; 77862306a36Sopenharmony_ci break; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci case HCIUARTGETDEVICE: 78162306a36Sopenharmony_ci if (test_bit(HCI_UART_REGISTERED, &hu->flags)) 78262306a36Sopenharmony_ci err = hu->hdev->id; 78362306a36Sopenharmony_ci else 78462306a36Sopenharmony_ci err = -EUNATCH; 78562306a36Sopenharmony_ci break; 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci case HCIUARTSETFLAGS: 78862306a36Sopenharmony_ci if (test_bit(HCI_UART_PROTO_SET, &hu->flags)) 78962306a36Sopenharmony_ci err = -EBUSY; 79062306a36Sopenharmony_ci else 79162306a36Sopenharmony_ci err = hci_uart_set_flags(hu, arg); 79262306a36Sopenharmony_ci break; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci case HCIUARTGETFLAGS: 79562306a36Sopenharmony_ci err = hu->hdev_flags; 79662306a36Sopenharmony_ci break; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci default: 79962306a36Sopenharmony_ci err = n_tty_ioctl_helper(tty, cmd, arg); 80062306a36Sopenharmony_ci break; 80162306a36Sopenharmony_ci } 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci return err; 80462306a36Sopenharmony_ci} 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci/* 80762306a36Sopenharmony_ci * We don't provide read/write/poll interface for user space. 80862306a36Sopenharmony_ci */ 80962306a36Sopenharmony_cistatic ssize_t hci_uart_tty_read(struct tty_struct *tty, struct file *file, 81062306a36Sopenharmony_ci u8 *buf, size_t nr, void **cookie, 81162306a36Sopenharmony_ci unsigned long offset) 81262306a36Sopenharmony_ci{ 81362306a36Sopenharmony_ci return 0; 81462306a36Sopenharmony_ci} 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_cistatic ssize_t hci_uart_tty_write(struct tty_struct *tty, struct file *file, 81762306a36Sopenharmony_ci const u8 *data, size_t count) 81862306a36Sopenharmony_ci{ 81962306a36Sopenharmony_ci return 0; 82062306a36Sopenharmony_ci} 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_cistatic struct tty_ldisc_ops hci_uart_ldisc = { 82362306a36Sopenharmony_ci .owner = THIS_MODULE, 82462306a36Sopenharmony_ci .num = N_HCI, 82562306a36Sopenharmony_ci .name = "n_hci", 82662306a36Sopenharmony_ci .open = hci_uart_tty_open, 82762306a36Sopenharmony_ci .close = hci_uart_tty_close, 82862306a36Sopenharmony_ci .read = hci_uart_tty_read, 82962306a36Sopenharmony_ci .write = hci_uart_tty_write, 83062306a36Sopenharmony_ci .ioctl = hci_uart_tty_ioctl, 83162306a36Sopenharmony_ci .compat_ioctl = hci_uart_tty_ioctl, 83262306a36Sopenharmony_ci .receive_buf = hci_uart_tty_receive, 83362306a36Sopenharmony_ci .write_wakeup = hci_uart_tty_wakeup, 83462306a36Sopenharmony_ci}; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_cistatic int __init hci_uart_init(void) 83762306a36Sopenharmony_ci{ 83862306a36Sopenharmony_ci int err; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci BT_INFO("HCI UART driver ver %s", VERSION); 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci /* Register the tty discipline */ 84362306a36Sopenharmony_ci err = tty_register_ldisc(&hci_uart_ldisc); 84462306a36Sopenharmony_ci if (err) { 84562306a36Sopenharmony_ci BT_ERR("HCI line discipline registration failed. (%d)", err); 84662306a36Sopenharmony_ci return err; 84762306a36Sopenharmony_ci } 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci#ifdef CONFIG_BT_HCIUART_H4 85062306a36Sopenharmony_ci h4_init(); 85162306a36Sopenharmony_ci#endif 85262306a36Sopenharmony_ci#ifdef CONFIG_BT_HCIUART_BCSP 85362306a36Sopenharmony_ci bcsp_init(); 85462306a36Sopenharmony_ci#endif 85562306a36Sopenharmony_ci#ifdef CONFIG_BT_HCIUART_LL 85662306a36Sopenharmony_ci ll_init(); 85762306a36Sopenharmony_ci#endif 85862306a36Sopenharmony_ci#ifdef CONFIG_BT_HCIUART_ATH3K 85962306a36Sopenharmony_ci ath_init(); 86062306a36Sopenharmony_ci#endif 86162306a36Sopenharmony_ci#ifdef CONFIG_BT_HCIUART_3WIRE 86262306a36Sopenharmony_ci h5_init(); 86362306a36Sopenharmony_ci#endif 86462306a36Sopenharmony_ci#ifdef CONFIG_BT_HCIUART_INTEL 86562306a36Sopenharmony_ci intel_init(); 86662306a36Sopenharmony_ci#endif 86762306a36Sopenharmony_ci#ifdef CONFIG_BT_HCIUART_BCM 86862306a36Sopenharmony_ci bcm_init(); 86962306a36Sopenharmony_ci#endif 87062306a36Sopenharmony_ci#ifdef CONFIG_BT_HCIUART_QCA 87162306a36Sopenharmony_ci qca_init(); 87262306a36Sopenharmony_ci#endif 87362306a36Sopenharmony_ci#ifdef CONFIG_BT_HCIUART_AG6XX 87462306a36Sopenharmony_ci ag6xx_init(); 87562306a36Sopenharmony_ci#endif 87662306a36Sopenharmony_ci#ifdef CONFIG_BT_HCIUART_MRVL 87762306a36Sopenharmony_ci mrvl_init(); 87862306a36Sopenharmony_ci#endif 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci return 0; 88162306a36Sopenharmony_ci} 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_cistatic void __exit hci_uart_exit(void) 88462306a36Sopenharmony_ci{ 88562306a36Sopenharmony_ci#ifdef CONFIG_BT_HCIUART_H4 88662306a36Sopenharmony_ci h4_deinit(); 88762306a36Sopenharmony_ci#endif 88862306a36Sopenharmony_ci#ifdef CONFIG_BT_HCIUART_BCSP 88962306a36Sopenharmony_ci bcsp_deinit(); 89062306a36Sopenharmony_ci#endif 89162306a36Sopenharmony_ci#ifdef CONFIG_BT_HCIUART_LL 89262306a36Sopenharmony_ci ll_deinit(); 89362306a36Sopenharmony_ci#endif 89462306a36Sopenharmony_ci#ifdef CONFIG_BT_HCIUART_ATH3K 89562306a36Sopenharmony_ci ath_deinit(); 89662306a36Sopenharmony_ci#endif 89762306a36Sopenharmony_ci#ifdef CONFIG_BT_HCIUART_3WIRE 89862306a36Sopenharmony_ci h5_deinit(); 89962306a36Sopenharmony_ci#endif 90062306a36Sopenharmony_ci#ifdef CONFIG_BT_HCIUART_INTEL 90162306a36Sopenharmony_ci intel_deinit(); 90262306a36Sopenharmony_ci#endif 90362306a36Sopenharmony_ci#ifdef CONFIG_BT_HCIUART_BCM 90462306a36Sopenharmony_ci bcm_deinit(); 90562306a36Sopenharmony_ci#endif 90662306a36Sopenharmony_ci#ifdef CONFIG_BT_HCIUART_QCA 90762306a36Sopenharmony_ci qca_deinit(); 90862306a36Sopenharmony_ci#endif 90962306a36Sopenharmony_ci#ifdef CONFIG_BT_HCIUART_AG6XX 91062306a36Sopenharmony_ci ag6xx_deinit(); 91162306a36Sopenharmony_ci#endif 91262306a36Sopenharmony_ci#ifdef CONFIG_BT_HCIUART_MRVL 91362306a36Sopenharmony_ci mrvl_deinit(); 91462306a36Sopenharmony_ci#endif 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci tty_unregister_ldisc(&hci_uart_ldisc); 91762306a36Sopenharmony_ci} 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_cimodule_init(hci_uart_init); 92062306a36Sopenharmony_cimodule_exit(hci_uart_exit); 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ciMODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); 92362306a36Sopenharmony_ciMODULE_DESCRIPTION("Bluetooth HCI UART driver ver " VERSION); 92462306a36Sopenharmony_ciMODULE_VERSION(VERSION); 92562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 92662306a36Sopenharmony_ciMODULE_ALIAS_LDISC(N_HCI); 927