patch for Ultraport Camera II and 2.6.22.2
Frank Thieme <[email protected]>
| Newsgroups | gmane.linux.usb.devel |
|---|---|
| Message-ID | <[email protected]> |
Hi, after trying the patch for 2.6.18 I changed it a bit to make it compile with 2.6.22.2. because kernel is still compiling I didn't test it yet. But if it has worked with 2.6.18 it should now, as I didn't any functional changes. Bye...Frank ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ _______________________________________________ [email protected] To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel
ultracam.patch-2.6.22.2
(text/x-objcsrc, 78.9 KB)
--- linux-2.6.22.2/drivers/media/video/usbvideo/ultracam.c 2007-08-09 23:28:15.000000000 +0200 +++ /usr/src/linux-2.6.22.2/drivers/media/video/usbvideo/ultracam.c 2007-08-12 19:08:49.562471538 +0200 @@ -1,12 +1,16 @@ /* - * USB NB Camera driver + * USB NB (Ultraport) Camera driver * - * HISTORY: - * 25-Dec-2002 Dmitri Removed lighting, sharpness parameters, methods. + * Original source by Dmitri + * Updated by Karl Gutwin <[email protected]> + * Updated by Jakob Lichtenberg <[email protected]> + * Kernel version 2.6.10 support by Jeremy Viehland <[email protected]> + * Thanks to axel grossklaus <[email protected]> */ #include <linux/kernel.h> #include <linux/module.h> +#include <linux/moduleparam.h> #include <linux/init.h> #include "usbvideo.h" @@ -23,21 +27,73 @@ int initialized; /* Had we already sent init sequence? */ int camera_model; /* What type of IBM camera we got? */ int has_hdr; + int bytes_in; /* bytes remaining to read before drop */ + int invert; /* shall we invert the picture? */ + int rbar, gbar, bbar; /* mean vals for rgb, used for auto wb */ + int projected_whitebal; + int frames_since_adjust; + int ybar; } ultracam_t; #define ULTRACAM_T(uvd) ((ultracam_t *)((uvd)->user_data)) static struct usbvideo *cams = NULL; +/* + * Intended Debugging Levels + * + * 0 -- End user messages only. + * Detection of camera. + * Errors which cause camera failure. + * + * 1 -- End user debugging only. + * Logging of module parameters. + * Camera probe messages. + * Changes to user-configurable settings. + * Automatic changes (e.g., white balance). + * Errors which the user might be able to correct. + * + * 2 -- Developer messages begin here. + * + * 3 -- Tracing of interface function entry. + * + * 4 -- Cruft. + * + * 5 -- Unused. + * 6 -- Unused. + * 7 -- Unused. + * 8 -- Unused. + * 9 -- Unused. + */ static int debug = 0; +#define TRACE_FUNC_ENTRY() \ +do { if (debug >= 3) dbg("%s", __FUNCTION__); } while (0); -static int flags = 0; /* FLAGS_DISPLAY_HINTS | FLAGS_OVERLAY_STATS; */ +static int ultracam_is_backward(struct uvd* uvd); +static void ultracam_set_white_balance(struct uvd* uvd); -static const int min_canvasWidth = 8; -static const int min_canvasHeight = 4; +static int flags = 0; +/* FLAGS_RETRY_VIDIOCSYNC (1 << 0) /\* 1 *\/ */ +/* FLAGS_MONOCHROME (1 << 1) /\* 2 *\/ */ +/* FLAGS_DISPLAY_HINTS (1 << 2) /\* 4 *\/ */ +/* FLAGS_OVERLAY_STATS (1 << 3) /\* 8 *\/ */ +/* FLAGS_FORCE_TESTPATTERN (1 << 4) /\* 16 *\/ */ +/* FLAGS_SEPARATE_FRAMES (1 << 5) /\* 32 *\/ */ +/* FLAGS_CLEAN_FRAMES (1 << 6) /\* 64 *\/ */ +/* FLAGS_NO_DECODING (1 << 7) /\* 128 *\/ */ + +static int const min_canvasWidth = 8; +static int const min_canvasHeight = 4; + +static int whitebal = -1; /* auto whitebal */ +static int wbmaxdelt = 1; + +#define SHARPNESS_MIN 0 +#define SHARPNESS_MAX 4 +static int sharpness = 3; /* Low noise, good details */ #define FRAMERATE_MIN 0 #define FRAMERATE_MAX 6 -static int framerate = -1; +static int framerate = FRAMERATE_MAX; /* Slow camera. */ /* * Here we define several initialization variables. They may @@ -55,12 +111,52 @@ */ static int init_brightness = 128; static int init_contrast = 192; +// TODO: check, if this variable is still needed: static int init_color = 128; +static int init_sat = 10; static int init_hue = 128; +// TODO: check, if this variable is still needed: static int hue_correction = 128; +static int brite = 0; +module_param(brite, int, 0); +MODULE_PARM_DESC(brite, "y adjust: (0-255) or -1: automatic (default)"); + +static unsigned short hs_0b = 0x002e; +static unsigned short hs_0c = 0x00d6; +static unsigned short hs_0d = 0x00fc; +static unsigned short hs_0e = 0x00f1; +static unsigned short hs_0f = 0x00da; +static unsigned short hs_10 = 0x0036; + +module_param(hs_0b, ushort, 0); +module_param(hs_0c, ushort, 0); +module_param(hs_0d, ushort, 0); +module_param(hs_0e, ushort, 0); +module_param(hs_0f, ushort, 0); +module_param(hs_10, ushort, 0); + +static unsigned short wb_51 = 0xff00; +static unsigned short wb_52 = 0xff00; +static unsigned short wb_53 = 0xff00; +static unsigned short wb_11 = 0xff00; +static unsigned short wb_12 = 0xff00; +static unsigned short wb_13 = 0xff00; + +module_param(wb_51, ushort, 0); +module_param(wb_52, ushort, 0); +module_param(wb_53, ushort, 0); +module_param(wb_11, ushort, 0); +module_param(wb_12, ushort, 0); +module_param(wb_13, ushort, 0); + +static int yuv = 0; +module_param(yuv, int, 0); module_param(debug, int, S_IRUGO | S_IWUSR); +/* MODULE_PARM(debug, "i"); */ + MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)"); +/* MODULE_PARM(flags, "i"); */ module_param(flags, int, 0); MODULE_PARM_DESC(flags, "Bitfield: 0=VIDIOCSYNC, " @@ -70,11 +166,23 @@ "4=test pattern, " "5=separate frames, " "6=clean frames"); +/* MODULE_PARM(whitebal, "i"); */ +module_param(whitebal, int, 0); +MODULE_PARM_DESC(whitebal, + "White balance: 0-48 (0:bluish, 48:reddish) or -1: automatic(default)"); +/* MODULE_PARM(wbmaxdelt, "i"); */ +module_param(wbmaxdelt, int, 0); +MODULE_PARM_DESC(wbmaxdelt, + "White balance maximum delta: 1-48 (1:slow, 48:fast) (default=1)"); +/* MODULE_PARM(sharpness, "i"); */ +module_param(sharpness, int, 0); +MODULE_PARM_DESC(sharpness, "Sharpness: 0=smooth, 4=sharp (default=3)"); +/* MODULE_PARM(framerate, "i"); */ module_param(framerate, int, 0); MODULE_PARM_DESC(framerate, "Framerate setting: 0=slowest, 6=fastest (default=2)"); module_param(init_brightness, int, 0); -MODULE_PARM_DESC(init_brightness, "Brightness preconfiguration: 0-255 (default=128)"); +MODULE_PARM_DESC(init_brightness, "Brightness preconfiguration: 0-255 or -1: automatic(default)"); module_param(init_contrast, int, 0); MODULE_PARM_DESC(init_contrast, "Contrast preconfiguration: 0-255 (default=192)"); module_param(init_color, int, 0); @@ -84,6 +192,726 @@ module_param(hue_correction, int, 0); MODULE_PARM_DESC(hue_correction, "YUV colorspace regulation: 0-255 (default=128)"); +static void +print_user_data( + ultracam_t const* const ultracam) +{ + TRACE_FUNC_ENTRY(); + dbg("ultracam->initialized = %d", ultracam->initialized); + dbg("ultracam->camera_model = 0x%04x", ultracam->camera_model); + dbg("ultracam->has_hdr = %d", ultracam->has_hdr); + dbg("ultracam->bytes_in = %d", ultracam->bytes_in); + dbg("ultracam->invert = %d", ultracam->invert); + dbg("ultracam->rbar = %d", ultracam->rbar); + dbg("ultracam->gbar = %d", ultracam->gbar); + dbg("ultracam->bbar = %d", ultracam->bbar); + dbg("ultracam->projected_whitebal = %d", ultracam->projected_whitebal); + dbg("ultracam->frames_since_adjust = %d", ultracam->frames_since_adjust); + dbg("ultracam->ybar = %d", ultracam->ybar); +} + +/** + * Converts given videosize value to readable string. + * + * @since 07-Aug-2000 Created. + * @since 19-Oct-2000 Reworked for usbvideo module. + */ +static void usbvideo_VideosizeToString(char* buf, int bufLen, videosize_t vs) +{ + char tmp[40]; + int n; + n = 1 + sprintf(tmp, "%ldx%ld", VIDEOSIZE_X(vs), VIDEOSIZE_Y(vs)); + assert(n < sizeof(tmp)); + if ((buf == NULL) || (bufLen < n)) + err("usbvideo_VideosizeToString: buffer is too small."); + else + memmove(buf, tmp, n); +} + +static void +print_flags(char* buf, int bufLen, int flags) +{ + char* c = buf; + int charCount = 0; + char const* flagName; + int i; + int const imax = 7; /* Number of flags. */ + assert(NULL != buf); + assert(bufLen >= 163*2); /* 2 * sum(#chars) of all flag names. */ + buf[bufLen-1] = '\0'; + for (i = 0; i < imax; ++i) + { + int flag = 1 << i; + if (0 == (flag & flags)) + continue; /* Flag not set. */ + switch (flag) + { + case FLAGS_RETRY_VIDIOCSYNC: + flagName = "FLAGS_RETRY_VIDIOCSYNC"; + break; + case FLAGS_MONOCHROME: + flagName = "FLAGS_MONOCHROME"; + break; + case FLAGS_DISPLAY_HINTS: + flagName = "FLAGS_DISPLAY_HINTS"; + break; + case FLAGS_OVERLAY_STATS: + flagName = "FLAGS_OVERLAY_STATS"; + break; + case FLAGS_FORCE_TESTPATTERN: + flagName = "FLAGS_FORCE_TESTPATTERN"; + break; + case FLAGS_SEPARATE_FRAMES: + flagName = "FLAGS_SEPARATE_FRAMES"; + break; + case FLAGS_CLEAN_FRAMES: + flagName = "FLAGS_CLEAN_FRAMES"; + break; + case FLAGS_NO_DECODING: + flagName = "FLAGS_NO_DECODING"; + break; + default: + flagName = "Unknown flag"; + break; + } + charCount += (sprintf(buf + charCount, "|%s", flagName)); + c = buf + charCount; + } + *c = '\0'; + dbg("uvd->flags = %s", buf); +} + +static void +print_uvd(struct uvd const* const uvd) +{ + char buf[512]; + /* struct video_device vdev; */ + /* struct usb_device* dev; */ + /* struct usbvideo* handle; */ + if (NULL != uvd) + print_user_data(uvd->user_data); + else + dbg("uvd->user_data = NULL"); + dbg("uvd->user_size = %d", uvd->user_size); + dbg("uvd->debug = %d", uvd->debug); + dbg("uvd->iface = %d", (int)uvd->iface); + dbg("uvd->video_endp = %d", (int)uvd->video_endp); + dbg("uvd->ifaceAltActive = %d", (int)uvd->ifaceAltActive); + dbg("uvd->ifaceAltInactive = %d", (int)uvd->ifaceAltInactive); + print_flags(buf, sizeof(buf), uvd->flags); + dbg("uvd->paletteBits = %08lx", uvd->paletteBits); + dbg("uvd->defaultPalette = %08hx", uvd->defaultPalette); + /* struct semaphore lock; */ + dbg("uvd->user = %d", uvd->user); + usbvideo_VideosizeToString(buf, sizeof(buf), uvd->videosize); + dbg("uvd->videosize = %s", buf); + usbvideo_VideosizeToString(buf, sizeof(buf), uvd->canvas); + dbg("uvd->canvas = %s", buf); + dbg("uvd->max_frame_size = %d", uvd->max_frame_size); + dbg("uvd->uvd_used = %d", uvd->uvd_used); + dbg("uvd->streaming = %d", uvd->streaming); + dbg("uvd->grabbing = %d", uvd->grabbing); + dbg("uvd->settingsAdjusted = %d", uvd->settingsAdjusted); + dbg("uvd->last_error = %d", uvd->last_error); + /* char* fbuf; */ + dbg("uvd->fbuf_size = %d", uvd->fbuf_size); + dbg("uvd->curframe = %d", uvd->curframe); + dbg("uvd->iso_packet_len = %d", uvd->iso_packet_len); + /* struct RingQueue dp; */ + /* struct usbvideo_frame frame[USBVIDEO_NUMFRAMES]; */ + /* struct usbvideo_sbuf sbuf[USBVIDEO_NUMSBUF]; */ + dbg("uvd->remove_pending = %d", uvd->remove_pending); + /* struct video_picture vpic, vpic_old; */ + /* struct video_capability vcap; */ + /* struct video_channel vchan; */ + /* struct usbvideo_statistics stats; */ + dbg("uvd->videoName = %s", uvd->videoName ? uvd->videoName : ""); +} + +/** + * Overlays a single character on the frame. Unsupported characters + * will result in a space being printed. + * + * @todo Support other paletteBits. Right now, we're only using + * RGB24_PUTPIXEL. + * + * @todo Make overlay more legible by deciding the color of the font + * based on the average brightness of the 5x3 block it overlays. Then + * again, this would slow things down. + * + * @param uvd The device. + * @param frame + * @param x Where to place the upper left corner of the character. + * @param y Where to place the upper left corner of the character. + * @param ch Character to print (if not [0-9A-Z], then space). + * Lowercase letters will be converted to uppercase. + * @since 01-Feb-2000 Created. + * @since 31-May-2005 Renovated. + */ +void usbvideo_OverlayChar(struct uvd* uvd, struct usbvideo_frame* frame, int x, int y, int ch) +{ + /* White letters, 3x5. */ + static unsigned char const R = 0xff; + static unsigned char const G = 0xff; + static unsigned char const B = 0xff; + static int const overlay_char_sz_x = 3; + static int const overlay_char_sz_y = 5; + static unsigned short const digits[36] = { + 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 */ + 0xf2de, /* g */ + 0xb7da, /* h */ + 0xe92e, /* i */ + 0xe92c, /* j */ + 0xb75a, /* k */ + 0x924e, /* l */ + 0xbeda, /* m */ + 0xd6da, /* n */ + 0x56d4, /* o */ + 0xf7c8, /* p */ + 0xf6fe, /* q */ + 0xf75a, /* r */ + 0x739c, /* s */ + 0xe924, /* t */ + 0xb6de, /* u */ + 0xb6d4, /* v */ + 0xb6fa, /* w */ + 0xb55a, /* x */ + 0xb524, /* y */ + 0xe54e /* z */ + }; + unsigned short digit; + int ix, iy; + + if ((uvd == NULL) || (frame == NULL)) + return; + + if (! (uvd->paletteBits & (1L << VIDEO_PALETTE_RGB24))) + return; + + if (ch >= '0' && ch <= '9') + ch -= '0'; + else if (ch >= 'A' && ch <= 'Z') + ch = 10 + (ch - 'A'); + else if (ch >= 'a' && ch <= 'z') + ch = 10 + (ch - 'a'); + else + return; /* Effectively, prints a space char. */ + digit = digits[ch]; + + { + int const xMax = VIDEOSIZE_X(frame->canvas); + int const yMax = VIDEOSIZE_Y(frame->canvas); + for (iy = 0; iy < overlay_char_sz_y; ++iy) + for (ix = 0; ix < overlay_char_sz_x; ++ix, digit <<= 1) + if (digit & 0x8000) + RGB24_PUTPIXEL(frame, + (x + ix) % xMax, + (y + iy) % yMax, + R, G, B); + } +} + +/** + * Overlays a string on the frame. Unsupported characters + * will result in a space being printed. + * + * @param uvd The device. + * @param frame + * @param x Location of upper left corner of first character. + * @param y Location of upper left corner of first character. + * @param format Gets passed to snprintf. + * @param arg Gets passed to snprintf. + * @see usbvideo_OverlayChar + * @since 01-Feb-2000 Created. + * @since 31-May-2005 Renovated. + */ +static void +usbvideo_OverlayString(struct uvd* uvd, struct usbvideo_frame* frame, int x, int y, char const* format, unsigned long arg) +{ + static char buf[16]; + static int const bufLen = sizeof(buf); + char const* str = buf; + /* Any mistake in the size of the string will show up on the + * display, so there's no need to check too carefully. */ + int const nChars = snprintf(buf, bufLen, format, arg); + if (nChars >= bufLen) /* Output was truncated. */ + buf[bufLen - 1] = '\0'; /* Don't overrun buffer below. */ + while (*str) + { + usbvideo_OverlayChar(uvd, frame, x, y, *str); + str++; + x += 4; /* 3 pixels character + 1 space */ + } +} + +/** + * Overlays important debugging information. + * + * @param uvd The device. + * @param frame + * @since 01-Feb-2000 Created. + * @since 31-May-2005 Renovated. + */ +static void +usbvideo_OverlayStats(struct uvd* uvd, struct usbvideo_frame* frame) +{ + ultracam_t* ucam = ULTRACAM_T(uvd); + int const y_diff = 8; /* Vertical separation of lines of overlayed text. */ + int x = 10, y = 10; + long i, j, barLength; + int const qi_x1 = 60; + int const qi_y1 = 10; + int const qi_x2 = VIDEOSIZE_X(frame->request) - 10; + int const qi_h = 10; + int const xReqLess30 = (VIDEOSIZE_X(frame->request) - 30); + + /* + * Call the user callback, see if we may proceed after that + */ + if (VALID_CALLBACK(uvd, overlayHook)) + if (GET_CALLBACK(uvd, overlayHook) (uvd, frame) < 0) + return; + /** + * Draws a (mostly) hollow rectangle with qi_xxx coordinates. + * Left edge symbolizes the queue index 0; right edge symbolizes + * the full capacity of the queue. + */ + barLength = qi_x2 - qi_x1 - 2; + if ((barLength > 10) && (uvd->paletteBits & (1L << VIDEO_PALETTE_RGB24))) + { + /* TODO */ + long u_lo, u_hi, q_used; + long m_ri, m_wi, m_lo, m_hi; + + /* + * Determine fill zones (used areas of the queue): + * 0 xxxxxxx u_lo ...... uvd->dp.ri xxxxxxxx u_hi ..... uvd->dp.length + * + * if u_lo < 0 then there is no first filler. + */ + + q_used = RingQueue_GetLength(&uvd->dp); + if ((uvd->dp.ri + q_used) >= uvd->dp.length) + { + u_hi = uvd->dp.length; + u_lo = (q_used + uvd->dp.ri) & (uvd->dp.length - 1); + } + else + { + u_hi = (q_used + uvd->dp.ri); + u_lo = -1; + } + + /* + * Convert byte indices into screen units + */ + m_ri = qi_x1 + ((barLength * uvd->dp.ri) / uvd->dp.length); + m_wi = qi_x1 + ((barLength * uvd->dp.wi) / uvd->dp.length); + m_lo = (u_lo > 0) ? (qi_x1 + ((barLength * u_lo) / uvd->dp.length)) : -1; + m_hi = qi_x1 + ((barLength * u_hi) / uvd->dp.length); + + for (j = qi_y1; j < (qi_y1 + qi_h); j++) + { + for (i = qi_x1; i < qi_x2; i++) + { + /* + * Draw border lines + */ + if ((j == qi_y1) || (j == (qi_y1 + qi_h - 1)) || + (i == qi_x1) || (i == (qi_x2 - 1))) + { + RGB24_PUTPIXEL(frame, i, j, 0xFF, 0xFF, 0xFF); + continue; + } + /* + * For all other points the Y coordinate does not matter + */ + if ((i >= m_ri) && (i <= (m_ri + 3))) + { + RGB24_PUTPIXEL(frame, i, j, 0x00, 0xFF, 0x00); + } + else if ((i >= m_wi) && (i <= (m_wi + 3))) + { + RGB24_PUTPIXEL(frame, i, j, 0xFF, 0x00, 0x00); + } + else if ((i < m_lo) || ((i > m_ri) && (i < m_hi))) + RGB24_PUTPIXEL(frame, i, j, 0x00, 0x00, 0xFF); + } + } + } + + y -= y_diff; /* Back up for the sake of being able to write y += y_diff inline. */ + /* User has no idea what the rectangle is, so label it `Queue:' */ + usbvideo_OverlayString(uvd, frame, x, y += y_diff, "Queue:", uvd->stats.frame_num); + usbvideo_OverlayString(uvd, frame, x, y += y_diff, "f# %8lx", uvd->stats.frame_num); + usbvideo_OverlayString(uvd, frame, x, y += y_diff, "u# %8lx", uvd->stats.urb_count); + usbvideo_OverlayString(uvd, frame, x, y += y_diff, "ul %8lx", uvd->stats.urb_length); + usbvideo_OverlayString(uvd, frame, x, y += y_diff, "d# %8lx", uvd->stats.data_count); + usbvideo_OverlayString(uvd, frame, x, y += y_diff, "h# %8lx", uvd->stats.header_count); + usbvideo_OverlayString(uvd, frame, x, y += y_diff, "sk %8lx", uvd->stats.iso_skip_count); + usbvideo_OverlayString(uvd, frame, x, y += y_diff, "er %8lx", uvd->stats.iso_err_count); + usbvideo_OverlayString(uvd, frame, x, y += y_diff, "wh %8d", uvd->vpic.whiteness >> 8); + y += y_diff; /* Skip a line. */ + usbvideo_OverlayString(uvd, frame, x, y += y_diff, "br %8x", uvd->vpic.brightness >> 8); + usbvideo_OverlayString(uvd, frame, x, y += y_diff, "hu %8x", uvd->vpic.hue); + usbvideo_OverlayString(uvd, frame, x, y += y_diff, "cn %8x", uvd->vpic.contrast >> 12); + usbvideo_OverlayString(uvd, frame, x, y += y_diff, "co %8x", uvd->vpic.colour); + /* On the right hand side, overlay the average color values. */ + usbvideo_OverlayString(uvd, frame, xReqLess30, 100, "wb %3d", ucam->projected_whitebal); + usbvideo_OverlayString(uvd, frame, xReqLess30, 116, "r_ %3d", ucam->rbar); + usbvideo_OverlayString(uvd, frame, xReqLess30, 124, "g_ %3d", ucam->gbar); + usbvideo_OverlayString(uvd, frame, xReqLess30, 132, "b_ %3d", ucam->bbar); + usbvideo_OverlayString(uvd, frame, xReqLess30, 148, "y_ %3d", ucam->ybar); +} + +/** + * Does various things to the image once it's been read in, such as + * overlay debugging information, and adjust white balance. + * @param uvd The device. + * @param frame + * @since 31-May-2005 Renovated. + */ +static void +ultracam_postProcess(struct uvd* uvd, struct usbvideo_frame* frame) +{ + /* This is just _too_ verbose. */ + /* TRACE_FUNC_ENTRY(); */ + + assert(uvd); + assert(frame); + { + + ultracam_t* const ucam = ULTRACAM_T(uvd); + { + /* Application wants this size? */ + int const xRequest = VIDEOSIZE_X(frame->request); + int const yRequest = VIDEOSIZE_Y(frame->request); + int const xy = xRequest * yRequest; + if (!xRequest || !yRequest) + return; + ucam->rbar /= xy; + ucam->gbar /= xy; + ucam->bbar /= xy; + ucam->ybar /= xy; + } + + ++ucam->frames_since_adjust; + if (ucam->frames_since_adjust > 10) + { /* module param! */ + ucam->frames_since_adjust = 0; + if (whitebal < 0) + { + /** + * Auto white balance: + * + * I noticed that on one end of the white balance scale, + * everything looks very blue (low, 0 end). On the other + * end, everything looks very red (high, 48 + * end). Therefore, this simple algorithm takes the + * difference between the average red and blue values, + * divides that by two, and changes the white balance by + * that much. + * + * delt is the estimated distance between where we are and + * where we need to be, white-balancy speaking. Since + * always jumping by size delt can cause radical color + * shifts (and because I'm a patient guy) we restrict the + * upper range of delt to wbmaxdelt, a module parameter. + * For quicker responses, increase the value of wbmaxdelt. + * + * -Karl + * + * PS. I know next to nothing about color or imaging... if + * someone out there knows a better solution than this, + * let me know! Thanks... + */ + int delt = ((ucam->bbar - ucam->rbar) >> 1); + + if (delt > wbmaxdelt) + delt = wbmaxdelt; + else if ((delt < 0) && (-delt > wbmaxdelt)) + delt = -wbmaxdelt; + + ucam->projected_whitebal += delt; + RESTRICT_TO_RANGE(ucam->projected_whitebal, 0, 48); + + if (uvd->debug >= 4) + info("Autoadjusting whitebal to %d", ucam->projected_whitebal); + ultracam_set_white_balance(uvd); + } + } + /* Optionally display statistics on the screen */ + if (uvd->flags & FLAGS_OVERLAY_STATS) + usbvideo_OverlayStats(uvd, frame); + } +} + +/* + * ultracam_find_header() + * + * Locate one of supported header markers in the queue. + * Once found, remove all preceding bytes AND the marker (8 bytes) + * from the data pump queue. Whatever follows must be video lines. + * + * History: + * 5/16/01 Created. + */ +static enum ParseState ultracam_find_header(struct uvd* uvd, struct usbvideo_frame* frame) +{ + ultracam_t* ucam; + + if ((uvd->curframe) < 0 || (uvd->curframe >= USBVIDEO_NUMFRAMES)) + { + err("ibmcam_find_header: Illegal frame %d.", uvd->curframe); + return scan_EndParse; + } + + ucam = ULTRACAM_T(uvd); + assert(ucam != NULL); + ucam->has_hdr = 0; + /* and start looking for header */ + + while (RingQueue_GetLength(&uvd->dp) >= 8) + { + if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) && + (RING_QUEUE_PEEK(&uvd->dp, 1) == 0x01) && + (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x19) && + (RING_QUEUE_PEEK(&uvd->dp, 3) == 0x00) && + (RING_QUEUE_PEEK(&uvd->dp, 5) == 0x00) && + (RING_QUEUE_PEEK(&uvd->dp, 6) == 0x00) && + (RING_QUEUE_PEEK(&uvd->dp, 7) == 0x40)) + { +#if 0 /* This code helps to detect new frame markers */ + info("Header sig: 00 01 19 00 %02X", RING_QUEUE_PEEK(&uvd->dp, 4)); +#endif + frame->header = RING_QUEUE_PEEK(&uvd->dp, 7); + if ((frame->header == 0x40)) + { +#if 0 + info("Header found."); +#endif + RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 8); + ucam->bytes_in = 7; + ucam->has_hdr = 1; + ucam->invert = ultracam_is_backward(uvd); + ucam->rbar = ucam->gbar = ucam->bbar = 0; + break; + } + } + /* If we are still here then this doesn't look like a header */ + RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1); + } + + if (!ucam->has_hdr) + { + if (uvd->debug >= 4) + info("Skipping frame, no header"); + return scan_EndParse; + } + + /* Header found */ + ucam->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; +} + +/** + * For some unknown reason, the Ultraport camera sticks a fluke byte + * into the bytestream every 640 bytes. This produces dotted lines on + * the picture, and when left unadjusted, skewed frames. This routine + * simply keeps track of how much we've dequeued so far, and drops the + * 640th byte of the stream. -Karl + * + * @todo Remove hard-coding of 640, and replace with the size of the + * image, to see if that's what the interval truly is. + */ +static int ultracam_Dequeue(struct uvd* uvd, unsigned char* buf, int req) +{ + static int const nth = 640; + int left; + ultracam_t* const ucam = ULTRACAM_T(uvd); + left = ((nth - 1) - ucam->bytes_in); + if (req > left) + { + RingQueue_Dequeue(&uvd->dp, buf, left); + RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1); + ucam->bytes_in = 0; + /* mmmm... recursion... <drool> */ + ultracam_Dequeue(uvd, (buf + left), (req - left)); + } + else + { + ucam->bytes_in += req; + RingQueue_Dequeue(&uvd->dp, buf, req); + } + return req; +} + +/** + * Parses 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. + * + * Data seems to look like this: + * + * <pre> + * + * |----luma ----|-chroma -| + * |-------------+---------| + * |YYYYYYYY(320)|UUUU(160)|\ + * |YYYYYYYY(320)|VVVV(160)| 240 lines + * |.... ... | ... |/ + * |_____________|_________| + * + * </pre> + * + * The chroma is overlapped over four pixels to fill out the data. + * + * @since 16-May-2001 Created. + */ +static enum ParseState ultracam_parse_lines(struct uvd* uvd, struct usbvideo_frame* frame) +{ + ultracam_t* const ucam = ULTRACAM_T(uvd); + + int const xRequest = VIDEOSIZE_X(frame->request); /* Application wants this size? */ + int const yRequest = VIDEOSIZE_Y(frame->request); + + int const xvid = VIDEOSIZE_X(uvd->videosize); /* We set camera to this resolution? */ + int const yvid = VIDEOSIZE_Y(uvd->videosize); + + int const ymax = min(yRequest, yvid); /* Use the smaller of the two. */ + int const xmax = min(xRequest, xvid); + + /** + * We're actually going to process two lines at once. Each chroma + * byte has to be duplicated over four luma bytes. However, in the + * process of getting the entire chroma set, we end up reading in + * -two- luma lines. So... we process them all - it's quicker. + * (on my system, this is faster than Windows! :) -Karl + */ + int const jmax = 2; /* Parse 2 at a time. */ + int const tX = 320; + int const tX3 = 3 * tX; /* 2 luma @ 320 + 1 chroma @ 160 */ + + unsigned char buf[ tX3 + 10]; + unsigned char* yl[2]; + unsigned char* ul; + unsigned char* vl; + int i, j; + unsigned char r, g, b, y, u, v; + + /* Make sure there's enough data for the entire line. */ + if (RingQueue_GetLength(&uvd->dp) < tX3) + return scan_Out; + + /* Suck one line out of the ring queue. */ + ultracam_Dequeue(uvd, buf, tX3); + /* RingQueue_Dequeue(&uvd->dp, buf, tX3); */ + + /** + * Make sure that our writing into output buffer will not exceed + * the buffer. Mind that we may write not into current output + * scanline but in several after it as well (if we enlarge image + * vertically.) + */ + if ((frame->curline + 2) >= ymax) + return scan_NextFrame; + /** + * Now we are sure that entire line (representing all 'scanLength' + * pixels from the camera) is available in the buffer. We start + * copying the line left-aligned to the V4L buffer. If the camera + * line is shorter then we should pad the V4L buffer with + * something (black) to complete the line. + */ + assert(frame->data != NULL); + + yl[0] = buf; + vl = (yl[0] + tX); + yl[1] = (vl + (tX >> 1)); + ul = (yl[1] + tX); + for (j = 0; j < jmax; j++) + { + for (i = 0; i < xmax; i++) + { + /** + * At some point, I would like to scale the video to fit + * the requested window, rather than ignoring the size + * request. + */ + if (i < tX) + { + y = yl[j][i]; + u = ul[(i >> 1)]; + v = vl[(i >> 1)]; + /* invert around 128 (signed/unsigned conflict?) */ + y += ((y < 128) ? 128 : -128); + u += ((u < 128) ? 128 : -128); + v += ((v < 128) ? 128 : -128); + y += brite; + } + else + y = u = v = 0; + if (flags & FLAGS_MONOCHROME) + { + switch (yuv) { + default: + case 0: r = g = b = y; break; + case 1: r = g = b = u; break; + case 2: r = g = b = v; break; + } + } + else + YUV_TO_RGB_BY_THE_BOOK(y, u, v, r, g, b); + /* this is the slow way to put pixels. if you need speed, + * check out how the IBM cam driver does it. + */ + if (ucam->invert) + { + RGB24_PUTPIXEL(frame, + (xmax - i - 1), + (ymax - frame->curline - 3), + r, g, b); + } + else + { + RGB24_PUTPIXEL(frame, i, frame->curline, r, g, b); + } + ucam->ybar += y; + ucam->rbar += r; + ucam->gbar += g; + ucam->bbar += b; + } + frame->curline++; + } + if (frame->curline >= ymax) + return scan_NextFrame; + else + return scan_Continue; +} + /* * ultracam_ProcessIsocData() * @@ -96,32 +924,38 @@ */ static void ultracam_ProcessIsocData(struct uvd *uvd, struct usbvideo_frame *frame) { - int n; + enum ParseState pstate; + + /* This is just _too_ verbose. */ + /* TRACE_FUNC_ENTRY(); */ assert(uvd != NULL); assert(frame != NULL); - /* Try to move data from queue into frame buffer */ - n = RingQueue_GetLength(&uvd->dp); - if (n > 0) { - int m; - /* See how much spare we have left */ - m = uvd->max_frame_size - frame->seqRead_Length; - if (n > m) - n = m; - /* Now move that much data into frame buffer */ - RingQueue_Dequeue( - &uvd->dp, - frame->data + frame->seqRead_Length, - m); - frame->seqRead_Length += m; - } - /* See if we filled the frame */ - if (frame->seqRead_Length >= uvd->max_frame_size) { - frame->frameState = FrameState_Done; - uvd->curframe = -1; - uvd->stats.frame_num++; + while (1) + { + pstate = scan_Out; + if (frame->scanstate == ScanState_Scanning) + { + pstate = ultracam_find_header(uvd, frame); + } + else if (frame->scanstate == ScanState_Lines) + { + pstate = ultracam_parse_lines(uvd, frame); + } + if (pstate == scan_Continue) + continue; + else if ((pstate == scan_NextFrame) || (pstate == scan_Out)) + break; + else + return; } + if (pstate == scan_NextFrame) + { + frame->frameState = FrameState_Done; + uvd->curframe = -1; + uvd->stats.frame_num++; + } } /* @@ -135,35 +969,40 @@ unsigned char req, unsigned short value, unsigned short index, - int is_out) + unsigned char *is_out) { static const char proc[] = "ultracam_veio"; - unsigned char cp[8] /* = { 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef } */; +#if 0 + unsigned char cp[8] + /* = { 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef } */ ; +#endif int i; if (!CAMERA_IS_OPERATIONAL(uvd)) return 0; - if (!is_out) { - i = usb_control_msg( - uvd->dev, + if (uvd->debug >= 4) + dbg("%s(req = 0x%02x, value = 0x%04x, index = 0x%04x", + __FUNCTION__, req, value, index); + + if (is_out) { + i = usb_control_msg(uvd->dev, usb_rcvctrlpipe(uvd->dev, 0), req, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value, index, - cp, - sizeof(cp), - 1000); -#if 1 + is_out, + 2, + HZ); +#if 0 info("USB => %02x%02x%02x%02x%02x%02x%02x%02x " "(req=$%02x val=$%04x ind=$%04x)", cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7], req, value, index); #endif } else { - i = usb_control_msg( - uvd->dev, + i = usb_control_msg(uvd->dev, usb_sndctrlpipe(uvd->dev, 0), req, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, @@ -171,7 +1010,7 @@ index, NULL, 0, - 1000); + HZ); } if (i < 0) { err("%s: ERROR=%d. Camera stopped; Reconnect or reload driver.", @@ -181,12 +1020,85 @@ return i; } -/* - * ultracam_calculate_fps() +/** + * FIXME: This is probably the wrong thing to do in certain + * circumstances, because it results in the following call chain: + * + * <pre> + * usb_set_interface -> usb_disable_interface + * usb_disable_interface -> usb_disable_endpoint + * usb_disable_endpoint -> ((struct usb_device*)dev)->bus->op->disable + * + * NOTE: At /usr/src/linux-2.6.10/drivers/usb/core/hcd.c:1526, + * the above function pointer `disable' is set to + * `hcd_endpoint_disable'. + * + * ... -> hcd_endpoint_disable + * hcd_endpoint_disable -> ... + * + * NOTE: hcd_endpoint_disable disables the endpoint and + * ***cancels any pending urbs***. + * </pre> + */ +static int ultracam_alternateSetting(struct uvd* uvd, int setting) +{ + static const char proc[] = "ultracam_alternateSetting"; + int i; + if (uvd->debug >= 2) + dbg("%s: calling usb_set_interface(dev, uvd->iface = %d, uvd->ifaceAltActive = %d)", + __FUNCTION__, uvd->iface, setting); + i = usb_set_interface(uvd->dev, uvd->iface, setting); + if (uvd->debug >= 2) + dbg("%s: usb_set_interface returned %d", __FUNCTION__, i); + if (i < 0) + { + err("%s: usb_set_interface error", proc); + uvd->last_error = i; + return -EBUSY; + } + return 0; +} + +/** + * Computes the frame rate. IBM's website documents that this camera + * can do 30 FPS (Frames Per Second). In reality, don't expect much + * from this camera, the number is more like 5. + * + * @todo Figure out why the original author felt that the framerate + * could be a module parameter, and not an intrinsic property of the + * camera. + * + * @todo Figure out where the original framerate computation comes + * from, and why <code>fps == 9/2 framerate + 3</code>. (Note that if + * framerate == FRAMERATE_MAX, the above formula yields 30, the + * documented maximum value.) + * + * @return The number of frames per second. */ static int ultracam_calculate_fps(struct uvd *uvd) { - return 3 + framerate*4 + framerate/2; + int fps; + TRACE_FUNC_ENTRY(); + fps = 9/2 * framerate + 3; +#ifdef DEBUG + if (debug >= 1) + { + static int old_fps = -1; + static int const fps_logging_threshold = 1; + int const dFPS = (fps - old_fps); + if (dFPS >= fps_logging_threshold) + { + int const increased = (dFPS > 0); + dbg("%s: %d frames per second (%s %d)", + __FUNCTION__, + fps, + increased ? "increased by " : "decreased by ", + increased ? dFPS : -dFPS); + } + old_fps = fps; + } +#endif + return fps; } /* @@ -194,6 +1106,112 @@ */ static void ultracam_adjust_contrast(struct uvd *uvd) { + TRACE_FUNC_ENTRY(); + if (debug >= 2) + info("%s: unimplemented", __FUNCTION__); +} + +/* + * ultracam_set_white_balance() + */ +static void ultracam_set_white_balance(struct uvd* uvd) +{ + int wb; + /* white balance codes to send to cam (sniffed from Windows) */ + unsigned short* wbp; + unsigned short whitebalcodes[49 * 6] = { + 0x0034, 0x003f, 0x00da, 0x00ff, 0x0002, 0x00f5, + 0x0035, 0x003f, 0x00d6, 0x00ff, 0x0002, 0x00f5, + 0x0036, 0x003f, 0x00d3, 0x00ff, 0x0002, 0x00f5, + 0x0037, 0x003f, 0x00cf, 0x00ff, 0x0002, 0x00f5, + 0x0038, 0x003f, 0x00cc, 0x00ff, 0x0002, 0x00f5, + 0x0038, 0x003f, 0x00c8, 0x00ff, 0x0002, 0x00f5, + 0x0039, 0x003f, 0x00c5, 0x00ff, 0x0002, 0x00f5, + 0x003a, 0x003f, 0x00c1, 0x00ff, 0x0002, 0x00f5, + 0x003b, 0x003f, 0x00be, 0x0000, 0x0002, 0x00f6, + 0x003c, 0x003f, 0x00ba, 0x0000, 0x0002, 0x00f6, + 0x003d, 0x003f, 0x00b6, 0x0000, 0x0002, 0x00f6, + 0x003e, 0x003f, 0x00b3, 0x0000, 0x0002, 0x00f6, + 0x003f, 0x003f, 0x00af, 0x0001, 0x0002, 0x00f6, + 0x003f, 0x003f, 0x00ac, 0x0001, 0x0002, 0x00f6, + 0x0040, 0x003f, 0x00a8, 0x0001, 0x0002, 0x00f6, + 0x0041, 0x003f, 0x00a5, 0x0001, 0x0002, 0x00f6, + 0x0042, 0x003f, 0x00a1, 0x0001, 0x0002, 0x00f6, + 0x0045, 0x003f, 0x009f, 0x0001, 0x0002, 0x00f6, + 0x0049, 0x003f, 0x009d, 0x0001, 0x0002, 0x00f6, + 0x004c, 0x003f, 0x009b, 0x0000, 0x0002, 0x00f7, + 0x004f, 0x003f, 0x009a, 0x0000, 0x0003, 0x00f7, + 0x0053, 0x003f, 0x0098, 0x00ff, 0x0003, 0x00f7, + 0x0056, 0x003f, 0x0096, 0x00ff, 0x0003, 0x00f7, + 0x0059, 0x003f, 0x0094, 0x00ff, 0x0003, 0x00f7, + 0x005d, 0x003f, 0x0092, 0x00ff, 0x0003, 0x00f8, + 0x0060, 0x003f, 0x0090, 0x00ff, 0x0003, 0x00f8, + 0x0063, 0x003f, 0x008e, 0x00ff, 0x0003, 0x00f8, + 0x0066, 0x003f, 0x008c, 0x00fe, 0x0003, 0x00f8, + 0x006a, 0x003f, 0x008b, 0x00fe, 0x0004, 0x00f8, + 0x006d, 0x003f, 0x0089, 0x00fe, 0x0004, 0x00f8, + 0x0070, 0x003f, 0x0087, 0x00fe, 0x0004, 0x00f9, + 0x0074, 0x003f, 0x0085, 0x00fd, 0x0004, 0x00f9, + 0x0077, 0x003f, 0x0083, 0x00fd, 0x0004, 0x00f9, + 0x0078, 0x003f, 0x007f, 0x00fd, 0x0004, 0x00f9, + 0x007a, 0x003f, 0x007b, 0x00fd, 0x0004, 0x00fa, + 0x007b, 0x003f, 0x0077, 0x00fc, 0x0004, 0x00fa, + 0x007d, 0x003f, 0x0073, 0x00fc, 0x0004, 0x00fa, + 0x007e, 0x003f, 0x006f, 0x00fc, 0x0003, 0x00fa, + 0x007f, 0x003f, 0x006b, 0x00fc, 0x0003, 0x00fb, + 0x0081, 0x003f, 0x0067, 0x00fb, 0x0003, 0x00fb, + 0x0082, 0x0040, 0x0064, 0x00fb, 0x0003, 0x00fb, + 0x0083, 0x0040, 0x0060, 0x00fb, 0x0003, 0x00fb, + 0x0085, 0x0040, 0x005c, 0x00fb, 0x0003, 0x00fc, + 0x0086, 0x0040, 0x0058, 0x00fa, 0x0003, 0x00fc, + 0x0088, 0x0040, 0x0054, 0x00fa, 0x0003, 0x00fc, + 0x0089, 0x0040, 0x0050, 0x00fa, 0x0002, 0x00fc, + 0x008a, 0x0040, 0x004c, 0x00fa, 0x0002, 0x00fd, + 0x008c, 0x0040, 0x0048, 0x00f9, 0x0002, 0x00fd, + 0x008d, 0x0040, 0x0044, 0x00f9, 0x0002, 0x00fd + }; + /** + * I'm trying to figure out what these codes actually mean. Some + * hints may include rgb or yuv gain within the camera itself, but + * it doesn't make a whole lot of sense, since some values change + * a lot, some hardly change at all, and none is precisely linear + * or even suggests a coordinating function (Yes, I plotted the + * values out. They're not linear.) + * + * Any ideas? + * -Karl + */ + + RESTRICT_TO_RANGE(whitebal, -1, 48); + + if (whitebal >= 0) + wb = whitebal; + else + wb = ULTRACAM_T(uvd)->projected_whitebal; + + wbp = whitebalcodes + (wb*6); + + ultracam_veio(uvd, 0x01, ((wb_51 == 0xff00) ? *wbp : wb_51), 0x0051, NULL); wbp++; + ultracam_veio(uvd, 0x01, ((wb_52 == 0xff00) ? *wbp : wb_52), 0x0052, NULL); wbp++; + ultracam_veio(uvd, 0x01, ((wb_53 == 0xff00) ? *wbp : wb_53), 0x0053, NULL); wbp++; + ultracam_veio(uvd, 0x01, ((wb_11 == 0xff00) ? *wbp : wb_11), 0x0011, NULL); wbp++; + ultracam_veio(uvd, 0x01, ((wb_12 == 0xff00) ? *wbp : wb_12), 0x0012, NULL); wbp++; + ultracam_veio(uvd, 0x01, ((wb_13 == 0xff00) ? *wbp : wb_13), 0x0013, NULL); +} + +/** + * Cameras have internal smoothing feature. It is controlled by value + * in range [0..4], where 0 is most smooth and 4 is most sharp (raw + * image, I guess). Recommended value is 3. + */ +static void ultracam_set_sharpness(struct uvd* uvd) +{ + unsigned char buf[2]; + unsigned short sharps[SHARPNESS_MAX + 1] = + { 0x0004, 0x0024, 0x0064, 0x00a4, 0x00e4 }; + RESTRICT_TO_RANGE(sharpness, SHARPNESS_MIN, SHARPNESS_MAX); + ultracam_veio(uvd, 0x01, 0x0000, 0x0001, buf); + ultracam_veio(uvd, 0x01, sharps[sharpness], 0x0001, NULL); } /* @@ -203,68 +1221,121 @@ */ static void ultracam_set_brightness(struct uvd *uvd) { + TRACE_FUNC_ENTRY(); + if (debug >= 2) + info("%s: unimplemented", __FUNCTION__); } static void ultracam_set_hue(struct uvd *uvd) { + TRACE_FUNC_ENTRY(); + if (debug >= 2) + info("%s: unimplemented", __FUNCTION__); } -/* - * ultracam_adjust_picture() - * - * This procedure gets called from V4L interface to update picture settings. - * Here we change brightness and contrast. +/** + * This procedure gets called from V4L interface to update picture + * settings. Here we change brightness and contrast. */ static void ultracam_adjust_picture(struct uvd *uvd) { + TRACE_FUNC_ENTRY(); ultracam_adjust_contrast(uvd); ultracam_set_brightness(uvd); ultracam_set_hue(uvd); } -/* - * ultracam_video_stop() - * +/** * This code tells camera to stop streaming. The interface remains * configured and bandwidth - claimed. */ static void ultracam_video_stop(struct uvd *uvd) { + TRACE_FUNC_ENTRY(); + /* I think it's this... */ + ultracam_veio(uvd, 0x02, 0x0000, 0x0001, NULL); + ultracam_alternateSetting(uvd, 0x00); + ultracam_veio(uvd, 0x01, 0x0000, 0x0001, NULL); + ultracam_veio(uvd, 0x02, 0x0003, 0x0000, NULL); + ultracam_veio(uvd, 0x02, 0x0000, 0x0005, NULL); } -/* - * ultracam_reinit_iso() - * +static int ultracam_resetPipe(struct uvd* uvd) +{ + int ret; + TRACE_FUNC_ENTRY(); + /** + * Would like to be able to change the setting (not necessarily + * right here, but `ultracam_alternateSetting' causes the + * isochronous transfer URB's to be cancelled, and doesn't create + * and submit new ones. + */ + ret = usb_clear_halt(uvd->dev, uvd->video_endp); + if (uvd->debug >= 2) + if (ret != 0) + dbg("%s: usb_clear_halt(uvd->dev, uvd->video_endp = %d) returned %d (ignored)", + __FUNCTION__, (int)uvd->video_endp, ret); + return 0; +} + +/** * This procedure sends couple of commands to the camera and then * resets the video pipe. This sequence was observed to reinit the * camera or, at least, to initiate ISO data stream. */ static void ultracam_reinit_iso(struct uvd *uvd, int do_stop) { + TRACE_FUNC_ENTRY(); + ultracam_resetPipe(uvd); } static void ultracam_video_start(struct uvd *uvd) { + TRACE_FUNC_ENTRY(); + /** + * Perhaps we should implement and call something like: + * ultracam_change_lighting_conditions(uvd); + */ + /* this is doing no good here... looks like + * sharpness is set on camera init. + ultracam_set_sharpness(uvd); + */ ultracam_reinit_iso(uvd, 0); } -static int ultracam_resetPipe(struct uvd *uvd) +/** + * This method is called from ultracam_is_backward, and should not be + * called from other locations; to do so would defeat the logging of + * changes in the camera orientation. + * + * @return 1 if the camera faces toward the laptop user. + */ +static int ultracam_is_forward(struct uvd* uvd) { - usb_clear_halt(uvd->dev, uvd->video_endp); - return 0; + unsigned char buf[2]; + ultracam_veio(uvd, 0x02, 0x0000, 0x000b, buf); + return 0x05 == buf[1]; } -static int ultracam_alternateSetting(struct uvd *uvd, int setting) +/** + * Reports the orientation of the camera. If debugging is enabled, + * logs a message only when the user changes the camera direction. + * + * @return 1 if the camera faces away from the laptop user. + */ +static int ultracam_is_backward(struct uvd* uvd) { - static const char proc[] = "ultracam_alternateSetting"; - int i; - i = usb_set_interface(uvd->dev, uvd->iface, setting); - if (i < 0) { - err("%s: usb_set_interface error", proc); - uvd->last_error = i; - return -EBUSY; + static int wasBackward = -1; + int const isBackward = ! ultracam_is_forward(uvd); + if (debug >= 1) + { + int const changed = (isBackward != wasBackward); + if (changed) + info("Camera is facing %s", + isBackward ? "backward" : "forward"); } - return 0; + wasBackward = isBackward; + return isBackward; } /* @@ -272,188 +1343,218 @@ */ static int ultracam_setup_on_open(struct uvd *uvd) { + unsigned char buf[2]; + int setup_ok = 0; /* Success by default */ + + TRACE_FUNC_ENTRY(); + + ULTRACAM_T(uvd)->projected_whitebal = 20; + /* Send init sequence only once, it's large! */ - if (!ULTRACAM_T(uvd)->initialized) { - ultracam_alternateSetting(uvd, 0x04); - ultracam_alternateSetting(uvd, 0x00); - ultracam_veio(uvd, 0x02, 0x0004, 0x000b, 1); - ultracam_veio(uvd, 0x02, 0x0001, 0x0005, 1); - ultracam_veio(uvd, 0x02, 0x8000, 0x0000, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x0000, 1); - ultracam_veio(uvd, 0x00, 0x00b0, 0x0001, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x0002, 1); - ultracam_veio(uvd, 0x00, 0x000c, 0x0003, 1); - ultracam_veio(uvd, 0x00, 0x000b, 0x0004, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x0005, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x0006, 1); - ultracam_veio(uvd, 0x00, 0x0079, 0x0007, 1); - ultracam_veio(uvd, 0x00, 0x003b, 0x0008, 1); - ultracam_veio(uvd, 0x00, 0x0002, 0x000f, 1); - ultracam_veio(uvd, 0x00, 0x0001, 0x0010, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x0011, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00bf, 1); - ultracam_veio(uvd, 0x00, 0x0001, 0x00c0, 1); - ultracam_veio(uvd, 0x00, 0x0010, 0x00cb, 1); - ultracam_veio(uvd, 0x01, 0x00a4, 0x0001, 1); - ultracam_veio(uvd, 0x01, 0x0010, 0x0002, 1); - ultracam_veio(uvd, 0x01, 0x0066, 0x0007, 1); - ultracam_veio(uvd, 0x01, 0x000b, 0x0008, 1); - ultracam_veio(uvd, 0x01, 0x0034, 0x0009, 1); - ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 1); - ultracam_veio(uvd, 0x01, 0x002e, 0x000b, 1); - ultracam_veio(uvd, 0x01, 0x00d6, 0x000c, 1); - ultracam_veio(uvd, 0x01, 0x00fc, 0x000d, 1); - ultracam_veio(uvd, 0x01, 0x00f1, 0x000e, 1); - ultracam_veio(uvd, 0x01, 0x00da, 0x000f, 1); - ultracam_veio(uvd, 0x01, 0x0036, 0x0010, 1); - ultracam_veio(uvd, 0x01, 0x000b, 0x0011, 1); - ultracam_veio(uvd, 0x01, 0x0001, 0x0012, 1); - ultracam_veio(uvd, 0x01, 0x0000, 0x0013, 1); - ultracam_veio(uvd, 0x01, 0x0000, 0x0014, 1); - ultracam_veio(uvd, 0x01, 0x0087, 0x0051, 1); - ultracam_veio(uvd, 0x01, 0x0040, 0x0052, 1); - ultracam_veio(uvd, 0x01, 0x0058, 0x0053, 1); - ultracam_veio(uvd, 0x01, 0x0040, 0x0054, 1); - ultracam_veio(uvd, 0x01, 0x0000, 0x0040, 1); - ultracam_veio(uvd, 0x01, 0x0010, 0x0041, 1); - ultracam_veio(uvd, 0x01, 0x0020, 0x0042, 1); - ultracam_veio(uvd, 0x01, 0x0030, 0x0043, 1); - ultracam_veio(uvd, 0x01, 0x0040, 0x0044, 1); - ultracam_veio(uvd, 0x01, 0x0050, 0x0045, 1); - ultracam_veio(uvd, 0x01, 0x0060, 0x0046, 1); - ultracam_veio(uvd, 0x01, 0x0070, 0x0047, 1); - ultracam_veio(uvd, 0x01, 0x0080, 0x0048, 1); - ultracam_veio(uvd, 0x01, 0x0090, 0x0049, 1); - ultracam_veio(uvd, 0x01, 0x00a0, 0x004a, 1); - ultracam_veio(uvd, 0x01, 0x00b0, 0x004b, 1); - ultracam_veio(uvd, 0x01, 0x00c0, 0x004c, 1); - ultracam_veio(uvd, 0x01, 0x00d0, 0x004d, 1); - ultracam_veio(uvd, 0x01, 0x00e0, 0x004e, 1); - ultracam_veio(uvd, 0x01, 0x00f0, 0x004f, 1); - ultracam_veio(uvd, 0x01, 0x00ff, 0x0050, 1); - ultracam_veio(uvd, 0x01, 0x0000, 0x0056, 1); - ultracam_veio(uvd, 0x00, 0x0080, 0x00c1, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c2, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0080, 0x00c1, 1); - ultracam_veio(uvd, 0x00, 0x0004, 0x00c2, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0002, 0x00c1, 1); - ultracam_veio(uvd, 0x00, 0x0020, 0x00c2, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0040, 0x00c1, 1); - ultracam_veio(uvd, 0x00, 0x0017, 0x00c2, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x00c0, 0x00c1, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c2, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1); - ultracam_veio(uvd, 0x02, 0xc040, 0x0001, 1); - ultracam_veio(uvd, 0x01, 0x0000, 0x0008, 0); - ultracam_veio(uvd, 0x01, 0x0000, 0x0009, 0); - ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 0); - ultracam_veio(uvd, 0x01, 0x0000, 0x000b, 0); - ultracam_veio(uvd, 0x01, 0x0000, 0x000c, 0); - ultracam_veio(uvd, 0x01, 0x0000, 0x000d, 0); - ultracam_veio(uvd, 0x01, 0x0000, 0x000e, 0); - ultracam_veio(uvd, 0x01, 0x0000, 0x000f, 0); - ultracam_veio(uvd, 0x01, 0x0000, 0x0010, 0); - ultracam_veio(uvd, 0x01, 0x000b, 0x0008, 1); - ultracam_veio(uvd, 0x01, 0x0034, 0x0009, 1); - ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 1); - ultracam_veio(uvd, 0x01, 0x002e, 0x000b, 1); - ultracam_veio(uvd, 0x01, 0x00d6, 0x000c, 1); - ultracam_veio(uvd, 0x01, 0x00fc, 0x000d, 1); - ultracam_veio(uvd, 0x01, 0x00f1, 0x000e, 1); - ultracam_veio(uvd, 0x01, 0x00da, 0x000f, 1); - ultracam_veio(uvd, 0x01, 0x0036, 0x0010, 1); - ultracam_veio(uvd, 0x01, 0x0000, 0x0001, 0); - ultracam_veio(uvd, 0x01, 0x0064, 0x0001, 1); - ultracam_veio(uvd, 0x01, 0x0059, 0x0051, 1); - ultracam_veio(uvd, 0x01, 0x003f, 0x0052, 1); - ultracam_veio(uvd, 0x01, 0x0094, 0x0053, 1); - ultracam_veio(uvd, 0x01, 0x00ff, 0x0011, 1); - ultracam_veio(uvd, 0x01, 0x0003, 0x0012, 1); - ultracam_veio(uvd, 0x01, 0x00f7, 0x0013, 1); - ultracam_veio(uvd, 0x00, 0x0009, 0x0011, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x0001, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x0000, 1); - ultracam_veio(uvd, 0x00, 0x0020, 0x00c1, 1); - ultracam_veio(uvd, 0x00, 0x0010, 0x00c2, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1); - ultracam_alternateSetting(uvd, 0x04); - ultracam_veio(uvd, 0x02, 0x0000, 0x0001, 1); - ultracam_veio(uvd, 0x02, 0x0000, 0x0001, 1); - ultracam_veio(uvd, 0x02, 0x0000, 0x0006, 1); - ultracam_veio(uvd, 0x02, 0x9000, 0x0007, 1); - ultracam_veio(uvd, 0x02, 0x0042, 0x0001, 1); - ultracam_veio(uvd, 0x02, 0x0000, 0x000b, 0); + if (!ULTRACAM_T(uvd)->initialized) + { + ultracam_veio(uvd, 0x02, 0x0004, 0x000b, NULL); + ultracam_veio(uvd, 0x02, 0x0001, 0x0005, NULL); + ultracam_veio(uvd, 0x02, 0x8000, 0x0000, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x0000, NULL); + ultracam_veio(uvd, 0x00, 0x00b0, 0x0001, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x0002, NULL); + ultracam_veio(uvd, 0x00, 0x000c, 0x0003, NULL); + ultracam_veio(uvd, 0x00, 0x000b, 0x0004, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x0005, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x0006, NULL); + ultracam_veio(uvd, 0x00, 0x0079, 0x0007, NULL); + ultracam_veio(uvd, 0x00, 0x003b, 0x0008, NULL); + ultracam_veio(uvd, 0x00, 0x0002, 0x000f, NULL); + ultracam_veio(uvd, 0x00, 0x0001, 0x0010, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x0011, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00bf, NULL); + ultracam_veio(uvd, 0x00, 0x0001, 0x00c0, NULL); + ultracam_veio(uvd, 0x00, 0x0010, 0x00cb, NULL); + ultracam_veio(uvd, 0x01, 0x00a4, 0x0001, NULL); + ultracam_veio(uvd, 0x01, 0x0010, 0x0002, NULL); + ultracam_veio(uvd, 0x01, 0x0066, 0x0007, NULL); + ultracam_veio(uvd, 0x01, 0x000b, 0x0008, NULL); + ultracam_veio(uvd, 0x01, 0x0034, 0x0009, NULL); + ultracam_veio(uvd, 0x01, 0x0000, 0x000a, NULL); + ultracam_veio(uvd, 0x01, 0x002e, 0x000b, NULL); + ultracam_veio(uvd, 0x01, 0x00d6, 0x000c, NULL); + ultracam_veio(uvd, 0x01, 0x00fc, 0x000d, NULL); + ultracam_veio(uvd, 0x01, 0x00f1, 0x000e, NULL); + ultracam_veio(uvd, 0x01, 0x00da, 0x000f, NULL); + ultracam_veio(uvd, 0x01, 0x0036, 0x0010, NULL); + ultracam_veio(uvd, 0x01, 0x000b, 0x0011, NULL); + ultracam_veio(uvd, 0x01, 0x0001, 0x0012, NULL); + ultracam_veio(uvd, 0x01, 0x0000, 0x0013, NULL); + ultracam_veio(uvd, 0x01, 0x0000, 0x0014, NULL); + ultracam_veio(uvd, 0x01, 0x0087, 0x0051, NULL); + ultracam_veio(uvd, 0x01, 0x0040, 0x0052, NULL); + ultracam_veio(uvd, 0x01, 0x0058, 0x0053, NULL); + ultracam_veio(uvd, 0x01, 0x0040, 0x0054, NULL); + ultracam_veio(uvd, 0x01, 0x0000, 0x0040, NULL); + ultracam_veio(uvd, 0x01, 0x0010, 0x0041, NULL); + ultracam_veio(uvd, 0x01, 0x0020, 0x0042, NULL); + ultracam_veio(uvd, 0x01, 0x0030, 0x0043, NULL); + ultracam_veio(uvd, 0x01, 0x0040, 0x0044, NULL); + ultracam_veio(uvd, 0x01, 0x0050, 0x0045, NULL); + ultracam_veio(uvd, 0x01, 0x0060, 0x0046, NULL); + ultracam_veio(uvd, 0x01, 0x0070, 0x0047, NULL); + ultracam_veio(uvd, 0x01, 0x0080, 0x0048, NULL); + ultracam_veio(uvd, 0x01, 0x0090, 0x0049, NULL); + ultracam_veio(uvd, 0x01, 0x00a0, 0x004a, NULL); + ultracam_veio(uvd, 0x01, 0x00b0, 0x004b, NULL); + ultracam_veio(uvd, 0x01, 0x00c0, 0x004c, NULL); + ultracam_veio(uvd, 0x01, 0x00d0, 0x004d, NULL); + ultracam_veio(uvd, 0x01, 0x00e0, 0x004e, NULL); + ultracam_veio(uvd, 0x01, 0x00f0, 0x004f, NULL); + ultracam_veio(uvd, 0x01, 0x00ff, 0x0050, NULL); + ultracam_veio(uvd, 0x01, 0x0000, 0x0056, NULL); + ultracam_veio(uvd, 0x00, 0x0080, 0x00c1, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c2, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL); + ultracam_veio(uvd, 0x00, 0x0080, 0x00c1, NULL); + ultracam_veio(uvd, 0x00, 0x0004, 0x00c2, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL); + ultracam_veio(uvd, 0x00, 0x0002, 0x00c1, NULL); + ultracam_veio(uvd, 0x00, 0x0020, 0x00c2, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL); + ultracam_veio(uvd, 0x00, 0x0040, 0x00c1, NULL); + ultracam_veio(uvd, 0x00, 0x0017, 0x00c2, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL); + ultracam_veio(uvd, 0x00, 0x00c0, 0x00c1, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00c2, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, NULL); + + /* command mode? */ + ultracam_veio(uvd, 0x02, 0xc040, 0x0001, NULL); + + /* read in hue/sat? */ + ultracam_veio(uvd, 0x01, 0x0000, 0x0008, buf); + ultracam_veio(uvd, 0x01, 0x0000, 0x0009, buf); + ultracam_veio(uvd, 0x01, 0x0000, 0x000a, buf); + ultracam_veio(uvd, 0x01, 0x0000, 0x000b, buf); + ultracam_veio(uvd, 0x01, 0x0000, 0x000c, buf); + ultracam_veio(uvd, 0x01, 0x0000, 0x000d, buf); + ultracam_veio(uvd, 0x01, 0x0000, 0x000e, buf); + ultracam_veio(uvd, 0x01, 0x0000, 0x000f, buf); + ultracam_veio(uvd, 0x01, 0x0000, 0x0010, buf); + + /* hue/saturation */ + ultracam_veio(uvd, 0x01, 0x000b, 0x0008, NULL); + ultracam_veio(uvd, 0x01, 0x0034, 0x0009, NULL); + ultracam_veio(uvd, 0x01, 0x0000, 0x000a, NULL); + + ultracam_veio(uvd, 0x01, hs_0b, 0x000b, NULL); + ultracam_veio(uvd, 0x01, hs_0c, 0x000c, NULL); + ultracam_veio(uvd, 0x01, hs_0d, 0x000d, NULL); + ultracam_veio(uvd, 0x01, hs_0e, 0x000e, NULL); + ultracam_veio(uvd, 0x01, hs_0f, 0x000f, NULL); + ultracam_veio(uvd, 0x01, hs_10, 0x0010, NULL); + + ultracam_set_sharpness(uvd); + + ultracam_set_white_balance(uvd); + + /* here I have >>>>>> 0x0007 (unknown setting?) */ + ultracam_veio(uvd, 0x00, 0x0009, 0x0011, NULL); + + ultracam_veio(uvd, 0x00, 0x0000, 0x0001, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x0000, NULL); + + /* on my system, these look like this: + * 0x00 0x001b 0x00c1 + * 0x00 0x00e0 0x00c2 + * 0x00 0x0000 0x00ca + * some unknown values? + * -Karl + */ + /* Using Karl's values => green & black image. */ + ultracam_veio(uvd, 0x00, 0x0020, 0x00c1, NULL); + ultracam_veio(uvd, 0x00, 0x0010, 0x00c2, NULL); + ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, NULL); + + ultracam_veio(uvd, 0x02, 0x0000, 0x0001, NULL); + ultracam_veio(uvd, 0x02, 0x0000, 0x0001, NULL); + /* Changing 6 to 7 => no noticeable change. */ + ultracam_veio(uvd, 0x02, 0x0000, 0x0006, NULL); + + /* resolution */ + /* How do we get larger frames from camera? */ + /* Changing 7 to 8 => black image. */ + ultracam_veio(uvd, 0x02, 0x9000, 0x0007, NULL); + + /* turn on camera? */ + ultracam_veio(uvd, 0x02, 0x0042, 0x0001, NULL); + + ultracam_is_backward(uvd); ultracam_resetPipe(uvd); ULTRACAM_T(uvd)->initialized = (setup_ok != 0); + } return setup_ok; } @@ -465,14 +1566,14 @@ RESTRICT_TO_RANGE(init_brightness, 0, 255); RESTRICT_TO_RANGE(init_contrast, 0, 255); - RESTRICT_TO_RANGE(init_color, 0, 255); - RESTRICT_TO_RANGE(init_hue, 0, 255); - RESTRICT_TO_RANGE(hue_correction, 0, 255); + RESTRICT_TO_RANGE(init_sat, 0, 20); + RESTRICT_TO_RANGE(init_hue, 0, 360); + RESTRICT_TO_RANGE(wbmaxdelt, 1, 48); memset(&uvd->vpic, 0, sizeof(uvd->vpic)); memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old)); - uvd->vpic.colour = init_color << 8; + uvd->vpic.colour = init_sat << 8; uvd->vpic.hue = init_hue << 8; uvd->vpic.brightness = init_brightness << 8; uvd->vpic.contrast = init_contrast << 8; @@ -481,7 +1582,7 @@ uvd->vpic.palette = VIDEO_PALETTE_RGB24; memset(&uvd->vcap, 0, sizeof(uvd->vcap)); - strcpy(uvd->vcap.name, "IBM Ultra Camera"); + strcpy(uvd->vcap.name, "IBM Ultraport Camera"); uvd->vcap.type = VID_TYPE_CAPTURE; uvd->vcap.channels = 1; uvd->vcap.audios = 0; @@ -498,139 +1599,347 @@ strcpy(uvd->vchan.name, "Camera"); } -/* - * ultracam_probe() - * - * This procedure queries device descriptor and accepts the interface - * if it looks like our camera. - * - * History: - * 12-Nov-2000 Reworked to comply with new probe() signature. - * 23-Jan-2001 Added compatibility with 2.2.x kernels. +/** + * Verifies the vendor id and product id of the device. + * @return 1 (true) if everything is okay. */ -static int ultracam_probe(struct usb_interface *intf, const struct usb_device_id *devid) +static int +ultracam_probe_camera_recognized( + struct usb_interface* intf, + struct usb_device const* const dev) { - struct usb_device *dev = interface_to_usbdev(intf); - struct uvd *uvd = NULL; - int ix, i, nas; - int actInterface=-1, inactInterface=-1, maxPS=0; - unsigned char video_ep = 0; - - if (debug >= 1) - info("ultracam_probe(%p)", intf); - - /* We don't handle multi-config cameras */ - if (dev->descriptor.bNumConfigurations != 1) - return -ENODEV; - - info("IBM Ultra camera found (rev. 0x%04x)", - le16_to_cpu(dev->descriptor.bcdDevice)); - - /* Validate found interface: must have one ISO endpoint */ - nas = intf->num_altsetting; - if (debug > 0) - info("Number of alternate settings=%d.", nas); - if (nas < 8) { - err("Too few alternate settings for this camera!"); - return -ENODEV; + int recognized = 0; + if (ULTRACAM_VENDOR_ID != dev->descriptor.idVendor) + { + err("Wrong vendor id: %d (expected %d).", + dev->descriptor.idVendor, + ULTRACAM_VENDOR_ID); + } + else if (ULTRACAM_PRODUCT_ID != dev->descriptor.idProduct) + { + err("Wrong product id: %d (expected %d).", + dev->descriptor.idProduct, + ULTRACAM_PRODUCT_ID); } - /* Validate all alternate settings */ - for (ix=0; ix < nas; ix++) { - const struct usb_host_interface *interface; - const struct usb_endpoint_descriptor *endpoint; - - interface = &intf->altsetting[ix]; - i = interface->desc.bAlternateSetting; - if (interface->desc.bNumEndpoints != 1) { + else if (1 != dev->descriptor.bNumConfigurations) + { + /** @todo Can't we just ignore all but one? */ + err("Multi-config cameras not supported."); + } + else + { + info("IBM Ultra camera found (rev. 0x%04x)", + dev->descriptor.bcdDevice); + recognized = 1; + } + return recognized; +} + +/** + * Interface must have exactly one endpoint. + * @todo Document why. + * @return 1 on success. + */ +int +ultracam_probe_camera_validate_interface_endpoint_count( + struct usb_host_interface const* const interface) +{ + int validated_ok = + (1 == interface->desc.bNumEndpoints); + if (! validated_ok) + { err("Interface %d. has %u. endpoints!", interface->desc.bInterfaceNumber, (unsigned)(interface->desc.bNumEndpoints)); - return -ENODEV; } - endpoint = &interface->endpoint[0].desc; - if (video_ep == 0) - video_ep = endpoint->bEndpointAddress; - else if (video_ep != endpoint->bEndpointAddress) { - err("Alternate settings have different endpoint addresses!"); - return -ENODEV; + return validated_ok; } - if ((endpoint->bmAttributes & 0x03) != 0x01) { + +/** + * Endpoints must be isochronous, and must be inbound. (Because the + * device is a camera, it has a real-time video stream in only one + * direction.) + * + * @return 1 on success. + */ +int +ultracam_probe_camera_validate_interface_endpoint( + struct usb_host_interface const* const interface, + struct usb_endpoint_descriptor const* endpoint) +{ + int validated_ok = 0; + if (USB_ENDPOINT_XFER_ISOC != + (endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)) + { err("Interface %d. has non-ISO endpoint!", interface->desc.bInterfaceNumber); - return -ENODEV; } - if ((endpoint->bEndpointAddress & 0x80) == 0) { + else if (0 == + (endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)) + { err("Interface %d. has ISO OUT endpoint!", interface->desc.bInterfaceNumber); + } + else + { + validated_ok = 1; + } + return validated_ok; +} + +/** + * Validates found interface: must have one ISO endpoint. Validates + * all alternate settings. + */ +static int ultracam_probe_camera_validated( + struct usb_interface* intf, + struct usb_device const* const dev) +{ + int i; + int iy; + unsigned char video_ep = 0; + int actInterface = -1; + int inactInterface = -1; + int maxPS = 0; + struct usb_endpoint_descriptor const* endpoint; + struct usb_host_interface const* interface; + int nas = intf->num_altsetting; + for (i = 0; i < nas; i++) + { + interface = &intf->altsetting[i]; + + if (!ultracam_probe_camera_validate_interface_endpoint_count(interface)) + return -ENODEV; + + endpoint = &interface->endpoint[0].desc; + + if (!ultracam_probe_camera_validate_interface_endpoint(interface, endpoint)) + return -ENODEV; + + if (0 == video_ep) + video_ep = endpoint->bEndpointAddress; + else if (video_ep != endpoint->bEndpointAddress) + { + err("Alternate settings have different endpoint addresses!"); return -ENODEV; } - if (le16_to_cpu(endpoint->wMaxPacketSize) == 0) { + + iy = interface->desc.bAlternateSetting; + if (endpoint->wMaxPacketSize == 0) + { if (inactInterface < 0) - inactInterface = i; - else { + inactInterface = iy; + else + { err("More than one inactive alt. setting!"); return -ENODEV; } - } else { - if (actInterface < 0) { - actInterface = i; - maxPS = le16_to_cpu(endpoint->wMaxPacketSize); - if (debug > 0) - info("Active setting=%d. maxPS=%d.", i, maxPS); - } else { - /* Got another active alt. setting */ - if (maxPS < le16_to_cpu(endpoint->wMaxPacketSize)) { - /* This one is better! */ - actInterface = i; - maxPS = le16_to_cpu(endpoint->wMaxPacketSize); - if (debug > 0) { - info("Even better ctive setting=%d. maxPS=%d.", - i, maxPS); - } } + else if ((actInterface < 0) || (maxPS < endpoint->wMaxPacketSize)) + { + actInterface = iy; + maxPS = endpoint->wMaxPacketSize; } } + if (nas < 8) + { + if (debug >= 1) + info("Number of alternate settings=%d.", nas); + err("Too few alternate settings for this camera! (must have >= 8)"); + return -ENODEV; } - if ((maxPS <= 0) || (actInterface < 0) || (inactInterface < 0)) { + if ((maxPS <= 0) || (actInterface < 0) || (inactInterface < 0)) + { err("Failed to recognize the camera!"); return -ENODEV; } + return 0; +} - uvd = usbvideo_AllocateDevice(cams); - if (uvd != NULL) { - /* Here uvd is a fully allocated uvd object */ - uvd->flags = flags; - uvd->debug = debug; - uvd->dev = dev; - uvd->iface = intf->altsetting->desc.bInterfaceNumber; - uvd->ifaceAltInactive = inactInterface; - uvd->ifaceAltActive = actInterface; - uvd->video_endp = video_ep; - uvd->iso_packet_len = maxPS; - uvd->paletteBits = 1L << VIDEO_PALETTE_RGB24; - uvd->defaultPalette = VIDEO_PALETTE_RGB24; - uvd->canvas = VIDEOSIZE(640, 480); /* FIXME */ - uvd->videosize = uvd->canvas; /* ultracam_size_to_videosize(size);*/ - - /* Initialize ibmcam-specific data */ - assert(ULTRACAM_T(uvd) != NULL); - ULTRACAM_T(uvd)->camera_model = 0; /* Not used yet */ - ULTRACAM_T(uvd)->initialized = 0; - - ultracam_configure_video(uvd); - - i = usbvideo_RegisterVideoDevice(uvd); - if (i != 0) { - err("usbvideo_RegisterVideoDevice() failed."); - uvd = NULL; +static int +get_actInterface( + struct usb_interface const* const intf, + struct usb_device const* const dev, + int* maxPs) +{ + int actInterface = -1; + int i; + struct usb_endpoint_descriptor const* endpoint; + struct usb_host_interface const* interface; + int maxPS = 0; + int const nas = intf->num_altsetting; + int isMaxPsNull = (NULL == maxPs); + if (isMaxPsNull) + maxPs = &maxPS; + for (i = 0; i < nas; i++) + { + interface = &intf->altsetting[i]; + endpoint = &interface->endpoint[0].desc; + if (0 == endpoint->wMaxPacketSize) + continue; + if ((actInterface < 0) + || + (*maxPs < endpoint->wMaxPacketSize)) + { + if (4 == actInterface) /* HACK */ + continue; /* Used to use 4, trying to revert to what works. */ + actInterface = interface->desc.bAlternateSetting; + *maxPs = endpoint->wMaxPacketSize; + if (! isMaxPsNull && /* Only log once. */ + debug > 0) + info("Active setting %d: maxPS = %d", actInterface, *maxPs); } } + if (actInterface == -1) + err("%s: failed to find active interface", __FUNCTION__); + return actInterface; +} + +static int +get_inactInterface( + struct usb_interface const* const intf, + struct usb_device const* const dev) +{ + int inactInterface = -1; + int i; + struct usb_endpoint_descriptor const* endpoint; + struct usb_host_interface const* interface; + int const nas = intf->num_altsetting; + for (i = 0; i < nas; i++) + { + interface = &intf->altsetting[i]; + endpoint = &interface->endpoint[0].desc; + if (0 != endpoint->wMaxPacketSize) + continue; + inactInterface = interface->desc.bAlternateSetting; + /* We know that there is exactly one inactive interface + * because we successfully passed + * ultracam_probe_camera_validated. A failure there would + * have resulted in -ENODEV and a failure of + * ultracam_probe. */ + break; + } + /* See comment above, but just in case, we'll report the error. */ + if (inactInterface == -1) + err("%s: failed to find inactive interface", __FUNCTION__); + return inactInterface; +} + +static int +get_maxPS( + struct usb_interface const* const intf, + struct usb_device const* const dev) +{ + int maxPS = 0; + + int const actInterface = get_actInterface(intf, dev, &maxPS); + + if (-1 == actInterface || 0 == maxPS) + err("%s: failed to find MaxPacketSize", __FUNCTION__); + + return maxPS; +} + +static unsigned char +get_video_ep( + struct usb_interface const* const intf, + struct usb_device const* const dev) +{ + unsigned char video_ep = 0; + + /* We can arbitrarily pick 0 because all of the settings are + * verified to be the same by ultracam_probe_camera_validated. */ + if (0 == video_ep) + video_ep = intf->altsetting[0].endpoint[0].desc.bEndpointAddress; + + if (0 == video_ep) + err("%s: failed to find video endpoint", __FUNCTION__); + + return video_ep; +} + +/* + * ultracam_probe() + * + * This procedure queries device descriptor and accepts the interface + * if it looks like our camera. + * + * History: + * 12-Nov-2000 Reworked to comply with new probe() signature. + * 23-Jan-2001 Added compatibility with 2.2.x kernels. + */ +static int ultracam_probe(struct usb_interface *intf, const struct usb_device_id *devid) +{ + int ret; + struct usb_device *dev = interface_to_usbdev(intf); + struct uvd *uvd = NULL; + ultracam_t* ucam = NULL; + + if (debug >= 1) + info("ultracam_probe(%p)", intf); + + if (!ultracam_probe_camera_recognized(intf, dev)) + return -ENODEV; + + if (0 != ultracam_probe_camera_validated(intf, dev)) + return -ENODEV; + + if (NULL == (uvd = usbvideo_AllocateDevice(cams))) + return -EIO; + + /* Here uvd is a fully allocated uvd object */ + uvd->flags = flags; + uvd->debug = debug; + uvd->dev = dev; + uvd->iface = intf->altsetting->desc.bInterfaceNumber; + uvd->ifaceAltInactive = get_inactInterface(intf, dev); + uvd->ifaceAltActive = get_actInterface(intf, dev, NULL); + uvd->video_endp = get_video_ep(intf, dev); + uvd->iso_packet_len = get_maxPS(intf, dev); + uvd->paletteBits = 1L << VIDEO_PALETTE_RGB24; + uvd->defaultPalette = VIDEO_PALETTE_RGB24; + /* uvd->canvas = VIDEOSIZE(320, 240); */ + + uvd->canvas = VIDEOSIZE(uvd->iso_packet_len, uvd->iso_packet_len * 3/4); + uvd->videosize = uvd->canvas; /* ultracam_size_to_videosize(size);*/ + + /* Initialize ibmcam-specific data */ + ucam = ULTRACAM_T(uvd); + /* Allocation of user_data field is usbvideo's responsibility. */ + assert(ucam != NULL); + ucam->initialized = 0; + ucam->camera_model = ULTRACAM_PRODUCT_ID; + ucam->bytes_in = 0; + ucam->invert = ultracam_is_backward(uvd); + ucam->rbar = 0; + ucam->gbar = 0; + ucam->bbar = 0; + ucam->projected_whitebal = 20; + ucam->frames_since_adjust = 0; + ucam->ybar = 0; + + ultracam_configure_video(uvd); + + if (0 != (ret = usbvideo_RegisterVideoDevice(uvd))) + { + err("usbvideo_RegisterVideoDevice failed! (returned %d)", ret); + uvd = NULL; + } if (uvd) { usb_set_intfdata (intf, uvd); - return 0; + snprintf(uvd->videoName, + sizeof(uvd->videoName), + "IBM Ultraport Camera (v. %hd.%02hd)", + ((dev->descriptor.bcdDevice & 0xff00) >> 8), + (dev->descriptor.bcdDevice & 0x00ff)); + + if (debug >= 3) + print_uvd(uvd); + } - return -EIO; + + return ret; } @@ -639,6 +1948,244 @@ { } /* Terminating entry */ }; +static int +ultracam_CompressIsochronous(struct uvd *uvd, struct urb *urb) +{ + char *cdata; + int i, totlen = 0; + + for (i = 0; i < urb->number_of_packets; i++) + { + int n = urb->iso_frame_desc[i].actual_length; + int st = urb->iso_frame_desc[i].status; + + cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset; + + /* + * Detect and ignore errored packets + */ + if (st < 0) + { + if (uvd->debug >= 2) + err("Data error: packet=%d. len=%d. status=%d.", i, n, st); + uvd->stats.iso_err_count++; + continue; + } + + /* + * Detect and ignore empty packets + */ + if (n <= 0) + { + uvd->stats.iso_skip_count++; + continue; + } + totlen += n; /* Little local accounting */ + RingQueue_Enqueue(&uvd->dp, cdata, n); + } + return totlen; +} + +static void +ultracam_IsocIrq(struct urb *urb) +{ + int i, ret, len; + struct uvd *uvd = urb->context; + + /* + * We don't want to do anything if we are about to be removed! + */ + if (!CAMERA_IS_OPERATIONAL(uvd)) + return; +#if 0 + if (urb->actual_length > 0) + { + info("urb=$%p status=%d. errcount=%d. length=%d.", + urb, urb->status, urb->error_count, urb->actual_length); + } + else + { + static int c = 0; + if (c++ % 100 == 0) + info("No Isoc data. (urb=$%p status=%d. errcount=%d. length=%d).", + urb, urb->status, urb->error_count, urb->actual_length); + } +#endif + + if (!uvd->streaming) + { + if (uvd->debug >= 1) + info("Not streaming, but interrupt!"); + return; + } + + uvd->stats.urb_count++; + if (urb->actual_length <= 0) + { + if (uvd->debug >= 2) + info("%s: urb->actual_length = %d", + __FUNCTION__, urb->actual_length); + goto urb_done_with; + } + + /* + * Copy the data received into ring queue + */ + len = ultracam_CompressIsochronous(uvd, urb); + uvd->stats.urb_length = len; + if (len <= 0) + { + if (uvd->debug >= 1) + info("%s: len = %d", __FUNCTION__, len); + goto urb_done_with; + } + + /* + * Here we got some data + */ + uvd->stats.data_count += len; + RingQueue_WakeUpInterruptible(&uvd->dp); + + urb_done_with: + for (i = 0; i < FRAMES_PER_DESC; i++) + { + urb->iso_frame_desc[i].status = 0; + urb->iso_frame_desc[i].actual_length = 0; + } + urb->status = 0; + urb->dev = uvd->dev; + ret = usb_submit_urb(urb, GFP_KERNEL); + if (uvd->debug >= 2) + if (ret) + err("usb_submit_urb error (%d)", ret); + return; +} + +static int +ultracam_StartDataPump(struct uvd *uvd) +{ + struct usb_device *dev = uvd->dev; + int i, errFlag; + + if (!CAMERA_IS_OPERATIONAL(uvd)) + { + err("%s: Camera is not operational", __FUNCTION__); + return -EFAULT; + } + uvd->curframe = -1; + + /* + * Alternate interface 1 is is the biggest frame size + */ + if (uvd->debug >= 3) + dbg("%s($%p): enabling data transfers on interfaces %d", + __FUNCTION__, uvd, uvd->ifaceAltActive); + i = usb_set_interface(dev, uvd->iface, uvd->ifaceAltActive); + if (i < 0) + { + err("%s: usb_set_interface error: returned %d", __FUNCTION__, i); + uvd->last_error = i; + return -EBUSY; + } + if (VALID_CALLBACK(uvd, videoStart)) + GET_CALLBACK(uvd, videoStart) (uvd); + else + err("%s: videoStart not set", __FUNCTION__); + + /* + * We double buffer the Iso lists + */ + for (i = 0; i < USBVIDEO_NUMSBUF; ++i) + { + int j, k; + struct urb *urb = uvd->sbuf[i].urb; + urb->dev = dev; + urb->context = uvd; + urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp); + urb->interval = 2; + urb->transfer_flags = URB_ISO_ASAP; + urb->transfer_buffer = uvd->sbuf[i].data; + urb->complete = ultracam_IsocIrq; + urb->number_of_packets = FRAMES_PER_DESC; + urb->transfer_buffer_length = uvd->iso_packet_len * FRAMES_PER_DESC; + for (j = k = 0; j < FRAMES_PER_DESC; ++j, k += uvd->iso_packet_len) + { + urb->iso_frame_desc[j].offset = k; + urb->iso_frame_desc[j].length = uvd->iso_packet_len; + } + } + + /* + * Submit all URBs + */ + for (i = 0; i < USBVIDEO_NUMSBUF; ++i) + { + errFlag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL); + if (errFlag) + err("%s: usb_submit_urb(%d) ret %d", __FUNCTION__, i, errFlag); + } + + uvd->streaming = 1; + if (uvd->debug >= 2) + info("%s: streaming = %d, video_endp = $%02x", + __FUNCTION__, uvd->streaming, uvd->video_endp); + return errFlag; +} + +/* + * usbvideo_StopDataPump() + * + * This procedure stops streaming and deallocates URBs. Then it + * activates zero-bandwidth alt. setting of the video interface. + * + * History: + * 22-Jan-2000 Corrected order of actions to work after surprise removal. + * 27-Jan-2000 Used uvd->iface, uvd->ifaceAltInactive instead of hardcoded values. + */ +static void +ultracam_StopDataPump(struct uvd *uvd) +{ + int i, j; + + if (uvd->debug >= 2) + info("%s($%p)", __FUNCTION__, uvd); + + if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL)) + return; + + /* + * Unschedule all of the iso td's + */ + for (i = 0; i < USBVIDEO_NUMSBUF; i++) + { + usb_kill_urb(uvd->sbuf[i].urb); + } + if (uvd->debug >= 2) + info("%s: streaming=0", __FUNCTION__); + uvd->streaming = 0; + + if (!uvd->remove_pending) + { + /* + * Invoke minidriver's magic to stop the camera + */ + if (VALID_CALLBACK(uvd, videoStop)) + GET_CALLBACK(uvd, videoStop) (uvd); + else + err("%s: videoStop not set", __FUNCTION__); + + /* + * Set packet size to 0 + */ + j = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltInactive); + if (j < 0) + { + err("%s: usb_set_interface() error %d.", __FUNCTION__, j); + uvd->last_error = j; + } + } +} + /* * ultracam_init() * @@ -653,20 +2200,19 @@ cbTbl.videoStart = ultracam_video_start; cbTbl.videoStop = ultracam_video_stop; cbTbl.processData = ultracam_ProcessIsocData; - cbTbl.postProcess = usbvideo_DeinterlaceFrame; + cbTbl.postProcess = ultracam_postProcess; cbTbl.adjustPicture = ultracam_adjust_picture; cbTbl.getFPS = ultracam_calculate_fps; - return usbvideo_register( - &cams, + cbTbl.startDataPump = ultracam_StartDataPump; + cbTbl.stopDataPump = ultracam_StopDataPump; + return usbvideo_register(&cams, MAX_CAMERAS, sizeof(ultracam_t), - "ultracam", - &cbTbl, - THIS_MODULE, - id_table); + "ultracam", &cbTbl, THIS_MODULE, id_table); } -static void __exit ultracam_cleanup(void) +static void __exit +ultracam_cleanup(void) { usbvideo_Deregister(&cams); }
signature.asc
(application/pgp-signature, 189 B)
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) iD8DBQBGv0ydOUZy7Ywnge4RApWDAKCierqRL+545XB6blwM9NvZ0acjAwCbBV0B 2kLZLWmVvYlNix8Y7acn6JE= =X2lV -----END PGP SIGNATURE-----