OSDN Git Service

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