1/* 2 Winbond w9966cf Webcam parport driver. 3 4 Version 0.33 5 6 Copyright (C) 2001 Jakob Kemi <jakob.kemi@post.utfors.se> 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 2 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software 20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21*/ 22/* 23 Supported devices: 24 *Lifeview FlyCam Supra (using the Philips saa7111a chip) 25 26 Does any other model using the w9966 interface chip exist ? 27 28 Todo: 29 30 *Add a working EPP mode, since DMA ECP read isn't implemented 31 in the parport drivers. (That's why it's so sloow) 32 33 *Add support for other ccd-control chips than the saa7111 34 please send me feedback on what kind of chips you have. 35 36 *Add proper probing. I don't know what's wrong with the IEEE1284 37 parport drivers but (IEEE1284_MODE_NIBBLE|IEEE1284_DEVICE_ID) 38 and nibble read seems to be broken for some peripherals. 39 40 *Add probing for onboard SRAM, port directions etc. (if possible) 41 42 *Add support for the hardware compressed modes (maybe using v4l2) 43 44 *Fix better support for the capture window (no skewed images, v4l 45 interface to capt. window) 46 47 *Probably some bugs that I don't know of 48 49 Please support me by sending feedback! 50 51 Changes: 52 53 Alan Cox: Removed RGB mode for kernel merge, added THIS_MODULE 54 and owner support for newer module locks 55*/ 56 57#include <linux/module.h> 58#include <linux/init.h> 59#include <linux/delay.h> 60#include <linux/version.h> 61#include <linux/videodev2.h> 62#include <linux/slab.h> 63#include <media/v4l2-common.h> 64#include <media/v4l2-ioctl.h> 65#include <media/v4l2-device.h> 66#include <linux/parport.h> 67 68/*#define DEBUG*/ /* Undef me for production */ 69 70#ifdef DEBUG 71#define DPRINTF(x, a...) printk(KERN_DEBUG "W9966: %s(): "x, __func__ , ##a) 72#else 73#define DPRINTF(x...) 74#endif 75 76/* 77 * Defines, simple typedefs etc. 78 */ 79 80#define W9966_DRIVERNAME "W9966CF Webcam" 81#define W9966_MAXCAMS 4 /* Maximum number of cameras */ 82#define W9966_RBUFFER 2048 /* Read buffer (must be an even number) */ 83#define W9966_SRAMSIZE 131072 /* 128kb */ 84#define W9966_SRAMID 0x02 /* check w9966cf.pdf */ 85 86/* Empirically determined window limits */ 87#define W9966_WND_MIN_X 16 88#define W9966_WND_MIN_Y 14 89#define W9966_WND_MAX_X 705 90#define W9966_WND_MAX_Y 253 91#define W9966_WND_MAX_W (W9966_WND_MAX_X - W9966_WND_MIN_X) 92#define W9966_WND_MAX_H (W9966_WND_MAX_Y - W9966_WND_MIN_Y) 93 94/* Keep track of our current state */ 95#define W9966_STATE_PDEV 0x01 96#define W9966_STATE_CLAIMED 0x02 97#define W9966_STATE_VDEV 0x04 98 99#define W9966_I2C_W_ID 0x48 100#define W9966_I2C_R_ID 0x49 101#define W9966_I2C_R_DATA 0x08 102#define W9966_I2C_R_CLOCK 0x04 103#define W9966_I2C_W_DATA 0x02 104#define W9966_I2C_W_CLOCK 0x01 105 106struct w9966 { 107 struct v4l2_device v4l2_dev; 108 unsigned char dev_state; 109 unsigned char i2c_state; 110 unsigned short ppmode; 111 struct parport *pport; 112 struct pardevice *pdev; 113 struct video_device vdev; 114 unsigned short width; 115 unsigned short height; 116 unsigned char brightness; 117 signed char contrast; 118 signed char color; 119 signed char hue; 120 struct mutex lock; 121}; 122 123/* 124 * Module specific properties 125 */ 126 127MODULE_AUTHOR("Jakob Kemi <jakob.kemi@post.utfors.se>"); 128MODULE_DESCRIPTION("Winbond w9966cf WebCam driver (0.32)"); 129MODULE_LICENSE("GPL"); 130 131 132#ifdef MODULE 133static const char *pardev[] = {[0 ... W9966_MAXCAMS] = ""}; 134#else 135static const char *pardev[] = {[0 ... W9966_MAXCAMS] = "aggressive"}; 136#endif 137module_param_array(pardev, charp, NULL, 0); 138MODULE_PARM_DESC(pardev, "pardev: where to search for\n" 139 "\teach camera. 'aggressive' means brute-force search.\n" 140 "\tEg: >pardev=parport3,aggressive,parport2,parport1< would assign\n" 141 "\tcam 1 to parport3 and search every parport for cam 2 etc..."); 142 143static int parmode; 144module_param(parmode, int, 0); 145MODULE_PARM_DESC(parmode, "parmode: transfer mode (0=auto, 1=ecp, 2=epp"); 146 147static int video_nr = -1; 148module_param(video_nr, int, 0); 149 150static struct w9966 w9966_cams[W9966_MAXCAMS]; 151 152/* 153 * Private function defines 154 */ 155 156 157/* Set camera phase flags, so we know what to uninit when terminating */ 158static inline void w9966_set_state(struct w9966 *cam, int mask, int val) 159{ 160 cam->dev_state = (cam->dev_state & ~mask) ^ val; 161} 162 163/* Get camera phase flags */ 164static inline int w9966_get_state(struct w9966 *cam, int mask, int val) 165{ 166 return ((cam->dev_state & mask) == val); 167} 168 169/* Claim parport for ourself */ 170static void w9966_pdev_claim(struct w9966 *cam) 171{ 172 if (w9966_get_state(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED)) 173 return; 174 parport_claim_or_block(cam->pdev); 175 w9966_set_state(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED); 176} 177 178/* Release parport for others to use */ 179static void w9966_pdev_release(struct w9966 *cam) 180{ 181 if (w9966_get_state(cam, W9966_STATE_CLAIMED, 0)) 182 return; 183 parport_release(cam->pdev); 184 w9966_set_state(cam, W9966_STATE_CLAIMED, 0); 185} 186 187/* Read register from W9966 interface-chip 188 Expects a claimed pdev 189 -1 on error, else register data (byte) */ 190static int w9966_read_reg(struct w9966 *cam, int reg) 191{ 192 /* ECP, read, regtransfer, REG, REG, REG, REG, REG */ 193 const unsigned char addr = 0x80 | (reg & 0x1f); 194 unsigned char val; 195 196 if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0) 197 return -1; 198 if (parport_write(cam->pport, &addr, 1) != 1) 199 return -1; 200 if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0) 201 return -1; 202 if (parport_read(cam->pport, &val, 1) != 1) 203 return -1; 204 205 return val; 206} 207 208/* Write register to W9966 interface-chip 209 Expects a claimed pdev 210 -1 on error */ 211static int w9966_write_reg(struct w9966 *cam, int reg, int data) 212{ 213 /* ECP, write, regtransfer, REG, REG, REG, REG, REG */ 214 const unsigned char addr = 0xc0 | (reg & 0x1f); 215 const unsigned char val = data; 216 217 if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0) 218 return -1; 219 if (parport_write(cam->pport, &addr, 1) != 1) 220 return -1; 221 if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0) 222 return -1; 223 if (parport_write(cam->pport, &val, 1) != 1) 224 return -1; 225 226 return 0; 227} 228 229/* 230 * Ugly and primitive i2c protocol functions 231 */ 232 233/* Sets the data line on the i2c bus. 234 Expects a claimed pdev. */ 235static void w9966_i2c_setsda(struct w9966 *cam, int state) 236{ 237 if (state) 238 cam->i2c_state |= W9966_I2C_W_DATA; 239 else 240 cam->i2c_state &= ~W9966_I2C_W_DATA; 241 242 w9966_write_reg(cam, 0x18, cam->i2c_state); 243 udelay(5); 244} 245 246/* Get peripheral clock line 247 Expects a claimed pdev. */ 248static int w9966_i2c_getscl(struct w9966 *cam) 249{ 250 const unsigned char state = w9966_read_reg(cam, 0x18); 251 return ((state & W9966_I2C_R_CLOCK) > 0); 252} 253 254/* Sets the clock line on the i2c bus. 255 Expects a claimed pdev. -1 on error */ 256static int w9966_i2c_setscl(struct w9966 *cam, int state) 257{ 258 unsigned long timeout; 259 260 if (state) 261 cam->i2c_state |= W9966_I2C_W_CLOCK; 262 else 263 cam->i2c_state &= ~W9966_I2C_W_CLOCK; 264 265 w9966_write_reg(cam, 0x18, cam->i2c_state); 266 udelay(5); 267 268 /* we go to high, we also expect the peripheral to ack. */ 269 if (state) { 270 timeout = jiffies + 100; 271 while (!w9966_i2c_getscl(cam)) { 272 if (time_after(jiffies, timeout)) 273 return -1; 274 } 275 } 276 return 0; 277} 278 279 280/* Write a byte with ack to the i2c bus. 281 Expects a claimed pdev. -1 on error */ 282static int w9966_i2c_wbyte(struct w9966 *cam, int data) 283{ 284 int i; 285 286 for (i = 7; i >= 0; i--) { 287 w9966_i2c_setsda(cam, (data >> i) & 0x01); 288 289 if (w9966_i2c_setscl(cam, 1) == -1) 290 return -1; 291 w9966_i2c_setscl(cam, 0); 292 } 293 294 w9966_i2c_setsda(cam, 1); 295 296 if (w9966_i2c_setscl(cam, 1) == -1) 297 return -1; 298 w9966_i2c_setscl(cam, 0); 299 300 return 0; 301} 302 303/* Read a data byte with ack from the i2c-bus 304 Expects a claimed pdev. -1 on error */ 305 306/* Read a register from the i2c device. 307 Expects claimed pdev. -1 on error */ 308 309/* Write a register to the i2c device. 310 Expects claimed pdev. -1 on error */ 311static int w9966_write_reg_i2c(struct w9966 *cam, int reg, int data) 312{ 313 w9966_i2c_setsda(cam, 0); 314 w9966_i2c_setscl(cam, 0); 315 316 if (w9966_i2c_wbyte(cam, W9966_I2C_W_ID) == -1 || 317 w9966_i2c_wbyte(cam, reg) == -1 || 318 w9966_i2c_wbyte(cam, data) == -1) 319 return -1; 320 321 w9966_i2c_setsda(cam, 0); 322 if (w9966_i2c_setscl(cam, 1) == -1) 323 return -1; 324 325 w9966_i2c_setsda(cam, 1); 326 327 return 0; 328} 329 330/* Find a good length for capture window (used both for W and H) 331 A bit ugly but pretty functional. The capture length 332 have to match the downscale */ 333static int w9966_findlen(int near, int size, int maxlen) 334{ 335 int bestlen = size; 336 int besterr = abs(near - bestlen); 337 int len; 338 339 for (len = size + 1; len < maxlen; len++) { 340 int err; 341 if (((64 * size) % len) != 0) 342 continue; 343 344 err = abs(near - len); 345 346 /* Only continue as long as we keep getting better values */ 347 if (err > besterr) 348 break; 349 350 besterr = err; 351 bestlen = len; 352 } 353 354 return bestlen; 355} 356 357/* Modify capture window (if necessary) 358 and calculate downscaling 359 Return -1 on error */ 360static int w9966_calcscale(int size, int min, int max, int *beg, int *end, unsigned char *factor) 361{ 362 int maxlen = max - min; 363 int len = *end - *beg + 1; 364 int newlen = w9966_findlen(len, size, maxlen); 365 int err = newlen - len; 366 367 /* Check for bad format */ 368 if (newlen > maxlen || newlen < size) 369 return -1; 370 371 /* Set factor (6 bit fixed) */ 372 *factor = (64 * size) / newlen; 373 if (*factor == 64) 374 *factor = 0x00; /* downscale is disabled */ 375 else 376 *factor |= 0x80; /* set downscale-enable bit */ 377 378 /* Modify old beginning and end */ 379 *beg -= err / 2; 380 *end += err - (err / 2); 381 382 /* Move window if outside borders */ 383 if (*beg < min) { 384 *end += min - *beg; 385 *beg += min - *beg; 386 } 387 if (*end > max) { 388 *beg -= *end - max; 389 *end -= *end - max; 390 } 391 392 return 0; 393} 394 395/* Setup the cameras capture window etc. 396 Expects a claimed pdev 397 return -1 on error */ 398static int w9966_setup(struct w9966 *cam, int x1, int y1, int x2, int y2, int w, int h) 399{ 400 unsigned int i; 401 unsigned int enh_s, enh_e; 402 unsigned char scale_x, scale_y; 403 unsigned char regs[0x1c]; 404 unsigned char saa7111_regs[] = { 405 0x21, 0x00, 0xd8, 0x23, 0x00, 0x80, 0x80, 0x00, 406 0x88, 0x10, 0x80, 0x40, 0x40, 0x00, 0x01, 0x00, 407 0x48, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 408 0x00, 0x00, 0x00, 0x71, 0xe7, 0x00, 0x00, 0xc0 409 }; 410 411 412 if (w * h * 2 > W9966_SRAMSIZE) { 413 DPRINTF("capture window exceeds SRAM size!.\n"); 414 w = 200; h = 160; /* Pick default values */ 415 } 416 417 w &= ~0x1; 418 if (w < 2) 419 w = 2; 420 if (h < 1) 421 h = 1; 422 if (w > W9966_WND_MAX_W) 423 w = W9966_WND_MAX_W; 424 if (h > W9966_WND_MAX_H) 425 h = W9966_WND_MAX_H; 426 427 cam->width = w; 428 cam->height = h; 429 430 enh_s = 0; 431 enh_e = w * h * 2; 432 433 /* Modify capture window if necessary and calculate downscaling */ 434 if (w9966_calcscale(w, W9966_WND_MIN_X, W9966_WND_MAX_X, &x1, &x2, &scale_x) != 0 || 435 w9966_calcscale(h, W9966_WND_MIN_Y, W9966_WND_MAX_Y, &y1, &y2, &scale_y) != 0) 436 return -1; 437 438 DPRINTF("%dx%d, x: %d<->%d, y: %d<->%d, sx: %d/64, sy: %d/64.\n", 439 w, h, x1, x2, y1, y2, scale_x & ~0x80, scale_y & ~0x80); 440 441 /* Setup registers */ 442 regs[0x00] = 0x00; /* Set normal operation */ 443 regs[0x01] = 0x18; /* Capture mode */ 444 regs[0x02] = scale_y; /* V-scaling */ 445 regs[0x03] = scale_x; /* H-scaling */ 446 447 /* Capture window */ 448 regs[0x04] = (x1 & 0x0ff); /* X-start (8 low bits) */ 449 regs[0x05] = (x1 & 0x300)>>8; /* X-start (2 high bits) */ 450 regs[0x06] = (y1 & 0x0ff); /* Y-start (8 low bits) */ 451 regs[0x07] = (y1 & 0x300)>>8; /* Y-start (2 high bits) */ 452 regs[0x08] = (x2 & 0x0ff); /* X-end (8 low bits) */ 453 regs[0x09] = (x2 & 0x300)>>8; /* X-end (2 high bits) */ 454 regs[0x0a] = (y2 & 0x0ff); /* Y-end (8 low bits) */ 455 456 regs[0x0c] = W9966_SRAMID; /* SRAM-banks (1x 128kb) */ 457 458 /* Enhancement layer */ 459 regs[0x0d] = (enh_s & 0x000ff); /* Enh. start (0-7) */ 460 regs[0x0e] = (enh_s & 0x0ff00) >> 8; /* Enh. start (8-15) */ 461 regs[0x0f] = (enh_s & 0x70000) >> 16; /* Enh. start (16-17/18??) */ 462 regs[0x10] = (enh_e & 0x000ff); /* Enh. end (0-7) */ 463 regs[0x11] = (enh_e & 0x0ff00) >> 8; /* Enh. end (8-15) */ 464 regs[0x12] = (enh_e & 0x70000) >> 16; /* Enh. end (16-17/18??) */ 465 466 /* Misc */ 467 regs[0x13] = 0x40; /* VEE control (raw 4:2:2) */ 468 regs[0x17] = 0x00; /* ??? */ 469 regs[0x18] = cam->i2c_state = 0x00; /* Serial bus */ 470 regs[0x19] = 0xff; /* I/O port direction control */ 471 regs[0x1a] = 0xff; /* I/O port data register */ 472 regs[0x1b] = 0x10; /* ??? */ 473 474 /* SAA7111 chip settings */ 475 saa7111_regs[0x0a] = cam->brightness; 476 saa7111_regs[0x0b] = cam->contrast; 477 saa7111_regs[0x0c] = cam->color; 478 saa7111_regs[0x0d] = cam->hue; 479 480 /* Reset (ECP-fifo & serial-bus) */ 481 if (w9966_write_reg(cam, 0x00, 0x03) == -1) 482 return -1; 483 484 /* Write regs to w9966cf chip */ 485 for (i = 0; i < 0x1c; i++) 486 if (w9966_write_reg(cam, i, regs[i]) == -1) 487 return -1; 488 489 /* Write regs to saa7111 chip */ 490 for (i = 0; i < 0x20; i++) 491 if (w9966_write_reg_i2c(cam, i, saa7111_regs[i]) == -1) 492 return -1; 493 494 return 0; 495} 496 497/* 498 * Video4linux interfacing 499 */ 500 501static int cam_querycap(struct file *file, void *priv, 502 struct v4l2_capability *vcap) 503{ 504 struct w9966 *cam = video_drvdata(file); 505 506 strlcpy(vcap->driver, cam->v4l2_dev.name, sizeof(vcap->driver)); 507 strlcpy(vcap->card, W9966_DRIVERNAME, sizeof(vcap->card)); 508 strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info)); 509 vcap->version = KERNEL_VERSION(0, 33, 0); 510 vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE; 511 return 0; 512} 513 514static int cam_enum_input(struct file *file, void *fh, struct v4l2_input *vin) 515{ 516 if (vin->index > 0) 517 return -EINVAL; 518 strlcpy(vin->name, "Camera", sizeof(vin->name)); 519 vin->type = V4L2_INPUT_TYPE_CAMERA; 520 vin->audioset = 0; 521 vin->tuner = 0; 522 vin->std = 0; 523 vin->status = 0; 524 return 0; 525} 526 527static int cam_g_input(struct file *file, void *fh, unsigned int *inp) 528{ 529 *inp = 0; 530 return 0; 531} 532 533static int cam_s_input(struct file *file, void *fh, unsigned int inp) 534{ 535 return (inp > 0) ? -EINVAL : 0; 536} 537 538static int cam_queryctrl(struct file *file, void *priv, 539 struct v4l2_queryctrl *qc) 540{ 541 switch (qc->id) { 542 case V4L2_CID_BRIGHTNESS: 543 return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128); 544 case V4L2_CID_CONTRAST: 545 return v4l2_ctrl_query_fill(qc, -64, 64, 1, 64); 546 case V4L2_CID_SATURATION: 547 return v4l2_ctrl_query_fill(qc, -64, 64, 1, 64); 548 case V4L2_CID_HUE: 549 return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0); 550 } 551 return -EINVAL; 552} 553 554static int cam_g_ctrl(struct file *file, void *priv, 555 struct v4l2_control *ctrl) 556{ 557 struct w9966 *cam = video_drvdata(file); 558 int ret = 0; 559 560 switch (ctrl->id) { 561 case V4L2_CID_BRIGHTNESS: 562 ctrl->value = cam->brightness; 563 break; 564 case V4L2_CID_CONTRAST: 565 ctrl->value = cam->contrast; 566 break; 567 case V4L2_CID_SATURATION: 568 ctrl->value = cam->color; 569 break; 570 case V4L2_CID_HUE: 571 ctrl->value = cam->hue; 572 break; 573 default: 574 ret = -EINVAL; 575 break; 576 } 577 return ret; 578} 579 580static int cam_s_ctrl(struct file *file, void *priv, 581 struct v4l2_control *ctrl) 582{ 583 struct w9966 *cam = video_drvdata(file); 584 int ret = 0; 585 586 mutex_lock(&cam->lock); 587 switch (ctrl->id) { 588 case V4L2_CID_BRIGHTNESS: 589 cam->brightness = ctrl->value; 590 break; 591 case V4L2_CID_CONTRAST: 592 cam->contrast = ctrl->value; 593 break; 594 case V4L2_CID_SATURATION: 595 cam->color = ctrl->value; 596 break; 597 case V4L2_CID_HUE: 598 cam->hue = ctrl->value; 599 break; 600 default: 601 ret = -EINVAL; 602 break; 603 } 604 605 if (ret == 0) { 606 w9966_pdev_claim(cam); 607 608 if (w9966_write_reg_i2c(cam, 0x0a, cam->brightness) == -1 || 609 w9966_write_reg_i2c(cam, 0x0b, cam->contrast) == -1 || 610 w9966_write_reg_i2c(cam, 0x0c, cam->color) == -1 || 611 w9966_write_reg_i2c(cam, 0x0d, cam->hue) == -1) { 612 ret = -EIO; 613 } 614 615 w9966_pdev_release(cam); 616 } 617 mutex_unlock(&cam->lock); 618 return ret; 619} 620 621static int cam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) 622{ 623 struct w9966 *cam = video_drvdata(file); 624 struct v4l2_pix_format *pix = &fmt->fmt.pix; 625 626 pix->width = cam->width; 627 pix->height = cam->height; 628 pix->pixelformat = V4L2_PIX_FMT_YUYV; 629 pix->field = V4L2_FIELD_NONE; 630 pix->bytesperline = 2 * cam->width; 631 pix->sizeimage = 2 * cam->width * cam->height; 632 /* Just a guess */ 633 pix->colorspace = V4L2_COLORSPACE_SMPTE170M; 634 return 0; 635} 636 637static int cam_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) 638{ 639 struct v4l2_pix_format *pix = &fmt->fmt.pix; 640 641 if (pix->width < 2) 642 pix->width = 2; 643 if (pix->height < 1) 644 pix->height = 1; 645 if (pix->width > W9966_WND_MAX_W) 646 pix->width = W9966_WND_MAX_W; 647 if (pix->height > W9966_WND_MAX_H) 648 pix->height = W9966_WND_MAX_H; 649 pix->pixelformat = V4L2_PIX_FMT_YUYV; 650 pix->field = V4L2_FIELD_NONE; 651 pix->bytesperline = 2 * pix->width; 652 pix->sizeimage = 2 * pix->width * pix->height; 653 /* Just a guess */ 654 pix->colorspace = V4L2_COLORSPACE_SMPTE170M; 655 return 0; 656} 657 658static int cam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) 659{ 660 struct w9966 *cam = video_drvdata(file); 661 struct v4l2_pix_format *pix = &fmt->fmt.pix; 662 int ret = cam_try_fmt_vid_cap(file, fh, fmt); 663 664 if (ret) 665 return ret; 666 667 mutex_lock(&cam->lock); 668 /* Update camera regs */ 669 w9966_pdev_claim(cam); 670 ret = w9966_setup(cam, 0, 0, 1023, 1023, pix->width, pix->height); 671 w9966_pdev_release(cam); 672 mutex_unlock(&cam->lock); 673 return ret; 674} 675 676static int cam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) 677{ 678 static struct v4l2_fmtdesc formats[] = { 679 { 0, 0, 0, 680 "YUV 4:2:2", V4L2_PIX_FMT_YUYV, 681 { 0, 0, 0, 0 } 682 }, 683 }; 684 enum v4l2_buf_type type = fmt->type; 685 686 if (fmt->index > 0) 687 return -EINVAL; 688 689 *fmt = formats[fmt->index]; 690 fmt->type = type; 691 return 0; 692} 693 694/* Capture data */ 695static ssize_t w9966_v4l_read(struct file *file, char __user *buf, 696 size_t count, loff_t *ppos) 697{ 698 struct w9966 *cam = video_drvdata(file); 699 unsigned char addr = 0xa0; /* ECP, read, CCD-transfer, 00000 */ 700 unsigned char __user *dest = (unsigned char __user *)buf; 701 unsigned long dleft = count; 702 unsigned char *tbuf; 703 704 /* Why would anyone want more than this?? */ 705 if (count > cam->width * cam->height * 2) 706 return -EINVAL; 707 708 mutex_lock(&cam->lock); 709 w9966_pdev_claim(cam); 710 w9966_write_reg(cam, 0x00, 0x02); /* Reset ECP-FIFO buffer */ 711 w9966_write_reg(cam, 0x00, 0x00); /* Return to normal operation */ 712 w9966_write_reg(cam, 0x01, 0x98); /* Enable capture */ 713 714 /* write special capture-addr and negotiate into data transfer */ 715 if ((parport_negotiate(cam->pport, cam->ppmode|IEEE1284_ADDR) != 0) || 716 (parport_write(cam->pport, &addr, 1) != 1) || 717 (parport_negotiate(cam->pport, cam->ppmode|IEEE1284_DATA) != 0)) { 718 w9966_pdev_release(cam); 719 mutex_unlock(&cam->lock); 720 return -EFAULT; 721 } 722 723 tbuf = kmalloc(W9966_RBUFFER, GFP_KERNEL); 724 if (tbuf == NULL) { 725 count = -ENOMEM; 726 goto out; 727 } 728 729 while (dleft > 0) { 730 unsigned long tsize = (dleft > W9966_RBUFFER) ? W9966_RBUFFER : dleft; 731 732 if (parport_read(cam->pport, tbuf, tsize) < tsize) { 733 count = -EFAULT; 734 goto out; 735 } 736 if (copy_to_user(dest, tbuf, tsize) != 0) { 737 count = -EFAULT; 738 goto out; 739 } 740 dest += tsize; 741 dleft -= tsize; 742 } 743 744 w9966_write_reg(cam, 0x01, 0x18); /* Disable capture */ 745 746out: 747 kfree(tbuf); 748 w9966_pdev_release(cam); 749 mutex_unlock(&cam->lock); 750 751 return count; 752} 753 754static const struct v4l2_file_operations w9966_fops = { 755 .owner = THIS_MODULE, 756 .ioctl = video_ioctl2, 757 .read = w9966_v4l_read, 758}; 759 760static const struct v4l2_ioctl_ops w9966_ioctl_ops = { 761 .vidioc_querycap = cam_querycap, 762 .vidioc_g_input = cam_g_input, 763 .vidioc_s_input = cam_s_input, 764 .vidioc_enum_input = cam_enum_input, 765 .vidioc_queryctrl = cam_queryctrl, 766 .vidioc_g_ctrl = cam_g_ctrl, 767 .vidioc_s_ctrl = cam_s_ctrl, 768 .vidioc_enum_fmt_vid_cap = cam_enum_fmt_vid_cap, 769 .vidioc_g_fmt_vid_cap = cam_g_fmt_vid_cap, 770 .vidioc_s_fmt_vid_cap = cam_s_fmt_vid_cap, 771 .vidioc_try_fmt_vid_cap = cam_try_fmt_vid_cap, 772}; 773 774 775/* Initialize camera device. Setup all internal flags, set a 776 default video mode, setup ccd-chip, register v4l device etc.. 777 Also used for 'probing' of hardware. 778 -1 on error */ 779static int w9966_init(struct w9966 *cam, struct parport *port) 780{ 781 struct v4l2_device *v4l2_dev = &cam->v4l2_dev; 782 783 if (cam->dev_state != 0) 784 return -1; 785 786 strlcpy(v4l2_dev->name, "w9966", sizeof(v4l2_dev->name)); 787 788 if (v4l2_device_register(NULL, v4l2_dev) < 0) { 789 v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); 790 return -1; 791 } 792 cam->pport = port; 793 cam->brightness = 128; 794 cam->contrast = 64; 795 cam->color = 64; 796 cam->hue = 0; 797 798 /* Select requested transfer mode */ 799 switch (parmode) { 800 default: /* Auto-detect (priority: hw-ecp, hw-epp, sw-ecp) */ 801 case 0: 802 if (port->modes & PARPORT_MODE_ECP) 803 cam->ppmode = IEEE1284_MODE_ECP; 804 else if (port->modes & PARPORT_MODE_EPP) 805 cam->ppmode = IEEE1284_MODE_EPP; 806 else 807 cam->ppmode = IEEE1284_MODE_ECP; 808 break; 809 case 1: /* hw- or sw-ecp */ 810 cam->ppmode = IEEE1284_MODE_ECP; 811 break; 812 case 2: /* hw- or sw-epp */ 813 cam->ppmode = IEEE1284_MODE_EPP; 814 break; 815 } 816 817 /* Tell the parport driver that we exists */ 818 cam->pdev = parport_register_device(port, "w9966", NULL, NULL, NULL, 0, NULL); 819 if (cam->pdev == NULL) { 820 DPRINTF("parport_register_device() failed\n"); 821 return -1; 822 } 823 w9966_set_state(cam, W9966_STATE_PDEV, W9966_STATE_PDEV); 824 825 w9966_pdev_claim(cam); 826 827 /* Setup a default capture mode */ 828 if (w9966_setup(cam, 0, 0, 1023, 1023, 200, 160) != 0) { 829 DPRINTF("w9966_setup() failed.\n"); 830 return -1; 831 } 832 833 w9966_pdev_release(cam); 834 835 /* Fill in the video_device struct and register us to v4l */ 836 strlcpy(cam->vdev.name, W9966_DRIVERNAME, sizeof(cam->vdev.name)); 837 cam->vdev.v4l2_dev = v4l2_dev; 838 cam->vdev.fops = &w9966_fops; 839 cam->vdev.ioctl_ops = &w9966_ioctl_ops; 840 cam->vdev.release = video_device_release_empty; 841 video_set_drvdata(&cam->vdev, cam); 842 843 mutex_init(&cam->lock); 844 845 if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) 846 return -1; 847 848 w9966_set_state(cam, W9966_STATE_VDEV, W9966_STATE_VDEV); 849 850 /* All ok */ 851 v4l2_info(v4l2_dev, "Found and initialized a webcam on %s.\n", 852 cam->pport->name); 853 return 0; 854} 855 856 857/* Terminate everything gracefully */ 858static void w9966_term(struct w9966 *cam) 859{ 860 /* Unregister from v4l */ 861 if (w9966_get_state(cam, W9966_STATE_VDEV, W9966_STATE_VDEV)) { 862 video_unregister_device(&cam->vdev); 863 w9966_set_state(cam, W9966_STATE_VDEV, 0); 864 } 865 866 /* Terminate from IEEE1284 mode and release pdev block */ 867 if (w9966_get_state(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) { 868 w9966_pdev_claim(cam); 869 parport_negotiate(cam->pport, IEEE1284_MODE_COMPAT); 870 w9966_pdev_release(cam); 871 } 872 873 /* Unregister from parport */ 874 if (w9966_get_state(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) { 875 parport_unregister_device(cam->pdev); 876 w9966_set_state(cam, W9966_STATE_PDEV, 0); 877 } 878} 879 880 881/* Called once for every parport on init */ 882static void w9966_attach(struct parport *port) 883{ 884 int i; 885 886 for (i = 0; i < W9966_MAXCAMS; i++) { 887 if (w9966_cams[i].dev_state != 0) /* Cam is already assigned */ 888 continue; 889 if (strcmp(pardev[i], "aggressive") == 0 || strcmp(pardev[i], port->name) == 0) { 890 if (w9966_init(&w9966_cams[i], port) != 0) 891 w9966_term(&w9966_cams[i]); 892 break; /* return */ 893 } 894 } 895} 896 897/* Called once for every parport on termination */ 898static void w9966_detach(struct parport *port) 899{ 900 int i; 901 902 for (i = 0; i < W9966_MAXCAMS; i++) 903 if (w9966_cams[i].dev_state != 0 && w9966_cams[i].pport == port) 904 w9966_term(&w9966_cams[i]); 905} 906 907 908static struct parport_driver w9966_ppd = { 909 .name = W9966_DRIVERNAME, 910 .attach = w9966_attach, 911 .detach = w9966_detach, 912}; 913 914/* Module entry point */ 915static int __init w9966_mod_init(void) 916{ 917 int i; 918 919 for (i = 0; i < W9966_MAXCAMS; i++) 920 w9966_cams[i].dev_state = 0; 921 922 return parport_register_driver(&w9966_ppd); 923} 924 925/* Module cleanup */ 926static void __exit w9966_mod_term(void) 927{ 928 parport_unregister_driver(&w9966_ppd); 929} 930 931module_init(w9966_mod_init); 932module_exit(w9966_mod_term); 933