Saturday, October 18, 2008

New Sensor + Merge + FAQ [Tascorp 17a1:0128]

During the last months, Jean F. Moine did a lot of work to merge gspca inside the kernel mainstream. You can find gspca included in the kernel since 2.6.27.X. Also the libv4lconvert inclusion ( by Hans de Goede ) allowed to move decoding process from kernel space to user space, and hence , permitted a fast insertion of gspca in the main tree.

Also, libv4lconvert, allow compatibility between older apps ( using v4l1) and new formats conversion ( or specifics decoders that some apps do not include ) for apps that use v4l2.

In the last two days, a new sensor was added to the t613 subdriver ( which i
mantains). The new sensor is reported as OM6802. Thx to the people testing this ( Luiz Gonzaga da Mata, Marc Boettinger and Peter (from Austria ) ), also to J F Moine who developed big part of this sensor and fixes.

A new sensor have appeared too, reported 0x08 : 0x03, if anyone have this sensor, please mail me.

I also attach some little tools to extract image from UsbSnoop logs ( for tascorp / t613 only ) at the end.


So, always checkout the last hg from http://linuxtv.org/hg/~jfrancois/gspca/
if the current version is not working with your device.

[Little FAQ]

1) My webcam is not working, what i can i do?

1.1) Checkout lastest hg and test again. (libv4lconvert is inside v4l2-apps/lib/libv4l/ )

1.2) Check messages to find something relevant, like "sensor not found",
"not supported," usb error",etc.
1.3) Do a # echo 0x3f > /sys/modules/gspca_main/parameters/debug
1.4) Try svv application:
http://moinejf.free.fr/svv.c
1.4.1 ) ./svv
1.4.2 ) ./svv -r
1.4.3 ) ./svv -g -r ( image.dat sould be created if all goes ok )
1.4.4) If there is some "mode" error, you can also try ./svv -m r

1.5 ) Send all logs files within your email. Also attach the image.dat
if it was created on steps 1.4.x

1.6 ) Try to email the author of the subdriver fist and cc the involved people. If you dont get any response, you should email the current responsible of gspca ( moinejf@free.fr ). Also you can get in touch in the maillist.
If related to t613, mailme to lcostantino@gmail.com or le_costantino@pixartargentina.com.ar
1.7) Be prepared to test set of patches.

2) I got asked about win usb traces of my webcam, wtf?

2.1 Get http://www.pcausa.com/Utilities/UsbSnoop/default.htm
2.2 Start logging
2.3 Replug the webcam
2.4 Open the video capture application on win.
2.5 What i usually ask is the following for the first time:
1 - Start preview
2 - Stop preview
3 - Change resolution ( 640x480 -> 320x240 if vga, else another resolution )
4 - Do a Reset Defaults settings on controls
5 - Start Preview
6 - Stop Preview.
7 - Close the log file.
2.6 Attach C:\Windows\UsbSnoop.log.
2.7 Usually i dont care about the image frames ( isoch ), but its help to assure the format is the same as expected and we are not dealing with something else. ( anyway, this help for unknown bridges, etc ).
Do not keep long on the preview, or your log file will get really bigger.
2.8 If all goes ok, and you webcam start streaming when you test newer patches, then you could be asked by a new usb trace with differents instructions ( like changing gamma, colors, etc ).


3) Camorama, gcam, skype, etc, etc do not work!

3.0 Check you already have installed v4l1compat.so or v4l2convert.so
( /usr/src/gspca-xxxx/v4l2-apps/lib/libv4l )
Also there is a README inside that dir.

3.1 Camorama, GQCam and others apps are older. They still use v4l1. Thnxs to libv4lconvert you can still make use of this apps. Something like
#LD_PRELOAD=/usr/local/libv4l/v4l1compat.so camorama
could help.

3.2 Some applications, use v4l2 but do not support some format conversions, in that case you should need this ( for example ) :
#LD_PRELOAD=/usr/local/libv4l/v4l2conver.so skype
--------------------------------------------------------------------
Tools: Copy and Paste on each file.
The blog will mess all the formats, if you need it let me know, i will send it via email. ( one day i will upload it on some place )
This tool is just for analysis purposed, but if you wanna play, is just a simple parser. Also the code could be reduced to fewer lines, but i don't care, its for my use.

How to use it:
1) ruby extract_sets.rb UsbSnoop.log outdir/
2) ruby extract_image.rb outdir/
Extracting from outdir/
Total: 462 Processed: [5/462] [1%]
3) You should see .dat and jpg files inside outdir.

========================================================================
[BEGIN extract_set.rb ]

#!/usr/bin/ruby


if ARGV.length < 2 || ARGV[0].empty? || ARGV[1].empty?
print "Tascorp Image Extract\n"
print "./extract_sets.rb [usbsnoop log file] [sets_dir]"
print "\n"
exit 0
end

print "Extracting from #{ARGV[0]} to Ouput dir #{ARGV[1]}\n"

begin
archivo = File.new(ARGV[0],"r")
rescue => err
puts "Error: #{err}"
exit 0
end

begin
Dir.open(ARGV[1])
rescue => err
puts "Dir do not exists... creating it..."
begin
Dir.mkdir(ARGV[1])
rescue => mkdir_err
puts "Error on mkdir #{err}"
exit 0
end

end

start = false

out_set = nil
count = 0
while str = archivo.gets
if str.strip.chomp.match('[0-9a-b]+:')

if str =~ /ff d8/
start = true
out_set = File.new("#{ARGV[1]}/#{count}.dat","w")
puts "Extracting set #{count}"
count+=1
elsif str =~ /ff d9/ && start == true

out_set << str
out_set.close
start = false
end
if start == true
out_set << str
end
end

end
[ EOF extract_sets.rb ]

[ BEGIN extract_image.rb]

#!/usr/bin/ruby

if ARGV.length < 1 || ARGV[0].empty?
puts "./extract_image.rb data_set_dir"
exit 0
end

print "Extracting from #{ARGV[0]}\n"

count = 0
Dir.chdir(ARGV[0])

files = Dir.glob("*.dat").sort

