Commit f83d142d authored by Joe Burks's avatar Joe Burks Committed by Linus Torvalds

[PATCH] USB: Vicam driver update/rewrite

Updates the vicam driver to the latest version from the sourceforge.net
project.


Binary files linux-2.5.41/drivers/usb/media/.usbvideo.c.swp and
linux-2.5.41-vicam/drivers/usb/media/.usbvideo.c.swp differ
diff -urN linux-2.5.41/drivers/usb/media/Makefile
linux-2.5.41-vicam/drivers/usb/media/Makefile
parent 0c9fd8bb
...@@ -14,6 +14,6 @@ obj-$(CONFIG_USB_OV511) += ov511.o ...@@ -14,6 +14,6 @@ obj-$(CONFIG_USB_OV511) += ov511.o
obj-$(CONFIG_USB_PWC) += pwc.o obj-$(CONFIG_USB_PWC) += pwc.o
obj-$(CONFIG_USB_SE401) += se401.o obj-$(CONFIG_USB_SE401) += se401.o
obj-$(CONFIG_USB_STV680) += stv680.o obj-$(CONFIG_USB_STV680) += stv680.o
obj-$(CONFIG_USB_VICAM) += vicam.o obj-$(CONFIG_USB_VICAM) += vicam.o usbvideo.o
include $(TOPDIR)/Rules.make include $(TOPDIR)/Rules.make
/* -*- linux-c -*- /*
* USB ViCAM driver * USB ViCam WebCam driver
* * Copyright (c) 2002 Joe Burks (jburks@wavicle.org)
* Copyright (c) 2001 Christopher L Cheney (ccheney@cheney.cx)
* Copyright (c) 2001 Pavel Machek (pavel@suse.cz) sponsored by SuSE
* *
* This program is free software; you can redistribute it and/or * Supports 3COM HomeConnect PC Digital WebCam
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* *
* This driver is for the Vista Imaging ViCAM and 3Com HomeConnect USB * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* *
* Thanks to Greg Kroah-Hartman for the USB Skeleton driver * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* *
* TODO: * You should have received a copy of the GNU General Public License
* - find out the ids for the Vista Imaging ViCAM * along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* *
* History: * This source code is based heavily on the CPiA webcam driver which was
* written by Peter Pregler, Scott J. Bertin and Johannes Erdfelt
* *
* 2001_07_07 - 0.1 - christopher: first version * Portions of this code were also copied from usbvideo.c
* 2001_08_28 - 0.2 - pavel: messed it up, but for some fun, try
while true; do dd if=/dev/video of=/dev/fb0 bs=$[0x1e480] count=1 2> /dev/null; done
yep, moving pictures.
* 2001_08_29 - 0.3 - pavel: played a little bit more. Experimental mmap support. For some fun,
get gqcam-0.9, compile it and run. Better than dd ;-).
* 2001_08_29 - 0.4 - pavel: added shutter speed control (not much functional)
kill update_params if it does not seem to work for you.
* 2001_08_30 - 0.5 - pavel: fixed stupid bug with update_params & vicam_bulk
* *
* FIXME: It crashes on rmmod with camera plugged. * Special thanks to the the whole team at Sourceforge for help making
*/ * this driver become a reality. Notably:
#define DEBUG 1 * Andy Armstrong who reverse engineered the color encoding and
* Pavel Machek and Chris Cheney who worked on reverse engineering the
* camera controls and wrote the first generation driver.
* */
#include <linux/config.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/wrapper.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/pagemap.h>
#include <linux/slab.h>
#include <linux/fcntl.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/spinlock.h> #include <linux/init.h>
#include <linux/list.h> #include <linux/videodev.h>
#include <linux/smp_lock.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/usb.h> #include <linux/usb.h>
#include <asm/io.h>
#include <linux/wrapper.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/proc_fs.h>
#include "usbvideo.h"
#include <linux/videodev.h> // #define VICAM_DEBUG
#include "vicam.h" #ifndef MODULE_LICENSE
#include "vicamurbs.h" #define MODULE_LICENSE(a)
#endif
#ifndef bool
#define bool int
#endif
#ifdef VICAM_DEBUG
#define ADBG(lineno,fmt,args...) printk(fmt, jiffies, __FUNCTION__, lineno, ##args)
#define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG __FILE__"(%ld):%s (%d):"fmt,##args)
#else
#define DBG(fmn,args...) do {} while(0)
#endif
/* Version Information */ /* Version Information */
#define DRIVER_VERSION "v0" #define DRIVER_VERSION "v1.0"
#define DRIVER_AUTHOR "Christopher L Cheney <ccheney@cheney.cx>, Pavel Machek <pavel@suse.cz>" #define DRIVER_AUTHOR "Joe Burks, jburks@wavicle.org"
#define DRIVER_DESC "USB ViCAM Driver" #define DRIVER_DESC "ViCam WebCam Driver"
/* Define these values to match your device */ /* Define these values to match your device */
#define USB_VICAM_VENDOR_ID 0x04C1 #define USB_VICAM_VENDOR_ID 0x04c1
#define USB_VICAM_PRODUCT_ID 0x009D #define USB_VICAM_PRODUCT_ID 0x009d
/* table of devices that work with this driver */ #define VICAM_BYTES_PER_PIXEL 3
static struct usb_device_id vicam_table [] = { #define VICAM_MAX_READ_SIZE (512*242+128)
{ USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID) }, #define VICAM_MAX_FRAME_SIZE (VICAM_BYTES_PER_PIXEL*320*240)
{ } /* Terminating entry */ #define VICAM_FRAMES 2
};
MODULE_DEVICE_TABLE (usb, vicam_table); /* Not sure what all the bytes in these char
* arrays do, but they're necessary to make
* the camera work.
*/
static int video_nr = -1; /* next avail video device */ static unsigned char setup1[] = {
static struct usb_driver vicam_driver; 0xB6, 0xC3, 0x1F, 0x00, 0x02, 0x64, 0xE7, 0x67,
0xFD, 0xFF, 0x0E, 0xC0, 0xE7, 0x09, 0xDE, 0x00,
0x8E, 0x00, 0xC0, 0x09, 0x40, 0x03, 0xC0, 0x17,
0x44, 0x03, 0x4B, 0xAF, 0xC0, 0x07, 0x00, 0x00,
0x4B, 0xAF, 0x97, 0xCF, 0x00, 0x00
};
static char *buf, *buf2; static unsigned char setup2[] = {
static volatile int change_pending = 0; 0xB6, 0xC3, 0x03, 0x00, 0x03, 0x64, 0x18, 0x00,
0x00, 0x00
};
static int vicam_parameters(struct usb_vicam *vicam); static unsigned char setup3[] = {
0xB6, 0xC3, 0x01, 0x00, 0x06, 0x64, 0x00, 0x00
};
/****************************************************************************** static unsigned char setup4[] = {
* 0xB6, 0xC3, 0x8F, 0x06, 0x02, 0x64, 0xE7, 0x07,
* Memory management functions 0x00, 0x00, 0x08, 0xC0, 0xE7, 0x07, 0x00, 0x00,
* 0x3E, 0xC0, 0xE7, 0x07, 0x54, 0x01, 0xAA, 0x00,
* Taken from bttv-drivers.c 2.4.7-pre3 0xE7, 0x07, 0xC8, 0x05, 0xB6, 0x00, 0xE7, 0x07,
* 0x42, 0x01, 0xD2, 0x00, 0xE7, 0x07, 0x7C, 0x00,
******************************************************************************/ 0x16, 0x00, 0xE7, 0x07, 0x56, 0x00, 0x18, 0x00,
0xE7, 0x07, 0x06, 0x00, 0x92, 0xC0, 0xE7, 0x07,
0x00, 0x00, 0x1E, 0xC0, 0xE7, 0x07, 0xFF, 0xFF,
0x22, 0xC0, 0xE7, 0x07, 0x04, 0x00, 0x24, 0xC0,
0xE7, 0x07, 0xEC, 0x27, 0x28, 0xC0, 0xE7, 0x07,
0x16, 0x01, 0x8E, 0x00, 0xE7, 0x87, 0x01, 0x00,
0x0E, 0xC0, 0x97, 0xCF, 0xD7, 0x09, 0x00, 0xC0,
0xE7, 0x77, 0x01, 0x00, 0x92, 0xC0, 0x09, 0xC1,
0xE7, 0x09, 0xFE, 0x05, 0x24, 0x01, 0xE7, 0x09,
0x04, 0x06, 0x26, 0x01, 0xE7, 0x07, 0x07, 0x00,
0x92, 0xC0, 0xE7, 0x05, 0x00, 0xC0, 0xC0, 0xDF,
0x97, 0xCF, 0x17, 0x00, 0x57, 0x00, 0x17, 0x02,
0xD7, 0x09, 0x00, 0xC0, 0xE7, 0x77, 0x01, 0x00,
0x92, 0xC0, 0x0A, 0xC1, 0xE7, 0x57, 0xFF, 0xFF,
0xFA, 0x05, 0x0D, 0xC0, 0xE7, 0x57, 0x00, 0x00,
0xFA, 0x05, 0x0F, 0xC0, 0x9F, 0xAF, 0xC6, 0x00,
0xE7, 0x05, 0x00, 0xC0, 0xC8, 0x05, 0xC1, 0x05,
0xC0, 0x05, 0xC0, 0xDF, 0x97, 0xCF, 0x27, 0xDA,
0xFA, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x0B, 0x06,
0x73, 0xCF, 0x9F, 0xAF, 0x78, 0x01, 0x9F, 0xAF,
0x1A, 0x03, 0x6E, 0xCF, 0xE7, 0x09, 0xFC, 0x05,
0x24, 0x01, 0xE7, 0x09, 0x02, 0x06, 0x26, 0x01,
0xE7, 0x07, 0x07, 0x00, 0x92, 0xC0, 0xE7, 0x09,
0xFC, 0x05, 0xFE, 0x05, 0xE7, 0x09, 0x02, 0x06,
0x04, 0x06, 0xE7, 0x09, 0x00, 0x06, 0xFC, 0x05,
0xE7, 0x09, 0xFE, 0x05, 0x00, 0x06, 0x27, 0xDA,
0xFA, 0x05, 0xE7, 0x57, 0x01, 0x00, 0xFA, 0x05,
0x02, 0xCA, 0x04, 0xC0, 0x97, 0xCF, 0x9F, 0xAF,
0x66, 0x05, 0x97, 0xCF, 0xE7, 0x07, 0x40, 0x00,
0x02, 0x06, 0xC8, 0x09, 0xFC, 0x05, 0x9F, 0xAF,
0xDA, 0x02, 0x97, 0xCF, 0xCF, 0x17, 0x02, 0x00,
0xEF, 0x57, 0x81, 0x00, 0x09, 0x06, 0x9F, 0xA0,
0xB6, 0x01, 0xEF, 0x57, 0x80, 0x00, 0x09, 0x06,
0x9F, 0xA0, 0x40, 0x02, 0xEF, 0x57, 0x01, 0x00,
0x0B, 0x06, 0x9F, 0xA0, 0x46, 0x03, 0xE7, 0x07,
0x01, 0x00, 0x0A, 0xC0, 0x46, 0xAF, 0x47, 0xAF,
0x9F, 0xAF, 0x40, 0x02, 0xE7, 0x07, 0x2E, 0x00,
0x0A, 0xC0, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06,
0x97, 0xCF, 0x00, 0x0E, 0x01, 0x00, 0xC0, 0x57,
0x51, 0x00, 0x9F, 0xC0, 0x9E, 0x02, 0xC0, 0x57,
0x50, 0x00, 0x20, 0xC0, 0xC0, 0x57, 0x55, 0x00,
0x12, 0xC0, 0xC0, 0x57, 0x56, 0x00, 0x9F, 0xC0,
0x72, 0x02, 0x9F, 0xCF, 0xD6, 0x02, 0xC1, 0x0B,
0x08, 0x06, 0x01, 0xD0, 0x6F, 0x90, 0x08, 0x06,
0xC0, 0x07, 0x08, 0x00, 0xC1, 0x0B, 0x08, 0x06,
0x9F, 0xAF, 0x28, 0x05, 0x97, 0xCF, 0x2F, 0x0E,
0x02, 0x00, 0x08, 0x06, 0xC0, 0x07, 0x08, 0x00,
0xC1, 0x0B, 0x08, 0x06, 0x9F, 0xAF, 0x28, 0x05,
0x9F, 0xCF, 0xD6, 0x02, 0x2F, 0x0E, 0x02, 0x00,
0x09, 0x06, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06,
0x9F, 0xCF, 0xD6, 0x02, 0xEF, 0x67, 0x7F, 0xFF,
0x09, 0x06, 0xE7, 0x67, 0xFF, 0xFD, 0x22, 0xC0,
0xE7, 0x67, 0xEF, 0xFF, 0x24, 0xC0, 0xE7, 0x87,
0x10, 0x00, 0x28, 0xC0, 0x9F, 0xAF, 0xB8, 0x05,
0xE7, 0x87, 0xE0, 0x21, 0x24, 0xC0, 0x9F, 0xAF,
0xA8, 0x05, 0xE7, 0x87, 0x08, 0x00, 0x24, 0xC0,
0xE7, 0x67, 0xDF, 0xFF, 0x24, 0xC0, 0xC8, 0x07,
0x0A, 0x00, 0xC0, 0x07, 0x00, 0x00, 0xC1, 0x07,
0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0x9F, 0xAF,
0xB8, 0x05, 0xC0, 0x07, 0x9E, 0x00, 0x9F, 0xAF,
0x44, 0x05, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
0xC0, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01,
0x24, 0xC0, 0xC0, 0x77, 0x00, 0x02, 0x0F, 0xC1,
0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x67,
0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x08, 0x00,
0x24, 0xC0, 0x08, 0xDA, 0x5E, 0xC1, 0xEF, 0x07,
0x80, 0x00, 0x09, 0x06, 0x97, 0xCF, 0xEF, 0x07,
0x01, 0x00, 0x0A, 0x06, 0x97, 0xCF, 0xEF, 0x07,
0x00, 0x00, 0x0B, 0x06, 0xEF, 0x07, 0x00, 0x00,
0x0A, 0x06, 0xEF, 0x67, 0x7F, 0xFF, 0x09, 0x06,
0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06, 0xE7, 0x67,
0xEF, 0xFF, 0x28, 0xC0, 0xE7, 0x67, 0x17, 0xD8,
0x24, 0xC0, 0xE7, 0x07, 0x00, 0x00, 0x1E, 0xC0,
0xE7, 0x07, 0xFF, 0xFF, 0x22, 0xC0, 0x97, 0xCF,
0xC8, 0x07, 0x0E, 0x06, 0x9F, 0xAF, 0xDA, 0x02,
0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07,
0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0x0E, 0x06,
0xF4, 0x05, 0xE7, 0x07, 0xD6, 0x02, 0xF8, 0x05,
0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80,
0x50, 0xAF, 0x97, 0xCF, 0x2F, 0x0C, 0x02, 0x00,
0x07, 0x06, 0x2F, 0x0C, 0x04, 0x00, 0x06, 0x06,
0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07,
0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0xE2, 0x05,
0xF4, 0x05, 0xE7, 0x07, 0xCE, 0x02, 0xF8, 0x05,
0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80,
0x51, 0xAF, 0x97, 0xCF, 0x9F, 0xAF, 0x66, 0x04,
0x9F, 0xAF, 0x1A, 0x03, 0x59, 0xAF, 0x97, 0xCF,
0xC0, 0x07, 0x0E, 0x00, 0xC1, 0x0B, 0x0C, 0x06,
0x41, 0xD1, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
0x3C, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0x68, 0x00,
0xC0, 0x07, 0x3B, 0x00, 0x9F, 0xAF, 0x44, 0x05,
0x6F, 0x00, 0x0C, 0x06, 0x68, 0x00, 0xE0, 0x07,
0x04, 0x01, 0xE8, 0x0B, 0x0A, 0x06, 0xE8, 0x07,
0x00, 0x00, 0xE0, 0x07, 0x00, 0x02, 0xE0, 0x07,
0xEC, 0x01, 0xE0, 0x07, 0xFC, 0xFF, 0x97, 0xCF,
0xE7, 0x07, 0xFF, 0xFF, 0xFA, 0x05, 0xEF, 0x07,
0x00, 0x00, 0x0B, 0x06, 0xE7, 0x07, 0x0E, 0x06,
0x24, 0x01, 0xE7, 0x07, 0x0E, 0x06, 0xFE, 0x05,
0xE7, 0x07, 0x40, 0x00, 0x26, 0x01, 0xE7, 0x07,
0x40, 0x00, 0x04, 0x06, 0xE7, 0x07, 0x07, 0x00,
0x92, 0xC0, 0x97, 0xCF, 0xEF, 0x07, 0x02, 0x00,
0x0B, 0x06, 0x9F, 0xAF, 0x78, 0x01, 0xEF, 0x77,
0x80, 0x00, 0x07, 0x06, 0x9F, 0xC0, 0x14, 0x04,
0xEF, 0x77, 0x01, 0x00, 0x07, 0x06, 0x37, 0xC0,
0xEF, 0x77, 0x01, 0x00, 0x0D, 0x06, 0x0F, 0xC1,
0xEF, 0x07, 0x01, 0x00, 0x0D, 0x06, 0xC0, 0x07,
0x02, 0x00, 0xC1, 0x07, 0x30, 0x00, 0x9F, 0xAF,
0x28, 0x05, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07,
0x02, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07,
0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07,
0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x77,
0x03, 0x00, 0x02, 0xC1, 0x08, 0xDA, 0x75, 0xC1,
0xC1, 0x77, 0x01, 0x00, 0x0A, 0xC1, 0xC0, 0x07,
0x01, 0x00, 0xC1, 0x07, 0x02, 0x00, 0x9F, 0xAF,
0x28, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x06, 0x06,
0x2C, 0xCF, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07,
0x04, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xEF, 0x07,
0x00, 0x00, 0x06, 0x06, 0x22, 0xCF, 0xEF, 0x07,
0x00, 0x00, 0x0D, 0x06, 0xEF, 0x57, 0x01, 0x00,
0x06, 0x06, 0x1B, 0xC0, 0xC0, 0x07, 0x01, 0x00,
0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05,
0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00,
0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07, 0xFF, 0x4F,
0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07, 0x38, 0x00,
0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x67, 0x03, 0x00,
0xC1, 0x57, 0x03, 0x00, 0x02, 0xC0, 0x08, 0xDA,
0x73, 0xC1, 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07,
0x12, 0x00, 0xEF, 0x57, 0x00, 0x00, 0x06, 0x06,
0x02, 0xC0, 0xC1, 0x07, 0x23, 0x00, 0x9F, 0xAF,
0x28, 0x05, 0xC0, 0x07, 0x14, 0x00, 0xC1, 0x0B,
0xEA, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
0x3E, 0x00, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x09,
0xE4, 0x05, 0xFA, 0x05, 0x27, 0xD8, 0xFA, 0x05,
0xE7, 0x07, 0x0E, 0x06, 0xFC, 0x05, 0xE7, 0x07,
0x4E, 0x06, 0x00, 0x06, 0xE7, 0x07, 0x40, 0x00,
0x02, 0x06, 0x9F, 0xAF, 0x66, 0x05, 0x9F, 0xAF,
0xC6, 0x00, 0x97, 0xCF, 0xC1, 0x0B, 0xE2, 0x05,
0x41, 0xD0, 0x01, 0xD2, 0xC1, 0x17, 0x23, 0x00,
0x9F, 0xAF, 0xDC, 0x04, 0xC0, 0x07, 0x04, 0x00,
0xC1, 0x0B, 0xE3, 0x05, 0x9F, 0xAF, 0x28, 0x05,
0xC0, 0x07, 0x06, 0x00, 0xC1, 0x09, 0xE6, 0x05,
0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x07, 0x00,
0xC1, 0x09, 0xE6, 0x05, 0xC1, 0xD1, 0x9F, 0xAF,
0x28, 0x05, 0xC0, 0x07, 0x0B, 0x00, 0xC1, 0x09,
0xE8, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
0x0C, 0x00, 0xC1, 0x09, 0xE8, 0x05, 0xC1, 0xD1,
0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0D, 0x00,
0xC1, 0x07, 0x09, 0x00, 0x9F, 0xAF, 0x28, 0x05,
0xC0, 0x07, 0x03, 0x00, 0xC1, 0x07, 0x32, 0x00,
0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0F, 0x00,
0xC1, 0x07, 0x00, 0x00, 0x9F, 0xAF, 0x28, 0x05,
0x97, 0xCF, 0xE7, 0x67, 0xFF, 0xD9, 0x24, 0xC0,
0xC8, 0x07, 0x0A, 0x00, 0x40, 0x00, 0xC0, 0x67,
0x00, 0x02, 0x27, 0x80, 0x24, 0xC0, 0xE7, 0x87,
0x00, 0x04, 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xF9,
0x24, 0xC0, 0x01, 0xD2, 0x08, 0xDA, 0x72, 0xC1,
0xE7, 0x87, 0x00, 0x20, 0x24, 0xC0, 0x97, 0xCF,
0x27, 0x00, 0x1E, 0xC0, 0xE7, 0x87, 0xFF, 0x00,
0x22, 0xC0, 0xE7, 0x67, 0x7F, 0xFF, 0x24, 0xC0,
0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0, 0xE7, 0x87,
0x80, 0x00, 0x24, 0xC0, 0x97, 0xCF, 0x9F, 0xAF,
0x0A, 0x05, 0x67, 0x00, 0x1E, 0xC0, 0xE7, 0x67,
0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00,
0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
0x97, 0xCF, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x67,
0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE,
0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
0xC1, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01,
0x24, 0xC0, 0x97, 0xCF, 0xC0, 0x07, 0x40, 0x00,
0xC8, 0x09, 0xFC, 0x05, 0xE7, 0x67, 0x00, 0xFF,
0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x67,
0xBF, 0xFF, 0x24, 0xC0, 0x00, 0xDA, 0xE8, 0x09,
0x20, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, 0x00, 0xDA,
0xE8, 0x09, 0x20, 0xC0, 0x6D, 0xC1, 0xE7, 0x87,
0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF, 0xE7, 0x07,
0x32, 0x00, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80,
0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0xE7, 0x07,
0x20, 0x4E, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80,
0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0x09, 0x02,
0x19, 0x00, 0x01, 0x01, 0x00, 0x80, 0x96, 0x09,
0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
/* Here we want the physical address of the memory. static unsigned char setup5[] = {
* This is used when initializing the contents of the area. 0xB6, 0xC3, 0x2F, 0x01, 0x03, 0x64, 0x0E, 0x00,
*/ 0x14, 0x00, 0x1A, 0x00, 0x20, 0x00, 0x26, 0x00,
static inline unsigned long kvirt_to_pa(unsigned long adr) 0x4A, 0x00, 0x64, 0x00, 0x6A, 0x00, 0x92, 0x00,
0x9A, 0x00, 0xA0, 0x00, 0xB2, 0x00, 0xB8, 0x00,
0xBE, 0x00, 0xC2, 0x00, 0xC8, 0x00, 0xCE, 0x00,
0xDC, 0x00, 0xDA, 0x00, 0xE2, 0x00, 0xE0, 0x00,
0xE8, 0x00, 0xE6, 0x00, 0xEE, 0x00, 0xEC, 0x00,
0xF2, 0x00, 0xF8, 0x00, 0x02, 0x01, 0x0A, 0x01,
0x0E, 0x01, 0x12, 0x01, 0x1E, 0x01, 0x22, 0x01,
0x28, 0x01, 0x2C, 0x01, 0x32, 0x01, 0x36, 0x01,
0x44, 0x01, 0x50, 0x01, 0x5E, 0x01, 0x72, 0x01,
0x76, 0x01, 0x7A, 0x01, 0x80, 0x01, 0x88, 0x01,
0x8C, 0x01, 0x94, 0x01, 0x9C, 0x01, 0xA0, 0x01,
0xA4, 0x01, 0xAA, 0x01, 0xB0, 0x01, 0xB4, 0x01,
0xBA, 0x01, 0xD0, 0x01, 0xDA, 0x01, 0xF6, 0x01,
0xFA, 0x01, 0x02, 0x02, 0x34, 0x02, 0x3C, 0x02,
0x44, 0x02, 0x4A, 0x02, 0x50, 0x02, 0x56, 0x02,
0x74, 0x02, 0x78, 0x02, 0x7E, 0x02, 0x84, 0x02,
0x8A, 0x02, 0x88, 0x02, 0x90, 0x02, 0x8E, 0x02,
0x94, 0x02, 0xA2, 0x02, 0xA8, 0x02, 0xAE, 0x02,
0xB4, 0x02, 0xBA, 0x02, 0xB8, 0x02, 0xC0, 0x02,
0xBE, 0x02, 0xC4, 0x02, 0xD0, 0x02, 0xD4, 0x02,
0xE0, 0x02, 0xE6, 0x02, 0xEE, 0x02, 0xF8, 0x02,
0xFC, 0x02, 0x06, 0x03, 0x1E, 0x03, 0x24, 0x03,
0x28, 0x03, 0x30, 0x03, 0x2E, 0x03, 0x3C, 0x03,
0x4A, 0x03, 0x4E, 0x03, 0x54, 0x03, 0x58, 0x03,
0x5E, 0x03, 0x66, 0x03, 0x6E, 0x03, 0x7A, 0x03,
0x86, 0x03, 0x8E, 0x03, 0x96, 0x03, 0xB2, 0x03,
0xB8, 0x03, 0xC6, 0x03, 0xCC, 0x03, 0xD4, 0x03,
0xDA, 0x03, 0xE8, 0x03, 0xF4, 0x03, 0xFC, 0x03,
0x04, 0x04, 0x20, 0x04, 0x2A, 0x04, 0x32, 0x04,
0x36, 0x04, 0x3E, 0x04, 0x44, 0x04, 0x42, 0x04,
0x48, 0x04, 0x4E, 0x04, 0x4C, 0x04, 0x54, 0x04,
0x52, 0x04, 0x5A, 0x04, 0x5E, 0x04, 0x62, 0x04,
0x68, 0x04, 0x74, 0x04, 0x7C, 0x04, 0x80, 0x04,
0x88, 0x04, 0x8C, 0x04, 0x94, 0x04, 0x9A, 0x04,
0xA2, 0x04, 0xA6, 0x04, 0xAE, 0x04, 0xB4, 0x04,
0xC0, 0x04, 0xCC, 0x04, 0xD8, 0x04, 0x2A, 0x05,
0x46, 0x05, 0x6C, 0x05, 0x00, 0x00
};
static unsigned long kvirt_to_pa(unsigned long adr)
{ {
unsigned long kva, ret; unsigned long kva, ret;
...@@ -106,526 +360,734 @@ static inline unsigned long kvirt_to_pa(unsigned long adr) ...@@ -106,526 +360,734 @@ static inline unsigned long kvirt_to_pa(unsigned long adr)
return ret; return ret;
} }
static void * rvmalloc(unsigned long size) /* rvmalloc / rvfree copied from usbvideo.c
*
* Not sure why these are not yet non-statics which I can reference through
* usbvideo.h the same as it is in 2.4.20. I bet this will get fixed sometime
* in the future.
*
*/
static void *rvmalloc(unsigned long size)
{ {
void * mem; void *mem;
unsigned long adr; unsigned long adr;
size=PAGE_ALIGN(size); size = PAGE_ALIGN(size);
mem=vmalloc_32(size); mem = vmalloc_32(size);
if (mem) if (!mem)
{ return NULL;
memset(mem, 0, size); /* Clear the ram out, no junk to the user */
adr=(unsigned long) mem; memset(mem, 0, size); /* Clear the ram out, no junk to the user */
while (size > 0) adr = (unsigned long) mem;
{ while (size > 0) {
mem_map_reserve(vmalloc_to_page((void *)adr)); mem_map_reserve(vmalloc_to_page((void *)adr));
adr+=PAGE_SIZE; adr += PAGE_SIZE;
size-=PAGE_SIZE; size -= PAGE_SIZE;
}
} }
return mem; return mem;
} }
static void rvfree(void * mem, unsigned long size) static void rvfree(void *mem, unsigned long size)
{ {
unsigned long adr; unsigned long adr;
if (mem) if (!mem)
{ return;
adr=(unsigned long) mem;
while ((long) size > 0) adr = (unsigned long) mem;
{ while ((long) size > 0) {
mem_map_unreserve(vmalloc_to_page((void *)adr)); mem_map_unreserve(vmalloc_to_page((void *)adr));
adr+=PAGE_SIZE; adr += PAGE_SIZE;
size-=PAGE_SIZE; size -= PAGE_SIZE;
}
vfree(mem);
} }
vfree(mem);
} }
struct vicam_camera {
u16 shutter_speed; // capture shutter speed
u16 gain; // capture gain
/****************************************************************************** u8 *raw_image; // raw data captured from the camera
* u8 *framebuf; // processed data in RGB24 format
* Foo Bar
*
******************************************************************************/
/** struct video_device vdev; // v4l video device
* usb_vicam_debug_data struct usb_device *udev; // usb device
*/
static inline void usb_vicam_debug_data (const char *function, int size, const unsigned char *data)
{
int i;
if (!debug) struct semaphore busy_lock; // guard against SMP multithreading
return;
printk (KERN_DEBUG __FILE__": %s - length = %d, data = ", bool is_initialized;
function, size); u8 open_count;
for (i = 0; i < size; ++i) { u8 bulkEndpoint;
printk ("%.2x ", data[i]); bool needsDummyRead;
}
printk ("\n");
}
/***************************************************************************** u32 framebuf_size; // # of valid bytes in framebuf
* u32 framebuf_read_start; // position in frame buf that a read is happening at.
* Send command to vicam
* #ifdef CONFIG_PROC_FS
*****************************************************************************/ struct proc_dir_entry *proc_entry;
#endif
static int vicam_sndctrl(int set, struct usb_vicam *vicam, unsigned short req, };
unsigned short value, unsigned char *cp, int size)
static int vicam_probe( struct usb_interface *intf, const struct usb_device_id *id);
static void vicam_disconnect(struct usb_interface *intf);
static void read_frame(struct vicam_camera *cam, int framenum);
static int
send_control_msg(struct usb_device *udev, u8 request, u16 value, u16 index,
unsigned char *cp, u16 size)
{ {
int ret; int status;
unsigned char *transfer_buffer = kmalloc (size, GFP_KERNEL);
/* Needs to return data I think, works for sending though */ // for reasons not yet known to me, you can't send USB control messages
// with data in the module (if you are compiled as a module). Whatever
// the reason, copying it to memory allocated as kernel memory then
// doing the usb control message fixes the problem.
unsigned char *transfer_buffer = kmalloc(size, GFP_KERNEL);
memcpy(transfer_buffer, cp, size); memcpy(transfer_buffer, cp, size);
ret = usb_control_msg ( vicam->udev, set ? usb_sndctrlpipe(vicam->udev, 0) : usb_rcvctrlpipe(vicam->udev, 0), req, (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value, 0, transfer_buffer, size, HZ); status = usb_control_msg(udev,
usb_sndctrlpipe(udev, 0),
request,
USB_DIR_OUT | USB_TYPE_VENDOR |
USB_RECIP_DEVICE, value, index,
transfer_buffer, size, HZ);
kfree(transfer_buffer); kfree(transfer_buffer);
if (ret)
printk("vicam: error: %d\n", ret);
mdelay(100);
return ret;
}
if (status < 0) {
printk(KERN_INFO "Failed sending control message, error %d.\n",
status);
}
/***************************************************************************** return status;
* }
* Video4Linux Helpers
*
*****************************************************************************/
static int vicam_get_capability(struct usb_vicam *vicam, struct video_capability *b) static int
initialize_camera(struct vicam_camera *cam)
{ {
dbg("vicam_get_capability"); struct usb_device *udev = cam->udev;
int status;
strcpy(b->name, vicam->camera_name);
b->type = VID_TYPE_CAPTURE | VID_TYPE_MONOCHROME; if ((status =
b->channels = 1; send_control_msg(udev, 0xff, 0, 0, setup1, sizeof (setup1))) < 0)
b->audios = 0; return status;
if ((status =
b->maxwidth = vicam->width[vicam->sizes-1]; send_control_msg(udev, 0xff, 0, 0, setup2, sizeof (setup2))) < 0)
b->maxheight = vicam->height[vicam->sizes-1]; return status;
b->minwidth = vicam->width[0]; if ((status =
b->minheight = vicam->height[0]; send_control_msg(udev, 0xff, 0, 0, setup3, sizeof (setup3))) < 0)
return status;
if ((status =
send_control_msg(udev, 0xff, 0, 0, setup4, sizeof (setup4))) < 0)
return status;
if ((status =
send_control_msg(udev, 0xff, 0, 0, setup5, sizeof (setup5))) < 0)
return status;
if ((status =
send_control_msg(udev, 0xff, 0, 0, setup3, sizeof (setup3))) < 0)
return status;
return 0; return 0;
} }
static int vicam_get_channel(struct usb_vicam *vicam, struct video_channel *v) static int
set_camera_power(struct vicam_camera *cam, int state)
{ {
dbg("vicam_get_channel"); int status;
if (v->channel != 0) if ((status = send_control_msg(cam->udev, 0x50, state, 0, NULL, 0)) < 0)
return -EINVAL; return status;
v->flags = 0;
v->tuners = 0;
v->type = VIDEO_TYPE_CAMERA;
strcpy(v->name, "Camera");
return 0; if (state) {
} send_control_msg(cam->udev, 0x55, 1, 0, NULL, 0);
}
static int vicam_set_channel(struct usb_vicam *vicam, struct video_channel *v)
{
dbg("vicam_set_channel");
if (v->channel != 0)
return -EINVAL;
return 0; return 0;
} }
static int vicam_get_mmapbuffer(struct usb_vicam *vicam, struct video_mbuf *vm) static int
vicam_ioctl(struct inode *inode, struct file *file, unsigned int ioctlnr, unsigned long ul_arg)
{ {
int i; void *arg = (void *)ul_arg;
struct vicam_camera *cam = file->private_data;
int retval = 0;
dbg("vicam_get_mmapbuffer"); if (!cam)
return -ENODEV;
memset(vm, 0, sizeof(vm)); /* make this _really_ smp-safe */
vm->size = VICAM_NUMFRAMES * vicam->maxframesize; if (down_interruptible(&cam->busy_lock))
vm->frames = VICAM_NUMFRAMES; return -EINTR;
for (i=0; i<VICAM_NUMFRAMES; i++) switch (ioctlnr) {
vm->offsets[i] = vicam->maxframesize * i; /* query capabilites */
case VIDIOCGCAP:
{
struct video_capability b;
DBG("VIDIOCGCAP\n");
strcpy(b.name, "ViCam-based Camera");
b.type = VID_TYPE_CAPTURE;
b.channels = 1;
b.audios = 0;
b.maxwidth = 320; /* VIDEOSIZE_CIF */
b.maxheight = 240;
b.minwidth = 320; /* VIDEOSIZE_48_48 */
b.minheight = 240;
if (copy_to_user(arg, &b, sizeof (b)))
retval = -EFAULT;
break;
}
/* get/set video source - we are a camera and nothing else */
case VIDIOCGCHAN:
{
struct video_channel v;
DBG("VIDIOCGCHAN\n");
if (copy_from_user(&v, arg, sizeof (v))) {
retval = -EFAULT;
break;
}
if (v.channel != 0) {
retval = -EINVAL;
break;
}
v.channel = 0;
strcpy(v.name, "Camera");
v.tuners = 0;
v.flags = 0;
v.type = VIDEO_TYPE_CAMERA;
v.norm = 0;
if (copy_to_user(arg, &v, sizeof (v)))
retval = -EFAULT;
break;
}
return 0; case VIDIOCSCHAN:
} {
int v;
static int vicam_get_picture(struct usb_vicam *vicam, struct video_picture *p) if (copy_from_user(&v, arg, sizeof (v)))
{ retval = -EFAULT;
dbg("vicam_get_picture"); DBG("VIDIOCSCHAN %d\n", v);
/* This is probably where that weird 0x56 call goes */ if (retval == 0 && v != 0)
p->brightness = vicam->win.brightness; retval = -EINVAL;
p->hue = vicam->win.hue;
p->colour = vicam->win.colour;
p->contrast = vicam->win.contrast;
p->whiteness = vicam->win.whiteness;
p->depth = vicam->win.depth;
p->palette = vicam->win.palette;
return 0; break;
} }
static void synchronize(struct usb_vicam *vicam) /* image properties */
{ case VIDIOCGPICT:
DECLARE_WAITQUEUE(wait, current); {
change_pending = 1; struct video_picture vp;
set_current_state(TASK_INTERRUPTIBLE); DBG("VIDIOCGPICT\n");
add_wait_queue(&vicam->wait, &wait); memset(&vp, 0, sizeof (struct video_picture));
if (change_pending) vp.brightness = cam->gain << 8;
schedule(); vp.depth = 24;
remove_wait_queue(&vicam->wait, &wait); vp.palette = VIDEO_PALETTE_RGB24;
set_current_state(TASK_RUNNING); if (copy_to_user
vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x00, NULL, 0); (arg, &vp, sizeof (struct video_picture)))
mdelay(10); retval = -EFAULT;
vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x00, NULL, 0); break;
mdelay(10); }
}
static void params_changed(struct usb_vicam *vicam) case VIDIOCSPICT:
{ {
#if 1 struct video_picture *vp = (struct video_picture *) arg;
synchronize(vicam);
mdelay(10); DBG("VIDIOCSPICT depth = %d, pal = %d\n", vp->depth,
vicam_parameters(vicam); vp->palette);
printk(KERN_DEBUG "Submiting urb: %d\n", usb_submit_urb(vicam->readurb, GFP_KERNEL));
#endif cam->gain = vp->brightness >> 8;
if (vp->depth != 24
|| vp->palette != VIDEO_PALETTE_RGB24)
retval = -EINVAL;
break;
}
/* get/set capture window */
case VIDIOCGWIN:
{
struct video_window vw;
vw.x = 0;
vw.y = 0;
vw.width = 320;
vw.height = 240;
vw.chromakey = 0;
vw.flags = 0;
vw.clips = NULL;
vw.clipcount = 0;
DBG("VIDIOCGWIN\n");
if (copy_to_user
((void *) arg, (void *) &vw, sizeof (vw)))
retval = -EFAULT;
// I'm not sure what the deal with a capture window is, it is very poorly described
// in the doc. So I won't support it now.
break;
}
case VIDIOCSWIN:
{
struct video_window *vw = (struct video_window *) arg;
DBG("VIDIOCSWIN %d x %d\n", vw->width, vw->height);
if ( vw->width != 320 || vw->height != 240 )
retval = -EFAULT;
break;
}
/* mmap interface */
case VIDIOCGMBUF:
{
struct video_mbuf vm;
int i;
DBG("VIDIOCGMBUF\n");
memset(&vm, 0, sizeof (vm));
vm.size =
VICAM_MAX_FRAME_SIZE * VICAM_FRAMES;
vm.frames = VICAM_FRAMES;
for (i = 0; i < VICAM_FRAMES; i++)
vm.offsets[i] = VICAM_MAX_FRAME_SIZE * i;
if (copy_to_user
((void *) arg, (void *) &vm, sizeof (vm)))
retval = -EFAULT;
break;
}
case VIDIOCMCAPTURE:
{
struct video_mmap vm;
// int video_size;
if (copy_from_user
((void *) &vm, (void *) arg, sizeof (vm))) {
retval = -EFAULT;
break;
}
DBG("VIDIOCMCAPTURE frame=%d, height=%d, width=%d, format=%d.\n",vm.frame,vm.width,vm.height,vm.format);
if ( vm.frame >= VICAM_FRAMES || vm.format != VIDEO_PALETTE_RGB24 )
retval = -EINVAL;
// in theory right here we'd start the image capturing
// (fill in a bulk urb and submit it asynchronously)
//
// Instead we're going to do a total hack job for now and
// retrieve the frame in VIDIOCSYNC
break;
}
case VIDIOCSYNC:
{
int frame;
if (copy_from_user((void *) &frame, arg, sizeof (int))) {
retval = -EFAULT;
break;
}
DBG("VIDIOCSYNC: %d\n", frame);
read_frame(cam, frame);
break;
}
/* pointless to implement overlay with this camera */
case VIDIOCCAPTURE:
case VIDIOCGFBUF:
case VIDIOCSFBUF:
case VIDIOCKEY:
retval = -EINVAL;
break;
/* tuner interface - we have none */
case VIDIOCGTUNER:
case VIDIOCSTUNER:
case VIDIOCGFREQ:
case VIDIOCSFREQ:
retval = -EINVAL;
break;
/* audio interface - we have none */
case VIDIOCGAUDIO:
case VIDIOCSAUDIO:
retval = -EINVAL;
break;
default:
retval = -ENOIOCTLCMD;
break;
}
up(&cam->busy_lock);
return retval;
} }
static int vicam_set_picture(struct usb_vicam *vicam, struct video_picture *p) static int
vicam_open(struct inode *inode, struct file *file)
{ {
int changed = 0; struct video_device *dev = video_devdata(file);
info("vicam_set_picture (%d)", p->brightness); struct vicam_camera *cam =
(struct vicam_camera *) dev->priv;
DBG("open\n");
#define SET(x) \
if (vicam->win.x != p->x) \ if (!cam) {
vicam->win.x = p->x, changed = 1; printk(KERN_ERR
SET(brightness); "vicam video_device improperly initialized");
SET(hue); }
SET(colour);
SET(contrast);
SET(whiteness);
SET(depth);
SET(palette);
if (changed)
params_changed(vicam);
return 0; down_interruptible(&cam->busy_lock);
/* Investigate what should be done maybe 0x56 type call */
if (p->depth != 8) return 1; if (cam->open_count > 0) {
if (p->palette != VIDEO_PALETTE_GREY) return 1; printk(KERN_INFO
"vicam_open called on already opened camera");
up(&cam->busy_lock);
return -EBUSY;
}
if (!cam->raw_image) {
cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL);
if (!cam->raw_image) {
up(&cam->busy_lock);
return -ENOMEM;
}
}
if (!cam->framebuf) {
cam->framebuf =
rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
if (!cam->framebuf) {
kfree(cam->raw_image);
up(&cam->busy_lock);
return -ENOMEM;
}
}
// First upload firmware, then turn the camera on
if (!cam->is_initialized) {
initialize_camera(cam);
cam->is_initialized = 1;
}
set_camera_power(cam, 1);
cam->needsDummyRead = 1;
cam->open_count++;
up(&cam->busy_lock);
file->private_data = cam;
return 0; return 0;
} }
/* FIXME - vicam_sync_frame - important */ static int
static int vicam_sync_frame(struct usb_vicam *vicam, int frame) vicam_close(struct inode *inode, struct file *file)
{ {
dbg("vicam_sync_frame"); struct vicam_camera *cam = file->private_data;
DBG("close\n");
set_camera_power(cam, 0);
if(frame <0 || frame >= VICAM_NUMFRAMES) cam->open_count--;
return -EINVAL;
/* Probably need to handle various cases */
/* ret=vicam_newframe(vicam, frame);
vicam->frame[frame].grabstate=FRAME_UNUSED;
*/
return 0; return 0;
} }
static int vicam_get_window(struct usb_vicam *vicam, struct video_window *vw)
{
dbg("vicam_get_window");
vw->x = 0; inline int pin(int x)
vw->y = 0; {
vw->chromakey = 0; return((x > 255) ? 255 : ((x < 0) ? 0 : x));
vw->flags = 0; }
vw->clipcount = 0;
vw->width = vicam->win.width;
vw->height = vicam->win.height;
return 0; inline void writepixel(char *rgb, int Y, int Cr, int Cb)
{
Y = 1160 * (Y - 16);
rgb[2] = pin( ( ( Y + ( 1594 * Cr ) ) + 500 ) / 1300 );
rgb[1] = pin( ( ( Y - ( 392 * Cb ) - ( 813 * Cr ) ) + 500 ) / 1000 );
rgb[0] = pin( ( ( Y + ( 2017 * Cb ) ) + 500 ) / 900 );
} }
static int vicam_set_window(struct usb_vicam *vicam, struct video_window *vw) #define DATA_HEADER_SIZE 64
// --------------------------------------------------------------------------------
// vicam_decode_color - Convert from Vicam Y-Cr-Cb to RGB
//
// Copyright (C) 2002 Monroe Williams (monroe@pobox.com)
// --------------------------------------------------------------------------------
void vicam_decode_color( char *data, char *rgb)
{ {
info("vicam_set_window"); int x,y;
int Cr, Cb;
if (vw->flags) int sign;
return -EINVAL; int prevX, nextX, prevY, nextY;
if (vw->clipcount) int skip;
return -EINVAL; unsigned char *src;
unsigned char *dst;
if (vicam->win.width == vw->width && vicam->win.height == vw->height) prevY = 512;
return 0; nextY = 512;
/* Pick largest mode that is smaller than specified res */ src = data + DATA_HEADER_SIZE;
/* If specified res is too small reject */ dst = rgb;
/* Add urb send to device... */ for(y = 1; y < 241; y += 2)
{
// even line
sign = 1;
prevX = 1;
nextX = 1;
vicam->win.width = vw->width; skip = 0;
vicam->win.height = vw->height;
params_changed(vicam);
return 0; dst = rgb + (y-1)*320*3;
}
for(x = 0; x < 512; x++)
{
if(x == 512-1)
nextX = -1;
/* FIXME - vicam_mmap_capture - important */ Cr = sign * ((src[prevX] - src[0]) + (src[nextX] - src[0])) >> 1;
static int vicam_mmap_capture(struct usb_vicam *vicam, struct video_mmap *vm) Cb = sign * ((src[prevY] - src[prevX + prevY]) + (src[prevY] - src[nextX + prevY]) + (src[nextY] - src[prevX + nextY]) + (src[nextY] - src[nextX + nextY])) >> 2;
{
dbg("vicam_mmap_capture");
/* usbvideo.c looks good for using here */ writepixel(
dst + ((x*5)>>3)*3,
src[0] + (sign * (Cr >> 1)),
Cr,
Cb);
/* src++;
if (vm->frame >= VICAM_NUMFRAMES) sign *= -1;
return -EINVAL; prevX = -1;
if (vicam->frame[vm->frame].grabstate != FRAME_UNUSED) }
return -EBUSY;
vicam->frame[vm->frame].grabstate=FRAME_READY;
*/
/* No need to vicam_set_window here according to Alan */ prevY = -512;
/* if(y == (242 - 2))
if (!vicam->streaming) nextY = -512;
vicam_start_stream(vicam);
*/
/* set frame as ready */ // odd line
sign = 1;
prevX = 1;
nextX = 1;
return 0; skip = 0;
}
/***************************************************************************** dst = rgb + (y)*320*3;
*
* Video4Linux for(x = 0; x < 512; x++)
* {
*****************************************************************************/ if(x == 512-1)
nextX = -1;
Cr = sign * ((src[prevX + prevY] - src[prevY]) + (src[nextX + prevY] - src[prevY]) + (src[prevX + nextY] - src[nextY]) + (src[nextX + nextY] - src[nextY])) >> 2;
Cb = sign * ((src[0] - src[prevX]) + (src[0] - src[nextX])) >> 1;
writepixel(
dst + ((x * 5)>>3)*3,
src[0] - (sign * (Cb >> 1)),
Cr,
Cb);
src++;
sign *= -1;
prevX = -1;
}
}
}
static int vicam_v4l_open(struct inode *inode, struct file *file) static void
read_frame(struct vicam_camera *cam, int framenum)
{ {
struct video_device *vdev = video_devdata(file); unsigned char request[16];
struct usb_vicam *vicam = (struct usb_vicam *)vdev; int realShutter;
int err = 0; int n;
int actual_length;
dbg("vicam_v4l_open");
down(&vicam->sem); memset(request, 0, 16);
request[0] = cam->gain; // 0 = 0% gain, FF = 100% gain
vicam->fbuf = rvmalloc(vicam->maxframesize * VICAM_NUMFRAMES);
if (vicam->open_count) { request[1] = 0; // 512x242 capture
err = -EBUSY;
} else if (!vicam->fbuf) { request[2] = 0x90; // the function of these two bytes
err =- ENOMEM; request[3] = 0x07; // is not yet understood
if (cam->shutter_speed > 60) {
// Short exposure
realShutter =
((-15631900 / cam->shutter_speed) + 260533) / 1000;
request[4] = realShutter & 0xFF;
request[5] = (realShutter >> 8) & 0xFF;
request[6] = 0x03;
request[7] = 0x01;
} else { } else {
#ifdef BLINKING // Long exposure
vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x01, NULL, 0); realShutter = 15600 / cam->shutter_speed - 1;
info ("led on"); request[4] = 0;
vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x01, NULL, 0); request[5] = 0;
#endif request[6] = realShutter & 0xFF;
vicam->open_count++; request[7] = realShutter >> 8;
file->private_data = vdev;
} }
up(&vicam->sem); // Per John Markus Bjrndalen, byte at index 8 causes problems if it isn't 0
return err; request[8] = 0;
} // bytes 9-15 do not seem to affect exposure or image quality
static int vicam_v4l_close(struct inode *inode, struct file *file)
{
struct video_device *vdev = file->private_data;
struct usb_vicam *vicam = (struct usb_vicam *)vdev;
dbg("vicam_v4l_close"); n = send_control_msg(cam->udev, 0x51, 0x80, 0, request, 16);
down(&vicam->sem);
#ifdef BLINKING if (n < 0) {
info ("led off"); printk(KERN_ERR
vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x00, NULL, 0); " Problem sending frame capture control message");
// vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x00, NULL, 0); Leave it on return;
#endif }
rvfree(vicam->fbuf, vicam->maxframesize * VICAM_NUMFRAMES); n = usb_bulk_msg(cam->udev,
vicam->fbuf = 0; usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint),
vicam->open_count=0; cam->raw_image,
file->private_data = NULL; 512 * 242 + 128, &actual_length, HZ*10);
up(&vicam->sem); if (n < 0) {
/* Why does se401.c have a usbdevice check here? */ printk(KERN_ERR "Problem during bulk read of frame data: %d\n",
/* If device is unplugged while open, I guess we only may unregister now */ n);
return 0; }
}
static int vicam_v4l_read(struct file *file, char *user_buf, vicam_decode_color(cam->raw_image,
size_t buflen, loff_t *ppos) cam->framebuf +
{ framenum * VICAM_MAX_FRAME_SIZE );
struct video_device *vdev = file->private_data;
//struct usb_vicam *vicam = (struct usb_vicam *)vdev;
dbg("vicam_v4l_read(%d)", buflen); cam->framebuf_size =
320 * 240 * VICAM_BYTES_PER_PIXEL;
cam->framebuf_read_start = 0;
if (!vdev || !buf) return;
return -EFAULT;
if (copy_to_user(user_buf, buf2, buflen))
return -EFAULT;
return buflen;
} }
static int vicam_v4l_do_ioctl(struct inode *inode, struct file *file, static int
unsigned int cmd, void *arg) vicam_read( struct file *file, char *buf, size_t count, loff_t *ppos )
{ {
struct video_device *vdev = file->private_data; struct vicam_camera *cam = file->private_data;
struct usb_vicam *vicam = (struct usb_vicam *)vdev; DBG("read %d bytes.\n", (int) count);
int ret = -EL3RST;
if (!vicam->udev) if (!buf)
return -EIO; return -EINVAL;
down(&vicam->sem); if (!count)
return -EINVAL;
switch (cmd) { // This is some code that will hopefully allow us to do shell copies from
case VIDIOCGCAP: // the /dev/videoX to a file and have it actually work.
{ if (cam->framebuf_size != 0) {
struct video_capability *b = arg; if (cam->framebuf_read_start == cam->framebuf_size) {
ret = vicam_get_capability(vicam,b); cam->framebuf_size = cam->framebuf_read_start = 0;
dbg("name %s",b->name); return 0;
break; } else {
} if (cam->framebuf_read_start + count <=
case VIDIOCGFBUF: cam->framebuf_size) {
{ // count does not exceed available bytes
struct video_buffer *vb = arg; copy_to_user(buf,
info("vicam_v4l_ioctl - VIDIOCGBUF - query frame buffer param"); (cam->framebuf) +
/* frame buffer not supported, not used */ cam->framebuf_read_start, count);
memset(vb, 0, sizeof(*vb)); cam->framebuf_read_start += count;
ret = 0; return count;
break; } else {
} count =
case VIDIOCGWIN: cam->framebuf_size -
{ cam->framebuf_read_start;
struct video_window *vw = arg; copy_to_user(buf,
ret = vicam_get_window(vicam, vw); (cam->framebuf) +
break; cam->framebuf_read_start, count);
} cam->framebuf_read_start = cam->framebuf_size;
case VIDIOCSWIN: return count;
{ }
struct video_window *vw = arg; }
ret = vicam_set_window(vicam, vw);
break;
} }
case VIDIOCGCHAN:
{
struct video_channel *v = arg;
ret = vicam_get_channel(vicam,v); down_interruptible(&cam->busy_lock);
break;
} if (cam->needsDummyRead) {
case VIDIOCSCHAN: read_frame(cam, 0);
{ cam->needsDummyRead = 0;
struct video_channel *v = arg;
ret = vicam_set_channel(vicam,v);
break;
}
case VIDIOCGPICT:
{
struct video_picture *p = arg;
ret = vicam_get_picture(vicam,p);
break;
}
case VIDIOCSPICT:
{
struct video_picture *p = arg;
ret = vicam_set_picture(vicam,p);
break;
}
case VIDIOCGMBUF:
{
struct video_mbuf *vm = arg;
ret = vicam_get_mmapbuffer(vicam,vm);
break;
}
case VIDIOCMCAPTURE:
{
struct video_mmap *vm = arg;
ret = vicam_mmap_capture(vicam,vm);
break;
}
case VIDIOCSYNC:
{
int *frame = arg;
ret = vicam_sync_frame(vicam,*frame);
break;
} }
// read_frame twice because the camera doesn't seem to take the shutter speed for the first one.
case VIDIOCKEY: read_frame(cam, 0);
ret = 0;
case VIDIOCCAPTURE:
case VIDIOCSFBUF:
case VIDIOCGTUNER:
case VIDIOCSTUNER:
case VIDIOCGFREQ:
case VIDIOCSFREQ:
case VIDIOCGAUDIO:
case VIDIOCSAUDIO:
case VIDIOCGUNIT:
ret = -EINVAL;
default: if (count > cam->framebuf_size)
{ count = cam->framebuf_size;
info("vicam_v4l_ioctl - %ui",cmd);
ret = -ENOIOCTLCMD;
}
} /* end switch */
up(&vicam->sem); copy_to_user(buf, cam->framebuf, count);
return ret;
}
static int vicam_v4l_ioctl(struct inode *inode, struct file *file, if (count != cam->framebuf_size)
unsigned int cmd, unsigned long arg) cam->framebuf_read_start = count;
{ else
return video_usercopy(inode, file, cmd, arg, vicam_v4l_do_ioctl); cam->framebuf_size = 0;
up(&cam->busy_lock);
return count;
} }
static int vicam_v4l_mmap(struct file *file, struct vm_area_struct *vma)
static int
vicam_mmap(struct file *file, struct vm_area_struct *vma)
{ {
struct video_device *vdev = file->private_data; // TODO: allocate the raw frame buffer if necessary
struct usb_vicam *vicam = (struct usb_vicam *)vdev; unsigned long page, pos;
unsigned long start = vma->vm_start; unsigned long start = vma->vm_start;
unsigned long size = vma->vm_end-vma->vm_start; unsigned long size = vma->vm_end-vma->vm_start;
unsigned long page, pos; struct vicam_camera *cam = file->private_data;
down(&vicam->sem); if (!cam)
return -ENODEV;
if (vicam->udev == NULL) {
up(&vicam->sem); DBG("vicam_mmap: %ld\n", size);
return -EIO;
} /* We let mmap allocate as much as it wants because Linux was adding 2048 bytes
#if 0 * to the size the application requested for mmap and it was screwing apps up.
if (size > (((VICAM_NUMFRAMES * vicam->maxframesize) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) { if (size > VICAM_FRAMES*VICAM_MAX_FRAME_SIZE)
up(&vicam->sem); return -EINVAL;
return -EINVAL; */
/* make this _really_ smp-safe */
if (down_interruptible(&cam->busy_lock))
return -EINTR;
if (!cam->framebuf) { /* we do lazy allocation */
cam->framebuf =
rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
if (!cam->framebuf) {
up(&cam->busy_lock);
return -ENOMEM;
}
} }
#endif
pos = (unsigned long)vicam->fbuf; pos = (unsigned long)cam->framebuf;
while (size > 0) { while (size > 0) {
page = kvirt_to_pa(pos); page = kvirt_to_pa(pos);
if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
up(&vicam->sem);
return -EAGAIN; return -EAGAIN;
}
start += PAGE_SIZE; start += PAGE_SIZE;
pos += PAGE_SIZE; pos += PAGE_SIZE;
if (size > PAGE_SIZE) if (size > PAGE_SIZE)
...@@ -633,299 +1095,315 @@ static int vicam_v4l_mmap(struct file *file, struct vm_area_struct *vma) ...@@ -633,299 +1095,315 @@ static int vicam_v4l_mmap(struct file *file, struct vm_area_struct *vma)
else else
size = 0; size = 0;
} }
up(&vicam->sem);
return 0; up(&cam->busy_lock);
return 0;
} }
/* FIXME - vicam_template - important */ #ifdef CONFIG_PROC_FS
static struct file_operations vicam_fops = {
.owner = THIS_MODULE,
.open = vicam_v4l_open,
.release = vicam_v4l_close,
.read = vicam_v4l_read,
.mmap = vicam_v4l_mmap,
.ioctl = vicam_v4l_ioctl,
.llseek = no_llseek,
};
static struct video_device vicam_template = {
.owner = THIS_MODULE,
.name = "vicam USB camera",
.type = VID_TYPE_CAPTURE,
.hardware = VID_HARDWARE_SE401, /* need to ask for own id */
.fops = &vicam_fops,
};
/****************************************************************************** static struct proc_dir_entry *vicam_proc_root = NULL;
*
* Some Routines
*
******************************************************************************/
/* static int
Flash the led vicam_read_proc(char *page, char **start, off_t off,
vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x01, NULL, 0); int count, int *eof, void *data)
info ("led on"); {
vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x01, NULL, 0); char *out = page;
info ("led off"); int len;
vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x00, NULL, 0); struct vicam_camera *cam = (struct vicam_camera *) data;
vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x00, NULL, 0);
*/ out +=
sprintf(out, "Vicam-based WebCam Linux Driver.\n");
out += sprintf(out, "(c) 2002 Joe Burks (jburks@wavicle.org)\n");
out += sprintf(out, "vicam stats:\n");
out += sprintf(out, " Shutter Speed: 1/%d\n", cam->shutter_speed);
out += sprintf(out, " Gain: %d\n", cam->gain);
len = out - page;
len -= off;
if (len < count) {
*eof = 1;
if (len <= 0)
return 0;
} else
len = count;
*start = page + off;
return len;
}
static void vicam_bulk(struct urb *urb) static int
vicam_write_proc(struct file *file, const char *buffer,
unsigned long count, void *data)
{ {
struct usb_vicam *vicam = urb->context; char *in;
char *start;
struct vicam_camera *cam = (struct vicam_camera *) data;
/* if (!vicam || !vicam->dev || !vicam->used) in = kmalloc(count + 1, GFP_KERNEL);
return; if (!in)
*/ return -ENOMEM;
if (urb->status) in[count] = 0; // I'm not sure buffer is gauranteed to be null terminated
printk("vicam%d: nonzero read/write bulk status received: %d", // so I do this to make sure I have a null in there.
0, urb->status);
urb->actual_length = 0; strncpy(in, buffer, count);
urb->dev = vicam->udev;
memcpy(buf2, buf+64, 0x1e480); start = strstr(in, "gain=");
if (vicam->fbuf) if (start
memcpy(vicam->fbuf, buf+64, 0x1e480); && (start == in || *(start - 1) == ' ' || *(start - 1) == ','))
cam->gain = simple_strtoul(start + 5, NULL, 10);
if (!change_pending) { start = strstr(in, "shutter=");
if (usb_submit_urb(urb, GFP_ATOMIC)) if (start
dbg("failed resubmitting read urb"); && (start == in || *(start - 1) == ' ' || *(start - 1) == ','))
} else { cam->shutter_speed = simple_strtoul(start + 8, NULL, 10);
change_pending = 0;
wake_up_interruptible(&vicam->wait); kfree(in);
} return count;
} }
static int vicam_parameters(struct usb_vicam *vicam) void
vicam_create_proc_root(void)
{ {
unsigned char req[0x10]; vicam_proc_root = create_proc_entry("video/vicam", S_IFDIR, 0);
unsigned int shutter;
shutter = 10;
switch (vicam->win.width) { if (vicam_proc_root)
case 512: vicam_proc_root->owner = THIS_MODULE;
default: else
memcpy(req, s512x242bw, 0x10); printk(KERN_ERR
break; "could not create /proc entry for vicam!");
case 256: }
memcpy(req, s256x242bw, 0x10);
break;
case 128:
memcpy(req, s128x122bw, 0x10);
break;
}
void
vicam_destroy_proc_root(void)
{
if (vicam_proc_root)
remove_proc_entry("video/vicam", 0);
}
mdelay(10); void
vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x01, NULL, 0); vicam_create_proc_entry(void *ptr)
info ("led on"); {
vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x01, NULL, 0); struct vicam_camera *cam = (struct vicam_camera *) ptr;
mdelay(10); char name[7];
struct proc_dir_entry *ent;
shutter = vicam->win.contrast / 256; DBG(KERN_INFO "vicam: creating proc entry\n");
if (shutter == 0)
shutter = 1;
printk("vicam_parameters: brightness %d, shutter %d\n", vicam->win.brightness, shutter );
req[0] = vicam->win.brightness /256;
shutter = 15600/shutter - 1;
req[6] = shutter & 0xff;
req[7] = (shutter >> 8) & 0xff;
vicam_sndctrl(1, vicam, VICAM_REQ_CAPTURE, 0x80, req, 0x10);
mdelay(10);
vicam_sndctrl(0, vicam, VICAM_REQ_GET_SOMETHIN, 0, buf, 0x10);
mdelay(10);
return 0; if (!vicam_proc_root || !cam) {
printk(KERN_INFO
"vicam: could not create proc entry, %s pointer is null.\n",
(!cam ? "camera" : "root"));
return;
}
sprintf(name, "video%d", cam->vdev.minor);
ent =
create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR,
vicam_proc_root);
if (!ent)
return;
ent->data = cam;
ent->read_proc = vicam_read_proc;
ent->write_proc = vicam_write_proc;
ent->size = 512;
cam->proc_entry = ent;
} }
static int vicam_init(struct usb_vicam *vicam) void
vicam_destroy_proc_entry(void *ptr)
{ {
int width[] = {128, 256, 512}; struct vicam_camera *cam = (struct vicam_camera *) ptr;
int height[] = {122, 242, 242}; char name[7];
dbg("vicam_init");
buf = kmalloc(0x1e480, GFP_KERNEL);
buf2 = kmalloc(0x1e480, GFP_KERNEL);
if ((!buf) || (!buf2)) {
printk("Not enough memory for vicam!\n");
goto error;
}
/* do we do aspect correction in kernel or not? */ if (!cam || !cam->proc_entry)
vicam->sizes = 3; return;
vicam->width = kmalloc(vicam->sizes*sizeof(int), GFP_KERNEL);
vicam->height = kmalloc(vicam->sizes*sizeof(int), GFP_KERNEL);
memcpy(vicam->width, &width, sizeof(width));
memcpy(vicam->height, &height, sizeof(height));
vicam->maxframesize = vicam->width[vicam->sizes-1] * vicam->height[vicam->sizes-1];
/* Download firmware to camera */ sprintf(name, "video%d", cam->vdev.minor);
vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, firmware1, sizeof(firmware1)); remove_proc_entry(name, vicam_proc_root);
vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, findex1, sizeof(findex1)); cam->proc_entry = NULL;
vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, fsetup, sizeof(fsetup));
vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, firmware2, sizeof(firmware2));
vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, findex2, sizeof(findex2));
vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, fsetup, sizeof(fsetup));
vicam_parameters(vicam); }
FILL_BULK_URB(vicam->readurb, vicam->udev, usb_rcvbulkpipe(vicam->udev, 0x81), #endif
buf, 0x1e480, vicam_bulk, vicam);
printk(KERN_DEBUG "Submiting urb: %d\n", usb_submit_urb(vicam->readurb, GFP_KERNEL));
int
vicam_video_init(struct video_device *vdev)
{
// This would normally create the proc entry for this camera
#ifdef CONFIG_PROC_FS
vicam_create_proc_entry(vdev->priv);
#endif
return 0; return 0;
error:
if (buf)
kfree(buf);
if (buf2)
kfree(buf2);
return 1;
} }
static int vicam_probe(struct usb_interface *intf, static struct file_operations vicam_fops = {
const struct usb_device_id *id) .owner = THIS_MODULE,
{ .open = vicam_open,
struct usb_device *udev = interface_to_usbdev(intf); .release =vicam_close,
struct usb_vicam *vicam; .read = vicam_read,
char *camera_name=NULL; .mmap = vicam_mmap,
.ioctl = vicam_ioctl,
.llseek = no_llseek,
};
static struct video_device vicam_template = {
.owner = THIS_MODULE,
.name = "ViCam-based USB Camera",
.type = VID_TYPE_CAPTURE,
.hardware = VID_HARDWARE_VICAM,
.fops = &vicam_fops,
// .initialize = vicam_video_init,
.minor = -1,
};
/* table of devices that work with this driver */
static struct usb_device_id vicam_table[] = {
{USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)},
{} /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, vicam_table);
dbg("vicam_probe"); static struct usb_driver vicam_driver = {
name:"vicam",
probe:vicam_probe,
disconnect:vicam_disconnect,
id_table:vicam_table
};
/**
* vicam_probe
*
* Called by the usb core when a new device is connected that it thinks
* this driver might be interested in.
*/
static int
vicam_probe( struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev(intf);
int bulkEndpoint = 0;
const struct usb_interface_descriptor *interface;
const struct usb_endpoint_descriptor *endpoint;
struct vicam_camera *cam;
/* See if the device offered us matches what we can accept */ /* See if the device offered us matches what we can accept */
if ((udev->descriptor.idVendor != USB_VICAM_VENDOR_ID) || if ((dev->descriptor.idVendor != USB_VICAM_VENDOR_ID) ||
(udev->descriptor.idProduct != USB_VICAM_PRODUCT_ID)) { (dev->descriptor.idProduct != USB_VICAM_PRODUCT_ID)) {
return -ENODEV; return -ENODEV;
} }
camera_name="3Com HomeConnect USB"; printk(KERN_INFO "ViCam based webcam connected\n");
info("ViCAM camera found: %s", camera_name);
interface = &intf->altsetting[0];
vicam = kmalloc (sizeof(struct usb_vicam), GFP_KERNEL);
if (vicam == NULL) { DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n",
err ("couldn't kmalloc vicam struct"); ifnum, (unsigned) (interface->bNumEndpoints));
return -ENOMEM; endpoint = &interface->endpoint[0];
if ((endpoint->bEndpointAddress & 0x80) &&
((endpoint->bmAttributes & 3) == 0x02)) {
/* we found a bulk in endpoint */
bulkEndpoint = endpoint->bEndpointAddress;
} else {
printk(KERN_ERR
"No bulk in endpoint was found ?! (this is bad)\n");
} }
memset(vicam, 0, sizeof(*vicam));
vicam->readurb = usb_alloc_urb(0, GFP_KERNEL); if ((cam =
if (!vicam->readurb) { kmalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) {
kfree(vicam); printk(KERN_WARNING
"could not allocate kernel memory for vicam_camera struct\n");
return -ENOMEM; return -ENOMEM;
} }
vicam->udev = udev; memset(cam, 0, sizeof (struct vicam_camera));
vicam->camera_name = camera_name;
vicam->win.brightness = 128;
vicam->win.contrast = 10;
/* FIXME */ cam->shutter_speed = 15;
if (vicam_init(vicam)) {
usb_free_urb(vicam->readurb); init_MUTEX(&cam->busy_lock);
kfree(vicam);
return -ENOMEM; memcpy(&cam->vdev, &vicam_template,
} sizeof (vicam_template));
memcpy(&vicam->vdev, &vicam_template, sizeof(vicam_template)); cam->vdev.priv = cam; // sort of a reverse mapping for those functions that get vdev only
memcpy(vicam->vdev.name, vicam->camera_name, strlen(vicam->camera_name));
cam->udev = dev;
if (video_register_device(&vicam->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { cam->bulkEndpoint = bulkEndpoint;
err("video_register_device");
usb_free_urb(vicam->readurb); if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) == -1) {
kfree(vicam); kfree(cam);
printk(KERN_WARNING "video_register_device failed\n");
return -EIO; return -EIO;
} }
info("registered new video device: video%d", vicam->vdev.minor); printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor);
init_MUTEX (&vicam->sem); dev_set_drvdata(&intf->dev, cam);
init_waitqueue_head(&vicam->wait);
dev_set_drvdata (&intf->dev, vicam);
return 0; return 0;
} }
static void
/* FIXME - vicam_disconnect - important */ vicam_disconnect(struct usb_interface *intf)
static void vicam_disconnect(struct usb_interface *intf)
{ {
struct usb_vicam *vicam; struct vicam_camera *cam = dev_get_drvdata(&intf->dev);
vicam = dev_get_drvdata (&intf->dev); dev_set_drvdata ( &intf->dev, NULL );
usb_put_dev(cam->udev);
cam->udev = NULL;
video_unregister_device(&cam->vdev);
dev_set_drvdata (&intf->dev, NULL); #ifdef CONFIG_PROC_FS
vicam_destroy_proc_entry(cam);
#endif
if (vicam) { if (cam->raw_image)
video_unregister_device(&vicam->vdev); kfree(cam->raw_image);
vicam->udev = NULL; if (cam->framebuf)
/* rvfree(cam->framebuf,
vicam->frame[0].grabstate = FRAME_ERROR; VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
vicam->frame[1].grabstate = FRAME_ERROR;
*/
/* Free buffers and shit */ kfree(cam);
info("%s disconnected", vicam->camera_name);
synchronize(vicam);
if (!vicam->open_count) { printk(KERN_DEBUG "ViCam-based WebCam disconnected\n");
/* Other random junk */
usb_free_urb(vicam->readurb);
kfree(vicam);
vicam = NULL;
}
}
} }
/* usb specific object needed to register this driver with the usb subsystem */ /*
static struct usb_driver vicam_driver = { */
.owner = THIS_MODULE, static int __init
.name = "vicam", usb_vicam_init(void)
.probe = vicam_probe,
.disconnect = vicam_disconnect,
.id_table = vicam_table,
};
/******************************************************************************
*
* Module Routines
*
******************************************************************************/
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
/* Module paramaters */
MODULE_PARM(debug, "i");
MODULE_PARM_DESC(debug, "Debug enabled or not");
static int __init usb_vicam_init(void)
{ {
int result; DBG(KERN_INFO "ViCam-based WebCam driver startup\n");
#ifdef CONFIG_PROC_FS
printk("VICAM: initializing\n"); vicam_create_proc_root();
/* register this driver with the USB subsystem */ #endif
result = usb_register(&vicam_driver); if (usb_register(&vicam_driver) != 0)
if (result < 0) { printk(KERN_WARNING "usb_register failed!\n");
err("usb_register failed for the "__FILE__" driver. Error number %d",
result);
return -1;
}
info(DRIVER_VERSION " " DRIVER_AUTHOR);
info(DRIVER_DESC);
return 0; return 0;
} }
static void __exit usb_vicam_exit(void) static void __exit
usb_vicam_exit(void)
{ {
/* deregister this driver with the USB subsystem */ DBG(KERN_INFO
"ViCam-based WebCam driver shutdown\n");
usb_deregister(&vicam_driver); usb_deregister(&vicam_driver);
#ifdef CONFIG_PROC_FS
vicam_destroy_proc_root();
#endif
} }
module_init(usb_vicam_init); module_init(usb_vicam_init);
module_exit(usb_vicam_exit); module_exit(usb_vicam_exit);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
/*
*
* Vista Imaging ViCAM / 3Com HomeConnect Usermode Driver
* Christopher L Cheney (C) 2001
*
*/
#ifndef __LINUX_VICAM_H
#define __LINUX_VICAM_H
#ifdef CONFIG_USB_DEBUG
static int debug = 1;
#else
static int debug;
#endif
/* Use our own dbg macro */
#undef dbg
#define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg); } while (0)
#define VICAM_NUMFRAMES 30
#define VICAM_NUMSBUF 1
/* USB REQUEST NUMBERS */
#define VICAM_REQ_VENDOR 0xff
#define VICAM_REQ_CAMERA_POWER 0x50
#define VICAM_REQ_CAPTURE 0x51
#define VICAM_REQ_LED_CONTROL 0x55
#define VICAM_REQ_GET_SOMETHIN 0x56
/* not required but lets you know camera is on */
/* camera must be on to turn on led */
/* 0x01 always on 0x03 on when picture taken (flashes) */
struct picture_parm
{
int width;
int height;
int brightness;
int hue;
int colour;
int contrast;
int whiteness;
int depth;
int palette;
};
struct vicam_scratch {
unsigned char *data;
volatile int state;
int offset;
int length;
};
/* Structure to hold all of our device specific stuff */
struct usb_vicam
{
struct video_device vdev;
struct usb_device *udev;
int open_count; /* number of times this port has been opened */
struct semaphore sem; /* locks this structure */
wait_queue_head_t wait; /* Processes waiting */
int streaming;
/* v4l stuff */
char *camera_name;
char *fbuf;
struct urb *urb[VICAM_NUMSBUF];
int sizes;
int *width;
int *height;
int maxframesize;
struct picture_parm win;
struct proc_dir_entry *proc_entry; /* /proc/se401/videoX */
struct urb *readurb;
};
#endif
...@@ -397,6 +397,7 @@ struct video_code ...@@ -397,6 +397,7 @@ struct video_code
#define VID_HARDWARE_PWC 31 /* Philips webcams */ #define VID_HARDWARE_PWC 31 /* Philips webcams */
#define VID_HARDWARE_MEYE 32 /* Sony Vaio MotionEye cameras */ #define VID_HARDWARE_MEYE 32 /* Sony Vaio MotionEye cameras */
#define VID_HARDWARE_CPIA2 33 #define VID_HARDWARE_CPIA2 33
#define VID_HARDWARE_VICAM 34
#endif /* __LINUX_VIDEODEV_H */ #endif /* __LINUX_VIDEODEV_H */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment