OSDN Git Service

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