patch-2.3.20 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: 1710
- Date:
Thu Oct 7 10:17:09 1999
- Orig file:
v2.3.19/linux/drivers/usb/cpia.c
- Orig date:
Fri Sep 10 23:57:36 1999
diff -u --recursive --new-file v2.3.19/linux/drivers/usb/cpia.c linux/drivers/usb/cpia.c
@@ -28,452 +28,509 @@
#define CPIA_DEBUG /* Gobs of debugging info */
+/* Video Size 384 x 288 x 3 bytes for RGB */
#define MAX_FRAME_SIZE (384 * 288 * 3)
/*******************************/
/* Memory management functions */
/*******************************/
-/* convert virtual user memory address to physical address */
-/* (virt_to_phys only works for kmalloced kernel memory) */
+#define MDEBUG(x) do { } while(0) /* Debug memory management */
-static inline unsigned long uvirt_to_phys(unsigned long adr)
+/* 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)
{
- pgd_t *pgd;
- pmd_t *pmd;
- pte_t *ptep, pte;
-
- pgd = pgd_offset(current->mm, adr);
- if (pgd_none(*pgd))
- return 0;
- pmd = pmd_offset(pgd, adr);
- if (pmd_none(*pmd))
- return 0;
- ptep = pte_offset(pmd, adr/*&(~PGDIR_MASK)*/);
- pte = *ptep;
- if(pte_present(pte))
- return
- virt_to_phys((void *)(pte_page(pte)|(adr&(PAGE_SIZE-1))));
- return 0;
+ 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 = (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)
+static inline unsigned long uvirt_to_bus(unsigned long adr)
{
- return virt_to_bus(phys_to_virt(uvirt_to_phys(adr)));
-}
+ unsigned long kva, ret;
-/* convert virtual kernel memory address to physical address */
-/* (virt_to_phys only works for kmalloced kernel memory) */
+ 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_phys(unsigned long adr)
+static inline unsigned long kvirt_to_bus(unsigned long adr)
{
- return uvirt_to_phys(VMALLOC_VMADDR(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;
}
-static inline unsigned long kvirt_to_bus(unsigned long adr)
+/* 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)
{
- return uvirt_to_bus(VMALLOC_VMADDR(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)
+static void *rvmalloc(unsigned long size)
{
- void * mem;
+ 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)
- {
- memset(mem, 0, size); /* Clear the ram out, no junk to the user */
- adr=(unsigned long) mem;
- while (size > 0)
- {
- page = kvirt_to_phys(adr);
- mem_map_reserve(MAP_NR(phys_to_virt(page)));
- adr+=PAGE_SIZE;
- if (size > PAGE_SIZE)
- size-=PAGE_SIZE;
- else
- size=0;
- }
+ 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)
+static void rvfree(void *mem, unsigned long size)
{
unsigned long adr, page;
-
+
+ if (!mem)
+ return;
+
size += (PAGE_SIZE - 1);
size &= ~(PAGE_SIZE - 1);
- if (mem)
- {
- adr=(unsigned long) mem;
- while (size > 0)
- {
- page = kvirt_to_phys(adr);
- mem_map_unreserve(MAP_NR(phys_to_virt(page)));
- adr+=PAGE_SIZE;
- if (size > PAGE_SIZE)
- size-=PAGE_SIZE;
- else
- size=0;
- }
- vfree(mem);
+ 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);
}
-int usb_cpia_get_version(struct usb_device *dev, void *buf)
+static int usb_cpia_get_version(struct usb_device *dev, void *buf)
{
- devrequest dr;
-
- dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE) | 0x80;
- dr.request = USB_REQ_CPIA_GET_VERSION;
- dr.value = 0;
- dr.index = 0;
- dr.length = 4;
-
- return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, 4);
+ 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);
}
-int usb_cpia_get_pnp_id(struct usb_device *dev, void *buf)
+#ifdef NOTUSED
+static int usb_cpia_get_pnp_id(struct usb_device *dev, void *buf)
{
- devrequest dr;
-
- dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE) | 0x80;
- dr.request = USB_REQ_CPIA_GET_PNP_ID;
- dr.value = 0;
- dr.index = 0;
- dr.length = 6;
-
- return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, 6);
+ 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
-int usb_cpia_get_camera_status(struct usb_device *dev, void *buf)
+#ifdef NOTUSED
+static int usb_cpia_get_camera_status(struct usb_device *dev, void *buf)
{
- devrequest dr;
-
- dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE) | 0x80;
- dr.request = USB_REQ_CPIA_GET_CAMERA_STATUS;
- dr.value = 0;
- dr.index = 0;
- dr.length = 8;
-
- return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, 8);
+ 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
-int usb_cpia_goto_hi_power(struct usb_device *dev)
+static int usb_cpia_goto_hi_power(struct usb_device *dev)
{
- devrequest dr;
-
- dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
- dr.request = USB_REQ_CPIA_GOTO_HI_POWER;
- dr.value = 0;
- dr.index = 0;
- dr.length = 0;
-
- return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+ 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);
}
-int usb_cpia_get_vp_version(struct usb_device *dev, void *buf)
+static int usb_cpia_get_vp_version(struct usb_device *dev, void *buf)
{
- devrequest dr;
-
- dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
- dr.request = USB_REQ_CPIA_GET_VP_VERSION;
- dr.value = 0;
- dr.index = 0;
- dr.length = 4;
-
- return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, buf, 4);
+ 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);
}
-int usb_cpia_set_sensor_fps(struct usb_device *dev, int sensorbaserate, int sensorclkdivisor)
+static int usb_cpia_set_sensor_fps(struct usb_device *dev, int sensorbaserate, int sensorclkdivisor)
{
- devrequest dr;
-
- dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
- dr.request = USB_REQ_CPIA_SET_SENSOR_FPS;
- dr.value = (sensorclkdivisor << 8) + sensorbaserate;
- dr.index = 0;
- dr.length = 0;
-
- return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+ 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);
}
-int usb_cpia_grab_frame(struct usb_device *dev, int streamstartline)
+static int usb_cpia_grab_frame(struct usb_device *dev, int streamstartline)
{
- devrequest dr;
-
- dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
- dr.request = USB_REQ_CPIA_GRAB_FRAME;
- dr.value = streamstartline << 8;
- dr.index = 0;
- dr.length = 0;
-
- return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+ 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);
}
-int usb_cpia_upload_frame(struct usb_device *dev, int forceupload)
+static int usb_cpia_upload_frame(struct usb_device *dev, int forceupload)
{
- devrequest dr;
-
- dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
- dr.request = USB_REQ_CPIA_UPLOAD_FRAME;
- dr.value = forceupload;
- dr.index = 0;
- dr.length = 0;
-
- return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+ 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);
}
-int usb_cpia_set_grab_mode(struct usb_device *dev, int continuousgrab)
+static int usb_cpia_set_grab_mode(struct usb_device *dev, int continuousgrab)
{
- devrequest dr;
-
- dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
- dr.request = USB_REQ_CPIA_SET_GRAB_MODE;
- dr.value = continuousgrab;
- dr.index = 0;
- dr.length = 0;
-
- return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+ 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);
}
-int usb_cpia_set_format(struct usb_device *dev, int size, int subsample, int order)
+static int usb_cpia_set_format(struct usb_device *dev, int size, int subsample, int order)
{
- devrequest dr;
-
- dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
- dr.request = USB_REQ_CPIA_SET_FORMAT;
- dr.value = (subsample << 8) + size;
- dr.index = order;
- dr.length = 0;
-
- return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+ 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);
}
-int usb_cpia_set_compression(struct usb_device *dev, int compmode, int decimation)
+static int usb_cpia_set_roi(struct usb_device *dev, int colstart, int colend, int rowstart, int rowend)
{
- devrequest dr;
-
- dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
- dr.request = USB_REQ_CPIA_SET_COMPRESSION;
- dr.value = (decimation << 8) + compmode;
- dr.index = 0;
- dr.length = 0;
-
- return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+ 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);
}
-int usb_cpia_initstreamcap(struct usb_device *dev, int skipframes, int streamstartline)
+static int usb_cpia_set_compression(struct usb_device *dev, int compmode, int decimation)
{
- devrequest dr;
-
- dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
- dr.request = USB_REQ_CPIA_INIT_STREAM_CAP;
- dr.value = (streamstartline << 8) + skipframes;
- dr.index = 0;
- dr.length = 0;
-
- return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+ 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);
}
-int usb_cpia_finistreamcap(struct usb_device *dev)
+#ifdef NOTUSED
+static int usb_cpia_initstreamcap(struct usb_device *dev, int skipframes, int streamstartline)
{
- devrequest dr;
-
- dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
- dr.request = USB_REQ_CPIA_FINI_STREAM_CAP;
- dr.value = 0;
- dr.index = 0;
- dr.length = 0;
-
- return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+ 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);
}
-int usb_cpia_startstreamcap(struct usb_device *dev)
+static int usb_cpia_finistreamcap(struct usb_device *dev)
{
- devrequest dr;
-
- dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
- dr.request = USB_REQ_CPIA_START_STREAM_CAP;
- dr.value = 0;
- dr.index = 0;
- dr.length = 0;
-
- return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+ 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);
}
-int usb_cpia_endstreamcap(struct usb_device *dev)
+static int usb_cpia_startstreamcap(struct usb_device *dev)
{
- devrequest dr;
-
- dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
- dr.request = USB_REQ_CPIA_END_STREAM_CAP;
- dr.value = 0;
- dr.index = 0;
- dr.length = 0;
+ 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);
+}
- return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+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 l;
- int done;
- done = 0;
- while (!done && scratch_left(data)) {
- switch (cpia->state) {
+ 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:
{
- unsigned char *begin = data;
+ struct cpia_frame_header *header;
/* We need atleast 2 bytes for the magic value */
- if (scratch_left(data) < 2) {
- done = 1;
- break;
- }
+ if (scratch_left(data) < 2)
+ goto out;
+
+ header = (struct cpia_frame_header *)data;
- /* 0x1968 is magic */
- printk("header: %X\n", (*data << 8) + *(data + 1));
- if ((*data == 0x19) && (*(data + 1) == 0x68)) {
- cpia->state = STATE_HEADER;
- printk("moving to header\n");
+ 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) {
- done = 1;
- break;
- }
+ if (scratch_left(data) < 4)
+ goto out;
- printk("Scanning for end of frame\n");
+ /* See if we found the end of the frame */
while (scratch_left(data) >= 4) {
- if ((*data == 0xFF) &&
- (*(data + 1) == 0xFF) &&
- (*(data + 2) == 0xFF) &&
- (*(data + 3) == 0xFF)) {
+ if (*((__u32 *)data) == 0xFFFFFFFF) {
+printk("found end of frame\n");
data += 4;
- break;
+goto error;
}
data++;
}
-#ifdef CPIA_DEBUG
- printk("scan: scanned %d bytes\n", data-begin);
-#endif
break;
}
case STATE_HEADER:
/* We need atleast 64 bytes for the header */
- if (scratch_left(data) < 64) {
- done = 1;
- break;
- }
+ 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;
#ifdef CPIA_DEBUG
- printk("header: framerate %d\n", data[41]);
+ printk("cpia: frame size %dx%d\n",
+ frame->hdrwidth, frame->hdrheight);
+ printk("cpia: frame %scompressed\n",
+ frame->header.comp_enable ? "" : "not ");
#endif
- data += 64;
+ frame->scanstate = STATE_LINES;
+ frame->curline = 0;
- cpia->state = STATE_LINES;
-
break;
case STATE_LINES:
{
- unsigned char *begin = data;
- int found = 0;
-
- while (scratch_left(data)) {
- if (*data == 0xFD) {
- data++;
- found = 1;
- break;
- } else if ((*data == 0xFF) &&
- (scratch_left(data) >= 3) &&
- (*(data + 1) == 0xFF) &&
- (*(data + 2) == 0xFF) &&
- (*(data + 3) == 0xFF)) {
- data += 4;
- cpia->curline = 144;
- found = 1;
- break;
- }
-
- data++;
+ unsigned char *f, *end;
+ unsigned int len;
+ int i;
+ int y, u, y1, v, r, g, b;
+
+ /* We want atleast 2 bytes for the length */
+ if (scratch_left(data) < 2)
+ goto out;
+
+ /* Grab the length */
+ len = data[0] + (data[1] << 8);
+
+printk("line %d, %d bytes long\n", frame->curline, len);
+ /* Check to make sure it's nothing outrageous */
+ if (len > (frame->hdrwidth * 2) + 1) {
+ printk(KERN_INFO "cpia: bad length, resynching\n");
+ goto error;
}
- if (data-begin == 355 && cpia->frame[cpia->curframe].width != 64) {
- int i;
- char *f = cpia->frame[cpia->curframe].data, *b = begin;
-
- b += 2;
- f += (cpia->frame[cpia->curframe].width * 3) * cpia->curline;
-
- for (i = 0; i < 176; i++)
- f[(i * 3) + 0] =
- f[(i * 3) + 1] =
- f[(i * 3) + 2] =
- b[(i * 2)];
+ /* 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) {
+ printk(KERN_INFO "cpia: lost synch\n");
+end = data + len - 1 - 4;
+printk("%02X %02X %02X %02X %02X %02X %02X %02X\n",
+end[0], end[1],
+end[2], end[3],
+end[4], end[5],
+end[6], end[7]);
+ goto error;
}
- if (found) {
- cpia->curline++;
- if (cpia->curline >= 144) {
- wake_up(&cpia->wq);
- cpia->state = STATE_SCANNING;
- cpia->curline = 0;
- cpia->curframe = -1;
- done = 1;
+ /* 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);
+ 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;
+/*
+ f[0] = f[1] = f[2] = *data;
+ f += 3;
+ data += 2;
+ fp += 3;
+*/
+ }
}
} else {
- data = begin;
- done = 1;
+ /* 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);
+ }
}
-
+
+#ifdef CPIA_DEBUG
+ /* Make sure we found the end correctly */
+ if (*data != 0xFD)
+ printk("cpia: missed end!\n");
+#endif
+
+ /* Skip the last byte */
+ data++;
+
+ if (++frame->curline >= frame->hdrheight)
+ goto nextframe;
+
break;
}
}
}
+nextframe:
+ if (scratch_left(data) >= 4 && *((__u32 *)data) == 0xFFFFFFFF) {
+ data += 4;
+printk("end of frame found normally\n");
+}
+
+ frame->grabstate = FRAME_DONE;
+ cpia->curframe = -1;
+
+ /* This will cause the process to request another frame */
+ if (waitqueue_active(&frame->wq))
+ wake_up_interruptible(&frame->wq);
+
+ goto out;
+
+error:
+ frame->grabstate = FRAME_ERROR;
+ cpia->curframe = -1;
+ cpia->compress = 0;
+
+ /* This will cause the process to request another frame */
+ if (waitqueue_active(&frame->wq))
+ wake_up_interruptible(&frame->wq);
+
+out:
+printk("scanned %d bytes, %d left\n", data - cpia->scratch, scratch_left(data));
/* Grab the remaining */
l = scratch_left(data);
memmove(cpia->scratch, data, l);
-
cpia->scratchlen = l;
}
/*
- * For the moment there is no actual data compression (making blocks
- * of data contiguous). This just checks the "frames" array for errors.
+ * Make all of the blocks of data contiguous
*/
-static int cpia_compress_isochronous(struct usb_isoc_desc *isodesc)
+static int cpia_compress_isochronous(struct usb_cpia *cpia, struct usb_isoc_desc *isodesc)
{
- char *data = isodesc->data;
+ unsigned char *cdata, *data;
int i, totlen = 0;
+ cdata = isodesc->data;
+ data = cpia->scratch + cpia->scratchlen;
for (i = 0; i < isodesc->frame_count; i++) {
- int n = isodesc->frames [i].frame_length;
- int st = isodesc->frames [i].frame_status;
-
+ int n = isodesc->frames[i].frame_length;
#ifdef CPIA_DEBUG
- /* Debugging */
+ int st = isodesc->frames[i].frame_status;
+
if (st)
printk(KERN_DEBUG "cpia data error: [%d] len=%d, status=%X\n",
i, n, st);
#endif
+ if ((cpia->scratchlen + n) > SCRATCH_BUF_SIZE) {
+ printk(KERN_ERR "cpia: scratch buf overflow!\n");
+ return 0;
+ }
+
+ if (n)
+ memmove(data, cdata, n);
+ data += n;
+ totlen += n;
+ cpia->scratchlen += n;
+ cdata += isodesc->frame_size;
}
return totlen;
@@ -481,157 +538,114 @@
static int cpia_isoc_irq(int status, void *__buffer, int len, void *dev_id)
{
- struct usb_cpia *cpia = dev_id;
- struct usb_device *dev = cpia->dev;
+ struct usb_cpia *cpia = (struct usb_cpia *)dev_id;
struct cpia_sbuf *sbuf;
int i;
- char *p;
if (!cpia->streaming) {
printk("oops, not streaming, but interrupt\n");
return 0;
}
- if (cpia->curframe < 0) {
- if (cpia->frame[0].state == FRAME_READY) {
- cpia->curframe = 0;
- cpia->frame[0].state = FRAME_GRABBING;
-#ifdef CPIA_DEBUG
- printk("capturing to frame 0\n");
-#endif
- } else if (cpia->frame[1].state == FRAME_READY) {
- cpia->curframe = 1;
- cpia->frame[1].state = FRAME_GRABBING;
-#ifdef CPIA_DEBUG
- printk("capturing to frame 1\n");
-#endif
-#ifdef CPIA_DEBUG
- } else
- printk("no frame available\n");
-#else
- }
-#endif
- }
-
- sbuf = &cpia->sbuf[cpia->receivesbuf];
-
+ sbuf = &cpia->sbuf[cpia->cursbuf];
usb_kill_isoc(sbuf->isodesc);
- /* Do something to it now */
- sbuf->len = cpia_compress_isochronous(sbuf->isodesc);
+ /* Copy the data received into our scratch buffer */
+ len = cpia_compress_isochronous(cpia, sbuf->isodesc);
-#ifdef CPIA_DEBUG
- if (sbuf->len)
- printk("%d bytes received\n", sbuf->len);
-#endif
+printk("%d bytes received\n", len);
+ /* If we don't have a frame we're current working on, complain */
+ if (len) {
+ if (cpia->curframe < 0)
+ printk("cpia: received data, but no frame available\n");
+ else
+ cpia_parse_data(cpia);
+ }
- if (sbuf->len && cpia->curframe >= 0) {
- if (sbuf->len > (SCRATCH_BUF_SIZE - cpia->scratchlen)) {
- printk("overflow!\n");
- return 0;
- }
- memcpy(cpia->scratch + cpia->scratchlen, sbuf->data, sbuf->len);
- cpia->scratchlen += sbuf->len;
+ for (i = 0; i < FRAMES_PER_DESC; i++)
+ sbuf->isodesc->frames[i].frame_length = FRAME_SIZE_PER_DESC;
- cpia_parse_data(cpia);
- }
+ /* Move to the next sbuf */
+ cpia->cursbuf = (cpia->cursbuf + 1) % CPIA_NUMSBUF;
/* Reschedule this block of Isochronous desc */
- /*
- usb_run_isoc(sbuf->isodesc, NULL);
- */
-/*
- usb_schedule_isochronous(dev, sbuf->isodesc, cpia->sbuf[(cpia->receivesbuf + 2) % 3].isodesc);
-*/
-
- /* Move to the next one */
- cpia->receivesbuf = (cpia->receivesbuf + 1) % 3;
+ usb_run_isoc(sbuf->isodesc, cpia->sbuf[cpia->cursbuf].isodesc);
- return 1;
+ return -1;
}
-int cpia_init_isoc(struct usb_cpia *cpia)
+static int cpia_init_isoc(struct usb_cpia *cpia)
{
struct usb_device *dev = cpia->dev;
struct usb_isoc_desc *id;
int fx, err;
- cpia->receivesbuf = 0;
-
+ cpia->curframe = -1;
+ cpia->cursbuf = 0;
cpia->scratchlen = 0;
- cpia->curline = 0;
- cpia->state = STATE_SCANNING;
- /* ALT_ISOC is only doing double-buffering, not triple. */
- err = usb_init_isoc (dev, usb_rcvisocpipe (dev, 1), FRAMES_PER_DESC, cpia,
- &cpia->sbuf[0].isodesc);
- if (err)
- printk ("cpia_init_isoc: usb_init_isoc() ret. %d\n", err);
- err = usb_init_isoc (dev, usb_rcvisocpipe (dev, 1), FRAMES_PER_DESC, cpia,
- &cpia->sbuf[1].isodesc);
- if (err)
- printk ("cpia_init_isoc: usb_init_isoc() ret. %d\n", err);
+ /* We double buffer the Iso lists */
+ err = usb_init_isoc(dev, usb_rcvisocpipe(dev, 1), FRAMES_PER_DESC,
+ cpia, &cpia->sbuf[0].isodesc);
+ if (err) {
+ printk(KERN_ERR "cpia_init_isoc: usb_init_isoc() ret %d\n",
+ err);
+ return -ENOMEM;
+ }
- if (!cpia->sbuf[0].isodesc || !cpia->sbuf[1].isodesc) {
- if (cpia->sbuf[0].isodesc)
- usb_free_isoc (cpia->sbuf[0].isodesc);
- if (cpia->sbuf[1].isodesc)
- usb_free_isoc (cpia->sbuf[1].isodesc);
+ err = usb_init_isoc(dev, usb_rcvisocpipe(dev, 1), FRAMES_PER_DESC,
+ cpia, &cpia->sbuf[1].isodesc);
+ if (err) {
+ printk(KERN_ERR "cpia_init_isoc: usb_init_isoc() ret %d\n",
+ err);
+ usb_free_isoc (cpia->sbuf[0].isodesc);
return -ENOMEM;
}
-#if 0
- cpia->sbuf[0].isodesc = usb_allocate_isochronous(dev, usb_rcvisocpipe(dev,1), cpia->sbuf[0].data, STREAM_BUF_SIZE, 960, cpia_isoc_irq, cpia);
- cpia->sbuf[1].isodesc = usb_allocate_isochronous(dev, usb_rcvisocpipe(dev,1), cpia->sbuf[1].data, STREAM_BUF_SIZE, 960, cpia_isoc_irq, cpia);
- cpia->sbuf[2].isodesc = usb_allocate_isochronous(dev, usb_rcvisocpipe(dev,1), cpia->sbuf[2].data, STREAM_BUF_SIZE, 960, cpia_isoc_irq, cpia);
-#endif
#ifdef CPIA_DEBUG
printk("isodesc[0] @ %p\n", cpia->sbuf[0].isodesc);
printk("isodesc[1] @ %p\n", cpia->sbuf[1].isodesc);
-#if 0
- printk("isodesc[2] @ %p\n", cpia->sbuf[2].isodesc);
-#endif
#endif
/* Set the Isoc. desc. parameters. */
/* First for desc. [0] */
- id = cpia->sbuf [0].isodesc;
+ id = cpia->sbuf[0].isodesc;
id->start_type = START_ASAP;
id->callback_frames = 10; /* on every 10th frame */
id->callback_fn = cpia_isoc_irq;
id->data = cpia->sbuf[0].data;
id->buf_size = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
for (fx = 0; fx < FRAMES_PER_DESC; fx++)
- id->frames [fx].frame_length = FRAME_SIZE_PER_DESC;
+ id->frames[fx].frame_length = FRAME_SIZE_PER_DESC;
/* and the desc. [1] */
- id = cpia->sbuf [1].isodesc;
+ id = cpia->sbuf[1].isodesc;
id->start_type = 0; /* will follow the first desc. */
id->callback_frames = 10; /* on every 10th frame */
id->callback_fn = cpia_isoc_irq;
id->data = cpia->sbuf[1].data;
id->buf_size = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
for (fx = 0; fx < FRAMES_PER_DESC; fx++)
- id->frames [fx].frame_length = FRAME_SIZE_PER_DESC;
+ id->frames[fx].frame_length = FRAME_SIZE_PER_DESC;
- usb_run_isoc (cpia->sbuf[0].isodesc, NULL);
- usb_run_isoc (cpia->sbuf[1].isodesc, cpia->sbuf[0].isodesc);
-
-#if 0
- usb_schedule_isochronous(dev, cpia->sbuf[0].isodesc, NULL);
- usb_schedule_isochronous(dev, cpia->sbuf[1].isodesc, cpia->sbuf[0].isodesc);
- usb_schedule_isochronous(dev, cpia->sbuf[2].isodesc, cpia->sbuf[1].isodesc);
-#endif
+ usb_run_isoc(cpia->sbuf[0].isodesc, NULL);
+ usb_run_isoc(cpia->sbuf[1].isodesc, cpia->sbuf[0].isodesc);
#ifdef CPIA_DEBUG
printk("done scheduling\n");
#endif
- if (usb_set_interface(cpia->dev, 1, 3)) {
- printk("cpia_set_interface error\n");
- return -EINVAL;
+ /* Alternate interface 3 is is the biggest frame size */
+ if (usb_set_interface(cpia->dev, 1, 3) < 0) {
+ printk("usb_set_interface error\n");
+ return -EBUSY;
}
- usb_cpia_startstreamcap(cpia->dev);
+#if 0
+ if (usb_cpia_grab_frame(dev, 120) < 0) {
+ printk(KERN_INFO "cpia_grab_frame error\n");
+ return -EBUSY;
+ }
+#endif
cpia->streaming = 1;
#ifdef CPIA_DEBUG
@@ -641,41 +655,102 @@
return 0;
}
-void cpia_stop_isoc(struct usb_cpia *cpia)
+static void cpia_stop_isoc(struct usb_cpia *cpia)
{
- struct usb_device *dev = cpia->dev;
-
if (!cpia->streaming)
return;
cpia->streaming = 0;
- /* Stop the streaming */
- usb_cpia_endstreamcap(cpia->dev);
+ /* Turn off continuous grab */
+ if (usb_cpia_set_grab_mode(cpia->dev, 0) < 0) {
+ printk(KERN_INFO "cpia_set_grab_mode error\n");
+ return /* -EBUSY */;
+ }
+
+#if 0
+ if (usb_cpia_grab_frame(cpia->dev, 0) < 0) {
+ printk(KERN_INFO "cpia_grab_frame error\n");
+ return /* -EBUSY */;
+ }
+#endif
/* Set packet size to 0 */
- if (usb_set_interface(cpia->dev, 1, 0)) {
- printk("cpia_set_interface error\n");
+ if (usb_set_interface(cpia->dev, 1, 0) < 0) {
+ printk(KERN_INFO "usb_set_interface error\n");
return /* -EINVAL */;
}
/* Unschedule all of the iso td's */
- usb_kill_isoc (cpia->sbuf[1].isodesc);
- usb_kill_isoc (cpia->sbuf[0].isodesc);
-#if 0
- usb_unschedule_isochronous(dev, cpia->sbuf[2].isodesc);
- usb_unschedule_isochronous(dev, cpia->sbuf[1].isodesc);
- usb_unschedule_isochronous(dev, cpia->sbuf[0].isodesc);
-#endif
+ usb_kill_isoc(cpia->sbuf[1].isodesc);
+ usb_kill_isoc(cpia->sbuf[0].isodesc);
/* Delete them all */
- usb_free_isoc (cpia->sbuf[1].isodesc);
- usb_free_isoc (cpia->sbuf[0].isodesc);
-#if 0
- usb_delete_isochronous(dev, cpia->sbuf[2].isodesc);
- usb_delete_isochronous(dev, cpia->sbuf[1].isodesc);
- usb_delete_isochronous(dev, cpia->sbuf[0].isodesc);
-#endif
+ usb_free_isoc(cpia->sbuf[1].isodesc);
+ usb_free_isoc(cpia->sbuf[0].isodesc);
+}
+
+static int cpia_new_frame(struct usb_cpia *cpia, int framenum)
+{
+ struct cpia_frame *frame;
+ int width, height;
+
+printk("new frame %d\n", framenum);
+ if (framenum == -1) {
+ int i;
+ for (i = 0; i < CPIA_NUMFRAMES; i++)
+ if (cpia->frame[i].grabstate == FRAME_READY)
+ break;
+
+ if (i >= CPIA_NUMFRAMES) {
+ printk("no frame ready\n");
+ return 0;
+ }
+
+ framenum = i;
+printk("using frame %d\n", framenum);
+ }
+
+ if (cpia->curframe != -1 && cpia->curframe != framenum)
+ return 0;
+
+ frame = &cpia->frame[framenum];
+ width = frame->width;
+ height = frame->height;
+
+ /* 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 ? 1 : 0, 0) < 0) {
+ printk(KERN_INFO "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, 1) < 0) {
+ printk(KERN_INFO "cpia_upload_frame error\n");
+ return -EBUSY;
+ }
+
+ frame->grabstate = FRAME_GRABBING;
+ frame->scanstate = STATE_SCANNING;
+
+ cpia->curframe = framenum;
+
+ return 0;
}
/* Video 4 Linux API */
@@ -688,13 +763,14 @@
printk("cpia_open\n");
#endif
+ cpia->frame[0].grabstate = FRAME_UNUSED;
+ cpia->frame[1].grabstate = FRAME_UNUSED;
+
+ /* Allocate memory for the frame buffers */
cpia->fbuf = rvmalloc(2 * MAX_FRAME_SIZE);
if (!cpia->fbuf)
goto open_err_ret;
- cpia->frame[0].state = FRAME_DONE;
- cpia->frame[1].state = FRAME_DONE;
-
cpia->frame[0].data = cpia->fbuf;
cpia->frame[1].data = cpia->fbuf + MAX_FRAME_SIZE;
#ifdef CPIA_DEBUG
@@ -710,37 +786,17 @@
if (!cpia->sbuf[1].data)
goto open_err_on1;
-#if 0
- cpia->sbuf[0].data = kmalloc(STREAM_BUF_SIZE, GFP_KERNEL);
- if (!cpia->sbuf[0].data)
- goto open_err_on0;
-
- cpia->sbuf[1].data = kmalloc(STREAM_BUF_SIZE, GFP_KERNEL);
- if (!cpia->sbuf[1].data)
- goto open_err_on1;
-
- cpia->sbuf[2].data = kmalloc(STREAM_BUF_SIZE, GFP_KERNEL);
- if (!cpia->sbuf[2].data)
- goto open_err_on2;
-#endif
-
#ifdef CPIA_DEBUG
printk("sbuf[0] @ %p\n", cpia->sbuf[0].data);
printk("sbuf[1] @ %p\n", cpia->sbuf[1].data);
-#if 0
- printk("sbuf[2] @ %p\n", cpia->sbuf[2].data);
-#endif
#endif
- cpia->curframe = -1;
- cpia->receivesbuf = 0;
-
- usb_cpia_initstreamcap(cpia->dev, 0, 60);
-
err = cpia_init_isoc(cpia);
if (err)
goto open_err_on2;
+ MOD_INC_USE_COUNT;
+
return 0;
open_err_on2:
@@ -761,13 +817,12 @@
printk("cpia_close\n");
#endif
- cpia_stop_isoc(cpia);
+ MOD_DEC_USE_COUNT;
- usb_cpia_finistreamcap(cpia->dev);
+ cpia_stop_isoc(cpia);
rvfree(cpia->fbuf, 2 * MAX_FRAME_SIZE);
- kfree(cpia->sbuf[2].data);
kfree(cpia->sbuf[1].data);
kfree(cpia->sbuf[0].data);
}
@@ -791,23 +846,32 @@
{
struct video_capability b;
+#ifdef CPIA_DEBUG
+ printk("GCAP\n");
+#endif
+
strcpy(b.name, "CPiA USB Camera");
- b.type = VID_TYPE_CAPTURE /* | VID_TYPE_SUBCAPTURE */;
+ b.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
b.channels = 1;
b.audios = 0;
- b.maxwidth = 176 /* 352 */;
- b.maxheight = 144 /* 240 */;
- b.minwidth = 176 /* (Something small?) */;
- b.minheight = 144 /* " " */;
+ b.maxwidth = 352; /* CIF */
+ b.maxheight = 288; /* " */
+ b.minwidth = 176; /* QCIF */
+ b.minheight = 144; /* " */
if (copy_to_user(arg, &b, sizeof(b)))
return -EFAULT;
+
return 0;
}
case VIDIOCGCHAN:
{
struct video_channel v;
+#ifdef CPIA_DEBUG
+ printk("GCHAN\n");
+#endif
+
if (copy_from_user(&v, arg, sizeof(v)))
return -EFAULT;
if (v.channel != 0)
@@ -826,47 +890,14 @@
{
int v;
- if (copy_from_user(&v, arg, sizeof(v)))
- return -EFAULT;
-
- if (v != 0)
- return -EINVAL;
-
- return 0;
- }
- case VIDIOCGTUNER:
- {
- struct video_tuner v;
-
- if (copy_from_user(&v, arg, sizeof(v)))
- return -EFAULT;
-
- if (v.tuner)
- return -EINVAL;
-
- strcpy(v.name, "Format");
-
- v.rangelow = 0;
- v.rangehigh = 0;
- v.flags = 0;
- v.mode = VIDEO_MODE_AUTO;
-
- if (copy_to_user(arg, &v, sizeof(v)))
- return -EFAULT;
-
- return 0;
- }
- case VIDIOCSTUNER:
- {
- struct video_tuner v;
+#ifdef CPIA_DEBUG
+ printk("SCHAN\n");
+#endif
if (copy_from_user(&v, arg, sizeof(v)))
return -EFAULT;
- if (v.tuner)
- return -EINVAL;
-
- if (v.mode != VIDEO_MODE_AUTO)
+ if (v != 0)
return -EINVAL;
return 0;
@@ -875,6 +906,10 @@
{
struct video_picture p;
+#ifdef CPIA_DEBUG
+ printk("GPICT\n");
+#endif
+
p.colour = 0x8000; /* Damn British people :) */
p.hue = 0x8000;
p.brightness = 180 << 8; /* XXX */
@@ -895,6 +930,10 @@
{
struct video_picture p;
+#ifdef CPIA_DEBUG
+ printk("SPICT\n");
+#endif
+
if (copy_from_user(&p, arg, sizeof(p)))
return -EFAULT;
@@ -910,7 +949,7 @@
struct video_window vw;
#ifdef CPIA_DEBUG
- printk("VIDIOCSWIN\n");
+ printk("SWIN\n");
#endif
if (copy_from_user(&vw, arg, sizeof(vw)))
@@ -924,6 +963,8 @@
if (vw.width != 144)
return -EINVAL;
+ cpia->compress = 0;
+
return 0;
}
case VIDIOCGWIN:
@@ -931,7 +972,7 @@
struct video_window vw;
#ifdef CPIA_DEBUG
- printk("VIDIOCGWIN\n");
+ printk("GWIN\n");
#endif
vw.x = 0;
@@ -949,6 +990,9 @@
case VIDIOCGMBUF:
{
struct video_mbuf vm;
+#ifdef CPIA_DEBUG
+ printk("MBUF\n");
+#endif
memset(&vm, 0, sizeof(vm));
vm.size = MAX_FRAME_SIZE * 2;
@@ -965,6 +1009,7 @@
{
struct video_mmap vm;
+
if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm)))
return -EFAULT;
@@ -980,53 +1025,85 @@
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 free */
- cpia->frame[vm.frame].state = FRAME_READY;
+ /* Mark it as ready */
+ cpia->frame[vm.frame].grabstate = FRAME_READY;
- return 0;
+ return cpia_new_frame(cpia, vm.frame);
}
case VIDIOCSYNC:
{
int frame;
+#ifdef CPIA_DEBUG
+ printk("SYNC\n");
+#endif
+
if (copy_from_user((void *)&frame, arg, sizeof(int)))
return -EFAULT;
#ifdef CPIA_DEBUG
- printk("syncing to frame %d\n", frame);
+ printk("cpia: syncing to frame %d\n", frame);
#endif
- switch (cpia->frame[frame].state) {
- case FRAME_UNUSED:
- return -EINVAL;
- case FRAME_READY:
- case FRAME_GRABBING:
- interruptible_sleep_on(&cpia->wq);
- case FRAME_DONE:
- cpia->frame[frame].state = FRAME_UNUSED;
- break;
+
+ switch (cpia->frame[frame].grabstate) {
+ case FRAME_UNUSED:
+ return -EINVAL;
+ case FRAME_READY:
+ case FRAME_GRABBING:
+redo:
+ do {
+printk("enter sleeping\n");
+ interruptible_sleep_on(&cpia->frame[frame].wq);
+printk("back from sleeping\n");
+ 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;
}
+
#ifdef CPIA_DEBUG
- printk("synced to frame %d\n", frame);
+ printk("cpia: finished, synced to frame %d\n", frame);
#endif
- return 0;
+
+ return cpia_new_frame(cpia, -1);
}
+ case VIDIOCKEY:
+ return 0;
case VIDIOCCAPTURE:
return -EINVAL;
case VIDIOCGFBUF:
- return -EINVAL;
case VIDIOCSFBUF:
return -EINVAL;
- case VIDIOCKEY:
- return 0;
- case VIDIOCGFREQ:
+ case VIDIOCGTUNER:
+ case VIDIOCSTUNER:
return -EINVAL;
+ case VIDIOCGFREQ:
case VIDIOCSFREQ:
return -EINVAL;
case VIDIOCGAUDIO:
- return -EINVAL;
case VIDIOCSAUDIO:
return -EINVAL;
default:
@@ -1037,17 +1114,14 @@
static long cpia_read(struct video_device *dev, char *buf, unsigned long count, int noblock)
{
+#if 0
struct usb_cpia *cpia = (struct usb_cpia *)dev;
int len;
+#endif
#ifdef CPIA_DEBUG
printk("cpia_read: %ld bytes\n", count);
#endif
-#if 0
- len = cpia_capture(cpia, buf, count);
-
- return len;
-#endif
return 0;
}
@@ -1064,17 +1138,17 @@
return -EINVAL;
pos = (unsigned long)cpia->fbuf;
- while (size > 0)
- {
- page = kvirt_to_phys(pos);
+ 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;
+
+ start += PAGE_SIZE;
+ pos += PAGE_SIZE;
if (size > PAGE_SIZE)
- size-=PAGE_SIZE;
+ size -= PAGE_SIZE;
else
- size=0;
+ size = 0;
}
return 0;
@@ -1097,87 +1171,92 @@
0
};
-static void usb_cpia_configure(struct usb_cpia *cpia)
+static int usb_cpia_configure(struct usb_cpia *cpia)
{
struct usb_device *dev = cpia->dev;
unsigned char version[4];
- unsigned char pnpid[6];
- unsigned char camerastat[8];
- unsigned char *buf;
- if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) {
- printk (KERN_INFO " Failed usb_set_configuration: CPIA\n");
- return;
+ if (usb_set_configuration(dev, dev->config[0].bConfigurationValue) < 0) {
+ printk(KERN_INFO "cpia: usb_set_configuration failed\n");
+ return -EBUSY;
}
- if (usb_cpia_get_version(dev, version)) {
- printk("cpia_get_version error\n");
- return;
+ /* Set packet size to 0 */
+ if (usb_set_interface(dev, 1, 0) < 0) {
+ printk(KERN_INFO "usb_set_interface error\n");
+ return -EBUSY;
}
- printk("cpia: Firmware v%d.%d, VC Hardware v%d.%d\n",
- version[0], version[1], version[2], version[3]);
-
- if (usb_cpia_get_pnp_id(dev, pnpid)) {
- printk("cpia_get_pnp_id error\n");
- return;
+ if (usb_cpia_get_version(dev, version) < 0) {
+ printk(KERN_INFO "cpia_get_version error\n");
+ return -EBUSY;
}
- printk("cpia: PnP Id: Vendor: %X, Product: %X, Revision: %X\n",
- (pnpid[1] << 8) + pnpid[0], (pnpid[3] << 8) + pnpid[2],
- (pnpid[5] << 8) + pnpid[4]);
+ printk("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->wq);
+ 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("video_register_device failed\n");
- return;
+ printk(KERN_INFO "video_register_device failed\n");
+ return -EBUSY;
}
- if (usb_cpia_goto_hi_power(dev)) {
- printk("cpia_goto_hi_power error\n");
- return;
+ if (usb_cpia_goto_hi_power(dev) < 0) {
+ printk(KERN_INFO "cpia_goto_hi_power error\n");
+ goto error;
}
- if (usb_cpia_get_vp_version(dev, version)) {
- printk("cpia_get_vp_version error\n");
- return;
+ if (usb_cpia_get_vp_version(dev, version) < 0) {
+ printk(KERN_INFO "cpia_get_vp_version error\n");
+ goto error;
}
printk("cpia: VP v%d rev %d\n", version[0], version[1]);
printk("cpia: Camera Head ID %04X\n", (version[3] << 8) + version[2]);
- /* Turn off continuous grab */
- if (usb_cpia_set_grab_mode(dev, 1)) {
- printk("cpia_set_grab_mode error\n");
- return;
+ /* Turn on continuous grab */
+ if (usb_cpia_set_grab_mode(dev, 1) < 0) {
+ printk(KERN_INFO "cpia_set_grab_mode error\n");
+ goto error;
}
/* Set up the sensor to be 30fps */
- if (usb_cpia_set_sensor_fps(dev, 1, 0)) {
- printk("cpia_set_sensor_fps error\n");
- return;
+ if (usb_cpia_set_sensor_fps(dev, 1, 0) < 0) {
+ printk(KERN_INFO "cpia_set_sensor_fps error\n");
+ goto error;
}
- /* Set video into QCIF mode, and order into YUYV mode */
- if (usb_cpia_set_format(dev, CPIA_QCIF, 1, CPIA_YUYV)) {
- printk("cpia_set_format error\n");
- return;
+ /* Set video into CIF mode, and order into YUYV mode */
+ if (usb_cpia_set_format(dev, CPIA_CIF, 1, CPIA_YUYV) < 0) {
+ printk(KERN_INFO "cpia_set_format error\n");
+ goto error;
}
/* Turn off compression */
- if (usb_cpia_set_compression(dev, 0, 0)) {
- printk("cpia_set_compression error\n");
- return;
+ if (usb_cpia_set_compression(dev, 0, 0) < 0) {
+ printk(KERN_INFO "cpia_set_compression error\n");
+ goto error;
}
+
+ cpia->compress = 0;
+
+ return 0;
+
+error:
+ video_unregister_device(&cpia->vdev);
+
+ kfree(cpia);
+
+ return -EBUSY;
}
static int cpia_probe(struct usb_device *dev)
{
struct usb_interface_descriptor *interface;
- struct usb_endpoint_descriptor *endpoint;
struct usb_cpia *cpia;
/* We don't handle multi-config cameras */
@@ -1191,6 +1270,8 @@
return -1;
if (dev->descriptor.idProduct != 0x0002)
return -1;
+
+ /* Checking vendor/product should be enough, but what the hell */
if (interface->bInterfaceClass != 0xFF)
return -1;
if (interface->bInterfaceSubClass != 0x00)
@@ -1209,9 +1290,7 @@
dev->private = cpia;
cpia->dev = dev;
- usb_cpia_configure(cpia);
-
- return 0;
+ return usb_cpia_configure(cpia);
}
static void cpia_disconnect(struct usb_device *dev)
@@ -1231,9 +1310,6 @@
{ NULL, NULL }
};
-/*
- * This should be a separate module.
- */
int usb_cpia_init(void)
{
usb_register(&cpia_driver);
@@ -1241,6 +1317,11 @@
return 0;
}
+void usb_cpia_cleanup(void)
+{
+ usb_deregister(&cpia_driver);
+}
+
#ifdef MODULE
int init_module(void)
{
@@ -1249,6 +1330,7 @@
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)