Skip to content

Commit 175278a

Browse files
committed
Make the driver work with both devices.
1 parent 2b3ebcb commit 175278a

File tree

1 file changed

+106
-40
lines changed

1 file changed

+106
-40
lines changed

module/surface_sam_vhf.c

Lines changed: 106 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,38 @@
1717

1818
#define VHF_INPUT_NAME "Microsoft Virtual HID Framework Device"
1919

20-
/*
21-
* Request ID for VHF events. This value is based on the output of the Surface
22-
* EC and should not be changed.
23-
*/
24-
#define SAM_EVENT_VHF_RQID 0x0015
25-
#define SAM_EVENT_VHF_TC 0x15
20+
#define VHF_MSHW0096 BIT(0)
21+
#define VHF_MSHW0114 BIT(1)
22+
23+
struct vhf_device_info {
24+
const u8 type;
25+
const u16 rqid;
26+
const u8 tc;
27+
};
2628

2729
struct vhf_evtctx {
2830
struct device *dev;
2931
struct hid_device *hid;
32+
const struct vhf_device_info *info;
3033
};
3134

3235
struct vhf_drvdata {
3336
struct vhf_evtctx event_ctx;
3437
};
3538

3639

40+
static const struct vhf_device_info device_mshw0096 = {
41+
.type = VHF_MSHW0096,
42+
.rqid = 0x0001,
43+
.tc = 0x08,
44+
};
45+
46+
static const struct vhf_device_info device_mshw0114 = {
47+
.type = VHF_MSHW0114,
48+
.rqid = 0x0015,
49+
.tc = 0x15,
50+
};
51+
3752
/*
3853
* These report descriptors have been extracted from a Surface Book 2.
3954
* They seems to be similar enough to be usable on the Surface Laptop.
@@ -591,6 +606,58 @@ static const u8 vhf_hid_desc[] = {
591606
/* 0xC0 /1* End Collection *1/ */
592607
};
593608

609+
// Contains only the keyboard descriptor (MSHW0096 only provided the keyboard)
610+
static const u8 vhf_hid_keyboard_only_desc[] = {
611+
// keyboard descriptor (event command ID 0x03)
612+
0x05, 0x01, /* Usage Page (Desktop), */
613+
0x09, 0x06, /* Usage (Keyboard), */
614+
0xA1, 0x01, /* Collection (Application), */
615+
0x85, 0x01, /* Report ID (1), */
616+
0x14, /* Logical Minimum (0), */
617+
0x25, 0x01, /* Logical Maximum (1), */
618+
0x75, 0x01, /* Report Size (1), */
619+
0x95, 0x08, /* Report Count (8), */
620+
0x05, 0x07, /* Usage Page (Keyboard), */
621+
0x19, 0xE0, /* Usage Minimum (KB Leftcontrol), */
622+
0x29, 0xE7, /* Usage Maximum (KB Right GUI), */
623+
0x81, 0x02, /* Input (Variable), */
624+
0x75, 0x08, /* Report Size (8), */
625+
0x95, 0x0A, /* Report Count (10), */
626+
0x18, /* Usage Minimum (None), */
627+
0x29, 0x91, /* Usage Maximum (KB LANG2), */
628+
0x26, 0xFF, 0x00, /* Logical Maximum (255), */
629+
0x80, /* Input, */
630+
0x05, 0x0C, /* Usage Page (Consumer), */
631+
0x0A, 0xC0, 0x02, /* Usage (02C0h), */
632+
0xA1, 0x02, /* Collection (Logical), */
633+
0x1A, 0xC1, 0x02, /* Usage Minimum (02C1h), */
634+
0x2A, 0xC6, 0x02, /* Usage Maximum (02C6h), */
635+
0x95, 0x06, /* Report Count (6), */
636+
0xB1, 0x03, /* Feature (Constant, Variable), */
637+
0xC0, /* End Collection, */
638+
0x05, 0x08, /* Usage Page (LED), */
639+
0x19, 0x01, /* Usage Minimum (01h), */
640+
0x29, 0x03, /* Usage Maximum (03h), */
641+
0x75, 0x01, /* Report Size (1), */
642+
0x95, 0x03, /* Report Count (3), */
643+
0x25, 0x01, /* Logical Maximum (1), */
644+
0x91, 0x02, /* Output (Variable), */
645+
0x95, 0x05, /* Report Count (5), */
646+
0x91, 0x01, /* Output (Constant), */
647+
0xC0, /* End Collection, */
648+
649+
// media key descriptor (event command ID 0x04)
650+
0x09, 0x01, /* Usage (Consumer Control), */
651+
0xA1, 0x01, /* Collection (Application), */
652+
0x85, 0x03, /* Report ID (3), */
653+
0x75, 0x10, /* Report Size (16), */
654+
0x14, /* Logical Minimum (0), */
655+
0x26, 0xFF, 0x03, /* Logical Maximum (1023), */
656+
0x18, /* Usage Minimum (00h), */
657+
0x2A, 0xFF, 0x03, /* Usage Maximum (03FFh), */
658+
0x80, /* Input, */
659+
0xC0, /* End Collection, */
660+
};
594661

