V4L/DVB (10759): cx18: Convert GPIO connected functions to act as v4l2_subdevices
[safe/jmp/linux-2.6] / drivers / media / video / cx18 / cx18-ioctl.c
index 0f0cd56..e4c9e3d 100644 (file)
@@ -160,10 +160,8 @@ static int cx18_g_fmt_vid_cap(struct file *file, void *fh,
        pixfmt->priv = 0;
        if (id->type == CX18_ENC_STREAM_TYPE_YUV) {
                pixfmt->pixelformat = V4L2_PIX_FMT_HM12;
-               /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
-               pixfmt->sizeimage =
-                       pixfmt->height * pixfmt->width +
-                       pixfmt->height * (pixfmt->width / 2);
+               /* YUV size is (Y=(h*720) + UV=(h*(720/2))) */
+               pixfmt->sizeimage = pixfmt->height * 720 * 3 / 2;
                pixfmt->bytesperline = 720;
        } else {
                pixfmt->pixelformat = V4L2_PIX_FMT_MPEG;
@@ -210,7 +208,7 @@ static int cx18_g_fmt_sliced_vbi_cap(struct file *file, void *fh,
         * digitizer/slicer.  Note, cx18_av_vbi() wipes the passed in
         * fmt->fmt.sliced under valid calling conditions
         */
-       if (cx18_av_cmd(cx, VIDIOC_G_FMT, fmt))
+       if (v4l2_subdev_call(cx->sd_av, video, g_fmt, fmt))
                return -EINVAL;
 
        /* Ensure V4L2 spec compliant output */
@@ -228,11 +226,18 @@ static int cx18_try_fmt_vid_cap(struct file *file, void *fh,
        struct cx18 *cx = id->cx;
        int w = fmt->fmt.pix.width;
        int h = fmt->fmt.pix.height;
+       int min_h = 2;
 
        w = min(w, 720);
-       w = max(w, 1);
+       w = max(w, 2);
+       if (id->type == CX18_ENC_STREAM_TYPE_YUV) {
+               /* YUV height must be a multiple of 32 */
+               h &= ~0x1f;
+               min_h = 32;
+       }
        h = min(h, cx->is_50hz ? 576 : 480);
-       h = max(h, 2);
+       h = max(h, min_h);
+
        cx18_g_fmt_vid_cap(file, fh, fmt);
        fmt->fmt.pix.width = w;
        fmt->fmt.pix.height = h;
@@ -290,7 +295,7 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
 
        cx->params.width = w;
        cx->params.height = h;
-       cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
+       v4l2_subdev_call(cx->sd_av, video, s_fmt, fmt);
        return cx18_g_fmt_vid_cap(file, fh, fmt);
 }
 
@@ -317,7 +322,7 @@ static int cx18_s_fmt_vbi_cap(struct file *file, void *fh,
         * Note cx18_av_vbi_wipes out alot of the passed in fmt under valid
         * calling conditions
         */
-       ret = cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
+       ret = v4l2_subdev_call(cx->sd_av, video, s_fmt, fmt);
        if (ret)
                return ret;
 
@@ -354,7 +359,7 @@ static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh,
         * Note, cx18_av_vbi() wipes some "impossible" service lines in the
         * passed in fmt->fmt.sliced under valid calling conditions
         */
-       ret = cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
+       ret = v4l2_subdev_call(cx->sd_av, video, s_fmt, fmt);
        if (ret)
                return ret;
        /* Store our current v4l2 sliced VBI settings */
@@ -367,35 +372,69 @@ static int cx18_g_chip_ident(struct file *file, void *fh,
                                struct v4l2_dbg_chip_ident *chip)
 {
        struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+       int err = 0;
 
        chip->ident = V4L2_IDENT_NONE;
        chip->revision = 0;
-       if (v4l2_chip_match_host(&chip->match)) {
-               chip->ident = V4L2_IDENT_CX23418;
-               return 0;
+       switch (chip->match.type) {
+       case V4L2_CHIP_MATCH_HOST:
+               switch (chip->match.addr) {
+               case 0:
+                       chip->ident = V4L2_IDENT_CX23418;
+                       chip->revision = cx18_read_reg(cx, 0xC72028);
+                       break;
+               case 1:
+                       /*
+                        * The A/V decoder is always present, but in the rare
+                        * case that the card doesn't have analog, we don't
+                        * use it.  We find it w/o using the cx->sd_av pointer
+                        */
+                       cx18_call_hw(cx, CX18_HW_418_AV,
+                                    core, g_chip_ident, chip);
+                       break;
+               default:
+                       /*
+                        * Could return ident = V4L2_IDENT_UNKNOWN if we had
+                        * other host chips at higher addresses, but we don't
+                        */
+                       err = -EINVAL; /* per V4L2 spec */
+                       break;
+               }
+               break;
+       case V4L2_CHIP_MATCH_I2C_DRIVER:
+               /* If needed, returns V4L2_IDENT_AMBIGUOUS without extra work */
+               cx18_call_all(cx, core, g_chip_ident, chip);
+               break;
+       case V4L2_CHIP_MATCH_I2C_ADDR:
+               /*
+                * We could return V4L2_IDENT_UNKNOWN, but we don't do the work
+                * to look if a chip is at the address with no driver.  That's a
+                * dangerous thing to do with EEPROMs anyway.
+                */
+               cx18_call_all(cx, core, g_chip_ident, chip);
+               break;
+       default:
+               err = -EINVAL;
+               break;
        }
-       cx18_call_i2c_clients(cx, VIDIOC_DBG_G_CHIP_IDENT, chip);
-       return 0;
+       return err;
 }
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg)
 {
        struct v4l2_dbg_register *regs = arg;
-       unsigned long flags;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
        if (regs->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE)
                return -EINVAL;
 
-       spin_lock_irqsave(&cx18_cards_lock, flags);
        regs->size = 4;
-       if (cmd == VIDIOC_DBG_G_REGISTER)
-               regs->val = cx18_read_enc(cx, regs->reg);
-       else
+       if (cmd == VIDIOC_DBG_S_REGISTER)
                cx18_write_enc(cx, regs->val, regs->reg);
-       spin_unlock_irqrestore(&cx18_cards_lock, flags);
+       else
+               regs->val = cx18_read_enc(cx, regs->reg);
        return 0;
 }
 
@@ -406,7 +445,8 @@ static int cx18_g_register(struct file *file, void *fh,
 
        if (v4l2_chip_match_host(&reg->match))
                return cx18_cxc(cx, VIDIOC_DBG_G_REGISTER, reg);
-       cx18_call_i2c_clients(cx, VIDIOC_DBG_G_REGISTER, reg);
+       /* FIXME - errors shouldn't be ignored */
+       cx18_call_all(cx, core, g_register, reg);
        return 0;
 }
 
@@ -417,7 +457,8 @@ static int cx18_s_register(struct file *file, void *fh,
 
        if (v4l2_chip_match_host(&reg->match))
                return cx18_cxc(cx, VIDIOC_DBG_S_REGISTER, reg);
-       cx18_call_i2c_clients(cx, VIDIOC_DBG_S_REGISTER, reg);
+       /* FIXME - errors shouldn't be ignored */
+       cx18_call_all(cx, core, s_register, reg);
        return 0;
 }
 #endif
@@ -514,7 +555,8 @@ static int cx18_s_crop(struct file *file, void *fh, struct v4l2_crop *crop)
 
        if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
-       return cx18_av_cmd(cx, VIDIOC_S_CROP, crop);
+       CX18_DEBUG_WARN("VIDIOC_S_CROP not implemented\n");
+       return -EINVAL;
 }
 
 static int cx18_g_crop(struct file *file, void *fh, struct v4l2_crop *crop)
@@ -523,7 +565,8 @@ static int cx18_g_crop(struct file *file, void *fh, struct v4l2_crop *crop)
 
        if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
-       return cx18_av_cmd(cx, VIDIOC_G_CROP, crop);
+       CX18_DEBUG_WARN("VIDIOC_G_CROP not implemented\n");
+       return -EINVAL;
 }
 
 static int cx18_enum_fmt_vid_cap(struct file *file, void *fh,
@@ -594,7 +637,7 @@ static int cx18_g_frequency(struct file *file, void *fh,
        if (vf->tuner != 0)
                return -EINVAL;
 
-       cx18_call_i2c_clients(cx, VIDIOC_G_FREQUENCY, vf);
+       cx18_call_all(cx, tuner, g_frequency, vf);
        return 0;
 }
 
@@ -613,7 +656,7 @@ int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
 
        cx18_mute(cx);
        CX18_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf->frequency);
-       cx18_call_i2c_clients(cx, VIDIOC_S_FREQUENCY, vf);
+       cx18_call_all(cx, tuner, s_frequency, vf);
        cx18_unmute(cx);
        return 0;
 }
@@ -662,7 +705,7 @@ int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std)
                        (unsigned long long) cx->std);
 
        /* Tuner */
