Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 438aa183 authored by Carl van Schaik's avatar Carl van Schaik Committed by Gerrit - the friendly Code Review server
Browse files

vservices: serial: Add the serial protocol and drivers



Adds the virtual services serial protocol and tty drivers
for virtual serial and console

Change-Id: I2dd86a677406d6b74b0e02e5fda720eaf9edcd62
Signed-off-by: default avatarCarl van Schaik <carl@cog.systems>
Git-commit: 29f5766e09adb6064b01bf20e76c117bcfa94e41
Git-repo: https://github.com/CogSystems/linux-msm.git


Signed-off-by: default avatarMinming Qi <mqi@codeaurora.org>
parent 2d2d3ac9
Loading
Loading
Loading
Loading
+38 −0
Original line number Diff line number Diff line
@@ -631,3 +631,41 @@ config OKL4_PIPE
        Virtual pipe driver for the OKL4 Microvisor. This driver allows
        OKL4 Microvisor pipes to be exposed directly to user level as
        character devices.

config VSERVICES_SERIAL
	tristate

config VSERVICES_SERIAL_SERVER
	tristate "Virtual Services serial server"
	depends on VSERVICES_SUPPORT && VSERVICES_SERVER
	select VSERVICES_SERIAL
	select VSERVICES_PROTOCOL_SERIAL_SERVER
	default y
	help
	  Select this option if you want support for server side Virtual
	  Services serial. A virtual serial service behaves similarly to
	  a UNIX pseudo terminal (pty), and does not require any physical
	  serial hardware. Virtual serial devices are typically called
	  /dev/ttyVS0, /dev/ttyVS1, etc.

config VSERVICES_SERIAL_CLIENT
	tristate "Virtual Services serial client"
	depends on VSERVICES_SUPPORT && VSERVICES_CLIENT
	select VSERVICES_SERIAL
	select VSERVICES_PROTOCOL_SERIAL_CLIENT
	default y
	help
	  Select this option if you want support for client side Virtual
	  Services serial. A virtual serial service behaves similarly to
	  a UNIX pseudo terminal (pty), and does not require any physical
	  serial hardware. Virtual serial devices are typically called
	  /dev/ttyVS0, /dev/ttyVS1, etc.

config VSERVICES_VTTY_COUNT
	int "Maximum number of Virtual Services serial devices"
	depends on VSERVICES_SERIAL
	range 0 256
	default "8"
	help
	  The maximum number of Virtual Services serial devices to support.
	  This limit applies to both the client and server.
+6 −0
Original line number Diff line number Diff line
@@ -69,3 +69,9 @@ endif
obj-$(CONFIG_MSM_RDBG)		+= rdbg.o
obj-$(CONFIG_OKL4_PIPE)		+= okl4_pipe.o
CFLAGS_okl4_pipe.o			+= -Werror
obj-$(CONFIG_VSERVICES_SERIAL)		+= vservices_serial.o
CFLAGS_vservices_serial.o	+= -Werror
obj-$(CONFIG_VSERVICES_SERIAL_CLIENT)	+= vs_serial_client.o
CFLAGS_vs_serial_client.o	 += -Werror
obj-$(CONFIG_VSERVICES_SERIAL_SERVER)	+= vs_serial_server.o
CFLAGS_vs_serial_server.o	+= -Werror
+132 −0
Original line number Diff line number Diff line
/*
 * drivers/char/vs_serial_client.c
 *
 * Copyright (c) 2012-2018 General Dynamics
 * Copyright (c) 2014 Open Kernel Labs, Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * Serial vService client driver
 *
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>

#include <vservices/transport.h>
#include <vservices/types.h>
#include <vservices/buffer.h>
#include <vservices/service.h>

#include <vservices/protocol/serial/common.h>
#include <vservices/protocol/serial/types.h>
#include <vservices/protocol/serial/client.h>

#include "vs_serial_common.h"

#define client_state_to_port(state) \
	container_of(state, struct vtty_port, u.vs_client)

static struct vs_mbuf *vs_serial_client_alloc_msg_buf(struct vtty_port *port,
		struct vs_pbuf *pbuf, gfp_t gfp_flags)
{
	return vs_client_serial_serial_alloc_msg(&port->u.vs_client, pbuf,
			gfp_flags);
}

static void vs_serial_client_free_msg_buf(struct vtty_port *port,
		struct vs_mbuf *mbuf, struct vs_pbuf *pbuf)
{
	vs_client_serial_serial_free_msg(&port->u.vs_client, pbuf, mbuf);
}

static int vs_serial_client_send_msg_buf(struct vtty_port *port,
		struct vs_mbuf *mbuf, struct vs_pbuf *pbuf)
{
	return vs_client_serial_serial_send_msg(&port->u.vs_client, *pbuf,
			mbuf);
}

static bool vs_serial_client_is_vservices_running(struct vtty_port *port)
{
	return VSERVICE_BASE_STATE_IS_RUNNING(port->u.vs_client.state.base);
}

static struct vtty_port_ops client_port_ops = {
	.alloc_msg_buf	= vs_serial_client_alloc_msg_buf,
	.free_msg_buf	= vs_serial_client_free_msg_buf,
	.send_msg_buf	= vs_serial_client_send_msg_buf,
	.is_running	= vs_serial_client_is_vservices_running,
};

static struct vs_client_serial_state *
vs_serial_client_alloc(struct vs_service_device *service)
{
	struct vtty_port *port;

	port = vs_serial_alloc_port(service, &client_port_ops);
	if (!port)
		return NULL;

	dev_set_drvdata(&service->dev, port);
	return &port->u.vs_client;
}

static void vs_serial_client_release(struct vs_client_serial_state *_state)
{
	vs_serial_release(client_state_to_port(_state));
}

static void vs_serial_client_closed(struct vs_client_serial_state *_state)
{
	vs_serial_reset(client_state_to_port(_state));
}

static void vs_serial_client_opened(struct vs_client_serial_state *_state)
{
	struct vtty_port *port = client_state_to_port(_state);

	dev_dbg(&port->service->dev, "ack_open\n");
	port->max_transfer_size = _state->packet_size;
}

static int
vs_serial_client_handle_message(struct vs_client_serial_state *_state,
		struct vs_pbuf data, struct vs_mbuf *mbuf)
{
	return vs_serial_handle_message(client_state_to_port(_state), mbuf,
			&data);
}

static struct vs_client_serial vs_client_serial_driver = {
	.rx_atomic		= true,
	.alloc			= vs_serial_client_alloc,
	.release		= vs_serial_client_release,
	.closed			= vs_serial_client_closed,
	.opened			= vs_serial_client_opened,
	.serial = {
		.msg_msg	= vs_serial_client_handle_message,
	},
};

static int __init vs_serial_client_init(void)
{
	return vservice_serial_client_register(&vs_client_serial_driver,
			"vserial");
}

static void __exit vs_serial_client_exit(void)
{
	vservice_serial_client_unregister(&vs_client_serial_driver);
}

module_init(vs_serial_client_init);
module_exit(vs_serial_client_exit);

MODULE_DESCRIPTION("OKL4 Virtual Services Serial Client Driver");
MODULE_AUTHOR("Open Kernel Labs, Inc");
+91 −0
Original line number Diff line number Diff line
/*
 * drivers/char/vs_serial_common.h
 *
 * Copyright (c) 2012-2018 General Dynamics
 * Copyright (c) 2014 Open Kernel Labs, Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 */

#ifndef _VS_SERIAL_COMMON_H
#define _VS_SERIAL_COMMON_H

#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/mutex.h>
#include <linux/completion.h>
#include <linux/console.h>

#include <vservices/protocol/serial/common.h>
#include <vservices/protocol/serial/types.h>
#include <vservices/protocol/serial/server.h>
#include <vservices/protocol/serial/client.h>

#define OUTBUFFER_SIZE 1024
#define vtty_list_last_entry(ptr, type, member) \
	list_entry((ptr)->prev, type, member)

struct vtty_port;
struct vs_service_device;

struct vtty_port_ops {
	struct vs_mbuf	*(*alloc_msg_buf)(struct vtty_port *port,
			struct vs_pbuf *pbuf, gfp_t gfp_flags);
	void		(*free_msg_buf)(struct vtty_port *port,
			struct vs_mbuf *mbuf, struct vs_pbuf *pbuf);
	int		(*send_msg_buf)(struct vtty_port *port,
			struct vs_mbuf *mbuf, struct vs_pbuf *pbuf);
	bool		(*is_running)(struct vtty_port *port);
};

struct vtty_port {
	union {
		struct vs_client_serial_state vs_client;
		struct vs_server_serial_state vs_server;
	} u;

	struct vs_service_device	*service;
	int				port_num;

	struct tty_driver		*vtty_driver;

	struct vtty_port_ops		ops;

	/* output data */
	bool				doing_release;

	int				max_transfer_size;

	/* Tracks if tty layer can receive data from driver */
	bool				tty_canrecv;

	/*
	 * List of pending incoming buffers from the vServices stack. If we
	 * receive a buffer, but cannot write it to the tty layer then we
	 * queue it on this list to handle later. in_lock protects access to
	 * the pending_in_packets list and the tty_canrecv field.
	 */
	struct list_head		pending_in_packets;
	spinlock_t			in_lock;

#ifdef CONFIG_OKL4_VTTY_CONSOLE
	struct console			console;
#endif

	struct tty_port			port;
};

extern struct vtty_port *
vs_serial_alloc_port(struct vs_service_device *service,
	struct vtty_port_ops *port_ops);
extern void vs_serial_release(struct vtty_port *port);
extern void vs_serial_reset(struct vtty_port *port);
extern int vs_serial_handle_message(struct vtty_port *port,
		struct vs_mbuf *mbuf, struct vs_pbuf *pbuf);

#endif /* _VS_SERIAL_COMMON_H */
+152 −0
Original line number Diff line number Diff line
/*
 * drivers/char/vs_serial_server.c
 *
 * Copyright (c) 2012-2018 General Dynamics
 * Copyright (c) 2014 Open Kernel Labs, Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * Serial vService server driver
 *
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>

#include <vservices/transport.h>
#include <vservices/types.h>
#include <vservices/buffer.h>
#include <vservices/service.h>

#include <vservices/protocol/serial/common.h>
#include <vservices/protocol/serial/types.h>
#include <vservices/protocol/serial/server.h>

#include "vs_serial_common.h"

#define server_state_to_port(state) \
	container_of(state, struct vtty_port, u.vs_server)

static struct vs_mbuf *vs_serial_server_alloc_msg_buf(struct vtty_port *port,
		struct vs_pbuf *pbuf, gfp_t gfp_flags)
{
	return vs_server_serial_serial_alloc_msg(&port->u.vs_server, pbuf,
			gfp_flags);
}

static void vs_serial_server_free_msg_buf(struct vtty_port *port,
		struct vs_mbuf *mbuf, struct vs_pbuf *pbuf)
{
	vs_server_serial_serial_free_msg(&port->u.vs_server, pbuf, mbuf);
}

static int vs_serial_server_send_msg_buf(struct vtty_port *port,
		struct vs_mbuf *mbuf, struct vs_pbuf *pbuf)
{
	return vs_server_serial_serial_send_msg(&port->u.vs_server, *pbuf, mbuf);
}

static bool vs_serial_server_is_vservices_running(struct vtty_port *port)
{
	return VSERVICE_BASE_STATE_IS_RUNNING(port->u.vs_server.state.base);
}

static struct vtty_port_ops server_port_ops = {
	.alloc_msg_buf	= vs_serial_server_alloc_msg_buf,
	.free_msg_buf	= vs_serial_server_free_msg_buf,
	.send_msg_buf	= vs_serial_server_send_msg_buf,
	.is_running	= vs_serial_server_is_vservices_running,
};

static struct vs_server_serial_state *
vs_serial_server_alloc(struct vs_service_device *service)
{
	struct vtty_port *port;

	port = vs_serial_alloc_port(service, &server_port_ops);
	if (!port)
		return NULL;

	dev_set_drvdata(&service->dev, port);
	return &port->u.vs_server;
}

static void vs_serial_server_release(struct vs_server_serial_state *_state)
{
	vs_serial_release(server_state_to_port(_state));
}

static void vs_serial_server_closed(struct vs_server_serial_state *_state)
{
	vs_serial_reset(server_state_to_port(_state));
}

static int
vs_serial_server_handle_message(struct vs_server_serial_state *_state,
		struct vs_pbuf data, struct vs_mbuf *mbuf)
{
	return vs_serial_handle_message(server_state_to_port(_state), mbuf,
			&data);
}

static vs_server_response_type_t
vs_serial_server_req_open(struct vs_server_serial_state *_state)
{
	struct vtty_port *port = server_state_to_port(_state);

	dev_dbg(&port->service->dev, "req_open\n");

	/* FIXME: Jira ticket SDK-3521 - ryanm. */
	port->max_transfer_size = vs_service_max_mbuf_size(port->service) - 8;
	_state->packet_size = port->max_transfer_size;

	return VS_SERVER_RESP_SUCCESS;
}

static vs_server_response_type_t
vs_serial_server_req_close(struct vs_server_serial_state *_state)
{
	struct vtty_port *port = server_state_to_port(_state);

	dev_dbg(&port->service->dev, "req_close\n");

	return VS_SERVER_RESP_SUCCESS;
}

static struct vs_server_serial vs_server_serial_driver = {
	.rx_atomic		= true,
	.alloc			= vs_serial_server_alloc,
	.release		= vs_serial_server_release,
	.closed			= vs_serial_server_closed,
	.open			= vs_serial_server_req_open,
	.close			= vs_serial_server_req_close,
	.serial = {
		.msg_msg	= vs_serial_server_handle_message,
	},

	/* Large default quota for batching data messages */
	.in_quota_best		= 16,
	.out_quota_best		= 16,
};

static int __init vs_serial_server_init(void)
{
	return vservice_serial_server_register(&vs_server_serial_driver,
			"vserial");
}

static void __exit vs_serial_server_exit(void)
{
	vservice_serial_server_unregister(&vs_server_serial_driver);
}

module_init(vs_serial_server_init);
module_exit(vs_serial_server_exit);

MODULE_DESCRIPTION("OKL4 Virtual Services Serial Server Driver");
MODULE_AUTHOR("Open Kernel Labs, Inc");
Loading