]> bbs.cooldavid.org Git - net-next-2.6.git/blame - drivers/media/video/c-qcam.c
Merge branch 'for-linus' of git://oss.sgi.com/xfs/xfs
[net-next-2.6.git] / drivers / media / video / c-qcam.c
CommitLineData
1da177e4
LT
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.
d56410e0 19 * -- March 14, 1999 Billy Donahue <billy@escape.com>
1da177e4
LT
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>
3593cab5 36#include <linux/mutex.h>
168c626c 37#include <linux/jiffies.h>
d71964fb
HV
38#include <linux/version.h>
39#include <linux/videodev2.h>
1da177e4 40#include <asm/uaccess.h>
d71964fb
HV
41#include <media/v4l2-device.h>
42#include <media/v4l2-common.h>
43#include <media/v4l2-ioctl.h>
1da177e4 44
d71964fb
HV
45struct qcam {
46 struct v4l2_device v4l2_dev;
1da177e4
LT
47 struct video_device vdev;
48 struct pardevice *pdev;
49 struct parport *pport;
50 int width, height;
51 int ccd_width, ccd_height;
52 int mode;
53 int contrast, brightness, whitebal;
54 int top, left;
55 unsigned int bidirectional;
3593cab5 56 struct mutex lock;
1da177e4
LT
57};
58
59/* cameras maximum */
60#define MAX_CAMS 4
61
62/* The three possible QuickCam modes */
63#define QC_MILLIONS 0x18
64#define QC_BILLIONS 0x10
65#define QC_THOUSANDS 0x08 /* with VIDEC compression (not supported) */
66
67/* The three possible decimations */
68#define QC_DECIMATION_1 0
69#define QC_DECIMATION_2 2
70#define QC_DECIMATION_4 4
71
d71964fb 72#define BANNER "Colour QuickCam for Video4Linux v0.06"
1da177e4
LT
73
74static int parport[MAX_CAMS] = { [1 ... MAX_CAMS-1] = -1 };
75static int probe = 2;
ff699e6b 76static int force_rgb;
1da177e4
LT
77static int video_nr = -1;
78
d71964fb
HV
79/* FIXME: parport=auto would never have worked, surely? --RR */
80MODULE_PARM_DESC(parport, "parport=<auto|n[,n]...> for port detection method\n"
81 "probe=<0|1|2> for camera detection method\n"
82 "force_rgb=<0|1> for RGB data format (default BGR)");
83module_param_array(parport, int, NULL, 0);
84module_param(probe, int, 0);
85module_param(force_rgb, bool, 0);
86module_param(video_nr, int, 0);
87
88static struct qcam *qcams[MAX_CAMS];
89static unsigned int num_cams;
90
91static inline void qcam_set_ack(struct qcam *qcam, unsigned int i)
1da177e4
LT
92{
93 /* note: the QC specs refer to the PCAck pin by voltage, not
94 software level. PC ports have builtin inverters. */
51224aa4 95 parport_frob_control(qcam->pport, 8, i ? 8 : 0);
1da177e4
LT
96}
97
d71964fb 98static inline unsigned int qcam_ready1(struct qcam *qcam)
1da177e4 99{
51224aa4 100 return (parport_read_status(qcam->pport) & 0x8) ? 1 : 0;
1da177e4
LT
101}
102
d71964fb 103static inline unsigned int qcam_ready2(struct qcam *qcam)
1da177e4 104{
51224aa4 105 return (parport_read_data(qcam->pport) & 0x1) ? 1 : 0;
1da177e4
LT
106}
107
d71964fb 108static unsigned int qcam_await_ready1(struct qcam *qcam, int value)
1da177e4 109{
d71964fb 110 struct v4l2_device *v4l2_dev = &qcam->v4l2_dev;
1da177e4
LT
111 unsigned long oldjiffies = jiffies;
112 unsigned int i;
113
168c626c 114 for (oldjiffies = jiffies;
51224aa4 115 time_before(jiffies, oldjiffies + msecs_to_jiffies(40));)
1da177e4
LT
116 if (qcam_ready1(qcam) == value)
117 return 0;
118
d56410e0 119 /* If the camera didn't respond within 1/25 second, poll slowly
1da177e4 120 for a while. */
51224aa4 121 for (i = 0; i < 50; i++) {
1da177e4
LT
122 if (qcam_ready1(qcam) == value)
123 return 0;
124 msleep_interruptible(100);
125 }
126
127 /* Probably somebody pulled the plug out. Not much we can do. */
d71964fb 128 v4l2_err(v4l2_dev, "ready1 timeout (%d) %x %x\n", value,
1da177e4
LT
129 parport_read_status(qcam->pport),
130 parport_read_control(qcam->pport));
131 return 1;
132}
133
d71964fb 134static unsigned int qcam_await_ready2(struct qcam *qcam, int value)
1da177e4 135{
d71964fb 136 struct v4l2_device *v4l2_dev = &qcam->v4l2_dev;
1da177e4
LT
137 unsigned long oldjiffies = jiffies;
138 unsigned int i;
139
168c626c 140 for (oldjiffies = jiffies;
51224aa4 141 time_before(jiffies, oldjiffies + msecs_to_jiffies(40));)
1da177e4
LT
142 if (qcam_ready2(qcam) == value)
143 return 0;
144
d56410e0 145 /* If the camera didn't respond within 1/25 second, poll slowly
1da177e4 146 for a while. */
51224aa4 147 for (i = 0; i < 50; i++) {
1da177e4
LT
148 if (qcam_ready2(qcam) == value)
149 return 0;
150 msleep_interruptible(100);
151 }
152
153 /* Probably somebody pulled the plug out. Not much we can do. */
d71964fb 154 v4l2_err(v4l2_dev, "ready2 timeout (%d) %x %x %x\n", value,
1da177e4
LT
155 parport_read_status(qcam->pport),
156 parport_read_control(qcam->pport),
157 parport_read_data(qcam->pport));
158 return 1;
159}
160
d71964fb 161static int qcam_read_data(struct qcam *qcam)
1da177e4
LT
162{
163 unsigned int idata;
51224aa4 164
1da177e4 165 qcam_set_ack(qcam, 0);
51224aa4
HV
166 if (qcam_await_ready1(qcam, 1))
167 return -1;
1da177e4
LT
168 idata = parport_read_status(qcam->pport) & 0xf0;
169 qcam_set_ack(qcam, 1);
51224aa4
HV
170 if (qcam_await_ready1(qcam, 0))
171 return -1;
172 idata |= parport_read_status(qcam->pport) >> 4;
1da177e4
LT
173 return idata;
174}
175
d71964fb 176static int qcam_write_data(struct qcam *qcam, unsigned int data)
1da177e4 177{
d71964fb 178 struct v4l2_device *v4l2_dev = &qcam->v4l2_dev;
1da177e4 179 unsigned int idata;
51224aa4 180
1da177e4
LT
181 parport_write_data(qcam->pport, data);
182 idata = qcam_read_data(qcam);
51224aa4 183 if (data != idata) {
d71964fb 184 v4l2_warn(v4l2_dev, "sent %x but received %x\n", data,
1da177e4
LT
185 idata);
186 return 1;
d56410e0 187 }
1da177e4
LT
188 return 0;
189}
190
d71964fb 191static inline int qcam_set(struct qcam *qcam, unsigned int cmd, unsigned int data)
1da177e4
LT
192{
193 if (qcam_write_data(qcam, cmd))
194 return -1;
195 if (qcam_write_data(qcam, data))
196 return -1;
197 return 0;
198}
199
d71964fb 200static inline int qcam_get(struct qcam *qcam, unsigned int cmd)
1da177e4
LT
201{
202 if (qcam_write_data(qcam, cmd))
203 return -1;
204 return qcam_read_data(qcam);
205}
206
d71964fb 207static int qc_detect(struct qcam *qcam)
1da177e4
LT
208{
209 unsigned int stat, ostat, i, count = 0;
210
211 /* The probe routine below is not very reliable. The IEEE-1284
212 probe takes precedence. */
213 /* XXX Currently parport provides no way to distinguish between
214 "the IEEE probe was not done" and "the probe was done, but
215 no device was found". Fix this one day. */
216 if (qcam->pport->probe_info[0].class == PARPORT_CLASS_MEDIA
217 && qcam->pport->probe_info[0].model
d56410e0 218 && !strcmp(qcam->pdev->port->probe_info[0].model,
1da177e4
LT
219 "Color QuickCam 2.0")) {
220 printk(KERN_DEBUG "QuickCam: Found by IEEE1284 probe.\n");
221 return 1;
222 }
d56410e0 223
1da177e4
LT
224 if (probe < 2)
225 return 0;
226
227 parport_write_control(qcam->pport, 0xc);
228
229 /* look for a heartbeat */
230 ostat = stat = parport_read_status(qcam->pport);
51224aa4 231 for (i = 0; i < 250; i++) {
1da177e4
LT
232 mdelay(1);
233 stat = parport_read_status(qcam->pport);
51224aa4
HV
234 if (ostat != stat) {
235 if (++count >= 3)
236 return 1;
1da177e4
LT
237 ostat = stat;
238 }
239 }
240
241 /* Reset the camera and try again */
242 parport_write_control(qcam->pport, 0xc);
243 parport_write_control(qcam->pport, 0x8);
244 mdelay(1);
245 parport_write_control(qcam->pport, 0xc);
246 mdelay(1);
247 count = 0;
248
249 ostat = stat = parport_read_status(qcam->pport);
51224aa4 250 for (i = 0; i < 250; i++) {
1da177e4
LT
251 mdelay(1);
252 stat = parport_read_status(qcam->pport);
51224aa4
HV
253 if (ostat != stat) {
254 if (++count >= 3)
255 return 1;
1da177e4
LT
256 ostat = stat;
257 }
258 }
259
260 /* no (or flatline) camera, give up */
261 return 0;
262}
263
d71964fb 264static void qc_reset(struct qcam *qcam)
1da177e4
LT
265{
266 parport_write_control(qcam->pport, 0xc);
267 parport_write_control(qcam->pport, 0x8);
268 mdelay(1);
269 parport_write_control(qcam->pport, 0xc);
d56410e0 270 mdelay(1);
1da177e4
LT
271}
272
273/* Reset the QuickCam and program for brightness, contrast,
274 * white-balance, and resolution. */
275
d71964fb 276static void qc_setup(struct qcam *qcam)
1da177e4 277{
d71964fb 278 qc_reset(qcam);
1da177e4 279
51224aa4 280 /* Set the brightness. */
d71964fb 281 qcam_set(qcam, 11, qcam->brightness);
1da177e4
LT
282
283 /* Set the height and width. These refer to the actual
284 CCD area *before* applying the selected decimation. */
d71964fb
HV
285 qcam_set(qcam, 17, qcam->ccd_height);
286 qcam_set(qcam, 19, qcam->ccd_width / 2);
1da177e4
LT
287
288 /* Set top and left. */
d71964fb
HV
289 qcam_set(qcam, 0xd, qcam->top);
290 qcam_set(qcam, 0xf, qcam->left);
1da177e4
LT
291
292 /* Set contrast and white balance. */
d71964fb
HV
293 qcam_set(qcam, 0x19, qcam->contrast);
294 qcam_set(qcam, 0x1f, qcam->whitebal);
d56410e0 295
1da177e4 296 /* Set the speed. */
d71964fb 297 qcam_set(qcam, 45, 2);
1da177e4
LT
298}
299
d56410e0 300/* Read some bytes from the camera and put them in the buffer.
1da177e4
LT
301 nbytes should be a multiple of 3, because bidirectional mode gives
302 us three bytes at a time. */
303
d71964fb 304static unsigned int qcam_read_bytes(struct qcam *qcam, unsigned char *buf, unsigned int nbytes)
1da177e4
LT
305{
306 unsigned int bytes = 0;
307
d71964fb
HV
308 qcam_set_ack(qcam, 0);
309 if (qcam->bidirectional) {
1da177e4 310 /* It's a bidirectional port */
51224aa4 311 while (bytes < nbytes) {
1da177e4
LT
312 unsigned int lo1, hi1, lo2, hi2;
313 unsigned char r, g, b;
314
d71964fb 315 if (qcam_await_ready2(qcam, 1))
51224aa4 316 return bytes;
d71964fb
HV
317 lo1 = parport_read_data(qcam->pport) >> 1;
318 hi1 = ((parport_read_status(qcam->pport) >> 3) & 0x1f) ^ 0x10;
319 qcam_set_ack(qcam, 1);
320 if (qcam_await_ready2(qcam, 0))
51224aa4 321 return bytes;
d71964fb
HV
322 lo2 = parport_read_data(qcam->pport) >> 1;
323 hi2 = ((parport_read_status(qcam->pport) >> 3) & 0x1f) ^ 0x10;
324 qcam_set_ack(qcam, 0);
51224aa4
HV
325 r = lo1 | ((hi1 & 1) << 7);
326 g = ((hi1 & 0x1e) << 3) | ((hi2 & 0x1e) >> 1);
327 b = lo2 | ((hi2 & 1) << 7);
1da177e4
LT
328 if (force_rgb) {
329 buf[bytes++] = r;
330 buf[bytes++] = g;
331 buf[bytes++] = b;
332 } else {
333 buf[bytes++] = b;
334 buf[bytes++] = g;
335 buf[bytes++] = r;
336 }
337 }
51224aa4 338 } else {
1da177e4
LT
339 /* It's a unidirectional port */
340 int i = 0, n = bytes;
341 unsigned char rgb[3];
342
51224aa4 343 while (bytes < nbytes) {
1da177e4
LT
344 unsigned int hi, lo;
345
d71964fb 346 if (qcam_await_ready1(qcam, 1))
51224aa4 347 return bytes;
d71964fb
HV
348 hi = (parport_read_status(qcam->pport) & 0xf0);
349 qcam_set_ack(qcam, 1);
350 if (qcam_await_ready1(qcam, 0))
51224aa4 351 return bytes;
d71964fb
HV
352 lo = (parport_read_status(qcam->pport) & 0xf0);
353 qcam_set_ack(qcam, 0);
1da177e4
LT
354 /* flip some bits */
355 rgb[(i = bytes++ % 3)] = (hi | (lo >> 4)) ^ 0x88;
356 if (i >= 2) {
357get_fragment:
358 if (force_rgb) {
359 buf[n++] = rgb[0];
360 buf[n++] = rgb[1];
361 buf[n++] = rgb[2];
362 } else {
363 buf[n++] = rgb[2];
364 buf[n++] = rgb[1];
365 buf[n++] = rgb[0];
366 }
367 }
368 }
369 if (i) {
370 i = 0;
371 goto get_fragment;
372 }
373 }
374 return bytes;
375}
376
377#define BUFSZ 150
378
d71964fb 379static long qc_capture(struct qcam *qcam, char __user *buf, unsigned long len)
1da177e4 380{
d71964fb 381 struct v4l2_device *v4l2_dev = &qcam->v4l2_dev;
1da177e4 382 unsigned lines, pixelsperline, bitsperxfer;
d71964fb 383 unsigned int is_bi_dir = qcam->bidirectional;
1da177e4
LT
384 size_t wantlen, outptr = 0;
385 char tmpbuf[BUFSZ];
386
387 if (!access_ok(VERIFY_WRITE, buf, len))
388 return -EFAULT;
389
390 /* Wait for camera to become ready */
51224aa4 391 for (;;) {
d71964fb 392 int i = qcam_get(qcam, 41);
51224aa4 393
1da177e4 394 if (i == -1) {
d71964fb 395 qc_setup(qcam);
1da177e4
LT
396 return -EIO;
397 }
398 if ((i & 0x80) == 0)
399 break;
51224aa4 400 schedule();
1da177e4
LT
401 }
402
d71964fb 403 if (qcam_set(qcam, 7, (qcam->mode | (is_bi_dir ? 1 : 0)) + 1))
1da177e4 404 return -EIO;
d56410e0 405
d71964fb
HV
406 lines = qcam->height;
407 pixelsperline = qcam->width;
1da177e4
LT
408 bitsperxfer = (is_bi_dir) ? 24 : 8;
409
51224aa4 410 if (is_bi_dir) {
1da177e4 411 /* Turn the port around */
d71964fb 412 parport_data_reverse(qcam->pport);
1da177e4 413 mdelay(3);
d71964fb
HV
414 qcam_set_ack(qcam, 0);
415 if (qcam_await_ready1(qcam, 1)) {
416 qc_setup(qcam);
1da177e4
LT
417 return -EIO;
418 }
d71964fb
HV
419 qcam_set_ack(qcam, 1);
420 if (qcam_await_ready1(qcam, 0)) {
421 qc_setup(qcam);
1da177e4
LT
422 return -EIO;
423 }
424 }
425
426 wantlen = lines * pixelsperline * 24 / 8;
427
51224aa4 428 while (wantlen) {
1da177e4 429 size_t t, s;
51224aa4
HV
430
431 s = (wantlen > BUFSZ) ? BUFSZ : wantlen;
d71964fb 432 t = qcam_read_bytes(qcam, tmpbuf, s);
51224aa4 433 if (outptr < len) {
1da177e4 434 size_t sz = len - outptr;
51224aa4
HV
435
436 if (sz > t)
437 sz = t;
438 if (__copy_to_user(buf + outptr, tmpbuf, sz))
1da177e4
LT
439 break;
440 outptr += sz;
441 }
442 wantlen -= t;
443 if (t < s)
444 break;
445 cond_resched();
446 }
447
448 len = outptr;
449
51224aa4 450 if (wantlen) {
d71964fb 451 v4l2_err(v4l2_dev, "short read.\n");
1da177e4 452 if (is_bi_dir)
d71964fb
HV
453 parport_data_forward(qcam->pport);
454 qc_setup(qcam);
1da177e4
LT
455 return len;
456 }
457
51224aa4 458 if (is_bi_dir) {
1da177e4 459 int l;
51224aa4 460
1da177e4 461 do {
d71964fb 462 l = qcam_read_bytes(qcam, tmpbuf, 3);
1da177e4
LT
463 cond_resched();
464 } while (l && (tmpbuf[0] == 0x7e || tmpbuf[1] == 0x7e || tmpbuf[2] == 0x7e));
465 if (force_rgb) {
466 if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
d71964fb 467 v4l2_err(v4l2_dev, "bad EOF\n");
1da177e4
LT
468 } else {
469 if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe)
d71964fb 470 v4l2_err(v4l2_dev, "bad EOF\n");
1da177e4 471 }
d71964fb
HV
472 qcam_set_ack(qcam, 0);
473 if (qcam_await_ready1(qcam, 1)) {
474 v4l2_err(v4l2_dev, "no ack after EOF\n");
475 parport_data_forward(qcam->pport);
476 qc_setup(qcam);
1da177e4
LT
477 return len;
478 }
d71964fb 479 parport_data_forward(qcam->pport);
1da177e4 480 mdelay(3);
d71964fb
HV
481 qcam_set_ack(qcam, 1);
482 if (qcam_await_ready1(qcam, 0)) {
483 v4l2_err(v4l2_dev, "no ack to port turnaround\n");
484 qc_setup(qcam);
1da177e4
LT
485 return len;
486 }
51224aa4 487 } else {
1da177e4 488 int l;
51224aa4 489
1da177e4 490 do {
d71964fb 491 l = qcam_read_bytes(qcam, tmpbuf, 1);
1da177e4
LT
492 cond_resched();
493 } while (l && tmpbuf[0] == 0x7e);
d71964fb 494 l = qcam_read_bytes(qcam, tmpbuf + 1, 2);
1da177e4
LT
495 if (force_rgb) {
496 if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
d71964fb 497 v4l2_err(v4l2_dev, "bad EOF\n");
1da177e4
LT
498 } else {
499 if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe)
d71964fb 500 v4l2_err(v4l2_dev, "bad EOF\n");
1da177e4
LT
501 }
502 }
503
d71964fb 504 qcam_write_data(qcam, 0);
1da177e4
LT
505 return len;
506}
507
508/*
509 * Video4linux interfacing
510 */
511
d71964fb
HV
512static int qcam_querycap(struct file *file, void *priv,
513 struct v4l2_capability *vcap)
1da177e4 514{
d71964fb 515 struct qcam *qcam = video_drvdata(file);
d56410e0 516
d71964fb
HV
517 strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver));
518 strlcpy(vcap->card, "Color Quickcam", sizeof(vcap->card));
519 strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info));
520 vcap->version = KERNEL_VERSION(0, 0, 3);
521 vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
522 return 0;
523}
51224aa4 524
d71964fb
HV
525static int qcam_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
526{
527 if (vin->index > 0)
528 return -EINVAL;
529 strlcpy(vin->name, "Camera", sizeof(vin->name));
530 vin->type = V4L2_INPUT_TYPE_CAMERA;
531 vin->audioset = 0;
532 vin->tuner = 0;
533 vin->std = 0;
534 vin->status = 0;
535 return 0;
536}
51224aa4 537
d71964fb
HV
538static int qcam_g_input(struct file *file, void *fh, unsigned int *inp)
539{
540 *inp = 0;
541 return 0;
542}
543
544static int qcam_s_input(struct file *file, void *fh, unsigned int inp)
545{
546 return (inp > 0) ? -EINVAL : 0;
547}
548
549static int qcam_queryctrl(struct file *file, void *priv,
550 struct v4l2_queryctrl *qc)
551{
552 switch (qc->id) {
553 case V4L2_CID_BRIGHTNESS:
554 return v4l2_ctrl_query_fill(qc, 0, 255, 1, 240);
555 case V4L2_CID_CONTRAST:
556 return v4l2_ctrl_query_fill(qc, 0, 255, 1, 192);
557 case V4L2_CID_GAMMA:
558 return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
51224aa4 559 }
d71964fb
HV
560 return -EINVAL;
561}
562
563static int qcam_g_ctrl(struct file *file, void *priv,
564 struct v4l2_control *ctrl)
565{
566 struct qcam *qcam = video_drvdata(file);
567 int ret = 0;
568
569 switch (ctrl->id) {
570 case V4L2_CID_BRIGHTNESS:
571 ctrl->value = qcam->brightness;
572 break;
573 case V4L2_CID_CONTRAST:
574 ctrl->value = qcam->contrast;
575 break;
576 case V4L2_CID_GAMMA:
577 ctrl->value = qcam->whitebal;
578 break;
579 default:
580 ret = -EINVAL;
581 break;
51224aa4 582 }
d71964fb
HV
583 return ret;
584}
585
586static int qcam_s_ctrl(struct file *file, void *priv,
587 struct v4l2_control *ctrl)
588{
589 struct qcam *qcam = video_drvdata(file);
590 int ret = 0;
591
592 mutex_lock(&qcam->lock);
593 switch (ctrl->id) {
594 case V4L2_CID_BRIGHTNESS:
595 qcam->brightness = ctrl->value;
596 break;
597 case V4L2_CID_CONTRAST:
598 qcam->contrast = ctrl->value;
599 break;
600 case V4L2_CID_GAMMA:
601 qcam->whitebal = ctrl->value;
602 break;
603 default:
604 ret = -EINVAL;
605 break;
51224aa4 606 }
d71964fb 607 if (ret == 0) {
51224aa4
HV
608 parport_claim_or_block(qcam->pdev);
609 qc_setup(qcam);
610 parport_release(qcam->pdev);
51224aa4 611 }
d71964fb
HV
612 mutex_unlock(&qcam->lock);
613 return ret;
614}
51224aa4 615
d71964fb
HV
616static int qcam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
617{
618 struct qcam *qcam = video_drvdata(file);
619 struct v4l2_pix_format *pix = &fmt->fmt.pix;
620
621 pix->width = qcam->width;
622 pix->height = qcam->height;
623 pix->pixelformat = V4L2_PIX_FMT_RGB24;
624 pix->field = V4L2_FIELD_NONE;
625 pix->bytesperline = 3 * qcam->width;
626 pix->sizeimage = 3 * qcam->width * qcam->height;
627 /* Just a guess */
628 pix->colorspace = V4L2_COLORSPACE_SRGB;
629 return 0;
630}
631
632static int qcam_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
633{
634 struct v4l2_pix_format *pix = &fmt->fmt.pix;
635
636 if (pix->height < 60 || pix->width < 80) {
637 pix->height = 60;
638 pix->width = 80;
639 } else if (pix->height < 120 || pix->width < 160) {
640 pix->height = 120;
641 pix->width = 160;
642 } else {
643 pix->height = 240;
644 pix->width = 320;
51224aa4 645 }
d71964fb
HV
646 pix->pixelformat = V4L2_PIX_FMT_RGB24;
647 pix->field = V4L2_FIELD_NONE;
648 pix->bytesperline = 3 * pix->width;
649 pix->sizeimage = 3 * pix->width * pix->height;
650 /* Just a guess */
651 pix->colorspace = V4L2_COLORSPACE_SRGB;
652 return 0;
653}
654
655static int qcam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
656{
657 struct qcam *qcam = video_drvdata(file);
658 struct v4l2_pix_format *pix = &fmt->fmt.pix;
659 int ret = qcam_try_fmt_vid_cap(file, fh, fmt);
660
661 if (ret)
662 return ret;
663 switch (pix->height) {
664 case 60:
665 qcam->mode = QC_DECIMATION_4;
666 break;
667 case 120:
668 qcam->mode = QC_DECIMATION_2;
669 break;
51224aa4 670 default:
d71964fb
HV
671 qcam->mode = QC_DECIMATION_1;
672 break;
1da177e4 673 }
d71964fb
HV
674
675 mutex_lock(&qcam->lock);
676 qcam->mode |= QC_MILLIONS;
677 qcam->height = pix->height;
678 qcam->width = pix->width;
679 parport_claim_or_block(qcam->pdev);
680 qc_setup(qcam);
681 parport_release(qcam->pdev);
682 mutex_unlock(&qcam->lock);
1da177e4
LT
683 return 0;
684}
685
d71964fb 686static int qcam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt)
1da177e4 687{
d71964fb
HV
688 static struct v4l2_fmtdesc formats[] = {
689 { 0, 0, 0,
690 "RGB 8:8:8", V4L2_PIX_FMT_RGB24,
691 { 0, 0, 0, 0 }
692 },
693 };
694 enum v4l2_buf_type type = fmt->type;
695
696 if (fmt->index > 0)
697 return -EINVAL;
698
699 *fmt = formats[fmt->index];
700 fmt->type = type;
701 return 0;
1da177e4
LT
702}
703
704static ssize_t qcam_read(struct file *file, char __user *buf,
705 size_t count, loff_t *ppos)
706{
d71964fb 707 struct qcam *qcam = video_drvdata(file);
1da177e4
LT
708 int len;
709
3593cab5 710 mutex_lock(&qcam->lock);
1da177e4
LT
711 parport_claim_or_block(qcam->pdev);
712 /* Probably should have a semaphore against multiple users */
51224aa4 713 len = qc_capture(qcam, buf, count);
1da177e4 714 parport_release(qcam->pdev);
3593cab5 715 mutex_unlock(&qcam->lock);
1da177e4
LT
716 return len;
717}
718
bec43661 719static const struct v4l2_file_operations qcam_fops = {
1da177e4 720 .owner = THIS_MODULE,
d71964fb 721 .ioctl = video_ioctl2,
1da177e4 722 .read = qcam_read,
1da177e4
LT
723};
724
d71964fb
HV
725static const struct v4l2_ioctl_ops qcam_ioctl_ops = {
726 .vidioc_querycap = qcam_querycap,
727 .vidioc_g_input = qcam_g_input,
728 .vidioc_s_input = qcam_s_input,
729 .vidioc_enum_input = qcam_enum_input,
730 .vidioc_queryctrl = qcam_queryctrl,
731 .vidioc_g_ctrl = qcam_g_ctrl,
732 .vidioc_s_ctrl = qcam_s_ctrl,
733 .vidioc_enum_fmt_vid_cap = qcam_enum_fmt_vid_cap,
734 .vidioc_g_fmt_vid_cap = qcam_g_fmt_vid_cap,
735 .vidioc_s_fmt_vid_cap = qcam_s_fmt_vid_cap,
736 .vidioc_try_fmt_vid_cap = qcam_try_fmt_vid_cap,
1da177e4
LT
737};
738
739/* Initialize the QuickCam driver control structure. */
740
d71964fb 741static struct qcam *qcam_init(struct parport *port)
1da177e4 742{
d71964fb
HV
743 struct qcam *qcam;
744 struct v4l2_device *v4l2_dev;
d56410e0 745
d71964fb
HV
746 qcam = kzalloc(sizeof(*qcam), GFP_KERNEL);
747 if (qcam == NULL)
1da177e4
LT
748 return NULL;
749
d71964fb
HV
750 v4l2_dev = &qcam->v4l2_dev;
751 strlcpy(v4l2_dev->name, "c-qcam", sizeof(v4l2_dev->name));
752
753 if (v4l2_device_register(NULL, v4l2_dev) < 0) {
754 v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
755 return NULL;
756 }
757
758 qcam->pport = port;
759 qcam->pdev = parport_register_device(port, "c-qcam", NULL, NULL,
1da177e4
LT
760 NULL, 0, NULL);
761
d71964fb 762 qcam->bidirectional = (qcam->pport->modes & PARPORT_MODE_TRISTATE) ? 1 : 0;
1da177e4 763
d71964fb
HV
764 if (qcam->pdev == NULL) {
765 v4l2_err(v4l2_dev, "couldn't register for %s.\n", port->name);
766 kfree(qcam);
1da177e4
LT
767 return NULL;
768 }
d56410e0 769
d71964fb
HV
770 strlcpy(qcam->vdev.name, "Colour QuickCam", sizeof(qcam->vdev.name));
771 qcam->vdev.v4l2_dev = v4l2_dev;
772 qcam->vdev.fops = &qcam_fops;
773 qcam->vdev.ioctl_ops = &qcam_ioctl_ops;
774 qcam->vdev.release = video_device_release_empty;
775 video_set_drvdata(&qcam->vdev, qcam);
776
777 mutex_init(&qcam->lock);
778 qcam->width = qcam->ccd_width = 320;
779 qcam->height = qcam->ccd_height = 240;
780 qcam->mode = QC_MILLIONS | QC_DECIMATION_1;
781 qcam->contrast = 192;
782 qcam->brightness = 240;
783 qcam->whitebal = 128;
784 qcam->top = 1;
785 qcam->left = 14;
786 return qcam;
1da177e4
LT
787}
788
1da177e4
LT
789static int init_cqcam(struct parport *port)
790{
d71964fb
HV
791 struct qcam *qcam;
792 struct v4l2_device *v4l2_dev;
1da177e4 793
51224aa4 794 if (parport[0] != -1) {
1da177e4
LT
795 /* The user gave specific instructions */
796 int i, found = 0;
51224aa4
HV
797
798 for (i = 0; i < MAX_CAMS && parport[i] != -1; i++) {
1da177e4
LT
799 if (parport[0] == port->number)
800 found = 1;
801 }
802 if (!found)
803 return -ENODEV;
804 }
805
806 if (num_cams == MAX_CAMS)
807 return -ENOSPC;
808
809 qcam = qcam_init(port);
51224aa4 810 if (qcam == NULL)
1da177e4 811 return -ENODEV;
d56410e0 812
d71964fb
HV
813 v4l2_dev = &qcam->v4l2_dev;
814
1da177e4
LT
815 parport_claim_or_block(qcam->pdev);
816
817 qc_reset(qcam);
d56410e0 818
51224aa4 819 if (probe && qc_detect(qcam) == 0) {
1da177e4
LT
820 parport_release(qcam->pdev);
821 parport_unregister_device(qcam->pdev);
822 kfree(qcam);
823 return -ENODEV;
824 }
825
826 qc_setup(qcam);
827
828 parport_release(qcam->pdev);
d56410e0 829
dc60de33 830 if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
d71964fb 831 v4l2_err(v4l2_dev, "Unable to register Colour QuickCam on %s\n",
1da177e4
LT
832 qcam->pport->name);
833 parport_unregister_device(qcam->pdev);
834 kfree(qcam);
835 return -ENODEV;
836 }
837
d71964fb 838 v4l2_info(v4l2_dev, "%s: Colour QuickCam found on %s\n",
38c7c036 839 video_device_node_name(&qcam->vdev), qcam->pport->name);
d56410e0 840
1da177e4
LT
841 qcams[num_cams++] = qcam;
842
843 return 0;
844}
845
d71964fb 846static void close_cqcam(struct qcam *qcam)
1da177e4
LT
847{
848 video_unregister_device(&qcam->vdev);
849 parport_unregister_device(qcam->pdev);
850 kfree(qcam);
851}
852
853static void cq_attach(struct parport *port)
854{
855 init_cqcam(port);
856}
857
858static void cq_detach(struct parport *port)
859{
860 /* Write this some day. */
861}
862
863static struct parport_driver cqcam_driver = {
864 .name = "cqcam",
865 .attach = cq_attach,
866 .detach = cq_detach,
867};
868
51224aa4 869static int __init cqcam_init(void)
1da177e4 870{
d71964fb 871 printk(KERN_INFO BANNER "\n");
1da177e4
LT
872
873 return parport_register_driver(&cqcam_driver);
874}
875
51224aa4 876static void __exit cqcam_cleanup(void)
1da177e4
LT
877{
878 unsigned int i;
879
880 for (i = 0; i < num_cams; i++)
881 close_cqcam(qcams[i]);
882
883 parport_unregister_driver(&cqcam_driver);
884}
885
886MODULE_AUTHOR("Philip Blundell <philb@gnu.org>");
887MODULE_DESCRIPTION(BANNER);
888MODULE_LICENSE("GPL");
889
1da177e4
LT
890module_init(cqcam_init);
891module_exit(cqcam_cleanup);