⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 spca_core.c

📁 通用的摄像头驱动源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
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 + -