Re: [RFC PATCH 03/12] mt9m001: convert to the control framework.

2011-01-25 Thread Hans Verkuil
On Sunday, January 23, 2011 04:38:21 Kim HeungJun wrote:
> Hello,
> 
> I'm reading threads about the new v4l2_ctrl framework and If you don't mind
> I gotta tell you my humble opinion about testing result the new v4l2_ctrl
> framework subdev.
> I have actually similar curcumstance, with I2C subdev M5MOLS Fujitsu device
> which is just send the patch and S5PC210 board for testing this, except not
> using soc_camera framework.
> But, it's maybe helpful to discuss about this changes to everyone.
> 
> 2011. 1. 23., 오전 6:21, Guennadi Liakhovetski 작성:
> 
> > On Wed, 12 Jan 2011, Hans Verkuil wrote:
> > 
> >> Signed-off-by: Hans Verkuil 
> 
> [snip]
> 
> >> -  case V4L2_CID_EXPOSURE:
> >> -  /* mt9m001 has maximum == default */
> >> -  if (ctrl->value > qctrl->maximum || ctrl->value < 
> >> qctrl->minimum)
> >> -  return -EINVAL;
> >> -  else {
> >> -  unsigned long range = qctrl->maximum - qctrl->minimum;
> >> -  unsigned long shutter = ((ctrl->value - qctrl->minimum) 
> >> * 1048 +
> >> +  case V4L2_CID_EXPOSURE_AUTO:
> >> +  /* Force manual exposure if only the exposure was changed */
> >> +  if (!ctrl->has_new)
> >> +  ctrl->val = V4L2_EXPOSURE_MANUAL;
> >> +  if (ctrl->val == V4L2_EXPOSURE_MANUAL) {
> >> +  unsigned long range = exp->maximum - exp->minimum;
> >> +  unsigned long shutter = ((exp->val - exp->minimum) * 
> >> 1048 +
> >> range / 2) / range + 1;
> >> 
> >>dev_dbg(&client->dev,
> >>"Setting shutter width from %d to %lu\n",
> >> -  reg_read(client, MT9M001_SHUTTER_WIDTH),
> >> -  shutter);
> >> +  reg_read(client, MT9M001_SHUTTER_WIDTH), 
> >> shutter);
> >>if (reg_write(client, MT9M001_SHUTTER_WIDTH, shutter) < 
> >> 0)
> >>return -EIO;
> >> -  mt9m001->exposure = ctrl->value;
> >> -  mt9m001->autoexposure = 0;
> >> -  }
> >> -  break;
> >> -  case V4L2_CID_EXPOSURE_AUTO:
> >> -  if (ctrl->value) {
> >> +  } else {
> >>const u16 vblank = 25;
> >>unsigned int total_h = mt9m001->rect.height +
> >>mt9m001->y_skip_top + vblank;
> >> -  if (reg_write(client, MT9M001_SHUTTER_WIDTH,
> >> -total_h) < 0)
> >> +
> >> +  if (reg_write(client, MT9M001_SHUTTER_WIDTH, total_h) < 
> >> 0)
> >>return -EIO;
> >> -  qctrl = soc_camera_find_qctrl(icd->ops, 
> >> V4L2_CID_EXPOSURE);
> >> -  mt9m001->exposure = (524 + (total_h - 1) *
> >> -   (qctrl->maximum - qctrl->minimum)) /
> >> -  1048 + qctrl->minimum;
> >> -  mt9m001->autoexposure = 1;
> >> -  } else
> >> -  mt9m001->autoexposure = 0;
> >> -  break;
> >> +  exp->val = (524 + (total_h - 1) *
> >> +  (exp->maximum - exp->minimum)) / 1048 +
> >> +  exp->minimum;
> >> +  }
> >> +  return 0;
> >>}
> >> -  return 0;
> >> +  return -EINVAL;
> > 
> > It seems to me, that you've dropped V4L2_CID_EXPOSURE here, was it 
> > intentional? I won't verify this in detail now, because, if it wasn't 
> > intentional and you fix it in v2, I'll have to re-check it anyway. Or is 
> > it supposed to be handled by that V4L2_EXPOSURE_MANUAL? So, if the user 
> > issues a V4L2_CID_EXPOSURE, are you getting V4L2_CID_EXPOSURE_AUTO with 
> > val == V4L2_EXPOSURE_MANUAL instead? Weird...
> 
> I also wonder first at this part for a long time like below:
> 
> 1. when calling V4L2_CID_EXPOSURE_AUTO with V4L2_EXPOSURE_AUTO, it's ok.
> 2. when calling V4L2_CID_EXPOSURE_AUTO with V4L2_EXPOSURE_MANUAL, it's
> also ok.
> 3. when calling V4L2_CID_EXPOSURE? where the device handle this CID?
> 
> but, after testing with application step by step, I finally know below:
> when calling V4L2_CID_EXPOSURE, changing internal(v4l2_ctrl framework) 
> variable,
> exactly struct v4l2_ctrl exposure, which is register for probing time by
> V4L2_CID_EXPOSURE, and clustered with struct v4l2_ctrl autoexposure. So, when
> the device no needs to handle this values, but it automatically calls control 
> clustered with
> itself, in this case the V4L2_CID_EXPOSURE calls(just 
> words)V4L2_CID_EXPOSURE_AUTO.
> 
> So, the my POV is that foo clustered with auto_foo calls auto_foo with foo's 
> characteristics.  

