blob: 3884c9d300c5ed766f34eed7060cb59161494c77 [file] [log] [blame]
Kyle Guinnd661e622009-01-16 05:36:14 -03001/*
2 * Mars MR97310A library
3 *
Theodore Kilgore930bf782009-10-05 05:11:35 -03004 * The original mr97310a driver, which supported the Aiptek Pencam VGA+, is
Kyle Guinnd661e622009-01-16 05:36:14 -03005 * Copyright (C) 2009 Kyle Guinn <elyk03@gmail.com>
6 *
Theodore Kilgore89f08632009-08-14 06:51:52 -03007 * Support for the MR97310A cameras in addition to the Aiptek Pencam VGA+
8 * and for the routines for detecting and classifying these various cameras,
Theodore Kilgore930bf782009-10-05 05:11:35 -03009 * is Copyright (C) 2009 Theodore Kilgore <kilgota@auburn.edu>
Theodore Kilgore89f08632009-08-14 06:51:52 -030010 *
Theodore Kilgore930bf782009-10-05 05:11:35 -030011 * Support for the control settings for the CIF cameras is
Hans de Goede1fddcf02010-09-05 07:06:04 -030012 * Copyright (C) 2009 Hans de Goede <hdegoede@redhat.com> and
Theodore Kilgore930bf782009-10-05 05:11:35 -030013 * Thomas Kaiser <thomas@kaiser-linux.li>
14 *
15 * Support for the control settings for the VGA cameras is
Theodore Kilgore89f08632009-08-14 06:51:52 -030016 * Copyright (C) 2009 Theodore Kilgore <kilgota@auburn.edu>
17 *
Theodore Kilgore930bf782009-10-05 05:11:35 -030018 * Several previously unsupported cameras are owned and have been tested by
Hans de Goede1fddcf02010-09-05 07:06:04 -030019 * Hans de Goede <hdegoede@redhat.com> and
Theodore Kilgore930bf782009-10-05 05:11:35 -030020 * Thomas Kaiser <thomas@kaiser-linux.li> and
Theodore Kilgore1160a382009-10-30 04:29:56 -030021 * Theodore Kilgore <kilgota@auburn.edu> and
22 * Edmond Rodriguez <erodrig_97@yahoo.com> and
23 * Aurelien Jacobs <aurel@gnuage.org>
Theodore Kilgore89f08632009-08-14 06:51:52 -030024 *
25 * The MR97311A support in gspca/mars.c has been helpful in understanding some
26 * of the registers in these cameras.
27 *
Kyle Guinnd661e622009-01-16 05:36:14 -030028 * This program is free software; you can redistribute it and/or modify
29 * it under the terms of the GNU General Public License as published by
30 * the Free Software Foundation; either version 2 of the License, or
31 * any later version.
32 *
33 * This program is distributed in the hope that it will be useful,
34 * but WITHOUT ANY WARRANTY; without even the implied warranty of
35 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
36 * GNU General Public License for more details.
37 *
38 * You should have received a copy of the GNU General Public License
39 * along with this program; if not, write to the Free Software
40 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
41 */
42
43#define MODULE_NAME "mr97310a"
44
45#include "gspca.h"
46
Theodore Kilgore89f08632009-08-14 06:51:52 -030047#define CAM_TYPE_CIF 0
48#define CAM_TYPE_VGA 1
49
Theodore Kilgore89f08632009-08-14 06:51:52 -030050#define MR97310A_BRIGHTNESS_DEFAULT 0
51
Theodore Kilgore930bf782009-10-05 05:11:35 -030052#define MR97310A_EXPOSURE_MIN 0
Theodore Kilgore89f08632009-08-14 06:51:52 -030053#define MR97310A_EXPOSURE_MAX 4095
54#define MR97310A_EXPOSURE_DEFAULT 1000
55
56#define MR97310A_GAIN_MIN 0
57#define MR97310A_GAIN_MAX 31
58#define MR97310A_GAIN_DEFAULT 25
59
Theodore Kilgore9d3103d2010-02-09 18:05:25 -030060#define MR97310A_CONTRAST_MIN 0
61#define MR97310A_CONTRAST_MAX 31
62#define MR97310A_CONTRAST_DEFAULT 23
63
64#define MR97310A_CS_GAIN_MIN 0
65#define MR97310A_CS_GAIN_MAX 0x7ff
66#define MR97310A_CS_GAIN_DEFAULT 0x110
67
Hans de Goede065b6f72009-10-29 07:42:30 -030068#define MR97310A_MIN_CLOCKDIV_MIN 3
69#define MR97310A_MIN_CLOCKDIV_MAX 8
70#define MR97310A_MIN_CLOCKDIV_DEFAULT 3
71
Theodore Kilgore89f08632009-08-14 06:51:52 -030072MODULE_AUTHOR("Kyle Guinn <elyk03@gmail.com>,"
73 "Theodore Kilgore <kilgota@auburn.edu>");
Kyle Guinnd661e622009-01-16 05:36:14 -030074MODULE_DESCRIPTION("GSPCA/Mars-Semi MR97310A USB Camera Driver");
75MODULE_LICENSE("GPL");
76
Hans de Goede78028702009-09-02 09:55:16 -030077/* global parameters */
Jean-Francois Moine83955552009-12-12 06:58:01 -030078static int force_sensor_type = -1;
Hans de Goede78028702009-09-02 09:55:16 -030079module_param(force_sensor_type, int, 0644);
80MODULE_PARM_DESC(force_sensor_type, "Force sensor type (-1 (auto), 0 or 1)");
81
Kyle Guinnd661e622009-01-16 05:36:14 -030082/* specific webcam descriptor */
83struct sd {
84 struct gspca_dev gspca_dev; /* !! must be the first item */
Kyle Guinnd661e622009-01-16 05:36:14 -030085 u8 sof_read;
Theodore Kilgore89f08632009-08-14 06:51:52 -030086 u8 cam_type; /* 0 is CIF and 1 is VGA */
87 u8 sensor_type; /* We use 0 and 1 here, too. */
88 u8 do_lcd_stop;
Theodore Kilgore64f4d9a2009-10-30 04:43:39 -030089 u8 adj_colors;
Theodore Kilgore89f08632009-08-14 06:51:52 -030090
91 int brightness;
92 u16 exposure;
Theodore Kilgore9d3103d2010-02-09 18:05:25 -030093 u32 gain;
94 u8 contrast;
Hans de Goede065b6f72009-10-29 07:42:30 -030095 u8 min_clockdiv;
Kyle Guinnd661e622009-01-16 05:36:14 -030096};
97
Theodore Kilgore89f08632009-08-14 06:51:52 -030098struct sensor_w_data {
99 u8 reg;
100 u8 flags;
101 u8 data[16];
102 int len;
103};
104
Theodore Kilgore930bf782009-10-05 05:11:35 -0300105static void sd_stopN(struct gspca_dev *gspca_dev);
Theodore Kilgore89f08632009-08-14 06:51:52 -0300106static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
107static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
108static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
109static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
Theodore Kilgore9d3103d2010-02-09 18:05:25 -0300110static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
111static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
Theodore Kilgore89f08632009-08-14 06:51:52 -0300112static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
113static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
Hans de Goede065b6f72009-10-29 07:42:30 -0300114static int sd_setmin_clockdiv(struct gspca_dev *gspca_dev, __s32 val);
115static int sd_getmin_clockdiv(struct gspca_dev *gspca_dev, __s32 *val);
Hans de Goede9ac69782009-08-14 10:15:52 -0300116static void setbrightness(struct gspca_dev *gspca_dev);
117static void setexposure(struct gspca_dev *gspca_dev);
118static void setgain(struct gspca_dev *gspca_dev);
Theodore Kilgore9d3103d2010-02-09 18:05:25 -0300119static void setcontrast(struct gspca_dev *gspca_dev);
Theodore Kilgore89f08632009-08-14 06:51:52 -0300120
Kyle Guinnd661e622009-01-16 05:36:14 -0300121/* V4L2 controls supported by the driver */
Marton Nemeth7e64dc42009-12-30 09:12:41 -0300122static const struct ctrl sd_ctrls[] = {
Theodore Kilgore1160a382009-10-30 04:29:56 -0300123/* Separate brightness control description for Argus QuickClix as it has
Theodore Kilgore9d3103d2010-02-09 18:05:25 -0300124 * different limits from the other mr97310a cameras, and separate gain
125 * control for Sakar CyberPix camera. */
Theodore Kilgore89f08632009-08-14 06:51:52 -0300126 {
Theodore Kilgore930bf782009-10-05 05:11:35 -0300127#define NORM_BRIGHTNESS_IDX 0
Theodore Kilgore89f08632009-08-14 06:51:52 -0300128 {
129 .id = V4L2_CID_BRIGHTNESS,
130 .type = V4L2_CTRL_TYPE_INTEGER,
131 .name = "Brightness",
Theodore Kilgore930bf782009-10-05 05:11:35 -0300132 .minimum = -254,
133 .maximum = 255,
Theodore Kilgore89f08632009-08-14 06:51:52 -0300134 .step = 1,
135 .default_value = MR97310A_BRIGHTNESS_DEFAULT,
136 .flags = 0,
137 },
138 .set = sd_setbrightness,
139 .get = sd_getbrightness,
140 },
141 {
Theodore Kilgore930bf782009-10-05 05:11:35 -0300142#define ARGUS_QC_BRIGHTNESS_IDX 1
143 {
144 .id = V4L2_CID_BRIGHTNESS,
145 .type = V4L2_CTRL_TYPE_INTEGER,
146 .name = "Brightness",
147 .minimum = 0,
148 .maximum = 15,
149 .step = 1,
150 .default_value = MR97310A_BRIGHTNESS_DEFAULT,
151 .flags = 0,
152 },
153 .set = sd_setbrightness,
154 .get = sd_getbrightness,
155 },
156 {
157#define EXPOSURE_IDX 2
Theodore Kilgore89f08632009-08-14 06:51:52 -0300158 {
159 .id = V4L2_CID_EXPOSURE,
160 .type = V4L2_CTRL_TYPE_INTEGER,
161 .name = "Exposure",
162 .minimum = MR97310A_EXPOSURE_MIN,
163 .maximum = MR97310A_EXPOSURE_MAX,
164 .step = 1,
165 .default_value = MR97310A_EXPOSURE_DEFAULT,
166 .flags = 0,
167 },
168 .set = sd_setexposure,
169 .get = sd_getexposure,
170 },
171 {
Theodore Kilgore930bf782009-10-05 05:11:35 -0300172#define GAIN_IDX 3
Theodore Kilgore89f08632009-08-14 06:51:52 -0300173 {
174 .id = V4L2_CID_GAIN,
175 .type = V4L2_CTRL_TYPE_INTEGER,
176 .name = "Gain",
177 .minimum = MR97310A_GAIN_MIN,
178 .maximum = MR97310A_GAIN_MAX,
179 .step = 1,
180 .default_value = MR97310A_GAIN_DEFAULT,
181 .flags = 0,
182 },
183 .set = sd_setgain,
184 .get = sd_getgain,
185 },
Hans de Goede065b6f72009-10-29 07:42:30 -0300186 {
Theodore Kilgore9d3103d2010-02-09 18:05:25 -0300187#define SAKAR_CS_GAIN_IDX 4
188 {
189 .id = V4L2_CID_GAIN,
190 .type = V4L2_CTRL_TYPE_INTEGER,
191 .name = "Gain",
192 .minimum = MR97310A_CS_GAIN_MIN,
193 .maximum = MR97310A_CS_GAIN_MAX,
194 .step = 1,
195 .default_value = MR97310A_CS_GAIN_DEFAULT,
196 .flags = 0,
197 },
198 .set = sd_setgain,
199 .get = sd_getgain,
200 },
201 {
202#define CONTRAST_IDX 5
203 {
204 .id = V4L2_CID_CONTRAST,
205 .type = V4L2_CTRL_TYPE_INTEGER,
206 .name = "Contrast",
207 .minimum = MR97310A_CONTRAST_MIN,
208 .maximum = MR97310A_CONTRAST_MAX,
209 .step = 1,
210 .default_value = MR97310A_CONTRAST_DEFAULT,
211 .flags = 0,
212 },
213 .set = sd_setcontrast,
214 .get = sd_getcontrast,
215 },
216 {
217#define MIN_CLOCKDIV_IDX 6
Hans de Goede065b6f72009-10-29 07:42:30 -0300218 {
219 .id = V4L2_CID_PRIVATE_BASE,
220 .type = V4L2_CTRL_TYPE_INTEGER,
221 .name = "Minimum Clock Divider",
222 .minimum = MR97310A_MIN_CLOCKDIV_MIN,
223 .maximum = MR97310A_MIN_CLOCKDIV_MAX,
224 .step = 1,
225 .default_value = MR97310A_MIN_CLOCKDIV_DEFAULT,
226 .flags = 0,
227 },
228 .set = sd_setmin_clockdiv,
229 .get = sd_getmin_clockdiv,
230 },
Kyle Guinnd661e622009-01-16 05:36:14 -0300231};
232
233static const struct v4l2_pix_format vga_mode[] = {
234 {160, 120, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE,
235 .bytesperline = 160,
236 .sizeimage = 160 * 120,
237 .colorspace = V4L2_COLORSPACE_SRGB,
238 .priv = 4},
239 {176, 144, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE,
240 .bytesperline = 176,
241 .sizeimage = 176 * 144,
242 .colorspace = V4L2_COLORSPACE_SRGB,
243 .priv = 3},
244 {320, 240, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE,
245 .bytesperline = 320,
246 .sizeimage = 320 * 240,
247 .colorspace = V4L2_COLORSPACE_SRGB,
248 .priv = 2},
249 {352, 288, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE,
250 .bytesperline = 352,
251 .sizeimage = 352 * 288,
252 .colorspace = V4L2_COLORSPACE_SRGB,
253 .priv = 1},
254 {640, 480, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE,
255 .bytesperline = 640,
256 .sizeimage = 640 * 480,
257 .colorspace = V4L2_COLORSPACE_SRGB,
258 .priv = 0},
259};
260
261/* the bytes to write are in gspca_dev->usb_buf */
Theodore Kilgore89f08632009-08-14 06:51:52 -0300262static int mr_write(struct gspca_dev *gspca_dev, int len)
Kyle Guinnd661e622009-01-16 05:36:14 -0300263{
264 int rc;
265
266 rc = usb_bulk_msg(gspca_dev->dev,
267 usb_sndbulkpipe(gspca_dev->dev, 4),
Jean-Francois Moine92e8c912009-02-02 16:25:38 -0300268 gspca_dev->usb_buf, len, NULL, 500);
Kyle Guinnd661e622009-01-16 05:36:14 -0300269 if (rc < 0)
Jean-François Moine0b656322010-09-13 05:19:58 -0300270 err("reg write [%02x] error %d",
Kyle Guinnd661e622009-01-16 05:36:14 -0300271 gspca_dev->usb_buf[0], rc);
272 return rc;
273}
274
Theodore Kilgore89f08632009-08-14 06:51:52 -0300275/* the bytes are read into gspca_dev->usb_buf */
276static int mr_read(struct gspca_dev *gspca_dev, int len)
277{
278 int rc;
279
280 rc = usb_bulk_msg(gspca_dev->dev,
281 usb_rcvbulkpipe(gspca_dev->dev, 3),
282 gspca_dev->usb_buf, len, NULL, 500);
283 if (rc < 0)
Jean-François Moine0b656322010-09-13 05:19:58 -0300284 err("reg read [%02x] error %d",
Theodore Kilgore89f08632009-08-14 06:51:52 -0300285 gspca_dev->usb_buf[0], rc);
286 return rc;
287}
288
289static int sensor_write_reg(struct gspca_dev *gspca_dev, u8 reg, u8 flags,
290 const u8 *data, int len)
291{
292 gspca_dev->usb_buf[0] = 0x1f;
293 gspca_dev->usb_buf[1] = flags;
294 gspca_dev->usb_buf[2] = reg;
295 memcpy(gspca_dev->usb_buf + 3, data, len);
296
297 return mr_write(gspca_dev, len + 3);
298}
299
300static int sensor_write_regs(struct gspca_dev *gspca_dev,
301 const struct sensor_w_data *data, int len)
302{
303 int i, rc;
304
305 for (i = 0; i < len; i++) {
306 rc = sensor_write_reg(gspca_dev, data[i].reg, data[i].flags,
307 data[i].data, data[i].len);
308 if (rc < 0)
309 return rc;
310 }
311
312 return 0;
313}
314
315static int sensor_write1(struct gspca_dev *gspca_dev, u8 reg, u8 data)
316{
Hans de Goedea2e081b2009-08-14 17:11:36 -0300317 struct sd *sd = (struct sd *) gspca_dev;
318 u8 buf, confirm_reg;
Theodore Kilgore89f08632009-08-14 06:51:52 -0300319 int rc;
320
321 buf = data;
Theodore Kilgore930bf782009-10-05 05:11:35 -0300322 if (sd->cam_type == CAM_TYPE_CIF) {
323 rc = sensor_write_reg(gspca_dev, reg, 0x01, &buf, 1);
324 confirm_reg = sd->sensor_type ? 0x13 : 0x11;
325 } else {
326 rc = sensor_write_reg(gspca_dev, reg, 0x00, &buf, 1);
327 confirm_reg = 0x11;
328 }
Theodore Kilgore89f08632009-08-14 06:51:52 -0300329 if (rc < 0)
330 return rc;
331
332 buf = 0x01;
Hans de Goedea2e081b2009-08-14 17:11:36 -0300333 rc = sensor_write_reg(gspca_dev, confirm_reg, 0x00, &buf, 1);
Theodore Kilgore89f08632009-08-14 06:51:52 -0300334 if (rc < 0)
335 return rc;
336
337 return 0;
338}
339
Theodore Kilgore930bf782009-10-05 05:11:35 -0300340static int cam_get_response16(struct gspca_dev *gspca_dev, u8 reg, int verbose)
Theodore Kilgore89f08632009-08-14 06:51:52 -0300341{
Theodore Kilgore89f08632009-08-14 06:51:52 -0300342 int err_code;
343
Theodore Kilgore930bf782009-10-05 05:11:35 -0300344 gspca_dev->usb_buf[0] = reg;
Theodore Kilgore89f08632009-08-14 06:51:52 -0300345 err_code = mr_write(gspca_dev, 1);
346 if (err_code < 0)
347 return err_code;
348
349 err_code = mr_read(gspca_dev, 16);
Theodore Kilgore930bf782009-10-05 05:11:35 -0300350 if (err_code < 0)
351 return err_code;
352
353 if (verbose)
354 PDEBUG(D_PROBE, "Register: %02x reads %02x%02x%02x", reg,
355 gspca_dev->usb_buf[0],
356 gspca_dev->usb_buf[1],
357 gspca_dev->usb_buf[2]);
358
359 return 0;
Theodore Kilgore89f08632009-08-14 06:51:52 -0300360}
361
362static int zero_the_pointer(struct gspca_dev *gspca_dev)
363{
364 __u8 *data = gspca_dev->usb_buf;
365 int err_code;
366 u8 status = 0;
367 int tries = 0;
368
Theodore Kilgore930bf782009-10-05 05:11:35 -0300369 err_code = cam_get_response16(gspca_dev, 0x21, 0);
Theodore Kilgore89f08632009-08-14 06:51:52 -0300370 if (err_code < 0)
371 return err_code;
372
Theodore Kilgore89f08632009-08-14 06:51:52 -0300373 data[0] = 0x19;
374 data[1] = 0x51;
375 err_code = mr_write(gspca_dev, 2);
376 if (err_code < 0)
377 return err_code;
378
Theodore Kilgore930bf782009-10-05 05:11:35 -0300379 err_code = cam_get_response16(gspca_dev, 0x21, 0);
Theodore Kilgore89f08632009-08-14 06:51:52 -0300380 if (err_code < 0)
381 return err_code;
382
383 data[0] = 0x19;
384 data[1] = 0xba;
385 err_code = mr_write(gspca_dev, 2);
386 if (err_code < 0)
387 return err_code;
388
Theodore Kilgore930bf782009-10-05 05:11:35 -0300389 err_code = cam_get_response16(gspca_dev, 0x21, 0);
Theodore Kilgore89f08632009-08-14 06:51:52 -0300390 if (err_code < 0)
391 return err_code;
392
393 data[0] = 0x19;
394 data[1] = 0x00;
395 err_code = mr_write(gspca_dev, 2);
396 if (err_code < 0)
397 return err_code;
398
Theodore Kilgore930bf782009-10-05 05:11:35 -0300399 err_code = cam_get_response16(gspca_dev, 0x21, 0);
Theodore Kilgore89f08632009-08-14 06:51:52 -0300400 if (err_code < 0)
401 return err_code;
402
403 data[0] = 0x19;
404 data[1] = 0x00;
405 err_code = mr_write(gspca_dev, 2);
406 if (err_code < 0)
407 return err_code;
408
409 while (status != 0x0a && tries < 256) {
Theodore Kilgore930bf782009-10-05 05:11:35 -0300410 err_code = cam_get_response16(gspca_dev, 0x21, 0);
Theodore Kilgore89f08632009-08-14 06:51:52 -0300411 status = data[0];
412 tries++;
413 if (err_code < 0)
414 return err_code;
415 }
Hans de Goede54943782009-08-14 11:05:38 -0300416 if (status != 0x0a)
417 PDEBUG(D_ERR, "status is %02x", status);
Theodore Kilgore89f08632009-08-14 06:51:52 -0300418
419 tries = 0;
420 while (tries < 4) {
421 data[0] = 0x19;
422 data[1] = 0x00;
423 err_code = mr_write(gspca_dev, 2);
424 if (err_code < 0)
425 return err_code;
426
Theodore Kilgore930bf782009-10-05 05:11:35 -0300427 err_code = cam_get_response16(gspca_dev, 0x21, 0);
Theodore Kilgore89f08632009-08-14 06:51:52 -0300428 status = data[0];
429 tries++;
430 if (err_code < 0)
431 return err_code;
432 }
Theodore Kilgore89f08632009-08-14 06:51:52 -0300433
434 data[0] = 0x19;
435 err_code = mr_write(gspca_dev, 1);
436 if (err_code < 0)
437 return err_code;
438
439 err_code = mr_read(gspca_dev, 16);
440 if (err_code < 0)
441 return err_code;
442
443 return 0;
444}
445
Theodore Kilgore930bf782009-10-05 05:11:35 -0300446static int stream_start(struct gspca_dev *gspca_dev)
Theodore Kilgore89f08632009-08-14 06:51:52 -0300447{
Theodore Kilgore930bf782009-10-05 05:11:35 -0300448 gspca_dev->usb_buf[0] = 0x01;
449 gspca_dev->usb_buf[1] = 0x01;
450 return mr_write(gspca_dev, 2);
451}
Theodore Kilgore89f08632009-08-14 06:51:52 -0300452
Theodore Kilgore930bf782009-10-05 05:11:35 -0300453static void stream_stop(struct gspca_dev *gspca_dev)
454{
455 gspca_dev->usb_buf[0] = 0x01;
456 gspca_dev->usb_buf[1] = 0x00;
457 if (mr_write(gspca_dev, 2) < 0)
458 PDEBUG(D_ERR, "Stream Stop failed");
459}
Theodore Kilgore89f08632009-08-14 06:51:52 -0300460
Theodore Kilgore930bf782009-10-05 05:11:35 -0300461static void lcd_stop(struct gspca_dev *gspca_dev)
462{
463 gspca_dev->usb_buf[0] = 0x19;
464 gspca_dev->usb_buf[1] = 0x54;
465 if (mr_write(gspca_dev, 2) < 0)
466 PDEBUG(D_ERR, "LCD Stop failed");
467}
Theodore Kilgore89f08632009-08-14 06:51:52 -0300468
Theodore Kilgore930bf782009-10-05 05:11:35 -0300469static int isoc_enable(struct gspca_dev *gspca_dev)
470{
471 gspca_dev->usb_buf[0] = 0x00;
472 gspca_dev->usb_buf[1] = 0x4d; /* ISOC transfering enable... */
473 return mr_write(gspca_dev, 2);
Theodore Kilgore89f08632009-08-14 06:51:52 -0300474}
475
Theodore Kilgore1160a382009-10-30 04:29:56 -0300476/* This function is called at probe time */
Kyle Guinnd661e622009-01-16 05:36:14 -0300477static int sd_config(struct gspca_dev *gspca_dev,
478 const struct usb_device_id *id)
479{
Theodore Kilgore89f08632009-08-14 06:51:52 -0300480 struct sd *sd = (struct sd *) gspca_dev;
Kyle Guinnd661e622009-01-16 05:36:14 -0300481 struct cam *cam;
Theodore Kilgore9d3103d2010-02-09 18:05:25 -0300482 int gain_default = MR97310A_GAIN_DEFAULT;
Hans de Goede5f5e26b2009-08-14 10:40:26 -0300483 int err_code;
Kyle Guinnd661e622009-01-16 05:36:14 -0300484
485 cam = &gspca_dev->cam;
486 cam->cam_mode = vga_mode;
487 cam->nmodes = ARRAY_SIZE(vga_mode);
Theodore Kilgore930bf782009-10-05 05:11:35 -0300488 sd->do_lcd_stop = 0;
489
Theodore Kilgore1160a382009-10-30 04:29:56 -0300490 /* Several of the supported CIF cameras share the same USB ID but
491 * require different initializations and different control settings.
492 * The same is true of the VGA cameras. Therefore, we are forced
493 * to start the initialization process in order to determine which
494 * camera is present. Some of the supported cameras require the
Theodore Kilgore930bf782009-10-05 05:11:35 -0300495 * memory pointer to be set to 0 as the very first item of business
496 * or else they will not stream. So we do that immediately.
497 */
498 err_code = zero_the_pointer(gspca_dev);
499 if (err_code < 0)
500 return err_code;
Hans de Goede9ac69782009-08-14 10:15:52 -0300501
Theodore Kilgoreb3e440e2009-10-09 03:54:49 -0300502 err_code = stream_start(gspca_dev);
503 if (err_code < 0)
504 return err_code;
505
Theodore Kilgorec260fe92010-01-15 05:54:36 -0300506 /* Now, the query for sensor type. */
507 err_code = cam_get_response16(gspca_dev, 0x07, 1);
508 if (err_code < 0)
509 return err_code;
510
Aurelien Jacobs8ac246c2009-10-29 07:45:24 -0300511 if (id->idProduct == 0x0110 || id->idProduct == 0x010e) {
Theodore Kilgore89f08632009-08-14 06:51:52 -0300512 sd->cam_type = CAM_TYPE_CIF;
Hans de Goede9ac69782009-08-14 10:15:52 -0300513 cam->nmodes--;
Theodore Kilgore930bf782009-10-05 05:11:35 -0300514 /*
Theodore Kilgore1160a382009-10-30 04:29:56 -0300515 * All but one of the known CIF cameras share the same USB ID,
516 * but two different init routines are in use, and the control
517 * settings are different, too. We need to detect which camera
518 * of the two known varieties is connected!
Theodore Kilgore930bf782009-10-05 05:11:35 -0300519 *
520 * A list of known CIF cameras follows. They all report either
Theodore Kilgorec260fe92010-01-15 05:54:36 -0300521 * 0200 for type 0 or 0300 for type 1.
Theodore Kilgore930bf782009-10-05 05:11:35 -0300522 * If you have another to report, please do
523 *
524 * Name sd->sensor_type reported by
525 *
Theodore Kilgore9d3103d2010-02-09 18:05:25 -0300526 * Sakar 56379 Spy-shot 0 T. Kilgore
Theodore Kilgore930bf782009-10-05 05:11:35 -0300527 * Innovage 0 T. Kilgore
528 * Vivitar Mini 0 H. De Goede
529 * Vivitar Mini 0 E. Rodriguez
530 * Vivitar Mini 1 T. Kilgore
531 * Elta-Media 8212dc 1 T. Kaiser
532 * Philips dig. keych. 1 T. Kilgore
Theodore Kilgore1160a382009-10-30 04:29:56 -0300533 * Trust Spyc@m 100 1 A. Jacobs
Theodore Kilgore930bf782009-10-05 05:11:35 -0300534 */
Theodore Kilgorec260fe92010-01-15 05:54:36 -0300535 switch (gspca_dev->usb_buf[0]) {
Theodore Kilgore930bf782009-10-05 05:11:35 -0300536 case 2:
537 sd->sensor_type = 0;
538 break;
539 case 3:
540 sd->sensor_type = 1;
541 break;
542 default:
Jean-François Moine0b656322010-09-13 05:19:58 -0300543 err("Unknown CIF Sensor id : %02x",
Theodore Kilgore930bf782009-10-05 05:11:35 -0300544 gspca_dev->usb_buf[1]);
545 return -ENODEV;
546 }
547 PDEBUG(D_PROBE, "MR97310A CIF camera detected, sensor: %d",
548 sd->sensor_type);
549 } else {
550 sd->cam_type = CAM_TYPE_VGA;
Hans de Goede5f5e26b2009-08-14 10:40:26 -0300551
Hans de Goede5f5e26b2009-08-14 10:40:26 -0300552 /*
Theodore Kilgorec260fe92010-01-15 05:54:36 -0300553 * Here is a table of the responses to the query for sensor
Theodore Kilgore9d3103d2010-02-09 18:05:25 -0300554 * type, from the known MR97310A VGA cameras. Six different
555 * cameras of which five share the same USB ID.
Theodore Kilgore930bf782009-10-05 05:11:35 -0300556 *
557 * Name gspca_dev->usb_buf[] sd->sensor_type
Theodore Kilgoreb3e440e2009-10-09 03:54:49 -0300558 * sd->do_lcd_stop
559 * Aiptek Pencam VGA+ 0300 0 1
Theodore Kilgore9d3103d2010-02-09 18:05:25 -0300560 * ION digital 0300 0 1
Theodore Kilgoreb3e440e2009-10-09 03:54:49 -0300561 * Argus DC-1620 0450 1 0
562 * Argus QuickClix 0420 1 1
Theodore Kilgore9d3103d2010-02-09 18:05:25 -0300563 * Sakar 77379 Digital 0350 0 1
564 * Sakar 1638x CyberPix 0120 0 2
Theodore Kilgore930bf782009-10-05 05:11:35 -0300565 *
Theodore Kilgoreb3e440e2009-10-09 03:54:49 -0300566 * Based upon these results, we assume default settings
567 * and then correct as necessary, as follows.
Theodore Kilgore930bf782009-10-05 05:11:35 -0300568 *
Hans de Goede5f5e26b2009-08-14 10:40:26 -0300569 */
Hans de Goede5f5e26b2009-08-14 10:40:26 -0300570
Theodore Kilgoreb3e440e2009-10-09 03:54:49 -0300571 sd->sensor_type = 1;
572 sd->do_lcd_stop = 0;
Theodore Kilgore64f4d9a2009-10-30 04:43:39 -0300573 sd->adj_colors = 0;
Theodore Kilgore9d3103d2010-02-09 18:05:25 -0300574 if (gspca_dev->usb_buf[0] == 0x01) {
575 sd->sensor_type = 2;
576 } else if ((gspca_dev->usb_buf[0] != 0x03) &&
Theodore Kilgoreb3e440e2009-10-09 03:54:49 -0300577 (gspca_dev->usb_buf[0] != 0x04)) {
Jean-François Moine0b656322010-09-13 05:19:58 -0300578 err("Unknown VGA Sensor id Byte 0: %02x",
Theodore Kilgore9d3103d2010-02-09 18:05:25 -0300579 gspca_dev->usb_buf[0]);
Jean-François Moine0b656322010-09-13 05:19:58 -0300580 err("Defaults assumed, may not work");
581 err("Please report this");
Theodore Kilgoreb3e440e2009-10-09 03:54:49 -0300582 }
Theodore Kilgore64f4d9a2009-10-30 04:43:39 -0300583 /* Sakar Digital color needs to be adjusted. */
584 if ((gspca_dev->usb_buf[0] == 0x03) &&
585 (gspca_dev->usb_buf[1] == 0x50))
586 sd->adj_colors = 1;
Theodore Kilgoreb3e440e2009-10-09 03:54:49 -0300587 if (gspca_dev->usb_buf[0] == 0x04) {
588 sd->do_lcd_stop = 1;
Theodore Kilgore930bf782009-10-05 05:11:35 -0300589 switch (gspca_dev->usb_buf[1]) {
590 case 0x50:
Theodore Kilgoreb3e440e2009-10-09 03:54:49 -0300591 sd->sensor_type = 0;
592 PDEBUG(D_PROBE, "sensor_type corrected to 0");
Theodore Kilgore930bf782009-10-05 05:11:35 -0300593 break;
594 case 0x20:
Theodore Kilgoreb3e440e2009-10-09 03:54:49 -0300595 /* Nothing to do here. */
Theodore Kilgore930bf782009-10-05 05:11:35 -0300596 break;
597 default:
Jean-François Moine0b656322010-09-13 05:19:58 -0300598 err("Unknown VGA Sensor id Byte 1: %02x",
Theodore Kilgoreb3e440e2009-10-09 03:54:49 -0300599 gspca_dev->usb_buf[1]);
Jean-François Moine0b656322010-09-13 05:19:58 -0300600 err("Defaults assumed, may not work");
601 err("Please report this");
Theodore Kilgore930bf782009-10-05 05:11:35 -0300602 }
Hans de Goede78028702009-09-02 09:55:16 -0300603 }
Theodore Kilgore930bf782009-10-05 05:11:35 -0300604 PDEBUG(D_PROBE, "MR97310A VGA camera detected, sensor: %d",
605 sd->sensor_type);
606 }
Theodore Kilgorec260fe92010-01-15 05:54:36 -0300607 /* Stop streaming as we've started it only to probe the sensor type. */
Theodore Kilgore930bf782009-10-05 05:11:35 -0300608 sd_stopN(gspca_dev);
Hans de Goede78028702009-09-02 09:55:16 -0300609
Theodore Kilgore930bf782009-10-05 05:11:35 -0300610 if (force_sensor_type != -1) {
611 sd->sensor_type = !!force_sensor_type;
612 PDEBUG(D_PROBE, "Forcing sensor type to: %d",
613 sd->sensor_type);
614 }
615
616 /* Setup controls depending on camera type */
617 if (sd->cam_type == CAM_TYPE_CIF) {
618 /* No brightness for sensor_type 0 */
Hans de Goede5f5e26b2009-08-14 10:40:26 -0300619 if (sd->sensor_type == 0)
Theodore Kilgore930bf782009-10-05 05:11:35 -0300620 gspca_dev->ctrl_dis = (1 << NORM_BRIGHTNESS_IDX) |
Theodore Kilgore9d3103d2010-02-09 18:05:25 -0300621 (1 << ARGUS_QC_BRIGHTNESS_IDX) |
622 (1 << CONTRAST_IDX) |
623 (1 << SAKAR_CS_GAIN_IDX);
Theodore Kilgore930bf782009-10-05 05:11:35 -0300624 else
Hans de Goede065b6f72009-10-29 07:42:30 -0300625 gspca_dev->ctrl_dis = (1 << ARGUS_QC_BRIGHTNESS_IDX) |
Theodore Kilgore9d3103d2010-02-09 18:05:25 -0300626 (1 << CONTRAST_IDX) |
627 (1 << SAKAR_CS_GAIN_IDX) |
Hans de Goede065b6f72009-10-29 07:42:30 -0300628 (1 << MIN_CLOCKDIV_IDX);
Hans de Goede9ac69782009-08-14 10:15:52 -0300629 } else {
Theodore Kilgore930bf782009-10-05 05:11:35 -0300630 /* All controls need to be disabled if VGA sensor_type is 0 */
631 if (sd->sensor_type == 0)
632 gspca_dev->ctrl_dis = (1 << NORM_BRIGHTNESS_IDX) |
633 (1 << ARGUS_QC_BRIGHTNESS_IDX) |
634 (1 << EXPOSURE_IDX) |
Hans de Goede065b6f72009-10-29 07:42:30 -0300635 (1 << GAIN_IDX) |
Theodore Kilgore9d3103d2010-02-09 18:05:25 -0300636 (1 << CONTRAST_IDX) |
637 (1 << SAKAR_CS_GAIN_IDX) |
Hans de Goede065b6f72009-10-29 07:42:30 -0300638 (1 << MIN_CLOCKDIV_IDX);
Theodore Kilgore9d3103d2010-02-09 18:05:25 -0300639 else if (sd->sensor_type == 2) {
640 gspca_dev->ctrl_dis = (1 << NORM_BRIGHTNESS_IDX) |
641 (1 << ARGUS_QC_BRIGHTNESS_IDX) |
642 (1 << GAIN_IDX) |
643 (1 << MIN_CLOCKDIV_IDX);
644 gain_default = MR97310A_CS_GAIN_DEFAULT;
645 } else if (sd->do_lcd_stop)
Theodore Kilgore930bf782009-10-05 05:11:35 -0300646 /* Argus QuickClix has different brightness limits */
Theodore Kilgore9d3103d2010-02-09 18:05:25 -0300647 gspca_dev->ctrl_dis = (1 << NORM_BRIGHTNESS_IDX) |
648 (1 << CONTRAST_IDX) |
649 (1 << SAKAR_CS_GAIN_IDX);
Theodore Kilgore930bf782009-10-05 05:11:35 -0300650 else
Theodore Kilgore9d3103d2010-02-09 18:05:25 -0300651 gspca_dev->ctrl_dis = (1 << ARGUS_QC_BRIGHTNESS_IDX) |
652 (1 << CONTRAST_IDX) |
653 (1 << SAKAR_CS_GAIN_IDX);
Theodore Kilgore89f08632009-08-14 06:51:52 -0300654 }
Hans de Goede9ac69782009-08-14 10:15:52 -0300655
656 sd->brightness = MR97310A_BRIGHTNESS_DEFAULT;
657 sd->exposure = MR97310A_EXPOSURE_DEFAULT;
Theodore Kilgore9d3103d2010-02-09 18:05:25 -0300658 sd->gain = gain_default;
659 sd->contrast = MR97310A_CONTRAST_DEFAULT;
Hans de Goede065b6f72009-10-29 07:42:30 -0300660 sd->min_clockdiv = MR97310A_MIN_CLOCKDIV_DEFAULT;
Hans de Goede9ac69782009-08-14 10:15:52 -0300661
Kyle Guinnd661e622009-01-16 05:36:14 -0300662 return 0;
663}
664
665/* this function is called at probe and resume time */
666static int sd_init(struct gspca_dev *gspca_dev)
667{
668 return 0;
669}
670
Theodore Kilgore89f08632009-08-14 06:51:52 -0300671static int start_cif_cam(struct gspca_dev *gspca_dev)
Kyle Guinnd661e622009-01-16 05:36:14 -0300672{
673 struct sd *sd = (struct sd *) gspca_dev;
674 __u8 *data = gspca_dev->usb_buf;
675 int err_code;
Jean-François Moine294d8b42010-10-01 07:37:15 -0300676 static const __u8 startup_string[] = {
Theodore Kilgore89f08632009-08-14 06:51:52 -0300677 0x00,
678 0x0d,
679 0x01,
680 0x00, /* Hsize/8 for 352 or 320 */
681 0x00, /* Vsize/4 for 288 or 240 */
682 0x13, /* or 0xbb, depends on sensor */
683 0x00, /* Hstart, depends on res. */
684 0x00, /* reserved ? */
685 0x00, /* Vstart, depends on res. and sensor */
686 0x50, /* 0x54 to get 176 or 160 */
687 0xc0
688 };
Kyle Guinnd661e622009-01-16 05:36:14 -0300689
Theodore Kilgore89f08632009-08-14 06:51:52 -0300690 /* Note: Some of the above descriptions guessed from MR97113A driver */
Kyle Guinnd661e622009-01-16 05:36:14 -0300691
Theodore Kilgore89f08632009-08-14 06:51:52 -0300692 memcpy(data, startup_string, 11);
693 if (sd->sensor_type)
694 data[5] = 0xbb;
695
696 switch (gspca_dev->width) {
697 case 160:
698 data[9] |= 0x04; /* reg 8, 2:1 scale down from 320 */
699 /* fall thru */
700 case 320:
701 default:
702 data[3] = 0x28; /* reg 2, H size/8 */
703 data[4] = 0x3c; /* reg 3, V size/4 */
704 data[6] = 0x14; /* reg 5, H start */
705 data[8] = 0x1a + sd->sensor_type; /* reg 7, V start */
706 break;
707 case 176:
708 data[9] |= 0x04; /* reg 8, 2:1 scale down from 352 */
709 /* fall thru */
710 case 352:
711 data[3] = 0x2c; /* reg 2, H size/8 */
712 data[4] = 0x48; /* reg 3, V size/4 */
713 data[6] = 0x06; /* reg 5, H start */
Theodore Kilgore32345b02009-11-01 12:59:42 -0300714 data[8] = 0x06 - sd->sensor_type; /* reg 7, V start */
Theodore Kilgore89f08632009-08-14 06:51:52 -0300715 break;
716 }
717 err_code = mr_write(gspca_dev, 11);
718 if (err_code < 0)
719 return err_code;
720
721 if (!sd->sensor_type) {
Jean-François Moine294d8b42010-10-01 07:37:15 -0300722 static const struct sensor_w_data cif_sensor0_init_data[] = {
Theodore Kilgore89f08632009-08-14 06:51:52 -0300723 {0x02, 0x00, {0x03, 0x5a, 0xb5, 0x01,
724 0x0f, 0x14, 0x0f, 0x10}, 8},
725 {0x0c, 0x00, {0x04, 0x01, 0x01, 0x00, 0x1f}, 5},
726 {0x12, 0x00, {0x07}, 1},
727 {0x1f, 0x00, {0x06}, 1},
728 {0x27, 0x00, {0x04}, 1},
729 {0x29, 0x00, {0x0c}, 1},
730 {0x40, 0x00, {0x40, 0x00, 0x04}, 3},
731 {0x50, 0x00, {0x60}, 1},
732 {0x60, 0x00, {0x06}, 1},
733 {0x6b, 0x00, {0x85, 0x85, 0xc8, 0xc8, 0xc8, 0xc8}, 6},
734 {0x72, 0x00, {0x1e, 0x56}, 2},
735 {0x75, 0x00, {0x58, 0x40, 0xa2, 0x02, 0x31, 0x02,
736 0x31, 0x80, 0x00}, 9},
737 {0x11, 0x00, {0x01}, 1},
738 {0, 0, {0}, 0}
739 };
740 err_code = sensor_write_regs(gspca_dev, cif_sensor0_init_data,
741 ARRAY_SIZE(cif_sensor0_init_data));
742 } else { /* sd->sensor_type = 1 */
Jean-François Moine294d8b42010-10-01 07:37:15 -0300743 static const struct sensor_w_data cif_sensor1_init_data[] = {
Hans de Goede9ac69782009-08-14 10:15:52 -0300744 /* Reg 3,4, 7,8 get set by the controls */
Theodore Kilgore89f08632009-08-14 06:51:52 -0300745 {0x02, 0x00, {0x10}, 1},
Hans de Goede9ac69782009-08-14 10:15:52 -0300746 {0x05, 0x01, {0x22}, 1}, /* 5/6 also seen as 65h/32h */
747 {0x06, 0x01, {0x00}, 1},
Theodore Kilgore89f08632009-08-14 06:51:52 -0300748 {0x09, 0x02, {0x0e}, 1},
749 {0x0a, 0x02, {0x05}, 1},
750 {0x0b, 0x02, {0x05}, 1},
751 {0x0c, 0x02, {0x0f}, 1},
Hans de Goede9ac69782009-08-14 10:15:52 -0300752 {0x0d, 0x02, {0x07}, 1},
Theodore Kilgore89f08632009-08-14 06:51:52 -0300753 {0x0e, 0x02, {0x0c}, 1},
754 {0x0f, 0x00, {0x00}, 1},
755 {0x10, 0x00, {0x06}, 1},
756 {0x11, 0x00, {0x07}, 1},
757 {0x12, 0x00, {0x00}, 1},
758 {0x13, 0x00, {0x01}, 1},
759 {0, 0, {0}, 0}
760 };
Theodore Kilgore70136082009-12-25 05:15:10 -0300761 /* Without this command the cam won't work with USB-UHCI */
762 gspca_dev->usb_buf[0] = 0x0a;
763 gspca_dev->usb_buf[1] = 0x00;
764 err_code = mr_write(gspca_dev, 2);
765 if (err_code < 0)
766 return err_code;
Theodore Kilgore89f08632009-08-14 06:51:52 -0300767 err_code = sensor_write_regs(gspca_dev, cif_sensor1_init_data,
768 ARRAY_SIZE(cif_sensor1_init_data));
769 }
Theodore Kilgore930bf782009-10-05 05:11:35 -0300770 return err_code;
Theodore Kilgore89f08632009-08-14 06:51:52 -0300771}
772
773static int start_vga_cam(struct gspca_dev *gspca_dev)
774{
775 struct sd *sd = (struct sd *) gspca_dev;
776 __u8 *data = gspca_dev->usb_buf;
777 int err_code;
Jean-François Moine294d8b42010-10-01 07:37:15 -0300778 static const __u8 startup_string[] =
779 {0x00, 0x0d, 0x01, 0x00, 0x00, 0x2b, 0x00, 0x00,
780 0x00, 0x50, 0xc0};
Theodore Kilgore89f08632009-08-14 06:51:52 -0300781 /* What some of these mean is explained in start_cif_cam(), above */
Theodore Kilgore89f08632009-08-14 06:51:52 -0300782
Theodore Kilgore89f08632009-08-14 06:51:52 -0300783 memcpy(data, startup_string, 11);
784 if (!sd->sensor_type) {
785 data[5] = 0x00;
786 data[10] = 0x91;
787 }
Theodore Kilgore9d3103d2010-02-09 18:05:25 -0300788 if (sd->sensor_type == 2) {
789 data[5] = 0x00;
790 data[10] = 0x18;
791 }
Kyle Guinnd661e622009-01-16 05:36:14 -0300792
793 switch (gspca_dev->width) {
794 case 160:
795 data[9] |= 0x0c; /* reg 8, 4:1 scale down */
796 /* fall thru */
797 case 320:
798 data[9] |= 0x04; /* reg 8, 2:1 scale down */
799 /* fall thru */
800 case 640:
801 default:
Theodore Kilgore89f08632009-08-14 06:51:52 -0300802 data[3] = 0x50; /* reg 2, H size/8 */
803 data[4] = 0x78; /* reg 3, V size/4 */
Kyle Guinnd661e622009-01-16 05:36:14 -0300804 data[6] = 0x04; /* reg 5, H start */
805 data[8] = 0x03; /* reg 7, V start */
Theodore Kilgore9d3103d2010-02-09 18:05:25 -0300806 if (sd->sensor_type == 2) {
807 data[6] = 2;
808 data[8] = 1;
809 }
Theodore Kilgore89f08632009-08-14 06:51:52 -0300810 if (sd->do_lcd_stop)
811 data[8] = 0x04; /* Bayer tile shifted */
Kyle Guinnd661e622009-01-16 05:36:14 -0300812 break;
813
814 case 176:
815 data[9] |= 0x04; /* reg 8, 2:1 scale down */
816 /* fall thru */
817 case 352:
818 data[3] = 0x2c; /* reg 2, H size */
819 data[4] = 0x48; /* reg 3, V size */
820 data[6] = 0x94; /* reg 5, H start */
821 data[8] = 0x63; /* reg 7, V start */
Theodore Kilgore89f08632009-08-14 06:51:52 -0300822 if (sd->do_lcd_stop)
823 data[8] = 0x64; /* Bayer tile shifted */
Kyle Guinnd661e622009-01-16 05:36:14 -0300824 break;
825 }
826
Theodore Kilgore89f08632009-08-14 06:51:52 -0300827 err_code = mr_write(gspca_dev, 11);
Kyle Guinnd661e622009-01-16 05:36:14 -0300828 if (err_code < 0)
829 return err_code;
830
Theodore Kilgore89f08632009-08-14 06:51:52 -0300831 if (!sd->sensor_type) {
Jean-François Moine294d8b42010-10-01 07:37:15 -0300832 static const struct sensor_w_data vga_sensor0_init_data[] = {
Theodore Kilgore89f08632009-08-14 06:51:52 -0300833 {0x01, 0x00, {0x0c, 0x00, 0x04}, 3},
834 {0x14, 0x00, {0x01, 0xe4, 0x02, 0x84}, 4},
835 {0x20, 0x00, {0x00, 0x80, 0x00, 0x08}, 4},
836 {0x25, 0x00, {0x03, 0xa9, 0x80}, 3},
837 {0x30, 0x00, {0x30, 0x18, 0x10, 0x18}, 4},
838 {0, 0, {0}, 0}
839 };
840 err_code = sensor_write_regs(gspca_dev, vga_sensor0_init_data,
841 ARRAY_SIZE(vga_sensor0_init_data));
Theodore Kilgore9d3103d2010-02-09 18:05:25 -0300842 } else if (sd->sensor_type == 1) {
Jean-François Moine294d8b42010-10-01 07:37:15 -0300843 static const struct sensor_w_data color_adj[] = {
Theodore Kilgore89f08632009-08-14 06:51:52 -0300844 {0x02, 0x00, {0x06, 0x59, 0x0c, 0x16, 0x00,
Theodore Kilgore64f4d9a2009-10-30 04:43:39 -0300845 /* adjusted blue, green, red gain correct
846 too much blue from the Sakar Digital */
Theodore Kilgoreb31210d2009-11-01 13:02:59 -0300847 0x05, 0x01, 0x04}, 8}
Theodore Kilgore64f4d9a2009-10-30 04:43:39 -0300848 };
849
Jean-François Moine294d8b42010-10-01 07:37:15 -0300850 static const struct sensor_w_data color_no_adj[] = {
Theodore Kilgore64f4d9a2009-10-30 04:43:39 -0300851 {0x02, 0x00, {0x06, 0x59, 0x0c, 0x16, 0x00,
852 /* default blue, green, red gain settings */
853 0x07, 0x00, 0x01}, 8}
854 };
855
Jean-François Moine294d8b42010-10-01 07:37:15 -0300856 static const struct sensor_w_data vga_sensor1_init_data[] = {
Theodore Kilgore89f08632009-08-14 06:51:52 -0300857 {0x11, 0x04, {0x01}, 1},
Theodore Kilgore542821d2009-11-01 13:09:15 -0300858 {0x0a, 0x00, {0x00, 0x01, 0x00, 0x00, 0x01,
859 /* These settings may be better for some cameras */
860 /* {0x0a, 0x00, {0x01, 0x06, 0x00, 0x00, 0x01, */
Theodore Kilgore89f08632009-08-14 06:51:52 -0300861 0x00, 0x0a}, 7},
862 {0x11, 0x04, {0x01}, 1},
863 {0x12, 0x00, {0x00, 0x63, 0x00, 0x70, 0x00, 0x00}, 6},
864 {0x11, 0x04, {0x01}, 1},
865 {0, 0, {0}, 0}
866 };
Theodore Kilgore64f4d9a2009-10-30 04:43:39 -0300867
868 if (sd->adj_colors)
869 err_code = sensor_write_regs(gspca_dev, color_adj,
870 ARRAY_SIZE(color_adj));
871 else
872 err_code = sensor_write_regs(gspca_dev, color_no_adj,
873 ARRAY_SIZE(color_no_adj));
874
875 if (err_code < 0)
876 return err_code;
877
Theodore Kilgore89f08632009-08-14 06:51:52 -0300878 err_code = sensor_write_regs(gspca_dev, vga_sensor1_init_data,
879 ARRAY_SIZE(vga_sensor1_init_data));
Theodore Kilgore9d3103d2010-02-09 18:05:25 -0300880 } else { /* sensor type == 2 */
Jean-François Moine294d8b42010-10-01 07:37:15 -0300881 static const struct sensor_w_data vga_sensor2_init_data[] = {
Theodore Kilgore9d3103d2010-02-09 18:05:25 -0300882
883 {0x01, 0x00, {0x48}, 1},
884 {0x02, 0x00, {0x22}, 1},
885 /* Reg 3 msb and 4 is lsb of the exposure setting*/
886 {0x05, 0x00, {0x10}, 1},
887 {0x06, 0x00, {0x00}, 1},
888 {0x07, 0x00, {0x00}, 1},
889 {0x08, 0x00, {0x00}, 1},
890 {0x09, 0x00, {0x00}, 1},
891 /* The following are used in the gain control
892 * which is BTW completely borked in the OEM driver
893 * The values for each color go from 0 to 0x7ff
894 *{0x0a, 0x00, {0x01}, 1}, green1 gain msb
895 *{0x0b, 0x00, {0x10}, 1}, green1 gain lsb
896 *{0x0c, 0x00, {0x01}, 1}, red gain msb
897 *{0x0d, 0x00, {0x10}, 1}, red gain lsb
898 *{0x0e, 0x00, {0x01}, 1}, blue gain msb
899 *{0x0f, 0x00, {0x10}, 1}, blue gain lsb
900 *{0x10, 0x00, {0x01}, 1}, green2 gain msb
901 *{0x11, 0x00, {0x10}, 1}, green2 gain lsb
902 */
903 {0x12, 0x00, {0x00}, 1},
904 {0x13, 0x00, {0x04}, 1}, /* weird effect on colors */
905 {0x14, 0x00, {0x00}, 1},
906 {0x15, 0x00, {0x06}, 1},
907 {0x16, 0x00, {0x01}, 1},
908 {0x17, 0x00, {0xe2}, 1}, /* vertical alignment */
909 {0x18, 0x00, {0x02}, 1},
910 {0x19, 0x00, {0x82}, 1}, /* don't mess with */
911 {0x1a, 0x00, {0x00}, 1},
912 {0x1b, 0x00, {0x20}, 1},
913 /* {0x1c, 0x00, {0x17}, 1}, contrast control */
914 {0x1d, 0x00, {0x80}, 1}, /* moving causes a mess */
915 {0x1e, 0x00, {0x08}, 1}, /* moving jams the camera */
916 {0x1f, 0x00, {0x0c}, 1},
917 {0x20, 0x00, {0x00}, 1},
918 {0, 0, {0}, 0}
919 };
920 err_code = sensor_write_regs(gspca_dev, vga_sensor2_init_data,
921 ARRAY_SIZE(vga_sensor2_init_data));
Theodore Kilgore89f08632009-08-14 06:51:52 -0300922 }
Theodore Kilgore89f08632009-08-14 06:51:52 -0300923 return err_code;
924}
925
926static int sd_start(struct gspca_dev *gspca_dev)
927{
928 struct sd *sd = (struct sd *) gspca_dev;
929 int err_code;
Theodore Kilgore89f08632009-08-14 06:51:52 -0300930
Theodore Kilgore89f08632009-08-14 06:51:52 -0300931 sd->sof_read = 0;
Theodore Kilgore930bf782009-10-05 05:11:35 -0300932
933 /* Some of the VGA cameras require the memory pointer
934 * to be set to 0 again. We have been forced to start the
Theodore Kilgoreb4b84de2009-11-01 13:07:08 -0300935 * stream in sd_config() to detect the hardware, and closed it.
936 * Thus, we need here to do a completely fresh and clean start. */
Theodore Kilgore930bf782009-10-05 05:11:35 -0300937 err_code = zero_the_pointer(gspca_dev);
938 if (err_code < 0)
939 return err_code;
940
941 err_code = stream_start(gspca_dev);
942 if (err_code < 0)
943 return err_code;
944
Theodore Kilgore89f08632009-08-14 06:51:52 -0300945 if (sd->cam_type == CAM_TYPE_CIF) {
Theodore Kilgore89f08632009-08-14 06:51:52 -0300946 err_code = start_cif_cam(gspca_dev);
947 } else {
Theodore Kilgore89f08632009-08-14 06:51:52 -0300948 err_code = start_vga_cam(gspca_dev);
949 }
Theodore Kilgore930bf782009-10-05 05:11:35 -0300950 if (err_code < 0)
951 return err_code;
952
953 setbrightness(gspca_dev);
Theodore Kilgore9d3103d2010-02-09 18:05:25 -0300954 setcontrast(gspca_dev);
Theodore Kilgore930bf782009-10-05 05:11:35 -0300955 setexposure(gspca_dev);
956 setgain(gspca_dev);
957
958 return isoc_enable(gspca_dev);
Kyle Guinnd661e622009-01-16 05:36:14 -0300959}
960
961static void sd_stopN(struct gspca_dev *gspca_dev)
962{
Theodore Kilgore89f08632009-08-14 06:51:52 -0300963 struct sd *sd = (struct sd *) gspca_dev;
Kyle Guinnd661e622009-01-16 05:36:14 -0300964
Theodore Kilgore930bf782009-10-05 05:11:35 -0300965 stream_stop(gspca_dev);
Theodore Kilgore89f08632009-08-14 06:51:52 -0300966 /* Not all the cams need this, but even if not, probably a good idea */
967 zero_the_pointer(gspca_dev);
Theodore Kilgore930bf782009-10-05 05:11:35 -0300968 if (sd->do_lcd_stop)
969 lcd_stop(gspca_dev);
Theodore Kilgore89f08632009-08-14 06:51:52 -0300970}
971
972static void setbrightness(struct gspca_dev *gspca_dev)
973{
974 struct sd *sd = (struct sd *) gspca_dev;
975 u8 val;
Theodore Kilgore930bf782009-10-05 05:11:35 -0300976 u8 sign_reg = 7; /* This reg and the next one used on CIF cams. */
977 u8 value_reg = 8; /* VGA cams seem to use regs 0x0b and 0x0c */
Jean-François Moine294d8b42010-10-01 07:37:15 -0300978 static const u8 quick_clix_table[] =
Theodore Kilgore930bf782009-10-05 05:11:35 -0300979 /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */
980 { 0, 4, 8, 12, 1, 2, 3, 5, 6, 9, 7, 10, 13, 11, 14, 15};
981 /*
982 * This control is disabled for CIF type 1 and VGA type 0 cameras.
983 * It does not quite act linearly for the Argus QuickClix camera,
984 * but it does control brightness. The values are 0 - 15 only, and
985 * the table above makes them act consecutively.
986 */
987 if ((gspca_dev->ctrl_dis & (1 << NORM_BRIGHTNESS_IDX)) &&
988 (gspca_dev->ctrl_dis & (1 << ARGUS_QC_BRIGHTNESS_IDX)))
Hans de Goede9ac69782009-08-14 10:15:52 -0300989 return;
990
Theodore Kilgore930bf782009-10-05 05:11:35 -0300991 if (sd->cam_type == CAM_TYPE_VGA) {
992 sign_reg += 4;
993 value_reg += 4;
994 }
995
Theodore Kilgoreb4b84de2009-11-01 13:07:08 -0300996 /* Note register 7 is also seen as 0x8x or 0xCx in some dumps */
Theodore Kilgore89f08632009-08-14 06:51:52 -0300997 if (sd->brightness > 0) {
Theodore Kilgore930bf782009-10-05 05:11:35 -0300998 sensor_write1(gspca_dev, sign_reg, 0x00);
Theodore Kilgore89f08632009-08-14 06:51:52 -0300999 val = sd->brightness;
1000 } else {
Theodore Kilgore930bf782009-10-05 05:11:35 -03001001 sensor_write1(gspca_dev, sign_reg, 0x01);
1002 val = (257 - sd->brightness);
Theodore Kilgore89f08632009-08-14 06:51:52 -03001003 }
Theodore Kilgore930bf782009-10-05 05:11:35 -03001004 /* Use lookup table for funky Argus QuickClix brightness */
1005 if (sd->do_lcd_stop)
1006 val = quick_clix_table[val];
1007
1008 sensor_write1(gspca_dev, value_reg, val);
Theodore Kilgore89f08632009-08-14 06:51:52 -03001009}
1010
1011static void setexposure(struct gspca_dev *gspca_dev)
1012{
1013 struct sd *sd = (struct sd *) gspca_dev;
Theodore Kilgore9d3103d2010-02-09 18:05:25 -03001014 int exposure = MR97310A_EXPOSURE_DEFAULT;
Hans de Goede065b6f72009-10-29 07:42:30 -03001015 u8 buf[2];
Theodore Kilgore89f08632009-08-14 06:51:52 -03001016
Hans de Goede9ac69782009-08-14 10:15:52 -03001017 if (gspca_dev->ctrl_dis & (1 << EXPOSURE_IDX))
1018 return;
1019
Theodore Kilgore930bf782009-10-05 05:11:35 -03001020 if (sd->cam_type == CAM_TYPE_CIF && sd->sensor_type == 1) {
Theodore Kilgoreb4b84de2009-11-01 13:07:08 -03001021 /* This cam does not like exposure settings < 300,
Hans de Goeded76f9752009-10-11 05:22:29 -03001022 so scale 0 - 4095 to 300 - 4095 */
1023 exposure = (sd->exposure * 9267) / 10000 + 300;
Theodore Kilgore930bf782009-10-05 05:11:35 -03001024 sensor_write1(gspca_dev, 3, exposure >> 4);
1025 sensor_write1(gspca_dev, 4, exposure & 0x0f);
Theodore Kilgore9d3103d2010-02-09 18:05:25 -03001026 } else if (sd->sensor_type == 2) {
1027 exposure = sd->exposure;
1028 exposure >>= 3;
1029 sensor_write1(gspca_dev, 3, exposure >> 8);
1030 sensor_write1(gspca_dev, 4, exposure & 0xff);
Hans de Goedea2e081b2009-08-14 17:11:36 -03001031 } else {
Hans de Goedea2e081b2009-08-14 17:11:36 -03001032 /* We have both a clock divider and an exposure register.
1033 We first calculate the clock divider, as that determines
Theodore Kilgoreb4b84de2009-11-01 13:07:08 -03001034 the maximum exposure and then we calculate the exposure
Hans de Goedea2e081b2009-08-14 17:11:36 -03001035 register setting (which goes from 0 - 511).
1036
1037 Note our 0 - 4095 exposure is mapped to 0 - 511
1038 milliseconds exposure time */
Theodore Kilgore930bf782009-10-05 05:11:35 -03001039 u8 clockdiv = (60 * sd->exposure + 7999) / 8000;
Hans de Goedea2e081b2009-08-14 17:11:36 -03001040
1041 /* Limit framerate to not exceed usb bandwidth */
Hans de Goede065b6f72009-10-29 07:42:30 -03001042 if (clockdiv < sd->min_clockdiv && gspca_dev->width >= 320)
1043 clockdiv = sd->min_clockdiv;
Hans de Goedea2e081b2009-08-14 17:11:36 -03001044 else if (clockdiv < 2)
1045 clockdiv = 2;
1046
Theodore Kilgore930bf782009-10-05 05:11:35 -03001047 if (sd->cam_type == CAM_TYPE_VGA && clockdiv < 4)
1048 clockdiv = 4;
1049
Hans de Goedea2e081b2009-08-14 17:11:36 -03001050 /* Frame exposure time in ms = 1000 * clockdiv / 60 ->
1051 exposure = (sd->exposure / 8) * 511 / (1000 * clockdiv / 60) */
1052 exposure = (60 * 511 * sd->exposure) / (8000 * clockdiv);
1053 if (exposure > 511)
1054 exposure = 511;
1055
1056 /* exposure register value is reversed! */
1057 exposure = 511 - exposure;
1058
Hans de Goede065b6f72009-10-29 07:42:30 -03001059 buf[0] = exposure & 0xff;
1060 buf[1] = exposure >> 8;
1061 sensor_write_reg(gspca_dev, 0x0e, 0, buf, 2);
Hans de Goedea2e081b2009-08-14 17:11:36 -03001062 sensor_write1(gspca_dev, 0x02, clockdiv);
Hans de Goedea2e081b2009-08-14 17:11:36 -03001063 }
Theodore Kilgore89f08632009-08-14 06:51:52 -03001064}
1065
1066static void setgain(struct gspca_dev *gspca_dev)
1067{
1068 struct sd *sd = (struct sd *) gspca_dev;
Theodore Kilgore9d3103d2010-02-09 18:05:25 -03001069 u8 gainreg;
Theodore Kilgore89f08632009-08-14 06:51:52 -03001070
Theodore Kilgore9d3103d2010-02-09 18:05:25 -03001071 if ((gspca_dev->ctrl_dis & (1 << GAIN_IDX)) &&
1072 (gspca_dev->ctrl_dis & (1 << SAKAR_CS_GAIN_IDX)))
Hans de Goede9ac69782009-08-14 10:15:52 -03001073 return;
1074
Theodore Kilgore9d3103d2010-02-09 18:05:25 -03001075 if (sd->cam_type == CAM_TYPE_CIF && sd->sensor_type == 1)
Hans de Goede823902d2009-08-17 12:25:17 -03001076 sensor_write1(gspca_dev, 0x0e, sd->gain);
Theodore Kilgore9d3103d2010-02-09 18:05:25 -03001077 else if (sd->cam_type == CAM_TYPE_VGA && sd->sensor_type == 2)
1078 for (gainreg = 0x0a; gainreg < 0x11; gainreg += 2) {
1079 sensor_write1(gspca_dev, gainreg, sd->gain >> 8);
1080 sensor_write1(gspca_dev, gainreg + 1, sd->gain & 0xff);
1081 }
1082 else
Hans de Goedea2e081b2009-08-14 17:11:36 -03001083 sensor_write1(gspca_dev, 0x10, sd->gain);
Theodore Kilgore89f08632009-08-14 06:51:52 -03001084}
1085
Theodore Kilgore9d3103d2010-02-09 18:05:25 -03001086static void setcontrast(struct gspca_dev *gspca_dev)
1087{
1088 struct sd *sd = (struct sd *) gspca_dev;
1089
1090 if (gspca_dev->ctrl_dis & (1 << CONTRAST_IDX))
1091 return;
1092
1093 sensor_write1(gspca_dev, 0x1c, sd->contrast);
1094}
1095
1096
Theodore Kilgore89f08632009-08-14 06:51:52 -03001097static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
1098{
1099 struct sd *sd = (struct sd *) gspca_dev;
1100
1101 sd->brightness = val;
1102 if (gspca_dev->streaming)
1103 setbrightness(gspca_dev);
1104 return 0;
1105}
1106
1107static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
1108{
1109 struct sd *sd = (struct sd *) gspca_dev;
1110
1111 *val = sd->brightness;
1112 return 0;
1113}
1114
1115static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
1116{
1117 struct sd *sd = (struct sd *) gspca_dev;
1118
1119 sd->exposure = val;
1120 if (gspca_dev->streaming)
1121 setexposure(gspca_dev);
1122 return 0;
1123}
1124
1125static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
1126{
1127 struct sd *sd = (struct sd *) gspca_dev;
1128
1129 *val = sd->exposure;
1130 return 0;
1131}
1132
1133static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
1134{
1135 struct sd *sd = (struct sd *) gspca_dev;
1136
1137 sd->gain = val;
1138 if (gspca_dev->streaming)
1139 setgain(gspca_dev);
1140 return 0;
1141}
1142
1143static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
1144{
1145 struct sd *sd = (struct sd *) gspca_dev;
1146
1147 *val = sd->gain;
1148 return 0;
Kyle Guinnd661e622009-01-16 05:36:14 -03001149}
1150
Theodore Kilgore9d3103d2010-02-09 18:05:25 -03001151static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
1152{
1153 struct sd *sd = (struct sd *) gspca_dev;
1154
1155 sd->contrast = val;
1156 if (gspca_dev->streaming)
1157 setcontrast(gspca_dev);
1158 return 0;
1159}
1160
1161
1162static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
1163{
1164 struct sd *sd = (struct sd *) gspca_dev;
1165
1166 *val = sd->contrast;
1167 return 0;
1168}
1169
Hans de Goede065b6f72009-10-29 07:42:30 -03001170static int sd_setmin_clockdiv(struct gspca_dev *gspca_dev, __s32 val)
1171{
1172 struct sd *sd = (struct sd *) gspca_dev;
1173
1174 sd->min_clockdiv = val;
1175 if (gspca_dev->streaming)
1176 setexposure(gspca_dev);
1177 return 0;
1178}
1179
1180static int sd_getmin_clockdiv(struct gspca_dev *gspca_dev, __s32 *val)
1181{
1182 struct sd *sd = (struct sd *) gspca_dev;
1183
1184 *val = sd->min_clockdiv;
1185 return 0;
1186}
1187
Kyle Guinnd661e622009-01-16 05:36:14 -03001188/* Include pac common sof detection functions */
1189#include "pac_common.h"
1190
1191static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03001192 u8 *data, /* isoc packet */
1193 int len) /* iso packet length */
Kyle Guinnd661e622009-01-16 05:36:14 -03001194{
Marton Nemetha6b69e42009-11-02 08:05:51 -03001195 struct sd *sd = (struct sd *) gspca_dev;
Kyle Guinnd661e622009-01-16 05:36:14 -03001196 unsigned char *sof;
1197
Marton Nemetha6b69e42009-11-02 08:05:51 -03001198 sof = pac_find_sof(&sd->sof_read, data, len);
Kyle Guinnd661e622009-01-16 05:36:14 -03001199 if (sof) {
1200 int n;
1201
1202 /* finish decoding current frame */
1203 n = sof - data;
1204 if (n > sizeof pac_sof_marker)
1205 n -= sizeof pac_sof_marker;
1206 else
1207 n = 0;
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03001208 gspca_frame_add(gspca_dev, LAST_PACKET,
Kyle Guinnd661e622009-01-16 05:36:14 -03001209 data, n);
Theodore Kilgore9832d762009-03-13 13:04:31 -03001210 /* Start next frame. */
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03001211 gspca_frame_add(gspca_dev, FIRST_PACKET,
Theodore Kilgore9832d762009-03-13 13:04:31 -03001212 pac_sof_marker, sizeof pac_sof_marker);
Kyle Guinnd661e622009-01-16 05:36:14 -03001213 len -= sof - data;
1214 data = sof;
1215 }
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03001216 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Kyle Guinnd661e622009-01-16 05:36:14 -03001217}
1218
1219/* sub-driver description */
1220static const struct sd_desc sd_desc = {
1221 .name = MODULE_NAME,
1222 .ctrls = sd_ctrls,
1223 .nctrls = ARRAY_SIZE(sd_ctrls),
1224 .config = sd_config,
1225 .init = sd_init,
1226 .start = sd_start,
1227 .stopN = sd_stopN,
1228 .pkt_scan = sd_pkt_scan,
1229};
1230
1231/* -- module initialisation -- */
Jean-François Moine95c967c2011-01-13 05:20:29 -03001232static const struct usb_device_id device_table[] = {
Aurelien Jacobs8ac246c2009-10-29 07:45:24 -03001233 {USB_DEVICE(0x08ca, 0x0110)}, /* Trust Spyc@m 100 */
Theodore Kilgore89f08632009-08-14 06:51:52 -03001234 {USB_DEVICE(0x08ca, 0x0111)}, /* Aiptek Pencam VGA+ */
1235 {USB_DEVICE(0x093a, 0x010f)}, /* All other known MR97310A VGA cams */
1236 {USB_DEVICE(0x093a, 0x010e)}, /* All known MR97310A CIF cams */
Kyle Guinnd661e622009-01-16 05:36:14 -03001237 {}
1238};
1239MODULE_DEVICE_TABLE(usb, device_table);
1240
1241/* -- device connect -- */
1242static int sd_probe(struct usb_interface *intf,
1243 const struct usb_device_id *id)
1244{
1245 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1246 THIS_MODULE);
1247}
1248
1249static struct usb_driver sd_driver = {
1250 .name = MODULE_NAME,
1251 .id_table = device_table,
1252 .probe = sd_probe,
1253 .disconnect = gspca_disconnect,
1254#ifdef CONFIG_PM
1255 .suspend = gspca_suspend,
1256 .resume = gspca_resume,
1257#endif
1258};
1259
1260/* -- module insert / remove -- */
1261static int __init sd_mod_init(void)
1262{
Jean-François Moine54826432010-09-13 04:53:03 -03001263 return usb_register(&sd_driver);
Kyle Guinnd661e622009-01-16 05:36:14 -03001264}
1265static void __exit sd_mod_exit(void)
1266{
1267 usb_deregister(&sd_driver);
Kyle Guinnd661e622009-01-16 05:36:14 -03001268}
1269
1270module_init(sd_mod_init);
1271module_exit(sd_mod_exit);