files.each { |fname|

archivo = File.open(fname)
final_data = String.new
data = Array.new
count += 1
str = "Total: #{files.count} Processed: [#{count}/#{files.count}] [" +
((count*100)/files.count).to_s + "%]"

str.length.times { print "\b"}
print str
$stdout.flush


while str = archivo.gets

nset =
str.strip.chomp.gsub(/[0-9a-h]+:/,'').strip.gsub(/([A-Z]|\[|-).*/,'').gsub(/^02 a[0-1]/,'').strip

if ! nset.empty?
nset.split(' ').each { |s| data << s}
end
end
out = File.open("#{fname.sub(".dat",".jpg")}","wb")
data.each do |byte|
out.print byte.to_a.pack("H*")
end
out.close
}

puts "done"

[EOF extract_image.rb]

Friday, May 9, 2008

17a1:0128 TASCORP



Driver: gspcav2 ( gspca with v4l2 support, etc,etc)
Driver Base - Homepage: http://moinejf.free.fr ( Michel Xhaard / Jean-Fran├žois Moine )
Base file: gspcav2-0.1.0.tar.gz
Patch for: Tascorp 17a1:0128 "XPX JPEG Webcam"
Chipset/Bridge: T613 Sensor: TAS5130A
Link to MailList with patch

Download: Patch File

Note: I need testers for this webcam. Also , be sure that chip and sensor is the same on your device. "Webcam Effects" are there for testing purpose only.

UPDATE: Lastest version of gspca2 with t613 subdriver included ( not need to patch ),
can be downloaded from: http://moinejf.free.fr/gspcav2-0.2.0.tar.gz








diff -Nru gspcav2-0.1.0/gspca.h gspcav2-0.1.0-t613/gspca.h
--- gspcav2-0.1.0/gspca.h 2008-04-28 04:58:27.000000000 -0300
+++ gspcav2-0.1.0-t613/gspca.h 2008-05-07 03:43:09.000000000 -0300
@@ -68,6 +68,12 @@
struct gspca_dev;
struct gspca_frame;

+struct control_menu_info
+{
+ int value;
+ char name[32];
+};
+
/* subdriver operations */
typedef int (*cam_op) (struct gspca_dev *);
typedef void (*cam_v_op) (struct gspca_dev *);
diff -Nru gspcav2-0.1.0/Kbuild gspcav2-0.1.0-t613/Kbuild
--- gspcav2-0.1.0/Kbuild 2008-04-12 03:49:59.000000000 -0300
+++ gspcav2-0.1.0-t613/Kbuild 2008-05-07 03:45:02.000000000 -0300
@@ -5,7 +5,7 @@
gspca_sonixb.o gspca_sonixj.o gspca_spca500.o gspca_spca501.o \
gspca_spca505.o gspca_spca506.o gspca_spca508.o gspca_spca561.o \
gspca_sunplus.o gspca_stk014.o gspca_tv8532.o \
- gspca_vc032x.o gspca_zc3xx.o
+ gspca_vc032x.o gspca_zc3xx.o gspca_t613.o
gspca_conex-objs := conex.o
gspca_etoms-objs := etoms.o
gspca_main-objs := gspca.o
@@ -26,3 +26,5 @@
gspca_tv8532-objs := tv8532.o
gspca_vc032x-objs := vc032x.o
gspca_zc3xx-objs := zc3xx.o
+gspca_t613-objs := t613.o
+
diff -Nru gspcav2-0.1.0/Makefile.standalone gspcav2-0.1.0-t613/Makefile.standalone
--- gspcav2-0.1.0/Makefile.standalone 2008-04-29 03:26:09.000000000 -0300
+++ gspcav2-0.1.0-t613/Makefile.standalone 2008-05-07 03:51:06.000000000 -0300
@@ -49,6 +49,7 @@
gspcav2-$(VERSION)/tv8532.c \
gspcav2-$(VERSION)/vc032x.c \
gspcav2-$(VERSION)/webcam.html \
- gspcav2-$(VERSION)/zc3xx.c;
+ gspcav2-$(VERSION)/zc3xx.c \
+ gspcav2-$(VERSION)/t613.c;
rm gspcav2-$(VERSION)

diff -Nru gspcav2-0.1.0/t613.c gspcav2-0.1.0-t613/t613.c
--- gspcav2-0.1.0/t613.c 1969-12-31 21:00:00.000000000 -0300
+++ gspcav2-0.1.0-t613/t613.c 2008-05-08 03:38:53.000000000 -0300
@@ -0,0 +1,1009 @@
+#define MODULE_NAME "t613"
+#include "gspca.h"
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(0, 0, 21)
+static const char version[] = "0.0.21";
+#define MAX_GAMMA 0x10 //0 to 15
+
+//From LUVCVIEW
+#define V4L2_CID_POWER_LINE_FREQUENCY (V4L2_CID_PRIVATE_BASE+1)
+#define V4L2_CID_SHARPNESS (V4L2_CID_PRIVATE_BASE+0)
+#define V4L2_CID_WHITE_BALANCE_TEMPERATURE_AUTO (V4L2_CID_PRIVATE_BASE + 2 )
+#define V4L2_CID_EFFECTS (V4L2_CID_PRIVATE_BASE + 3 )
+
+
+#define BRIDGE_T16 1
+
+MODULE_AUTHOR("Leandro Costantino ");
+MODULE_DESCRIPTION("GSPCA/T613 (JPEG Compliance ) USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/*
+ *Notes: * t613 + tas5130A
+ * Focus to light do not balance well as in win. Quality in win is not good, but its kinda better.
+ * * Fix some "extraneous bytes", most of apps will show the image anyway
+ * * Gamma table, is there, but its really doing something?
+ * * 7~8 Fps, its ok, max on win its 10.
+ * Costantino Leandro
+ */
+
+
+
+struct sd
+{
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ unsigned char packet[ISO_MAX_SIZE + 128]; // !! no more than 128 ff in an ISO packet
+
+ unsigned char brightness;
+ unsigned char contrast;
+ unsigned char colors;
+ unsigned char autogain;
+ unsigned char gamma;
+ unsigned char sharpness;
+ unsigned char freq;
+ unsigned char whitebalance;
+ unsigned char mirror;
+ unsigned char effect;
+ char qindex;
+ char bridge;
+ char subtype;
+
+};
+
+/* 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_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setlowlight(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getgamma(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 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_setflip(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getflip(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);
+
+
+//just in case someone need to pass it as mod parameter, and use it as in vmicro/ztar module, function its already here
+static void setlightfreq(struct gspca_dev *gspca_dev);
+
+static struct ctrl sd_ctrls[] =
+{
+#define SD_BRIGHTNESS 0
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 0xf,
+ .step = 1,
+ .default_value = 0x9,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+#define SD_CONTRAST 1
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 0xD,
+ .step = 1,
+ .default_value = 0x7,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+#define SD_COLOR 2
+ {
+ {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Color",
+ .minimum = 0,
+ .maximum = 0xF,
+ .step = 1,
+ .default_value = 0x5,
+ },
+ .set = sd_setcolors,
+ .get = sd_getcolors,
+ },
+#define SD_AUTOGAIN 3
+
+ {
+ {
+ .id = V4L2_CID_GAIN, //here, i activate only the lowlight, some apps dont bring up the backligth_compensation control)
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Low Light",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0x1,
+ },
+ .set = sd_setlowlight,
+ .get = sd_getlowlight,
+ },
+#define SD_GAMMA 4
+ {
+ {
+ .id = V4L2_CID_GAMMA, //(gamma on win )
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gamma ( Untested )",
+ .minimum = 0,
+ .maximum = MAX_GAMMA,
+ .step = 1,
+ .default_value = 0x9,
+ },
+ .set = sd_setgamma,
+ .get = sd_getgamma,
+ },
+#define SD_SHARPNESS 5 // (aka definition on win )
+ {
+ {
+ .id = V4L2_CID_SHARPNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Sharpness",
+ .minimum = 0,
+ .maximum = MAX_GAMMA , //0 to 16
+ .step = 1,
+ .default_value = 0x6,
+ },
+ .set = sd_setsharpness,
+ .get = sd_getsharpness,
+ },
+#define SD_LIGHTFREQ 6
+ {
+ {
+ .id = V4L2_CID_POWER_LINE_FREQUENCY,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .name = "Light Frequency Filter",
+ .minimum = 0, //0 -> 0x50, 1->0x60
+ .maximum = 1 ,
+ .step = 1,
+ .default_value = 0,
+ },
+ .set = sd_setfreq,
+ .get = sd_getfreq
+ },
+
+#define SD_WHITE_BALANCE 7
+ {
+ {
+ .id = V4L2_CID_WHITE_BALANCE_TEMPERATURE_AUTO,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "White Balance",
+ .minimum = 0,
+ .maximum = 1 ,
+ .step = 1,
+ .default_value = 1,
+ },
+ .set = sd_setwhitebalance,
+ .get = sd_getwhitebalance
+ },
+#define SD_MIRROR 8
+ {
+ {
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Mirror Image",
+ .minimum = 0,
+ .maximum = 1 ,
+ .step = 1,
+ .default_value = 0,
+ },
+ .set = sd_setflip,
+ .get = sd_getflip
+ },
+
+#define SD_EFFECTS 8
+ {
+ {
+ .id = V4L2_CID_EFFECTS,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .name = "Webcam Effects",
+ .minimum = 0,
+ .maximum = 4 ,
+ .step = 1,
+ .default_value = 0,
+ },
+ .set = sd_seteffect,
+ .get = sd_geteffect
+ },
+
+};
+
+static struct control_menu_info flicker_control[] =
+{
+ { 0, "50 Hz" },
+ { 1, "60 Hz" },
+
+};
+#define NUM_FLICKER_CONTROL (sizeof(flicker_control)/sizeof(flicker_control[0]))
+static struct control_menu_info effects_control[] =
+{
+ { 0, "Normal" },
+ { 1, "Emboss" }, //disabled
+ { 2, "Monochrome" },
+ { 3, "Sepia" },
+ { 4, "Sketch" },
+ { 5, "Sun Effect" }, //disabled
+ { 6, "Negative" },
+};
+#define NUM_EFFECTS_CONTROL (sizeof(effects_control)/sizeof(effects_control[0]))
+
+
+static struct cam_mode vga_mode_t16[]=
+{
+ {V4L2_PIX_FMT_JPEG, 160, 120, 4},
+ {V4L2_PIX_FMT_JPEG, 176, 144, 3},
+ {V4L2_PIX_FMT_JPEG, 320, 240, 2},
+ {V4L2_PIX_FMT_JPEG, 352, 288, 1},
+ {V4L2_PIX_FMT_JPEG, 640, 480, 0},
+
+}
+;
+#define T16_OFFSET_DATA 631
+#define MAX_EFFECTS 7
+/* easily done by soft, this table could be removed, i keep it here just in case */
+unsigned char effects_table[MAX_EFFECTS][6]=
+{
+ {0xa8,0xe8,0xc6,0xd2,0xc0,0x00}, //Normal
+ {0xa8,0xc8,0xc6,0x52,0xc0,0x04},//Repujar
+ {0xa8,0xe8,0xc6,0xd2,0xc0,0x20}, //Monochrome
+ {0xa8,0xe8,0xc6,0xd2,0xc0,0x80}, //Sepia
+ {0xa8,0xc8,0xc6,0x52,0xc0,0x02}, //Croquis
+ {0xa8,0xc8,0xc6,0xd2,0xc0,0x10}, //Sun Effect
+ {0xa8,0xc8,0xc6,0xd2,0xc0,0x40}, //Negative
+};
+
+
+
+unsigned char gamma_table[MAX_GAMMA][34]=
+{
+ {0x90 ,0x00 ,0x91 ,0x3e ,0x92 ,0x69 ,0x93 ,0x85 ,0x94 ,0x95 ,0x95 ,0xa1 ,0x96 ,0xae ,0x97 ,0xb9 ,0x98 ,0xc2 ,0x99 ,0xcb ,0x9a ,0xd4 ,0x9b ,0xdb ,0x9c ,0xe3 ,0x9d ,0xea ,0x9e ,0xf1 ,0x9f ,0xf8 ,0xa0 ,0xff },
+ {0x90 ,0x00 ,0x91 ,0x33 ,0x92 ,0x5A ,0x93 ,0x75 ,0x94 ,0x85 ,0x95 ,0x93 ,0x96 ,0xA1 ,0x97 ,0xAD ,0x98 ,0xB7 ,0x99 ,0xC2 ,0x9A ,0xCB ,0x9B ,0xD4 ,0x9C ,0xDE ,0x9D ,0xE7 ,0x9E ,0xF0 ,0x9F ,0xF7 ,0xa0 ,0xff },
+ {0x90 ,0x00 ,0x91 ,0x2F ,0x92 ,0x51 ,0x93 ,0x6B ,0x94 ,0x7C ,0x95 ,0x8A ,0x96 ,0x99 ,0x97 ,0xA6 ,0x98 ,0xB1 ,0x99 ,0xBC ,0x9A ,0xC6 ,0x9B ,0xD0 ,0x9C ,0xDB ,0x9D ,0xE4 ,0x9E ,0xED ,0x9F ,0xF6 ,0xa0 ,0xff },
+ {0x90 ,0x00 ,0x91 ,0x29 ,0x92 ,0x48 ,0x93 ,0x60 ,0x94 ,0x72 ,0x95 ,0x81 ,0x96 ,0x90 ,0x97 ,0x9E ,0x98 ,0xAA ,0x99 ,0xB5 ,0x9A ,0xBF ,0x9B ,0xCB ,0x9C ,0xD6 ,0x9D ,0xE1 ,0x9E ,0xEB ,0x9F ,0xF5 ,0xa0 ,0xff },
+ {0x90 ,0x00 ,0x91 ,0x23 ,0x92 ,0x3F ,0x93 ,0x55 ,0x94 ,0x68 ,0x95 ,0x77 ,0x96 ,0x86 ,0x97 ,0x95 ,0x98 ,0xA2 ,0x99 ,0xAD ,0x9A ,0xB9 ,0x9B ,0xC6 ,0x9C ,0xD2 ,0x9D ,0xDE ,0x9E ,0xE9 ,0x9F ,0xF4 ,0xa0 ,0xff },
+ {0x90 ,0x00 ,0x91 ,0x1B ,0x92 ,0x33 ,0x93 ,0x48 ,0x94 ,0x59 ,0x95 ,0x69 ,0x96 ,0x79 ,0x97 ,0x87 ,0x98 ,0x96 ,0x99 ,0xA3 ,0x9A ,0xB1 ,0x9B ,0xBE ,0x9C ,0xCC ,0x9D ,0xDA ,0x9E ,0xE7 ,0x9F ,0xF3 ,0xa0 ,0xff },
+ {0x90 ,0x00 ,0x91 ,0x02 ,0x92 ,0x10 ,0x93 ,0x20 ,0x94 ,0x32 ,0x95 ,0x40 ,0x96 ,0x57 ,0x97 ,0x67 ,0x98 ,0x77 ,0x99 ,0x88 ,0x9a ,0x99 ,0x9b ,0xaa ,0x9c ,0xbb ,0x9d ,0xcc ,0x9e ,0xdd ,0x9f ,0xee ,0xa0 ,0xff },
+ {0x90 ,0x00 ,0x91 ,0x02 ,0x92 ,0x14 ,0x93 ,0x26 ,0x94 ,0x38 ,0x95 ,0x4A ,0x96 ,0x60 ,0x97 ,0x70 ,0x98 ,0x80 ,0x99 ,0x90 ,0x9A ,0xA0 ,0x9B ,0xB0 ,0x9C ,0xC0 ,0x9D ,0xD0 ,0x9E ,0xE0 ,0x9F ,0xF0 ,0xa0 ,0xff },
+ {0x90 ,0x00 ,0x91 ,0x10 ,0x92 ,0x22 ,0x93 ,0x35 ,0x94 ,0x47 ,0x95 ,0x5A ,0x96 ,0x69 ,0x97 ,0x79 ,0x98 ,0x88 ,0x99 ,0x97 ,0x9A ,0xA7 ,0x9B ,0xB6 ,0x9C ,0xC4 ,0x9D ,0xD3 ,0x9E ,0xE0 ,0x9F ,0xF0 ,0xa0 ,0xff },
+ {0x90 ,0x00 ,0x91 ,0x10 ,0x92 ,0x26 ,0x93 ,0x40 ,0x94 ,0x54 ,0x95 ,0x65 ,0x96 ,0x75 ,0x97 ,0x84 ,0x98 ,0x93 ,0x99 ,0xa1 ,0x9a ,0xb0 ,0x9b ,0xbd ,0x9c ,0xca ,0x9d ,0xd6 ,0x9e ,0xe0 ,0x9f ,0xf0 ,0xa0 ,0xff },
+ {0x90 ,0x00 ,0x91 ,0x18 ,0x92 ,0x2B ,0x93 ,0x44 ,0x94 ,0x60 ,0x95 ,0x70 ,0x96 ,0x80 ,0x97 ,0x8E ,0x98 ,0x9C ,0x99 ,0xAA ,0x9A ,0xB7 ,0x9B ,0xC4 ,0x9C ,0xD0 ,0x9D ,0xD8 ,0x9E ,0xE2 ,0x9F ,0xF0 ,0xa0 ,0xff },
+ {0x90 ,0x00 ,0x91 ,0x1A ,0x92 ,0x34 ,0x93 ,0x52 ,0x94 ,0x66 ,0x95 ,0x7E ,0x96 ,0x8D ,0x97 ,0x9B ,0x98 ,0xA8 ,0x99 ,0xB4 ,0x9A ,0xC0 ,0x9B ,0xCB ,0x9C ,0xD6 ,0x9D ,0xE1 ,0x9E ,0xEB ,0x9F ,0xF5 ,0xa0 ,0xff },
+ {0x90 ,0x00 ,0x91 ,0x3F ,0x92 ,0x5A ,0x93 ,0x6E ,0x94 ,0x7F ,0x95 ,0x8E ,0x96 ,0x9C ,0x97 ,0xA8 ,0x98 ,0xB4 ,0x99 ,0xBF ,0x9A ,0xC9 ,0x9B ,0xD3 ,0x9C ,0xDC ,0x9D ,0xE5 ,0x9E ,0xEE ,0x9F ,0xF6 ,0xA0 ,0xFF},
+ {0x90 ,0x00 ,0x91 ,0x54 ,0x92 ,0x6F ,0x93 ,0x83 ,0x94 ,0x93 ,0x95 ,0xA0 ,0x96 ,0xAD ,0x97 ,0xB7 ,0x98 ,0xC2 ,0x99 ,0xCB ,0x9A ,0xD4 ,0x9B ,0xDC ,0x9C ,0xE4 ,0x9D ,0xEB ,0x9E ,0xF2 ,0x9F ,0xF9 ,0xa0 ,0xff },
+ {0x90 ,0x00 ,0x91 ,0x6E ,0x92 ,0x88 ,0x93 ,0x9A ,0x94 ,0xA8 ,0x95 ,0xB3 ,0x96 ,0xBD ,0x97 ,0xC6 ,0x98 ,0xCF ,0x99 ,0xD6 ,0x9A ,0xDD ,0x9B ,0xE3 ,0x9C ,0xE9 ,0x9D ,0xEF ,0x9E ,0xF4 ,0x9F ,0xFA ,0xa0 ,0xff },
+ {0x90 ,0x00 ,0x91 ,0x93 ,0x92 ,0xA8 ,0x93 ,0xB7 ,0x94 ,0xC1 ,0x95 ,0xCA ,0x96 ,0xD2 ,0x97 ,0xD8 ,0x98 ,0xDE ,0x99 ,0xE3 ,0x9A ,0xE8 ,0x9B ,0xED ,0x9C ,0xF1 ,0x9D ,0xF5 ,0x9E ,0xF8 ,0x9F ,0xFC ,0xA0 ,0xFF}
+}
+;
+
+static __u8 tas5130a_sensor_init[][8]=
+{
+ {0x62,0x08,0x63,0x70,0x64,0x1d,0x60,0x09},
+ {0x62,0x20,0x63,0x01,0x64,0x02,0x60,0x09},
+ {0x62,0x07,0x63,0x03,0x64,0x00,0x60,0x09},
+ {0x62,0x07,0x63,0x03,0x64,0x00,0x60,0x09},
+ {0,0,0,0,0,0,0,0 },
+
+};
+
+static void t16RegRead(struct usb_device *dev,
+ __u16 reg,
+ __u16 value,
+ __u16 index,
+ __u8 *buffer, __u16 length)
+{
+ usb_control_msg(dev,
+ usb_rcvctrlpipe(dev, 0),
+ reg,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ (__u16) value, (__u16) index, buffer, length,
+ 500);
+}
+
+static void t16RegWrite(struct usb_device *dev,
+ __u16 reg,
+ __u16 value,
+ __u16 index,
+ __u8 *buffer, __u16 length)
+{
+ usb_control_msg(dev,
+ usb_sndctrlpipe(dev, 0),
+ reg,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ (__u16) value, (__u16) index, buffer, length,
+ 500);
+}
+
+/* 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;
+ struct cam *cam;
+ __u16 vendor;
+ __u16 product;
+
+ vendor = id->idVendor;
+ product = id->idProduct;
+ switch (vendor)
+ {
+ case 0x17a1:
+ //t613 + tas5130A
+ //Currently one sensor supported...
+ sd->freq = 0;
+ sd->bridge = BRIDGE_T16;
+ break;
+
+ default:
+ break;;
+ }
+
+ cam = &gspca_dev->cam;
+ cam->dev_name = (char *) id->driver_info;
+ cam->epaddr = 0x01;
+
+ switch (sd->bridge)
+ {
+
+ default:
+ case BRIDGE_T16:
+ cam->cam_mode = vga_mode_t16;
+ cam->nmodes = sizeof vga_mode_t16 / sizeof vga_mode_t16[0];
+ break;
+
+ }
+ sd->qindex = 4;
+ sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+ sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+ sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
+ sd->gamma = sd_ctrls[SD_GAMMA].qctrl.default_value;
+ sd->sharpness = sd_ctrls[SD_SHARPNESS].qctrl.default_value;
+ sd->freq = sd_ctrls[SD_LIGHTFREQ].qctrl.default_value;
+ sd->whitebalance = sd_ctrls[SD_WHITE_BALANCE].qctrl.default_value;
+ sd->mirror = sd_ctrls[SD_MIRROR].qctrl.default_value;
+ sd->effect = sd_ctrls[SD_EFFECTS].qctrl.default_value;
+ return 0;
+}
+
+static int init_default_parameters( struct gspca_dev * gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+
+ /* some of this registers are not really neded, because they are overriden by setbrigthness, setcontrast, etc,
+ * but wont hurt anyway, and can help someone with similar webcam to see the initial parameters.*/
+ int i=0;
+ __u8 test_byte;
+
+ unsigned char read_indexs[]={0x06,0x07,0x0a,0x0b,0x66,0x80,0x81,0x8e,0x8f,0xa5,0xa6,0xa8,0xbb,0xbc,0xc6,0x00,0x00};
+ unsigned char nset[6]={0x61,0xc2,0x65,0x0d,0x60,0x08};
+ unsigned char nset1[50]={
+ 0x80 ,0x3c ,0x81 ,0x68 ,0x83 ,0xa0 ,0x84 ,0x20 ,0x8a ,0x5c ,0x8b ,0x4c ,0x8c ,0x88 ,0x8e ,0xb4,
+ 0x8f ,0x24 ,0xa1 ,0xb1 ,0xa2 ,0x30 ,0xa5 ,0x18 ,0xa6 ,0x4a ,0xae ,0x03 ,0xb1 ,0x44 ,0xb2 ,0x08,
+ 0xb7 ,0x06 ,0xb9 ,0xe7 ,0xbb ,0xc4 ,0xbc ,0x4a ,0xbe ,0x36 ,0xbf ,0xff ,0xc2 ,0x88 ,0xc5 ,0xc0,
+ 0xc6 ,0xd2
+ };
+ unsigned char nset4[18]={
+ 0xe0,0x40,0xe1,0x80,0xe2,0xc0,0xe3,0x41,0xe4,0x81,0xe5,0xc3,0xe6,0x5c,0xe7,0x99,
+ 0xe8,0xe0
+ };
+ //ojo puede ser 0xe6 en vez de 0xe9
+ unsigned char nset2[20]={
+ 0xd0,0xff,0xd1,0xa7,0xd2,0x28,0xd3,0x19,0xd4,0xa0,0xd5,0x07,0xd6,0x04,0xd7,0x62,
+ 0xd8,0xe6,0xd9,0xbc
+ };
+ unsigned char nset3[18]={
+ 0xc7,0x40,0xc8,0x80,0xc9,0xc0,0xca,0x40,0xcb,0x80,0xcc,0xc0,0xcd,0x4d,0xce,0x97,
+ 0xcf,0xe4
+ };
+ unsigned char nset5[4]={0x8f,0x24,0xc3,0x00}; //bright
+ unsigned char nset6[34]={
+ 0x90,0x00,0x91,0x10,0x92,0x26,0x93,0x40,0x94,0x54,0x95,0x65,0x96,0x75,0x97,0x84,
+ 0x98,0x93,0x99,0xa1,0x9a,0xb0,0x9b,0xbd,0x9c,0xca,0x9d,0xd6,0x9e,0xe0,0x9f,0xf0,
+ 0xa0,0xff
+ }; //Gamma
+ unsigned char nset7[4]={0x66,0x00,0xa8,0xe8}; //50/60 Hz
+ unsigned char nset9[4]={0x0b,0x04,0x0a,0x40};
+ unsigned char nset8[6]={0xa8,0xe8,0xc6,0xd2,0xc0,0x00};
+ unsigned char nset10[6]={0x0c,0x03,0xab,0x08,0x81,0x68};
+
+ while( read_indexs[i] != 0x00 )
+ {
+ t16RegRead(dev,0x00,0x00,read_indexs[i], &test_byte,1);
+ PDEBUG( D_CONF, "Reg 0x%x => 0x%x\n",read_indexs[i],test_byte);
+ i++;
+ }
+
+ t16RegWrite(dev, 0x00,0x01,0x0000,nset,0x06);
+ t16RegWrite(dev, 0x00,0x01,0x0000,nset1,0x32);
+ t16RegWrite(dev, 0x00,0x01,0x0000,nset2,0x14);
+ t16RegWrite(dev, 0x00,0x01,0x0000,nset3,0x12);
+ t16RegWrite(dev, 0x00,0x01,0x0000,nset4,0x12);
+ t16RegWrite(dev, 0x00,0x00,0x3c80,0x00,0x0);
+ t16RegWrite(dev, 0x00,0x00,0x3c80,0x00,0x0);
+ t16RegWrite(dev, 0x00,0x00,0xb48e,0x00,0x0);
+ t16RegWrite(dev, 0x00,0x01,00,nset5,0x05);
+ t16RegWrite(dev, 0x00,0x00,0x00a9,0x00,0x0);
+ t16RegWrite(dev, 0x00,0x01,00,nset6,0x22);
+ t16RegWrite(dev, 0x00,0x00,0xc6bb,0x00,0x0);
+ t16RegWrite(dev, 0x00,0x00,0x4aa6,0x00,0x0);
+ // missing write..
+ //t16RegWrite(dev, 0x00,0x01,00,default,0x08);
+ t16RegWrite(dev, 0x00,0x00,0x2087,0x00,0x0);
+ t16RegWrite(dev, 0x00,0x00,0x2088,0x00,0x0);
+ t16RegWrite(dev, 0x00,0x00,0x2089,0x00,0x0);
+
+ t16RegWrite(dev, 0x00,0x01,00,nset7,0x4);
+ t16RegWrite(dev, 0x00,0x01,00,nset10,0x06);
+ t16RegWrite(dev, 0x00,0x01,00,nset8,0x06);
+ t16RegWrite(dev, 0x00,0x01,00,nset9,0x04);
+
+ t16RegWrite(dev, 0x00,0x01,0x0000,nset2,0x14);
+ t16RegWrite(dev, 0x00,0x01,0x0000,nset3,0x12);
+ t16RegWrite(dev, 0x00,0x01,0x0000,nset4,0x12);
+
+ return 0;
+}
+
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ unsigned int brightness;
+ unsigned char set6[4]= {0x8f,0x26,0xc3,0x80};
+ brightness = sd->brightness;
+
+ if( brightness < 7 )
+ set6[3]= 0x70 - ( brightness * 0xa);
+ else
+ {
+ set6[1]= 0x24;
+ set6[3]= 0x00 + (( brightness-7) * 0xa);
+ }
+
+ t16RegWrite(dev, 0x00,0x01,0x0000,set6,4);
+}
+
+static void setflip(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+
+ unsigned char flipcmd[8]= {0x62,0x07,0x63,0x03,0x64,0x00,0x60,0x09};
+
+ if( sd->mirror == 1 )
+ flipcmd[3] = 0x01;
+
+ t16RegWrite(dev, 0x00,0x01,0x0000,flipcmd,8);
+
+}
+
+static void seteffect(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+
+ //just in case...
+ if( sd->effect >= MAX_EFFECTS )
+ sd->effect=0;
+
+ t16RegWrite(dev,0x00,0x01,0x0000, effects_table[sd->effect],0x6);
+ if( sd->effect == 1 || sd->effect ==5 )
+ {
+ PDEBUG( D_CONF, "This effect have been disabled for webcam \"safety\"\n");
+ return;
+ }
+
+ if( sd->effect == 1 || sd->effect == 4 )
+ t16RegWrite(dev,0x00,0x00,0x4aa6,0x00,0x00);
+ else
+ t16RegWrite(dev,0x00,0x00,0xfaa6,0x00,0x00);
+
+}
+
+static void setwhitebalance(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+
+ unsigned char white_balance[8]= {0x87,0x20,0x88,0x20,0x89,0x20,0x80,0x38};
+
+ if( sd->whitebalance == 1 )
+ white_balance[7]=0x3c;
+
+ t16RegWrite(dev, 0x00,0x01,0x0000,white_balance,8);
+
+}
+
+static void setlightfreq( struct gspca_dev *gspca_dev )
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ __u8 freq[4] = {0x66,0x40,0xa8,0xe8};
+
+ if( sd->freq == 1 ) //60hz
+ freq[1]= 0x00;
+
+ t16RegWrite(dev,0x00,0x1,0x0000,freq,0x4);
+
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev )
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ unsigned int contrast = sd->contrast;
+ __u16 reg_to_write = 0x00;
+
+ if( contrast < 7 )
+ reg_to_write = 0x8ea9 - (0x200 * contrast);
+ else
+ reg_to_write = ( 0x00a9 + ( (contrast-7) * 0x200 ));
+
+ t16RegWrite(dev,0x00,0x00,reg_to_write,0x00,0);
+
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ __u16 reg_to_write = 0x00;
+
+ reg_to_write = 0xc0bb + (sd->colors * 0x100);
+ t16RegWrite(dev,0x00, 0x00,reg_to_write,0x00,0);
+
+
+}
+
+static void setgamma(struct gspca_dev *gspca_dev)
+{
+
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+
+ printk( KERN_INFO " Gamma: %d\n", sd->gamma);
+
+ if( sd->gamma >= MAX_GAMMA)
+ sd->gamma = 5;
+
+ t16RegWrite(dev, 0x00,0x01,0x0000, gamma_table[sd->gamma],34);
+
+}
+
+static void setsharpness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ __u16 reg_to_write = 0x00;
+ reg_to_write = (0x0aa6) + (0x1000 * sd->sharpness);
+
+ t16RegWrite(dev, 0x00,0x00,reg_to_write, 0x00,0x00);
+
+}
+
+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 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ *val = sd->brightness;
+ return *val;
+}
+
+
+static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->whitebalance = val;
+ if (gspca_dev->streaming)
+ setwhitebalance(gspca_dev);
+ return 0;
+}
+
+static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->whitebalance;
+ return *val;
+}
+
+
+static int sd_setflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->mirror = val;
+ if (gspca_dev->streaming)
+ setflip(gspca_dev);
+ return 0;
+}
+
+static int sd_getflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->mirror;
+ return *val;
+}
+
+static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+
+ sd->effect = val;
+ if (gspca_dev->streaming)
+ seteffect(gspca_dev);
+ return 0;
+
+}
+
+static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->effect;
+ return *val;
+}
+
+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 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ *val = sd->contrast;
+ return *val;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->colors = val;
+ if (gspca_dev->streaming)
+ setcolors(gspca_dev);
+ return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->colors;
+ return 0;
+}
+
+static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->gamma = val;
+ if (gspca_dev->streaming)
+ setgamma(gspca_dev);
+
+ return 0;
+}
+
+static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ *val = sd->gamma;
+ return 0;
+}
+
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->freq = val;
+ if (gspca_dev->streaming)
+ setlightfreq(gspca_dev);
+ return 0;
+}
+
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ *val = sd->freq;
+ 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 0;
+}
+
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ *val = sd->sharpness;
+ return 0;
+}
+
+/* Low Light set here......*/
+static int sd_setlowlight(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+
+ sd->autogain = val;
+ if( val == 1 )
+ t16RegWrite(dev, 0x00,0x00,0xf48e,0x00,0);
+ else
+ t16RegWrite(dev, 0x00,0x00,0xb48e,0x00,0);
+
+ return 0;
+}
+
+static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->autogain;
+ return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ int mode;
+ __u8 test_byte;
+
+ unsigned char t1[]={0x66,0x00,0xa8,0xe8};
+ unsigned char t2[]={0x07,0x00,0x0d,0x60,0x0e,0x80};
+ unsigned char t3[]={0xb3,0x07,0xb4,0x00,0xb5,0x88,0xb6,0x02,0xb7,0x06,0xb8,0x00,0xb9,0xe7,0xba,0x01};
+ unsigned char t4[]={0x0b,0x04,0x0a,0x40};
+
+ switch( sd->bridge)
+ {
+ default:
+ case BRIDGE_T16:
+ mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].mode;
+ switch(mode)
+ {
+ case 1: //352x288
+ t2[1] = 0x40;
+ break;;
+ case 2: //320x240
+ t2[1] = 0x10;
+ break;;
+ case 3: //176x144
+ t2[1] = 0x50;
+ break;;
+ case 4: //160x120
+ t2[1] =0x20;
+ break;;
+ default: //640x480 (0x00)
+ break;;
+ }
+ break;;
+ }
+
+ t16RegWrite(dev, 0x00,0x01,0x0000,tas5130a_sensor_init[0],0x8);
+ t16RegWrite(dev, 0x00,0x01,0x0000,tas5130a_sensor_init[1],0x8);
+ t16RegWrite(dev, 0x00,0x01,0x0000,tas5130a_sensor_init[2],0x8);
+ t16RegWrite(dev, 0x00,0x01,0x0000,tas5130a_sensor_init[3],0x8);
+ t16RegWrite(dev, 0x00,0x00,0x3c80,0x00,0x00);//just in case and to keep sync with logs ( for mine )
+ t16RegWrite(dev, 0x00,0x01,0x0000,tas5130a_sensor_init[3],0x8);
+ t16RegWrite(dev, 0x00,0x00,0x3c80,0x00,0x00);//just in case and to keep sync with logs ( for mine )
+ t16RegWrite(dev, 0x00,0x01,0x0000,t1,4);
+ t16RegWrite(dev, 0x00,0x01,0x0000,t2,6);
+ t16RegRead(dev,0x00,0x00,0x0012,&test_byte,0x1);
+ t16RegWrite(dev, 0x00,0x01,0x0000,t3,0x10);
+ t16RegWrite(dev,0x00,0x00,0x0013,0x00,0x00);
+ t16RegWrite(dev, 0x00,0x01,0x0000,t4,0x4);
+ //restar on each start, just in case, sometimes regs goes wrong when using controls from app
+ setbrightness(gspca_dev);
+ setcontrast(gspca_dev);
+ setcolors( gspca_dev);
+ seteffect(gspca_dev);
+ setflip( gspca_dev);
+
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame, // target
+ unsigned char *data, // isoc packet
+ int len) // iso packet length
+{
+ int sof = 0;
+ static unsigned char ffd9[] = {0xff, 0xd9};
+
+
+ if( data[0] == 0x5a )
+ {
+ //Control Packet, after this came the header again, but extra bytes came in the packet before this , sometimes an EOF arrives, sometimes not...
+ return;
+ }
+
+ if( data[len-1] == 0xff && data[len] ==0xd9 )
+ {
+ //Just in case, i have seen packets with the marker, other's do not include it...
+ data+=2;
+ len -=4;
+ }
+
+ else if( data[2] == 0xff && data[3] == 0xd8 )
+ {
+ sof=1;
+ data+=2;
+ len -=2;
+ }
+ else
+ {
+ data += 2;
+ len -= 2;
+ }
+
+ if (sof)
+ {
+ //extra bytes..... , could be processed too but would be a waste of time, right now leave the application and libjpeg do it for ourserlves..
+ frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+ ffd9, 2);
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len );
+ return;
+ }
+
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+ return;
+
+}
+
+static int sd_querymenu (struct gspca_dev *gspca_dev,struct v4l2_querymenu *menu)
+{
+ memset(menu->name,0,sizeof(menu->name));
+
+ switch( menu->id )
+ {
+ case V4L2_CID_POWER_LINE_FREQUENCY:
+
+ if( menu->index < 0 || menu->index >= NUM_FLICKER_CONTROL )
+ return -EINVAL;
+ strncpy(menu->name,flicker_control[menu->index].name,32);
+ break;;
+ case V4L2_CID_EFFECTS:
+ if( menu->index < 0 || menu->index >= NUM_EFFECTS_CONTROL )
+ return -EINVAL;
+ strncpy(menu->name,effects_control[menu->index].name,32);
+ break;;
+ default:
+ break;;
+ };
+
+
+ return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ switch (sd->bridge)
+ {
+ case BRIDGE_T16:
+ init_default_parameters(gspca_dev);
+ break;;
+ default:
+ break;;
+
+ }
+ return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc =
+{
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = sizeof sd_ctrls / sizeof sd_ctrls[0],
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .pkt_scan = sd_pkt_scan,
+ .querymenu = sd_querymenu,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] =
+{
+ {USB_DEVICE(0x17a1, 0x0128), DVNM("XPX Webcam")},
+
+ {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ PDEBUG(D_PROBE, "camera probe");
+ return gspca_dev_probe(intf, id, &sd_desc, sizeof (struct sd));
+}
+
+static struct usb_driver sd_driver =
+{
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ PDEBUG(D_PROBE, "v%s registered", version);
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
+
+
+

Thursday, May 8, 2008

Microdia 0c45:612a - Patch



Driver: gspcav1
Driver Base - Homepage: mxhaard.free.fr ( Michel Xhaard )
Base file: gspcav1-20071224.tgz


Patch for: Microdia 0c45:612a "Avant" Camera
Chipset/Bridge: SN9C325 Sensor: OV7648
Link to MailList with patch

Download: Patch File









diff -Nru gspcav1-20071224/Sonix/sn9cxxx.h gspcav1-20071224-sn9c325-ov7648/Sonix/sn9cxxx.h
--- gspcav1-20071224/Sonix/sn9cxxx.h 2007-04-26 09:51:48.000000000 -0300
+++ gspcav1-20071224-sn9c325-ov7648/Sonix/sn9cxxx.h 2008-02-26 23:10:17.000000000 -0300
@@ -80,6 +80,7 @@
SN9C105,
SN9C110,
SN9C120,
+ SN9C325,
};

static __u8 sn_mi0360[] = {
@@ -114,6 +115,13 @@
0x01, 0x01, 0x08, 0x28, 0x1e, 0x20, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
//reg12 reg13 reg14 reg15 reg16 reg17 reg18 reg19 reg1a reg1b reg1c reg1d reg1e reg1f reg20 reg21 reg22 reg23
};
+
+static __u8 sn_ov7648[] =
+{
+ 0x00,0x21,0x62,0x00,0x1a,0x20,0x20,0x20,0xA1,0x6E,0x18,0x65,
+ 0x00,0x00,0x00,0x10,0x03,0x00,0x00,0x06,0x06,0x28,0x1E,0x82,
+ 0x07,0x00,0x00,0x00,0x00,0x00
+};

static __u8 reg9a[] = {
0x08, 0x40, 0x20, 0x10, 0x00, 0x04
@@ -128,6 +136,20 @@
//0x3E, 0x00, 0xC3, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00
0x3E, 0x00, 0xC3, 0x0F, 0xf7, 0x0f, 0x0a, 0x00, 0x00
};
+static __u8 reg9a_sn9c325[]=
+{
+ 0x0a,0x40,0x38,0x30,0x00,0x20
+};
+static __u8 regsn20_sn9c325[]=
+{
+ 0x0A,0x3A,0x56, 0x6C ,0x7E ,0x8D ,0x9A ,0xA4 ,0xAF ,0xBB ,0xC5 ,0xCD ,0xD5 ,0xDE ,0xE8 ,0xED ,0xF5
+}
+;
+static __u8 reg84_sn9c325[] =
+{
+ 0x14,0x00,0x27,0x00,0x07,0x00,0xE4,0x0F,0xD3,0x0F,0x4B,0x00,0x48,0x00,0xC0,0x0F,0xF8,0x0F,0x00,0x00,0x00
+};
+
static __u8 hv7131r_sensor_init[][8] = {
{0xC1, 0x11, 0x01, 0x08, 0x01, 0x00, 0x00, 0x10},
{0xB1, 0x11, 0x34, 0x17, 0x7F, 0x00, 0x00, 0x10},
@@ -309,6 +331,60 @@
};
// reg0x04 reg0x07 reg 0x10
//expo = (COM1 & 0x02) | (AECHH & 0x2f <<10) [ (AECh << 2)
+static __u8 ov7648_sensor_init[][8] =
+{
+ {0xC1,0x00,0x01,0x00,0x00,0x00,0x01,0x00},
+ {0xC1,0x00,0x00,0x00,0x00,0x00,0x01,0x00},
+ {0xC1,0x00,0x01,0x00,0x00,0x00,0x01,0x00},
+ {0xA1,0x6E,0x3F,0x20,0x00,0x00,0x00,0x10},
+ {0xA1,0x6E,0x3F,0x00,0x00,0x00,0x00,0x10},
+ {0xA1,0x6E,0x3E,0x00,0x00,0x00,0x00,0x10},
+ {0xD1,0x6E,0x04,0x02,0xB1,0x02,0x39,0x10},
+ {0xD1,0x6E,0x08,0x00,0x01,0x00,0x00,0x10},
+ {0xD1,0x6E,0x0C,0x02,0x7F,0x01,0xE0,0x10},
+ {0xD1,0x6E,0x12,0x03,0x02,0x00,0x03,0x10},
+ {0xD1,0x6E,0x16,0x85,0x40,0x4A,0x40,0x10},
+ {0xC1,0x6E,0x1A,0x00,0x80,0x00,0x00,0x10},
+ {0xD1,0x6E,0x1D,0x08,0x03,0x00,0x00,0x10},
+ {0xD1,0x6E,0x23,0x00,0xB0,0x00,0x94,0x10},
+ {0xD1,0x6E,0x27,0x58,0x00,0x00,0x00,0x10},
+ {0xD1,0x6E,0x2D,0x14,0x35,0x61,0x84,0x10},
+ {0xD1,0x6E,0x31,0xA2,0xBD,0xD8,0xFF,0x10},
+ {0xD1,0x6E,0x35,0x06,0x1E,0x12,0x02,0x10},
+ {0xD1,0x6E,0x39,0xAA,0x53,0x37,0xD5,0x10},
+ {0xA1,0x6E,0x3D,0xF2,0x00,0x00,0x00,0x10},
+ {0xD1,0x6E,0x3E,0x00,0x00,0x80,0x03,0x10},
+ {0xD1,0x6E,0x42,0x03,0x00,0x00,0x00,0x10},
+ {0xC1,0x6E,0x46,0x00,0x80,0x80,0x00,0x10},
+ {0xD1,0x6E,0x4B,0x02,0xEF,0x08,0xCD,0x10},
+ {0xD1,0x6E,0x4F,0x00,0xD0,0x00,0xA0,0x10},
+ {0xD1,0x6E,0x53,0x01,0xAA,0x01,0x40,0x10},
+ {0xD1,0x6E,0x5A,0x50,0x04,0x30,0x03,0x10},
+ {0xA1,0x6E,0x5E,0x00,0x00,0x00,0x00,0x10},
+ {0xD1,0x6E,0x5F,0x10,0x40,0xFF,0x00,0x10},
+ /* {0xD1,0x6E,0x63,0x40,0x40,0x00,0x00,0x10},
+ {0xD1,0x6E,0x67,0x00,0x00,0x00,0x00,0x10}, This is currently setting a
+ {0xD1,0x6E,0x6B,0x00,0x00,0x00,0x00,0x10}, blue tint, and some things more , i leave it here for future test if
+ {0xD1,0x6E,0x6F,0x00,0x00,0x00,0x00,0x10}, somene is having problems with color on this sensor
+ {0xC1,0x6E,0x73,0x10,0x80,0xEB,0x00,0x10},
+ {0xA1,0x6E,0x1E,0x03,0x00,0x00,0x00,0x10},
+ {0xA1,0x6E,0x15,0x01,0x00,0x00,0x00,0x10},
+ {0xC1,0x6E,0x16,0x40,0x40,0x40,0x00,0x10},
+ {0xA1,0x6E,0x1D,0x08,0x00,0x00,0x00,0x10},
+ {0xA1,0x6E,0x06,0x02,0x00,0x00,0x00,0x10},
+ {0xA1,0x6E,0x07,0xB5,0x00,0x00,0x00,0x10},
+ {0xA1,0x6E,0x18,0x6B,0x00,0x00,0x00,0x10},
+ {0xA1,0x6E,0x1D,0x08,0x00,0x00,0x00,0x10},
+ {0xA1,0x6E,0x06,0x02,0x00,0x00,0x00,0x10},
+ {0xA1,0x6E,0x07,0xB8,0x00,0x00,0x00,0x10},
+ */ {0xC1,0x00,0x01,0x00,0x00,0x00,0x01,0x00},
+ {0xA1,0x6E,0x06,0x03,0x00,0x00,0x00,0x10}, //Bright...
+ {0xA1,0x6E,0x07,0x66,0x00,0x00,0x00,0x10}, //B..
+ {0xC1,0x6E,0x1A,0x03,0x65,0x90,0x00,0x10}, //Bright/Witen....
+// {0xC1,0x6E,0x16,0x45,0x40,0x60,0x00,0x10}, //Bright/Witene
+ {0, 0, 0, 0, 0, 0, 0, 0}
+};
+

#if 0
static __u8 qtable1[] = {
@@ -607,6 +683,19 @@
i++;
}
}
+static void
+ ov7648_InitSensor(struct usb_spca50x *spca50x)
+{
+ int i = 0;
+ struct usb_device *dev = spca50x->dev;
+
+ while (ov7648_sensor_init[i][0])
+ {
+ sn9c102p_i2cwritebuf(dev, ov7648_sensor_init[i]);
+ i++;
+ }
+}
+
static int
sn9cxxx_init(struct usb_spca50x *spca50x)
{
@@ -615,6 +704,7 @@
__u8 *sn9c1xx = NULL;
__u8 regF1 = 0x01;
__u8 regGpio[] = { 0x29, 0x74 };
+ __u8 regGpioAlt = 0x62;
__u8 data = 0x00;
/* setup a selector by customid */
switch (spca50x->sensor) {
@@ -630,7 +720,11 @@
case SENSOR_OV7660:
sn9c1xx = sn_ov7660;
break;
+ case SENSOR_OV7648:
+ sn9c1xx = sn_ov7648;
+ break;
}
+
if (sn9c1xx == NULL)
return -ENODEV;
sonixRegWrite(dev, 0x08, 0xf1, 0x0000, ®F1, 1);
@@ -660,6 +754,11 @@
regGpio[1] = 0x70;
sonixRegWrite(dev, 0x08, 0x02, 0x0000, regGpio, 2);
break;
+ case SN9C325:
+ if (regF1 != 0x12 )
+ return -ENODEV;
+ sonixRegWrite(dev, 0x08, 0x02, 0x0000, ®GpioAlt, 1);
+ break;;
}

regF1 = 0x01;
@@ -708,6 +807,7 @@
struct usb_device *dev = spca50x->dev;
__u8 stophv7131[] = { 0xA1, 0x11, 0x02, 0x09, 0x00, 0x00, 0x00, 0x10 };
__u8 stopmi0360[] = { 0xB1, 0x5D, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10 };
+
__u8 regF1 = 0x01;
__u8 data = 0x0b;
__u8 *sn9c1xx = NULL;
@@ -728,6 +828,10 @@
case SENSOR_OV7660:
sn9c1xx = sn_ov7660;
break;
+ case SENSOR_OV7648:
+ sn9c1xx = sn_ov7648;
+ data = 0x29;
+ break;
}
if (sn9c1xx == NULL)
return;
@@ -746,6 +850,7 @@
__u8 C0[] = { 0x2d, 0x2d, 0x3a, 0x05, 0x04, 0x3f };
__u8 CA[] = { 0x28, 0xd8, 0x14, 0xec };
__u8 CE[] = { 0x32, 0xdd, 0x2d, 0xdd }; //MI0360
+ __u8 CE_sn9c325[] = { 0x32, 0xdd, 0x32, 0xdd }; //OV7648 - SN9C325
__u8 data = 0;
__u8 regF1 = 0x00;
__u8 reg17 = 0x61;
@@ -765,6 +870,10 @@
case SENSOR_OV7660:
sn9c1xx = sn_ov7660;
break;
+ case SENSOR_OV7648:
+ sn9c1xx = sn_ov7648;
+ break;
+
}
if (sn9c1xx == NULL)
return;
@@ -773,15 +882,19 @@
sonixRegWrite(dev, 0x08, 0x01, 0x0000, &sn9c1xx[1], 2);
sonixRegWrite(dev, 0x08, 0x08, 0x0000, &sn9c1xx[8], 2);
sonixRegWrite(dev, 0x08, 0x17, 0x0000, &sn9c1xx[0x17], 3);
-
- sonixRegWrite(dev, 0x08, 0x9a, 0x0000, reg9a, 6);
+ if( spca50x->customid == SN9C325 )
+ sonixRegWrite(dev, 0x08, 0x9a, 0x0000, reg9a_sn9c325, 6);
+ else
+ sonixRegWrite(dev, 0x08, 0x9a, 0x0000, reg9a, 6);
data = 0x60;
sonixRegWrite(dev, 0x08, 0xD4, 0x0000, &data, 1);
-
sonixRegWrite(dev, 0x08, 0x03, 0x0000, &sn9c1xx[3], 0x0f);
data = 0x43;
sonixRegWrite(dev, 0x08, 0x01, 0x0000, &data, 1);
- data = 0x61;
+ if( spca50x->customid == SN9C325 )
+ data = 0xae;
+ else
+ data = 0x61;
sonixRegWrite(dev, 0x08, 0x17, 0x0000, &data, 1);
data = 0x42;
sonixRegWrite(dev, 0x08, 0x01, 0x0000, &data, 1);
@@ -805,18 +918,38 @@
sonixRegWrite(dev, 0x08, 0xc8, 0x0000, &DC29[4], 1);
sonixRegWrite(dev, 0x08, 0xc9, 0x0000, &DC29[5], 1);
sonixRegWrite(dev, 0x08, 0x18, 0x0000, &sn9c1xx[0x18], 1);
- data = 0x60;
+ if( spca50x->customid == SN9C325 )
+ data = 0xAE;
+ else
+ data = 0x60;
sonixRegWrite(dev, 0x08, 0x17, 0x0000, &data, 1);
sonixRegWrite(dev, 0x08, 0x05, 0x0000, &sn9c1xx[5], 1);
sonixRegWrite(dev, 0x08, 0x07, 0x0000, &sn9c1xx[7], 1);
sonixRegWrite(dev, 0x08, 0x06, 0x0000, &sn9c1xx[6], 1);
sonixRegWrite(dev, 0x08, 0x14, 0x0000, &sn9c1xx[0x14], 1);
- sonixRegWrite(dev, 0x08, 0x20, 0x0000, regsn20, 0x11);
+ if( spca50x->customid == SN9C325 )
+ sonixRegWrite(dev, 0x08, 0x20, 0x0000, regsn20_sn9c325, 0x11);
+ else
+ sonixRegWrite(dev, 0x08, 0x20, 0x0000, regsn20, 0x11);
+
for (i = 0; i < 8; i++)
- sonixRegWrite(dev, 0x08, 0x84, 0x0000, reg84, 0x15);
- data = 0x08;
+ {
+ if( spca50x->customid == SN9C325 )
+ sonixRegWrite(dev, 0x08, 0x84, 0x0000, reg84_sn9c325, 0x15);
+ else
+ sonixRegWrite(dev, 0x08, 0x84, 0x0000, reg84, 0x15);
+ }
+
+ if( spca50x->customid == SN9C325 )
+ data = 0x0a;
+ else
+ data = 0x08;
sonixRegWrite(dev, 0x08, 0x9a, 0x0000, &data, 1);
- data = 0x59;
+
+ if( spca50x->customid == SN9C325 )
+ data = 0x60;
+ else
+ data = 0x59;
sonixRegWrite(dev, 0x08, 0x99, 0x0000, &data, 1);

