diff options
Diffstat (limited to 'drivers/media/video/gspca')
33 files changed, 3017 insertions, 1401 deletions
diff --git a/drivers/media/video/gspca/Kconfig b/drivers/media/video/gspca/Kconfig index 5d920e584de..23db0c29f68 100644 --- a/drivers/media/video/gspca/Kconfig +++ b/drivers/media/video/gspca/Kconfig @@ -246,6 +246,15 @@ config USB_GSPCA_SPCA561 To compile this driver as a module, choose M here: the module will be called gspca_spca561. +config USB_GSPCA_SPCA1528 + tristate "SPCA1528 USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the SPCA1528 chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_spca1528. + config USB_GSPCA_SQ905 tristate "SQ Technologies SQ905 based USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA @@ -264,6 +273,15 @@ config USB_GSPCA_SQ905C To compile this driver as a module, choose M here: the module will be called gspca_sq905c. +config USB_GSPCA_SQ930X + tristate "SQ Technologies SQ930X based USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the SQ930X chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_sq930x. + config USB_GSPCA_STK014 tristate "Syntek DV4000 (STK014) USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA diff --git a/drivers/media/video/gspca/Makefile b/drivers/media/video/gspca/Makefile index 6e4cf1ce01c..f6616db0b7f 100644 --- a/drivers/media/video/gspca/Makefile +++ b/drivers/media/video/gspca/Makefile @@ -23,8 +23,10 @@ obj-$(CONFIG_USB_GSPCA_SPCA505) += gspca_spca505.o obj-$(CONFIG_USB_GSPCA_SPCA506) += gspca_spca506.o obj-$(CONFIG_USB_GSPCA_SPCA508) += gspca_spca508.o obj-$(CONFIG_USB_GSPCA_SPCA561) += gspca_spca561.o +obj-$(CONFIG_USB_GSPCA_SPCA1528) += gspca_spca1528.o obj-$(CONFIG_USB_GSPCA_SQ905) += gspca_sq905.o obj-$(CONFIG_USB_GSPCA_SQ905C) += gspca_sq905c.o +obj-$(CONFIG_USB_GSPCA_SQ930X) += gspca_sq930x.o obj-$(CONFIG_USB_GSPCA_SUNPLUS) += gspca_sunplus.o obj-$(CONFIG_USB_GSPCA_STK014) += gspca_stk014.o obj-$(CONFIG_USB_GSPCA_STV0680) += gspca_stv0680.o @@ -58,8 +60,10 @@ gspca_spca505-objs := spca505.o gspca_spca506-objs := spca506.o gspca_spca508-objs := spca508.o gspca_spca561-objs := spca561.o +gspca_spca1528-objs := spca1528.o gspca_sq905-objs := sq905.o gspca_sq905c-objs := sq905c.o +gspca_sq930x-objs := sq930x.o gspca_stk014-objs := stk014.o gspca_stv0680-objs := stv0680.o gspca_sunplus-objs := sunplus.o diff --git a/drivers/media/video/gspca/conex.c b/drivers/media/video/gspca/conex.c index 19fe6b24c9a..d6a75772f3f 100644 --- a/drivers/media/video/gspca/conex.c +++ b/drivers/media/video/gspca/conex.c @@ -41,7 +41,7 @@ struct sd { #define QUALITY_MAX 60 #define QUALITY_DEF 40 - u8 *jpeg_hdr; + u8 jpeg_hdr[JPEG_HDR_SZ]; }; /* V4L2 controls supported by the driver */ @@ -845,9 +845,6 @@ static int sd_start(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; /* create the JPEG header */ - sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL); - if (!sd->jpeg_hdr) - return -ENOMEM; jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, 0x22); /* JPEG 411 */ jpeg_set_qual(sd->jpeg_hdr, sd->quality); @@ -862,11 +859,8 @@ static int sd_start(struct gspca_dev *gspca_dev) /* called on streamoff with alt 0 and on disconnect */ static void sd_stop0(struct gspca_dev *gspca_dev) { - struct sd *sd = (struct sd *) gspca_dev; int retry = 50; - kfree(sd->jpeg_hdr); - if (!gspca_dev->present) return; reg_w_val(gspca_dev, 0x0000, 0x00); diff --git a/drivers/media/video/gspca/cpia1.c b/drivers/media/video/gspca/cpia1.c index 58b696f455b..3747a1dcff5 100644 --- a/drivers/media/video/gspca/cpia1.c +++ b/drivers/media/video/gspca/cpia1.c @@ -1760,22 +1760,19 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, data[25] == sd->params.roi.colEnd && data[26] == sd->params.roi.rowStart && data[27] == sd->params.roi.rowEnd) { - struct gspca_frame *frame = gspca_get_i_frame(gspca_dev); + u8 *image; atomic_set(&sd->cam_exposure, data[39] * 2); atomic_set(&sd->fps, data[41]); - if (frame == NULL) { - gspca_dev->last_packet_type = DISCARD_PACKET; - return; - } - /* Check for proper EOF for last frame */ - if ((frame->data_end - frame->data) > 4 && - frame->data_end[-4] == 0xff && - frame->data_end[-3] == 0xff && - frame->data_end[-2] == 0xff && - frame->data_end[-1] == 0xff) + image = gspca_dev->image; + if (image != NULL && + gspca_dev->image_len > 4 && + image[gspca_dev->image_len - 4] == 0xff && + image[gspca_dev->image_len - 3] == 0xff && + image[gspca_dev->image_len - 2] == 0xff && + image[gspca_dev->image_len - 1] == 0xff) gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); diff --git a/drivers/media/video/gspca/gl860/gl860-mi2020.c b/drivers/media/video/gspca/gl860/gl860-mi2020.c index 7c31b4f2abe..57782e011c9 100644 --- a/drivers/media/video/gspca/gl860/gl860-mi2020.c +++ b/drivers/media/video/gspca/gl860/gl860-mi2020.c @@ -1,6 +1,7 @@ /* Subdriver for the GL860 chip with the MI2020 sensor - * Author Olivier LORIN, from Ice/Soro2005's logs(A), Fret_saw/Hulkie's - * logs(B) and Tricid"s logs(C). With the help of Kytrix/BUGabundo/Blazercist. + * Author Olivier LORIN, from logs by Iceman/Soro2005 + Fret_saw/Hulkie/Tricid + * with the help of Kytrix/BUGabundo/Blazercist. + * Driver achieved thanks to a webcam gift by Kytrix. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,47 +21,70 @@ #include "gl860.h" +static u8 dat_wbal1[] = {0x8c, 0xa2, 0x0c}; + static u8 dat_bright1[] = {0x8c, 0xa2, 0x06}; static u8 dat_bright3[] = {0x8c, 0xa1, 0x02}; static u8 dat_bright4[] = {0x90, 0x00, 0x0f}; static u8 dat_bright5[] = {0x8c, 0xa1, 0x03}; static u8 dat_bright6[] = {0x90, 0x00, 0x05}; -static u8 dat_dummy1[] = {0x90, 0x00, 0x06}; -/*static u8 dummy2[] = {0x8c, 0xa1, 0x02};*/ -/*static u8 dummy3[] = {0x90, 0x00, 0x1f};*/ - static u8 dat_hvflip1[] = {0x8c, 0x27, 0x19}; static u8 dat_hvflip3[] = {0x8c, 0x27, 0x3b}; static u8 dat_hvflip5[] = {0x8c, 0xa1, 0x03}; static u8 dat_hvflip6[] = {0x90, 0x00, 0x06}; +static struct idxdata tbl_middle_hvflip_low[] = { + {0x33, "\x90\x00\x06"}, + {6, "\xff\xff\xff"}, + {0x33, "\x90\x00\x06"}, + {6, "\xff\xff\xff"}, + {0x33, "\x90\x00\x06"}, + {6, "\xff\xff\xff"}, + {0x33, "\x90\x00\x06"}, + {6, "\xff\xff\xff"}, +}; + +static struct idxdata tbl_middle_hvflip_big[] = { + {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x01"}, {0x33, "\x8c\xa1\x20"}, + {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x00"}, + {102, "\xff\xff\xff"}, + {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x02"}, {0x33, "\x8c\xa1\x20"}, + {0x33, "\x90\x00\x72"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"}, +}; + +static struct idxdata tbl_end_hvflip[] = { + {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"}, + {6, "\xff\xff\xff"}, + {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"}, + {6, "\xff\xff\xff"}, + {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"}, + {6, "\xff\xff\xff"}, + {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"}, +}; + static u8 dat_freq1[] = { 0x8c, 0xa4, 0x04 }; static u8 dat_multi5[] = { 0x8c, 0xa1, 0x03 }; static u8 dat_multi6[] = { 0x90, 0x00, 0x05 }; -static struct validx tbl_common1[] = { - {0x0000, 0x0000}, - {1, 0xffff}, /* msleep(35); */ - {0x006a, 0x0007}, {0x0063, 0x0006}, {0x006a, 0x000d}, {0x0000, 0x00c0}, - {0x0010, 0x0010}, {0x0003, 0x00c1}, {0x0042, 0x00c2}, {0x0004, 0x00d8}, - {0x0000, 0x0058}, {0x0002, 0x0004}, {0x0041, 0x0000}, +static struct validx tbl_init_at_startup[] = { + {0x0000, 0x0000}, {0x0010, 0x0010}, {0x0008, 0x00c0}, {0x0001,0x00c1}, + {0x0001, 0x00c2}, {0x0020, 0x0006}, {0x006a, 0x000d}, + {53, 0xffff}, + {0x0040, 0x0000}, {0x0063, 0x0006}, }; -static struct validx tbl_common2[] = { - {0x006a, 0x0007}, - {35, 0xffff}, - {0x00ef, 0x0006}, - {35, 0xffff}, - {0x006a, 0x000d}, - {35, 0xffff}, - {0x0000, 0x00c0}, {0x0010, 0x0010}, {0x0003, 0x00c1}, {0x0042, 0x00c2}, +static struct validx tbl_common_0B[] = { + {0x0002, 0x0004}, {0x006a, 0x0007}, {0x00ef, 0x0006}, {0x006a,0x000d}, + {0x0000, 0x00c0}, {0x0010, 0x0010}, {0x0003, 0x00c1}, {0x0042,0x00c2}, {0x0004, 0x00d8}, {0x0000, 0x0058}, {0x0041, 0x0000}, }; -static struct idxdata tbl_common3[] = { - {0x32, "\x02\x00\x08"}, {0x33, "\xf4\x03\x1d"}, +static struct idxdata tbl_common_3B[] = { + {0x33, "\x86\x25\x01"}, {0x33, "\x86\x25\x00"}, + {2, "\xff\xff\xff"}, + {0x30, "\x1a\x0a\xcc"}, {0x32, "\x02\x00\x08"}, {0x33, "\xf4\x03\x1d"}, {6, "\xff\xff\xff"}, /* 12 */ {0x34, "\x1e\x8f\x09"}, {0x34, "\x1c\x01\x28"}, {0x34, "\x1e\x8f\x09"}, {2, "\xff\xff\xff"}, /* - */ @@ -98,85 +122,58 @@ static struct idxdata tbl_common3[] = { {0x35, "\x50\x00\x06"}, {0x35, "\x48\x07\xff"}, {0x35, "\x60\x05\x89"}, {0x35, "\x58\x07\xff"}, {0x35, "\x40\x00\xa0"}, {0x35, "\x42\x00\x00"}, {0x32, "\x10\x01\xfc"}, {0x33, "\x8c\xa1\x18"}, {0x33, "\x90\x00\x3c"}, - {1, "\xff\xff\xff"}, {0x33, "\x78\x00\x00"}, - {1, "\xff\xff\xff"}, + {2, "\xff\xff\xff"}, {0x35, "\xb8\x1f\x20"}, {0x33, "\x8c\xa2\x06"}, {0x33, "\x90\x00\x10"}, {0x33, "\x8c\xa2\x07"}, {0x33, "\x90\x00\x08"}, {0x33, "\x8c\xa2\x42"}, {0x33, "\x90\x00\x0b"}, {0x33, "\x8c\xa2\x4a"}, {0x33, "\x90\x00\x8c"}, {0x35, "\xba\xfa\x08"}, {0x33, "\x8c\xa2\x02"}, {0x33, "\x90\x00\x22"}, - {0x33, "\x8c\xa2\x03"}, {0x33, "\x90\x00\xbb"}, -}; - -static struct idxdata tbl_common4[] = { - {0x33, "\x8c\x22\x2e"}, {0x33, "\x90\x00\xa0"}, {0x33, "\x8c\xa4\x08"}, + {0x33, "\x8c\xa2\x03"}, {0x33, "\x90\x00\xbb"}, {0x33, "\x8c\xa4\x04"}, + {0x33, "\x90\x00\x80"}, {0x33, "\x8c\xa7\x9d"}, {0x33, "\x90\x00\x00"}, + {0x33, "\x8c\xa7\x9e"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa2\x0c"}, + {0x33, "\x90\x00\x17"}, {0x33, "\x8c\xa2\x15"}, {0x33, "\x90\x00\x04"}, + {0x33, "\x8c\xa2\x14"}, {0x33, "\x90\x00\x20"}, {0x33, "\x8c\xa1\x03"}, + {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x17"}, {0x33, "\x90\x21\x11"}, + {0x33, "\x8c\x27\x1b"}, {0x33, "\x90\x02\x4f"}, {0x33, "\x8c\x27\x25"}, + {0x33, "\x90\x06\x0f"}, {0x33, "\x8c\x27\x39"}, {0x33, "\x90\x21\x11"}, + {0x33, "\x8c\x27\x3d"}, {0x33, "\x90\x01\x20"}, {0x33, "\x8c\x27\x47"}, + {0x33, "\x90\x09\x4c"}, {0x33, "\x8c\x27\x03"}, {0x33, "\x90\x02\x84"}, + {0x33, "\x8c\x27\x05"}, {0x33, "\x90\x01\xe2"}, {0x33, "\x8c\x27\x07"}, + {0x33, "\x90\x06\x40"}, {0x33, "\x8c\x27\x09"}, {0x33, "\x90\x04\xb0"}, + {0x33, "\x8c\x27\x0d"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x0f"}, + {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x11"}, {0x33, "\x90\x04\xbd"}, + {0x33, "\x8c\x27\x13"}, {0x33, "\x90\x06\x4d"}, {0x33, "\x8c\x27\x15"}, + {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x17"}, {0x33, "\x90\x21\x11"}, + {0x33, "\x8c\x27\x19"}, {0x33, "\x90\x04\x6c"}, {0x33, "\x8c\x27\x1b"}, + {0x33, "\x90\x02\x4f"}, {0x33, "\x8c\x27\x1d"}, {0x33, "\x90\x01\x02"}, + {0x33, "\x8c\x27\x1f"}, {0x33, "\x90\x02\x79"}, {0x33, "\x8c\x27\x21"}, + {0x33, "\x90\x01\x55"}, {0x33, "\x8c\x27\x23"}, {0x33, "\x90\x02\x85"}, + {0x33, "\x8c\x27\x25"}, {0x33, "\x90\x06\x0f"}, {0x33, "\x8c\x27\x27"}, + {0x33, "\x90\x20\x20"}, {0x33, "\x8c\x27\x29"}, {0x33, "\x90\x20\x20"}, + {0x33, "\x8c\x27\x2b"}, {0x33, "\x90\x10\x20"}, {0x33, "\x8c\x27\x2d"}, + {0x33, "\x90\x20\x07"}, {0x33, "\x8c\x27\x2f"}, {0x33, "\x90\x00\x04"}, + {0x33, "\x8c\x27\x31"}, {0x33, "\x90\x00\x04"}, {0x33, "\x8c\x27\x33"}, + {0x33, "\x90\x04\xbb"}, {0x33, "\x8c\x27\x35"}, {0x33, "\x90\x06\x4b"}, + {0x33, "\x8c\x27\x37"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x39"}, + {0x33, "\x90\x21\x11"}, {0x33, "\x8c\x27\x3b"}, {0x33, "\x90\x00\x24"}, + {0x33, "\x8c\x27\x3d"}, {0x33, "\x90\x01\x20"}, {0x33, "\x8c\x27\x41"}, + {0x33, "\x90\x01\x69"}, {0x33, "\x8c\x27\x45"}, {0x33, "\x90\x04\xed"}, + {0x33, "\x8c\x27\x47"}, {0x33, "\x90\x09\x4c"}, {0x33, "\x8c\x27\x51"}, + {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x53"}, {0x33, "\x90\x03\x20"}, + {0x33, "\x8c\x27\x55"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x57"}, + {0x33, "\x90\x02\x58"}, {0x33, "\x8c\x27\x5f"}, {0x33, "\x90\x00\x00"}, + {0x33, "\x8c\x27\x61"}, {0x33, "\x90\x06\x40"}, {0x33, "\x8c\x27\x63"}, + {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x65"}, {0x33, "\x90\x04\xb0"}, + {0x33, "\x8c\x22\x2e"}, {0x33, "\x90\x00\xa1"}, {0x33, "\x8c\xa4\x08"}, {0x33, "\x90\x00\x1f"}, {0x33, "\x8c\xa4\x09"}, {0x33, "\x90\x00\x21"}, {0x33, "\x8c\xa4\x0a"}, {0x33, "\x90\x00\x25"}, {0x33, "\x8c\xa4\x0b"}, - {0x33, "\x90\x00\x27"}, {0x33, "\x8c\x24\x11"}, {0x33, "\x90\x00\xa0"}, - {0x33, "\x8c\x24\x13"}, {0x33, "\x90\x00\xc0"}, {0x33, "\x8c\x24\x15"}, - {0x33, "\x90\x00\xa0"}, {0x33, "\x8c\x24\x17"}, {0x33, "\x90\x00\xc0"}, -}; - -static struct idxdata tbl_common5[] = { - {0x33, "\x8c\xa4\x04"}, {0x33, "\x90\x00\x80"}, {0x33, "\x8c\xa7\x9d"}, - {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa7\x9e"}, {0x33, "\x90\x00\x00"}, - {0x33, "\x8c\xa2\x0c"}, {0x33, "\x90\x00\x17"}, {0x33, "\x8c\xa2\x15"}, - {0x33, "\x90\x00\x04"}, {0x33, "\x8c\xa2\x14"}, {0x33, "\x90\x00\x20"}, - {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x17"}, - /* msleep(53); */ - {0x33, "\x90\x21\x11"}, {0x33, "\x8c\x27\x1b"}, {0x33, "\x90\x02\x4f"}, - {0x33, "\x8c\x27\x25"}, {0x33, "\x90\x06\x0f"}, {0x33, "\x8c\x27\x39"}, - {0x33, "\x90\x21\x11"}, {0x33, "\x8c\x27\x3d"}, {0x33, "\x90\x01\x20"}, - {0x33, "\x8c\x27\x47"}, {0x33, "\x90\x09\x4c"}, {0x33, "\x8c\x27\x03"}, - {0x33, "\x90\x02\x84"}, {0x33, "\x8c\x27\x05"}, {0x33, "\x90\x01\xe2"}, - {0x33, "\x8c\x27\x07"}, {0x33, "\x90\x06\x40"}, {0x33, "\x8c\x27\x09"}, - {0x33, "\x90\x04\xb0"}, {0x33, "\x8c\x27\x0d"}, {0x33, "\x90\x00\x00"}, - {0x33, "\x8c\x27\x0f"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x11"}, - {0x33, "\x90\x04\xbd"}, {0x33, "\x8c\x27\x13"}, {0x33, "\x90\x06\x4d"}, - {0x33, "\x8c\x27\x15"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x17"}, - {0x33, "\x90\x21\x11"}, {0x33, "\x8c\x27\x19"}, {0x33, "\x90\x04\x6c"}, - {0x33, "\x8c\x27\x1b"}, {0x33, "\x90\x02\x4f"}, {0x33, "\x8c\x27\x1d"}, - {0x33, "\x90\x01\x02"}, {0x33, "\x8c\x27\x1f"}, {0x33, "\x90\x02\x79"}, - {0x33, "\x8c\x27\x21"}, {0x33, "\x90\x01\x55"}, {0x33, "\x8c\x27\x23"}, - {0x33, "\x90\x02\x85"}, {0x33, "\x8c\x27\x25"}, {0x33, "\x90\x06\x0f"}, - {0x33, "\x8c\x27\x27"}, {0x33, "\x90\x20\x20"}, {0x33, "\x8c\x27\x29"}, - {0x33, "\x90\x20\x20"}, {0x33, "\x8c\x27\x2b"}, {0x33, "\x90\x10\x20"}, - {0x33, "\x8c\x27\x2d"}, {0x33, "\x90\x20\x07"}, {0x33, "\x8c\x27\x2f"}, - {0x33, "\x90\x00\x04"}, {0x33, "\x8c\x27\x31"}, {0x33, "\x90\x00\x04"}, - {0x33, "\x8c\x27\x33"}, {0x33, "\x90\x04\xbb"}, {0x33, "\x8c\x27\x35"}, - {0x33, "\x90\x06\x4b"}, {0x33, "\x8c\x27\x37"}, {0x33, "\x90\x00\x00"}, - {0x33, "\x8c\x27\x39"}, {0x33, "\x90\x21\x11"}, {0x33, "\x8c\x27\x3b"}, - {0x33, "\x90\x00\x24"}, {0x33, "\x8c\x27\x3d"}, {0x33, "\x90\x01\x20"}, - {0x33, "\x8c\x27\x41"}, {0x33, "\x90\x01\x69"}, {0x33, "\x8c\x27\x45"}, - {0x33, "\x90\x04\xed"}, {0x33, "\x8c\x27\x47"}, {0x33, "\x90\x09\x4c"}, - {0x33, "\x8c\x27\x51"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x53"}, - {0x33, "\x90\x03\x20"}, {0x33, "\x8c\x27\x55"}, {0x33, "\x90\x00\x00"}, - {0x33, "\x8c\x27\x57"}, {0x33, "\x90\x02\x58"}, {0x33, "\x8c\x27\x5f"}, - {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x61"}, {0x33, "\x90\x06\x40"}, - {0x33, "\x8c\x27\x63"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x65"}, - {0x33, "\x90\x04\xb0"}, {0x33, "\x8c\x22\x2e"}, {0x33, "\x90\x00\xa1"}, - {0x33, "\x8c\xa4\x08"}, {0x33, "\x90\x00\x1f"}, {0x33, "\x8c\xa4\x09"}, - {0x33, "\x90\x00\x21"}, {0x33, "\x8c\xa4\x0a"}, {0x33, "\x90\x00\x25"}, - {0x33, "\x8c\xa4\x0b"}, {0x33, "\x90\x00\x27"}, {0x33, "\x8c\x24\x11"}, - {0x33, "\x90\x00\xa1"}, {0x33, "\x8c\x24\x13"}, {0x33, "\x90\x00\xc1"}, - {0x33, "\x8c\x24\x15"}, -}; - -static struct validx tbl_init_at_startup[] = { - {0x0000, 0x0000}, - {53, 0xffff}, - {0x0010, 0x0010}, - {53, 0xffff}, - {0x0008, 0x00c0}, - {53, 0xffff}, - {0x0001, 0x00c1}, - {53, 0xffff}, - {0x0001, 0x00c2}, - {53, 0xffff}, - {0x0020, 0x0006}, - {53, 0xffff}, - {0x006a, 0x000d}, - {53, 0xffff}, + {0x33, "\x90\x00\x27"}, {0x33, "\x8c\x24\x11"}, {0x33, "\x90\x00\xa1"}, + {0x33, "\x8c\x24\x13"}, {0x33, "\x90\x00\xc1"}, {0x33, "\x8c\x24\x15"}, + {0x33, "\x90\x00\x6a"}, {0x33, "\x8c\x24\x17"}, {0x33, "\x90\x00\x80"}, + {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"}, + {2, "\xff\xff\xff"}, + {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"}, + {3, "\xff\xff\xff"}, }; static struct idxdata tbl_init_post_alt_low1[] = { @@ -209,7 +206,7 @@ static struct idxdata tbl_init_post_alt_low3[] = { {2, "\xff\xff\xff"}, {0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x01"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x00"}, - {2, "\xff\xff\xff"}, /* - * */ + {2, "\xff\xff\xff"}, {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"}, {2, "\xff\xff\xff"}, {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"}, @@ -217,61 +214,15 @@ static struct idxdata tbl_init_post_alt_low3[] = { {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"}, {2, "\xff\xff\xff"}, {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"}, - {1, "\xff\xff\xff"}, -}; - -static struct idxdata tbl_init_post_alt_low4[] = { - {0x32, "\x10\x01\xf8"}, {0x34, "\xce\x01\xa8"}, {0x34, "\xd0\x66\x33"}, - {0x34, "\xd2\x31\x9a"}, {0x34, "\xd4\x94\x63"}, {0x34, "\xd6\x4b\x25"}, - {0x34, "\xd8\x26\x70"}, {0x34, "\xda\x72\x4c"}, {0x34, "\xdc\xff\x04"}, - {0x34, "\xde\x01\x5b"}, {0x34, "\xe6\x01\x13"}, {0x34, "\xee\x0b\xf0"}, - {0x34, "\xf6\x0b\xa4"}, {0x35, "\x00\xf6\xe7"}, {0x35, "\x08\x0d\xfd"}, - {0x35, "\x10\x25\x63"}, {0x35, "\x18\x35\x6c"}, {0x35, "\x20\x42\x7e"}, - {0x35, "\x28\x19\x44"}, {0x35, "\x30\x39\xd4"}, {0x35, "\x38\xf5\xa8"}, - {0x35, "\x4c\x07\x90"}, {0x35, "\x44\x07\xb8"}, {0x35, "\x5c\x06\x88"}, - {0x35, "\x54\x07\xff"}, {0x34, "\xe0\x01\x52"}, {0x34, "\xe8\x00\xcc"}, - {0x34, "\xf0\x0d\x83"}, {0x34, "\xf8\x0c\xb3"}, {0x35, "\x02\xfe\xba"}, - {0x35, "\x0a\x04\xe0"}, {0x35, "\x12\x1c\x63"}, {0x35, "\x1a\x2b\x5a"}, - {0x35, "\x22\x32\x5e"}, {0x35, "\x2a\x0d\x28"}, {0x35, "\x32\x2c\x02"}, - {0x35, "\x3a\xf4\xfa"}, {0x35, "\x4e\x07\xef"}, {0x35, "\x46\x07\x88"}, - {0x35, "\x5e\x07\xc1"}, {0x35, "\x56\x04\x64"}, {0x34, "\xe4\x01\x15"}, - {0x34, "\xec\x00\x82"}, {0x34, "\xf4\x0c\xce"}, {0x34, "\xfc\x0c\xba"}, - {0x35, "\x06\x1f\x02"}, {0x35, "\x0e\x02\xe3"}, {0x35, "\x16\x1a\x50"}, - {0x35, "\x1e\x24\x39"}, {0x35, "\x26\x23\x4c"}, {0x35, "\x2e\xf9\x1b"}, - {0x35, "\x36\x23\x19"}, {0x35, "\x3e\x12\x08"}, {0x35, "\x52\x07\x22"}, - {0x35, "\x4a\x03\xd3"}, {0x35, "\x62\x06\x54"}, {0x35, "\x5a\x04\x5d"}, - {0x34, "\xe2\x01\x04"}, {0x34, "\xea\x00\xa0"}, {0x34, "\xf2\x0c\xbc"}, - {0x34, "\xfa\x0c\x5b"}, {0x35, "\x04\x17\xf2"}, {0x35, "\x0c\x02\x08"}, - {0x35, "\x14\x28\x43"}, {0x35, "\x1c\x28\x62"}, {0x35, "\x24\x2b\x60"}, - {0x35, "\x2c\x07\x33"}, {0x35, "\x34\x1f\xb0"}, {0x35, "\x3c\xed\xcd"}, - {0x35, "\x50\x00\x06"}, {0x35, "\x48\x07\xff"}, {0x35, "\x60\x05\x89"}, - {0x35, "\x58\x07\xff"}, {0x35, "\x40\x00\xa0"}, {0x35, "\x42\x00\x00"}, - {0x32, "\x10\x01\xfc"}, {0x33, "\x8c\xa1\x18"}, - /* Flip/Mirror h/v=1 */ - {0x33, "\x90\x00\x3c"}, {0x33, "\x8c\x27\x19"}, {0x33, "\x90\x04\x6c"}, - {0x33, "\x8c\x27\x3b"}, {0x33, "\x90\x00\x24"}, {0x33, "\x8c\xa1\x03"}, - {0x33, "\x90\x00\x06"}, - {130, "\xff\xff\xff"}, - {0x33, "\x90\x00\x06"}, {0x33, "\x90\x00\x06"}, {0x33, "\x90\x00\x06"}, - {0x33, "\x90\x00\x06"}, {0x33, "\x90\x00\x06"}, {0x33, "\x90\x00\x06"}, - {100, "\xff\xff\xff"}, - /* ?? */ - {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"}, {0x33, "\x8c\xa1\x02"}, - {0x33, "\x90\x00\x1f"}, {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"}, - {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"}, - /* Brigthness=70 */ - {0x33, "\x8c\xa2\x06"}, {0x33, "\x90\x00\x46"}, {0x33, "\x8c\xa1\x02"}, - {0x33, "\x90\x00\x0f"}, {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"}, - /* Sharpness=20 */ - {0x32, "\x6c\x14\x08"}, }; -static struct idxdata tbl_init_post_alt_big1[] = { +static struct idxdata tbl_init_post_alt_big[] = { {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"}, {2, "\xff\xff\xff"}, {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"}, {2, "\xff\xff\xff"}, {0x34, "\x1e\x8f\x09"}, {0x34, "\x1c\x01\x28"}, {0x34, "\x1e\x8f\x09"}, + {2, "\xff\xff\xff"}, {0x34, "\x1e\x8f\x09"}, {0x32, "\x14\x06\xe6"}, {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"}, {2, "\xff\xff\xff"}, @@ -285,9 +236,17 @@ static struct idxdata tbl_init_post_alt_big1[] = { {0x33, "\x90\x00\x03"}, {0x33, "\x8c\xa1\x34"}, {0x33, "\x90\x00\x03"}, {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x02"}, {0x33, "\x2e\x01\x00"}, {0x34, "\x04\x00\x2a"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"}, + {0x33, "\x8c\x27\x97"}, {0x33, "\x90\x01\x00"}, + {51, "\xff\xff\xff"}, + {0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa1\x03"}, + {0x33, "\x90\x00\x01"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x00"}, + {51, "\xff\xff\xff"}, + {0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x72"}, {0x33, "\x8c\xa1\x03"}, + {0x33, "\x90\x00\x02"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"}, + {51, "\xff\xff\xff"}, }; -static struct idxdata tbl_init_post_alt_big2[] = { +static struct idxdata tbl_init_post_alt_3B[] = { {0x32, "\x10\x01\xf8"}, {0x34, "\xce\x01\xa8"}, {0x34, "\xd0\x66\x33"}, {0x34, "\xd2\x31\x9a"}, {0x34, "\xd4\x94\x63"}, {0x34, "\xd6\x4b\x25"}, {0x34, "\xd8\x26\x70"}, {0x34, "\xda\x72\x4c"}, {0x34, "\xdc\xff\x04"}, @@ -316,17 +275,6 @@ static struct idxdata tbl_init_post_alt_big2[] = { {0x32, "\x10\x01\xfc"}, {0x33, "\x8c\xa1\x18"}, {0x33, "\x90\x00\x3c"}, }; -static struct idxdata tbl_init_post_alt_big3[] = { - {0x33, "\x8c\xa1\x02"}, - {0x33, "\x90\x00\x1f"}, - {0x33, "\x8c\xa1\x02"}, - {0x33, "\x90\x00\x1f"}, - {0x33, "\x8c\xa1\x02"}, - {0x33, "\x90\x00\x1f"}, - {0x33, "\x8c\xa1\x02"}, - {0x33, "\x90\x00\x1f"}, -}; - static u8 *dat_640 = "\xd0\x02\xd1\x08\xd2\xe1\xd3\x02\xd4\x10\xd5\x81"; static u8 *dat_800 = "\xd0\x02\xd1\x10\xd2\x57\xd3\x02\xd4\x18\xd5\x21"; static u8 *dat_1280 = "\xd0\x02\xd1\x20\xd2\x01\xd3\x02\xd4\x28\xd5\x01"; @@ -351,7 +299,7 @@ void mi2020_init_settings(struct gspca_dev *gspca_dev) sd->vcur.gamma = 0; sd->vcur.hue = 0; sd->vcur.saturation = 60; - sd->vcur.whitebal = 50; + sd->vcur.whitebal = 0; /* 50, not done by hardware */ sd->vcur.mirror = 0; sd->vcur.flip = 0; sd->vcur.AC50Hz = 1; @@ -361,17 +309,12 @@ void mi2020_init_settings(struct gspca_dev *gspca_dev) sd->vmax.sharpness = 40; sd->vmax.contrast = 3; sd->vmax.gamma = 2; - sd->vmax.hue = 0 + 1; /* 200 */ - sd->vmax.saturation = 0; /* 100 */ - sd->vmax.whitebal = 0; /* 100 */ + sd->vmax.hue = 0 + 1; /* 200, not done by hardware */ + sd->vmax.saturation = 0; /* 100, not done by hardware */ + sd->vmax.whitebal = 2; /* 100, not done by hardware */ sd->vmax.mirror = 1; sd->vmax.flip = 1; sd->vmax.AC50Hz = 1; - if (_MI2020b_) { - sd->vmax.contrast = 0; - sd->vmax.gamma = 0; - sd->vmax.backlight = 0; - } sd->dev_camera_settings = mi2020_camera_settings; sd->dev_init_at_startup = mi2020_init_at_startup; @@ -384,51 +327,9 @@ void mi2020_init_settings(struct gspca_dev *gspca_dev) static void common(struct gspca_dev *gspca_dev) { - s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv; - - if (_MI2020b_) { - fetch_validx(gspca_dev, tbl_common1, ARRAY_SIZE(tbl_common1)); - } else { - if (_MI2020_) - ctrl_out(gspca_dev, 0x40, 1, 0x0008, 0x0004, 0, NULL); - else - ctrl_out(gspca_dev, 0x40, 1, 0x0002, 0x0004, 0, NULL); - msleep(35); - fetch_validx(gspca_dev, tbl_common2, ARRAY_SIZE(tbl_common2)); - } - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x86\x25\x01"); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x86\x25\x00"); - msleep(2); /* - * */ - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0030, 3, "\x1a\x0a\xcc"); - if (reso == IMAGE_1600) - msleep(2); /* 1600 */ - fetch_idxdata(gspca_dev, tbl_common3, ARRAY_SIZE(tbl_common3)); - - if (_MI2020b_ || _MI2020_) - fetch_idxdata(gspca_dev, tbl_common4, - ARRAY_SIZE(tbl_common4)); - - fetch_idxdata(gspca_dev, tbl_common5, ARRAY_SIZE(tbl_common5)); - if (_MI2020b_ || _MI2020_) { - /* Different from fret */ - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x78"); - /* Same as fret */ - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\x24\x17"); - /* Different from fret */ - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x90"); - } else { - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x6a"); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\x24\x17"); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x80"); - } - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03"); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x05"); - msleep(2); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03"); - if (reso == IMAGE_1600) - msleep(14); /* 1600 */ - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x06"); - msleep(2); + fetch_validx(gspca_dev, tbl_common_0B, ARRAY_SIZE(tbl_common_0B)); + fetch_idxdata(gspca_dev, tbl_common_3B, ARRAY_SIZE(tbl_common_3B)); + ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x0000, 0, NULL); } static int mi2020_init_at_startup(struct gspca_dev *gspca_dev) @@ -441,8 +342,16 @@ static int mi2020_init_at_startup(struct gspca_dev *gspca_dev) fetch_validx(gspca_dev, tbl_init_at_startup, ARRAY_SIZE(tbl_init_at_startup)); + ctrl_out(gspca_dev, 0x40, 1, 0x7a00, 0x8030, 0, NULL); + ctrl_in(gspca_dev, 0xc0, 2, 0x7a00, 0x8030, 1, &c); + common(gspca_dev); + msleep(61); +/* ctrl_out(gspca_dev, 0x40, 11, 0x0000, 0x0000, 0, NULL); */ +/* msleep(36); */ + ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0000, 0, NULL); + return 0; } @@ -450,17 +359,17 @@ static int mi2020_init_pre_alt(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - sd->mirrorMask = 0; + sd->mirrorMask = 0; + sd->vold.hue = -1; - sd->vold.backlight = -1; + /* These controls need to be reset */ sd->vold.brightness = -1; sd->vold.sharpness = -1; - sd->vold.contrast = -1; - sd->vold.gamma = -1; - sd->vold.hue = -1; - sd->vold.mirror = -1; - sd->vold.flip = -1; - sd->vold.AC50Hz = -1; + + /* If not different from default, they do not need to be set */ + sd->vold.contrast = 0; + sd->vold.gamma = 0; + sd->vold.backlight = 0; mi2020_init_post_alt(gspca_dev); @@ -472,10 +381,10 @@ static int mi2020_init_post_alt(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv; - s32 backlight = sd->vcur.backlight; s32 mirror = (((sd->vcur.mirror > 0) ^ sd->mirrorMask) > 0); s32 flip = (((sd->vcur.flip > 0) ^ sd->mirrorMask) > 0); s32 freq = (sd->vcur.AC50Hz > 0); + s32 wbal = sd->vcur.whitebal; u8 dat_freq2[] = {0x90, 0x00, 0x80}; u8 dat_multi1[] = {0x8c, 0xa7, 0x00}; @@ -484,6 +393,7 @@ static int mi2020_init_post_alt(struct gspca_dev *gspca_dev) u8 dat_multi4[] = {0x90, 0x00, 0x00}; u8 dat_hvflip2[] = {0x90, 0x04, 0x6c}; u8 dat_hvflip4[] = {0x90, 0x00, 0x24}; + u8 dat_wbal2[] = {0x90, 0x00, 0x00}; u8 c; sd->nbIm = -1; @@ -491,23 +401,26 @@ static int mi2020_init_post_alt(struct gspca_dev *gspca_dev) dat_freq2[2] = freq ? 0xc0 : 0x80; dat_multi1[2] = 0x9d; dat_multi3[2] = dat_multi1[2] + 1; - dat_multi4[2] = dat_multi2[2] = backlight; + if (wbal == 0) { + dat_multi4[2] = dat_multi2[2] = 0; + dat_wbal2[2] = 0x17; + } else if (wbal == 1) { + dat_multi4[2] = dat_multi2[2] = 0; + dat_wbal2[2] = 0x35; + } else if (wbal == 2) { + dat_multi4[2] = dat_multi2[2] = 0x20; + dat_wbal2[2] = 0x17; + } dat_hvflip2[2] = 0x6c + 2 * (1 - flip) + (1 - mirror); dat_hvflip4[2] = 0x24 + 2 * (1 - flip) + (1 - mirror); msleep(200); - ctrl_out(gspca_dev, 0x40, 5, 0x0001, 0x0000, 0, NULL); - msleep(3); /* 35 * */ + msleep(2); common(gspca_dev); - ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x0000, 0, NULL); - msleep(70); - - if (_MI2020b_) - ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL); - + msleep(142); ctrl_out(gspca_dev, 0x40, 1, 0x0010, 0x0010, 0, NULL); ctrl_out(gspca_dev, 0x40, 1, 0x0003, 0x00c1, 0, NULL); ctrl_out(gspca_dev, 0x40, 1, 0x0042, 0x00c2, 0, NULL); @@ -523,8 +436,7 @@ static int mi2020_init_post_alt(struct gspca_dev *gspca_dev) ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, dat_800); - if (_MI2020c_) - fetch_idxdata(gspca_dev, tbl_init_post_alt_low1, + fetch_idxdata(gspca_dev, tbl_init_post_alt_low1, ARRAY_SIZE(tbl_init_post_alt_low1)); if (reso == IMAGE_800) @@ -534,87 +446,10 @@ static int mi2020_init_post_alt(struct gspca_dev *gspca_dev) fetch_idxdata(gspca_dev, tbl_init_post_alt_low3, ARRAY_SIZE(tbl_init_post_alt_low3)); - if (_MI2020b_) { - ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0010, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL); - msleep(150); - } else if (_MI2020c_) { - ctrl_out(gspca_dev, 0x40, 1, 0x0010, 0x0010, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL); - msleep(120); - ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL); - msleep(30); - } else if (_MI2020_) { - ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0010, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL); - msleep(120); - ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL); - msleep(30); - } - - /* AC power frequency */ - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq1); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq2); - msleep(20); - /* backlight */ - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4); - /* at init time but not after */ - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa2\x0c"); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x17"); - /* finish the backlight */ - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6); - msleep(5);/* " */ - - if (_MI2020c_) { - fetch_idxdata(gspca_dev, tbl_init_post_alt_low4, - ARRAY_SIZE(tbl_init_post_alt_low4)); - } else { - ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, &c); - msleep(14); /* 0xd8 */ - - /* flip/mirror */ - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, - 3, dat_hvflip1); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, - 3, dat_hvflip2); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, - 3, dat_hvflip3); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, - 3, dat_hvflip4); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, - 3, dat_hvflip5); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, - 3, dat_hvflip6); - msleep(21); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, - 3, dat_dummy1); - msleep(5); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, - 3, dat_dummy1); - msleep(5); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, - 3, dat_dummy1); - msleep(5); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, - 3, dat_dummy1); - msleep(5); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, - 3, dat_dummy1); - msleep(5); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, - 3, dat_dummy1); - /* end of flip/mirror main part */ - msleep(246); /* 146 */ - - sd->nbIm = 0; - } + ctrl_out(gspca_dev, 0x40, 1, 0x0010, 0x0010, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL); + msleep(120); break; case IMAGE_1280: @@ -643,108 +478,62 @@ static int mi2020_init_post_alt(struct gspca_dev *gspca_dev) 3, "\x90\x04\xb0"); } - fetch_idxdata(gspca_dev, tbl_init_post_alt_big1, - ARRAY_SIZE(tbl_init_post_alt_big1)); - - if (reso == IMAGE_1600) - msleep(13); /* 1600 */ - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\x27\x97"); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x01\x00"); - msleep(53); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x20"); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x00"); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03"); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x01"); - if (reso == IMAGE_1600) - msleep(13); /* 1600 */ - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa7\x02"); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x00"); - msleep(53); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x20"); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x72"); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03"); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x02"); - if (reso == IMAGE_1600) - msleep(13); /* 1600 */ - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa7\x02"); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x01"); - msleep(53); - - if (_MI2020b_) { - ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0010, 0, NULL); - if (reso == IMAGE_1600) - msleep(500); /* 1600 */ - ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL); - msleep(1850); - } else if (_MI2020c_ || _MI2020_) { - ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0010, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL); - msleep(1850); - ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL); - msleep(30); - } + fetch_idxdata(gspca_dev, tbl_init_post_alt_big, + ARRAY_SIZE(tbl_init_post_alt_big)); - /* AC power frequency */ - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq1); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq2); - msleep(20); - /* backlight */ - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4); - /* at init time but not after */ - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa2\x0c"); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x17"); - /* finish the backlight */ - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6); - msleep(6); /* " */ + ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0010, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL); + msleep(1850); + } - ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, &c); - msleep(14); + ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL); + msleep(40); + + /* AC power frequency */ + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq1); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq2); + msleep(33); + /* light source */ + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_wbal1); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_wbal2); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6); + msleep(7); + ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, &c); + + fetch_idxdata(gspca_dev, tbl_init_post_alt_3B, + ARRAY_SIZE(tbl_init_post_alt_3B)); + + /* hvflip */ + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip1); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip2); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip3); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip4); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip5); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip6); + msleep(250); + + if (reso == IMAGE_640 || reso == IMAGE_800) + fetch_idxdata(gspca_dev, tbl_middle_hvflip_low, + ARRAY_SIZE(tbl_middle_hvflip_low)); + else + fetch_idxdata(gspca_dev, tbl_middle_hvflip_big, + ARRAY_SIZE(tbl_middle_hvflip_big)); - if (_MI2020c_) - fetch_idxdata(gspca_dev, tbl_init_post_alt_big2, - ARRAY_SIZE(tbl_init_post_alt_big2)); + fetch_idxdata(gspca_dev, tbl_end_hvflip, + ARRAY_SIZE(tbl_end_hvflip)); - /* flip/mirror */ - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip1); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip2); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip3); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip4); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip5); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip6); - /* end of flip/mirror main part */ - msleep(16); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03"); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x01"); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x20"); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x00"); - if (reso == IMAGE_1600) - msleep(25); /* 1600 */ - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa7\x02"); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x00"); - msleep(103); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03"); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x02"); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x20"); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x72"); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa7\x02"); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x01"); - sd->nbIm = 0; - - if (_MI2020c_) - fetch_idxdata(gspca_dev, tbl_init_post_alt_big3, - ARRAY_SIZE(tbl_init_post_alt_big3)); - } + sd->nbIm = 0; sd->vold.mirror = mirror; sd->vold.flip = flip; sd->vold.AC50Hz = freq; - sd->vold.backlight = backlight; + sd->vold.whitebal = wbal; mi2020_camera_settings(gspca_dev); @@ -772,6 +561,7 @@ static int mi2020_configure_alt(struct gspca_dev *gspca_dev) static int mi2020_camera_settings(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; + s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv; s32 backlight = sd->vcur.backlight; s32 bright = sd->vcur.brightness; @@ -782,6 +572,7 @@ static int mi2020_camera_settings(struct gspca_dev *gspca_dev) s32 mirror = (((sd->vcur.mirror > 0) ^ sd->mirrorMask) > 0); s32 flip = (((sd->vcur.flip > 0) ^ sd->mirrorMask) > 0); s32 freq = (sd->vcur.AC50Hz > 0); + s32 wbal = sd->vcur.whitebal; u8 dat_sharp[] = {0x6c, 0x00, 0x08}; u8 dat_bright2[] = {0x90, 0x00, 0x00}; @@ -792,6 +583,7 @@ static int mi2020_camera_settings(struct gspca_dev *gspca_dev) u8 dat_multi4[] = {0x90, 0x00, 0x00}; u8 dat_hvflip2[] = {0x90, 0x04, 0x6c}; u8 dat_hvflip4[] = {0x90, 0x00, 0x24}; + u8 dat_wbal2[] = {0x90, 0x00, 0x00}; /* Less than 4 images received -> too early to set the settings */ if (sd->nbIm < 4) { @@ -809,67 +601,89 @@ static int mi2020_camera_settings(struct gspca_dev *gspca_dev) msleep(20); } + if (wbal != sd->vold.whitebal) { + sd->vold.whitebal = wbal; + if (wbal < 0 || wbal > sd->vmax.whitebal) + wbal = 0; + + dat_multi1[2] = 0x9d; + dat_multi3[2] = dat_multi1[2] + 1; + if (wbal == 0) { + dat_multi4[2] = dat_multi2[2] = 0; + dat_wbal2[2] = 0x17; + } else if (wbal == 1) { + dat_multi4[2] = dat_multi2[2] = 0; + dat_wbal2[2] = 0x35; + } else if (wbal == 2) { + dat_multi4[2] = dat_multi2[2] = 0x20; + dat_wbal2[2] = 0x17; + } + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_wbal1); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_wbal2); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6); + } + if (mirror != sd->vold.mirror || flip != sd->vold.flip) { sd->vold.mirror = mirror; sd->vold.flip = flip; dat_hvflip2[2] = 0x6c + 2 * (1 - flip) + (1 - mirror); dat_hvflip4[2] = 0x24 + 2 * (1 - flip) + (1 - mirror); + + fetch_idxdata(gspca_dev, tbl_init_post_alt_3B, + ARRAY_SIZE(tbl_init_post_alt_3B)); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip1); ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip2); ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip3); ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip4); ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip5); ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip6); - msleep(130); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1); - msleep(6); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1); - msleep(6); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1); - msleep(6); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1); - msleep(6); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1); - msleep(6); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1); - msleep(6); - - /* Sometimes present, sometimes not, useful? */ - /* ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy2); - * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy3); - * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy2); - * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy3); - * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy2); - * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy3); - * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy2); - * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy3);*/ + msleep(40); + + if (reso == IMAGE_640 || reso == IMAGE_800) + fetch_idxdata(gspca_dev, tbl_middle_hvflip_low, + ARRAY_SIZE(tbl_middle_hvflip_low)); + else + fetch_idxdata(gspca_dev, tbl_middle_hvflip_big, + ARRAY_SIZE(tbl_middle_hvflip_big)); + + fetch_idxdata(gspca_dev, tbl_end_hvflip, + ARRAY_SIZE(tbl_end_hvflip)); } - if (backlight != sd->vold.backlight) { - sd->vold.backlight = backlight; - if (backlight < 0 || backlight > sd->vmax.backlight) - backlight = 0; + if (bright != sd->vold.brightness) { + sd->vold.brightness = bright; + if (bright < 0 || bright > sd->vmax.brightness) + bright = 0; - dat_multi1[2] = 0x9d; - dat_multi3[2] = dat_multi1[2] + 1; - dat_multi4[2] = dat_multi2[2] = backlight; - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6); + dat_bright2[2] = bright; + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright1); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright2); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright3); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright4); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright5); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright6); } - if (gam != sd->vold.gamma) { + if (cntr != sd->vold.contrast || gam != sd->vold.gamma) { + sd->vold.contrast = cntr; + if (cntr < 0 || cntr > sd->vmax.contrast) + cntr = 0; sd->vold.gamma = gam; if (gam < 0 || gam > sd->vmax.gamma) gam = 0; dat_multi1[2] = 0x6d; dat_multi3[2] = dat_multi1[2] + 1; - dat_multi4[2] = dat_multi2[2] = 0x40 + gam; + if (cntr == 0) + cntr = 4; + dat_multi4[2] = dat_multi2[2] = cntr * 0x10 + 2 - gam; ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1); ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2); ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3); @@ -878,14 +692,14 @@ static int mi2020_camera_settings(struct gspca_dev *gspca_dev) ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6); } - if (cntr != sd->vold.contrast) { - sd->vold.contrast = cntr; - if (cntr < 0 || cntr > sd->vmax.contrast) - cntr = 0; + if (backlight != sd->vold.backlight) { + sd->vold.backlight = backlight; + if (backlight < 0 || backlight > sd->vmax.backlight) + backlight = 0; - dat_multi1[2] = 0x6d; + dat_multi1[2] = 0x9d; dat_multi3[2] = dat_multi1[2] + 1; - dat_multi4[2] = dat_multi2[2] = 0x12 + 16 * cntr; + dat_multi4[2] = dat_multi2[2] = backlight; ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1); ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2); ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3); @@ -894,20 +708,6 @@ static int mi2020_camera_settings(struct gspca_dev *gspca_dev) ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6); } - if (bright != sd->vold.brightness) { - sd->vold.brightness = bright; - if (bright < 0 || bright > sd->vmax.brightness) - bright = 0; - - dat_bright2[2] = bright; - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright1); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright2); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright3); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright4); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright5); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright6); - } - if (sharp != sd->vold.sharpness) { sd->vold.sharpness = sharp; if (sharp < 0 || sharp > sd->vmax.sharpness) @@ -928,9 +728,6 @@ static int mi2020_camera_settings(struct gspca_dev *gspca_dev) static void mi2020_post_unset_alt(struct gspca_dev *gspca_dev) { ctrl_out(gspca_dev, 0x40, 5, 0x0000, 0x0000, 0, NULL); - msleep(20); - if (_MI2020c_ || _MI2020_) - ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0000, 0, NULL); - else - ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x0000, 0, NULL); + msleep(40); + ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0000, 0, NULL); } diff --git a/drivers/media/video/gspca/gl860/gl860-ov9655.c b/drivers/media/video/gspca/gl860/gl860-ov9655.c index d412694c50a..5ae9619d72a 100644 --- a/drivers/media/video/gspca/gl860/gl860-ov9655.c +++ b/drivers/media/video/gspca/gl860/gl860-ov9655.c @@ -69,7 +69,7 @@ static u8 *tbl_640[] = { "\xd0\x01\xd1\x08\xd2\xe0\xd3\x01" "\xd4\x10\xd5\x80" }; -static u8 *tbl_800[] = { +static u8 *tbl_1280[] = { "\x00\x40\x07\x6a\x06\xf3\x0d\x6a" "\x10\x10\xc1\x01" , "\x12\x80\x00\x00\x01\x98\x02\x80" "\x03\x12\x04\x01\x0b\x57\x0e\x61" @@ -217,7 +217,7 @@ static int ov9655_init_post_alt(struct gspca_dev *gspca_dev) ctrl_out(gspca_dev, 0x40, 5, 0x0001, 0x0000, 0, NULL); - tbl = (reso == IMAGE_640) ? tbl_640 : tbl_800; + tbl = (reso == IMAGE_640) ? tbl_640 : tbl_1280; ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, tbl_length[0], tbl[0]); diff --git a/drivers/media/video/gspca/gl860/gl860.c b/drivers/media/video/gspca/gl860/gl860.c index 9e42476c0ea..e86eb8b4aed 100644 --- a/drivers/media/video/gspca/gl860/gl860.c +++ b/drivers/media/video/gspca/gl860/gl860.c @@ -63,7 +63,7 @@ static int sd_set_##thename(struct gspca_dev *gspca_dev, s32 val)\ \ sd->vcur.thename = val;\ if (gspca_dev->streaming)\ - sd->dev_camera_settings(gspca_dev);\ + sd->waitSet = 1;\ return 0;\ } \ static int sd_get_##thename(struct gspca_dev *gspca_dev, s32 *val)\ @@ -91,7 +91,6 @@ SD_SETGET(contrast) /* control table */ static struct ctrl sd_ctrls_mi1320[GL860_NCTRLS]; static struct ctrl sd_ctrls_mi2020[GL860_NCTRLS]; -static struct ctrl sd_ctrls_mi2020b[GL860_NCTRLS]; static struct ctrl sd_ctrls_ov2640[GL860_NCTRLS]; static struct ctrl sd_ctrls_ov9655[GL860_NCTRLS]; @@ -121,8 +120,6 @@ static int gl860_build_control_table(struct gspca_dev *gspca_dev) sd_ctrls = sd_ctrls_mi1320; else if (_MI2020_) sd_ctrls = sd_ctrls_mi2020; - else if (_MI2020b_) - sd_ctrls = sd_ctrls_mi2020b; else if (_OV2640_) sd_ctrls = sd_ctrls_ov2640; else if (_OV9655_) @@ -187,19 +184,6 @@ static const struct sd_desc sd_desc_mi2020 = { .dq_callback = sd_callback, }; -static const struct sd_desc sd_desc_mi2020b = { - .name = MODULE_NAME, - .ctrls = sd_ctrls_mi2020b, - .nctrls = GL860_NCTRLS, - .config = sd_config, - .init = sd_init, - .isoc_init = sd_isoc_init, - .start = sd_start, - .stop0 = sd_stop0, - .pkt_scan = sd_pkt_scan, - .dq_callback = sd_callback, -}; - static const struct sd_desc sd_desc_ov2640 = { .name = MODULE_NAME, .ctrls = sd_ctrls_ov2640, @@ -235,9 +219,9 @@ static struct v4l2_pix_format mi2020_mode[] = { .colorspace = V4L2_COLORSPACE_SRGB, .priv = 0 }, - { 800, 600, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, + { 800, 598, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, .bytesperline = 800, - .sizeimage = 800 * 600, + .sizeimage = 800 * 598, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 1 }, @@ -247,9 +231,9 @@ static struct v4l2_pix_format mi2020_mode[] = { .colorspace = V4L2_COLORSPACE_SRGB, .priv = 2 }, - {1600, 1200, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, + {1600, 1198, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, .bytesperline = 1600, - .sizeimage = 1600 * 1200, + .sizeimage = 1600 * 1198, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 3 }, @@ -344,8 +328,6 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->sensor = ID_OV9655; else if (strcmp(sensor, "MI2020") == 0) sd->sensor = ID_MI2020; - else if (strcmp(sensor, "MI2020b") == 0) - sd->sensor = ID_MI2020b; /* Get sensor and set the suitable init/start/../stop functions */ if (gl860_guess_sensor(gspca_dev, vendor_id, product_id) == -1) @@ -369,13 +351,6 @@ static int sd_config(struct gspca_dev *gspca_dev, dev_init_settings = mi2020_init_settings; break; - case ID_MI2020b: - gspca_dev->sd_desc = &sd_desc_mi2020b; - cam->cam_mode = mi2020_mode; - cam->nmodes = ARRAY_SIZE(mi2020_mode); - dev_init_settings = mi2020_init_settings; - break; - case ID_OV2640: gspca_dev->sd_desc = &sd_desc_ov2640; cam->cam_mode = ov2640_mode; @@ -620,10 +595,7 @@ int gl860_RTx(struct gspca_dev *gspca_dev, else if (len > 1 && r < len) PDEBUG(D_ERR, "short ctrl transfer %d/%d", r, len); - if ((_MI2020_ || _MI2020b_ || _MI2020c_) && (val || index)) - msleep(1); - if (_OV2640_) - msleep(1); + msleep(1); return r; } @@ -767,8 +739,6 @@ static int gl860_guess_sensor(struct gspca_dev *gspca_dev, PDEBUG(D_PROBE, "05e3:f191 sensor MI1320 (1.3M)"); } else if (_MI2020_) { PDEBUG(D_PROBE, "05e3:0503 sensor MI2020 (2.0M)"); - } else if (_MI2020b_) { - PDEBUG(D_PROBE, "05e3:0503 sensor MI2020 alt. driver (2.0M)"); } else if (_OV9655_) { PDEBUG(D_PROBE, "05e3:0503 sensor OV9655 (1.3M)"); } else if (_OV2640_) { diff --git a/drivers/media/video/gspca/gl860/gl860.h b/drivers/media/video/gspca/gl860/gl860.h index 305061ff838..49ad4acbf60 100644 --- a/drivers/media/video/gspca/gl860/gl860.h +++ b/drivers/media/video/gspca/gl860/gl860.h @@ -32,19 +32,16 @@ #define ID_OV2640 2 #define ID_OV9655 4 #define ID_MI2020 8 -#define ID_MI2020b 16 #define _MI1320_ (((struct sd *) gspca_dev)->sensor == ID_MI1320) #define _MI2020_ (((struct sd *) gspca_dev)->sensor == ID_MI2020) -#define _MI2020b_ (((struct sd *) gspca_dev)->sensor == ID_MI2020b) -#define _MI2020c_ 0 #define _OV2640_ (((struct sd *) gspca_dev)->sensor == ID_OV2640) #define _OV9655_ (((struct sd *) gspca_dev)->sensor == ID_OV9655) #define IMAGE_640 0 #define IMAGE_800 1 #define IMAGE_1280 2 -#define IMAGE_1600 3 +#define IMAGE_1600 3 struct sd_gl860 { u16 backlight; @@ -75,10 +72,10 @@ struct sd { int (*dev_camera_settings)(struct gspca_dev *); u8 swapRB; - u8 mirrorMask; - u8 sensor; - s32 nbIm; - s32 nbRightUp; + u8 mirrorMask; + u8 sensor; + s32 nbIm; + s32 nbRightUp; u8 waitSet; }; diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index 678675bb365..d951b0f0e05 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -201,7 +201,7 @@ static int alloc_and_submit_int_urb(struct gspca_dev *gspca_dev, buffer_len = le16_to_cpu(ep->wMaxPacketSize); interval = ep->bInterval; - PDEBUG(D_PROBE, "found int in endpoint: 0x%x, " + PDEBUG(D_CONF, "found int in endpoint: 0x%x, " "buffer_len=%u, interval=%u", ep->bEndpointAddress, buffer_len, interval); @@ -226,7 +226,7 @@ static int alloc_and_submit_int_urb(struct gspca_dev *gspca_dev, gspca_dev->int_urb = urb; ret = usb_submit_urb(urb, GFP_KERNEL); if (ret < 0) { - PDEBUG(D_ERR, "submit URB failed with error %i", ret); + PDEBUG(D_ERR, "submit int URB failed with error %i", ret); goto error_submit; } return ret; @@ -294,19 +294,6 @@ static inline int gspca_input_connect(struct gspca_dev *dev) } #endif -/* get the current input frame buffer */ -struct gspca_frame *gspca_get_i_frame(struct gspca_dev *gspca_dev) -{ - struct gspca_frame *frame; - - frame = gspca_dev->cur_frame; - if ((frame->v4l2_buf.flags & BUF_ALL_FLAGS) - != V4L2_BUF_FLAG_QUEUED) - return NULL; - return frame; -} -EXPORT_SYMBOL(gspca_get_i_frame); - /* * fill a video frame from an URB and resubmit */ @@ -439,20 +426,20 @@ void gspca_frame_add(struct gspca_dev *gspca_dev, PDEBUG(D_PACK, "add t:%d l:%d", packet_type, len); - /* check the availability of the frame buffer */ - frame = gspca_dev->cur_frame; - if ((frame->v4l2_buf.flags & BUF_ALL_FLAGS) - != V4L2_BUF_FLAG_QUEUED) { - gspca_dev->last_packet_type = DISCARD_PACKET; - return; - } - - /* when start of a new frame, if the current frame buffer - * is not queued, discard the whole frame */ if (packet_type == FIRST_PACKET) { - frame->data_end = frame->data; + i = atomic_read(&gspca_dev->fr_i); + + /* if there are no queued buffer, discard the whole frame */ + if (i == atomic_read(&gspca_dev->fr_q)) { + gspca_dev->last_packet_type = DISCARD_PACKET; + return; + } + j = gspca_dev->fr_queue[i]; + frame = &gspca_dev->frame[j]; frame->v4l2_buf.timestamp = ktime_to_timeval(ktime_get()); frame->v4l2_buf.sequence = ++gspca_dev->sequence; + gspca_dev->image = frame->data; + gspca_dev->image_len = 0; } else if (gspca_dev->last_packet_type == DISCARD_PACKET) { if (packet_type == LAST_PACKET) gspca_dev->last_packet_type = packet_type; @@ -461,34 +448,37 @@ void gspca_frame_add(struct gspca_dev *gspca_dev, /* append the packet to the frame buffer */ if (len > 0) { - if (frame->data_end - frame->data + len - > frame->v4l2_buf.length) { - PDEBUG(D_ERR|D_PACK, "frame overflow %zd > %d", - frame->data_end - frame->data + len, - frame->v4l2_buf.length); + if (gspca_dev->image_len + len > gspca_dev->frsz) { + PDEBUG(D_ERR|D_PACK, "frame overflow %d > %d", + gspca_dev->image_len + len, + gspca_dev->frsz); packet_type = DISCARD_PACKET; } else { - memcpy(frame->data_end, data, len); - frame->data_end += len; + memcpy(gspca_dev->image + gspca_dev->image_len, + data, len); + gspca_dev->image_len += len; } } gspca_dev->last_packet_type = packet_type; - /* if last packet, wake up the application and advance in the queue */ + /* if last packet, invalidate packet concatenation until + * next first packet, wake up the application and advance + * in the queue */ if (packet_type == LAST_PACKET) { - frame->v4l2_buf.bytesused = frame->data_end - frame->data; - frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_QUEUED; - frame->v4l2_buf.flags |= V4L2_BUF_FLAG_DONE; - wake_up_interruptible(&gspca_dev->wq); /* event = new frame */ - i = (gspca_dev->fr_i + 1) % gspca_dev->nframes; - gspca_dev->fr_i = i; - PDEBUG(D_FRAM, "frame complete len:%d q:%d i:%d o:%d", - frame->v4l2_buf.bytesused, - gspca_dev->fr_q, - i, - gspca_dev->fr_o); + i = atomic_read(&gspca_dev->fr_i); j = gspca_dev->fr_queue[i]; - gspca_dev->cur_frame = &gspca_dev->frame[j]; + frame = &gspca_dev->frame[j]; + frame->v4l2_buf.bytesused = gspca_dev->image_len; + frame->v4l2_buf.flags = (frame->v4l2_buf.flags + | V4L2_BUF_FLAG_DONE) + & ~V4L2_BUF_FLAG_QUEUED; + i = (i + 1) % GSPCA_MAX_FRAMES; + atomic_set(&gspca_dev->fr_i, i); + wake_up_interruptible(&gspca_dev->wq); /* event = new frame */ + PDEBUG(D_FRAM, "frame complete len:%d", + frame->v4l2_buf.bytesused); + gspca_dev->image = NULL; + gspca_dev->image_len = 0; } } EXPORT_SYMBOL(gspca_frame_add); @@ -506,36 +496,6 @@ static int gspca_is_compressed(__u32 format) return 0; } -static void *rvmalloc(long size) -{ - void *mem; - unsigned long adr; - - mem = vmalloc_32(size); - if (mem != NULL) { - adr = (unsigned long) mem; - while (size > 0) { - SetPageReserved(vmalloc_to_page((void *) adr)); - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - } - return mem; -} - -static void rvfree(void *mem, long size) -{ - unsigned long adr; - - adr = (unsigned long) mem; - while (size > 0) { - ClearPageReserved(vmalloc_to_page((void *) adr)); - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - vfree(mem); -} - static int frame_alloc(struct gspca_dev *gspca_dev, unsigned int count) { @@ -548,9 +508,9 @@ static int frame_alloc(struct gspca_dev *gspca_dev, PDEBUG(D_STREAM, "frame alloc frsz: %d", frsz); frsz = PAGE_ALIGN(frsz); gspca_dev->frsz = frsz; - if (count > GSPCA_MAX_FRAMES) - count = GSPCA_MAX_FRAMES; - gspca_dev->frbuf = rvmalloc(frsz * count); + if (count >= GSPCA_MAX_FRAMES) + count = GSPCA_MAX_FRAMES - 1; + gspca_dev->frbuf = vmalloc_32(frsz * count); if (!gspca_dev->frbuf) { err("frame alloc failed"); return -ENOMEM; @@ -565,14 +525,12 @@ static int frame_alloc(struct gspca_dev *gspca_dev, frame->v4l2_buf.length = frsz; frame->v4l2_buf.memory = gspca_dev->memory; frame->v4l2_buf.sequence = 0; - frame->data = frame->data_end = - gspca_dev->frbuf + i * frsz; + frame->data = gspca_dev->frbuf + i * frsz; frame->v4l2_buf.m.offset = i * frsz; } - gspca_dev->fr_i = gspca_dev->fr_o = gspca_dev->fr_q = 0; - gspca_dev->cur_frame = &gspca_dev->frame[0]; - gspca_dev->last_packet_type = DISCARD_PACKET; - gspca_dev->sequence = 0; + atomic_set(&gspca_dev->fr_q, 0); + atomic_set(&gspca_dev->fr_i, 0); + gspca_dev->fr_o = 0; return 0; } @@ -582,8 +540,7 @@ static void frame_free(struct gspca_dev *gspca_dev) PDEBUG(D_STREAM, "frame free"); if (gspca_dev->frbuf != NULL) { - rvfree(gspca_dev->frbuf, - gspca_dev->nframes * gspca_dev->frsz); + vfree(gspca_dev->frbuf); gspca_dev->frbuf = NULL; for (i = 0; i < gspca_dev->nframes; i++) gspca_dev->frame[i].data = NULL; @@ -683,12 +640,16 @@ static struct usb_host_endpoint *get_ep(struct gspca_dev *gspca_dev) : USB_ENDPOINT_XFER_ISOC; i = gspca_dev->alt; /* previous alt setting */ if (gspca_dev->cam.reverse_alts) { + if (gspca_dev->audio) + i++; while (++i < gspca_dev->nbalt) { ep = alt_xfer(&intf->altsetting[i], xfer); if (ep) break; } } else { + if (gspca_dev->audio) + i--; while (--i >= 0) { ep = alt_xfer(&intf->altsetting[i], xfer); if (ep) @@ -811,6 +772,12 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) goto out; } + /* reset the streaming variables */ + gspca_dev->image = NULL; + gspca_dev->image_len = 0; + gspca_dev->last_packet_type = DISCARD_PACKET; + gspca_dev->sequence = 0; + gspca_dev->usb_err = 0; /* set the higher alternate setting and @@ -1433,34 +1400,6 @@ static int vidioc_g_ctrl(struct file *file, void *priv, return ret; } -/*fixme: have an audio flag in gspca_dev?*/ -static int vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *audio) -{ - if (audio->index != 0) - return -EINVAL; - return 0; -} - -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *audio) -{ - strcpy(audio->name, "Microphone"); - return 0; -} - -static int vidioc_enumaudio(struct file *file, void *priv, - struct v4l2_audio *audio) -{ - if (audio->index != 0) - return -EINVAL; - - strcpy(audio->name, "Microphone"); - audio->capability = 0; - audio->mode = 0; - return 0; -} - static int vidioc_querymenu(struct file *file, void *priv, struct v4l2_querymenu *qmenu) { @@ -1504,7 +1443,8 @@ static int vidioc_reqbufs(struct file *file, void *priv, struct gspca_dev *gspca_dev = priv; int i, ret = 0, streaming; - switch (rb->memory) { + i = rb->memory; /* (avoid compilation warning) */ + switch (i) { case GSPCA_MEMORY_READ: /* (internal call) */ case V4L2_MEMORY_MMAP: case V4L2_MEMORY_USERPTR: @@ -1626,7 +1566,7 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type buf_type) { struct gspca_dev *gspca_dev = priv; - int i, ret; + int ret; if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -1650,12 +1590,10 @@ static int vidioc_streamoff(struct file *file, void *priv, gspca_stream_off(gspca_dev); mutex_unlock(&gspca_dev->usb_lock); - /* empty the application queues */ - for (i = 0; i < gspca_dev->nframes; i++) - gspca_dev->frame[i].v4l2_buf.flags &= ~BUF_ALL_FLAGS; - gspca_dev->fr_i = gspca_dev->fr_o = gspca_dev->fr_q = 0; - gspca_dev->last_packet_type = DISCARD_PACKET; - gspca_dev->sequence = 0; + /* empty the transfer queues */ + atomic_set(&gspca_dev->fr_q, 0); + atomic_set(&gspca_dev->fr_i, 0); + gspca_dev->fr_o = 0; ret = 0; out: mutex_unlock(&gspca_dev->queue_lock); @@ -1732,7 +1670,7 @@ static int vidioc_s_parm(struct file *filp, void *priv, int n; n = parm->parm.capture.readbuffers; - if (n == 0 || n > GSPCA_MAX_FRAMES) + if (n == 0 || n >= GSPCA_MAX_FRAMES) parm->parm.capture.readbuffers = gspca_dev->nbufread; else gspca_dev->nbufread = n; @@ -1755,49 +1693,6 @@ static int vidioc_s_parm(struct file *filp, void *priv, return 0; } -#ifdef CONFIG_VIDEO_V4L1_COMPAT -static int vidiocgmbuf(struct file *file, void *priv, - struct video_mbuf *mbuf) -{ - struct gspca_dev *gspca_dev = file->private_data; - int i; - - PDEBUG(D_STREAM, "cgmbuf"); - if (gspca_dev->nframes == 0) { - int ret; - - { - struct v4l2_format fmt; - - fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - i = gspca_dev->cam.nmodes - 1; /* highest mode */ - fmt.fmt.pix.width = gspca_dev->cam.cam_mode[i].width; - fmt.fmt.pix.height = gspca_dev->cam.cam_mode[i].height; - fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_BGR24; - ret = vidioc_s_fmt_vid_cap(file, priv, &fmt); - if (ret != 0) - return ret; - } - { - struct v4l2_requestbuffers rb; - - memset(&rb, 0, sizeof rb); - rb.count = 4; - rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - rb.memory = V4L2_MEMORY_MMAP; - ret = vidioc_reqbufs(file, priv, &rb); - if (ret != 0) - return ret; - } - } - mbuf->frames = gspca_dev->nframes; - mbuf->size = gspca_dev->frsz * gspca_dev->nframes; - for (i = 0; i < mbuf->frames; i++) - mbuf->offsets[i] = gspca_dev->frame[i].v4l2_buf.m.offset; - return 0; -} -#endif - static int dev_mmap(struct file *file, struct vm_area_struct *vma) { struct gspca_dev *gspca_dev = file->private_data; @@ -1838,12 +1733,7 @@ static int dev_mmap(struct file *file, struct vm_area_struct *vma) ret = -EINVAL; goto out; } -#ifdef CONFIG_VIDEO_V4L1_COMPAT - /* v4l1 maps all the buffers */ - if (i != 0 - || size != frame->v4l2_buf.length * gspca_dev->nframes) -#endif - if (size != frame->v4l2_buf.length) { + if (size != frame->v4l2_buf.length) { PDEBUG(D_STREAM, "mmap bad size"); ret = -EINVAL; goto out; @@ -1883,21 +1773,17 @@ out: static int frame_wait(struct gspca_dev *gspca_dev, int nonblock_ing) { - struct gspca_frame *frame; - int i, j, ret; + int i, ret; /* check if a frame is ready */ i = gspca_dev->fr_o; - j = gspca_dev->fr_queue[i]; - frame = &gspca_dev->frame[j]; - - if (!(frame->v4l2_buf.flags & V4L2_BUF_FLAG_DONE)) { + if (i == atomic_read(&gspca_dev->fr_i)) { if (nonblock_ing) return -EAGAIN; /* wait till a frame is ready */ ret = wait_event_interruptible_timeout(gspca_dev->wq, - (frame->v4l2_buf.flags & V4L2_BUF_FLAG_DONE) || + i != atomic_read(&gspca_dev->fr_i) || !gspca_dev->streaming || !gspca_dev->present, msecs_to_jiffies(3000)); if (ret < 0) @@ -1906,11 +1792,7 @@ static int frame_wait(struct gspca_dev *gspca_dev, return -EIO; } - gspca_dev->fr_o = (i + 1) % gspca_dev->nframes; - PDEBUG(D_FRAM, "frame wait q:%d i:%d o:%d", - gspca_dev->fr_q, - gspca_dev->fr_i, - gspca_dev->fr_o); + gspca_dev->fr_o = (i + 1) % GSPCA_MAX_FRAMES; if (gspca_dev->sd_desc->dq_callback) { mutex_lock(&gspca_dev->usb_lock); @@ -1919,7 +1801,7 @@ static int frame_wait(struct gspca_dev *gspca_dev, gspca_dev->sd_desc->dq_callback(gspca_dev); mutex_unlock(&gspca_dev->usb_lock); } - return j; + return gspca_dev->fr_queue[i]; } /* @@ -2024,15 +1906,9 @@ static int vidioc_qbuf(struct file *file, void *priv, } /* put the buffer in the 'queued' queue */ - i = gspca_dev->fr_q; + i = atomic_read(&gspca_dev->fr_q); gspca_dev->fr_queue[i] = index; - if (gspca_dev->fr_i == i) - gspca_dev->cur_frame = frame; - gspca_dev->fr_q = (i + 1) % gspca_dev->nframes; - PDEBUG(D_FRAM, "qbuf q:%d i:%d o:%d", - gspca_dev->fr_q, - gspca_dev->fr_i, - gspca_dev->fr_o); + atomic_set(&gspca_dev->fr_q, (i + 1) % GSPCA_MAX_FRAMES); v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED; v4l2_buf->flags &= ~V4L2_BUF_FLAG_DONE; @@ -2088,7 +1964,7 @@ static int read_alloc(struct gspca_dev *gspca_dev, static unsigned int dev_poll(struct file *file, poll_table *wait) { struct gspca_dev *gspca_dev = file->private_data; - int i, ret; + int ret; PDEBUG(D_FRAM, "poll"); @@ -2106,11 +1982,9 @@ static unsigned int dev_poll(struct file *file, poll_table *wait) if (mutex_lock_interruptible(&gspca_dev->queue_lock) != 0) return POLLERR; - /* check the next incoming buffer */ - i = gspca_dev->fr_o; - i = gspca_dev->fr_queue[i]; - if (gspca_dev->frame[i].v4l2_buf.flags & V4L2_BUF_FLAG_DONE) - ret = POLLIN | POLLRDNORM; /* something to read */ + /* check if an image has been received */ + if (gspca_dev->fr_o != atomic_read(&gspca_dev->fr_i)) + ret = POLLIN | POLLRDNORM; /* yes */ else ret = 0; mutex_unlock(&gspca_dev->queue_lock); @@ -2214,9 +2088,6 @@ static const struct v4l2_ioctl_ops dev_ioctl_ops = { .vidioc_queryctrl = vidioc_queryctrl, .vidioc_g_ctrl = vidioc_g_ctrl, .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_enumaudio = vidioc_enumaudio, .vidioc_querymenu = vidioc_querymenu, .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, @@ -2235,9 +2106,6 @@ static const struct v4l2_ioctl_ops dev_ioctl_ops = { .vidioc_s_register = vidioc_s_register, #endif .vidioc_g_chip_ident = vidioc_g_chip_ident, -#ifdef CONFIG_VIDEO_V4L1_COMPAT - .vidiocgmbuf = vidiocgmbuf, -#endif }; static struct video_device gspca_template = { @@ -2253,31 +2121,18 @@ static struct video_device gspca_template = { * This function must be called by the sub-driver when it is * called for probing a new device. */ -int gspca_dev_probe(struct usb_interface *intf, +int gspca_dev_probe2(struct usb_interface *intf, const struct usb_device_id *id, const struct sd_desc *sd_desc, int dev_size, struct module *module) { - struct usb_interface_descriptor *interface; struct gspca_dev *gspca_dev; struct usb_device *dev = interface_to_usbdev(intf); int ret; PDEBUG(D_PROBE, "probing %04x:%04x", id->idVendor, id->idProduct); - /* we don't handle multi-config cameras */ - if (dev->descriptor.bNumConfigurations != 1) { - PDEBUG(D_ERR, "Too many config"); - return -ENODEV; - } - - /* the USB video interface must be the first one */ - interface = &intf->cur_altsetting->desc; - if (dev->config->desc.bNumInterfaces != 1 && - interface->bInterfaceNumber != 0) - return -ENODEV; - /* create the device */ if (dev_size < sizeof *gspca_dev) dev_size = sizeof *gspca_dev; @@ -2293,8 +2148,26 @@ int gspca_dev_probe(struct usb_interface *intf, goto out; } gspca_dev->dev = dev; - gspca_dev->iface = interface->bInterfaceNumber; + gspca_dev->iface = intf->cur_altsetting->desc.bInterfaceNumber; gspca_dev->nbalt = intf->num_altsetting; + + /* check if any audio device */ + if (dev->config->desc.bNumInterfaces != 1) { + int i; + struct usb_interface *intf2; + + for (i = 0; i < dev->config->desc.bNumInterfaces; i++) { + intf2 = dev->config->interface[i]; + if (intf2 != NULL + && intf2->altsetting != NULL + && intf2->altsetting->desc.bInterfaceClass == + USB_CLASS_AUDIO) { + gspca_dev->audio = 1; + break; + } + } + } + gspca_dev->sd_desc = sd_desc; gspca_dev->nbufread = 2; gspca_dev->empty_packet = -1; /* don't check the empty packets */ @@ -2345,6 +2218,31 @@ out: kfree(gspca_dev); return ret; } +EXPORT_SYMBOL(gspca_dev_probe2); + +/* same function as the previous one, but check the interface */ +int gspca_dev_probe(struct usb_interface *intf, + const struct usb_device_id *id, + const struct sd_desc *sd_desc, + int dev_size, + struct module *module) +{ + struct usb_device *dev = interface_to_usbdev(intf); + + /* we don't handle multi-config cameras */ + if (dev->descriptor.bNumConfigurations != 1) { + PDEBUG(D_ERR, "%04x:%04x too many config", + id->idVendor, id->idProduct); + return -ENODEV; + } + + /* the USB video interface must be the first one */ + if (dev->config->desc.bNumInterfaces != 1 + && intf->cur_altsetting->desc.bInterfaceNumber != 0) + return -ENODEV; + + return gspca_dev_probe2(intf, id, sd_desc, dev_size, module); +} EXPORT_SYMBOL(gspca_dev_probe); /* diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h index 8b963dfae86..b749c36d9f7 100644 --- a/drivers/media/video/gspca/gspca.h +++ b/drivers/media/video/gspca/gspca.h @@ -7,7 +7,6 @@ #include <linux/videodev2.h> #include <media/v4l2-common.h> #include <linux/mutex.h> -#include <linux/slab.h> /* compilation option */ #define GSPCA_DEBUG 1 @@ -148,7 +147,6 @@ enum gspca_packet_type { struct gspca_frame { __u8 *data; /* frame buffer */ - __u8 *data_end; /* end of frame while filling */ int vma_use_count; struct v4l2_buffer v4l2_buf; }; @@ -177,13 +175,14 @@ struct gspca_dev { __u8 *frbuf; /* buffer for nframes */ struct gspca_frame frame[GSPCA_MAX_FRAMES]; - struct gspca_frame *cur_frame; /* frame beeing filled */ + u8 *image; /* image beeing filled */ __u32 frsz; /* frame size */ - char nframes; /* number of frames */ - char fr_i; /* frame being filled */ - char fr_q; /* next frame to queue */ - char fr_o; /* next frame to dequeue */ + u32 image_len; /* current length of image */ + atomic_t fr_q; /* next frame to queue */ + atomic_t fr_i; /* frame being filled */ signed char fr_queue[GSPCA_MAX_FRAMES]; /* frame queue */ + char nframes; /* number of frames */ + u8 fr_o; /* next frame to dequeue */ __u8 last_packet_type; __s8 empty_packet; /* if (-1) don't check empty packets */ __u8 streaming; @@ -199,6 +198,7 @@ struct gspca_dev { struct mutex read_lock; /* read protection */ struct mutex queue_lock; /* ISOC queue protection */ int usb_err; /* USB error - protected by usb_lock */ + u16 pkt_size; /* ISOC packet size */ #ifdef CONFIG_PM char frozen; /* suspend - resume */ #endif @@ -209,7 +209,7 @@ struct gspca_dev { __u8 iface; /* USB interface number */ __u8 alt; /* USB alternate setting */ __u8 nbalt; /* number of USB alternate settings */ - u16 pkt_size; /* ISOC packet size */ + u8 audio; /* presence of audio device */ }; int gspca_dev_probe(struct usb_interface *intf, @@ -217,12 +217,16 @@ int gspca_dev_probe(struct usb_interface *intf, const struct sd_desc *sd_desc, int dev_size, struct module *module); +int gspca_dev_probe2(struct usb_interface *intf, + const struct usb_device_id *id, + const struct sd_desc *sd_desc, + int dev_size, + struct module *module); void gspca_disconnect(struct usb_interface *intf); void gspca_frame_add(struct gspca_dev *gspca_dev, enum gspca_packet_type packet_type, const u8 *data, int len); -struct gspca_frame *gspca_get_i_frame(struct gspca_dev *gspca_dev); #ifdef CONFIG_PM int gspca_suspend(struct usb_interface *intf, pm_message_t message); int gspca_resume(struct usb_interface *intf); diff --git a/drivers/media/video/gspca/jeilinj.c b/drivers/media/video/gspca/jeilinj.c index 84ecd56c647..12d9cf4caba 100644 --- a/drivers/media/video/gspca/jeilinj.c +++ b/drivers/media/video/gspca/jeilinj.c @@ -50,7 +50,7 @@ struct sd { struct workqueue_struct *work_thread; u8 quality; /* image quality */ u8 jpegqual; /* webcam quality */ - u8 *jpeg_hdr; + u8 jpeg_hdr[JPEG_HDR_SZ]; }; struct jlj_command { @@ -282,7 +282,6 @@ static void sd_stop0(struct gspca_dev *gspca_dev) destroy_workqueue(dev->work_thread); dev->work_thread = NULL; mutex_lock(&gspca_dev->usb_lock); - kfree(dev->jpeg_hdr); } /* this function is called at probe and resume time */ @@ -298,9 +297,6 @@ static int sd_start(struct gspca_dev *gspca_dev) int ret; /* create the JPEG header */ - dev->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL); - if (dev->jpeg_hdr == NULL) - return -ENOMEM; jpeg_define(dev->jpeg_hdr, gspca_dev->height, gspca_dev->width, 0x21); /* JPEG 422 */ jpeg_set_qual(dev->jpeg_hdr, dev->quality); diff --git a/drivers/media/video/gspca/m5602/m5602_bridge.h b/drivers/media/video/gspca/m5602/m5602_bridge.h index 1127a405c9b..51af3ee3ab8 100644 --- a/drivers/media/video/gspca/m5602/m5602_bridge.h +++ b/drivers/media/video/gspca/m5602/m5602_bridge.h @@ -19,6 +19,7 @@ #ifndef M5602_BRIDGE_H_ #define M5602_BRIDGE_H_ +#include <linux/slab.h> #include "gspca.h" #define MODULE_NAME "ALi m5602" diff --git a/drivers/media/video/gspca/m5602/m5602_core.c b/drivers/media/video/gspca/m5602/m5602_core.c index 4294c75e3b1..b073d66acd0 100644 --- a/drivers/media/video/gspca/m5602/m5602_core.c +++ b/drivers/media/video/gspca/m5602/m5602_core.c @@ -305,30 +305,23 @@ static void m5602_urb_complete(struct gspca_dev *gspca_dev, sd->frame_count); } else { - struct gspca_frame *frame; int cur_frame_len; - frame = gspca_get_i_frame(gspca_dev); - if (frame == NULL) { - gspca_dev->last_packet_type = DISCARD_PACKET; - return; - } - - cur_frame_len = frame->data_end - frame->data; + cur_frame_len = gspca_dev->image_len; /* Remove urb header */ data += 4; len -= 4; - if (cur_frame_len + len <= frame->v4l2_buf.length) { + if (cur_frame_len + len <= gspca_dev->frsz) { PDEBUG(D_FRAM, "Continuing frame %d copying %d bytes", sd->frame_count, len); gspca_frame_add(gspca_dev, INTER_PACKET, data, len); - } else if (frame->v4l2_buf.length - cur_frame_len > 0) { + } else { /* Add the remaining data up to frame size */ gspca_frame_add(gspca_dev, INTER_PACKET, data, - frame->v4l2_buf.length - cur_frame_len); + gspca_dev->frsz - cur_frame_len); } } } diff --git a/drivers/media/video/gspca/m5602/m5602_s5k83a.c b/drivers/media/video/gspca/m5602/m5602_s5k83a.c index 6b3be4fa2c0..fbd91545497 100644 --- a/drivers/media/video/gspca/m5602/m5602_s5k83a.c +++ b/drivers/media/video/gspca/m5602/m5602_s5k83a.c @@ -17,7 +17,6 @@ */ #include <linux/kthread.h> -#include <linux/slab.h> #include "m5602_s5k83a.h" static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val); diff --git a/drivers/media/video/gspca/mars.c b/drivers/media/video/gspca/mars.c index 3d9229e22b2..031f7195ce0 100644 --- a/drivers/media/video/gspca/mars.c +++ b/drivers/media/video/gspca/mars.c @@ -41,7 +41,7 @@ struct sd { #define QUALITY_MAX 70 #define QUALITY_DEF 50 - u8 *jpeg_hdr; + u8 jpeg_hdr[JPEG_HDR_SZ]; }; /* V4L2 controls supported by the driver */ @@ -200,9 +200,6 @@ static int sd_start(struct gspca_dev *gspca_dev) int i; /* create the JPEG header */ - sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL); - if (!sd->jpeg_hdr) - return -ENOMEM; jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, 0x21); /* JPEG 422 */ jpeg_set_qual(sd->jpeg_hdr, sd->quality); @@ -317,13 +314,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev) PDEBUG(D_ERR, "Camera Stop failed"); } -static void sd_stop0(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - kfree(sd->jpeg_hdr); -} - static void sd_pkt_scan(struct gspca_dev *gspca_dev, u8 *data, /* isoc packet */ int len) /* iso packet length */ @@ -486,7 +476,6 @@ static const struct sd_desc sd_desc = { .init = sd_init, .start = sd_start, .stopN = sd_stopN, - .stop0 = sd_stop0, .pkt_scan = sd_pkt_scan, .get_jcomp = sd_get_jcomp, .set_jcomp = sd_set_jcomp, diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c index f36e11a0458..2b2cbdbf03f 100644 --- a/drivers/media/video/gspca/ov519.c +++ b/drivers/media/video/gspca/ov519.c @@ -41,6 +41,11 @@ #include <linux/input.h> #include "gspca.h" +/* The jpeg_hdr is used by w996Xcf only */ +/* The CONEX_CAM define for jpeg.h needs renaming, now its used here too */ +#define CONEX_CAM +#include "jpeg.h" + MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>"); MODULE_DESCRIPTION("OV519 USB Camera Driver"); MODULE_LICENSE("GPL"); @@ -90,6 +95,7 @@ struct sd { #define QUALITY_DEF 50 __u8 stopped; /* Streaming is temporarily paused */ + __u8 first_frame; __u8 frame_rate; /* current Framerate */ __u8 clockdiv; /* clockdiv override */ @@ -115,7 +121,7 @@ struct sd { int sensor_height; int sensor_reg_cache[256]; - u8 *jpeg_hdr; + u8 jpeg_hdr[JPEG_HDR_SZ]; }; /* Note this is a bit of a hack, but the w9968cf driver needs the code for all @@ -3147,7 +3153,7 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->autobrightness = AUTOBRIGHT_DEF; if (sd->sensor == SEN_OV7670) { sd->freq = OV7670_FREQ_DEF; - gspca_dev->ctrl_dis = 1 << FREQ_IDX; + gspca_dev->ctrl_dis = (1 << FREQ_IDX) | (1 << COLOR_IDX); } else { sd->freq = FREQ_DEF; gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX) | @@ -3961,6 +3967,8 @@ static int sd_start(struct gspca_dev *gspca_dev) sd_reset_snapshot(gspca_dev); sd->snapshot_pressed = 0; + sd->first_frame = 3; + ret = ov51x_restart(sd); if (ret < 0) goto out; @@ -4153,13 +4161,23 @@ static void ovfx2_pkt_scan(struct gspca_dev *gspca_dev, u8 *data, /* isoc packet */ int len) /* iso packet length */ { + struct sd *sd = (struct sd *) gspca_dev; + + gspca_frame_add(gspca_dev, INTER_PACKET, data, len); + /* A short read signals EOF */ if (len < OVFX2_BULK_SIZE) { - gspca_frame_add(gspca_dev, LAST_PACKET, data, len); + /* If the frame is short, and it is one of the first ones + the sensor and bridge are still syncing, so drop it. */ + if (sd->first_frame) { + sd->first_frame--; + if (gspca_dev->image_len < + sd->gspca_dev.width * sd->gspca_dev.height) + gspca_dev->last_packet_type = DISCARD_PACKET; + } + gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0); - return; } - gspca_frame_add(gspca_dev, INTER_PACKET, data, len); } static void sd_pkt_scan(struct gspca_dev *gspca_dev, diff --git a/drivers/media/video/gspca/ov534.c b/drivers/media/video/gspca/ov534.c index dc1e4efe30f..96cb3a97658 100644 --- a/drivers/media/video/gspca/ov534.c +++ b/drivers/media/video/gspca/ov534.c @@ -987,13 +987,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, data + 12, len - 12); /* If this packet is marked as EOF, end the frame */ } else if (data[1] & UVC_STREAM_EOF) { - struct gspca_frame *frame; - sd->last_pts = 0; - frame = gspca_get_i_frame(gspca_dev); - if (frame == NULL) - goto discard; - if (frame->data_end - frame->data + (len - 12) != + if (gspca_dev->image_len + len - 12 != gspca_dev->width * gspca_dev->height * 2) { PDEBUG(D_PACK, "wrong sized frame"); goto discard; diff --git a/drivers/media/video/gspca/pac7302.c b/drivers/media/video/gspca/pac7302.c index 2a68220d1ad..a66df07d762 100644 --- a/drivers/media/video/gspca/pac7302.c +++ b/drivers/media/video/gspca/pac7302.c @@ -402,7 +402,7 @@ static void reg_w_buf(struct gspca_dev *gspca_dev, memcpy(gspca_dev->usb_buf, buffer, len); ret = usb_control_msg(gspca_dev->dev, usb_sndctrlpipe(gspca_dev->dev, 0), - 1, /* request */ + 0, /* request */ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, /* value */ index, gspca_dev->usb_buf, len, @@ -804,7 +804,6 @@ static const unsigned char pac_jpeg_header2[] = { }; static void pac_start_frame(struct gspca_dev *gspca_dev, - struct gspca_frame *frame, __u16 lines, __u16 samples_per_line) { unsigned char tmpbuf[4]; @@ -829,19 +828,13 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, int len) /* iso packet length */ { struct sd *sd = (struct sd *) gspca_dev; - struct gspca_frame *frame; + u8 *image; unsigned char *sof; sof = pac_find_sof(&sd->sof_read, data, len); if (sof) { int n, lum_offset, footer_length; - frame = gspca_get_i_frame(gspca_dev); - if (frame == NULL) { - gspca_dev->last_packet_type = DISCARD_PACKET; - return; - } - /* 6 bytes after the FF D9 EOF marker a number of lumination bytes are send corresponding to different parts of the image, the 14th and 15th byte after the EOF seem to @@ -852,16 +845,17 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, /* Finish decoding current frame */ n = (sof - data) - (footer_length + sizeof pac_sof_marker); if (n < 0) { - frame->data_end += n; + gspca_dev->image_len += n; n = 0; + } else { + gspca_frame_add(gspca_dev, INTER_PACKET, data, n); } - gspca_frame_add(gspca_dev, INTER_PACKET, - data, n); - if (gspca_dev->last_packet_type != DISCARD_PACKET && - frame->data_end[-2] == 0xff && - frame->data_end[-1] == 0xd9) - gspca_frame_add(gspca_dev, LAST_PACKET, - NULL, 0); + + image = gspca_dev->image; + if (image != NULL + && image[gspca_dev->image_len - 2] == 0xff + && image[gspca_dev->image_len - 1] == 0xd9) + gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); n = sof - data; len -= n; @@ -877,7 +871,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, /* Start the new frame with the jpeg header */ /* The PAC7302 has the image rotated 90 degrees */ - pac_start_frame(gspca_dev, frame, + pac_start_frame(gspca_dev, gspca_dev->width, gspca_dev->height); } gspca_frame_add(gspca_dev, INTER_PACKET, data, len); @@ -1200,6 +1194,7 @@ static const struct usb_device_id device_table[] __devinitconst = { {USB_DEVICE(0x093a, 0x2621)}, {USB_DEVICE(0x093a, 0x2622), .driver_info = FL_VFLIP}, {USB_DEVICE(0x093a, 0x2624), .driver_info = FL_VFLIP}, + {USB_DEVICE(0x093a, 0x2625)}, {USB_DEVICE(0x093a, 0x2626)}, {USB_DEVICE(0x093a, 0x2628)}, {USB_DEVICE(0x093a, 0x2629), .driver_info = FL_VFLIP}, diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c index 44fed968672..1cb7e99e92b 100644 --- a/drivers/media/video/gspca/pac7311.c +++ b/drivers/media/video/gspca/pac7311.c @@ -270,7 +270,7 @@ static void reg_w_buf(struct gspca_dev *gspca_dev, memcpy(gspca_dev->usb_buf, buffer, len); ret = usb_control_msg(gspca_dev->dev, usb_sndctrlpipe(gspca_dev->dev, 0), - 1, /* request */ + 0, /* request */ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, /* value */ index, gspca_dev->usb_buf, len, @@ -599,7 +599,6 @@ static const unsigned char pac_jpeg_header2[] = { }; static void pac_start_frame(struct gspca_dev *gspca_dev, - struct gspca_frame *frame, __u16 lines, __u16 samples_per_line) { unsigned char tmpbuf[4]; @@ -624,19 +623,13 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, int len) /* iso packet length */ { struct sd *sd = (struct sd *) gspca_dev; + u8 *image; unsigned char *sof; - struct gspca_frame *frame; sof = pac_find_sof(&sd->sof_read, data, len); if (sof) { int n, lum_offset, footer_length; - frame = gspca_get_i_frame(gspca_dev); - if (frame == NULL) { - gspca_dev->last_packet_type = DISCARD_PACKET; - return; - } - /* 6 bytes after the FF D9 EOF marker a number of lumination bytes are send corresponding to different parts of the image, the 14th and 15th byte after the EOF seem to @@ -647,16 +640,16 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, /* Finish decoding current frame */ n = (sof - data) - (footer_length + sizeof pac_sof_marker); if (n < 0) { - frame->data_end += n; + gspca_dev->image_len += n; n = 0; + } else { + gspca_frame_add(gspca_dev, INTER_PACKET, data, n); } - gspca_frame_add(gspca_dev, INTER_PACKET, - data, n); - if (gspca_dev->last_packet_type != DISCARD_PACKET && - frame->data_end[-2] == 0xff && - frame->data_end[-1] == 0xd9) - gspca_frame_add(gspca_dev, LAST_PACKET, - NULL, 0); + image = gspca_dev->image; + if (image != NULL + && image[gspca_dev->image_len - 2] == 0xff + && image[gspca_dev->image_len - 1] == 0xd9) + gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); n = sof - data; len -= n; @@ -671,7 +664,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, atomic_set(&sd->avg_lum, -1); /* Start the new frame with the jpeg header */ - pac_start_frame(gspca_dev, frame, + pac_start_frame(gspca_dev, gspca_dev->height, gspca_dev->width); } gspca_frame_add(gspca_dev, INTER_PACKET, data, len); diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c index 644a7fd4701..83a718f0f3f 100644 --- a/drivers/media/video/gspca/sn9c20x.c +++ b/drivers/media/video/gspca/sn9c20x.c @@ -20,7 +20,6 @@ #ifdef CONFIG_INPUT #include <linux/input.h> -#include <linux/slab.h> #endif #include "gspca.h" @@ -89,7 +88,7 @@ struct sd { u8 hstart; u8 vstart; - u8 *jpeg_hdr; + u8 jpeg_hdr[JPEG_HDR_SZ]; u8 quality; u8 flags; @@ -2162,10 +2161,6 @@ static int sd_start(struct gspca_dev *gspca_dev) int height = gspca_dev->height; u8 fmt, scale = 0; - sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL); - if (sd->jpeg_hdr == NULL) - return -ENOMEM; - jpeg_define(sd->jpeg_hdr, height, width, 0x21); jpeg_set_qual(sd->jpeg_hdr, sd->quality); @@ -2197,8 +2192,8 @@ static int sd_start(struct gspca_dev *gspca_dev) } configure_sensor_output(gspca_dev, mode); - reg_w(gspca_dev, 0x1100, sd->jpeg_hdr + JPEG_QT0_OFFSET, 64); - reg_w(gspca_dev, 0x1140, sd->jpeg_hdr + JPEG_QT1_OFFSET, 64); + reg_w(gspca_dev, 0x1100, &sd->jpeg_hdr[JPEG_QT0_OFFSET], 64); + reg_w(gspca_dev, 0x1140, &sd->jpeg_hdr[JPEG_QT1_OFFSET], 64); reg_w(gspca_dev, 0x10fb, CLR_WIN(width, height), 5); reg_w(gspca_dev, 0x1180, HW_WIN(mode, sd->hstart, sd->vstart), 6); reg_w1(gspca_dev, 0x1189, scale); @@ -2226,12 +2221,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev) reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] & ~0x02); } -static void sd_stop0(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - kfree(sd->jpeg_hdr); -} - static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum) { struct sd *sd = (struct sd *) gspca_dev; @@ -2397,7 +2386,6 @@ static const struct sd_desc sd_desc = { .init = sd_init, .start = sd_start, .stopN = sd_stopN, - .stop0 = sd_stop0, .pkt_scan = sd_pkt_scan, #ifdef CONFIG_INPUT .int_pkt_scan = sd_int_pkt_scan, diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c index 95354a339e3..204bb3af455 100644 --- a/drivers/media/video/gspca/sonixb.c +++ b/drivers/media/video/gspca/sonixb.c @@ -1251,16 +1251,10 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_RAW) { /* In raw mode we sometimes get some garbage after the frame ignore this */ - struct gspca_frame *frame; int used; int size = cam->cam_mode[gspca_dev->curr_mode].sizeimage; - frame = gspca_get_i_frame(gspca_dev); - if (frame == NULL) { - gspca_dev->last_packet_type = DISCARD_PACKET; - return; - } - used = frame->data_end - frame->data; + used = gspca_dev->image_len; if (used + len > size) len = size - used; } diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index 176c5b3d5e6..ee17b034bf6 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -22,7 +22,6 @@ #define MODULE_NAME "sonixj" #include <linux/input.h> -#include <linux/slab.h> #include "gspca.h" #include "jpeg.h" @@ -392,7 +391,7 @@ static const u8 sn_gc0307[0x1c] = { static const u8 sn_hv7131[0x1c] = { /* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ - 0x00, 0x03, 0x64, 0x00, 0x1a, 0x20, 0x20, 0x20, + 0x00, 0x03, 0x60, 0x00, 0x1a, 0x20, 0x20, 0x20, /* reg8 reg9 rega regb regc regd rege regf */ 0x81, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ @@ -403,7 +402,7 @@ static const u8 sn_hv7131[0x1c] = { static const u8 sn_mi0360[0x1c] = { /* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ - 0x00, 0x61, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, + 0x00, 0x61, 0x40, 0x00, 0x1a, 0x20, 0x20, 0x20, /* reg8 reg9 rega regb regc regd rege regf */ 0x81, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ @@ -1644,6 +1643,7 @@ static void bridge_init(struct gspca_dev *gspca_dev, const u8 *sn9c1xx) { struct sd *sd = (struct sd *) gspca_dev; + u8 reg0102[2]; const u8 *reg9a; static const u8 reg9a_def[] = {0x00, 0x40, 0x20, 0x00, 0x00, 0x00}; @@ -1656,7 +1656,11 @@ static void bridge_init(struct gspca_dev *gspca_dev, reg_w1(gspca_dev, 0x01, sn9c1xx[1]); /* configure gpio */ - reg_w(gspca_dev, 0x01, &sn9c1xx[1], 2); + reg0102[0] = sn9c1xx[1]; + reg0102[1] = sn9c1xx[2]; + if (gspca_dev->audio) + reg0102[1] |= 0x04; /* keep the audio connection */ + reg_w(gspca_dev, 0x01, reg0102, 2); reg_w(gspca_dev, 0x08, &sn9c1xx[8], 2); reg_w(gspca_dev, 0x17, &sn9c1xx[0x17], 5); switch (sd->sensor) { @@ -1737,13 +1741,12 @@ static void bridge_init(struct gspca_dev *gspca_dev, reg_w1(gspca_dev, 0x01, 0x40); break; case SENSOR_PO2030N: + case SENSOR_OV7660: reg_w1(gspca_dev, 0x01, 0x63); reg_w1(gspca_dev, 0x17, 0x20); reg_w1(gspca_dev, 0x01, 0x62); reg_w1(gspca_dev, 0x01, 0x42); break; - case SENSOR_OV7660: - /* fall thru */ case SENSOR_SP80708: reg_w1(gspca_dev, 0x01, 0x63); reg_w1(gspca_dev, 0x17, 0x20); @@ -1816,7 +1819,7 @@ static int sd_init(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; const u8 *sn9c1xx; - u8 regGpio[] = { 0x29, 0x74 }; + u8 regGpio[] = { 0x29, 0x74 }; /* with audio */ u8 regF1; /* setup a selector by bridge */ @@ -1856,7 +1859,7 @@ static int sd_init(struct gspca_dev *gspca_dev) po2030n_probe(gspca_dev); break; } - regGpio[1] = 0x70; + regGpio[1] = 0x70; /* no audio */ reg_w(gspca_dev, 0x01, regGpio, 2); break; default: @@ -2274,7 +2277,7 @@ static int sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; int i; - u8 reg1, reg2, reg17; + u8 reg1, reg17; const u8 *sn9c1xx; const u8 (*init)[8]; int mode; @@ -2304,23 +2307,6 @@ static int sd_start(struct gspca_dev *gspca_dev) /* initialize the sensor */ i2c_w_seq(gspca_dev, sensor_init[sd->sensor]); - switch (sd->sensor) { - case SENSOR_ADCM1700: - reg2 = 0x60; - break; - case SENSOR_OM6802: - reg2 = 0x71; - break; - case SENSOR_SP80708: - reg2 = 0x62; - break; - default: - reg2 = 0x40; - break; - } - reg_w1(gspca_dev, 0x02, reg2); - reg_w1(gspca_dev, 0x02, reg2); - reg_w1(gspca_dev, 0x15, sn9c1xx[0x15]); reg_w1(gspca_dev, 0x16, sn9c1xx[0x16]); reg_w1(gspca_dev, 0x12, sn9c1xx[0x12]); diff --git a/drivers/media/video/gspca/spca1528.c b/drivers/media/video/gspca/spca1528.c new file mode 100644 index 00000000000..3f514eb1d99 --- /dev/null +++ b/drivers/media/video/gspca/spca1528.c @@ -0,0 +1,605 @@ +/* + * spca1528 subdriver + * + * Copyright (C) 2010 Jean-Francois Moine (http://moinejf.free.fr) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define MODULE_NAME "spca1528" + +#include "gspca.h" +#include "jpeg.h" + +MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>"); +MODULE_DESCRIPTION("SPCA1528 USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + u8 brightness; + u8 contrast; + u8 hue; + u8 color; + u8 sharpness; + + u8 pkt_seq; + + u8 jpeg_hdr[JPEG_HDR_SZ]; +}; + +/* V4L2 controls supported by the driver */ +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val); +static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcolor(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcolor(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val); + +static const struct ctrl sd_ctrls[] = { + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 255, + .step = 1, +#define BRIGHTNESS_DEF 128 + .default_value = BRIGHTNESS_DEF, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, + { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 8, + .step = 1, +#define CONTRAST_DEF 1 + .default_value = CONTRAST_DEF, + }, + .set = sd_setcontrast, + .get = sd_getcontrast, + }, + { + { + .id = V4L2_CID_HUE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Hue", + .minimum = 0, + .maximum = 255, + .step = 1, +#define HUE_DEF 0 + .default_value = HUE_DEF, + }, + .set = sd_sethue, + .get = sd_gethue, + }, + { + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Saturation", + .minimum = 0, + .maximum = 8, + .step = 1, +#define COLOR_DEF 1 + .default_value = COLOR_DEF, + }, + .set = sd_setcolor, + .get = sd_getcolor, + }, + { + { + .id = V4L2_CID_SHARPNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Sharpness", + .minimum = 0, + .maximum = 255, + .step = 1, +#define SHARPNESS_DEF 0 + .default_value = SHARPNESS_DEF, + }, + .set = sd_setsharpness, + .get = sd_getsharpness, + }, +}; + +static const struct v4l2_pix_format vga_mode[] = { +/* (does not work correctly) + {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144 * 5 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 3}, +*/ + {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 4 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 2}, + {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, +}; + +/* read <len> bytes to gspca usb_buf */ +static void reg_r(struct gspca_dev *gspca_dev, + u8 req, + u16 index, + int len) +{ +#if USB_BUF_SZ < 64 +#error "USB buffer too small" +#endif + struct usb_device *dev = gspca_dev->dev; + int ret; + + if (gspca_dev->usb_err < 0) + return; + ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + req, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0x0000, /* value */ + index, + gspca_dev->usb_buf, len, + 500); + PDEBUG(D_USBI, "GET %02x 0000 %04x %02x", req, index, + gspca_dev->usb_buf[0]); + if (ret < 0) { + PDEBUG(D_ERR, "reg_r err %d", ret); + gspca_dev->usb_err = ret; + } +} + +static void reg_w(struct gspca_dev *gspca_dev, + u8 req, + u16 value, + u16 index) +{ + struct usb_device *dev = gspca_dev->dev; + int ret; + + if (gspca_dev->usb_err < 0) + return; + PDEBUG(D_USBO, "SET %02x %04x %04x", req, value, index); + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + req, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, + NULL, 0, 500); + if (ret < 0) { + PDEBUG(D_ERR, "reg_w err %d", ret); + gspca_dev->usb_err = ret; + } +} + +static void reg_wb(struct gspca_dev *gspca_dev, + u8 req, + u16 value, + u16 index, + u8 byte) +{ + struct usb_device *dev = gspca_dev->dev; + int ret; + + if (gspca_dev->usb_err < 0) + return; + PDEBUG(D_USBO, "SET %02x %04x %04x %02x", req, value, index, byte); + gspca_dev->usb_buf[0] = byte; + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + req, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, + gspca_dev->usb_buf, 1, 500); + if (ret < 0) { + PDEBUG(D_ERR, "reg_w err %d", ret); + gspca_dev->usb_err = ret; + } +} + +static void wait_status_0(struct gspca_dev *gspca_dev) +{ + int i; + + i = 20; + do { + reg_r(gspca_dev, 0x21, 0x0000, 1); + if (gspca_dev->usb_buf[0] == 0) + return; + msleep(30); + } while (--i > 0); + PDEBUG(D_ERR, "wait_status_0 timeout"); + gspca_dev->usb_err = -ETIME; +} + +static void wait_status_1(struct gspca_dev *gspca_dev) +{ + int i; + + i = 10; + do { + reg_r(gspca_dev, 0x21, 0x0001, 1); + msleep(10); + if (gspca_dev->usb_buf[0] == 1) { + reg_wb(gspca_dev, 0x21, 0x0000, 0x0001, 0x00); + reg_r(gspca_dev, 0x21, 0x0001, 1); + return; + } + } while (--i > 0); + PDEBUG(D_ERR, "wait_status_1 timeout"); + gspca_dev->usb_err = -ETIME; +} + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_wb(gspca_dev, 0xc0, 0x0000, 0x00c0, sd->brightness); +} + +static void setcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_wb(gspca_dev, 0xc1, 0x0000, 0x00c1, sd->contrast); +} + +static void sethue(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_wb(gspca_dev, 0xc2, 0x0000, 0x0000, sd->hue); +} + +static void setcolor(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_wb(gspca_dev, 0xc3, 0x0000, 0x00c3, sd->color); +} + +static void setsharpness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_wb(gspca_dev, 0xc4, 0x0000, 0x00c4, sd->sharpness); +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + + gspca_dev->cam.cam_mode = vga_mode; + gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode); + gspca_dev->cam.npkt = 128; /* number of packets per ISOC message */ + /*fixme: 256 in ms-win traces*/ + + sd->brightness = BRIGHTNESS_DEF; + sd->contrast = CONTRAST_DEF; + sd->hue = HUE_DEF; + sd->color = COLOR_DEF; + sd->sharpness = SHARPNESS_DEF; + + gspca_dev->nbalt = 4; /* use alternate setting 3 */ + + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + reg_w(gspca_dev, 0x00, 0x0001, 0x2067); + reg_w(gspca_dev, 0x00, 0x00d0, 0x206b); + reg_w(gspca_dev, 0x00, 0x0000, 0x206c); + reg_w(gspca_dev, 0x00, 0x0001, 0x2069); + msleep(8); + reg_w(gspca_dev, 0x00, 0x00c0, 0x206b); + reg_w(gspca_dev, 0x00, 0x0000, 0x206c); + reg_w(gspca_dev, 0x00, 0x0001, 0x2069); + + reg_r(gspca_dev, 0x20, 0x0000, 1); + reg_r(gspca_dev, 0x20, 0x0000, 5); + reg_r(gspca_dev, 0x23, 0x0000, 64); + PDEBUG(D_PROBE, "%s%s", &gspca_dev->usb_buf[0x1c], + &gspca_dev->usb_buf[0x30]); + reg_r(gspca_dev, 0x23, 0x0001, 64); + return gspca_dev->usb_err; +} + +/* function called at start time before URB creation */ +static int sd_isoc_init(struct gspca_dev *gspca_dev) +{ + u8 mode; + + reg_r(gspca_dev, 0x00, 0x2520, 1); + wait_status_0(gspca_dev); + reg_w(gspca_dev, 0xc5, 0x0003, 0x0000); + wait_status_1(gspca_dev); + + wait_status_0(gspca_dev); + mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; + reg_wb(gspca_dev, 0x25, 0x0000, 0x0004, mode); + reg_r(gspca_dev, 0x25, 0x0004, 1); + reg_wb(gspca_dev, 0x27, 0x0000, 0x0000, 0x06); + reg_r(gspca_dev, 0x27, 0x0000, 1); + return gspca_dev->usb_err; +} + +/* -- start the camera -- */ +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + /* initialize the JPEG header */ + jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, + 0x22); /* JPEG 411 */ + + /* the JPEG quality seems to be 82% */ + jpeg_set_qual(sd->jpeg_hdr, 82); + + /* set the controls */ + setbrightness(gspca_dev); + setcontrast(gspca_dev); + sethue(gspca_dev); + setcolor(gspca_dev); + setsharpness(gspca_dev); + + msleep(5); + reg_r(gspca_dev, 0x00, 0x2520, 1); + msleep(8); + + /* start the capture */ + wait_status_0(gspca_dev); + reg_w(gspca_dev, 0x31, 0x0000, 0x0004); + wait_status_1(gspca_dev); + wait_status_0(gspca_dev); + msleep(200); + + sd->pkt_seq = 0; + return gspca_dev->usb_err; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + /* stop the capture */ + wait_status_0(gspca_dev); + reg_w(gspca_dev, 0x31, 0x0000, 0x0000); + wait_status_1(gspca_dev); + wait_status_0(gspca_dev); +} + +/* move a packet adding 0x00 after 0xff */ +static void add_packet(struct gspca_dev *gspca_dev, + u8 *data, + int len) +{ + int i; + + i = 0; + do { + if (data[i] == 0xff) { + gspca_frame_add(gspca_dev, INTER_PACKET, + data, i + 1); + len -= i; + data += i; + *data = 0x00; + i = 0; + } + } while (++i < len); + gspca_frame_add(gspca_dev, INTER_PACKET, data, len); +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + struct sd *sd = (struct sd *) gspca_dev; + static const u8 ffd9[] = {0xff, 0xd9}; + + /* image packets start with: + * 02 8n + * with <n> bit: + * 0x01: even (0) / odd (1) image + * 0x02: end of image when set + */ + if (len < 3) + return; /* empty packet */ + if (*data == 0x02) { + if (data[1] & 0x02) { + sd->pkt_seq = !(data[1] & 1); + add_packet(gspca_dev, data + 2, len - 2); + gspca_frame_add(gspca_dev, LAST_PACKET, + ffd9, 2); + return; + } + if ((data[1] & 1) != sd->pkt_seq) + goto err; + if (gspca_dev->last_packet_type == LAST_PACKET) + gspca_frame_add(gspca_dev, FIRST_PACKET, + sd->jpeg_hdr, JPEG_HDR_SZ); + add_packet(gspca_dev, data + 2, len - 2); + return; + } +err: + gspca_dev->last_packet_type = DISCARD_PACKET; +} + +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + if (gspca_dev->streaming) + setbrightness(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->brightness; + return 0; +} + +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->contrast = val; + if (gspca_dev->streaming) + setcontrast(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->contrast; + return 0; +} + +static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->hue = val; + if (gspca_dev->streaming) + sethue(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->hue; + return 0; +} + +static int sd_setcolor(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->color = val; + if (gspca_dev->streaming) + setcolor(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_getcolor(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->color; + return 0; +} + +static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->sharpness = val; + if (gspca_dev->streaming) + setsharpness(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->sharpness; + return 0; +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .isoc_init = sd_isoc_init, + .start = sd_start, + .stopN = sd_stopN, + .pkt_scan = sd_pkt_scan, +}; + +/* -- module initialisation -- */ +static const __devinitdata struct usb_device_id device_table[] = { + {USB_DEVICE(0x04fc, 0x1528)}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + /* the video interface for isochronous transfer is 1 */ + if (intf->cur_altsetting->desc.bInterfaceNumber != 1) + return -ENODEV; + + return gspca_dev_probe2(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + int ret; + + ret = usb_register(&sd_driver); + if (ret < 0) + return ret; + info("registered"); + return 0; +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); + info("deregistered"); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff --git a/drivers/media/video/gspca/spca500.c b/drivers/media/video/gspca/spca500.c index b866c73c97d..c02beb6c1e9 100644 --- a/drivers/media/video/gspca/spca500.c +++ b/drivers/media/video/gspca/spca500.c @@ -57,7 +57,7 @@ struct sd { #define PalmPixDC85 13 #define ToptroIndus 14 - u8 *jpeg_hdr; + u8 jpeg_hdr[JPEG_HDR_SZ]; }; /* V4L2 controls supported by the driver */ @@ -669,9 +669,6 @@ static int sd_start(struct gspca_dev *gspca_dev) __u8 xmult, ymult; /* create the JPEG header */ - sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL); - if (!sd->jpeg_hdr) - return -ENOMEM; jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, 0x22); /* JPEG 411 */ jpeg_set_qual(sd->jpeg_hdr, sd->quality); @@ -891,13 +888,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev) gspca_dev->usb_buf[0]); } -static void sd_stop0(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - kfree(sd->jpeg_hdr); -} - static void sd_pkt_scan(struct gspca_dev *gspca_dev, u8 *data, /* isoc packet */ int len) /* iso packet length */ @@ -1055,7 +1045,6 @@ static const struct sd_desc sd_desc = { .init = sd_init, .start = sd_start, .stopN = sd_stopN, - .stop0 = sd_stop0, .pkt_scan = sd_pkt_scan, .get_jcomp = sd_get_jcomp, .set_jcomp = sd_set_jcomp, diff --git a/drivers/media/video/gspca/sq930x.c b/drivers/media/video/gspca/sq930x.c new file mode 100644 index 00000000000..37cee5e063c --- /dev/null +++ b/drivers/media/video/gspca/sq930x.c @@ -0,0 +1,1402 @@ +/* + * SQ930x subdriver + * + * Copyright (C) 2010 Jean-François Moine <http://moinejf.free.fr> + * Copyright (C) 2006 -2008 Gerard Klaver <gerard at gkall dot hobby dot nl> + * Copyright (C) 2007 Sam Revitch <samr7@cs.washington.edu> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define MODULE_NAME "sq930x" + +#include "gspca.h" +#include "jpeg.h" + +MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>\n" + "Gerard Klaver <gerard at gkall dot hobby dot nl\n" + "Sam Revitch <samr7@cs.washington.edu>"); +MODULE_DESCRIPTION("GSPCA/SQ930x USB Camera Driver"); +MODULE_LICENSE("GPL"); + +#define BULK_TRANSFER_LEN 5128 + +/* Structure to hold all of our device specific stuff */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + u16 expo; + u8 gain; + + u8 quality; /* webcam quality 0..3 */ +#define QUALITY_DEF 1 + + u8 gpio[2]; + + u8 eof_len; + u8 do_ctrl; + + u8 sensor; +enum { + SENSOR_ICX098BQ, + SENSOR_LZ24BP, + SENSOR_MI0360, + SENSOR_MT9V111, + SENSOR_OV7660, + SENSOR_OV9630, +} sensors; + u8 type; +#define Generic 0 +#define Creative_live_motion 1 + + u8 jpeg_hdr[JPEG_HDR_SZ]; +}; + +static int sd_setexpo(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getexpo(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); + +static const struct ctrl sd_ctrls[] = { + { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = 0x0001, + .maximum = 0x0fff, + .step = 1, +#define EXPO_DEF 0x027d + .default_value = EXPO_DEF, + }, + .set = sd_setexpo, + .get = sd_getexpo, + }, + { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = 0x01, + .maximum = 0xff, + .step = 1, +#define GAIN_DEF 0x61 + .default_value = GAIN_DEF, + }, + .set = sd_setgain, + .get = sd_getgain, + }, +}; + +static struct v4l2_pix_format vga_mode[] = { + {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120 * 5 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, + {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 4 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, + {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 2}, +}; + +/* JPEG quality indexed by webcam quality */ +#define QUAL_0 90 +#define QUAL_1 85 +#define QUAL_2 75 +#define QUAL_3 70 +static const u8 quality_tb[4] = { QUAL_0, QUAL_1, QUAL_2, QUAL_3 }; + +/* sq930x registers */ +#define SQ930_CTRL_UCBUS_IO 0x0001 +#define SQ930_CTRL_I2C_IO 0x0002 +#define SQ930_CTRL_GPIO 0x0005 +#define SQ930_CTRL_CAP_START 0x0010 +#define SQ930_CTRL_CAP_STOP 0x0011 +#define SQ930_CTRL_SET_EXPOSURE 0x001d +#define SQ930_CTRL_RESET 0x001e +#define SQ930_CTRL_GET_DEV_INFO 0x001f + +/* gpio 1 (8..15) */ +#define SQ930_GPIO_DFL_I2C_SDA 0x0001 +#define SQ930_GPIO_DFL_I2C_SCL 0x0002 +#define SQ930_GPIO_RSTBAR 0x0004 +#define SQ930_GPIO_EXTRA1 0x0040 +#define SQ930_GPIO_EXTRA2 0x0080 +/* gpio 3 (24..31) */ +#define SQ930_GPIO_POWER 0x0200 +#define SQ930_GPIO_DFL_LED 0x1000 + +struct ucbus_write_cmd { + u16 bw_addr; + u8 bw_data; +}; +struct i2c_write_cmd { + u8 reg; + u16 val; +}; + +static const struct ucbus_write_cmd icx098bq_start_0[] = { + {0x0354, 0x00}, {0x03fa, 0x00}, {0xf800, 0x02}, {0xf801, 0xce}, + {0xf802, 0xc1}, {0xf804, 0x00}, {0xf808, 0x00}, {0xf809, 0x0e}, + {0xf80a, 0x01}, {0xf80b, 0xee}, {0xf807, 0x60}, {0xf80c, 0x02}, + {0xf80d, 0xf0}, {0xf80e, 0x03}, {0xf80f, 0x0a}, {0xf81c, 0x02}, + {0xf81d, 0xf0}, {0xf81e, 0x03}, {0xf81f, 0x0a}, {0xf83a, 0x00}, + {0xf83b, 0x10}, {0xf83c, 0x00}, {0xf83d, 0x4e}, {0xf810, 0x04}, + {0xf811, 0x00}, {0xf812, 0x02}, {0xf813, 0x10}, {0xf803, 0x00}, + {0xf814, 0x01}, {0xf815, 0x18}, {0xf816, 0x00}, {0xf817, 0x48}, + {0xf818, 0x00}, {0xf819, 0x25}, {0xf81a, 0x00}, {0xf81b, 0x3c}, + {0xf82f, 0x03}, {0xf820, 0xff}, {0xf821, 0x0d}, {0xf822, 0xff}, + {0xf823, 0x07}, {0xf824, 0xff}, {0xf825, 0x03}, {0xf826, 0xff}, + {0xf827, 0x06}, {0xf828, 0xff}, {0xf829, 0x03}, {0xf82a, 0xff}, + {0xf82b, 0x0c}, {0xf82c, 0xfd}, {0xf82d, 0x01}, {0xf82e, 0x00}, + {0xf830, 0x00}, {0xf831, 0x47}, {0xf832, 0x00}, {0xf833, 0x00}, + {0xf850, 0x00}, {0xf851, 0x00}, {0xf852, 0x00}, {0xf853, 0x24}, + {0xf854, 0x00}, {0xf855, 0x18}, {0xf856, 0x00}, {0xf857, 0x3c}, + {0xf858, 0x00}, {0xf859, 0x0c}, {0xf85a, 0x00}, {0xf85b, 0x30}, + {0xf85c, 0x00}, {0xf85d, 0x0c}, {0xf85e, 0x00}, {0xf85f, 0x30}, + {0xf860, 0x00}, {0xf861, 0x48}, {0xf862, 0x01}, {0xf863, 0xdc}, + {0xf864, 0xff}, {0xf865, 0x98}, {0xf866, 0xff}, {0xf867, 0xc0}, + {0xf868, 0xff}, {0xf869, 0x70}, {0xf86c, 0xff}, {0xf86d, 0x00}, + {0xf86a, 0xff}, {0xf86b, 0x48}, {0xf86e, 0xff}, {0xf86f, 0x00}, + {0xf870, 0x01}, {0xf871, 0xdb}, {0xf872, 0x01}, {0xf873, 0xfa}, + {0xf874, 0x01}, {0xf875, 0xdb}, {0xf876, 0x01}, {0xf877, 0xfa}, + {0xf878, 0x0f}, {0xf879, 0x0f}, {0xf87a, 0xff}, {0xf87b, 0xff}, + {0xf800, 0x03} +}; +static const struct ucbus_write_cmd icx098bq_start_1[] = { + {0xf5f0, 0x00}, {0xf5f1, 0xcd}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, + {0xf5f4, 0xc0}, + {0xf5f0, 0x49}, {0xf5f1, 0xcd}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, + {0xf5f4, 0xc0}, + {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00}, + {0xf5f9, 0x00} +}; + +static const struct ucbus_write_cmd icx098bq_start_2[] = { + {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x82}, {0xf806, 0x00}, + {0xf807, 0x7f}, {0xf800, 0x03}, + {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x40}, {0xf806, 0x00}, + {0xf807, 0x7f}, {0xf800, 0x03}, + {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0xcf}, {0xf806, 0xd0}, + {0xf807, 0x7f}, {0xf800, 0x03}, + {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x00}, {0xf806, 0x00}, + {0xf807, 0x7f}, {0xf800, 0x03} +}; + +static const struct ucbus_write_cmd lz24bp_start_0[] = { + {0x0354, 0x00}, {0x03fa, 0x00}, {0xf800, 0x02}, {0xf801, 0xbe}, + {0xf802, 0xc6}, {0xf804, 0x00}, {0xf808, 0x00}, {0xf809, 0x06}, + {0xf80a, 0x01}, {0xf80b, 0xfe}, {0xf807, 0x84}, {0xf80c, 0x02}, + {0xf80d, 0xf7}, {0xf80e, 0x03}, {0xf80f, 0x0b}, {0xf81c, 0x00}, + {0xf81d, 0x49}, {0xf81e, 0x03}, {0xf81f, 0x0b}, {0xf83a, 0x00}, + {0xf83b, 0x01}, {0xf83c, 0x00}, {0xf83d, 0x6b}, {0xf810, 0x03}, + {0xf811, 0x10}, {0xf812, 0x02}, {0xf813, 0x6f}, {0xf803, 0x00}, + {0xf814, 0x00}, {0xf815, 0x44}, {0xf816, 0x00}, {0xf817, 0x48}, + {0xf818, 0x00}, {0xf819, 0x25}, {0xf81a, 0x00}, {0xf81b, 0x3c}, + {0xf82f, 0x03}, {0xf820, 0xff}, {0xf821, 0x0d}, {0xf822, 0xff}, + {0xf823, 0x07}, {0xf824, 0xfd}, {0xf825, 0x07}, {0xf826, 0xf0}, + {0xf827, 0x0c}, {0xf828, 0xff}, {0xf829, 0x03}, {0xf82a, 0xff}, + {0xf82b, 0x0c}, {0xf82c, 0xfc}, {0xf82d, 0x01}, {0xf82e, 0x00}, + {0xf830, 0x00}, {0xf831, 0x47}, {0xf832, 0x00}, {0xf833, 0x00}, + {0xf850, 0x00}, {0xf851, 0x00}, {0xf852, 0x00}, {0xf853, 0x24}, + {0xf854, 0x00}, {0xf855, 0x0c}, {0xf856, 0x00}, {0xf857, 0x30}, + {0xf858, 0x00}, {0xf859, 0x18}, {0xf85a, 0x00}, {0xf85b, 0x3c}, + {0xf85c, 0x00}, {0xf85d, 0x18}, {0xf85e, 0x00}, {0xf85f, 0x3c}, + {0xf860, 0xff}, {0xf861, 0x37}, {0xf862, 0xff}, {0xf863, 0x1d}, + {0xf864, 0xff}, {0xf865, 0x98}, {0xf866, 0xff}, {0xf867, 0xc0}, + {0xf868, 0x00}, {0xf869, 0x37}, {0xf86c, 0x02}, {0xf86d, 0x1d}, + {0xf86a, 0x00}, {0xf86b, 0x37}, {0xf86e, 0x02}, {0xf86f, 0x1d}, + {0xf870, 0x01}, {0xf871, 0xc6}, {0xf872, 0x02}, {0xf873, 0x04}, + {0xf874, 0x01}, {0xf875, 0xc6}, {0xf876, 0x02}, {0xf877, 0x04}, + {0xf878, 0x0f}, {0xf879, 0x0f}, {0xf87a, 0xff}, {0xf87b, 0xff}, + {0xf800, 0x03} +}; +static const struct ucbus_write_cmd lz24bp_start_1_gen[] = { + {0xf5f0, 0x00}, {0xf5f1, 0xff}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, + {0xf5f4, 0xb3}, + {0xf5f0, 0x40}, {0xf5f1, 0xff}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, + {0xf5f4, 0xb3}, + {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00}, + {0xf5f9, 0x00} +}; + +static const struct ucbus_write_cmd lz24bp_start_1_clm[] = { + {0xf5f0, 0x00}, {0xf5f1, 0xff}, {0xf5f2, 0x88}, {0xf5f3, 0x88}, + {0xf5f4, 0xc0}, + {0xf5f0, 0x40}, {0xf5f1, 0xff}, {0xf5f2, 0x88}, {0xf5f3, 0x88}, + {0xf5f4, 0xc0}, + {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00}, + {0xf5f9, 0x00} +}; + +static const struct ucbus_write_cmd lz24bp_start_2[] = { + {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x80}, {0xf806, 0x00}, + {0xf807, 0x7f}, {0xf800, 0x03}, + {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x4e}, {0xf806, 0x00}, + {0xf807, 0x7f}, {0xf800, 0x03}, + {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0xc0}, {0xf806, 0x48}, + {0xf807, 0x7f}, {0xf800, 0x03}, + {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x00}, {0xf806, 0x00}, + {0xf807, 0x7f}, {0xf800, 0x03} +}; + +static const struct ucbus_write_cmd mi0360_start_0[] = { + {0x0354, 0x00}, {0x03fa, 0x00}, {0xf332, 0xcc}, {0xf333, 0xcc}, + {0xf334, 0xcc}, {0xf335, 0xcc}, {0xf33f, 0x00} +}; +static const struct i2c_write_cmd mi0360_init_23[] = { + {0x30, 0x0040}, /* reserved - def 0x0005 */ + {0x31, 0x0000}, /* reserved - def 0x002a */ + {0x34, 0x0100}, /* reserved - def 0x0100 */ + {0x3d, 0x068f}, /* reserved - def 0x068f */ +}; +static const struct i2c_write_cmd mi0360_init_24[] = { + {0x03, 0x01e5}, /* window height */ + {0x04, 0x0285}, /* window width */ +}; +static const struct i2c_write_cmd mi0360_init_25[] = { + {0x35, 0x0020}, /* global gain */ + {0x2b, 0x0020}, /* green1 gain */ + {0x2c, 0x002a}, /* blue gain */ + {0x2d, 0x0028}, /* red gain */ + {0x2e, 0x0020}, /* green2 gain */ +}; +static const struct ucbus_write_cmd mi0360_start_1[] = { + {0xf5f0, 0x11}, {0xf5f1, 0x99}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, + {0xf5f4, 0xa6}, + {0xf5f0, 0x51}, {0xf5f1, 0x99}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, + {0xf5f4, 0xa6}, + {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00}, + {0xf5f9, 0x00} +}; +static const struct i2c_write_cmd mi0360_start_2[] = { + {0x62, 0x041d}, /* reserved - def 0x0418 */ +}; +static const struct i2c_write_cmd mi0360_start_3[] = { + {0x05, 0x007b}, /* horiz blanking */ +}; +static const struct i2c_write_cmd mi0360_start_4[] = { + {0x05, 0x03f5}, /* horiz blanking */ +}; + +static const struct i2c_write_cmd mt9v111_init_0[] = { + {0x01, 0x0001}, /* select IFP/SOC registers */ + {0x06, 0x300c}, /* operating mode control */ + {0x08, 0xcc00}, /* output format control (RGB) */ + {0x01, 0x0004}, /* select core registers */ +}; +static const struct i2c_write_cmd mt9v111_init_1[] = { + {0x03, 0x01e5}, /* window height */ + {0x04, 0x0285}, /* window width */ +}; +static const struct i2c_write_cmd mt9v111_init_2[] = { + {0x30, 0x7800}, + {0x31, 0x0000}, + {0x07, 0x3002}, /* output control */ + {0x35, 0x0020}, /* global gain */ + {0x2b, 0x0020}, /* green1 gain */ + {0x2c, 0x0020}, /* blue gain */ + {0x2d, 0x0020}, /* red gain */ + {0x2e, 0x0020}, /* green2 gain */ +}; +static const struct ucbus_write_cmd mt9v111_start_1[] = { + {0xf5f0, 0x11}, {0xf5f1, 0x96}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, + {0xf5f4, 0xaa}, + {0xf5f0, 0x51}, {0xf5f1, 0x96}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, + {0xf5f4, 0xaa}, + {0xf5fa, 0x00}, {0xf5f6, 0x0a}, {0xf5f7, 0x0a}, {0xf5f8, 0x0a}, + {0xf5f9, 0x0a} +}; +static const struct i2c_write_cmd mt9v111_init_3[] = { + {0x62, 0x0405}, +}; +static const struct i2c_write_cmd mt9v111_init_4[] = { + {0x05, 0x00ce}, /* horizontal blanking */ +}; + +static const struct ucbus_write_cmd ov7660_start_0[] = { + {0x0354, 0x00}, {0x03fa, 0x00}, {0xf332, 0x00}, {0xf333, 0xc0}, + {0xf334, 0x39}, {0xf335, 0xe7}, {0xf33f, 0x03} +}; + +static const struct ucbus_write_cmd ov9630_start_0[] = { + {0x0354, 0x00}, {0x03fa, 0x00}, {0xf332, 0x00}, {0xf333, 0x00}, + {0xf334, 0x3e}, {0xf335, 0xf8}, {0xf33f, 0x03} +}; + +static const struct cap_s { + u8 cc_sizeid; + u8 cc_bytes[32]; +} capconfig[4][3] = { + [SENSOR_ICX098BQ] = { + {0, /* JPEG, 160x120 */ + {0x01, 0x1f, 0x20, 0x0e, 0x00, 0x9f, 0x02, 0xee, + 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, + 0x02, 0x8b, 0x00, 0x8b, 0x00, 0x41, 0x01, 0x41, + 0x01, 0x41, 0x01, 0x05, 0x40, 0x01, 0xf0, 0x00} }, + {2, /* JPEG, 320x240 */ + {0x01, 0x1f, 0x20, 0x0e, 0x00, 0x9f, 0x02, 0xee, + 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, + 0x02, 0xdf, 0x01, 0x00, 0x00, 0x3f, 0x01, 0x3f, + 0x01, 0x00, 0x00, 0x05, 0x40, 0x01, 0xf0, 0x00} }, + {4, /* JPEG, 640x480 */ + {0x01, 0x22, 0x20, 0x0e, 0x00, 0xa2, 0x02, 0xf0, + 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, + 0x07, 0xe1, 0x01, 0xe1, 0x01, 0x3f, 0x01, 0x3f, + 0x01, 0x3f, 0x01, 0x05, 0x80, 0x02, 0xe0, 0x01} }, + }, + [SENSOR_LZ24BP] = { + {0, /* JPEG, 160x120 */ + {0x01, 0x1f, 0x20, 0x0e, 0x00, 0x9f, 0x02, 0xee, + 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, + 0x02, 0x8b, 0x00, 0x8b, 0x00, 0x41, 0x01, 0x41, + 0x01, 0x41, 0x01, 0x05, 0x40, 0x01, 0xf0, 0x00} }, + {2, /* JPEG, 320x240 */ + {0x01, 0x22, 0x20, 0x0e, 0x00, 0xa2, 0x02, 0xee, + 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, + 0x02, 0xdf, 0x01, 0x00, 0x00, 0x3f, 0x01, 0x3f, + 0x01, 0x00, 0x00, 0x05, 0x40, 0x01, 0xf0, 0x00} }, + {4, /* JPEG, 640x480 */ + {0x01, 0x22, 0x20, 0x0e, 0x00, 0xa2, 0x02, 0xf0, + 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, + 0x07, 0xe1, 0x01, 0xe1, 0x01, 0x3f, 0x01, 0x3f, + 0x01, 0x3f, 0x01, 0x05, 0x80, 0x02, 0xe0, 0x01} }, + }, + [SENSOR_MI0360] = { + {0, /* JPEG, 160x120 */ + {0x05, 0x3d, 0x20, 0x0b, 0x00, 0xbd, 0x02, 0x0b, + 0x02, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, + 0x02, 0x01, 0x01, 0x01, 0x01, 0x9f, 0x00, 0x9f, + 0x00, 0x9f, 0x01, 0x05, 0xa0, 0x00, 0x80, 0x00} }, + {2, /* JPEG, 320x240 */ + {0x01, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1, +/*fixme 03 e3 */ + 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, + 0x02, 0xdf, 0x01, 0x00, 0x00, 0x3f, 0x01, 0x3f, + 0x01, 0x00, 0x00, 0x05, 0x40, 0x01, 0xf0, 0x00} }, + {4, /* JPEG, 640x480 */ + {0x01, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe3, + 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, + 0x07, 0xe1, 0x01, 0xe1, 0x01, 0x3f, 0x01, 0x3f, + 0x01, 0x3f, 0x01, 0x05, 0x80, 0x02, 0xe0, 0x01} }, + }, + [SENSOR_MT9V111] = { + {0, /* JPEG, 160x120 */ + {0x05, 0x3d, 0x20, 0x0b, 0x00, 0xbd, 0x02, 0x0b, + 0x02, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, + 0x02, 0x01, 0x01, 0x01, 0x01, 0x9f, 0x00, 0x9f, + 0x00, 0x9f, 0x01, 0x05, 0xa0, 0x00, 0x80, 0x00} }, + {2, /* JPEG, 320x240 */ + {0x01, 0x02, 0x20, 0x03, 0x20, 0x82, 0x02, 0xe3, + 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, + 0x02, 0xdf, 0x01, 0x00, 0x00, 0x3f, 0x01, 0x3f, + 0x01, 0x00, 0x00, 0x05, 0x40, 0x01, 0xf0, 0x00} }, + {4, /* JPEG, 640x480 */ + {0x01, 0x02, 0x20, 0x03, 0x20, 0x82, 0x02, 0xe3, + 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, + 0x07, 0xe1, 0x01, 0xe1, 0x01, 0x3f, 0x01, 0x3f, + 0x01, 0x3f, 0x01, 0x05, 0x80, 0x02, 0xe0, 0x01} }, + }, +}; + +struct sensor_s { + const char *name; + u8 i2c_addr; + u8 i2c_dum; + u8 gpio[5]; + u8 cmd_len; + const struct ucbus_write_cmd *cmd; +}; + +static const struct sensor_s sensor_tb[] = { + [SENSOR_ICX098BQ] = { + "icx098bp", + 0x00, 0x00, + {0, + SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL, + SQ930_GPIO_DFL_I2C_SDA, + 0, + SQ930_GPIO_RSTBAR + }, + 8, icx098bq_start_0 + }, + [SENSOR_LZ24BP] = { + "lz24bp", + 0x00, 0x00, + {0, + SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL, + SQ930_GPIO_DFL_I2C_SDA, + 0, + SQ930_GPIO_RSTBAR + }, + 8, lz24bp_start_0 + }, + [SENSOR_MI0360] = { + "mi0360", + 0x5d, 0x80, + {SQ930_GPIO_RSTBAR, + SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL, + SQ930_GPIO_DFL_I2C_SDA, + 0, + 0 + }, + 7, mi0360_start_0 + }, + [SENSOR_MT9V111] = { + "mt9v111", + 0x5c, 0x7f, + {SQ930_GPIO_RSTBAR, + SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL, + SQ930_GPIO_DFL_I2C_SDA, + 0, + 0 + }, + 7, mi0360_start_0 + }, + [SENSOR_OV7660] = { + "ov7660", + 0x21, 0x00, + {0, + SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL, + SQ930_GPIO_DFL_I2C_SDA, + 0, + SQ930_GPIO_RSTBAR + }, + 7, ov7660_start_0 + }, + [SENSOR_OV9630] = { + "ov9630", + 0x30, 0x00, + {0, + SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL, + SQ930_GPIO_DFL_I2C_SDA, + 0, + SQ930_GPIO_RSTBAR + }, + 7, ov9630_start_0 + }, +}; + +static void reg_r(struct gspca_dev *gspca_dev, + u16 value, int len) +{ + int ret; + + if (gspca_dev->usb_err < 0) + return; + ret = usb_control_msg(gspca_dev->dev, + usb_rcvctrlpipe(gspca_dev->dev, 0), + 0x0c, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, 0, gspca_dev->usb_buf, len, + 500); + if (ret < 0) { + PDEBUG(D_ERR, "reg_r %04x failed %d", value, ret); + gspca_dev->usb_err = ret; + } +} + +static void reg_w(struct gspca_dev *gspca_dev, u16 value, u16 index) +{ + int ret; + + if (gspca_dev->usb_err < 0) + return; + PDEBUG(D_USBO, "reg_w v: %04x i: %04x", value, index); + ret = usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0x0c, /* request */ + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, NULL, 0, + 500); + msleep(30); + if (ret < 0) { + PDEBUG(D_ERR, "reg_w %04x %04x failed %d", value, index, ret); + gspca_dev->usb_err = ret; + } +} + +static void reg_wb(struct gspca_dev *gspca_dev, u16 value, u16 index, + const u8 *data, int len) +{ + int ret; + + if (gspca_dev->usb_err < 0) + return; + PDEBUG(D_USBO, "reg_wb v: %04x i: %04x %02x...%02x", + value, index, *data, data[len - 1]); + memcpy(gspca_dev->usb_buf, data, len); + ret = usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0x0c, /* request */ + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, gspca_dev->usb_buf, len, + 1000); + msleep(30); + if (ret < 0) { + PDEBUG(D_ERR, "reg_wb %04x %04x failed %d", value, index, ret); + gspca_dev->usb_err = ret; + } +} + +static void i2c_write(struct sd *sd, + const struct i2c_write_cmd *cmd, + int ncmds) +{ + struct gspca_dev *gspca_dev = &sd->gspca_dev; + const struct sensor_s *sensor; + u16 val, idx; + u8 *buf; + int ret; + + if (gspca_dev->usb_err < 0) + return; + + sensor = &sensor_tb[sd->sensor]; + + val = (sensor->i2c_addr << 8) | SQ930_CTRL_I2C_IO; + idx = (cmd->val & 0xff00) | cmd->reg; + + buf = gspca_dev->usb_buf; + *buf++ = sensor->i2c_dum; + *buf++ = cmd->val; + + while (--ncmds > 0) { + cmd++; + *buf++ = cmd->reg; + *buf++ = cmd->val >> 8; + *buf++ = sensor->i2c_dum; + *buf++ = cmd->val; + } + + PDEBUG(D_USBO, "i2c_w v: %04x i: %04x %02x...%02x", + val, idx, gspca_dev->usb_buf[0], buf[-1]); + ret = usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0x0c, /* request */ + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + val, idx, + gspca_dev->usb_buf, buf - gspca_dev->usb_buf, + 500); + if (ret < 0) { + PDEBUG(D_ERR, "i2c_write failed %d", ret); + gspca_dev->usb_err = ret; + } +} + +static void ucbus_write(struct gspca_dev *gspca_dev, + const struct ucbus_write_cmd *cmd, + int ncmds, + int batchsize) +{ + u8 *buf; + u16 val, idx; + int len, ret; + + if (gspca_dev->usb_err < 0) + return; + +#ifdef GSPCA_DEBUG + if ((batchsize - 1) * 3 > USB_BUF_SZ) { + err("Bug: usb_buf overflow"); + gspca_dev->usb_err = -ENOMEM; + return; + } +#endif + + for (;;) { + len = ncmds; + if (len > batchsize) + len = batchsize; + ncmds -= len; + + val = (cmd->bw_addr << 8) | SQ930_CTRL_UCBUS_IO; + idx = (cmd->bw_data << 8) | (cmd->bw_addr >> 8); + + buf = gspca_dev->usb_buf; + while (--len > 0) { + cmd++; + *buf++ = cmd->bw_addr; + *buf++ = cmd->bw_addr >> 8; + *buf++ = cmd->bw_data; + } + if (buf != gspca_dev->usb_buf) + PDEBUG(D_USBO, "ucbus v: %04x i: %04x %02x...%02x", + val, idx, + gspca_dev->usb_buf[0], buf[-1]); + else + PDEBUG(D_USBO, "ucbus v: %04x i: %04x", + val, idx); + ret = usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0x0c, /* request */ + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + val, idx, + gspca_dev->usb_buf, buf - gspca_dev->usb_buf, + 500); + if (ret < 0) { + PDEBUG(D_ERR, "ucbus_write failed %d", ret); + gspca_dev->usb_err = ret; + return; + } + msleep(30); + if (ncmds <= 0) + break; + cmd++; + } +} + +static void gpio_set(struct sd *sd, u16 val, u16 mask) +{ + struct gspca_dev *gspca_dev = &sd->gspca_dev; + + if (mask & 0x00ff) { + sd->gpio[0] &= ~mask; + sd->gpio[0] |= val; + reg_w(gspca_dev, 0x0100 | SQ930_CTRL_GPIO, + ~sd->gpio[0] << 8); + } + mask >>= 8; + val >>= 8; + if (mask) { + sd->gpio[1] &= ~mask; + sd->gpio[1] |= val; + reg_w(gspca_dev, 0x0300 | SQ930_CTRL_GPIO, + ~sd->gpio[1] << 8); + } +} + +static void gpio_init(struct sd *sd, + const u8 *gpio) +{ + gpio_set(sd, *gpio++, 0x000f); + gpio_set(sd, *gpio++, 0x000f); + gpio_set(sd, *gpio++, 0x000f); + gpio_set(sd, *gpio++, 0x000f); + gpio_set(sd, *gpio, 0x000f); +} + +static void bridge_init(struct sd *sd) +{ + static const struct ucbus_write_cmd clkfreq_cmd = { + 0xf031, 0 /* SQ930_CLKFREQ_60MHZ */ + }; + + ucbus_write(&sd->gspca_dev, &clkfreq_cmd, 1, 1); + + gpio_set(sd, SQ930_GPIO_POWER, 0xff00); +} + +static void cmos_probe(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i; + const struct sensor_s *sensor; + static const u8 probe_order[] = { +/* SENSOR_LZ24BP, (tested as ccd) */ + SENSOR_OV9630, + SENSOR_MI0360, + SENSOR_OV7660, + SENSOR_MT9V111, + }; + + for (i = 0; i < ARRAY_SIZE(probe_order); i++) { + sensor = &sensor_tb[probe_order[i]]; + ucbus_write(&sd->gspca_dev, sensor->cmd, sensor->cmd_len, 8); + gpio_init(sd, sensor->gpio); + msleep(100); + reg_r(gspca_dev, (sensor->i2c_addr << 8) | 0x001c, 1); + msleep(100); + if (gspca_dev->usb_buf[0] != 0) + break; + } + if (i >= ARRAY_SIZE(probe_order)) + PDEBUG(D_PROBE, "Unknown sensor"); + else + sd->sensor = probe_order[i]; +} + +static void mt9v111_init(struct gspca_dev *gspca_dev) +{ + int i, nwait; + static const u8 cmd_001b[] = { + 0x00, 0x3b, 0xf6, 0x01, 0x03, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00 + }; + static const u8 cmd_011b[][7] = { + {0x10, 0x01, 0x66, 0x08, 0x00, 0x00, 0x00}, + {0x01, 0x00, 0x1a, 0x04, 0x00, 0x00, 0x00}, + {0x20, 0x00, 0x10, 0x04, 0x00, 0x00, 0x00}, + {0x02, 0x01, 0xae, 0x01, 0x00, 0x00, 0x00}, + }; + + reg_wb(gspca_dev, 0x001b, 0x0000, cmd_001b, sizeof cmd_001b); + for (i = 0; i < ARRAY_SIZE(cmd_011b); i++) { + reg_wb(gspca_dev, 0x001b, 0x0000, cmd_011b[i], + ARRAY_SIZE(cmd_011b[0])); + msleep(400); + nwait = 20; + for (;;) { + reg_r(gspca_dev, 0x031b, 1); + if (gspca_dev->usb_buf[0] == 0 + || gspca_dev->usb_err != 0) + break; + if (--nwait < 0) { + PDEBUG(D_PROBE, "mt9v111_init timeout"); + gspca_dev->usb_err = -ETIME; + return; + } + msleep(50); + } + } +} + +static void global_init(struct sd *sd, int first_time) +{ + switch (sd->sensor) { + case SENSOR_ICX098BQ: + if (first_time) + ucbus_write(&sd->gspca_dev, + icx098bq_start_0, + 8, 8); + gpio_init(sd, sensor_tb[sd->sensor].gpio); + break; + case SENSOR_LZ24BP: + if (sd->type != Creative_live_motion) + gpio_set(sd, SQ930_GPIO_EXTRA1, 0x00ff); + else + gpio_set(sd, 0, 0x00ff); + msleep(50); + if (first_time) + ucbus_write(&sd->gspca_dev, + lz24bp_start_0, + 8, 8); + gpio_init(sd, sensor_tb[sd->sensor].gpio); + break; + case SENSOR_MI0360: + if (first_time) + ucbus_write(&sd->gspca_dev, + mi0360_start_0, + ARRAY_SIZE(mi0360_start_0), + 8); + gpio_init(sd, sensor_tb[sd->sensor].gpio); + gpio_set(sd, SQ930_GPIO_EXTRA2, SQ930_GPIO_EXTRA2); + break; + default: +/* case SENSOR_MT9V111: */ + if (first_time) + mt9v111_init(&sd->gspca_dev); + else + gpio_init(sd, sensor_tb[sd->sensor].gpio); + break; + } +} + +static void lz24bp_ppl(struct sd *sd, u16 ppl) +{ + struct ucbus_write_cmd cmds[2] = { + {0xf810, ppl >> 8}, + {0xf811, ppl} + }; + + ucbus_write(&sd->gspca_dev, cmds, ARRAY_SIZE(cmds), 2); +} + +static void setexposure(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i, integclks, intstartclk, frameclks, min_frclk; + const struct sensor_s *sensor; + u16 cmd; + u8 buf[15]; + + integclks = sd->expo; + i = 0; + cmd = SQ930_CTRL_SET_EXPOSURE; + + switch (sd->sensor) { + case SENSOR_ICX098BQ: /* ccd */ + case SENSOR_LZ24BP: + min_frclk = sd->sensor == SENSOR_ICX098BQ ? 0x210 : 0x26f; + if (integclks >= min_frclk) { + intstartclk = 0; + frameclks = integclks; + } else { + intstartclk = min_frclk - integclks; + frameclks = min_frclk; + } + buf[i++] = intstartclk >> 8; + buf[i++] = intstartclk; + buf[i++] = frameclks >> 8; + buf[i++] = frameclks; + buf[i++] = sd->gain; + break; + default: /* cmos */ +/* case SENSOR_MI0360: */ +/* case SENSOR_MT9V111: */ + cmd |= 0x0100; + sensor = &sensor_tb[sd->sensor]; + buf[i++] = sensor->i2c_addr; /* i2c_slave_addr */ + buf[i++] = 0x08; /* 2 * ni2c */ + buf[i++] = 0x09; /* reg = shutter width */ + buf[i++] = integclks >> 8; /* val H */ + buf[i++] = sensor->i2c_dum; + buf[i++] = integclks; /* val L */ + buf[i++] = 0x35; /* reg = global gain */ + buf[i++] = 0x00; /* val H */ + buf[i++] = sensor->i2c_dum; + buf[i++] = sd->gain; /* val L */ + buf[i++] = 0x00; + buf[i++] = 0x00; + buf[i++] = 0x00; + buf[i++] = 0x00; + buf[i++] = 0x83; + break; + } + reg_wb(gspca_dev, cmd, 0, buf, i); +} + +/* This function is called at probe time just before sd_init */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam = &gspca_dev->cam; + + sd->sensor = id->driver_info >> 8; + sd->type = id->driver_info; + + cam->cam_mode = vga_mode; + cam->nmodes = ARRAY_SIZE(vga_mode); + + cam->bulk = 1; + cam->bulk_size = BULK_TRANSFER_LEN; +/* cam->bulk_nurbs = 2; fixme: if no setexpo sync */ + + sd->quality = QUALITY_DEF; + sd->gain = GAIN_DEF; + sd->expo = EXPO_DEF; + + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->gpio[0] = sd->gpio[1] = 0xff; /* force gpio rewrite */ + +/*fixme: is this needed for icx098bp and mi0360? + if (sd->sensor != SENSOR_LZ24BP) + reg_w(gspca_dev, SQ930_CTRL_RESET, 0x0000); + */ + + reg_r(gspca_dev, SQ930_CTRL_GET_DEV_INFO, 8); +/* it returns: + * 03 00 12 93 0b f6 c9 00 live! ultra + * 03 00 07 93 0b f6 ca 00 live! ultra for notebook + * 03 00 12 93 0b fe c8 00 Trust WB-3500T + * 02 00 06 93 0b fe c8 00 Joy-IT 318S + * 03 00 12 93 0b f6 cf 00 icam tracer - sensor icx098bq + * 02 00 12 93 0b fe cf 00 ProQ Motion Webcam + * + * byte + * 0: 02 = usb 1.0 (12Mbit) / 03 = usb2.0 (480Mbit) + * 1: 00 + * 2: 06 / 07 / 12 = mode webcam? firmware?? + * 3: 93 chip = 930b (930b or 930c) + * 4: 0b + * 5: f6 = cdd (icx098bq, lz24bp) / fe or de = cmos (i2c) (other sensors) + * 6: c8 / c9 / ca / cf = mode webcam?, sensor? webcam? + * 7: 00 + */ + PDEBUG(D_PROBE, "info: %02x %02x %02x %02x %02x %02x %02x %02x", + gspca_dev->usb_buf[0], + gspca_dev->usb_buf[1], + gspca_dev->usb_buf[2], + gspca_dev->usb_buf[3], + gspca_dev->usb_buf[4], + gspca_dev->usb_buf[5], + gspca_dev->usb_buf[6], + gspca_dev->usb_buf[7]); + + bridge_init(sd); + + if (sd->sensor == SENSOR_MI0360) { + + /* no sensor probe for icam tracer */ + if (gspca_dev->usb_buf[5] == 0xf6) { /* if CMOS */ + sd->sensor = SENSOR_ICX098BQ; + gspca_dev->cam.cam_mode = &vga_mode[1]; + gspca_dev->cam.nmodes = 1; /* only 320x240 */ + } else { + cmos_probe(gspca_dev); + } + } + + PDEBUG(D_PROBE, "Sensor %s", sensor_tb[sd->sensor].name); + + global_init(sd, 1); + return gspca_dev->usb_err; +} + +/* special function to create the quantization tables of the JPEG header */ +static void sd_jpeg_set_qual(u8 *jpeg_hdr, + int quality) +{ + int i, sc1, sc2; + + quality = quality_tb[quality]; /* convert to JPEG quality */ +/* + * approximative qualities for Y and U/V: + * quant = 0:94%/91% 1:91%/87% 2:82%/73% 3:69%/56% + * should have: + * quant = 0:94%/91% 1:91%/87.5% 2:81.5%/72% 3:69%/54.5% + */ + sc1 = 200 - quality * 2; + quality = quality * 7 / 5 - 40; /* UV quality */ + sc2 = 200 - quality * 2; + for (i = 0; i < 64; i++) { + jpeg_hdr[JPEG_QT0_OFFSET + i] = + (jpeg_head[JPEG_QT0_OFFSET + i] * sc1 + 50) / 100; + jpeg_hdr[JPEG_QT1_OFFSET + i] = + (jpeg_head[JPEG_QT1_OFFSET + i] * sc2 + 50) / 100; + } +} + +/* send the start/stop commands to the webcam */ +static void send_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + const struct cap_s *cap; + int mode, quality; + + mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; + cap = &capconfig[sd->sensor][mode]; + quality = sd->quality; + reg_wb(gspca_dev, (quality << 12) + | 0x0a00 /* 900 for Bayer */ + | SQ930_CTRL_CAP_START, + 0x0500 /* a00 for Bayer */ + | cap->cc_sizeid, + cap->cc_bytes, 32); +}; +static void send_stop(struct gspca_dev *gspca_dev) +{ + reg_w(gspca_dev, SQ930_CTRL_CAP_STOP, 0); +}; + +/* function called at start time before URB creation */ +static int sd_isoc_init(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + gspca_dev->cam.bulk_nurbs = 1; /* there must be one URB only */ + sd->do_ctrl = 0; + return 0; +} + +/* start the capture */ +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int mode; + + /* initialize the JPEG header */ + jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, + 0x21); /* JPEG 422 */ + sd_jpeg_set_qual(sd->jpeg_hdr, sd->quality); + + bridge_init(sd); + global_init(sd, 0); + msleep(100); + + switch (sd->sensor) { + case SENSOR_ICX098BQ: + ucbus_write(gspca_dev, icx098bq_start_0, + ARRAY_SIZE(icx098bq_start_0), + 8); + ucbus_write(gspca_dev, icx098bq_start_1, + ARRAY_SIZE(icx098bq_start_1), + 5); + ucbus_write(gspca_dev, icx098bq_start_2, + ARRAY_SIZE(icx098bq_start_2), + 6); + msleep(50); + + /* 1st start */ + send_start(gspca_dev); + gpio_set(sd, SQ930_GPIO_EXTRA2 | SQ930_GPIO_RSTBAR, 0x00ff); + msleep(70); + reg_w(gspca_dev, SQ930_CTRL_CAP_STOP, 0x0000); + gpio_set(sd, 0x7f, 0x00ff); + + /* 2nd start */ + send_start(gspca_dev); + gpio_set(sd, SQ930_GPIO_EXTRA2 | SQ930_GPIO_RSTBAR, 0x00ff); + goto out; + case SENSOR_LZ24BP: + ucbus_write(gspca_dev, lz24bp_start_0, + ARRAY_SIZE(lz24bp_start_0), + 8); + if (sd->type != Creative_live_motion) + ucbus_write(gspca_dev, lz24bp_start_1_gen, + ARRAY_SIZE(lz24bp_start_1_gen), + 5); + else + ucbus_write(gspca_dev, lz24bp_start_1_clm, + ARRAY_SIZE(lz24bp_start_1_clm), + 5); + ucbus_write(gspca_dev, lz24bp_start_2, + ARRAY_SIZE(lz24bp_start_2), + 6); + mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; + lz24bp_ppl(sd, mode == 2 ? 0x0564 : 0x0310); + msleep(10); + break; + case SENSOR_MI0360: + ucbus_write(gspca_dev, mi0360_start_0, + ARRAY_SIZE(mi0360_start_0), + 8); + i2c_write(sd, mi0360_init_23, + ARRAY_SIZE(mi0360_init_23)); + i2c_write(sd, mi0360_init_24, + ARRAY_SIZE(mi0360_init_24)); + i2c_write(sd, mi0360_init_25, + ARRAY_SIZE(mi0360_init_25)); + ucbus_write(gspca_dev, mi0360_start_1, + ARRAY_SIZE(mi0360_start_1), + 5); + i2c_write(sd, mi0360_start_2, + ARRAY_SIZE(mi0360_start_2)); + i2c_write(sd, mi0360_start_3, + ARRAY_SIZE(mi0360_start_3)); + + /* 1st start */ + send_start(gspca_dev); + msleep(60); + reg_w(gspca_dev, SQ930_CTRL_CAP_STOP, 0x0000); + + i2c_write(sd, + mi0360_start_4, ARRAY_SIZE(mi0360_start_4)); + break; + default: +/* case SENSOR_MT9V111: */ + ucbus_write(gspca_dev, mi0360_start_0, + ARRAY_SIZE(mi0360_start_0), + 8); + i2c_write(sd, mt9v111_init_0, + ARRAY_SIZE(mt9v111_init_0)); + i2c_write(sd, mt9v111_init_1, + ARRAY_SIZE(mt9v111_init_1)); + i2c_write(sd, mt9v111_init_2, + ARRAY_SIZE(mt9v111_init_2)); + ucbus_write(gspca_dev, mt9v111_start_1, + ARRAY_SIZE(mt9v111_start_1), + 8); + i2c_write(sd, mt9v111_init_3, + ARRAY_SIZE(mt9v111_init_3)); + i2c_write(sd, mt9v111_init_4, + ARRAY_SIZE(mt9v111_init_4)); + break; + } + + send_start(gspca_dev); +out: + msleep(1000); + + sd->eof_len = 0; /* init packet scan */ + + if (sd->sensor == SENSOR_MT9V111) + gpio_set(sd, SQ930_GPIO_DFL_LED, SQ930_GPIO_DFL_LED); + + sd->do_ctrl = 1; /* set the exposure */ + + return gspca_dev->usb_err; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->sensor == SENSOR_MT9V111) + gpio_set(sd, 0, SQ930_GPIO_DFL_LED); + send_stop(gspca_dev); +} + +/* function called when the application gets a new frame */ +/* It sets the exposure if required and restart the bulk transfer. */ +static void sd_dq_callback(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int ret; + + if (!sd->do_ctrl || gspca_dev->cam.bulk_nurbs != 0) + return; + sd->do_ctrl = 0; + + setexposure(gspca_dev); + + gspca_dev->cam.bulk_nurbs = 1; + ret = usb_submit_urb(gspca_dev->urb[0], GFP_ATOMIC); + if (ret < 0) + PDEBUG(D_ERR|D_PACK, "sd_dq_callback() err %d", ret); + + /* wait a little time, otherwise the webcam crashes */ + msleep(100); +} + +/* move a packet adding 0x00 after 0xff */ +static void add_packet(struct gspca_dev *gspca_dev, + u8 *data, + int len) +{ + int i; + + i = 0; + do { + if (data[i] == 0xff) { + gspca_frame_add(gspca_dev, INTER_PACKET, + data, i + 1); + len -= i; + data += i; + *data = 0x00; + i = 0; + } + } while (++i < len); + gspca_frame_add(gspca_dev, INTER_PACKET, data, len); +} + +/* end a frame and start a new one */ +static void eof_sof(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + static const u8 ffd9[] = {0xff, 0xd9}; + + /* if control set, stop bulk transfer */ + if (sd->do_ctrl + && gspca_dev->last_packet_type == INTER_PACKET) + gspca_dev->cam.bulk_nurbs = 0; + gspca_frame_add(gspca_dev, LAST_PACKET, + ffd9, 2); + gspca_frame_add(gspca_dev, FIRST_PACKET, + sd->jpeg_hdr, JPEG_HDR_SZ); +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 *p; + int l; + + len -= 8; /* ignore last 8 bytes (00 00 55 aa 55 aa 00 00) */ + + /* + * the end/start of frame is indicated by + * 0x00 * 16 - 0xab * 8 + * aligned on 8 bytes boundary + */ + if (sd->eof_len != 0) { /* if 'abababab' in previous pkt */ + if (*((u32 *) data) == 0xabababab) { + /*fixme: should remove previous 0000ababab*/ + eof_sof(gspca_dev); + data += 4; + len -= 4; + } + sd->eof_len = 0; + } + p = data; + l = len; + for (;;) { + if (*((u32 *) p) == 0xabababab) { + if (l < 8) { /* (may be 4 only) */ + sd->eof_len = 1; + break; + } + if (*((u32 *) p + 1) == 0xabababab) { + add_packet(gspca_dev, data, p - data - 16); + /* remove previous zeros */ + eof_sof(gspca_dev); + p += 8; + l -= 8; + if (l <= 0) + return; + len = l; + data = p; + continue; + } + } + p += 4; + l -= 4; + if (l <= 0) + break; + } + add_packet(gspca_dev, data, len); +} + +static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->gain = val; + if (gspca_dev->streaming) + sd->do_ctrl = 1; + return 0; +} + +static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->gain; + return 0; +} +static int sd_setexpo(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->expo = val; + if (gspca_dev->streaming) + sd->do_ctrl = 1; + return 0; +} + +static int sd_getexpo(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->expo; + return 0; +} + +static int sd_set_jcomp(struct gspca_dev *gspca_dev, + struct v4l2_jpegcompression *jcomp) +{ + struct sd *sd = (struct sd *) gspca_dev; + int quality; + + if (jcomp->quality >= (QUAL_0 + QUAL_1) / 2) + quality = 0; + else if (jcomp->quality >= (QUAL_1 + QUAL_2) / 2) + quality = 1; + else if (jcomp->quality >= (QUAL_2 + QUAL_3) / 2) + quality = 2; + else + quality = 3; + + if (quality != sd->quality) { + sd->quality = quality; + if (gspca_dev->streaming) { + send_stop(gspca_dev); + sd_jpeg_set_qual(sd->jpeg_hdr, sd->quality); + msleep(70); + send_start(gspca_dev); + } + } + return gspca_dev->usb_err; +} + +static int sd_get_jcomp(struct gspca_dev *gspca_dev, + struct v4l2_jpegcompression *jcomp) +{ + struct sd *sd = (struct sd *) gspca_dev; + + memset(jcomp, 0, sizeof *jcomp); + jcomp->quality = quality_tb[sd->quality]; + jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT + | V4L2_JPEG_MARKER_DQT; + return 0; +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .isoc_init = sd_isoc_init, + .start = sd_start, + .stopN = sd_stopN, + .pkt_scan = sd_pkt_scan, + .dq_callback = sd_dq_callback, + .get_jcomp = sd_get_jcomp, + .set_jcomp = sd_set_jcomp, +}; + +/* Table of supported USB devices */ +#define ST(sensor, type) \ + .driver_info = (SENSOR_ ## sensor << 8) \ + | (type) +static const __devinitdata struct usb_device_id device_table[] = { + {USB_DEVICE(0x041e, 0x4038), ST(MI0360, 0)}, + {USB_DEVICE(0x041e, 0x403c), ST(LZ24BP, 0)}, + {USB_DEVICE(0x041e, 0x403d), ST(LZ24BP, 0)}, + {USB_DEVICE(0x041e, 0x4041), ST(LZ24BP, Creative_live_motion)}, + {USB_DEVICE(0x2770, 0x930b), ST(MI0360, 0)}, + {USB_DEVICE(0x2770, 0x930c), ST(MI0360, 0)}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + int ret; + + ret = usb_register(&sd_driver); + if (ret < 0) + return ret; + info("registered"); + return 0; +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); + info("deregistered"); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff --git a/drivers/media/video/gspca/stk014.c b/drivers/media/video/gspca/stk014.c index 0fb534210a2..2aedf4b1bfa 100644 --- a/drivers/media/video/gspca/stk014.c +++ b/drivers/media/video/gspca/stk014.c @@ -36,11 +36,11 @@ struct sd { unsigned char colors; unsigned char lightfreq; u8 quality; -#define QUALITY_MIN 60 +#define QUALITY_MIN 70 #define QUALITY_MAX 95 -#define QUALITY_DEF 80 +#define QUALITY_DEF 88 - u8 *jpeg_hdr; + u8 jpeg_hdr[JPEG_HDR_SZ]; }; /* V4L2 controls supported by the driver */ @@ -337,9 +337,6 @@ static int sd_start(struct gspca_dev *gspca_dev) int ret, value; /* create the JPEG header */ - sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL); - if (!sd->jpeg_hdr) - return -ENOMEM; jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, 0x22); /* JPEG 411 */ jpeg_set_qual(sd->jpeg_hdr, sd->quality); @@ -412,13 +409,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev) PDEBUG(D_STREAM, "camera stopped"); } -static void sd_stop0(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - kfree(sd->jpeg_hdr); -} - static void sd_pkt_scan(struct gspca_dev *gspca_dev, u8 *data, /* isoc packet */ int len) /* iso packet length */ @@ -578,7 +568,6 @@ static const struct sd_desc sd_desc = { .init = sd_init, .start = sd_start, .stopN = sd_stopN, - .stop0 = sd_stop0, .pkt_scan = sd_pkt_scan, .querymenu = sd_querymenu, .get_jcomp = sd_get_jcomp, diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.h b/drivers/media/video/gspca/stv06xx/stv06xx.h index 992ce530f13..053a27e3a40 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx.h +++ b/drivers/media/video/gspca/stv06xx/stv06xx.h @@ -30,6 +30,7 @@ #ifndef STV06XX_H_ #define STV06XX_H_ +#include <linux/slab.h> #include "gspca.h" #define MODULE_NAME "STV06xx" diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c index 0c786e00ebc..21d82bab0c2 100644 --- a/drivers/media/video/gspca/sunplus.c +++ b/drivers/media/video/gspca/sunplus.c @@ -54,7 +54,7 @@ struct sd { #define MegapixV4 4 #define MegaImageVI 5 - u8 *jpeg_hdr; + u8 jpeg_hdr[JPEG_HDR_SZ]; }; /* V4L2 controls supported by the driver */ @@ -842,9 +842,6 @@ static int sd_start(struct gspca_dev *gspca_dev) int enable; /* create the JPEG header */ - sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL); - if (!sd->jpeg_hdr) - return -ENOMEM; jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, 0x22); /* JPEG 411 */ jpeg_set_qual(sd->jpeg_hdr, sd->quality); @@ -954,13 +951,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev) } } -static void sd_stop0(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - kfree(sd->jpeg_hdr); -} - static void sd_pkt_scan(struct gspca_dev *gspca_dev, u8 *data, /* isoc packet */ int len) /* iso packet length */ @@ -1162,7 +1152,6 @@ static const struct sd_desc sd_desc = { .init = sd_init, .start = sd_start, .stopN = sd_stopN, - .stop0 = sd_stop0, .pkt_scan = sd_pkt_scan, .get_jcomp = sd_get_jcomp, .set_jcomp = sd_set_jcomp, diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/video/gspca/t613.c index 63014372adb..2a0f12d55e4 100644 --- a/drivers/media/video/gspca/t613.c +++ b/drivers/media/video/gspca/t613.c @@ -1,5 +1,7 @@ /* - * V4L2 by Jean-Francois Moine <http://moinejf.free.fr> + * T613 subdriver + * + * Copyright (C) 2010 Jean-Francois Moine (http://moinejf.free.fr) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,6 +28,7 @@ #define MODULE_NAME "t613" +#include <linux/slab.h> #include "gspca.h" #define V4L2_CID_EFFECTS (V4L2_CID_PRIVATE_BASE + 0) @@ -44,18 +47,20 @@ struct sd { u8 gamma; u8 sharpness; u8 freq; - u8 red_balance; /* split balance */ - u8 blue_balance; - u8 global_gain; /* aka gain */ - u8 whitebalance; /* set default r/g/b and activate */ + u8 red_gain; + u8 blue_gain; + u8 green_gain; + u8 awb; /* set default r/g/b and activate */ u8 mirror; u8 effect; u8 sensor; -#define SENSOR_OM6802 0 -#define SENSOR_OTHER 1 -#define SENSOR_TAS5130A 2 -#define SENSOR_LT168G 3 /* must verify if this is the actual model */ +enum { + SENSOR_OM6802, + SENSOR_OTHER, + SENSOR_TAS5130A, + SENSOR_LT168G, /* must verify if this is the actual model */ +} sensors; }; /* V4L2 controls supported by the driver */ @@ -74,24 +79,22 @@ static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val); static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val); static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val); - -static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setblue_balance(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getblue_balance(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setred_balance(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getred_balance(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setglobal_gain(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getglobal_gain(struct gspca_dev *gspca_dev, __s32 *val); - -static int sd_setflip(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getflip(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setawb(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getawb(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setblue_gain(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getblue_gain(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setred_gain(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getred_gain(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); + +static int sd_setmirror(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getmirror(struct gspca_dev *gspca_dev, __s32 *val); static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val); static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val); static int sd_querymenu(struct gspca_dev *gspca_dev, struct v4l2_querymenu *menu); - static const struct ctrl sd_ctrls[] = { { { @@ -177,8 +180,8 @@ static const struct ctrl sd_ctrls[] = { #define MIRROR_DEF 0 .default_value = MIRROR_DEF, }, - .set = sd_setflip, - .get = sd_getflip + .set = sd_setmirror, + .get = sd_getmirror }, { { @@ -198,15 +201,15 @@ static const struct ctrl sd_ctrls[] = { { .id = V4L2_CID_AUTO_WHITE_BALANCE, .type = V4L2_CTRL_TYPE_INTEGER, - .name = "White Balance", + .name = "Auto White Balance", .minimum = 0, .maximum = 1, .step = 1, -#define WHITE_BALANCE_DEF 0 - .default_value = WHITE_BALANCE_DEF, +#define AWB_DEF 0 + .default_value = AWB_DEF, }, - .set = sd_setwhitebalance, - .get = sd_getwhitebalance + .set = sd_setawb, + .get = sd_getawb }, { { @@ -244,11 +247,11 @@ static const struct ctrl sd_ctrls[] = { .minimum = 0x10, .maximum = 0x40, .step = 1, -#define BLUE_BALANCE_DEF 0x20 - .default_value = BLUE_BALANCE_DEF, +#define BLUE_GAIN_DEF 0x20 + .default_value = BLUE_GAIN_DEF, }, - .set = sd_setblue_balance, - .get = sd_getblue_balance, + .set = sd_setblue_gain, + .get = sd_getblue_gain, }, { { @@ -258,11 +261,11 @@ static const struct ctrl sd_ctrls[] = { .minimum = 0x10, .maximum = 0x40, .step = 1, -#define RED_BALANCE_DEF 0x20 - .default_value = RED_BALANCE_DEF, +#define RED_GAIN_DEF 0x20 + .default_value = RED_GAIN_DEF, }, - .set = sd_setred_balance, - .get = sd_getred_balance, + .set = sd_setred_gain, + .get = sd_getred_gain, }, { { @@ -272,24 +275,14 @@ static const struct ctrl sd_ctrls[] = { .minimum = 0x10, .maximum = 0x40, .step = 1, -#define global_gain_DEF 0x20 - .default_value = global_gain_DEF, +#define GAIN_DEF 0x20 + .default_value = GAIN_DEF, }, - .set = sd_setglobal_gain, - .get = sd_getglobal_gain, + .set = sd_setgain, + .get = sd_getgain, }, }; -static char *effects_control[] = { - "Normal", - "Emboss", /* disabled */ - "Monochrome", - "Sepia", - "Sketch", - "Sun Effect", /* disabled */ - "Negative", -}; - static const struct v4l2_pix_format vga_mode_t16[] = { {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 160, @@ -327,7 +320,6 @@ struct additional_sensor_data { const u8 data1[10]; const u8 data2[9]; const u8 data3[9]; - const u8 data4[4]; const u8 data5[6]; const u8 stream[4]; }; @@ -375,7 +367,7 @@ static const u8 n4_lt168g[] = { }; static const struct additional_sensor_data sensor_data[] = { - { /* 0: OM6802 */ +[SENSOR_OM6802] = { .n3 = {0x61, 0x68, 0x65, 0x0a, 0x60, 0x04}, .n4 = n4_om6802, @@ -392,14 +384,12 @@ static const struct additional_sensor_data sensor_data[] = { .data3 = {0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff, 0xff}, - .data4 = /*Freq (50/60Hz). Splitted for test purpose */ - {0x66, 0xca, 0xa8, 0xf0}, .data5 = /* this could be removed later */ {0x0c, 0x03, 0xab, 0x13, 0x81, 0x23}, .stream = {0x0b, 0x04, 0x0a, 0x78}, }, - { /* 1: OTHER */ +[SENSOR_OTHER] = { .n3 = {0x61, 0xc2, 0x65, 0x88, 0x60, 0x00}, .n4 = n4_other, @@ -416,14 +406,12 @@ static const struct additional_sensor_data sensor_data[] = { .data3 = {0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96, 0xd9}, - .data4 = - {0x66, 0x00, 0xa8, 0xa8}, .data5 = {0x0c, 0x03, 0xab, 0x29, 0x81, 0x69}, .stream = {0x0b, 0x04, 0x0a, 0x00}, }, - { /* 2: TAS5130A */ +[SENSOR_TAS5130A] = { .n3 = {0x61, 0xc2, 0x65, 0x0d, 0x60, 0x08}, .n4 = n4_tas5130a, @@ -440,14 +428,12 @@ static const struct additional_sensor_data sensor_data[] = { .data3 = {0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0}, - .data4 = /* Freq (50/60Hz). Splitted for test purpose */ - {0x66, 0x00, 0xa8, 0xe8}, .data5 = {0x0c, 0x03, 0xab, 0x10, 0x81, 0x20}, .stream = {0x0b, 0x04, 0x0a, 0x40}, }, - { /* 3: LT168G */ +[SENSOR_LT168G] = { .n3 = {0x61, 0xc2, 0x65, 0x68, 0x60, 0x00}, .n4 = n4_lt168g, .n4sz = sizeof n4_lt168g, @@ -460,7 +446,6 @@ static const struct additional_sensor_data sensor_data[] = { 0xff}, .data3 = {0x40, 0x80, 0xc0, 0x50, 0xa0, 0xf0, 0x53, 0xa6, 0xff}, - .data4 = {0x66, 0x41, 0xa8, 0xf0}, .data5 = {0x0c, 0x03, 0xab, 0x4b, 0x81, 0x2b}, .stream = {0x0b, 0x04, 0x0a, 0x28}, }, @@ -469,6 +454,15 @@ static const struct additional_sensor_data sensor_data[] = { #define MAX_EFFECTS 7 /* easily done by soft, this table could be removed, * i keep it here just in case */ +static char *effects_control[MAX_EFFECTS] = { + "Normal", + "Emboss", /* disabled */ + "Monochrome", + "Sepia", + "Sketch", + "Sun Effect", /* disabled */ + "Negative", +}; static const u8 effects_table[MAX_EFFECTS][6] = { {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x00}, /* Normal */ {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x04}, /* Repujar */ @@ -480,40 +474,41 @@ static const u8 effects_table[MAX_EFFECTS][6] = { }; static const u8 gamma_table[GAMMA_MAX][17] = { - {0x00, 0x3e, 0x69, 0x85, 0x95, 0xa1, 0xae, 0xb9, /* 0 */ - 0xc2, 0xcb, 0xd4, 0xdb, 0xe3, 0xea, 0xf1, 0xf8, +/* gamma table from cam1690.ini */ + {0x00, 0x00, 0x01, 0x04, 0x08, 0x0e, 0x16, 0x21, /* 0 */ + 0x2e, 0x3d, 0x50, 0x65, 0x7d, 0x99, 0xb8, 0xdb, 0xff}, - {0x00, 0x33, 0x5a, 0x75, 0x85, 0x93, 0xa1, 0xad, /* 1 */ - 0xb7, 0xc2, 0xcb, 0xd4, 0xde, 0xe7, 0xf0, 0xf7, + {0x00, 0x01, 0x03, 0x08, 0x0e, 0x16, 0x21, 0x2d, /* 1 */ + 0x3c, 0x4d, 0x60, 0x75, 0x8d, 0xa6, 0xc2, 0xe1, 0xff}, - {0x00, 0x2f, 0x51, 0x6b, 0x7c, 0x8a, 0x99, 0xa6, /* 2 */ - 0xb1, 0xbc, 0xc6, 0xd0, 0xdb, 0xe4, 0xed, 0xf6, + {0x00, 0x01, 0x05, 0x0b, 0x12, 0x1c, 0x28, 0x35, /* 2 */ + 0x45, 0x56, 0x69, 0x7e, 0x95, 0xad, 0xc7, 0xe3, 0xff}, - {0x00, 0x29, 0x48, 0x60, 0x72, 0x81, 0x90, 0x9e, /* 3 */ - 0xaa, 0xb5, 0xbf, 0xcb, 0xd6, 0xe1, 0xeb, 0xf5, + {0x00, 0x02, 0x07, 0x0f, 0x18, 0x24, 0x30, 0x3f, /* 3 */ + 0x4f, 0x61, 0x73, 0x88, 0x9d, 0xb4, 0xcd, 0xe6, 0xff}, - {0x00, 0x23, 0x3f, 0x55, 0x68, 0x77, 0x86, 0x95, /* 4 */ - 0xa2, 0xad, 0xb9, 0xc6, 0xd2, 0xde, 0xe9, 0xf4, + {0x00, 0x04, 0x0B, 0x15, 0x20, 0x2d, 0x3b, 0x4a, /* 4 */ + 0x5b, 0x6c, 0x7f, 0x92, 0xa7, 0xbc, 0xd2, 0xe9, 0xff}, - {0x00, 0x1b, 0x33, 0x48, 0x59, 0x69, 0x79, 0x87, /* 5 */ - 0x96, 0xa3, 0xb1, 0xbe, 0xcc, 0xda, 0xe7, 0xf3, + {0x00, 0x07, 0x11, 0x15, 0x20, 0x2d, 0x48, 0x58, /* 5 */ + 0x68, 0x79, 0x8b, 0x9d, 0xb0, 0xc4, 0xd7, 0xec, 0xff}, - {0x00, 0x02, 0x10, 0x20, 0x32, 0x40, 0x57, 0x67, /* 6 */ + {0x00, 0x0c, 0x1a, 0x29, 0x38, 0x47, 0x57, 0x67, /* 6 */ 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}, - {0x00, 0x02, 0x14, 0x26, 0x38, 0x4a, 0x60, 0x70, /* 7 */ + {0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, /* 7 */ 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0xff}, - {0x00, 0x10, 0x22, 0x35, 0x47, 0x5a, 0x69, 0x79, /* 8 */ - 0x88, 0x97, 0xa7, 0xb6, 0xc4, 0xd3, 0xe0, 0xf0, + {0x00, 0x15, 0x27, 0x38, 0x49, 0x59, 0x69, 0x79, /* 8 */ + 0x88, 0x97, 0xa7, 0xb6, 0xc4, 0xd3, 0xe2, 0xf0, 0xff}, - {0x00, 0x10, 0x26, 0x40, 0x54, 0x65, 0x75, 0x84, /* 9 */ - 0x93, 0xa1, 0xb0, 0xbd, 0xca, 0xd6, 0xe0, 0xf0, + {0x00, 0x1c, 0x30, 0x43, 0x54, 0x65, 0x75, 0x84, /* 9 */ + 0x93, 0xa1, 0xb0, 0xbd, 0xca, 0xd8, 0xe5, 0xf2, 0xff}, - {0x00, 0x18, 0x2b, 0x44, 0x60, 0x70, 0x80, 0x8e, /* 10 */ - 0x9c, 0xaa, 0xb7, 0xc4, 0xd0, 0xd8, 0xe2, 0xf0, + {0x00, 0x24, 0x3b, 0x4f, 0x60, 0x70, 0x80, 0x8e, /* 10 */ + 0x9c, 0xaa, 0xb7, 0xc4, 0xd0, 0xdc, 0xe8, 0xf3, 0xff}, - {0x00, 0x1a, 0x34, 0x52, 0x66, 0x7e, 0x8d, 0x9b, /* 11 */ + {0x00, 0x2a, 0x3c, 0x5d, 0x6e, 0x7e, 0x8d, 0x9b, /* 11 */ 0xa8, 0xb4, 0xc0, 0xcb, 0xd6, 0xe1, 0xeb, 0xf5, 0xff}, {0x00, 0x3f, 0x5a, 0x6e, 0x7f, 0x8e, 0x9c, 0xa8, /* 12 */ @@ -577,12 +572,11 @@ static void reg_w_buf(struct gspca_dev *gspca_dev, } else { u8 *tmpbuf; - tmpbuf = kmalloc(len, GFP_KERNEL); + tmpbuf = kmemdup(buffer, len, GFP_KERNEL); if (!tmpbuf) { err("Out of memory"); return; } - memcpy(tmpbuf, buffer, len); usb_control_msg(gspca_dev->dev, usb_sndctrlpipe(gspca_dev->dev, 0), 0, @@ -625,7 +619,6 @@ static void reg_w_ixbuf(struct gspca_dev *gspca_dev, kfree(tmpbuf); } -/* Reported as OM6802*/ static void om6802_sensor_init(struct gspca_dev *gspca_dev) { int i; @@ -703,12 +696,12 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->autogain = AUTOGAIN_DEF; sd->mirror = MIRROR_DEF; sd->freq = FREQ_DEF; - sd->whitebalance = WHITE_BALANCE_DEF; + sd->awb = AWB_DEF; sd->sharpness = SHARPNESS_DEF; sd->effect = EFFECTS_DEF; - sd->red_balance = RED_BALANCE_DEF; - sd->blue_balance = BLUE_BALANCE_DEF; - sd->global_gain = global_gain_DEF; + sd->red_gain = RED_GAIN_DEF; + sd->blue_gain = BLUE_GAIN_DEF; + sd->green_gain = GAIN_DEF * 3 - RED_GAIN_DEF - BLUE_GAIN_DEF; return 0; } @@ -761,40 +754,59 @@ static void setgamma(struct gspca_dev *gspca_dev) reg_w_ixbuf(gspca_dev, 0x90, gamma_table[sd->gamma], sizeof gamma_table[0]); } -static void setglobalgain(struct gspca_dev *gspca_dev) -{ +static void setRGB(struct gspca_dev *gspca_dev) +{ struct sd *sd = (struct sd *) gspca_dev; - reg_w(gspca_dev, (sd->red_balance << 8) + 0x87); - reg_w(gspca_dev, (sd->blue_balance << 8) + 0x88); - reg_w(gspca_dev, (sd->global_gain << 8) + 0x89); + u8 all_gain_reg[6] = + {0x87, 0x00, 0x88, 0x00, 0x89, 0x00}; + + all_gain_reg[1] = sd->red_gain; + all_gain_reg[3] = sd->blue_gain; + all_gain_reg[5] = sd->green_gain; + reg_w_buf(gspca_dev, all_gain_reg, sizeof all_gain_reg); } -/* Generic fnc for r/b balance, exposure and whitebalance */ -static void setbalance(struct gspca_dev *gspca_dev) +/* Generic fnc for r/b balance, exposure and awb */ +static void setawb(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; + u16 reg80; - /* on whitebalance leave defaults values */ - if (sd->whitebalance) { - reg_w(gspca_dev, 0x3c80); - } else { - reg_w(gspca_dev, 0x3880); + reg80 = (sensor_data[sd->sensor].reg80 << 8) | 0x80; + + /* on awb leave defaults values */ + if (!sd->awb) { /* shoud we wait here.. */ - /* update and reset 'global gain' with webcam parameters */ - sd->red_balance = reg_r(gspca_dev, 0x0087); - sd->blue_balance = reg_r(gspca_dev, 0x0088); - sd->global_gain = reg_r(gspca_dev, 0x0089); - setglobalgain(gspca_dev); + /* update and reset RGB gains with webcam values */ + sd->red_gain = reg_r(gspca_dev, 0x0087); + sd->blue_gain = reg_r(gspca_dev, 0x0088); + sd->green_gain = reg_r(gspca_dev, 0x0089); + reg80 &= ~0x0400; /* AWB off */ } - + reg_w(gspca_dev, reg80); + reg_w(gspca_dev, reg80); } - - -static void setwhitebalance(struct gspca_dev *gspca_dev) +static void init_gains(struct gspca_dev *gspca_dev) { - setbalance(gspca_dev); + struct sd *sd = (struct sd *) gspca_dev; + u16 reg80; + u8 all_gain_reg[8] = + {0x87, 0x00, 0x88, 0x00, 0x89, 0x00, 0x80, 0x00}; + + all_gain_reg[1] = sd->red_gain; + all_gain_reg[3] = sd->blue_gain; + all_gain_reg[5] = sd->green_gain; + reg80 = sensor_data[sd->sensor].reg80; + if (!sd->awb) + reg80 &= ~0x04; + all_gain_reg[7] = reg80; + reg_w_buf(gspca_dev, all_gain_reg, sizeof all_gain_reg); + + reg_w(gspca_dev, (sd->red_gain << 8) + 0x87); + reg_w(gspca_dev, (sd->blue_gain << 8) + 0x88); + reg_w(gspca_dev, (sd->green_gain << 8) + 0x89); } static void setsharpness(struct gspca_dev *gspca_dev) @@ -807,6 +819,38 @@ static void setsharpness(struct gspca_dev *gspca_dev) reg_w(gspca_dev, reg_to_write); } +static void setfreq(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 reg66; + u8 freq[4] = { 0x66, 0x00, 0xa8, 0xe8 }; + + switch (sd->sensor) { + case SENSOR_LT168G: + if (sd->freq != 0) + freq[3] = 0xa8; + reg66 = 0x41; + break; + case SENSOR_OM6802: + reg66 = 0xca; + break; + default: + reg66 = 0x40; + break; + } + switch (sd->freq) { + case 0: /* no flicker */ + freq[3] = 0xf0; + break; + case 2: /* 60Hz */ + reg66 &= ~0x40; + break; + } + freq[1] = reg66; + + reg_w_buf(gspca_dev, freq, sizeof freq); +} + /* this function is called at probe and resume time */ static int sd_init(struct gspca_dev *gspca_dev) { @@ -901,13 +945,9 @@ static int sd_init(struct gspca_dev *gspca_dev) setgamma(gspca_dev); setcolors(gspca_dev); setsharpness(gspca_dev); - setwhitebalance(gspca_dev); - - reg_w(gspca_dev, 0x2087); /* tied to white balance? */ - reg_w(gspca_dev, 0x2088); - reg_w(gspca_dev, 0x2089); + init_gains(gspca_dev); + setfreq(gspca_dev); - reg_w_buf(gspca_dev, sensor->data4, sizeof sensor->data4); reg_w_buf(gspca_dev, sensor->data5, sizeof sensor->data5); reg_w_buf(gspca_dev, sensor->nset8, sizeof sensor->nset8); reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream); @@ -926,16 +966,16 @@ static int sd_init(struct gspca_dev *gspca_dev) return 0; } -static void setflip(struct gspca_dev *gspca_dev) +static void setmirror(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - u8 flipcmd[8] = + u8 hflipcmd[8] = {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09}; if (sd->mirror) - flipcmd[3] = 0x01; + hflipcmd[3] = 0x01; - reg_w_buf(gspca_dev, flipcmd, sizeof flipcmd); + reg_w_buf(gspca_dev, hflipcmd, sizeof hflipcmd); } static void seteffect(struct gspca_dev *gspca_dev) @@ -956,17 +996,6 @@ static void seteffect(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0xfaa6); } -static void setlightfreq(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 freq[4] = { 0x66, 0x40, 0xa8, 0xe8 }; - - if (sd->freq == 2) /* 60hz */ - freq[1] = 0x00; - - reg_w_buf(gspca_dev, freq, sizeof freq); -} - /* Is this really needed? * i added some module parameters for test with some users */ static void poll_sensor(struct gspca_dev *gspca_dev) @@ -979,9 +1008,7 @@ static void poll_sensor(struct gspca_dev *gspca_dev) static const u8 poll2[] = {0x67, 0x02, 0x68, 0x71, 0x69, 0x72, 0x72, 0xa9, 0x73, 0x02, 0x73, 0x02, 0x60, 0x14}; - static const u8 poll3[] = - {0x87, 0x3f, 0x88, 0x20, 0x89, 0x2d}; - static const u8 poll4[] = + static const u8 noise03[] = /* (some differences / ms-drv) */ {0xa6, 0x0a, 0xea, 0xcf, 0xbe, 0x26, 0xb1, 0x5f, 0xa1, 0xb1, 0xda, 0x6b, 0xdb, 0x98, 0xdf, 0x0c, 0xc2, 0x80, 0xc3, 0x10}; @@ -989,8 +1016,7 @@ static void poll_sensor(struct gspca_dev *gspca_dev) PDEBUG(D_STREAM, "[Sensor requires polling]"); reg_w_buf(gspca_dev, poll1, sizeof poll1); reg_w_buf(gspca_dev, poll2, sizeof poll2); - reg_w_buf(gspca_dev, poll3, sizeof poll3); - reg_w_buf(gspca_dev, poll4, sizeof poll4); + reg_w_buf(gspca_dev, noise03, sizeof noise03); } static int sd_start(struct gspca_dev *gspca_dev) @@ -1025,12 +1051,7 @@ static int sd_start(struct gspca_dev *gspca_dev) case SENSOR_OM6802: om6802_sensor_init(gspca_dev); break; - case SENSOR_LT168G: - break; - case SENSOR_OTHER: - break; - default: -/* case SENSOR_TAS5130A: */ + case SENSOR_TAS5130A: i = 0; for (;;) { reg_w_buf(gspca_dev, tas5130a_sensor_init[i], @@ -1047,7 +1068,7 @@ static int sd_start(struct gspca_dev *gspca_dev) break; } sensor = &sensor_data[sd->sensor]; - reg_w_buf(gspca_dev, sensor->data4, sizeof sensor->data4); + setfreq(gspca_dev); reg_r(gspca_dev, 0x0012); reg_w_buf(gspca_dev, t2, sizeof t2); reg_w_ixbuf(gspca_dev, 0xb3, t3, sizeof t3); @@ -1080,7 +1101,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, u8 *data, /* isoc packet */ int len) /* iso packet length */ { - static u8 ffd9[] = { 0xff, 0xd9 }; + int pkt_type; if (data[0] == 0x5a) { /* Control Packet, after this came the header again, @@ -1090,84 +1111,88 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, } data += 2; len -= 2; - if (data[0] == 0xff && data[1] == 0xd8) { - /* extra bytes....., could be processed too but would be - * a waste of time, right now leave the application and - * libjpeg do it for ourserlves.. */ - gspca_frame_add(gspca_dev, LAST_PACKET, - ffd9, 2); - gspca_frame_add(gspca_dev, FIRST_PACKET, data, len); - return; - } - - if (data[len - 2] == 0xff && data[len - 1] == 0xd9) { - /* Just in case, i have seen packets with the marker, - * other's do not include it... */ - len -= 2; - } - gspca_frame_add(gspca_dev, INTER_PACKET, data, len); + if (data[0] == 0xff && data[1] == 0xd8) + pkt_type = FIRST_PACKET; + else if (data[len - 2] == 0xff && data[len - 1] == 0xd9) + pkt_type = LAST_PACKET; + else + pkt_type = INTER_PACKET; + gspca_frame_add(gspca_dev, pkt_type, data, len); } - -static int sd_setblue_balance(struct gspca_dev *gspca_dev, __s32 val) +static int sd_setblue_gain(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; - sd->blue_balance = val; + sd->blue_gain = val; if (gspca_dev->streaming) reg_w(gspca_dev, (val << 8) + 0x88); return 0; } -static int sd_getblue_balance(struct gspca_dev *gspca_dev, __s32 *val) +static int sd_getblue_gain(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; - *val = sd->blue_balance; + *val = sd->blue_gain; return 0; } -static int sd_setred_balance(struct gspca_dev *gspca_dev, __s32 val) +static int sd_setred_gain(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; - sd->red_balance = val; + sd->red_gain = val; if (gspca_dev->streaming) reg_w(gspca_dev, (val << 8) + 0x87); return 0; } -static int sd_getred_balance(struct gspca_dev *gspca_dev, __s32 *val) +static int sd_getred_gain(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; - *val = sd->red_balance; + *val = sd->red_gain; return 0; } - - -static int sd_setglobal_gain(struct gspca_dev *gspca_dev, __s32 val) +static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; + u16 psg, nsg; + + psg = sd->red_gain + sd->blue_gain + sd->green_gain; + nsg = val * 3; + sd->red_gain = sd->red_gain * nsg / psg; + if (sd->red_gain > 0x40) + sd->red_gain = 0x40; + else if (sd->red_gain < 0x10) + sd->red_gain = 0x10; + sd->blue_gain = sd->blue_gain * nsg / psg; + if (sd->blue_gain > 0x40) + sd->blue_gain = 0x40; + else if (sd->blue_gain < 0x10) + sd->blue_gain = 0x10; + sd->green_gain = sd->green_gain * nsg / psg; + if (sd->green_gain > 0x40) + sd->green_gain = 0x40; + else if (sd->green_gain < 0x10) + sd->green_gain = 0x10; - sd->global_gain = val; if (gspca_dev->streaming) - setglobalgain(gspca_dev); - + setRGB(gspca_dev); return 0; } -static int sd_getglobal_gain(struct gspca_dev *gspca_dev, __s32 *val) +static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; - *val = sd->global_gain; + *val = (sd->red_gain + sd->blue_gain + sd->green_gain) / 3; return 0; } - static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; @@ -1186,35 +1211,35 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) return *val; } -static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val) +static int sd_setawb(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; - sd->whitebalance = val; + sd->awb = val; if (gspca_dev->streaming) - setwhitebalance(gspca_dev); + setawb(gspca_dev); return 0; } -static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val) +static int sd_getawb(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; - *val = sd->whitebalance; + *val = sd->awb; return *val; } -static int sd_setflip(struct gspca_dev *gspca_dev, __s32 val) +static int sd_setmirror(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; sd->mirror = val; if (gspca_dev->streaming) - setflip(gspca_dev); + setmirror(gspca_dev); return 0; } -static int sd_getflip(struct gspca_dev *gspca_dev, __s32 *val) +static int sd_getmirror(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; @@ -1300,7 +1325,7 @@ static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val) sd->freq = val; if (gspca_dev->streaming) - setlightfreq(gspca_dev); + setfreq(gspca_dev); return 0; } @@ -1368,7 +1393,8 @@ static int sd_querymenu(struct gspca_dev *gspca_dev, case V4L2_CID_EFFECTS: if ((unsigned) menu->index < ARRAY_SIZE(effects_control)) { strncpy((char *) menu->name, - effects_control[menu->index], 32); + effects_control[menu->index], + sizeof menu->name); return 0; } break; diff --git a/drivers/media/video/gspca/tv8532.c b/drivers/media/video/gspca/tv8532.c index c7b6eb1e04d..d9c5bf3449d 100644 --- a/drivers/media/video/gspca/tv8532.c +++ b/drivers/media/video/gspca/tv8532.c @@ -30,29 +30,46 @@ MODULE_LICENSE("GPL"); struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - __u16 brightness; + __u16 exposure; + __u16 gain; __u8 packet; }; /* V4L2 controls supported by the driver */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); static const struct ctrl sd_ctrls[] = { { { - .id = V4L2_CID_BRIGHTNESS, + .id = V4L2_CID_EXPOSURE, .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", + .name = "Exposure", .minimum = 1, - .maximum = 0x15f, /* = 352 - 1 */ + .maximum = 0x18f, .step = 1, -#define BRIGHTNESS_DEF 0x14c - .default_value = BRIGHTNESS_DEF, +#define EXPOSURE_DEF 0x18f + .default_value = EXPOSURE_DEF, }, - .set = sd_setbrightness, - .get = sd_getbrightness, + .set = sd_setexposure, + .get = sd_getexposure, + }, + { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = 0, + .maximum = 0x7ff, + .step = 1, +#define GAIN_DEF 0x100 + .default_value = GAIN_DEF, + }, + .set = sd_setgain, + .get = sd_getgain, }, }; @@ -92,6 +109,14 @@ static const struct v4l2_pix_format sif_mode[] = { #define R14_AD_ROW_BEGINL 0x14 #define R15_AD_ROWBEGINH 0x15 #define R1C_AD_EXPOSE_TIMEL 0x1c +#define R20_GAIN_G1L 0x20 +#define R21_GAIN_G1H 0x21 +#define R22_GAIN_RL 0x22 +#define R23_GAIN_RH 0x23 +#define R24_GAIN_BL 0x24 +#define R25_GAIN_BH 0x25 +#define R26_GAIN_G2L 0x26 +#define R27_GAIN_G2H 0x27 #define R28_QUANT 0x28 #define R29_LINE 0x29 #define R2C_POLARITY 0x2c @@ -129,18 +154,6 @@ static const u8 eeprom_data[][3] = { {0x05, 0x09, 0xf1}, }; -static int reg_r(struct gspca_dev *gspca_dev, - __u16 index) -{ - usb_control_msg(gspca_dev->dev, - usb_rcvctrlpipe(gspca_dev->dev, 0), - 0x03, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, /* value */ - index, gspca_dev->usb_buf, 1, - 500); - return gspca_dev->usb_buf[0]; -} /* write 1 byte */ static void reg_w1(struct gspca_dev *gspca_dev, @@ -183,7 +196,6 @@ static void tv_8532WriteEEprom(struct gspca_dev *gspca_dev) } reg_w1(gspca_dev, R07_TABLE_LEN, i); reg_w1(gspca_dev, R01_TIMING_CONTROL_LOW, CMD_EEprom_Close); - msleep(10); } /* this function is called at probe time */ @@ -197,53 +209,13 @@ static int sd_config(struct gspca_dev *gspca_dev, cam->cam_mode = sif_mode; cam->nmodes = ARRAY_SIZE(sif_mode); - sd->brightness = BRIGHTNESS_DEF; + sd->exposure = EXPOSURE_DEF; + sd->gain = GAIN_DEF; return 0; } -static void tv_8532ReadRegisters(struct gspca_dev *gspca_dev) -{ - int i; - static u8 reg_tb[] = { - R0C_AD_WIDTHL, - R0D_AD_WIDTHH, - R28_QUANT, - R29_LINE, - R2C_POLARITY, - R2D_POINT, - R2E_POINTH, - R2F_POINTB, - R30_POINTBH, - R2A_HIGH_BUDGET, - R2B_LOW_BUDGET, - R34_VID, - R35_VIDH, - R36_PID, - R37_PIDH, - R83_AD_IDH, - R10_AD_COL_BEGINL, - R11_AD_COL_BEGINH, - R14_AD_ROW_BEGINL, - R15_AD_ROWBEGINH, - 0 - }; - - i = 0; - do { - reg_r(gspca_dev, reg_tb[i]); - i++; - } while (reg_tb[i] != 0); -} - static void tv_8532_setReg(struct gspca_dev *gspca_dev) { - reg_w1(gspca_dev, R10_AD_COL_BEGINL, 0x44); - /* begin active line */ - reg_w1(gspca_dev, R11_AD_COL_BEGINH, 0x00); - /* mirror and digital gain */ - reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE); - /* = 0x84 */ - reg_w1(gspca_dev, R3B_Test3, 0x0a); /* Test0Sel = 10 */ /******************************************************/ reg_w1(gspca_dev, R0E_AD_HEIGHTL, 0x90); @@ -255,100 +227,43 @@ static void tv_8532_setReg(struct gspca_dev *gspca_dev) /* mirror and digital gain */ reg_w1(gspca_dev, R14_AD_ROW_BEGINL, 0x0a); - reg_w1(gspca_dev, R91_AD_SLOPEREG, 0x00); reg_w1(gspca_dev, R94_AD_BITCONTROL, 0x02); - - reg_w1(gspca_dev, R01_TIMING_CONTROL_LOW, CMD_EEprom_Close); - reg_w1(gspca_dev, R91_AD_SLOPEREG, 0x00); reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE); /* = 0x84 */ } -static void tv_8532_PollReg(struct gspca_dev *gspca_dev) -{ - int i; - - /* strange polling from tgc */ - for (i = 0; i < 10; i++) { - reg_w1(gspca_dev, R2C_POLARITY, 0x10); - reg_w1(gspca_dev, R00_PART_CONTROL, - LATENT_CHANGE | EXPO_CHANGE); - reg_w1(gspca_dev, R31_UPD, 0x01); - } -} - /* this function is called at probe and resume time */ static int sd_init(struct gspca_dev *gspca_dev) { tv_8532WriteEEprom(gspca_dev); - reg_w1(gspca_dev, R91_AD_SLOPEREG, 0x32); /* slope begin 1,7V, - * slope rate 2 */ - reg_w1(gspca_dev, R94_AD_BITCONTROL, 0x00); - tv_8532ReadRegisters(gspca_dev); - reg_w1(gspca_dev, R3B_Test3, 0x0b); - reg_w2(gspca_dev, R0E_AD_HEIGHTL, 0x0190); - reg_w2(gspca_dev, R1C_AD_EXPOSE_TIMEL, 0x018f); - reg_w1(gspca_dev, R0C_AD_WIDTHL, 0xe8); - reg_w1(gspca_dev, R0D_AD_WIDTHH, 0x03); - - /*******************************************************************/ - reg_w1(gspca_dev, R28_QUANT, 0x90); - /* no compress - fixed Q - quant 0 */ - reg_w1(gspca_dev, R29_LINE, 0x81); - /* 0x84; // CIF | 4 packet 0x29 */ - - /************************************************/ - reg_w1(gspca_dev, R2C_POLARITY, 0x10); - /* 0x48; //0x08; 0x2c */ - reg_w1(gspca_dev, R2D_POINT, 0x14); - /* 0x38; 0x2d */ - reg_w1(gspca_dev, R2E_POINTH, 0x01); - /* 0x04; 0x2e */ - reg_w1(gspca_dev, R2F_POINTB, 0x12); - /* 0x04; 0x2f */ - reg_w1(gspca_dev, R30_POINTBH, 0x01); - /* 0x04; 0x30 */ - reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE); - /* 0x00<-0x84 */ - /*************************************************/ - reg_w1(gspca_dev, R31_UPD, 0x01); /* update registers */ - msleep(200); - reg_w1(gspca_dev, R31_UPD, 0x00); /* end update */ - /*************************************************/ - tv_8532_setReg(gspca_dev); - /*************************************************/ - reg_w1(gspca_dev, R3B_Test3, 0x0b); /* Test0Sel = 11 = GPIO */ - /*************************************************/ - tv_8532_setReg(gspca_dev); - /*************************************************/ - tv_8532_PollReg(gspca_dev); return 0; } -static void setbrightness(struct gspca_dev *gspca_dev) +static void setexposure(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - reg_w2(gspca_dev, R1C_AD_EXPOSE_TIMEL, sd->brightness); + reg_w2(gspca_dev, R1C_AD_EXPOSE_TIMEL, sd->exposure); reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE); /* 0x84 */ } -/* -- start the camera -- */ -static int sd_start(struct gspca_dev *gspca_dev) +static void setgain(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - reg_w1(gspca_dev, R91_AD_SLOPEREG, 0x32); /* slope begin 1,7V, - * slope rate 2 */ - reg_w1(gspca_dev, R94_AD_BITCONTROL, 0x00); - tv_8532ReadRegisters(gspca_dev); - reg_w1(gspca_dev, R3B_Test3, 0x0b); + reg_w2(gspca_dev, R20_GAIN_G1L, sd->gain); + reg_w2(gspca_dev, R22_GAIN_RL, sd->gain); + reg_w2(gspca_dev, R24_GAIN_BL, sd->gain); + reg_w2(gspca_dev, R26_GAIN_G2L, sd->gain); +} - reg_w2(gspca_dev, R0E_AD_HEIGHTL, 0x0190); - setbrightness(gspca_dev); +/* -- start the camera -- */ +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; reg_w1(gspca_dev, R0C_AD_WIDTHL, 0xe8); /* 0x20; 0x0c */ reg_w1(gspca_dev, R0D_AD_WIDTHH, 0x03); @@ -371,19 +286,15 @@ static int sd_start(struct gspca_dev *gspca_dev) reg_w1(gspca_dev, R2E_POINTH, 0x01); reg_w1(gspca_dev, R2F_POINTB, 0x12); reg_w1(gspca_dev, R30_POINTBH, 0x01); - reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE); + + tv_8532_setReg(gspca_dev); + + setexposure(gspca_dev); + setgain(gspca_dev); + /************************************************/ reg_w1(gspca_dev, R31_UPD, 0x01); /* update registers */ msleep(200); - reg_w1(gspca_dev, R31_UPD, 0x00); /* end update */ - /************************************************/ - tv_8532_setReg(gspca_dev); - /************************************************/ - reg_w1(gspca_dev, R3B_Test3, 0x0b); /* Test0Sel = 11 = GPIO */ - /************************************************/ - tv_8532_setReg(gspca_dev); - /************************************************/ - tv_8532_PollReg(gspca_dev); reg_w1(gspca_dev, R31_UPD, 0x00); /* end update */ gspca_dev->empty_packet = 0; /* check the empty packets */ @@ -428,21 +339,39 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, data + gspca_dev->width + 5, gspca_dev->width); } -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->exposure = val; + if (gspca_dev->streaming) + setexposure(gspca_dev); + return 0; +} + +static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->exposure; + return 0; +} + +static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; - sd->brightness = val; + sd->gain = val; if (gspca_dev->streaming) - setbrightness(gspca_dev); + setgain(gspca_dev); return 0; } -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; - *val = sd->brightness; + *val = sd->gain; return 0; } diff --git a/drivers/media/video/gspca/vc032x.c b/drivers/media/video/gspca/vc032x.c index 732c3dfe46f..031266a4081 100644 --- a/drivers/media/video/gspca/vc032x.c +++ b/drivers/media/video/gspca/vc032x.c @@ -2748,11 +2748,11 @@ static const u8 poxxxx_init_common[][4] = { {0xb3, 0x04, 0x15, 0xcc}, {0xb3, 0x20, 0x00, 0xcc}, {0xb3, 0x21, 0x00, 0xcc}, - {0xb3, 0x22, 0x04, 0xcc}, + {0xb3, 0x22, 0x04, 0xcc}, /* sensor height = 1024 */ {0xb3, 0x23, 0x00, 0xcc}, {0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc}, - {0xb3, 0x16, 0x04, 0xcc}, + {0xb3, 0x16, 0x04, 0xcc}, /* sensor width = 1280 */ {0xb3, 0x17, 0xff, 0xcc}, {0xb3, 0x2c, 0x03, 0xcc}, {0xb3, 0x2d, 0x56, 0xcc}, @@ -2919,7 +2919,7 @@ static const u8 poxxxx_initVGA[][4] = { {0x00, 0x20, 0x11, 0xaa}, {0x00, 0x33, 0x38, 0xaa}, {0x00, 0xbb, 0x0d, 0xaa}, - {0xb3, 0x22, 0x01, 0xcc}, + {0xb3, 0x22, 0x01, 0xcc}, /* change to 640x480 */ {0xb3, 0x23, 0xe0, 0xcc}, {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc}, @@ -2935,7 +2935,7 @@ static const u8 poxxxx_initQVGA[][4] = { {0x00, 0x20, 0x33, 0xaa}, {0x00, 0x33, 0x38, 0xaa}, {0x00, 0xbb, 0x0d, 0xaa}, - {0xb3, 0x22, 0x00, 0xcc}, + {0xb3, 0x22, 0x00, 0xcc}, /* change to 320x240 */ {0xb3, 0x23, 0xf0, 0xcc}, {0xb3, 0x16, 0x01, 0xcc}, {0xb3, 0x17, 0x3f, 0xcc}, @@ -3068,37 +3068,84 @@ static const struct sensor_info vc0323_probe_data[] = { }; /* read 'len' bytes in gspca_dev->usb_buf */ -static void reg_r(struct gspca_dev *gspca_dev, +static void reg_r_i(struct gspca_dev *gspca_dev, u16 req, u16 index, u16 len) { - usb_control_msg(gspca_dev->dev, + int ret; + + if (gspca_dev->usb_err < 0) + return; + ret = usb_control_msg(gspca_dev->dev, usb_rcvctrlpipe(gspca_dev->dev, 0), req, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 1, /* value */ index, gspca_dev->usb_buf, len, 500); + if (ret < 0) { + PDEBUG(D_ERR, "reg_r err %d", ret); + gspca_dev->usb_err = ret; + } +} +static void reg_r(struct gspca_dev *gspca_dev, + u16 req, + u16 index, + u16 len) +{ + reg_r_i(gspca_dev, req, index, len); +#ifdef GSPCA_DEBUG + if (gspca_dev->usb_err < 0) + return; + if (len == 1) + PDEBUG(D_USBI, "GET %02x 0001 %04x %02x", req, index, + gspca_dev->usb_buf[0]); + else + PDEBUG(D_USBI, "GET %02x 0001 %04x %02x %02x %02x", + req, index, + gspca_dev->usb_buf[0], + gspca_dev->usb_buf[1], + gspca_dev->usb_buf[2]); +#endif } -static void reg_w(struct usb_device *dev, +static void reg_w_i(struct gspca_dev *gspca_dev, u16 req, u16 value, u16 index) { - usb_control_msg(dev, - usb_sndctrlpipe(dev, 0), + int ret; + + if (gspca_dev->usb_err < 0) + return; + ret = usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), req, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value, index, NULL, 0, 500); + if (ret < 0) { + PDEBUG(D_ERR, "reg_w err %d", ret); + gspca_dev->usb_err = ret; + } +} +static void reg_w(struct gspca_dev *gspca_dev, + u16 req, + u16 value, + u16 index) +{ +#ifdef GSPCA_DEBUG + if (gspca_dev->usb_err < 0) + return; + PDEBUG(D_USBO, "SET %02x %04x %04x", req, value, index); +#endif + reg_w_i(gspca_dev, req, value, index); } static u16 read_sensor_register(struct gspca_dev *gspca_dev, u16 address) { - struct usb_device *dev = gspca_dev->dev; u8 ldata, mdata, hdata; int retry = 50; @@ -3108,8 +3155,8 @@ static u16 read_sensor_register(struct gspca_dev *gspca_dev, gspca_dev->usb_buf[0]); return 0; } - reg_w(dev, 0xa0, address, 0xb33a); - reg_w(dev, 0xa0, 0x02, 0xb339); + reg_w(gspca_dev, 0xa0, address, 0xb33a); + reg_w(gspca_dev, 0xa0, 0x02, 0xb339); do { reg_r(gspca_dev, 0xa1, 0xb33b, 1); @@ -3136,15 +3183,15 @@ static u16 read_sensor_register(struct gspca_dev *gspca_dev, static int vc032x_probe_sensor(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - struct usb_device *dev = gspca_dev->dev; int i, n; u16 value; const struct sensor_info *ptsensor_info; /*fixme: should also check the other sensor (back mi1320_soc, front mc501cb)*/ if (sd->flags & FL_SAMSUNG) { - reg_w(dev, 0xa0, 0x01, 0xb301); - reg_w(dev, 0x89, 0xf0ff, 0xffff); /* select the back sensor */ + reg_w(gspca_dev, 0xa0, 0x01, 0xb301); + reg_w(gspca_dev, 0x89, 0xf0ff, 0xffff); + /* select the back sensor */ } reg_r(gspca_dev, 0xa1, 0xbfcf, 1); @@ -3158,13 +3205,13 @@ static int vc032x_probe_sensor(struct gspca_dev *gspca_dev) n = ARRAY_SIZE(vc0323_probe_data); } for (i = 0; i < n; i++) { - reg_w(dev, 0xa0, 0x02, 0xb334); - reg_w(dev, 0xa0, ptsensor_info->m1, 0xb300); - reg_w(dev, 0xa0, ptsensor_info->m2, 0xb300); - reg_w(dev, 0xa0, 0x01, 0xb308); - reg_w(dev, 0xa0, 0x0c, 0xb309); - reg_w(dev, 0xa0, ptsensor_info->I2cAdd, 0xb335); - reg_w(dev, 0xa0, ptsensor_info->op, 0xb301); + reg_w(gspca_dev, 0xa0, 0x02, 0xb334); + reg_w(gspca_dev, 0xa0, ptsensor_info->m1, 0xb300); + reg_w(gspca_dev, 0xa0, ptsensor_info->m2, 0xb300); + reg_w(gspca_dev, 0xa0, 0x01, 0xb308); + reg_w(gspca_dev, 0xa0, 0x0c, 0xb309); + reg_w(gspca_dev, 0xa0, ptsensor_info->I2cAdd, 0xb335); + reg_w(gspca_dev, 0xa0, ptsensor_info->op, 0xb301); value = read_sensor_register(gspca_dev, ptsensor_info->IdAdd); if (value == 0 && ptsensor_info->IdAdd == 0x82) value = read_sensor_register(gspca_dev, 0x83); @@ -3192,26 +3239,33 @@ static void i2c_write(struct gspca_dev *gspca_dev, u8 reg, const u8 *val, u8 size) /* 1 or 2 */ { - struct usb_device *dev = gspca_dev->dev; int retry; - reg_r(gspca_dev, 0xa1, 0xb33f, 1); +#ifdef GSPCA_DEBUG + if (gspca_dev->usb_err < 0) + return; + if (size == 1) + PDEBUG(D_USBO, "i2c_w %02x %02x", reg, *val); + else + PDEBUG(D_USBO, "i2c_w %02x %02x%02x", reg, *val, val[1]); +#endif + reg_r_i(gspca_dev, 0xa1, 0xb33f, 1); /*fixme:should check if (!(gspca_dev->usb_buf[0] & 0x02)) error*/ - reg_w(dev, 0xa0, size, 0xb334); - reg_w(dev, 0xa0, reg, 0xb33a); - reg_w(dev, 0xa0, val[0], 0xb336); + reg_w_i(gspca_dev, 0xa0, size, 0xb334); + reg_w_i(gspca_dev, 0xa0, reg, 0xb33a); + reg_w_i(gspca_dev, 0xa0, val[0], 0xb336); if (size > 1) - reg_w(dev, 0xa0, val[1], 0xb337); - reg_w(dev, 0xa0, 0x01, 0xb339); + reg_w_i(gspca_dev, 0xa0, val[1], 0xb337); + reg_w_i(gspca_dev, 0xa0, 0x01, 0xb339); retry = 4; do { - reg_r(gspca_dev, 0xa1, 0xb33b, 1); + reg_r_i(gspca_dev, 0xa1, 0xb33b, 1); if (gspca_dev->usb_buf[0] == 0) break; msleep(20); } while (--retry > 0); if (retry <= 0) - PDEBUG(D_ERR, "i2c_write failed"); + PDEBUG(D_ERR, "i2c_write timeout"); } static void put_tab_to_reg(struct gspca_dev *gspca_dev, @@ -3221,13 +3275,12 @@ static void put_tab_to_reg(struct gspca_dev *gspca_dev, u16 ad = addr; for (j = 0; j < tabsize; j++) - reg_w(gspca_dev->dev, 0xa0, tab[j], ad++); + reg_w(gspca_dev, 0xa0, tab[j], ad++); } static void usb_exchange(struct gspca_dev *gspca_dev, const u8 data[][4]) { - struct usb_device *dev = gspca_dev->dev; int i = 0; for (;;) { @@ -3235,7 +3288,7 @@ static void usb_exchange(struct gspca_dev *gspca_dev, default: return; case 0xcc: /* normal write */ - reg_w(dev, 0xa0, data[i][2], + reg_w(gspca_dev, 0xa0, data[i][2], (data[i][0]) << 8 | data[i][1]); break; case 0xaa: /* i2c op */ @@ -3259,7 +3312,6 @@ static int sd_config(struct gspca_dev *gspca_dev, const struct usb_device_id *id) { struct sd *sd = (struct sd *) gspca_dev; - struct usb_device *dev = gspca_dev->dev; struct cam *cam; int sensor; static u8 npkt[] = { /* number of packets per ISOC message */ @@ -3363,13 +3415,6 @@ static int sd_config(struct gspca_dev *gspca_dev, if (sd->sensor == SENSOR_OV7670) sd->flags |= FL_HFLIP | FL_VFLIP; - if (sd->bridge == BRIDGE_VC0321) { - reg_r(gspca_dev, 0x8a, 0, 3); - reg_w(dev, 0x87, 0x00, 0x0f0f); - - reg_r(gspca_dev, 0x8b, 0, 3); - reg_w(dev, 0x88, 0x00, 0x0202); - } return 0; } @@ -3378,15 +3423,21 @@ static int sd_init(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - if (sd->sensor == SENSOR_POxxxx) { - reg_r(gspca_dev, 0xa1, 0xb300, 1); - if (gspca_dev->usb_buf[0] != 0) { - reg_w(gspca_dev->dev, 0xa0, 0x26, 0xb300); - reg_w(gspca_dev->dev, 0xa0, 0x04, 0xb300); - reg_w(gspca_dev->dev, 0xa0, 0x00, 0xb300); + if (sd->bridge == BRIDGE_VC0321) { + reg_r(gspca_dev, 0x8a, 0, 3); + reg_w(gspca_dev, 0x87, 0x00, 0x0f0f); + reg_r(gspca_dev, 0x8b, 0, 3); + reg_w(gspca_dev, 0x88, 0x00, 0x0202); + if (sd->sensor == SENSOR_POxxxx) { + reg_r(gspca_dev, 0xa1, 0xb300, 1); + if (gspca_dev->usb_buf[0] != 0) { + reg_w(gspca_dev, 0xa0, 0x26, 0xb300); + reg_w(gspca_dev, 0xa0, 0x04, 0xb300); + reg_w(gspca_dev, 0xa0, 0x00, 0xb300); + } } } - return 0; + return gspca_dev->usb_err; } static void setbrightness(struct gspca_dev *gspca_dev) @@ -3516,17 +3567,17 @@ static int sd_start(struct gspca_dev *gspca_dev) /*fixme: back sensor only*/ if (sd->flags & FL_SAMSUNG) { - reg_w(gspca_dev->dev, 0x89, 0xf0ff, 0xffff); - reg_w(gspca_dev->dev, 0xa9, 0x8348, 0x000e); - reg_w(gspca_dev->dev, 0xa9, 0x0000, 0x001a); + reg_w(gspca_dev, 0x89, 0xf0ff, 0xffff); + reg_w(gspca_dev, 0xa9, 0x8348, 0x000e); + reg_w(gspca_dev, 0xa9, 0x0000, 0x001a); } /* Assume start use the good resolution from gspca_dev->mode */ if (sd->bridge == BRIDGE_VC0321) { - reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfec); - reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfed); - reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfee); - reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfef); + reg_w(gspca_dev, 0xa0, 0xff, 0xbfec); + reg_w(gspca_dev, 0xa0, 0xff, 0xbfed); + reg_w(gspca_dev, 0xa0, 0xff, 0xbfee); + reg_w(gspca_dev, 0xa0, 0xff, 0xbfef); sd->image_offset = 46; } else { if (gspca_dev->cam.cam_mode[gspca_dev->curr_mode].pixelformat @@ -3617,7 +3668,7 @@ static int sd_start(struct gspca_dev *gspca_dev) init = poxxxx_initVGA; usb_exchange(gspca_dev, init); reg_r(gspca_dev, 0x8c, 0x0000, 3); - reg_w(gspca_dev->dev, 0xa0, + reg_w(gspca_dev, 0xa0, gspca_dev->usb_buf[2] & 1 ? 0 : 1, 0xb35c); msleep(300); @@ -3635,10 +3686,10 @@ static int sd_start(struct gspca_dev *gspca_dev) switch (sd->sensor) { case SENSOR_PO1200: case SENSOR_HV7131R: - reg_w(gspca_dev->dev, 0x89, 0x0400, 0x1415); + reg_w(gspca_dev, 0x89, 0x0400, 0x1415); break; case SENSOR_MI1310_SOC: - reg_w(gspca_dev->dev, 0x89, 0x058c, 0x0000); + reg_w(gspca_dev, 0x89, 0x058c, 0x0000); break; } msleep(100); @@ -3648,9 +3699,9 @@ static int sd_start(struct gspca_dev *gspca_dev) } switch (sd->sensor) { case SENSOR_OV7670: - reg_w(gspca_dev->dev, 0x87, 0xffff, 0xffff); - reg_w(gspca_dev->dev, 0x88, 0xff00, 0xf0f1); - reg_w(gspca_dev->dev, 0xa0, 0x0000, 0xbfff); + reg_w(gspca_dev, 0x87, 0xffff, 0xffff); + reg_w(gspca_dev, 0x88, 0xff00, 0xf0f1); + reg_w(gspca_dev, 0xa0, 0x0000, 0xbfff); break; case SENSOR_POxxxx: setcolors(gspca_dev); @@ -3659,51 +3710,49 @@ static int sd_start(struct gspca_dev *gspca_dev) /* led on */ msleep(80); - reg_w(gspca_dev->dev, 0x89, 0xffff, 0xfdff); + reg_w(gspca_dev, 0x89, 0xffff, 0xfdff); usb_exchange(gspca_dev, poxxxx_init_end_2); break; } - return 0; + return gspca_dev->usb_err; } static void sd_stopN(struct gspca_dev *gspca_dev) { - struct usb_device *dev = gspca_dev->dev; struct sd *sd = (struct sd *) gspca_dev; switch (sd->sensor) { case SENSOR_MI1310_SOC: - reg_w(dev, 0x89, 0x058c, 0x00ff); + reg_w(gspca_dev, 0x89, 0x058c, 0x00ff); break; case SENSOR_POxxxx: return; default: if (!(sd->flags & FL_SAMSUNG)) - reg_w(dev, 0x89, 0xffff, 0xffff); + reg_w(gspca_dev, 0x89, 0xffff, 0xffff); break; } - reg_w(dev, 0xa0, 0x01, 0xb301); - reg_w(dev, 0xa0, 0x09, 0xb003); + reg_w(gspca_dev, 0xa0, 0x01, 0xb301); + reg_w(gspca_dev, 0xa0, 0x09, 0xb003); } /* called on streamoff with alt 0 and on disconnect */ static void sd_stop0(struct gspca_dev *gspca_dev) { - struct usb_device *dev = gspca_dev->dev; struct sd *sd = (struct sd *) gspca_dev; if (!gspca_dev->present) return; /*fixme: is this useful?*/ if (sd->sensor == SENSOR_MI1310_SOC) - reg_w(dev, 0x89, 0x058c, 0x00ff); + reg_w(gspca_dev, 0x89, 0x058c, 0x00ff); else if (!(sd->flags & FL_SAMSUNG)) - reg_w(dev, 0x89, 0xffff, 0xffff); + reg_w(gspca_dev, 0x89, 0xffff, 0xffff); if (sd->sensor == SENSOR_POxxxx) { - reg_w(dev, 0xa0, 0x26, 0xb300); - reg_w(dev, 0xa0, 0x04, 0xb300); - reg_w(dev, 0xa0, 0x00, 0xb300); + reg_w(gspca_dev, 0xa0, 0x26, 0xb300); + reg_w(gspca_dev, 0xa0, 0x04, 0xb300); + reg_w(gspca_dev, 0xa0, 0x00, 0xb300); } } @@ -3726,17 +3775,12 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, /* The vc0321 sends some additional data after sending the complete * frame, we ignore this. */ if (sd->bridge == BRIDGE_VC0321) { - struct gspca_frame *frame; - int l; + int size, l; - frame = gspca_get_i_frame(gspca_dev); - if (frame == NULL) { - gspca_dev->last_packet_type = DISCARD_PACKET; - return; - } - l = frame->data_end - frame->data; - if (len > frame->v4l2_buf.length - l) - len = frame->v4l2_buf.length - l; + l = gspca_dev->image_len; + size = gspca_dev->frsz; + if (len > size - l) + len = size - l; } gspca_frame_add(gspca_dev, INTER_PACKET, data, len); } @@ -3748,7 +3792,7 @@ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) sd->brightness = val; if (gspca_dev->streaming) setbrightness(gspca_dev); - return 0; + return gspca_dev->usb_err; } static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) @@ -3766,7 +3810,7 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) sd->contrast = val; if (gspca_dev->streaming) setcontrast(gspca_dev); - return 0; + return gspca_dev->usb_err; } static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) @@ -3784,7 +3828,7 @@ static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) sd->colors = val; if (gspca_dev->streaming) setcolors(gspca_dev); - return 0; + return gspca_dev->usb_err; } static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) @@ -3802,7 +3846,7 @@ static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val) sd->hflip = val; if (gspca_dev->streaming) sethvflip(gspca_dev); - return 0; + return gspca_dev->usb_err; } static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val) @@ -3820,7 +3864,7 @@ static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val) sd->vflip = val; if (gspca_dev->streaming) sethvflip(gspca_dev); - return 0; + return gspca_dev->usb_err; } static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val) @@ -3838,7 +3882,7 @@ static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val) sd->lightfreq = val; if (gspca_dev->streaming) setlightfreq(gspca_dev); - return 0; + return gspca_dev->usb_err; } static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val) @@ -3856,7 +3900,7 @@ static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val) sd->sharpness = val; if (gspca_dev->streaming) setsharpness(gspca_dev); - return 0; + return gspca_dev->usb_err; } static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val) diff --git a/drivers/media/video/gspca/w996Xcf.c b/drivers/media/video/gspca/w996Xcf.c index 2fffe203bed..38a68591ce4 100644 --- a/drivers/media/video/gspca/w996Xcf.c +++ b/drivers/media/video/gspca/w996Xcf.c @@ -31,14 +31,10 @@ the sensor drivers to v4l2 sub drivers, and properly split of this driver from ov519.c */ -/* The CONEX_CAM define for jpeg.h needs renaming, now its used here too */ -#define CONEX_CAM -#include "jpeg.h" - #define W9968CF_I2C_BUS_DELAY 4 /* delay in us for I2C bit r/w operations */ -#define Y_QUANTABLE (sd->jpeg_hdr + JPEG_QT0_OFFSET) -#define UV_QUANTABLE (sd->jpeg_hdr + JPEG_QT1_OFFSET) +#define Y_QUANTABLE (&sd->jpeg_hdr[JPEG_QT0_OFFSET]) +#define UV_QUANTABLE (&sd->jpeg_hdr[JPEG_QT1_OFFSET]) static const struct v4l2_pix_format w9968cf_vga_mode[] = { {160, 120, V4L2_PIX_FMT_UYVY, V4L2_FIELD_NONE, @@ -509,11 +505,6 @@ static int w9968cf_mode_init_regs(struct sd *sd) if (w9968cf_vga_mode[sd->gspca_dev.curr_mode].pixelformat == V4L2_PIX_FMT_JPEG) { /* We may get called multiple times (usb isoc bw negotiat.) */ - if (!sd->jpeg_hdr) - sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL); - if (!sd->jpeg_hdr) - return -ENOMEM; - jpeg_define(sd->jpeg_hdr, sd->gspca_dev.height, sd->gspca_dev.width, 0x22); /* JPEG 420 */ jpeg_set_qual(sd->jpeg_hdr, sd->quality); @@ -562,9 +553,6 @@ static void w9968cf_stop0(struct sd *sd) reg_w(sd, 0x39, 0x0000); /* disable JPEG encoder */ reg_w(sd, 0x16, 0x0000); /* stop video capture */ } - - kfree(sd->jpeg_hdr); - sd->jpeg_hdr = NULL; } /* The w9968cf docs say that a 0 sized packet means EOF (and also SOF diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c index d02aa5c8472..4473f0fb8b7 100644 --- a/drivers/media/video/gspca/zc3xx.c +++ b/drivers/media/video/gspca/zc3xx.c @@ -22,7 +22,6 @@ #define MODULE_NAME "zc3xx" #include <linux/input.h> -#include <linux/slab.h> #include "gspca.h" #include "jpeg.h" @@ -40,15 +39,16 @@ static int force_sensor = -1; struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ + u8 brightness; u8 contrast; u8 gamma; u8 autogain; u8 lightfreq; u8 sharpness; u8 quality; /* image quality */ -#define QUALITY_MIN 40 -#define QUALITY_MAX 60 -#define QUALITY_DEF 50 +#define QUALITY_MIN 50 +#define QUALITY_MAX 80 +#define QUALITY_DEF 70 u8 sensor; /* Type of image sensor chip */ /* !! values used in different tables */ @@ -75,10 +75,12 @@ struct sd { #define SENSOR_MAX 19 unsigned short chip_revision; - u8 *jpeg_hdr; + u8 jpeg_hdr[JPEG_HDR_SZ]; }; /* V4L2 controls supported by the driver */ +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); @@ -93,6 +95,20 @@ static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val); static const struct ctrl sd_ctrls[] = { { { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 255, + .step = 1, +#define BRIGHTNESS_DEF 128 + .default_value = BRIGHTNESS_DEF, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, + { + { .id = V4L2_CID_CONTRAST, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Contrast", @@ -132,7 +148,7 @@ static const struct ctrl sd_ctrls[] = { .set = sd_setautogain, .get = sd_getautogain, }, -#define LIGHTFREQ_IDX 3 +#define LIGHTFREQ_IDX 4 { { .id = V4L2_CID_POWER_LINE_FREQUENCY, @@ -6011,9 +6027,12 @@ static void setcontrast(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; struct usb_device *dev = gspca_dev->dev; const u8 *Tgamma; - int g, i, k, adj, gp; + int g, i, brightness, contrast, adj, gp1, gp2; u8 gr[16]; - static const u8 delta_tb[16] = /* delta for contrast */ + static const u8 delta_b[16] = /* delta for brightness */ + {0x50, 0x38, 0x2d, 0x28, 0x24, 0x21, 0x1e, 0x1d, + 0x1d, 0x1b, 0x1b, 0x1b, 0x19, 0x18, 0x18, 0x18}; + static const u8 delta_c[16] = /* delta for contrast */ {0x2c, 0x1a, 0x12, 0x0c, 0x0a, 0x06, 0x06, 0x06, 0x04, 0x06, 0x04, 0x04, 0x03, 0x03, 0x02, 0x02}; static const u8 gamma_tb[6][16] = { @@ -6033,30 +6052,30 @@ static void setcontrast(struct gspca_dev *gspca_dev) Tgamma = gamma_tb[sd->gamma - 1]; - k = ((int) sd->contrast - 128); /* -128 / 128 */ + contrast = ((int) sd->contrast - 128); /* -128 / 127 */ + brightness = ((int) sd->brightness - 128); /* -128 / 92 */ adj = 0; - gp = 0; + gp1 = gp2 = 0; for (i = 0; i < 16; i++) { - g = Tgamma[i] - delta_tb[i] * k / 256 - adj / 2; + g = Tgamma[i] + delta_b[i] * brightness / 256 + - delta_c[i] * contrast / 256 - adj / 2; if (g > 0xff) g = 0xff; else if (g < 0) g = 0; reg_w(dev, g, 0x0120 + i); /* gamma */ - if (k > 0) + if (contrast > 0) adj--; - else + else if (contrast < 0) adj++; - - if (i != 0) { - if (gp == 0) - gr[i - 1] = 0; - else - gr[i - 1] = g - gp; - } - gp = g; + if (i > 1) + gr[i - 1] = (g - gp2) / 2; + else if (i != 0) + gr[0] = gp1 == 0 ? 0 : (g - gp1); + gp2 = gp1; + gp1 = g; } - gr[15] = gr[14] / 2; + gr[15] = (0xff - gp2) / 2; for (i = 0; i < 16; i++) reg_w(dev, gr[i], 0x0130 + i); /* gradient */ } @@ -6744,6 +6763,7 @@ static int sd_config(struct gspca_dev *gspca_dev, cam->nmodes = ARRAY_SIZE(broken_vga_mode); break; } + sd->brightness = BRIGHTNESS_DEF; sd->contrast = CONTRAST_DEF; sd->gamma = gamma[sd->sensor]; sd->autogain = AUTOGAIN_DEF; @@ -6798,9 +6818,6 @@ static int sd_start(struct gspca_dev *gspca_dev) }; /* create the JPEG header */ - sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL); - if (!sd->jpeg_hdr) - return -ENOMEM; jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, 0x21); /* JPEG 422 */ jpeg_set_qual(sd->jpeg_hdr, sd->quality); @@ -6918,10 +6935,6 @@ static int sd_start(struct gspca_dev *gspca_dev) reg_w(dev, 0x00, 0x0007); /* (from win traces) */ reg_w(dev, 0x02, ZC3XX_R008_CLOCKSETTING); break; - case SENSOR_PAS202B: - reg_w(dev, 0x32, 0x0007); /* (from win traces) */ - reg_w(dev, 0x02, ZC3XX_R008_CLOCKSETTING); - break; } return 0; } @@ -6931,7 +6944,6 @@ static void sd_stop0(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - kfree(sd->jpeg_hdr); if (!gspca_dev->present) return; send_unknown(gspca_dev->dev, sd->sensor); @@ -6962,6 +6974,24 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, gspca_frame_add(gspca_dev, INTER_PACKET, data, len); } +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + if (gspca_dev->streaming) + setcontrast(gspca_dev); + return 0; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->brightness; + return 0; +} + static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; @@ -7163,9 +7193,7 @@ static const __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x046d, 0x08aa)}, {USB_DEVICE(0x046d, 0x08ac)}, {USB_DEVICE(0x046d, 0x08ad)}, -#if !defined CONFIG_USB_ZC0301 && !defined CONFIG_USB_ZC0301_MODULE {USB_DEVICE(0x046d, 0x08ae)}, -#endif {USB_DEVICE(0x046d, 0x08af)}, {USB_DEVICE(0x046d, 0x08b9)}, {USB_DEVICE(0x046d, 0x08d7)}, |