521 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * HID class driver for the Greybus.4 *5 * Copyright 2014 Google Inc.6 * Copyright 2014 Linaro Ltd.7 */8 9#include <linux/bitops.h>10#include <linux/hid.h>11#include <linux/kernel.h>12#include <linux/module.h>13#include <linux/mutex.h>14#include <linux/slab.h>15#include <linux/greybus.h>16 17/* Greybus HID device's structure */18struct gb_hid {19 struct gb_bundle *bundle;20 struct gb_connection *connection;21 22 struct hid_device *hid;23 struct gb_hid_desc_response hdesc;24 25 unsigned long flags;26#define GB_HID_STARTED 0x0127#define GB_HID_READ_PENDING 0x0428 29 unsigned int bufsize;30 char *inbuf;31};32 33/* Routines to get controller's information over greybus */34 35/* Operations performed on greybus */36static int gb_hid_get_desc(struct gb_hid *ghid)37{38 return gb_operation_sync(ghid->connection, GB_HID_TYPE_GET_DESC, NULL,39 0, &ghid->hdesc, sizeof(ghid->hdesc));40}41 42static int gb_hid_get_report_desc(struct gb_hid *ghid, char *rdesc)43{44 int ret;45 46 ret = gb_pm_runtime_get_sync(ghid->bundle);47 if (ret)48 return ret;49 50 ret = gb_operation_sync(ghid->connection, GB_HID_TYPE_GET_REPORT_DESC,51 NULL, 0, rdesc,52 le16_to_cpu(ghid->hdesc.wReportDescLength));53 54 gb_pm_runtime_put_autosuspend(ghid->bundle);55 56 return ret;57}58 59static int gb_hid_set_power(struct gb_hid *ghid, int type)60{61 int ret;62 63 ret = gb_pm_runtime_get_sync(ghid->bundle);64 if (ret)65 return ret;66 67 ret = gb_operation_sync(ghid->connection, type, NULL, 0, NULL, 0);68 69 gb_pm_runtime_put_autosuspend(ghid->bundle);70 71 return ret;72}73 74static int gb_hid_get_report(struct gb_hid *ghid, u8 report_type, u8 report_id,75 unsigned char *buf, int len)76{77 struct gb_hid_get_report_request request;78 int ret;79 80 ret = gb_pm_runtime_get_sync(ghid->bundle);81 if (ret)82 return ret;83 84 request.report_type = report_type;85 request.report_id = report_id;86 87 ret = gb_operation_sync(ghid->connection, GB_HID_TYPE_GET_REPORT,88 &request, sizeof(request), buf, len);89 90 gb_pm_runtime_put_autosuspend(ghid->bundle);91 92 return ret;93}94 95static int gb_hid_set_report(struct gb_hid *ghid, u8 report_type, u8 report_id,96 unsigned char *buf, int len)97{98 struct gb_hid_set_report_request *request;99 struct gb_operation *operation;100 int ret, size = sizeof(*request) + len - 1;101 102 ret = gb_pm_runtime_get_sync(ghid->bundle);103 if (ret)104 return ret;105 106 operation = gb_operation_create(ghid->connection,107 GB_HID_TYPE_SET_REPORT, size, 0,108 GFP_KERNEL);109 if (!operation) {110 gb_pm_runtime_put_autosuspend(ghid->bundle);111 return -ENOMEM;112 }113 114 request = operation->request->payload;115 request->report_type = report_type;116 request->report_id = report_id;117 memcpy(request->report, buf, len);118 119 ret = gb_operation_request_send_sync(operation);120 if (ret) {121 dev_err(&operation->connection->bundle->dev,122 "failed to set report: %d\n", ret);123 } else {124 ret = len;125 }126 127 gb_operation_put(operation);128 gb_pm_runtime_put_autosuspend(ghid->bundle);129 130 return ret;131}132 133static int gb_hid_request_handler(struct gb_operation *op)134{135 struct gb_connection *connection = op->connection;136 struct gb_hid *ghid = gb_connection_get_data(connection);137 struct gb_hid_input_report_request *request = op->request->payload;138 139 if (op->type != GB_HID_TYPE_IRQ_EVENT) {140 dev_err(&connection->bundle->dev,141 "unsupported unsolicited request\n");142 return -EINVAL;143 }144 145 if (test_bit(GB_HID_STARTED, &ghid->flags))146 hid_input_report(ghid->hid, HID_INPUT_REPORT,147 request->report, op->request->payload_size, 1);148 149 return 0;150}151 152static int gb_hid_report_len(struct hid_report *report)153{154 return ((report->size - 1) >> 3) + 1 +155 report->device->report_enum[report->type].numbered;156}157 158static void gb_hid_find_max_report(struct hid_device *hid, unsigned int type,159 unsigned int *max)160{161 struct hid_report *report;162 unsigned int size;163 164 list_for_each_entry(report, &hid->report_enum[type].report_list, list) {165 size = gb_hid_report_len(report);166 if (*max < size)167 *max = size;168 }169}170 171static void gb_hid_free_buffers(struct gb_hid *ghid)172{173 kfree(ghid->inbuf);174 ghid->inbuf = NULL;175 ghid->bufsize = 0;176}177 178static int gb_hid_alloc_buffers(struct gb_hid *ghid, size_t bufsize)179{180 ghid->inbuf = kzalloc(bufsize, GFP_KERNEL);181 if (!ghid->inbuf)182 return -ENOMEM;183 184 ghid->bufsize = bufsize;185 186 return 0;187}188 189/* Routines dealing with reports */190static void gb_hid_init_report(struct gb_hid *ghid, struct hid_report *report)191{192 unsigned int size;193 194 size = gb_hid_report_len(report);195 if (gb_hid_get_report(ghid, report->type, report->id, ghid->inbuf,196 size))197 return;198 199 /*200 * hid->driver_lock is held as we are in probe function,201 * we just need to setup the input fields, so using202 * hid_report_raw_event is safe.203 */204 hid_report_raw_event(ghid->hid, report->type, ghid->inbuf, size, 1);205}206 207static void gb_hid_init_reports(struct gb_hid *ghid)208{209 struct hid_device *hid = ghid->hid;210 struct hid_report *report;211 212 list_for_each_entry(report,213 &hid->report_enum[HID_INPUT_REPORT].report_list,214 list)215 gb_hid_init_report(ghid, report);216 217 list_for_each_entry(report,218 &hid->report_enum[HID_FEATURE_REPORT].report_list,219 list)220 gb_hid_init_report(ghid, report);221}222 223static int __gb_hid_get_raw_report(struct hid_device *hid,224 unsigned char report_number, __u8 *buf, size_t count,225 unsigned char report_type)226{227 struct gb_hid *ghid = hid->driver_data;228 int ret;229 230 if (report_type == HID_OUTPUT_REPORT)231 return -EINVAL;232 233 ret = gb_hid_get_report(ghid, report_type, report_number, buf, count);234 if (!ret)235 ret = count;236 237 return ret;238}239 240static int __gb_hid_output_raw_report(struct hid_device *hid, __u8 *buf,241 size_t len, unsigned char report_type)242{243 struct gb_hid *ghid = hid->driver_data;244 int report_id = buf[0];245 int ret;246 247 if (report_type == HID_INPUT_REPORT)248 return -EINVAL;249 250 if (report_id) {251 buf++;252 len--;253 }254 255 ret = gb_hid_set_report(ghid, report_type, report_id, buf, len);256 if (report_id && ret >= 0)257 ret++; /* add report_id to the number of transferred bytes */258 259 return 0;260}261 262static int gb_hid_raw_request(struct hid_device *hid, unsigned char reportnum,263 __u8 *buf, size_t len, unsigned char rtype,264 int reqtype)265{266 switch (reqtype) {267 case HID_REQ_GET_REPORT:268 return __gb_hid_get_raw_report(hid, reportnum, buf, len, rtype);269 case HID_REQ_SET_REPORT:270 if (buf[0] != reportnum)271 return -EINVAL;272 return __gb_hid_output_raw_report(hid, buf, len, rtype);273 default:274 return -EIO;275 }276}277 278/* HID Callbacks */279static int gb_hid_parse(struct hid_device *hid)280{281 struct gb_hid *ghid = hid->driver_data;282 unsigned int rsize;283 char *rdesc;284 int ret;285 286 rsize = le16_to_cpu(ghid->hdesc.wReportDescLength);287 if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) {288 dbg_hid("weird size of report descriptor (%u)\n", rsize);289 return -EINVAL;290 }291 292 rdesc = kzalloc(rsize, GFP_KERNEL);293 if (!rdesc)294 return -ENOMEM;295 296 ret = gb_hid_get_report_desc(ghid, rdesc);297 if (ret) {298 hid_err(hid, "reading report descriptor failed\n");299 goto free_rdesc;300 }301 302 ret = hid_parse_report(hid, rdesc, rsize);303 if (ret)304 dbg_hid("parsing report descriptor failed\n");305 306free_rdesc:307 kfree(rdesc);308 309 return ret;310}311 312static int gb_hid_start(struct hid_device *hid)313{314 struct gb_hid *ghid = hid->driver_data;315 unsigned int bufsize = HID_MIN_BUFFER_SIZE;316 int ret;317 318 gb_hid_find_max_report(hid, HID_INPUT_REPORT, &bufsize);319 gb_hid_find_max_report(hid, HID_OUTPUT_REPORT, &bufsize);320 gb_hid_find_max_report(hid, HID_FEATURE_REPORT, &bufsize);321 322 if (bufsize > HID_MAX_BUFFER_SIZE)323 bufsize = HID_MAX_BUFFER_SIZE;324 325 ret = gb_hid_alloc_buffers(ghid, bufsize);326 if (ret)327 return ret;328 329 if (!(hid->quirks & HID_QUIRK_NO_INIT_REPORTS))330 gb_hid_init_reports(ghid);331 332 return 0;333}334 335static void gb_hid_stop(struct hid_device *hid)336{337 struct gb_hid *ghid = hid->driver_data;338 339 gb_hid_free_buffers(ghid);340}341 342static int gb_hid_open(struct hid_device *hid)343{344 struct gb_hid *ghid = hid->driver_data;345 int ret;346 347 ret = gb_hid_set_power(ghid, GB_HID_TYPE_PWR_ON);348 if (ret < 0)349 return ret;350 351 set_bit(GB_HID_STARTED, &ghid->flags);352 return 0;353}354 355static void gb_hid_close(struct hid_device *hid)356{357 struct gb_hid *ghid = hid->driver_data;358 int ret;359 360 clear_bit(GB_HID_STARTED, &ghid->flags);361 362 /* Save some power */363 ret = gb_hid_set_power(ghid, GB_HID_TYPE_PWR_OFF);364 if (ret)365 dev_err(&ghid->connection->bundle->dev,366 "failed to power off (%d)\n", ret);367}368 369static int gb_hid_power(struct hid_device *hid, int lvl)370{371 struct gb_hid *ghid = hid->driver_data;372 373 switch (lvl) {374 case PM_HINT_FULLON:375 return gb_hid_set_power(ghid, GB_HID_TYPE_PWR_ON);376 case PM_HINT_NORMAL:377 return gb_hid_set_power(ghid, GB_HID_TYPE_PWR_OFF);378 }379 380 return 0;381}382 383/* HID structure to pass callbacks */384static const struct hid_ll_driver gb_hid_ll_driver = {385 .parse = gb_hid_parse,386 .start = gb_hid_start,387 .stop = gb_hid_stop,388 .open = gb_hid_open,389 .close = gb_hid_close,390 .power = gb_hid_power,391 .raw_request = gb_hid_raw_request,392};393 394static int gb_hid_init(struct gb_hid *ghid)395{396 struct hid_device *hid = ghid->hid;397 int ret;398 399 ret = gb_hid_get_desc(ghid);400 if (ret)401 return ret;402 403 hid->version = le16_to_cpu(ghid->hdesc.bcdHID);404 hid->vendor = le16_to_cpu(ghid->hdesc.wVendorID);405 hid->product = le16_to_cpu(ghid->hdesc.wProductID);406 hid->country = ghid->hdesc.bCountryCode;407 408 hid->driver_data = ghid;409 hid->ll_driver = &gb_hid_ll_driver;410 hid->dev.parent = &ghid->connection->bundle->dev;411// hid->bus = BUS_GREYBUS; /* Need a bustype for GREYBUS in <linux/input.h> */412 413 /* Set HID device's name */414 snprintf(hid->name, sizeof(hid->name), "%s %04X:%04X",415 dev_name(&ghid->connection->bundle->dev),416 hid->vendor, hid->product);417 418 return 0;419}420 421static int gb_hid_probe(struct gb_bundle *bundle,422 const struct greybus_bundle_id *id)423{424 struct greybus_descriptor_cport *cport_desc;425 struct gb_connection *connection;426 struct hid_device *hid;427 struct gb_hid *ghid;428 int ret;429 430 if (bundle->num_cports != 1)431 return -ENODEV;432 433 cport_desc = &bundle->cport_desc[0];434 if (cport_desc->protocol_id != GREYBUS_PROTOCOL_HID)435 return -ENODEV;436 437 ghid = kzalloc(sizeof(*ghid), GFP_KERNEL);438 if (!ghid)439 return -ENOMEM;440 441 connection = gb_connection_create(bundle, le16_to_cpu(cport_desc->id),442 gb_hid_request_handler);443 if (IS_ERR(connection)) {444 ret = PTR_ERR(connection);445 goto err_free_ghid;446 }447 448 gb_connection_set_data(connection, ghid);449 ghid->connection = connection;450 451 hid = hid_allocate_device();452 if (IS_ERR(hid)) {453 ret = PTR_ERR(hid);454 goto err_connection_destroy;455 }456 457 ghid->hid = hid;458 ghid->bundle = bundle;459 460 greybus_set_drvdata(bundle, ghid);461 462 ret = gb_connection_enable(connection);463 if (ret)464 goto err_destroy_hid;465 466 ret = gb_hid_init(ghid);467 if (ret)468 goto err_connection_disable;469 470 ret = hid_add_device(hid);471 if (ret) {472 hid_err(hid, "can't add hid device: %d\n", ret);473 goto err_connection_disable;474 }475 476 gb_pm_runtime_put_autosuspend(bundle);477 478 return 0;479 480err_connection_disable:481 gb_connection_disable(connection);482err_destroy_hid:483 hid_destroy_device(hid);484err_connection_destroy:485 gb_connection_destroy(connection);486err_free_ghid:487 kfree(ghid);488 489 return ret;490}491 492static void gb_hid_disconnect(struct gb_bundle *bundle)493{494 struct gb_hid *ghid = greybus_get_drvdata(bundle);495 496 if (gb_pm_runtime_get_sync(bundle))497 gb_pm_runtime_get_noresume(bundle);498 499 hid_destroy_device(ghid->hid);500 gb_connection_disable(ghid->connection);501 gb_connection_destroy(ghid->connection);502 kfree(ghid);503}504 505static const struct greybus_bundle_id gb_hid_id_table[] = {506 { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_HID) },507 { }508};509MODULE_DEVICE_TABLE(greybus, gb_hid_id_table);510 511static struct greybus_driver gb_hid_driver = {512 .name = "hid",513 .probe = gb_hid_probe,514 .disconnect = gb_hid_disconnect,515 .id_table = gb_hid_id_table,516};517module_greybus_driver(gb_hid_driver);518 519MODULE_DESCRIPTION("HID class driver for the Greybus");520MODULE_LICENSE("GPL v2");521