?? w9968cf.c
字號:
" for every device." "\n");MODULE_PARM_DESC(contrast, "\n<n[,...]> Set picture contrast (0-65535)." "\nDefault value is "__MODULE_STRING(W9968CF_CONTRAST) " for every device." "\n");MODULE_PARM_DESC(whiteness, "\n<n[,...]> Set picture whiteness (0-65535)." "\nDefault value is "__MODULE_STRING(W9968CF_WHITENESS) " for every device." "\n");#ifdef W9968CF_DEBUGMODULE_PARM_DESC(debug, "\n<n> Debugging information level, from 0 to 6:" "\n0 = none (use carefully)" "\n1 = critical errors" "\n2 = significant informations" "\n3 = configuration or general messages" "\n4 = warnings" "\n5 = called functions" "\n6 = function internals" "\nLevel 5 and 6 are useful for testing only, when only " "one device is used." "\nDefault value is "__MODULE_STRING(W9968CF_DEBUG_LEVEL)"." "\n");MODULE_PARM_DESC(specific_debug, "\n<0|1> Enable or disable specific debugging messages:" "\n0 = print messages concerning every level" " <= 'debug' level." "\n1 = print messages concerning the level" " indicated by 'debug'." "\nDefault value is " __MODULE_STRING(W9968CF_SPECIFIC_DEBUG)"." "\n");#endif /* W9968CF_DEBUG *//**************************************************************************** * Some prototypes * ****************************************************************************//* Video4linux interface */static struct file_operations w9968cf_fops;static int w9968cf_open(struct inode*, struct file*);static int w9968cf_release(struct inode*, struct file*);static int w9968cf_mmap(struct file*, struct vm_area_struct*);static int w9968cf_ioctl(struct inode*, struct file*, unsigned, unsigned long);static ssize_t w9968cf_read(struct file*, char __user *, size_t, loff_t*);static int w9968cf_v4l_ioctl(struct inode*, struct file*, unsigned int, void __user *);/* USB-specific */static int w9968cf_start_transfer(struct w9968cf_device*);static int w9968cf_stop_transfer(struct w9968cf_device*);static int w9968cf_write_reg(struct w9968cf_device*, u16 value, u16 index);static int w9968cf_read_reg(struct w9968cf_device*, u16 index);static int w9968cf_write_fsb(struct w9968cf_device*, u16* data);static int w9968cf_write_sb(struct w9968cf_device*, u16 value);static int w9968cf_read_sb(struct w9968cf_device*);static int w9968cf_upload_quantizationtables(struct w9968cf_device*);static void w9968cf_urb_complete(struct urb *urb, struct pt_regs *regs);/* Low-level I2C (SMBus) I/O */static int w9968cf_smbus_start(struct w9968cf_device*);static int w9968cf_smbus_stop(struct w9968cf_device*);static int w9968cf_smbus_write_byte(struct w9968cf_device*, u8 v);static int w9968cf_smbus_read_byte(struct w9968cf_device*, u8* v);static int w9968cf_smbus_write_ack(struct w9968cf_device*);static int w9968cf_smbus_read_ack(struct w9968cf_device*);static int w9968cf_smbus_refresh_bus(struct w9968cf_device*);static int w9968cf_i2c_adap_read_byte(struct w9968cf_device* cam, u16 address, u8* value);static int w9968cf_i2c_adap_read_byte_data(struct w9968cf_device*, u16 address, u8 subaddress, u8* value);static int w9968cf_i2c_adap_write_byte(struct w9968cf_device*, u16 address, u8 subaddress);static int w9968cf_i2c_adap_fastwrite_byte_data(struct w9968cf_device*, u16 address, u8 subaddress, u8 value);/* I2C interface to kernel */static int w9968cf_i2c_init(struct w9968cf_device*);static int w9968cf_i2c_smbus_xfer(struct i2c_adapter*, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data*);static u32 w9968cf_i2c_func(struct i2c_adapter*);static int w9968cf_i2c_attach_inform(struct i2c_client*);static int w9968cf_i2c_detach_inform(struct i2c_client*);static int w9968cf_i2c_control(struct i2c_adapter*, unsigned int cmd, unsigned long arg);/* Memory management */static inline unsigned long kvirt_to_pa(unsigned long adr);static void* rvmalloc(unsigned long size);static void rvfree(void *mem, unsigned long size);static void w9968cf_deallocate_memory(struct w9968cf_device*);static int w9968cf_allocate_memory(struct w9968cf_device*);/* High-level image sensor control functions */static int w9968cf_sensor_set_control(struct w9968cf_device*,int cid,int val);static int w9968cf_sensor_get_control(struct w9968cf_device*,int cid,int *val);static int w9968cf_sensor_cmd(struct w9968cf_device*, unsigned int cmd, void *arg);static int w9968cf_sensor_init(struct w9968cf_device*);static int w9968cf_sensor_update_settings(struct w9968cf_device*);static int w9968cf_sensor_get_picture(struct w9968cf_device*);static int w9968cf_sensor_update_picture(struct w9968cf_device*, struct video_picture pict);/* Other helper functions */static void w9968cf_configure_camera(struct w9968cf_device*,struct usb_device*, enum w9968cf_model_id, const unsigned short dev_nr);static void w9968cf_adjust_configuration(struct w9968cf_device*);static int w9968cf_turn_on_led(struct w9968cf_device*);static int w9968cf_init_chip(struct w9968cf_device*);static inline u16 w9968cf_valid_palette(u16 palette);static inline u16 w9968cf_valid_depth(u16 palette);static inline u8 w9968cf_need_decompression(u16 palette);static int w9968cf_set_picture(struct w9968cf_device*, struct video_picture);static int w9968cf_set_window(struct w9968cf_device*, struct video_window);static int w9968cf_postprocess_frame(struct w9968cf_device*, struct w9968cf_frame_t*);static int w9968cf_adjust_window_size(struct w9968cf_device*, u16* w, u16* h);static void w9968cf_init_framelist(struct w9968cf_device*);static void w9968cf_push_frame(struct w9968cf_device*, u8 f_num);static void w9968cf_pop_frame(struct w9968cf_device*,struct w9968cf_frame_t**);static void w9968cf_release_resources(struct w9968cf_device*);/* Intermodule communication */static int w9968cf_vppmod_detect(struct w9968cf_device*);static void w9968cf_vppmod_release(struct w9968cf_device*);/**************************************************************************** * Symbolic names * ****************************************************************************//* Used to represent a list of values and their respective symbolic names */struct w9968cf_symbolic_list { const int num; const char *name;};/*-------------------------------------------------------------------------- Returns the name of the matching element in the symbolic_list array. The end of the list must be marked with an element that has a NULL name. --------------------------------------------------------------------------*/static inline const char * symbolic(struct w9968cf_symbolic_list list[], const int num){ int i; for (i = 0; list[i].name != NULL; i++) if (list[i].num == num) return (list[i].name); return "Unknown";}static struct w9968cf_symbolic_list camlist[] = { { W9968CF_MOD_GENERIC, "W996[87]CF JPEG USB Dual Mode Camera" }, { W9968CF_MOD_CLVBWGP, "Creative Labs Video Blaster WebCam Go Plus" }, /* Other cameras (having the same descriptors as Generic W996[87]CF) */ { W9968CF_MOD_ADPVDMA, "Aroma Digi Pen VGA Dual Mode ADG-5000" }, { W9986CF_MOD_AAU, "AVerMedia AVerTV USB" }, { W9968CF_MOD_CLVBWG, "Creative Labs Video Blaster WebCam Go" }, { W9968CF_MOD_LL, "Lebon LDC-035A" }, { W9968CF_MOD_EEEMC, "Ezonics EZ-802 EZMega Cam" }, { W9968CF_MOD_OOE, "OmniVision OV8610-EDE" }, { W9968CF_MOD_ODPVDMPC, "OPCOM Digi Pen VGA Dual Mode Pen Camera" }, { W9968CF_MOD_PDPII, "Pretec Digi Pen-II" }, { W9968CF_MOD_PDP480, "Pretec DigiPen-480" }, { -1, NULL }};static struct w9968cf_symbolic_list senlist[] = { { CC_OV76BE, "OV76BE" }, { CC_OV7610, "OV7610" }, { CC_OV7620, "OV7620" }, { CC_OV7620AE, "OV7620AE" }, { CC_OV6620, "OV6620" }, { CC_OV6630, "OV6630" }, { CC_OV6630AE, "OV6630AE" }, { CC_OV6630AF, "OV6630AF" }, { -1, NULL }};/* Video4Linux1 palettes */static struct w9968cf_symbolic_list v4l1_plist[] = { { VIDEO_PALETTE_GREY, "GREY" }, { VIDEO_PALETTE_HI240, "HI240" }, { VIDEO_PALETTE_RGB565, "RGB565" }, { VIDEO_PALETTE_RGB24, "RGB24" }, { VIDEO_PALETTE_RGB32, "RGB32" }, { VIDEO_PALETTE_RGB555, "RGB555" }, { VIDEO_PALETTE_YUV422, "YUV422" }, { VIDEO_PALETTE_YUYV, "YUYV" }, { VIDEO_PALETTE_UYVY, "UYVY" }, { VIDEO_PALETTE_YUV420, "YUV420" }, { VIDEO_PALETTE_YUV411, "YUV411" }, { VIDEO_PALETTE_RAW, "RAW" }, { VIDEO_PALETTE_YUV422P, "YUV422P" }, { VIDEO_PALETTE_YUV411P, "YUV411P" }, { VIDEO_PALETTE_YUV420P, "YUV420P" }, { VIDEO_PALETTE_YUV410P, "YUV410P" }, { -1, NULL }};/* Decoder error codes: */static struct w9968cf_symbolic_list decoder_errlist[] = { { W9968CF_DEC_ERR_CORRUPTED_DATA, "Corrupted data" }, { W9968CF_DEC_ERR_BUF_OVERFLOW, "Buffer overflow" }, { W9968CF_DEC_ERR_NO_SOI, "SOI marker not found" }, { W9968CF_DEC_ERR_NO_SOF0, "SOF0 marker not found" }, { W9968CF_DEC_ERR_NO_SOS, "SOS marker not found" }, { W9968CF_DEC_ERR_NO_EOI, "EOI marker not found" }, { -1, NULL }};/* URB error codes: */static struct w9968cf_symbolic_list urb_errlist[] = { { -ENOMEM, "No memory for allocation of internal structures" }, { -ENOSPC, "The host controller's bandwidth is already consumed" }, { -ENOENT, "URB was canceled by unlink_urb" }, { -EXDEV, "ISO transfer only partially completed" }, { -EAGAIN, "Too match scheduled for the future" }, { -ENXIO, "URB already queued" }, { -EFBIG, "Too much ISO frames requested" }, { -ENOSR, "Buffer error (overrun)" }, { -EPIPE, "Specified endpoint is stalled (device not responding)"}, { -EOVERFLOW, "Babble (bad cable?)" }, { -EPROTO, "Bit-stuff error (bad cable?)" }, { -EILSEQ, "CRC/Timeout" }, { -ETIMEDOUT, "NAK (device does not respond)" }, { -1, NULL }};/**************************************************************************** * Memory management functions * ****************************************************************************//* Here we want the physical address of the memory. This is used when initializing the contents of the area. */static inline unsigned long kvirt_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;}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 (size > 0) { SetPageReserved(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; size -= PAGE_SIZE; } return mem;}static void rvfree(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);}/*-------------------------------------------------------------------------- Deallocate previously allocated memory. --------------------------------------------------------------------------*/static void w9968cf_deallocate_memory(struct w9968cf_device* cam){ u8 i; /* Free the isochronous transfer buffers */ for (i = 0; i < W9968CF_URBS; i++) { kfree(cam->transfer_buffer[i]); cam->transfer_buffer[i] = NULL; } /* Free temporary frame buffer */ if (cam->frame_tmp.buffer) { rvfree(cam->frame_tmp.buffer, cam->frame_tmp.size); cam->frame_tmp.buffer = NULL; } /* Free helper buffer */ if (cam->frame_vpp.buffer) { rvfree(cam->frame_vpp.buffer, cam->frame_vpp.size); cam->frame_vpp.buffer = NULL; } /* Free video frame buffers */ if (cam->frame[0].buffer) { rvfree(cam->frame[0].buffer, cam->nbuffers*cam->frame[0].size); cam->frame[0].buffer = NULL; } cam->nbuffers = 0; DBG(5, "Memory successfully deallocated")}/*-------------------------------------------------------------------------- Allocate memory buffers for USB transfers and video frames. This function is called by open() only. Return 0 on success, a negative number otherwise. --------------------------------------------------------------------------*/static int w9968cf_allocate_memory(struct w9968cf_device* cam){ const u16 p_size = wMaxPacketSize[cam->altsetting-1]; void* buff = NULL; unsigned long hw_bufsize, vpp_bufsize; u8 i, bpp; /* NOTE: Deallocation is done elsewhere in case of error */ /* Calculate the max amount of raw data per frame from the device */ hw_bufsize = cam->maxwidth*cam->maxheight*2; /* Calculate the max buf. size needed for post-processing routines */ bpp = (w9968cf_vpp) ? 4 : 2; if (cam->upscaling) vpp_bufsize = max(W9968CF_MAX_WIDTH*W9968CF_MAX_HEIGHT*bpp, cam->maxwidth*cam->maxheight*bpp); else vpp_bufsize = cam->maxwidth*cam->maxheight*bpp; /* Allocate memory for the isochronous transfer buffers */ for (i = 0; i < W9968CF_URBS; i++) {
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -