📄 quickcam_messenger.c
字号:
if ((fhdr->id) == cpu_to_be16(0x8001)) { RingQueue_Enqueue(&uvd->dp, marker, 4); totaldata += 4; continue; } if ((fhdr->id & cpu_to_be16(0xFF00)) == cpu_to_be16(0x0200)) { RingQueue_Enqueue(&uvd->dp, cdata, datalen); totaldata += datalen; } framelen -= datalen; cdata += datalen; } return totaldata;}static int qcm_compress_iso(struct uvd *uvd, struct urb *dataurb){ int totlen; int i; unsigned char *cdata; totlen=0; for (i = 0; i < dataurb->number_of_packets; i++) { int n = dataurb->iso_frame_desc[i].actual_length; int st = dataurb->iso_frame_desc[i].status; cdata = dataurb->transfer_buffer + dataurb->iso_frame_desc[i].offset; if (st < 0) { dev_warn(&uvd->dev->dev, "Data error: packet=%d. len=%d. status=%d.\n", i, n, st); uvd->stats.iso_err_count++; continue; } if (!n) continue; totlen += qcm_process_frame(uvd, cdata, n); } return totlen;}static void resubmit_urb(struct uvd *uvd, struct urb *urb){ int ret; urb->dev = uvd->dev; ret = usb_submit_urb(urb, GFP_ATOMIC); if (ret) err("usb_submit_urb error (%d)", ret);}#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)static void qcm_isoc_irq(struct urb *urb, struct pt_regs *regs)#elsestatic void qcm_isoc_irq(struct urb *urb)#endif{ int len; struct uvd *uvd = urb->context; if (!CAMERA_IS_OPERATIONAL(uvd)) return; if (!uvd->streaming) return; uvd->stats.urb_count++; if (!urb->actual_length) { resubmit_urb(uvd, urb); return; } len = qcm_compress_iso(uvd, urb); resubmit_urb(uvd, urb); uvd->stats.urb_length = len; uvd->stats.data_count += len; if (len) RingQueue_WakeUpInterruptible(&uvd->dp);}static int qcm_start_data(struct uvd *uvd){ struct qcm *cam = (struct qcm *) uvd->user_data; int i; int errflag; int pktsz; int err; pktsz = uvd->iso_packet_len; if (!CAMERA_IS_OPERATIONAL(uvd)) { err("Camera is not operational"); return -EFAULT; } err = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltActive); if (err < 0) { err("usb_set_interface error"); uvd->last_error = err; return -EBUSY; } for (i=0; i < USBVIDEO_NUMSBUF; i++) { int j, k; struct urb *urb = uvd->sbuf[i].urb; urb->dev = uvd->dev; urb->context = uvd; urb->pipe = usb_rcvisocpipe(uvd->dev, uvd->video_endp); urb->interval = 1; urb->transfer_flags = URB_ISO_ASAP; urb->transfer_buffer = uvd->sbuf[i].data; urb->complete = qcm_isoc_irq; urb->number_of_packets = FRAMES_PER_DESC; urb->transfer_buffer_length = pktsz * FRAMES_PER_DESC; for (j=k=0; j < FRAMES_PER_DESC; j++, k += pktsz) { urb->iso_frame_desc[j].offset = k; urb->iso_frame_desc[j].length = pktsz; } } uvd->streaming = 1; uvd->curframe = -1; for (i=0; i < USBVIDEO_NUMSBUF; i++) { errflag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL); if (errflag) err ("usb_submit_isoc(%d) ret %d", i, errflag); } CHECK_RET(err, qcm_setup_input_int(cam, uvd)); CHECK_RET(err, qcm_camera_on(uvd)); return 0;}static void qcm_stop_data(struct uvd *uvd){ struct qcm *cam = (struct qcm *) uvd->user_data; int i, j; int ret; if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL)) return; ret = qcm_camera_off(uvd); if (ret) dev_warn(&uvd->dev->dev, "couldn't turn the cam off.\n"); uvd->streaming = 0; /* Unschedule all of the iso td's */ for (i=0; i < USBVIDEO_NUMSBUF; i++) usb_kill_urb(uvd->sbuf[i].urb); qcm_stop_int_data(cam); if (!uvd->remove_pending) { /* Set packet size to 0 */ j = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltInactive); if (j < 0) { err("usb_set_interface() error %d.", j); uvd->last_error = j; } }}static void qcm_process_isoc(struct uvd *uvd, struct usbvideo_frame *frame){ struct qcm *cam = (struct qcm *) uvd->user_data; int x; struct rgb *rgbL0; struct rgb *rgbL1; struct bayL0 *bayL0; struct bayL1 *bayL1; int hor,ver,hordel,verdel; assert(frame != NULL); switch (cam->size) { case SIZE_160X120: hor = 162; ver = 124; hordel = 1; verdel = 2; break; case SIZE_320X240: default: hor = 324; ver = 248; hordel = 2; verdel = 4; break; } if (frame->scanstate == ScanState_Scanning) { while (RingQueue_GetLength(&uvd->dp) >= 4 + (hor*verdel + hordel)) { if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) && (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xff) && (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x00) && (RING_QUEUE_PEEK(&uvd->dp, 3) == 0xff)) { frame->curline = 0; frame->scanstate = ScanState_Lines; frame->frameState = FrameState_Grabbing; RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 4); /* * if we're starting, we need to discard the first * 4 lines of y bayer data * and the first 2 gr elements of x bayer data */ RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, (hor*verdel + hordel)); break; } RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1); } } if (frame->scanstate == ScanState_Scanning) return; /* now we can start processing bayer data so long as we have at least * 2 lines worth of data. this is the simplest demosaicing method that * I could think of. I use each 2x2 bayer element without interpolation * to generate 4 rgb pixels. */ while ( frame->curline < cam->height && (RingQueue_GetLength(&uvd->dp) >= hor*2)) { /* get 2 lines of bayer for demosaicing * into 2 lines of RGB */ RingQueue_Dequeue(&uvd->dp, cam->scratch, hor*2); bayL0 = (struct bayL0 *) cam->scratch; bayL1 = (struct bayL1 *) (cam->scratch + hor); /* frame->curline is the rgb y line */ rgbL0 = (struct rgb *) ( frame->data + (cam->width*3*frame->curline)); /* w/2 because we're already doing 2 pixels */ rgbL1 = rgbL0 + (cam->width/2); for (x=0; x < cam->width; x+=2) { rgbL0->r = bayL0->r; rgbL0->g = bayL0->g; rgbL0->b = bayL1->b; rgbL0->r2 = bayL0->r; rgbL0->g2 = bayL1->g; rgbL0->b2 = bayL1->b; rgbL1->r = bayL0->r; rgbL1->g = bayL1->g; rgbL1->b = bayL1->b; rgbL1->r2 = bayL0->r; rgbL1->g2 = bayL1->g; rgbL1->b2 = bayL1->b; rgbL0++; rgbL1++; bayL0++; bayL1++; } frame->seqRead_Length += cam->width*3*2; frame->curline += 2; } /* See if we filled the frame */ if (frame->curline == cam->height) { frame->frameState = FrameState_Done_Hold; frame->curline = 0; uvd->curframe = -1; uvd->stats.frame_num++; }}/* taken from konicawc */static int qcm_set_video_mode(struct uvd *uvd, struct video_window *vw){ int ret; int newsize; int oldsize; int x = vw->width; int y = vw->height; struct qcm *cam = (struct qcm *) uvd->user_data; if (x > 0 && y > 0) { DEBUG(2, "trying to find size %d,%d", x, y); for (newsize = 0; newsize <= MAX_FRAME_SIZE; newsize++) { if ((camera_sizes[newsize].width == x) && (camera_sizes[newsize].height == y)) break; } } else newsize = cam->size; if (newsize > MAX_FRAME_SIZE) { DEBUG(1, "couldn't find size %d,%d", x, y); return -EINVAL; } if (newsize == cam->size) { DEBUG(1, "Nothing to do"); return 0; } qcm_stop_data(uvd); if (cam->size != newsize) { oldsize = cam->size; cam->size = newsize; ret = qcm_set_camera_size(uvd); if (ret) { err("Couldn't set camera size, err=%d",ret); /* restore the original size */ cam->size = oldsize; return ret; } } /* Flush the input queue and clear any current frame in progress */ RingQueue_Flush(&uvd->dp); if (uvd->curframe != -1) { uvd->frame[uvd->curframe].curline = 0; uvd->frame[uvd->curframe].seqRead_Length = 0; uvd->frame[uvd->curframe].seqRead_Index = 0; } CHECK_RET(ret, qcm_start_data(uvd)); return 0;}static int qcm_configure_video(struct uvd *uvd){ int ret; memset(&uvd->vpic, 0, sizeof(uvd->vpic)); memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old)); uvd->vpic.colour = colour; uvd->vpic.hue = hue; uvd->vpic.brightness = brightness; uvd->vpic.contrast = contrast; uvd->vpic.whiteness = whiteness; uvd->vpic.depth = 24; uvd->vpic.palette = VIDEO_PALETTE_RGB24; memset(&uvd->vcap, 0, sizeof(uvd->vcap)); strcpy(uvd->vcap.name, "QCM USB Camera"); uvd->vcap.type = VID_TYPE_CAPTURE; uvd->vcap.channels = 1; uvd->vcap.audios = 0; uvd->vcap.minwidth = camera_sizes[SIZE_160X120].width; uvd->vcap.minheight = camera_sizes[SIZE_160X120].height; uvd->vcap.maxwidth = camera_sizes[SIZE_320X240].width; uvd->vcap.maxheight = camera_sizes[SIZE_320X240].height; memset(&uvd->vchan, 0, sizeof(uvd->vchan)); uvd->vchan.flags = 0 ; uvd->vchan.tuners = 0; uvd->vchan.channel = 0; uvd->vchan.type = VIDEO_TYPE_CAMERA; strcpy(uvd->vchan.name, "Camera"); CHECK_RET(ret, qcm_sensor_init(uvd)); return 0;}static int qcm_probe(struct usb_interface *intf, const struct usb_device_id *devid){ int err; struct uvd *uvd; struct usb_device *dev = interface_to_usbdev(intf); struct qcm *cam; size_t buffer_size; unsigned char video_ep; struct usb_host_interface *interface; struct usb_endpoint_descriptor *endpoint; int i,j; unsigned int ifacenum, ifacenum_inact=0; __le16 sensor_id; /* we don't support multiconfig cams */ if (dev->descriptor.bNumConfigurations != 1) return -ENODEV; /* first check for the video interface and not * the audio interface */ interface = &intf->cur_altsetting[0]; if ((interface->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC) || (interface->desc.bInterfaceSubClass != USB_CLASS_VENDOR_SPEC)) return -ENODEV; /* walk through each endpoint in each setting in the interface stop when we find the one that's an isochronous IN endpoint. */ for (i=0; i < intf->num_altsetting; i++) { interface = &intf->cur_altsetting[i]; ifacenum = interface->desc.bAlternateSetting; /* walk the end points */ for (j=0; j < interface->desc.bNumEndpoints; j++) { endpoint = &interface->endpoint[j].desc; if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) != USB_DIR_IN) continue; /* not input then not good */ buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); if (!buffer_size) { ifacenum_inact = ifacenum; continue; /* 0 pkt size is not what we want */ } if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_ISOC) { video_ep = endpoint->bEndpointAddress; /* break out of the search */ goto good_videoep; } } } /* failed out since nothing useful was found */ err("No suitable endpoint was found\n"); return -ENODEV;good_videoep: /* disable isochronous stream before doing anything else */ err = qcm_stv_setb(dev, STV_ISO_ENABLE, 0); if (err < 0) { err("Failed to disable sensor stream"); return -EIO; } /* Check that this is the same unknown sensor that is known to work. This sensor is suspected to be the ST VV6422C001. I'll check the same value that the qc-usb driver checks. This value is probably not even the sensor ID since it matches the USB dev ID. Oh well. If it doesn't match, it's probably a diff sensor so exit and apologize. */ err = qcm_stv_getw(dev, CMOS_SENSOR_IDREV, &sensor_id); if (err < 0) { err("Couldn't read sensor values. Err %d\n",err); return err; } if (sensor_id != cpu_to_le16(0x08F0)) { err("Sensor ID %x != %x. Unsupported. Sorry\n", le16_to_cpu(sensor_id), (0x08F0)); return -ENODEV; } uvd = usbvideo_AllocateDevice(cams); if (!uvd) return -ENOMEM; cam = (struct qcm *) uvd->user_data; /* buf for doing demosaicing */ cam->scratch = kmalloc(324*2, GFP_KERNEL); if (!cam->scratch) /* uvd freed in dereg */ return -ENOMEM; /* yes, if we fail after here, cam->scratch gets freed by qcm_free_uvd */ err = qcm_alloc_int_urb(cam); if (err < 0) return err; /* yes, if we fail after here, int urb gets freed by qcm_free_uvd */ RESTRICT_TO_RANGE(size, SIZE_160X120, SIZE_320X240); cam->width = camera_sizes[size].width; cam->height = camera_sizes[size].height; cam->size = size; uvd->debug = debug; uvd->flags = 0; uvd->dev = dev; uvd->iface = intf->altsetting->desc.bInterfaceNumber; uvd->ifaceAltActive = ifacenum; uvd->ifaceAltInactive = ifacenum_inact; uvd->video_endp = video_ep; uvd->iso_packet_len = buffer_size; uvd->paletteBits = 1L << VIDEO_PALETTE_RGB24; uvd->defaultPalette = VIDEO_PALETTE_RGB24; uvd->canvas = VIDEOSIZE(320, 240); uvd->videosize = VIDEOSIZE(cam->width, cam->height); err = qcm_configure_video(uvd); if (err) { err("failed to configure video settings"); return err; } err = usbvideo_RegisterVideoDevice(uvd); if (err) { /* the uvd gets freed in Deregister */ err("usbvideo_RegisterVideoDevice() failed."); return err; } uvd->max_frame_size = (320 * 240 * 3); qcm_register_input(cam, dev); usb_set_intfdata(intf, uvd); return 0;}static void qcm_free_uvd(struct uvd *uvd){ struct qcm *cam = (struct qcm *) uvd->user_data; kfree(cam->scratch); qcm_unregister_input(cam); qcm_free_int(cam);}static struct usbvideo_cb qcm_driver = { .probe = qcm_probe, .setupOnOpen = qcm_setup_on_open, .processData = qcm_process_isoc, .setVideoMode = qcm_set_video_mode, .startDataPump = qcm_start_data, .stopDataPump = qcm_stop_data, .adjustPicture = qcm_adjust_picture, .userFree = qcm_free_uvd};static int __init qcm_init(void){ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" DRIVER_DESC "\n"); return usbvideo_register( &cams, MAX_CAMERAS, sizeof(struct qcm), "QCM", &qcm_driver, THIS_MODULE, qcm_table);}static void __exit qcm_exit(void){ usbvideo_Deregister(&cams);}module_param(size, int, 0);MODULE_PARM_DESC(size, "Initial Size 0: 160x120 1: 320x240");module_param(colour, int, 0);MODULE_PARM_DESC(colour, "Initial colour");module_param(hue, int, 0);MODULE_PARM_DESC(hue, "Initial hue");module_param(brightness, int, 0);MODULE_PARM_DESC(brightness, "Initial brightness");module_param(contrast, int, 0);MODULE_PARM_DESC(contrast, "Initial contrast");module_param(whiteness, int, 0);MODULE_PARM_DESC(whiteness, "Initial whiteness");#ifdef CONFIG_USB_DEBUGmodule_param(debug, int, S_IRUGO | S_IWUSR);MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");#endifmodule_init(qcm_init);module_exit(qcm_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("Jaya Kumar");MODULE_DESCRIPTION("QCM USB Camera");MODULE_SUPPORTED_DEVICE("QCM USB Camera");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -