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

Commit 4324282d authored by Johan Hovold's avatar Johan Hovold Committed by Greg Kroah-Hartman
Browse files

greybus: hid: convert to bundle driver



Convert the legacy HID protocol driver to a bundle driver.

This also fixes a potential crash should a (malicious) module have sent
an early request before the private data had been initialised.

Reviewed-by: default avatarViresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: default avatarJohan Hovold <johan@hovoldconsulting.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@google.com>
parent 5dd8cc53
Loading
Loading
Loading
Loading
+51 −19
Original line number Original line Diff line number Diff line
@@ -97,13 +97,13 @@ static int gb_hid_set_report(struct gb_hid *ghid, u8 report_type, u8 report_id,
	return ret;
	return ret;
}
}


static int gb_hid_irq_handler(u8 type, struct gb_operation *op)
static int gb_hid_request_handler(struct gb_operation *op)
{
{
	struct gb_connection *connection = op->connection;
	struct gb_connection *connection = op->connection;
	struct gb_hid *ghid = connection->private;
	struct gb_hid *ghid = connection->private;
	struct gb_hid_input_report_request *request = op->request->payload;
	struct gb_hid_input_report_request *request = op->request->payload;


	if (type != GB_HID_TYPE_IRQ_EVENT) {
	if (op->type != GB_HID_TYPE_IRQ_EVENT) {
		dev_err(&connection->bundle->dev,
		dev_err(&connection->bundle->dev,
			"unsupported unsolicited request\n");
			"unsupported unsolicited request\n");
		return -EINVAL;
		return -EINVAL;
@@ -418,64 +418,96 @@ static int gb_hid_init(struct gb_hid *ghid)
	return 0;
	return 0;
}
}


static int gb_hid_connection_init(struct gb_connection *connection)
static int gb_hid_probe(struct gb_bundle *bundle,
			const struct greybus_bundle_id *id)
{
{
	struct greybus_descriptor_cport *cport_desc;
	struct gb_connection *connection;
	struct hid_device *hid;
	struct hid_device *hid;
	struct gb_hid *ghid;
	struct gb_hid *ghid;
	int ret;
	int ret;


	if (bundle->num_cports != 1)
		return -ENODEV;

	cport_desc = &bundle->cport_desc[0];
	if (cport_desc->protocol_id != GREYBUS_PROTOCOL_HID)
		return -ENODEV;

	ghid = kzalloc(sizeof(*ghid), GFP_KERNEL);
	ghid = kzalloc(sizeof(*ghid), GFP_KERNEL);
	if (!ghid)
	if (!ghid)
		return -ENOMEM;
		return -ENOMEM;


	hid = hid_allocate_device();
	connection = gb_connection_create(bundle, le16_to_cpu(cport_desc->id),
	if (IS_ERR(hid)) {
						gb_hid_request_handler);
		ret = PTR_ERR(hid);
	if (IS_ERR(connection)) {
		ret = PTR_ERR(connection);
		goto err_free_ghid;
		goto err_free_ghid;
	}
	}


	connection->private = ghid;
	connection->private = ghid;
	ghid->connection = connection;
	ghid->connection = connection;

	hid = hid_allocate_device();
	if (IS_ERR(hid)) {
		ret = PTR_ERR(hid);
		goto err_connection_destroy;
	}

	ghid->hid = hid;
	ghid->hid = hid;


	ret = gb_hid_init(ghid);
	greybus_set_drvdata(bundle, ghid);

	ret = gb_connection_enable(connection);
	if (ret)
	if (ret)
		goto err_destroy_hid;
		goto err_destroy_hid;


	ret = gb_hid_init(ghid);
	if (ret)
		goto err_connection_disable;

	ret = hid_add_device(hid);
	ret = hid_add_device(hid);
	if (ret) {
	if (ret) {
		hid_err(hid, "can't add hid device: %d\n", ret);
		hid_err(hid, "can't add hid device: %d\n", ret);
		goto err_destroy_hid;
		goto err_connection_disable;
	}
	}


	return 0;
	return 0;


err_connection_disable:
	gb_connection_disable(connection);
err_destroy_hid:
err_destroy_hid:
	hid_destroy_device(hid);
	hid_destroy_device(hid);
err_connection_destroy:
	gb_connection_destroy(connection);
err_free_ghid:
err_free_ghid:
	kfree(ghid);
	kfree(ghid);


	return ret;
	return ret;
}
}


static void gb_hid_connection_exit(struct gb_connection *connection)
static void gb_hid_disconnect(struct gb_bundle *bundle)
{
{
	struct gb_hid *ghid = connection->private;
	struct gb_hid *ghid = greybus_get_drvdata(bundle);


	gb_connection_disable(ghid->connection);
	hid_destroy_device(ghid->hid);
	hid_destroy_device(ghid->hid);
	gb_connection_destroy(ghid->connection);
	kfree(ghid);
	kfree(ghid);
}
}


static struct gb_protocol hid_protocol = {
static const struct greybus_bundle_id gb_hid_id_table[] = {
	.name			= "hid",
	{ GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_HID) },
	.id			= GREYBUS_PROTOCOL_HID,
	{ }
	.major			= GB_HID_VERSION_MAJOR,
	.minor			= GB_HID_VERSION_MINOR,
	.connection_init	= gb_hid_connection_init,
	.connection_exit	= gb_hid_connection_exit,
	.request_recv		= gb_hid_irq_handler,
};
};
MODULE_DEVICE_TABLE(greybus, gb_hid_id_table);


gb_protocol_driver(&hid_protocol);
static struct greybus_driver gb_hid_driver = {
	.name		= "hid",
	.probe		= gb_hid_probe,
	.disconnect	= gb_hid_disconnect,
	.id_table	= gb_hid_id_table,
};
module_greybus_driver(gb_hid_driver);


MODULE_LICENSE("GPL v2");
MODULE_LICENSE("GPL v2");
+0 −1
Original line number Original line Diff line number Diff line
@@ -236,7 +236,6 @@ static const struct greybus_bundle_id legacy_id_table[] = {
	{ GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_GPIO) },
	{ GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_GPIO) },
	{ GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_I2C) },
	{ GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_I2C) },
	{ GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_UART) },
	{ GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_UART) },
	{ GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_HID) },
	{ GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_USB) },
	{ GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_USB) },
	{ GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_SDIO) },
	{ GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_SDIO) },
	{ GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_POWER_SUPPLY) },
	{ GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_POWER_SUPPLY) },