linux/drivers/staging/dream/camera/msm_camera.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2008-2009 QUALCOMM Incorporated.
   3 */
   4
   5/* FIXME: most allocations need not be GFP_ATOMIC */
   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>
  15#include <linux/slab.h>
  16#include <linux/init.h>
  17#include <linux/sched.h>
  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        };                                                      \
  80} while (0)
  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);    \
  87} while (0)
  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",
 365                        __func__,
 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
 459static struct msm_queue_cmd *__msm_control(struct msm_sync *sync,
 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         */
 596        kfree(qcmd);
 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",
 673                                        __func__);
 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;
 721                                } else {
 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:
 798        kfree(qcmd);
 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                }
 839        } else
 840                ctrlcmd->value = NULL;
 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
 870        switch (cfgcmd.cmd_type) {
 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) {
 877                        pr_err("%s: pmem region lookup error\n", __func__);
 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) {
 889                        pr_err("%s: pmem region lookup error\n", __func__);
 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",
 900                        __func__, cfgcmd.cmd_type);
 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) {
 929                        pr_err("%s: pmem region lookup error\n", __func__);
 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) {
 940                        pr_err("%s: pmem region lookup error\n", __func__);
 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) {
 951                        pr_err("%s: pmem region lookup error\n", __func__);
 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) {
 960                        pr_err("%s: pmem region lookup error\n", __func__);
 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) {
 971                        pr_err("%s: pmem region lookup error\n", __func__);
 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",
 982                        __func__, cfgcmd->cmd_type);
 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",
