blob: 24fc00965a12d048be055498230b734b794283fa [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>
Ingo Molnar3593cab2006-02-07 06:49:14 -020036#include <linux/mutex.h>
Julia Lawall168c6262008-04-16 16:13:15 -030037#include <linux/jiffies.h>
Hans Verkuild71964f2010-05-10 03:55:25 -030038#include <linux/version.h>
39#include <linux/videodev2.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070040#include <asm/uaccess.h>
Hans Verkuild71964f2010-05-10 03:55:25 -030041#include <media/v4l2-device.h>
42#include <media/v4l2-common.h>
43#include <media/v4l2-ioctl.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070044
Hans Verkuild71964f2010-05-10 03:55:25 -030045struct qcam {
46 struct v4l2_device v4l2_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -070047 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;
Ingo Molnar3593cab2006-02-07 06:49:14 -020056 struct mutex lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -070057};
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
Hans Verkuild71964f2010-05-10 03:55:25 -030072#define BANNER "Colour QuickCam for Video4Linux v0.06"
Linus Torvalds1da177e2005-04-16 15:20:36 -070073
74static int parport[MAX_CAMS] = { [1 ... MAX_CAMS-1] = -1 };
75static int probe = 2;
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -030076static int force_rgb;
Linus Torvalds1da177e2005-04-16 15:20:36 -070077static int video_nr = -1;
78
Hans Verkuild71964f2010-05-10 03:55:25 -030079/* 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)
Linus Torvalds1da177e2005-04-16 15:20:36 -070092{
93 /* note: the QC specs refer to the PCAck pin by voltage, not
94 software level. PC ports have builtin inverters. */
Hans Verkuil51224aa2010-03-22 04:33:56 -030095 parport_frob_control(qcam->pport, 8, i ? 8 : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070096}
97
Hans Verkuild71964f2010-05-10 03:55:25 -030098static inline unsigned int qcam_ready1(struct qcam *qcam)
Linus Torvalds1da177e2005-04-16 15:20:36 -070099{
Hans Verkuil51224aa2010-03-22 04:33:56 -0300100 return (parport_read_status(qcam->pport) & 0x8) ? 1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101}
102
Hans Verkuild71964f2010-05-10 03:55:25 -0300103static inline unsigned int qcam_ready2(struct qcam *qcam)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104{
Hans Verkuil51224aa2010-03-22 04:33:56 -0300105 return (parport_read_data(qcam->pport) & 0x1) ? 1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106}
107
Hans Verkuild71964f2010-05-10 03:55:25 -0300108static unsigned int qcam_await_ready1(struct qcam *qcam, int value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109{
Hans Verkuild71964f2010-05-10 03:55:25 -0300110 struct v4l2_device *v4l2_dev = &qcam->v4l2_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 unsigned long oldjiffies = jiffies;
112 unsigned int i;
113
Julia Lawall168c6262008-04-16 16:13:15 -0300114 for (oldjiffies = jiffies;
Hans Verkuil51224aa2010-03-22 04:33:56 -0300115 time_before(jiffies, oldjiffies + msecs_to_jiffies(40));)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 if (qcam_ready1(qcam) == value)
117 return 0;
118
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300119 /* If the camera didn't respond within 1/25 second, poll slowly
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120 for a while. */
Hans Verkuil51224aa2010-03-22 04:33:56 -0300121 for (i = 0; i < 50; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122 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. */
Hans Verkuild71964f2010-05-10 03:55:25 -0300128 v4l2_err(v4l2_dev, "ready1 timeout (%d) %x %x\n", value,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 parport_read_status(qcam->pport),
130 parport_read_control(qcam->pport));
131 return 1;
132}
133
Hans Verkuild71964f2010-05-10 03:55:25 -0300134static unsigned int qcam_await_ready2(struct qcam *qcam, int value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135{
Hans Verkuild71964f2010-05-10 03:55:25 -0300136 struct v4l2_device *v4l2_dev = &qcam->v4l2_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 unsigned long oldjiffies = jiffies;
138 unsigned int i;
139
Julia Lawall168c6262008-04-16 16:13:15 -0300140 for (oldjiffies = jiffies;
Hans Verkuil51224aa2010-03-22 04:33:56 -0300141 time_before(jiffies, oldjiffies + msecs_to_jiffies(40));)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 if (qcam_ready2(qcam) == value)
143 return 0;
144
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300145 /* If the camera didn't respond within 1/25 second, poll slowly
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 for a while. */
Hans Verkuil51224aa2010-03-22 04:33:56 -0300147 for (i = 0; i < 50; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 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. */
Hans Verkuild71964f2010-05-10 03:55:25 -0300154 v4l2_err(v4l2_dev, "ready2 timeout (%d) %x %x %x\n", value,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 parport_read_status(qcam->pport),
156 parport_read_control(qcam->pport),
157 parport_read_data(qcam->pport));
158 return 1;
159}
160
Hans Verkuild71964f2010-05-10 03:55:25 -0300161static int qcam_read_data(struct qcam *qcam)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162{
163 unsigned int idata;
Hans Verkuil51224aa2010-03-22 04:33:56 -0300164
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 qcam_set_ack(qcam, 0);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300166 if (qcam_await_ready1(qcam, 1))
167 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 idata = parport_read_status(qcam->pport) & 0xf0;
169 qcam_set_ack(qcam, 1);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300170 if (qcam_await_ready1(qcam, 0))
171 return -1;
172 idata |= parport_read_status(qcam->pport) >> 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 return idata;
174}
175
Hans Verkuild71964f2010-05-10 03:55:25 -0300176static int qcam_write_data(struct qcam *qcam, unsigned int data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177{
Hans Verkuild71964f2010-05-10 03:55:25 -0300178 struct v4l2_device *v4l2_dev = &qcam->v4l2_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 unsigned int idata;
Hans Verkuil51224aa2010-03-22 04:33:56 -0300180
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 parport_write_data(qcam->pport, data);
182 idata = qcam_read_data(qcam);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300183 if (data != idata) {
Hans Verkuild71964f2010-05-10 03:55:25 -0300184 v4l2_warn(v4l2_dev, "sent %x but received %x\n", data,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 idata);
186 return 1;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300187 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 return 0;
189}
190
Hans Verkuild71964f2010-05-10 03:55:25 -0300191static inline int qcam_set(struct qcam *qcam, unsigned int cmd, unsigned int data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192{
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
Hans Verkuild71964f2010-05-10 03:55:25 -0300200static inline int qcam_get(struct qcam *qcam, unsigned int cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201{
202 if (qcam_write_data(qcam, cmd))
203 return -1;
204 return qcam_read_data(qcam);
205}
206
Hans Verkuild71964f2010-05-10 03:55:25 -0300207static int qc_detect(struct qcam *qcam)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208{
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
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300218 && !strcmp(qcam->pdev->port->probe_info[0].model,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 "Color QuickCam 2.0")) {
220 printk(KERN_DEBUG "QuickCam: Found by IEEE1284 probe.\n");
221 return 1;
222 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300223
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 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);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300231 for (i = 0; i < 250; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 mdelay(1);
233 stat = parport_read_status(qcam->pport);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300234 if (ostat != stat) {
235 if (++count >= 3)
236 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 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);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300250 for (i = 0; i < 250; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 mdelay(1);
252 stat = parport_read_status(qcam->pport);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300253 if (ostat != stat) {
254 if (++count >= 3)
255 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 ostat = stat;
257 }
258 }
259
260 /* no (or flatline) camera, give up */
261 return 0;
262}
263
Hans Verkuild71964f2010-05-10 03:55:25 -0300264static void qc_reset(struct qcam *qcam)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265{
266 parport_write_control(qcam->pport, 0xc);
267 parport_write_control(qcam->pport, 0x8);
268 mdelay(1);
269 parport_write_control(qcam->pport, 0xc);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300270 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271}
272
273/* Reset the QuickCam and program for brightness, contrast,
274 * white-balance, and resolution. */
275
Hans Verkuild71964f2010-05-10 03:55:25 -0300276static void qc_setup(struct qcam *qcam)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277{
Hans Verkuild71964f2010-05-10 03:55:25 -0300278 qc_reset(qcam);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279
Hans Verkuil51224aa2010-03-22 04:33:56 -0300280 /* Set the brightness. */
Hans Verkuild71964f2010-05-10 03:55:25 -0300281 qcam_set(qcam, 11, qcam->brightness);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282
283 /* Set the height and width. These refer to the actual
284 CCD area *before* applying the selected decimation. */
Hans Verkuild71964f2010-05-10 03:55:25 -0300285 qcam_set(qcam, 17, qcam->ccd_height);
286 qcam_set(qcam, 19, qcam->ccd_width / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
288 /* Set top and left. */
Hans Verkuild71964f2010-05-10 03:55:25 -0300289 qcam_set(qcam, 0xd, qcam->top);
290 qcam_set(qcam, 0xf, qcam->left);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291
292 /* Set contrast and white balance. */
Hans Verkuild71964f2010-05-10 03:55:25 -0300293 qcam_set(qcam, 0x19, qcam->contrast);
294 qcam_set(qcam, 0x1f, qcam->whitebal);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300295
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 /* Set the speed. */
Hans Verkuild71964f2010-05-10 03:55:25 -0300297 qcam_set(qcam, 45, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298}
299
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300300/* Read some bytes from the camera and put them in the buffer.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 nbytes should be a multiple of 3, because bidirectional mode gives
302 us three bytes at a time. */
303
Hans Verkuild71964f2010-05-10 03:55:25 -0300304static unsigned int qcam_read_bytes(struct qcam *qcam, unsigned char *buf, unsigned int nbytes)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305{
306 unsigned int bytes = 0;
307
Hans Verkuild71964f2010-05-10 03:55:25 -0300308 qcam_set_ack(qcam, 0);
309 if (qcam->bidirectional) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 /* It's a bidirectional port */
Hans Verkuil51224aa2010-03-22 04:33:56 -0300311 while (bytes < nbytes) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 unsigned int lo1, hi1, lo2, hi2;
313 unsigned char r, g, b;
314
Hans Verkuild71964f2010-05-10 03:55:25 -0300315 if (qcam_await_ready2(qcam, 1))
Hans Verkuil51224aa2010-03-22 04:33:56 -0300316 return bytes;
Hans Verkuild71964f2010-05-10 03:55:25 -0300317 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))
Hans Verkuil51224aa2010-03-22 04:33:56 -0300321 return bytes;
Hans Verkuild71964f2010-05-10 03:55:25 -0300322 lo2 = parport_read_data(qcam->pport) >> 1;
323 hi2 = ((parport_read_status(qcam->pport) >> 3) & 0x1f) ^ 0x10;
324 qcam_set_ack(qcam, 0);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300325 r = lo1 | ((hi1 & 1) << 7);
326 g = ((hi1 & 0x1e) << 3) | ((hi2 & 0x1e) >> 1);
327 b = lo2 | ((hi2 & 1) << 7);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 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 }
Hans Verkuil51224aa2010-03-22 04:33:56 -0300338 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 /* It's a unidirectional port */
340 int i = 0, n = bytes;
341 unsigned char rgb[3];
342
Hans Verkuil51224aa2010-03-22 04:33:56 -0300343 while (bytes < nbytes) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 unsigned int hi, lo;
345
Hans Verkuild71964f2010-05-10 03:55:25 -0300346 if (qcam_await_ready1(qcam, 1))
Hans Verkuil51224aa2010-03-22 04:33:56 -0300347 return bytes;
Hans Verkuild71964f2010-05-10 03:55:25 -0300348 hi = (parport_read_status(qcam->pport) & 0xf0);
349 qcam_set_ack(qcam, 1);
350 if (qcam_await_ready1(qcam, 0))
Hans Verkuil51224aa2010-03-22 04:33:56 -0300351 return bytes;
Hans Verkuild71964f2010-05-10 03:55:25 -0300352 lo = (parport_read_status(qcam->pport) & 0xf0);
353 qcam_set_ack(qcam, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 /* 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
Hans Verkuild71964f2010-05-10 03:55:25 -0300379static long qc_capture(struct qcam *qcam, char __user *buf, unsigned long len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380{
Hans Verkuild71964f2010-05-10 03:55:25 -0300381 struct v4l2_device *v4l2_dev = &qcam->v4l2_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 unsigned lines, pixelsperline, bitsperxfer;
Hans Verkuild71964f2010-05-10 03:55:25 -0300383 unsigned int is_bi_dir = qcam->bidirectional;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 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 */
Hans Verkuil51224aa2010-03-22 04:33:56 -0300391 for (;;) {
Hans Verkuild71964f2010-05-10 03:55:25 -0300392 int i = qcam_get(qcam, 41);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300393
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 if (i == -1) {
Hans Verkuild71964f2010-05-10 03:55:25 -0300395 qc_setup(qcam);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 return -EIO;
397 }
398 if ((i & 0x80) == 0)
399 break;
Hans Verkuil51224aa2010-03-22 04:33:56 -0300400 schedule();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 }
402
Hans Verkuild71964f2010-05-10 03:55:25 -0300403 if (qcam_set(qcam, 7, (qcam->mode | (is_bi_dir ? 1 : 0)) + 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 return -EIO;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300405
Hans Verkuild71964f2010-05-10 03:55:25 -0300406 lines = qcam->height;
407 pixelsperline = qcam->width;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 bitsperxfer = (is_bi_dir) ? 24 : 8;
409
Hans Verkuil51224aa2010-03-22 04:33:56 -0300410 if (is_bi_dir) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 /* Turn the port around */
Hans Verkuild71964f2010-05-10 03:55:25 -0300412 parport_data_reverse(qcam->pport);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 mdelay(3);
Hans Verkuild71964f2010-05-10 03:55:25 -0300414 qcam_set_ack(qcam, 0);
415 if (qcam_await_ready1(qcam, 1)) {
416 qc_setup(qcam);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 return -EIO;
418 }
Hans Verkuild71964f2010-05-10 03:55:25 -0300419 qcam_set_ack(qcam, 1);
420 if (qcam_await_ready1(qcam, 0)) {
421 qc_setup(qcam);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 return -EIO;
423 }
424 }
425
426 wantlen = lines * pixelsperline * 24 / 8;
427
Hans Verkuil51224aa2010-03-22 04:33:56 -0300428 while (wantlen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 size_t t, s;
Hans Verkuil51224aa2010-03-22 04:33:56 -0300430
431 s = (wantlen > BUFSZ) ? BUFSZ : wantlen;
Hans Verkuild71964f2010-05-10 03:55:25 -0300432 t = qcam_read_bytes(qcam, tmpbuf, s);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300433 if (outptr < len) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 size_t sz = len - outptr;
Hans Verkuil51224aa2010-03-22 04:33:56 -0300435
436 if (sz > t)
437 sz = t;
438 if (__copy_to_user(buf + outptr, tmpbuf, sz))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 break;
440 outptr += sz;
441 }
442 wantlen -= t;
443 if (t < s)
444 break;
445 cond_resched();
446 }
447
448 len = outptr;
449
Hans Verkuil51224aa2010-03-22 04:33:56 -0300450 if (wantlen) {
Hans Verkuild71964f2010-05-10 03:55:25 -0300451 v4l2_err(v4l2_dev, "short read.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 if (is_bi_dir)
Hans Verkuild71964f2010-05-10 03:55:25 -0300453 parport_data_forward(qcam->pport);
454 qc_setup(qcam);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 return len;
456 }
457
Hans Verkuil51224aa2010-03-22 04:33:56 -0300458 if (is_bi_dir) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 int l;
Hans Verkuil51224aa2010-03-22 04:33:56 -0300460
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 do {
Hans Verkuild71964f2010-05-10 03:55:25 -0300462 l = qcam_read_bytes(qcam, tmpbuf, 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 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)
Hans Verkuild71964f2010-05-10 03:55:25 -0300467 v4l2_err(v4l2_dev, "bad EOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 } else {
469 if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe)
Hans Verkuild71964f2010-05-10 03:55:25 -0300470 v4l2_err(v4l2_dev, "bad EOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 }
Hans Verkuild71964f2010-05-10 03:55:25 -0300472 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 return len;
478 }
Hans Verkuild71964f2010-05-10 03:55:25 -0300479 parport_data_forward(qcam->pport);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 mdelay(3);
Hans Verkuild71964f2010-05-10 03:55:25 -0300481 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 return len;
486 }
Hans Verkuil51224aa2010-03-22 04:33:56 -0300487 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 int l;
Hans Verkuil51224aa2010-03-22 04:33:56 -0300489
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 do {
Hans Verkuild71964f2010-05-10 03:55:25 -0300491 l = qcam_read_bytes(qcam, tmpbuf, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 cond_resched();
493 } while (l && tmpbuf[0] == 0x7e);
Hans Verkuild71964f2010-05-10 03:55:25 -0300494 l = qcam_read_bytes(qcam, tmpbuf + 1, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 if (force_rgb) {
496 if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
Hans Verkuild71964f2010-05-10 03:55:25 -0300497 v4l2_err(v4l2_dev, "bad EOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 } else {
499 if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe)
Hans Verkuild71964f2010-05-10 03:55:25 -0300500 v4l2_err(v4l2_dev, "bad EOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 }
502 }
503
Hans Verkuild71964f2010-05-10 03:55:25 -0300504 qcam_write_data(qcam, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 return len;
506}
507
508/*
509 * Video4linux interfacing
510 */
511
Hans Verkuild71964f2010-05-10 03:55:25 -0300512static int qcam_querycap(struct file *file, void *priv,
513 struct v4l2_capability *vcap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514{
Hans Verkuild71964f2010-05-10 03:55:25 -0300515 struct qcam *qcam = video_drvdata(file);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300516
Hans Verkuild71964f2010-05-10 03:55:25 -0300517 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 return 0;
523}
524
Hans Verkuild71964f2010-05-10 03:55:25 -0300525static int qcam_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526{
Hans Verkuild71964f2010-05-10 03:55:25 -0300527 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}
537
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);
559 }
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;
582 }
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;
606 }
607 if (ret == 0) {
608 parport_claim_or_block(qcam->pdev);
609 qc_setup(qcam);
610 parport_release(qcam->pdev);
611 }
612 mutex_unlock(&qcam->lock);
613 return ret;
614}
615
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;
645 }
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;
670 default:
671 qcam->mode = QC_DECIMATION_1;
672 break;
673 }
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);
683 return 0;
684}
685
686static int qcam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt)
687{
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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702}
703
704static ssize_t qcam_read(struct file *file, char __user *buf,
705 size_t count, loff_t *ppos)
706{
Hans Verkuild71964f2010-05-10 03:55:25 -0300707 struct qcam *qcam = video_drvdata(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 int len;
709
Ingo Molnar3593cab2006-02-07 06:49:14 -0200710 mutex_lock(&qcam->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 parport_claim_or_block(qcam->pdev);
712 /* Probably should have a semaphore against multiple users */
Hans Verkuil51224aa2010-03-22 04:33:56 -0300713 len = qc_capture(qcam, buf, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 parport_release(qcam->pdev);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200715 mutex_unlock(&qcam->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 return len;
717}
718
Hans Verkuilbec43662008-12-30 06:58:20 -0300719static const struct v4l2_file_operations qcam_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 .owner = THIS_MODULE,
Hans Verkuil61df3c92010-11-14 10:09:38 -0300721 .unlocked_ioctl = video_ioctl2,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 .read = qcam_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723};
724
Hans Verkuild71964f2010-05-10 03:55:25 -0300725static 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,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737};
738
739/* Initialize the QuickCam driver control structure. */
740
Hans Verkuild71964f2010-05-10 03:55:25 -0300741static struct qcam *qcam_init(struct parport *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742{
Hans Verkuild71964f2010-05-10 03:55:25 -0300743 struct qcam *qcam;
744 struct v4l2_device *v4l2_dev;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300745
Hans Verkuild71964f2010-05-10 03:55:25 -0300746 qcam = kzalloc(sizeof(*qcam), GFP_KERNEL);
747 if (qcam == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 return NULL;
749
Hans Verkuild71964f2010-05-10 03:55:25 -0300750 v4l2_dev = &qcam->v4l2_dev;
751 strlcpy(v4l2_dev->name, "c-qcam", sizeof(v4l2_dev->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752
Hans Verkuild71964f2010-05-10 03:55:25 -0300753 if (v4l2_device_register(NULL, v4l2_dev) < 0) {
754 v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 return NULL;
756 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300757
Hans Verkuild71964f2010-05-10 03:55:25 -0300758 qcam->pport = port;
759 qcam->pdev = parport_register_device(port, "c-qcam", NULL, NULL,
760 NULL, 0, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761
Hans Verkuild71964f2010-05-10 03:55:25 -0300762 qcam->bidirectional = (qcam->pport->modes & PARPORT_MODE_TRISTATE) ? 1 : 0;
763
764 if (qcam->pdev == NULL) {
765 v4l2_err(v4l2_dev, "couldn't register for %s.\n", port->name);
766 kfree(qcam);
767 return NULL;
768 }
769
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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787}
788
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789static int init_cqcam(struct parport *port)
790{
Hans Verkuild71964f2010-05-10 03:55:25 -0300791 struct qcam *qcam;
792 struct v4l2_device *v4l2_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793
Hans Verkuil51224aa2010-03-22 04:33:56 -0300794 if (parport[0] != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 /* The user gave specific instructions */
796 int i, found = 0;
Hans Verkuil51224aa2010-03-22 04:33:56 -0300797
798 for (i = 0; i < MAX_CAMS && parport[i] != -1; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 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);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300810 if (qcam == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 return -ENODEV;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300812
Hans Verkuild71964f2010-05-10 03:55:25 -0300813 v4l2_dev = &qcam->v4l2_dev;
814
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 parport_claim_or_block(qcam->pdev);
816
817 qc_reset(qcam);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300818
Hans Verkuil51224aa2010-03-22 04:33:56 -0300819 if (probe && qc_detect(qcam) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 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);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300829
Hans Verkuildc60de32008-09-03 17:11:58 -0300830 if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
Hans Verkuild71964f2010-05-10 03:55:25 -0300831 v4l2_err(v4l2_dev, "Unable to register Colour QuickCam on %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 qcam->pport->name);
833 parport_unregister_device(qcam->pdev);
834 kfree(qcam);
835 return -ENODEV;
836 }
837
Hans Verkuild71964f2010-05-10 03:55:25 -0300838 v4l2_info(v4l2_dev, "%s: Colour QuickCam found on %s\n",
Laurent Pinchart38c7c032009-11-27 13:57:15 -0300839 video_device_node_name(&qcam->vdev), qcam->pport->name);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300840
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 qcams[num_cams++] = qcam;
842
843 return 0;
844}
845
Hans Verkuild71964f2010-05-10 03:55:25 -0300846static void close_cqcam(struct qcam *qcam)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847{
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
Hans Verkuil51224aa2010-03-22 04:33:56 -0300869static int __init cqcam_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870{
Hans Verkuild71964f2010-05-10 03:55:25 -0300871 printk(KERN_INFO BANNER "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872
873 return parport_register_driver(&cqcam_driver);
874}
875
Hans Verkuil51224aa2010-03-22 04:33:56 -0300876static void __exit cqcam_cleanup(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877{
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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890module_init(cqcam_init);
891module_exit(cqcam_cleanup);