xref: /aosp_15_r20/hardware/interfaces/usb/1.0/default/Usb.cpp (revision 4d7e907c777eeecc4c5bd7cf640a754fac206ff7)
1*4d7e907cSAndroid Build Coastguard Worker /*
2*4d7e907cSAndroid Build Coastguard Worker  * Copyright (C) 2016 The Android Open Source Project
3*4d7e907cSAndroid Build Coastguard Worker  *
4*4d7e907cSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*4d7e907cSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*4d7e907cSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*4d7e907cSAndroid Build Coastguard Worker  *
8*4d7e907cSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*4d7e907cSAndroid Build Coastguard Worker  *
10*4d7e907cSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*4d7e907cSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*4d7e907cSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*4d7e907cSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*4d7e907cSAndroid Build Coastguard Worker  * limitations under the License.
15*4d7e907cSAndroid Build Coastguard Worker  */
16*4d7e907cSAndroid Build Coastguard Worker #include <assert.h>
17*4d7e907cSAndroid Build Coastguard Worker #include <dirent.h>
18*4d7e907cSAndroid Build Coastguard Worker #include <iostream>
19*4d7e907cSAndroid Build Coastguard Worker #include <fstream>
20*4d7e907cSAndroid Build Coastguard Worker #include <pthread.h>
21*4d7e907cSAndroid Build Coastguard Worker #include <stdio.h>
22*4d7e907cSAndroid Build Coastguard Worker #include <sys/types.h>
23*4d7e907cSAndroid Build Coastguard Worker #include <unistd.h>
24*4d7e907cSAndroid Build Coastguard Worker 
25*4d7e907cSAndroid Build Coastguard Worker #include <cutils/uevent.h>
26*4d7e907cSAndroid Build Coastguard Worker #include <sys/epoll.h>
27*4d7e907cSAndroid Build Coastguard Worker #include <utils/Errors.h>
28*4d7e907cSAndroid Build Coastguard Worker #include <utils/StrongPointer.h>
29*4d7e907cSAndroid Build Coastguard Worker 
30*4d7e907cSAndroid Build Coastguard Worker #include "Usb.h"
31*4d7e907cSAndroid Build Coastguard Worker 
32*4d7e907cSAndroid Build Coastguard Worker namespace android {
33*4d7e907cSAndroid Build Coastguard Worker namespace hardware {
34*4d7e907cSAndroid Build Coastguard Worker namespace usb {
35*4d7e907cSAndroid Build Coastguard Worker namespace V1_0 {
36*4d7e907cSAndroid Build Coastguard Worker namespace implementation {
37*4d7e907cSAndroid Build Coastguard Worker 
38*4d7e907cSAndroid Build Coastguard Worker // Set by the signal handler to destroy the thread
39*4d7e907cSAndroid Build Coastguard Worker volatile bool destroyThread;
40*4d7e907cSAndroid Build Coastguard Worker 
readFile(std::string filename,std::string & contents)41*4d7e907cSAndroid Build Coastguard Worker int32_t readFile(std::string filename, std::string& contents) {
42*4d7e907cSAndroid Build Coastguard Worker     std::ifstream file(filename);
43*4d7e907cSAndroid Build Coastguard Worker 
44*4d7e907cSAndroid Build Coastguard Worker     if (file.is_open()) {
45*4d7e907cSAndroid Build Coastguard Worker         getline(file, contents);
46*4d7e907cSAndroid Build Coastguard Worker         file.close();
47*4d7e907cSAndroid Build Coastguard Worker         return 0;
48*4d7e907cSAndroid Build Coastguard Worker     }
49*4d7e907cSAndroid Build Coastguard Worker     return -1;
50*4d7e907cSAndroid Build Coastguard Worker }
51*4d7e907cSAndroid Build Coastguard Worker 
appendRoleNodeHelper(const std::string portName,PortRoleType type)52*4d7e907cSAndroid Build Coastguard Worker std::string appendRoleNodeHelper(const std::string portName, PortRoleType type) {
53*4d7e907cSAndroid Build Coastguard Worker     std::string node("/sys/class/dual_role_usb/" + portName);
54*4d7e907cSAndroid Build Coastguard Worker 
55*4d7e907cSAndroid Build Coastguard Worker     switch(type) {
56*4d7e907cSAndroid Build Coastguard Worker         case PortRoleType::DATA_ROLE:
57*4d7e907cSAndroid Build Coastguard Worker             return node + "/data_role";
58*4d7e907cSAndroid Build Coastguard Worker         case PortRoleType::POWER_ROLE:
59*4d7e907cSAndroid Build Coastguard Worker             return node + "/power_role";
60*4d7e907cSAndroid Build Coastguard Worker         default:
61*4d7e907cSAndroid Build Coastguard Worker             return node + "/mode";
62*4d7e907cSAndroid Build Coastguard Worker     }
63*4d7e907cSAndroid Build Coastguard Worker }
64*4d7e907cSAndroid Build Coastguard Worker 
convertRoletoString(PortRole role)65*4d7e907cSAndroid Build Coastguard Worker std::string convertRoletoString(PortRole role) {
66*4d7e907cSAndroid Build Coastguard Worker     if (role.type == PortRoleType::POWER_ROLE) {
67*4d7e907cSAndroid Build Coastguard Worker         if (role.role == static_cast<uint32_t> (PortPowerRole::SOURCE))
68*4d7e907cSAndroid Build Coastguard Worker             return "source";
69*4d7e907cSAndroid Build Coastguard Worker         else if (role.role ==  static_cast<uint32_t> (PortPowerRole::SINK))
70*4d7e907cSAndroid Build Coastguard Worker             return "sink";
71*4d7e907cSAndroid Build Coastguard Worker     } else if (role.type == PortRoleType::DATA_ROLE) {
72*4d7e907cSAndroid Build Coastguard Worker         if (role.role == static_cast<uint32_t> (PortDataRole::HOST))
73*4d7e907cSAndroid Build Coastguard Worker             return "host";
74*4d7e907cSAndroid Build Coastguard Worker         if (role.role == static_cast<uint32_t> (PortDataRole::DEVICE))
75*4d7e907cSAndroid Build Coastguard Worker             return "device";
76*4d7e907cSAndroid Build Coastguard Worker     } else if (role.type == PortRoleType::MODE) {
77*4d7e907cSAndroid Build Coastguard Worker         if (role.role == static_cast<uint32_t> (PortMode::UFP))
78*4d7e907cSAndroid Build Coastguard Worker             return "ufp";
79*4d7e907cSAndroid Build Coastguard Worker         if (role.role == static_cast<uint32_t> (PortMode::DFP))
80*4d7e907cSAndroid Build Coastguard Worker             return "dfp";
81*4d7e907cSAndroid Build Coastguard Worker     }
82*4d7e907cSAndroid Build Coastguard Worker     return "none";
83*4d7e907cSAndroid Build Coastguard Worker }
84*4d7e907cSAndroid Build Coastguard Worker 
switchRole(const hidl_string & portName,const PortRole & newRole)85*4d7e907cSAndroid Build Coastguard Worker Return<void> Usb::switchRole(const hidl_string& portName,
86*4d7e907cSAndroid Build Coastguard Worker         const PortRole& newRole) {
87*4d7e907cSAndroid Build Coastguard Worker     std::string filename = appendRoleNodeHelper(std::string(portName.c_str()),
88*4d7e907cSAndroid Build Coastguard Worker         newRole.type);
89*4d7e907cSAndroid Build Coastguard Worker     std::ofstream file(filename);
90*4d7e907cSAndroid Build Coastguard Worker     std::string written;
91*4d7e907cSAndroid Build Coastguard Worker 
92*4d7e907cSAndroid Build Coastguard Worker     ALOGI("filename write: %s role:%d", filename.c_str(), newRole.role);
93*4d7e907cSAndroid Build Coastguard Worker 
94*4d7e907cSAndroid Build Coastguard Worker     if (file.is_open()) {
95*4d7e907cSAndroid Build Coastguard Worker         file << convertRoletoString(newRole).c_str();
96*4d7e907cSAndroid Build Coastguard Worker         file.close();
97*4d7e907cSAndroid Build Coastguard Worker         if (!readFile(filename, written)) {
98*4d7e907cSAndroid Build Coastguard Worker             ALOGI("written: %s", written.c_str());
99*4d7e907cSAndroid Build Coastguard Worker             if (written == convertRoletoString(newRole)) {
100*4d7e907cSAndroid Build Coastguard Worker                 ALOGI("Role switch successfull");
101*4d7e907cSAndroid Build Coastguard Worker                 Return<void> ret =
102*4d7e907cSAndroid Build Coastguard Worker                     mCallback->notifyRoleSwitchStatus(portName, newRole,
103*4d7e907cSAndroid Build Coastguard Worker                     Status::SUCCESS);
104*4d7e907cSAndroid Build Coastguard Worker                 if (!ret.isOk())
105*4d7e907cSAndroid Build Coastguard Worker                     ALOGE("RoleSwitchStatus error %s",
106*4d7e907cSAndroid Build Coastguard Worker                         ret.description().c_str());
107*4d7e907cSAndroid Build Coastguard Worker             }
108*4d7e907cSAndroid Build Coastguard Worker         }
109*4d7e907cSAndroid Build Coastguard Worker     }
110*4d7e907cSAndroid Build Coastguard Worker 
111*4d7e907cSAndroid Build Coastguard Worker     Return<void> ret = mCallback->notifyRoleSwitchStatus(portName, newRole, Status::ERROR);
112*4d7e907cSAndroid Build Coastguard Worker     if (!ret.isOk())
113*4d7e907cSAndroid Build Coastguard Worker         ALOGE("RoleSwitchStatus error %s", ret.description().c_str());
114*4d7e907cSAndroid Build Coastguard Worker 
115*4d7e907cSAndroid Build Coastguard Worker     return Void();
116*4d7e907cSAndroid Build Coastguard Worker }
117*4d7e907cSAndroid Build Coastguard Worker 
getCurrentRoleHelper(std::string portName,PortRoleType type,uint32_t & currentRole)118*4d7e907cSAndroid Build Coastguard Worker Status getCurrentRoleHelper(std::string portName,
119*4d7e907cSAndroid Build Coastguard Worker         PortRoleType type, uint32_t &currentRole)  {
120*4d7e907cSAndroid Build Coastguard Worker     std::string filename;
121*4d7e907cSAndroid Build Coastguard Worker     std::string roleName;
122*4d7e907cSAndroid Build Coastguard Worker 
123*4d7e907cSAndroid Build Coastguard Worker     if (type == PortRoleType::POWER_ROLE) {
124*4d7e907cSAndroid Build Coastguard Worker         filename = "/sys/class/dual_role_usb/" +
125*4d7e907cSAndroid Build Coastguard Worker             portName + "/power_role";
126*4d7e907cSAndroid Build Coastguard Worker         currentRole = static_cast<uint32_t>(PortPowerRole::NONE);
127*4d7e907cSAndroid Build Coastguard Worker     } else if (type == PortRoleType::DATA_ROLE) {
128*4d7e907cSAndroid Build Coastguard Worker         filename = "/sys/class/dual_role_usb/" +
129*4d7e907cSAndroid Build Coastguard Worker             portName + "/data_role";
130*4d7e907cSAndroid Build Coastguard Worker         currentRole = static_cast<uint32_t> (PortDataRole::NONE);
131*4d7e907cSAndroid Build Coastguard Worker     } else if (type == PortRoleType::MODE) {
132*4d7e907cSAndroid Build Coastguard Worker         filename = "/sys/class/dual_role_usb/" +
133*4d7e907cSAndroid Build Coastguard Worker             portName + "/mode";
134*4d7e907cSAndroid Build Coastguard Worker         currentRole = static_cast<uint32_t> (PortMode::NONE);
135*4d7e907cSAndroid Build Coastguard Worker     }
136*4d7e907cSAndroid Build Coastguard Worker 
137*4d7e907cSAndroid Build Coastguard Worker     if (readFile(filename, roleName)) {
138*4d7e907cSAndroid Build Coastguard Worker         ALOGE("getCurrentRole: Failed to open filesystem node");
139*4d7e907cSAndroid Build Coastguard Worker         return Status::ERROR;
140*4d7e907cSAndroid Build Coastguard Worker     }
141*4d7e907cSAndroid Build Coastguard Worker 
142*4d7e907cSAndroid Build Coastguard Worker     if (roleName == "dfp")
143*4d7e907cSAndroid Build Coastguard Worker         currentRole = static_cast<uint32_t> (PortMode::DFP);
144*4d7e907cSAndroid Build Coastguard Worker     else if (roleName == "ufp")
145*4d7e907cSAndroid Build Coastguard Worker         currentRole = static_cast<uint32_t> (PortMode::UFP);
146*4d7e907cSAndroid Build Coastguard Worker     else if (roleName == "source")
147*4d7e907cSAndroid Build Coastguard Worker         currentRole = static_cast<uint32_t> (PortPowerRole::SOURCE);
148*4d7e907cSAndroid Build Coastguard Worker     else if (roleName == "sink")
149*4d7e907cSAndroid Build Coastguard Worker         currentRole = static_cast<uint32_t> (PortPowerRole::SINK);
150*4d7e907cSAndroid Build Coastguard Worker     else if (roleName == "host")
151*4d7e907cSAndroid Build Coastguard Worker         currentRole = static_cast<uint32_t> (PortDataRole::HOST);
152*4d7e907cSAndroid Build Coastguard Worker     else if (roleName == "device")
153*4d7e907cSAndroid Build Coastguard Worker         currentRole = static_cast<uint32_t> (PortDataRole::DEVICE);
154*4d7e907cSAndroid Build Coastguard Worker     else if (roleName != "none") {
155*4d7e907cSAndroid Build Coastguard Worker          /* case for none has already been addressed.
156*4d7e907cSAndroid Build Coastguard Worker           * so we check if the role isnt none.
157*4d7e907cSAndroid Build Coastguard Worker           */
158*4d7e907cSAndroid Build Coastguard Worker         return Status::UNRECOGNIZED_ROLE;
159*4d7e907cSAndroid Build Coastguard Worker     }
160*4d7e907cSAndroid Build Coastguard Worker     return Status::SUCCESS;
161*4d7e907cSAndroid Build Coastguard Worker }
162*4d7e907cSAndroid Build Coastguard Worker 
getTypeCPortNamesHelper(std::vector<std::string> & names)163*4d7e907cSAndroid Build Coastguard Worker Status getTypeCPortNamesHelper(std::vector<std::string>& names) {
164*4d7e907cSAndroid Build Coastguard Worker     DIR *dp;
165*4d7e907cSAndroid Build Coastguard Worker 
166*4d7e907cSAndroid Build Coastguard Worker     dp = opendir("/sys/class/dual_role_usb");
167*4d7e907cSAndroid Build Coastguard Worker     if (dp != NULL)
168*4d7e907cSAndroid Build Coastguard Worker     {
169*4d7e907cSAndroid Build Coastguard Worker rescan:
170*4d7e907cSAndroid Build Coastguard Worker         int32_t ports = 0;
171*4d7e907cSAndroid Build Coastguard Worker         int32_t current = 0;
172*4d7e907cSAndroid Build Coastguard Worker         struct dirent *ep;
173*4d7e907cSAndroid Build Coastguard Worker 
174*4d7e907cSAndroid Build Coastguard Worker         while ((ep = readdir (dp))) {
175*4d7e907cSAndroid Build Coastguard Worker             if (ep->d_type == DT_LNK) {
176*4d7e907cSAndroid Build Coastguard Worker                 ports++;
177*4d7e907cSAndroid Build Coastguard Worker             }
178*4d7e907cSAndroid Build Coastguard Worker         }
179*4d7e907cSAndroid Build Coastguard Worker 
180*4d7e907cSAndroid Build Coastguard Worker         if (ports == 0) {
181*4d7e907cSAndroid Build Coastguard Worker             closedir(dp);
182*4d7e907cSAndroid Build Coastguard Worker             return Status::SUCCESS;
183*4d7e907cSAndroid Build Coastguard Worker         }
184*4d7e907cSAndroid Build Coastguard Worker 
185*4d7e907cSAndroid Build Coastguard Worker         names.resize(ports);
186*4d7e907cSAndroid Build Coastguard Worker         rewinddir(dp);
187*4d7e907cSAndroid Build Coastguard Worker 
188*4d7e907cSAndroid Build Coastguard Worker         while ((ep = readdir (dp))) {
189*4d7e907cSAndroid Build Coastguard Worker             if (ep->d_type == DT_LNK) {
190*4d7e907cSAndroid Build Coastguard Worker                 /* Check to see if new ports were added since the first pass. */
191*4d7e907cSAndroid Build Coastguard Worker                 if (current >= ports) {
192*4d7e907cSAndroid Build Coastguard Worker                     rewinddir(dp);
193*4d7e907cSAndroid Build Coastguard Worker                     goto rescan;
194*4d7e907cSAndroid Build Coastguard Worker                 }
195*4d7e907cSAndroid Build Coastguard Worker                 names[current++] = ep->d_name;
196*4d7e907cSAndroid Build Coastguard Worker             }
197*4d7e907cSAndroid Build Coastguard Worker         }
198*4d7e907cSAndroid Build Coastguard Worker 
199*4d7e907cSAndroid Build Coastguard Worker         closedir (dp);
200*4d7e907cSAndroid Build Coastguard Worker         return Status::SUCCESS;
201*4d7e907cSAndroid Build Coastguard Worker     }
202*4d7e907cSAndroid Build Coastguard Worker 
203*4d7e907cSAndroid Build Coastguard Worker     ALOGE("Failed to open /sys/class/dual_role_usb");
204*4d7e907cSAndroid Build Coastguard Worker     return Status::ERROR;
205*4d7e907cSAndroid Build Coastguard Worker }
206*4d7e907cSAndroid Build Coastguard Worker 
canSwitchRoleHelper(const std::string portName,PortRoleType type)207*4d7e907cSAndroid Build Coastguard Worker bool canSwitchRoleHelper(const std::string portName, PortRoleType type)  {
208*4d7e907cSAndroid Build Coastguard Worker     std::string filename = appendRoleNodeHelper(portName, type);
209*4d7e907cSAndroid Build Coastguard Worker     std::ofstream file(filename);
210*4d7e907cSAndroid Build Coastguard Worker 
211*4d7e907cSAndroid Build Coastguard Worker     if (file.is_open()) {
212*4d7e907cSAndroid Build Coastguard Worker         file.close();
213*4d7e907cSAndroid Build Coastguard Worker         return true;
214*4d7e907cSAndroid Build Coastguard Worker     }
215*4d7e907cSAndroid Build Coastguard Worker     return false;
216*4d7e907cSAndroid Build Coastguard Worker }
217*4d7e907cSAndroid Build Coastguard Worker 
getPortModeHelper(const std::string portName,PortMode & portMode)218*4d7e907cSAndroid Build Coastguard Worker Status getPortModeHelper(const std::string portName, PortMode& portMode)  {
219*4d7e907cSAndroid Build Coastguard Worker     std::string filename = "/sys/class/dual_role_usb/" +
220*4d7e907cSAndroid Build Coastguard Worker     std::string(portName.c_str()) + "/supported_modes";
221*4d7e907cSAndroid Build Coastguard Worker     std::string modes;
222*4d7e907cSAndroid Build Coastguard Worker 
223*4d7e907cSAndroid Build Coastguard Worker     if (readFile(filename, modes)) {
224*4d7e907cSAndroid Build Coastguard Worker         ALOGE("getSupportedRoles: Failed to open filesystem node");
225*4d7e907cSAndroid Build Coastguard Worker         return Status::ERROR;
226*4d7e907cSAndroid Build Coastguard Worker     }
227*4d7e907cSAndroid Build Coastguard Worker 
228*4d7e907cSAndroid Build Coastguard Worker     if (modes == "ufp dfp")
229*4d7e907cSAndroid Build Coastguard Worker         portMode = PortMode::DRP;
230*4d7e907cSAndroid Build Coastguard Worker     else  if (modes == "ufp")
231*4d7e907cSAndroid Build Coastguard Worker         portMode = PortMode::UFP;
232*4d7e907cSAndroid Build Coastguard Worker     else if  (modes == "dfp")
233*4d7e907cSAndroid Build Coastguard Worker         portMode = PortMode::DFP;
234*4d7e907cSAndroid Build Coastguard Worker     else
235*4d7e907cSAndroid Build Coastguard Worker         return Status::UNRECOGNIZED_ROLE;
236*4d7e907cSAndroid Build Coastguard Worker 
237*4d7e907cSAndroid Build Coastguard Worker     return Status::SUCCESS;
238*4d7e907cSAndroid Build Coastguard Worker }
239*4d7e907cSAndroid Build Coastguard Worker 
getPortStatusHelper(hidl_vec<PortStatus> & currentPortStatus)240*4d7e907cSAndroid Build Coastguard Worker Status getPortStatusHelper (hidl_vec<PortStatus>& currentPortStatus) {
241*4d7e907cSAndroid Build Coastguard Worker     std::vector<std::string> names;
242*4d7e907cSAndroid Build Coastguard Worker     Status result = getTypeCPortNamesHelper(names);
243*4d7e907cSAndroid Build Coastguard Worker 
244*4d7e907cSAndroid Build Coastguard Worker     if (result == Status::SUCCESS) {
245*4d7e907cSAndroid Build Coastguard Worker         currentPortStatus.resize(names.size());
246*4d7e907cSAndroid Build Coastguard Worker         for(std::vector<std::string>::size_type i = 0; i < names.size(); i++) {
247*4d7e907cSAndroid Build Coastguard Worker             ALOGI("%s", names[i].c_str());
248*4d7e907cSAndroid Build Coastguard Worker             currentPortStatus[i].portName = names[i];
249*4d7e907cSAndroid Build Coastguard Worker 
250*4d7e907cSAndroid Build Coastguard Worker             uint32_t currentRole;
251*4d7e907cSAndroid Build Coastguard Worker             if (getCurrentRoleHelper(names[i], PortRoleType::POWER_ROLE,
252*4d7e907cSAndroid Build Coastguard Worker                     currentRole) == Status::SUCCESS) {
253*4d7e907cSAndroid Build Coastguard Worker                 currentPortStatus[i].currentPowerRole =
254*4d7e907cSAndroid Build Coastguard Worker                 static_cast<PortPowerRole> (currentRole);
255*4d7e907cSAndroid Build Coastguard Worker             } else {
256*4d7e907cSAndroid Build Coastguard Worker                 ALOGE("Error while retreiving portNames");
257*4d7e907cSAndroid Build Coastguard Worker                 goto done;
258*4d7e907cSAndroid Build Coastguard Worker             }
259*4d7e907cSAndroid Build Coastguard Worker 
260*4d7e907cSAndroid Build Coastguard Worker             if (getCurrentRoleHelper(names[i],
261*4d7e907cSAndroid Build Coastguard Worker                     PortRoleType::DATA_ROLE, currentRole) == Status::SUCCESS) {
262*4d7e907cSAndroid Build Coastguard Worker                 currentPortStatus[i].currentDataRole =
263*4d7e907cSAndroid Build Coastguard Worker                         static_cast<PortDataRole> (currentRole);
264*4d7e907cSAndroid Build Coastguard Worker             } else {
265*4d7e907cSAndroid Build Coastguard Worker                 ALOGE("Error while retreiving current port role");
266*4d7e907cSAndroid Build Coastguard Worker                 goto done;
267*4d7e907cSAndroid Build Coastguard Worker             }
268*4d7e907cSAndroid Build Coastguard Worker 
269*4d7e907cSAndroid Build Coastguard Worker             if (getCurrentRoleHelper(names[i], PortRoleType::MODE,
270*4d7e907cSAndroid Build Coastguard Worker                     currentRole) == Status::SUCCESS) {
271*4d7e907cSAndroid Build Coastguard Worker                 currentPortStatus[i].currentMode =
272*4d7e907cSAndroid Build Coastguard Worker                     static_cast<PortMode> (currentRole);
273*4d7e907cSAndroid Build Coastguard Worker             } else {
274*4d7e907cSAndroid Build Coastguard Worker                 ALOGE("Error while retreiving current data role");
275*4d7e907cSAndroid Build Coastguard Worker                 goto done;
276*4d7e907cSAndroid Build Coastguard Worker             }
277*4d7e907cSAndroid Build Coastguard Worker 
278*4d7e907cSAndroid Build Coastguard Worker             currentPortStatus[i].canChangeMode =
279*4d7e907cSAndroid Build Coastguard Worker                 canSwitchRoleHelper(names[i], PortRoleType::MODE);
280*4d7e907cSAndroid Build Coastguard Worker             currentPortStatus[i].canChangeDataRole =
281*4d7e907cSAndroid Build Coastguard Worker                 canSwitchRoleHelper(names[i], PortRoleType::DATA_ROLE);
282*4d7e907cSAndroid Build Coastguard Worker             currentPortStatus[i].canChangePowerRole =
283*4d7e907cSAndroid Build Coastguard Worker                 canSwitchRoleHelper(names[i], PortRoleType::POWER_ROLE);
284*4d7e907cSAndroid Build Coastguard Worker 
285*4d7e907cSAndroid Build Coastguard Worker             ALOGI("canChangeMode: %d canChagedata: %d canChangePower:%d",
286*4d7e907cSAndroid Build Coastguard Worker                 currentPortStatus[i].canChangeMode,
287*4d7e907cSAndroid Build Coastguard Worker                 currentPortStatus[i].canChangeDataRole,
288*4d7e907cSAndroid Build Coastguard Worker                 currentPortStatus[i].canChangePowerRole);
289*4d7e907cSAndroid Build Coastguard Worker 
290*4d7e907cSAndroid Build Coastguard Worker             if (getPortModeHelper(names[i], currentPortStatus[i].supportedModes)
291*4d7e907cSAndroid Build Coastguard Worker                   != Status::SUCCESS) {
292*4d7e907cSAndroid Build Coastguard Worker                 ALOGE("Error while retrieving port modes");
293*4d7e907cSAndroid Build Coastguard Worker                 goto done;
294*4d7e907cSAndroid Build Coastguard Worker             }
295*4d7e907cSAndroid Build Coastguard Worker         }
296*4d7e907cSAndroid Build Coastguard Worker         return Status::SUCCESS;
297*4d7e907cSAndroid Build Coastguard Worker     }
298*4d7e907cSAndroid Build Coastguard Worker done:
299*4d7e907cSAndroid Build Coastguard Worker     return Status::ERROR;
300*4d7e907cSAndroid Build Coastguard Worker }
301*4d7e907cSAndroid Build Coastguard Worker 
queryPortStatus()302*4d7e907cSAndroid Build Coastguard Worker Return<void> Usb::queryPortStatus() {
303*4d7e907cSAndroid Build Coastguard Worker     hidl_vec<PortStatus> currentPortStatus;
304*4d7e907cSAndroid Build Coastguard Worker     Status status;
305*4d7e907cSAndroid Build Coastguard Worker 
306*4d7e907cSAndroid Build Coastguard Worker     status = getPortStatusHelper(currentPortStatus);
307*4d7e907cSAndroid Build Coastguard Worker     Return<void> ret = mCallback->notifyPortStatusChange(currentPortStatus,
308*4d7e907cSAndroid Build Coastguard Worker        status);
309*4d7e907cSAndroid Build Coastguard Worker     if (!ret.isOk())
310*4d7e907cSAndroid Build Coastguard Worker         ALOGE("queryPortStatus error %s", ret.description().c_str());
311*4d7e907cSAndroid Build Coastguard Worker 
312*4d7e907cSAndroid Build Coastguard Worker     return Void();
313*4d7e907cSAndroid Build Coastguard Worker }
314*4d7e907cSAndroid Build Coastguard Worker struct data {
315*4d7e907cSAndroid Build Coastguard Worker     int uevent_fd;
316*4d7e907cSAndroid Build Coastguard Worker     android::hardware::usb::V1_0::implementation::Usb *usb;
317*4d7e907cSAndroid Build Coastguard Worker };
318*4d7e907cSAndroid Build Coastguard Worker 
uevent_event(uint32_t,struct data * payload)319*4d7e907cSAndroid Build Coastguard Worker static void uevent_event(uint32_t /*epevents*/, struct data *payload) {
320*4d7e907cSAndroid Build Coastguard Worker     char msg[UEVENT_MSG_LEN + 2];
321*4d7e907cSAndroid Build Coastguard Worker     char *cp;
322*4d7e907cSAndroid Build Coastguard Worker     int n;
323*4d7e907cSAndroid Build Coastguard Worker 
324*4d7e907cSAndroid Build Coastguard Worker     n = uevent_kernel_multicast_recv(payload->uevent_fd, msg, UEVENT_MSG_LEN);
325*4d7e907cSAndroid Build Coastguard Worker     if (n <= 0)
326*4d7e907cSAndroid Build Coastguard Worker         return;
327*4d7e907cSAndroid Build Coastguard Worker     if (n >= UEVENT_MSG_LEN)   /* overflow -- discard */
328*4d7e907cSAndroid Build Coastguard Worker         return;
329*4d7e907cSAndroid Build Coastguard Worker 
330*4d7e907cSAndroid Build Coastguard Worker     msg[n] = '\0';
331*4d7e907cSAndroid Build Coastguard Worker     msg[n + 1] = '\0';
332*4d7e907cSAndroid Build Coastguard Worker     cp = msg;
333*4d7e907cSAndroid Build Coastguard Worker 
334*4d7e907cSAndroid Build Coastguard Worker     while (*cp) {
335*4d7e907cSAndroid Build Coastguard Worker         if (!strcmp(cp, "SUBSYSTEM=dual_role_usb")) {
336*4d7e907cSAndroid Build Coastguard Worker             ALOGE("uevent received %s", cp);
337*4d7e907cSAndroid Build Coastguard Worker             if (payload->usb->mCallback != NULL) {
338*4d7e907cSAndroid Build Coastguard Worker                 hidl_vec<PortStatus> currentPortStatus;
339*4d7e907cSAndroid Build Coastguard Worker                 Status status = getPortStatusHelper(currentPortStatus);
340*4d7e907cSAndroid Build Coastguard Worker                 Return<void> ret =
341*4d7e907cSAndroid Build Coastguard Worker                     payload->usb->mCallback->notifyPortStatusChange(currentPortStatus, status);
342*4d7e907cSAndroid Build Coastguard Worker                 if (!ret.isOk())
343*4d7e907cSAndroid Build Coastguard Worker                     ALOGE("error %s", ret.description().c_str());
344*4d7e907cSAndroid Build Coastguard Worker             }
345*4d7e907cSAndroid Build Coastguard Worker             break;
346*4d7e907cSAndroid Build Coastguard Worker         }
347*4d7e907cSAndroid Build Coastguard Worker         /* advance to after the next \0 */
348*4d7e907cSAndroid Build Coastguard Worker         while (*cp++);
349*4d7e907cSAndroid Build Coastguard Worker     }
350*4d7e907cSAndroid Build Coastguard Worker }
351*4d7e907cSAndroid Build Coastguard Worker 
work(void * param)352*4d7e907cSAndroid Build Coastguard Worker void* work(void* param) {
353*4d7e907cSAndroid Build Coastguard Worker     int epoll_fd, uevent_fd;
354*4d7e907cSAndroid Build Coastguard Worker     struct epoll_event ev;
355*4d7e907cSAndroid Build Coastguard Worker     int nevents = 0;
356*4d7e907cSAndroid Build Coastguard Worker     struct data payload;
357*4d7e907cSAndroid Build Coastguard Worker 
358*4d7e907cSAndroid Build Coastguard Worker     ALOGE("creating thread");
359*4d7e907cSAndroid Build Coastguard Worker 
360*4d7e907cSAndroid Build Coastguard Worker     uevent_fd = uevent_open_socket(64*1024, true);
361*4d7e907cSAndroid Build Coastguard Worker 
362*4d7e907cSAndroid Build Coastguard Worker     if (uevent_fd < 0) {
363*4d7e907cSAndroid Build Coastguard Worker         ALOGE("uevent_init: uevent_open_socket failed\n");
364*4d7e907cSAndroid Build Coastguard Worker         return NULL;
365*4d7e907cSAndroid Build Coastguard Worker     }
366*4d7e907cSAndroid Build Coastguard Worker 
367*4d7e907cSAndroid Build Coastguard Worker     payload.uevent_fd = uevent_fd;
368*4d7e907cSAndroid Build Coastguard Worker     payload.usb = (android::hardware::usb::V1_0::implementation::Usb *)param;
369*4d7e907cSAndroid Build Coastguard Worker 
370*4d7e907cSAndroid Build Coastguard Worker     fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
371*4d7e907cSAndroid Build Coastguard Worker 
372*4d7e907cSAndroid Build Coastguard Worker     ev.events = EPOLLIN;
373*4d7e907cSAndroid Build Coastguard Worker     ev.data.ptr = (void *)uevent_event;
374*4d7e907cSAndroid Build Coastguard Worker 
375*4d7e907cSAndroid Build Coastguard Worker     epoll_fd = epoll_create(64);
376*4d7e907cSAndroid Build Coastguard Worker     if (epoll_fd == -1) {
377*4d7e907cSAndroid Build Coastguard Worker         ALOGE("epoll_create failed; errno=%d", errno);
378*4d7e907cSAndroid Build Coastguard Worker         goto error;
379*4d7e907cSAndroid Build Coastguard Worker     }
380*4d7e907cSAndroid Build Coastguard Worker 
381*4d7e907cSAndroid Build Coastguard Worker     if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, uevent_fd, &ev) == -1) {
382*4d7e907cSAndroid Build Coastguard Worker         ALOGE("epoll_ctl failed; errno=%d", errno);
383*4d7e907cSAndroid Build Coastguard Worker         goto error;
384*4d7e907cSAndroid Build Coastguard Worker     }
385*4d7e907cSAndroid Build Coastguard Worker 
386*4d7e907cSAndroid Build Coastguard Worker     while (!destroyThread) {
387*4d7e907cSAndroid Build Coastguard Worker         struct epoll_event events[64];
388*4d7e907cSAndroid Build Coastguard Worker 
389*4d7e907cSAndroid Build Coastguard Worker         nevents = epoll_wait(epoll_fd, events, 64, -1);
390*4d7e907cSAndroid Build Coastguard Worker         if (nevents == -1) {
391*4d7e907cSAndroid Build Coastguard Worker             if (errno == EINTR)
392*4d7e907cSAndroid Build Coastguard Worker                 continue;
393*4d7e907cSAndroid Build Coastguard Worker             ALOGE("usb epoll_wait failed; errno=%d", errno);
394*4d7e907cSAndroid Build Coastguard Worker             break;
395*4d7e907cSAndroid Build Coastguard Worker         }
396*4d7e907cSAndroid Build Coastguard Worker 
397*4d7e907cSAndroid Build Coastguard Worker         for (int n = 0; n < nevents; ++n) {
398*4d7e907cSAndroid Build Coastguard Worker             if (events[n].data.ptr)
399*4d7e907cSAndroid Build Coastguard Worker                 (*(void (*)(int, struct data *payload))events[n].data.ptr)
400*4d7e907cSAndroid Build Coastguard Worker                     (events[n].events, &payload);
401*4d7e907cSAndroid Build Coastguard Worker         }
402*4d7e907cSAndroid Build Coastguard Worker     }
403*4d7e907cSAndroid Build Coastguard Worker 
404*4d7e907cSAndroid Build Coastguard Worker     ALOGI("exiting worker thread");
405*4d7e907cSAndroid Build Coastguard Worker error:
406*4d7e907cSAndroid Build Coastguard Worker     close(uevent_fd);
407*4d7e907cSAndroid Build Coastguard Worker 
408*4d7e907cSAndroid Build Coastguard Worker     if (epoll_fd >= 0)
409*4d7e907cSAndroid Build Coastguard Worker         close(epoll_fd);
410*4d7e907cSAndroid Build Coastguard Worker 
411*4d7e907cSAndroid Build Coastguard Worker     return NULL;
412*4d7e907cSAndroid Build Coastguard Worker }
413*4d7e907cSAndroid Build Coastguard Worker 
sighandler(int sig)414*4d7e907cSAndroid Build Coastguard Worker void sighandler(int sig)
415*4d7e907cSAndroid Build Coastguard Worker {
416*4d7e907cSAndroid Build Coastguard Worker     if (sig == SIGUSR1) {
417*4d7e907cSAndroid Build Coastguard Worker         destroyThread = true;
418*4d7e907cSAndroid Build Coastguard Worker         ALOGI("destroy set");
419*4d7e907cSAndroid Build Coastguard Worker         return;
420*4d7e907cSAndroid Build Coastguard Worker     }
421*4d7e907cSAndroid Build Coastguard Worker     signal(SIGUSR1, sighandler);
422*4d7e907cSAndroid Build Coastguard Worker }
423*4d7e907cSAndroid Build Coastguard Worker 
setCallback(const sp<IUsbCallback> & callback)424*4d7e907cSAndroid Build Coastguard Worker Return<void> Usb::setCallback(const sp<IUsbCallback>& callback) {
425*4d7e907cSAndroid Build Coastguard Worker 
426*4d7e907cSAndroid Build Coastguard Worker     pthread_mutex_lock(&mLock);
427*4d7e907cSAndroid Build Coastguard Worker     if ((mCallback == NULL && callback == NULL) ||
428*4d7e907cSAndroid Build Coastguard Worker             (mCallback != NULL && callback != NULL)) {
429*4d7e907cSAndroid Build Coastguard Worker         mCallback = callback;
430*4d7e907cSAndroid Build Coastguard Worker         pthread_mutex_unlock(&mLock);
431*4d7e907cSAndroid Build Coastguard Worker         return Void();
432*4d7e907cSAndroid Build Coastguard Worker     }
433*4d7e907cSAndroid Build Coastguard Worker 
434*4d7e907cSAndroid Build Coastguard Worker     mCallback = callback;
435*4d7e907cSAndroid Build Coastguard Worker     ALOGI("registering callback");
436*4d7e907cSAndroid Build Coastguard Worker 
437*4d7e907cSAndroid Build Coastguard Worker     if (mCallback == NULL) {
438*4d7e907cSAndroid Build Coastguard Worker         if  (!pthread_kill(mPoll, SIGUSR1)) {
439*4d7e907cSAndroid Build Coastguard Worker             pthread_join(mPoll, NULL);
440*4d7e907cSAndroid Build Coastguard Worker             ALOGI("pthread destroyed");
441*4d7e907cSAndroid Build Coastguard Worker         }
442*4d7e907cSAndroid Build Coastguard Worker         pthread_mutex_unlock(&mLock);
443*4d7e907cSAndroid Build Coastguard Worker         return Void();
444*4d7e907cSAndroid Build Coastguard Worker     }
445*4d7e907cSAndroid Build Coastguard Worker 
446*4d7e907cSAndroid Build Coastguard Worker     destroyThread = false;
447*4d7e907cSAndroid Build Coastguard Worker     signal(SIGUSR1, sighandler);
448*4d7e907cSAndroid Build Coastguard Worker 
449*4d7e907cSAndroid Build Coastguard Worker     if (pthread_create(&mPoll, NULL, work, this)) {
450*4d7e907cSAndroid Build Coastguard Worker         ALOGE("pthread creation failed %d", errno);
451*4d7e907cSAndroid Build Coastguard Worker         mCallback = NULL;
452*4d7e907cSAndroid Build Coastguard Worker     }
453*4d7e907cSAndroid Build Coastguard Worker     pthread_mutex_unlock(&mLock);
454*4d7e907cSAndroid Build Coastguard Worker     return Void();
455*4d7e907cSAndroid Build Coastguard Worker }
456*4d7e907cSAndroid Build Coastguard Worker 
457*4d7e907cSAndroid Build Coastguard Worker // Protects *usb assignment
458*4d7e907cSAndroid Build Coastguard Worker pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
459*4d7e907cSAndroid Build Coastguard Worker Usb *usb;
460*4d7e907cSAndroid Build Coastguard Worker 
Usb()461*4d7e907cSAndroid Build Coastguard Worker Usb::Usb() {
462*4d7e907cSAndroid Build Coastguard Worker     pthread_mutex_lock(&lock);
463*4d7e907cSAndroid Build Coastguard Worker     // Make this a singleton class
464*4d7e907cSAndroid Build Coastguard Worker     assert(usb == NULL);
465*4d7e907cSAndroid Build Coastguard Worker     usb = this;
466*4d7e907cSAndroid Build Coastguard Worker     pthread_mutex_unlock(&lock);
467*4d7e907cSAndroid Build Coastguard Worker }
468*4d7e907cSAndroid Build Coastguard Worker 
469*4d7e907cSAndroid Build Coastguard Worker }  // namespace implementation
470*4d7e907cSAndroid Build Coastguard Worker }  // namespace V1_0
471*4d7e907cSAndroid Build Coastguard Worker }  // namespace usb
472*4d7e907cSAndroid Build Coastguard Worker }  // namespace hardware
473*4d7e907cSAndroid Build Coastguard Worker }  // namespace android
474