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) &&
!test_bit(HCI_UART_PROTO_INIT, &hu->flags)) goto no_schedule;
set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); if (test_and_set_bit(HCI_UART_SENDING, &hu->tx_state)) goto no_schedule;
/* Check the underlying device or tty has flow control support */ bool hci_uart_has_flow_control(struct hci_uart *hu)
{ /* serdev nodes check if the needed operations are present */ if (hu->serdev) returntrue;
if (hu->tty->driver->ops->tiocmget && hu->tty->driver->ops->tiocmset) returntrue;
returnfalse;
}
/* Flow control or un-flow control the device */ void hci_uart_set_flow_control(struct hci_uart *hu, bool enable)
{ struct tty_struct *tty = hu->tty; struct ktermios ktermios; int status; unsignedint set = 0; unsignedint clear = 0;
if (hu->serdev) {
serdev_device_set_flow_control(hu->serdev, !enable);
serdev_device_set_rts(hu->serdev, !enable); return;
}
/* Clear RTS to prevent the device from sending */ /* Most UARTs need OUT2 to enable interrupts */
status = tty->driver->ops->tiocmget(tty);
BT_DBG("Current tiocm 0x%x", status);
set &= ~(TIOCM_OUT2 | TIOCM_RTS);
clear = ~set;
set &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 |
TIOCM_OUT2 | TIOCM_LOOP;
clear &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 |
TIOCM_OUT2 | TIOCM_LOOP;
status = tty->driver->ops->tiocmset(tty, set, clear);
BT_DBG("Clearing RTS: %s", status ? "failed" : "success");
} else { /* Set RTS to allow the device to send again */
status = tty->driver->ops->tiocmget(tty);
BT_DBG("Current tiocm 0x%x", status);
/* Flush any pending characters in the driver */
tty_driver_flush_buffer(tty);
return 0;
}
/* hci_uart_tty_close() * * Called when the line discipline is changed to something * else, the tty is closed, or the tty detects a hangup.
*/ staticvoid hci_uart_tty_close(struct tty_struct *tty)
{ struct hci_uart *hu = tty->disc_data; struct hci_dev *hdev;
BT_DBG("tty %p", tty);
/* Detach from the tty */
tty->disc_data = NULL;
if (!hu) return;
hdev = hu->hdev; if (hdev)
hci_uart_close(hdev);
if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) {
percpu_down_write(&hu->proto_lock);
clear_bit(HCI_UART_PROTO_READY, &hu->flags);
percpu_up_write(&hu->proto_lock);
if (hdev) { if (test_bit(HCI_UART_REGISTERED, &hu->flags))
hci_unregister_dev(hdev);
hci_free_dev(hdev);
}
hu->proto->close(hu);
}
clear_bit(HCI_UART_PROTO_SET, &hu->flags);
percpu_free_rwsem(&hu->proto_lock);
kfree(hu);
}
/* hci_uart_tty_wakeup() * * Callback for transmit wakeup. Called when low level * device driver can accept more send data. * * Arguments: tty pointer to associated tty instance data * Return Value: None
*/ staticvoid hci_uart_tty_wakeup(struct tty_struct *tty)
{ struct hci_uart *hu = tty->disc_data;
BT_DBG("");
if (!hu) return;
clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
if (tty != hu->tty) return;
if (test_bit(HCI_UART_PROTO_READY, &hu->flags) ||
test_bit(HCI_UART_PROTO_INIT, &hu->flags))
hci_uart_tx_wakeup(hu);
}
/* hci_uart_tty_receive() * * Called by tty low level driver when receive data is * available. * * Arguments: tty pointer to tty instance data * data pointer to received data * flags pointer to flags for data * count count of received data in bytes * * Return Value: None
*/ staticvoid hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, const u8 *flags, size_t count)
{ struct hci_uart *hu = tty->disc_data;
if (!hu || tty != hu->tty) return;
percpu_down_read(&hu->proto_lock);
if (!test_bit(HCI_UART_PROTO_READY, &hu->flags) &&
!test_bit(HCI_UART_PROTO_INIT, &hu->flags)) {
percpu_up_read(&hu->proto_lock); return;
}
/* It does not need a lock here as it is already protected by a mutex in * tty caller
*/
hu->proto->recv(hu, data, count);
percpu_up_read(&hu->proto_lock);
if (hu->hdev)
hu->hdev->stat.byte_rx += count;
tty_unthrottle(tty);
}
staticint hci_uart_register_dev(struct hci_uart *hu)
{ struct hci_dev *hdev; int err;
BT_DBG("");
/* Initialize and register HCI device */
hdev = hci_alloc_dev(); if (!hdev) {
BT_ERR("Can't allocate HCI device"); return -ENOMEM;
}
hu->hdev = hdev;
hdev->bus = HCI_UART;
hci_set_drvdata(hdev, hu);
/* Only when vendor specific setup callback is provided, consider * the manufacturer information valid. This avoids filling in the * value for Ericsson when nothing is specified.
*/ if (hu->proto->setup)
hdev->manufacturer = hu->proto->manufacturer;
if (test_bit(HCI_UART_RAW_DEVICE, &hu->hdev_flags))
hci_set_quirk(hdev, HCI_QUIRK_RAW_DEVICE);
if (test_bit(HCI_UART_EXT_CONFIG, &hu->hdev_flags))
hci_set_quirk(hdev, HCI_QUIRK_EXTERNAL_CONFIG);
if (!test_bit(HCI_UART_RESET_ON_INIT, &hu->hdev_flags))
hci_set_quirk(hdev, HCI_QUIRK_RESET_ON_CLOSE);
/* Only call open() for the protocol after hdev is fully initialized as * open() (or a timer/workqueue it starts) may attempt to reference it.
*/
err = hu->proto->open(hu); if (err) {
hu->hdev = NULL;
hci_free_dev(hdev); return err;
}
if (test_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags)) return 0;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.