mars.c revision 95c967c167785eb991cf6b22fb854dd8d61d0ff8
1/*
2 *		Mars-Semi MR97311A library
3 *		Copyright (C) 2005 <bradlch@hotmail.com>
4 *
5 * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22#define MODULE_NAME "mars"
23
24#include "gspca.h"
25#include "jpeg.h"
26
27MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
28MODULE_DESCRIPTION("GSPCA/Mars USB Camera Driver");
29MODULE_LICENSE("GPL");
30
31/* controls */
32enum e_ctrl {
33	BRIGHTNESS,
34	COLORS,
35	GAMMA,
36	SHARPNESS,
37	ILLUM_TOP,
38	ILLUM_BOT,
39	NCTRLS		/* number of controls */
40};
41
42/* specific webcam descriptor */
43struct sd {
44	struct gspca_dev gspca_dev;	/* !! must be the first item */
45
46	struct gspca_ctrl ctrls[NCTRLS];
47
48	u8 quality;
49#define QUALITY_MIN 40
50#define QUALITY_MAX 70
51#define QUALITY_DEF 50
52
53	u8 jpeg_hdr[JPEG_HDR_SZ];
54};
55
56/* V4L2 controls supported by the driver */
57static void setbrightness(struct gspca_dev *gspca_dev);
58static void setcolors(struct gspca_dev *gspca_dev);
59static void setgamma(struct gspca_dev *gspca_dev);
60static void setsharpness(struct gspca_dev *gspca_dev);
61static int sd_setilluminator1(struct gspca_dev *gspca_dev, __s32 val);
62static int sd_setilluminator2(struct gspca_dev *gspca_dev, __s32 val);
63
64static const struct ctrl sd_ctrls[NCTRLS] = {
65[BRIGHTNESS] = {
66	    {
67		.id      = V4L2_CID_BRIGHTNESS,
68		.type    = V4L2_CTRL_TYPE_INTEGER,
69		.name    = "Brightness",
70		.minimum = 0,
71		.maximum = 30,
72		.step    = 1,
73		.default_value = 15,
74	    },
75	    .set_control = setbrightness
76	},
77[COLORS] = {
78	    {
79		.id      = V4L2_CID_SATURATION,
80		.type    = V4L2_CTRL_TYPE_INTEGER,
81		.name    = "Color",
82		.minimum = 1,
83		.maximum = 255,
84		.step    = 1,
85		.default_value = 200,
86	    },
87	    .set_control = setcolors
88	},
89[GAMMA] = {
90	    {
91		.id      = V4L2_CID_GAMMA,
92		.type    = V4L2_CTRL_TYPE_INTEGER,
93		.name    = "Gamma",
94		.minimum = 0,
95		.maximum = 3,
96		.step    = 1,
97		.default_value = 1,
98	    },
99	    .set_control = setgamma
100	},
101[SHARPNESS] = {
102	    {
103		.id	 = V4L2_CID_SHARPNESS,
104		.type    = V4L2_CTRL_TYPE_INTEGER,
105		.name    = "Sharpness",
106		.minimum = 0,
107		.maximum = 2,
108		.step    = 1,
109		.default_value = 1,
110	    },
111	    .set_control = setsharpness
112	},
113[ILLUM_TOP] = {
114	    {
115		.id	 = V4L2_CID_ILLUMINATORS_1,
116		.type    = V4L2_CTRL_TYPE_BOOLEAN,
117		.name    = "Top illuminator",
118		.minimum = 0,
119		.maximum = 1,
120		.step    = 1,
121		.default_value = 0,
122		.flags = V4L2_CTRL_FLAG_UPDATE,
123	    },
124	    .set = sd_setilluminator1
125	},
126[ILLUM_BOT] = {
127	    {
128		.id	 = V4L2_CID_ILLUMINATORS_2,
129		.type    = V4L2_CTRL_TYPE_BOOLEAN,
130		.name    = "Bottom illuminator",
131		.minimum = 0,
132		.maximum = 1,
133		.step    = 1,
134		.default_value = 0,
135		.flags = V4L2_CTRL_FLAG_UPDATE,
136	    },
137	    .set = sd_setilluminator2
138	},
139};
140
141static const struct v4l2_pix_format vga_mode[] = {
142	{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
143		.bytesperline = 320,
144		.sizeimage = 320 * 240 * 3 / 8 + 590,
145		.colorspace = V4L2_COLORSPACE_JPEG,
146		.priv = 2},
147	{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
148		.bytesperline = 640,
149		.sizeimage = 640 * 480 * 3 / 8 + 590,
150		.colorspace = V4L2_COLORSPACE_JPEG,
151		.priv = 1},
152};
153
154static const __u8 mi_data[0x20] = {
155/*	 01    02   03     04    05    06    07    08 */
156	0x48, 0x22, 0x01, 0x47, 0x10, 0x00, 0x00, 0x00,
157/*	 09    0a   0b     0c    0d    0e    0f    10 */
158	0x00, 0x01, 0x30, 0x01, 0x30, 0x01, 0x30, 0x01,
159/*	 11    12   13     14    15    16    17    18 */
160	0x30, 0x00, 0x04, 0x00, 0x06, 0x01, 0xe2, 0x02,
161/*	 19    1a   1b     1c    1d    1e    1f    20 */
162	0x82, 0x00, 0x20, 0x17, 0x80, 0x08, 0x0c, 0x00
163};
164
165/* write <len> bytes from gspca_dev->usb_buf */
166static void reg_w(struct gspca_dev *gspca_dev,
167		 int len)
168{
169	int alen, ret;
170
171	if (gspca_dev->usb_err < 0)
172		return;
173
174	ret = usb_bulk_msg(gspca_dev->dev,
175			usb_sndbulkpipe(gspca_dev->dev, 4),
176			gspca_dev->usb_buf,
177			len,
178			&alen,
179			500);	/* timeout in milliseconds */
180	if (ret < 0) {
181		err("reg write [%02x] error %d",
182			gspca_dev->usb_buf[0], ret);
183		gspca_dev->usb_err = ret;
184	}
185}
186
187static void mi_w(struct gspca_dev *gspca_dev,
188		 u8 addr,
189		 u8 value)
190{
191	gspca_dev->usb_buf[0] = 0x1f;
192	gspca_dev->usb_buf[1] = 0;			/* control byte */
193	gspca_dev->usb_buf[2] = addr;
194	gspca_dev->usb_buf[3] = value;
195
196	reg_w(gspca_dev, 4);
197}
198
199static void setbrightness(struct gspca_dev *gspca_dev)
200{
201	struct sd *sd = (struct sd *) gspca_dev;
202
203	gspca_dev->usb_buf[0] = 0x61;
204	gspca_dev->usb_buf[1] = sd->ctrls[BRIGHTNESS].val;
205	reg_w(gspca_dev, 2);
206}
207
208static void setcolors(struct gspca_dev *gspca_dev)
209{
210	struct sd *sd = (struct sd *) gspca_dev;
211	s16 val;
212
213	val = sd->ctrls[COLORS].val;
214	gspca_dev->usb_buf[0] = 0x5f;
215	gspca_dev->usb_buf[1] = val << 3;
216	gspca_dev->usb_buf[2] = ((val >> 2) & 0xf8) | 0x04;
217	reg_w(gspca_dev, 3);
218}
219
220static void setgamma(struct gspca_dev *gspca_dev)
221{
222	struct sd *sd = (struct sd *) gspca_dev;
223
224	gspca_dev->usb_buf[0] = 0x06;
225	gspca_dev->usb_buf[1] = sd->ctrls[GAMMA].val * 0x40;
226	reg_w(gspca_dev, 2);
227}
228
229static void setsharpness(struct gspca_dev *gspca_dev)
230{
231	struct sd *sd = (struct sd *) gspca_dev;
232
233	gspca_dev->usb_buf[0] = 0x67;
234	gspca_dev->usb_buf[1] = sd->ctrls[SHARPNESS].val * 4 + 3;
235	reg_w(gspca_dev, 2);
236}
237
238static void setilluminators(struct gspca_dev *gspca_dev)
239{
240	struct sd *sd = (struct sd *) gspca_dev;
241
242	gspca_dev->usb_buf[0] = 0x22;
243	if (sd->ctrls[ILLUM_TOP].val)
244		gspca_dev->usb_buf[1] = 0x76;
245	else if (sd->ctrls[ILLUM_BOT].val)
246		gspca_dev->usb_buf[1] = 0x7a;
247	else
248		gspca_dev->usb_buf[1] = 0x7e;
249	reg_w(gspca_dev, 2);
250}
251
252/* this function is called at probe time */
253static int sd_config(struct gspca_dev *gspca_dev,
254			const struct usb_device_id *id)
255{
256	struct sd *sd = (struct sd *) gspca_dev;
257	struct cam *cam;
258
259	cam = &gspca_dev->cam;
260	cam->cam_mode = vga_mode;
261	cam->nmodes = ARRAY_SIZE(vga_mode);
262	cam->ctrls = sd->ctrls;
263	sd->quality = QUALITY_DEF;
264	gspca_dev->nbalt = 9;		/* use the altsetting 08 */
265	return 0;
266}
267
268/* this function is called at probe and resume time */
269static int sd_init(struct gspca_dev *gspca_dev)
270{
271	gspca_dev->ctrl_inac = (1 << ILLUM_TOP) | (1 << ILLUM_BOT);
272	return 0;
273}
274
275static int sd_start(struct gspca_dev *gspca_dev)
276{
277	struct sd *sd = (struct sd *) gspca_dev;
278	u8 *data;
279	int i;
280
281	/* create the JPEG header */
282	jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
283			0x21);		/* JPEG 422 */
284	jpeg_set_qual(sd->jpeg_hdr, sd->quality);
285
286	data = gspca_dev->usb_buf;
287
288	data[0] = 0x01;		/* address */
289	data[1] = 0x01;
290	reg_w(gspca_dev, 2);
291
292	/*
293	   Initialize the MR97113 chip register
294	 */
295	data[0] = 0x00;		/* address */
296	data[1] = 0x0c | 0x01;	/* reg 0 */
297	data[2] = 0x01;		/* reg 1 */
298	data[3] = gspca_dev->width / 8;		/* h_size , reg 2 */
299	data[4] = gspca_dev->height / 8;	/* v_size , reg 3 */
300	data[5] = 0x30;		/* reg 4, MI, PAS5101 :
301				 *	0x30 for 24mhz , 0x28 for 12mhz */
302	data[6] = 0x02;		/* reg 5, H start - was 0x04 */
303	data[7] = sd->ctrls[GAMMA].val * 0x40;	/* reg 0x06: gamma */
304	data[8] = 0x01;		/* reg 7, V start - was 0x03 */
305/*	if (h_size == 320 ) */
306/*		data[9]= 0x56;	 * reg 8, 24MHz, 2:1 scale down */
307/*	else */
308	data[9] = 0x52;		/* reg 8, 24MHz, no scale down */
309/*jfm: from win trace*/
310	data[10] = 0x18;
311
312	reg_w(gspca_dev, 11);
313
314	data[0] = 0x23;		/* address */
315	data[1] = 0x09;		/* reg 35, append frame header */
316
317	reg_w(gspca_dev, 2);
318
319	data[0] = 0x3c;		/* address */
320/*	if (gspca_dev->width == 1280) */
321/*		data[1] = 200;	 * reg 60, pc-cam frame size
322				 *	(unit: 4KB) 800KB */
323/*	else */
324	data[1] = 50;		/* 50 reg 60, pc-cam frame size
325				 *	(unit: 4KB) 200KB */
326	reg_w(gspca_dev, 2);
327
328	/* auto dark-gain */
329	data[0] = 0x5e;		/* address */
330	data[1] = 0;		/* reg 94, Y Gain (auto) */
331/*jfm: from win trace*/
332				/* reg 0x5f/0x60 (LE) = saturation */
333				/* h (60): xxxx x100
334				 * l (5f): xxxx x000 */
335	data[2] = sd->ctrls[COLORS].val << 3;
336	data[3] = ((sd->ctrls[COLORS].val >> 2) & 0xf8) | 0x04;
337	data[4] = sd->ctrls[BRIGHTNESS].val; /* reg 0x61 = brightness */
338	data[5] = 0x00;
339
340	reg_w(gspca_dev, 6);
341
342	data[0] = 0x67;
343/*jfm: from win trace*/
344	data[1] = sd->ctrls[SHARPNESS].val * 4 + 3;
345	data[2] = 0x14;
346	reg_w(gspca_dev, 3);
347
348	data[0] = 0x69;
349	data[1] = 0x2f;
350	data[2] = 0x28;
351	data[3] = 0x42;
352	reg_w(gspca_dev, 4);
353
354	data[0] = 0x63;
355	data[1] = 0x07;
356	reg_w(gspca_dev, 2);
357/*jfm: win trace - many writes here to reg 0x64*/
358
359	/* initialize the MI sensor */
360	for (i = 0; i < sizeof mi_data; i++)
361		mi_w(gspca_dev, i + 1, mi_data[i]);
362
363	data[0] = 0x00;
364	data[1] = 0x4d;		/* ISOC transfering enable... */
365	reg_w(gspca_dev, 2);
366
367	gspca_dev->ctrl_inac = 0; /* activate the illuminator controls */
368	return gspca_dev->usb_err;
369}
370
371static void sd_stopN(struct gspca_dev *gspca_dev)
372{
373	struct sd *sd = (struct sd *) gspca_dev;
374
375	gspca_dev->ctrl_inac = (1 << ILLUM_TOP) | (1 << ILLUM_BOT);
376	if (sd->ctrls[ILLUM_TOP].val || sd->ctrls[ILLUM_BOT].val) {
377		sd->ctrls[ILLUM_TOP].val = 0;
378		sd->ctrls[ILLUM_BOT].val = 0;
379		setilluminators(gspca_dev);
380		msleep(20);
381	}
382
383	gspca_dev->usb_buf[0] = 1;
384	gspca_dev->usb_buf[1] = 0;
385	reg_w(gspca_dev, 2);
386}
387
388static void sd_pkt_scan(struct gspca_dev *gspca_dev,
389			u8 *data,			/* isoc packet */
390			int len)			/* iso packet length */
391{
392	struct sd *sd = (struct sd *) gspca_dev;
393	int p;
394
395	if (len < 6) {
396/*		gspca_dev->last_packet_type = DISCARD_PACKET; */
397		return;
398	}
399	for (p = 0; p < len - 6; p++) {
400		if (data[0 + p] == 0xff
401		    && data[1 + p] == 0xff
402		    && data[2 + p] == 0x00
403		    && data[3 + p] == 0xff
404		    && data[4 + p] == 0x96) {
405			if (data[5 + p] == 0x64
406			    || data[5 + p] == 0x65
407			    || data[5 + p] == 0x66
408			    || data[5 + p] == 0x67) {
409				PDEBUG(D_PACK, "sof offset: %d len: %d",
410					p, len);
411				gspca_frame_add(gspca_dev, LAST_PACKET,
412						data, p);
413
414				/* put the JPEG header */
415				gspca_frame_add(gspca_dev, FIRST_PACKET,
416					sd->jpeg_hdr, JPEG_HDR_SZ);
417				data += p + 16;
418				len -= p + 16;
419				break;
420			}
421		}
422	}
423	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
424}
425
426static int sd_setilluminator1(struct gspca_dev *gspca_dev, __s32 val)
427{
428	struct sd *sd = (struct sd *) gspca_dev;
429
430	/* only one illuminator may be on */
431	sd->ctrls[ILLUM_TOP].val = val;
432	if (val)
433		sd->ctrls[ILLUM_BOT].val = 0;
434	setilluminators(gspca_dev);
435	return gspca_dev->usb_err;
436}
437
438static int sd_setilluminator2(struct gspca_dev *gspca_dev, __s32 val)
439{
440	struct sd *sd = (struct sd *) gspca_dev;
441
442	/* only one illuminator may be on */
443	sd->ctrls[ILLUM_BOT].val = val;
444	if (val)
445		sd->ctrls[ILLUM_TOP].val = 0;
446	setilluminators(gspca_dev);
447	return gspca_dev->usb_err;
448}
449
450static int sd_set_jcomp(struct gspca_dev *gspca_dev,
451			struct v4l2_jpegcompression *jcomp)
452{
453	struct sd *sd = (struct sd *) gspca_dev;
454
455	if (jcomp->quality < QUALITY_MIN)
456		sd->quality = QUALITY_MIN;
457	else if (jcomp->quality > QUALITY_MAX)
458		sd->quality = QUALITY_MAX;
459	else
460		sd->quality = jcomp->quality;
461	if (gspca_dev->streaming)
462		jpeg_set_qual(sd->jpeg_hdr, sd->quality);
463	return 0;
464}
465
466static int sd_get_jcomp(struct gspca_dev *gspca_dev,
467			struct v4l2_jpegcompression *jcomp)
468{
469	struct sd *sd = (struct sd *) gspca_dev;
470
471	memset(jcomp, 0, sizeof *jcomp);
472	jcomp->quality = sd->quality;
473	jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
474			| V4L2_JPEG_MARKER_DQT;
475	return 0;
476}
477
478/* sub-driver description */
479static const struct sd_desc sd_desc = {
480	.name = MODULE_NAME,
481	.ctrls = sd_ctrls,
482	.nctrls = NCTRLS,
483	.config = sd_config,
484	.init = sd_init,
485	.start = sd_start,
486	.stopN = sd_stopN,
487	.pkt_scan = sd_pkt_scan,
488	.get_jcomp = sd_get_jcomp,
489	.set_jcomp = sd_set_jcomp,
490};
491
492/* -- module initialisation -- */
493static const struct usb_device_id device_table[] = {
494	{USB_DEVICE(0x093a, 0x050f)},
495	{}
496};
497MODULE_DEVICE_TABLE(usb, device_table);
498
499/* -- device connect -- */
500static int sd_probe(struct usb_interface *intf,
501			const struct usb_device_id *id)
502{
503	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
504				THIS_MODULE);
505}
506
507static struct usb_driver sd_driver = {
508	.name = MODULE_NAME,
509	.id_table = device_table,
510	.probe = sd_probe,
511	.disconnect = gspca_disconnect,
512#ifdef CONFIG_PM
513	.suspend = gspca_suspend,
514	.resume = gspca_resume,
515#endif
516};
517
518/* -- module insert / remove -- */
519static int __init sd_mod_init(void)
520{
521	return usb_register(&sd_driver);
522}
523static void __exit sd_mod_exit(void)
524{
525	usb_deregister(&sd_driver);
526}
527
528module_init(sd_mod_init);
529module_exit(sd_mod_exit);
530