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