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
2729struct vhf_evtctx {
2830 struct device * dev ;
2931 struct hid_device * hid ;
32+ const struct vhf_device_info * info ;
3033};
3134
3235struct 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
595662static int vhf_hid_start (struct hid_device * hid )
596663{
@@ -616,39 +683,33 @@ static void vhf_hid_close(struct hid_device *hid)
616683
617684static 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
622698static 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
789854err_event_source :
790- surface_sam_ssh_remove_event_handler (SAM_EVENT_VHF_RQID );
855+ surface_sam_ssh_remove_event_handler (info -> rqid );
791856err_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)
799864static 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
814880static 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};
819885MODULE_DEVICE_TABLE (acpi , surface_sam_vhf_match );
0 commit comments