Correct. This tells me two things: 1) nobody ever reads documentation, and 2) I
must place a comment in the code making people aware that the 
V4L2_CID_EXPOSURE_AUTO
case will handle all controls in the cluster.

Re: [RFC PATCH 03/12] mt9m001: convert to the control framework.

2011-01-24 Thread Hans Verkuil
On Saturday, January 22, 2011 22:21:23 Guennadi Liakhovetski wrote:
> On Wed, 12 Jan 2011, Hans Verkuil wrote:
> 
> > Signed-off-by: Hans Verkuil 
> > ---
> >  drivers/media/video/mt9m001.c |  210 
> > +++--
> >  1 files changed, 75 insertions(+), 135 deletions(-)
> > 
> > diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c
> > index f7fc88d..b9b6e33 100644
> > --- a/drivers/media/video/mt9m001.c
> > +++ b/drivers/media/video/mt9m001.c
> > @@ -15,6 +15,7 @@
> >  
> >  #include 
> >  #include 
> > +#include 
> >  #include 
> >  
> >  /*
> > @@ -84,15 +85,18 @@ static const struct mt9m001_datafmt 
> > mt9m001_monochrome_fmts[] = {
> >  
> >  struct mt9m001 {
> > struct v4l2_subdev subdev;
> > +   struct v4l2_ctrl_handler hdl;
> > +   struct {
> > +   /* exposure/auto-exposure cluster */
> > +   struct v4l2_ctrl *autoexposure;
> > +   struct v4l2_ctrl *exposure;
> > +   };
> 
> Hm, why an anonymous struct? Why not just put them directly at the top 
> level?

There are a few ways you can declare control clusters. This is the most obvious:

struct v4l2_ctrl *exp_cluster[2];

The only problem with this is that it is very annoying if you have to access
one of these controls: doing 'state->exp_cluster[CTRL_EXPOSURE]->cur.val' is
quite a mouthful.

The other approach is to define the pointers directly at top level:

struct mt9m001 {
...
/* exposure/auto-exposure cluster */
struct v4l2_ctrl *autoexposure;
struct v4l2_ctrl *exposure;
};

The problem with that is that it isn't clear that this is a unit and that
you can't just add a field in between.

Using an anonymous struct will 1) keep the ease of use and 2) visually put
these pointers together in a unit.

I've been using it everywhere I need to make a control cluster and it works
very nicely.
 
