linux/drivers/hid/amd-sfh-hid/amd_sfh_hid.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * AMD MP2 Sensors transport driver
   4 *
   5 * Authors: Nehal Bakulchandra Shah <Nehal-bakulchandra.shah@amd.com>
   6 *          Sandeep Singh <sandeep.singh@amd.com>
   7 */
   8#include <linux/hid.h>
   9#include <linux/wait.h>
  10#include <linux/sched.h>
  11
  12#include "amd_sfh_hid.h"
  13
  14#define AMD_SFH_RESPONSE_TIMEOUT        1500
  15
  16/**
  17 * amdtp_hid_parse() - hid-core .parse() callback
  18 * @hid:        hid device instance
  19 *
  20 * This function gets called during call to hid_add_device
  21 *
  22 * Return: 0 on success and non zero on error
  23 */
  24static int amdtp_hid_parse(struct hid_device *hid)
  25{
  26        struct amdtp_hid_data *hid_data = hid->driver_data;
  27        struct amdtp_cl_data *cli_data = hid_data->cli_data;
  28
  29        return hid_parse_report(hid, cli_data->report_descr[hid_data->index],
  30                              cli_data->report_descr_sz[hid_data->index]);
  31}
  32
  33/* Empty callbacks with success return code */
  34static int amdtp_hid_start(struct hid_device *hid)
  35{
  36        return 0;
  37}
  38
  39static void amdtp_hid_stop(struct hid_device *hid)
  40{
  41}
  42
  43static int amdtp_hid_open(struct hid_device *hid)
  44{
  45        return 0;
  46}
  47
  48static void amdtp_hid_close(struct hid_device *hid)
  49{
  50}
  51
  52static int amdtp_raw_request(struct hid_device *hdev, u8 reportnum,
  53                             u8 *buf, size_t len, u8 rtype, int reqtype)
  54{
  55        return 0;
  56}
  57
  58static void amdtp_hid_request(struct hid_device *hid, struct hid_report *rep, int reqtype)
  59{
  60        int rc;
  61
  62        switch (reqtype) {
  63        case HID_REQ_GET_REPORT:
  64                rc = amd_sfh_get_report(hid, rep->id, rep->type);
  65                if (rc)
  66                        dev_err(&hid->dev, "AMDSFH  get report error\n");
  67                break;
  68        case HID_REQ_SET_REPORT:
  69                amd_sfh_set_report(hid, rep->id, reqtype);
  70                break;
  71        default:
  72                break;
  73        }
  74}
  75
  76static int amdtp_wait_for_response(struct hid_device *hid)
  77{
  78        struct amdtp_hid_data *hid_data =  hid->driver_data;
  79        struct amdtp_cl_data *cli_data = hid_data->cli_data;
  80        int i, ret = 0;
  81
  82        for (i = 0; i < cli_data->num_hid_devices; i++) {
  83                if (cli_data->hid_sensor_hubs[i] == hid)
  84                        break;
  85        }
  86
  87        if (!cli_data->request_done[i])
  88                ret = wait_event_interruptible_timeout(hid_data->hid_wait,
  89                                                       cli_data->request_done[i],
  90                                                       msecs_to_jiffies(AMD_SFH_RESPONSE_TIMEOUT));
  91        if (ret == -ERESTARTSYS)
  92                return -ERESTARTSYS;
  93        else if (ret < 0)
  94                return -ETIMEDOUT;
  95        else
  96                return 0;
  97}
  98
  99void amdtp_hid_wakeup(struct hid_device *hid)
 100{
 101        struct amdtp_hid_data *hid_data = hid->driver_data;
 102        struct amdtp_cl_data *cli_data = hid_data->cli_data;
 103
 104        cli_data->request_done[cli_data->cur_hid_dev] = true;
 105        wake_up_interruptible(&hid_data->hid_wait);
 106}
 107
 108static struct hid_ll_driver amdtp_hid_ll_driver = {
 109        .parse  =       amdtp_hid_parse,
 110        .start  =       amdtp_hid_start,
 111        .stop   =       amdtp_hid_stop,
 112        .open   =       amdtp_hid_open,
 113        .close  =       amdtp_hid_close,
 114        .request  =     amdtp_hid_request,
 115        .wait   =       amdtp_wait_for_response,
 116        .raw_request  = amdtp_raw_request,
 117};
 118
 119int amdtp_hid_probe(u32 cur_hid_dev, struct amdtp_cl_data *cli_data)
 120{
 121        struct hid_device *hid;
 122        struct amdtp_hid_data *hid_data;
 123        int rc;
 124
 125        hid = hid_allocate_device();
 126        if (IS_ERR(hid))
 127                return PTR_ERR(hid);
 128
 129        hid_data = kzalloc(sizeof(*hid_data), GFP_KERNEL);
 130        if (!hid_data) {
 131                rc = -ENOMEM;
 132                goto err_hid_data;
 133        }
 134
 135        hid->ll_driver = &amdtp_hid_ll_driver;
 136        hid_data->index = cur_hid_dev;
 137        hid_data->cli_data = cli_data;
 138        init_waitqueue_head(&hid_data->hid_wait);
 139
 140        hid->driver_data = hid_data;
 141        cli_data->hid_sensor_hubs[cur_hid_dev] = hid;
 142        hid->bus = BUS_AMD_AMDTP;
 143        hid->vendor = AMD_SFH_HID_VENDOR;
 144        hid->product = AMD_SFH_HID_PRODUCT;
 145        snprintf(hid->name, sizeof(hid->name), "%s %04X:%04X", "hid-amdtp",
 146                 hid->vendor, hid->product);
 147
 148        rc = hid_add_device(hid);
 149        if (rc)
 150                goto err_hid_device;
 151        return 0;
 152
 153err_hid_device:
 154        kfree(hid_data);
 155err_hid_data:
 156        hid_destroy_device(hid);
 157        return rc;
 158}
 159
 160void amdtp_hid_remove(struct amdtp_cl_data *cli_data)
 161{
 162        int i;
 163
 164        for (i = 0; i < cli_data->num_hid_devices; ++i) {
 165                if (cli_data->hid_sensor_hubs[i]) {
 166                        kfree(cli_data->hid_sensor_hubs[i]->driver_data);
 167                        hid_destroy_device(cli_data->hid_sensor_hubs[i]);
 168                        cli_data->hid_sensor_hubs[i] = NULL;
 169                }
 170        }
 171}
 172