diff -urN spca5xx-20060402.orig/drivers/usb/Makefile spca5xx-20060402/drivers/usb/Makefile --- spca5xx-20060402.orig/drivers/usb/Makefile 1970-01-01 09:00:00.000000000 +0900 +++ spca5xx-20060402/drivers/usb/Makefile 2006-06-04 11:21:10.000000000 +0900 @@ -0,0 +1,19 @@ +# Makefile for spca5shot/spca5view +# +all: spca5shot spca5view + +SHARESRCS = spca5share.c linux_usbif.c spca5xx.c spcadecoder.c + +spca5shot: Makefile.spca5shot spca5shot.c ${SHARESRCS} + make -f Makefile.spca5shot + +spca5view: Makefile.spca5view spca5view.c gui.c ${SHARESRCS} + make -f Makefile.spca5view + +install: + make -f Makefile.spca5shot install + make -f Makefile.spca5view install + +clean: + make -f Makefile.spca5shot clean + make -f Makefile.spca5view clean diff -urN spca5xx-20060402.orig/drivers/usb/Makefile.spca5shot spca5xx-20060402/drivers/usb/Makefile.spca5shot --- spca5xx-20060402.orig/drivers/usb/Makefile.spca5shot 1970-01-01 09:00:00.000000000 +0900 +++ spca5xx-20060402/drivers/usb/Makefile.spca5shot 2006-06-04 11:21:10.000000000 +0900 @@ -0,0 +1,18 @@ +# Makefile for spca5shot +# +PREFIX ?= /usr/local +BINDIR ?= ${PREFIX}/bin +MANDIR ?= ${PREFIX}/man + +PROG = spca5shot +SRCS = spca5shot.c spca5share.c linux_usbif.c spca5xx.c spcadecoder.c + +MAN = ${PROG}.1 + +CFLAGS += -Wall -g +LDFLAGS += -Wall -g + +clean: cleanprog + rm -f *~ *.orig ${PROG}.cat1 + +.include diff -urN spca5xx-20060402.orig/drivers/usb/Makefile.spca5view spca5xx-20060402/drivers/usb/Makefile.spca5view --- spca5xx-20060402.orig/drivers/usb/Makefile.spca5view 1970-01-01 09:00:00.000000000 +0900 +++ spca5xx-20060402/drivers/usb/Makefile.spca5view 2006-06-04 11:21:10.000000000 +0900 @@ -0,0 +1,22 @@ +# Makefile for spca5view +# +PREFIX ?= /usr/local +BINDIR ?= ${PREFIX}/bin +MANDIR ?= ${PREFIX}/man + +PROG = spca5view +SRCS = spca5view.c spca5share.c linux_usbif.c spca5xx.c spcadecoder.c gui.c +MAN = ${PROG}.1 + +GTKCFLAGS != gtk-config --cflags +IMLIBCFLAGS != imlib-config --cflags-gdk +CFLAGS += -Wall -g ${GTKCFLAGS} ${IMLIBCFLAGS} -I/usr/pkg/include + +GTKLDFLAGS != gtk-config --libs +IMLIBLDFLAGS!= imlib-config --libs-gdk +LDFLAGS += -Wall -g ${GTKLDFLAGS} ${IMLIBLDFLAGS} -L/usr/pkg/include + +clean: cleanprog + rm -f *~ *.orig ${PROG}.cat1 + +.include diff -urN spca5xx-20060402.orig/drivers/usb/README.BSD spca5xx-20060402/drivers/usb/README.BSD --- spca5xx-20060402.orig/drivers/usb/README.BSD 1970-01-01 09:00:00.000000000 +0900 +++ spca5xx-20060402/drivers/usb/README.BSD 2006-06-04 22:19:30.000000000 +0900 @@ -0,0 +1,112 @@ + USB cameras based SPCA5xx Image Capture Programs for *BSD + + Takafumi Mizuno < taka-qce at ls-a.jp > + +USB Cameras based SPCA5xx Utilities for *BSD version 0.6a +----------------------------------------------- +1. What is it? + They are patches from SPCA5xx chipset linux driver to be worked on *BSD, + There is included two userland programs as follow; + + spca5shot ... simple image capture program. + spca5view ... sequential image viewer program. + +2. Supported USB cameras + + Vendor Device Product Name + ------ ------ ------------ + 0x041e 0x4036 Creative WebCam Live! + 0x041e 0x403a Creative webcam nx pro + 0x046d 0x092c Logitech QuickCam Express II + 0x046d 0x092c Logitech QuickCam chat + 0x0572 0x0041 Creative webcam notebook PD1170 + 0x060b 0xa001 Maxell CompactPC Camera PM3 + 0x0733 0x0401 Intel CS330 + 0x0923 0x010f Generic webcam based ICM532/TV8532 + 0x093a 0x2468 Generic webcam based PAC207 + 0x0ac8 0x301b LOAS MCM-H06SL + 0x0c45 0x6005 Generic webcam based SN9C101 + 0x0c45 0x6025 LOAS MCM-S02SL + 0x0c45 0x6029 Raccoon AM-ST3 + 0xabcd 0xcdee SIGMA-APO Petcam + + +3. How do I build it? + + a) Download Linux SPCA50x USB webcams driver, spca5xx-20060402.tar.gz + from http://mxhaard.free.fr/download.html or + http://mxhaard.free.fr/spca50x/Download/oldrelease + + Note: the patchset supported a spca5xx-20060402.tar.gz. + + for example. + + % wget http://mxhaard.free.fr/spca50x/Download/spca5xx-20060402.tar.gz + + b) Download patch file for *BSD. + + % wget http://www.medias.ne.jp/~takam/bsd/spca5xx-bsd-0.6a.patch.gz + + c) Extract tarball and applied patches. + + % tar -zxvf spca5xx-20060402.tar.gz + % gzip -dc spca5xx-bsd-0.6a.patch.gz | patch -p0 + + d) Do make + + % cd spca5xx-20060402/drivers/usb/ + % make + % su root -c 'make install' + +4. Quick Start + + a) spca5shot + - display the camera information. + % spca5shot -i + + - take a photo by 640x480 and save to out.ppm + % spca5shot -s 640x480 -o out.ppm + + - display help message and manual + % spca5shot -h + % man spca5shot + + b) spca5view + - start + % spca5view + + - display help message and manual + % spca5view -h + % man spca5view + +----------------------------------------------- +References: + Michel Xhaard's Web Page + http://mxhaard.free.fr/index.html + + SPCA50X USB Camera Linux Driver + http://spca50x.sourceforge.net/ + + Image Processing Program by Linux(Japanese only!) + Author Iio Jun, ohmsha publising. ISBN 4-274-94623-1 + +----------------------------------------------- +CREDITS: +Special Thanks to Michel Xhaard and spca50x linux driver's developers +- Rev.0.6a +Thanks to Jindra Fucik for supporting webcams based PAC207 +- Rev.0.6 +Thanks to Tomas Hecker for creating the patchset to spca5xx-20060402 + and supporting Creative WebCam Live! +- Rev.0.5 +Thanks to Dennis Schneider for creating the patchset to spca5xx-20060301 + and testing Trust WB-1400T +Thanks to pkgsrc-users@netbsd.org for creating the patchset to Dragonfly BSD +- Rev.0.4 +Thanks to Christian Mangin for creating those patches almost :) +Thanks to Pete for checking man page and (M)Jpeg options. +Thanks to Wouter Klouwen for testing Quickcam Express II +- Rev.0.3 +Thanks to Radko Keves for testing Creative Web NX Pro on FreeBSD +Thanks to Tokuda Hiroshi for testing LOAS MCM-H06SL +Thanks to Vladislav Sekulic for testing Intel CS330 diff -urN spca5xx-20060402.orig/drivers/usb/gui.c spca5xx-20060402/drivers/usb/gui.c --- spca5xx-20060402.orig/drivers/usb/gui.c 1970-01-01 09:00:00.000000000 +0900 +++ spca5xx-20060402/drivers/usb/gui.c 2006-06-04 11:21:10.000000000 +0900 @@ -0,0 +1,213 @@ +/* + * GUI of sequential image capture program. + * gui.[ch] GUI and callback functions + * + * Copyright (C) 2003,2004,2005 Takafumi Mizuno + * + * Reference: Image Processing Program by Linux, author Iio Jun, ohmsha publishing + * ISBN:4-274-94623-1 ( Japanese Only! ) + */ +#include /* gettimeofday */ + +#include +#include + +#include "gui.h" +#define REQ_SPCA5VIEW +#include "spca5shot.h" + +/* interval time (milliseconds) */ +#define INTERVAL 1000 +static int interval = INTERVAL; + +/* display area */ +static GdkImlibImage *im = NULL; + +/* backing store pixmap area */ +static GdkPixmap *pixmap = NULL; + +/* interval timer tag */ +static gint ttag; + +/* check grab image error */ +int errnum = 0; + +/* set GUI */ +void gui_config(void) +{ + GtkWidget *main_window; + GtkWidget *aspframe; + GtkWidget *drawing_area; + struct timeval tv[EXPOSURE_TIMES]; + gint ti = 0; /* index of tv[] */ + gint i; + + /* 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); + + /* calc frame rate */ + printf("calculating frame rate... just a moment please."); + gettimeofday(&tv[ti], NULL); /* tv[0] */ + for ( i = 0; i < EXPOSURE_TIMES; i++ ) { + im = get_new_frame(im); + printf("."); fflush(stdout); + ti = (ti + 1) % EXPOSURE_TIMES; + gettimeofday(&tv[ti], NULL); + } + printf("%.2f(fps)\n", calc_framerate(tv, ti, &interval)); + if ( interval < 0 ) { + interval = INTERVAL; + } else if ( interval < 33 ) { /* 33.3 = 30fps */ + interval = 33; + } + + + if ( im == NULL || errnum > ERRNUM_LIMITS ) { + fprintf(stderr, "can't get a first frame\n"); + exit(-1); + } + errnum = 0; + + /* 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_signal_connect(GTK_OBJECT(main_window), "key_press_event", + GTK_SIGNAL_FUNC(pushkey), 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_imlib_free_pixmap(pixmap); + pixmap = gdk_imlib_move_image(im); + + return TRUE; +} + +/* key_press event */ +gint pushkey(GtkWidget *widget, GdkEventKey *event) +{ + if( *(event->string) == 'q' || *(event->string) == 'Q' ) { + /* quit */ + gtk_main_quit(); + return FALSE; + } else { + do_pushkey(*(event->string)); + } + + return TRUE; +} + +/* exposed event */ +gint 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 ) { + /* do nothing */ + return TRUE; + } + configured(widget, NULL); + exposed(widget, &e); + } + + return TRUE; + +} + +#if 0 +/* caluclate frame rate */ +gint calc_framerate(struct timeval tv[], gint lastnum) +{ + gint i; + glong avetime, difftime; + +#define PREVNUM(num) ((((num)-1)<0)?(EXPOSURE_TIMES-1):((num)-1)) + + i = lastnum; + avetime = difftime = 0L; + do { + /* diff time */ + if ( tv[PREVNUM(i)].tv_sec > tv[i].tv_sec ) { + /* previous time is future? */ + return -1; + } else { + difftime = (tv[i].tv_sec - tv[PREVNUM(i)].tv_sec) * 1000000L; + } + difftime = difftime + tv[i].tv_usec - tv[PREVNUM(i)].tv_usec; + PDEBUG(5, "num:%d-%d now:%ldsec:%ld prev:%ldsec:%ld difftime:%ld", + i, PREVNUM(i), + tv[i].tv_sec, tv[i].tv_usec, + tv[PREVNUM(i)].tv_sec, tv[PREVNUM(i)].tv_usec, + difftime); + avetime += difftime; + i = PREVNUM(i); + } while ( PREVNUM(i) != lastnum ); + + avetime /= (EXPOSURE_TIMES-1); + if ( avetime == 0 ) { + return -1; + } else { + return avetime / 1000; /* us->ms */ + } + +} +#endif diff -urN spca5xx-20060402.orig/drivers/usb/gui.h spca5xx-20060402/drivers/usb/gui.h --- spca5xx-20060402.orig/drivers/usb/gui.h 1970-01-01 09:00:00.000000000 +0900 +++ spca5xx-20060402/drivers/usb/gui.h 2006-06-04 11:21:10.000000000 +0900 @@ -0,0 +1,13 @@ +#ifndef _GUI_H_ +#define _GUI_H_ + +/* prototype declaration */ +void gui_config(void); + +gint configured(GtkWidget *, GdkEventConfigure *); +gint exposed(GtkWidget *, GdkEventExpose *); +gint flipvertical(GtkWidget *, GdkEventExpose *); +gint update_screen(GtkWidget *); +gint pushkey(GtkWidget *widget, GdkEventKey *); + +#endif /* _GUI_H_ */ diff -urN spca5xx-20060402.orig/drivers/usb/linux_usbif.c spca5xx-20060402/drivers/usb/linux_usbif.c --- spca5xx-20060402.orig/drivers/usb/linux_usbif.c 1970-01-01 09:00:00.000000000 +0900 +++ spca5xx-20060402/drivers/usb/linux_usbif.c 2006-06-04 11:21:10.000000000 +0900 @@ -0,0 +1,152 @@ +/* + * linux_usbif.c - Linux API; usb_control_msg() usb_set_interface() + * usb_set_configuration() usb_ifnum_to_if() + * Copyright (C) 2003,2004,2005,2006 Takafumi Mizuno + * + * vide4linux definications from videodev.h (see linux_usbif.h ) + * by v4l project + * v4l2 project homepage: http://www.thedirks.org/v4l2/ + * patches available from: http://bytesex.org/patches/ + * + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: linux_usbif.c,v 1.6 2006/03/12 12:06:10 taka Exp taka $ + */ + +#include +#include + +#if defined(__DragonFly__) +#include +#else +#include +#endif + +#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_configuration(struct usb_device *dev, int configuration) +{ + if (ioctl(dev->fd, USB_SET_CONFIG, &configuration) < 0) { + perror("USB_SET_CONFIG"); + 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; +} + +int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, + void *data, int len, int *actual_length, int timeout) +{ + /* XXX pipe,actual_length,timeout is dummy */ + ssize_t readlen; + + /* note: you must open the endpoint(efd) before call me */ + readlen = read(usb_dev->efd, data, len); + if ( readlen < 0 ) { + perror("usb_bulk_msg"); + return -1; + } + *actual_length = (int)readlen; + return 0; +} + +struct usb_interface_desc *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum) +{ + struct usb_interface_desc *interface; + + interface = &(dev->interfacedesc); + if (!interface) { + interface->uid_config_index = USB_CURRENT_CONFIG_INDEX; + interface->uid_interface_index = 0; + interface->uid_alt_index = 0; + if (ioctl(dev->fd, USB_GET_INTERFACE_DESC, interface) < 0) { + perror("usb_ifnum_to_if:USB_GET_INTERFACE_DESC"); + return NULL; + } + } + if ( interface->uid_desc.bInterfaceNumber == ifnum ) { + return interface; + } else { + return NULL; + } + +} + +struct palette_name_list PALlist[] ={ + {0, "unknown(#0)"}, + {VIDEO_PALETTE_GREY, "Linear greyscale"}, + {VIDEO_PALETTE_HI240, "High 240 cube (BT848)"}, + {VIDEO_PALETTE_RGB565, "565 16 bit RGB"}, + {VIDEO_PALETTE_RGB24, "24bit RGB"}, + {VIDEO_PALETTE_RGB32, "32bit RGB "}, + {VIDEO_PALETTE_RGB555, "555 15bit RGB"}, + {VIDEO_PALETTE_YUV422, "YUV422 capture"}, + {VIDEO_PALETTE_YUYV, "YUYV capture"}, + {VIDEO_PALETTE_UYVY, "UYVY capture"}, + {VIDEO_PALETTE_YUV420, "YUV420 capture"}, + {VIDEO_PALETTE_YUV411, "YUV411 capture"}, + {VIDEO_PALETTE_RAW, "RAW capture (BT848)"}, + {VIDEO_PALETTE_YUV422P, "YUV 4:2:2 Planar"}, + {VIDEO_PALETTE_YUV411P, "YUV 4:1:1 Planar"}, + {VIDEO_PALETTE_YUV420P, "YUV 4:2:0 Planar"}, + {VIDEO_PALETTE_YUV410P, "YUV 4:1:0 Planar"}, + {17, "unknown(#17)"}, + {18, "unknown(#18)"}, + {19, "unknown(#19)"}, + {20, "JPEG without header"}, /* spca5xx uniq */ + {21, "JPEG with header"}, /* spca5xx uniq */ + {-1,NULL} +}; diff -urN spca5xx-20060402.orig/drivers/usb/linux_usbif.h spca5xx-20060402/drivers/usb/linux_usbif.h --- spca5xx-20060402.orig/drivers/usb/linux_usbif.h 1970-01-01 09:00:00.000000000 +0900 +++ spca5xx-20060402/drivers/usb/linux_usbif.h 2006-06-04 11:21:10.000000000 +0900 @@ -0,0 +1,374 @@ +#ifndef __LINUX_USBIF__H +#define __LINUX_USBIF__H + +/* + * linux_usbif.h - Linux API; usb_control_msg() usb_set_interface() + * usb_set_configuration() + * Copyright (C) 2003,2004,2005,2006 Takafumi Mizuno + * + * $Id: linux_usbif.h,v 1.9 2006/03/12 12:06:12 taka Exp taka $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__DragonFly__) +#include +#else +#include +#endif + +#define USB_ENDPOINT_DIR_MASK 0x80 +#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 USB_ENDPOINT_XFERTYPE_MASK UE_XFERTYPE +#define USB_ENDPOINT_XFER_CONTROL UE_CONTROL +#define USB_ENDPOINT_XFER_ISOC UE_ISOCHRONOUS +#define USB_ENDPOINT_XFER_BULK UE_BULK +#define USB_ENDPOINT_XFER_INT UE_INTERRUPT + +#define USB_REQ_SET_INTERFACE UR_SET_INTERFACE + +#define HZ 1000 /* ms */ + +/* dummy */ +#define usb_sndctrlpipe(a,b) (b) +#define usb_rcvctrlpipe(a,b) (b) +#define usb_rcvbulkpipe(a,b) (b) + +typedef u_int8_t u8; +typedef u_int16_t u16; +typedef u_int32_t u32; +typedef u_int8_t __u8; +typedef u_int16_t __u16; +typedef int32_t __s32; +typedef u_int32_t __u32; + +/* memory */ +#define printk(fmt,args...) fprintf(stderr,fmt,##args) +#define kmalloc(siz,opt) malloc(siz) +#define kfree(pt) free(pt) +#define rvmalloc(siz) malloc(siz) +#define rvfree(pt,siz) free(pt) +#define usbvideo_rvmalloc(siz) malloc(siz) +#define usbvideo_rvfree(pt,sz) free(pt) + +/* from $kernel_source_top/include/linux/???.h */ +/* I referenced 2.4.19 */ +#define LINUX_VERSION_CODE 0x020419 +#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; +}; + +struct usb_device_id { + __u16 idVendor; + __u16 idProduct; +}; +#define USB_DEVICE(vend,prod) (vend), (prod) + +/* from $kernel_source_top/include/linux/a.out.h */ +/* original size = 0x400 too small!? */ +#define PAGE_SIZE 0x800 + +/* from $kernel_source_top/include/linux/usb.h */ +/* rapper for BSD */ +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_configuration(struct usb_device *dev, int configuration); +int usb_set_interface(struct usb_device *dev, int ifnum, int alternate); +int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, + void *data, int len, int *actual_length, int timeout); +struct usb_interface_desc *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum); +#define wait_ms(ms) usleep(ms) + +/* 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 */ + +/* from $kernel_source_top/include/linux/module.h */ +#define MODULE_AUTHOR(name) +#define MODULE_LICENSE(license) +#define MODULE_DESCRIPTION(desc) +#define MODULE_SUPPORTED_DEVICE(name) +#define MODULE_PARM(var,type) +#define MODULE_PARM_DESC(var,desc) + +#define THIS_MODULE NULL +#define MOD_INC_USE_COUNT do { } while (0) +#define MOD_DEC_USE_COUNT do { } while (0) +#define MOD_IN_USE 1 + +#define MODULE_DEVICE_TABLE(type,name) + +/* from $kernel_source_top/include/linux/wait.h */ +/* no action for queue */ +typedef int wait_queue_head_t; +#define init_waitqueue_head(q) do { } while (0) +#define waitqueue_active(q) 0 +#define wake_up_interruptible(q) do { } while (0) + +/* from $kernel_source_top/include/asm-$arch/semaphore.h */ +/* no action for semaphore */ +struct semaphore { + int dummy; +}; +#define down(lock) do { } while (0) +#define up(lock) do { } while (0) +#define init_MUTEX(lock) do { } while (0) + +/* from $kernel_source_top/include/asm-$arch/spinlock.h */ +#define SPIN_LOCK_UNLOCKED 0 + +/* from $kernel_source_top/include/asm-$arch/hardirq.h */ +/* no idea */ +#define in_interrupt() 0 + +/* from $kernel_source_top/include/linux/timer.h */ +/* no use for static timer */ +struct timer_list { + unsigned long expires; + unsigned long data; + void (*function)(unsigned long); +}; +#define init_timer(tim) do { } while (0) +#define del_timer(tim) do { } while (0) +#define add_timer(tim) { usleep((tim)->expires); \ + ((tim)->function)((tim)->data); } + +/* from $kernel_source_top/include/linux/sched.h */ +/* dummy set */ +#define jiffies 0 +#define wait_event_interruptible(wq, condition) 1 /* always fail ... ok? */ +#define schedule() do { } while (0) + +/* from $kernel_source_top/include/linux/tqueue.h */ +/* no action for task */ +struct tq_struct { +// struct list_head list; /* linked list of active bh's */ + unsigned long sync; /* must be initialized to zero */ + void (*routine)(void *); /* function to call */ + void *data; /* argument to function */ +}; + +/* from $kernel_source_top/include/linux/videodev.h */ +#define VID_TYPE_CAPTURE 1 /* Can capture */ +#define VID_TYPE_TUNER 2 /* Can tune */ +#define VID_TYPE_TELETEXT 4 /* Does teletext */ +#define VID_TYPE_OVERLAY 8 /* Overlay onto frame buffer */ +#define VID_TYPE_CHROMAKEY 16 /* Overlay by chromakey */ +#define VID_TYPE_CLIPPING 32 /* Can clip */ +#define VID_TYPE_FRAMERAM 64 /* Uses the frame buffer memory */ +#define VID_TYPE_SCALES 128 /* Scalable */ +#define VID_TYPE_MONOCHROME 256 /* Monochrome only */ +#define VID_TYPE_SUBCAPTURE 512 /* Can capture subareas of the image */ +#define VID_TYPE_MPEG_DECODER 1024 /* Can decode MPEG streams */ +#define VID_TYPE_MPEG_ENCODER 2048 /* Can encode MPEG streams */ +#define VID_TYPE_MJPEG_DECODER 4096 /* Can decode MJPEG streams */ +#define VID_TYPE_MJPEG_ENCODER 8192 /* Can encode MJPEG streams */ + +struct video_capability +{ + char name[32]; + int type; + int channels; /* Num channels */ + int audios; /* Num audio devices */ + int maxwidth; /* Supported width */ + int maxheight; /* And height */ + int minwidth; /* Supported width */ + int minheight; /* And height */ +}; + +struct video_channel +{ + int channel; + char name[32]; + int tuners; + __u32 flags; +#define VIDEO_VC_TUNER 1 /* Channel has a tuner */ +#define VIDEO_VC_AUDIO 2 /* Channel has audio */ + __u16 type; +#define VIDEO_TYPE_TV 1 +#define VIDEO_TYPE_CAMERA 2 + __u16 norm; /* Norm set by channel */ +}; + +struct video_tuner +{ + int tuner; + char name[32]; + unsigned long rangelow, rangehigh; /* Tuner range */ + __u32 flags; +#define VIDEO_TUNER_PAL 1 +#define VIDEO_TUNER_NTSC 2 +#define VIDEO_TUNER_SECAM 4 +#define VIDEO_TUNER_LOW 8 /* Uses KHz not MHz */ +#define VIDEO_TUNER_NORM 16 /* Tuner can set norm */ +#define VIDEO_TUNER_STEREO_ON 128 /* Tuner is seeing stereo */ +#define VIDEO_TUNER_RDS_ON 256 /* Tuner is seeing an RDS datastream */ +#define VIDEO_TUNER_MBS_ON 512 /* Tuner is seeing an MBS datastream */ + __u16 mode; /* PAL/NTSC/SECAM/OTHER */ +#define VIDEO_MODE_PAL 0 +#define VIDEO_MODE_NTSC 1 +#define VIDEO_MODE_SECAM 2 +#define VIDEO_MODE_AUTO 3 + __u16 signal; /* Signal strength 16bit scale */ +}; + +struct video_picture +{ + __u16 brightness; + __u16 hue; + __u16 colour; + __u16 contrast; + __u16 whiteness; /* Black and white only */ + __u16 depth; /* Capture depth */ + __u16 palette; /* Palette in use */ +#define VIDEO_PALETTE_GREY 1 /* Linear greyscale */ +#define VIDEO_PALETTE_HI240 2 /* High 240 cube (BT848) */ +#define VIDEO_PALETTE_RGB565 3 /* 565 16 bit RGB */ +#define VIDEO_PALETTE_RGB24 4 /* 24bit RGB */ +#define VIDEO_PALETTE_RGB32 5 /* 32bit RGB */ +#define VIDEO_PALETTE_RGB555 6 /* 555 15bit RGB */ +#define VIDEO_PALETTE_YUV422 7 /* YUV422 capture */ +#define VIDEO_PALETTE_YUYV 8 +#define VIDEO_PALETTE_UYVY 9 /* The great thing about standards is ... */ +#define VIDEO_PALETTE_YUV420 10 +#define VIDEO_PALETTE_YUV411 11 /* YUV411 capture */ +#define VIDEO_PALETTE_RAW 12 /* RAW capture (BT848) */ +#define VIDEO_PALETTE_YUV422P 13 /* YUV 4:2:2 Planar */ +#define VIDEO_PALETTE_YUV411P 14 /* YUV 4:1:1 Planar */ +#define VIDEO_PALETTE_YUV420P 15 /* YUV 4:2:0 Planar */ +#define VIDEO_PALETTE_YUV410P 16 /* YUV 4:1:0 Planar */ +#define VIDEO_PALETTE_PLANAR 13 /* start of planar entries */ +#define VIDEO_PALETTE_COMPONENT 7 /* start of component entries */ +}; + +struct video_window +{ + __u32 x,y; /* Position of window */ + __u32 width,height; /* Its size */ + __u32 chromakey; + __u32 flags; + struct video_clip *clips; /* Set only */ + int clipcount; +#define VIDEO_WINDOW_INTERLACE 1 +#define VIDEO_WINDOW_CHROMAKEY 16 /* Overlay by chromakey */ +#define VIDEO_CLIP_BITMAP -1 +/* bitmap is 1024x625, a '1' bit represents a clipped pixel */ +#define VIDEO_CLIPMAP_SIZE (128 * 625) +}; + +struct video_capture +{ + __u32 x,y; /* Offsets into image */ + __u32 width, height; /* Area to capture */ + __u16 decimation; /* Decimation divider */ + __u16 flags; /* Flags for capture */ +#define VIDEO_CAPTURE_ODD 0 /* Temporal */ +#define VIDEO_CAPTURE_EVEN 1 +}; + +struct video_buffer +{ + void *base; + int height,width; + int depth; + int bytesperline; +}; + +struct video_mmap +{ + unsigned int frame; /* Frame (0 - n) for double buffer */ + int height,width; + unsigned int format; /* should be VIDEO_PALETTE_* */ +}; + +#define VIDEO_MAX_FRAME 32 + +struct video_mbuf +{ + int size; /* Total memory to map */ + int frames; /* Frames */ + int offsets[VIDEO_MAX_FRAME]; +}; + + +#define VIDIOCGCAP 1 /* Get capabilities */ +#define VIDIOCGCHAN 2 /* Get channel info (sources) */ +#define VIDIOCSCHAN 3 /* Set channel */ +#define VIDIOCGTUNER 4 /* Get tuner abilities */ +#define VIDIOCSTUNER 5 /* Tune the tuner for the current channel */ +#define VIDIOCGPICT 6 /* Get picture properties */ +#define VIDIOCSPICT 7 /* Set picture properties */ +#define VIDIOCCAPTURE 8 /* Start, end capture */ +#define VIDIOCGWIN 9 /* Get the video overlay window */ +#define VIDIOCSWIN 10 /* Set the video overlay window - passes clip list for hardware smarts , chromakey etc */ +#define VIDIOCGFBUF 11 /* Get frame buffer */ +#define VIDIOCSFBUF 12 /* Set frame buffer - root only */ +#define VIDIOCKEY 13 /* Video key event - to dev 255 is to all - cuts capture on all DMA windows with this key (0xFFFFFFFF == all) */ +#define VIDIOCGFREQ 14 /* Set tuner */ +#define VIDIOCSFREQ 15 /* Set tuner */ +#define VIDIOCGAUDIO 16 /* Get audio info */ +#define VIDIOCSAUDIO 17 /* Audio source, mute etc */ +#define VIDIOCSYNC 18 /* Sync with mmap grabbing */ +#define VIDIOCMCAPTURE 19 /* Grab frames */ +#define VIDIOCGMBUF 20 /* Memory map buffer info */ +#define VIDIOCGUNIT 21 /* Get attached units */ +#define VIDIOCGCAPTURE 22 /* Get subcapture */ +#define VIDIOCSCAPTURE 23 /* Set subcapture */ +#define VIDIOCSPLAYMODE 24 /* Set output video mode/feature */ +#define VIDIOCSWRITEMODE 25 /* Set write mode */ +#define VIDIOCGPLAYINFO 26 /* Get current playback info from hardware */ +#define VIDIOCSMICROCODE 27 /* Load microcode into hardware */ +#define VIDIOCGVBIFMT 28 /* Get VBI information */ +#define VIDIOCSVBIFMT 29 /* Set VBI information */ + +/* palette name */ +struct palette_name_list { + int num; + const char *name; +}; +extern struct palette_name_list PALlist[]; + +#endif /* __LINUX_USBIF__H */ diff -urN spca5xx-20060402.orig/drivers/usb/mr97311.h spca5xx-20060402/drivers/usb/mr97311.h --- spca5xx-20060402.orig/drivers/usb/mr97311.h 2006-01-13 23:01:11.000000000 +0900 +++ spca5xx-20060402/drivers/usb/mr97311.h 2006-06-04 11:21:10.000000000 +0900 @@ -85,7 +85,7 @@ buf[i] = value[i]; rc = usb_control_msg(dev, - usb_sndbulkpipe(dev, 4), + 0, // dummy 0x12, 0xc8, index_value, index, value, length, 5 * HZ); @@ -103,7 +103,7 @@ unsigned char data[242]; unsigned short MI_buf[242]; int h_size, v_size; - int intpipe; + /* int intpipe; *BSD patch */ //struct usb_device *dev = pcam->dev; memset(data, 0, 242); memset(MI_buf, 0, 242); @@ -367,9 +367,10 @@ MISensor_BulkWrite(pcam->dev, MI_buf + 0xF1, 0xF1, 1, 0); - +/* BSD patch (we probably need a wrapper for usb_clear_halt) intpipe = usb_sndintpipe(pcam->dev, 0); err_code = usb_clear_halt(pcam->dev, intpipe); +*/ data[0] = 0x00; data[1] = 0x4D; // ISOC transfering enable... @@ -399,7 +400,7 @@ data[dest + 2] = 0; result = usb_control_msg(dev, - usb_sndbulkpipe(dev, 4), + 0, // dummy 0x12, 0xc8, 0, Address, data, 5, 5 * HZ); PDEBUG(1, "reg write: 0x%02X , result = 0x%x \n", Address, result); diff -urN spca5xx-20060402.orig/drivers/usb/pac207.h spca5xx-20060402/drivers/usb/pac207.h --- spca5xx-20060402.orig/drivers/usb/pac207.h 2006-02-20 07:44:22.000000000 +0900 +++ spca5xx-20060402/drivers/usb/pac207.h 2006-06-04 11:21:10.000000000 +0900 @@ -273,7 +273,7 @@ static void pac207_setAutobright(struct usb_spca50x *spca50x) { - unsigned long flags; + /* unsigned long flags; BSD patch */ __u8 luma = 0; __u8 luma_mean = 128; __u8 luma_delta = 20; @@ -284,9 +284,9 @@ pac207_reg_read(spca50x->dev, 0x02, &Pxclk); Gbright = Pxclk; - spin_lock_irqsave(&spca50x->v4l_lock, flags); + /* spin_lock_irqsave(&spca50x->v4l_lock, flags); BSD patch */ luma = spca50x->avg_lum; - spin_unlock_irqrestore(&spca50x->v4l_lock, flags); + /* spin_unlock_irqrestore(&spca50x->v4l_lock, flags); BSD patch */ PDEBUG(2, "Pac207 lumamean %d", luma); if ((luma < (luma_mean - luma_delta)) || diff -urN spca5xx-20060402.orig/drivers/usb/spca561.h spca5xx-20060402/drivers/usb/spca561.h --- spca5xx-20060402.orig/drivers/usb/spca561.h 2006-03-18 02:27:39.000000000 +0900 +++ spca5xx-20060402/drivers/usb/spca561.h 2006-06-04 11:21:10.000000000 +0900 @@ -556,7 +556,7 @@ Clck = 0x25; break; } - if (compress && spca50x->mode <= 1) { + if(spca50x->mode <= 1){ // Enable compression // this is correct for 320x240; it also works at 352x288 // hell, I don't even know what this value means :) Clck = 0x83; diff -urN spca5xx-20060402.orig/drivers/usb/spca5share.c spca5xx-20060402/drivers/usb/spca5share.c --- spca5xx-20060402.orig/drivers/usb/spca5share.c 1970-01-01 09:00:00.000000000 +0900 +++ spca5xx-20060402/drivers/usb/spca5share.c 2006-06-04 11:22:11.000000000 +0900 @@ -0,0 +1,901 @@ +/* + * usbcam based SPCA5xx Image Capture Program for NetBSD, version 0.6 + * spca5share - spca5shot/spca5view shared functions + * Copyright (C) 2005-2006 Takafumi Mizuno + * + * Portions of this program were modeled after or adapted from the + * version 0.56 of the SPCA5xx video for linux (v4l) driver. + * SPCA5xx version by Michel Xhaard + * Based on : + * SPCA50x version by Joel Crisp + * OmniVision OV511 Camera-to-USB Bridge Driver + * Copyright (c) 1999-2000 Mark W. McClelland + * Kernel 2.6.x port Michel Xhaard && Reza Jelveh (feb 2004) + * and many people; see spca50x.c and ../../README and URL as follow; + * http://spca50x.sourceforge.net/ + * http://mxhaard.free.fr/ + * + * 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 + +#if defined(__DragonFly__) +#include +#else +#include +#endif + +#include "linux_usbif.h" +#include "spca5xx.h" +#include "spcadecoder.h" // spca50x_outpicture +#include "spca5shot.h" + +#define MAX_FRAME_SIZE (640 * 480 * 4) // spca5xx.c +#define TV8532_TAG_LEN 4 /* [Seq][0xff][0xff][NextSeq] */ +#define TV8532_PENDING_LEN (TV8532_TAG_LEN-1) +#define TV8532_VSYNC_STA 0x81 + +extern unsigned char isobuf[MAX_FRAME_SIZE_PER_DESC]; +extern int errnum; + +int dumpflag = 0; +char *filename = NULL; + +/* + * reference: spca50x_move_data(@spca50x.c) + */ +int spca_grab(struct usb_spca50x *spca50x) +{ + unsigned char *cdata; //Pointer to buffer where we do store next packet + unsigned char *pData; //Pointer to buffer where we do store next packet + struct spca50x_frame *frame; //Pointer to frame data + int iPix; //Offset of pixel data in the ISO packet + int totlen = 0; + int tv8532 = 0; + int datalength; + int sequenceNumber; + int sof; + int j ,p; + int dumpnum = 0; + int seqframe = 0; + + struct usb_device *udev; + + if ( (spca50x->packet_size <= 0) || ( spca50x->packet_size > MAX_FRAME_SIZE_PER_DESC ) ) { + fprintf(stderr, "invalid packet_size %d\n", spca50x->packet_size); + return -1; + } + + udev = spca50x->dev; + if ( spca50x->curframe == -1 ) { + fprintf(stderr, "curframe = -1\n"); + return -1; + } + frame = &spca50x->frame[spca50x->curframe]; + PDEBUG(1, "Frame is %d x %d, Hdr Frame is %d x %d", + frame->width, frame->height, frame->hdrwidth, frame->hdrheight); + + cdata = NULL; + pData = NULL; + datalength = 0; + sequenceNumber = SPCA50X_SEQUENCE_DROP; + sof = 0; + + /* frame init */ + frame->highwater = frame->data; + frame->last_packet = -1; + frame->totlength = 0; + frame->grabstate = FRAME_UNUSED; + frame->scanstate = STATE_SCANNING; + + /* recieve isoc transfer data */ + for ( ;; ) { /* isoc transfer */ + datalength = read(udev->efd, (void *)isobuf, spca50x->packet_size ); + if ( datalength < 0 ) { + errnum++; + if ( errnum > 5 ) { + perror("read"); + return -1; + } else { + continue; + } + } + /* dump mode ? */ + if ( dumpflag != 0 ) { + if ( outputdump(isobuf, datalength, dumpnum) != 0 ) { + return -1; + } + dumpnum++; + if ( dumpnum >= DUMP_PACKETS ) { + return -1; + } + continue; + } + + cdata = isobuf; + + /* read the sequence number */ + if (spca50x->bridge == BRIDGE_SONIX || + spca50x->bridge == BRIDGE_ZC3XX || + spca50x->bridge == BRIDGE_CX11646 || + spca50x->bridge == BRIDGE_TV8532 || + spca50x->bridge == BRIDGE_ETOMS || + spca50x->bridge == BRIDGE_SN9CXXX || + spca50x->bridge == BRIDGE_MR97311 || + spca50x->bridge == BRIDGE_PAC207) + { + if (frame->last_packet == -1){ + /*initialize a new frame */ + sequenceNumber = 0; + } else { + sequenceNumber = frame->last_packet; + } + } else { + sequenceNumber = cdata[SPCA50X_OFFSET_SEQUENCE]; + PDEBUG (4, "Packet start %x %x %x %x %x", cdata[0], cdata[1], + cdata[2], cdata[3], cdata[4]); + } + + /* check frame start */ + switch (spca50x->bridge){ + case BRIDGE_SN9CXXX: + iPix = 0; + sof = datalength - 64; + if (sof < 0) + sequenceNumber++; + else if(cdata[sof] == 0xff && cdata[sof +1] == 0xd9){ + sequenceNumber = 0; //start of frame + // copy the end of data frame + memcpy (frame->highwater, cdata, sof+2); + frame->highwater += (sof+2); + totlen += (sof+2); +#if 0 + spin_lock(&spca50x->v4l_lock); + spca50x->avg_lum = (cdata[sof+24] + cdata[sof+26]) >> 1 ; + spin_unlock(&spca50x->v4l_lock); + PDEBUG (5,"mean luma %d",spca50x->avg_lum ); +#endif + PDEBUG (5, + "Sonix header packet found datalength %d totlength %d!!", + datalength, totlen); + PDEBUG(5,"%03d %03d %03d %03d %03d %03d %03d %03d",cdata[sof+24], cdata[sof+25], + cdata[sof+26] , cdata[sof+27], cdata[sof+28], cdata[sof+29], + cdata[sof+30], cdata[sof+31]); + // setting to skip the rest of the packet + spca50x->header_len = datalength; + } else + sequenceNumber++; + break; + case BRIDGE_ETOMS: + { + iPix = 8; + seqframe= cdata[0] & 0x3f; + datalength = (int)(((cdata[0] & 0xc0) << 2) | cdata[1]); + if (seqframe == 0x3f){ + PDEBUG(5, "Etoms header packet found datalength %d totlength %d!!",datalength,totlen); + PDEBUG(5,"Etoms G %d R %d G %d B %d",cdata[2],cdata[3],cdata[4],cdata[5]); + sequenceNumber = 0; //start of frame + spca50x->header_len = 30; + } else { + if (datalength){ + sequenceNumber++; + } else { + /* Drop Packet */ + continue; + } + } + } + break; + case BRIDGE_CX11646: + { + iPix = 0; + if (cdata[0] == 0xFF && cdata[1] == 0xD8) + { + sequenceNumber = 0; + spca50x->header_len = 2; + PDEBUG (5, + "Cx11646 header packet found datalength %d totlength %d!!", + datalength, totlen); + } + else + { + sequenceNumber++; + } + + } + break; + case BRIDGE_ZC3XX: + { + iPix = 0; + if (cdata[0] == 0xFF && cdata[1] == 0xD8) + { + sequenceNumber = 0; + spca50x->header_len = 2; //18 remove 0xff 0xd8; + PDEBUG (5, + "Zc301 header packet found datalength %d totlength %d!!", + datalength, totlen); + } + else + { + sequenceNumber++; + } + + } + break; + case BRIDGE_SONIX: + { + iPix = 0; + sof = 0; + j = 0; + p = 0; + if (datalength > 6) + { + j = datalength - 6; + } + else + { + j = 0; + } + if (j > 0) + { + for (p = 0; p < j; p++) + { + if ((cdata[0 + p] == 0xFF) && (cdata[1 + p] == 0xFF) + && (cdata[2 + p] == 0x00) + && (cdata[3 + p] == 0xC4) + && (cdata[4 + p] == 0xC4) + && (cdata[5 + p] == 0x96)) + { + sof = 1; + break; + } + } + } + if (sof) + { + sequenceNumber = 0; + spca50x->header_len = p + 12; + PDEBUG (5, + "Sonix header packet found %d datalength %d totlength %d!!", + p, datalength, totlen); + } + else + { + /* drop packet */ + sequenceNumber++; + } + + } + break; + case BRIDGE_SPCA500: + case BRIDGE_SPCA533: + { + iPix = 1; + if (sequenceNumber == SPCA50X_SEQUENCE_DROP) + { + if (cdata[1] == 0x01) + { + sequenceNumber = 0; + } + else + { + /* drop packet */ + PDEBUG (5, "Dropped packet (expected seq 0x%02x)", + frame->last_packet + 1); + continue; + } + } + else + { + sequenceNumber++; + } + } + break; + case BRIDGE_SPCA536: + { + iPix = 2; + if (sequenceNumber == SPCA50X_SEQUENCE_DROP) + { + sequenceNumber = 0; + } + else + { + sequenceNumber++; + } + } + break; + case BRIDGE_SPCA504: + case BRIDGE_SPCA504B: + case BRIDGE_SPCA504C: + { + iPix = 1; + switch (sequenceNumber) + { + case 0xfe: + sequenceNumber = 0; + break; + case SPCA50X_SEQUENCE_DROP: + /* drop packet */ + PDEBUG (5, "Dropped packet (expected seq 0x%02x)", + frame->last_packet + 1); + continue; + default: + sequenceNumber++; + break; + } + } + break; + case BRIDGE_TV8532: + { + //iPix = 4; + iPix = 0; + spca50x->header_len = 0; + PDEBUG (1, "icm532, sequenceNumber: 0x%02x packet %d ", + sequenceNumber, spca50x->packet); + /* here we detect 0x80 */ + if (cdata[0] == 0x80) + { + /* counter is limited so we need few header for a frame :) */ + + /* header 0x80 0x80 0x80 0x80 0x80 */ + /* packet 00 63 127 145 00 */ + /* sof 0 1 1 0 0 */ + /* update sequence */ + if ((spca50x->packet == 63) || (spca50x->packet == 127)) + tv8532 = 1; + /* is there a frame start ? */ + if (spca50x->packet >= ((spca50x->hdrheight >> 1) - 1)) + { + PDEBUG (1, "SOF > %d seqnumber %d packet %d", tv8532, + sequenceNumber, spca50x->packet); + if (!tv8532) + { + sequenceNumber = 0; + spca50x->packet = 0; + } + } + else + { + + if (!tv8532) + { + // Drop packet frame corrupt + PDEBUG (1, "DROP SOF %d seqnumber %d packet %d", + tv8532, sequenceNumber, spca50x->packet); + frame->last_packet = sequenceNumber = 0; + spca50x->packet = 0; + continue; + } + tv8532 = 1; + sequenceNumber++; + spca50x->packet++; + } + + } + else + { + sequenceNumber++; + spca50x->packet++; + } + } + break; + case BRIDGE_MR97311: + { + iPix = 0; + sof = 0; + j = 0; + p = 0; + if (datalength < 6 ) + continue; + else + { + for (p = 0; p < datalength-6; p++) + { + if ((cdata[0 + p] == 0xFF) && (cdata[1 + p] == 0xFF) + && (cdata[2 + p] == 0x00) + && (cdata[3 + p] == 0xFF) + && (cdata[4 + p] == 0x96) + ) + { + if((cdata[5 + p] == 0x64 ) || (cdata[5 + p] == 0x65) || + (cdata[5 + p] == 0x66) || (cdata[5 + p] == 0x67) ) + { + sof = 1; + break; + } + } + } + + if (sof) + { + sequenceNumber = 0; + spca50x->header_len = p+16; + PDEBUG (5, + "Pcam header packet found, %d datalength %d totlength %d!!", + p, datalength, totlen); + } + else + { + /* drop packet */ + sequenceNumber++; + } + + } + } + break; + case BRIDGE_PAC207: +// case 0: + { + iPix = 0; + sof = 0; + j = 0; + p = 0; + if (datalength < 6 ) + continue; + else + { + for (p = 0; p < datalength-6; p++) + { + if ((cdata[0 + p] == 0xFF) && (cdata[1 + p] == 0xFF) + && (cdata[2 + p] == 0x00) + && (cdata[3 + p] == 0xFF) + && (cdata[4 + p] == 0x96) + ) + { + sof = 1; + break; + } + } + + if (sof) + { + //printf("sof p %d datalength %d\n",p,datalength); + sequenceNumber = 0; +// JFU patch + if (frame->scanstate == STATE_SCANNING) + { + frame->highwater = frame->data; + frame->last_packet = -1; + frame->totlength = 0; + memcpy (frame->highwater, cdata+p,datalength-p); + frame->highwater += (datalength-p); + totlen = (datalength-p); + } +// JFU patch + // copy the end of data to the current frame + memcpy (frame->highwater, cdata,p); + frame->highwater += p; + totlen += p; + spca50x->header_len = p ; //copy to the nextframe start at p + PDEBUG (5, + "Pixartcam header packet found, %d datalength %d totlength %d!!", + p, datalength, totlen); + } + else + { + /* drop packet */ + sequenceNumber++; + } + + } + } + break; + case BRIDGE_SPCA561: + iPix = 1; + if (sequenceNumber == SPCA50X_SEQUENCE_DROP) + { + PDEBUG (3, "Dropped packet (expected seq 0x%02x)", + frame->last_packet + 1); + continue; + } +#if 0 + if (!sequenceNumber) + { + spin_lock(&spca50x->v4l_lock); + spca50x->avg_lum = (75*(cdata[11]+cdata[14])+77*cdata[12]+29*cdata[13]) >> 8; + spin_unlock(&spca50x->v4l_lock); + PDEBUG (4, "Frame %d,Win2 %02d ", cdata[4],spca50x->avg_lum); + } +#endif + break; + default: + { + iPix = 1; + /* check if this is a drop packet */ + if (sequenceNumber == SPCA50X_SEQUENCE_DROP) + { + PDEBUG (3, "Dropped packet (expected seq 0x%02x)", + frame->last_packet + 1); + continue; + } + } + break; + } + + PDEBUG(3, "spca50x: Packet seqnum = 0x%02x. curframe=%2d", + sequenceNumber, spca50x->curframe); + pData = cdata; + + /* Can we find a frame start */ + if (sequenceNumber == 0) { + totlen = 0; + iPix = spca50x->header_len; + PDEBUG(3, "spca50x: Found Frame Start!, framenum = %d", spca50x->curframe); + // Start of frame is implicit end of previous frame + // Check for a previous frame and finish it off if one exists + if(frame->scanstate == STATE_LINES) { + /* Decode the frame */ + frame->grabstate = FRAME_DONE; + break; + } else { + frame->scanstate=STATE_LINES; + } + } + + /* Are we in a frame? */ + if (frame == NULL || frame->scanstate != STATE_LINES) + continue; + if(sequenceNumber != frame->last_packet + 1 && frame->last_packet != -1) { + /* Note, may get one of these for the first packet after opening */ + PDEBUG(2,"Out of order packet, last = %d, this = %d", + frame->last_packet, sequenceNumber); + } + frame->last_packet = sequenceNumber; + + /* This is the real conversion of the raw camera data to BGR for V4L */ + if (spca50x->bridge == BRIDGE_TV8532) { + datalength -= (iPix + 6); // correct length for packet header skeep the last 4 byte at the end + } else { + /* This is the real conversion of the raw camera data to BGR for V4L */ + datalength -= iPix; // correct length for packet header + } + pData = cdata + iPix; // Skip packet header (1 or 10 bytes) + + if ( datalength > 0 ) { /* fail safe */ + // Consume data + PDEBUG(5, "Processing packet seq %d,length %d,totlength %d", + frame->last_packet, datalength, frame->totlength); + /* this copy consume input data from the isoc stream */ + memcpy(frame->highwater, pData, datalength); + frame->highwater += datalength; + totlen += datalength; + frame->totlength = totlen; + } else { + PDEBUG(5, "Drop packet seq %d,length %d,totlength %d", + frame->last_packet, datalength, frame->totlength); + } + } + + /* decode */ + memcpy (&frame->pictsetting,&spca50x->pictsetting,sizeof(struct pictparam)); + frame->pictsetting.force_rgb = 1; + frame->scanlength = frame->totlength; + + return spca50x_outpicture(frame); + +} + +/* + * search tag function for tv8532_grab() + */ +int search_tag(unsigned char *data, int len, int *seq, int *nextseq) +{ + int i; + + if ( len < TV8532_TAG_LEN ) return -1; + + for ( i = 0; i < len-TV8532_TAG_LEN; i++ ) { + if ( (data[i+1] == 0xff) && (data[i+2] == 0xff) ) { + if ( data[i] >= 0xbf ) { + /* camera firmware bug? */ + if ( (data[i]+1) == (data[i+3]+0x40) ) { + *seq = data[i]; + *nextseq = data[i+3]+0x40; + PDEBUG(3,"found tag seq:0x%02x next:0x%02x(0x%02x) at +%d",*seq,*nextseq,data[i+3],i); + return i; + } else if ( data[i+3] == 0x80 ) { + *seq = data[i]; + *nextseq = data[i+3]; + PDEBUG(3,"found tag seq:0x%02x next:0x%02x(0x%02x) at +%d",*seq,*nextseq,data[i+3],i); + return i; + } + } else { + if ( (data[i]+1) == data[i+3] ) { + *seq = data[i]; + *nextseq = data[i+3]; + PDEBUG(3,"found tag seq:0x%02x next:0x%02x at +%d",*seq,*nextseq,i); + return i; + } + } + } + } + return -1; +} + +/* + * XXX: coding now... + */ +int tv8532_grab(struct usb_spca50x *spca50x) +{ + unsigned char *cdata; //Pointer to buffer where we do store next packet + struct spca50x_frame *frame; //Pointer to frame data + int iPix; //Offset of pixel data in the ISO packet + int sequenceNumber, NextsequenceNumber; + int totlen = 0; + int datalength; + int dumpnum = 0; + int end_of_frame = 0; + struct usb_device *udev; + + PDEBUG(5,"packet size is %d\n", spca50x->packet_size); + if ( (spca50x->packet_size <= 0) || ( spca50x->packet_size > MAX_FRAME_SIZE_PER_DESC ) ) { + fprintf(stderr, "invalid packet_size %d\n", spca50x->packet_size); + return -1; + } + + udev = spca50x->dev; + if ( spca50x->curframe == -1 ) { + fprintf(stderr, "curframe = -1\n"); + return -1; + } + + end_of_frame = spca50x->hdrwidth * (spca50x->hdrheight+2); + PDEBUG(4,"expected recieve data size:%d",end_of_frame); + + spca50x->header_len = 0; + frame = &spca50x->frame[spca50x->curframe]; + + /* frame init */ + frame->highwater = frame->data; + frame->last_packet = -1; + frame->totlength = 0; + frame->grabstate = FRAME_UNUSED; + frame->scanstate = STATE_SCANNING; + + /* recieve isoc transfer data */ + datalength = 0; + cdata = isobuf; + for ( ;; ) { /* isoc transfer */ + datalength += read(udev->efd, (void *)cdata, spca50x->packet_size ); + PDEBUG(3,"read data size: %d(offset:%d)", datalength,cdata-isobuf); + if ( datalength <= 0 ) { + perror("read"); + if ( ++errnum > 5 ) { + return -1; + } + } + /* dump mode ? */ + if ( dumpflag != 0 ) { + PDEBUG (1, "Packet Dump(No.%d)", dumpnum); + if ( outputdump(isobuf, datalength, dumpnum) != 0 ) { + return -1; + } + dumpnum++; + if ( dumpnum >= DUMP_PACKETS ) { + return -1; + } + datalength = 0; + cdata = isobuf; + continue; + } + + if ( datalength < TV8532_TAG_LEN ) { + cdata += datalength; + continue; + } + + /* Are we in a frame? */ + while ( (iPix = search_tag(isobuf, datalength, + &sequenceNumber, &NextsequenceNumber)) >= 0 ) { + /* found tag */ + /* get data */ + if ( frame->scanstate == STATE_LINES ) { + if ( totlen + (iPix+TV8532_TAG_LEN) > MAX_FRAME_SIZE ) { + PDEBUG(2,"buffer overflow"); + return -1; + } + memcpy(frame->highwater, isobuf, iPix+TV8532_TAG_LEN); + frame->highwater += (iPix+TV8532_TAG_LEN); + totlen += (iPix+TV8532_TAG_LEN); + PDEBUG(3,"get data total size: %d (+%d)bytes", totlen, (iPix+TV8532_TAG_LEN)); + if ( totlen >= end_of_frame ) { + PDEBUG(1,"end of frame: totalsize:%d",totlen); + frame->grabstate = FRAME_DONE; + } + } + /* check sequence number */ + if ( (frame->last_packet != sequenceNumber) + && (frame->scanstate == STATE_LINES) ) { + /* packet drop! */ + PDEBUG (3, "Dropped packet 0x%02x(expected seq 0x%02x)", + sequenceNumber, frame->last_packet); + frame->last_packet = NextsequenceNumber; /* reset */ + } else { + if ( (NextsequenceNumber == TV8532_VSYNC_STA) && + (frame->last_packet != TV8532_VSYNC_STA-1) ) { + if ( frame->scanstate == STATE_SCANNING ) { + /* start of frame */ + PDEBUG(1,"start of frame"); + frame->scanstate = STATE_LINES; + frame->highwater = frame->data; + totlen = 0; + } + } + frame->last_packet = NextsequenceNumber; + } + /* shift buffer */ + PDEBUG(3,"buffer info: datalen:%d data: %d", datalength, cdata-isobuf); + if ( iPix + TV8532_TAG_LEN < datalength ) { + memcpy(isobuf, (isobuf+iPix+TV8532_TAG_LEN), + datalength - (iPix+TV8532_TAG_LEN)); + datalength -= (iPix+TV8532_TAG_LEN); + cdata = isobuf + datalength; + PDEBUG(3,"buffer info: datalen:%d data: %d", datalength, cdata-isobuf); + } else { + /* no buffer */ + datalength = 0; + cdata = isobuf; + PDEBUG(3,"buffer info: datalen:%d data: %d", datalength, cdata-isobuf); + } + } /* while */ + + /* get data without last 3(TV8532_PENDING_LEN) bytes */ + if ( frame->scanstate == STATE_LINES ) { + if ( datalength - TV8532_PENDING_LEN > 0 ) { + if ( totlen + (datalength - TV8532_PENDING_LEN) > MAX_FRAME_SIZE ) { + PDEBUG(2,"buffer overflow"); + return -1; + } + memcpy(frame->highwater, isobuf, (datalength - TV8532_PENDING_LEN)); + frame->highwater += (datalength - TV8532_PENDING_LEN); + totlen += (datalength - TV8532_PENDING_LEN); + PDEBUG(3,"get data total size: %d bytes(+%d)", totlen, + (datalength - TV8532_PENDING_LEN)); + } + } + /* shift buffer last 3(TV8532_PENDING_LEN) bytes */ + PDEBUG(3,"buffer info: datalen:%d data: %d", datalength, cdata-isobuf); + if ( datalength >= TV8532_PENDING_LEN ) { + memcpy(isobuf, (isobuf+datalength-TV8532_PENDING_LEN), TV8532_PENDING_LEN); + datalength = TV8532_PENDING_LEN; + cdata = isobuf + TV8532_PENDING_LEN; + } + PDEBUG(3,"buffer info: datalen:%d data: %d", datalength, cdata-isobuf); + if ( frame->grabstate == FRAME_DONE ) { + break; /* for ( ;; ) */ + } + } /* for ( ;; ) */ + + /* decode */ + memcpy (&frame->pictsetting,&spca50x->pictsetting,sizeof(struct pictparam)); + frame->pictsetting.force_rgb = 1; + frame->totlength = totlen; + frame->scanlength = frame->totlength; + + return spca50x_outpicture(frame); +} + +int outputdump(unsigned char *startp, int size, int seq) +{ + static FILE *oid; + unsigned char *curp; + + if ( seq == 0 ) { + if ( filename != NULL ) { + if ( (oid = fopen(filename, "wb")) == NULL ) { + perror("fopen"); + return -1; + } + } else { + oid = stdout; + } + } + + fprintf(oid, "--- No.%02d Len:%d\n" + "+0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +f\n", seq,size); + for ( curp = startp; (curp - startp) < size; ) { + fprintf(oid, "%02x ", *curp++); + if ( ((curp-startp) % 16) == 0 ) fprintf(oid, "\n"); + } + fprintf(oid, "\n"); + + if ( seq == DUMP_PACKETS-1 ) { + if ( filename != NULL ) { + fclose(oid); + } + return -1; + } + + return 0; +} + +double calc_framerate(struct timeval tv[], int lastnum, int *interval) +{ + int i; + long avetime, difftime; + +#define PREVNUM(num) ((((num)-1)<0)?(EXPOSURE_TIMES-1):((num)-1)) + + PDEBUG(4,"framerate calcuration start."); + i = lastnum; + avetime = difftime = 0L; + do { + /* diff time */ + if ( tv[PREVNUM(i)].tv_sec > tv[i].tv_sec ) { + /* previous time is future? */ + return (double)0; + } else { + difftime = (tv[i].tv_sec - tv[PREVNUM(i)].tv_sec) * 1000000L; + } + difftime = difftime + tv[i].tv_usec - tv[PREVNUM(i)].tv_usec; + PDEBUG(5, "num:%d-%d now:%ldsec:%ld prev:%ldsec:%ld difftime:%ld", + i, PREVNUM(i), + tv[i].tv_sec, tv[i].tv_usec, + tv[PREVNUM(i)].tv_sec, tv[PREVNUM(i)].tv_usec, + difftime); + avetime += difftime; + i = PREVNUM(i); + } while ( PREVNUM(i) != lastnum ); + + avetime /= (EXPOSURE_TIMES-1); + PDEBUG(4,"framerate calcuration end. avetime:%ld", avetime); + if ( interval != NULL ) { + *interval = avetime / 1000; + } + if ( avetime == 0 ) { + return (double)0; + } else { + return (double)1000000 / avetime; + } +} + +void displayinfo(struct usb_spca50x *spdev) +{ + struct video_capability vc; + struct video_picture vp; + + spca50x_do_ioctl(spcadev, VIDIOCGCAP, &vc); + printf("--- video capability ---\n"); + printf("name: %s", vc.name); + printf("type: %X\n", vc.type); + printf("channels: %d\n", vc.channels); + printf("maxwidth: %d\n", vc.maxwidth); + printf("maxheight: %d\n", vc.maxheight); + printf("minwidth: %d\n", vc.minwidth); + printf("minheight: %d\n", vc.minheight); + + printf("--- size and format ---\n"); + display_more_info(spcadev); + + memset(&vp, 0, sizeof(struct video_picture)); + spca50x_do_ioctl(spcadev, VIDIOCGPICT, &vp); + printf("--- video picture (initial value) ---\n"); + printf("brightness: %d\n", vp.brightness); + printf("hue: %d\n", vp.hue); + printf("colour: %d\n", vp.colour); + printf("contrast: %d\n", vp.contrast); + printf("whiteness: %d\n", vp.whiteness); + printf("depth: %d\n", vp.depth); + printf("palette: %d\n", vp.palette); + + return; +} + diff -urN spca5xx-20060402.orig/drivers/usb/spca5shot.1 spca5xx-20060402/drivers/usb/spca5shot.1 --- spca5xx-20060402.orig/drivers/usb/spca5shot.1 1970-01-01 09:00:00.000000000 +0900 +++ spca5xx-20060402/drivers/usb/spca5shot.1 2006-06-04 11:21:10.000000000 +0900 @@ -0,0 +1,141 @@ +.\"/*- +.\" * Copyright (c) 2005-2006 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 March 12, 2006 +.Dt spca5shot 1 +.Os +.Sh NAME +.Nm spca5shot +.Nd simple image capture program for SPCA5xx based usb cameras. +.Sh SYNOPSIS +.Nm spca5shot +.Op -d device +.Op -s NxN +.Op -o file +.Op -e times +.Op -a +.Op -t +.Op -i +.Op -h +.Op -S +.Op -j +.OP -c level +.OP -C level +.OP -W level +.OP -H level +.Op -D level +.Op -p +.Sh DESCRIPTION +.Nm +is a simple program to capture image frames for SPCA5xx based usb cameras. +.Pp +The following options are supported: +.Bl -tag -width indent +.It -d device +Specifies the device name by absolute path. 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 +.Bl -tag -width indent +.It -s NxN +Specifies the size of the output image frame. This option depends on chipset. +using -i option shows all valid size. +.El +.Bl -tag -width indent +.It -o file +Specify output file name instead of stdout. If file exist already, it is overwrited. +.El +.Bl -tag -width indent +.It -e times +Specify exposure time. Useful if images are too dark, used many times with the -a option. +.El +.Bl -tag -width indent +.It -a +Specify enable auto brightness support within chipset. default is disable. +This option depends on chipset. +.El +.Bl -tag -width indent +.It -t +Display average of frame capture rate, report based on last 10 frame captures. +.El +.Bl -tag -width indent +.It -i +Display information for the camera and exit, all other options will be ignored. +.El +.Bl -tag -width indent +.It -j +Specify output to be in Jpeg format. +.El +.Bl -tag -width indent +.It -c level +Specify contrast level, if support within chipset. +.El +.Bl -tag -width indent +.It -C level +Specify "color" level, if support within chipset. +.El +.Bl -tag -width indent +.It -W level +Specify "Whiteness" level, if support within chipset. +.El +.Bl -tag -width indent +.It -H level +Specify "Hue" level, if support within chipset. +.El +.Bl -tag -width indent +.It -S +Specify to output a MJpeg stream format (a stream Jpeg images with HTTP headers) simular or many webcams. +.El +.Bl -tag -width indent +.It -h +Display usage messages and exit. +.El +.Bl -tag -width indent +.It -D level +Specify the level of debug message. level means as follow. + 0 no debug messages. + 1 init/detection/unload and other significant messages. + 2 some warning messages + 3 config/control function calls + 4 most function calls and data parsing messages + 5 highly repetitive mesgs +.El +.Bl -tag -width indent +.It -p +Specify dump isochronous packets. This options is for debug. +.El +.Sh EXAMPLES +spca5shot -s 352x288 \*[Gt] output.ppm +.Sh SEE ALSO +.Xr ugen 4 +.Xr spca5view 1 +.Sh WEBPAGE OF PORTING FOR BSD +http://www.medias.ne.jp/~takam/bsd/NetBSD.html#spca561 +.Sh REFERENCE +SPCA50X Linux Device Driver Project; http://spca50x.sourceforge.net/ +Michel Xhaard's Project; http://mxhaard.free.fr/index.html +.Sh AUTHORS +.An Mizuno Takafumi diff -urN spca5xx-20060402.orig/drivers/usb/spca5shot.c spca5xx-20060402/drivers/usb/spca5shot.c --- spca5xx-20060402.orig/drivers/usb/spca5shot.c 1970-01-01 09:00:00.000000000 +0900 +++ spca5xx-20060402/drivers/usb/spca5shot.c 2006-06-04 11:21:10.000000000 +0900 @@ -0,0 +1,558 @@ +/* + * usbcam based SPCA5xx Image Capture Program for NetBSD, version 0.6 + * spca5shot - Simple image capture program. + * Copyright (C) 2003-2006 Takafumi Mizuno + * + * Portions of this program were modeled after or adapted from the + * version 0.56 of the SPCA5xx video for linux (v4l) driver. + * SPCA5xx version by Michel Xhaard + * Based on : + * SPCA50x version by Joel Crisp + * OmniVision OV511 Camera-to-USB Bridge Driver + * Copyright (c) 1999-2000 Mark W. McClelland + * Kernel 2.6.x port Michel Xhaard && Reza Jelveh (feb 2004) + * and many people; see spca50x.c and ../../README and URL as follow; + * http://spca50x.sourceforge.net/ + * http://mxhaard.free.fr/ + * + * 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 /* basename */ +#include +#include +#include +#include +#include +#include + +#if defined(__DragonFly__) +#include +#else +#include +#endif + +#include "linux_usbif.h" +#include "spca5xx.h" +#include "spcadecoder.h" +#include "spca5shot.h" + +#ifndef DEFHEIGHT +#define DEFHEIGHT LOCAL_Y +#endif + +#ifndef DEFWIDTH +#define DEFWIDTH LOCAL_X +#endif + +#define IFNUM 0 +#define USEFRAMENUM 0 + +struct usb_device usbdev; +struct usb_spca50x *spcadev; + +char dev[FILENAME_MAX]; + +unsigned char isobuf[MAX_FRAME_SIZE_PER_DESC]; /* one raw isoc packets data */ + +int errnum = 0; +static int infflag = 0; +static int jpegout = 0; +static int abflag = 0; +static int timflag = 0; +static int quietflag = 0; +static int bcflag = 0; /* brightness/contrast */ +static int stream; +#define BFLAG 0x01 +#define CFLAG 0x02 +#define WFLAG 0x04 +#define HFLAG 0x08 +#define RFLAG 0x10 +static int extime = EXPOSURE_TIMES; + +static void outputppm(unsigned char *target, int x, int y, char *name); +static void outputraw(unsigned char *target, int length, char *name); + +void usage(char *pname) +{ + fprintf (stderr, + "Usage: %s [-d device] [-s NxN] [-o file] [-b brightness] [-c contrast] [-e time] [-a] [-t] [-i] [-h] [-D level] [-p]\n" + " -d device Specify the target device. Absolute path are accepted.\n" + " -s NxN Specify size of the output image. (default:%dx%d)\n" + " -o file Specify output file name instead of stdout.\n" + " -b brightness Specify the brightness. [0-65535]\n" + " -c contrast Specify the contrast. [0-65535]\n" + " -C colour Specify the colour. [0-65535]\n" + " -w whitenes Specify the whitenes. [0-65535]\n" + " -H hue Specify the hue. [0-65535]\n" + " -e times Specify exposure times. (default:%d)\n" + " -a Specify enable auto brightness with chipset support.\n" + " -t Display frame rate after output a image.\n" + " -i Display information of the camera without a output image.\n" + " -h Display usage. (this message)\n" + " -D level Specify the level of debug message. (0:default - 5:verbose)\n" + " -p Specify dump %d isoc packets. (for debug)\n" + " -S Stream images in a HTTP MJpeg stream.\n" +#ifdef __FreeBSD__ + "Example: %s -d /dev/ugen1\n", +#else + "Example: %s -d /dev/ugen1.00\n", +#endif + (char*)basename(pname), + LOCAL_X, LOCAL_Y, EXPOSURE_TIMES, DUMP_PACKETS, + (char*)basename(pname)); + exit (1); +} + +int ck_arg(char *arg, char *name) +{ +char *s; + + s = rindex(arg, '/'); + + if (s) { + s++; + } else { + s = arg; + } + if (strcmp(s, name) == 0) { + return 1; + } else { + return 0; + } +} + +int main(int argc, char *argv[]) +{ + int c,optmp; + int i = 0; + int ret = 0; + char *devname = NULL; + struct timeval tv[EXPOSURE_TIMES]; + int ti = 0; /* index of tv[] */ + struct video_mmap vm; + struct video_picture vp; + __u16 brightness = 0; + __u16 contrast = 0; + __u16 whiteness = 0; + __u16 hue = 0; + __u16 colour = 0; + + setlinebuf(stderr); setlinebuf(stdout); + + vm.height = DEFHEIGHT; + vm.width = DEFWIDTH; + + if (ck_arg(argv[0], "spca5stream")) { + stream = 1; + jpegout = 1; + quietflag = 1; + } else { + + /* + * check option + */ + while ((c = getopt(argc, argv, "ab:b:C:c:d:e:ijo:pqSs:tH:W:w:D:h")) != EOF) { + switch (c) { + case 'a': + abflag = 1; + break; + case 'b': + bcflag |= BFLAG; + optmp = atoi(optarg); + if ( optmp < 0 || optmp > 65535 ) { + usage(argv[0]); + } + brightness = (__u16)optmp; + break; + case 'c': + bcflag |= CFLAG; + optmp = atoi(optarg); + if ( optmp < 0 || optmp > 65535 ) { + usage(argv[0]); + } + contrast = (__u16)optmp; + break; + case 'C': + bcflag |= RFLAG; + optmp = atoi(optarg); + if ( optmp < 0 || optmp > 65535 ) { + usage(argv[0]); + } + colour = (__u16)optmp; + break; + case 'W': + case 'w': + bcflag |= WFLAG; + optmp = atoi(optarg); + if ( optmp < 0 || optmp > 65535 ) { + usage(argv[0]); + } + whiteness = (__u16)optmp; + break; + + case 'H': + bcflag |= HFLAG; + optmp = atoi(optarg); + if ( optmp < 0 || optmp > 65535 ) { + usage(argv[0]); + } + hue = (__u16)optmp; + break; + + case 'd': + devname = optarg; + break; + case 'e': + optmp = atoi(optarg); + if ( optmp < 0 ) { + usage(argv[0]); + } + extime = optmp; + break; + case 'i': + infflag = 1; + break; + case 'S': + stream = 1; + /* fall through */ + /* jpeg output assumed. */ + case 'j': + jpegout = 1; + break; + case 'o': + filename = optarg; + break; + case 'p': + dumpflag = 1; + break; + case 's': + if ( sscanf(optarg, "%dx%d", &vm.width, &vm.height) != 2 ) { + usage(argv[0]); + } + break; + case 't': + timflag = 1; + break; + case 'q': + quietflag = 1; + break; + case 'D': + optmp = atoi(optarg); + if ( optmp < 0 || optmp > 5 ) { + usage(argv[0]); + } + debug = optmp; + break; + case 'h': + case '?': + default: + usage(argv[0]); + break; + } + } + + if ( argc != optind ) { + usage(argv[0]); + } + } + + + if ( devname == NULL ) { + /* 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 ( (spcadev = (struct usb_spca50x *)spca5xx_probe(&usbdev, IFNUM)) == NULL ) { + close(usbdev.fd); + usbdev.fd = -1; + continue; + } else { + break; + } + } + } else { + if ( (usbdev.fd = open(devname, O_RDWR)) < 0 ) { + perror(devname); + } else { + if ( (spcadev = (struct usb_spca50x *)spca5xx_probe(&usbdev, IFNUM)) == NULL ) { + close(usbdev.fd); + usbdev.fd = -1; + } else { + (void)strcpy(dev, devname); + } + } + } + + if ( usbdev.fd < 0 ) { + fprintf(stderr, "Not found SPCA50x based usb camera, or Permission denied\n"); + exit(1); + } + + if ( spca5xx_open(spcadev) != 0 ) { + ret = 1; + goto OPENERR; + } + + /* get/set picture param */ + spca50x_do_ioctl(spcadev, VIDIOCGPICT, &vp); + if ( bcflag != 0 ) { + if ( (bcflag & BFLAG) != 0 ) { + vp.brightness = brightness; + } + if ( (bcflag & CFLAG) != 0 ) { + vp.contrast = contrast; + } + if ( (bcflag & WFLAG) != 0 ) { + vp.whiteness = whiteness; + } + if ( (bcflag & HFLAG) != 0 ) { + vp.hue = hue; + } + if ( (bcflag & RFLAG) != 0 ) { + vp.colour = colour; + } + spca50x_do_ioctl(spcadev, VIDIOCSPICT, &vp); + } + + if ( infflag != 0 ) { + displayinfo(spcadev); + goto DO_CLOSE; + } + + vm.frame = USEFRAMENUM; + if (jpegout == 1) { + vm.format = VIDEO_PALETTE_JPEG; + } else { + vm.format = VIDEO_PALETTE_RGB24; + } + + if ( spca50x_do_ioctl(spcadev, VIDIOCMCAPTURE, &vm) != 0 ) { + ret = 1; + goto MODEINIERR; + } + + /* open endpoint */ +#ifdef __FreeBSD__ + sprintf(usbdev.epdevname, "%s.%d", dev, spcadev->endpoint_address); +#else + sprintf(usbdev.epdevname, "%s.%02d", strtok(dev,"."), spcadev->endpoint_address); +#endif + if ((usbdev.efd = open(usbdev.epdevname, O_RDONLY)) < 0) { + perror(usbdev.epdevname); + ret = 2; + goto EPOPENERR; + } + + memset((void *)isobuf, 0, MAX_FRAME_SIZE_PER_DESC); + if ( timflag != 0 ) { + for ( ti = 1; ti < EXPOSURE_TIMES; ti++) { + tv[ti].tv_sec = -1L; + tv[ti].tv_usec = -1L; + } + ti = 0; + gettimeofday(&tv[ti], NULL); /* tv[0] */ + } + + + + i=0; + c=0; + if (stream) { + // greet our client; + printf("HTTP/1.0 200 OK\r\n" + "Server: spca5 Web Server/1.0\r\n" + "Content-Type: multipart/x-mixed-replace;boundary=--IPCamBoundary--\r\n" + "MIME-version: 1.0\r\n" + "Pragma: no-cache\r\n" + "Cache-Control: no-cache\r\n" + "Expires: 01 Jan 1970 00:00:00 GMT\r\n" + "\r\n"); + + while(1) { + if ( spcadev->bridge == BRIDGE_TV8532 ) { + ret = tv8532_grab(spcadev); + } else { + ret = spca_grab(spcadev); + } + if ( abflag != 0 ) { + auto_bh((void *)spcadev); + } + if ( ret < 0 ) { + i++; + } else { + i=0; + } + /* break after 10 errors in a row */ + if ( i > 10 ) { + ret=1; + break; + } + printf( "--IPCamBoundary--\r\n" + "ETag: image_%06d\r\n" + "Content-Type: image/jpeg\r\n" + "Content-Length: %d\r\n" + "\r\n", + c++, + (int) spcadev->frame[USEFRAMENUM].scanlength ); + + ret = fwrite( spcadev->frame[USEFRAMENUM].data, + spcadev->frame[USEFRAMENUM].scanlength, 1, stdout); + + if (ret < 1) { + break; + ret=1; + } + } /* while 1 */ + } else { + for ( i = extime; i > 0; i-- ) { + if ( spcadev->bridge == BRIDGE_TV8532 ) { + ret = tv8532_grab(spcadev); + } else { + ret = spca_grab(spcadev); + } + if ( timflag != 0 ) { + ti = (ti + 1) % EXPOSURE_TIMES; + gettimeofday(&tv[ti], NULL); + } + if ( abflag != 0 ) { + auto_bh((void *)spcadev); + } + if ( ret < 0 ) { + ret=1; + break; + } + if (!quietflag) + fprintf(stderr, "exposure time: last %d \r", i); + + if (!quietflag) + fprintf(stderr, "brightness %d, colour %d, contrast %d, hue %d, whiteness %d\n", + spcadev->brightness, spcadev->colour, spcadev->contrast, spcadev->hue, + spcadev->whiteness); + } + + if ( i == 0 ) { + + if (jpegout == 1) { + outputraw(spcadev->frame[USEFRAMENUM].data, (int) spcadev->frame[USEFRAMENUM].scanlength, + filename); + } else { + outputppm(spcadev->frame[USEFRAMENUM].data, + spcadev->frame[USEFRAMENUM].width, spcadev->frame[USEFRAMENUM].height, + filename); + } + + + ret = 0; + if ( timflag != 0 ) { + if ( extime < EXPOSURE_TIMES ) { + fprintf(stderr, "frame rate: can not calculate. at lease exposure times must be more than %d, check -e option.\n", EXPOSURE_TIMES); + } else { + fprintf(stderr, "frame rate: %.2f(fps)\n", calc_framerate(tv, ti, NULL)); + } + } + + } else { + ret = 1; + } + } + + close(usbdev.efd); + +DO_CLOSE: +EPOPENERR: +MODEINIERR: + spca5xx_close(spcadev); +OPENERR: + spca5xx_disconnect(&usbdev, (void *)spcadev); + close(usbdev.fd); + if (!quietflag) + fprintf(stderr, "\nDone.\n"); + + return ret; +} + + +static void outputraw(unsigned char *target, int length, char *out) +{ + int i; + FILE *fid; + + if ( target == NULL ) return; + + if ( out != NULL ) { + if ( (fid = fopen(out, "wb")) == NULL ) { + perror("fopen"); + return; + } + } else { + /* stdout */ + fid = stdout; + } + + i = fwrite(target, length, 1, fid); + if (i < 1) { + fprintf(stderr, "wrote %d instead of %d", i, length); + perror("fwrite"); + return; + } + + if ( out != NULL ) { + fclose(fid); + } +} + +static void outputppm(unsigned char *target, int x, int y, char *out) +{ + int i; + FILE *fid; + + if ( target == NULL ) return; + + if ( out != NULL ) { + if ( (fid = fopen(out, "wb")) == NULL ) { + perror("fopen"); + return; + } + } else { + /* stdout */ + fid = stdout; + } + + fprintf(fid, "P6\n"); + fprintf(fid, "%d %d 255 ", x, y); + for ( i = 0; i < (x*y*3); i+=3 ) { + fprintf(fid, "%c%c%c", + target[i], + target[i+1], + target[i+2]); + } + + if ( out != NULL ) { + fclose(fid); + } + + return; +} + diff -urN spca5xx-20060402.orig/drivers/usb/spca5shot.h spca5xx-20060402/drivers/usb/spca5shot.h --- spca5xx-20060402.orig/drivers/usb/spca5shot.h 1970-01-01 09:00:00.000000000 +0900 +++ spca5xx-20060402/drivers/usb/spca5shot.h 2006-06-04 11:21:10.000000000 +0900 @@ -0,0 +1,64 @@ +#ifndef _INC_SPCA5SHOT_H_ +#define _INC_SPCA5SHOT_H_ + +#include "linux_usbif.h" +#include "spca5xx.h" + +#define LOCAL_X 352 +#define LOCAL_Y 288 + +#define EXPOSURE_TIMES 10 +#define DUMP_PACKETS 1000 + +/* from ../../Makefile */ +#define SPCA5XX_VERSION "20051105" + +/* message */ +#define err(fmt, args...) fprintf(stderr, fmt "\n", ## args) +#define info(fmt, args...) fprintf(stderr, fmt "\n", ## args) + +/* spca50x.c */ +void* spca5xx_probe(struct usb_device *dev, unsigned int ifnum); +int spca5xx_open(struct usb_spca50x *spca50x); +int spca5xx_close(struct usb_spca50x *spca50x); +void spca5xx_disconnect(struct usb_device *dev, void *ptr); +void auto_bh(void* data); +int spca50x_mode_init_regs(struct usb_spca50x *spca50x, + int width, int height, int mode, __u16 ext_modes [][6]); +int spca50x_do_ioctl(struct usb_spca50x *spca50x, unsigned int cmd, void *arg); + +void display_more_info(struct usb_spca50x *spca50x); /* BSD original */ + +extern int debug; +extern struct usb_device usbdev; +extern struct usb_spca50x *spcadev; + +/* spca5share.c */ +extern int dumpflag; +extern char *filename; + +int spca_grab(struct usb_spca50x *spca50x); +int tv8532_grab(struct usb_spca50x *spca50x); +int outputdump(unsigned char *, int, int); +void displayinfo(struct usb_spca50x *spdev); +double calc_framerate(struct timeval tv[], int lastnum, int *interval); + +/* for spca506.h */ +#define VIDEO_MODE_PAL 0 +#define VIDEO_MODE_NTSC 1 +#define VIDEO_MODE_SECAM 2 +#define VIDEO_MODE_AUTO 3 + +/* for zc3xx.h */ +#define udelay(d) usleep(1) + +#ifdef REQ_SPCA5VIEW +extern GdkImlibImage *get_new_frame(GdkImlibImage *); +extern void do_pushkey(int key); + +#define ERRNUM_LIMITS 9 +extern int errnum; +extern int vflag; +#endif /* REQ_SPCA5VIEW */ + +#endif /* _INC_SPCA5SHOT_H_ */ diff -urN spca5xx-20060402.orig/drivers/usb/spca5view.1 spca5xx-20060402/drivers/usb/spca5view.1 --- spca5xx-20060402.orig/drivers/usb/spca5view.1 1970-01-01 09:00:00.000000000 +0900 +++ spca5xx-20060402/drivers/usb/spca5view.1 2006-06-04 11:21:10.000000000 +0900 @@ -0,0 +1,122 @@ +.\"/*- +.\" * Copyright (c) 2005-2006 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 March 12, 2006 +.Dt spca5view 1 +.Os +.Sh NAME +.Nm spca5view +.Nd sequential image capture program for SPCA5xx based video cameras. +.Sh SYNOPSIS +.Nm spca5view +.Op -d device +.Op -s NxN +.Op -b brightness +.Op -c contrast +.Op -v +.Op -a +.Op -i +.Op -h +.Sh DESCRIPTION +.Nm +is a sequential image capture and view program for SPCA5xx based video cameras. +.Pp +The following options are supported: +.Bl -tag -width indent +.It -d device +Specifies the ugen device name by absolute path. 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 +.Bl -tag -width indent +.It -s NxN +Specifies the size of the output image frame. This option depends on chipset. +using spca5shot(1) with -i option shows all valid size. +.El +.Bl -tag -width indent +.It -b brightness +Specify the brightness between 0 and 65535. +.El +.Bl -tag -width indent +.It -c contrast +Specify the contrast between 0 and 65535. +.El +.Bl -tag -width indent +.It -v +Specify doing flip-flops image frame. default is none. +.El +.Bl -tag -width indent +.It -a +Specify enable auto brightness with chipset support. default is disable. +This option depends on chipset. +.El +.Bl -tag -width indent +.It -i +Display information of the camera with ignore other options. +.El +.Bl -tag -width indent +.It -h +Display usage messages. +.El +.Sh KEYBOARD CONTROL +.Bl -tag -width indent +.It [b] +increment the brightness +.El +.Bl -tag -width indent +.It [B] +decrement the brightness +.El +.Bl -tag -width indent +.It [c] +increment the contrast +.El +.Bl -tag -width indent +.It [C] +decrement the contrast +.El +.Bl -tag -width indent +.It [i] +display current picture setting +.El +.Bl -tag -width indent +.It [v] [SPC] +doing flip-flops the image frame +.El +.Bl -tag -width indent +.It [q] +quit this program +.El +.Sh SEE ALSO +.Xr ugen 4 +.Xr spca5shot 1 +.Sh WEBPAGE OF PORTING FOR BSD +http://www.medias.ne.jp/~takam/bsd/NetBSD.html#spca561 +.Sh REFERENCE +SPCA50X Linux Device Driver Project; http://spca50x.sourceforge.net/ +Michel Xhaard's Project; http://mxhaard.free.fr/index.html +.Sh AUTHORS +.An Mizuno Takafumi diff -urN spca5xx-20060402.orig/drivers/usb/spca5view.c spca5xx-20060402/drivers/usb/spca5view.c --- spca5xx-20060402.orig/drivers/usb/spca5view.c 1970-01-01 09:00:00.000000000 +0900 +++ spca5xx-20060402/drivers/usb/spca5view.c 2006-06-04 11:22:11.000000000 +0900 @@ -0,0 +1,430 @@ +/* + * usbcam based SPCA5xx Image Capture Program for NetBSD, version 0.6 + * spca5view - Sequential image capture program. + * Copyright (C) 2003-2006 Takafumi Mizuno + * + * Portions of this program were modeled after or adapted from the + * version 0.56 of the SPCA5xx video for linux (v4l) driver. + * SPCA5xx version by Michel Xhaard + * Based on : + * SPCA50x version by Joel Crisp + * OmniVision OV511 Camera-to-USB Bridge Driver + * Copyright (c) 1999-2000 Mark W. McClelland + * Kernel 2.6.x port Michel Xhaard && Reza Jelveh (feb 2004) + * and many people; see spca50x.c and ../../README and URL as follow; + * http://spca50x.sourceforge.net/ + * http://mxhaard.free.fr/ + * + * 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. */ + +/* + * Reference: Image Processing Program by Linux, author Iio Jun, ohmsha publishing + * ISBN:4-274-94623-1 ( Japanese Only! ) + */ + +#include +#include +#include +#include /* basename */ +#include +#include +#include +#include +#include +#include + +#if defined(__DragonFly__) +#include +#else +#include +#endif + +#include +#include + +#include "gui.h" + +#include "linux_usbif.h" +#include "spca5xx.h" +#include "spcadecoder.h" + +#define REQ_SPCA5VIEW +#include "spca5shot.h" + +struct usb_device usbdev; +struct usb_spca50x *spcadev; +struct video_mmap vm; +struct video_picture vp; + +#define IFNUM 0 +#define USEFRAMENUM 0 + +char dev[FILENAME_MAX]; + +unsigned char isobuf[MAX_FRAME_SIZE_PER_DESC]; /* one raw isoc packets data */ + +static int abflag = 0; +GdkImlibImage *get_new_frame(GdkImlibImage *); +void do_pushkey(int key); + +static int infflag = 0; +static int vflag = 0; /* virtical */ +static int bcflag = 0; /* brightness/contrast */ +#define BFLAG 0x01 +#define CFLAG 0x02 + +void usage(char *pname) +{ + fprintf (stderr, + "Usage: %s [-d device] [-s NxN] [-b brightness] [-c contrast] [-v] [-a] [-i] [-h]\n" + " -d device Specify the target device. Absolute path are accepted.\n" + " -s NxN Specify size of the output image. (default:%dx%d)\n" + " -b brightness Specify the brightness. [0-65535]\n" + " -c contrast Specify the contrast. [0-65535]\n" + " -v Specify doing flip-flops image frame. (default:none)\n" + " -a Specify enable auto brightness with chipset support.\n" + " -i Display information of the camera without a output image.\n" + " -h Display usage. (this message)\n" + "KeyBoard Control:\n" + " [b] increment the brightness\n" + " [B] decrement the brightness\n" + " [c] increment the contrast\n" + " [C] decrement the contrast\n" + " [i] display current picture setting\n" + " [v][SPC] doing flip-flops the image frame\n" + " [q] quit this program\n" +#ifdef __FreeBSD__ + "Example: %s -d /dev/ugen1\n", +#else + "Example: %s -d /dev/ugen1.00\n", +#endif + (char*)basename(pname), + LOCAL_X, LOCAL_Y, + (char*)basename(pname)); + exit (1); +} + +int main(int argc, char *argv[]) +{ + int c,optmp; + int i; + int ret = 1; + char *devname = NULL; + struct video_picture local_vp; + + vm.height = LOCAL_Y; + vm.width = LOCAL_X; + + gtk_init(&argc, &argv); + gdk_imlib_init(); + + /* + * check option + */ + while ((c = getopt(argc, argv, "ab:c:d:is:hv")) != EOF) { + switch (c) { + case 'a': + abflag = 1; + break; + case 'b': + bcflag |= BFLAG; + optmp = atoi(optarg); + if ( optmp < 0 || optmp > 65535 ) { + usage(argv[0]); + } + local_vp.brightness = optmp; + break; + case 'c': + bcflag |= CFLAG; + optmp = atoi(optarg); + if ( optmp < 0 || optmp > 65535 ) { + usage(argv[0]); + } + local_vp.contrast = optmp; + break; + case 'd': + devname = optarg; + break; + case 'i': + infflag = 1; + break; + case 's': + if ( sscanf(optarg, "%dx%d", &vm.width, &vm.height) != 2 ) { + usage(argv[0]); + } + break; + case 'v': + vflag = 1; + break; + case 'h': + case '?': + default: + usage(argv[0]); + break; + } + } + if ( argc != optind ) { + usage(argv[0]); + } + + if ( devname == NULL ) { + /* 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 ( (spcadev = (struct usb_spca50x *)spca5xx_probe(&usbdev, IFNUM)) == NULL ) { + close(usbdev.fd); + usbdev.fd = -1; + continue; + } else { + break; + } + } + } else { + if ( (usbdev.fd = open(devname, O_RDWR)) < 0 ) { + perror(devname); + } else { + if ( (spcadev = (struct usb_spca50x *)spca5xx_probe(&usbdev, IFNUM)) == NULL ) { + close(usbdev.fd); + usbdev.fd = -1; + } else { + (void)strcpy(dev, devname); + } + } + } + + if ( usbdev.fd < 0 ) { + fprintf(stderr, "Not found target usb camera, or Permission denied\n"); + exit(1); + } + + if ( spca5xx_open(spcadev) != 0 ) { + ret = 1; + goto OPENERR; + } + + /* get/set picture param */ + spca50x_do_ioctl(spcadev, VIDIOCGPICT, &vp); + if ( bcflag != 0 ) { + if ( (bcflag & BFLAG) != 0 ) { + vp.brightness = local_vp.brightness; + } + if ( (bcflag & CFLAG) != 0 ) { + vp.contrast = local_vp.contrast; + } + spca50x_do_ioctl(spcadev, VIDIOCSPICT, &vp); + } + + if ( infflag != 0 ) { + displayinfo(spcadev); + goto DO_CLOSE; + } + + vm.frame = USEFRAMENUM; + vm.format = VIDEO_PALETTE_RGB24; + if ( spca50x_do_ioctl(spcadev, VIDIOCMCAPTURE, &vm) != 0 ) { + ret = 1; + goto MODEINIERR; + } + + /* open endpoint */ +#ifdef __FreeBSD__ + sprintf(usbdev.epdevname, "%s.%d", dev, spcadev->endpoint_address); +#else + sprintf(usbdev.epdevname, "%s.%02d", strtok(dev,"."), spcadev->endpoint_address); +#endif + if ((usbdev.efd = open(usbdev.epdevname, O_RDONLY)) < 0) { + perror(usbdev.epdevname); + ret = 2; + goto EPOPENERR; + } + + /* image clear */ + memset((void *)isobuf, 0, MAX_FRAME_SIZE_PER_DESC); + + gui_config(); + gtk_main(); + + fprintf(stderr, "Closing ....."); + close(usbdev.efd); + ret = 0; + +DO_CLOSE: +EPOPENERR: +MODEINIERR: + spca5xx_close(spcadev); +OPENERR: + spca5xx_disconnect(&usbdev, (void *)spcadev); + close(usbdev.fd); + fprintf(stderr, "\nDone.\n"); + + return ret; +} + +void do_pushkey(int key) +{ +#define UPDOWNUNIT 512 + switch ( key ) { + case 'b': + if ( vp.brightness < 65535-UPDOWNUNIT ) { + vp.brightness += UPDOWNUNIT; + } else { + vp.brightness=65535; + } + spca50x_do_ioctl(spcadev, VIDIOCSPICT, &vp); + printf("brightness:%5d\n", vp.brightness); + break; + case 'B': + if ( vp.brightness > UPDOWNUNIT ) { + vp.brightness -= UPDOWNUNIT; + } else { + vp.brightness=0; + } + spca50x_do_ioctl(spcadev, VIDIOCSPICT, &vp); + printf("brightness:%5d\n", vp.brightness); + break; + case 'c': + if ( vp.contrast < 65535-UPDOWNUNIT ) { + vp.contrast += UPDOWNUNIT; + } else { + vp.contrast = 65535; + } + spca50x_do_ioctl(spcadev, VIDIOCSPICT, &vp); + printf("contrast:%5d\n", vp.contrast); + break; + case 'C': + if ( vp.contrast > UPDOWNUNIT ) { + vp.contrast -= UPDOWNUNIT; + } else { + vp.contrast = 0; + } + spca50x_do_ioctl(spcadev, VIDIOCSPICT, &vp); + printf("contrast:%5d\n", vp.contrast); + break; + case 'h': + if ( vp.hue < 65534 ) { + vp.hue += 1; + } else { + vp.hue = 65535; + } + spca50x_do_ioctl(spcadev, VIDIOCSPICT, &vp); + printf("hue:%5d\n", vp.hue); + break; + case 'H': + if ( vp.hue > 1 ) { + vp.hue -= 1; + } else { + vp.hue = 0; + } + spca50x_do_ioctl(spcadev, VIDIOCSPICT, &vp); + printf("hue:%5d\n", vp.hue); + break; + case 'o': + if ( vp.colour < 65534 ) { + vp.colour += 1; + } else { + vp.colour = 65535; + } + spca50x_do_ioctl(spcadev, VIDIOCSPICT, &vp); + printf("colour:%5d\n", vp.colour); + break; + case 'O': + if ( vp.colour > 1 ) { + vp.colour -= 1; + } else { + vp.colour = 0; + } + spca50x_do_ioctl(spcadev, VIDIOCSPICT, &vp); + printf("colour:%5d\n", vp.colour); + break; + case 'w': + if ( vp.whiteness < 65534 ) { + vp.whiteness += 1; + } else { + vp.whiteness = 65535; + } + spca50x_do_ioctl(spcadev, VIDIOCSPICT, &vp); + printf("whiteness:%5d\n", vp.whiteness); + break; + case 'W': + if ( vp.whiteness > 1 ) { + vp.whiteness -= 1; + } else { + vp.whiteness = 0; + } + spca50x_do_ioctl(spcadev, VIDIOCSPICT, &vp); + printf("whiteness:%5d\n", vp.whiteness); + break; + case 'i': + spca50x_do_ioctl(spcadev, VIDIOCGPICT, &vp); + printf("\n--- video picture ---\n"); + printf("brightness: %d\n", vp.brightness); + printf("hue: %d\n", vp.hue); + printf("colour: %d\n", vp.colour); + printf("contrast: %d\n", vp.contrast); + printf("whiteness: %d\n", vp.whiteness); + printf("depth: %d\n", vp.depth); + printf("palette: %d\n", vp.palette); + break; + case 'v': + case ' ': + vflag = (vflag + 1) % 2; + break; + default: + break; + } + + return; +} + + +/* Read raw-data from camera and convert to RGB24 + */ +GdkImlibImage *get_new_frame(GdkImlibImage *current) +{ + GdkImlibImage *im = NULL; + struct usb_spca50x *spca50x = spcadev; + + if ( spca50x->bridge == BRIDGE_TV8532 ) { + tv8532_grab(spca50x); + } else { + spca_grab(spca50x); + } + + + /* autobrightness */ + if ( abflag != 0 ) { + auto_bh((void *)spca50x); + } + + if (current) gdk_imlib_kill_image(current); + im = gdk_imlib_create_image_from_data( + spca50x->frame[USEFRAMENUM].data, NULL, + spca50x->frame[USEFRAMENUM].width, spca50x->frame[USEFRAMENUM].height); + + if (vflag) { + gdk_imlib_flip_image_horizontal(im); + gdk_imlib_flip_image_vertical(im); + } + + return im; +} + diff -urN spca5xx-20060402.orig/drivers/usb/spca5xx.c spca5xx-20060402/drivers/usb/spca5xx.c --- spca5xx-20060402.orig/drivers/usb/spca5xx.c 2006-04-03 04:33:50.000000000 +0900 +++ spca5xx-20060402/drivers/usb/spca5xx.c 2006-06-04 11:21:10.000000000 +0900 @@ -33,46 +33,25 @@ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -static const char version[] = SPCA5XX_VERSION; - - -#include -#include -#include -#include - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include +/* Those sources are applied patch for *BSD */ +#include "spca5shot.h" -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) -/* only on 2.6.x */ -#include -#endif +static const char version[] = SPCA5XX_VERSION; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) -#include -#endif -#include +#include +#include +#include +#include +#include +#include -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9) -#include +#if defined(__DragonFly__) +#include +#else +#include #endif +#include "linux_usbif.h" #include "spca5xx.h" #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) @@ -106,10 +85,12 @@ /* Hardware auto exposure / whiteness (PC-CAM 600) */ static int autoexpo = 1; +#if 0 /* BSD patch */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,5) /* Video device number (-1 is first available) */ static int video_nr = -1; #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,5) */ +#endif /* BSD patch */ /* 0=no debug messages * 1=init/detection/unload and other significant messages, @@ -119,7 +100,7 @@ * 5=highly repetitive mesgs * NOTE: This should be changed to 0, 1, or 2 for production kernels */ -static int debug = 0; +int debug = 0; /* Force image to be read in RGB instead of BGR. This option allow * programs that expect RGB data (e.g. gqcam) to work with this driver. */ @@ -131,13 +112,15 @@ static int GRed = 256; static int GBlue = 256; static int GGreen = 256; +/* Number of seconds before inactive buffers are deallocated */ +/* static int buf_timeout = 5; BSD patch */ static int usbgrabber = 0; #ifdef SPCA50X_ENABLE_COMPRESSION /* Enable compression. This is for experimentation only; compressed images * still cannot be decoded yet. */ -static int compress = 0; +int compress = 0; #endif /* SPCA50X_ENABLE_COMPRESSION */ #ifdef SPCA5XX_ENABLE_REGISTERPLAY @@ -147,8 +130,8 @@ #endif /* SPCA5XX_ENABLE_REGISTERPLAY */ /* Initial brightness & contrast (for debug purposes) */ -static int bright = 0x80; -static int contrast = 0x60; +//static int bright = 0x80; +//static int contrast = 0x60; /* Parameter that enables you to set the minimal suitable bpp */ static int min_bpp = 0; @@ -257,12 +240,13 @@ MODULE_LICENSE("GPL"); - +void auto_bh(void* data); +#if 0 /* BSD patch */ static int spca50x_move_data(struct usb_spca50x *spca50x, struct urb *urb); - -static struct usb_driver spca5xx_driver; +static struct usb_driver spca50x_driver; +#endif /* BSD patch */ #ifndef max static inline int max(int a, int b) @@ -643,6 +627,7 @@ {-1, NULL} }; +#if 0 /* BSD patch */ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) static __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x0733, 0x0430)}, /* Intel PC Camera Pro */ @@ -820,6 +805,7 @@ #else /* LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) */ #define VIRT_TO_PAGE MAP_NR #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) */ +#endif /* BSD patch */ /* * Let's include the initialization data for each camera type */ @@ -1075,7 +1061,8 @@ }; #endif /* CONFIG_PROC_FS */ -/* function for the tasklet */ +#if 0 /* BSD patch */ +/* function for the tasklets */ void outpict_do_tasklet(unsigned long ptr); @@ -1229,6 +1216,7 @@ vfree(mem); } +#endif /* BSD patch */ /********************************************************************** * /proc interface @@ -1552,9 +1540,14 @@ static int spca50x_set_packet_size(struct usb_spca50x *spca50x, int size) { int alt; + int ep_index; /* for BSD */ + struct usb_interface_desc *interface; /* for BSD */ + struct usb_endpoint_desc *endpoint; /* for BSD */ + /**********************************************************************/ /******** Try to find real Packet size from usb struct ****************/ struct usb_device *dev = spca50x->dev; +#if 0 /* BSD patch */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) struct usb_interface_descriptor *interface = NULL; @@ -1563,6 +1556,7 @@ struct usb_host_interface *interface = NULL; struct usb_interface *intf; #endif +#endif /* BSD patch */ int mysize = 0; int ep = 0; @@ -1615,6 +1609,7 @@ ep = SPCA50X_ENDPOINT_ADDRESS - 1; } +#if 0 /* BSD patch */ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,3) intf = usb_ifnum_to_if(dev, spca50x->iface); if (intf) { @@ -1636,8 +1631,47 @@ mysize = (interface->endpoint[ep].wMaxPacketSize); #endif #endif +#endif /* BSD patch */ + + /* get real packet size routine for BSD */ + + interface = &(dev->interfacedesc); + interface->uid_config_index = USB_CURRENT_CONFIG_INDEX; + interface->uid_interface_index = spca50x->iface; + interface->uid_alt_index = alt; + if (ioctl(dev->fd, USB_GET_INTERFACE_DESC, interface) < 0) { + perror("spca50x_set_packet_size:USB_GET_INTERFACE_DESC"); + return -ENXIO; + } + + endpoint = &(dev->endpointdesc); + for ( ep_index = 0; ep_index < interface->uid_desc.bNumEndpoints; ep_index++ ) { + endpoint->ued_config_index = USB_CURRENT_CONFIG_INDEX; + endpoint->ued_interface_index = spca50x->iface; + endpoint->ued_alt_index = USB_CURRENT_ALT_INDEX; + endpoint->ued_endpoint_index = ep_index; + if (ioctl(dev->fd, USB_GET_ENDPOINT_DESC, endpoint) < 0) { + perror("spca50x_set_packet_size:USB_GET_ENDPOINT_DESC"); + return -ENXIO; + } + if ( ( endpoint->ued_desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK ) != + USB_ENDPOINT_XFER_ISOC ) { + continue; + } + if ( ( endpoint->ued_desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK ) == USB_DIR_OUT ) { + continue; + } + mysize = UGETW(endpoint->ued_desc.wMaxPacketSize); + break; + } + if ( ep_index == interface->uid_desc.bNumEndpoints ) { + PDEBUG(0, "Not found ISO endpoint!"); + return -ENXIO; + } + spca50x->endpoint_address = ep_index+1; /* help for BSD */ + PDEBUG(4, "MaxPacketSize %d: EndpointAddress %d", mysize, spca50x->endpoint_address); - spca50x->packet_size = mysize & 0x03ff; + spca50x->packet_size = mysize; spca50x->alt = alt; PDEBUG(1, "set real packet size: %d, alt=%d", mysize, alt); return 0; @@ -1681,6 +1715,7 @@ } } +#if 0 /* BSD patch */ /********************************************************************** * spca50x_isoc_irq * Function processes the finish of the USB transfer by calling @@ -1747,6 +1782,7 @@ return; } +#endif /* BSD patch */ /********************************************************************** @@ -1943,20 +1979,22 @@ static int spca50x_init_isoc(struct usb_spca50x *spca50x) { - struct urb *urb; - int fx, err, n; - int intpipe; + /* struct urb *urb; */ + /* int fx, err, n; */ + /* int intpipe; */ PDEBUG(3, "*** Initializing capture ***"); /* reset iso context */ - spca50x->compress = compress; + /* spca50x->compress = compress; BSD patch */ spca50x->curframe = 0; - spca50x->cursbuf = 0; + /* spca50x->cursbuf = 0; BSD patch */ spca50x->frame[0].seq = -1; spca50x->lastFrameRead = -1; spca50x_set_packet_size(spca50x, spca50x->pipe_size); PDEBUG(2, "setpacketsize %d", spca50x->pipe_size); +#if 0 /* BSD patch */ + for (n = 0; n < SPCA50X_NUMSBUF; n++) { #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL); @@ -1999,7 +2037,9 @@ for (n = 0; n < SPCA50X_NUMSBUF - 1; n++) spca50x->sbuf[n].urb->next = spca50x->sbuf[n + 1].urb; #endif +#endif /* BSD patch */ spcaCameraStart(spca50x); +#if 0 /* BSD patch */ if (spca50x->bridge == BRIDGE_SONIX) { intpipe = usb_rcvintpipe(spca50x->dev, 3); usb_clear_halt(spca50x->dev, intpipe); @@ -2023,6 +2063,7 @@ spca50x->frame[n].grabstate = FRAME_UNUSED; spca50x->frame[n].scanstate = STATE_SCANNING; } +#endif /* BSD patch */ spca50x->streaming = 1; @@ -2038,7 +2079,7 @@ ***********************************************************************/ static void spca5xx_kill_isoc(struct usb_spca50x *spca50x) { - int n; +// int n; if (!spca50x) return; @@ -2046,6 +2087,7 @@ PDEBUG(3, "*** killing capture ***"); spca50x->streaming = 0; +#if 0 /* BSD patch */ /* Unschedule all of the iso td's */ for (n = SPCA50X_NUMSBUF - 1; n >= 0; n--) { if (spca50x->sbuf[n].urb) { @@ -2058,6 +2100,7 @@ spca50x->sbuf[n].urb = NULL; } } +#endif /* BSD patch */ PDEBUG(3, "*** Isoc killed ***"); } @@ -2123,7 +2166,7 @@ if (spca50x->mode_cam[i].method == 0 && spca50x->mode_cam[i].width) { spca50x->width = spca50x->mode_cam[i].width; spca50x->height = spca50x->mode_cam[i].height; - spca50x->method = 0; + spca50x->method = spca50x->mode_cam[i].method; spca50x->pipe_size = spca50x->mode_cam[i].pipe; spca50x->mode = spca50x->mode_cam[i].mode; return 0; @@ -2584,7 +2627,7 @@ out: return r; } -static int +int spca50x_mode_init_regs(struct usb_spca50x *spca50x, int width, int height, int mode, __u16 ext_modes[][6]) @@ -2830,7 +2873,7 @@ } - +#if 0 /* BSD patch */ /********************************************************************** * * SPCA50X data transfer, IRQ handler @@ -2979,6 +3022,10 @@ return jiffies_to_msecs(times_now); #endif } +#endif /* BSD patch */ + +#if 0 /* BSD patch */ + /* ****************************************************************** * spca50x_move_data @@ -3332,7 +3379,7 @@ if (sof) { sequenceNumber = 0; -#if 1 +#if 0 spin_lock(&spca50x->v4l_lock); spca50x->avg_lum = cdata[p+9] ; spin_unlock(&spca50x->v4l_lock); @@ -3475,6 +3522,15 @@ } return totlen; } +#endif /* BSD patch */ + +void auto_bh(void* data) +{ + struct usb_spca50x *spca50x = (struct usb_spca50x*)data; + + autobrightness(spca50x); + spca50x->bh_requested = 0; /* bottom half process finished */ +} /**************************************************************************** @@ -3507,7 +3563,7 @@ sizeof(struct pictparam)); PDEBUG(4, "frame[%d] @ %p", i, spca50x->frame[i].data); } - +#if 0 /* BSD patch */ for (i = 0; i < SPCA50X_NUMSBUF; i++) { spca50x->sbuf[i].data = kmalloc(FRAMES_PER_DESC * MAX_FRAME_SIZE_PER_DESC, @@ -3516,6 +3572,8 @@ goto error; PDEBUG(4, "sbuf[%d] @ %p", i, spca50x->sbuf[i].data); } +#endif /* BSD patch */ + spca50x->buf_state = BUF_ALLOCATED; out: up(&spca50x->buf_lock); @@ -3523,6 +3581,7 @@ return 0; error: /* FIXME: IMHO, it's better to move error deallocation code here. */ +#if 0 /* BSD patch */ for (i = 0; i < SPCA50X_NUMSBUF; i++) { @@ -3531,6 +3590,7 @@ spca50x->sbuf[i].data = NULL; } } +#endif /* BSD patch */ if (spca50x->fbuf) { rvfree(spca50x->fbuf, SPCA50X_NUMFRAMES * MAX_DATA_SIZE); spca50x->fbuf = NULL; @@ -3563,12 +3623,14 @@ spca50x->tmpBuffer = NULL; } +#if 0 /* BSD patch */ for (i = 0; i < SPCA50X_NUMSBUF; i++) { if (spca50x->sbuf[i].data) { kfree(spca50x->sbuf[i].data); spca50x->sbuf[i].data = NULL; } } +#endif /* BSD patch */ PDEBUG(2, "buffer memory deallocated"); spca50x->buf_state = BUF_NOT_ALLOCATED; @@ -3863,22 +3925,16 @@ static inline void spca5xx_chgDtimes(struct usb_spca50x *spca50x, __u16 dtimes) { - unsigned long flags; - spin_lock_irqsave(&spca50x->v4l_lock, flags); + /* unsigned long flags; BSD patch */ + /* spin_lock_irqsave(&spca50x->v4l_lock, flags); BSD patch */ spca50x->dtimes = (unsigned int) dtimes; - spin_unlock_irqrestore(&spca50x->v4l_lock, flags); + /* spin_unlock_irqrestore(&spca50x->v4l_lock, flags); BSD patch */ } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,22) -static int spca5xx_open(struct inode *inode, struct file *file) -{ - struct video_device *vdev = video_devdata(file); -#else -static int spca5xx_open(struct video_device *vdev, int flags) -{ -#endif - struct usb_spca50x *spca50x = video_get_drvdata(vdev); +/* changed for BSD */ +int spca5xx_open(struct usb_spca50x *spca50x) +{ int err; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) @@ -3912,9 +3968,6 @@ spca5xx_setFrameDecoder(spca50x); spca50x->user++; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,22) - file->private_data = vdev; -#endif err = spca50x_init_isoc(spca50x); if (err) { PDEBUG(0, " DEALLOC error on init_Isoc\n"); @@ -3922,9 +3975,6 @@ spca5xx_kill_isoc(spca50x); up(&spca50x->lock); spca5xx_dealloc(spca50x); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,22) - file->private_data = NULL; -#endif goto out2; } @@ -3941,10 +3991,6 @@ out: up(&spca50x->lock); out2: -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - if (err) - MOD_DEC_USE_COUNT; -#endif if (err) { PDEBUG(2, "Open failed"); @@ -3978,16 +4024,9 @@ } } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,22) -static int spca5xx_close(struct inode *inode, struct file *file) -{ - - struct video_device *vdev = file->private_data; -#else -static void spca5xx_close(struct video_device *vdev) -{ -#endif - struct usb_spca50x *spca50x = video_get_drvdata(vdev); +/* changed for BSD */ +int spca5xx_close(struct usb_spca50x *spca50x) + { int i; PDEBUG(2, "spca50x_close"); @@ -4013,14 +4052,7 @@ spca5xx_dealloc(spca50x); PDEBUG(2, "Release ressources done"); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - MOD_DEC_USE_COUNT; -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,22) - file->private_data = NULL; return 0; -#endif } static int @@ -4037,18 +4069,9 @@ return 0; } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,22) -static int -spca5xx_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, - void *arg) -{ - struct video_device *vdev = file->private_data; -#else -static int -spca5xx_ioctl(struct video_device *vdev, unsigned int cmd, void *arg) -{ -#endif - struct usb_spca50x *spca50x = video_get_drvdata(vdev); +/* changed for BSD */ +int spca50x_do_ioctl(struct usb_spca50x *spca50x, unsigned int cmd, void *arg) + { PDEBUG(2, "do_IOCtl: 0x%X", cmd); @@ -4058,12 +4081,7 @@ switch (cmd) { case VIDIOCGCAP: { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,22) struct video_capability *b = arg; -#else - struct video_capability j; - struct video_capability *b = &j; -#endif PDEBUG(2, "VIDIOCGCAP %p :", b); memset(b, 0, sizeof(struct video_capability)); @@ -4076,23 +4094,12 @@ b->minwidth = spca50x->minwidth; b->minheight = spca50x->minheight; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,22) - if (copy_to_user(arg, b, sizeof(struct video_capability))) - return -EFAULT; -#endif return 0; } case VIDIOCGCHAN: { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,22) struct video_channel *v = arg; -#else - struct video_channel k; - struct video_channel *v = &k; - if (copy_from_user(v, arg, sizeof(struct video_channel))) - return -EFAULT; -#endif switch (spca50x->bridge) { case BRIDGE_SPCA500: case BRIDGE_SPCA501: @@ -4148,10 +4155,6 @@ v->flags = 0; v->tuners = 0; v->type = VIDEO_TYPE_CAMERA; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,22) - if (copy_to_user(arg, v, sizeof(struct video_channel))) - return -EFAULT; -#endif return 0; } @@ -4163,14 +4166,7 @@ of video_channel is an int channel number and we just ignore the rest */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,22) struct video_channel *v = arg; -#else - struct video_channel k; - struct video_channel *v = &k; - if (copy_from_user(v, arg, sizeof(struct video_channel))) - return -EFAULT; -#endif /* exclude hardware channel reserved */ if ((v->channel < 0) || (v->channel > 9) || (v->channel == 4) || (v->channel == 5)) @@ -4184,12 +4180,7 @@ } case VIDIOCGPICT: { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,22) struct video_picture *p = arg; -#else - struct video_picture p1; - struct video_picture *p = &p1; -#endif p->depth = spca50x->frame[0].depth; p->palette = spca50x->format; @@ -4327,24 +4318,12 @@ } } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,22) - if (copy_to_user(arg, p, sizeof(struct video_picture))) - return -EFAULT; -#endif - return 0; } case VIDIOCSPICT: { int i; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,22) struct video_picture *p = arg; -#else - struct video_picture p1; - struct video_picture *p = &p1; - if (copy_from_user(p, arg, sizeof(struct video_picture))) - return -EFAULT; -#endif PDEBUG(4, "VIDIOCSPICT"); @@ -4574,14 +4553,7 @@ case VIDIOCSWIN: { int result; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,22) struct video_window *vw = arg; -#else - struct video_window vw1; - struct video_window *vw = &vw1; - if (copy_from_user(vw, arg, sizeof(struct video_window))) - return -EFAULT; -#endif PDEBUG(3, "VIDIOCSWIN: width=%d, height=%d, flags=%d", vw->width, vw->height, vw->flags); @@ -4632,12 +4604,7 @@ } case VIDIOCGWIN: { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,22) struct video_window *vw = arg; -#else - struct video_window vw1; - struct video_window *vw = &vw1; -#endif memset(vw, 0, sizeof(struct video_window)); vw->x = 0; @@ -4647,21 +4614,12 @@ vw->flags = 0; PDEBUG(4, "VIDIOCGWIN: %dx%d", vw->width, vw->height); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,22) - if (copy_to_user(arg, vw, sizeof(struct video_capture))) - return -EFAULT; -#endif return 0; } case VIDIOCGMBUF: { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,22) struct video_mbuf *vm = arg; -#else - struct video_mbuf vm1; - struct video_mbuf *vm = &vm1; -#endif int i; PDEBUG(2, "VIDIOCGMBUF: %p ", vm); memset(vm, 0, sizeof(struct video_mbuf)); @@ -4671,24 +4629,13 @@ for (i = 0; i < SPCA50X_NUMFRAMES; i++) { vm->offsets[i] = MAX_DATA_SIZE * i; } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,22) - if (copy_to_user(arg, vm, sizeof(struct video_mbuf))) - return -EFAULT; -#endif return 0; } case VIDIOCMCAPTURE: { int ret, depth; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,22) struct video_mmap *vm = arg; -#else - struct video_mmap vm1; - struct video_mmap *vm = &vm1; - if (copy_from_user(vm, arg, sizeof(struct video_mmap))) - return -EFAULT; -#endif PDEBUG(4, "CMCAPTURE"); PDEBUG(4, "CM frame: %d, size: %dx%d, format: %d", @@ -4715,9 +4662,15 @@ err("VIDIOCMCAPTURE: requested dimensions too small"); return -EINVAL; } - if(spca5xx_testPalSize(spca50x,vm->format,vm->width,vm->height) < 0) - return -EINVAL; - + switch (spca50x->bridge) { /* BSD quick hack FIXME */ + case BRIDGE_TV8532: + case BRIDGE_CX11646: + break; + default: + if(spca5xx_testPalSize(spca50x,vm->format,vm->width,vm->height) < 0) + return -EINVAL; + break; + } /* * If we are grabbing the current frame, let it pass */ @@ -4816,13 +4769,7 @@ case VIDIOCSYNC: { int ret; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,22) unsigned int frame = *((unsigned int *) arg); -#else - unsigned int frame; - if (copy_from_user((void *) &frame, arg, sizeof(int))) - return -EFAULT; -#endif PDEBUG(4, "syncing to frame %d, grabstate = %d", frame, @@ -4875,36 +4822,19 @@ } case VIDIOCGFBUF: { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,22) struct video_buffer *vb = arg; -#else - struct video_buffer vb1; - struct video_buffer *vb = &vb1; -#endif memset(vb, 0, sizeof(struct video_buffer)); vb->base = NULL; /* frame buffer not supported, not used */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,22) - if (copy_to_user(arg, vb, sizeof(struct video_buffer))) - return -EFAULT; -#endif return 0; } +#if 0 /* BSD patch */ case SPCAGVIDIOPARAM: { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,22) struct video_param *vp = arg; -#else - struct video_param vp1; - struct video_param *vp = &vp1; -#endif vp->autobright = (__u8) spca50x->autoexpo; vp->quality = (__u8) spca50x->qindex; vp->time_interval = (__u16) spca50x->dtimes; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,22) - if (copy_to_user(arg, vp, sizeof(struct video_param))) - return -EFAULT; -#endif return 0; } @@ -4934,6 +4864,7 @@ } return 0; } +#endif /* BSD patch */ /************************************/ case VIDIOCKEY: return 0; @@ -4951,12 +4882,13 @@ case VIDIOCSAUDIO: return -EINVAL; default: - return -ENOIOCTLCMD; + return -EINVAL; /* original is ENOIOCTLCMD. BSD patch */ } /* end switch */ return 0; } +#if 0 /* BSD patch */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,22) static int spca5xx_ioctl(struct inode *inode, struct file *file, unsigned int cmd, @@ -5177,6 +5109,7 @@ ioctl:spca5xx_ioctl }; #endif //KERNEL VERSION 2,4,22 +#endif /* BSD patch */ /**************************************************************************** * * SPCA50X configuration @@ -5480,7 +5413,7 @@ __u8 Data; - if (spca_set_interface(spca50x->dev, spca50x->iface, 0) < 0) { + if (usb_set_interface(spca50x->dev, spca50x->iface, 0) < 0) { err("Set packet size: set interface error"); goto error; } @@ -5492,7 +5425,7 @@ PDEBUG(5, "ClickSmart310 sync pipe %d altsetting %d ", spca50x->pipe_size, spca50x->alt); /* Windoze use pipe with altsetting 6 why 7 here */ - if (spca_set_interface(spca50x->dev, spca50x->iface, spca50x->alt) < 0) { + if (usb_set_interface(spca50x->dev, spca50x->iface, spca50x->alt) < 0) { err("Set packet size: set interface error"); goto error; @@ -8240,23 +8173,31 @@ default: goto error; } + info("\n"); /* XXX BSD patch */ return 0; error: return -ENODEV; } -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) -static int -spca5xx_probe(struct usb_interface *intf, const struct usb_device_id *id) -#else -static void *spca5xx_probe(struct usb_device *dev, unsigned int ifnum, - const struct usb_device_id *id) -#endif +/* changed for BSD */ +void *spca5xx_probe (struct usb_device *dev, unsigned int ifnum) { - struct usb_interface_descriptor *interface; + struct usb_interface_desc *interface; struct usb_spca50x *spca50x; + usb_device_descriptor_t ddesc; int err_probe; int i; + + + if (ioctl(dev->fd, USB_GET_DEVICE_DESC, &ddesc) < 0) { + perror("USB_GET_DEVICE_DESC"); + return NULL; + } + dev->descriptor.bNumConfigurations = ddesc.bNumConfigurations; + dev->descriptor.idVendor = UGETW(ddesc.idVendor); + dev->descriptor.idProduct = UGETW(ddesc.idProduct); + dev->descriptor.bcdDevice = UGETW(ddesc.bcdDevice); + #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) struct usb_device *dev = interface_to_usbdev(intf); #endif @@ -8268,7 +8209,15 @@ if (ifnum > 0) goto nodevice; - interface = &dev->actconfig->interface[ifnum].altsetting[0]; + /* Get the current alternate interface, adjust packet size */ + interface = &(dev->interfacedesc); + interface->uid_config_index = USB_CURRENT_CONFIG_INDEX; + interface->uid_interface_index = ifnum; + interface->uid_alt_index = 0; + if (ioctl(dev->fd, USB_GET_INTERFACE_DESC, interface) < 0) { + perror("USB_GET_INTERFACE_DESC"); + return NULL; + } /* Since code below may sleep, we use this as a lock */ MOD_INC_USE_COUNT; #else @@ -8292,7 +8241,7 @@ memset(spca50x, 0, sizeof(struct usb_spca50x)); spca50x->dev = dev; - spca50x->iface = interface->bInterfaceNumber; + spca50x->iface = interface->uid_desc.bInterfaceNumber; if ((err_probe = spcaDetectCamera(spca50x)) < 0) { err(" Devices not found !! "); /* FIXME kfree spca50x and goto nodevice */ @@ -8321,6 +8270,7 @@ err("Failed to configure camera"); goto error; } +#if 0 /* BSD patch */ /* Init video stuff */ spca50x->vdev = video_device_alloc(); if (!spca50x->vdev) @@ -8339,6 +8289,7 @@ err("video_register_device failed"); goto error; } +#endif /* BSD patch */ /* test on disconnect */ spca50x->present = 1; /* Workaround for some applications that want data in RGB @@ -8358,10 +8309,11 @@ MOD_DEC_USE_COUNT; return spca50x; #else - return 0; + return NULL; #endif error: +#if 0 /* BSD patch */ if (spca50x->vdev) { if (spca50x->vdev->minor == -1) video_device_release(spca50x->vdev); @@ -8369,6 +8321,7 @@ video_unregister_device(spca50x->vdev); spca50x->vdev = NULL; } +#endif /* BSD patch */ if (spca50x) { kfree(spca50x); spca50x = NULL; @@ -8393,7 +8346,7 @@ { struct usb_spca50x *spca50x = usb_get_intfdata(intf); #else -static void spca5xx_disconnect(struct usb_device *dev, void *ptr) +void spca5xx_disconnect(struct usb_device *dev, void *ptr) { struct usb_spca50x *spca50x = (struct usb_spca50x *) ptr; #endif @@ -8429,6 +8382,7 @@ /* be sure close did not use &intf->dev ? */ dev_set_drvdata(&intf->dev, NULL); #endif +#if 0 /* BSD patch */ /* We don't want people trying to open up the device */ if (spca50x->vdev) video_unregister_device(spca50x->vdev); @@ -8438,6 +8392,7 @@ &spca50x->dev->actconfig-> interface[spca50x->iface]); #endif +#endif /* BSD patch */ spca50x->dev = NULL; up(&spca50x->lock); #ifdef CONFIG_PROC_FS @@ -8458,6 +8413,7 @@ } +#if 0 /* BSD patch */ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,22) static struct usb_driver spca5xx_driver = { #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16) @@ -8514,4 +8470,25 @@ module_init(usb_spca5xx_init); module_exit(usb_spca5xx_exit); +#endif /* BSD patch */ + +/* for BSD */ +void display_more_info(struct usb_spca50x *spca50x) +{ + int i; + + if ( spca50x == NULL ) return; + + printf("size: "); + for (i = 0; (GET_EXT_MODES(spca50x->bridge))[i][0] && + ((GET_EXT_MODES(spca50x->bridge))[i][0] > 0 && (GET_EXT_MODES(spca50x->bridge))[i][1] > 0); + i++) { + printf("%dx%d ", (GET_EXT_MODES(spca50x->bridge))[i][0], (GET_EXT_MODES(spca50x->bridge))[i][1]); + } + printf("\n"); + printf("native input format: %s\n", Plist[spca50x->cameratype].name); + printf("output format: %s\n", PALlist[spca50x->frame[0].format].name); + +} + //eof diff -urN spca5xx-20060402.orig/drivers/usb/spca5xx.h spca5xx-20060402/drivers/usb/spca5xx.h --- spca5xx-20060402.orig/drivers/usb/spca5xx.h 2006-01-13 23:01:11.000000000 +0900 +++ spca5xx-20060402/drivers/usb/spca5xx.h 2006-06-04 11:21:10.000000000 +0900 @@ -7,7 +7,10 @@ * SPCA50x version by Joel Crisp; all bugs are mine, all nice features are his. */ -#ifdef __KERNEL__ +/* Those sources are applied patch for *BSD */ +#include "linux_usbif.h" + +#if 0 /* BSD Patch */ #include #include #include @@ -18,6 +21,7 @@ #define urb_t struct urb #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20) */ +#endif /* BSD patch */ //static const char SPCA50X_H_CVS_VERSION[]="$Id: spca50x.h,v 1.28 2004/01/10 21:37:40 mxhaard Exp $"; @@ -26,6 +30,8 @@ #define VIDEO_PALETTE_RAW_JPEG 20 #define VIDEO_PALETTE_JPEG 21 +#define SPCA50X_ENABLE_DEBUG + #ifdef SPCA50X_ENABLE_DEBUG # define PDEBUG(level, fmt, args...) \ @@ -44,8 +50,8 @@ #define SPCA50X_ENDPOINT_ADDRESS 1 /* Isoc endpoint number */ #define PAC207_ENDPOINT_ADDRESS 5 /* Isoc endpoint number */ /* only 2 or 4 frames are allowed here !!! */ -#define SPCA50X_NUMFRAMES 2 -#define SPCA50X_NUMSBUF 2 +#define SPCA50X_NUMFRAMES 1 /* BSD patch */ +#define SPCA50X_NUMSBUF 1 /* BSD patch */ #define BRIDGE_SPCA505 0 #define BRIDGE_SPCA506 1 @@ -445,9 +451,14 @@ struct usb_spca50x { +#if 0 /* BSD patch */ struct video_device *vdev; struct usb_device *dev; /* Device structure */ struct tasklet_struct spca5xx_tasklet; /* use a tasklet per device */ +#endif /* BSD patch */ + struct usb_device *dev;/* BSD Device structure */ + struct tq_struct task; /* BSD task structure for scheduling bh */ + char bh_requested; /* BSD if bottom half processing requested */ struct dec_data maindecode; unsigned long last_times; //timestamp unsigned int dtimes; //nexttimes to acquire @@ -489,7 +500,10 @@ int cameratype; /* native in frame format */ struct pictparam pictsetting; /* Statistics variables */ - spinlock_t v4l_lock; /* lock to protect shared data between isoc and process context */ +#if 0 /* BSD patch */ + spinlock_t v4l_lock;/* lock to protect shared data between isoc and process context */ +#endif /* BSD patch */ + int v4l_lock; /* dummy BSD patch */ int avg_lum; //The average luminance (if available from theframe header) int avg_bg, avg_rg; //The average B-G and R-G for white balancing struct semaphore lock; @@ -504,8 +518,14 @@ char *fbuf; /* Videodev buffer area */ int curframe; /* Current receiving frame buffer */ struct spca50x_frame frame[SPCA50X_NUMFRAMES]; +#if 0 /* BSD patch */ int cursbuf; /* Current receiving sbuf */ struct spca50x_sbuf sbuf[SPCA50X_NUMSBUF]; +#endif /* BSD patch */ + + int endpoint_address; /* BSD Endpoint Address */ + struct timer_list buf_timer; /* BSD buf_timer */ + /* Temporary jpeg decoder workspace */ char *tmpBuffer; /* Framebuffer/sbuf management */ @@ -562,7 +582,4 @@ u8 common_L; }; -#endif /* __KERNEL__ */ - - #endif /* SPCA50X_H */ diff -urN spca5xx-20060402.orig/drivers/usb/spcadecoder.c spca5xx-20060402/drivers/usb/spcadecoder.c --- spca5xx-20060402.orig/drivers/usb/spcadecoder.c 2006-01-29 02:54:27.000000000 +0900 +++ spca5xx-20060402/drivers/usb/spcadecoder.c 2006-06-04 12:46:36.000000000 +0900 @@ -589,7 +589,7 @@ unsigned short word; int row; /* skip header */ - inp += 16; + inp += 16+1023; /* and ask to go at pixel +1 ?? */ outp++; @@ -598,6 +598,7 @@ word = getShort(inp); switch (word) { case 0x0FF0: + case 0x00FF: memcpy(outp, inp + 2, width); inp += (2 + width); break; @@ -606,8 +607,9 @@ break; default: - - return -1; + memcpy(outp, inp + 2, width); + inp += (3 + width); +// return -1; } outp += width; } diff -urN spca5xx-20060402.orig/drivers/usb/spcausb.h spca5xx-20060402/drivers/usb/spcausb.h --- spca5xx-20060402.orig/drivers/usb/spcausb.h 2006-01-13 23:01:11.000000000 +0900 +++ spca5xx-20060402/drivers/usb/spcausb.h 2006-06-04 11:21:10.000000000 +0900 @@ -40,8 +40,10 @@ __u16 reg, __u16 value, __u16 index, __u8 * buffer, __u16 length); +#if 0 /* Patch BSD */ static int spca_set_interface(struct usb_device *dev, int interface, int alternate); +#endif /* Patch BSD */ /* static int spca_clear_feature(struct usb_device *dev, int endpoint) @@ -258,6 +260,7 @@ } return; } +#if 0 /* Patch BSD */ static int spca_set_interface(struct usb_device *dev, int interface, int alternate) { @@ -288,6 +291,7 @@ return 0; } +#endif /* Patch BSD */ static int spca50x_reg_write(struct usb_device *dev, __u16 reg, __u16 index, __u16 value)