switch (spca50x->sensor) {
@@ -859,10 +992,22 @@
}

break;
+ case SENSOR_OV7648:
+ reg17 = 0xa2;
+ reg1 = 0x44;
+ ov7648_InitSensor(spca50x);
+ if (spca50x->mode){ //320x2...
+ }
+ else { //640x...
+ }
+ break;;
}
sonixRegWrite(dev, 0x08, 0xc0, 0x0000, C0, 6);
sonixRegWrite(dev, 0x08, 0xca, 0x0000, CA, 4);
- sonixRegWrite(dev, 0x08, 0xce, 0x0000, CE, 4); //?? {0x1e,0xdd,0x2d,0xe7}
+ if( spca50x->customid == SN9C325 )
+ sonixRegWrite(dev, 0x08, 0xce, 0x0000, CE_sn9c325, 4);
+ else
+ sonixRegWrite(dev, 0x08, 0xce, 0x0000, CE, 4); //?? {0x1e,0xdd,0x2d,0xe7}

// here change size mode 0 -> VGA; 1 -> CIF
data = 0x40 | sn9c1xx[0x18] | (spca50x->mode << 4);
diff -Nru gspcav1-20071224/Sonix/sonix.h gspcav1-20071224-sn9c325-ov7648/Sonix/sonix.h
--- gspcav1-20071224/Sonix/sonix.h 2007-11-22 11:52:16.000000000 -0300
+++ gspcav1-20071224-sn9c325-ov7648/Sonix/sonix.h 2008-02-26 01:51:01.000000000 -0300
@@ -654,6 +654,7 @@
case SENSOR_HV7131R:
case SENSOR_MI0360:
case SENSOR_PAS202:
+ case SENSOR_OV7648:
set_sonixVGA(spca50x);
break;
case SENSOR_PAS106:
diff -Nru gspcav1-20071224/gspca.h gspcav1-20071224-sn9c325-ov7648/gspca.h
--- gspcav1-20071224/gspca.h 2007-12-24 13:56:47.000000000 -0300
+++ gspcav1-20071224-sn9c325-ov7648/gspca.h 2008-02-26 01:46:21.000000000 -0300
@@ -129,7 +129,7 @@
#define SENSOR_OV7670 29
#define SENSOR_MI1310_SOC 30
#define SENSOR_MC501CB 31
-
+#define SENSOR_OV7648 35
/* Alternate interface transfer sizes */
#define SPCA50X_ALT_SIZE_0 0
#define SPCA50X_ALT_SIZE_128 1
diff -Nru gspcav1-20071224/gspca_core.c gspcav1-20071224-sn9c325-ov7648/gspca_core.c
--- gspcav1-20071224/gspca_core.c 2007-12-24 13:56:47.000000000 -0300
+++ gspcav1-20071224-sn9c325-ov7648/gspca_core.c 2008-02-26 01:49:48.000000000 -0300
@@ -422,6 +422,7 @@
Lenovo,
LogitechQC4Notebooks,
PhilipsSPC220NC,
+ AvantCamera,
LastCamera
};
static struct cam_list clist[] = {
@@ -620,6 +621,7 @@
{Lenovo,"lenovo MI1310_SOC"},
{LogitechQC4Notebooks,"Logitech QuickCam for Notebooks"},
{PhilipsSPC220NC,"Philips SPC220NC PAC207"},
+ {AvantCamera,"Avant Camera"},
{-1, NULL}
};
static __devinitdata struct usb_device_id device_table[] = {
@@ -834,6 +836,7 @@
{USB_DEVICE(0x046d, 0x08af)}, /* Logitech QuickCam Cool */
{USB_DEVICE(0x093a, 0x2472)}, /* PAC207 Genius VideoCam ge110 */
{USB_DEVICE(0x093a, 0x2463)}, /* Philips spc200nc pac207 */
+ {USB_DEVICE(0x0c45, 0x612a)}, /* Philips spc200nc pac207 */
{USB_DEVICE(0x0000, 0x0000)}, /* MystFromOri Unknow Camera */
{} /* Terminating entry */
};
@@ -1926,6 +1929,7 @@
case SENSOR_OV7660:
case SENSOR_OV7620:
case SENSOR_MC501CB:
+ case SENSOR_OV7648:
break;
default:
PDEBUG(0,
@@ -3889,6 +3893,14 @@
spca50x->i2c_ctrl_reg = 0x20;
spca50x->i2c_base = 0x11;
break;
+ case 0x612a:
+ spca50x->desc = AvantCamera;
+ spca50x->bridge =BRIDGE_SN9CXXX;
+ spca50x->sensor = SENSOR_OV7648;
+ spca50x->customid = SN9C325;
+ spca50x->i2c_ctrl_reg = 0x81;
+ spca50x->i2c_base = 0x21;
+ break;
case 0x6024:
case 0x6025:
spca50x->desc = Sonix6025;



Wednesday, May 7, 2008

Microdia 0c45:6011 - Patch



Driver: gspcav1
Driver Base - Homepage: mxhaard.free.fr ( Michel Xhaard )
Base file: gspcav1-20071224.tgz
Patch for: Microdia 0c45:6011 / Sweex "foldable" webcam || "Avant" Camera
Chipset/Bridge: SN9C102 Sensor: OV6650
Link to MailList with patch

Download: Patch File






diff -Nru gspcav1-20071224/Sonix/sonix.h gspcav1-20071224-ov6650/Sonix/sonix.h
--- gspcav1-20071224/Sonix/sonix.h 2007-11-22 11:52:16.000000000 -0300
+++ gspcav1-20071224-ov6650/Sonix/sonix.h 2008-03-03 22:41:48.000000000 -0300
@@ -243,6 +243,13 @@
0x00, 0x00, 0x02, 0x03, 0x0F, 0x0C
};

