linux/drivers/media/video/w9966.c
<<
>>
Prefs
   1/*
   2        Winbond w9966cf Webcam parport driver.
   3
   4        Version 0.32
   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/videodev.h>
  61#include <media/v4l2-common.h>
  62#include <media/v4l2-ioctl.h>
  63#include <linux/parport.h>
  64
  65/*#define DEBUG*/                               /* Undef me for production */
  66
  67#ifdef DEBUG
  68#define DPRINTF(x, a...) printk(KERN_DEBUG "W9966: %s(): "x, __func__ , ##a)
  69#else
  70#define DPRINTF(x...)
  71#endif
  72
  73/*
  74 *      Defines, simple typedefs etc.
  75 */
  76
  77#define W9966_DRIVERNAME        "W9966CF Webcam"
  78#define W9966_MAXCAMS           4       // Maximum number of cameras
  79#define W9966_RBUFFER           2048    // Read buffer (must be an even number)
  80#define W9966_SRAMSIZE          131072  // 128kb
  81#define W9966_SRAMID            0x02    // check w9966cf.pdf
  82
  83// Empirically determined window limits
  84#define W9966_WND_MIN_X         16
  85#define W9966_WND_MIN_Y         14
  86#define W9966_WND_MAX_X         705
  87#define W9966_WND_MAX_Y         253
  88#define W9966_WND_MAX_W         (W9966_WND_MAX_X - W9966_WND_MIN_X)
  89#define W9966_WND_MAX_H         (W9966_WND_MAX_Y - W9966_WND_MIN_Y)
  90
  91// Keep track of our current state
  92#define W9966_STATE_PDEV        0x01
  93#define W9966_STATE_CLAIMED     0x02
  94#define W9966_STATE_VDEV        0x04
  95
  96#define W9966_I2C_W_ID          0x48
  97#define W9966_I2C_R_ID          0x49
  98#define W9966_I2C_R_DATA        0x08
  99#define W9966_I2C_R_CLOCK       0x04
 100#define W9966_I2C_W_DATA        0x02
 101#define W9966_I2C_W_CLOCK       0x01
 102
 103struct w9966_dev {
 104        unsigned char dev_state;
 105        unsigned char i2c_state;
 106        unsigned short ppmode;
 107        struct parport* pport;
 108        struct pardevice* pdev;
 109        struct video_device vdev;
 110        unsigned short width;
 111        unsigned short height;
 112        unsigned char brightness;
 113        signed char contrast;
 114        signed char color;
 115        signed char hue;
 116        unsigned long in_use;
 117};
 118
 119/*
 120 *      Module specific properties
 121 */
 122
 123MODULE_AUTHOR("Jakob Kemi <jakob.kemi@post.utfors.se>");
 124MODULE_DESCRIPTION("Winbond w9966cf WebCam driver (0.32)");
 125MODULE_LICENSE("GPL");
 126
 127
 128#ifdef MODULE
 129static const char* pardev[] = {[0 ... W9966_MAXCAMS] = ""};
 130#else
 131static const char* pardev[] = {[0 ... W9966_MAXCAMS] = "aggressive"};
 132#endif
 133module_param_array(pardev, charp, NULL, 0);
 134MODULE_PARM_DESC(pardev, "pardev: where to search for\n\
 135\teach camera. 'aggressive' means brute-force search.\n\
 136\tEg: >pardev=parport3,aggressive,parport2,parport1< would assign\n\
 137\tcam 1 to parport3 and search every parport for cam 2 etc...");
 138
 139static int parmode;
 140module_param(parmode, int, 0);
 141MODULE_PARM_DESC(parmode, "parmode: transfer mode (0=auto, 1=ecp, 2=epp");
 142
 143static int video_nr = -1;
 144module_param(video_nr, int, 0);
 145
 146/*
 147 *      Private data
 148 */
 149
 150static struct w9966_dev w9966_cams[W9966_MAXCAMS];
 151
 152/*
 153 *      Private function declares
 154 */
 155
 156static inline void w9966_setState(struct w9966_dev* cam, int mask, int val);
 157static inline int  w9966_getState(struct w9966_dev* cam, int mask, int val);
 158static inline void w9966_pdev_claim(struct w9966_dev *vdev);
 159static inline void w9966_pdev_release(struct w9966_dev *vdev);
 160
 161static int w9966_rReg(struct w9966_dev* cam, int reg);
 162static int w9966_wReg(struct w9966_dev* cam, int reg, int data);
 163#if 0
 164static int w9966_rReg_i2c(struct w9966_dev* cam, int reg);
 165#endif
 166static int w9966_wReg_i2c(struct w9966_dev* cam, int reg, int data);
 167static int w9966_findlen(int near, int size, int maxlen);
 168static int w9966_calcscale(int size, int min, int max, int* beg, int* end, unsigned char* factor);
 169static int w9966_setup(struct w9966_dev* cam, int x1, int y1, int x2, int y2, int w, int h);
 170
 171static int  w9966_init(struct w9966_dev* cam, struct parport* port);
 172static void w9966_term(struct w9966_dev* cam);
 173
 174static inline void w9966_i2c_setsda(struct w9966_dev* cam, int state);
 175static inline int  w9966_i2c_setscl(struct w9966_dev* cam, int state);
 176static inline int  w9966_i2c_getsda(struct w9966_dev* cam);
 177static inline int  w9966_i2c_getscl(struct w9966_dev* cam);
 178static int w9966_i2c_wbyte(struct w9966_dev* cam, int data);
 179#if 0
 180static int w9966_i2c_rbyte(struct w9966_dev* cam);
 181#endif
 182
 183static long w9966_v4l_ioctl(struct file *file,
 184                           unsigned int cmd, unsigned long arg);
 185static ssize_t w9966_v4l_read(struct file *file, char __user *buf,
 186                              size_t count, loff_t *ppos);
 187
 188static int w9966_exclusive_open(struct file *file)
 189{
 190        struct w9966_dev *cam = video_drvdata(file);
 191
 192        return test_and_set_bit(0, &cam->in_use) ? -EBUSY : 0;
 193}
 194
 195static int w9966_exclusive_release(struct file *file)
 196{
 197        struct w9966_dev *cam = video_drvdata(file);
 198
 199        clear_bit(0, &cam->in_use);
 200        return 0;
 201}
 202
 203static const struct v4l2_file_operations w9966_fops = {
 204        .owner          = THIS_MODULE,
 205        .open           = w9966_exclusive_open,
 206        .release        = w9966_exclusive_release,
 207        .ioctl          = w9966_v4l_ioctl,
 208        .read           = w9966_v4l_read,
 209};
 210static struct video_device w9966_template = {
 211        .name           = W9966_DRIVERNAME,
 212        .fops           = &w9966_fops,
 213        .release        = video_device_release_empty,
 214};
 215
 216/*
 217 *      Private function defines
 218 */
 219
 220
 221// Set camera phase flags, so we know what to uninit when terminating
 222static inline void w9966_setState(struct w9966_dev* cam, int mask, int val)
 223{
 224        cam->dev_state = (cam->dev_state & ~mask) ^ val;
 225}
 226
 227// Get camera phase flags
 228static inline int w9966_getState(struct w9966_dev* cam, int mask, int val)
 229{
 230        return ((cam->dev_state & mask) == val);
 231}
 232
 233// Claim parport for ourself
 234static inline void w9966_pdev_claim(struct w9966_dev* cam)
 235{
 236        if (w9966_getState(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED))
 237                return;
 238        parport_claim_or_block(cam->pdev);
 239        w9966_setState(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED);
 240}
 241
 242// Release parport for others to use
 243static inline void w9966_pdev_release(struct w9966_dev* cam)
 244{
 245        if (w9966_getState(cam, W9966_STATE_CLAIMED, 0))
 246                return;
 247        parport_release(cam->pdev);
 248        w9966_setState(cam, W9966_STATE_CLAIMED, 0);
 249}
 250
 251// Read register from W9966 interface-chip
 252// Expects a claimed pdev
 253// -1 on error, else register data (byte)
 254static int w9966_rReg(struct w9966_dev* cam, int reg)
 255{
 256        // ECP, read, regtransfer, REG, REG, REG, REG, REG
 257        const unsigned char addr = 0x80 | (reg & 0x1f);
 258        unsigned char val;
 259
 260        if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0)
 261                return -1;
 262        if (parport_write(cam->pport, &addr, 1) != 1)
 263                return -1;
 264        if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0)
 265                return -1;
 266        if (parport_read(cam->pport, &val, 1) != 1)
 267                return -1;
 268
 269        return val;
 270}
 271
 272// Write register to W9966 interface-chip
 273// Expects a claimed pdev
 274// -1 on error
 275static int w9966_wReg(struct w9966_dev* cam, int reg, int data)
 276{
 277        // ECP, write, regtransfer, REG, REG, REG, REG, REG
 278        const unsigned char addr = 0xc0 | (reg & 0x1f);
 279        const unsigned char val = data;
 280
 281        if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0)
 282                return -1;
 283        if (parport_write(cam->pport, &addr, 1) != 1)
 284                return -1;
 285        if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0)
 286                return -1;
 287        if (parport_write(cam->pport, &val, 1) != 1)
 288                return -1;
 289
 290        return 0;
 291}
 292
 293// Initialize camera device. Setup all internal flags, set a
 294// default video mode, setup ccd-chip, register v4l device etc..
 295// Also used for 'probing' of hardware.
 296// -1 on error
 297static int w9966_init(struct w9966_dev* cam, struct parport* port)
 298{
 299        if (cam->dev_state != 0)
 300                return -1;
 301
 302        cam->pport = port;
 303        cam->brightness = 128;
 304        cam->contrast = 64;
 305        cam->color = 64;
 306        cam->hue = 0;
 307
 308// Select requested transfer mode
 309        switch(parmode)
 310        {
 311        default:        // Auto-detect (priority: hw-ecp, hw-epp, sw-ecp)
 312        case 0:
 313                if (port->modes & PARPORT_MODE_ECP)
 314                        cam->ppmode = IEEE1284_MODE_ECP;
 315                else if (port->modes & PARPORT_MODE_EPP)
 316                        cam->ppmode = IEEE1284_MODE_EPP;
 317                else
 318                        cam->ppmode = IEEE1284_MODE_ECP;
 319                break;
 320        case 1:         // hw- or sw-ecp
 321                cam->ppmode = IEEE1284_MODE_ECP;
 322                break;
 323        case 2:         // hw- or sw-epp
 324                cam->ppmode = IEEE1284_MODE_EPP;
 325        break;
 326        }
 327
 328// Tell the parport driver that we exists
 329        cam->pdev = parport_register_device(port, "w9966", NULL, NULL, NULL, 0, NULL);
 330        if (cam->pdev == NULL) {
 331                DPRINTF("parport_register_device() failed\n");
 332                return -1;
 333        }
 334        w9966_setState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV);
 335
 336        w9966_pdev_claim(cam);
 337
 338// Setup a default capture mode
 339        if (w9966_setup(cam, 0, 0, 1023, 1023, 200, 160) != 0) {
 340                DPRINTF("w9966_setup() failed.\n");
 341                return -1;
 342        }
 343
 344        w9966_pdev_release(cam);
 345
 346// Fill in the video_device struct and register us to v4l
 347        memcpy(&cam->vdev, &w9966_template, sizeof(struct video_device));
 348        video_set_drvdata(&cam->vdev, cam);
 349
 350        if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0)
 351                return -1;
 352
 353        w9966_setState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV);
 354
 355        // All ok
 356        printk(
 357                "w9966cf: Found and initialized a webcam on %s.\n",
 358                cam->pport->name
 359        );
 360        return 0;
 361}
 362
 363
 364// Terminate everything gracefully
 365static void w9966_term(struct w9966_dev* cam)
 366{
 367// Unregister from v4l
 368        if (w9966_getState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV)) {
 369                video_unregister_device(&cam->vdev);
 370                w9966_setState(cam, W9966_STATE_VDEV, 0);
 371        }
 372
 373// Terminate from IEEE1284 mode and release pdev block
 374        if (w9966_getState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) {
 375                w9966_pdev_claim(cam);
 376                parport_negotiate(cam->pport, IEEE1284_MODE_COMPAT);
 377                w9966_pdev_release(cam);
 378        }
 379
 380// Unregister from parport
 381        if (w9966_getState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) {
 382                parport_unregister_device(cam->pdev);
 383                w9966_setState(cam, W9966_STATE_PDEV, 0);
 384        }
 385}
 386
 387
 388// Find a good length for capture window (used both for W and H)
 389// A bit ugly but pretty functional. The capture length
 390// have to match the downscale
 391static int w9966_findlen(int near, int size, int maxlen)
 392{
 393        int bestlen = size;
 394        int besterr = abs(near - bestlen);
 395        int len;
 396
 397        for(len = size+1;len < maxlen;len++)
 398        {
 399                int err;
 400                if ( ((64*size) %len) != 0)
 401                        continue;
 402
 403                err = abs(near - len);
 404
 405                // Only continue as long as we keep getting better values
 406                if (err > besterr)
 407                        break;
 408
 409                besterr = err;
 410                bestlen = len;
 411        }
 412
 413        return bestlen;
 414}
 415
 416// Modify capture window (if necessary)
 417// and calculate downscaling
 418// Return -1 on error
 419static int w9966_calcscale(int size, int min, int max, int* beg, int* end, unsigned char* factor)
 420{
 421        int maxlen = max - min;
 422        int len = *end - *beg + 1;
 423        int newlen = w9966_findlen(len, size, maxlen);
 424        int err = newlen - len;
 425
 426        // Check for bad format
 427        if (newlen > maxlen || newlen < size)
 428                return -1;
 429
 430        // Set factor (6 bit fixed)
 431        *factor = (64*size) / newlen;
 432        if (*factor == 64)
 433                *factor = 0x00; // downscale is disabled
 434        else
 435                *factor |= 0x80; // set downscale-enable bit
 436
 437        // Modify old beginning and end
 438        *beg -= err / 2;
 439        *end += err - (err / 2);
 440
 441        // Move window if outside borders
 442        if (*beg < min) {
 443                *end += min - *beg;
 444                *beg += min - *beg;
 445        }
 446        if (*end > max) {
 447                *beg -= *end - max;
 448                *end -= *end - max;
 449        }
 450
 451        return 0;
 452}
 453
 454// Setup the cameras capture window etc.
 455// Expects a claimed pdev
 456// return -1 on error
 457static int w9966_setup(struct w9966_dev* cam, int x1, int y1, int x2, int y2, int w, int h)
 458{
 459        unsigned int i;
 460        unsigned int enh_s, enh_e;
 461        unsigned char scale_x, scale_y;
 462        unsigned char regs[0x1c];
 463        unsigned char saa7111_regs[] = {
 464                0x21, 0x00, 0xd8, 0x23, 0x00, 0x80, 0x80, 0x00,
 465                0x88, 0x10, 0x80, 0x40, 0x40, 0x00, 0x01, 0x00,
 466                0x48, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 467                0x00, 0x00, 0x00, 0x71, 0xe7, 0x00, 0x00, 0xc0
 468        };
 469
 470
 471        if (w*h*2 > W9966_SRAMSIZE)
 472        {
 473                DPRINTF("capture window exceeds SRAM size!.\n");
 474                w = 200; h = 160;       // Pick default values
 475        }
 476
 477        w &= ~0x1;
 478        if (w < 2) w = 2;
 479        if (h < 1) h = 1;
 480        if (w > W9966_WND_MAX_W) w = W9966_WND_MAX_W;
 481        if (h > W9966_WND_MAX_H) h = W9966_WND_MAX_H;
 482
 483        cam->width = w;
 484        cam->height = h;
 485
 486        enh_s = 0;
 487        enh_e = w*h*2;
 488
 489// Modify capture window if necessary and calculate downscaling
 490        if (
 491                w9966_calcscale(w, W9966_WND_MIN_X, W9966_WND_MAX_X, &x1, &x2, &scale_x) != 0 ||
 492                w9966_calcscale(h, W9966_WND_MIN_Y, W9966_WND_MAX_Y, &y1, &y2, &scale_y) != 0
 493        ) return -1;
 494
 495        DPRINTF(
 496                "%dx%d, x: %d<->%d, y: %d<->%d, sx: %d/64, sy: %d/64.\n",
 497                w, h, x1, x2, y1, y2, scale_x&~0x80, scale_y&~0x80
 498        );
 499
 500// Setup registers
 501        regs[0x00] = 0x00;                      // Set normal operation
 502        regs[0x01] = 0x18;                      // Capture mode
 503        regs[0x02] = scale_y;                   // V-scaling
 504        regs[0x03] = scale_x;                   // H-scaling
 505
 506        // Capture window
 507        regs[0x04] = (x1 & 0x0ff);              // X-start (8 low bits)
 508        regs[0x05] = (x1 & 0x300)>>8;           // X-start (2 high bits)
 509        regs[0x06] = (y1 & 0x0ff);              // Y-start (8 low bits)
 510        regs[0x07] = (y1 & 0x300)>>8;           // Y-start (2 high bits)
 511        regs[0x08] = (x2 & 0x0ff);              // X-end (8 low bits)
 512        regs[0x09] = (x2 & 0x300)>>8;           // X-end (2 high bits)
 513        regs[0x0a] = (y2 & 0x0ff);              // Y-end (8 low bits)
 514
 515        regs[0x0c] = W9966_SRAMID;              // SRAM-banks (1x 128kb)
 516
 517        // Enhancement layer
 518        regs[0x0d] = (enh_s& 0x000ff);          // Enh. start (0-7)
 519        regs[0x0e] = (enh_s& 0x0ff00)>>8;       // Enh. start (8-15)
 520        regs[0x0f] = (enh_s& 0x70000)>>16;      // Enh. start (16-17/18??)
 521        regs[0x10] = (enh_e& 0x000ff);          // Enh. end (0-7)
 522        regs[0x11] = (enh_e& 0x0ff00)>>8;       // Enh. end (8-15)
 523        regs[0x12] = (enh_e& 0x70000)>>16;      // Enh. end (16-17/18??)
 524
 525        // Misc
 526        regs[0x13] = 0x40;                      // VEE control (raw 4:2:2)
 527        regs[0x17] = 0x00;                      // ???
 528        regs[0x18] = cam->i2c_state = 0x00;     // Serial bus
 529        regs[0x19] = 0xff;                      // I/O port direction control
 530        regs[0x1a] = 0xff;                      // I/O port data register
 531        regs[0x1b] = 0x10;                      // ???
 532
 533        // SAA7111 chip settings
 534        saa7111_regs[0x0a] = cam->brightness;
 535        saa7111_regs[0x0b] = cam->contrast;
 536        saa7111_regs[0x0c] = cam->color;
 537        saa7111_regs[0x0d] = cam->hue;
 538
 539// Reset (ECP-fifo & serial-bus)
 540        if (w9966_wReg(cam, 0x00, 0x03) == -1)
 541                return -1;
 542
 543// Write regs to w9966cf chip
 544        for (i = 0; i < 0x1c; i++)
 545                if (w9966_wReg(cam, i, regs[i]) == -1)
 546                        return -1;
 547
 548// Write regs to saa7111 chip
 549        for (i = 0; i < 0x20; i++)
 550                if (w9966_wReg_i2c(cam, i, saa7111_regs[i]) == -1)
 551                        return -1;
 552
 553        return 0;
 554}
 555
 556/*
 557 *      Ugly and primitive i2c protocol functions
 558 */
 559
 560// Sets the data line on the i2c bus.
 561// Expects a claimed pdev.
 562static inline void w9966_i2c_setsda(struct w9966_dev* cam, int state)
 563{
 564        if (state)
 565                cam->i2c_state |= W9966_I2C_W_DATA;
 566        else
 567                cam->i2c_state &= ~W9966_I2C_W_DATA;
 568
 569        w9966_wReg(cam, 0x18, cam->i2c_state);
 570        udelay(5);
 571}
 572
 573// Get peripheral clock line
 574// Expects a claimed pdev.
 575static inline int w9966_i2c_getscl(struct w9966_dev* cam)
 576{
 577        const unsigned char state = w9966_rReg(cam, 0x18);
 578        return ((state & W9966_I2C_R_CLOCK) > 0);
 579}
 580
 581// Sets the clock line on the i2c bus.
 582// Expects a claimed pdev. -1 on error
 583static inline int w9966_i2c_setscl(struct w9966_dev* cam, int state)
 584{
 585        unsigned long timeout;
 586
 587        if (state)
 588                cam->i2c_state |= W9966_I2C_W_CLOCK;
 589        else
 590                cam->i2c_state &= ~W9966_I2C_W_CLOCK;
 591
 592        w9966_wReg(cam, 0x18, cam->i2c_state);
 593        udelay(5);
 594
 595        // we go to high, we also expect the peripheral to ack.
 596        if (state) {
 597                timeout = jiffies + 100;
 598                while (!w9966_i2c_getscl(cam)) {
 599                        if (time_after(jiffies, timeout))
 600                                return -1;
 601                }
 602        }
 603        return 0;
 604}
 605
 606// Get peripheral data line
 607// Expects a claimed pdev.
 608static inline int w9966_i2c_getsda(struct w9966_dev* cam)
 609{
 610        const unsigned char state = w9966_rReg(cam, 0x18);
 611        return ((state & W9966_I2C_R_DATA) > 0);
 612}
 613
 614// Write a byte with ack to the i2c bus.
 615// Expects a claimed pdev. -1 on error
 616static int w9966_i2c_wbyte(struct w9966_dev* cam, int data)
 617{
 618        int i;
 619        for (i = 7; i >= 0; i--)
 620        {
 621                w9966_i2c_setsda(cam, (data >> i) & 0x01);
 622
 623                if (w9966_i2c_setscl(cam, 1) == -1)
 624                        return -1;
 625                w9966_i2c_setscl(cam, 0);
 626        }
 627
 628        w9966_i2c_setsda(cam, 1);
 629
 630        if (w9966_i2c_setscl(cam, 1) == -1)
 631                return -1;
 632        w9966_i2c_setscl(cam, 0);
 633
 634        return 0;
 635}
 636
 637// Read a data byte with ack from the i2c-bus
 638// Expects a claimed pdev. -1 on error
 639#if 0
 640static int w9966_i2c_rbyte(struct w9966_dev* cam)
 641{
 642        unsigned char data = 0x00;
 643        int i;
 644
 645        w9966_i2c_setsda(cam, 1);
 646
 647        for (i = 0; i < 8; i++)
 648        {
 649                if (w9966_i2c_setscl(cam, 1) == -1)
 650                        return -1;
 651                data = data << 1;
 652                if (w9966_i2c_getsda(cam))
 653                        data |= 0x01;
 654
 655                w9966_i2c_setscl(cam, 0);
 656        }
 657        return data;
 658}
 659#endif
 660
 661// Read a register from the i2c device.
 662// Expects claimed pdev. -1 on error
 663#if 0
 664static int w9966_rReg_i2c(struct w9966_dev* cam, int reg)
 665{
 666        int data;
 667
 668        w9966_i2c_setsda(cam, 0);
 669        w9966_i2c_setscl(cam, 0);
 670
 671        if (
 672                w9966_i2c_wbyte(cam, W9966_I2C_W_ID) == -1 ||
 673                w9966_i2c_wbyte(cam, reg) == -1
 674        )
 675                return -1;
 676
 677        w9966_i2c_setsda(cam, 1);
 678        if (w9966_i2c_setscl(cam, 1) == -1)
 679                return -1;
 680        w9966_i2c_setsda(cam, 0);
 681        w9966_i2c_setscl(cam, 0);
 682
 683        if (
 684                w9966_i2c_wbyte(cam, W9966_I2C_R_ID) == -1 ||
 685                (data = w9966_i2c_rbyte(cam)) == -1
 686        )
 687                return -1;
 688
 689        w9966_i2c_setsda(cam, 0);
 690
 691        if (w9966_i2c_setscl(cam, 1) == -1)
 692                return -1;
 693        w9966_i2c_setsda(cam, 1);
 694
 695        return data;
 696}
 697#endif
 698
 699// Write a register to the i2c device.
 700// Expects claimed pdev. -1 on error
 701static int w9966_wReg_i2c(struct w9966_dev* cam, int reg, int data)
 702{
 703        w9966_i2c_setsda(cam, 0);
 704        w9966_i2c_setscl(cam, 0);
 705
 706        if (
 707                w9966_i2c_wbyte(cam, W9966_I2C_W_ID) == -1 ||
 708                w9966_i2c_wbyte(cam, reg) == -1 ||
 709                w9966_i2c_wbyte(cam, data) == -1
 710        )
 711                return -1;
 712
 713        w9966_i2c_setsda(cam, 0);
 714        if (w9966_i2c_setscl(cam, 1) == -1)
 715                return -1;
 716
 717        w9966_i2c_setsda(cam, 1);
 718
 719        return 0;
 720}
 721
 722/*
 723 *      Video4linux interfacing
 724 */
 725
 726static long w9966_v4l_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 727{
 728        struct w9966_dev *cam = video_drvdata(file);
 729
 730        switch(cmd)
 731        {
 732        case VIDIOCGCAP:
 733        {
 734                static struct video_capability vcap = {
 735                        .name      = W9966_DRIVERNAME,
 736                        .type      = VID_TYPE_CAPTURE | VID_TYPE_SCALES,
 737                        .channels  = 1,
 738                        .maxwidth  = W9966_WND_MAX_W,
 739                        .maxheight = W9966_WND_MAX_H,
 740                        .minwidth  = 2,
 741                        .minheight = 1,
 742                };
 743                struct video_capability *cap = arg;
 744                *cap = vcap;
 745                return 0;
 746        }
 747        case VIDIOCGCHAN:
 748        {
 749                struct video_channel *vch = arg;
 750                if(vch->channel != 0)   // We only support one channel (#0)
 751                        return -EINVAL;
 752                memset(vch,0,sizeof(*vch));
 753                strcpy(vch->name, "CCD-input");
 754                vch->type = VIDEO_TYPE_CAMERA;
 755                return 0;
 756        }
 757        case VIDIOCSCHAN:
 758        {
 759                struct video_channel *vch = arg;
 760                if(vch->channel != 0)
 761                        return -EINVAL;
 762                return 0;
 763        }
 764        case VIDIOCGTUNER:
 765        {
 766                struct video_tuner *vtune = arg;
 767                if(vtune->tuner != 0)
 768                        return -EINVAL;
 769                strcpy(vtune->name, "no tuner");
 770                vtune->rangelow = 0;
 771                vtune->rangehigh = 0;
 772                vtune->flags = VIDEO_TUNER_NORM;
 773                vtune->mode = VIDEO_MODE_AUTO;
 774                vtune->signal = 0xffff;
 775                return 0;
 776        }
 777        case VIDIOCSTUNER:
 778        {
 779                struct video_tuner *vtune = arg;
 780                if (vtune->tuner != 0)
 781                        return -EINVAL;
 782                if (vtune->mode != VIDEO_MODE_AUTO)
 783                        return -EINVAL;
 784                return 0;
 785        }
 786        case VIDIOCGPICT:
 787        {
 788                struct video_picture vpic = {
 789                        cam->brightness << 8,   // brightness
 790                        (cam->hue + 128) << 8,  // hue
 791                        cam->color << 9,        // color
 792                        cam->contrast << 9,     // contrast
 793                        0x8000,                 // whiteness
 794                        16, VIDEO_PALETTE_YUV422// bpp, palette format
 795                };
 796                struct video_picture *pic = arg;
 797                *pic = vpic;
 798                return 0;
 799        }
 800        case VIDIOCSPICT:
 801        {
 802                struct video_picture *vpic = arg;
 803                if (vpic->depth != 16 || (vpic->palette != VIDEO_PALETTE_YUV422 && vpic->palette != VIDEO_PALETTE_YUYV))
 804                        return -EINVAL;
 805
 806                cam->brightness = vpic->brightness >> 8;
 807                cam->hue = (vpic->hue >> 8) - 128;
 808                cam->color = vpic->colour >> 9;
 809                cam->contrast = vpic->contrast >> 9;
 810
 811                w9966_pdev_claim(cam);
 812
 813                if (
 814                        w9966_wReg_i2c(cam, 0x0a, cam->brightness) == -1 ||
 815                        w9966_wReg_i2c(cam, 0x0b, cam->contrast) == -1 ||
 816                        w9966_wReg_i2c(cam, 0x0c, cam->color) == -1 ||
 817                        w9966_wReg_i2c(cam, 0x0d, cam->hue) == -1
 818                ) {
 819                        w9966_pdev_release(cam);
 820                        return -EIO;
 821                }
 822
 823                w9966_pdev_release(cam);
 824                return 0;
 825        }
 826        case VIDIOCSWIN:
 827        {
 828                int ret;
 829                struct video_window *vwin = arg;
 830
 831                if (vwin->flags != 0)
 832                        return -EINVAL;
 833                if (vwin->clipcount != 0)
 834                        return -EINVAL;
 835                if (vwin->width < 2 || vwin->width > W9966_WND_MAX_W)
 836                        return -EINVAL;
 837                if (vwin->height < 1 || vwin->height > W9966_WND_MAX_H)
 838                        return -EINVAL;
 839
 840                // Update camera regs
 841                w9966_pdev_claim(cam);
 842                ret = w9966_setup(cam, 0, 0, 1023, 1023, vwin->width, vwin->height);
 843                w9966_pdev_release(cam);
 844
 845                if (ret != 0) {
 846                        DPRINTF("VIDIOCSWIN: w9966_setup() failed.\n");
 847                        return -EIO;
 848                }
 849
 850                return 0;
 851        }
 852        case VIDIOCGWIN:
 853        {
 854                struct video_window *vwin = arg;
 855                memset(vwin, 0, sizeof(*vwin));
 856                vwin->width = cam->width;
 857                vwin->height = cam->height;
 858                return 0;
 859        }
 860        // Unimplemented
 861        case VIDIOCCAPTURE:
 862        case VIDIOCGFBUF:
 863        case VIDIOCSFBUF:
 864        case VIDIOCKEY:
 865        case VIDIOCGFREQ:
 866        case VIDIOCSFREQ:
 867        case VIDIOCGAUDIO:
 868        case VIDIOCSAUDIO:
 869                return -EINVAL;
 870        default:
 871                return -ENOIOCTLCMD;
 872        }
 873        return 0;
 874}
 875
 876static long w9966_v4l_ioctl(struct file *file,
 877                           unsigned int cmd, unsigned long arg)
 878{
 879        return video_usercopy(file, cmd, arg, w9966_v4l_do_ioctl);
 880}
 881
 882// Capture data
 883static ssize_t w9966_v4l_read(struct file *file, char  __user *buf,
 884                              size_t count, loff_t *ppos)
 885{
 886        struct w9966_dev *cam = video_drvdata(file);
 887        unsigned char addr = 0xa0;      // ECP, read, CCD-transfer, 00000
 888        unsigned char __user *dest = (unsigned char __user *)buf;
 889        unsigned long dleft = count;
 890        unsigned char *tbuf;
 891
 892        // Why would anyone want more than this??
 893        if (count > cam->width * cam->height * 2)
 894                return -EINVAL;
 895
 896        w9966_pdev_claim(cam);
 897        w9966_wReg(cam, 0x00, 0x02);    // Reset ECP-FIFO buffer
 898        w9966_wReg(cam, 0x00, 0x00);    // Return to normal operation
 899        w9966_wReg(cam, 0x01, 0x98);    // Enable capture
 900
 901        // write special capture-addr and negotiate into data transfer
 902        if (
 903                (parport_negotiate(cam->pport, cam->ppmode|IEEE1284_ADDR) != 0  )||
 904                (parport_write(cam->pport, &addr, 1) != 1                                               )||
 905                (parport_negotiate(cam->pport, cam->ppmode|IEEE1284_DATA) != 0  )
 906        ) {
 907                w9966_pdev_release(cam);
 908                return -EFAULT;
 909        }
 910
 911        tbuf = kmalloc(W9966_RBUFFER, GFP_KERNEL);
 912        if (tbuf == NULL) {
 913                count = -ENOMEM;
 914                goto out;
 915        }
 916
 917        while(dleft > 0)
 918        {
 919                unsigned long tsize = (dleft > W9966_RBUFFER) ? W9966_RBUFFER : dleft;
 920
 921                if (parport_read(cam->pport, tbuf, tsize) < tsize) {
 922                        count = -EFAULT;
 923                        goto out;
 924                }
 925                if (copy_to_user(dest, tbuf, tsize) != 0) {
 926                        count = -EFAULT;
 927                        goto out;
 928                }
 929                dest += tsize;
 930                dleft -= tsize;
 931        }
 932
 933        w9966_wReg(cam, 0x01, 0x18);    // Disable capture
 934
 935out:
 936        kfree(tbuf);
 937        w9966_pdev_release(cam);
 938
 939        return count;
 940}
 941
 942
 943// Called once for every parport on init
 944static void w9966_attach(struct parport *port)
 945{
 946        int i;
 947
 948        for (i = 0; i < W9966_MAXCAMS; i++)
 949        {
 950                if (w9966_cams[i].dev_state != 0)       // Cam is already assigned
 951                        continue;
 952                if (
 953                        strcmp(pardev[i], "aggressive") == 0 ||
 954                        strcmp(pardev[i], port->name) == 0
 955                ) {
 956                        if (w9966_init(&w9966_cams[i], port) != 0)
 957                        w9966_term(&w9966_cams[i]);
 958                        break;  // return
 959                }
 960        }
 961}
 962
 963// Called once for every parport on termination
 964static void w9966_detach(struct parport *port)
 965{
 966        int i;
 967        for (i = 0; i < W9966_MAXCAMS; i++)
 968        if (w9966_cams[i].dev_state != 0 && w9966_cams[i].pport == port)
 969                w9966_term(&w9966_cams[i]);
 970}
 971
 972
 973static struct parport_driver w9966_ppd = {
 974        .name = W9966_DRIVERNAME,
 975        .attach = w9966_attach,
 976        .detach = w9966_detach,
 977};
 978
 979// Module entry point
 980static int __init w9966_mod_init(void)
 981{
 982        int i;
 983        for (i = 0; i < W9966_MAXCAMS; i++)
 984                w9966_cams[i].dev_state = 0;
 985
 986        return parport_register_driver(&w9966_ppd);
 987}
 988
 989// Module cleanup
 990static void __exit w9966_mod_term(void)
 991{
 992        parport_unregister_driver(&w9966_ppd);
 993}
 994
 995module_init(w9966_mod_init);
 996module_exit(w9966_mod_term);
 997