1 /*
2  * Copyright (C) Texas Instruments - http://www.ti.com/
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 
17 /**
18 * @file OMXDccDataSave.cpp
19 *
20 * This file contains functionality for handling DCC data save
21 *
22 */
23 
24 #include "CameraHal.h"
25 #include "OMXCameraAdapter.h"
26 
27 
28 namespace Ti {
29 namespace Camera {
30 
initDccFileDataSave(OMX_HANDLETYPE * omxHandle,int portIndex)31 status_t OMXCameraAdapter::initDccFileDataSave(OMX_HANDLETYPE* omxHandle, int portIndex)
32 {
33     OMX_CONFIG_EXTRADATATYPE extraDataControl;
34     status_t ret = NO_ERROR;
35     OMX_ERRORTYPE eError = OMX_ErrorNone;
36 
37     LOG_FUNCTION_NAME;
38 
39     OMX_INIT_STRUCT_PTR (&extraDataControl, OMX_CONFIG_EXTRADATATYPE);
40     extraDataControl.nPortIndex = portIndex;
41     extraDataControl.eExtraDataType = OMX_TI_DccData;
42     extraDataControl.bEnable = OMX_TRUE;
43 
44     eError =  OMX_SetConfig(*omxHandle,
45                         ( OMX_INDEXTYPE ) OMX_IndexConfigOtherExtraDataControl,
46                         &extraDataControl);
47 
48     if ( OMX_ErrorNone != eError )
49         {
50         CAMHAL_LOGEB("Error while configuring dcc data overwrite extra data 0x%x",
51                     eError);
52 
53         ret =  NO_INIT;
54         }
55 
56     if (mDccData.pData) {
57         free(mDccData.pData);
58         mDccData.pData = NULL;
59     }
60     LOG_FUNCTION_NAME_EXIT;
61 
62     return ret;
63 }
64 
sniffDccFileDataSave(OMX_BUFFERHEADERTYPE * pBuffHeader)65 status_t OMXCameraAdapter::sniffDccFileDataSave(OMX_BUFFERHEADERTYPE* pBuffHeader)
66 {
67     OMX_OTHER_EXTRADATATYPE *extraData;
68     OMX_TI_DCCDATATYPE* dccData;
69     status_t ret = NO_ERROR;
70 
71     LOG_FUNCTION_NAME;
72 
73     android::AutoMutex lock(mDccDataLock);
74 
75     if ( NULL == pBuffHeader ) {
76         CAMHAL_LOGEA("Invalid Buffer header");
77         LOG_FUNCTION_NAME_EXIT;
78         return -EINVAL;
79     }
80 
81     extraData = getExtradata(pBuffHeader->pPlatformPrivate,
82                              (OMX_EXTRADATATYPE)OMX_TI_DccData);
83 
84     if ( NULL != extraData ) {
85         CAMHAL_LOGVB("Size = %d, sizeof = %d, eType = 0x%x, nDataSize= %d, nPortIndex = 0x%x, nVersion = 0x%x",
86                      extraData->nSize,
87                      sizeof(OMX_OTHER_EXTRADATATYPE),
88                      extraData->eType,
89                      extraData->nDataSize,
90                      extraData->nPortIndex,
91                      extraData->nVersion);
92     } else {
93         CAMHAL_LOGVA("Invalid OMX_TI_DCCDATATYPE");
94         LOG_FUNCTION_NAME_EXIT;
95         return NO_ERROR;
96     }
97 
98     dccData = ( OMX_TI_DCCDATATYPE * ) extraData->data;
99 
100     if (NULL == dccData) {
101         CAMHAL_LOGVA("OMX_TI_DCCDATATYPE is not found in extra data");
102         LOG_FUNCTION_NAME_EXIT;
103         return NO_ERROR;
104     }
105 
106     if (mDccData.pData) {
107         free(mDccData.pData);
108     }
109 
110     memcpy(&mDccData, dccData, sizeof(mDccData));
111 
112     int dccDataSize = (int)dccData->nSize - (int)(&(((OMX_TI_DCCDATATYPE*)0)->pData));
113 
114     mDccData.pData = (OMX_PTR)malloc(dccDataSize);
115 
116     if (NULL == mDccData.pData) {
117         CAMHAL_LOGVA("not enough memory for DCC data");
118         LOG_FUNCTION_NAME_EXIT;
119         return NO_ERROR;
120     }
121 
122     memcpy(mDccData.pData, &(dccData->pData), dccDataSize);
123 
124     LOG_FUNCTION_NAME_EXIT;
125 
126     return ret;
127 }
128 
129 // Recursively searches given directory contents for the correct DCC file.
130 // The directory must be opened and its stream pointer + path passed
131 // as arguments. As this function is called recursively, to avoid excessive
132 // stack usage the path param is reused -> this MUST be char array with
133 // enough length!!! (260 should suffice). Path must end with "/".
134 // The directory must also be closed in the caller function.
135 // If the correct camera DCC file is found (based on the OMX measurement data)
136 // its file stream pointer is returned. NULL is returned otherwise
parseDCCsubDir(DIR * pDir,char * path)137 FILE * OMXCameraAdapter::parseDCCsubDir(DIR *pDir, char *path)
138 {
139     FILE *pFile;
140     DIR *pSubDir;
141     struct dirent *dirEntry;
142     int initialPathLength = strlen(path);
143 
144     LOG_FUNCTION_NAME;
145 
146     /* check each directory entry */
147     while ((dirEntry = readdir(pDir)) != NULL)
148     {
149         if (dirEntry->d_name[0] == '.')
150             continue;
151 
152         strcat(path, dirEntry->d_name);
153         // dirEntry might be sub directory -> check it
154         pSubDir = opendir(path);
155         if (pSubDir) {
156             // dirEntry is sub directory -> parse it
157             strcat(path, "/");
158             pFile = parseDCCsubDir(pSubDir, path);
159             closedir(pSubDir);
160             if (pFile) {
161                 // the correct DCC file found!
162                 LOG_FUNCTION_NAME_EXIT;
163                 return pFile;
164             }
165         } else {
166             // dirEntry is file -> open it
167             pFile = fopen(path, "rb");
168             if (pFile) {
169                 // now check if this is the correct DCC file for that camera
170                 OMX_U32 dccFileIDword;
171                 OMX_U32 *dccFileDesc = (OMX_U32 *) &mDccData.nCameraModuleId;
172                 int i;
173 
174                 // DCC file ID is 3 4-byte words
175                 for (i = 0; i < 3; i++) {
176                     if (fread(&dccFileIDword, sizeof(OMX_U32), 1, pFile) != 1) {
177                         // file too short
178                         break;
179                     }
180                     if (dccFileIDword != dccFileDesc[i]) {
181                         // DCC file ID word i does not match
182                         break;
183                     }
184                 }
185 
186                 fclose(pFile);
187                 if (i == 3) {
188                     // the correct DCC file found!
189                     CAMHAL_LOGDB("DCC file to be updated: %s", path);
190                     // reopen it for modification
191                     pFile = fopen(path, "rb+");
192                     if (!pFile)
193                         CAMHAL_LOGEB("ERROR: DCC file %s failed to open for modification", path);
194                     LOG_FUNCTION_NAME_EXIT;
195                     return pFile;
196                 }
197             } else {
198                 CAMHAL_LOGEB("ERROR: Failed to open file %s for reading", path);
199             }
200         }
201         // restore original path
202         path[initialPathLength] = '\0';
203     }
204 
205     LOG_FUNCTION_NAME_EXIT;
206 
207     // DCC file not found in this directory tree
208     return NULL;
209 }
210 
211 // Finds the DCC file corresponding to the current camera based on the
212 // OMX measurement data, opens it and returns the file stream pointer
213 // (NULL on error or if file not found).
214 // The folder string dccFolderPath must end with "/"
fopenCameraDCC(const char * dccFolderPath)215 FILE * OMXCameraAdapter::fopenCameraDCC(const char *dccFolderPath)
216 {
217     FILE *pFile;
218     DIR *pDir;
219     char dccPath[260];
220 
221     LOG_FUNCTION_NAME;
222 
223     strcpy(dccPath, dccFolderPath);
224 
225     pDir = opendir(dccPath);
226     if (!pDir) {
227         CAMHAL_LOGEB("ERROR: Opening DCC directory %s failed", dccPath);
228         LOG_FUNCTION_NAME_EXIT;
229         return NULL;
230     }
231 
232     pFile = parseDCCsubDir(pDir, dccPath);
233     closedir(pDir);
234     if (pFile) {
235         CAMHAL_LOGDB("DCC file %s opened for modification", dccPath);
236     }
237 
238     LOG_FUNCTION_NAME_EXIT;
239 
240     return pFile;
241 }
242 
243 // Positions the DCC file stream pointer to the correct offset within the
244 // correct usecase based on the OMX mesurement data. Returns 0 on success
fseekDCCuseCasePos(FILE * pFile)245 status_t OMXCameraAdapter::fseekDCCuseCasePos(FILE *pFile)
246 {
247     OMX_U32 dccNumUseCases = 0;
248     OMX_U32 dccUseCaseData[3];
249     OMX_U32 i;
250 
251     LOG_FUNCTION_NAME;
252 
253     // position the file pointer to the DCC use cases section
254     if (fseek(pFile, 80, SEEK_SET)) {
255         CAMHAL_LOGEA("ERROR: Unexpected end of DCC file");
256         LOG_FUNCTION_NAME_EXIT;
257         return -EINVAL;
258     }
259 
260     if (fread(&dccNumUseCases, sizeof(OMX_U32), 1, pFile) != 1 ||
261         dccNumUseCases == 0) {
262         CAMHAL_LOGEA("ERROR: DCC file contains 0 use cases");
263         LOG_FUNCTION_NAME_EXIT;
264         return -EINVAL;
265     }
266 
267     for (i = 0; i < dccNumUseCases; i++) {
268         if (fread(dccUseCaseData, sizeof(OMX_U32), 3, pFile) != 3) {
269             CAMHAL_LOGEA("ERROR: Unexpected end of DCC file");
270             LOG_FUNCTION_NAME_EXIT;
271             return -EINVAL;
272         }
273 
274         if (dccUseCaseData[0] == mDccData.nUseCaseId) {
275             // DCC use case match!
276             break;
277         }
278     }
279 
280     if (i == dccNumUseCases) {
281         CAMHAL_LOGEB("ERROR: Use case ID %lu not found in DCC file", mDccData.nUseCaseId);
282         LOG_FUNCTION_NAME_EXIT;
283         return -EINVAL;
284     }
285 
286     // dccUseCaseData[1] is the offset to the beginning of the actual use case
287     // from the beginning of the file
288     // mDccData.nOffset is the offset within the actual use case (from the
289     // beginning of the use case to the data to be modified)
290 
291     if (fseek(pFile,dccUseCaseData[1] + mDccData.nOffset, SEEK_SET ))
292     {
293         CAMHAL_LOGEA("ERROR: Error setting the correct offset");
294         LOG_FUNCTION_NAME_EXIT;
295         return -EINVAL;
296     }
297 
298     LOG_FUNCTION_NAME_EXIT;
299 
300     return NO_ERROR;
301 }
302 
saveDccFileDataSave()303 status_t OMXCameraAdapter::saveDccFileDataSave()
304 {
305     status_t ret = NO_ERROR;
306 
307     LOG_FUNCTION_NAME;
308 
309     android::AutoMutex lock(mDccDataLock);
310 
311     if (mDccData.pData)
312         {
313         FILE *fd = fopenCameraDCC(DCC_PATH);
314 
315         if (fd)
316             {
317             if (!fseekDCCuseCasePos(fd))
318                 {
319                 int dccDataSize = (int)mDccData.nSize - (int)(&(((OMX_TI_DCCDATATYPE*)0)->pData));
320 
321                 if (fwrite(mDccData.pData, dccDataSize, 1, fd) != 1)
322                     {
323                     CAMHAL_LOGEA("ERROR: Writing to DCC file failed");
324                     }
325                 else
326                     {
327                     CAMHAL_LOGDA("DCC file successfully updated");
328                     }
329                 }
330             fclose(fd);
331             }
332         else
333             {
334             CAMHAL_LOGEA("ERROR: Correct DCC file not found or failed to open for modification");
335             }
336         }
337 
338     LOG_FUNCTION_NAME_EXIT;
339 
340     return ret;
341 }
342 
closeDccFileDataSave()343 status_t OMXCameraAdapter::closeDccFileDataSave()
344 {
345     status_t ret = NO_ERROR;
346 
347     LOG_FUNCTION_NAME;
348 
349     android::AutoMutex lock(mDccDataLock);
350 
351     if (mDccData.pData) {
352         free(mDccData.pData);
353         mDccData.pData = NULL;
354     }
355     LOG_FUNCTION_NAME_EXIT;
356 
357     return ret;
358 }
359 
360 } // namespace Camera
361 } // namespace Ti
362