diff options
Diffstat (limited to 'drivers/media/video/c-qcam.c')
-rw-r--r-- | drivers/media/video/c-qcam.c | 634 |
1 files changed, 330 insertions, 304 deletions
diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c index 8f1dd88b32a6..6e4b19698c13 100644 --- a/drivers/media/video/c-qcam.c +++ b/drivers/media/video/c-qcam.c | |||
@@ -33,15 +33,17 @@ | |||
33 | #include <linux/mm.h> | 33 | #include <linux/mm.h> |
34 | #include <linux/parport.h> | 34 | #include <linux/parport.h> |
35 | #include <linux/sched.h> | 35 | #include <linux/sched.h> |
36 | #include <linux/videodev.h> | ||
37 | #include <media/v4l2-common.h> | ||
38 | #include <media/v4l2-ioctl.h> | ||
39 | #include <linux/mutex.h> | 36 | #include <linux/mutex.h> |
40 | #include <linux/jiffies.h> | 37 | #include <linux/jiffies.h> |
41 | 38 | #include <linux/version.h> | |
39 | #include <linux/videodev2.h> | ||
42 | #include <asm/uaccess.h> | 40 | #include <asm/uaccess.h> |
41 | #include <media/v4l2-device.h> | ||
42 | #include <media/v4l2-common.h> | ||
43 | #include <media/v4l2-ioctl.h> | ||
43 | 44 | ||
44 | struct qcam_device { | 45 | struct qcam { |
46 | struct v4l2_device v4l2_dev; | ||
45 | struct video_device vdev; | 47 | struct video_device vdev; |
46 | struct pardevice *pdev; | 48 | struct pardevice *pdev; |
47 | struct parport *pport; | 49 | struct parport *pport; |
@@ -51,7 +53,6 @@ struct qcam_device { | |||
51 | int contrast, brightness, whitebal; | 53 | int contrast, brightness, whitebal; |
52 | int top, left; | 54 | int top, left; |
53 | unsigned int bidirectional; | 55 | unsigned int bidirectional; |
54 | unsigned long in_use; | ||
55 | struct mutex lock; | 56 | struct mutex lock; |
56 | }; | 57 | }; |
57 | 58 | ||
@@ -68,33 +69,45 @@ struct qcam_device { | |||
68 | #define QC_DECIMATION_2 2 | 69 | #define QC_DECIMATION_2 2 |
69 | #define QC_DECIMATION_4 4 | 70 | #define QC_DECIMATION_4 4 |
70 | 71 | ||
71 | #define BANNER "Colour QuickCam for Video4Linux v0.05" | 72 | #define BANNER "Colour QuickCam for Video4Linux v0.06" |
72 | 73 | ||
73 | static int parport[MAX_CAMS] = { [1 ... MAX_CAMS-1] = -1 }; | 74 | static int parport[MAX_CAMS] = { [1 ... MAX_CAMS-1] = -1 }; |
74 | static int probe = 2; | 75 | static int probe = 2; |
75 | static int force_rgb; | 76 | static int force_rgb; |
76 | static int video_nr = -1; | 77 | static int video_nr = -1; |
77 | 78 | ||
78 | static inline void qcam_set_ack(struct qcam_device *qcam, unsigned int i) | 79 | /* FIXME: parport=auto would never have worked, surely? --RR */ |
80 | MODULE_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)"); | ||
83 | module_param_array(parport, int, NULL, 0); | ||
84 | module_param(probe, int, 0); | ||
85 | module_param(force_rgb, bool, 0); | ||
86 | module_param(video_nr, int, 0); | ||
87 | |||
88 | static struct qcam *qcams[MAX_CAMS]; | ||
89 | static unsigned int num_cams; | ||
90 | |||
91 | static inline void qcam_set_ack(struct qcam *qcam, unsigned int i) | ||
79 | { | 92 | { |
80 | /* note: the QC specs refer to the PCAck pin by voltage, not | 93 | /* note: the QC specs refer to the PCAck pin by voltage, not |
81 | software level. PC ports have builtin inverters. */ | 94 | software level. PC ports have builtin inverters. */ |
82 | parport_frob_control(qcam->pport, 8, i ? 8 : 0); | 95 | parport_frob_control(qcam->pport, 8, i ? 8 : 0); |
83 | } | 96 | } |
84 | 97 | ||
85 | static inline unsigned int qcam_ready1(struct qcam_device *qcam) | 98 | static inline unsigned int qcam_ready1(struct qcam *qcam) |
86 | { | 99 | { |
87 | return (parport_read_status(qcam->pport) & 0x8) ? 1 : 0; | 100 | return (parport_read_status(qcam->pport) & 0x8) ? 1 : 0; |
88 | } | 101 | } |
89 | 102 | ||
90 | static inline unsigned int qcam_ready2(struct qcam_device *qcam) | 103 | static inline unsigned int qcam_ready2(struct qcam *qcam) |
91 | { | 104 | { |
92 | return (parport_read_data(qcam->pport) & 0x1) ? 1 : 0; | 105 | return (parport_read_data(qcam->pport) & 0x1) ? 1 : 0; |
93 | } | 106 | } |
94 | 107 | ||
95 | static unsigned int qcam_await_ready1(struct qcam_device *qcam, | 108 | static unsigned int qcam_await_ready1(struct qcam *qcam, int value) |
96 | int value) | ||
97 | { | 109 | { |
110 | struct v4l2_device *v4l2_dev = &qcam->v4l2_dev; | ||
98 | unsigned long oldjiffies = jiffies; | 111 | unsigned long oldjiffies = jiffies; |
99 | unsigned int i; | 112 | unsigned int i; |
100 | 113 | ||
@@ -112,14 +125,15 @@ static unsigned int qcam_await_ready1(struct qcam_device *qcam, | |||
112 | } | 125 | } |
113 | 126 | ||
114 | /* Probably somebody pulled the plug out. Not much we can do. */ | 127 | /* Probably somebody pulled the plug out. Not much we can do. */ |
115 | printk(KERN_ERR "c-qcam: ready1 timeout (%d) %x %x\n", value, | 128 | v4l2_err(v4l2_dev, "ready1 timeout (%d) %x %x\n", value, |
116 | parport_read_status(qcam->pport), | 129 | parport_read_status(qcam->pport), |
117 | parport_read_control(qcam->pport)); | 130 | parport_read_control(qcam->pport)); |
118 | return 1; | 131 | return 1; |
119 | } | 132 | } |
120 | 133 | ||
121 | static unsigned int qcam_await_ready2(struct qcam_device *qcam, int value) | 134 | static unsigned int qcam_await_ready2(struct qcam *qcam, int value) |
122 | { | 135 | { |
136 | struct v4l2_device *v4l2_dev = &qcam->v4l2_dev; | ||
123 | unsigned long oldjiffies = jiffies; | 137 | unsigned long oldjiffies = jiffies; |
124 | unsigned int i; | 138 | unsigned int i; |
125 | 139 | ||
@@ -137,14 +151,14 @@ static unsigned int qcam_await_ready2(struct qcam_device *qcam, int value) | |||
137 | } | 151 | } |
138 | 152 | ||
139 | /* Probably somebody pulled the plug out. Not much we can do. */ | 153 | /* Probably somebody pulled the plug out. Not much we can do. */ |
140 | printk(KERN_ERR "c-qcam: ready2 timeout (%d) %x %x %x\n", value, | 154 | v4l2_err(v4l2_dev, "ready2 timeout (%d) %x %x %x\n", value, |
141 | parport_read_status(qcam->pport), | 155 | parport_read_status(qcam->pport), |
142 | parport_read_control(qcam->pport), | 156 | parport_read_control(qcam->pport), |
143 | parport_read_data(qcam->pport)); | 157 | parport_read_data(qcam->pport)); |
144 | return 1; | 158 | return 1; |
145 | } | 159 | } |
146 | 160 | ||
147 | static int qcam_read_data(struct qcam_device *qcam) | 161 | static int qcam_read_data(struct qcam *qcam) |
148 | { | 162 | { |
149 | unsigned int idata; | 163 | unsigned int idata; |
150 | 164 | ||
@@ -159,21 +173,22 @@ static int qcam_read_data(struct qcam_device *qcam) | |||
159 | return idata; | 173 | return idata; |
160 | } | 174 | } |
161 | 175 | ||
162 | static int qcam_write_data(struct qcam_device *qcam, unsigned int data) | 176 | static int qcam_write_data(struct qcam *qcam, unsigned int data) |
163 | { | 177 | { |
178 | struct v4l2_device *v4l2_dev = &qcam->v4l2_dev; | ||
164 | unsigned int idata; | 179 | unsigned int idata; |
165 | 180 | ||
166 | parport_write_data(qcam->pport, data); | 181 | parport_write_data(qcam->pport, data); |
167 | idata = qcam_read_data(qcam); | 182 | idata = qcam_read_data(qcam); |
168 | if (data != idata) { | 183 | if (data != idata) { |
169 | printk(KERN_WARNING "cqcam: sent %x but received %x\n", data, | 184 | v4l2_warn(v4l2_dev, "sent %x but received %x\n", data, |
170 | idata); | 185 | idata); |
171 | return 1; | 186 | return 1; |
172 | } | 187 | } |
173 | return 0; | 188 | return 0; |
174 | } | 189 | } |
175 | 190 | ||
176 | static inline int qcam_set(struct qcam_device *qcam, unsigned int cmd, unsigned int data) | 191 | static inline int qcam_set(struct qcam *qcam, unsigned int cmd, unsigned int data) |
177 | { | 192 | { |
178 | if (qcam_write_data(qcam, cmd)) | 193 | if (qcam_write_data(qcam, cmd)) |
179 | return -1; | 194 | return -1; |
@@ -182,14 +197,14 @@ static inline int qcam_set(struct qcam_device *qcam, unsigned int cmd, unsigned | |||
182 | return 0; | 197 | return 0; |
183 | } | 198 | } |
184 | 199 | ||
185 | static inline int qcam_get(struct qcam_device *qcam, unsigned int cmd) | 200 | static inline int qcam_get(struct qcam *qcam, unsigned int cmd) |
186 | { | 201 | { |
187 | if (qcam_write_data(qcam, cmd)) | 202 | if (qcam_write_data(qcam, cmd)) |
188 | return -1; | 203 | return -1; |
189 | return qcam_read_data(qcam); | 204 | return qcam_read_data(qcam); |
190 | } | 205 | } |
191 | 206 | ||
192 | static int qc_detect(struct qcam_device *qcam) | 207 | static int qc_detect(struct qcam *qcam) |
193 | { | 208 | { |
194 | unsigned int stat, ostat, i, count = 0; | 209 | unsigned int stat, ostat, i, count = 0; |
195 | 210 | ||
@@ -246,7 +261,7 @@ static int qc_detect(struct qcam_device *qcam) | |||
246 | return 0; | 261 | return 0; |
247 | } | 262 | } |
248 | 263 | ||
249 | static void qc_reset(struct qcam_device *qcam) | 264 | static void qc_reset(struct qcam *qcam) |
250 | { | 265 | { |
251 | parport_write_control(qcam->pport, 0xc); | 266 | parport_write_control(qcam->pport, 0xc); |
252 | parport_write_control(qcam->pport, 0x8); | 267 | parport_write_control(qcam->pport, 0x8); |
@@ -258,55 +273,55 @@ static void qc_reset(struct qcam_device *qcam) | |||
258 | /* Reset the QuickCam and program for brightness, contrast, | 273 | /* Reset the QuickCam and program for brightness, contrast, |
259 | * white-balance, and resolution. */ | 274 | * white-balance, and resolution. */ |
260 | 275 | ||
261 | static void qc_setup(struct qcam_device *q) | 276 | static void qc_setup(struct qcam *qcam) |
262 | { | 277 | { |
263 | qc_reset(q); | 278 | qc_reset(qcam); |
264 | 279 | ||
265 | /* Set the brightness. */ | 280 | /* Set the brightness. */ |
266 | qcam_set(q, 11, q->brightness); | 281 | qcam_set(qcam, 11, qcam->brightness); |
267 | 282 | ||
268 | /* Set the height and width. These refer to the actual | 283 | /* Set the height and width. These refer to the actual |
269 | CCD area *before* applying the selected decimation. */ | 284 | CCD area *before* applying the selected decimation. */ |
270 | qcam_set(q, 17, q->ccd_height); | 285 | qcam_set(qcam, 17, qcam->ccd_height); |
271 | qcam_set(q, 19, q->ccd_width / 2); | 286 | qcam_set(qcam, 19, qcam->ccd_width / 2); |
272 | 287 | ||
273 | /* Set top and left. */ | 288 | /* Set top and left. */ |
274 | qcam_set(q, 0xd, q->top); | 289 | qcam_set(qcam, 0xd, qcam->top); |
275 | qcam_set(q, 0xf, q->left); | 290 | qcam_set(qcam, 0xf, qcam->left); |
276 | 291 | ||
277 | /* Set contrast and white balance. */ | 292 | /* Set contrast and white balance. */ |
278 | qcam_set(q, 0x19, q->contrast); | 293 | qcam_set(qcam, 0x19, qcam->contrast); |
279 | qcam_set(q, 0x1f, q->whitebal); | 294 | qcam_set(qcam, 0x1f, qcam->whitebal); |
280 | 295 | ||
281 | /* Set the speed. */ | 296 | /* Set the speed. */ |
282 | qcam_set(q, 45, 2); | 297 | qcam_set(qcam, 45, 2); |
283 | } | 298 | } |
284 | 299 | ||
285 | /* Read some bytes from the camera and put them in the buffer. | 300 | /* Read some bytes from the camera and put them in the buffer. |
286 | nbytes should be a multiple of 3, because bidirectional mode gives | 301 | nbytes should be a multiple of 3, because bidirectional mode gives |
287 | us three bytes at a time. */ | 302 | us three bytes at a time. */ |
288 | 303 | ||
289 | static unsigned int qcam_read_bytes(struct qcam_device *q, unsigned char *buf, unsigned int nbytes) | 304 | static unsigned int qcam_read_bytes(struct qcam *qcam, unsigned char *buf, unsigned int nbytes) |
290 | { | 305 | { |
291 | unsigned int bytes = 0; | 306 | unsigned int bytes = 0; |
292 | 307 | ||
293 | qcam_set_ack(q, 0); | 308 | qcam_set_ack(qcam, 0); |
294 | if (q->bidirectional) { | 309 | if (qcam->bidirectional) { |
295 | /* It's a bidirectional port */ | 310 | /* It's a bidirectional port */ |
296 | while (bytes < nbytes) { | 311 | while (bytes < nbytes) { |
297 | unsigned int lo1, hi1, lo2, hi2; | 312 | unsigned int lo1, hi1, lo2, hi2; |
298 | unsigned char r, g, b; | 313 | unsigned char r, g, b; |
299 | 314 | ||
300 | if (qcam_await_ready2(q, 1)) | 315 | if (qcam_await_ready2(qcam, 1)) |
301 | return bytes; | 316 | return bytes; |
302 | lo1 = parport_read_data(q->pport) >> 1; | 317 | lo1 = parport_read_data(qcam->pport) >> 1; |
303 | hi1 = ((parport_read_status(q->pport) >> 3) & 0x1f) ^ 0x10; | 318 | hi1 = ((parport_read_status(qcam->pport) >> 3) & 0x1f) ^ 0x10; |
304 | qcam_set_ack(q, 1); | 319 | qcam_set_ack(qcam, 1); |
305 | if (qcam_await_ready2(q, 0)) | 320 | if (qcam_await_ready2(qcam, 0)) |
306 | return bytes; | 321 | return bytes; |
307 | lo2 = parport_read_data(q->pport) >> 1; | 322 | lo2 = parport_read_data(qcam->pport) >> 1; |
308 | hi2 = ((parport_read_status(q->pport) >> 3) & 0x1f) ^ 0x10; | 323 | hi2 = ((parport_read_status(qcam->pport) >> 3) & 0x1f) ^ 0x10; |
309 | qcam_set_ack(q, 0); | 324 | qcam_set_ack(qcam, 0); |
310 | r = lo1 | ((hi1 & 1) << 7); | 325 | r = lo1 | ((hi1 & 1) << 7); |
311 | g = ((hi1 & 0x1e) << 3) | ((hi2 & 0x1e) >> 1); | 326 | g = ((hi1 & 0x1e) << 3) | ((hi2 & 0x1e) >> 1); |
312 | b = lo2 | ((hi2 & 1) << 7); | 327 | b = lo2 | ((hi2 & 1) << 7); |
@@ -328,14 +343,14 @@ static unsigned int qcam_read_bytes(struct qcam_device *q, unsigned char *buf, u | |||
328 | while (bytes < nbytes) { | 343 | while (bytes < nbytes) { |
329 | unsigned int hi, lo; | 344 | unsigned int hi, lo; |
330 | 345 | ||
331 | if (qcam_await_ready1(q, 1)) | 346 | if (qcam_await_ready1(qcam, 1)) |
332 | return bytes; | 347 | return bytes; |
333 | hi = (parport_read_status(q->pport) & 0xf0); | 348 | hi = (parport_read_status(qcam->pport) & 0xf0); |
334 | qcam_set_ack(q, 1); | 349 | qcam_set_ack(qcam, 1); |
335 | if (qcam_await_ready1(q, 0)) | 350 | if (qcam_await_ready1(qcam, 0)) |
336 | return bytes; | 351 | return bytes; |
337 | lo = (parport_read_status(q->pport) & 0xf0); | 352 | lo = (parport_read_status(qcam->pport) & 0xf0); |
338 | qcam_set_ack(q, 0); | 353 | qcam_set_ack(qcam, 0); |
339 | /* flip some bits */ | 354 | /* flip some bits */ |
340 | rgb[(i = bytes++ % 3)] = (hi | (lo >> 4)) ^ 0x88; | 355 | rgb[(i = bytes++ % 3)] = (hi | (lo >> 4)) ^ 0x88; |
341 | if (i >= 2) { | 356 | if (i >= 2) { |
@@ -361,10 +376,11 @@ get_fragment: | |||
361 | 376 | ||
362 | #define BUFSZ 150 | 377 | #define BUFSZ 150 |
363 | 378 | ||
364 | static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long len) | 379 | static long qc_capture(struct qcam *qcam, char __user *buf, unsigned long len) |
365 | { | 380 | { |
381 | struct v4l2_device *v4l2_dev = &qcam->v4l2_dev; | ||
366 | unsigned lines, pixelsperline, bitsperxfer; | 382 | unsigned lines, pixelsperline, bitsperxfer; |
367 | unsigned int is_bi_dir = q->bidirectional; | 383 | unsigned int is_bi_dir = qcam->bidirectional; |
368 | size_t wantlen, outptr = 0; | 384 | size_t wantlen, outptr = 0; |
369 | char tmpbuf[BUFSZ]; | 385 | char tmpbuf[BUFSZ]; |
370 | 386 | ||
@@ -373,10 +389,10 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le | |||
373 | 389 | ||
374 | /* Wait for camera to become ready */ | 390 | /* Wait for camera to become ready */ |
375 | for (;;) { | 391 | for (;;) { |
376 | int i = qcam_get(q, 41); | 392 | int i = qcam_get(qcam, 41); |
377 | 393 | ||
378 | if (i == -1) { | 394 | if (i == -1) { |
379 | qc_setup(q); | 395 | qc_setup(qcam); |
380 | return -EIO; | 396 | return -EIO; |
381 | } | 397 | } |
382 | if ((i & 0x80) == 0) | 398 | if ((i & 0x80) == 0) |
@@ -384,25 +400,25 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le | |||
384 | schedule(); | 400 | schedule(); |
385 | } | 401 | } |
386 | 402 | ||
387 | if (qcam_set(q, 7, (q->mode | (is_bi_dir ? 1 : 0)) + 1)) | 403 | if (qcam_set(qcam, 7, (qcam->mode | (is_bi_dir ? 1 : 0)) + 1)) |
388 | return -EIO; | 404 | return -EIO; |
389 | 405 | ||
390 | lines = q->height; | 406 | lines = qcam->height; |
391 | pixelsperline = q->width; | 407 | pixelsperline = qcam->width; |
392 | bitsperxfer = (is_bi_dir) ? 24 : 8; | 408 | bitsperxfer = (is_bi_dir) ? 24 : 8; |
393 | 409 | ||
394 | if (is_bi_dir) { | 410 | if (is_bi_dir) { |
395 | /* Turn the port around */ | 411 | /* Turn the port around */ |
396 | parport_data_reverse(q->pport); | 412 | parport_data_reverse(qcam->pport); |
397 | mdelay(3); | 413 | mdelay(3); |
398 | qcam_set_ack(q, 0); | 414 | qcam_set_ack(qcam, 0); |
399 | if (qcam_await_ready1(q, 1)) { | 415 | if (qcam_await_ready1(qcam, 1)) { |
400 | qc_setup(q); | 416 | qc_setup(qcam); |
401 | return -EIO; | 417 | return -EIO; |
402 | } | 418 | } |
403 | qcam_set_ack(q, 1); | 419 | qcam_set_ack(qcam, 1); |
404 | if (qcam_await_ready1(q, 0)) { | 420 | if (qcam_await_ready1(qcam, 0)) { |
405 | qc_setup(q); | 421 | qc_setup(qcam); |
406 | return -EIO; | 422 | return -EIO; |
407 | } | 423 | } |
408 | } | 424 | } |
@@ -413,7 +429,7 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le | |||
413 | size_t t, s; | 429 | size_t t, s; |
414 | 430 | ||
415 | s = (wantlen > BUFSZ) ? BUFSZ : wantlen; | 431 | s = (wantlen > BUFSZ) ? BUFSZ : wantlen; |
416 | t = qcam_read_bytes(q, tmpbuf, s); | 432 | t = qcam_read_bytes(qcam, tmpbuf, s); |
417 | if (outptr < len) { | 433 | if (outptr < len) { |
418 | size_t sz = len - outptr; | 434 | size_t sz = len - outptr; |
419 | 435 | ||
@@ -432,10 +448,10 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le | |||
432 | len = outptr; | 448 | len = outptr; |
433 | 449 | ||
434 | if (wantlen) { | 450 | if (wantlen) { |
435 | printk(KERN_ERR "qcam: short read.\n"); | 451 | v4l2_err(v4l2_dev, "short read.\n"); |
436 | if (is_bi_dir) | 452 | if (is_bi_dir) |
437 | parport_data_forward(q->pport); | 453 | parport_data_forward(qcam->pport); |
438 | qc_setup(q); | 454 | qc_setup(qcam); |
439 | return len; | 455 | return len; |
440 | } | 456 | } |
441 | 457 | ||
@@ -443,49 +459,49 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le | |||
443 | int l; | 459 | int l; |
444 | 460 | ||
445 | do { | 461 | do { |
446 | l = qcam_read_bytes(q, tmpbuf, 3); | 462 | l = qcam_read_bytes(qcam, tmpbuf, 3); |
447 | cond_resched(); | 463 | cond_resched(); |
448 | } while (l && (tmpbuf[0] == 0x7e || tmpbuf[1] == 0x7e || tmpbuf[2] == 0x7e)); | 464 | } while (l && (tmpbuf[0] == 0x7e || tmpbuf[1] == 0x7e || tmpbuf[2] == 0x7e)); |
449 | if (force_rgb) { | 465 | if (force_rgb) { |
450 | if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf) | 466 | if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf) |
451 | printk(KERN_ERR "qcam: bad EOF\n"); | 467 | v4l2_err(v4l2_dev, "bad EOF\n"); |
452 | } else { | 468 | } else { |
453 | if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe) | 469 | if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe) |
454 | printk(KERN_ERR "qcam: bad EOF\n"); | 470 | v4l2_err(v4l2_dev, "bad EOF\n"); |
455 | } | 471 | } |
456 | qcam_set_ack(q, 0); | 472 | qcam_set_ack(qcam, 0); |
457 | if (qcam_await_ready1(q, 1)) { | 473 | if (qcam_await_ready1(qcam, 1)) { |
458 | printk(KERN_ERR "qcam: no ack after EOF\n"); | 474 | v4l2_err(v4l2_dev, "no ack after EOF\n"); |
459 | parport_data_forward(q->pport); | 475 | parport_data_forward(qcam->pport); |
460 | qc_setup(q); | 476 | qc_setup(qcam); |
461 | return len; | 477 | return len; |
462 | } | 478 | } |
463 | parport_data_forward(q->pport); | 479 | parport_data_forward(qcam->pport); |
464 | mdelay(3); | 480 | mdelay(3); |
465 | qcam_set_ack(q, 1); | 481 | qcam_set_ack(qcam, 1); |
466 | if (qcam_await_ready1(q, 0)) { | 482 | if (qcam_await_ready1(qcam, 0)) { |
467 | printk(KERN_ERR "qcam: no ack to port turnaround\n"); | 483 | v4l2_err(v4l2_dev, "no ack to port turnaround\n"); |
468 | qc_setup(q); | 484 | qc_setup(qcam); |
469 | return len; | 485 | return len; |
470 | } | 486 | } |
471 | } else { | 487 | } else { |
472 | int l; | 488 | int l; |
473 | 489 | ||
474 | do { | 490 | do { |
475 | l = qcam_read_bytes(q, tmpbuf, 1); | 491 | l = qcam_read_bytes(qcam, tmpbuf, 1); |
476 | cond_resched(); | 492 | cond_resched(); |
477 | } while (l && tmpbuf[0] == 0x7e); | 493 | } while (l && tmpbuf[0] == 0x7e); |
478 | l = qcam_read_bytes(q, tmpbuf + 1, 2); | 494 | l = qcam_read_bytes(qcam, tmpbuf + 1, 2); |
479 | if (force_rgb) { | 495 | if (force_rgb) { |
480 | if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf) | 496 | if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf) |
481 | printk(KERN_ERR "qcam: bad EOF\n"); | 497 | v4l2_err(v4l2_dev, "bad EOF\n"); |
482 | } else { | 498 | } else { |
483 | if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe) | 499 | if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe) |
484 | printk(KERN_ERR "qcam: bad EOF\n"); | 500 | v4l2_err(v4l2_dev, "bad EOF\n"); |
485 | } | 501 | } |
486 | } | 502 | } |
487 | 503 | ||
488 | qcam_write_data(q, 0); | 504 | qcam_write_data(qcam, 0); |
489 | return len; | 505 | return len; |
490 | } | 506 | } |
491 | 507 | ||
@@ -493,184 +509,202 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le | |||
493 | * Video4linux interfacing | 509 | * Video4linux interfacing |
494 | */ | 510 | */ |
495 | 511 | ||
496 | static long qcam_do_ioctl(struct file *file, unsigned int cmd, void *arg) | 512 | static int qcam_querycap(struct file *file, void *priv, |
513 | struct v4l2_capability *vcap) | ||
497 | { | 514 | { |
498 | struct video_device *dev = video_devdata(file); | 515 | struct qcam *qcam = video_drvdata(file); |
499 | struct qcam_device *qcam = (struct qcam_device *)dev; | ||
500 | 516 | ||
501 | switch (cmd) { | 517 | strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver)); |
502 | case VIDIOCGCAP: | 518 | strlcpy(vcap->card, "Color Quickcam", sizeof(vcap->card)); |
503 | { | 519 | strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info)); |
504 | struct video_capability *b = arg; | 520 | vcap->version = KERNEL_VERSION(0, 0, 3); |
521 | vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE; | ||
522 | return 0; | ||
523 | } | ||
505 | 524 | ||
506 | strcpy(b->name, "Quickcam"); | 525 | static int qcam_enum_input(struct file *file, void *fh, struct v4l2_input *vin) |
507 | b->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; | 526 | { |
508 | b->channels = 1; | 527 | if (vin->index > 0) |
509 | b->audios = 0; | 528 | return -EINVAL; |
510 | b->maxwidth = 320; | 529 | strlcpy(vin->name, "Camera", sizeof(vin->name)); |
511 | b->maxheight = 240; | 530 | vin->type = V4L2_INPUT_TYPE_CAMERA; |
512 | b->minwidth = 80; | 531 | vin->audioset = 0; |
513 | b->minheight = 60; | 532 | vin->tuner = 0; |
514 | return 0; | 533 | vin->std = 0; |
515 | } | 534 | vin->status = 0; |
516 | case VIDIOCGCHAN: | 535 | return 0; |
517 | { | 536 | } |
518 | struct video_channel *v = arg; | ||
519 | |||
520 | if (v->channel != 0) | ||
521 | return -EINVAL; | ||
522 | v->flags = 0; | ||
523 | v->tuners = 0; | ||
524 | /* Good question.. its composite or SVHS so.. */ | ||
525 | v->type = VIDEO_TYPE_CAMERA; | ||
526 | strcpy(v->name, "Camera"); | ||
527 | return 0; | ||
528 | } | ||
529 | case VIDIOCSCHAN: | ||
530 | { | ||
531 | struct video_channel *v = arg; | ||
532 | 537 | ||
533 | if (v->channel != 0) | 538 | static int qcam_g_input(struct file *file, void *fh, unsigned int *inp) |
534 | return -EINVAL; | 539 | { |
535 | return 0; | 540 | *inp = 0; |
536 | } | 541 | return 0; |
537 | case VIDIOCGTUNER: | 542 | } |
538 | { | 543 | |
539 | struct video_tuner *v = arg; | 544 | static int qcam_s_input(struct file *file, void *fh, unsigned int inp) |
540 | 545 | { | |
541 | if (v->tuner) | 546 | return (inp > 0) ? -EINVAL : 0; |
542 | return -EINVAL; | 547 | } |
543 | memset(v, 0, sizeof(*v)); | 548 | |
544 | strcpy(v->name, "Format"); | 549 | static int qcam_queryctrl(struct file *file, void *priv, |
545 | v->mode = VIDEO_MODE_AUTO; | 550 | struct v4l2_queryctrl *qc) |
546 | return 0; | 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); | ||
547 | } | 559 | } |
548 | case VIDIOCSTUNER: | 560 | return -EINVAL; |
549 | { | 561 | } |
550 | struct video_tuner *v = arg; | 562 | |
551 | 563 | static int qcam_g_ctrl(struct file *file, void *priv, | |
552 | if (v->tuner) | 564 | struct v4l2_control *ctrl) |
553 | return -EINVAL; | 565 | { |
554 | if (v->mode != VIDEO_MODE_AUTO) | 566 | struct qcam *qcam = video_drvdata(file); |
555 | return -EINVAL; | 567 | int ret = 0; |
556 | return 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; | ||
557 | } | 582 | } |
558 | case VIDIOCGPICT: | 583 | return ret; |
559 | { | 584 | } |
560 | struct video_picture *p = arg; | 585 | |
561 | 586 | static int qcam_s_ctrl(struct file *file, void *priv, | |
562 | p->colour = 0x8000; | 587 | struct v4l2_control *ctrl) |
563 | p->hue = 0x8000; | 588 | { |
564 | p->brightness = qcam->brightness << 8; | 589 | struct qcam *qcam = video_drvdata(file); |
565 | p->contrast = qcam->contrast << 8; | 590 | int ret = 0; |
566 | p->whiteness = qcam->whitebal << 8; | 591 | |
567 | p->depth = 24; | 592 | mutex_lock(&qcam->lock); |
568 | p->palette = VIDEO_PALETTE_RGB24; | 593 | switch (ctrl->id) { |
569 | return 0; | 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; | ||
570 | } | 606 | } |
571 | case VIDIOCSPICT: | 607 | if (ret == 0) { |
572 | { | ||
573 | struct video_picture *p = arg; | ||
574 | |||
575 | /* | ||
576 | * Sanity check args | ||
577 | */ | ||
578 | if (p->depth != 24 || p->palette != VIDEO_PALETTE_RGB24) | ||
579 | return -EINVAL; | ||
580 | |||
581 | /* | ||
582 | * Now load the camera. | ||
583 | */ | ||
584 | qcam->brightness = p->brightness >> 8; | ||
585 | qcam->contrast = p->contrast >> 8; | ||
586 | qcam->whitebal = p->whiteness >> 8; | ||
587 | |||
588 | mutex_lock(&qcam->lock); | ||
589 | parport_claim_or_block(qcam->pdev); | 608 | parport_claim_or_block(qcam->pdev); |
590 | qc_setup(qcam); | 609 | qc_setup(qcam); |
591 | parport_release(qcam->pdev); | 610 | parport_release(qcam->pdev); |
592 | mutex_unlock(&qcam->lock); | ||
593 | return 0; | ||
594 | } | 611 | } |
595 | case VIDIOCSWIN: | 612 | mutex_unlock(&qcam->lock); |
596 | { | 613 | return ret; |
597 | struct video_window *vw = arg; | 614 | } |
598 | |||
599 | if (vw->flags) | ||
600 | return -EINVAL; | ||
601 | if (vw->clipcount) | ||
602 | return -EINVAL; | ||
603 | if (vw->height < 60 || vw->height > 240) | ||
604 | return -EINVAL; | ||
605 | if (vw->width < 80 || vw->width > 320) | ||
606 | return -EINVAL; | ||
607 | |||
608 | qcam->width = 80; | ||
609 | qcam->height = 60; | ||
610 | qcam->mode = QC_DECIMATION_4; | ||
611 | 615 | ||
612 | if (vw->width >= 160 && vw->height >= 120) { | 616 | static int qcam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) |
613 | qcam->width = 160; | 617 | { |
614 | qcam->height = 120; | 618 | struct qcam *qcam = video_drvdata(file); |
615 | qcam->mode = QC_DECIMATION_2; | 619 | struct v4l2_pix_format *pix = &fmt->fmt.pix; |
616 | } | 620 | |
617 | if (vw->width >= 320 && vw->height >= 240) { | 621 | pix->width = qcam->width; |
618 | qcam->width = 320; | 622 | pix->height = qcam->height; |
619 | qcam->height = 240; | 623 | pix->pixelformat = V4L2_PIX_FMT_RGB24; |
620 | qcam->mode = QC_DECIMATION_1; | 624 | pix->field = V4L2_FIELD_NONE; |
621 | } | 625 | pix->bytesperline = 3 * qcam->width; |
622 | qcam->mode |= QC_MILLIONS; | 626 | pix->sizeimage = 3 * qcam->width * qcam->height; |
623 | #if 0 | 627 | /* Just a guess */ |
624 | if (vw->width >= 640 && vw->height >= 480) { | 628 | pix->colorspace = V4L2_COLORSPACE_SRGB; |
625 | qcam->width = 640; | 629 | return 0; |
626 | qcam->height = 480; | 630 | } |
627 | qcam->mode = QC_BILLIONS | QC_DECIMATION_1; | 631 | |
628 | } | 632 | static int qcam_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) |
629 | #endif | 633 | { |
630 | /* Ok we figured out what to use from our | 634 | struct v4l2_pix_format *pix = &fmt->fmt.pix; |
631 | wide choice */ | 635 | |
632 | mutex_lock(&qcam->lock); | 636 | if (pix->height < 60 || pix->width < 80) { |
633 | parport_claim_or_block(qcam->pdev); | 637 | pix->height = 60; |
634 | qc_setup(qcam); | 638 | pix->width = 80; |
635 | parport_release(qcam->pdev); | 639 | } else if (pix->height < 120 || pix->width < 160) { |
636 | mutex_unlock(&qcam->lock); | 640 | pix->height = 120; |
637 | return 0; | 641 | pix->width = 160; |
638 | } | 642 | } else { |
639 | case VIDIOCGWIN: | 643 | pix->height = 240; |
640 | { | 644 | pix->width = 320; |
641 | struct video_window *vw = arg; | ||
642 | memset(vw, 0, sizeof(*vw)); | ||
643 | vw->width = qcam->width; | ||
644 | vw->height = qcam->height; | ||
645 | return 0; | ||
646 | } | 645 | } |
647 | case VIDIOCKEY: | 646 | pix->pixelformat = V4L2_PIX_FMT_RGB24; |
648 | return 0; | 647 | pix->field = V4L2_FIELD_NONE; |
649 | case VIDIOCCAPTURE: | 648 | pix->bytesperline = 3 * pix->width; |
650 | case VIDIOCGFBUF: | 649 | pix->sizeimage = 3 * pix->width * pix->height; |
651 | case VIDIOCSFBUF: | 650 | /* Just a guess */ |
652 | case VIDIOCGFREQ: | 651 | pix->colorspace = V4L2_COLORSPACE_SRGB; |
653 | case VIDIOCSFREQ: | 652 | return 0; |
654 | case VIDIOCGAUDIO: | 653 | } |
655 | case VIDIOCSAUDIO: | 654 | |
656 | return -EINVAL; | 655 | static 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; | ||
657 | default: | 670 | default: |
658 | return -ENOIOCTLCMD; | 671 | qcam->mode = QC_DECIMATION_1; |
672 | break; | ||
659 | } | 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); | ||
660 | return 0; | 683 | return 0; |
661 | } | 684 | } |
662 | 685 | ||
663 | static long qcam_ioctl(struct file *file, | 686 | static int qcam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) |
664 | unsigned int cmd, unsigned long arg) | ||
665 | { | 687 | { |
666 | return video_usercopy(file, cmd, arg, qcam_do_ioctl); | 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; | ||
667 | } | 702 | } |
668 | 703 | ||
669 | static ssize_t qcam_read(struct file *file, char __user *buf, | 704 | static ssize_t qcam_read(struct file *file, char __user *buf, |
670 | size_t count, loff_t *ppos) | 705 | size_t count, loff_t *ppos) |
671 | { | 706 | { |
672 | struct video_device *v = video_devdata(file); | 707 | struct qcam *qcam = video_drvdata(file); |
673 | struct qcam_device *qcam = (struct qcam_device *)v; | ||
674 | int len; | 708 | int len; |
675 | 709 | ||
676 | mutex_lock(&qcam->lock); | 710 | mutex_lock(&qcam->lock); |
@@ -682,81 +716,80 @@ static ssize_t qcam_read(struct file *file, char __user *buf, | |||
682 | return len; | 716 | return len; |
683 | } | 717 | } |
684 | 718 | ||
685 | static int qcam_exclusive_open(struct file *file) | ||
686 | { | ||
687 | struct video_device *dev = video_devdata(file); | ||
688 | struct qcam_device *qcam = (struct qcam_device *)dev; | ||
689 | |||
690 | return test_and_set_bit(0, &qcam->in_use) ? -EBUSY : 0; | ||
691 | } | ||
692 | |||
693 | static int qcam_exclusive_release(struct file *file) | ||
694 | { | ||
695 | struct video_device *dev = video_devdata(file); | ||
696 | struct qcam_device *qcam = (struct qcam_device *)dev; | ||
697 | |||
698 | clear_bit(0, &qcam->in_use); | ||
699 | return 0; | ||
700 | } | ||
701 | |||
702 | /* video device template */ | ||
703 | static const struct v4l2_file_operations qcam_fops = { | 719 | static const struct v4l2_file_operations qcam_fops = { |
704 | .owner = THIS_MODULE, | 720 | .owner = THIS_MODULE, |
705 | .open = qcam_exclusive_open, | 721 | .ioctl = video_ioctl2, |
706 | .release = qcam_exclusive_release, | ||
707 | .ioctl = qcam_ioctl, | ||
708 | .read = qcam_read, | 722 | .read = qcam_read, |
709 | }; | 723 | }; |
710 | 724 | ||
711 | static struct video_device qcam_template = { | 725 | static const struct v4l2_ioctl_ops qcam_ioctl_ops = { |
712 | .name = "Colour QuickCam", | 726 | .vidioc_querycap = qcam_querycap, |
713 | .fops = &qcam_fops, | 727 | .vidioc_g_input = qcam_g_input, |
714 | .release = video_device_release_empty, | 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, | ||
715 | }; | 737 | }; |
716 | 738 | ||
717 | /* Initialize the QuickCam driver control structure. */ | 739 | /* Initialize the QuickCam driver control structure. */ |
718 | 740 | ||
719 | static struct qcam_device *qcam_init(struct parport *port) | 741 | static struct qcam *qcam_init(struct parport *port) |
720 | { | 742 | { |
721 | struct qcam_device *q; | 743 | struct qcam *qcam; |
744 | struct v4l2_device *v4l2_dev; | ||
722 | 745 | ||
723 | q = kmalloc(sizeof(struct qcam_device), GFP_KERNEL); | 746 | qcam = kzalloc(sizeof(*qcam), GFP_KERNEL); |
724 | if (q == NULL) | 747 | if (qcam == NULL) |
725 | return NULL; | 748 | return NULL; |
726 | 749 | ||
727 | q->pport = port; | 750 | v4l2_dev = &qcam->v4l2_dev; |
728 | q->pdev = parport_register_device(port, "c-qcam", NULL, NULL, | 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, | ||
729 | NULL, 0, NULL); | 760 | NULL, 0, NULL); |
730 | 761 | ||
731 | q->bidirectional = (q->pport->modes & PARPORT_MODE_TRISTATE) ? 1 : 0; | 762 | qcam->bidirectional = (qcam->pport->modes & PARPORT_MODE_TRISTATE) ? 1 : 0; |
732 | 763 | ||
733 | if (q->pdev == NULL) { | 764 | if (qcam->pdev == NULL) { |
734 | printk(KERN_ERR "c-qcam: couldn't register for %s.\n", | 765 | v4l2_err(v4l2_dev, "couldn't register for %s.\n", port->name); |
735 | port->name); | 766 | kfree(qcam); |
736 | kfree(q); | ||
737 | return NULL; | 767 | return NULL; |
738 | } | 768 | } |
739 | 769 | ||
740 | memcpy(&q->vdev, &qcam_template, sizeof(qcam_template)); | 770 | strlcpy(qcam->vdev.name, "Colour QuickCam", sizeof(qcam->vdev.name)); |
741 | 771 | qcam->vdev.v4l2_dev = v4l2_dev; | |
742 | mutex_init(&q->lock); | 772 | qcam->vdev.fops = &qcam_fops; |
743 | q->width = q->ccd_width = 320; | 773 | qcam->vdev.ioctl_ops = &qcam_ioctl_ops; |
744 | q->height = q->ccd_height = 240; | 774 | qcam->vdev.release = video_device_release_empty; |
745 | q->mode = QC_MILLIONS | QC_DECIMATION_1; | 775 | video_set_drvdata(&qcam->vdev, qcam); |
746 | q->contrast = 192; | 776 | |
747 | q->brightness = 240; | 777 | mutex_init(&qcam->lock); |
748 | q->whitebal = 128; | 778 | qcam->width = qcam->ccd_width = 320; |
749 | q->top = 1; | 779 | qcam->height = qcam->ccd_height = 240; |
750 | q->left = 14; | 780 | qcam->mode = QC_MILLIONS | QC_DECIMATION_1; |
751 | return q; | 781 | qcam->contrast = 192; |
782 | qcam->brightness = 240; | ||
783 | qcam->whitebal = 128; | ||
784 | qcam->top = 1; | ||
785 | qcam->left = 14; | ||
786 | return qcam; | ||
752 | } | 787 | } |
753 | 788 | ||
754 | static struct qcam_device *qcams[MAX_CAMS]; | ||
755 | static unsigned int num_cams; | ||
756 | |||
757 | static int init_cqcam(struct parport *port) | 789 | static int init_cqcam(struct parport *port) |
758 | { | 790 | { |
759 | struct qcam_device *qcam; | 791 | struct qcam *qcam; |
792 | struct v4l2_device *v4l2_dev; | ||
760 | 793 | ||
761 | if (parport[0] != -1) { | 794 | if (parport[0] != -1) { |
762 | /* The user gave specific instructions */ | 795 | /* The user gave specific instructions */ |
@@ -777,6 +810,8 @@ static int init_cqcam(struct parport *port) | |||
777 | if (qcam == NULL) | 810 | if (qcam == NULL) |
778 | return -ENODEV; | 811 | return -ENODEV; |
779 | 812 | ||
813 | v4l2_dev = &qcam->v4l2_dev; | ||
814 | |||
780 | parport_claim_or_block(qcam->pdev); | 815 | parport_claim_or_block(qcam->pdev); |
781 | 816 | ||
782 | qc_reset(qcam); | 817 | qc_reset(qcam); |
@@ -793,14 +828,14 @@ static int init_cqcam(struct parport *port) | |||
793 | parport_release(qcam->pdev); | 828 | parport_release(qcam->pdev); |
794 | 829 | ||
795 | if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { | 830 | if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { |
796 | printk(KERN_ERR "Unable to register Colour QuickCam on %s\n", | 831 | v4l2_err(v4l2_dev, "Unable to register Colour QuickCam on %s\n", |
797 | qcam->pport->name); | 832 | qcam->pport->name); |
798 | parport_unregister_device(qcam->pdev); | 833 | parport_unregister_device(qcam->pdev); |
799 | kfree(qcam); | 834 | kfree(qcam); |
800 | return -ENODEV; | 835 | return -ENODEV; |
801 | } | 836 | } |
802 | 837 | ||
803 | printk(KERN_INFO "%s: Colour QuickCam found on %s\n", | 838 | v4l2_info(v4l2_dev, "%s: Colour QuickCam found on %s\n", |
804 | video_device_node_name(&qcam->vdev), qcam->pport->name); | 839 | video_device_node_name(&qcam->vdev), qcam->pport->name); |
805 | 840 | ||
806 | qcams[num_cams++] = qcam; | 841 | qcams[num_cams++] = qcam; |
@@ -808,7 +843,7 @@ static int init_cqcam(struct parport *port) | |||
808 | return 0; | 843 | return 0; |
809 | } | 844 | } |
810 | 845 | ||
811 | static void close_cqcam(struct qcam_device *qcam) | 846 | static void close_cqcam(struct qcam *qcam) |
812 | { | 847 | { |
813 | video_unregister_device(&qcam->vdev); | 848 | video_unregister_device(&qcam->vdev); |
814 | parport_unregister_device(qcam->pdev); | 849 | parport_unregister_device(qcam->pdev); |
@@ -833,7 +868,7 @@ static struct parport_driver cqcam_driver = { | |||
833 | 868 | ||
834 | static int __init cqcam_init(void) | 869 | static int __init cqcam_init(void) |
835 | { | 870 | { |
836 | printk(BANNER "\n"); | 871 | printk(KERN_INFO BANNER "\n"); |
837 | 872 | ||
838 | return parport_register_driver(&cqcam_driver); | 873 | return parport_register_driver(&cqcam_driver); |
839 | } | 874 | } |
@@ -852,14 +887,5 @@ MODULE_AUTHOR("Philip Blundell <philb@gnu.org>"); | |||
852 | MODULE_DESCRIPTION(BANNER); | 887 | MODULE_DESCRIPTION(BANNER); |
853 | MODULE_LICENSE("GPL"); | 888 | MODULE_LICENSE("GPL"); |
854 | 889 | ||
855 | /* FIXME: parport=auto would never have worked, surely? --RR */ | ||
856 | MODULE_PARM_DESC(parport, "parport=<auto|n[,n]...> for port detection method\n" | ||
857 | "probe=<0|1|2> for camera detection method\n" | ||
858 | "force_rgb=<0|1> for RGB data format (default BGR)"); | ||
859 | module_param_array(parport, int, NULL, 0); | ||
860 | module_param(probe, int, 0); | ||
861 | module_param(force_rgb, bool, 0); | ||
862 | module_param(video_nr, int, 0); | ||
863 | |||
864 | module_init(cqcam_init); | 890 | module_init(cqcam_init); |
865 | module_exit(cqcam_cleanup); | 891 | module_exit(cqcam_cleanup); |