📄 spca_core.c
字号:
MODULE_DEVICE_TABLE (usb, device_table);/* We also setup the function for getting page number from the virtual address */#define VIRT_TO_PAGE virt_to_page#else /* LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) */#define VIRT_TO_PAGE MAP_NR#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) *//* * Let's include the initialization data for each camera type */#include "spcausb.h"#include "sp5xxfw2.h"#include "zc3xx.h"#include "sn9cxxx.h"/* function for the tasklet */void outpict_do_tasklet (unsigned long ptr);/********************************************************************** * * Memory management * * This is a shameless copy from the USB-cpia driver (linux kernel * version 2.3.29 or so, I have no idea what this code actually does ;). * Actually it seems to be a copy of a shameless copy of the bttv-driver. * Or that is a copy of a shameless copy of ... (To the powers: is there * no generic kernel-function to do this sort of stuff?) * * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says * there will be one, but apparentely not yet -jerdfelt * * So I copied it again for the ov511 driver -claudio * And again for the spca50x driver -jcrisp **********************************************************************//* Given PGD from the address space's page table, return the kernel * virtual mapping of the physical memory mapped at ADR. */#ifndef RH9_REMAPstatic inline unsigned longuvirt_to_kva (pgd_t * pgd, unsigned long adr){ unsigned long ret = 0UL; pmd_t *pmd; pte_t *ptep, pte; if (!pgd_none (*pgd)) {#if PUD_SHIFT pud_t *pud = pud_offset (pgd, adr); if (!pud_none (*pud)) { pmd = pmd_offset (pud, adr);#else pmd = pmd_offset (pgd, adr);#endif if (!pmd_none (*pmd)) { ptep = pte_offset_kernel (pmd, adr); pte = *ptep; if (pte_present (pte)) { ret = (unsigned long) page_address (pte_page (pte)); ret |= (adr & (PAGE_SIZE - 1)); }#if PUD_SHIFT }#endif }}return ret;}#endif /* RH9_REMAP *//* Here we want the physical address of the memory. * This is used when initializing the contents of the * area and marking the pages as reserved. */#ifdef RH9_REMAPstatic 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); /* restore the offset */ ret = __pa (kva); return ret;}#else /* RH9_REMAP */#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)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;}#elsestatic inline unsigned longkvirt_to_pa (unsigned long adr){ unsigned long va, kva, ret; va = VMALLOC_VMADDR (adr); kva = uvirt_to_kva (pgd_offset_k (va), va); ret = __pa (kva); return ret;}#endif#endif /* RH9_REMAP */static void *rvmalloc (unsigned long size){ void *mem; unsigned long adr;#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 23)unsigned long page;#endif 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) {#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 68) SetPageReserved (vmalloc_to_page ((void *) adr));#else#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 23) mem_map_reserve (vmalloc_to_page ((void *) adr));#else page = kvirt_to_pa (adr); mem_map_reserve(VIRT_TO_PAGE(__va (page)));#endif#endif adr += PAGE_SIZE; size -= PAGE_SIZE; } return mem;}static voidrvfree (void *mem, unsigned long size){ unsigned long adr;#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 23)unsigned long page;#endif if (!mem) return; adr = (unsigned long) mem; while ((long) size > 0) {#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 68) ClearPageReserved (vmalloc_to_page ((void *) adr));#else#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 23) mem_map_unreserve (vmalloc_to_page ((void *) adr));#else page = kvirt_to_pa (adr); mem_map_unreserve(VIRT_TO_PAGE(__va (page)));#endif#endif adr += PAGE_SIZE; size -= PAGE_SIZE; } vfree (mem);}static intspca50x_set_packet_size (struct usb_spca50x *spca50x, int size){ int alt; /**********************************************************************/ /******** Try to find real Packet size from usb struct ****************/ struct usb_device *dev = spca50x->dev;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) struct usb_interface_descriptor *interface = NULL; struct usb_config_descriptor *config = dev->actconfig;#else struct usb_host_interface *interface = NULL; struct usb_interface *intf;#endif int mysize = 0; int ep = 0; /**********************************************************************/ if (size == 0) alt = SPCA50X_ALT_SIZE_0; else if (size == 128) alt = SPCA50X_ALT_SIZE_128; else if (size == 256) alt = SPCA50X_ALT_SIZE_256; else if (size == 384) alt = SPCA50X_ALT_SIZE_384; else if (size == 512) alt = SPCA50X_ALT_SIZE_512; else if (size == 640) alt = SPCA50X_ALT_SIZE_640; else if (size == 768) alt = SPCA50X_ALT_SIZE_768; else if (size == 896) alt = SPCA50X_ALT_SIZE_896; else if (size == 1023) if (spca50x->bridge == BRIDGE_SN9CXXX ) { alt = 8; } else { alt = SPCA50X_ALT_SIZE_1023; } else { /* if an unrecognised size, default to the minimum */ PDEBUG (5, "Set packet size: invalid size (%d), defaulting to %d", size, SPCA50X_ALT_SIZE_128); alt = SPCA50X_ALT_SIZE_128; } PDEBUG (5, "iface alt size: %d %d %d", spca50x->iface, alt, size); if (usb_set_interface (spca50x->dev, spca50x->iface, alt) < 0) { err ("Set packet size: set interface error"); return -EBUSY; } ep = SPCA50X_ENDPOINT_ADDRESS - 1;#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,3) intf = usb_ifnum_to_if (dev, spca50x->iface); if (intf) { interface = usb_altnum_to_altsetting (intf, alt); } else { PDEBUG (0, "intf not found"); return -ENXIO; }#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11) mysize = le16_to_cpu(interface->endpoint[ep].desc.wMaxPacketSize);#else mysize = (interface->endpoint[ep].desc.wMaxPacketSize); #endif#else interface = &config->interface[spca50x->iface].altsetting[alt];#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11) mysize = le16_to_cpu(interface->endpoint[ep].wMaxPacketSize);#else mysize = (interface->endpoint[ep].wMaxPacketSize);#endif #endif spca50x->packet_size = mysize & 0x03ff; spca50x->alt = alt; PDEBUG (1, "set real packet size: %d, alt=%d", mysize, alt); return 0;}/* 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_RAW_JPEG: return 8; /* 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 ) { 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,5,0)static voidspca50x_isoc_irq (struct urb *urb, struct pt_regs *regs){ int i;#elsestatic voidspca50x_isoc_irq (struct urb *urb){#endif int len; struct usb_spca50x *spca50x; if (!urb->context) { PDEBUG (4, "no context"); return; } spca50x = (struct usb_spca50x *) urb->context; 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 */ spca50x->cursbuf = (spca50x->cursbuf + 1) % SPCA50X_NUMSBUF; urb->dev = spca50x->dev; urb->status = 0;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 4) if ((i = usb_submit_urb (urb, GFP_ATOMIC)) != 0) err ("usb_submit_urb() ret %d", i);#else/* If we use urb->next usb_submit_urb() is not need in 2.4.x */ //if ((i = usb_submit_urb(urb)) != 0) //err("usb_submit_urb() ret %d", i);#endif return;}/*********************************************************************** spca50x_init_isoc* Function starts the ISO USB transfer by enabling this process* from USB side and enabling ISO machine from the chip side***********************************************************************/static inline voidspcaCameraStart (struct usb_spca50x *spca50x){ switch (spca50x->bridge) { case BRIDGE_SN9CXXX: sn9cxxx_start(spca50x); break; case BRIDGE_ZC3XX: zc3xx_start (spca50x); break; case BRIDGE_SPCA504: case BRIDGE_SPCA504C: case BRIDGE_SPCA536: case BRIDGE_SPCA533: case BRIDGE_SPCA504B: { sp5xxfw2_start(spca50x); break; } }}static inline voidspcaCameraStop (struct usb_spca50x *spca50x){ switch (spca50x->bridge) { case BRIDGE_SN9CXXX: sn9cxxx_stop (spca50x); break; case BRIDGE_ZC3XX: zc3xx_stop (spca50x); break; case BRIDGE_SPCA504C: case BRIDGE_SPCA504: case BRIDGE_SPCA536: case BRIDGE_SPCA533: case BRIDGE_SPCA504B: { sp5xxfw2_stop (spca50x); break; } }}static intspca50x_init_isoc (struct usb_spca50x *spca50x){ struct urb *urb; int fx, err, n; PDEBUG (3, "*** Initializing capture ***");/* reset iso context */ spca50x->compress = compress; spca50x->curframe = 0; spca50x->cursbuf = 0; spca50x->frame[0].seq = -1; spca50x->lastFrameRead = -1; spca50x_set_packet_size (spca50x, spca50x->pipe_size); PDEBUG (2, "setpacketsize %d", spca50x->pipe_size); for (n = 0; n < SPCA50X_NUMSBUF; n++) {#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) urb = usb_alloc_urb (FRAMES_PER_DESC, GFP_KERNEL);#else urb = usb_alloc_urb (FRAMES_PER_DESC);#endif if (!urb) { err ("init isoc: usb_alloc_urb ret. NULL"); return -ENOMEM; } spca50x->sbuf[n].urb = urb; urb->dev = spca50x->dev; urb->context = spca50x; urb->pipe = usb_rcvisocpipe (spca50x->dev, SPCA50X_ENDPOINT_ADDRESS);#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) urb->transfer_flags = URB_ISO_ASAP; urb->interval = 1;#else urb->transfer_flags = USB_ISO_ASAP;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -