Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Greybus driver for the log protocol
  4 *
  5 * Copyright 2016 Google Inc.
  6 */
  7#include <linux/kernel.h>
  8#include <linux/module.h>
  9#include <linux/slab.h>
 10#include <linux/sizes.h>
 11#include <linux/uaccess.h>
 12
 13#include "greybus.h"
 14
 15struct gb_log {
 16	struct gb_connection *connection;
 17};
 18
 19static int gb_log_request_handler(struct gb_operation *op)
 20{
 21	struct gb_connection *connection = op->connection;
 22	struct device *dev = &connection->bundle->dev;
 23	struct gb_log_send_log_request *receive;
 24	u16 len;
 25
 26	if (op->type != GB_LOG_TYPE_SEND_LOG) {
 27		dev_err(dev, "unknown request type 0x%02x\n", op->type);
 28		return -EINVAL;
 29	}
 30
 31	/* Verify size of payload */
 32	if (op->request->payload_size < sizeof(*receive)) {
 33		dev_err(dev, "log request too small (%zu < %zu)\n",
 34				op->request->payload_size, sizeof(*receive));
 35		return -EINVAL;
 36	}
 37	receive = op->request->payload;
 38	len = le16_to_cpu(receive->len);
 39	if (len != (op->request->payload_size - sizeof(*receive))) {
 40		dev_err(dev, "log request wrong size %d vs %zu\n", len,
 41				(op->request->payload_size - sizeof(*receive)));
 42		return -EINVAL;
 43	}
 44	if (len == 0) {
 45		dev_err(dev, "log request of 0 bytes?\n");
 46		return -EINVAL;
 47	}
 48
 49	if (len > GB_LOG_MAX_LEN) {
 50		dev_err(dev, "log request too big: %d\n", len);
 51		return -EINVAL;
 52	}
 53
 54	/* Ensure the buffer is 0 terminated */
 55	receive->msg[len - 1] = '\0';
 56
 57	/*
 58	 * Print with dev_dbg() so that it can be easily turned off using
 59	 * dynamic debugging (and prevent any DoS)
 60	 */
 61	dev_dbg(dev, "%s", receive->msg);
 62
 63	return 0;
 64}
 65
 66static int gb_log_probe(struct gb_bundle *bundle,
 67			const struct greybus_bundle_id *id)
 68{
 69	struct greybus_descriptor_cport *cport_desc;
 70	struct gb_connection *connection;
 71	struct gb_log *log;
 72	int retval;
 73
 74	if (bundle->num_cports != 1)
 75		return -ENODEV;
 76
 77	cport_desc = &bundle->cport_desc[0];
 78	if (cport_desc->protocol_id != GREYBUS_PROTOCOL_LOG)
 79		return -ENODEV;
 80
 81	log = kzalloc(sizeof(*log), GFP_KERNEL);
 82	if (!log)
 83		return -ENOMEM;
 84
 85	connection = gb_connection_create(bundle, le16_to_cpu(cport_desc->id),
 86			gb_log_request_handler);
 87	if (IS_ERR(connection)) {
 88		retval = PTR_ERR(connection);
 89		goto error_free;
 90	}
 91
 92	log->connection = connection;
 93	greybus_set_drvdata(bundle, log);
 94
 95	retval = gb_connection_enable(connection);
 96	if (retval)
 97		goto error_connection_destroy;
 98
 99	return 0;
100
101error_connection_destroy:
102	gb_connection_destroy(connection);
103error_free:
104	kfree(log);
105	return retval;
106}
107
108static void gb_log_disconnect(struct gb_bundle *bundle)
109{
110	struct gb_log *log = greybus_get_drvdata(bundle);
111	struct gb_connection *connection = log->connection;
112
113	gb_connection_disable(connection);
114	gb_connection_destroy(connection);
115
116	kfree(log);
117}
118
119static const struct greybus_bundle_id gb_log_id_table[] = {
120	{ GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_LOG) },
121	{ }
122};
123MODULE_DEVICE_TABLE(greybus, gb_log_id_table);
124
125static struct greybus_driver gb_log_driver = {
126	.name           = "log",
127	.probe          = gb_log_probe,
128	.disconnect     = gb_log_disconnect,
129	.id_table       = gb_log_id_table,
130};
131module_greybus_driver(gb_log_driver);
132
133MODULE_LICENSE("GPL v2");