blob: 73c65c2bf17807769d80a6bd8a6878927fa50dba [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/videodev2.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include <asm/uaccess.h>
Hans Verkuild71964f2010-05-10 03:55:25 -030040#include <media/v4l2-device.h>
41#include <media/v4l2-common.h>
42#include <media/v4l2-ioctl.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043
Hans Verkuild71964f2010-05-10 03:55:25 -030044struct qcam {
45 struct v4l2_device v4l2_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -070046 struct video_device vdev;
47 struct pardevice *pdev;
48 struct parport *pport;
49 int width, height;
50 int ccd_width, ccd_height;
51 int mode;
52 int contrast, brightness, whitebal;
53 int top, left;
54 unsigned int bidirectional;
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
Hans Verkuild71964f2010-05-10 03:55:25 -030071#define BANNER "Colour QuickCam for Video4Linux v0.06"
Linus Torvalds1da177e2005-04-16 15:20:36 -070072
73static int parport[MAX_CAMS] = { [1 ... MAX_CAMS-1] = -1 };
74static int probe = 2;
Rusty Russell90ab5ee2012-01-13 09:32:20 +103075static bool force_rgb;
Linus Torvalds1da177e2005-04-16 15:20:36 -070076static int video_nr = -1;
77
Hans Verkuild71964f2010-05-10 03:55:25 -030078/* FIXME: parport=auto would never have worked, surely? --RR */
79MODULE_PARM_DESC(parport, "parport=<auto|n[,n]...> for port detection method\n"
80 "probe=<0|1|2> for camera detection method\n"
81 "force_rgb=<0|1> for RGB data format (default BGR)");
82module_param_array(parport, int, NULL, 0);
83module_param(probe, int, 0);
84module_param(force_rgb, bool, 0);
85module_param(video_nr, int, 0);
86
87static struct qcam *qcams[MAX_CAMS];
88static unsigned int num_cams;
89
90static inline void qcam_set_ack(struct qcam *qcam, unsigned int i)
Linus Torvalds1da177e2005-04-16 15:20:36 -070091{
92 /* note: the QC specs refer to the PCAck pin by voltage, not
93 software level. PC ports have builtin inverters. */
Hans Verkuil51224aa2010-03-22 04:33:56 -030094 parport_frob_control(qcam->pport, 8, i ? 8 : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070095}
96
Hans Verkuild71964f2010-05-10 03:55:25 -030097static inline unsigned int qcam_ready1(struct qcam *qcam)
Linus Torvalds1da177e2005-04-16 15:20:36 -070098{
Hans Verkuil51224aa2010-03-22 04:33:56 -030099 return (parport_read_status(qcam->pport) & 0x8) ? 1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100}
101
Hans Verkuild71964f2010-05-10 03:55:25 -0300102static inline unsigned int qcam_ready2(struct qcam *qcam)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103{
Hans Verkuil51224aa2010-03-22 04:33:56 -0300104 return (parport_read_data(qcam->pport) & 0x1) ? 1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105}
106
Hans Verkuild71964f2010-05-10 03:55:25 -0300107static unsigned int qcam_await_ready1(struct qcam *qcam, int value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108{
Hans Verkuild71964f2010-05-10 03:55:25 -0300109 struct v4l2_device *v4l2_dev = &qcam->v4l2_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 unsigned long oldjiffies = jiffies;
111 unsigned int i;
112
Julia Lawall168c6262008-04-16 16:13:15 -0300113 for (oldjiffies = jiffies;
Hans Verkuil51224aa2010-03-22 04:33:56 -0300114 time_before(jiffies, oldjiffies + msecs_to_jiffies(40));)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115 if (qcam_ready1(qcam) == value)
116 return 0;
117
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300118 /* If the camera didn't respond within 1/25 second, poll slowly
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 for a while. */
Hans Verkuil51224aa2010-03-22 04:33:56 -0300120 for (i = 0; i < 50; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 if (qcam_ready1(qcam) == value)
122 return 0;
123 msleep_interruptible(100);
124 }
125
126 /* Probably somebody pulled the plug out. Not much we can do. */
Hans Verkuild71964f2010-05-10 03:55:25 -0300127 v4l2_err(v4l2_dev, "ready1 timeout (%d) %x %x\n", value,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 parport_read_status(qcam->pport),
129 parport_read_control(qcam->pport));
130 return 1;
131}
132
Hans Verkuild71964f2010-05-10 03:55:25 -0300133static unsigned int qcam_await_ready2(struct qcam *qcam, int value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134{
Hans Verkuild71964f2010-05-10 03:55:25 -0300135 struct v4l2_device *v4l2_dev = &qcam->v4l2_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 unsigned long oldjiffies = jiffies;
137 unsigned int i;
138
Julia Lawall168c6262008-04-16 16:13:15 -0300139 for (oldjiffies = jiffies;
Hans Verkuil51224aa2010-03-22 04:33:56 -0300140 time_before(jiffies, oldjiffies + msecs_to_jiffies(40));)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141 if (qcam_ready2(qcam) == value)
142 return 0;
143
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300144 /* If the camera didn't respond within 1/25 second, poll slowly
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 for a while. */
Hans Verkuil51224aa2010-03-22 04:33:56 -0300146 for (i = 0; i < 50; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 if (qcam_ready2(qcam) == value)
148 return 0;
149 msleep_interruptible(100);
150 }
151
152 /* Probably somebody pulled the plug out. Not much we can do. */
Hans Verkuild71964f2010-05-10 03:55:25 -0300153 v4l2_err(v4l2_dev, "ready2 timeout (%d) %x %x %x\n", value,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 parport_read_status(qcam->pport),
155 parport_read_control(qcam->pport),
156 parport_read_data(qcam->pport));
157 return 1;
158}
159
Hans Verkuild71964f2010-05-10 03:55:25 -0300160static int qcam_read_data(struct qcam *qcam)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161{
162 unsigned int idata;
Hans Verkuil51224aa2010-03-22 04:33:56 -0300163
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 qcam_set_ack(qcam, 0);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300165 if (qcam_await_ready1(qcam, 1))
166 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 idata = parport_read_status(qcam->pport) & 0xf0;
168 qcam_set_ack(qcam, 1);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300169 if (qcam_await_ready1(qcam, 0))
170 return -1;
171 idata |= parport_read_status(qcam->pport) >> 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 return idata;
173}
174
Hans Verkuild71964f2010-05-10 03:55:25 -0300175static int qcam_write_data(struct qcam *qcam, unsigned int data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176{
Hans Verkuild71964f2010-05-10 03:55:25 -0300177 struct v4l2_device *v4l2_dev = &qcam->v4l2_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 unsigned int idata;
Hans Verkuil51224aa2010-03-22 04:33:56 -0300179
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 parport_write_data(qcam->pport, data);
181 idata = qcam_read_data(qcam);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300182 if (data != idata) {
Hans Verkuild71964f2010-05-10 03:55:25 -0300183 v4l2_warn(v4l2_dev, "sent %x but received %x\n", data,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 idata);
185 return 1;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300186 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 return 0;
188}
189
Hans Verkuild71964f2010-05-10 03:55:25 -0300190static inline int qcam_set(struct qcam *qcam, unsigned int cmd, unsigned int data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191{
192 if (qcam_write_data(qcam, cmd))
193 return -1;
194 if (qcam_write_data(qcam, data))
195 return -1;
196 return 0;
197}
198
Hans Verkuild71964f2010-05-10 03:55:25 -0300199static inline int qcam_get(struct qcam *qcam, unsigned int cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200{
201 if (qcam_write_data(qcam, cmd))
202 return -1;
203 return qcam_read_data(qcam);
204}
205
Hans Verkuild71964f2010-05-10 03:55:25 -0300206static int qc_detect(struct qcam *qcam)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207{
208 unsigned int stat, ostat, i, count = 0;
209
210 /* The probe routine below is not very reliable. The IEEE-1284
211 probe takes precedence. */
212 /* XXX Currently parport provides no way to distinguish between
213 "the IEEE probe was not done" and "the probe was done, but
214 no device was found". Fix this one day. */
215 if (qcam->pport->probe_info[0].class == PARPORT_CLASS_MEDIA
216 && qcam->pport->probe_info[0].model
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300217 && !strcmp(qcam->pdev->port->probe_info[0].model,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 "Color QuickCam 2.0")) {
219 printk(KERN_DEBUG "QuickCam: Found by IEEE1284 probe.\n");
220 return 1;
221 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300222
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 if (probe < 2)
224 return 0;
225
226 parport_write_control(qcam->pport, 0xc);
227
228 /* look for a heartbeat */
229 ostat = stat = parport_read_status(qcam->pport);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300230 for (i = 0; i < 250; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 mdelay(1);
232 stat = parport_read_status(qcam->pport);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300233 if (ostat != stat) {
234 if (++count >= 3)
235 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 ostat = stat;
237 }
238 }
239
240 /* Reset the camera and try again */
241 parport_write_control(qcam->pport, 0xc);
242 parport_write_control(qcam->pport, 0x8);
243 mdelay(1);
244 parport_write_control(qcam->pport, 0xc);
245 mdelay(1);
246 count = 0;
247
248 ostat = stat = parport_read_status(qcam->pport);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300249 for (i = 0; i < 250; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 mdelay(1);
251 stat = parport_read_status(qcam->pport);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300252 if (ostat != stat) {
253 if (++count >= 3)
254 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 ostat = stat;
256 }
257 }
258
259 /* no (or flatline) camera, give up */
260 return 0;
261}
262
Hans Verkuild71964f2010-05-10 03:55:25 -0300263static void qc_reset(struct qcam *qcam)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264{
265 parport_write_control(qcam->pport, 0xc);
266 parport_write_control(qcam->pport, 0x8);
267 mdelay(1);
268 parport_write_control(qcam->pport, 0xc);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300269 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270}
271
272/* Reset the QuickCam and program for brightness, contrast,
273 * white-balance, and resolution. */
274
Hans Verkuild71964f2010-05-10 03:55:25 -0300275static void qc_setup(struct qcam *qcam)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276{
Hans Verkuild71964f2010-05-10 03:55:25 -0300277 qc_reset(qcam);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
Hans Verkuil51224aa2010-03-22 04:33:56 -0300279 /* Set the brightness. */
Hans Verkuild71964f2010-05-10 03:55:25 -0300280 qcam_set(qcam, 11, qcam->brightness);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281
282 /* Set the height and width. These refer to the actual
283 CCD area *before* applying the selected decimation. */
Hans Verkuild71964f2010-05-10 03:55:25 -0300284 qcam_set(qcam, 17, qcam->ccd_height);
285 qcam_set(qcam, 19, qcam->ccd_width / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286
287 /* Set top and left. */
Hans Verkuild71964f2010-05-10 03:55:25 -0300288 qcam_set(qcam, 0xd, qcam->top);
289 qcam_set(qcam, 0xf, qcam->left);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290
291 /* Set contrast and white balance. */
Hans Verkuild71964f2010-05-10 03:55:25 -0300292 qcam_set(qcam, 0x19, qcam->contrast);
293 qcam_set(qcam, 0x1f, qcam->whitebal);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300294
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 /* Set the speed. */
Hans Verkuild71964f2010-05-10 03:55:25 -0300296 qcam_set(qcam, 45, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297}
298
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300299/* Read some bytes from the camera and put them in the buffer.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 nbytes should be a multiple of 3, because bidirectional mode gives
301 us three bytes at a time. */
302
Hans Verkuild71964f2010-05-10 03:55:25 -0300303static unsigned int qcam_read_bytes(struct qcam *qcam, unsigned char *buf, unsigned int nbytes)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304{
305 unsigned int bytes = 0;
306
Hans Verkuild71964f2010-05-10 03:55:25 -0300307 qcam_set_ack(qcam, 0);
308 if (qcam->bidirectional) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 /* It's a bidirectional port */
Hans Verkuil51224aa2010-03-22 04:33:56 -0300310 while (bytes < nbytes) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 unsigned int lo1, hi1, lo2, hi2;
312 unsigned char r, g, b;
313
Hans Verkuild71964f2010-05-10 03:55:25 -0300314 if (qcam_await_ready2(qcam, 1))
Hans Verkuil51224aa2010-03-22 04:33:56 -0300315 return bytes;
Hans Verkuild71964f2010-05-10 03:55:25 -0300316 lo1 = parport_read_data(qcam->pport) >> 1;
317 hi1 = ((parport_read_status(qcam->pport) >> 3) & 0x1f) ^ 0x10;
318 qcam_set_ack(qcam, 1);
319 if (qcam_await_ready2(qcam, 0))
Hans Verkuil51224aa2010-03-22 04:33:56 -0300320 return bytes;
Hans Verkuild71964f2010-05-10 03:55:25 -0300321 lo2 = parport_read_data(qcam->pport) >> 1;
322 hi2 = ((parport_read_status(qcam->pport) >> 3) & 0x1f) ^ 0x10;
323 qcam_set_ack(qcam, 0);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300324 r = lo1 | ((hi1 & 1) << 7);
325 g = ((hi1 & 0x1e) << 3) | ((hi2 & 0x1e) >> 1);
326 b = lo2 | ((hi2 & 1) << 7);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 if (force_rgb) {
328 buf[bytes++] = r;
329 buf[bytes++] = g;
330 buf[bytes++] = b;
331 } else {
332 buf[bytes++] = b;
333 buf[bytes++] = g;
334 buf[bytes++] = r;
335 }
336 }
Hans Verkuil51224aa2010-03-22 04:33:56 -0300337 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 /* It's a unidirectional port */
339 int i = 0, n = bytes;
340 unsigned char rgb[3];
341
Hans Verkuil51224aa2010-03-22 04:33:56 -0300342 while (bytes < nbytes) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 unsigned int hi, lo;
344
Hans Verkuild71964f2010-05-10 03:55:25 -0300345 if (qcam_await_ready1(qcam, 1))
Hans Verkuil51224aa2010-03-22 04:33:56 -0300346 return bytes;
Hans Verkuild71964f2010-05-10 03:55:25 -0300347 hi = (parport_read_status(qcam->pport) & 0xf0);
348 qcam_set_ack(qcam, 1);
349 if (qcam_await_ready1(qcam, 0))
Hans Verkuil51224aa2010-03-22 04:33:56 -0300350 return bytes;
Hans Verkuild71964f2010-05-10 03:55:25 -0300351 lo = (parport_read_status(qcam->pport) & 0xf0);
352 qcam_set_ack(qcam, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 /* flip some bits */
354 rgb[(i = bytes++ % 3)] = (hi | (lo >> 4)) ^ 0x88;
355 if (i >= 2) {
356get_fragment:
357 if (force_rgb) {
358 buf[n++] = rgb[0];
359 buf[n++] = rgb[1];
360 buf[n++] = rgb[2];
361 } else {
362 buf[n++] = rgb[2];
363 buf[n++] = rgb[1];
364 buf[n++] = rgb[0];
365 }
366 }
367 }
368 if (i) {
369 i = 0;
370 goto get_fragment;
371 }
372 }
373 return bytes;
374}
375
376#define BUFSZ 150
377
Hans Verkuild71964f2010-05-10 03:55:25 -0300378static long qc_capture(struct qcam *qcam, char __user *buf, unsigned long len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379{
Hans Verkuild71964f2010-05-10 03:55:25 -0300380 struct v4l2_device *v4l2_dev = &qcam->v4l2_dev;
Hans Verkuil81730902012-04-20 07:30:48 -0300381 unsigned lines, pixelsperline;
Hans Verkuild71964f2010-05-10 03:55:25 -0300382 unsigned int is_bi_dir = qcam->bidirectional;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 size_t wantlen, outptr = 0;
384 char tmpbuf[BUFSZ];
385
386 if (!access_ok(VERIFY_WRITE, buf, len))
387 return -EFAULT;
388
389 /* Wait for camera to become ready */
Hans Verkuil51224aa2010-03-22 04:33:56 -0300390 for (;;) {
Hans Verkuild71964f2010-05-10 03:55:25 -0300391 int i = qcam_get(qcam, 41);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300392
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 if (i == -1) {
Hans Verkuild71964f2010-05-10 03:55:25 -0300394 qc_setup(qcam);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 return -EIO;
396 }
397 if ((i & 0x80) == 0)
398 break;
Hans Verkuil51224aa2010-03-22 04:33:56 -0300399 schedule();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 }
401
Hans Verkuild71964f2010-05-10 03:55:25 -0300402 if (qcam_set(qcam, 7, (qcam->mode | (is_bi_dir ? 1 : 0)) + 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 return -EIO;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300404
Hans Verkuild71964f2010-05-10 03:55:25 -0300405 lines = qcam->height;
406 pixelsperline = qcam->width;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407
Hans Verkuil51224aa2010-03-22 04:33:56 -0300408 if (is_bi_dir) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 /* Turn the port around */
Hans Verkuild71964f2010-05-10 03:55:25 -0300410 parport_data_reverse(qcam->pport);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 mdelay(3);
Hans Verkuild71964f2010-05-10 03:55:25 -0300412 qcam_set_ack(qcam, 0);
413 if (qcam_await_ready1(qcam, 1)) {
414 qc_setup(qcam);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 return -EIO;
416 }
Hans Verkuild71964f2010-05-10 03:55:25 -0300417 qcam_set_ack(qcam, 1);
418 if (qcam_await_ready1(qcam, 0)) {
419 qc_setup(qcam);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 return -EIO;
421 }
422 }
423
424 wantlen = lines * pixelsperline * 24 / 8;
425
Hans Verkuil51224aa2010-03-22 04:33:56 -0300426 while (wantlen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 size_t t, s;
Hans Verkuil51224aa2010-03-22 04:33:56 -0300428
429 s = (wantlen > BUFSZ) ? BUFSZ : wantlen;
Hans Verkuild71964f2010-05-10 03:55:25 -0300430 t = qcam_read_bytes(qcam, tmpbuf, s);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300431 if (outptr < len) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 size_t sz = len - outptr;
Hans Verkuil51224aa2010-03-22 04:33:56 -0300433
434 if (sz > t)
435 sz = t;
436 if (__copy_to_user(buf + outptr, tmpbuf, sz))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 break;
438 outptr += sz;
439 }
440 wantlen -= t;
441 if (t < s)
442 break;
443 cond_resched();
444 }
445
446 len = outptr;
447
Hans Verkuil51224aa2010-03-22 04:33:56 -0300448 if (wantlen) {
Hans Verkuild71964f2010-05-10 03:55:25 -0300449 v4l2_err(v4l2_dev, "short read.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 if (is_bi_dir)
Hans Verkuild71964f2010-05-10 03:55:25 -0300451 parport_data_forward(qcam->pport);
452 qc_setup(qcam);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 return len;
454 }
455
Hans Verkuil51224aa2010-03-22 04:33:56 -0300456 if (is_bi_dir) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 int l;
Hans Verkuil51224aa2010-03-22 04:33:56 -0300458
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 do {
Hans Verkuild71964f2010-05-10 03:55:25 -0300460 l = qcam_read_bytes(qcam, tmpbuf, 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 cond_resched();
462 } while (l && (tmpbuf[0] == 0x7e || tmpbuf[1] == 0x7e || tmpbuf[2] == 0x7e));
463 if (force_rgb) {
464 if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
Hans Verkuild71964f2010-05-10 03:55:25 -0300465 v4l2_err(v4l2_dev, "bad EOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 } else {
467 if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe)
Hans Verkuild71964f2010-05-10 03:55:25 -0300468 v4l2_err(v4l2_dev, "bad EOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 }
Hans Verkuild71964f2010-05-10 03:55:25 -0300470 qcam_set_ack(qcam, 0);
471 if (qcam_await_ready1(qcam, 1)) {
472 v4l2_err(v4l2_dev, "no ack after EOF\n");
473 parport_data_forward(qcam->pport);
474 qc_setup(qcam);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 return len;
476 }
Hans Verkuild71964f2010-05-10 03:55:25 -0300477 parport_data_forward(qcam->pport);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 mdelay(3);
Hans Verkuild71964f2010-05-10 03:55:25 -0300479 qcam_set_ack(qcam, 1);
480 if (qcam_await_ready1(qcam, 0)) {
481 v4l2_err(v4l2_dev, "no ack to port turnaround\n");
482 qc_setup(qcam);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 return len;
484 }
Hans Verkuil51224aa2010-03-22 04:33:56 -0300485 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 int l;
Hans Verkuil51224aa2010-03-22 04:33:56 -0300487
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 do {
Hans Verkuild71964f2010-05-10 03:55:25 -0300489 l = qcam_read_bytes(qcam, tmpbuf, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 cond_resched();
491 } while (l && tmpbuf[0] == 0x7e);
Hans Verkuild71964f2010-05-10 03:55:25 -0300492 l = qcam_read_bytes(qcam, tmpbuf + 1, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 if (force_rgb) {
494 if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
Hans Verkuild71964f2010-05-10 03:55:25 -0300495 v4l2_err(v4l2_dev, "bad EOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 } else {
497 if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe)
Hans Verkuild71964f2010-05-10 03:55:25 -0300498 v4l2_err(v4l2_dev, "bad EOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 }
500 }
501
Hans Verkuild71964f2010-05-10 03:55:25 -0300502 qcam_write_data(qcam, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 return len;
504}
505
506/*
507 * Video4linux interfacing
508 */
509
Hans Verkuild71964f2010-05-10 03:55:25 -0300510static int qcam_querycap(struct file *file, void *priv,
511 struct v4l2_capability *vcap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512{
Hans Verkuild71964f2010-05-10 03:55:25 -0300513 struct qcam *qcam = video_drvdata(file);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300514
Hans Verkuild71964f2010-05-10 03:55:25 -0300515 strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver));
516 strlcpy(vcap->card, "Color Quickcam", sizeof(vcap->card));
517 strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info));
Hans Verkuild71964f2010-05-10 03:55:25 -0300518 vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 return 0;
520}
521
Hans Verkuild71964f2010-05-10 03:55:25 -0300522static int qcam_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523{
Hans Verkuild71964f2010-05-10 03:55:25 -0300524 if (vin->index > 0)
525 return -EINVAL;
526 strlcpy(vin->name, "Camera", sizeof(vin->name));
527 vin->type = V4L2_INPUT_TYPE_CAMERA;
528 vin->audioset = 0;
529 vin->tuner = 0;
530 vin->std = 0;
531 vin->status = 0;
532 return 0;
533}
534
535static int qcam_g_input(struct file *file, void *fh, unsigned int *inp)
536{
537 *inp = 0;
538 return 0;
539}
540
541static int qcam_s_input(struct file *file, void *fh, unsigned int inp)
542{
543 return (inp > 0) ? -EINVAL : 0;
544}
545
546static int qcam_queryctrl(struct file *file, void *priv,
547 struct v4l2_queryctrl *qc)
548{
549 switch (qc->id) {
550 case V4L2_CID_BRIGHTNESS:
551 return v4l2_ctrl_query_fill(qc, 0, 255, 1, 240);
552 case V4L2_CID_CONTRAST:
553 return v4l2_ctrl_query_fill(qc, 0, 255, 1, 192);
554 case V4L2_CID_GAMMA:
555 return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
556 }
557 return -EINVAL;
558}
559
560static int qcam_g_ctrl(struct file *file, void *priv,
561 struct v4l2_control *ctrl)
562{
563 struct qcam *qcam = video_drvdata(file);
564 int ret = 0;
565
566 switch (ctrl->id) {
567 case V4L2_CID_BRIGHTNESS:
568 ctrl->value = qcam->brightness;
569 break;
570 case V4L2_CID_CONTRAST:
571 ctrl->value = qcam->contrast;
572 break;
573 case V4L2_CID_GAMMA:
574 ctrl->value = qcam->whitebal;
575 break;
576 default:
577 ret = -EINVAL;
578 break;
579 }
580 return ret;
581}
582
583static int qcam_s_ctrl(struct file *file, void *priv,
584 struct v4l2_control *ctrl)
585{
586 struct qcam *qcam = video_drvdata(file);
587 int ret = 0;
588
589 mutex_lock(&qcam->lock);
590 switch (ctrl->id) {
591 case V4L2_CID_BRIGHTNESS:
592 qcam->brightness = ctrl->value;
593 break;
594 case V4L2_CID_CONTRAST:
595 qcam->contrast = ctrl->value;
596 break;
597 case V4L2_CID_GAMMA:
598 qcam->whitebal = ctrl->value;
599 break;
600 default:
601 ret = -EINVAL;
602 break;
603 }
604 if (ret == 0) {
605 parport_claim_or_block(qcam->pdev);
606 qc_setup(qcam);
607 parport_release(qcam->pdev);
608 }
609 mutex_unlock(&qcam->lock);
610 return ret;
611}
612
613static int qcam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
614{
615 struct qcam *qcam = video_drvdata(file);
616 struct v4l2_pix_format *pix = &fmt->fmt.pix;
617
618 pix->width = qcam->width;
619 pix->height = qcam->height;
620 pix->pixelformat = V4L2_PIX_FMT_RGB24;
621 pix->field = V4L2_FIELD_NONE;
622 pix->bytesperline = 3 * qcam->width;
623 pix->sizeimage = 3 * qcam->width * qcam->height;
624 /* Just a guess */
625 pix->colorspace = V4L2_COLORSPACE_SRGB;
626 return 0;
627}
628
629static int qcam_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
630{
631 struct v4l2_pix_format *pix = &fmt->fmt.pix;
632
633 if (pix->height < 60 || pix->width < 80) {
634 pix->height = 60;
635 pix->width = 80;
636 } else if (pix->height < 120 || pix->width < 160) {
637 pix->height = 120;
638 pix->width = 160;
639 } else {
640 pix->height = 240;
641 pix->width = 320;
642 }
643 pix->pixelformat = V4L2_PIX_FMT_RGB24;
644 pix->field = V4L2_FIELD_NONE;
645 pix->bytesperline = 3 * pix->width;
646 pix->sizeimage = 3 * pix->width * pix->height;
647 /* Just a guess */
648 pix->colorspace = V4L2_COLORSPACE_SRGB;
649 return 0;
650}
651
652static int qcam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
653{
654 struct qcam *qcam = video_drvdata(file);
655 struct v4l2_pix_format *pix = &fmt->fmt.pix;
656 int ret = qcam_try_fmt_vid_cap(file, fh, fmt);
657
658 if (ret)
659 return ret;
660 switch (pix->height) {
661 case 60:
662 qcam->mode = QC_DECIMATION_4;
663 break;
664 case 120:
665 qcam->mode = QC_DECIMATION_2;
666 break;
667 default:
668 qcam->mode = QC_DECIMATION_1;
669 break;
670 }
671
672 mutex_lock(&qcam->lock);
673 qcam->mode |= QC_MILLIONS;
674 qcam->height = pix->height;
675 qcam->width = pix->width;
676 parport_claim_or_block(qcam->pdev);
677 qc_setup(qcam);
678 parport_release(qcam->pdev);
679 mutex_unlock(&qcam->lock);
680 return 0;
681}
682
683static int qcam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt)
684{
685 static struct v4l2_fmtdesc formats[] = {
686 { 0, 0, 0,
687 "RGB 8:8:8", V4L2_PIX_FMT_RGB24,
688 { 0, 0, 0, 0 }
689 },
690 };
691 enum v4l2_buf_type type = fmt->type;
692
693 if (fmt->index > 0)
694 return -EINVAL;
695
696 *fmt = formats[fmt->index];
697 fmt->type = type;
698 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699}
700
701static ssize_t qcam_read(struct file *file, char __user *buf,
702 size_t count, loff_t *ppos)
703{
Hans Verkuild71964f2010-05-10 03:55:25 -0300704 struct qcam *qcam = video_drvdata(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 int len;
706
Ingo Molnar3593cab2006-02-07 06:49:14 -0200707 mutex_lock(&qcam->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 parport_claim_or_block(qcam->pdev);
709 /* Probably should have a semaphore against multiple users */
Hans Verkuil51224aa2010-03-22 04:33:56 -0300710 len = qc_capture(qcam, buf, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 parport_release(qcam->pdev);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200712 mutex_unlock(&qcam->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 return len;
714}
715
Hans Verkuilbec43662008-12-30 06:58:20 -0300716static const struct v4l2_file_operations qcam_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 .owner = THIS_MODULE,
Hans Verkuil61df3c92010-11-14 10:09:38 -0300718 .unlocked_ioctl = video_ioctl2,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 .read = qcam_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720};
721
Hans Verkuild71964f2010-05-10 03:55:25 -0300722static const struct v4l2_ioctl_ops qcam_ioctl_ops = {
723 .vidioc_querycap = qcam_querycap,
724 .vidioc_g_input = qcam_g_input,
725 .vidioc_s_input = qcam_s_input,
726 .vidioc_enum_input = qcam_enum_input,
727 .vidioc_queryctrl = qcam_queryctrl,
728 .vidioc_g_ctrl = qcam_g_ctrl,
729 .vidioc_s_ctrl = qcam_s_ctrl,
730 .vidioc_enum_fmt_vid_cap = qcam_enum_fmt_vid_cap,
731 .vidioc_g_fmt_vid_cap = qcam_g_fmt_vid_cap,
732 .vidioc_s_fmt_vid_cap = qcam_s_fmt_vid_cap,
733 .vidioc_try_fmt_vid_cap = qcam_try_fmt_vid_cap,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734};
735
736/* Initialize the QuickCam driver control structure. */
737
Hans Verkuild71964f2010-05-10 03:55:25 -0300738static struct qcam *qcam_init(struct parport *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739{
Hans Verkuild71964f2010-05-10 03:55:25 -0300740 struct qcam *qcam;
741 struct v4l2_device *v4l2_dev;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300742
Hans Verkuild71964f2010-05-10 03:55:25 -0300743 qcam = kzalloc(sizeof(*qcam), GFP_KERNEL);
744 if (qcam == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 return NULL;
746
Hans Verkuild71964f2010-05-10 03:55:25 -0300747 v4l2_dev = &qcam->v4l2_dev;
748 strlcpy(v4l2_dev->name, "c-qcam", sizeof(v4l2_dev->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749
Hans Verkuild71964f2010-05-10 03:55:25 -0300750 if (v4l2_device_register(NULL, v4l2_dev) < 0) {
751 v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
Julia Lawallee893e92011-07-04 11:11:42 -0300752 kfree(qcam);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 return NULL;
754 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300755
Hans Verkuild71964f2010-05-10 03:55:25 -0300756 qcam->pport = port;
757 qcam->pdev = parport_register_device(port, "c-qcam", NULL, NULL,
758 NULL, 0, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759
Hans Verkuild71964f2010-05-10 03:55:25 -0300760 qcam->bidirectional = (qcam->pport->modes & PARPORT_MODE_TRISTATE) ? 1 : 0;
761
762 if (qcam->pdev == NULL) {
763 v4l2_err(v4l2_dev, "couldn't register for %s.\n", port->name);
764 kfree(qcam);
765 return NULL;
766 }
767
768 strlcpy(qcam->vdev.name, "Colour QuickCam", sizeof(qcam->vdev.name));
769 qcam->vdev.v4l2_dev = v4l2_dev;
770 qcam->vdev.fops = &qcam_fops;
771 qcam->vdev.ioctl_ops = &qcam_ioctl_ops;
772 qcam->vdev.release = video_device_release_empty;
773 video_set_drvdata(&qcam->vdev, qcam);
774
775 mutex_init(&qcam->lock);
776 qcam->width = qcam->ccd_width = 320;
777 qcam->height = qcam->ccd_height = 240;
778 qcam->mode = QC_MILLIONS | QC_DECIMATION_1;
779 qcam->contrast = 192;
780 qcam->brightness = 240;
781 qcam->whitebal = 128;
782 qcam->top = 1;
783 qcam->left = 14;
784 return qcam;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785}
786
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787static int init_cqcam(struct parport *port)
788{
Hans Verkuild71964f2010-05-10 03:55:25 -0300789 struct qcam *qcam;
790 struct v4l2_device *v4l2_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791
Hans Verkuil51224aa2010-03-22 04:33:56 -0300792 if (parport[0] != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 /* The user gave specific instructions */
794 int i, found = 0;
Hans Verkuil51224aa2010-03-22 04:33:56 -0300795
796 for (i = 0; i < MAX_CAMS && parport[i] != -1; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 if (parport[0] == port->number)
798 found = 1;
799 }
800 if (!found)
801 return -ENODEV;
802 }
803
804 if (num_cams == MAX_CAMS)
805 return -ENOSPC;
806
807 qcam = qcam_init(port);
Hans Verkuil51224aa2010-03-22 04:33:56 -0300808 if (qcam == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 return -ENODEV;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300810
Hans Verkuild71964f2010-05-10 03:55:25 -0300811 v4l2_dev = &qcam->v4l2_dev;
812
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 parport_claim_or_block(qcam->pdev);
814
815 qc_reset(qcam);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300816
Hans Verkuil51224aa2010-03-22 04:33:56 -0300817 if (probe && qc_detect(qcam) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 parport_release(qcam->pdev);
819 parport_unregister_device(qcam->pdev);
820 kfree(qcam);
821 return -ENODEV;
822 }
823
824 qc_setup(qcam);
825
826 parport_release(qcam->pdev);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300827
Hans Verkuildc60de32008-09-03 17:11:58 -0300828 if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
Hans Verkuild71964f2010-05-10 03:55:25 -0300829 v4l2_err(v4l2_dev, "Unable to register Colour QuickCam on %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 qcam->pport->name);
831 parport_unregister_device(qcam->pdev);
832 kfree(qcam);
833 return -ENODEV;
834 }
835
Hans Verkuild71964f2010-05-10 03:55:25 -0300836 v4l2_info(v4l2_dev, "%s: Colour QuickCam found on %s\n",
Laurent Pinchart38c7c032009-11-27 13:57:15 -0300837 video_device_node_name(&qcam->vdev), qcam->pport->name);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300838
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 qcams[num_cams++] = qcam;
840
841 return 0;
842}
843
Hans Verkuild71964f2010-05-10 03:55:25 -0300844static void close_cqcam(struct qcam *qcam)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845{
846 video_unregister_device(&qcam->vdev);
847 parport_unregister_device(qcam->pdev);
848 kfree(qcam);
849}
850
851static void cq_attach(struct parport *port)
852{
853 init_cqcam(port);
854}
855
856static void cq_detach(struct parport *port)
857{
858 /* Write this some day. */
859}
860
861static struct parport_driver cqcam_driver = {
862 .name = "cqcam",
863 .attach = cq_attach,
864 .detach = cq_detach,
865};
866
Hans Verkuil51224aa2010-03-22 04:33:56 -0300867static int __init cqcam_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868{
Hans Verkuild71964f2010-05-10 03:55:25 -0300869 printk(KERN_INFO BANNER "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870
871 return parport_register_driver(&cqcam_driver);
872}
873
Hans Verkuil51224aa2010-03-22 04:33:56 -0300874static void __exit cqcam_cleanup(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875{
876 unsigned int i;
877
878 for (i = 0; i < num_cams; i++)
879 close_cqcam(qcams[i]);
880
881 parport_unregister_driver(&cqcam_driver);
882}
883
884MODULE_AUTHOR("Philip Blundell <philb@gnu.org>");
885MODULE_DESCRIPTION(BANNER);
886MODULE_LICENSE("GPL");
Mauro Carvalho Chehab1990d502011-06-24 14:45:49 -0300887MODULE_VERSION("0.0.4");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889module_init(cqcam_init);
890module_exit(cqcam_cleanup);