1048                        __func__);
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",
1132                        __func__, cfgcmd->cmd_type);
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) {
1141                        pr_err("%s: pmem region lookup error\n", __func__);
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",
1178                                __func__,
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",
1224                        __func__,
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();
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;
1623        printk(KERN_INFO "msm_camera: RELEASE %s\n",
1624                                        filep->f_path.dentry->d_name.name);
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;
1638        printk(KERN_INFO "msm_camera: RELEASE %s\n",
1639                                        filep->f_path.dentry->d_name.name);
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) {
1723                switch (vdata->type) {
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) {
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);
1888        if (rc < 0) {
1889                kfree(ctrl_pmsm);
1890                return rc;
1891        }
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:
1934        kfree(rcmd);
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,
1944};
1945
1946static const struct file_operations msm_fops_control = {
1947        .owner = THIS_MODULE,
1948        .open = msm_open_control,
1949        .unlocked_ioctl = msm_ioctl_control,
1950        .release = msm_release_control,
1951};
1952
1953static const struct file_operations msm_fops_frame = {
1954        .owner = THIS_MODULE,
1955        .open = msm_open,
1956        .unlocked_ioctl = msm_ioctl_frame,
1957        .release = msm_release_frame,
1958        .poll = msm_poll_frame,
1959};
1960
1961static int msm_setup_cdev(struct msm_device *msm,
1962                        int node,
1963                        dev_t devno,
1964                        const char *suffix,
1965                        const struct file_operations *fops)
1966{
1967        int rc = -ENODEV;
1968
1969        struct device *device =
1970                device_create(msm_class, NULL,
1971                        devno, NULL,
1972                        "%s%d", suffix, node);
1973
1974        if (IS_ERR(device)) {
1975                rc = PTR_ERR(device);
1976                pr_err("msm_camera: error creating device: %d\n", rc);
1977                return rc;
1978        }
1979
1980        cdev_init(&msm->cdev, fops);
1981        msm->cdev.owner = THIS_MODULE;
1982
1983        rc = cdev_add(&msm->cdev, devno, 1);
1984        if (rc < 0) {
1985                pr_err("msm_camera: error adding cdev: %d\n", rc);
1986                device_destroy(msm_class, devno);
1987                return rc;
1988        }
1989
1990        return rc;
1991}
1992
1993static int msm_tear_down_cdev(struct msm_device *msm, dev_t devno)
1994{
1995        cdev_del(&msm->cdev);
1996        device_destroy(msm_class, devno);
1997        return 0;
1998}
1999
2000int msm_v4l2_register(struct msm_v4l2_driver *drv)
2001{
2002        /* FIXME: support multiple sensors */
2003        if (list_empty(&msm_sensors))
2004                return -ENODEV;
2005
2006        drv->sync = list_first_entry(&msm_sensors, struct msm_sync, list);
2007        drv->open      = __msm_open;
2008        drv->release   = __msm_release;
2009        drv->ctrl      = __msm_v4l2_control;
2010        drv->reg_pmem  = __msm_register_pmem;
2011        drv->get_frame = __msm_get_frame;
2012        drv->put_frame = __msm_put_frame_buf;
2013        drv->get_pict  = __msm_get_pic;
2014        drv->drv_poll  = __msm_poll_frame;
2015
2016        return 0;
2017}
2018EXPORT_SYMBOL(msm_v4l2_register);
2019
2020int msm_v4l2_unregister(struct msm_v4l2_driver *drv)
2021{
2022        drv->sync = NULL;
2023        return 0;
2024}
2025EXPORT_SYMBOL(msm_v4l2_unregister);
2026
2027static int msm_sync_init(struct msm_sync *sync,
2028                struct platform_device *pdev,
2029                int (*sensor_probe)(const struct msm_camera_sensor_info *,
2030                                struct msm_sensor_ctrl *))
2031{
2032        int rc = 0;
2033        struct msm_sensor_ctrl sctrl;
2034        sync->sdata = pdev->dev.platform_data;
2035
2036        spin_lock_init(&sync->msg_event_q_lock);
2037        INIT_LIST_HEAD(&sync->msg_event_q);
2038        init_waitqueue_head(&sync->msg_event_wait);
2039
2040        spin_lock_init(&sync->prev_frame_q_lock);
2041        INIT_LIST_HEAD(&sync->prev_frame_q);
2042        init_waitqueue_head(&sync->prev_frame_wait);
2043
2044        spin_lock_init(&sync->pict_frame_q_lock);
2045        INIT_LIST_HEAD(&sync->pict_frame_q);
2046        init_waitqueue_head(&sync->pict_frame_wait);
2047
2048        rc = msm_camio_probe_on(pdev);
2049        if (rc < 0)
2050                return rc;
2051        rc = sensor_probe(sync->sdata, &sctrl);
2052        if (rc >= 0) {
2053                sync->pdev = pdev;
2054                sync->sctrl = sctrl;
2055        }
2056        msm_camio_probe_off(pdev);
2057        if (rc < 0) {
2058                pr_err("msm_camera: failed to initialize %s\n",
2059                        sync->sdata->sensor_name);
2060                return rc;
2061        }
2062
2063        sync->opencnt = 0;
2064        mutex_init(&sync->lock);
2065        CDBG("initialized %s\n", sync->sdata->sensor_name);
2066        return rc;
2067}
2068
2069static int msm_sync_destroy(struct msm_sync *sync)
2070{
2071        return 0;
2072}
2073
2074static int msm_device_init(struct msm_device *pmsm,
2075                struct msm_sync *sync,
2076                int node)
2077{
2078        int dev_num = 3 * node;
2079        int rc = msm_setup_cdev(pmsm, node,
2080                MKDEV(MAJOR(msm_devno), dev_num),
2081                "control", &msm_fops_control);
2082        if (rc < 0) {
2083                pr_err("error creating control node: %d\n", rc);
2084                return rc;
2085        }
2086
2087        rc = msm_setup_cdev(pmsm + 1, node,
2088                MKDEV(MAJOR(msm_devno), dev_num + 1),
2089                "config", &msm_fops_config);
2090        if (rc < 0) {
2091                pr_err("error creating config node: %d\n", rc);
2092                msm_tear_down_cdev(pmsm, MKDEV(MAJOR(msm_devno),
2093                                dev_num));
2094                return rc;
2095        }
2096
2097        rc = msm_setup_cdev(pmsm + 2, node,
2098                MKDEV(MAJOR(msm_devno), dev_num + 2),
2099                "frame", &msm_fops_frame);
2100        if (rc < 0) {
2101                pr_err("error creating frame node: %d\n", rc);
2102                msm_tear_down_cdev(pmsm,
2103                        MKDEV(MAJOR(msm_devno), dev_num));
2104                msm_tear_down_cdev(pmsm + 1,
2105                        MKDEV(MAJOR(msm_devno), dev_num + 1));
2106                return rc;
2107        }
2108
2109        atomic_set(&pmsm[0].opened, 0);
2110        atomic_set(&pmsm[1].opened, 0);
2111        atomic_set(&pmsm[2].opened, 0);
2112
2113        pmsm[0].sync = sync;
2114        pmsm[1].sync = sync;
2115        pmsm[2].sync = sync;
2116
2117        return rc;
2118}
2119
2120int msm_camera_drv_start(struct platform_device *dev,
2121                int (*sensor_probe)(const struct msm_camera_sensor_info *,
2122                        struct msm_sensor_ctrl *))
2123{
2124        struct msm_device *pmsm = NULL;
2125        struct msm_sync *sync;
2126        int rc = -ENODEV;
2127        static int camera_node;
2128
2129        if (camera_node >= MSM_MAX_CAMERA_SENSORS) {
2130                pr_err("msm_camera: too many camera sensors\n");
2131                return rc;
2132        }
2133
2134        if (!msm_class) {
2135                /* There are three device nodes per sensor */
2136                rc = alloc_chrdev_region(&msm_devno, 0,
2137                                3 * MSM_MAX_CAMERA_SENSORS,
2138                                "msm_camera");
2139                if (rc < 0) {
2140                        pr_err("msm_camera: failed to allocate chrdev: %d\n",
2141                                rc);
2142                        return rc;
2143                }
2144
2145                msm_class = class_create(THIS_MODULE, "msm_camera");
2146                if (IS_ERR(msm_class)) {
2147                        rc = PTR_ERR(msm_class);
2148                        pr_err("msm_camera: create device class failed: %d\n",
2149                                rc);
2150                        return rc;
2151                }
2152        }
2153
2154        pmsm = kzalloc(sizeof(struct msm_device) * 3 +
2155                        sizeof(struct msm_sync), GFP_ATOMIC);
2156        if (!pmsm)
2157                return -ENOMEM;
2158        sync = (struct msm_sync *)(pmsm + 3);
2159
2160        rc = msm_sync_init(sync, dev, sensor_probe);
2161        if (rc < 0) {
2162                kfree(pmsm);
2163                return rc;
2164        }
2165
2166        CDBG("setting camera node %d\n", camera_node);
2167        rc = msm_device_init(pmsm, sync, camera_node);
2168        if (rc < 0) {
2169                msm_sync_destroy(sync);
2170                kfree(pmsm);
2171                return rc;
2172        }
2173
2174        camera_node++;
2175        list_add(&sync->list, &msm_sensors);
2176        return rc;
2177}
2178EXPORT_SYMBOL(msm_camera_drv_start);
2179
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.