diff options
author | Hans Verkuil <hans.verkuil@cisco.com> | 2012-05-14 05:30:06 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-07-30 17:22:26 -0400 |
commit | bfaab899e7c8ded57afe93ebed234b3688d9a898 (patch) | |
tree | 9067ef2398465c51593217e545b87832b088cd4a /drivers | |
parent | 8792015ec58be8059cdb9ff86e3639481a4be4fb (diff) |
[media] gspca-jeilinj: convert to the control framework
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/video/gspca/jeilinj.c | 218 |
1 files changed, 90 insertions, 128 deletions
diff --git a/drivers/media/video/gspca/jeilinj.c b/drivers/media/video/gspca/jeilinj.c index 5ab3f7e12760..51016db2fc62 100644 --- a/drivers/media/video/gspca/jeilinj.c +++ b/drivers/media/video/gspca/jeilinj.c | |||
@@ -54,21 +54,13 @@ enum { | |||
54 | #define CAMQUALITY_MIN 0 /* highest cam quality */ | 54 | #define CAMQUALITY_MIN 0 /* highest cam quality */ |
55 | #define CAMQUALITY_MAX 97 /* lowest cam quality */ | 55 | #define CAMQUALITY_MAX 97 /* lowest cam quality */ |
56 | 56 | ||
57 | enum e_ctrl { | ||
58 | LIGHTFREQ, | ||
59 | AUTOGAIN, | ||
60 | RED, | ||
61 | GREEN, | ||
62 | BLUE, | ||
63 | NCTRLS /* number of controls */ | ||
64 | }; | ||
65 | |||
66 | /* Structure to hold all of our device specific stuff */ | 57 | /* Structure to hold all of our device specific stuff */ |
67 | struct sd { | 58 | struct sd { |
68 | struct gspca_dev gspca_dev; /* !! must be the first item */ | 59 | struct gspca_dev gspca_dev; /* !! must be the first item */ |
69 | struct gspca_ctrl ctrls[NCTRLS]; | ||
70 | int blocks_left; | 60 | int blocks_left; |
71 | const struct v4l2_pix_format *cap_mode; | 61 | const struct v4l2_pix_format *cap_mode; |
62 | struct v4l2_ctrl *freq; | ||
63 | struct v4l2_ctrl *jpegqual; | ||
72 | /* Driver stuff */ | 64 | /* Driver stuff */ |
73 | u8 type; | 65 | u8 type; |
74 | u8 quality; /* image quality */ | 66 | u8 quality; /* image quality */ |
@@ -139,23 +131,21 @@ static void jlj_read1(struct gspca_dev *gspca_dev, unsigned char response) | |||
139 | } | 131 | } |
140 | } | 132 | } |
141 | 133 | ||
142 | static void setfreq(struct gspca_dev *gspca_dev) | 134 | static void setfreq(struct gspca_dev *gspca_dev, s32 val) |
143 | { | 135 | { |
144 | struct sd *sd = (struct sd *) gspca_dev; | ||
145 | u8 freq_commands[][2] = { | 136 | u8 freq_commands[][2] = { |
146 | {0x71, 0x80}, | 137 | {0x71, 0x80}, |
147 | {0x70, 0x07} | 138 | {0x70, 0x07} |
148 | }; | 139 | }; |
149 | 140 | ||
150 | freq_commands[0][1] |= (sd->ctrls[LIGHTFREQ].val >> 1); | 141 | freq_commands[0][1] |= val >> 1; |
151 | 142 | ||
152 | jlj_write2(gspca_dev, freq_commands[0]); | 143 | jlj_write2(gspca_dev, freq_commands[0]); |
153 | jlj_write2(gspca_dev, freq_commands[1]); | 144 | jlj_write2(gspca_dev, freq_commands[1]); |
154 | } | 145 | } |
155 | 146 | ||
156 | static void setcamquality(struct gspca_dev *gspca_dev) | 147 | static void setcamquality(struct gspca_dev *gspca_dev, s32 val) |
157 | { | 148 | { |
158 | struct sd *sd = (struct sd *) gspca_dev; | ||
159 | u8 quality_commands[][2] = { | 149 | u8 quality_commands[][2] = { |
160 | {0x71, 0x1E}, | 150 | {0x71, 0x1E}, |
161 | {0x70, 0x06} | 151 | {0x70, 0x06} |
@@ -163,7 +153,7 @@ static void setcamquality(struct gspca_dev *gspca_dev) | |||
163 | u8 camquality; | 153 | u8 camquality; |
164 | 154 | ||
165 | /* adapt camera quality from jpeg quality */ | 155 | /* adapt camera quality from jpeg quality */ |
166 | camquality = ((QUALITY_MAX - sd->quality) * CAMQUALITY_MAX) | 156 | camquality = ((QUALITY_MAX - val) * CAMQUALITY_MAX) |
167 | / (QUALITY_MAX - QUALITY_MIN); | 157 | / (QUALITY_MAX - QUALITY_MIN); |
168 | quality_commands[0][1] += camquality; | 158 | quality_commands[0][1] += camquality; |
169 | 159 | ||
@@ -171,130 +161,58 @@ static void setcamquality(struct gspca_dev *gspca_dev) | |||
171 | jlj_write2(gspca_dev, quality_commands[1]); | 161 | jlj_write2(gspca_dev, quality_commands[1]); |
172 | } | 162 | } |
173 | 163 | ||
174 | static void setautogain(struct gspca_dev *gspca_dev) | 164 | static void setautogain(struct gspca_dev *gspca_dev, s32 val) |
175 | { | 165 | { |
176 | struct sd *sd = (struct sd *) gspca_dev; | ||
177 | u8 autogain_commands[][2] = { | 166 | u8 autogain_commands[][2] = { |
178 | {0x94, 0x02}, | 167 | {0x94, 0x02}, |
179 | {0xcf, 0x00} | 168 | {0xcf, 0x00} |
180 | }; | 169 | }; |
181 | 170 | ||
182 | autogain_commands[1][1] = (sd->ctrls[AUTOGAIN].val << 4); | 171 | autogain_commands[1][1] = val << 4; |
183 | 172 | ||
184 | jlj_write2(gspca_dev, autogain_commands[0]); | 173 | jlj_write2(gspca_dev, autogain_commands[0]); |
185 | jlj_write2(gspca_dev, autogain_commands[1]); | 174 | jlj_write2(gspca_dev, autogain_commands[1]); |
186 | } | 175 | } |
187 | 176 | ||
188 | static void setred(struct gspca_dev *gspca_dev) | 177 | static void setred(struct gspca_dev *gspca_dev, s32 val) |
189 | { | 178 | { |
190 | struct sd *sd = (struct sd *) gspca_dev; | ||
191 | u8 setred_commands[][2] = { | 179 | u8 setred_commands[][2] = { |
192 | {0x94, 0x02}, | 180 | {0x94, 0x02}, |
193 | {0xe6, 0x00} | 181 | {0xe6, 0x00} |
194 | }; | 182 | }; |
195 | 183 | ||
196 | setred_commands[1][1] = sd->ctrls[RED].val; | 184 | setred_commands[1][1] = val; |
197 | 185 | ||
198 | jlj_write2(gspca_dev, setred_commands[0]); | 186 | jlj_write2(gspca_dev, setred_commands[0]); |
199 | jlj_write2(gspca_dev, setred_commands[1]); | 187 | jlj_write2(gspca_dev, setred_commands[1]); |
200 | } | 188 | } |
201 | 189 | ||
202 | static void setgreen(struct gspca_dev *gspca_dev) | 190 | static void setgreen(struct gspca_dev *gspca_dev, s32 val) |
203 | { | 191 | { |
204 | struct sd *sd = (struct sd *) gspca_dev; | ||
205 | u8 setgreen_commands[][2] = { | 192 | u8 setgreen_commands[][2] = { |
206 | {0x94, 0x02}, | 193 | {0x94, 0x02}, |
207 | {0xe7, 0x00} | 194 | {0xe7, 0x00} |
208 | }; | 195 | }; |
209 | 196 | ||
210 | setgreen_commands[1][1] = sd->ctrls[GREEN].val; | 197 | setgreen_commands[1][1] = val; |
211 | 198 | ||
212 | jlj_write2(gspca_dev, setgreen_commands[0]); | 199 | jlj_write2(gspca_dev, setgreen_commands[0]); |
213 | jlj_write2(gspca_dev, setgreen_commands[1]); | 200 | jlj_write2(gspca_dev, setgreen_commands[1]); |
214 | } | 201 | } |
215 | 202 | ||
216 | static void setblue(struct gspca_dev *gspca_dev) | 203 | static void setblue(struct gspca_dev *gspca_dev, s32 val) |
217 | { | 204 | { |
218 | struct sd *sd = (struct sd *) gspca_dev; | ||
219 | u8 setblue_commands[][2] = { | 205 | u8 setblue_commands[][2] = { |
220 | {0x94, 0x02}, | 206 | {0x94, 0x02}, |
221 | {0xe9, 0x00} | 207 | {0xe9, 0x00} |
222 | }; | 208 | }; |
223 | 209 | ||
224 | setblue_commands[1][1] = sd->ctrls[BLUE].val; | 210 | setblue_commands[1][1] = val; |
225 | 211 | ||
226 | jlj_write2(gspca_dev, setblue_commands[0]); | 212 | jlj_write2(gspca_dev, setblue_commands[0]); |
227 | jlj_write2(gspca_dev, setblue_commands[1]); | 213 | jlj_write2(gspca_dev, setblue_commands[1]); |
228 | } | 214 | } |
229 | 215 | ||
230 | static const struct ctrl sd_ctrls[NCTRLS] = { | ||
231 | [LIGHTFREQ] = { | ||
232 | { | ||
233 | .id = V4L2_CID_POWER_LINE_FREQUENCY, | ||
234 | .type = V4L2_CTRL_TYPE_MENU, | ||
235 | .name = "Light frequency filter", | ||
236 | .minimum = V4L2_CID_POWER_LINE_FREQUENCY_DISABLED, /* 1 */ | ||
237 | .maximum = V4L2_CID_POWER_LINE_FREQUENCY_60HZ, /* 2 */ | ||
238 | .step = 1, | ||
239 | .default_value = V4L2_CID_POWER_LINE_FREQUENCY_60HZ, | ||
240 | }, | ||
241 | .set_control = setfreq | ||
242 | }, | ||
243 | [AUTOGAIN] = { | ||
244 | { | ||
245 | .id = V4L2_CID_AUTOGAIN, | ||
246 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
247 | .name = "Automatic Gain (and Exposure)", | ||
248 | .minimum = 0, | ||
249 | .maximum = 3, | ||
250 | .step = 1, | ||
251 | #define AUTOGAIN_DEF 0 | ||
252 | .default_value = AUTOGAIN_DEF, | ||
253 | }, | ||
254 | .set_control = setautogain | ||
255 | }, | ||
256 | [RED] = { | ||
257 | { | ||
258 | .id = V4L2_CID_RED_BALANCE, | ||
259 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
260 | .name = "red balance", | ||
261 | .minimum = 0, | ||
262 | .maximum = 3, | ||
263 | .step = 1, | ||
264 | #define RED_BALANCE_DEF 2 | ||
265 | .default_value = RED_BALANCE_DEF, | ||
266 | }, | ||
267 | .set_control = setred | ||
268 | }, | ||
269 | |||
270 | [GREEN] = { | ||
271 | { | ||
272 | .id = V4L2_CID_GAIN, | ||
273 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
274 | .name = "green balance", | ||
275 | .minimum = 0, | ||
276 | .maximum = 3, | ||
277 | .step = 1, | ||
278 | #define GREEN_BALANCE_DEF 2 | ||
279 | .default_value = GREEN_BALANCE_DEF, | ||
280 | }, | ||
281 | .set_control = setgreen | ||
282 | }, | ||
283 | [BLUE] = { | ||
284 | { | ||
285 | .id = V4L2_CID_BLUE_BALANCE, | ||
286 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
287 | .name = "blue balance", | ||
288 | .minimum = 0, | ||
289 | .maximum = 3, | ||
290 | .step = 1, | ||
291 | #define BLUE_BALANCE_DEF 2 | ||
292 | .default_value = BLUE_BALANCE_DEF, | ||
293 | }, | ||
294 | .set_control = setblue | ||
295 | }, | ||
296 | }; | ||
297 | |||
298 | static int jlj_start(struct gspca_dev *gspca_dev) | 216 | static int jlj_start(struct gspca_dev *gspca_dev) |
299 | { | 217 | { |
300 | int i; | 218 | int i; |
@@ -344,9 +262,9 @@ static int jlj_start(struct gspca_dev *gspca_dev) | |||
344 | if (start_commands[i].ack_wanted) | 262 | if (start_commands[i].ack_wanted) |
345 | jlj_read1(gspca_dev, response); | 263 | jlj_read1(gspca_dev, response); |
346 | } | 264 | } |
347 | setcamquality(gspca_dev); | 265 | setcamquality(gspca_dev, v4l2_ctrl_g_ctrl(sd->jpegqual)); |
348 | msleep(2); | 266 | msleep(2); |
349 | setfreq(gspca_dev); | 267 | setfreq(gspca_dev, v4l2_ctrl_g_ctrl(sd->freq)); |
350 | if (gspca_dev->usb_err < 0) | 268 | if (gspca_dev->usb_err < 0) |
351 | PDEBUG(D_ERR, "Start streaming command failed"); | 269 | PDEBUG(D_ERR, "Start streaming command failed"); |
352 | return gspca_dev->usb_err; | 270 | return gspca_dev->usb_err; |
@@ -403,7 +321,6 @@ static int sd_config(struct gspca_dev *gspca_dev, | |||
403 | struct sd *dev = (struct sd *) gspca_dev; | 321 | struct sd *dev = (struct sd *) gspca_dev; |
404 | 322 | ||
405 | dev->type = id->driver_info; | 323 | dev->type = id->driver_info; |
406 | gspca_dev->cam.ctrls = dev->ctrls; | ||
407 | dev->quality = QUALITY_DEF; | 324 | dev->quality = QUALITY_DEF; |
408 | 325 | ||
409 | cam->cam_mode = jlj_mode; | 326 | cam->cam_mode = jlj_mode; |
@@ -479,25 +396,81 @@ static const struct usb_device_id device_table[] = { | |||
479 | 396 | ||
480 | MODULE_DEVICE_TABLE(usb, device_table); | 397 | MODULE_DEVICE_TABLE(usb, device_table); |
481 | 398 | ||
482 | static int sd_querymenu(struct gspca_dev *gspca_dev, | 399 | static int sd_s_ctrl(struct v4l2_ctrl *ctrl) |
483 | struct v4l2_querymenu *menu) | ||
484 | { | 400 | { |
485 | switch (menu->id) { | 401 | struct gspca_dev *gspca_dev = |
402 | container_of(ctrl->handler, struct gspca_dev, ctrl_handler); | ||
403 | struct sd *sd = (struct sd *)gspca_dev; | ||
404 | |||
405 | gspca_dev->usb_err = 0; | ||
406 | |||
407 | if (!gspca_dev->streaming) | ||
408 | return 0; | ||
409 | |||
410 | switch (ctrl->id) { | ||
486 | case V4L2_CID_POWER_LINE_FREQUENCY: | 411 | case V4L2_CID_POWER_LINE_FREQUENCY: |
487 | switch (menu->index) { | 412 | setfreq(gspca_dev, ctrl->val); |
488 | case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */ | 413 | break; |
489 | strcpy((char *) menu->name, "disable"); | 414 | case V4L2_CID_RED_BALANCE: |
490 | return 0; | 415 | setred(gspca_dev, ctrl->val); |
491 | case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ | 416 | break; |
492 | strcpy((char *) menu->name, "50 Hz"); | 417 | case V4L2_CID_GAIN: |
493 | return 0; | 418 | setgreen(gspca_dev, ctrl->val); |
494 | case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */ | 419 | break; |
495 | strcpy((char *) menu->name, "60 Hz"); | 420 | case V4L2_CID_BLUE_BALANCE: |
496 | return 0; | 421 | setblue(gspca_dev, ctrl->val); |
497 | } | 422 | break; |
423 | case V4L2_CID_AUTOGAIN: | ||
424 | setautogain(gspca_dev, ctrl->val); | ||
425 | break; | ||
426 | case V4L2_CID_JPEG_COMPRESSION_QUALITY: | ||
427 | jpeg_set_qual(sd->jpeg_hdr, ctrl->val); | ||
428 | setcamquality(gspca_dev, ctrl->val); | ||
498 | break; | 429 | break; |
499 | } | 430 | } |
500 | return -EINVAL; | 431 | return gspca_dev->usb_err; |
432 | } | ||
433 | |||
434 | static const struct v4l2_ctrl_ops sd_ctrl_ops = { | ||
435 | .s_ctrl = sd_s_ctrl, | ||
436 | }; | ||
437 | |||
438 | static int sd_init_controls(struct gspca_dev *gspca_dev) | ||
439 | { | ||
440 | struct sd *sd = (struct sd *)gspca_dev; | ||
441 | struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; | ||
442 | static const struct v4l2_ctrl_config custom_autogain = { | ||
443 | .ops = &sd_ctrl_ops, | ||
444 | .id = V4L2_CID_AUTOGAIN, | ||
445 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
446 | .name = "Automatic Gain (and Exposure)", | ||
447 | .max = 3, | ||
448 | .step = 1, | ||
449 | .def = 0, | ||
450 | }; | ||
451 | |||
452 | gspca_dev->vdev.ctrl_handler = hdl; | ||
453 | v4l2_ctrl_handler_init(hdl, 6); | ||
454 | sd->freq = v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops, | ||
455 | V4L2_CID_POWER_LINE_FREQUENCY, | ||
456 | V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 1, | ||
457 | V4L2_CID_POWER_LINE_FREQUENCY_60HZ); | ||
458 | v4l2_ctrl_new_custom(hdl, &custom_autogain, NULL); | ||
459 | v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, | ||
460 | V4L2_CID_RED_BALANCE, 0, 3, 1, 2); | ||
461 | v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, | ||
462 | V4L2_CID_GAIN, 0, 3, 1, 2); | ||
463 | v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, | ||
464 | V4L2_CID_BLUE_BALANCE, 0, 3, 1, 2); | ||
465 | sd->jpegqual = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, | ||
466 | V4L2_CID_JPEG_COMPRESSION_QUALITY, | ||
467 | QUALITY_MIN, QUALITY_MAX, 1, QUALITY_DEF); | ||
468 | |||
469 | if (hdl->error) { | ||
470 | pr_err("Could not initialize controls\n"); | ||
471 | return hdl->error; | ||
472 | } | ||
473 | return 0; | ||
501 | } | 474 | } |
502 | 475 | ||
503 | static int sd_set_jcomp(struct gspca_dev *gspca_dev, | 476 | static int sd_set_jcomp(struct gspca_dev *gspca_dev, |
@@ -505,16 +478,7 @@ static int sd_set_jcomp(struct gspca_dev *gspca_dev, | |||
505 | { | 478 | { |
506 | struct sd *sd = (struct sd *) gspca_dev; | 479 | struct sd *sd = (struct sd *) gspca_dev; |
507 | 480 | ||
508 | if (jcomp->quality < QUALITY_MIN) | 481 | v4l2_ctrl_s_ctrl(sd->jpegqual, jcomp->quality); |
509 | sd->quality = QUALITY_MIN; | ||
510 | else if (jcomp->quality > QUALITY_MAX) | ||
511 | sd->quality = QUALITY_MAX; | ||
512 | else | ||
513 | sd->quality = jcomp->quality; | ||
514 | if (gspca_dev->streaming) { | ||
515 | jpeg_set_qual(sd->jpeg_hdr, sd->quality); | ||
516 | setcamquality(gspca_dev); | ||
517 | } | ||
518 | return 0; | 482 | return 0; |
519 | } | 483 | } |
520 | 484 | ||
@@ -524,7 +488,7 @@ static int sd_get_jcomp(struct gspca_dev *gspca_dev, | |||
524 | struct sd *sd = (struct sd *) gspca_dev; | 488 | struct sd *sd = (struct sd *) gspca_dev; |
525 | 489 | ||
526 | memset(jcomp, 0, sizeof *jcomp); | 490 | memset(jcomp, 0, sizeof *jcomp); |
527 | jcomp->quality = sd->quality; | 491 | jcomp->quality = v4l2_ctrl_g_ctrl(sd->jpegqual); |
528 | jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT | 492 | jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT |
529 | | V4L2_JPEG_MARKER_DQT; | 493 | | V4L2_JPEG_MARKER_DQT; |
530 | return 0; | 494 | return 0; |
@@ -546,12 +510,10 @@ static const struct sd_desc sd_desc_sportscam_dv15 = { | |||
546 | .name = MODULE_NAME, | 510 | .name = MODULE_NAME, |
547 | .config = sd_config, | 511 | .config = sd_config, |
548 | .init = sd_init, | 512 | .init = sd_init, |
513 | .init_controls = sd_init_controls, | ||
549 | .start = sd_start, | 514 | .start = sd_start, |
550 | .stopN = sd_stopN, | 515 | .stopN = sd_stopN, |
551 | .pkt_scan = sd_pkt_scan, | 516 | .pkt_scan = sd_pkt_scan, |
552 | .ctrls = sd_ctrls, | ||
553 | .nctrls = ARRAY_SIZE(sd_ctrls), | ||
554 | .querymenu = sd_querymenu, | ||
555 | .get_jcomp = sd_get_jcomp, | 517 | .get_jcomp = sd_get_jcomp, |
556 | .set_jcomp = sd_set_jcomp, | 518 | .set_jcomp = sd_set_jcomp, |
557 | }; | 519 | }; |