-       cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std);
+       cx18_call_all(cx, tuner, s_std, cx->std);
        return 0;
 }
 
@@ -679,9 +722,7 @@ static int cx18_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
        if (vt->index != 0)
                return -EINVAL;
 
-       /* Setting tuner can only set audio mode */
-       cx18_call_i2c_clients(cx, VIDIOC_S_TUNER, vt);
-
+       cx18_call_all(cx, tuner, s_tuner, vt);
        return 0;
 }
 
@@ -692,7 +733,7 @@ static int cx18_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
        if (vt->index != 0)
                return -EINVAL;
 
-       cx18_call_i2c_clients(cx, VIDIOC_G_TUNER, vt);
+       cx18_call_all(cx, tuner, g_tuner, vt);
 
        if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
                strlcpy(vt->name, "cx18 Radio Tuner", sizeof(vt->name));
@@ -842,14 +883,14 @@ static int cx18_log_status(struct file *file, void *fh)
        int i;
 
        CX18_INFO("=================  START STATUS CARD #%d  "
-                 "=================\n", cx->num);
+                 "=================\n", cx->instance);
        CX18_INFO("Version: %s  Card: %s\n", CX18_VERSION, cx->card_name);
        if (cx->hw_flags & CX18_HW_TVEEPROM) {
                struct tveeprom tv;
 
                cx18_read_eeprom(cx, &tv);
        }
