diff options
author | Hans de Goede <hdegoede@redhat.com> | 2009-06-17 17:37:57 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-06-23 02:13:11 -0400 |
commit | 8668d504d72c384fbfb6ab6f5d02a9fe4d813554 (patch) | |
tree | 4ba923b0a7ccda8121960231e758135ba9bd584a | |
parent | ae49c40461d8981b232e3fec28234d492067f0e1 (diff) |
V4L/DVB (12082): gspca_stv06xx: Add support for st6422 bridge and sensor
Add support for st6422 bridge and sensor to the stv06xx gspca sub driver,
tested with:
Logitech QuickCam Messenger 046d:08f0 ST6422 integrated
Logitech QuickCam Mess. Plus 046d:08f6 ST6422 integrated
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r-- | drivers/media/video/gspca/stv06xx/Makefile | 3 | ||||
-rw-r--r-- | drivers/media/video/gspca/stv06xx/stv06xx.c | 53 | ||||
-rw-r--r-- | drivers/media/video/gspca/stv06xx/stv06xx.h | 11 | ||||
-rw-r--r-- | drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c | 10 | ||||
-rw-r--r-- | drivers/media/video/gspca/stv06xx/stv06xx_sensor.h | 3 | ||||
-rw-r--r-- | drivers/media/video/gspca/stv06xx/stv06xx_st6422.c | 453 | ||||
-rw-r--r-- | drivers/media/video/gspca/stv06xx/stv06xx_st6422.h | 59 |
7 files changed, 577 insertions, 15 deletions
diff --git a/drivers/media/video/gspca/stv06xx/Makefile b/drivers/media/video/gspca/stv06xx/Makefile index feeaa94ab588..2f3c3a606ce4 100644 --- a/drivers/media/video/gspca/stv06xx/Makefile +++ b/drivers/media/video/gspca/stv06xx/Makefile | |||
@@ -3,7 +3,8 @@ obj-$(CONFIG_USB_STV06XX) += gspca_stv06xx.o | |||
3 | gspca_stv06xx-objs := stv06xx.o \ | 3 | gspca_stv06xx-objs := stv06xx.o \ |
4 | stv06xx_vv6410.o \ | 4 | stv06xx_vv6410.o \ |
5 | stv06xx_hdcs.o \ | 5 | stv06xx_hdcs.o \ |
6 | stv06xx_pb0100.o | 6 | stv06xx_pb0100.o \ |
7 | stv06xx_st6422.o | ||
7 | 8 | ||
8 | EXTRA_CFLAGS += -Idrivers/media/video/gspca | 9 | EXTRA_CFLAGS += -Idrivers/media/video/gspca |
9 | 10 | ||
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.c b/drivers/media/video/gspca/stv06xx/stv06xx.c index e573c3406324..0da8e0de0456 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx.c +++ b/drivers/media/video/gspca/stv06xx/stv06xx.c | |||
@@ -92,11 +92,10 @@ static int stv06xx_write_sensor_finish(struct sd *sd) | |||
92 | { | 92 | { |
93 | int err = 0; | 93 | int err = 0; |
94 | 94 | ||
95 | if (IS_850(sd)) { | 95 | if (sd->bridge == BRIDGE_STV610) { |
96 | struct usb_device *udev = sd->gspca_dev.dev; | 96 | struct usb_device *udev = sd->gspca_dev.dev; |
97 | __u8 *buf = sd->gspca_dev.usb_buf; | 97 | __u8 *buf = sd->gspca_dev.usb_buf; |
98 | 98 | ||
99 | /* Quickam Web needs an extra packet */ | ||
100 | buf[0] = 0; | 99 | buf[0] = 0; |
101 | err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), | 100 | err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), |
102 | 0x04, 0x40, 0x1704, 0, buf, 1, | 101 | 0x04, 0x40, 0x1704, 0, buf, 1, |
@@ -253,7 +252,7 @@ static int stv06xx_init(struct gspca_dev *gspca_dev) | |||
253 | 252 | ||
254 | err = sd->sensor->init(sd); | 253 | err = sd->sensor->init(sd); |
255 | 254 | ||
256 | if (dump_sensor) | 255 | if (dump_sensor && sd->sensor->dump) |
257 | sd->sensor->dump(sd); | 256 | sd->sensor->dump(sd); |
258 | 257 | ||
259 | return (err < 0) ? err : 0; | 258 | return (err < 0) ? err : 0; |
@@ -318,6 +317,8 @@ static void stv06xx_pkt_scan(struct gspca_dev *gspca_dev, | |||
318 | __u8 *data, /* isoc packet */ | 317 | __u8 *data, /* isoc packet */ |
319 | int len) /* iso packet length */ | 318 | int len) /* iso packet length */ |
320 | { | 319 | { |
320 | struct sd *sd = (struct sd *) gspca_dev; | ||
321 | |||
321 | PDEBUG(D_PACK, "Packet of length %d arrived", len); | 322 | PDEBUG(D_PACK, "Packet of length %d arrived", len); |
322 | 323 | ||
323 | /* A packet may contain several frames | 324 | /* A packet may contain several frames |
@@ -343,14 +344,29 @@ static void stv06xx_pkt_scan(struct gspca_dev *gspca_dev, | |||
343 | if (len < chunk_len) { | 344 | if (len < chunk_len) { |
344 | PDEBUG(D_ERR, "URB packet length is smaller" | 345 | PDEBUG(D_ERR, "URB packet length is smaller" |
345 | " than the specified chunk length"); | 346 | " than the specified chunk length"); |
347 | gspca_dev->last_packet_type = DISCARD_PACKET; | ||
346 | return; | 348 | return; |
347 | } | 349 | } |
348 | 350 | ||
351 | /* First byte seem to be 02=data 2nd byte is unknown??? */ | ||
352 | if (sd->bridge == BRIDGE_ST6422 && (id & 0xFF00) == 0x0200) | ||
353 | goto frame_data; | ||
354 | |||
349 | switch (id) { | 355 | switch (id) { |
350 | case 0x0200: | 356 | case 0x0200: |
351 | case 0x4200: | 357 | case 0x4200: |
358 | frame_data: | ||
352 | PDEBUG(D_PACK, "Frame data packet detected"); | 359 | PDEBUG(D_PACK, "Frame data packet detected"); |
353 | 360 | ||
361 | if (sd->to_skip) { | ||
362 | int skip = (sd->to_skip < chunk_len) ? | ||
363 | sd->to_skip : chunk_len; | ||
364 | data += skip; | ||
365 | len -= skip; | ||
366 | chunk_len -= skip; | ||
367 | sd->to_skip -= skip; | ||
368 | } | ||
369 | |||
354 | gspca_frame_add(gspca_dev, INTER_PACKET, frame, | 370 | gspca_frame_add(gspca_dev, INTER_PACKET, frame, |
355 | data, chunk_len); | 371 | data, chunk_len); |
356 | break; | 372 | break; |
@@ -365,6 +381,9 @@ static void stv06xx_pkt_scan(struct gspca_dev *gspca_dev, | |||
365 | gspca_frame_add(gspca_dev, FIRST_PACKET, | 381 | gspca_frame_add(gspca_dev, FIRST_PACKET, |
366 | frame, data, 0); | 382 | frame, data, 0); |
367 | 383 | ||
384 | if (sd->bridge == BRIDGE_ST6422) | ||
385 | sd->to_skip = gspca_dev->width * 4; | ||
386 | |||
368 | if (chunk_len) | 387 | if (chunk_len) |
369 | PDEBUG(D_ERR, "Chunk length is " | 388 | PDEBUG(D_ERR, "Chunk length is " |
370 | "non-zero on a SOF"); | 389 | "non-zero on a SOF"); |
@@ -395,8 +414,12 @@ static void stv06xx_pkt_scan(struct gspca_dev *gspca_dev, | |||
395 | /* Unknown chunk with 2 bytes of data, | 414 | /* Unknown chunk with 2 bytes of data, |
396 | occurs 2-3 times per USB interrupt */ | 415 | occurs 2-3 times per USB interrupt */ |
397 | break; | 416 | break; |
417 | case 0x42ff: | ||
418 | PDEBUG(D_PACK, "Chunk 0x42ff detected"); | ||
419 | /* Special chunk seen sometimes on the ST6422 */ | ||
420 | break; | ||
398 | default: | 421 | default: |
399 | PDEBUG(D_PACK, "Unknown chunk %d detected", id); | 422 | PDEBUG(D_PACK, "Unknown chunk 0x%04x detected", id); |
400 | /* Unknown chunk */ | 423 | /* Unknown chunk */ |
401 | } | 424 | } |
402 | data += chunk_len; | 425 | data += chunk_len; |
@@ -428,11 +451,16 @@ static int stv06xx_config(struct gspca_dev *gspca_dev, | |||
428 | 451 | ||
429 | cam = &gspca_dev->cam; | 452 | cam = &gspca_dev->cam; |
430 | sd->desc = sd_desc; | 453 | sd->desc = sd_desc; |
454 | sd->bridge = id->driver_info; | ||
431 | gspca_dev->sd_desc = &sd->desc; | 455 | gspca_dev->sd_desc = &sd->desc; |
432 | 456 | ||
433 | if (dump_bridge) | 457 | if (dump_bridge) |
434 | stv06xx_dump_bridge(sd); | 458 | stv06xx_dump_bridge(sd); |
435 | 459 | ||
460 | sd->sensor = &stv06xx_sensor_st6422; | ||
461 | if (!sd->sensor->probe(sd)) | ||
462 | return 0; | ||
463 | |||
436 | sd->sensor = &stv06xx_sensor_vv6410; | 464 | sd->sensor = &stv06xx_sensor_vv6410; |
437 | if (!sd->sensor->probe(sd)) | 465 | if (!sd->sensor->probe(sd)) |
438 | return 0; | 466 | return 0; |
@@ -457,9 +485,20 @@ static int stv06xx_config(struct gspca_dev *gspca_dev, | |||
457 | 485 | ||
458 | /* -- module initialisation -- */ | 486 | /* -- module initialisation -- */ |
459 | static const __devinitdata struct usb_device_id device_table[] = { | 487 | static const __devinitdata struct usb_device_id device_table[] = { |
460 | {USB_DEVICE(0x046d, 0x0840)}, /* QuickCam Express */ | 488 | /* QuickCam Express */ |
461 | {USB_DEVICE(0x046d, 0x0850)}, /* LEGO cam / QuickCam Web */ | 489 | {USB_DEVICE(0x046d, 0x0840), .driver_info = BRIDGE_STV600 }, |
462 | {USB_DEVICE(0x046d, 0x0870)}, /* Dexxa WebCam USB */ | 490 | /* LEGO cam / QuickCam Web */ |
491 | {USB_DEVICE(0x046d, 0x0850), .driver_info = BRIDGE_STV610 }, | ||
492 | /* Dexxa WebCam USB */ | ||
493 | {USB_DEVICE(0x046d, 0x0870), .driver_info = BRIDGE_STV602 }, | ||
494 | /* QuickCam Messenger */ | ||
495 | {USB_DEVICE(0x046D, 0x08F0), .driver_info = BRIDGE_ST6422 }, | ||
496 | /* QuickCam Communicate */ | ||
497 | {USB_DEVICE(0x046D, 0x08F5), .driver_info = BRIDGE_ST6422 }, | ||
498 | /* QuickCam Messenger (new) */ | ||
499 | {USB_DEVICE(0x046D, 0x08F6), .driver_info = BRIDGE_ST6422 }, | ||
500 | /* QuickCam Messenger (new) */ | ||
501 | {USB_DEVICE(0x046D, 0x08DA), .driver_info = BRIDGE_ST6422 }, | ||
463 | {} | 502 | {} |
464 | }; | 503 | }; |
465 | MODULE_DEVICE_TABLE(usb, device_table); | 504 | MODULE_DEVICE_TABLE(usb, device_table); |
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.h b/drivers/media/video/gspca/stv06xx/stv06xx.h index 1207e7d17f14..9df7137fe67e 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx.h +++ b/drivers/media/video/gspca/stv06xx/stv06xx.h | |||
@@ -93,6 +93,17 @@ struct sd { | |||
93 | 93 | ||
94 | /* Sensor private data */ | 94 | /* Sensor private data */ |
95 | void *sensor_priv; | 95 | void *sensor_priv; |
96 | |||
97 | /* The first 4 lines produced by the stv6422 are no good, this keeps | ||
98 | track of how many bytes we still need to skip during a frame */ | ||
99 | int to_skip; | ||
100 | |||
101 | /* Bridge / Camera type */ | ||
102 | u8 bridge; | ||
103 | #define BRIDGE_STV600 0 | ||
104 | #define BRIDGE_STV602 1 | ||
105 | #define BRIDGE_STV610 2 | ||
106 | #define BRIDGE_ST6422 3 /* With integrated sensor */ | ||
96 | }; | 107 | }; |
97 | 108 | ||
98 | int stv06xx_write_bridge(struct sd *sd, u16 address, u16 i2c_data); | 109 | int stv06xx_write_bridge(struct sd *sd, u16 address, u16 i2c_data); |
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c index b16903814203..3039ec208f3a 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c +++ b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c | |||
@@ -434,7 +434,7 @@ static int hdcs_probe_1x00(struct sd *sd) | |||
434 | hdcs->exp.er = 100; | 434 | hdcs->exp.er = 100; |
435 | 435 | ||
436 | /* | 436 | /* |
437 | * Frame rate on HDCS-1000 0x46D:0x840 depends on PSMP: | 437 | * Frame rate on HDCS-1000 with STV600 depends on PSMP: |
438 | * 4 = doesn't work at all | 438 | * 4 = doesn't work at all |
439 | * 5 = 7.8 fps, | 439 | * 5 = 7.8 fps, |
440 | * 6 = 6.9 fps, | 440 | * 6 = 6.9 fps, |
@@ -443,7 +443,7 @@ static int hdcs_probe_1x00(struct sd *sd) | |||
443 | * 15 = 4.4 fps, | 443 | * 15 = 4.4 fps, |
444 | * 31 = 2.8 fps | 444 | * 31 = 2.8 fps |
445 | * | 445 | * |
446 | * Frame rate on HDCS-1000 0x46D:0x870 depends on PSMP: | 446 | * Frame rate on HDCS-1000 with STV602 depends on PSMP: |
447 | * 15 = doesn't work at all | 447 | * 15 = doesn't work at all |
448 | * 18 = doesn't work at all | 448 | * 18 = doesn't work at all |
449 | * 19 = 7.3 fps | 449 | * 19 = 7.3 fps |
@@ -453,7 +453,7 @@ static int hdcs_probe_1x00(struct sd *sd) | |||
453 | * 24 = 6.3 fps | 453 | * 24 = 6.3 fps |
454 | * 30 = 5.4 fps | 454 | * 30 = 5.4 fps |
455 | */ | 455 | */ |
456 | hdcs->psmp = IS_870(sd) ? 20 : 5; | 456 | hdcs->psmp = (sd->bridge == BRIDGE_STV602) ? 20 : 5; |
457 | 457 | ||
458 | sd->sensor_priv = hdcs; | 458 | sd->sensor_priv = hdcs; |
459 | 459 | ||
@@ -530,7 +530,7 @@ static int hdcs_init(struct sd *sd) | |||
530 | int i, err = 0; | 530 | int i, err = 0; |
531 | 531 | ||
532 | /* Set the STV0602AA in STV0600 emulation mode */ | 532 | /* Set the STV0602AA in STV0600 emulation mode */ |
533 | if (IS_870(sd)) | 533 | if (sd->bridge == BRIDGE_STV602) |
534 | stv06xx_write_bridge(sd, STV_STV0600_EMULATION, 1); | 534 | stv06xx_write_bridge(sd, STV_STV0600_EMULATION, 1); |
535 | 535 | ||
536 | /* Execute the bridge init */ | 536 | /* Execute the bridge init */ |
@@ -558,7 +558,7 @@ static int hdcs_init(struct sd *sd) | |||
558 | return err; | 558 | return err; |
559 | 559 | ||
560 | /* Set PGA sample duration | 560 | /* Set PGA sample duration |
561 | (was 0x7E for IS_870, but caused slow framerate with HDCS-1020) */ | 561 | (was 0x7E for the STV602, but caused slow framerate with HDCS-1020) */ |
562 | if (IS_1020(sd)) | 562 | if (IS_1020(sd)) |
563 | err = stv06xx_write_sensor(sd, HDCS_TCTRL, | 563 | err = stv06xx_write_sensor(sd, HDCS_TCTRL, |
564 | (HDCS_ADC_START_SIG_DUR << 6) | hdcs->psmp); | 564 | (HDCS_ADC_START_SIG_DUR << 6) | hdcs->psmp); |
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h b/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h index e88c42f7d2f8..934b9cebc1ab 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h +++ b/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h | |||
@@ -32,14 +32,13 @@ | |||
32 | 32 | ||
33 | #include "stv06xx.h" | 33 | #include "stv06xx.h" |
34 | 34 | ||
35 | #define IS_850(sd) ((sd)->gspca_dev.dev->descriptor.idProduct == 0x850) | ||
36 | #define IS_870(sd) ((sd)->gspca_dev.dev->descriptor.idProduct == 0x870) | ||
37 | #define IS_1020(sd) ((sd)->sensor == &stv06xx_sensor_hdcs1020) | 35 | #define IS_1020(sd) ((sd)->sensor == &stv06xx_sensor_hdcs1020) |
38 | 36 | ||
39 | extern const struct stv06xx_sensor stv06xx_sensor_vv6410; | 37 | extern const struct stv06xx_sensor stv06xx_sensor_vv6410; |
40 | extern const struct stv06xx_sensor stv06xx_sensor_hdcs1x00; | 38 | extern const struct stv06xx_sensor stv06xx_sensor_hdcs1x00; |
41 | extern const struct stv06xx_sensor stv06xx_sensor_hdcs1020; | 39 | extern const struct stv06xx_sensor stv06xx_sensor_hdcs1020; |
42 | extern const struct stv06xx_sensor stv06xx_sensor_pb0100; | 40 | extern const struct stv06xx_sensor stv06xx_sensor_pb0100; |
41 | extern const struct stv06xx_sensor stv06xx_sensor_st6422; | ||
43 | 42 | ||
44 | struct stv06xx_sensor { | 43 | struct stv06xx_sensor { |
45 | /* Defines the name of a sensor */ | 44 | /* Defines the name of a sensor */ |
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c new file mode 100644 index 000000000000..87cb5b9ddfa7 --- /dev/null +++ b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c | |||
@@ -0,0 +1,453 @@ | |||
1 | /* | ||
2 | * Support for the sensor part which is integrated (I think) into the | ||
3 | * st6422 stv06xx alike bridge, as its integrated there are no i2c writes | ||
4 | * but instead direct bridge writes. | ||
5 | * | ||
6 | * Copyright (c) 2009 Hans de Goede <hdegoede@redhat.com> | ||
7 | * | ||
8 | * Strongly based on qc-usb-messenger, which is: | ||
9 | * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher | ||
10 | * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland | ||
11 | * Copyright (c) 2002, 2003 Tuukka Toivonen | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, write to the Free Software | ||
25 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
26 | * | ||
27 | */ | ||
28 | |||
29 | #include "stv06xx_st6422.h" | ||
30 | |||
31 | static struct v4l2_pix_format st6422_mode[] = { | ||
32 | /* Note we actually get 124 lines of data, of which we skip the 4st | ||
33 | 4 as they are garbage */ | ||
34 | { | ||
35 | 162, | ||
36 | 120, | ||
37 | V4L2_PIX_FMT_SGRBG8, | ||
38 | V4L2_FIELD_NONE, | ||
39 | .sizeimage = 162 * 120, | ||
40 | .bytesperline = 162, | ||
41 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
42 | .priv = 1 | ||
43 | }, | ||
44 | /* Note we actually get 248 lines of data, of which we skip the 4st | ||
45 | 4 as they are garbage, and we tell the app it only gets the | ||
46 | first 240 of the 244 lines it actually gets, so that it ignores | ||
47 | the last 4. */ | ||
48 | { | ||
49 | 324, | ||
50 | 240, | ||
51 | V4L2_PIX_FMT_SGRBG8, | ||
52 | V4L2_FIELD_NONE, | ||
53 | .sizeimage = 324 * 244, | ||
54 | .bytesperline = 324, | ||
55 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
56 | .priv = 0 | ||
57 | }, | ||
58 | }; | ||
59 | |||
60 | static const struct ctrl st6422_ctrl[] = { | ||
61 | #define BRIGHTNESS_IDX 0 | ||
62 | { | ||
63 | { | ||
64 | .id = V4L2_CID_BRIGHTNESS, | ||
65 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
66 | .name = "Brightness", | ||
67 | .minimum = 0, | ||
68 | .maximum = 31, | ||
69 | .step = 1, | ||
70 | .default_value = 3 | ||
71 | }, | ||
72 | .set = st6422_set_brightness, | ||
73 | .get = st6422_get_brightness | ||
74 | }, | ||
75 | #define CONTRAST_IDX 1 | ||
76 | { | ||
77 | { | ||
78 | .id = V4L2_CID_CONTRAST, | ||
79 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
80 | .name = "Contrast", | ||
81 | .minimum = 0, | ||
82 | .maximum = 15, | ||
83 | .step = 1, | ||
84 | .default_value = 11 | ||
85 | }, | ||
86 | .set = st6422_set_contrast, | ||
87 | .get = st6422_get_contrast | ||
88 | }, | ||
89 | #define GAIN_IDX 2 | ||
90 | { | ||
91 | { | ||
92 | .id = V4L2_CID_GAIN, | ||
93 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
94 | .name = "Gain", | ||
95 | .minimum = 0, | ||
96 | .maximum = 255, | ||
97 | .step = 1, | ||
98 | .default_value = 64 | ||
99 | }, | ||
100 | .set = st6422_set_gain, | ||
101 | .get = st6422_get_gain | ||
102 | }, | ||
103 | #define EXPOSURE_IDX 3 | ||
104 | { | ||
105 | { | ||
106 | .id = V4L2_CID_EXPOSURE, | ||
107 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
108 | .name = "Exposure", | ||
109 | .minimum = 0, | ||
110 | .maximum = 1023, | ||
111 | .step = 1, | ||
112 | .default_value = 256 | ||
113 | }, | ||
114 | .set = st6422_set_exposure, | ||
115 | .get = st6422_get_exposure | ||
116 | }, | ||
117 | }; | ||
118 | |||
119 | static int st6422_probe(struct sd *sd) | ||
120 | { | ||
121 | int i; | ||
122 | s32 *sensor_settings; | ||
123 | |||
124 | if (sd->bridge != BRIDGE_ST6422) | ||
125 | return -ENODEV; | ||
126 | |||
127 | info("st6422 sensor detected"); | ||
128 | |||
129 | sensor_settings = kmalloc(ARRAY_SIZE(st6422_ctrl) * sizeof(s32), | ||
130 | GFP_KERNEL); | ||
131 | if (!sensor_settings) | ||
132 | return -ENOMEM; | ||
133 | |||
134 | sd->gspca_dev.cam.cam_mode = st6422_mode; | ||
135 | sd->gspca_dev.cam.nmodes = ARRAY_SIZE(st6422_mode); | ||
136 | sd->desc.ctrls = st6422_ctrl; | ||
137 | sd->desc.nctrls = ARRAY_SIZE(st6422_ctrl); | ||
138 | sd->sensor_priv = sensor_settings; | ||
139 | |||
140 | for (i = 0; i < sd->desc.nctrls; i++) | ||
141 | sensor_settings[i] = st6422_ctrl[i].qctrl.default_value; | ||
142 | |||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | static int st6422_init(struct sd *sd) | ||
147 | { | ||
148 | int err = 0, i; | ||
149 | |||
150 | const u16 st6422_bridge_init[][2] = { | ||
151 | { STV_ISO_ENABLE, 0x00 }, /* disable capture */ | ||
152 | { 0x1436, 0x00 }, | ||
153 | { 0x1432, 0x03 }, /* 0x00-0x1F brightness */ | ||
154 | { 0x143a, 0xF9 }, /* 0x00-0x0F contrast */ | ||
155 | { 0x0509, 0x38 }, /* R */ | ||
156 | { 0x050a, 0x38 }, /* G */ | ||
157 | { 0x050b, 0x38 }, /* B */ | ||
158 | { 0x050c, 0x2A }, | ||
159 | { 0x050d, 0x01 }, | ||
160 | |||
161 | |||
162 | { 0x1431, 0x00 }, /* 0x00-0x07 ??? */ | ||
163 | { 0x1433, 0x34 }, /* 160x120, 0x00-0x01 night filter */ | ||
164 | { 0x1438, 0x18 }, /* 640x480 */ | ||
165 | /* 18 bayes */ | ||
166 | /* 10 compressed? */ | ||
167 | |||
168 | { 0x1439, 0x00 }, | ||
169 | /* antiflimmer?? 0xa2 ger perfekt bild mot monitor */ | ||
170 | |||
171 | { 0x143b, 0x05 }, | ||
172 | { 0x143c, 0x00 }, /* 0x00-0x01 - ??? */ | ||
173 | |||
174 | |||
175 | /* shutter time 0x0000-0x03FF */ | ||
176 | /* low value give good picures on moving objects (but requires much light) */ | ||
177 | /* high value gives good picures in darkness (but tends to be overexposed) */ | ||
178 | { 0x143e, 0x01 }, | ||
179 | { 0x143d, 0x00 }, | ||
180 | |||
181 | { 0x1442, 0xe2 }, | ||
182 | /* write: 1x1x xxxx */ | ||
183 | /* read: 1x1x xxxx */ | ||
184 | /* bit 5 == button pressed and hold if 0 */ | ||
185 | /* write 0xe2,0xea */ | ||
186 | |||
187 | /* 0x144a */ | ||
188 | /* 0x00 init */ | ||
189 | /* bit 7 == button has been pressed, but not handled */ | ||
190 | |||
191 | /* interrupt */ | ||
192 | /* if(urb->iso_frame_desc[i].status == 0x80) { */ | ||
193 | /* if(urb->iso_frame_desc[i].status == 0x88) { */ | ||
194 | |||
195 | { 0x1500, 0xd0 }, | ||
196 | { 0x1500, 0xd0 }, | ||
197 | { 0x1500, 0x50 }, /* 0x00 - 0xFF 0x80 == compr ? */ | ||
198 | |||
199 | { 0x1501, 0xaf }, | ||
200 | /* high val-> ljus area blir morkare. */ | ||
201 | /* low val -> ljus area blir ljusare. */ | ||
202 | { 0x1502, 0xc2 }, | ||
203 | /* high val-> ljus area blir morkare. */ | ||
204 | /* low val -> ljus area blir ljusare. */ | ||
205 | { 0x1503, 0x45 }, | ||
206 | /* high val-> ljus area blir morkare. */ | ||
207 | /* low val -> ljus area blir ljusare. */ | ||
208 | |||
209 | { 0x1505, 0x02 }, | ||
210 | /* 2 : 324x248 80352 bytes */ | ||
211 | /* 7 : 248x162 40176 bytes */ | ||
212 | /* c+f: 162*124 20088 bytes */ | ||
213 | |||
214 | { 0x150e, 0x8e }, | ||
215 | { 0x150f, 0x37 }, | ||
216 | { 0x15c0, 0x00 }, | ||
217 | { 0x15c1, 1023 }, /* 160x120, ISOC_PACKET_SIZE */ | ||
218 | { 0x15c3, 0x08 }, /* 0x04/0x14 ... test pictures ??? */ | ||
219 | |||
220 | |||
221 | { 0x143f, 0x01 }, /* commit settings */ | ||
222 | |||
223 | }; | ||
224 | |||
225 | for (i = 0; i < ARRAY_SIZE(st6422_bridge_init) && !err; i++) { | ||
226 | err = stv06xx_write_bridge(sd, st6422_bridge_init[i][0], | ||
227 | st6422_bridge_init[i][1]); | ||
228 | } | ||
229 | |||
230 | return err; | ||
231 | } | ||
232 | |||
233 | static void st6422_disconnect(struct sd *sd) | ||
234 | { | ||
235 | sd->sensor = NULL; | ||
236 | kfree(sd->sensor_priv); | ||
237 | } | ||
238 | |||
239 | static int st6422_start(struct sd *sd) | ||
240 | { | ||
241 | int err, packet_size; | ||
242 | struct cam *cam = &sd->gspca_dev.cam; | ||
243 | s32 *sensor_settings = sd->sensor_priv; | ||
244 | struct usb_host_interface *alt; | ||
245 | struct usb_interface *intf; | ||
246 | |||
247 | intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface); | ||
248 | alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt); | ||
249 | if (!alt) { | ||
250 | PDEBUG(D_ERR, "Couldn't get altsetting"); | ||
251 | return -EIO; | ||
252 | } | ||
253 | |||
254 | packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); | ||
255 | err = stv06xx_write_bridge(sd, 0x15c1, packet_size); | ||
256 | if (err < 0) | ||
257 | return err; | ||
258 | |||
259 | if (cam->cam_mode[sd->gspca_dev.curr_mode].priv) | ||
260 | err = stv06xx_write_bridge(sd, 0x1505, 0x0f); | ||
261 | else | ||
262 | err = stv06xx_write_bridge(sd, 0x1505, 0x02); | ||
263 | if (err < 0) | ||
264 | return err; | ||
265 | |||
266 | err = st6422_set_brightness(&sd->gspca_dev, | ||
267 | sensor_settings[BRIGHTNESS_IDX]); | ||
268 | if (err < 0) | ||
269 | return err; | ||
270 | |||
271 | err = st6422_set_contrast(&sd->gspca_dev, | ||
272 | sensor_settings[CONTRAST_IDX]); | ||
273 | if (err < 0) | ||
274 | return err; | ||
275 | |||
276 | err = st6422_set_exposure(&sd->gspca_dev, | ||
277 | sensor_settings[EXPOSURE_IDX]); | ||
278 | if (err < 0) | ||
279 | return err; | ||
280 | |||
281 | err = st6422_set_gain(&sd->gspca_dev, | ||
282 | sensor_settings[GAIN_IDX]); | ||
283 | if (err < 0) | ||
284 | return err; | ||
285 | |||
286 | PDEBUG(D_STREAM, "Starting stream"); | ||
287 | |||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | static int st6422_stop(struct sd *sd) | ||
292 | { | ||
293 | PDEBUG(D_STREAM, "Halting stream"); | ||
294 | |||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | static int st6422_get_brightness(struct gspca_dev *gspca_dev, __s32 *val) | ||
299 | { | ||
300 | struct sd *sd = (struct sd *) gspca_dev; | ||
301 | s32 *sensor_settings = sd->sensor_priv; | ||
302 | |||
303 | *val = sensor_settings[BRIGHTNESS_IDX]; | ||
304 | |||
305 | PDEBUG(D_V4L2, "Read brightness %d", *val); | ||
306 | |||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | static int st6422_set_brightness(struct gspca_dev *gspca_dev, __s32 val) | ||
311 | { | ||
312 | int err; | ||
313 | struct sd *sd = (struct sd *) gspca_dev; | ||
314 | s32 *sensor_settings = sd->sensor_priv; | ||
315 | |||
316 | sensor_settings[BRIGHTNESS_IDX] = val; | ||
317 | |||
318 | if (!gspca_dev->streaming) | ||
319 | return 0; | ||
320 | |||
321 | /* val goes from 0 -> 31 */ | ||
322 | PDEBUG(D_V4L2, "Set brightness to %d", val); | ||
323 | err = stv06xx_write_bridge(sd, 0x1432, val); | ||
324 | if (err < 0) | ||
325 | return err; | ||
326 | |||
327 | /* commit settings */ | ||
328 | err = stv06xx_write_bridge(sd, 0x143f, 0x01); | ||
329 | return (err < 0) ? err : 0; | ||
330 | } | ||
331 | |||
332 | static int st6422_get_contrast(struct gspca_dev *gspca_dev, __s32 *val) | ||
333 | { | ||
334 | struct sd *sd = (struct sd *) gspca_dev; | ||
335 | s32 *sensor_settings = sd->sensor_priv; | ||
336 | |||
337 | *val = sensor_settings[CONTRAST_IDX]; | ||
338 | |||
339 | PDEBUG(D_V4L2, "Read contrast %d", *val); | ||
340 | |||
341 | return 0; | ||
342 | } | ||
343 | |||
344 | static int st6422_set_contrast(struct gspca_dev *gspca_dev, __s32 val) | ||
345 | { | ||
346 | int err; | ||
347 | struct sd *sd = (struct sd *) gspca_dev; | ||
348 | s32 *sensor_settings = sd->sensor_priv; | ||
349 | |||
350 | sensor_settings[CONTRAST_IDX] = val; | ||
351 | |||
352 | if (!gspca_dev->streaming) | ||
353 | return 0; | ||
354 | |||
355 | /* Val goes from 0 -> 15 */ | ||
356 | PDEBUG(D_V4L2, "Set contrast to %d\n", val); | ||
357 | err = stv06xx_write_bridge(sd, 0x143a, 0xf0 | val); | ||
358 | if (err < 0) | ||
359 | return err; | ||
360 | |||
361 | /* commit settings */ | ||
362 | err = stv06xx_write_bridge(sd, 0x143f, 0x01); | ||
363 | return (err < 0) ? err : 0; | ||
364 | } | ||
365 | |||
366 | static int st6422_get_gain(struct gspca_dev *gspca_dev, __s32 *val) | ||
367 | { | ||
368 | struct sd *sd = (struct sd *) gspca_dev; | ||
369 | s32 *sensor_settings = sd->sensor_priv; | ||
370 | |||
371 | *val = sensor_settings[GAIN_IDX]; | ||
372 | |||
373 | PDEBUG(D_V4L2, "Read gain %d", *val); | ||
374 | |||
375 | return 0; | ||
376 | } | ||
377 | |||
378 | static int st6422_set_gain(struct gspca_dev *gspca_dev, __s32 val) | ||
379 | { | ||
380 | int err; | ||
381 | struct sd *sd = (struct sd *) gspca_dev; | ||
382 | s32 *sensor_settings = sd->sensor_priv; | ||
383 | |||
384 | sensor_settings[GAIN_IDX] = val; | ||
385 | |||
386 | if (!gspca_dev->streaming) | ||
387 | return 0; | ||
388 | |||
389 | PDEBUG(D_V4L2, "Set gain to %d", val); | ||
390 | |||
391 | /* Set red, green, blue, gain */ | ||
392 | err = stv06xx_write_bridge(sd, 0x0509, val); | ||
393 | if (err < 0) | ||
394 | return err; | ||
395 | |||
396 | err = stv06xx_write_bridge(sd, 0x050a, val); | ||
397 | if (err < 0) | ||
398 | return err; | ||
399 | |||
400 | err = stv06xx_write_bridge(sd, 0x050b, val); | ||
401 | if (err < 0) | ||
402 | return err; | ||
403 | |||
404 | /* 2 mystery writes */ | ||
405 | err = stv06xx_write_bridge(sd, 0x050c, 0x2a); | ||
406 | if (err < 0) | ||
407 | return err; | ||
408 | |||
409 | err = stv06xx_write_bridge(sd, 0x050d, 0x01); | ||
410 | if (err < 0) | ||
411 | return err; | ||
412 | |||
413 | /* commit settings */ | ||
414 | err = stv06xx_write_bridge(sd, 0x143f, 0x01); | ||
415 | return (err < 0) ? err : 0; | ||
416 | } | ||
417 | |||
418 | static int st6422_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) | ||
419 | { | ||
420 | struct sd *sd = (struct sd *) gspca_dev; | ||
421 | s32 *sensor_settings = sd->sensor_priv; | ||
422 | |||
423 | *val = sensor_settings[EXPOSURE_IDX]; | ||
424 | |||
425 | PDEBUG(D_V4L2, "Read exposure %d", *val); | ||
426 | |||
427 | return 0; | ||
428 | } | ||
429 | |||
430 | static int st6422_set_exposure(struct gspca_dev *gspca_dev, __s32 val) | ||
431 | { | ||
432 | int err; | ||
433 | struct sd *sd = (struct sd *) gspca_dev; | ||
434 | s32 *sensor_settings = sd->sensor_priv; | ||
435 | |||
436 | sensor_settings[EXPOSURE_IDX] = val; | ||
437 | |||
438 | if (!gspca_dev->streaming) | ||
439 | return 0; | ||
440 | |||
441 | PDEBUG(D_V4L2, "Set exposure to %d\n", val); | ||
442 | err = stv06xx_write_bridge(sd, 0x143d, val & 0xff); | ||
443 | if (err < 0) | ||
444 | return err; | ||
445 | |||
446 | err = stv06xx_write_bridge(sd, 0x143e, val >> 8); | ||
447 | if (err < 0) | ||
448 | return err; | ||
449 | |||
450 | /* commit settings */ | ||
451 | err = stv06xx_write_bridge(sd, 0x143f, 0x01); | ||
452 | return (err < 0) ? err : 0; | ||
453 | } | ||
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h new file mode 100644 index 000000000000..b2d45fe50522 --- /dev/null +++ b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h | |||
@@ -0,0 +1,59 @@ | |||
1 | /* | ||
2 | * Support for the sensor part which is integrated (I think) into the | ||
3 | * st6422 stv06xx alike bridge, as its integrated there are no i2c writes | ||
4 | * but instead direct bridge writes. | ||
5 | * | ||
6 | * Copyright (c) 2009 Hans de Goede <hdegoede@redhat.com> | ||
7 | * | ||
8 | * Strongly based on qc-usb-messenger, which is: | ||
9 | * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher | ||
10 | * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland | ||
11 | * Copyright (c) 2002, 2003 Tuukka Toivonen | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, write to the Free Software | ||
25 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
26 | * | ||
27 | */ | ||
28 | |||
29 | #ifndef STV06XX_ST6422_H_ | ||
30 | #define STV06XX_ST6422_H_ | ||
31 | |||
32 | #include "stv06xx_sensor.h" | ||
33 | |||
34 | static int st6422_probe(struct sd *sd); | ||
35 | static int st6422_start(struct sd *sd); | ||
36 | static int st6422_init(struct sd *sd); | ||
37 | static int st6422_stop(struct sd *sd); | ||
38 | static void st6422_disconnect(struct sd *sd); | ||
39 | |||
40 | /* V4L2 controls supported by the driver */ | ||
41 | static int st6422_get_brightness(struct gspca_dev *gspca_dev, __s32 *val); | ||
42 | static int st6422_set_brightness(struct gspca_dev *gspca_dev, __s32 val); | ||
43 | static int st6422_get_contrast(struct gspca_dev *gspca_dev, __s32 *val); | ||
44 | static int st6422_set_contrast(struct gspca_dev *gspca_dev, __s32 val); | ||
45 | static int st6422_get_gain(struct gspca_dev *gspca_dev, __s32 *val); | ||
46 | static int st6422_set_gain(struct gspca_dev *gspca_dev, __s32 val); | ||
47 | static int st6422_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); | ||
48 | static int st6422_set_exposure(struct gspca_dev *gspca_dev, __s32 val); | ||
49 | |||
50 | const struct stv06xx_sensor stv06xx_sensor_st6422 = { | ||
51 | .name = "ST6422", | ||
52 | .init = st6422_init, | ||
53 | .probe = st6422_probe, | ||
54 | .start = st6422_start, | ||
55 | .stop = st6422_stop, | ||
56 | .disconnect = st6422_disconnect, | ||
57 | }; | ||
58 | |||
59 | #endif | ||