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 | ||