595662
static int vhf_hid_start(struct hid_device *hid)
596663
{
@@ -616,39 +683,33 @@ static void vhf_hid_close(struct hid_device *hid)
616683

617684
static int vhf_hid_parse(struct hid_device *hid)
618685
{
619-
return hid_parse_report(hid, (u8 *)vhf_hid_desc, ARRAY_SIZE(vhf_hid_desc));
686+
struct vhf_drvdata *data = platform_get_drvdata(to_platform_device(hid->dev.parent));
687+
688+
switch (data->event_ctx.info->type) {
689+
case VHF_MSHW0096:
690+
return hid_parse_report(hid, (u8 *)vhf_hid_keyboard_only_desc, ARRAY_SIZE(vhf_hid_keyboard_only_desc));
691+
case VHF_MSHW0114:
692+
return hid_parse_report(hid, (u8 *)vhf_hid_desc, ARRAY_SIZE(vhf_hid_desc));
693+
};
694+
695+
return -EINVAL;
620696
}
621697

622698
static int vhf_hid_raw_request(struct hid_device *hid, unsigned char reportnum,
623699
u8 *buf, size_t len, unsigned char rtype,
624700
int reqtype)
625701
{
626-
hid_dbg(hid, "%s: reportnum %#04x %i %i\n", __func__, reportnum, rtype, reqtype);
702+
// Byte 0 is the report number. Report data starts at byte 1.
627703
buf[0] = reportnum;
704+
705+
hid_dbg(hid, "%s: reportnum %#04x %i %i\n", __func__, reportnum, rtype, reqtype);
628706
print_hex_dump_debug("report:", DUMP_PREFIX_OFFSET, 16, 1, buf, len, false);
629-
// rtype: HID_INPUT_REPORT(1)/HID_OUTPUT_REPORT(2)/HID_FEATURE_REPORT(3)
630-
// reqtype: HID_REQ_SET_REPORT(0x9)/HID_REQ_GET_REPORT(0x1)
631707

632708
int status;
633709
u8 iid = 0x02;
634710
u8 cid;
635711

636-
/* switch (rtype) { */
637-
/* case HID_INPUT_REPORT: */
638-
/* iid = 0x01; */
639-
/* break; */
640-
/* /1* case HID_OUTPUT_REPORT: *1/ */
641-
/* /1* iid = 0x02; *1/ */
642-
/* /1* break; *1/ */
643-
/* // TODO: keyboard reports need to go to iid 0x00 */
644-
/* case HID_OUTPUT_REPORT: */
645-
/* case HID_FEATURE_REPORT: */
646-
/* iid = 0x03; */
647-
/* break; */
648-
/* default: */
649-
/* hid_err(hid, "%s: unknown report type 0x%02x\n", __func__, rtype); */
650-
/* return 0; // discard everything */
651-
/* } */
712+
struct vhf_drvdata *data = platform_get_drvdata(to_platform_device(hid->dev.parent));
652713

653714
switch (reqtype) {
654715
case HID_REQ_GET_REPORT:
@@ -663,7 +724,7 @@ static int vhf_hid_raw_request(struct hid_device *hid, unsigned char reportnum,
663724
}
664725

665726
struct surface_sam_ssh_rqst rqst = {
666-
.tc = SAM_EVENT_VHF_TC,
727+
.tc = data->event_ctx.info->tc,
667728
.pri = SURFACE_SAM_PRIORITY_HIGH,
668729
.iid = iid,
669730
.cid = cid,
@@ -730,7 +791,7 @@ static int vhf_event_handler(struct surface_sam_ssh_event *event, void *data)
730791
{
731792
struct vhf_evtctx *ctx = (struct vhf_evtctx *)data;
732793

733-
if (event->tc == SAM_EVENT_VHF_TC && (event->cid == 0x00 || event->cid == 0x03 || event->cid == 0x04)) {
794+
if (event->tc == ctx->info->tc && (event->cid == 0x00 || event->cid == 0x03 || event->cid == 0x04)) {
734795
return hid_input_report(ctx->hid, HID_INPUT_REPORT, event->pld, event->len, 1);
735796
}
736797

@@ -742,6 +803,7 @@ static int surface_sam_vhf_probe(struct platform_device *pdev)
742803
{
743804
struct vhf_drvdata *drvdata;
744805
struct hid_device *hid;
806+
const struct vhf_device_info *info;
745807
int status;
746808

747809
// add device link to EC
@@ -761,33 +823,36 @@ static int surface_sam_vhf_probe(struct platform_device *pdev)
761823
goto err_probe_hid;
762824
}
763825

826+
info = acpi_device_get_match_data(&pdev->dev);
827+
828+
drvdata->event_ctx.dev = &pdev->dev;
829+
drvdata->event_ctx.hid = hid;
830+
drvdata->event_ctx.info = info;
831+
832+
platform_set_drvdata(pdev, drvdata);
833+
764834
status = hid_add_device(hid);
765835
if (status) {
766836
goto err_add_hid;
767837
}
768838

769-
drvdata->event_ctx.dev = &pdev->dev;
770-
drvdata->event_ctx.hid = hid;
771-
772-
platform_set_drvdata(pdev, drvdata);
773-
774839
status = surface_sam_ssh_set_event_handler(
775-
SAM_EVENT_VHF_RQID,
840+
info->rqid,
776841
vhf_event_handler,
777842
&drvdata->event_ctx);
778843
if (status) {
779844
goto err_add_hid;
780845
}
781846

782-
status = surface_sam_ssh_enable_event_source(SAM_EVENT_VHF_TC, 0x01, SAM_EVENT_VHF_RQID);
847+
status = surface_sam_ssh_enable_event_source(info->tc, 0x01, info->rqid);
783848
if (status) {
784849
goto err_event_source;
785850
}
786851

787852
return 0;
788853

789854
err_event_source:
790-
surface_sam_ssh_remove_event_handler(SAM_EVENT_VHF_RQID);
855+
surface_sam_ssh_remove_event_handler(info->rqid);
791856
err_add_hid:
792857
hid_destroy_device(hid);
793858
platform_set_drvdata(pdev, NULL);
@@ -799,9 +864,10 @@ static int surface_sam_vhf_probe(struct platform_device *pdev)
799864
static int surface_sam_vhf_remove(struct platform_device *pdev)
800865
{
801866
struct vhf_drvdata *drvdata = platform_get_drvdata(pdev);
867+
struct vhf_device_info *info = drvdata->event_ctx.info;
802868

803-
surface_sam_ssh_disable_event_source(SAM_EVENT_VHF_TC, 0x01, SAM_EVENT_VHF_RQID);
804-
surface_sam_ssh_remove_event_handler(SAM_EVENT_VHF_RQID);
869+
surface_sam_ssh_disable_event_source(info->tc, 0x01, info->rqid);
870+
surface_sam_ssh_remove_event_handler(info->rqid);
805871

806872
hid_destroy_device(drvdata->event_ctx.hid);
807873
kfree(drvdata);
@@ -812,8 +878,8 @@ static int surface_sam_vhf_remove(struct platform_device *pdev)
812878

813879

814880
static const struct acpi_device_id surface_sam_vhf_match[] = {
815-
{ "MSHW0096" },
816-
{ "MSHW0114" },
881+
{ "MSHW0096", .driver_data = (kernel_ulong_t)&device_mshw0096 },
882+
{ "MSHW0114", .driver_data = (kernel_ulong_t)&device_mshw0114 },
817883
{ },
818884
};
819885
MODULE_DEVICE_TABLE(acpi, surface_sam_vhf_match);

0 commit comments

Comments
 (0)