diff -Nru pwc-10.0.5.orig/ChangeLog pwc-10.0.5/ChangeLog --- pwc-10.0.5.orig/ChangeLog 2004-09-14 12:11:50.000000000 +0200 +++ pwc-10.0.5/ChangeLog 1970-01-01 01:00:00.000000000 +0100 @@ -1,143 +0,0 @@ -9.0.2 - -* Adding #ifdef to compile PWC before and after 2.6.5 - -9.0.1 - -9.0 - - -8.12 - -* Implement motorized pan/tilt feature for Logitech QuickCam Orbit/Spere. - -8.11.1 - -* Fix for PCVC720/40, would not be able to set videomode -* Fix for Samsung MPC models, appearantly they are based on a newer chipset - -8.11 - -* 20 dev_hints (per request) -* Hot unplugging should be better, no more dangling pointers or memory leaks -* Added reserved Logitech webcam IDs -* Device now remembers size & fps between close()/open() -* Removed palette stuff altogether - -8.10.1 - -* Added IDs for PCVC720K/40 and Creative Labs Webcam Pro - -8.10 - -* Fixed ID for QuickCam Notebook pro -* Added GREALSIZE ioctl() call -* Fixed bug in case PWCX was not loaded and invalid size was set - -8.9 - -* Merging with kernel 2.5.49 -* Adding IDs for QuickCam Zoom & QuickCam Notebook - -8.8 - -* Fixing 'leds' parameter -* Adding IDs for Logitech QuickCam Pro 4000 -* Making URB init/cleanup a little nicer - -8.7 - -* Incorporating changes in ioctl() parameter passing -* Also changes to URB mechanism - -8.6 - -* Added ID's for Visionite VCS UM100 and UC300 -* Removed YUV420-interlaced palette altogether (was confusing) -* Removed MIRROR stuff as it didn't work anyway -* Fixed a problem with the 'leds' parameter (wouldn't blink) -* Added ioctl()s for advanced features: 'extended' whitebalance ioctl()s, - CONTOUR, BACKLIGHT, FLICKER, DYNNOISE. -* VIDIOCGCAP.name now contains real camera model name instead of - 'Philips xxx webcam' -* Added PROBE ioctl (see previous point & API doc) - -8.5 - -* Adding IDs for Creative Labs Webcam 5 -* Adding IDs for SOTEC CMS-001 webcam -* Solving possible hang in VIDIOCSYNC when unplugging the cam -* Forgot to return structure in VIDIOCPWCGAWB, oops -* Time interval for the LEDs are now in milliseconds - -8.4 - -* Fixing power_save option for Vesta range -* Handling new error codes in ISOC callback -* Adding dev_hint module parameter, to specify /dev/videoX device nodes - -8.3 - -* Adding Samsung C10 and C30 cameras -* Removing palette module parameter -* Fixed typo in ID of QuickCam 3000 Pro -* Adding LED settings (blinking while in use) for ToUCam cameras. -* Turns LED off when camera is not in use. - -8.2 - -* Making module more silent when trace = 0 -* Adding QuickCam 3000 Pro IDs -* Chrominance control for the Vesta cameras -* Hopefully fixed problems on machines with BIGMEM and > 1GB of RAM -* Included Oliver Neukem's lock_kernel() patch -* Allocates less memory for image buffers -* Adds ioctl()s for the whitebalancing - -8.1 - -* Adding support for 750 -* Adding V4L GAUDIO/SAUDIO/UNIT ioctl() calls - -8.0 -* 'damage control' after inclusion in 2.4.5. -* Changed wait-queue mechanism in read/mmap/poll according to the book. -* Included YUV420P palette. -* Changed interface to decompressor module. -* Cleaned up pwc structure a bit. - -7.0 - -* Fixed bug in vcvt_420i_yuyv; extra variables on stack were misaligned. -* There is now a clear error message when an image size is selected that - is only supported using the decompressor, and the decompressor isn't - loaded. -* When the decompressor wasn't loaded, selecting large image size - would create skewed or double images. - -6.3 - -* Introduced spinlocks for the buffer pointer manipulation; a number of - reports seem to suggest the down()/up() semaphores were the cause of - lockups, since they are not suitable for interrupt/user locking. -* Separated decompressor and core code into 2 modules. - -6.2 - -* Non-integral image sizes are now padded with gray or black. -* Added SHUTTERSPEED ioctl(). -* Fixed buglet in VIDIOCPWCSAGC; the function would always return an error, - even though the call succeeded. -* Added hotplug support for 2.4.*. -* Memory: the 645/646 uses less memory now. - -6.1 - -* VIDIOCSPICT returns -EINVAL with invalid palettes. -* Added saturation control. -* Split decompressors from rest. -* Fixed bug that would reset the framerate to the default framerate if - the rate field was set to 0 (which is not what I intended, nl. do not - change the framerate!). -* VIDIOCPWCSCQUAL (setting compression quality) now takes effect immediately. -* Workaround for a bug in the 730 sensor. diff -Nru pwc-10.0.5.orig/Makefile pwc-10.0.5/Makefile --- pwc-10.0.5.orig/Makefile 2004-10-21 23:23:32.000000000 +0200 +++ pwc-10.0.5/Makefile 2005-11-26 15:48:20.000000000 +0100 @@ -1,42 +1,21 @@ +# Makefile for phpsview # -# Makefile for the Linux Philips USB Webcam driver -# -# NOTE: This make file can serve as both an external Makefile (launched -# directly by the user), or as the sub-dir Makefile used by the kernel -# build system. - -# If CONFIG_USB_PWC isn't set, we'll assume the user want to build this driver has a module - -ifndef CONFIG_USB_PWC -CONFIG_USB_PWC=m -endif - -ifneq ($(KERNELRELEASE),) - -pwc-objs := pwc-if.o pwc-misc.o pwc-ctrl.o pwc-uncompress.o pwc-dec1.o pwc-dec23.o pwc-kiara.o pwc-timon.o - -obj-$(CONFIG_USB_PWC) += pwc.o - -else -KVER := $(shell uname -r) -KLINK := $(shell test -e /lib/modules/${KVER}/source/ && echo source || echo build) -KDIR := /lib/modules/$(KVER)/$(KLINK) -KMISC := /lib/modules/$(KVER)/kernel/drivers/usb/media -PWD := $(shell pwd) - - - -default: - $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules - -install: default - install -d $(KMISC) - install -m 644 -c pwc.ko $(KMISC) - /sbin/depmod -a - -endif - -clean: - rm -f *.[oas] .*.flags *.ko .*.cmd .*.d .*.tmp *.mod.c - rm -rf .tmp_versions +CC=gcc +PREFIX ?= /usr/local +BINDIR ?= ${PREFIX}/bin +MANDIR ?= ${PREFIX}/man + +PROG = phpsview +SRCS = phpsview.c linux_usbif.c gui.c pwc-ctrl.c pwc-if.c pwc-misc.c pwc-kiara.c pwc-timon.c pwc-dec23.c pwc-dec1.c pwc-uncompress.c +MAN = phpsview.1 +MAN1 = phpsview.1 + +GTKCFLAGS != gtk-config --cflags +IMLIBCFLAGS != imlib-config --cflags-gdk +CFLAGS += -g -Wall ${GTKCFLAGS} ${IMLIBCFLAGS} + +GTKLDFLAGS != gtk-config --libs +IMLIBLDFLAGS!= imlib-config --libs-gdk +LDFLAGS += -Wall ${GTKLDFLAGS} ${IMLIBLDFLAGS} +.include diff -Nru pwc-10.0.5.orig/Makefile.phpsshot pwc-10.0.5/Makefile.phpsshot --- pwc-10.0.5.orig/Makefile.phpsshot 1970-01-01 01:00:00.000000000 +0100 +++ pwc-10.0.5/Makefile.phpsshot 2004-12-02 19:22:24.000000000 +0100 @@ -0,0 +1,18 @@ +# Makefile for phpsshot +# +PREFIX ?= /usr/local +BINDIR ?= ${PREFIX}/bin +MANDIR ?= ${PREFIX}/man + +PROG = phpsshot +SRCS = phpsshot.c linux_usbif.c pwc-ctrl.c pwc-if.c pwc-misc.c pwc-kiara.c pwc-timon.c pwc-dec23.c pwc-dec1.c pwc-uncompress.c + +MAN = phpsshot.1 +MAN1 = phpsshot.1 + +CFLAGS += -Wall + +LDFLAGS += -Wall + + +.include diff -Nru pwc-10.0.5.orig/Makefile.phpsview pwc-10.0.5/Makefile.phpsview --- pwc-10.0.5.orig/Makefile.phpsview 1970-01-01 01:00:00.000000000 +0100 +++ pwc-10.0.5/Makefile.phpsview 2005-11-26 15:48:20.000000000 +0100 @@ -0,0 +1,21 @@ +# Makefile for phpsview +# +CC=gcc +PREFIX ?= /usr/local +BINDIR ?= ${PREFIX}/bin +MANDIR ?= ${PREFIX}/man + +PROG = phpsview +SRCS = phpsview.c linux_usbif.c gui.c pwc-ctrl.c pwc-if.c pwc-misc.c pwc-kiara.c pwc-timon.c pwc-dec23.c pwc-dec1.c pwc-uncompress.c +MAN = phpsview.1 +MAN1 = phpsview.1 + +GTKCFLAGS != gtk-config --cflags +IMLIBCFLAGS != imlib-config --cflags-gdk +CFLAGS += -g -Wall ${GTKCFLAGS} ${IMLIBCFLAGS} + +GTKLDFLAGS != gtk-config --libs +IMLIBLDFLAGS!= imlib-config --libs-gdk +LDFLAGS += -Wall ${GTKLDFLAGS} ${IMLIBLDFLAGS} + +.include diff -Nru pwc-10.0.5.orig/README.BSD pwc-10.0.5/README.BSD --- pwc-10.0.5.orig/README.BSD 1970-01-01 01:00:00.000000000 +0100 +++ pwc-10.0.5/README.BSD 2006-01-29 23:57:53.000000000 +0100 @@ -0,0 +1,163 @@ + USB Philips webcam Image Capture Programs 0.06 for NetBSD/FreeBSD + + This patches have been written by Takafumi Mizuno and Vincent Hourdin + +Philips USB Cameras Utilities for NetBSD/FreeBSD +----------------------------------------------- + +1. What is it? + phpsshot ... simple image capture program ( output stdout PPM file ) + phpsview ... sequential image viewer program ( about 3fps, even with decompression ) + +2. What are supported USB camera? + + Vendor Device Product Name(Sensor name) + ------ ------ ---------------------------------- + 0x046d 0x08b1 Logitech QuickCam Notebook Pro + 0x046d 0x08b2 Logitech QuickCam Pro 4000 + 0x041e 0x400c Creative Labs Webcam 5 + 0x0471 0x0311 Philips ToUCam Pro + + Maybe a camera that has a same CCD will work. + + Same CCD cameras + - Logitech QuickCam Pro 3000 + - Logitech QuickCam Zoom + - Logitech QuickCam Zoom(new model) + - Logitech QuickCam Orbit/Sphere + - Creative Labs Webcam Pro Ex + - Samsung MPC-C30 + - Visionite VCS-UC300 + + +2. How to compile? + a) Check your system. + I tested below: + NetBSD 1.6.2 and NetBSD 2.0.2 + I caught reports below: + FreeBSD 5.2-RC(03/12/27) + phpsview requires below: + - gtk+-1.2.?? ( I tested 1.2.10 ) + - imlib 1.9.?? ( I tested 1.9.14 and 15 ) + + - for NetBSD and Model that has a built-in microphone users. + NetBSD Generic kernel configured Qcam Pro 4000 as uaudio(4). + because it has a built-in microphone. + You may rebuild a kernel without uaudio(4) or apply a patch below + that configured Qcam Pro 4000(and Notebook Pro) as ugen(4). + + Patch file for NetBSD 1.6.2_RC3 (you can do the same to other versions). + For example: + cd /usr/src/sys + cat ${YOUR_DOWNLOAD_DIR}/phpsview-netbsd-sys-1.6.2.diff | patch -p0 + cd dev/usb + make -f Makefile.usbdevs + cd ../../arch/i386/conf + config GENERIC + cd ../compile/GENERIC + make depend + make + make install + and reboot. + + b1) Download Linux Philips USB webcams driver and BSD patch: + from http://www.saillard.org/linux/pwc/ : + 'pwc-10.0.5.tar.bz2' is supported by pwc-10.0.5-bsd-0.04.patch.gz (0.04) patch. + 'pwc-10.0.5.tar.bz2' is supported by pwc-10.0.5-bsd-0.05.patch.gz (0.05) patch. + from http://www.smcc.demon.nl/webcam/ : + 'pwc-9.0.2.tar.gz' is supported by pwc-9.0.2-bsd-0.03.patch.gz (0.03) patch. (deprecated, no vga) + 'pwc-8.12.tar.gz' is supported by http://www2.starcat.ne.jp/~takam/bsd/NetBSD.html patch. (deprecated, no vga) + + b2) Download tarball and go to d): + from http://vinvin.dyndns.org/projects/pwc-10.0.5-bsd-0.06.tar.gz + + c) Extract and Applied patch. + for example: + % tar -zxvf ${YOUR_DOWNLOAD_DIR}/pwc-10.0.5.tar.gz + % gzip -dc pwc-10.0.5-bsd-0.04.patch.gz | patch -p0 + + d) Do make + % cd pwc-10.0.5/ or cd pwc-9.0.2/2.4/ or pwc-8.12/2.4/ + % make -f Makefile.phpsshot + % su root -c 'make -f Makefile.phpsshot install' + % make -f Makefile.phpsview + % su root -c 'make -f Makefile.phpsview install' + +3. How to use? +3.1. phpsshot + a) usage: phpsshot [devname] + + for Example. + % phpsshot > output.ppm + + % phpsshot | ppmtojpeg > output.jpg + + b) Command line options. + [devname] specify ugen device name. ex. /dev/ugen0.00 + + If no device file is specified, the program will cycle through the + /dev/ugen0, /dev/ugen1, ... devices until it finds an attached Philips webcam. + +3.2. phpsview + a) usage: phpsview [-n] [devname] [resolution] [filename] [-ddump_interval] + + for Example. + % phpsview + % phpsview -d5000 tutu.pnm 160x120 /dev/ugen1.00 -n + + b) Command line options. + [-n] no display. does not open the window (can be used with dump). + [devname] specify ugen device name. ex. /dev/ugen0.00 + [resolution] specify capture resolution. ex. 320x240 + [filename] specify a file where a frame will be dumped each second (pnm format) + [-ddump_interval] set dump interval to dump_interval (used if filename provided) + + If no device file is specified, the program will cycle through the + /dev/ugen0, /dev/ugen1, ... devices until it finds an attached Philips webcam. + + +----------------------------------------------- +References: + Original author + http://www2.starcat.ne.jp/~takam/bsd/NetBSD.html + + Linux driver for Philips webcam + USB and Video4Linux interface part. + (C) 1999-2003 Nemosoft Unv. + http://www.smcc.demon.nl/webcam/ + Free pwc from Luc Saillard : + http://www.saillard.org/linux/pwc/ + + GNU/Linux OS Driver for the Quickcam Express + http://qce-ga.sourceforge.net/ + + NetBSD/FreeBSD Simple OV511 video capture program, version 1.0 + http://members.home.com/housel/projects.htm +----------------------------------------------- +Problems and Questions: + a) Builtin microphone is not used. + + b) Low performace, because those programs aren't device driver. + + c) There are header bit streams that I don't know. + + d) Other Philips cameras (PCA645/646, PCVC675/680/690) ware not worked. + I can't understand to VSYNC at above cameras. + +----------------------------------------------- +History: +2003-09-12 0.01 First release +2003-12-30 0.02 support Linux driver for Philips webcam pwc-8.12, + add man pages, add FreeBSD-5 support, add Qcam for Notebook pro +2004-10-30 0.03 support for pwc-9.0.2 +2004-11-25 0.04 support for pwc-10.0.5 with decompression (supports vga size) +2005-12-24 0.05 added command line options to specify resolution +2006-01-16 0.06 added command line options for frame dump, dump interval, and no display +----------------------------------------------- +Credits: +Thanks to GNU/Linux OS Driver for the Philips webcam developers. +Thanks to everyone who has tested this program and given me feedback on it. +----------------------------------------------- + +written by Takafumi Mizuno and rewritten by Vincent Hourdin. + diff -Nru pwc-10.0.5.orig/gui.c pwc-10.0.5/gui.c --- pwc-10.0.5.orig/gui.c 1970-01-01 01:00:00.000000000 +0100 +++ pwc-10.0.5/gui.c 2004-12-02 19:32:22.000000000 +0100 @@ -0,0 +1,132 @@ +/* + * GUI of sequential image capture program. + * gui.[ch] GUI and callback functions + * + * Copyright (C) 2003 Takafumi Mizuno + * + * Reference: Image Processing Program by Linux, author Iio Jun, ohmsha publishing + * ISBN:4-274-94623-1 ( Japanese Only! ) + */ +#include +#include +#include +#include "gui.h" +#include "phpsview.h" + +/* micro seconds */ +#define INTERVAL 200 + +/* display area */ +static GdkImlibImage *im = NULL; + +/* backing store pixmap area */ +static GdkPixmap *pixmap = NULL; + +/* interval timer tag */ +static gint ttag; + +/* set GUI */ +void gui_config(void) +{ + GtkWidget *main_window; + GtkWidget *aspframe; + GtkWidget *drawing_area; + + /* Top level Main Window */ + main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_signal_connect(GTK_OBJECT(main_window), "destroy", + GTK_SIGNAL_FUNC(gtk_main_quit), NULL); + + /* aspect frame */ + aspframe = gtk_aspect_frame_new(NULL,0.5,0.5,1.0,TRUE); + gtk_frame_set_shadow_type(GTK_FRAME(aspframe), GTK_SHADOW_NONE); + + im = get_new_frame(im); + if (im == NULL){ + fprintf(stderr, "get_new_frame failed!\n"); + return; + } + + /* display area */ + drawing_area = gtk_drawing_area_new(); + gtk_drawing_area_size(GTK_DRAWING_AREA(drawing_area), + im->rgb_width, im->rgb_height); + gtk_container_add(GTK_CONTAINER(main_window), aspframe); + gtk_container_add(GTK_CONTAINER(aspframe), drawing_area); + + /* signal configure */ + gtk_signal_connect(GTK_OBJECT(main_window), "destroy", + GTK_SIGNAL_FUNC(gtk_main_quit), NULL); + gtk_signal_connect(GTK_OBJECT(drawing_area), "expose_event", + GTK_SIGNAL_FUNC(exposed), NULL); + gtk_signal_connect(GTK_OBJECT(drawing_area), "configure_event", + GTK_SIGNAL_FUNC(configured), NULL); + gtk_widget_set_events(drawing_area, GDK_EXPOSURE_MASK); + + /* timer set */ + ttag = gtk_timeout_add(INTERVAL, (GtkFunction)update_screen, + (gpointer)drawing_area); + + /* display */ + gtk_widget_show_all(main_window); + return; +} + +/* configure(e.g. resize) event */ +gint configured(GtkWidget *widget, GdkEventConfigure *event) +{ + gint w, h; + + w = widget->allocation.width; + h = widget->allocation.height; + gdk_imlib_render(im, w, h); + + /* create new pixmap from new size image */ + if ( pixmap ) gdk_pixmap_unref(pixmap); + pixmap = gdk_imlib_move_image(im); + + return TRUE; +} + +/* exposed event */ +int exposed(GtkWidget *widget, GdkEventExpose *event) +{ + if (pixmap) gdk_draw_pixmap(widget->window, + widget->style->fg_gc[GTK_WIDGET_STATE(widget)], + pixmap, + event->area.x, event->area.y, + event->area.x, event->area.y, + event->area.width, event->area.height); + return TRUE; +} + +gint update_screen(GtkWidget *widget) +{ + GdkEventExpose e; + + if ( errnum > ERRNUM_LIMITS ) { + gtk_main_quit(); + return FALSE; + } + + e.type = GDK_EXPOSE; + e.window = widget->window; + e.area.x = 0; e.area.y = 0; + e.area.width = widget->allocation.width; + e.area.height = widget->allocation.height; + e.send_event = 0; e.count = 0; + + if ( e.window != NULL ) { + im = get_new_frame(im); + if ( im == NULL ) { + fprintf(stderr, "get_new_frame() failed\n"); + return TRUE; + } + configured(widget, NULL); + exposed(widget, &e); + } + + return TRUE; + +} + diff -Nru pwc-10.0.5.orig/gui.h pwc-10.0.5/gui.h --- pwc-10.0.5.orig/gui.h 1970-01-01 01:00:00.000000000 +0100 +++ pwc-10.0.5/gui.h 2004-11-23 00:21:12.000000000 +0100 @@ -0,0 +1,15 @@ +#ifndef _GUI_H_ +#define _GUI_H_ + +#include +#include + +/* prototype declaration */ +void gui_config(void); + +gint configured(GtkWidget *, GdkEventConfigure *); +int exposed(GtkWidget *, GdkEventExpose *); +gint update_screen(GtkWidget *); + + +#endif /* _GUI_H_ */ diff -Nru pwc-10.0.5.orig/linux_usbif.c pwc-10.0.5/linux_usbif.c --- pwc-10.0.5.orig/linux_usbif.c 1970-01-01 01:00:00.000000000 +0100 +++ pwc-10.0.5/linux_usbif.c 2004-12-02 19:32:43.000000000 +0100 @@ -0,0 +1,73 @@ +/* + * linux_usbif.c - Linux API; usb_control_msg() usb_set_interface() + * Copyright (C) 2003 Takafumi Mizuno + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +#include +#include + +#include "linux_usbif.h" + +/* Linux API rapper */ + +int usb_control_msg(struct usb_device *dev, unsigned int pipe, + u_int8_t request, u_int8_t requesttype, + u_int16_t value, u_int16_t index, void *data, u_int16_t size, int timeout) +{ + /* XXX pipe and timeout is dummy */ + struct usb_ctl_request ur; + + ur.ucr_request.bRequest = request; + ur.ucr_request.bmRequestType = requesttype; + USETW(ur.ucr_request.wValue, value); + USETW(ur.ucr_request.wIndex, index); + USETW(ur.ucr_request.wLength, size); + ur.ucr_data = data; + ur.ucr_flags = 0; + ur.ucr_actlen = 0; + + if (ioctl(dev->fd, USB_DO_REQUEST, &ur) < 0) { + return -1; + } + + return 0; + +} + +int usb_set_interface(struct usb_device *dev, int ifnum, int alternate) +{ + /* XXX ifnum is dummy */ + struct usb_alt_interface alt; /* interface/alternate selection */ + + alt.uai_config_index = USB_CURRENT_CONFIG_INDEX; + alt.uai_interface_index = 0; + alt.uai_alt_no = alternate; + if (ioctl(dev->fd, USB_SET_ALTINTERFACE, &alt) < 0) { + perror("USB_SET_ALTINTERFACE"); + return -1; + } + return 0; +} diff -Nru pwc-10.0.5.orig/linux_usbif.h pwc-10.0.5/linux_usbif.h --- pwc-10.0.5.orig/linux_usbif.h 1970-01-01 01:00:00.000000000 +0100 +++ pwc-10.0.5/linux_usbif.h 2004-11-23 16:51:56.000000000 +0100 @@ -0,0 +1,92 @@ +#ifndef __LINUX_USBIF__H +#define __LINUX_USBIF__H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define USB_DIR_OUT UT_WRITE +#define USB_DIR_IN UT_READ +#define USB_TYPE_VENDOR UT_VENDOR +#define USB_RECIP_DEVICE UT_DEVICE +#define USB_RECIP_INTERFACE UT_INTERFACE +#define USB_RECIP_ENDPOINT UT_ENDPOINT +#define USB_RECIP_OTHER UT_OTHER + +#define HZ 1000 /* dummy */ + +/* dummy */ +#define usb_sndctrlpipe(a,b) (b) +#define usb_rcvctrlpipe(a,b) (b) + +typedef u_int16_t __u16; +typedef int32_t __s32; +typedef u_int32_t __u32; + +/*#define printk printf*/ + +/* fake $kernel_source_top/include/linux/???.h */ +/* I referenced 2.4.?? */ +#define LINUX_VERSION_CODE 0x020400 +#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) + +struct devinfo{ + uint8_t class; + uint8_t subclass; + uint8_t protocol; + uint8_t bNumConfigurations; + uint16_t idVendor; + uint16_t idProduct; + uint16_t bcdDevice; +}; + +struct usb_device { + int fd; + int efd; + char epdevname[FILENAME_MAX]; + struct devinfo descriptor; + struct usb_config_desc configdesc; + struct usb_config_desc *actconfig; + struct usb_interface_desc interfacedesc; + struct usb_endpoint_desc endpointdesc; +}; + +/* fake $kernel_source_top/include/linux/a.out.h */ +/* original size = 0x400 too small!? */ +#define PAGE_SIZE 0x800 + +/* fake $kernel_source_top/include/linux/usb.h */ +int usb_control_msg(struct usb_device *dev, unsigned int pipe, + u_int8_t request, u_int8_t requesttype, + u_int16_t value, u_int16_t index, void *data, u_int16_t size, int timeout); + +int usb_set_interface(struct usb_device *dev, int ifnum, int alternate); + +/* from $kernel_source_top/include/linux/kernel.h */ +#define KERN_EMERG "<0>" /* system is unusable */ +#define KERN_ALERT "<1>" /* action must be taken immediately */ +#define KERN_CRIT "<2>" /* critical conditions */ +#define KERN_ERR "<3>" /* error conditions */ +#define KERN_WARNING "<4>" /* warning conditions */ +#define KERN_NOTICE "<5>" /* normal but significant condition */ +#define KERN_INFO "<6>" /* informational */ +#define KERN_DEBUG "<7>" /* debug-level messages */ + +/* XXX */ +#define MODULE_PARM(a,b) +#define MODULE_PARM_DESC(a,b) +#define MODULE_DESCRIPTION(a) +#define MODULE_AUTHOR(a) +#define MODULE_LICENSE(a) +#define MODULE_DEVICE_TABLE(a,b) + + +#endif /* __LINUX_USBIF__H */ diff -Nru pwc-10.0.5.orig/phpsshot.1 pwc-10.0.5/phpsshot.1 --- pwc-10.0.5.orig/phpsshot.1 1970-01-01 01:00:00.000000000 +0100 +++ pwc-10.0.5/phpsshot.1 2006-01-29 21:50:07.000000000 +0100 @@ -0,0 +1,63 @@ +.\"/*- +.\" * Copyright (c) 2003 Mizuno Takafumi +.\" * All rights reserved. +.\" * +.\" * Redistribution and use in source and binary forms, with or without +.\" * modification, are permitted provided that the following conditions +.\" * are met: +.\" * 1. Redistributions of source code must retain the above copyright +.\" * notice, this list of conditions and the following disclaimer. +.\" * 2. Redistributions in binary form must reproduce the above copyright +.\" * notice, this list of conditions and the following disclaimer in the +.\" * documentation and/or other materials provided with the distribution. +.\" * +.\" * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" * SUCH DAMAGE. +.\" * +.\" */ +.Dd December 30, 2003 +.Dt phpsshot 1 +.Os +.Sh NAME +.Nm phpsshot +.Nd simple image capture program for Philips USB Cameras +.Sh SYNOPSIS +.Nm phpsshot +.Op /dev/ugen?.00 +.Sh DESCRIPTION +.Nm +is a simple program to capture image for Philips USB Cameras. +.Pp +The captured image is PPM format as 640x480 size. It is written to the standard output. +.Pp +The following options are supported: +.Bl -tag -width indent +.It /dev/ugen?.00 +Specifies the ugen device name. If no device name is specified, +the program will cycle through the /dev/ugen0.00, /dev/ugen1.00, ... +devices until it finds an attached target camera. +.El +.Sh EXAMPLES +phpsshot \*[Gt] output.ppm +.Sh SEE ALSO +.Xr ugen 4 +.Sh REFERENCE +Linux driver for Philips webcam; http://www.smcc.demon.nl/webcam/ +.Sh SUPPORT CAMERAS +.Bl -tag -width indent -compact +.It Pa Vendor Device Product_Name(Sensor_name) +.It 0x046d 0x08b1 Logitech QuickCam Notebook Pro +.It 0x046d 0x08b2 Logitech QuickCam Pro 4000 +.El +.Sh AUTHORS +.An Mizuno Takafumi + diff -Nru pwc-10.0.5.orig/phpsshot.c pwc-10.0.5/phpsshot.c --- pwc-10.0.5.orig/phpsshot.c 1970-01-01 01:00:00.000000000 +0100 +++ pwc-10.0.5/phpsshot.c 2004-12-05 18:13:20.000000000 +0100 @@ -0,0 +1,351 @@ +/* + * Philips webcam Image Capture Program for NetBSD/FreeBSD, version 0.0 + * phpsshot - Simple image capture program. + * Copyright (C) 2003 Takafumi Mizuno + * + * Portions of this program were modeled after or adapted from the + * Philips webcam dirver for Linux by USB and Video4Linux interface part + * (C) 1999-2003 Nemosoft Unv.; see + * http://www.smcc.demon.nl/webcam/ + * + * This program is free software; you can redistribute it and/or modify + * 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 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "linux_usbif.h" +#include "pwc.h" +#include "pwc-ioctl.h" + +#include "phpsshot.h" +#define IFNUM 0 + +struct usb_device usbdev; +struct pwc_device *pwcdev; + +char dev[FILENAME_MAX]; + +#define LOCAL_FPS 10 +#define LOCAL_X 640 +#define LOCAL_Y 480 + +#define LOCAL_SIZE_RGB (LOCAL_X * LOCAL_Y * 3) +#define LOCAL_SIZE_YUV (LOCAL_SIZE_RGB / 2) + +#define MY_ENDP_SIZE 592 /* XXX 592... My camera's endpoint max packet size */ + +#define RAW_PKTSIZE (LOCAL_SIZE_YUV+TOUCAM_HEADER_SIZE+TOUCAM_TRAILER_SIZE) +#define STORE_BUFSIZE (RAW_PKTSIZE*2+(MY_ENDP_SIZE*2)) /* (MY_ENDP_SIZE*2) is margin */ + +#define MIN(a,b) ((a)<(b) ? (a) : (b)) + +unsigned char *storebuf; /* raw isoc packets data */ +unsigned char *grabbuf; /* native image format data from above */ +unsigned char *yuv; /* YUV420P image data from above */ +unsigned char *rgb; /* RGB image data from above */ + +static int pwc_grab(struct usb_device *udev); +static void outputppm(unsigned char *); +static void yuv420p2rgb( unsigned char *yuvbuf, unsigned char *rgbbuf ); + + +/*#define DUMPONLY*/ + +int main(int argc, char *argv[]) +{ + int i = 0; + int ret, exflag; + + if (((storebuf = malloc(STORE_BUFSIZE)) == NULL) || + ((grabbuf = malloc(RAW_PKTSIZE)) == NULL) || + ((yuv = malloc(LOCAL_SIZE_YUV)) == NULL) || + ((rgb = malloc(LOCAL_SIZE_RGB)) == NULL)){ + perror("malloc"); + exit(-1); + } + + /* module initial */ + usb_pwc_init(); + + /* + * check option + */ + if (argc == 1) { + /* search camera */ + for ( i = 0; i < 15; ++i ) { +#ifdef __FreeBSD__ + sprintf(dev, "/dev/ugen%d", i); +#else + sprintf(dev, "/dev/ugen%d.00", i); +#endif + if ( (usbdev.fd = open(dev, O_RDWR)) < 0 ) { + continue; + } + if ( (pwcdev = (struct pwc_device *)usb_pwc_probe(&usbdev, IFNUM)) == NULL ) { + close(usbdev.fd); + usbdev.fd = -1; + continue; + } else { + break; + } + } + } else { + if ( argv[1][0] != '/' ) { + fprintf(stderr, "usage: %s [device-name]\n", argv[0]); + fprintf(stderr, " [device-name] must be started slash \'/\' character.\n"); + exit(1); + } + strncpy(dev, argv[1], FILENAME_MAX-1); + if ( (usbdev.fd = open(dev, O_RDWR)) < 0 ) { + err(1, "%s", dev); + } else { + if ( (pwcdev = (struct pwc_device *)usb_pwc_probe(&usbdev, IFNUM)) == NULL ) { + close(usbdev.fd); + usbdev.fd = -1; + } + } + } + + if ( usbdev.fd < 0 ) { + fprintf(stderr, "Not found Philips Webcam, or Permission denied\n"); + exit(1); + } + + if ( pwc_video_open(pwcdev) < 0 ) { + usb_pwc_disconnect(&usbdev, (void *)pwcdev); + close(usbdev.fd); + exit(1); + } + + /* best quality is SIF(320x240) 5fps with uncompress mode. */ + if ( pwc_try_video_mode(pwcdev, LOCAL_X, LOCAL_Y, LOCAL_FPS, 0, 0) != 0) { + usb_pwc_disconnect(&usbdev, (void *)pwcdev); + close(usbdev.fd); + exit(1); + } + + /* open endpoint */ +#ifdef __FreeBSD__ + sprintf(usbdev.epdevname, "%s.%d", dev, pwcdev->vendpoint); +#else + sprintf(usbdev.epdevname, "%s.%02d", strtok(dev,"."), pwcdev->vendpoint); +#endif + if ((usbdev.efd = open(usbdev.epdevname, O_RDONLY)) < 0) { + perror(usbdev.epdevname); + pwc_video_close(pwcdev); + usb_pwc_disconnect(&usbdev, (void *)pwcdev); + close(usbdev.fd); + exit(1); + } + + /* image clear */ + memset((void *)grabbuf, 0, RAW_PKTSIZE); + +#define EXPOSURE_TIME 10 + exflag = 0; + for ( i = 0; i < EXPOSURE_TIME; i++ ) { + ret = pwc_grab(&usbdev); + if ( ret < 0 ) { + break; + } else if ( ret == 0 ) { + if ( i > 7 ) exflag = 1; + } /* when not found header, do nothing */ + if ((i%2) == 0) fprintf(stderr, " Say cheese! after %d\r", 5-(i/2)); + } + + if (exflag == 1) { + outputppm(rgb); + } else { + fprintf(stderr, "Error: Not found Image header.\n"); + } + + fprintf(stderr, "Closing %s.....",pwcdev->vdev_name); + close(usbdev.efd); + pwc_video_close(pwcdev); /* */ + usb_pwc_disconnect(&usbdev, (void *)pwcdev); + close(usbdev.fd); + fprintf(stderr, "Done.\n"); + free(storebuf); + free(grabbuf); + free(yuv); + free(rgb); + + return 0; +} + +static int pwc_grab(struct usb_device *udev) +{ + int totalsize, overchk; + int hdflag; + unsigned char *isodat, *searchp; + ssize_t readlen; +#ifdef DUMPONLY + int i; +#endif + + isodat = storebuf; + totalsize = 0; + overchk = 0; + readlen = 0; + + while ( totalsize < RAW_PKTSIZE*2 ) { + readlen = read(udev->efd, (void *)isodat, MY_ENDP_SIZE); + if ( readlen < 0 ) { + break; + } + isodat += readlen; + totalsize += readlen; + if ( ++overchk > (STORE_BUFSIZE/MY_ENDP_SIZE+1) ) break; + } + + if ( totalsize > STORE_BUFSIZE ) { + fprintf(stderr, "overrun error\n"); + return -1; + } + + /* search header */ + /* + * header bit stream that I found ... (uncompressed mode) + * 00 01 00 00 03 cb 04 bd + * 00 01 00 14 03 bc 04 ab + * 00 01 00 09 03 cc 04 7f + * 00 01 00 0b 04 60 04 ac + * 00 01 00 00 04 04 04 e2 + * 00 01 00 00 04 04 04 e3 + * 00 01 ff ff 04 4d 04 d3 + * 00 01 ff ff 04 4d 04 c7 + * 00 01 Xa Xb ** ** 04 ** <= check bytes (Xa == Xb) or (Xa == 00) + */ + searchp = storebuf; + hdflag = 0; + while ( searchp < isodat ) { + if ( + /* uncompressed 320x240x5*/ + (*searchp == 0x00 && (*(searchp+1) == 0x01) && (*(searchp+6) == 0x04) && + ((*(searchp+2) == *(searchp+3)) || (*(searchp+2) == 0x00))) || + + /* compressed 640x480x10 and few others, depending on camera */ + /* 20 0x 00 xx 04 xx xx xx */ + (*searchp == 0x20 && (*(searchp+1) <= 0x02) && (*(searchp+2) == 0x00) && + (*(searchp+4) == 0x04)) + ){ + /* found header */ + searchp += TOUCAM_HEADER_SIZE; + hdflag = 1; + break; + } + searchp++; + } + + if ( hdflag == 1 ) { + memcpy((void *)grabbuf, (void *)searchp, MIN(LOCAL_SIZE_YUV, totalsize - (searchp - storebuf))); + pwc_decompress(pwcdev); + yuv420p2rgb(yuv, rgb); + } else { +#ifdef DUMPONLY + isodat = storebuf; + for ( i = 0; i < totalsize; i++ ) { + printf("%02x ", *isodat++); + if (((i+1) % 16) == 0 ) printf("\n"); + } + return 0; +#else + fprintf(stderr, "header not found !\n"); + return 1; +#endif + } + + return 0; + +} + +static void outputppm(unsigned char *target) +{ + int i; + + if ( target == NULL ) return; +#ifdef DUMPONLY + return; +#endif + + printf("P6\n"); + printf("%d %d 255 ", LOCAL_X, LOCAL_Y); + + for ( i = 0; i < (LOCAL_SIZE_RGB); i+=3 ) { + printf("%c%c%c", + target[i], + target[i+1], + target[i+2]); + } + + return; +} + +static void yuv420p2rgb( unsigned char *yuvbuf, unsigned char *rgbbuf ) +{ + int i, j; + int halfoff; + unsigned char *yp, *up, *vp; + float y, u, v; + float r, g, b; + +#ifdef DUMPONLY + return; +#endif + + yp = yuvbuf; + up = yuvbuf + LOCAL_X * LOCAL_Y; + vp = up + (LOCAL_X/2) * (LOCAL_Y/2); + + for ( i = 0; i < LOCAL_Y; i++ ) { + for ( j = 0; j < LOCAL_X; j++ ) { + y = (float)*(yp + ( i * LOCAL_X + j )); + halfoff = (((i%2==1)?i-1:i)/2)*(LOCAL_X/2) + ((j%2==1)?j-1:j)/2; + u = (float)*(up + halfoff); + v = (float)*(vp + halfoff); + + /* convert to RGB from YUV */ + u = u - 128.0; + v = v - 128.0; + + r = 1.4*u + y; + g = 1.02 * y - 0.750 * u - 0.336 * v; + b = 1.77*v + y; + + if ( r > 255 ) r = 255; + if ( r < 0 ) r = 0; + if ( g > 255 ) g = 255; + if ( g < 0 ) g = 0; + if ( b > 255 ) b = 255; + if ( b < 0 ) b = 0; + + /* print data */ + *rgbbuf++ = (unsigned char)b; + *rgbbuf++ = (unsigned char)g; + *rgbbuf++ = (unsigned char)r; + } + } + + return; +} diff -Nru pwc-10.0.5.orig/phpsshot.cat1 pwc-10.0.5/phpsshot.cat1 --- pwc-10.0.5.orig/phpsshot.cat1 1970-01-01 01:00:00.000000000 +0100 +++ pwc-10.0.5/phpsshot.cat1 2004-11-25 13:03:01.000000000 +0100 @@ -0,0 +1,42 @@ +phpsshot(1) NetBSD Reference Manual phpsshot(1) + +NNAAMMEE + pphhppsssshhoott - simple image capture program for Philips USB Cameras + +SSYYNNOOPPSSIISS + pphhppsssshhoott [/dev/ugen?.00] + +DDEESSCCRRIIPPTTIIOONN + pphhppsssshhoott is a simple program to capture image for Philips USB Cameras. + + The captured image is PPM format as 320x240 size. It is written to the + standard output. + + The following options are supported: + + /dev/ugen?.00 + Specifies the ugen device name. If no device name is specified, + the program will cycle through the /dev/ugen0.00, /dev/ugen1.00, + ... devices until it finds an attached target camera. + +EEXXAAMMPPLLEESS + phpsshot > output.ppm + +SSEEEE AALLSSOO + ugen(4) + +RREEFFEERREENNCCEE + Linux driver for Philips webcam; http://www.smcc.demon.nl/webcam/ + +SSUUPPPPOORRTT CCAAMMEERRAASS + _V_e_n_d_o_r _D_e_v_i_c_e _P_r_o_d_u_c_t___N_a_m_e_(_S_e_n_s_o_r___n_a_m_e_) + 0x046d 0x08b1 Logitech QuickCam Notebook Pro + 0x046d 0x08b2 Logitech QuickCam Pro 4000 + +AAUUTTHHOORRSS + Mizuno Takafumi + + + + +NetBSD 1.6.2 December 30, 2003 1 diff -Nru pwc-10.0.5.orig/phpsshot.h pwc-10.0.5/phpsshot.h --- pwc-10.0.5.orig/phpsshot.h 1970-01-01 01:00:00.000000000 +0100 +++ pwc-10.0.5/phpsshot.h 2004-12-02 20:10:18.000000000 +0100 @@ -0,0 +1,13 @@ +#ifndef _INC_PHPSSHOT_H_ +#define _INC_PHPSSHOT_H_ + +extern struct usb_device usbdev; +extern struct pwc_device *pwcdev; + +extern unsigned char *storebuf; /* raw isoc packets data */ +extern unsigned char *grabbuf; /* native image format data from above */ +extern unsigned char *yuv; /* YUV420P image data from above */ +extern unsigned char *rgb; /* RGB image data from above */ + + +#endif /* _INC_PHPSSHOT_H_ */ diff -Nru pwc-10.0.5.orig/phpsview.1 pwc-10.0.5/phpsview.1 --- pwc-10.0.5.orig/phpsview.1 1970-01-01 01:00:00.000000000 +0100 +++ pwc-10.0.5/phpsview.1 2006-01-29 23:59:30.000000000 +0100 @@ -0,0 +1,82 @@ +.\"/*- +.\" * Copyright (c) 2003 Mizuno Takafumi +.\" * All rights reserved. +.\" * +.\" * Redistribution and use in source and binary forms, with or without +.\" * modification, are permitted provided that the following conditions +.\" * are met: +.\" * 1. Redistributions of source code must retain the above copyright +.\" * notice, this list of conditions and the following disclaimer. +.\" * 2. Redistributions in binary form must reproduce the above copyright +.\" * notice, this list of conditions and the following disclaimer in the +.\" * documentation and/or other materials provided with the distribution. +.\" * +.\" * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" * SUCH DAMAGE. +.\" * +.\" */ +.Dd January 16, 2006 +.Dt phpsview 1 +.Os +.Sh NAME +.Nm phpsview +.Nd sequential image capture and view program for Philips Cameras +.Sh SYNOPSIS +.Nm phpsview +.Op -n +.Op /dev/ugen?.00 +.Op 320x240 +.Op filename +.Op -ddump_interval +.Sh DESCRIPTION +.Nm +is a sequential image capture and view program for Philips USB Cameras. +.Pp +The default captured image size is 640x480. +.Pp +The following options are supported: +.Bl -tag -width indent +.It /dev/ugen?.00 +Specifies the ugen device name. If no device name is specified, +the program will cycle through the /dev/ugen0.00, /dev/ugen1.00, ... +devices until it finds an attached target camera. +.It 320x240 +Sets the capture resolution to 320x240. Can also be 160x120, 640x480 or whatever. +The original pwc driver supports all resolutions, coloring not used pixels if +real capture resolution is lower than requested size. +.It filename +If specified, an image will be dumped to that file every second. +Cannot begin with a digit nor /dev. +.It -ddump_interval +Sets dump interval for dump file. Time is in ms, for example -d1000 is every second. +Used if filename is specified. No space allowed. +.It -n +Turns on no display mode. The X window won't be open. You can use this only if a filename +is specified for dumping. +.El +.Sh SEE ALSO +.Xr ugen 4 +.Sh WEBPAGE OF PORTING FOR BSD +http://www2.starcat.ne.jp/~takam/bsd/NetBSD.html#qcamPro (formerly) and +http://vinvin.dyndns.org/projects/pwc_bsd.html (last versions) +.Sh REFERENCE +Linux driver for Philips webcam: http://www.saillard.org/linux/pwc/ and http://www.smcc.demon.nl/webcam/ +.Sh SUPPORT CAMERAS +.Bl -tag -width indent -compact +.It Pa Vendor Device Product_Name +.It 0x046d 0x08b1 Logitech QuickCam Notebook Pro +.It 0x046d 0x08b2 Logitech QuickCam Pro 4000 +.It 0x041e 0x400c Creative Labs Webcam 5 +.It 0x0471 0x0311 Philips ToUCam Pro +.El +.Sh AUTHORS +.An Mizuno Takafumi and Vincent Hourdin diff -Nru pwc-10.0.5.orig/phpsview.c pwc-10.0.5/phpsview.c --- pwc-10.0.5.orig/phpsview.c 1970-01-01 01:00:00.000000000 +0100 +++ pwc-10.0.5/phpsview.c 2006-01-30 00:01:26.000000000 +0100 @@ -0,0 +1,399 @@ +/* + * Philips webcam Sequential Image Capture Program for NetBSD, version 0.0 + * phpsview - Sequential image capture program. + * Copyright (C) 2003 Takafumi Mizuno + * + * Portions of this program were modeled after or adapted from the + * Philips WebCam driver for Linux (C) Luc Saillard: + * http://www.saillard.org/linux/pwc/ + * + * This program is free software; you can redistribute it and/or modify + * 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 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. + * + * Reference: Image Processing Program by Linux, author Iio Jun, ohmsha publishing + * ISBN:4-274-94623-1 ( Japanese Only! ) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gui.h" + +#include "linux_usbif.h" +#include "pwc.h" +#include "pwc-ioctl.h" + +#include "phpsview.h" +#define IFNUM 0 +/* #define FIND_HEADER (this is not working) */ + +struct usb_device usbdev; +struct pwc_device *pwcdev = NULL; + +char dev[FILENAME_MAX]; +char dumpfile[FILENAME_MAX]; +int dump_interval = 1000; + +#define LOCAL_FPS 10 + +#define MY_ENDP_SIZE 592 /* XXX 592... My camera's endpoint max packet size */ + +#define RAW_PKTSIZE (LOCAL_SIZE_YUV+TOUCAM_HEADER_SIZE+TOUCAM_TRAILER_SIZE) +#define STORE_BUFSIZE (RAW_PKTSIZE*2+(MY_ENDP_SIZE*2)) /* (MY_ENDP_SIZE*2) is margin */ + + +unsigned char *storebuf; /* raw isoc packets data */ +unsigned char *grabbuf; /* native image format data from above */ +unsigned char *yuv; /* YUV420P image data from above */ +unsigned char *rgb; /* RGB image data from above */ + +GdkImlibImage *get_new_frame(GdkImlibImage *); +static void yuv420p2rgb( unsigned char *yuvbuf, unsigned char *rgbbuf ); +void dump_frame(); +static void print_usage(char *argv); + +int errnum = 0; /* shared gui.c */ +int LOCAL_X = 640, LOCAL_Y = 480; +int LOCAL_SIZE_RGB; +int LOCAL_SIZE_YUV; +int no_display = 0; + + +int main(int argc, char *argv[]) +{ + int i = 0; + //int ioctl_arg; + + gtk_init(&argc, &argv); + gdk_imlib_init(); + + /* args parsing */ + for (i=1; i '9') + strncpy(dumpfile, argv[i], FILENAME_MAX-1); + else { + LOCAL_X = atoi(argv[i]); + if (LOCAL_X == 0 || LOCAL_X > 640 || + strlen(argv[i]) < 7 || argv[i][3] != 'x') + print_usage(*argv); + + LOCAL_Y = atoi(argv[i]+4); + if (LOCAL_Y == 0 || LOCAL_Y > 480) + print_usage(*argv); + } + } else { + if (!strncmp(argv[i], "/dev/", 5)) + strncpy(dev, argv[i], FILENAME_MAX-1); + else + strncpy(dumpfile, argv[i], FILENAME_MAX-1); + } + } + + if (no_display && dumpfile[0] == '\0') + print_usage(*argv); + + /* module initialisation */ + usb_pwc_init(); + + /* opening camera device */ + for ( i = -1; i < 15; ++i ) { + if (i == -1 && dev[0] == '\0') continue; + if (i >= 0){ +#ifdef __FreeBSD__ + sprintf(dev, "/dev/ugen%d", i); +#elif defined __NetBSD__ + sprintf(dev, "/dev/ugen%d.00", i); +#else +#error what device ? +#endif + } + if ( (usbdev.fd = open(dev, O_RDWR)) < 0 ) { + if (i == -1) break; + continue; + } + if ( (pwcdev = (struct pwc_device *)usb_pwc_probe(&usbdev, IFNUM)) == NULL ) { + close(usbdev.fd); + usbdev.fd = -1; + if (i == -1) break; + continue; + } else { + break; + } + } + + if ( usbdev.fd < 0 ) { + fprintf(stderr, "Not found Philips Webcam, or Permission denied\n"); + exit(1); + } + + if ( pwc_video_open(pwcdev) < 0 ) { + usb_pwc_disconnect(&usbdev, (void *)pwcdev); + close(usbdev.fd); + exit(1); + } + + if ( pwc_try_video_mode(pwcdev, LOCAL_X, LOCAL_Y, LOCAL_FPS, 0, 0) != 0) { + usb_pwc_disconnect(&usbdev, (void *)pwcdev); + close(usbdev.fd); + exit(1); + } + + /* open endpoint */ +#ifdef __FreeBSD__ + sprintf(usbdev.epdevname, "%s.%d", dev, pwcdev->vendpoint); +#elif defined __NetBSD__ + sprintf(usbdev.epdevname, "%s.%02d", strtok(dev,"."), pwcdev->vendpoint); +#else +#error what device ? +#endif + if ((usbdev.efd = open(usbdev.epdevname, O_RDONLY)) < 0) { + perror(usbdev.epdevname); + pwc_video_close(pwcdev); + usb_pwc_disconnect(&usbdev, (void *)pwcdev); + close(usbdev.fd); + exit(1); + } + + printf("Using resolution %dx%d\n", LOCAL_X, LOCAL_Y); + if (dumpfile[0] != '\0') + printf("frames will be dumped to %s every %d ms.\n", dumpfile, dump_interval); +#if 0 + ioctl_arg = 1; + if (ioctl(usbdev.efd, USB_SET_SHORT_XFER, &ioctl_arg)) + perror("ioctl"); + + ioctl_arg = 120; + if (ioctl(usbdev.efd, USB_SET_TIMEOUT, &ioctl_arg)) + perror("ioctl"); +#endif + LOCAL_SIZE_RGB = (LOCAL_X * LOCAL_Y * 3); + LOCAL_SIZE_YUV = (LOCAL_SIZE_RGB / 2); + if (((storebuf = malloc(STORE_BUFSIZE)) == NULL) || + ((grabbuf = malloc(RAW_PKTSIZE)) == NULL) || + ((yuv = malloc(LOCAL_SIZE_YUV)) == NULL) || + ((rgb = malloc(LOCAL_SIZE_RGB)) == NULL)){ + perror("malloc"); + exit(-1); + } + + /* image clear */ + memset((void *)grabbuf, 0, RAW_PKTSIZE); + + if (no_display){ + while (1) + get_new_frame(NULL); + } else { + gui_config(); + gtk_main(); + } + + fprintf(stderr, "Closing %s.....",pwcdev->vdev_name); + close(usbdev.efd); + pwc_video_close(pwcdev); + usb_pwc_disconnect(&usbdev, (void *)pwcdev); + close(usbdev.fd); + fprintf(stderr, "Done.\n"); + free(storebuf); + free(grabbuf); + free(yuv); + free(rgb); + + return 0; +} + +/* Read raw-data from camera and convert to RGB24 +*/ +GdkImlibImage *get_new_frame(GdkImlibImage *current) +{ + int totalsize, overchk; + int hdflag; + unsigned char *isodat, *searchp; + struct usb_device *udev; + ssize_t readlen; + + isodat = storebuf; + totalsize = 0; + overchk = 0; + readlen = 0; + + udev = &usbdev; + + if ( errnum > ERRNUM_LIMITS ) { + fprintf(stderr,"Can't found image header. Program aborted.\n"); + errnum = (ERRNUM_LIMITS+1); + return NULL; + } + + while ( totalsize < RAW_PKTSIZE*2 ) { + readlen = read(udev->efd, (void *)isodat, MY_ENDP_SIZE); + if ( readlen < 0 ) { + perror("read"); + break; + } + isodat += readlen; + totalsize += readlen; + if ( ++overchk > (STORE_BUFSIZE/MY_ENDP_SIZE+1) ) break; + } + + if ( totalsize > STORE_BUFSIZE ) { + fprintf(stderr, "overrun error\n"); + return NULL; + } + + /* search header */ + /* + * header bit stream that I found ... + * see phpsshot.c + */ + searchp = storebuf; + hdflag = 0; + while ( searchp < isodat ) { +#ifdef FIND_HEADER + int i; + if (*searchp == 0x20){ + printf("header:"); + for (i=0; i<8; i++) + printf(" %02x", *(searchp+i)); + fputc('\n', stdout); + } +#endif + if ( + /* uncompressed */ + (*searchp == 0x00 && (*(searchp+1) == 0x01) && (*(searchp+6) == 0x04) && + ((*(searchp+2) == *(searchp+3)) || (*(searchp+2) == 0x00))) || + + /* compressed */ + /* 20 0x 00 xx 04 xx xx xx */ + (*searchp == 0x20 && (*(searchp+1) <= 0x02) && (*(searchp+2) == 0x00) && + (*(searchp+4) == 0x04)) + ){ + + /* found header */ + searchp += TOUCAM_HEADER_SIZE; + hdflag = 1; + break; + } + searchp++; + } + + if ( hdflag == 1 ) { + errnum = 0; + memcpy((void *)grabbuf, (void *)searchp, MIN(LOCAL_SIZE_YUV, totalsize-(searchp-storebuf))); + pwc_decompress(pwcdev); + yuv420p2rgb(yuv, rgb); + if (dumpfile[0] != '\0') + dump_frame(); + } else { + errnum++; + fprintf(stderr, "header not found !\n"); + return NULL; + } + + if (current) gdk_imlib_kill_image(current); + if (no_display) + return NULL; + return gdk_imlib_create_image_from_data(rgb, NULL, LOCAL_X, LOCAL_Y); +} + +static void yuv420p2rgb( unsigned char *yuvbuf, unsigned char *rgbbuf ) +{ + int i, j; + int halfoff; + unsigned char *yp, *up, *vp; + float y, u, v; + float r, g, b; + + yp = yuvbuf; + up = yuvbuf + LOCAL_X * LOCAL_Y; + vp = up + (LOCAL_X/2) * (LOCAL_Y/2); + + for ( i = 0; i < LOCAL_Y; i++ ) { + for ( j = 0; j < LOCAL_X; j++ ) { + y = (float)*(yp + ( i * LOCAL_X + j )); + halfoff = (((i%2==1)?i-1:i)/2)*(LOCAL_X/2) + ((j%2==1)?j-1:j)/2; + u = (float)*(up + halfoff); + v = (float)*(vp + halfoff); + + /* convert to RGB from YUV */ + u = u - 128.0; + v = v - 128.0; + + r = 1.4*u + y; + g = 1.02 * y - 0.750 * u - 0.336 * v; + b = 1.77*v + y; + + if ( r > 255 ) r = 255; + if ( r < 0 ) r = 0; + if ( g > 255 ) g = 255; + if ( g < 0 ) g = 0; + if ( b > 255 ) b = 255; + if ( b < 0 ) b = 0; + + /* print data */ + *rgbbuf++ = (unsigned char)b; + *rgbbuf++ = (unsigned char)g; + *rgbbuf++ = (unsigned char)r; + } + } + + return; +} + +void dump_frame(){ + int dump_fd; + static struct timeval last = {0, 0}; + struct timeval now; + gettimeofday(&now, NULL); + if ((now.tv_sec - last.tv_sec)*1000 + (now.tv_usec - last.tv_usec)/1000 < dump_interval) + return; + if ((dump_fd = open(dumpfile, O_WRONLY | O_CREAT | O_TRUNC, 0660)) == -1){ + fprintf(stderr, "could not open dump file %s for write, cancelled.\n", dumpfile); + dumpfile[0] = '\0'; + } else { + char header[16]; + int len = sprintf(header, "P6 %d %d 255\n", LOCAL_X, LOCAL_Y); + write(dump_fd, header, len); + write(dump_fd, rgb, LOCAL_SIZE_RGB); + close(dump_fd); + } + gettimeofday(&last, NULL); +} + +void print_usage(char *argv){ + fprintf(stderr, "\nusage: %s [-n] [device-name] [160x120 | 320x240 | 640x480] [filename] [-ddump_interval]\n", argv); + fprintf(stderr, "\t[-n] no display. Don't open window, dumping must be active to use this.\n"); + fprintf(stderr, "\t[device-name] the device used to grab pictures. Must begin with \"/dev/\" .\n"); + fprintf(stderr, "\t[320x240] capture resolution, can be max 640x480 and min 160x120.\n"); + fprintf(stderr, "\t[filename] capture file, can be any filename except /dev ones.\n"); + fprintf(stderr, "\t[-ddump_interval] dump interval in ms, used if filename is specified.\n\n"); + exit(1); +} diff -Nru pwc-10.0.5.orig/phpsview.cat1 pwc-10.0.5/phpsview.cat1 --- pwc-10.0.5.orig/phpsview.cat1 1970-01-01 01:00:00.000000000 +0100 +++ pwc-10.0.5/phpsview.cat1 2006-01-29 23:59:32.000000000 +0100 @@ -0,0 +1,61 @@ +phpsview(1) NetBSD General Commands Manual phpsview(1) + +NNAAMMEE + pphhppssvviieeww - sequential image capture and view program for Philips Cameras + +SSYYNNOOPPSSIISS + pphhppssvviieeww [-n] [/dev/ugen?.00] [320x240] [filename] [-ddump_interval] + +DDEESSCCRRIIPPTTIIOONN + pphhppssvviieeww is a sequential image capture and view program for Philips USB + Cameras. + + The default captured image size is 640x480. + + The following options are supported: + + /dev/ugen?.00 + Specifies the ugen device name. If no device name is specified, + the program will cycle through the /dev/ugen0.00, /dev/ugen1.00, + ... devices until it finds an attached target camera. + + 320x240 + Sets the capture resolution to 320x240. Can also be 160x120, + 640x480 or whatever. The original pwc driver supports all reso- + lutions, coloring not used pixels if real capture resolution is + lower than requested size. + + filename + If specified, an image will be dumped to that file every second. + Cannot begin with a digit nor /dev. + + -ddump_interval + Sets dump interval for dump file. Time is in ms, for example + -d1000 is every second. Used if filename is specified. No space + allowed. + + -n Turns on no display mode. The X window won't be open. You can use + this only if a filename is specified for dumping. + +SSEEEE AALLSSOO + ugen(4) + +WWEEBBPPAAGGEE OOFF PPOORRTTIINNGG FFOORR BBSSDD + http://www2.starcat.ne.jp/~takam/bsd/NetBSD.html#qcamPro (formerly) and + http://vinvin.dyndns.org/projects/pwc_bsd.html (last versions) + +RREEFFEERREENNCCEE + Linux driver for Philips webcam: http://www.saillard.org/linux/pwc/ and + http://www.smcc.demon.nl/webcam/ + +SSUUPPPPOORRTT CCAAMMEERRAASS + _V_e_n_d_o_r _D_e_v_i_c_e _P_r_o_d_u_c_t___N_a_m_e + 0x046d 0x08b1 Logitech QuickCam Notebook Pro + 0x046d 0x08b2 Logitech QuickCam Pro 4000 + 0x041e 0x400c Creative Labs Webcam 5 + 0x0471 0x0311 Philips ToUCam Pro + +AAUUTTHHOORRSS + Mizuno Takafumi and Vincent Hourdin + +NetBSD 2.0.2 January 16, 2006 NetBSD 2.0.2 diff -Nru pwc-10.0.5.orig/phpsview.h pwc-10.0.5/phpsview.h --- pwc-10.0.5.orig/phpsview.h 1970-01-01 01:00:00.000000000 +0100 +++ pwc-10.0.5/phpsview.h 2004-11-23 00:19:57.000000000 +0100 @@ -0,0 +1,20 @@ +#ifndef _INC_PHPSVIEW_H_ +#define _INC_PHPSVIEW_H_ + +#include +#include + +extern struct usb_device usbdev; +extern struct pwc_device *pwcdev; +extern GdkImlibImage *get_new_frame(GdkImlibImage *); +extern GdkImlibImage *get_first_frame(GdkImlibImage *); + +extern unsigned char *storebuf; /* raw isoc packets data */ +extern unsigned char *grabbuf; /* native image format data from above */ +extern unsigned char *yuv; /* YUV420P image data from above */ +extern unsigned char *rgb; /* RGB image data from above */ + +#define ERRNUM_LIMITS 9 +extern int errnum; + +#endif /* _INC_PHPSVIEW_H_ */ diff -Nru pwc-10.0.5.orig/pwc-ctrl.c pwc-10.0.5/pwc-ctrl.c --- pwc-10.0.5.orig/pwc-ctrl.c 2004-10-21 23:30:00.000000000 +0200 +++ pwc-10.0.5/pwc-ctrl.c 2004-12-02 19:37:29.000000000 +0100 @@ -4,45 +4,39 @@ (C) 1999-2003 Nemosoft Unv. (C) 2004 Luc Saillard (luc@saillard.org) - NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx - driver and thus may have bugs that are not present in the original version. - Please send bug reports and support requests to . - - NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx - driver and thus may have bugs that are not present in the original version. - Please send bug reports and support requests to . - The decompression routines have been implemented by reverse-engineering the - Nemosoft binary pwcx module. Caveat emptor. - - 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. - - 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. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx +driver and thus may have bugs that are not present in the original version. +Please send bug reports and support requests to . + +NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx +driver and thus may have bugs that are not present in the original version. +Please send bug reports and support requests to . +The decompression routines have been implemented by reverse-engineering the +Nemosoft binary pwcx module. Caveat emptor. + +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. + +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. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* Changes 2001/08/03 Alvarado Added methods for changing white balance and - red/green gains - */ + red/green gains + */ /* Control functions for the cam; brightness, contrast, video mode, etc. */ -#ifdef __KERNEL__ -#include -#endif -#include -#include - #include "pwc.h" #include "pwc-ioctl.h" #include "pwc-uncompress.h" @@ -129,9 +123,9 @@ /* Entries for the Nala (645/646) camera; the Nala doesn't have compression preferences, so you either get compressed or non-compressed streams. - + An alternate value of 0 means this mode is not available at all. - */ + */ struct Nala_table_entry { char alternate; /* USB alternate setting */ @@ -151,19 +145,19 @@ #define SendControlMsg(request, value, buflen) \ usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), \ - request, \ - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \ - value, \ - pdev->vcinterface, \ - &buf, buflen, HZ / 2) + request, \ + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \ + value, \ + pdev->vcinterface, \ + &buf, buflen, HZ / 2) #define RecvControlMsg(request, value, buflen) \ usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), \ - request, \ - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \ - value, \ - pdev->vcinterface, \ - &buf, buflen, HZ / 2) + request, \ + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \ + value, \ + pdev->vcinterface, \ + &buf, buflen, HZ / 2) #if PWC_DEBUG @@ -193,12 +187,12 @@ static inline int send_video_command(struct usb_device *udev, int index, void *buf, int buflen) { return usb_control_msg(udev, - usb_sndctrlpipe(udev, 0), - SET_EP_STREAM_CTL, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - VIDEO_OUTPUT_CONTROL_FORMATTER, - index, - buf, buflen, HZ); + usb_sndctrlpipe(udev, 0), + SET_EP_STREAM_CTL, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + VIDEO_OUTPUT_CONTROL_FORMATTER, + index, + buf, buflen, HZ); } @@ -210,24 +204,24 @@ struct Nala_table_entry *pEntry; int frames2frames[31] = { /* closest match of framerate */ - 0, 0, 0, 0, 4, /* 0-4 */ - 5, 5, 7, 7, 10, /* 5-9 */ - 10, 10, 12, 12, 15, /* 10-14 */ - 15, 15, 15, 20, 20, /* 15-19 */ - 20, 20, 20, 24, 24, /* 20-24 */ - 24, 24, 24, 24, 24, /* 25-29 */ - 24 /* 30 */ + 0, 0, 0, 0, 4, /* 0-4 */ + 5, 5, 7, 7, 10, /* 5-9 */ + 10, 10, 12, 12, 15, /* 10-14 */ + 15, 15, 15, 20, 20, /* 15-19 */ + 20, 20, 20, 24, 24, /* 20-24 */ + 24, 24, 24, 24, 24, /* 25-29 */ + 24 /* 30 */ }; int frames2table[31] = { 0, 0, 0, 0, 0, /* 0-4 */ - 1, 1, 1, 2, 2, /* 5-9 */ - 3, 3, 4, 4, 4, /* 10-14 */ - 5, 5, 5, 5, 5, /* 15-19 */ - 6, 6, 6, 6, 7, /* 20-24 */ - 7, 7, 7, 7, 7, /* 25-29 */ - 7 /* 30 */ + 1, 1, 1, 2, 2, /* 5-9 */ + 3, 3, 4, 4, 4, /* 10-14 */ + 5, 5, 5, 5, 5, /* 15-19 */ + 6, 6, 6, 6, 7, /* 20-24 */ + 7, 7, 7, 7, 7, /* 25-29 */ + 7 /* 30 */ }; - + if (size < 0 || size > PSZ_CIF || frames < 4 || frames > 25) return -EINVAL; frames = frames2frames[frames]; @@ -245,26 +239,26 @@ Debug("Failed to send video command... %d\n", ret); return ret; } - if (pEntry->compressed && pdev->vpalette != VIDEO_PALETTE_RAW) - { - switch(pdev->type) { - case 645: - case 646: - pwc_dec1_init(pdev->type, pdev->release, buf, pdev->decompress_data); - break; - - case 675: - case 680: - case 690: - case 720: - case 730: - case 740: - case 750: - pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); - break; - } + if (pEntry->compressed) + { + switch(pdev->type) { + case 645: + case 646: + pwc_dec1_init(pdev->type, pdev->release, buf, pdev->decompress_data); + break; + + case 675: + case 680: + case 690: + case 720: + case 730: + case 740: + case 750: + pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); + break; + } } - + pdev->cmd_len = 3; memcpy(pdev->cmd_buf, buf, 3); @@ -304,13 +298,13 @@ /* Find a supported framerate with progressively higher compression ratios if the preferred ratio is not available. - */ + */ pChoose = NULL; while (compression <= 3) { - pChoose = &Timon_table[size][fps][compression]; - if (pChoose->alternate != 0) - break; - compression++; + pChoose = &Timon_table[size][fps][compression]; + if (pChoose->alternate != 0) + break; + compression++; } if (pChoose == NULL || pChoose->alternate == 0) return -ENOENT; /* Not supported. */ @@ -322,8 +316,15 @@ if (ret < 0) return ret; - if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW) - pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); + if (pChoose->bandlength > 0){ + if (!pdev->decompress_data) + pdev->decompress_data = malloc(sizeof(struct pwc_dec23_private)); + + if (pdev->decompress_data == NULL){ + return -ENOMEM; + } + pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); + } pdev->cmd_len = 13; memcpy(pdev->cmd_buf, buf, 13); @@ -348,7 +349,6 @@ const struct Kiara_table_entry *pChoose = 0; int fps, ret; unsigned char buf[12]; - struct Kiara_table_entry RawEntry = {6, 773, 1272, {0xAD, 0xF4, 0x10, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x03, 0x80}}; if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3) return -EINVAL; @@ -362,23 +362,15 @@ /* Only available in case the raw palette is selected or we have the decompressor available. This mode is only available in compressed form - */ - if (pdev->vpalette == VIDEO_PALETTE_RAW) - { - Info("Choosing VGA/5 BAYER mode (%d).\n", pdev->vpalette); - pChoose = &RawEntry; - } - else - { - Info("VGA/5 BAYER mode _must_ have a decompressor available, or use RAW palette.\n"); - } + */ + Info("VGA/5 BAYER mode _must_ have a decompressor available, or use RAW palette.\n"); } else { - /* Find a supported framerate with progressively higher compression ratios + /* Find a supported framerate with progressively higher compression ratios if the preferred ratio is not available. - Skip this step when using RAW modes. - */ + Skip this step when using RAW modes. + */ while (compression <= 3) { pChoose = &Kiara_table[size][fps][compression]; if (pChoose->alternate != 0) @@ -390,7 +382,7 @@ return -ENOENT; /* Not supported. */ Debug("Using alternate setting %d.\n", pChoose->alternate); - + /* usb_control_msg won't take staticly allocated arrays as argument?? */ memcpy(buf, pChoose->mode, 12); if (snapshot) @@ -398,11 +390,19 @@ /* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */ ret = send_video_command(pdev->udev, 4 /* pdev->vendpoint */, buf, 12); - if (ret < 0) + if (ret < 0){ + Debug("send_video_command returned %d\n", ret); return ret; + } - if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW) - pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); + if (pChoose->bandlength > 0){ + if (!pdev->decompress_data) + pdev->decompress_data = malloc(sizeof(struct pwc_dec23_private)); + if (pdev->decompress_data == NULL){ + return -ENOMEM; + } + pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); + } pdev->cmd_len = 12; memcpy(pdev->cmd_buf, buf, 12); @@ -423,18 +423,18 @@ /** - @pdev: device structure - @width: viewport width - @height: viewport height - @frame: framerate, in fps - @compression: preferred compression ratio - @snapshot: snapshot mode or streaming - */ + @pdev: device structure + @width: viewport width + @height: viewport height + @frame: framerate, in fps + @compression: preferred compression ratio + @snapshot: snapshot mode or streaming + */ int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot) { - int ret, size; + int ret, size; - Trace(TRACE_FLOW, "set_video_mode(%dx%d @ %d, palette %d).\n", width, height, frames, pdev->vpalette); + Trace(TRACE_FLOW, "set_video_mode(%dx%d @ %d, palette %d).\n", width, height, frames, pdev->vpalette); size = pwc_decode_size(pdev, width, height); if (size < 0) { Debug("Could not find suitable size.\n"); @@ -442,25 +442,25 @@ } Debug("decode_size = %d.\n", size); - ret = -EINVAL; + ret = -EINVAL; switch(pdev->type) { - case 645: - case 646: - ret = set_video_mode_Nala(pdev, size, frames); - break; - - case 675: - case 680: - case 690: - ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot); - break; - - case 720: - case 730: - case 740: - case 750: - ret = set_video_mode_Kiara(pdev, size, frames, compression, snapshot); - break; + case 645: + case 646: + ret = set_video_mode_Nala(pdev, size, frames); + break; + + case 675: + case 680: + case 690: + ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot); + break; + + case 720: + case 730: + case 740: + case 750: + ret = set_video_mode_Kiara(pdev, size, frames, compression, snapshot); + break; } if (ret < 0) { if (ret == -ENOENT) @@ -474,27 +474,18 @@ pdev->view.y = height; pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size; pwc_set_image_buffer_size(pdev); + Trace(TRACE_SIZE, "Set viewport to %dx%d, image size is %dx%d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y); return 0; } - void pwc_set_image_buffer_size(struct pwc_device *pdev) { - int i, factor = 0, filler = 0; + int factor = 0, filler = 0; /* for PALETTE_YUV420P */ - switch(pdev->vpalette) - { - case VIDEO_PALETTE_YUV420P: - factor = 6; - filler = 128; - break; - case VIDEO_PALETTE_RAW: - factor = 6; /* can be uncompressed YUV420P */ - filler = 0; - break; - } + factor = 6; + filler = 128; /* Set sizes in bytes */ pdev->image.size = pdev->image.x * pdev->image.y * factor / 4; @@ -504,19 +495,12 @@ YUV420 mode... x must be multiple of 4 (to get the Y's in place), and y even (or you'll mixup U & V). This is less of a problem for YUV420P. - */ + */ pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC; pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE; - - /* Fill buffers with gray or black */ - for (i = 0; i < MAX_IMAGES; i++) { - if (pdev->image_ptr[i] != NULL) - memset(pdev->image_ptr[i], filler, pdev->view.size); - } } - /* BRIGHTNESS */ int pwc_get_brightness(struct pwc_device *pdev) @@ -573,7 +557,7 @@ { char buf; int ret; - + ret = RecvControlMsg(GET_LUM_CTL, GAMMA_FORMATTER, 1); if (ret < 0) return ret; @@ -629,14 +613,14 @@ { char buf; int ret; - + if (mode) buf = 0x0; /* auto */ else buf = 0xff; /* fixed */ ret = SendControlMsg(SET_LUM_CTL, AGC_MODE_FORMATTER, 1); - + if (!mode && ret >= 0) { if (value < 0) value = 0; @@ -654,7 +638,7 @@ { unsigned char buf; int ret; - + ret = RecvControlMsg(GET_LUM_CTL, AGC_MODE_FORMATTER, 1); if (ret < 0) return ret; @@ -690,7 +674,7 @@ buf[0] = 0x0; /* auto */ else buf[0] = 0xff; /* fixed */ - + ret = SendControlMsg(SET_LUM_CTL, SHUTTER_MODE_FORMATTER, 1); if (!mode && ret >= 0) { @@ -699,22 +683,22 @@ if (value > 0xffff) value = 0xffff; switch(pdev->type) { - case 675: - case 680: - case 690: - /* speed ranges from 0x0 to 0x290 (656) */ - speed = (value / 100); - buf[1] = speed >> 8; - buf[0] = speed & 0xff; - break; - case 720: - case 730: - case 740: - case 750: - /* speed seems to range from 0x0 to 0xff */ - buf[1] = 0; - buf[0] = value >> 8; - break; + case 675: + case 680: + case 690: + /* speed ranges from 0x0 to 0x290 (656) */ + speed = (value / 100); + buf[1] = speed >> 8; + buf[0] = speed & 0xff; + break; + case 720: + case 730: + case 740: + case 750: + /* speed seems to range from 0x0 to 0xff */ + buf[1] = 0; + buf[0] = value >> 8; + break; } ret = SendControlMsg(SET_LUM_CTL, PRESET_SHUTTER_FORMATTER, 2); @@ -761,33 +745,33 @@ return SendControlMsg(SET_STATUS_CTL, RESTORE_FACTORY_DEFAULTS_FORMATTER, 0); } - /* ************************************************* */ - /* Patch by Alvarado: (not in the original version */ +/* ************************************************* */ +/* Patch by Alvarado: (not in the original version */ - /* - * the camera recognizes modes from 0 to 4: - * - * 00: indoor (incandescant lighting) - * 01: outdoor (sunlight) - * 02: fluorescent lighting - * 03: manual - * 04: auto - */ +/* + * the camera recognizes modes from 0 to 4: + * + * 00: indoor (incandescant lighting) + * 01: outdoor (sunlight) + * 02: fluorescent lighting + * 03: manual + * 04: auto + */ static inline int pwc_set_awb(struct pwc_device *pdev, int mode) { char buf; int ret; - + if (mode < 0) - mode = 0; - + mode = 0; + if (mode > 4) - mode = 4; - + mode = 4; + buf = mode & 0x07; /* just the lowest three bits */ - + ret = SendControlMsg(SET_CHROM_CTL, WB_MODE_FORMATTER, 1); - + if (ret < 0) return ret; return 0; @@ -797,7 +781,7 @@ { unsigned char buf; int ret; - + ret = RecvControlMsg(GET_CHROM_CTL, WB_MODE_FORMATTER, 1); if (ret < 0) @@ -807,7 +791,7 @@ static inline int pwc_set_red_gain(struct pwc_device *pdev, int value) { - unsigned char buf; + unsigned char buf; if (value < 0) value = 0; @@ -822,10 +806,10 @@ { unsigned char buf; int ret; - + ret = RecvControlMsg(GET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, 1); if (ret < 0) - return ret; + return ret; *value = buf << 8; return 0; } @@ -848,10 +832,10 @@ { unsigned char buf; int ret; - + ret = RecvControlMsg(GET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, 1); if (ret < 0) - return ret; + return ret; *value = buf << 8; return 0; } @@ -860,12 +844,12 @@ /* The following two functions are different, since they only read the internal red/blue gains, which may be different from the manual gains set or read above. - */ + */ static inline int pwc_read_red_gain(struct pwc_device *pdev, int *value) { unsigned char buf; int ret; - + ret = RecvControlMsg(GET_STATUS_CTL, READ_RED_GAIN_FORMATTER, 1); if (ret < 0) return ret; @@ -877,7 +861,7 @@ { unsigned char buf; int ret; - + ret = RecvControlMsg(GET_STATUS_CTL, READ_BLUE_GAIN_FORMATTER, 1); if (ret < 0) return ret; @@ -889,7 +873,7 @@ static inline int pwc_set_wb_speed(struct pwc_device *pdev, int speed) { unsigned char buf; - + /* useful range is 0x01..0x20 */ buf = speed / 0x7f0; return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, 1); @@ -899,7 +883,7 @@ { unsigned char buf; int ret; - + ret = RecvControlMsg(GET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, 1); if (ret < 0) return ret; @@ -911,7 +895,7 @@ static inline int pwc_set_wb_delay(struct pwc_device *pdev, int delay) { unsigned char buf; - + /* useful range is 0x01..0x3F */ buf = (delay >> 10); return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, 1); @@ -921,7 +905,7 @@ { unsigned char buf; int ret; - + ret = RecvControlMsg(GET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, 1); if (ret < 0) return ret; @@ -957,7 +941,7 @@ { unsigned char buf[2]; int ret; - + if (pdev->type < 730) { *on_value = -1; *off_value = -1; @@ -976,7 +960,7 @@ { unsigned char buf; int ret; - + if (contour < 0) buf = 0xff; /* auto contour on */ else @@ -984,12 +968,12 @@ ret = SendControlMsg(SET_LUM_CTL, AUTO_CONTOUR_FORMATTER, 1); if (ret < 0) return ret; - + if (contour < 0) return 0; if (contour > 0xffff) contour = 0xffff; - + buf = (contour >> 10); /* contour preset is [0..3f] */ ret = SendControlMsg(SET_LUM_CTL, PRESET_CONTOUR_FORMATTER, 1); if (ret < 0) @@ -1001,7 +985,7 @@ { unsigned char buf; int ret; - + ret = RecvControlMsg(GET_LUM_CTL, AUTO_CONTOUR_FORMATTER, 1); if (ret < 0) return ret; @@ -1022,7 +1006,7 @@ static inline int pwc_set_backlight(struct pwc_device *pdev, int backlight) { unsigned char buf; - + if (backlight) buf = 0xff; else @@ -1034,7 +1018,7 @@ { int ret; unsigned char buf; - + ret = RecvControlMsg(GET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1); if (ret < 0) return ret; @@ -1046,7 +1030,7 @@ static inline int pwc_set_flicker(struct pwc_device *pdev, int flicker) { unsigned char buf; - + if (flicker) buf = 0xff; else @@ -1058,7 +1042,7 @@ { int ret; unsigned char buf; - + ret = RecvControlMsg(GET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1); if (ret < 0) return ret; @@ -1083,7 +1067,7 @@ { int ret; unsigned char buf; - + ret = RecvControlMsg(GET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1); if (ret < 0) return ret; @@ -1094,7 +1078,7 @@ static inline int _pwc_mpt_reset(struct pwc_device *pdev, int flags) { unsigned char buf; - + buf = flags & 0x03; // only lower two bits are currently used return SendControlMsg(SET_MPT_CTL, PT_RESET_CONTROL_FORMATTER, 1); } @@ -1113,12 +1097,12 @@ static inline int _pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt) { unsigned char buf[4]; - + /* set new relative angle; angles are expressed in degrees * 100, but cam as .5 degree resolution, hence devide by 200. Also the angle must be multiplied by 64 before it's send to the cam (??) - */ + */ pan = 64 * pan / 100; tilt = -64 * tilt / 100; /* positive tilt is down, which is not what the user would expect */ buf[0] = pan & 0xFF; @@ -1134,9 +1118,9 @@ /* check absolute ranges */ if (pan < pdev->angle_range.pan_min || - pan > pdev->angle_range.pan_max || - tilt < pdev->angle_range.tilt_min || - tilt > pdev->angle_range.tilt_max) + pan > pdev->angle_range.pan_max || + tilt < pdev->angle_range.tilt_min || + tilt > pdev->angle_range.tilt_max) return -ERANGE; /* go to relative range, check again */ @@ -1160,7 +1144,7 @@ { int ret; unsigned char buf[5]; - + ret = RecvControlMsg(GET_MPT_CTL, PT_STATUS_FORMATTER, 5); if (ret < 0) return ret; @@ -1175,14 +1159,14 @@ { unsigned char buf; int ret = -1, request; - + if (pdev->type < 675) request = SENSOR_TYPE_FORMATTER1; else if (pdev->type < 730) return -1; /* The Vesta series doesn't have this call */ else request = SENSOR_TYPE_FORMATTER2; - + ret = RecvControlMsg(GET_STATUS_CTL, request, 1); if (ret < 0) return ret; @@ -1194,15 +1178,15 @@ } - /* End of Add-Ons */ - /* ************************************************* */ +/* End of Add-Ons */ +/* ************************************************* */ /* Linux 2.5.something and 2.6 pass direct pointers to arguments of ioctl() calls. With 2.4, you have to do tedious copy_from_user() and copy_to_user() calls. With these macros we circumvent this, and let me maintain only one source file. The functionality is exactly the same otherwise. - */ + */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) @@ -1237,405 +1221,405 @@ #endif +#if 0 /* vinvin BSD patch */ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) { int ret = 0; switch(cmd) { - case VIDIOCPWCRUSER: - { - if (pwc_restore_user(pdev)) - ret = -EINVAL; - break; - } - - case VIDIOCPWCSUSER: - { - if (pwc_save_user(pdev)) - ret = -EINVAL; - break; - } - - case VIDIOCPWCFACTORY: - { - if (pwc_restore_factory(pdev)) - ret = -EINVAL; - break; - } - - case VIDIOCPWCSCQUAL: - { - ARG_DEF(int, qual) + case VIDIOCPWCRUSER: + { + if (pwc_restore_user(pdev)) + ret = -EINVAL; + break; + } - ARG_IN(qual) - if (ARGR(qual) < 0 || ARGR(qual) > 3) - ret = -EINVAL; - else - ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, ARGR(qual), pdev->vsnapshot); - if (ret >= 0) - pdev->vcompression = ARGR(qual); - break; - } - - case VIDIOCPWCGCQUAL: - { - ARG_DEF(int, qual) - - ARGR(qual) = pdev->vcompression; - ARG_OUT(qual) - break; - } - - case VIDIOCPWCPROBE: - { - ARG_DEF(struct pwc_probe, probe) - - strcpy(ARGR(probe).name, pdev->vdev->name); - ARGR(probe).type = pdev->type; - ARG_OUT(probe) - break; - } + case VIDIOCPWCSUSER: + { + if (pwc_save_user(pdev)) + ret = -EINVAL; + break; + } - case VIDIOCPWCGSERIAL: - { - ARG_DEF(struct pwc_serial, serial) - - strcpy(ARGR(serial).serial, pdev->serial); - ARG_OUT(serial) - break; - } + case VIDIOCPWCFACTORY: + { + if (pwc_restore_factory(pdev)) + ret = -EINVAL; + break; + } - case VIDIOCPWCSAGC: - { - ARG_DEF(int, agc) + case VIDIOCPWCSCQUAL: + { + ARG_DEF(int, qual) + + ARG_IN(qual) + if (ARGR(qual) < 0 || ARGR(qual) > 3) + ret = -EINVAL; + else + ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, ARGR(qual), pdev->vsnapshot); + if (ret >= 0) + pdev->vcompression = ARGR(qual); + break; + } - ARG_IN(agc) - if (pwc_set_agc(pdev, ARGR(agc) < 0 ? 1 : 0, ARGR(agc))) - ret = -EINVAL; - break; - } - - case VIDIOCPWCGAGC: - { - ARG_DEF(int, agc) - - if (pwc_get_agc(pdev, ARGA(agc))) - ret = -EINVAL; - ARG_OUT(agc) - break; - } - - case VIDIOCPWCSSHUTTER: - { - ARG_DEF(int, shutter_speed) + case VIDIOCPWCGCQUAL: + { + ARG_DEF(int, qual) - ARG_IN(shutter_speed) - ret = pwc_set_shutter_speed(pdev, ARGR(shutter_speed) < 0 ? 1 : 0, ARGR(shutter_speed)); - break; - } - - case VIDIOCPWCSAWB: - { - ARG_DEF(struct pwc_whitebalance, wb) - - ARG_IN(wb) - ret = pwc_set_awb(pdev, ARGR(wb).mode); - if (ret >= 0 && ARGR(wb).mode == PWC_WB_MANUAL) { - pwc_set_red_gain(pdev, ARGR(wb).manual_red); - pwc_set_blue_gain(pdev, ARGR(wb).manual_blue); - } - break; - } + ARGR(qual) = pdev->vcompression; + ARG_OUT(qual) + break; + } - case VIDIOCPWCGAWB: - { - ARG_DEF(struct pwc_whitebalance, wb) + case VIDIOCPWCPROBE: + { + ARG_DEF(struct pwc_probe, probe) - memset(ARGA(wb), 0, sizeof(struct pwc_whitebalance)); - ARGR(wb).mode = pwc_get_awb(pdev); - if (ARGR(wb).mode < 0) - ret = -EINVAL; - else { - if (ARGR(wb).mode == PWC_WB_MANUAL) { - ret = pwc_get_red_gain(pdev, &ARGR(wb).manual_red); + strcpy(ARGR(probe).name, pdev->vdev_name); + ARGR(probe).type = pdev->type; + ARG_OUT(probe) + break; + } + + case VIDIOCPWCGSERIAL: + { + ARG_DEF(struct pwc_serial, serial) + + strcpy(ARGR(serial).serial, pdev->serial); + ARG_OUT(serial) + break; + } + + case VIDIOCPWCSAGC: + { + ARG_DEF(int, agc) + + ARG_IN(agc) + if (pwc_set_agc(pdev, ARGR(agc) < 0 ? 1 : 0, ARGR(agc))) + ret = -EINVAL; + break; + } + + case VIDIOCPWCGAGC: + { + ARG_DEF(int, agc) + + if (pwc_get_agc(pdev, ARGA(agc))) + ret = -EINVAL; + ARG_OUT(agc) + break; + } + + case VIDIOCPWCSSHUTTER: + { + ARG_DEF(int, shutter_speed) + + ARG_IN(shutter_speed) + ret = pwc_set_shutter_speed(pdev, ARGR(shutter_speed) < 0 ? 1 : 0, ARGR(shutter_speed)); + break; + } + + case VIDIOCPWCSAWB: + { + ARG_DEF(struct pwc_whitebalance, wb) + + ARG_IN(wb) + ret = pwc_set_awb(pdev, ARGR(wb).mode); + if (ret >= 0 && ARGR(wb).mode == PWC_WB_MANUAL) { + pwc_set_red_gain(pdev, ARGR(wb).manual_red); + pwc_set_blue_gain(pdev, ARGR(wb).manual_blue); + } + break; + } + + case VIDIOCPWCGAWB: + { + ARG_DEF(struct pwc_whitebalance, wb) + + memset(ARGA(wb), 0, sizeof(struct pwc_whitebalance)); + ARGR(wb).mode = pwc_get_awb(pdev); + if (ARGR(wb).mode < 0) + ret = -EINVAL; + else { + if (ARGR(wb).mode == PWC_WB_MANUAL) { + ret = pwc_get_red_gain(pdev, &ARGR(wb).manual_red); + if (ret < 0) + break; + ret = pwc_get_blue_gain(pdev, &ARGR(wb).manual_blue); + if (ret < 0) + break; + } + if (ARGR(wb).mode == PWC_WB_AUTO) { + ret = pwc_read_red_gain(pdev, &ARGR(wb).read_red); + if (ret < 0) + break; + ret =pwc_read_blue_gain(pdev, &ARGR(wb).read_blue); + if (ret < 0) + break; + } + } + ARG_OUT(wb) + break; + } + + case VIDIOCPWCSAWBSPEED: + { + ARG_DEF(struct pwc_wb_speed, wbs) + + if (ARGR(wbs).control_speed > 0) { + ret = pwc_set_wb_speed(pdev, ARGR(wbs).control_speed); + } + if (ARGR(wbs).control_delay > 0) { + ret = pwc_set_wb_delay(pdev, ARGR(wbs).control_delay); + } + break; + } + + case VIDIOCPWCGAWBSPEED: + { + ARG_DEF(struct pwc_wb_speed, wbs) + + ret = pwc_get_wb_speed(pdev, &ARGR(wbs).control_speed); if (ret < 0) break; - ret = pwc_get_blue_gain(pdev, &ARGR(wb).manual_blue); + ret = pwc_get_wb_delay(pdev, &ARGR(wbs).control_delay); if (ret < 0) break; + ARG_OUT(wbs) + break; } - if (ARGR(wb).mode == PWC_WB_AUTO) { - ret = pwc_read_red_gain(pdev, &ARGR(wb).read_red); - if (ret < 0) + + case VIDIOCPWCSLED: + { + ARG_DEF(struct pwc_leds, leds) + + ARG_IN(leds) + ret = pwc_set_leds(pdev, ARGR(leds).led_on, ARGR(leds).led_off); + break; + } + + + case VIDIOCPWCGLED: + { + ARG_DEF(struct pwc_leds, leds) + + ret = pwc_get_leds(pdev, &ARGR(leds).led_on, &ARGR(leds).led_off); + ARG_OUT(leds) break; - ret =pwc_read_blue_gain(pdev, &ARGR(wb).read_blue); - if (ret < 0) - break; } - } - ARG_OUT(wb) - break; - } - - case VIDIOCPWCSAWBSPEED: - { - ARG_DEF(struct pwc_wb_speed, wbs) - - if (ARGR(wbs).control_speed > 0) { - ret = pwc_set_wb_speed(pdev, ARGR(wbs).control_speed); - } - if (ARGR(wbs).control_delay > 0) { - ret = pwc_set_wb_delay(pdev, ARGR(wbs).control_delay); - } - break; - } - - case VIDIOCPWCGAWBSPEED: - { - ARG_DEF(struct pwc_wb_speed, wbs) - - ret = pwc_get_wb_speed(pdev, &ARGR(wbs).control_speed); - if (ret < 0) - break; - ret = pwc_get_wb_delay(pdev, &ARGR(wbs).control_delay); - if (ret < 0) - break; - ARG_OUT(wbs) - break; - } - case VIDIOCPWCSLED: - { - ARG_DEF(struct pwc_leds, leds) + case VIDIOCPWCSCONTOUR: + { + ARG_DEF(int, contour) - ARG_IN(leds) - ret = pwc_set_leds(pdev, ARGR(leds).led_on, ARGR(leds).led_off); - break; - } + ARG_IN(contour) + ret = pwc_set_contour(pdev, ARGR(contour)); + break; + } + case VIDIOCPWCGCONTOUR: + { + ARG_DEF(int, contour) - case VIDIOCPWCGLED: - { - ARG_DEF(struct pwc_leds, leds) - - ret = pwc_get_leds(pdev, &ARGR(leds).led_on, &ARGR(leds).led_off); - ARG_OUT(leds) - break; - } + ret = pwc_get_contour(pdev, ARGA(contour)); + ARG_OUT(contour) + break; + } - case VIDIOCPWCSCONTOUR: - { - ARG_DEF(int, contour) + case VIDIOCPWCSBACKLIGHT: + { + ARG_DEF(int, backlight) - ARG_IN(contour) - ret = pwc_set_contour(pdev, ARGR(contour)); - break; - } - - case VIDIOCPWCGCONTOUR: - { - ARG_DEF(int, contour) - - ret = pwc_get_contour(pdev, ARGA(contour)); - ARG_OUT(contour) - break; - } - - case VIDIOCPWCSBACKLIGHT: - { - ARG_DEF(int, backlight) - - ARG_IN(backlight) - ret = pwc_set_backlight(pdev, ARGR(backlight)); - break; - } + ARG_IN(backlight) + ret = pwc_set_backlight(pdev, ARGR(backlight)); + break; + } - case VIDIOCPWCGBACKLIGHT: - { - ARG_DEF(int, backlight) - - ret = pwc_get_backlight(pdev, ARGA(backlight)); - ARG_OUT(backlight) - break; - } - - case VIDIOCPWCSFLICKER: - { - ARG_DEF(int, flicker) - - ARG_IN(flicker) - ret = pwc_set_flicker(pdev, ARGR(flicker)); - break; - } + case VIDIOCPWCGBACKLIGHT: + { + ARG_DEF(int, backlight) - case VIDIOCPWCGFLICKER: - { - ARG_DEF(int, flicker) - - ret = pwc_get_flicker(pdev, ARGA(flicker)); - ARG_OUT(flicker) - break; - } - - case VIDIOCPWCSDYNNOISE: - { - ARG_DEF(int, dynnoise) - - ARG_IN(dynnoise) - ret = pwc_set_dynamic_noise(pdev, ARGR(dynnoise)); - break; - } - - case VIDIOCPWCGDYNNOISE: - { - ARG_DEF(int, dynnoise) + ret = pwc_get_backlight(pdev, ARGA(backlight)); + ARG_OUT(backlight) + break; + } - ret = pwc_get_dynamic_noise(pdev, ARGA(dynnoise)); - ARG_OUT(dynnoise); - break; - } + case VIDIOCPWCSFLICKER: + { + ARG_DEF(int, flicker) - case VIDIOCPWCGREALSIZE: - { - ARG_DEF(struct pwc_imagesize, size) - - ARGR(size).width = pdev->image.x; - ARGR(size).height = pdev->image.y; - ARG_OUT(size) - break; - } - - case VIDIOCPWCMPTRESET: - { - if (pdev->features & FEATURE_MOTOR_PANTILT) - { - ARG_DEF(int, flags) - - ARG_IN(flags) - ret = pwc_mpt_reset(pdev, ARGR(flags)); - } - else - { - ret = -ENXIO; - } - break; - } - - case VIDIOCPWCMPTGRANGE: - { - if (pdev->features & FEATURE_MOTOR_PANTILT) - { - ARG_DEF(struct pwc_mpt_range, range) - - ARGR(range) = pdev->angle_range; - ARG_OUT(range) - } - else - { - ret = -ENXIO; - } - break; - } - - case VIDIOCPWCMPTSANGLE: - { - int new_pan, new_tilt; - - if (pdev->features & FEATURE_MOTOR_PANTILT) - { - ARG_DEF(struct pwc_mpt_angles, angles) - - ARG_IN(angles) - /* The camera can only set relative angles, so - do some calculations when getting an absolute angle . - */ - if (ARGR(angles).absolute) - { - new_pan = ARGR(angles).pan; - new_tilt = ARGR(angles).tilt; - } - else - { - new_pan = pdev->pan_angle + ARGR(angles).pan; - new_tilt = pdev->tilt_angle + ARGR(angles).tilt; + ARG_IN(flicker) + ret = pwc_set_flicker(pdev, ARGR(flicker)); + break; } - ret = pwc_mpt_set_angle(pdev, new_pan, new_tilt); - } - else - { - ret = -ENXIO; - } - break; - } - - case VIDIOCPWCMPTGANGLE: - { - - if (pdev->features & FEATURE_MOTOR_PANTILT) - { - ARG_DEF(struct pwc_mpt_angles, angles) - - ARGR(angles).absolute = 1; - ARGR(angles).pan = pdev->pan_angle; - ARGR(angles).tilt = pdev->tilt_angle; - ARG_OUT(angles) - } - else - { - ret = -ENXIO; - } - break; - } - - case VIDIOCPWCMPTSTATUS: - { - if (pdev->features & FEATURE_MOTOR_PANTILT) - { - ARG_DEF(struct pwc_mpt_status, status) - - ret = pwc_mpt_get_status(pdev, ARGA(status)); - ARG_OUT(status) - } - else - { - ret = -ENXIO; - } - break; - } - case VIDIOCPWCGVIDCMD: - { - ARG_DEF(struct pwc_video_command, cmd); - - ARGR(cmd).type = pdev->type; - ARGR(cmd).release = pdev->release; - ARGR(cmd).command_len = pdev->cmd_len; - memcpy(&ARGR(cmd).command_buf, pdev->cmd_buf, pdev->cmd_len); - ARGR(cmd).bandlength = pdev->vbandlength; - ARGR(cmd).frame_size = pdev->frame_size; - ARG_OUT(cmd) - break; - } - /* - case VIDIOCPWCGVIDTABLE: - { - ARG_DEF(struct pwc_table_init_buffer, table); - ARGR(table).len = pdev->cmd_len; - memcpy(&ARGR(table).buffer, pdev->decompress_data, pdev->decompressor->table_size); - ARG_OUT(table) - break; - } - */ - - default: - ret = -ENOIOCTLCMD; - break; + case VIDIOCPWCGFLICKER: + { + ARG_DEF(int, flicker) + + ret = pwc_get_flicker(pdev, ARGA(flicker)); + ARG_OUT(flicker) + break; + } + + case VIDIOCPWCSDYNNOISE: + { + ARG_DEF(int, dynnoise) + + ARG_IN(dynnoise) + ret = pwc_set_dynamic_noise(pdev, ARGR(dynnoise)); + break; + } + + case VIDIOCPWCGDYNNOISE: + { + ARG_DEF(int, dynnoise) + + ret = pwc_get_dynamic_noise(pdev, ARGA(dynnoise)); + ARG_OUT(dynnoise); + break; + } + + case VIDIOCPWCGREALSIZE: + { + ARG_DEF(struct pwc_imagesize, size) + + ARGR(size).width = pdev->image.x; + ARGR(size).height = pdev->image.y; + ARG_OUT(size) + break; + } + + case VIDIOCPWCMPTRESET: + { + if (pdev->features & FEATURE_MOTOR_PANTILT) + { + ARG_DEF(int, flags) + + ARG_IN(flags) + ret = pwc_mpt_reset(pdev, ARGR(flags)); + } + else + { + ret = -ENXIO; + } + break; + } + + case VIDIOCPWCMPTGRANGE: + { + if (pdev->features & FEATURE_MOTOR_PANTILT) + { + ARG_DEF(struct pwc_mpt_range, range) + + ARGR(range) = pdev->angle_range; + ARG_OUT(range) + } + else + { + ret = -ENXIO; + } + break; + } + + case VIDIOCPWCMPTSANGLE: + { + int new_pan, new_tilt; + + if (pdev->features & FEATURE_MOTOR_PANTILT) + { + ARG_DEF(struct pwc_mpt_angles, angles) + + ARG_IN(angles) + /* The camera can only set relative angles, so + do some calculations when getting an absolute angle . + */ + if (ARGR(angles).absolute) + { + new_pan = ARGR(angles).pan; + new_tilt = ARGR(angles).tilt; + } + else + { + new_pan = pdev->pan_angle + ARGR(angles).pan; + new_tilt = pdev->tilt_angle + ARGR(angles).tilt; + } + ret = pwc_mpt_set_angle(pdev, new_pan, new_tilt); + } + else + { + ret = -ENXIO; + } + break; + } + + case VIDIOCPWCMPTGANGLE: + { + + if (pdev->features & FEATURE_MOTOR_PANTILT) + { + ARG_DEF(struct pwc_mpt_angles, angles) + + ARGR(angles).absolute = 1; + ARGR(angles).pan = pdev->pan_angle; + ARGR(angles).tilt = pdev->tilt_angle; + ARG_OUT(angles) + } + else + { + ret = -ENXIO; + } + break; + } + + case VIDIOCPWCMPTSTATUS: + { + if (pdev->features & FEATURE_MOTOR_PANTILT) + { + ARG_DEF(struct pwc_mpt_status, status) + + ret = pwc_mpt_get_status(pdev, ARGA(status)); + ARG_OUT(status) + } + else + { + ret = -ENXIO; + } + break; + } + + case VIDIOCPWCGVIDCMD: + { + ARG_DEF(struct pwc_video_command, cmd); + + ARGR(cmd).type = pdev->type; + ARGR(cmd).release = pdev->release; + ARGR(cmd).command_len = pdev->cmd_len; + memcpy(&ARGR(cmd).command_buf, pdev->cmd_buf, pdev->cmd_len); + ARGR(cmd).bandlength = pdev->vbandlength; + ARGR(cmd).frame_size = pdev->frame_size; + ARG_OUT(cmd) + break; + } + /* + case VIDIOCPWCGVIDTABLE: + { + ARG_DEF(struct pwc_table_init_buffer, table); + ARGR(table).len = pdev->cmd_len; + memcpy(&ARGR(table).buffer, pdev->decompress_data, pdev->decompressor->table_size); + ARG_OUT(table) + break; + } + */ + + default: + ret = -EINVAL; + break; } - + if (ret > 0) return 0; return ret; } - - +#endif /* vinvin BSD patch */ diff -Nru pwc-10.0.5.orig/pwc-dec23.c pwc-10.0.5/pwc-dec23.c --- pwc-10.0.5.orig/pwc-dec23.c 2004-09-17 14:33:59.000000000 +0200 +++ pwc-10.0.5/pwc-dec23.c 2004-11-23 18:00:06.000000000 +0100 @@ -2,33 +2,35 @@ Decompression for chipset version 2 et 3 (C) 2004 Luc Saillard (luc@saillard.org) - NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx - driver and thus may have bugs that are not present in the original version. - Please send bug reports and support requests to . - The decompression routines have been implemented by reverse-engineering the - Nemosoft binary pwcx module. Caveat emptor. - - 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. - - 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. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx +driver and thus may have bugs that are not present in the original version. +Please send bug reports and support requests to . +The decompression routines have been implemented by reverse-engineering the +Nemosoft binary pwcx module. Caveat emptor. + +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. + +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. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "pwc.h" #include "pwc-timon.h" #include "pwc-kiara.h" #include "pwc-dec23.h" #include "pwc-ioctl.h" -#include +#include +#include /**** * @@ -39,46 +41,46 @@ static void fill_table_a000(unsigned int *p) { - static unsigned int initial_values[12] = { - 0xFFAD9B00, 0xFFDDEE00, 0x00221200, 0x00526500, - 0xFFC21E00, 0x003DE200, 0xFF924B80, 0xFFD2A300, - 0x002D5D00, 0x006DB480, 0xFFED3E00, 0x0012C200 - }; - static unsigned int values_derivated[12] = { - 0x0000A4CA, 0x00004424, 0xFFFFBBDC, 0xFFFF5B36, - 0x00007BC4, 0xFFFF843C, 0x0000DB69, 0x00005ABA, - 0xFFFFA546, 0xFFFF2497, 0x00002584, 0xFFFFDA7C - }; - unsigned int temp_values[12]; - int i,j; - - memcpy(temp_values,initial_values,sizeof(initial_values)); - for (i=0;i<256;i++) - { - for (j=0;j<12;j++) - { - *p++ = temp_values[j]; - temp_values[j] += values_derivated[j]; - } - } + static unsigned int initial_values[12] = { + 0xFFAD9B00, 0xFFDDEE00, 0x00221200, 0x00526500, + 0xFFC21E00, 0x003DE200, 0xFF924B80, 0xFFD2A300, + 0x002D5D00, 0x006DB480, 0xFFED3E00, 0x0012C200 + }; + static unsigned int values_derivated[12] = { + 0x0000A4CA, 0x00004424, 0xFFFFBBDC, 0xFFFF5B36, + 0x00007BC4, 0xFFFF843C, 0x0000DB69, 0x00005ABA, + 0xFFFFA546, 0xFFFF2497, 0x00002584, 0xFFFFDA7C + }; + unsigned int temp_values[12]; + int i,j; + + memcpy(temp_values,initial_values,sizeof(initial_values)); + for (i=0;i<256;i++) + { + for (j=0;j<12;j++) + { + *p++ = temp_values[j]; + temp_values[j] += values_derivated[j]; + } + } } static void fill_table_d000(unsigned char *p) { - int bit,byte; + int bit,byte; - for (bit=0; bit<8; bit++) - { - unsigned char bitpower = 1<=1 && k<3) - bit=(table[0]>>15)&7; - else if (k>=3 && k<6) - bit=(table[0]>>12)&7; - else if (k>=6 && k<10) - bit=(table[0]>>9)&7; - else if (k>=10 && k<13) - bit=(table[0]>>6)&7; - else if (k>=13 && k<15) - bit=(table[0]>>3)&7; - else - bit=(table[0])&7; - if (k == 0) - *(unsigned char *)p8++ = 8; - else - *(unsigned char *)p8++ = j - bit; - *(unsigned char *)p8++ = bit; - - pw = 1<=1 && k<3) + bit=(table[0]>>15)&7; + else if (k>=3 && k<6) + bit=(table[0]>>12)&7; + else if (k>=6 && k<10) + bit=(table[0]>>9)&7; + else if (k>=10 && k<13) + bit=(table[0]>>6)&7; + else if (k>=13 && k<15) + bit=(table[0]>>3)&7; + else + bit=(table[0])&7; + if (k == 0) + *(unsigned char *)p8++ = 8; + else + *(unsigned char *)p8++ = j - bit; + *(unsigned char *)p8++ = bit; + + pw = 1<> 15; - - if ( msb > 255) - { - if (msb) - msb=0; - else - msb=255; - } + int i; + unsigned int offset1, offset2; - *pdc00++ = msb << precision; - *pd800++ = offset2; - } + for(i=0,offset1=0x4000, offset2=0; i<256 ; i++,offset1+=0x7BC4, offset2+=0x7BC4) + { + unsigned int msb = offset1 >> 15; + + if ( msb > 255) + { + if (msb) + msb=0; + else + msb=255; + } + + *pdc00++ = msb << precision; + *pd800++ = offset2; + } } @@ -183,22 +185,22 @@ * */ static unsigned int table_ops[] = { -0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x10, 0x00,0x06,0x01,0x30, -0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x01,0x20, 0x01,0x00,0x00,0x00, -0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x50, 0x00,0x05,0x02,0x00, -0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x03,0x00, 0x01,0x00,0x00,0x00, -0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x10, 0x00,0x06,0x02,0x10, -0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x01,0x60, 0x01,0x00,0x00,0x00, -0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x50, 0x00,0x05,0x02,0x40, -0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x03,0x40, 0x01,0x00,0x00,0x00, -0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x10, 0x00,0x06,0x01,0x70, -0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x01,0x20, 0x01,0x00,0x00,0x00, -0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x50, 0x00,0x05,0x02,0x00, -0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x03,0x00, 0x01,0x00,0x00,0x00, -0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x10, 0x00,0x06,0x02,0x50, -0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x01,0x60, 0x01,0x00,0x00,0x00, -0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x50, 0x00,0x05,0x02,0x40, -0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x03,0x40, 0x01,0x00,0x00,0x00 + 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x10, 0x00,0x06,0x01,0x30, + 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x01,0x20, 0x01,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x50, 0x00,0x05,0x02,0x00, + 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x03,0x00, 0x01,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x10, 0x00,0x06,0x02,0x10, + 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x01,0x60, 0x01,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x50, 0x00,0x05,0x02,0x40, + 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x03,0x40, 0x01,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x10, 0x00,0x06,0x01,0x70, + 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x01,0x20, 0x01,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x50, 0x00,0x05,0x02,0x00, + 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x03,0x00, 0x01,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x10, 0x00,0x06,0x02,0x50, + 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x01,0x60, 0x01,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x50, 0x00,0x05,0x02,0x40, + 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x03,0x40, 0x01,0x00,0x00,0x00 }; /* @@ -206,81 +208,83 @@ * */ static unsigned int MulIdx[256] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, - 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, - 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, - 6, 7, 8, 9, 7,10,11, 8, 8,11,10, 7, 9, 8, 7, 6, - 4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4, - 1, 3, 0, 2, 1, 3, 0, 2, 1, 3, 0, 2, 1, 3, 0, 2, - 0, 3, 3, 0, 1, 2, 2, 1, 2, 1, 1, 2, 3, 0, 0, 3, - 0, 1, 2, 3, 3, 2, 1, 0, 3, 2, 1, 0, 0, 1, 2, 3, - 1, 1, 1, 1, 3, 3, 3, 3, 0, 0, 0, 0, 2, 2, 2, 2, - 7,10,11, 8, 9, 8, 7, 6, 6, 7, 8, 9, 8,11,10, 7, - 4, 5, 5, 4, 5, 4, 4, 5, 5, 4, 4, 5, 4, 5, 5, 4, - 7, 9, 6, 8,10, 8, 7,11,11, 7, 8,10, 8, 6, 9, 7, - 1, 3, 0, 2, 2, 0, 3, 1, 2, 0, 3, 1, 1, 3, 0, 2, - 1, 2, 2, 1, 3, 0, 0, 3, 0, 3, 3, 0, 2, 1, 1, 2, -10, 8, 7,11, 8, 6, 9, 7, 7, 9, 6, 8,11, 7, 8,10 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, + 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, + 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, + 6, 7, 8, 9, 7,10,11, 8, 8,11,10, 7, 9, 8, 7, 6, + 4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4, + 1, 3, 0, 2, 1, 3, 0, 2, 1, 3, 0, 2, 1, 3, 0, 2, + 0, 3, 3, 0, 1, 2, 2, 1, 2, 1, 1, 2, 3, 0, 0, 3, + 0, 1, 2, 3, 3, 2, 1, 0, 3, 2, 1, 0, 0, 1, 2, 3, + 1, 1, 1, 1, 3, 3, 3, 3, 0, 0, 0, 0, 2, 2, 2, 2, + 7,10,11, 8, 9, 8, 7, 6, 6, 7, 8, 9, 8,11,10, 7, + 4, 5, 5, 4, 5, 4, 4, 5, 5, 4, 4, 5, 4, 5, 5, 4, + 7, 9, 6, 8,10, 8, 7,11,11, 7, 8,10, 8, 6, 9, 7, + 1, 3, 0, 2, 2, 0, 3, 1, 2, 0, 3, 1, 1, 3, 0, 2, + 1, 2, 2, 1, 3, 0, 0, 3, 0, 3, 3, 0, 2, 1, 1, 2, + 10, 8, 7,11, 8, 6, 9, 7, 7, 9, 6, 8,11, 7, 8,10 }; void pwc_dec23_init(int type, int release, unsigned char *mode, void *data) { - int flags; - struct pwc_dec23_private *pdev = data; - release = release; - - switch (type) - { - case 720: - case 730: - case 740: - case 750: - flags = mode[2]&0x18; /* our: flags = 8, mode[2]==e8 */ - if (flags==8) - pdev->zz = 7; - else if (flags==0x10) - pdev->zz = 8; - else - pdev->zz = 6; - flags = mode[2]>>5; /* our: 7 */ - - fill_table_color(flags, (unsigned int *)KiaraRomTable, pdev->table_0004, pdev->table_8004); - break; - - - case 675: - case 680: - case 690: - flags = mode[2]&6; - if (flags==2) - pdev->zz = 7; - else if (flags==4) - pdev->zz = 8; - else - pdev->zz = 6; - flags = mode[2]>>3; - - fill_table_color(flags, (unsigned int *)TimonRomTable, pdev->table_0004, pdev->table_8004); - break; - - default: - /* Not supported */ - return; - } - - /* * * * ** */ - pdev->xx = 8 - pdev->zz; - pdev->yy = 15 - pdev->xx; - pdev->zzmask = 0xFF>>pdev->xx; - //pdev->zzmask = (1U<zz)-1; - - - fill_table_dc00_d800(pdev->xx + pdev->yy, pdev->table_dc00, pdev->table_d800); - fill_table_a000(pdev->table_a004); - fill_table_d000(pdev->table_d004); + int flags; + struct pwc_dec23_private *pdev = data; + release = release; + + switch (type) + { + case 720: + case 730: + case 740: + case 750: + flags = mode[2]&0x18; /* our: flags = 8, mode[2]==e8 */ + if (flags==8) + pdev->zz = 7; + else if (flags==0x10) + pdev->zz = 8; + else + pdev->zz = 6; + flags = mode[2]>>5; /* our: 7 */ + + fill_table_color(flags, (unsigned int *)KiaraRomTable, pdev->table_0004, pdev->table_8004); + Debug("Kiara decompressor initialised\n"); + break; + + + case 675: + case 680: + case 690: + flags = mode[2]&6; + if (flags==2) + pdev->zz = 7; + else if (flags==4) + pdev->zz = 8; + else + pdev->zz = 6; + flags = mode[2]>>3; + + fill_table_color(flags, (unsigned int *)TimonRomTable, pdev->table_0004, pdev->table_8004); + Debug("Timon decompressor initialised\n"); + break; + + default: + /* Not supported */ + return; + } + + /* * * * ** */ + pdev->xx = 8 - pdev->zz; + pdev->yy = 15 - pdev->xx; + pdev->zzmask = 0xFF>>pdev->xx; + //pdev->zzmask = (1U<zz)-1; + + + fill_table_dc00_d800(pdev->xx + pdev->yy, pdev->table_dc00, pdev->table_d800); + fill_table_a000(pdev->table_a004); + fill_table_d000(pdev->table_d004); } @@ -292,179 +296,179 @@ * */ #define fill_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted) do { \ - while (nbits_in_reservoir>= nbits_wanted; \ - nbits_in_reservoir -= nbits_wanted; \ + fill_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted); \ + result = (reservoir) & ((1U<>= nbits_wanted; \ + nbits_in_reservoir -= nbits_wanted; \ } while(0); static void DecompressBand23(const struct pwc_dec23_private *pdev, - const unsigned char *rawyuv, - unsigned char *planar_y, - unsigned char *planar_u, - unsigned char *planar_v, - unsigned int image_x, /* aka number of pixels wanted ??? */ - unsigned int pixels_per_line, /* aka number of pixels per line */ - int flags) + const unsigned char *rawyuv, + unsigned char *planar_y, + unsigned char *planar_u, + unsigned char *planar_v, + unsigned int image_x, /* aka number of pixels wanted ??? */ + unsigned int pixels_per_line, /* aka number of pixels per line */ + int flags) { - unsigned int reservoir, nbits_in_reservoir; - int first_4_bits; - unsigned int bytes_per_channel; - int line_size; /* size of the line (4Y+U+V) */ - int passes; - const unsigned char *ptable0004, *ptable8004; - - int even_line; - unsigned int temp_colors[16]; - int nblocks; - - const unsigned char *stream; - unsigned char *dest_y, *dest_u=NULL, *dest_v=NULL; - unsigned int offset_to_plane_u, offset_to_plane_v; - - int i; - - - reservoir = 0; - nbits_in_reservoir = 0; - stream = rawyuv+1; /* The first byte of the stream is skipped */ - even_line = 1; - - get_nbits(reservoir,nbits_in_reservoir,stream,4,first_4_bits); - - line_size = pixels_per_line*3; - - for (passes=0;passes<2;passes++) - { - if (passes==0) - { - bytes_per_channel = pixels_per_line; - dest_y = planar_y; - nblocks = image_x/4; - } - else - { - /* Format planar: All Y, then all U, then all V */ - bytes_per_channel = pixels_per_line/2; - dest_u = planar_u; - dest_v = planar_v; - dest_y = dest_u; - nblocks = image_x/8; - } - - offset_to_plane_u = bytes_per_channel*2; - offset_to_plane_v = bytes_per_channel*3; - /* - printf("bytes_per_channel = %d\n",bytes_per_channel); - printf("offset_to_plane_u = %d\n",offset_to_plane_u); - printf("offset_to_plane_v = %d\n",offset_to_plane_v); - */ - - while (nblocks-->0) - { - unsigned int gray_index; - - fill_nbits(reservoir,nbits_in_reservoir,stream,16); - gray_index = reservoir & pdev->zzmask; - reservoir >>= pdev->zz; - nbits_in_reservoir -= pdev->zz; - - fill_nbits(reservoir,nbits_in_reservoir,stream,2); - - if ( (reservoir & 3) == 0) - { - reservoir>>=2; - nbits_in_reservoir-=2; - for (i=0;i<16;i++) - temp_colors[i] = pdev->table_dc00[gray_index]; - - } - else - { - unsigned int channel_v, offset1; - - /* swap bit 0 and 2 of offset_OR */ - channel_v = ((reservoir & 1) << 2) | (reservoir & 2) | ((reservoir & 4)>>2); - reservoir>>=3; - nbits_in_reservoir-=3; - - for (i=0;i<16;i++) - temp_colors[i] = pdev->table_d800[gray_index]; - - ptable0004 = pdev->table_0004 + (passes*16384) + (first_4_bits*1024) + (channel_v*128); - ptable8004 = pdev->table_8004 + (passes*4096) + (first_4_bits*256) + (channel_v*32); - - offset1 = 0; - while(1) - { - unsigned int index_in_table_ops, op, rows=0; - fill_nbits(reservoir,nbits_in_reservoir,stream,16); - - /* mode is 0,1 or 2 */ - index_in_table_ops = (reservoir&0x3F); - op = table_ops[ index_in_table_ops*4 ]; - if (op == 2) - { - reservoir >>= 2; - nbits_in_reservoir -= 2; - break; /* exit the while(1) */ - } - if (op == 0) - { - unsigned int shift; - - offset1 = (offset1 + table_ops[index_in_table_ops*4+2]) & 0x0F; - shift = table_ops[ index_in_table_ops*4+1 ]; - reservoir >>= shift; - nbits_in_reservoir -= shift; - rows = ptable0004[ offset1 + table_ops[index_in_table_ops*4+3] ]; - } - if (op == 1) - { - /* 10bits [ xxxx xxxx yyyy 000 ] - * yyy => offset in the table8004 - * xxx => offset in the tabled004 + unsigned int reservoir, nbits_in_reservoir; + int first_4_bits; + unsigned int bytes_per_channel; + int line_size; /* size of the line (4Y+U+V) */ + int passes; + const unsigned char *ptable0004, *ptable8004; + + int even_line; + unsigned int temp_colors[16]; + int nblocks; + + const unsigned char *stream; + unsigned char *dest_y, *dest_u=NULL, *dest_v=NULL; + unsigned int offset_to_plane_u, offset_to_plane_v; + + int i; + + + reservoir = 0; + nbits_in_reservoir = 0; + stream = rawyuv+1; /* The first byte of the stream is skipped */ + even_line = 1; + + get_nbits(reservoir,nbits_in_reservoir,stream,4,first_4_bits); + + line_size = pixels_per_line*3; + + for (passes=0;passes<2;passes++) + { + if (passes==0) + { + bytes_per_channel = pixels_per_line; + dest_y = planar_y; + nblocks = image_x/4; + } + else + { + /* Format planar: All Y, then all U, then all V */ + bytes_per_channel = pixels_per_line/2; + dest_u = planar_u; + dest_v = planar_v; + dest_y = dest_u; + nblocks = image_x/8; + } + + offset_to_plane_u = bytes_per_channel*2; + offset_to_plane_v = bytes_per_channel*3; + /* + printf("bytes_per_channel = %d\n",bytes_per_channel); + printf("offset_to_plane_u = %d\n",offset_to_plane_u); + printf("offset_to_plane_v = %d\n",offset_to_plane_v); */ - unsigned int mask, shift; - unsigned int col1, row1, total_bits; - - offset1 = (offset1 + ((reservoir>>3)&0x0F)+1) & 0x0F; - col1 = (reservoir>>7) & 0xFF; - row1 = ptable8004 [ offset1*2 ]; - - /* Bit mask table */ - mask = pdev->table_d004[ (row1<<8) + col1 ]; - shift = ptable8004 [ offset1*2 + 1]; - rows = ((mask << shift) + 0x80) & 0xFF; - - total_bits = row1 + 8; - reservoir >>= total_bits; - nbits_in_reservoir -= total_bits; - } - { - const unsigned int *table_a004 = pdev->table_a004 + rows*12; - unsigned int *poffset = MulIdx + offset1*16; /* 64/4 (int) */ - for (i=0;i<16;i++) - { - temp_colors[i] += table_a004[ *poffset ]; - poffset++; - } - } - } - } + while (nblocks-->0) + { + unsigned int gray_index; + + fill_nbits(reservoir,nbits_in_reservoir,stream,16); + gray_index = reservoir & pdev->zzmask; + reservoir >>= pdev->zz; + nbits_in_reservoir -= pdev->zz; + + fill_nbits(reservoir,nbits_in_reservoir,stream,2); + + if ( (reservoir & 3) == 0) + { + reservoir>>=2; + nbits_in_reservoir-=2; + for (i=0;i<16;i++) + temp_colors[i] = pdev->table_dc00[gray_index]; + + } + else + { + unsigned int channel_v, offset1; + + /* swap bit 0 and 2 of offset_OR */ + channel_v = ((reservoir & 1) << 2) | (reservoir & 2) | ((reservoir & 4)>>2); + reservoir>>=3; + nbits_in_reservoir-=3; + + for (i=0;i<16;i++) + temp_colors[i] = pdev->table_d800[gray_index]; + + ptable0004 = pdev->table_0004 + (passes*16384) + (first_4_bits*1024) + (channel_v*128); + ptable8004 = pdev->table_8004 + (passes*4096) + (first_4_bits*256) + (channel_v*32); + + offset1 = 0; + while(1) + { + unsigned int index_in_table_ops, op, rows=0; + fill_nbits(reservoir,nbits_in_reservoir,stream,16); + + /* mode is 0,1 or 2 */ + index_in_table_ops = (reservoir&0x3F); + op = table_ops[ index_in_table_ops*4 ]; + if (op == 2) + { + reservoir >>= 2; + nbits_in_reservoir -= 2; + break; /* exit the while(1) */ + } + if (op == 0) + { + unsigned int shift; + + offset1 = (offset1 + table_ops[index_in_table_ops*4+2]) & 0x0F; + shift = table_ops[ index_in_table_ops*4+1 ]; + reservoir >>= shift; + nbits_in_reservoir -= shift; + rows = ptable0004[ offset1 + table_ops[index_in_table_ops*4+3] ]; + } + if (op == 1) + { + /* 10bits [ xxxx xxxx yyyy 000 ] + * yyy => offset in the table8004 + * xxx => offset in the tabled004 + */ + unsigned int mask, shift; + unsigned int col1, row1, total_bits; + + offset1 = (offset1 + ((reservoir>>3)&0x0F)+1) & 0x0F; + + col1 = (reservoir>>7) & 0xFF; + row1 = ptable8004 [ offset1*2 ]; + + /* Bit mask table */ + mask = pdev->table_d004[ (row1<<8) + col1 ]; + shift = ptable8004 [ offset1*2 + 1]; + rows = ((mask << shift) + 0x80) & 0xFF; + + total_bits = row1 + 8; + reservoir >>= total_bits; + nbits_in_reservoir -= total_bits; + } + { + const unsigned int *table_a004 = pdev->table_a004 + rows*12; + unsigned int *poffset = MulIdx + offset1*16; /* 64/4 (int) */ + for (i=0;i<16;i++) + { + temp_colors[i] += table_a004[ *poffset ]; + poffset++; + } + } + } + } #define USE_SIGNED_INT_FOR_COLOR #ifdef USE_SIGNED_INT_FOR_COLOR # define CLAMP(x) ((x)>255?255:((x)<0?0:x)) @@ -472,76 +476,76 @@ # define CLAMP(x) ((x)>255?255:x) #endif - if (passes == 0) - { + if (passes == 0) + { #ifdef USE_SIGNED_INT_FOR_COLOR - const int *c = temp_colors; + const int *c = temp_colors; #else - const unsigned int *c = temp_colors; + const unsigned int *c = temp_colors; #endif - unsigned char *d; + unsigned char *d; - d = dest_y; - for (i=0;i<4;i++,c++) - *d++ = CLAMP((*c) >> pdev->yy); - - d = dest_y + bytes_per_channel; - for (i=0;i<4;i++,c++) - *d++ = CLAMP((*c) >> pdev->yy); - - d = dest_y + offset_to_plane_u; - for (i=0;i<4;i++,c++) - *d++ = CLAMP((*c) >> pdev->yy); - - d = dest_y + offset_to_plane_v; - for (i=0;i<4;i++,c++) - *d++ = CLAMP((*c) >> pdev->yy); - - dest_y += 4; - } - else if (passes == 1) - { + d = dest_y; + for (i=0;i<4;i++,c++) + *d++ = CLAMP((*c) >> pdev->yy); + + d = dest_y + bytes_per_channel; + for (i=0;i<4;i++,c++) + *d++ = CLAMP((*c) >> pdev->yy); + + d = dest_y + offset_to_plane_u; + for (i=0;i<4;i++,c++) + *d++ = CLAMP((*c) >> pdev->yy); + + d = dest_y + offset_to_plane_v; + for (i=0;i<4;i++,c++) + *d++ = CLAMP((*c) >> pdev->yy); + + dest_y += 4; + } + else if (passes == 1) + { #ifdef USE_SIGNED_INT_FOR_COLOR - int *c1 = temp_colors; - int *c2 = temp_colors+4; + int *c1 = temp_colors; + int *c2 = temp_colors+4; #else - unsigned int *c1 = temp_colors; - unsigned int *c2 = temp_colors+4; + unsigned int *c1 = temp_colors; + unsigned int *c2 = temp_colors+4; #endif - unsigned char *d; + unsigned char *d; - d = dest_y; - for (i=0;i<4;i++,c1++,c2++) - { - *d++ = CLAMP((*c1) >> pdev->yy); - *d++ = CLAMP((*c2) >> pdev->yy); - } - c1 = temp_colors+12; - //c2 = temp_colors+8; - d = dest_y + bytes_per_channel; - for (i=0;i<4;i++,c1++,c2++) - { - *d++ = CLAMP((*c1) >> pdev->yy); - *d++ = CLAMP((*c2) >> pdev->yy); - } - - if (even_line) /* Each line, swap u/v */ - { - even_line=0; - dest_y = dest_v; - dest_u += 8; - } - else - { - even_line=1; - dest_y = dest_u; - dest_v += 8; - } - } + d = dest_y; + for (i=0;i<4;i++,c1++,c2++) + { + *d++ = CLAMP((*c1) >> pdev->yy); + *d++ = CLAMP((*c2) >> pdev->yy); + } + c1 = temp_colors+12; + //c2 = temp_colors+8; + d = dest_y + bytes_per_channel; + for (i=0;i<4;i++,c1++,c2++) + { + *d++ = CLAMP((*c1) >> pdev->yy); + *d++ = CLAMP((*c2) >> pdev->yy); + } + + if (even_line) /* Each line, swap u/v */ + { + even_line=0; + dest_y = dest_v; + dest_u += 8; + } + else + { + even_line=1; + dest_y = dest_u; + dest_v += 8; + } + } - } /* end of while (nblocks-->0) */ + } /* end of while (nblocks-->0) */ - } /* end of for (passes=0;passes<2;passes++) */ + } /* end of for (passes=0;passes<2;passes++) */ } @@ -560,64 +564,64 @@ * */ void pwc_dec23_decompress(const struct pwc_coord *image, - const struct pwc_coord *view, - const struct pwc_coord *offset, - const void *src, - void *dst, - int flags, - const void *data, - int bandlength) + const struct pwc_coord *view, + const struct pwc_coord *offset, + const void *src, + void *dst, + int flags, + const void *data, + int bandlength) { - const struct pwc_dec23_private *pdev = data; - unsigned char *pout, *pout_planar_y=NULL, *pout_planar_u=NULL, *pout_planar_v=NULL; - int i,n,stride,pixel_size; - - - if (flags & PWCX_FLAG_BAYER) - { - pout = dst + (view->x * offset->y) + offset->x; - pixel_size = view->x * 4; - } - else - { - n = view->x * view->y; - - /* offset in Y plane */ - stride = view->x * offset->y; - pout_planar_y = dst + stride + offset->x; - - /* offsets in U/V planes */ - stride = (view->x * offset->y)/4 + offset->x/2; - pout_planar_u = dst + n + + stride; - pout_planar_v = dst + n + n/4 + stride; - - pixel_size = view->x * 4; - } - - - for (i=0;iy;i+=4) - { - if (flags & PWCX_FLAG_BAYER) - { - //TODO: - //DecompressBandBayer(pdev,src,pout,image.x,view->x,flags); - src += bandlength; - pout += pixel_size; - } - else - { - DecompressBand23(pdev,src,pout_planar_y,pout_planar_u,pout_planar_v,image->x,view->x,flags); - src += bandlength; - pout_planar_y += pixel_size; - pout_planar_u += view->x; - pout_planar_v += view->x; - } - } + const struct pwc_dec23_private *pdev = data; + unsigned char *pout, *pout_planar_y=NULL, *pout_planar_u=NULL, *pout_planar_v=NULL; + int i,n,stride,pixel_size; + + + if (flags & PWCX_FLAG_BAYER) + { + pout = dst + (view->x * offset->y) + offset->x; + pixel_size = view->x * 4; + } + else + { + n = view->x * view->y; + + /* offset in Y plane */ + stride = view->x * offset->y; + pout_planar_y = dst + stride + offset->x; + + /* offsets in U/V planes */ + stride = (view->x * offset->y)/4 + offset->x/2; + pout_planar_u = dst + n + + stride; + pout_planar_v = dst + n + n/4 + stride; + + pixel_size = view->x * 4; + } + + + for (i=0;iy;i+=4) + { + if (flags & PWCX_FLAG_BAYER) + { + //TODO: + //DecompressBandBayer(pdev,src,pout,image.x,view->x,flags); + src += bandlength; + pout += pixel_size; + } + else + { + DecompressBand23(pdev,src,pout_planar_y,pout_planar_u,pout_planar_v,image->x,view->x,flags); + src += bandlength; + pout_planar_y += pixel_size; + pout_planar_u += view->x; + pout_planar_v += view->x; + } + } } void pwc_dec23_exit(void) { - /* Do nothing */ + /* Do nothing */ } diff -Nru pwc-10.0.5.orig/pwc-dec23.h pwc-10.0.5/pwc-dec23.h --- pwc-10.0.5.orig/pwc-dec23.h 2004-09-14 11:56:04.000000000 +0200 +++ pwc-10.0.5/pwc-dec23.h 2004-11-22 15:36:27.000000000 +0100 @@ -1,25 +1,25 @@ /* Linux driver for Philips webcam (C) 2004 Luc Saillard (luc@saillard.org) - NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx - driver and thus may have bugs that are not present in the original version. - Please send bug reports and support requests to . - The decompression routines have been implemented by reverse-engineering the - Nemosoft binary pwcx module. Caveat emptor. - - 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. - - 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. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx +driver and thus may have bugs that are not present in the original version. +Please send bug reports and support requests to . +The decompression routines have been implemented by reverse-engineering the +Nemosoft binary pwcx module. Caveat emptor. + +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. + +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. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef PWC_DEC23_H @@ -27,28 +27,28 @@ struct pwc_dec23_private { - unsigned char xx,yy,zz,zzmask; + unsigned char xx, yy, zz, zzmask; - unsigned char table_0004[2*0x4000]; - unsigned char table_8004[2*0x1000]; - unsigned int table_a004[256*12]; - - unsigned char table_d004[8*256]; - unsigned int table_d800[256]; - unsigned int table_dc00[256]; + unsigned char table_0004[2*0x4000]; + unsigned char table_8004[2*0x1000]; + unsigned int table_a004[256*12]; + + unsigned char table_d004[8*256]; + unsigned int table_d800[256]; + unsigned int table_dc00[256]; }; void pwc_dec23_init(int type, int release, unsigned char *buffer, void *private_data); void pwc_dec23_exit(void); void pwc_dec23_decompress(const struct pwc_coord *image, - const struct pwc_coord *view, - const struct pwc_coord *offset, - const void *src, - void *dst, - int flags, - const void *data, - int bandlength); + const struct pwc_coord *view, + const struct pwc_coord *offset, + const void *src, + void *dst, + int flags, + const void *data, + int bandlength); diff -Nru pwc-10.0.5.orig/pwc-if.c pwc-10.0.5/pwc-if.c --- pwc-10.0.5.orig/pwc-if.c 2004-10-21 23:30:00.000000000 +0200 +++ pwc-10.0.5/pwc-if.c 2004-12-02 19:39:30.000000000 +0100 @@ -3,45 +3,45 @@ (C) 1999-2004 Nemosoft Unv. (C) 2004 Luc Saillard (luc@saillard.org) - NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx - driver and thus may have bugs that are not present in the original version. - Please send bug reports and support requests to . - The decompression routines have been implemented by reverse-engineering the - Nemosoft binary pwcx module. Caveat emptor. - - 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. - - 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. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx +driver and thus may have bugs that are not present in the original version. +Please send bug reports and support requests to . +The decompression routines have been implemented by reverse-engineering the +Nemosoft binary pwcx module. Caveat emptor. + +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. + +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. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* - This code forms the interface between the USB layers and the Philips - specific stuff. Some adanved stuff of the driver falls under an - NDA, signed between me and Philips B.V., Eindhoven, the Netherlands, and - is thus not distributed in source form. The binary pwcx.o module - contains the code that falls under the NDA. - - In case you're wondering: 'pwc' stands for "Philips WebCam", but - I really didn't want to type 'philips_web_cam' every time (I'm lazy as - any Linux kernel hacker, but I don't like uncomprehensible abbreviations - without explanation). - - Oh yes, convention: to disctinguish between all the various pointers to - device-structures, I use these names for the pointer variables: - udev: struct usb_device * - vdev: struct video_device * - pdev: struct pwc_devive * + This code forms the interface between the USB layers and the Philips + specific stuff. Some adanved stuff of the driver falls under an + NDA, signed between me and Philips B.V., Eindhoven, the Netherlands, and + is thus not distributed in source form. The binary pwcx.o module + contains the code that falls under the NDA. + + In case you're wondering: 'pwc' stands for "Philips WebCam", but + I really didn't want to type 'philips_web_cam' every time (I'm lazy as + any Linux kernel hacker, but I don't like uncomprehensible abbreviations + without explanation). + + Oh yes, convention: to disctinguish between all the various pointers to + device-structures, I use these names for the pointer variables: +udev: struct usb_device * +vdev: struct video_device * +pdev: struct pwc_devive * */ /* Contributors: @@ -53,16 +53,17 @@ - Xavier Roche: QuickCam Pro 4000 ID - Jens Knudsen: QuickCam Zoom ID - J. Debert: QuickCam for Notebooks ID -*/ + */ + +#include +#include +#include +#include +#include +#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include "linux_usbif.h" #include "pwc.h" #include "pwc-ioctl.h" @@ -74,6 +75,8 @@ /* Function prototypes and driver templates */ +#if 0 /* BSD patch */ + /* hotplug device table support */ static struct usb_device_id pwc_device_table [] = { { USB_DEVICE(0x0471, 0x0302) }, /* Philips models */ @@ -107,45 +110,28 @@ { } }; MODULE_DEVICE_TABLE(usb, pwc_device_table); +#endif /* BSD patch */ -static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id); -static void usb_pwc_disconnect(struct usb_interface *intf); - -static struct usb_driver pwc_driver = { - .owner = THIS_MODULE, - .name = "Philips webcam", /* name */ - .id_table = pwc_device_table, - .probe = usb_pwc_probe, /* probe() */ - .disconnect = usb_pwc_disconnect, /* disconnect() */ -}; - -#define MAX_DEV_HINTS 20 #define MAX_ISOC_ERRORS 20 static int default_size = PSZ_QCIF; static int default_fps = 10; static int default_fbufs = 3; /* Default number of frame buffers */ static int default_mbufs = 2; /* Default number of mmap() buffers */ - int pwc_trace = TRACE_MODULE | TRACE_FLOW | TRACE_PWCX; +int pwc_trace = 0; static int power_save = 0; static int led_on = 100, led_off = 0; /* defaults to LED that is on while in use */ - int pwc_preferred_compression = 2; /* 0..3 = uncompressed..high */ -static struct { - int type; - char serial_number[30]; - int device_node; - struct pwc_device *pdev; -} device_hint[MAX_DEV_HINTS]; +int pwc_preferred_compression = 2; /* 0..3 = uncompressed..high */ /***/ - +#if 0 /* BSD patch */ static int pwc_video_open(struct inode *inode, struct file *file); static int pwc_video_close(struct inode *inode, struct file *file); static ssize_t pwc_video_read(struct file *file, char *buf, - size_t count, loff_t *ppos); + size_t count, loff_t *ppos); static unsigned int pwc_video_poll(struct file *file, poll_table *wait); static int pwc_video_ioctl(struct inode *inode, struct file *file, - unsigned int ioctlnr, unsigned long arg); + unsigned int ioctlnr, unsigned long arg); static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma); static struct file_operations pwc_fops = { @@ -167,7 +153,7 @@ .fops = &pwc_fops, .minor = -1, }; - +#endif /* BSD patch */ /***************************************************************************/ /* Okay, this is some magic that I worked out and the reasoning behind it... @@ -179,7 +165,7 @@ 2) Tell them not to (won't work: they'll do it anyway) 3) Oops the kernel (this will have a negative effect on a user's uptime) 4) Do something sensible. - + Of course, we go for option 4. It happens that this device will be linked to two times, once from @@ -192,223 +178,12 @@ unfortunately I can't free the memory since the struct is still in use by the file descriptor. This free-ing is then deferend until the first opportunity. Crude, but it works. - + A small 'advantage' is that if a user unplugs the cam and plugs it back in, it should get assigned the same video device minor, but unfortunately it's non-trivial to re-link the cam back to the video device... (that would surely be magic! :)) -*/ - -/***************************************************************************/ -/* Private functions */ - -/* Here we want the physical address of the memory. - * This is used when initializing the contents of the area. - */ -static inline unsigned long kvirt_to_pa(unsigned long adr) -{ - unsigned long kva, ret; - - kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); - kva |= adr & (PAGE_SIZE-1); /* restore the offset */ - ret = __pa(kva); - return ret; -} - -static void * rvmalloc(unsigned long size) -{ - void * mem; - unsigned long adr; - - size=PAGE_ALIGN(size); - mem=vmalloc_32(size); - if (mem) - { - memset(mem, 0, size); /* Clear the ram out, no junk to the user */ - adr=(unsigned long) mem; - while (size > 0) - { - SetPageReserved(vmalloc_to_page((void *)adr)); - adr+=PAGE_SIZE; - size-=PAGE_SIZE; - } - } - return mem; -} - -static void rvfree(void * mem, unsigned long size) -{ - unsigned long adr; - - if (mem) - { - adr=(unsigned long) mem; - while ((long) size > 0) - { - ClearPageReserved(vmalloc_to_page((void *)adr)); - adr+=PAGE_SIZE; - size-=PAGE_SIZE; - } - vfree(mem); - } -} - - - - -static int pwc_allocate_buffers(struct pwc_device *pdev) -{ - int i; - void *kbuf; - - Trace(TRACE_MEMORY, ">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev); - - if (pdev == NULL) - return -ENXIO; - -#ifdef PWC_MAGIC - if (pdev->magic != PWC_MAGIC) { - Err("allocate_buffers(): magic failed.\n"); - return -ENXIO; - } -#endif - /* Allocate Isochronuous pipe buffers */ - for (i = 0; i < MAX_ISO_BUFS; i++) { - if (pdev->sbuf[i].data == NULL) { - kbuf = kmalloc(ISO_BUFFER_SIZE, GFP_KERNEL); - if (kbuf == NULL) { - Err("Failed to allocate iso buffer %d.\n", i); - return -ENOMEM; - } - Trace(TRACE_MEMORY, "Allocated iso buffer at %p.\n", kbuf); - pdev->sbuf[i].data = kbuf; - memset(kbuf, 0, ISO_BUFFER_SIZE); - } - } - - /* Allocate frame buffer structure */ - if (pdev->fbuf == NULL) { - kbuf = kmalloc(default_fbufs * sizeof(struct pwc_frame_buf), GFP_KERNEL); - if (kbuf == NULL) { - Err("Failed to allocate frame buffer structure.\n"); - return -ENOMEM; - } - Trace(TRACE_MEMORY, "Allocated frame buffer structure at %p.\n", kbuf); - pdev->fbuf = kbuf; - memset(kbuf, 0, default_fbufs * sizeof(struct pwc_frame_buf)); - } - /* create frame buffers, and make circular ring */ - for (i = 0; i < default_fbufs; i++) { - if (pdev->fbuf[i].data == NULL) { - kbuf = vmalloc(PWC_FRAME_SIZE); /* need vmalloc since frame buffer > 128K */ - if (kbuf == NULL) { - Err("Failed to allocate frame buffer %d.\n", i); - return -ENOMEM; - } - Trace(TRACE_MEMORY, "Allocated frame buffer %d at %p.\n", i, kbuf); - pdev->fbuf[i].data = kbuf; - memset(kbuf, 128, PWC_FRAME_SIZE); - } - } - - /* Allocate decompressor table space */ - kbuf = NULL; - switch (pdev->type) - { - case 675: - case 680: - case 690: - case 720: - case 730: - case 740: - case 750: - Trace(TRACE_MEMORY,"private_data(%d)\n",sizeof(struct pwc_dec23_private)); - kbuf = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL); /* Timon & Kiara */ - break; - case 645: - case 646: - /* TODO & FIXME */ - kbuf = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL); - break; - } - if (kbuf == NULL) { - Err("Failed to allocate decompress table.\n"); - return -ENOMEM; - } - pdev->decompress_data = kbuf; - - /* Allocate image buffer; double buffer for mmap() */ - kbuf = rvmalloc(default_mbufs * pdev->len_per_image); - if (kbuf == NULL) { - Err("Failed to allocate image buffer(s). needed (%d)\n",default_mbufs * pdev->len_per_image); - return -ENOMEM; - } - Trace(TRACE_MEMORY, "Allocated image buffer at %p.\n", kbuf); - pdev->image_data = kbuf; - for (i = 0; i < default_mbufs; i++) - pdev->image_ptr[i] = kbuf + i * pdev->len_per_image; - for (; i < MAX_IMAGES; i++) - pdev->image_ptr[i] = NULL; - - kbuf = NULL; - - Trace(TRACE_MEMORY, "<< pwc_allocate_buffers()\n"); - return 0; -} - -static void pwc_free_buffers(struct pwc_device *pdev) -{ - int i; - - Trace(TRACE_MEMORY, "Entering free_buffers(%p).\n", pdev); - - if (pdev == NULL) - return; -#ifdef PWC_MAGIC - if (pdev->magic != PWC_MAGIC) { - Err("free_buffers(): magic failed.\n"); - return; - } -#endif - - /* Release Iso-pipe buffers */ - for (i = 0; i < MAX_ISO_BUFS; i++) - if (pdev->sbuf[i].data != NULL) { - Trace(TRACE_MEMORY, "Freeing ISO buffer at %p.\n", pdev->sbuf[i].data); - kfree(pdev->sbuf[i].data); - pdev->sbuf[i].data = NULL; - } - - /* The same for frame buffers */ - if (pdev->fbuf != NULL) { - for (i = 0; i < default_fbufs; i++) { - if (pdev->fbuf[i].data != NULL) { - Trace(TRACE_MEMORY, "Freeing frame buffer %d at %p.\n", i, pdev->fbuf[i].data); - vfree(pdev->fbuf[i].data); - pdev->fbuf[i].data = NULL; - } - } - kfree(pdev->fbuf); - pdev->fbuf = NULL; - } - - /* Intermediate decompression buffer & tables */ - if (pdev->decompress_data != NULL) { - Trace(TRACE_MEMORY, "Freeing decompression buffer at %p.\n", pdev->decompress_data); - kfree(pdev->decompress_data); - pdev->decompress_data = NULL; - } - pdev->decompressor = NULL; - - /* Release image buffers */ - if (pdev->image_data != NULL) { - Trace(TRACE_MEMORY, "Freeing image buffer at %p.\n", pdev->image_data); - rvfree(pdev->image_data, default_mbufs * pdev->len_per_image); - } - pdev->image_data = NULL; - - Trace(TRACE_MEMORY, "Leaving free_buffers().\n"); -} + */ /* The frame & image buffer mess. @@ -444,29 +219,30 @@ Eventually, I came up with a system with 2 lists: an 'empty' frame list and a 'full' frame list: - * Initially, all frame buffers but one are on the 'empty' list; the one - remaining buffer is our initial fill frame. - * If a frame is needed for filling, we try to take it from the 'empty' - list, unless that list is empty, in which case we take the buffer at - the head of the 'full' list. - * When our fill buffer has been filled, it is appended to the 'full' - list. - * If a frame is needed by read() or mmap(), it is taken from the head of - the 'full' list, handled, and then appended to the 'empty' list. If no - buffer is present on the 'full' list, we wait. - The advantage is that the buffer that is currently being decompressed/ - converted, is on neither list, and thus not in our way (any other scheme - I tried had the problem of old data lingering in the queue). - - Whatever strategy you choose, it always remains a tradeoff: with more - frame buffers the chances of a missed frame are reduced. On the other - hand, on slower machines it introduces lag because the queue will - always be full. + * Initially, all frame buffers but one are on the 'empty' list; the one + remaining buffer is our initial fill frame. + * If a frame is needed for filling, we try to take it from the 'empty' + list, unless that list is empty, in which case we take the buffer at + the head of the 'full' list. + * When our fill buffer has been filled, it is appended to the 'full' + list. + * If a frame is needed by read() or mmap(), it is taken from the head of + the 'full' list, handled, and then appended to the 'empty' list. If no + buffer is present on the 'full' list, we wait. + The advantage is that the buffer that is currently being decompressed/ + converted, is on neither list, and thus not in our way (any other scheme + I tried had the problem of old data lingering in the queue). + + Whatever strategy you choose, it always remains a tradeoff: with more + frame buffers the chances of a missed frame are reduced. On the other + hand, on slower machines it introduces lag because the queue will + always be full. */ +#if 0 /* BSD patch */ /** \brief Find next frame buffer to fill. Take from empty or full list, whichever comes first. - */ + */ static inline int pwc_next_fill_frame(struct pwc_device *pdev) { int ret; @@ -518,7 +294,7 @@ \brief Reset all buffers, pointers and lists, except for the image_used[] buffer. If the image_used[] buffer is cleared too, mmap()/VIDIOCSYNC will run into trouble. - */ + */ static void pwc_reset_buffers(struct pwc_device *pdev) { int i; @@ -548,7 +324,7 @@ /** \brief Do all the handling for getting one frame: get pointer, decompress, advance pointers. - */ + */ static int pwc_handle_frame(struct pwc_device *pdev) { int ret = 0; @@ -578,7 +354,7 @@ /* Decompression is a lenghty process, so it's outside of the lock. This gives the isoc_handler the opportunity to fill more frames in the mean time. - */ + */ spin_unlock_irqrestore(&pdev->ptrlock, flags); ret = pwc_decompress(pdev); spin_lock_irqsave(&pdev->ptrlock, flags); @@ -601,7 +377,7 @@ /** \brief Advance pointers of image buffer (after each user request) -*/ + */ static inline void pwc_next_image(struct pwc_device *pdev) { pdev->image_used[pdev->fill_image] = 0; @@ -651,7 +427,7 @@ Trace(TRACE_FLOW, "pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg); /* Give up after a number of contiguous errors on the USB bus. Appearantly something is wrong so we simulate an unplug event. - */ + */ if (++pdev->visoc_errors > MAX_ISOC_ERRORS) { Info("Too many ISOC errors, bailing out.\n"); @@ -676,9 +452,9 @@ pdev->visoc_errors = 0; /* vsync: 0 = don't copy data - 1 = sync-hunt - 2 = synched - */ + 1 = sync-hunt + 2 = synched + */ /* Compact data */ for (i = 0; i < urb->number_of_packets; i++) { fst = urb->iso_frame_desc[i].status; @@ -707,15 +483,15 @@ /* Shorter packet... We probably have the end of an image-frame; wake up read() process and let select()/poll() do something. Decompression is done in user time over there. - */ + */ if (pdev->vsync == 2) { /* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus frames on the USB wire after an exposure change. This conditition is however detected in the cam and a bit is set in the header. - */ + */ if (pdev->type == 730) { unsigned char *ptr = (unsigned char *)fbuf->data; - + if (ptr[1] == 1 && ptr[0] & 0x10) { #if PWC_DEBUG Debug("Hyundai CMOS sensor bug. Dropping frame %d.\n", fbuf->sequence); @@ -740,18 +516,18 @@ after a short frame; this condition is filtered out specifically. A 4 byte frame doesn't make sense anyway. So we get either this sequence: - drop_bit set -> 4 byte frame -> short frame -> good frame + drop_bit set -> 4 byte frame -> short frame -> good frame Or this one: - drop_bit set -> short frame -> good frame + drop_bit set -> short frame -> good frame So we drop either 3 or 2 frames in all! - */ + */ if (fbuf->filled == 4) pdev->drop_frames++; } /* In case we were instructed to drop the frame, do so silently. The buffer pointers are not updated either (but the counters are reset below). - */ + */ if (pdev->drop_frames > 0) pdev->drop_frames--; else { @@ -808,46 +584,55 @@ if (i != 0) Err("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i); } - +#endif /* BSD patch */ static int pwc_isoc_init(struct pwc_device *pdev) { struct usb_device *udev; - struct urb *urb; - int i, j, ret; - struct usb_interface *intf; - struct usb_host_interface *idesc = NULL; + struct usb_interface_desc *ifd; + struct usb_endpoint_desc *epd; + int i, ret; + Trace(TRACE_OPEN, ">> pwc_isoc_init()\n"); if (pdev == NULL) return -EFAULT; if (pdev->iso_init) return 0; pdev->vsync = 0; udev = pdev->udev; + ifd = &udev->interfacedesc; + epd = &udev->endpointdesc; + /* Get the current alternate interface, adjust packet size */ - if (!udev->actconfig) - return -EFAULT; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,5) - idesc = &udev->actconfig->interface[0]->altsetting[pdev->valternate]; -#else - intf = usb_ifnum_to_if(udev, 0); - if (intf) - idesc = usb_altnum_to_altsetting(intf, pdev->valternate); -#endif - - if (!idesc) + ifd->uid_config_index = USB_CURRENT_CONFIG_INDEX; + ifd->uid_interface_index = 0; + ifd->uid_alt_index = pdev->valternate; + if (ioctl(udev->fd, USB_GET_INTERFACE_DESC, ifd) < 0) { + perror("USB_GET_INTERFACE_DESC"); return -EFAULT; + } + /* Search video endpoint */ pdev->vmax_packet_size = -1; - for (i = 0; i < idesc->desc.bNumEndpoints; i++) - if ((idesc->endpoint[i].desc.bEndpointAddress & 0xF) == pdev->vendpoint) { - pdev->vmax_packet_size = idesc->endpoint[i].desc.wMaxPacketSize; - break; + for (i = 0; i < ifd->uid_desc.bNumEndpoints; i++ ) { + epd->ued_config_index = USB_CURRENT_CONFIG_INDEX; + epd->ued_alt_index = pdev->valternate; + epd->ued_endpoint_index = i; + if (ioctl(udev->fd, USB_GET_ENDPOINT_DESC, epd) < 0) { + perror("USB_GET_ENDPOINT_DESC"); + return -EFAULT; + } else { + if ((epd->ued_desc.bEndpointAddress & 0xF) == pdev->vendpoint) { + pdev->vmax_packet_size = (int)UGETW(epd->ued_desc.wMaxPacketSize); + break; + } + } - + } + if (pdev->vmax_packet_size < 0 || pdev->vmax_packet_size > ISO_MAX_FRAME_SIZE) { Err("Failed to find packet size for video endpoint in current alternate setting.\n"); return -ENFILE; /* Odd error, that should be noticable */ @@ -859,7 +644,7 @@ ret = usb_set_interface(pdev->udev, 0, pdev->valternate); if (ret < 0) return ret; - +#if 0 /* BSD patch */ for (i = 0; i < MAX_ISO_BUFS; i++) { urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL); if (urb == NULL) { @@ -868,7 +653,7 @@ break; } pdev->sbuf[i].urb = urb; - Trace(TRACE_MEMORY, "Allocated URB at 0x%p\n", urb); + Trace(TRACE_MEMORY, "Allocated URB at %p\n", urb); } if (ret) { /* De-allocate in reverse order */ @@ -887,12 +672,12 @@ urb->interval = 1; // devik urb->dev = udev; - urb->pipe = usb_rcvisocpipe(udev, pdev->vendpoint); + urb->pipe = usb_rcvisocpipe(udev, pdev->vendpoint); urb->transfer_flags = URB_ISO_ASAP; - urb->transfer_buffer = pdev->sbuf[i].data; - urb->transfer_buffer_length = ISO_BUFFER_SIZE; - urb->complete = pwc_isoc_handler; - urb->context = pdev; + urb->transfer_buffer = pdev->sbuf[i].data; + urb->transfer_buffer_length = ISO_BUFFER_SIZE; + urb->complete = pwc_isoc_handler; + urb->context = pdev; urb->start_frame = 0; urb->number_of_packets = ISO_FRAMES_PER_DESC; for (j = 0; j < ISO_FRAMES_PER_DESC; j++) { @@ -907,8 +692,9 @@ if (ret) Err("isoc_init() submit_urb %d failed with error %d\n", i, ret); else - Trace(TRACE_MEMORY, "URB 0x%p submitted.\n", pdev->sbuf[i].urb); + Trace(TRACE_MEMORY, "URB %p submitted.\n", pdev->sbuf[i].urb); } +#endif /* BSD patch */ /* All is done... */ pdev->iso_init = 1; @@ -918,12 +704,10 @@ static void pwc_isoc_cleanup(struct pwc_device *pdev) { - int i; - Trace(TRACE_OPEN, ">> pwc_isoc_cleanup()\n"); if (pdev == NULL) return; - +#if 0 /* BSD patch */ /* Unlinking ISOC buffers one by one */ for (i = 0; i < MAX_ISO_BUFS; i++) { struct urb *urb; @@ -939,10 +723,10 @@ pdev->sbuf[i].urb = NULL; } } - +#endif /* BSD patch */ /* Stop camera, but only if we are sure the camera is still there (unplug is signalled by EPIPE) - */ + */ if (pdev->error_status && pdev->error_status != EPIPE) { Trace(TRACE_OPEN, "Setting alternate interface 0.\n"); usb_set_interface(pdev->udev, 0, 0); @@ -958,16 +742,14 @@ /* Stop isoc stuff */ pwc_isoc_cleanup(pdev); - /* Reset parameters */ - pwc_reset_buffers(pdev); /* Try to set video mode... */ start = ret = pwc_set_video_mode(pdev, width, height, new_fps, new_compression, new_snapshot); if (ret) { - Trace(TRACE_FLOW, "pwc_set_video_mode attempt 1 failed.\n"); + Trace(TRACE_FLOW, "pwc_set_video_mode attempt 1 failed.\n"); /* That failed... restore old mode (we know that worked) */ start = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot); if (start) { - Trace(TRACE_FLOW, "pwc_set_video_mode attempt 2 failed.\n"); + Trace(TRACE_FLOW, "pwc_set_video_mode attempt 2 failed.\n"); } } if (start == 0) @@ -982,6 +764,7 @@ return ret; /* Return original error code */ } +#if 0 /* vinvin BSD patch */ /********* * sysfs *********/ @@ -998,7 +781,7 @@ } static ssize_t store_pan_tilt(struct class_device *class_dev, const char *buf, - size_t count) + size_t count) { struct pwc_device *pdev = cd_to_pwc(class_dev); int pan, tilt; @@ -1015,7 +798,7 @@ return strlen(buf); } static CLASS_DEVICE_ATTR(pan_tilt, S_IRUGO | S_IWUSR, show_pan_tilt, - store_pan_tilt); + store_pan_tilt); static void pwc_create_sysfs_files(struct video_device *vdev) { @@ -1030,29 +813,26 @@ if (pdev->features & FEATURE_MOTOR_PANTILT) video_device_remove_file(vdev, &class_device_attr_pan_tilt); } +#endif /* vinvin BSD patch */ /***************************************************************************/ /* Video4Linux functions */ -static int pwc_video_open(struct inode *inode, struct file *file) +int pwc_video_open(struct pwc_device *pdev) { int i; - struct video_device *vdev = video_devdata(file); - struct pwc_device *pdev; - Trace(TRACE_OPEN, ">> video_open called(vdev = 0x%p).\n", vdev); - - pdev = (struct pwc_device *)vdev->priv; + Trace(TRACE_OPEN, ">> video_open called(pdev = %p).\n", pdev); + if (pdev == NULL) - BUG(); + return -EFAULT; if (pdev->vopen) return -EBUSY; - - down(&pdev->modlock); + if (!pdev->usb_init) { Trace(TRACE_OPEN, "Doing first time initialization.\n"); pdev->usb_init = 1; - + if (pwc_trace & TRACE_OPEN) { /* Query sensor type */ @@ -1063,21 +843,21 @@ if (ret >= 0) { switch(i) { - case 0x00: sensor_type = "Hyundai CMOS sensor"; break; - case 0x20: sensor_type = "Sony CCD sensor + TDA8787"; break; - case 0x2E: sensor_type = "Sony CCD sensor + Exas 98L59"; break; - case 0x2F: sensor_type = "Sony CCD sensor + ADI 9804"; break; - case 0x30: sensor_type = "Sharp CCD sensor + TDA8787"; break; - case 0x3E: sensor_type = "Sharp CCD sensor + Exas 98L59"; break; - case 0x3F: sensor_type = "Sharp CCD sensor + ADI 9804"; break; - case 0x40: sensor_type = "UPA 1021 sensor"; break; - case 0x100: sensor_type = "VGA sensor"; break; - case 0x101: sensor_type = "PAL MR sensor"; break; - default: sensor_type = "unknown type of sensor"; break; + case 0x00: sensor_type = "Hyundai CMOS sensor"; break; + case 0x20: sensor_type = "Sony CCD sensor + TDA8787"; break; + case 0x2E: sensor_type = "Sony CCD sensor + Exas 98L59"; break; + case 0x2F: sensor_type = "Sony CCD sensor + ADI 9804"; break; + case 0x30: sensor_type = "Sharp CCD sensor + TDA8787"; break; + case 0x3E: sensor_type = "Sharp CCD sensor + Exas 98L59"; break; + case 0x3F: sensor_type = "Sharp CCD sensor + ADI 9804"; break; + case 0x40: sensor_type = "UPA 1021 sensor"; break; + case 0x100: sensor_type = "VGA sensor"; break; + case 0x101: sensor_type = "PAL MR sensor"; break; + default: sensor_type = "unknown type of sensor"; break; } } if (sensor_type != NULL) - Info("This %s camera is equipped with a %s (%d).\n", pdev->vdev->name, sensor_type, i); + Info("This %s camera is equipped with a %s (%d).\n", pdev->vdev_name, sensor_type, i); } } @@ -1090,9 +870,10 @@ /* Set LED on/off time */ if (pwc_set_leds(pdev, led_on, led_off) < 0) Info("Failed to set LED on/off time.\n"); - + pwc_construct(pdev); /* set min/max sizes correct */ +#if 0 /* BSD patch */ /* So far, so good. Allocate memory. */ i = pwc_allocate_buffers(pdev); if (i < 0) { @@ -1100,9 +881,10 @@ up(&pdev->modlock); return i; } - + /* Reset buffers & parameters */ pwc_reset_buffers(pdev); +#endif /* BSD patch */ for (i = 0; i < default_mbufs; i++) pdev->image_used[i] = 0; pdev->vframe_count = 0; @@ -1121,7 +903,7 @@ /* Start iso pipe for video; first try the last used video size (or the default one); if that fails try QCIF/10 or QSIF/10; it that fails too, give up. - */ + */ i = pwc_set_video_mode(pdev, pwc_image_sizes[pdev->vsize].x, pwc_image_sizes[pdev->vsize].y, pdev->vframes, pdev->vcompression, 0); if (i) { Trace(TRACE_OPEN, "First attempt at set_video_mode failed.\n"); @@ -1132,63 +914,53 @@ } if (i) { Trace(TRACE_OPEN, "Second attempt at set_video_mode failed.\n"); - up(&pdev->modlock); return i; } - + i = pwc_isoc_init(pdev); if (i) { Trace(TRACE_OPEN, "Failed to init ISOC stuff = %d.\n", i); - up(&pdev->modlock); return i; } pdev->vopen++; - file->private_data = vdev; - up(&pdev->modlock); Trace(TRACE_OPEN, "<< video_open() returns 0.\n"); return 0; } /* Note that all cleanup is done in the reverse order as in _open */ -static int pwc_video_close(struct inode *inode, struct file *file) +int pwc_video_close(struct pwc_device *pdev) { - struct video_device *vdev = file->private_data; - struct pwc_device *pdev; int i; - Trace(TRACE_OPEN, ">> video_close called(vdev = 0x%p).\n", vdev); - - pdev = (struct pwc_device *)vdev->priv; if (pdev->vopen == 0) Info("video_close() called on closed device?\n"); /* Dump statistics, but only if a reasonable amount of frames were processed (to prevent endless log-entries in case of snap-shot programs) - */ + */ if (pdev->vframe_count > 20) Info("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error); switch (pdev->type) - { - case 675: - case 680: - case 690: - case 720: - case 730: - case 740: - case 750: - pwc_dec23_exit(); /* Timon & Kiara */ - break; - case 645: - case 646: - pwc_dec1_exit(); - break; - } + { + case 675: + case 680: + case 690: + case 720: + case 730: + case 740: + case 750: + pwc_dec23_exit(); /* Timon & Kiara */ + break; + case 645: + case 646: + pwc_dec1_exit(); + break; + } pwc_isoc_cleanup(pdev); - pwc_free_buffers(pdev); /* Turn off LEDS and power down camera, but only when not unplugged */ if (pdev->error_status != EPIPE) { @@ -1209,25 +981,25 @@ /* * FIXME: what about two parallel reads ???? * ANSWER: Not supported. You can't open the device more than once, - despite what the V4L1 interface says. First, I don't see - the need, second there's no mechanism of alerting the - 2nd/3rd/... process of events like changing image size. - And I don't see the point of blocking that for the - 2nd/3rd/... process. - In multi-threaded environments reading parallel from any - device is tricky anyhow. + despite what the V4L1 interface says. First, I don't see + the need, second there's no mechanism of alerting the + 2nd/3rd/... process of events like changing image size. + And I don't see the point of blocking that for the + 2nd/3rd/... process. + In multi-threaded environments reading parallel from any + device is tricky anyhow. */ - +#if 0 /* BSD patch */ static ssize_t pwc_video_read(struct file *file, char *buf, - size_t count, loff_t *ppos) + size_t count, loff_t *ppos) { struct video_device *vdev = file->private_data; struct pwc_device *pdev; int noblock = file->f_flags & O_NONBLOCK; DECLARE_WAITQUEUE(wait, current); - int bytes_to_read; + int bytes_to_read; - Trace(TRACE_READ, "video_read(0x%p, %p, %d) called.\n", vdev, buf, count); + Trace(TRACE_READ, "video_read(%p, %p, %d) called.\n", vdev, buf, count); if (vdev == NULL) return -EFAULT; pdev = vdev->priv; @@ -1247,22 +1019,22 @@ set_current_state(TASK_RUNNING); return -pdev->error_status ; } - if (noblock) { - remove_wait_queue(&pdev->frameq, &wait); - set_current_state(TASK_RUNNING); - return -EWOULDBLOCK; - } - if (signal_pending(current)) { - remove_wait_queue(&pdev->frameq, &wait); - set_current_state(TASK_RUNNING); - return -ERESTARTSYS; - } - schedule(); - set_current_state(TASK_INTERRUPTIBLE); + if (noblock) { + remove_wait_queue(&pdev->frameq, &wait); + set_current_state(TASK_RUNNING); + return -EWOULDBLOCK; + } + if (signal_pending(current)) { + remove_wait_queue(&pdev->frameq, &wait); + set_current_state(TASK_RUNNING); + return -ERESTARTSYS; + } + schedule(); + set_current_state(TASK_INTERRUPTIBLE); } remove_wait_queue(&pdev->frameq, &wait); set_current_state(TASK_RUNNING); - + /* Decompress and release frame */ if (pwc_handle_frame(pdev)) return -EFAULT; @@ -1272,7 +1044,7 @@ if (pdev->vpalette == VIDEO_PALETTE_RAW) bytes_to_read = pdev->frame_size; else - bytes_to_read = pdev->view.size; + bytes_to_read = pdev->view.size; /* copy bytes to user space; we allow for partial reads */ if (count + pdev->image_read_pos > bytes_to_read) @@ -1308,7 +1080,7 @@ } static int pwc_video_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) + unsigned int cmd, void *arg) { struct video_device *vdev = file->private_data; struct pwc_device *pdev; @@ -1323,312 +1095,312 @@ switch (cmd) { /* Query cabapilities */ case VIDIOCGCAP: - { - struct video_capability *caps = arg; + { + struct video_capability *caps = arg; - strcpy(caps->name, vdev->name); - caps->type = VID_TYPE_CAPTURE; - caps->channels = 1; - caps->audios = 0; - caps->minwidth = pdev->view_min.x; - caps->minheight = pdev->view_min.y; - caps->maxwidth = pdev->view_max.x; - caps->maxheight = pdev->view_max.y; - break; - } + strcpy(caps->name, vdev->name); + caps->type = VID_TYPE_CAPTURE; + caps->channels = 1; + caps->audios = 0; + caps->minwidth = pdev->view_min.x; + caps->minheight = pdev->view_min.y; + caps->maxwidth = pdev->view_max.x; + caps->maxheight = pdev->view_max.y; + break; + } - /* Channel functions (simulate 1 channel) */ + /* Channel functions (simulate 1 channel) */ case VIDIOCGCHAN: - { - struct video_channel *v = arg; + { + struct video_channel *v = arg; - if (v->channel != 0) - return -EINVAL; - v->flags = 0; - v->tuners = 0; - v->type = VIDEO_TYPE_CAMERA; - strcpy(v->name, "Webcam"); - return 0; - } + if (v->channel != 0) + return -EINVAL; + v->flags = 0; + v->tuners = 0; + v->type = VIDEO_TYPE_CAMERA; + strcpy(v->name, "Webcam"); + return 0; + } case VIDIOCSCHAN: - { - /* The spec says the argument is an integer, but - the bttv driver uses a video_channel arg, which - makes sense becasue it also has the norm flag. - */ - struct video_channel *v = arg; - if (v->channel != 0) - return -EINVAL; - return 0; - } + { + /* The spec says the argument is an integer, but + the bttv driver uses a video_channel arg, which + makes sense becasue it also has the norm flag. + */ + struct video_channel *v = arg; + if (v->channel != 0) + return -EINVAL; + return 0; + } - /* Picture functions; contrast etc. */ + /* Picture functions; contrast etc. */ case VIDIOCGPICT: - { - struct video_picture *p = arg; - int val; + { + struct video_picture *p = arg; + int val; - val = pwc_get_brightness(pdev); - if (val >= 0) - p->brightness = val; - else - p->brightness = 0xffff; - val = pwc_get_contrast(pdev); - if (val >= 0) - p->contrast = val; - else - p->contrast = 0xffff; - /* Gamma, Whiteness, what's the difference? :) */ - val = pwc_get_gamma(pdev); - if (val >= 0) - p->whiteness = val; - else - p->whiteness = 0xffff; - val = pwc_get_saturation(pdev); - if (val >= 0) - p->colour = val; - else - p->colour = 0xffff; - p->depth = 24; - p->palette = pdev->vpalette; - p->hue = 0xFFFF; /* N/A */ - break; - } + val = pwc_get_brightness(pdev); + if (val >= 0) + p->brightness = val; + else + p->brightness = 0xffff; + val = pwc_get_contrast(pdev); + if (val >= 0) + p->contrast = val; + else + p->contrast = 0xffff; + /* Gamma, Whiteness, what's the difference? :) */ + val = pwc_get_gamma(pdev); + if (val >= 0) + p->whiteness = val; + else + p->whiteness = 0xffff; + val = pwc_get_saturation(pdev); + if (val >= 0) + p->colour = val; + else + p->colour = 0xffff; + p->depth = 24; + p->palette = pdev->vpalette; + p->hue = 0xFFFF; /* N/A */ + break; + } case VIDIOCSPICT: - { - struct video_picture *p = arg; - /* - * FIXME: Suppose we are mid read - ANSWER: No problem: the firmware of the camera - can handle brightness/contrast/etc - changes at _any_ time, and the palette - is used exactly once in the uncompress - routine. - */ - pwc_set_brightness(pdev, p->brightness); - pwc_set_contrast(pdev, p->contrast); - pwc_set_gamma(pdev, p->whiteness); - pwc_set_saturation(pdev, p->colour); - if (p->palette && p->palette != pdev->vpalette) { - switch (p->palette) { - case VIDEO_PALETTE_YUV420P: - case VIDEO_PALETTE_RAW: - pdev->vpalette = p->palette; - return pwc_try_video_mode(pdev, pdev->image.x, pdev->image.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot); - break; - default: - return -EINVAL; - break; + { + struct video_picture *p = arg; + /* + * FIXME: Suppose we are mid read +ANSWER: No problem: the firmware of the camera +can handle brightness/contrast/etc +changes at _any_ time, and the palette +is used exactly once in the uncompress +routine. +*/ + pwc_set_brightness(pdev, p->brightness); + pwc_set_contrast(pdev, p->contrast); + pwc_set_gamma(pdev, p->whiteness); + pwc_set_saturation(pdev, p->colour); + if (p->palette && p->palette != pdev->vpalette) { + switch (p->palette) { + case VIDEO_PALETTE_YUV420P: + case VIDEO_PALETTE_RAW: + pdev->vpalette = p->palette; + return pwc_try_video_mode(pdev, pdev->image.x, pdev->image.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot); + break; + default: + return -EINVAL; + break; + } } + break; } - break; - } - /* Window/size parameters */ + /* Window/size parameters */ case VIDIOCGWIN: - { - struct video_window *vw = arg; - - vw->x = 0; - vw->y = 0; - vw->width = pdev->view.x; - vw->height = pdev->view.y; - vw->chromakey = 0; - vw->flags = (pdev->vframes << PWC_FPS_SHIFT) | - (pdev->vsnapshot ? PWC_FPS_SNAPSHOT : 0); - break; - } - + { + struct video_window *vw = arg; + + vw->x = 0; + vw->y = 0; + vw->width = pdev->view.x; + vw->height = pdev->view.y; + vw->chromakey = 0; + vw->flags = (pdev->vframes << PWC_FPS_SHIFT) | + (pdev->vsnapshot ? PWC_FPS_SNAPSHOT : 0); + break; + } + case VIDIOCSWIN: - { - struct video_window *vw = arg; - int fps, snapshot, ret; + { + struct video_window *vw = arg; + int fps, snapshot, ret; - fps = (vw->flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT; - snapshot = vw->flags & PWC_FPS_SNAPSHOT; - if (fps == 0) - fps = pdev->vframes; - if (pdev->view.x == vw->width && pdev->view.y && fps == pdev->vframes && snapshot == pdev->vsnapshot) - return 0; - ret = pwc_try_video_mode(pdev, vw->width, vw->height, fps, pdev->vcompression, snapshot); - if (ret) - return ret; - break; - } - - /* We don't have overlay support (yet) */ + fps = (vw->flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT; + snapshot = vw->flags & PWC_FPS_SNAPSHOT; + if (fps == 0) + fps = pdev->vframes; + if (pdev->view.x == vw->width && pdev->view.y && fps == pdev->vframes && snapshot == pdev->vsnapshot) + return 0; + ret = pwc_try_video_mode(pdev, vw->width, vw->height, fps, pdev->vcompression, snapshot); + if (ret) + return ret; + break; + } + + /* We don't have overlay support (yet) */ case VIDIOCGFBUF: - { - struct video_buffer *vb = arg; + { + struct video_buffer *vb = arg; - memset(vb,0,sizeof(*vb)); - break; - } + memset(vb,0,sizeof(*vb)); + break; + } - /* mmap() functions */ + /* mmap() functions */ case VIDIOCGMBUF: - { - /* Tell the user program how much memory is needed for a mmap() */ - struct video_mbuf *vm = arg; - int i; - - memset(vm, 0, sizeof(*vm)); - vm->size = default_mbufs * pdev->len_per_image; - vm->frames = default_mbufs; /* double buffering should be enough for most applications */ - for (i = 0; i < default_mbufs; i++) - vm->offsets[i] = i * pdev->len_per_image; - break; - } + { + /* Tell the user program how much memory is needed for a mmap() */ + struct video_mbuf *vm = arg; + int i; + + memset(vm, 0, sizeof(*vm)); + vm->size = default_mbufs * pdev->len_per_image; + vm->frames = default_mbufs; /* double buffering should be enough for most applications */ + for (i = 0; i < default_mbufs; i++) + vm->offsets[i] = i * pdev->len_per_image; + break; + } case VIDIOCMCAPTURE: - { - /* Start capture into a given image buffer (called 'frame' in video_mmap structure) */ - struct video_mmap *vm = arg; + { + /* Start capture into a given image buffer (called 'frame' in video_mmap structure) */ + struct video_mmap *vm = arg; - Trace(TRACE_READ, "VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm->width, vm->height, vm->frame, vm->format); - if (vm->frame < 0 || vm->frame >= default_mbufs) - return -EINVAL; + Trace(TRACE_READ, "VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm->width, vm->height, vm->frame, vm->format); + if (vm->frame < 0 || vm->frame >= default_mbufs) + return -EINVAL; - /* xawtv is nasty. It probes the available palettes - by setting a very small image size and trying - various palettes... The driver doesn't support - such small images, so I'm working around it. - */ - if (vm->format) - { - switch (vm->format) + /* xawtv is nasty. It probes the available palettes + by setting a very small image size and trying + various palettes... The driver doesn't support + such small images, so I'm working around it. + */ + if (vm->format) { - case VIDEO_PALETTE_YUV420P: - case VIDEO_PALETTE_RAW: - break; - default: - return -EINVAL; - break; + switch (vm->format) + { + case VIDEO_PALETTE_YUV420P: + case VIDEO_PALETTE_RAW: + break; + default: + return -EINVAL; + break; + } } + + if ((vm->width != pdev->view.x || vm->height != pdev->view.y) && + (vm->width >= pdev->view_min.x && vm->height >= pdev->view_min.y)) { + int ret; + + Trace(TRACE_OPEN, "VIDIOCMCAPTURE: changing size to please xawtv :-(.\n"); + ret = pwc_try_video_mode(pdev, vm->width, vm->height, pdev->vframes, pdev->vcompression, pdev->vsnapshot); + if (ret) + return ret; + } /* ... size mismatch */ + + /* FIXME: should we lock here? */ + if (pdev->image_used[vm->frame]) + return -EBUSY; /* buffer wasn't available. Bummer */ + pdev->image_used[vm->frame] = 1; + + /* Okay, we're done here. In the SYNC call we wait until a + frame comes available, then expand image into the given + buffer. + In contrast to the CPiA cam the Philips cams deliver a + constant stream, almost like a grabber card. Also, + we have separate buffers for the rawdata and the image, + meaning we can nearly always expand into the requested buffer. + */ + Trace(TRACE_READ, "VIDIOCMCAPTURE done.\n"); + break; } - if ((vm->width != pdev->view.x || vm->height != pdev->view.y) && - (vm->width >= pdev->view_min.x && vm->height >= pdev->view_min.y)) { + case VIDIOCSYNC: + { + /* The doc says: "Whenever a buffer is used it should + call VIDIOCSYNC to free this frame up and continue." + + The only odd thing about this whole procedure is + that MCAPTURE flags the buffer as "in use", and + SYNC immediately unmarks it, while it isn't + after SYNC that you know that the buffer actually + got filled! So you better not start a CAPTURE in + the same frame immediately (use double buffering). + This is not a problem for this cam, since it has + extra intermediate buffers, but a hardware + grabber card will then overwrite the buffer + you're working on. + */ + int *mbuf = arg; int ret; - Trace(TRACE_OPEN, "VIDIOCMCAPTURE: changing size to please xawtv :-(.\n"); - ret = pwc_try_video_mode(pdev, vm->width, vm->height, pdev->vframes, pdev->vcompression, pdev->vsnapshot); - if (ret) - return ret; - } /* ... size mismatch */ + Trace(TRACE_READ, "VIDIOCSYNC called (%d).\n", *mbuf); - /* FIXME: should we lock here? */ - if (pdev->image_used[vm->frame]) - return -EBUSY; /* buffer wasn't available. Bummer */ - pdev->image_used[vm->frame] = 1; - - /* Okay, we're done here. In the SYNC call we wait until a - frame comes available, then expand image into the given - buffer. - In contrast to the CPiA cam the Philips cams deliver a - constant stream, almost like a grabber card. Also, - we have separate buffers for the rawdata and the image, - meaning we can nearly always expand into the requested buffer. - */ - Trace(TRACE_READ, "VIDIOCMCAPTURE done.\n"); - break; - } - - case VIDIOCSYNC: - { - /* The doc says: "Whenever a buffer is used it should - call VIDIOCSYNC to free this frame up and continue." - - The only odd thing about this whole procedure is - that MCAPTURE flags the buffer as "in use", and - SYNC immediately unmarks it, while it isn't - after SYNC that you know that the buffer actually - got filled! So you better not start a CAPTURE in - the same frame immediately (use double buffering). - This is not a problem for this cam, since it has - extra intermediate buffers, but a hardware - grabber card will then overwrite the buffer - you're working on. - */ - int *mbuf = arg; - int ret; + /* bounds check */ + if (*mbuf < 0 || *mbuf >= default_mbufs) + return -EINVAL; + /* check if this buffer was requested anyway */ + if (pdev->image_used[*mbuf] == 0) + return -EINVAL; - Trace(TRACE_READ, "VIDIOCSYNC called (%d).\n", *mbuf); + /* Add ourselves to the frame wait-queue. - /* bounds check */ - if (*mbuf < 0 || *mbuf >= default_mbufs) - return -EINVAL; - /* check if this buffer was requested anyway */ - if (pdev->image_used[*mbuf] == 0) - return -EINVAL; +FIXME: needs auditing for safety. +QUESTION: In what respect? I think that using the +frameq is safe now. +*/ + add_wait_queue(&pdev->frameq, &wait); + while (pdev->full_frames == NULL) { + if (pdev->error_status) { + remove_wait_queue(&pdev->frameq, &wait); + set_current_state(TASK_RUNNING); + return -pdev->error_status; + } - /* Add ourselves to the frame wait-queue. - - FIXME: needs auditing for safety. - QUESTION: In what respect? I think that using the - frameq is safe now. - */ - add_wait_queue(&pdev->frameq, &wait); - while (pdev->full_frames == NULL) { - if (pdev->error_status) { - remove_wait_queue(&pdev->frameq, &wait); - set_current_state(TASK_RUNNING); - return -pdev->error_status; + if (signal_pending(current)) { + remove_wait_queue(&pdev->frameq, &wait); + set_current_state(TASK_RUNNING); + return -ERESTARTSYS; + } + schedule(); + set_current_state(TASK_INTERRUPTIBLE); } - - if (signal_pending(current)) { - remove_wait_queue(&pdev->frameq, &wait); - set_current_state(TASK_RUNNING); - return -ERESTARTSYS; - } - schedule(); - set_current_state(TASK_INTERRUPTIBLE); - } - remove_wait_queue(&pdev->frameq, &wait); - set_current_state(TASK_RUNNING); - - /* The frame is ready. Expand in the image buffer - requested by the user. I don't care if you - mmap() 5 buffers and request data in this order: - buffer 4 2 3 0 1 2 3 0 4 3 1 . . . - Grabber hardware may not be so forgiving. - */ - Trace(TRACE_READ, "VIDIOCSYNC: frame ready.\n"); - pdev->fill_image = *mbuf; /* tell in which buffer we want the image to be expanded */ - /* Decompress, etc */ - ret = pwc_handle_frame(pdev); - pdev->image_used[*mbuf] = 0; - if (ret) - return -EFAULT; - break; - } - + remove_wait_queue(&pdev->frameq, &wait); + set_current_state(TASK_RUNNING); + + /* The frame is ready. Expand in the image buffer + requested by the user. I don't care if you + mmap() 5 buffers and request data in this order: + buffer 4 2 3 0 1 2 3 0 4 3 1 . . . + Grabber hardware may not be so forgiving. + */ + Trace(TRACE_READ, "VIDIOCSYNC: frame ready.\n"); + pdev->fill_image = *mbuf; /* tell in which buffer we want the image to be expanded */ + /* Decompress, etc */ + ret = pwc_handle_frame(pdev); + pdev->image_used[*mbuf] = 0; + if (ret) + return -EFAULT; + break; + } + case VIDIOCGAUDIO: case VIDIOCSAUDIO: return -EINVAL; case VIDIOCGUNIT: - { - struct video_unit *vu = arg; - - vu->video = pdev->vdev->minor & 0x3F; - vu->audio = VIDEO_NO_UNIT; - vu->vbi = VIDEO_NO_UNIT; - vu->radio = VIDEO_NO_UNIT; - vu->teletext = VIDEO_NO_UNIT; - break; - } + { + struct video_unit *vu = arg; + + vu->video = pdev->vdev->minor & 0x3F; + vu->audio = VIDEO_NO_UNIT; + vu->vbi = VIDEO_NO_UNIT; + vu->radio = VIDEO_NO_UNIT; + vu->teletext = VIDEO_NO_UNIT; + break; + } default: return pwc_ioctl(pdev, cmd, arg); } /* ..switch */ return 0; -} +} static int pwc_video_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) + unsigned int cmd, unsigned long arg) { return video_usercopy(inode, file, cmd, arg, pwc_video_do_ioctl); } @@ -1641,8 +1413,8 @@ unsigned long start = vma->vm_start; unsigned long size = vma->vm_end-vma->vm_start; unsigned long page, pos; - - Trace(TRACE_MEMORY, "mmap(0x%p, 0x%lx, %lu) called.\n", vdev, start, size); + + Trace(TRACE_MEMORY, "mmap(%p, %lx, %lu) called.\n", vdev, start, size); pdev = vdev->priv; pos = (unsigned long)pdev->image_data; @@ -1661,6 +1433,7 @@ return 0; } +#endif /* BSD patch */ /***************************************************************************/ /* USB functions */ @@ -1669,388 +1442,306 @@ * is loaded. */ -static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id) +struct pwc_device * usb_pwc_probe(struct usb_device *udev, unsigned int ifnum) { - struct usb_device *udev = interface_to_usbdev(intf); struct pwc_device *pdev = NULL; int vendor_id, product_id, type_id; - int i, hint; int features = 0; int video_nr = -1; /* default: use next available device */ - char serial_number[30], *name; + char *name; + usb_device_descriptor_t ddesc; /* Check if we can handle this device */ Trace(TRACE_PROBE, "probe() called [%04X %04X], if %d\n", - udev->descriptor.idVendor, udev->descriptor.idProduct, - intf->altsetting->desc.bInterfaceNumber); + udev->descriptor.idVendor, udev->descriptor.idProduct, ifnum); + + if (ioctl(udev->fd, USB_GET_DEVICE_DESC, &ddesc) < 0) { + perror("USB_GET_DEVICE_DESC"); + return NULL; + } + udev->descriptor.bNumConfigurations = ddesc.bNumConfigurations; + udev->descriptor.idVendor = UGETW(ddesc.idVendor); + udev->descriptor.idProduct = UGETW(ddesc.idProduct); + udev->descriptor.bcdDevice = UGETW(ddesc.bcdDevice); + video_nr = -1; /* the interfaces are probed one by one. We are only interested in the video interface (0) now. Interface 1 is the Audio Control, and interface 2 Audio itself. - */ - if (intf->altsetting->desc.bInterfaceNumber > 0) - return -ENODEV; + */ + if (ifnum > 0) + return NULL; vendor_id = udev->descriptor.idVendor; product_id = udev->descriptor.idProduct; if (vendor_id == 0x0471) { switch (product_id) { - case 0x0302: - Info("Philips PCA645VC USB webcam detected.\n"); - name = "Philips 645 webcam"; - type_id = 645; - break; - case 0x0303: - Info("Philips PCA646VC USB webcam detected.\n"); - name = "Philips 646 webcam"; - type_id = 646; - break; - case 0x0304: - Info("Askey VC010 type 2 USB webcam detected.\n"); - name = "Askey VC010 webcam"; - type_id = 646; - break; - case 0x0307: - Info("Philips PCVC675K (Vesta) USB webcam detected.\n"); - name = "Philips 675 webcam"; - type_id = 675; - break; - case 0x0308: - Info("Philips PCVC680K (Vesta Pro) USB webcam detected.\n"); - name = "Philips 680 webcam"; - type_id = 680; - break; - case 0x030C: - Info("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n"); - name = "Philips 690 webcam"; - type_id = 690; - break; - case 0x0310: - Info("Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II) USB webcam detected.\n"); - name = "Philips 730 webcam"; - type_id = 730; - break; - case 0x0311: - Info("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n"); - name = "Philips 740 webcam"; - type_id = 740; - break; - case 0x0312: - Info("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n"); - name = "Philips 750 webcam"; - type_id = 750; - break; - case 0x0313: - Info("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n"); - name = "Philips 720K/40 webcam"; - type_id = 720; - break; - default: - return -ENODEV; - break; + case 0x0302: + Info("Philips PCA645VC USB webcam detected.\n"); + name = "Philips 645 webcam"; + type_id = 645; + break; + case 0x0303: + Info("Philips PCA646VC USB webcam detected.\n"); + name = "Philips 646 webcam"; + type_id = 646; + break; + case 0x0304: + Info("Askey VC010 type 2 USB webcam detected.\n"); + name = "Askey VC010 webcam"; + type_id = 646; + break; + case 0x0307: + Info("Philips PCVC675K (Vesta) USB webcam detected.\n"); + name = "Philips 675 webcam"; + type_id = 675; + break; + case 0x0308: + Info("Philips PCVC680K (Vesta Pro) USB webcam detected.\n"); + name = "Philips 680 webcam"; + type_id = 680; + break; + case 0x030C: + Info("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n"); + name = "Philips 690 webcam"; + type_id = 690; + break; + case 0x0310: + Info("Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II) USB webcam detected.\n"); + name = "Philips 730 webcam"; + type_id = 730; + break; + case 0x0311: + Info("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n"); + name = "Philips 740 webcam"; + type_id = 740; + break; + case 0x0312: + Info("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n"); + name = "Philips 750 webcam"; + type_id = 750; + break; + case 0x0313: + Info("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n"); + name = "Philips 720K/40 webcam"; + type_id = 720; + break; + default: + return NULL; + break; } } else if (vendor_id == 0x069A) { switch(product_id) { - case 0x0001: - Info("Askey VC010 type 1 USB webcam detected.\n"); - name = "Askey VC010 webcam"; - type_id = 645; - break; - default: - return -ENODEV; - break; + case 0x0001: + Info("Askey VC010 type 1 USB webcam detected.\n"); + name = "Askey VC010 webcam"; + type_id = 645; + break; + default: + return NULL; + break; } } else if (vendor_id == 0x046d) { switch(product_id) { - case 0x08b0: - Info("Logitech QuickCam Pro 3000 USB webcam detected.\n"); - name = "Logitech QuickCam Pro 3000"; - type_id = 740; /* CCD sensor */ - break; - case 0x08b1: - Info("Logitech QuickCam Notebook Pro USB webcam detected.\n"); - name = "Logitech QuickCam Notebook Pro"; - type_id = 740; /* CCD sensor */ - break; - case 0x08b2: - Info("Logitech QuickCam 4000 Pro USB webcam detected.\n"); - name = "Logitech QuickCam Pro 4000"; - type_id = 740; /* CCD sensor */ - break; - case 0x08b3: - Info("Logitech QuickCam Zoom USB webcam detected.\n"); - name = "Logitech QuickCam Zoom"; - type_id = 740; /* CCD sensor */ - break; - case 0x08B4: - Info("Logitech QuickCam Zoom (new model) USB webcam detected.\n"); - name = "Logitech QuickCam Zoom"; - type_id = 740; /* CCD sensor */ - break; - case 0x08b5: - Info("Logitech QuickCam Orbit/Sphere USB webcam detected.\n"); - name = "Logitech QuickCam Orbit"; - type_id = 740; /* CCD sensor */ - features |= FEATURE_MOTOR_PANTILT; - break; - case 0x08b6: - case 0x08b7: - case 0x08b8: - Info("Logitech QuickCam detected (reserved ID).\n"); - name = "Logitech QuickCam (res.)"; - type_id = 730; /* Assuming CMOS */ - break; - default: - return -ENODEV; - break; - } - } + case 0x08b0: + Info("Logitech QuickCam Pro 3000 USB webcam detected.\n"); + name = "Logitech QuickCam Pro 3000"; + type_id = 740; /* CCD sensor */ + break; + case 0x08b1: + Info("Logitech QuickCam Notebook Pro USB webcam detected.\n"); + name = "Logitech QuickCam Notebook Pro"; + type_id = 740; /* CCD sensor */ + break; + case 0x08b2: + Info("Logitech QuickCam 4000 Pro USB webcam detected.\n"); + name = "Logitech QuickCam Pro 4000"; + type_id = 740; /* CCD sensor */ + break; + case 0x08b3: + Info("Logitech QuickCam Zoom USB webcam detected.\n"); + name = "Logitech QuickCam Zoom"; + type_id = 740; /* CCD sensor */ + break; + case 0x08B4: + Info("Logitech QuickCam Zoom (new model) USB webcam detected.\n"); + name = "Logitech QuickCam Zoom"; + type_id = 740; /* CCD sensor */ + break; + case 0x08b5: + Info("Logitech QuickCam Orbit/Sphere USB webcam detected.\n"); + name = "Logitech QuickCam Orbit"; + type_id = 740; /* CCD sensor */ + features |= FEATURE_MOTOR_PANTILT; + break; + case 0x08b6: + case 0x08b7: + case 0x08b8: + Info("Logitech QuickCam detected (reserved ID).\n"); + name = "Logitech QuickCam (res.)"; + type_id = 730; /* Assuming CMOS */ + break; + default: + return NULL; + break; + } + } else if (vendor_id == 0x055d) { /* I don't know the difference between the C10 and the C30; I suppose the difference is the sensor, but both cameras work equally well with a type_id of 675 - */ + */ switch(product_id) { - case 0x9000: - Info("Samsung MPC-C10 USB webcam detected.\n"); - name = "Samsung MPC-C10"; - type_id = 675; - break; - case 0x9001: - Info("Samsung MPC-C30 USB webcam detected.\n"); - name = "Samsung MPC-C30"; - type_id = 675; - break; - default: - return -ENODEV; - break; + case 0x9000: + Info("Samsung MPC-C10 USB webcam detected.\n"); + name = "Samsung MPC-C10"; + type_id = 675; + break; + case 0x9001: + Info("Samsung MPC-C30 USB webcam detected.\n"); + name = "Samsung MPC-C30"; + type_id = 675; + break; + default: + return NULL; + break; } } else if (vendor_id == 0x041e) { switch(product_id) { - case 0x400c: - Info("Creative Labs Webcam 5 detected.\n"); - name = "Creative Labs Webcam 5"; - type_id = 730; - break; - case 0x4011: - Info("Creative Labs Webcam Pro Ex detected.\n"); - name = "Creative Labs Webcam Pro Ex"; - type_id = 740; - break; - default: - return -ENODEV; - break; + case 0x400c: + Info("Creative Labs Webcam 5 detected.\n"); + name = "Creative Labs Webcam 5"; + type_id = 730; + break; + case 0x4011: + Info("Creative Labs Webcam Pro Ex detected.\n"); + name = "Creative Labs Webcam Pro Ex"; + type_id = 740; + break; + default: + return NULL; + break; } } else if (vendor_id == 0x04cc) { switch(product_id) { - case 0x8116: - Info("Sotec Afina Eye USB webcam detected.\n"); - name = "Sotec Afina Eye"; - type_id = 730; - break; - default: - return -ENODEV; - break; + case 0x8116: + Info("Sotec Afina Eye USB webcam detected.\n"); + name = "Sotec Afina Eye"; + type_id = 730; + break; + default: + return NULL; + break; } } else if (vendor_id == 0x06be) { switch(product_id) { - case 0x8116: - /* This is essentially the same cam as the Sotec Afina Eye */ - Info("AME Co. Afina Eye USB webcam detected.\n"); - name = "AME Co. Afina Eye"; - type_id = 750; - break; - default: - return -ENODEV; - break; + case 0x8116: + /* This is essentially the same cam as the Sotec Afina Eye */ + Info("AME Co. Afina Eye USB webcam detected.\n"); + name = "AME Co. Afina Eye"; + type_id = 750; + break; + default: + return NULL; + break; } - + } else if (vendor_id == 0x0d81) { switch(product_id) { - case 0x1900: - Info("Visionite VCS-UC300 USB webcam detected.\n"); - name = "Visionite VCS-UC300"; - type_id = 740; /* CCD sensor */ - break; - case 0x1910: - Info("Visionite VCS-UM100 USB webcam detected.\n"); - name = "Visionite VCS-UM100"; - type_id = 730; /* CMOS sensor */ - break; - default: - return -ENODEV; - break; + case 0x1900: + Info("Visionite VCS-UC300 USB webcam detected.\n"); + name = "Visionite VCS-UC300"; + type_id = 740; /* CCD sensor */ + break; + case 0x1910: + Info("Visionite VCS-UM100 USB webcam detected.\n"); + name = "Visionite VCS-UM100"; + type_id = 730; /* CMOS sensor */ + break; + default: + return NULL; + break; } } else - return -ENODEV; /* Not any of the know types; but the list keeps growing. */ + return NULL; /* Not any of the know types; but the list keeps growing. */ - memset(serial_number, 0, 30); - usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29); - Trace(TRACE_PROBE, "Device serial number is %s\n", serial_number); if (udev->descriptor.bNumConfigurations > 1) Info("Warning: more than 1 configuration available.\n"); - /* Allocate structure, initialize pointers, mutexes, etc. and link it to the usb_device */ - pdev = kmalloc(sizeof(struct pwc_device), GFP_KERNEL); + pdev = malloc(sizeof(struct pwc_device)); if (pdev == NULL) { Err("Oops, could not allocate memory for pwc_device.\n"); - return -ENOMEM; + return NULL; } memset(pdev, 0, sizeof(struct pwc_device)); pdev->type = type_id; pdev->vsize = default_size; pdev->vframes = default_fps; - strcpy(pdev->serial, serial_number); + /* strcpy(pdev->serial, serial_number); */ pdev->features = features; if (vendor_id == 0x046D && product_id == 0x08B5) { /* Logitech QuickCam Orbit - The ranges have been determined experimentally; they may differ from cam to cam. - Also, the exact ranges left-right and up-down are different for my cam - */ + The ranges have been determined experimentally; they may differ from cam to cam. + Also, the exact ranges left-right and up-down are different for my cam + */ pdev->angle_range.pan_min = -7000; pdev->angle_range.pan_max = 7000; pdev->angle_range.tilt_min = -3000; pdev->angle_range.tilt_max = 2500; } - init_MUTEX(&pdev->modlock); - pdev->ptrlock = SPIN_LOCK_UNLOCKED; - pdev->udev = udev; - init_waitqueue_head(&pdev->frameq); pdev->vcompression = pwc_preferred_compression; - /* Allocate video_device structure */ - pdev->vdev = video_device_alloc(); - if (pdev->vdev == 0) - { - Err("Err, cannot allocate video_device struture. Failing probe."); - kfree(pdev); - return -ENOMEM; - } - memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template)); - pdev->vdev->dev = &(udev->dev); - strcpy(pdev->vdev->name, name); - pdev->vdev->owner = THIS_MODULE; - video_set_drvdata(pdev->vdev, pdev); + strcpy(pdev->vdev_name, name); pdev->release = udev->descriptor.bcdDevice; Trace(TRACE_PROBE, "Release: %04x\n", pdev->release); - /* Now search device_hint[] table for a match, so we can hint a node number. */ - for (hint = 0; hint < MAX_DEV_HINTS; hint++) { - if (((device_hint[hint].type == -1) || (device_hint[hint].type == pdev->type)) && - (device_hint[hint].pdev == NULL)) { - /* so far, so good... try serial number */ - if ((device_hint[hint].serial_number[0] == '*') || !strcmp(device_hint[hint].serial_number, serial_number)) { - /* match! */ - video_nr = device_hint[hint].device_node; - Trace(TRACE_PROBE, "Found hint, will try to register as /dev/video%d\n", video_nr); - break; - } - } - } - - pdev->vdev->release = video_device_release; - i = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr); - if (i < 0) { - Err("Failed to register as video device (%d).\n", i); - video_device_release(pdev->vdev); /* Drip... drip... drip... */ - kfree(pdev); /* Oops, no memory leaks please */ - return -EIO; - } - else { - Info("Registered as /dev/video%d.\n", pdev->vdev->minor & 0x3F); - } - - /* occupy slot */ - if (hint < MAX_DEV_HINTS) - device_hint[hint].pdev = pdev; - - Trace(TRACE_PROBE, "probe() function returning struct at 0x%p.\n", pdev); - usb_set_intfdata (intf, pdev); - pwc_create_sysfs_files(pdev->vdev); - return 0; + Trace(TRACE_PROBE, "probe() function returning struct at %p.\n", pdev); + return pdev; } /* The user janked out the cable... */ -static void usb_pwc_disconnect(struct usb_interface *intf) +void usb_pwc_disconnect(struct usb_device *udev, void *ptr) { struct pwc_device *pdev; - int hint; - lock_kernel(); - pdev = usb_get_intfdata (intf); - usb_set_intfdata (intf, NULL); + pdev = (struct pwc_device *)ptr; if (pdev == NULL) { Err("pwc_disconnect() Called without private pointer.\n"); - goto disconnect_out; + return; } if (pdev->udev == NULL) { Err("pwc_disconnect() already called for %p\n", pdev); - goto disconnect_out; + return; } - if (pdev->udev != interface_to_usbdev(intf)) { + if (pdev->udev != udev) { Err("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n"); - goto disconnect_out; + return; } #ifdef PWC_MAGIC if (pdev->magic != PWC_MAGIC) { Err("pwc_disconnect() Magic number failed. Consult your scrolls and try again.\n"); - goto disconnect_out; + return; } #endif - - /* We got unplugged; this is signalled by an EPIPE error code */ - if (pdev->vopen) { - Info("Disconnected while webcam is in use!\n"); - pdev->error_status = EPIPE; - } - /* Alert waiting processes */ - wake_up_interruptible(&pdev->frameq); - /* Wait until device is closed */ - while (pdev->vopen) - schedule(); /* Device is now closed, so we can safely unregister it */ Trace(TRACE_PROBE, "Unregistering video device in disconnect().\n"); - pwc_remove_sysfs_files(pdev->vdev); - video_unregister_device(pdev->vdev); /* Free memory (don't set pdev to 0 just yet) */ - kfree(pdev); - -disconnect_out: - /* search device_hint[] table if we occupy a slot, by any chance */ - for (hint = 0; hint < MAX_DEV_HINTS; hint++) - if (device_hint[hint].pdev == pdev) - device_hint[hint].pdev = NULL; - - unlock_kernel(); -} - - -/* *grunt* We have to do atoi ourselves :-( */ -static int pwc_atoi(const char *s) -{ - int k = 0; - - k = 0; - while (*s != '\0' && *s >= '0' && *s <= '9') { - k = 10 * k + (*s - '0'); - s++; - } - return k; + free(pdev); } @@ -2065,7 +1756,6 @@ static int trace = -1; static int compression = -1; static int leds[2] = { -1, -1 }; -static char *dev_hint[MAX_DEV_HINTS] = { }; MODULE_PARM(size, "s"); MODULE_PARM_DESC(size, "Initial image size. One of sqcif, qsif, qcif, sif, cif, vga"); @@ -2083,23 +1773,17 @@ MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)"); MODULE_PARM(leds, "2i"); MODULE_PARM_DESC(leds, "LED on,off time in milliseconds"); -MODULE_PARM(dev_hint, "0-20s"); -MODULE_PARM_DESC(dev_hint, "Device node hints"); MODULE_DESCRIPTION("Philips & OEM USB webcam driver"); MODULE_AUTHOR("Luc Saillard "); MODULE_LICENSE("GPL"); -MODULE_VERSION( PWC_VERSION ); -static int __init usb_pwc_init(void) +int usb_pwc_init(void) { - int i, sz; + int sz; char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" }; - Info("Philips webcam module version " PWC_VERSION " loaded.\n"); - Info("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n"); - Info("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n"); - Info("the Creative WebCam 5 & Pro Ex, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n"); + Info("Using PWC version " PWC_VERSION "\n"); if (fps) { if (fps < 4 || fps > 30) { @@ -2141,7 +1825,7 @@ Info("Number of frame buffers set to %d.\n", default_fbufs); } if (trace >= 0) { - Info("Trace options: 0x%04x\n", trace); + Info("Trace options: %04x\n", trace); pwc_trace = trace; } if (compression >= 0) { @@ -2158,14 +1842,14 @@ led_on = leds[0]; if (leds[1] >= 0) led_off = leds[1]; - +#if 0 /* BSD patch */ /* Big device node whoopla. Basicly, it allows you to assign a device node (/dev/videoX) to a camera, based on its type & serial number. The format is [type[.serialnumber]:]node. Any camera that isn't matched by these rules gets the next available free device node. - */ + */ for (i = 0; i < MAX_DEV_HINTS; i++) { char *s, *colon, *dot; @@ -2206,7 +1890,7 @@ if (*dot != '\0') { /* There's a serial number as well */ int k; - + dot++; k = 0; while (*dot != ':' && k < 29) { @@ -2227,10 +1911,11 @@ device_hint[i].type = 0; /* not filled */ } /* ..for MAX_DEV_HINTS */ - Trace(TRACE_PROBE, "Registering driver at address 0x%p.\n", &pwc_driver); - return usb_register(&pwc_driver); + Trace(TRACE_PROBE, "Registering driver at address %p.\n", &pwc_driver); +#endif /* BSD patch */ + return 0; } - +#if 0 /* BSD patch */ static void __exit usb_pwc_exit(void) { Trace(TRACE_MODULE, "Deregistering driver.\n"); @@ -2240,4 +1925,4 @@ module_init(usb_pwc_init); module_exit(usb_pwc_exit); - +#endif /* BSD patch */ diff -Nru pwc-10.0.5.orig/pwc-ioctl.h pwc-10.0.5/pwc-ioctl.h --- pwc-10.0.5.orig/pwc-ioctl.h 2004-09-14 11:56:04.000000000 +0200 +++ pwc-10.0.5/pwc-ioctl.h 2004-11-23 16:52:51.000000000 +0100 @@ -59,7 +59,7 @@ #define PSZ_SIF 0x03 #define PSZ_CIF 0x04 #define PSZ_VGA 0x05 -#define PSZ_MAX 6 +#define PSZ_MAX 0x06 /* The frame rate is encoded in the video_window.flags parameter using diff -Nru pwc-10.0.5.orig/pwc-misc.c pwc-10.0.5/pwc-misc.c --- pwc-10.0.5.orig/pwc-misc.c 2004-10-21 23:33:26.000000000 +0200 +++ pwc-10.0.5/pwc-misc.c 2004-11-21 19:00:29.000000000 +0100 @@ -24,8 +24,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include - #include "pwc.h" struct pwc_coord pwc_image_sizes[PSZ_MAX] = @@ -48,6 +46,7 @@ you don't have the decompressor loaded or use RAW mode, the maximum viewable size is smaller. */ +#if 0 /* vinvin BSD patch */ if (pdev->vpalette == VIDEO_PALETTE_RAW) { if (width > pdev->abs_max.x || height > pdev->abs_max.y) @@ -64,7 +63,7 @@ return -1; } } - +#endif /* vinvin BSD patch */ /* Find the largest size supported by the camera that fits into the requested size. */ @@ -129,7 +128,6 @@ pdev->frame_trailer_size = TOUCAM_TRAILER_SIZE; break; } - pdev->vpalette = VIDEO_PALETTE_YUV420P; /* default */ pdev->view_min.size = pdev->view_min.x * pdev->view_min.y; pdev->view_max.size = pdev->view_max.x * pdev->view_max.y; /* length of image, in YUV format; always allocate enough memory. */ diff -Nru pwc-10.0.5.orig/pwc-uncompress.c pwc-10.0.5/pwc-uncompress.c --- pwc-10.0.5.orig/pwc-uncompress.c 2004-09-14 11:56:04.000000000 +0200 +++ pwc-10.0.5/pwc-uncompress.c 2004-12-02 20:05:05.000000000 +0100 @@ -3,143 +3,116 @@ (C) 1999-2003 Nemosoft Unv. (C) 2004 Luc Saillard (luc@saillard.org) - NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx - driver and thus may have bugs that are not present in the original version. - Please send bug reports and support requests to . - The decompression routines have been implemented by reverse-engineering the - Nemosoft binary pwcx module. Caveat emptor. - - 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. - - 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. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx +driver and thus may have bugs that are not present in the original version. +Please send bug reports and support requests to . +The decompression routines have been implemented by reverse-engineering the +Nemosoft binary pwcx module. Caveat emptor. + +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. + +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. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include -#include - #include "pwc.h" #include "pwc-uncompress.h" #include "pwc-dec1.h" #include "pwc-dec23.h" +#include "linux_usbif.h" int pwc_decompress(struct pwc_device *pdev) { - struct pwc_frame_buf *fbuf; int n, line, col, stride; - void *yuv, *image; - u16 *src; - u16 *dsty, *dstu, *dstv; + __u16 *src; + __u16 *dsty, *dstu, *dstv; if (pdev == NULL) return -EFAULT; -#if defined(__KERNEL__) && defined(PWC_MAGIC) - if (pdev->magic != PWC_MAGIC) { - Err("pwc_decompress(): magic failed.\n"); - return -EFAULT; - } -#endif - - fbuf = pdev->read_frame; - if (fbuf == NULL) - return -EFAULT; - image = pdev->image_ptr[pdev->fill_image]; - if (!image) - return -EFAULT; - - yuv = fbuf->data + pdev->frame_header_size; /* Skip header */ - - /* Raw format; that's easy... */ - if (pdev->vpalette == VIDEO_PALETTE_RAW) - { - memcpy(image, yuv, pdev->frame_size); - return 0; - } if (pdev->vbandlength == 0) { /* Uncompressed mode. We copy the data into the output buffer, using the viewport size (which may be larger than the image size). Unfortunately we have to do a bit of byte stuffing to get the desired output format/size. + */ + /* + * We do some byte shuffling here to go from the + * native format to YUV420P. */ - /* - * We do some byte shuffling here to go from the - * native format to YUV420P. - */ - src = (u16 *)yuv; - n = pdev->view.x * pdev->view.y; - - /* offset in Y plane */ - stride = pdev->view.x * pdev->offset.y + pdev->offset.x; - dsty = (u16 *)(image + stride); - - /* offsets in U/V planes */ - stride = pdev->view.x * pdev->offset.y / 4 + pdev->offset.x / 2; - dstu = (u16 *)(image + n + stride); - dstv = (u16 *)(image + n + n / 4 + stride); - - /* increment after each line */ - stride = (pdev->view.x - pdev->image.x) / 2; /* u16 is 2 bytes */ - - for (line = 0; line < pdev->image.y; line++) { - for (col = 0; col < pdev->image.x; col += 4) { - *dsty++ = *src++; - *dsty++ = *src++; - if (line & 1) - *dstv++ = *src++; - else - *dstu++ = *src++; - } - dsty += stride; + src = (__u16 *)grabbuf; + n = pdev->view.x * pdev->view.y; + + /* offset in Y plane */ + stride = pdev->view.x * pdev->offset.y + pdev->offset.x; + dsty = (__u16 *)(yuv + stride); + + /* offsets in U/V planes */ + stride = pdev->view.x * pdev->offset.y / 4 + pdev->offset.x / 2; + dstu = (__u16 *)(yuv + n + stride); + dstv = (__u16 *)(yuv + n + n / 4 + stride); + + /* increment after each line */ + stride = (pdev->view.x - pdev->image.x) / 2; /* u16 is 2 bytes */ + + for (line = 0; line < pdev->image.y; line++) { + for (col = 0; col < pdev->image.x; col += 4) { + *dsty++ = *src++; + *dsty++ = *src++; if (line & 1) - dstv += (stride >> 1); + *dstv++ = *src++; else - dstu += (stride >> 1); + *dstu++ = *src++; } + dsty += stride; + if (line & 1) + dstv += (stride >> 1); + else + dstu += (stride >> 1); + } } else { /* Compressed; the decompressor routines will write the data in planar format immediately. - */ + */ int flags; - - flags = PWCX_FLAG_PLANAR; - if (pdev->vsize == PSZ_VGA && pdev->vframes == 5 && pdev->vsnapshot) - { - printk(KERN_ERR "pwc: Mode Bayer is not supported for now\n"); - flags |= PWCX_FLAG_BAYER; - return -ENXIO; /* No such device or address: missing decompressor */ - } + + flags = PWCX_FLAG_PLANAR; + if (pdev->vsize == PSZ_VGA && pdev->vframes == 5 && pdev->vsnapshot) + { + Debug(KERN_ERR "pwc: Mode Bayer is not supported for now\n"); + flags |= PWCX_FLAG_BAYER; + return -ENXIO; /* No such device or address: missing decompressor */ + } switch (pdev->type) - { - case 675: - case 680: - case 690: - case 720: - case 730: - case 740: - case 750: - pwc_dec23_decompress(&pdev->image, &pdev->view, &pdev->offset, - yuv, image, - flags, - pdev->decompress_data, pdev->vbandlength); - break; - case 645: - case 646: - /* TODO & FIXME */ - return -ENXIO; /* No such device or address: missing decompressor */ - break; - } + { + case 675: + case 680: + case 690: + case 720: + case 730: + case 740: + case 750: + pwc_dec23_decompress(&pdev->image, &pdev->view, &pdev->offset, + grabbuf, yuv, flags, + pdev->decompress_data, pdev->vbandlength); + break; + case 645: + case 646: + /* TODO & FIXME */ + return -ENXIO; /* No such device or address: missing decompressor */ + break; + } } return 0; } diff -Nru pwc-10.0.5.orig/pwc-uncompress.h pwc-10.0.5/pwc-uncompress.h --- pwc-10.0.5.orig/pwc-uncompress.h 2004-09-14 11:56:04.000000000 +0200 +++ pwc-10.0.5/pwc-uncompress.h 2004-12-02 20:09:53.000000000 +0100 @@ -30,10 +30,12 @@ #ifndef PWC_UNCOMPRESS_H #define PWC_UNCOMPRESS_H -#include - #include "pwc-ioctl.h" +/* phpsview | phpsshot .h */ +extern unsigned char *grabbuf; +extern unsigned char *yuv; + /* from pwc-dec.h */ #define PWCX_FLAG_PLANAR 0x0001 /* */ diff -Nru pwc-10.0.5.orig/pwc.h pwc-10.0.5/pwc.h --- pwc-10.0.5.orig/pwc.h 2004-10-21 23:30:00.000000000 +0200 +++ pwc-10.0.5/pwc.h 2004-11-23 16:59:01.000000000 +0100 @@ -1,41 +1,31 @@ /* (C) 1999-2003 Nemosoft Unv. (C) 2004 Luc Saillard (luc@saillard.org) - NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx - driver and thus may have bugs that are not present in the original version. - Please send bug reports and support requests to . - The decompression routines have been implemented by reverse-engineering the - Nemosoft binary pwcx module. Caveat emptor. - - 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. - - 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. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx +driver and thus may have bugs that are not present in the original version. +Please send bug reports and support requests to . +The decompression routines have been implemented by reverse-engineering the +Nemosoft binary pwcx module. Caveat emptor. + +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. + +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. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef PWC_H #define PWC_H -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "linux_usbif.h" #include "pwc-uncompress.h" #include "pwc-ioctl.h" @@ -46,7 +36,7 @@ #undef PWC_MAGIC /* Turn some debugging options on/off */ -#define PWC_DEBUG 0 +#define PWC_DEBUG 1 /* Trace certain actions in the driver */ #define TRACE_MODULE 0x0001 @@ -59,10 +49,10 @@ #define TRACE_PWCX 0x0080 #define TRACE_SEQUENCE 0x1000 -#define Trace(R, A...) if (pwc_trace & R) printk(KERN_DEBUG PWC_NAME " " A) -#define Debug(A...) printk(KERN_DEBUG PWC_NAME " " A) -#define Info(A...) printk(KERN_INFO PWC_NAME " " A) -#define Err(A...) printk(KERN_ERR PWC_NAME " " A) +#define Trace(R, A...) if (pwc_trace & R) fprintf(stderr,KERN_DEBUG PWC_NAME " " A) +#define Debug(A...) fprintf(stderr,KERN_DEBUG PWC_NAME " " A) +#define Info(A...) fprintf(stderr,KERN_INFO PWC_NAME " " A) +#define Err(A...) fprintf(stderr,KERN_ERR PWC_NAME " " A) /* Defines for ToUCam cameras */ @@ -109,115 +99,111 @@ /* intermediate buffers with raw data from the USB cam */ struct pwc_frame_buf { - void *data; - volatile int filled; /* number of bytes filled */ - struct pwc_frame_buf *next; /* list */ + void *data; + volatile int filled; /* number of bytes filled */ + struct pwc_frame_buf *next; /* list */ #if PWC_DEBUG - int sequence; /* Sequence number */ + int sequence; /* Sequence number */ #endif }; struct pwc_device { - struct video_device *vdev; #ifdef PWC_MAGIC - int magic; + int magic; #endif - /* Pointer to our usb_device */ - struct usb_device *udev; - - int type; /* type of cam (645, 646, 675, 680, 690, 720, 730, 740, 750) */ - int release; /* release number */ - int features; /* feature bits */ - char serial[30]; /* serial number (string) */ - int error_status; /* set when something goes wrong with the cam (unplugged, USB errors) */ - int usb_init; /* set when the cam has been initialized over USB */ - - /*** Video data ***/ - int vopen; /* flag */ - int vendpoint; /* video isoc endpoint */ - int vcinterface; /* video control interface */ - int valternate; /* alternate interface needed */ - int vframes, vsize; /* frames-per-second & size (see PSZ_*) */ - int vpalette; /* palette: 420P, RAW or RGBBAYER */ - int vframe_count; /* received frames */ - int vframes_dumped; /* counter for dumped frames */ - int vframes_error; /* frames received in error */ - int vmax_packet_size; /* USB maxpacket size */ - int vlast_packet_size; /* for frame synchronisation */ - int visoc_errors; /* number of contiguous ISOC errors */ - int vcompression; /* desired compression factor */ - int vbandlength; /* compressed band length; 0 is uncompressed */ - char vsnapshot; /* snapshot mode */ - char vsync; /* used by isoc handler */ - char vmirror; /* for ToUCaM series */ - - int cmd_len; - unsigned char cmd_buf[13]; - - /* The image acquisition requires 3 to 4 steps: - 1. data is gathered in short packets from the USB controller - 2. data is synchronized and packed into a frame buffer - 3a. in case data is compressed, decompress it directly into image buffer - 3b. in case data is uncompressed, copy into image buffer with viewport - 4. data is transferred to the user process - - Note that MAX_ISO_BUFS != MAX_FRAMES != MAX_IMAGES.... - We have in effect a back-to-back-double-buffer system. - */ - /* 1: isoc */ - struct pwc_iso_buf sbuf[MAX_ISO_BUFS]; - char iso_init; - - /* 2: frame */ - struct pwc_frame_buf *fbuf; /* all frames */ - struct pwc_frame_buf *empty_frames, *empty_frames_tail; /* all empty frames */ - struct pwc_frame_buf *full_frames, *full_frames_tail; /* all filled frames */ - struct pwc_frame_buf *fill_frame; /* frame currently being filled */ - struct pwc_frame_buf *read_frame; /* frame currently read by user process */ - int frame_header_size, frame_trailer_size; - int frame_size; - int frame_total_size; /* including header & trailer */ - int drop_frames; + /* Pointer to our usb_device */ + struct usb_device *udev; + + int type; /* type of cam (645, 646, 675, 680, 690, 720, 730, 740, 750) */ + int release; /* release number */ + int features; /* feature bits */ + char serial[30]; /* serial number (string) */ + int error_status; /* set when something goes wrong with the cam (unplugged, USB errors) */ + int usb_init; /* set when the cam has been initialized over USB */ + + /*** Video data ***/ + int vopen; /* flag */ + int vendpoint; /* video isoc endpoint */ + int vcinterface; /* video control interface */ + int valternate; /* alternate interface needed */ + int vframes, vsize; /* frames-per-second & size (see PSZ_*) */ + int vpalette; /* palette: 420P, RAW or RGBBAYER */ + int vframe_count; /* received frames */ + int vframes_dumped; /* counter for dumped frames */ + int vframes_error; /* frames received in error */ + int vmax_packet_size; /* USB maxpacket size */ + int vlast_packet_size; /* for frame synchronisation */ + int visoc_errors; /* number of contiguous ISOC errors */ + int vcompression; /* desired compression factor */ + int vbandlength; /* compressed band length; 0 is uncompressed */ + char vsnapshot; /* snapshot mode */ + char vsync; /* used by isoc handler */ + char vmirror; /* for ToUCaM series */ + + int cmd_len; + unsigned char cmd_buf[13]; + + /* The image acquisition requires 3 to 4 steps: + 1. data is gathered in short packets from the USB controller + 2. data is synchronized and packed into a frame buffer + 3a. in case data is compressed, decompress it directly into image buffer + 3b. in case data is uncompressed, copy into image buffer with viewport + 4. data is transferred to the user process + + Note that MAX_ISO_BUFS != MAX_FRAMES != MAX_IMAGES.... + We have in effect a back-to-back-double-buffer system. + */ + /* 1: isoc */ + struct pwc_iso_buf sbuf[MAX_ISO_BUFS]; + char iso_init; + + /* 2: frame */ +#if 0 /* BSD patch */ + struct pwc_frame_buf *fbuf; /* all frames */ + struct pwc_frame_buf *empty_frames, *empty_frames_tail; /* all empty frames */ + struct pwc_frame_buf *full_frames, *full_frames_tail; /* all filled frames */ + struct pwc_frame_buf *fill_frame; /* frame currently being filled */ + struct pwc_frame_buf *read_frame; /* frame currently read by user process */ +#endif /* BSD patch */ + int frame_header_size, frame_trailer_size; + int frame_size; + int frame_total_size; /* including header & trailer */ + int drop_frames; #if PWC_DEBUG - int sequence; /* Debugging aid */ + int sequence; /* Debugging aid */ #endif - /* 3: decompression */ - struct pwc_decompressor *decompressor; /* function block with decompression routines */ - void *decompress_data; /* private data for decompression engine */ - - /* 4: image */ - /* We have an 'image' and a 'view', where 'image' is the fixed-size image - as delivered by the camera, and 'view' is the size requested by the - program. The camera image is centered in this viewport, laced with - a gray or black border. view_min <= image <= view <= view_max; - */ - int image_mask; /* bitmask of supported sizes */ - struct pwc_coord view_min, view_max; /* minimum and maximum viewable sizes */ - struct pwc_coord abs_max; /* maximum supported size with compression */ - struct pwc_coord image, view; /* image and viewport size */ - struct pwc_coord offset; /* offset within the viewport */ - - void *image_data; /* total buffer, which is subdivided into ... */ - void *image_ptr[MAX_IMAGES]; /* ...several images... */ - int fill_image; /* ...which are rotated. */ - int len_per_image; /* length per image */ - int image_read_pos; /* In case we read data in pieces, keep track of were we are in the imagebuffer */ - int image_used[MAX_IMAGES]; /* For MCAPTURE and SYNC */ - - struct semaphore modlock; /* to prevent races in video_open(), etc */ - spinlock_t ptrlock; /* for manipulating the buffer pointers */ - - /*** motorized pan/tilt feature */ - struct pwc_mpt_range angle_range; - int pan_angle; /* in degrees * 100 */ - int tilt_angle; /* absolute angle; 0,0 is home position */ + /* 3: decompression */ + struct pwc_decompressor *decompressor; /* function block with decompression routines */ + void *decompress_data; /* private data for decompression engine */ + + /* 4: image */ + /* We have an 'image' and a 'view', where 'image' is the fixed-size image + as delivered by the camera, and 'view' is the size requested by the + program. The camera image is centered in this viewport, laced with + a gray or black border. view_min <= image <= view <= view_max; + */ + int image_mask; /* bitmask of supported sizes */ + struct pwc_coord view_min, view_max; /* minimum and maximum viewable sizes */ + struct pwc_coord abs_max; /* maximum supported size with compression */ + struct pwc_coord image, view; /* image and viewport size */ + struct pwc_coord offset; /* offset within the viewport */ + + int fill_image; /* ...which are rotated. */ + int len_per_image; /* length per image */ + int image_read_pos; /* In case we read data in pieces, keep track of were we are in the imagebuffer */ + int image_used[MAX_IMAGES]; /* For MCAPTURE and SYNC */ + + /*** motorized pan/tilt feature */ + struct pwc_mpt_range angle_range; + int pan_angle; /* in degrees * 100 */ + int tilt_angle; /* absolute angle; 0,0 is home position */ - /*** Misc. data ***/ - wait_queue_head_t frameq; /* When waiting for a frame to finish... */ + /*** Misc. data ***/ + char vdev_name[32]; /* vdev.name by BSD patch */ #if PWC_INT_PIPE - void *usb_int_handler; /* for the interrupt endpoint */ + void *usb_int_handler; /* for the interrupt endpoint */ #endif }; @@ -226,51 +212,56 @@ extern "C" { #endif -/* Global variables */ -extern int pwc_trace; -extern int pwc_preferred_compression; - -/** functions in pwc-if.c */ -int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot); - -/** Functions in pwc-misc.c */ -/* sizes in pixels */ -extern struct pwc_coord pwc_image_sizes[PSZ_MAX]; - -int pwc_decode_size(struct pwc_device *pdev, int width, int height); -void pwc_construct(struct pwc_device *pdev); - -/** Functions in pwc-ctrl.c */ -/* Request a certain video mode. Returns < 0 if not possible */ -extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot); -/* Calculate the number of bytes per image (not frame) */ -extern void pwc_set_image_buffer_size(struct pwc_device *pdev); -extern int pwc_mpt_reset(struct pwc_device *pdev, int flags); -extern int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt); - -/* Various controls; should be obvious. Value 0..65535, or < 0 on error */ -extern int pwc_get_brightness(struct pwc_device *pdev); -extern int pwc_set_brightness(struct pwc_device *pdev, int value); -extern int pwc_get_contrast(struct pwc_device *pdev); -extern int pwc_set_contrast(struct pwc_device *pdev, int value); -extern int pwc_get_gamma(struct pwc_device *pdev); -extern int pwc_set_gamma(struct pwc_device *pdev, int value); -extern int pwc_get_saturation(struct pwc_device *pdev); -extern int pwc_set_saturation(struct pwc_device *pdev, int value); -extern int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value); -extern int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value); -extern int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor); - -/* Power down or up the camera; not supported by all models */ -extern int pwc_camera_power(struct pwc_device *pdev, int power); - -/* Private ioctl()s; see pwc-ioctl.h */ -extern int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg); - - -/** pwc-uncompress.c */ -/* Expand frame to image, possibly including decompression. Uses read_frame and fill_image */ -extern int pwc_decompress(struct pwc_device *pdev); + /* Global variables */ + extern int pwc_trace; + extern int pwc_preferred_compression; + + /** functions in pwc-if.c */ + int pwc_video_open(struct pwc_device *pdev); + int pwc_video_close(struct pwc_device *pdev); + int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot); + struct pwc_device * usb_pwc_probe(struct usb_device *udev, unsigned int ifnum); + void usb_pwc_disconnect(struct usb_device *udev, void *ptr); + int usb_pwc_init(void); + + /** Functions in pwc-misc.c */ + /* sizes in pixels */ + extern struct pwc_coord pwc_image_sizes[PSZ_MAX]; + + int pwc_decode_size(struct pwc_device *pdev, int width, int height); + void pwc_construct(struct pwc_device *pdev); + + /** Functions in pwc-ctrl.c */ + /* Request a certain video mode. Returns < 0 if not possible */ + extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot); + /* Calculate the number of bytes per image (not frame) */ + extern void pwc_set_image_buffer_size(struct pwc_device *pdev); + extern int pwc_mpt_reset(struct pwc_device *pdev, int flags); + extern int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt); + + /* Various controls; should be obvious. Value 0..65535, or < 0 on error */ + extern int pwc_get_brightness(struct pwc_device *pdev); + extern int pwc_set_brightness(struct pwc_device *pdev, int value); + extern int pwc_get_contrast(struct pwc_device *pdev); + extern int pwc_set_contrast(struct pwc_device *pdev, int value); + extern int pwc_get_gamma(struct pwc_device *pdev); + extern int pwc_set_gamma(struct pwc_device *pdev, int value); + extern int pwc_get_saturation(struct pwc_device *pdev); + extern int pwc_set_saturation(struct pwc_device *pdev, int value); + extern int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value); + extern int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value); + extern int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor); + + /* Power down or up the camera; not supported by all models */ + extern int pwc_camera_power(struct pwc_device *pdev, int power); + + /* Private ioctl()s; see pwc-ioctl.h */ + extern int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg); + + + /** pwc-uncompress.c */ + /* Expand frame to image, possibly including decompression. Uses read_frame and fill_image */ + extern int pwc_decompress(struct pwc_device *pdev); #ifdef __cplusplus }