?? w9968cf.c
字號:
} /* "(*f)" will be used instead of "cam->frame_current" */ f = &cam->frame_current; /* If a frame has been requested and we are grabbing into the temporary frame, we'll switch to that requested frame */ if ((*f) == &cam->frame_tmp && *cam->requested_frame) { if (cam->frame_tmp.status == F_GRABBING) { w9968cf_pop_frame(cam, &cam->frame_current); (*f)->status = F_GRABBING; (*f)->length = cam->frame_tmp.length; memcpy((*f)->buffer, cam->frame_tmp.buffer, (*f)->length); DBG(6, "Switched from temp. frame to frame #%d", (*f)->number) } } for (i = 0; i < urb->number_of_packets; i++) { len = urb->iso_frame_desc[i].actual_length; status = urb->iso_frame_desc[i].status; pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer; if (status && len != 0) { DBG(4, "URB failed, error in data packet " "(error #%u, %s)", status, symbolic(urb_errlist, status)) (*f)->status = F_ERROR; continue; } if (len) { /* start of frame */ if ((*f)->status == F_UNUSED) { (*f)->status = F_GRABBING; (*f)->length = 0; } /* Buffer overflows shouldn't happen, however...*/ if ((*f)->length + len > (*f)->size) { DBG(4, "Buffer overflow: bad data packets") (*f)->status = F_ERROR; } if ((*f)->status == F_GRABBING) { memcpy((*f)->buffer + (*f)->length, pos, len); (*f)->length += len; } } else if ((*f)->status == F_GRABBING) { /* end of frame */ DBG(6, "Frame #%d successfully grabbed", (*f)->number) if (cam->vpp_flag & VPP_DECOMPRESSION) { err = w9968cf_vpp->check_headers((*f)->buffer, (*f)->length); if (err) { DBG(4, "Skip corrupted frame: %s", symbolic(decoder_errlist, err)) (*f)->status = F_UNUSED; continue; /* grab this frame again */ } } (*f)->status = F_READY; (*f)->queued = 0; /* Take a pointer to the new frame from the FIFO list. If the list is empty,we'll use the temporary frame*/ if (*cam->requested_frame) w9968cf_pop_frame(cam, &cam->frame_current); else { cam->frame_current = &cam->frame_tmp; (*f)->status = F_UNUSED; } } else if ((*f)->status == F_ERROR) (*f)->status = F_UNUSED; /* grab it again */ PDBGG("Frame length %lu | pack.#%u | pack.len. %u | state %d", (unsigned long)(*f)->length, i, len, (*f)->status) } /* end for */ /* Resubmit this URB */ urb->dev = cam->usbdev; urb->status = 0; spin_lock(&cam->urb_lock); if (cam->streaming) if ((err = usb_submit_urb(urb, GFP_ATOMIC))) { cam->misconfigured = 1; DBG(1, "Couldn't resubmit the URB: error %d, %s", err, symbolic(urb_errlist, err)) } spin_unlock(&cam->urb_lock); /* Wake up the user process */ wake_up_interruptible(&cam->wait_queue);}/*--------------------------------------------------------------------------- Setup the URB structures for the isochronous transfer. Submit the URBs so that the data transfer begins. Return 0 on success, a negative number otherwise. ---------------------------------------------------------------------------*/static int w9968cf_start_transfer(struct w9968cf_device* cam){ struct usb_device *udev = cam->usbdev; struct urb* urb; const u16 p_size = wMaxPacketSize[cam->altsetting-1]; u16 w, h, d; int vidcapt; u32 t_size; int err = 0; s8 i, j; for (i = 0; i < W9968CF_URBS; i++) { urb = usb_alloc_urb(W9968CF_ISO_PACKETS, GFP_KERNEL); cam->urb[i] = urb; if (!urb) { for (j = 0; j < i; j++) usb_free_urb(cam->urb[j]); DBG(1, "Couldn't allocate the URB structures") return -ENOMEM; } urb->dev = udev; urb->context = (void*)cam; urb->pipe = usb_rcvisocpipe(udev, 1); urb->transfer_flags = URB_ISO_ASAP; urb->number_of_packets = W9968CF_ISO_PACKETS; urb->complete = w9968cf_urb_complete; urb->transfer_buffer = cam->transfer_buffer[i]; urb->transfer_buffer_length = p_size*W9968CF_ISO_PACKETS; urb->interval = 1; for (j = 0; j < W9968CF_ISO_PACKETS; j++) { urb->iso_frame_desc[j].offset = p_size*j; urb->iso_frame_desc[j].length = p_size; } } /* Transfer size per frame, in WORD ! */ d = cam->hw_depth; w = cam->hw_width; h = cam->hw_height; t_size = (w*h*d)/16; err = w9968cf_write_reg(cam, 0xbf17, 0x00); /* reset everything */ err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* normal operation */ /* Transfer size */ err += w9968cf_write_reg(cam, t_size & 0xffff, 0x3d); /* low bits */ err += w9968cf_write_reg(cam, t_size >> 16, 0x3e); /* high bits */ if (cam->vpp_flag & VPP_DECOMPRESSION) err += w9968cf_upload_quantizationtables(cam); vidcapt = w9968cf_read_reg(cam, 0x16); /* read picture settings */ err += w9968cf_write_reg(cam, vidcapt|0x8000, 0x16); /* capt. enable */ err += usb_set_interface(udev, 0, cam->altsetting); err += w9968cf_write_reg(cam, 0x8a05, 0x3c); /* USB FIFO enable */ if (err || (vidcapt < 0)) { for (i = 0; i < W9968CF_URBS; i++) usb_free_urb(cam->urb[i]); DBG(1, "Couldn't tell the camera to start the data transfer") return err; } w9968cf_init_framelist(cam); /* Begin to grab into the temporary buffer */ cam->frame_tmp.status = F_UNUSED; cam->frame_tmp.queued = 0; cam->frame_current = &cam->frame_tmp; if (!(cam->vpp_flag & VPP_DECOMPRESSION)) DBG(5, "Isochronous transfer size: %lu bytes/frame", (unsigned long)t_size*2) DBG(5, "Starting the isochronous transfer...") cam->streaming = 1; /* Submit the URBs */ for (i = 0; i < W9968CF_URBS; i++) { err = usb_submit_urb(cam->urb[i], GFP_KERNEL); if (err) { cam->streaming = 0; for (j = i-1; j >= 0; j--) { usb_kill_urb(cam->urb[j]); usb_free_urb(cam->urb[j]); } DBG(1, "Couldn't send a transfer request to the " "USB core (error #%d, %s)", err, symbolic(urb_errlist, err)) return err; } } return 0;}/*-------------------------------------------------------------------------- Stop the isochronous transfer and set alternate setting to 0 (0Mb/s). Return 0 on success, a negative number otherwise. --------------------------------------------------------------------------*/static int w9968cf_stop_transfer(struct w9968cf_device* cam){ struct usb_device *udev = cam->usbdev; unsigned long lock_flags; int err = 0; s8 i; if (!cam->streaming) return 0; /* This avoids race conditions with usb_submit_urb() in the URB completition handler */ spin_lock_irqsave(&cam->urb_lock, lock_flags); cam->streaming = 0; spin_unlock_irqrestore(&cam->urb_lock, lock_flags); for (i = W9968CF_URBS-1; i >= 0; i--) if (cam->urb[i]) { usb_kill_urb(cam->urb[i]); usb_free_urb(cam->urb[i]); cam->urb[i] = NULL; } if (cam->disconnected) goto exit; err = w9968cf_write_reg(cam, 0x0a05, 0x3c); /* stop USB transfer */ err += usb_set_interface(udev, 0, 0); /* 0 Mb/s */ err += w9968cf_write_reg(cam, 0x0000, 0x39); /* disable JPEG encoder */ err += w9968cf_write_reg(cam, 0x0000, 0x16); /* stop video capture */ if (err) { DBG(2, "Failed to tell the camera to stop the isochronous " "transfer. However this is not a critical error.") return -EIO; }exit: DBG(5, "Isochronous transfer stopped") return 0;}/*-------------------------------------------------------------------------- Write a W9968CF register. Return 0 on success, -1 otherwise. --------------------------------------------------------------------------*/static int w9968cf_write_reg(struct w9968cf_device* cam, u16 value, u16 index){ struct usb_device* udev = cam->usbdev; int res; res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0, USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, value, index, NULL, 0, W9968CF_USB_CTRL_TIMEOUT); if (res < 0) DBG(4, "Failed to write a register " "(value 0x%04X, index 0x%02X, error #%d, %s)", value, index, res, symbolic(urb_errlist, res)) return (res >= 0) ? 0 : -1;}/*-------------------------------------------------------------------------- Read a W9968CF register. Return the register value on success, -1 otherwise. --------------------------------------------------------------------------*/static int w9968cf_read_reg(struct w9968cf_device* cam, u16 index){ struct usb_device* udev = cam->usbdev; u16* buff = cam->control_buffer; int res; res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 1, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, index, buff, 2, W9968CF_USB_CTRL_TIMEOUT); if (res < 0) DBG(4, "Failed to read a register " "(index 0x%02X, error #%d, %s)", index, res, symbolic(urb_errlist, res)) return (res >= 0) ? (int)(*buff) : -1;}/*-------------------------------------------------------------------------- Write 64-bit data to the fast serial bus registers. Return 0 on success, -1 otherwise. --------------------------------------------------------------------------*/static int w9968cf_write_fsb(struct w9968cf_device* cam, u16* data){ struct usb_device* udev = cam->usbdev; u16 value; int res; value = *data++; res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0, USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, value, 0x06, data, 6, W9968CF_USB_CTRL_TIMEOUT); if (res < 0) DBG(4, "Failed to write the FSB registers " "(error #%d, %s)", res, symbolic(urb_errlist, res)) return (res >= 0) ? 0 : -1;}/*-------------------------------------------------------------------------- Write data to the serial bus control register. Return 0 on success, a negative number otherwise. --------------------------------------------------------------------------*/static int w9968cf_write_sb(struct w9968cf_device* cam, u16 value){ int err = 0; err = w9968cf_write_reg(cam, value, 0x01); udelay(W9968CF_I2C_BUS_DELAY); return err;}/*-------------------------------------------------------------------------- Read data from the serial bus control register. Return 0 on success, a negative number otherwise. --------------------------------------------------------------------------*/static int w9968cf_read_sb(struct w9968cf_device* cam){ int v = 0; v = w9968cf_read_reg(cam, 0x01); udelay(W9968CF_I2C_BUS_DELAY); return v;}/*-------------------------------------------------------------------------- Upload quantization tables for the JPEG compression. This function is called by w9968cf_start_transfer(). Return 0 on success, a negative number otherwise. --------------------------------------------------------------------------*/static int w9968cf_upload_quantizationtables(struct w9968cf_device* cam){ u16 a, b; int err = 0, i, j; err += w9968cf_write_reg(cam, 0x0010, 0x39); /* JPEG clock enable */ for (i = 0, j = 0; i < 32; i++, j += 2) { a = Y_QUANTABLE[j] | ((unsigned)(Y_QUANTABLE[j+1]) << 8); b = UV_QUANTABLE[j] | ((unsigned)(UV_QUANTABLE[j+1]) << 8); err += w9968cf_write_reg(cam, a, 0x40+i); err += w9968cf_write_reg(cam, b, 0x60+i); } err += w9968cf_write_reg(cam, 0x0012, 0x39); /* JPEG encoder enable */ return err;}/**************************************************************************** * Low-level I2C I/O functions. * * The adapter supports the following I2C transfer functions: * * i2c_adap_fastwrite_byte_data() (at 400 kHz bit frequency only) * * i2c_adap_read_byte_data() * * i2c_adap_read_byte() * ****************************************************************************/static int w9968cf_smbus_start(struct w9968cf_device* cam){ int err = 0; err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */ err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */ return err;}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -