📄 gspca_core.c
字号:
times_now = get_jiffies_64(); return jiffies_to_msecs(times_now);}/* ******************************************************************* spca50x_move_data* Function serves for moving data from USB transfer buffers* to internal driver frame buffers.******************************************************************* */static intspca50x_move_data(struct usb_spca50x *spca50x, struct urb *urb){ unsigned char *cdata; //Pointer to buffer where we do store next packet unsigned char *pData; //Pointer to buffer where we do store next packet int i; for (i = 0; i < urb->number_of_packets; i++) { int datalength = urb->iso_frame_desc[i].actual_length; int st = urb->iso_frame_desc[i].status; unsigned long ms_times_now; unsigned long ms_times_before; struct spca50x_frame *frame; //Pointer to frame data int sequenceNumber; int sof; int iPix; //Offset of pixel data in the ISO packet if (st) { PDEBUG(0, "ISOC data error: [%d] len=%d, status=%d \n", i, datalength, st); continue; } cdata = ((unsigned char *) urb->transfer_buffer) + urb->iso_frame_desc[i].offset;/* Check for zero length block or no selected frame buffer */ if (!datalength || spca50x->curframe == -1) { spca50x->synchro = 0; continue; } PDEBUG(5, "Packet data [%d,%d,%d] Status: %d", datalength, st, urb->iso_frame_desc[i].offset, st); frame = &spca50x->frame[spca50x->curframe]; if (frame->last_packet == -1) {/*initialize a new frame */ sequenceNumber = 0; } else { sequenceNumber = frame->last_packet; }/* check frame start */ if ((sof = spca50x->funct.sof_detect(spca50x, frame, cdata, &iPix, sequenceNumber, &datalength)) < 0) continue; sequenceNumber = sof; PDEBUG(3, "spca50x: Packet seqnum = 0x%02x. curframe=%2d", sequenceNumber, spca50x->curframe); pData = cdata;/* 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 || spca50x->cameratype == JPGV) 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: case SENSOR_OV7620: case SENSOR_MC501CB: 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(sp
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -