~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/drivers/media/video/c-qcam.c

Version: ~ [ 2.2.5 ] ~ [ 2.4.1 ] ~ [ 2.4.9 ] ~ [ 2.6.17.10 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  *      Video4Linux Colour QuickCam driver
  3  *      Copyright 1997-2000 Philip Blundell <philb@gnu.org>
  4  *
  5  *    Module parameters:
  6  *
  7  *      parport=auto      -- probe all parports (default)
  8  *      parport=0         -- parport0 becomes qcam1
  9  *      parport=2,0,1     -- parports 2,0,1 are tried in that order
 10  *
 11  *      probe=0           -- do no probing, assume camera is present
 12  *      probe=1           -- use IEEE-1284 autoprobe data only (default)
 13  *      probe=2           -- probe aggressively for cameras
 14  *
 15  *      force_rgb=1       -- force data format to RGB (default is BGR)
 16  *
 17  * The parport parameter controls which parports will be scanned.
 18  * Scanning all parports causes some printers to print a garbage page.
 19  *       -- March 14, 1999  Billy Donahue <billy@escape.com> 
 20  *
 21  * Fixed data format to BGR, added force_rgb parameter. Added missing
 22  * parport_unregister_driver() on module removal.
 23  *       -- May 28, 2000  Claudio Matsuoka <claudio@conectiva.com>
 24  */
 25 
 26 #include <linux/module.h>
 27 #include <linux/delay.h>
 28 #include <linux/errno.h>
 29 #include <linux/fs.h>
 30 #include <linux/init.h>
 31 #include <linux/kernel.h>
 32 #include <linux/slab.h>
 33 #include <linux/mm.h>
 34 #include <linux/parport.h>
 35 #include <linux/sched.h>
 36 #include <linux/version.h>
 37 #include <linux/videodev.h>
 38 #include <asm/semaphore.h>
 39 #include <asm/uaccess.h>
 40 
 41 struct qcam_device {
 42         struct video_device vdev;
 43         struct pardevice *pdev;
 44         struct parport *pport;
 45         int width, height;
 46         int ccd_width, ccd_height;
 47         int mode;
 48         int contrast, brightness, whitebal;
 49         int top, left;
 50         unsigned int bidirectional;
 51         struct semaphore lock;
 52 };
 53 
 54 /* cameras maximum */
 55 #define MAX_CAMS 4
 56 
 57 /* The three possible QuickCam modes */
 58 #define QC_MILLIONS     0x18
 59 #define QC_BILLIONS     0x10
 60 #define QC_THOUSANDS    0x08    /* with VIDEC compression (not supported) */
 61 
 62 /* The three possible decimations */
 63 #define QC_DECIMATION_1         0
 64 #define QC_DECIMATION_2         2
 65 #define QC_DECIMATION_4         4
 66 
 67 #define BANNER "Colour QuickCam for Video4Linux v0.05"
 68 
 69 static int parport[MAX_CAMS] = { [1 ... MAX_CAMS-1] = -1 };
 70 static int probe = 2;
 71 static int force_rgb = 0;
 72 static int video_nr = -1;
 73 
 74 static inline void qcam_set_ack(struct qcam_device *qcam, unsigned int i)
 75 {
 76         /* note: the QC specs refer to the PCAck pin by voltage, not
 77            software level.  PC ports have builtin inverters. */
 78         parport_frob_control(qcam->pport, 8, i?8:0);
 79 }
 80 
 81 static inline unsigned int qcam_ready1(struct qcam_device *qcam)
 82 {
 83         return (parport_read_status(qcam->pport) & 0x8)?1:0;
 84 }
 85 
 86 static inline unsigned int qcam_ready2(struct qcam_device *qcam)
 87 {
 88         return (parport_read_data(qcam->pport) & 0x1)?1:0;
 89 }
 90 
 91 static unsigned int qcam_await_ready1(struct qcam_device *qcam, 
 92                                              int value)
 93 {
 94         unsigned long oldjiffies = jiffies;
 95         unsigned int i;
 96 
 97         for (oldjiffies = jiffies; (jiffies - oldjiffies) < (HZ/25); )
 98                 if (qcam_ready1(qcam) == value)
 99                         return 0;
100 
101         /* If the camera didn't respond within 1/25 second, poll slowly 
102            for a while. */
103         for (i = 0; i < 50; i++)
104         {
105                 if (qcam_ready1(qcam) == value)
106                         return 0;
107                 current->state=TASK_INTERRUPTIBLE;
108                 schedule_timeout(HZ/10);
109         }
110 
111         /* Probably somebody pulled the plug out.  Not much we can do. */
112         printk(KERN_ERR "c-qcam: ready1 timeout (%d) %x %x\n", value,
113                parport_read_status(qcam->pport),
114                parport_read_control(qcam->pport));
115         return 1;
116 }
117 
118 static unsigned int qcam_await_ready2(struct qcam_device *qcam, int value)
119 {
120         unsigned long oldjiffies = jiffies;
121         unsigned int i;
122 
123         for (oldjiffies = jiffies; (jiffies - oldjiffies) < (HZ/25); )
124                 if (qcam_ready2(qcam) == value)
125                         return 0;
126 
127         /* If the camera didn't respond within 1/25 second, poll slowly 
128            for a while. */
129         for (i = 0; i < 50; i++)
130         {
131                 if (qcam_ready2(qcam) == value)
132                         return 0;
133                 current->state=TASK_INTERRUPTIBLE;
134                 schedule_timeout(HZ/10);
135         }
136 
137         /* Probably somebody pulled the plug out.  Not much we can do. */
138         printk(KERN_ERR "c-qcam: ready2 timeout (%d) %x %x %x\n", value,
139                parport_read_status(qcam->pport),
140                parport_read_control(qcam->pport),
141                parport_read_data(qcam->pport));
142         return 1;
143 }
144 
145 static int qcam_read_data(struct qcam_device *qcam)
146 {
147         unsigned int idata;
148         qcam_set_ack(qcam, 0);
149         if (qcam_await_ready1(qcam, 1)) return -1;
150         idata = parport_read_status(qcam->pport) & 0xf0;
151         qcam_set_ack(qcam, 1);
152         if (qcam_await_ready1(qcam, 0)) return -1;
153         idata |= (parport_read_status(qcam->pport) >> 4);
154         return idata;
155 }
156 
157 static int qcam_write_data(struct qcam_device *qcam, unsigned int data)
158 {
159         unsigned int idata;
160         parport_write_data(qcam->pport, data);
161         idata = qcam_read_data(qcam);
162         if (data != idata) 
163         {
164                 printk(KERN_WARNING "cqcam: sent %x but received %x\n", data, 
165                        idata);
166                 return 1;
167         } 
168         return 0;
169 }
170 
171 static inline int qcam_set(struct qcam_device *qcam, unsigned int cmd, unsigned int data)
172 {
173         if (qcam_write_data(qcam, cmd))
174                 return -1;
175         if (qcam_write_data(qcam, data))
176                 return -1;
177         return 0;
178 }
179 
180 static inline int qcam_get(struct qcam_device *qcam, unsigned int cmd)
181 {
182         if (qcam_write_data(qcam, cmd))
183                 return -1;
184         return qcam_read_data(qcam);
185 }
186 
187 static int qc_detect(struct qcam_device *qcam)
188 {
189         unsigned int stat, ostat, i, count = 0;
190 
191         /* The probe routine below is not very reliable.  The IEEE-1284
192            probe takes precedence. */
193         /* XXX Currently parport provides no way to distinguish between
194            "the IEEE probe was not done" and "the probe was done, but
195            no device was found".  Fix this one day. */
196         if (qcam->pport->probe_info[0].class == PARPORT_CLASS_MEDIA
197             && qcam->pport->probe_info[0].model
198             && !strcmp(qcam->pdev->port->probe_info[0].model, 
199                        "Color QuickCam 2.0")) {
200                 printk(KERN_DEBUG "QuickCam: Found by IEEE1284 probe.\n");
201                 return 1;
202         }
203         
204         if (probe < 2)
205                 return 0;
206 
207         parport_write_control(qcam->pport, 0xc);
208 
209         /* look for a heartbeat */
210         ostat = stat = parport_read_status(qcam->pport);
211         for (i=0; i<250; i++) 
212         {
213                 mdelay(1);
214                 stat = parport_read_status(qcam->pport);
215                 if (ostat != stat) 
216                 {
217                         if (++count >= 3) return 1;
218                         ostat = stat;
219                 }
220         }
221 
222         /* Reset the camera and try again */
223         parport_write_control(qcam->pport, 0xc);
224         parport_write_control(qcam->pport, 0x8);
225         mdelay(1);
226         parport_write_control(qcam->pport, 0xc);
227         mdelay(1);
228         count = 0;
229 
230         ostat = stat = parport_read_status(qcam->pport);
231         for (i=0; i<250; i++) 
232         {
233                 mdelay(1);
234                 stat = parport_read_status(qcam->pport);
235                 if (ostat != stat) 
236                 {
237                         if (++count >= 3) return 1;
238                         ostat = stat;
239                 }
240         }
241 
242         /* no (or flatline) camera, give up */
243         return 0;
244 }
245 
246 static void qc_reset(struct qcam_device *qcam)
247 {
248         parport_write_control(qcam->pport, 0xc);
249         parport_write_control(qcam->pport, 0x8);
250         mdelay(1);
251         parport_write_control(qcam->pport, 0xc);
252         mdelay(1);          
253 }
254 
255 /* Reset the QuickCam and program for brightness, contrast,
256  * white-balance, and resolution. */
257 
258 static void qc_setup(struct qcam_device *q)
259 {
260         qc_reset(q);
261 
262         /* Set the brightness.  */
263         qcam_set(q, 11, q->brightness);
264 
265         /* Set the height and width.  These refer to the actual
266            CCD area *before* applying the selected decimation.  */
267         qcam_set(q, 17, q->ccd_height);
268         qcam_set(q, 19, q->ccd_width / 2);
269 
270         /* Set top and left.  */
271         qcam_set(q, 0xd, q->top);
272         qcam_set(q, 0xf, q->left);
273 
274         /* Set contrast and white balance.  */
275         qcam_set(q, 0x19, q->contrast);
276         qcam_set(q, 0x1f, q->whitebal);
277         
278         /* Set the speed.  */
279         qcam_set(q, 45, 2);
280 }
281 
282 /* Read some bytes from the camera and put them in the buffer. 
283    nbytes should be a multiple of 3, because bidirectional mode gives
284    us three bytes at a time.  */
285 
286 static unsigned int qcam_read_bytes(struct qcam_device *q, unsigned char *buf, unsigned int nbytes)
287 {
288         unsigned int bytes = 0;
289 
290         qcam_set_ack(q, 0);
291         if (q->bidirectional)
292         {
293                 /* It's a bidirectional port */
294                 while (bytes < nbytes)
295                 {
296                         unsigned int lo1, hi1, lo2, hi2;
297                         unsigned char r, g, b;
298 
299                         if (qcam_await_ready2(q, 1)) return bytes;
300                         lo1 = parport_read_data(q->pport) >> 1;
301                         hi1 = ((parport_read_status(q->pport) >> 3) & 0x1f) ^ 0x10;
302                         qcam_set_ack(q, 1);
303                         if (qcam_await_ready2(q, 0)) return bytes;
304                         lo2 = parport_read_data(q->pport) >> 1;
305                         hi2 = ((parport_read_status(q->pport) >> 3) & 0x1f) ^ 0x10;
306                         qcam_set_ack(q, 0);
307                         r = (lo1 | ((hi1 & 1)<<7));
308                         g = ((hi1 & 0x1e)<<3) | ((hi2 & 0x1e)>>1);
309                         b = (lo2 | ((hi2 & 1)<<7));
310                         if (force_rgb) {
311                                 buf[bytes++] = r;
312                                 buf[bytes++] = g;
313                                 buf[bytes++] = b;
314                         } else {
315                                 buf[bytes++] = b;
316                                 buf[bytes++] = g;
317                                 buf[bytes++] = r;
318                         }
319                 }
320         }
321         else
322         {
323                 /* It's a unidirectional port */
324                 int i = 0, n = bytes;
325                 unsigned char rgb[3];
326 
327                 while (bytes < nbytes)
328                 {
329                         unsigned int hi, lo;
330 
331                         if (qcam_await_ready1(q, 1)) return bytes;
332                         hi = (parport_read_status(q->pport) & 0xf0);
333                         qcam_set_ack(q, 1);
334                         if (qcam_await_ready1(q, 0)) return bytes;
335                         lo = (parport_read_status(q->pport) & 0xf0);
336                         qcam_set_ack(q, 0);
337                         /* flip some bits */
338                         rgb[(i = bytes++ % 3)] = (hi | (lo >> 4)) ^ 0x88;
339                         if (i >= 2) {
340 get_fragment:
341                                 if (force_rgb) {
342                                         buf[n++] = rgb[0];
343                                         buf[n++] = rgb[1];
344                                         buf[n++] = rgb[2];
345                                 } else {
346                                         buf[n++] = rgb[2];
347                                         buf[n++] = rgb[1];
348                                         buf[n++] = rgb[0];
349                                 }
350                         }
351                 }
352                 if (i) {
353                         i = 0;
354                         goto get_fragment;
355                 }
356         }
357         return bytes;
358 }
359 
360 #define BUFSZ   150
361 
362 static long qc_capture(struct qcam_device *q, char *buf, unsigned long len)
363 {
364         unsigned lines, pixelsperline, bitsperxfer;
365         unsigned int is_bi_dir = q->bidirectional;
366         size_t wantlen, outptr = 0;
367         char tmpbuf[BUFSZ];
368 
369         if (verify_area(VERIFY_WRITE, buf, len))
370                 return -EFAULT;
371 
372         /* Wait for camera to become ready */
373         for (;;)
374         {
375                 int i = qcam_get(q, 41);
376                 if (i == -1) {
377                         qc_setup(q);
378                         return -EIO;
379                 }
380                 if ((i & 0x80) == 0)
381                         break;
382                 else
383                         schedule();
384         }
385 
386         if (qcam_set(q, 7, (q->mode | (is_bi_dir?1:0)) + 1))
387                 return -EIO;
388         
389         lines = q->height;
390         pixelsperline = q->width;
391         bitsperxfer = (is_bi_dir) ? 24 : 8;
392 
393         if (is_bi_dir)
394         {
395                 /* Turn the port around */
396                 parport_data_reverse(q->pport);
397                 mdelay(3);
398                 qcam_set_ack(q, 0);
399                 if (qcam_await_ready1(q, 1)) {
400                         qc_setup(q);
401                         return -EIO;
402                 }
403                 qcam_set_ack(q, 1);
404                 if (qcam_await_ready1(q, 0)) {
405                         qc_setup(q);
406                         return -EIO;
407                 }
408         }
409 
410         wantlen = lines * pixelsperline * 24 / 8;
411 
412         while (wantlen)
413         {
414                 size_t t, s;
415                 s = (wantlen > BUFSZ)?BUFSZ:wantlen;
416                 t = qcam_read_bytes(q, tmpbuf, s);
417                 if (outptr < len)
418                 {
419                         size_t sz = len - outptr;
420                         if (sz > t) sz = t;
421                         if (__copy_to_user(buf+outptr, tmpbuf, sz))
422                                 break;
423                         outptr += sz;
424                 }
425                 wantlen -= t;
426                 if (t < s)
427                         break;
428                 if (current->need_resched)
429                         schedule();
430         }
431 
432         len = outptr;
433 
434         if (wantlen)
435         {
436                 printk("qcam: short read.\n");
437                 if (is_bi_dir)
438                         parport_data_forward(q->pport);
439                 qc_setup(q);
440                 return len;
441         }
442 
443         if (is_bi_dir)
444         {
445                 int l;
446                 do {
447                         l = qcam_read_bytes(q, tmpbuf, 3);
448                         if (current->need_resched)
449                                 schedule();
450                 } while (l && (tmpbuf[0] == 0x7e || tmpbuf[1] == 0x7e || tmpbuf[2] == 0x7e));
451                 if (force_rgb) {
452                         if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
453                                 printk("qcam: bad EOF\n");
454                 } else {
455                         if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe)
456                                 printk("qcam: bad EOF\n");
457                 }
458                 qcam_set_ack(q, 0);
459                 if (qcam_await_ready1(q, 1))
460                 {
461                         printk("qcam: no ack after EOF\n");
462                         parport_data_forward(q->pport);
463                         qc_setup(q);
464                         return len;
465                 }
466                 parport_data_forward(q->pport);
467                 mdelay(3);
468                 qcam_set_ack(q, 1);
469                 if (qcam_await_ready1(q, 0))
470                 {
471                         printk("qcam: no ack to port turnaround\n");
472                         qc_setup(q);
473                         return len;
474                 }
475         }
476         else
477         {
478                 int l;
479                 do {
480                         l = qcam_read_bytes(q, tmpbuf, 1);
481                         if (current->need_resched)
482                                 schedule();
483                 } while (l && tmpbuf[0] == 0x7e);
484                 l = qcam_read_bytes(q, tmpbuf+1, 2);
485                 if (force_rgb) {
486                         if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
487                                 printk("qcam: bad EOF\n");
488                 } else {
489                         if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe)
490                                 printk("qcam: bad EOF\n");
491                 }
492         }
493 
494         qcam_write_data(q, 0);
495         return len;
496 }
497 
498 /*
499  *      Video4linux interfacing
500  */
501 
502 static int qcam_open(struct video_device *dev, int flags)
503 {
504         return 0;
505 }
506 
507 static void qcam_close(struct video_device *dev)
508 {
509 }
510 
511 static long qcam_write(struct video_device *v, const char *buf, unsigned long count, int noblock)
512 {
513         return -EINVAL;
514 }
515 
516 static int qcam_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
517 {
518         struct qcam_device *qcam=(struct qcam_device *)dev;
519         
520         switch(cmd)
521         {
522                 case VIDIOCGCAP:
523                 {
524                         struct video_capability b;
525                         strcpy(b.name, "Quickcam");
526                         b.type = VID_TYPE_CAPTURE|VID_TYPE_SCALES;
527                         b.channels = 1;
528                         b.audios = 0;
529                         b.maxwidth = 320;
530                         b.maxheight = 240;
531                         b.minwidth = 80;
532                         b.minheight = 60;
533                         if(copy_to_user(arg, &b,sizeof(b)))
534                                 return -EFAULT;
535                         return 0;
536                 }
537                 case VIDIOCGCHAN:
538                 {
539                         struct video_channel v;
540                         if(copy_from_user(&v, arg, sizeof(v)))
541                                 return -EFAULT;
542                         if(v.channel!=0)
543                                 return -EINVAL;
544                         v.flags=0;
545                         v.tuners=0;
546                         /* Good question.. its composite or SVHS so.. */
547                         v.type = VIDEO_TYPE_CAMERA;
548                         strcpy(v.name, "Camera");
549                         if(copy_to_user(arg, &v, sizeof(v)))
550                                 return -EFAULT;
551                         return 0;
552                 }
553                 case VIDIOCSCHAN:
554                 {
555                         int v;
556                         if(copy_from_user(&v, arg,sizeof(v)))
557                                 return -EFAULT;
558                         if(v!=0)
559                                 return -EINVAL;
560                         return 0;
561                 }
562                 case VIDIOCGTUNER:
563                 {
564                         struct video_tuner v;
565                         if(copy_from_user(&v, arg, sizeof(v))!=0)
566                                 return -EFAULT;
567                         if(v.tuner)
568                                 return -EINVAL;
569                         strcpy(v.name, "Format");
570                         v.rangelow=0;
571                         v.rangehigh=0;
572                         v.flags= 0;
573                         v.mode = VIDEO_MODE_AUTO;
574                         if(copy_to_user(arg,&v,sizeof(v))!=0)
575                                 return -EFAULT;
576                         return 0;
577                 }
578                 case VIDIOCSTUNER:
579                 {
580                         struct video_tuner v;
581                         if(copy_from_user(&v, arg, sizeof(v))!=0)
582                                 return -EFAULT;
583                         if(v.tuner)
584                                 return -EINVAL;
585                         if(v.mode!=VIDEO_MODE_AUTO)
586                                 return -EINVAL;
587                         return 0;
588                 }
589                 case VIDIOCGPICT:
590                 {
591                         struct video_picture p;
592                         p.colour=0x8000;
593                         p.hue=0x8000;
594                         p.brightness=qcam->brightness<<8;
595                         p.contrast=qcam->contrast<<8;
596                         p.whiteness=qcam->whitebal<<8;
597                         p.depth=24;
598                         p.palette=VIDEO_PALETTE_RGB24;
599                         if(copy_to_user(arg, &p, sizeof(p)))
600                                 return -EFAULT;
601                         return 0;
602                 }
603                 case VIDIOCSPICT:
604                 {
605                         struct video_picture p;
606                         if(copy_from_user(&p, arg, sizeof(p)))
607                                 return -EFAULT;
608 
609                         /*
610                          *      Sanity check args
611                          */
612                         if (p.depth != 24 || p.palette != VIDEO_PALETTE_RGB24)
613                                 return -EINVAL;
614                         
615                         /*
616                          *      Now load the camera.
617                          */
618                         qcam->brightness = p.brightness>>8;
619                         qcam->contrast = p.contrast>>8;
620                         qcam->whitebal = p.whiteness>>8;
621 
622                         down(&qcam->lock);                      
623                         parport_claim_or_block(qcam->pdev);
624                         qc_setup(qcam); 
625                         parport_release(qcam->pdev);
626                         up(&qcam->lock);
627                         return 0;
628                 }
629                 case VIDIOCSWIN:
630                 {
631                         struct video_window vw;
632 
633                         if(copy_from_user(&vw, arg,sizeof(vw)))
634                                 return -EFAULT;
635                         if(vw.flags)
636                                 return -EINVAL;
637                         if(vw.clipcount)
638                                 return -EINVAL;
639                         if(vw.height<60||vw.height>240)
640                                 return -EINVAL;
641                         if(vw.width<80||vw.width>320)
642                                 return -EINVAL;
643                                 
644                         qcam->width = 80;
645                         qcam->height = 60;
646                         qcam->mode = QC_DECIMATION_4;
647                         
648                         if(vw.width>=160 && vw.height>=120)
649                         {
650                                 qcam->width = 160;
651                                 qcam->height = 120;
652                                 qcam->mode = QC_DECIMATION_2;
653                         }
654                         if(vw.width>=320 && vw.height>=240)
655                         {
656                                 qcam->width = 320;
657                                 qcam->height = 240;
658                                 qcam->mode = QC_DECIMATION_1;
659                         }
660                         qcam->mode |= QC_MILLIONS;
661 #if 0
662                         if(vw.width>=640 && vw.height>=480)
663                         {
664                                 qcam->width = 640;
665                                 qcam->height = 480;
666                                 qcam->mode = QC_BILLIONS | QC_DECIMATION_1;
667                         }
668 #endif
669                         /* Ok we figured out what to use from our 
670                            wide choice */
671                         down(&qcam->lock);
672                         parport_claim_or_block(qcam->pdev);
673                         qc_setup(qcam);
674                         parport_release(qcam->pdev);
675                         up(&qcam->lock);
676                         return 0;
677                 }
678                 case VIDIOCGWIN:
679                 {
680                         struct video_window vw;
681                         memset(&vw, 0, sizeof(vw));
682                         vw.width=qcam->width;
683                         vw.height=qcam->height;
684                         if(copy_to_user(arg, &vw, sizeof(vw)))
685                                 return -EFAULT;
686                         return 0;
687                 }
688                 case VIDIOCCAPTURE:
689                         return -EINVAL;
690                 case VIDIOCGFBUF:
691                         return -EINVAL;
692                 case VIDIOCSFBUF:
693                         return -EINVAL;
694                 case VIDIOCKEY:
695                         return 0;
696                 case VIDIOCGFREQ:
697                         return -EINVAL;
698                 case VIDIOCSFREQ:
699                         return -EINVAL;
700                 case VIDIOCGAUDIO:
701                         return -EINVAL;
702                 case VIDIOCSAUDIO:
703                         return -EINVAL;
704                 default:
705                         return -ENOIOCTLCMD;
706         }
707         return 0;
708 }
709 
710 static long qcam_read(struct video_device *v, char *buf, unsigned long count,  int noblock)
711 {
712         struct qcam_device *qcam=(struct qcam_device *)v;
713         int len;
714 
715         down(&qcam->lock);
716         parport_claim_or_block(qcam->pdev);
717         /* Probably should have a semaphore against multiple users */
718         len = qc_capture(qcam, buf,count); 
719         parport_release(qcam->pdev);
720         up(&qcam->lock);
721         return len;
722 }
723 
724 /* video device template */
725 static struct video_device qcam_template=
726 {
727         owner:          THIS_MODULE,
728         name:           "Colour QuickCam",
729         type:           VID_TYPE_CAPTURE,
730         hardware:       VID_HARDWARE_QCAM_C,
731         open:           qcam_open,
732         close:          qcam_close,
733         read:           qcam_read,
734         write:          qcam_write,
735         ioctl:          qcam_ioctl,
736 };
737 
738 /* Initialize the QuickCam driver control structure. */
739 
740 static struct qcam_device *qcam_init(struct parport *port)
741 {
742         struct qcam_device *q;
743         
744         q = kmalloc(sizeof(struct qcam_device), GFP_KERNEL);
745         if(q==NULL)
746                 return NULL;
747 
748         q->pport = port;
749         q->pdev = parport_register_device(port, "c-qcam", NULL, NULL,
750                                           NULL, 0, NULL);
751 
752         q->bidirectional = (q->pport->modes & PARPORT_MODE_TRISTATE)?1:0;
753 
754         if (q->pdev == NULL) 
755         {
756                 printk(KERN_ERR "c-qcam: couldn't register for %s.\n",
757                        port->name);
758                 kfree(q);
759                 return NULL;
760         }
761         
762         memcpy(&q->vdev, &qcam_template, sizeof(qcam_template));
763 
764         init_MUTEX(&q->lock);
765         q->width = q->ccd_width = 320;
766         q->height = q->ccd_height = 240;
767         q->mode = QC_MILLIONS | QC_DECIMATION_1;
768         q->contrast = 192;
769         q->brightness = 240;
770         q->whitebal = 128;
771         q->top = 1;
772         q->left = 14;
773         return q;
774 }
775 
776 static struct qcam_device *qcams[MAX_CAMS];
777 static unsigned int num_cams = 0;
778 
779 int init_cqcam(struct parport *port)
780 {
781         struct qcam_device *qcam;
782 
783         if (parport[0] != -1)
784         {
785                 /* The user gave specific instructions */
786                 int i, found = 0;
787                 for (i = 0; i < MAX_CAMS && parport[i] != -1; i++)
788                 {
789                         if (parport[0] == port->number)
790                                 found = 1;
791                 }
792                 if (!found)
793                         return -ENODEV;
794         }
795 
796         if (num_cams == MAX_CAMS)
797                 return -ENOSPC;
798 
799         qcam = qcam_init(port);
800         if (qcam==NULL)
801                 return -ENODEV;
802                 
803         parport_claim_or_block(qcam->pdev);
804 
805         qc_reset(qcam);
806         
807         if (probe && qc_detect(qcam)==0)
808         {
809                 parport_release(qcam->pdev);
810                 parport_unregister_device(qcam->pdev);
811                 kfree(qcam);
812                 return -ENODEV;
813         }
814 
815         qc_setup(qcam);
816 
817         parport_release(qcam->pdev);
818         
819         if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr)==-1)
820         {
821                 printk(KERN_ERR "Unable to register Colour QuickCam on %s\n",
822                        qcam->pport->name);
823                 parport_unregister_device(qcam->pdev);
824                 kfree(qcam);
825                 return -ENODEV;
826         }
827 
828         printk(KERN_INFO "video%d: Colour QuickCam found on %s\n", 
829                qcam->vdev.minor, qcam->pport->name);
830         
831         qcams[num_cams++] = qcam;
832 
833         return 0;
834 }
835 
836 void close_cqcam(struct qcam_device *qcam)
837 {
838         video_unregister_device(&qcam->vdev);
839         parport_unregister_device(qcam->pdev);
840         kfree(qcam);
841 }
842 
843 static void cq_attach(struct parport *port)
844 {
845         init_cqcam(port);
846 }
847 
848 static void cq_detach(struct parport *port)
849 {
850         /* Write this some day. */
851 }
852 
853 static struct parport_driver cqcam_driver = {
854         "cqcam",
855         cq_attach,
856         cq_detach,
857         NULL
858 };
859 
860 static int __init cqcam_init (void)
861 {
862         printk(BANNER "\n");
863 
864         return parport_register_driver(&cqcam_driver);
865 }
866 
867 static void __exit cqcam_cleanup (void)
868 {
869         unsigned int i;
870 
871         for (i = 0; i < num_cams; i++)
872                 close_cqcam(qcams[i]);
873 
874         parport_unregister_driver(&cqcam_driver);
875 }
876 
877 MODULE_AUTHOR("Philip Blundell <philb@gnu.org>");
878 MODULE_DESCRIPTION(BANNER);
879 MODULE_PARM_DESC(parport ,"parport=<auto|n[,n]...> for port detection method\n\
880 probe=<0|1|2> for camera detection method\n\
881 force_rgb=<0|1> for RGB data format (default BGR)");
882 MODULE_PARM(parport, "1-" __MODULE_STRING(MAX_CAMS) "i");
883 MODULE_PARM(probe, "i");
884 MODULE_PARM(force_rgb, "i");
885 MODULE_PARM(video_nr,"i");
886 
887 module_init(cqcam_init);
888 module_exit(cqcam_cleanup);
889 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.