?? w9968cf.c
字號(hào):
if (!(cam->transfer_buffer[i] = kmalloc(W9968CF_ISO_PACKETS*p_size, GFP_KERNEL))) { DBG(1, "Couldn't allocate memory for the isochronous " "transfer buffers (%u bytes)", p_size * W9968CF_ISO_PACKETS) return -ENOMEM; } memset(cam->transfer_buffer[i], 0, W9968CF_ISO_PACKETS*p_size); } /* Allocate memory for the temporary frame buffer */ if (!(cam->frame_tmp.buffer = rvmalloc(hw_bufsize))) { DBG(1, "Couldn't allocate memory for the temporary " "video frame buffer (%lu bytes)", hw_bufsize) return -ENOMEM; } cam->frame_tmp.size = hw_bufsize; cam->frame_tmp.number = -1; /* Allocate memory for the helper buffer */ if (w9968cf_vpp) { if (!(cam->frame_vpp.buffer = rvmalloc(vpp_bufsize))) { DBG(1, "Couldn't allocate memory for the helper buffer" " (%lu bytes)", vpp_bufsize) return -ENOMEM; } cam->frame_vpp.size = vpp_bufsize; } else cam->frame_vpp.buffer = NULL; /* Allocate memory for video frame buffers */ cam->nbuffers = cam->max_buffers; while (cam->nbuffers >= 2) { if ((buff = rvmalloc(cam->nbuffers * vpp_bufsize))) break; else cam->nbuffers--; } if (!buff) { DBG(1, "Couldn't allocate memory for the video frame buffers") cam->nbuffers = 0; return -ENOMEM; } if (cam->nbuffers != cam->max_buffers) DBG(2, "Couldn't allocate memory for %u video frame buffers. " "Only memory for %u buffers has been allocated", cam->max_buffers, cam->nbuffers) for (i = 0; i < cam->nbuffers; i++) { cam->frame[i].buffer = buff + i*vpp_bufsize; cam->frame[i].size = vpp_bufsize; cam->frame[i].number = i; /* Circular list */ if (i != cam->nbuffers-1) cam->frame[i].next = &cam->frame[i+1]; else cam->frame[i].next = &cam->frame[0]; cam->frame[i].status = F_UNUSED; } DBG(5, "Memory successfully allocated") return 0;}/**************************************************************************** * USB-specific functions * ****************************************************************************//*-------------------------------------------------------------------------- This is an handler function which is called after the URBs are completed. It collects multiple data packets coming from the camera by putting them into frame buffers: one or more zero data length data packets are used to mark the end of a video frame; the first non-zero data packet is the start of the next video frame; if an error is encountered in a packet, the entire video frame is discarded and grabbed again. If there are no requested frames in the FIFO list, packets are collected into a temporary buffer. --------------------------------------------------------------------------*/static void w9968cf_urb_complete(struct urb *urb, struct pt_regs *regs){ struct w9968cf_device* cam = (struct w9968cf_device*)urb->context; struct w9968cf_frame_t** f; unsigned int len, status; void* pos; u8 i; int err = 0; if ((!cam->streaming) || cam->disconnected) { DBG(4, "Got interrupt, but not streaming") return; } /* "(*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)",
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -