diff -ruN linux/drivers/usb.org/Config.in linux/drivers/usb/Config.in --- linux/drivers/usb.org/Config.in Tue Sep 3 23:59:14 2002 +++ linux/drivers/usb/Config.in Tue Sep 3 23:55:33 2002 @@ -79,6 +79,7 @@ dep_tristate ' USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB $CONFIG_VIDEO_DEV dep_tristate ' USB Philips Cameras' CONFIG_USB_PWC $CONFIG_USB $CONFIG_VIDEO_DEV dep_tristate ' USB SE401 Camera support' CONFIG_USB_SE401 $CONFIG_USB $CONFIG_VIDEO_DEV + dep_tristate ' USB SE402 and EP800 Camera support' CONFIG_USB_EPCAM $CONFIG_USB $CONFIG_VIDEO_DEV dep_tristate ' USB STV680 (Pencam) Camera support' CONFIG_USB_STV680 $CONFIG_USB $CONFIG_VIDEO_DEV dep_tristate ' USB 3com HomeConnect (aka vicam) support (EXPERIMENTAL)' CONFIG_USB_VICAM $CONFIG_USB $CONFIG_VIDEO_DEV $CONFIG_EXPERIMENTAL dep_tristate ' D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB $CONFIG_VIDEO_DEV $CONFIG_EXPERIMENTAL diff -ruN linux/drivers/usb.org/Makefile linux/drivers/usb/Makefile --- linux/drivers/usb.org/Makefile Tue Sep 3 23:58:54 2002 +++ linux/drivers/usb/Makefile Tue Sep 3 23:54:00 2002 @@ -80,6 +80,7 @@ obj-$(CONFIG_USB_VICAM) += vicam.o obj-$(CONFIG_USB_OV511) += ov511.o obj-$(CONFIG_USB_SE401) += se401.o +obj-$(CONFIG_USB_EPCAM) += epcam.o obj-$(CONFIG_USB_STV680) += stv680.o obj-$(CONFIG_USB_PEGASUS) += pegasus.o obj-$(CONFIG_USB_RTL8150) += rtl8150.o diff -ruN linux/drivers/usb.org/epcam.c linux/drivers/usb/epcam.c --- linux/drivers/usb.org/epcam.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/usb/epcam.c Tue Sep 10 22:05:40 2002 @@ -0,0 +1,1621 @@ +/* + * Endpoints EPCAM USB Camera Driver + * + * Copyright (c) 2001 Jeroen B. Vreeken (pe1rxq@amsat.org) + * + * Based on the se401 driver, which in turn is based on the ov511 driver. + * + * 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. + * + * + * Thanks to Endpoints Inc. (www.endpoints.com) for making documentation on + * their chips available and sending me two reference boards. + * - Jeroen Vreeken + */ + +static const char version[] = "0.05"; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "epcam.h" + +static int video_nr=-1; + +static struct usb_device_id device_table [] = { + { USB_DEVICE(0x03e8, 0x1005), driver_info:(unsigned long)"Endpoints EP800" },/* Reference model*/ + { USB_DEVICE(0x03e8, 0x1003), driver_info:(unsigned long)"Endpoints SE402" },/* Reference model*/ + { USB_DEVICE(0x03e8, 0x1000), driver_info:(unsigned long)"Endpoints SE401" },/* Reference model*/ + { USB_DEVICE(0x03e8, 0x2112), driver_info:(unsigned long)"SpyPen Actor" }, + { USB_DEVICE(0x03e8, 0x2040), driver_info:(unsigned long)"Rimax Slim Multicam" }, + { USB_DEVICE(0x041e, 0x400d), driver_info:(unsigned long)"Creative PD1001" }, + { USB_DEVICE(0x04f2, 0xa001), driver_info:(unsigned long)"Chicony DC-100" }, + { } +}; + + +MODULE_AUTHOR("Jeroen Vreeken "); +MODULE_DESCRIPTION("EPcam USB Camera Driver"); +MODULE_PARM(video_nr, "i"); +MODULE_DEVICE_TABLE(usb, device_table); +EXPORT_NO_SYMBOLS; + + +static struct usb_driver epcam_driver; + + +/********************************************************************** + * + * Memory management + * + **********************************************************************/ + +/* Here we want the physical address of the memory. + * This is used when initializing the contents of the area. + */ +static inline unsigned long kvirt_to_pa(unsigned long adr) +{ + unsigned long kva, ret; + + kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); + kva |= adr & (PAGE_SIZE-1); /* restore the offset */ + ret = __pa(kva); + return ret; +} + +static void *rvmalloc(unsigned long size) +{ + void *mem; + unsigned long adr; + + size = PAGE_ALIGN(size); + mem = vmalloc_32(size); + if (!mem) + return NULL; + + memset(mem, 0, size); /* Clear the ram out, no junk to the user */ + adr = (unsigned long) mem; + while (size > 0) { + mem_map_reserve(vmalloc_to_page((void *)adr)); + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + + return mem; +} + +static void rvfree(void *mem, unsigned long size) +{ + unsigned long adr; + + if (!mem) + return; + + adr = (unsigned long) mem; + while ((long) size > 0) { + mem_map_unreserve(vmalloc_to_page((void *)adr)); + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + vfree(mem); +} + + + +/**************************************************************************** + * + * /proc interface + * + ***************************************************************************/ + +#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) + +static struct proc_dir_entry *epcam_proc_entry = NULL; +extern struct proc_dir_entry *video_proc_entry; + +#define YES_NO(x) ((x) ? "yes" : "no") + +static int epcam_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + char *out = page; + int len; + struct usb_epcam *epcam = data; + + /* Stay under PAGE_SIZE or else bla bla bla.... */ + + out+=sprintf(out, "driver_version : %s\n", version); + out+=sprintf(out, "model : %s\n", epcam->camera_name); + out+=sprintf(out, "in use : %s\n", YES_NO (epcam->user)); + out+=sprintf(out, "streaming : %s\n", YES_NO (epcam->streaming)); + + out+=sprintf(out, "button state : %s\n", YES_NO (epcam->button)); + out+=sprintf(out, "button pressed : %s\n", YES_NO (epcam->buttonpressed)); + if (epcam->buttonpressed) + epcam->buttonpressed--; + + out+=sprintf(out, "num_frames : %d\n", EPCAM_NUMFRAMES); + out+=sprintf(out, "maximum-width : %d\n", epcam->maxwidth); + out+=sprintf(out, "maximum-height : %d\n", epcam->maxheight); + out+=sprintf(out, "Packets dropped : %d\n", epcam->dropped); + out+=sprintf(out, "Packets corrupt : %d\n", epcam->datacorrupt); + out+=sprintf(out, "Frames total : %d\n", epcam->readcount); + out+=sprintf(out, "Frames read : %d\n", epcam->framecount); + out+=sprintf(out, "Frames cancelled: %d\n", epcam->cancel); + out+=sprintf(out, "Que underruns : %d\n", epcam->underrun); + + len = out - page; + len -= off; + if (len < count) { + *eof = 1; + if (len <= 0) return 0; + } else + len = count; + + *start = page + off; + + return len; +} + +static int epcam_write_proc(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + return -EINVAL; +} + +static void create_proc_epcam_cam (struct usb_epcam *epcam) +{ + char name[7]; + struct proc_dir_entry *ent; + + if (!epcam_proc_entry || !epcam) + return; + + sprintf (name, "video%d", epcam->vdev.minor); + + ent = create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR, + epcam_proc_entry); + + if (!ent) + return; + + ent->data = epcam; + ent->read_proc = epcam_read_proc; + ent->write_proc = epcam_write_proc; + epcam->proc_entry = ent; +} + +static void destroy_proc_epcam_cam (struct usb_epcam *epcam) +{ + /* One to much, just to be sure :) */ + char name[9]; + + if (!epcam || !epcam->proc_entry) + return; + + sprintf(name, "video%d", epcam->vdev.minor); + remove_proc_entry(name, epcam_proc_entry); + epcam->proc_entry = NULL; +} + +static void proc_epcam_create (void) +{ + if (video_proc_entry == NULL) { + err("/proc/video/ doesn't exist"); + return; + } + + epcam_proc_entry=create_proc_entry("epcam", S_IFDIR, video_proc_entry); + + if (epcam_proc_entry) + epcam_proc_entry->owner = THIS_MODULE; + else + err("Unable to initialize /proc/video/epcam"); +} + +static void proc_epcam_destroy(void) +{ + if (epcam_proc_entry == NULL) + return; + + remove_proc_entry("epcam", video_proc_entry); +} +#endif /* CONFIG_PROC_FS && CONFIG_VIDEO_PROC_FS */ + + +/**************************************************************************** + * + * epcam register read/write functions + * + ***************************************************************************/ + +static int epcam_sndctrl(int set, struct usb_epcam *epcam, unsigned short req, + unsigned short value, unsigned char *cp, int size) +{ + return usb_control_msg ( + epcam->dev, + set ? usb_sndctrlpipe(epcam->dev, 0) : usb_rcvctrlpipe(epcam->dev, 0), + req, + (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, + 0, + cp, + size, + HZ + ); +} + +static int epcam_set_feature(struct usb_epcam *epcam, unsigned short reg, + unsigned short value) +{ + unsigned char cp[2]; + INT2QT(value, cp); + return usb_control_msg ( + epcam->dev, + usb_sndctrlpipe(epcam->dev, 0), + VENDOR_REQ_EXT_FEATURE, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + reg, + 0, + cp, + 2, + HZ + ); +} + +static unsigned short epcam_get_feature(struct usb_epcam *epcam, + unsigned short reg) +{ + unsigned char cp[2]; + usb_control_msg ( + epcam->dev, + usb_rcvctrlpipe(epcam->dev, 0), + VENDOR_REQ_EXT_FEATURE, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + reg, + 0, + cp, + 2, + HZ + ); + return QT2INT(cp); +} + +static unsigned short epcam_read_bios(struct usb_epcam *epcam, + unsigned short address) +{ + unsigned char cp[2]; + usb_control_msg ( + epcam->dev, + usb_rcvctrlpipe(epcam->dev, 0), + VENDOR_REQ_BIOS, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + VENDOR_CMD_BIOS_READ, + address, + cp, + 2, + HZ + ); + return QT2INT(cp); +} + +/**************************************************************************** + * + * Camera control + * + ***************************************************************************/ + + +static int epcam_send_pict(struct usb_epcam *epcam) +{ + unsigned char cp[40]; + int size; + + if (epcam->brightness<4096) + epcam->brightness=4096; + + epcam_sndctrl(0, epcam, VENDOR_REQ_IMAGE_INFO, 0, cp, sizeof(cp)); + INT2QT(epcam->brightness>>5, cp+2); + size=QT2INT(cp); + if (size>40) + size=40; + epcam_sndctrl(1, epcam, VENDOR_REQ_IMAGE_INFO, 0, cp, size); + + return 0; +} + +static int epcam_recv_pict(struct usb_epcam *epcam) +{ + unsigned char cp[40]; + + epcam_sndctrl(0, epcam, VENDOR_REQ_IMAGE_INFO, 0, cp, sizeof(cp)); + epcam->brightness=QT2INT(cp+2)<<5; + + return 0; +} + +static int epcam_get_pict(struct usb_epcam *epcam, struct video_picture *p) +{ + epcam_recv_pict(epcam); + p->brightness=epcam->brightness; + p->whiteness=32768; + p->colour=65535; + p->contrast=65535; + p->hue=65535; + p->palette=epcam->palette; + p->depth=3; /* rgb24 */ + + return 0; +} + + +static int epcam_set_pict(struct usb_epcam *epcam, struct video_picture *p) +{ + if (p->palette != VIDEO_PALETTE_RGB24) { + epcam->palette=p->palette; + return 1; + } + + p->whiteness=32768; + p->colour=65535; + p->contrast=65535; + p->hue=65535; + epcam->brightness=p->brightness; + epcam_send_pict(epcam); + return 0; +} + +/* + Hyundai have some really nice docs about this and other sensor related + stuff on their homepage: www.hei.co.kr +*/ +static void epcam_auto_resetlevel(struct usb_epcam *epcam) +{ + unsigned int ahrc, alrc; + int oldreset=epcam->resetlevel; + + /* For some reason these normally read-only registers don't get reset + to zero after reading them just once... + */ + epcam_get_feature(epcam, HV7131_REG_HIREFNOH); + epcam_get_feature(epcam, HV7131_REG_HIREFNOL); + epcam_get_feature(epcam, HV7131_REG_LOREFNOH); + epcam_get_feature(epcam, HV7131_REG_LOREFNOL); + ahrc=256*epcam_get_feature(epcam, HV7131_REG_HIREFNOH) + + epcam_get_feature(epcam, HV7131_REG_HIREFNOL); + alrc=256*epcam_get_feature(epcam, HV7131_REG_LOREFNOH) + + epcam_get_feature(epcam, HV7131_REG_LOREFNOL); + + /* Not an exact science, but it seems to work pretty well... */ + if (alrc > 10) { + while (alrc>=10 && epcam->resetlevel < 63) { + epcam->resetlevel++; + alrc /=2; + } + } else if (ahrc > 20) { + while (ahrc>=20 && epcam->resetlevel > 0) { + epcam->resetlevel--; + ahrc /=2; + } + } + if (epcam->resetlevel!=oldreset) + epcam_set_feature(epcam, HV7131_REG_ARLV, epcam->resetlevel); + + return; +} + +/* irq handler for snapshot button */ +static void epcam_button_irq(struct urb *urb) +{ + struct usb_epcam *epcam=urb->context; + int length=urb->actual_length; + + /* ohoh... */ + if (!urb) { + info ("ohoh: null urb"); + return; + } + if (!epcam->dev) { + info ("ohoh: device vapourished"); + return; + } + + if (length >=2 && !urb->status) { + if (epcam->button) + epcam->buttonpressed=1; + } +} + +static void epcam_video_irq(struct urb *urb) +{ + struct usb_epcam *epcam=urb->context; + int length=0, i; + + /* ohoh... */ + if (!epcam->streaming) { + return; + } + if (!urb) { + info ("ohoh: null urb"); + return; + } + if (!epcam->dev) { + info ("ohoh: device vapourished"); + return; + } + + /* 0 sized packets happen if we are to fast, but sometimes the camera + keeps sending them forever... + */ + if (urb->status && urb->status != USB_ST_BUFFERUNDERRUN) { + epcam->scratch_offset=0; + return; + } + switch(epcam->scratch[epcam->scratch_next].state) { + case BUFFER_READY: + case BUFFER_BUSY: { + epcam->dropped++; + break; + } + case BUFFER_UNUSED: { + for (i=0; iiso_frame_desc[i].actual_length) { + epcam->nullpackets=0; + memcpy( + epcam->scratch[epcam->scratch_next].data+length, + (unsigned char *)urb->transfer_buffer+urb->iso_frame_desc[i].offset, + urb->iso_frame_desc[i].actual_length); + length+=urb->iso_frame_desc[i].actual_length; + } + } + if (length) { + epcam->scratch[epcam->scratch_next].state=BUFFER_READY; + epcam->scratch[epcam->scratch_next].offset=epcam->scratch_offset; + epcam->scratch[epcam->scratch_next].length=length; + if (waitqueue_active(&epcam->wq)) + wake_up_interruptible(&epcam->wq); + epcam->scratch_overflow=0; + epcam->scratch_next++; + if (epcam->scratch_next>=EPCAM_NUMSCRATCH) + epcam->scratch_next=0; + } + } + } + + if (length) + epcam->scratch_offset++; + else + epcam->scratch_offset=0; + return; +} + +static void epcam_send_size(struct usb_epcam *epcam, int width, int height) +{ + unsigned char cp[40]; + int compress=0; + int size; + + epcam_sndctrl(0, epcam, VENDOR_REQ_AUTO_CONTROL, 1, NULL, 0); + + epcam->format=FMT_BAYER; + if (epcam->camid==0x800) { + /* Don't use compression on small images: camera goes crazy */ + if (width*height>=38400) { + compress=0x02; + epcam->format=FMT_EPLITE; + if (width <= epcam->maxwidth/2 && + height <= epcam->maxheight/2) { + width*=2; + height*=2; + compress|=0x80; + } + } + } + + info("vendor_req_capture_info: %d", epcam_sndctrl(0, epcam, VENDOR_REQ_CAPTURE_INFO, 0, cp, sizeof(cp))); + INT2QT(1, cp+2); + INT2QT(0, cp+4); + INT2QT(0, cp+6); + INT2QT((epcam->maxwidth-width)/2, cp+4); + INT2QT((epcam->maxheight-height)/2, cp+6); + INT2QT(width, cp+8); + INT2QT(height, cp+10); + size=QT2INT(cp); + if (size>40) + size=40; + epcam_sndctrl(1, epcam, VENDOR_REQ_CAPTURE_INFO, 0, cp, size); + info("vendor_req_capture_info: %d", epcam_sndctrl(0, epcam, VENDOR_REQ_CAPTURE_INFO, 0, cp, sizeof(cp))); + info("capture info size: %d", QT2INT(cp)); + info("mode : %d", QT2INT(cp+2)); + info("xstart : %d", QT2INT(cp+4)); + info("ystart : %d", QT2INT(cp+6)); + info("width : %d", QT2INT(cp+8)); + info("height : %d", QT2INT(cp+10)); + info("framerate: %d", QT2INT(cp+12)); + info("zoom : %d", QT2INT(cp+14)); + + info("vendor_req_compression: %d", epcam_sndctrl(0, epcam, VENDOR_REQ_COMPRESSION, 0, cp, sizeof(cp))); + INT2QT(compress, cp); + epcam_sndctrl(1, epcam, VENDOR_REQ_COMPRESSION, 0, cp, 2); + info("compression: %d", compress); + + return; +} + +/* + In this function epcam_send_pict is called several times, + for some reason (depending on the state of the sensor and the phase of + the moon :) doing this only in either place doesn't always work... +*/ +static int epcam_start_stream(struct usb_epcam *epcam) +{ + struct urb *urb; + int err=0, i, fx; + struct usb_interface_descriptor *interface; + struct usb_endpoint_descriptor *endpoint; + + + + /* Set the camera to Iso transfers */ + if (usb_set_interface(epcam->dev, epcam->iface, 4)< 0) { + info("interface set failed"); + return -1; + } + + epcam->streaming=1; + +info("interface set"); + interface=&epcam->dev->actconfig->interface[epcam->iface].altsetting[4]; + endpoint=&interface->endpoint[0]; + epcam->packetsize=endpoint->wMaxPacketSize; +info("packetsize: %d", epcam->packetsize); + + epcam_sndctrl(1, epcam, VENDOR_REQ_CAM_POWER, 1, NULL, 0); + epcam_sndctrl(1, epcam, VENDOR_REQ_LED_CONTROL, 1, NULL, 0); +info("led and power on"); + /* Set picture settings */ + + epcam_send_pict(epcam); + + epcam_send_size(epcam, epcam->cwidth, epcam->cheight); + + + epcam_sndctrl(1, epcam, VENDOR_REQ_CONT_CAPTURE, 1, NULL, 0); +info("capture on"); + /* Do some memory allocation */ + for (i=0; iframe[i].data=epcam->fbuf + i * epcam->maxframesize; + epcam->frame[i].curpix=0; + } + for (i=0; isbuf[i].data=kmalloc(epcam->packetsize*EPCAM_PACKETBUFS, GFP_KERNEL); + } + + epcam->scratch_offset=0; + epcam->lastoffset=-1; + epcam->scratch_next=0; + epcam->scratch_use=0; + epcam->scratch_overflow=0; + for (i=0; iscratch[i].data=kmalloc(epcam->packetsize*EPCAM_PACKETBUFS, GFP_KERNEL); + epcam->scratch[i].state=BUFFER_UNUSED; + } + + for (i=0; idev=epcam->dev; + urb->context=epcam; + urb->pipe=usb_rcvisocpipe(epcam->dev, EPCAM_VIDEO_ENDPOINT); + urb->transfer_flags=USB_ISO_ASAP; + urb->transfer_buffer=epcam->sbuf[i].data; + urb->complete=epcam_video_irq; + urb->number_of_packets=EPCAM_PACKETBUFS; + urb->transfer_buffer_length=epcam->packetsize*EPCAM_PACKETBUFS; + for (fx=0; fxiso_frame_desc[fx].offset=epcam->packetsize*fx; + urb->iso_frame_desc[fx].length=epcam->packetsize; + } + epcam->urb[i]=urb; + } + for (i=0; iurb[i]->next=epcam->urb[i+1]; + } + epcam->urb[EPCAM_NUMSBUF-1]->next=epcam->urb[0]; + for (i=0; iurb[i]); + if(err) + err("urb burned down"); + } +info("urbs flying!"); + epcam_set_feature(epcam, HV7131_REG_ARLV, epcam->resetlevel); + + return 0; +} + +static int epcam_stop_stream(struct usb_epcam *epcam) +{ + int i; + + if (!epcam->streaming || !epcam->dev) + return 1; + + epcam->streaming=0; + + for (i=0; iurb[i]) { + epcam->urb[i]->next=NULL; + usb_unlink_urb(epcam->urb[i]); + usb_free_urb(epcam->urb[i]); + epcam->urb[i]=NULL; + kfree(epcam->sbuf[i].data); + } + for (i=0; iscratch[i].data); + epcam->scratch[i].data=NULL; + } + epcam_sndctrl(1, epcam, VENDOR_REQ_CONT_CAPTURE, 0, NULL, 0); + epcam_sndctrl(1, epcam, VENDOR_REQ_LED_CONTROL, 0, NULL, 0); + epcam_sndctrl(1, epcam, VENDOR_REQ_CAM_POWER, 0, NULL, 0); + + return 0; +} + +static int epcam_set_size(struct usb_epcam *epcam, int width, int height) +{ + int wasstreaming=epcam->streaming; + + /* Check to see if we need to change */ + if (epcam->cwidth==width && epcam->cheight==height) + return 0; + + /* Check for a valid mode */ + if (width<=0 || height<=0) + return 1; + if ((width & 1) || (height & 1)) + return 1; + if (width>epcam->maxwidth) + return 1; + if (height>epcam->maxheight) + return 1; + + /* Stop a current stream and start it again at the new size */ + if (wasstreaming) + epcam_stop_stream(epcam); + epcam->cwidth=width; + epcam->cheight=height; + if (wasstreaming) + epcam_start_stream(epcam); + + return 0; +} + + +/**************************************************************************** + * + * Video Decoding + * + ***************************************************************************/ + +static inline void decode_bayer (struct usb_epcam *epcam, unsigned char *data, int len) +{ + int datasize=epcam->cwidth*epcam->cheight; + struct epcam_frame *frame=&epcam->frame[epcam->curframe]; + + unsigned char *framedata=frame->data, *curline, *nextline; + int width=epcam->cwidth; + int blineoffset=0, bline; + int linelength=width*3, i; + + + /* Check if we have to much data */ + if (frame->curpix+len > datasize) { + info("to much! %d %d %d %d", datasize, frame->curpix, len, frame->curpix+len-datasize); +// frame->curpix=0; +// return; + len=datasize-frame->curpix; + } + + if (frame->curpix==0) { + if (frame->grabstate==FRAME_READY) { + frame->grabstate=FRAME_GRABBING; + } + /* Clear stuff the user might have put on this line */ + memset(framedata+datasize*3-linelength, 0, linelength); + frame->curline=framedata+linelength; + frame->curlinepix=0; + } + + if (epcam->cheight%4) + blineoffset=1; + bline=frame->curpix/epcam->cwidth+blineoffset; + + curline=frame->curline; + nextline=curline+linelength; + if (nextline >= framedata+datasize*3) + nextline=curline; + while (len) { + if (frame->curlinepix>=width) { + frame->curlinepix-=width; + bline=frame->curpix/width+blineoffset; + curline+=linelength*2; + nextline+=linelength*2; + if (curline >= framedata+datasize*3) { + frame->curlinepix++; + curline-=3; + nextline-=3; + len--; + data++; + frame->curpix++; + } + if (nextline >= framedata+datasize*3) + nextline=curline; + } + if ((bline&1)) { + if ((frame->curlinepix&1)) { + *(curline+2)=*data; + *(curline-1)=*data; + *(nextline+2)=*data; + *(nextline-1)=*data; + } else { + *(curline+1)= + (*(curline+1)+*data)/2; + *(curline-2)= + (*(curline-2)+*data)/2; + *(nextline+1)=*data; + *(nextline-2)=*data; + } + } else { + if ((frame->curlinepix&1)) { + *(curline+1)= + (*(curline+1)+*data)/2; + *(curline-2)= + (*(curline-2)+*data)/2; + *(nextline+1)=*data; + *(nextline-2)=*data; + } else { + *curline=*data; + *(curline-3)=*data; + *nextline=*data; + *(nextline-3)=*data; + } + } + frame->curlinepix++; + curline-=3; + nextline-=3; + len--; + data++; + frame->curpix++; + } + frame->curline=curline; + + if (frame->curpix>=datasize-epcam->packetsize) { + /* Fix the top line */ + framedata+=linelength; + for (i=0; icheight; i++) { + *framedata=*(framedata+3); + *(framedata+1)=*(framedata+4); + *(framedata+2)=*(framedata+5); + framedata+=linelength; + } + frame->curpix=0; + frame->grabstate=FRAME_DONE; + epcam->framecount++; + epcam->readcount++; + if (epcam->frame[(epcam->curframe+1)&(EPCAM_NUMFRAMES-1)].grabstate==FRAME_READY) { + epcam->curframe=(epcam->curframe+1) & (EPCAM_NUMFRAMES-1); + } + } +} + +static inline void decode_eplite_integrate(struct usb_epcam *epcam, int data) +{ + int linelength=epcam->cwidth; + int i; + + /* First two are absolute, all others relative. + */ + if (epcam->eplite_curpix < 2) { + *(epcam->eplite_data+epcam->eplite_curpix)=1+data*4; + } else { + *(epcam->eplite_data+epcam->eplite_curpix)=i= + *(epcam->eplite_data+epcam->eplite_curpix-2)+data*4; + if (i>255 || i<0) { + epcam->lastoffset=-1; + epcam->datacorrupt++; + } + } + + epcam->eplite_curpix++; + + if (epcam->eplite_curpix>=linelength) { + decode_bayer(epcam, epcam->eplite_data, linelength); + + epcam->eplite_curpix=0; + epcam->eplite_curline+=linelength; + if (epcam->eplite_curline>=epcam->cheight*linelength) + epcam->eplite_curline=0; + } +} + +static inline void decode_eplite (struct usb_epcam *epcam, struct epcam_scratch *buffer) +{ + int i; + + unsigned char *data=buffer->data; + int len=buffer->length; + struct epcam_frame *frame=&epcam->frame[epcam->curframe]; + + int pos=0; + int vlc_cod; + int vlc_size; + int vlc_data; + int bit_cur; + + int bit; + + /* Check for cancelled frames: */ + for (i=0; icancel++; + frame->curpix=0; + return; + } + } + + /* New image? */ + if (!buffer->offset) { + frame->curpix=0; + } + if (!frame->curpix) { + epcam->eplite_curline=0; + epcam->eplite_curpix=0; + epcam->vlc_cod=0; + epcam->vlc_data=0; + epcam->vlc_size=0; + if (frame->grabstate==FRAME_READY) + frame->grabstate=FRAME_GRABBING; + } + + vlc_cod=epcam->vlc_cod; + vlc_size=epcam->vlc_size; + vlc_data=epcam->vlc_data; + + while (pos < len && frame->grabstate==FRAME_GRABBING) { + bit_cur=8; + while (bit_cur) { + bit=((*data)>>(bit_cur-1))&1; + if (!vlc_cod) { + if (bit) { + vlc_size++; + } else { + if (!vlc_size) { + decode_eplite_integrate(epcam, 0); + } else { + vlc_cod=2; + vlc_data=0; + } + } + } else { + if (vlc_size > 7) { + epcam->datacorrupt++; + epcam->lastoffset=-1; + return; + } + if (vlc_cod==2) { + if (!bit) vlc_data=-(1<grabstate==FRAME_GRABBING) { + epcam->vlc_size=vlc_size; + epcam->vlc_cod=vlc_cod; + epcam->vlc_data=vlc_data; + } else { + /* If there is data left regard image as corrupt */ + if (len-pos > epcam->packetsize) { + info("len-pos: %d\n", len-pos); + frame->grabstate=FRAME_GRABBING; + epcam->datacorrupt++; + } + epcam->lastoffset=-1; + } + +} + +static int epcam_newframe(struct usb_epcam *epcam, int framenr, int noblock) +{ + DECLARE_WAITQUEUE(wait, current); + int errors=0; + int process; + + if (epcam->framecount%64==8) + epcam_auto_resetlevel(epcam); + + while (epcam->streaming && + (epcam->frame[framenr].grabstate==FRAME_READY || + epcam->frame[framenr].grabstate==FRAME_GRABBING) ) { + if(!epcam->frame[framenr].curpix) { + errors++; + } + wait_interruptible( + epcam->scratch[epcam->scratch_use].state!=BUFFER_READY, + noblock, + &epcam->wq, + &wait + ); + if (epcam->nullpackets > EPCAM_MAX_NULLPACKETS) { + epcam->nullpackets=0; + info("to many null length packets, restarting capture"); + epcam_stop_stream(epcam); + epcam_start_stream(epcam); + } else { + struct epcam_scratch *buffer=&epcam->scratch[epcam->scratch_use]; + unsigned char *data=epcam->scratch[epcam->scratch_use].data; + int len=epcam->scratch[epcam->scratch_use].length; + struct epcam_frame *frame=&epcam->frame[epcam->curframe]; + + if (epcam->scratch[epcam->scratch_use].state!=BUFFER_READY) { + epcam->frame[framenr].grabstate=FRAME_ERROR; + return -EIO; + } + epcam->scratch[epcam->scratch_use].state=BUFFER_BUSY; + + process=1; + /* Check if we lost packets in the que */ + if ( buffer->offset!=epcam->lastoffset+1) { + epcam->underrun++; + epcam->lastoffset=-1; + process=0; + } else { + epcam->lastoffset=buffer->offset; + } + + /* New image? */ + if (!buffer->offset) { + frame->curpix=0; + } + + if (process) { + if (epcam->format==FMT_EPLITE) { + decode_eplite(epcam, &epcam->scratch[epcam->scratch_use]); + } else { + decode_bayer(epcam, data, len); + } + } + + epcam->scratch[epcam->scratch_use].state=BUFFER_UNUSED; + epcam->scratch_use++; + if (epcam->scratch_use>=EPCAM_NUMSCRATCH) + epcam->scratch_use=0; + if (errors > EPCAM_MAX_ERRORS) { + errors=0; + info("to much errors, restarting capture"); + epcam_stop_stream(epcam); + epcam_start_stream(epcam); + } + } + } + if (epcam->frame[framenr].grabstate==FRAME_GRABBING) + return -EAGAIN; + + return 0; +} + +static void epcam_remove_disconnected(struct usb_epcam *epcam) +{ + int i; + + epcam->dev = NULL; + + for (i=0; iurb[i]) { + epcam->urb[i]->next = NULL; + usb_unlink_urb(epcam->urb[i]); + usb_free_urb(epcam->urb[i]); + epcam->urb[i] = NULL; + kfree(epcam->sbuf[i].data); + } + for (i=0; iscratch[i].data) { + kfree(epcam->scratch[i].data); + } + if (epcam->inturb) { + usb_unlink_urb(epcam->inturb); + usb_free_urb(epcam->inturb); + } + + info("%s disconnected", epcam->camera_name); + + /* Free the memory */ + if (!epcam->user) { + kfree(epcam); + epcam = NULL; + } +} + + + +/**************************************************************************** + * + * Video4Linux + * + ***************************************************************************/ + + +static int epcam_open(struct video_device *dev, int flags) +{ + struct usb_epcam *epcam = (struct usb_epcam *)dev; + int err = 0; + + MOD_INC_USE_COUNT; + + epcam->fbuf=rvmalloc(epcam->maxframesize * EPCAM_NUMFRAMES); + if(!epcam->fbuf) err=-ENOMEM; + + if (err) { + MOD_DEC_USE_COUNT; + return err; + } + + epcam->user=1; + + return 0; +} + +static void epcam_close(struct video_device *dev) +{ + struct usb_epcam *epcam = (struct usb_epcam *)dev; + int i; + + rvfree(epcam->fbuf, epcam->maxframesize * EPCAM_NUMFRAMES); + if (epcam->removed) { + video_unregister_device(&epcam->vdev); + epcam_remove_disconnected(epcam); + info("device unregistered"); + } else { + for (i=0; iframe[i].grabstate=FRAME_UNUSED; + if (epcam->streaming) + epcam_stop_stream(epcam); + epcam->user=0; + } + + MOD_DEC_USE_COUNT; +} + +static int epcam_init_done(struct video_device *dev) +{ +#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) + create_proc_epcam_cam((struct usb_epcam *)dev); +#endif + + return 0; +} + +static long epcam_write(struct video_device *dev, const char *buf, unsigned long + count, int noblock) +{ + return -EINVAL; +} + +static int epcam_ioctl(struct video_device *vdev, unsigned int cmd, void *arg) +{ + struct usb_epcam *epcam = (struct usb_epcam *)vdev; + + if (!epcam->dev) + return -EIO; + switch (cmd) { + case VIDIOCGCAP: + { + struct video_capability b; + strcpy(b.name, epcam->camera_name); + b.type = VID_TYPE_CAPTURE; + b.channels = 1; + b.audios = 0; + b.maxwidth = epcam->maxwidth; + b.maxheight = epcam->maxheight; + b.minwidth = 2;//FIXME!!!!! + b.minheight = 2;//FIXME!!!!! + + if (copy_to_user(arg, &b, sizeof(b))) + return -EFAULT; + + return 0; + } + case VIDIOCGCHAN: + { + struct video_channel v; + + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if (v.channel != 0) + return -EINVAL; + + v.flags = 0; + v.tuners = 0; + v.type = VIDEO_TYPE_CAMERA; + strcpy(v.name, "Camera"); + + if (copy_to_user(arg, &v, sizeof(v))) + return -EFAULT; + + return 0; + } + case VIDIOCSCHAN: + { + int v; + + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + + if (v != 0) + return -EINVAL; + + return 0; + } + case VIDIOCGPICT: + { + struct video_picture p; + + epcam_get_pict(epcam, &p); + + if (copy_to_user(arg, &p, sizeof(p))) + return -EFAULT; + return 0; + } + case VIDIOCSPICT: + { + struct video_picture p; + + if (copy_from_user(&p, arg, sizeof(p))) + return -EFAULT; + + if (epcam_set_pict(epcam, &p)) + return -EINVAL; + return 0; + } + case VIDIOCSWIN: + { + struct video_window vw; + + if (copy_from_user(&vw, arg, sizeof(vw))) + return -EFAULT; + if (vw.flags) + return -EINVAL; + if (vw.clipcount) + return -EINVAL; + if (epcam_set_size(epcam, vw.width, vw.height)) + return -EINVAL; + + return 0; + } + case VIDIOCGWIN: + { + struct video_window vw; + + vw.x = 0; + vw.y = 0; + vw.chromakey = 0; + vw.flags = 0; + vw.clipcount = 0; + vw.width = epcam->cwidth; + vw.height = epcam->cheight; + + if (copy_to_user(arg, &vw, sizeof(vw))) + return -EFAULT; + + return 0; + } + case VIDIOCGMBUF: + { + struct video_mbuf vm; + int i; + + memset(&vm, 0, sizeof(vm)); + vm.size = EPCAM_NUMFRAMES * epcam->maxframesize; + vm.frames = EPCAM_NUMFRAMES; + for (i=0; imaxframesize * i; + + if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm))) + return -EFAULT; + + return 0; + } + case VIDIOCMCAPTURE: + { + struct video_mmap vm; + + if (copy_from_user(&vm, arg, sizeof(vm))) + return -EFAULT; + + if (vm.format != VIDEO_PALETTE_RGB24) + return -EINVAL; + if (vm.frame < 0 || vm.frame >= EPCAM_NUMFRAMES) + return -EINVAL; + if (epcam->frame[vm.frame].grabstate != FRAME_UNUSED) + return -EBUSY; + + if (epcam_set_size(epcam, vm.width, vm.height)) + return -EINVAL; + epcam->frame[vm.frame].grabstate=FRAME_READY; + + if (!epcam->streaming) + epcam_start_stream(epcam); + + return 0; + } + case VIDIOCSYNC: + { + int frame, ret=0; + + if (copy_from_user((void *)&frame, arg, sizeof(int))) + return -EFAULT; + + ret=epcam_newframe(epcam, frame, 0); + epcam->frame[frame].grabstate=FRAME_UNUSED; + return ret; + } + case VIDIOCGFBUF: + { + struct video_buffer vb; + + memset(&vb, 0, sizeof(vb)); + vb.base = NULL; /* frame buffer not supported, not used */ + + if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb))) + return -EFAULT; + + return 0; + } + case VIDIOCKEY: + return 0; + case VIDIOCCAPTURE: + return -EINVAL; + case VIDIOCSFBUF: + return -EINVAL; + case VIDIOCGTUNER: + case VIDIOCSTUNER: + return -EINVAL; + case VIDIOCGFREQ: + case VIDIOCSFREQ: + return -EINVAL; + case VIDIOCGAUDIO: + case VIDIOCSAUDIO: + return -EINVAL; + default: + return -ENOIOCTLCMD; + } /* end switch */ + + return 0; +} + +static long epcam_read(struct video_device *dev, char *buf, unsigned long count, + int noblock) +{ + int realcount=count, ret=0; + struct usb_epcam *epcam = (struct usb_epcam *)dev; + + + if (epcam->dev == NULL) + return -EIO; + if (realcount > epcam->cwidth*epcam->cheight*3) + realcount=epcam->cwidth*epcam->cheight*3; + + if (!epcam->frame[0].grabstate==FRAME_GRABBING) { + epcam->frame[0].grabstate=FRAME_READY; + epcam->frame[1].grabstate=FRAME_UNUSED; + epcam->curframe=0; + } + + if (!epcam->streaming) + epcam_start_stream(epcam); + + ret=epcam_newframe(epcam, 0, noblock); + + if (ret == -EAGAIN) + return ret; + if (!ret) { + copy_to_user(buf, epcam->frame[0].data, realcount); + } else { + realcount=ret;; + } + + epcam->frame[0].grabstate=FRAME_UNUSED; + return realcount; +} + +static int epcam_mmap(struct video_device *dev, const char *adr, + unsigned long size) +{ + struct usb_epcam *epcam = (struct usb_epcam *)dev; + unsigned long start = (unsigned long)adr; + unsigned long page, pos; + + if (epcam->dev == NULL) { + return -EIO; + } + if (size > (((EPCAM_NUMFRAMES * epcam->maxframesize) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) { + return -EINVAL; + } + pos = (unsigned long)epcam->fbuf; + while (size > 0) { + page = kvirt_to_pa(pos); + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) { + return -EAGAIN; + } + start += PAGE_SIZE; + pos += PAGE_SIZE; + if (size > PAGE_SIZE) + size -= PAGE_SIZE; + else + size = 0; + } + + return 0; +} + +static struct video_device epcam_template = { + name: "EPCAM USB camera", + type: VID_TYPE_CAPTURE, + hardware: VID_HARDWARE_EPCAM, + open: epcam_open, + close: epcam_close, + read: epcam_read, + write: epcam_write, + ioctl: epcam_ioctl, + mmap: epcam_mmap, + initialize: epcam_init_done, +}; + + + +/***************************/ +static int epcam_init(struct usb_epcam *epcam) +{ + int i=0, rc; + unsigned char cp[0x80]; + /* led on */ + epcam_sndctrl(1, epcam, VENDOR_REQ_LED_CONTROL, 1, NULL, 0); + + /* get camera descriptor */ + memset(cp, 0, 0x80); + rc=epcam_sndctrl(0, epcam, VENDOR_REQ_CAMERA_INFO, 0, cp, sizeof(cp)); + info("vendor_req_camera_info: %d", rc); + if (rc<0) { + info("Error reading camera descriptor"); + return 1; + } + info("size :%d %x %x", QT2INT(cp ), cp[0], cp[1]); + info("rev :%d %x %x", QT2INT(cp+4 ), cp[4], cp[5]); + info("maxwidth :%d %x %x", QT2INT(cp+6 ), cp[6], cp[7]); + info("maxheight:%d %x %x", QT2INT(cp+8 ), cp[8], cp[9]); + info("zoomcaps :%d %x %x", QT2INT(cp+10), cp[10], cp[11]); + info("ISPCaps :%d %x %x", QT2INT(cp+12), cp[12], cp[13]); + info("Formats :%d %x %x", QT2INT(cp+14), cp[14], cp[15]); + for (i=0; imaxwidth=QT2INT(cp+6); + epcam->maxheight=QT2INT(cp+8); + epcam->camid=QT2INT(cp+2); + + info("camid: %x", epcam->camid); + if (epcam->camid!=0x800 && + epcam->camid!=0x402 && + epcam->camid!=0x401 ) { + err("Not a supported camid: %d!", epcam->camid); + return 1; + } + if (epcam->camid==0x401) { + info("Your camera might work with this driver..."); + info("Please send your results to: pe1rxq@amsat.org"); + } + + epcam->cwidth=epcam->maxwidth/2; + epcam->cheight=epcam->maxheight/2; + epcam->maxframesize=epcam->maxwidth*epcam->maxheight*3; + + /* some default values */ + epcam->brightness=32768; + epcam_send_pict(epcam); + epcam->resetlevel=0x2d; + epcam->palette=VIDEO_PALETTE_RGB24; + epcam->dropped=0; + epcam->framecount=0; + epcam->readcount=0; + epcam_recv_pict(epcam); + + /* Start interrupt transfers for snapshot button */ + epcam->inturb=usb_alloc_urb(0); + if (!epcam->inturb) { + info("Allocation of inturb failed"); + return 1; + } + FILL_INT_URB(epcam->inturb, epcam->dev, + usb_rcvintpipe(epcam->dev, EPCAM_BUTTON_ENDPOINT), + &epcam->button, sizeof(epcam->button), + epcam_button_irq, + epcam, + HZ/10 + ); + if (usb_submit_urb(epcam->inturb)) { + info("int urb burned down"); + return 1; + } + + /* Flash the led */ + epcam_sndctrl(1, epcam, VENDOR_REQ_CAM_POWER, 1, NULL, 0); + epcam_sndctrl(1, epcam, VENDOR_REQ_LED_CONTROL, 1, NULL, 0); + epcam_sndctrl(1, epcam, VENDOR_REQ_CAM_POWER, 0, NULL, 0); + epcam_sndctrl(1, epcam, VENDOR_REQ_LED_CONTROL, 0, NULL, 0); + + + return 0; +} + +static void* __devinit epcam_probe(struct usb_device *dev, unsigned int ifnum, + const struct usb_device_id *id) +{ + struct usb_interface_descriptor *interface; + struct usb_epcam *epcam; + char *camera_name=NULL; + + if (!id) + return NULL; + if (dev->descriptor.bNumConfigurations != 1) + return NULL; + + interface = &dev->actconfig->interface[ifnum].altsetting[0]; + if (interface->bInterfaceNumber!=0) + return NULL; + + camera_name=(char *)id->driver_info; + + /* We found one */ + info("epcam camera found: %s", camera_name); + + if ((epcam = kmalloc(sizeof(*epcam), GFP_KERNEL)) == NULL) { + err("couldn't kmalloc epcam struct"); + return NULL; + } + + memset(epcam, 0, sizeof(*epcam)); + + epcam->dev = dev; + epcam->iface = interface->bInterfaceNumber; + epcam->camera_name = camera_name; + info("firmware version: %02x", dev->descriptor.bcdDevice & 255); + + if (epcam_init(epcam)) + return NULL; + memcpy(&epcam->vdev, &epcam_template, sizeof(epcam_template)); + memcpy(epcam->vdev.name, epcam->camera_name, strlen(epcam->camera_name)); + if (video_register_device(&epcam->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { + err("video_register_device failed"); + return NULL; + } + info("registered new video device: video%d", epcam->vdev.minor); + + init_waitqueue_head(&epcam->wq); + + return epcam; +} + +static void epcam_disconnect(struct usb_device *dev, void *ptr) +{ + struct usb_epcam *epcam = (struct usb_epcam *) ptr; + + lock_kernel(); + /* We don't want people trying to open up the device */ + if (!epcam->user) { + video_unregister_device(&epcam->vdev); + epcam_remove_disconnected(epcam); + } else { + usb_driver_release_interface(&epcam_driver, + &epcam->dev->actconfig->interface[epcam->iface]); + + epcam->frame[0].grabstate = FRAME_ERROR; + epcam->frame[1].grabstate = FRAME_ERROR; + + epcam->streaming = 0; + + if (waitqueue_active(&epcam->wq)) + wake_up_interruptible(&epcam->wq); + epcam->removed = 1; + } + +#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) + destroy_proc_epcam_cam(epcam); +#endif + + unlock_kernel(); +} + + +static struct usb_driver epcam_driver = { + name: "epcam", + id_table: device_table, + probe: epcam_probe, + disconnect: epcam_disconnect +}; + + + +/**************************************************************************** + * + * Module routines + * + ***************************************************************************/ + +static int __init usb_epcam_init(void) +{ +#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) + proc_epcam_create(); +#endif + + info("EPcam usb camera driver version %s registering", version); + if (usb_register(&epcam_driver) < 0) + return -1; + return 0; +} + +static void __exit usb_epcam_exit(void) +{ + usb_deregister(&epcam_driver); + info("EPcam driver deregistered"); + +#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) + proc_epcam_destroy(); +#endif +} + +module_init(usb_epcam_init); +module_exit(usb_epcam_exit); diff -ruN linux/drivers/usb.org/epcam.h linux/drivers/usb/epcam.h --- linux/drivers/usb.org/epcam.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/usb/epcam.h Thu Sep 5 20:25:51 2002 @@ -0,0 +1,238 @@ + +#ifndef __LINUX_epcam_H +#define __LINUX_epcam_H + +#include +#include +#include + +#define epcam_DEBUG /* Turn on debug messages */ + +#ifdef epcam_DEBUG +# define PDEBUG(level, fmt, args...) \ +if (debug >= level) info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ , ## args) +#else +# define PDEBUG(level, fmt, args...) do {} while(0) +#endif + +/* An almost drop-in replacement for sleep_on_interruptible */ +#define wait_interruptible(test, noblock, queue, wait) \ +{ \ + add_wait_queue(queue, wait); \ + set_current_state(TASK_INTERRUPTIBLE); \ + if (test) \ + schedule(); \ + remove_wait_queue(queue, wait); \ + set_current_state(TASK_RUNNING); \ + if (signal_pending(current)) \ + break; \ +} + + +/* Helpers for reading/writing integers to the QT engine */ +#define INT2QT(val, buf) { (buf)[0]=(val)&255; (buf)[1]=(val)/256; } +#define QT2INT(buf) ((buf)[0]+(buf)[1]*256) + + +/* EPCAM controls: */ + +#define VENDOR_REQ_CAMERA_INFO 0x00 +#define VENDOR_REQ_CAPTURE_INFO 0x01 +#define VENDOR_REQ_COMPRESSION 0x02 +#define VENDOR_REQ_CONT_CAPTURE 0x03 +#define VENDOR_REQ_CAPTURE_FRAME 0x04 +#define VENDOR_REQ_IMAGE_INFO 0x05 +#define VENDOR_REQ_EXT_FEATURE 0x06 +#define VENDOR_REQ_CAM_POWER 0x07 +#define VENDOR_REQ_LED_CONTROL 0x08 +#define VENDOR_DEAD_PIXEL 0x09 +#define VENDOR_REQ_AUTO_CONTROL 0x0a +#define VENDOR_REQ_BIOS 0xff + +#define VENDOR_CMD_BIOS_READ 0x07 + +#define EPCAM_FORMAT_BAYER 1 + +/* Hyundai hv7131b registers + 7121 and 7141 should be the same (haven't really checked...) */ +/* Mode registers: */ +#define HV7131_REG_MODE_A 0x00 +#define HV7131_REG_MODE_B 0x01 +#define HV7131_REG_MODE_C 0x02 +/* Frame registers: */ +#define HV7131_REG_FRSU 0x10 +#define HV7131_REG_FRSL 0x11 +#define HV7131_REG_FCSU 0x12 +#define HV7131_REG_FCSL 0x13 +#define HV7131_REG_FWHU 0x14 +#define HV7131_REG_FWHL 0x15 +#define HV7131_REG_FWWU 0x16 +#define HV7131_REG_FWWL 0x17 +/* Timing registers: */ +#define HV7131_REG_THBU 0x20 +#define HV7131_REG_THBL 0x21 +#define HV7131_REG_TVBU 0x22 +#define HV7131_REG_TVBL 0x23 +#define HV7131_REG_TITU 0x25 +#define HV7131_REG_TITM 0x26 +#define HV7131_REG_TITL 0x27 +#define HV7131_REG_TMCD 0x28 +/* Adjust Registers: */ +#define HV7131_REG_ARLV 0x30 +#define HV7131_REG_ARCG 0x31 +#define HV7131_REG_AGCG 0x32 +#define HV7131_REG_ABCG 0x33 +#define HV7131_REG_APBV 0x34 +#define HV7131_REG_ASLP 0x54 +/* Offset Registers: */ +#define HV7131_REG_OFSR 0x50 +#define HV7131_REG_OFSG 0x51 +#define HV7131_REG_OFSB 0x52 +/* Reset level statistics registers: */ +#define HV7131_REG_LOREFNOH 0x57 +#define HV7131_REG_LOREFNOL 0x58 +#define HV7131_REG_HIREFNOH 0x59 +#define HV7131_REG_HIREFNOL 0x5a + +///* se401 registers */ +//#define SE401_OPERATINGMODE 0x2000 + + +/* size of usb transfers */ +#define EPCAM_PACKETBUFS 4 +/* number of iso urbs to use */ +#define EPCAM_NUMSBUF 4 +/* read the usb specs for this one :) */ +#define EPCAM_VIDEO_ENDPOINT 1 +#define EPCAM_BUTTON_ENDPOINT 2 +/* number of frames supported by the v4l part */ +#define EPCAM_NUMFRAMES 2 +/* scratch buffers for passing data to the decoders */ +#define EPCAM_NUMSCRATCH 64 +/* maximum amount of data in a JangGu packet */ +#define EPCAM_VLCDATALEN 1024 +/* number of nul sized packets to receive before kicking the camera */ +#define EPCAM_MAX_NULLPACKETS 4000 +/* number of decoding errors before kicking the camera */ +#define EPCAM_MAX_ERRORS 200 + + +struct usb_device; + +struct epcam_sbuf { + unsigned char *data; +}; + +enum { + FRAME_UNUSED, /* Unused (no MCAPTURE) */ + FRAME_READY, /* Ready to start grabbing */ + FRAME_GRABBING, /* In the process of being grabbed into */ + FRAME_DONE, /* Finished grabbing, but not been synced yet */ + FRAME_ERROR, /* Something bad happened while processing */ +}; + +enum { + FMT_BAYER, + FMT_JANGGU, + FMT_EPLITE, +}; + +enum { + BUFFER_UNUSED, + BUFFER_READY, + BUFFER_BUSY, + BUFFER_DONE, +}; + +struct epcam_scratch { + unsigned char *data; + volatile int state; + int offset; + int length; +}; + +struct epcam_frame { + unsigned char *data; /* Frame buffer */ + + volatile int grabstate; /* State of grabbing */ + + unsigned char *curline; + int curlinepix; + int curpix; +}; + +struct usb_epcam { + struct video_device vdev; + + /* Device structure */ + struct usb_device *dev; + + unsigned char iface; + + char *camera_name; + unsigned int camid; + + int brightness; + int resetlevel; + + int enhance; + + int format; + int maxwidth; /* max width */ + int maxheight; /* max height */ + int cwidth; /* current width */ + int cheight; /* current height */ + int palette; + int maxframesize; + + int removed; + int user; /* user count for exclusive use */ + + int streaming; /* Are we streaming video? */ + + char *fbuf; /* Videodev buffer area */ + + int packetsize; + struct urb *urb[EPCAM_NUMSBUF]; + struct urb *inturb; + + int button; + int buttonpressed; + + int curframe; /* Current receiving frame */ + struct epcam_frame frame[EPCAM_NUMFRAMES]; + int readcount; + int framecount; + + int cancel; + int dropped; + int underrun; + int datacorrupt; + + int scratch_next; + int scratch_use; + int scratch_overflow; + struct epcam_scratch scratch[EPCAM_NUMSCRATCH]; + int scratch_offset; + + /* Decoder specific data: */ + int lastoffset; + int eplite_curpix; + int eplite_curline; + unsigned char eplite_data[1024]; + int vlc_size; + int vlc_cod; + int vlc_data; + + struct epcam_sbuf sbuf[EPCAM_NUMSBUF]; + + wait_queue_head_t wq; /* Processes waiting */ + + /* proc interface */ + struct proc_dir_entry *proc_entry; /* /proc/epcam/videoX */ + + int nullpackets; +}; + + +#endif --- linux/include/linux/videodev.h.org Thu Sep 5 20:26:53 2002 +++ linux/include/linux/videodev.h Thu Sep 5 20:28:33 2002 @@ -403,6 +403,7 @@ #define VID_HARDWARE_PWC 31 /* Philips webcams */ #define VID_HARDWARE_MEYE 32 /* Sony Vaio MotionEye cameras */ #define VID_HARDWARE_CPIA2 33 +#define VID_HARDWARE_EPCAM 34 /* Endpoints SE402 and EP800 webcams */ #endif /* __LINUX_VIDEODEV_H */