aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/gspca/jeilinj.c
diff options
context:
space:
mode:
authorPatrice Chotard <patrice.chotard@sfr.fr>2011-04-18 16:42:06 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-05-20 08:27:22 -0400
commit5396e62fa1c637f9993023c82f5a1840ab58a960 (patch)
treee86bc81152345374ddf7b09bf576157ffc2a1647 /drivers/media/video/gspca/jeilinj.c
parent713b466f0f67de2d9dc9de85741fffd8516b34fb (diff)
[media] gspca - jeilinj: add SPORTSCAM specific controls
Signed-off-by: Patrice CHOTARD <patricechotard@free.fr> Signed-off-by: Jean-François Moine <moinejf@free.fr> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/gspca/jeilinj.c')
-rw-r--r--drivers/media/video/gspca/jeilinj.c248
1 files changed, 242 insertions, 6 deletions
diff --git a/drivers/media/video/gspca/jeilinj.c b/drivers/media/video/gspca/jeilinj.c
index da92867fb27..1bd9c4b542d 100644
--- a/drivers/media/video/gspca/jeilinj.c
+++ b/drivers/media/video/gspca/jeilinj.c
@@ -5,6 +5,8 @@
5 * download raw JPEG data. 5 * download raw JPEG data.
6 * 6 *
7 * Copyright (C) 2009 Theodore Kilgore 7 * Copyright (C) 2009 Theodore Kilgore
8 *
9 * Sportscam DV15 support and control settings are
8 * Copyright (C) 2011 Patrice Chotard 10 * Copyright (C) 2011 Patrice Chotard
9 * 11 *
10 * This program is free software; you can redistribute it and/or modify 12 * This program is free software; you can redistribute it and/or modify
@@ -46,14 +48,31 @@ enum {
46 SAKAR_57379, 48 SAKAR_57379,
47 SPORTSCAM_DV15, 49 SPORTSCAM_DV15,
48}; 50};
51
52#define CAMQUALITY_MIN 0 /* highest cam quality */
53#define CAMQUALITY_MAX 97 /* lowest cam quality */
54
55enum e_ctrl {
56 LIGHTFREQ,
57 AUTOGAIN,
58 RED,
59 GREEN,
60 BLUE,
61 NCTRLS /* number of controls */
62};
63
49/* Structure to hold all of our device specific stuff */ 64/* Structure to hold all of our device specific stuff */
50struct sd { 65struct sd {
51 struct gspca_dev gspca_dev; /* !! must be the first item */ 66 struct gspca_dev gspca_dev; /* !! must be the first item */
67 struct gspca_ctrl ctrls[NCTRLS];
52 int blocks_left; 68 int blocks_left;
53 const struct v4l2_pix_format *cap_mode; 69 const struct v4l2_pix_format *cap_mode;
54 /* Driver stuff */ 70 /* Driver stuff */
55 u8 type; 71 u8 type;
56 u8 quality; /* image quality */ 72 u8 quality; /* image quality */
73#define QUALITY_MIN 35
74#define QUALITY_MAX 85
75#define QUALITY_DEF 85
57 u8 jpeg_hdr[JPEG_HDR_SZ]; 76 u8 jpeg_hdr[JPEG_HDR_SZ];
58}; 77};
59 78
@@ -118,6 +137,162 @@ static void jlj_read1(struct gspca_dev *gspca_dev, unsigned char response)
118 } 137 }
119} 138}
120 139
140static void setfreq(struct gspca_dev *gspca_dev)
141{
142 struct sd *sd = (struct sd *) gspca_dev;
143 u8 freq_commands[][2] = {
144 {0x71, 0x80},
145 {0x70, 0x07}
146 };
147
148 freq_commands[0][1] |= (sd->ctrls[LIGHTFREQ].val >> 1);
149
150 jlj_write2(gspca_dev, freq_commands[0]);
151 jlj_write2(gspca_dev, freq_commands[1]);
152}
153
154static void setcamquality(struct gspca_dev *gspca_dev)
155{
156 struct sd *sd = (struct sd *) gspca_dev;
157 u8 quality_commands[][2] = {
158 {0x71, 0x1E},
159 {0x70, 0x06}
160 };
161 u8 camquality;
162
163 /* adapt camera quality from jpeg quality */
164 camquality = ((QUALITY_MAX - sd->quality) * CAMQUALITY_MAX)
165 / (QUALITY_MAX - QUALITY_MIN);
166 quality_commands[0][1] += camquality;
167
168 jlj_write2(gspca_dev, quality_commands[0]);
169 jlj_write2(gspca_dev, quality_commands[1]);
170}
171
172static void setautogain(struct gspca_dev *gspca_dev)
173{
174 struct sd *sd = (struct sd *) gspca_dev;
175 u8 autogain_commands[][2] = {
176 {0x94, 0x02},
177 {0xcf, 0x00}
178 };
179
180 autogain_commands[1][1] = (sd->ctrls[AUTOGAIN].val << 4);
181
182 jlj_write2(gspca_dev, autogain_commands[0]);
183 jlj_write2(gspca_dev, autogain_commands[1]);
184}
185
186static void setred(struct gspca_dev *gspca_dev)
187{
188 struct sd *sd = (struct sd *) gspca_dev;
189 u8 setred_commands[][2] = {
190 {0x94, 0x02},
191 {0xe6, 0x00}
192 };
193
194 setred_commands[1][1] = sd->ctrls[RED].val;
195
196 jlj_write2(gspca_dev, setred_commands[0]);
197 jlj_write2(gspca_dev, setred_commands[1]);
198}
199
200static void setgreen(struct gspca_dev *gspca_dev)
201{
202 struct sd *sd = (struct sd *) gspca_dev;
203 u8 setgreen_commands[][2] = {
204 {0x94, 0x02},
205 {0xe7, 0x00}
206 };
207
208 setgreen_commands[1][1] = sd->ctrls[GREEN].val;
209
210 jlj_write2(gspca_dev, setgreen_commands[0]);
211 jlj_write2(gspca_dev, setgreen_commands[1]);
212}
213
214static void setblue(struct gspca_dev *gspca_dev)
215{
216 struct sd *sd = (struct sd *) gspca_dev;
217 u8 setblue_commands[][2] = {
218 {0x94, 0x02},
219 {0xe9, 0x00}
220 };
221
222 setblue_commands[1][1] = sd->ctrls[BLUE].val;
223
224 jlj_write2(gspca_dev, setblue_commands[0]);
225 jlj_write2(gspca_dev, setblue_commands[1]);
226}
227
228static const struct ctrl sd_ctrls[NCTRLS] = {
229[LIGHTFREQ] = {
230 {
231 .id = V4L2_CID_POWER_LINE_FREQUENCY,
232 .type = V4L2_CTRL_TYPE_MENU,
233 .name = "Light frequency filter",
234 .minimum = V4L2_CID_POWER_LINE_FREQUENCY_DISABLED, /* 1 */
235 .maximum = V4L2_CID_POWER_LINE_FREQUENCY_60HZ, /* 2 */
236 .step = 1,
237 .default_value = V4L2_CID_POWER_LINE_FREQUENCY_60HZ,
238 },
239 .set_control = setfreq
240 },
241[AUTOGAIN] = {
242 {
243 .id = V4L2_CID_AUTOGAIN,
244 .type = V4L2_CTRL_TYPE_INTEGER,
245 .name = "Automatic Gain (and Exposure)",
246 .minimum = 0,
247 .maximum = 3,
248 .step = 1,
249#define AUTOGAIN_DEF 0
250 .default_value = AUTOGAIN_DEF,
251 },
252 .set_control = setautogain
253 },
254[RED] = {
255 {
256 .id = V4L2_CID_RED_BALANCE,
257 .type = V4L2_CTRL_TYPE_INTEGER,
258 .name = "red balance",
259 .minimum = 0,
260 .maximum = 3,
261 .step = 1,
262#define RED_BALANCE_DEF 2
263 .default_value = RED_BALANCE_DEF,
264 },
265 .set_control = setred
266 },
267
268[GREEN] = {
269 {
270 .id = V4L2_CID_GAIN,
271 .type = V4L2_CTRL_TYPE_INTEGER,
272 .name = "green balance",
273 .minimum = 0,
274 .maximum = 3,
275 .step = 1,
276#define GREEN_BALANCE_DEF 2
277 .default_value = GREEN_BALANCE_DEF,
278 },
279 .set_control = setgreen
280 },
281[BLUE] = {
282 {
283 .id = V4L2_CID_BLUE_BALANCE,
284 .type = V4L2_CTRL_TYPE_INTEGER,
285 .name = "blue balance",
286 .minimum = 0,
287 .maximum = 3,
288 .step = 1,
289#define BLUE_BALANCE_DEF 2
290 .default_value = BLUE_BALANCE_DEF,
291 },
292 .set_control = setblue
293 },
294};
295
121static int jlj_start(struct gspca_dev *gspca_dev) 296static int jlj_start(struct gspca_dev *gspca_dev)
122{ 297{
123 int i; 298 int i;
@@ -148,11 +323,7 @@ static int jlj_start(struct gspca_dev *gspca_dev)
148 {{0x94, 0x02}, 0, 0}, 323 {{0x94, 0x02}, 0, 0},
149 {{0xe6, 0x2c}, 0, 0}, 324 {{0xe6, 0x2c}, 0, 0},
150 {{0x94, 0x03}, 0, 0}, 325 {{0x94, 0x03}, 0, 0},
151 {{0xaa, 0x00}, 0, 0}, 326 {{0xaa, 0x00}, 0, 0}
152 {{0x71, 0x1e}, 0, 0},
153 {{0x70, 0x06}, 0, 0},
154 {{0x71, 0x80}, 0, 0},
155 {{0x70, 0x07}, 0, 0}
156 }; 327 };
157 328
158 sd->blocks_left = 0; 329 sd->blocks_left = 0;
@@ -171,6 +342,9 @@ static int jlj_start(struct gspca_dev *gspca_dev)
171 if (start_commands[i].ack_wanted) 342 if (start_commands[i].ack_wanted)
172 jlj_read1(gspca_dev, response); 343 jlj_read1(gspca_dev, response);
173 } 344 }
345 setcamquality(gspca_dev);
346 msleep(2);
347 setfreq(gspca_dev);
174 if (gspca_dev->usb_err < 0) 348 if (gspca_dev->usb_err < 0)
175 PDEBUG(D_ERR, "Start streaming command failed"); 349 PDEBUG(D_ERR, "Start streaming command failed");
176 return gspca_dev->usb_err; 350 return gspca_dev->usb_err;
@@ -227,7 +401,12 @@ static int sd_config(struct gspca_dev *gspca_dev,
227 struct sd *dev = (struct sd *) gspca_dev; 401 struct sd *dev = (struct sd *) gspca_dev;
228 402
229 dev->type = id->driver_info; 403 dev->type = id->driver_info;
230 dev->quality = 85; 404 gspca_dev->cam.ctrls = dev->ctrls;
405 dev->quality = QUALITY_DEF;
406 dev->ctrls[LIGHTFREQ].def = V4L2_CID_POWER_LINE_FREQUENCY_60HZ;
407 dev->ctrls[RED].def = RED_BALANCE_DEF;
408 dev->ctrls[GREEN].def = GREEN_BALANCE_DEF;
409 dev->ctrls[BLUE].def = BLUE_BALANCE_DEF;
231 PDEBUG(D_PROBE, 410 PDEBUG(D_PROBE,
232 "JEILINJ camera detected" 411 "JEILINJ camera detected"
233 " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); 412 " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
@@ -304,6 +483,58 @@ static const struct usb_device_id device_table[] = {
304 483
305MODULE_DEVICE_TABLE(usb, device_table); 484MODULE_DEVICE_TABLE(usb, device_table);
306 485
486static int sd_querymenu(struct gspca_dev *gspca_dev,
487 struct v4l2_querymenu *menu)
488{
489 switch (menu->id) {
490 case V4L2_CID_POWER_LINE_FREQUENCY:
491 switch (menu->index) {
492 case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
493 strcpy((char *) menu->name, "disable");
494 return 0;
495 case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
496 strcpy((char *) menu->name, "50 Hz");
497 return 0;
498 case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
499 strcpy((char *) menu->name, "60 Hz");
500 return 0;
501 }
502 break;
503 }
504 return -EINVAL;
505}
506
507static int sd_set_jcomp(struct gspca_dev *gspca_dev,
508 struct v4l2_jpegcompression *jcomp)
509{
510 struct sd *sd = (struct sd *) gspca_dev;
511
512 if (jcomp->quality < QUALITY_MIN)
513 sd->quality = QUALITY_MIN;
514 else if (jcomp->quality > QUALITY_MAX)
515 sd->quality = QUALITY_MAX;
516 else
517 sd->quality = jcomp->quality;
518 if (gspca_dev->streaming) {
519 jpeg_set_qual(sd->jpeg_hdr, sd->quality);
520 setcamquality(gspca_dev);
521 }
522 return 0;
523}
524
525static int sd_get_jcomp(struct gspca_dev *gspca_dev,
526 struct v4l2_jpegcompression *jcomp)
527{
528 struct sd *sd = (struct sd *) gspca_dev;
529
530 memset(jcomp, 0, sizeof *jcomp);
531 jcomp->quality = sd->quality;
532 jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
533 | V4L2_JPEG_MARKER_DQT;
534 return 0;
535}
536
537
307/* sub-driver description */ 538/* sub-driver description */
308static const struct sd_desc sd_desc_sakar_57379 = { 539static const struct sd_desc sd_desc_sakar_57379 = {
309 .name = MODULE_NAME, 540 .name = MODULE_NAME,
@@ -322,6 +553,11 @@ static const struct sd_desc sd_desc_sportscam_dv15 = {
322 .start = sd_start, 553 .start = sd_start,
323 .stopN = sd_stopN, 554 .stopN = sd_stopN,
324 .pkt_scan = sd_pkt_scan, 555 .pkt_scan = sd_pkt_scan,
556 .ctrls = sd_ctrls,
557 .nctrls = ARRAY_SIZE(sd_ctrls),
558 .querymenu = sd_querymenu,
559 .get_jcomp = sd_get_jcomp,
560 .set_jcomp = sd_set_jcomp,
325}; 561};
326 562
327static const struct sd_desc *sd_desc[2] = { 563static const struct sd_desc *sd_desc[2] = {