• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/drivers/media/video/gspca/
1/*
2 *		Pixart PAC7302 library
3 *		Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
4 *
5 * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
6 *
7 * Separated from Pixart PAC7311 library by M��rton N��meth
8 * Camera button input handling by M��rton N��meth <nm127@freemail.hu>
9 * Copyright (C) 2009-2010 M��rton N��meth <nm127@freemail.hu>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
26/* Some documentation about various registers as determined by trial and error.
27
28   Register page 1:
29
30   Address	Description
31   0x78		Global control, bit 6 controls the LED (inverted)
32
33   Register page 3:
34
35   Address	Description
36   0x02		Clock divider 3-63, fps = 90 / val. Must be a multiple of 3 on
37		the 7302, so one of 3, 6, 9, ..., except when between 6 and 12?
38   0x03		Variable framerate ctrl reg2==3: 0 -> ~30 fps, 255 -> ~22fps
39   0x04		Another var framerate ctrl reg2==3, reg3==0: 0 -> ~30 fps,
40		63 -> ~27 fps, the 2 msb's must always be 1 !!
41   0x05		Another var framerate ctrl reg2==3, reg3==0, reg4==0xc0:
42		1 -> ~30 fps, 2 -> ~20 fps
43   0x0e		Exposure bits 0-7, 0-448, 0 = use full frame time
44   0x0f		Exposure bit 8, 0-448, 448 = no exposure at all
45   0x10		Master gain 0-31
46   0x21		Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused
47
48   The registers are accessed in the following functions:
49
50   Page | Register   | Function
51   -----+------------+---------------------------------------------------
52    0   | 0x0f..0x20 | setcolors()
53    0   | 0xa2..0xab | setbrightcont()
54    0   | 0xc5       | setredbalance()
55    0   | 0xc6       | setwhitebalance()
56    0   | 0xc7       | setbluebalance()
57    0   | 0xdc       | setbrightcont(), setcolors()
58    3   | 0x02       | setexposure()
59    3   | 0x10       | setgain()
60    3   | 0x11       | setcolors(), setgain(), setexposure(), sethvflip()
61    3   | 0x21       | sethvflip()
62*/
63
64#define MODULE_NAME "pac7302"
65
66#include <linux/input.h>
67#include <media/v4l2-chip-ident.h>
68#include "gspca.h"
69
70MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li");
71MODULE_DESCRIPTION("Pixart PAC7302");
72MODULE_LICENSE("GPL");
73
74/* specific webcam descriptor for pac7302 */
75struct sd {
76	struct gspca_dev gspca_dev;		/* !! must be the first item */
77
78	unsigned char brightness;
79	unsigned char contrast;
80	unsigned char colors;
81	unsigned char white_balance;
82	unsigned char red_balance;
83	unsigned char blue_balance;
84	unsigned char gain;
85	unsigned char autogain;
86	unsigned short exposure;
87	__u8 hflip;
88	__u8 vflip;
89	u8 flags;
90#define FL_HFLIP 0x01		/* mirrored by default */
91#define FL_VFLIP 0x02		/* vertical flipped by default */
92
93	u8 sof_read;
94	u8 autogain_ignore_frames;
95
96	atomic_t avg_lum;
97};
98
99/* V4L2 controls supported by the driver */
100static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
101static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
102static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
103static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
104static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
105static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
106static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val);
107static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val);
108static int sd_setredbalance(struct gspca_dev *gspca_dev, __s32 val);
109static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val);
110static int sd_setbluebalance(struct gspca_dev *gspca_dev, __s32 val);
111static int sd_getbluebalance(struct gspca_dev *gspca_dev, __s32 *val);
112static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
113static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
114static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
115static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
116static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
117static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
118static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
119static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
120static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
121static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
122
123static const struct ctrl sd_ctrls[] = {
124	{
125	    {
126		.id      = V4L2_CID_BRIGHTNESS,
127		.type    = V4L2_CTRL_TYPE_INTEGER,
128		.name    = "Brightness",
129		.minimum = 0,
130#define BRIGHTNESS_MAX 0x20
131		.maximum = BRIGHTNESS_MAX,
132		.step    = 1,
133#define BRIGHTNESS_DEF 0x10
134		.default_value = BRIGHTNESS_DEF,
135	    },
136	    .set = sd_setbrightness,
137	    .get = sd_getbrightness,
138	},
139	{
140	    {
141		.id      = V4L2_CID_CONTRAST,
142		.type    = V4L2_CTRL_TYPE_INTEGER,
143		.name    = "Contrast",
144		.minimum = 0,
145#define CONTRAST_MAX 255
146		.maximum = CONTRAST_MAX,
147		.step    = 1,
148#define CONTRAST_DEF 127
149		.default_value = CONTRAST_DEF,
150	    },
151	    .set = sd_setcontrast,
152	    .get = sd_getcontrast,
153	},
154	{
155	    {
156		.id      = V4L2_CID_SATURATION,
157		.type    = V4L2_CTRL_TYPE_INTEGER,
158		.name    = "Saturation",
159		.minimum = 0,
160#define COLOR_MAX 255
161		.maximum = COLOR_MAX,
162		.step    = 1,
163#define COLOR_DEF 127
164		.default_value = COLOR_DEF,
165	    },
166	    .set = sd_setcolors,
167	    .get = sd_getcolors,
168	},
169	{
170	    {
171		.id      = V4L2_CID_WHITE_BALANCE_TEMPERATURE,
172		.type    = V4L2_CTRL_TYPE_INTEGER,
173		.name    = "White Balance",
174		.minimum = 0,
175		.maximum = 255,
176		.step    = 1,
177#define WHITEBALANCE_DEF 4
178		.default_value = WHITEBALANCE_DEF,
179	    },
180	    .set = sd_setwhitebalance,
181	    .get = sd_getwhitebalance,
182	},
183	{
184	    {
185		.id      = V4L2_CID_RED_BALANCE,
186		.type    = V4L2_CTRL_TYPE_INTEGER,
187		.name    = "Red",
188		.minimum = 0,
189		.maximum = 3,
190		.step    = 1,
191#define REDBALANCE_DEF 1
192		.default_value = REDBALANCE_DEF,
193	    },
194	    .set = sd_setredbalance,
195	    .get = sd_getredbalance,
196	},
197	{
198	    {
199		.id      = V4L2_CID_BLUE_BALANCE,
200		.type    = V4L2_CTRL_TYPE_INTEGER,
201		.name    = "Blue",
202		.minimum = 0,
203		.maximum = 3,
204		.step    = 1,
205#define BLUEBALANCE_DEF 1
206		.default_value = BLUEBALANCE_DEF,
207	    },
208	    .set = sd_setbluebalance,
209	    .get = sd_getbluebalance,
210	},
211	{
212	    {
213		.id      = V4L2_CID_GAIN,
214		.type    = V4L2_CTRL_TYPE_INTEGER,
215		.name    = "Gain",
216		.minimum = 0,
217#define GAIN_MAX 255
218		.maximum = GAIN_MAX,
219		.step    = 1,
220#define GAIN_DEF 127
221#define GAIN_KNEE 255 /* Gain seems to cause little noise on the pac73xx */
222		.default_value = GAIN_DEF,
223	    },
224	    .set = sd_setgain,
225	    .get = sd_getgain,
226	},
227	{
228	    {
229		.id      = V4L2_CID_EXPOSURE,
230		.type    = V4L2_CTRL_TYPE_INTEGER,
231		.name    = "Exposure",
232		.minimum = 0,
233		.maximum = 1023,
234		.step    = 1,
235#define EXPOSURE_DEF  66  /*  33 ms / 30 fps */
236#define EXPOSURE_KNEE 133 /*  66 ms / 15 fps */
237		.default_value = EXPOSURE_DEF,
238	    },
239	    .set = sd_setexposure,
240	    .get = sd_getexposure,
241	},
242	{
243	    {
244		.id      = V4L2_CID_AUTOGAIN,
245		.type    = V4L2_CTRL_TYPE_BOOLEAN,
246		.name    = "Auto Gain",
247		.minimum = 0,
248		.maximum = 1,
249		.step    = 1,
250#define AUTOGAIN_DEF 1
251		.default_value = AUTOGAIN_DEF,
252	    },
253	    .set = sd_setautogain,
254	    .get = sd_getautogain,
255	},
256	{
257	    {
258		.id      = V4L2_CID_HFLIP,
259		.type    = V4L2_CTRL_TYPE_BOOLEAN,
260		.name    = "Mirror",
261		.minimum = 0,
262		.maximum = 1,
263		.step    = 1,
264#define HFLIP_DEF 0
265		.default_value = HFLIP_DEF,
266	    },
267	    .set = sd_sethflip,
268	    .get = sd_gethflip,
269	},
270	{
271	    {
272		.id      = V4L2_CID_VFLIP,
273		.type    = V4L2_CTRL_TYPE_BOOLEAN,
274		.name    = "Vflip",
275		.minimum = 0,
276		.maximum = 1,
277		.step    = 1,
278#define VFLIP_DEF 0
279		.default_value = VFLIP_DEF,
280	    },
281	    .set = sd_setvflip,
282	    .get = sd_getvflip,
283	},
284};
285
286static const struct v4l2_pix_format vga_mode[] = {
287	{640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
288		.bytesperline = 640,
289		.sizeimage = 640 * 480 * 3 / 8 + 590,
290		.colorspace = V4L2_COLORSPACE_JPEG,
291		.priv = 0},
292};
293
294#define LOAD_PAGE3		255
295#define END_OF_SEQUENCE		0
296
297/* pac 7302 */
298static const __u8 init_7302[] = {
299/*	index,value */
300	0xff, 0x01,		/* page 1 */
301	0x78, 0x00,		/* deactivate */
302	0xff, 0x01,
303	0x78, 0x40,		/* led off */
304};
305static const __u8 start_7302[] = {
306/*	index, len, [value]* */
307	0xff, 1,	0x00,		/* page 0 */
308	0x00, 12,	0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80,
309			0x00, 0x00, 0x00, 0x00,
310	0x0d, 24,	0x03, 0x01, 0x00, 0xb5, 0x07, 0xcb, 0x00, 0x00,
311			0x07, 0xc8, 0x00, 0xea, 0x07, 0xcf, 0x07, 0xf7,
312			0x07, 0x7e, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x11,
313	0x26, 2,	0xaa, 0xaa,
314	0x2e, 1,	0x31,
315	0x38, 1,	0x01,
316	0x3a, 3,	0x14, 0xff, 0x5a,
317	0x43, 11,	0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11,
318			0x00, 0x54, 0x11,
319	0x55, 1,	0x00,
320	0x62, 4, 	0x10, 0x1e, 0x1e, 0x18,
321	0x6b, 1,	0x00,
322	0x6e, 3,	0x08, 0x06, 0x00,
323	0x72, 3,	0x00, 0xff, 0x00,
324	0x7d, 23,	0x01, 0x01, 0x58, 0x46, 0x50, 0x3c, 0x50, 0x3c,
325			0x54, 0x46, 0x54, 0x56, 0x52, 0x50, 0x52, 0x50,
326			0x56, 0x64, 0xa4, 0x00, 0xda, 0x00, 0x00,
327	0xa2, 10,	0x22, 0x2c, 0x3c, 0x54, 0x69, 0x7c, 0x9c, 0xb9,
328			0xd2, 0xeb,
329	0xaf, 1,	0x02,
330	0xb5, 2,	0x08, 0x08,
331	0xb8, 2,	0x08, 0x88,
332	0xc4, 4,	0xae, 0x01, 0x04, 0x01,
333	0xcc, 1,	0x00,
334	0xd1, 11,	0x01, 0x30, 0x49, 0x5e, 0x6f, 0x7f, 0x8e, 0xa9,
335			0xc1, 0xd7, 0xec,
336	0xdc, 1,	0x01,
337	0xff, 1,	0x01,		/* page 1 */
338	0x12, 3,	0x02, 0x00, 0x01,
339	0x3e, 2,	0x00, 0x00,
340	0x76, 5,	0x01, 0x20, 0x40, 0x00, 0xf2,
341	0x7c, 1,	0x00,
342	0x7f, 10,	0x4b, 0x0f, 0x01, 0x2c, 0x02, 0x58, 0x03, 0x20,
343			0x02, 0x00,
344	0x96, 5,	0x01, 0x10, 0x04, 0x01, 0x04,
345	0xc8, 14,	0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
346			0x07, 0x00, 0x01, 0x07, 0x04, 0x01,
347	0xd8, 1,	0x01,
348	0xdb, 2,	0x00, 0x01,
349	0xde, 7,	0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00,
350	0xe6, 4,	0x00, 0x00, 0x00, 0x01,
351	0xeb, 1,	0x00,
352	0xff, 1,	0x02,		/* page 2 */
353	0x22, 1,	0x00,
354	0xff, 1,	0x03,		/* page 3 */
355	0, LOAD_PAGE3,			/* load the page 3 */
356	0x11, 1,	0x01,
357	0xff, 1,	0x02,		/* page 2 */
358	0x13, 1,	0x00,
359	0x22, 4,	0x1f, 0xa4, 0xf0, 0x96,
360	0x27, 2,	0x14, 0x0c,
361	0x2a, 5,	0xc8, 0x00, 0x18, 0x12, 0x22,
362	0x64, 8,	0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44,
363	0x6e, 1,	0x08,
364	0xff, 1,	0x01,		/* page 1 */
365	0x78, 1,	0x00,
366	0, END_OF_SEQUENCE		/* end of sequence */
367};
368
369#define SKIP		0xaa
370/* page 3 - the value SKIP says skip the index - see reg_w_page() */
371static const __u8 page3_7302[] = {
372	0x90, 0x40, 0x03, 0x00, 0xc0, 0x01, 0x14, 0x16,
373	0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00,
374	0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
375	0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00,
376	0x00, 0x08, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x21,
377	0x00, 0x00, 0x00, 0x54, 0xf4, 0x02, 0x52, 0x54,
378	0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00,
379	0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
380	0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00,
381	SKIP, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00,
382	0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
383	0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00,
384	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
385	0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc8, 0xc8,
386	0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
387	0x08, 0x10, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00,
388	0x01, 0x00, 0x02, 0x47, 0x00, 0x00, 0x00, 0x00,
389	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
390	0x00, 0x02, 0xfa, 0x00, 0x64, 0x5a, 0x28, 0x00,
391	0x00
392};
393
394static void reg_w_buf(struct gspca_dev *gspca_dev,
395		  __u8 index,
396		  const char *buffer, int len)
397{
398	int ret;
399
400	if (gspca_dev->usb_err < 0)
401		return;
402	memcpy(gspca_dev->usb_buf, buffer, len);
403	ret = usb_control_msg(gspca_dev->dev,
404			usb_sndctrlpipe(gspca_dev->dev, 0),
405			0,		/* request */
406			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
407			0,		/* value */
408			index, gspca_dev->usb_buf, len,
409			500);
410	if (ret < 0) {
411		PDEBUG(D_ERR, "reg_w_buf(): "
412		"Failed to write registers to index 0x%x, error %i",
413		index, ret);
414		gspca_dev->usb_err = ret;
415	}
416}
417
418
419static void reg_w(struct gspca_dev *gspca_dev,
420		  __u8 index,
421		  __u8 value)
422{
423	int ret;
424
425	if (gspca_dev->usb_err < 0)
426		return;
427	gspca_dev->usb_buf[0] = value;
428	ret = usb_control_msg(gspca_dev->dev,
429			usb_sndctrlpipe(gspca_dev->dev, 0),
430			0,			/* request */
431			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
432			0, index, gspca_dev->usb_buf, 1,
433			500);
434	if (ret < 0) {
435		PDEBUG(D_ERR, "reg_w(): "
436		"Failed to write register to index 0x%x, value 0x%x, error %i",
437		index, value, ret);
438		gspca_dev->usb_err = ret;
439	}
440}
441
442static void reg_w_seq(struct gspca_dev *gspca_dev,
443		const __u8 *seq, int len)
444{
445	while (--len >= 0) {
446		reg_w(gspca_dev, seq[0], seq[1]);
447		seq += 2;
448	}
449}
450
451/* load the beginning of a page */
452static void reg_w_page(struct gspca_dev *gspca_dev,
453			const __u8 *page, int len)
454{
455	int index;
456	int ret = 0;
457
458	if (gspca_dev->usb_err < 0)
459		return;
460	for (index = 0; index < len; index++) {
461		if (page[index] == SKIP)		/* skip this index */
462			continue;
463		gspca_dev->usb_buf[0] = page[index];
464		ret = usb_control_msg(gspca_dev->dev,
465				usb_sndctrlpipe(gspca_dev->dev, 0),
466				0,			/* request */
467			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
468				0, index, gspca_dev->usb_buf, 1,
469				500);
470		if (ret < 0) {
471			PDEBUG(D_ERR, "reg_w_page(): "
472			"Failed to write register to index 0x%x, "
473			"value 0x%x, error %i",
474			index, page[index], ret);
475			gspca_dev->usb_err = ret;
476			break;
477		}
478	}
479}
480
481/* output a variable sequence */
482static void reg_w_var(struct gspca_dev *gspca_dev,
483			const __u8 *seq,
484			const __u8 *page3, unsigned int page3_len)
485{
486	int index, len;
487
488	for (;;) {
489		index = *seq++;
490		len = *seq++;
491		switch (len) {
492		case END_OF_SEQUENCE:
493			return;
494		case LOAD_PAGE3:
495			reg_w_page(gspca_dev, page3, page3_len);
496			break;
497		default:
498			if (len > USB_BUF_SZ) {
499				PDEBUG(D_ERR|D_STREAM,
500					"Incorrect variable sequence");
501				return;
502			}
503			while (len > 0) {
504				if (len < 8) {
505					reg_w_buf(gspca_dev,
506						index, seq, len);
507					seq += len;
508					break;
509				}
510				reg_w_buf(gspca_dev, index, seq, 8);
511				seq += 8;
512				index += 8;
513				len -= 8;
514			}
515		}
516	}
517	/* not reached */
518}
519
520/* this function is called at probe time for pac7302 */
521static int sd_config(struct gspca_dev *gspca_dev,
522			const struct usb_device_id *id)
523{
524	struct sd *sd = (struct sd *) gspca_dev;
525	struct cam *cam;
526
527	cam = &gspca_dev->cam;
528
529	PDEBUG(D_CONF, "Find Sensor PAC7302");
530	cam->cam_mode = vga_mode;	/* only 640x480 */
531	cam->nmodes = ARRAY_SIZE(vga_mode);
532
533	sd->brightness = BRIGHTNESS_DEF;
534	sd->contrast = CONTRAST_DEF;
535	sd->colors = COLOR_DEF;
536	sd->white_balance = WHITEBALANCE_DEF;
537	sd->red_balance = REDBALANCE_DEF;
538	sd->blue_balance = BLUEBALANCE_DEF;
539	sd->gain = GAIN_DEF;
540	sd->exposure = EXPOSURE_DEF;
541	sd->autogain = AUTOGAIN_DEF;
542	sd->hflip = HFLIP_DEF;
543	sd->vflip = VFLIP_DEF;
544	sd->flags = id->driver_info;
545	return 0;
546}
547
548/* This function is used by pac7302 only */
549static void setbrightcont(struct gspca_dev *gspca_dev)
550{
551	struct sd *sd = (struct sd *) gspca_dev;
552	int i, v;
553	static const __u8 max[10] =
554		{0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb,
555		 0xd4, 0xec};
556	static const __u8 delta[10] =
557		{0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17,
558		 0x11, 0x0b};
559
560	reg_w(gspca_dev, 0xff, 0x00);		/* page 0 */
561	for (i = 0; i < 10; i++) {
562		v = max[i];
563		v += (sd->brightness - BRIGHTNESS_MAX)
564			* 150 / BRIGHTNESS_MAX;		/* 200 ? */
565		v -= delta[i] * sd->contrast / CONTRAST_MAX;
566		if (v < 0)
567			v = 0;
568		else if (v > 0xff)
569			v = 0xff;
570		reg_w(gspca_dev, 0xa2 + i, v);
571	}
572	reg_w(gspca_dev, 0xdc, 0x01);
573}
574
575/* This function is used by pac7302 only */
576static void setcolors(struct gspca_dev *gspca_dev)
577{
578	struct sd *sd = (struct sd *) gspca_dev;
579	int i, v;
580	static const int a[9] =
581		{217, -212, 0, -101, 170, -67, -38, -315, 355};
582	static const int b[9] =
583		{19, 106, 0, 19, 106, 1, 19, 106, 1};
584
585	reg_w(gspca_dev, 0xff, 0x03);			/* page 3 */
586	reg_w(gspca_dev, 0x11, 0x01);
587	reg_w(gspca_dev, 0xff, 0x00);			/* page 0 */
588	for (i = 0; i < 9; i++) {
589		v = a[i] * sd->colors / COLOR_MAX + b[i];
590		reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
591		reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
592	}
593	reg_w(gspca_dev, 0xdc, 0x01);
594	PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
595}
596
597static void setwhitebalance(struct gspca_dev *gspca_dev)
598{
599	struct sd *sd = (struct sd *) gspca_dev;
600
601	reg_w(gspca_dev, 0xff, 0x00);		/* page 0 */
602	reg_w(gspca_dev, 0xc6, sd->white_balance);
603
604	reg_w(gspca_dev, 0xdc, 0x01);
605	PDEBUG(D_CONF|D_STREAM, "white_balance: %i", sd->white_balance);
606}
607
608static void setredbalance(struct gspca_dev *gspca_dev)
609{
610	struct sd *sd = (struct sd *) gspca_dev;
611
612	reg_w(gspca_dev, 0xff, 0x00);		/* page 0 */
613	reg_w(gspca_dev, 0xc5, sd->red_balance);
614
615	reg_w(gspca_dev, 0xdc, 0x01);
616	PDEBUG(D_CONF|D_STREAM, "red_balance: %i", sd->red_balance);
617}
618
619static void setbluebalance(struct gspca_dev *gspca_dev)
620{
621	struct sd *sd = (struct sd *) gspca_dev;
622
623	reg_w(gspca_dev, 0xff, 0x00);			/* page 0 */
624	reg_w(gspca_dev, 0xc7, sd->blue_balance);
625
626	reg_w(gspca_dev, 0xdc, 0x01);
627	PDEBUG(D_CONF|D_STREAM, "blue_balance: %i", sd->blue_balance);
628}
629
630static void setgain(struct gspca_dev *gspca_dev)
631{
632	struct sd *sd = (struct sd *) gspca_dev;
633
634	reg_w(gspca_dev, 0xff, 0x03);			/* page 3 */
635	reg_w(gspca_dev, 0x10, sd->gain >> 3);
636
637	/* load registers to sensor (Bit 0, auto clear) */
638	reg_w(gspca_dev, 0x11, 0x01);
639}
640
641static void setexposure(struct gspca_dev *gspca_dev)
642{
643	struct sd *sd = (struct sd *) gspca_dev;
644	__u8 clockdiv;
645	__u16 exposure;
646
647	/* register 2 of frame 3 contains the clock divider configuring the
648	   no fps according to the formula: 90 / reg. sd->exposure is the
649	   desired exposure time in 0.5 ms. */
650	clockdiv = (90 * sd->exposure + 1999) / 2000;
651
652	/* Note clockdiv = 3 also works, but when running at 30 fps, depending
653	   on the scene being recorded, the camera switches to another
654	   quantization table for certain JPEG blocks, and we don't know how
655	   to decompress these blocks. So we cap the framerate at 15 fps */
656	if (clockdiv < 6)
657		clockdiv = 6;
658	else if (clockdiv > 63)
659		clockdiv = 63;
660
661	/* reg2 MUST be a multiple of 3, except when between 6 and 12?
662	   Always round up, otherwise we cannot get the desired frametime
663	   using the partial frame time exposure control */
664	if (clockdiv < 6 || clockdiv > 12)
665		clockdiv = ((clockdiv + 2) / 3) * 3;
666
667	/* frame exposure time in ms = 1000 * clockdiv / 90    ->
668	exposure = (sd->exposure / 2) * 448 / (1000 * clockdiv / 90) */
669	exposure = (sd->exposure * 45 * 448) / (1000 * clockdiv);
670	/* 0 = use full frametime, 448 = no exposure, reverse it */
671	exposure = 448 - exposure;
672
673	reg_w(gspca_dev, 0xff, 0x03);			/* page 3 */
674	reg_w(gspca_dev, 0x02, clockdiv);
675	reg_w(gspca_dev, 0x0e, exposure & 0xff);
676	reg_w(gspca_dev, 0x0f, exposure >> 8);
677
678	/* load registers to sensor (Bit 0, auto clear) */
679	reg_w(gspca_dev, 0x11, 0x01);
680}
681
682static void sethvflip(struct gspca_dev *gspca_dev)
683{
684	struct sd *sd = (struct sd *) gspca_dev;
685	u8 data, hflip, vflip;
686
687	hflip = sd->hflip;
688	if (sd->flags & FL_HFLIP)
689		hflip = !hflip;
690	vflip = sd->vflip;
691	if (sd->flags & FL_VFLIP)
692		vflip = !vflip;
693
694	reg_w(gspca_dev, 0xff, 0x03);			/* page 3 */
695	data = (hflip ? 0x08 : 0x00) | (vflip ? 0x04 : 0x00);
696	reg_w(gspca_dev, 0x21, data);
697
698	/* load registers to sensor (Bit 0, auto clear) */
699	reg_w(gspca_dev, 0x11, 0x01);
700}
701
702/* this function is called at probe and resume time for pac7302 */
703static int sd_init(struct gspca_dev *gspca_dev)
704{
705	reg_w_seq(gspca_dev, init_7302, sizeof(init_7302)/2);
706	return gspca_dev->usb_err;
707}
708
709static int sd_start(struct gspca_dev *gspca_dev)
710{
711	struct sd *sd = (struct sd *) gspca_dev;
712
713	sd->sof_read = 0;
714
715	reg_w_var(gspca_dev, start_7302,
716		page3_7302, sizeof(page3_7302));
717	setbrightcont(gspca_dev);
718	setcolors(gspca_dev);
719	setwhitebalance(gspca_dev);
720	setredbalance(gspca_dev);
721	setbluebalance(gspca_dev);
722	setgain(gspca_dev);
723	setexposure(gspca_dev);
724	sethvflip(gspca_dev);
725
726	/* only resolution 640x480 is supported for pac7302 */
727
728	sd->sof_read = 0;
729	sd->autogain_ignore_frames = 0;
730	atomic_set(&sd->avg_lum, -1);
731
732	/* start stream */
733	reg_w(gspca_dev, 0xff, 0x01);
734	reg_w(gspca_dev, 0x78, 0x01);
735
736	return gspca_dev->usb_err;
737}
738
739static void sd_stopN(struct gspca_dev *gspca_dev)
740{
741
742	/* stop stream */
743	reg_w(gspca_dev, 0xff, 0x01);
744	reg_w(gspca_dev, 0x78, 0x00);
745}
746
747/* called on streamoff with alt 0 and on disconnect for pac7302 */
748static void sd_stop0(struct gspca_dev *gspca_dev)
749{
750	if (!gspca_dev->present)
751		return;
752	reg_w(gspca_dev, 0xff, 0x01);
753	reg_w(gspca_dev, 0x78, 0x40);
754}
755
756/* Include pac common sof detection functions */
757#include "pac_common.h"
758
759static void do_autogain(struct gspca_dev *gspca_dev)
760{
761	struct sd *sd = (struct sd *) gspca_dev;
762	int avg_lum = atomic_read(&sd->avg_lum);
763	int desired_lum;
764	const int deadzone = 30;
765
766	if (avg_lum == -1)
767		return;
768
769	desired_lum = 270 + sd->brightness;
770
771	if (sd->autogain_ignore_frames > 0)
772		sd->autogain_ignore_frames--;
773	else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
774			deadzone, GAIN_KNEE, EXPOSURE_KNEE))
775		sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
776}
777
778/* JPEG header, part 1 */
779static const unsigned char pac_jpeg_header1[] = {
780  0xff, 0xd8,		/* SOI: Start of Image */
781
782  0xff, 0xc0,		/* SOF0: Start of Frame (Baseline DCT) */
783  0x00, 0x11,		/* length = 17 bytes (including this length field) */
784  0x08			/* Precision: 8 */
785  /* 2 bytes is placed here: number of image lines */
786  /* 2 bytes is placed here: samples per line */
787};
788
789/* JPEG header, continued */
790static const unsigned char pac_jpeg_header2[] = {
791  0x03,			/* Number of image components: 3 */
792  0x01, 0x21, 0x00,	/* ID=1, Subsampling 1x1, Quantization table: 0 */
793  0x02, 0x11, 0x01,	/* ID=2, Subsampling 2x1, Quantization table: 1 */
794  0x03, 0x11, 0x01,	/* ID=3, Subsampling 2x1, Quantization table: 1 */
795
796  0xff, 0xda,		/* SOS: Start Of Scan */
797  0x00, 0x0c,		/* length = 12 bytes (including this length field) */
798  0x03,			/* number of components: 3 */
799  0x01, 0x00,		/* selector 1, table 0x00 */
800  0x02, 0x11,		/* selector 2, table 0x11 */
801  0x03, 0x11,		/* selector 3, table 0x11 */
802  0x00, 0x3f,		/* Spectral selection: 0 .. 63 */
803  0x00			/* Successive approximation: 0 */
804};
805
806static void pac_start_frame(struct gspca_dev *gspca_dev,
807		__u16 lines, __u16 samples_per_line)
808{
809	unsigned char tmpbuf[4];
810
811	gspca_frame_add(gspca_dev, FIRST_PACKET,
812		pac_jpeg_header1, sizeof(pac_jpeg_header1));
813
814	tmpbuf[0] = lines >> 8;
815	tmpbuf[1] = lines & 0xff;
816	tmpbuf[2] = samples_per_line >> 8;
817	tmpbuf[3] = samples_per_line & 0xff;
818
819	gspca_frame_add(gspca_dev, INTER_PACKET,
820		tmpbuf, sizeof(tmpbuf));
821	gspca_frame_add(gspca_dev, INTER_PACKET,
822		pac_jpeg_header2, sizeof(pac_jpeg_header2));
823}
824
825/* this function is run at interrupt level */
826static void sd_pkt_scan(struct gspca_dev *gspca_dev,
827			u8 *data,			/* isoc packet */
828			int len)			/* iso packet length */
829{
830	struct sd *sd = (struct sd *) gspca_dev;
831	u8 *image;
832	unsigned char *sof;
833
834	sof = pac_find_sof(&sd->sof_read, data, len);
835	if (sof) {
836		int n, lum_offset, footer_length;
837
838		/* 6 bytes after the FF D9 EOF marker a number of lumination
839		   bytes are send corresponding to different parts of the
840		   image, the 14th and 15th byte after the EOF seem to
841		   correspond to the center of the image */
842		lum_offset = 61 + sizeof pac_sof_marker;
843		footer_length = 74;
844
845		/* Finish decoding current frame */
846		n = (sof - data) - (footer_length + sizeof pac_sof_marker);
847		if (n < 0) {
848			gspca_dev->image_len += n;
849			n = 0;
850		} else {
851			gspca_frame_add(gspca_dev, INTER_PACKET, data, n);
852		}
853
854		image = gspca_dev->image;
855		if (image != NULL
856		 && image[gspca_dev->image_len - 2] == 0xff
857		 && image[gspca_dev->image_len - 1] == 0xd9)
858			gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
859
860		n = sof - data;
861		len -= n;
862		data = sof;
863
864		/* Get average lumination */
865		if (gspca_dev->last_packet_type == LAST_PACKET &&
866				n >= lum_offset)
867			atomic_set(&sd->avg_lum, data[-lum_offset] +
868						data[-lum_offset + 1]);
869		else
870			atomic_set(&sd->avg_lum, -1);
871
872		/* Start the new frame with the jpeg header */
873		/* The PAC7302 has the image rotated 90 degrees */
874		pac_start_frame(gspca_dev,
875			gspca_dev->width, gspca_dev->height);
876	}
877	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
878}
879
880static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
881{
882	struct sd *sd = (struct sd *) gspca_dev;
883
884	sd->brightness = val;
885	if (gspca_dev->streaming)
886		setbrightcont(gspca_dev);
887	return gspca_dev->usb_err;
888}
889
890static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
891{
892	struct sd *sd = (struct sd *) gspca_dev;
893
894	*val = sd->brightness;
895	return 0;
896}
897
898static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
899{
900	struct sd *sd = (struct sd *) gspca_dev;
901
902	sd->contrast = val;
903	if (gspca_dev->streaming) {
904		setbrightcont(gspca_dev);
905	}
906	return gspca_dev->usb_err;
907}
908
909static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
910{
911	struct sd *sd = (struct sd *) gspca_dev;
912
913	*val = sd->contrast;
914	return 0;
915}
916
917static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
918{
919	struct sd *sd = (struct sd *) gspca_dev;
920
921	sd->colors = val;
922	if (gspca_dev->streaming)
923		setcolors(gspca_dev);
924	return gspca_dev->usb_err;
925}
926
927static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
928{
929	struct sd *sd = (struct sd *) gspca_dev;
930
931	*val = sd->colors;
932	return 0;
933}
934
935static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val)
936{
937	struct sd *sd = (struct sd *) gspca_dev;
938
939	sd->white_balance = val;
940	if (gspca_dev->streaming)
941		setwhitebalance(gspca_dev);
942	return gspca_dev->usb_err;
943}
944
945static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val)
946{
947	struct sd *sd = (struct sd *) gspca_dev;
948
949	*val = sd->white_balance;
950	return 0;
951}
952
953static int sd_setredbalance(struct gspca_dev *gspca_dev, __s32 val)
954{
955	struct sd *sd = (struct sd *) gspca_dev;
956
957	sd->red_balance = val;
958	if (gspca_dev->streaming)
959		setredbalance(gspca_dev);
960	return gspca_dev->usb_err;
961}
962
963static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val)
964{
965	struct sd *sd = (struct sd *) gspca_dev;
966
967	*val = sd->red_balance;
968	return 0;
969}
970
971static int sd_setbluebalance(struct gspca_dev *gspca_dev, __s32 val)
972{
973	struct sd *sd = (struct sd *) gspca_dev;
974
975	sd->blue_balance = val;
976	if (gspca_dev->streaming)
977		setbluebalance(gspca_dev);
978	return gspca_dev->usb_err;
979}
980
981static int sd_getbluebalance(struct gspca_dev *gspca_dev, __s32 *val)
982{
983	struct sd *sd = (struct sd *) gspca_dev;
984
985	*val = sd->blue_balance;
986	return 0;
987}
988
989static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
990{
991	struct sd *sd = (struct sd *) gspca_dev;
992
993	sd->gain = val;
994	if (gspca_dev->streaming)
995		setgain(gspca_dev);
996	return gspca_dev->usb_err;
997}
998
999static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
1000{
1001	struct sd *sd = (struct sd *) gspca_dev;
1002
1003	*val = sd->gain;
1004	return 0;
1005}
1006
1007static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
1008{
1009	struct sd *sd = (struct sd *) gspca_dev;
1010
1011	sd->exposure = val;
1012	if (gspca_dev->streaming)
1013		setexposure(gspca_dev);
1014	return gspca_dev->usb_err;
1015}
1016
1017static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
1018{
1019	struct sd *sd = (struct sd *) gspca_dev;
1020
1021	*val = sd->exposure;
1022	return 0;
1023}
1024
1025static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1026{
1027	struct sd *sd = (struct sd *) gspca_dev;
1028
1029	sd->autogain = val;
1030	/* when switching to autogain set defaults to make sure
1031	   we are on a valid point of the autogain gain /
1032	   exposure knee graph, and give this change time to
1033	   take effect before doing autogain. */
1034	if (sd->autogain) {
1035		sd->exposure = EXPOSURE_DEF;
1036		sd->gain = GAIN_DEF;
1037		if (gspca_dev->streaming) {
1038			sd->autogain_ignore_frames =
1039				PAC_AUTOGAIN_IGNORE_FRAMES;
1040			setexposure(gspca_dev);
1041			setgain(gspca_dev);
1042		}
1043	}
1044
1045	return gspca_dev->usb_err;
1046}
1047
1048static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1049{
1050	struct sd *sd = (struct sd *) gspca_dev;
1051
1052	*val = sd->autogain;
1053	return 0;
1054}
1055
1056static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
1057{
1058	struct sd *sd = (struct sd *) gspca_dev;
1059
1060	sd->hflip = val;
1061	if (gspca_dev->streaming)
1062		sethvflip(gspca_dev);
1063	return gspca_dev->usb_err;
1064}
1065
1066static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
1067{
1068	struct sd *sd = (struct sd *) gspca_dev;
1069
1070	*val = sd->hflip;
1071	return 0;
1072}
1073
1074static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
1075{
1076	struct sd *sd = (struct sd *) gspca_dev;
1077
1078	sd->vflip = val;
1079	if (gspca_dev->streaming)
1080		sethvflip(gspca_dev);
1081	return gspca_dev->usb_err;
1082}
1083
1084static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
1085{
1086	struct sd *sd = (struct sd *) gspca_dev;
1087
1088	*val = sd->vflip;
1089	return 0;
1090}
1091
1092#ifdef CONFIG_VIDEO_ADV_DEBUG
1093static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
1094			struct v4l2_dbg_register *reg)
1095{
1096	__u8 index;
1097	__u8 value;
1098
1099	/* reg->reg: bit0..15: reserved for register index (wIndex is 16bit
1100			       long on the USB bus)
1101	*/
1102	if (reg->match.type == V4L2_CHIP_MATCH_HOST &&
1103	    reg->match.addr == 0 &&
1104	    (reg->reg < 0x000000ff) &&
1105	    (reg->val <= 0x000000ff)
1106	) {
1107		/* Currently writing to page 0 is only supported. */
1108		/* reg_w() only supports 8bit index */
1109		index = reg->reg & 0x000000ff;
1110		value = reg->val & 0x000000ff;
1111
1112		/* Note that there shall be no access to other page
1113		   by any other function between the page swith and
1114		   the actual register write */
1115		reg_w(gspca_dev, 0xff, 0x00);		/* page 0 */
1116		reg_w(gspca_dev, index, value);
1117
1118		reg_w(gspca_dev, 0xdc, 0x01);
1119	}
1120	return gspca_dev->usb_err;
1121}
1122
1123static int sd_chip_ident(struct gspca_dev *gspca_dev,
1124			struct v4l2_dbg_chip_ident *chip)
1125{
1126	int ret = -EINVAL;
1127
1128	if (chip->match.type == V4L2_CHIP_MATCH_HOST &&
1129	    chip->match.addr == 0) {
1130		chip->revision = 0;
1131		chip->ident = V4L2_IDENT_UNKNOWN;
1132		ret = 0;
1133	}
1134	return ret;
1135}
1136#endif
1137
1138#ifdef CONFIG_INPUT
1139static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
1140			u8 *data,		/* interrupt packet data */
1141			int len)		/* interrput packet length */
1142{
1143	int ret = -EINVAL;
1144	u8 data0, data1;
1145
1146	if (len == 2) {
1147		data0 = data[0];
1148		data1 = data[1];
1149		if ((data0 == 0x00 && data1 == 0x11) ||
1150		    (data0 == 0x22 && data1 == 0x33) ||
1151		    (data0 == 0x44 && data1 == 0x55) ||
1152		    (data0 == 0x66 && data1 == 0x77) ||
1153		    (data0 == 0x88 && data1 == 0x99) ||
1154		    (data0 == 0xaa && data1 == 0xbb) ||
1155		    (data0 == 0xcc && data1 == 0xdd) ||
1156		    (data0 == 0xee && data1 == 0xff)) {
1157			input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
1158			input_sync(gspca_dev->input_dev);
1159			input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
1160			input_sync(gspca_dev->input_dev);
1161			ret = 0;
1162		}
1163	}
1164
1165	return ret;
1166}
1167#endif
1168
1169/* sub-driver description for pac7302 */
1170static const struct sd_desc sd_desc = {
1171	.name = MODULE_NAME,
1172	.ctrls = sd_ctrls,
1173	.nctrls = ARRAY_SIZE(sd_ctrls),
1174	.config = sd_config,
1175	.init = sd_init,
1176	.start = sd_start,
1177	.stopN = sd_stopN,
1178	.stop0 = sd_stop0,
1179	.pkt_scan = sd_pkt_scan,
1180	.dq_callback = do_autogain,
1181#ifdef CONFIG_VIDEO_ADV_DEBUG
1182	.set_register = sd_dbg_s_register,
1183	.get_chip_ident = sd_chip_ident,
1184#endif
1185#ifdef CONFIG_INPUT
1186	.int_pkt_scan = sd_int_pkt_scan,
1187#endif
1188};
1189
1190/* -- module initialisation -- */
1191static const struct usb_device_id device_table[] __devinitconst = {
1192	{USB_DEVICE(0x06f8, 0x3009)},
1193	{USB_DEVICE(0x093a, 0x2620)},
1194	{USB_DEVICE(0x093a, 0x2621)},
1195	{USB_DEVICE(0x093a, 0x2622), .driver_info = FL_VFLIP},
1196	{USB_DEVICE(0x093a, 0x2624), .driver_info = FL_VFLIP},
1197	{USB_DEVICE(0x093a, 0x2625)},
1198	{USB_DEVICE(0x093a, 0x2626)},
1199	{USB_DEVICE(0x093a, 0x2628)},
1200	{USB_DEVICE(0x093a, 0x2629), .driver_info = FL_VFLIP},
1201	{USB_DEVICE(0x093a, 0x262a)},
1202	{USB_DEVICE(0x093a, 0x262c)},
1203	{}
1204};
1205MODULE_DEVICE_TABLE(usb, device_table);
1206
1207/* -- device connect -- */
1208static int __devinit sd_probe(struct usb_interface *intf,
1209			const struct usb_device_id *id)
1210{
1211	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1212				THIS_MODULE);
1213}
1214
1215static struct usb_driver sd_driver = {
1216	.name = MODULE_NAME,
1217	.id_table = device_table,
1218	.probe = sd_probe,
1219	.disconnect = gspca_disconnect,
1220#ifdef CONFIG_PM
1221	.suspend = gspca_suspend,
1222	.resume = gspca_resume,
1223#endif
1224};
1225
1226/* -- module insert / remove -- */
1227static int __init sd_mod_init(void)
1228{
1229	int ret;
1230	ret = usb_register(&sd_driver);
1231	if (ret < 0)
1232		return ret;
1233	PDEBUG(D_PROBE, "registered");
1234	return 0;
1235}
1236static void __exit sd_mod_exit(void)
1237{
1238	usb_deregister(&sd_driver);
1239	PDEBUG(D_PROBE, "deregistered");
1240}
1241
1242module_init(sd_mod_init);
1243module_exit(sd_mod_exit);
1244