usbvision-core.c
来自「trident tm5600的linux驱动」· C语言 代码 · 共 2,344 行 · 第 1/5 页
C
2,344 行
/* * usbvision-core.c - driver for NT100x USB video capture devices * * * Copyright (c) 1999-2005 Joerg Heckenbach <joerg@heckenbach-aw.de> * Dwaine Garden <dwainegarden@rogers.com> * * This module is part of usbvision driver project. * Updates to driver completed by Dwaine P. Garden * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#include <linux/kernel.h>#include <linux/list.h>#include <linux/timer.h>#include <linux/slab.h>#include <linux/mm.h>#include <linux/utsname.h>#include <linux/highmem.h>#include <linux/vmalloc.h>#include <linux/module.h>#include <linux/init.h>#include <linux/spinlock.h>#include <asm/io.h>#include <linux/videodev2.h>#include <linux/video_decoder.h>#include <linux/i2c.h>#include <media/saa7115.h>#include <media/v4l2-common.h>#include <media/tuner.h>#include <linux/workqueue.h>#include "usbvision.h"static unsigned int core_debug;module_param(core_debug,int,0644);MODULE_PARM_DESC(core_debug,"enable debug messages [core]");static unsigned int force_testpattern;module_param(force_testpattern,int,0644);MODULE_PARM_DESC(force_testpattern,"enable test pattern display [core]");static int adjustCompression = 1; /* Set the compression to be adaptive */module_param(adjustCompression, int, 0444);MODULE_PARM_DESC(adjustCompression, " Set the ADPCM compression for the device. Default: 1 (On)");/* To help people with Black and White output with using s-video input. * Some cables and input device are wired differently. */static int SwitchSVideoInput;module_param(SwitchSVideoInput, int, 0444);MODULE_PARM_DESC(SwitchSVideoInput, " Set the S-Video input. Some cables and input device are wired differently. Default: 0 (Off)");static unsigned int adjust_X_Offset = -1;module_param(adjust_X_Offset, int, 0644);MODULE_PARM_DESC(adjust_X_Offset, "adjust X offset display [core]");static unsigned int adjust_Y_Offset = -1;module_param(adjust_Y_Offset, int, 0644);MODULE_PARM_DESC(adjust_Y_Offset, "adjust Y offset display [core]");#define ENABLE_HEXDUMP 0 /* Enable if you need it */#ifdef USBVISION_DEBUG #define PDEBUG(level, fmt, args...) { \ if (core_debug & (level)) \ printk(KERN_INFO KBUILD_MODNAME ":[%s:%d] " fmt, \ __func__, __LINE__ , ## args); \ }#else #define PDEBUG(level, fmt, args...) do {} while(0)#endif#define DBG_HEADER 1<<0#define DBG_IRQ 1<<1#define DBG_ISOC 1<<2#define DBG_PARSE 1<<3#define DBG_SCRATCH 1<<4#define DBG_FUNC 1<<5static const int max_imgwidth = MAX_FRAME_WIDTH;static const int max_imgheight = MAX_FRAME_HEIGHT;static const int min_imgwidth = MIN_FRAME_WIDTH;static const int min_imgheight = MIN_FRAME_HEIGHT;/* The value of 'scratch_buf_size' affects quality of the picture * in many ways. Shorter buffers may cause loss of data when client * is too slow. Larger buffers are memory-consuming and take longer * to work with. This setting can be adjusted, but the default value * should be OK for most desktop users. */#define DEFAULT_SCRATCH_BUF_SIZE (0x20000) // 128kB memory scratch bufferstatic const int scratch_buf_size = DEFAULT_SCRATCH_BUF_SIZE;// Function prototypesstatic int usbvision_request_intra (struct usb_usbvision *usbvision);static int usbvision_unrequest_intra (struct usb_usbvision *usbvision);static int usbvision_adjust_compression (struct usb_usbvision *usbvision);static int usbvision_measure_bandwidth (struct usb_usbvision *usbvision);/*******************************//* Memory management functions *//*******************************//* * Here we want the physical address of the memory. * This is used when initializing the contents of the area. */static void *usbvision_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 usbvision_rvfree(void *mem, unsigned long size){ unsigned long adr; if (!mem) return; size = PAGE_ALIGN(size); adr = (unsigned long) mem; while ((long) size > 0) { ClearPageReserved(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; size -= PAGE_SIZE; } vfree(mem);}#if ENABLE_HEXDUMPstatic void usbvision_hexdump(const unsigned char *data, int len){ char tmp[80]; int i, k; for (i = k = 0; len > 0; i++, len--) { if (i > 0 && (i % 16 == 0)) { printk("%s\n", tmp); k = 0; } k += sprintf(&tmp[k], "%02x ", data[i]); } if (k > 0) printk("%s\n", tmp);}#endif/******************************** * scratch ring buffer handling ********************************/static int scratch_len(struct usb_usbvision *usbvision) /*This returns the amount of data actually in the buffer */{ int len = usbvision->scratch_write_ptr - usbvision->scratch_read_ptr; if (len < 0) { len += scratch_buf_size; } PDEBUG(DBG_SCRATCH, "scratch_len() = %d\n", len); return len;}/* This returns the free space left in the buffer */static int scratch_free(struct usb_usbvision *usbvision){ int free = usbvision->scratch_read_ptr - usbvision->scratch_write_ptr; if (free <= 0) { free += scratch_buf_size; } if (free) { free -= 1; /* at least one byte in the buffer must */ /* left blank, otherwise there is no chance to differ between full and empty */ } PDEBUG(DBG_SCRATCH, "return %d\n", free); return free;}/* This puts data into the buffer */static int scratch_put(struct usb_usbvision *usbvision, unsigned char *data, int len){ int len_part; if (usbvision->scratch_write_ptr + len < scratch_buf_size) { memcpy(usbvision->scratch + usbvision->scratch_write_ptr, data, len); usbvision->scratch_write_ptr += len; } else { len_part = scratch_buf_size - usbvision->scratch_write_ptr; memcpy(usbvision->scratch + usbvision->scratch_write_ptr, data, len_part); if (len == len_part) { usbvision->scratch_write_ptr = 0; /* just set write_ptr to zero */ } else { memcpy(usbvision->scratch, data + len_part, len - len_part); usbvision->scratch_write_ptr = len - len_part; } } PDEBUG(DBG_SCRATCH, "len=%d, new write_ptr=%d\n", len, usbvision->scratch_write_ptr); return len;}/* This marks the write_ptr as position of new frame header */static void scratch_mark_header(struct usb_usbvision *usbvision){ PDEBUG(DBG_SCRATCH, "header at write_ptr=%d\n", usbvision->scratch_headermarker_write_ptr); usbvision->scratch_headermarker[usbvision->scratch_headermarker_write_ptr] = usbvision->scratch_write_ptr; usbvision->scratch_headermarker_write_ptr += 1; usbvision->scratch_headermarker_write_ptr %= USBVISION_NUM_HEADERMARKER;}/* This gets data from the buffer at the given "ptr" position */static int scratch_get_extra(struct usb_usbvision *usbvision, unsigned char *data, int *ptr, int len){ int len_part; if (*ptr + len < scratch_buf_size) { memcpy(data, usbvision->scratch + *ptr, len); *ptr += len; } else { len_part = scratch_buf_size - *ptr; memcpy(data, usbvision->scratch + *ptr, len_part); if (len == len_part) { *ptr = 0; /* just set the y_ptr to zero */ } else { memcpy(data + len_part, usbvision->scratch, len - len_part); *ptr = len - len_part; } } PDEBUG(DBG_SCRATCH, "len=%d, new ptr=%d\n", len, *ptr); return len;}/* This sets the scratch extra read pointer */static void scratch_set_extra_ptr(struct usb_usbvision *usbvision, int *ptr, int len){ *ptr = (usbvision->scratch_read_ptr + len)%scratch_buf_size; PDEBUG(DBG_SCRATCH, "ptr=%d\n", *ptr);}/*This increments the scratch extra read pointer */static void scratch_inc_extra_ptr(int *ptr, int len){ *ptr = (*ptr + len) % scratch_buf_size; PDEBUG(DBG_SCRATCH, "ptr=%d\n", *ptr);}/* This gets data from the buffer */static int scratch_get(struct usb_usbvision *usbvision, unsigned char *data, int len){ int len_part; if (usbvision->scratch_read_ptr + len < scratch_buf_size) { memcpy(data, usbvision->scratch + usbvision->scratch_read_ptr, len); usbvision->scratch_read_ptr += len; } else { len_part = scratch_buf_size - usbvision->scratch_read_ptr; memcpy(data, usbvision->scratch + usbvision->scratch_read_ptr, len_part); if (len == len_part) { usbvision->scratch_read_ptr = 0; /* just set the read_ptr to zero */ } else { memcpy(data + len_part, usbvision->scratch, len - len_part); usbvision->scratch_read_ptr = len - len_part; } } PDEBUG(DBG_SCRATCH, "len=%d, new read_ptr=%d\n", len, usbvision->scratch_read_ptr); return len;}/* This sets read pointer to next header and returns it */static int scratch_get_header(struct usb_usbvision *usbvision, struct usbvision_frame_header *header){ int errCode = 0; PDEBUG(DBG_SCRATCH, "from read_ptr=%d", usbvision->scratch_headermarker_read_ptr); while (usbvision->scratch_headermarker_write_ptr - usbvision->scratch_headermarker_read_ptr != 0) { usbvision->scratch_read_ptr = usbvision->scratch_headermarker[usbvision->scratch_headermarker_read_ptr]; usbvision->scratch_headermarker_read_ptr += 1; usbvision->scratch_headermarker_read_ptr %= USBVISION_NUM_HEADERMARKER; scratch_get(usbvision, (unsigned char *)header, USBVISION_HEADER_LENGTH); if ((header->magic_1 == USBVISION_MAGIC_1) && (header->magic_2 == USBVISION_MAGIC_2) && (header->headerLength == USBVISION_HEADER_LENGTH)) { errCode = USBVISION_HEADER_LENGTH; header->frameWidth = header->frameWidthLo + (header->frameWidthHi << 8); header->frameHeight = header->frameHeightLo + (header->frameHeightHi << 8); break; } } return errCode;}/*This removes len bytes of old data from the buffer */static void scratch_rm_old(struct usb_usbvision *usbvision, int len){ usbvision->scratch_read_ptr += len; usbvision->scratch_read_ptr %= scratch_buf_size; PDEBUG(DBG_SCRATCH, "read_ptr is now %d\n", usbvision->scratch_read_ptr);}/*This resets the buffer - kills all data in it too */static void scratch_reset(struct usb_usbvision *usbvision){ PDEBUG(DBG_SCRATCH, "\n"); usbvision->scratch_read_ptr = 0; usbvision->scratch_write_ptr = 0; usbvision->scratch_headermarker_read_ptr = 0; usbvision->scratch_headermarker_write_ptr = 0; usbvision->isocstate = IsocState_NoFrame;}int usbvision_scratch_alloc(struct usb_usbvision *usbvision){ usbvision->scratch = vmalloc_32(scratch_buf_size); scratch_reset(usbvision); if(usbvision->scratch == NULL) { err("%s: unable to allocate %d bytes for scratch", __func__, scratch_buf_size); return -ENOMEM; } return 0;}void usbvision_scratch_free(struct usb_usbvision *usbvision){ if (usbvision->scratch != NULL) { vfree(usbvision->scratch); usbvision->scratch = NULL; }}/* * usbvision_testpattern() * * Procedure forms a test pattern (yellow grid on blue background). * * Parameters: * fullframe: if TRUE then entire frame is filled, otherwise the procedure * continues from the current scanline. * pmode 0: fill the frame with solid blue color (like on VCR or TV) * 1: Draw a colored grid * */static void usbvision_testpattern(struct usb_usbvision *usbvision, int fullframe, int pmode){ static const char proc[] = "usbvision_testpattern"; struct usbvision_frame *frame; unsigned char *f; int num_cell = 0; int scan_length = 0; static int num_pass; if (usbvision == NULL) { printk(KERN_ERR "%s: usbvision == NULL\n", proc); return; } if (usbvision->curFrame == NULL) { printk(KERN_ERR "%s: usbvision->curFrame is NULL.\n", proc); return; } /* Grab the current frame */ frame = usbvision->curFrame; /* Optionally start at the beginning */ if (fullframe) { frame->curline = 0; frame->scanlength = 0; } /* Form every scan line */ for (; frame->curline < frame->frmheight; frame->curline++) { int i; f = frame->data + (usbvision->curwidth * 3 * frame->curline); for (i = 0; i < usbvision->curwidth; i++) { unsigned char cb = 0x80; unsigned char cg = 0; unsigned char cr = 0; if (pmode == 1) { if (frame->curline % 32 == 0) cb = 0, cg = cr = 0xFF; else if (i % 32 == 0) { if (frame->curline % 32 == 1) num_cell++; cb = 0, cg = cr = 0xFF; } else { cb = ((num_cell * 7) + num_pass) & 0xFF; cg = ((num_cell * 5) + num_pass * 2) & 0xFF; cr = ((num_cell * 3) + num_pass * 3) & 0xFF; } } else { /* Just the blue screen */ }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?