linux-old/drivers/usb/vicam.c
<<
>>
Prefs
   1/*
   2 * USB ViCam WebCam driver
   3 * Copyright (c) 2002 Joe Burks (jburks@wavicle.org),
   4 *                    Christopher L Cheney (ccheney@cheney.cx),
   5 *                    Pavel Machek (pavel@suse.cz),
   6 *                    John Tyner (jtyner@cs.ucr.edu),
   7 *                    Monroe Williams (monroe@pobox.com)
   8 *
   9 * Supports 3COM HomeConnect PC Digital WebCam
  10 *
  11 * This program is free software; you can redistribute it and/or modify
  12 * it under the terms of the GNU General Public License as published by
  13 * the Free Software Foundation; either version 2 of the License, or
  14 * (at your option) any later version.
  15 *
  16 * This program is distributed in the hope that it will be useful,
  17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19 * GNU General Public License for more details.
  20 *
  21 * You should have received a copy of the GNU General Public License
  22 * along with this program; if not, write to the Free Software
  23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24 *
  25 * This source code is based heavily on the CPiA webcam driver which was
  26 * written by Peter Pregler, Scott J. Bertin and Johannes Erdfelt
  27 *
  28 * Portions of this code were also copied from usbvideo.c
  29 *
  30 * Special thanks to the the whole team at Sourceforge for help making
  31 * this driver become a reality.  Notably:
  32 * Andy Armstrong who reverse engineered the color encoding and
  33 * Pavel Machek and Chris Cheney who worked on reverse engineering the
  34 *    camera controls and wrote the first generation driver.
  35 */
  36
  37#include <linux/kernel.h>
  38#include <linux/wrapper.h>
  39#include <linux/module.h>
  40#include <linux/init.h>
  41#include <linux/videodev.h>
  42#include <linux/usb.h>
  43#include <linux/vmalloc.h>
  44#include <linux/slab.h>
  45#include <linux/proc_fs.h>
  46#include "usbvideo.h"
  47
  48// #define VICAM_DEBUG
  49
  50#ifndef MODULE_LICENSE
  51#define MODULE_LICENSE(a)
  52#endif
  53
  54#ifndef bool
  55#define bool int
  56#endif
  57
  58#ifdef VICAM_DEBUG
  59#define ADBG(lineno,fmt,args...) printk(fmt, jiffies, __FUNCTION__, lineno, ##args)
  60#define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG __FILE__"(%ld):%s (%d):"fmt,##args)
  61#else
  62#define DBG(fmn,args...) do {} while(0)
  63#endif
  64
  65/* Version Information */
  66#define DRIVER_VERSION "v1.0"
  67#define DRIVER_AUTHOR "Joe Burks, jburks@wavicle.org"
  68#define DRIVER_DESC "ViCam WebCam Driver"
  69
  70/* Define these values to match your device */
  71#define USB_VICAM_VENDOR_ID     0x04c1
  72#define USB_VICAM_PRODUCT_ID    0x009d
  73
  74#define VICAM_BYTES_PER_PIXEL 3
  75#define VICAM_MAX_READ_SIZE (512*242+128)
  76#define VICAM_MAX_FRAME_SIZE (VICAM_BYTES_PER_PIXEL*320*240)
  77#define VICAM_FRAMES 2
  78
  79/* Not sure what all the bytes in these char
  80 * arrays do, but they're necessary to make
  81 * the camera work.
  82 */
  83
  84static unsigned char setup1[] = {
  85        0xB6, 0xC3, 0x1F, 0x00, 0x02, 0x64, 0xE7, 0x67,
  86        0xFD, 0xFF, 0x0E, 0xC0, 0xE7, 0x09, 0xDE, 0x00,
  87        0x8E, 0x00, 0xC0, 0x09, 0x40, 0x03, 0xC0, 0x17,
  88        0x44, 0x03, 0x4B, 0xAF, 0xC0, 0x07, 0x00, 0x00,
  89        0x4B, 0xAF, 0x97, 0xCF, 0x00, 0x00
  90};
  91
  92static unsigned char setup2[] = {
  93        0xB6, 0xC3, 0x03, 0x00, 0x03, 0x64, 0x18, 0x00,
  94        0x00, 0x00
  95};
  96
  97static unsigned char setup3[] = {
  98        0xB6, 0xC3, 0x01, 0x00, 0x06, 0x64, 0x00, 0x00
  99};
 100
 101static unsigned char setup4[] = {
 102        0xB6, 0xC3, 0x8F, 0x06, 0x02, 0x64, 0xE7, 0x07,
 103        0x00, 0x00, 0x08, 0xC0, 0xE7, 0x07, 0x00, 0x00,
 104        0x3E, 0xC0, 0xE7, 0x07, 0x54, 0x01, 0xAA, 0x00,
 105        0xE7, 0x07, 0xC8, 0x05, 0xB6, 0x00, 0xE7, 0x07,
 106        0x42, 0x01, 0xD2, 0x00, 0xE7, 0x07, 0x7C, 0x00,
 107        0x16, 0x00, 0xE7, 0x07, 0x56, 0x00, 0x18, 0x00,
 108        0xE7, 0x07, 0x06, 0x00, 0x92, 0xC0, 0xE7, 0x07,
 109        0x00, 0x00, 0x1E, 0xC0, 0xE7, 0x07, 0xFF, 0xFF,
 110        0x22, 0xC0, 0xE7, 0x07, 0x04, 0x00, 0x24, 0xC0,
 111        0xE7, 0x07, 0xEC, 0x27, 0x28, 0xC0, 0xE7, 0x07,
 112        0x16, 0x01, 0x8E, 0x00, 0xE7, 0x87, 0x01, 0x00,
 113        0x0E, 0xC0, 0x97, 0xCF, 0xD7, 0x09, 0x00, 0xC0,
 114        0xE7, 0x77, 0x01, 0x00, 0x92, 0xC0, 0x09, 0xC1,
 115        0xE7, 0x09, 0xFE, 0x05, 0x24, 0x01, 0xE7, 0x09,
 116        0x04, 0x06, 0x26, 0x01, 0xE7, 0x07, 0x07, 0x00,
 117        0x92, 0xC0, 0xE7, 0x05, 0x00, 0xC0, 0xC0, 0xDF,
 118        0x97, 0xCF, 0x17, 0x00, 0x57, 0x00, 0x17, 0x02,
 119        0xD7, 0x09, 0x00, 0xC0, 0xE7, 0x77, 0x01, 0x00,
 120        0x92, 0xC0, 0x0A, 0xC1, 0xE7, 0x57, 0xFF, 0xFF,
 121        0xFA, 0x05, 0x0D, 0xC0, 0xE7, 0x57, 0x00, 0x00,
 122        0xFA, 0x05, 0x0F, 0xC0, 0x9F, 0xAF, 0xC6, 0x00,
 123        0xE7, 0x05, 0x00, 0xC0, 0xC8, 0x05, 0xC1, 0x05,
 124        0xC0, 0x05, 0xC0, 0xDF, 0x97, 0xCF, 0x27, 0xDA,
 125        0xFA, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x0B, 0x06,
 126        0x73, 0xCF, 0x9F, 0xAF, 0x78, 0x01, 0x9F, 0xAF,
 127        0x1A, 0x03, 0x6E, 0xCF, 0xE7, 0x09, 0xFC, 0x05,
 128        0x24, 0x01, 0xE7, 0x09, 0x02, 0x06, 0x26, 0x01,
 129        0xE7, 0x07, 0x07, 0x00, 0x92, 0xC0, 0xE7, 0x09,
 130        0xFC, 0x05, 0xFE, 0x05, 0xE7, 0x09, 0x02, 0x06,
 131        0x04, 0x06, 0xE7, 0x09, 0x00, 0x06, 0xFC, 0x05,
 132        0xE7, 0x09, 0xFE, 0x05, 0x00, 0x06, 0x27, 0xDA,
 133        0xFA, 0x05, 0xE7, 0x57, 0x01, 0x00, 0xFA, 0x05,
 134        0x02, 0xCA, 0x04, 0xC0, 0x97, 0xCF, 0x9F, 0xAF,
 135        0x66, 0x05, 0x97, 0xCF, 0xE7, 0x07, 0x40, 0x00,
 136        0x02, 0x06, 0xC8, 0x09, 0xFC, 0x05, 0x9F, 0xAF,
 137        0xDA, 0x02, 0x97, 0xCF, 0xCF, 0x17, 0x02, 0x00,
 138        0xEF, 0x57, 0x81, 0x00, 0x09, 0x06, 0x9F, 0xA0,
 139        0xB6, 0x01, 0xEF, 0x57, 0x80, 0x00, 0x09, 0x06,
 140        0x9F, 0xA0, 0x40, 0x02, 0xEF, 0x57, 0x01, 0x00,
 141        0x0B, 0x06, 0x9F, 0xA0, 0x46, 0x03, 0xE7, 0x07,
 142        0x01, 0x00, 0x0A, 0xC0, 0x46, 0xAF, 0x47, 0xAF,
 143        0x9F, 0xAF, 0x40, 0x02, 0xE7, 0x07, 0x2E, 0x00,
 144        0x0A, 0xC0, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06,
 145        0x97, 0xCF, 0x00, 0x0E, 0x01, 0x00, 0xC0, 0x57,
 146        0x51, 0x00, 0x9F, 0xC0, 0x9E, 0x02, 0xC0, 0x57,
 147        0x50, 0x00, 0x20, 0xC0, 0xC0, 0x57, 0x55, 0x00,
 148        0x12, 0xC0, 0xC0, 0x57, 0x56, 0x00, 0x9F, 0xC0,
 149        0x72, 0x02, 0x9F, 0xCF, 0xD6, 0x02, 0xC1, 0x0B,
 150        0x08, 0x06, 0x01, 0xD0, 0x6F, 0x90, 0x08, 0x06,
 151        0xC0, 0x07, 0x08, 0x00, 0xC1, 0x0B, 0x08, 0x06,
 152        0x9F, 0xAF, 0x28, 0x05, 0x97, 0xCF, 0x2F, 0x0E,
 153        0x02, 0x00, 0x08, 0x06, 0xC0, 0x07, 0x08, 0x00,
 154        0xC1, 0x0B, 0x08, 0x06, 0x9F, 0xAF, 0x28, 0x05,
 155        0x9F, 0xCF, 0xD6, 0x02, 0x2F, 0x0E, 0x02, 0x00,
 156        0x09, 0x06, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06,
 157        0x9F, 0xCF, 0xD6, 0x02, 0xEF, 0x67, 0x7F, 0xFF,
 158        0x09, 0x06, 0xE7, 0x67, 0xFF, 0xFD, 0x22, 0xC0,
 159        0xE7, 0x67, 0xEF, 0xFF, 0x24, 0xC0, 0xE7, 0x87,
 160        0x10, 0x00, 0x28, 0xC0, 0x9F, 0xAF, 0xB8, 0x05,
 161        0xE7, 0x87, 0xE0, 0x21, 0x24, 0xC0, 0x9F, 0xAF,
 162        0xA8, 0x05, 0xE7, 0x87, 0x08, 0x00, 0x24, 0xC0,
 163        0xE7, 0x67, 0xDF, 0xFF, 0x24, 0xC0, 0xC8, 0x07,
 164        0x0A, 0x00, 0xC0, 0x07, 0x00, 0x00, 0xC1, 0x07,
 165        0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0x9F, 0xAF,
 166        0xB8, 0x05, 0xC0, 0x07, 0x9E, 0x00, 0x9F, 0xAF,
 167        0x44, 0x05, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
 168        0xC0, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01,
 169        0x24, 0xC0, 0xC0, 0x77, 0x00, 0x02, 0x0F, 0xC1,
 170        0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x67,
 171        0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x08, 0x00,
 172        0x24, 0xC0, 0x08, 0xDA, 0x5E, 0xC1, 0xEF, 0x07,
 173        0x80, 0x00, 0x09, 0x06, 0x97, 0xCF, 0xEF, 0x07,
 174        0x01, 0x00, 0x0A, 0x06, 0x97, 0xCF, 0xEF, 0x07,
 175        0x00, 0x00, 0x0B, 0x06, 0xEF, 0x07, 0x00, 0x00,
 176        0x0A, 0x06, 0xEF, 0x67, 0x7F, 0xFF, 0x09, 0x06,
 177        0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06, 0xE7, 0x67,
 178        0xEF, 0xFF, 0x28, 0xC0, 0xE7, 0x67, 0x17, 0xD8,
 179        0x24, 0xC0, 0xE7, 0x07, 0x00, 0x00, 0x1E, 0xC0,
 180        0xE7, 0x07, 0xFF, 0xFF, 0x22, 0xC0, 0x97, 0xCF,
 181        0xC8, 0x07, 0x0E, 0x06, 0x9F, 0xAF, 0xDA, 0x02,
 182        0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07,
 183        0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0x0E, 0x06,
 184        0xF4, 0x05, 0xE7, 0x07, 0xD6, 0x02, 0xF8, 0x05,
 185        0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80,
 186        0x50, 0xAF, 0x97, 0xCF, 0x2F, 0x0C, 0x02, 0x00,
 187        0x07, 0x06, 0x2F, 0x0C, 0x04, 0x00, 0x06, 0x06,
 188        0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07,
 189        0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0xE2, 0x05,
 190        0xF4, 0x05, 0xE7, 0x07, 0xCE, 0x02, 0xF8, 0x05,
 191        0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80,
 192        0x51, 0xAF, 0x97, 0xCF, 0x9F, 0xAF, 0x66, 0x04,
 193        0x9F, 0xAF, 0x1A, 0x03, 0x59, 0xAF, 0x97, 0xCF,
 194        0xC0, 0x07, 0x0E, 0x00, 0xC1, 0x0B, 0x0C, 0x06,
 195        0x41, 0xD1, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
 196        0x3C, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0x68, 0x00,
 197        0xC0, 0x07, 0x3B, 0x00, 0x9F, 0xAF, 0x44, 0x05,
 198        0x6F, 0x00, 0x0C, 0x06, 0x68, 0x00, 0xE0, 0x07,
 199        0x04, 0x01, 0xE8, 0x0B, 0x0A, 0x06, 0xE8, 0x07,
 200        0x00, 0x00, 0xE0, 0x07, 0x00, 0x02, 0xE0, 0x07,
 201        0xEC, 0x01, 0xE0, 0x07, 0xFC, 0xFF, 0x97, 0xCF,
 202        0xE7, 0x07, 0xFF, 0xFF, 0xFA, 0x05, 0xEF, 0x07,
 203        0x00, 0x00, 0x0B, 0x06, 0xE7, 0x07, 0x0E, 0x06,
 204        0x24, 0x01, 0xE7, 0x07, 0x0E, 0x06, 0xFE, 0x05,
 205        0xE7, 0x07, 0x40, 0x00, 0x26, 0x01, 0xE7, 0x07,
 206        0x40, 0x00, 0x04, 0x06, 0xE7, 0x07, 0x07, 0x00,
 207        0x92, 0xC0, 0x97, 0xCF, 0xEF, 0x07, 0x02, 0x00,
 208        0x0B, 0x06, 0x9F, 0xAF, 0x78, 0x01, 0xEF, 0x77,
 209        0x80, 0x00, 0x07, 0x06, 0x9F, 0xC0, 0x14, 0x04,
 210        0xEF, 0x77, 0x01, 0x00, 0x07, 0x06, 0x37, 0xC0,
 211        0xEF, 0x77, 0x01, 0x00, 0x0D, 0x06, 0x0F, 0xC1,
 212        0xEF, 0x07, 0x01, 0x00, 0x0D, 0x06, 0xC0, 0x07,
 213        0x02, 0x00, 0xC1, 0x07, 0x30, 0x00, 0x9F, 0xAF,
 214        0x28, 0x05, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07,
 215        0x02, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07,
 216        0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07,
 217        0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x77,
 218        0x03, 0x00, 0x02, 0xC1, 0x08, 0xDA, 0x75, 0xC1,
 219        0xC1, 0x77, 0x01, 0x00, 0x0A, 0xC1, 0xC0, 0x07,
 220        0x01, 0x00, 0xC1, 0x07, 0x02, 0x00, 0x9F, 0xAF,
 221        0x28, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x06, 0x06,
 222        0x2C, 0xCF, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07,
 223        0x04, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xEF, 0x07,
 224        0x00, 0x00, 0x06, 0x06, 0x22, 0xCF, 0xEF, 0x07,
 225        0x00, 0x00, 0x0D, 0x06, 0xEF, 0x57, 0x01, 0x00,
 226        0x06, 0x06, 0x1B, 0xC0, 0xC0, 0x07, 0x01, 0x00,
 227        0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05,
 228        0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00,
 229        0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07, 0xFF, 0x4F,
 230        0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07, 0x38, 0x00,
 231        0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x67, 0x03, 0x00,
 232        0xC1, 0x57, 0x03, 0x00, 0x02, 0xC0, 0x08, 0xDA,
 233        0x73, 0xC1, 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07,
 234        0x12, 0x00, 0xEF, 0x57, 0x00, 0x00, 0x06, 0x06,
 235        0x02, 0xC0, 0xC1, 0x07, 0x23, 0x00, 0x9F, 0xAF,
 236        0x28, 0x05, 0xC0, 0x07, 0x14, 0x00, 0xC1, 0x0B,
 237        0xEA, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
 238        0x3E, 0x00, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x09,
 239        0xE4, 0x05, 0xFA, 0x05, 0x27, 0xD8, 0xFA, 0x05,
 240        0xE7, 0x07, 0x0E, 0x06, 0xFC, 0x05, 0xE7, 0x07,
 241        0x4E, 0x06, 0x00, 0x06, 0xE7, 0x07, 0x40, 0x00,
 242        0x02, 0x06, 0x9F, 0xAF, 0x66, 0x05, 0x9F, 0xAF,
 243        0xC6, 0x00, 0x97, 0xCF, 0xC1, 0x0B, 0xE2, 0x05,
 244        0x41, 0xD0, 0x01, 0xD2, 0xC1, 0x17, 0x23, 0x00,
 245        0x9F, 0xAF, 0xDC, 0x04, 0xC0, 0x07, 0x04, 0x00,
 246        0xC1, 0x0B, 0xE3, 0x05, 0x9F, 0xAF, 0x28, 0x05,
 247        0xC0, 0x07, 0x06, 0x00, 0xC1, 0x09, 0xE6, 0x05,
 248        0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x07, 0x00,
 249        0xC1, 0x09, 0xE6, 0x05, 0xC1, 0xD1, 0x9F, 0xAF,
 250        0x28, 0x05, 0xC0, 0x07, 0x0B, 0x00, 0xC1, 0x09,
 251        0xE8, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
 252        0x0C, 0x00, 0xC1, 0x09, 0xE8, 0x05, 0xC1, 0xD1,
 253        0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0D, 0x00,
 254        0xC1, 0x07, 0x09, 0x00, 0x9F, 0xAF, 0x28, 0x05,
 255        0xC0, 0x07, 0x03, 0x00, 0xC1, 0x07, 0x32, 0x00,
 256        0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0F, 0x00,
 257        0xC1, 0x07, 0x00, 0x00, 0x9F, 0xAF, 0x28, 0x05,
 258        0x97, 0xCF, 0xE7, 0x67, 0xFF, 0xD9, 0x24, 0xC0,
 259        0xC8, 0x07, 0x0A, 0x00, 0x40, 0x00, 0xC0, 0x67,
 260        0x00, 0x02, 0x27, 0x80, 0x24, 0xC0, 0xE7, 0x87,
 261        0x00, 0x04, 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xF9,
 262        0x24, 0xC0, 0x01, 0xD2, 0x08, 0xDA, 0x72, 0xC1,
 263        0xE7, 0x87, 0x00, 0x20, 0x24, 0xC0, 0x97, 0xCF,
 264        0x27, 0x00, 0x1E, 0xC0, 0xE7, 0x87, 0xFF, 0x00,
 265        0x22, 0xC0, 0xE7, 0x67, 0x7F, 0xFF, 0x24, 0xC0,
 266        0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0, 0xE7, 0x87,
 267        0x80, 0x00, 0x24, 0xC0, 0x97, 0xCF, 0x9F, 0xAF,
 268        0x0A, 0x05, 0x67, 0x00, 0x1E, 0xC0, 0xE7, 0x67,
 269        0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00,
 270        0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
 271        0x97, 0xCF, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x67,
 272        0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE,
 273        0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
 274        0xC1, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01,
 275        0x24, 0xC0, 0x97, 0xCF, 0xC0, 0x07, 0x40, 0x00,
 276        0xC8, 0x09, 0xFC, 0x05, 0xE7, 0x67, 0x00, 0xFF,
 277        0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
 278        0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x67,
 279        0xBF, 0xFF, 0x24, 0xC0, 0x00, 0xDA, 0xE8, 0x09,
 280        0x20, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
 281        0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, 0x00, 0xDA,
 282        0xE8, 0x09, 0x20, 0xC0, 0x6D, 0xC1, 0xE7, 0x87,
 283        0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF, 0xE7, 0x07,
 284        0x32, 0x00, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80,
 285        0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0xE7, 0x07,
 286        0x20, 0x4E, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80,
 287        0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0x09, 0x02,
 288        0x19, 0x00, 0x01, 0x01, 0x00, 0x80, 0x96, 0x09,
 289        0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
 290        0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x00,
 291        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 292        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 293        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 294        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 295        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 296        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 297        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 298        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 299        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 300        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 301        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 302        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 303        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 304        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 305        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 306        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 307        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 308        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 309        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 310        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 311        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 312        0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 313};
 314
 315static unsigned char setup5[] = {
 316        0xB6, 0xC3, 0x2F, 0x01, 0x03, 0x64, 0x0E, 0x00,
 317        0x14, 0x00, 0x1A, 0x00, 0x20, 0x00, 0x26, 0x00,
 318        0x4A, 0x00, 0x64, 0x00, 0x6A, 0x00, 0x92, 0x00,
 319        0x9A, 0x00, 0xA0, 0x00, 0xB2, 0x00, 0xB8, 0x00,
 320        0xBE, 0x00, 0xC2, 0x00, 0xC8, 0x00, 0xCE, 0x00,
 321        0xDC, 0x00, 0xDA, 0x00, 0xE2, 0x00, 0xE0, 0x00,
 322        0xE8, 0x00, 0xE6, 0x00, 0xEE, 0x00, 0xEC, 0x00,
 323        0xF2, 0x00, 0xF8, 0x00, 0x02, 0x01, 0x0A, 0x01,
 324        0x0E, 0x01, 0x12, 0x01, 0x1E, 0x01, 0x22, 0x01,
 325        0x28, 0x01, 0x2C, 0x01, 0x32, 0x01, 0x36, 0x01,
 326        0x44, 0x01, 0x50, 0x01, 0x5E, 0x01, 0x72, 0x01,
 327        0x76, 0x01, 0x7A, 0x01, 0x80, 0x01, 0x88, 0x01,
 328        0x8C, 0x01, 0x94, 0x01, 0x9C, 0x01, 0xA0, 0x01,
 329        0xA4, 0x01, 0xAA, 0x01, 0xB0, 0x01, 0xB4, 0x01,
 330        0xBA, 0x01, 0xD0, 0x01, 0xDA, 0x01, 0xF6, 0x01,
 331        0xFA, 0x01, 0x02, 0x02, 0x34, 0x02, 0x3C, 0x02,
 332        0x44, 0x02, 0x4A, 0x02, 0x50, 0x02, 0x56, 0x02,
 333        0x74, 0x02, 0x78, 0x02, 0x7E, 0x02, 0x84, 0x02,
 334        0x8A, 0x02, 0x88, 0x02, 0x90, 0x02, 0x8E, 0x02,
 335        0x94, 0x02, 0xA2, 0x02, 0xA8, 0x02, 0xAE, 0x02,
 336        0xB4, 0x02, 0xBA, 0x02, 0xB8, 0x02, 0xC0, 0x02,
 337        0xBE, 0x02, 0xC4, 0x02, 0xD0, 0x02, 0xD4, 0x02,
 338        0xE0, 0x02, 0xE6, 0x02, 0xEE, 0x02, 0xF8, 0x02,
 339        0xFC, 0x02, 0x06, 0x03, 0x1E, 0x03, 0x24, 0x03,
 340        0x28, 0x03, 0x30, 0x03, 0x2E, 0x03, 0x3C, 0x03,
 341        0x4A, 0x03, 0x4E, 0x03, 0x54, 0x03, 0x58, 0x03,
 342        0x5E, 0x03, 0x66, 0x03, 0x6E, 0x03, 0x7A, 0x03,
 343        0x86, 0x03, 0x8E, 0x03, 0x96, 0x03, 0xB2, 0x03,
 344        0xB8, 0x03, 0xC6, 0x03, 0xCC, 0x03, 0xD4, 0x03,
 345        0xDA, 0x03, 0xE8, 0x03, 0xF4, 0x03, 0xFC, 0x03,
 346        0x04, 0x04, 0x20, 0x04, 0x2A, 0x04, 0x32, 0x04,
 347        0x36, 0x04, 0x3E, 0x04, 0x44, 0x04, 0x42, 0x04,
 348        0x48, 0x04, 0x4E, 0x04, 0x4C, 0x04, 0x54, 0x04,
 349        0x52, 0x04, 0x5A, 0x04, 0x5E, 0x04, 0x62, 0x04,
 350        0x68, 0x04, 0x74, 0x04, 0x7C, 0x04, 0x80, 0x04,
 351        0x88, 0x04, 0x8C, 0x04, 0x94, 0x04, 0x9A, 0x04,
 352        0xA2, 0x04, 0xA6, 0x04, 0xAE, 0x04, 0xB4, 0x04,
 353        0xC0, 0x04, 0xCC, 0x04, 0xD8, 0x04, 0x2A, 0x05,
 354        0x46, 0x05, 0x6C, 0x05, 0x00, 0x00
 355};
 356
 357struct vicam_camera {
 358        u16 shutter_speed;      // capture shutter speed
 359        u16 gain;               // capture gain
 360
 361        u8 *raw_image;          // raw data captured from the camera
 362        u8 *framebuf;           // processed data in RGB24 format
 363
 364        struct video_device vdev;       // v4l video device
 365        struct usb_device *udev;        // usb device
 366
 367        struct semaphore busy_lock;     // guard against SMP multithreading
 368
 369        bool is_initialized;
 370        bool is_removed;
 371        bool is_opened;
 372        u8 bulkEndpoint;
 373        bool needsDummyRead;
 374
 375        u32 framebuf_size;      // # of valid bytes in framebuf
 376        u32 framebuf_read_start;        // position in frame buf that a read is happening at.
 377
 378#ifdef CONFIG_PROC_FS
 379        struct proc_dir_entry *proc_entry;
 380#endif
 381
 382};
 383
 384static void *vicam_probe(struct usb_device *dev, unsigned int ifnum,
 385                               const struct usb_device_id *id);
 386static void vicam_disconnect(struct usb_device *dev, void *ptr);
 387static void read_frame(struct vicam_camera *cam, int framenum);
 388static void vicam_purge(struct vicam_camera *cam);
 389
 390static int
 391send_control_msg(struct usb_device *udev, u8 request, u16 value, u16 index,
 392                 unsigned char *cp, u16 size)
 393{
 394        int status;
 395
 396        // for reasons not yet known to me, you can't send USB control messages
 397        // with data in the module (if you are compiled as a module).  Whatever
 398        // the reason, copying it to memory allocated as kernel memory then
 399        // doing the usb control message fixes the problem.
 400
 401        unsigned char *transfer_buffer = kmalloc(size, GFP_KERNEL);
 402        memcpy(transfer_buffer, cp, size);
 403
 404        status = usb_control_msg(udev,
 405                                 usb_sndctrlpipe(udev, 0),
 406                                 request,
 407                                 USB_DIR_OUT | USB_TYPE_VENDOR |
 408                                 USB_RECIP_DEVICE, value, index,
 409                                 transfer_buffer, size, HZ);
 410
 411        kfree(transfer_buffer);
 412
 413        if (status < 0) {
 414                printk(KERN_INFO "Failed sending control message, error %d.\n",
 415                       status);
 416        }
 417
 418        return status;
 419}
 420
 421static int
 422initialize_camera(struct vicam_camera *cam)
 423{
 424        struct usb_device *udev = cam->udev;
 425        int status;
 426
 427        if ((status =
 428             send_control_msg(udev, 0xff, 0, 0, setup1, sizeof (setup1))) < 0)
 429                return status;
 430        if ((status =
 431             send_control_msg(udev, 0xff, 0, 0, setup2, sizeof (setup2))) < 0)
 432                return status;
 433        if ((status =
 434             send_control_msg(udev, 0xff, 0, 0, setup3, sizeof (setup3))) < 0)
 435                return status;
 436        if ((status =
 437             send_control_msg(udev, 0xff, 0, 0, setup4, sizeof (setup4))) < 0)
 438                return status;
 439        if ((status =
 440             send_control_msg(udev, 0xff, 0, 0, setup5, sizeof (setup5))) < 0)
 441                return status;
 442        if ((status =
 443             send_control_msg(udev, 0xff, 0, 0, setup3, sizeof (setup3))) < 0)
 444                return status;
 445
 446        return 0;
 447}
 448
 449static int
 450set_camera_power(struct vicam_camera *cam, int state)
 451{
 452        int status;
 453
 454        if ((status = send_control_msg(cam->udev, 0x50, state, 0, NULL, 0)) < 0)
 455                return status;
 456
 457        if (state) {
 458                send_control_msg(cam->udev, 0x55, 1, 0, NULL, 0);
 459        }
 460
 461        return 0;
 462}
 463
 464static int
 465vicam_ioctl(struct video_device *dev, unsigned int ioctlnr, void *arg)
 466{
 467        struct vicam_camera *cam = dev->priv;
 468        int retval = 0;
 469
 470        if (!cam)
 471                return -ENODEV;
 472
 473        /* make this _really_ smp-safe */
 474        if (down_interruptible(&cam->busy_lock))
 475                return -EINTR;
 476
 477        switch (ioctlnr) {
 478                /* query capabilites */
 479        case VIDIOCGCAP:
 480                {
 481                        struct video_capability b;
 482
 483                        DBG("VIDIOCGCAP\n");
 484                        strcpy(b.name, "ViCam-based Camera");
 485                        b.type = VID_TYPE_CAPTURE;
 486                        b.channels = 1;
 487                        b.audios = 0;
 488                        b.maxwidth = 320;       /* VIDEOSIZE_CIF */
 489                        b.maxheight = 240;
 490                        b.minwidth = 320;       /* VIDEOSIZE_48_48 */
 491                        b.minheight = 240;
 492
 493                        if (copy_to_user(arg, &b, sizeof (b)))
 494                                retval = -EFAULT;
 495
 496                        break;
 497                }
 498                /* get/set video source - we are a camera and nothing else */
 499        case VIDIOCGCHAN:
 500                {
 501                        struct video_channel v;
 502
 503                        DBG("VIDIOCGCHAN\n");
 504                        if (copy_from_user(&v, arg, sizeof (v))) {
 505                                retval = -EFAULT;
 506                                break;
 507                        }
 508                        if (v.channel != 0) {
 509                                retval = -EINVAL;
 510                                break;
 511                        }
 512
 513                        v.channel = 0;
 514                        strcpy(v.name, "Camera");
 515                        v.tuners = 0;
 516                        v.flags = 0;
 517                        v.type = VIDEO_TYPE_CAMERA;
 518                        v.norm = 0;
 519
 520                        if (copy_to_user(arg, &v, sizeof (v)))
 521                                retval = -EFAULT;
 522                        break;
 523                }
 524
 525        case VIDIOCSCHAN:
 526                {
 527                        int v;
 528
 529                        if (copy_from_user(&v, arg, sizeof (v)))
 530                                retval = -EFAULT;
 531                        DBG("VIDIOCSCHAN %d\n", v);
 532
 533                        if (retval == 0 && v != 0)
 534                                retval = -EINVAL;
 535
 536                        break;
 537                }
 538
 539                /* image properties */
 540        case VIDIOCGPICT:
 541                {
 542                        struct video_picture vp;
 543                        DBG("VIDIOCGPICT\n");
 544                        memset(&vp, 0, sizeof (struct video_picture));
 545                        vp.brightness = cam->gain << 8;
 546                        vp.depth = 24;
 547                        vp.palette = VIDEO_PALETTE_RGB24;
 548                        if (copy_to_user
 549                            (arg, &vp, sizeof (struct video_picture)))
 550                                retval = -EFAULT;
 551                        break;
 552                }
 553
 554        case VIDIOCSPICT:
 555                {
 556                        struct video_picture vp;
 557                        
 558                        if(copy_from_user(&vp, (struct video_picture *) arg,
 559                                sizeof(struct video_picture)))
 560                                retval = -EFAULT;
 561
 562                        else
 563                        {
 564                                DBG("VIDIOCSPICT depth = %d, pal = %d\n", vp.depth,
 565                                    vp.palette);
 566
 567                                cam->gain = vp.brightness >> 8;
 568
 569                                if (vp.depth != 24
 570                                    || vp.palette != VIDEO_PALETTE_RGB24)
 571                                        retval = -EINVAL;
 572                        }
 573
 574                        break;
 575                }
 576
 577                /* get/set capture window */
 578        case VIDIOCGWIN:
 579                {
 580                        struct video_window vw;
 581                        vw.x = 0;
 582                        vw.y = 0;
 583                        vw.width = 320;
 584                        vw.height = 240;
 585                        vw.chromakey = 0;
 586                        vw.flags = 0;
 587                        vw.clips = NULL;
 588                        vw.clipcount = 0;
 589
 590                        DBG("VIDIOCGWIN\n");
 591
 592                        if (copy_to_user
 593                            ((void *) arg, (void *) &vw, sizeof (vw)))
 594                                retval = -EFAULT;
 595
 596                        // I'm not sure what the deal with a capture window is, it is very poorly described
 597                        // in the doc.  So I won't support it now.
 598                        break;
 599                }
 600
 601        case VIDIOCSWIN:
 602                {
 603
 604                        struct video_window vw;
 605
 606                        if (copy_from_user(&vw, arg, sizeof(vw)))
 607                        {
 608                                retval = -EFAULT;
 609                                break;
 610                        }
 611
 612                        DBG("VIDIOCSWIN %d x %d\n", vw->width, vw->height);
 613                        
 614                        if ( vw.width != 320 || vw.height != 240 )
 615                                retval = -EFAULT;
 616
 617                        break;
 618                }
 619
 620                /* mmap interface */
 621        case VIDIOCGMBUF:
 622                {
 623                        struct video_mbuf vm;
 624                        int i;
 625
 626                        DBG("VIDIOCGMBUF\n");
 627                        memset(&vm, 0, sizeof (vm));
 628                        vm.size =
 629                            VICAM_MAX_FRAME_SIZE * VICAM_FRAMES;
 630                        vm.frames = VICAM_FRAMES;
 631                        for (i = 0; i < VICAM_FRAMES; i++)
 632                                vm.offsets[i] = VICAM_MAX_FRAME_SIZE * i;
 633
 634                        if (copy_to_user
 635                            ((void *) arg, (void *) &vm, sizeof (vm)))
 636                                retval = -EFAULT;
 637
 638                        break;
 639                }
 640
 641        case VIDIOCMCAPTURE:
 642                {
 643                        struct video_mmap vm;
 644                        // int video_size;
 645
 646                        if (copy_from_user
 647                            ((void *) &vm, (void *) arg, sizeof (vm))) {
 648                                retval = -EFAULT;
 649                                break;
 650                        }
 651
 652                        DBG("VIDIOCMCAPTURE frame=%d, height=%d, width=%d, format=%d.\n",vm.frame,vm.width,vm.height,vm.format);
 653
 654                        if ( vm.frame >= VICAM_FRAMES || vm.format != VIDEO_PALETTE_RGB24 )
 655                                retval = -EINVAL;
 656
 657                        // in theory right here we'd start the image capturing
 658                        // (fill in a bulk urb and submit it asynchronously)
 659                        //
 660                        // Instead we're going to do a total hack job for now and
 661                        // retrieve the frame in VIDIOCSYNC
 662
 663                        break;
 664                }
 665
 666        case VIDIOCSYNC:
 667                {
 668                        int frame;
 669
 670                        if (copy_from_user((void *) &frame, arg, sizeof (int))) {
 671                                retval = -EFAULT;
 672                                break;
 673                        }
 674                        DBG("VIDIOCSYNC: %d\n", frame);
 675
 676                        read_frame(cam, frame);
 677
 678                        break;
 679                }
 680
 681                /* pointless to implement overlay with this camera */
 682        case VIDIOCCAPTURE:
 683        case VIDIOCGFBUF:
 684        case VIDIOCSFBUF:
 685        case VIDIOCKEY:
 686                retval = -EINVAL;
 687                break;
 688
 689                /* tuner interface - we have none */
 690        case VIDIOCGTUNER:
 691        case VIDIOCSTUNER:
 692        case VIDIOCGFREQ:
 693        case VIDIOCSFREQ:
 694                retval = -EINVAL;
 695                break;
 696
 697                /* audio interface - we have none */
 698        case VIDIOCGAUDIO:
 699        case VIDIOCSAUDIO:
 700                retval = -EINVAL;
 701                break;
 702        default:
 703                retval = -ENOIOCTLCMD;
 704                break;
 705        }
 706
 707        up(&cam->busy_lock);
 708        return retval;
 709}
 710
 711static int
 712vicam_open(struct video_device *dev, int flags)
 713{
 714        struct vicam_camera *cam =
 715            (struct vicam_camera *) dev->priv;
 716        int intr;
 717        DBG("open\n");
 718
 719        if (!cam) {
 720                printk(KERN_ERR
 721                       "vicam video_device improperly initialized");
 722        }
 723
 724        intr = down_interruptible(&cam->busy_lock);
 725        if (intr)
 726                return -EINTR;
 727
 728        if (cam->is_opened) {
 729                printk(KERN_INFO
 730                       "vicam_open called on already opened camera");
 731                up(&cam->busy_lock);
 732                return -EBUSY;
 733        }
 734
 735        if (!cam->raw_image) {
 736                cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL);
 737                if (!cam->raw_image) {
 738                        up(&cam->busy_lock);
 739                        return -ENOMEM;
 740                }
 741        }
 742
 743        if (!cam->framebuf) {
 744                cam->framebuf =
 745                    usbvideo_rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
 746                if (!cam->framebuf) {
 747                        kfree(cam->raw_image);
 748                        up(&cam->busy_lock);
 749                        return -ENOMEM;
 750                }
 751        }
 752        // First upload firmware, then turn the camera on
 753
 754        if (!cam->is_initialized) {
 755                initialize_camera(cam);
 756
 757                cam->is_initialized = 1;
 758        }
 759
 760        set_camera_power(cam, 1);
 761
 762        cam->needsDummyRead = 1;
 763        cam->is_opened = 1;
 764
 765        up(&cam->busy_lock);
 766
 767        return 0;
 768}
 769
 770static void
 771vicam_close(struct video_device *dev)
 772{
 773        struct vicam_camera *cam = (struct vicam_camera *) dev->priv;
 774        DBG("close\n");
 775
 776
 777        if (cam->is_removed) {
 778                vicam_purge(cam);
 779        } else {
 780                set_camera_power(cam, 0);
 781                cam->is_opened = 0;
 782        }
 783}
 784
 785inline int pin(int x)
 786{
 787        return((x > 255) ? 255 : ((x < 0) ? 0 : x));
 788}
 789
 790inline void writepixel(char *rgb, int Y, int Cr, int Cb)
 791{
 792        Y = 1160 * (Y - 16);
 793
 794        rgb[2] = pin( ( ( Y + ( 1594 * Cr ) ) + 500 ) / 1300 );
 795        rgb[1] = pin( ( ( Y - (  392 * Cb ) - ( 813 * Cr ) ) + 500 ) / 1000 );
 796        rgb[0] = pin( ( ( Y + ( 2017 * Cb ) ) + 500 ) / 900 );
 797}
 798
 799#define DATA_HEADER_SIZE 64
 800
 801// --------------------------------------------------------------------------------
 802//      vicam_decode_color - Convert from Vicam Y-Cr-Cb to RGB
 803//
 804//   Copyright (C) 2002 Monroe Williams (monroe@pobox.com)
 805// --------------------------------------------------------------------------------
 806
 807void vicam_decode_color( char *data, char *rgb)
 808{
 809        int x,y;
 810        int Cr, Cb;
 811        int sign;
 812        int prevX, nextX, prevY, nextY;
 813        int skip;
 814        unsigned char *src;
 815        unsigned char *dst;
 816
 817        prevY = 512;
 818        nextY = 512;
 819
 820        src = data + DATA_HEADER_SIZE;
 821        dst = rgb;
 822
 823        for(y = 1; y < 241; y += 2)
 824        {
 825                // even line
 826                sign = 1;
 827                prevX = 1;
 828                nextX = 1;
 829
 830                skip = 0;
 831
 832                dst = rgb + (y-1)*320*3;
 833                
 834                for(x = 0; x < 512; x++)
 835                {
 836                        if(x == 512-1)
 837                                nextX = -1;
 838
 839                        Cr = sign * ((src[prevX] - src[0]) + (src[nextX] - src[0])) >> 1;
 840                        Cb = sign * ((src[prevY] - src[prevX + prevY]) + (src[prevY] - src[nextX + prevY]) + (src[nextY] - src[prevX + nextY]) + (src[nextY] - src[nextX + nextY])) >> 2;
 841
 842                        writepixel(
 843                                        dst + ((x*5)>>3)*3,
 844                                        src[0] + (sign * (Cr >> 1)),
 845                                        Cr,
 846                                        Cb);
 847
 848                        src++;
 849                        sign *= -1;
 850                        prevX = -1;
 851                }
 852
 853                prevY = -512;
 854
 855                if(y == (242 - 2))
 856                        nextY = -512;
 857
 858                // odd line
 859                sign = 1;
 860                prevX = 1;
 861                nextX = 1;
 862
 863                skip = 0;
 864
 865                dst = rgb + (y)*320*3;
 866                
 867                for(x = 0; x < 512; x++)
 868                {
 869                        if(x == 512-1)
 870                                nextX = -1;
 871                        
 872                        Cr = sign * ((src[prevX + prevY] - src[prevY]) + (src[nextX + prevY] - src[prevY]) + (src[prevX + nextY] - src[nextY]) + (src[nextX + nextY] - src[nextY])) >> 2;
 873                        Cb = sign * ((src[0] - src[prevX]) + (src[0] - src[nextX])) >> 1;
 874
 875                        writepixel(
 876                                        dst + ((x * 5)>>3)*3,
 877                                        src[0] - (sign * (Cb >> 1)),
 878                                        Cr,
 879                                        Cb);
 880
 881                        src++;
 882                        sign *= -1;
 883                        prevX = -1;
 884                }
 885        }
 886}
 887
 888static void
 889read_frame(struct vicam_camera *cam, int framenum)
 890{
 891        unsigned char request[16];
 892        int realShutter;
 893        int n;
 894        int actual_length;
 895
 896        memset(request, 0, 16);
 897        request[0] = cam->gain; // 0 = 0% gain, FF = 100% gain
 898
 899        request[1] = 0; // 512x242 capture
 900
 901        request[2] = 0x90;      // the function of these two bytes
 902        request[3] = 0x07;      // is not yet understood
 903
 904        if (cam->shutter_speed > 60) {
 905                // Short exposure
 906                realShutter =
 907                    ((-15631900 / cam->shutter_speed) + 260533) / 1000;
 908                request[4] = realShutter & 0xFF;
 909                request[5] = (realShutter >> 8) & 0xFF;
 910                request[6] = 0x03;
 911                request[7] = 0x01;
 912        } else {
 913                // Long exposure
 914                realShutter = 15600 / cam->shutter_speed - 1;
 915                request[4] = 0;
 916                request[5] = 0;
 917                request[6] = realShutter & 0xFF;
 918                request[7] = realShutter >> 8;
 919        }
 920
 921        // Per John Markus Bjørndalen, byte at index 8 causes problems if it isn't 0
 922        request[8] = 0;
 923        // bytes 9-15 do not seem to affect exposure or image quality
 924
 925        n = send_control_msg(cam->udev, 0x51, 0x80, 0, request, 16);
 926
 927        if (n < 0) {
 928                printk(KERN_ERR
 929                       " Problem sending frame capture control message");
 930                return;
 931        }
 932
 933        n = usb_bulk_msg(cam->udev,
 934                         usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint),
 935                         cam->raw_image,
 936                         512 * 242 + 128, &actual_length, 500);
 937
 938        if (n < 0) {
 939                printk(KERN_ERR "Problem during bulk read of frame data: %d\n",
 940                       n);
 941        }
 942
 943        vicam_decode_color(cam->raw_image,
 944                         cam->framebuf +
 945                         framenum * VICAM_MAX_FRAME_SIZE );
 946
 947        cam->framebuf_size =
 948            320 * 240 * VICAM_BYTES_PER_PIXEL;
 949        cam->framebuf_read_start = 0;
 950
 951        return;
 952
 953}
 954
 955static long
 956vicam_read(struct video_device *dev, char *buf,
 957                 unsigned long count, int noblock)
 958{
 959        struct vicam_camera *cam = dev->priv;
 960        int intr;
 961        DBG("read %d bytes.\n", (int) count);
 962
 963        if (!buf)
 964                return -EINVAL;
 965
 966        if (!count)
 967                return -EINVAL;
 968
 969        // This is some code that will hopefully allow us to do shell copies from
 970        // the /dev/videoX to a file and have it actually work.
 971        if (cam->framebuf_size != 0) {
 972                if (cam->framebuf_read_start == cam->framebuf_size) {
 973                        cam->framebuf_size = cam->framebuf_read_start = 0;
 974                        return 0;
 975                } else {
 976                        if (cam->framebuf_read_start + count <=
 977                            cam->framebuf_size) {
 978                                // count does not exceed available bytes
 979                                if (copy_to_user(buf,
 980                                                 (cam->framebuf) +
 981                                                 cam->framebuf_read_start, count))
 982                                        return -EFAULT;
 983                                cam->framebuf_read_start += count;
 984                                return count;
 985                        } else {
 986                                count =
 987                                    cam->framebuf_size -
 988                                    cam->framebuf_read_start;
 989                                if (copy_to_user(buf,
 990                                                 (cam->framebuf) +
 991                                                 cam->framebuf_read_start, count))
 992                                        return -EFAULT;
 993                                cam->framebuf_read_start = cam->framebuf_size;
 994                                return count;
 995                        }
 996                }
 997        }
 998
 999        intr = down_interruptible(&cam->busy_lock);
1000        if (intr)
1001                return -EINTR;
1002
1003        if (cam->needsDummyRead) {
1004                read_frame(cam, 0);
1005                cam->needsDummyRead = 0;
1006        }
1007        // read_frame twice because the camera doesn't seem to take the shutter speed for the first one.
1008
1009        read_frame(cam, 0);
1010
1011        if (count > cam->framebuf_size)
1012                count = cam->framebuf_size;
1013
1014        if (copy_to_user(buf, cam->framebuf, count)) {
1015                up(&cam->busy_lock);
1016                return -EFAULT;
1017        }
1018
1019        if (count != cam->framebuf_size)
1020                cam->framebuf_read_start = count;
1021        else
1022                cam->framebuf_size = 0;
1023
1024        up(&cam->busy_lock);
1025
1026        return count;
1027}
1028
1029static int
1030vicam_mmap(struct video_device *dev, const char *adr, unsigned long size)
1031{
1032        // TODO: allocate the raw frame buffer if necessary
1033        unsigned long start = (unsigned long) adr;
1034        unsigned long page, pos;
1035        struct vicam_camera *cam = dev->priv;
1036
1037        if (!cam)
1038                return -ENODEV;
1039
1040        DBG("vicam_mmap: %ld\n", size);
1041
1042        /* We let mmap allocate as much as it wants because Linux was adding 2048 bytes
1043         * to the size the application requested for mmap and it was screwing apps up.
1044         if (size > VICAM_FRAMES*VICAM_MAX_FRAME_SIZE)
1045         return -EINVAL;
1046         */
1047
1048        /* make this _really_ smp-safe */
1049        if (down_interruptible(&cam->busy_lock))
1050                return -EINTR;
1051
1052        if (!cam->framebuf) {   /* we do lazy allocation */
1053                cam->framebuf =
1054                    usbvideo_rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
1055                if (!cam->framebuf) {
1056                        up(&cam->busy_lock);
1057                        return -ENOMEM;
1058                }
1059        }
1060
1061        pos = (unsigned long) (cam->framebuf);
1062        while (size > 0) {
1063                page = usbvideo_kvirt_to_pa(pos);
1064                if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) {
1065                        up(&cam->busy_lock);
1066                        return -EAGAIN;
1067                }
1068                start += PAGE_SIZE;
1069                pos += PAGE_SIZE;
1070                if (size > PAGE_SIZE)
1071                        size -= PAGE_SIZE;
1072                else
1073                        size = 0;
1074        }
1075
1076        up(&cam->busy_lock);
1077
1078        return 0;
1079}
1080
1081#ifdef CONFIG_PROC_FS
1082
1083static struct proc_dir_entry *vicam_proc_root = NULL;
1084
1085static int
1086vicam_read_proc(char *page, char **start, off_t off,
1087                      int count, int *eof, void *data)
1088{
1089        char *out = page;
1090        int len;
1091        struct vicam_camera *cam = (struct vicam_camera *) data;
1092
1093        out +=
1094            sprintf(out, "Vicam-based WebCam Linux Driver.\n");
1095        out += sprintf(out, "(c) 2002 Joe Burks (jburks@wavicle.org)\n");
1096        out += sprintf(out, "vicam stats:\n");
1097        out += sprintf(out, "    Shutter Speed: 1/%d\n", cam->shutter_speed);
1098        out += sprintf(out, "             Gain: %d\n", cam->gain);
1099
1100        len = out - page;
1101        len -= off;
1102        if (len < count) {
1103                *eof = 1;
1104                if (len <= 0)
1105                        return 0;
1106        } else
1107                len = count;
1108
1109        *start = page + off;
1110        return len;
1111}
1112
1113static int
1114vicam_write_proc(struct file *file, const char *buffer,
1115                       unsigned long count, void *data)
1116{
1117        char *in;
1118        char *start;
1119        struct vicam_camera *cam = (struct vicam_camera *) data;
1120
1121        in = kmalloc(count + 1, GFP_KERNEL);
1122        if (!in)
1123                return -ENOMEM;
1124
1125        in[count] = 0;          // I'm not sure buffer is gauranteed to be null terminated
1126        // so I do this to make sure I have a null in there.
1127
1128        strncpy(in, buffer, count);
1129
1130        start = strstr(in, "gain=");
1131        if (start
1132            && (start == in || *(start - 1) == ' ' || *(start - 1) == ','))
1133                cam->gain = simple_strtoul(start + 5, NULL, 10);
1134
1135        start = strstr(in, "shutter=");
1136        if (start
1137            && (start == in || *(start - 1) == ' ' || *(start - 1) == ','))
1138                cam->shutter_speed = simple_strtoul(start + 8, NULL, 10);
1139
1140        kfree(in);
1141        return count;
1142}
1143
1144void
1145vicam_create_proc_root(void)
1146{
1147        vicam_proc_root = create_proc_entry("video/vicam", S_IFDIR, 0);
1148
1149        if (vicam_proc_root)
1150                vicam_proc_root->owner = THIS_MODULE;
1151        else
1152                printk(KERN_ERR
1153                       "could not create /proc entry for vicam!");
1154}
1155
1156void
1157vicam_destroy_proc_root(void)
1158{
1159        if (vicam_proc_root)
1160                remove_proc_entry("video/vicam", 0);
1161}
1162
1163void
1164vicam_create_proc_entry(void *ptr)
1165{
1166        struct vicam_camera *cam = (struct vicam_camera *) ptr;
1167
1168        char name[7];
1169        struct proc_dir_entry *ent;
1170
1171        DBG(KERN_INFO "vicam: creating proc entry\n");
1172
1173        if (!vicam_proc_root || !cam) {
1174                printk(KERN_INFO
1175                       "vicam: could not create proc entry, %s pointer is null.\n",
1176                       (!cam ? "camera" : "root"));
1177                return;
1178        }
1179
1180        sprintf(name, "video%d", cam->vdev.minor);
1181
1182        ent =
1183            create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR,
1184                              vicam_proc_root);
1185        if (!ent)
1186                return;
1187
1188        ent->data = cam;
1189        ent->read_proc = vicam_read_proc;
1190        ent->write_proc = vicam_write_proc;
1191        ent->size = 512;
1192        cam->proc_entry = ent;
1193}
1194
1195void
1196vicam_destroy_proc_entry(void *ptr)
1197{
1198        struct vicam_camera *cam = (struct vicam_camera *) ptr;
1199        char name[7];
1200
1201        if (!cam || !cam->proc_entry)
1202                return;
1203
1204        sprintf(name, "video%d", cam->vdev.minor);
1205        remove_proc_entry(name, vicam_proc_root);
1206        cam->proc_entry = NULL;
1207
1208}
1209
1210#endif
1211
1212int
1213vicam_video_init(struct video_device *vdev)
1214{
1215        // This would normally create the proc entry for this camera
1216#ifdef CONFIG_PROC_FS
1217        vicam_create_proc_entry(vdev->priv);
1218#endif
1219        return 0;
1220}
1221
1222static long
1223vicam_write(struct video_device *v, const char *buf, unsigned long count,
1224                  int nonblock)
1225{
1226
1227        return -EINVAL;
1228}
1229
1230static struct video_device vicam_template = {
1231        owner:THIS_MODULE,
1232        name:"ViCam-based USB Camera",
1233        type:VID_TYPE_CAPTURE,
1234        hardware:VID_HARDWARE_VICAM,
1235        open:vicam_open,
1236        close:vicam_close,
1237        read:vicam_read,
1238        write:vicam_write,
1239        ioctl:vicam_ioctl,
1240        mmap:vicam_mmap,
1241        initialize:vicam_video_init,
1242        minor:-1,
1243};
1244
1245/* table of devices that work with this driver */
1246static struct usb_device_id vicam_table[] = {
1247        {USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)},
1248        {}                      /* Terminating entry */
1249};
1250
1251MODULE_DEVICE_TABLE(usb, vicam_table);
1252
1253static struct usb_driver vicam_driver = {
1254        name:"vicam",
1255        probe:vicam_probe,
1256        disconnect:vicam_disconnect,
1257        id_table:vicam_table
1258};
1259
1260/**
1261 *      vicam_probe
1262 *
1263 *      Called by the usb core when a new device is connected that it thinks
1264 *      this driver might be interested in.
1265 */
1266static void *
1267vicam_probe(struct usb_device *dev, unsigned int ifnum,
1268                  const struct usb_device_id *id)
1269{
1270        int nas, bulkEndpoint = 0;
1271        const struct usb_interface_descriptor *interface;
1272        const struct usb_endpoint_descriptor *endpoint;
1273        struct vicam_camera *cam;
1274
1275        /* See if the device offered us matches what we can accept */
1276        if ((dev->descriptor.idVendor != USB_VICAM_VENDOR_ID) ||
1277            (dev->descriptor.idProduct != USB_VICAM_PRODUCT_ID)) {
1278                return NULL;
1279        }
1280
1281        printk(KERN_INFO "ViCam based webcam connected\n");
1282
1283        nas = dev->actconfig->interface[ifnum].num_altsetting;
1284        if (nas != 1) {
1285                printk(KERN_WARNING
1286                       "Expected only one alternate setting for this camera!\n");
1287                return NULL;
1288        }
1289
1290        interface = &dev->actconfig->interface[ifnum].altsetting[0];
1291        DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n",
1292               ifnum, (unsigned) (interface->bNumEndpoints));
1293        endpoint = &interface->endpoint[0];
1294
1295        if ((endpoint->bEndpointAddress & 0x80) &&
1296            ((endpoint->bmAttributes & 3) == 0x02)) {
1297                /* we found a bulk in endpoint */
1298                bulkEndpoint = endpoint->bEndpointAddress;
1299        } else {
1300                printk(KERN_ERR
1301                       "No bulk in endpoint was found ?! (this is bad)\n");
1302        }
1303
1304        if ((cam =
1305             kmalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) {
1306                printk(KERN_WARNING
1307                       "could not allocate kernel memory for vicam_camera struct\n");
1308                return NULL;
1309        }
1310
1311        memset(cam, 0, sizeof (struct vicam_camera));
1312
1313        cam->shutter_speed = 15;
1314
1315        init_MUTEX(&cam->busy_lock);
1316
1317        memcpy(&cam->vdev, &vicam_template,
1318               sizeof (vicam_template));
1319        cam->vdev.priv = cam;   // sort of a reverse mapping for those functions that get vdev only
1320
1321        cam->udev = dev;
1322        cam->bulkEndpoint = bulkEndpoint;
1323
1324        if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) == -1) {
1325                kfree(cam);
1326                printk(KERN_WARNING "video_register_device failed\n");
1327                return NULL;
1328        }
1329
1330        printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor);
1331
1332        return cam;
1333}
1334
1335
1336static void
1337vicam_purge(struct vicam_camera *cam)
1338{
1339        video_unregister_device(&cam->vdev);
1340
1341#ifdef CONFIG_PROC_FS
1342        vicam_destroy_proc_entry(cam);
1343#endif
1344
1345        if (cam->raw_image)
1346                kfree(cam->raw_image);
1347        if (cam->framebuf)
1348                usbvideo_rvfree(cam->framebuf,
1349                       VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
1350
1351        kfree(cam);
1352
1353        printk(KERN_DEBUG "ViCam-based WebCam disconnected\n");
1354}
1355
1356static void
1357vicam_disconnect(struct usb_device *dev, void *ptr)
1358{
1359        struct vicam_camera *cam = ptr;
1360
1361        if (cam->is_opened) {
1362                cam->is_removed = 1;
1363        } else {
1364                vicam_purge(cam);
1365        }
1366}
1367
1368/*
1369 */
1370static int __init
1371usb_vicam_init(void)
1372{
1373        DBG(KERN_INFO "ViCam-based WebCam driver startup\n");
1374#ifdef CONFIG_PROC_FS
1375        vicam_create_proc_root();
1376#endif
1377        if (usb_register(&vicam_driver) != 0)
1378                printk(KERN_WARNING "usb_register failed!\n");
1379        return 0;
1380}
1381
1382static void __exit
1383usb_vicam_exit(void)
1384{
1385        DBG(KERN_INFO
1386               "ViCam-based WebCam driver shutdown\n");
1387
1388        usb_deregister(&vicam_driver);
1389#ifdef CONFIG_PROC_FS
1390        vicam_destroy_proc_root();
1391#endif
1392}
1393
1394module_init(usb_vicam_init);
1395module_exit(usb_vicam_exit);
1396
1397MODULE_AUTHOR(DRIVER_AUTHOR);
1398MODULE_DESCRIPTION(DRIVER_DESC);
1399MODULE_LICENSE("GPL");
1400
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.