18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Bluetooth HCI serdev driver lib 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2017 Linaro, Ltd., Rob Herring <robh@kernel.org> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Based on hci_ldisc.c: 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Copyright (C) 2000-2001 Qualcomm Incorporated 108c2ecf20Sopenharmony_ci * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com> 118c2ecf20Sopenharmony_ci * Copyright (C) 2004-2005 Marcel Holtmann <marcel@holtmann.org> 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/kernel.h> 158c2ecf20Sopenharmony_ci#include <linux/types.h> 168c2ecf20Sopenharmony_ci#include <linux/serdev.h> 178c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <net/bluetooth/bluetooth.h> 208c2ecf20Sopenharmony_ci#include <net/bluetooth/hci_core.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include "hci_uart.h" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic inline void hci_uart_tx_complete(struct hci_uart *hu, int pkt_type) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci struct hci_dev *hdev = hu->hdev; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci /* Update HCI stat counters */ 298c2ecf20Sopenharmony_ci switch (pkt_type) { 308c2ecf20Sopenharmony_ci case HCI_COMMAND_PKT: 318c2ecf20Sopenharmony_ci hdev->stat.cmd_tx++; 328c2ecf20Sopenharmony_ci break; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci case HCI_ACLDATA_PKT: 358c2ecf20Sopenharmony_ci hdev->stat.acl_tx++; 368c2ecf20Sopenharmony_ci break; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci case HCI_SCODATA_PKT: 398c2ecf20Sopenharmony_ci hdev->stat.sco_tx++; 408c2ecf20Sopenharmony_ci break; 418c2ecf20Sopenharmony_ci } 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci struct sk_buff *skb = hu->tx_skb; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci if (!skb) { 498c2ecf20Sopenharmony_ci if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) 508c2ecf20Sopenharmony_ci skb = hu->proto->dequeue(hu); 518c2ecf20Sopenharmony_ci } else 528c2ecf20Sopenharmony_ci hu->tx_skb = NULL; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci return skb; 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic void hci_uart_write_work(struct work_struct *work) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci struct hci_uart *hu = container_of(work, struct hci_uart, write_work); 608c2ecf20Sopenharmony_ci struct serdev_device *serdev = hu->serdev; 618c2ecf20Sopenharmony_ci struct hci_dev *hdev = hu->hdev; 628c2ecf20Sopenharmony_ci struct sk_buff *skb; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci /* REVISIT: 658c2ecf20Sopenharmony_ci * should we cope with bad skbs or ->write() returning an error value? 668c2ecf20Sopenharmony_ci */ 678c2ecf20Sopenharmony_ci do { 688c2ecf20Sopenharmony_ci clear_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci while ((skb = hci_uart_dequeue(hu))) { 718c2ecf20Sopenharmony_ci int len; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci len = serdev_device_write_buf(serdev, 748c2ecf20Sopenharmony_ci skb->data, skb->len); 758c2ecf20Sopenharmony_ci hdev->stat.byte_tx += len; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci skb_pull(skb, len); 788c2ecf20Sopenharmony_ci if (skb->len) { 798c2ecf20Sopenharmony_ci hu->tx_skb = skb; 808c2ecf20Sopenharmony_ci break; 818c2ecf20Sopenharmony_ci } 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci hci_uart_tx_complete(hu, hci_skb_pkt_type(skb)); 848c2ecf20Sopenharmony_ci kfree_skb(skb); 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci clear_bit(HCI_UART_SENDING, &hu->tx_state); 888c2ecf20Sopenharmony_ci } while (test_bit(HCI_UART_TX_WAKEUP, &hu->tx_state)); 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci/* ------- Interface to HCI layer ------ */ 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci/* Reset device */ 948c2ecf20Sopenharmony_cistatic int hci_uart_flush(struct hci_dev *hdev) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci struct hci_uart *hu = hci_get_drvdata(hdev); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci BT_DBG("hdev %p serdev %p", hdev, hu->serdev); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci if (hu->tx_skb) { 1018c2ecf20Sopenharmony_ci kfree_skb(hu->tx_skb); hu->tx_skb = NULL; 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci /* Flush any pending characters in the driver and discipline. */ 1058c2ecf20Sopenharmony_ci serdev_device_write_flush(hu->serdev); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) 1088c2ecf20Sopenharmony_ci hu->proto->flush(hu); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci return 0; 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci/* Initialize device */ 1148c2ecf20Sopenharmony_cistatic int hci_uart_open(struct hci_dev *hdev) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci struct hci_uart *hu = hci_get_drvdata(hdev); 1178c2ecf20Sopenharmony_ci int err; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci BT_DBG("%s %p", hdev->name, hdev); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci /* When Quirk HCI_QUIRK_NON_PERSISTENT_SETUP is set by 1228c2ecf20Sopenharmony_ci * driver, BT SoC is completely turned OFF during 1238c2ecf20Sopenharmony_ci * BT OFF. Upon next BT ON UART port should be opened. 1248c2ecf20Sopenharmony_ci */ 1258c2ecf20Sopenharmony_ci if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) { 1268c2ecf20Sopenharmony_ci err = serdev_device_open(hu->serdev); 1278c2ecf20Sopenharmony_ci if (err) 1288c2ecf20Sopenharmony_ci return err; 1298c2ecf20Sopenharmony_ci set_bit(HCI_UART_PROTO_READY, &hu->flags); 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci /* Undo clearing this from hci_uart_close() */ 1338c2ecf20Sopenharmony_ci hdev->flush = hci_uart_flush; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci return 0; 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci/* Close device */ 1398c2ecf20Sopenharmony_cistatic int hci_uart_close(struct hci_dev *hdev) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci struct hci_uart *hu = hci_get_drvdata(hdev); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci BT_DBG("hdev %p", hdev); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) 1468c2ecf20Sopenharmony_ci return 0; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci hci_uart_flush(hdev); 1498c2ecf20Sopenharmony_ci hdev->flush = NULL; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci /* When QUIRK HCI_QUIRK_NON_PERSISTENT_SETUP is set by driver, 1528c2ecf20Sopenharmony_ci * BT SOC is completely powered OFF during BT OFF, holding port 1538c2ecf20Sopenharmony_ci * open may drain the battery. 1548c2ecf20Sopenharmony_ci */ 1558c2ecf20Sopenharmony_ci if (test_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks)) { 1568c2ecf20Sopenharmony_ci clear_bit(HCI_UART_PROTO_READY, &hu->flags); 1578c2ecf20Sopenharmony_ci serdev_device_close(hu->serdev); 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci return 0; 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci/* Send frames from HCI layer */ 1648c2ecf20Sopenharmony_cistatic int hci_uart_send_frame(struct hci_dev *hdev, struct sk_buff *skb) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci struct hci_uart *hu = hci_get_drvdata(hdev); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci BT_DBG("%s: type %d len %d", hdev->name, hci_skb_pkt_type(skb), 1698c2ecf20Sopenharmony_ci skb->len); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci hu->proto->enqueue(hu, skb); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci hci_uart_tx_wakeup(hu); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci return 0; 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cistatic int hci_uart_setup(struct hci_dev *hdev) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci struct hci_uart *hu = hci_get_drvdata(hdev); 1818c2ecf20Sopenharmony_ci struct hci_rp_read_local_version *ver; 1828c2ecf20Sopenharmony_ci struct sk_buff *skb; 1838c2ecf20Sopenharmony_ci unsigned int speed; 1848c2ecf20Sopenharmony_ci int err; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci /* Init speed if any */ 1878c2ecf20Sopenharmony_ci if (hu->init_speed) 1888c2ecf20Sopenharmony_ci speed = hu->init_speed; 1898c2ecf20Sopenharmony_ci else if (hu->proto->init_speed) 1908c2ecf20Sopenharmony_ci speed = hu->proto->init_speed; 1918c2ecf20Sopenharmony_ci else 1928c2ecf20Sopenharmony_ci speed = 0; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if (speed) 1958c2ecf20Sopenharmony_ci serdev_device_set_baudrate(hu->serdev, speed); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci /* Operational speed if any */ 1988c2ecf20Sopenharmony_ci if (hu->oper_speed) 1998c2ecf20Sopenharmony_ci speed = hu->oper_speed; 2008c2ecf20Sopenharmony_ci else if (hu->proto->oper_speed) 2018c2ecf20Sopenharmony_ci speed = hu->proto->oper_speed; 2028c2ecf20Sopenharmony_ci else 2038c2ecf20Sopenharmony_ci speed = 0; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci if (hu->proto->set_baudrate && speed) { 2068c2ecf20Sopenharmony_ci err = hu->proto->set_baudrate(hu, speed); 2078c2ecf20Sopenharmony_ci if (err) 2088c2ecf20Sopenharmony_ci bt_dev_err(hdev, "Failed to set baudrate"); 2098c2ecf20Sopenharmony_ci else 2108c2ecf20Sopenharmony_ci serdev_device_set_baudrate(hu->serdev, speed); 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci if (hu->proto->setup) 2148c2ecf20Sopenharmony_ci return hu->proto->setup(hu); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci if (!test_bit(HCI_UART_VND_DETECT, &hu->hdev_flags)) 2178c2ecf20Sopenharmony_ci return 0; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL, 2208c2ecf20Sopenharmony_ci HCI_INIT_TIMEOUT); 2218c2ecf20Sopenharmony_ci if (IS_ERR(skb)) { 2228c2ecf20Sopenharmony_ci bt_dev_err(hdev, "Reading local version info failed (%ld)", 2238c2ecf20Sopenharmony_ci PTR_ERR(skb)); 2248c2ecf20Sopenharmony_ci return 0; 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci if (skb->len != sizeof(*ver)) 2288c2ecf20Sopenharmony_ci bt_dev_err(hdev, "Event length mismatch for version info"); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci kfree_skb(skb); 2318c2ecf20Sopenharmony_ci return 0; 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci/** hci_uart_write_wakeup - transmit buffer wakeup 2358c2ecf20Sopenharmony_ci * @serdev: serial device 2368c2ecf20Sopenharmony_ci * 2378c2ecf20Sopenharmony_ci * This function is called by the serdev framework when it accepts 2388c2ecf20Sopenharmony_ci * more data being sent. 2398c2ecf20Sopenharmony_ci */ 2408c2ecf20Sopenharmony_cistatic void hci_uart_write_wakeup(struct serdev_device *serdev) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci struct hci_uart *hu = serdev_device_get_drvdata(serdev); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci BT_DBG(""); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci if (!hu || serdev != hu->serdev) { 2478c2ecf20Sopenharmony_ci WARN_ON(1); 2488c2ecf20Sopenharmony_ci return; 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) 2528c2ecf20Sopenharmony_ci hci_uart_tx_wakeup(hu); 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci/** hci_uart_receive_buf - receive buffer wakeup 2568c2ecf20Sopenharmony_ci * @serdev: serial device 2578c2ecf20Sopenharmony_ci * @data: pointer to received data 2588c2ecf20Sopenharmony_ci * @count: count of received data in bytes 2598c2ecf20Sopenharmony_ci * 2608c2ecf20Sopenharmony_ci * This function is called by the serdev framework when it received data 2618c2ecf20Sopenharmony_ci * in the RX buffer. 2628c2ecf20Sopenharmony_ci * 2638c2ecf20Sopenharmony_ci * Return: number of processed bytes 2648c2ecf20Sopenharmony_ci */ 2658c2ecf20Sopenharmony_cistatic int hci_uart_receive_buf(struct serdev_device *serdev, const u8 *data, 2668c2ecf20Sopenharmony_ci size_t count) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci struct hci_uart *hu = serdev_device_get_drvdata(serdev); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci if (!hu || serdev != hu->serdev) { 2718c2ecf20Sopenharmony_ci WARN_ON(1); 2728c2ecf20Sopenharmony_ci return 0; 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) 2768c2ecf20Sopenharmony_ci return 0; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci /* It does not need a lock here as it is already protected by a mutex in 2798c2ecf20Sopenharmony_ci * tty caller 2808c2ecf20Sopenharmony_ci */ 2818c2ecf20Sopenharmony_ci hu->proto->recv(hu, data, count); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci if (hu->hdev) 2848c2ecf20Sopenharmony_ci hu->hdev->stat.byte_rx += count; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci return count; 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistatic const struct serdev_device_ops hci_serdev_client_ops = { 2908c2ecf20Sopenharmony_ci .receive_buf = hci_uart_receive_buf, 2918c2ecf20Sopenharmony_ci .write_wakeup = hci_uart_write_wakeup, 2928c2ecf20Sopenharmony_ci}; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ciint hci_uart_register_device(struct hci_uart *hu, 2958c2ecf20Sopenharmony_ci const struct hci_uart_proto *p) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci int err; 2988c2ecf20Sopenharmony_ci struct hci_dev *hdev; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci BT_DBG(""); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci serdev_device_set_client_ops(hu->serdev, &hci_serdev_client_ops); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci if (percpu_init_rwsem(&hu->proto_lock)) 3058c2ecf20Sopenharmony_ci return -ENOMEM; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci err = serdev_device_open(hu->serdev); 3088c2ecf20Sopenharmony_ci if (err) 3098c2ecf20Sopenharmony_ci goto err_rwsem; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci err = p->open(hu); 3128c2ecf20Sopenharmony_ci if (err) 3138c2ecf20Sopenharmony_ci goto err_open; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci hu->proto = p; 3168c2ecf20Sopenharmony_ci set_bit(HCI_UART_PROTO_READY, &hu->flags); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci /* Initialize and register HCI device */ 3198c2ecf20Sopenharmony_ci hdev = hci_alloc_dev(); 3208c2ecf20Sopenharmony_ci if (!hdev) { 3218c2ecf20Sopenharmony_ci BT_ERR("Can't allocate HCI device"); 3228c2ecf20Sopenharmony_ci err = -ENOMEM; 3238c2ecf20Sopenharmony_ci goto err_alloc; 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci hu->hdev = hdev; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci hdev->bus = HCI_UART; 3298c2ecf20Sopenharmony_ci hci_set_drvdata(hdev, hu); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci INIT_WORK(&hu->init_ready, hci_uart_init_work); 3328c2ecf20Sopenharmony_ci INIT_WORK(&hu->write_work, hci_uart_write_work); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci /* Only when vendor specific setup callback is provided, consider 3358c2ecf20Sopenharmony_ci * the manufacturer information valid. This avoids filling in the 3368c2ecf20Sopenharmony_ci * value for Ericsson when nothing is specified. 3378c2ecf20Sopenharmony_ci */ 3388c2ecf20Sopenharmony_ci if (hu->proto->setup) 3398c2ecf20Sopenharmony_ci hdev->manufacturer = hu->proto->manufacturer; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci hdev->open = hci_uart_open; 3428c2ecf20Sopenharmony_ci hdev->close = hci_uart_close; 3438c2ecf20Sopenharmony_ci hdev->flush = hci_uart_flush; 3448c2ecf20Sopenharmony_ci hdev->send = hci_uart_send_frame; 3458c2ecf20Sopenharmony_ci hdev->setup = hci_uart_setup; 3468c2ecf20Sopenharmony_ci SET_HCIDEV_DEV(hdev, &hu->serdev->dev); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci if (test_bit(HCI_UART_RAW_DEVICE, &hu->hdev_flags)) 3498c2ecf20Sopenharmony_ci set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci if (test_bit(HCI_UART_EXT_CONFIG, &hu->hdev_flags)) 3528c2ecf20Sopenharmony_ci set_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci if (test_bit(HCI_UART_CREATE_AMP, &hu->hdev_flags)) 3558c2ecf20Sopenharmony_ci hdev->dev_type = HCI_AMP; 3568c2ecf20Sopenharmony_ci else 3578c2ecf20Sopenharmony_ci hdev->dev_type = HCI_PRIMARY; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci if (test_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags)) 3608c2ecf20Sopenharmony_ci return 0; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci if (hci_register_dev(hdev) < 0) { 3638c2ecf20Sopenharmony_ci BT_ERR("Can't register HCI device"); 3648c2ecf20Sopenharmony_ci err = -ENODEV; 3658c2ecf20Sopenharmony_ci goto err_register; 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci set_bit(HCI_UART_REGISTERED, &hu->flags); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci return 0; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_cierr_register: 3738c2ecf20Sopenharmony_ci hci_free_dev(hdev); 3748c2ecf20Sopenharmony_cierr_alloc: 3758c2ecf20Sopenharmony_ci clear_bit(HCI_UART_PROTO_READY, &hu->flags); 3768c2ecf20Sopenharmony_ci p->close(hu); 3778c2ecf20Sopenharmony_cierr_open: 3788c2ecf20Sopenharmony_ci serdev_device_close(hu->serdev); 3798c2ecf20Sopenharmony_cierr_rwsem: 3808c2ecf20Sopenharmony_ci percpu_free_rwsem(&hu->proto_lock); 3818c2ecf20Sopenharmony_ci return err; 3828c2ecf20Sopenharmony_ci} 3838c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(hci_uart_register_device); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_civoid hci_uart_unregister_device(struct hci_uart *hu) 3868c2ecf20Sopenharmony_ci{ 3878c2ecf20Sopenharmony_ci struct hci_dev *hdev = hu->hdev; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci cancel_work_sync(&hu->init_ready); 3908c2ecf20Sopenharmony_ci if (test_bit(HCI_UART_REGISTERED, &hu->flags)) 3918c2ecf20Sopenharmony_ci hci_unregister_dev(hdev); 3928c2ecf20Sopenharmony_ci hci_free_dev(hdev); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci cancel_work_sync(&hu->write_work); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci hu->proto->close(hu); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) { 3998c2ecf20Sopenharmony_ci clear_bit(HCI_UART_PROTO_READY, &hu->flags); 4008c2ecf20Sopenharmony_ci serdev_device_close(hu->serdev); 4018c2ecf20Sopenharmony_ci } 4028c2ecf20Sopenharmony_ci percpu_free_rwsem(&hu->proto_lock); 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(hci_uart_unregister_device); 405