+static __u8 initOv6650[] =
+{
+ 0x44, 0x44 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x80 ,0x60 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00,
+ 0x00 ,0x02 ,0x01 ,0x0a ,0x16 ,0x12 ,0x68 ,0x0b ,0x10 ,0x1d ,0x10 ,0x00 ,0x06 ,0x1f ,0x00
+
+};
+
//compression 0x86 mckinit1 0x2b
static __u8 pas106_data[][2] = {
{0x02, 0x04}, /* Pixel Clock Divider 6 */
@@ -337,6 +344,42 @@
{0, 0, 0, 0, 0, 0, 0, 0}
};

+static __u8 ov6650_sensor_init[][8] =
+{
+
+ {0xA0,0x60,0x12,0x80,0x00,0x00,0x00,0x10},
+ {0xD0,0x60,0x11,0xC0,0x1B,0x18,0xC1,0x10},
+ {0xB0,0x60,0x15,0x00,0x02,0x18,0xC1,0x10},
+ //{0xA0,0x60,0x1B,0x01,0x02,0x18,0xC1,0x10}, //THIS SET GREEN SCREEN ( pixels could be innverted indecode kind of "brg", but blue wont be there. Avoid this data ...
+ {0xD0,0x60,0x26,0x01,0x14,0xD8,0xA4,0x10}, //format out?
+ {0xD0,0x60,0x26,0x01,0x14,0xD8,0xA4,0x10},
+ {0xA0,0x60,0x30,0x3D,0x0A,0xD8,0xA4,0x10},
+ {0xB0,0x60,0x60,0x66,0x68,0xD8,0xA4,0x10},
+ {0xA0,0x60,0x68,0x04,0x68,0xD8,0xA4,0x10},
+ {0xD0,0x60,0x17,0x24,0xD6,0x04,0x94,0x10}, //Clipreg
+ {0xA0,0x60,0x10,0x5D,0x99,0x04,0x94,0x16},
+ {0xA0,0x60,0x2D,0x0A,0x99,0x04,0x94,0x16},
+ {0xA0,0x60,0x32,0x00,0x99,0x04,0x94,0x16},
+ {0xA0,0x60,0x33,0x40,0x99,0x04,0x94,0x16},
+ {0xA0,0x60,0x11,0xC0,0x99,0x04,0x94,0x16},
+ {0xA0,0x60,0x00,0x16,0x99,0x04,0x94,0x15}, //bright / Lumino
+ {0xA0,0x60,0x2B,0xAB,0x99,0x04,0x94,0x15}, //?flicker o brillo
+ {0xA0,0x60,0x2D,0x2A,0x99,0x04,0x94,0x15},
+ {0xA0,0x60,0x2D,0x2B,0x99,0x04,0x94,0x16},
+ {0xA0,0x60,0x32,0x00,0x99,0x04,0x94,0x16},
+ {0xA0,0x60,0x33,0x00,0x99,0x04,0x94,0x16},
+ {0xA0,0x60,0x10,0x57,0x99,0x04,0x94,0x16},
+// {0xA0,0x60,0x33,0x9D,0x99,0x04,0x94,0x16},
+ {0xA0,0x60,0x2D,0x2B,0x99,0x04,0x94,0x16},
+ {0xA0,0x60,0x32,0x00,0x99,0x04,0x94,0x16}, // Low Light ( Enabled: 0x32 0x1 | Disabled: 0x32 0x00 )
+ {0xA0,0x60,0x33,0x29,0x99,0x04,0x94,0x16}, // Low Ligth ( Enabled: 0x33 0x13 | Disabled: 0x33 0x29 )
+// {0xA0,0x60,0x11,0xC1,0x99,0x04,0x94,0x16},
+// {0xA0,0x60,0x00,0x16,0x99,0x04,0x94,0x15},
+ {0xA0,0x60,0x00,0x17,0x99,0x04,0x94,0x15},
+ {0xA0,0x60,0x00,0x18,0x99,0x04,0x94,0x15},
+ {0 , 0, 0, 0, 0, 0, 0, 0},
+}
+;
static int
sonix_i2cwrite(struct usb_device *dev, __u8 * buffer, __u16 length)
{
@@ -380,6 +423,7 @@
__u8 i2cpdoit[] = { 0xA0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16 };
//__u8 i2cpexpo1[] = { 0xB0,0x40,0x04,0x07,0x2A,0x00,0x63,0x16 };
__u8 i2cpexpo[] = { 0xB0, 0x40, 0x0e, 0x01, 0xab, 0x00, 0x63, 0x16 };
+ __u8 i2cOV6650[] = { 0xa0, 0x60, 0x06,0x11, 0x99, 0x04, 0x94, 0x15 };
if (spca50x->sensor == SENSOR_TAS5130CXX ||
spca50x->sensor == SENSOR_TAS5110) {
value = (0xFF - (spca50x->brightness >> 8));
@@ -416,6 +460,12 @@
if (sonix_i2cwrite(spca50x->dev, i2cpdoit, 8) < 0)
PDEBUG(0, "i2c error brightness");
}
+ else if( spca50x->sensor == SENSOR_OV6650 )
+ {
+ i2cOV6650[3] =spca50x->brightness>> 8;
+ if (sonix_i2cwrite(spca50x->dev, i2cOV6650, 8) < 0)
+ PDEBUG(0, "i2c error brightness");
+ }
}
static void
sonix_setcontrast(struct usb_spca50x *spca50x)
@@ -513,6 +563,17 @@
}
return 0;
}
+static int
+ov6650_I2cinit(struct usb_spca50x *spca50x)
+{
+ int i = 0;
+ while (ov6650_sensor_init[i][0]) {
+ if (sonix_i2cwrite(spca50x->dev, ov6650_sensor_init[i], 8) < 0)
+ PDEBUG(0, "i2c error ov665-");
+ i++;
+ }
+ return 0;
+}
static void
sonix_start(struct usb_spca50x *spca50x)
{
@@ -588,6 +649,17 @@
CompressCtrl[1] = 0x20; //reg19 30
MCK_SIZE = 0x20;
break;
+ case SENSOR_OV6650:
+ sn9c10x = initOv6650;
+ if( spca50x->mode )
+ compress = 0x9b;
+ else
+ compress = 0x8b;
+ CompressCtrl[0] = compress;
+ frmult = 0x68;
+ CompressCtrl[1] = 0x20;
+ MCK_SIZE = 0x20;
+ break;
}
/* reg 0x01 bit 2 video transfert on */

