19961127dSVincent Cuissard /* 29961127dSVincent Cuissard * Copyright (C) 2015, Marvell International Ltd. 39961127dSVincent Cuissard * 49961127dSVincent Cuissard * This software file (the "File") is distributed by Marvell International 59961127dSVincent Cuissard * Ltd. under the terms of the GNU General Public License Version 2, June 1991 69961127dSVincent Cuissard * (the "License"). You may use, redistribute and/or modify this File in 79961127dSVincent Cuissard * accordance with the terms and conditions of the License, a copy of which 89961127dSVincent Cuissard * is available on the worldwide web at 99961127dSVincent Cuissard * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. 109961127dSVincent Cuissard * 119961127dSVincent Cuissard * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 129961127dSVincent Cuissard * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 139961127dSVincent Cuissard * ARE EXPRESSLY DISCLAIMED. The License provides additional details about 149961127dSVincent Cuissard * this warranty disclaimer. 159961127dSVincent Cuissard */ 169961127dSVincent Cuissard 179961127dSVincent Cuissard /* Inspired (hugely) by HCI LDISC implementation in Bluetooth. 189961127dSVincent Cuissard * 199961127dSVincent Cuissard * Copyright (C) 2000-2001 Qualcomm Incorporated 209961127dSVincent Cuissard * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com> 219961127dSVincent Cuissard * Copyright (C) 2004-2005 Marcel Holtmann <marcel@holtmann.org> 229961127dSVincent Cuissard */ 239961127dSVincent Cuissard 249961127dSVincent Cuissard #include <linux/module.h> 259961127dSVincent Cuissard 269961127dSVincent Cuissard #include <linux/kernel.h> 279961127dSVincent Cuissard #include <linux/init.h> 289961127dSVincent Cuissard #include <linux/types.h> 299961127dSVincent Cuissard #include <linux/fcntl.h> 309961127dSVincent Cuissard #include <linux/interrupt.h> 319961127dSVincent Cuissard #include <linux/ptrace.h> 329961127dSVincent Cuissard #include <linux/poll.h> 339961127dSVincent Cuissard 349961127dSVincent Cuissard #include <linux/slab.h> 359961127dSVincent Cuissard #include <linux/tty.h> 369961127dSVincent Cuissard #include <linux/errno.h> 379961127dSVincent Cuissard #include <linux/string.h> 389961127dSVincent Cuissard #include <linux/signal.h> 399961127dSVincent Cuissard #include <linux/ioctl.h> 409961127dSVincent Cuissard #include <linux/skbuff.h> 419961127dSVincent Cuissard 429961127dSVincent Cuissard #include <net/nfc/nci.h> 439961127dSVincent Cuissard #include <net/nfc/nci_core.h> 449961127dSVincent Cuissard 459961127dSVincent Cuissard /* TX states */ 469961127dSVincent Cuissard #define NCI_UART_SENDING 1 479961127dSVincent Cuissard #define NCI_UART_TX_WAKEUP 2 489961127dSVincent Cuissard 499961127dSVincent Cuissard static struct nci_uart *nci_uart_drivers[NCI_UART_DRIVER_MAX]; 509961127dSVincent Cuissard 519961127dSVincent Cuissard static inline struct sk_buff *nci_uart_dequeue(struct nci_uart *nu) 529961127dSVincent Cuissard { 539961127dSVincent Cuissard struct sk_buff *skb = nu->tx_skb; 549961127dSVincent Cuissard 559961127dSVincent Cuissard if (!skb) 569961127dSVincent Cuissard skb = skb_dequeue(&nu->tx_q); 579961127dSVincent Cuissard else 589961127dSVincent Cuissard nu->tx_skb = NULL; 599961127dSVincent Cuissard 609961127dSVincent Cuissard return skb; 619961127dSVincent Cuissard } 629961127dSVincent Cuissard 639961127dSVincent Cuissard static inline int nci_uart_queue_empty(struct nci_uart *nu) 649961127dSVincent Cuissard { 659961127dSVincent Cuissard if (nu->tx_skb) 669961127dSVincent Cuissard return 0; 679961127dSVincent Cuissard 689961127dSVincent Cuissard return skb_queue_empty(&nu->tx_q); 699961127dSVincent Cuissard } 709961127dSVincent Cuissard 719961127dSVincent Cuissard static int nci_uart_tx_wakeup(struct nci_uart *nu) 729961127dSVincent Cuissard { 739961127dSVincent Cuissard if (test_and_set_bit(NCI_UART_SENDING, &nu->tx_state)) { 749961127dSVincent Cuissard set_bit(NCI_UART_TX_WAKEUP, &nu->tx_state); 759961127dSVincent Cuissard return 0; 769961127dSVincent Cuissard } 779961127dSVincent Cuissard 789961127dSVincent Cuissard schedule_work(&nu->write_work); 799961127dSVincent Cuissard 809961127dSVincent Cuissard return 0; 819961127dSVincent Cuissard } 829961127dSVincent Cuissard 839961127dSVincent Cuissard static void nci_uart_write_work(struct work_struct *work) 849961127dSVincent Cuissard { 859961127dSVincent Cuissard struct nci_uart *nu = container_of(work, struct nci_uart, write_work); 869961127dSVincent Cuissard struct tty_struct *tty = nu->tty; 879961127dSVincent Cuissard struct sk_buff *skb; 889961127dSVincent Cuissard 899961127dSVincent Cuissard restart: 909961127dSVincent Cuissard clear_bit(NCI_UART_TX_WAKEUP, &nu->tx_state); 919961127dSVincent Cuissard 929961127dSVincent Cuissard if (nu->ops.tx_start) 939961127dSVincent Cuissard nu->ops.tx_start(nu); 949961127dSVincent Cuissard 959961127dSVincent Cuissard while ((skb = nci_uart_dequeue(nu))) { 969961127dSVincent Cuissard int len; 979961127dSVincent Cuissard 989961127dSVincent Cuissard set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); 999961127dSVincent Cuissard len = tty->ops->write(tty, skb->data, skb->len); 1009961127dSVincent Cuissard skb_pull(skb, len); 1019961127dSVincent Cuissard if (skb->len) { 1029961127dSVincent Cuissard nu->tx_skb = skb; 1039961127dSVincent Cuissard break; 1049961127dSVincent Cuissard } 1059961127dSVincent Cuissard kfree_skb(skb); 1069961127dSVincent Cuissard } 1079961127dSVincent Cuissard 1089961127dSVincent Cuissard if (test_bit(NCI_UART_TX_WAKEUP, &nu->tx_state)) 1099961127dSVincent Cuissard goto restart; 1109961127dSVincent Cuissard 1119961127dSVincent Cuissard if (nu->ops.tx_done && nci_uart_queue_empty(nu)) 1129961127dSVincent Cuissard nu->ops.tx_done(nu); 1139961127dSVincent Cuissard 1149961127dSVincent Cuissard clear_bit(NCI_UART_SENDING, &nu->tx_state); 1159961127dSVincent Cuissard } 1169961127dSVincent Cuissard 1179961127dSVincent Cuissard static int nci_uart_set_driver(struct tty_struct *tty, unsigned int driver) 1189961127dSVincent Cuissard { 1199961127dSVincent Cuissard struct nci_uart *nu = NULL; 1209961127dSVincent Cuissard int ret; 1219961127dSVincent Cuissard 1229961127dSVincent Cuissard if (driver >= NCI_UART_DRIVER_MAX) 1239961127dSVincent Cuissard return -EINVAL; 1249961127dSVincent Cuissard 1259961127dSVincent Cuissard if (!nci_uart_drivers[driver]) 1269961127dSVincent Cuissard return -ENOENT; 1279961127dSVincent Cuissard 1289961127dSVincent Cuissard nu = kzalloc(sizeof(*nu), GFP_KERNEL); 1299961127dSVincent Cuissard if (!nu) 1309961127dSVincent Cuissard return -ENOMEM; 1319961127dSVincent Cuissard 1329961127dSVincent Cuissard memcpy(nu, nci_uart_drivers[driver], sizeof(struct nci_uart)); 1339961127dSVincent Cuissard nu->tty = tty; 1349961127dSVincent Cuissard tty->disc_data = nu; 1359961127dSVincent Cuissard skb_queue_head_init(&nu->tx_q); 1369961127dSVincent Cuissard INIT_WORK(&nu->write_work, nci_uart_write_work); 1379961127dSVincent Cuissard spin_lock_init(&nu->rx_lock); 1389961127dSVincent Cuissard 1399961127dSVincent Cuissard ret = nu->ops.open(nu); 1409961127dSVincent Cuissard if (ret) { 1419961127dSVincent Cuissard tty->disc_data = NULL; 1429961127dSVincent Cuissard kfree(nu); 1439961127dSVincent Cuissard } else if (!try_module_get(nu->owner)) { 1449961127dSVincent Cuissard nu->ops.close(nu); 1459961127dSVincent Cuissard tty->disc_data = NULL; 1469961127dSVincent Cuissard kfree(nu); 1479961127dSVincent Cuissard return -ENOENT; 1489961127dSVincent Cuissard } 1499961127dSVincent Cuissard return ret; 1509961127dSVincent Cuissard } 1519961127dSVincent Cuissard 1529961127dSVincent Cuissard /* ------ LDISC part ------ */ 1539961127dSVincent Cuissard 1549961127dSVincent Cuissard /* nci_uart_tty_open 1559961127dSVincent Cuissard * 1569961127dSVincent Cuissard * Called when line discipline changed to NCI_UART. 1579961127dSVincent Cuissard * 1589961127dSVincent Cuissard * Arguments: 1599961127dSVincent Cuissard * tty pointer to tty info structure 1609961127dSVincent Cuissard * Return Value: 1619961127dSVincent Cuissard * 0 if success, otherwise error code 1629961127dSVincent Cuissard */ 1639961127dSVincent Cuissard static int nci_uart_tty_open(struct tty_struct *tty) 1649961127dSVincent Cuissard { 1659961127dSVincent Cuissard /* Error if the tty has no write op instead of leaving an exploitable 1669961127dSVincent Cuissard * hole 1679961127dSVincent Cuissard */ 1689961127dSVincent Cuissard if (!tty->ops->write) 1699961127dSVincent Cuissard return -EOPNOTSUPP; 1709961127dSVincent Cuissard 1719961127dSVincent Cuissard tty->disc_data = NULL; 1729961127dSVincent Cuissard tty->receive_room = 65536; 1739961127dSVincent Cuissard 174582e20a0SPeter Hurley /* Flush any pending characters in the driver */ 1759961127dSVincent Cuissard tty_driver_flush_buffer(tty); 1769961127dSVincent Cuissard 1779961127dSVincent Cuissard return 0; 1789961127dSVincent Cuissard } 1799961127dSVincent Cuissard 1809961127dSVincent Cuissard /* nci_uart_tty_close() 1819961127dSVincent Cuissard * 1829961127dSVincent Cuissard * Called when the line discipline is changed to something 1839961127dSVincent Cuissard * else, the tty is closed, or the tty detects a hangup. 1849961127dSVincent Cuissard */ 1859961127dSVincent Cuissard static void nci_uart_tty_close(struct tty_struct *tty) 1869961127dSVincent Cuissard { 1879961127dSVincent Cuissard struct nci_uart *nu = (void *)tty->disc_data; 1889961127dSVincent Cuissard 1899961127dSVincent Cuissard /* Detach from the tty */ 1909961127dSVincent Cuissard tty->disc_data = NULL; 1919961127dSVincent Cuissard 1929961127dSVincent Cuissard if (!nu) 1939961127dSVincent Cuissard return; 1949961127dSVincent Cuissard 1959961127dSVincent Cuissard if (nu->tx_skb) 1969961127dSVincent Cuissard kfree_skb(nu->tx_skb); 1979961127dSVincent Cuissard if (nu->rx_skb) 1989961127dSVincent Cuissard kfree_skb(nu->rx_skb); 1999961127dSVincent Cuissard 2009961127dSVincent Cuissard skb_queue_purge(&nu->tx_q); 2019961127dSVincent Cuissard 2029961127dSVincent Cuissard nu->ops.close(nu); 2039961127dSVincent Cuissard nu->tty = NULL; 2049961127dSVincent Cuissard module_put(nu->owner); 2059961127dSVincent Cuissard 2069961127dSVincent Cuissard cancel_work_sync(&nu->write_work); 2079961127dSVincent Cuissard 2089961127dSVincent Cuissard kfree(nu); 2099961127dSVincent Cuissard } 2109961127dSVincent Cuissard 2119961127dSVincent Cuissard /* nci_uart_tty_wakeup() 2129961127dSVincent Cuissard * 2139961127dSVincent Cuissard * Callback for transmit wakeup. Called when low level 2149961127dSVincent Cuissard * device driver can accept more send data. 2159961127dSVincent Cuissard * 2169961127dSVincent Cuissard * Arguments: tty pointer to associated tty instance data 2179961127dSVincent Cuissard * Return Value: None 2189961127dSVincent Cuissard */ 2199961127dSVincent Cuissard static void nci_uart_tty_wakeup(struct tty_struct *tty) 2209961127dSVincent Cuissard { 2219961127dSVincent Cuissard struct nci_uart *nu = (void *)tty->disc_data; 2229961127dSVincent Cuissard 2239961127dSVincent Cuissard if (!nu) 2249961127dSVincent Cuissard return; 2259961127dSVincent Cuissard 2269961127dSVincent Cuissard clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); 2279961127dSVincent Cuissard 2289961127dSVincent Cuissard if (tty != nu->tty) 2299961127dSVincent Cuissard return; 2309961127dSVincent Cuissard 2319961127dSVincent Cuissard nci_uart_tx_wakeup(nu); 2329961127dSVincent Cuissard } 2339961127dSVincent Cuissard 2349961127dSVincent Cuissard /* nci_uart_tty_receive() 2359961127dSVincent Cuissard * 2369961127dSVincent Cuissard * Called by tty low level driver when receive data is 2379961127dSVincent Cuissard * available. 2389961127dSVincent Cuissard * 2399961127dSVincent Cuissard * Arguments: tty pointer to tty isntance data 2409961127dSVincent Cuissard * data pointer to received data 2419961127dSVincent Cuissard * flags pointer to flags for data 2429961127dSVincent Cuissard * count count of received data in bytes 2439961127dSVincent Cuissard * 2449961127dSVincent Cuissard * Return Value: None 2459961127dSVincent Cuissard */ 2469961127dSVincent Cuissard static void nci_uart_tty_receive(struct tty_struct *tty, const u8 *data, 2479961127dSVincent Cuissard char *flags, int count) 2489961127dSVincent Cuissard { 2499961127dSVincent Cuissard struct nci_uart *nu = (void *)tty->disc_data; 2509961127dSVincent Cuissard 2519961127dSVincent Cuissard if (!nu || tty != nu->tty) 2529961127dSVincent Cuissard return; 2539961127dSVincent Cuissard 2549961127dSVincent Cuissard spin_lock(&nu->rx_lock); 2559961127dSVincent Cuissard nu->ops.recv_buf(nu, (void *)data, flags, count); 2569961127dSVincent Cuissard spin_unlock(&nu->rx_lock); 2579961127dSVincent Cuissard 2589961127dSVincent Cuissard tty_unthrottle(tty); 2599961127dSVincent Cuissard } 2609961127dSVincent Cuissard 2619961127dSVincent Cuissard /* nci_uart_tty_ioctl() 2629961127dSVincent Cuissard * 2639961127dSVincent Cuissard * Process IOCTL system call for the tty device. 2649961127dSVincent Cuissard * 2659961127dSVincent Cuissard * Arguments: 2669961127dSVincent Cuissard * 2679961127dSVincent Cuissard * tty pointer to tty instance data 2689961127dSVincent Cuissard * file pointer to open file object for device 2699961127dSVincent Cuissard * cmd IOCTL command code 2709961127dSVincent Cuissard * arg argument for IOCTL call (cmd dependent) 2719961127dSVincent Cuissard * 2729961127dSVincent Cuissard * Return Value: Command dependent 2739961127dSVincent Cuissard */ 2749961127dSVincent Cuissard static int nci_uart_tty_ioctl(struct tty_struct *tty, struct file *file, 2759961127dSVincent Cuissard unsigned int cmd, unsigned long arg) 2769961127dSVincent Cuissard { 2779961127dSVincent Cuissard struct nci_uart *nu = (void *)tty->disc_data; 2789961127dSVincent Cuissard int err = 0; 2799961127dSVincent Cuissard 2809961127dSVincent Cuissard switch (cmd) { 2819961127dSVincent Cuissard case NCIUARTSETDRIVER: 2829961127dSVincent Cuissard if (!nu) 2839961127dSVincent Cuissard return nci_uart_set_driver(tty, (unsigned int)arg); 2849961127dSVincent Cuissard else 2859961127dSVincent Cuissard return -EBUSY; 2869961127dSVincent Cuissard break; 2879961127dSVincent Cuissard default: 2889961127dSVincent Cuissard err = n_tty_ioctl_helper(tty, file, cmd, arg); 2899961127dSVincent Cuissard break; 2909961127dSVincent Cuissard } 2919961127dSVincent Cuissard 2929961127dSVincent Cuissard return err; 2939961127dSVincent Cuissard } 2949961127dSVincent Cuissard 2959961127dSVincent Cuissard /* We don't provide read/write/poll interface for user space. */ 2969961127dSVincent Cuissard static ssize_t nci_uart_tty_read(struct tty_struct *tty, struct file *file, 2979961127dSVincent Cuissard unsigned char __user *buf, size_t nr) 2989961127dSVincent Cuissard { 2999961127dSVincent Cuissard return 0; 3009961127dSVincent Cuissard } 3019961127dSVincent Cuissard 3029961127dSVincent Cuissard static ssize_t nci_uart_tty_write(struct tty_struct *tty, struct file *file, 3039961127dSVincent Cuissard const unsigned char *data, size_t count) 3049961127dSVincent Cuissard { 3059961127dSVincent Cuissard return 0; 3069961127dSVincent Cuissard } 3079961127dSVincent Cuissard 308ade994f4SAl Viro static __poll_t nci_uart_tty_poll(struct tty_struct *tty, 3099961127dSVincent Cuissard struct file *filp, poll_table *wait) 3109961127dSVincent Cuissard { 3119961127dSVincent Cuissard return 0; 3129961127dSVincent Cuissard } 3139961127dSVincent Cuissard 3149961127dSVincent Cuissard static int nci_uart_send(struct nci_uart *nu, struct sk_buff *skb) 3159961127dSVincent Cuissard { 3169961127dSVincent Cuissard /* Queue TX packet */ 3179961127dSVincent Cuissard skb_queue_tail(&nu->tx_q, skb); 3189961127dSVincent Cuissard 3199961127dSVincent Cuissard /* Try to start TX (if possible) */ 3209961127dSVincent Cuissard nci_uart_tx_wakeup(nu); 3219961127dSVincent Cuissard 3229961127dSVincent Cuissard return 0; 3239961127dSVincent Cuissard } 3249961127dSVincent Cuissard 3259961127dSVincent Cuissard /* -- Default recv_buf handler -- 3269961127dSVincent Cuissard * 3279961127dSVincent Cuissard * This handler supposes that NCI frames are sent over UART link without any 3289961127dSVincent Cuissard * framing. It reads NCI header, retrieve the packet size and once all packet 3299961127dSVincent Cuissard * bytes are received it passes it to nci_uart driver for processing. 3309961127dSVincent Cuissard */ 3319961127dSVincent Cuissard static int nci_uart_default_recv_buf(struct nci_uart *nu, const u8 *data, 3329961127dSVincent Cuissard char *flags, int count) 3339961127dSVincent Cuissard { 3349961127dSVincent Cuissard int chunk_len; 3359961127dSVincent Cuissard 3369961127dSVincent Cuissard if (!nu->ndev) { 3379961127dSVincent Cuissard nfc_err(nu->tty->dev, 3389961127dSVincent Cuissard "receive data from tty but no NCI dev is attached yet, drop buffer\n"); 3399961127dSVincent Cuissard return 0; 3409961127dSVincent Cuissard } 3419961127dSVincent Cuissard 3429961127dSVincent Cuissard /* Decode all incoming data in packets 3439961127dSVincent Cuissard * and enqueue then for processing. 3449961127dSVincent Cuissard */ 3459961127dSVincent Cuissard while (count > 0) { 3469961127dSVincent Cuissard /* If this is the first data of a packet, allocate a buffer */ 3479961127dSVincent Cuissard if (!nu->rx_skb) { 3489961127dSVincent Cuissard nu->rx_packet_len = -1; 3499961127dSVincent Cuissard nu->rx_skb = nci_skb_alloc(nu->ndev, 3509961127dSVincent Cuissard NCI_MAX_PACKET_SIZE, 3519961127dSVincent Cuissard GFP_KERNEL); 3529961127dSVincent Cuissard if (!nu->rx_skb) 3539961127dSVincent Cuissard return -ENOMEM; 3549961127dSVincent Cuissard } 3559961127dSVincent Cuissard 3569961127dSVincent Cuissard /* Eat byte after byte till full packet header is received */ 3579961127dSVincent Cuissard if (nu->rx_skb->len < NCI_CTRL_HDR_SIZE) { 358634fef61SJohannes Berg skb_put_u8(nu->rx_skb, *data++); 3599961127dSVincent Cuissard --count; 3609961127dSVincent Cuissard continue; 3619961127dSVincent Cuissard } 3629961127dSVincent Cuissard 3639961127dSVincent Cuissard /* Header was received but packet len was not read */ 3649961127dSVincent Cuissard if (nu->rx_packet_len < 0) 3659961127dSVincent Cuissard nu->rx_packet_len = NCI_CTRL_HDR_SIZE + 3669961127dSVincent Cuissard nci_plen(nu->rx_skb->data); 3679961127dSVincent Cuissard 3689961127dSVincent Cuissard /* Compute how many bytes are missing and how many bytes can 3699961127dSVincent Cuissard * be consumed. 3709961127dSVincent Cuissard */ 3719961127dSVincent Cuissard chunk_len = nu->rx_packet_len - nu->rx_skb->len; 3729961127dSVincent Cuissard if (count < chunk_len) 3739961127dSVincent Cuissard chunk_len = count; 37459ae1d12SJohannes Berg skb_put_data(nu->rx_skb, data, chunk_len); 3759961127dSVincent Cuissard data += chunk_len; 3769961127dSVincent Cuissard count -= chunk_len; 3779961127dSVincent Cuissard 3789961127dSVincent Cuissard /* Chcek if packet is fully received */ 3799961127dSVincent Cuissard if (nu->rx_packet_len == nu->rx_skb->len) { 3809961127dSVincent Cuissard /* Pass RX packet to driver */ 3819961127dSVincent Cuissard if (nu->ops.recv(nu, nu->rx_skb) != 0) 3829961127dSVincent Cuissard nfc_err(nu->tty->dev, "corrupted RX packet\n"); 3839961127dSVincent Cuissard /* Next packet will be a new one */ 3849961127dSVincent Cuissard nu->rx_skb = NULL; 3859961127dSVincent Cuissard } 3869961127dSVincent Cuissard } 3879961127dSVincent Cuissard 3889961127dSVincent Cuissard return 0; 3899961127dSVincent Cuissard } 3909961127dSVincent Cuissard 3919961127dSVincent Cuissard /* -- Default recv handler -- */ 3929961127dSVincent Cuissard static int nci_uart_default_recv(struct nci_uart *nu, struct sk_buff *skb) 3939961127dSVincent Cuissard { 3949961127dSVincent Cuissard return nci_recv_frame(nu->ndev, skb); 3959961127dSVincent Cuissard } 3969961127dSVincent Cuissard 3979961127dSVincent Cuissard int nci_uart_register(struct nci_uart *nu) 3989961127dSVincent Cuissard { 3999961127dSVincent Cuissard if (!nu || !nu->ops.open || 4009961127dSVincent Cuissard !nu->ops.recv || !nu->ops.close) 4019961127dSVincent Cuissard return -EINVAL; 4029961127dSVincent Cuissard 4039961127dSVincent Cuissard /* Set the send callback */ 4049961127dSVincent Cuissard nu->ops.send = nci_uart_send; 4059961127dSVincent Cuissard 4069961127dSVincent Cuissard /* Install default handlers if not overridden */ 4079961127dSVincent Cuissard if (!nu->ops.recv_buf) 4089961127dSVincent Cuissard nu->ops.recv_buf = nci_uart_default_recv_buf; 4099961127dSVincent Cuissard if (!nu->ops.recv) 4109961127dSVincent Cuissard nu->ops.recv = nci_uart_default_recv; 4119961127dSVincent Cuissard 4129961127dSVincent Cuissard /* Add this driver in the driver list */ 413fb77ff4fSVincent Cuissard if (nci_uart_drivers[nu->driver]) { 4149961127dSVincent Cuissard pr_err("driver %d is already registered\n", nu->driver); 4159961127dSVincent Cuissard return -EBUSY; 4169961127dSVincent Cuissard } 4179961127dSVincent Cuissard nci_uart_drivers[nu->driver] = nu; 4189961127dSVincent Cuissard 4199961127dSVincent Cuissard pr_info("NCI uart driver '%s [%d]' registered\n", nu->name, nu->driver); 4209961127dSVincent Cuissard 4219961127dSVincent Cuissard return 0; 4229961127dSVincent Cuissard } 4239961127dSVincent Cuissard EXPORT_SYMBOL_GPL(nci_uart_register); 4249961127dSVincent Cuissard 4259961127dSVincent Cuissard void nci_uart_unregister(struct nci_uart *nu) 4269961127dSVincent Cuissard { 4279961127dSVincent Cuissard pr_info("NCI uart driver '%s [%d]' unregistered\n", nu->name, 4289961127dSVincent Cuissard nu->driver); 4299961127dSVincent Cuissard 4309961127dSVincent Cuissard /* Remove this driver from the driver list */ 4319961127dSVincent Cuissard nci_uart_drivers[nu->driver] = NULL; 4329961127dSVincent Cuissard } 4339961127dSVincent Cuissard EXPORT_SYMBOL_GPL(nci_uart_unregister); 4349961127dSVincent Cuissard 4359961127dSVincent Cuissard void nci_uart_set_config(struct nci_uart *nu, int baudrate, int flow_ctrl) 4369961127dSVincent Cuissard { 4379961127dSVincent Cuissard struct ktermios new_termios; 4389961127dSVincent Cuissard 4399961127dSVincent Cuissard if (!nu->tty) 4409961127dSVincent Cuissard return; 4419961127dSVincent Cuissard 4429961127dSVincent Cuissard down_read(&nu->tty->termios_rwsem); 4439961127dSVincent Cuissard new_termios = nu->tty->termios; 4449961127dSVincent Cuissard up_read(&nu->tty->termios_rwsem); 4459961127dSVincent Cuissard tty_termios_encode_baud_rate(&new_termios, baudrate, baudrate); 4469961127dSVincent Cuissard 4479961127dSVincent Cuissard if (flow_ctrl) 4489961127dSVincent Cuissard new_termios.c_cflag |= CRTSCTS; 4499961127dSVincent Cuissard else 4509961127dSVincent Cuissard new_termios.c_cflag &= ~CRTSCTS; 4519961127dSVincent Cuissard 4529961127dSVincent Cuissard tty_set_termios(nu->tty, &new_termios); 4539961127dSVincent Cuissard } 4549961127dSVincent Cuissard EXPORT_SYMBOL_GPL(nci_uart_set_config); 4559961127dSVincent Cuissard 4569961127dSVincent Cuissard static struct tty_ldisc_ops nci_uart_ldisc = { 4579961127dSVincent Cuissard .magic = TTY_LDISC_MAGIC, 4589961127dSVincent Cuissard .owner = THIS_MODULE, 4599961127dSVincent Cuissard .name = "n_nci", 4609961127dSVincent Cuissard .open = nci_uart_tty_open, 4619961127dSVincent Cuissard .close = nci_uart_tty_close, 4629961127dSVincent Cuissard .read = nci_uart_tty_read, 4639961127dSVincent Cuissard .write = nci_uart_tty_write, 4649961127dSVincent Cuissard .poll = nci_uart_tty_poll, 4659961127dSVincent Cuissard .receive_buf = nci_uart_tty_receive, 4669961127dSVincent Cuissard .write_wakeup = nci_uart_tty_wakeup, 4679961127dSVincent Cuissard .ioctl = nci_uart_tty_ioctl, 4689961127dSVincent Cuissard }; 4699961127dSVincent Cuissard 4709961127dSVincent Cuissard static int __init nci_uart_init(void) 4719961127dSVincent Cuissard { 4729961127dSVincent Cuissard memset(nci_uart_drivers, 0, sizeof(nci_uart_drivers)); 4739961127dSVincent Cuissard return tty_register_ldisc(N_NCI, &nci_uart_ldisc); 4749961127dSVincent Cuissard } 4759961127dSVincent Cuissard 4769961127dSVincent Cuissard static void __exit nci_uart_exit(void) 4779961127dSVincent Cuissard { 4789961127dSVincent Cuissard tty_unregister_ldisc(N_NCI); 4799961127dSVincent Cuissard } 4809961127dSVincent Cuissard 4819961127dSVincent Cuissard module_init(nci_uart_init); 4829961127dSVincent Cuissard module_exit(nci_uart_exit); 4839961127dSVincent Cuissard 4849961127dSVincent Cuissard MODULE_AUTHOR("Marvell International Ltd."); 4859961127dSVincent Cuissard MODULE_DESCRIPTION("NFC NCI UART driver"); 4869961127dSVincent Cuissard MODULE_LICENSE("GPL"); 4879961127dSVincent Cuissard MODULE_ALIAS_LDISC(N_NCI); 488