1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "SwitchInputMapper"
18 //#define LOG_NDEBUG 0
19 
20 #include "SwitchInputMapper.h"
21 
22 #include <inttypes.h>
23 #include <linux/input.h>
24 #include <hardware/input.h>
25 #include <utils/Log.h>
26 
27 #include "InputHost.h"
28 #include "InputHub.h"
29 
30 namespace android {
31 
32 static struct {
33     int32_t scancode;
34     InputUsage usage;
35 } codeMap[] = {
36     {SW_LID, INPUT_USAGE_SWITCH_LID},
37     {SW_TABLET_MODE, INPUT_USAGE_SWITCH_UNKNOWN},
38     {SW_HEADPHONE_INSERT, INPUT_USAGE_SWITCH_HEADPHONE_INSERT},
39     {SW_RFKILL_ALL, INPUT_USAGE_SWITCH_UNKNOWN},
40     {SW_MICROPHONE_INSERT, INPUT_USAGE_SWITCH_MICROPHONE_INSERT},
41     {SW_DOCK, INPUT_USAGE_SWITCH_UNKNOWN},
42     {SW_LINEOUT_INSERT, INPUT_USAGE_SWITCH_LINEOUT_INSERT},
43     {SW_JACK_PHYSICAL_INSERT, INPUT_USAGE_SWITCH_UNKNOWN},
44     {SW_VIDEOOUT_INSERT, INPUT_USAGE_SWITCH_UNKNOWN},
45     {SW_CAMERA_LENS_COVER, INPUT_USAGE_SWITCH_CAMERA_LENS_COVER},
46     {SW_KEYPAD_SLIDE, INPUT_USAGE_SWITCH_KEYPAD_SLIDE},
47     {SW_FRONT_PROXIMITY, INPUT_USAGE_SWITCH_UNKNOWN},
48     {SW_ROTATE_LOCK, INPUT_USAGE_SWITCH_UNKNOWN},
49     {SW_LINEIN_INSERT, INPUT_USAGE_SWITCH_UNKNOWN},
50     {SW_MUTE_DEVICE, INPUT_USAGE_SWITCH_UNKNOWN},
51     {SW_PEN_INSERTED, INPUT_USAGE_SWITCH_UNKNOWN},
52     {SW_HPHL_OVERCURRENT, INPUT_USAGE_SWITCH_UNKNOWN},
53     {SW_HPHR_OVERCURRENT, INPUT_USAGE_SWITCH_UNKNOWN},
54     {SW_UNSUPPORT_INSERT, INPUT_USAGE_SWITCH_UNKNOWN},
55     {0x13 /* unused */, INPUT_USAGE_SWITCH_UNKNOWN},
56     {0x14 /* unused */, INPUT_USAGE_SWITCH_UNKNOWN},
57     {0x15 /* unused */, INPUT_USAGE_SWITCH_UNKNOWN},
58     {0x16 /* unused */, INPUT_USAGE_SWITCH_UNKNOWN},
59     {0x17 /* unused */, INPUT_USAGE_SWITCH_UNKNOWN},
60     {0x18 /* unused */, INPUT_USAGE_SWITCH_UNKNOWN},
61     {0x19 /* unused */, INPUT_USAGE_SWITCH_UNKNOWN},
62     {SW_MAX, INPUT_USAGE_SWITCH_UNKNOWN},
63 };
64 
SwitchInputMapper()65 SwitchInputMapper::SwitchInputMapper()
66     : InputMapper() {
67     // If this gets larger than 64, then the mSwitchValues and mUpdatedSwitchMask
68     // variables need to be changed to support more than 64 bits.
69     static_assert(SW_CNT <= 64, "More than 64 switches defined in linux/input.h");
70 }
71 
configureInputReport(InputDeviceNode * devNode,InputReportDefinition * report)72 bool SwitchInputMapper::configureInputReport(InputDeviceNode* devNode,
73         InputReportDefinition* report) {
74     InputUsage usages[SW_CNT];
75     int numUsages = 0;
76     for (int32_t i = 0; i < SW_CNT; ++i) {
77         if (devNode->hasSwitch(codeMap[i].scancode)) {
78             usages[numUsages++] = codeMap[i].usage;
79         }
80     }
81     if (numUsages == 0) {
82         ALOGE("SwitchInputMapper found no switches for %s!", devNode->getPath().c_str());
83         return false;
84     }
85     setInputReportDefinition(report);
86     getInputReportDefinition()->addCollection(INPUT_COLLECTION_ID_SWITCH, 1);
87     getInputReportDefinition()->declareUsages(INPUT_COLLECTION_ID_SWITCH, usages, numUsages);
88     return true;
89 }
90 
process(const InputEvent & event)91 void SwitchInputMapper::process(const InputEvent& event) {
92     switch (event.type) {
93         case EV_SW:
94             processSwitch(event.code, event.value);
95             break;
96         case EV_SYN:
97             if (event.code == SYN_REPORT) {
98                 sync(event.when);
99             }
100             break;
101         default:
102             ALOGV("unknown switch event type: %d", event.type);
103     }
104 }
105 
processSwitch(int32_t switchCode,int32_t switchValue)106 void SwitchInputMapper::processSwitch(int32_t switchCode, int32_t switchValue) {
107     ALOGV("processing switch event. code=%" PRId32 ", value=%" PRId32, switchCode, switchValue);
108     if (switchCode >= 0 && switchCode < SW_CNT) {
109         if (switchValue) {
110             mSwitchValues.markBit(switchCode);
111         } else {
112             mSwitchValues.clearBit(switchCode);
113         }
114         mUpdatedSwitchMask.markBit(switchCode);
115     }
116 }
117 
sync(nsecs_t when)118 void SwitchInputMapper::sync(nsecs_t when) {
119     if (mUpdatedSwitchMask.isEmpty()) {
120         // Clear the values just in case.
121         mSwitchValues.clear();
122         return;
123     }
124 
125     while (!mUpdatedSwitchMask.isEmpty()) {
126         auto bit = mUpdatedSwitchMask.firstMarkedBit();
127         getInputReport()->setBoolUsage(INPUT_COLLECTION_ID_SWITCH, codeMap[bit].usage,
128                 mSwitchValues.hasBit(bit), 0);
129         mUpdatedSwitchMask.clearBit(bit);
130     }
131     getInputReport()->reportEvent(getDeviceHandle());
132     mUpdatedSwitchMask.clear();
133     mSwitchValues.clear();
134 }
135 
136 }  // namespace android
137