📄 cpia.c
字号:
*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 0printk("cpia_isoc_irq: %p status %d, errcount = %d, length = %d\n", urb, urb->status, urb->error_count, urb->actual_length);#endif if (!cpia->streaming) { if (debug >= 1) printk(KERN_DEBUG "cpia: oops, not streaming, but interrupt\n"); return; } sbuf = &cpia->sbuf[cpia->cursbuf]; // usb_kill_isoc(sbuf->isodesc); /* 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; /* Reschedule this block of Isochronous desc */ // usb_run_isoc(sbuf->isodesc, cpia->sbuf[cpia->cursbuf].isodesc); return;}static int cpia_init_isoc(struct usb_cpia *cpia){ struct usb_device *dev = cpia->dev; 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 */// err = usb_init_isoc(dev, usb_rcvisocpipe(dev, 1), FRAMES_PER_DESC, cpia, &cpia->sbuf[0].isodesc); 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 = dev; urb->context = cpia; urb->pipe = usb_rcvisocpipe(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 = dev; urb->context = cpia; urb->pipe = usb_rcvisocpipe(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_run_isoc(0) ret %d\n", err); err = usb_submit_urb(cpia->sbuf[1].urb); if (err) printk(KERN_ERR "cpia_init_isoc: usb_run_isoc(1) ret %d\n", err); cpia->streaming = 1; return 0;}static void cpia_stop_isoc(struct usb_cpia *cpia){ if (!cpia->streaming) 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 */; } /* Unschedule all of the iso td's */ usb_unlink_urb(cpia->sbuf[1].urb); usb_unlink_urb(cpia->sbuf[0].urb); cpia->streaming = 0; /* Delete them all */ usb_free_urb(cpia->sbuf[1].urb); usb_free_urb(cpia->sbuf[0].urb);}static int cpia_new_frame(struct usb_cpia *cpia, int framenum){ struct cpia_frame *frame; int width, height; /* 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);}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; 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; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -