blob: 0194eacc563a5fb48e1ac44751b3fa84e0ee529f [file] [log] [blame]
Carl van Schaik438aa182018-07-06 22:22:42 +10001/*
2 * drivers/char/vservice_serial.c
3 *
4 * Copyright (c) 2012-2018 General Dynamics
5 * Copyright (c) 2014 Open Kernel Labs, Inc.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * serial vservice client driver
12 *
13 */
14
15#include <linux/kernel.h>
16#include <linux/module.h>
17#include <linux/bitmap.h>
18#include <linux/tty.h>
19#include <linux/tty_driver.h>
20#include <linux/tty_flip.h>
21#include <linux/console.h>
22#include <linux/version.h>
23#include <linux/sched.h>
24#include <linux/wait.h>
25#include <linux/mutex.h>
26
27#include <vservices/transport.h>
28#include <vservices/types.h>
29#include <vservices/buffer.h>
30#include <vservices/protocol/serial/common.h>
31#include <vservices/protocol/serial/types.h>
32#include <vservices/protocol/serial/server.h>
33#include <vservices/service.h>
34#include <vservices/wait.h>
35
36#include "vs_serial_common.h"
37
38struct vtty_in_packet {
39 struct vs_pbuf pbuf;
40 size_t offset;
41};
42
43static int max_ttys = CONFIG_VSERVICES_VTTY_COUNT;
44static unsigned long *alloced_ttys;
45module_param(max_ttys, int, S_IRUGO);
46
47static struct tty_driver *vtty_driver;
48
49static DEFINE_MUTEX(tty_bitmap_lock);
50
51static struct vtty_port *dev_to_port(struct device *dev)
52{
53 struct vs_service_device *service = to_vs_service_device(dev);
54
55#if defined(CONFIG_VSERVICES_SERIAL_SERVER) || \
56 defined(CONFIG_VSERIVCES_SERIAL_SERVER_MODULE)
57 if (service->is_server) {
58 struct vs_server_serial_state *server = dev_get_drvdata(dev);
59 return container_of(server, struct vtty_port, u.vs_server);
60 }
61#endif
62#if defined(CONFIG_VSERVICES_SERIAL_CLIENT) || \
63 defined(CONFIG_VSERIVCES_SERIAL_CLIENT_MODULE)
64 if (!service->is_server) {
65 struct vs_client_serial_state *client = dev_get_drvdata(dev);
66 return container_of(client, struct vtty_port, u.vs_client);
67 }
68#endif
69 /* should never get here */
70 WARN_ON(1);
71 return NULL;
72}
73
74static struct vtty_port *port_from_tty(struct tty_struct *tty)
75{
76 return dev_to_port(tty->dev->parent);
77}
78
79static int vtty_install(struct tty_driver *driver, struct tty_struct *tty)
80{
81 struct vtty_port *port;
82
83 if (tty->index < 0 || !test_bit(tty->index, alloced_ttys))
84 return -ENXIO;
85
86 port = port_from_tty(tty);
87
88 if (!port)
89 return -ENXIO;
90
91 tty->driver_data = port;
92#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0)
93 if (tty->port)
94 tty->port->low_latency = 0;
95#else
96 tty->low_latency = 0;
97#endif
98
99#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
100 tty_port_install(&port->port, driver, tty);
101#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0)
102 tty->port = &port->port;
103 tty_standard_install(driver, tty);
104#else
105 tty->port = &port->port;
106 if (tty_init_termios(tty) != 0)
107 return -ENOMEM;
108
109 tty_driver_kref_get(driver);
110 tty->count++;
111 driver->ttys[tty->index] = tty;
112#endif
113
114 return 0;
115}
116
117static int vtty_open(struct tty_struct *tty, struct file *file)
118{
119 struct vtty_port *port = tty->driver_data;
120 return tty_port_open(&port->port, tty, file);
121}
122
123static void vtty_close(struct tty_struct *tty, struct file *file)
124{
125 struct vtty_port *port = tty->driver_data;
126 if (port)
127 tty_port_close(&port->port, tty, file);
128}
129
130static void vtty_shutdown(struct tty_port *port)
131{
132 struct vtty_port *vtty_port =
133 container_of(port, struct vtty_port, port);
134
135 if (vtty_port->doing_release)
136 kfree(port);
137}
138
139static int vtty_write_room(struct tty_struct *tty)
140{
141 struct vtty_port *port = tty->driver_data;
142
143 return vs_service_send_mbufs_available(port->service) *
144 port->max_transfer_size;
145}
146
147static struct vs_mbuf *vserial_alloc_send_buffer(struct vtty_port *port,
148 const unsigned char *buf, size_t size, struct vs_pbuf *pbuf,
149 gfp_t gfp_flags)
150{
151 struct vs_mbuf *mbuf;
152 ssize_t ret;
153
154 mbuf = port->ops.alloc_msg_buf(port, pbuf, gfp_flags);
155 if (IS_ERR(mbuf)) {
156 ret = PTR_ERR(mbuf);
157 goto fail;
158 }
159
160 ret = vs_pbuf_resize(pbuf, size);
161 if (ret < (ssize_t)size)
162 goto fail_free_buf;
163
164 ret = vs_pbuf_copyin(pbuf, 0, buf, size);
165 if (ret < (ssize_t)size)
166 goto fail_free_buf;
167
168 return mbuf;
169
170fail_free_buf:
171 port->ops.free_msg_buf(port, mbuf, pbuf);
172fail:
173 return ERR_PTR(ret);
174}
175
176static int vtty_write(struct tty_struct *tty, const unsigned char *buf,
177 int count)
178{
179 struct vtty_port *port;
180 size_t sent_bytes = 0, size;
181 struct vs_mbuf *mbuf;
182 struct vs_pbuf pbuf;
183 int err;
184
185 if (WARN_ON(!tty || !buf))
186 return -EINVAL;
187
188 port = tty->driver_data;
189 if (!port->ops.is_running(port)) {
190 dev_dbg(&port->service->dev, "tty is not running!");
191 return 0;
192 }
193
194 /*
195 * We need to break our message up into chunks of
196 * port->max_transfer_size.
197 */
198 dev_dbg(&port->service->dev, "Writing %d bytes\n", count);
199 while (sent_bytes < count) {
200 size = min_t(size_t, count - sent_bytes,
201 port->max_transfer_size);
202
203 /*
204 * Passing &port->u.vs_client here works for both the client
205 * and the server since vs_client and vs_server are in the
206 * same union, and therefore have the same address.
207 */
208 mbuf = vs_service_waiting_alloc(&port->u.vs_client,
209 vserial_alloc_send_buffer(port,
210 buf + sent_bytes, size, &pbuf, GFP_KERNEL));
211 if (IS_ERR(mbuf)) {
212 dev_err(&port->service->dev,
213 "Failed to alloc mbuf of %zu bytes: %ld - resetting service\n",
214 size, PTR_ERR(mbuf));
215 vs_service_reset(port->service, port->service);
216 return -EIO;
217 }
218
219 vs_service_state_lock(port->service);
220 err = port->ops.send_msg_buf(port, mbuf, &pbuf);
221 vs_service_state_unlock(port->service);
222 if (err) {
223 port->ops.free_msg_buf(port, mbuf, &pbuf);
224 dev_err(&port->service->dev,
225 "send failed: %d - resetting service",
226 err);
227 vs_service_reset(port->service, port->service);
228 return -EIO;
229 }
230
231 dev_dbg(&port->service->dev, "Sent %zu bytes (%zu/%d)\n",
232 size, sent_bytes + size, count);
233 sent_bytes += size;
234 }
235
236 dev_dbg(&port->service->dev, "Write complete - sent %zu/%d bytes\n",
237 sent_bytes, count);
238 return sent_bytes;
239}
240
241static int vtty_put_char(struct tty_struct *tty, unsigned char ch)
242{
243 return vtty_write(tty, &ch, 1);
244}
245
246static size_t vs_serial_send_pbuf_to_tty(struct vtty_port *port,
247 struct vs_pbuf *pbuf, size_t offset)
248{
249 struct tty_struct *tty = tty_port_tty_get(&port->port);
250 size_t space, size;
251
252 lockdep_assert_held(&port->in_lock);
253
254 size = vs_pbuf_size(pbuf) - offset;
255#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0)
256 space = tty_buffer_request_room(tty->port, size);
257#else
258 space = tty_buffer_request_room(tty, size);
259#endif
260 if (space) {
261#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0)
262 tty_insert_flip_string(tty->port, pbuf->data + offset, space);
263 tty_flip_buffer_push(tty->port);
264#else
265 tty_insert_flip_string(tty, pbuf->data + offset, space);
266 tty_flip_buffer_push(tty);
267#endif
268 }
269
270 tty_kref_put(tty);
271
272 /* Return the number of bytes written */
273 return space;
274}
275
276static void vtty_throttle(struct tty_struct *tty)
277{
278 struct vtty_port *port = tty->driver_data;
279
280 dev_dbg(&port->service->dev, "throttle\n");
281
282 spin_lock_bh(&port->in_lock);
283 port->tty_canrecv = false;
284 spin_unlock_bh(&port->in_lock);
285}
286
287static void vtty_unthrottle(struct tty_struct *tty)
288{
289 struct vtty_port *port = tty->driver_data;
290 struct vtty_in_packet *packet;
291 struct vs_mbuf *mbuf;
292 size_t sent;
293
294 dev_dbg(&port->service->dev, "unthrottle\n");
295
296 spin_lock_bh(&port->in_lock);
297
298 while (!list_empty(&port->pending_in_packets)) {
299 mbuf = list_first_entry(&port->pending_in_packets,
300 struct vs_mbuf, queue);
301 packet = mbuf->priv;
302
303 sent = vs_serial_send_pbuf_to_tty(port, &packet->pbuf,
304 packet->offset);
305 packet->offset += sent;
306 if (packet->offset < vs_pbuf_size(&packet->pbuf)) {
307 /*
308 * Only wrote part of the buffer. This means that we
309 * still have pending data that cannot be written to
310 * the tty at this time. The tty layer will rethrottle
311 * and this function will be called again when the tty
312 * layer is next able to handle data and we can write
313 * the remainder of the buffer.
314 */
315 dev_dbg(&port->service->dev,
316 "unthrottle: Only wrote %zu (%zu/%zu) bytes\n",
317 sent, packet->offset,
318 vs_pbuf_size(&packet->pbuf));
319 break;
320 }
321
322 dev_dbg(&port->service->dev,
323 "unthrottle: wrote %zu (%zu/%zu) bytes\n",
324 sent, packet->offset,
325 vs_pbuf_size(&packet->pbuf));
326
327 /* Wrote the whole buffer - free it */
328 list_del(&mbuf->queue);
329 port->ops.free_msg_buf(port, mbuf, &packet->pbuf);
330 kfree(packet);
331 }
332
333 port->tty_canrecv = true;
334 spin_unlock_bh(&port->in_lock);
335}
336
337static struct tty_port_operations vtty_port_ops = {
338 .shutdown = vtty_shutdown,
339};
340
341static struct tty_operations vtty_ops = {
342 .install = vtty_install,
343 .open = vtty_open,
344 .close = vtty_close,
345 .write = vtty_write,
346 .write_room = vtty_write_room,
347 .put_char = vtty_put_char,
348 .throttle = vtty_throttle,
349 .unthrottle = vtty_unthrottle
350};
351
352static int vs_serial_queue_incoming_packet(struct vtty_port *port,
353 struct vs_mbuf *mbuf, struct vs_pbuf *pbuf, size_t offset)
354{
355 struct vtty_in_packet *packet;
356
357 lockdep_assert_held(&port->in_lock);
358
359 packet = kzalloc(sizeof(*packet), GFP_ATOMIC);
360 if (!packet) {
361 /*
362 * Uh oh, we are seriously out of memory. The incoming data
363 * will be lost.
364 */
365 return -ENOMEM;
366 }
367
368 dev_dbg(&port->service->dev, "Queuing packet %zu bytes, offset %zu\n",
369 vs_pbuf_size(pbuf), offset);
370 mbuf->priv = packet;
371 memcpy(&packet->pbuf, pbuf, sizeof(*pbuf));
372 packet->offset = offset;
373
374 list_add_tail(&mbuf->queue, &port->pending_in_packets);
375 return 0;
376}
377
378int vs_serial_handle_message(struct vtty_port *port, struct vs_mbuf *mbuf,
379 struct vs_pbuf *pbuf)
380{
381 struct tty_struct *tty = tty_port_tty_get(&port->port);
382 bool queue_packet = false;
383 size_t sent = 0;
384 int err;
385
386 if (!tty) {
387 dev_dbg(&port->service->dev,
388 "tty not open. Dropping %zu chars\n",
389 pbuf->size);
390 port->ops.free_msg_buf(port, mbuf, pbuf);
391 return 0;
392 }
393
394 dev_dbg(&port->service->dev, "Incoming message - len = %zu\n",
395 pbuf->size);
396
397 spin_lock(&port->in_lock);
398 if (!port->tty_canrecv || !list_empty(&port->pending_in_packets)) {
399 /*
400 * We cannot send to the tty right now, either because we are
401 * being throttled or because we still have pending data
402 * to write out to the tty. Queue the buffer up so we can
403 * write it later.
404 */
405 dev_dbg(&port->service->dev,
406 "Cannot send (canrecv = %d, queued = %d) - queuing message\n",
407 port->tty_canrecv,
408 !list_empty(&port->pending_in_packets));
409 queue_packet = true;
410
411 } else {
412 sent = vs_serial_send_pbuf_to_tty(port, pbuf, 0);
413 if (sent < vs_pbuf_size(pbuf)) {
414 /*
415 * Only wrote part of the buffer to the tty. Queue
416 * the buffer to write the rest.
417 */
418 dev_dbg(&port->service->dev,
419 "Sent %zu/%zu bytes to tty - queueing rest\n",
420 sent, vs_pbuf_size(pbuf));
421 queue_packet = true;
422 }
423 }
424
425 if (queue_packet) {
426 /*
427 * Queue the incoming data up. If we are not already throttled,
428 * the tty layer will do so now since it has no room in its
429 * buffers.
430 */
431 err = vs_serial_queue_incoming_packet(port, mbuf, pbuf, sent);
432 if (err) {
433 dev_err(&port->service->dev,
434 "Failed to queue packet - dropping chars\n");
435 port->ops.free_msg_buf(port, mbuf, pbuf);
436 }
437
438 } else {
439 port->ops.free_msg_buf(port, mbuf, pbuf);
440 }
441
442 spin_unlock(&port->in_lock);
443 tty_kref_put(tty);
444
445 return 0;
446}
447EXPORT_SYMBOL_GPL(vs_serial_handle_message);
448
449#ifdef CONFIG_OKL4_VTTY_CONSOLE
450static int vconsole_setup(struct console *co, char *options)
451{
452 if (co->index < 0 || co->index >= max_ttys)
453 co->index = 0;
454
455 pr_info("OKL4 virtual console init\n");
456
457 return 0;
458}
459
460static void vconsole_write(struct console *co, const char *p, unsigned count)
461{
462}
463
464static struct tty_driver *vconsole_device(struct console *co, int *index)
465{
466 *index = co->index;
467
468 return vtty_driver;
469}
470#endif /* CONFIG_OKL4_VTTY_CONSOLE */
471
472static void vs_serial_free_buffers(struct vtty_port *port)
473{
474 struct vtty_in_packet *packet;
475 struct vs_mbuf *mbuf;
476
477 /* Free the list of incoming buffers */
478 spin_lock_bh(&port->in_lock);
479 while (!list_empty(&port->pending_in_packets)) {
480 mbuf = list_first_entry(&port->pending_in_packets,
481 struct vs_mbuf, queue);
482 packet = mbuf->priv;
483
484 list_del(&mbuf->queue);
485 port->ops.free_msg_buf(port, mbuf, &packet->pbuf);
486 kfree(packet);
487 }
488 spin_unlock_bh(&port->in_lock);
489}
490
491/** vservices callbacks **/
492struct vtty_port *vs_serial_alloc_port(struct vs_service_device *service,
493 struct vtty_port_ops *port_ops)
494{
495 struct vtty_port *port;
496 int port_num;
497
498 mutex_lock(&tty_bitmap_lock);
499 port_num = find_first_zero_bit(alloced_ttys, max_ttys);
500
501 if (port_num >= max_ttys) {
502 mutex_unlock(&tty_bitmap_lock);
503 return NULL;
504 }
505
506 port = kzalloc(sizeof(struct vtty_port), GFP_KERNEL);
507 if (!port) {
508 mutex_unlock(&tty_bitmap_lock);
509 return NULL;
510 }
511
512 port->service = service;
513 port->ops = *port_ops;
514 port->tty_canrecv = true;
515 port->port_num = port_num;
516 INIT_LIST_HEAD(&port->pending_in_packets);
517 spin_lock_init(&port->in_lock);
518#ifdef CONFIG_OKL4_VTTY_CONSOLE
519 /* Set up and register the port's console device */
520 strlcpy(port->console.name, "vconvs", sizeof(port->console.name));
521 port->console.write = vconsole_write;
522 port->console.flags = CON_PRINTBUFFER;
523 port->console.device = vconsole_device;
524 port->console.setup = vconsole_setup;
525 port->console.index = port_num;
526
527 register_console(&port->console);
528#endif
529 port->vtty_driver = vtty_driver;
530
531 tty_port_init(&port->port);
532 port->port.ops = &vtty_port_ops;
533
534 tty_register_device(vtty_driver, port_num, &service->dev);
535 bitmap_set(alloced_ttys, port_num, 1);
536 mutex_unlock(&tty_bitmap_lock);
537
538 return port;
539}
540EXPORT_SYMBOL(vs_serial_alloc_port);
541
542void vs_serial_release(struct vtty_port *port)
543{
544 dev_dbg(&port->service->dev, "Release\n");
545
546#ifdef CONFIG_OKL4_VTTY_CONSOLE
547 unregister_console(&port->console);
548#endif
549
550 mutex_lock(&tty_bitmap_lock);
551 bitmap_clear(alloced_ttys, port->port_num, 1);
552 mutex_unlock(&tty_bitmap_lock);
553
554 if (port->port.tty) {
555 tty_vhangup(port->port.tty);
556 tty_kref_put(port->port.tty);
557 }
558
559 vs_serial_free_buffers(port);
560 port->doing_release = true;
561 tty_unregister_device(vtty_driver, port->port_num);
562}
563EXPORT_SYMBOL_GPL(vs_serial_release);
564
565void vs_serial_reset(struct vtty_port *port)
566{
567 /* Free list of in and out mbufs. */
568 vs_serial_free_buffers(port);
569}
570EXPORT_SYMBOL_GPL(vs_serial_reset);
571
572static int __init vs_serial_init(void)
573{
574 int err;
575
576 if (max_ttys == 0)
577 return -EINVAL;
578
579 alloced_ttys = kzalloc(sizeof(unsigned long) * BITS_TO_LONGS(max_ttys),
580 GFP_KERNEL);
581 if (!alloced_ttys) {
582 err = -ENOMEM;
583 goto fail_alloc_ttys;
584 }
585
586 /* Set up the tty driver. */
587 vtty_driver = alloc_tty_driver(max_ttys);
588 if (!vtty_driver) {
589 err = -ENOMEM;
590 goto fail_alloc_tty_driver;
591 }
592
593 vtty_driver->owner = THIS_MODULE;
594 vtty_driver->driver_name = "okl4-vservices-serial";
595 vtty_driver->name = "ttyVS";
596 vtty_driver->type = TTY_DRIVER_TYPE_SERIAL;
597 vtty_driver->subtype = SERIAL_TYPE_NORMAL;
598 vtty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
599 vtty_driver->init_termios = tty_std_termios;
600 vtty_driver->num = max_ttys;
601
602 /* These flags don't really matter; just use sensible defaults. */
603 vtty_driver->init_termios.c_cflag =
604 B9600 | CS8 | CREAD | HUPCL | CLOCAL;
605 vtty_driver->init_termios.c_ispeed = 9600;
606 vtty_driver->init_termios.c_ospeed = 9600;
607
608 tty_set_operations(vtty_driver, &vtty_ops);
609
610 err = tty_register_driver(vtty_driver);
611 if (err)
612 goto fail_tty_driver_register;
613
614 return 0;
615
616fail_tty_driver_register:
617 put_tty_driver(vtty_driver);
618fail_alloc_tty_driver:
619 kfree(alloced_ttys);
620fail_alloc_ttys:
621 return err;
622}
623
624static void __exit vs_serial_exit(void)
625{
626 tty_unregister_driver(vtty_driver);
627 put_tty_driver(vtty_driver);
628}
629
630module_init(vs_serial_init);
631module_exit(vs_serial_exit);
632
633MODULE_DESCRIPTION("OKL4 Virtual Services Serial Core Driver");
634MODULE_AUTHOR("Open Kernel Labs, Inc");