Re: [RFC PATCH 03/12] mt9m001: convert to the control framework.
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.
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.
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.
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.
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