blob: 8f1dd88b32a6c5210269e4d11e8688d4bb9e8fb7 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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.
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -030019 * -- March 14, 1999 Billy Donahue <billy@escape.com>
Linus Torvalds1da177e2005-04-16 15:20:36 -070020 *
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/videodev.h>
Mauro Carvalho Chehab5e87efa2006-06-05 10:26:32 -030037#include <media/v4l2-common.h>
Hans Verkuil35ea11f2008-07-20 08:12:02 -030038#include <media/v4l2-ioctl.h>
Ingo Molnar3593cab2006-02-07 06:49:14 -020039#include <linux/mutex.h>
Julia Lawall168c6262008-04-16 16:13:15 -030040#include <linux/jiffies.h>
Ingo Molnar3593cab2006-02-07 06:49:14 -020041
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include <asm/uaccess.h>
43
44struct qcam_device {
45 struct video_device vdev;
46 struct pardevice *pdev;
47 struct parport *pport;
48 int width, height;
49 int ccd_width, ccd_height;
50 int mode;
51 int contrast, brightness, whitebal;
52 int top, left;
53 unsigned int bidirectional;
Hans Verkuil7d43cd52008-08-23 05:31:47 -030054 unsigned long in_use;
Ingo Molnar3593cab2006-02-07 06:49:14 -020055 struct mutex lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -070056};
57
58/* cameras maximum */
59#define MAX_CAMS 4
60
61/* The three possible QuickCam modes */
62#define QC_MILLIONS 0x18
63#define QC_BILLIONS 0x10
64#define QC_THOUSANDS 0x08 /* with VIDEC compression (not supported) */
65
66/* The three possible decimations */
67#define QC_DECIMATION_1 0
68#define QC_DECIMATION_2 2
69#define QC_DECIMATION_4 4
70
71#define BANNER "Colour QuickCam for Video4Linux v0.05"
72
73static int parport[MAX_CAMS] = { [1 ... MAX_CAMS-1] = -1 };
74static int probe = 2;
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -030075static int force_rgb;
Linus Torvalds1da177e2005-04-16 15:20:36 -070076static int video_nr = -1;
77
78static inline void qcam_set_ack(struct qcam_device *qcam, unsigned int i)
79{
80 /* note: the QC specs refer to the PCAck pin by voltage, not
81 software level. PC ports have builtin inverters. */
Hans Verkuil51224aa2010-03-22 04:33:56 -030082 parport_frob_control(qcam->pport, 8, i ? 8 : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070083}
84
85static inline unsigned int qcam_ready1(struct qcam_device *qcam)
86{
Hans Verkuil51224aa2010-03-22 04:33:56 -030087 return (parport_read_status(qcam->pport) & 0x8) ? 1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070088}
89
90static inline unsigned int qcam_ready2(struct qcam_device *qcam)
91{
Hans Verkuil51224aa2010-03-22 04:33:56 -030092 return (parport_read_data(qcam->pport) & 0x1) ? 1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070093}
94
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -030095static unsigned int qcam_await_ready1(struct qcam_device *qcam,
Linus Torvalds1da177e2005-04-16 15:20:36 -070096 int value)
97{
98 unsigned long oldjiffies = jiffies;
99 unsigned int i;
100
Julia Lawall168c6262008-04-16 16:13:15 -0300101 for (oldjiffies = jiffies;
Hans Verkuil51224aa2010-03-22 04:33:56 -0300102 time_before(jiffies, oldjiffies + msecs_to_jiffies(40));)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 if (qcam_ready1(qcam) == value)
104 return 0;
105
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300106 /* If the camera didn't respond within 1/25 second, poll slowly
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 for a while. */
Hans Verkuil51224aa2010-03-22 04:33:56 -0300108 for (i = 0; i < 50; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 if (qcam_ready1(qcam) == value)
110 return 0;
111 msleep_interruptible(100);
112 }
113
114 /* Probably somebody pulled the plug out. Not much we can do. */
115 printk(KERN_ERR "c-qcam: ready1 timeout (%d) %x %x\n", value,
116 parport_read_status(qcam->pport),
117 parport_read_control(qcam->pport));
118 return 1;
119}
120
121static unsigned int qcam_await_ready2(struct qcam_device *qcam, int value)
122{
123 unsigned long oldjiffies = jiffies;
124 unsigned int i;
125
Julia Lawall168c6262008-04-16 16:13:15 -0300126 for (oldjiffies = jiffies;
Hans Verkuil51224aa2010-03-22 04:33:56 -0300127 time_before(jiffies, oldjiffies + msecs_to_jiffies(40));)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 if (qcam_ready2(qcam) == value)
129 return 0;
130
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300131 /* If the camera didn't respond within 1/25 second, poll slowly
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 for a while. */
Hans Verkuil51224aa2010-03-22 04:33:56 -0300133 for (i = 0; i < 50; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 if (qcam_ready2(qcam) == value)
135 return 0;
136 msleep_interruptible(100);
137 }
138
139 /* Probably somebody pulled the plug out. Not much we can do. */
140 printk(KERN_ERR "c-qcam: ready2 timeout (%d) %x %x %x\n", value,
141 parport_read_status(qcam->pport),
142 parport_read_control(qcam->pport),
143 parport_read_data(qcam->pport));
144 return 1;
145}
146
147static int qcam_read_data(struct qcam_device *qcam)
148{
149 unsigned int idata;
Hans Verkuil51224aa2010-03-22 04:33:56 -0300150
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 qcam_set_ack(qcam, 0);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300152 if (qcam_await_ready1(qcam, 1))
153 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 idata = parport_read_status(qcam->pport) & 0xf0;
155 qcam_set_ack(qcam, 1);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300156 if (qcam_await_ready1(qcam, 0))
157 return -1;
158 idata |= parport_read_status(qcam->pport) >> 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 return idata;
160}
161
162static int qcam_write_data(struct qcam_device *qcam, unsigned int data)
163{
164 unsigned int idata;
Hans Verkuil51224aa2010-03-22 04:33:56 -0300165
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 parport_write_data(qcam->pport, data);
167 idata = qcam_read_data(qcam);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300168 if (data != idata) {
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300169 printk(KERN_WARNING "cqcam: sent %x but received %x\n", data,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 idata);
171 return 1;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300172 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 return 0;
174}
175
176static inline int qcam_set(struct qcam_device *qcam, unsigned int cmd, unsigned int data)
177{
178 if (qcam_write_data(qcam, cmd))
179 return -1;
180 if (qcam_write_data(qcam, data))
181 return -1;
182 return 0;
183}
184
185static inline int qcam_get(struct qcam_device *qcam, unsigned int cmd)
186{
187 if (qcam_write_data(qcam, cmd))
188 return -1;
189 return qcam_read_data(qcam);
190}
191
192static int qc_detect(struct qcam_device *qcam)
193{
194 unsigned int stat, ostat, i, count = 0;
195
196 /* The probe routine below is not very reliable. The IEEE-1284
197 probe takes precedence. */
198 /* XXX Currently parport provides no way to distinguish between
199 "the IEEE probe was not done" and "the probe was done, but
200 no device was found". Fix this one day. */
201 if (qcam->pport->probe_info[0].class == PARPORT_CLASS_MEDIA
202 && qcam->pport->probe_info[0].model
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300203 && !strcmp(qcam->pdev->port->probe_info[0].model,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 "Color QuickCam 2.0")) {
205 printk(KERN_DEBUG "QuickCam: Found by IEEE1284 probe.\n");
206 return 1;
207 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300208
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 if (probe < 2)
210 return 0;
211
212 parport_write_control(qcam->pport, 0xc);
213
214 /* look for a heartbeat */
215 ostat = stat = parport_read_status(qcam->pport);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300216 for (i = 0; i < 250; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 mdelay(1);
218 stat = parport_read_status(qcam->pport);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300219 if (ostat != stat) {
220 if (++count >= 3)
221 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 ostat = stat;
223 }
224 }
225
226 /* Reset the camera and try again */
227 parport_write_control(qcam->pport, 0xc);
228 parport_write_control(qcam->pport, 0x8);
229 mdelay(1);
230 parport_write_control(qcam->pport, 0xc);
231 mdelay(1);
232 count = 0;
233
234 ostat = stat = parport_read_status(qcam->pport);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300235 for (i = 0; i < 250; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 mdelay(1);
237 stat = parport_read_status(qcam->pport);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300238 if (ostat != stat) {
239 if (++count >= 3)
240 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 ostat = stat;
242 }
243 }
244
245 /* no (or flatline) camera, give up */
246 return 0;
247}
248
249static void qc_reset(struct qcam_device *qcam)
250{
251 parport_write_control(qcam->pport, 0xc);
252 parport_write_control(qcam->pport, 0x8);
253 mdelay(1);
254 parport_write_control(qcam->pport, 0xc);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300255 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256}
257
258/* Reset the QuickCam and program for brightness, contrast,
259 * white-balance, and resolution. */
260
261static void qc_setup(struct qcam_device *q)
262{
263 qc_reset(q);
264
Hans Verkuil51224aa2010-03-22 04:33:56 -0300265 /* Set the brightness. */
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300266 qcam_set(q, 11, q->brightness);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267
268 /* Set the height and width. These refer to the actual
269 CCD area *before* applying the selected decimation. */
270 qcam_set(q, 17, q->ccd_height);
271 qcam_set(q, 19, q->ccd_width / 2);
272
273 /* Set top and left. */
274 qcam_set(q, 0xd, q->top);
275 qcam_set(q, 0xf, q->left);
276
277 /* Set contrast and white balance. */
278 qcam_set(q, 0x19, q->contrast);
279 qcam_set(q, 0x1f, q->whitebal);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300280
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 /* Set the speed. */
282 qcam_set(q, 45, 2);
283}
284
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300285/* Read some bytes from the camera and put them in the buffer.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 nbytes should be a multiple of 3, because bidirectional mode gives
287 us three bytes at a time. */
288
289static unsigned int qcam_read_bytes(struct qcam_device *q, unsigned char *buf, unsigned int nbytes)
290{
291 unsigned int bytes = 0;
292
293 qcam_set_ack(q, 0);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300294 if (q->bidirectional) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 /* It's a bidirectional port */
Hans Verkuil51224aa2010-03-22 04:33:56 -0300296 while (bytes < nbytes) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 unsigned int lo1, hi1, lo2, hi2;
298 unsigned char r, g, b;
299
Hans Verkuil51224aa2010-03-22 04:33:56 -0300300 if (qcam_await_ready2(q, 1))
301 return bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 lo1 = parport_read_data(q->pport) >> 1;
303 hi1 = ((parport_read_status(q->pport) >> 3) & 0x1f) ^ 0x10;
304 qcam_set_ack(q, 1);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300305 if (qcam_await_ready2(q, 0))
306 return bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 lo2 = parport_read_data(q->pport) >> 1;
308 hi2 = ((parport_read_status(q->pport) >> 3) & 0x1f) ^ 0x10;
309 qcam_set_ack(q, 0);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300310 r = lo1 | ((hi1 & 1) << 7);
311 g = ((hi1 & 0x1e) << 3) | ((hi2 & 0x1e) >> 1);
312 b = lo2 | ((hi2 & 1) << 7);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 if (force_rgb) {
314 buf[bytes++] = r;
315 buf[bytes++] = g;
316 buf[bytes++] = b;
317 } else {
318 buf[bytes++] = b;
319 buf[bytes++] = g;
320 buf[bytes++] = r;
321 }
322 }
Hans Verkuil51224aa2010-03-22 04:33:56 -0300323 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 /* It's a unidirectional port */
325 int i = 0, n = bytes;
326 unsigned char rgb[3];
327
Hans Verkuil51224aa2010-03-22 04:33:56 -0300328 while (bytes < nbytes) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 unsigned int hi, lo;
330
Hans Verkuil51224aa2010-03-22 04:33:56 -0300331 if (qcam_await_ready1(q, 1))
332 return bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 hi = (parport_read_status(q->pport) & 0xf0);
334 qcam_set_ack(q, 1);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300335 if (qcam_await_ready1(q, 0))
336 return bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 lo = (parport_read_status(q->pport) & 0xf0);
338 qcam_set_ack(q, 0);
339 /* flip some bits */
340 rgb[(i = bytes++ % 3)] = (hi | (lo >> 4)) ^ 0x88;
341 if (i >= 2) {
342get_fragment:
343 if (force_rgb) {
344 buf[n++] = rgb[0];
345 buf[n++] = rgb[1];
346 buf[n++] = rgb[2];
347 } else {
348 buf[n++] = rgb[2];
349 buf[n++] = rgb[1];
350 buf[n++] = rgb[0];
351 }
352 }
353 }
354 if (i) {
355 i = 0;
356 goto get_fragment;
357 }
358 }
359 return bytes;
360}
361
362#define BUFSZ 150
363
364static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long len)
365{
366 unsigned lines, pixelsperline, bitsperxfer;
367 unsigned int is_bi_dir = q->bidirectional;
368 size_t wantlen, outptr = 0;
369 char tmpbuf[BUFSZ];
370
371 if (!access_ok(VERIFY_WRITE, buf, len))
372 return -EFAULT;
373
374 /* Wait for camera to become ready */
Hans Verkuil51224aa2010-03-22 04:33:56 -0300375 for (;;) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 int i = qcam_get(q, 41);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300377
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 if (i == -1) {
379 qc_setup(q);
380 return -EIO;
381 }
382 if ((i & 0x80) == 0)
383 break;
Hans Verkuil51224aa2010-03-22 04:33:56 -0300384 schedule();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 }
386
Hans Verkuil51224aa2010-03-22 04:33:56 -0300387 if (qcam_set(q, 7, (q->mode | (is_bi_dir ? 1 : 0)) + 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 return -EIO;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300389
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 lines = q->height;
391 pixelsperline = q->width;
392 bitsperxfer = (is_bi_dir) ? 24 : 8;
393
Hans Verkuil51224aa2010-03-22 04:33:56 -0300394 if (is_bi_dir) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 /* 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
Hans Verkuil51224aa2010-03-22 04:33:56 -0300412 while (wantlen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 size_t t, s;
Hans Verkuil51224aa2010-03-22 04:33:56 -0300414
415 s = (wantlen > BUFSZ) ? BUFSZ : wantlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 t = qcam_read_bytes(q, tmpbuf, s);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300417 if (outptr < len) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 size_t sz = len - outptr;
Hans Verkuil51224aa2010-03-22 04:33:56 -0300419
420 if (sz > t)
421 sz = t;
422 if (__copy_to_user(buf + outptr, tmpbuf, sz))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 break;
424 outptr += sz;
425 }
426 wantlen -= t;
427 if (t < s)
428 break;
429 cond_resched();
430 }
431
432 len = outptr;
433
Hans Verkuil51224aa2010-03-22 04:33:56 -0300434 if (wantlen) {
435 printk(KERN_ERR "qcam: short read.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 if (is_bi_dir)
437 parport_data_forward(q->pport);
438 qc_setup(q);
439 return len;
440 }
441
Hans Verkuil51224aa2010-03-22 04:33:56 -0300442 if (is_bi_dir) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 int l;
Hans Verkuil51224aa2010-03-22 04:33:56 -0300444
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 do {
446 l = qcam_read_bytes(q, tmpbuf, 3);
447 cond_resched();
448 } while (l && (tmpbuf[0] == 0x7e || tmpbuf[1] == 0x7e || tmpbuf[2] == 0x7e));
449 if (force_rgb) {
450 if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
Hans Verkuil51224aa2010-03-22 04:33:56 -0300451 printk(KERN_ERR "qcam: bad EOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 } else {
453 if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe)
Hans Verkuil51224aa2010-03-22 04:33:56 -0300454 printk(KERN_ERR "qcam: bad EOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 }
456 qcam_set_ack(q, 0);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300457 if (qcam_await_ready1(q, 1)) {
458 printk(KERN_ERR "qcam: no ack after EOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 parport_data_forward(q->pport);
460 qc_setup(q);
461 return len;
462 }
463 parport_data_forward(q->pport);
464 mdelay(3);
465 qcam_set_ack(q, 1);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300466 if (qcam_await_ready1(q, 0)) {
467 printk(KERN_ERR "qcam: no ack to port turnaround\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 qc_setup(q);
469 return len;
470 }
Hans Verkuil51224aa2010-03-22 04:33:56 -0300471 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 int l;
Hans Verkuil51224aa2010-03-22 04:33:56 -0300473
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 do {
475 l = qcam_read_bytes(q, tmpbuf, 1);
476 cond_resched();
477 } while (l && tmpbuf[0] == 0x7e);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300478 l = qcam_read_bytes(q, tmpbuf + 1, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 if (force_rgb) {
480 if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
Hans Verkuil51224aa2010-03-22 04:33:56 -0300481 printk(KERN_ERR "qcam: bad EOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 } else {
483 if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe)
Hans Verkuil51224aa2010-03-22 04:33:56 -0300484 printk(KERN_ERR "qcam: bad EOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 }
486 }
487
488 qcam_write_data(q, 0);
489 return len;
490}
491
492/*
493 * Video4linux interfacing
494 */
495
Hans Verkuil069b7472008-12-30 07:04:34 -0300496static long qcam_do_ioctl(struct file *file, unsigned int cmd, void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497{
498 struct video_device *dev = video_devdata(file);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300499 struct qcam_device *qcam = (struct qcam_device *)dev;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300500
Hans Verkuil51224aa2010-03-22 04:33:56 -0300501 switch (cmd) {
502 case VIDIOCGCAP:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 {
Hans Verkuil51224aa2010-03-22 04:33:56 -0300504 struct video_capability *b = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505
Hans Verkuil51224aa2010-03-22 04:33:56 -0300506 strcpy(b->name, "Quickcam");
507 b->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
508 b->channels = 1;
509 b->audios = 0;
510 b->maxwidth = 320;
511 b->maxheight = 240;
512 b->minwidth = 80;
513 b->minheight = 60;
514 return 0;
515 }
516 case VIDIOCGCHAN:
517 {
518 struct video_channel *v = arg;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300519
Hans Verkuil51224aa2010-03-22 04:33:56 -0300520 if (v->channel != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 return -EINVAL;
Hans Verkuil51224aa2010-03-22 04:33:56 -0300522 v->flags = 0;
523 v->tuners = 0;
524 /* Good question.. its composite or SVHS so.. */
525 v->type = VIDEO_TYPE_CAMERA;
526 strcpy(v->name, "Camera");
527 return 0;
528 }
529 case VIDIOCSCHAN:
530 {
531 struct video_channel *v = arg;
532
533 if (v->channel != 0)
534 return -EINVAL;
535 return 0;
536 }
537 case VIDIOCGTUNER:
538 {
539 struct video_tuner *v = arg;
540
541 if (v->tuner)
542 return -EINVAL;
543 memset(v, 0, sizeof(*v));
544 strcpy(v->name, "Format");
545 v->mode = VIDEO_MODE_AUTO;
546 return 0;
547 }
548 case VIDIOCSTUNER:
549 {
550 struct video_tuner *v = arg;
551
552 if (v->tuner)
553 return -EINVAL;
554 if (v->mode != VIDEO_MODE_AUTO)
555 return -EINVAL;
556 return 0;
557 }
558 case VIDIOCGPICT:
559 {
560 struct video_picture *p = arg;
561
562 p->colour = 0x8000;
563 p->hue = 0x8000;
564 p->brightness = qcam->brightness << 8;
565 p->contrast = qcam->contrast << 8;
566 p->whiteness = qcam->whitebal << 8;
567 p->depth = 24;
568 p->palette = VIDEO_PALETTE_RGB24;
569 return 0;
570 }
571 case VIDIOCSPICT:
572 {
573 struct video_picture *p = arg;
574
575 /*
576 * Sanity check args
577 */
578 if (p->depth != 24 || p->palette != VIDEO_PALETTE_RGB24)
579 return -EINVAL;
580
581 /*
582 * Now load the camera.
583 */
584 qcam->brightness = p->brightness >> 8;
585 qcam->contrast = p->contrast >> 8;
586 qcam->whitebal = p->whiteness >> 8;
587
588 mutex_lock(&qcam->lock);
589 parport_claim_or_block(qcam->pdev);
590 qc_setup(qcam);
591 parport_release(qcam->pdev);
592 mutex_unlock(&qcam->lock);
593 return 0;
594 }
595 case VIDIOCSWIN:
596 {
597 struct video_window *vw = arg;
598
599 if (vw->flags)
600 return -EINVAL;
601 if (vw->clipcount)
602 return -EINVAL;
603 if (vw->height < 60 || vw->height > 240)
604 return -EINVAL;
605 if (vw->width < 80 || vw->width > 320)
606 return -EINVAL;
607
608 qcam->width = 80;
609 qcam->height = 60;
610 qcam->mode = QC_DECIMATION_4;
611
612 if (vw->width >= 160 && vw->height >= 120) {
613 qcam->width = 160;
614 qcam->height = 120;
615 qcam->mode = QC_DECIMATION_2;
616 }
617 if (vw->width >= 320 && vw->height >= 240) {
618 qcam->width = 320;
619 qcam->height = 240;
620 qcam->mode = QC_DECIMATION_1;
621 }
622 qcam->mode |= QC_MILLIONS;
623#if 0
624 if (vw->width >= 640 && vw->height >= 480) {
625 qcam->width = 640;
626 qcam->height = 480;
627 qcam->mode = QC_BILLIONS | QC_DECIMATION_1;
628 }
629#endif
630 /* Ok we figured out what to use from our
631 wide choice */
632 mutex_lock(&qcam->lock);
633 parport_claim_or_block(qcam->pdev);
634 qc_setup(qcam);
635 parport_release(qcam->pdev);
636 mutex_unlock(&qcam->lock);
637 return 0;
638 }
639 case VIDIOCGWIN:
640 {
641 struct video_window *vw = arg;
642 memset(vw, 0, sizeof(*vw));
643 vw->width = qcam->width;
644 vw->height = qcam->height;
645 return 0;
646 }
647 case VIDIOCKEY:
648 return 0;
649 case VIDIOCCAPTURE:
650 case VIDIOCGFBUF:
651 case VIDIOCSFBUF:
652 case VIDIOCGFREQ:
653 case VIDIOCSFREQ:
654 case VIDIOCGAUDIO:
655 case VIDIOCSAUDIO:
656 return -EINVAL;
657 default:
658 return -ENOIOCTLCMD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 }
660 return 0;
661}
662
Hans Verkuil069b7472008-12-30 07:04:34 -0300663static long qcam_ioctl(struct file *file,
Hans Verkuilf473bf72008-11-01 08:25:11 -0300664 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665{
Hans Verkuilf473bf72008-11-01 08:25:11 -0300666 return video_usercopy(file, cmd, arg, qcam_do_ioctl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667}
668
669static ssize_t qcam_read(struct file *file, char __user *buf,
670 size_t count, loff_t *ppos)
671{
672 struct video_device *v = video_devdata(file);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300673 struct qcam_device *qcam = (struct qcam_device *)v;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 int len;
675
Ingo Molnar3593cab2006-02-07 06:49:14 -0200676 mutex_lock(&qcam->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 parport_claim_or_block(qcam->pdev);
678 /* Probably should have a semaphore against multiple users */
Hans Verkuil51224aa2010-03-22 04:33:56 -0300679 len = qc_capture(qcam, buf, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 parport_release(qcam->pdev);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200681 mutex_unlock(&qcam->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 return len;
683}
684
Hans Verkuilbec43662008-12-30 06:58:20 -0300685static int qcam_exclusive_open(struct file *file)
Hans Verkuil7d43cd52008-08-23 05:31:47 -0300686{
687 struct video_device *dev = video_devdata(file);
688 struct qcam_device *qcam = (struct qcam_device *)dev;
689
690 return test_and_set_bit(0, &qcam->in_use) ? -EBUSY : 0;
691}
692
Hans Verkuilbec43662008-12-30 06:58:20 -0300693static int qcam_exclusive_release(struct file *file)
Hans Verkuil7d43cd52008-08-23 05:31:47 -0300694{
695 struct video_device *dev = video_devdata(file);
696 struct qcam_device *qcam = (struct qcam_device *)dev;
697
698 clear_bit(0, &qcam->in_use);
699 return 0;
700}
701
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702/* video device template */
Hans Verkuilbec43662008-12-30 06:58:20 -0300703static const struct v4l2_file_operations qcam_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 .owner = THIS_MODULE,
Hans Verkuil7d43cd52008-08-23 05:31:47 -0300705 .open = qcam_exclusive_open,
706 .release = qcam_exclusive_release,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 .ioctl = qcam_ioctl,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 .read = qcam_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709};
710
Hans Verkuil51224aa2010-03-22 04:33:56 -0300711static struct video_device qcam_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 .name = "Colour QuickCam",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 .fops = &qcam_fops,
Hans Verkuilaa5e90a2008-08-23 06:23:55 -0300714 .release = video_device_release_empty,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715};
716
717/* Initialize the QuickCam driver control structure. */
718
719static struct qcam_device *qcam_init(struct parport *port)
720{
721 struct qcam_device *q;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300722
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 q = kmalloc(sizeof(struct qcam_device), GFP_KERNEL);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300724 if (q == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 return NULL;
726
727 q->pport = port;
728 q->pdev = parport_register_device(port, "c-qcam", NULL, NULL,
729 NULL, 0, NULL);
730
Hans Verkuil51224aa2010-03-22 04:33:56 -0300731 q->bidirectional = (q->pport->modes & PARPORT_MODE_TRISTATE) ? 1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732
Hans Verkuil51224aa2010-03-22 04:33:56 -0300733 if (q->pdev == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 printk(KERN_ERR "c-qcam: couldn't register for %s.\n",
735 port->name);
736 kfree(q);
737 return NULL;
738 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300739
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 memcpy(&q->vdev, &qcam_template, sizeof(qcam_template));
741
Ingo Molnar3593cab2006-02-07 06:49:14 -0200742 mutex_init(&q->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 q->width = q->ccd_width = 320;
744 q->height = q->ccd_height = 240;
745 q->mode = QC_MILLIONS | QC_DECIMATION_1;
746 q->contrast = 192;
747 q->brightness = 240;
748 q->whitebal = 128;
749 q->top = 1;
750 q->left = 14;
751 return q;
752}
753
754static struct qcam_device *qcams[MAX_CAMS];
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -0300755static unsigned int num_cams;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756
757static int init_cqcam(struct parport *port)
758{
759 struct qcam_device *qcam;
760
Hans Verkuil51224aa2010-03-22 04:33:56 -0300761 if (parport[0] != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 /* The user gave specific instructions */
763 int i, found = 0;
Hans Verkuil51224aa2010-03-22 04:33:56 -0300764
765 for (i = 0; i < MAX_CAMS && parport[i] != -1; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 if (parport[0] == port->number)
767 found = 1;
768 }
769 if (!found)
770 return -ENODEV;
771 }
772
773 if (num_cams == MAX_CAMS)
774 return -ENOSPC;
775
776 qcam = qcam_init(port);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300777 if (qcam == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 return -ENODEV;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300779
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 parport_claim_or_block(qcam->pdev);
781
782 qc_reset(qcam);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300783
Hans Verkuil51224aa2010-03-22 04:33:56 -0300784 if (probe && qc_detect(qcam) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 parport_release(qcam->pdev);
786 parport_unregister_device(qcam->pdev);
787 kfree(qcam);
788 return -ENODEV;
789 }
790
791 qc_setup(qcam);
792
793 parport_release(qcam->pdev);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300794
Hans Verkuildc60de32008-09-03 17:11:58 -0300795 if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 printk(KERN_ERR "Unable to register Colour QuickCam on %s\n",
797 qcam->pport->name);
798 parport_unregister_device(qcam->pdev);
799 kfree(qcam);
800 return -ENODEV;
801 }
802
Laurent Pinchart38c7c032009-11-27 13:57:15 -0300803 printk(KERN_INFO "%s: Colour QuickCam found on %s\n",
804 video_device_node_name(&qcam->vdev), qcam->pport->name);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300805
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 qcams[num_cams++] = qcam;
807
808 return 0;
809}
810
811static void close_cqcam(struct qcam_device *qcam)
812{
813 video_unregister_device(&qcam->vdev);
814 parport_unregister_device(qcam->pdev);
815 kfree(qcam);
816}
817
818static void cq_attach(struct parport *port)
819{
820 init_cqcam(port);
821}
822
823static void cq_detach(struct parport *port)
824{
825 /* Write this some day. */
826}
827
828static struct parport_driver cqcam_driver = {
829 .name = "cqcam",
830 .attach = cq_attach,
831 .detach = cq_detach,
832};
833
Hans Verkuil51224aa2010-03-22 04:33:56 -0300834static int __init cqcam_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835{
836 printk(BANNER "\n");
837
838 return parport_register_driver(&cqcam_driver);
839}
840
Hans Verkuil51224aa2010-03-22 04:33:56 -0300841static void __exit cqcam_cleanup(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842{
843 unsigned int i;
844
845 for (i = 0; i < num_cams; i++)
846 close_cqcam(qcams[i]);
847
848 parport_unregister_driver(&cqcam_driver);
849}
850
851MODULE_AUTHOR("Philip Blundell <philb@gnu.org>");
852MODULE_DESCRIPTION(BANNER);
853MODULE_LICENSE("GPL");
854
855/* FIXME: parport=auto would never have worked, surely? --RR */
Hans Verkuil51224aa2010-03-22 04:33:56 -0300856MODULE_PARM_DESC(parport, "parport=<auto|n[,n]...> for port detection method\n"
857 "probe=<0|1|2> for camera detection method\n"
858 "force_rgb=<0|1> for RGB data format (default BGR)");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859module_param_array(parport, int, NULL, 0);
860module_param(probe, int, 0);
861module_param(force_rgb, bool, 0);
862module_param(video_nr, int, 0);
863
864module_init(cqcam_init);
865module_exit(cqcam_cleanup);