-       cx18_call_i2c_clients(cx, VIDIOC_LOG_STATUS, NULL);
+       cx18_call_all(cx, core, log_status);
        cx18_get_input(cx, cx->active_input, &vidin);
        cx18_get_audio_input(cx, cx->audio_input, &audin);
        CX18_INFO("Video Input: %s\n", vidin.name);
@@ -860,7 +901,7 @@ static int cx18_log_status(struct file *file, void *fh)
        mutex_unlock(&cx->gpio_lock);
        CX18_INFO("Tuner: %s\n",
                test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ?  "Radio" : "TV");
-       cx2341x_log_status(&cx->params, cx->name);
+       cx2341x_log_status(&cx->params, cx->v4l2_dev.name);
        CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags);
        for (i = 0; i < CX18_MAX_STREAMS; i++) {
                struct cx18_stream *s = &cx->streams[i];
@@ -875,7 +916,8 @@ static int cx18_log_status(struct file *file, void *fh)
        CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n",
                        (long long)cx->mpg_data_received,
                        (long long)cx->vbi_data_inserted);
-       CX18_INFO("==================  END STATUS CARD #%d  ==================\n", cx->num);
+       CX18_INFO("==================  END STATUS CARD #%d  "
+                 "==================\n", cx->instance);
        return 0;
 }
 
@@ -889,7 +931,8 @@ static long cx18_default(struct file *file, void *fh, int cmd, void *arg)
 
                CX18_DEBUG_IOCTL("VIDIOC_INT_S_AUDIO_ROUTING(%d, %d)\n",
                        route->input, route->output);
-               cx18_audio_set_route(cx, route);
+               cx18_call_hw(cx, cx->card->hw_audio_ctrl, audio, s_routing,
+                            route);
                break;
        }
 
@@ -897,7 +940,8 @@ static long cx18_default(struct file *file, void *fh, int cmd, void *arg)
                u32 val = *(u32 *)arg;
 
                if ((val == 0) || (val & 0x01))
-                       cx18_reset_ir_gpio(&cx->i2c_algo_cb_data[0]);
+                       cx18_call_hw(cx, CX18_HW_GPIO_RESET_CTRL, core, reset,
+                                    (u32) CX18_GPIO_RESET_Z8F0811);
                break;
        }
 
@@ -917,6 +961,8 @@ long cx18_v4l2_ioctl(struct file *filp, unsigned int cmd,
 
        mutex_lock(&cx->serialize_lock);
 
+       /* FIXME - consolidate v4l2_prio_check()'s here */
+
        if (cx18_debug & CX18_DBGFLG_IOCTL)
                vfd->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG;
        res = video_ioctl2(filp, cmd, arg);