@@ -615,6 +687,9 @@
case SENSOR_PAS202:
err = pas202_I2cinit(spca50x);
break;
+ case SENSOR_OV6650:
+ err = ov6650_I2cinit(spca50x);
+ break;
default:
err = -EINVAL;
break;
@@ -658,7 +733,8 @@
break;
case SENSOR_PAS106:
case SENSOR_TAS5110:
- set_sonixSIF(spca50x);
+ case SENSOR_OV6650:
+ set_sonixSIF(spca50x);
break;
default:
return -EINVAL;
diff -Nru gspcav1-20071224/gspca.h gspcav1-20071224-ov6650/gspca.h
--- gspcav1-20071224/gspca.h 2007-12-24 13:56:47.000000000 -0300
+++ gspcav1-20071224-ov6650/gspca.h 2008-03-03 22:41:48.000000000 -0300
@@ -129,6 +129,7 @@
#define SENSOR_OV7670 29
#define SENSOR_MI1310_SOC 30
#define SENSOR_MC501CB 31
+#define SENSOR_OV6650 32

/* Alternate interface transfer sizes */
#define SPCA50X_ALT_SIZE_0 0
diff -Nru gspcav1-20071224/gspca_core.c gspcav1-20071224-ov6650/gspca_core.c
--- gspcav1-20071224/gspca_core.c 2007-12-24 13:56:47.000000000 -0300
+++ gspcav1-20071224-ov6650/gspca_core.c 2008-03-03 22:41:48.000000000 -0300
@@ -422,6 +422,7 @@
Lenovo,
LogitechQC4Notebooks,
PhilipsSPC220NC,
+ MaxSonixCamera,
LastCamera
};
static struct cam_list clist[] = {
@@ -620,6 +621,7 @@
{Lenovo,"lenovo MI1310_SOC"},
{LogitechQC4Notebooks,"Logitech QuickCam for Notebooks"},
{PhilipsSPC220NC,"Philips SPC220NC PAC207"},
+ {MaxSonixCamera,"Max Webcam (SN9C101G-OV6650-352x288)"},
{-1, NULL}
};
static __devinitdata struct usb_device_id device_table[] = {
@@ -834,6 +836,7 @@
{USB_DEVICE(0x046d, 0x08af)}, /* Logitech QuickCam Cool */
{USB_DEVICE(0x093a, 0x2472)}, /* PAC207 Genius VideoCam ge110 */
{USB_DEVICE(0x093a, 0x2463)}, /* Philips spc200nc pac207 */
+ {USB_DEVICE(0x0c45, 0x6011)}, /* MAX Webcam ( OV 6650 - SN9C101G ( works only with SONIX BRIDGE ) */
{USB_DEVICE(0x0000, 0x0000)}, /* MystFromOri Unknow Camera */
{} /* Terminating entry */
};
@@ -3889,6 +3892,14 @@
spca50x->i2c_ctrl_reg = 0x20;
spca50x->i2c_base = 0x11;
break;
+ case 0x6011:
+ spca50x->desc = MaxSonixCamera;
+ spca50x->bridge = BRIDGE_SONIX;
+ spca50x->sensor = SENSOR_OV6650;
+ spca50x->customid = SN9C101; //SN9C101G
+ spca50x->i2c_ctrl_reg = 0x81;
+ spca50x->i2c_base = 0x21;
+ break;
case 0x6024:
case 0x6025:
spca50x->desc = Sonix6025;