linux/drivers/staging/solo6x10/solo6010-v4l2.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
   3 * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License as published by
   7 * the Free Software Foundation; either version 2 of the License, or
   8 * (at your option) any later version.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 *
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program; if not, write to the Free Software
  17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  18 */
  19
  20#include <linux/kernel.h>
  21#include <linux/module.h>
  22#include <linux/kthread.h>
  23#include <linux/freezer.h>
  24
  25#include <media/v4l2-ioctl.h>
  26#include <media/v4l2-common.h>
  27#include <media/videobuf-dma-sg.h>
  28
  29#include "solo6010.h"
  30#include "solo6010-tw28.h"
  31
  32#define SOLO_HW_BPL             2048
  33#define SOLO_DISP_PIX_FIELD     V4L2_FIELD_INTERLACED
  34
  35/* Image size is two fields, SOLO_HW_BPL is one horizontal line */
  36#define solo_vlines(__solo)     (__solo->video_vsize * 2)
  37#define solo_image_size(__solo) (solo_bytesperline(__solo) * \
  38                                 solo_vlines(__solo))
  39#define solo_bytesperline(__solo) (__solo->video_hsize * 2)
  40
  41#define MIN_VID_BUFFERS         4
  42
  43/* Simple file handle */
  44struct solo_filehandle {
  45        struct solo6010_dev     *solo_dev;
  46        struct videobuf_queue   vidq;
  47        struct task_struct      *kthread;
  48        spinlock_t              slock;
  49        int                     old_write;
  50        struct list_head        vidq_active;
  51        struct p2m_desc         desc[SOLO_NR_P2M_DESC];
  52        int                     desc_idx;
  53};
  54
  55unsigned video_nr = -1;
  56module_param(video_nr, uint, 0644);
  57MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect (default)");
  58
  59static void erase_on(struct solo6010_dev *solo_dev)
  60{
  61        solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, SOLO_VO_DISP_ERASE_ON);
  62        solo_dev->erasing = 1;
  63        solo_dev->frame_blank = 0;
  64}
  65
  66static int erase_off(struct solo6010_dev *solo_dev)
  67{
  68        if (!solo_dev->erasing)
  69                return 0;
  70
  71        /* First time around, assert erase off */
  72        if (!solo_dev->frame_blank)
  73                solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, 0);
  74        /* Keep the erasing flag on for 8 frames minimum */
  75        if (solo_dev->frame_blank++ >= 8)
  76                solo_dev->erasing = 0;
  77
  78        return 1;
  79}
  80
  81void solo_video_in_isr(struct solo6010_dev *solo_dev)
  82{
  83        solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_VIDEO_IN);
  84        wake_up_interruptible(&solo_dev->disp_thread_wait);
  85}
  86
  87static void solo_win_setup(struct solo6010_dev *solo_dev, u8 ch,
  88                           int sx, int sy, int ex, int ey, int scale)
  89{
  90        if (ch >= solo_dev->nr_chans)
  91                return;
  92
  93        /* Here, we just keep window/channel the same */
  94        solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL0(ch),
  95                       SOLO_VI_WIN_CHANNEL(ch) |
  96                       SOLO_VI_WIN_SX(sx) |
  97                       SOLO_VI_WIN_EX(ex) |
  98                       SOLO_VI_WIN_SCALE(scale));
  99
 100        solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL1(ch),
 101                       SOLO_VI_WIN_SY(sy) |
 102                       SOLO_VI_WIN_EY(ey));
 103}
 104
 105static int solo_v4l2_ch_ext_4up(struct solo6010_dev *solo_dev, u8 idx, int on)
 106{
 107        u8 ch = idx * 4;
 108
 109        if (ch >= solo_dev->nr_chans)
 110                return -EINVAL;
 111
 112        if (!on) {
 113                u8 i;
 114                for (i = ch; i < ch + 4; i++)
 115                        solo_win_setup(solo_dev, i, solo_dev->video_hsize,
 116                                       solo_vlines(solo_dev),
 117                                       solo_dev->video_hsize,
 118                                       solo_vlines(solo_dev), 0);
 119                return 0;
 120        }
 121
 122        /* Row 1 */
 123        solo_win_setup(solo_dev, ch, 0, 0, solo_dev->video_hsize / 2,
 124                       solo_vlines(solo_dev) / 2, 3);
 125        solo_win_setup(solo_dev, ch + 1, solo_dev->video_hsize / 2, 0,
 126                       solo_dev->video_hsize, solo_vlines(solo_dev) / 2, 3);
 127        /* Row 2 */
 128        solo_win_setup(solo_dev, ch + 2, 0, solo_vlines(solo_dev) / 2,
 129                       solo_dev->video_hsize / 2, solo_vlines(solo_dev), 3);
 130        solo_win_setup(solo_dev, ch + 3, solo_dev->video_hsize / 2,
 131                       solo_vlines(solo_dev) / 2, solo_dev->video_hsize,
 132                       solo_vlines(solo_dev), 3);
 133
 134        return 0;
 135}
 136
 137static int solo_v4l2_ch_ext_16up(struct solo6010_dev *solo_dev, int on)
 138{
 139        int sy, ysize, hsize, i;
 140
 141        if (!on) {
 142                for (i = 0; i < 16; i++)
 143                        solo_win_setup(solo_dev, i, solo_dev->video_hsize,
 144                                       solo_vlines(solo_dev),
 145                                       solo_dev->video_hsize,
 146                                       solo_vlines(solo_dev), 0);
 147                return 0;
 148        }
 149
 150        ysize = solo_vlines(solo_dev) / 4;
 151        hsize = solo_dev->video_hsize / 4;
 152
 153        for (sy = 0, i = 0; i < 4; i++, sy += ysize) {
 154                solo_win_setup(solo_dev, i * 4, 0, sy, hsize,
 155                               sy + ysize, 5);
 156                solo_win_setup(solo_dev, (i * 4) + 1, hsize, sy,
 157                               hsize * 2, sy + ysize, 5);
 158                solo_win_setup(solo_dev, (i * 4) + 2, hsize * 2, sy,
 159                               hsize * 3, sy + ysize, 5);
 160                solo_win_setup(solo_dev, (i * 4) + 3, hsize * 3, sy,
 161                               solo_dev->video_hsize, sy + ysize, 5);
 162        }
 163
 164        return 0;
 165}
 166
 167static int solo_v4l2_ch(struct solo6010_dev *solo_dev, u8 ch, int on)
 168{
 169        u8 ext_ch;
 170
 171        if (ch < solo_dev->nr_chans) {
 172                solo_win_setup(solo_dev, ch, on ? 0 : solo_dev->video_hsize,
 173                               on ? 0 : solo_vlines(solo_dev),
 174                               solo_dev->video_hsize, solo_vlines(solo_dev),
 175                               on ? 1 : 0);
 176                return 0;
 177        }
 178
 179        if (ch >= solo_dev->nr_chans + solo_dev->nr_ext)
 180                return -EINVAL;
 181
 182        ext_ch = ch - solo_dev->nr_chans;
 183
 184        /* 4up's first */
 185        if (ext_ch < 4)
 186                return solo_v4l2_ch_ext_4up(solo_dev, ext_ch, on);
 187
 188        /* Remaining case is 16up for 16-port */
 189        return solo_v4l2_ch_ext_16up(solo_dev, on);
 190}
 191
 192static int solo_v4l2_set_ch(struct solo6010_dev *solo_dev, u8 ch)
 193{
 194        if (ch >= solo_dev->nr_chans + solo_dev->nr_ext)
 195                return -EINVAL;
 196
 197        erase_on(solo_dev);
 198
 199        solo_v4l2_ch(solo_dev, solo_dev->cur_disp_ch, 0);
 200        solo_v4l2_ch(solo_dev, ch, 1);
 201
 202        solo_dev->cur_disp_ch = ch;
 203
 204        return 0;
 205}
 206
 207static void disp_reset_desc(struct solo_filehandle *fh)
 208{
 209        /* We use desc mode, which ignores desc 0 */
 210        memset(fh->desc, 0, sizeof(*fh->desc));
 211        fh->desc_idx = 1;
 212}
 213
 214static int disp_flush_descs(struct solo_filehandle *fh)
 215{
 216        int ret;
 217
 218        if (!fh->desc_idx)
 219                return 0;
 220
 221        ret = solo_p2m_dma_desc(fh->solo_dev, SOLO_P2M_DMA_ID_DISP,
 222                                fh->desc, fh->desc_idx);
 223        disp_reset_desc(fh);
 224
 225        return ret;
 226}
 227
 228static int disp_push_desc(struct solo_filehandle *fh, dma_addr_t dma_addr,
 229                      u32 ext_addr, int size, int repeat, int ext_size)
 230{
 231        if (fh->desc_idx >= SOLO_NR_P2M_DESC) {
 232                int ret = disp_flush_descs(fh);
 233                if (ret)
 234                        return ret;
 235        }
 236
 237        solo_p2m_push_desc(&fh->desc[fh->desc_idx], 0, dma_addr, ext_addr,
 238                           size, repeat, ext_size);
 239        fh->desc_idx++;
 240
 241        return 0;
 242}
 243
 244static void solo_fillbuf(struct solo_filehandle *fh,
 245                         struct videobuf_buffer *vb)
 246{
 247        struct solo6010_dev *solo_dev = fh->solo_dev;
 248        struct videobuf_dmabuf *vbuf;
 249        unsigned int fdma_addr;
 250        int error = 1;
 251        int i;
 252        struct scatterlist *sg;
 253        dma_addr_t sg_dma;
 254        int sg_size_left;
 255
 256        vbuf = videobuf_to_dma(vb);
 257        if (!vbuf)
 258                goto finish_buf;
 259
 260        if (erase_off(solo_dev)) {
 261                int i;
 262
 263                /* Just blit to the entire sg list, ignoring size */
 264                for_each_sg(vbuf->sglist, sg, vbuf->sglen, i) {
 265                        void *p = sg_virt(sg);
 266                        size_t len = sg_dma_len(sg);
 267
 268                        for (i = 0; i < len; i += 2) {
 269                                ((u8 *)p)[i] = 0x80;
 270                                ((u8 *)p)[i + 1] = 0x00;
 271                        }
 272                }
 273
 274                error = 0;
 275                goto finish_buf;
 276        }
 277
 278        disp_reset_desc(fh);
 279        sg = vbuf->sglist;
 280        sg_dma = sg_dma_address(sg);
 281        sg_size_left = sg_dma_len(sg);
 282
 283        fdma_addr = SOLO_DISP_EXT_ADDR(solo_dev) + (fh->old_write *
 284                        (SOLO_HW_BPL * solo_vlines(solo_dev)));
 285
 286        for (i = 0; i < solo_vlines(solo_dev); i++) {
 287                int line_len = solo_bytesperline(solo_dev);
 288                int lines;
 289
 290                if (!sg_size_left) {
 291                        sg = sg_next(sg);
 292                        if (sg == NULL)
 293                                goto finish_buf;
 294                        sg_dma = sg_dma_address(sg);
 295                        sg_size_left = sg_dma_len(sg);
 296                }
 297
 298                /* No room for an entire line, so chunk it up */
 299                if (sg_size_left < line_len) {
 300                        int this_addr = fdma_addr;
 301
 302                        while (line_len > 0) {
 303                                int this_write;
 304
 305                                if (!sg_size_left) {
 306                                        sg = sg_next(sg);
 307                                        if (sg == NULL)
 308                                                goto finish_buf;
 309                                        sg_dma = sg_dma_address(sg);
 310                                        sg_size_left = sg_dma_len(sg);
 311                                }
 312
 313                                this_write = min(sg_size_left, line_len);
 314
 315                                if (disp_push_desc(fh, sg_dma, this_addr,
 316                                                   this_write, 0, 0))
 317                                        goto finish_buf;
 318
 319                                line_len -= this_write;
 320                                sg_size_left -= this_write;
 321                                sg_dma += this_write;
 322                                this_addr += this_write;
 323                        }
 324
 325                        fdma_addr += SOLO_HW_BPL;
 326                        continue;
 327                }
 328
 329                /* Shove as many lines into a repeating descriptor as possible */
 330                lines = min(sg_size_left / line_len,
 331                            solo_vlines(solo_dev) - i);
 332
 333                if (disp_push_desc(fh, sg_dma, fdma_addr, line_len,
 334                                   lines - 1, SOLO_HW_BPL))
 335                        goto finish_buf;
 336
 337                i += lines - 1;
 338                fdma_addr += SOLO_HW_BPL * lines;
 339                sg_dma += lines * line_len;
 340                sg_size_left -= lines * line_len;
 341        }
 342
 343        error = disp_flush_descs(fh);
 344
 345finish_buf:
 346        if (error) {
 347                vb->state = VIDEOBUF_ERROR;
 348        } else {
 349                vb->size = solo_vlines(solo_dev) * solo_bytesperline(solo_dev);
 350                vb->state = VIDEOBUF_DONE;
 351                vb->field_count++;
 352                do_gettimeofday(&vb->ts);
 353        }
 354
 355        wake_up(&vb->done);
 356
 357        return;
 358}
 359
 360static void solo_thread_try(struct solo_filehandle *fh)
 361{
 362        struct videobuf_buffer *vb;
 363        unsigned int cur_write;
 364
 365        for (;;) {
 366                spin_lock(&fh->slock);
 367
 368                if (list_empty(&fh->vidq_active))
 369                        break;
 370
 371                vb = list_first_entry(&fh->vidq_active, struct videobuf_buffer,
 372                                      queue);
 373
 374                if (!waitqueue_active(&vb->done))
 375                        break;
 376
 377                cur_write = SOLO_VI_STATUS0_PAGE(solo_reg_read(fh->solo_dev,
 378                                                 SOLO_VI_STATUS0));
 379                if (cur_write == fh->old_write)
 380                        break;
 381
 382                fh->old_write = cur_write;
 383                list_del(&vb->queue);
 384
 385                spin_unlock(&fh->slock);
 386
 387                solo_fillbuf(fh, vb);
 388        }
 389
 390        assert_spin_locked(&fh->slock);
 391        spin_unlock(&fh->slock);
 392}
 393
 394static int solo_thread(void *data)
 395{
 396        struct solo_filehandle *fh = data;
 397        struct solo6010_dev *solo_dev = fh->solo_dev;
 398        DECLARE_WAITQUEUE(wait, current);
 399
 400        set_freezable();
 401        add_wait_queue(&solo_dev->disp_thread_wait, &wait);
 402
 403        for (;;) {
 404                long timeout = schedule_timeout_interruptible(HZ);
 405                if (timeout == -ERESTARTSYS || kthread_should_stop())
 406                        break;
 407                solo_thread_try(fh);
 408                try_to_freeze();
 409        }
 410
 411        remove_wait_queue(&solo_dev->disp_thread_wait, &wait);
 412
 413        return 0;
 414}
 415
 416static int solo_start_thread(struct solo_filehandle *fh)
 417{
 418        fh->kthread = kthread_run(solo_thread, fh, SOLO6010_NAME "_disp");
 419
 420        if (IS_ERR(fh->kthread))
 421                return PTR_ERR(fh->kthread);
 422
 423        return 0;
 424}
 425
 426static void solo_stop_thread(struct solo_filehandle *fh)
 427{
 428        if (fh->kthread) {
 429                kthread_stop(fh->kthread);
 430                fh->kthread = NULL;
 431        }
 432}
 433
 434static int solo_buf_setup(struct videobuf_queue *vq, unsigned int *count,
 435                          unsigned int *size)
 436{
 437        struct solo_filehandle *fh = vq->priv_data;
 438        struct solo6010_dev *solo_dev  = fh->solo_dev;
 439
 440        *size = solo_image_size(solo_dev);
 441
 442        if (*count < MIN_VID_BUFFERS)
 443                *count = MIN_VID_BUFFERS;
 444
 445        return 0;
 446}
 447
 448static int solo_buf_prepare(struct videobuf_queue *vq,
 449                            struct videobuf_buffer *vb, enum v4l2_field field)
 450{
 451        struct solo_filehandle *fh  = vq->priv_data;
 452        struct solo6010_dev *solo_dev = fh->solo_dev;
 453
 454        vb->size = solo_image_size(solo_dev);
 455        if (vb->baddr != 0 && vb->bsize < vb->size)
 456                return -EINVAL;
 457
 458        /* XXX: These properties only change when queue is idle */
 459        vb->width  = solo_dev->video_hsize;
 460        vb->height = solo_vlines(solo_dev);
 461        vb->bytesperline = solo_bytesperline(solo_dev);
 462        vb->field  = field;
 463
 464        if (vb->state == VIDEOBUF_NEEDS_INIT) {
 465                int rc = videobuf_iolock(vq, vb, NULL);
 466                if (rc < 0) {
 467                        struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
 468                        videobuf_dma_unmap(vq->dev, dma);
 469                        videobuf_dma_free(dma);
 470                        vb->state = VIDEOBUF_NEEDS_INIT;
 471                        return rc;
 472                }
 473        }
 474        vb->state = VIDEOBUF_PREPARED;
 475
 476        return 0;
 477}
 478
 479static void solo_buf_queue(struct videobuf_queue *vq,
 480                           struct videobuf_buffer *vb)
 481{
 482        struct solo_filehandle *fh = vq->priv_data;
 483        struct solo6010_dev *solo_dev = fh->solo_dev;
 484
 485        vb->state = VIDEOBUF_QUEUED;
 486        list_add_tail(&vb->queue, &fh->vidq_active);
 487        wake_up_interruptible(&solo_dev->disp_thread_wait);
 488}
 489
 490static void solo_buf_release(struct videobuf_queue *vq,
 491                             struct videobuf_buffer *vb)
 492{
 493        struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
 494
 495        videobuf_dma_unmap(vq->dev, dma);
 496        videobuf_dma_free(dma);
 497        vb->state = VIDEOBUF_NEEDS_INIT;
 498}
 499
 500static struct videobuf_queue_ops solo_video_qops = {
 501        .buf_setup      = solo_buf_setup,
 502        .buf_prepare    = solo_buf_prepare,
 503        .buf_queue      = solo_buf_queue,
 504        .buf_release    = solo_buf_release,
 505};
 506
 507static unsigned int solo_v4l2_poll(struct file *file,
 508                                   struct poll_table_struct *wait)
 509{
 510        struct solo_filehandle *fh = file->private_data;
 511
 512        return videobuf_poll_stream(file, &fh->vidq, wait);
 513}
 514
 515static int solo_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
 516{
 517        struct solo_filehandle *fh = file->private_data;
 518
 519        return videobuf_mmap_mapper(&fh->vidq, vma);
 520}
 521
 522static int solo_v4l2_open(struct file *file)
 523{
 524        struct solo6010_dev *solo_dev = video_drvdata(file);
 525        struct solo_filehandle *fh;
 526        int ret;
 527
 528        fh = kzalloc(sizeof(*fh), GFP_KERNEL);
 529        if (fh == NULL)
 530                return -ENOMEM;
 531
 532        spin_lock_init(&fh->slock);
 533        INIT_LIST_HEAD(&fh->vidq_active);
 534        fh->solo_dev = solo_dev;
 535        file->private_data = fh;
 536
 537        ret = solo_start_thread(fh);
 538        if (ret) {
 539                kfree(fh);
 540                return ret;
 541        }
 542
 543        videobuf_queue_sg_init(&fh->vidq, &solo_video_qops,
 544                               &solo_dev->pdev->dev, &fh->slock,
 545                               V4L2_BUF_TYPE_VIDEO_CAPTURE,
 546                               SOLO_DISP_PIX_FIELD,
 547                               sizeof(struct videobuf_buffer), fh, NULL);
 548
 549        return 0;
 550}
 551
 552static ssize_t solo_v4l2_read(struct file *file, char __user *data,
 553                              size_t count, loff_t *ppos)
 554{
 555        struct solo_filehandle *fh = file->private_data;
 556
 557        return videobuf_read_stream(&fh->vidq, data, count, ppos, 0,
 558                                    file->f_flags & O_NONBLOCK);
 559}
 560
 561static int solo_v4l2_release(struct file *file)
 562{
 563        struct solo_filehandle *fh = file->private_data;
 564
 565        videobuf_stop(&fh->vidq);
 566        videobuf_mmap_free(&fh->vidq);
 567        solo_stop_thread(fh);
 568        kfree(fh);
 569
 570        return 0;
 571}
 572
 573static int solo_querycap(struct file *file, void  *priv,
 574                         struct v4l2_capability *cap)
 575{
 576        struct solo_filehandle  *fh  = priv;
 577        struct solo6010_dev *solo_dev = fh->solo_dev;
 578
 579        strcpy(cap->driver, SOLO6010_NAME);
 580        strcpy(cap->card, "Softlogic 6010");
 581        snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI %s",
 582                 pci_name(solo_dev->pdev));
 583        cap->version = SOLO6010_VER_NUM;
 584        cap->capabilities =     V4L2_CAP_VIDEO_CAPTURE |
 585                                V4L2_CAP_READWRITE |
 586                                V4L2_CAP_STREAMING;
 587        return 0;
 588}
 589
 590static int solo_enum_ext_input(struct solo6010_dev *solo_dev,
 591                               struct v4l2_input *input)
 592{
 593        static const char *dispnames_1[] = { "4UP" };
 594        static const char *dispnames_2[] = { "4UP-1", "4UP-2" };
 595        static const char *dispnames_5[] = {
 596                "4UP-1", "4UP-2", "4UP-3", "4UP-4", "16UP"
 597        };
 598        const char **dispnames;
 599
 600        if (input->index >= (solo_dev->nr_chans + solo_dev->nr_ext))
 601                return -EINVAL;
 602
 603        if (solo_dev->nr_ext == 5)
 604                dispnames = dispnames_5;
 605        else if (solo_dev->nr_ext == 2)
 606                dispnames = dispnames_2;
 607        else
 608                dispnames = dispnames_1;
 609
 610        snprintf(input->name, sizeof(input->name), "Multi %s",
 611                 dispnames[input->index - solo_dev->nr_chans]);
 612
 613        return 0;
 614}
 615
 616static int solo_enum_input(struct file *file, void *priv,
 617                           struct v4l2_input *input)
 618{
 619        struct solo_filehandle *fh  = priv;
 620        struct solo6010_dev *solo_dev = fh->solo_dev;
 621
 622        if (input->index >= solo_dev->nr_chans) {
 623                int ret = solo_enum_ext_input(solo_dev, input);
 624                if (ret < 0)
 625                        return ret;
 626        } else {
 627                snprintf(input->name, sizeof(input->name), "Camera %d",
 628                         input->index + 1);
 629
 630                /* We can only check this for normal inputs */
 631                if (!tw28_get_video_status(solo_dev, input->index))
 632                        input->status = V4L2_IN_ST_NO_SIGNAL;
 633        }
 634
 635        input->type = V4L2_INPUT_TYPE_CAMERA;
 636
 637        if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC)
 638                input->std = V4L2_STD_NTSC_M;
 639        else
 640                input->std = V4L2_STD_PAL_B;
 641
 642        return 0;
 643}
 644
 645static int solo_set_input(struct file *file, void *priv, unsigned int index)
 646{
 647        struct solo_filehandle *fh = priv;
 648
 649        return solo_v4l2_set_ch(fh->solo_dev, index);
 650}
 651
 652static int solo_get_input(struct file *file, void *priv, unsigned int *index)
 653{
 654        struct solo_filehandle *fh = priv;
 655
 656        *index = fh->solo_dev->cur_disp_ch;
 657
 658        return 0;
 659}
 660
 661static int solo_enum_fmt_cap(struct file *file, void *priv,
 662                             struct v4l2_fmtdesc *f)
 663{
 664        if (f->index)
 665                return -EINVAL;
 666
 667        f->pixelformat = V4L2_PIX_FMT_UYVY;
 668        strlcpy(f->description, "UYUV 4:2:2 Packed", sizeof(f->description));
 669
 670        return 0;
 671}
 672
 673static int solo_try_fmt_cap(struct file *file, void *priv,
 674                            struct v4l2_format *f)
 675{
 676        struct solo_filehandle *fh = priv;
 677        struct solo6010_dev *solo_dev = fh->solo_dev;
 678        struct v4l2_pix_format *pix = &f->fmt.pix;
 679        int image_size = solo_image_size(solo_dev);
 680
 681        /* Check supported sizes */
 682        if (pix->width != solo_dev->video_hsize)
 683                pix->width = solo_dev->video_hsize;
 684        if (pix->height != solo_vlines(solo_dev))
 685                pix->height = solo_vlines(solo_dev);
 686        if (pix->sizeimage != image_size)
 687                pix->sizeimage = image_size;
 688
 689        /* Check formats */
 690        if (pix->field == V4L2_FIELD_ANY)
 691                pix->field = SOLO_DISP_PIX_FIELD;
 692
 693        if (pix->pixelformat != V4L2_PIX_FMT_UYVY ||
 694            pix->field       != SOLO_DISP_PIX_FIELD ||
 695            pix->colorspace  != V4L2_COLORSPACE_SMPTE170M)
 696                return -EINVAL;
 697
 698        return 0;
 699}
 700
 701static int solo_set_fmt_cap(struct file *file, void *priv,
 702                            struct v4l2_format *f)
 703{
 704        struct solo_filehandle *fh = priv;
 705
 706        if (videobuf_queue_is_busy(&fh->vidq))
 707                return -EBUSY;
 708
 709        /* For right now, if it doesn't match our running config,
 710         * then fail */
 711        return solo_try_fmt_cap(file, priv, f);
 712}
 713
 714static int solo_get_fmt_cap(struct file *file, void *priv,
 715                            struct v4l2_format *f)
 716{
 717        struct solo_filehandle *fh = priv;
 718        struct solo6010_dev *solo_dev = fh->solo_dev;
 719        struct v4l2_pix_format *pix = &f->fmt.pix;
 720
 721        pix->width = solo_dev->video_hsize;
 722        pix->height = solo_vlines(solo_dev);
 723        pix->pixelformat = V4L2_PIX_FMT_UYVY;
 724        pix->field = SOLO_DISP_PIX_FIELD;
 725        pix->sizeimage = solo_image_size(solo_dev);
 726        pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
 727        pix->bytesperline = solo_bytesperline(solo_dev);
 728
 729        return 0;
 730}
 731
 732static int solo_reqbufs(struct file *file, void *priv,
 733                        struct v4l2_requestbuffers *req)
 734{
 735        struct solo_filehandle *fh = priv;
 736
 737        return videobuf_reqbufs(&fh->vidq, req);
 738}
 739
 740static int solo_querybuf(struct file *file, void *priv, struct v4l2_buffer *buf)
 741{
 742        struct solo_filehandle *fh = priv;
 743
 744        return videobuf_querybuf(&fh->vidq, buf);
 745}
 746
 747static int solo_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
 748{
 749        struct solo_filehandle *fh = priv;
 750
 751        return videobuf_qbuf(&fh->vidq, buf);
 752}
 753
 754static int solo_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
 755{
 756        struct solo_filehandle *fh = priv;
 757
 758        return videobuf_dqbuf(&fh->vidq, buf, file->f_flags & O_NONBLOCK);
 759}
 760
 761static int solo_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
 762{
 763        struct solo_filehandle *fh = priv;
 764
 765        if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 766                return -EINVAL;
 767
 768        return videobuf_streamon(&fh->vidq);
 769}
 770
 771static int solo_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
 772{
 773        struct solo_filehandle *fh = priv;
 774
 775        if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 776                return -EINVAL;
 777
 778        return videobuf_streamoff(&fh->vidq);
 779}
 780
 781static int solo_s_std(struct file *file, void *priv, v4l2_std_id *i)
 782{
 783        return 0;
 784}
 785
 786static const u32 solo_motion_ctrls[] = {
 787        V4L2_CID_MOTION_TRACE,
 788        0
 789};
 790
 791static const u32 *solo_ctrl_classes[] = {
 792        solo_motion_ctrls,
 793        NULL
 794};
 795
 796static int solo_disp_queryctrl(struct file *file, void *priv,
 797                               struct v4l2_queryctrl *qc)
 798{
 799        qc->id = v4l2_ctrl_next(solo_ctrl_classes, qc->id);
 800        if (!qc->id)
 801                return -EINVAL;
 802
 803        switch (qc->id) {
 804#ifdef PRIVATE_CIDS
 805        case V4L2_CID_MOTION_TRACE:
 806                qc->type = V4L2_CTRL_TYPE_BOOLEAN;
 807                qc->minimum = 0;
 808                qc->maximum = qc->step = 1;
 809                qc->default_value = 0;
 810                strlcpy(qc->name, "Motion Detection Trace", sizeof(qc->name));
 811                return 0;
 812#else
 813        case V4L2_CID_MOTION_TRACE:
 814                return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
 815#endif
 816        }
 817        return -EINVAL;
 818}
 819
 820static int solo_disp_g_ctrl(struct file *file, void *priv,
 821                            struct v4l2_control *ctrl)
 822{
 823        struct solo_filehandle *fh = priv;
 824        struct solo6010_dev *solo_dev = fh->solo_dev;
 825
 826        switch (ctrl->id) {
 827        case V4L2_CID_MOTION_TRACE:
 828                ctrl->value = solo_reg_read(solo_dev, SOLO_VI_MOTION_BAR)
 829                        ? 1 : 0;
 830                return 0;
 831        }
 832        return -EINVAL;
 833}
 834
 835static int solo_disp_s_ctrl(struct file *file, void *priv,
 836                            struct v4l2_control *ctrl)
 837{
 838        struct solo_filehandle *fh = priv;
 839        struct solo6010_dev *solo_dev = fh->solo_dev;
 840
 841        switch (ctrl->id) {
 842        case V4L2_CID_MOTION_TRACE:
 843                if (ctrl->value) {
 844                        solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER,
 845                                        SOLO_VI_MOTION_Y_ADD |
 846                                        SOLO_VI_MOTION_Y_VALUE(0x20) |
 847                                        SOLO_VI_MOTION_CB_VALUE(0x10) |
 848                                        SOLO_VI_MOTION_CR_VALUE(0x10));
 849                        solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR,
 850                                        SOLO_VI_MOTION_CR_ADD |
 851                                        SOLO_VI_MOTION_Y_VALUE(0x10) |
 852                                        SOLO_VI_MOTION_CB_VALUE(0x80) |
 853                                        SOLO_VI_MOTION_CR_VALUE(0x10));
 854                } else {
 855                        solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, 0);
 856                        solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0);
 857                }
 858                return 0;
 859        }
 860        return -EINVAL;
 861}
 862
 863static const struct v4l2_file_operations solo_v4l2_fops = {
 864        .owner                  = THIS_MODULE,
 865        .open                   = solo_v4l2_open,
 866        .release                = solo_v4l2_release,
 867        .read                   = solo_v4l2_read,
 868        .poll                   = solo_v4l2_poll,
 869        .mmap                   = solo_v4l2_mmap,
 870        .ioctl                  = video_ioctl2,
 871};
 872
 873static const struct v4l2_ioctl_ops solo_v4l2_ioctl_ops = {
 874        .vidioc_querycap                = solo_querycap,
 875        .vidioc_s_std                   = solo_s_std,
 876        /* Input callbacks */
 877        .vidioc_enum_input              = solo_enum_input,
 878        .vidioc_s_input                 = solo_set_input,
 879        .vidioc_g_input                 = solo_get_input,
 880        /* Video capture format callbacks */
 881        .vidioc_enum_fmt_vid_cap        = solo_enum_fmt_cap,
 882        .vidioc_try_fmt_vid_cap         = solo_try_fmt_cap,
 883        .vidioc_s_fmt_vid_cap           = solo_set_fmt_cap,
 884        .vidioc_g_fmt_vid_cap           = solo_get_fmt_cap,
 885        /* Streaming I/O */
 886        .vidioc_reqbufs                 = solo_reqbufs,
 887        .vidioc_querybuf                = solo_querybuf,
 888        .vidioc_qbuf                    = solo_qbuf,
 889        .vidioc_dqbuf                   = solo_dqbuf,
 890        .vidioc_streamon                = solo_streamon,
 891        .vidioc_streamoff               = solo_streamoff,
 892        /* Controls */
 893        .vidioc_queryctrl               = solo_disp_queryctrl,
 894        .vidioc_g_ctrl                  = solo_disp_g_ctrl,
 895        .vidioc_s_ctrl                  = solo_disp_s_ctrl,
 896};
 897
 898static struct video_device solo_v4l2_template = {
 899        .name                   = SOLO6010_NAME,
 900        .fops                   = &solo_v4l2_fops,
 901        .ioctl_ops              = &solo_v4l2_ioctl_ops,
 902        .minor                  = -1,
 903        .release                = video_device_release,
 904
 905        .tvnorms                = V4L2_STD_NTSC_M | V4L2_STD_PAL_B,
 906        .current_norm           = V4L2_STD_NTSC_M,
 907};
 908
 909int solo_v4l2_init(struct solo6010_dev *solo_dev)
 910{
 911        int ret;
 912        int i;
 913
 914        init_waitqueue_head(&solo_dev->disp_thread_wait);
 915
 916        solo_dev->vfd = video_device_alloc();
 917        if (!solo_dev->vfd)
 918                return -ENOMEM;
 919
 920        *solo_dev->vfd = solo_v4l2_template;
 921        solo_dev->vfd->parent = &solo_dev->pdev->dev;
 922
 923        ret = video_register_device(solo_dev->vfd, VFL_TYPE_GRABBER, video_nr);
 924        if (ret < 0) {
 925                video_device_release(solo_dev->vfd);
 926                solo_dev->vfd = NULL;
 927                return ret;
 928        }
 929
 930        video_set_drvdata(solo_dev->vfd, solo_dev);
 931
 932        snprintf(solo_dev->vfd->name, sizeof(solo_dev->vfd->name), "%s (%i)",
 933                 SOLO6010_NAME, solo_dev->vfd->num);
 934
 935        if (video_nr != -1)
 936                video_nr++;
 937
 938        dev_info(&solo_dev->pdev->dev, "Display as /dev/video%d with "
 939                 "%d inputs (%d extended)\n", solo_dev->vfd->num,
 940                 solo_dev->nr_chans, solo_dev->nr_ext);
 941
 942        /* Cycle all the channels and clear */
 943        for (i = 0; i < solo_dev->nr_chans; i++) {
 944                solo_v4l2_set_ch(solo_dev, i);
 945                while (erase_off(solo_dev))
 946                        ;/* Do nothing */
 947        }
 948
 949        /* Set the default display channel */
 950        solo_v4l2_set_ch(solo_dev, 0);
 951        while (erase_off(solo_dev))
 952                ;/* Do nothing */
 953
 954        solo6010_irq_on(solo_dev, SOLO_IRQ_VIDEO_IN);
 955
 956        return 0;
 957}
 958
 959void solo_v4l2_exit(struct solo6010_dev *solo_dev)
 960{
 961        solo6010_irq_off(solo_dev, SOLO_IRQ_VIDEO_IN);
 962        if (solo_dev->vfd) {
 963                video_unregister_device(solo_dev->vfd);
 964                solo_dev->vfd = NULL;
 965        }
 966}
 967