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/module.h>
14 #include <linux/property.h>
15 #include <linux/soundwire/sdw.h>
16 #include <linux/types.h>
17 #include <sound/sdca.h>
18 #include <sound/sdca_function.h>
19 #include <sound/sdca_hid.h>
20
sdwhid_parse(struct hid_device * hid)21 static int sdwhid_parse(struct hid_device *hid)
22 {
23 struct sdca_entity *entity = hid->driver_data;
24 unsigned int rsize;
25 int ret;
26
27 rsize = le16_to_cpu(entity->hide.hid_desc.rpt_desc.wDescriptorLength);
28
29 if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) {
30 dev_err(&hid->dev, "invalid size of report descriptor (%u)\n", rsize);
31 return -EINVAL;
32 }
33
34 ret = hid_parse_report(hid, entity->hide.hid_report_desc, rsize);
35
36 if (!ret)
37 return 0;
38
39 dev_err(&hid->dev, "parsing report descriptor failed\n");
40 return ret;
41 }
42
sdwhid_start(struct hid_device * hid)43 static int sdwhid_start(struct hid_device *hid)
44 {
45 return 0;
46 }
47
sdwhid_stop(struct hid_device * hid)48 static void sdwhid_stop(struct hid_device *hid)
49 {
50 }
51
sdwhid_raw_request(struct hid_device * hid,unsigned char reportnum,__u8 * buf,size_t len,unsigned char rtype,int reqtype)52 static int sdwhid_raw_request(struct hid_device *hid, unsigned char reportnum,
53 __u8 *buf, size_t len, unsigned char rtype, int reqtype)
54 {
55 switch (reqtype) {
56 case HID_REQ_GET_REPORT:
57 /* not implemented yet */
58 return 0;
59 case HID_REQ_SET_REPORT:
60 /* not implemented yet */
61 return 0;
62 default:
63 return -EIO;
64 }
65 }
66
sdwhid_open(struct hid_device * hid)67 static int sdwhid_open(struct hid_device *hid)
68 {
69 return 0;
70 }
71
sdwhid_close(struct hid_device * hid)72 static void sdwhid_close(struct hid_device *hid)
73 {
74 }
75
76 static const struct hid_ll_driver sdw_hid_driver = {
77 .parse = sdwhid_parse,
78 .start = sdwhid_start,
79 .stop = sdwhid_stop,
80 .open = sdwhid_open,
81 .close = sdwhid_close,
82 .raw_request = sdwhid_raw_request,
83 };
84
sdca_add_hid_device(struct device * dev,struct sdca_entity * entity)85 int sdca_add_hid_device(struct device *dev, struct sdca_entity *entity)
86 {
87 struct sdw_bus *bus;
88 struct hid_device *hid;
89 struct sdw_slave *slave = dev_to_sdw_dev(dev);
90 int ret;
91
92 bus = slave->bus;
93
94 hid = hid_allocate_device();
95 if (IS_ERR(hid))
96 return PTR_ERR(hid);
97
98 hid->ll_driver = &sdw_hid_driver;
99
100 hid->dev.parent = dev;
101 hid->bus = BUS_SDW;
102 hid->version = le16_to_cpu(entity->hide.hid_desc.bcdHID);
103
104 snprintf(hid->name, sizeof(hid->name),
105 "HID sdw:%01x:%01x:%04x:%04x:%02x",
106 bus->controller_id, bus->link_id, slave->id.mfg_id,
107 slave->id.part_id, slave->id.class_id);
108
109 snprintf(hid->phys, sizeof(hid->phys), "%s", dev->bus->name);
110
111 hid->driver_data = entity;
112
113 ret = hid_add_device(hid);
114 if (ret && ret != -ENODEV) {
115 dev_err(dev, "can't add hid device: %d\n", ret);
116 hid_destroy_device(hid);
117 return ret;
118 }
119
120 entity->hide.hid = hid;
121
122 return 0;
123 }
124 EXPORT_SYMBOL_NS(sdca_add_hid_device, "SND_SOC_SDCA");
125
126 MODULE_LICENSE("Dual BSD/GPL");
127 MODULE_DESCRIPTION("SDCA HID library");
128