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