📄 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/wrapper.h>#include <linux/module.h>#include <linux/init.h>#include "usbvideo.h"#define IBMCAM_VENDOR_ID 0x0545#define IBMCAM_PRODUCT_ID 0x8080#define NETCAM_PRODUCT_ID 0x8002 /* IBM NetCamera, close to model 2 */#define MAX_IBMCAM 4 /* How many devices we allow to connect */#define USES_IBMCAM_PUTPIXEL 0 /* 0=Fast/oops 1=Slow/secure *//* Header signatures *//* Model 1 header: 00 FF 00 xx */#define HDRSIG_MODEL1_128x96 0x06 /* U Y V Y ... */#define HDRSIG_MODEL1_176x144 0x0e /* U Y V Y ... */#define HDRSIG_MODEL1_352x288 0x00 /* V Y U Y ... */#define IBMCAM_MODEL_1 1 /* XVP-501, 3 interfaces, rev. 0.02 */#define IBMCAM_MODEL_2 2 /* KSX-X9903, 2 interfaces, rev. 3.0a */#define IBMCAM_MODEL_3 3 /* KSX-X9902, 2 interfaces, rev. 3.01 */#define IBMCAM_MODEL_4 4 /* IBM NetCamera, 0545/8002/3.0a *//* Video sizes supported */#define VIDEOSIZE_128x96 VIDEOSIZE(128, 96)#define VIDEOSIZE_176x144 VIDEOSIZE(176,144)#define VIDEOSIZE_352x288 VIDEOSIZE(352,288)#define VIDEOSIZE_320x240 VIDEOSIZE(320,240)#define VIDEOSIZE_352x240 VIDEOSIZE(352,240)#define VIDEOSIZE_640x480 VIDEOSIZE(640,480)#define VIDEOSIZE_160x120 VIDEOSIZE(160,120)/* Video sizes supported */enum { SIZE_128x96 = 0, SIZE_160x120, SIZE_176x144, SIZE_320x240, SIZE_352x240, SIZE_352x288, SIZE_640x480, /* Add/remove/rearrange items before this line */ SIZE_LastItem};/* * This structure lives in uvd_t->user field. */typedef struct { int initialized; /* Had we already sent init sequence? */ int camera_model; /* What type of IBM camera we got? */ int has_hdr;} ibmcam_t;#define IBMCAM_T(uvd) ((ibmcam_t *)((uvd)->user_data))usbvideo_t *cams = NULL;static int debug = 0;static int flags = 0; /* FLAGS_DISPLAY_HINTS | FLAGS_OVERLAY_STATS; */static const int min_canvasWidth = 8;static const int min_canvasHeight = 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 = -1;static int size = SIZE_352x288;/* * 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_rg2 = -1;static int init_model2_sat = -1;static int init_model2_yb = -1;/* 01.01.08 - Added for RCA video in support -LO *//* Settings for camera model 3 */static int init_model3_input = 0;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=separate 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(size, "i");MODULE_PARM_DESC(size, "Image size: 0=128x96 1=160x120 2=176x144 3=320x240 4=352x240 5=352x288 6=640x480 (default=5)");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, "Color 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_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)");/* 01.01.08 - Added for RCA video in support -LO */MODULE_PARM(init_model3_input, "i");MODULE_PARM_DESC(init_model3_input, "Model3 input: 0=CCD 1=RCA");MODULE_AUTHOR ("Dmitri");MODULE_DESCRIPTION ("IBM/Xirlink C-it USB Camera Driver for Linux (c) 2000");MODULE_LICENSE("GPL");/* 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_hue = 0x0024; /* 0..$7F, $70 is about right */static const unsigned short mod2_sensitivity = 0x0028; /* 0 (min) .. $1F (max) */struct struct_initData { unsigned char req; unsigned short value; unsigned short index;};/* * ibmcam_size_to_videosize() * * This procedure converts module option 'size' into the actual * videosize_t that defines the image size in pixels. We need * simplified 'size' because user wants a simple enumerated list * of choices, not an infinite set of possibilities. */static videosize_t ibmcam_size_to_videosize(int size){ videosize_t vs = VIDEOSIZE_352x288; RESTRICT_TO_RANGE(size, 0, (SIZE_LastItem-1)); switch (size) { case SIZE_128x96: vs = VIDEOSIZE_128x96; break; case SIZE_160x120: vs = VIDEOSIZE_160x120; break; case SIZE_176x144: vs = VIDEOSIZE_176x144; break; case SIZE_320x240: vs = VIDEOSIZE_320x240; break; case SIZE_352x240: vs = VIDEOSIZE_352x240; break; case SIZE_352x288: vs = VIDEOSIZE_352x288; break; case SIZE_640x480: vs = VIDEOSIZE_640x480; break; default: err("size=%d. is not valid", size); break; } return vs;}/* * ibmcam_find_header() * * Locate one of supported header markers in the queue. * Once found, remove all preceding bytes AND the marker (4 bytes) * from the data pump queue. Whatever follows must be video lines. * * History: * 1/21/00 Created. */static ParseState_t ibmcam_find_header(uvd_t *uvd) /* FIXME: Add frame here */{ usbvideo_frame_t *frame; ibmcam_t *icam; if ((uvd->curframe) < 0 || (uvd->curframe >= USBVIDEO_NUMFRAMES)) { err("ibmcam_find_header: Illegal frame %d.", uvd->curframe); return scan_EndParse; } icam = IBMCAM_T(uvd); assert(icam != NULL); frame = &uvd->frame[uvd->curframe]; icam->has_hdr = 0; switch (icam->camera_model) { case IBMCAM_MODEL_1: { const int marker_len = 4; while (RingQueue_GetLength(&uvd->dp) >= marker_len) { if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) && (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xFF) && (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x00)) {#if 0 /* This code helps to detect new frame markers */ info("Header sig: 00 FF 00 %02X", RING_QUEUE_PEEK(&uvd->dp, 3));#endif frame->header = RING_QUEUE_PEEK(&uvd->dp, 3); if ((frame->header == HDRSIG_MODEL1_128x96) || (frame->header == HDRSIG_MODEL1_176x144) || (frame->header == HDRSIG_MODEL1_352x288)) {#if 0 info("Header found.");#endif RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len); icam->has_hdr = 1; break; } } /* If we are still here then this doesn't look like a header */ RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1); } break; } case IBMCAM_MODEL_2:case IBMCAM_MODEL_4: { int marker_len = 0; switch (uvd->videosize) { case VIDEOSIZE_176x144: marker_len = 10; break; default: marker_len = 2; break; } while (RingQueue_GetLength(&uvd->dp) >= marker_len) { if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) && (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xFF)) {#if 0 info("Header found.");#endif RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len); icam->has_hdr = 1; frame->header = HDRSIG_MODEL1_176x144; break; } /* If we are still here then this doesn't look like a header */ RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1); } break; } case IBMCAM_MODEL_3: { /* * Headers: (one precedes every frame). nc=no compression, * bq=best quality bf=best frame rate. * * 176x144: 00 FF 02 { 0A=nc CA=bq EA=bf } * 320x240: 00 FF 02 { 08=nc 28=bq 68=bf } * 640x480: 00 FF 03 { 08=nc 28=bq 68=bf } * * Bytes '00 FF' seem to indicate header. Other two bytes * encode the frame type. This is a set of bit fields that * encode image size, compression type etc. These fields * do NOT contain frame number because all frames carry * the same header. */ const int marker_len = 4; while (RingQueue_GetLength(&uvd->dp) >= marker_len) { if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) && (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xFF) && (RING_QUEUE_PEEK(&uvd->dp, 2) != 0xFF)) { /* * Combine 2 bytes of frame type into one * easy to use value */ unsigned long byte3, byte4; byte3 = RING_QUEUE_PEEK(&uvd->dp, 2); byte4 = RING_QUEUE_PEEK(&uvd->dp, 3); frame->header = (byte3 << 8) | byte4;#if 0 info("Header found.");#endif RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len); icam->has_hdr = 1; break; } /* If we are still here then this doesn't look like a header */ RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1); } break; } default: break; } if (!icam->has_hdr) { if (uvd->debug > 2) info("Skipping frame, no header"); return scan_EndParse; } /* Header found */ icam->has_hdr = 1; uvd->stats.header_count++; frame->scanstate = ScanState_Lines; frame->curline = 0; if (flags & FLAGS_FORCE_TESTPATTERN) { usbvideo_TestPattern(uvd, 1, 1); return scan_NextFrame; } return scan_Continue;}/* * ibmcam_parse_lines() * * Parse one line (interlaced) from the buffer, put * decoded RGB value into the current frame buffer * and add the written number of bytes (RGB) to * the *pcopylen. * * History: * 21-Jan-2000 Created. * 12-Oct-2000 Reworked to reflect interlaced nature of the data. */static ParseState_t ibmcam_parse_lines( uvd_t *uvd, usbvideo_frame_t *frame, long *pcopylen){ unsigned char *f; ibmcam_t *icam; unsigned int len, scanLength, scanHeight, order_uv, order_yc; int v4l_linesize; /* V4L line offset */ const int hue_corr = (uvd->vpic.hue - 0x8000) >> 10; /* -32..+31 */ const int hue2_corr = (hue_correction - 128) / 4; /* -32..+31 */ const int ccm = 128; /* Color correction median - see below */ int y, u, v, i, frame_done=0, color_corr; static unsigned char lineBuffer[640*3]; unsigned const char *chromaLine, *lumaLine; assert(uvd != NULL); assert(frame != NULL); icam = IBMCAM_T(uvd); assert(icam != NULL); color_corr = (uvd->vpic.colour - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/ RESTRICT_TO_RANGE(color_corr, -ccm, ccm+1); v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL; if (IBMCAM_T(uvd)->camera_model == IBMCAM_MODEL_4) { /* Model 4 frame markers do not carry image size identification */ switch (uvd->videosize) { case VIDEOSIZE_128x96: case VIDEOSIZE_160x120: case VIDEOSIZE_176x144: scanLength = VIDEOSIZE_X(uvd->videosize); scanHeight = VIDEOSIZE_Y(uvd->videosize);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -