1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57#include <linux/module.h>
58#include <linux/init.h>
59#include <linux/delay.h>
60#include <linux/videodev.h>
61#include <media/v4l2-common.h>
62#include <media/v4l2-ioctl.h>
63#include <linux/parport.h>
64
65
66
67#ifdef DEBUG
68#define DPRINTF(x, a...) printk(KERN_DEBUG "W9966: %s(): "x, __func__ , ##a)
69#else
70#define DPRINTF(x...)
71#endif
72
73
74
75
76
77#define W9966_DRIVERNAME "W9966CF Webcam"
78#define W9966_MAXCAMS 4
79#define W9966_RBUFFER 2048
80#define W9966_SRAMSIZE 131072
81#define W9966_SRAMID 0x02
82
83
84#define W9966_WND_MIN_X 16
85#define W9966_WND_MIN_Y 14
86#define W9966_WND_MAX_X 705
87#define W9966_WND_MAX_Y 253
88#define W9966_WND_MAX_W (W9966_WND_MAX_X - W9966_WND_MIN_X)
89#define W9966_WND_MAX_H (W9966_WND_MAX_Y - W9966_WND_MIN_Y)
90
91
92#define W9966_STATE_PDEV 0x01
93#define W9966_STATE_CLAIMED 0x02
94#define W9966_STATE_VDEV 0x04
95
96#define W9966_I2C_W_ID 0x48
97#define W9966_I2C_R_ID 0x49
98#define W9966_I2C_R_DATA 0x08
99#define W9966_I2C_R_CLOCK 0x04
100#define W9966_I2C_W_DATA 0x02
101#define W9966_I2C_W_CLOCK 0x01
102
103struct w9966_dev {
104 unsigned char dev_state;
105 unsigned char i2c_state;
106 unsigned short ppmode;
107 struct parport* pport;
108 struct pardevice* pdev;
109 struct video_device vdev;
110 unsigned short width;
111 unsigned short height;
112 unsigned char brightness;
113 signed char contrast;
114 signed char color;
115 signed char hue;
116 unsigned long in_use;
117};
118
119
120
121
122
123MODULE_AUTHOR("Jakob Kemi <jakob.kemi@post.utfors.se>");
124MODULE_DESCRIPTION("Winbond w9966cf WebCam driver (0.32)");
125MODULE_LICENSE("GPL");
126
127
128#ifdef MODULE
129static const char* pardev[] = {[0 ... W9966_MAXCAMS] = ""};
130#else
131static const char* pardev[] = {[0 ... W9966_MAXCAMS] = "aggressive"};
132#endif
133module_param_array(pardev, charp, NULL, 0);
134MODULE_PARM_DESC(pardev, "pardev: where to search for\n\
135\teach camera. 'aggressive' means brute-force search.\n\
136\tEg: >pardev=parport3,aggressive,parport2,parport1< would assign\n\
137\tcam 1 to parport3 and search every parport for cam 2 etc...");
138
139static int parmode;
140module_param(parmode, int, 0);
141MODULE_PARM_DESC(parmode, "parmode: transfer mode (0=auto, 1=ecp, 2=epp");
142
143static int video_nr = -1;
144module_param(video_nr, int, 0);
145
146
147
148
149
150static struct w9966_dev w9966_cams[W9966_MAXCAMS];
151
152
153
154
155
156static inline void w9966_setState(struct w9966_dev* cam, int mask, int val);
157static inline int w9966_getState(struct w9966_dev* cam, int mask, int val);
158static inline void w9966_pdev_claim(struct w9966_dev *vdev);
159static inline void w9966_pdev_release(struct w9966_dev *vdev);
160
161static int w9966_rReg(struct w9966_dev* cam, int reg);
162static int w9966_wReg(struct w9966_dev* cam, int reg, int data);
163#if 0
164static int w9966_rReg_i2c(struct w9966_dev* cam, int reg);
165#endif
166static int w9966_wReg_i2c(struct w9966_dev* cam, int reg, int data);
167static int w9966_findlen(int near, int size, int maxlen);
168static int w9966_calcscale(int size, int min, int max, int* beg, int* end, unsigned char* factor);
169static int w9966_setup(struct w9966_dev* cam, int x1, int y1, int x2, int y2, int w, int h);
170
171static int w9966_init(struct w9966_dev* cam, struct parport* port);
172static void w9966_term(struct w9966_dev* cam);
173
174static inline void w9966_i2c_setsda(struct w9966_dev* cam, int state);
175static inline int w9966_i2c_setscl(struct w9966_dev* cam, int state);
176static inline int w9966_i2c_getsda(struct w9966_dev* cam);
177static inline int w9966_i2c_getscl(struct w9966_dev* cam);
178static int w9966_i2c_wbyte(struct w9966_dev* cam, int data);
179#if 0
180static int w9966_i2c_rbyte(struct w9966_dev* cam);
181#endif
182
183static long w9966_v4l_ioctl(struct file *file,
184 unsigned int cmd, unsigned long arg);
185static ssize_t w9966_v4l_read(struct file *file, char __user *buf,
186 size_t count, loff_t *ppos);
187
188static int w9966_exclusive_open(struct file *file)
189{
190 struct w9966_dev *cam = video_drvdata(file);
191
192 return test_and_set_bit(0, &cam->in_use) ? -EBUSY : 0;
193}
194
195static int w9966_exclusive_release(struct file *file)
196{
197 struct w9966_dev *cam = video_drvdata(file);
198
199 clear_bit(0, &cam->in_use);
200 return 0;
201}
202
203static const struct v4l2_file_operations w9966_fops = {
204 .owner = THIS_MODULE,
205 .open = w9966_exclusive_open,
206 .release = w9966_exclusive_release,
207 .ioctl = w9966_v4l_ioctl,
208 .read = w9966_v4l_read,
209};
210static struct video_device w9966_template = {
211 .name = W9966_DRIVERNAME,
212 .fops = &w9966_fops,
213 .release = video_device_release_empty,
214};
215
216
217
218
219
220
221
222static inline void w9966_setState(struct w9966_dev* cam, int mask, int val)
223{
224 cam->dev_state = (cam->dev_state & ~mask) ^ val;
225}
226
227
228static inline int w9966_getState(struct w9966_dev* cam, int mask, int val)
229{
230 return ((cam->dev_state & mask) == val);
231}
232
233
234static inline void w9966_pdev_claim(struct w9966_dev* cam)
235{
236 if (w9966_getState(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED))
237 return;
238 parport_claim_or_block(cam->pdev);
239 w9966_setState(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED);
240}
241
242
243static inline void w9966_pdev_release(struct w9966_dev* cam)
244{
245 if (w9966_getState(cam, W9966_STATE_CLAIMED, 0))
246 return;
247 parport_release(cam->pdev);
248 w9966_setState(cam, W9966_STATE_CLAIMED, 0);
249}
250
251
252
253
254static int w9966_rReg(struct w9966_dev* cam, int reg)
255{
256
257 const unsigned char addr = 0x80 | (reg & 0x1f);
258 unsigned char val;
259
260 if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0)
261 return -1;
262 if (parport_write(cam->pport, &addr, 1) != 1)
263 return -1;
264 if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0)
265 return -1;
266 if (parport_read(cam->pport, &val, 1) != 1)
267 return -1;
268
269 return val;
270}
271
272
273
274
275static int w9966_wReg(struct w9966_dev* cam, int reg, int data)
276{
277
278 const unsigned char addr = 0xc0 | (reg & 0x1f);
279 const unsigned char val = data;
280
281 if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0)
282 return -1;
283 if (parport_write(cam->pport, &addr, 1) != 1)
284 return -1;
285 if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0)
286 return -1;
287 if (parport_write(cam->pport, &val, 1) != 1)
288 return -1;
289
290 return 0;
291}
292
293
294
295
296
297static int w9966_init(struct w9966_dev* cam, struct parport* port)
298{
299 if (cam->dev_state != 0)
300 return -1;
301
302 cam->pport = port;
303 cam->brightness = 128;
304 cam->contrast = 64;
305 cam->color = 64;
306 cam->hue = 0;
307
308
309 switch(parmode)
310 {
311 default:
312 case 0:
313 if (port->modes & PARPORT_MODE_ECP)
314 cam->ppmode = IEEE1284_MODE_ECP;
315 else if (port->modes & PARPORT_MODE_EPP)
316 cam->ppmode = IEEE1284_MODE_EPP;
317 else
318 cam->ppmode = IEEE1284_MODE_ECP;
319 break;
320 case 1:
321 cam->ppmode = IEEE1284_MODE_ECP;
322 break;
323 case 2:
324 cam->ppmode = IEEE1284_MODE_EPP;
325 break;
326 }
327
328
329 cam->pdev = parport_register_device(port, "w9966", NULL, NULL, NULL, 0, NULL);
330 if (cam->pdev == NULL) {
331 DPRINTF("parport_register_device() failed\n");
332 return -1;
333 }
334 w9966_setState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV);
335
336 w9966_pdev_claim(cam);
337
338
339 if (w9966_setup(cam, 0, 0, 1023, 1023, 200, 160) != 0) {
340 DPRINTF("w9966_setup() failed.\n");
341 return -1;
342 }
343
344 w9966_pdev_release(cam);
345
346
347 memcpy(&cam->vdev, &w9966_template, sizeof(struct video_device));
348 video_set_drvdata(&cam->vdev, cam);
349
350 if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0)
351 return -1;
352
353 w9966_setState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV);
354
355
356 printk(
357 "w9966cf: Found and initialized a webcam on %s.\n",
358 cam->pport->name
359 );
360 return 0;
361}
362
363
364
365static void w9966_term(struct w9966_dev* cam)
366{
367
368 if (w9966_getState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV)) {
369 video_unregister_device(&cam->vdev);
370 w9966_setState(cam, W9966_STATE_VDEV, 0);
371 }
372
373
374 if (w9966_getState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) {
375 w9966_pdev_claim(cam);
376 parport_negotiate(cam->pport, IEEE1284_MODE_COMPAT);
377 w9966_pdev_release(cam);
378 }
379
380
381 if (w9966_getState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) {
382 parport_unregister_device(cam->pdev);
383 w9966_setState(cam, W9966_STATE_PDEV, 0);
384 }
385}
386
387
388
389
390
391static int w9966_findlen(int near, int size, int maxlen)
392{
393 int bestlen = size;
394 int besterr = abs(near - bestlen);
395 int len;
396
397 for(len = size+1;len < maxlen;len++)
398 {
399 int err;
400 if ( ((64*size) %len) != 0)
401 continue;
402
403 err = abs(near - len);
404
405
406 if (err > besterr)
407 break;
408
409 besterr = err;
410 bestlen = len;
411 }
412
413 return bestlen;
414}
415
416
417
418
419static int w9966_calcscale(int size, int min, int max, int* beg, int* end, unsigned char* factor)
420{
421 int maxlen = max - min;
422 int len = *end - *beg + 1;
423 int newlen = w9966_findlen(len, size, maxlen);
424 int err = newlen - len;
425
426
427 if (newlen > maxlen || newlen < size)
428 return -1;
429
430
431 *factor = (64*size) / newlen;
432 if (*factor == 64)
433 *factor = 0x00;
434 else
435 *factor |= 0x80;
436
437
438 *beg -= err / 2;
439 *end += err - (err / 2);
440
441
442 if (*beg < min) {
443 *end += min - *beg;
444 *beg += min - *beg;
445 }
446 if (*end > max) {
447 *beg -= *end - max;
448 *end -= *end - max;
449 }
450
451 return 0;
452}
453
454
455
456
457static int w9966_setup(struct w9966_dev* cam, int x1, int y1, int x2, int y2, int w, int h)
458{
459 unsigned int i;
460 unsigned int enh_s, enh_e;
461 unsigned char scale_x, scale_y;
462 unsigned char regs[0x1c];
463 unsigned char saa7111_regs[] = {
464 0x21, 0x00, 0xd8, 0x23, 0x00, 0x80, 0x80, 0x00,
465 0x88, 0x10, 0x80, 0x40, 0x40, 0x00, 0x01, 0x00,
466 0x48, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
467 0x00, 0x00, 0x00, 0x71, 0xe7, 0x00, 0x00, 0xc0
468 };
469
470
471 if (w*h*2 > W9966_SRAMSIZE)
472 {
473 DPRINTF("capture window exceeds SRAM size!.\n");
474 w = 200; h = 160;
475 }
476
477 w &= ~0x1;
478 if (w < 2) w = 2;
479 if (h < 1) h = 1;
480 if (w > W9966_WND_MAX_W) w = W9966_WND_MAX_W;
481 if (h > W9966_WND_MAX_H) h = W9966_WND_MAX_H;
482
483 cam->width = w;
484 cam->height = h;
485
486 enh_s = 0;
487 enh_e = w*h*2;
488
489
490 if (
491 w9966_calcscale(w, W9966_WND_MIN_X, W9966_WND_MAX_X, &x1, &x2, &scale_x) != 0 ||
492 w9966_calcscale(h, W9966_WND_MIN_Y, W9966_WND_MAX_Y, &y1, &y2, &scale_y) != 0
493 ) return -1;
494
495 DPRINTF(
496 "%dx%d, x: %d<->%d, y: %d<->%d, sx: %d/64, sy: %d/64.\n",
497 w, h, x1, x2, y1, y2, scale_x&~0x80, scale_y&~0x80
498 );
499
500
501 regs[0x00] = 0x00;
502 regs[0x01] = 0x18;
503 regs[0x02] = scale_y;
504 regs[0x03] = scale_x;
505
506
507 regs[0x04] = (x1 & 0x0ff);
508 regs[0x05] = (x1 & 0x300)>>8;
509 regs[0x06] = (y1 & 0x0ff);
510 regs[0x07] = (y1 & 0x300)>>8;
511 regs[0x08] = (x2 & 0x0ff);
512 regs[0x09] = (x2 & 0x300)>>8;
513 regs[0x0a] = (y2 & 0x0ff);
514
515 regs[0x0c] = W9966_SRAMID;
516
517
518 regs[0x0d] = (enh_s& 0x000ff);
519 regs[0x0e] = (enh_s& 0x0ff00)>>8;
520 regs[0x0f] = (enh_s& 0x70000)>>16;
521 regs[0x10] = (enh_e& 0x000ff);
522 regs[0x11] = (enh_e& 0x0ff00)>>8;
523 regs[0x12] = (enh_e& 0x70000)>>16;
524
525
526 regs[0x13] = 0x40;
527 regs[0x17] = 0x00;
528 regs[0x18] = cam->i2c_state = 0x00;
529 regs[0x19] = 0xff;
530 regs[0x1a] = 0xff;
531 regs[0x1b] = 0x10;
532
533
534 saa7111_regs[0x0a] = cam->brightness;
535 saa7111_regs[0x0b] = cam->contrast;
536 saa7111_regs[0x0c] = cam->color;
537 saa7111_regs[0x0d] = cam->hue;
538
539
540 if (w9966_wReg(cam, 0x00, 0x03) == -1)
541 return -1;
542
543
544 for (i = 0; i < 0x1c; i++)
545 if (w9966_wReg(cam, i, regs[i]) == -1)
546 return -1;
547
548
549 for (i = 0; i < 0x20; i++)
550 if (w9966_wReg_i2c(cam, i, saa7111_regs[i]) == -1)
551 return -1;
552
553 return 0;
554}
555
556
557
558
559
560
561
562static inline void w9966_i2c_setsda(struct w9966_dev* cam, int state)
563{
564 if (state)
565 cam->i2c_state |= W9966_I2C_W_DATA;
566 else
567 cam->i2c_state &= ~W9966_I2C_W_DATA;
568
569 w9966_wReg(cam, 0x18, cam->i2c_state);
570 udelay(5);
571}
572
573
574
575static inline int w9966_i2c_getscl(struct w9966_dev* cam)
576{
577 const unsigned char state = w9966_rReg(cam, 0x18);
578 return ((state & W9966_I2C_R_CLOCK) > 0);
579}
580
581
582
583static inline int w9966_i2c_setscl(struct w9966_dev* cam, int state)
584{
585 unsigned long timeout;
586
587 if (state)
588 cam->i2c_state |= W9966_I2C_W_CLOCK;
589 else
590 cam->i2c_state &= ~W9966_I2C_W_CLOCK;
591
592 w9966_wReg(cam, 0x18, cam->i2c_state);
593 udelay(5);
594
595
596 if (state) {
597 timeout = jiffies + 100;
598 while (!w9966_i2c_getscl(cam)) {
599 if (time_after(jiffies, timeout))
600 return -1;
601 }
602 }
603 return 0;
604}
605
606
607
608static inline int w9966_i2c_getsda(struct w9966_dev* cam)
609{
610 const unsigned char state = w9966_rReg(cam, 0x18);
611 return ((state & W9966_I2C_R_DATA) > 0);
612}
613
614
615
616static int w9966_i2c_wbyte(struct w9966_dev* cam, int data)
617{
618 int i;
619 for (i = 7; i >= 0; i--)
620 {
621 w9966_i2c_setsda(cam, (data >> i) & 0x01);
622
623 if (w9966_i2c_setscl(cam, 1) == -1)
624 return -1;
625 w9966_i2c_setscl(cam, 0);
626 }
627
628 w9966_i2c_setsda(cam, 1);
629
630 if (w9966_i2c_setscl(cam, 1) == -1)
631 return -1;
632 w9966_i2c_setscl(cam, 0);
633
634 return 0;
635}
636
637
638
639#if 0
640static int w9966_i2c_rbyte(struct w9966_dev* cam)
641{
642 unsigned char data = 0x00;
643 int i;
644
645 w9966_i2c_setsda(cam, 1);
646
647 for (i = 0; i < 8; i++)
648 {
649 if (w9966_i2c_setscl(cam, 1) == -1)
650 return -1;
651 data = data << 1;
652 if (w9966_i2c_getsda(cam))
653 data |= 0x01;
654
655 w9966_i2c_setscl(cam, 0);
656 }
657 return data;
658}
659#endif
660
661
662
663#if 0
664static int w9966_rReg_i2c(struct w9966_dev* cam, int reg)
665{
666 int data;
667
668 w9966_i2c_setsda(cam, 0);
669 w9966_i2c_setscl(cam, 0);
670
671 if (
672 w9966_i2c_wbyte(cam, W9966_I2C_W_ID) == -1 ||
673 w9966_i2c_wbyte(cam, reg) == -1
674 )
675 return -1;
676
677 w9966_i2c_setsda(cam, 1);
678 if (w9966_i2c_setscl(cam, 1) == -1)
679 return -1;
680 w9966_i2c_setsda(cam, 0);
681 w9966_i2c_setscl(cam, 0);
682
683 if (
684 w9966_i2c_wbyte(cam, W9966_I2C_R_ID) == -1 ||
685 (data = w9966_i2c_rbyte(cam)) == -1
686 )
687 return -1;
688
689 w9966_i2c_setsda(cam, 0);
690
691 if (w9966_i2c_setscl(cam, 1) == -1)
692 return -1;
693 w9966_i2c_setsda(cam, 1);
694
695 return data;
696}
697#endif
698
699
700
701static int w9966_wReg_i2c(struct w9966_dev* cam, int reg, int data)
702{
703 w9966_i2c_setsda(cam, 0);
704 w9966_i2c_setscl(cam, 0);
705
706 if (
707 w9966_i2c_wbyte(cam, W9966_I2C_W_ID) == -1 ||
708 w9966_i2c_wbyte(cam, reg) == -1 ||
709 w9966_i2c_wbyte(cam, data) == -1
710 )
711 return -1;
712
713 w9966_i2c_setsda(cam, 0);
714 if (w9966_i2c_setscl(cam, 1) == -1)
715 return -1;
716
717 w9966_i2c_setsda(cam, 1);
718
719 return 0;
720}
721
722
723
724
725
726static long w9966_v4l_do_ioctl(struct file *file, unsigned int cmd, void *arg)
727{
728 struct w9966_dev *cam = video_drvdata(file);
729
730 switch(cmd)
731 {
732 case VIDIOCGCAP:
733 {
734 static struct video_capability vcap = {
735 .name = W9966_DRIVERNAME,
736 .type = VID_TYPE_CAPTURE | VID_TYPE_SCALES,
737 .channels = 1,
738 .maxwidth = W9966_WND_MAX_W,
739 .maxheight = W9966_WND_MAX_H,
740 .minwidth = 2,
741 .minheight = 1,
742 };
743 struct video_capability *cap = arg;
744 *cap = vcap;
745 return 0;
746 }
747 case VIDIOCGCHAN:
748 {
749 struct video_channel *vch = arg;
750 if(vch->channel != 0)
751 return -EINVAL;
752 memset(vch,0,sizeof(*vch));
753 strcpy(vch->name, "CCD-input");
754 vch->type = VIDEO_TYPE_CAMERA;
755 return 0;
756 }
757 case VIDIOCSCHAN:
758 {
759 struct video_channel *vch = arg;
760 if(vch->channel != 0)
761 return -EINVAL;
762 return 0;
763 }
764 case VIDIOCGTUNER:
765 {
766 struct video_tuner *vtune = arg;
767 if(vtune->tuner != 0)
768 return -EINVAL;
769 strcpy(vtune->name, "no tuner");
770 vtune->rangelow = 0;
771 vtune->rangehigh = 0;
772 vtune->flags = VIDEO_TUNER_NORM;
773 vtune->mode = VIDEO_MODE_AUTO;
774 vtune->signal = 0xffff;
775 return 0;
776 }
777 case VIDIOCSTUNER:
778 {
779 struct video_tuner *vtune = arg;
780 if (vtune->tuner != 0)
781 return -EINVAL;
782 if (vtune->mode != VIDEO_MODE_AUTO)
783 return -EINVAL;
784 return 0;
785 }
786 case VIDIOCGPICT:
787 {
788 struct video_picture vpic = {
789 cam->brightness << 8,
790 (cam->hue + 128) << 8,
791 cam->color << 9,
792 cam->contrast << 9,
793 0x8000,
794 16, VIDEO_PALETTE_YUV422
795 };
796 struct video_picture *pic = arg;
797 *pic = vpic;
798 return 0;
799 }
800 case VIDIOCSPICT:
801 {
802 struct video_picture *vpic = arg;
803 if (vpic->depth != 16 || (vpic->palette != VIDEO_PALETTE_YUV422 && vpic->palette != VIDEO_PALETTE_YUYV))
804 return -EINVAL;
805
806 cam->brightness = vpic->brightness >> 8;
807 cam->hue = (vpic->hue >> 8) - 128;
808 cam->color = vpic->colour >> 9;
809 cam->contrast = vpic->contrast >> 9;
810
811 w9966_pdev_claim(cam);
812
813 if (
814 w9966_wReg_i2c(cam, 0x0a, cam->brightness) == -1 ||
815 w9966_wReg_i2c(cam, 0x0b, cam->contrast) == -1 ||
816 w9966_wReg_i2c(cam, 0x0c, cam->color) == -1 ||
817 w9966_wReg_i2c(cam, 0x0d, cam->hue) == -1
818 ) {
819 w9966_pdev_release(cam);
820 return -EIO;
821 }
822
823 w9966_pdev_release(cam);
824 return 0;
825 }
826 case VIDIOCSWIN:
827 {
828 int ret;
829 struct video_window *vwin = arg;
830
831 if (vwin->flags != 0)
832 return -EINVAL;
833 if (vwin->clipcount != 0)
834 return -EINVAL;
835 if (vwin->width < 2 || vwin->width > W9966_WND_MAX_W)
836 return -EINVAL;
837 if (vwin->height < 1 || vwin->height > W9966_WND_MAX_H)
838 return -EINVAL;
839
840
841 w9966_pdev_claim(cam);
842 ret = w9966_setup(cam, 0, 0, 1023, 1023, vwin->width, vwin->height);
843 w9966_pdev_release(cam);
844
845 if (ret != 0) {
846 DPRINTF("VIDIOCSWIN: w9966_setup() failed.\n");
847 return -EIO;
848 }
849
850 return 0;
851 }
852 case VIDIOCGWIN:
853 {
854 struct video_window *vwin = arg;
855 memset(vwin, 0, sizeof(*vwin));
856 vwin->width = cam->width;
857 vwin->height = cam->height;
858 return 0;
859 }
860
861 case VIDIOCCAPTURE:
862 case VIDIOCGFBUF:
863 case VIDIOCSFBUF:
864 case VIDIOCKEY:
865 case VIDIOCGFREQ:
866 case VIDIOCSFREQ:
867 case VIDIOCGAUDIO:
868 case VIDIOCSAUDIO:
869 return -EINVAL;
870 default:
871 return -ENOIOCTLCMD;
872 }
873 return 0;
874}
875
876static long w9966_v4l_ioctl(struct file *file,
877 unsigned int cmd, unsigned long arg)
878{
879 return video_usercopy(file, cmd, arg, w9966_v4l_do_ioctl);
880}
881
882
883static ssize_t w9966_v4l_read(struct file *file, char __user *buf,
884 size_t count, loff_t *ppos)
885{
886 struct w9966_dev *cam = video_drvdata(file);
887 unsigned char addr = 0xa0;
888 unsigned char __user *dest = (unsigned char __user *)buf;
889 unsigned long dleft = count;
890 unsigned char *tbuf;
891
892
893 if (count > cam->width * cam->height * 2)
894 return -EINVAL;
895
896 w9966_pdev_claim(cam);
897 w9966_wReg(cam, 0x00, 0x02);
898 w9966_wReg(cam, 0x00, 0x00);
899 w9966_wReg(cam, 0x01, 0x98);
900
901
902 if (
903 (parport_negotiate(cam->pport, cam->ppmode|IEEE1284_ADDR) != 0 )||
904 (parport_write(cam->pport, &addr, 1) != 1 )||
905 (parport_negotiate(cam->pport, cam->ppmode|IEEE1284_DATA) != 0 )
906 ) {
907 w9966_pdev_release(cam);
908 return -EFAULT;
909 }
910
911 tbuf = kmalloc(W9966_RBUFFER, GFP_KERNEL);
912 if (tbuf == NULL) {
913 count = -ENOMEM;
914 goto out;
915 }
916
917 while(dleft > 0)
918 {
919 unsigned long tsize = (dleft > W9966_RBUFFER) ? W9966_RBUFFER : dleft;
920
921 if (parport_read(cam->pport, tbuf, tsize) < tsize) {
922 count = -EFAULT;
923 goto out;
924 }
925 if (copy_to_user(dest, tbuf, tsize) != 0) {
926 count = -EFAULT;
927 goto out;
928 }
929 dest += tsize;
930 dleft -= tsize;
931 }
932
933 w9966_wReg(cam, 0x01, 0x18);
934
935out:
936 kfree(tbuf);
937 w9966_pdev_release(cam);
938
939 return count;
940}
941
942
943
944static void w9966_attach(struct parport *port)
945{
946 int i;
947
948 for (i = 0; i < W9966_MAXCAMS; i++)
949 {
950 if (w9966_cams[i].dev_state != 0)
951 continue;
952 if (
953 strcmp(pardev[i], "aggressive") == 0 ||
954 strcmp(pardev[i], port->name) == 0
955 ) {
956 if (w9966_init(&w9966_cams[i], port) != 0)
957 w9966_term(&w9966_cams[i]);
958 break;
959 }
960 }
961}
962
963
964static void w9966_detach(struct parport *port)
965{
966 int i;
967 for (i = 0; i < W9966_MAXCAMS; i++)
968 if (w9966_cams[i].dev_state != 0 && w9966_cams[i].pport == port)
969 w9966_term(&w9966_cams[i]);
970}
971
972
973static struct parport_driver w9966_ppd = {
974 .name = W9966_DRIVERNAME,
975 .attach = w9966_attach,
976 .detach = w9966_detach,
977};
978
979
980static int __init w9966_mod_init(void)
981{
982 int i;
983 for (i = 0; i < W9966_MAXCAMS; i++)
984 w9966_cams[i].dev_state = 0;
985
986 return parport_register_driver(&w9966_ppd);
987}
988
989
990static void __exit w9966_mod_term(void)
991{
992 parport_unregister_driver(&w9966_ppd);
993}
994
995module_init(w9966_mod_init);
996module_exit(w9966_mod_term);
997