From: Greg KH To: torvalds@transmeta.com Cc: linux-usb-devel@lists.sourceforge.net Subject: [PATCH 2 of 4] USB vicam driver added Hi, Here's a patch against 2.5.2-pre6 that adds the USB vicam video camera driver. The driver was written by Christopher Cheney and Pavel Machek. A patch to add the driver to the build and the Configure.help entry will be sent later. thanks, greg k-h diff -Nru a/drivers/usb/vicam.c b/drivers/usb/vicam.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/usb/vicam.c Wed Jan 2 14:34:03 2002 @@ -0,0 +1,986 @@ +/* -*- linux-c -*- + * USB ViCAM driver + * + * Copyright (c) 2001 Christopher L Cheney (ccheney@cheney.cx) + * Copyright (c) 2001 Pavel Machek (pavel@suse.cz) sponsored by SuSE + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This driver is for the Vista Imaging ViCAM and 3Com HomeConnect USB + * + * Thanks to Greg Kroah-Hartman for the USB Skeleton driver + * + * TODO: + * - find out the ids for the Vista Imaging ViCAM + * + * History: + * + * 2001_07_07 - 0.1 - christopher: first version + * 2001_08_28 - 0.2 - pavel: messed it up, but for some fun, try + while true; do dd if=/dev/video of=/dev/fb0 bs=$[0x1e480] count=1 2> /dev/null; done + yep, moving pictures. + * 2001_08_29 - 0.3 - pavel: played a little bit more. Experimental mmap support. For some fun, + get gqcam-0.9, compile it and run. Better than dd ;-). + * 2001_08_29 - 0.4 - pavel: added shutter speed control (not much functional) + kill update_params if it does not seem to work for you. + * 2001_08_30 - 0.5 - pavel: fixed stupid bug with update_params & vicam_bulk + + * + * FIXME: It crashes on rmmod with camera plugged. + */ +#define DEBUG 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "vicam.h" +#include "vicamurbs.h" + +/* Version Information */ +#define DRIVER_VERSION "v0" +#define DRIVER_AUTHOR "Christopher L Cheney , Pavel Machek " +#define DRIVER_DESC "USB ViCAM Driver" + +/* Define these values to match your device */ +#define USB_VICAM_VENDOR_ID 0x04C1 +#define USB_VICAM_PRODUCT_ID 0x009D + +/* table of devices that work with this driver */ +static struct usb_device_id vicam_table [] = { + { USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID) }, + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE (usb, vicam_table); + +static int video_nr = -1; /* next avail video device */ +static struct usb_driver vicam_driver; + +static char *buf, *buf2; +static int change_pending = 0; + +static int vicam_parameters(struct usb_vicam *vicam); + +/****************************************************************************** + * + * Memory management functions + * + * Taken from bttv-drivers.c 2.4.7-pre3 + * + ******************************************************************************/ + +/* [DaveM] I've recoded most of this so that: + * 1) It's easier to tell what is happening + * 2) It's more portable, especially for translating things + * out of vmalloc mapped areas in the kernel. + * 3) Less unnecessary translations happen. + * + * The code used to assume that the kernel vmalloc mappings + * existed in the page tables of every process, this is simply + * not guarenteed. We now use pgd_offset_k which is the + * defined way to get at the kernel page tables. + */ + +/* Given PGD from the address space's page table, return the kernel + * virtual mapping of the physical memory mapped at ADR. + */ +static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr) +{ + unsigned long ret = 0UL; + pmd_t *pmd; + pte_t *ptep, pte; + + if (!pgd_none(*pgd)) { + pmd = pmd_offset(pgd, adr); + if (!pmd_none(*pmd)) { + ptep = pte_offset(pmd, adr); + pte = *ptep; + if(pte_present(pte)) { + ret = (unsigned long) page_address(pte_page(pte)); + ret |= (adr & (PAGE_SIZE - 1)); + + } + } + } + return ret; +} + +static inline unsigned long uvirt_to_bus(unsigned long adr) +{ + unsigned long kva, ret; + + kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr); + ret = virt_to_bus((void *)kva); + return ret; +} + +static inline unsigned long kvirt_to_bus(unsigned long adr) +{ + unsigned long va, kva, ret; + + va = VMALLOC_VMADDR(adr); + kva = uvirt_to_kva(pgd_offset_k(va), va); + ret = virt_to_bus((void *)kva); + return ret; +} + +/* Here we want the physical address of the memory. + * This is used when initializing the contents of the + * area and marking the pages as reserved. + */ +static inline unsigned long kvirt_to_pa(unsigned long adr) +{ + unsigned long va, kva, ret; + + va = VMALLOC_VMADDR(adr); + kva = uvirt_to_kva(pgd_offset_k(va), va); + ret = __pa(kva); + return ret; +} + +static void * rvmalloc(signed long size) +{ + void * mem; + unsigned long adr, page; + + mem=vmalloc_32(size); + if (mem) + { + memset(mem, 0, size); /* Clear the ram out, no junk to the user */ + adr=(unsigned long) mem; + while (size > 0) + { + page = kvirt_to_pa(adr); + mem_map_reserve(virt_to_page(__va(page))); + adr+=PAGE_SIZE; + size-=PAGE_SIZE; + } + } + return mem; +} + +static void rvfree(void * mem, signed long size) +{ + unsigned long adr, page; + + if (mem) + { + adr=(unsigned long) mem; + while (size > 0) + { + page = kvirt_to_pa(adr); + mem_map_unreserve(virt_to_page(__va(page))); + adr+=PAGE_SIZE; + size-=PAGE_SIZE; + } + vfree(mem); + } +} + +/****************************************************************************** + * + * Foo Bar + * + ******************************************************************************/ + +/** + * usb_vicam_debug_data + */ +static inline void usb_vicam_debug_data (const char *function, int size, const unsigned char *data) +{ + int i; + + if (!debug) + return; + + printk (KERN_DEBUG __FILE__": %s - length = %d, data = ", + function, size); + for (i = 0; i < size; ++i) { + printk ("%.2x ", data[i]); + } + printk ("\n"); +} + +/***************************************************************************** + * + * Send command to vicam + * + *****************************************************************************/ + +static int vicam_sndctrl(int set, struct usb_vicam *vicam, unsigned short req, + unsigned short value, unsigned char *cp, int size) +{ + int ret; + unsigned char *transfer_buffer = kmalloc (size, GFP_KERNEL); + + /* Needs to return data I think, works for sending though */ + memcpy(transfer_buffer, cp, size); + + ret = usb_control_msg ( vicam->udev, set ? usb_sndctrlpipe(vicam->udev, 0) : usb_rcvctrlpipe(vicam->udev, 0), req, (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value, 0, transfer_buffer, size, HZ); + + kfree(transfer_buffer); + if (ret) + printk("vicam: error: %d\n", ret); + mdelay(100); + return ret; +} + + +/***************************************************************************** + * + * Video4Linux Helpers + * + *****************************************************************************/ + +static int vicam_get_capability(struct usb_vicam *vicam, struct video_capability *b) +{ + dbg("vicam_get_capability"); + + strcpy(b->name, vicam->camera_name); + b->type = VID_TYPE_CAPTURE | VID_TYPE_MONOCHROME; + b->channels = 1; + b->audios = 0; + + b->maxwidth = vicam->width[vicam->sizes-1]; + b->maxheight = vicam->height[vicam->sizes-1]; + b->minwidth = vicam->width[0]; + b->minheight = vicam->height[0]; + + return 0; +} + +static int vicam_get_channel(struct usb_vicam *vicam, struct video_channel *v) +{ + dbg("vicam_get_channel"); + + if (v->channel != 0) + return -EINVAL; + + v->flags = 0; + v->tuners = 0; + v->type = VIDEO_TYPE_CAMERA; + strcpy(v->name, "Camera"); + + return 0; +} + +static int vicam_set_channel(struct usb_vicam *vicam, struct video_channel *v) +{ + dbg("vicam_set_channel"); + + if (v->channel != 0) + return -EINVAL; + + return 0; +} + +static int vicam_get_mmapbuffer(struct usb_vicam *vicam, struct video_mbuf *vm) +{ + int i; + + dbg("vicam_get_mmapbuffer"); + + memset(vm, 0, sizeof(vm)); + vm->size = VICAM_NUMFRAMES * vicam->maxframesize; + vm->frames = VICAM_NUMFRAMES; + + for (i=0; ioffsets[i] = vicam->maxframesize * i; + + return 0; +} + +static int vicam_get_picture(struct usb_vicam *vicam, struct video_picture *p) +{ + dbg("vicam_get_picture"); + + /* This is probably where that weird 0x56 call goes */ + p->brightness = vicam->win.brightness; + p->hue = vicam->win.hue; + p->colour = vicam->win.colour; + p->contrast = vicam->win.contrast; + p->whiteness = vicam->win.whiteness; + p->depth = vicam->win.depth; + p->palette = vicam->win.palette; + + return 0; +} + +static void synchronize(struct usb_vicam *vicam) +{ + change_pending = 1; + interruptible_sleep_on(&vicam->wait); + vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x00, NULL, 0); + mdelay(10); + vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x00, NULL, 0); + mdelay(10); +} + +static void params_changed(struct usb_vicam *vicam) +{ +#if 1 + synchronize(vicam); + mdelay(10); + vicam_parameters(vicam); + printk("Submiting urb: %d\n", usb_submit_urb(&vicam->readurb)); +#endif +} + +static int vicam_set_picture(struct usb_vicam *vicam, struct video_picture *p) +{ + int changed = 0; + info("vicam_set_picture (%d)", p->brightness); + + +#define SET(x) \ + if (vicam->win.x != p->x) \ + vicam->win.x = p->x, changed = 1; + SET(brightness); + SET(hue); + SET(colour); + SET(contrast); + SET(whiteness); + SET(depth); + SET(palette); + if (changed) + params_changed(vicam); + + return 0; + /* Investigate what should be done maybe 0x56 type call */ + if (p->depth != 8) return 1; + if (p->palette != VIDEO_PALETTE_GREY) return 1; + + return 0; +} + +/* FIXME - vicam_sync_frame - important */ +static int vicam_sync_frame(struct usb_vicam *vicam, int frame) +{ + dbg("vicam_sync_frame"); + + if(frame <0 || frame >= VICAM_NUMFRAMES) + return -EINVAL; + + /* Probably need to handle various cases */ +/* ret=vicam_newframe(vicam, frame); + vicam->frame[frame].grabstate=FRAME_UNUSED; +*/ + return 0; +} + +static int vicam_get_window(struct usb_vicam *vicam, struct video_window *vw) +{ + dbg("vicam_get_window"); + + vw->x = 0; + vw->y = 0; + vw->chromakey = 0; + vw->flags = 0; + vw->clipcount = 0; + vw->width = vicam->win.width; + vw->height = vicam->win.height; + + return 0; +} + +static int vicam_set_window(struct usb_vicam *vicam, struct video_window *vw) +{ + info("vicam_set_window"); + + if (vw->flags) + return -EINVAL; + if (vw->clipcount) + return -EINVAL; + + if (vicam->win.width == vw->width && vicam->win.height == vw->height) + return 0; + + /* Pick largest mode that is smaller than specified res */ + /* If specified res is too small reject */ + + /* Add urb send to device... */ + + vicam->win.width = vw->width; + vicam->win.height = vw->height; + params_changed(vicam); + + return 0; +} + +/* FIXME - vicam_mmap_capture - important */ +static int vicam_mmap_capture(struct usb_vicam *vicam, struct video_mmap *vm) +{ + dbg("vicam_mmap_capture"); + + /* usbvideo.c looks good for using here */ + + /* + if (vm->frame >= VICAM_NUMFRAMES) + return -EINVAL; + if (vicam->frame[vm->frame].grabstate != FRAME_UNUSED) + return -EBUSY; + vicam->frame[vm->frame].grabstate=FRAME_READY; + */ + + /* No need to vicam_set_window here according to Alan */ + + /* + if (!vicam->streaming) + vicam_start_stream(vicam); + */ + + /* set frame as ready */ + + return 0; +} + +/***************************************************************************** + * + * Video4Linux + * + *****************************************************************************/ + +static int vicam_v4l_open(struct video_device *vdev, int flags) +{ + struct usb_vicam *vicam = (struct usb_vicam *)vdev; + int err = 0; + + dbg("vicam_v4l_open"); + + MOD_INC_USE_COUNT; + down(&vicam->sem); + + if (vicam->open_count) /* Maybe not needed? */ + err = -EBUSY; + else { + vicam->fbuf = rvmalloc(vicam->maxframesize * VICAM_NUMFRAMES); + if (!vicam->fbuf) + err=-ENOMEM; + else { + vicam->open_count = 1; + } +#ifdef BLINKING + vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x01, NULL, 0); + info ("led on"); + vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x01, NULL, 0); +#endif + } + + up(&vicam->sem); + if (err) + MOD_DEC_USE_COUNT; + return err; +} + +static void vicam_v4l_close(struct video_device *vdev) +{ + struct usb_vicam *vicam = (struct usb_vicam *)vdev; + + dbg("vicam_v4l_close"); + + down(&vicam->sem); + +#ifdef BLINKING + info ("led off"); + vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x00, NULL, 0); +// vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x00, NULL, 0); Leave it on +#endif + + rvfree(vicam->fbuf, vicam->maxframesize * VICAM_NUMFRAMES); + vicam->fbuf = 0; + vicam->open_count=0; + + up(&vicam->sem); + /* Why does se401.c have a usbdevice check here? */ + /* If device is unplugged while open, I guess we only may unregister now */ + MOD_DEC_USE_COUNT; +} + +static long vicam_v4l_read(struct video_device *vdev, char *user_buf, unsigned long buflen, int noblock) +{ + //struct usb_vicam *vicam = (struct usb_vicam *)vdev; + + dbg("vicam_v4l_read(%ld)", buflen); + + if (!vdev || !buf) + return -EFAULT; + + if (copy_to_user(user_buf, buf2, buflen)) + return -EFAULT; + return buflen; +} + +static long vicam_v4l_write(struct video_device *dev, const char *buf, unsigned long count, int noblock) +{ + info("vicam_v4l_write"); + return -EINVAL; +} + +static int vicam_v4l_ioctl(struct video_device *vdev, unsigned int cmd, void *arg) +{ + struct usb_vicam *vicam = (struct usb_vicam *)vdev; + int ret = -EL3RST; + + if (!vicam->udev) + return -EIO; + + down(&vicam->sem); + + switch (cmd) { + case VIDIOCGCAP: + { + struct video_capability b; + ret = vicam_get_capability(vicam,&b); + dbg("name %s",b.name); + if (copy_to_user(arg, &b, sizeof(b))) + ret = -EFAULT; + } + case VIDIOCGFBUF: + { + struct video_buffer vb; + info("vicam_v4l_ioctl - VIDIOCGBUF - query frame buffer param"); + /* frame buffer not supported, not used */ + memset(&vb, 0, sizeof(vb)); + vb.base = NULL; + + /* FIXME - VIDIOCGFBUF - why the void */ + if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb))) + ret = -EFAULT; + ret = 0; + } + case VIDIOCGWIN: + { + struct video_window vw; + ret = vicam_get_window(vicam, &vw); + if (copy_to_user(arg, &vw, sizeof(vw))) + ret = -EFAULT; + } + case VIDIOCSWIN: + { + struct video_window vw; + if (copy_from_user(&vw, arg, sizeof(vw))) + ret = -EFAULT; + else + ret = vicam_set_window(vicam, &vw); + return ret; + } + case VIDIOCGCHAN: + { + struct video_channel v; + + if (copy_from_user(&v, arg, sizeof(v))) + ret = -EFAULT; + else { + ret = vicam_get_channel(vicam,&v); + if (copy_to_user(arg, &v, sizeof(v))) + ret = -EFAULT; + } + } + case VIDIOCSCHAN: + { + struct video_channel v; + if (copy_from_user(&v, arg, sizeof(v))) + ret = -EFAULT; + else + ret = vicam_set_channel(vicam,&v); + } + case VIDIOCGPICT: + { + struct video_picture p; + ret = vicam_get_picture(vicam, &p); + if (copy_to_user(arg, &p, sizeof(p))) + ret = -EFAULT; + } + case VIDIOCSPICT: + { + struct video_picture p; + if (copy_from_user(&p, arg, sizeof(p))) + ret = -EFAULT; + else + ret = vicam_set_picture(vicam, &p); + } + case VIDIOCGMBUF: + { + struct video_mbuf vm; + ret = vicam_get_mmapbuffer(vicam,&vm); + /* FIXME - VIDIOCGMBUF - why the void */ + if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm))) + ret = -EFAULT; + } + case VIDIOCMCAPTURE: + { + struct video_mmap vm; + ret = vicam_mmap_capture(vicam, &vm); + /* FIXME: This is probably not right */ + } + case VIDIOCSYNC: + { + int frame; + /* FIXME - VIDIOCSYNC - why the void */ + if (copy_from_user((void *)&frame, arg, sizeof(int))) + ret = -EFAULT; + else + ret = vicam_sync_frame(vicam,frame); + } + + case VIDIOCKEY: + ret = 0; + + case VIDIOCCAPTURE: + case VIDIOCSFBUF: + case VIDIOCGTUNER: + case VIDIOCSTUNER: + case VIDIOCGFREQ: + case VIDIOCSFREQ: + case VIDIOCGAUDIO: + case VIDIOCSAUDIO: + case VIDIOCGUNIT: + ret = -EINVAL; + + default: + { + info("vicam_v4l_ioctl - %ui",cmd); + ret = -ENOIOCTLCMD; + } + } /* end switch */ + + up(&vicam->sem); + return ret; +} + +static int vicam_v4l_mmap(struct video_device *dev, const char *adr, unsigned long size) +{ + struct usb_vicam *vicam = (struct usb_vicam *)dev; + unsigned long start = (unsigned long)adr; + unsigned long page, pos; + + down(&vicam->sem); + + if (vicam->udev == NULL) { + up(&vicam->sem); + return -EIO; + } +#if 0 + if (size > (((VICAM_NUMFRAMES * vicam->maxframesize) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) { + up(&vicam->sem); + return -EINVAL; + } +#endif + pos = (unsigned long)vicam->fbuf; + while (size > 0) { + page = kvirt_to_pa(pos); + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) { + up(&vicam->sem); + return -EAGAIN; + } + start += PAGE_SIZE; + pos += PAGE_SIZE; + if (size > PAGE_SIZE) + size -= PAGE_SIZE; + else + size = 0; + } + up(&vicam->sem); + + return 0; +} + +/* FIXME - vicam_v4l_init */ +static int vicam_v4l_init(struct video_device *dev) +{ + /* stick proc fs stuff in here if wanted */ + dbg("vicam_v4l_init"); + return 0; +} + +/* FIXME - vicam_template - important */ +static struct video_device vicam_template = { + name: "vicam USB camera", + type: VID_TYPE_CAPTURE, + hardware: VID_HARDWARE_SE401, /* need to ask for own id */ + open: vicam_v4l_open, + close: vicam_v4l_close, + read: vicam_v4l_read, + write: vicam_v4l_write, + ioctl: vicam_v4l_ioctl, + mmap: vicam_v4l_mmap, + initialize: vicam_v4l_init, +}; + +/****************************************************************************** + * + * Some Routines + * + ******************************************************************************/ + +/* +Flash the led +vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x01, NULL, 0); +info ("led on"); +vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x01, NULL, 0); +info ("led off"); +vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x00, NULL, 0); +vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x00, NULL, 0); +*/ + +static void vicam_bulk(struct urb *urb) +{ + struct usb_vicam *vicam = urb->context; + + /* if (!vicam || !vicam->dev || !vicam->used) + return; + */ + + if (urb->status) + printk("vicam%d: nonzero read/write bulk status received: %d", + 0, urb->status); + + urb->actual_length = 0; + urb->dev = vicam->udev; + + memcpy(buf2, buf+64, 0x1e480); + if (vicam->fbuf) + memcpy(vicam->fbuf, buf+64, 0x1e480); + + if (!change_pending) { + if (usb_submit_urb(urb)) + dbg("failed resubmitting read urb"); + } else { + change_pending = 0; + wake_up_interruptible(&vicam->wait); + } +} + +static int vicam_parameters(struct usb_vicam *vicam) +{ + unsigned char req[0x10]; + unsigned int shutter; + shutter = 10; + + switch (vicam->win.width) { + case 512: + default: + memcpy(req, s512x242bw, 0x10); + break; + case 256: + memcpy(req, s256x242bw, 0x10); + break; + case 128: + memcpy(req, s128x122bw, 0x10); + break; + } + + + mdelay(10); + vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x01, NULL, 0); + info ("led on"); + vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x01, NULL, 0); + + mdelay(10); + + shutter = vicam->win.contrast / 256; + if (shutter == 0) + shutter = 1; + printk("vicam_parameters: brightness %d, shutter %d\n", vicam->win.brightness, shutter ); + req[0] = vicam->win.brightness /256; + shutter = 15600/shutter - 1; + req[6] = shutter & 0xff; + req[7] = (shutter >> 8) & 0xff; + vicam_sndctrl(1, vicam, VICAM_REQ_CAPTURE, 0x80, req, 0x10); + mdelay(10); + vicam_sndctrl(0, vicam, VICAM_REQ_GET_SOMETHIN, 0, buf, 0x10); + mdelay(10); + + return 0; +} + +static int vicam_init(struct usb_vicam *vicam) +{ + int width[] = {128, 256, 512}; + int height[] = {122, 242, 242}; + + dbg("vicam_init"); + buf = kmalloc(0x1e480, GFP_KERNEL); + buf2 = kmalloc(0x1e480, GFP_KERNEL); + if ((!buf) || (!buf2)) { + printk("Not enough memory for vicam!\n"); + goto error; + } + + /* do we do aspect correction in kernel or not? */ + vicam->sizes = 3; + vicam->width = kmalloc(vicam->sizes*sizeof(int), GFP_KERNEL); + vicam->height = kmalloc(vicam->sizes*sizeof(int), GFP_KERNEL); + memcpy(vicam->width, &width, sizeof(width)); + memcpy(vicam->height, &height, sizeof(height)); + vicam->maxframesize = vicam->width[vicam->sizes-1] * vicam->height[vicam->sizes-1]; + + /* Download firmware to camera */ + vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, firmware1, sizeof(firmware1)); + vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, findex1, sizeof(findex1)); + vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, fsetup, sizeof(fsetup)); + vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, firmware2, sizeof(firmware2)); + vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, findex2, sizeof(findex2)); + vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, fsetup, sizeof(fsetup)); + + vicam_parameters(vicam); + + FILL_BULK_URB(&vicam->readurb, vicam->udev, usb_rcvbulkpipe(vicam->udev, 0x81), + buf, 0x1e480, vicam_bulk, vicam); + printk("Submiting urb: %d\n", usb_submit_urb(&vicam->readurb)); + + return 0; +error: + if (buf) + kfree(buf); + if (buf2) + kfree(buf2); + return 1; +} + +static void * __devinit vicam_probe(struct usb_device *udev, unsigned int ifnum, + const struct usb_device_id *id) +{ + struct usb_vicam *vicam; + char *camera_name=NULL; + + dbg("vicam_probe"); + + /* See if the device offered us matches what we can accept */ + if ((udev->descriptor.idVendor != USB_VICAM_VENDOR_ID) || + (udev->descriptor.idProduct != USB_VICAM_PRODUCT_ID)) { + return NULL; + } + + camera_name="3Com HomeConnect USB"; + info("ViCAM camera found: %s", camera_name); + + vicam = kmalloc (sizeof(struct usb_vicam), GFP_KERNEL); + if (vicam == NULL) { + err ("couldn't kmalloc vicam struct"); + return NULL; + } + memset(vicam, 0, sizeof(*vicam)); + + vicam->udev = udev; + vicam->camera_name = camera_name; + vicam->win.brightness = 128; + vicam->win.contrast = 10; + + /* FIXME */ + if (vicam_init(vicam)) + return NULL; + memcpy(&vicam->vdev, &vicam_template, sizeof(vicam_template)); + memcpy(vicam->vdev.name, vicam->camera_name, strlen(vicam->camera_name)); + + if (video_register_device(&vicam->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { + err("video_register_device"); + return NULL; + } + + info("registered new video device: video%d", vicam->vdev.minor); + + init_MUTEX (&vicam->sem); + init_waitqueue_head(&vicam->wait); + + return vicam; +} + + +/* FIXME - vicam_disconnect - important */ +static void vicam_disconnect(struct usb_device *udev, void *ptr) +{ + struct usb_vicam *vicam; + + vicam = (struct usb_vicam *) ptr; + + if (!vicam->open_count) + video_unregister_device(&vicam->vdev); + vicam->udev = NULL; +/* + vicam->frame[0].grabstate = FRAME_ERROR; + vicam->frame[1].grabstate = FRAME_ERROR; +*/ + + /* Free buffers and shit */ + + info("%s disconnected", vicam->camera_name); + synchronize(vicam); + + if (!vicam->open_count) { + /* Other random junk */ + kfree(vicam); + vicam = NULL; + } +} + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver vicam_driver = { + name: "vicam", + probe: vicam_probe, + disconnect: vicam_disconnect, + id_table: vicam_table, +}; + +/****************************************************************************** + * + * Module Routines + * + ******************************************************************************/ + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +/* Module paramaters */ +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + +static int __init usb_vicam_init(void) +{ + int result; + + printk("VICAM: initializing\n"); + /* register this driver with the USB subsystem */ + result = usb_register(&vicam_driver); + if (result < 0) { + err("usb_register failed for the "__FILE__" driver. Error number %d", + result); + return -1; + } + + info(DRIVER_VERSION " " DRIVER_AUTHOR); + info(DRIVER_DESC); + return 0; +} + +static void __exit usb_vicam_exit(void) +{ + /* deregister this driver with the USB subsystem */ + usb_deregister(&vicam_driver); +} + +module_init(usb_vicam_init); +module_exit(usb_vicam_exit); diff -Nru a/drivers/usb/vicam.h b/drivers/usb/vicam.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/usb/vicam.h Wed Jan 2 14:34:03 2002 @@ -0,0 +1,81 @@ +/* + * + * Vista Imaging ViCAM / 3Com HomeConnect Usermode Driver + * Christopher L Cheney (C) 2001 + * + */ + +#ifndef __LINUX_VICAM_H +#define __LINUX_VICAM_H + + +#ifdef CONFIG_USB_DEBUG + static int debug = 1; +#else + static int debug; +#endif + +/* Use our own dbg macro */ +#undef dbg +#define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg); } while (0) + +#define VICAM_NUMFRAMES 30 +#define VICAM_NUMSBUF 1 + +/* USB REQUEST NUMBERS */ +#define VICAM_REQ_VENDOR 0xff +#define VICAM_REQ_CAMERA_POWER 0x50 +#define VICAM_REQ_CAPTURE 0x51 +#define VICAM_REQ_LED_CONTROL 0x55 +#define VICAM_REQ_GET_SOMETHIN 0x56 + +/* not required but lets you know camera is on */ +/* camera must be on to turn on led */ +/* 0x01 always on 0x03 on when picture taken (flashes) */ + +struct picture_parm +{ + int width; + int height; + int brightness; + int hue; + int colour; + int contrast; + int whiteness; + int depth; + int palette; +}; + +struct vicam_scratch { + unsigned char *data; + volatile int state; + int offset; + int length; +}; + +/* Structure to hold all of our device specific stuff */ +struct usb_vicam +{ + struct video_device vdev; + struct usb_device *udev; + + int open_count; /* number of times this port has been opened */ + struct semaphore sem; /* locks this structure */ + wait_queue_head_t wait; /* Processes waiting */ + + int streaming; + + /* v4l stuff */ + char *camera_name; + char *fbuf; + urb_t *urb[VICAM_NUMSBUF]; + int sizes; + int *width; + int *height; + int maxframesize; + struct picture_parm win; + struct proc_dir_entry *proc_entry; /* /proc/se401/videoX */ + struct urb readurb; +}; + +#endif diff -Nru a/drivers/usb/vicamurbs.h b/drivers/usb/vicamurbs.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/usb/vicamurbs.h Wed Jan 2 14:34:03 2002 @@ -0,0 +1,330 @@ +/* + * + * Vista Imaging ViCAM / 3Com HomeConnect Usermode Driver + * Christopher L Cheney (C) 2001 + * + */ + + +#ifndef __LINUX_VICAMURBS_H +#define __LINUX_VICAMURBS_H + +/* -------------------------------------------------------------------------- */ + +/* FIXME - Figure out transfers so that this doesn't need to be here + * + * Notice: in pieces below, "0" means other code will fill it while "0x00" means this is zero */ + +/* Request 0x51 Image Setup */ + +/* 128x98 ? 0x3180 size */ +static unsigned char s128x98bw[] = { + 0, 0x34, 0xC4, 0x00, 0x00, 0x00, 0, 0, + 0x18, 0x02, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00 +}; + +/* 128x122 3D80 size */ +static unsigned char s128x122bw[] = { + 0, 0x34, 0xF4, 0x00, 0x00, 0x00, 0, 0, + 0x00, 0x02, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00 +}; + +/* 256x242 ? 0xF280 size */ +static unsigned char s256x242bw[] = { + 0, 0x03, 0xC8, 0x03, 0x00, 0x00, 0, 0, + 0x00, 0x04, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00 +}; + +/* 512x242 0x1E480 size */ +static unsigned char s512x242bw[] = { + 0, 0x05, 0x90, 0x07, 0x00, 0x00, 0, 0, + 0x00, 0x08, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00 +}; + +/* In s512x242: + byte 0: gain -- higher number means brighter image + byte 6, 7: shutter speed, little-endian; set this to 15600 * (shutter speed) - 1. (Where shutter speed is something like 1/1000). +*/ + +/* -------------------------------------------------------------------------- */ + +static unsigned char fsetup[] = { + 0xB6, 0xC3, 0x01, 0x00, 0x06, 0x64, + + 0x00, 0x00 +}; + +static unsigned char firmware1[] = { + 0xB6, 0xC3, 0x1F, 0x00, 0x02, 0x64, + + 0xE7, 0x67, 0xFD, 0xFF, 0x0E, 0xC0, 0xE7, 0x09, + 0xDE, 0x00, 0x8E, 0x00, 0xC0, 0x09, 0x40, 0x03, + 0xC0, 0x17, 0x44, 0x03, 0x4B, 0xAF, 0xC0, 0x07, + 0x00, 0x00, 0x4B, 0xAF, 0x97, 0xCF, 0x00, 0x00 +}; + +static unsigned char findex1[] = { + 0xB6, 0xC3, 0x03, 0x00, 0x03, 0x64, + + 0x18, 0x00, 0x00, 0x00 +}; + +static unsigned char firmware2[] = { + 0xB6, 0xC3, 0x8F, 0x06, 0x02, 0x64, + + 0xE7, 0x07, 0x00, 0x00, 0x08, 0xC0, 0xE7, 0x07, + 0x00, 0x00, 0x3E, 0xC0, 0xE7, 0x07, 0x54, 0x01, + 0xAA, 0x00, 0xE7, 0x07, 0xC8, 0x05, 0xB6, 0x00, + 0xE7, 0x07, 0x42, 0x01, 0xD2, 0x00, 0xE7, 0x07, + 0x7C, 0x00, 0x16, 0x00, 0xE7, 0x07, 0x56, 0x00, + 0x18, 0x00, 0xE7, 0x07, 0x06, 0x00, 0x92, 0xC0, + 0xE7, 0x07, 0x00, 0x00, 0x1E, 0xC0, 0xE7, 0x07, + 0xFF, 0xFF, 0x22, 0xC0, 0xE7, 0x07, 0x04, 0x00, + 0x24, 0xC0, 0xE7, 0x07, 0xEC, 0x27, 0x28, 0xC0, + 0xE7, 0x07, 0x16, 0x01, 0x8E, 0x00, 0xE7, 0x87, + 0x01, 0x00, 0x0E, 0xC0, 0x97, 0xCF, 0xD7, 0x09, + 0x00, 0xC0, 0xE7, 0x77, 0x01, 0x00, 0x92, 0xC0, + 0x09, 0xC1, 0xE7, 0x09, 0xFE, 0x05, 0x24, 0x01, + 0xE7, 0x09, 0x04, 0x06, 0x26, 0x01, 0xE7, 0x07, + 0x07, 0x00, 0x92, 0xC0, 0xE7, 0x05, 0x00, 0xC0, + 0xC0, 0xDF, 0x97, 0xCF, 0x17, 0x00, 0x57, 0x00, + 0x17, 0x02, 0xD7, 0x09, 0x00, 0xC0, 0xE7, 0x77, + 0x01, 0x00, 0x92, 0xC0, 0x0A, 0xC1, 0xE7, 0x57, + 0xFF, 0xFF, 0xFA, 0x05, 0x0D, 0xC0, 0xE7, 0x57, + 0x00, 0x00, 0xFA, 0x05, 0x0F, 0xC0, 0x9F, 0xAF, + 0xC6, 0x00, 0xE7, 0x05, 0x00, 0xC0, 0xC8, 0x05, + 0xC1, 0x05, 0xC0, 0x05, 0xC0, 0xDF, 0x97, 0xCF, + 0x27, 0xDA, 0xFA, 0x05, 0xEF, 0x07, 0x01, 0x00, + 0x0B, 0x06, 0x73, 0xCF, 0x9F, 0xAF, 0x78, 0x01, + 0x9F, 0xAF, 0x1A, 0x03, 0x6E, 0xCF, 0xE7, 0x09, + 0xFC, 0x05, 0x24, 0x01, 0xE7, 0x09, 0x02, 0x06, + 0x26, 0x01, 0xE7, 0x07, 0x07, 0x00, 0x92, 0xC0, + 0xE7, 0x09, 0xFC, 0x05, 0xFE, 0x05, 0xE7, 0x09, + 0x02, 0x06, 0x04, 0x06, 0xE7, 0x09, 0x00, 0x06, + 0xFC, 0x05, 0xE7, 0x09, 0xFE, 0x05, 0x00, 0x06, + 0x27, 0xDA, 0xFA, 0x05, 0xE7, 0x57, 0x01, 0x00, + 0xFA, 0x05, 0x02, 0xCA, 0x04, 0xC0, 0x97, 0xCF, + 0x9F, 0xAF, 0x66, 0x05, 0x97, 0xCF, 0xE7, 0x07, + 0x40, 0x00, 0x02, 0x06, 0xC8, 0x09, 0xFC, 0x05, + 0x9F, 0xAF, 0xDA, 0x02, 0x97, 0xCF, 0xCF, 0x17, + 0x02, 0x00, 0xEF, 0x57, 0x81, 0x00, 0x09, 0x06, + 0x9F, 0xA0, 0xB6, 0x01, 0xEF, 0x57, 0x80, 0x00, + 0x09, 0x06, 0x9F, 0xA0, 0x40, 0x02, 0xEF, 0x57, + 0x01, 0x00, 0x0B, 0x06, 0x9F, 0xA0, 0x46, 0x03, + 0xE7, 0x07, 0x01, 0x00, 0x0A, 0xC0, 0x46, 0xAF, + 0x47, 0xAF, 0x9F, 0xAF, 0x40, 0x02, 0xE7, 0x07, + 0x2E, 0x00, 0x0A, 0xC0, 0xEF, 0x87, 0x80, 0x00, + 0x09, 0x06, 0x97, 0xCF, 0x00, 0x0E, 0x01, 0x00, + 0xC0, 0x57, 0x51, 0x00, 0x9F, 0xC0, 0x9E, 0x02, + 0xC0, 0x57, 0x50, 0x00, 0x20, 0xC0, 0xC0, 0x57, + 0x55, 0x00, 0x12, 0xC0, 0xC0, 0x57, 0x56, 0x00, + 0x9F, 0xC0, 0x72, 0x02, 0x9F, 0xCF, 0xD6, 0x02, + 0xC1, 0x0B, 0x08, 0x06, 0x01, 0xD0, 0x6F, 0x90, + 0x08, 0x06, 0xC0, 0x07, 0x08, 0x00, 0xC1, 0x0B, + 0x08, 0x06, 0x9F, 0xAF, 0x28, 0x05, 0x97, 0xCF, + 0x2F, 0x0E, 0x02, 0x00, 0x08, 0x06, 0xC0, 0x07, + 0x08, 0x00, 0xC1, 0x0B, 0x08, 0x06, 0x9F, 0xAF, + 0x28, 0x05, 0x9F, 0xCF, 0xD6, 0x02, 0x2F, 0x0E, + 0x02, 0x00, 0x09, 0x06, 0xEF, 0x87, 0x80, 0x00, + 0x09, 0x06, 0x9F, 0xCF, 0xD6, 0x02, 0xEF, 0x67, + 0x7F, 0xFF, 0x09, 0x06, 0xE7, 0x67, 0xFF, 0xFD, + 0x22, 0xC0, 0xE7, 0x67, 0xEF, 0xFF, 0x24, 0xC0, + 0xE7, 0x87, 0x10, 0x00, 0x28, 0xC0, 0x9F, 0xAF, + 0xB8, 0x05, 0xE7, 0x87, 0xE0, 0x21, 0x24, 0xC0, + 0x9F, 0xAF, 0xA8, 0x05, 0xE7, 0x87, 0x08, 0x00, + 0x24, 0xC0, 0xE7, 0x67, 0xDF, 0xFF, 0x24, 0xC0, + 0xC8, 0x07, 0x0A, 0x00, 0xC0, 0x07, 0x00, 0x00, + 0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05, + 0x9F, 0xAF, 0xB8, 0x05, 0xC0, 0x07, 0x9E, 0x00, + 0x9F, 0xAF, 0x44, 0x05, 0xE7, 0x67, 0xFF, 0xFE, + 0x24, 0xC0, 0xC0, 0x09, 0x20, 0xC0, 0xE7, 0x87, + 0x00, 0x01, 0x24, 0xC0, 0xC0, 0x77, 0x00, 0x02, + 0x0F, 0xC1, 0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0, + 0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x87, + 0x08, 0x00, 0x24, 0xC0, 0x08, 0xDA, 0x5E, 0xC1, + 0xEF, 0x07, 0x80, 0x00, 0x09, 0x06, 0x97, 0xCF, + 0xEF, 0x07, 0x01, 0x00, 0x0A, 0x06, 0x97, 0xCF, + 0xEF, 0x07, 0x00, 0x00, 0x0B, 0x06, 0xEF, 0x07, + 0x00, 0x00, 0x0A, 0x06, 0xEF, 0x67, 0x7F, 0xFF, + 0x09, 0x06, 0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06, + 0xE7, 0x67, 0xEF, 0xFF, 0x28, 0xC0, 0xE7, 0x67, + 0x17, 0xD8, 0x24, 0xC0, 0xE7, 0x07, 0x00, 0x00, + 0x1E, 0xC0, 0xE7, 0x07, 0xFF, 0xFF, 0x22, 0xC0, + 0x97, 0xCF, 0xC8, 0x07, 0x0E, 0x06, 0x9F, 0xAF, + 0xDA, 0x02, 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, + 0xE7, 0x07, 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, + 0x0E, 0x06, 0xF4, 0x05, 0xE7, 0x07, 0xD6, 0x02, + 0xF8, 0x05, 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, + 0x00, 0x80, 0x50, 0xAF, 0x97, 0xCF, 0x2F, 0x0C, + 0x02, 0x00, 0x07, 0x06, 0x2F, 0x0C, 0x04, 0x00, + 0x06, 0x06, 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, + 0xE7, 0x07, 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, + 0xE2, 0x05, 0xF4, 0x05, 0xE7, 0x07, 0xCE, 0x02, + 0xF8, 0x05, 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, + 0x00, 0x80, 0x51, 0xAF, 0x97, 0xCF, 0x9F, 0xAF, + 0x66, 0x04, 0x9F, 0xAF, 0x1A, 0x03, 0x59, 0xAF, + 0x97, 0xCF, 0xC0, 0x07, 0x0E, 0x00, 0xC1, 0x0B, + 0x0C, 0x06, 0x41, 0xD1, 0x9F, 0xAF, 0x28, 0x05, + 0xC0, 0x07, 0x3C, 0x00, 0x9F, 0xAF, 0x44, 0x05, + 0x68, 0x00, 0xC0, 0x07, 0x3B, 0x00, 0x9F, 0xAF, + 0x44, 0x05, 0x6F, 0x00, 0x0C, 0x06, 0x68, 0x00, + 0xE0, 0x07, 0x04, 0x01, 0xE8, 0x0B, 0x0A, 0x06, + 0xE8, 0x07, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x02, + 0xE0, 0x07, 0xEC, 0x01, 0xE0, 0x07, 0xFC, 0xFF, + 0x97, 0xCF, 0xE7, 0x07, 0xFF, 0xFF, 0xFA, 0x05, + 0xEF, 0x07, 0x00, 0x00, 0x0B, 0x06, 0xE7, 0x07, + 0x0E, 0x06, 0x24, 0x01, 0xE7, 0x07, 0x0E, 0x06, + 0xFE, 0x05, 0xE7, 0x07, 0x40, 0x00, 0x26, 0x01, + 0xE7, 0x07, 0x40, 0x00, 0x04, 0x06, 0xE7, 0x07, + 0x07, 0x00, 0x92, 0xC0, 0x97, 0xCF, 0xEF, 0x07, + 0x02, 0x00, 0x0B, 0x06, 0x9F, 0xAF, 0x78, 0x01, + 0xEF, 0x77, 0x80, 0x00, 0x07, 0x06, 0x9F, 0xC0, + 0x14, 0x04, 0xEF, 0x77, 0x01, 0x00, 0x07, 0x06, + 0x37, 0xC0, 0xEF, 0x77, 0x01, 0x00, 0x0D, 0x06, + 0x0F, 0xC1, 0xEF, 0x07, 0x01, 0x00, 0x0D, 0x06, + 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00, + 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x01, 0x00, + 0xC1, 0x07, 0x02, 0x00, 0x9F, 0xAF, 0x28, 0x05, + 0xC8, 0x07, 0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05, + 0xC0, 0x07, 0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05, + 0xC1, 0x77, 0x03, 0x00, 0x02, 0xC1, 0x08, 0xDA, + 0x75, 0xC1, 0xC1, 0x77, 0x01, 0x00, 0x0A, 0xC1, + 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07, 0x02, 0x00, + 0x9F, 0xAF, 0x28, 0x05, 0xEF, 0x07, 0x01, 0x00, + 0x06, 0x06, 0x2C, 0xCF, 0xC0, 0x07, 0x01, 0x00, + 0xC1, 0x07, 0x04, 0x00, 0x9F, 0xAF, 0x28, 0x05, + 0xEF, 0x07, 0x00, 0x00, 0x06, 0x06, 0x22, 0xCF, + 0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06, 0xEF, 0x57, + 0x01, 0x00, 0x06, 0x06, 0x1B, 0xC0, 0xC0, 0x07, + 0x01, 0x00, 0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF, + 0x28, 0x05, 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, + 0x30, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07, + 0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07, + 0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x67, + 0x03, 0x00, 0xC1, 0x57, 0x03, 0x00, 0x02, 0xC0, + 0x08, 0xDA, 0x73, 0xC1, 0xC0, 0x07, 0x02, 0x00, + 0xC1, 0x07, 0x12, 0x00, 0xEF, 0x57, 0x00, 0x00, + 0x06, 0x06, 0x02, 0xC0, 0xC1, 0x07, 0x23, 0x00, + 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x14, 0x00, + 0xC1, 0x0B, 0xEA, 0x05, 0x9F, 0xAF, 0x28, 0x05, + 0xC0, 0x07, 0x3E, 0x00, 0x9F, 0xAF, 0x0A, 0x05, + 0xE7, 0x09, 0xE4, 0x05, 0xFA, 0x05, 0x27, 0xD8, + 0xFA, 0x05, 0xE7, 0x07, 0x0E, 0x06, 0xFC, 0x05, + 0xE7, 0x07, 0x4E, 0x06, 0x00, 0x06, 0xE7, 0x07, + 0x40, 0x00, 0x02, 0x06, 0x9F, 0xAF, 0x66, 0x05, + 0x9F, 0xAF, 0xC6, 0x00, 0x97, 0xCF, 0xC1, 0x0B, + 0xE2, 0x05, 0x41, 0xD0, 0x01, 0xD2, 0xC1, 0x17, + 0x23, 0x00, 0x9F, 0xAF, 0xDC, 0x04, 0xC0, 0x07, + 0x04, 0x00, 0xC1, 0x0B, 0xE3, 0x05, 0x9F, 0xAF, + 0x28, 0x05, 0xC0, 0x07, 0x06, 0x00, 0xC1, 0x09, + 0xE6, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, + 0x07, 0x00, 0xC1, 0x09, 0xE6, 0x05, 0xC1, 0xD1, + 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0B, 0x00, + 0xC1, 0x09, 0xE8, 0x05, 0x9F, 0xAF, 0x28, 0x05, + 0xC0, 0x07, 0x0C, 0x00, 0xC1, 0x09, 0xE8, 0x05, + 0xC1, 0xD1, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, + 0x0D, 0x00, 0xC1, 0x07, 0x09, 0x00, 0x9F, 0xAF, + 0x28, 0x05, 0xC0, 0x07, 0x03, 0x00, 0xC1, 0x07, + 0x32, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, + 0x0F, 0x00, 0xC1, 0x07, 0x00, 0x00, 0x9F, 0xAF, + 0x28, 0x05, 0x97, 0xCF, 0xE7, 0x67, 0xFF, 0xD9, + 0x24, 0xC0, 0xC8, 0x07, 0x0A, 0x00, 0x40, 0x00, + 0xC0, 0x67, 0x00, 0x02, 0x27, 0x80, 0x24, 0xC0, + 0xE7, 0x87, 0x00, 0x04, 0x24, 0xC0, 0xE7, 0x67, + 0xFF, 0xF9, 0x24, 0xC0, 0x01, 0xD2, 0x08, 0xDA, + 0x72, 0xC1, 0xE7, 0x87, 0x00, 0x20, 0x24, 0xC0, + 0x97, 0xCF, 0x27, 0x00, 0x1E, 0xC0, 0xE7, 0x87, + 0xFF, 0x00, 0x22, 0xC0, 0xE7, 0x67, 0x7F, 0xFF, + 0x24, 0xC0, 0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0, + 0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0, 0x97, 0xCF, + 0x9F, 0xAF, 0x0A, 0x05, 0x67, 0x00, 0x1E, 0xC0, + 0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x87, + 0x40, 0x00, 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, + 0x24, 0xC0, 0x97, 0xCF, 0x9F, 0xAF, 0x0A, 0x05, + 0xE7, 0x67, 0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67, + 0xFF, 0xFE, 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, + 0x24, 0xC0, 0xC1, 0x09, 0x20, 0xC0, 0xE7, 0x87, + 0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF, 0xC0, 0x07, + 0x40, 0x00, 0xC8, 0x09, 0xFC, 0x05, 0xE7, 0x67, + 0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, + 0x24, 0xC0, 0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, + 0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0x00, 0xDA, + 0xE8, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x40, 0x00, + 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, + 0x00, 0xDA, 0xE8, 0x09, 0x20, 0xC0, 0x6D, 0xC1, + 0xE7, 0x87, 0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF, + 0xE7, 0x07, 0x32, 0x00, 0x12, 0xC0, 0xE7, 0x77, + 0x00, 0x80, 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, + 0xE7, 0x07, 0x20, 0x4E, 0x12, 0xC0, 0xE7, 0x77, + 0x00, 0x80, 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, + 0x09, 0x02, 0x19, 0x00, 0x01, 0x01, 0x00, 0x80, + 0x96, 0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static unsigned char findex2[] = { + 0xB6, 0xC3, 0x2F, 0x01, 0x03, 0x64, + + 0x0E, 0x00, 0x14, 0x00, 0x1A, 0x00, 0x20, 0x00, + 0x26, 0x00, 0x4A, 0x00, 0x64, 0x00, 0x6A, 0x00, + 0x92, 0x00, 0x9A, 0x00, 0xA0, 0x00, 0xB2, 0x00, + 0xB8, 0x00, 0xBE, 0x00, 0xC2, 0x00, 0xC8, 0x00, + 0xCE, 0x00, 0xDC, 0x00, 0xDA, 0x00, 0xE2, 0x00, + 0xE0, 0x00, 0xE8, 0x00, 0xE6, 0x00, 0xEE, 0x00, + 0xEC, 0x00, 0xF2, 0x00, 0xF8, 0x00, 0x02, 0x01, + 0x0A, 0x01, 0x0E, 0x01, 0x12, 0x01, 0x1E, 0x01, + 0x22, 0x01, 0x28, 0x01, 0x2C, 0x01, 0x32, 0x01, + 0x36, 0x01, 0x44, 0x01, 0x50, 0x01, 0x5E, 0x01, + 0x72, 0x01, 0x76, 0x01, 0x7A, 0x01, 0x80, 0x01, + 0x88, 0x01, 0x8C, 0x01, 0x94, 0x01, 0x9C, 0x01, + 0xA0, 0x01, 0xA4, 0x01, 0xAA, 0x01, 0xB0, 0x01, + 0xB4, 0x01, 0xBA, 0x01, 0xD0, 0x01, 0xDA, 0x01, + 0xF6, 0x01, 0xFA, 0x01, 0x02, 0x02, 0x34, 0x02, + 0x3C, 0x02, 0x44, 0x02, 0x4A, 0x02, 0x50, 0x02, + 0x56, 0x02, 0x74, 0x02, 0x78, 0x02, 0x7E, 0x02, + 0x84, 0x02, 0x8A, 0x02, 0x88, 0x02, 0x90, 0x02, + 0x8E, 0x02, 0x94, 0x02, 0xA2, 0x02, 0xA8, 0x02, + 0xAE, 0x02, 0xB4, 0x02, 0xBA, 0x02, 0xB8, 0x02, + 0xC0, 0x02, 0xBE, 0x02, 0xC4, 0x02, 0xD0, 0x02, + 0xD4, 0x02, 0xE0, 0x02, 0xE6, 0x02, 0xEE, 0x02, + 0xF8, 0x02, 0xFC, 0x02, 0x06, 0x03, 0x1E, 0x03, + 0x24, 0x03, 0x28, 0x03, 0x30, 0x03, 0x2E, 0x03, + 0x3C, 0x03, 0x4A, 0x03, 0x4E, 0x03, 0x54, 0x03, + 0x58, 0x03, 0x5E, 0x03, 0x66, 0x03, 0x6E, 0x03, + 0x7A, 0x03, 0x86, 0x03, 0x8E, 0x03, 0x96, 0x03, + 0xB2, 0x03, 0xB8, 0x03, 0xC6, 0x03, 0xCC, 0x03, + 0xD4, 0x03, 0xDA, 0x03, 0xE8, 0x03, 0xF4, 0x03, + 0xFC, 0x03, 0x04, 0x04, 0x20, 0x04, 0x2A, 0x04, + 0x32, 0x04, 0x36, 0x04, 0x3E, 0x04, 0x44, 0x04, + 0x42, 0x04, 0x48, 0x04, 0x4E, 0x04, 0x4C, 0x04, + 0x54, 0x04, 0x52, 0x04, 0x5A, 0x04, 0x5E, 0x04, + 0x62, 0x04, 0x68, 0x04, 0x74, 0x04, 0x7C, 0x04, + 0x80, 0x04, 0x88, 0x04, 0x8C, 0x04, 0x94, 0x04, + 0x9A, 0x04, 0xA2, 0x04, 0xA6, 0x04, 0xAE, 0x04, + 0xB4, 0x04, 0xC0, 0x04, 0xCC, 0x04, 0xD8, 0x04, + 0x2A, 0x05, 0x46, 0x05, 0x6C, 0x05, 0x00, 0x00 +}; + +#endif