/* nci_uart_tty_open * * Called when line discipline changed to NCI_UART. * * Arguments: * tty pointer to tty info structure * Return Value: * 0 if success, otherwise error code
*/ staticint nci_uart_tty_open(struct tty_struct *tty)
{ /* Error if the tty has no write op instead of leaving an exploitable * hole
*/ if (!tty->ops->write) return -EOPNOTSUPP;
tty->disc_data = NULL;
tty->receive_room = 65536;
/* Flush any pending characters in the driver */
tty_driver_flush_buffer(tty);
return 0;
}
/* nci_uart_tty_close() * * Called when the line discipline is changed to something * else, the tty is closed, or the tty detects a hangup.
*/ staticvoid nci_uart_tty_close(struct tty_struct *tty)
{ struct nci_uart *nu = tty->disc_data;
/* nci_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 nci_uart_tty_wakeup(struct tty_struct *tty)
{ struct nci_uart *nu = tty->disc_data;
if (!nu) return;
clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
if (tty != nu->tty) return;
nci_uart_tx_wakeup(nu);
}
/* -- Default recv_buf handler -- * * This handler supposes that NCI frames are sent over UART link without any * framing. It reads NCI header, retrieve the packet size and once all packet * bytes are received it passes it to nci_uart driver for processing.
*/ staticint nci_uart_default_recv_buf(struct nci_uart *nu, const u8 *data, int count)
{ int chunk_len;
if (!nu->ndev) {
nfc_err(nu->tty->dev, "receive data from tty but no NCI dev is attached yet, drop buffer\n"); return 0;
}
/* Decode all incoming data in packets * and enqueue then for processing.
*/ while (count > 0) { /* If this is the first data of a packet, allocate a buffer */ if (!nu->rx_skb) {
nu->rx_packet_len = -1;
nu->rx_skb = nci_skb_alloc(nu->ndev,
NCI_MAX_PACKET_SIZE,
GFP_ATOMIC); if (!nu->rx_skb) return -ENOMEM;
}
/* Eat byte after byte till full packet header is received */ if (nu->rx_skb->len < NCI_CTRL_HDR_SIZE) {
skb_put_u8(nu->rx_skb, *data++);
--count; continue;
}
/* Header was received but packet len was not read */ if (nu->rx_packet_len < 0)
nu->rx_packet_len = NCI_CTRL_HDR_SIZE +
nci_plen(nu->rx_skb->data);
/* Compute how many bytes are missing and how many bytes can * be consumed.
*/
chunk_len = nu->rx_packet_len - nu->rx_skb->len; if (count < chunk_len)
chunk_len = count;
skb_put_data(nu->rx_skb, data, chunk_len);
data += chunk_len;
count -= chunk_len;
/* Check if packet is fully received */ if (nu->rx_packet_len == nu->rx_skb->len) { /* Pass RX packet to driver */ if (nu->ops.recv(nu, nu->rx_skb) != 0)
nfc_err(nu->tty->dev, "corrupted RX packet\n"); /* Next packet will be a new one */
nu->rx_skb = NULL;
}
}
return 0;
}
/* nci_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 nci_uart_tty_receive(struct tty_struct *tty, const u8 *data, const u8 *flags, size_t count)
{ struct nci_uart *nu = tty->disc_data;
/* Try to start TX (if possible) */
nci_uart_tx_wakeup(nu);
return 0;
}
int nci_uart_register(struct nci_uart *nu)
{ if (!nu || !nu->ops.open ||
!nu->ops.recv || !nu->ops.close) return -EINVAL;
/* Set the send callback */
nu->ops.send = nci_uart_send;
/* Add this driver in the driver list */ if (nci_uart_drivers[nu->driver]) {
pr_err("driver %d is already registered\n", nu->driver); return -EBUSY;
}
nci_uart_drivers[nu->driver] = nu;
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.