Added initialization of camera. This should prevent breaking of camera
[flashlight-appl] / src / flashlight_lib.c
1 /*
2  *  Flashlight applet (widget) for Maemo.
3  *  Copyright (C) 2009 Roman Moravcik
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23
24 #include <fcntl.h>
25 #include <unistd.h>
26 #include <errno.h>
27 #include <sys/stat.h>
28 #include <sys/ioctl.h>
29 #include <sys/mman.h>
30
31 #include <asm/types.h>
32 #include <linux/videodev2.h>
33
34 #include "flashlight_lib.h"
35
36 struct buffer {
37         void *start;
38         size_t length;
39 };
40
41 struct buffer *buffers = NULL;
42 static unsigned int n_buffers = 0;
43
44 int flashlight_get_status (FlashlightContext_t *flashlight, int *status)
45 {
46         struct v4l2_control ctrl;
47
48         printf ("flashlight_get_status()\n");
49
50         if (flashlight == NULL) {
51                 printf ("flashlight_get_status: flashlight context is not valid\n");
52                 return ENOCONTEXT;
53         }
54
55         if (flashlight->fd == -1) {
56                 printf ("flashlight_get_status: device not openned\n");
57                 return ENODEVICE;
58         }
59
60         *status = 0;
61
62         /* check short circuit fault */
63         ctrl.id = V4L2_CID_FLASH_ADP1653_FAULT_SCP;
64         if (ioctl (flashlight->fd, VIDIOC_G_CTRL, &ctrl) == -1) {
65                 printf ("flashlight_set_intensity: cannot get circuit fault status (%s)\n", strerror (errno));
66                 return EGENERROR;
67         }
68
69         if (ctrl.value)
70                 *status |= FLASHLIGHT_STATUS_SHORT_CIRCUT_FAULT;
71         else
72                 *status &= ~FLASHLIGHT_STATUS_SHORT_CIRCUT_FAULT;
73
74         /* check overtemperature fault */
75         ctrl.id = V4L2_CID_FLASH_ADP1653_FAULT_OT;
76         if (ioctl (flashlight->fd, VIDIOC_G_CTRL, &ctrl) == -1) {
77                 printf ("flashlight_set_intensity: cannot get overtemperature fault status (%s)\n", strerror (errno));
78                 return EGENERROR;
79         }
80
81         if (ctrl.value)
82                 *status |= FLASHLIGHT_STATUS_OVERTEMPERATURE_FAULT;
83         else
84                 *status &= ~FLASHLIGHT_STATUS_OVERTEMPERATURE_FAULT;
85
86         /* check timeout fault */
87         ctrl.id = V4L2_CID_FLASH_ADP1653_FAULT_TMR;
88         if (ioctl (flashlight->fd, VIDIOC_G_CTRL, &ctrl) == -1) {
89                 printf ("flashlight_set_intensity: cannot get timeout fault status (%s)\n", strerror (errno));
90                 return EGENERROR;
91         }
92
93         if (ctrl.value)
94                 *status |= FLASHLIGHT_STATUS_TIMEOUT_FAULT;
95         else
96                 *status &= ~FLASHLIGHT_STATUS_TIMEOUT_FAULT;
97
98         /* check overtemperature fault */
99         ctrl.id = V4L2_CID_FLASH_ADP1653_FAULT_OV;
100         if (ioctl (flashlight->fd, VIDIOC_G_CTRL, &ctrl) == -1) {
101                 printf ("flashlight_set_intensity: cannot get overvoltage fault status (%s)\n", strerror (errno));
102                 return EGENERROR;
103         }
104
105         if (ctrl.value)
106                 *status |= FLASHLIGHT_STATUS_OVERVOLTAGE_FAULT;
107         else
108                 *status &= ~FLASHLIGHT_STATUS_OVERVOLTAGE_FAULT;
109
110         return ENOERROR;
111 }
112
113 int flashlight_set_intensity (FlashlightContext_t *flashlight, int intensity)
114 {
115         struct v4l2_control ctrl;
116         enum v4l2_buf_type type;
117         unsigned int i;
118
119         printf ("flashlight_set_intensity(%d)\n", intensity);
120
121         if (flashlight == NULL) {
122                 printf ("flashlight_set_intensity: flashlight context is not valid\n");
123                 return ENOCONTEXT;
124         }
125
126         if (flashlight->fd == -1) {
127                 printf ("flashlight_set_intensity: device not openned\n");
128                 return ENODEVICE;
129         }
130
131         if (intensity > flashlight->max_intensity)
132                 intensity = flashlight->max_intensity;
133
134         ctrl.id = V4L2_CID_TORCH_INTENSITY;
135         ctrl.value = intensity;
136
137         if (ioctl (flashlight->fd, VIDIOC_S_CTRL, &ctrl) == -1) {
138                 printf ("flashlight_set_intensity: cannot set intensity (%s)\n", strerror (errno));
139                 return EGENERROR;
140         }
141
142         /*
143            WORKAROUND: start/stop i/o streaming to block camera application
144          */
145         if (intensity > 0) {
146                 for (i = 0; i < n_buffers; ++i) {
147                         struct v4l2_buffer buf;
148
149                         buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
150                         buf.memory      = V4L2_MEMORY_MMAP;
151                         buf.index       = i;
152                         if (ioctl (flashlight->fd, VIDIOC_QBUF, &buf) == -1) {
153                                 printf ("flashlight_set_intensity: unable to exchange a buffer %d with driver (%s)\n", i, strerror (errno));
154                                 return EGENERROR;
155                         }
156                 }
157
158                 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
159                 if (ioctl (flashlight->fd, VIDIOC_STREAMON, &type)) {
160                         printf ("flashlight_set_intensity: unable to start i/o streaming (%s)\n", strerror (errno));
161                         return EGENERROR;
162                 }
163         } else {
164                 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
165                 if (ioctl (flashlight->fd, VIDIOC_STREAMOFF, &type) == -1) {
166                         printf ("flashlight_set_intensity: unable to stop i/o streaming (%s)\n", strerror (errno));
167                         return EGENERROR;
168                 }
169         }
170
171         return ENOERROR;
172 }
173
174 int flashlight_get_intensity (FlashlightContext_t *flashlight, int *intensity)
175 {
176         struct v4l2_control ctrl;
177
178         printf ("flashlight_get_intensity()\n");
179
180         if (flashlight == NULL) {
181                 printf ("flashlight_get_intensity: flashlight context is not valid\n");
182                 return ENOCONTEXT;
183         }
184
185         if (flashlight->fd == -1) {
186                 printf ("flashlight_get_intensity: device not openned\n");
187                 return ENODEVICE;
188         }
189
190         ctrl.id = V4L2_CID_TORCH_INTENSITY;
191
192         if (ioctl (flashlight->fd, VIDIOC_G_CTRL, &ctrl) == -1) {
193                 printf ("flashlight_get_intensity: cannot get intensity (%s)\n", strerror (errno));
194                 return EGENERROR;
195         }
196
197         *intensity = ctrl.value;
198         return ENOERROR;
199 }
200
201 int flashlight_open (FlashlightContext_t *flashlight, const char *device_name)
202 {
203         struct v4l2_queryctrl ctrl;
204         struct v4l2_cropcap cropcap;
205         struct v4l2_crop crop;
206         struct v4l2_format fmt;
207         struct v4l2_requestbuffers req;
208         struct stat st;
209
210         printf ("flashlight_open(%s)\n", device_name);
211
212         if (flashlight == NULL) {
213                 printf ("flashlight_open: flashlight context is not valid\n");
214                 return ENOCONTEXT;
215         }
216
217         if (device_name == NULL) {
218                 printf ("flashlight_open: device name not specified\n");
219                 return EGENERROR;
220         }
221
222         memcpy (flashlight->device_name, device_name, sizeof(flashlight->device_name));
223
224         if (stat (flashlight->device_name, &st) == -1) {
225                 printf ("flashlight_open: cannot identify '%s' (%s)\n", flashlight->device_name, strerror (errno));
226                 return EGENERROR;
227         }
228
229         /* check it device_name is real device */
230         if (!S_ISCHR (st.st_mode)) {
231                 printf ("flashlight_open: %s is no device\n", flashlight->device_name);
232                 return EGENERROR;
233         }
234
235         flashlight->fd = open (flashlight->device_name, O_RDWR /* required */ | O_NONBLOCK, 0);
236
237         if (flashlight->fd == -1) {
238                 printf ("flashlight_open: cannot open '%s' (%s)\n", flashlight->device_name, strerror (errno));
239                 return ENODEVICE;
240         }
241
242         /* query from driver minimal and maximal flashlight intensity */
243         ctrl.id = V4L2_CID_TORCH_INTENSITY;
244         if (ioctl (flashlight->fd, VIDIOC_QUERYCTRL, &ctrl) == -1) {
245                 printf ("flashlight_open: cannot get minimal and maximal flashlight intensity (%s)\n", strerror (errno));
246                 return EGENERROR;
247         }
248
249         flashlight->min_intensity = ctrl.minimum;
250         flashlight->max_intensity = ctrl.maximum;
251
252         /*
253            WORKAROUND: Initialization of camera extracted from v4l2_example.
254            http://v4l2spec.bytesex.org/spec/capture-example.html
255
256            We need to initialize camera in other to block camera application.
257            (bug 4949: Applet breaks the camera application)
258          */
259         /* get crop capabilities */
260         cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
261         if (ioctl (flashlight->fd, VIDIOC_CROPCAP, &cropcap) == -1) {
262                 printf ("flashlight_open: unable to get crop capabilities (%s)\n", strerror (errno));
263                 return EGENERROR;
264         }
265
266         /* set crop capabilities */
267         crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
268         crop.c = cropcap.defrect; /* reset to default */
269         if (ioctl (flashlight->fd, VIDIOC_S_CROP, &crop) == -1) {
270                 printf ("flashlight_open: unable to set cropping rectangle (%s)\n", strerror (errno));
271                 return EGENERROR;
272         }
273
274         /* set data format */
275         fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
276         fmt.fmt.pix.width       = 640;
277         fmt.fmt.pix.height      = 480;
278         fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
279         fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;
280         if (ioctl (flashlight->fd, VIDIOC_S_FMT, &fmt) == -1) {
281                 printf ("flashlight_open: unable to set data format (%s)\n", strerror (errno));
282                 return EGENERROR;
283         }
284
285         req.count       = 4;
286         req.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
287         req.memory      = V4L2_MEMORY_MMAP;
288         if (ioctl (flashlight->fd, VIDIOC_REQBUFS, &req) == -1) {
289                 printf ("flashlight_open: unable to initiate memory mapping (%s)\n", strerror (errno));
290                 return EGENERROR;
291         }
292
293         if (req.count < 2) {
294                 printf ("flashlight_open: insufficient buffer memory on %s\n", device_name);
295                 return EGENERROR;
296         }
297
298         buffers = calloc (req.count, sizeof (*buffers));
299         if (!buffers) {
300                 printf ("flashlight_open: unable to allocate memory\n");
301                 return EGENERROR;
302         }
303
304         for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {
305                 struct v4l2_buffer buf;
306
307                 buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
308                 buf.memory      = V4L2_MEMORY_MMAP;
309                 buf.index       = n_buffers;
310
311                 if (ioctl (flashlight->fd, VIDIOC_QUERYBUF, &buf) == -1) {
312                         printf ("flashlight_open: unable to query the status of a buffer %d (%s)\n",
313                                 n_buffers, strerror (errno));
314                         return EGENERROR;
315                 }
316
317                 buffers[n_buffers].length = buf.length;
318                 buffers[n_buffers].start = mmap (NULL /* start anywhere */,
319                                                  buf.length,
320                                                  PROT_READ | PROT_WRITE /* required */,
321                                                  MAP_SHARED /* recommended */,
322                                                  flashlight->fd,
323                                                  buf.m.offset);
324
325                 if (buffers[n_buffers].start == MAP_FAILED) {
326                         printf ("flashlight_open: unable to map memory (%s)\n", strerror (errno));
327                         return EGENERROR;
328                 }
329         }
330
331         return ENOERROR;
332 }
333
334 int flashlight_close (FlashlightContext_t *flashlight)
335 {
336         unsigned int i;
337
338         printf ("flashlight_close()\n");
339
340         if (flashlight == NULL) {
341                 printf ("flashlight_close: flashlight context is not valid\n");
342                 return ENOCONTEXT;
343         }
344
345         /* unmap memory mapped buffers */
346         for (i = 0; i < n_buffers; ++i) {
347                 if (munmap (buffers[i].start, buffers[i].length) == -1) {
348                         printf ("flashlight_close: unable to unmap memory (%s)\n", strerror (errno));
349                         return EGENERROR;
350                 }
351         }
352         free (buffers);
353
354         if (flashlight->fd != -1) {
355                 if (close (flashlight->fd) == -1) {
356                         printf ("flashlight_close: cannot close device '%s' (%s)\n", flashlight->device_name, strerror (errno));
357                         return ENODEVICE;
358                 }
359         }
360
361         flashlight->fd = -1;
362         return ENOERROR;
363 }
364
365 int flashlight_init (FlashlightContext_t **pRefContext)
366 {
367         FlashlightContext_t *flashlight = NULL;
368
369         printf ("flashlight_init()\n");
370
371         if (*pRefContext != NULL) {
372                 printf("flashlight_init: expecting zero pointer context '*pRefContext'\n");
373                 return EGENERROR;
374         }
375
376         /* allocate memory for context structure */
377         flashlight = malloc (sizeof (FlashlightContext_t));
378         if (flashlight == NULL) {
379                 printf ("flashlight_init: unable to allocate memory for context\n");
380                 return ENOCONTEXT;
381         }
382
383         *pRefContext = flashlight;
384
385         /* initialize default values */
386         memset (flashlight, 0x00, sizeof (FlashlightContext_t));
387         flashlight->fd = -1;
388
389         /* from adp1653.c */
390         flashlight->min_intensity = 0;
391         flashlight->max_intensity = 11;
392
393         return ENOERROR;
394 }
395
396 int flashlight_deinit (FlashlightContext_t *flashlight)
397 {
398         int intensity = 0;
399
400         printf ("flashlight_deinit()\n");
401
402         if (flashlight == NULL) {
403                 printf ("flashlight_deinit: flashlight context is not valid\n");
404                 return ENOCONTEXT;
405         }
406
407         if (flashlight->fd != -1) {
408                 /* check if flashlight isn't enabled before closing device */
409                 if (flashlight_get_intensity (flashlight, &intensity) == -1)
410                         return EGENERROR;
411
412                 if (intensity > 0) {
413                         if (flashlight_set_intensity (flashlight, 0) == -1)
414                                 return EGENERROR;
415                 }
416
417                 if (flashlight_close(flashlight))
418                         return EGENERROR;
419         }
420
421         /* free allocated memory */
422         free (flashlight);
423
424         return ENOERROR;
425 }