blob: c9083334d946008688cdba0af6c0600beefcd7f4 [file] [log] [blame]
Jignesh Mehtaa06591f2012-10-31 17:18:08 -07001/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/of.h>
14#include <linux/module.h>
15#include <linux/workqueue.h>
16#include <linux/delay.h>
17#include <linux/types.h>
18#include <linux/list.h>
19#include <linux/ioctl.h>
20#include <linux/spinlock.h>
21#include <linux/proc_fs.h>
22#include <linux/atomic.h>
23#include <linux/wait.h>
24#include <linux/videodev2.h>
25#include <linux/msm_ion.h>
26#include <linux/iommu.h>
27#include <linux/platform_device.h>
28#include <media/v4l2-fh.h>
29#include "msm.h"
30#include "msm_vb2.h"
31#include "msm_sd.h"
32
33struct msm_queue_head {
34 struct list_head list;
35 spinlock_t lock;
36 int len;
37 int max;
38};
39
40/** msm_event:
41 *
42 * event sent by imaging server
43 **/
44struct msm_event {
45 struct video_device *vdev;
46 atomic_t on_heap;
47};
48
49struct msm_command {
50 struct list_head list;
51 struct v4l2_event event;
52 atomic_t on_heap;
53};
54
55/** struct msm_command_ack
56 *
57 * Object of command_ack_q, which is
58 * created per open operation
59 *
60 * contains struct msm_command
61 **/
62struct msm_command_ack {
63 struct list_head list;
64 struct msm_queue_head command_q;
65 wait_queue_head_t wait;
66 int stream_id;
67};
68
69struct msm_stream {
70 struct list_head list;
71
72 /* stream index per session, same
73 * as stream_id but set through s_parm */
74 unsigned int stream_id;
75
76 /* vb2 buffer handling */
77 struct vb2_queue *vb2_q;
78};
79
80struct msm_v4l2_subdev {
81 /* FIXME: for session close and error handling such
82 * as daemon shutdown */
83 int close_sequence;
84};
85
86struct msm_session {
87 struct list_head list;
88
89 /* session index */
90 unsigned int session_id;
91
92 /* event queue sent by imaging server */
93 struct msm_event event_q;
94
95 /* ACK by imaging server. Object type of
96 * struct msm_command_ack per open,
97 * assumption is application can send
98 * command on every opened video node */
99 struct msm_queue_head command_ack_q;
100
101 /* real streams(either data or metadate) owned by one
102 * session struct msm_stream */
103 struct msm_queue_head stream_q;
104};
105
106static struct v4l2_device *msm_v4l2_dev;
107
108static struct msm_queue_head *msm_session_q;
109
110/* config node envent queue */
111static struct v4l2_fh *msm_eventq;
112spinlock_t msm_eventq_lock;
113
114static struct pid *msm_pid;
115spinlock_t msm_pid_lock;
116
117#define msm_dequeue(queue, type, member) ({ \
118 unsigned long flags; \
119 struct msm_queue_head *__q = (queue); \
120 type *node = 0; \
121 spin_lock_irqsave(&__q->lock, flags); \
122 if (!list_empty(&__q->list)) { \
123 __q->len--; \
124 node = list_first_entry(&__q->list, \
125 type, member); \
126 if ((node) && (&node->member) && (&node->member.next)) \
127 list_del_init(&node->member); \
128 } \
129 spin_unlock_irqrestore(&__q->lock, flags); \
130 node; \
131})
132
133#define msm_delete_sd_entry(queue, type, member, q_node) ({ \
134 unsigned long flags; \
135 struct msm_queue_head *__q = (queue); \
136 type *node = 0; \
137 spin_lock_irqsave(&__q->lock, flags); \
138 if (!list_empty(&__q->list)) { \
139 list_for_each_entry(node, &__q->list, member) \
140 if (node->sd == q_node) { \
141 __q->len--; \
142 list_del_init(&node->member); \
143 kfree(node); \
144 break; \
145 } \
146 } \
147 spin_unlock_irqrestore(&__q->lock, flags); \
148})
149
150#define msm_delete_entry(queue, type, member, q_node) ({ \
151 unsigned long flags; \
152 struct msm_queue_head *__q = (queue); \
153 type *node = 0; \
154 spin_lock_irqsave(&__q->lock, flags); \
155 if (!list_empty(&__q->list)) { \
156 list_for_each_entry(node, &__q->list, member) \
157 if (node == q_node) { \
158 __q->len--; \
159 list_del_init(&node->member); \
160 kfree(node); \
161 break; \
162 } \
163 } \
164 spin_unlock_irqrestore(&__q->lock, flags); \
165})
166
167#define msm_queue_drain(queue, type, member) do { \
168 unsigned long flags; \
169 struct msm_queue_head *__q = (queue); \
170 type *node; \
171 spin_lock_irqsave(&__q->lock, flags); \
172 while (!list_empty(&__q->list)) { \
173 __q->len--; \
174 node = list_first_entry(&__q->list, \
175 type, member); \
176 if (node) { \
177 if (&node->member) \
178 list_del_init(&node->member); \
179 kfree(node); \
180 } \
181 } \
182 spin_unlock_irqrestore(&__q->lock, flags); \
183} while (0);
184
185typedef int (*msm_queue_func)(void *d1, void *d2);
186#define msm_queue_traverse_action(queue, type, member, func, data) do {\
187 unsigned long flags; \
188 struct msm_queue_head *__q = (queue); \
189 type *node = 0; \
190 msm_queue_func __f = (func); \
191 spin_lock_irqsave(&__q->lock, flags); \
192 if (!list_empty(&__q->list)) { \
193 list_for_each_entry(node, &__q->list, member) \
194 if (node && __f) { \
195 __f(node, data); \
196 } \
197 } \
198 spin_unlock_irqrestore(&__q->lock, flags); \
199} while (0)
200
201typedef int (*msm_queue_find_func)(void *d1, void *d2);
202#define msm_queue_find(queue, type, member, func, data) ({\
203 unsigned long flags; \
204 struct msm_queue_head *__q = (queue); \
205 type *node = 0; \
206 typeof(node) __ret = NULL; \
207 msm_queue_find_func __f = (func); \
208 spin_lock_irqsave(&__q->lock, flags); \
209 if (!list_empty(&__q->list)) { \
210 list_for_each_entry(node, &__q->list, member) \
211 if ((__f) && __f(node, data)) { \
212 __ret = node; \
213 break; \
214 } \
215 } \
216 spin_unlock_irqrestore(&__q->lock, flags); \
217 __ret; \
218})
219
220static void msm_init_queue(struct msm_queue_head *qhead)
221{
222 BUG_ON(!qhead);
223
224 INIT_LIST_HEAD(&qhead->list);
225 spin_lock_init(&qhead->lock);
226 qhead->len = 0;
227 qhead->max = 0;
228}
229
230static void msm_enqueue(struct msm_queue_head *qhead,
231 struct list_head *entry)
232{
233 unsigned long flags;
234 spin_lock_irqsave(&qhead->lock, flags);
235 qhead->len++;
236 if (qhead->len > qhead->max)
237 qhead->max = qhead->len;
238 list_add_tail(entry, &qhead->list);
239 spin_unlock_irqrestore(&qhead->lock, flags);
240}
241
242/* index = session id */
243static inline int __msm_queue_find_session(void *d1, void *d2)
244{
245 struct msm_session *session = d1;
246 return (session->session_id == *(unsigned int *)d2) ? 1 : 0;
247}
248
249static inline int __msm_queue_find_stream(void *d1, void *d2)
250{
251 struct msm_stream *stream = d1;
252 return (stream->stream_id == *(unsigned int *)d2) ? 1 : 0;
253}
254
255static inline int __msm_queue_find_command_ack_q(void *d1, void *d2)
256{
257 struct msm_command_ack *ack = d1;
258 return (ack->stream_id == *(unsigned int *)d2) ? 1 : 0;
259}
260
261int msm_create_stream(unsigned int session_id,
262 unsigned int stream_id, struct vb2_queue *q)
263{
264 struct msm_session *session;
265 struct msm_stream *stream;
266
267 session = msm_queue_find(msm_session_q, struct msm_session,
268 list, __msm_queue_find_session, &session_id);
269 if (!session)
270 return -EINVAL;
271
272 stream = kzalloc(sizeof(*stream), GFP_KERNEL);
273 if (!stream)
274 return -ENOMEM;
275
276 stream->stream_id = stream_id;
277 stream->vb2_q = q;
278
279 msm_enqueue(&session->stream_q, &stream->list);
280 session->stream_q.len++;
281
282 return 0;
283}
284
285void msm_delete_stream(unsigned int session_id, unsigned int stream_id)
286{
287 struct msm_session *session = NULL;
288 struct msm_stream *stream = NULL;
289
290 session = msm_queue_find(msm_session_q, struct msm_session,
291 list, __msm_queue_find_session, &session_id);
292 if (!session)
293 return;
294
295 stream = msm_queue_find(&session->stream_q, struct msm_stream,
296 list, __msm_queue_find_stream, &stream_id);
297 if (!stream)
298 return;
299
300 list_del_init(&stream->list);
301 session->stream_q.len--;
302 kfree(stream);
303}
304
305static void msm_sd_unregister_subdev(struct video_device *vdev)
306{
307 struct v4l2_subdev *sd = video_get_drvdata(vdev);
308 sd->devnode = NULL;
309 kfree(vdev);
310}
311
312static inline int __msm_sd_register_subdev(struct v4l2_subdev *sd)
313{
314 int rc = 0;
315 struct video_device *vdev;
316
317 if (!msm_v4l2_dev || !sd || !sd->name[0])
318 return -EINVAL;
319
320 rc = v4l2_device_register_subdev(msm_v4l2_dev, sd);
321 if (rc < 0)
322 return rc;
323
324 /* Register a device node for every subdev marked with the
325 * V4L2_SUBDEV_FL_HAS_DEVNODE flag.
326 */
327 if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE))
328 return rc;
329
330 vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
331 if (!vdev) {
332 rc = -ENOMEM;
333 goto clean_up;
334 }
335
336 video_set_drvdata(vdev, sd);
337 strlcpy(vdev->name, sd->name, sizeof(vdev->name));
338 vdev->v4l2_dev = msm_v4l2_dev;
339 vdev->fops = &v4l2_subdev_fops;
340 vdev->release = msm_sd_unregister_subdev;
341 rc = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1,
342 sd->owner);
343 if (rc < 0) {
344 kfree(vdev);
345 goto clean_up;
346 }
347
348#if defined(CONFIG_MEDIA_CONTROLLER)
349 sd->entity.info.v4l.major = VIDEO_MAJOR;
350 sd->entity.info.v4l.minor = vdev->minor;
351 sd->entity.name = video_device_node_name(vdev);
352#endif
353 sd->devnode = vdev;
354 return 0;
355
356clean_up:
357 if (sd->devnode)
358 video_unregister_device(sd->devnode);
359 return rc;
360}
361
362int msm_sd_register(struct msm_sd_subdev *msm_subdev)
363{
364 if (WARN_ON(!msm_subdev))
365 return -EINVAL;
366
367 if (WARN_ON(!msm_v4l2_dev) && WARN_ON(!msm_v4l2_dev->dev))
368 return -EIO;
369
370 return __msm_sd_register_subdev(&msm_subdev->sd);
371}
372
373int msm_sd_unregister(struct msm_sd_subdev *msm_subdev)
374{
375 if (WARN_ON(!msm_subdev))
376 return -EINVAL;
377
378 v4l2_device_unregister_subdev(&msm_subdev->sd);
379 return 0;
380}
381
382int msm_create_session(unsigned int session_id, struct video_device *vdev)
383{
384 struct msm_session *session = NULL;
385
386 if (!msm_session_q)
387 return -ENODEV;
388
389 session = msm_queue_find(msm_session_q, struct msm_session,
390 list, __msm_queue_find_session, &session_id);
391 if (session)
392 return -EINVAL;
393
394 session = kzalloc(sizeof(*session), GFP_KERNEL);
395 if (!session)
396 return -ENOMEM;
397
398 session->session_id = session_id;
399 session->event_q.vdev = vdev;
400 msm_init_queue(&session->command_ack_q);
401 msm_init_queue(&session->stream_q);
402 msm_enqueue(msm_session_q, &session->list);
403 return 0;
404}
405
406int msm_create_command_ack_q(unsigned int session_id, unsigned int stream_id)
407{
408 struct msm_session *session;
409 struct msm_command_ack *cmd_ack;
410
411 if (!msm_session_q)
412 return -ENODEV;
413
414 session = msm_queue_find(msm_session_q, struct msm_session,
415 list, __msm_queue_find_session, &session_id);
416 if (!session)
417 return -EINVAL;
418
419 cmd_ack = kzalloc(sizeof(*cmd_ack), GFP_KERNEL);
420 if (!cmd_ack)
421 return -ENOMEM;
422
423 msm_init_queue(&cmd_ack->command_q);
424 INIT_LIST_HEAD(&cmd_ack->list);
425 init_waitqueue_head(&cmd_ack->wait);
426 cmd_ack->stream_id = stream_id;
427
428 msm_enqueue(&session->command_ack_q, &cmd_ack->list);
429 session->command_ack_q.len++;
430
431 return 0;
432}
433
434void msm_delete_command_ack_q(unsigned int session_id, unsigned int stream_id)
435{
436 struct msm_session *session;
437 struct msm_command_ack *cmd_ack;
438
439 session = msm_queue_find(msm_session_q, struct msm_session,
440 list, __msm_queue_find_session, &session_id);
441 if (!session)
442 return;
443
444 cmd_ack = msm_queue_find(&session->command_ack_q,
445 struct msm_command_ack, list, __msm_queue_find_command_ack_q,
446 &stream_id);
447 if (!cmd_ack)
448 return;
449
450 msm_queue_drain(&cmd_ack->command_q, struct msm_command, list);
451}
452
453static inline int __msm_v4l2_subdev_shutdown(struct v4l2_subdev *sd)
454{
455 return 0;
456}
457
458static void msm_sd_try_shutdown(void)
459{
460 unsigned long flags;
461 struct v4l2_subdev *sd;
462
463 /* release all subdev's resource */
464 spin_lock_irqsave(&msm_v4l2_dev->lock, flags);
465 if (!list_empty(&msm_v4l2_dev->subdevs)) {
466 list_for_each_entry(sd, &msm_v4l2_dev->subdevs, list)
467 __msm_v4l2_subdev_shutdown(sd);
468 }
469 spin_unlock_irqrestore(&msm_v4l2_dev->lock, flags);
470}
471
472static inline int __msm_sd_close_session_streams(struct v4l2_subdev *sd,
473 struct msm_sd_close_ioctl *sd_close)
474{
475 v4l2_subdev_call(sd, core, ioctl,
476 MSM_SD_CLOSE_SESSION_AND_STREAM, &sd_close);
477
478 return 0;
479}
480
481static inline int __msm_destroy_session_streams(void *d1, void *d2)
482{
483 struct msm_stream *stream = d1;
484 struct msm_sd_close_ioctl *sd_close = d2;
485 struct v4l2_subdev *sd;
486 unsigned long flags;
487
488 sd_close->stream = stream->stream_id;
489
490 spin_lock_irqsave(&msm_v4l2_dev->lock, flags);
491 if (!list_empty(&msm_v4l2_dev->subdevs))
492 list_for_each_entry(sd, &msm_v4l2_dev->subdevs, list)
493 __msm_sd_close_session_streams(sd, sd_close);
494 spin_unlock_irqrestore(&msm_v4l2_dev->lock, flags);
495
496 return 0;
497}
498
499static void msm_destroy_session_streams(struct msm_session *session)
500{
501 struct msm_sd_close_ioctl sd_close;
502
503 /* to ensure error handling purpose, it needs to detach all subdevs
504 * which are being connected to streams */
505 if (!session)
506 return;
507
508 sd_close.session = session->session_id;
509
510 msm_queue_traverse_action(&session->stream_q, struct msm_stream, list,
511 __msm_destroy_session_streams, &sd_close);
512
513 msm_queue_drain(&session->stream_q, struct msm_stream, list);
514}
515
516static inline int __msm_remove_session_cmd_ack_q(void *d1, void *d2)
517{
518 struct msm_command_ack *cmd_ack = d1;
519
520 msm_queue_drain(&cmd_ack->command_q, struct msm_command, list);
521
522 return 0;
523}
524
525static void msm_remove_session_cmd_ack_q(struct msm_session *session)
526{
527 if (!session)
528 return;
529
530 /* to ensure error handling purpose, it needs to detach all subdevs
531 * which are being connected to streams */
532 msm_queue_traverse_action(&session->command_ack_q,
533 struct msm_command_ack, list,
534 __msm_remove_session_cmd_ack_q, NULL);
535
536 msm_queue_drain(&session->command_ack_q, struct msm_command_ack, list);
537}
538
539int msm_destroy_session(unsigned int session_id)
540{
541 struct msm_session *session;
542
543 session = msm_queue_find(msm_session_q, struct msm_session,
544 list, __msm_queue_find_session, &session_id);
545 if (!session)
546 return -EINVAL;
547
548 msm_destroy_session_streams(session);
549 msm_remove_session_cmd_ack_q(session);
550
551 msm_delete_entry(msm_session_q, struct msm_session,
552 list, session);
553
554 return 0;
555}
556
557static long msm_private_ioctl(struct file *file, void *fh,
558 bool valid_prio, int cmd, void *arg)
559{
560 int rc = 0;
561 struct msm_v4l2_event_data *event_data;
562 struct msm_session *session;
563 unsigned int session_id;
564 unsigned int stream_id;
565
566 event_data = (struct msm_v4l2_event_data *)
567 ((struct v4l2_event *)arg)->u.data;
568
569 session_id = event_data->session_id;
570 stream_id = event_data->stream_id;
571
572 session = msm_queue_find(msm_session_q, struct msm_session,
573 list, __msm_queue_find_session, &session_id);
574
575 if (!session)
576 return -EINVAL;
577
578 switch (cmd) {
579 case MSM_CAM_V4L2_IOCTL_NOTIFY: {
580 if (WARN_ON(!session->event_q.vdev)) {
581 rc = -EFAULT;
582 break;
583 }
584
585 v4l2_event_queue(session->event_q.vdev,
586 (struct v4l2_event *)arg);
587 }
588 break;
589
590 case MSM_CAM_V4L2_IOCTL_CMD_ACK: {
591 struct msm_command_ack *cmd_ack;
592 struct msm_command *ret_cmd;
593
594 ret_cmd = kzalloc(sizeof(*ret_cmd), GFP_KERNEL);
595 if (!ret_cmd) {
596 rc = -ENOMEM;
597 break;
598 }
599
600 cmd_ack = msm_queue_find(&session->command_ack_q,
601 struct msm_command_ack, list,
602 __msm_queue_find_command_ack_q,
603 &stream_id);
604 if (WARN_ON(!cmd_ack)) {
605 kfree(ret_cmd);
606 rc = -EFAULT;
607 break;
608 }
609
610 ret_cmd->event = *(struct v4l2_event *)arg;
611 msm_enqueue(&cmd_ack->command_q, &ret_cmd->list);
612 wake_up(&cmd_ack->wait);
613 }
614 break;
615
616 default:
617 rc = -ENOTTY;
618 break;
619 }
620
621 return rc;
622}
623
624static int msm_unsubscribe_event(struct v4l2_fh *fh,
625 struct v4l2_event_subscription *sub)
626{
627 return v4l2_event_unsubscribe(fh, sub);
628}
629
630static int msm_subscribe_event(struct v4l2_fh *fh,
631 struct v4l2_event_subscription *sub)
632{
633 return v4l2_event_subscribe(fh, sub, 5);
634}
635
636static const struct v4l2_ioctl_ops g_msm_ioctl_ops = {
637 .vidioc_subscribe_event = msm_subscribe_event,
638 .vidioc_unsubscribe_event = msm_unsubscribe_event,
639 .vidioc_default = msm_private_ioctl,
640};
641
642static unsigned int msm_poll(struct file *f,
643 struct poll_table_struct *pll_table)
644{
645 int rc = 0;
646 struct v4l2_fh *eventq = f->private_data;
647
648 BUG_ON(!eventq);
649
650 poll_wait(f, &eventq->wait, pll_table);
651
652 if (v4l2_event_pending(eventq))
653 rc = POLLIN | POLLRDNORM;
654
655 return rc;
656}
657
658/* something seriously wrong if msm_close is triggered
659 * !!! user space imaging server is shutdown !!!
660 */
661int msm_post_event(struct v4l2_event *event, int timeout)
662{
663 int rc = 0;
664 struct video_device *vdev;
665 struct msm_session *session;
666 struct msm_v4l2_event_data *event_data =
667 (struct msm_v4l2_event_data *)&event->u.data[0];
668 struct msm_command_ack *cmd_ack;
669 struct msm_command *cmd;
670 int session_id, stream_id;
671 unsigned long flags = 0;
672
673 session_id = event_data->session_id;
674 stream_id = event_data->stream_id;
675
676 spin_lock_irqsave(&msm_eventq_lock, flags);
677 if (!msm_eventq) {
678 spin_unlock_irqrestore(&msm_eventq_lock, flags);
679 return -ENODEV;
680 }
681 spin_unlock_irqrestore(&msm_eventq_lock, flags);
682
683 vdev = msm_eventq->vdev;
684
685 /* send to imaging server and wait for ACK */
686 session = msm_queue_find(msm_session_q, struct msm_session,
687 list, __msm_queue_find_session, &session_id);
688 if (WARN_ON(!session))
689 return -EIO;
690
691 cmd_ack = msm_queue_find(&session->command_ack_q,
692 struct msm_command_ack, list,
693 __msm_queue_find_command_ack_q, &stream_id);
694 if (WARN_ON(!cmd_ack))
695 return -EIO;
696
697 v4l2_event_queue(vdev, event);
698
699 if (timeout < 0)
700 return rc;
701
702 /* should wait on session based condition */
703 rc = wait_event_interruptible_timeout(cmd_ack->wait,
704 !list_empty_careful(&cmd_ack->command_q.list),
705 msecs_to_jiffies(timeout));
706 if (list_empty_careful(&cmd_ack->command_q.list)) {
707 if (!rc)
708 rc = -ETIMEDOUT;
709 if (rc < 0)
710 return rc;
711 }
712
713 cmd = msm_dequeue(&cmd_ack->command_q,
714 struct msm_command, list);
715 if (!cmd)
716 return -EINVAL;
717
718 event_data = (struct msm_v4l2_event_data *)cmd->event.u.data;
719
720 /* compare cmd_ret and event */
721 if (WARN_ON(event->type != cmd->event.type) ||
722 WARN_ON(event->id != cmd->event.id))
723 rc = -EINVAL;
724
725 *event = cmd->event;
726
727 kfree(cmd);
728 return rc;
729}
730
731static int __msm_close_destry_session_notify_apps(void *d1, void *d2)
732{
733 struct v4l2_event event;
734 struct msm_v4l2_event_data *event_data =
735 (struct msm_v4l2_event_data *)&event.u.data[0];
736 struct msm_session *session = d1;
737
738 event.type = MSM_CAMERA_V4L2_EVENT_TYPE;
739 event.id = MSM_CAMERA_MSM_NOTIFY;
740 event_data->command = MSM_CAMERA_PRIV_SHUTDOWN;
741
742 v4l2_event_queue(session->event_q.vdev, &event);
743
744 msm_destroy_session_streams(session);
745 msm_remove_session_cmd_ack_q(session);
746
747 return 0;
748}
749
750static int msm_close(struct file *filep)
751{
752 int rc = 0;
753 unsigned long flags;
754 struct msm_video_device *pvdev = video_drvdata(filep);
755
756 /* 1st thing 1st, send v4l2_event to HAL immediately,
757 * to ensure error handling purpose, it needs to detach all subdevs
758 * which are being connected to streams */
759 msm_queue_traverse_action(msm_session_q, struct msm_session, list,
760 __msm_close_destry_session_notify_apps, NULL);
761
762 msm_queue_drain(msm_session_q, struct msm_session, list);
763
764 spin_lock_irqsave(&msm_eventq_lock, flags);
765 msm_eventq = NULL;
766 spin_unlock_irqrestore(&msm_eventq_lock, flags);
767 v4l2_fh_release(filep);
768
769 msm_sd_try_shutdown();
770
771 spin_lock_irqsave(&msm_pid_lock, flags);
772 put_pid(msm_pid);
773 msm_pid = NULL;
774 spin_unlock_irqrestore(&msm_pid_lock, flags);
775
776 atomic_set(&pvdev->opened, 0);
777
778 return rc;
779}
780
781static inline void msm_list_switch(struct list_head *l1,
782 struct list_head *l2)
783{
784 l1->next = l2->next;
785 l2->prev = l1->prev;
786 l1->prev->next = l2;
787 l2->next->prev = l1;
788 l1->prev = l2;
789 l2->next = l1;
790}
791
792static int msm_open(struct file *filep)
793{
794 int rc;
795 unsigned long flags;
796 struct msm_video_device *pvdev = video_drvdata(filep);
797
798 BUG_ON(!pvdev);
799
800 /* !!! only ONE open is allowed !!! */
801 if (atomic_read(&pvdev->opened))
802 return -EBUSY;
803
804 atomic_set(&pvdev->opened, 1);
805
806 spin_lock_irqsave(&msm_pid_lock, flags);
807 msm_pid = get_pid(task_pid(current));
808 spin_unlock_irqrestore(&msm_pid_lock, flags);
809
810 /* create event queue */
811 rc = v4l2_fh_open(filep);
812 if (rc < 0)
813 return rc;
814
815 spin_lock_irqsave(&msm_eventq_lock, flags);
816 msm_eventq = filep->private_data;
817 spin_unlock_irqrestore(&msm_eventq_lock, flags);
818
819 return rc;
820}
821
822static struct v4l2_file_operations msm_fops = {
823 .owner = THIS_MODULE,
824 .open = msm_open,
825 .poll = msm_poll,
826 .release = msm_close,
827 .ioctl = video_ioctl2,
828};
829
830struct msm_stream *msm_get_stream(unsigned int session_id,
831 unsigned int stream_id)
832{
833 struct msm_session *session;
834 struct msm_stream *stream;
835
836 session = msm_queue_find(msm_session_q, struct msm_session,
837 list, __msm_queue_find_session, &session_id);
838 if (!session)
839 return ERR_PTR(-EINVAL);
840
841 stream = msm_queue_find(&session->stream_q, struct msm_stream,
842 list, __msm_queue_find_stream, &stream_id);
843
844 if (!stream)
845 return ERR_PTR(-EINVAL);
846
847 return stream;
848}
849
850struct vb2_queue *msm_get_stream_vb2q(unsigned int session_id,
851 unsigned int stream_id)
852{
853 struct msm_session *session;
854 struct msm_stream *stream;
855
856 session = msm_queue_find(msm_session_q, struct msm_session,
857 list, __msm_queue_find_session, &session_id);
858 if (!session)
859 return NULL;
860
861 stream = msm_queue_find(&session->stream_q, struct msm_stream,
862 list, __msm_queue_find_stream, &stream_id);
863 if (!stream)
864 return NULL;
865
866 return stream->vb2_q;
867}
868
869static struct v4l2_subdev *msm_sd_find(const char *name)
870{
871 unsigned long flags;
872 struct v4l2_subdev *subdev = NULL;
873
874 spin_lock_irqsave(&msm_v4l2_dev->lock, flags);
875 if (!list_empty(&msm_v4l2_dev->subdevs)) {
876 list_for_each_entry(subdev, &msm_v4l2_dev->subdevs, list)
877 if (!strcmp(name, subdev->name))
878 break;
879 }
880 spin_unlock_irqrestore(&msm_v4l2_dev->lock, flags);
881
882 return subdev;
883}
884
885static void msm_sd_notify(struct v4l2_subdev *sd,
886 unsigned int notification, void *arg)
887{
888 int rc = 0;
889 struct v4l2_subdev *subdev = NULL;
890
891 BUG_ON(!sd);
892 BUG_ON(!arg);
893
894 /* Check if subdev exists before processing*/
895 if (!msm_sd_find(sd->name))
896 return;
897
898 switch (notification) {
899 case MSM_SD_NOTIFY_GET_SD: {
900 struct msm_sd_req_sd *get_sd = arg;
901
902 get_sd->subdev = msm_sd_find(get_sd->name);
903 /* TODO: might need to add ref count on ret_sd */
904 }
905 break;
906
907 case MSM_SD_NOTIFY_PUT_SD: {
908 struct msm_sd_req_sd *put_sd = arg;
909 subdev = msm_sd_find(put_sd->name);
910 }
911 break;
912
913 case MSM_SD_NOTIFY_REQ_CB: {
914 struct msm_sd_req_vb2_q *req_sd = arg;
915 rc = msm_vb2_request_cb(req_sd);
916 if (rc < 0)
917 return;
918 }
919 break;
920
921 default:
922 break;
923 }
924}
925
926static int __devinit msm_probe(struct platform_device *pdev)
927{
928 struct msm_video_device *pvdev;
929 int rc = 0;
930
931 msm_v4l2_dev = kzalloc(sizeof(*msm_v4l2_dev),
932 GFP_KERNEL);
933 if (WARN_ON(!msm_v4l2_dev)) {
934 rc = -ENOMEM;
935 goto probe_end;
936 }
937
938 pvdev = kzalloc(sizeof(struct msm_video_device),
939 GFP_KERNEL);
940 if (WARN_ON(!pvdev)) {
941 rc = -ENOMEM;
942 goto pvdev_fail;
943 }
944
945 pvdev->vdev = video_device_alloc();
946 if (WARN_ON(!pvdev->vdev)) {
947 rc = -ENOMEM;
948 goto video_fail;
949 }
950
951#if defined(CONFIG_MEDIA_CONTROLLER)
952 msm_v4l2_dev->mdev = kzalloc(sizeof(struct media_device),
953 GFP_KERNEL);
954 if (!msm_v4l2_dev->mdev) {
955 rc = -ENOMEM;
956 goto mdev_fail;
957 }
958 strlcpy(msm_v4l2_dev->mdev->model, MSM_CONFIGURATION_NAME,
959 sizeof(msm_v4l2_dev->mdev->model));
960 msm_v4l2_dev->mdev->dev = &(pdev->dev);
961
962 rc = media_device_register(msm_v4l2_dev->mdev);
963 if (WARN_ON(rc < 0))
964 goto media_fail;
965
966 if (WARN_ON((rc == media_entity_init(&pvdev->vdev->entity,
967 0, NULL, 0)) < 0))
968 goto entity_fail;
969
970 pvdev->vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L;
971 pvdev->vdev->entity.group_id = QCAMERA_VNODE_GROUP_ID;
972#endif
973
974 msm_v4l2_dev->notify = msm_sd_notify;
975
976 pvdev->vdev->v4l2_dev = msm_v4l2_dev;
977
978 rc = v4l2_device_register(&(pdev->dev), pvdev->vdev->v4l2_dev);
979 if (WARN_ON(rc < 0))
980 goto register_fail;
981
982 strlcpy(pvdev->vdev->name, "msm-config", sizeof(pvdev->vdev->name));
983 pvdev->vdev->release = video_device_release;
984 pvdev->vdev->fops = &msm_fops;
985 pvdev->vdev->ioctl_ops = &g_msm_ioctl_ops;
986 pvdev->vdev->minor = -1;
987 pvdev->vdev->vfl_type = VFL_TYPE_GRABBER;
988 rc = video_register_device(pvdev->vdev,
989 VFL_TYPE_GRABBER, -1);
990 if (WARN_ON(rc < 0))
991 goto v4l2_fail;
992
993#if defined(CONFIG_MEDIA_CONTROLLER)
994 /* FIXME: How to get rid of this messy? */
995 pvdev->vdev->entity.name = video_device_node_name(pvdev->vdev);
996#endif
997
998 atomic_set(&pvdev->opened, 0);
999 video_set_drvdata(pvdev->vdev, pvdev);
1000
1001 msm_session_q = kzalloc(sizeof(*msm_session_q), GFP_KERNEL);
1002 if (WARN_ON(!msm_session_q))
1003 goto v4l2_fail;
1004
1005 msm_init_queue(msm_session_q);
1006 spin_lock_init(&msm_eventq_lock);
1007 spin_lock_init(&msm_pid_lock);
1008
1009 goto probe_end;
1010
1011v4l2_fail:
1012 v4l2_device_unregister(pvdev->vdev->v4l2_dev);
1013register_fail:
1014#if defined(CONFIG_MEDIA_CONTROLLER)
1015 media_entity_cleanup(&pvdev->vdev->entity);
1016entity_fail:
1017 media_device_unregister(msm_v4l2_dev->mdev);
1018media_fail:
1019 kfree(msm_v4l2_dev->mdev);
1020mdev_fail:
1021#endif
1022 video_device_release(pvdev->vdev);
1023video_fail:
1024 kfree(pvdev);
1025pvdev_fail:
1026 kfree(msm_v4l2_dev);
1027probe_end:
1028 return rc;
1029}
1030
1031static const struct of_device_id msm_dt_match[] = {
1032 {.compatible = "qcom,msm-cam"},
1033}
1034
1035MODULE_DEVICE_TABLE(of, msm_dt_match);
1036
1037static struct platform_driver msm_driver = {
1038 .probe = msm_probe,
1039 .driver = {
1040 .name = "msm",
1041 .owner = THIS_MODULE,
1042 .of_match_table = msm_dt_match,
1043 },
1044};
1045
1046static int __init msm_init(void)
1047{
1048 return platform_driver_register(&msm_driver);
1049}
1050
1051static void __exit msm_exit(void)
1052{
1053 platform_driver_unregister(&msm_driver);
1054}
1055
1056
1057module_init(msm_init);
1058module_exit(msm_exit);
1059MODULE_DESCRIPTION("MSM V4L2 Camera");
1060MODULE_LICENSE("GPL v2");