📄 gspca_core.c
字号:
/* Can we find a frame start */ if (sequenceNumber == 0) { PDEBUG(3, "spca50x: Found Frame Start!, framenum = %d", spca50x->curframe);// Start of frame is implicit end of previous frame// Check for a previous frame and finish it off if one exists if (frame->scanstate == STATE_LINES) { if (frame->format != VIDEO_PALETTE_RAW_JPEG) {/* overflow ? */ ms_times_now = spca5xx_gettimes(); if (ms_times_now < spca50x->last_times) spca50x->last_times = 0; spin_lock(&spca50x->v4l_lock); ms_times_before = spca50x->last_times + spca50x->dtimes; spin_unlock(&spca50x->v4l_lock); if (ms_times_now >= ms_times_before) { PDEBUG(2, "Decode frame last %d", (int) (ms_times_now - spca50x-> last_times)); spca50x->last_times = ms_times_now;/* Decode the frame one at a times or drop*/ if(!atomic_read(&spca50x->in_use)){ atomic_set(&spca50x->in_use,1); spca50x->spca5xx_tasklet.data = (unsigned long) frame; tasklet_schedule(&spca50x-> spca5xx_tasklet); } else frame->grabstate = FRAME_ERROR; } else frame->grabstate = FRAME_ERROR; } else {/* RAW DATA stream */ frame->grabstate = FRAME_DONE; if (waitqueue_active(&frame->wq)) wake_up_interruptible(&frame-> wq); }// If someone decided to wait for ANY frame - wake him up if (waitqueue_active(&spca50x->wq)) wake_up_interruptible(&spca50x->wq); frame = spca50x_next_frame(spca50x, cdata); } else frame->scanstate = STATE_LINES; }/* Are we in a frame? */ if (frame == NULL || frame->scanstate != STATE_LINES) continue; frame->last_packet = sequenceNumber; pData = cdata + iPix; // Skip packet header (1 or 10 bytes)// Consume data PDEBUG(5, "Processing packet seq %d,length %d,totlength %d", frame->last_packet, datalength, frame->totlength);/* this copy consume input data from the isoc stream */ if ((datalength > 0)) { memcpy(frame->highwater, pData, datalength); frame->highwater += datalength; frame->totlength += datalength; } } return 0;}/****************************************************************************** Buffer management****************************************************************************/static intspca50x_alloc(struct usb_spca50x *spca50x){ int i; PDEBUG(4, "entered"); down(&spca50x->buf_lock); if (spca50x->buf_state == BUF_ALLOCATED) goto out; spca50x->tmpBuffer = rvmalloc(MAX_FRAME_SIZE); if (!spca50x->tmpBuffer) goto error; spca50x->fbuf = rvmalloc(SPCA50X_NUMFRAMES * MAX_DATA_SIZE); if (!spca50x->fbuf) goto error; for (i = 0; i < SPCA50X_NUMFRAMES; i++) { spca50x->frame[i].tmpbuffer = spca50x->tmpBuffer; spca50x->frame[i].decoder = &spca50x->maindecode; //connect each frame to the main data decoding spca50x->frame[i].spca50x_dev = spca50x; //refind the whole structure spca50x->frame[i].grabstate = FRAME_UNUSED; spca50x->frame[i].scanstate = STATE_SCANNING; spca50x->frame[i].data = spca50x->fbuf + i * MAX_DATA_SIZE; spca50x->frame[i].highwater = spca50x->frame[i].data; memset(&spca50x->frame[i].pictsetting, 0, sizeof (struct pictparam)); PDEBUG(4, "frame[%d] @ %p", i, spca50x->frame[i].data); } spca50x->buf_state = BUF_ALLOCATED; out: up(&spca50x->buf_lock); PDEBUG(4, "leaving"); return 0; error: if (spca50x->fbuf) { rvfree(spca50x->fbuf, SPCA50X_NUMFRAMES * MAX_DATA_SIZE); spca50x->fbuf = NULL; } if (spca50x->tmpBuffer) { rvfree(spca50x->tmpBuffer, MAX_FRAME_SIZE); spca50x->tmpBuffer = NULL; } spca50x->buf_state = BUF_NOT_ALLOCATED; up(&spca50x->buf_lock); PDEBUG(1, "errored"); return -ENOMEM;}static voidspca5xx_dealloc(struct usb_spca50x *spca50x){ int i; PDEBUG(2, "entered dealloc"); down(&spca50x->buf_lock); if (spca50x->fbuf) { rvfree(spca50x->fbuf, SPCA50X_NUMFRAMES * MAX_DATA_SIZE); spca50x->fbuf = NULL; for (i = 0; i < SPCA50X_NUMFRAMES; i++) spca50x->frame[i].data = NULL; } if (spca50x->tmpBuffer) { rvfree(spca50x->tmpBuffer, MAX_FRAME_SIZE); spca50x->tmpBuffer = NULL; } PDEBUG(2, "buffer memory deallocated"); spca50x->buf_state = BUF_NOT_ALLOCATED; up(&spca50x->buf_lock); PDEBUG(2, "leaving dealloc");}/*** Reset the camera and send the correct initialization sequence for the* currently selected source*/static intspca50x_init_source(struct usb_spca50x *spca50x){ int err_code; if ((err_code = spca50x->funct.initialize(spca50x)) < 0) return -EINVAL; spca50x->norme = 0; spca50x->channel = 0; spca50x->light_freq = lightfreq; if ((err_code = spca5xx_setMode(spca50x, spca50x->width, spca50x->height, VIDEO_PALETTE_RGB24)) < 0) return -EINVAL; spca5xx_set_light_freq(spca50x, lightfreq); return 0;}/****************************************************************************** V4L API****************************************************************************/static inline voidspca5xx_setFrameDecoder(struct usb_spca50x *spca50x){ int i;/* configure the frame detector with default parameters */ memset(&spca50x->pictsetting, 0, sizeof (struct pictparam)); spca50x->pictsetting.change = 0x01; spca50x->pictsetting.force_rgb = force_rgb; spca50x->pictsetting.gamma = gamma; spca50x->pictsetting.OffRed = OffRed; spca50x->pictsetting.OffBlue = OffBlue; spca50x->pictsetting.OffGreen = OffGreen; spca50x->pictsetting.GRed = GRed; spca50x->pictsetting.GBlue = GBlue; spca50x->pictsetting.GGreen = GGreen;/* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used* (using read() instead). */ for (i = 0; i < SPCA50X_NUMFRAMES; i++) { spca50x->frame[i].width = spca50x->width; spca50x->frame[i].height = spca50x->height; spca50x->frame[i].cameratype = spca50x->cameratype; spca50x->frame[i].scanlength = spca50x->width * spca50x->height * 3 / 2; // assumes 4:2:0 data spca50x->frame[i].depth = 24;/* Note: format reflects format of data as returned to* a process, not as read from camera hardware.* This might be a good idea for dumb programs always* assuming the following settings.*/ spca50x->frame[i].format = VIDEO_PALETTE_RGB24; } spca50x->format = VIDEO_PALETTE_RGB24;}static intspca5xx_isjpeg(struct usb_spca50x *spca50x){ if (spca50x->cameratype == JPGH || spca50x->cameratype == JPGC || spca50x->cameratype == JPGS || spca50x->cameratype == JPEG || spca50x->cameratype == JPGM || spca50x->cameratype == PJPG) return 1; return 0;}static voidspca5xx_initDecoder(struct usb_spca50x *spca50x){ if (spca5xx_isjpeg(spca50x)) init_jpeg_decoder(spca50x); if (spca50x->bridge == BRIDGE_SONIX) init_sonix_decoder(spca50x); if (spca50x->bridge == BRIDGE_PAC207) init_pixart_decoder(spca50x);}static voidspca5xx_chgAuto(struct usb_spca50x *spca50x, __u8 autoval){ spca50x->autoexpo = (int) autoval; spca50x->funct.set_autobright(spca50x);}static voidspca5xx_chgQtable(struct usb_spca50x *spca50x, __u8 qtable){ int intqtable = (int) qtable;/* one frame maybe corrupted wait for the result */ if (spca5xx_isjpeg(spca50x) && (spca50x->qindex != intqtable)) { if (spca50x->cameratype == JPGH) {/* only vimicro ATM */ spca50x->qindex = intqtable; spca50x->funct.set_quality(spca50x); init_jpeg_decoder(spca50x); } }}static inline voidspca5xx_chgDtimes(struct usb_spca50x *spca50x, __u16 dtimes){ unsigned long flags; spin_lock_irqsave(&spca50x->v4l_lock, flags); spca50x->dtimes = (unsigned int) dtimes; spin_unlock_irqrestore(&spca50x->v4l_lock, flags);}/* Matches the sensor's internal frame rate to the lighting frequency. * Valid frequencies are: * 50 - 50Hz, for European and Asian lighting (default) * 60 - 60Hz, for American lighting * 0 - No Fliker (for outdoore usage) * Returns: 0 for success */static intspca5xx_set_light_freq(struct usb_spca50x *spca50x, int freq){ int freq_set; if (freq == 50) freq_set = freq_50HZ; else if (freq == 60) freq_set = freq_60HZ; else if (freq == 0) freq_set = NoFliker; else { PDEBUG(0,"Invalid light freq (%d Hz)", freq); return -EINVAL; } switch (spca50x->sensor) { case SENSOR_TAS5130C_VF0250: case SENSOR_TAS5130CXX: case SENSOR_PB0330: case SENSOR_PAS106: case SENSOR_ICM105A: case SENSOR_HDCS2020b: case SENSOR_CS2102: case SENSOR_OV7660: break; default: PDEBUG(0,"Sensor currently not support light frequency banding filters."); return -EINVAL; } if (freq_set == freq_50HZ) { PDEBUG(1, "Light frequency banding filter set to 50HZ mode"); if (spca50x->mode && spca50x->funct.set_50HZ) { spca50x->funct.set_50HZ(spca50x); } else if (spca50x->funct.set_50HZScale) { spca50x->funct.set_50HZScale(spca50x); } } else if (freq_set == freq_60HZ) { PDEBUG(1, "Light frequency banding filter set to 60HZ mode"); if (spca50x->mode && spca50x->funct.set_60HZ) { spca50x->funct.set_60HZ(spca50x); } else if (spca50x->funct.set_60HZScale) { spca50x->funct.set_60HZScale(spca50x); } } else if (freq_set == NoFliker) { PDEBUG(1, "Light frequency banding filter set to NoFliker mode"); if (spca50x->mode && spca50x->funct.set_NoFliker) { spca50x->funct.set_NoFliker(spca50x); } else if (spca50x->funct.set_NoFlikerScale) { spca50x->funct.set_NoFlikerScale(spca50x); } } spca50x->light_freq = freq; return 0;}static intspca5xx_open(struct inode *inode, struct file *file){ struct video_device *vdev = video_devdata(file); struct usb_spca50x *spca50x = video_get_drvdata(vdev); int err; PDEBUG(2, "opening"); down(&spca50x->lock);/* sanity check disconnect, in use, no memory available */ err = -ENODEV; if (!spca50x->present) goto out; err = -EBUSY; if (spca50x->user) goto out; err = -ENOMEM; if (spca50x_alloc(spca50x)) goto out;/* initialize sensor and decoding */ err = spca50x_init_source(spca50x); if (err != 0) { PDEBUG(0, "DEALLOC error on spca50x_init_source\n"); up(&spca50x->lock); spca5xx_dealloc(spca50x); goto out2; } spca5xx_initDecoder(spca50x);/* open always start in rgb24 a bug in gqcam did not select the palette nor the size v4l spec need that the camera always start on the last setting */ spca5xx_setFrameDecoder(spca50x); spca50x->user++; file->private_data = vdev; err = gspca_init_transfert(spca50x); if (err) { PDEBUG(0, " DEALLOC error on init_Isoc\n"); spca50x->user--; gspca_kill_transfert(spca50x); up(&spca50x->lock); spca5xx_dealloc(spca50x); file->private_data = NULL; goto out2; }/* Now, let's get brightness from the camera */ spca50x->brightness = spca50x->funct.get_bright(spca50x); spca50x->whiteness = 0; out: up(&spca50x->lock); out2: if (err) { PDEBUG(2, "Open failed"); } else { PDEBUG(2, "Open done"); } return err;}static void inlinespcaCameraShutDown(struct usb_spca50x *spca50x){ if (spca50x->dev) { spca50x->funct.cam_shutdown(spca50x); }}static intspca5xx_close(struct inode *inode, struct file *file){ struct video_device *vdev = file->private_data; struct usb_spca50x *spca50x = video_get_drvdata(vdev); int i; PDEBUG(2, "spca50x_close"); down(&spca50x->lock); spca50x->user--; spca50x->curframe = -1; if (spca50x->present) { spca50x_stop_isoc(spca50x); spcaCameraShutDown(spca50x); for (i = 0; i < SPCA50X_NUMFRAMES; i++) { if (waitqueue_active(&spca50x->frame[i].wq)) wake_up_interruptible(&spca50x->frame[i].wq); } if (waitqueue_active(&spca50x->wq)) wake_up_interruptible(&spca50x->wq); }/* times to dealloc ressource */ up(&spca50x->lock); spca5xx_dealloc(spca50x); PD
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -