patch-2.3.99-pre4 linux/drivers/usb/cpia.c
Next file: linux/drivers/usb/cpia.h
Previous file: linux/drivers/usb/audio.h
Back to the patch index
Back to the overall index
- Lines: 1426
- Date:
Wed Dec 31 16:00:00 1969
- Orig file:
v2.3.99-pre3/linux/drivers/usb/cpia.c
- Orig date:
Fri Mar 10 16:40:44 2000
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/cpia.c linux/drivers/usb/cpia.c
@@ -1,1425 +0,0 @@
-/*
- * USB CPiA Video Camera driver
- *
- * Supports CPiA based Video Cameras. Many manufacturers use this chipset.
- *
- * (C) Copyright 1999-2000 Johannes Erdfelt, jerdfelt@valinux.com
- * (C) Copyright 1999 Randy Dunlap
- */
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/list.h>
-#include <linux/malloc.h>
-#include <linux/mm.h>
-#include <linux/smp_lock.h>
-#include <linux/videodev.h>
-#include <linux/vmalloc.h>
-#include <linux/wrapper.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/usb.h>
-
-#include <asm/io.h>
-
-#include "cpia.h"
-
-static int debug = 0;
-MODULE_PARM(debug, "i");
-
-/* Video Size 384 x 288 x 3 bytes for RGB */
-/* 384 because xawtv tries to grab 384 even though we tell it 352 is our max */
-#define MAX_FRAME_SIZE (384 * 288 * 3)
-
-/*******************************/
-/* Memory management functions */
-/*******************************/
-
-#define MDEBUG(x) do { } while(0) /* Debug memory management */
-
-static struct usb_driver cpia_driver;
-
-/* 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 = page_address(pte_page(pte)) | (adr & (PAGE_SIZE-1));
- }
- }
- MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret));
- 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);
- MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret));
- 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);
- MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret));
- 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);
- MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret));
- return ret;
-}
-
-static void *rvmalloc(unsigned long size)
-{
- void *mem;
- unsigned long adr, page;
-
- /* Round it off to PAGE_SIZE */
- size += (PAGE_SIZE - 1);
- size &= ~(PAGE_SIZE - 1);
-
- mem = vmalloc(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) {
- page = kvirt_to_pa(adr);
- mem_map_reserve(MAP_NR(__va(page)));
- adr += PAGE_SIZE;
- if (size > PAGE_SIZE)
- size -= PAGE_SIZE;
- else
- size = 0;
- }
-
- return mem;
-}
-
-static void rvfree(void *mem, unsigned long size)
-{
- unsigned long adr, page;
-
- if (!mem)
- return;
-
- size += (PAGE_SIZE - 1);
- size &= ~(PAGE_SIZE - 1);
-
- adr=(unsigned long) mem;
- while (size > 0) {
- page = kvirt_to_pa(adr);
- mem_map_unreserve(MAP_NR(__va(page)));
- adr += PAGE_SIZE;
- if (size > PAGE_SIZE)
- size -= PAGE_SIZE;
- else
- size = 0;
- }
- vfree(mem);
-}
-
-static int usb_cpia_get_version(struct usb_device *dev, void *buf)
-{
- return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
- USB_REQ_CPIA_GET_VERSION,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, 0, buf, 4, HZ);
-}
-
-#ifdef NOTUSED
-static int usb_cpia_get_pnp_id(struct usb_device *dev, void *buf)
-{
- return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
- USB_REQ_CPIA_GET_PNP_ID,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, 0, buf, 6, HZ);
-}
-#endif
-
-#ifdef NOTUSED
-static int usb_cpia_get_camera_status(struct usb_device *dev, void *buf)
-{
- return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
- USB_REQ_CPIA_GET_CAMERA_STATUS,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, 0, buf, 8, HZ);
-}
-#endif
-
-static int usb_cpia_goto_hi_power(struct usb_device *dev)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CPIA_GOTO_HI_POWER, USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, 0, NULL, 0, HZ);
-}
-
-static int usb_cpia_get_vp_version(struct usb_device *dev, void *buf)
-{
- return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
- USB_REQ_CPIA_GET_VP_VERSION,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, 0, buf, 4, HZ);
-}
-
-static int usb_cpia_set_sensor_fps(struct usb_device *dev, int sensorbaserate, int sensorclkdivisor)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CPIA_SET_SENSOR_FPS,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- (sensorbaserate << 8) + sensorclkdivisor, 0, NULL, 0, HZ);
-}
-
-#ifdef NOTUSED
-static int usb_cpia_grab_frame(struct usb_device *dev, int streamstartline)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CPIA_GRAB_FRAME, USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- streamstartline << 8, 0, NULL, 0, HZ);
-}
-#endif
-
-static int usb_cpia_upload_frame(struct usb_device *dev, int forceupload)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CPIA_UPLOAD_FRAME, USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- forceupload, 0, NULL, 0, HZ);
-}
-
-static int usb_cpia_set_grab_mode(struct usb_device *dev, int continuousgrab)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CPIA_SET_GRAB_MODE,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE, continuousgrab,
- 0, NULL, 0, HZ);
-}
-
-static int usb_cpia_set_format(struct usb_device *dev, int size, int subsample, int order)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CPIA_SET_FORMAT,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- (subsample << 8) + size, order, NULL, 0, HZ);
-}
-
-static int usb_cpia_set_roi(struct usb_device *dev, int colstart, int colend, int rowstart, int rowend)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CPIA_SET_ROI,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- (colend << 8) + colstart, (rowend << 8) + rowstart,
- NULL, 0, HZ);
-}
-
-static int usb_cpia_set_compression(struct usb_device *dev, int compmode, int decimation)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CPIA_SET_COMPRESSION,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- (decimation << 8) + compmode, 0, NULL, 0, HZ);
-}
-
-#ifdef NOTUSED
-static int usb_cpia_set_compression_target(struct usb_device *dev, int target, int targetfr, int targetq)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CPIA_SET_COMPRESSION_TARGET,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- (targetfr << 8) + target, targetq, NULL, 0, HZ);
-}
-#endif
-
-#ifdef NOTUSED
-static int usb_cpia_initstreamcap(struct usb_device *dev, int skipframes, int streamstartline)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CPIA_INIT_STREAM_CAP,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- (streamstartline << 8) + skipframes, 0, NULL, 0, HZ);
-}
-
-static int usb_cpia_finistreamcap(struct usb_device *dev)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CPIA_FINI_STREAM_CAP,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, 0, NULL, 0, HZ);
-}
-
-static int usb_cpia_startstreamcap(struct usb_device *dev)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CPIA_START_STREAM_CAP,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, 0, NULL, 0, HZ);
-}
-
-static int usb_cpia_endstreamcap(struct usb_device *dev)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CPIA_END_STREAM_CAP,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, 0, NULL, 0, HZ);
-}
-#endif
-
-/* How much data is left in the scratch buf? */
-#define scratch_left(x) (cpia->scratchlen - (int)((char *)x - (char *)cpia->scratch))
-
-static void cpia_parse_data(struct usb_cpia *cpia)
-{
- struct cpia_frame *frame, *pframe;
- unsigned char *data = cpia->scratch;
- unsigned long left;
- long copylen = 0;
-
- /* Grab the current frame and the previous frame */
- frame = &cpia->frame[cpia->curframe];
- pframe = &cpia->frame[(cpia->curframe - 1 + CPIA_NUMFRAMES) % CPIA_NUMFRAMES];
-
- while (1) {
- if (!scratch_left(data))
- goto out;
-
- switch (frame->scanstate) {
- case STATE_SCANNING:
- {
- struct cpia_frame_header *header;
-
- /* We need at least 2 bytes for the magic value */
- if (scratch_left(data) < 2)
- goto out;
-
- header = (struct cpia_frame_header *)data;
-
- if (be16_to_cpup(&header->magic) == CPIA_MAGIC) {
- frame->scanstate = STATE_HEADER;
- break;
- }
-
- /* Woops, lost the header, find the end of the frame */
- if (scratch_left(data) < 4)
- goto out;
-
- /* See if we found the end of the frame */
- while (scratch_left(data) >= 4) {
- if (*((__u32 *)data) == 0xFFFFFFFF) {
- data += 4;
- if (debug >= 1)
- printk(KERN_INFO "cpia: EOF while scanning for magic\n");
- goto error;
- }
- data++;
- }
- break;
- }
- case STATE_HEADER:
- /* We need at least 64 bytes for the header */
- if (scratch_left(data) <
- sizeof(struct cpia_frame_header))
- goto out;
-
- memcpy(&frame->header, data,
- sizeof(struct cpia_frame_header));
-
- /* Skip over the header */
- data += sizeof(struct cpia_frame_header);
-
- frame->hdrwidth = (frame->header.col_end -
- frame->header.col_start) * 8;
- frame->hdrheight = (frame->header.row_end -
- frame->header.row_start) * 4;
- if (debug >= 2) {
- printk(KERN_DEBUG "cpia: frame size %dx%d\n",
- frame->hdrwidth, frame->hdrheight);
- printk(KERN_DEBUG "cpia: frame %scompressed\n",
- frame->header.comp_enable ? "" : "not ");
- }
-
- frame->scanstate = STATE_LINES;
- frame->curline = 0;
- break;
-
- case STATE_LINES:
- {
- unsigned char *f, *end;
- unsigned int len;
- int i;
- int y, u, y1, v, r, g, b;
-
- /* We want at least 2 bytes for the length */
- if (scratch_left(data) < 2)
- goto out;
-
- /* Grab the length */
- len = data[0] + (data[1] << 8);
-
- /* Check to make sure it's nothing outrageous */
- if (len > (frame->hdrwidth * 2) + 1) {
- if (debug >= 1)
- printk(KERN_DEBUG "cpia: bad length, resynching (expected %d, got %d)\n", (frame->hdrwidth * 2) + 1, len);
- goto error;
- }
-
- /* Make sure there's enough data for the entire line */
- if (scratch_left(data + 2) < len)
- goto out;
-
- /* Skip over the length */
- data += 2;
-
- /* Is the end of the line there */
- if (data[len - 1] != 0xFD) {
- if (debug >= 1)
- printk(KERN_DEBUG "cpia: lost synch\n");
- goto error;
- }
-
- /* Start at the beginning */
- end = data + len - 1;
-
- f = frame->data + (frame->width * 3 * frame->curline);
-
- if (frame->header.comp_enable) {
- unsigned char *fp;
-
- /* We use the previous frame as a reference */
- fp = pframe->data +
- (frame->width * 3 * frame->curline);
-
- while (data < end) {
- if (*data & 1) {
- /* Compress RLE data */
- i = *data >> 1;
- memcpy(f, fp, i * 3);
- copylen += (i * 3);
- f += (i * 3);
- fp += (i * 3);
- data++;
- } else {
- /* Raw data */
-
-#define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)
-
-y = *data++ - 16;
-u = *data++ - 128;
-y1 = *data++ - 16;
-v = *data++ - 128;
-r = 104635 * v;
-g = -25690 * u + -53294 * v;
-b = 132278 * u;
-y *= 76310;
-y1 *= 76310;
-*f++ = LIMIT(b + y); *f++ = LIMIT(g + y); *f++ = LIMIT(r + y);
-*f++ = LIMIT(b + y1); *f++ = LIMIT(g + y1); *f++ = LIMIT(r + y1);
- fp += 6;
- copylen += 6;
- }
- }
- } else {
- /* Raw data */
- while (data < end) {
-y = *data++ - 16;
-u = *data++ - 128;
-y1 = *data++ - 16;
-v = *data++ - 128;
-r = 104635 * v;
-g = -25690 * u + -53294 * v;
-b = 132278 * u;
-y *= 76310;
-y1 *= 76310;
-*f++ = LIMIT(b + y); *f++ = LIMIT(g + y); *f++ = LIMIT(r + y);
-*f++ = LIMIT(b + y1); *f++ = LIMIT(g + y1); *f++ = LIMIT(r + y1);
-copylen += 6;
- }
- }
-
- /* Skip the last byte */
- data++;
-
- if (++frame->curline >= frame->hdrheight)
- goto nextframe;
-
- break;
- } /* end case STATE_LINES */
- } /* end switch (scanstate) */
- } /* end while (1) */
-
-nextframe:
- if (debug >= 1)
- printk(KERN_DEBUG "cpia: marking as success\n");
-
- if (scratch_left(data) >= 4 && *((__u32 *)data) == 0xFFFFFFFF)
- data += 4;
-
- frame->grabstate = FRAME_DONE;
-
- goto wakeup;
-
-error:
- if (debug >= 1)
- printk(KERN_DEBUG "cpia: marking as error\n");
-
- frame->grabstate = FRAME_ERROR;
-
- /* Get a fresh frame since this frame may have been important */
- cpia->compress = 0;
-
- copylen = 0;
-
-wakeup:
- cpia->curframe = -1;
-
- /* This will cause the process to request another frame. */
- if (waitqueue_active(&frame->wq))
- wake_up_interruptible(&frame->wq);
-
-out:
- /* Grab the remaining */
- left = scratch_left(data);
- memmove(cpia->scratch, data, left);
- cpia->scratchlen = left;
-
- /* Update the frame's uncompressed length. */
- frame->scanlength += copylen;
-}
-
-/*
- * Make all of the blocks of data contiguous
- */
-static int cpia_compress_isochronous(struct usb_cpia *cpia, urb_t *urb)
-{
- unsigned char *cdata, *data;
- int i, totlen = 0;
-
- data = cpia->scratch + cpia->scratchlen;
- for (i = 0; i < urb->number_of_packets; i++) {
- int n = urb->iso_frame_desc[i].actual_length;
- int st = urb->iso_frame_desc[i].status;
-
- cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
-
- if (st && debug >= 1)
- printk(KERN_DEBUG "cpia data error: [%d] len=%d, status=%X\n",
- i, n, st);
-
- if ((cpia->scratchlen + n) > SCRATCH_BUF_SIZE) {
- printk(KERN_DEBUG "cpia: scratch buf overflow!scr_len: %d, n: %d\n",cpia->scratchlen, n );
- return totlen;
- }
-
- if (n) {
- memmove(data, cdata, n);
- data += n;
- totlen += n;
- cpia->scratchlen += n;
- }
- }
-
- return totlen;
-}
-
-static void cpia_isoc_irq(struct urb *urb)
-{
- int len;
- struct usb_cpia *cpia = urb->context;
- struct cpia_sbuf *sbuf;
- int i;
-
- if (!cpia->dev)
- return;
-
- if (!cpia->streaming) {
- if (debug >= 1)
- printk(KERN_DEBUG "cpia: oops, not streaming, but interrupt\n");
- return;
- }
-
- sbuf = &cpia->sbuf[cpia->cursbuf];
-
- /* Copy the data received into our scratch buffer */
- len = cpia_compress_isochronous(cpia, urb);
-
- /* If we don't have a frame we're current working on, complain */
- if (cpia->scratchlen) {
- if (cpia->curframe < 0) {
- if (debug >= 1)
- printk(KERN_DEBUG "cpia: received data, but no frame available\n");
- } else
- cpia_parse_data(cpia);
- }
-
- for (i = 0; i < FRAMES_PER_DESC; i++) {
- sbuf->urb->iso_frame_desc[i].status = 0;
- sbuf->urb->iso_frame_desc[i].actual_length = 0;
- }
-
- /* Move to the next sbuf */
- cpia->cursbuf = (cpia->cursbuf + 1) % CPIA_NUMSBUF;
-
- return;
-}
-
-static int cpia_init_isoc(struct usb_cpia *cpia)
-{
- urb_t *urb;
- int fx, err;
-
- cpia->compress = 0;
- cpia->curframe = -1;
- cpia->cursbuf = 0;
- cpia->scratchlen = 0;
-
- /* Alternate interface 3 is is the biggest frame size */
- if (usb_set_interface(cpia->dev, cpia->iface, 3) < 0) {
- printk(KERN_ERR "usb_set_interface error\n");
- return -EBUSY;
- }
-
- /* We double buffer the Iso lists */
- urb = usb_alloc_urb(FRAMES_PER_DESC);
-
- if (!urb) {
- printk(KERN_ERR "cpia_init_isoc: usb_init_isoc ret %d\n",
- 0);
- return -ENOMEM;
- }
- cpia->sbuf[0].urb = urb;
- urb->dev = cpia->dev;
- urb->context = cpia;
- urb->pipe = usb_rcvisocpipe(cpia->dev, 1);
- urb->transfer_flags = USB_ISO_ASAP;
- urb->transfer_buffer = cpia->sbuf[0].data;
- urb->complete = cpia_isoc_irq;
- urb->number_of_packets = FRAMES_PER_DESC;
- urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
- for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
- urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx;
- urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
- }
- urb = usb_alloc_urb(FRAMES_PER_DESC);
- if (!urb) {
- printk(KERN_ERR "cpia_init_isoc: usb_init_isoc ret %d\n",
- 0);
- return -ENOMEM;
- }
- cpia->sbuf[1].urb = urb;
- urb->dev = cpia->dev;
- urb->context = cpia;
- urb->pipe = usb_rcvisocpipe(cpia->dev, 1);
- urb->transfer_flags = USB_ISO_ASAP;
- urb->transfer_buffer = cpia->sbuf[1].data;
- urb->complete = cpia_isoc_irq;
- urb->number_of_packets = FRAMES_PER_DESC;
- urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
- for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
- urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx;
- urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
- }
-
- cpia->sbuf[1].urb->next = cpia->sbuf[0].urb;
- cpia->sbuf[0].urb->next = cpia->sbuf[1].urb;
-
- err = usb_submit_urb(cpia->sbuf[0].urb);
- if (err)
- printk(KERN_ERR "cpia_init_isoc: usb_submit_urb(0) ret %d\n",
- err);
- err = usb_submit_urb(cpia->sbuf[1].urb);
- if (err)
- printk(KERN_ERR "cpia_init_isoc: usb_submit_urb(1) ret %d\n",
- err);
-
- cpia->streaming = 1;
-
- return 0;
-}
-
-static void cpia_stop_isoc(struct usb_cpia *cpia)
-{
- if (!cpia->streaming || !cpia->dev)
- return;
-
- /* Turn off continuous grab */
- if (usb_cpia_set_grab_mode(cpia->dev, 0) < 0) {
- printk(KERN_ERR "cpia_set_grab_mode error\n");
- return /* -EBUSY */;
- }
-
- /* Set packet size to 0 */
- if (usb_set_interface(cpia->dev, cpia->iface, 0) < 0) {
- printk(KERN_ERR "usb_set_interface error\n");
- return /* -EINVAL */;
- }
-
- cpia->streaming = 0;
-
- /* Unschedule all of the iso td's */
- if (cpia->sbuf[1].urb) {
- cpia->sbuf[1].urb->next = NULL;
- usb_unlink_urb(cpia->sbuf[1].urb);
- usb_free_urb(cpia->sbuf[1].urb);
- cpia->sbuf[1].urb = NULL;
- }
- if (cpia->sbuf[0].urb) {
- cpia->sbuf[0].urb->next = NULL;
- usb_unlink_urb(cpia->sbuf[0].urb);
- usb_free_urb(cpia->sbuf[0].urb);
- cpia->sbuf[0].urb = NULL;
- }
-}
-
-static int cpia_new_frame(struct usb_cpia *cpia, int framenum)
-{
- struct cpia_frame *frame;
- int width, height;
-
- if (!cpia->dev)
- return -1;
-
- /* If we're not grabbing a frame right now and the other frame is */
- /* ready to be grabbed into, then use it instead */
- if (cpia->curframe == -1) {
- if (cpia->frame[(framenum - 1 + CPIA_NUMFRAMES) % CPIA_NUMFRAMES].grabstate == FRAME_READY)
- framenum = (framenum - 1 + CPIA_NUMFRAMES) % CPIA_NUMFRAMES;
- } else
- return 0;
-
- frame = &cpia->frame[framenum];
- width = frame->width;
- height = frame->height;
-
- frame->grabstate = FRAME_GRABBING;
- frame->scanstate = STATE_SCANNING;
- frame->scanlength = 0; /* accumulated in cpia_parse_data() */
-
- cpia->curframe = framenum;
-
- /* Make sure it's not too big */
- if (width > 352)
- width = 352;
- width = (width / 8) * 8; /* Multiple of 8 */
-
- if (height > 288)
- height = 288;
- height = (height / 4) * 4; /* Multiple of 4 */
-
- /* Set the ROI they want */
- if (usb_cpia_set_roi(cpia->dev, 0, width / 8, 0, height / 4) < 0)
- return -EBUSY;
-
- if (usb_cpia_set_compression(cpia->dev, cpia->compress ?
- COMP_AUTO : COMP_DISABLED, DONT_DECIMATE) < 0) {
- printk(KERN_ERR "cpia_set_compression error\n");
- return -EBUSY;
- }
-
- /* We want a fresh frame every 30 we get */
- cpia->compress = (cpia->compress + 1) % 30;
-
- /* Grab the frame */
- if (usb_cpia_upload_frame(cpia->dev, WAIT_FOR_NEXT_FRAME) < 0) {
- printk(KERN_ERR "cpia_upload_frame error\n");
- return -EBUSY;
- }
-
- return 0;
-}
-
-/* Video 4 Linux API */
-static int cpia_open(struct video_device *dev, int flags)
-{
- int err = -EBUSY;
- struct usb_cpia *cpia = (struct usb_cpia *)dev;
-
- down(&cpia->lock);
- if (cpia->user)
- goto out_unlock;
-
- cpia->frame[0].grabstate = FRAME_UNUSED;
- cpia->frame[1].grabstate = FRAME_UNUSED;
-
- err = -ENOMEM;
-
- /* Allocate memory for the frame buffers */
- cpia->fbuf = rvmalloc(2 * MAX_FRAME_SIZE);
- if (!cpia->fbuf)
- goto open_err_ret;
-
- cpia->frame[0].data = cpia->fbuf;
- cpia->frame[1].data = cpia->fbuf + MAX_FRAME_SIZE;
-
- cpia->sbuf[0].data = kmalloc (FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL);
- if (!cpia->sbuf[0].data)
- goto open_err_on0;
-
- cpia->sbuf[1].data = kmalloc (FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL);
- if (!cpia->sbuf[1].data)
- goto open_err_on1;
-
- /* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used
- * (using read() instead). */
- cpia->frame[0].width = 352;
- cpia->frame[0].height = 288;
- cpia->frame[0].bytes_read = 0;
- cpia->frame[1].width = 352;
- cpia->frame[1].height = 288;
- cpia->frame[1].bytes_read = 0;
-
- err = cpia_init_isoc(cpia);
- if (err)
- goto open_err_on2;
-
- cpia->user++;
- up(&cpia->lock);
-
- MOD_INC_USE_COUNT;
-
- return 0;
-
-open_err_on2:
- kfree (cpia->sbuf[1].data);
-open_err_on1:
- kfree (cpia->sbuf[0].data);
-open_err_on0:
- rvfree(cpia->fbuf, 2 * MAX_FRAME_SIZE);
-open_err_ret:
- return err;
-
-out_unlock:
- up(&cpia->lock);
- return err;
-}
-
-static void cpia_close(struct video_device *dev)
-{
- struct usb_cpia *cpia = (struct usb_cpia *)dev;
-
- down(&cpia->lock);
- cpia->user--;
-
- MOD_DEC_USE_COUNT;
-
- cpia_stop_isoc(cpia);
-
- rvfree(cpia->fbuf, 2 * MAX_FRAME_SIZE);
-
- kfree(cpia->sbuf[1].data);
- kfree(cpia->sbuf[0].data);
-
- up(&cpia->lock);
-
- if (!cpia->dev) {
- video_unregister_device(&cpia->vdev);
- kfree(cpia);
- }
-}
-
-static int cpia_init_done(struct video_device *dev)
-{
- return 0;
-}
-
-static long cpia_write(struct video_device *dev, const char *buf, unsigned long count, int noblock)
-{
- return -EINVAL;
-}
-
-static int cpia_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
-{
- struct usb_cpia *cpia = (struct usb_cpia *)dev;
-
- if (!cpia->dev)
- return -EIO;
-
- switch (cmd) {
- case VIDIOCGCAP:
- {
- struct video_capability b;
-
- strcpy(b.name, "CPiA USB Camera");
- b.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
- b.channels = 1;
- b.audios = 0;
- b.maxwidth = 352; /* CIF */
- b.maxheight = 288; /* " */
- b.minwidth = 8;
- b.minheight = 4;
-
- 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;
-
- p.colour = 0x8000; /* Damn British people :) */
- p.hue = 0x8000;
- p.brightness = 180 << 8; /* XXX */
- p.contrast = 192 << 8; /* XXX */
- p.whiteness = 105 << 8; /* XXX */
- p.depth = 24;
- p.palette = VIDEO_PALETTE_RGB24;
-
- 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;
-
- 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 (vw.height != 288)
- return -EINVAL;
- if (vw.width != 352)
- return -EINVAL;
-
- cpia->compress = 0;
-
- return 0;
- }
- case VIDIOCGWIN:
- {
- struct video_window vw;
-
- vw.x = 0;
- vw.y = 0;
- vw.width = 352;
- vw.height = 288;
- vw.chromakey = 0;
- vw.flags = 30; /* 30 fps */
-
- if (copy_to_user(arg, &vw, sizeof(vw)))
- return -EFAULT;
-
- return 0;
- }
- case VIDIOCGMBUF:
- {
- struct video_mbuf vm;
-
- memset(&vm, 0, sizeof(vm));
- vm.size = MAX_FRAME_SIZE * 2;
- vm.frames = 2;
- vm.offsets[0] = 0;
- vm.offsets[1] = MAX_FRAME_SIZE;
-
- if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
- return -EFAULT;
-
- return 0;
- }
- case VIDIOCMCAPTURE:
- {
- struct video_mmap vm;
-
- if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm)))
- return -EFAULT;
-
- if (debug >= 1)
- printk(KERN_DEBUG "frame: %d, size: %dx%d, format: %d\n",
- vm.frame, vm.width, vm.height, vm.format);
-
- if (vm.format != VIDEO_PALETTE_RGB24)
- return -EINVAL;
-
- if ((vm.frame != 0) && (vm.frame != 1))
- return -EINVAL;
-
- if (cpia->frame[vm.frame].grabstate == FRAME_GRABBING)
- return -EBUSY;
-
- /* Don't compress if the size changed */
- if ((cpia->frame[vm.frame].width != vm.width) ||
- (cpia->frame[vm.frame].height != vm.height))
- cpia->compress = 0;
-
- cpia->frame[vm.frame].width = vm.width;
- cpia->frame[vm.frame].height = vm.height;
-
- /* Mark it as ready */
- cpia->frame[vm.frame].grabstate = FRAME_READY;
-
- return cpia_new_frame(cpia, vm.frame);
- }
- case VIDIOCSYNC:
- {
- int frame;
-
- if (copy_from_user((void *)&frame, arg, sizeof(int)))
- return -EFAULT;
-
- if (debug >= 1)
- printk(KERN_DEBUG "cpia: syncing to frame %d\n", frame);
-
- switch (cpia->frame[frame].grabstate) {
- case FRAME_UNUSED:
- return -EINVAL;
- case FRAME_READY:
- case FRAME_GRABBING:
- case FRAME_ERROR:
-redo:
- if (!cpia->dev)
- return -EIO;
-
- do {
- interruptible_sleep_on(&cpia->frame[frame].wq);
- if (signal_pending(current))
- return -EINTR;
- } while (cpia->frame[frame].grabstate == FRAME_GRABBING);
-
- if (cpia->frame[frame].grabstate == FRAME_ERROR) {
- int ret;
-
- if ((ret = cpia_new_frame(cpia, frame)) < 0)
- return ret;
- goto redo;
- }
- case FRAME_DONE:
- cpia->frame[frame].grabstate = FRAME_UNUSED;
- break;
- }
-
- cpia->frame[frame].grabstate = FRAME_UNUSED;
-
- return 0;
- }
- 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;
- }
- return 0;
-}
-
-static long cpia_read(struct video_device *dev, char *buf, unsigned long count, int noblock)
-{
- struct usb_cpia *cpia = (struct usb_cpia *)dev;
- int frmx = -1;
- volatile struct cpia_frame *frame;
-
- if (debug >= 1)
- printk(KERN_DEBUG "cpia_read: %ld bytes, noblock=%d\n", count, noblock);
-
- if (!dev || !buf)
- return -EFAULT;
-
- if (!cpia->dev)
- return -EIO;
-
- /* See if a frame is completed, then use it. */
- if (cpia->frame[0].grabstate >= FRAME_DONE) /* _DONE or _ERROR */
- frmx = 0;
- else if (cpia->frame[1].grabstate >= FRAME_DONE)/* _DONE or _ERROR */
- frmx = 1;
-
- if (noblock && (frmx == -1))
- return -EAGAIN;
-
- /* If no FRAME_DONE, look for a FRAME_GRABBING state. */
- /* See if a frame is in process (grabbing), then use it. */
- if (frmx == -1) {
- if (cpia->frame[0].grabstate == FRAME_GRABBING)
- frmx = 0;
- else if (cpia->frame[1].grabstate == FRAME_GRABBING)
- frmx = 1;
- }
-
- /* If no frame is active, start one. */
- if (frmx == -1)
- cpia_new_frame(cpia, frmx = 0);
-
- frame = &cpia->frame[frmx];
-
-restart:
- if (!cpia->dev)
- return -EIO;
-
- while (frame->grabstate == FRAME_GRABBING) {
- interruptible_sleep_on(&frame->wq);
- if (signal_pending(current))
- return -EINTR;
- }
-
- if (frame->grabstate == FRAME_ERROR) {
- frame->bytes_read = 0;
-printk("cpia_read: errored frame %d\n", cpia->curframe);
- if (cpia_new_frame(cpia, frmx))
- printk(KERN_ERR "cpia_read: cpia_new_frame error\n");
- goto restart;
- }
-
- if (debug >= 1)
- printk(KERN_DEBUG "cpia_read: frmx=%d, bytes_read=%ld, scanlength=%ld\n",
- frmx, frame->bytes_read, frame->scanlength);
-
- /* copy bytes to user space; we allow for partials reads */
- if ((count + frame->bytes_read) > frame->scanlength)
- count = frame->scanlength - frame->bytes_read;
-
- if (copy_to_user(buf, frame->data + frame->bytes_read, count))
- return -EFAULT;
-
- frame->bytes_read += count;
- if (debug >= 1)
- printk(KERN_DEBUG "cpia_read: {copy} count used=%ld, new bytes_read=%ld\n",
- count, frame->bytes_read);
-
- if (frame->bytes_read >= frame->scanlength) { /* All data has been read */
- frame->bytes_read = 0;
-
- /* Mark it as available to be used again. */
- cpia->frame[frmx].grabstate = FRAME_UNUSED;
- if (cpia_new_frame(cpia, frmx ? 0 : 1))
- printk(KERN_ERR "cpia_read: cpia_new_frame returned error\n");
- }
-
- return count;
-}
-
-static int cpia_mmap(struct video_device *dev, const char *adr, unsigned long size)
-{
- struct usb_cpia *cpia = (struct usb_cpia *)dev;
- unsigned long start = (unsigned long)adr;
- unsigned long page, pos;
-
- if (!cpia->dev)
- return -EIO;
-
- if (size > (((2 * MAX_FRAME_SIZE) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))
- return -EINVAL;
-
- pos = (unsigned long)cpia->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 cpia_template = {
- "CPiA USB Camera",
- VID_TYPE_CAPTURE,
- VID_HARDWARE_CPIA,
- cpia_open,
- cpia_close,
- cpia_read,
- cpia_write,
- NULL,
- cpia_ioctl,
- cpia_mmap,
- cpia_init_done,
- NULL,
- 0,
- 0
-};
-
-static int usb_cpia_configure(struct usb_cpia *cpia)
-{
- struct usb_device *dev = cpia->dev;
- unsigned char version[4];
-
- /* Set altsetting 0 */
- if (usb_set_interface(dev, cpia->iface, 0) < 0) {
- printk(KERN_ERR "usb_set_interface error\n");
- return -EBUSY;
- }
-
- if (usb_cpia_get_version(dev, version) < 0) {
- printk(KERN_ERR "cpia_get_version error\n");
- return -EBUSY;
- }
-
- if (debug >= 1)
- printk(KERN_DEBUG "cpia: Firmware v%d.%d, VC Hardware v%d.%d\n",
- version[0], version[1], version[2], version[3]);
-
- memcpy(&cpia->vdev, &cpia_template, sizeof(cpia_template));
-
- init_waitqueue_head(&cpia->frame[0].wq);
- init_waitqueue_head(&cpia->frame[1].wq);
-
- if (video_register_device(&cpia->vdev, VFL_TYPE_GRABBER) == -1) {
- printk(KERN_ERR "video_register_device failed\n");
- return -EBUSY;
- }
-
- if (usb_cpia_goto_hi_power(dev) < 0) {
- printk(KERN_ERR "cpia_goto_hi_power error\n");
- goto error;
- }
-
- if (usb_cpia_get_vp_version(dev, version) < 0) {
- printk(KERN_ERR "cpia_get_vp_version error\n");
- goto error;
- }
-
- if (debug >= 1) {
- printk(KERN_DEBUG "cpia: VP v%d rev %d\n", version[0], version[1]);
- printk(KERN_DEBUG "cpia: Camera Head ID %04X\n", (version[3] << 8) + version[2]);
- }
-
- /* Turn on continuous grab */
- if (usb_cpia_set_grab_mode(dev, 1) < 0) {
- printk(KERN_ERR "cpia_set_grab_mode error\n");
- goto error;
- }
-
- /* Set up the sensor to be 30fps */
- if (usb_cpia_set_sensor_fps(dev, 1, 0) < 0) {
- printk(KERN_ERR "cpia_set_sensor_fps error\n");
- goto error;
- }
-
- /* Set video into CIF mode, and order into YUYV mode */
- if (usb_cpia_set_format(dev, FORMAT_CIF, FORMAT_422,
- FORMAT_YUYV) < 0) {
- printk(KERN_ERR "cpia_set_format error\n");
- goto error;
- }
-
- /* Turn off compression */
- if (usb_cpia_set_compression(dev, COMP_DISABLED, DONT_DECIMATE) < 0) {
- printk(KERN_ERR "cpia_set_compression error\n");
- goto error;
- }
-
- cpia->compress = 0;
-
- return 0;
-
-error:
- video_unregister_device(&cpia->vdev);
- usb_driver_release_interface(&cpia_driver,
- &dev->actconfig->interface[0]);
-
- kfree(cpia);
-
- return -EBUSY;
-}
-
-static void * cpia_probe(struct usb_device *dev, unsigned int ifnum)
-{
- struct usb_interface_descriptor *interface;
- struct usb_cpia *cpia;
-
- /* We don't handle multi-config cameras */
- if (dev->descriptor.bNumConfigurations != 1)
- return NULL;
-
- interface = &dev->actconfig->interface[ifnum].altsetting[0];
-
- /* Is it a CPiA? */
- if (dev->descriptor.idVendor != 0x0553)
- return NULL;
- if (dev->descriptor.idProduct != 0x0002)
- return NULL;
-
- /* Checking vendor/product should be enough, but what the hell */
- if (interface->bInterfaceClass != 0xFF)
- return NULL;
- if (interface->bInterfaceSubClass != 0x00)
- return NULL;
-
- /* We found a CPiA */
- printk(KERN_INFO "USB CPiA camera found\n");
-
- if ((cpia = kmalloc(sizeof(*cpia), GFP_KERNEL)) == NULL) {
- printk(KERN_ERR "couldn't kmalloc cpia struct\n");
- return NULL;
- }
-
- memset(cpia, 0, sizeof(*cpia));
-
- cpia->dev = dev;
- cpia->iface = interface->bInterfaceNumber;
-
- if (!usb_cpia_configure(cpia)) {
- cpia->user=0;
- init_MUTEX(&cpia->lock); /* to 1 == available */
-
- return cpia;
- } else
- return NULL;
-}
-
-static void cpia_disconnect(struct usb_device *dev, void *ptr)
-{
- struct usb_cpia *cpia = (struct usb_cpia *) ptr;
-
- /* We don't want people trying to open up the device */
- if (!cpia->user)
- video_unregister_device(&cpia->vdev);
-
- usb_driver_release_interface(&cpia_driver,
- &cpia->dev->actconfig->interface[0]);
-
- cpia->dev = NULL;
- cpia->frame[0].grabstate = FRAME_ERROR;
- cpia->frame[1].grabstate = FRAME_ERROR;
- cpia->curframe = -1;
-
- /* This will cause the process to request another frame. */
- if (waitqueue_active(&cpia->frame[0].wq))
- wake_up_interruptible(&cpia->frame[0].wq);
-
- if (waitqueue_active(&cpia->frame[1].wq))
- wake_up_interruptible(&cpia->frame[1].wq);
-
- cpia->streaming = 0;
-
- /* Unschedule all of the iso td's */
- if (cpia->sbuf[1].urb) {
- cpia->sbuf[1].urb->next = NULL;
- usb_unlink_urb(cpia->sbuf[1].urb);
- usb_free_urb(cpia->sbuf[1].urb);
- cpia->sbuf[1].urb = NULL;
- }
- if (cpia->sbuf[0].urb) {
- cpia->sbuf[0].urb->next = NULL;
- usb_unlink_urb(cpia->sbuf[0].urb);
- usb_free_urb(cpia->sbuf[0].urb);
- cpia->sbuf[0].urb = NULL;
- }
-
- /* Free the memory */
- if (!cpia->user)
- kfree(cpia);
-}
-
-static struct usb_driver cpia_driver = {
- "cpia",
- cpia_probe,
- cpia_disconnect,
- { NULL, NULL }
-};
-
-int usb_cpia_init(void)
-{
- return usb_register(&cpia_driver);
-}
-
-void usb_cpia_cleanup(void)
-{
- usb_deregister(&cpia_driver);
-}
-
-#ifdef MODULE
-int init_module(void)
-{
- return usb_cpia_init();
-}
-
-void cleanup_module(void)
-{
- usb_cpia_cleanup();
-}
-#endif
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)