> > struct v4l2_rect rect;  /* Sensor window */
> > const struct mt9m001_datafmt *fmt;
> > const struct mt9m001_datafmt *fmts;
> > int num_fmts;
> > int model;  /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */
> > -   unsigned int gain;
> > -   unsigned int exposure;
> > unsigned short y_skip_top;  /* Lines to skip at the top */
> > -   unsigned char autoexposure;
> >  };
> >  
> >  static struct mt9m001 *to_mt9m001(const struct i2c_client *client)
> > @@ -209,7 +213,6 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, 
> > struct v4l2_crop *a)
> > struct i2c_client *client = v4l2_get_subdevdata(sd);
> > struct mt9m001 *mt9m001 = to_mt9m001(client);
> > struct v4l2_rect rect = a->c;
> > -   struct soc_camera_device *icd = client->dev.platform_data;
> > int ret;
> > const u16 hblank = 9, vblank = 25;
> > unsigned int total_h;
> > @@ -251,17 +254,18 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, 
> > struct v4l2_crop *a)
> > if (!ret)
> > ret = reg_write(client, MT9M001_WINDOW_HEIGHT,
> > rect.height + mt9m001->y_skip_top - 1);
> > -   if (!ret && mt9m001->autoexposure) {
> > +   v4l2_ctrl_lock(mt9m001->autoexposure);
> > +   if (!ret && mt9m001->autoexposure->cur.val == V4L2_EXPOSURE_AUTO) {
> > ret = reg_write(client, MT9M001_SHUTTER_WIDTH, total_h);
> > if (!ret) {
> > -   const struct v4l2_queryctrl *qctrl =
> > -   soc_camera_find_qctrl(icd->ops,
> > - V4L2_CID_EXPOSURE);
> > -   mt9m001->exposure = (524 + (total_h - 1) *
> > -(qctrl->maximum - qctrl->minimum)) /
> > -   1048 + qctrl->minimum;
> > +   struct v4l2_ctrl *ctrl = mt9m001->exposure;
> > +
> > +   ctrl->cur.val = (524 + (total_h - 1) *
> > +(ctrl->maximum - ctrl->minimum)) /
> > +   1048 + ctrl->minimum;
> > }
> > }
> > +   v4l2_ctrl_unlock(mt9m001->autoexposure);
> >  
> > if (!ret)
> > mt9m001->rect = rect;
> > @@ -421,107 +425,36 @@ static int mt9m001_s_register(struct v4l2_subdev *sd,
> >  }
> >  #endif
> >  
> > -static const struct v4l2_queryctrl mt9m001_controls[] = {
> > -   {
> > -   .id = V4L2_CID_VFLIP,
> > -   .type   = V4L2_CTRL_TYPE_BOOLEAN,
> > -   .name   = "Flip Vertically",
> > -   .minimum= 0,
> > -   .maximum= 1,
> > -   .step   = 1,
> > -   .default_value  = 0,
> > -   }, {
> > -   .id = V4L2_CID_GAIN,
> > -   .type   = V4L2_CTRL_TYPE_INTEGER,
> > -   .name   = "Gain",
> > -   .minimum= 0,
> > -   .maximum= 127,
> > -   .step   = 1,
> > -   .default_value  = 64,
> > -   .flags  = V4L2_CTRL_FLAG_SLIDER,
> > -   }, {
> > -   .id 

Re: [RFC PATCH 03/12] mt9m001: convert to the control framework.

2011-01-22 Thread Kim HeungJun
Hello,

I'm reading threads about the new v4l2_ctrl framework and If you don't mind
I gotta tell you my humble opinion about testing result the new v4l2_ctrl
framework subdev.
I have actually similar curcumstance, with I2C subdev M5MOLS Fujitsu device
which is just send the patch and S5PC210 board for testing this, except not
using soc_camera framework.
But, it's maybe helpful to discuss about this changes to everyone.

2011. 1. 23., 오전 6:21, Guennadi Liakhovetski 작성:

> On Wed, 12 Jan 2011, Hans Verkuil wrote:
> 
>> Signed-off-by: Hans Verkuil 

[snip]

>> -case V4L2_CID_EXPOSURE:
>> -/* mt9m001 has maximum == default */
>> -if (ctrl->value > qctrl->maximum || ctrl->value < 
>> qctrl->minimum)
>> -return -EINVAL;
>> -else {
>> -unsigned long range = qctrl->maximum - qctrl->minimum;
>> -unsigned long shutter = ((ctrl->value - qctrl->minimum) 
>> * 1048 +
>> +case V4L2_CID_EXPOSURE_AUTO:
>> +/* Force manual exposure if only the exposure was changed */
>> +if (!ctrl->has_new)
>> +ctrl->val = V4L2_EXPOSURE_MANUAL;
>> +if (ctrl->val == V4L2_EXPOSURE_MANUAL) {
>> +unsigned long range = exp->maximum - exp->minimum;
>> +unsigned long shutter = ((exp->val - exp->minimum) * 
>> 1048 +
>>   range / 2) / range + 1;
>> 
>>  dev_dbg(&client->dev,
>>  "Setting shutter width from %d to %lu\n",
>> -reg_read(client, MT9M001_SHUTTER_WIDTH),
>> -shutter);
>> +reg_read(client, MT9M001_SHUTTER_WIDTH), 
>> shutter);
>>  if (reg_write(client, MT9M001_SHUTTER_WIDTH, shutter) < 
>> 0)
>>  return -EIO;
>> -mt9m001->exposure = ctrl->value;
>> -mt9m001->autoexposure = 0;
>> -}
>> -break;
>> -case V4L2_CID_EXPOSURE_AUTO:
>> -if (ctrl->value) {
>> +} else {
>>  const u16 vblank = 25;
>>  unsigned int total_h = mt9m001->rect.height +
>>  mt9m001->y_skip_top + vblank;
>> -if (reg_write(client, MT9M001_SHUTTER_WIDTH,
>> -  total_h) < 0)
>> +
>> +if (reg_write(client, MT9M001_SHUTTER_WIDTH, total_h) < 
>> 0)
>>  return -EIO;
>> -qctrl = soc_camera_find_qctrl(icd->ops, 
>> V4L2_CID_EXPOSURE);
>> -mt9m001->exposure = (524 + (total_h - 1) *
>> - (qctrl->maximum - qctrl->minimum)) /
>> -1048 + qctrl->minimum;
>> -mt9m001->autoexposure = 1;
>> -} else
>> -mt9m001->autoexposure = 0;
>> -break;
>> +exp->val = (524 + (total_h - 1) *
>> +(exp->maximum - exp->minimum)) / 1048 +
>> +exp->minimum;
>> +}
>> +return 0;
>>  }
>> -return 0;
>> +return -EINVAL;
> 
> It seems to me, that you've dropped V4L2_CID_EXPOSURE here, was it 
> intentional? I won't verify this in detail now, because, if it wasn't 
> intentional and you fix it in v2, I'll have to re-check it anyway. Or is 
> it supposed to be handled by that V4L2_EXPOSURE_MANUAL? So, if the user 
> issues a V4L2_CID_EXPOSURE, are you getting V4L2_CID_EXPOSURE_AUTO with 
> val == V4L2_EXPOSURE_MANUAL instead? Weird...

I also wonder first at this part for a long time like below:

1. when calling V4L2_CID_EXPOSURE_AUTO with V4L2_EXPOSURE_AUTO, it's ok.
2. when calling V4L2_CID_EXPOSURE_AUTO with V4L2_EXPOSURE_MANUAL, it's
also ok.
3. when calling V4L2_CID_EXPOSURE? where the device handle this CID?

but, after testing with application step by step, I finally know below:
when calling V4L2_CID_EXPOSURE, changing internal(v4l2_ctrl framework) variable,
exactly struct v4l2_ctrl exposure, which is register for probing time by
V4L2_CID_EXPOSURE, and clustered with struct v4l2_ctrl autoexposure. So, when
the device no needs to handle this values, but it automatically calls control 
clustered with
itself, in this case the V4L2_CID_EXPOSURE calls(just 
words)V4L2_CID_EXPOSURE_AUTO.

So, the my POV is that foo clustered with auto_foo calls auto_foo with foo's 
characteristics.  

But, Hans probably would do more clear answer.

Regards,
Heungjun Kim

  --
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [RFC PATCH 03/12] mt9m001: convert to the control framework.

2011-01-22 Thread Guennadi Liakhovetski
On Wed, 12 Jan 2011, Hans Verkuil wrote:

> Signed-off-by: Hans Verkuil 
> ---
>  drivers/media/video/mt9m001.c |  210 
> +++--
>  1 files changed, 75 insertions(+), 135 deletions(-)
> 
> diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c
> index f7fc88d..b9b6e33 100644
> --- a/drivers/media/video/mt9m001.c
> +++ b/drivers/media/video/mt9m001.c
> @@ -15,6 +15,7 @@
>  
>  #include 
>  #include 
> +#include 
>  #include 
>  
>  /*
> @@ -84,15 +85,18 @@ static const struct mt9m001_datafmt 
> mt9m001_monochrome_fmts[] = {
>  
>  struct mt9m001 {
>   struct v4l2_subdev subdev;
> + struct v4l2_ctrl_handler hdl;
> + struct {
> + /* exposure/auto-exposure cluster */
> + struct v4l2_ctrl *autoexposure;
> + struct v4l2_ctrl *exposure;
> + };

Hm, why an anonymous struct? Why not just put them directly at the top 
level?

>   struct v4l2_rect rect;  /* Sensor window */
>   const struct mt9m001_datafmt *fmt;
>   const struct mt9m001_datafmt *fmts;
>   int num_fmts;
>   int model;  /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */
> - unsigned int gain;
> - unsigned int exposure;
>   unsigned short y_skip_top;  /* Lines to skip at the top */
> - unsigned char autoexposure;
>  };
>  
>  static struct mt9m001 *to_mt9m001(const struct i2c_client *client)
> @@ -209,7 +213,6 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, struct 
> v4l2_crop *a)
>   struct i2c_client *client = v4l2_get_subdevdata(sd);
>   struct mt9m001 *mt9m001 = to_mt9m001(client);
>   struct v4l2_rect rect = a->c;
> - struct soc_camera_device *icd = client->dev.platform_data;
>   int ret;
>   const u16 hblank = 9, vblank = 25;
>   unsigned int total_h;
> @@ -251,17 +254,18 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, 
> struct v4l2_crop *a)
>   if (!ret)
>   ret = reg_write(client, MT9M001_WINDOW_HEIGHT,
>   rect.height + mt9m001->y_skip_top - 1);
> - if (!ret && mt9m001->autoexposure) {
> + v4l2_ctrl_lock(mt9m001->autoexposure);
> + if (!ret && mt9m001->autoexposure->cur.val == V4L2_EXPOSURE_AUTO) {
>   ret = reg_write(client, MT9M001_SHUTTER_WIDTH, total_h);
>   if (!ret) {
> - const struct v4l2_queryctrl *qctrl =
> - soc_camera_find_qctrl(icd->ops,
> -   V4L2_CID_EXPOSURE);
> - mt9m001->exposure = (524 + (total_h - 1) *
> -  (qctrl->maximum - qctrl->minimum)) /
> - 1048 + qctrl->minimum;
> + struct v4l2_ctrl *ctrl = mt9m001->exposure;
> +
> + ctrl->cur.val = (524 + (total_h - 1) *
> +  (ctrl->maximum - ctrl->minimum)) /
> + 1048 + ctrl->minimum;
>   }
>   }
> + v4l2_ctrl_unlock(mt9m001->autoexposure);
>  
>   if (!ret)
>   mt9m001->rect = rect;
> @@ -421,107 +425,36 @@ static int mt9m001_s_register(struct v4l2_subdev *sd,
>  }
>  #endif
>  
> -static const struct v4l2_queryctrl mt9m001_controls[] = {
> - {
> - .id = V4L2_CID_VFLIP,
> - .type   = V4L2_CTRL_TYPE_BOOLEAN,
> - .name   = "Flip Vertically",
> - .minimum= 0,
> - .maximum= 1,
> - .step   = 1,
> - .default_value  = 0,
> - }, {
> - .id = V4L2_CID_GAIN,
> - .type   = V4L2_CTRL_TYPE_INTEGER,
> - .name   = "Gain",
> - .minimum= 0,
> - .maximum= 127,
> - .step   = 1,
> - .default_value  = 64,
> - .flags  = V4L2_CTRL_FLAG_SLIDER,
> - }, {
> - .id = V4L2_CID_EXPOSURE,
> - .type   = V4L2_CTRL_TYPE_INTEGER,
> - .name   = "Exposure",
> - .minimum= 1,
> - .maximum= 255,
> - .step   = 1,
> - .default_value  = 255,
> - .flags  = V4L2_CTRL_FLAG_SLIDER,
> - }, {
> - .id = V4L2_CID_EXPOSURE_AUTO,
> - .type   = V4L2_CTRL_TYPE_BOOLEAN,
> - .name   = "Automatic Exposure",
> - .minimum= 0,
> - .maximum= 1,
> - .step   = 1,
> - .default_value  = 1,
> - }
> -};
> -
>  static struct soc_camera_ops mt9m001_ops = {
>   .set_bus_param  = mt9m001_set_bus_param,
>   .query_bus_param= mt9m001_query_bus_param,
> - .controls   = mt9m001_controls,
> - .num_controls   = ARRAY_SIZE(mt9m001_controls),
>  };
> 

[RFC PATCH 03/12] mt9m001: convert to the control framework.

2011-01-11 Thread Hans Verkuil
Signed-off-by: Hans Verkuil 
---
 drivers/media/video/mt9m001.c |  210 +++--
 1 files changed, 75 insertions(+), 135 deletions(-)

diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c
index f7fc88d..b9b6e33 100644
--- a/drivers/media/video/mt9m001.c
+++ b/drivers/media/video/mt9m001.c
@@ -15,6 +15,7 @@
 
 #include 
 #include 
+#include 
 #include 
 
 /*
@@ -84,15 +85,18 @@ static const struct mt9m001_datafmt 
mt9m001_monochrome_fmts[] = {
 
 struct mt9m001 {
struct v4l2_subdev subdev;
+   struct v4l2_ctrl_handler hdl;
+   struct {
+   /* exposure/auto-exposure cluster */
+   struct v4l2_ctrl *autoexposure;
+   struct v4l2_ctrl *exposure;
+   };
struct v4l2_rect rect;  /* Sensor window */
const struct mt9m001_datafmt *fmt;
const struct mt9m001_datafmt *fmts;
int num_fmts;
int model;  /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */
-   unsigned int gain;
-   unsigned int exposure;
unsigned short y_skip_top;  /* Lines to skip at the top */
-   unsigned char autoexposure;
 };
 
 static struct mt9m001 *to_mt9m001(const struct i2c_client *client)
