<row id="v4l2-colorfx">
<entry><constant>V4L2_CID_COLORFX</constant></entry>
<entry>enum</entry>
- <entry>Selects a color effect. Possible values for
- <constant>enum v4l2_colorfx</constant> are:
- <constant>V4L2_COLORFX_NONE</constant> (0),
- <constant>V4L2_COLORFX_BW</constant> (1),
- <constant>V4L2_COLORFX_SEPIA</constant> (2),
- <constant>V4L2_COLORFX_NEGATIVE</constant> (3),
- <constant>V4L2_COLORFX_EMBOSS</constant> (4),
- <constant>V4L2_COLORFX_SKETCH</constant> (5),
- <constant>V4L2_COLORFX_SKY_BLUE</constant> (6),
- <constant>V4L2_COLORFX_GRASS_GREEN</constant> (7),
- <constant>V4L2_COLORFX_SKIN_WHITEN</constant> (8) and
- <constant>V4L2_COLORFX_VIVID</constant> (9).</entry>
+ <entry>Selects a color effect. The following values are defined:
+ </entry>
+ </row><row>
+ <entry></entry>
+ <entry></entry>
+ <entrytbl spanname="descr" cols="2">
+ <tbody valign="top">
+ <row>
+ <entry><constant>V4L2_COLORFX_NONE</constant> </entry>
+ <entry>Color effect is disabled.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_COLORFX_ANTIQUE</constant> </entry>
+ <entry>An aging (old photo) effect.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_COLORFX_ART_FREEZE</constant> </entry>
+ <entry>Frost color effect.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_COLORFX_AQUA</constant> </entry>
+ <entry>Water color, cool tone.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_COLORFX_BW</constant> </entry>
+ <entry>Black and white.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_COLORFX_EMBOSS</constant> </entry>
+ <entry>Emboss, the highlights and shadows replace light/dark boundaries
+ and low contrast areas are set to a gray background.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_COLORFX_GRASS_GREEN</constant> </entry>
+ <entry>Grass green.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_COLORFX_NEGATIVE</constant> </entry>
+ <entry>Negative.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_COLORFX_SEPIA</constant> </entry>
+ <entry>Sepia tone.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_COLORFX_SKETCH</constant> </entry>
+ <entry>Sketch.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_COLORFX_SKIN_WHITEN</constant> </entry>
+ <entry>Skin whiten.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_COLORFX_SKY_BLUE</constant> </entry>
+ <entry>Sky blue.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_COLORFX_SOLARIZATION</constant> </entry>
+ <entry>Solarization, the image is partially reversed in tone,
+ only color values above or below a certain threshold are inverted.
+ </entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_COLORFX_SILHOUETTE</constant> </entry>
+ <entry>Silhouette (outline).</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_COLORFX_VIVID</constant> </entry>
+ <entry>Vivid colors.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_COLORFX_SET_CBCR</constant> </entry>
+ <entry>The Cb and Cr chroma components are replaced by fixed
+ coefficients determined by <constant>V4L2_CID_COLORFX_CBCR</constant>
+ control.</entry>
+ </row>
+ </tbody>
+ </entrytbl>
+ </row>
+ <row>
+ <entry><constant>V4L2_CID_COLORFX_CBCR</constant></entry>
+ <entry>integer</entry>
+ <entry>Determines the Cb and Cr coefficients for <constant>V4L2_COLORFX_SET_CBCR</constant>
+ color effect. Bits [7:0] of the supplied 32 bit value are interpreted as
+ Cr component, bits [15:8] as Cb component and bits [31:16] must be zero.
+ </entry>
</row>
<row>
<entry><constant>V4L2_CID_ROTATE</constant></entry>
<entry>integer</entry>
</row>
<row><entry spanname="descr">Cyclic intra macroblock refresh. This is the number of continuous macroblocks
-refreshed every frame. Each frame a succesive set of macroblocks is refreshed until the cycle completes and starts from the
+refreshed every frame. Each frame a successive set of macroblocks is refreshed until the cycle completes and starts from the
top of the frame. Applicable to H264, H263 and MPEG4 encoder.</entry>
</row>
<entry>integer</entry>
</row>
<row><entry spanname="descr">The Video Buffer Verifier size in kilobytes, it is used as a limitation of frame skip.
-The VBV is defined in the standard as a mean to verify that the produced stream will be succesfully decoded.
+The VBV is defined in the standard as a mean to verify that the produced stream will be successfully decoded.
The standard describes it as "Part of a hypothetical decoder that is conceptually connected to the
output of the encoder. Its purpose is to provide a constraint on the variability of the data rate that an
encoder or editing process may produce.".
<entry>integer</entry>
</row>
<row><entry spanname="descr">The Coded Picture Buffer size in kilobytes, it is used as a limitation of frame skip.
-The CPB is defined in the H264 standard as a mean to verify that the produced stream will be succesfully decoded.
+The CPB is defined in the H264 standard as a mean to verify that the produced stream will be successfully decoded.
Applicable to the H264 encoder.</entry>
</row>
</row>
<row><entry></entry></row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_EXPOSURE_BIAS</constant> </entry>
+ <entry>integer menu</entry>
+ </row><row><entry spanname="descr"> Determines the automatic
+ exposure compensation, it is effective only when <constant>V4L2_CID_EXPOSURE_AUTO</constant>
+ control is set to <constant>AUTO</constant>, <constant>SHUTTER_PRIORITY </constant>
+ or <constant>APERTURE_PRIORITY</constant>.
+ It is expressed in terms of EV, drivers should interpret the values as 0.001 EV
+ units, where the value 1000 stands for +1 EV.
+ <para>Increasing the exposure compensation value is equivalent to decreasing
+ the exposure value (EV) and will increase the amount of light at the image
+ sensor. The camera performs the exposure compensation by adjusting absolute
+ exposure time and/or aperture.</para></entry>
+ </row>
+ <row><entry></entry></row>
+
+ <row id="v4l2-exposure-metering">
+ <entry spanname="id"><constant>V4L2_CID_EXPOSURE_METERING</constant> </entry>
+ <entry>enum v4l2_exposure_metering</entry>
+ </row><row><entry spanname="descr">Determines how the camera measures
+ the amount of light available for the frame exposure. Possible values are:</entry>
+ </row>
+ <row>
+ <entrytbl spanname="descr" cols="2">
+ <tbody valign="top">
+ <row>
+ <entry><constant>V4L2_EXPOSURE_METERING_AVERAGE</constant> </entry>
+ <entry>Use the light information coming from the entire frame
+ and average giving no weighting to any particular portion of the metered area.
+ </entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_EXPOSURE_METERING_CENTER_WEIGHTED</constant> </entry>
+ <entry>Average the light information coming from the entire frame
+ giving priority to the center of the metered area.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_EXPOSURE_METERING_SPOT</constant> </entry>
+ <entry>Measure only very small area at the center of the frame.</entry>
+ </row>
+ </tbody>
+ </entrytbl>
+ </row>
+ <row><entry></entry></row>
+
<row>
<entry spanname="id"><constant>V4L2_CID_PAN_RELATIVE</constant> </entry>
<entry>integer</entry>
<row>
<entry spanname="id"><constant>V4L2_CID_FOCUS_AUTO</constant> </entry>
<entry>boolean</entry>
- </row><row><entry spanname="descr">Enables automatic focus
- adjustments. The effect of manual focus adjustments while this feature
+ </row><row><entry spanname="descr">Enables continuous automatic
+ focus adjustments. The effect of manual focus adjustments while this feature
is enabled is undefined, drivers should ignore such requests.</entry>
</row>
<row><entry></entry></row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_AUTO_FOCUS_START</constant> </entry>
+ <entry>button</entry>
+ </row><row><entry spanname="descr">Starts single auto focus process.
+ The effect of setting this control when <constant>V4L2_CID_FOCUS_AUTO</constant>
+ is set to <constant>TRUE</constant> (1) is undefined, drivers should ignore
+ such requests.</entry>
+ </row>
+ <row><entry></entry></row>
+
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_AUTO_FOCUS_STOP</constant> </entry>
+ <entry>button</entry>
+ </row><row><entry spanname="descr">Aborts automatic focusing
+ started with <constant>V4L2_CID_AUTO_FOCUS_START</constant> control. It is
+ effective only when the continuous autofocus is disabled, that is when
+ <constant>V4L2_CID_FOCUS_AUTO</constant> control is set to <constant>FALSE
+ </constant> (0).</entry>
+ </row>
+ <row><entry></entry></row>
+
+ <row id="v4l2-auto-focus-status">
+ <entry spanname="id">
+ <constant>V4L2_CID_AUTO_FOCUS_STATUS</constant> </entry>
+ <entry>bitmask</entry>
+ </row>
+ <row><entry spanname="descr">The automatic focus status. This is a read-only
+ control.</entry>
+ </row>
+ <row>
+ <entrytbl spanname="descr" cols="2">
+ <tbody valign="top">
+ <row>
+ <entry><constant>V4L2_AUTO_FOCUS_STATUS_IDLE</constant> </entry>
+ <entry>Automatic focus is not active.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_AUTO_FOCUS_STATUS_BUSY</constant> </entry>
+ <entry>Automatic focusing is in progress.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_AUTO_FOCUS_STATUS_REACHED</constant> </entry>
+ <entry>Focus has been reached.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_AUTO_FOCUS_STATUS_FAILED</constant> </entry>
+ <entry>Automatic focus has failed, the driver will not
+ transition from this state until another action is
+ performed by an application.</entry>
+ </row>
+ </tbody>
+ </entrytbl>
+ </row>
+ <row><entry spanname="descr">
+ Setting <constant>V4L2_LOCK_FOCUS</constant> lock bit of the <constant>V4L2_CID_3A_LOCK
+ </constant> control may stop updates of the <constant>V4L2_CID_AUTO_FOCUS_STATUS</constant>
+ control value.</entry>
+ </row>
+ <row><entry></entry></row>
+
+ <row id="v4l2-auto-focus-range">
+ <entry spanname="id">
+ <constant>V4L2_CID_AUTO_FOCUS_RANGE</constant> </entry>
+ <entry>enum v4l2_auto_focus_range</entry>
+ </row>
+ <row><entry spanname="descr">Determines auto focus distance range
+ for which lens may be adjusted. </entry>
+ </row>
+ <row>
+ <entrytbl spanname="descr" cols="2">
+ <tbody valign="top">
+ <row>
+ <entry><constant>V4L2_AUTO_FOCUS_RANGE_AUTO</constant> </entry>
+ <entry>The camera automatically selects the focus range.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_AUTO_FOCUS_RANGE_NORMAL</constant> </entry>
+ <entry>Normal distance range, limited for best automatic focus
+ performance.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_AUTO_FOCUS_RANGE_MACRO</constant> </entry>
+ <entry>Macro (close-up) auto focus. The camera will
+ use its minimum possible distance for auto focus.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_AUTO_FOCUS_RANGE_INFINITY</constant> </entry>
+ <entry>The lens is set to focus on an object at infinite distance.</entry>
+ </row>
+ </tbody>
+ </entrytbl>
+ </row>
+ <row><entry></entry></row>
+
<row>
<entry spanname="id"><constant>V4L2_CID_ZOOM_ABSOLUTE</constant> </entry>
<entry>integer</entry>
be used, for example, to filter out the fluorescent light component.</entry>
</row>
<row><entry></entry></row>
+
+ <row id="v4l2-auto-n-preset-white-balance">
+ <entry spanname="id"><constant>V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE</constant> </entry>
+ <entry>enum v4l2_auto_n_preset_white_balance</entry>
+ </row><row><entry spanname="descr">Sets white balance to automatic,
+ manual or a preset. The presets determine color temperature of the light as
+ a hint to the camera for white balance adjustments resulting in most accurate
+ color representation. The following white balance presets are listed in order
+ of increasing color temperature.</entry>
+ </row>
+ <row>
+ <entrytbl spanname="descr" cols="2">
+ <tbody valign="top">
+ <row>
+ <entry><constant>V4L2_WHITE_BALANCE_MANUAL</constant> </entry>
+ <entry>Manual white balance.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_WHITE_BALANCE_AUTO</constant> </entry>
+ <entry>Automatic white balance adjustments.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_WHITE_BALANCE_INCANDESCENT</constant> </entry>
+ <entry>White balance setting for incandescent (tungsten) lighting.
+ It generally cools down the colors and corresponds approximately to 2500...3500 K
+ color temperature range.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_WHITE_BALANCE_FLUORESCENT</constant> </entry>
+ <entry>White balance preset for fluorescent lighting.
+ It corresponds approximately to 4000...5000 K color temperature.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_WHITE_BALANCE_FLUORESCENT_H</constant> </entry>
+ <entry>With this setting the camera will compensate for
+ fluorescent H lighting.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_WHITE_BALANCE_HORIZON</constant> </entry>
+ <entry>White balance setting for horizon daylight.
+ It corresponds approximately to 5000 K color temperature.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_WHITE_BALANCE_DAYLIGHT</constant> </entry>
+ <entry>White balance preset for daylight (with clear sky).
+ It corresponds approximately to 5000...6500 K color temperature.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_WHITE_BALANCE_FLASH</constant> </entry>
+ <entry>With this setting the camera will compensate for the flash
+ light. It slightly warms up the colors and corresponds roughly to 5000...5500 K
+ color temperature.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_WHITE_BALANCE_CLOUDY</constant> </entry>
+ <entry>White balance preset for moderately overcast sky.
+ This option corresponds approximately to 6500...8000 K color temperature
+ range.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_WHITE_BALANCE_SHADE</constant> </entry>
+ <entry>White balance preset for shade or heavily overcast
+ sky. It corresponds approximately to 9000...10000 K color temperature.
+ </entry>
+ </row>
+ </tbody>
+ </entrytbl>
+ </row>
+ <row><entry></entry></row>
+
+ <row id="v4l2-wide-dynamic-range">
+ <entry spanname="id"><constant>V4L2_CID_WIDE_DYNAMIC_RANGE</constant></entry>
+ <entry>boolean</entry>
+ </row>
+ <row>
+ <entry spanname="descr">Enables or disables the camera's wide dynamic
+ range feature. This feature allows to obtain clear images in situations where
+ intensity of the illumination varies significantly throughout the scene, i.e.
+ there are simultaneously very dark and very bright areas. It is most commonly
+ realized in cameras by combining two subsequent frames with different exposure
+ times. <footnote id="ctypeconv"><para> This control may be changed to a menu
+ control in the future, if more options are required.</para></footnote></entry>
+ </row>
+ <row><entry></entry></row>
+
+ <row id="v4l2-image-stabilization">
+ <entry spanname="id"><constant>V4L2_CID_IMAGE_STABILIZATION</constant></entry>
+ <entry>boolean</entry>
+ </row>
+ <row>
+ <entry spanname="descr">Enables or disables image stabilization.
+ <footnoteref linkend="ctypeconv"/></entry>
+ </row>
+ <row><entry></entry></row>
+
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_ISO_SENSITIVITY</constant> </entry>
+ <entry>integer menu</entry>
+ </row><row><entry spanname="descr">Determines ISO equivalent of an
+ image sensor indicating the sensor's sensitivity to light. The numbers are
+ expressed in arithmetic scale, as per <xref linkend="iso12232" /> standard,
+ where doubling the sensor sensitivity is represented by doubling the numerical
+ ISO value. Applications should interpret the values as standard ISO values
+ multiplied by 1000, e.g. control value 800 stands for ISO 0.8. Drivers will
+ usually support only a subset of standard ISO values. The effect of setting
+ this control while the <constant>V4L2_CID_ISO_SENSITIVITY_AUTO</constant>
+ control is set to a value other than <constant>V4L2_CID_ISO_SENSITIVITY_MANUAL
+ </constant> is undefined, drivers should ignore such requests.</entry>
+ </row>
+ <row><entry></entry></row>
+
+ <row id="v4l2-iso-sensitivity-auto-type">
+ <entry spanname="id"><constant>V4L2_CID_ISO_SENSITIVITY_AUTO</constant> </entry>
+ <entry>enum v4l2_iso_sensitivity_type</entry>
+ </row><row><entry spanname="descr">Enables or disables automatic ISO
+ sensitivity adjustments.</entry>
+ </row>
+ <row>
+ <entrytbl spanname="descr" cols="2">
+ <tbody valign="top">
+ <row>
+ <entry><constant>V4L2_CID_ISO_SENSITIVITY_MANUAL</constant> </entry>
+ <entry>Manual ISO sensitivity.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_CID_ISO_SENSITIVITY_AUTO</constant> </entry>
+ <entry>Automatic ISO sensitivity adjustments.</entry>
+ </row>
+ </tbody>
+ </entrytbl>
+ </row>
+ <row><entry></entry></row>
+
+ <row id="v4l2-scene-mode">
+ <entry spanname="id"><constant>V4L2_CID_SCENE_MODE</constant> </entry>
+ <entry>enum v4l2_scene_mode</entry>
+ </row><row><entry spanname="descr">This control allows to select
+ scene programs as the camera automatic modes optimized for common shooting
+ scenes. Within these modes the camera determines best exposure, aperture,
+ focusing, light metering, white balance and equivalent sensitivity. The
+ controls of those parameters are influenced by the scene mode control.
+ An exact behavior in each mode is subject to the camera specification.
+
+ <para>When the scene mode feature is not used, this control should be set to
+ <constant>V4L2_SCENE_MODE_NONE</constant> to make sure the other possibly
+ related controls are accessible. The following scene programs are defined:
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entrytbl spanname="descr" cols="2">
+ <tbody valign="top">
+ <row>
+ <entry><constant>V4L2_SCENE_MODE_NONE</constant> </entry>
+ <entry>The scene mode feature is disabled.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_SCENE_MODE_BACKLIGHT</constant> </entry>
+ <entry>Backlight. Compensates for dark shadows when light is
+ coming from behind a subject, also by automatically turning
+ on the flash.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_SCENE_MODE_BEACH_SNOW</constant> </entry>
+ <entry>Beach and snow. This mode compensates for all-white or
+ bright scenes, which tend to look gray and low contrast, when camera's automatic
+ exposure is based on an average scene brightness. To compensate, this mode
+ automatically slightly overexposes the frames. The white balance may also be
+ adjusted to compensate for the fact that reflected snow looks bluish rather
+ than white.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_SCENE_MODE_CANDLELIGHT</constant> </entry>
+ <entry>Candle light. The camera generally raises the ISO
+ sensitivity and lowers the shutter speed. This mode compensates for relatively
+ close subject in the scene. The flash is disabled in order to preserve the
+ ambiance of the light.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_SCENE_MODE_DAWN_DUSK</constant> </entry>
+ <entry>Dawn and dusk. Preserves the colors seen in low
+ natural light before dusk and after down. The camera may turn off the flash,
+ and automatically focus at infinity. It will usually boost saturation and
+ lower the shutter speed.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_SCENE_MODE_FALL_COLORS</constant> </entry>
+ <entry>Fall colors. Increases saturation and adjusts white
+ balance for color enhancement. Pictures of autumn leaves get saturated reds
+ and yellows.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_SCENE_MODE_FIREWORKS</constant> </entry>
+ <entry>Fireworks. Long exposure times are used to capture
+ the expanding burst of light from a firework. The camera may invoke image
+ stabilization.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_SCENE_MODE_LANDSCAPE</constant> </entry>
+ <entry>Landscape. The camera may choose a small aperture to
+ provide deep depth of field and long exposure duration to help capture detail
+ in dim light conditions. The focus is fixed at infinity. Suitable for distant
+ and wide scenery.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_SCENE_MODE_NIGHT</constant> </entry>
+ <entry>Night, also known as Night Landscape. Designed for low
+ light conditions, it preserves detail in the dark areas without blowing out bright
+ objects. The camera generally sets itself to a medium-to-high ISO sensitivity,
+ with a relatively long exposure time, and turns flash off. As such, there will be
+ increased image noise and the possibility of blurred image.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_SCENE_MODE_PARTY_INDOOR</constant> </entry>
+ <entry>Party and indoor. Designed to capture indoor scenes
+ that are lit by indoor background lighting as well as the flash. The camera
+ usually increases ISO sensitivity, and adjusts exposure for the low light
+ conditions.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_SCENE_MODE_PORTRAIT</constant> </entry>
+ <entry>Portrait. The camera adjusts the aperture so that the
+ depth of field is reduced, which helps to isolate the subject against a smooth
+ background. Most cameras recognize the presence of faces in the scene and focus
+ on them. The color hue is adjusted to enhance skin tones. The intensity of the
+ flash is often reduced.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_SCENE_MODE_SPORTS</constant> </entry>
+ <entry>Sports. Significantly increases ISO and uses a fast
+ shutter speed to freeze motion of rapidly-moving subjects. Increased image
+ noise may be seen in this mode.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_SCENE_MODE_SUNSET</constant> </entry>
+ <entry>Sunset. Preserves deep hues seen in sunsets and
+ sunrises. It bumps up the saturation.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_SCENE_MODE_TEXT</constant> </entry>
+ <entry>Text. It applies extra contrast and sharpness, it is
+ typically a black-and-white mode optimized for readability. Automatic focus
+ may be switched to close-up mode and this setting may also involve some
+ lens-distortion correction.</entry>
+ </row>
+ </tbody>
+ </entrytbl>
+ </row>
+ <row><entry></entry></row>
+
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_3A_LOCK</constant></entry>
+ <entry>bitmask</entry>
+ </row>
+ <row>
+ <entry spanname="descr">This control locks or unlocks the automatic
+ focus, exposure and white balance. The automatic adjustments can be paused
+ independently by setting the corresponding lock bit to 1. The camera then retains
+ the settings until the lock bit is cleared. The following lock bits are defined:
+ </entry>
+ </row>
+ <row>
+ <entrytbl spanname="descr" cols="2">
+ <tbody valign="top">
+ <row>
+ <entry><constant>V4L2_LOCK_EXPOSURE</constant></entry>
+ <entry>Automatic exposure adjustments lock.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_LOCK_WHITE_BALANCE</constant></entry>
+ <entry>Automatic white balance adjustments lock.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_LOCK_FOCUS</constant></entry>
+ <entry>Automatic focus lock.</entry>
+ </row>
+ </tbody>
+ </entrytbl>
+ </row>
+ <row><entry spanname="descr">
+ When a given algorithm is not enabled, drivers should ignore requests
+ to lock it and should return no error. An example might be an application
+ setting bit <constant>V4L2_LOCK_WHITE_BALANCE</constant> when the
+ <constant>V4L2_CID_AUTO_WHITE_BALANCE</constant> control is set to
+ <constant>FALSE</constant>. The value of this control may be changed
+ by exposure, white balance or focus controls.</entry>
+ </row>
+ <row><entry></entry></row>
+
</tbody>
</tgroup>
</table>
<entry spanname="id"><constant>V4L2_CID_JPEG_CHROMA_SUBSAMPLING</constant></entry>
<entry>menu</entry>
</row>
- <row id="jpeg-chroma-subsampling-control">
+ <row id="v4l2-jpeg-chroma-subsampling">
<entry spanname="descr">The chroma subsampling factors describe how
each component of an input image is sampled, in respect to maximum
sample rate in each spatial dimension. See <xref linkend="itu-t81"/>,
from RGB to Y'CbCr color space.
</entry>
</row>
- <row>
+ <row id = "v4l2-jpeg-chroma-subsampling">
<entrytbl spanname="descr" cols="2">
<tbody valign="top">
<row>
</entry>
</row>
<row id="jpeg-quality-control">
- <entry spanname="id"><constant>V4L2_CID_JPEG_COMPRESION_QUALITY</constant></entry>
+ <entry spanname="id"><constant>V4L2_CID_JPEG_COMPRESSION_QUALITY</constant></entry>
<entry>integer</entry>
</row>
<row>
<entry spanname="descr">
- <constant>V4L2_CID_JPEG_COMPRESION_QUALITY</constant> control
+ <constant>V4L2_CID_JPEG_COMPRESSION_QUALITY</constant> control
determines trade-off between image quality and size.
It provides simpler method for applications to control image quality,
without a need for direct reconfiguration of luminance and chrominance
In cases where a driver uses quantization tables configured directly
by an application, using interfaces defined elsewhere, <constant>
- V4L2_CID_JPEG_COMPRESION_QUALITY</constant> control should be set
+ V4L2_CID_JPEG_COMPRESSION_QUALITY</constant> control should be set
by driver to 0.
<para>The value range of this control is driver-specific. Only
to <xref linkend="itu-t81"/>, <xref linkend="jfif"/>,
<xref linkend="w3c-jpeg-jfif"/>.</para>
</section>
+
+ <section id="image-source-controls">
+ <title>Image Source Control Reference</title>
+
+ <note>
+ <title>Experimental</title>
+
+ <para>This is an <link
+ linkend="experimental">experimental</link> interface and may
+ change in the future.</para>
+ </note>
+
+ <para>
+ The Image Source control class is intended for low-level
+ control of image source devices such as image sensors. The
+ devices feature an analogue to digital converter and a bus
+ transmitter to transmit the image data out of the device.
+ </para>
+
+ <table pgwide="1" frame="none" id="image-source-control-id">
+ <title>Image Source Control IDs</title>
+
+ <tgroup cols="4">
+ <colspec colname="c1" colwidth="1*" />
+ <colspec colname="c2" colwidth="6*" />
+ <colspec colname="c3" colwidth="2*" />
+ <colspec colname="c4" colwidth="6*" />
+ <spanspec namest="c1" nameend="c2" spanname="id" />
+ <spanspec namest="c2" nameend="c4" spanname="descr" />
+ <thead>
+ <row>
+ <entry spanname="id" align="left">ID</entry>
+ <entry align="left">Type</entry>
+ </row><row rowsep="1"><entry spanname="descr" align="left">Description</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row><entry></entry></row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_IMAGE_SOURCE_CLASS</constant></entry>
+ <entry>class</entry>
+ </row>
+ <row>
+ <entry spanname="descr">The IMAGE_SOURCE class descriptor.</entry>
+ </row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_VBLANK</constant></entry>
+ <entry>integer</entry>
+ </row>
+ <row>
+ <entry spanname="descr">Vertical blanking. The idle period
+ after every frame during which no image data is produced.
+ The unit of vertical blanking is a line. Every line has
+ length of the image width plus horizontal blanking at the
+ pixel rate defined by
+ <constant>V4L2_CID_PIXEL_RATE</constant> control in the
+ same sub-device.</entry>
+ </row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_HBLANK</constant></entry>
+ <entry>integer</entry>
+ </row>
+ <row>
+ <entry spanname="descr">Horizontal blanking. The idle
+ period after every line of image data during which no
+ image data is produced. The unit of horizontal blanking is
+ pixels.</entry>
+ </row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_ANALOGUE_GAIN</constant></entry>
+ <entry>integer</entry>
+ </row>
+ <row>
+ <entry spanname="descr">Analogue gain is gain affecting
+ all colour components in the pixel matrix. The gain
+ operation is performed in the analogue domain before A/D
+ conversion.
+ </entry>
+ </row>
+ <row><entry></entry></row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ </section>
+
+ <section id="image-process-controls">
+ <title>Image Process Control Reference</title>
+
+ <note>
+ <title>Experimental</title>
+
+ <para>This is an <link
+ linkend="experimental">experimental</link> interface and may
+ change in the future.</para>
+ </note>
+
+ <para>
+ The Image Source control class is intended for low-level control of
+ image processing functions. Unlike
+ <constant>V4L2_CID_IMAGE_SOURCE_CLASS</constant>, the controls in
+ this class affect processing the image, and do not control capturing
+ of it.
+ </para>
+
+ <table pgwide="1" frame="none" id="image-process-control-id">
+ <title>Image Source Control IDs</title>
+
+ <tgroup cols="4">
+ <colspec colname="c1" colwidth="1*" />
+ <colspec colname="c2" colwidth="6*" />
+ <colspec colname="c3" colwidth="2*" />
+ <colspec colname="c4" colwidth="6*" />
+ <spanspec namest="c1" nameend="c2" spanname="id" />
+ <spanspec namest="c2" nameend="c4" spanname="descr" />
+ <thead>
+ <row>
+ <entry spanname="id" align="left">ID</entry>
+ <entry align="left">Type</entry>
+ </row><row rowsep="1"><entry spanname="descr" align="left">Description</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row><entry></entry></row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_IMAGE_PROC_CLASS</constant></entry>
+ <entry>class</entry>
+ </row>
+ <row>
+ <entry spanname="descr">The IMAGE_PROC class descriptor.</entry>
+ </row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_LINK_FREQ</constant></entry>
+ <entry>integer menu</entry>
+ </row>
+ <row>
+ <entry spanname="descr">Data bus frequency. Together with the
+ media bus pixel code, bus type (clock cycles per sample), the
+ data bus frequency defines the pixel rate
+ (<constant>V4L2_CID_PIXEL_RATE</constant>) in the
+ pixel array (or possibly elsewhere, if the device is not an
+ image sensor). The frame rate can be calculated from the pixel
+ clock, image width and height and horizontal and vertical
+ blanking. While the pixel rate control may be defined elsewhere
+ than in the subdev containing the pixel array, the frame rate
+ cannot be obtained from that information. This is because only
+ on the pixel array it can be assumed that the vertical and
+ horizontal blanking information is exact: no other blanking is
+ allowed in the pixel array. The selection of frame rate is
+ performed by selecting the desired horizontal and vertical
+ blanking. The unit of this control is Hz. </entry>
+ </row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_PIXEL_RATE</constant></entry>
+ <entry>64-bit integer</entry>
+ </row>
+ <row>
+ <entry spanname="descr">Pixel rate in the source pads of
+ the subdev. This control is read-only and its unit is
+ pixels / second.
+ </entry>
+ </row>
+ <row><entry></entry></row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ </section>
</section>
JOM(4, "ending successfully\n");
return 0;
}
- /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
- /*****************************************************************************/
- /*--------------------------------------------------------------------------*/
- /*
- * THIS FUNCTION IS CALLED FROM WITHIN easycap_usb_disconnect() AND IS
- * PROTECTED BY SEMAPHORES SET AND CLEARED BY easycap_usb_disconnect().
- *
- * BY THIS STAGE THE DEVICE HAS ALREADY BEEN PHYSICALLY UNPLUGGED, SO
- * peasycap->pusb_device IS NO LONGER VALID.
- */
- /*---------------------------------------------------------------------------*/
- static void easycap_delete(struct kref *pkref)
- {
- struct easycap *peasycap;
- struct data_urb *pdata_urb;
- struct list_head *plist_head, *plist_next;
- int k, m, gone, kd;
- int allocation_video_urb;
- int allocation_video_page;
- int allocation_video_struct;
- int allocation_audio_urb;
- int allocation_audio_page;
- int allocation_audio_struct;
- int registered_video, registered_audio;
-
- peasycap = container_of(pkref, struct easycap, kref);
- if (!peasycap) {
- SAM("ERROR: peasycap is NULL: cannot perform deletions\n");
- return;
- }
- kd = easycap_isdongle(peasycap);
- /*---------------------------------------------------------------------------*/
- /*
- * FREE VIDEO.
- */
- /*---------------------------------------------------------------------------*/
- if (peasycap->purb_video_head) {
- m = 0;
- list_for_each(plist_head, peasycap->purb_video_head) {
- pdata_urb = list_entry(plist_head,
- struct data_urb, list_head);
- if (pdata_urb && pdata_urb->purb) {
- usb_free_urb(pdata_urb->purb);
- pdata_urb->purb = NULL;
- peasycap->allocation_video_urb--;
- m++;
- }
- }
-
- JOM(4, "%i video urbs freed\n", m);
- /*---------------------------------------------------------------------------*/
- JOM(4, "freeing video data_urb structures.\n");
- m = 0;
- list_for_each_safe(plist_head, plist_next,
- peasycap->purb_video_head) {
- pdata_urb = list_entry(plist_head,
- struct data_urb, list_head);
- if (pdata_urb) {
- peasycap->allocation_video_struct -=
- sizeof(struct data_urb);
- kfree(pdata_urb);
- m++;
- }
- }
- JOM(4, "%i video data_urb structures freed\n", m);
- JOM(4, "setting peasycap->purb_video_head=NULL\n");
- peasycap->purb_video_head = NULL;
- }
- /*---------------------------------------------------------------------------*/
- JOM(4, "freeing video isoc buffers.\n");
- m = 0;
- for (k = 0; k < VIDEO_ISOC_BUFFER_MANY; k++) {
- if (peasycap->video_isoc_buffer[k].pgo) {
- free_pages((unsigned long)
- peasycap->video_isoc_buffer[k].pgo,
- VIDEO_ISOC_ORDER);
- peasycap->video_isoc_buffer[k].pgo = NULL;
- peasycap->allocation_video_page -=
- BIT(VIDEO_ISOC_ORDER);
- m++;
- }
- }
- JOM(4, "isoc video buffers freed: %i pages\n",
- m * (0x01 << VIDEO_ISOC_ORDER));
- /*---------------------------------------------------------------------------*/
- JOM(4, "freeing video field buffers.\n");
- gone = 0;
- for (k = 0; k < FIELD_BUFFER_MANY; k++) {
- for (m = 0; m < FIELD_BUFFER_SIZE/PAGE_SIZE; m++) {
- if (peasycap->field_buffer[k][m].pgo) {
- free_page((unsigned long)
- peasycap->field_buffer[k][m].pgo);
- peasycap->field_buffer[k][m].pgo = NULL;
- peasycap->allocation_video_page -= 1;
- gone++;
- }
- }
- }
- JOM(4, "video field buffers freed: %i pages\n", gone);
- /*---------------------------------------------------------------------------*/
- JOM(4, "freeing video frame buffers.\n");
- gone = 0;
- for (k = 0; k < FRAME_BUFFER_MANY; k++) {
- for (m = 0; m < FRAME_BUFFER_SIZE/PAGE_SIZE; m++) {
- if (peasycap->frame_buffer[k][m].pgo) {
- free_page((unsigned long)
- peasycap->frame_buffer[k][m].pgo);
- peasycap->frame_buffer[k][m].pgo = NULL;
- peasycap->allocation_video_page -= 1;
- gone++;
- }
- }
- }
- JOM(4, "video frame buffers freed: %i pages\n", gone);
- /*---------------------------------------------------------------------------*/
- /*
- * FREE AUDIO.
- */
- /*---------------------------------------------------------------------------*/
- if (peasycap->purb_audio_head) {
- JOM(4, "freeing audio urbs\n");
- m = 0;
- list_for_each(plist_head, (peasycap->purb_audio_head)) {
- pdata_urb = list_entry(plist_head,
- struct data_urb, list_head);
- if (pdata_urb && pdata_urb->purb) {
- usb_free_urb(pdata_urb->purb);
- pdata_urb->purb = NULL;
- peasycap->allocation_audio_urb--;
- m++;
- }
- }
- JOM(4, "%i audio urbs freed\n", m);
- /*---------------------------------------------------------------------------*/
- JOM(4, "freeing audio data_urb structures.\n");
- m = 0;
- list_for_each_safe(plist_head, plist_next,
- peasycap->purb_audio_head) {
- pdata_urb = list_entry(plist_head,
- struct data_urb, list_head);
- if (pdata_urb) {
- peasycap->allocation_audio_struct -=
- sizeof(struct data_urb);
- kfree(pdata_urb);
- m++;
- }
- }
- JOM(4, "%i audio data_urb structures freed\n", m);
- JOM(4, "setting peasycap->purb_audio_head=NULL\n");
- peasycap->purb_audio_head = NULL;
- }
- /*---------------------------------------------------------------------------*/
- JOM(4, "freeing audio isoc buffers.\n");
- m = 0;
- for (k = 0; k < AUDIO_ISOC_BUFFER_MANY; k++) {
- if (peasycap->audio_isoc_buffer[k].pgo) {
- free_pages((unsigned long)
- (peasycap->audio_isoc_buffer[k].pgo),
- AUDIO_ISOC_ORDER);
- peasycap->audio_isoc_buffer[k].pgo = NULL;
- peasycap->allocation_audio_page -=
- BIT(AUDIO_ISOC_ORDER);
- m++;
- }
- }
- JOM(4, "easyoss_delete(): isoc audio buffers freed: %i pages\n",
- m * (0x01 << AUDIO_ISOC_ORDER));
- /*---------------------------------------------------------------------------*/
- JOM(4, "freeing easycap structure.\n");
- allocation_video_urb = peasycap->allocation_video_urb;
- allocation_video_page = peasycap->allocation_video_page;
- allocation_video_struct = peasycap->allocation_video_struct;
- registered_video = peasycap->registered_video;
- allocation_audio_urb = peasycap->allocation_audio_urb;
- allocation_audio_page = peasycap->allocation_audio_page;
- allocation_audio_struct = peasycap->allocation_audio_struct;
- registered_audio = peasycap->registered_audio;
-
- if (0 <= kd && DONGLE_MANY > kd) {
- if (mutex_lock_interruptible(&mutex_dongle)) {
- SAY("ERROR: cannot down mutex_dongle\n");
- } else {
- JOM(4, "locked mutex_dongle\n");
- easycapdc60_dongle[kd].peasycap = NULL;
- mutex_unlock(&mutex_dongle);
- JOM(4, "unlocked mutex_dongle\n");
- JOT(4, " null-->dongle[%i].peasycap\n", kd);
- allocation_video_struct -= sizeof(struct easycap);
- }
- } else {
- SAY("ERROR: cannot purge dongle[].peasycap");
- }
-
- kfree(peasycap);
-
- /*---------------------------------------------------------------------------*/
- SAY("%8i=video urbs after all deletions\n", allocation_video_urb);
- SAY("%8i=video pages after all deletions\n", allocation_video_page);
- SAY("%8i=video structs after all deletions\n", allocation_video_struct);
- SAY("%8i=video devices after all deletions\n", registered_video);
- SAY("%8i=audio urbs after all deletions\n", allocation_audio_urb);
- SAY("%8i=audio pages after all deletions\n", allocation_audio_page);
- SAY("%8i=audio structs after all deletions\n", allocation_audio_struct);
- SAY("%8i=audio devices after all deletions\n", registered_audio);
- JOT(4, "ending.\n");
- return;
- }
/*****************************************************************************/
static unsigned int easycap_poll(struct file *file, poll_table *wait)
{
return;
}
- static const struct v4l2_file_operations v4l2_fops = {
- .owner = THIS_MODULE,
- .open = easycap_open_noinode,
- .unlocked_ioctl = easycap_unlocked_ioctl,
- .poll = easycap_poll,
- .mmap = easycap_mmap,
- };
-
- /*
- * When the device is plugged, this function is called three times,
- * one for each interface.
- */
- static int easycap_usb_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
+ static struct easycap *alloc_easycap(u8 bInterfaceNumber)
{
- struct usb_device *usbdev;
- struct usb_host_interface *alt;
- struct usb_endpoint_descriptor *ep;
- struct usb_interface_descriptor *interface;
- struct urb *purb;
struct easycap *peasycap;
- int ndong;
- struct data_urb *pdata_urb;
- int i, j, k, m, rc;
- u8 bInterfaceNumber;
- u8 bInterfaceClass;
- u8 bInterfaceSubClass;
- void *pbuf;
- int okalt[8], isokalt;
- int okepn[8];
- int okmps[8];
- int maxpacketsize;
- u16 mask;
- s32 value;
- struct easycap_format *peasycap_format;
- int fmtidx;
- struct inputset *inputset;
+ int i;
- usbdev = interface_to_usbdev(intf);
+ peasycap = kzalloc(sizeof(struct easycap), GFP_KERNEL);
+ if (!peasycap) {
+ SAY("ERROR: Could not allocate peasycap\n");
+ return NULL;
+ }
- alt = usb_altnum_to_altsetting(intf, 0);
- if (!alt) {
- SAY("ERROR: usb_host_interface not found\n");
- return -EFAULT;
+ if (mutex_lock_interruptible(&mutex_dongle)) {
+ SAY("ERROR: cannot lock mutex_dongle\n");
+ kfree(peasycap);
+ return NULL;
}
- interface = &alt->desc;
- if (!interface) {
- SAY("ERROR: intf_descriptor is NULL\n");
- return -EFAULT;
+ /* Find a free dongle in easycapdc60_dongle array */
+ for (i = 0; i < DONGLE_MANY; i++) {
+
+ if ((!easycapdc60_dongle[i].peasycap) &&
+ (!mutex_is_locked(&easycapdc60_dongle[i].mutex_video)) &&
+ (!mutex_is_locked(&easycapdc60_dongle[i].mutex_audio))) {
+
+ easycapdc60_dongle[i].peasycap = peasycap;
+ peasycap->isdongle = i;
+ JOM(8, "intf[%i]: peasycap-->easycap"
+ "_dongle[%i].peasycap\n",
+ bInterfaceNumber, i);
+ break;
+ }
}
- /* Get properties of probed interface */
- bInterfaceNumber = interface->bInterfaceNumber;
- bInterfaceClass = interface->bInterfaceClass;
- bInterfaceSubClass = interface->bInterfaceSubClass;
+ mutex_unlock(&mutex_dongle);
- JOT(4, "intf[%i]: num_altsetting=%i\n",
- bInterfaceNumber, intf->num_altsetting);
- JOT(4, "intf[%i]: cur_altsetting - altsetting=%li\n",
- bInterfaceNumber,
- (long int)(intf->cur_altsetting - intf->altsetting));
- JOT(4, "intf[%i]: bInterfaceClass=0x%02X bInterfaceSubClass=0x%02X\n",
- bInterfaceNumber, bInterfaceClass, bInterfaceSubClass);
+ if (i >= DONGLE_MANY) {
+ SAM("ERROR: too many dongles\n");
+ kfree(peasycap);
+ return NULL;
+ }
- /*
- * A new struct easycap is always allocated when interface 0 is probed.
- * It is not possible here to free any existing struct easycap.
- * This should have been done by easycap_delete() when the device was
- * physically unplugged.
- * The allocated struct easycap is saved for later usage when
- * interfaces 1 and 2 are probed.
- */
- if (0 == bInterfaceNumber) {
- peasycap = kzalloc(sizeof(struct easycap), GFP_KERNEL);
- if (!peasycap) {
- SAY("ERROR: Could not allocate peasycap\n");
- return -ENOMEM;
- }
-
- /* Perform urgent initializations */
- peasycap->minor = -1;
- kref_init(&peasycap->kref);
- JOM(8, "intf[%i]: after kref_init(..._video) "
- "%i=peasycap->kref.refcount.counter\n",
- bInterfaceNumber, peasycap->kref.refcount.counter);
+ return peasycap;
+ }
- /* module params */
- peasycap->gain = (s8)clamp(easycap_gain, 0, 31);
+ static void free_easycap(struct easycap *peasycap)
+ {
+ int allocation_video_urb;
+ int allocation_video_page;
+ int allocation_video_struct;
+ int allocation_audio_urb;
+ int allocation_audio_page;
+ int allocation_audio_struct;
+ int registered_video, registered_audio;
+ int kd;
- init_waitqueue_head(&peasycap->wq_video);
- init_waitqueue_head(&peasycap->wq_audio);
- init_waitqueue_head(&peasycap->wq_trigger);
+ JOM(4, "freeing easycap structure.\n");
+ allocation_video_urb = peasycap->allocation_video_urb;
+ allocation_video_page = peasycap->allocation_video_page;
+ allocation_video_struct = peasycap->allocation_video_struct;
+ registered_video = peasycap->registered_video;
+ allocation_audio_urb = peasycap->allocation_audio_urb;
+ allocation_audio_page = peasycap->allocation_audio_page;
+ allocation_audio_struct = peasycap->allocation_audio_struct;
+ registered_audio = peasycap->registered_audio;
+ kd = easycap_isdongle(peasycap);
+ if (0 <= kd && DONGLE_MANY > kd) {
if (mutex_lock_interruptible(&mutex_dongle)) {
SAY("ERROR: cannot down mutex_dongle\n");
- return -ERESTARTSYS;
+ } else {
+ JOM(4, "locked mutex_dongle\n");
+ easycapdc60_dongle[kd].peasycap = NULL;
+ mutex_unlock(&mutex_dongle);
+ JOM(4, "unlocked mutex_dongle\n");
+ JOT(4, " null-->dongle[%i].peasycap\n", kd);
+ allocation_video_struct -= sizeof(struct easycap);
}
+ } else {
+ SAY("ERROR: cannot purge dongle[].peasycap");
+ }
- for (ndong = 0; ndong < DONGLE_MANY; ndong++) {
- if ((!easycapdc60_dongle[ndong].peasycap) &&
- (!mutex_is_locked(&easycapdc60_dongle
- [ndong].mutex_video)) &&
- (!mutex_is_locked(&easycapdc60_dongle
- [ndong].mutex_audio))) {
- easycapdc60_dongle[ndong].peasycap = peasycap;
- peasycap->isdongle = ndong;
- JOM(8, "intf[%i]: peasycap-->easycap"
- "_dongle[%i].peasycap\n",
- bInterfaceNumber, ndong);
- break;
+ /* Free device structure */
+ kfree(peasycap);
+
+ SAY("%8i=video urbs after all deletions\n", allocation_video_urb);
+ SAY("%8i=video pages after all deletions\n", allocation_video_page);
+ SAY("%8i=video structs after all deletions\n", allocation_video_struct);
+ SAY("%8i=video devices after all deletions\n", registered_video);
+ SAY("%8i=audio urbs after all deletions\n", allocation_audio_urb);
+ SAY("%8i=audio pages after all deletions\n", allocation_audio_page);
+ SAY("%8i=audio structs after all deletions\n", allocation_audio_struct);
+ SAY("%8i=audio devices after all deletions\n", registered_audio);
+ }
+
+ /*
+ * FIXME: Identify the appropriate pointer peasycap for interfaces
+ * 1 and 2. The address of peasycap->pusb_device is reluctantly used
+ * for this purpose.
+ */
+ static struct easycap *get_easycap(struct usb_device *usbdev,
+ u8 bInterfaceNumber)
+ {
+ int i;
+ struct easycap *peasycap;
+
+ for (i = 0; i < DONGLE_MANY; i++) {
+ if (easycapdc60_dongle[i].peasycap->pusb_device == usbdev) {
+ peasycap = easycapdc60_dongle[i].peasycap;
+ JOT(8, "intf[%i]: dongle[%i].peasycap\n",
+ bInterfaceNumber, i);
+ break;
+ }
+ }
+ if (i >= DONGLE_MANY) {
+ SAY("ERROR: peasycap is unknown when probing interface %i\n",
+ bInterfaceNumber);
+ return NULL;
+ }
+ if (!peasycap) {
+ SAY("ERROR: peasycap is NULL when probing interface %i\n",
+ bInterfaceNumber);
+ return NULL;
+ }
+
+ return peasycap;
+ }
+
+ static void init_easycap(struct easycap *peasycap,
+ struct usb_device *usbdev,
+ struct usb_interface *intf,
+ u8 bInterfaceNumber)
+ {
+ /* Save usb_device and usb_interface */
+ peasycap->pusb_device = usbdev;
+ peasycap->pusb_interface = intf;
+
+ peasycap->minor = -1;
+ kref_init(&peasycap->kref);
+ JOM(8, "intf[%i]: after kref_init(..._video) "
+ "%i=peasycap->kref.refcount.counter\n",
+ bInterfaceNumber, peasycap->kref.refcount.counter);
+
+ /* module params */
+ peasycap->gain = (s8)clamp(easycap_gain, 0, 31);
+
+ init_waitqueue_head(&peasycap->wq_video);
+ init_waitqueue_head(&peasycap->wq_audio);
+ init_waitqueue_head(&peasycap->wq_trigger);
+
+ peasycap->allocation_video_struct = sizeof(struct easycap);
+
+ peasycap->microphone = false;
+
+ peasycap->video_interface = -1;
+ peasycap->video_altsetting_on = -1;
+ peasycap->video_altsetting_off = -1;
+ peasycap->video_endpointnumber = -1;
+ peasycap->video_isoc_maxframesize = -1;
+ peasycap->video_isoc_buffer_size = -1;
+
+ peasycap->audio_interface = -1;
+ peasycap->audio_altsetting_on = -1;
+ peasycap->audio_altsetting_off = -1;
+ peasycap->audio_endpointnumber = -1;
+ peasycap->audio_isoc_maxframesize = -1;
+ peasycap->audio_isoc_buffer_size = -1;
+
+ peasycap->frame_buffer_many = FRAME_BUFFER_MANY;
+
+ peasycap->ntsc = easycap_ntsc;
+ JOM(8, "defaulting initially to %s\n",
+ easycap_ntsc ? "NTSC" : "PAL");
+ }
+
+ static int populate_inputset(struct easycap *peasycap)
+ {
+ struct inputset *inputset;
+ struct easycap_format *peasycap_format;
+ struct v4l2_pix_format *pix;
+ int m, i, k, mask, fmtidx;
+ s32 value;
+
+ inputset = peasycap->inputset;
+
+ fmtidx = peasycap->ntsc ? NTSC_M : PAL_BGHIN;
+
+ m = 0;
+ mask = 0;
+ for (i = 0; easycap_standard[i].mask != 0xffff; i++) {
+ if (fmtidx == easycap_standard[i].v4l2_standard.index) {
+ m++;
+ for (k = 0; k < INPUT_MANY; k++)
+ inputset[k].standard_offset = i;
+ mask = easycap_standard[i].mask;
+ }
+ }
+
+ if (m != 1) {
+ SAM("ERROR: inputset->standard_offset unpopulated, %i=m\n", m);
+ return -ENOENT;
+ }
+
+ peasycap_format = &easycap_format[0];
+ m = 0;
+ for (i = 0; peasycap_format->v4l2_format.fmt.pix.width; i++) {
+ pix = &peasycap_format->v4l2_format.fmt.pix;
+ if (((peasycap_format->mask & 0x0F) == (mask & 0x0F))
+ && pix->field == V4L2_FIELD_NONE
+ && pix->pixelformat == V4L2_PIX_FMT_UYVY
+ && pix->width == 640 && pix->height == 480) {
+ m++;
+ for (k = 0; k < INPUT_MANY; k++)
+ inputset[k].format_offset = i;
+ break;
+ }
+ peasycap_format++;
+ }
+ if (m != 1) {
+ SAM("ERROR: inputset[]->format_offset unpopulated\n");
+ return -ENOENT;
+ }
+
+ m = 0;
+ for (i = 0; easycap_control[i].id != 0xffffffff; i++) {
+ value = easycap_control[i].default_value;
+ if (V4L2_CID_BRIGHTNESS == easycap_control[i].id) {
+ m++;
+ for (k = 0; k < INPUT_MANY; k++)
+ inputset[k].brightness = value;
+ } else if (V4L2_CID_CONTRAST == easycap_control[i].id) {
+ m++;
+ for (k = 0; k < INPUT_MANY; k++)
+ inputset[k].contrast = value;
+ } else if (V4L2_CID_SATURATION == easycap_control[i].id) {
+ m++;
+ for (k = 0; k < INPUT_MANY; k++)
+ inputset[k].saturation = value;
+ } else if (V4L2_CID_HUE == easycap_control[i].id) {
+ m++;
+ for (k = 0; k < INPUT_MANY; k++)
+ inputset[k].hue = value;
+ }
+ }
+
+ if (m != 4) {
+ SAM("ERROR: inputset[]->brightness underpopulated\n");
+ return -ENOENT;
+ }
+
+ for (k = 0; k < INPUT_MANY; k++)
+ inputset[k].input = k;
+ JOM(4, "populated inputset[]\n");
+
+ return 0;
+ }
+
+ static int alloc_framebuffers(struct easycap *peasycap)
+ {
+ int i, j;
+ void *pbuf;
+
+ JOM(4, "allocating %i frame buffers of size %li\n",
+ FRAME_BUFFER_MANY, (long int)FRAME_BUFFER_SIZE);
+ JOM(4, ".... each scattered over %li pages\n",
+ FRAME_BUFFER_SIZE/PAGE_SIZE);
+
+ for (i = 0; i < FRAME_BUFFER_MANY; i++) {
+ for (j = 0; j < FRAME_BUFFER_SIZE/PAGE_SIZE; j++) {
+ if (peasycap->frame_buffer[i][j].pgo)
+ SAM("attempting to reallocate framebuffers\n");
+ else {
+ pbuf = (void *)__get_free_page(GFP_KERNEL);
+ if (!pbuf) {
+ SAM("ERROR: Could not allocate "
+ "framebuffer %i page %i\n", i, j);
+ return -ENOMEM;
+ }
+ peasycap->allocation_video_page += 1;
+ peasycap->frame_buffer[i][j].pgo = pbuf;
}
+ peasycap->frame_buffer[i][j].pto =
+ peasycap->frame_buffer[i][j].pgo;
}
+ }
- if (DONGLE_MANY <= ndong) {
- SAM("ERROR: too many dongles\n");
- mutex_unlock(&mutex_dongle);
+ peasycap->frame_fill = 0;
+ peasycap->frame_read = 0;
+ JOM(4, "allocation of frame buffers done: %i pages\n", i*j);
+
+ return 0;
+ }
+
+ static void free_framebuffers(struct easycap *peasycap)
+ {
+ int k, m, gone;
+
+ JOM(4, "freeing video frame buffers.\n");
+ gone = 0;
+ for (k = 0; k < FRAME_BUFFER_MANY; k++) {
+ for (m = 0; m < FRAME_BUFFER_SIZE/PAGE_SIZE; m++) {
+ if (peasycap->frame_buffer[k][m].pgo) {
+ free_page((unsigned long)
+ peasycap->frame_buffer[k][m].pgo);
+ peasycap->frame_buffer[k][m].pgo = NULL;
+ peasycap->allocation_video_page -= 1;
+ gone++;
+ }
+ }
+ }
+ JOM(4, "video frame buffers freed: %i pages\n", gone);
+ }
+
+ static int alloc_fieldbuffers(struct easycap *peasycap)
+ {
+ int i, j;
+ void *pbuf;
+
+ JOM(4, "allocating %i field buffers of size %li\n",
+ FIELD_BUFFER_MANY, (long int)FIELD_BUFFER_SIZE);
+ JOM(4, ".... each scattered over %li pages\n",
+ FIELD_BUFFER_SIZE/PAGE_SIZE);
+
+ for (i = 0; i < FIELD_BUFFER_MANY; i++) {
+ for (j = 0; j < FIELD_BUFFER_SIZE/PAGE_SIZE; j++) {
+ if (peasycap->field_buffer[i][j].pgo) {
+ SAM("ERROR: attempting to reallocate "
+ "fieldbuffers\n");
+ } else {
+ pbuf = (void *) __get_free_page(GFP_KERNEL);
+ if (!pbuf) {
+ SAM("ERROR: Could not allocate "
+ "fieldbuffer %i page %i\n", i, j);
+ return -ENOMEM;
+ }
+ peasycap->allocation_video_page += 1;
+ peasycap->field_buffer[i][j].pgo = pbuf;
+ }
+ peasycap->field_buffer[i][j].pto =
+ peasycap->field_buffer[i][j].pgo;
+ }
+ /* TODO: Hardcoded 0x0200 meaning? */
+ peasycap->field_buffer[i][0].kount = 0x0200;
+ }
+ peasycap->field_fill = 0;
+ peasycap->field_page = 0;
+ peasycap->field_read = 0;
+ JOM(4, "allocation of field buffers done: %i pages\n", i*j);
+
+ return 0;
+ }
+
+ static void free_fieldbuffers(struct easycap *peasycap)
+ {
+ int k, m, gone;
+
+ JOM(4, "freeing video field buffers.\n");
+ gone = 0;
+ for (k = 0; k < FIELD_BUFFER_MANY; k++) {
+ for (m = 0; m < FIELD_BUFFER_SIZE/PAGE_SIZE; m++) {
+ if (peasycap->field_buffer[k][m].pgo) {
+ free_page((unsigned long)
+ peasycap->field_buffer[k][m].pgo);
+ peasycap->field_buffer[k][m].pgo = NULL;
+ peasycap->allocation_video_page -= 1;
+ gone++;
+ }
+ }
+ }
+ JOM(4, "video field buffers freed: %i pages\n", gone);
+ }
+
+ static int alloc_isocbuffers(struct easycap *peasycap)
+ {
+ int i;
+ void *pbuf;
+
+ JOM(4, "allocating %i isoc video buffers of size %i\n",
+ VIDEO_ISOC_BUFFER_MANY,
+ peasycap->video_isoc_buffer_size);
+ JOM(4, ".... each occupying contiguous memory pages\n");
+
+ for (i = 0; i < VIDEO_ISOC_BUFFER_MANY; i++) {
+ pbuf = (void *)__get_free_pages(GFP_KERNEL,
+ VIDEO_ISOC_ORDER);
+ if (!pbuf) {
+ SAM("ERROR: Could not allocate isoc "
+ "video buffer %i\n", i);
return -ENOMEM;
}
- mutex_unlock(&mutex_dongle);
+ peasycap->allocation_video_page += BIT(VIDEO_ISOC_ORDER);
- peasycap->allocation_video_struct = sizeof(struct easycap);
+ peasycap->video_isoc_buffer[i].pgo = pbuf;
+ peasycap->video_isoc_buffer[i].pto =
+ pbuf + peasycap->video_isoc_buffer_size;
+ peasycap->video_isoc_buffer[i].kount = i;
+ }
+ JOM(4, "allocation of isoc video buffers done: %i pages\n",
+ i * (0x01 << VIDEO_ISOC_ORDER));
+ return 0;
+ }
- /* and further initialize the structure */
- peasycap->pusb_device = usbdev;
- peasycap->pusb_interface = intf;
+ static void free_isocbuffers(struct easycap *peasycap)
+ {
+ int k, m;
- peasycap->microphone = false;
+ JOM(4, "freeing video isoc buffers.\n");
+ m = 0;
+ for (k = 0; k < VIDEO_ISOC_BUFFER_MANY; k++) {
+ if (peasycap->video_isoc_buffer[k].pgo) {
+ free_pages((unsigned long)
+ peasycap->video_isoc_buffer[k].pgo,
+ VIDEO_ISOC_ORDER);
+ peasycap->video_isoc_buffer[k].pgo = NULL;
+ peasycap->allocation_video_page -=
+ BIT(VIDEO_ISOC_ORDER);
+ m++;
+ }
+ }
+ JOM(4, "isoc video buffers freed: %i pages\n",
+ m * (0x01 << VIDEO_ISOC_ORDER));
+ }
- peasycap->video_interface = -1;
- peasycap->video_altsetting_on = -1;
- peasycap->video_altsetting_off = -1;
- peasycap->video_endpointnumber = -1;
- peasycap->video_isoc_maxframesize = -1;
- peasycap->video_isoc_buffer_size = -1;
+ static int create_video_urbs(struct easycap *peasycap)
+ {
+ struct urb *purb;
+ struct data_urb *pdata_urb;
+ int i, j;
+
+ JOM(4, "allocating %i struct urb.\n", VIDEO_ISOC_BUFFER_MANY);
+ JOM(4, "using %i=peasycap->video_isoc_framesperdesc\n",
+ peasycap->video_isoc_framesperdesc);
+ JOM(4, "using %i=peasycap->video_isoc_maxframesize\n",
+ peasycap->video_isoc_maxframesize);
+ JOM(4, "using %i=peasycap->video_isoc_buffer_sizen",
+ peasycap->video_isoc_buffer_size);
+
+ for (i = 0; i < VIDEO_ISOC_BUFFER_MANY; i++) {
+ purb = usb_alloc_urb(peasycap->video_isoc_framesperdesc,
+ GFP_KERNEL);
+ if (!purb) {
+ SAM("ERROR: usb_alloc_urb returned NULL for buffer "
+ "%i\n", i);
+ return -ENOMEM;
+ }
- peasycap->audio_interface = -1;
- peasycap->audio_altsetting_on = -1;
- peasycap->audio_altsetting_off = -1;
- peasycap->audio_endpointnumber = -1;
- peasycap->audio_isoc_maxframesize = -1;
- peasycap->audio_isoc_buffer_size = -1;
+ peasycap->allocation_video_urb += 1;
+ pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL);
+ if (!pdata_urb) {
+ SAM("ERROR: Could not allocate struct data_urb.\n");
+ return -ENOMEM;
+ }
- peasycap->frame_buffer_many = FRAME_BUFFER_MANY;
+ peasycap->allocation_video_struct +=
+ sizeof(struct data_urb);
+
+ pdata_urb->purb = purb;
+ pdata_urb->isbuf = i;
+ pdata_urb->length = 0;
+ list_add_tail(&(pdata_urb->list_head),
+ peasycap->purb_video_head);
+
+ if (!i) {
+ JOM(4, "initializing video urbs thus:\n");
+ JOM(4, " purb->interval = 1;\n");
+ JOM(4, " purb->dev = peasycap->pusb_device;\n");
+ JOM(4, " purb->pipe = usb_rcvisocpipe"
+ "(peasycap->pusb_device,%i);\n",
+ peasycap->video_endpointnumber);
+ JOM(4, " purb->transfer_flags = URB_ISO_ASAP;\n");
+ JOM(4, " purb->transfer_buffer = peasycap->"
+ "video_isoc_buffer[.].pgo;\n");
+ JOM(4, " purb->transfer_buffer_length = %i;\n",
+ peasycap->video_isoc_buffer_size);
+ JOM(4, " purb->complete = easycap_complete;\n");
+ JOM(4, " purb->context = peasycap;\n");
+ JOM(4, " purb->start_frame = 0;\n");
+ JOM(4, " purb->number_of_packets = %i;\n",
+ peasycap->video_isoc_framesperdesc);
+ JOM(4, " for (j = 0; j < %i; j++)\n",
+ peasycap->video_isoc_framesperdesc);
+ JOM(4, " {\n");
+ JOM(4, " purb->iso_frame_desc[j].offset = j*%i;\n",
+ peasycap->video_isoc_maxframesize);
+ JOM(4, " purb->iso_frame_desc[j].length = %i;\n",
+ peasycap->video_isoc_maxframesize);
+ JOM(4, " }\n");
+ }
- /* Dynamically fill in the available formats */
- rc = easycap_video_fillin_formats();
- if (0 > rc) {
- SAM("ERROR: fillin_formats() rc = %i\n", rc);
- return -EFAULT;
+ purb->interval = 1;
+ purb->dev = peasycap->pusb_device;
+ purb->pipe = usb_rcvisocpipe(peasycap->pusb_device,
+ peasycap->video_endpointnumber);
+
+ purb->transfer_flags = URB_ISO_ASAP;
+ purb->transfer_buffer = peasycap->video_isoc_buffer[i].pgo;
+ purb->transfer_buffer_length =
+ peasycap->video_isoc_buffer_size;
+
+ purb->complete = easycap_complete;
+ purb->context = peasycap;
+ purb->start_frame = 0;
+ purb->number_of_packets = peasycap->video_isoc_framesperdesc;
+
+ for (j = 0; j < peasycap->video_isoc_framesperdesc; j++) {
+ purb->iso_frame_desc[j].offset =
+ j * peasycap->video_isoc_maxframesize;
+ purb->iso_frame_desc[j].length =
+ peasycap->video_isoc_maxframesize;
}
- JOM(4, "%i formats available\n", rc);
+ }
+ JOM(4, "allocation of %i struct urb done.\n", i);
+ return 0;
+ }
- /* Populate easycap.inputset[] */
- inputset = peasycap->inputset;
- fmtidx = peasycap->ntsc ? NTSC_M : PAL_BGHIN;
+ static void free_video_urbs(struct easycap *peasycap)
+ {
+ struct list_head *plist_head, *plist_next;
+ struct data_urb *pdata_urb;
+ int m;
+
+ if (peasycap->purb_video_head) {
m = 0;
- mask = 0;
- for (i = 0; 0xFFFF != easycap_standard[i].mask; i++) {
- if (fmtidx == easycap_standard[i].v4l2_standard.index) {
+ list_for_each(plist_head, peasycap->purb_video_head) {
+ pdata_urb = list_entry(plist_head,
+ struct data_urb, list_head);
+ if (pdata_urb && pdata_urb->purb) {
+ usb_free_urb(pdata_urb->purb);
+ pdata_urb->purb = NULL;
+ peasycap->allocation_video_urb--;
m++;
- for (k = 0; k < INPUT_MANY; k++)
- inputset[k].standard_offset = i;
+ }
+ }
- mask = easycap_standard[i].mask;
+ JOM(4, "%i video urbs freed\n", m);
+ JOM(4, "freeing video data_urb structures.\n");
+ m = 0;
+ list_for_each_safe(plist_head, plist_next,
+ peasycap->purb_video_head) {
+ pdata_urb = list_entry(plist_head,
+ struct data_urb, list_head);
+ if (pdata_urb) {
+ peasycap->allocation_video_struct -=
+ sizeof(struct data_urb);
+ kfree(pdata_urb);
+ m++;
}
}
- if (1 != m) {
- SAM("ERROR: "
- "inputset->standard_offset unpopulated, %i=m\n", m);
- return -ENOENT;
+ JOM(4, "%i video data_urb structures freed\n", m);
+ JOM(4, "setting peasycap->purb_video_head=NULL\n");
+ peasycap->purb_video_head = NULL;
+ }
+ }
+
+ static int alloc_audio_buffers(struct easycap *peasycap)
+ {
+ void *pbuf;
+ int k;
+
+ JOM(4, "allocating %i isoc audio buffers of size %i\n",
+ AUDIO_ISOC_BUFFER_MANY,
+ peasycap->audio_isoc_buffer_size);
+ JOM(4, ".... each occupying contiguous memory pages\n");
+
+ for (k = 0; k < AUDIO_ISOC_BUFFER_MANY; k++) {
+ pbuf = (void *)__get_free_pages(GFP_KERNEL, AUDIO_ISOC_ORDER);
+ if (!pbuf) {
+ SAM("ERROR: Could not allocate isoc audio buffer %i\n",
+ k);
+ return -ENOMEM;
+ }
+ peasycap->allocation_audio_page += BIT(AUDIO_ISOC_ORDER);
+
+ peasycap->audio_isoc_buffer[k].pgo = pbuf;
+ peasycap->audio_isoc_buffer[k].pto =
+ pbuf + peasycap->audio_isoc_buffer_size;
+ peasycap->audio_isoc_buffer[k].kount = k;
+ }
+
+ JOM(4, "allocation of isoc audio buffers done.\n");
+ return 0;
+ }
+
+ static void free_audio_buffers(struct easycap *peasycap)
+ {
+ int k, m;
+
+ JOM(4, "freeing audio isoc buffers.\n");
+ m = 0;
+ for (k = 0; k < AUDIO_ISOC_BUFFER_MANY; k++) {
+ if (peasycap->audio_isoc_buffer[k].pgo) {
+ free_pages((unsigned long)
+ (peasycap->audio_isoc_buffer[k].pgo),
+ AUDIO_ISOC_ORDER);
+ peasycap->audio_isoc_buffer[k].pgo = NULL;
+ peasycap->allocation_audio_page -=
+ BIT(AUDIO_ISOC_ORDER);
+ m++;
+ }
+ }
+ JOM(4, "easyoss_delete(): isoc audio buffers freed: %i pages\n",
+ m * (0x01 << AUDIO_ISOC_ORDER));
+ }
+
+ static int create_audio_urbs(struct easycap *peasycap)
+ {
+ struct urb *purb;
+ struct data_urb *pdata_urb;
+ int k, j;
+
+ JOM(4, "allocating %i struct urb.\n", AUDIO_ISOC_BUFFER_MANY);
+ JOM(4, "using %i=peasycap->audio_isoc_framesperdesc\n",
+ peasycap->audio_isoc_framesperdesc);
+ JOM(4, "using %i=peasycap->audio_isoc_maxframesize\n",
+ peasycap->audio_isoc_maxframesize);
+ JOM(4, "using %i=peasycap->audio_isoc_buffer_size\n",
+ peasycap->audio_isoc_buffer_size);
+
+ for (k = 0; k < AUDIO_ISOC_BUFFER_MANY; k++) {
+ purb = usb_alloc_urb(peasycap->audio_isoc_framesperdesc,
+ GFP_KERNEL);
+ if (!purb) {
+ SAM("ERROR: usb_alloc_urb returned NULL for buffer "
+ "%i\n", k);
+ return -ENOMEM;
+ }
+ peasycap->allocation_audio_urb += 1 ;
+ pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL);
+ if (!pdata_urb) {
+ usb_free_urb(purb);
+ SAM("ERROR: Could not allocate struct data_urb.\n");
+ return -ENOMEM;
}
+ peasycap->allocation_audio_struct +=
+ sizeof(struct data_urb);
+
+ pdata_urb->purb = purb;
+ pdata_urb->isbuf = k;
+ pdata_urb->length = 0;
+ list_add_tail(&(pdata_urb->list_head),
+ peasycap->purb_audio_head);
+
+ if (!k) {
+ JOM(4, "initializing audio urbs thus:\n");
+ JOM(4, " purb->interval = 1;\n");
+ JOM(4, " purb->dev = peasycap->pusb_device;\n");
+ JOM(4, " purb->pipe = usb_rcvisocpipe(peasycap->"
+ "pusb_device,%i);\n",
+ peasycap->audio_endpointnumber);
+ JOM(4, " purb->transfer_flags = URB_ISO_ASAP;\n");
+ JOM(4, " purb->transfer_buffer = "
+ "peasycap->audio_isoc_buffer[.].pgo;\n");
+ JOM(4, " purb->transfer_buffer_length = %i;\n",
+ peasycap->audio_isoc_buffer_size);
+ JOM(4, " purb->complete = easycap_alsa_complete;\n");
+ JOM(4, " purb->context = peasycap;\n");
+ JOM(4, " purb->start_frame = 0;\n");
+ JOM(4, " purb->number_of_packets = %i;\n",
+ peasycap->audio_isoc_framesperdesc);
+ JOM(4, " for (j = 0; j < %i; j++)\n",
+ peasycap->audio_isoc_framesperdesc);
+ JOM(4, " {\n");
+ JOM(4, " purb->iso_frame_desc[j].offset = j*%i;\n",
+ peasycap->audio_isoc_maxframesize);
+ JOM(4, " purb->iso_frame_desc[j].length = %i;\n",
+ peasycap->audio_isoc_maxframesize);
+ JOM(4, " }\n");
+ }
+
+ purb->interval = 1;
+ purb->dev = peasycap->pusb_device;
+ purb->pipe = usb_rcvisocpipe(peasycap->pusb_device,
+ peasycap->audio_endpointnumber);
+ purb->transfer_flags = URB_ISO_ASAP;
+ purb->transfer_buffer = peasycap->audio_isoc_buffer[k].pgo;
+ purb->transfer_buffer_length =
+ peasycap->audio_isoc_buffer_size;
+ purb->complete = easycap_alsa_complete;
+ purb->context = peasycap;
+ purb->start_frame = 0;
+ purb->number_of_packets = peasycap->audio_isoc_framesperdesc;
+ for (j = 0; j < peasycap->audio_isoc_framesperdesc; j++) {
+ purb->iso_frame_desc[j].offset =
+ j * peasycap->audio_isoc_maxframesize;
+ purb->iso_frame_desc[j].length =
+ peasycap->audio_isoc_maxframesize;
+ }
+ }
+ JOM(4, "allocation of %i struct urb done.\n", k);
+ return 0;
+ }
+
+ static void free_audio_urbs(struct easycap *peasycap)
+ {
+ struct list_head *plist_head, *plist_next;
+ struct data_urb *pdata_urb;
+ int m;
- peasycap_format = &easycap_format[0];
+ if (peasycap->purb_audio_head) {
+ JOM(4, "freeing audio urbs\n");
m = 0;
- for (i = 0; peasycap_format->v4l2_format.fmt.pix.width; i++) {
- struct v4l2_pix_format *pix =
- &peasycap_format->v4l2_format.fmt.pix;
- if (((peasycap_format->mask & 0x0F) == (mask & 0x0F)) &&
- pix->field == V4L2_FIELD_NONE &&
- pix->pixelformat == V4L2_PIX_FMT_UYVY &&
- pix->width == 640 && pix->height == 480) {
+ list_for_each(plist_head, (peasycap->purb_audio_head)) {
+ pdata_urb = list_entry(plist_head,
+ struct data_urb, list_head);
+ if (pdata_urb && pdata_urb->purb) {
+ usb_free_urb(pdata_urb->purb);
+ pdata_urb->purb = NULL;
+ peasycap->allocation_audio_urb--;
m++;
- for (k = 0; k < INPUT_MANY; k++)
- inputset[k].format_offset = i;
- break;
}
- peasycap_format++;
}
- if (1 != m) {
- SAM("ERROR: inputset[]->format_offset unpopulated\n");
- return -ENOENT;
- }
-
+ JOM(4, "%i audio urbs freed\n", m);
+ JOM(4, "freeing audio data_urb structures.\n");
m = 0;
- for (i = 0; 0xFFFFFFFF != easycap_control[i].id; i++) {
- value = easycap_control[i].default_value;
- if (V4L2_CID_BRIGHTNESS == easycap_control[i].id) {
- m++;
- for (k = 0; k < INPUT_MANY; k++)
- inputset[k].brightness = value;
- } else if (V4L2_CID_CONTRAST == easycap_control[i].id) {
- m++;
- for (k = 0; k < INPUT_MANY; k++)
- inputset[k].contrast = value;
- } else if (V4L2_CID_SATURATION == easycap_control[i].id) {
- m++;
- for (k = 0; k < INPUT_MANY; k++)
- inputset[k].saturation = value;
- } else if (V4L2_CID_HUE == easycap_control[i].id) {
+ list_for_each_safe(plist_head, plist_next,
+ peasycap->purb_audio_head) {
+ pdata_urb = list_entry(plist_head,
+ struct data_urb, list_head);
+ if (pdata_urb) {
+ peasycap->allocation_audio_struct -=
+ sizeof(struct data_urb);
+ kfree(pdata_urb);
m++;
- for (k = 0; k < INPUT_MANY; k++)
- inputset[k].hue = value;
- }
- }
-
- if (4 != m) {
- SAM("ERROR: inputset[]->brightness underpopulated\n");
- return -ENOENT;
- }
- for (k = 0; k < INPUT_MANY; k++)
- inputset[k].input = k;
- JOM(4, "populated inputset[]\n");
- JOM(4, "finished initialization\n");
- } else {
-
- /*
- * FIXME: Identify the appropriate pointer
- * peasycap for interfaces 1 and 2.
- * The address of peasycap->pusb_device
- * is reluctantly used for this purpose.
- */
- for (ndong = 0; ndong < DONGLE_MANY; ndong++) {
- if (usbdev == easycapdc60_dongle[ndong].peasycap->
- pusb_device) {
- peasycap = easycapdc60_dongle[ndong].peasycap;
- JOT(8, "intf[%i]: dongle[%i].peasycap\n",
- bInterfaceNumber, ndong);
- break;
}
}
- if (DONGLE_MANY <= ndong) {
- SAY("ERROR: peasycap is unknown when probing interface %i\n",
- bInterfaceNumber);
- return -ENODEV;
- }
- if (!peasycap) {
- SAY("ERROR: peasycap is NULL when probing interface %i\n",
- bInterfaceNumber);
- return -ENODEV;
- }
+ JOM(4, "%i audio data_urb structures freed\n", m);
+ JOM(4, "setting peasycap->purb_audio_head=NULL\n");
+ peasycap->purb_audio_head = NULL;
}
+ }
+ static void config_easycap(struct easycap *peasycap,
+ u8 bInterfaceNumber,
+ u8 bInterfaceClass,
+ u8 bInterfaceSubClass)
+ {
if ((USB_CLASS_VIDEO == bInterfaceClass) ||
(USB_CLASS_VENDOR_SPEC == bInterfaceClass)) {
if (-1 == peasycap->video_interface) {
peasycap->video_interface = bInterfaceNumber;
JOM(4, "setting peasycap->video_interface=%i\n",
- peasycap->video_interface);
+ peasycap->video_interface);
} else {
if (peasycap->video_interface != bInterfaceNumber) {
SAM("ERROR: attempting to reset "
- "peasycap->video_interface\n");
+ "peasycap->video_interface\n");
SAM("...... continuing with "
- "%i=peasycap->video_interface\n",
- peasycap->video_interface);
+ "%i=peasycap->video_interface\n",
+ peasycap->video_interface);
}
}
} else if ((USB_CLASS_AUDIO == bInterfaceClass) &&
if (-1 == peasycap->audio_interface) {
peasycap->audio_interface = bInterfaceNumber;
JOM(4, "setting peasycap->audio_interface=%i\n",
- peasycap->audio_interface);
+ peasycap->audio_interface);
} else {
if (peasycap->audio_interface != bInterfaceNumber) {
SAM("ERROR: attempting to reset "
- "peasycap->audio_interface\n");
+ "peasycap->audio_interface\n");
SAM("...... continuing with "
- "%i=peasycap->audio_interface\n",
- peasycap->audio_interface);
+ "%i=peasycap->audio_interface\n",
+ peasycap->audio_interface);
}
}
}
- err("Not able to register with videodev");
+ }
+
+ /*
+ * This function is called from within easycap_usb_disconnect() and is
+ * protected by semaphores set and cleared by easycap_usb_disconnect().
+ * By this stage the device has already been physically unplugged,
+ * so peasycap->pusb_device is no longer valid.
+ */
+ static void easycap_delete(struct kref *pkref)
+ {
+ struct easycap *peasycap;
+
+ peasycap = container_of(pkref, struct easycap, kref);
+ if (!peasycap) {
+ SAM("ERROR: peasycap is NULL: cannot perform deletions\n");
+ return;
+ }
+
+ /* Free video urbs */
+ free_video_urbs(peasycap);
+
+ /* Free video isoc buffers */
+ free_isocbuffers(peasycap);
+
+ /* Free video field buffers */
+ free_fieldbuffers(peasycap);
+
+ /* Free video frame buffers */
+ free_framebuffers(peasycap);
+
+ /* Free audio urbs */
+ free_audio_urbs(peasycap);
+
+ /* Free audio isoc buffers */
+ free_audio_buffers(peasycap);
+
+ free_easycap(peasycap);
+
+ JOT(4, "ending.\n");
+ }
+
+ static const struct v4l2_file_operations v4l2_fops = {
+ .owner = THIS_MODULE,
+ .open = easycap_open_noinode,
+ .unlocked_ioctl = easycap_unlocked_ioctl,
+ .poll = easycap_poll,
+ .mmap = easycap_mmap,
+ };
+
+ static int easycap_register_video(struct easycap *peasycap)
+ {
+ /*
+ * FIXME: This is believed to be harmless,
+ * but may well be unnecessary or wrong.
+ */
+ peasycap->video_device.v4l2_dev = NULL;
+
+ strcpy(&peasycap->video_device.name[0], "easycapdc60");
+ peasycap->video_device.fops = &v4l2_fops;
+ peasycap->video_device.minor = -1;
+ peasycap->video_device.release = (void *)(&videodev_release);
+
+ video_set_drvdata(&(peasycap->video_device), (void *)peasycap);
+
+ if (0 != (video_register_device(&(peasycap->video_device),
+ VFL_TYPE_GRABBER, -1))) {
+ videodev_release(&(peasycap->video_device));
+ return -ENODEV;
+ }
+
+ peasycap->registered_video++;
+
+ SAM("registered with videodev: %i=minor\n",
+ peasycap->video_device.minor);
+ peasycap->minor = peasycap->video_device.minor;
+
+ return 0;
+ }
+
+ /*
+ * When the device is plugged, this function is called three times,
+ * one for each interface.
+ */
+ static int easycap_usb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+ {
+ struct usb_device *usbdev;
+ struct usb_host_interface *alt;
+ struct usb_endpoint_descriptor *ep;
+ struct usb_interface_descriptor *interface;
+ struct easycap *peasycap;
+ int i, j, rc;
+ u8 bInterfaceNumber;
+ u8 bInterfaceClass;
+ u8 bInterfaceSubClass;
+ int okalt[8], isokalt;
+ int okepn[8];
+ int okmps[8];
+ int maxpacketsize;
+
+ usbdev = interface_to_usbdev(intf);
+
+ alt = usb_altnum_to_altsetting(intf, 0);
+ if (!alt) {
+ SAY("ERROR: usb_host_interface not found\n");
+ return -EFAULT;
+ }
+
+ interface = &alt->desc;
+ if (!interface) {
+ SAY("ERROR: intf_descriptor is NULL\n");
+ return -EFAULT;
+ }
+
+ /* Get properties of probed interface */
+ bInterfaceNumber = interface->bInterfaceNumber;
+ bInterfaceClass = interface->bInterfaceClass;
+ bInterfaceSubClass = interface->bInterfaceSubClass;
+
+ JOT(4, "intf[%i]: num_altsetting=%i\n",
+ bInterfaceNumber, intf->num_altsetting);
+ JOT(4, "intf[%i]: cur_altsetting - altsetting=%li\n",
+ bInterfaceNumber,
+ (long int)(intf->cur_altsetting - intf->altsetting));
+ JOT(4, "intf[%i]: bInterfaceClass=0x%02X bInterfaceSubClass=0x%02X\n",
+ bInterfaceNumber, bInterfaceClass, bInterfaceSubClass);
+
+ /*
+ * A new struct easycap is always allocated when interface 0 is probed.
+ * It is not possible here to free any existing struct easycap.
+ * This should have been done by easycap_delete() when the device was
+ * physically unplugged.
+ * The allocated struct easycap is saved for later usage when
+ * interfaces 1 and 2 are probed.
+ */
+ if (0 == bInterfaceNumber) {
+ /*
+ * Alloc structure and save it in a free slot in
+ * easycapdc60_dongle array
+ */
+ peasycap = alloc_easycap(bInterfaceNumber);
+ if (!peasycap)
+ return -ENOMEM;
+
+ /* Perform basic struct initialization */
+ init_easycap(peasycap, usbdev, intf, bInterfaceNumber);
+
+ /* Dynamically fill in the available formats */
+ rc = easycap_video_fillin_formats();
+ if (0 > rc) {
+ SAM("ERROR: fillin_formats() rc = %i\n", rc);
+ return -EFAULT;
+ }
+ JOM(4, "%i formats available\n", rc);
+
+ /* Populate easycap.inputset[] */
+ rc = populate_inputset(peasycap);
+ if (rc < 0)
+ return rc;
+ JOM(4, "finished initialization\n");
+ } else {
+ peasycap = get_easycap(usbdev, bInterfaceNumber);
+ if (!peasycap)
+ return -ENODEV;
+ }
+
+ config_easycap(peasycap, bInterfaceNumber,
+ bInterfaceClass,
+ bInterfaceSubClass);
/*
* Investigate all altsettings. This is done in detail
*/
INIT_LIST_HEAD(&(peasycap->urb_video_head));
peasycap->purb_video_head = &(peasycap->urb_video_head);
- JOM(4, "allocating %i frame buffers of size %li\n",
- FRAME_BUFFER_MANY, (long int)FRAME_BUFFER_SIZE);
- JOM(4, ".... each scattered over %li pages\n",
- FRAME_BUFFER_SIZE/PAGE_SIZE);
-
- for (k = 0; k < FRAME_BUFFER_MANY; k++) {
- for (m = 0; m < FRAME_BUFFER_SIZE/PAGE_SIZE; m++) {
- if (peasycap->frame_buffer[k][m].pgo)
- SAM("attempting to reallocate frame "
- " buffers\n");
- else {
- pbuf = (void *)__get_free_page(GFP_KERNEL);
- if (!pbuf) {
- SAM("ERROR: Could not allocate frame "
- "buffer %i page %i\n", k, m);
- return -ENOMEM;
- }
-
- peasycap->allocation_video_page += 1;
- peasycap->frame_buffer[k][m].pgo = pbuf;
- }
- peasycap->frame_buffer[k][m].pto =
- peasycap->frame_buffer[k][m].pgo;
- }
- }
-
- peasycap->frame_fill = 0;
- peasycap->frame_read = 0;
- JOM(4, "allocation of frame buffers done: %i pages\n", k *
- m);
- JOM(4, "allocating %i field buffers of size %li\n",
- FIELD_BUFFER_MANY, (long int)FIELD_BUFFER_SIZE);
- JOM(4, ".... each scattered over %li pages\n",
- FIELD_BUFFER_SIZE/PAGE_SIZE);
-
- for (k = 0; k < FIELD_BUFFER_MANY; k++) {
- for (m = 0; m < FIELD_BUFFER_SIZE/PAGE_SIZE; m++) {
- if (peasycap->field_buffer[k][m].pgo) {
- SAM("ERROR: attempting to reallocate "
- "field buffers\n");
- } else {
- pbuf = (void *) __get_free_page(GFP_KERNEL);
- if (!pbuf) {
- SAM("ERROR: Could not allocate field"
- " buffer %i page %i\n", k, m);
- return -ENOMEM;
- }
-
- peasycap->allocation_video_page += 1;
- peasycap->field_buffer[k][m].pgo = pbuf;
- }
- peasycap->field_buffer[k][m].pto =
- peasycap->field_buffer[k][m].pgo;
- }
- peasycap->field_buffer[k][0].kount = 0x0200;
- }
- peasycap->field_fill = 0;
- peasycap->field_page = 0;
- peasycap->field_read = 0;
- JOM(4, "allocation of field buffers done: %i pages\n", k *
- m);
- JOM(4, "allocating %i isoc video buffers of size %i\n",
- VIDEO_ISOC_BUFFER_MANY,
- peasycap->video_isoc_buffer_size);
- JOM(4, ".... each occupying contiguous memory pages\n");
-
- for (k = 0; k < VIDEO_ISOC_BUFFER_MANY; k++) {
- pbuf = (void *)__get_free_pages(GFP_KERNEL,
- VIDEO_ISOC_ORDER);
- if (!pbuf) {
- SAM("ERROR: Could not allocate isoc video buffer "
- "%i\n", k);
- return -ENOMEM;
- }
- peasycap->allocation_video_page +=
- BIT(VIDEO_ISOC_ORDER);
-
- peasycap->video_isoc_buffer[k].pgo = pbuf;
- peasycap->video_isoc_buffer[k].pto =
- pbuf + peasycap->video_isoc_buffer_size;
- peasycap->video_isoc_buffer[k].kount = k;
- }
- JOM(4, "allocation of isoc video buffers done: %i pages\n",
- k * (0x01 << VIDEO_ISOC_ORDER));
-
- /* Allocate and initialize multiple struct usb */
- JOM(4, "allocating %i struct urb.\n", VIDEO_ISOC_BUFFER_MANY);
- JOM(4, "using %i=peasycap->video_isoc_framesperdesc\n",
- peasycap->video_isoc_framesperdesc);
- JOM(4, "using %i=peasycap->video_isoc_maxframesize\n",
- peasycap->video_isoc_maxframesize);
- JOM(4, "using %i=peasycap->video_isoc_buffer_sizen",
- peasycap->video_isoc_buffer_size);
-
- for (k = 0; k < VIDEO_ISOC_BUFFER_MANY; k++) {
- purb = usb_alloc_urb(peasycap->video_isoc_framesperdesc,
- GFP_KERNEL);
- if (!purb) {
- SAM("ERROR: usb_alloc_urb returned NULL for buffer "
- "%i\n", k);
- return -ENOMEM;
- }
- peasycap->allocation_video_urb += 1;
- pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL);
- if (!pdata_urb) {
- SAM("ERROR: Could not allocate struct data_urb.\n");
- return -ENOMEM;
- }
+ rc = alloc_framebuffers(peasycap);
+ if (rc < 0)
+ return rc;
- peasycap->allocation_video_struct +=
- sizeof(struct data_urb);
+ rc = alloc_fieldbuffers(peasycap);
+ if (rc < 0)
+ return rc;
- pdata_urb->purb = purb;
- pdata_urb->isbuf = k;
- pdata_urb->length = 0;
- list_add_tail(&(pdata_urb->list_head),
- peasycap->purb_video_head);
-
- /* Initialize allocated urbs */
- if (!k) {
- JOM(4, "initializing video urbs thus:\n");
- JOM(4, " purb->interval = 1;\n");
- JOM(4, " purb->dev = peasycap->pusb_device;\n");
- JOM(4, " purb->pipe = usb_rcvisocpipe"
- "(peasycap->pusb_device,%i);\n",
- peasycap->video_endpointnumber);
- JOM(4, " purb->transfer_flags = URB_ISO_ASAP;\n");
- JOM(4, " purb->transfer_buffer = peasycap->"
- "video_isoc_buffer[.].pgo;\n");
- JOM(4, " purb->transfer_buffer_length = %i;\n",
- peasycap->video_isoc_buffer_size);
- JOM(4, " purb->complete = easycap_complete;\n");
- JOM(4, " purb->context = peasycap;\n");
- JOM(4, " purb->start_frame = 0;\n");
- JOM(4, " purb->number_of_packets = %i;\n",
- peasycap->video_isoc_framesperdesc);
- JOM(4, " for (j = 0; j < %i; j++)\n",
- peasycap->video_isoc_framesperdesc);
- JOM(4, " {\n");
- JOM(4, " purb->iso_frame_desc[j].offset = j*%i;\n",
- peasycap->video_isoc_maxframesize);
- JOM(4, " purb->iso_frame_desc[j].length = %i;\n",
- peasycap->video_isoc_maxframesize);
- JOM(4, " }\n");
- }
+ rc = alloc_isocbuffers(peasycap);
+ if (rc < 0)
+ return rc;
- purb->interval = 1;
- purb->dev = peasycap->pusb_device;
- purb->pipe = usb_rcvisocpipe(peasycap->pusb_device,
- peasycap->video_endpointnumber);
- purb->transfer_flags = URB_ISO_ASAP;
- purb->transfer_buffer = peasycap->video_isoc_buffer[k].pgo;
- purb->transfer_buffer_length =
- peasycap->video_isoc_buffer_size;
- purb->complete = easycap_complete;
- purb->context = peasycap;
- purb->start_frame = 0;
- purb->number_of_packets = peasycap->video_isoc_framesperdesc;
- for (j = 0; j < peasycap->video_isoc_framesperdesc; j++) {
- purb->iso_frame_desc[j].offset = j *
- peasycap->video_isoc_maxframesize;
- purb->iso_frame_desc[j].length =
- peasycap->video_isoc_maxframesize;
- }
- }
- JOM(4, "allocation of %i struct urb done.\n", k);
+ /* Allocate and initialize video urbs */
+ rc = create_video_urbs(peasycap);
+ if (rc < 0)
+ return rc;
/* Save pointer peasycap in this interface */
usb_set_intfdata(intf, peasycap);
* because some udev rules triggers easycap_open()
* immediately after registration, causing a clash.
*/
- peasycap->ntsc = easycap_ntsc;
- JOM(8, "defaulting initially to %s\n",
- easycap_ntsc ? "NTSC" : "PAL");
rc = reset(peasycap);
if (rc) {
SAM("ERROR: reset() rc = %i\n", rc);
JOM(4, "registered device instance: %s\n",
peasycap->v4l2_device.name);
- /*
- * FIXME: This is believed to be harmless,
- * but may well be unnecessary or wrong.
- */
- peasycap->video_device.v4l2_dev = NULL;
-
-
- strcpy(&peasycap->video_device.name[0], "easycapdc60");
- peasycap->video_device.fops = &v4l2_fops;
- peasycap->video_device.minor = -1;
- peasycap->video_device.release = (void *)(&videodev_release);
-
- video_set_drvdata(&(peasycap->video_device), (void *)peasycap);
-
- if (0 != (video_register_device(&(peasycap->video_device),
- VFL_TYPE_GRABBER, -1))) {
+ rc = easycap_register_video(peasycap);
- if (rc < 0)
++ if (rc < 0) {
+ dev_err(&intf->dev,
+ "Not able to register with videodev\n");
- videodev_release(&(peasycap->video_device));
return -ENODEV;
-
- peasycap->registered_video++;
- SAM("registered with videodev: %i=minor\n",
- peasycap->video_device.minor);
- peasycap->minor = peasycap->video_device.minor;
-
+ }
break;
}
/* 1: Audio control */
INIT_LIST_HEAD(&(peasycap->urb_audio_head));
peasycap->purb_audio_head = &(peasycap->urb_audio_head);
- JOM(4, "allocating %i isoc audio buffers of size %i\n",
- AUDIO_ISOC_BUFFER_MANY,
- peasycap->audio_isoc_buffer_size);
- JOM(4, ".... each occupying contiguous memory pages\n");
-
- for (k = 0; k < AUDIO_ISOC_BUFFER_MANY; k++) {
- pbuf = (void *)__get_free_pages(GFP_KERNEL,
- AUDIO_ISOC_ORDER);
- if (!pbuf) {
- SAM("ERROR: Could not allocate isoc audio buffer "
- "%i\n", k);
- return -ENOMEM;
- }
- peasycap->allocation_audio_page +=
- BIT(AUDIO_ISOC_ORDER);
-
- peasycap->audio_isoc_buffer[k].pgo = pbuf;
- peasycap->audio_isoc_buffer[k].pto = pbuf +
- peasycap->audio_isoc_buffer_size;
- peasycap->audio_isoc_buffer[k].kount = k;
- }
- JOM(4, "allocation of isoc audio buffers done.\n");
+ alloc_audio_buffers(peasycap);
+ if (rc < 0)
+ return rc;
/* Allocate and initialize urbs */
- JOM(4, "allocating %i struct urb.\n", AUDIO_ISOC_BUFFER_MANY);
- JOM(4, "using %i=peasycap->audio_isoc_framesperdesc\n",
- peasycap->audio_isoc_framesperdesc);
- JOM(4, "using %i=peasycap->audio_isoc_maxframesize\n",
- peasycap->audio_isoc_maxframesize);
- JOM(4, "using %i=peasycap->audio_isoc_buffer_size\n",
- peasycap->audio_isoc_buffer_size);
-
- for (k = 0; k < AUDIO_ISOC_BUFFER_MANY; k++) {
- purb = usb_alloc_urb(peasycap->audio_isoc_framesperdesc,
- GFP_KERNEL);
- if (!purb) {
- SAM("ERROR: usb_alloc_urb returned NULL for buffer "
- "%i\n", k);
- return -ENOMEM;
- }
- peasycap->allocation_audio_urb += 1 ;
- pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL);
- if (!pdata_urb) {
- usb_free_urb(purb);
- SAM("ERROR: Could not allocate struct data_urb.\n");
- return -ENOMEM;
- }
- peasycap->allocation_audio_struct +=
- sizeof(struct data_urb);
-
- pdata_urb->purb = purb;
- pdata_urb->isbuf = k;
- pdata_urb->length = 0;
- list_add_tail(&(pdata_urb->list_head),
- peasycap->purb_audio_head);
-
- if (!k) {
- JOM(4, "initializing audio urbs thus:\n");
- JOM(4, " purb->interval = 1;\n");
- JOM(4, " purb->dev = peasycap->pusb_device;\n");
- JOM(4, " purb->pipe = usb_rcvisocpipe(peasycap->"
- "pusb_device,%i);\n",
- peasycap->audio_endpointnumber);
- JOM(4, " purb->transfer_flags = URB_ISO_ASAP;\n");
- JOM(4, " purb->transfer_buffer = "
- "peasycap->audio_isoc_buffer[.].pgo;\n");
- JOM(4, " purb->transfer_buffer_length = %i;\n",
- peasycap->audio_isoc_buffer_size);
- JOM(4, " purb->complete = easycap_alsa_complete;\n");
- JOM(4, " purb->context = peasycap;\n");
- JOM(4, " purb->start_frame = 0;\n");
- JOM(4, " purb->number_of_packets = %i;\n",
- peasycap->audio_isoc_framesperdesc);
- JOM(4, " for (j = 0; j < %i; j++)\n",
- peasycap->audio_isoc_framesperdesc);
- JOM(4, " {\n");
- JOM(4, " purb->iso_frame_desc[j].offset = j*%i;\n",
- peasycap->audio_isoc_maxframesize);
- JOM(4, " purb->iso_frame_desc[j].length = %i;\n",
- peasycap->audio_isoc_maxframesize);
- JOM(4, " }\n");
- }
-
- purb->interval = 1;
- purb->dev = peasycap->pusb_device;
- purb->pipe = usb_rcvisocpipe(peasycap->pusb_device,
- peasycap->audio_endpointnumber);
- purb->transfer_flags = URB_ISO_ASAP;
- purb->transfer_buffer = peasycap->audio_isoc_buffer[k].pgo;
- purb->transfer_buffer_length =
- peasycap->audio_isoc_buffer_size;
- purb->complete = easycap_alsa_complete;
- purb->context = peasycap;
- purb->start_frame = 0;
- purb->number_of_packets = peasycap->audio_isoc_framesperdesc;
- for (j = 0; j < peasycap->audio_isoc_framesperdesc; j++) {
- purb->iso_frame_desc[j].offset = j *
- peasycap->audio_isoc_maxframesize;
- purb->iso_frame_desc[j].length =
- peasycap->audio_isoc_maxframesize;
- }
- }
- JOM(4, "allocation of %i struct urb done.\n", k);
+ rc = create_audio_urbs(peasycap);
+ if (rc < 0)
+ return rc;
/* Save pointer peasycap in this interface */
usb_set_intfdata(intf, peasycap);
rc = easycap_alsa_probe(peasycap);
if (rc) {
- err("easycap_alsa_probe() rc = %i\n", rc);
+ dev_err(&intf->dev, "easycap_alsa_probe() rc = %i\n",
+ rc);
return -ENODEV;
}
SAM("ends successfully for interface %i\n", bInterfaceNumber);
return 0;
}
- /*****************************************************************************/
- /*---------------------------------------------------------------------------*/
+
/*
- * WHEN THIS FUNCTION IS CALLED THE EasyCAP HAS ALREADY BEEN PHYSICALLY
- * UNPLUGGED. HENCE peasycap->pusb_device IS NO LONGER VALID.
- *
- * THIS FUNCTION AFFECTS ALSA. BEWARE.
+ * When this function is called the device has already been
+ * physically unplugged.
+ * Hence, peasycap->pusb_device is no longer valid.
+ * This function affects alsa.
*/
- /*---------------------------------------------------------------------------*/
static void easycap_usb_disconnect(struct usb_interface *pusb_interface)
{
struct usb_host_interface *pusb_host_interface;
minor = pusb_interface->minor;
JOT(4, "intf[%i]: minor=%i\n", bInterfaceNumber, minor);
+ /* There is nothing to do for Interface Number 1 */
if (1 == bInterfaceNumber)
return;
SAY("ERROR: peasycap is NULL\n");
return;
}
- /*---------------------------------------------------------------------------*/
- /*
- * IF THE WAIT QUEUES ARE NOT CLEARED A DEADLOCK IS POSSIBLE. BEWARE.
- */
- /*---------------------------------------------------------------------------*/
+
+ /* If the waitqueues are not cleared a deadlock is possible */
peasycap->video_eof = 1;
peasycap->audio_eof = 1;
wake_up_interruptible(&(peasycap->wq_video));
default:
break;
}
- /*--------------------------------------------------------------------------*/
- /*
- * DEREGISTER
- *
- * THIS PROCEDURE WILL BLOCK UNTIL easycap_poll(), VIDEO IOCTL AND AUDIO
- * IOCTL ARE ALL UNLOCKED. IF THIS IS NOT DONE AN Oops CAN OCCUR WHEN
- * AN EasyCAP IS UNPLUGGED WHILE THE URBS ARE RUNNING. BEWARE.
- */
- /*--------------------------------------------------------------------------*/
+
+ /*
+ * Deregister
+ * This procedure will block until easycap_poll(),
+ * video and audio ioctl are all unlocked.
+ * If this is not done an oops can occur when an easycap
+ * is unplugged while the urbs are running.
+ */
kd = easycap_isdongle(peasycap);
switch (bInterfaceNumber) {
case 0: {
} else {
SAY("ERROR: %i=kd is bad: cannot lock dongle\n", kd);
}
- /*---------------------------------------------------------------------------*/
if (!peasycap->v4l2_device.name[0]) {
SAM("ERROR: peasycap->v4l2_device.name is empty\n");
if (0 <= kd && DONGLE_MANY > kd)
JOM(4, "intf[%i]: video_unregister_device() minor=%i\n",
bInterfaceNumber, minor);
peasycap->registered_video--;
- /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
if (0 <= kd && DONGLE_MANY > kd) {
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
default:
break;
}
- /*---------------------------------------------------------------------------*/
- /*
- * CALL easycap_delete() IF NO REMAINING REFERENCES TO peasycap
- * (ALSO WHEN ALSA HAS BEEN IN USE)
- */
- /*---------------------------------------------------------------------------*/
+
+ /*
+ * If no remaining references to peasycap,
+ * call easycap_delete.
+ * (Also when alsa has been in use)
+ */
if (!peasycap->kref.refcount.counter) {
SAM("ERROR: peasycap->kref.refcount.counter is zero "
"so cannot call kref_put()\n");
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
JOT(4, "unlocked dongle[%i].mutex_video\n", kd);
}
- /*---------------------------------------------------------------------------*/
JOM(4, "ends\n");
return;
}
- /*****************************************************************************/
- /*---------------------------------------------------------------------------*/
- /*
- * PARAMETERS APPLICABLE TO ENTIRE DRIVER, I.E. BOTH VIDEO AND AUDIO
- */
- /*---------------------------------------------------------------------------*/
+ /* Devices supported by this driver */
static struct usb_device_id easycap_usb_device_id_table[] = {
{USB_DEVICE(USB_EASYCAP_VENDOR_ID, USB_EASYCAP_PRODUCT_ID)},
{ }
return rc;
}
- /*****************************************************************************/
+
static void __exit easycap_module_exit(void)
{
usb_deregister(&easycap_usb_driver);
}
- /*****************************************************************************/
module_init(easycap_module_init);
module_exit(easycap_module_exit);
-
- /*****************************************************************************/