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