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 */ memset(mem, 0, size); /* Clear the ram out, no junk to the user */
adr=(unsigned long) mem; adr = (unsigned long) mem;
while (size > 0) 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
* Foo Bar u16 gain; // capture gain
*
******************************************************************************/
/** u8 *raw_image; // raw data captured from the camera
* usb_vicam_debug_data u8 *framebuf; // processed data in RGB24 format
*/
static inline void usb_vicam_debug_data (const char *function, int size, const unsigned char *data)
{
int i;
if (!debug) struct video_device vdev; // v4l video device
return; struct usb_device *udev; // usb device
printk (KERN_DEBUG __FILE__": %s - length = %d, data = ", struct semaphore busy_lock; // guard against SMP multithreading
function, size);
for (i = 0; i < size; ++i) {
printk ("%.2x ", data[i]);
}
printk ("\n");
}
/***************************************************************************** bool is_initialized;
* u8 open_count;
* Send command to vicam u8 bulkEndpoint;
* bool needsDummyRead;
*****************************************************************************/
u32 framebuf_size; // # of valid bytes in framebuf
u32 framebuf_read_start; // position in frame buf that a read is happening at.
#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);
// 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.
/* Needs to return data I think, works for sending though */ 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; if (state) {
v->tuners = 0; send_control_msg(cam->udev, 0x55, 1, 0, NULL, 0);
v->type = VIDEO_TYPE_CAMERA; }
strcpy(v->name, "Camera");
return 0; return 0;
} }
static int vicam_set_channel(struct usb_vicam *vicam, struct video_channel *v) static int
vicam_ioctl(struct inode *inode, struct file *file, unsigned int ioctlnr, unsigned long ul_arg)
{ {
dbg("vicam_set_channel"); void *arg = (void *)ul_arg;
struct vicam_camera *cam = file->private_data;
int retval = 0;
if (v->channel != 0) if (!cam)
return -EINVAL; return -ENODEV;
return 0; /* make this _really_ smp-safe */
} if (down_interruptible(&cam->busy_lock))
return -EINTR;
static int vicam_get_mmapbuffer(struct usb_vicam *vicam, struct video_mbuf *vm) switch (ioctlnr) {
{ /* query capabilites */
int i; case VIDIOCGCAP:
{
struct video_capability b;
dbg("vicam_get_mmapbuffer"); 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;
memset(vm, 0, sizeof(vm)); if (copy_to_user(arg, &b, sizeof (b)))
vm->size = VICAM_NUMFRAMES * vicam->maxframesize; retval = -EFAULT;
vm->frames = VICAM_NUMFRAMES;
for (i=0; i<VICAM_NUMFRAMES; i++) break;
vm->offsets[i] = vicam->maxframesize * i; }
/* get/set video source - we are a camera and nothing else */
case VIDIOCGCHAN:
{
struct video_channel v;
return 0; DBG("VIDIOCGCHAN\n");
} if (copy_from_user(&v, arg, sizeof (v))) {
retval = -EFAULT;
break;
}
if (v.channel != 0) {
retval = -EINVAL;
break;
}
static int vicam_get_picture(struct usb_vicam *vicam, struct video_picture *p) v.channel = 0;
{ strcpy(v.name, "Camera");
dbg("vicam_get_picture"); v.tuners = 0;
v.flags = 0;
v.type = VIDEO_TYPE_CAMERA;
v.norm = 0;
/* This is probably where that weird 0x56 call goes */ if (copy_to_user(arg, &v, sizeof (v)))
p->brightness = vicam->win.brightness; retval = -EFAULT;
p->hue = vicam->win.hue; break;
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; case VIDIOCSCHAN:
} {
int v;
static void synchronize(struct usb_vicam *vicam) if (copy_from_user(&v, arg, sizeof (v)))
{ retval = -EFAULT;
DECLARE_WAITQUEUE(wait, current); DBG("VIDIOCSCHAN %d\n", v);
change_pending = 1;
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&vicam->wait, &wait);
if (change_pending)
schedule();
remove_wait_queue(&vicam->wait, &wait);
set_current_state(TASK_RUNNING);
vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x00, NULL, 0);
mdelay(10);
vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x00, NULL, 0);
mdelay(10);
}
static void params_changed(struct usb_vicam *vicam) if (retval == 0 && v != 0)
{ retval = -EINVAL;
#if 1
synchronize(vicam);
mdelay(10);
vicam_parameters(vicam);
printk(KERN_DEBUG "Submiting urb: %d\n", usb_submit_urb(vicam->readurb, GFP_KERNEL));
#endif
}
static int vicam_set_picture(struct usb_vicam *vicam, struct video_picture *p) break;
{ }
int changed = 0;
info("vicam_set_picture (%d)", p->brightness);
#define SET(x) \
if (vicam->win.x != p->x) \
vicam->win.x = p->x, changed = 1;
SET(brightness);
SET(hue);
SET(colour);
SET(contrast);
SET(whiteness);
SET(depth);
SET(palette);
if (changed)
params_changed(vicam);
return 0; /* image properties */
/* Investigate what should be done maybe 0x56 type call */ case VIDIOCGPICT:
if (p->depth != 8) return 1; {
if (p->palette != VIDEO_PALETTE_GREY) return 1; struct video_picture vp;
DBG("VIDIOCGPICT\n");
memset(&vp, 0, sizeof (struct video_picture));
vp.brightness = cam->gain << 8;
vp.depth = 24;
vp.palette = VIDEO_PALETTE_RGB24;
if (copy_to_user
(arg, &vp, sizeof (struct video_picture)))
retval = -EFAULT;
break;
}
return 0; case VIDIOCSPICT:
} {
struct video_picture *vp = (struct video_picture *) arg;
/* FIXME - vicam_sync_frame - important */ DBG("VIDIOCSPICT depth = %d, pal = %d\n", vp->depth,
static int vicam_sync_frame(struct usb_vicam *vicam, int frame) vp->palette);
{
dbg("vicam_sync_frame");
if(frame <0 || frame >= VICAM_NUMFRAMES) cam->gain = vp->brightness >> 8;
return -EINVAL;
/* Probably need to handle various cases */ if (vp->depth != 24
/* ret=vicam_newframe(vicam, frame); || vp->palette != VIDEO_PALETTE_RGB24)
vicam->frame[frame].grabstate=FRAME_UNUSED; retval = -EINVAL;
*/
return 0;
}
static int vicam_get_window(struct usb_vicam *vicam, struct video_window *vw) break;
{ }
dbg("vicam_get_window");
vw->x = 0; /* get/set capture window */
vw->y = 0; case VIDIOCGWIN:
vw->chromakey = 0; {
vw->flags = 0; struct video_window vw;
vw->clipcount = 0; vw.x = 0;
vw->width = vicam->win.width; vw.y = 0;
vw->height = vicam->win.height; 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;
}
return 0; case VIDIOCSWIN:
} {
static int vicam_set_window(struct usb_vicam *vicam, struct video_window *vw) struct video_window *vw = (struct video_window *) arg;
{ DBG("VIDIOCSWIN %d x %d\n", vw->width, vw->height);
info("vicam_set_window");
if (vw->flags) if ( vw->width != 320 || vw->height != 240 )
return -EINVAL; retval = -EFAULT;
if (vw->clipcount)
return -EINVAL;
if (vicam->win.width == vw->width && vicam->win.height == vw->height) break;
return 0; }
/* Pick largest mode that is smaller than specified res */ /* mmap interface */
/* If specified res is too small reject */ case VIDIOCGMBUF:
{
struct video_mbuf vm;
int i;
/* Add urb send to device... */ 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;
vicam->win.width = vw->width; if (copy_to_user
vicam->win.height = vw->height; ((void *) arg, (void *) &vm, sizeof (vm)))
params_changed(vicam); retval = -EFAULT;
return 0; break;
} }
/* FIXME - vicam_mmap_capture - important */ case VIDIOCMCAPTURE:
static int vicam_mmap_capture(struct usb_vicam *vicam, struct video_mmap *vm) {
{ struct video_mmap vm;
dbg("vicam_mmap_capture"); // int video_size;
/* usbvideo.c looks good for using here */ 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_NUMFRAMES)
return -EINVAL;
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 */ if ( vm.frame >= VICAM_FRAMES || vm.format != VIDEO_PALETTE_RGB24 )
retval = -EINVAL;
/* // in theory right here we'd start the image capturing
if (!vicam->streaming) // (fill in a bulk urb and submit it asynchronously)
vicam_start_stream(vicam); //
*/ // Instead we're going to do a total hack job for now and
// retrieve the frame in VIDIOCSYNC
/* set frame as ready */ break;
}
return 0; case VIDIOCSYNC:
} {
int frame;
/***************************************************************************** if (copy_from_user((void *) &frame, arg, sizeof (int))) {
* retval = -EFAULT;
* Video4Linux break;
* }
*****************************************************************************/ DBG("VIDIOCSYNC: %d\n", frame);
static int vicam_v4l_open(struct inode *inode, struct file *file) read_frame(cam, frame);
{
struct video_device *vdev = video_devdata(file); break;
struct usb_vicam *vicam = (struct usb_vicam *)vdev; }
int err = 0;
/* pointless to implement overlay with this camera */
dbg("vicam_v4l_open"); case VIDIOCCAPTURE:
down(&vicam->sem); case VIDIOCGFBUF:
case VIDIOCSFBUF:
vicam->fbuf = rvmalloc(vicam->maxframesize * VICAM_NUMFRAMES); case VIDIOCKEY:
if (vicam->open_count) { retval = -EINVAL;
err = -EBUSY; break;
} else if (!vicam->fbuf) {
err =- ENOMEM; /* tuner interface - we have none */
} else { case VIDIOCGTUNER:
#ifdef BLINKING case VIDIOCSTUNER:
vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x01, NULL, 0); case VIDIOCGFREQ:
info ("led on"); case VIDIOCSFREQ:
vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x01, NULL, 0); retval = -EINVAL;
#endif break;
vicam->open_count++;
file->private_data = vdev; /* audio interface - we have none */
case VIDIOCGAUDIO:
case VIDIOCSAUDIO:
retval = -EINVAL;
break;
default:
retval = -ENOIOCTLCMD;
break;
} }
up(&vicam->sem); up(&cam->busy_lock);
return err; return retval;
} }
static int vicam_v4l_close(struct inode *inode, struct file *file) static int
vicam_open(struct inode *inode, struct file *file)
{ {
struct video_device *vdev = file->private_data; struct video_device *dev = video_devdata(file);
struct usb_vicam *vicam = (struct usb_vicam *)vdev; struct vicam_camera *cam =
(struct vicam_camera *) dev->priv;
DBG("open\n");
if (!cam) {
printk(KERN_ERR
"vicam video_device improperly initialized");
}
dbg("vicam_v4l_close"); down_interruptible(&cam->busy_lock);
down(&vicam->sem); if (cam->open_count > 0) {
printk(KERN_INFO
"vicam_open called on already opened camera");
up(&cam->busy_lock);
return -EBUSY;
}
#ifdef BLINKING if (!cam->raw_image) {
info ("led off"); cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL);
vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x00, NULL, 0); if (!cam->raw_image) {
// vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x00, NULL, 0); Leave it on up(&cam->busy_lock);
#endif 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;
}
rvfree(vicam->fbuf, vicam->maxframesize * VICAM_NUMFRAMES); set_camera_power(cam, 1);
vicam->fbuf = 0;
vicam->open_count=0; cam->needsDummyRead = 1;
file->private_data = NULL; cam->open_count++;
up(&cam->busy_lock);
file->private_data = cam;
up(&vicam->sem);
/* Why does se401.c have a usbdevice check here? */
/* If device is unplugged while open, I guess we only may unregister now */
return 0; return 0;
} }
static int vicam_v4l_read(struct file *file, char *user_buf, static int
size_t buflen, loff_t *ppos) vicam_close(struct inode *inode, struct file *file)
{ {
struct video_device *vdev = file->private_data; struct vicam_camera *cam = file->private_data;
//struct usb_vicam *vicam = (struct usb_vicam *)vdev; DBG("close\n");
set_camera_power(cam, 0);
dbg("vicam_v4l_read(%d)", buflen); cam->open_count--;
if (!vdev || !buf) return 0;
return -EFAULT; }
if (copy_to_user(user_buf, buf2, buflen)) inline int pin(int x)
return -EFAULT; {
return buflen; return((x > 255) ? 255 : ((x < 0) ? 0 : x));
} }
static int vicam_v4l_do_ioctl(struct inode *inode, struct file *file, inline void writepixel(char *rgb, int Y, int Cr, int Cb)
unsigned int cmd, void *arg)
{ {
struct video_device *vdev = file->private_data; Y = 1160 * (Y - 16);
struct usb_vicam *vicam = (struct usb_vicam *)vdev;
int ret = -EL3RST;
if (!vicam->udev) rgb[2] = pin( ( ( Y + ( 1594 * Cr ) ) + 500 ) / 1300 );
return -EIO; rgb[1] = pin( ( ( Y - ( 392 * Cb ) - ( 813 * Cr ) ) + 500 ) / 1000 );
rgb[0] = pin( ( ( Y + ( 2017 * Cb ) ) + 500 ) / 900 );
}
down(&vicam->sem); #define DATA_HEADER_SIZE 64
switch (cmd) { // --------------------------------------------------------------------------------
case VIDIOCGCAP: // 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)
{
int x,y;
int Cr, Cb;
int sign;
int prevX, nextX, prevY, nextY;
int skip;
unsigned char *src;
unsigned char *dst;
prevY = 512;
nextY = 512;
src = data + DATA_HEADER_SIZE;
dst = rgb;
for(y = 1; y < 241; y += 2)
{ {
struct video_capability *b = arg; // even line
ret = vicam_get_capability(vicam,b); sign = 1;
dbg("name %s",b->name); prevX = 1;
break; nextX = 1;
}
case VIDIOCGFBUF: skip = 0;
dst = rgb + (y-1)*320*3;
for(x = 0; x < 512; x++)
{ {
struct video_buffer *vb = arg; if(x == 512-1)
info("vicam_v4l_ioctl - VIDIOCGBUF - query frame buffer param"); nextX = -1;
/* frame buffer not supported, not used */
memset(vb, 0, sizeof(*vb)); Cr = sign * ((src[prevX] - src[0]) + (src[nextX] - src[0])) >> 1;
ret = 0; Cb = sign * ((src[prevY] - src[prevX + prevY]) + (src[prevY] - src[nextX + prevY]) + (src[nextY] - src[prevX + nextY]) + (src[nextY] - src[nextX + nextY])) >> 2;
break;
writepixel(
dst + ((x*5)>>3)*3,
src[0] + (sign * (Cr >> 1)),
Cr,
Cb);
src++;
sign *= -1;
prevX = -1;
} }
case VIDIOCGWIN:
prevY = -512;
if(y == (242 - 2))
nextY = -512;
// odd line
sign = 1;
prevX = 1;
nextX = 1;
skip = 0;
dst = rgb + (y)*320*3;
for(x = 0; x < 512; x++)
{ {
struct video_window *vw = arg; if(x == 512-1)
ret = vicam_get_window(vicam, vw); nextX = -1;
break;
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;
} }
case VIDIOCSWIN:
{
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); static void
break; read_frame(struct vicam_camera *cam, int framenum)
{
unsigned char request[16];
int realShutter;
int n;
int actual_length;
memset(request, 0, 16);
request[0] = cam->gain; // 0 = 0% gain, FF = 100% gain
request[1] = 0; // 512x242 capture
request[2] = 0x90; // the function of these two bytes
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 {
// Long exposure
realShutter = 15600 / cam->shutter_speed - 1;
request[4] = 0;
request[5] = 0;
request[6] = realShutter & 0xFF;
request[7] = realShutter >> 8;
} }
case VIDIOCSCHAN:
{ // Per John Markus Bjrndalen, byte at index 8 causes problems if it isn't 0
struct video_channel *v = arg; request[8] = 0;
ret = vicam_set_channel(vicam,v); // bytes 9-15 do not seem to affect exposure or image quality
break;
n = send_control_msg(cam->udev, 0x51, 0x80, 0, request, 16);
if (n < 0) {
printk(KERN_ERR
" Problem sending frame capture control message");
return;
} }
case VIDIOCGPICT:
{ n = usb_bulk_msg(cam->udev,
struct video_picture *p = arg; usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint),
ret = vicam_get_picture(vicam,p); cam->raw_image,
break; 512 * 242 + 128, &actual_length, HZ*10);
if (n < 0) {
printk(KERN_ERR "Problem during bulk read of frame data: %d\n",
n);
} }
case VIDIOCSPICT:
{ vicam_decode_color(cam->raw_image,
struct video_picture *p = arg; cam->framebuf +
ret = vicam_set_picture(vicam,p); framenum * VICAM_MAX_FRAME_SIZE );
break;
cam->framebuf_size =
320 * 240 * VICAM_BYTES_PER_PIXEL;
cam->framebuf_read_start = 0;
return;
}
static int
vicam_read( struct file *file, char *buf, size_t count, loff_t *ppos )
{
struct vicam_camera *cam = file->private_data;
DBG("read %d bytes.\n", (int) count);
if (!buf)
return -EINVAL;
if (!count)
return -EINVAL;
// This is some code that will hopefully allow us to do shell copies from
// the /dev/videoX to a file and have it actually work.
if (cam->framebuf_size != 0) {
if (cam->framebuf_read_start == cam->framebuf_size) {
cam->framebuf_size = cam->framebuf_read_start = 0;
return 0;
} else {
if (cam->framebuf_read_start + count <=
cam->framebuf_size) {
// count does not exceed available bytes
copy_to_user(buf,
(cam->framebuf) +
cam->framebuf_read_start, count);
cam->framebuf_read_start += count;
return count;
} else {
count =
cam->framebuf_size -
cam->framebuf_read_start;
copy_to_user(buf,
(cam->framebuf) +
cam->framebuf_read_start, count);
cam->framebuf_read_start = cam->framebuf_size;
return count;
} }
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:
{ down_interruptible(&cam->busy_lock);
int *frame = arg;
ret = vicam_sync_frame(vicam,*frame); if (cam->needsDummyRead) {
break; read_frame(cam, 0);
cam->needsDummyRead = 0;
} }
// 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: if (count > cam->framebuf_size)
case VIDIOCSFBUF: count = cam->framebuf_size;
case VIDIOCGTUNER:
case VIDIOCSTUNER:
case VIDIOCGFREQ:
case VIDIOCSFREQ:
case VIDIOCGAUDIO:
case VIDIOCSAUDIO:
case VIDIOCGUNIT:
ret = -EINVAL;
default: copy_to_user(buf, cam->framebuf, count);
{
info("vicam_v4l_ioctl - %ui",cmd);
ret = -ENOIOCTLCMD;
}
} /* end switch */
up(&vicam->sem); if (count != cam->framebuf_size)
return ret; cam->framebuf_read_start = count;
} else
cam->framebuf_size = 0;
static int vicam_v4l_ioctl(struct inode *inode, struct file *file, up(&cam->busy_lock);
unsigned int cmd, unsigned long arg)
{ return count;
return video_usercopy(inode, file, cmd, arg, vicam_v4l_do_ioctl);
} }
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) { DBG("vicam_mmap: %ld\n", size);
up(&vicam->sem);
return -EIO; /* We let mmap allocate as much as it wants because Linux was adding 2048 bytes
} * to the size the application requested for mmap and it was screwing apps up.
#if 0 if (size > VICAM_FRAMES*VICAM_MAX_FRAME_SIZE)
if (size > (((VICAM_NUMFRAMES * vicam->maxframesize) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) {
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);
up(&cam->busy_lock);
return 0; 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;
static void vicam_bulk(struct urb *urb) *start = page + off;
return len;
}
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"); if (!cam || !cam->proc_entry)
buf = kmalloc(0x1e480, GFP_KERNEL); return;
buf2 = kmalloc(0x1e480, GFP_KERNEL);
if ((!buf) || (!buf2)) { sprintf(name, "video%d", cam->vdev.minor);
printk("Not enough memory for vicam!\n"); remove_proc_entry(name, vicam_proc_root);
goto error; cam->proc_entry = NULL;
}
/* do we do aspect correction in kernel or not? */
vicam->sizes = 3;
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 */
vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, firmware1, sizeof(firmware1));
vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, findex1, sizeof(findex1));
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),
buf, 0x1e480, vicam_bulk, vicam);
printk(KERN_DEBUG "Submiting urb: %d\n", usb_submit_urb(vicam->readurb, GFP_KERNEL));
return 0;
error:
if (buf)
kfree(buf);
if (buf2)
kfree(buf2);
return 1;
} }
static int vicam_probe(struct usb_interface *intf, #endif
const struct usb_device_id *id)
int
vicam_video_init(struct video_device *vdev)
{ {
struct usb_device *udev = interface_to_usbdev(intf); // This would normally create the proc entry for this camera
struct usb_vicam *vicam; #ifdef CONFIG_PROC_FS
char *camera_name=NULL; vicam_create_proc_entry(vdev->priv);
#endif
return 0;
}
static struct file_operations vicam_fops = {
.owner = THIS_MODULE,
.open = vicam_open,
.release =vicam_close,
.read = vicam_read,
.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);
vicam = kmalloc (sizeof(struct usb_vicam), GFP_KERNEL); interface = &intf->altsetting[0];
if (vicam == NULL) {
err ("couldn't kmalloc vicam struct"); DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n",
return -ENOMEM; ifnum, (unsigned) (interface->bNumEndpoints));
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));
if (video_register_device(&vicam->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { cam->udev = dev;
err("video_register_device"); cam->bulkEndpoint = bulkEndpoint;
usb_free_urb(vicam->readurb);
kfree(vicam); if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) == -1) {
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); dev_set_drvdata ( &intf->dev, NULL );
usb_put_dev(cam->udev);
if (vicam) { cam->udev = NULL;
video_unregister_device(&vicam->vdev);
vicam->udev = NULL;
/*
vicam->frame[0].grabstate = FRAME_ERROR;
vicam->frame[1].grabstate = FRAME_ERROR;
*/
/* Free buffers and shit */ video_unregister_device(&cam->vdev);
info("%s disconnected", vicam->camera_name);
synchronize(vicam);
if (!vicam->open_count) { #ifdef CONFIG_PROC_FS
/* Other random junk */ vicam_destroy_proc_entry(cam);
usb_free_urb(vicam->readurb); #endif
kfree(vicam);
vicam = NULL;
}
}
}
/* usb specific object needed to register this driver with the usb subsystem */ if (cam->raw_image)
static struct usb_driver vicam_driver = { kfree(cam->raw_image);
.owner = THIS_MODULE, if (cam->framebuf)
.name = "vicam", rvfree(cam->framebuf,
.probe = vicam_probe, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
.disconnect = vicam_disconnect,
.id_table = vicam_table,
};
/****************************************************************************** kfree(cam);
*
* Module Routines
*
******************************************************************************/
MODULE_AUTHOR(DRIVER_AUTHOR); printk(KERN_DEBUG "ViCam-based WebCam disconnected\n");
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) /*
*/
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