📄 gspca_core.c
字号:
/*Let's include the initialization data for each camera type*/#include "utils/spcausb.h"#include "Sunplus/spca501_init.h"#include "Sunplus/spca505_init.h"#include "Sunplus/spca506.h"#include "Sunplus/spca508_init.h"#include "Sunplus/spca561.h"#include "Sunplus-jpeg/jpeg_qtables.h"#include "Sunplus-jpeg/spca500_init.h"#include "Sunplus-jpeg/sp5xxfw2.h"#include "Sonix/sonix.h"#include "Vimicro/zc3xx.h"#include "Conexant/cx11646.h"#include "Transvision/tv8532.h"#include "Etoms/et61xx51.h"#include "Mars-Semi/mr97311.h"#include "Pixart/pac207.h"#include "Pixart/pac7311.h"#include "Vimicro/vc032x.h"/* function for the tasklet */void outpict_do_tasklet(unsigned long ptr);/************************************************************************ Memory management**********************************************************************/static inline unsigned longkvirt_to_pa(unsigned long adr){ unsigned long kva, ret; kva = (unsigned long) page_address(vmalloc_to_page((void *) adr)); kva |= adr & (PAGE_SIZE - 1); ret = __pa(kva); return ret;}static void *rvmalloc(unsigned long size){ void *mem; unsigned long adr; size = PAGE_ALIGN(size); mem = vmalloc_32(size); if (!mem) return NULL; memset(mem, 0, size); /* Clear the ram out, no junk to the user */ adr = (unsigned long) mem; while ((long) size > 0) { SetPageReserved(vmalloc_to_page((void *) adr)); adr += PAGE_SIZE; size -= PAGE_SIZE; } return mem;}static voidrvfree(void *mem, unsigned long size){ unsigned long adr; if (!mem) return; adr = (unsigned long) mem; while ((long) size > 0) { ClearPageReserved(vmalloc_to_page((void *) adr)); adr += PAGE_SIZE; size -= PAGE_SIZE; } vfree(mem);}/* ------------------------------------------------------------------------ *//*** Endpoint management we assume one isoc endpoint per device* that is not true some Zoran 0x0572:0x0001 have two* assume ep adresse is static know * FIXME as I don't know how to set the bandwith budget* we allow the maximum**/static struct usb_host_endpoint *gspca_set_isoc_ep(struct usb_spca50x *spca50x, int nbalt){ int i, j; struct usb_interface *intf; struct usb_host_endpoint *ep; struct usb_device *dev = spca50x->dev; struct usb_host_interface *altsetting = NULL; int error = 0; PDEBUG(3, "enter get iso ep "); intf = usb_ifnum_to_if(dev, spca50x->iface); /* bandwith budget can be set here */ for (i = nbalt; i; i--) { altsetting = &intf->altsetting[i]; for (j = 0; j < altsetting->desc.bNumEndpoints; ++j) { ep = &altsetting->endpoint[j]; PDEBUG(3, "test ISO EndPoint %d",ep->desc.bEndpointAddress); if ((ep->desc.bEndpointAddress == (spca50x->epadr | USB_DIR_IN)) && ((ep->desc. bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_ISOC)) { PDEBUG(0, "ISO EndPoint found 0x%02X AlternateSet %d", ep->desc.bEndpointAddress,i); if ((error = usb_set_interface(dev, spca50x->iface, i)) < 0) { PDEBUG(0, "Set interface err %d", error); return NULL; } spca50x->alt = i; return ep; } } } PDEBUG(0, "FATAL ISO EndPoint not found "); return NULL;}static intgspca_set_alt0(struct usb_spca50x *spca50x){ int error = 0; if ((error = usb_set_interface(spca50x->dev, spca50x->iface, 0)) < 0) { PDEBUG(0, "Set interface err %d", error); } spca50x->alt = 0; return error;}static intgspca_kill_transfert(struct usb_spca50x *spca50x){ struct urb *urb; unsigned int i; spca50x->streaming = 0; for (i = 0; i < SPCA50X_NUMSBUF; ++i) { if ((urb = spca50x->sbuf[i].urb) == NULL) continue; usb_kill_urb(urb); /* urb->transfer_buffer_length is not touched by USB core, so * we can use it here as the buffer length. */ if (spca50x->sbuf[i].data) { // kfree(gspca_dev->sbuf[i].data); usb_buffer_free(spca50x->dev, urb->transfer_buffer_length, spca50x->sbuf[i].data, urb->transfer_dma); spca50x->sbuf[i].data = NULL; } usb_free_urb(urb); spca50x->sbuf[i].urb = NULL; } return 0;} static intgspca_init_transfert(struct usb_spca50x *spca50x){ struct usb_host_endpoint *ep; struct usb_interface *intf; struct urb *urb; __u16 psize; int n,fx; struct usb_device *dev = spca50x->dev;// struct usb_host_interface *altsetting = NULL; int error = -ENOSPC; int nbalt = 0; if (spca50x->streaming) return -EBUSY; intf = usb_ifnum_to_if(dev, spca50x->iface); nbalt = intf->num_altsetting - 1; /* Damned Sunplus fault */ if(spca50x->bridge == BRIDGE_SPCA561) nbalt =7; PDEBUG(3, "get iso nbalt %d",nbalt); spca50x->curframe = 0; while (nbalt && (error == -ENOSPC)) { if ((ep = gspca_set_isoc_ep(spca50x,nbalt--)) == NULL) return -EIO; psize = le16_to_cpu(ep->desc.wMaxPacketSize); psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3)); PDEBUG(3, "packet size %d", psize); for (n = 0; n < SPCA50X_NUMSBUF; n++) { urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL); if (!urb) { err("init isoc: usb_alloc_urb ret. NULL"); return -ENOMEM; } spca50x->sbuf[n].data = usb_buffer_alloc(spca50x->dev, psize * FRAMES_PER_DESC, GFP_KERNEL, &urb->transfer_dma); //gspca_dev->sbuf[n].data = kmalloc((psize+1)* FRAMES_PER_DESC,GFP_KERNEL); if(spca50x->sbuf[n].data == NULL){ usb_free_urb(urb); gspca_kill_transfert(spca50x); return -ENOMEM; } spca50x->sbuf[n].urb = urb; urb->dev = spca50x->dev; urb->context = spca50x; urb->pipe = usb_rcvisocpipe(spca50x->dev, ep->desc.bEndpointAddress); urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; urb->interval = ep->desc.bInterval; urb->transfer_buffer = spca50x->sbuf[n].data; urb->complete = spca50x_isoc_irq; urb->number_of_packets = FRAMES_PER_DESC; urb->transfer_buffer_length = psize * FRAMES_PER_DESC; for (fx = 0; fx < FRAMES_PER_DESC; fx++) { urb->iso_frame_desc[fx].offset = psize * fx; urb->iso_frame_desc[fx].length = psize; } } /* mark all frame unused */ for (n = 0; n < SPCA50X_NUMFRAMES; n++) { spca50x->frame[n].grabstate = FRAME_UNUSED; spca50x->frame[n].scanstate = STATE_SCANNING; } /* start the cam and initialize the tasklet lock */ spca50x->funct.start(spca50x); spca50x->streaming = 1; atomic_set(&spca50x->in_use,0); PDEBUG(3, "Submit URB Now"); /* Submit the URBs. */ for (n = 0; n < SPCA50X_NUMSBUF; ++n) { if ((error = usb_submit_urb(spca50x->sbuf[n].urb, GFP_KERNEL)) < 0) { err("init isoc: usb_submit_urb(%d) ret %d", n, error); gspca_kill_transfert(spca50x); break; } } } return error;}/* Returns number of bits per pixel (regardless of where they are located; planar or* not), or zero for unsupported format.*/static intspca5xx_get_depth(struct usb_spca50x *spca50x, int palette){ switch (palette) {// case VIDEO_PALETTE_GREY: return 8; case VIDEO_PALETTE_RGB565: return 16; case VIDEO_PALETTE_RGB24: return 24;// case VIDEO_PALETTE_YUV422: return 16;// case VIDEO_PALETTE_YUYV:// return 16;// case VIDEO_PALETTE_YUV420: return 24; case VIDEO_PALETTE_YUV420P: return 12; /* strange need 12 this break the read method for this planar mode (6*8/4) */// case VIDEO_PALETTE_YUV422P: return 24; /* Planar */ case VIDEO_PALETTE_RGB32: return 32; case VIDEO_PALETTE_RAW_JPEG: return 24; /* raw jpeg. what should we return ?? */ case VIDEO_PALETTE_JPEG: if (spca50x->cameratype == JPEG || spca50x->cameratype == JPGH || spca50x->cameratype == JPGC || spca50x->cameratype == JPGS || spca50x->cameratype == JPGM || spca50x->cameratype == PJPG) { return 8; } else return 0; default: return 0; /* Invalid format */ }}/*********************************************************************** spca50x_isoc_irq* Function processes the finish of the USB transfer by calling * spca50x_move_data function to move data from USB buffer to internal* driver structures ***********************************************************************/#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)static voidspca50x_isoc_irq(struct urb *urb, struct pt_regs *regs)#elsestatic voidspca50x_isoc_irq(struct urb *urb)#endif{ int i; struct usb_spca50x *spca50x = (struct usb_spca50x *) urb->context; int len; switch (urb->status) { case 0: break; default: PDEBUG(0, "Non-zero status (%d) in isoc " "completion handler.", urb->status); case -ENOENT: /* usb_kill_urb() called. */ case -ECONNRESET: /* usb_unlink_urb() called. */ case -ESHUTDOWN: /* The endpoint is being disabled. */ return; } if (!spca50x->dev) { PDEBUG(4, "no device "); return; } if (!spca50x->user) { PDEBUG(4, "device not open"); return; } if (!spca50x->streaming) {/* Always get some of these after close but before packet engine stops */ PDEBUG(4, "hmmm... not streaming, but got interrupt"); return; } if (!spca50x->present) {/* */ PDEBUG(4, "device disconnected ..., but got interrupt !!"); return; }/* Copy the data received into our scratch buffer */ if (spca50x->curframe >= 0) { len = spca50x_move_data(spca50x, urb); } else if (waitqueue_active(&spca50x->wq)) { wake_up_interruptible(&spca50x->wq); }/* Move to the next sbuf */ urb->dev = spca50x->dev; urb->status = 0; if ((i = usb_submit_urb(urb, GFP_ATOMIC)) != 0) err("usb_submit_urb() ret %d", i); return;}static voidspca50x_stop_isoc(struct usb_spca50x *spca50x){ if (!spca50x->streaming || !spca50x->dev) return; PDEBUG(3, "*** Stopping capture ***"); spca50x->funct.stopN(spca50x); gspca_kill_transfert(spca50x); gspca_set_alt0(spca50x); spca50x->funct.stop0(spca50x); PDEBUG(3, "*** Capture stopped ***");}/*********************************************************************** spca50x_smallest_mode_index* Function finds the mode index in the modes table of the smallest* available mode.***********************************************************************/static intspca5xx_getDefaultMode(struct usb_spca50x *spca50x){ int i; for (i = QCIF; i < TOTMODE; i++) { if (spca50x->mode_cam[i].method == 0 && spca50x->mode_cam[i].width) { spca50x->width = spca50x->mode_cam[i].width; spca50x->height = spca50x->mode_cam[i].height; spca50x->method = 0; spca50x->pipe_size = spca50x->mode_cam[i].pipe; spca50x->mode = spca50x->mode_cam[i].mode; return 0; } } return -EINVAL;}/*********************************************************************** spca50x_set_mode* Function sets up the resolution directly. * Attention!!! index, the index in modes array is NOT checked. ***********************************************************************/static intspca5xx_getcapability(struct usb_spca50x *spca50x){ int maxw, maxh, minw, minh; int i; minw = minh = 255 * 255; maxw = maxh = 0; for (i = QCIF; i < TOTMODE; i++) { if (spca50x->mode_cam[i].width) { if (maxw < spca50x->mode_cam[i].width || maxh < spca50x->mode_cam[i].height) { maxw = spca50x->mode_cam[i].width; maxh = spca50x->mode_cam[i].height; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -