📄 ibmcam.c
字号:
/* * USB IBM C-It Video Camera driver * * Supports IBM C-It Video Camera. * * This driver is based on earlier work of: * * (C) Copyright 1999 Johannes Erdfelt * (C) Copyright 1999 Randy Dunlap * * 5/24/00 Removed optional (and unnecessary) locking of the driver while * the device remains plugged in. Corrected race conditions in ibmcam_open * and ibmcam_probe() routines using this as a guideline: * * (2) The big kernel lock is automatically released when a process sleeps * in the kernel and is automatically reacquired on reschedule if the * process had the lock originally. Any code that can be compiled as * a module and is entered with the big kernel lock held *MUST* * increment the use count to activate the indirect module protection * before doing anything that might sleep. * * In practice, this means that all routines that live in modules and * are invoked under the big kernel lock should do MOD_INC_USE_COUNT * as their very first action. And all failure paths from that * routine must do MOD_DEC_USE_COUNT before returning. */#include <linux/kernel.h>#include <linux/sched.h>#include <linux/list.h>#include <linux/malloc.h>#include <linux/mm.h>#include <linux/smp_lock.h>#include <linux/videodev.h>#include <linux/vmalloc.h>#include <linux/wrapper.h>#include <linux/module.h>#include <linux/init.h>#include <linux/spinlock.h>#include <linux/usb.h>#include <asm/io.h>#include "ibmcam.h"#define ENABLE_HEXDUMP 0 /* Enable if you need it */static int debug = 0;/* Completion states of the data parser */typedef enum { scan_Continue, /* Just parse next item */ scan_NextFrame, /* Frame done, send it to V4L */ scan_Out, /* Not enough data for frame */ scan_EndParse /* End parsing */} scan_state_t;/* Bit flags (options) */#define FLAGS_RETRY_VIDIOCSYNC (1 << 0)#define FLAGS_MONOCHROME (1 << 1)#define FLAGS_DISPLAY_HINTS (1 << 2)#define FLAGS_OVERLAY_STATS (1 << 3)#define FLAGS_FORCE_TESTPATTERN (1 << 4)#define FLAGS_SEPARATE_FRAMES (1 << 5)#define FLAGS_CLEAN_FRAMES (1 << 6)static int flags = 0; /* FLAGS_DISPLAY_HINTS | FLAGS_OVERLAY_STATS; *//* This is the size of V4L frame that we provide */static const int imgwidth = V4L_FRAME_WIDTH_USED;static const int imgheight = V4L_FRAME_HEIGHT;static const int min_imgwidth = 8;static const int min_imgheight = 4;static int lighting = 1; /* Medium */#define SHARPNESS_MIN 0#define SHARPNESS_MAX 6static int sharpness = 4; /* Low noise, good details */#define FRAMERATE_MIN 0#define FRAMERATE_MAX 6static int framerate = 2; /* Lower, reliable frame rate (8-12 fps) */enum { VIDEOSIZE_128x96 = 0, VIDEOSIZE_176x144, VIDEOSIZE_352x288, VIDEOSIZE_320x240, VIDEOSIZE_352x240,};static int videosize = VIDEOSIZE_352x288;/* * The value of 'scratchbufsize' 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 (0x10000) /* 64 KB */static const int scratchbufsize = DEFAULT_SCRATCH_BUF_SIZE;/* * Here we define several initialization variables. They may * be used to automatically set color, hue, brightness and * contrast to desired values. This is particularly useful in * case of webcams (which have no controls and no on-screen * output) and also when a client V4L software is used that * does not have some of those controls. In any case it's * good to have startup values as options. * * These values are all in [0..255] range. This simplifies * operation. Note that actual values of V4L variables may * be scaled up (as much as << 8). User can see that only * on overlay output, however, or through a V4L client. */static int init_brightness = 128;static int init_contrast = 192;static int init_color = 128;static int init_hue = 128;static int hue_correction = 128;/* Settings for camera model 2 */static int init_model2_rg = -1;static int init_model2_rg2 = -1;static int init_model2_sat = -1;static int init_model2_yb = -1;MODULE_PARM(debug, "i");MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");MODULE_PARM(flags, "i");MODULE_PARM_DESC(flags, "Bitfield: 0=VIDIOCSYNC, 1=B/W, 2=show hints, 3=show stats, 4=test pattern, 5=seperate frames, 6=clean frames");MODULE_PARM(framerate, "i");MODULE_PARM_DESC(framerate, "Framerate setting: 0=slowest, 6=fastest (default=2)");MODULE_PARM(lighting, "i");MODULE_PARM_DESC(lighting, "Photosensitivity: 0=bright, 1=medium (default), 2=low light");MODULE_PARM(sharpness, "i");MODULE_PARM_DESC(sharpness, "Model1 noise reduction: 0=smooth, 6=sharp (default=4)");MODULE_PARM(videosize, "i");MODULE_PARM_DESC(videosize, "Image size: 0=128x96, 1=176x144, 2=352x288, 3=320x240, 4=352x240 (default=1)");MODULE_PARM(init_brightness, "i");MODULE_PARM_DESC(init_brightness, "Brightness preconfiguration: 0-255 (default=128)");MODULE_PARM(init_contrast, "i");MODULE_PARM_DESC(init_contrast, "Contrast preconfiguration: 0-255 (default=192)");MODULE_PARM(init_color, "i");MODULE_PARM_DESC(init_color, "Dolor preconfiguration: 0-255 (default=128)");MODULE_PARM(init_hue, "i");MODULE_PARM_DESC(init_hue, "Hue preconfiguration: 0-255 (default=128)");MODULE_PARM(hue_correction, "i");MODULE_PARM_DESC(hue_correction, "YUV colorspace regulation: 0-255 (default=128)");MODULE_PARM(init_model2_rg, "i");MODULE_PARM_DESC(init_model2_rg, "Model2 preconfiguration: 0-255 (default=112)");MODULE_PARM(init_model2_rg2, "i");MODULE_PARM_DESC(init_model2_rg2, "Model2 preconfiguration: 0-255 (default=47)");MODULE_PARM(init_model2_sat, "i");MODULE_PARM_DESC(init_model2_sat, "Model2 preconfiguration: 0-255 (default=52)");MODULE_PARM(init_model2_yb, "i");MODULE_PARM_DESC(init_model2_yb, "Model2 preconfiguration: 0-255 (default=160)");MODULE_AUTHOR ("module author");MODULE_DESCRIPTION ("IBM/Xirlink C-it USB Camera Driver for Linux (c) 2000");/* Still mysterious i2c commands */static const unsigned short unknown_88 = 0x0088;static const unsigned short unknown_89 = 0x0089;static const unsigned short bright_3x[3] = { 0x0031, 0x0032, 0x0033 };static const unsigned short contrast_14 = 0x0014;static const unsigned short light_27 = 0x0027;static const unsigned short sharp_13 = 0x0013;/* i2c commands for Model 2 cameras */static const unsigned short mod2_brightness = 0x001a; /* $5b .. $ee; default=$5a */static const unsigned short mod2_set_framerate = 0x001c; /* 0 (fast).. $1F (slow) */static const unsigned short mod2_color_balance_rg2 = 0x001e; /* 0 (red) .. $7F (green) */static const unsigned short mod2_saturation = 0x0020; /* 0 (b/w) - $7F (full color) */static const unsigned short mod2_color_balance_yb = 0x0022; /* 0..$7F, $50 is about right */static const unsigned short mod2_color_balance_rg = 0x0024; /* 0..$7F, $70 is about right */static const unsigned short mod2_sensitivity = 0x0028; /* 0 (min) .. $1F (max) */#define MAX_IBMCAM 4struct usb_ibmcam cams[MAX_IBMCAM];/*******************************//* Memory management functions *//*******************************/#define MDEBUG(x) do { } while(0) /* Debug memory management */static struct usb_driver ibmcam_driver;static void usb_ibmcam_release(struct usb_ibmcam *ibmcam);/* Given PGD from the address space's page table, return the kernel * virtual mapping of the physical memory mapped at ADR. */static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr){ unsigned long ret = 0UL; pmd_t *pmd; pte_t *ptep, pte; if (!pgd_none(*pgd)) { pmd = pmd_offset(pgd, adr); if (!pmd_none(*pmd)) { ptep = pte_offset(pmd, adr); pte = *ptep; if (pte_present(pte)) { ret = (unsigned long) page_address(pte_page(pte)); ret |= (adr & (PAGE_SIZE - 1)); } } } MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret)); return ret;}static inline unsigned long uvirt_to_bus(unsigned long adr){ unsigned long kva, ret; kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr); ret = virt_to_bus((void *)kva); MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret)); return ret;}static inline unsigned long kvirt_to_bus(unsigned long adr){ unsigned long va, kva, ret; va = VMALLOC_VMADDR(adr); kva = uvirt_to_kva(pgd_offset_k(va), va); ret = virt_to_bus((void *)kva); MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret)); return ret;}/* 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. */static inline unsigned long kvirt_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); MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret)); return ret;}static void *rvmalloc(unsigned long size){ void *mem; unsigned long adr, page; /* Round it off to PAGE_SIZE */ size += (PAGE_SIZE - 1); size &= ~(PAGE_SIZE - 1); 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) { page = kvirt_to_pa(adr); mem_map_reserve(virt_to_page(__va(page))); adr += PAGE_SIZE; if (size > PAGE_SIZE) size -= PAGE_SIZE; else size = 0; } return mem;}static void rvfree(void *mem, unsigned long size){ unsigned long adr, page; if (!mem) return; size += (PAGE_SIZE - 1); size &= ~(PAGE_SIZE - 1); adr=(unsigned long) mem; while (size > 0) { page = kvirt_to_pa(adr); mem_map_unreserve(virt_to_page(__va(page))); adr += PAGE_SIZE; if (size > PAGE_SIZE) size -= PAGE_SIZE; else size = 0; } vfree(mem);}#if ENABLE_HEXDUMPstatic void ibmcam_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/* * usb_ibmcam_overlaychar() * * History: * 1/2/00 Created. */void usb_ibmcam_overlaychar( struct usb_ibmcam *ibmcam, struct ibmcam_frame *frame, int x, int y, int ch){ static const unsigned short digits[16] = { 0xF6DE, /* 0 */ 0x2492, /* 1 */ 0xE7CE, /* 2 */ 0xE79E, /* 3 */ 0xB792, /* 4 */ 0xF39E, /* 5 */ 0xF3DE, /* 6 */ 0xF492, /* 7 */ 0xF7DE, /* 8 */ 0xF79E, /* 9 */ 0x77DA, /* a */ 0xD75C, /* b */ 0xF24E, /* c */ 0xD6DC, /* d */ 0xF34E, /* e */ 0xF348 /* f */ }; unsigned short digit; int ix, iy; if ((ibmcam == NULL) || (frame == NULL)) return; if (ch >= '0' && ch <= '9') ch -= '0'; else if (ch >= 'A' && ch <= 'F') ch = 10 + (ch - 'A'); else if (ch >= 'a' && ch <= 'f') ch = 10 + (ch - 'a'); else return; digit = digits[ch]; for (iy=0; iy < 5; iy++) { for (ix=0; ix < 3; ix++) { if (digit & 0x8000) { IBMCAM_PUTPIXEL(frame, x+ix, y+iy, 0xFF, 0xFF, 0xFF); } digit = digit << 1; } }}/* * usb_ibmcam_overlaystring() * * History: * 1/2/00 Created. */void usb_ibmcam_overlaystring( struct usb_ibmcam *ibmcam, struct ibmcam_frame *frame, int x, int y, const char *str){ while (*str) { usb_ibmcam_overlaychar(ibmcam, frame, x, y, *str); str++; x += 4; /* 3 pixels character + 1 space */ }}/* * usb_ibmcam_overlaystats() * * Overlays important debugging information. * * History: * 1/2/00 Created. */void usb_ibmcam_overlaystats(struct usb_ibmcam *ibmcam, struct ibmcam_frame *frame){ const int y_diff = 8; char tmp[16]; int x = 10; int y = 10; sprintf(tmp, "%8x", ibmcam->frame_num); usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp); y += y_diff; sprintf(tmp, "%8lx", ibmcam->urb_count); usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp); y += y_diff; sprintf(tmp, "%8lx", ibmcam->urb_length); usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp); y += y_diff; sprintf(tmp, "%8lx", ibmcam->data_count); usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp); y += y_diff; sprintf(tmp, "%8lx", ibmcam->header_count); usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp); y += y_diff;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -