diff options
Diffstat (limited to 'drivers/media/video/gspca/mars.c')
-rw-r--r-- | drivers/media/video/gspca/mars.c | 455 |
1 files changed, 455 insertions, 0 deletions
diff --git a/drivers/media/video/gspca/mars.c b/drivers/media/video/gspca/mars.c new file mode 100644 index 000000000000..48b861d68299 --- /dev/null +++ b/drivers/media/video/gspca/mars.c | |||
@@ -0,0 +1,455 @@ | |||
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 | |||
27 | #define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 0) | ||
28 | static const char version[] = "2.1.0"; | ||
29 | |||
30 | MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>"); | ||
31 | MODULE_DESCRIPTION("GSPCA/Mars USB Camera Driver"); | ||
32 | MODULE_LICENSE("GPL"); | ||
33 | |||
34 | /* specific webcam descriptor */ | ||
35 | struct sd { | ||
36 | struct gspca_dev gspca_dev; /* !! must be the first item */ | ||
37 | |||
38 | char qindex; | ||
39 | }; | ||
40 | |||
41 | /* V4L2 controls supported by the driver */ | ||
42 | static struct ctrl sd_ctrls[] = { | ||
43 | }; | ||
44 | |||
45 | static struct cam_mode vga_mode[] = { | ||
46 | {V4L2_PIX_FMT_JPEG, 320, 240, 2}, | ||
47 | {V4L2_PIX_FMT_JPEG, 640, 480, 1}, | ||
48 | }; | ||
49 | |||
50 | /* MI Register table //elvis */ | ||
51 | enum { | ||
52 | REG_HW_MI_0, | ||
53 | REG_HW_MI_1, | ||
54 | REG_HW_MI_2, | ||
55 | REG_HW_MI_3, | ||
56 | REG_HW_MI_4, | ||
57 | REG_HW_MI_5, | ||
58 | REG_HW_MI_6, | ||
59 | REG_HW_MI_7, | ||
60 | REG_HW_MI_9 = 0x09, | ||
61 | REG_HW_MI_B = 0x0B, | ||
62 | REG_HW_MI_C, | ||
63 | REG_HW_MI_D, | ||
64 | REG_HW_MI_1E = 0x1E, | ||
65 | REG_HW_MI_20 = 0x20, | ||
66 | REG_HW_MI_2B = 0x2B, | ||
67 | REG_HW_MI_2C, | ||
68 | REG_HW_MI_2D, | ||
69 | REG_HW_MI_2E, | ||
70 | REG_HW_MI_35 = 0x35, | ||
71 | REG_HW_MI_5F = 0x5f, | ||
72 | REG_HW_MI_60, | ||
73 | REG_HW_MI_61, | ||
74 | REG_HW_MI_62, | ||
75 | REG_HW_MI_63, | ||
76 | REG_HW_MI_64, | ||
77 | REG_HW_MI_F1 = 0xf1, | ||
78 | ATTR_TOTAL_MI_REG = 242 | ||
79 | }; | ||
80 | |||
81 | static int pcam_reg_write(struct usb_device *dev, | ||
82 | __u16 index, unsigned char *value, int length) | ||
83 | { | ||
84 | int rc; | ||
85 | |||
86 | rc = usb_control_msg(dev, | ||
87 | usb_sndbulkpipe(dev, 4), | ||
88 | 0x12, | ||
89 | /* ?? 0xc8 = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_??? !? */ | ||
90 | 0xc8, | ||
91 | 0, /* value */ | ||
92 | index, value, length, 500); | ||
93 | PDEBUG(D_USBO, "reg write: 0x%02X , result = 0x%x", index, rc); | ||
94 | |||
95 | if (rc < 0) | ||
96 | PDEBUG(D_ERR, "reg write: error %d", rc); | ||
97 | return rc; | ||
98 | } | ||
99 | |||
100 | static void MISensor_BulkWrite(struct usb_device *dev, unsigned short *pch, | ||
101 | char Address) | ||
102 | { | ||
103 | int result; | ||
104 | unsigned char data[6]; | ||
105 | |||
106 | data[0] = 0x1f; | ||
107 | data[1] = 0; | ||
108 | data[2] = Address; | ||
109 | data[3] = *pch >> 8; /* high byte */ | ||
110 | data[4] = *pch; /* low byte */ | ||
111 | data[5] = 0; | ||
112 | |||
113 | result = usb_control_msg(dev, | ||
114 | usb_sndbulkpipe(dev, 4), | ||
115 | 0x12, | ||
116 | /* ?? 0xc8 = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_??? !? */ | ||
117 | 0xc8, | ||
118 | 0, /* value */ | ||
119 | Address, /* index */ | ||
120 | data, 5, 500); | ||
121 | PDEBUG(D_USBO, "bulk write 0x%02x = 0x%04x", Address, *pch); | ||
122 | |||
123 | if (result < 0) | ||
124 | PDEBUG(D_ERR, "reg write: error %d", result); | ||
125 | } | ||
126 | |||
127 | /* this function is called at probe time */ | ||
128 | static int sd_config(struct gspca_dev *gspca_dev, | ||
129 | const struct usb_device_id *id) | ||
130 | { | ||
131 | struct sd *sd = (struct sd *) gspca_dev; | ||
132 | struct cam *cam; | ||
133 | |||
134 | cam = &gspca_dev->cam; | ||
135 | cam->dev_name = (char *) id->driver_info; | ||
136 | cam->epaddr = 0x01; | ||
137 | cam->cam_mode = vga_mode; | ||
138 | cam->nmodes = sizeof vga_mode / sizeof vga_mode[0]; | ||
139 | sd->qindex = 1; /* set the quantization table */ | ||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | /* this function is called at open time */ | ||
144 | static int sd_open(struct gspca_dev *gspca_dev) | ||
145 | { | ||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | static void sd_start(struct gspca_dev *gspca_dev) | ||
150 | { | ||
151 | struct usb_device *dev = gspca_dev->dev; | ||
152 | int err_code; | ||
153 | __u8 data[12]; | ||
154 | __u16 MI_buf[242]; | ||
155 | int h_size, v_size; | ||
156 | int intpipe; | ||
157 | /* struct usb_device *dev = pcam->dev; */ | ||
158 | memset(data, 0, sizeof data); | ||
159 | memset(MI_buf, 0, sizeof MI_buf); | ||
160 | |||
161 | PDEBUG(D_STREAM, "camera start, iface %d, alt 8", gspca_dev->iface); | ||
162 | if (usb_set_interface(dev, gspca_dev->iface, 8) < 0) { | ||
163 | PDEBUG(D_ERR|D_STREAM, "Set packet size: set interface error"); | ||
164 | return; | ||
165 | } | ||
166 | |||
167 | data[0] = 0x01; /* address */ | ||
168 | data[1] = 0x01; | ||
169 | |||
170 | err_code = pcam_reg_write(dev, data[0], data, 0x02); | ||
171 | if (err_code < 0) | ||
172 | return; | ||
173 | |||
174 | /* | ||
175 | Initialize the MR97113 chip register | ||
176 | */ | ||
177 | data[0] = 0x00; /* address */ | ||
178 | data[1] = 0x0c | 0x01; /* reg 0 */ | ||
179 | data[2] = 0x01; /* reg 1 */ | ||
180 | h_size = gspca_dev->width; | ||
181 | v_size = gspca_dev->height; | ||
182 | data[3] = h_size / 8; /* h_size , reg 2 */ | ||
183 | data[4] = v_size / 8; /* v_size , reg 3 */ | ||
184 | data[5] = 0x30; /* reg 4, MI, PAS5101 : | ||
185 | * 0x30 for 24mhz , 0x28 for 12mhz */ | ||
186 | data[6] = 4; /* reg 5, H start */ | ||
187 | data[7] = 0xc0; /* reg 6, gamma 1.5 */ | ||
188 | data[8] = 3; /* reg 7, V start */ | ||
189 | /* if(h_size == 320 ) */ | ||
190 | /* data[9]= 0x56; * reg 8, 24MHz, 2:1 scale down */ | ||
191 | /* else */ | ||
192 | data[9] = 0x52; /* reg 8, 24MHz, no scale down */ | ||
193 | data[10] = 0x5d; /* reg 9, I2C device address | ||
194 | * [for PAS5101 (0x40)] [for MI (0x5d)] */ | ||
195 | |||
196 | err_code = pcam_reg_write(dev, data[0], data, 0x0b); | ||
197 | if (err_code < 0) | ||
198 | return; | ||
199 | |||
200 | data[0] = 0x23; /* address */ | ||
201 | data[1] = 0x09; /* reg 35, append frame header */ | ||
202 | |||
203 | err_code = pcam_reg_write(dev, data[0], data, 0x02); | ||
204 | if (err_code < 0) { | ||
205 | PDEBUG(D_ERR, "Register write failed"); | ||
206 | return; | ||
207 | } | ||
208 | |||
209 | data[0] = 0x3C; /* address */ | ||
210 | /* if (pcam->width == 1280) */ | ||
211 | /* data[1] = 200; * reg 60, pc-cam frame size | ||
212 | * (unit: 4KB) 800KB */ | ||
213 | /* else */ | ||
214 | data[1] = 50; /* 50 reg 60, pc-cam frame size | ||
215 | * (unit: 4KB) 200KB */ | ||
216 | err_code = pcam_reg_write(dev, data[0], data, 0x02); | ||
217 | if (err_code < 0) | ||
218 | return; | ||
219 | |||
220 | if (0) { /* fixed dark-gain */ | ||
221 | data[1] = 0; /* reg 94, Y Gain (1.75) */ | ||
222 | data[2] = 0; /* reg 95, UV Gain (1.75) */ | ||
223 | data[3] = 0x3f; /* reg 96, Y Gain/UV Gain/disable auto dark-gain */ | ||
224 | data[4] = 0; /* reg 97, set fixed dark level */ | ||
225 | data[5] = 0; /* reg 98, don't care */ | ||
226 | } else { /* auto dark-gain */ | ||
227 | data[1] = 0; /* reg 94, Y Gain (auto) */ | ||
228 | data[2] = 0; /* reg 95, UV Gain (1.75) */ | ||
229 | data[3] = 0x78; /* reg 96, Y Gain/UV Gain/disable auto dark-gain */ | ||
230 | switch (gspca_dev->width) { | ||
231 | /* case 1280: */ | ||
232 | /* data[4] = 154; | ||
233 | * reg 97, %3 shadow point (unit: 256 pixel) */ | ||
234 | /* data[5] = 51; | ||
235 | * reg 98, %1 highlight point | ||
236 | * (uint: 256 pixel) */ | ||
237 | /* break; */ | ||
238 | default: | ||
239 | /* case 640: */ | ||
240 | data[4] = 36; /* reg 97, %3 shadow point | ||
241 | * (unit: 256 pixel) */ | ||
242 | data[5] = 12; /* reg 98, %1 highlight point | ||
243 | * (uint: 256 pixel) */ | ||
244 | break; | ||
245 | case 320: | ||
246 | data[4] = 9; /* reg 97, %3 shadow point | ||
247 | * (unit: 256 pixel) */ | ||
248 | data[5] = 3; /* reg 98, %1 highlight point | ||
249 | * (uint: 256 pixel) */ | ||
250 | break; | ||
251 | } | ||
252 | } | ||
253 | /* auto dark-gain */ | ||
254 | data[0] = 0x5e; /* address */ | ||
255 | |||
256 | err_code = pcam_reg_write(dev, data[0], data, 0x06); | ||
257 | if (err_code < 0) | ||
258 | return; | ||
259 | |||
260 | data[0] = 0x67; | ||
261 | data[1] = 0x13; /* reg 103, first pixel B, disable sharpness */ | ||
262 | err_code = pcam_reg_write(dev, data[0], data, 0x02); | ||
263 | if (err_code < 0) | ||
264 | return; | ||
265 | |||
266 | /* | ||
267 | * initialize the value of MI sensor... | ||
268 | */ | ||
269 | MI_buf[REG_HW_MI_1] = 0x000a; | ||
270 | MI_buf[REG_HW_MI_2] = 0x000c; | ||
271 | MI_buf[REG_HW_MI_3] = 0x0405; | ||
272 | MI_buf[REG_HW_MI_4] = 0x0507; | ||
273 | /* mi_Attr_Reg_[REG_HW_MI_5] = 0x01ff;//13 */ | ||
274 | MI_buf[REG_HW_MI_5] = 0x0013; /* 13 */ | ||
275 | MI_buf[REG_HW_MI_6] = 0x001f; /* vertical blanking */ | ||
276 | /* mi_Attr_Reg_[REG_HW_MI_6] = 0x0400; // vertical blanking */ | ||
277 | MI_buf[REG_HW_MI_7] = 0x0002; | ||
278 | /* mi_Attr_Reg_[REG_HW_MI_9] = 0x015f; */ | ||
279 | /* mi_Attr_Reg_[REG_HW_MI_9] = 0x030f; */ | ||
280 | MI_buf[REG_HW_MI_9] = 0x0374; | ||
281 | MI_buf[REG_HW_MI_B] = 0x0000; | ||
282 | MI_buf[REG_HW_MI_C] = 0x0000; | ||
283 | MI_buf[REG_HW_MI_D] = 0x0000; | ||
284 | MI_buf[REG_HW_MI_1E] = 0x8000; | ||
285 | /* mi_Attr_Reg_[REG_HW_MI_20] = 0x1104; */ | ||
286 | MI_buf[REG_HW_MI_20] = 0x1104; /* 0x111c; */ | ||
287 | MI_buf[REG_HW_MI_2B] = 0x0008; | ||
288 | /* mi_Attr_Reg_[REG_HW_MI_2C] = 0x000f; */ | ||
289 | MI_buf[REG_HW_MI_2C] = 0x001f; /* lita suggest */ | ||
290 | MI_buf[REG_HW_MI_2D] = 0x0008; | ||
291 | MI_buf[REG_HW_MI_2E] = 0x0008; | ||
292 | MI_buf[REG_HW_MI_35] = 0x0051; | ||
293 | MI_buf[REG_HW_MI_5F] = 0x0904; /* fail to write */ | ||
294 | MI_buf[REG_HW_MI_60] = 0x0000; | ||
295 | MI_buf[REG_HW_MI_61] = 0x0000; | ||
296 | MI_buf[REG_HW_MI_62] = 0x0498; | ||
297 | MI_buf[REG_HW_MI_63] = 0x0000; | ||
298 | MI_buf[REG_HW_MI_64] = 0x0000; | ||
299 | MI_buf[REG_HW_MI_F1] = 0x0001; | ||
300 | /* changing while setting up the different value of dx/dy */ | ||
301 | |||
302 | if (gspca_dev->width != 1280) { | ||
303 | MI_buf[0x01] = 0x010a; | ||
304 | MI_buf[0x02] = 0x014c; | ||
305 | MI_buf[0x03] = 0x01e5; | ||
306 | MI_buf[0x04] = 0x0287; | ||
307 | } | ||
308 | MI_buf[0x20] = 0x1104; | ||
309 | |||
310 | MISensor_BulkWrite(dev, MI_buf + 1, 1); | ||
311 | MISensor_BulkWrite(dev, MI_buf + 2, 2); | ||
312 | MISensor_BulkWrite(dev, MI_buf + 3, 3); | ||
313 | MISensor_BulkWrite(dev, MI_buf + 4, 4); | ||
314 | MISensor_BulkWrite(dev, MI_buf + 5, 5); | ||
315 | MISensor_BulkWrite(dev, MI_buf + 6, 6); | ||
316 | MISensor_BulkWrite(dev, MI_buf + 7, 7); | ||
317 | MISensor_BulkWrite(dev, MI_buf + 9, 9); | ||
318 | MISensor_BulkWrite(dev, MI_buf + 0x0b, 0x0b); | ||
319 | MISensor_BulkWrite(dev, MI_buf + 0x0c, 0x0c); | ||
320 | MISensor_BulkWrite(dev, MI_buf + 0x0d, 0x0d); | ||
321 | MISensor_BulkWrite(dev, MI_buf + 0x1e, 0x1e); | ||
322 | MISensor_BulkWrite(dev, MI_buf + 0x20, 0x20); | ||
323 | MISensor_BulkWrite(dev, MI_buf + 0x2b, 0x2b); | ||
324 | MISensor_BulkWrite(dev, MI_buf + 0x2c, 0x2c); | ||
325 | MISensor_BulkWrite(dev, MI_buf + 0x2d, 0x2d); | ||
326 | MISensor_BulkWrite(dev, MI_buf + 0x2e, 0x2e); | ||
327 | MISensor_BulkWrite(dev, MI_buf + 0x35, 0x35); | ||
328 | MISensor_BulkWrite(dev, MI_buf + 0x5f, 0x5f); | ||
329 | MISensor_BulkWrite(dev, MI_buf + 0x60, 0x60); | ||
330 | MISensor_BulkWrite(dev, MI_buf + 0x61, 0x61); | ||
331 | MISensor_BulkWrite(dev, MI_buf + 0x62, 0x62); | ||
332 | MISensor_BulkWrite(dev, MI_buf + 0x63, 0x63); | ||
333 | MISensor_BulkWrite(dev, MI_buf + 0x64, 0x64); | ||
334 | MISensor_BulkWrite(dev, MI_buf + 0xf1, 0xf1); | ||
335 | |||
336 | intpipe = usb_sndintpipe(dev, 0); | ||
337 | err_code = usb_clear_halt(dev, intpipe); | ||
338 | |||
339 | data[0] = 0x00; | ||
340 | data[1] = 0x4d; /* ISOC transfering enable... */ | ||
341 | pcam_reg_write(dev, data[0], data, 0x02); | ||
342 | } | ||
343 | |||
344 | static void sd_stopN(struct gspca_dev *gspca_dev) | ||
345 | { | ||
346 | int result; | ||
347 | __u8 data[2]; | ||
348 | |||
349 | data[0] = 1; | ||
350 | data[1] = 0; | ||
351 | result = pcam_reg_write(gspca_dev->dev, data[0], data, 2); | ||
352 | if (result < 0) | ||
353 | PDEBUG(D_ERR, "Camera Stop failed"); | ||
354 | } | ||
355 | |||
356 | static void sd_stop0(struct gspca_dev *gspca_dev) | ||
357 | { | ||
358 | } | ||
359 | |||
360 | static void sd_close(struct gspca_dev *gspca_dev) | ||
361 | { | ||
362 | } | ||
363 | |||
364 | static void sd_pkt_scan(struct gspca_dev *gspca_dev, | ||
365 | struct gspca_frame *frame, /* target */ | ||
366 | unsigned char *data, /* isoc packet */ | ||
367 | int len) /* iso packet length */ | ||
368 | { | ||
369 | struct sd *sd = (struct sd *) gspca_dev; | ||
370 | int p; | ||
371 | |||
372 | if (len < 6) { | ||
373 | /* gspca_dev->last_packet_type = DISCARD_PACKET; */ | ||
374 | return; | ||
375 | } | ||
376 | for (p = 0; p < len - 6; p++) { | ||
377 | if (data[0 + p] == 0xff | ||
378 | && data[1 + p] == 0xff | ||
379 | && data[2 + p] == 0x00 | ||
380 | && data[3 + p] == 0xff | ||
381 | && data[4 + p] == 0x96) { | ||
382 | if (data[5 + p] == 0x64 | ||
383 | || data[5 + p] == 0x65 | ||
384 | || data[5 + p] == 0x66 | ||
385 | || data[5 + p] == 0x67) { | ||
386 | PDEBUG(D_PACK, "sof offset: %d leng: %d", | ||
387 | p, len); | ||
388 | frame = gspca_frame_add(gspca_dev, LAST_PACKET, | ||
389 | frame, data, 0); | ||
390 | |||
391 | /* put the JPEG header */ | ||
392 | jpeg_put_header(gspca_dev, frame, | ||
393 | sd->qindex, 0x21); | ||
394 | data += 16; | ||
395 | len -= 16; | ||
396 | break; | ||
397 | } | ||
398 | } | ||
399 | } | ||
400 | gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len); | ||
401 | } | ||
402 | |||
403 | /* sub-driver description */ | ||
404 | static struct sd_desc sd_desc = { | ||
405 | .name = MODULE_NAME, | ||
406 | .ctrls = sd_ctrls, | ||
407 | .nctrls = ARRAY_SIZE(sd_ctrls), | ||
408 | .config = sd_config, | ||
409 | .open = sd_open, | ||
410 | .start = sd_start, | ||
411 | .stopN = sd_stopN, | ||
412 | .stop0 = sd_stop0, | ||
413 | .close = sd_close, | ||
414 | .pkt_scan = sd_pkt_scan, | ||
415 | }; | ||
416 | |||
417 | /* -- module initialisation -- */ | ||
418 | #define DVNM(name) .driver_info = (kernel_ulong_t) name | ||
419 | static __devinitdata struct usb_device_id device_table[] = { | ||
420 | {USB_DEVICE(0x093a, 0x050f), DVNM("Mars-Semi Pc-Camera")}, | ||
421 | {} | ||
422 | }; | ||
423 | MODULE_DEVICE_TABLE(usb, device_table); | ||
424 | |||
425 | /* -- device connect -- */ | ||
426 | static int sd_probe(struct usb_interface *intf, | ||
427 | const struct usb_device_id *id) | ||
428 | { | ||
429 | return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), | ||
430 | THIS_MODULE); | ||
431 | } | ||
432 | |||
433 | static struct usb_driver sd_driver = { | ||
434 | .name = MODULE_NAME, | ||
435 | .id_table = device_table, | ||
436 | .probe = sd_probe, | ||
437 | .disconnect = gspca_disconnect, | ||
438 | }; | ||
439 | |||
440 | /* -- module insert / remove -- */ | ||
441 | static int __init sd_mod_init(void) | ||
442 | { | ||
443 | if (usb_register(&sd_driver) < 0) | ||
444 | return -1; | ||
445 | PDEBUG(D_PROBE, "v%s registered", version); | ||
446 | return 0; | ||
447 | } | ||
448 | static void __exit sd_mod_exit(void) | ||
449 | { | ||
450 | usb_deregister(&sd_driver); | ||
451 | PDEBUG(D_PROBE, "deregistered"); | ||
452 | } | ||
453 | |||
454 | module_init(sd_mod_init); | ||
455 | module_exit(sd_mod_exit); | ||