drivers/bluetooth/hci_serdev.c

Source file repositories/reference/linux-study-clean/drivers/bluetooth/hci_serdev.c

File Facts

System
Linux kernel
Corpus path
drivers/bluetooth/hci_serdev.c
Extension
.c
Size
9443 bytes
Lines
415
Domain
Driver Families
Bucket
drivers/bluetooth
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

while ((skb = hci_uart_dequeue(hu))) {
			int len;

			len = serdev_device_write_buf(serdev,
						      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);
		}

		clear_bit(HCI_UART_SENDING, &hu->tx_state);
	} while (test_bit(HCI_UART_TX_WAKEUP, &hu->tx_state));
}

/* ------- Interface to HCI layer ------ */

/* Reset device */
static int hci_uart_flush(struct hci_dev *hdev)
{
	struct hci_uart *hu  = hci_get_drvdata(hdev);

	BT_DBG("hdev %p serdev %p", hdev, hu->serdev);

	if (hu->tx_skb) {
		kfree_skb(hu->tx_skb); hu->tx_skb = NULL;
	}

	/* Flush any pending characters in the driver and discipline. */
	serdev_device_write_flush(hu->serdev);

	if (test_bit(HCI_UART_PROTO_READY, &hu->flags))
		hu->proto->flush(hu);

	return 0;
}

/* Initialize device */
static int hci_uart_open(struct hci_dev *hdev)
{
	struct hci_uart *hu = hci_get_drvdata(hdev);
	int err;

	BT_DBG("%s %p", hdev->name, hdev);

	/* When Quirk HCI_QUIRK_NON_PERSISTENT_SETUP is set by
	 * driver, BT SoC is completely turned OFF during
	 * BT OFF. Upon next BT ON UART port should be opened.
	 */
	if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) {
		err = serdev_device_open(hu->serdev);
		if (err)
			return err;
		set_bit(HCI_UART_PROTO_READY, &hu->flags);
	}

	/* Undo clearing this from hci_uart_close() */
	hdev->flush = hci_uart_flush;

	return 0;
}

/* Close device */
static int hci_uart_close(struct hci_dev *hdev)
{
	struct hci_uart *hu = hci_get_drvdata(hdev);

	BT_DBG("hdev %p", hdev);

	if (!test_bit(HCI_UART_PROTO_READY, &hu->flags))
		return 0;

	hci_uart_flush(hdev);
	hdev->flush = NULL;

	/* When QUIRK HCI_QUIRK_NON_PERSISTENT_SETUP is set by driver,
	 * BT SOC is completely powered OFF during BT OFF, holding port
	 * open may drain the battery.
	 */
	if (hci_test_quirk(hdev, HCI_QUIRK_NON_PERSISTENT_SETUP)) {
		clear_bit(HCI_UART_PROTO_READY, &hu->flags);
		serdev_device_close(hu->serdev);
	}

Annotation

Implementation Notes