1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright (C) 2015, Marvell International Ltd. |
4 | * |
5 | * Inspired (hugely) by HCI LDISC implementation in Bluetooth. |
6 | * |
7 | * Copyright (C) 2000-2001 Qualcomm Incorporated |
8 | * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com> |
9 | * Copyright (C) 2004-2005 Marcel Holtmann <marcel@holtmann.org> |
10 | */ |
11 | |
12 | #include <linux/module.h> |
13 | |
14 | #include <linux/kernel.h> |
15 | #include <linux/init.h> |
16 | #include <linux/types.h> |
17 | #include <linux/fcntl.h> |
18 | #include <linux/interrupt.h> |
19 | #include <linux/ptrace.h> |
20 | #include <linux/poll.h> |
21 | |
22 | #include <linux/slab.h> |
23 | #include <linux/tty.h> |
24 | #include <linux/errno.h> |
25 | #include <linux/string.h> |
26 | #include <linux/signal.h> |
27 | #include <linux/ioctl.h> |
28 | #include <linux/skbuff.h> |
29 | |
30 | #include <net/nfc/nci.h> |
31 | #include <net/nfc/nci_core.h> |
32 | |
33 | /* TX states */ |
34 | #define NCI_UART_SENDING 1 |
35 | #define NCI_UART_TX_WAKEUP 2 |
36 | |
37 | static struct nci_uart *nci_uart_drivers[NCI_UART_DRIVER_MAX]; |
38 | |
39 | static inline struct sk_buff *nci_uart_dequeue(struct nci_uart *nu) |
40 | { |
41 | struct sk_buff *skb = nu->tx_skb; |
42 | |
43 | if (!skb) |
44 | skb = skb_dequeue(list: &nu->tx_q); |
45 | else |
46 | nu->tx_skb = NULL; |
47 | |
48 | return skb; |
49 | } |
50 | |
51 | static inline int nci_uart_queue_empty(struct nci_uart *nu) |
52 | { |
53 | if (nu->tx_skb) |
54 | return 0; |
55 | |
56 | return skb_queue_empty(list: &nu->tx_q); |
57 | } |
58 | |
59 | static int nci_uart_tx_wakeup(struct nci_uart *nu) |
60 | { |
61 | if (test_and_set_bit(NCI_UART_SENDING, addr: &nu->tx_state)) { |
62 | set_bit(NCI_UART_TX_WAKEUP, addr: &nu->tx_state); |
63 | return 0; |
64 | } |
65 | |
66 | schedule_work(work: &nu->write_work); |
67 | |
68 | return 0; |
69 | } |
70 | |
71 | static void nci_uart_write_work(struct work_struct *work) |
72 | { |
73 | struct nci_uart *nu = container_of(work, struct nci_uart, write_work); |
74 | struct tty_struct *tty = nu->tty; |
75 | struct sk_buff *skb; |
76 | |
77 | restart: |
78 | clear_bit(NCI_UART_TX_WAKEUP, addr: &nu->tx_state); |
79 | |
80 | if (nu->ops.tx_start) |
81 | nu->ops.tx_start(nu); |
82 | |
83 | while ((skb = nci_uart_dequeue(nu))) { |
84 | int len; |
85 | |
86 | set_bit(TTY_DO_WRITE_WAKEUP, addr: &tty->flags); |
87 | len = tty->ops->write(tty, skb->data, skb->len); |
88 | skb_pull(skb, len); |
89 | if (skb->len) { |
90 | nu->tx_skb = skb; |
91 | break; |
92 | } |
93 | kfree_skb(skb); |
94 | } |
95 | |
96 | if (test_bit(NCI_UART_TX_WAKEUP, &nu->tx_state)) |
97 | goto restart; |
98 | |
99 | if (nu->ops.tx_done && nci_uart_queue_empty(nu)) |
100 | nu->ops.tx_done(nu); |
101 | |
102 | clear_bit(NCI_UART_SENDING, addr: &nu->tx_state); |
103 | } |
104 | |
105 | static int nci_uart_set_driver(struct tty_struct *tty, unsigned int driver) |
106 | { |
107 | struct nci_uart *nu = NULL; |
108 | int ret; |
109 | |
110 | if (driver >= NCI_UART_DRIVER_MAX) |
111 | return -EINVAL; |
112 | |
113 | if (!nci_uart_drivers[driver]) |
114 | return -ENOENT; |
115 | |
116 | nu = kzalloc(size: sizeof(*nu), GFP_KERNEL); |
117 | if (!nu) |
118 | return -ENOMEM; |
119 | |
120 | memcpy(nu, nci_uart_drivers[driver], sizeof(struct nci_uart)); |
121 | nu->tty = tty; |
122 | tty->disc_data = nu; |
123 | skb_queue_head_init(list: &nu->tx_q); |
124 | INIT_WORK(&nu->write_work, nci_uart_write_work); |
125 | spin_lock_init(&nu->rx_lock); |
126 | |
127 | ret = nu->ops.open(nu); |
128 | if (ret) { |
129 | tty->disc_data = NULL; |
130 | kfree(objp: nu); |
131 | } else if (!try_module_get(module: nu->owner)) { |
132 | nu->ops.close(nu); |
133 | tty->disc_data = NULL; |
134 | kfree(objp: nu); |
135 | return -ENOENT; |
136 | } |
137 | return ret; |
138 | } |
139 | |
140 | /* ------ LDISC part ------ */ |
141 | |
142 | /* nci_uart_tty_open |
143 | * |
144 | * Called when line discipline changed to NCI_UART. |
145 | * |
146 | * Arguments: |
147 | * tty pointer to tty info structure |
148 | * Return Value: |
149 | * 0 if success, otherwise error code |
150 | */ |
151 | static int nci_uart_tty_open(struct tty_struct *tty) |
152 | { |
153 | /* Error if the tty has no write op instead of leaving an exploitable |
154 | * hole |
155 | */ |
156 | if (!tty->ops->write) |
157 | return -EOPNOTSUPP; |
158 | |
159 | tty->disc_data = NULL; |
160 | tty->receive_room = 65536; |
161 | |
162 | /* Flush any pending characters in the driver */ |
163 | tty_driver_flush_buffer(tty); |
164 | |
165 | return 0; |
166 | } |
167 | |
168 | /* nci_uart_tty_close() |
169 | * |
170 | * Called when the line discipline is changed to something |
171 | * else, the tty is closed, or the tty detects a hangup. |
172 | */ |
173 | static void nci_uart_tty_close(struct tty_struct *tty) |
174 | { |
175 | struct nci_uart *nu = tty->disc_data; |
176 | |
177 | /* Detach from the tty */ |
178 | tty->disc_data = NULL; |
179 | |
180 | if (!nu) |
181 | return; |
182 | |
183 | kfree_skb(skb: nu->tx_skb); |
184 | kfree_skb(skb: nu->rx_skb); |
185 | |
186 | skb_queue_purge(list: &nu->tx_q); |
187 | |
188 | nu->ops.close(nu); |
189 | nu->tty = NULL; |
190 | module_put(module: nu->owner); |
191 | |
192 | cancel_work_sync(work: &nu->write_work); |
193 | |
194 | kfree(objp: nu); |
195 | } |
196 | |
197 | /* nci_uart_tty_wakeup() |
198 | * |
199 | * Callback for transmit wakeup. Called when low level |
200 | * device driver can accept more send data. |
201 | * |
202 | * Arguments: tty pointer to associated tty instance data |
203 | * Return Value: None |
204 | */ |
205 | static void nci_uart_tty_wakeup(struct tty_struct *tty) |
206 | { |
207 | struct nci_uart *nu = tty->disc_data; |
208 | |
209 | if (!nu) |
210 | return; |
211 | |
212 | clear_bit(TTY_DO_WRITE_WAKEUP, addr: &tty->flags); |
213 | |
214 | if (tty != nu->tty) |
215 | return; |
216 | |
217 | nci_uart_tx_wakeup(nu); |
218 | } |
219 | |
220 | /* -- Default recv_buf handler -- |
221 | * |
222 | * This handler supposes that NCI frames are sent over UART link without any |
223 | * framing. It reads NCI header, retrieve the packet size and once all packet |
224 | * bytes are received it passes it to nci_uart driver for processing. |
225 | */ |
226 | static int nci_uart_default_recv_buf(struct nci_uart *nu, const u8 *data, |
227 | int count) |
228 | { |
229 | int chunk_len; |
230 | |
231 | if (!nu->ndev) { |
232 | nfc_err(nu->tty->dev, |
233 | "receive data from tty but no NCI dev is attached yet, drop buffer\n" ); |
234 | return 0; |
235 | } |
236 | |
237 | /* Decode all incoming data in packets |
238 | * and enqueue then for processing. |
239 | */ |
240 | while (count > 0) { |
241 | /* If this is the first data of a packet, allocate a buffer */ |
242 | if (!nu->rx_skb) { |
243 | nu->rx_packet_len = -1; |
244 | nu->rx_skb = nci_skb_alloc(ndev: nu->ndev, |
245 | NCI_MAX_PACKET_SIZE, |
246 | GFP_ATOMIC); |
247 | if (!nu->rx_skb) |
248 | return -ENOMEM; |
249 | } |
250 | |
251 | /* Eat byte after byte till full packet header is received */ |
252 | if (nu->rx_skb->len < NCI_CTRL_HDR_SIZE) { |
253 | skb_put_u8(skb: nu->rx_skb, val: *data++); |
254 | --count; |
255 | continue; |
256 | } |
257 | |
258 | /* Header was received but packet len was not read */ |
259 | if (nu->rx_packet_len < 0) |
260 | nu->rx_packet_len = NCI_CTRL_HDR_SIZE + |
261 | nci_plen(nu->rx_skb->data); |
262 | |
263 | /* Compute how many bytes are missing and how many bytes can |
264 | * be consumed. |
265 | */ |
266 | chunk_len = nu->rx_packet_len - nu->rx_skb->len; |
267 | if (count < chunk_len) |
268 | chunk_len = count; |
269 | skb_put_data(skb: nu->rx_skb, data, len: chunk_len); |
270 | data += chunk_len; |
271 | count -= chunk_len; |
272 | |
273 | /* Check if packet is fully received */ |
274 | if (nu->rx_packet_len == nu->rx_skb->len) { |
275 | /* Pass RX packet to driver */ |
276 | if (nu->ops.recv(nu, nu->rx_skb) != 0) |
277 | nfc_err(nu->tty->dev, "corrupted RX packet\n" ); |
278 | /* Next packet will be a new one */ |
279 | nu->rx_skb = NULL; |
280 | } |
281 | } |
282 | |
283 | return 0; |
284 | } |
285 | |
286 | /* nci_uart_tty_receive() |
287 | * |
288 | * Called by tty low level driver when receive data is |
289 | * available. |
290 | * |
291 | * Arguments: tty pointer to tty instance data |
292 | * data pointer to received data |
293 | * flags pointer to flags for data |
294 | * count count of received data in bytes |
295 | * |
296 | * Return Value: None |
297 | */ |
298 | static void nci_uart_tty_receive(struct tty_struct *tty, const u8 *data, |
299 | const u8 *flags, size_t count) |
300 | { |
301 | struct nci_uart *nu = tty->disc_data; |
302 | |
303 | if (!nu || tty != nu->tty) |
304 | return; |
305 | |
306 | spin_lock(lock: &nu->rx_lock); |
307 | nci_uart_default_recv_buf(nu, data, count); |
308 | spin_unlock(lock: &nu->rx_lock); |
309 | |
310 | tty_unthrottle(tty); |
311 | } |
312 | |
313 | /* nci_uart_tty_ioctl() |
314 | * |
315 | * Process IOCTL system call for the tty device. |
316 | * |
317 | * Arguments: |
318 | * |
319 | * tty pointer to tty instance data |
320 | * cmd IOCTL command code |
321 | * arg argument for IOCTL call (cmd dependent) |
322 | * |
323 | * Return Value: Command dependent |
324 | */ |
325 | static int nci_uart_tty_ioctl(struct tty_struct *tty, unsigned int cmd, |
326 | unsigned long arg) |
327 | { |
328 | struct nci_uart *nu = tty->disc_data; |
329 | int err = 0; |
330 | |
331 | switch (cmd) { |
332 | case NCIUARTSETDRIVER: |
333 | if (!nu) |
334 | return nci_uart_set_driver(tty, driver: (unsigned int)arg); |
335 | else |
336 | return -EBUSY; |
337 | break; |
338 | default: |
339 | err = n_tty_ioctl_helper(tty, cmd, arg); |
340 | break; |
341 | } |
342 | |
343 | return err; |
344 | } |
345 | |
346 | /* We don't provide read/write/poll interface for user space. */ |
347 | static ssize_t nci_uart_tty_read(struct tty_struct *tty, struct file *file, |
348 | u8 *buf, size_t nr, void **cookie, |
349 | unsigned long offset) |
350 | { |
351 | return 0; |
352 | } |
353 | |
354 | static ssize_t nci_uart_tty_write(struct tty_struct *tty, struct file *file, |
355 | const u8 *data, size_t count) |
356 | { |
357 | return 0; |
358 | } |
359 | |
360 | static int nci_uart_send(struct nci_uart *nu, struct sk_buff *skb) |
361 | { |
362 | /* Queue TX packet */ |
363 | skb_queue_tail(list: &nu->tx_q, newsk: skb); |
364 | |
365 | /* Try to start TX (if possible) */ |
366 | nci_uart_tx_wakeup(nu); |
367 | |
368 | return 0; |
369 | } |
370 | |
371 | int nci_uart_register(struct nci_uart *nu) |
372 | { |
373 | if (!nu || !nu->ops.open || |
374 | !nu->ops.recv || !nu->ops.close) |
375 | return -EINVAL; |
376 | |
377 | /* Set the send callback */ |
378 | nu->ops.send = nci_uart_send; |
379 | |
380 | /* Add this driver in the driver list */ |
381 | if (nci_uart_drivers[nu->driver]) { |
382 | pr_err("driver %d is already registered\n" , nu->driver); |
383 | return -EBUSY; |
384 | } |
385 | nci_uart_drivers[nu->driver] = nu; |
386 | |
387 | pr_info("NCI uart driver '%s [%d]' registered\n" , nu->name, nu->driver); |
388 | |
389 | return 0; |
390 | } |
391 | EXPORT_SYMBOL_GPL(nci_uart_register); |
392 | |
393 | void nci_uart_unregister(struct nci_uart *nu) |
394 | { |
395 | pr_info("NCI uart driver '%s [%d]' unregistered\n" , nu->name, |
396 | nu->driver); |
397 | |
398 | /* Remove this driver from the driver list */ |
399 | nci_uart_drivers[nu->driver] = NULL; |
400 | } |
401 | EXPORT_SYMBOL_GPL(nci_uart_unregister); |
402 | |
403 | void nci_uart_set_config(struct nci_uart *nu, int baudrate, int flow_ctrl) |
404 | { |
405 | struct ktermios new_termios; |
406 | |
407 | if (!nu->tty) |
408 | return; |
409 | |
410 | down_read(sem: &nu->tty->termios_rwsem); |
411 | new_termios = nu->tty->termios; |
412 | up_read(sem: &nu->tty->termios_rwsem); |
413 | tty_termios_encode_baud_rate(termios: &new_termios, ibaud: baudrate, obaud: baudrate); |
414 | |
415 | if (flow_ctrl) |
416 | new_termios.c_cflag |= CRTSCTS; |
417 | else |
418 | new_termios.c_cflag &= ~CRTSCTS; |
419 | |
420 | tty_set_termios(tty: nu->tty, kt: &new_termios); |
421 | } |
422 | EXPORT_SYMBOL_GPL(nci_uart_set_config); |
423 | |
424 | static struct tty_ldisc_ops nci_uart_ldisc = { |
425 | .owner = THIS_MODULE, |
426 | .num = N_NCI, |
427 | .name = "n_nci" , |
428 | .open = nci_uart_tty_open, |
429 | .close = nci_uart_tty_close, |
430 | .read = nci_uart_tty_read, |
431 | .write = nci_uart_tty_write, |
432 | .receive_buf = nci_uart_tty_receive, |
433 | .write_wakeup = nci_uart_tty_wakeup, |
434 | .ioctl = nci_uart_tty_ioctl, |
435 | .compat_ioctl = nci_uart_tty_ioctl, |
436 | }; |
437 | |
438 | static int __init nci_uart_init(void) |
439 | { |
440 | return tty_register_ldisc(new_ldisc: &nci_uart_ldisc); |
441 | } |
442 | |
443 | static void __exit nci_uart_exit(void) |
444 | { |
445 | tty_unregister_ldisc(ldisc: &nci_uart_ldisc); |
446 | } |
447 | |
448 | module_init(nci_uart_init); |
449 | module_exit(nci_uart_exit); |
450 | |
451 | MODULE_AUTHOR("Marvell International Ltd." ); |
452 | MODULE_DESCRIPTION("NFC NCI UART driver" ); |
453 | MODULE_LICENSE("GPL" ); |
454 | MODULE_ALIAS_LDISC(N_NCI); |
455 | |