@@ -209,7 +213,6 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, struct 
v4l2_crop *a)
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m001 *mt9m001 = to_mt9m001(client);
struct v4l2_rect rect = a->c;
-   struct soc_camera_device *icd = client->dev.platform_data;
int ret;
const u16 hblank = 9, vblank = 25;
unsigned int total_h;
@@ -251,17 +254,18 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, struct 
v4l2_crop *a)
if (!ret)
ret = reg_write(client, MT9M001_WINDOW_HEIGHT,
rect.height + mt9m001->y_skip_top - 1);
-   if (!ret && mt9m001->autoexposure) {
+   v4l2_ctrl_lock(mt9m001->autoexposure);
+   if (!ret && mt9m001->autoexposure->cur.val == V4L2_EXPOSURE_AUTO) {
ret = reg_write(client, MT9M001_SHUTTER_WIDTH, total_h);
if (!ret) {
-   const struct v4l2_queryctrl *qctrl =
-   soc_camera_find_qctrl(icd->ops,
- V4L2_CID_EXPOSURE);
-   mt9m001->exposure = (524 + (total_h - 1) *
-(qctrl->maximum - qctrl->minimum)) /
-   1048 + qctrl->minimum;
+   struct v4l2_ctrl *ctrl = mt9m001->exposure;
+
+   ctrl->cur.val = (524 + (total_h - 1) *
+(ctrl->maximum - ctrl->minimum)) /
+   1048 + ctrl->minimum;
}
}
+   v4l2_ctrl_unlock(mt9m001->autoexposure);
 
if (!ret)
mt9m001->rect = rect;
@@ -421,107 +425,36 @@ static int mt9m001_s_register(struct v4l2_subdev *sd,
 }
 #endif
 
-static const struct v4l2_queryctrl mt9m001_controls[] = {
-   {
-   .id = V4L2_CID_VFLIP,
-   .type   = V4L2_CTRL_TYPE_BOOLEAN,
-   .name   = "Flip Vertically",
-   .minimum= 0,
-   .maximum= 1,
-   .step   = 1,
-   .default_value  = 0,
-   }, {
-   .id = V4L2_CID_GAIN,
-   .type   = V4L2_CTRL_TYPE_INTEGER,
-   .name   = "Gain",
-   .minimum= 0,
-   .maximum= 127,
-   .step   = 1,
-   .default_value  = 64,
-   .flags  = V4L2_CTRL_FLAG_SLIDER,
-   }, {
-   .id = V4L2_CID_EXPOSURE,
-   .type   = V4L2_CTRL_TYPE_INTEGER,
-   .name   = "Exposure",
-   .minimum= 1,
-   .maximum= 255,
-   .step   = 1,
-   .default_value  = 255,
-   .flags  = V4L2_CTRL_FLAG_SLIDER,
-   }, {
-   .id = V4L2_CID_EXPOSURE_AUTO,
-   .type   = V4L2_CTRL_TYPE_BOOLEAN,
-   .name   = "Automatic Exposure",
-   .minimum= 0,
-   .maximum= 1,
-   .step   = 1,
-   .default_value  = 1,
-   }
-};
-
 static struct soc_camera_ops mt9m001_ops = {
.set_bus_param  = mt9m001_set_bus_param,
.query_bus_param= mt9m001_query_bus_param,
-   .controls   = mt9m001_controls,
-   .num_controls   = ARRAY_SIZE(mt9m001_controls),
 };
 
-static int mt9m001_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+static int mt9m001_s_ctrl(struct v4l2_ctrl *ctrl)
 {
+   struct v4l2_subdev *sd =
+   &container_of(ctrl->han