OSDN Git Service

libsensors: retry more and deal with sensor hub quirk
[android-x86/hardware-intel-libsensors.git] / common / libsensors / SensorIIODev.cpp
1 /*
2  * Copyright (C) 2010-2012 Intel Corporation
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 #include <dirent.h>
17 #include <fcntl.h>
18 #include <cutils/log.h>
19 #include "SensorIIODev.h"
20 #include "Helpers.h"
21
22 static const std::string IIO_DIR = "/sys/bus/iio/devices";
23 static const int DEF_BUFFER_LEN = 2;
24 static const int DEF_HYST_VALUE = 0;
25
26 SensorIIODev::SensorIIODev(const std::string& dev_name, const std::string& units,
27                            const std::string& exponent,
28                            const std::string& channel_prefix, int retry_cnt)
29              : SensorBase(""),
30                initialized(false),
31                unit_expo_str(exponent),
32                unit_str(units),
33                device_name(dev_name),
34                channel_prefix_str(channel_prefix),
35                unit_expo_value(0),
36                units_value(0),
37                retry_count(retry_cnt),
38                raw_buffer(NULL)
39 {
40
41     ALOGV("%s", __func__);
42 }
43
44 SensorIIODev::SensorIIODev(const std::string& dev_name, const std::string& units,
45                            const std::string& exponent,
46                            const std::string& channel_prefix)
47              : SensorBase(""),
48                initialized(false),
49                unit_expo_str(exponent),
50                unit_str(units),
51                device_name(dev_name),
52                channel_prefix_str(channel_prefix),
53                unit_expo_value(0),
54                units_value(0),
55                retry_count(1),
56                raw_buffer(NULL)
57 {
58
59     ALOGV("%s", __func__);
60 }
61
62 int SensorIIODev::discover()
63 {
64     int cnt;
65     int status;
66     int ret;
67
68     ALOGD(">>%s discover", __func__);
69     for (cnt = 0; cnt < retry_count; cnt++) {
70         status = ParseIIODirectory(device_name);
71         if (status >= 0){
72             std::stringstream filename;
73             initialized = true;
74             filename << "/dev/iio:device" << device_number;
75             mDevPath = filename.str();
76             ALOGV("mDevPath %s", mDevPath.c_str());
77             ret = 0;
78             break;
79         }
80         else{
81             ALOGE("Sensor IIO Init failed, retry left:%d\n", retry_count-cnt);
82             mDevPath = "";
83             ret = -1;
84         }
85         // Device not enumerated yet, wait and retry
86         sleep(1);
87     }
88     return ret;
89 }
90
91 int SensorIIODev::AllocateRxBuffer()
92 {
93     ALOGV(">>%s Allocate:%d", __func__, datum_size * buffer_len);
94     raw_buffer = new unsigned char[datum_size * buffer_len];
95     if (!raw_buffer) {
96         ALOGE("AllocateRxBuffer: Failed\n");
97         return -ENOMEM;
98     }
99     return 0;
100 }
101
102 int SensorIIODev::FreeRxBuffer()
103 {
104     ALOGV(">>%s", __func__);
105     delete []raw_buffer;
106     raw_buffer = NULL;
107     return 0;
108 }
109
110 int SensorIIODev::enable(int enabled)
111 {
112     int ret =0;
113
114     ALOGD(">>%s enabled:%d", __func__, enabled);
115
116     if (mEnabled == enabled) {
117         return 0;
118     }
119     if (enabled){
120         // QUIRK: some sensor hubs need to be turned on and off and on
121         // before sending any information. So we turn it on and off first
122         // before enabling again later in this function.
123         EnableBuffer(1);
124         EnableBuffer(0);
125
126         if (ReadHIDExponentValue(&unit_expo_value) < 0)
127             goto err_ret;
128         if (ReadHIDMeasurmentUnit(&units_value) < 0)
129             goto err_ret;
130         if (SetDataReadyTrigger(GetDeviceNumber(), true) < 0)
131             goto err_ret;
132         if (EnableBuffer(1) < 0)
133             goto err_ret;
134         if (DeviceActivate(GetDeviceNumber(), 1) < 0)
135             goto err_ret;
136         if (DeviceSetSensitivity(GetDeviceNumber(), DEF_HYST_VALUE) < 0)
137             goto err_ret;
138         if (AllocateRxBuffer() < 0)
139             goto err_ret;
140         mEnabled = enabled;
141     }
142     else{
143         mEnabled = enabled;
144         if (SetDataReadyTrigger(GetDeviceNumber(), false) < 0)
145             goto err_ret;
146         if (EnableBuffer(0) < 0)
147             goto err_ret;
148         if (DeviceActivate(GetDeviceNumber(), 0) < 0)
149             goto err_ret;
150         if (DeviceSetSensitivity(GetDeviceNumber(), 0))
151             goto err_ret;
152         if (FreeRxBuffer() < 0)
153             goto err_ret;
154         mDevPath = "";
155     }
156     return 0;
157
158 err_ret:
159     ALOGE("SesnorIIO: Enable failed\n");
160     return -1;
161 }
162
163 int SensorIIODev::setDelay(int64_t delay_ns){
164     int ms = nsToMs(delay_ns);
165     int r;
166
167     ALOGV(">>%s %ld", __func__, delay_ns);
168     if (IsDeviceInitialized() == false){
169         ALOGE("Device was not initialized \n");
170         return  -EFAULT;
171     }
172     if (ms){
173         if ((r = SetSampleDelay(GetDeviceNumber(), ms)) < 0)
174             return r;
175     }
176     ALOGV("<<%s", __func__);
177     return 0;
178 }
179
180 int SensorIIODev::setInitialState(){
181     mHasPendingEvent = false;
182     return 0;
183 }
184
185 long SensorIIODev::GetUnitValue()
186 {
187     return units_value;
188 }
189
190 long SensorIIODev::GetExponentValue()
191 {
192     return unit_expo_value;
193 }
194
195 bool SensorIIODev::IsDeviceInitialized(){
196     return initialized;
197 }
198
199 int SensorIIODev::GetDeviceNumber(){
200     return device_number;
201 }
202
203 int SensorIIODev::GetDir(const std::string& dir, std::vector < std::string >& files){
204     DIR *dp;
205     struct dirent *dirp;
206
207     if ((dp = opendir(dir.c_str())) == NULL){
208         ALOGE("Error opening directory %s\n", (char*)dir.c_str());
209         return errno;
210     }
211     while ((dirp = readdir(dp)) != NULL){
212         files.push_back(std::string(dirp->d_name));
213     }
214     closedir(dp);
215     return 0;
216 }
217
218 void SensorIIODev::ListFiles(const std::string& dir){
219     std::vector < std::string > files = std::vector < std::string > ();
220
221     GetDir(dir, files);
222
223     for (unsigned int i = 0; i < files.size(); i++){
224         ALOGV("File List.. %s\n", (char*)files[i].c_str());
225     }
226 }
227
228 // This function returns a device number for IIO device
229 // For example if the device is "iio:device1", this will return 1
230 int SensorIIODev::FindDeviceNumberFromName(const std::string& name, const std::string&
231     prefix){
232     int dev_number;
233     std::vector < std::string > files = std::vector < std::string > ();
234     std::string device_name;
235
236     GetDir(std::string(IIO_DIR), files);
237
238     for (unsigned int i = 0; i < files.size(); i++){
239         std::stringstream ss;
240         if ((files[i] == ".") || (files[i] == "..") || files[i].length() <=
241             prefix.length())
242             continue;
243
244         if (files[i].compare(0, prefix.length(), prefix) == 0){
245             sscanf(files[i].c_str() + prefix.length(), "%d", &dev_number);
246         }
247         ss << IIO_DIR << "/" << prefix << dev_number;
248         std::ifstream ifs(ss.str().c_str(), std::ifstream::in);
249         if (!ifs.good()){
250             dev_number =  -1;
251             ifs.close();
252             continue;
253         }
254         ifs.close();
255
256         std::ifstream ifn((ss.str() + "/" + "name").c_str(), std::ifstream::in);
257
258         if (!ifn.good()){
259             dev_number =  -1;
260             ifn.close();
261             continue;
262         }
263         std::getline(ifn, device_name);
264         if (name.compare(device_name) == 0){
265             ALOGV("matched %s\n", device_name.c_str());
266             ifn.close();
267             return dev_number;
268         }
269         ifn.close();
270
271     }
272     return  -EFAULT;
273 }
274
275 // Setup Trigger
276 int SensorIIODev::SetUpTrigger(int dev_num){
277     std::stringstream trigger_name;
278     int trigger_num;
279
280     trigger_name << device_name << "-dev" << dev_num;
281     if (trigger_name.str().length()){
282         ALOGV("trigger_name %s\n", (char*)trigger_name.str().c_str());
283         trigger_num = FindDeviceNumberFromName(trigger_name.str(), "trigger");
284         if (trigger_num < 0){
285             ALOGE("Failed to find trigger\n");
286             return  -EFAULT;
287         }
288     }
289     else{
290         ALOGE("trigger_name not found \n");
291         return  -EFAULT;
292     }
293     return 0;
294 }
295
296 // Setup buffer length in terms of datum size
297 int SensorIIODev::SetUpBufferLen(int len){
298     std::stringstream filename;
299     std::stringstream len_str;
300
301     ALOGV("%s: len:%d", __func__, len);
302
303     filename << buffer_dir_name.str() << "/" << "length";
304
305     PathOps path_ops;
306     len_str << len;
307     int ret = path_ops.write(filename.str(), len_str.str());
308     if (ret < 0) {
309         ALOGE("Write Error %s", filename.str().c_str());
310         return ret;
311     }
312     buffer_len = len;
313     return 0;
314 }
315
316 // Enable buffer
317 int SensorIIODev::EnableBuffer(int status){
318     std::stringstream filename;
319     std::stringstream status_str;
320
321     ALOGV("%s: len:%d", __func__, status);
322
323     filename << buffer_dir_name.str() << "/" << "enable";
324     PathOps path_ops;
325     status_str << status;
326     int ret = path_ops.write(filename.str(), status_str.str());
327     if (ret < 0) {
328         ALOGE("Write Error %s", filename.str().c_str());
329         return ret;
330     }
331     enable_buffer = status;
332     return 0;
333 }
334
335 int SensorIIODev::EnableChannels(){
336     int ret = 0;
337     int count;
338     int counter = 0;
339     std::string dir = std::string(IIO_DIR);
340     std::vector < std::string > files = std::vector < std::string > ();
341     const std::string FORMAT_SCAN_ELEMENTS_DIR = "/scan_elements";
342     unsigned char signchar, bits_used, total_bits, shift, unused;
343     SensorIIOChannel iio_channel;
344
345     ALOGV(">>%s", __func__);
346     scan_el_dir.str(std::string());
347     scan_el_dir << dev_device_name.str() << FORMAT_SCAN_ELEMENTS_DIR;
348     GetDir(scan_el_dir.str(), files);
349
350     for (unsigned int i = 0; i < files.size(); i++){
351         int len = files[i].length();
352         if (len > 3 && files[i].compare(len - 3, 3, "_en") == 0){
353             std::stringstream filename, file_type;
354             PathOps path_ops;
355
356             filename << scan_el_dir.str() << "/" << files[i];
357             ret = path_ops.write(filename.str(), "1");
358             if (ret < 0)
359               ALOGE("Channel Enable Error %s:%d", filename.str().c_str(), ret);
360         }
361     }
362     return ret;
363 }
364
365 int SensorIIODev::BuildChannelList(){
366     int ret;
367     int count;
368     int counter = 0;
369     std::string dir = std::string(IIO_DIR);
370     std::vector < std::string > files = std::vector < std::string > ();
371     const std::string FORMAT_SCAN_ELEMENTS_DIR = "/scan_elements";
372     unsigned char signchar, bits_used, total_bits, shift, unused;
373     SensorIIOChannel iio_channel;
374     std::string type_name;
375
376     ALOGV(">>%s", __func__);
377     scan_el_dir.str(std::string());
378     scan_el_dir << dev_device_name.str() << FORMAT_SCAN_ELEMENTS_DIR;
379     GetDir(scan_el_dir.str(), files);
380
381     // File ending with _en will specify a channel
382     // it contains the count. If we add all these count
383     // those many channels present
384     for (unsigned int i = 0; i < files.size(); i++){
385         int len = files[i].length();
386         // At the least the length should be more than 3 for "_en"
387         if (len > 3 && files[i].compare(len - 3, 3, "_en") == 0){
388             std::stringstream filename, file_type;
389             filename << scan_el_dir.str() << "/" << files[i];
390             std::ifstream ifs(filename.str().c_str(), std::ifstream::in);
391
392             if (!ifs.good()){
393                 ifs.close();
394                 continue;
395             }
396             count = ifs.get() - '0';
397             if (count == 1)
398                 counter++;
399             ifs.close();
400
401             iio_channel.enabled = 1;
402             iio_channel.scale = 1.0;
403             iio_channel.offset = 0;
404
405             iio_channel.name = files[i].substr(0, files[i].length() - 3);
406
407             ALOGV("IIO channel name:%s\n", (char*)iio_channel.name.c_str());
408             file_type << scan_el_dir.str() << "/" << iio_channel.name <<
409                 "_type";
410
411             std::ifstream its(file_type.str().c_str(), std::ifstream::in);
412             if (!its.good()){
413                 its.close();
414                 continue;
415             }
416             std::getline(its, type_name);
417             sscanf(type_name.c_str(), "%c%c%c%c%u/%u>>%u", (unsigned char*) &unused,
418                 (unsigned char*) &unused, (unsigned char*) &unused, (unsigned
419                 char*) &signchar, (unsigned int*) &bits_used, (unsigned int*)
420                 &total_bits, (unsigned int*) &shift);
421
422             its.close();
423             // Buggy sscanf on some platforms
424             if (total_bits == 0 || bits_used == 0){
425                 if (!strcmp(type_name.c_str(), "le:s16/32")){
426                     total_bits = 32;
427                     bits_used = 16;
428                 }
429                 else if (!strcmp(type_name.c_str(), "le:s16/16")){
430                     total_bits = 16;
431                     bits_used = 16;
432                 }
433                 else{
434                     total_bits = 32;
435                     bits_used = 16;
436                 }
437             }
438
439             iio_channel.bytes = total_bits / 8;
440             iio_channel.real_bytes = bits_used / 8;
441             iio_channel.shift = shift;
442             iio_channel.is_signed = signchar;
443
444             // Add to list
445             info_array.push_back(iio_channel);
446         }
447     }
448     ALOGV("<<%s", __func__);
449     return counter;
450 }
451
452 int SensorIIODev::GetSizeFromChannels(){
453     int size = 0;
454     for (unsigned int i = 0; i < info_array.size(); i++){
455         SensorIIOChannel channel = info_array[i];
456         size += channel.bytes;
457     }
458     ALOGD("%s:%d:%d", __func__, info_array.size(), size);
459     return size;
460 }
461
462 int SensorIIODev::GetChannelBytesUsedSize(unsigned int channel_no){
463     if (channel_no < info_array.size()){
464         SensorIIOChannel channel = info_array[channel_no];
465         return channel.real_bytes;
466     }
467     else
468         return 0;
469 }
470
471 int SensorIIODev::ParseIIODirectory(const std::string& name){
472     int dev_num;
473     int ret;
474     int size;
475
476     ALOGV(">>%s", __func__);
477
478     dev_device_name.str(std::string());
479     buffer_dir_name.str(std::string());
480
481     device_number = dev_num = FindDeviceNumberFromName(name, "iio:device");
482     if (dev_num < 0){
483         ALOGE("Failed to  find device %s\n", (char*)name.c_str());
484         return  -EFAULT;
485     }
486
487     // Construct device directory Eg. /sys/devices/iio:device0
488     dev_device_name << IIO_DIR << "/" << "iio:device" << dev_num;
489
490     // Construct device directory Eg. /sys/devices/iio:device0:buffer0
491     buffer_dir_name << dev_device_name.str() << "/" << "buffer";
492
493     // Setup Trigger
494     ret = SetUpTrigger(dev_num);
495     if (ret < 0){
496         ALOGE("ParseIIODirectory Failed due to Trigger\n");
497         return  -EFAULT;
498     }
499
500     // Setup buffer len. This is in the datum units, not an absolute number
501     SetUpBufferLen(DEF_BUFFER_LEN);
502
503     // Set up channel masks
504     ret = EnableChannels();
505     if (ret < 0){
506         ALOGE("ParseIIODirectory Failed due Enable Channels failed\n");
507         if (ret == -EACCES) {
508             // EACCES means the nodes do not have current owner.
509             // Need to retry, or else sensors won't power on.
510             // Other errors can be ignored, as these nodes are
511             // set once, and will return error when set again.
512             return ret;
513         }
514     }
515
516     // Parse the channels and build a list
517     ret = BuildChannelList();
518     if (ret < 0){
519         ALOGE("ParseIIODirectory Failed due BuildChannelList\n");
520         return  -EFAULT;
521     }
522
523     datum_size = GetSizeFromChannels();
524     ALOGV("Datum Size %d", datum_size);
525     ALOGV("<<%s", __func__);
526     return 0;
527 }
528
529 // Set Data Ready
530 int SensorIIODev::SetDataReadyTrigger(int dev_num, bool status){
531     std::stringstream filename;
532     std::stringstream trigger_name;
533     int trigger_num;
534
535     ALOGV("%s: status:%d", __func__, status);
536
537     filename << dev_device_name.str() << "/trigger/current_trigger";
538     trigger_name << device_name << "-dev" << dev_num;
539
540     PathOps path_ops;
541     int ret;
542     if (status)
543         ret = path_ops.write(filename.str(), trigger_name.str());
544     else
545         ret = path_ops.write(filename.str(), " ");
546     if (ret < 0) {
547         ALOGE("Write Error %s:%d", filename.str().c_str(), ret);
548         // Ignore error, as this may be due to
549         // Trigger was active during resume
550     }
551     return 0;
552 }
553
554 // Activate device
555 int SensorIIODev::DeviceActivate(int dev_num, int state){
556     std::stringstream filename;
557     std::stringstream activate_str;
558
559     ALOGV("%s: Device Activate:%d", __func__, rate);
560     return 0;
561 }
562
563 // Set sensitivity in absolute terms
564 int SensorIIODev::DeviceSetSensitivity(int dev_num, int value){
565     std::stringstream filename;
566     std::stringstream sensitivity_str;
567
568     ALOGV("%s: Sensitivity :%d", __func__, value);
569
570     filename << IIO_DIR << "/" << "iio:device" << dev_num << "/" << channel_prefix_str << "hysteresis";
571
572     PathOps path_ops;
573     sensitivity_str << value;
574     int ret = path_ops.write(filename.str(), sensitivity_str.str());
575     if (ret < 0) {
576         ALOGE("Write Error %s", filename.str().c_str());
577         // Don't bail out as this  field may be absent
578     }
579     return 0;
580 }
581
582 // Set the sample period delay: units ms
583 int SensorIIODev::SetSampleDelay(int dev_num, int period){
584     std::stringstream filename;
585     std::stringstream sample_rate_str;
586
587     ALOGV("%s: sample_rate:%d", __func__, rate);
588
589     filename << IIO_DIR << "/" << "iio:device" << dev_num << "/" << channel_prefix_str << "sampling_frequency";
590     if (period <= 0) {
591         ALOGE("%s: Invalid_rate:%d", __func__, period);
592     }
593     PathOps path_ops;
594     sample_rate_str << 1000/period;
595     int ret = path_ops.write(filename.str(), sample_rate_str.str());
596     if (ret < 0) {
597         ALOGE("Write Error %s", filename.str().c_str());
598         // Don't bail out as this  field may be absent
599     }
600     return 0;
601 }
602
603 int SensorIIODev::readEvents(sensors_event_t *data, int count){
604     ssize_t read_size;
605     int numEventReceived;
606
607     if (count < 1)
608         return  - EINVAL;
609
610     if (mFd < 0)
611         return  - EBADF;
612
613     if (!raw_buffer)
614         return - EAGAIN;
615
616     if (mHasPendingEvent){
617         mHasPendingEvent = false;
618         mPendingEvent.timestamp = getTimestamp();
619         *data = mPendingEvent;
620         return 1;
621     }
622     read_size = read(mFd, raw_buffer, datum_size * buffer_len);
623     numEventReceived = 0;
624     if (processEvent(raw_buffer, datum_size) >= 0){
625         mPendingEvent.timestamp = getTimestamp();
626         mPendingEvent.timestamp = getTimestamp();
627         *data = mPendingEvent;
628         numEventReceived++;
629     }
630     return numEventReceived;
631 }
632
633 int SensorIIODev::ReadHIDMeasurmentUnit(long *unit){
634     std::stringstream filename;
635     int size;
636     std::string long_str;
637
638     filename << IIO_DIR << "/" << "iio:device" << device_number << "/" << unit_str;
639
640     std::ifstream its(filename.str().c_str(), std::ifstream::in);
641     if (!its.good()){
642         ALOGE("%s: Can't Open :%s",
643                 __func__, filename.str().c_str());
644         its.close();
645         return -EINVAL;
646     }
647     std::getline(its, long_str);
648     its.close();
649
650     if (long_str.length() > 0){
651         *unit = atol(long_str.c_str());
652         return 0;
653     }
654     ALOGE("ReadHIDMeasurmentUnit failed");
655     return  -EINVAL;
656 }
657
658 int SensorIIODev::ReadHIDExponentValue(long *exponent){
659     std::stringstream filename;
660     int size;
661     std::string long_str;
662
663     filename << IIO_DIR << "/" << "iio:device" << device_number << "/" << unit_expo_str;
664
665     std::ifstream its(filename.str().c_str(), std::ifstream::in);
666     if (!its.good()){
667         ALOGE("%s: Can't Open :%s",
668                __func__, filename.str().c_str());
669         its.close();
670         return -EINVAL;
671     }
672     std::getline(its, long_str);
673     its.close();
674
675     if (long_str.length() > 0){
676         *exponent = atol(long_str.c_str());
677         return 0;
678     }
679     ALOGE("ReadHIDExponentValue failed");
680     return  -EINVAL;
681 }