0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <asm/unaligned.h>
0011 #include <linux/hid.h>
0012 #include <linux/kernel.h>
0013 #include <linux/module.h>
0014 #include <linux/types.h>
0015 #include <linux/usb/ch9.h>
0016
0017 #include <linux/surface_aggregator/controller.h>
0018
0019 #include "surface_hid_core.h"
0020
0021
0022
0023
0024 static bool surface_hid_is_hot_removed(struct surface_hid_device *shid)
0025 {
0026
0027
0028
0029
0030 if (!is_ssam_device(shid->dev))
0031 return false;
0032
0033 return ssam_device_is_hot_removed(to_ssam_device(shid->dev));
0034 }
0035
0036
0037
0038
0039 static int surface_hid_load_hid_descriptor(struct surface_hid_device *shid)
0040 {
0041 int status;
0042
0043 if (surface_hid_is_hot_removed(shid))
0044 return -ENODEV;
0045
0046 status = shid->ops.get_descriptor(shid, SURFACE_HID_DESC_HID,
0047 (u8 *)&shid->hid_desc, sizeof(shid->hid_desc));
0048 if (status)
0049 return status;
0050
0051 if (shid->hid_desc.desc_len != sizeof(shid->hid_desc)) {
0052 dev_err(shid->dev, "unexpected HID descriptor length: got %u, expected %zu\n",
0053 shid->hid_desc.desc_len, sizeof(shid->hid_desc));
0054 return -EPROTO;
0055 }
0056
0057 if (shid->hid_desc.desc_type != HID_DT_HID) {
0058 dev_err(shid->dev, "unexpected HID descriptor type: got %#04x, expected %#04x\n",
0059 shid->hid_desc.desc_type, HID_DT_HID);
0060 return -EPROTO;
0061 }
0062
0063 if (shid->hid_desc.num_descriptors != 1) {
0064 dev_err(shid->dev, "unexpected number of descriptors: got %u, expected 1\n",
0065 shid->hid_desc.num_descriptors);
0066 return -EPROTO;
0067 }
0068
0069 if (shid->hid_desc.report_desc_type != HID_DT_REPORT) {
0070 dev_err(shid->dev, "unexpected report descriptor type: got %#04x, expected %#04x\n",
0071 shid->hid_desc.report_desc_type, HID_DT_REPORT);
0072 return -EPROTO;
0073 }
0074
0075 return 0;
0076 }
0077
0078 static int surface_hid_load_device_attributes(struct surface_hid_device *shid)
0079 {
0080 int status;
0081
0082 if (surface_hid_is_hot_removed(shid))
0083 return -ENODEV;
0084
0085 status = shid->ops.get_descriptor(shid, SURFACE_HID_DESC_ATTRS,
0086 (u8 *)&shid->attrs, sizeof(shid->attrs));
0087 if (status)
0088 return status;
0089
0090 if (get_unaligned_le32(&shid->attrs.length) != sizeof(shid->attrs)) {
0091 dev_err(shid->dev, "unexpected attribute length: got %u, expected %zu\n",
0092 get_unaligned_le32(&shid->attrs.length), sizeof(shid->attrs));
0093 return -EPROTO;
0094 }
0095
0096 return 0;
0097 }
0098
0099
0100
0101
0102 static int surface_hid_start(struct hid_device *hid)
0103 {
0104 struct surface_hid_device *shid = hid->driver_data;
0105
0106 return ssam_notifier_register(shid->ctrl, &shid->notif);
0107 }
0108
0109 static void surface_hid_stop(struct hid_device *hid)
0110 {
0111 struct surface_hid_device *shid = hid->driver_data;
0112 bool hot_removed;
0113
0114
0115
0116
0117
0118
0119
0120 hot_removed = surface_hid_is_hot_removed(shid);
0121
0122
0123 __ssam_notifier_unregister(shid->ctrl, &shid->notif, !hot_removed);
0124 }
0125
0126 static int surface_hid_open(struct hid_device *hid)
0127 {
0128 return 0;
0129 }
0130
0131 static void surface_hid_close(struct hid_device *hid)
0132 {
0133 }
0134
0135 static int surface_hid_parse(struct hid_device *hid)
0136 {
0137 struct surface_hid_device *shid = hid->driver_data;
0138 size_t len = get_unaligned_le16(&shid->hid_desc.report_desc_len);
0139 u8 *buf;
0140 int status;
0141
0142 if (surface_hid_is_hot_removed(shid))
0143 return -ENODEV;
0144
0145 buf = kzalloc(len, GFP_KERNEL);
0146 if (!buf)
0147 return -ENOMEM;
0148
0149 status = shid->ops.get_descriptor(shid, SURFACE_HID_DESC_REPORT, buf, len);
0150 if (!status)
0151 status = hid_parse_report(hid, buf, len);
0152
0153 kfree(buf);
0154 return status;
0155 }
0156
0157 static int surface_hid_raw_request(struct hid_device *hid, unsigned char reportnum, u8 *buf,
0158 size_t len, unsigned char rtype, int reqtype)
0159 {
0160 struct surface_hid_device *shid = hid->driver_data;
0161
0162 if (surface_hid_is_hot_removed(shid))
0163 return -ENODEV;
0164
0165 if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT)
0166 return shid->ops.output_report(shid, reportnum, buf, len);
0167
0168 else if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT)
0169 return shid->ops.get_feature_report(shid, reportnum, buf, len);
0170
0171 else if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT)
0172 return shid->ops.set_feature_report(shid, reportnum, buf, len);
0173
0174 return -EIO;
0175 }
0176
0177 static struct hid_ll_driver surface_hid_ll_driver = {
0178 .start = surface_hid_start,
0179 .stop = surface_hid_stop,
0180 .open = surface_hid_open,
0181 .close = surface_hid_close,
0182 .parse = surface_hid_parse,
0183 .raw_request = surface_hid_raw_request,
0184 };
0185
0186
0187
0188
0189 int surface_hid_device_add(struct surface_hid_device *shid)
0190 {
0191 int status;
0192
0193 status = surface_hid_load_hid_descriptor(shid);
0194 if (status)
0195 return status;
0196
0197 status = surface_hid_load_device_attributes(shid);
0198 if (status)
0199 return status;
0200
0201 shid->hid = hid_allocate_device();
0202 if (IS_ERR(shid->hid))
0203 return PTR_ERR(shid->hid);
0204
0205 shid->hid->dev.parent = shid->dev;
0206 shid->hid->bus = BUS_HOST;
0207 shid->hid->vendor = get_unaligned_le16(&shid->attrs.vendor);
0208 shid->hid->product = get_unaligned_le16(&shid->attrs.product);
0209 shid->hid->version = get_unaligned_le16(&shid->hid_desc.hid_version);
0210 shid->hid->country = shid->hid_desc.country_code;
0211
0212 snprintf(shid->hid->name, sizeof(shid->hid->name), "Microsoft Surface %04X:%04X",
0213 shid->hid->vendor, shid->hid->product);
0214
0215 strscpy(shid->hid->phys, dev_name(shid->dev), sizeof(shid->hid->phys));
0216
0217 shid->hid->driver_data = shid;
0218 shid->hid->ll_driver = &surface_hid_ll_driver;
0219
0220 status = hid_add_device(shid->hid);
0221 if (status)
0222 hid_destroy_device(shid->hid);
0223
0224 return status;
0225 }
0226 EXPORT_SYMBOL_GPL(surface_hid_device_add);
0227
0228 void surface_hid_device_destroy(struct surface_hid_device *shid)
0229 {
0230 hid_destroy_device(shid->hid);
0231 }
0232 EXPORT_SYMBOL_GPL(surface_hid_device_destroy);
0233
0234
0235
0236
0237 #ifdef CONFIG_PM_SLEEP
0238
0239 static int surface_hid_suspend(struct device *dev)
0240 {
0241 struct surface_hid_device *d = dev_get_drvdata(dev);
0242
0243 return hid_driver_suspend(d->hid, PMSG_SUSPEND);
0244 }
0245
0246 static int surface_hid_resume(struct device *dev)
0247 {
0248 struct surface_hid_device *d = dev_get_drvdata(dev);
0249
0250 return hid_driver_resume(d->hid);
0251 }
0252
0253 static int surface_hid_freeze(struct device *dev)
0254 {
0255 struct surface_hid_device *d = dev_get_drvdata(dev);
0256
0257 return hid_driver_suspend(d->hid, PMSG_FREEZE);
0258 }
0259
0260 static int surface_hid_poweroff(struct device *dev)
0261 {
0262 struct surface_hid_device *d = dev_get_drvdata(dev);
0263
0264 return hid_driver_suspend(d->hid, PMSG_HIBERNATE);
0265 }
0266
0267 static int surface_hid_restore(struct device *dev)
0268 {
0269 struct surface_hid_device *d = dev_get_drvdata(dev);
0270
0271 return hid_driver_reset_resume(d->hid);
0272 }
0273
0274 const struct dev_pm_ops surface_hid_pm_ops = {
0275 .freeze = surface_hid_freeze,
0276 .thaw = surface_hid_resume,
0277 .suspend = surface_hid_suspend,
0278 .resume = surface_hid_resume,
0279 .poweroff = surface_hid_poweroff,
0280 .restore = surface_hid_restore,
0281 };
0282 EXPORT_SYMBOL_GPL(surface_hid_pm_ops);
0283
0284 #else
0285
0286 const struct dev_pm_ops surface_hid_pm_ops = { };
0287 EXPORT_SYMBOL_GPL(surface_hid_pm_ops);
0288
0289 #endif
0290
0291 MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
0292 MODULE_DESCRIPTION("HID transport driver core for Surface System Aggregator Module");
0293 MODULE_LICENSE("GPL");