1 // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) 2 3 /* 4 * The MIPI SDCA specification is available for public downloads at 5 * https://www.mipi.org/mipi-sdca-v1-0-download 6 */ 7 8 #include <linux/acpi.h> 9 #include <linux/byteorder/generic.h> 10 #include <linux/cleanup.h> 11 #include <linux/device.h> 12 #include <linux/dev_printk.h> 13 #include <linux/hid.h> 14 #include <linux/module.h> 15 #include <linux/property.h> 16 #include <linux/soundwire/sdw.h> 17 #include <linux/string.h> 18 #include <linux/types.h> 19 #include <sound/sdca.h> 20 #include <sound/sdca_function.h> 21 #include <sound/sdca_hid.h> 22 #include <sound/sdca_interrupts.h> 23 #include <sound/sdca_ump.h> 24 25 static int sdwhid_parse(struct hid_device *hid) 26 { 27 struct sdca_function_data *function = hid->driver_data; 28 unsigned int rsize; 29 int ret; 30 31 rsize = le16_to_cpu(function->hid.desc.rpt_desc.wDescriptorLength); 32 33 if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) { 34 dev_err(&hid->dev, "invalid size of report descriptor (%u)\n", rsize); 35 return -EINVAL; 36 } 37 38 ret = hid_parse_report(hid, function->hid.report_desc, rsize); 39 40 if (!ret) 41 return 0; 42 43 dev_err(&hid->dev, "parsing report descriptor failed\n"); 44 return ret; 45 } 46 47 static int sdwhid_start(struct hid_device *hid) 48 { 49 return 0; 50 } 51 52 static void sdwhid_stop(struct hid_device *hid) 53 { 54 } 55 56 static int sdwhid_raw_request(struct hid_device *hid, unsigned char reportnum, 57 __u8 *buf, size_t len, unsigned char rtype, int reqtype) 58 { 59 switch (reqtype) { 60 case HID_REQ_GET_REPORT: 61 /* not implemented yet */ 62 return 0; 63 case HID_REQ_SET_REPORT: 64 /* not implemented yet */ 65 return 0; 66 default: 67 return -EIO; 68 } 69 } 70 71 static int sdwhid_open(struct hid_device *hid) 72 { 73 return 0; 74 } 75 76 static void sdwhid_close(struct hid_device *hid) 77 { 78 } 79 80 static const struct hid_ll_driver sdw_hid_driver = { 81 .parse = sdwhid_parse, 82 .start = sdwhid_start, 83 .stop = sdwhid_stop, 84 .open = sdwhid_open, 85 .close = sdwhid_close, 86 .raw_request = sdwhid_raw_request, 87 }; 88 89 /** 90 * sdca_add_hid_device - create a new SDCA HID device 91 * @interrupt: Pointer to the SDCA interrupt information structure. 92 * 93 * Return: Zero on success, and a negative error code on failure. 94 */ 95 int sdca_add_hid_device(struct sdca_interrupt *interrupt) 96 { 97 struct device *dev = interrupt->dev; 98 struct sdca_function_data *function = interrupt->function; 99 struct hid_device *hid; 100 int ret; 101 102 hid = hid_allocate_device(); 103 if (IS_ERR(hid)) 104 return PTR_ERR(hid); 105 106 hid->ll_driver = &sdw_hid_driver; 107 108 hid->dev.parent = dev; 109 hid->bus = BUS_SDW; 110 hid->version = le16_to_cpu(function->hid.desc.bcdHID); 111 112 strscpy(hid->phys, dev_name(dev)); 113 snprintf(hid->name, sizeof(hid->name), "SDCA %s:%02x", 114 function->desc->name, function->desc->adr); 115 116 hid->driver_data = function; 117 118 ret = hid_add_device(hid); 119 if (ret && ret != -ENODEV) { 120 dev_err(dev, "can't add hid device: %d\n", ret); 121 hid_destroy_device(hid); 122 return ret; 123 } 124 125 interrupt->priv = hid; 126 127 return 0; 128 } 129 EXPORT_SYMBOL_NS(sdca_add_hid_device, "SND_SOC_SDCA"); 130 131 /** 132 * sdca_destroy_hid_device - destroy the HID device 133 * @interrupt: Pointer to the SDCA interrupt information structure. 134 */ 135 void sdca_destroy_hid_device(struct sdca_interrupt *interrupt) 136 { 137 struct hid_device *hid = interrupt->priv; 138 139 hid_destroy_device(hid); 140 } 141 EXPORT_SYMBOL_NS(sdca_destroy_hid_device, "SND_SOC_SDCA"); 142 143 /** 144 * sdca_hid_process_report - read a HID event from the device and report 145 * @interrupt: Pointer to the SDCA interrupt information structure. 146 * 147 * Return: Zero on success, and a negative error code on failure. 148 */ 149 int sdca_hid_process_report(struct sdca_interrupt *interrupt) 150 { 151 struct device *dev = interrupt->dev; 152 struct hid_device *hid = interrupt->priv; 153 void *val __free(kfree) = NULL; 154 int len, ret; 155 156 ret = sdca_ump_get_owner_host(dev, interrupt->function_regmap, 157 interrupt->function, interrupt->entity, 158 interrupt->control); 159 if (ret) 160 return ret; 161 162 len = sdca_ump_read_message(dev, interrupt->device_regmap, 163 interrupt->function_regmap, 164 interrupt->function, interrupt->entity, 165 SDCA_CTL_HIDE_HIDTX_MESSAGEOFFSET, 166 SDCA_CTL_HIDE_HIDTX_MESSAGELENGTH, &val); 167 if (len < 0) 168 return len; 169 170 ret = sdca_ump_set_owner_device(dev, interrupt->function_regmap, 171 interrupt->function, interrupt->entity, 172 interrupt->control); 173 if (ret) 174 return ret; 175 176 ret = hid_input_report(hid, HID_INPUT_REPORT, val, len, true); 177 if (ret < 0) { 178 dev_err(dev, "failed to report hid event: %d\n", ret); 179 return ret; 180 } 181 182 return 0; 183 } 184 EXPORT_SYMBOL_NS(sdca_hid_process_report, "SND_SOC_SDCA"); 185