linux/drivers/staging/cx25821/cx25821-videoioctl.c
<<
>>
Prefs
   1/*
   2 *  Driver for the Conexant CX25821 PCIe bridge
   3 *
   4 *  Copyright (C) 2009 Conexant Systems Inc.
   5 *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
   6 *  Based on Steven Toth <stoth@linuxtv.org> cx23885 driver
   7 *
   8 *  This program is free software; you can redistribute it and/or modify
   9 *  it under the terms of the GNU General Public License as published by
  10 *  the Free Software Foundation; either version 2 of the License, or
  11 *  (at your option) any later version.
  12 *
  13 *  This program is distributed in the hope that it will be useful,
  14 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 *
  17 *  GNU General Public License for more details.
  18 *
  19 *  You should have received a copy of the GNU General Public License
  20 *  along with this program; if not, write to the Free Software
  21 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  22 */
  23
  24#include "cx25821-video.h"
  25
  26static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
  27{
  28        struct cx25821_buffer *buf =
  29            container_of(vb, struct cx25821_buffer, vb);
  30        struct cx25821_buffer *prev;
  31        struct cx25821_fh *fh = vq->priv_data;
  32        struct cx25821_dev *dev = fh->dev;
  33        struct cx25821_dmaqueue *q = &dev->vidq[VIDEO_IOCTL_CH];
  34
  35        /* add jump to stopper */
  36        buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
  37        buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
  38        buf->risc.jmp[2] = cpu_to_le32(0);      /* bits 63-32 */
  39
  40        dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
  41
  42        if (!list_empty(&q->queued)) {
  43                list_add_tail(&buf->vb.queue, &q->queued);
  44                buf->vb.state = VIDEOBUF_QUEUED;
  45                dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
  46                        buf->vb.i);
  47
  48        } else if (list_empty(&q->active)) {
  49                list_add_tail(&buf->vb.queue, &q->active);
  50                cx25821_start_video_dma(dev, q, buf,
  51                                        &dev->sram_channels[VIDEO_IOCTL_CH]);
  52                buf->vb.state = VIDEOBUF_ACTIVE;
  53                buf->count = q->count++;
  54                mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
  55                dprintk(2,
  56                        "[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
  57                        buf, buf->vb.i, buf->count, q->count);
  58        } else {
  59                prev =
  60                    list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
  61                if (prev->vb.width == buf->vb.width
  62                    && prev->vb.height == buf->vb.height
  63                    && prev->fmt == buf->fmt) {
  64                        list_add_tail(&buf->vb.queue, &q->active);
  65                        buf->vb.state = VIDEOBUF_ACTIVE;
  66                        buf->count = q->count++;
  67                        prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
  68
  69                        /* 64 bit bits 63-32 */
  70                        prev->risc.jmp[2] = cpu_to_le32(0);
  71                        dprintk(2,
  72                                "[%p/%d] buffer_queue - append to active, buf->count=%d\n",
  73                                buf, buf->vb.i, buf->count);
  74
  75                } else {
  76                        list_add_tail(&buf->vb.queue, &q->queued);
  77                        buf->vb.state = VIDEOBUF_QUEUED;
  78                        dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
  79                                buf->vb.i);
  80                }
  81        }
  82
  83        if (list_empty(&q->active)) {
  84                dprintk(2, "active queue empty!\n");
  85        }
  86}
  87
  88static struct videobuf_queue_ops cx25821_video_qops = {
  89        .buf_setup = buffer_setup,
  90        .buf_prepare = buffer_prepare,
  91        .buf_queue = buffer_queue,
  92        .buf_release = buffer_release,
  93};
  94
  95static int video_open(struct file *file)
  96{
  97        int minor = video_devdata(file)->minor;
  98        struct cx25821_dev *h, *dev = NULL;
  99        struct cx25821_fh *fh;
 100        struct list_head *list;
 101        enum v4l2_buf_type type = 0;
 102        u32 pix_format;
 103
 104        lock_kernel();
 105        list_for_each(list, &cx25821_devlist) {
 106                h = list_entry(list, struct cx25821_dev, devlist);
 107
 108                if (h->ioctl_dev && h->ioctl_dev->minor == minor) {
 109                        dev = h;
 110                        type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 111                }
 112        }
 113
 114        if (NULL == dev) {
 115                unlock_kernel();
 116                return -ENODEV;
 117        }
 118
 119        printk("open minor=%d type=%s\n", minor, v4l2_type_names[type]);
 120
 121        /* allocate + initialize per filehandle data */
 122        fh = kzalloc(sizeof(*fh), GFP_KERNEL);
 123        if (NULL == fh) {
 124                unlock_kernel();
 125                return -ENOMEM;
 126        }
 127
 128        file->private_data = fh;
 129        fh->dev = dev;
 130        fh->type = type;
 131        fh->width = 720;
 132
 133        if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
 134                fh->height = 576;
 135        else
 136                fh->height = 480;
 137
 138        dev->channel_opened = VIDEO_IOCTL_CH;
 139        pix_format = V4L2_PIX_FMT_YUYV;
 140        fh->fmt = format_by_fourcc(pix_format);
 141
 142        v4l2_prio_open(&dev->prio, &fh->prio);
 143
 144        videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
 145                               &dev->pci->dev, &dev->slock,
 146                               V4L2_BUF_TYPE_VIDEO_CAPTURE,
 147                               V4L2_FIELD_INTERLACED,
 148                               sizeof(struct cx25821_buffer), fh);
 149
 150        dprintk(1, "post videobuf_queue_init()\n");
 151        unlock_kernel();
 152
 153        return 0;
 154}
 155
 156static ssize_t video_read(struct file *file, char __user * data, size_t count,
 157                          loff_t * ppos)
 158{
 159        struct cx25821_fh *fh = file->private_data;
 160
 161        switch (fh->type) {
 162        case V4L2_BUF_TYPE_VIDEO_CAPTURE:
 163                if (res_locked(fh->dev, RESOURCE_VIDEO_IOCTL))
 164                        return -EBUSY;
 165
 166                return videobuf_read_one(&fh->vidq, data, count, ppos,
 167                                         file->f_flags & O_NONBLOCK);
 168
 169        default:
 170                BUG();
 171                return 0;
 172        }
 173}
 174
 175static unsigned int video_poll(struct file *file,
 176                               struct poll_table_struct *wait)
 177{
 178        struct cx25821_fh *fh = file->private_data;
 179        struct cx25821_buffer *buf;
 180
 181        if (res_check(fh, RESOURCE_VIDEO_IOCTL)) {
 182                /* streaming capture */
 183                if (list_empty(&fh->vidq.stream))
 184                        return POLLERR;
 185                buf = list_entry(fh->vidq.stream.next,
 186                                 struct cx25821_buffer, vb.stream);
 187        } else {
 188                /* read() capture */
 189                buf = (struct cx25821_buffer *)fh->vidq.read_buf;
 190                if (NULL == buf)
 191                        return POLLERR;
 192        }
 193
 194        poll_wait(file, &buf->vb.done, wait);
 195        if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR)
 196                return POLLIN | POLLRDNORM;
 197
 198        return 0;
 199}
 200
 201static int video_release(struct file *file)
 202{
 203        struct cx25821_fh *fh = file->private_data;
 204        struct cx25821_dev *dev = fh->dev;
 205
 206        /* stop video capture */
 207        if (res_check(fh, RESOURCE_VIDEO_IOCTL)) {
 208                videobuf_queue_cancel(&fh->vidq);
 209                res_free(dev, fh, RESOURCE_VIDEO_IOCTL);
 210        }
 211
 212        if (fh->vidq.read_buf) {
 213                buffer_release(&fh->vidq, fh->vidq.read_buf);
 214                kfree(fh->vidq.read_buf);
 215        }
 216
 217        videobuf_mmap_free(&fh->vidq);
 218
 219        v4l2_prio_close(&dev->prio, &fh->prio);
 220
 221        file->private_data = NULL;
 222        kfree(fh);
 223
 224        return 0;
 225}
 226
 227static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
 228{
 229        struct cx25821_fh *fh = priv;
 230        struct cx25821_dev *dev = fh->dev;
 231
 232        if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
 233                return -EINVAL;
 234        }
 235
 236        if (unlikely(i != fh->type)) {
 237                return -EINVAL;
 238        }
 239
 240        if (unlikely(!res_get(dev, fh, get_resource(fh, RESOURCE_VIDEO_IOCTL)))) {
 241                return -EBUSY;
 242        }
 243
 244        return videobuf_streamon(get_queue(fh));
 245}
 246
 247static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
 248{
 249        struct cx25821_fh *fh = priv;
 250        struct cx25821_dev *dev = fh->dev;
 251        int err, res;
 252
 253        if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 254                return -EINVAL;
 255        if (i != fh->type)
 256                return -EINVAL;
 257
 258        res = get_resource(fh, RESOURCE_VIDEO_IOCTL);
 259        err = videobuf_streamoff(get_queue(fh));
 260        if (err < 0)
 261                return err;
 262        res_free(dev, fh, res);
 263        return 0;
 264}
 265
 266static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 267                                struct v4l2_format *f)
 268{
 269        struct cx25821_fh *fh = priv;
 270        struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
 271        int err;
 272
 273        if (fh) {
 274                err = v4l2_prio_check(&dev->prio, &fh->prio);
 275                if (0 != err)
 276                        return err;
 277        }
 278
 279        dprintk(2, "%s()\n", __func__);
 280        err = vidioc_try_fmt_vid_cap(file, priv, f);
 281
 282        if (0 != err)
 283                return err;
 284        fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
 285        fh->width = f->fmt.pix.width;
 286        fh->height = f->fmt.pix.height;
 287        fh->vidq.field = f->fmt.pix.field;
 288        dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
 289                fh->height, fh->vidq.field);
 290        cx25821_call_all(dev, video, s_fmt, f);
 291        return 0;
 292}
 293
 294static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
 295{
 296        struct cx25821_fh *fh = priv;
 297        return videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
 298}
 299
 300static long video_ioctl_set(struct file *file, unsigned int cmd,
 301                            unsigned long arg)
 302{
 303        struct cx25821_fh *fh = file->private_data;
 304        struct cx25821_dev *dev = fh->dev;
 305        struct downstream_user_struct *data_from_user;
 306        int command;
 307        int width = 720;
 308        int selected_channel = 0, pix_format = 0, i = 0;
 309        int cif_enable = 0, cif_width = 0;
 310        u32 value = 0;
 311
 312        data_from_user = (struct downstream_user_struct *)arg;
 313
 314        if (!data_from_user) {
 315                printk("cx25821 in %s(): User data is INVALID. Returning.\n",
 316                       __func__);
 317                return 0;
 318        }
 319
 320        command = data_from_user->command;
 321
 322        if (command != SET_VIDEO_STD && command != SET_PIXEL_FORMAT
 323            && command != ENABLE_CIF_RESOLUTION && command != REG_READ
 324            && command != REG_WRITE && command != MEDUSA_READ
 325            && command != MEDUSA_WRITE) {
 326                return 0;
 327        }
 328
 329        switch (command) {
 330        case SET_VIDEO_STD:
 331                dev->tvnorm =
 332                    !strcmp(data_from_user->vid_stdname,
 333                            "PAL") ? V4L2_STD_PAL_BG : V4L2_STD_NTSC_M;
 334                medusa_set_videostandard(dev);
 335                break;
 336
 337        case SET_PIXEL_FORMAT:
 338                selected_channel = data_from_user->decoder_select;
 339                pix_format = data_from_user->pixel_format;
 340
 341                if (!(selected_channel <= 7 && selected_channel >= 0)) {
 342                        selected_channel -= 4;
 343                        selected_channel = selected_channel % 8;
 344                }
 345
 346                if (selected_channel >= 0)
 347                        cx25821_set_pixel_format(dev, selected_channel,
 348                                                 pix_format);
 349
 350                break;
 351
 352        case ENABLE_CIF_RESOLUTION:
 353                selected_channel = data_from_user->decoder_select;
 354                cif_enable = data_from_user->cif_resolution_enable;
 355                cif_width = data_from_user->cif_width;
 356
 357                if (cif_enable) {
 358                        if (dev->tvnorm & V4L2_STD_PAL_BG
 359                            || dev->tvnorm & V4L2_STD_PAL_DK)
 360                                width = 352;
 361                        else
 362                                width = (cif_width == 320
 363                                         || cif_width == 352) ? cif_width : 320;
 364                }
 365
 366                if (!(selected_channel <= 7 && selected_channel >= 0)) {
 367                        selected_channel -= 4;
 368                        selected_channel = selected_channel % 8;
 369                }
 370
 371                if (selected_channel <= 7 && selected_channel >= 0) {
 372                        dev->use_cif_resolution[selected_channel] = cif_enable;
 373                        dev->cif_width[selected_channel] = width;
 374                } else {
 375                        for (i = 0; i < VID_CHANNEL_NUM; i++) {
 376                                dev->use_cif_resolution[i] = cif_enable;
 377                                dev->cif_width[i] = width;
 378                        }
 379                }
 380
 381                medusa_set_resolution(dev, width, selected_channel);
 382                break;
 383        case REG_READ:
 384                data_from_user->reg_data = cx_read(data_from_user->reg_address);
 385                break;
 386        case REG_WRITE:
 387                cx_write(data_from_user->reg_address, data_from_user->reg_data);
 388                break;
 389        case MEDUSA_READ:
 390                value =
 391                    cx25821_i2c_read(&dev->i2c_bus[0],
 392                                     (u16) data_from_user->reg_address,
 393                                     &data_from_user->reg_data);
 394                break;
 395        case MEDUSA_WRITE:
 396                cx25821_i2c_write(&dev->i2c_bus[0],
 397                                  (u16) data_from_user->reg_address,
 398                                  data_from_user->reg_data);
 399                break;
 400        }
 401
 402        return 0;
 403}
 404
 405static int vidioc_log_status(struct file *file, void *priv)
 406{
 407        struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
 408        char name[32 + 2];
 409
 410        snprintf(name, sizeof(name), "%s/2", dev->name);
 411        printk(KERN_INFO "%s/2: ============  START LOG STATUS  ============\n",
 412               dev->name);
 413        cx25821_call_all(dev, core, log_status);
 414        printk(KERN_INFO "%s/2: =============  END LOG STATUS  =============\n",
 415               dev->name);
 416        return 0;
 417}
 418
 419static int vidioc_s_ctrl(struct file *file, void *priv,
 420                         struct v4l2_control *ctl)
 421{
 422        struct cx25821_fh *fh = priv;
 423        struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
 424        int err;
 425
 426        if (fh) {
 427                err = v4l2_prio_check(&dev->prio, &fh->prio);
 428                if (0 != err)
 429                        return err;
 430        }
 431
 432        return 0;
 433}
 434
 435// exported stuff
 436static const struct v4l2_file_operations video_fops = {
 437        .owner = THIS_MODULE,
 438        .open = video_open,
 439        .release = video_release,
 440        .read = video_read,
 441        .poll = video_poll,
 442        .mmap = video_mmap,
 443        .ioctl = video_ioctl_set,
 444};
 445
 446static const struct v4l2_ioctl_ops video_ioctl_ops = {
 447        .vidioc_querycap = vidioc_querycap,
 448        .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
 449        .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
 450        .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
 451        .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
 452        .vidioc_reqbufs = vidioc_reqbufs,
 453        .vidioc_querybuf = vidioc_querybuf,
 454        .vidioc_qbuf = vidioc_qbuf,
 455        .vidioc_dqbuf = vidioc_dqbuf,
 456#ifdef TUNER_FLAG
 457        .vidioc_s_std = vidioc_s_std,
 458        .vidioc_querystd = vidioc_querystd,
 459#endif
 460        .vidioc_cropcap = vidioc_cropcap,
 461        .vidioc_s_crop = vidioc_s_crop,
 462        .vidioc_g_crop = vidioc_g_crop,
 463        .vidioc_enum_input = vidioc_enum_input,
 464        .vidioc_g_input = vidioc_g_input,
 465        .vidioc_s_input = vidioc_s_input,
 466        .vidioc_g_ctrl = vidioc_g_ctrl,
 467        .vidioc_s_ctrl = vidioc_s_ctrl,
 468        .vidioc_queryctrl = vidioc_queryctrl,
 469        .vidioc_streamon = vidioc_streamon,
 470        .vidioc_streamoff = vidioc_streamoff,
 471        .vidioc_log_status = vidioc_log_status,
 472        .vidioc_g_priority = vidioc_g_priority,
 473        .vidioc_s_priority = vidioc_s_priority,
 474#ifdef CONFIG_VIDEO_V4L1_COMPAT
 475        .vidiocgmbuf = vidiocgmbuf,
 476#endif
 477#ifdef TUNER_FLAG
 478        .vidioc_g_tuner = vidioc_g_tuner,
 479        .vidioc_s_tuner = vidioc_s_tuner,
 480        .vidioc_g_frequency = vidioc_g_frequency,
 481        .vidioc_s_frequency = vidioc_s_frequency,
 482#endif
 483#ifdef CONFIG_VIDEO_ADV_DEBUG
 484        .vidioc_g_register = vidioc_g_register,
 485        .vidioc_s_register = vidioc_s_register,
 486#endif
 487};
 488
 489struct video_device cx25821_videoioctl_template = {
 490        .name = "cx25821-videoioctl",
 491        .fops = &video_fops,
 492        .minor = -1,
 493        .ioctl_ops = &video_ioctl_ops,
 494        .tvnorms = CX25821_NORMS,
 495        .current_norm = V4L2_STD_NTSC_M,
 496};
 497