📄 spca50x.c
字号:
for (i = 0; str[i] >= '0' && str[i] <= '9'; i++) { result *= 10; result += str[i] - '0'; } return result;}static int spca50x_ctlwrite_proc(struct file *file, const char *buffer, unsigned long count, void *data){ int off; //where look for a value struct usb_spca50x *spca50x = data; if ((off = match("lum_level=", buffer, count)) >= 0) spca50x->lum_level = atoi(buffer + off); if ((off = match("min_bpp=", buffer, count)) >= 0) spca50x->min_bpp = atoi(buffer + off); if ((off = match("force_rgb=", buffer, count)) >= 0) spca50x->force_rgb = atoi(buffer + off); if ((off = match("debug=", buffer, count)) >= 0) debug = atoi(buffer + off); return count;}static void create_proc_spca50x_cam (struct usb_spca50x *spca50x){ char name[PROC_NAME_LEN]; struct proc_dir_entry *ent; if (!spca50x_proc_entry || !spca50x) return;//Create videoxx proc entry sprintf(name, "video%d", spca50x->vdev->minor); PDEBUG (4, "creating /proc/video/spca50x/%s", name); ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, spca50x_proc_entry); if (!ent) return; ent->data = spca50x; ent->read_proc = spca50x_read_proc; ent->write_proc = spca50x_write_proc; spca50x->proc_entry = ent;// Create the controlxx proc entry sprintf(name, "control%d", spca50x->vdev->minor); PDEBUG (4, "creating /proc/video/spca50x/%s", name); ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, spca50x_proc_entry); if (!ent) return; ent->data = spca50x; ent->read_proc = spca50x_ctlread_proc; ent->write_proc = spca50x_ctlwrite_proc; spca50x->ctl_proc_entry = ent;#ifdef SPCA50X_ENABLE_RAWPROCENTRY// Create the rawxx proc entry sprintf(name, "raw%d", spca50x->vdev.minor); PDEBUG (4, "creating /proc/video/spca50x/%s", name); ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, spca50x_proc_entry); if (!ent) return; ent->data = spca50x; ent->read_proc = spca50x_rawread_proc; ent->write_proc = spca50x_rawwrite_proc; spca50x->raw_proc_entry = ent; spca50x->rawBufferSize = 0; spca50x->rawBuffer = vmalloc(10*1024*1024); if (spca50x->rawBuffer != NULL) { spca50x->rawBufferMax = 10*1024*1024; PDEBUG(3, "allocated 10Mb raw proc entry buffer"); } else { PDEBUG(3, "vmalloc of raw proc entry buffer failed"); spca50x->rawBufferMax = 0; }#endif /* SPCA50X_ENABLE_RAWPROCENTRY */}static void destroy_proc_spca50x_cam (struct usb_spca50x *spca50x){ char name[PROC_NAME_LEN]; if (!spca50x || !spca50x_proc_entry) return; /* destroy videoxx proc entry */ if (spca50x->proc_entry != NULL) { sprintf(name, "video%d", spca50x->vdev->minor); PDEBUG (4, "destroying %s", name); remove_proc_entry(name, spca50x_proc_entry); spca50x->proc_entry = NULL; } /* destroy controlxx proc entry */ if (spca50x->ctl_proc_entry != NULL) { sprintf(name, "control%d", spca50x->vdev->minor); PDEBUG (4, "destroying %s", name); remove_proc_entry(name, spca50x_proc_entry); spca50x->ctl_proc_entry = NULL; }#ifdef SPCA50X_ENABLE_RAWPROCENTRY /* destroy rawxx proc entry */ if (spca50x->raw_proc_entry != NULL) { sprintf(name, "raw%d", spca50x->vdev.minor); remove_proc_entry(name, spca50x_proc_entry); spca50x->raw_proc_entry = NULL; vfree(spca50x->rawBuffer); }#endif /* SPCA50X_ENABLE_RAWPROCENTRY */}static void proc_spca50x_create(void){ /* No current standard here. Alan prefers /proc/video/ as it keeps * /proc "less cluttered than /proc/randomcardifoundintheshed/" * -claudio */#ifdef CONFIG_VIDEO_PROC_FS if (video_proc_entry == NULL) { err("Unable to initialise /proc/video/spca50x"); return; } spca50x_proc_entry = create_proc_entry("spca50x", S_IFDIR, video_proc_entry);#else /* CONFIG_VIDEO_PROC_FS */ spca50x_proc_entry = create_proc_entry("spca50x", S_IFDIR, 0);#endif /* CONFIG_VIDEO_PROC_FS */#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) if (spca50x_proc_entry) spca50x_proc_entry->owner = THIS_MODULE; else#ifdef CONFIG_VIDEO_PROC_FS err("Unable to initialise /proc/video/spca50x");#else /* CONFIG_VIDEO_PROC_FS */ err("Unable to initialise /proc/spca50x");#endif /* CONFIG_VIDEO_PROC_FS */#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) */}static void proc_spca50x_destroy(void){#ifdef CONFIG_VIDEO_PROC_FS PDEBUG (3, "removing /proc/video/spca50x");#else /* CONFIG_VIDEO_PROC_FS */ PDEBUG (3, "removing /proc/spca50x");#endif /* CONFIG_VIDEO_PROC_FS */ if (spca50x_proc_entry == NULL) return;#ifdef CONFIG_VIDEO_PROC_FS remove_proc_entry("spca50x", video_proc_entry);#else /* CONFIG_VIDEO_PROC_FS */ remove_proc_entry("spca50x", 0);#endif /* CONFIG_VIDEO_PROC_FS */}#endif /* CONFIG_PROC_FS *//********************************************************************** * * Camera interface * **********************************************************************//* Read a value from the I2C bus. Returns the value read */static int spca50x_read_i2c(struct usb_spca50x *spca50x,__u16 device,__u16 address){ struct usb_device *dev = spca50x->dev; int err_code; int retry; int ctrl = spca50x->i2c_ctrl_reg; //The I2C control register int base = spca50x->i2c_base; //The I2C base address err_code = spca50x_reg_write(dev, ctrl, base + SPCA50X_I2C_DEVICE, device); err_code = spca50x_reg_write(dev, ctrl, base + SPCA50X_I2C_SUBADDR, address); err_code = spca50x_reg_write(dev, ctrl, base + SPCA50X_I2C_TRIGGER, SPCA50X_I2C_TRIGGER_BIT); /* Hmm. 506 docs imply we should poll the ready register before reading the return value */ /* Poll the status register for a ready status*/ /* Doesn't look like the windows driver does tho' */ retry = 60; while(--retry) { err_code = spca50x_reg_read(dev, ctrl, base + SPCA50X_I2C_STATUS, 1); if (err_code < 0) PDEBUG(1, "Error reading I2C status register"); if (!err_code) break; } if (!retry) PDEBUG(1, "Too many retries polling I2C status after write to register"); err_code = spca50x_reg_read(dev, ctrl, base + SPCA50X_I2C_READ, 1); if (err_code < 0) PDEBUG(1, "Failed to read I2C register at %d:%d",device,address); PDEBUG(3, "Read %d from %d:%d",err_code,device,address); return err_code;}static int spca50x_read_SAA7113_status(struct usb_spca50x *spca50x){ int value=0; value=spca50x_read_i2c(spca50x,SAA7113_I2C_BASE_READ,SAA7113_REG_STATUS); if(value<0) PDEBUG(1,"Failed to read SAA7113 status"); PDEBUG(1,"7113 status : "); PDEBUG(1," READY %s",(SAA7113_STATUS_READY(value)?"YES":"NO")); PDEBUG(1," COPRO %s",(SAA7113_STATUS_COPRO(value)?"YES":"NO")); /*PDEBUG(1," SLTCA %s",(SAA7113_STATUS_SLTCA(value)?"YES":"NO"));*/ PDEBUG(1," WIPA %s",(SAA7113_STATUS_WIPA(value)?"YES":"NO")); PDEBUG(1," GLIMB %s",(SAA7113_STATUS_GLIMB(value)?"YES":"NO")); PDEBUG(1," GLIMT %s",(SAA7113_STATUS_GLIMT(value)?"YES":"NO")); PDEBUG(1," FIDT %s",(SAA7113_STATUS_FIDT(value)?"YES":"NO")); PDEBUG(1," HLVLN %s",(SAA7113_STATUS_HLVLN(value)?"YES":"NO")); PDEBUG(1," INTL %s",(SAA7113_STATUS_INTL(value)?"YES":"NO")); return value;}static int spca50x_write_i2c(struct usb_spca50x *spca50x,__u16 device,__u16 subaddress,__u16 data){ struct usb_device *dev=spca50x->dev; int err_code; int retry; int ctrl = spca50x->i2c_ctrl_reg; //The I2C control register int base = spca50x->i2c_base; //The I2C base address /* Tell the SPCA50x i2c subsystem the device address of the i2c device */ err_code = spca50x_reg_write(dev, ctrl, base + SPCA50X_I2C_DEVICE,device); /* Poll the status register for a ready status*/ retry = 60; // Arbitrary while(--retry) { err_code = spca50x_reg_read(dev, ctrl, base + SPCA50X_I2C_STATUS, 1); if (err_code < 0) PDEBUG(1,"Error reading I2C status register"); if (!err_code) break; } if (!retry) PDEBUG(1, "Too many retries polling I2C status"); err_code = spca50x_reg_write(dev, ctrl, base + SPCA50X_I2C_SUBADDR, subaddress); err_code = spca50x_reg_write(dev, ctrl, base + SPCA50X_I2C_VALUE,data); if (spca50x->i2c_trigger_on_write) err_code = spca50x_reg_write(dev, ctrl, base + SPCA50X_I2C_TRIGGER, SPCA50X_I2C_TRIGGER_BIT); /* Poll the status register for a ready status*/ retry = 60; while(--retry) { err_code=spca50x_reg_read(dev, ctrl, SPCA50X_I2C_STATUS, 2); if (err_code < 0) PDEBUG(1,"Error reading I2C status register"); if (!err_code) break; } if (!retry) PDEBUG(1, "Too many retries polling I2C status after write to register"); if (debug > 2) { err_code = spca50x_read_i2c(spca50x, device, subaddress); if (err_code < 0) { PDEBUG(3, "Can't read back I2C register value for %d:%d", device, subaddress); } else if ((err_code & 0xff) != (data & 0xff)) PDEBUG(3, "Read back %x should be %x at subaddr %x", err_code, data, subaddress); } return 0;}static int spca50x_write_i2c_vector(struct usb_spca50x *spca50x,__u16 device,__u16 data[][2]){ int I=0; while(data[I][0]) { spca50x_write_i2c(spca50x,device,data[I][0],data[I][1]); I++; } return 0;}static int spca50x_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; /**********************************************************************/ 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_SONIX){ 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: %d %d ",spca50x->iface, alt); if (usb_set_interface(spca50x->dev, spca50x->iface, alt) < 0) { err("Set packet size: set interface error"); return -EBUSY; } #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; } mysize = interface->endpoint[0].desc.wMaxPacketSize; #else interface = &config->interface[spca50x->iface].altsetting[alt]; mysize = interface->endpoint[0].wMaxPacketSize;#endif PDEBUG(1, "set real packet size: %d, alt=%d", mysize, alt); spca50x->packet_size = mysize; spca50x->alt = alt; return 0;}/* Returns number of bits per pixel (regardless of where they are located; planar or * not), or zero for unsupported format. */static int spca50x_get_depth(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: return 8; 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 void spca50x_isoc_irq(struct urb *urb, struct pt_regs *regs) { int i;#elsestatic void spca50x_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; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -