]> bbs.cooldavid.org Git - net-next-2.6.git/blame - drivers/staging/dream/camera/msm_camera.c
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel...
[net-next-2.6.git] / drivers / staging / dream / camera / msm_camera.c
CommitLineData
eb7b797b
BS
1/*
2 * Copyright (C) 2008-2009 QUALCOMM Incorporated.
3 */
4
49c9b5c7 5/* FIXME: most allocations need not be GFP_ATOMIC */
eb7b797b
BS
6/* FIXME: management of mutexes */
7/* FIXME: msm_pmem_region_lookup return values */
8/* FIXME: way too many copy to/from user */
9/* FIXME: does region->active mean free */
10/* FIXME: check limits on command lenghts passed from userspace */
11/* FIXME: __msm_release: which queues should we flush when opencnt != 0 */
12
13#include <linux/kernel.h>
14#include <linux/module.h>
5a0e3ad6 15#include <linux/slab.h>
eb7b797b 16#include <linux/init.h>
ace9e791 17#include <linux/sched.h>
eb7b797b
BS
18#include <mach/board.h>
19
20#include <linux/fs.h>
21#include <linux/list.h>
22#include <linux/uaccess.h>
23#include <linux/android_pmem.h>
24#include <linux/poll.h>
25#include <media/msm_camera.h>
26#include <mach/camera.h>
27
28#define MSM_MAX_CAMERA_SENSORS 5
29
30#define ERR_USER_COPY(to) pr_err("%s(%d): copy %s user\n", \
31 __func__, __LINE__, ((to) ? "to" : "from"))
32#define ERR_COPY_FROM_USER() ERR_USER_COPY(0)
33#define ERR_COPY_TO_USER() ERR_USER_COPY(1)
34
35static struct class *msm_class;
36static dev_t msm_devno;
37static LIST_HEAD(msm_sensors);
38
39#define __CONTAINS(r, v, l, field) ({ \
40 typeof(r) __r = r; \
41 typeof(v) __v = v; \
42 typeof(v) __e = __v + l; \
43 int res = __v >= __r->field && \
44 __e <= __r->field + __r->len; \
45 res; \
46})
47
48#define CONTAINS(r1, r2, field) ({ \
49 typeof(r2) __r2 = r2; \
50 __CONTAINS(r1, __r2->field, __r2->len, field); \
51})
52
53#define IN_RANGE(r, v, field) ({ \
54 typeof(r) __r = r; \
55 typeof(v) __vv = v; \
56 int res = ((__vv >= __r->field) && \
57 (__vv < (__r->field + __r->len))); \
58 res; \
59})
60
61#define OVERLAPS(r1, r2, field) ({ \
62 typeof(r1) __r1 = r1; \
63 typeof(r2) __r2 = r2; \
64 typeof(__r2->field) __v = __r2->field; \
65 typeof(__v) __e = __v + __r2->len - 1; \
66 int res = (IN_RANGE(__r1, __v, field) || \
67 IN_RANGE(__r1, __e, field)); \
68 res; \
69})
70
71#define MSM_DRAIN_QUEUE_NOSYNC(sync, name) do { \
72 struct msm_queue_cmd *qcmd = NULL; \
73 CDBG("%s: draining queue "#name"\n", __func__); \
74 while (!list_empty(&(sync)->name)) { \
75 qcmd = list_first_entry(&(sync)->name, \
76 struct msm_queue_cmd, list); \
77 list_del_init(&qcmd->list); \
78 kfree(qcmd); \
79 }; \
451ff373 80} while (0)
eb7b797b
BS
81
82#define MSM_DRAIN_QUEUE(sync, name) do { \
83 unsigned long flags; \
84 spin_lock_irqsave(&(sync)->name##_lock, flags); \
85 MSM_DRAIN_QUEUE_NOSYNC(sync, name); \
86 spin_unlock_irqrestore(&(sync)->name##_lock, flags); \
451ff373 87} while (0)
eb7b797b
BS
88
89static int check_overlap(struct hlist_head *ptype,
90 unsigned long paddr,
91 unsigned long len)
92{
93 struct msm_pmem_region *region;
94 struct msm_pmem_region t = { .paddr = paddr, .len = len };
95 struct hlist_node *node;
96
97 hlist_for_each_entry(region, node, ptype, list) {
98 if (CONTAINS(region, &t, paddr) ||
99 CONTAINS(&t, region, paddr) ||
100 OVERLAPS(region, &t, paddr)) {
101 printk(KERN_ERR
102 " region (PHYS %p len %ld)"
103 " clashes with registered region"
104 " (paddr %p len %ld)\n",
105 (void *)t.paddr, t.len,
106 (void *)region->paddr, region->len);
107 return -1;
108 }
109 }
110
111 return 0;
112}
113
114static int msm_pmem_table_add(struct hlist_head *ptype,
115 struct msm_pmem_info *info)
116{
117 struct file *file;
118 unsigned long paddr;
119 unsigned long vstart;
120 unsigned long len;
121 int rc;
122 struct msm_pmem_region *region;
123
124 rc = get_pmem_file(info->fd, &paddr, &vstart, &len, &file);
125 if (rc < 0) {
126 pr_err("msm_pmem_table_add: get_pmem_file fd %d error %d\n",
127 info->fd, rc);
128 return rc;
129 }
130
131 if (check_overlap(ptype, paddr, len) < 0)
132 return -EINVAL;
133
134 CDBG("%s: type = %d, paddr = 0x%lx, vaddr = 0x%lx\n",
135 __func__,
136 info->type, paddr, (unsigned long)info->vaddr);
137
138 region = kmalloc(sizeof(*region), GFP_KERNEL);
139 if (!region)
140 return -ENOMEM;
141
142 INIT_HLIST_NODE(&region->list);
143
144 region->type = info->type;
145 region->vaddr = info->vaddr;
146 region->paddr = paddr;
147 region->len = len;
148 region->file = file;
149 region->y_off = info->y_off;
150 region->cbcr_off = info->cbcr_off;
151 region->fd = info->fd;
152 region->active = info->active;
153
154 hlist_add_head(&(region->list), ptype);
155
156 return 0;
157}
158
159/* return of 0 means failure */
160static uint8_t msm_pmem_region_lookup(struct hlist_head *ptype,
161 int pmem_type, struct msm_pmem_region *reg, uint8_t maxcount)
162{
163 struct msm_pmem_region *region;
164 struct msm_pmem_region *regptr;
165 struct hlist_node *node, *n;
166
167 uint8_t rc = 0;
168
169 regptr = reg;
170
171 hlist_for_each_entry_safe(region, node, n, ptype, list) {
172 if (region->type == pmem_type && region->active) {
173 *regptr = *region;
174 rc += 1;
175 if (rc >= maxcount)
176 break;
177 regptr++;
178 }
179 }
180
181 return rc;
182}
183
184static unsigned long msm_pmem_frame_ptov_lookup(struct msm_sync *sync,
185 unsigned long pyaddr,
186 unsigned long pcbcraddr,
187 uint32_t *yoff, uint32_t *cbcroff, int *fd)
188{
189 struct msm_pmem_region *region;
190 struct hlist_node *node, *n;
191
192 hlist_for_each_entry_safe(region, node, n, &sync->frame, list) {
193 if (pyaddr == (region->paddr + region->y_off) &&
194 pcbcraddr == (region->paddr +
195 region->cbcr_off) &&
196 region->active) {
197 /* offset since we could pass vaddr inside
198 * a registerd pmem buffer
199 */
200 *yoff = region->y_off;
201 *cbcroff = region->cbcr_off;
202 *fd = region->fd;
203 region->active = 0;
204 return (unsigned long)(region->vaddr);
205 }
206 }
207
208 return 0;
209}
210
211static unsigned long msm_pmem_stats_ptov_lookup(struct msm_sync *sync,
212 unsigned long addr, int *fd)
213{
214 struct msm_pmem_region *region;
215 struct hlist_node *node, *n;
216
217 hlist_for_each_entry_safe(region, node, n, &sync->stats, list) {
218 if (addr == region->paddr && region->active) {
219 /* offset since we could pass vaddr inside a
220 * registered pmem buffer */
221 *fd = region->fd;
222 region->active = 0;
223 return (unsigned long)(region->vaddr);
224 }
225 }
226
227 return 0;
228}
229
230static unsigned long msm_pmem_frame_vtop_lookup(struct msm_sync *sync,
231 unsigned long buffer,
232 uint32_t yoff, uint32_t cbcroff, int fd)
233{
234 struct msm_pmem_region *region;
235 struct hlist_node *node, *n;
236
237 hlist_for_each_entry_safe(region,
238 node, n, &sync->frame, list) {
239 if (((unsigned long)(region->vaddr) == buffer) &&
240 (region->y_off == yoff) &&
241 (region->cbcr_off == cbcroff) &&
242 (region->fd == fd) &&
243 (region->active == 0)) {
244
245 region->active = 1;
246 return region->paddr;
247 }
248 }
249
250 return 0;
251}
252
253static unsigned long msm_pmem_stats_vtop_lookup(
254 struct msm_sync *sync,
255 unsigned long buffer,
256 int fd)
257{
258 struct msm_pmem_region *region;
259 struct hlist_node *node, *n;
260
261 hlist_for_each_entry_safe(region, node, n, &sync->stats, list) {
262 if (((unsigned long)(region->vaddr) == buffer) &&
263 (region->fd == fd) && region->active == 0) {
264 region->active = 1;
265 return region->paddr;
266 }
267 }
268
269 return 0;
270}
271
272static int __msm_pmem_table_del(struct msm_sync *sync,
273 struct msm_pmem_info *pinfo)
274{
275 int rc = 0;
276 struct msm_pmem_region *region;
277 struct hlist_node *node, *n;
278
279 switch (pinfo->type) {
280 case MSM_PMEM_OUTPUT1:
281 case MSM_PMEM_OUTPUT2:
282 case MSM_PMEM_THUMBAIL:
283 case MSM_PMEM_MAINIMG:
284 case MSM_PMEM_RAW_MAINIMG:
285 hlist_for_each_entry_safe(region, node, n,
286 &sync->frame, list) {
287
288 if (pinfo->type == region->type &&
289 pinfo->vaddr == region->vaddr &&
290 pinfo->fd == region->fd) {
291 hlist_del(node);
292 put_pmem_file(region->file);
293 kfree(region);
294 }
295 }
296 break;
297
298 case MSM_PMEM_AEC_AWB:
299 case MSM_PMEM_AF:
300 hlist_for_each_entry_safe(region, node, n,
301 &sync->stats, list) {
302
303 if (pinfo->type == region->type &&
304 pinfo->vaddr == region->vaddr &&
305 pinfo->fd == region->fd) {
306 hlist_del(node);
307 put_pmem_file(region->file);
308 kfree(region);
309 }
310 }
311 break;
312
313 default:
314 rc = -EINVAL;
315 break;
316 }
317
318 return rc;
319}
320
321static int msm_pmem_table_del(struct msm_sync *sync, void __user *arg)
322{
323 struct msm_pmem_info info;
324
325 if (copy_from_user(&info, arg, sizeof(info))) {
326 ERR_COPY_FROM_USER();
327 return -EFAULT;
328 }
329
330 return __msm_pmem_table_del(sync, &info);
331}
332
333static int __msm_get_frame(struct msm_sync *sync,
334 struct msm_frame *frame)
335{
336 unsigned long flags;
337 int rc = 0;
338
339 struct msm_queue_cmd *qcmd = NULL;
340 struct msm_vfe_phy_info *pphy;
341
342 spin_lock_irqsave(&sync->prev_frame_q_lock, flags);
343 if (!list_empty(&sync->prev_frame_q)) {
344 qcmd = list_first_entry(&sync->prev_frame_q,
345 struct msm_queue_cmd, list);
346 list_del_init(&qcmd->list);
347 }
348 spin_unlock_irqrestore(&sync->prev_frame_q_lock, flags);
349
350 if (!qcmd) {
351 pr_err("%s: no preview frame.\n", __func__);
352 return -EAGAIN;
353 }
354
355 pphy = (struct msm_vfe_phy_info *)(qcmd->command);
356
357 frame->buffer =
358 msm_pmem_frame_ptov_lookup(sync,
359 pphy->y_phy,
360 pphy->cbcr_phy, &(frame->y_off),
361 &(frame->cbcr_off), &(frame->fd));
362 if (!frame->buffer) {
363 pr_err("%s: cannot get frame, invalid lookup address "
364 "y=%x cbcr=%x offset=%d\n",
451ff373 365 __func__,
eb7b797b
BS
366 pphy->y_phy,
367 pphy->cbcr_phy,
368 frame->y_off);
369 rc = -EINVAL;
370 }
371
372 CDBG("__msm_get_frame: y=0x%x, cbcr=0x%x, qcmd=0x%x, virt_addr=0x%x\n",
373 pphy->y_phy, pphy->cbcr_phy, (int) qcmd, (int) frame->buffer);
374
375 kfree(qcmd);
376 return rc;
377}
378
379static int msm_get_frame(struct msm_sync *sync, void __user *arg)
380{
381 int rc = 0;
382 struct msm_frame frame;
383
384 if (copy_from_user(&frame,
385 arg,
386 sizeof(struct msm_frame))) {
387 ERR_COPY_FROM_USER();
388 return -EFAULT;
389 }
390
391 rc = __msm_get_frame(sync, &frame);
392 if (rc < 0)
393 return rc;
394
395 if (sync->croplen) {
396 if (frame.croplen > sync->croplen) {
397 pr_err("msm_get_frame: invalid frame croplen %d\n",
398 frame.croplen);
399 return -EINVAL;
400 }
401
402 if (copy_to_user((void *)frame.cropinfo,
403 sync->cropinfo,
404 sync->croplen)) {
405 ERR_COPY_TO_USER();
406 return -EFAULT;
407 }
408 }
409
410 if (copy_to_user((void *)arg,
411 &frame, sizeof(struct msm_frame))) {
412 ERR_COPY_TO_USER();
413 rc = -EFAULT;
414 }
415
416 CDBG("Got frame!!!\n");
417
418 return rc;
419}
420
421static int msm_enable_vfe(struct msm_sync *sync, void __user *arg)
422{
423 int rc = -EIO;
424 struct camera_enable_cmd cfg;
425
426 if (copy_from_user(&cfg,
427 arg,
428 sizeof(struct camera_enable_cmd))) {
429 ERR_COPY_FROM_USER();
430 return -EFAULT;
431 }
432
433 if (sync->vfefn.vfe_enable)
434 rc = sync->vfefn.vfe_enable(&cfg);
435
436 CDBG("msm_enable_vfe: returned rc = %d\n", rc);
437 return rc;
438}
439
440static int msm_disable_vfe(struct msm_sync *sync, void __user *arg)
441{
442 int rc = -EIO;
443 struct camera_enable_cmd cfg;
444
445 if (copy_from_user(&cfg,
446 arg,
447 sizeof(struct camera_enable_cmd))) {
448 ERR_COPY_FROM_USER();
449 return -EFAULT;
450 }
451
452 if (sync->vfefn.vfe_disable)
453 rc = sync->vfefn.vfe_disable(&cfg, NULL);
454
455 CDBG("msm_disable_vfe: returned rc = %d\n", rc);
456 return rc;
457}
458
451ff373 459static struct msm_queue_cmd *__msm_control(struct msm_sync *sync,
eb7b797b
BS
460 struct msm_control_device_queue *queue,
461 struct msm_queue_cmd *qcmd,
462 int timeout)
463{
464 unsigned long flags;
465 int rc;
466
467 spin_lock_irqsave(&sync->msg_event_q_lock, flags);
468 list_add_tail(&qcmd->list, &sync->msg_event_q);
469 /* wake up config thread */
470 wake_up(&sync->msg_event_wait);
471 spin_unlock_irqrestore(&sync->msg_event_q_lock, flags);
472
473 if (!queue)
474 return NULL;
475
476 /* wait for config status */
477 rc = wait_event_interruptible_timeout(
478 queue->ctrl_status_wait,
479 !list_empty_careful(&queue->ctrl_status_q),
480 timeout);
481 if (list_empty_careful(&queue->ctrl_status_q)) {
482 if (!rc)
483 rc = -ETIMEDOUT;
484 if (rc < 0) {
485 pr_err("msm_control: wait_event error %d\n", rc);
486#if 0
487 /* This is a bit scary. If we time out too early, we
488 * will free qcmd at the end of this function, and the
489 * dsp may do the same when it does respond, so we
490 * remove the message from the source queue.
491 */
492 pr_err("%s: error waiting for ctrl_status_q: %d\n",
493 __func__, rc);
494 spin_lock_irqsave(&sync->msg_event_q_lock, flags);
495 list_del_init(&qcmd->list);
496 spin_unlock_irqrestore(&sync->msg_event_q_lock, flags);
497#endif
498 return ERR_PTR(rc);
499 }
500 }
501
502 /* control command status is ready */
503 spin_lock_irqsave(&queue->ctrl_status_q_lock, flags);
504 BUG_ON(list_empty(&queue->ctrl_status_q));
505 qcmd = list_first_entry(&queue->ctrl_status_q,
506 struct msm_queue_cmd, list);
507 list_del_init(&qcmd->list);
508 spin_unlock_irqrestore(&queue->ctrl_status_q_lock, flags);
509
510 return qcmd;
511}
512
513static int msm_control(struct msm_control_device *ctrl_pmsm,
514 int block,
515 void __user *arg)
516{
517 int rc = 0;
518
519 struct msm_sync *sync = ctrl_pmsm->pmsm->sync;
520 struct msm_ctrl_cmd udata, *ctrlcmd;
521 struct msm_queue_cmd *qcmd = NULL, *qcmd_temp;
522
523 if (copy_from_user(&udata, arg, sizeof(struct msm_ctrl_cmd))) {
524 ERR_COPY_FROM_USER();
525 rc = -EFAULT;
526 goto end;
527 }
528
529 qcmd = kmalloc(sizeof(struct msm_queue_cmd) +
530 sizeof(struct msm_ctrl_cmd) + udata.length,
531 GFP_KERNEL);
532 if (!qcmd) {
533 pr_err("msm_control: cannot allocate buffer\n");
534 rc = -ENOMEM;
535 goto end;
536 }
537
538 qcmd->type = MSM_CAM_Q_CTRL;
539 qcmd->command = ctrlcmd = (struct msm_ctrl_cmd *)(qcmd + 1);
540 *ctrlcmd = udata;
541 ctrlcmd->value = ctrlcmd + 1;
542
543 if (udata.length) {
544 if (copy_from_user(ctrlcmd->value,
545 udata.value, udata.length)) {
546 ERR_COPY_FROM_USER();
547 rc = -EFAULT;
548 goto end;
549 }
550 }
551
552 if (!block) {
553 /* qcmd will be set to NULL */
554 qcmd = __msm_control(sync, NULL, qcmd, 0);
555 goto end;
556 }
557
558 qcmd_temp = __msm_control(sync,
559 &ctrl_pmsm->ctrl_q,
560 qcmd, MAX_SCHEDULE_TIMEOUT);
561
562 if (IS_ERR(qcmd_temp)) {
563 rc = PTR_ERR(qcmd_temp);
564 goto end;
565 }
566 qcmd = qcmd_temp;
567
568 if (qcmd->command) {
569 void __user *to = udata.value;
570 udata = *(struct msm_ctrl_cmd *)qcmd->command;
571 if (udata.length > 0) {
572 if (copy_to_user(to,
573 udata.value,
574 udata.length)) {
575 ERR_COPY_TO_USER();
576 rc = -EFAULT;
577 goto end;
578 }
579 }
580 udata.value = to;
581
582 if (copy_to_user((void *)arg, &udata,
583 sizeof(struct msm_ctrl_cmd))) {
584 ERR_COPY_TO_USER();
585 rc = -EFAULT;
586 goto end;
587 }
588 }
589
590end:
591 /* Note: if we get here as a result of an error, we will free the
592 * qcmd that we kmalloc() in this function. When we come here as
593 * a result of a successful completion, we are freeing the qcmd that
594 * we dequeued from queue->ctrl_status_q.
595 */
451ff373 596 kfree(qcmd);
eb7b797b
BS
597
598 CDBG("msm_control: end rc = %d\n", rc);
599 return rc;
600}
601
602static int msm_get_stats(struct msm_sync *sync, void __user *arg)
603{
604 unsigned long flags;
605 int timeout;
606 int rc = 0;
607
608 struct msm_stats_event_ctrl se;
609
610 struct msm_queue_cmd *qcmd = NULL;
611 struct msm_ctrl_cmd *ctrl = NULL;
612 struct msm_vfe_resp *data = NULL;
613 struct msm_stats_buf stats;
614
615 if (copy_from_user(&se, arg,
616 sizeof(struct msm_stats_event_ctrl))) {
617 ERR_COPY_FROM_USER();
618 return -EFAULT;
619 }
620
621 timeout = (int)se.timeout_ms;
622
623 CDBG("msm_get_stats timeout %d\n", timeout);
624 rc = wait_event_interruptible_timeout(
625 sync->msg_event_wait,
626 !list_empty_careful(&sync->msg_event_q),
627 msecs_to_jiffies(timeout));
628 if (list_empty_careful(&sync->msg_event_q)) {
629 if (rc == 0)
630 rc = -ETIMEDOUT;
631 if (rc < 0) {
632 pr_err("msm_get_stats error %d\n", rc);
633 return rc;
634 }
635 }
636 CDBG("msm_get_stats returned from wait: %d\n", rc);
637
638 spin_lock_irqsave(&sync->msg_event_q_lock, flags);
639 BUG_ON(list_empty(&sync->msg_event_q));
640 qcmd = list_first_entry(&sync->msg_event_q,
641 struct msm_queue_cmd, list);
642 list_del_init(&qcmd->list);
643 spin_unlock_irqrestore(&sync->msg_event_q_lock, flags);
644
645 CDBG("=== received from DSP === %d\n", qcmd->type);
646
647 switch (qcmd->type) {
648 case MSM_CAM_Q_VFE_EVT:
649 case MSM_CAM_Q_VFE_MSG:
650 data = (struct msm_vfe_resp *)(qcmd->command);
651
652 /* adsp event and message */
653 se.resptype = MSM_CAM_RESP_STAT_EVT_MSG;
654
655 /* 0 - msg from aDSP, 1 - event from mARM */
656 se.stats_event.type = data->evt_msg.type;
657 se.stats_event.msg_id = data->evt_msg.msg_id;
658 se.stats_event.len = data->evt_msg.len;
659
660 CDBG("msm_get_stats, qcmd->type = %d\n", qcmd->type);
661 CDBG("length = %d\n", se.stats_event.len);
662 CDBG("msg_id = %d\n", se.stats_event.msg_id);
663
664 if ((data->type == VFE_MSG_STATS_AF) ||
665 (data->type == VFE_MSG_STATS_WE)) {
666
667 stats.buffer =
668 msm_pmem_stats_ptov_lookup(sync,
669 data->phy.sbuf_phy,
670 &(stats.fd));
671 if (!stats.buffer) {
672 pr_err("%s: msm_pmem_stats_ptov_lookup error\n",
451ff373 673 __func__);
eb7b797b
BS
674 rc = -EINVAL;
675 goto failure;
676 }
677
678 if (copy_to_user((void *)(se.stats_event.data),
679 &stats,
680 sizeof(struct msm_stats_buf))) {
681 ERR_COPY_TO_USER();
682 rc = -EFAULT;
683 goto failure;
684 }
685 } else if ((data->evt_msg.len > 0) &&
686 (data->type == VFE_MSG_GENERAL)) {
687 if (copy_to_user((void *)(se.stats_event.data),
688 data->evt_msg.data,
689 data->evt_msg.len)) {
690 ERR_COPY_TO_USER();
691 rc = -EFAULT;
692 }
693 } else if (data->type == VFE_MSG_OUTPUT1 ||
694 data->type == VFE_MSG_OUTPUT2) {
695 if (copy_to_user((void *)(se.stats_event.data),
696 data->extdata,
697 data->extlen)) {
698 ERR_COPY_TO_USER();
699 rc = -EFAULT;
700 }
701 } else if (data->type == VFE_MSG_SNAPSHOT && sync->pict_pp) {
702 struct msm_postproc buf;
703 struct msm_pmem_region region;
704 buf.fmnum = msm_pmem_region_lookup(&sync->frame,
705 MSM_PMEM_MAINIMG,
706 &region, 1);
707 if (buf.fmnum == 1) {
708 buf.fmain.buffer = (unsigned long)region.vaddr;
709 buf.fmain.y_off = region.y_off;
710 buf.fmain.cbcr_off = region.cbcr_off;
711 buf.fmain.fd = region.fd;
712 } else {
713 buf.fmnum = msm_pmem_region_lookup(&sync->frame,
714 MSM_PMEM_RAW_MAINIMG,
715 &region, 1);
716 if (buf.fmnum == 1) {
717 buf.fmain.path = MSM_FRAME_PREV_2;
718 buf.fmain.buffer =
719 (unsigned long)region.vaddr;
720 buf.fmain.fd = region.fd;
451ff373 721 } else {
eb7b797b
BS
722 pr_err("%s: pmem lookup failed\n",
723 __func__);
724 rc = -EINVAL;
725 }
726 }
727
728 if (copy_to_user((void *)(se.stats_event.data), &buf,
729 sizeof(buf))) {
730 ERR_COPY_TO_USER();
731 rc = -EFAULT;
732 goto failure;
733 }
734 CDBG("snapshot copy_to_user!\n");
735 }
736 break;
737
738 case MSM_CAM_Q_CTRL:
739 /* control command from control thread */
740 ctrl = (struct msm_ctrl_cmd *)(qcmd->command);
741
742 CDBG("msm_get_stats, qcmd->type = %d\n", qcmd->type);
743 CDBG("length = %d\n", ctrl->length);
744
745 if (ctrl->length > 0) {
746 if (copy_to_user((void *)(se.ctrl_cmd.value),
747 ctrl->value,
748 ctrl->length)) {
749 ERR_COPY_TO_USER();
750 rc = -EFAULT;
751 goto failure;
752 }
753 }
754
755 se.resptype = MSM_CAM_RESP_CTRL;
756
757 /* what to control */
758 se.ctrl_cmd.type = ctrl->type;
759 se.ctrl_cmd.length = ctrl->length;
760 se.ctrl_cmd.resp_fd = ctrl->resp_fd;
761 break;
762
763 case MSM_CAM_Q_V4L2_REQ:
764 /* control command from v4l2 client */
765 ctrl = (struct msm_ctrl_cmd *)(qcmd->command);
766
767 CDBG("msm_get_stats, qcmd->type = %d\n", qcmd->type);
768 CDBG("length = %d\n", ctrl->length);
769
770 if (ctrl->length > 0) {
771 if (copy_to_user((void *)(se.ctrl_cmd.value),
772 ctrl->value, ctrl->length)) {
773 ERR_COPY_TO_USER();
774 rc = -EFAULT;
775 goto failure;
776 }
777 }
778
779 /* 2 tells config thread this is v4l2 request */
780 se.resptype = MSM_CAM_RESP_V4L2;
781
782 /* what to control */
783 se.ctrl_cmd.type = ctrl->type;
784 se.ctrl_cmd.length = ctrl->length;
785 break;
786
787 default:
788 rc = -EFAULT;
789 goto failure;
790 } /* switch qcmd->type */
791
792 if (copy_to_user((void *)arg, &se, sizeof(se))) {
793 ERR_COPY_TO_USER();
794 rc = -EFAULT;
795 }
796
797failure:
451ff373 798 kfree(qcmd);
eb7b797b
BS
799
800 CDBG("msm_get_stats: %d\n", rc);
801 return rc;
802}
803
804static int msm_ctrl_cmd_done(struct msm_control_device *ctrl_pmsm,
805 void __user *arg)
806{
807 unsigned long flags;
808 int rc = 0;
809
810 struct msm_ctrl_cmd udata, *ctrlcmd;
811 struct msm_queue_cmd *qcmd = NULL;
812
813 if (copy_from_user(&udata, arg, sizeof(struct msm_ctrl_cmd))) {
814 ERR_COPY_FROM_USER();
815 rc = -EFAULT;
816 goto end;
817 }
818
819 qcmd = kmalloc(sizeof(struct msm_queue_cmd) +
820 sizeof(struct msm_ctrl_cmd) + udata.length,
821 GFP_KERNEL);
822 if (!qcmd) {
823 rc = -ENOMEM;
824 goto end;
825 }
826
827 qcmd->command = ctrlcmd = (struct msm_ctrl_cmd *)(qcmd + 1);
828 *ctrlcmd = udata;
829 if (udata.length > 0) {
830 ctrlcmd->value = ctrlcmd + 1;
831 if (copy_from_user(ctrlcmd->value,
832 (void *)udata.value,
833 udata.length)) {
834 ERR_COPY_FROM_USER();
835 rc = -EFAULT;
836 kfree(qcmd);
837 goto end;
838 }
451ff373
JM
839 } else
840 ctrlcmd->value = NULL;
eb7b797b
BS
841
842end:
843 CDBG("msm_ctrl_cmd_done: end rc = %d\n", rc);
844 if (rc == 0) {
845 /* wake up control thread */
846 spin_lock_irqsave(&ctrl_pmsm->ctrl_q.ctrl_status_q_lock, flags);
847 list_add_tail(&qcmd->list, &ctrl_pmsm->ctrl_q.ctrl_status_q);
848 wake_up(&ctrl_pmsm->ctrl_q.ctrl_status_wait);
849 spin_unlock_irqrestore(&ctrl_pmsm->ctrl_q.ctrl_status_q_lock, flags);
850 }
851
852 return rc;
853}
854
855static int msm_config_vfe(struct msm_sync *sync, void __user *arg)
856{
857 struct msm_vfe_cfg_cmd cfgcmd;
858 struct msm_pmem_region region[8];
859 struct axidata axi_data;
860 void *data = NULL;
861 int rc = -EIO;
862
863 memset(&axi_data, 0, sizeof(axi_data));
864
865 if (copy_from_user(&cfgcmd, arg, sizeof(cfgcmd))) {
866 ERR_COPY_FROM_USER();
867 return -EFAULT;
868 }
869
451ff373 870 switch (cfgcmd.cmd_type) {
eb7b797b
BS
871 case CMD_STATS_ENABLE:
872 axi_data.bufnum1 =
873 msm_pmem_region_lookup(&sync->stats,
874 MSM_PMEM_AEC_AWB, &region[0],
875 NUM_WB_EXP_STAT_OUTPUT_BUFFERS);
876 if (!axi_data.bufnum1) {
451ff373 877 pr_err("%s: pmem region lookup error\n", __func__);
eb7b797b
BS
878 return -EINVAL;
879 }
880 axi_data.region = &region[0];
881 data = &axi_data;
882 break;
883 case CMD_STATS_AF_ENABLE:
884 axi_data.bufnum1 =
885 msm_pmem_region_lookup(&sync->stats,
886 MSM_PMEM_AF, &region[0],
887 NUM_AF_STAT_OUTPUT_BUFFERS);
888 if (!axi_data.bufnum1) {
451ff373 889 pr_err("%s: pmem region lookup error\n", __func__);
eb7b797b
BS
890 return -EINVAL;
891 }
892 axi_data.region = &region[0];
893 data = &axi_data;
894 break;
895 case CMD_GENERAL:
896 case CMD_STATS_DISABLE:
897 break;
898 default:
899 pr_err("%s: unknown command type %d\n",
451ff373 900 __func__, cfgcmd.cmd_type);
eb7b797b
BS
901 return -EINVAL;
902 }
903
904
905 if (sync->vfefn.vfe_config)
906 rc = sync->vfefn.vfe_config(&cfgcmd, data);
907
908 return rc;
909}
910
911static int msm_frame_axi_cfg(struct msm_sync *sync,
912 struct msm_vfe_cfg_cmd *cfgcmd)
913{
914 int rc = -EIO;
915 struct axidata axi_data;
916 void *data = &axi_data;
917 struct msm_pmem_region region[8];
918 int pmem_type;
919
920 memset(&axi_data, 0, sizeof(axi_data));
921
922 switch (cfgcmd->cmd_type) {
923 case CMD_AXI_CFG_OUT1:
924 pmem_type = MSM_PMEM_OUTPUT1;
925 axi_data.bufnum1 =
926 msm_pmem_region_lookup(&sync->frame, pmem_type,
927 &region[0], 8);
928 if (!axi_data.bufnum1) {
451ff373 929 pr_err("%s: pmem region lookup error\n", __func__);
eb7b797b
BS
930 return -EINVAL;
931 }
932 break;
933
934 case CMD_AXI_CFG_OUT2:
935 pmem_type = MSM_PMEM_OUTPUT2;
936 axi_data.bufnum2 =
937 msm_pmem_region_lookup(&sync->frame, pmem_type,
938 &region[0], 8);
939 if (!axi_data.bufnum2) {
451ff373 940 pr_err("%s: pmem region lookup error\n", __func__);
eb7b797b
BS
941 return -EINVAL;
942 }
943 break;
944
945 case CMD_AXI_CFG_SNAP_O1_AND_O2:
946 pmem_type = MSM_PMEM_THUMBAIL;
947 axi_data.bufnum1 =
948 msm_pmem_region_lookup(&sync->frame, pmem_type,
949 &region[0], 8);
950 if (!axi_data.bufnum1) {
451ff373 951 pr_err("%s: pmem region lookup error\n", __func__);
eb7b797b
BS
952 return -EINVAL;
953 }
954
955 pmem_type = MSM_PMEM_MAINIMG;
956 axi_data.bufnum2 =
957 msm_pmem_region_lookup(&sync->frame, pmem_type,
958 &region[axi_data.bufnum1], 8);
959 if (!axi_data.bufnum2) {
451ff373 960 pr_err("%s: pmem region lookup error\n", __func__);
eb7b797b
BS
961 return -EINVAL;
962 }
963 break;
964
965 case CMD_RAW_PICT_AXI_CFG:
966 pmem_type = MSM_PMEM_RAW_MAINIMG;
967 axi_data.bufnum2 =
968 msm_pmem_region_lookup(&sync->frame, pmem_type,
969 &region[0], 8);
970 if (!axi_data.bufnum2) {
451ff373 971 pr_err("%s: pmem region lookup error\n", __func__);
eb7b797b
BS
972 return -EINVAL;
973 }
974 break;
975
976 case CMD_GENERAL:
977 data = NULL;
978 break;
979
980 default:
981 pr_err("%s: unknown command type %d\n",
451ff373 982 __func__, cfgcmd->cmd_type);
eb7b797b
BS
983 return -EINVAL;
984 }
985
986 axi_data.region = &region[0];
987
988 /* send the AXI configuration command to driver */
989 if (sync->vfefn.vfe_config)
990 rc = sync->vfefn.vfe_config(cfgcmd, data);
991
992 return rc;
993}
994
995static int msm_get_sensor_info(struct msm_sync *sync, void __user *arg)
996{
997 int rc = 0;
998 struct msm_camsensor_info info;
999 struct msm_camera_sensor_info *sdata;
1000
1001 if (copy_from_user(&info,
1002 arg,
1003 sizeof(struct msm_camsensor_info))) {
1004 ERR_COPY_FROM_USER();
1005 return -EFAULT;
1006 }
1007
1008 sdata = sync->pdev->dev.platform_data;
1009 CDBG("sensor_name %s\n", sdata->sensor_name);
1010
1011 memcpy(&info.name[0],
1012 sdata->sensor_name,
1013 MAX_SENSOR_NAME);
1014 info.flash_enabled = sdata->flash_type != MSM_CAMERA_FLASH_NONE;
1015
1016 /* copy back to user space */
1017 if (copy_to_user((void *)arg,
1018 &info,
1019 sizeof(struct msm_camsensor_info))) {
1020 ERR_COPY_TO_USER();
1021 rc = -EFAULT;
1022 }
1023
1024 return rc;
1025}
1026
1027static int __msm_put_frame_buf(struct msm_sync *sync,
1028 struct msm_frame *pb)
1029{
1030 unsigned long pphy;
1031 struct msm_vfe_cfg_cmd cfgcmd;
1032
1033 int rc = -EIO;
1034
1035 pphy = msm_pmem_frame_vtop_lookup(sync,
1036 pb->buffer,
1037 pb->y_off, pb->cbcr_off, pb->fd);
1038
1039 if (pphy != 0) {
1040 CDBG("rel: vaddr = 0x%lx, paddr = 0x%lx\n",
1041 pb->buffer, pphy);
1042 cfgcmd.cmd_type = CMD_FRAME_BUF_RELEASE;
1043 cfgcmd.value = (void *)pb;
1044 if (sync->vfefn.vfe_config)
1045 rc = sync->vfefn.vfe_config(&cfgcmd, &pphy);
1046 } else {
1047 pr_err("%s: msm_pmem_frame_vtop_lookup failed\n",
451ff373 1048 __func__);
eb7b797b
BS
1049 rc = -EINVAL;
1050 }
1051
1052 return rc;
1053}
1054
1055static int msm_put_frame_buffer(struct msm_sync *sync, void __user *arg)
1056{
1057 struct msm_frame buf_t;
1058
1059 if (copy_from_user(&buf_t,
1060 arg,
1061 sizeof(struct msm_frame))) {
1062 ERR_COPY_FROM_USER();
1063 return -EFAULT;
1064 }
1065
1066 return __msm_put_frame_buf(sync, &buf_t);
1067}
1068
1069static int __msm_register_pmem(struct msm_sync *sync,
1070 struct msm_pmem_info *pinfo)
1071{
1072 int rc = 0;
1073
1074 switch (pinfo->type) {
1075 case MSM_PMEM_OUTPUT1:
1076 case MSM_PMEM_OUTPUT2:
1077 case MSM_PMEM_THUMBAIL:
1078 case MSM_PMEM_MAINIMG:
1079 case MSM_PMEM_RAW_MAINIMG:
1080 rc = msm_pmem_table_add(&sync->frame, pinfo);
1081 break;
1082
1083 case MSM_PMEM_AEC_AWB:
1084 case MSM_PMEM_AF:
1085 rc = msm_pmem_table_add(&sync->stats, pinfo);
1086 break;
1087
1088 default:
1089 rc = -EINVAL;
1090 break;
1091 }
1092
1093 return rc;
1094}
1095
1096static int msm_register_pmem(struct msm_sync *sync, void __user *arg)
1097{
1098 struct msm_pmem_info info;
1099
1100 if (copy_from_user(&info, arg, sizeof(info))) {
1101 ERR_COPY_FROM_USER();
1102 return -EFAULT;
1103 }
1104
1105 return __msm_register_pmem(sync, &info);
1106}
1107
1108static int msm_stats_axi_cfg(struct msm_sync *sync,
1109 struct msm_vfe_cfg_cmd *cfgcmd)
1110{
1111 int rc = -EIO;
1112 struct axidata axi_data;
1113 void *data = &axi_data;
1114
1115 struct msm_pmem_region region[3];
1116 int pmem_type = MSM_PMEM_MAX;
1117
1118 memset(&axi_data, 0, sizeof(axi_data));
1119
1120 switch (cfgcmd->cmd_type) {
1121 case CMD_STATS_AXI_CFG:
1122 pmem_type = MSM_PMEM_AEC_AWB;
1123 break;
1124 case CMD_STATS_AF_AXI_CFG:
1125 pmem_type = MSM_PMEM_AF;
1126 break;
1127 case CMD_GENERAL:
1128 data = NULL;
1129 break;
1130 default:
1131 pr_err("%s: unknown command type %d\n",
451ff373 1132 __func__, cfgcmd->cmd_type);
eb7b797b
BS
1133 return -EINVAL;
1134 }
1135
1136 if (cfgcmd->cmd_type != CMD_GENERAL) {
1137 axi_data.bufnum1 =
1138 msm_pmem_region_lookup(&sync->stats, pmem_type,
1139 &region[0], NUM_WB_EXP_STAT_OUTPUT_BUFFERS);
1140 if (!axi_data.bufnum1) {
451ff373 1141 pr_err("%s: pmem region lookup error\n", __func__);
eb7b797b
BS
1142 return -EINVAL;
1143 }
1144 axi_data.region = &region[0];
1145 }
1146
1147 /* send the AEC/AWB STATS configuration command to driver */
1148 if (sync->vfefn.vfe_config)
1149 rc = sync->vfefn.vfe_config(cfgcmd, &axi_data);
1150
1151 return rc;
1152}
1153
1154static int msm_put_stats_buffer(struct msm_sync *sync, void __user *arg)
1155{
1156 int rc = -EIO;
1157
1158 struct msm_stats_buf buf;
1159 unsigned long pphy;
1160 struct msm_vfe_cfg_cmd cfgcmd;
1161
1162 if (copy_from_user(&buf, arg,
1163 sizeof(struct msm_stats_buf))) {
1164 ERR_COPY_FROM_USER();
1165 return -EFAULT;
1166 }
1167
1168 CDBG("msm_put_stats_buffer\n");
1169 pphy = msm_pmem_stats_vtop_lookup(sync, buf.buffer, buf.fd);
1170
1171 if (pphy != 0) {
1172 if (buf.type == STAT_AEAW)
1173 cfgcmd.cmd_type = CMD_STATS_BUF_RELEASE;
1174 else if (buf.type == STAT_AF)
1175 cfgcmd.cmd_type = CMD_STATS_AF_BUF_RELEASE;
1176 else {
1177 pr_err("%s: invalid buf type %d\n",
451ff373 1178 __func__,
eb7b797b
BS
1179 buf.type);
1180 rc = -EINVAL;
1181 goto put_done;
1182 }
1183
1184 cfgcmd.value = (void *)&buf;
1185
1186 if (sync->vfefn.vfe_config) {
1187 rc = sync->vfefn.vfe_config(&cfgcmd, &pphy);
1188 if (rc < 0)
1189 pr_err("msm_put_stats_buffer: "\
1190 "vfe_config err %d\n", rc);
1191 } else
1192 pr_err("msm_put_stats_buffer: vfe_config is NULL\n");
1193 } else {
1194 pr_err("msm_put_stats_buffer: NULL physical address\n");
1195 rc = -EINVAL;
1196 }
1197
1198put_done:
1199 return rc;
1200}
1201
1202static int msm_axi_config(struct msm_sync *sync, void __user *arg)
1203{
1204 struct msm_vfe_cfg_cmd cfgcmd;
1205
1206 if (copy_from_user(&cfgcmd, arg, sizeof(cfgcmd))) {
1207 ERR_COPY_FROM_USER();
1208 return -EFAULT;
1209 }
1210
1211 switch (cfgcmd.cmd_type) {
1212 case CMD_AXI_CFG_OUT1:
1213 case CMD_AXI_CFG_OUT2:
1214 case CMD_AXI_CFG_SNAP_O1_AND_O2:
1215 case CMD_RAW_PICT_AXI_CFG:
1216 return msm_frame_axi_cfg(sync, &cfgcmd);
1217
1218 case CMD_STATS_AXI_CFG:
1219 case CMD_STATS_AF_AXI_CFG:
1220 return msm_stats_axi_cfg(sync, &cfgcmd);
1221
1222 default:
1223 pr_err("%s: unknown command type %d\n",
451ff373 1224 __func__,
eb7b797b
BS
1225 cfgcmd.cmd_type);
1226 return -EINVAL;
1227 }
1228
1229 return 0;
1230}
1231
1232static int __msm_get_pic(struct msm_sync *sync, struct msm_ctrl_cmd *ctrl)
1233{
1234 unsigned long flags;
1235 int rc = 0;
1236 int tm;
1237
1238 struct msm_queue_cmd *qcmd = NULL;
1239
1240 tm = (int)ctrl->timeout_ms;
1241
1242 rc = wait_event_interruptible_timeout(
1243 sync->pict_frame_wait,
1244 !list_empty_careful(&sync->pict_frame_q),
1245 msecs_to_jiffies(tm));
1246 if (list_empty_careful(&sync->pict_frame_q)) {
1247 if (rc == 0)
1248 return -ETIMEDOUT;
1249 if (rc < 0) {
1250 pr_err("msm_camera_get_picture, rc = %d\n", rc);
1251 return rc;
1252 }
1253 }
1254
1255 spin_lock_irqsave(&sync->pict_frame_q_lock, flags);
1256 BUG_ON(list_empty(&sync->pict_frame_q));
1257 qcmd = list_first_entry(&sync->pict_frame_q,
1258 struct msm_queue_cmd, list);
1259 list_del_init(&qcmd->list);
1260 spin_unlock_irqrestore(&sync->pict_frame_q_lock, flags);
1261
1262 if (qcmd->command != NULL) {
1263 struct msm_ctrl_cmd *q =
1264 (struct msm_ctrl_cmd *)qcmd->command;
1265 ctrl->type = q->type;
1266 ctrl->status = q->status;
1267 } else {
1268 ctrl->type = -1;
1269 ctrl->status = -1;
1270 }
1271
1272 kfree(qcmd);
1273 return rc;
1274}
1275
1276static int msm_get_pic(struct msm_sync *sync, void __user *arg)
1277{
1278 struct msm_ctrl_cmd ctrlcmd_t;
1279 int rc;
1280
1281 if (copy_from_user(&ctrlcmd_t,
1282 arg,
1283 sizeof(struct msm_ctrl_cmd))) {
1284 ERR_COPY_FROM_USER();
1285 return -EFAULT;
1286 }
1287
1288 rc = __msm_get_pic(sync, &ctrlcmd_t);
1289 if (rc < 0)
1290 return rc;
1291
1292 if (sync->croplen) {
1293 if (ctrlcmd_t.length < sync->croplen) {
1294 pr_err("msm_get_pic: invalid len %d\n",
1295 ctrlcmd_t.length);
1296 return -EINVAL;
1297 }
1298 if (copy_to_user(ctrlcmd_t.value,
1299 sync->cropinfo,
1300 sync->croplen)) {
1301 ERR_COPY_TO_USER();
1302 return -EFAULT;
1303 }
1304 }
1305
1306 if (copy_to_user((void *)arg,
1307 &ctrlcmd_t,
1308 sizeof(struct msm_ctrl_cmd))) {
1309 ERR_COPY_TO_USER();
1310 return -EFAULT;
1311 }
1312 return 0;
1313}
1314
1315static int msm_set_crop(struct msm_sync *sync, void __user *arg)
1316{
1317 struct crop_info crop;
1318
1319 if (copy_from_user(&crop,
1320 arg,
1321 sizeof(struct crop_info))) {
1322 ERR_COPY_FROM_USER();
1323 return -EFAULT;
1324 }
1325
1326 if (!sync->croplen) {
1327 sync->cropinfo = kmalloc(crop.len, GFP_KERNEL);
1328 if (!sync->cropinfo)
1329 return -ENOMEM;
1330 } else if (sync->croplen < crop.len)
1331 return -EINVAL;
1332
1333 if (copy_from_user(sync->cropinfo,
1334 crop.info,
1335 crop.len)) {
1336 ERR_COPY_FROM_USER();
1337 kfree(sync->cropinfo);
1338 return -EFAULT;
1339 }
1340
1341 sync->croplen = crop.len;
1342
1343 return 0;
1344}
1345
1346static int msm_pict_pp_done(struct msm_sync *sync, void __user *arg)
1347{
1348 struct msm_ctrl_cmd udata;
1349 struct msm_ctrl_cmd *ctrlcmd = NULL;
1350 struct msm_queue_cmd *qcmd = NULL;
1351 unsigned long flags;
1352 int rc = 0;
1353
1354 if (!sync->pict_pp)
1355 return -EINVAL;
1356
1357 if (copy_from_user(&udata, arg, sizeof(struct msm_ctrl_cmd))) {
1358 ERR_COPY_FROM_USER();
1359 rc = -EFAULT;
1360 goto pp_fail;
1361 }
1362
1363 qcmd = kmalloc(sizeof(struct msm_queue_cmd) +
1364 sizeof(struct msm_ctrl_cmd),
1365 GFP_KERNEL);
1366 if (!qcmd) {
1367 rc = -ENOMEM;
1368 goto pp_fail;
1369 }
1370
1371 qcmd->type = MSM_CAM_Q_VFE_MSG;
1372 qcmd->command = ctrlcmd = (struct msm_ctrl_cmd *)(qcmd + 1);
1373 memset(ctrlcmd, 0, sizeof(struct msm_ctrl_cmd));
1374 ctrlcmd->type = udata.type;
1375 ctrlcmd->status = udata.status;
1376
1377 spin_lock_irqsave(&sync->pict_frame_q_lock, flags);
1378 list_add_tail(&qcmd->list, &sync->pict_frame_q);
1379 spin_unlock_irqrestore(&sync->pict_frame_q_lock, flags);
1380 wake_up(&sync->pict_frame_wait);
1381
1382pp_fail:
1383 return rc;
1384}
1385
1386static long msm_ioctl_common(struct msm_device *pmsm,
1387 unsigned int cmd,
1388 void __user *argp)
1389{
1390 CDBG("msm_ioctl_common\n");
1391 switch (cmd) {
1392 case MSM_CAM_IOCTL_REGISTER_PMEM:
1393 return msm_register_pmem(pmsm->sync, argp);
1394 case MSM_CAM_IOCTL_UNREGISTER_PMEM:
1395 return msm_pmem_table_del(pmsm->sync, argp);
1396 default:
1397 return -EINVAL;
1398 }
1399}
1400
1401static long msm_ioctl_config(struct file *filep, unsigned int cmd,
1402 unsigned long arg)
1403{
1404 int rc = -EINVAL;
1405 void __user *argp = (void __user *)arg;
1406 struct msm_device *pmsm = filep->private_data;
1407
1408 CDBG("msm_ioctl_config cmd = %d\n", _IOC_NR(cmd));
1409
1410 switch (cmd) {
1411 case MSM_CAM_IOCTL_GET_SENSOR_INFO:
1412 rc = msm_get_sensor_info(pmsm->sync, argp);
1413 break;
1414
1415 case MSM_CAM_IOCTL_CONFIG_VFE:
1416 /* Coming from config thread for update */
1417 rc = msm_config_vfe(pmsm->sync, argp);
1418 break;
1419
1420 case MSM_CAM_IOCTL_GET_STATS:
1421 /* Coming from config thread wait
1422 * for vfe statistics and control requests */
1423 rc = msm_get_stats(pmsm->sync, argp);
1424 break;
1425
1426 case MSM_CAM_IOCTL_ENABLE_VFE:
1427 /* This request comes from control thread:
1428 * enable either QCAMTASK or VFETASK */
1429 rc = msm_enable_vfe(pmsm->sync, argp);
1430 break;
1431
1432 case MSM_CAM_IOCTL_DISABLE_VFE:
1433 /* This request comes from control thread:
1434 * disable either QCAMTASK or VFETASK */
1435 rc = msm_disable_vfe(pmsm->sync, argp);
1436 break;
1437
1438 case MSM_CAM_IOCTL_VFE_APPS_RESET:
1439 msm_camio_vfe_blk_reset();
1440 rc = 0;
1441 break;
1442
1443 case MSM_CAM_IOCTL_RELEASE_STATS_BUFFER:
1444 rc = msm_put_stats_buffer(pmsm->sync, argp);
1445 break;
1446
1447 case MSM_CAM_IOCTL_AXI_CONFIG:
1448 rc = msm_axi_config(pmsm->sync, argp);
1449 break;
1450
1451 case MSM_CAM_IOCTL_SET_CROP:
1452 rc = msm_set_crop(pmsm->sync, argp);
1453 break;
1454
1455 case MSM_CAM_IOCTL_PICT_PP: {
1456 uint8_t enable;
1457 if (copy_from_user(&enable, argp, sizeof(enable))) {
1458 ERR_COPY_FROM_USER();
1459 rc = -EFAULT;
1460 } else {
1461 pmsm->sync->pict_pp = enable;
1462 rc = 0;
1463 }
1464 break;
1465 }
1466
1467 case MSM_CAM_IOCTL_PICT_PP_DONE:
1468 rc = msm_pict_pp_done(pmsm->sync, argp);
1469 break;
1470
1471 case MSM_CAM_IOCTL_SENSOR_IO_CFG:
1472 rc = pmsm->sync->sctrl.s_config(argp);
1473 break;
1474
1475 case MSM_CAM_IOCTL_FLASH_LED_CFG: {
1476 uint32_t led_state;
1477 if (copy_from_user(&led_state, argp, sizeof(led_state))) {
1478 ERR_COPY_FROM_USER();
1479 rc = -EFAULT;
1480 } else
1481 rc = msm_camera_flash_set_led_state(led_state);
1482 break;
1483 }
1484
1485 default:
1486 rc = msm_ioctl_common(pmsm, cmd, argp);
1487 break;
1488 }
1489
1490 CDBG("msm_ioctl_config cmd = %d DONE\n", _IOC_NR(cmd));
1491 return rc;
1492}
1493
1494static int msm_unblock_poll_frame(struct msm_sync *);
1495
1496static long msm_ioctl_frame(struct file *filep, unsigned int cmd,
1497 unsigned long arg)
1498{
1499 int rc = -EINVAL;
1500 void __user *argp = (void __user *)arg;
1501 struct msm_device *pmsm = filep->private_data;
1502
1503
1504 switch (cmd) {
1505 case MSM_CAM_IOCTL_GETFRAME:
1506 /* Coming from frame thread to get frame
1507 * after SELECT is done */
1508 rc = msm_get_frame(pmsm->sync, argp);
1509 break;
1510 case MSM_CAM_IOCTL_RELEASE_FRAME_BUFFER:
1511 rc = msm_put_frame_buffer(pmsm->sync, argp);
1512 break;
1513 case MSM_CAM_IOCTL_UNBLOCK_POLL_FRAME:
1514 rc = msm_unblock_poll_frame(pmsm->sync);
1515 break;
1516 default:
1517 break;
1518 }
1519
1520 return rc;
1521}
1522
1523
1524static long msm_ioctl_control(struct file *filep, unsigned int cmd,
1525 unsigned long arg)
1526{
1527 int rc = -EINVAL;
1528 void __user *argp = (void __user *)arg;
1529 struct msm_control_device *ctrl_pmsm = filep->private_data;
1530 struct msm_device *pmsm = ctrl_pmsm->pmsm;
1531
1532 switch (cmd) {
1533 case MSM_CAM_IOCTL_CTRL_COMMAND:
1534 /* Coming from control thread, may need to wait for
1535 * command status */
1536 rc = msm_control(ctrl_pmsm, 1, argp);
1537 break;
1538 case MSM_CAM_IOCTL_CTRL_COMMAND_2:
1539 /* Sends a message, returns immediately */
1540 rc = msm_control(ctrl_pmsm, 0, argp);
1541 break;
1542 case MSM_CAM_IOCTL_CTRL_CMD_DONE:
1543 /* Config thread calls the control thread to notify it
1544 * of the result of a MSM_CAM_IOCTL_CTRL_COMMAND.
1545 */
1546 rc = msm_ctrl_cmd_done(ctrl_pmsm, argp);
1547 break;
1548 case MSM_CAM_IOCTL_GET_PICTURE:
1549 rc = msm_get_pic(pmsm->sync, argp);
1550 break;
1551 default:
1552 rc = msm_ioctl_common(pmsm, cmd, argp);
1553 break;
1554 }
1555
1556 return rc;
1557}
1558
1559static int __msm_release(struct msm_sync *sync)
1560{
1561 struct msm_pmem_region *region;
1562 struct hlist_node *hnode;
1563 struct hlist_node *n;
1564
1565 mutex_lock(&sync->lock);
1566 if (sync->opencnt)
1567 sync->opencnt--;
1568
1569 if (!sync->opencnt) {
1570 /* need to clean up system resource */
1571 if (sync->vfefn.vfe_release)
1572 sync->vfefn.vfe_release(sync->pdev);
1573
1574 if (sync->cropinfo) {
1575 kfree(sync->cropinfo);
1576 sync->cropinfo = NULL;
1577 sync->croplen = 0;
1578 }
1579
1580 hlist_for_each_entry_safe(region, hnode, n,
1581 &sync->frame, list) {
1582 hlist_del(hnode);
1583 put_pmem_file(region->file);
1584 kfree(region);
1585 }
1586
1587 hlist_for_each_entry_safe(region, hnode, n,
1588 &sync->stats, list) {
1589 hlist_del(hnode);
1590 put_pmem_file(region->file);
1591 kfree(region);
1592 }
1593
1594 MSM_DRAIN_QUEUE(sync, msg_event_q);
1595 MSM_DRAIN_QUEUE(sync, prev_frame_q);
1596 MSM_DRAIN_QUEUE(sync, pict_frame_q);
1597
1598 sync->sctrl.s_release();
eb7b797b
BS
1599
1600 sync->apps_id = NULL;
1601 CDBG("msm_release completed!\n");
1602 }
1603 mutex_unlock(&sync->lock);
1604
1605 return 0;
1606}
1607
1608static int msm_release_config(struct inode *node, struct file *filep)
1609{
1610 int rc;
1611 struct msm_device *pmsm = filep->private_data;
1612 printk("msm_camera: RELEASE %s\n", filep->f_path.dentry->d_name.name);
1613 rc = __msm_release(pmsm->sync);
1614 atomic_set(&pmsm->opened, 0);
1615 return rc;
1616}
1617
1618static int msm_release_control(struct inode *node, struct file *filep)
1619{
1620 int rc;
1621 struct msm_control_device *ctrl_pmsm = filep->private_data;
1622 struct msm_device *pmsm = ctrl_pmsm->pmsm;
df84f941
CC
1623 printk(KERN_INFO "msm_camera: RELEASE %s\n",
1624 filep->f_path.dentry->d_name.name);
eb7b797b
BS
1625 rc = __msm_release(pmsm->sync);
1626 if (!rc) {
1627 MSM_DRAIN_QUEUE(&ctrl_pmsm->ctrl_q, ctrl_status_q);
1628 MSM_DRAIN_QUEUE(pmsm->sync, pict_frame_q);
1629 }
1630 kfree(ctrl_pmsm);
1631 return rc;
1632}
1633
1634static int msm_release_frame(struct inode *node, struct file *filep)
1635{
1636 int rc;
1637 struct msm_device *pmsm = filep->private_data;
df84f941
CC
1638 printk(KERN_INFO "msm_camera: RELEASE %s\n",
1639 filep->f_path.dentry->d_name.name);
eb7b797b
BS
1640 rc = __msm_release(pmsm->sync);
1641 if (!rc) {
1642 MSM_DRAIN_QUEUE(pmsm->sync, prev_frame_q);
1643 atomic_set(&pmsm->opened, 0);
1644 }
1645 return rc;
1646}
1647
1648static int msm_unblock_poll_frame(struct msm_sync *sync)
1649{
1650 unsigned long flags;
1651 CDBG("msm_unblock_poll_frame\n");
1652 spin_lock_irqsave(&sync->prev_frame_q_lock, flags);
1653 sync->unblock_poll_frame = 1;
1654 wake_up(&sync->prev_frame_wait);
1655 spin_unlock_irqrestore(&sync->prev_frame_q_lock, flags);
1656 return 0;
1657}
1658
1659static unsigned int __msm_poll_frame(struct msm_sync *sync,
1660 struct file *filep,
1661 struct poll_table_struct *pll_table)
1662{
1663 int rc = 0;
1664 unsigned long flags;
1665
1666 poll_wait(filep, &sync->prev_frame_wait, pll_table);
1667
1668 spin_lock_irqsave(&sync->prev_frame_q_lock, flags);
1669 if (!list_empty_careful(&sync->prev_frame_q))
1670 /* frame ready */
1671 rc = POLLIN | POLLRDNORM;
1672 if (sync->unblock_poll_frame) {
1673 CDBG("%s: sync->unblock_poll_frame is true\n", __func__);
1674 rc |= POLLPRI;
1675 sync->unblock_poll_frame = 0;
1676 }
1677 spin_unlock_irqrestore(&sync->prev_frame_q_lock, flags);
1678
1679 return rc;
1680}
1681
1682static unsigned int msm_poll_frame(struct file *filep,
1683 struct poll_table_struct *pll_table)
1684{
1685 struct msm_device *pmsm = filep->private_data;
1686 return __msm_poll_frame(pmsm->sync, filep, pll_table);
1687}
1688
1689/*
1690 * This function executes in interrupt context.
1691 */
1692
1693static void *msm_vfe_sync_alloc(int size,
1694 void *syncdata __attribute__((unused)))
1695{
1696 struct msm_queue_cmd *qcmd =
1697 kmalloc(sizeof(struct msm_queue_cmd) + size, GFP_ATOMIC);
1698 return qcmd ? qcmd + 1 : NULL;
1699}
1700
1701/*
1702 * This function executes in interrupt context.
1703 */
1704
1705static void msm_vfe_sync(struct msm_vfe_resp *vdata,
1706 enum msm_queue qtype, void *syncdata)
1707{
1708 struct msm_queue_cmd *qcmd = NULL;
1709 struct msm_queue_cmd *qcmd_frame = NULL;
1710 struct msm_vfe_phy_info *fphy;
1711
1712 unsigned long flags;
1713 struct msm_sync *sync = (struct msm_sync *)syncdata;
1714 if (!sync) {
1715 pr_err("msm_camera: no context in dsp callback.\n");
1716 return;
1717 }
1718
1719 qcmd = ((struct msm_queue_cmd *)vdata) - 1;
1720 qcmd->type = qtype;
1721
1722 if (qtype == MSM_CAM_Q_VFE_MSG) {
451ff373 1723 switch (vdata->type) {
eb7b797b
BS
1724 case VFE_MSG_OUTPUT1:
1725 case VFE_MSG_OUTPUT2:
1726 qcmd_frame =
1727 kmalloc(sizeof(struct msm_queue_cmd) +
1728 sizeof(struct msm_vfe_phy_info),
1729 GFP_ATOMIC);
1730 if (!qcmd_frame)
1731 goto mem_fail;
1732 fphy = (struct msm_vfe_phy_info *)(qcmd_frame + 1);
1733 *fphy = vdata->phy;
1734
1735 qcmd_frame->type = MSM_CAM_Q_VFE_MSG;
1736 qcmd_frame->command = fphy;
1737
1738 CDBG("qcmd_frame= 0x%x phy_y= 0x%x, phy_cbcr= 0x%x\n",
1739 (int) qcmd_frame, fphy->y_phy, fphy->cbcr_phy);
1740
1741 spin_lock_irqsave(&sync->prev_frame_q_lock, flags);
1742 list_add_tail(&qcmd_frame->list, &sync->prev_frame_q);
1743 wake_up(&sync->prev_frame_wait);
1744 spin_unlock_irqrestore(&sync->prev_frame_q_lock, flags);
1745 CDBG("woke up frame thread\n");
1746 break;
1747 case VFE_MSG_SNAPSHOT:
1748 if (sync->pict_pp)
1749 break;
1750
1751 CDBG("snapshot pp = %d\n", sync->pict_pp);
1752 qcmd_frame =
1753 kmalloc(sizeof(struct msm_queue_cmd),
1754 GFP_ATOMIC);
1755 if (!qcmd_frame)
1756 goto mem_fail;
1757 qcmd_frame->type = MSM_CAM_Q_VFE_MSG;
1758 qcmd_frame->command = NULL;
1759 spin_lock_irqsave(&sync->pict_frame_q_lock,
1760 flags);
1761 list_add_tail(&qcmd_frame->list, &sync->pict_frame_q);
1762 wake_up(&sync->pict_frame_wait);
1763 spin_unlock_irqrestore(&sync->pict_frame_q_lock, flags);
1764 CDBG("woke up picture thread\n");
1765 break;
1766 default:
1767 CDBG("%s: qtype = %d not handled\n",
1768 __func__, vdata->type);
1769 break;
1770 }
1771 }
1772
1773 qcmd->command = (void *)vdata;
1774 CDBG("vdata->type = %d\n", vdata->type);
1775
1776 spin_lock_irqsave(&sync->msg_event_q_lock, flags);
1777 list_add_tail(&qcmd->list, &sync->msg_event_q);
1778 wake_up(&sync->msg_event_wait);
1779 spin_unlock_irqrestore(&sync->msg_event_q_lock, flags);
1780 CDBG("woke up config thread\n");
1781 return;
1782
1783mem_fail:
1784 kfree(qcmd);
1785}
1786
1787static struct msm_vfe_callback msm_vfe_s = {
1788 .vfe_resp = msm_vfe_sync,
1789 .vfe_alloc = msm_vfe_sync_alloc,
1790};
1791
1792static int __msm_open(struct msm_sync *sync, const char *const apps_id)
1793{
1794 int rc = 0;
1795
1796 mutex_lock(&sync->lock);
1797 if (sync->apps_id && strcmp(sync->apps_id, apps_id)) {
1798 pr_err("msm_camera(%s): sensor %s is already opened for %s\n",
1799 apps_id,
1800 sync->sdata->sensor_name,
1801 sync->apps_id);
1802 rc = -EBUSY;
1803 goto msm_open_done;
1804 }
1805
1806 sync->apps_id = apps_id;
1807
1808 if (!sync->opencnt) {
eb7b797b
BS
1809
1810 msm_camvfe_fn_init(&sync->vfefn, sync);
1811 if (sync->vfefn.vfe_init) {
1812 rc = sync->vfefn.vfe_init(&msm_vfe_s,
1813 sync->pdev);
1814 if (rc < 0) {
1815 pr_err("vfe_init failed at %d\n", rc);
1816 goto msm_open_done;
1817 }
1818 rc = sync->sctrl.s_init(sync->sdata);
1819 if (rc < 0) {
1820 pr_err("sensor init failed: %d\n", rc);
1821 goto msm_open_done;
1822 }
1823 } else {
1824 pr_err("no sensor init func\n");
1825 rc = -ENODEV;
1826 goto msm_open_done;
1827 }
1828
1829 if (rc >= 0) {
1830 INIT_HLIST_HEAD(&sync->frame);
1831 INIT_HLIST_HEAD(&sync->stats);
1832 sync->unblock_poll_frame = 0;
1833 }
1834 }
1835 sync->opencnt++;
1836
1837msm_open_done:
1838 mutex_unlock(&sync->lock);
1839 return rc;
1840}
1841
1842static int msm_open_common(struct inode *inode, struct file *filep,
1843 int once)
1844{
1845 int rc;
1846 struct msm_device *pmsm =
1847 container_of(inode->i_cdev, struct msm_device, cdev);
1848
1849 CDBG("msm_camera: open %s\n", filep->f_path.dentry->d_name.name);
1850
1851 if (atomic_cmpxchg(&pmsm->opened, 0, 1) && once) {
1852 pr_err("msm_camera: %s is already opened.\n",
1853 filep->f_path.dentry->d_name.name);
1854 return -EBUSY;
1855 }
1856
1857 rc = nonseekable_open(inode, filep);
1858 if (rc < 0) {
1859 pr_err("msm_open: nonseekable_open error %d\n", rc);
1860 return rc;
1861 }
1862
1863 rc = __msm_open(pmsm->sync, MSM_APPS_ID_PROP);
1864 if (rc < 0)
1865 return rc;
1866
1867 filep->private_data = pmsm;
1868
1869 CDBG("msm_open() open: rc = %d\n", rc);
1870 return rc;
1871}
1872
1873static int msm_open(struct inode *inode, struct file *filep)
1874{
1875 return msm_open_common(inode, filep, 1);
1876}
1877
1878static int msm_open_control(struct inode *inode, struct file *filep)
1879{
1880 int rc;
1881
1882 struct msm_control_device *ctrl_pmsm =
1883 kmalloc(sizeof(struct msm_control_device), GFP_KERNEL);
1884 if (!ctrl_pmsm)
1885 return -ENOMEM;
1886
1887 rc = msm_open_common(inode, filep, 0);
ccf972bd
PM
1888 if (rc < 0) {
1889 kfree(ctrl_pmsm);
eb7b797b 1890 return rc;
ccf972bd 1891 }
eb7b797b
BS
1892
1893 ctrl_pmsm->pmsm = filep->private_data;
1894 filep->private_data = ctrl_pmsm;
1895 spin_lock_init(&ctrl_pmsm->ctrl_q.ctrl_status_q_lock);
1896 INIT_LIST_HEAD(&ctrl_pmsm->ctrl_q.ctrl_status_q);
1897 init_waitqueue_head(&ctrl_pmsm->ctrl_q.ctrl_status_wait);
1898
1899 CDBG("msm_open() open: rc = %d\n", rc);
1900 return rc;
1901}
1902
1903static int __msm_v4l2_control(struct msm_sync *sync,
1904 struct msm_ctrl_cmd *out)
1905{
1906 int rc = 0;
1907
1908 struct msm_queue_cmd *qcmd = NULL, *rcmd = NULL;
1909 struct msm_ctrl_cmd *ctrl;
1910 struct msm_control_device_queue FIXME;
1911
1912 /* wake up config thread, 4 is for V4L2 application */
1913 qcmd = kmalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL);
1914 if (!qcmd) {
1915 pr_err("msm_control: cannot allocate buffer\n");
1916 rc = -ENOMEM;
1917 goto end;
1918 }
1919 qcmd->type = MSM_CAM_Q_V4L2_REQ;
1920 qcmd->command = out;
1921
1922 rcmd = __msm_control(sync, &FIXME, qcmd, out->timeout_ms);
1923 if (IS_ERR(rcmd)) {
1924 rc = PTR_ERR(rcmd);
1925 goto end;
1926 }
1927
1928 ctrl = (struct msm_ctrl_cmd *)(rcmd->command);
1929 /* FIXME: we should just set out->length = ctrl->length; */
1930 BUG_ON(out->length < ctrl->length);
1931 memcpy(out->value, ctrl->value, ctrl->length);
1932
1933end:
451ff373 1934 kfree(rcmd);
eb7b797b
BS
1935 CDBG("__msm_v4l2_control: end rc = %d\n", rc);
1936 return rc;
1937}
1938
1939static const struct file_operations msm_fops_config = {
1940 .owner = THIS_MODULE,
1941 .open = msm_open,
1942 .unlocked_ioctl = msm_ioctl_config,
1943 .release = msm_release_config,
6038f373 1944 .llseek = no_llseek,
eb7b797b
BS
1945};
1946
1947static const struct file_operations msm_fops_control = {
1948 .owner = THIS_MODULE,
1949 .open = msm_open_control,
1950 .unlocked_ioctl = msm_ioctl_control,
1951 .release = msm_release_control,
6038f373 1952 .llseek = no_llseek,
eb7b797b
BS
1953};
1954
1955static const struct file_operations msm_fops_frame = {
1956 .owner = THIS_MODULE,
1957 .open = msm_open,
1958 .unlocked_ioctl = msm_ioctl_frame,
1959 .release = msm_release_frame,
1960 .poll = msm_poll_frame,
6038f373 1961 .llseek = no_llseek,
eb7b797b
BS
1962};
1963
1964static int msm_setup_cdev(struct msm_device *msm,
1965 int node,
1966 dev_t devno,
1967 const char *suffix,
1968 const struct file_operations *fops)
1969{
1970 int rc = -ENODEV;
1971
1972 struct device *device =
1973 device_create(msm_class, NULL,
1974 devno, NULL,
1975 "%s%d", suffix, node);
1976
1977 if (IS_ERR(device)) {
1978 rc = PTR_ERR(device);
1979 pr_err("msm_camera: error creating device: %d\n", rc);
1980 return rc;
1981 }
1982
1983 cdev_init(&msm->cdev, fops);
1984 msm->cdev.owner = THIS_MODULE;
1985
1986 rc = cdev_add(&msm->cdev, devno, 1);
1987 if (rc < 0) {
1988 pr_err("msm_camera: error adding cdev: %d\n", rc);
1989 device_destroy(msm_class, devno);
1990 return rc;
1991 }
1992
1993 return rc;
1994}
1995
1996static int msm_tear_down_cdev(struct msm_device *msm, dev_t devno)
1997{
1998 cdev_del(&msm->cdev);
1999 device_destroy(msm_class, devno);
2000 return 0;
2001}
2002
2003int msm_v4l2_register(struct msm_v4l2_driver *drv)
2004{
2005 /* FIXME: support multiple sensors */
2006 if (list_empty(&msm_sensors))
2007 return -ENODEV;
2008
2009 drv->sync = list_first_entry(&msm_sensors, struct msm_sync, list);
2010 drv->open = __msm_open;
2011 drv->release = __msm_release;
2012 drv->ctrl = __msm_v4l2_control;
2013 drv->reg_pmem = __msm_register_pmem;
2014 drv->get_frame = __msm_get_frame;
2015 drv->put_frame = __msm_put_frame_buf;
2016 drv->get_pict = __msm_get_pic;
2017 drv->drv_poll = __msm_poll_frame;
2018
2019 return 0;
2020}
2021EXPORT_SYMBOL(msm_v4l2_register);
2022
2023int msm_v4l2_unregister(struct msm_v4l2_driver *drv)
2024{
2025 drv->sync = NULL;
2026 return 0;
2027}
2028EXPORT_SYMBOL(msm_v4l2_unregister);
2029
2030static int msm_sync_init(struct msm_sync *sync,
2031 struct platform_device *pdev,
2032 int (*sensor_probe)(const struct msm_camera_sensor_info *,
2033 struct msm_sensor_ctrl *))
2034{
2035 int rc = 0;
2036 struct msm_sensor_ctrl sctrl;
2037 sync->sdata = pdev->dev.platform_data;
2038
2039 spin_lock_init(&sync->msg_event_q_lock);
2040 INIT_LIST_HEAD(&sync->msg_event_q);
2041 init_waitqueue_head(&sync->msg_event_wait);
2042
2043 spin_lock_init(&sync->prev_frame_q_lock);
2044 INIT_LIST_HEAD(&sync->prev_frame_q);
2045 init_waitqueue_head(&sync->prev_frame_wait);
2046
2047 spin_lock_init(&sync->pict_frame_q_lock);
2048 INIT_LIST_HEAD(&sync->pict_frame_q);
2049 init_waitqueue_head(&sync->pict_frame_wait);
2050
eb7b797b
BS
2051 rc = msm_camio_probe_on(pdev);
2052 if (rc < 0)
2053 return rc;
2054 rc = sensor_probe(sync->sdata, &sctrl);
2055 if (rc >= 0) {
2056 sync->pdev = pdev;
2057 sync->sctrl = sctrl;
2058 }
2059 msm_camio_probe_off(pdev);
2060 if (rc < 0) {
2061 pr_err("msm_camera: failed to initialize %s\n",
2062 sync->sdata->sensor_name);
eb7b797b
BS
2063 return rc;
2064 }
2065
2066 sync->opencnt = 0;
2067 mutex_init(&sync->lock);
2068 CDBG("initialized %s\n", sync->sdata->sensor_name);
2069 return rc;
2070}
2071
2072static int msm_sync_destroy(struct msm_sync *sync)
2073{
eb7b797b
BS
2074 return 0;
2075}
2076
2077static int msm_device_init(struct msm_device *pmsm,
2078 struct msm_sync *sync,
2079 int node)
2080{
2081 int dev_num = 3 * node;
2082 int rc = msm_setup_cdev(pmsm, node,
2083 MKDEV(MAJOR(msm_devno), dev_num),
2084 "control", &msm_fops_control);
2085 if (rc < 0) {
2086 pr_err("error creating control node: %d\n", rc);
2087 return rc;
2088 }
2089
2090 rc = msm_setup_cdev(pmsm + 1, node,
2091 MKDEV(MAJOR(msm_devno), dev_num + 1),
2092 "config", &msm_fops_config);
2093 if (rc < 0) {
2094 pr_err("error creating config node: %d\n", rc);
2095 msm_tear_down_cdev(pmsm, MKDEV(MAJOR(msm_devno),
2096 dev_num));
2097 return rc;
2098 }
2099
2100 rc = msm_setup_cdev(pmsm + 2, node,
2101 MKDEV(MAJOR(msm_devno), dev_num + 2),
2102 "frame", &msm_fops_frame);
2103 if (rc < 0) {
2104 pr_err("error creating frame node: %d\n", rc);
2105 msm_tear_down_cdev(pmsm,
2106 MKDEV(MAJOR(msm_devno), dev_num));
2107 msm_tear_down_cdev(pmsm + 1,
2108 MKDEV(MAJOR(msm_devno), dev_num + 1));
2109 return rc;
2110 }
2111
2112 atomic_set(&pmsm[0].opened, 0);
2113 atomic_set(&pmsm[1].opened, 0);
2114 atomic_set(&pmsm[2].opened, 0);
2115
2116 pmsm[0].sync = sync;
2117 pmsm[1].sync = sync;
2118 pmsm[2].sync = sync;
2119
2120 return rc;
2121}
2122
2123int msm_camera_drv_start(struct platform_device *dev,
2124 int (*sensor_probe)(const struct msm_camera_sensor_info *,
2125 struct msm_sensor_ctrl *))
2126{
2127 struct msm_device *pmsm = NULL;
2128 struct msm_sync *sync;
2129 int rc = -ENODEV;
2130 static int camera_node;
2131
2132 if (camera_node >= MSM_MAX_CAMERA_SENSORS) {
2133 pr_err("msm_camera: too many camera sensors\n");
2134 return rc;
2135 }
2136
2137 if (!msm_class) {
2138 /* There are three device nodes per sensor */
2139 rc = alloc_chrdev_region(&msm_devno, 0,
2140 3 * MSM_MAX_CAMERA_SENSORS,
2141 "msm_camera");
2142 if (rc < 0) {
2143 pr_err("msm_camera: failed to allocate chrdev: %d\n",
2144 rc);
2145 return rc;
2146 }
2147
2148 msm_class = class_create(THIS_MODULE, "msm_camera");
2149 if (IS_ERR(msm_class)) {
2150 rc = PTR_ERR(msm_class);
2151 pr_err("msm_camera: create device class failed: %d\n",
2152 rc);
2153 return rc;
2154 }
2155 }
2156
2157 pmsm = kzalloc(sizeof(struct msm_device) * 3 +
2158 sizeof(struct msm_sync), GFP_ATOMIC);
2159 if (!pmsm)
2160 return -ENOMEM;
2161 sync = (struct msm_sync *)(pmsm + 3);
2162
2163 rc = msm_sync_init(sync, dev, sensor_probe);
2164 if (rc < 0) {
2165 kfree(pmsm);
2166 return rc;
2167 }
2168
2169 CDBG("setting camera node %d\n", camera_node);
2170 rc = msm_device_init(pmsm, sync, camera_node);
2171 if (rc < 0) {
2172 msm_sync_destroy(sync);
2173 kfree(pmsm);
2174 return rc;
2175 }
2176
2177 camera_node++;
2178 list_add(&sync->list, &msm_sensors);
2179 return rc;
2180}
2181EXPORT_SYMBOL(msm_camera_drv_start);