blob: 8bc6c3ceec2cf7c70df161990101f423d8952daf [file] [log] [blame]
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001/*
Jean-François Moinecd8955b2010-06-04 07:22:57 -03002 * T613 subdriver
3 *
4 * Copyright (C) 2010 Jean-Francois Moine (http://moinejf.free.fr)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Jean-Francois Moine10b0e962008-07-22 05:35:10 -030019 *
20 *Notes: * t613 + tas5130A
21 * * Focus to light do not balance well as in win.
22 * Quality in win is not good, but its kinda better.
23 * * Fix some "extraneous bytes", most of apps will show the image anyway
24 * * Gamma table, is there, but its really doing something?
25 * * 7~8 Fps, its ok, max on win its 10.
26 * Costantino Leandro
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030027 */
28
Joe Perches1b19e4292011-08-21 19:56:56 -030029#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
30
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030031#define MODULE_NAME "t613"
Jean-Francois Moine10b0e962008-07-22 05:35:10 -030032
Hans de Goedeee186fd2012-01-01 16:09:17 -030033#include <linux/input.h>
Jean-François Moinebe2a9fa2010-06-04 06:42:32 -030034#include <linux/slab.h>
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030035#include "gspca.h"
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030036
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030037MODULE_AUTHOR("Leandro Costantino <le_costantino@pixartargentina.com.ar>");
38MODULE_DESCRIPTION("GSPCA/T613 (JPEG Compliance) USB Camera Driver");
39MODULE_LICENSE("GPL");
40
41struct sd {
42 struct gspca_dev gspca_dev; /* !! must be the first item */
Hans Verkuil9bf81642012-05-18 03:41:58 -030043 struct v4l2_ctrl *freq;
44 struct { /* awb / color gains control cluster */
45 struct v4l2_ctrl *awb;
46 struct v4l2_ctrl *gain;
47 struct v4l2_ctrl *red_balance;
48 struct v4l2_ctrl *blue_balance;
49 };
Jean-Francois Moinefadc7992008-10-08 08:06:08 -030050
Jean-Francois Moine82e25492009-01-22 07:18:48 -030051 u8 sensor;
Hans de Goedeee186fd2012-01-01 16:09:17 -030052 u8 button_pressed;
Jean-François Moine11ce8842010-07-26 06:39:40 -030053};
54enum sensors {
Jean-François Moinecd8955b2010-06-04 07:22:57 -030055 SENSOR_OM6802,
56 SENSOR_OTHER,
57 SENSOR_TAS5130A,
58 SENSOR_LT168G, /* must verify if this is the actual model */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030059};
60
Jean-Francois Moinecc611b82008-12-29 07:49:41 -030061static const struct v4l2_pix_format vga_mode_t16[] = {
Jean-Francois Moinec2446b32008-07-05 11:49:20 -030062 {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
63 .bytesperline = 160,
Jean-Francois Moine5d052942008-09-03 16:48:09 -030064 .sizeimage = 160 * 120 * 4 / 8 + 590,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -030065 .colorspace = V4L2_COLORSPACE_JPEG,
66 .priv = 4},
Hans de Goede1ea172d2012-07-07 08:55:06 -030067#if 0 /* HDG: broken with my test cam, so lets disable it */
Jean-Francois Moinec2446b32008-07-05 11:49:20 -030068 {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
69 .bytesperline = 176,
70 .sizeimage = 176 * 144 * 3 / 8 + 590,
71 .colorspace = V4L2_COLORSPACE_JPEG,
72 .priv = 3},
Hans de Goede1ea172d2012-07-07 08:55:06 -030073#endif
Jean-Francois Moinec2446b32008-07-05 11:49:20 -030074 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
75 .bytesperline = 320,
76 .sizeimage = 320 * 240 * 3 / 8 + 590,
77 .colorspace = V4L2_COLORSPACE_JPEG,
78 .priv = 2},
Hans de Goede1ea172d2012-07-07 08:55:06 -030079#if 0 /* HDG: broken with my test cam, so lets disable it */
Jean-Francois Moinec2446b32008-07-05 11:49:20 -030080 {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
81 .bytesperline = 352,
82 .sizeimage = 352 * 288 * 3 / 8 + 590,
83 .colorspace = V4L2_COLORSPACE_JPEG,
84 .priv = 1},
Hans de Goede1ea172d2012-07-07 08:55:06 -030085#endif
Jean-Francois Moinec2446b32008-07-05 11:49:20 -030086 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
87 .bytesperline = 640,
88 .sizeimage = 640 * 480 * 3 / 8 + 590,
89 .colorspace = V4L2_COLORSPACE_JPEG,
90 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030091};
92
Leandro Costantinoad62fb02008-10-17 05:27:04 -030093/* sensor specific data */
94struct additional_sensor_data {
Jean-Francois Moine78a6d742009-07-07 04:03:24 -030095 const u8 n3[6];
96 const u8 *n4, n4sz;
97 const u8 reg80, reg8e;
98 const u8 nset8[6];
Jean-Francois Moine82e25492009-01-22 07:18:48 -030099 const u8 data1[10];
100 const u8 data2[9];
101 const u8 data3[9];
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300102 const u8 data5[6];
103 const u8 stream[4];
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300104};
105
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300106static const u8 n4_om6802[] = {
107 0x09, 0x01, 0x12, 0x04, 0x66, 0x8a, 0x80, 0x3c,
108 0x81, 0x22, 0x84, 0x50, 0x8a, 0x78, 0x8b, 0x68,
109 0x8c, 0x88, 0x8e, 0x33, 0x8f, 0x24, 0xaa, 0xb1,
110 0xa2, 0x60, 0xa5, 0x30, 0xa6, 0x3a, 0xa8, 0xe8,
111 0xae, 0x05, 0xb1, 0x00, 0xbb, 0x04, 0xbc, 0x48,
112 0xbe, 0x36, 0xc6, 0x88, 0xe9, 0x00, 0xc5, 0xc0,
113 0x65, 0x0a, 0xbb, 0x86, 0xaf, 0x58, 0xb0, 0x68,
114 0x87, 0x40, 0x89, 0x2b, 0x8d, 0xff, 0x83, 0x40,
115 0xac, 0x84, 0xad, 0x86, 0xaf, 0x46
116};
117static const u8 n4_other[] = {
118 0x66, 0x00, 0x7f, 0x00, 0x80, 0xac, 0x81, 0x69,
119 0x84, 0x40, 0x85, 0x70, 0x86, 0x20, 0x8a, 0x68,
120 0x8b, 0x58, 0x8c, 0x88, 0x8d, 0xff, 0x8e, 0xb8,
121 0x8f, 0x28, 0xa2, 0x60, 0xa5, 0x40, 0xa8, 0xa8,
122 0xac, 0x84, 0xad, 0x84, 0xae, 0x24, 0xaf, 0x56,
123 0xb0, 0x68, 0xb1, 0x00, 0xb2, 0x88, 0xbb, 0xc5,
124 0xbc, 0x4a, 0xbe, 0x36, 0xc2, 0x88, 0xc5, 0xc0,
125 0xc6, 0xda, 0xe9, 0x26, 0xeb, 0x00
126};
127static const u8 n4_tas5130a[] = {
128 0x80, 0x3c, 0x81, 0x68, 0x83, 0xa0, 0x84, 0x20,
129 0x8a, 0x68, 0x8b, 0x58, 0x8c, 0x88, 0x8e, 0xb4,
130 0x8f, 0x24, 0xa1, 0xb1, 0xa2, 0x30, 0xa5, 0x10,
131 0xa6, 0x4a, 0xae, 0x03, 0xb1, 0x44, 0xb2, 0x08,
132 0xb7, 0x06, 0xb9, 0xe7, 0xbb, 0xc4, 0xbc, 0x4a,
133 0xbe, 0x36, 0xbf, 0xff, 0xc2, 0x88, 0xc5, 0xc8,
134 0xc6, 0xda
135};
Nicolau Werneck00e80062010-01-30 16:00:15 -0300136static const u8 n4_lt168g[] = {
137 0x66, 0x01, 0x7f, 0x00, 0x80, 0x7c, 0x81, 0x28,
138 0x83, 0x44, 0x84, 0x20, 0x86, 0x20, 0x8a, 0x70,
139 0x8b, 0x58, 0x8c, 0x88, 0x8d, 0xa0, 0x8e, 0xb3,
140 0x8f, 0x24, 0xa1, 0xb0, 0xa2, 0x38, 0xa5, 0x20,
141 0xa6, 0x4a, 0xa8, 0xe8, 0xaf, 0x38, 0xb0, 0x68,
142 0xb1, 0x44, 0xb2, 0x88, 0xbb, 0x86, 0xbd, 0x40,
143 0xbe, 0x26, 0xc1, 0x05, 0xc2, 0x88, 0xc5, 0xc0,
144 0xda, 0x8e, 0xdb, 0xca, 0xdc, 0xa8, 0xdd, 0x8c,
145 0xde, 0x44, 0xdf, 0x0c, 0xe9, 0x80
146};
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300147
Tobias Klausere23b2902009-02-09 18:06:49 -0300148static const struct additional_sensor_data sensor_data[] = {
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300149[SENSOR_OM6802] = {
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300150 .n3 =
151 {0x61, 0x68, 0x65, 0x0a, 0x60, 0x04},
152 .n4 = n4_om6802,
153 .n4sz = sizeof n4_om6802,
154 .reg80 = 0x3c,
155 .reg8e = 0x33,
156 .nset8 = {0xa8, 0xf0, 0xc6, 0x88, 0xc0, 0x00},
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300157 .data1 =
158 {0xc2, 0x28, 0x0f, 0x22, 0xcd, 0x27, 0x2c, 0x06,
159 0xb3, 0xfc},
160 .data2 =
161 {0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff,
162 0xff},
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300163 .data3 =
164 {0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff,
165 0xff},
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300166 .data5 = /* this could be removed later */
167 {0x0c, 0x03, 0xab, 0x13, 0x81, 0x23},
168 .stream =
169 {0x0b, 0x04, 0x0a, 0x78},
170 },
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300171[SENSOR_OTHER] = {
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300172 .n3 =
173 {0x61, 0xc2, 0x65, 0x88, 0x60, 0x00},
174 .n4 = n4_other,
175 .n4sz = sizeof n4_other,
176 .reg80 = 0xac,
177 .reg8e = 0xb8,
178 .nset8 = {0xa8, 0xa8, 0xc6, 0xda, 0xc0, 0x00},
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300179 .data1 =
180 {0xc1, 0x48, 0x04, 0x1b, 0xca, 0x2e, 0x33, 0x3a,
181 0xe8, 0xfc},
182 .data2 =
183 {0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96,
184 0xd9},
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300185 .data3 =
186 {0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96,
187 0xd9},
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300188 .data5 =
189 {0x0c, 0x03, 0xab, 0x29, 0x81, 0x69},
190 .stream =
191 {0x0b, 0x04, 0x0a, 0x00},
192 },
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300193[SENSOR_TAS5130A] = {
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300194 .n3 =
195 {0x61, 0xc2, 0x65, 0x0d, 0x60, 0x08},
196 .n4 = n4_tas5130a,
197 .n4sz = sizeof n4_tas5130a,
198 .reg80 = 0x3c,
199 .reg8e = 0xb4,
200 .nset8 = {0xa8, 0xf0, 0xc6, 0xda, 0xc0, 0x00},
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300201 .data1 =
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300202 {0xbb, 0x28, 0x10, 0x10, 0xbb, 0x28, 0x1e, 0x27,
203 0xc8, 0xfc},
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300204 .data2 =
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300205 {0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,
206 0xe0},
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300207 .data3 =
208 {0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,
209 0xe0},
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300210 .data5 =
211 {0x0c, 0x03, 0xab, 0x10, 0x81, 0x20},
212 .stream =
213 {0x0b, 0x04, 0x0a, 0x40},
214 },
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300215[SENSOR_LT168G] = {
Nicolau Werneck00e80062010-01-30 16:00:15 -0300216 .n3 = {0x61, 0xc2, 0x65, 0x68, 0x60, 0x00},
217 .n4 = n4_lt168g,
218 .n4sz = sizeof n4_lt168g,
219 .reg80 = 0x7c,
220 .reg8e = 0xb3,
221 .nset8 = {0xa8, 0xf0, 0xc6, 0xba, 0xc0, 0x00},
222 .data1 = {0xc0, 0x38, 0x08, 0x10, 0xc0, 0x30, 0x10, 0x40,
223 0xb0, 0xf4},
224 .data2 = {0x40, 0x80, 0xc0, 0x50, 0xa0, 0xf0, 0x53, 0xa6,
225 0xff},
226 .data3 = {0x40, 0x80, 0xc0, 0x50, 0xa0, 0xf0, 0x53, 0xa6,
227 0xff},
Nicolau Werneck00e80062010-01-30 16:00:15 -0300228 .data5 = {0x0c, 0x03, 0xab, 0x4b, 0x81, 0x2b},
229 .stream = {0x0b, 0x04, 0x0a, 0x28},
230 },
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300231};
232
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300233#define MAX_EFFECTS 7
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300234static const u8 effects_table[MAX_EFFECTS][6] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300235 {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x00}, /* Normal */
236 {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x04}, /* Repujar */
237 {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x20}, /* Monochrome */
238 {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x80}, /* Sepia */
239 {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x02}, /* Croquis */
240 {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x10}, /* Sun Effect */
241 {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x40}, /* Negative */
242};
243
Hans Verkuil9bf81642012-05-18 03:41:58 -0300244#define GAMMA_MAX (15)
245static const u8 gamma_table[GAMMA_MAX+1][17] = {
Jean-François Moine79960d32010-06-04 07:24:53 -0300246/* gamma table from cam1690.ini */
247 {0x00, 0x00, 0x01, 0x04, 0x08, 0x0e, 0x16, 0x21, /* 0 */
248 0x2e, 0x3d, 0x50, 0x65, 0x7d, 0x99, 0xb8, 0xdb,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300249 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300250 {0x00, 0x01, 0x03, 0x08, 0x0e, 0x16, 0x21, 0x2d, /* 1 */
251 0x3c, 0x4d, 0x60, 0x75, 0x8d, 0xa6, 0xc2, 0xe1,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300252 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300253 {0x00, 0x01, 0x05, 0x0b, 0x12, 0x1c, 0x28, 0x35, /* 2 */
254 0x45, 0x56, 0x69, 0x7e, 0x95, 0xad, 0xc7, 0xe3,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300255 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300256 {0x00, 0x02, 0x07, 0x0f, 0x18, 0x24, 0x30, 0x3f, /* 3 */
257 0x4f, 0x61, 0x73, 0x88, 0x9d, 0xb4, 0xcd, 0xe6,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300258 0xff},
Jean-François Moine1d00d6c2010-10-29 13:58:22 -0300259 {0x00, 0x04, 0x0b, 0x15, 0x20, 0x2d, 0x3b, 0x4a, /* 4 */
Jean-François Moine79960d32010-06-04 07:24:53 -0300260 0x5b, 0x6c, 0x7f, 0x92, 0xa7, 0xbc, 0xd2, 0xe9,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300261 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300262 {0x00, 0x07, 0x11, 0x15, 0x20, 0x2d, 0x48, 0x58, /* 5 */
263 0x68, 0x79, 0x8b, 0x9d, 0xb0, 0xc4, 0xd7, 0xec,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300264 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300265 {0x00, 0x0c, 0x1a, 0x29, 0x38, 0x47, 0x57, 0x67, /* 6 */
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300266 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
267 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300268 {0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, /* 7 */
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300269 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0,
270 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300271 {0x00, 0x15, 0x27, 0x38, 0x49, 0x59, 0x69, 0x79, /* 8 */
272 0x88, 0x97, 0xa7, 0xb6, 0xc4, 0xd3, 0xe2, 0xf0,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300273 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300274 {0x00, 0x1c, 0x30, 0x43, 0x54, 0x65, 0x75, 0x84, /* 9 */
275 0x93, 0xa1, 0xb0, 0xbd, 0xca, 0xd8, 0xe5, 0xf2,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300276 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300277 {0x00, 0x24, 0x3b, 0x4f, 0x60, 0x70, 0x80, 0x8e, /* 10 */
278 0x9c, 0xaa, 0xb7, 0xc4, 0xd0, 0xdc, 0xe8, 0xf3,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300279 0xff},
Jean-François Moine79960d32010-06-04 07:24:53 -0300280 {0x00, 0x2a, 0x3c, 0x5d, 0x6e, 0x7e, 0x8d, 0x9b, /* 11 */
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300281 0xa8, 0xb4, 0xc0, 0xcb, 0xd6, 0xe1, 0xeb, 0xf5,
282 0xff},
283 {0x00, 0x3f, 0x5a, 0x6e, 0x7f, 0x8e, 0x9c, 0xa8, /* 12 */
284 0xb4, 0xbf, 0xc9, 0xd3, 0xdc, 0xe5, 0xee, 0xf6,
285 0xff},
286 {0x00, 0x54, 0x6f, 0x83, 0x93, 0xa0, 0xad, 0xb7, /* 13 */
287 0xc2, 0xcb, 0xd4, 0xdc, 0xe4, 0xeb, 0xf2, 0xf9,
288 0xff},
289 {0x00, 0x6e, 0x88, 0x9a, 0xa8, 0xb3, 0xbd, 0xc6, /* 14 */
290 0xcf, 0xd6, 0xdd, 0xe3, 0xe9, 0xef, 0xf4, 0xfa,
291 0xff},
292 {0x00, 0x93, 0xa8, 0xb7, 0xc1, 0xca, 0xd2, 0xd8, /* 15 */
293 0xde, 0xe3, 0xe8, 0xed, 0xf1, 0xf5, 0xf8, 0xfc,
294 0xff}
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300295};
296
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300297static const u8 tas5130a_sensor_init[][8] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300298 {0x62, 0x08, 0x63, 0x70, 0x64, 0x1d, 0x60, 0x09},
299 {0x62, 0x20, 0x63, 0x01, 0x64, 0x02, 0x60, 0x09},
300 {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300301};
302
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300303static u8 sensor_reset[] = {0x61, 0x68, 0x62, 0xff, 0x60, 0x07};
Jean-Francois Moine392ee5a2008-10-17 05:00:59 -0300304
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300305/* read 1 byte */
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300306static u8 reg_r(struct gspca_dev *gspca_dev,
307 u16 index)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300308{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300309 usb_control_msg(gspca_dev->dev,
310 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300311 0, /* request */
312 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
313 0, /* value */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300314 index,
315 gspca_dev->usb_buf, 1, 500);
316 return gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300317}
318
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300319static void reg_w(struct gspca_dev *gspca_dev,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300320 u16 index)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300321{
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300322 usb_control_msg(gspca_dev->dev,
323 usb_sndctrlpipe(gspca_dev->dev, 0),
324 0,
Jean-Francois Moine0bc99b52008-10-17 04:45:27 -0300325 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300326 0, index,
327 NULL, 0, 500);
328}
329
Jean-Francois Moinef89be032008-10-17 04:42:29 -0300330static void reg_w_buf(struct gspca_dev *gspca_dev,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300331 const u8 *buffer, u16 len)
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300332{
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300333 if (len <= USB_BUF_SZ) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300334 memcpy(gspca_dev->usb_buf, buffer, len);
335 usb_control_msg(gspca_dev->dev,
336 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300337 0,
Jean-Francois Moine0bc99b52008-10-17 04:45:27 -0300338 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300339 0x01, 0,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300340 gspca_dev->usb_buf, len, 500);
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300341 } else {
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300342 u8 *tmpbuf;
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300343
Julia Lawallfeda79b2010-07-01 01:30:11 -0300344 tmpbuf = kmemdup(buffer, len, GFP_KERNEL);
Jean-François Moine24f222e2010-03-07 05:58:55 -0300345 if (!tmpbuf) {
Joe Perches1b19e4292011-08-21 19:56:56 -0300346 pr_err("Out of memory\n");
Jean-François Moine24f222e2010-03-07 05:58:55 -0300347 return;
348 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300349 usb_control_msg(gspca_dev->dev,
350 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300351 0,
Jean-Francois Moine0bc99b52008-10-17 04:45:27 -0300352 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300353 0x01, 0,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300354 tmpbuf, len, 500);
355 kfree(tmpbuf);
356 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300357}
358
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300359/* write values to consecutive registers */
360static void reg_w_ixbuf(struct gspca_dev *gspca_dev,
361 u8 reg,
362 const u8 *buffer, u16 len)
363{
364 int i;
365 u8 *p, *tmpbuf;
366
Jean-François Moine24f222e2010-03-07 05:58:55 -0300367 if (len * 2 <= USB_BUF_SZ) {
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300368 p = tmpbuf = gspca_dev->usb_buf;
Jean-François Moine24f222e2010-03-07 05:58:55 -0300369 } else {
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300370 p = tmpbuf = kmalloc(len * 2, GFP_KERNEL);
Jean-François Moine24f222e2010-03-07 05:58:55 -0300371 if (!tmpbuf) {
Joe Perches1b19e4292011-08-21 19:56:56 -0300372 pr_err("Out of memory\n");
Jean-François Moine24f222e2010-03-07 05:58:55 -0300373 return;
374 }
375 }
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300376 i = len;
377 while (--i >= 0) {
378 *p++ = reg++;
379 *p++ = *buffer++;
380 }
381 usb_control_msg(gspca_dev->dev,
382 usb_sndctrlpipe(gspca_dev->dev, 0),
383 0,
384 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
385 0x01, 0,
386 tmpbuf, len * 2, 500);
387 if (len * 2 > USB_BUF_SZ)
388 kfree(tmpbuf);
389}
390
Jean-Francois Moine236088d2008-10-17 04:53:02 -0300391static void om6802_sensor_init(struct gspca_dev *gspca_dev)
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300392{
393 int i;
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300394 const u8 *p;
395 u8 byte;
396 u8 val[6] = {0x62, 0, 0x64, 0, 0x60, 0x05};
397 static const u8 sensor_init[] = {
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300398 0xdf, 0x6d,
399 0xdd, 0x18,
400 0x5a, 0xe0,
401 0x5c, 0x07,
402 0x5d, 0xb0,
403 0x5e, 0x1e,
404 0x60, 0x71,
405 0xef, 0x00,
406 0xe9, 0x00,
407 0xea, 0x00,
408 0x90, 0x24,
409 0x91, 0xb2,
410 0x82, 0x32,
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300411 0xfd, 0x41,
412 0x00 /* table end */
413 };
414
Jean-Francois Moine392ee5a2008-10-17 05:00:59 -0300415 reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset);
Jean-Francois Moinee30bdc62009-03-22 16:31:32 -0300416 msleep(100);
Jean-Francois Moine392ee5a2008-10-17 05:00:59 -0300417 i = 4;
Roel Kluin97a53a02008-12-21 11:58:05 -0300418 while (--i > 0) {
Jean-Francois Moine392ee5a2008-10-17 05:00:59 -0300419 byte = reg_r(gspca_dev, 0x0060);
420 if (!(byte & 0x01))
421 break;
422 msleep(100);
423 }
424 byte = reg_r(gspca_dev, 0x0063);
425 if (byte != 0x17) {
Joe Perches1b19e4292011-08-21 19:56:56 -0300426 pr_err("Bad sensor reset %02x\n", byte);
Jean-Francois Moine392ee5a2008-10-17 05:00:59 -0300427 /* continue? */
428 }
429
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300430 p = sensor_init;
431 while (*p != 0) {
432 val[1] = *p++;
433 val[3] = *p++;
434 if (*p == 0)
435 reg_w(gspca_dev, 0x3c80);
Jean-Francois Moinef89be032008-10-17 04:42:29 -0300436 reg_w_buf(gspca_dev, val, sizeof val);
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300437 i = 4;
438 while (--i >= 0) {
439 msleep(15);
440 byte = reg_r(gspca_dev, 0x60);
441 if (!(byte & 0x01))
442 break;
443 }
444 }
Jean-Francois Moine392ee5a2008-10-17 05:00:59 -0300445 msleep(15);
446 reg_w(gspca_dev, 0x3c80);
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300447}
448
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300449/* this function is called at probe time */
450static int sd_config(struct gspca_dev *gspca_dev,
451 const struct usb_device_id *id)
452{
Hans Verkuil9bf81642012-05-18 03:41:58 -0300453 struct cam *cam = &gspca_dev->cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300454
455 cam->cam_mode = vga_mode_t16;
456 cam->nmodes = ARRAY_SIZE(vga_mode_t16);
457
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300458 return 0;
459}
460
Hans Verkuil9bf81642012-05-18 03:41:58 -0300461static void setbrightness(struct gspca_dev *gspca_dev, s32 brightness)
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300462{
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300463 u8 set6[4] = { 0x8f, 0x24, 0xc3, 0x00 };
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300464
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300465 if (brightness < 7) {
466 set6[1] = 0x26;
467 set6[3] = 0x70 - brightness * 0x10;
468 } else {
469 set6[3] = 0x00 + ((brightness - 7) * 0x10);
470 }
471
472 reg_w_buf(gspca_dev, set6, sizeof set6);
473}
474
Hans Verkuil9bf81642012-05-18 03:41:58 -0300475static void setcontrast(struct gspca_dev *gspca_dev, s32 contrast)
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300476{
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300477 u16 reg_to_write;
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300478
479 if (contrast < 7)
480 reg_to_write = 0x8ea9 - contrast * 0x200;
481 else
482 reg_to_write = 0x00a9 + (contrast - 7) * 0x200;
483
484 reg_w(gspca_dev, reg_to_write);
485}
486
Hans Verkuil9bf81642012-05-18 03:41:58 -0300487static void setcolors(struct gspca_dev *gspca_dev, s32 val)
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300488{
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300489 u16 reg_to_write;
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300490
Hans Verkuil9bf81642012-05-18 03:41:58 -0300491 reg_to_write = 0x80bb + val * 0x100; /* was 0xc0 */
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300492 reg_w(gspca_dev, reg_to_write);
493}
494
Hans Verkuil9bf81642012-05-18 03:41:58 -0300495static void setgamma(struct gspca_dev *gspca_dev, s32 val)
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300496{
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300497 PDEBUG(D_CONF, "Gamma: %d", sd->gamma);
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300498 reg_w_ixbuf(gspca_dev, 0x90,
Hans Verkuil9bf81642012-05-18 03:41:58 -0300499 gamma_table[val], sizeof gamma_table[0]);
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300500}
501
Hans Verkuil9bf81642012-05-18 03:41:58 -0300502static void setawb_n_RGB(struct gspca_dev *gspca_dev)
Jean-François Moinee9b15652010-06-05 07:07:56 -0300503{
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300504 struct sd *sd = (struct sd *) gspca_dev;
Hans Verkuil9bf81642012-05-18 03:41:58 -0300505 u8 all_gain_reg[8] = {
506 0x87, 0x00, 0x88, 0x00, 0x89, 0x00, 0x80, 0x00 };
507 s32 red_gain, blue_gain, green_gain;
Jean-François Moinee9b15652010-06-05 07:07:56 -0300508
Hans Verkuil9bf81642012-05-18 03:41:58 -0300509 green_gain = sd->gain->val;
510
511 red_gain = green_gain + sd->red_balance->val;
512 if (red_gain > 0x40)
513 red_gain = 0x40;
514 else if (red_gain < 0x10)
515 red_gain = 0x10;
516
517 blue_gain = green_gain + sd->blue_balance->val;
518 if (blue_gain > 0x40)
519 blue_gain = 0x40;
520 else if (blue_gain < 0x10)
521 blue_gain = 0x10;
522
523 all_gain_reg[1] = red_gain;
524 all_gain_reg[3] = blue_gain;
525 all_gain_reg[5] = green_gain;
526 all_gain_reg[7] = sensor_data[sd->sensor].reg80;
527 if (!sd->awb->val)
528 all_gain_reg[7] &= ~0x04; /* AWB off */
529
Jean-François Moinee9b15652010-06-05 07:07:56 -0300530 reg_w_buf(gspca_dev, all_gain_reg, sizeof all_gain_reg);
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300531}
532
Hans Verkuil9bf81642012-05-18 03:41:58 -0300533static void setsharpness(struct gspca_dev *gspca_dev, s32 val)
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300534{
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300535 u16 reg_to_write;
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300536
Hans Verkuil9bf81642012-05-18 03:41:58 -0300537 reg_to_write = 0x0aa6 + 0x1000 * val;
Jean-Francois Moine35480b6b2008-10-17 05:19:46 -0300538
539 reg_w(gspca_dev, reg_to_write);
540}
541
Hans Verkuil9bf81642012-05-18 03:41:58 -0300542static void setfreq(struct gspca_dev *gspca_dev, s32 val)
Jean-François Moine78b98cb2010-06-05 07:01:46 -0300543{
544 struct sd *sd = (struct sd *) gspca_dev;
545 u8 reg66;
546 u8 freq[4] = { 0x66, 0x00, 0xa8, 0xe8 };
547
548 switch (sd->sensor) {
549 case SENSOR_LT168G:
Hans Verkuil9bf81642012-05-18 03:41:58 -0300550 if (val != 0)
Jean-François Moine78b98cb2010-06-05 07:01:46 -0300551 freq[3] = 0xa8;
552 reg66 = 0x41;
553 break;
554 case SENSOR_OM6802:
555 reg66 = 0xca;
556 break;
557 default:
558 reg66 = 0x40;
559 break;
560 }
Hans Verkuil9bf81642012-05-18 03:41:58 -0300561 switch (val) {
Jean-François Moine78b98cb2010-06-05 07:01:46 -0300562 case 0: /* no flicker */
563 freq[3] = 0xf0;
564 break;
565 case 2: /* 60Hz */
566 reg66 &= ~0x40;
567 break;
568 }
569 freq[1] = reg66;
570
571 reg_w_buf(gspca_dev, freq, sizeof freq);
572}
573
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300574/* this function is called at probe and resume time */
575static int sd_init(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300576{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300577 /* some of this registers are not really neded, because
578 * they are overriden by setbrigthness, setcontrast, etc,
579 * but wont hurt anyway, and can help someone with similar webcam
580 * to see the initial parameters.*/
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300581 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300582 const struct additional_sensor_data *sensor;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300583 int i;
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300584 u16 sensor_id;
Hans Verkuild9ddd3b2009-01-29 06:23:18 -0300585 u8 test_byte = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300586
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300587 static const u8 read_indexs[] =
Jean-Francois Moine249fe882009-03-22 16:30:42 -0300588 { 0x0a, 0x0b, 0x66, 0x80, 0x81, 0x8e, 0x8f, 0xa5,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300589 0xa6, 0xa8, 0xbb, 0xbc, 0xc6, 0x00 };
590 static const u8 n1[] =
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300591 {0x08, 0x03, 0x09, 0x03, 0x12, 0x04};
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300592 static const u8 n2[] =
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300593 {0x08, 0x00};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300594
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300595 sensor_id = (reg_r(gspca_dev, 0x06) << 8)
596 | reg_r(gspca_dev, 0x07);
Jean-Francois Moine3da37e42009-03-22 16:29:36 -0300597 switch (sensor_id & 0xff0f) {
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300598 case 0x0801:
Jean-Francois Moine748c0142009-02-06 14:11:58 -0300599 PDEBUG(D_PROBE, "sensor tas5130a");
Jean-Francois Moine236088d2008-10-17 04:53:02 -0300600 sd->sensor = SENSOR_TAS5130A;
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300601 break;
Nicolau Werneck00e80062010-01-30 16:00:15 -0300602 case 0x0802:
603 PDEBUG(D_PROBE, "sensor lt168g");
604 sd->sensor = SENSOR_LT168G;
605 break;
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300606 case 0x0803:
Jean-Francois Moine748c0142009-02-06 14:11:58 -0300607 PDEBUG(D_PROBE, "sensor 'other'");
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300608 sd->sensor = SENSOR_OTHER;
609 break;
610 case 0x0807:
Jean-Francois Moine748c0142009-02-06 14:11:58 -0300611 PDEBUG(D_PROBE, "sensor om6802");
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300612 sd->sensor = SENSOR_OM6802;
613 break;
614 default:
Joe Perches1b19e4292011-08-21 19:56:56 -0300615 pr_err("unknown sensor %04x\n", sensor_id);
Jean-Francois Moine409b11d2009-01-22 12:53:56 -0300616 return -EINVAL;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300617 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300618
Jean-Francois Moinedd72cb32009-03-12 04:40:19 -0300619 if (sd->sensor == SENSOR_OM6802) {
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300620 reg_w_buf(gspca_dev, n1, sizeof n1);
621 i = 5;
622 while (--i >= 0) {
623 reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset);
624 test_byte = reg_r(gspca_dev, 0x0063);
625 msleep(100);
626 if (test_byte == 0x17)
627 break; /* OK */
628 }
629 if (i < 0) {
Joe Perches1b19e4292011-08-21 19:56:56 -0300630 pr_err("Bad sensor reset %02x\n", test_byte);
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300631 return -EIO;
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300632 }
633 reg_w_buf(gspca_dev, n2, sizeof n2);
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300634 }
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300635
636 i = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300637 while (read_indexs[i] != 0x00) {
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300638 test_byte = reg_r(gspca_dev, read_indexs[i]);
639 PDEBUG(D_STREAM, "Reg 0x%02x = 0x%02x", read_indexs[i],
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300640 test_byte);
641 i++;
642 }
643
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300644 sensor = &sensor_data[sd->sensor];
645 reg_w_buf(gspca_dev, sensor->n3, sizeof sensor->n3);
646 reg_w_buf(gspca_dev, sensor->n4, sensor->n4sz);
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300647
Nicolau Werneck00e80062010-01-30 16:00:15 -0300648 if (sd->sensor == SENSOR_LT168G) {
649 test_byte = reg_r(gspca_dev, 0x80);
650 PDEBUG(D_STREAM, "Reg 0x%02x = 0x%02x", 0x80,
651 test_byte);
652 reg_w(gspca_dev, 0x6c80);
653 }
654
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300655 reg_w_ixbuf(gspca_dev, 0xd0, sensor->data1, sizeof sensor->data1);
656 reg_w_ixbuf(gspca_dev, 0xc7, sensor->data2, sizeof sensor->data2);
657 reg_w_ixbuf(gspca_dev, 0xe0, sensor->data3, sizeof sensor->data3);
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300658
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300659 reg_w(gspca_dev, (sensor->reg80 << 8) + 0x80);
660 reg_w(gspca_dev, (sensor->reg80 << 8) + 0x80);
661 reg_w(gspca_dev, (sensor->reg8e << 8) + 0x8e);
Hans Verkuil9bf81642012-05-18 03:41:58 -0300662 reg_w(gspca_dev, (0x20 << 8) + 0x87);
663 reg_w(gspca_dev, (0x20 << 8) + 0x88);
664 reg_w(gspca_dev, (0x20 << 8) + 0x89);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300665
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300666 reg_w_buf(gspca_dev, sensor->data5, sizeof sensor->data5);
667 reg_w_buf(gspca_dev, sensor->nset8, sizeof sensor->nset8);
668 reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300669
Nicolau Werneck00e80062010-01-30 16:00:15 -0300670 if (sd->sensor == SENSOR_LT168G) {
671 test_byte = reg_r(gspca_dev, 0x80);
672 PDEBUG(D_STREAM, "Reg 0x%02x = 0x%02x", 0x80,
673 test_byte);
674 reg_w(gspca_dev, 0x6c80);
675 }
676
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300677 reg_w_ixbuf(gspca_dev, 0xd0, sensor->data1, sizeof sensor->data1);
678 reg_w_ixbuf(gspca_dev, 0xc7, sensor->data2, sizeof sensor->data2);
679 reg_w_ixbuf(gspca_dev, 0xe0, sensor->data3, sizeof sensor->data3);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300680
681 return 0;
682}
683
Hans Verkuil9bf81642012-05-18 03:41:58 -0300684static void setmirror(struct gspca_dev *gspca_dev, s32 val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300685{
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300686 u8 hflipcmd[8] =
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300687 {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300688
Hans Verkuil9bf81642012-05-18 03:41:58 -0300689 if (val)
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300690 hflipcmd[3] = 0x01;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300691
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300692 reg_w_buf(gspca_dev, hflipcmd, sizeof hflipcmd);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300693}
694
Hans Verkuil9bf81642012-05-18 03:41:58 -0300695static void seteffect(struct gspca_dev *gspca_dev, s32 val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300696{
Hans Verkuil9bf81642012-05-18 03:41:58 -0300697 int idx = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300698
Hans Verkuil9bf81642012-05-18 03:41:58 -0300699 switch (val) {
700 case V4L2_COLORFX_NONE:
701 break;
702 case V4L2_COLORFX_BW:
703 idx = 2;
704 break;
705 case V4L2_COLORFX_SEPIA:
706 idx = 3;
707 break;
708 case V4L2_COLORFX_SKETCH:
709 idx = 4;
710 break;
711 case V4L2_COLORFX_NEGATIVE:
712 idx = 6;
713 break;
714 default:
715 break;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300716 }
717
Hans Verkuil9bf81642012-05-18 03:41:58 -0300718 reg_w_buf(gspca_dev, effects_table[idx],
719 sizeof effects_table[0]);
720
721 if (val == V4L2_COLORFX_SKETCH)
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300722 reg_w(gspca_dev, 0x4aa6);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300723 else
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300724 reg_w(gspca_dev, 0xfaa6);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300725}
726
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300727/* Is this really needed?
728 * i added some module parameters for test with some users */
729static void poll_sensor(struct gspca_dev *gspca_dev)
730{
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300731 static const u8 poll1[] =
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300732 {0x67, 0x05, 0x68, 0x81, 0x69, 0x80, 0x6a, 0x82,
733 0x6b, 0x68, 0x6c, 0x69, 0x72, 0xd9, 0x73, 0x34,
734 0x74, 0x32, 0x75, 0x92, 0x76, 0x00, 0x09, 0x01,
735 0x60, 0x14};
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300736 static const u8 poll2[] =
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300737 {0x67, 0x02, 0x68, 0x71, 0x69, 0x72, 0x72, 0xa9,
738 0x73, 0x02, 0x73, 0x02, 0x60, 0x14};
Jean-François Moine98388242010-06-04 07:30:21 -0300739 static const u8 noise03[] = /* (some differences / ms-drv) */
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300740 {0xa6, 0x0a, 0xea, 0xcf, 0xbe, 0x26, 0xb1, 0x5f,
741 0xa1, 0xb1, 0xda, 0x6b, 0xdb, 0x98, 0xdf, 0x0c,
742 0xc2, 0x80, 0xc3, 0x10};
743
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300744 PDEBUG(D_STREAM, "[Sensor requires polling]");
745 reg_w_buf(gspca_dev, poll1, sizeof poll1);
746 reg_w_buf(gspca_dev, poll2, sizeof poll2);
Jean-François Moine98388242010-06-04 07:30:21 -0300747 reg_w_buf(gspca_dev, noise03, sizeof noise03);
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300748}
749
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300750static int sd_start(struct gspca_dev *gspca_dev)
751{
752 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300753 const struct additional_sensor_data *sensor;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300754 int i, mode;
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300755 u8 t2[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 };
756 static const u8 t3[] =
757 { 0x07, 0x00, 0x88, 0x02, 0x06, 0x00, 0xe7, 0x01 };
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300758
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300759 mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300760 switch (mode) {
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300761 case 0: /* 640x480 (0x00) */
762 break;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300763 case 1: /* 352x288 */
764 t2[1] = 0x40;
765 break;
766 case 2: /* 320x240 */
767 t2[1] = 0x10;
768 break;
769 case 3: /* 176x144 */
770 t2[1] = 0x50;
771 break;
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300772 default:
773/* case 4: * 160x120 */
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300774 t2[1] = 0x20;
775 break;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300776 }
777
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300778 switch (sd->sensor) {
779 case SENSOR_OM6802:
780 om6802_sensor_init(gspca_dev);
781 break;
Jean-François Moinecd8955b2010-06-04 07:22:57 -0300782 case SENSOR_TAS5130A:
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300783 i = 0;
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300784 for (;;) {
Jean-Francois Moinef89be032008-10-17 04:42:29 -0300785 reg_w_buf(gspca_dev, tas5130a_sensor_init[i],
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300786 sizeof tas5130a_sensor_init[0]);
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300787 if (i >= ARRAY_SIZE(tas5130a_sensor_init) - 1)
788 break;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300789 i++;
790 }
791 reg_w(gspca_dev, 0x3c80);
792 /* just in case and to keep sync with logs (for mine) */
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300793 reg_w_buf(gspca_dev, tas5130a_sensor_init[i],
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300794 sizeof tas5130a_sensor_init[0]);
795 reg_w(gspca_dev, 0x3c80);
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300796 break;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300797 }
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300798 sensor = &sensor_data[sd->sensor];
Hans Verkuil9bf81642012-05-18 03:41:58 -0300799 setfreq(gspca_dev, v4l2_ctrl_g_ctrl(sd->freq));
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300800 reg_r(gspca_dev, 0x0012);
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300801 reg_w_buf(gspca_dev, t2, sizeof t2);
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300802 reg_w_ixbuf(gspca_dev, 0xb3, t3, sizeof t3);
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300803 reg_w(gspca_dev, 0x0013);
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300804 msleep(15);
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300805 reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
806 reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
Leandro Costantinoad62fb02008-10-17 05:27:04 -0300807
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300808 if (sd->sensor == SENSOR_OM6802)
809 poll_sensor(gspca_dev);
810
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300811 return 0;
812}
813
Jean-Francois Moineeb229b22008-10-17 05:28:40 -0300814static void sd_stopN(struct gspca_dev *gspca_dev)
815{
816 struct sd *sd = (struct sd *) gspca_dev;
817
818 reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
819 sizeof sensor_data[sd->sensor].stream);
Jean-Francois Moineeb229b22008-10-17 05:28:40 -0300820 reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
821 sizeof sensor_data[sd->sensor].stream);
Jean-Francois Moine78a6d742009-07-07 04:03:24 -0300822 if (sd->sensor == SENSOR_OM6802) {
Jean-Francois Moine2d56f3b2009-01-22 08:25:16 -0300823 msleep(20);
824 reg_w(gspca_dev, 0x0309);
825 }
Hans de Goedeee186fd2012-01-01 16:09:17 -0300826#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
827 /* If the last button state is pressed, release it now! */
828 if (sd->button_pressed) {
829 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
830 input_sync(gspca_dev->input_dev);
831 sd->button_pressed = 0;
832 }
833#endif
Jean-Francois Moineeb229b22008-10-17 05:28:40 -0300834}
835
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300836static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Jean-Francois Moine82e25492009-01-22 07:18:48 -0300837 u8 *data, /* isoc packet */
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300838 int len) /* iso packet length */
839{
Hans de Goedeee186fd2012-01-01 16:09:17 -0300840 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moineebb78c52010-06-05 06:56:48 -0300841 int pkt_type;
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300842
843 if (data[0] == 0x5a) {
Hans de Goedeee186fd2012-01-01 16:09:17 -0300844#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
845 if (len > 20) {
846 u8 state = (data[20] & 0x80) ? 1 : 0;
847 if (sd->button_pressed != state) {
848 input_report_key(gspca_dev->input_dev,
849 KEY_CAMERA, state);
850 input_sync(gspca_dev->input_dev);
851 sd->button_pressed = state;
852 }
853 }
854#endif
Jean-Francois Moinefadc7992008-10-08 08:06:08 -0300855 /* Control Packet, after this came the header again,
856 * but extra bytes came in the packet before this,
857 * sometimes an EOF arrives, sometimes not... */
858 return;
859 }
860 data += 2;
861 len -= 2;
Jean-François Moineebb78c52010-06-05 06:56:48 -0300862 if (data[0] == 0xff && data[1] == 0xd8)
863 pkt_type = FIRST_PACKET;
864 else if (data[len - 2] == 0xff && data[len - 1] == 0xd9)
865 pkt_type = LAST_PACKET;
866 else
867 pkt_type = INTER_PACKET;
868 gspca_frame_add(gspca_dev, pkt_type, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300869}
870
Hans Verkuil9bf81642012-05-18 03:41:58 -0300871static int sd_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300872{
Hans Verkuil9bf81642012-05-18 03:41:58 -0300873 struct gspca_dev *gspca_dev =
874 container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
875 struct sd *sd = (struct sd *)gspca_dev;
876 s32 red_gain, blue_gain, green_gain;
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300877
Hans Verkuil9bf81642012-05-18 03:41:58 -0300878 gspca_dev->usb_err = 0;
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300879
Hans Verkuil9bf81642012-05-18 03:41:58 -0300880 switch (ctrl->id) {
881 case V4L2_CID_AUTO_WHITE_BALANCE:
882 red_gain = reg_r(gspca_dev, 0x0087);
883 if (red_gain > 0x40)
884 red_gain = 0x40;
885 else if (red_gain < 0x10)
886 red_gain = 0x10;
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300887
Hans Verkuil9bf81642012-05-18 03:41:58 -0300888 blue_gain = reg_r(gspca_dev, 0x0088);
889 if (blue_gain > 0x40)
890 blue_gain = 0x40;
891 else if (blue_gain < 0x10)
892 blue_gain = 0x10;
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300893
Hans Verkuil9bf81642012-05-18 03:41:58 -0300894 green_gain = reg_r(gspca_dev, 0x0089);
895 if (green_gain > 0x40)
896 green_gain = 0x40;
897 else if (green_gain < 0x10)
898 green_gain = 0x10;
Costantino Leandrobe1da9e2010-03-23 12:31:16 -0300899
Hans Verkuil9bf81642012-05-18 03:41:58 -0300900 sd->gain->val = green_gain;
901 sd->red_balance->val = red_gain - green_gain;
902 sd->blue_balance->val = blue_gain - green_gain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300903 break;
904 }
Hans Verkuil9bf81642012-05-18 03:41:58 -0300905 return 0;
906}
907
908static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
909{
910 struct gspca_dev *gspca_dev =
911 container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
912
913 gspca_dev->usb_err = 0;
914
915 if (!gspca_dev->streaming)
916 return 0;
917
918 switch (ctrl->id) {
919 case V4L2_CID_BRIGHTNESS:
920 setbrightness(gspca_dev, ctrl->val);
921 break;
922 case V4L2_CID_CONTRAST:
923 setcontrast(gspca_dev, ctrl->val);
924 break;
925 case V4L2_CID_SATURATION:
926 setcolors(gspca_dev, ctrl->val);
927 break;
928 case V4L2_CID_GAMMA:
929 setgamma(gspca_dev, ctrl->val);
930 break;
931 case V4L2_CID_HFLIP:
932 setmirror(gspca_dev, ctrl->val);
933 break;
934 case V4L2_CID_SHARPNESS:
935 setsharpness(gspca_dev, ctrl->val);
936 break;
937 case V4L2_CID_POWER_LINE_FREQUENCY:
938 setfreq(gspca_dev, ctrl->val);
939 break;
940 case V4L2_CID_BACKLIGHT_COMPENSATION:
941 reg_w(gspca_dev, ctrl->val ? 0xf48e : 0xb48e);
942 break;
943 case V4L2_CID_AUTO_WHITE_BALANCE:
944 setawb_n_RGB(gspca_dev);
945 break;
946 case V4L2_CID_COLORFX:
947 seteffect(gspca_dev, ctrl->val);
948 break;
949 }
950 return gspca_dev->usb_err;
951}
952
953static const struct v4l2_ctrl_ops sd_ctrl_ops = {
954 .g_volatile_ctrl = sd_g_volatile_ctrl,
955 .s_ctrl = sd_s_ctrl,
956};
957
958static int sd_init_controls(struct gspca_dev *gspca_dev)
959{
960 struct sd *sd = (struct sd *)gspca_dev;
961 struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
962
963 gspca_dev->vdev.ctrl_handler = hdl;
964 v4l2_ctrl_handler_init(hdl, 12);
965 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
966 V4L2_CID_BRIGHTNESS, 0, 14, 1, 8);
967 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
968 V4L2_CID_CONTRAST, 0, 0x0d, 1, 7);
969 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
970 V4L2_CID_SATURATION, 0, 0xf, 1, 5);
971 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
972 V4L2_CID_GAMMA, 0, GAMMA_MAX, 1, 10);
973 /* Activate lowlight, some apps dont bring up the
974 backlight_compensation control) */
975 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
976 V4L2_CID_BACKLIGHT_COMPENSATION, 0, 1, 1, 1);
977 if (sd->sensor == SENSOR_TAS5130A)
978 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
979 V4L2_CID_HFLIP, 0, 1, 1, 0);
980 sd->awb = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
981 V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
982 sd->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
983 V4L2_CID_GAIN, 0x10, 0x40, 1, 0x20);
984 sd->blue_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
985 V4L2_CID_BLUE_BALANCE, -0x30, 0x30, 1, 0);
986 sd->red_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
987 V4L2_CID_RED_BALANCE, -0x30, 0x30, 1, 0);
988 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
989 V4L2_CID_SHARPNESS, 0, 15, 1, 6);
990 v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops,
991 V4L2_CID_COLORFX, V4L2_COLORFX_SKETCH,
992 ~((1 << V4L2_COLORFX_NONE) |
993 (1 << V4L2_COLORFX_BW) |
994 (1 << V4L2_COLORFX_SEPIA) |
995 (1 << V4L2_COLORFX_SKETCH) |
996 (1 << V4L2_COLORFX_NEGATIVE)),
997 V4L2_COLORFX_NONE);
998 sd->freq = v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops,
999 V4L2_CID_POWER_LINE_FREQUENCY,
1000 V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 1,
1001 V4L2_CID_POWER_LINE_FREQUENCY_50HZ);
1002
1003 if (hdl->error) {
1004 pr_err("Could not initialize controls\n");
1005 return hdl->error;
1006 }
1007
1008 v4l2_ctrl_auto_cluster(4, &sd->awb, 0, true);
1009
1010 return 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001011}
1012
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001013/* sub-driver description */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001014static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001015 .name = MODULE_NAME,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001016 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -03001017 .init = sd_init,
Hans Verkuil9bf81642012-05-18 03:41:58 -03001018 .init_controls = sd_init_controls,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001019 .start = sd_start,
Jean-Francois Moineeb229b22008-10-17 05:28:40 -03001020 .stopN = sd_stopN,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001021 .pkt_scan = sd_pkt_scan,
Hans de Goedeee186fd2012-01-01 16:09:17 -03001022#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
1023 .other_input = 1,
1024#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001025};
1026
1027/* -- module initialisation -- */
Jean-François Moine95c967c2011-01-13 05:20:29 -03001028static const struct usb_device_id device_table[] = {
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -03001029 {USB_DEVICE(0x17a1, 0x0128)},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001030 {}
1031};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001032MODULE_DEVICE_TABLE(usb, device_table);
1033
1034/* -- device connect -- */
1035static int sd_probe(struct usb_interface *intf,
1036 const struct usb_device_id *id)
1037{
1038 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1039 THIS_MODULE);
1040}
1041
1042static struct usb_driver sd_driver = {
1043 .name = MODULE_NAME,
1044 .id_table = device_table,
1045 .probe = sd_probe,
1046 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -03001047#ifdef CONFIG_PM
1048 .suspend = gspca_suspend,
1049 .resume = gspca_resume,
Hans de Goede8bb58962012-06-30 06:44:47 -03001050 .reset_resume = gspca_resume,
Jean-Francois Moine6a709742008-09-03 16:48:10 -03001051#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001052};
1053
Greg Kroah-Hartmanecb3b2b2011-11-18 09:46:12 -08001054module_usb_driver(sd_driver);