?? w9968cf.c
字號:
* Helper functions * ****************************************************************************//*-------------------------------------------------------------------------- Turn on the LED on some webcams. A beep should be heard too. Return 0 on success, a negative number otherwise. --------------------------------------------------------------------------*/static int w9968cf_turn_on_led(struct w9968cf_device* cam){ int err = 0; err += w9968cf_write_reg(cam, 0xff00, 0x00); /* power-down */ err += w9968cf_write_reg(cam, 0xbf17, 0x00); /* reset everything */ err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* normal operation */ err += w9968cf_write_reg(cam, 0x0010, 0x01); /* serial bus, SDS high */ err += w9968cf_write_reg(cam, 0x0000, 0x01); /* serial bus, SDS low */ err += w9968cf_write_reg(cam, 0x0010, 0x01); /* ..high 'beep-beep' */ if (err) DBG(2, "Couldn't turn on the LED") DBG(5, "LED turned on") return err;}/*-------------------------------------------------------------------------- Write some registers for the device initialization. This function is called once on open(). Return 0 on success, a negative number otherwise. --------------------------------------------------------------------------*/static int w9968cf_init_chip(struct w9968cf_device* cam){ unsigned long hw_bufsize = cam->maxwidth*cam->maxheight*2, y0 = 0x0000, u0 = y0 + hw_bufsize/2, v0 = u0 + hw_bufsize/4, y1 = v0 + hw_bufsize/4, u1 = y1 + hw_bufsize/2, v1 = u1 + hw_bufsize/4; int err = 0; err += w9968cf_write_reg(cam, 0xff00, 0x00); /* power off */ err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* power on */ err += w9968cf_write_reg(cam, 0x405d, 0x03); /* DRAM timings */ err += w9968cf_write_reg(cam, 0x0030, 0x04); /* SDRAM timings */ err += w9968cf_write_reg(cam, y0 & 0xffff, 0x20); /* Y buf.0, low */ err += w9968cf_write_reg(cam, y0 >> 16, 0x21); /* Y buf.0, high */ err += w9968cf_write_reg(cam, u0 & 0xffff, 0x24); /* U buf.0, low */ err += w9968cf_write_reg(cam, u0 >> 16, 0x25); /* U buf.0, high */ err += w9968cf_write_reg(cam, v0 & 0xffff, 0x28); /* V buf.0, low */ err += w9968cf_write_reg(cam, v0 >> 16, 0x29); /* V buf.0, high */ err += w9968cf_write_reg(cam, y1 & 0xffff, 0x22); /* Y buf.1, low */ err += w9968cf_write_reg(cam, y1 >> 16, 0x23); /* Y buf.1, high */ err += w9968cf_write_reg(cam, u1 & 0xffff, 0x26); /* U buf.1, low */ err += w9968cf_write_reg(cam, u1 >> 16, 0x27); /* U buf.1, high */ err += w9968cf_write_reg(cam, v1 & 0xffff, 0x2a); /* V buf.1, low */ err += w9968cf_write_reg(cam, v1 >> 16, 0x2b); /* V buf.1, high */ err += w9968cf_write_reg(cam, y1 & 0xffff, 0x32); /* JPEG buf 0 low */ err += w9968cf_write_reg(cam, y1 >> 16, 0x33); /* JPEG buf 0 high */ err += w9968cf_write_reg(cam, y1 & 0xffff, 0x34); /* JPEG buf 1 low */ err += w9968cf_write_reg(cam, y1 >> 16, 0x35); /* JPEG bug 1 high */ err += w9968cf_write_reg(cam, 0x0000, 0x36);/* JPEG restart interval */ err += w9968cf_write_reg(cam, 0x0804, 0x37);/*JPEG VLE FIFO threshold*/ err += w9968cf_write_reg(cam, 0x0000, 0x38);/* disable hw up-scaling */ err += w9968cf_write_reg(cam, 0x0000, 0x3f); /* JPEG/MCTL test data */ err += w9968cf_set_picture(cam, cam->picture); /* this before */ err += w9968cf_set_window(cam, cam->window); if (err) DBG(1, "Chip initialization failed") else DBG(5, "Chip successfully initialized") return err;}/*-------------------------------------------------------------------------- Return non-zero if the palette is supported, 0 otherwise. --------------------------------------------------------------------------*/static inline u16 w9968cf_valid_palette(u16 palette){ u8 i = 0; while (w9968cf_formatlist[i].palette != 0) { if (palette == w9968cf_formatlist[i].palette) return palette; i++; } return 0;}/*-------------------------------------------------------------------------- Return the depth corresponding to the given palette. Palette _must_ be supported ! --------------------------------------------------------------------------*/static inline u16 w9968cf_valid_depth(u16 palette){ u8 i=0; while (w9968cf_formatlist[i].palette != palette) i++; return w9968cf_formatlist[i].depth;}/*-------------------------------------------------------------------------- Return non-zero if the format requires decompression, 0 otherwise. --------------------------------------------------------------------------*/static inline u8 w9968cf_need_decompression(u16 palette){ u8 i = 0; while (w9968cf_formatlist[i].palette != 0) { if (palette == w9968cf_formatlist[i].palette) return w9968cf_formatlist[i].compression; i++; } return 0;}/*-------------------------------------------------------------------------- Change the picture settings of the camera. Return 0 on success, a negative number otherwise. --------------------------------------------------------------------------*/static intw9968cf_set_picture(struct w9968cf_device* cam, struct video_picture pict){ u16 fmt, hw_depth, hw_palette, reg_v = 0x0000; int err = 0; /* Make sure we are using a valid depth */ pict.depth = w9968cf_valid_depth(pict.palette); fmt = pict.palette; hw_depth = pict.depth; /* depth used by the winbond chip */ hw_palette = pict.palette; /* palette used by the winbond chip */ /* VS & HS polarities */ reg_v = (cam->vs_polarity << 12) | (cam->hs_polarity << 11); switch (fmt) { case VIDEO_PALETTE_UYVY: reg_v |= 0x0000; cam->vpp_flag = VPP_NONE; break; case VIDEO_PALETTE_YUV422P: reg_v |= 0x0002; cam->vpp_flag = VPP_DECOMPRESSION; break; case VIDEO_PALETTE_YUV420: case VIDEO_PALETTE_YUV420P: reg_v |= 0x0003; cam->vpp_flag = VPP_DECOMPRESSION; break; case VIDEO_PALETTE_YUYV: case VIDEO_PALETTE_YUV422: reg_v |= 0x0000; cam->vpp_flag = VPP_SWAP_YUV_BYTES; hw_palette = VIDEO_PALETTE_UYVY; break; /* Original video is used instead of RGBX palettes. Software conversion later. */ case VIDEO_PALETTE_GREY: case VIDEO_PALETTE_RGB555: case VIDEO_PALETTE_RGB565: case VIDEO_PALETTE_RGB24: case VIDEO_PALETTE_RGB32: reg_v |= 0x0000; /* UYVY 16 bit is used */ hw_depth = 16; hw_palette = VIDEO_PALETTE_UYVY; cam->vpp_flag = VPP_UYVY_TO_RGBX; break; } /* NOTE: due to memory issues, it is better to disable the hardware double buffering during compression */ if (cam->double_buffer && !(cam->vpp_flag & VPP_DECOMPRESSION)) reg_v |= 0x0080; if (cam->clamping) reg_v |= 0x0020; if (cam->filter_type == 1) reg_v |= 0x0008; else if (cam->filter_type == 2) reg_v |= 0x000c; if ((err = w9968cf_write_reg(cam, reg_v, 0x16))) goto error; if ((err = w9968cf_sensor_update_picture(cam, pict))) goto error; /* If all went well, update the device data structure */ memcpy(&cam->picture, &pict, sizeof(pict)); cam->hw_depth = hw_depth; cam->hw_palette = hw_palette; /* Settings changed, so we clear the frame buffers */ memset(cam->frame[0].buffer, 0, cam->nbuffers*cam->frame[0].size); DBG(4, "Palette is %s, depth is %u bpp", symbolic(v4l1_plist, pict.palette), pict.depth) return 0;error: DBG(1, "Failed to change picture settings") return err;}/*-------------------------------------------------------------------------- Change the capture area size of the camera. This function _must_ be called _after_ w9968cf_set_picture(). Return 0 on success, a negative number otherwise. --------------------------------------------------------------------------*/static intw9968cf_set_window(struct w9968cf_device* cam, struct video_window win){ u16 x, y, w, h, scx, scy, cw, ch, ax, ay; unsigned long fw, fh; struct ovcamchip_window s_win; int err = 0; /* Work around to avoid FP arithmetics */ #define __SC(x) ((x) << 10) #define __UNSC(x) ((x) >> 10) /* Make sure we are using a supported resolution */ if ((err = w9968cf_adjust_window_size(cam, (u16*)&win.width, (u16*)&win.height))) goto error; /* Scaling factors */ fw = __SC(win.width) / cam->maxwidth; fh = __SC(win.height) / cam->maxheight; /* Set up the width and height values used by the chip */ if ((win.width > cam->maxwidth) || (win.height > cam->maxheight)) { cam->vpp_flag |= VPP_UPSCALE; /* Calculate largest w,h mantaining the same w/h ratio */ w = (fw >= fh) ? cam->maxwidth : __SC(win.width)/fh; h = (fw >= fh) ? __SC(win.height)/fw : cam->maxheight; if (w < cam->minwidth) /* just in case */ w = cam->minwidth; if (h < cam->minheight) /* just in case */ h = cam->minheight; } else { cam->vpp_flag &= ~VPP_UPSCALE; w = win.width; h = win.height; } /* x,y offsets of the cropped area */ scx = cam->start_cropx; scy = cam->start_cropy; /* Calculate cropped area manteining the right w/h ratio */ if (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE)) { cw = (fw >= fh) ? cam->maxwidth : __SC(win.width)/fh; ch = (fw >= fh) ? __SC(win.height)/fw : cam->maxheight; } else { cw = w; ch = h; } /* Setup the window of the sensor */ s_win.format = VIDEO_PALETTE_UYVY; s_win.width = cam->maxwidth; s_win.height = cam->maxheight; s_win.quarter = 0; /* full progressive video */ /* Center it */ s_win.x = (s_win.width - cw) / 2; s_win.y = (s_win.height - ch) / 2; /* Clock divisor */ if (cam->clockdiv >= 0) s_win.clockdiv = cam->clockdiv; /* manual override */ else switch (cam->sensor) { case CC_OV6620: s_win.clockdiv = 0; break; case CC_OV6630: s_win.clockdiv = 0; break; case CC_OV76BE: case CC_OV7610: case CC_OV7620: s_win.clockdiv = 0; break; default: s_win.clockdiv = W9968CF_DEF_CLOCKDIVISOR; } /* We have to scale win.x and win.y offsets */ if ( (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE)) || (cam->vpp_flag & VPP_UPSCALE) ) { ax = __SC(win.x)/fw; ay = __SC(win.y)/fh; } else { ax = win.x; ay = win.y; } if ((ax + cw) > cam->maxwidth) ax = cam->maxwidth - cw; if ((ay + ch) > cam->maxheight) ay = cam->maxheight - ch; /* Adjust win.x, win.y */ if ( (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE)) || (cam->vpp_flag & VPP_UPSCALE) ) { win.x = __UNSC(ax*fw); win.y = __UNSC(ay*fh); } else { win.x = ax; win.y = ay; } /* Offsets used by the chip */ x = ax + s_win.x; y = ay + s_win.y; /* Go ! */ if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_S_MODE, &s_win))) goto error; err += w9968cf_write_reg(cam, scx + x, 0x10); err += w9968cf_write_reg(cam, scy + y, 0x11); err += w9968cf_write_reg(cam, scx + x + cw, 0x12); err += w9968cf_write_reg(cam, scy + y + ch, 0x13); err += w9968cf_write_reg(cam, w, 0x14); err += w9968cf_write_reg(cam, h, 0x15); /* JPEG width & height */ err += w9968cf_write_reg(cam, w, 0x30); err += w9968cf_write_reg(cam, h, 0x31); /* Y & UV frame buffer strides (in WORD) */ if (cam->vpp_flag & VPP_DECOMPRESSION) { err += w9968cf_write_reg(cam, w/2, 0x2c); err += w9968cf_write_reg(cam, w/4, 0x2d); } else err += w9968cf_write_reg(cam, w, 0x2c); if (err) goto error; /* If all went well, update the device data structure */ memcpy(&cam->window, &win, sizeof(win)); cam->hw_width = w; cam->hw_height = h; /* Settings changed, so we clear the frame buffers */ memset(cam->frame[0].buffer, 0, cam->nbuffers*cam->frame[0].size); DBG(4, "The capture area is %dx%d, Offset (x,y)=(%u,%u)", win.width, win.height, win.x, win.y) PDBGG("x=%u ,y=%u, w=%u, h=%u, ax=%u, ay=%u, s_win.x=%u, s_win.y=%u, " "cw=%u, ch=%u, win.x=%u, win.y=%u, win.width=%u, win.height=%u", x, y, w, h, ax, ay, s_win.x, s_win.y, cw, ch, win.x, win.y, win.width, win.height) return 0;error: DBG(1, "Failed to change the capture area size") return err;}/*-------------------------------------------------------------------------- Adjust the asked values for window width and height. Return 0 on success, -1 otherwise. --------------------------------------------------------------------------*/static intw9968cf_adjust_window_size(struct w9968cf_device* cam, u16* width, u16* height){ u16 maxw, maxh; if ((*width < cam->minwidth) ||
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -