aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/gspca/ov534.c
diff options
context:
space:
mode:
authorAntonio Ospite <ospite@studenti.unina.it>2008-11-22 03:23:39 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2008-12-29 14:53:40 -0500
commitfbb4c6d20f29f2b10daad31cc6238d91f93d70d4 (patch)
tree3c1921e51dd6fb9278430eea374fafb4a52e1943 /drivers/media/video/gspca/ov534.c
parenta08d81af37b3d7547813219da68c3c946f742fb3 (diff)
V4L/DVB (9712): gspca:Subdriver ov534 added.
The OmniVision OV534 is the USB bridge chip used in Sony Playstation EYE, it is found also in other webcams like Hercules Blog Webcam and Hercules Dualpix HD. This driver is the port to gspca of a prototype driver by Mark Ferrell based on vivi. The original code to initialize the camera and start the capture is from Jim Paris on ps2dev.org, here integrated with the analysis of the USB communications taken by the windows driver. Signed-off-by: Antonio Ospite <ospite@studenti.unina.it> Signed-off-by: Jean-Francois Moine <moinejf@free.fr> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/gspca/ov534.c')
-rw-r--r--drivers/media/video/gspca/ov534.c505
1 files changed, 505 insertions, 0 deletions
diff --git a/drivers/media/video/gspca/ov534.c b/drivers/media/video/gspca/ov534.c
new file mode 100644
index 000000000000..a574be09bd41
--- /dev/null
+++ b/drivers/media/video/gspca/ov534.c
@@ -0,0 +1,505 @@
1/*
2 * ov534/ov772x gspca driver
3 * Copyright (C) 2008 Antonio Ospite <ospite@studenti.unina.it>
4 *
5 * Based on a prototype written by Mark Ferrell <majortrips@gmail.com>
6 * USB protocol reverse engineered by Jim Paris <jim@jtan.com>
7 * https://jim.sh/svn/jim/devl/playstation/ps3/eye/test/
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24#define MODULE_NAME "ov534"
25
26#include "gspca.h"
27
28#define OV534_REG_ADDRESS 0xf1 /* ? */
29#define OV534_REG_SUBADDR 0xf2
30#define OV534_REG_WRITE 0xf3
31#define OV534_REG_READ 0xf4
32#define OV534_REG_OPERATION 0xf5
33#define OV534_REG_STATUS 0xf6
34
35#define OV534_OP_WRITE_3 0x37
36#define OV534_OP_WRITE_2 0x33
37#define OV534_OP_READ_2 0xf9
38
39#define CTRL_TIMEOUT 500
40
41MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>");
42MODULE_DESCRIPTION("GSPCA/OV534 USB Camera Driver");
43MODULE_LICENSE("GPL");
44
45/* global parameters */
46static int frame_rate;
47
48/* specific webcam descriptor */
49struct sd {
50 struct gspca_dev gspca_dev; /* !! must be the first item */
51 __u8 frame_rate;
52};
53
54/* V4L2 controls supported by the driver */
55static struct ctrl sd_ctrls[] = {
56};
57
58static struct v4l2_pix_format vga_mode[] = {
59 {640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
60 .bytesperline = 640 * 2,
61 .sizeimage = 640 * 480 * 2,
62 .colorspace = V4L2_COLORSPACE_JPEG,
63 .priv = 0},
64};
65
66static void ov534_reg_write(struct usb_device *udev, u16 reg, u16 val)
67{
68 u16 data = val;
69 int ret;
70
71 PDEBUG(D_USBO, "reg=0x%04x, val=0%04x", reg, val);
72 ret = usb_control_msg(udev,
73 usb_sndctrlpipe(udev, 0),
74 0x1,
75 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
76 0x0, reg, &data, 1, CTRL_TIMEOUT);
77 if (ret < 0)
78 PDEBUG(D_ERR, "write failed");
79}
80
81static u16 ov534_reg_read(struct usb_device *udev, u16 reg)
82{
83 u16 data;
84 int ret;
85
86 ret = usb_control_msg(udev,
87 usb_rcvctrlpipe(udev, 0),
88 0x1,
89 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
90 0x0, reg, &data, 1, CTRL_TIMEOUT);
91 PDEBUG(D_USBI, "reg=0x%04x, data=0x%04x", reg, data);
92 if (ret < 0)
93 PDEBUG(D_ERR, "read failed");
94 return data;
95}
96
97static void ov534_reg_verify_write(struct usb_device *udev, u16 reg, u16 val)
98{
99 u16 data;
100
101 ov534_reg_write(udev, reg, val);
102 data = ov534_reg_read(udev, reg);
103 if (data != val) {
104 PDEBUG(D_ERR | D_USBO,
105 "unexpected result from read: 0x%04x != 0x%04x", val,
106 data);
107 }
108}
109
110/* Two bits control LED: 0x21 bit 7 and 0x23 bit 7.
111 * (direction and output)? */
112static void ov534_set_led(struct usb_device *udev, int status)
113{
114 u16 data;
115
116 PDEBUG(D_CONF, "led status: %d", status);
117
118 data = ov534_reg_read(udev, 0x21);
119 data |= 0x80;
120 ov534_reg_write(udev, 0x21, data);
121
122 data = ov534_reg_read(udev, 0x23);
123 if (status)
124 data |= 0x80;
125 else
126 data &= ~(0x80);
127
128 ov534_reg_write(udev, 0x23, data);
129}
130
131static int sccb_check_status(struct usb_device *udev)
132{
133 u16 data;
134 int i;
135
136 for (i = 0; i < 5; i++) {
137 data = ov534_reg_read(udev, OV534_REG_STATUS);
138
139 switch (data & 0xFF) {
140 case 0x00:
141 return 1;
142 case 0x04:
143 return 0;
144 case 0x03:
145 break;
146 default:
147 PDEBUG(D_ERR, "sccb status 0x%02x, attempt %d/5\n",
148 data, i + 1);
149 }
150 }
151 return 0;
152}
153
154static void sccb_reg_write(struct usb_device *udev, u16 reg, u16 val)
155{
156 PDEBUG(D_USBO, "reg: 0x%04x, val: 0x%04x", reg, val);
157 ov534_reg_write(udev, OV534_REG_SUBADDR, reg);
158 ov534_reg_write(udev, OV534_REG_WRITE, val);
159 ov534_reg_write(udev, OV534_REG_OPERATION, OV534_OP_WRITE_3);
160
161 if (!sccb_check_status(udev))
162 PDEBUG(D_ERR, "sccb_reg_write failed");
163}
164
165/* setup method */
166static void ov534_setup(struct usb_device *udev)
167{
168 ov534_reg_verify_write(udev, 0xe7, 0x3a);
169
170 ov534_reg_write(udev, OV534_REG_ADDRESS, 0x60);
171 ov534_reg_write(udev, OV534_REG_ADDRESS, 0x60);
172 ov534_reg_write(udev, OV534_REG_ADDRESS, 0x60);
173 ov534_reg_write(udev, OV534_REG_ADDRESS, 0x42);
174
175 ov534_reg_verify_write(udev, 0xc2, 0x0c);
176 ov534_reg_verify_write(udev, 0x88, 0xf8);
177 ov534_reg_verify_write(udev, 0xc3, 0x69);
178 ov534_reg_verify_write(udev, 0x89, 0xff);
179 ov534_reg_verify_write(udev, 0x76, 0x03);
180 ov534_reg_verify_write(udev, 0x92, 0x01);
181 ov534_reg_verify_write(udev, 0x93, 0x18);
182 ov534_reg_verify_write(udev, 0x94, 0x10);
183 ov534_reg_verify_write(udev, 0x95, 0x10);
184 ov534_reg_verify_write(udev, 0xe2, 0x00);
185 ov534_reg_verify_write(udev, 0xe7, 0x3e);
186
187 ov534_reg_write(udev, 0x1c, 0x0a);
188 ov534_reg_write(udev, 0x1d, 0x22);
189 ov534_reg_write(udev, 0x1d, 0x06);
190
191 ov534_reg_verify_write(udev, 0x96, 0x00);
192
193 ov534_reg_write(udev, 0x97, 0x20);
194 ov534_reg_write(udev, 0x97, 0x20);
195 ov534_reg_write(udev, 0x97, 0x20);
196 ov534_reg_write(udev, 0x97, 0x0a);
197 ov534_reg_write(udev, 0x97, 0x3f);
198 ov534_reg_write(udev, 0x97, 0x4a);
199 ov534_reg_write(udev, 0x97, 0x20);
200 ov534_reg_write(udev, 0x97, 0x15);
201 ov534_reg_write(udev, 0x97, 0x0b);
202
203 ov534_reg_verify_write(udev, 0x8e, 0x40);
204 ov534_reg_verify_write(udev, 0x1f, 0x81);
205 ov534_reg_verify_write(udev, 0x34, 0x05);
206 ov534_reg_verify_write(udev, 0xe3, 0x04);
207 ov534_reg_verify_write(udev, 0x88, 0x00);
208 ov534_reg_verify_write(udev, 0x89, 0x00);
209 ov534_reg_verify_write(udev, 0x76, 0x00);
210 ov534_reg_verify_write(udev, 0xe7, 0x2e);
211 ov534_reg_verify_write(udev, 0x31, 0xf9);
212 ov534_reg_verify_write(udev, 0x25, 0x42);
213 ov534_reg_verify_write(udev, 0x21, 0xf0);
214
215 ov534_reg_write(udev, 0x1c, 0x00);
216 ov534_reg_write(udev, 0x1d, 0x40);
217 ov534_reg_write(udev, 0x1d, 0x02);
218 ov534_reg_write(udev, 0x1d, 0x00);
219 ov534_reg_write(udev, 0x1d, 0x02);
220 ov534_reg_write(udev, 0x1d, 0x57);
221 ov534_reg_write(udev, 0x1d, 0xff);
222
223 ov534_reg_verify_write(udev, 0x8d, 0x1c);
224 ov534_reg_verify_write(udev, 0x8e, 0x80);
225 ov534_reg_verify_write(udev, 0xe5, 0x04);
226
227 ov534_set_led(udev, 1);
228
229 sccb_reg_write(udev, 0x12, 0x80);
230 sccb_reg_write(udev, 0x11, 0x01);
231 sccb_reg_write(udev, 0x11, 0x01);
232 sccb_reg_write(udev, 0x11, 0x01);
233 sccb_reg_write(udev, 0x11, 0x01);
234 sccb_reg_write(udev, 0x11, 0x01);
235 sccb_reg_write(udev, 0x11, 0x01);
236 sccb_reg_write(udev, 0x11, 0x01);
237 sccb_reg_write(udev, 0x11, 0x01);
238 sccb_reg_write(udev, 0x11, 0x01);
239 sccb_reg_write(udev, 0x11, 0x01);
240 sccb_reg_write(udev, 0x11, 0x01);
241
242 ov534_set_led(udev, 0);
243
244 sccb_reg_write(udev, 0x3d, 0x03);
245 sccb_reg_write(udev, 0x17, 0x26);
246 sccb_reg_write(udev, 0x18, 0xa0);
247 sccb_reg_write(udev, 0x19, 0x07);
248 sccb_reg_write(udev, 0x1a, 0xf0);
249 sccb_reg_write(udev, 0x32, 0x00);
250 sccb_reg_write(udev, 0x29, 0xa0);
251 sccb_reg_write(udev, 0x2c, 0xf0);
252 sccb_reg_write(udev, 0x65, 0x20);
253 sccb_reg_write(udev, 0x11, 0x01);
254 sccb_reg_write(udev, 0x42, 0x7f);
255 sccb_reg_write(udev, 0x63, 0xe0);
256 sccb_reg_write(udev, 0x64, 0xff);
257 sccb_reg_write(udev, 0x66, 0x00);
258 sccb_reg_write(udev, 0x13, 0xf0);
259 sccb_reg_write(udev, 0x0d, 0x41);
260 sccb_reg_write(udev, 0x0f, 0xc5);
261 sccb_reg_write(udev, 0x14, 0x11);
262
263 ov534_set_led(udev, 1);
264
265 sccb_reg_write(udev, 0x22, 0x7f);
266 sccb_reg_write(udev, 0x23, 0x03);
267 sccb_reg_write(udev, 0x24, 0x40);
268 sccb_reg_write(udev, 0x25, 0x30);
269 sccb_reg_write(udev, 0x26, 0xa1);
270 sccb_reg_write(udev, 0x2a, 0x00);
271 sccb_reg_write(udev, 0x2b, 0x00);
272 sccb_reg_write(udev, 0x6b, 0xaa);
273 sccb_reg_write(udev, 0x13, 0xff);
274
275 ov534_set_led(udev, 0);
276
277 sccb_reg_write(udev, 0x90, 0x05);
278 sccb_reg_write(udev, 0x91, 0x01);
279 sccb_reg_write(udev, 0x92, 0x03);
280 sccb_reg_write(udev, 0x93, 0x00);
281 sccb_reg_write(udev, 0x94, 0x60);
282 sccb_reg_write(udev, 0x95, 0x3c);
283 sccb_reg_write(udev, 0x96, 0x24);
284 sccb_reg_write(udev, 0x97, 0x1e);
285 sccb_reg_write(udev, 0x98, 0x62);
286 sccb_reg_write(udev, 0x99, 0x80);
287 sccb_reg_write(udev, 0x9a, 0x1e);
288 sccb_reg_write(udev, 0x9b, 0x08);
289 sccb_reg_write(udev, 0x9c, 0x20);
290 sccb_reg_write(udev, 0x9e, 0x81);
291
292 ov534_set_led(udev, 1);
293
294 sccb_reg_write(udev, 0xa6, 0x04);
295 sccb_reg_write(udev, 0x7e, 0x0c);
296 sccb_reg_write(udev, 0x7f, 0x16);
297 sccb_reg_write(udev, 0x80, 0x2a);
298 sccb_reg_write(udev, 0x81, 0x4e);
299 sccb_reg_write(udev, 0x82, 0x61);
300 sccb_reg_write(udev, 0x83, 0x6f);
301 sccb_reg_write(udev, 0x84, 0x7b);
302 sccb_reg_write(udev, 0x85, 0x86);
303 sccb_reg_write(udev, 0x86, 0x8e);
304 sccb_reg_write(udev, 0x87, 0x97);
305 sccb_reg_write(udev, 0x88, 0xa4);
306 sccb_reg_write(udev, 0x89, 0xaf);
307 sccb_reg_write(udev, 0x8a, 0xc5);
308 sccb_reg_write(udev, 0x8b, 0xd7);
309 sccb_reg_write(udev, 0x8c, 0xe8);
310 sccb_reg_write(udev, 0x8d, 0x20);
311
312 sccb_reg_write(udev, 0x0c, 0x90);
313
314 ov534_reg_verify_write(udev, 0xc0, 0x50);
315 ov534_reg_verify_write(udev, 0xc1, 0x3c);
316 ov534_reg_verify_write(udev, 0xc2, 0x0c);
317
318 ov534_set_led(udev, 1);
319
320 sccb_reg_write(udev, 0x2b, 0x00);
321 sccb_reg_write(udev, 0x22, 0x7f);
322 sccb_reg_write(udev, 0x23, 0x03);
323 sccb_reg_write(udev, 0x11, 0x01);
324 sccb_reg_write(udev, 0x0c, 0xd0);
325 sccb_reg_write(udev, 0x64, 0xff);
326 sccb_reg_write(udev, 0x0d, 0x41);
327
328 sccb_reg_write(udev, 0x14, 0x41);
329 sccb_reg_write(udev, 0x0e, 0xcd);
330 sccb_reg_write(udev, 0xac, 0xbf);
331 sccb_reg_write(udev, 0x8e, 0x00);
332 sccb_reg_write(udev, 0x0c, 0xd0);
333
334 ov534_reg_write(udev, 0xe0, 0x09);
335 ov534_set_led(udev, 0);
336}
337
338/* this function is called at probe time */
339static int sd_config(struct gspca_dev *gspca_dev,
340 const struct usb_device_id *id)
341{
342 struct cam *cam;
343
344 cam = &gspca_dev->cam;
345
346 cam->epaddr = 0x01;
347 cam->cam_mode = vga_mode;
348 cam->nmodes = ARRAY_SIZE(vga_mode);
349
350 cam->bulk_size = vga_mode[0].sizeimage;
351 cam->bulk_nurbs = 2;
352
353 PDEBUG(D_PROBE, "bulk_size = %d", cam->bulk_size);
354
355 return 0;
356}
357
358/* this function is called at probe and resume time */
359static int sd_init(struct gspca_dev *gspca_dev)
360{
361 struct sd *sd = (struct sd *)gspca_dev;
362 ov534_setup(gspca_dev->dev);
363
364 if (frame_rate > 0)
365 sd->frame_rate = frame_rate;
366
367 PDEBUG(D_PROBE, "frame_rate = %d", sd->frame_rate);
368
369 switch (sd->frame_rate) {
370 case 50:
371 sccb_reg_write(gspca_dev->dev, 0x11, 0x01);
372 sccb_check_status(gspca_dev->dev);
373 sccb_reg_write(gspca_dev->dev, 0x0d, 0x41);
374 sccb_check_status(gspca_dev->dev);
375 ov534_reg_verify_write(gspca_dev->dev, 0xe5, 0x02);
376 break;
377 case 40:
378 sccb_reg_write(gspca_dev->dev, 0x11, 0x02);
379 sccb_check_status(gspca_dev->dev);
380 sccb_reg_write(gspca_dev->dev, 0x0d, 0xc1);
381 sccb_check_status(gspca_dev->dev);
382 ov534_reg_verify_write(gspca_dev->dev, 0xe5, 0x04);
383 break;
384 case 30:
385 default:
386 sccb_reg_write(gspca_dev->dev, 0x11, 0x04);
387 sccb_check_status(gspca_dev->dev);
388 sccb_reg_write(gspca_dev->dev, 0x0d, 0x81);
389 sccb_check_status(gspca_dev->dev);
390 ov534_reg_verify_write(gspca_dev->dev, 0xe5, 0x02);
391 break;
392 case 15:
393 sccb_reg_write(gspca_dev->dev, 0x11, 0x03);
394 sccb_check_status(gspca_dev->dev);
395 sccb_reg_write(gspca_dev->dev, 0x0d, 0x41);
396 sccb_check_status(gspca_dev->dev);
397 ov534_reg_verify_write(gspca_dev->dev, 0xe5, 0x04);
398 break;
399 };
400
401 return 0;
402}
403
404static int sd_start(struct gspca_dev *gspca_dev)
405{
406 PDEBUG(D_PROBE, "width = %d, height = %d",
407 gspca_dev->width, gspca_dev->height);
408
409 gspca_dev->cam.bulk_size = gspca_dev->width * gspca_dev->height * 2;
410
411 /* start streaming data */
412 ov534_set_led(gspca_dev->dev, 1);
413 ov534_reg_write(gspca_dev->dev, 0xe0, 0x00);
414
415 return 0;
416}
417
418static void sd_stopN(struct gspca_dev *gspca_dev)
419{
420 /* stop streaming data */
421 ov534_reg_write(gspca_dev->dev, 0xe0, 0x09);
422 ov534_set_led(gspca_dev->dev, 0);
423}
424
425static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame,
426 __u8 *data, int len)
427{
428 /*
429 * The current camera setup doesn't stream the last pixel, so we set it
430 * to a dummy value
431 */
432 __u8 last_pixel[4] = { 0, 0, 0, 0 };
433 int framesize = gspca_dev->cam.bulk_size;
434
435 if (len == framesize - 4) {
436 frame =
437 gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len);
438 frame =
439 gspca_frame_add(gspca_dev, LAST_PACKET, frame, last_pixel,
440 4);
441 } else
442 PDEBUG(D_PACK, "packet len = %d, framesize = %d", len,
443 framesize);
444}
445
446/* sub-driver description */
447static const struct sd_desc sd_desc = {
448 .name = MODULE_NAME,
449 .ctrls = sd_ctrls,
450 .nctrls = ARRAY_SIZE(sd_ctrls),
451 .config = sd_config,
452 .init = sd_init,
453 .start = sd_start,
454 .stopN = sd_stopN,
455 .pkt_scan = sd_pkt_scan,
456};
457
458/* -- module initialisation -- */
459static const __devinitdata struct usb_device_id device_table[] = {
460 {USB_DEVICE(0x06f8, 0x3002)}, /* Hercules Blog Webcam */
461 {USB_DEVICE(0x06f8, 0x3003)}, /* Hercules Dualpix HD Weblog */
462 {USB_DEVICE(0x1415, 0x2000)}, /* Sony HD Eye for PS3 (SLEH 00201) */
463 {}
464};
465
466MODULE_DEVICE_TABLE(usb, device_table);
467
468/* -- device connect -- */
469static int sd_probe(struct usb_interface *intf, const struct usb_device_id *id)
470{
471 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
472 THIS_MODULE);
473}
474
475static struct usb_driver sd_driver = {
476 .name = MODULE_NAME,
477 .id_table = device_table,
478 .probe = sd_probe,
479 .disconnect = gspca_disconnect,
480#ifdef CONFIG_PM
481 .suspend = gspca_suspend,
482 .resume = gspca_resume,
483#endif
484};
485
486/* -- module insert / remove -- */
487static int __init sd_mod_init(void)
488{
489 if (usb_register(&sd_driver) < 0)
490 return -1;
491 PDEBUG(D_PROBE, "registered");
492 return 0;
493}
494
495static void __exit sd_mod_exit(void)
496{
497 usb_deregister(&sd_driver);
498 PDEBUG(D_PROBE, "deregistered");
499}
500
501module_init(sd_mod_init);
502module_exit(sd_mod_exit);
503
504module_param(frame_rate, int, 0644);
505MODULE_PARM_DESC(frame_rate, "Frame rate (15, 30, 40, 50)");