// SPDX-License-Identifier: GPL-2.0-or-later
/*
*
* Bluetooth HCI UART driver
*
* Copyright (C) 2000-2001 Qualcomm Incorporated
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
* Copyright (C) 2004-2005 Marcel Holtmann <marcel@holtmann.org>
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
#include <linux/ptrace.h>
#include <linux/poll.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/signal.h>
#include <linux/ioctl.h>
#include <linux/skbuff.h>
#include <linux/firmware.h>
#include <linux/serdev.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include "btintel.h"
#include "btbcm.h"
#include "hci_uart.h"
#define VERSION "2.3"
static const struct hci_uart_proto *hup[HCI_UART_MAX_PROTO];
int hci_uart_register_proto(const struct hci_uart_proto *p)
{
if (p->id >= HCI_UART_MAX_PROTO)
return -EINVAL;
if (hup[p->id])
return -EEXIST;
hup[p->id] = p;
BT_INFO("HCI UART protocol %s registered", p->name);
return 0;
}
int hci_uart_unregister_proto(const struct hci_uart_proto *p)
{
if (p->id >= HCI_UART_MAX_PROTO)
return -EINVAL;
if (!hup[p->id])
return -EINVAL;
hup[p->id] = NULL;
return 0;
}
static const struct hci_uart_proto *hci_uart_get_proto(unsigned int id)
{
if (id >= HCI_UART_MAX_PROTO)
return NULL;
return hup[id];
}
static inline void hci_uart_tx_complete(struct hci_uart *hu, int pkt_type)
{
struct hci_dev *hdev = hu->hdev;
/* Update HCI stat counters */
switch (pkt_type) {
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;
}
}
static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu)
{
struct sk_buff *skb = hu->tx_skb;
if (!skb) {
percpu_down_read(&hu->proto_lock);
if (test_bit(HCI_UART_PROTO_READY, &hu->flags))
skb = hu->proto->dequeue(hu);
percpu_up_read(&hu->proto_lock);
} else {
hu->tx_skb = NULL;
}
return skb;
}
int hci_uart_tx_wakeup(struct hci_uart *hu)
{
/* This may be called in an IRQ context, so we can't sleep. Therefore
* we try to acquire the lock only, and if that fails we assume the
* tty is being closed because that is the only time the write lock is
* acquired. If, however, at some point in the future the write lock
* is also acquired in other situations, then this must be revisited.
*/
if (!percpu_down_read_trylock(&hu->proto_lock))
return 0;
if (!test_bit(HCI_UART_PROTO_READY, &hu->flags))
goto no_schedule;
if (test_and_set_bit(HCI_UART_SENDING, &hu->tx_state)) {
set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state);
goto no_schedule;
}
BT_DBG("");
schedule_work(&hu->write_work);
no_schedule:
percpu_up_read(&hu->proto_lock);
return 0;
}
EXPORT_SYMBOL_GPL(hci_uart_tx_wakeup);
static void hci_uart_write_work(struct work_struct *work)
{
struct hci_uart *hu = container_of(work, struct hci_uart, write_work);
struct tty_struct *tty = hu->tty;
struct hci_dev *hdev = hu->hdev;
struct sk_buff *skb;
/* REVISIT: should we cope with bad skbs or ->write() returning
* and error value ?
*/
restart:
clear_bit(HCI_UART_TX_WAKEUP, &hu->tx_state);
while ((skb = hci_uart_dequeue(hu))) {
int len;
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
len = tty->ops->write(tty, skb->data, skb->len);
hdev->stat.byte_tx += len;
skb_pull(skb, len);
if (skb->len) {
hu->tx_skb = skb;
break;
}
hci_uart_tx_complete(hu, hci_skb_pkt_type(skb));
kfree_skb(skb);
}
if (test_bit(HCI_UART_TX_WAKEUP, &hu->tx_state))
goto restart;
clear_bit(HCI_UART_SENDING, &hu->tx_state);
wake_up_bit(&hu->tx_state, HCI_UART_SENDING);
}
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, &<