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 ¤tRole) {
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