diff --git a/.gitignore b/.gitignore
index 9dacde0a4b2..e20396d2d05 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,6 +23,7 @@
*.symtypes
*.order
modules.builtin
+*.rej
*.elf
*.bin
*.gz
diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml
new file mode 100644
index 00000000000..85164016ed2
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/controls.xml
@@ -0,0 +1,3366 @@
+
+ User Controls
+
+ Devices typically have a number of user-settable controls
+such as brightness, saturation and so on, which would be presented to
+the user on a graphical user interface. But, different devices
+will have different controls available, and furthermore, the range of
+possible values, and the default value will vary from device to
+device. The control ioctls provide the information and a mechanism to
+create a nice user interface for these controls that will work
+correctly with any device.
+
+ All controls are accessed using an ID value. V4L2 defines
+several IDs for specific purposes. Drivers can also implement their
+own custom controls using V4L2_CID_PRIVATE_BASE
+and higher values. The pre-defined control IDs have the prefix
+V4L2_CID_, and are listed in . The ID is used when querying the attributes of
+a control, and when getting or setting the current value.
+
+ Generally applications should present controls to the user
+without assumptions about their purpose. Each control comes with a
+name string the user is supposed to understand. When the purpose is
+non-intuitive the driver writer should provide a user manual, a user
+interface plug-in or a driver specific panel application. Predefined
+IDs were introduced to change a few controls programmatically, for
+example to mute a device during a channel switch.
+
+ Drivers may enumerate different controls after switching
+the current video input or output, tuner or modulator, or audio input
+or output. Different in the sense of other bounds, another default and
+current value, step size or other menu items. A control with a certain
+custom ID can also change name and
+type.
+ It will be more convenient for applications if drivers
+make use of the V4L2_CTRL_FLAG_DISABLED flag, but
+that was never required.
+ Control values are stored globally, they do not
+change when switching except to stay within the reported bounds. They
+also do not change ⪚ when the device is opened or closed, when the
+tuner radio frequency is changed or generally never without
+application request. Since V4L2 specifies no event mechanism, panel
+applications intended to cooperate with other panel applications (be
+they built into a larger application, as a TV viewer) may need to
+regularly poll control values to update their user
+interface.
+ Applications could call an ioctl to request events.
+After another process called &VIDIOC-S-CTRL; or another ioctl changing
+shared properties the &func-select; function would indicate
+readability until any ioctl (querying the properties) is
+called.
+
+
+
+ All controls use machine endianness.
+
+
+
+ Control IDs
+
+ &cs-def;
+
+
+ ID
+ Type
+ Description
+
+
+
+
+ V4L2_CID_BASE
+
+ First predefined ID, equal to
+V4L2_CID_BRIGHTNESS.
+
+
+ V4L2_CID_USER_BASE
+
+ Synonym of V4L2_CID_BASE.
+
+
+ V4L2_CID_BRIGHTNESS
+ integer
+ Picture brightness, or more precisely, the black
+level.
+
+
+ V4L2_CID_CONTRAST
+ integer
+ Picture contrast or luma gain.
+
+
+ V4L2_CID_SATURATION
+ integer
+ Picture color saturation or chroma gain.
+
+
+ V4L2_CID_HUE
+ integer
+ Hue or color balance.
+
+
+ V4L2_CID_AUDIO_VOLUME
+ integer
+ Overall audio volume. Note some drivers also
+provide an OSS or ALSA mixer interface.
+
+
+ V4L2_CID_AUDIO_BALANCE
+ integer
+ Audio stereo balance. Minimum corresponds to all
+the way left, maximum to right.
+
+
+ V4L2_CID_AUDIO_BASS
+ integer
+ Audio bass adjustment.
+
+
+ V4L2_CID_AUDIO_TREBLE
+ integer
+ Audio treble adjustment.
+
+
+ V4L2_CID_AUDIO_MUTE
+ boolean
+ Mute audio, &ie; set the volume to zero, however
+without affecting V4L2_CID_AUDIO_VOLUME. Like
+ALSA drivers, V4L2 drivers must mute at load time to avoid excessive
+noise. Actually the entire device should be reset to a low power
+consumption state.
+
+
+ V4L2_CID_AUDIO_LOUDNESS
+ boolean
+ Loudness mode (bass boost).
+
+
+ V4L2_CID_BLACK_LEVEL
+ integer
+ Another name for brightness (not a synonym of
+V4L2_CID_BRIGHTNESS). This control is deprecated
+and should not be used in new drivers and applications.
+
+
+ V4L2_CID_AUTO_WHITE_BALANCE
+ boolean
+ Automatic white balance (cameras).
+
+
+ V4L2_CID_DO_WHITE_BALANCE
+ button
+ This is an action control. When set (the value is
+ignored), the device will do a white balance and then hold the current
+setting. Contrast this with the boolean
+V4L2_CID_AUTO_WHITE_BALANCE, which, when
+activated, keeps adjusting the white balance.
+
+
+ V4L2_CID_RED_BALANCE
+ integer
+ Red chroma balance.
+
+
+ V4L2_CID_BLUE_BALANCE
+ integer
+ Blue chroma balance.
+
+
+ V4L2_CID_GAMMA
+ integer
+ Gamma adjust.
+
+
+ V4L2_CID_WHITENESS
+ integer
+ Whiteness for grey-scale devices. This is a synonym
+for V4L2_CID_GAMMA. This control is deprecated
+and should not be used in new drivers and applications.
+
+
+ V4L2_CID_EXPOSURE
+ integer
+ Exposure (cameras). [Unit?]
+
+
+ V4L2_CID_AUTOGAIN
+ boolean
+ Automatic gain/exposure control.
+
+
+ V4L2_CID_GAIN
+ integer
+ Gain control.
+
+
+ V4L2_CID_HFLIP
+ boolean
+ Mirror the picture horizontally.
+
+
+ V4L2_CID_VFLIP
+ boolean
+ Mirror the picture vertically.
+
+
+ V4L2_CID_HCENTER_DEPRECATED (formerly V4L2_CID_HCENTER)
+ integer
+ Horizontal image centering. This control is
+deprecated. New drivers and applications should use the Camera class controls
+V4L2_CID_PAN_ABSOLUTE,
+V4L2_CID_PAN_RELATIVE and
+V4L2_CID_PAN_RESET instead.
+
+
+ V4L2_CID_VCENTER_DEPRECATED
+ (formerly V4L2_CID_VCENTER)
+ integer
+ Vertical image centering. Centering is intended to
+physically adjust cameras. For image cropping see
+, for clipping . This
+control is deprecated. New drivers and applications should use the
+Camera class controls
+V4L2_CID_TILT_ABSOLUTE,
+V4L2_CID_TILT_RELATIVE and
+V4L2_CID_TILT_RESET instead.
+
+
+ V4L2_CID_POWER_LINE_FREQUENCY
+ enum
+ Enables a power line frequency filter to avoid
+flicker. Possible values for enum v4l2_power_line_frequency are:
+V4L2_CID_POWER_LINE_FREQUENCY_DISABLED (0),
+V4L2_CID_POWER_LINE_FREQUENCY_50HZ (1) and
+V4L2_CID_POWER_LINE_FREQUENCY_60HZ (2).
+
+
+ V4L2_CID_HUE_AUTO
+ boolean
+ Enables automatic hue control by the device. The
+effect of setting V4L2_CID_HUE while automatic
+hue control is enabled is undefined, drivers should ignore such
+request.
+
+
+ V4L2_CID_WHITE_BALANCE_TEMPERATURE
+ integer
+ This control specifies the white balance settings
+as a color temperature in Kelvin. A driver should have a minimum of
+2800 (incandescent) to 6500 (daylight). For more information about
+color temperature see Wikipedia.
+
+
+ V4L2_CID_SHARPNESS
+ integer
+ Adjusts the sharpness filters in a camera. The
+minimum value disables the filters, higher values give a sharper
+picture.
+
+
+ V4L2_CID_BACKLIGHT_COMPENSATION
+ integer
+ Adjusts the backlight compensation in a camera. The
+minimum value disables backlight compensation.
+
+
+ V4L2_CID_CHROMA_AGC
+ boolean
+ Chroma automatic gain control.
+
+
+ V4L2_CID_CHROMA_GAIN
+ integer
+ Adjusts the Chroma gain control (for use when chroma AGC
+ is disabled).
+
+
+ V4L2_CID_COLOR_KILLER
+ boolean
+ Enable the color killer (&ie; force a black & white image in case of a weak video signal).
+
+
+ V4L2_CID_COLORFX
+ enum
+ Selects a color effect. Possible values for
+enum v4l2_colorfx are:
+V4L2_COLORFX_NONE (0),
+V4L2_COLORFX_BW (1),
+V4L2_COLORFX_SEPIA (2),
+V4L2_COLORFX_NEGATIVE (3),
+V4L2_COLORFX_EMBOSS (4),
+V4L2_COLORFX_SKETCH (5),
+V4L2_COLORFX_SKY_BLUE (6),
+V4L2_COLORFX_GRASS_GREEN (7),
+V4L2_COLORFX_SKIN_WHITEN (8) and
+V4L2_COLORFX_VIVID (9).
+
+
+ V4L2_CID_ROTATE
+ integer
+ Rotates the image by specified angle. Common angles are 90,
+ 270 and 180. Rotating the image to 90 and 270 will reverse the height
+ and width of the display window. It is necessary to set the new height and
+ width of the picture using the &VIDIOC-S-FMT; ioctl according to
+ the rotation angle selected.
+
+
+ V4L2_CID_BG_COLOR
+ integer
+ Sets the background color on the current output device.
+ Background color needs to be specified in the RGB24 format. The
+ supplied 32 bit value is interpreted as bits 0-7 Red color information,
+ bits 8-15 Green color information, bits 16-23 Blue color
+ information and bits 24-31 must be zero.
+
+
+ V4L2_CID_ILLUMINATORS_1
+ V4L2_CID_ILLUMINATORS_2
+ boolean
+ Switch on or off the illuminator 1 or 2 of the device
+ (usually a microscope).
+
+
+ V4L2_CID_LASTP1
+
+ End of the predefined control IDs (currently
+V4L2_CID_ILLUMINATORS_2 + 1).
+
+
+ V4L2_CID_MIN_BUFFERS_FOR_CAPTURE
+ integer
+ This is a read-only control that can be read by the application
+and used as a hint to determine the number of CAPTURE buffers to pass to REQBUFS.
+The value is the minimum number of CAPTURE buffers that is necessary for hardware
+to work.
+
+
+ V4L2_CID_MIN_BUFFERS_FOR_OUTPUT
+ integer
+ This is a read-only control that can be read by the application
+and used as a hint to determine the number of OUTPUT buffers to pass to REQBUFS.
+The value is the minimum number of OUTPUT buffers that is necessary for hardware
+to work.
+
+
+ V4L2_CID_PRIVATE_BASE
+
+ ID of the first custom (driver specific) control.
+Applications depending on particular custom controls should check the
+driver name and version, see .
+
+
+
+
+
+ Applications can enumerate the available controls with the
+&VIDIOC-QUERYCTRL; and &VIDIOC-QUERYMENU; ioctls, get and set a
+control value with the &VIDIOC-G-CTRL; and &VIDIOC-S-CTRL; ioctls.
+Drivers must implement VIDIOC_QUERYCTRL,
+VIDIOC_G_CTRL and
+VIDIOC_S_CTRL when the device has one or more
+controls, VIDIOC_QUERYMENU when it has one or
+more menu type controls.
+
+
+ Enumerating all controls
+
+
+&v4l2-queryctrl; queryctrl;
+&v4l2-querymenu; querymenu;
+
+static void
+enumerate_menu (void)
+{
+ printf (" Menu items:\n");
+
+ memset (&querymenu, 0, sizeof (querymenu));
+ querymenu.id = queryctrl.id;
+
+ for (querymenu.index = queryctrl.minimum;
+ querymenu.index <= queryctrl.maximum;
+ querymenu.index++) {
+ if (0 == ioctl (fd, &VIDIOC-QUERYMENU;, &querymenu)) {
+ printf (" %s\n", querymenu.name);
+ }
+ }
+}
+
+memset (&queryctrl, 0, sizeof (queryctrl));
+
+for (queryctrl.id = V4L2_CID_BASE;
+ queryctrl.id < V4L2_CID_LASTP1;
+ queryctrl.id++) {
+ if (0 == ioctl (fd, &VIDIOC-QUERYCTRL;, &queryctrl)) {
+ if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED)
+ continue;
+
+ printf ("Control %s\n", queryctrl.name);
+
+ if (queryctrl.type == V4L2_CTRL_TYPE_MENU)
+ enumerate_menu ();
+ } else {
+ if (errno == EINVAL)
+ continue;
+
+ perror ("VIDIOC_QUERYCTRL");
+ exit (EXIT_FAILURE);
+ }
+}
+
+for (queryctrl.id = V4L2_CID_PRIVATE_BASE;;
+ queryctrl.id++) {
+ if (0 == ioctl (fd, &VIDIOC-QUERYCTRL;, &queryctrl)) {
+ if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED)
+ continue;
+
+ printf ("Control %s\n", queryctrl.name);
+
+ if (queryctrl.type == V4L2_CTRL_TYPE_MENU)
+ enumerate_menu ();
+ } else {
+ if (errno == EINVAL)
+ break;
+
+ perror ("VIDIOC_QUERYCTRL");
+ exit (EXIT_FAILURE);
+ }
+}
+
+
+
+
+ Changing controls
+
+
+&v4l2-queryctrl; queryctrl;
+&v4l2-control; control;
+
+memset (&queryctrl, 0, sizeof (queryctrl));
+queryctrl.id = V4L2_CID_BRIGHTNESS;
+
+if (-1 == ioctl (fd, &VIDIOC-QUERYCTRL;, &queryctrl)) {
+ if (errno != EINVAL) {
+ perror ("VIDIOC_QUERYCTRL");
+ exit (EXIT_FAILURE);
+ } else {
+ printf ("V4L2_CID_BRIGHTNESS is not supported\n");
+ }
+} else if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) {
+ printf ("V4L2_CID_BRIGHTNESS is not supported\n");
+} else {
+ memset (&control, 0, sizeof (control));
+ control.id = V4L2_CID_BRIGHTNESS;
+ control.value = queryctrl.default_value;
+
+ if (-1 == ioctl (fd, &VIDIOC-S-CTRL;, &control)) {
+ perror ("VIDIOC_S_CTRL");
+ exit (EXIT_FAILURE);
+ }
+}
+
+memset (&control, 0, sizeof (control));
+control.id = V4L2_CID_CONTRAST;
+
+if (0 == ioctl (fd, &VIDIOC-G-CTRL;, &control)) {
+ control.value += 1;
+
+ /* The driver may clamp the value or return ERANGE, ignored here */
+
+ if (-1 == ioctl (fd, &VIDIOC-S-CTRL;, &control)
+ && errno != ERANGE) {
+ perror ("VIDIOC_S_CTRL");
+ exit (EXIT_FAILURE);
+ }
+/* Ignore if V4L2_CID_CONTRAST is unsupported */
+} else if (errno != EINVAL) {
+ perror ("VIDIOC_G_CTRL");
+ exit (EXIT_FAILURE);
+}
+
+control.id = V4L2_CID_AUDIO_MUTE;
+control.value = TRUE; /* silence */
+
+/* Errors ignored */
+ioctl (fd, VIDIOC_S_CTRL, &control);
+
+
+
+
+
+ Extended Controls
+
+
+ Introduction
+
+ The control mechanism as originally designed was meant
+to be used for user settings (brightness, saturation, etc). However,
+it turned out to be a very useful model for implementing more
+complicated driver APIs where each driver implements only a subset of
+a larger API.
+
+ The MPEG encoding API was the driving force behind
+designing and implementing this extended control mechanism: the MPEG
+standard is quite large and the currently supported hardware MPEG
+encoders each only implement a subset of this standard. Further more,
+many parameters relating to how the video is encoded into an MPEG
+stream are specific to the MPEG encoding chip since the MPEG standard
+only defines the format of the resulting MPEG stream, not how the
+video is actually encoded into that format.
+
+ Unfortunately, the original control API lacked some
+features needed for these new uses and so it was extended into the
+(not terribly originally named) extended control API.
+
+ Even though the MPEG encoding API was the first effort
+to use the Extended Control API, nowadays there are also other classes
+of Extended Controls, such as Camera Controls and FM Transmitter Controls.
+The Extended Controls API as well as all Extended Controls classes are
+described in the following text.
+
+
+
+ The Extended Control API
+
+ Three new ioctls are available: &VIDIOC-G-EXT-CTRLS;,
+&VIDIOC-S-EXT-CTRLS; and &VIDIOC-TRY-EXT-CTRLS;. These ioctls act on
+arrays of controls (as opposed to the &VIDIOC-G-CTRL; and
+&VIDIOC-S-CTRL; ioctls that act on a single control). This is needed
+since it is often required to atomically change several controls at
+once.
+
+ Each of the new ioctls expects a pointer to a
+&v4l2-ext-controls;. This structure contains a pointer to the control
+array, a count of the number of controls in that array and a control
+class. Control classes are used to group similar controls into a
+single class. For example, control class
+V4L2_CTRL_CLASS_USER contains all user controls
+(&ie; all controls that can also be set using the old
+VIDIOC_S_CTRL ioctl). Control class
+V4L2_CTRL_CLASS_MPEG contains all controls
+relating to MPEG encoding, etc.
+
+ All controls in the control array must belong to the
+specified control class. An error is returned if this is not the
+case.
+
+ It is also possible to use an empty control array (count
+== 0) to check whether the specified control class is
+supported.
+
+ The control array is a &v4l2-ext-control; array. The
+v4l2_ext_control structure is very similar to
+&v4l2-control;, except for the fact that it also allows for 64-bit
+values and pointers to be passed.
+
+ It is important to realize that due to the flexibility of
+controls it is necessary to check whether the control you want to set
+actually is supported in the driver and what the valid range of values
+is. So use the &VIDIOC-QUERYCTRL; and &VIDIOC-QUERYMENU; ioctls to
+check this. Also note that it is possible that some of the menu
+indices in a control of type V4L2_CTRL_TYPE_MENU
+may not be supported (VIDIOC_QUERYMENU will
+return an error). A good example is the list of supported MPEG audio
+bitrates. Some drivers only support one or two bitrates, others
+support a wider range.
+
+
+ All controls use machine endianness.
+
+
+
+
+ Enumerating Extended Controls
+
+ The recommended way to enumerate over the extended
+controls is by using &VIDIOC-QUERYCTRL; in combination with the
+V4L2_CTRL_FLAG_NEXT_CTRL flag:
+
+
+
+&v4l2-queryctrl; qctrl;
+
+qctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL;
+while (0 == ioctl (fd, &VIDIOC-QUERYCTRL;, &qctrl)) {
+ /* ... */
+ qctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
+}
+
+
+
+ The initial control ID is set to 0 ORed with the
+V4L2_CTRL_FLAG_NEXT_CTRL flag. The
+VIDIOC_QUERYCTRL ioctl will return the first
+control with a higher ID than the specified one. When no such controls
+are found an error is returned.
+
+ If you want to get all controls within a specific control
+class, then you can set the initial
+qctrl.id value to the control class and add
+an extra check to break out of the loop when a control of another
+control class is found:
+
+
+
+qctrl.id = V4L2_CTRL_CLASS_MPEG | V4L2_CTRL_FLAG_NEXT_CTRL;
+while (0 == ioctl (fd, &VIDIOC-QUERYCTRL;, &qctrl)) {
+ if (V4L2_CTRL_ID2CLASS (qctrl.id) != V4L2_CTRL_CLASS_MPEG)
+ break;
+ /* ... */
+ qctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
+ }
+
+
+
+ The 32-bit qctrl.id value is
+subdivided into three bit ranges: the top 4 bits are reserved for
+flags (⪚ V4L2_CTRL_FLAG_NEXT_CTRL) and are not
+actually part of the ID. The remaining 28 bits form the control ID, of
+which the most significant 12 bits define the control class and the
+least significant 16 bits identify the control within the control
+class. It is guaranteed that these last 16 bits are always non-zero
+for controls. The range of 0x1000 and up are reserved for
+driver-specific controls. The macro
+V4L2_CTRL_ID2CLASS(id) returns the control class
+ID based on a control ID.
+
+ If the driver does not support extended controls, then
+VIDIOC_QUERYCTRL will fail when used in
+combination with V4L2_CTRL_FLAG_NEXT_CTRL. In
+that case the old method of enumerating control should be used (see
+1.8). But if it is supported, then it is guaranteed to enumerate over
+all controls, including driver-private controls.
+
+
+
+ Creating Control Panels
+
+ It is possible to create control panels for a graphical
+user interface where the user can select the various controls.
+Basically you will have to iterate over all controls using the method
+described above. Each control class starts with a control of type
+V4L2_CTRL_TYPE_CTRL_CLASS.
+VIDIOC_QUERYCTRL will return the name of this
+control class which can be used as the title of a tab page within a
+control panel.
+
+ The flags field of &v4l2-queryctrl; also contains hints on
+the behavior of the control. See the &VIDIOC-QUERYCTRL; documentation
+for more details.
+
+
+
+ MPEG Control Reference
+
+ Below all controls within the MPEG control class are
+described. First the generic controls, then controls specific for
+certain hardware.
+
+
+ Generic MPEG Controls
+
+
+ MPEG Control IDs
+
+
+
+
+
+
+
+
+
+ ID
+ Type
+ Description
+
+
+
+
+
+ V4L2_CID_MPEG_CLASS
+ class
+ The MPEG class
+descriptor. Calling &VIDIOC-QUERYCTRL; for this control will return a
+description of this control class. This description can be used as the
+caption of a Tab page in a GUI, for example.
+
+
+
+ V4L2_CID_MPEG_STREAM_TYPE
+ enum v4l2_mpeg_stream_type
+ The MPEG-1, -2 or -4
+output stream type. One cannot assume anything here. Each hardware
+MPEG encoder tends to support different subsets of the available MPEG
+stream types. This control is specific to multiplexed MPEG streams.
+The currently defined stream types are:
+
+
+
+
+
+ V4L2_MPEG_STREAM_TYPE_MPEG2_PS
+ MPEG-2 program stream
+
+
+ V4L2_MPEG_STREAM_TYPE_MPEG2_TS
+ MPEG-2 transport stream
+
+
+ V4L2_MPEG_STREAM_TYPE_MPEG1_SS
+ MPEG-1 system stream
+
+
+ V4L2_MPEG_STREAM_TYPE_MPEG2_DVD
+ MPEG-2 DVD-compatible stream
+
+
+ V4L2_MPEG_STREAM_TYPE_MPEG1_VCD
+ MPEG-1 VCD-compatible stream
+
+
+ V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD
+ MPEG-2 SVCD-compatible stream
+
+
+
+
+
+
+ V4L2_CID_MPEG_STREAM_PID_PMT
+ integer
+ Program Map Table
+Packet ID for the MPEG transport stream (default 16)
+
+
+
+ V4L2_CID_MPEG_STREAM_PID_AUDIO
+ integer
+ Audio Packet ID for
+the MPEG transport stream (default 256)
+
+
+
+ V4L2_CID_MPEG_STREAM_PID_VIDEO
+ integer
+ Video Packet ID for
+the MPEG transport stream (default 260)
+
+
+
+ V4L2_CID_MPEG_STREAM_PID_PCR
+ integer
+ Packet ID for the
+MPEG transport stream carrying PCR fields (default 259)
+
+
+
+ V4L2_CID_MPEG_STREAM_PES_ID_AUDIO
+ integer
+ Audio ID for MPEG
+PES
+
+
+
+ V4L2_CID_MPEG_STREAM_PES_ID_VIDEO
+ integer
+ Video ID for MPEG
+PES
+
+
+
+ V4L2_CID_MPEG_STREAM_VBI_FMT
+ enum v4l2_mpeg_stream_vbi_fmt
+ Some cards can embed
+VBI data (⪚ Closed Caption, Teletext) into the MPEG stream. This
+control selects whether VBI data should be embedded, and if so, what
+embedding method should be used. The list of possible VBI formats
+depends on the driver. The currently defined VBI format types
+are:
+
+
+
+
+
+ V4L2_MPEG_STREAM_VBI_FMT_NONE
+ No VBI in the MPEG stream
+
+
+ V4L2_MPEG_STREAM_VBI_FMT_IVTV
+ VBI in private packets, IVTV format (documented
+in the kernel sources in the file Documentation/video4linux/cx2341x/README.vbi)
+
+
+
+
+
+
+ V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ
+ enum v4l2_mpeg_audio_sampling_freq
+ MPEG Audio sampling
+frequency. Possible values are:
+
+
+
+
+
+ V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100
+ 44.1 kHz
+
+
+ V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000
+ 48 kHz
+
+
+ V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000
+ 32 kHz
+
+
+
+
+
+
+ V4L2_CID_MPEG_AUDIO_ENCODING
+ enum v4l2_mpeg_audio_encoding
+ MPEG Audio encoding.
+This control is specific to multiplexed MPEG streams.
+Possible values are:
+
+
+
+
+
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_1
+ MPEG-1/2 Layer I encoding
+
+
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_2
+ MPEG-1/2 Layer II encoding
+
+
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_3
+ MPEG-1/2 Layer III encoding
+
+
+ V4L2_MPEG_AUDIO_ENCODING_AAC
+ MPEG-2/4 AAC (Advanced Audio Coding)
+
+
+ V4L2_MPEG_AUDIO_ENCODING_AC3
+ AC-3 aka ATSC A/52 encoding
+
+
+
+
+
+
+ V4L2_CID_MPEG_AUDIO_L1_BITRATE
+ enum v4l2_mpeg_audio_l1_bitrate
+ MPEG-1/2 Layer I bitrate.
+Possible values are:
+
+
+
+
+
+ V4L2_MPEG_AUDIO_L1_BITRATE_32K
+ 32 kbit/s
+
+ V4L2_MPEG_AUDIO_L1_BITRATE_64K
+ 64 kbit/s
+
+
+ V4L2_MPEG_AUDIO_L1_BITRATE_96K
+ 96 kbit/s
+
+
+ V4L2_MPEG_AUDIO_L1_BITRATE_128K
+ 128 kbit/s
+
+
+ V4L2_MPEG_AUDIO_L1_BITRATE_160K
+ 160 kbit/s
+
+
+ V4L2_MPEG_AUDIO_L1_BITRATE_192K
+ 192 kbit/s
+
+
+ V4L2_MPEG_AUDIO_L1_BITRATE_224K
+ 224 kbit/s
+
+
+ V4L2_MPEG_AUDIO_L1_BITRATE_256K
+ 256 kbit/s
+
+
+ V4L2_MPEG_AUDIO_L1_BITRATE_288K
+ 288 kbit/s
+
+
+ V4L2_MPEG_AUDIO_L1_BITRATE_320K
+ 320 kbit/s
+
+
+ V4L2_MPEG_AUDIO_L1_BITRATE_352K
+ 352 kbit/s
+
+
+ V4L2_MPEG_AUDIO_L1_BITRATE_384K
+ 384 kbit/s
+
+
+ V4L2_MPEG_AUDIO_L1_BITRATE_416K
+ 416 kbit/s
+
+
+ V4L2_MPEG_AUDIO_L1_BITRATE_448K
+ 448 kbit/s
+
+
+
+
+
+
+ V4L2_CID_MPEG_AUDIO_L2_BITRATE
+ enum v4l2_mpeg_audio_l2_bitrate
+ MPEG-1/2 Layer II bitrate.
+Possible values are:
+
+
+
+
+
+ V4L2_MPEG_AUDIO_L2_BITRATE_32K
+ 32 kbit/s
+
+
+ V4L2_MPEG_AUDIO_L2_BITRATE_48K
+ 48 kbit/s
+
+
+ V4L2_MPEG_AUDIO_L2_BITRATE_56K
+ 56 kbit/s
+
+
+ V4L2_MPEG_AUDIO_L2_BITRATE_64K
+ 64 kbit/s
+
+
+ V4L2_MPEG_AUDIO_L2_BITRATE_80K
+ 80 kbit/s
+
+
+ V4L2_MPEG_AUDIO_L2_BITRATE_96K
+ 96 kbit/s
+
+
+ V4L2_MPEG_AUDIO_L2_BITRATE_112K
+ 112 kbit/s
+
+
+ V4L2_MPEG_AUDIO_L2_BITRATE_128K
+ 128 kbit/s
+
+
+ V4L2_MPEG_AUDIO_L2_BITRATE_160K
+ 160 kbit/s
+
+
+ V4L2_MPEG_AUDIO_L2_BITRATE_192K
+ 192 kbit/s
+
+
+ V4L2_MPEG_AUDIO_L2_BITRATE_224K
+ 224 kbit/s
+
+
+ V4L2_MPEG_AUDIO_L2_BITRATE_256K
+ 256 kbit/s
+
+
+ V4L2_MPEG_AUDIO_L2_BITRATE_320K
+ 320 kbit/s
+
+
+ V4L2_MPEG_AUDIO_L2_BITRATE_384K
+ 384 kbit/s
+
+
+
+
+
+
+ V4L2_CID_MPEG_AUDIO_L3_BITRATE
+ enum v4l2_mpeg_audio_l3_bitrate
+ MPEG-1/2 Layer III bitrate.
+Possible values are:
+
+
+
+
+
+ V4L2_MPEG_AUDIO_L3_BITRATE_32K
+ 32 kbit/s
+
+
+ V4L2_MPEG_AUDIO_L3_BITRATE_40K
+ 40 kbit/s
+
+
+ V4L2_MPEG_AUDIO_L3_BITRATE_48K
+ 48 kbit/s
+
+
+ V4L2_MPEG_AUDIO_L3_BITRATE_56K
+ 56 kbit/s
+
+
+ V4L2_MPEG_AUDIO_L3_BITRATE_64K
+ 64 kbit/s
+
+
+ V4L2_MPEG_AUDIO_L3_BITRATE_80K
+ 80 kbit/s
+
+
+ V4L2_MPEG_AUDIO_L3_BITRATE_96K
+ 96 kbit/s
+
+
+ V4L2_MPEG_AUDIO_L3_BITRATE_112K
+ 112 kbit/s
+
+
+ V4L2_MPEG_AUDIO_L3_BITRATE_128K
+ 128 kbit/s
+
+
+ V4L2_MPEG_AUDIO_L3_BITRATE_160K
+ 160 kbit/s
+
+
+ V4L2_MPEG_AUDIO_L3_BITRATE_192K
+ 192 kbit/s
+
+
+ V4L2_MPEG_AUDIO_L3_BITRATE_224K
+ 224 kbit/s
+
+
+ V4L2_MPEG_AUDIO_L3_BITRATE_256K
+ 256 kbit/s
+
+
+ V4L2_MPEG_AUDIO_L3_BITRATE_320K
+ 320 kbit/s
+
+
+
+
+
+
+ V4L2_CID_MPEG_AUDIO_AAC_BITRATE
+ integer
+ AAC bitrate in bits per second.
+
+
+
+ V4L2_CID_MPEG_AUDIO_AC3_BITRATE
+ enum v4l2_mpeg_audio_ac3_bitrate
+ AC-3 bitrate.
+Possible values are:
+
+
+
+
+
+ V4L2_MPEG_AUDIO_AC3_BITRATE_32K
+ 32 kbit/s
+
+
+ V4L2_MPEG_AUDIO_AC3_BITRATE_40K
+ 40 kbit/s
+
+
+ V4L2_MPEG_AUDIO_AC3_BITRATE_48K
+ 48 kbit/s
+
+
+ V4L2_MPEG_AUDIO_AC3_BITRATE_56K
+ 56 kbit/s
+
+
+ V4L2_MPEG_AUDIO_AC3_BITRATE_64K
+ 64 kbit/s
+
+
+ V4L2_MPEG_AUDIO_AC3_BITRATE_80K
+ 80 kbit/s
+
+
+ V4L2_MPEG_AUDIO_AC3_BITRATE_96K
+ 96 kbit/s
+
+
+ V4L2_MPEG_AUDIO_AC3_BITRATE_112K
+ 112 kbit/s
+
+
+ V4L2_MPEG_AUDIO_AC3_BITRATE_128K
+ 128 kbit/s
+
+
+ V4L2_MPEG_AUDIO_AC3_BITRATE_160K
+ 160 kbit/s
+
+
+ V4L2_MPEG_AUDIO_AC3_BITRATE_192K
+ 192 kbit/s
+
+
+ V4L2_MPEG_AUDIO_AC3_BITRATE_224K
+ 224 kbit/s
+
+
+ V4L2_MPEG_AUDIO_AC3_BITRATE_256K
+ 256 kbit/s
+
+
+ V4L2_MPEG_AUDIO_AC3_BITRATE_320K
+ 320 kbit/s
+
+
+ V4L2_MPEG_AUDIO_AC3_BITRATE_384K
+ 384 kbit/s
+
+
+ V4L2_MPEG_AUDIO_AC3_BITRATE_448K
+ 448 kbit/s
+
+
+ V4L2_MPEG_AUDIO_AC3_BITRATE_512K
+ 512 kbit/s
+
+
+ V4L2_MPEG_AUDIO_AC3_BITRATE_576K
+ 576 kbit/s
+
+
+ V4L2_MPEG_AUDIO_AC3_BITRATE_640K
+ 640 kbit/s
+
+
+
+
+
+
+ V4L2_CID_MPEG_AUDIO_MODE
+ enum v4l2_mpeg_audio_mode
+ MPEG Audio mode.
+Possible values are:
+
+
+
+
+
+ V4L2_MPEG_AUDIO_MODE_STEREO
+ Stereo
+
+
+ V4L2_MPEG_AUDIO_MODE_JOINT_STEREO
+ Joint Stereo
+
+
+ V4L2_MPEG_AUDIO_MODE_DUAL
+ Bilingual
+
+
+ V4L2_MPEG_AUDIO_MODE_MONO
+ Mono
+
+
+
+
+
+
+ V4L2_CID_MPEG_AUDIO_MODE_EXTENSION
+ enum v4l2_mpeg_audio_mode_extension
+ Joint Stereo
+audio mode extension. In Layer I and II they indicate which subbands
+are in intensity stereo. All other subbands are coded in stereo. Layer
+III is not (yet) supported. Possible values
+are:
+
+
+
+
+
+ V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4
+ Subbands 4-31 in intensity stereo
+
+
+ V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_8
+ Subbands 8-31 in intensity stereo
+
+
+ V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_12
+ Subbands 12-31 in intensity stereo
+
+
+ V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16
+ Subbands 16-31 in intensity stereo
+
+
+
+
+
+
+ V4L2_CID_MPEG_AUDIO_EMPHASIS
+ enum v4l2_mpeg_audio_emphasis
+ Audio Emphasis.
+Possible values are:
+
+
+
+
+
+ V4L2_MPEG_AUDIO_EMPHASIS_NONE
+ None
+
+
+ V4L2_MPEG_AUDIO_EMPHASIS_50_DIV_15_uS
+ 50/15 microsecond emphasis
+
+
+ V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17
+ CCITT J.17
+
+
+
+
+
+
+ V4L2_CID_MPEG_AUDIO_CRC
+ enum v4l2_mpeg_audio_crc
+ CRC method. Possible
+values are:
+
+
+
+
+
+ V4L2_MPEG_AUDIO_CRC_NONE
+ None
+
+
+ V4L2_MPEG_AUDIO_CRC_CRC16
+ 16 bit parity check
+
+
+
+
+
+
+ V4L2_CID_MPEG_AUDIO_MUTE
+ boolean
+ Mutes the audio when
+capturing. This is not done by muting audio hardware, which can still
+produce a slight hiss, but in the encoder itself, guaranteeing a fixed
+and reproducible audio bitstream. 0 = unmuted, 1 = muted.
+
+
+
+ V4L2_CID_MPEG_VIDEO_ENCODING
+ enum v4l2_mpeg_video_encoding
+ MPEG Video encoding
+method. This control is specific to multiplexed MPEG streams.
+Possible values are:
+
+
+
+
+
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_1
+ MPEG-1 Video encoding
+
+
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_2
+ MPEG-2 Video encoding
+
+
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC
+ MPEG-4 AVC (H.264) Video encoding
+
+
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_ASPECT
+ enum v4l2_mpeg_video_aspect
+ Video aspect.
+Possible values are:
+
+
+
+
+
+ V4L2_MPEG_VIDEO_ASPECT_1x1
+
+
+ V4L2_MPEG_VIDEO_ASPECT_4x3
+
+
+ V4L2_MPEG_VIDEO_ASPECT_16x9
+
+
+ V4L2_MPEG_VIDEO_ASPECT_221x100
+
+
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_B_FRAMES
+ integer
+ Number of B-Frames
+(default 2)
+
+
+
+ V4L2_CID_MPEG_VIDEO_GOP_SIZE
+ integer
+ GOP size (default
+12)
+
+
+
+ V4L2_CID_MPEG_VIDEO_GOP_CLOSURE
+ boolean
+ GOP closure (default
+1)
+
+
+
+ V4L2_CID_MPEG_VIDEO_PULLDOWN
+ boolean
+ Enable 3:2 pulldown
+(default 0)
+
+
+
+ V4L2_CID_MPEG_VIDEO_BITRATE_MODE
+ enum v4l2_mpeg_video_bitrate_mode
+ Video bitrate mode.
+Possible values are:
+
+
+
+
+
+ V4L2_MPEG_VIDEO_BITRATE_MODE_VBR
+ Variable bitrate
+
+
+ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR
+ Constant bitrate
+
+
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_BITRATE
+ integer
+ Video bitrate in bits
+per second.
+
+
+
+ V4L2_CID_MPEG_VIDEO_BITRATE_PEAK
+ integer
+ Peak video bitrate in
+bits per second. Must be larger or equal to the average video bitrate.
+It is ignored if the video bitrate mode is set to constant
+bitrate.
+
+
+
+ V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION
+ integer
+ For every captured
+frame, skip this many subsequent frames (default 0).
+
+
+
+ V4L2_CID_MPEG_VIDEO_MUTE
+ boolean
+
+ "Mutes" the video to a
+fixed color when capturing. This is useful for testing, to produce a
+fixed video bitstream. 0 = unmuted, 1 = muted.
+
+
+
+ V4L2_CID_MPEG_VIDEO_MUTE_YUV
+ integer
+ Sets the "mute" color
+of the video. The supplied 32-bit integer is interpreted as follows (bit
+0 = least significant bit):
+
+
+
+
+
+ Bit 0:7
+ V chrominance information
+
+
+ Bit 8:15
+ U chrominance information
+
+
+ Bit 16:23
+ Y luminance information
+
+
+ Bit 24:31
+ Must be zero.
+
+
+
+
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE
+ boolean
+
+ If enabled the decoder expects to receive a single slice per buffer, otherwise
+the decoder expects a single frame in per buffer. Applicable to the decoder, all codecs.
+
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE
+ boolean
+
+ Enable writing sample aspect ratio in the Video Usability Information.
+Applicable to the H264 encoder.
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC
+ enum v4l2_mpeg_video_h264_vui_sar_idc
+
+ VUI sample aspect ratio indicator for H.264 encoding. The value
+is defined in the table E-1 in the standard. Applicable to the H264 encoder.
+
+
+
+
+
+
+ V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED
+ Unspecified
+
+
+ V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_1x1
+ 1x1
+
+
+ V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_12x11
+ 12x11
+
+
+ V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_10x11
+ 10x11
+
+
+ V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_16x11
+ 16x11
+
+
+ V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_40x33
+ 40x33
+
+
+ V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_24x11
+ 24x11
+
+
+ V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_20x11
+ 20x11
+
+
+ V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_32x11
+ 32x11
+
+
+ V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_80x33
+ 80x33
+
+
+ V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_18x11
+ 18x11
+
+
+ V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_15x11
+ 15x11
+
+
+ V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_64x33
+ 64x33
+
+
+ V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_160x99
+ 160x99
+
+
+ V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_4x3
+ 4x3
+
+
+ V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_3x2
+ 3x2
+
+
+ V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_2x1
+ 2x1
+
+
+ V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED
+ Extended SAR
+
+
+
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH
+ integer
+
+ Extended sample aspect ratio width for H.264 VUI encoding.
+Applicable to the H264 encoder.
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT
+ integer
+
+ Extended sample aspect ratio height for H.264 VUI encoding.
+Applicable to the H264 encoder.
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_H264_LEVEL
+ enum v4l2_mpeg_video_h264_level
+
+ The level information for the H264 video elementary stream.
+Applicable to the H264 encoder.
+Possible values are:
+
+
+
+
+
+ V4L2_MPEG_VIDEO_H264_LEVEL_1_0
+ Level 1.0
+
+
+ V4L2_MPEG_VIDEO_H264_LEVEL_1B
+ Level 1B
+
+
+ V4L2_MPEG_VIDEO_H264_LEVEL_1_1
+ Level 1.1
+
+
+ V4L2_MPEG_VIDEO_H264_LEVEL_1_2
+ Level 1.2
+
+
+ V4L2_MPEG_VIDEO_H264_LEVEL_1_3
+ Level 1.3
+
+
+ V4L2_MPEG_VIDEO_H264_LEVEL_2_0
+ Level 2.0
+
+
+ V4L2_MPEG_VIDEO_H264_LEVEL_2_1
+ Level 2.1
+
+
+ V4L2_MPEG_VIDEO_H264_LEVEL_2_2
+ Level 2.2
+
+
+ V4L2_MPEG_VIDEO_H264_LEVEL_3_0
+ Level 3.0
+
+
+ V4L2_MPEG_VIDEO_H264_LEVEL_3_1
+ Level 3.1
+
+
+ V4L2_MPEG_VIDEO_H264_LEVEL_3_2
+ Level 3.2
+
+
+ V4L2_MPEG_VIDEO_H264_LEVEL_4_0
+ Level 4.0
+
+
+ V4L2_MPEG_VIDEO_H264_LEVEL_4_1
+ Level 4.1
+
+
+ V4L2_MPEG_VIDEO_H264_LEVEL_4_2
+ Level 4.2
+
+
+ V4L2_MPEG_VIDEO_H264_LEVEL_5_0
+ Level 5.0
+
+
+ V4L2_MPEG_VIDEO_H264_LEVEL_5_1
+ Level 5.1
+
+
+
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL
+ enum v4l2_mpeg_video_mpeg4_level
+
+ The level information for the MPEG4 elementary stream.
+Applicable to the MPEG4 encoder.
+Possible values are:
+
+
+
+
+
+ V4L2_MPEG_VIDEO_LEVEL_0
+ Level 0
+
+
+ V4L2_MPEG_VIDEO_LEVEL_0B
+ Level 0b
+
+
+ V4L2_MPEG_VIDEO_LEVEL_1
+ Level 1
+
+
+ V4L2_MPEG_VIDEO_LEVEL_2
+ Level 2
+
+
+ V4L2_MPEG_VIDEO_LEVEL_3
+ Level 3
+
+
+ V4L2_MPEG_VIDEO_LEVEL_3B
+ Level 3b
+
+
+ V4L2_MPEG_VIDEO_LEVEL_4
+ Level 4
+
+
+ V4L2_MPEG_VIDEO_LEVEL_5
+ Level 5
+
+
+
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_H264_PROFILE
+ enum v4l2_mpeg_h264_profile
+
+ The profile information for H264.
+Applicable to the H264 encoder.
+Possible values are:
+
+
+
+
+
+ V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE
+ Baseline profile
+
+
+ V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE
+ Constrained Baseline profile
+
+
+ V4L2_MPEG_VIDEO_H264_PROFILE_MAIN
+ Main profile
+
+
+ V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED
+ Extended profile
+
+
+ V4L2_MPEG_VIDEO_H264_PROFILE_HIGH
+ High profile
+
+
+ V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10
+ High 10 profile
+
+
+ V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422
+ High 422 profile
+
+
+ V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE
+ High 444 Predictive profile
+
+
+ V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10_INTRA
+ High 10 Intra profile
+
+
+ V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422_INTRA
+ High 422 Intra profile
+
+
+ V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_INTRA
+ High 444 Intra profile
+
+
+ V4L2_MPEG_VIDEO_H264_PROFILE_CAVLC_444_INTRA
+ CAVLC 444 Intra profile
+
+
+ V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_BASELINE
+ Scalable Baseline profile
+
+
+ V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH
+ Scalable High profile
+
+
+ V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH_INTRA
+ Scalable High Intra profile
+
+
+ V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH
+ Stereo High profile
+
+
+ V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH
+ Multiview High profile
+
+
+
+
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE
+ enum v4l2_mpeg_mpeg4_profile
+
+ The profile information for MPEG4.
+Applicable to the MPEG4 encoder.
+Possible values are:
+
+
+
+
+
+ V4L2_MPEG_VIDEO_PROFILE_SIMPLE
+ Simple profile
+
+
+ V4L2_MPEG_VIDEO_PROFILE_ADVANCED_SIMPLE
+ Advanced Simple profile
+
+
+ V4L2_MPEG_VIDEO_PROFILE_CORE
+ Core profile
+
+
+ V4L2_MPEG_VIDEO_PROFILE_SIMPLE_SCALABLE
+ Simple Scalable profile
+
+
+ V4L2_MPEG_VIDEO_PROFILE_ADVANCED_CODING_EFFICIENCY
+
+
+
+
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_MAX_REF_PIC
+ integer
+
+ The maximum number of reference pictures used for encoding.
+Applicable to the encoder.
+
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE
+ enum v4l2_mpeg_multi_slice_mode
+
+ Determines how the encoder should handle division of frame into slices.
+Applicable to the encoder.
+Possible values are:
+
+
+
+
+
+ V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE
+ Single slice per frame.
+
+
+ V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB
+ Multiple slices with set maximum number of macroblocks per slice.
+
+
+ V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES
+ Multiple slice with set maximum size in bytes per slice.
+
+
+
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB
+ integer
+
+ The maximum number of macroblocks in a slice. Used when
+V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE is set to V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB.
+Applicable to the encoder.
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES
+ integer
+
+ The maximum size of a slice in bytes. Used when
+V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE is set to V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES.
+Applicable to the encoder.
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE
+ enum v4l2_mpeg_h264_loop_filter_mode
+
+ Loop filter mode for H264 encoder.
+Possible values are:
+
+
+
+
+
+ V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED
+ Loop filter is enabled.
+
+
+ V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED
+ Loop filter is disabled.
+
+
+ V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY
+ Loop filter is disabled at the slice boundary.
+
+
+
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA
+ integer
+
+ Loop filter alpha coefficient, defined in the H264 standard.
+Applicable to the H264 encoder.
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA
+ integer
+
+ Loop filter beta coefficient, defined in the H264 standard.
+Applicable to the H264 encoder.
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE
+ enum v4l2_mpeg_h264_symbol_mode
+
+ Entropy coding mode for H264 - CABAC/CAVALC.
+Applicable to the H264 encoder.
+Possible values are:
+
+
+
+
+
+ V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC
+ Use CAVLC entropy coding.
+
+
+ V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC
+ Use CABAC entropy coding.
+
+
+
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM
+ boolean
+
+ Enable 8X8 transform for H264. Applicable to the H264 encoder.
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB
+ integer
+
+ 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
+top of the frame. Applicable to H264, H263 and MPEG4 encoder.
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE
+ boolean
+
+ Frame level rate control enable.
+If this control is disabled then the quantization parameter for each frame type is constant and set with appropriate controls
+(e.g. V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP).
+If frame rate control is enabled then quantization parameter is adjusted to meet the chosen bitrate. Minimum and maximum value
+for the quantization parameter can be set with appropriate controls (e.g. V4L2_CID_MPEG_VIDEO_H263_MIN_QP).
+Applicable to encoders.
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE
+ boolean
+
+ Macroblock level rate control enable.
+Applicable to the MPEG4 and H264 encoders.
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_MPEG4_QPEL
+ boolean
+
+ Quarter pixel motion estimation for MPEG4. Applicable to the MPEG4 encoder.
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP
+ integer
+
+ Quantization parameter for an I frame for H263. Valid range: from 1 to 31.
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_H263_MIN_QP
+ integer
+
+ Minimum quantization parameter for H263. Valid range: from 1 to 31.
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_H263_MAX_QP
+ integer
+
+ Maximum quantization parameter for H263. Valid range: from 1 to 31.
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP
+ integer
+
+ Quantization parameter for an P frame for H263. Valid range: from 1 to 31.
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP
+ integer
+
+ Quantization parameter for an B frame for H263. Valid range: from 1 to 31.
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP
+ integer
+
+ Quantization parameter for an I frame for H264. Valid range: from 0 to 51.
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_H264_MIN_QP
+ integer
+
+ Minimum quantization parameter for H264. Valid range: from 0 to 51.
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_H264_MAX_QP
+ integer
+
+ Maximum quantization parameter for H264. Valid range: from 0 to 51.
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP
+ integer
+
+ Quantization parameter for an P frame for H264. Valid range: from 0 to 51.
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP
+ integer
+
+ Quantization parameter for an B frame for H264. Valid range: from 0 to 51.
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP
+ integer
+
+ Quantization parameter for an I frame for MPEG4. Valid range: from 1 to 31.
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP
+ integer
+
+ Minimum quantization parameter for MPEG4. Valid range: from 1 to 31.
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP
+ integer
+
+ Maximum quantization parameter for MPEG4. Valid range: from 1 to 31.
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP
+ integer
+
+ Quantization parameter for an P frame for MPEG4. Valid range: from 1 to 31.
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP
+ integer
+
+ Quantization parameter for an B frame for MPEG4. Valid range: from 1 to 31.
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_VBV_SIZE
+ integer
+
+ 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 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.".
+Applicable to the MPEG1, MPEG2, MPEG4 encoders.
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE
+ integer
+
+ 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.
+Applicable to the H264 encoder.
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_H264_I_PERIOD
+ integer
+
+ Period between I-frames in the open GOP for H264. In case of an open GOP
+this is the period between two I-frames. The period between IDR (Instantaneous Decoding Refresh) frames is taken from the GOP_SIZE control.
+An IDR frame, which stands for Instantaneous Decoding Refresh is an I-frame after which no prior frames are
+referenced. This means that a stream can be restarted from an IDR frame without the need to store or decode any
+previous frames. Applicable to the H264 encoder.
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_HEADER_MODE
+ enum v4l2_mpeg_header_mode
+
+ Determines whether the header is returned as the first buffer or is
+it returned together with the first frame. Applicable to encoders.
+Possible values are:
+
+
+
+
+
+ V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE
+ The stream header is returned separately in the first buffer.
+
+
+ V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME
+ The stream header is returned together with the first encoded frame.
+
+
+
+
+
+
+ V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER
+ boolean
+ Enabled the deblocking post processing filter for MPEG4 decoder.
+Applicable to the MPEG4 decoder.
+
+
+
+ V4L2_CID_MPEG_VIDEO_MPEG4_VOP_TIME_RES
+ integer
+ vop_time_increment_resolution value for MPEG4. Applicable to the MPEG4 encoder.
+
+
+
+ V4L2_CID_MPEG_VIDEO_MPEG4_VOP_TIME_INC
+ integer
+ vop_time_increment value for MPEG4. Applicable to the MPEG4 encoder.
+
+
+
+
+
+
+
+
+ MFC 5.1 MPEG Controls
+
+ The following MPEG class controls deal with MPEG
+decoding and encoding settings that are specific to the Multi Format Codec 5.1 device present
+in the S5P family of SoCs by Samsung.
+
+
+
+ MFC 5.1 Control IDs
+
+
+
+
+
+
+
+
+
+ ID
+ Type
+ Description
+
+
+
+
+
+ V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE
+ integer
+ If the display delay is enabled then the decoder has to return a
+CAPTURE buffer after processing a certain number of OUTPUT buffers. If this number is low, then it may result in
+buffers not being dequeued in display order. In addition hardware may still use those buffers as reference, thus
+application should not write to those buffers. This feature can be used for example for generating thumbnails of videos.
+Applicable to the H264 decoder.
+
+
+
+
+ V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY
+ integer
+ Display delay value for H264 decoder.
+The decoder is forced to return a decoded frame after the set 'display delay' number of frames. If this number is
+low it may result in frames returned out of dispaly order, in addition the hardware may still be using the returned buffer
+as a reference picture for subsequent frames.
+
+
+
+
+ V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P
+ integer
+ The number of reference pictures used for encoding a P picture.
+Applicable to the H264 encoder.
+
+
+
+ V4L2_CID_MPEG_MFC51_VIDEO_PADDING
+ boolean
+ Padding enable in the encoder - use a color instead of repeating border pixels.
+Applicable to encoders.
+
+
+
+ V4L2_CID_MPEG_MFC51_VIDEO_PADDING_YUV
+ integer
+ Padding color in the encoder. Applicable to encoders. The supplied 32-bit integer is interpreted as follows (bit
+0 = least significant bit):
+
+
+
+
+
+ Bit 0:7
+ V chrominance information
+
+
+ Bit 8:15
+ U chrominance information
+
+
+ Bit 16:23
+ Y luminance information
+
+
+ Bit 24:31
+ Must be zero.
+
+
+
+
+
+
+ V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF
+ integer
+ Reaction coefficient for MFC rate control. Applicable to encoders.
+Note 1: Valid only when the frame level RC is enabled.
+Note 2: For tight CBR, this field must be small (ex. 2 ~ 10).
+For VBR, this field must be large (ex. 100 ~ 1000).
+Note 3: It is not recommended to use the greater number than FRAME_RATE * (10^9 / BIT_RATE).
+
+
+
+
+ V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_DARK
+ boolean
+ Adaptive rate control for dark region.
+Valid only when H.264 and macroblock level RC is enabled (V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE).
+Applicable to the H264 encoder.
+
+
+
+ V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_SMOOTH
+ boolean
+ Adaptive rate control for smooth region.
+Valid only when H.264 and macroblock level RC is enabled (V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE).
+Applicable to the H264 encoder.
+
+
+
+ V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC
+ boolean
+ Adaptive rate control for static region.
+Valid only when H.264 and macroblock level RC is enabled (V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE).
+Applicable to the H264 encoder.
+
+
+
+ V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_ACTIVITY
+ boolean
+ Adaptive rate control for activity region.
+Valid only when H.264 and macroblock level RC is enabled (V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE).
+Applicable to the H264 encoder.
+
+
+
+ V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE
+ enum v4l2_mpeg_mfc51_frame_skip_mode
+
+
+Indicates in what conditions the encoder should skip frames. If encoding a frame would cause the encoded stream to be larger then
+a chosen data limit then the frame will be skipped.
+Possible values are:
+
+
+
+
+
+ V4L2_MPEG_MFC51_FRAME_SKIP_MODE_DISABLED
+ Frame skip mode is disabled.
+
+
+ V4L2_MPEG_MFC51_FRAME_SKIP_MODE_LEVEL_LIMIT
+ Frame skip mode enabled and buffer limit is set by the chosen level and is defined by the standard.
+
+
+ V4L2_MPEG_MFC51_FRAME_SKIP_MODE_BUF_LIMIT
+ Frame skip mode enabled and buffer limit is set by the VBV (MPEG1/2/4) or CPB (H264) buffer size control.
+
+
+
+
+
+
+ V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT
+ integer
+ Enable rate-control with fixed target bit.
+If this setting is enabled, then the rate control logic of the encoder will calculate the average bitrate
+for a GOP and keep it below or equal the set bitrate target. Otherwise the rate control logic calculates the
+overall average bitrate for the stream and keeps it below or equal to the set bitrate. In the first case
+the average bitrate for the whole stream will be smaller then the set bitrate. This is caused because the
+average is calculated for smaller number of frames, on the other hand enabling this setting will ensure that
+the stream will meet tight bandwidth contraints. Applicable to encoders.
+
+
+
+
+ V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE
+ enum v4l2_mpeg_mfc51_force_frame_type
+
+ Force a frame type for the next queued buffer. Applicable to encoders.
+Possible values are:
+
+
+
+
+
+ V4L2_MPEG_MFC51_FORCE_FRAME_TYPE_DISABLED
+ Forcing a specific frame type disabled.
+
+
+ V4L2_MPEG_MFC51_FORCE_FRAME_TYPE_I_FRAME
+ Force an I-frame.
+
+
+ V4L2_MPEG_MFC51_FORCE_FRAME_TYPE_NOT_CODED
+ Force a non-coded frame.
+
+
+
+
+
+
+
+
+
+
+ CX2341x MPEG Controls
+
+ The following MPEG class controls deal with MPEG
+encoding settings that are specific to the Conexant CX23415 and
+CX23416 MPEG encoding chips.
+
+
+ CX2341x Control IDs
+
+
+
+
+
+
+
+
+
+ ID
+ Type
+ Description
+
+
+
+
+
+ V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE
+ enum v4l2_mpeg_cx2341x_video_spatial_filter_mode
+ Sets the Spatial
+Filter mode (default MANUAL). Possible values
+are:
+
+
+
+
+
+ V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL
+ Choose the filter manually
+
+
+ V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO
+ Choose the filter automatically
+
+
+
+
+
+
+ V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER
+ integer (0-15)
+ The setting for the
+Spatial Filter. 0 = off, 15 = maximum. (Default is 0.)
+
+
+
+ V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE
+ enum v4l2_mpeg_cx2341x_video_luma_spatial_filter_type
+ Select the algorithm
+to use for the Luma Spatial Filter (default
+1D_HOR). Possible values:
+
+
+
+
+
+ V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF
+ No filter
+
+
+ V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR
+ One-dimensional horizontal
+
+
+ V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_VERT
+ One-dimensional vertical
+
+
+ V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_HV_SEPARABLE
+ Two-dimensional separable
+
+
+ V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE
+ Two-dimensional symmetrical
+non-separable
+
+
+
+
+
+
+ V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE
+ enum v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type
+ Select the algorithm
+for the Chroma Spatial Filter (default 1D_HOR).
+Possible values are:
+
+
+
+
+
+ V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF
+ No filter
+
+
+ V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR
+ One-dimensional horizontal
+
+
+
+
+
+
+ V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE
+ enum v4l2_mpeg_cx2341x_video_temporal_filter_mode
+ Sets the Temporal
+Filter mode (default MANUAL). Possible values
+are:
+
+
+
+
+
+ V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL
+ Choose the filter manually
+
+
+ V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO
+ Choose the filter automatically
+
+
+
+
+
+
+ V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER
+ integer (0-31)
+ The setting for the
+Temporal Filter. 0 = off, 31 = maximum. (Default is 8 for full-scale
+capturing and 0 for scaled capturing.)
+
+
+
+ V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE
+ enum v4l2_mpeg_cx2341x_video_median_filter_type
+ Median Filter Type
+(default OFF). Possible values are:
+
+
+
+
+
+ V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF
+ No filter
+
+
+ V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR
+ Horizontal filter
+
+
+ V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_VERT
+ Vertical filter
+
+
+ V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR_VERT
+ Horizontal and vertical filter
+
+
+ V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG
+ Diagonal filter
+
+
+
+
+
+
+ V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM
+ integer (0-255)
+ Threshold above which
+the luminance median filter is enabled (default 0)
+
+
+
+ V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP
+ integer (0-255)
+ Threshold below which
+the luminance median filter is enabled (default 255)
+
+
+
+ V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM
+ integer (0-255)
+ Threshold above which
+the chroma median filter is enabled (default 0)
+
+
+
+ V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP
+ integer (0-255)
+ Threshold below which
+the chroma median filter is enabled (default 255)
+
+
+
+ V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS
+ boolean
+
+ The CX2341X MPEG encoder
+can insert one empty MPEG-2 PES packet into the stream between every
+four video frames. The packet size is 2048 bytes, including the
+packet_start_code_prefix and stream_id fields. The stream_id is 0xBF
+(private stream 2). The payload consists of 0x00 bytes, to be filled
+in by the application. 0 = do not insert, 1 = insert packets.
+
+
+
+
+
+
+
+
+ Camera Control Reference
+
+ The Camera class includes controls for mechanical (or
+equivalent digital) features of a device such as controllable lenses
+or sensors.
+
+
+ Camera Control IDs
+
+
+
+
+
+
+
+
+
+ ID
+ Type
+ Description
+
+
+
+
+
+ V4L2_CID_CAMERA_CLASS
+ class
+ The Camera class
+descriptor. Calling &VIDIOC-QUERYCTRL; for this control will return a
+description of this control class.
+
+
+
+
+ V4L2_CID_EXPOSURE_AUTO
+ enum v4l2_exposure_auto_type
+ Enables automatic
+adjustments of the exposure time and/or iris aperture. The effect of
+manual changes of the exposure time or iris aperture while these
+features are enabled is undefined, drivers should ignore such
+requests. Possible values are:
+
+
+
+
+
+ V4L2_EXPOSURE_AUTO
+ Automatic exposure time, automatic iris
+aperture.
+
+
+ V4L2_EXPOSURE_MANUAL
+ Manual exposure time, manual iris.
+
+
+ V4L2_EXPOSURE_SHUTTER_PRIORITY
+ Manual exposure time, auto iris.
+
+
+ V4L2_EXPOSURE_APERTURE_PRIORITY
+ Auto exposure time, manual iris.
+
+
+
+
+
+
+
+ V4L2_CID_EXPOSURE_ABSOLUTE
+ integer
+ Determines the exposure
+time of the camera sensor. The exposure time is limited by the frame
+interval. Drivers should interpret the values as 100 µs units,
+where the value 1 stands for 1/10000th of a second, 10000 for 1 second
+and 100000 for 10 seconds.
+
+
+
+
+ V4L2_CID_EXPOSURE_AUTO_PRIORITY
+ boolean
+ When
+V4L2_CID_EXPOSURE_AUTO is set to
+AUTO or APERTURE_PRIORITY,
+this control determines if the device may dynamically vary the frame
+rate. By default this feature is disabled (0) and the frame rate must
+remain constant.
+
+
+
+
+ V4L2_CID_PAN_RELATIVE
+ integer
+ This control turns the
+camera horizontally by the specified amount. The unit is undefined. A
+positive value moves the camera to the right (clockwise when viewed
+from above), a negative value to the left. A value of zero does not
+cause motion. This is a write-only control.
+
+
+
+
+ V4L2_CID_TILT_RELATIVE
+ integer
+ This control turns the
+camera vertically by the specified amount. The unit is undefined. A
+positive value moves the camera up, a negative value down. A value of
+zero does not cause motion. This is a write-only control.
+
+
+
+
+ V4L2_CID_PAN_RESET
+ button
+ When this control is set,
+the camera moves horizontally to the default position.
+
+
+
+
+ V4L2_CID_TILT_RESET
+ button
+ When this control is set,
+the camera moves vertically to the default position.
+
+
+
+
+ V4L2_CID_PAN_ABSOLUTE
+ integer
+ This control
+turns the camera horizontally to the specified position. Positive
+values move the camera to the right (clockwise when viewed from above),
+negative values to the left. Drivers should interpret the values as arc
+seconds, with valid values between -180 * 3600 and +180 * 3600
+inclusive.
+
+
+
+
+ V4L2_CID_TILT_ABSOLUTE
+ integer
+ This control
+turns the camera vertically to the specified position. Positive values
+move the camera up, negative values down. Drivers should interpret the
+values as arc seconds, with valid values between -180 * 3600 and +180
+* 3600 inclusive.
+
+
+
+
+ V4L2_CID_FOCUS_ABSOLUTE
+ integer
+ This control sets the
+focal point of the camera to the specified position. The unit is
+undefined. Positive values set the focus closer to the camera,
+negative values towards infinity.
+
+
+
+
+ V4L2_CID_FOCUS_RELATIVE
+ integer
+ This control moves the
+focal point of the camera by the specified amount. The unit is
+undefined. Positive values move the focus closer to the camera,
+negative values towards infinity. This is a write-only control.
+
+
+
+
+ V4L2_CID_FOCUS_AUTO
+ boolean
+ Enables automatic focus
+adjustments. The effect of manual focus adjustments while this feature
+is enabled is undefined, drivers should ignore such requests.
+
+
+
+
+ V4L2_CID_ZOOM_ABSOLUTE
+ integer
+ Specify the objective lens
+focal length as an absolute value. The zoom unit is driver-specific and its
+value should be a positive integer.
+
+
+
+
+ V4L2_CID_ZOOM_RELATIVE
+ integer
+ Specify the objective lens
+focal length relatively to the current value. Positive values move the zoom
+lens group towards the telephoto direction, negative values towards the
+wide-angle direction. The zoom unit is driver-specific. This is a write-only control.
+
+
+
+
+ V4L2_CID_ZOOM_CONTINUOUS
+ integer
+ Move the objective lens group
+at the specified speed until it reaches physical device limits or until an
+explicit request to stop the movement. A positive value moves the zoom lens
+group towards the telephoto direction. A value of zero stops the zoom lens
+group movement. A negative value moves the zoom lens group towards the
+wide-angle direction. The zoom speed unit is driver-specific.
+
+
+
+
+ V4L2_CID_IRIS_ABSOLUTE
+ integer
+ This control sets the
+camera's aperture to the specified value. The unit is undefined.
+Larger values open the iris wider, smaller values close it.
+
+
+
+
+ V4L2_CID_IRIS_RELATIVE
+ integer
+ This control modifies the
+camera's aperture by the specified amount. The unit is undefined.
+Positive values open the iris one step further, negative values close
+it one step further. This is a write-only control.
+
+
+
+
+ V4L2_CID_PRIVACY
+ boolean
+ Prevent video from being acquired
+by the camera. When this control is set to TRUE (1), no
+image can be captured by the camera. Common means to enforce privacy are
+mechanical obturation of the sensor and firmware image processing, but the
+device is not restricted to these methods. Devices that implement the privacy
+control must support read access and may support write access.
+
+
+
+ V4L2_CID_BAND_STOP_FILTER
+ integer
+ Switch the band-stop filter of a
+camera sensor on or off, or specify its strength. Such band-stop filters can
+be used, for example, to filter out the fluorescent light component.
+
+
+
+
+
+
+
+
+ FM Transmitter Control Reference
+
+ The FM Transmitter (FM_TX) class includes controls for common features of
+FM transmissions capable devices. Currently this class includes parameters for audio
+compression, pilot tone generation, audio deviation limiter, RDS transmission and
+tuning power features.
+
+
+ FM_TX Control IDs
+
+
+
+
+
+
+
+
+
+
+ ID
+ Type
+ Description
+
+
+
+
+
+ V4L2_CID_FM_TX_CLASS
+ class
+ The FM_TX class
+descriptor. Calling &VIDIOC-QUERYCTRL; for this control will return a
+description of this control class.
+
+
+ V4L2_CID_RDS_TX_DEVIATION
+ integer
+
+ Configures RDS signal frequency deviation level in Hz.
+The range and step are driver-specific.
+
+
+ V4L2_CID_RDS_TX_PI
+ integer
+
+ Sets the RDS Programme Identification field
+for transmission.
+
+
+ V4L2_CID_RDS_TX_PTY
+ integer
+
+ Sets the RDS Programme Type field for transmission.
+This encodes up to 31 pre-defined programme types.
+
+
+ V4L2_CID_RDS_TX_PS_NAME
+ string
+
+ Sets the Programme Service name (PS_NAME) for transmission.
+It is intended for static display on a receiver. It is the primary aid to listeners in programme service
+identification and selection. In Annex E of , the RDS specification,
+there is a full description of the correct character encoding for Programme Service name strings.
+Also from RDS specification, PS is usually a single eight character text. However, it is also possible
+to find receivers which can scroll strings sized as 8 x N characters. So, this control must be configured
+with steps of 8 characters. The result is it must always contain a string with size multiple of 8.
+
+
+ V4L2_CID_RDS_TX_RADIO_TEXT
+ string
+
+ Sets the Radio Text info for transmission. It is a textual description of
+what is being broadcasted. RDS Radio Text can be applied when broadcaster wishes to transmit longer PS names,
+programme-related information or any other text. In these cases, RadioText should be used in addition to
+V4L2_CID_RDS_TX_PS_NAME. The encoding for Radio Text strings is also fully described
+in Annex E of . The length of Radio Text strings depends on which RDS Block is being
+used to transmit it, either 32 (2A block) or 64 (2B block). However, it is also possible
+to find receivers which can scroll strings sized as 32 x N or 64 x N characters. So, this control must be configured
+with steps of 32 or 64 characters. The result is it must always contain a string with size multiple of 32 or 64.
+
+
+ V4L2_CID_AUDIO_LIMITER_ENABLED
+ boolean
+
+ Enables or disables the audio deviation limiter feature.
+The limiter is useful when trying to maximize the audio volume, minimize receiver-generated
+distortion and prevent overmodulation.
+
+
+
+ V4L2_CID_AUDIO_LIMITER_RELEASE_TIME
+ integer
+
+ Sets the audio deviation limiter feature release time.
+Unit is in useconds. Step and range are driver-specific.
+
+
+ V4L2_CID_AUDIO_LIMITER_DEVIATION
+ integer
+
+ Configures audio frequency deviation level in Hz.
+The range and step are driver-specific.
+
+
+ V4L2_CID_AUDIO_COMPRESSION_ENABLED
+ boolean
+
+ Enables or disables the audio compression feature.
+This feature amplifies signals below the threshold by a fixed gain and compresses audio
+signals above the threshold by the ratio of Threshold/(Gain + Threshold).
+
+
+ V4L2_CID_AUDIO_COMPRESSION_GAIN
+ integer
+
+ Sets the gain for audio compression feature. It is
+a dB value. The range and step are driver-specific.
+
+
+ V4L2_CID_AUDIO_COMPRESSION_THRESHOLD
+ integer
+
+ Sets the threshold level for audio compression freature.
+It is a dB value. The range and step are driver-specific.
+
+
+ V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME
+ integer
+
+ Sets the attack time for audio compression feature.
+It is a useconds value. The range and step are driver-specific.
+
+
+ V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME
+ integer
+
+ Sets the release time for audio compression feature.
+It is a useconds value. The range and step are driver-specific.
+
+
+ V4L2_CID_PILOT_TONE_ENABLED
+ boolean
+
+ Enables or disables the pilot tone generation feature.
+
+
+ V4L2_CID_PILOT_TONE_DEVIATION
+ integer
+
+ Configures pilot tone frequency deviation level. Unit is
+in Hz. The range and step are driver-specific.
+
+
+ V4L2_CID_PILOT_TONE_FREQUENCY
+ integer
+
+ Configures pilot tone frequency value. Unit is
+in Hz. The range and step are driver-specific.
+
+
+ V4L2_CID_TUNE_PREEMPHASIS
+ integer
+
+ Configures the pre-emphasis value for broadcasting.
+A pre-emphasis filter is applied to the broadcast to accentuate the high audio frequencies.
+Depending on the region, a time constant of either 50 or 75 useconds is used. The enum v4l2_preemphasis
+defines possible values for pre-emphasis. Here they are:
+
+
+
+
+ V4L2_PREEMPHASIS_DISABLED
+ No pre-emphasis is applied.
+
+
+ V4L2_PREEMPHASIS_50_uS
+ A pre-emphasis of 50 uS is used.
+
+
+ V4L2_PREEMPHASIS_75_uS
+ A pre-emphasis of 75 uS is used.
+
+
+
+
+
+
+ V4L2_CID_TUNE_POWER_LEVEL
+ integer
+
+ Sets the output power level for signal transmission.
+Unit is in dBuV. Range and step are driver-specific.
+
+
+ V4L2_CID_TUNE_ANTENNA_CAPACITOR
+ integer
+
+ This selects the value of antenna tuning capacitor
+manually or automatically if set to zero. Unit, range and step are driver-specific.
+
+
+
+
+
+
+For more details about RDS specification, refer to
+ document, from CENELEC.
+
+
+
+ Flash Control Reference
+
+
+ Experimental
+
+ This is an experimental
+interface and may change in the future.
+
+
+
+ The V4L2 flash controls are intended to provide generic access
+ to flash controller devices. Flash controller devices are
+ typically used in digital cameras.
+
+
+
+ The interface can support both LED and xenon flash devices. As
+ of writing this, there is no xenon flash driver using this
+ interface.
+
+
+
+ Supported use cases
+
+
+ Unsynchronised LED flash (software strobe)
+
+
+ Unsynchronised LED flash is controlled directly by the
+ host as the sensor. The flash must be enabled by the host
+ before the exposure of the image starts and disabled once
+ it ends. The host is fully responsible for the timing of
+ the flash.
+
+
+ Example of such device: Nokia N900.
+
+
+
+ Synchronised LED flash (hardware strobe)
+
+
+ The synchronised LED flash is pre-programmed by the host
+ (power and timeout) but controlled by the sensor through a
+ strobe signal from the sensor to the flash.
+
+
+
+ The sensor controls the flash duration and timing. This
+ information typically must be made available to the
+ sensor.
+
+
+
+
+
+ LED flash as torch
+
+
+ LED flash may be used as torch in conjunction with another
+ use case involving camera or individually.
+
+
+
+
+
+
+
+ Flash Control IDs
+
+
+
+
+
+
+
+
+
+
+ ID
+ Type
+ Description
+
+
+
+
+
+ V4L2_CID_FLASH_CLASS
+ class
+
+
+ The FLASH class descriptor.
+
+
+ V4L2_CID_FLASH_LED_MODE
+ menu
+
+
+ Defines the mode of the flash LED,
+ the high-power white LED attached to the flash controller.
+ Setting this control may not be possible in presence of
+ some faults. See V4L2_CID_FLASH_FAULT.
+
+
+
+
+
+ V4L2_FLASH_LED_MODE_NONE
+ Off.
+
+
+ V4L2_FLASH_LED_MODE_FLASH
+ Flash mode.
+
+
+ V4L2_FLASH_LED_MODE_TORCH
+ Torch mode. See V4L2_CID_FLASH_TORCH_INTENSITY.
+
+
+
+
+
+ V4L2_CID_FLASH_STROBE_SOURCE
+ menu
+
+ Defines the source of the flash LED
+ strobe.
+
+
+
+
+
+ V4L2_FLASH_STROBE_SOURCE_SOFTWARE
+ The flash strobe is triggered by using
+ the V4L2_CID_FLASH_STROBE control.
+
+
+ V4L2_FLASH_STROBE_SOURCE_EXTERNAL
+ The flash strobe is triggered by an
+ external source. Typically this is a sensor,
+ which makes it possible to synchronises the
+ flash strobe start to exposure start.
+
+
+
+
+
+ V4L2_CID_FLASH_STROBE
+ button
+
+
+ Strobe flash. Valid when
+ V4L2_CID_FLASH_LED_MODE is set to
+ V4L2_FLASH_LED_MODE_FLASH and V4L2_CID_FLASH_STROBE_SOURCE
+ is set to V4L2_FLASH_STROBE_SOURCE_SOFTWARE. Setting this
+ control may not be possible in presence of some faults.
+ See V4L2_CID_FLASH_FAULT.
+
+
+ V4L2_CID_FLASH_STROBE_STOP
+ button
+
+ Stop flash strobe immediately.
+
+
+ V4L2_CID_FLASH_STROBE_STATUS
+ boolean
+
+
+ Strobe status: whether the flash
+ is strobing at the moment or not. This is a read-only
+ control.
+
+
+ V4L2_CID_FLASH_TIMEOUT
+ integer
+
+
+ Hardware timeout for flash. The
+ flash strobe is stopped after this period of time has
+ passed from the start of the strobe.
+
+
+ V4L2_CID_FLASH_INTENSITY
+ integer
+
+
+ Intensity of the flash strobe when
+ the flash LED is in flash mode
+ (V4L2_FLASH_LED_MODE_FLASH). The unit should be milliamps
+ (mA) if possible.
+
+
+ V4L2_CID_FLASH_TORCH_INTENSITY
+ integer
+
+
+ Intensity of the flash LED in
+ torch mode (V4L2_FLASH_LED_MODE_TORCH). The unit should be
+ milliamps (mA) if possible. Setting this control may not
+ be possible in presence of some faults. See
+ V4L2_CID_FLASH_FAULT.
+
+
+ V4L2_CID_FLASH_INDICATOR_INTENSITY
+ integer
+
+
+ Intensity of the indicator LED.
+ The indicator LED may be fully independent of the flash
+ LED. The unit should be microamps (uA) if possible.
+
+
+ V4L2_CID_FLASH_FAULT
+ bitmask
+
+
+ Faults related to the flash. The
+ faults tell about specific problems in the flash chip
+ itself or the LEDs attached to it. Faults may prevent
+ further use of some of the flash controls. In particular,
+ V4L2_CID_FLASH_LED_MODE is set to V4L2_FLASH_LED_MODE_NONE
+ if the fault affects the flash LED. Exactly which faults
+ have such an effect is chip dependent. Reading the faults
+ resets the control and returns the chip to a usable state
+ if possible.
+
+
+
+
+
+ V4L2_FLASH_FAULT_OVER_VOLTAGE
+ Flash controller voltage to the flash LED
+ has exceeded the limit specific to the flash
+ controller.
+
+
+ V4L2_FLASH_FAULT_TIMEOUT
+ The flash strobe was still on when
+ the timeout set by the user ---
+ V4L2_CID_FLASH_TIMEOUT control --- has expired.
+ Not all flash controllers may set this in all
+ such conditions.
+
+
+ V4L2_FLASH_FAULT_OVER_TEMPERATURE
+ The flash controller has overheated.
+
+
+ V4L2_FLASH_FAULT_SHORT_CIRCUIT
+ The short circuit protection of the flash
+ controller has been triggered.
+
+
+
+
+
+ V4L2_CID_FLASH_CHARGE
+ boolean
+
+ Enable or disable charging of the xenon
+ flash capacitor.
+
+
+ V4L2_CID_FLASH_READY
+ boolean
+
+
+ Is the flash ready to strobe?
+ Xenon flashes require their capacitors charged before
+ strobing. LED flashes often require a cooldown period
+ after strobe during which another strobe will not be
+ possible. This is a read-only control.
+
+
+
+
+
+
+
+
+
+
diff --git a/Documentation/DocBook/v4l/pixfmt.xml b/Documentation/DocBook/v4l/pixfmt.xml
index deb660207f9..8af0a42e84a 100644
--- a/Documentation/DocBook/v4l/pixfmt.xml
+++ b/Documentation/DocBook/v4l/pixfmt.xml
@@ -741,10 +741,55 @@ information.
V4L2_PIX_FMT_MPEG'MPEG'
- MPEG stream. The actual format is determined by
+ MPEG multiplexed stream. The actual format is determined by
extended control V4L2_CID_MPEG_STREAM_TYPE, see
.
+
+ V4L2_PIX_FMT_H264
+ 'H264'
+ H264 video elementary stream with start codes.
+
+
+ V4L2_PIX_FMT_H264_NO_SC
+ 'AVC1'
+ H264 video elementary stream without start codes.
+
+
+ V4L2_PIX_FMT_H263
+ 'H263'
+ H263 video elementary stream.
+
+
+ V4L2_PIX_FMT_MPEG1
+ 'MPG1'
+ MPEG1 video elementary stream.
+
+
+ V4L2_PIX_FMT_MPEG2
+ 'MPG2'
+ MPEG2 video elementary stream.
+
+
+ V4L2_PIX_FMT_MPEG4
+ 'MPG4'
+ MPEG4 video elementary stream.
+
+
+ V4L2_PIX_FMT_XVID
+ 'XVID'
+ Xvid video elementary stream.
+
+
+ V4L2_PIX_FMT_VC1_ANNEX_G
+ 'VC1G'
+ VC1, SMPTE 421M Annex G compliant stream.
+
+
+ V4L2_PIX_FMT_VC1_ANNEX_L
+ 'VC1L'
+ VC1, SMPTE 421M Annex L compliant stream.
+
diff --git a/Documentation/HOWTO b/Documentation/HOWTO
index 81bc1a9ab9d..59c080f084e 100644
--- a/Documentation/HOWTO
+++ b/Documentation/HOWTO
@@ -218,16 +218,16 @@ The development process
Linux kernel development process currently consists of a few different
main kernel "branches" and lots of different subsystem-specific kernel
branches. These different branches are:
- - main 2.6.x kernel tree
- - 2.6.x.y -stable kernel tree
- - 2.6.x -git kernel patches
+ - main 3.x kernel tree
+ - 3.x.y -stable kernel tree
+ - 3.x -git kernel patches
- subsystem specific kernel trees and patches
- - the 2.6.x -next kernel tree for integration tests
+ - the 3.x -next kernel tree for integration tests
-2.6.x kernel tree
+3.x kernel tree
-----------------
-2.6.x kernels are maintained by Linus Torvalds, and can be found on
-kernel.org in the pub/linux/kernel/v2.6/ directory. Its development
+3.x kernels are maintained by Linus Torvalds, and can be found on
+kernel.org in the pub/linux/kernel/v3.x/ directory. Its development
process is as follows:
- As soon as a new kernel is released a two weeks window is open,
during this period of time maintainers can submit big diffs to
@@ -262,21 +262,21 @@ mailing list about kernel releases:
released according to perceived bug status, not according to a
preconceived timeline."
-2.6.x.y -stable kernel tree
+3.x.y -stable kernel tree
---------------------------
-Kernels with 4-part versions are -stable kernels. They contain
+Kernels with 3-part versions are -stable kernels. They contain
relatively small and critical fixes for security problems or significant
-regressions discovered in a given 2.6.x kernel.
+regressions discovered in a given 3.x kernel.
This is the recommended branch for users who want the most recent stable
kernel and are not interested in helping test development/experimental
versions.
-If no 2.6.x.y kernel is available, then the highest numbered 2.6.x
+If no 3.x.y kernel is available, then the highest numbered 3.x
kernel is the current stable kernel.
-2.6.x.y are maintained by the "stable" team , and are
-released as needs dictate. The normal release period is approximately
+3.x.y are maintained by the "stable" team , and
+are released as needs dictate. The normal release period is approximately
two weeks, but it can be longer if there are no pressing problems. A
security-related problem, instead, can cause a release to happen almost
instantly.
@@ -285,7 +285,7 @@ The file Documentation/stable_kernel_rules.txt in the kernel tree
documents what kinds of changes are acceptable for the -stable tree, and
how the release process works.
-2.6.x -git patches
+3.x -git patches
------------------
These are daily snapshots of Linus' kernel tree which are managed in a
git repository (hence the name.) These patches are usually released
@@ -317,13 +317,13 @@ revisions to it, and maintainers can mark patches as under review,
accepted, or rejected. Most of these patchwork sites are listed at
http://patchwork.kernel.org/.
-2.6.x -next kernel tree for integration tests
+3.x -next kernel tree for integration tests
---------------------------------------------
-Before updates from subsystem trees are merged into the mainline 2.6.x
+Before updates from subsystem trees are merged into the mainline 3.x
tree, they need to be integration-tested. For this purpose, a special
testing repository exists into which virtually all subsystem trees are
pulled on an almost daily basis:
- http://git.kernel.org/?p=linux/kernel/git/sfr/linux-next.git
+ http://git.kernel.org/?p=linux/kernel/git/next/linux-next.git
http://linux.f-seidel.de/linux-next/pmwiki/
This way, the -next kernel gives a summary outlook onto what will be
diff --git a/Documentation/block/row-iosched.txt b/Documentation/block/row-iosched.txt
new file mode 100644
index 00000000000..987bd883444
--- /dev/null
+++ b/Documentation/block/row-iosched.txt
@@ -0,0 +1,117 @@
+Introduction
+============
+
+The ROW scheduling algorithm will be used in mobile devices as default
+block layer IO scheduling algorithm. ROW stands for "READ Over WRITE"
+which is the main requests dispatch policy of this algorithm.
+
+The ROW IO scheduler was developed with the mobile devices needs in
+mind. In mobile devices we favor user experience upon everything else,
+thus we want to give READ IO requests as much priority as possible.
+The main idea of the ROW scheduling policy is:
+If there are READ requests in pipe - dispatch them but don't starve
+the WRITE requests too much.
+
+Software description
+====================
+The requests are kept in queues according to their priority. The
+dispatching of requests is done in a Round Robin manner with a
+different slice for each queue. The dispatch quantum for a specific
+queue is defined according to the queues priority. READ queues are
+given bigger dispatch quantum than the WRITE queues, within a dispatch
+cycle.
+
+At the moment there are 6 types of queues the requests are
+distributed to:
+- High priority READ queue
+- High priority Synchronous WRITE queue
+- Regular priority READ queue
+- Regular priority Synchronous WRITE queue
+- Regular priority WRITE queue
+- Low priority READ queue
+
+If in a certain dispatch cycle one of the queues was empty and didn't
+use its quantum that queue will be marked as "un-served". If we're in a
+middle of a dispatch cycle dispatching from queue Y and a request
+arrives for queue X that was un-served in the previous cycle, if X's
+priority is higher than Y's, queue X will be preempted in the favor of
+queue Y. This won't mean that cycle is restarted. The "dispatched"
+counter of queue X will remain unchanged. Once queue Y uses up it's quantum
+(or there will be no more requests left on it) we'll switch back to queue X
+and allow it to finish it's quantum.
+
+For READ requests queues we allow idling in within a dispatch quantum in
+order to give the application a chance to insert more requests. Idling
+means adding some extra time for serving a certain queue even if the
+queue is empty. The idling is enabled if we identify the application is
+inserting requests in a high frequency.
+
+For idling on READ queues we use timer mechanism. When the timer expires,
+if there are requests in the scheduler we will signal the underlying driver
+(for example the MMC driver) to fetch another request for dispatch.
+
+The ROW algorithm takes the scheduling policy one step further, making
+it a bit more "user-needs oriented", by allowing the application to
+hint on the urgency of its requests. For example: even among the READ
+requests several requests may be more urgent for completion then others.
+The former will go to the High priority READ queue, that is given the
+bigger dispatch quantum than any other queue.
+
+ROW scheduler will support special services for block devices that
+supports High Priority Requests. That is, the scheduler may inform the
+device upon urgent requests using new callback make_urgent_request.
+In addition it will support rescheduling of requests that were
+interrupted. For example, if the device issues a long write request and
+a sudden high priority read interrupt pops in, the scheduler will
+inform the device about the urgent request, so the device can stop the
+current write request and serve the high priority read request. In such
+a case the device may also send back to the scheduler the reminder of
+the interrupted write request, such that the scheduler may continue
+sending high priority requests without the need to interrupt the
+ongoing write again and again. The write remainder will be sent later on
+according to the scheduler policy.
+
+Design
+======
+Existing algorithms (cfq, deadline) sort the io requests according LBA.
+When deciding on the next request to dispatch they choose the closest
+request to the current disk head position (from handling last
+dispatched request). This is done in order to reduce the disk head
+movement to a minimum.
+We feel that this functionality isn't really needed in mobile devices.
+Usually applications that write/read large chunks of data insert the
+requests in already sorted LBA order. Thus dealing with sort trees adds
+unnecessary complexity.
+
+We're planing to try this enhancement in the future to check if the
+performance is influenced by it.
+
+SMP/multi-core
+==============
+At the moment the code is acceded from 2 contexts:
+- Application context (from block/elevator layer): adding the requests.
+- Underlying driver context (for example the mmc driver thread): dispatching
+ the requests and notifying on completion.
+
+One lock is used to synchronize between the two. This lock is provided
+by the underlying driver along with the dispatch queue.
+
+Config options
+==============
+1. hp_read_quantum: dispatch quantum for the high priority READ queue
+2. rp_read_quantum: dispatch quantum for the regular priority READ queue
+3. hp_swrite_quantum: dispatch quantum for the high priority Synchronous
+ WRITE queue
+4. rp_swrite_quantum: dispatch quantum for the regular priority
+ Synchronous WRITE queue
+5. rp_write_quantum: dispatch quantum for the regular priority WRITE
+ queue
+6. lp_read_quantum: dispatch quantum for the low priority READ queue
+7. lp_swrite_quantum: dispatch quantum for the low priority Synchronous
+ WRITE queue
+8. read_idle: how long to idle on read queue in Msec (in case idling
+ is enabled on that queue).
+9. read_idle_freq: frequency of inserting READ requests that will
+ trigger idling. This is the time in Msec between inserting two READ
+ requests
+
diff --git a/Documentation/development-process/5.Posting b/Documentation/development-process/5.Posting
index 903a2546f13..8a48c9b6286 100644
--- a/Documentation/development-process/5.Posting
+++ b/Documentation/development-process/5.Posting
@@ -271,10 +271,10 @@ copies should go to:
the linux-kernel list.
- If you are fixing a bug, think about whether the fix should go into the
- next stable update. If so, stable@kernel.org should get a copy of the
- patch. Also add a "Cc: stable@kernel.org" to the tags within the patch
- itself; that will cause the stable team to get a notification when your
- fix goes into the mainline.
+ next stable update. If so, stable@vger.kernel.org should get a copy of
+ the patch. Also add a "Cc: stable@vger.kernel.org" to the tags within
+ the patch itself; that will cause the stable team to get a notification
+ when your fix goes into the mainline.
When selecting recipients for a patch, it is good to have an idea of who
you think will eventually accept the patch and get it merged. While it
diff --git a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware
index 3348d313fbe..511dd4df04c 100644
--- a/Documentation/dvb/get_dvb_firmware
+++ b/Documentation/dvb/get_dvb_firmware
@@ -114,7 +114,7 @@ sub tda10045 {
sub tda10046 {
my $sourcefile = "TT_PCI_2.19h_28_11_2006.zip";
- my $url = "http://www.tt-download.com/download/updates/219/$sourcefile";
+ my $url = "http://technotrend.com.ua/download/software/219/$sourcefile";
my $hash = "6a7e1e2f2644b162ff0502367553c72d";
my $outfile = "dvb-fe-tda10046.fw";
my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index b1c921c2751..6ff5af4499c 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -6,14 +6,6 @@ be removed from this file.
---------------------------
-What: x86 floppy disable_hlt
-When: 2012
-Why: ancient workaround of dubious utility clutters the
- code used by everybody else.
-Who: Len Brown
-
----------------------------
-
What: CONFIG_APM_CPU_IDLE, and its ability to call APM BIOS in idle
When: 2012
Why: This optional sub-feature of APM is of dubious reliability,
diff --git a/Documentation/hwmon/jc42 b/Documentation/hwmon/jc42
index a22ecf48f25..52729a756c1 100644
--- a/Documentation/hwmon/jc42
+++ b/Documentation/hwmon/jc42
@@ -7,21 +7,29 @@ Supported chips:
Addresses scanned: I2C 0x18 - 0x1f
Datasheets:
http://www.analog.com/static/imported-files/data_sheets/ADT7408.pdf
- * IDT TSE2002B3, TS3000B3
- Prefix: 'tse2002b3', 'ts3000b3'
+ * Atmel AT30TS00
+ Prefix: 'at30ts00'
Addresses scanned: I2C 0x18 - 0x1f
Datasheets:
- http://www.idt.com/products/getdoc.cfm?docid=18715691
- http://www.idt.com/products/getdoc.cfm?docid=18715692
+ http://www.atmel.com/Images/doc8585.pdf
+ * IDT TSE2002B3, TSE2002GB2, TS3000B3, TS3000GB2
+ Prefix: 'tse2002', 'ts3000'
+ Addresses scanned: I2C 0x18 - 0x1f
+ Datasheets:
+ http://www.idt.com/sites/default/files/documents/IDT_TSE2002B3C_DST_20100512_120303152056.pdf
+ http://www.idt.com/sites/default/files/documents/IDT_TSE2002GB2A1_DST_20111107_120303145914.pdf
+ http://www.idt.com/sites/default/files/documents/IDT_TS3000B3A_DST_20101129_120303152013.pdf
+ http://www.idt.com/sites/default/files/documents/IDT_TS3000GB2A1_DST_20111104_120303151012.pdf
* Maxim MAX6604
Prefix: 'max6604'
Addresses scanned: I2C 0x18 - 0x1f
Datasheets:
http://datasheets.maxim-ic.com/en/ds/MAX6604.pdf
- * Microchip MCP9805, MCP98242, MCP98243, MCP9843
- Prefixes: 'mcp9805', 'mcp98242', 'mcp98243', 'mcp9843'
+ * Microchip MCP9804, MCP9805, MCP98242, MCP98243, MCP9843
+ Prefixes: 'mcp9804', 'mcp9805', 'mcp98242', 'mcp98243', 'mcp9843'
Addresses scanned: I2C 0x18 - 0x1f
Datasheets:
+ http://ww1.microchip.com/downloads/en/DeviceDoc/22203C.pdf
http://ww1.microchip.com/downloads/en/DeviceDoc/21977b.pdf
http://ww1.microchip.com/downloads/en/DeviceDoc/21996a.pdf
http://ww1.microchip.com/downloads/en/DeviceDoc/22153c.pdf
@@ -48,6 +56,12 @@ Supported chips:
Datasheets:
http://www.st.com/stonline/products/literature/ds/13447/stts424.pdf
http://www.st.com/stonline/products/literature/ds/13448/stts424e02.pdf
+ * ST Microelectronics STTS2002, STTS3000
+ Prefix: 'stts2002', 'stts3000'
+ Addresses scanned: I2C 0x18 - 0x1f
+ Datasheets:
+ http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATASHEET/CD00225278.pdf
+ http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATA_BRIEF/CD00270920.pdf
* JEDEC JC 42.4 compliant temperature sensor chips
Prefix: 'jc42'
Addresses scanned: I2C 0x18 - 0x1f
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index aa47be71df4..389923426ca 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -531,6 +531,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
UART at the specified I/O port or MMIO address,
switching to the matching ttyS device later. The
options are the same as for ttyS, above.
+ hvc Use the hypervisor console device . This is for
+ both Xen and PowerPC hypervisors.
If the device connected to the port is not a TTY but a braille
device, prepend "brl," before the device type, for instance
@@ -679,6 +681,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
earlyprintk= [X86,SH,BLACKFIN]
earlyprintk=vga
+ earlyprintk=xen
earlyprintk=serial[,ttySn[,baudrate]]
earlyprintk=ttySn[,baudrate]
earlyprintk=dbgp[debugController#]
@@ -696,6 +699,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
The VGA output is eventually overwritten by the real
console.
+ The xen output can only be used by Xen PV guests.
+
ekgdboc= [X86,KGDB] Allow early kernel console debugging
ekgdboc=kbd
@@ -1764,6 +1769,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
noresidual [PPC] Don't use residual data on PReP machines.
+ nordrand [X86] Disable the direct use of the RDRAND
+ instruction even if it is supported by the
+ processor. RDRAND is still available to user
+ space applications.
+
noresume [SWSUSP] Disables resume and restores original swap
space.
diff --git a/Documentation/networking/ifenslave.c b/Documentation/networking/ifenslave.c
index 2bac9618c34..50f1dc49f48 100644
--- a/Documentation/networking/ifenslave.c
+++ b/Documentation/networking/ifenslave.c
@@ -539,12 +539,14 @@ static int if_getconfig(char *ifname)
metric = 0;
} else
metric = ifr.ifr_metric;
+ printf("The result of SIOCGIFMETRIC is %d\n", metric);
strcpy(ifr.ifr_name, ifname);
if (ioctl(skfd, SIOCGIFMTU, &ifr) < 0)
mtu = 0;
else
mtu = ifr.ifr_mtu;
+ printf("The result of SIOCGIFMTU is %d\n", mtu);
strcpy(ifr.ifr_name, ifname);
if (ioctl(skfd, SIOCGIFDSTADDR, &ifr) < 0) {
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index bfe924217f2..890fce9b368 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -147,7 +147,7 @@ tcp_adv_win_scale - INTEGER
(if tcp_adv_win_scale > 0) or bytes-bytes/2^(-tcp_adv_win_scale),
if it is <= 0.
Possible values are [-31, 31], inclusive.
- Default: 2
+ Default: 1
tcp_allowed_congestion_control - STRING
Show/set the congestion control choices available to non-privileged
@@ -407,7 +407,7 @@ tcp_rmem - vector of 3 INTEGERs: min, default, max
net.core.rmem_max. Calling setsockopt() with SO_RCVBUF disables
automatic tuning of that socket's receive buffer size, in which
case this value is ignored.
- Default: between 87380B and 4MB, depending on RAM size.
+ Default: between 87380B and 6MB, depending on RAM size.
tcp_sack - BOOLEAN
Enable select acknowledgments (SACKS).
@@ -534,6 +534,11 @@ tcp_thin_dupack - BOOLEAN
Documentation/networking/tcp-thin.txt
Default: 0
+tcp_challenge_ack_limit - INTEGER
+ Limits number of Challenge ACK sent per second, as recommended
+ in RFC 5961 (Improving TCP's Robustness to Blind In-Window Attacks)
+ Default: 100
+
UDP variables:
udp_mem - vector of 3 INTEGERs: min, pressure, max
diff --git a/Documentation/stable_kernel_rules.txt b/Documentation/stable_kernel_rules.txt
index 21fd05c28e7..22bf11b846c 100644
--- a/Documentation/stable_kernel_rules.txt
+++ b/Documentation/stable_kernel_rules.txt
@@ -1,4 +1,4 @@
-Everything you ever wanted to know about Linux 2.6 -stable releases.
+Everything you ever wanted to know about Linux -stable releases.
Rules on what kind of patches are accepted, and which ones are not, into the
"-stable" tree:
@@ -12,6 +12,12 @@ Rules on what kind of patches are accepted, and which ones are not, into the
marked CONFIG_BROKEN), an oops, a hang, data corruption, a real
security issue, or some "oh, that's not good" issue. In short, something
critical.
+ - Serious issues as reported by a user of a distribution kernel may also
+ be considered if they fix a notable performance or interactivity issue.
+ As these fixes are not as obvious and have a higher risk of a subtle
+ regression they should only be submitted by a distribution kernel
+ maintainer and include an addendum linking to a bugzilla entry if it
+ exists and additional information on the user-visible impact.
- New device IDs and quirks are also accepted.
- No "theoretical race condition" issues, unless an explanation of how the
race can be exploited is also provided.
@@ -35,10 +41,10 @@ Procedure for submitting patches to the -stable tree:
cherry-picked than this can be specified in the following format in
the sign-off area:
- Cc: # .32.x: a1f84a3: sched: Check for idle
- Cc: # .32.x: 1b9508f: sched: Rate-limit newidle
- Cc: # .32.x: fd21073: sched: Fix affinity logic
- Cc: # .32.x
+ Cc: # 3.3.x: a1f84a3: sched: Check for idle
+ Cc: # 3.3.x: 1b9508f: sched: Rate-limit newidle
+ Cc: # 3.3.x: fd21073: sched: Fix affinity logic
+ Cc: # 3.3.x
Signed-off-by: Ingo Molnar
The tag sequence has the meaning of:
@@ -72,6 +78,15 @@ Review cycle:
security kernel team, and not go through the normal review cycle.
Contact the kernel security team for more details on this procedure.
+Trees:
+
+ - The queues of patches, for both completed versions and in progress
+ versions can be found at:
+ http://git.kernel.org/?p=linux/kernel/git/stable/stable-queue.git
+ - The finalized and tagged releases of all stable kernels can be found
+ in separate branches per version at:
+ http://git.kernel.org/?p=linux/kernel/git/stable/linux-stable.git
+
Review committee:
diff --git a/Documentation/trace/postprocess/trace-vmscan-postprocess.pl b/Documentation/trace/postprocess/trace-vmscan-postprocess.pl
index 12cecc83cd9..4a37c4759cd 100644
--- a/Documentation/trace/postprocess/trace-vmscan-postprocess.pl
+++ b/Documentation/trace/postprocess/trace-vmscan-postprocess.pl
@@ -379,10 +379,10 @@ sub process_events {
# To closer match vmstat scanning statistics, only count isolate_both
# and isolate_inactive as scanning. isolate_active is rotation
- # isolate_inactive == 0
- # isolate_active == 1
- # isolate_both == 2
- if ($isolate_mode != 1) {
+ # isolate_inactive == 1
+ # isolate_active == 2
+ # isolate_both == 3
+ if ($isolate_mode != 2) {
$perprocesspid{$process_pid}->{HIGH_NR_SCANNED} += $nr_scanned;
}
$perprocesspid{$process_pid}->{HIGH_NR_CONTIG_DIRTY} += $nr_contig_dirty;
diff --git a/Documentation/usb/usbmon.txt b/Documentation/usb/usbmon.txt
index a4efa0462f0..5335fa8b06e 100644
--- a/Documentation/usb/usbmon.txt
+++ b/Documentation/usb/usbmon.txt
@@ -47,10 +47,11 @@ This allows to filter away annoying devices that talk continuously.
2. Find which bus connects to the desired device
-Run "cat /proc/bus/usb/devices", and find the T-line which corresponds to
-the device. Usually you do it by looking for the vendor string. If you have
-many similar devices, unplug one and compare two /proc/bus/usb/devices outputs.
-The T-line will have a bus number. Example:
+Run "cat /sys/kernel/debug/usb/devices", and find the T-line which corresponds
+to the device. Usually you do it by looking for the vendor string. If you have
+many similar devices, unplug one and compare the two
+/sys/kernel/debug/usb/devices outputs. The T-line will have a bus number.
+Example:
T: Bus=03 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=12 MxCh= 0
D: Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
@@ -58,7 +59,10 @@ P: Vendor=0557 ProdID=2004 Rev= 1.00
S: Manufacturer=ATEN
S: Product=UC100KM V2.00
-Bus=03 means it's bus 3.
+"Bus=03" means it's bus 3. Alternatively, you can look at the output from
+"lsusb" and get the bus number from the appropriate line. Example:
+
+Bus 003 Device 002: ID 0557:2004 ATEN UC100KM V2.00
3. Start 'cat'
diff --git a/MAINTAINERS b/MAINTAINERS
index 34e24186584..9b893d75d85 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2491,7 +2491,7 @@ S: Maintained
F: drivers/net/eexpress.*
ETHERNET BRIDGE
-M: Stephen Hemminger
+M: Stephen Hemminger
L: bridge@lists.linux-foundation.org
L: netdev@vger.kernel.org
W: http://www.linuxfoundation.org/en/Net:Bridge
@@ -4327,7 +4327,7 @@ S: Supported
F: drivers/infiniband/hw/nes/
NETEM NETWORK EMULATOR
-M: Stephen Hemminger
+M: Stephen Hemminger
L: netem@lists.linux-foundation.org
S: Maintained
F: net/sched/sch_netem.c
@@ -5247,7 +5247,7 @@ F: Documentation/blockdev/ramdisk.txt
F: drivers/block/brd.c
RANDOM NUMBER DRIVER
-M: Matt Mackall
+M: Theodore Ts'o"
S: Maintained
F: drivers/char/random.c
@@ -5779,7 +5779,7 @@ S: Maintained
F: drivers/usb/misc/sisusbvga/
SKGE, SKY2 10/100/1000 GIGABIT ETHERNET DRIVERS
-M: Stephen Hemminger
+M: Stephen Hemminger
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/skge.*
@@ -6039,7 +6039,7 @@ F: arch/alpha/kernel/srm_env.c
STABLE BRANCH
M: Greg Kroah-Hartman
-L: stable@kernel.org
+L: stable@vger.kernel.org
S: Maintained
STAGING SUBSYSTEM
diff --git a/Makefile b/Makefile
index 6d356e7dca4..082934a8d79 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
VERSION = 3
PATCHLEVEL = 0
-SUBLEVEL = 16
+SUBLEVEL = 81
EXTRAVERSION =
NAME = Sneaky Weasel
diff --git a/arch/alpha/include/asm/atomic.h b/arch/alpha/include/asm/atomic.h
index e756d04b6cd..b15162fedcc 100644
--- a/arch/alpha/include/asm/atomic.h
+++ b/arch/alpha/include/asm/atomic.h
@@ -14,8 +14,8 @@
*/
-#define ATOMIC_INIT(i) ( (atomic_t) { (i) } )
-#define ATOMIC64_INIT(i) ( (atomic64_t) { (i) } )
+#define ATOMIC_INIT(i) { (i) }
+#define ATOMIC64_INIT(i) { (i) }
#define atomic_read(v) (*(volatile int *)&(v)->counter)
#define atomic64_read(v) (*(volatile long *)&(v)->counter)
diff --git a/arch/alpha/include/asm/futex.h b/arch/alpha/include/asm/futex.h
index e8a761aee08..f939794363a 100644
--- a/arch/alpha/include/asm/futex.h
+++ b/arch/alpha/include/asm/futex.h
@@ -108,7 +108,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
" lda $31,3b-2b(%0)\n"
" .previous\n"
: "+r"(ret), "=&r"(prev), "=&r"(cmp)
- : "r"(uaddr), "r"((long)oldval), "r"(newval)
+ : "r"(uaddr), "r"((long)(int)oldval), "r"(newval)
: "memory");
*uval = prev;
diff --git a/arch/alpha/include/asm/socket.h b/arch/alpha/include/asm/socket.h
index 06edfefc337..3eeb47c5018 100644
--- a/arch/alpha/include/asm/socket.h
+++ b/arch/alpha/include/asm/socket.h
@@ -69,9 +69,11 @@
#define SO_RXQ_OVFL 40
+#ifdef __KERNEL__
/* O_NONBLOCK clashes with the bits used for socket types. Therefore we
* have to define SOCK_NONBLOCK to a different value here.
*/
#define SOCK_NONBLOCK 0x40000000
+#endif /* __KERNEL__ */
#endif /* _ASM_SOCKET_H */
diff --git a/arch/alpha/kernel/sys_nautilus.c b/arch/alpha/kernel/sys_nautilus.c
index 99c0f46f6b9..dc616b34610 100644
--- a/arch/alpha/kernel/sys_nautilus.c
+++ b/arch/alpha/kernel/sys_nautilus.c
@@ -189,6 +189,10 @@ nautilus_machine_check(unsigned long vector, unsigned long la_ptr)
extern void free_reserved_mem(void *, void *);
extern void pcibios_claim_one_bus(struct pci_bus *);
+static struct resource irongate_io = {
+ .name = "Irongate PCI IO",
+ .flags = IORESOURCE_IO,
+};
static struct resource irongate_mem = {
.name = "Irongate PCI MEM",
.flags = IORESOURCE_MEM,
@@ -210,6 +214,7 @@ nautilus_init_pci(void)
irongate = pci_get_bus_and_slot(0, 0);
bus->self = irongate;
+ bus->resource[0] = &irongate_io;
bus->resource[1] = &irongate_mem;
pci_bus_size_bridges(bus);
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 7f6fc98a0d9..679a96d5fa2 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1199,7 +1199,7 @@ config ARM_ERRATA_743622
depends on CPU_V7
help
This option enables the workaround for the 743622 Cortex-A9
- (r2p0..r2p2) erratum. Under very rare conditions, a faulty
+ (r2p*) erratum. Under very rare conditions, a faulty
optimisation in the Cortex-A9 Store Buffer may lead to data
corruption. This workaround sets a specific bit in the diagnostic
register of the Cortex-A9 which disables the Store Buffer
@@ -1277,6 +1277,42 @@ config KSAPI
Scorpion processor supported hardware performance counters on a per
thread basis or AXI counters on an overall system basis.
+config ARM_ERRATA_764369
+ bool "ARM errata: Data cache line maintenance operation by MVA may not succeed"
+ depends on CPU_V7 && SMP
+ help
+ This option enables the workaround for erratum 764369
+ affecting Cortex-A9 MPCore with two or more processors (all
+ current revisions). Under certain timing circumstances, a data
+ cache line maintenance operation by MVA targeting an Inner
+ Shareable memory region may fail to proceed up to either the
+ Point of Coherency or to the Point of Unification of the
+ system. This workaround adds a DSB instruction before the
+ relevant cache maintenance functions and sets a specific bit
+ in the diagnostic control register of the SCU.
+
+config PL310_ERRATA_769419
+ bool "PL310 errata: no automatic Store Buffer drain"
+ depends on CACHE_L2X0
+ help
+ On revisions of the PL310 prior to r3p2, the Store Buffer does
+ not automatically drain. This can cause normal, non-cacheable
+ writes to be retained when the memory system is idle, leading
+ to suboptimal I/O performance for drivers using coherent DMA.
+ This option adds a write barrier to the cpu_idle loop so that,
+ on systems with an outer cache, the store buffer is drained
+ explicitly.
+
+config ARM_ERRATA_775420
+ bool "ARM errata: A data cache maintenance operation which aborts, might lead to deadlock"
+ depends on CPU_V7
+ help
+ This option enables the workaround for the 775420 Cortex-A9 (r2p2,
+ r2p6,r2p8,r2p10,r3p0) erratum. In case a date cache maintenance
+ operation aborts with MMU exception, it might cause the processor
+ to deadlock. This workaround puts DSB before executing ISB if
+ an abort may occur on cache maintenance.
+
endmenu
source "arch/arm/common/Kconfig"
@@ -1341,32 +1377,6 @@ source "drivers/pci/Kconfig"
source "drivers/pcmcia/Kconfig"
-config ARM_ERRATA_764369
- bool "ARM errata: Data cache line maintenance operation by MVA may not succeed"
- depends on CPU_V7 && SMP
- help
- This option enables the workaround for erratum 764369
- affecting Cortex-A9 MPCore with two or more processors (all
- current revisions). Under certain timing circumstances, a data
- cache line maintenance operation by MVA targeting an Inner
- Shareable memory region may fail to proceed up to either the
- Point of Coherency or to the Point of Unification of the
- system. This workaround adds a DSB instruction before the
- relevant cache maintenance functions and sets a specific bit
- in the diagnostic control register of the SCU.
-
-config PL310_ERRATA_769419
- bool "PL310 errata: no automatic Store Buffer drain"
- depends on CACHE_L2X0
- help
- On revisions of the PL310 prior to r3p2, the Store Buffer does
- not automatically drain. This can cause normal, non-cacheable
- writes to be retained when the memory system is idle, leading
- to suboptimal I/O performance for drivers using coherent DMA.
- This option adds a write barrier to the cpu_idle loop so that,
- on systems with an outer cache, the store buffer is drained
- explicitly.
-
endmenu
menu "Kernel Features"
@@ -2012,6 +2022,7 @@ source "drivers/cpufreq/Kconfig"
config CPU_FREQ_IMX
tristate "CPUfreq driver for i.MX CPUs"
depends on ARCH_MXC && CPU_FREQ
+ select CPU_FREQ_TABLE
help
This enables the CPUfreq driver for i.MX CPUs.
diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
index 7f35d0c2912..e609e52a62d 100644
--- a/arch/arm/boot/compressed/head.S
+++ b/arch/arm/boot/compressed/head.S
@@ -654,6 +654,7 @@ __armv7_mmu_cache_on:
mcrne p15, 0, r0, c8, c7, 0 @ flush I,D TLBs
#endif
mrc p15, 0, r0, c1, c0, 0 @ read control reg
+ bic r0, r0, #1 << 28 @ clear SCTLR.TRE
orr r0, r0, #0x5000 @ I-cache enable, RR cache replacement
orr r0, r0, #0x003c @ write buffer
#ifdef CONFIG_MMU
diff --git a/arch/arm/configs/mxs_defconfig b/arch/arm/configs/mxs_defconfig
index 2bf224310fb..166d6aa97c4 100644
--- a/arch/arm/configs/mxs_defconfig
+++ b/arch/arm/configs/mxs_defconfig
@@ -29,7 +29,6 @@ CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_PREEMPT_VOLUNTARY=y
CONFIG_AEABI=y
-CONFIG_DEFAULT_MMAP_MIN_ADDR=65536
CONFIG_AUTO_ZRELADDR=y
CONFIG_FPE_NWFPE=y
CONFIG_NET=y
diff --git a/arch/arm/configs/vigor_aosp_defconfig b/arch/arm/configs/vigor_aosp_defconfig
index 524aaa3e9ba..1a683a649b3 100644
--- a/arch/arm/configs/vigor_aosp_defconfig
+++ b/arch/arm/configs/vigor_aosp_defconfig
@@ -27,6 +27,7 @@ CONFIG_VECTORS_BASE=0xffff0000
# CONFIG_ARM_PATCH_PHYS_VIRT is not set
CONFIG_GENERIC_BUG=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_MSM_MULTIMEDIA_USE_ION=y
CONFIG_HAVE_IRQ_WORK=y
#
@@ -44,7 +45,7 @@ CONFIG_KERNEL_GZIP=y
# CONFIG_KERNEL_LZMA is not set
# CONFIG_KERNEL_LZO is not set
CONFIG_DEFAULT_HOSTNAME="(none)"
-# CONFIG_SWAP is not set
+CONFIG_SWAP=y
# CONFIG_SYSVIPC is not set
# CONFIG_POSIX_MQUEUE is not set
# CONFIG_BSD_PROCESS_ACCT is not set
@@ -166,11 +167,13 @@ CONFIG_LBDAF=y
#
CONFIG_IOSCHED_NOOP=y
CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_ROW=y
CONFIG_IOSCHED_CFQ=y
-CONFIG_DEFAULT_DEADLINE=y
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_ROW=y
# CONFIG_DEFAULT_CFQ is not set
# CONFIG_DEFAULT_NOOP is not set
-CONFIG_DEFAULT_IOSCHED="deadline"
+CONFIG_DEFAULT_IOSCHED="row"
# CONFIG_INLINE_SPIN_TRYLOCK is not set
# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
# CONFIG_INLINE_SPIN_LOCK is not set
@@ -624,9 +627,9 @@ CONFIG_CPU_FREQ_TABLE=y
# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
-CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
-# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE=y
CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
@@ -1019,8 +1022,8 @@ CONFIG_BT_SCO=y
CONFIG_BT_RFCOMM=y
CONFIG_BT_RFCOMM_TTY=y
CONFIG_BT_BNEP=y
-# CONFIG_BT_BNEP_MC_FILTER is not set
-# CONFIG_BT_BNEP_PROTO_FILTER is not set
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
CONFIG_BT_HIDP=y
#
@@ -1092,6 +1095,9 @@ CONFIG_EXTRA_FIRMWARE=""
# CONFIG_SYS_HYPERVISOR is not set
CONFIG_GENLOCK=y
CONFIG_GENLOCK_MISCDEVICE=y
+CONFIG_SYNC=y
+CONFIG_SW_SYNC=y
+CONFIG_SW_SYNC_USER=y
# CONFIG_CONNECTOR is not set
# CONFIG_MTD is not set
# CONFIG_PARPORT is not set
@@ -1237,7 +1243,7 @@ CONFIG_LIBRA_SDIOIF=m
CONFIG_BCMDHD=m
CONFIG_BCMDHD_FW_PATH="/system/vendor/firmware/fw_bcmdhd.bin"
CONFIG_BCMDHD_NVRAM_PATH="/proc/calibration"
-# CONFIG_DHD_USE_STATIC_BUF is not set
+CONFIG_DHD_USE_STATIC_BUF=y
# CONFIG_DHD_USE_SCHED_SCAN is not set
# CONFIG_DHD_ENABLE_P2P is not set
# CONFIG_HOSTAP is not set
@@ -1876,7 +1882,8 @@ CONFIG_MT9D015=y
# Graphics support
#
# CONFIG_DRM is not set
-# CONFIG_ION is not set
+CONFIG_ION=y
+CONFIG_ION_MSM=y
CONFIG_MSM_KGSL=y
# CONFIG_MSM_KGSL_CFF_DUMP is not set
# CONFIG_MSM_KGSL_PSTMRTMDMP_CP_STAT_NO_DETAIL is not set
@@ -2136,7 +2143,7 @@ CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
CONFIG_USB_DEVICE_CLASS=y
# CONFIG_USB_DYNAMIC_MINORS is not set
CONFIG_USB_SUSPEND=y
-# CONFIG_USB_OTG is not set
+CONFIG_USB_OTG=y
# CONFIG_USB_OTG_WHITELIST is not set
# CONFIG_USB_OTG_BLACKLIST_HUB is not set
# CONFIG_USB_MON is not set
@@ -2243,46 +2250,38 @@ CONFIG_USB_GADGET_DUALSPEED=y
# CONFIG_USB_MIDI_GADGET is not set
# CONFIG_USB_G_PRINTER is not set
CONFIG_USB_G_ANDROID=y
-# CONFIG_USB_ANDROID_ACM is not set
-CONFIG_USB_ANDROID_ADB=y
-CONFIG_USB_ANDROID_DIAG=y
-CONFIG_USB_ANDROID_MDM9K_DIAG=y
-CONFIG_USB_ANDROID_MDM9K_MODEM=y
-CONFIG_USB_ANDROID_MASS_STORAGE=y
-CONFIG_USB_ANDROID_MTP=y
-CONFIG_USB_ANDROID_RNDIS=y
-# CONFIG_USB_ANDROID_RMNET is not set
+# CONFIG_USB_CDC_COMPOSITE is not set
+# CONFIG_USB_G_MULTI is not set
+# CONFIG_USB_G_HID is not set
+# CONFIG_USB_G_DBGP is not set
+CONFIG_USB_CSW_HACK=y
+# CONFIG_USB_MSC_PROFILING is not set
+CONFIG_MODEM_SUPPORT=y
CONFIG_RMNET_SMD_CTL_CHANNEL=""
CONFIG_RMNET_SMD_DATA_CHANNEL=""
-# CONFIG_USB_ANDROID_RMNET_SDIO is not set
CONFIG_RMNET_SDIO_CTL_CHANNEL=8
CONFIG_RMNET_SDIO_DATA_CHANNEL=8
-CONFIG_USB_ANDROID_RMNET_SMD_SDIO=y
CONFIG_RMNET_SMD_SDIO_CTL_CHANNEL=8
CONFIG_RMNET_SMD_SDIO_DATA_CHANNEL=8
CONFIG_RMNET_SDIO_SMD_DATA_CHANNEL="DATA40"
# CONFIG_USB_ANDROID_RMNET_CTRL_SMD is not set
# CONFIG_USB_F_SERIAL is not set
-CONFIG_MODEM_SUPPORT=y
-CONFIG_USB_ANDROID_SERIAL=y
-CONFIG_USB_ANDROID_PROJECTOR=y
-CONFIG_USB_ANDROID_ECM=y
# CONFIG_USB_F_SERIAL_SDIO is not set
# CONFIG_USB_F_SERIAL_SMD is not set
-CONFIG_USB_ANDROID_USBNET=y
# CONFIG_USB_CDC_COMPOSITE is not set
# CONFIG_USB_G_MULTI is not set
# CONFIG_USB_G_HID is not set
# CONFIG_USB_G_DBGP is not set
# CONFIG_USB_ACCESSORY_DETECT_BY_ADC is not set
-# CONFIG_USB_CSW_HACK is not set
+CONFIG_USB_CSW_HACK=y
CONFIG_USB_GADGET_VERIZON_PRODUCT_ID=y
+CONFIG_USB_HTC_SWITCH_STUB=y
#
# OTG and related infrastructure
#
CONFIG_USB_OTG_UTILS=y
-# CONFIG_USB_OTG_WAKELOCK is not set
+CONFIG_USB_OTG_WAKELOCK=y
# CONFIG_USB_GPIO_VBUS is not set
# CONFIG_USB_ULPI is not set
# CONFIG_USB_MSM_OTG_72K is not set
diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h
index 65c3f2474f5..4e25f188835 100644
--- a/arch/arm/include/asm/assembler.h
+++ b/arch/arm/include/asm/assembler.h
@@ -137,6 +137,11 @@
disable_irq
.endm
+ .macro save_and_disable_irqs_notrace, oldcpsr
+ mrs \oldcpsr, cpsr
+ disable_irq_notrace
+ .endm
+
/*
* Restore interrupt state previously stored in a register. We don't
* guarantee that this will preserve the flags.
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
index 584fe0b6fcd..1ea19850816 100644
--- a/arch/arm/include/asm/cacheflush.h
+++ b/arch/arm/include/asm/cacheflush.h
@@ -236,7 +236,9 @@ static inline void vivt_flush_cache_mm(struct mm_struct *mm)
static inline void
vivt_flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
{
- if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm)))
+ struct mm_struct *mm = vma->vm_mm;
+
+ if (!mm || cpumask_test_cpu(smp_processor_id(), mm_cpumask(mm)))
__cpuc_flush_user_range(start & PAGE_MASK, PAGE_ALIGN(end),
vma->vm_flags);
}
@@ -244,7 +246,9 @@ vivt_flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned
static inline void
vivt_flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsigned long pfn)
{
- if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) {
+ struct mm_struct *mm = vma->vm_mm;
+
+ if (!mm || cpumask_test_cpu(smp_processor_id(), mm_cpumask(mm))) {
unsigned long addr = user_addr & PAGE_MASK;
__cpuc_flush_user_range(addr, addr + PAGE_SIZE, vma->vm_flags);
}
diff --git a/arch/arm/include/asm/hwcap.h b/arch/arm/include/asm/hwcap.h
index c93a22a8b92..152700d63fd 100644
--- a/arch/arm/include/asm/hwcap.h
+++ b/arch/arm/include/asm/hwcap.h
@@ -23,6 +23,7 @@
#define HWCAP_VFPv4 (1 << 16)
#define HWCAP_IDIVA (1 << 17)
#define HWCAP_IDIVT (1 << 18)
+#define HWCAP_VFPD32 (1 << 19) /* set if VFP has 32 regs (not 16) */
#define HWCAP_IDIV (HWCAP_IDIVA | HWCAP_IDIVT)
#if defined(__KERNEL__) && !defined(__ASSEMBLY__)
diff --git a/arch/arm/include/asm/mutex.h b/arch/arm/include/asm/mutex.h
index fd3f17ef94a..d34063ced0c 100644
--- a/arch/arm/include/asm/mutex.h
+++ b/arch/arm/include/asm/mutex.h
@@ -8,128 +8,11 @@
#ifndef _ASM_MUTEX_H
#define _ASM_MUTEX_H
-#if __LINUX_ARM_ARCH__ < 6
-/* On pre-ARMv6 hardware the swp based implementation is the most efficient. */
-# include
-#else
-
-/*
- * Attempting to lock a mutex on ARMv6+ can be done with a bastardized
- * atomic decrement (it is not a reliable atomic decrement but it satisfies
- * the defined semantics for our purpose, while being smaller and faster
- * than a real atomic decrement or atomic swap. The idea is to attempt
- * decrementing the lock value only once. If once decremented it isn't zero,
- * or if its store-back fails due to a dispute on the exclusive store, we
- * simply bail out immediately through the slow path where the lock will be
- * reattempted until it succeeds.
- */
-static inline void
-__mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *))
-{
- int __ex_flag, __res;
-
- __asm__ (
-
- "ldrex %0, [%2] \n\t"
- "sub %0, %0, #1 \n\t"
- "strex %1, %0, [%2] "
-
- : "=&r" (__res), "=&r" (__ex_flag)
- : "r" (&(count)->counter)
- : "cc","memory" );
-
- __res |= __ex_flag;
- if (unlikely(__res != 0))
- fail_fn(count);
- else
- smp_rmb();
-}
-
-static inline int
-__mutex_fastpath_lock_retval(atomic_t *count, int (*fail_fn)(atomic_t *))
-{
- int __ex_flag, __res;
-
- __asm__ (
-
- "ldrex %0, [%2] \n\t"
- "sub %0, %0, #1 \n\t"
- "strex %1, %0, [%2] "
-
- : "=&r" (__res), "=&r" (__ex_flag)
- : "r" (&(count)->counter)
- : "cc","memory" );
-
- __res |= __ex_flag;
- if (unlikely(__res != 0))
- __res = fail_fn(count);
- else
- smp_rmb();
-
- return __res;
-}
-
-/*
- * Same trick is used for the unlock fast path. However the original value,
- * rather than the result, is used to test for success in order to have
- * better generated assembly.
- */
-static inline void
-__mutex_fastpath_unlock(atomic_t *count, void (*fail_fn)(atomic_t *))
-{
- int __ex_flag, __res, __orig;
-
- smp_wmb();
- __asm__ (
-
- "ldrex %0, [%3] \n\t"
- "add %1, %0, #1 \n\t"
- "strex %2, %1, [%3] "
-
- : "=&r" (__orig), "=&r" (__res), "=&r" (__ex_flag)
- : "r" (&(count)->counter)
- : "cc","memory" );
-
- __orig |= __ex_flag;
- if (unlikely(__orig != 0))
- fail_fn(count);
-}
-
/*
- * If the unlock was done on a contended lock, or if the unlock simply fails
- * then the mutex remains locked.
+ * On pre-ARMv6 hardware this results in a swp-based implementation,
+ * which is the most efficient. For ARMv6+, we emit a pair of exclusive
+ * accesses instead.
*/
-#define __mutex_slowpath_needs_to_unlock() 1
-/*
- * For __mutex_fastpath_trylock we use another construct which could be
- * described as a "single value cmpxchg".
- *
- * This provides the needed trylock semantics like cmpxchg would, but it is
- * lighter and less generic than a true cmpxchg implementation.
- */
-static inline int
-__mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *))
-{
- int __ex_flag, __res, __orig;
-
- __asm__ (
-
- "1: ldrex %0, [%3] \n\t"
- "subs %1, %0, #1 \n\t"
- "strexeq %2, %1, [%3] \n\t"
- "movlt %0, #0 \n\t"
- "cmpeq %2, #0 \n\t"
- "bgt 1b "
-
- : "=&r" (__orig), "=&r" (__res), "=&r" (__ex_flag)
- : "r" (&count->counter)
- : "cc", "memory" );
- if (__orig)
- smp_rmb();
-
- return __orig;
-}
-
-#endif
+#include
#endif
diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
index 9693d472b0a..07edd7d0cc5 100644
--- a/arch/arm/include/asm/pgtable.h
+++ b/arch/arm/include/asm/pgtable.h
@@ -376,6 +376,18 @@ static inline pte_t *pmd_page_vaddr(pmd_t pmd)
#define set_pte_ext(ptep,pte,ext) cpu_set_pte_ext(ptep,pte,ext)
#define pte_clear(mm,addr,ptep) set_pte_ext(ptep, __pte(0), 0)
+#define pte_none(pte) (!pte_val(pte))
+#define pte_present(pte) (pte_val(pte) & L_PTE_PRESENT)
+#define pte_write(pte) (!(pte_val(pte) & L_PTE_RDONLY))
+#define pte_dirty(pte) (pte_val(pte) & L_PTE_DIRTY)
+#define pte_young(pte) (pte_val(pte) & L_PTE_YOUNG)
+#define pte_exec(pte) (!(pte_val(pte) & L_PTE_XN))
+#define pte_special(pte) (0)
+
+#define pte_present_user(pte) \
+ ((pte_val(pte) & (L_PTE_PRESENT | L_PTE_USER)) == \
+ (L_PTE_PRESENT | L_PTE_USER))
+
#if __LINUX_ARM_ARCH__ < 6
static inline void __sync_icache_dcache(pte_t pteval)
{
@@ -387,25 +399,15 @@ extern void __sync_icache_dcache(pte_t pteval);
static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
pte_t *ptep, pte_t pteval)
{
- if (addr >= TASK_SIZE)
- set_pte_ext(ptep, pteval, 0);
- else {
+ unsigned long ext = 0;
+
+ if (addr < TASK_SIZE && pte_present_user(pteval)) {
__sync_icache_dcache(pteval);
- set_pte_ext(ptep, pteval, PTE_EXT_NG);
+ ext |= PTE_EXT_NG;
}
-}
-#define pte_none(pte) (!pte_val(pte))
-#define pte_present(pte) (pte_val(pte) & L_PTE_PRESENT)
-#define pte_write(pte) (!(pte_val(pte) & L_PTE_RDONLY))
-#define pte_dirty(pte) (pte_val(pte) & L_PTE_DIRTY)
-#define pte_young(pte) (pte_val(pte) & L_PTE_YOUNG)
-#define pte_exec(pte) (!(pte_val(pte) & L_PTE_XN))
-#define pte_special(pte) (0)
-
-#define pte_present_user(pte) \
- ((pte_val(pte) & (L_PTE_PRESENT | L_PTE_USER)) == \
- (L_PTE_PRESENT | L_PTE_USER))
+ set_pte_ext(ptep, pteval, ext);
+}
#define PTE_BIT_FUNC(fn,op) \
static inline pte_t pte_##fn(pte_t pte) { pte_val(pte) op; return pte; }
@@ -432,13 +434,13 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
*
* 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
* 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * <--------------- offset --------------------> <- type --> 0 0 0
+ * <--------------- offset ----------------------> < type -> 0 0 0
*
- * This gives us up to 63 swap files and 32GB per swap file. Note that
+ * This gives us up to 31 swap files and 64GB per swap file. Note that
* the offset field is always non-zero.
*/
#define __SWP_TYPE_SHIFT 3
-#define __SWP_TYPE_BITS 6
+#define __SWP_TYPE_BITS 5
#define __SWP_TYPE_MASK ((1 << __SWP_TYPE_BITS) - 1)
#define __SWP_OFFSET_SHIFT (__SWP_TYPE_BITS + __SWP_TYPE_SHIFT)
diff --git a/arch/arm/include/asm/signal.h b/arch/arm/include/asm/signal.h
index 43ba0fb1c8a..559ee24c956 100644
--- a/arch/arm/include/asm/signal.h
+++ b/arch/arm/include/asm/signal.h
@@ -127,6 +127,7 @@ struct sigaction {
__sigrestore_t sa_restorer;
sigset_t sa_mask; /* mask last for extensibility */
};
+#define __ARCH_HAS_SA_RESTORER
struct k_sigaction {
struct sigaction sa;
diff --git a/arch/arm/include/asm/tls.h b/arch/arm/include/asm/tls.h
index 60843eb0f61..73409e6c025 100644
--- a/arch/arm/include/asm/tls.h
+++ b/arch/arm/include/asm/tls.h
@@ -7,6 +7,8 @@
.macro set_tls_v6k, tp, tmp1, tmp2
mcr p15, 0, \tp, c13, c0, 3 @ set TLS register
+ mov \tmp1, #0
+ mcr p15, 0, \tmp1, c13, c0, 2 @ clear user r/w TLS register
.endm
.macro set_tls_v6, tp, tmp1, tmp2
@@ -15,6 +17,8 @@
mov \tmp2, #0xffff0fff
tst \tmp1, #HWCAP_TLS @ hardware TLS available?
mcrne p15, 0, \tp, c13, c0, 3 @ yes, set TLS register
+ movne \tmp1, #0
+ mcrne p15, 0, \tmp1, c13, c0, 2 @ clear user r/w TLS register
streq \tp, [\tmp2, #-15] @ set TLS value at 0xffff0ff0
.endm
diff --git a/arch/arm/include/asm/vfpmacros.h b/arch/arm/include/asm/vfpmacros.h
index 3d5fc41ae8d..c49c8f778b5 100644
--- a/arch/arm/include/asm/vfpmacros.h
+++ b/arch/arm/include/asm/vfpmacros.h
@@ -27,9 +27,9 @@
#if __LINUX_ARM_ARCH__ <= 6
ldr \tmp, =elf_hwcap @ may not have MVFR regs
ldr \tmp, [\tmp, #0]
- tst \tmp, #HWCAP_VFPv3D16
- ldceq p11, cr0, [\base],#32*4 @ FLDMIAD \base!, {d16-d31}
- addne \base, \base, #32*4 @ step over unused register space
+ tst \tmp, #HWCAP_VFPD32
+ ldcnel p11, cr0, [\base],#32*4 @ FLDMIAD \base!, {d16-d31}
+ addeq \base, \base, #32*4 @ step over unused register space
#else
VFPFMRX \tmp, MVFR0 @ Media and VFP Feature Register 0
and \tmp, \tmp, #MVFR0_A_SIMD_MASK @ A_SIMD field
@@ -51,9 +51,9 @@
#if __LINUX_ARM_ARCH__ <= 6
ldr \tmp, =elf_hwcap @ may not have MVFR regs
ldr \tmp, [\tmp, #0]
- tst \tmp, #HWCAP_VFPv3D16
- stceq p11, cr0, [\base],#32*4 @ FSTMIAD \base!, {d16-d31}
- addne \base, \base, #32*4 @ step over unused register space
+ tst \tmp, #HWCAP_VFPD32
+ stcnel p11, cr0, [\base],#32*4 @ FSTMIAD \base!, {d16-d31}
+ addeq \base, \base, #32*4 @ step over unused register space
#else
VFPFMRX \tmp, MVFR0 @ Media and VFP Feature Register 0
and \tmp, \tmp, #MVFR0_A_SIMD_MASK @ A_SIMD field
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
index 97260060bf2..172ae01c26e 100644
--- a/arch/arm/kernel/ptrace.c
+++ b/arch/arm/kernel/ptrace.c
@@ -719,10 +719,13 @@ static int vfp_set(struct task_struct *target,
{
int ret;
struct thread_info *thread = task_thread_info(target);
- struct vfp_hard_struct new_vfp = thread->vfpstate.hard;
+ struct vfp_hard_struct new_vfp;
const size_t user_fpregs_offset = offsetof(struct user_vfp, fpregs);
const size_t user_fpscr_offset = offsetof(struct user_vfp, fpscr);
+ vfp_sync_hwstate(thread);
+ new_vfp = thread->vfpstate.hard;
+
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
&new_vfp.fpregs,
user_fpregs_offset,
@@ -743,9 +746,8 @@ static int vfp_set(struct task_struct *target,
if (ret)
return ret;
- vfp_sync_hwstate(thread);
- thread->vfpstate.hard = new_vfp;
vfp_flush_hwstate(thread);
+ thread->vfpstate.hard = new_vfp;
return 0;
}
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index 0340224cf73..9e617bd4a14 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -227,6 +227,8 @@ static int restore_vfp_context(struct vfp_sigframe __user *frame)
if (magic != VFP_MAGIC || size != VFP_STORAGE_SIZE)
return -EINVAL;
+ vfp_flush_hwstate(thread);
+
/*
* Copy the floating point registers. There can be unused
* registers see asm/hwcap.h for details.
@@ -251,9 +253,6 @@ static int restore_vfp_context(struct vfp_sigframe __user *frame)
__get_user_error(h->fpinst, &frame->ufp_exc.fpinst, err);
__get_user_error(h->fpinst2, &frame->ufp_exc.fpinst2, err);
- if (!err)
- vfp_flush_hwstate(thread);
-
return err ? -EFAULT : 0;
}
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 5eee27487bd..2da52a42496 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -291,20 +291,26 @@ static void __cpuinit smp_store_cpu_info(unsigned int cpuid)
asmlinkage void __cpuinit secondary_start_kernel(void)
{
struct mm_struct *mm = &init_mm;
- unsigned int cpu = smp_processor_id();
+ unsigned int cpu;
- printk("CPU%u: Booted secondary processor\n", cpu);
+ /*
+ * The identity mapping is uncached (strongly ordered), so
+ * switch away from it before attempting any exclusive accesses.
+ */
+ cpu_switch_mm(mm->pgd, mm);
+ enter_lazy_tlb(mm, current);
+ local_flush_tlb_all();
/*
* All kernel threads share the same mm context; grab a
* reference and switch to it.
*/
+ cpu = smp_processor_id();
atomic_inc(&mm->mm_count);
current->active_mm = mm;
cpumask_set_cpu(cpu, mm_cpumask(mm));
- cpu_switch_mm(mm->pgd, mm);
- enter_lazy_tlb(mm, current);
- local_flush_tlb_all();
+
+ printk("CPU%u: Booted secondary processor\n", cpu);
cpu_init();
preempt_disable();
@@ -460,9 +466,7 @@ static DEFINE_PER_CPU(struct clock_event_device, percpu_clockevent);
static void ipi_timer(void)
{
struct clock_event_device *evt = &__get_cpu_var(percpu_clockevent);
- irq_enter();
evt->event_handler(evt);
- irq_exit();
}
#ifdef CONFIG_LOCAL_TIMERS
@@ -473,7 +477,9 @@ asmlinkage void __exception_irq_entry do_local_timer(struct pt_regs *regs)
if (local_timer_ack()) {
__inc_irq_stat(cpu, local_timer_irqs);
+ irq_enter();
ipi_timer();
+ irq_exit();
}
set_irq_regs(old_regs);
@@ -591,7 +597,9 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
/* Wake up from WFI/WFE using SGI */
break;
case IPI_TIMER:
+ irq_enter();
ipi_timer();
+ irq_exit();
break;
case IPI_RESCHEDULE:
@@ -599,15 +607,21 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
break;
case IPI_CALL_FUNC:
+ irq_enter();
generic_smp_call_function_interrupt();
+ irq_exit();
break;
case IPI_CALL_FUNC_SINGLE:
+ irq_enter();
generic_smp_call_function_single_interrupt();
+ irq_exit();
break;
case IPI_CPU_STOP:
+ irq_enter();
ipi_cpu_stop(cpu);
+ irq_exit();
break;
default:
diff --git a/arch/arm/kernel/swp_emulate.c b/arch/arm/kernel/swp_emulate.c
index 40ee7e5045e..0951a32493a 100644
--- a/arch/arm/kernel/swp_emulate.c
+++ b/arch/arm/kernel/swp_emulate.c
@@ -108,10 +108,12 @@ static void set_segfault(struct pt_regs *regs, unsigned long addr)
{
siginfo_t info;
+ down_read(¤t->mm->mmap_sem);
if (find_vma(current->mm, addr) == NULL)
info.si_code = SEGV_MAPERR;
else
info.si_code = SEGV_ACCERR;
+ up_read(¤t->mm->mmap_sem);
info.si_signo = SIGSEGV;
info.si_errno = 0;
diff --git a/arch/arm/kernel/sys_arm.c b/arch/arm/kernel/sys_arm.c
index 62e7c61d034..0264ab433e9 100644
--- a/arch/arm/kernel/sys_arm.c
+++ b/arch/arm/kernel/sys_arm.c
@@ -115,7 +115,7 @@ int kernel_execve(const char *filename,
"Ir" (THREAD_START_SP - sizeof(regs)),
"r" (®s),
"Ir" (sizeof(regs))
- : "r0", "r1", "r2", "r3", "ip", "lr", "memory");
+ : "r0", "r1", "r2", "r3", "r8", "r9", "ip", "lr", "memory");
out:
return ret;
diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
new file mode 100644
index 00000000000..939b2d8400b
--- /dev/null
+++ b/arch/arm/kernel/topology.c
@@ -0,0 +1,478 @@
+/*
+ * arch/arm/kernel/topology.c
+ *
+ * Copyright (C) 2011 Linaro Limited.
+ * Written by: Vincent Guittot
+ *
+ * based on arch/sh/kernel/topology.c
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifdef CONFIG_DEBUG_FS
+#include
+#include /* for copy_from_user */
+#endif
+
+#include
+#include
+
+/*
+ * cpu power scale management
+ */
+
+/*
+ * cpu power table
+ * This per cpu data structure describes the relative capacity of each core.
+ * On a heteregenous system, cores don't have the same computation capacity
+ * and we reflect that difference in the cpu_power field so the scheduler can
+ * take this difference into account during load balance. A per cpu structure
+ * is preferred because each CPU updates its own cpu_power field during the
+ * load balance except for idle cores. One idle core is selected to run the
+ * rebalance_domains for all idle cores and the cpu_power can be updated
+ * during this sequence.
+ */
+static DEFINE_PER_CPU(unsigned long, cpu_scale);
+
+unsigned long arch_scale_freq_power(struct sched_domain *sd, int cpu)
+{
+ return per_cpu(cpu_scale, cpu);
+}
+
+static void set_power_scale(unsigned int cpu, unsigned long power)
+{
+ per_cpu(cpu_scale, cpu) = power;
+}
+
+/*
+ * cpu topology management
+ */
+
+#define ARM_FAMILY_MASK 0xFF0FFFF0
+
+#define MPIDR_SMP_BITMASK (0x3 << 30)
+#define MPIDR_SMP_VALUE (0x2 << 30)
+
+#define MPIDR_MT_BITMASK (0x1 << 24)
+
+/*
+ * These masks reflect the current use of the affinity levels.
+ * The affinity level can be up to 16 bits according to ARM ARM
+ */
+
+#define MPIDR_LEVEL0_MASK 0x3
+#define MPIDR_LEVEL0_SHIFT 0
+
+#define MPIDR_LEVEL1_MASK 0xF
+#define MPIDR_LEVEL1_SHIFT 8
+
+#define MPIDR_LEVEL2_MASK 0xFF
+#define MPIDR_LEVEL2_SHIFT 16
+/*
+ * CPU topology table
+ */
+struct cputopo_arm cpu_topology[NR_CPUS];
+
+/*
+ * cpu power scale management
+ * a per cpu data structure should be better because each cpu is mainly
+ * using its own cpu_power even it's not always true because of
+ * nohz_idle_balance
+ */
+
+
+
+/*
+ * cpu topology mask update management
+ */
+
+static unsigned int prev_sched_mc_power_savings = 0;
+static unsigned int prev_sched_smt_power_savings = 0;
+
+ATOMIC_NOTIFIER_HEAD(topology_update_notifier_list);
+
+/*
+ * Update the cpu power of the scheduler
+ */
+
+
+int topology_register_notifier(struct notifier_block *nb)
+{
+
+ return atomic_notifier_chain_register(
+ &topology_update_notifier_list, nb);
+}
+
+int topology_unregister_notifier(struct notifier_block *nb)
+{
+
+ return atomic_notifier_chain_unregister(
+ &topology_update_notifier_list, nb);
+}
+
+/*
+ * sched_domain flag configuration
+ */
+/* TODO add a config flag for this function */
+int arch_sd_sibling_asym_packing(void)
+{
+ if (sched_smt_power_savings || sched_mc_power_savings)
+ return SD_ASYM_PACKING;
+ return 0;
+}
+
+/*
+ * default topology function
+ */
+const struct cpumask *cpu_coregroup_mask(int cpu)
+{
+ return &cpu_topology[cpu].core_sibling;
+}
+
+/*
+ * clear cpu topology masks
+ */
+static void clear_cpu_topology_mask(void)
+{
+ unsigned int cpuid;
+ for_each_possible_cpu(cpuid) {
+ struct cputopo_arm *cpuid_topo = &(cpu_topology[cpuid]);
+ cpumask_clear(&cpuid_topo->core_sibling);
+ cpumask_clear(&cpuid_topo->thread_sibling);
+ }
+ smp_wmb();
+}
+
+/*
+ * default_cpu_topology_mask set the core and thread mask as described in the
+ * ARM ARM
+ */
+static void default_cpu_topology_mask(unsigned int cpuid)
+{
+ struct cputopo_arm *cpuid_topo = &cpu_topology[cpuid];
+ unsigned int cpu;
+
+ for_each_possible_cpu(cpu) {
+ struct cputopo_arm *cpu_topo = &cpu_topology[cpu];
+
+ if (cpuid_topo->socket_id == cpu_topo->socket_id) {
+ cpumask_set_cpu(cpuid, &cpu_topo->core_sibling);
+ if (cpu != cpuid)
+ cpumask_set_cpu(cpu,
+ &cpuid_topo->core_sibling);
+
+ if (cpuid_topo->core_id == cpu_topo->core_id) {
+ cpumask_set_cpu(cpuid,
+ &cpu_topo->thread_sibling);
+ if (cpu != cpuid)
+ cpumask_set_cpu(cpu,
+ &cpuid_topo->thread_sibling);
+ }
+ }
+ }
+ smp_wmb();
+}
+
+static void normal_cpu_topology_mask(void)
+{
+ unsigned int cpuid;
+
+ for_each_possible_cpu(cpuid) {
+ default_cpu_topology_mask(cpuid);
+ }
+ smp_wmb();
+}
+
+/*
+ * For Cortex-A9 MPcore, we emulate a multi-package topology in power mode.
+ * The goal is to gathers tasks on 1 virtual package
+ */
+static void power_cpu_topology_mask_CA9(unsigned int cpuid)
+{
+ struct cputopo_arm *cpuid_topo = &cpu_topology[cpuid];
+ unsigned int cpu;
+
+ for_each_possible_cpu(cpu) {
+ struct cputopo_arm *cpu_topo = &cpu_topology[cpu];
+
+ if ((cpuid_topo->socket_id == cpu_topo->socket_id)
+ && ((cpuid & 0x1) == (cpu & 0x1))) {
+ cpumask_set_cpu(cpuid, &cpu_topo->core_sibling);
+ if (cpu != cpuid)
+ cpumask_set_cpu(cpu,
+ &cpuid_topo->core_sibling);
+
+ if (cpuid_topo->core_id == cpu_topo->core_id) {
+ cpumask_set_cpu(cpuid,
+ &cpu_topo->thread_sibling);
+ if (cpu != cpuid)
+ cpumask_set_cpu(cpu,
+ &cpuid_topo->thread_sibling);
+ }
+ }
+ }
+ smp_wmb();
+}
+
+static int need_topology_update(void)
+{
+ int update;
+
+ update = ((prev_sched_mc_power_savings ^ sched_mc_power_savings)
+ || (prev_sched_smt_power_savings ^ sched_smt_power_savings));
+
+ prev_sched_mc_power_savings = sched_mc_power_savings;
+ prev_sched_smt_power_savings = sched_smt_power_savings;
+
+ return update;
+}
+
+#define ARM_CORTEX_A9_FAMILY 0x410FC090
+
+/* update_cpu_topology_policy select a cpu topology policy according to the
+ * available cores.
+ * TODO: The current version assumes that all cores are exactly the same which
+ * might not be true. We need to update it to take into account various
+ * configuration among which system with different kind of core.
+ */
+static int update_cpu_topology_mask(void)
+{
+ unsigned long cpuid;
+
+ if (sched_mc_power_savings == POWERSAVINGS_BALANCE_NONE) {
+ normal_cpu_topology_mask();
+ return 0;
+ }
+
+ for_each_possible_cpu(cpuid) {
+ struct cputopo_arm *cpuid_topo = &(cpu_topology[cpuid]);
+
+ switch (cpuid_topo->id) {
+ case ARM_CORTEX_A9_FAMILY:
+ power_cpu_topology_mask_CA9(cpuid);
+ break;
+ default:
+ default_cpu_topology_mask(cpuid);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * store_cpu_topology is called at boot when only one cpu is running
+ * and with the mutex cpu_hotplug.lock locked, when several cpus have booted,
+ * which prevents simultaneous write access to cpu_topology array
+ */
+void store_cpu_topology(unsigned int cpuid)
+{
+ struct cputopo_arm *cpuid_topo = &cpu_topology[cpuid];
+ unsigned int mpidr;
+
+ /* If the cpu topology has been already set, just return */
+ if (cpuid_topo->core_id != -1)
+ return;
+
+ mpidr = read_cpuid_mpidr();
+
+ /* create cpu topology mapping */
+ if ((mpidr & MPIDR_SMP_BITMASK) == MPIDR_SMP_VALUE) {
+ /*
+ * This is a multiprocessor system
+ * multiprocessor format & multiprocessor mode field are set
+ */
+
+ if (mpidr & MPIDR_MT_BITMASK) {
+ /* core performance interdependency */
+ cpuid_topo->thread_id = (mpidr >> MPIDR_LEVEL0_SHIFT)
+ & MPIDR_LEVEL0_MASK;
+ cpuid_topo->core_id = (mpidr >> MPIDR_LEVEL1_SHIFT)
+ & MPIDR_LEVEL1_MASK;
+ cpuid_topo->socket_id = (mpidr >> MPIDR_LEVEL2_SHIFT)
+ & MPIDR_LEVEL2_MASK;
+ } else {
+ /* largely independent cores */
+ cpuid_topo->thread_id = -1;
+ cpuid_topo->core_id = (mpidr >> MPIDR_LEVEL0_SHIFT)
+ & MPIDR_LEVEL0_MASK;
+ cpuid_topo->socket_id = (mpidr >> MPIDR_LEVEL1_SHIFT)
+ & MPIDR_LEVEL1_MASK;
+ }
+
+ cpuid_topo->id = read_cpuid_id() & ARM_FAMILY_MASK;
+
+ } else {
+ /*
+ * This is an uniprocessor system
+ * we are in multiprocessor format but uniprocessor system
+ * or in the old uniprocessor format
+ */
+ cpuid_topo->thread_id = -1;
+ cpuid_topo->core_id = 0;
+ cpuid_topo->socket_id = -1;
+ }
+
+ /*
+ * The core and thread sibling masks can also be updated during the
+ * call of arch_update_cpu_topology
+ */
+ default_cpu_topology_mask(cpuid);
+
+
+ printk(KERN_INFO "CPU%u: thread %d, cpu %d, socket %d, mpidr %x\n",
+ cpuid, cpu_topology[cpuid].thread_id,
+ cpu_topology[cpuid].core_id,
+ cpu_topology[cpuid].socket_id, mpidr);
+}
+
+/*
+ * arch_update_cpu_topology is called by the scheduler before building
+ * a new sched_domain hierarchy.
+ */
+int arch_update_cpu_topology(void)
+{
+ if (!need_topology_update())
+ return 0;
+
+ /* clear core threads mask */
+ clear_cpu_topology_mask();
+
+ /* set topology mask */
+ update_cpu_topology_mask();
+
+ /* notify the topology update */
+ atomic_notifier_call_chain(&topology_update_notifier_list,
+ TOPOLOGY_POSTCHANGE, (void *)sched_mc_power_savings);
+
+ return 1;
+}
+
+/*
+ * init_cpu_topology is called at boot when only one cpu is running
+ * which prevent simultaneous write access to cpu_topology array
+ */
+void init_cpu_topology(void)
+{
+ unsigned int cpu;
+
+ /* init core mask */
+ for_each_possible_cpu(cpu) {
+ struct cputopo_arm *cpu_topo = &(cpu_topology[cpu]);
+
+ cpu_topo->id = -1;
+ cpu_topo->thread_id = -1;
+ cpu_topo->core_id = -1;
+ cpu_topo->socket_id = -1;
+ cpumask_clear(&cpu_topo->core_sibling);
+ cpumask_clear(&cpu_topo->thread_sibling);
+
+ set_power_scale(cpu, SCHED_POWER_SCALE);
+ }
+ smp_wmb();
+}
+
+/*
+ * debugfs interface for scaling cpu power
+ */
+
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *topo_debugfs_root;
+
+static ssize_t dbg_write(struct file *file, const char __user *buf,
+ size_t size, loff_t *off)
+{
+ unsigned int *value = file->f_dentry->d_inode->i_private;
+ char cdata[128];
+ unsigned long tmp;
+
+ if (size < (sizeof(cdata)-1)) {
+ if (copy_from_user(cdata, buf, size))
+ return -EFAULT;
+ cdata[size] = 0;
+ if (!strict_strtoul(cdata, 10, &tmp)) {
+ *value = tmp;
+ }
+ return size;
+ }
+ return -EINVAL;
+}
+
+static ssize_t dbg_read(struct file *file, char __user *buf,
+ size_t size, loff_t *off)
+{
+ unsigned int *value = file->f_dentry->d_inode->i_private;
+ char cdata[128];
+ unsigned int len;
+
+ len = sprintf(cdata, "%u\n", *value);
+ return simple_read_from_buffer(buf, size, off, cdata, len);
+}
+
+static const struct file_operations debugfs_fops = {
+ .read = dbg_read,
+ .write = dbg_write,
+};
+
+static struct dentry *topo_debugfs_register(unsigned int cpu,
+ struct dentry *parent)
+{
+ struct dentry *cpu_d, *d;
+ char cpu_name[16];
+
+ sprintf(cpu_name, "cpu%u", cpu);
+
+ cpu_d = debugfs_create_dir(cpu_name, parent);
+ if (!cpu_d)
+ return NULL;
+
+ d = debugfs_create_file("cpu_power", S_IRUGO | S_IWUGO,
+ cpu_d, &per_cpu(cpu_scale, cpu), &debugfs_fops);
+ if (!d)
+ goto err_out;
+
+ return cpu_d;
+
+err_out:
+ debugfs_remove_recursive(cpu_d);
+ return NULL;
+}
+
+static int __init topo_debugfs_init(void)
+{
+ struct dentry *d;
+ unsigned int cpu;
+
+ d = debugfs_create_dir("cpu_topo", NULL);
+ if (!d)
+ return -ENOMEM;
+ topo_debugfs_root = d;
+
+ for_each_possible_cpu(cpu) {
+ d = topo_debugfs_register(cpu, topo_debugfs_root);
+ if (d == NULL)
+ goto err_out;
+ }
+ return 0;
+
+err_out:
+ debugfs_remove_recursive(topo_debugfs_root);
+ return -ENOMEM;
+}
+
+late_initcall(topo_debugfs_init);
+#endif
+
diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c
index 7227755ffec..871a818e3db 100644
--- a/arch/arm/mach-at91/at91rm9200_devices.c
+++ b/arch/arm/mach-at91/at91rm9200_devices.c
@@ -454,7 +454,7 @@ static struct i2c_gpio_platform_data pdata = {
static struct platform_device at91rm9200_twi_device = {
.name = "i2c-gpio",
- .id = -1,
+ .id = 0,
.dev.platform_data = &pdata,
};
diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
index 39f81f47b4b..89a8414d7e2 100644
--- a/arch/arm/mach-at91/at91sam9260_devices.c
+++ b/arch/arm/mach-at91/at91sam9260_devices.c
@@ -459,7 +459,7 @@ static struct i2c_gpio_platform_data pdata = {
static struct platform_device at91sam9260_twi_device = {
.name = "i2c-gpio",
- .id = -1,
+ .id = 0,
.dev.platform_data = &pdata,
};
diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
index 5004bf0a05f..5d43cf45231 100644
--- a/arch/arm/mach-at91/at91sam9261_devices.c
+++ b/arch/arm/mach-at91/at91sam9261_devices.c
@@ -276,7 +276,7 @@ static struct i2c_gpio_platform_data pdata = {
static struct platform_device at91sam9261_twi_device = {
.name = "i2c-gpio",
- .id = -1,
+ .id = 0,
.dev.platform_data = &pdata,
};
diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
index a050f41fc86..2bbd16301a0 100644
--- a/arch/arm/mach-at91/at91sam9263_devices.c
+++ b/arch/arm/mach-at91/at91sam9263_devices.c
@@ -534,7 +534,7 @@ static struct i2c_gpio_platform_data pdata = {
static struct platform_device at91sam9263_twi_device = {
.name = "i2c-gpio",
- .id = -1,
+ .id = 0,
.dev.platform_data = &pdata,
};
diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
index aacb19dc922..659870e647f 100644
--- a/arch/arm/mach-at91/at91sam9rl_devices.c
+++ b/arch/arm/mach-at91/at91sam9rl_devices.c
@@ -319,7 +319,7 @@ static struct i2c_gpio_platform_data pdata = {
static struct platform_device at91sam9rl_twi_device = {
.name = "i2c-gpio",
- .id = -1,
+ .id = 0,
.dev.platform_data = &pdata,
};
diff --git a/arch/arm/mach-dove/common.c b/arch/arm/mach-dove/common.c
index cf7e5985eeb..46c04498629 100644
--- a/arch/arm/mach-dove/common.c
+++ b/arch/arm/mach-dove/common.c
@@ -31,6 +31,7 @@
#include
#include
#include
+#include
#include
#include "common.h"
@@ -74,7 +75,7 @@ void __init dove_map_io(void)
void __init dove_ehci0_init(void)
{
orion_ehci_init(&dove_mbus_dram_info,
- DOVE_USB0_PHYS_BASE, IRQ_DOVE_USB0);
+ DOVE_USB0_PHYS_BASE, IRQ_DOVE_USB0, EHCI_PHY_NA);
}
/*****************************************************************************
diff --git a/arch/arm/mach-dove/include/mach/pm.h b/arch/arm/mach-dove/include/mach/pm.h
index 3ad9f946a9e..11799c33475 100644
--- a/arch/arm/mach-dove/include/mach/pm.h
+++ b/arch/arm/mach-dove/include/mach/pm.h
@@ -45,7 +45,7 @@ static inline int pmu_to_irq(int pin)
static inline int irq_to_pmu(int irq)
{
- if (IRQ_DOVE_PMU_START < irq && irq < NR_IRQS)
+ if (IRQ_DOVE_PMU_START <= irq && irq < NR_IRQS)
return irq - IRQ_DOVE_PMU_START;
return -EINVAL;
diff --git a/arch/arm/mach-dove/irq.c b/arch/arm/mach-dove/irq.c
index f07fd16e0c9..9f2fd100174 100644
--- a/arch/arm/mach-dove/irq.c
+++ b/arch/arm/mach-dove/irq.c
@@ -61,8 +61,20 @@ static void pmu_irq_ack(struct irq_data *d)
int pin = irq_to_pmu(d->irq);
u32 u;
+ /*
+ * The PMU mask register is not RW0C: it is RW. This means that
+ * the bits take whatever value is written to them; if you write
+ * a '1', you will set the interrupt.
+ *
+ * Unfortunately this means there is NO race free way to clear
+ * these interrupts.
+ *
+ * So, let's structure the code so that the window is as small as
+ * possible.
+ */
u = ~(1 << (pin & 31));
- writel(u, PMU_INTERRUPT_CAUSE);
+ u &= readl_relaxed(PMU_INTERRUPT_CAUSE);
+ writel_relaxed(u, PMU_INTERRUPT_CAUSE);
}
static struct irq_chip pmu_irq_chip = {
diff --git a/arch/arm/mach-imx/mach-mx21ads.c b/arch/arm/mach-imx/mach-mx21ads.c
index 74ac88978dd..a37fe021d69 100644
--- a/arch/arm/mach-imx/mach-mx21ads.c
+++ b/arch/arm/mach-imx/mach-mx21ads.c
@@ -32,7 +32,7 @@
* Memory-mapped I/O on MX21ADS base board
*/
#define MX21ADS_MMIO_BASE_ADDR 0xf5000000
-#define MX21ADS_MMIO_SIZE SZ_16M
+#define MX21ADS_MMIO_SIZE 0xc00000
#define MX21ADS_REG_ADDR(offset) (void __force __iomem *) \
(MX21ADS_MMIO_BASE_ADDR + (offset))
diff --git a/arch/arm/mach-kirkwood/common.c b/arch/arm/mach-kirkwood/common.c
index f3248cfbe51..c5dbbb35e0b 100644
--- a/arch/arm/mach-kirkwood/common.c
+++ b/arch/arm/mach-kirkwood/common.c
@@ -28,6 +28,7 @@
#include
#include
#include
+#include
#include
#include
#include "common.h"
@@ -74,7 +75,7 @@ void __init kirkwood_ehci_init(void)
{
kirkwood_clk_ctrl |= CGC_USB0;
orion_ehci_init(&kirkwood_mbus_dram_info,
- USB_PHYS_BASE, IRQ_KIRKWOOD_USB);
+ USB_PHYS_BASE, IRQ_KIRKWOOD_USB, EHCI_PHY_NA);
}
diff --git a/arch/arm/mach-kirkwood/mpp.h b/arch/arm/mach-kirkwood/mpp.h
index ac787957e2d..7afccf47220 100644
--- a/arch/arm/mach-kirkwood/mpp.h
+++ b/arch/arm/mach-kirkwood/mpp.h
@@ -31,313 +31,313 @@
#define MPP_F6282_MASK MPP( 0, 0x0, 0, 0, 0, 0, 0, 0, 1 )
#define MPP0_GPIO MPP( 0, 0x0, 1, 1, 1, 1, 1, 1, 1 )
-#define MPP0_NF_IO2 MPP( 0, 0x1, 1, 1, 1, 1, 1, 1, 1 )
-#define MPP0_SPI_SCn MPP( 0, 0x2, 0, 1, 1, 1, 1, 1, 1 )
+#define MPP0_NF_IO2 MPP( 0, 0x1, 0, 0, 1, 1, 1, 1, 1 )
+#define MPP0_SPI_SCn MPP( 0, 0x2, 0, 0, 1, 1, 1, 1, 1 )
#define MPP1_GPO MPP( 1, 0x0, 0, 1, 1, 1, 1, 1, 1 )
-#define MPP1_NF_IO3 MPP( 1, 0x1, 1, 1, 1, 1, 1, 1, 1 )
-#define MPP1_SPI_MOSI MPP( 1, 0x2, 0, 1, 1, 1, 1, 1, 1 )
+#define MPP1_NF_IO3 MPP( 1, 0x1, 0, 0, 1, 1, 1, 1, 1 )
+#define MPP1_SPI_MOSI MPP( 1, 0x2, 0, 0, 1, 1, 1, 1, 1 )
#define MPP2_GPO MPP( 2, 0x0, 0, 1, 1, 1, 1, 1, 1 )
-#define MPP2_NF_IO4 MPP( 2, 0x1, 1, 1, 1, 1, 1, 1, 1 )
-#define MPP2_SPI_SCK MPP( 2, 0x2, 0, 1, 1, 1, 1, 1, 1 )
+#define MPP2_NF_IO4 MPP( 2, 0x1, 0, 0, 1, 1, 1, 1, 1 )
+#define MPP2_SPI_SCK MPP( 2, 0x2, 0, 0, 1, 1, 1, 1, 1 )
#define MPP3_GPO MPP( 3, 0x0, 0, 1, 1, 1, 1, 1, 1 )
-#define MPP3_NF_IO5 MPP( 3, 0x1, 1, 1, 1, 1, 1, 1, 1 )
-#define MPP3_SPI_MISO MPP( 3, 0x2, 1, 0, 1, 1, 1, 1, 1 )
+#define MPP3_NF_IO5 MPP( 3, 0x1, 0, 0, 1, 1, 1, 1, 1 )
+#define MPP3_SPI_MISO MPP( 3, 0x2, 0, 0, 1, 1, 1, 1, 1 )
#define MPP4_GPIO MPP( 4, 0x0, 1, 1, 1, 1, 1, 1, 1 )
-#define MPP4_NF_IO6 MPP( 4, 0x1, 1, 1, 1, 1, 1, 1, 1 )
-#define MPP4_UART0_RXD MPP( 4, 0x2, 1, 0, 1, 1, 1, 1, 1 )
-#define MPP4_SATA1_ACTn MPP( 4, 0x5, 0, 1, 0, 0, 1, 1, 1 )
+#define MPP4_NF_IO6 MPP( 4, 0x1, 0, 0, 1, 1, 1, 1, 1 )
+#define MPP4_UART0_RXD MPP( 4, 0x2, 0, 0, 1, 1, 1, 1, 1 )
+#define MPP4_SATA1_ACTn MPP( 4, 0x5, 0, 0, 0, 0, 1, 1, 1 )
#define MPP4_LCD_VGA_HSYNC MPP( 4, 0xb, 0, 0, 0, 0, 0, 0, 1 )
-#define MPP4_PTP_CLK MPP( 4, 0xd, 1, 0, 1, 1, 1, 1, 0 )
+#define MPP4_PTP_CLK MPP( 4, 0xd, 0, 0, 1, 1, 1, 1, 0 )
#define MPP5_GPO MPP( 5, 0x0, 0, 1, 1, 1, 1, 1, 1 )
-#define MPP5_NF_IO7 MPP( 5, 0x1, 1, 1, 1, 1, 1, 1, 1 )
-#define MPP5_UART0_TXD MPP( 5, 0x2, 0, 1, 1, 1, 1, 1, 1 )
-#define MPP5_PTP_TRIG_GEN MPP( 5, 0x4, 0, 1, 1, 1, 1, 1, 0 )
-#define MPP5_SATA0_ACTn MPP( 5, 0x5, 0, 1, 0, 1, 1, 1, 1 )
+#define MPP5_NF_IO7 MPP( 5, 0x1, 0, 0, 1, 1, 1, 1, 1 )
+#define MPP5_UART0_TXD MPP( 5, 0x2, 0, 0, 1, 1, 1, 1, 1 )
+#define MPP5_PTP_TRIG_GEN MPP( 5, 0x4, 0, 0, 1, 1, 1, 1, 0 )
+#define MPP5_SATA0_ACTn MPP( 5, 0x5, 0, 0, 0, 1, 1, 1, 1 )
#define MPP5_LCD_VGA_VSYNC MPP( 5, 0xb, 0, 0, 0, 0, 0, 0, 1 )
-#define MPP6_SYSRST_OUTn MPP( 6, 0x1, 0, 1, 1, 1, 1, 1, 1 )
-#define MPP6_SPI_MOSI MPP( 6, 0x2, 0, 1, 1, 1, 1, 1, 1 )
-#define MPP6_PTP_TRIG_GEN MPP( 6, 0x3, 0, 1, 1, 1, 1, 1, 0 )
+#define MPP6_SYSRST_OUTn MPP( 6, 0x1, 0, 0, 1, 1, 1, 1, 1 )
+#define MPP6_SPI_MOSI MPP( 6, 0x2, 0, 0, 1, 1, 1, 1, 1 )
+#define MPP6_PTP_TRIG_GEN MPP( 6, 0x3, 0, 0, 1, 1, 1, 1, 0 )
#define MPP7_GPO MPP( 7, 0x0, 0, 1, 1, 1, 1, 1, 1 )
-#define MPP7_PEX_RST_OUTn MPP( 7, 0x1, 0, 1, 1, 1, 1, 1, 0 )
-#define MPP7_SPI_SCn MPP( 7, 0x2, 0, 1, 1, 1, 1, 1, 1 )
-#define MPP7_PTP_TRIG_GEN MPP( 7, 0x3, 0, 1, 1, 1, 1, 1, 0 )
-#define MPP7_LCD_PWM MPP( 7, 0xb, 0, 1, 0, 0, 0, 0, 1 )
+#define MPP7_PEX_RST_OUTn MPP( 7, 0x1, 0, 0, 1, 1, 1, 1, 0 )
+#define MPP7_SPI_SCn MPP( 7, 0x2, 0, 0, 1, 1, 1, 1, 1 )
+#define MPP7_PTP_TRIG_GEN MPP( 7, 0x3, 0, 0, 1, 1, 1, 1, 0 )
+#define MPP7_LCD_PWM MPP( 7, 0xb, 0, 0, 0, 0, 0, 0, 1 )
#define MPP8_GPIO MPP( 8, 0x0, 1, 1, 1, 1, 1, 1, 1 )
-#define MPP8_TW0_SDA MPP( 8, 0x1, 1, 1, 1, 1, 1, 1, 1 )
-#define MPP8_UART0_RTS MPP( 8, 0x2, 0, 1, 1, 1, 1, 1, 1 )
-#define MPP8_UART1_RTS MPP( 8, 0x3, 0, 1, 1, 1, 1, 1, 1 )
-#define MPP8_MII0_RXERR MPP( 8, 0x4, 1, 0, 0, 1, 1, 1, 1 )
-#define MPP8_SATA1_PRESENTn MPP( 8, 0x5, 0, 1, 0, 0, 1, 1, 1 )
-#define MPP8_PTP_CLK MPP( 8, 0xc, 1, 0, 1, 1, 1, 1, 0 )
-#define MPP8_MII0_COL MPP( 8, 0xd, 1, 0, 1, 1, 1, 1, 1 )
+#define MPP8_TW0_SDA MPP( 8, 0x1, 0, 0, 1, 1, 1, 1, 1 )
+#define MPP8_UART0_RTS MPP( 8, 0x2, 0, 0, 1, 1, 1, 1, 1 )
+#define MPP8_UART1_RTS MPP( 8, 0x3, 0, 0, 1, 1, 1, 1, 1 )
+#define MPP8_MII0_RXERR MPP( 8, 0x4, 0, 0, 0, 1, 1, 1, 1 )
+#define MPP8_SATA1_PRESENTn MPP( 8, 0x5, 0, 0, 0, 0, 1, 1, 1 )
+#define MPP8_PTP_CLK MPP( 8, 0xc, 0, 0, 1, 1, 1, 1, 0 )
+#define MPP8_MII0_COL MPP( 8, 0xd, 0, 0, 1, 1, 1, 1, 1 )
#define MPP9_GPIO MPP( 9, 0x0, 1, 1, 1, 1, 1, 1, 1 )
-#define MPP9_TW0_SCK MPP( 9, 0x1, 1, 1, 1, 1, 1, 1, 1 )
-#define MPP9_UART0_CTS MPP( 9, 0x2, 1, 0, 1, 1, 1, 1, 1 )
-#define MPP9_UART1_CTS MPP( 9, 0x3, 1, 0, 1, 1, 1, 1, 1 )
-#define MPP9_SATA0_PRESENTn MPP( 9, 0x5, 0, 1, 0, 1, 1, 1, 1 )
-#define MPP9_PTP_EVENT_REQ MPP( 9, 0xc, 1, 0, 1, 1, 1, 1, 0 )
-#define MPP9_MII0_CRS MPP( 9, 0xd, 1, 0, 1, 1, 1, 1, 1 )
+#define MPP9_TW0_SCK MPP( 9, 0x1, 0, 0, 1, 1, 1, 1, 1 )
+#define MPP9_UART0_CTS MPP( 9, 0x2, 0, 0, 1, 1, 1, 1, 1 )
+#define MPP9_UART1_CTS MPP( 9, 0x3, 0, 0, 1, 1, 1, 1, 1 )
+#define MPP9_SATA0_PRESENTn MPP( 9, 0x5, 0, 0, 0, 1, 1, 1, 1 )
+#define MPP9_PTP_EVENT_REQ MPP( 9, 0xc, 0, 0, 1, 1, 1, 1, 0 )
+#define MPP9_MII0_CRS MPP( 9, 0xd, 0, 0, 1, 1, 1, 1, 1 )
#define MPP10_GPO MPP( 10, 0x0, 0, 1, 1, 1, 1, 1, 1 )
-#define MPP10_SPI_SCK MPP( 10, 0x2, 0, 1, 1, 1, 1, 1, 1 )
-#define MPP10_UART0_TXD MPP( 10, 0X3, 0, 1, 1, 1, 1, 1, 1 )
-#define MPP10_SATA1_ACTn MPP( 10, 0x5, 0, 1, 0, 0, 1, 1, 1 )
-#define MPP10_PTP_TRIG_GEN MPP( 10, 0xc, 0, 1, 1, 1, 1, 1, 0 )
+#define MPP10_SPI_SCK MPP( 10, 0x2, 0, 0, 1, 1, 1, 1, 1 )
+#define MPP10_UART0_TXD MPP( 10, 0X3, 0, 0, 1, 1, 1, 1, 1 )
+#define MPP10_SATA1_ACTn MPP( 10, 0x5, 0, 0, 0, 0, 1, 1, 1 )
+#define MPP10_PTP_TRIG_GEN MPP( 10, 0xc, 0, 0, 1, 1, 1, 1, 0 )
#define MPP11_GPIO MPP( 11, 0x0, 1, 1, 1, 1, 1, 1, 1 )
-#define MPP11_SPI_MISO MPP( 11, 0x2, 1, 0, 1, 1, 1, 1, 1 )
-#define MPP11_UART0_RXD MPP( 11, 0x3, 1, 0, 1, 1, 1, 1, 1 )
-#define MPP11_PTP_EVENT_REQ MPP( 11, 0x4, 1, 0, 1, 1, 1, 1, 0 )
-#define MPP11_PTP_TRIG_GEN MPP( 11, 0xc, 0, 1, 1, 1, 1, 1, 0 )
-#define MPP11_PTP_CLK MPP( 11, 0xd, 1, 0, 1, 1, 1, 1, 0 )
-#define MPP11_SATA0_ACTn MPP( 11, 0x5, 0, 1, 0, 1, 1, 1, 1 )
+#define MPP11_SPI_MISO MPP( 11, 0x2, 0, 0, 1, 1, 1, 1, 1 )
+#define MPP11_UART0_RXD MPP( 11, 0x3, 0, 0, 1, 1, 1, 1, 1 )
+#define MPP11_PTP_EVENT_REQ MPP( 11, 0x4, 0, 0, 1, 1, 1, 1, 0 )
+#define MPP11_PTP_TRIG_GEN MPP( 11, 0xc, 0, 0, 1, 1, 1, 1, 0 )
+#define MPP11_PTP_CLK MPP( 11, 0xd, 0, 0, 1, 1, 1, 1, 0 )
+#define MPP11_SATA0_ACTn MPP( 11, 0x5, 0, 0, 0, 1, 1, 1, 1 )
#define MPP12_GPO MPP( 12, 0x0, 0, 1, 1, 1, 1, 1, 1 )
-#define MPP12_SD_CLK MPP( 12, 0x1, 0, 1, 1, 1, 1, 1, 1 )
-#define MPP12_AU_SPDIF0 MPP( 12, 0xa, 0, 1, 0, 0, 0, 0, 1 )
-#define MPP12_SPI_MOSI MPP( 12, 0xb, 0, 1, 0, 0, 0, 0, 1 )
-#define MPP12_TW1_SDA MPP( 12, 0xd, 1, 0, 0, 0, 0, 0, 1 )
+#define MPP12_SD_CLK MPP( 12, 0x1, 0, 0, 1, 1, 1, 1, 1 )
+#define MPP12_AU_SPDIF0 MPP( 12, 0xa, 0, 0, 0, 0, 0, 0, 1 )
+#define MPP12_SPI_MOSI MPP( 12, 0xb, 0, 0, 0, 0, 0, 0, 1 )
+#define MPP12_TW1_SDA MPP( 12, 0xd, 0, 0, 0, 0, 0, 0, 1 )
#define MPP13_GPIO MPP( 13, 0x0, 1, 1, 1, 1, 1, 1, 1 )
-#define MPP13_SD_CMD MPP( 13, 0x1, 1, 1, 1, 1, 1, 1, 1 )
-#define MPP13_UART1_TXD MPP( 13, 0x3, 0, 1, 1, 1, 1, 1, 1 )
-#define MPP13_AU_SPDIFRMCLK MPP( 13, 0xa, 0, 1, 0, 0, 0, 0, 1 )
-#define MPP13_LCDPWM MPP( 13, 0xb, 0, 1, 0, 0, 0, 0, 1 )
+#define MPP13_SD_CMD MPP( 13, 0x1, 0, 0, 1, 1, 1, 1, 1 )
+#define MPP13_UART1_TXD MPP( 13, 0x3, 0, 0, 1, 1, 1, 1, 1 )
+#define MPP13_AU_SPDIFRMCLK MPP( 13, 0xa, 0, 0, 0, 0, 0, 0, 1 )
+#define MPP13_LCDPWM MPP( 13, 0xb, 0, 0, 0, 0, 0, 0, 1 )
#define MPP14_GPIO MPP( 14, 0x0, 1, 1, 1, 1, 1, 1, 1 )
-#define MPP14_SD_D0 MPP( 14, 0x1, 1, 1, 1, 1, 1, 1, 1 )
-#define MPP14_UART1_RXD MPP( 14, 0x3, 1, 0, 1, 1, 1, 1, 1 )
-#define MPP14_SATA1_PRESENTn MPP( 14, 0x4, 0, 1, 0, 0, 1, 1, 1 )
-#define MPP14_AU_SPDIFI MPP( 14, 0xa, 1, 0, 0, 0, 0, 0, 1 )
-#define MPP14_AU_I2SDI MPP( 14, 0xb, 1, 0, 0, 0, 0, 0, 1 )
-#define MPP14_MII0_COL MPP( 14, 0xd, 1, 0, 1, 1, 1, 1, 1 )
+#define MPP14_SD_D0 MPP( 14, 0x1, 0, 0, 1, 1, 1, 1, 1 )
+#define MPP14_UART1_RXD MPP( 14, 0x3, 0, 0, 1, 1, 1, 1, 1 )
+#define MPP14_SATA1_PRESENTn MPP( 14, 0x4, 0, 0, 0, 0, 1, 1, 1 )
+#define MPP14_AU_SPDIFI MPP( 14, 0xa, 0, 0, 0, 0, 0, 0, 1 )
+#define MPP14_AU_I2SDI MPP( 14, 0xb, 0, 0, 0, 0, 0, 0, 1 )
+#define MPP14_MII0_COL MPP( 14, 0xd, 0, 0, 1, 1, 1, 1, 1 )
#define MPP15_GPIO MPP( 15, 0x0, 1, 1, 1, 1, 1, 1, 1 )
-#define MPP15_SD_D1 MPP( 15, 0x1, 1, 1, 1, 1, 1, 1, 1 )
-#define MPP15_UART0_RTS MPP( 15, 0x2, 0, 1, 1, 1, 1, 1, 1 )
-#define MPP15_UART1_TXD MPP( 15, 0x3, 0, 1, 1, 1, 1, 1, 1 )
-#define MPP15_SATA0_ACTn MPP( 15, 0x4, 0, 1, 0, 1, 1, 1, 1 )
-#define MPP15_SPI_CSn MPP( 15, 0xb, 0, 1, 0, 0, 0, 0, 1 )
+#define MPP15_SD_D1 MPP( 15, 0x1, 0, 0, 1, 1, 1, 1, 1 )
+#define MPP15_UART0_RTS MPP( 15, 0x2, 0, 0, 1, 1, 1, 1, 1 )
+#define MPP15_UART1_TXD MPP( 15, 0x3, 0, 0, 1, 1, 1, 1, 1 )
+#define MPP15_SATA0_ACTn MPP( 15, 0x4, 0, 0, 0, 1, 1, 1, 1 )
+#define MPP15_SPI_CSn MPP( 15, 0xb, 0, 0, 0, 0, 0, 0, 1 )
#define MPP16_GPIO MPP( 16, 0x0, 1, 1, 1, 1, 1, 1, 1 )
-#define MPP16_SD_D2 MPP( 16, 0x1, 1, 1, 1, 1, 1, 1, 1 )
-#define MPP16_UART0_CTS MPP( 16, 0x2, 1, 0, 1, 1, 1, 1, 1 )
-#define MPP16_UART1_RXD MPP( 16, 0x3, 1, 0, 1, 1, 1, 1, 1 )
-#define MPP16_SATA1_ACTn MPP( 16, 0x4, 0, 1, 0, 0, 1, 1, 1 )
-#define MPP16_LCD_EXT_REF_CLK MPP( 16, 0xb, 1, 0, 0, 0, 0, 0, 1 )
-#define MPP16_MII0_CRS MPP( 16, 0xd, 1, 0, 1, 1, 1, 1, 1 )
+#define MPP16_SD_D2 MPP( 16, 0x1, 0, 0, 1, 1, 1, 1, 1 )
+#define MPP16_UART0_CTS MPP( 16, 0x2, 0, 0, 1, 1, 1, 1, 1 )
+#define MPP16_UART1_RXD MPP( 16, 0x3, 0, 0, 1, 1, 1, 1, 1 )
+#define MPP16_SATA1_ACTn MPP( 16, 0x4, 0, 0, 0, 0, 1, 1, 1 )
+#define MPP16_LCD_EXT_REF_CLK MPP( 16, 0xb, 0, 0, 0, 0, 0, 0, 1 )
+#define MPP16_MII0_CRS MPP( 16, 0xd, 0, 0, 1, 1, 1, 1, 1 )
#define MPP17_GPIO MPP( 17, 0x0, 1, 1, 1, 1, 1, 1, 1 )
-#define MPP17_SD_D3 MPP( 17, 0x1, 1, 1, 1, 1, 1, 1, 1 )
-#define MPP17_SATA0_PRESENTn MPP( 17, 0x4, 0, 1, 0, 1, 1, 1, 1 )
-#define MPP17_SATA1_ACTn MPP( 17, 0xa, 0, 1, 0, 0, 0, 0, 1 )
-#define MPP17_TW1_SCK MPP( 17, 0xd, 1, 1, 0, 0, 0, 0, 1 )
+#define MPP17_SD_D3 MPP( 17, 0x1, 0, 0, 1, 1, 1, 1, 1 )
+#define MPP17_SATA0_PRESENTn MPP( 17, 0x4, 0, 0, 0, 1, 1, 1, 1 )
+#define MPP17_SATA1_ACTn MPP( 17, 0xa, 0, 0, 0, 0, 0, 0, 1 )
+#define MPP17_TW1_SCK MPP( 17, 0xd, 0, 0, 0, 0, 0, 0, 1 )
#define MPP18_GPO MPP( 18, 0x0, 0, 1, 1, 1, 1, 1, 1 )
-#define MPP18_NF_IO0 MPP( 18, 0x1, 1, 1, 1, 1, 1, 1, 1 )
-#define MPP18_PEX0_CLKREQ MPP( 18, 0x2, 0, 1, 0, 0, 0, 0, 1 )
+#define MPP18_NF_IO0 MPP( 18, 0x1, 0, 0, 1, 1, 1, 1, 1 )
+#define MPP18_PEX0_CLKREQ MPP( 18, 0x2, 0, 0, 0, 0, 0, 0, 1 )
#define MPP19_GPO MPP( 19, 0x0, 0, 1, 1, 1, 1, 1, 1 )
-#define MPP19_NF_IO1 MPP( 19, 0x1, 1, 1, 1, 1, 1, 1, 1 )
+#define MPP19_NF_IO1 MPP( 19, 0x1, 0, 0, 1, 1, 1, 1, 1 )
#define MPP20_GPIO MPP( 20, 0x0, 1, 1, 0, 1, 1, 1, 1 )
-#define MPP20_TSMP0 MPP( 20, 0x1, 1, 1, 0, 0, 1, 1, 1 )
-#define MPP20_TDM_CH0_TX_QL MPP( 20, 0x2, 0, 1, 0, 0, 1, 1, 1 )
+#define MPP20_TSMP0 MPP( 20, 0x1, 0, 0, 0, 0, 1, 1, 1 )
+#define MPP20_TDM_CH0_TX_QL MPP( 20, 0x2, 0, 0, 0, 0, 1, 1, 1 )
#define MPP20_GE1_TXD0 MPP( 20, 0x3, 0, 0, 0, 1, 1, 1, 1 )
-#define MPP20_AU_SPDIFI MPP( 20, 0x4, 1, 0, 0, 0, 1, 1, 1 )
-#define MPP20_SATA1_ACTn MPP( 20, 0x5, 0, 1, 0, 0, 1, 1, 1 )
+#define MPP20_AU_SPDIFI MPP( 20, 0x4, 0, 0, 0, 0, 1, 1, 1 )
+#define MPP20_SATA1_ACTn MPP( 20, 0x5, 0, 0, 0, 0, 1, 1, 1 )
#define MPP20_LCD_D0 MPP( 20, 0xb, 0, 0, 0, 0, 0, 0, 1 )
#define MPP21_GPIO MPP( 21, 0x0, 1, 1, 0, 1, 1, 1, 1 )
-#define MPP21_TSMP1 MPP( 21, 0x1, 1, 1, 0, 0, 1, 1, 1 )
-#define MPP21_TDM_CH0_RX_QL MPP( 21, 0x2, 0, 1, 0, 0, 1, 1, 1 )
+#define MPP21_TSMP1 MPP( 21, 0x1, 0, 0, 0, 0, 1, 1, 1 )
+#define MPP21_TDM_CH0_RX_QL MPP( 21, 0x2, 0, 0, 0, 0, 1, 1, 1 )
#define MPP21_GE1_TXD1 MPP( 21, 0x3, 0, 0, 0, 1, 1, 1, 1 )
-#define MPP21_AU_SPDIFO MPP( 21, 0x4, 0, 1, 0, 0, 1, 1, 1 )
-#define MPP21_SATA0_ACTn MPP( 21, 0x5, 0, 1, 0, 1, 1, 1, 1 )
+#define MPP21_AU_SPDIFO MPP( 21, 0x4, 0, 0, 0, 0, 1, 1, 1 )
+#define MPP21_SATA0_ACTn MPP( 21, 0x5, 0, 0, 0, 1, 1, 1, 1 )
#define MPP21_LCD_D1 MPP( 21, 0xb, 0, 0, 0, 0, 0, 0, 1 )
#define MPP22_GPIO MPP( 22, 0x0, 1, 1, 0, 1, 1, 1, 1 )
-#define MPP22_TSMP2 MPP( 22, 0x1, 1, 1, 0, 0, 1, 1, 1 )
-#define MPP22_TDM_CH2_TX_QL MPP( 22, 0x2, 0, 1, 0, 0, 1, 1, 1 )
+#define MPP22_TSMP2 MPP( 22, 0x1, 0, 0, 0, 0, 1, 1, 1 )
+#define MPP22_TDM_CH2_TX_QL MPP( 22, 0x2, 0, 0, 0, 0, 1, 1, 1 )
#define MPP22_GE1_TXD2 MPP( 22, 0x3, 0, 0, 0, 1, 1, 1, 1 )
-#define MPP22_AU_SPDIFRMKCLK MPP( 22, 0x4, 0, 1, 0, 0, 1, 1, 1 )
-#define MPP22_SATA1_PRESENTn MPP( 22, 0x5, 0, 1, 0, 0, 1, 1, 1 )
+#define MPP22_AU_SPDIFRMKCLK MPP( 22, 0x4, 0, 0, 0, 0, 1, 1, 1 )
+#define MPP22_SATA1_PRESENTn MPP( 22, 0x5, 0, 0, 0, 0, 1, 1, 1 )
#define MPP22_LCD_D2 MPP( 22, 0xb, 0, 0, 0, 0, 0, 0, 1 )
#define MPP23_GPIO MPP( 23, 0x0, 1, 1, 0, 1, 1, 1, 1 )
-#define MPP23_TSMP3 MPP( 23, 0x1, 1, 1, 0, 0, 1, 1, 1 )
-#define MPP23_TDM_CH2_RX_QL MPP( 23, 0x2, 1, 0, 0, 0, 1, 1, 1 )
+#define MPP23_TSMP3 MPP( 23, 0x1, 0, 0, 0, 0, 1, 1, 1 )
+#define MPP23_TDM_CH2_RX_QL MPP( 23, 0x2, 0, 0, 0, 0, 1, 1, 1 )
#define MPP23_GE1_TXD3 MPP( 23, 0x3, 0, 0, 0, 1, 1, 1, 1 )
-#define MPP23_AU_I2SBCLK MPP( 23, 0x4, 0, 1, 0, 0, 1, 1, 1 )
-#define MPP23_SATA0_PRESENTn MPP( 23, 0x5, 0, 1, 0, 1, 1, 1, 1 )
+#define MPP23_AU_I2SBCLK MPP( 23, 0x4, 0, 0, 0, 0, 1, 1, 1 )
+#define MPP23_SATA0_PRESENTn MPP( 23, 0x5, 0, 0, 0, 1, 1, 1, 1 )
#define MPP23_LCD_D3 MPP( 23, 0xb, 0, 0, 0, 0, 0, 0, 1 )
#define MPP24_GPIO MPP( 24, 0x0, 1, 1, 0, 1, 1, 1, 1 )
-#define MPP24_TSMP4 MPP( 24, 0x1, 1, 1, 0, 0, 1, 1, 1 )
-#define MPP24_TDM_SPI_CS0 MPP( 24, 0x2, 0, 1, 0, 0, 1, 1, 1 )
+#define MPP24_TSMP4 MPP( 24, 0x1, 0, 0, 0, 0, 1, 1, 1 )
+#define MPP24_TDM_SPI_CS0 MPP( 24, 0x2, 0, 0, 0, 0, 1, 1, 1 )
#define MPP24_GE1_RXD0 MPP( 24, 0x3, 0, 0, 0, 1, 1, 1, 1 )
-#define MPP24_AU_I2SDO MPP( 24, 0x4, 0, 1, 0, 0, 1, 1, 1 )
+#define MPP24_AU_I2SDO MPP( 24, 0x4, 0, 0, 0, 0, 1, 1, 1 )
#define MPP24_LCD_D4 MPP( 24, 0xb, 0, 0, 0, 0, 0, 0, 1 )
#define MPP25_GPIO MPP( 25, 0x0, 1, 1, 0, 1, 1, 1, 1 )
-#define MPP25_TSMP5 MPP( 25, 0x1, 1, 1, 0, 0, 1, 1, 1 )
-#define MPP25_TDM_SPI_SCK MPP( 25, 0x2, 0, 1, 0, 0, 1, 1, 1 )
+#define MPP25_TSMP5 MPP( 25, 0x1, 0, 0, 0, 0, 1, 1, 1 )
+#define MPP25_TDM_SPI_SCK MPP( 25, 0x2, 0, 0, 0, 0, 1, 1, 1 )
#define MPP25_GE1_RXD1 MPP( 25, 0x3, 0, 0, 0, 1, 1, 1, 1 )
-#define MPP25_AU_I2SLRCLK MPP( 25, 0x4, 0, 1, 0, 0, 1, 1, 1 )
+#define MPP25_AU_I2SLRCLK MPP( 25, 0x4, 0, 0, 0, 0, 1, 1, 1 )
#define MPP25_LCD_D5 MPP( 25, 0xb, 0, 0, 0, 0, 0, 0, 1 )
#define MPP26_GPIO MPP( 26, 0x0, 1, 1, 0, 1, 1, 1, 1 )
-#define MPP26_TSMP6 MPP( 26, 0x1, 1, 1, 0, 0, 1, 1, 1 )
-#define MPP26_TDM_SPI_MISO MPP( 26, 0x2, 1, 0, 0, 0, 1, 1, 1 )
+#define MPP26_TSMP6 MPP( 26, 0x1, 0, 0, 0, 0, 1, 1, 1 )
+#define MPP26_TDM_SPI_MISO MPP( 26, 0x2, 0, 0, 0, 0, 1, 1, 1 )
#define MPP26_GE1_RXD2 MPP( 26, 0x3, 0, 0, 0, 1, 1, 1, 1 )
-#define MPP26_AU_I2SMCLK MPP( 26, 0x4, 0, 1, 0, 0, 1, 1, 1 )
+#define MPP26_AU_I2SMCLK MPP( 26, 0x4, 0, 0, 0, 0, 1, 1, 1 )
#define MPP26_LCD_D6 MPP( 26, 0xb, 0, 0, 0, 0, 0, 0, 1 )
#define MPP27_GPIO MPP( 27, 0x0, 1, 1, 0, 1, 1, 1, 1 )
-#define MPP27_TSMP7 MPP( 27, 0x1, 1, 1, 0, 0, 1, 1, 1 )
-#define MPP27_TDM_SPI_MOSI MPP( 27, 0x2, 0, 1, 0, 0, 1, 1, 1 )
+#define MPP27_TSMP7 MPP( 27, 0x1, 0, 0, 0, 0, 1, 1, 1 )
+#define MPP27_TDM_SPI_MOSI MPP( 27, 0x2, 0, 0, 0, 0, 1, 1, 1 )
#define MPP27_GE1_RXD3 MPP( 27, 0x3, 0, 0, 0, 1, 1, 1, 1 )
-#define MPP27_AU_I2SDI MPP( 27, 0x4, 1, 0, 0, 0, 1, 1, 1 )
+#define MPP27_AU_I2SDI MPP( 27, 0x4, 0, 0, 0, 0, 1, 1, 1 )
#define MPP27_LCD_D7 MPP( 27, 0xb, 0, 0, 0, 0, 0, 0, 1 )
#define MPP28_GPIO MPP( 28, 0x0, 1, 1, 0, 1, 1, 1, 1 )
-#define MPP28_TSMP8 MPP( 28, 0x1, 1, 1, 0, 0, 1, 1, 1 )
+#define MPP28_TSMP8 MPP( 28, 0x1, 0, 0, 0, 0, 1, 1, 1 )
#define MPP28_TDM_CODEC_INTn MPP( 28, 0x2, 0, 0, 0, 0, 1, 1, 1 )
#define MPP28_GE1_COL MPP( 28, 0x3, 0, 0, 0, 1, 1, 1, 1 )
-#define MPP28_AU_EXTCLK MPP( 28, 0x4, 1, 0, 0, 0, 1, 1, 1 )
+#define MPP28_AU_EXTCLK MPP( 28, 0x4, 0, 0, 0, 0, 1, 1, 1 )
#define MPP28_LCD_D8 MPP( 28, 0xb, 0, 0, 0, 0, 0, 0, 1 )
#define MPP29_GPIO MPP( 29, 0x0, 1, 1, 0, 1, 1, 1, 1 )
-#define MPP29_TSMP9 MPP( 29, 0x1, 1, 1, 0, 0, 1, 1, 1 )
+#define MPP29_TSMP9 MPP( 29, 0x1, 0, 0, 0, 0, 1, 1, 1 )
#define MPP29_TDM_CODEC_RSTn MPP( 29, 0x2, 0, 0, 0, 0, 1, 1, 1 )
#define MPP29_GE1_TCLK MPP( 29, 0x3, 0, 0, 0, 1, 1, 1, 1 )
#define MPP29_LCD_D9 MPP( 29, 0xb, 0, 0, 0, 0, 0, 0, 1 )
#define MPP30_GPIO MPP( 30, 0x0, 1, 1, 0, 1, 1, 1, 1 )
-#define MPP30_TSMP10 MPP( 30, 0x1, 1, 1, 0, 0, 1, 1, 1 )
-#define MPP30_TDM_PCLK MPP( 30, 0x2, 1, 1, 0, 0, 1, 1, 1 )
+#define MPP30_TSMP10 MPP( 30, 0x1, 0, 0, 0, 0, 1, 1, 1 )
+#define MPP30_TDM_PCLK MPP( 30, 0x2, 0, 0, 0, 0, 1, 1, 1 )
#define MPP30_GE1_RXCTL MPP( 30, 0x3, 0, 0, 0, 1, 1, 1, 1 )
#define MPP30_LCD_D10 MPP( 30, 0xb, 0, 0, 0, 0, 0, 0, 1 )
#define MPP31_GPIO MPP( 31, 0x0, 1, 1, 0, 1, 1, 1, 1 )
-#define MPP31_TSMP11 MPP( 31, 0x1, 1, 1, 0, 0, 1, 1, 1 )
-#define MPP31_TDM_FS MPP( 31, 0x2, 1, 1, 0, 0, 1, 1, 1 )
+#define MPP31_TSMP11 MPP( 31, 0x1, 0, 0, 0, 0, 1, 1, 1 )
+#define MPP31_TDM_FS MPP( 31, 0x2, 0, 0, 0, 0, 1, 1, 1 )
#define MPP31_GE1_RXCLK MPP( 31, 0x3, 0, 0, 0, 1, 1, 1, 1 )
#define MPP31_LCD_D11 MPP( 31, 0xb, 0, 0, 0, 0, 0, 0, 1 )
#define MPP32_GPIO MPP( 32, 0x0, 1, 1, 0, 1, 1, 1, 1 )
-#define MPP32_TSMP12 MPP( 32, 0x1, 1, 1, 0, 0, 1, 1, 1 )
-#define MPP32_TDM_DRX MPP( 32, 0x2, 1, 0, 0, 0, 1, 1, 1 )
+#define MPP32_TSMP12 MPP( 32, 0x1, 0, 0, 0, 0, 1, 1, 1 )
+#define MPP32_TDM_DRX MPP( 32, 0x2, 0, 0, 0, 0, 1, 1, 1 )
#define MPP32_GE1_TCLKOUT MPP( 32, 0x3, 0, 0, 0, 1, 1, 1, 1 )
#define MPP32_LCD_D12 MPP( 32, 0xb, 0, 0, 0, 0, 0, 0, 1 )
#define MPP33_GPO MPP( 33, 0x0, 0, 1, 0, 1, 1, 1, 1 )
-#define MPP33_TDM_DTX MPP( 33, 0x2, 0, 1, 0, 0, 1, 1, 1 )
+#define MPP33_TDM_DTX MPP( 33, 0x2, 0, 0, 0, 0, 1, 1, 1 )
#define MPP33_GE1_TXCTL MPP( 33, 0x3, 0, 0, 0, 1, 1, 1, 1 )
#define MPP33_LCD_D13 MPP( 33, 0xb, 0, 0, 0, 0, 0, 0, 1 )
#define MPP34_GPIO MPP( 34, 0x0, 1, 1, 0, 1, 1, 1, 1 )
-#define MPP34_TDM_SPI_CS1 MPP( 34, 0x2, 0, 1, 0, 0, 1, 1, 1 )
+#define MPP34_TDM_SPI_CS1 MPP( 34, 0x2, 0, 0, 0, 0, 1, 1, 1 )
#define MPP34_GE1_TXEN MPP( 34, 0x3, 0, 0, 0, 1, 1, 1, 1 )
-#define MPP34_SATA1_ACTn MPP( 34, 0x5, 0, 1, 0, 0, 0, 1, 1 )
+#define MPP34_SATA1_ACTn MPP( 34, 0x5, 0, 0, 0, 0, 0, 1, 1 )
#define MPP34_LCD_D14 MPP( 34, 0xb, 0, 0, 0, 0, 0, 0, 1 )
#define MPP35_GPIO MPP( 35, 0x0, 1, 1, 1, 1, 1, 1, 1 )
-#define MPP35_TDM_CH0_TX_QL MPP( 35, 0x2, 0, 1, 0, 0, 1, 1, 1 )
+#define MPP35_TDM_CH0_TX_QL MPP( 35, 0x2, 0, 0, 0, 0, 1, 1, 1 )
#define MPP35_GE1_RXERR MPP( 35, 0x3, 0, 0, 0, 1, 1, 1, 1 )
-#define MPP35_SATA0_ACTn MPP( 35, 0x5, 0, 1, 0, 1, 1, 1, 1 )
+#define MPP35_SATA0_ACTn MPP( 35, 0x5, 0, 0, 0, 1, 1, 1, 1 )
#define MPP35_LCD_D15 MPP( 22, 0xb, 0, 0, 0, 0, 0, 0, 1 )
-#define MPP35_MII0_RXERR MPP( 35, 0xc, 1, 0, 1, 1, 1, 1, 1 )
+#define MPP35_MII0_RXERR MPP( 35, 0xc, 0, 0, 1, 1, 1, 1, 1 )
#define MPP36_GPIO MPP( 36, 0x0, 1, 1, 1, 0, 0, 1, 1 )
-#define MPP36_TSMP0 MPP( 36, 0x1, 1, 1, 0, 0, 0, 1, 1 )
-#define MPP36_TDM_SPI_CS1 MPP( 36, 0x2, 0, 1, 0, 0, 0, 1, 1 )
-#define MPP36_AU_SPDIFI MPP( 36, 0x4, 1, 0, 1, 0, 0, 1, 1 )
-#define MPP36_TW1_SDA MPP( 36, 0xb, 1, 1, 0, 0, 0, 0, 1 )
+#define MPP36_TSMP0 MPP( 36, 0x1, 0, 0, 0, 0, 0, 1, 1 )
+#define MPP36_TDM_SPI_CS1 MPP( 36, 0x2, 0, 0, 0, 0, 0, 1, 1 )
+#define MPP36_AU_SPDIFI MPP( 36, 0x4, 0, 0, 1, 0, 0, 1, 1 )
+#define MPP36_TW1_SDA MPP( 36, 0xb, 0, 0, 0, 0, 0, 0, 1 )
#define MPP37_GPIO MPP( 37, 0x0, 1, 1, 1, 0, 0, 1, 1 )
-#define MPP37_TSMP1 MPP( 37, 0x1, 1, 1, 0, 0, 0, 1, 1 )
-#define MPP37_TDM_CH2_TX_QL MPP( 37, 0x2, 0, 1, 0, 0, 0, 1, 1 )
-#define MPP37_AU_SPDIFO MPP( 37, 0x4, 0, 1, 1, 0, 0, 1, 1 )
-#define MPP37_TW1_SCK MPP( 37, 0xb, 1, 1, 0, 0, 0, 0, 1 )
+#define MPP37_TSMP1 MPP( 37, 0x1, 0, 0, 0, 0, 0, 1, 1 )
+#define MPP37_TDM_CH2_TX_QL MPP( 37, 0x2, 0, 0, 0, 0, 0, 1, 1 )
+#define MPP37_AU_SPDIFO MPP( 37, 0x4, 0, 0, 1, 0, 0, 1, 1 )
+#define MPP37_TW1_SCK MPP( 37, 0xb, 0, 0, 0, 0, 0, 0, 1 )
#define MPP38_GPIO MPP( 38, 0x0, 1, 1, 1, 0, 0, 1, 1 )
-#define MPP38_TSMP2 MPP( 38, 0x1, 1, 1, 0, 0, 0, 1, 1 )
-#define MPP38_TDM_CH2_RX_QL MPP( 38, 0x2, 0, 1, 0, 0, 0, 1, 1 )
-#define MPP38_AU_SPDIFRMLCLK MPP( 38, 0x4, 0, 1, 1, 0, 0, 1, 1 )
+#define MPP38_TSMP2 MPP( 38, 0x1, 0, 0, 0, 0, 0, 1, 1 )
+#define MPP38_TDM_CH2_RX_QL MPP( 38, 0x2, 0, 0, 0, 0, 0, 1, 1 )
+#define MPP38_AU_SPDIFRMLCLK MPP( 38, 0x4, 0, 0, 1, 0, 0, 1, 1 )
#define MPP38_LCD_D18 MPP( 38, 0xb, 0, 0, 0, 0, 0, 0, 1 )
#define MPP39_GPIO MPP( 39, 0x0, 1, 1, 1, 0, 0, 1, 1 )
-#define MPP39_TSMP3 MPP( 39, 0x1, 1, 1, 0, 0, 0, 1, 1 )
-#define MPP39_TDM_SPI_CS0 MPP( 39, 0x2, 0, 1, 0, 0, 0, 1, 1 )
-#define MPP39_AU_I2SBCLK MPP( 39, 0x4, 0, 1, 1, 0, 0, 1, 1 )
+#define MPP39_TSMP3 MPP( 39, 0x1, 0, 0, 0, 0, 0, 1, 1 )
+#define MPP39_TDM_SPI_CS0 MPP( 39, 0x2, 0, 0, 0, 0, 0, 1, 1 )
+#define MPP39_AU_I2SBCLK MPP( 39, 0x4, 0, 0, 1, 0, 0, 1, 1 )
#define MPP39_LCD_D19 MPP( 39, 0xb, 0, 0, 0, 0, 0, 0, 1 )
#define MPP40_GPIO MPP( 40, 0x0, 1, 1, 1, 0, 0, 1, 1 )
-#define MPP40_TSMP4 MPP( 40, 0x1, 1, 1, 0, 0, 0, 1, 1 )
-#define MPP40_TDM_SPI_SCK MPP( 40, 0x2, 0, 1, 0, 0, 0, 1, 1 )
-#define MPP40_AU_I2SDO MPP( 40, 0x4, 0, 1, 1, 0, 0, 1, 1 )
+#define MPP40_TSMP4 MPP( 40, 0x1, 0, 0, 0, 0, 0, 1, 1 )
+#define MPP40_TDM_SPI_SCK MPP( 40, 0x2, 0, 0, 0, 0, 0, 1, 1 )
+#define MPP40_AU_I2SDO MPP( 40, 0x4, 0, 0, 1, 0, 0, 1, 1 )
#define MPP40_LCD_D20 MPP( 40, 0xb, 0, 0, 0, 0, 0, 0, 1 )
#define MPP41_GPIO MPP( 41, 0x0, 1, 1, 1, 0, 0, 1, 1 )
-#define MPP41_TSMP5 MPP( 41, 0x1, 1, 1, 0, 0, 0, 1, 1 )
-#define MPP41_TDM_SPI_MISO MPP( 41, 0x2, 1, 0, 0, 0, 0, 1, 1 )
-#define MPP41_AU_I2SLRCLK MPP( 41, 0x4, 0, 1, 1, 0, 0, 1, 1 )
+#define MPP41_TSMP5 MPP( 41, 0x1, 0, 0, 0, 0, 0, 1, 1 )
+#define MPP41_TDM_SPI_MISO MPP( 41, 0x2, 0, 0, 0, 0, 0, 1, 1 )
+#define MPP41_AU_I2SLRCLK MPP( 41, 0x4, 0, 0, 1, 0, 0, 1, 1 )
#define MPP41_LCD_D21 MPP( 41, 0xb, 0, 0, 0, 0, 0, 0, 1 )
#define MPP42_GPIO MPP( 42, 0x0, 1, 1, 1, 0, 0, 1, 1 )
-#define MPP42_TSMP6 MPP( 42, 0x1, 1, 1, 0, 0, 0, 1, 1 )
-#define MPP42_TDM_SPI_MOSI MPP( 42, 0x2, 0, 1, 0, 0, 0, 1, 1 )
-#define MPP42_AU_I2SMCLK MPP( 42, 0x4, 0, 1, 1, 0, 0, 1, 1 )
+#define MPP42_TSMP6 MPP( 42, 0x1, 0, 0, 0, 0, 0, 1, 1 )
+#define MPP42_TDM_SPI_MOSI MPP( 42, 0x2, 0, 0, 0, 0, 0, 1, 1 )
+#define MPP42_AU_I2SMCLK MPP( 42, 0x4, 0, 0, 1, 0, 0, 1, 1 )
#define MPP42_LCD_D22 MPP( 42, 0xb, 0, 0, 0, 0, 0, 0, 1 )
#define MPP43_GPIO MPP( 43, 0x0, 1, 1, 1, 0, 0, 1, 1 )
-#define MPP43_TSMP7 MPP( 43, 0x1, 1, 1, 0, 0, 0, 1, 1 )
+#define MPP43_TSMP7 MPP( 43, 0x1, 0, 0, 0, 0, 0, 1, 1 )
#define MPP43_TDM_CODEC_INTn MPP( 43, 0x2, 0, 0, 0, 0, 0, 1, 1 )
-#define MPP43_AU_I2SDI MPP( 43, 0x4, 1, 0, 1, 0, 0, 1, 1 )
+#define MPP43_AU_I2SDI MPP( 43, 0x4, 0, 0, 1, 0, 0, 1, 1 )
#define MPP43_LCD_D23 MPP( 22, 0xb, 0, 0, 0, 0, 0, 0, 1 )
#define MPP44_GPIO MPP( 44, 0x0, 1, 1, 1, 0, 0, 1, 1 )
-#define MPP44_TSMP8 MPP( 44, 0x1, 1, 1, 0, 0, 0, 1, 1 )
+#define MPP44_TSMP8 MPP( 44, 0x1, 0, 0, 0, 0, 0, 1, 1 )
#define MPP44_TDM_CODEC_RSTn MPP( 44, 0x2, 0, 0, 0, 0, 0, 1, 1 )
-#define MPP44_AU_EXTCLK MPP( 44, 0x4, 1, 0, 1, 0, 0, 1, 1 )
+#define MPP44_AU_EXTCLK MPP( 44, 0x4, 0, 0, 1, 0, 0, 1, 1 )
#define MPP44_LCD_CLK MPP( 44, 0xb, 0, 0, 0, 0, 0, 0, 1 )
#define MPP45_GPIO MPP( 45, 0x0, 1, 1, 0, 0, 0, 1, 1 )
-#define MPP45_TSMP9 MPP( 45, 0x1, 1, 1, 0, 0, 0, 1, 1 )
-#define MPP45_TDM_PCLK MPP( 45, 0x2, 1, 1, 0, 0, 0, 1, 1 )
+#define MPP45_TSMP9 MPP( 45, 0x1, 0, 0, 0, 0, 0, 1, 1 )
+#define MPP45_TDM_PCLK MPP( 45, 0x2, 0, 0, 0, 0, 0, 1, 1 )
#define MPP245_LCD_E MPP( 45, 0xb, 0, 0, 0, 0, 0, 0, 1 )
#define MPP46_GPIO MPP( 46, 0x0, 1, 1, 0, 0, 0, 1, 1 )
-#define MPP46_TSMP10 MPP( 46, 0x1, 1, 1, 0, 0, 0, 1, 1 )
-#define MPP46_TDM_FS MPP( 46, 0x2, 1, 1, 0, 0, 0, 1, 1 )
+#define MPP46_TSMP10 MPP( 46, 0x1, 0, 0, 0, 0, 0, 1, 1 )
+#define MPP46_TDM_FS MPP( 46, 0x2, 0, 0, 0, 0, 0, 1, 1 )
#define MPP46_LCD_HSYNC MPP( 46, 0xb, 0, 0, 0, 0, 0, 0, 1 )
#define MPP47_GPIO MPP( 47, 0x0, 1, 1, 0, 0, 0, 1, 1 )
-#define MPP47_TSMP11 MPP( 47, 0x1, 1, 1, 0, 0, 0, 1, 1 )
-#define MPP47_TDM_DRX MPP( 47, 0x2, 1, 0, 0, 0, 0, 1, 1 )
+#define MPP47_TSMP11 MPP( 47, 0x1, 0, 0, 0, 0, 0, 1, 1 )
+#define MPP47_TDM_DRX MPP( 47, 0x2, 0, 0, 0, 0, 0, 1, 1 )
#define MPP47_LCD_VSYNC MPP( 47, 0xb, 0, 0, 0, 0, 0, 0, 1 )
#define MPP48_GPIO MPP( 48, 0x0, 1, 1, 0, 0, 0, 1, 1 )
-#define MPP48_TSMP12 MPP( 48, 0x1, 1, 1, 0, 0, 0, 1, 1 )
-#define MPP48_TDM_DTX MPP( 48, 0x2, 0, 1, 0, 0, 0, 1, 1 )
+#define MPP48_TSMP12 MPP( 48, 0x1, 0, 0, 0, 0, 0, 1, 1 )
+#define MPP48_TDM_DTX MPP( 48, 0x2, 0, 0, 0, 0, 0, 1, 1 )
#define MPP48_LCD_D16 MPP( 22, 0xb, 0, 0, 0, 0, 0, 0, 1 )
#define MPP49_GPIO MPP( 49, 0x0, 1, 1, 0, 0, 0, 1, 0 )
#define MPP49_GPO MPP( 49, 0x0, 0, 1, 0, 0, 0, 0, 1 )
-#define MPP49_TSMP9 MPP( 49, 0x1, 1, 1, 0, 0, 0, 1, 0 )
-#define MPP49_TDM_CH0_RX_QL MPP( 49, 0x2, 0, 1, 0, 0, 0, 1, 1 )
-#define MPP49_PTP_CLK MPP( 49, 0x5, 1, 0, 0, 0, 0, 1, 0 )
-#define MPP49_PEX0_CLKREQ MPP( 49, 0xa, 0, 1, 0, 0, 0, 0, 1 )
+#define MPP49_TSMP9 MPP( 49, 0x1, 0, 0, 0, 0, 0, 1, 0 )
+#define MPP49_TDM_CH0_RX_QL MPP( 49, 0x2, 0, 0, 0, 0, 0, 1, 1 )
+#define MPP49_PTP_CLK MPP( 49, 0x5, 0, 0, 0, 0, 0, 1, 0 )
+#define MPP49_PEX0_CLKREQ MPP( 49, 0xa, 0, 0, 0, 0, 0, 0, 1 )
#define MPP49_LCD_D17 MPP( 49, 0xb, 0, 0, 0, 0, 0, 0, 1 )
#define MPP_MAX 49
diff --git a/arch/arm/mach-kirkwood/ts219-setup.c b/arch/arm/mach-kirkwood/ts219-setup.c
index 68f32f2bf55..eb1a7bae95c 100644
--- a/arch/arm/mach-kirkwood/ts219-setup.c
+++ b/arch/arm/mach-kirkwood/ts219-setup.c
@@ -124,7 +124,7 @@ static void __init qnap_ts219_init(void)
static int __init ts219_pci_init(void)
{
if (machine_is_ts219())
- kirkwood_pcie_init(KW_PCIE0);
+ kirkwood_pcie_init(KW_PCIE1 | KW_PCIE0);
return 0;
}
diff --git a/arch/arm/mach-lpc32xx/include/mach/irqs.h b/arch/arm/mach-lpc32xx/include/mach/irqs.h
index 2667f52e3b0..9e3b90df32e 100644
--- a/arch/arm/mach-lpc32xx/include/mach/irqs.h
+++ b/arch/arm/mach-lpc32xx/include/mach/irqs.h
@@ -61,7 +61,7 @@
*/
#define IRQ_LPC32XX_JTAG_COMM_TX LPC32XX_SIC1_IRQ(1)
#define IRQ_LPC32XX_JTAG_COMM_RX LPC32XX_SIC1_IRQ(2)
-#define IRQ_LPC32XX_GPI_11 LPC32XX_SIC1_IRQ(4)
+#define IRQ_LPC32XX_GPI_28 LPC32XX_SIC1_IRQ(4)
#define IRQ_LPC32XX_TS_P LPC32XX_SIC1_IRQ(6)
#define IRQ_LPC32XX_TS_IRQ LPC32XX_SIC1_IRQ(7)
#define IRQ_LPC32XX_TS_AUX LPC32XX_SIC1_IRQ(8)
diff --git a/arch/arm/mach-lpc32xx/irq.c b/arch/arm/mach-lpc32xx/irq.c
index 4eae566dfdc..c74de01ab5b 100644
--- a/arch/arm/mach-lpc32xx/irq.c
+++ b/arch/arm/mach-lpc32xx/irq.c
@@ -118,6 +118,10 @@ static const struct lpc32xx_event_info lpc32xx_events[NR_IRQS] = {
.event_group = &lpc32xx_event_pin_regs,
.mask = LPC32XX_CLKPWR_EXTSRC_GPI_06_BIT,
},
+ [IRQ_LPC32XX_GPI_28] = {
+ .event_group = &lpc32xx_event_pin_regs,
+ .mask = LPC32XX_CLKPWR_EXTSRC_GPI_28_BIT,
+ },
[IRQ_LPC32XX_GPIO_00] = {
.event_group = &lpc32xx_event_int_regs,
.mask = LPC32XX_CLKPWR_INTSRC_GPIO_00_BIT,
@@ -305,9 +309,18 @@ static int lpc32xx_irq_wake(struct irq_data *d, unsigned int state)
if (state)
eventreg |= lpc32xx_events[d->irq].mask;
- else
+ else {
eventreg &= ~lpc32xx_events[d->irq].mask;
+ /*
+ * When disabling the wakeup, clear the latched
+ * event
+ */
+ __raw_writel(lpc32xx_events[d->irq].mask,
+ lpc32xx_events[d->irq].
+ event_group->rawstat_reg);
+ }
+
__raw_writel(eventreg,
lpc32xx_events[d->irq].event_group->enab_reg);
@@ -380,13 +393,15 @@ void __init lpc32xx_init_irq(void)
/* Setup SIC1 */
__raw_writel(0, LPC32XX_INTC_MASK(LPC32XX_SIC1_BASE));
- __raw_writel(MIC_APR_DEFAULT, LPC32XX_INTC_POLAR(LPC32XX_SIC1_BASE));
- __raw_writel(MIC_ATR_DEFAULT, LPC32XX_INTC_ACT_TYPE(LPC32XX_SIC1_BASE));
+ __raw_writel(SIC1_APR_DEFAULT, LPC32XX_INTC_POLAR(LPC32XX_SIC1_BASE));
+ __raw_writel(SIC1_ATR_DEFAULT,
+ LPC32XX_INTC_ACT_TYPE(LPC32XX_SIC1_BASE));
/* Setup SIC2 */
__raw_writel(0, LPC32XX_INTC_MASK(LPC32XX_SIC2_BASE));
- __raw_writel(MIC_APR_DEFAULT, LPC32XX_INTC_POLAR(LPC32XX_SIC2_BASE));
- __raw_writel(MIC_ATR_DEFAULT, LPC32XX_INTC_ACT_TYPE(LPC32XX_SIC2_BASE));
+ __raw_writel(SIC2_APR_DEFAULT, LPC32XX_INTC_POLAR(LPC32XX_SIC2_BASE));
+ __raw_writel(SIC2_ATR_DEFAULT,
+ LPC32XX_INTC_ACT_TYPE(LPC32XX_SIC2_BASE));
/* Configure supported IRQ's */
for (i = 0; i < NR_IRQS; i++) {
diff --git a/arch/arm/mach-lpc32xx/serial.c b/arch/arm/mach-lpc32xx/serial.c
index 429cfdbb2b3..f2735281616 100644
--- a/arch/arm/mach-lpc32xx/serial.c
+++ b/arch/arm/mach-lpc32xx/serial.c
@@ -88,6 +88,7 @@ struct uartinit {
char *uart_ck_name;
u32 ck_mode_mask;
void __iomem *pdiv_clk_reg;
+ resource_size_t mapbase;
};
static struct uartinit uartinit_data[] __initdata = {
@@ -97,6 +98,7 @@ static struct uartinit uartinit_data[] __initdata = {
.ck_mode_mask =
LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 5),
.pdiv_clk_reg = LPC32XX_CLKPWR_UART5_CLK_CTRL,
+ .mapbase = LPC32XX_UART5_BASE,
},
#endif
#ifdef CONFIG_ARCH_LPC32XX_UART3_SELECT
@@ -105,6 +107,7 @@ static struct uartinit uartinit_data[] __initdata = {
.ck_mode_mask =
LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 3),
.pdiv_clk_reg = LPC32XX_CLKPWR_UART3_CLK_CTRL,
+ .mapbase = LPC32XX_UART3_BASE,
},
#endif
#ifdef CONFIG_ARCH_LPC32XX_UART4_SELECT
@@ -113,6 +116,7 @@ static struct uartinit uartinit_data[] __initdata = {
.ck_mode_mask =
LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 4),
.pdiv_clk_reg = LPC32XX_CLKPWR_UART4_CLK_CTRL,
+ .mapbase = LPC32XX_UART4_BASE,
},
#endif
#ifdef CONFIG_ARCH_LPC32XX_UART6_SELECT
@@ -121,6 +125,7 @@ static struct uartinit uartinit_data[] __initdata = {
.ck_mode_mask =
LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 6),
.pdiv_clk_reg = LPC32XX_CLKPWR_UART6_CLK_CTRL,
+ .mapbase = LPC32XX_UART6_BASE,
},
#endif
};
@@ -165,11 +170,24 @@ void __init lpc32xx_serial_init(void)
/* pre-UART clock divider set to 1 */
__raw_writel(0x0101, uartinit_data[i].pdiv_clk_reg);
+
+ /*
+ * Force a flush of the RX FIFOs to work around a
+ * HW bug
+ */
+ puart = uartinit_data[i].mapbase;
+ __raw_writel(0xC1, LPC32XX_UART_IIR_FCR(puart));
+ __raw_writel(0x00, LPC32XX_UART_DLL_FIFO(puart));
+ j = LPC32XX_SUART_FIFO_SIZE;
+ while (j--)
+ tmp = __raw_readl(
+ LPC32XX_UART_DLL_FIFO(puart));
+ __raw_writel(0, LPC32XX_UART_IIR_FCR(puart));
}
/* This needs to be done after all UART clocks are setup */
__raw_writel(clkmodes, LPC32XX_UARTCTL_CLKMODE);
- for (i = 0; i < ARRAY_SIZE(uartinit_data) - 1; i++) {
+ for (i = 0; i < ARRAY_SIZE(uartinit_data); i++) {
/* Force a flush of the RX FIFOs to work around a HW bug */
puart = serial_std_platform_data[i].mapbase;
__raw_writel(0xC1, LPC32XX_UART_IIR_FCR(puart));
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index f7de361bbb5..776edcc7d1a 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -169,7 +169,7 @@ obj-$(CONFIG_MSM7KV2_AUDIO) += qdsp5v2_2x/
obj-$(CONFIG_MSM7KV2_AUDIO) += htc_acoustic_7x30.o htc_acdb_7x30.o
obj-$(CONFIG_MSM_QDSP6) += qdsp6/
-obj-$(CONFIG_MSM8X60_AUDIO) += qdsp6v2_1x/
+obj-$(CONFIG_MSM8X60_AUDIO) += qdsp6v3/
obj-$(CONFIG_MSM_AUDIO_QDSP6) += qdsp6v2/
obj-$(CONFIG_MSM_HW3D) += hw3d.o
ifdef CONFIG_PM
diff --git a/arch/arm/mach-msm/board-vigor-audio.c b/arch/arm/mach-msm/board-vigor-audio.c
index beac20b8758..b96a4d904b6 100644
--- a/arch/arm/mach-msm/board-vigor-audio.c
+++ b/arch/arm/mach-msm/board-vigor-audio.c
@@ -19,16 +19,17 @@
#include
#include
#include
+#include
#include
#include
#include
-#include
-#include
-#include
-#include
-#include
-#include
+#include
+#include
+#include
+#include
+#include
+#include
#include
#include
@@ -326,7 +327,7 @@ int vigor_is_msm_i2s_slave(void)
int vigor_support_aic3254(void)
{
- return 0;
+ return 1;
}
int vigor_support_adie(void)
@@ -336,7 +337,7 @@ int vigor_support_adie(void)
int vigor_support_back_mic(void)
{
- return 0;
+ return 1;
}
int vigor_is_msm_i2s_master(void)
@@ -404,10 +405,6 @@ static struct dev_ctrl_ops dops = {
.support_opendsp = vigor_support_opendsp,
};
-static struct q6asm_ops qops = {
- .get_q6_effect = vigor_get_q6_effect_mode,
-};
-
void __init vigor_audio_init(void)
{
int i = 0;
@@ -419,7 +416,6 @@ void __init vigor_audio_init(void)
htc_8x60_register_ecodec_ops(&eops);
htc_8x60_register_icodec_ops(&iops);
htc_8x60_register_dev_ctrl_ops(&dops);
- htc_8x60_register_q6asm_ops(&qops);
acoustic_register_ops(&acoustic);
/* PMIC GPIO Init (See board-vigor.c) */
diff --git a/arch/arm/mach-msm/board-vigor.c b/arch/arm/mach-msm/board-vigor.c
index bae59260f3e..9a86563b7ec 100644
--- a/arch/arm/mach-msm/board-vigor.c
+++ b/arch/arm/mach-msm/board-vigor.c
@@ -84,7 +84,6 @@
#include
#include
#endif
-#include
#include
#ifdef CONFIG_MSM_DSPS
#include
@@ -100,7 +99,7 @@
#include
#include
#ifdef CONFIG_USB_G_ANDROID
-#include
+#include
#include
#endif
#include
@@ -135,6 +134,9 @@
#include
#include
+#include
+#include
+
#ifdef CONFIG_PERFLOCK
#include
#endif
@@ -346,6 +348,10 @@ int __init vigor_init_panel(struct resource *res, size_t size);
int set_two_phase_freq(int cpufreq);
#endif
+#ifdef CONFIG_ION_MSM
+static struct platform_device ion_dev;
+#endif
+
#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
static void (*sdc2_status_notify_cb)(int card_present, void *dev_id);
static void *sdc2_status_notify_cb_devid;
@@ -1654,19 +1660,7 @@ static int vigor_usb_product_id_match(int product_id, int intrsharing)
#endif
static struct android_usb_platform_data android_usb_pdata = {
- .vendor_id = 0x0BB4,
- .product_id = 0x0ccd,
- .version = 0x0100,
- .product_name = "Android Phone",
- .manufacturer_name = "HTC",
- .num_products = ARRAY_SIZE(usb_products),
- .products = usb_products,
- .num_functions = ARRAY_SIZE(usb_functions_all),
- .functions = usb_functions_all,
- .enable_fast_charge = NULL,
.update_pid_and_serial_num = usb_diag_update_pid_and_serial_num,
- .usb_id_pin_gpio = VIGOR_GPIO_USB_ID,
- .fserial_init_string = "smd:modem,sdio:modem_mdm,tty,tty,tty:serial",
#ifdef CONFIG_USB_GADGET_VERIZON_PRODUCT_ID
.match = vigor_usb_product_id_match,
#endif
@@ -1683,7 +1677,6 @@ static struct platform_device android_usb_device = {
static int __init board_serialno_setup(char *serialno)
{
- android_usb_pdata.serial_number = serialno;
return 1;
}
__setup("androidboot.serialno=", board_serialno_setup);
@@ -1691,24 +1684,9 @@ __setup("androidboot.serialno=", board_serialno_setup);
static void vigor_add_usb_devices(void)
{
printk(KERN_INFO "%s rev: %d\n", __func__, system_rev);
- android_usb_pdata.products[0].product_id =
- android_usb_pdata.product_id;
config_vigor_mhl_gpios();
- /* diag bit set */
- if (get_radio_flag() & 0x20000) {
- android_usb_pdata.diag_init = 1;
- android_usb_pdata.modem_init = 1;
- android_usb_pdata.rmnet_init = 1;
- }
-
- /* add cdrom support in normal mode */
- if (board_mfg_mode() == 0) {
- android_usb_pdata.nluns = 3;
- android_usb_pdata.cdrom_lun = 0x4;
- }
-
msm_device_gadget_peripheral.dev.parent = &msm_device_otg.dev;
platform_device_register(&msm_device_gadget_peripheral);
platform_device_register(&android_usb_device);
@@ -3162,6 +3140,7 @@ early_param("pmem_audio_size", pmem_audio_size_setup);
#endif
#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_ION_MSM
static struct android_pmem_platform_data android_pmem_sf_pdata = {
.name = "pmem",
.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
@@ -3174,7 +3153,7 @@ static struct platform_device android_pmem_sf_device = {
.id = 1,
.dev = { .platform_data = &android_pmem_sf_pdata },
};
-
+#endif
static struct android_pmem_platform_data android_pmem_adsp_pdata = {
.name = "pmem_adsp",
.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
@@ -3214,6 +3193,39 @@ static struct platform_device android_pmem_audio_device = {
.dev = { .platform_data = &android_pmem_audio_pdata },
};
+#ifdef CONFIG_ION_MSM
+static struct ion_co_heap_pdata co_ion_pdata = {
+ .adjacent_mem_id = INVALID_HEAP_ID,
+ .align = PAGE_SIZE,
+};
+
+static struct ion_platform_data ion_pdata = {
+ .nr = 2,
+ .heaps = {
+ {
+ .id = ION_SYSTEM_HEAP_ID,
+ .type = ION_HEAP_TYPE_SYSTEM,
+ .name = ION_VMALLOC_HEAP_NAME,
+ },
+ {
+ .id = ION_SF_HEAP_ID,
+ .type = ION_HEAP_TYPE_CARVEOUT,
+ .name = ION_SF_HEAP_NAME,
+ .base = MSM_PMEM_SF_BASE,
+ .size = MSM_PMEM_SF_SIZE,
+ .memory_type = ION_EBI_TYPE,
+ .extra_data = (void *)&co_ion_pdata,
+ },
+ }
+};
+
+static struct platform_device ion_dev = {
+ .name = "ion-msm",
+ .id = 1,
+ .dev = { .platform_data = &ion_pdata },
+};
+#endif
+
#define PMEM_BUS_WIDTH(_bw) \
{ \
.vectors = &(struct msm_bus_vectors){ \
@@ -7545,7 +7557,9 @@ static struct platform_device *vigor_devices[] __initdata = {
&msm_batt_device,
#endif
#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_ION_MSM
&android_pmem_sf_device,
+#endif
&android_pmem_adsp_device,
&android_pmem_adsp2_device,
&android_pmem_audio_device,
@@ -7633,6 +7647,9 @@ static struct platform_device *vigor_devices[] __initdata = {
&msm_device_sdio_al,
#endif
&msm8660_device_watchdog,
+#ifdef CONFIG_ION_MSM
+ &ion_dev,
+#endif
};
static struct memtype_reserve msm8x60_reserve_table[] __initdata = {
@@ -7680,8 +7697,10 @@ static void __init size_pmem_devices(void)
size_pmem_device(&android_pmem_adsp2_pdata, MSM_PMEM_ADSP2_BASE, MSM_PMEM_ADSP2_SIZE);
size_pmem_device(&android_pmem_smipool_pdata, MSM_PMEM_SMIPOOL_BASE, MSM_PMEM_SMIPOOL_SIZE);
size_pmem_device(&android_pmem_audio_pdata, MSM_PMEM_AUDIO_BASE, pmem_audio_size);
+#ifndef CONFIG_ION_MSM
size_pmem_device(&android_pmem_sf_pdata, MSM_PMEM_SF_BASE, pmem_sf_size);
#endif
+#endif
}
#ifdef CONFIG_ANDROID_PMEM
@@ -7703,8 +7722,10 @@ static void __init reserve_pmem_memory(void)
reserve_memory_for(&android_pmem_adsp_pdata);
reserve_memory_for(&android_pmem_smipool_pdata);
reserve_memory_for(&android_pmem_audio_pdata);
+#ifndef CONFIG_ION_MSM
reserve_memory_for(&android_pmem_sf_pdata);
#endif
+#endif
}
static void __init msm8x60_calculate_reserve_sizes(void)
diff --git a/arch/arm/mach-msm/clock-8x60.c b/arch/arm/mach-msm/clock-8x60.c
index 1cda5103e6f..86d95b74cc0 100644
--- a/arch/arm/mach-msm/clock-8x60.c
+++ b/arch/arm/mach-msm/clock-8x60.c
@@ -3777,6 +3777,12 @@ static struct clk_lookup msm_clocks_8x60[] = {
CLK_LOOKUP("iommu_clk", gfx2d0_clk.c, "msm_iommu.10"),
CLK_LOOKUP("iommu_clk", gfx2d1_clk.c, "msm_iommu.11"),
+ CLK_LOOKUP("mdp_iommu_clk", mdp_axi_clk.c, "msm_vidc.0"),
+ CLK_LOOKUP("rot_iommu_clk", rot_axi_clk.c, "msm_vidc.0"),
+ CLK_LOOKUP("vcodec_iommu0_clk", vcodec_axi_clk.c, "msm_vidc.0"),
+ CLK_LOOKUP("vcodec_iommu1_clk", vcodec_axi_clk.c, "msm_vidc.0"),
+ CLK_LOOKUP("smmu_iface_clk", smmu_p_clk.c, "msm_vidc.0"),
+
CLK_LOOKUP("dfab_dsps_clk", dfab_dsps_clk.c, NULL),
CLK_LOOKUP("core_clk", dfab_usb_hs_clk.c, "msm_otg"),
CLK_LOOKUP("bus_clk", dfab_sdc1_clk.c, "msm_sdcc.1"),
diff --git a/arch/arm/mach-msm/clock-8x60.h b/arch/arm/mach-msm/clock-8x60.h
new file mode 100644
index 00000000000..e9effae0ac8
--- /dev/null
+++ b/arch/arm/mach-msm/clock-8x60.h
@@ -0,0 +1,253 @@
+/* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_CLOCK_8X60_H
+#define __ARCH_ARM_MACH_MSM_CLOCK_8X60_H
+
+#include "clock-local.h"
+
+enum {
+ /* Peripheral Clocks */
+ L_GSBI1_UART_CLK, //0
+ L_GSBI2_UART_CLK,
+ L_GSBI3_UART_CLK,
+ L_GSBI4_UART_CLK,
+ L_GSBI5_UART_CLK,
+ L_GSBI6_UART_CLK,
+ L_GSBI7_UART_CLK,
+ L_GSBI8_UART_CLK,
+ L_GSBI9_UART_CLK,
+ L_GSBI10_UART_CLK,
+ L_GSBI11_UART_CLK, //10
+ L_GSBI12_UART_CLK,
+ L_GSBI1_QUP_CLK,
+ L_GSBI2_QUP_CLK,
+ L_GSBI3_QUP_CLK,
+ L_GSBI4_QUP_CLK,
+ L_GSBI5_QUP_CLK,
+ L_GSBI6_QUP_CLK,
+ L_GSBI7_QUP_CLK,
+ L_GSBI8_QUP_CLK,
+ L_GSBI9_QUP_CLK, //20
+ L_GSBI10_QUP_CLK,
+ L_GSBI11_QUP_CLK,
+ L_GSBI12_QUP_CLK,
+ L_PDM_CLK,
+ L_PMEM_CLK,
+ L_PRNG_CLK,
+ L_SDC1_CLK,
+ L_SDC2_CLK,
+ L_SDC3_CLK,
+ L_SDC4_CLK, //30
+ L_SDC5_CLK,
+ L_TSIF_REF_CLK,
+ L_TSSC_CLK,
+ L_USB_HS1_XCVR_CLK,
+ L_USB_PHY0_CLK,
+ L_USB_FS1_SRC_CLK,
+ L_USB_FS1_XCVR_CLK,
+ L_USB_FS1_SYS_CLK,
+ L_USB_FS2_SRC_CLK,
+ L_USB_FS2_XCVR_CLK, //40
+ L_USB_FS2_SYS_CLK,
+
+ /* HW-Voteable Clocks */
+ L_ADM0_CLK,
+ L_ADM0_P_CLK,
+ L_ADM1_CLK,
+ L_ADM1_P_CLK,
+ L_MODEM_AHB1_P_CLK,
+ L_MODEM_AHB2_P_CLK,
+ L_PMIC_ARB0_P_CLK,
+ L_PMIC_ARB1_P_CLK,
+ L_PMIC_SSBI2_CLK, //50
+ L_RPM_MSG_RAM_P_CLK,
+
+ /* Fast Peripheral Bus Clocks */
+ L_CE2_P_CLK,
+ L_GSBI1_P_CLK,
+ L_GSBI2_P_CLK,
+ L_GSBI3_P_CLK,
+ L_GSBI4_P_CLK,
+ L_GSBI5_P_CLK,
+ L_GSBI6_P_CLK,
+ L_GSBI7_P_CLK,
+ L_GSBI8_P_CLK, //60
+ L_GSBI9_P_CLK,
+ L_GSBI10_P_CLK,
+ L_GSBI11_P_CLK,
+ L_GSBI12_P_CLK,
+ L_PPSS_P_CLK,
+ L_TSIF_P_CLK,
+ L_USB_FS1_P_CLK,
+ L_USB_FS2_P_CLK,
+ L_USB_HS1_P_CLK,
+ L_SDC1_P_CLK, //70
+ L_SDC2_P_CLK,
+ L_SDC3_P_CLK,
+ L_SDC4_P_CLK,
+ L_SDC5_P_CLK,
+
+ /* Multimedia Clocks */
+ L_AMP_CLK,
+ L_CAM_CLK,
+ L_CSI_SRC_CLK,
+ L_CSI0_CLK,
+ L_CSI1_CLK,
+ L_DSI_BYTE_CLK, //80
+ L_DSI_ESC_CLK,
+ L_GFX2D0_CLK,
+ L_GFX2D1_CLK,
+ L_GFX3D_CLK,
+ L_IJPEG_CLK,
+ L_JPEGD_CLK,
+ L_MDP_CLK,
+ L_MDP_VSYNC_CLK,
+ L_PIXEL_SRC_CLK,
+ L_PIXEL_MDP_CLK, //90
+ L_PIXEL_LCDC_CLK,
+ L_ROT_CLK,
+ L_TV_SRC_CLK,
+ L_TV_ENC_CLK,
+ L_TV_DAC_CLK,
+ L_VCODEC_CLK,
+ L_MDP_TV_CLK,
+ L_HDMI_TV_CLK,
+ L_HDMI_APP_CLK,
+ L_VPE_CLK, //100
+ L_VFE_CLK,
+ L_CSI0_VFE_CLK,
+ L_CSI1_VFE_CLK,
+ L_GMEM_AXI_CLK,
+ L_IJPEG_AXI_CLK,
+ L_IMEM_AXI_CLK,
+ L_JPEGD_AXI_CLK,
+ L_VCODEC_AXI_CLK,
+ L_VFE_AXI_CLK,
+ L_MDP_AXI_CLK, //110
+ L_ROT_AXI_CLK,
+ L_VPE_AXI_CLK,
+
+ /* Multimedia Fast Peripheral Bus Clocks */
+ L_AMP_P_CLK,
+ L_CSI0_P_CLK,
+ L_CSI1_P_CLK,
+ L_DSI_M_P_CLK,
+ L_DSI_S_P_CLK,
+ L_GFX2D0_P_CLK,
+ L_GFX2D1_P_CLK,
+ L_GFX3D_P_CLK, //120
+ L_HDMI_M_P_CLK,
+ L_HDMI_S_P_CLK,
+ L_IJPEG_P_CLK,
+ L_IMEM_P_CLK,
+ L_JPEGD_P_CLK,
+ L_MDP_P_CLK,
+ L_ROT_P_CLK,
+ L_SMMU_P_CLK,
+ L_TV_ENC_P_CLK,
+ L_VCODEC_P_CLK, //130
+ L_VFE_P_CLK,
+ L_VPE_P_CLK,
+
+ /* LPA Clocks */
+ L_MI2S_SRC_CLK,
+ L_MI2S_OSR_CLK,
+ L_MI2S_BIT_CLK,
+ L_CODEC_I2S_MIC_OSR_CLK,
+ L_CODEC_I2S_MIC_BIT_CLK,
+ L_SPARE_I2S_MIC_OSR_CLK,
+ L_SPARE_I2S_MIC_BIT_CLK,
+ L_CODEC_I2S_SPKR_OSR_CLK, //140
+ L_CODEC_I2S_SPKR_BIT_CLK,
+ L_SPARE_I2S_SPKR_OSR_CLK,
+ L_SPARE_I2S_SPKR_BIT_CLK,
+ L_PCM_CLK,
+
+ /* Measurement-only Clocks */
+ L_SC0_DIV2_M_CLK,
+ L_SC1_DIV2_M_CLK,
+ L_L2_DIV2_M_CLK,
+ L_AFAB_M_CLK,
+ L_SFAB_M_CLK,
+ L_EBI1_2X_M_CLK,
+ L_CFPB0_M_CLK,
+ L_CFPB1_M_CLK,
+ L_CFPB2_M_CLK,
+ L_DFAB_M_CLK,
+ L_SFPB_M_CLK,
+ L_MMFAB_M_CLK,
+ L_SMI_DDR2X_M_CLK,
+ L_MMFPB_M_CLK,
+
+ L_NR_CLKS //145
+};
+
+enum clk_sources {
+ PLL_0 = 0,
+ PLL_1,
+ PLL_2,
+ PLL_3,
+ PLL_4,
+ PLL_6,
+ PLL_7,
+ PLL_8,
+ PXO,
+ CXO,
+ NUM_SRC
+};
+
+/*extern struct clk_local soc_clk_local_tbl_mxo[];*/
+
+struct pll_rate {
+ const uint32_t l_val;
+ const uint32_t m_val;
+ const uint32_t n_val;
+ const uint32_t vco;
+ const uint32_t post_div;
+ const uint32_t i_bits;
+};
+#define PLL_RATE(l, m, n, v, d, i) { l, m, n, v, (d>>1), i }
+
+extern struct clk_ops soc_clk_ops_8x60;
+#define CLK_8X60(clk_name, clk_id, clk_dev, clk_flags) { \
+ .con_id = clk_name, \
+ .dev_id = clk_dev, \
+ .clk = &(struct clk){ \
+ .id = L_##clk_id, \
+ .ops = &soc_clk_ops_8x60, \
+ .flags = clk_flags, \
+ .dbg_name = #clk_id, \
+ .name = clk_name, \
+ }, \
+ }
+
+void soc_clk_src_votes_show(void);
+
+#endif
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index 46f7d668aef..e8eb4826876 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -2396,10 +2396,12 @@ struct msm_vidc_platform_data vidc_platform_data = {
#ifdef CONFIG_MSM_BUS_SCALING
.vidc_bus_client_pdata = &vidc_bus_client_data,
#endif
- .memtype = MEMTYPE_SMI_KERNEL,
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ .memtype = ION_CP_MM_HEAP_ID,
.enable_ion = 1,
+ .cp_enabled = 0,
#else
+ .memtype = MEMTYPE_SMI_KERNEL,
.enable_ion = 0,
#endif
.disable_dmx = 0,
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index b241ee6857d..5b8afbb80ee 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -517,6 +517,7 @@ struct msm_vidc_platform_data {
u32 enable_ion;
int disable_dmx;
int disable_fullhd;
+ u32 cp_enabled;
#ifdef CONFIG_MSM_BUS_SCALING
struct msm_bus_scale_pdata *vidc_bus_client_pdata;
#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v3/apr.h b/arch/arm/mach-msm/include/mach/qdsp6v3/apr.h
new file mode 100644
index 00000000000..19f1860aa48
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp6v3/apr.h
@@ -0,0 +1,189 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef __APR_H_
+#define __APR_H_
+
+#define APR_Q6_NOIMG 0
+#define APR_Q6_LOADING 1
+#define APR_Q6_LOADED 2
+
+struct apr_q6 {
+ void *pil;
+ uint32_t state;
+ struct mutex lock;
+};
+
+struct apr_hdr {
+ uint16_t hdr_field;
+ uint16_t pkt_size;
+ uint8_t src_svc;
+ uint8_t src_domain;
+ uint16_t src_port;
+ uint8_t dest_svc;
+ uint8_t dest_domain;
+ uint16_t dest_port;
+ uint32_t token;
+ uint32_t opcode;
+};
+
+#define APR_HDR_LEN(hdr_len) ((hdr_len)/4)
+#define APR_PKT_SIZE(hdr_len, payload_len) ((hdr_len) + (payload_len))
+#define APR_HDR_FIELD(msg_type, hdr_len, ver)\
+ (((msg_type & 0x3) << 8) | ((hdr_len & 0xF) << 4) | (ver & 0xF))
+
+#define APR_HDR_SIZE sizeof(struct apr_hdr)
+
+/* Version */
+#define APR_PKT_VER 0x0
+
+/* Command and Response Types */
+#define APR_MSG_TYPE_EVENT 0x0
+#define APR_MSG_TYPE_CMD_RSP 0x1
+#define APR_MSG_TYPE_SEQ_CMD 0x2
+#define APR_MSG_TYPE_NSEQ_CMD 0x3
+#define APR_MSG_TYPE_MAX 0x04
+
+/* APR Basic Response Message */
+#define APR_BASIC_RSP_RESULT 0x000110E8
+#define APR_RSP_ACCEPTED 0x000100BE
+
+/* Domain IDs */
+#define APR_DOMAIN_SIM 0x1
+#define APR_DOMAIN_PC 0x2
+#define APR_DOMAIN_MODEM 0x3
+#define APR_DOMAIN_ADSP 0x4
+#define APR_DOMAIN_APPS 0x5
+#define APR_DOMAIN_MAX 0x6
+
+/* ADSP service IDs */
+#define APR_SVC_TEST_CLIENT 0x2
+#define APR_SVC_ADSP_CORE 0x3
+#define APR_SVC_AFE 0x4
+#define APR_SVC_VSM 0x5
+#define APR_SVC_VPM 0x6
+#define APR_SVC_ASM 0x7
+#define APR_SVC_ADM 0x8
+#define APR_SVC_ADSP_MVM 0x09
+#define APR_SVC_ADSP_CVS 0x0A
+#define APR_SVC_ADSP_CVP 0x0B
+#define APR_SVC_MAX 0x0C
+
+/* Modem Service IDs */
+#define APR_SVC_MVS 0x3
+#define APR_SVC_MVM 0x4
+#define APR_SVC_CVS 0x5
+#define APR_SVC_CVP 0x6
+#define APR_SVC_SRD 0x7
+
+/* APR Port IDs */
+#define APR_MAX_PORTS 0x40
+
+#define APR_NAME_MAX 0x40
+
+#define RESET_EVENTS 0xFFFFFFFF
+
+#define LPASS_RESTART_EVENT 0x1000
+#define LPASS_RESTART_READY 0x1001
+
+struct apr_client_data {
+ uint16_t reset_event;
+ uint16_t reset_proc;
+ uint16_t payload_size;
+ uint16_t hdr_len;
+ uint16_t msg_type;
+ uint16_t src;
+ uint16_t dest_svc;
+ uint16_t src_port;
+ uint16_t dest_port;
+ uint32_t token;
+ uint32_t opcode;
+ void *payload;
+};
+
+typedef int32_t (*apr_fn)(struct apr_client_data *data, void *priv);
+
+struct apr_svc {
+ uint16_t id;
+ uint16_t dest_id;
+ uint16_t client_id;
+ uint8_t rvd;
+ uint8_t port_cnt;
+ uint8_t svc_cnt;
+ uint8_t need_reset;
+ apr_fn port_fn[APR_MAX_PORTS];
+ void *port_priv[APR_MAX_PORTS];
+ apr_fn fn;
+ void *priv;
+ struct mutex m_lock;
+ spinlock_t w_lock;
+};
+
+struct apr_client {
+ uint8_t id;
+ uint8_t svc_cnt;
+ uint8_t rvd;
+ struct mutex m_lock;
+ struct apr_svc_ch_dev *handle;
+ struct apr_svc svc[APR_SVC_MAX];
+};
+
+#define ADSP_GET_VERSION 0x00011152
+#define ADSP_GET_VERSION_RSP 0x00011153
+
+struct adsp_get_version {
+ uint32_t build_id;
+ uint32_t svc_cnt;
+};
+
+struct adsp_service_info {
+ uint32_t svc_id;
+ uint32_t svc_ver;
+};
+
+#define ADSP_CMD_SET_POWER_COLLAPSE_STATE 0x0001115C
+struct adsp_power_collapse {
+ struct apr_hdr hdr;
+ uint32_t power_collapse;
+};
+
+struct apr_svc *apr_register(char *dest, char *svc_name, apr_fn svc_fn,
+ uint32_t src_port, void *priv);
+inline int apr_fill_hdr(void *handle, uint32_t *buf, uint16_t src_port,
+ uint16_t msg_type, uint16_t dest_port,
+ uint32_t token, uint32_t opcode, uint16_t len);
+
+int apr_send_pkt(void *handle, uint32_t *buf);
+int apr_deregister(void *handle);
+void change_q6_state(int state);
+void q6audio_dsp_not_responding(void);
+uint32_t core_get_adsp_version(void);
+void *core_open(void);
+int32_t core_close(void);
+void apr_reset(void *handle);
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v3/apr_audio.h b/arch/arm/mach-msm/include/mach/qdsp6v3/apr_audio.h
new file mode 100644
index 00000000000..a6657cffbd5
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp6v3/apr_audio.h
@@ -0,0 +1,1012 @@
+/*
+ *
+ * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#ifndef _APR_AUDIO_H_
+#define _APR_AUDIO_H_
+
+/* ASM opcodes without APR payloads*/
+#include
+
+/*
+ * Audio Front End (AFE)
+ */
+
+/* Port ID. Update afe_get_port_index when a new port is added here. */
+#define PRIMARY_I2S_RX 0 /* index = 0 */
+#define PRIMARY_I2S_TX 1 /* index = 1 */
+#define PCM_RX 2 /* index = 2 */
+#define PCM_TX 3 /* index = 3 */
+#define SECONDARY_I2S_RX 4 /* index = 4 */
+#define SECONDARY_I2S_TX 5 /* index = 5 */
+#define MI2S_RX 6 /* index = 6 */
+#define MI2S_TX 7 /* index = 7 */
+#define HDMI_RX 8 /* index = 8 */
+#define RSVD_2 9 /* index = 9 */
+#define RSVD_3 10 /* index = 10 */
+#define DIGI_MIC_TX 11 /* index = 11 */
+#define VOICE_RECORD_RX 0x8003 /* index = 12 */
+#define VOICE_RECORD_TX 0x8004 /* index = 13 */
+#define VOICE_PLAYBACK_TX 0x8005 /* index = 14 */
+#define AFE_PORT_INVALID 0xFFFF
+
+#define AFE_PORT_CMD_START 0x000100ca
+struct afe_port_start_command {
+ struct apr_hdr hdr;
+ u16 port_id;
+ u16 gain; /* Q13 */
+ u32 sample_rate; /* 8 , 16, 48khz */
+} __attribute__ ((packed));
+
+#define AFE_PORT_CMD_STOP 0x000100cb
+struct afe_port_stop_command {
+ struct apr_hdr hdr;
+ u16 port_id;
+ u16 reserved;
+} __attribute__ ((packed));
+
+#define AFE_PORT_CMD_APPLY_GAIN 0x000100cc
+struct afe_port_gain_command {
+ struct apr_hdr hdr;
+ u16 port_id;
+ u16 gain;/* Q13 */
+} __attribute__ ((packed));
+
+#define AFE_PORT_CMD_SIDETONE_CTL 0x000100cd
+struct afe_port_sidetone_command {
+ struct apr_hdr hdr;
+ u16 rx_port_id; /* Primary i2s tx = 1 */
+ /* PCM tx = 3 */
+ /* Secondary i2s tx = 5 */
+ /* Mi2s tx = 7 */
+ /* Digital mic tx = 11 */
+ u16 tx_port_id; /* Primary i2s rx = 0 */
+ /* PCM rx = 2 */
+ /* Secondary i2s rx = 4 */
+ /* Mi2S rx = 6 */
+ /* HDMI rx = 8 */
+ u16 gain; /* Q13 */
+ u16 enable; /* 1 = enable, 0 = disable */
+} __attribute__ ((packed));
+
+#define AFE_PORT_CMD_LOOPBACK 0x000100ce
+struct afe_loopback_command {
+ struct apr_hdr hdr;
+ u16 tx_port_id; /* Primary i2s rx = 0 */
+ /* PCM rx = 2 */
+ /* Secondary i2s rx = 4 */
+ /* Mi2S rx = 6 */
+ /* HDMI rx = 8 */
+ u16 rx_port_id; /* Primary i2s tx = 1 */
+ /* PCM tx = 3 */
+ /* Secondary i2s tx = 5 */
+ /* Mi2s tx = 7 */
+ /* Digital mic tx = 11 */
+ u16 mode; /* Default -1, DSP will conver
+ the tx to rx format */
+ u16 enable; /* 1 = enable, 0 = disable */
+} __attribute__ ((packed));
+
+#define AFE_PSEUDOPORT_CMD_START 0x000100cf
+struct afe_pseudoport_start_command {
+ struct apr_hdr hdr;
+ u16 port_id; /* Pseudo Port 1 = 0x8000 */
+ /* Pseudo Port 2 = 0x8001 */
+ /* Pseudo Port 3 = 0x8002 */
+ u16 timing; /* FTRT = 0 , AVTimer = 1, */
+} __attribute__ ((packed));
+
+#define AFE_PSEUDOPORT_CMD_STOP 0x000100d0
+struct afe_pseudoport_stop_command {
+ struct apr_hdr hdr;
+ u16 port_id; /* Pseudo Port 1 = 0x8000 */
+ /* Pseudo Port 2 = 0x8001 */
+ /* Pseudo Port 3 = 0x8002 */
+ u16 reserved;
+} __attribute__ ((packed));
+
+#define AFE_CMD_GET_ACTIVE_PORTS 0x000100d1
+
+
+#define AFE_CMD_GET_ACTIVE_HANDLES_FOR_PORT 0x000100d2
+struct afe_get_active_handles_command {
+ struct apr_hdr hdr;
+ u16 port_id;
+ u16 reserved;
+} __attribute__ ((packed));
+
+#define AFE_PCM_CFG_MODE_PCM 0x0
+#define AFE_PCM_CFG_MODE_AUX 0x1
+#define AFE_PCM_CFG_SYNC_EXT 0x0
+#define AFE_PCM_CFG_SYNC_INT 0x1
+#define AFE_PCM_CFG_FRM_8BPF 0x0
+#define AFE_PCM_CFG_FRM_16BPF 0x1
+#define AFE_PCM_CFG_FRM_32BPF 0x2
+#define AFE_PCM_CFG_FRM_64BPF 0x3
+#define AFE_PCM_CFG_FRM_128BPF 0x4
+#define AFE_PCM_CFG_FRM_256BPF 0x5
+#define AFE_PCM_CFG_QUANT_ALAW_NOPAD 0x0
+#define AFE_PCM_CFG_QUANT_MULAW_NOPAD 0x1
+#define AFE_PCM_CFG_QUANT_LINEAR_NOPAD 0x2
+#define AFE_PCM_CFG_QUANT_ALAW_PAD 0x3
+#define AFE_PCM_CFG_QUANT_MULAW_PAD 0x4
+#define AFE_PCM_CFG_QUANT_LINEAR_PAD 0x5
+#define AFE_PCM_CFG_CDATAOE_MASTER 0x0
+#define AFE_PCM_CFG_CDATAOE_SHARE 0x1
+
+struct afe_port_pcm_cfg {
+ u16 mode; /* PCM (short sync) = 0, AUXPCM (long sync) = 1 */
+ u16 sync; /* external = 0 , internal = 1 */
+ u16 frame; /* 8 bpf = 0 */
+ /* 16 bpf = 1 */
+ /* 32 bpf = 2 */
+ /* 64 bpf = 3 */
+ /* 128 bpf = 4 */
+ /* 256 bpf = 5 */
+ u16 quant;
+ u16 slot; /* Slot for PCM stream , 0 - 31 */
+ u16 data; /* 0, PCM block is the only master */
+ /* 1, PCM block is shares to driver data out signal */
+ /* other master */
+ u16 reserved;
+} __attribute__ ((packed));
+
+enum {
+ AFE_I2S_SD0 = 1,
+ AFE_I2S_SD1,
+ AFE_I2S_SD2,
+ AFE_I2S_SD3,
+ AFE_I2S_QUAD01,
+ AFE_I2S_QUAD23,
+ AFE_I2S_6CHS,
+ AFE_I2S_8CHS,
+};
+
+#define AFE_MI2S_MONO 0
+#define AFE_MI2S_STEREO 3
+#define AFE_MI2S_4CHANNELS 4
+#define AFE_MI2S_6CHANNELS 6
+#define AFE_MI2S_8CHANNELS 8
+
+struct afe_port_mi2s_cfg {
+ u16 bitwidth; /* 16,24,32 */
+ u16 line; /* Called ChannelMode in documentation */
+ /* i2s_sd0 = 1 */
+ /* i2s_sd1 = 2 */
+ /* i2s_sd2 = 3 */
+ /* i2s_sd3 = 4 */
+ /* i2s_quad01 = 5 */
+ /* i2s_quad23 = 6 */
+ /* i2s_6chs = 7 */
+ /* i2s_8chs = 8 */
+ u16 channel; /* Called MonoStereo in documentation */
+ /* i2s mono = 0 */
+ /* i2s mono right = 1 */
+ /* i2s mono left = 2 */
+ /* i2s stereo = 3 */
+ u16 ws; /* 0, word select signal from external source */
+ /* 1, word select signal from internal source */
+ u16 reserved;
+} __attribute__ ((packed));
+
+struct afe_port_hdmi_cfg {
+ u16 bitwidth; /* 16,24,32 */
+ u16 channel_mode; /* HDMI Stereo = 0 */
+ /* HDMI_3Point1 (4-ch) = 1 */
+ /* HDMI_5Point1 (6-ch) = 2 */
+ /* HDMI_6Point1 (8-ch) = 3 */
+ u16 data_type; /* HDMI_Linear = 0 */
+ /* HDMI_non_Linaer = 1 */
+} __attribute__ ((packed));
+
+#define AFE_PORT_AUDIO_IF_CONFIG 0x000100d3
+
+union afe_port_config {
+ struct afe_port_pcm_cfg pcm;
+ struct afe_port_mi2s_cfg mi2s;
+ struct afe_port_hdmi_cfg hdmi;
+} __attribute__((packed));
+
+struct afe_audioif_config_command {
+ struct apr_hdr hdr;
+ u16 port_id;
+ union afe_port_config port;
+} __attribute__ ((packed));
+
+#define AFE_TEST_CODEC_LOOPBACK_CTL 0x000100d5
+struct afe_codec_loopback_command {
+ u16 port_inf; /* Primary i2s = 0 */
+ /* PCM = 2 */
+ /* Secondary i2s = 4 */
+ /* Mi2s = 6 */
+ u16 enable; /* 0, disable. 1, enable */
+} __attribute__ ((packed));
+
+
+#define AFE_PARAM_ID_SIDETONE_GAIN 0x00010300
+struct afe_param_sidetone_gain {
+ u16 gain;
+ u16 reserved;
+} __attribute__ ((packed));
+
+#define AFE_PARAM_ID_SAMPLING_RATE 0x00010301
+struct afe_param_sampling_rate {
+ u32 sampling_rate;
+} __attribute__ ((packed));
+
+
+#define AFE_PARAM_ID_CHANNELS 0x00010302
+struct afe_param_channels {
+ u16 channels;
+ u16 reserved;
+} __attribute__ ((packed));
+
+
+#define AFE_PARAM_ID_LOOPBACK_GAIN 0x00010303
+struct afe_param_loopback_gain {
+ u16 gain;
+ u16 reserved;
+} __attribute__ ((packed));
+
+
+#define AFE_MODULE_ID_PORT_INFO 0x00010200
+struct afe_param_payload {
+ u32 module_id;
+ u32 param_id;
+ u16 param_size;
+ u16 reserved;
+ union {
+ struct afe_param_sidetone_gain sidetone_gain;
+ struct afe_param_sampling_rate sampling_rate;
+ struct afe_param_channels channels;
+ struct afe_param_loopback_gain loopback_gain;
+ } __attribute__((packed)) param;
+} __attribute__ ((packed));
+
+#define AFE_PORT_CMD_SET_PARAM 0x000100dc
+
+struct afe_port_cmd_set_param {
+ struct apr_hdr hdr;
+ u16 port_id;
+ u16 payload_size;
+ u32 payload_address;
+ struct afe_param_payload payload;
+} __attribute__ ((packed));
+
+
+#define AFE_EVENT_GET_ACTIVE_PORTS 0x00010100
+struct afe_get_active_ports_rsp {
+ u16 num_ports;
+ u16 port_id;
+} __attribute__ ((packed));
+
+
+#define AFE_EVENT_GET_ACTIVE_HANDLES 0x00010102
+struct afe_get_active_handles_rsp {
+ u16 port_id;
+ u16 num_handles;
+ u16 mode; /* 0, voice rx */
+ /* 1, voice tx */
+ /* 2, audio rx */
+ /* 3, audio tx */
+ u16 handle;
+} __attribute__ ((packed));
+
+#define ADM_MAX_COPPS 5
+
+#define ADM_SERVICE_CMD_GET_COPP_HANDLES 0x00010300
+struct adm_get_copp_handles_command {
+ struct apr_hdr hdr;
+} __attribute__ ((packed));
+
+#define ADM_CMD_MATRIX_MAP_ROUTINGS 0x00010301
+struct adm_routings_session {
+ u16 id;
+ u16 num_copps;
+ u16 copp_id[ADM_MAX_COPPS+1]; /*Padding if numCopps is odd */
+} __packed;
+
+struct adm_routings_command {
+ struct apr_hdr hdr;
+ u32 path; /* 0 = Rx, 1 Tx */
+ u32 num_sessions;
+ struct adm_routings_session session[8];
+} __attribute__ ((packed));
+
+
+#define ADM_CMD_MATRIX_RAMP_GAINS 0x00010302
+struct adm_ramp_gain {
+ struct apr_hdr hdr;
+ u16 session_id;
+ u16 copp_id;
+ u16 initial_gain;
+ u16 gain_increment;
+ u16 ramp_duration;
+ u16 reserved;
+} __attribute__ ((packed));
+
+struct adm_ramp_gains_command {
+ struct apr_hdr hdr;
+ u32 id;
+ u32 num_gains;
+ struct adm_ramp_gain gains[ADM_MAX_COPPS];
+} __attribute__ ((packed));
+
+
+#define ADM_CMD_COPP_OPEN 0x00010304
+struct adm_copp_open_command {
+ struct apr_hdr hdr;
+ u16 flags;
+ u16 mode; /* 1-RX, 2-Live TX, 3-Non Live TX */
+ u16 endpoint_id1;
+ u16 endpoint_id2;
+ u32 topology_id;
+ u16 channel_config;
+ u16 reserved;
+ u32 rate;
+} __attribute__ ((packed));
+
+#define ADM_CMD_COPP_CLOSE 0x00010305
+
+#define ADM_CMD_MEMORY_MAP 0x00010C30
+struct adm_cmd_memory_map{
+ struct apr_hdr hdr;
+ u32 buf_add;
+ u32 buf_size;
+ u16 mempool_id;
+ u16 reserved;
+} __attribute__((packed));
+
+#define ADM_CMD_MEMORY_UNMAP 0x00010C31
+struct adm_cmd_memory_unmap{
+ struct apr_hdr hdr;
+ u32 buf_add;
+} __attribute__((packed));
+
+#define ADM_CMD_MEMORY_MAP_REGIONS 0x00010C47
+struct adm_memory_map_regions{
+ u32 phys;
+ u32 buf_size;
+} __attribute__((packed));
+
+struct adm_cmd_memory_map_regions{
+ struct apr_hdr hdr;
+ u16 mempool_id;
+ u16 nregions;
+} __attribute__((packed));
+
+#define ADM_CMD_MEMORY_UNMAP_REGIONS 0x00010C48
+struct adm_memory_unmap_regions{
+ u32 phys;
+} __attribute__((packed));
+
+struct adm_cmd_memory_unmap_regions{
+ struct apr_hdr hdr;
+ u16 nregions;
+ u16 reserved;
+} __attribute__((packed));
+
+#define DEFAULT_COPP_TOPOLOGY 0x00010be3
+#define DEFAULT_POPP_TOPOLOGY 0x00010be4
+#define VPM_TX_SM_ECNS_COPP_TOPOLOGY 0x00010F71
+#define VPM_TX_DM_FLUENCE_COPP_TOPOLOGY 0x00010F72
+#define HTC_STEREO_RECORD_TOPOLOGY 0x10000000
+#define HTC_COPP_TOPOLOGY 0x10000001
+
+#define ASM_MAX_EQ_BANDS 12
+
+struct asm_eq_band {
+ u32 band_idx; /* The band index, 0 .. 11 */
+ u32 filter_type; /* Filter band type */
+ u32 center_freq_hz; /* Filter band center frequency */
+ u32 filter_gain; /* Filter band initial gain (dB) */
+ /* Range is +12 dB to -12 dB with 1dB increments. */
+ u32 q_factor;
+} __attribute__ ((packed));
+
+struct asm_equalizer_params {
+ u32 enable;
+ u32 num_bands;
+ struct asm_eq_band eq_bands[ASM_MAX_EQ_BANDS];
+} __attribute__ ((packed));
+
+struct asm_master_gain_params {
+ u16 master_gain;
+ u16 padding;
+} __attribute__ ((packed));
+
+struct asm_lrchannel_gain_params {
+ u16 left_gain;
+ u16 right_gain;
+} __attribute__ ((packed));
+
+struct asm_mute_params {
+ u32 muteflag;
+} __attribute__ ((packed));
+
+struct asm_softvolume_params {
+ u32 period;
+ u32 step;
+ u32 rampingcurve;
+} __attribute__ ((packed));
+
+struct asm_softpause_params {
+ u32 enable;
+ u32 period;
+ u32 step;
+ u32 rampingcurve;
+} __packed;
+
+struct asm_pp_param_data_hdr {
+ u32 module_id;
+ u32 param_id;
+ u16 param_size;
+ u16 reserved;
+} __attribute__ ((packed));
+
+struct asm_pp_params_command {
+ struct apr_hdr hdr;
+ u32 *payload;
+ u32 payload_size;
+ struct asm_pp_param_data_hdr params;
+} __attribute__ ((packed));
+
+#define EQUALIZER_MODULE_ID 0x00010c27
+#define EQUALIZER_PARAM_ID 0x00010c28
+
+#define VOLUME_CONTROL_MODULE_ID 0x00010bfe
+#define MASTER_GAIN_PARAM_ID 0x00010bff
+#define L_R_CHANNEL_GAIN_PARAM_ID 0x00010c00
+#define MUTE_CONFIG_PARAM_ID 0x00010c01
+#define SOFT_PAUSE_PARAM_ID 0x00010D6A
+
+#define IIR_FILTER_ENABLE_PARAM_ID 0x00010c03
+#define IIR_FILTER_PREGAIN_PARAM_ID 0x00010c04
+#define IIR_FILTER_CONFIG_PARAM_ID 0x00010c05
+
+#define MBADRC_MODULE_ID 0x00010c06
+#define MBADRC_ENABLE_PARAM_ID 0x00010c07
+#define MBADRC_CONFIG_PARAM_ID 0x00010c08
+
+
+#define ADM_CMD_SET_PARAMS 0x00010306
+#define ADM_CMD_GET_PARAMS 0x0001030B
+#define ADM_CMDRSP_GET_PARAMS 0x0001030C
+struct adm_set_params_command {
+ struct apr_hdr hdr;
+ u32 payload;
+ u32 payload_size;
+} __attribute__ ((packed));
+
+
+#define ADM_CMD_TAP_COPP_PCM 0x00010307
+struct adm_tap_copp_pcm_command {
+ struct apr_hdr hdr;
+} __attribute__ ((packed));
+
+
+/* QDSP6 to Client messages
+*/
+#define ADM_SERVICE_CMDRSP_GET_COPP_HANDLES 0x00010308
+struct adm_get_copp_handles_respond {
+ struct apr_hdr hdr;
+ u32 handles;
+ u32 copp_id;
+} __attribute__ ((packed));
+
+#define ADM_CMDRSP_COPP_OPEN 0x0001030A
+struct adm_copp_open_respond {
+ u32 status;
+ u16 copp_id;
+ u16 reserved;
+} __attribute__ ((packed));
+
+#define ASM_STREAM_PRIORITY_NORMAL 0
+#define ASM_STREAM_PRIORITY_LOW 1
+#define ASM_STREAM_PRIORITY_HIGH 2
+#define ASM_STREAM_PRIORITY_RESERVED 3
+
+#define ASM_END_POINT_DEVICE_MATRIX 0
+#define ASM_END_POINT_STREAM 1
+
+#define AAC_ENC_MODE_AAC_LC 0x02
+#define AAC_ENC_MODE_AAC_P 0x05
+#define AAC_ENC_MODE_EAAC_P 0x1D
+
+#define ASM_STREAM_CMD_CLOSE 0x00010BCD
+#define ASM_STREAM_CMD_FLUSH 0x00010BCE
+#define ASM_STREAM_CMD_SET_PP_PARAMS 0x00010BCF
+#define ASM_STREAM_CMD_GET_PP_PARAMS 0x00010BD0
+#define ASM_STREAM_CMDRSP_GET_PP_PARAMS 0x00010BD1
+#define ASM_SESSION_CMD_PAUSE 0x00010BD3
+#define ASM_SESSION_CMD_GET_SESSION_TIME 0x00010BD4
+#define ASM_DATA_CMD_EOS 0x00010BDB
+#define ASM_DATA_EVENT_EOS 0x00010BDD
+
+#define ASM_SERVICE_CMD_GET_STREAM_HANDLES 0x00010C0B
+#define ASM_STREAM_CMD_FLUSH_READBUFS 0x00010C09
+
+#define ASM_SESSION_EVENT_RX_UNDERFLOW 0x00010C17
+#define ASM_SESSION_EVENT_TX_OVERFLOW 0x00010C18
+#define ASM_SERVICE_CMD_GET_WALLCLOCK_TIME 0x00010C19
+#define ASM_DATA_CMDRSP_EOS 0x00010C1C
+
+/* ASM Data structures */
+
+/* common declarations */
+struct asm_pcm_cfg {
+ u16 ch_cfg;
+ u16 bits_per_sample;
+ u32 sample_rate;
+ u16 is_signed;
+ u16 interleaved;
+};
+
+struct asm_adpcm_cfg {
+ u16 ch_cfg;
+ u16 bits_per_sample;
+ u32 sample_rate;
+ u32 block_size;
+};
+
+struct asm_yadpcm_cfg {
+ u16 ch_cfg;
+ u16 bits_per_sample;
+ u32 sample_rate;
+};
+
+struct asm_midi_cfg {
+ u32 nMode;
+};
+
+struct asm_wma_cfg {
+ u16 format_tag;
+ u16 ch_cfg;
+ u32 sample_rate;
+ u32 avg_bytes_per_sec;
+ u16 block_align;
+ u16 valid_bits_per_sample;
+ u32 ch_mask;
+ u16 encode_opt;
+ u16 adv_encode_opt;
+ u32 adv_encode_opt2;
+ u32 drc_peak_ref;
+ u32 drc_peak_target;
+ u32 drc_ave_ref;
+ u32 drc_ave_target;
+};
+
+struct asm_wmapro_cfg {
+ u16 format_tag;
+ u16 ch_cfg;
+ u32 sample_rate;
+ u32 avg_bytes_per_sec;
+ u16 block_align;
+ u16 valid_bits_per_sample;
+ u32 ch_mask;
+ u16 encode_opt;
+ u16 adv_encode_opt;
+ u32 adv_encode_opt2;
+ u32 drc_peak_ref;
+ u32 drc_peak_target;
+ u32 drc_ave_ref;
+ u32 drc_ave_target;
+};
+
+struct asm_aac_cfg {
+ u16 format;
+ u16 aot;
+ u16 ep_config;
+ u16 section_data_resilience;
+ u16 scalefactor_data_resilience;
+ u16 spectral_data_resilience;
+ u16 ch_cfg;
+ u16 reserved;
+ u32 sample_rate;
+};
+
+struct asm_flac_cfg {
+ u16 stream_info_present;
+ u16 min_blk_size;
+ u16 max_blk_size;
+ u16 ch_cfg;
+ u16 sample_size;
+ u16 sample_rate;
+ u16 md5_sum;
+ u32 ext_sample_rate;
+ u32 min_frame_size;
+ u32 max_frame_size;
+};
+
+struct asm_vorbis_cfg {
+ u32 ch_cfg;
+ u32 bit_rate;
+ u32 min_bit_rate;
+ u32 max_bit_rate;
+ u16 bit_depth_pcm_sample;
+ u16 bit_stream_format;
+};
+
+struct asm_aac_read_cfg {
+ u32 bitrate;
+ u32 enc_mode;
+ u16 format;
+ u16 ch_cfg;
+ u32 sample_rate;
+};
+
+struct asm_amrnb_read_cfg {
+ u16 mode;
+ u16 dtx_mode;
+};
+
+struct asm_evrc_read_cfg {
+ u16 max_rate;
+ u16 min_rate;
+ u16 rate_modulation_cmd;
+ u16 reserved;
+};
+
+struct asm_qcelp13_read_cfg {
+ u16 max_rate;
+ u16 min_rate;
+ u16 reduced_rate_level;
+ u16 rate_modulation_cmd;
+};
+
+struct asm_sbc_read_cfg {
+ u32 subband;
+ u32 block_len;
+ u32 ch_mode;
+ u32 alloc_method;
+ u32 bit_rate;
+ u32 sample_rate;
+};
+
+struct asm_sbc_bitrate {
+ u32 bitrate;
+};
+
+struct asm_immed_decode {
+ u32 mode;
+};
+
+struct asm_sbr_ps {
+ u32 enable;
+};
+
+struct asm_encode_cfg_blk {
+ u32 frames_per_buf;
+ u32 format_id;
+ u32 cfg_size;
+ union {
+ struct asm_pcm_cfg pcm;
+ struct asm_aac_read_cfg aac;
+ struct asm_amrnb_read_cfg amrnb;
+ struct asm_evrc_read_cfg evrc;
+ struct asm_qcelp13_read_cfg qcelp13;
+ struct asm_sbc_read_cfg sbc;
+ } __attribute__((packed)) cfg;
+};
+
+struct asm_frame_meta_info {
+ u32 offset_to_frame;
+ u32 frame_size;
+ u32 encoded_pcm_samples;
+ u32 msw_ts;
+ u32 lsw_ts;
+ u32 nflags;
+};
+
+/* Stream level commands */
+#define ASM_STREAM_CMD_OPEN_READ 0x00010BCB
+struct asm_stream_cmd_open_read {
+ struct apr_hdr hdr;
+ u32 uMode;
+ u32 src_endpoint;
+ u32 pre_proc_top;
+ u32 format;
+} __attribute__((packed));
+
+/* Supported formats */
+#define LINEAR_PCM 0x00010BE5
+#define DTMF 0x00010BE6
+#define ADPCM 0x00010BE7
+#define YADPCM 0x00010BE8
+#define MP3 0x00010BE9
+#define MPEG4_AAC 0x00010BEA
+#define AMRNB_FS 0x00010BEB
+#define V13K_FS 0x00010BED
+#define EVRC_FS 0x00010BEE
+#define EVRCB_FS 0x00010BEF
+#define EVRCWB_FS 0x00010BF0
+#define MIDI 0x00010BF1
+#define SBC 0x00010BF2
+#define WMA_V10PRO 0x00010BF3
+#define WMA_V9 0x00010BF4
+#define AMR_WB_PLUS 0x00010BF5
+#define AC3_DECODER 0x00010BF6
+#define G711_ALAW_FS 0x00010BF7
+#define G711_MLAW_FS 0x00010BF8
+#define G711_PCM_FS 0x00010BF9
+
+#define ASM_ENCDEC_SBCRATE 0x00010C13
+#define ASM_ENCDEC_IMMDIATE_DECODE 0x00010C14
+#define ASM_ENCDEC_CFG_BLK 0x00010C2C
+
+#define ASM_ENCDEC_SBCRATE 0x00010C13
+#define ASM_ENCDEC_IMMDIATE_DECODE 0x00010C14
+#define ASM_ENCDEC_CFG_BLK 0x00010C2C
+
+#define ASM_STREAM_CMD_OPEN_WRITE 0x00010BCA
+struct asm_stream_cmd_open_write {
+ struct apr_hdr hdr;
+ u32 uMode;
+ u16 sink_endpoint;
+ u16 stream_handle;
+ u32 post_proc_top;
+ u32 format;
+} __attribute__((packed));
+
+#define ASM_STREAM_CMD_OPEN_READWRITE 0x00010BCC
+
+struct asm_stream_cmd_open_read_write {
+ struct apr_hdr hdr;
+ u32 uMode;
+ u32 post_proc_top;
+ u32 write_format;
+ u32 read_format;
+} __attribute__((packed));
+
+#define ASM_STREAM_CMD_SET_ENCDEC_PARAM 0x00010C10
+#define ASM_STREAM_CMD_GET_ENCDEC_PARAM 0x00010C11
+#define ASM_ENCDEC_CFG_BLK_ID 0x00010C2C
+#define ASM_ENABLE_SBR_PS 0x00010C63
+struct asm_stream_cmd_encdec_cfg_blk{
+ struct apr_hdr hdr;
+ u32 param_id;
+ u32 param_size;
+ struct asm_encode_cfg_blk enc_blk;
+} __attribute__((packed));
+
+struct asm_stream_cmd_encdec_sbc_bitrate{
+ struct apr_hdr hdr;
+ u32 param_id;
+ struct asm_sbc_bitrate sbc_bitrate;
+} __attribute__((packed));
+
+struct asm_stream_cmd_encdec_immed_decode{
+ struct apr_hdr hdr;
+ u32 param_id;
+ u32 param_size;
+ struct asm_immed_decode dec;
+} __attribute__((packed));
+
+struct asm_stream_cmd_encdec_sbr{
+ struct apr_hdr hdr;
+ u32 param_id;
+ u32 param_size;
+ struct asm_sbr_ps sbr_ps;
+} __attribute__((packed));
+
+#define ASM_STREAM _CMD_ADJUST_SAMPLES 0x00010C0A
+struct asm_stream_cmd_adjust_samples{
+ struct apr_hdr hdr;
+ u16 nsamples;
+ u16 reserved;
+} __attribute__((packed));
+
+#define ASM_STREAM_CMD_TAP_POPP_PCM 0x00010BF9
+struct asm_stream_cmd_tap_popp_pcm{
+ struct apr_hdr hdr;
+ u16 enable;
+ u16 reserved;
+ u32 module_id;
+} __attribute__((packed));
+
+/* Session Level commands */
+#define ASM_SESSION_CMD_MEMORY_MAP 0x00010C32
+struct asm_stream_cmd_memory_map{
+ struct apr_hdr hdr;
+ u32 buf_add;
+ u32 buf_size;
+ u16 mempool_id;
+ u16 reserved;
+} __attribute__((packed));
+
+#define ASM_SESSION_CMD_MEMORY_UNMAP 0x00010C33
+struct asm_stream_cmd_memory_unmap{
+ struct apr_hdr hdr;
+ u32 buf_add;
+} __attribute__((packed));
+
+#define ASM_SESSION_CMD_MEMORY_MAP_REGIONS 0x00010C45
+struct asm_memory_map_regions{
+ u32 phys;
+ u32 buf_size;
+} __attribute__((packed));
+
+struct asm_stream_cmd_memory_map_regions{
+ struct apr_hdr hdr;
+ u16 mempool_id;
+ u16 nregions;
+} __attribute__((packed));
+
+#define ASM_SESSION_CMD_MEMORY_UNMAP_REGIONS 0x00010C46
+struct asm_memory_unmap_regions{
+ u32 phys;
+} __attribute__((packed));
+
+struct asm_stream_cmd_memory_unmap_regions{
+ struct apr_hdr hdr;
+ u16 nregions;
+ u16 reserved;
+} __attribute__((packed));
+
+#define ASM_SESSION_CMD_RUN 0x00010BD2
+struct asm_stream_cmd_run{
+ struct apr_hdr hdr;
+ u32 flags;
+ u32 msw_ts;
+ u32 lsw_ts;
+} __attribute__((packed));
+
+/* Session level events */
+#define ASM_SESSION_CMD_REGISTER_FOR_RX_UNDERFLOW_EVENTS 0x00010BD5
+struct asm_stream_cmd_reg_rx_underflow_event{
+ struct apr_hdr hdr;
+ u16 enable;
+ u16 reserved;
+} __attribute__((packed));
+
+#define ASM_SESSION_CMD_REGISTER_FOR_TX_OVERFLOW_EVENTS 0x00010BD6
+struct asm_stream_cmd_reg_tx_overflow_event{
+ struct apr_hdr hdr;
+ u16 enable;
+ u16 reserved;
+} __attribute__((packed));
+
+/* Data Path commands */
+#define ASM_DATA_CMD_WRITE 0x00010BD9
+struct asm_stream_cmd_write{
+ struct apr_hdr hdr;
+ u32 buf_add;
+ u32 avail_bytes;
+ u32 uid;
+ u32 msw_ts;
+ u32 lsw_ts;
+ u32 uflags;
+} __attribute__((packed));
+
+#define ASM_DATA_CMD_READ 0x00010BDA
+struct asm_stream_cmd_read{
+ struct apr_hdr hdr;
+ u32 buf_add;
+ u32 buf_size;
+ u32 uid;
+} __attribute__((packed));
+
+#define ASM_DATA_CMD_MEDIA_FORMAT_UPDATE 0x00010BDC
+#define ASM_DATA_EVENT_MEDIA_FORMAT_UPDATE 0x00010BDE
+struct asm_stream_media_format_update{
+ struct apr_hdr hdr;
+ u32 format;
+ u32 cfg_size;
+ union {
+ struct asm_pcm_cfg pcm_cfg;
+ struct asm_adpcm_cfg adpcm_cfg;
+ struct asm_yadpcm_cfg yadpcm_cfg;
+ struct asm_midi_cfg midi_cfg;
+ struct asm_wma_cfg wma_cfg;
+ struct asm_wmapro_cfg wmapro_cfg;
+ struct asm_aac_cfg aac_cfg;
+ struct asm_flac_cfg flac_cfg;
+ struct asm_vorbis_cfg vorbis_cfg;
+ } __attribute__((packed)) write_cfg;
+} __attribute__((packed));
+
+
+/* Command Responses */
+#define ASM_STREAM_CMDRSP_GET_ENCDEC_PARAM 0x00010C12
+struct asm_stream_cmdrsp_get_readwrite_param{
+ struct apr_hdr hdr;
+ u32 status;
+ u32 param_id;
+ u16 param_size;
+ u16 padding;
+ union {
+ struct asm_sbc_bitrate sbc_bitrate;
+ struct asm_immed_decode aac_dec;
+ } __attribute__((packed)) read_write_cfg;
+} __attribute__((packed));
+
+
+#define ASM_SESSION_CMDRSP_GET_SESSION_TIME 0x00010BD8
+struct asm_stream_cmdrsp_get_session_time{
+ struct apr_hdr hdr;
+ u32 status;
+ u32 msw_ts;
+ u32 lsw_ts;
+} __attribute__((packed));
+
+#define ASM_DATA_EVENT_WRITE_DONE 0x00010BDF
+struct asm_data_event_write_done{
+ u32 buf_add;
+ u32 status;
+} __attribute__((packed));
+
+#define ASM_DATA_EVENT_READ_DONE 0x00010BE0
+struct asm_data_event_read_done{
+ u32 status;
+ u32 buffer_add;
+ u32 enc_frame_size;
+ u32 offset;
+ u32 msw_ts;
+ u32 lsw_ts;
+ u32 flags;
+ u32 num_frames;
+ u32 id;
+} __attribute__((packed));
+
+
+/* service level events */
+
+#define ASM_SERVICE_CMDRSP_GET_STREAM_HANDLES 0x00010C1B
+struct asm_svc_cmdrsp_get_strm_handles{
+ struct apr_hdr hdr;
+ u32 num_handles;
+ u32 stream_handles;
+} __attribute__((packed));
+
+
+#define ASM_SERVICE_CMDRSP_GET_WALLCLOCK_TIME 0x00010C1A
+struct asm_svc_cmdrsp_get_wallclock_time{
+ struct apr_hdr hdr;
+ u32 status;
+ u32 msw_ts;
+ u32 lsw_ts;
+} __attribute__((packed));
+
+/*
+ * Error code
+*/
+#define ADSP_EOK 0x00000000 /* Success / completed / no errors. */
+#define ADSP_EFAILED 0x00000001 /* General failure. */
+#define ADSP_EBADPARAM 0x00000002 /* Bad operation parameter(s). */
+#define ADSP_EUNSUPPORTED 0x00000003 /* Unsupported routine/operation. */
+#define ADSP_EVERSION 0x00000004 /* Unsupported version. */
+#define ADSP_EUNEXPECTED 0x00000005 /* Unexpected problem encountered. */
+#define ADSP_EPANIC 0x00000006 /* Unhandled problem occurred. */
+#define ADSP_ENORESOURCE 0x00000007 /* Unable to allocate resource(s). */
+#define ADSP_EHANDLE 0x00000008 /* Invalid handle. */
+#define ADSP_EALREADY 0x00000009 /* Operation is already processed. */
+#define ADSP_ENOTREADY 0x0000000A /* Operation not ready to be processed*/
+#define ADSP_EPENDING 0x0000000B /* Operation is pending completion*/
+#define ADSP_EBUSY 0x0000000C /* Operation could not be accepted or
+ processed. */
+#define ADSP_EABORTED 0x0000000D /* Operation aborted due to an error. */
+#define ADSP_EPREEMPTED 0x0000000E /* Operation preempted by higher priority*/
+#define ADSP_ECONTINUE 0x0000000F /* Operation requests intervention
+ to complete. */
+#define ADSP_EIMMEDIATE 0x00000010 /* Operation requests immediate
+ intervention to complete. */
+#define ADSP_ENOTIMPL 0x00000011 /* Operation is not implemented. */
+#define ADSP_ENEEDMORE 0x00000012 /* Operation needs more data or resources*/
+
+#endif /*_APR_AUDIO_H_*/
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v3/audio_dev_ctl.h b/arch/arm/mach-msm/include/mach/qdsp6v3/audio_dev_ctl.h
new file mode 100644
index 00000000000..d8ea0d45326
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp6v3/audio_dev_ctl.h
@@ -0,0 +1,240 @@
+/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef __MACH_QDSP6_V2_SNDDEV_H
+#define __MACH_QDSP6_V2_SNDDEV_H
+#include
+
+#define AUDIO_DEV_CTL_MAX_DEV 64
+#define DIR_TX 2
+#define DIR_RX 1
+
+#define DEVICE_IGNORE 0xffffffff
+#define SESSION_IGNORE 0x0UL
+
+/* 8 concurrent sessions with Q6 possible, session:0
+ reserved in DSP */
+#define MAX_SESSIONS 0x09
+
+/* This represents Maximum bit needed for representing sessions
+ per clients, MAX_BIT_PER_CLIENT >= MAX_SESSIONS */
+#define MAX_BIT_PER_CLIENT 16
+
+#define VOICE_STATE_INVALID 0x0
+#define VOICE_STATE_INCALL 0x1
+#define VOICE_STATE_OFFCALL 0x2
+#define ONE_TO_MANY 1
+#define MANY_TO_ONE 2
+
+struct msm_snddev_info {
+ const char *name;
+ u32 capability;
+ u32 copp_id;
+ u32 acdb_id;
+ u32 dev_volume;
+ struct msm_snddev_ops {
+ int (*open)(struct msm_snddev_info *);
+ int (*close)(struct msm_snddev_info *);
+ int (*set_freq)(struct msm_snddev_info *, u32);
+ int (*enable_sidetone)(struct msm_snddev_info *, u32, uint16_t);
+ int (*set_device_volume)(struct msm_snddev_info *, u32);
+ int (*enable_anc)(struct msm_snddev_info *, u32);
+ } dev_ops;
+ u8 opened;
+ void *private_data;
+ bool state;
+ u32 sample_rate;
+ u32 channel_mode;
+ u32 set_sample_rate;
+ u64 sessions;
+ int usage_count;
+ s32 max_voc_rx_vol[VOC_RX_VOL_ARRAY_NUM]; /* [0] is for NB,[1] for WB */
+ s32 min_voc_rx_vol[VOC_RX_VOL_ARRAY_NUM];
+};
+
+struct msm_volume {
+ int volume; /* Volume parameter, in % Scale */
+ int pan;
+};
+
+extern struct msm_volume msm_vol_ctl;
+
+void msm_snddev_register(struct msm_snddev_info *);
+void msm_snddev_unregister(struct msm_snddev_info *);
+int msm_snddev_devcount(void);
+int msm_snddev_query(int dev_id);
+unsigned short msm_snddev_route_dec(int popp_id);
+unsigned short msm_snddev_route_enc(int enc_id);
+
+int msm_snddev_set_dec(int popp_id, int copp_id, int set,
+ int rate, int channel_mode);
+int msm_snddev_set_enc(int popp_id, int copp_id, int set,
+ int rate, int channel_mode);
+
+int msm_snddev_is_set(int popp_id, int copp_id);
+int msm_get_voc_route(u32 *rx_id, u32 *tx_id);
+int msm_set_voc_route(struct msm_snddev_info *dev_info, int stream_type,
+ int dev_id);
+int msm_snddev_enable_sidetone(u32 dev_id, u32 enable, uint16_t gain);
+
+int msm_set_copp_id(int session_id, int copp_id);
+
+int msm_clear_copp_id(int session_id, int copp_id);
+
+int msm_clear_session_id(int session_id);
+
+int msm_reset_all_device(void);
+
+int msm_clear_all_session(void);
+
+struct msm_snddev_info *audio_dev_ctrl_find_dev(u32 dev_id);
+
+void msm_release_voc_thread(void);
+
+int snddev_voice_set_volume(int vol, int path);
+
+int msm_get_call_state(void);
+
+struct auddev_evt_voc_devinfo {
+ u32 dev_type; /* Rx or Tx */
+ u32 acdb_dev_id; /* acdb id of device */
+ u32 dev_sample; /* Sample rate of device */
+ s32 max_rx_vol[VOC_RX_VOL_ARRAY_NUM]; /* unit is mb (milibel),
+ [0] is for NB, other for WB */
+ s32 min_rx_vol[VOC_RX_VOL_ARRAY_NUM]; /* unit is mb */
+ u32 dev_id; /* registered device id */
+ u32 dev_port_id;
+};
+
+struct auddev_evt_audcal_info {
+ u32 dev_id;
+ u32 acdb_id;
+ u32 sample_rate;
+ u32 dev_type;
+ u32 sessions;
+};
+
+union msm_vol_mute {
+ int vol;
+ bool mute;
+};
+
+struct auddev_evt_voc_mute_info {
+ u32 dev_type;
+ u32 acdb_dev_id;
+ union msm_vol_mute dev_vm_val;
+};
+
+struct auddev_evt_freq_info {
+ u32 dev_type;
+ u32 acdb_dev_id;
+ u32 sample_rate;
+};
+
+union auddev_evt_data {
+ struct auddev_evt_voc_devinfo voc_devinfo;
+ struct auddev_evt_voc_mute_info voc_vm_info;
+ struct auddev_evt_freq_info freq_info;
+ u32 routing_id;
+ s32 session_vol;
+ s32 voice_state;
+ struct auddev_evt_audcal_info audcal_info;
+};
+
+struct message_header {
+ uint32_t id;
+ uint32_t data_len;
+};
+
+#define AUDDEV_EVT_DEV_CHG_VOICE 0x01 /* device change event */
+#define AUDDEV_EVT_DEV_RDY 0x02 /* device ready event */
+#define AUDDEV_EVT_DEV_RLS 0x04 /* device released event */
+#define AUDDEV_EVT_REL_PENDING 0x08 /* device release pending */
+#define AUDDEV_EVT_DEVICE_VOL_MUTE_CHG 0x10 /* device volume changed */
+#define AUDDEV_EVT_START_VOICE 0x20 /* voice call start */
+#define AUDDEV_EVT_END_VOICE 0x40 /* voice call end */
+#define AUDDEV_EVT_STREAM_VOL_CHG 0x80 /* device volume changed */
+#define AUDDEV_EVT_FREQ_CHG 0x100 /* Change in freq */
+#define AUDDEV_EVT_VOICE_STATE_CHG 0x200 /* Change in voice state */
+
+#define AUDDEV_CLNT_VOC 0x1 /*Vocoder clients*/
+#define AUDDEV_CLNT_DEC 0x2 /*Decoder clients*/
+#define AUDDEV_CLNT_ENC 0x3 /* Encoder clients */
+#define AUDDEV_CLNT_AUDIOCAL 0x4 /* AudioCalibration client */
+
+#define AUDIO_DEV_CTL_MAX_LISTNER 20 /* Max Listeners Supported */
+
+struct msm_snd_evt_listner {
+ uint32_t evt_id;
+ uint32_t clnt_type;
+ uint32_t clnt_id;
+ void *private_data;
+ void (*auddev_evt_listener)(u32 evt_id,
+ union auddev_evt_data *evt_payload,
+ void *private_data);
+ struct msm_snd_evt_listner *cb_next;
+ struct msm_snd_evt_listner *cb_prev;
+};
+
+struct event_listner {
+ struct msm_snd_evt_listner *cb;
+ u32 num_listner;
+ int state; /* Call state */ /* TODO remove this if not req*/
+};
+
+extern struct event_listner event;
+int auddev_register_evt_listner(u32 evt_id, u32 clnt_type, u32 clnt_id,
+ void (*listner)(u32 evt_id,
+ union auddev_evt_data *evt_payload,
+ void *private_data),
+ void *private_data);
+int auddev_unregister_evt_listner(u32 clnt_type, u32 clnt_id);
+void mixer_post_event(u32 evt_id, u32 dev_id);
+void broadcast_event(u32 evt_id, u32 dev_id, u64 session_id);
+int auddev_cfg_tx_copp_topology(int session_id, int cfg);
+int msm_snddev_request_freq(int *freq, u32 session_id,
+ u32 capability, u32 clnt_type);
+int msm_snddev_withdraw_freq(u32 session_id,
+ u32 capability, u32 clnt_type);
+int msm_device_is_voice(int dev_id);
+int msm_get_voc_freq(int *tx_freq, int *rx_freq);
+int msm_snddev_get_enc_freq(int session_id);
+int msm_set_voice_vol(int dir, s32 volume);
+int msm_set_voice_mute(int dir, int mute);
+int msm_get_voice_state(void);
+int msm_enable_incall_recording(int popp_id, int rec_mode, int rate,
+ int channel_mode);
+int msm_disable_incall_recording(uint32_t popp_id, uint32_t rec_mode);
+void msm_set_voc_freq(int tx_freq, int rx_freq);
+
+struct dev_ctrl_ops {
+ int (*support_opendsp) (void);
+};
+
+void htc_8x60_register_dev_ctrl_ops(struct dev_ctrl_ops *ops);
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v3/q6afe.h b/arch/arm/mach-msm/include/mach/qdsp6v3/q6afe.h
new file mode 100644
index 00000000000..0e977557f9d
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp6v3/q6afe.h
@@ -0,0 +1,67 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef __Q6AFE_H__
+#define __Q6AFE_H__
+#include
+
+#define MSM_AFE_MONO 0
+#define MSM_AFE_MONO_RIGHT 1
+#define MSM_AFE_MONO_LEFT 2
+#define MSM_AFE_STEREO 3
+
+enum {
+ IDX_PRIMARY_I2S_RX = 0,
+ IDX_PRIMARY_I2S_TX = 1,
+ IDX_PCM_RX = 2,
+ IDX_PCM_TX = 3,
+ IDX_SECONDARY_I2S_RX = 4,
+ IDX_SECONDARY_I2S_TX = 5,
+ IDX_MI2S_RX = 6,
+ IDX_MI2S_TX = 7,
+ IDX_HDMI_RX = 8,
+ IDX_RSVD_2 = 9,
+ IDX_RSVD_3 = 10,
+ IDX_DIGI_MIC_TX = 11,
+ IDX_VOICE_RECORD_RX = 12,
+ IDX_VOICE_RECORD_TX = 13,
+ IDX_VOICE_PLAYBACK_TX = 14,
+ AFE_MAX_PORTS
+};
+
+
+int afe_open(u16 port_id, union afe_port_config *afe_config, int rate);
+int afe_close(int port_id);
+int afe_loopback(u16 enable, u16 rx_port, u16 tx_port);
+int afe_sidetone(u16 tx_port_id, u16 rx_port_id, u16 enable, uint16_t gain);
+int afe_loopback_gain(u16 port_id, u16 volume);
+int afe_validate_port(u16 port_id);
+int afe_get_port_index(u16 port_id);
+int afe_start_pseudo_port(u16 port_id);
+int afe_stop_pseudo_port(u16 port_id);
+
+#endif /* __Q6AFE_H__ */
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v3/q6asm.h b/arch/arm/mach-msm/include/mach/qdsp6v3/q6asm.h
new file mode 100644
index 00000000000..afb037726a3
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp6v3/q6asm.h
@@ -0,0 +1,264 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef __Q6_ASM_H__
+#define __Q6_ASM_H__
+
+#include
+
+#define IN 0x000
+#define OUT 0x001
+#define CH_MODE_MONO 0x001
+#define CH_MODE_STEREO 0x002
+
+#define FORMAT_LINEAR_PCM 0x0000
+#define FORMAT_DTMF 0x0001
+#define FORMAT_ADPCM 0x0002
+#define FORMAT_YADPCM 0x0003
+#define FORMAT_MP3 0x0004
+#define FORMAT_MPEG4_AAC 0x0005
+#define FORMAT_AMRNB 0x0006
+#define FORMAT_AMRWB 0x0007
+#define FORMAT_V13K 0x0008
+#define FORMAT_EVRC 0x0009
+#define FORMAT_EVRCB 0x000a
+#define FORMAT_EVRCWB 0x000b
+#define FORMAT_MIDI 0x000c
+#define FORMAT_SBC 0x000d
+#define FORMAT_WMA_V10PRO 0x000e
+#define FORMAT_WMA_V9 0x000f
+#define FORMAT_AMR_WB_PLUS 0x0010
+
+#define ENCDEC_SBCBITRATE 0x0001
+#define ENCDEC_IMMEDIATE_DECODE 0x0002
+#define ENCDEC_CFG_BLK 0x0003
+
+#define CMD_PAUSE 0x0001
+#define CMD_FLUSH 0x0002
+#define CMD_EOS 0x0003
+#define CMD_CLOSE 0x0004
+
+/* bit 0:1 represents priority of stream */
+#define STREAM_PRIORITY_NORMAL 0x0000
+#define STREAM_PRIORITY_LOW 0x0001
+#define STREAM_PRIORITY_HIGH 0x0002
+
+/* bit 4 represents META enable of encoded data buffer */
+#define BUFFER_META_ENABLE 0x0010
+
+#define ASYNC_IO_MODE 0x0002
+#define SYNC_IO_MODE 0x0001
+#define NO_TIMESTAMP 0xFF00
+#define SET_TIMESTAMP 0x0000
+
+#define SOFT_PAUSE_ENABLE 1
+#define SOFT_PAUSE_DISABLE 0
+
+#define SESSION_MAX 0x08
+
+typedef void (*app_cb)(uint32_t opcode, uint32_t token,
+ uint32_t *payload, void *priv);
+
+struct audio_buffer {
+ dma_addr_t phys;
+ void *data;
+ uint32_t used;
+ uint32_t size;/* size of buffer */
+ uint32_t actual_size; /* actual number of bytes read by DSP */
+};
+
+struct audio_aio_write_param {
+ unsigned long paddr;
+ uint32_t uid;
+ uint32_t len;
+ uint32_t msw_ts;
+ uint32_t lsw_ts;
+ uint32_t flags;
+};
+
+struct audio_aio_read_param {
+ unsigned long paddr;
+ uint32_t len;
+ uint32_t uid;
+};
+
+struct audio_port_data {
+ struct audio_buffer *buf;
+ uint32_t max_buf_cnt;
+ uint32_t dsp_buf;
+ uint32_t cpu_buf;
+ /* read or write locks */
+ struct mutex lock;
+ spinlock_t dsp_lock;
+};
+
+struct audio_client {
+ int session;
+ /* idx:1 out port, 0: in port*/
+ struct audio_port_data port[2];
+
+ struct apr_svc *apr;
+ struct mutex cmd_lock;
+
+ atomic_t cmd_state;
+ atomic_t time_flag;
+ wait_queue_head_t cmd_wait;
+ wait_queue_head_t time_wait;
+
+ app_cb cb;
+ void *priv;
+ uint32_t io_mode;
+ uint64_t time_stamp;
+};
+
+void q6asm_audio_client_free(struct audio_client *ac);
+
+struct audio_client *q6asm_audio_client_alloc(app_cb cb, void *priv);
+
+int q6asm_audio_client_buf_alloc(unsigned int dir/* 1:Out,0:In */,
+ struct audio_client *ac,
+ unsigned int bufsz,
+ unsigned int bufcnt);
+int q6asm_audio_client_buf_alloc_contiguous(unsigned int dir
+ /* 1:Out,0:In */,
+ struct audio_client *ac,
+ unsigned int bufsz,
+ unsigned int bufcnt);
+
+int q6asm_audio_client_buf_free_contiguous(unsigned int dir,
+ struct audio_client *ac);
+
+int q6asm_open_read(struct audio_client *ac, uint32_t format);
+
+int q6asm_open_write(struct audio_client *ac, uint32_t format);
+
+int q6asm_open_read_write(struct audio_client *ac,
+ uint32_t rd_format,
+ uint32_t wr_format);
+
+int q6asm_write(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
+ uint32_t lsw_ts, uint32_t flags);
+
+int q6asm_write_nolock(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
+ uint32_t lsw_ts, uint32_t flags);
+
+int q6asm_async_write(struct audio_client *ac,
+ struct audio_aio_write_param *param);
+
+int q6asm_async_read(struct audio_client *ac,
+ struct audio_aio_read_param *param);
+
+int q6asm_read(struct audio_client *ac);
+int q6asm_read_nolock(struct audio_client *ac);
+
+int q6asm_memory_map(struct audio_client *ac, uint32_t buf_add,
+ int dir, uint32_t bufsz, uint32_t bufcnt);
+
+int q6asm_memory_unmap(struct audio_client *ac, uint32_t buf_add,
+ int dir);
+
+int q6asm_run(struct audio_client *ac, uint32_t flags,
+ uint32_t msw_ts, uint32_t lsw_ts);
+
+int q6asm_run_nowait(struct audio_client *ac, uint32_t flags,
+ uint32_t msw_ts, uint32_t lsw_ts);
+
+int q6asm_reg_tx_overflow(struct audio_client *ac, uint16_t enable);
+
+int q6asm_cmd(struct audio_client *ac, int cmd);
+
+int q6asm_cmd_nowait(struct audio_client *ac, int cmd);
+
+void *q6asm_is_cpu_buf_avail(int dir, struct audio_client *ac,
+ uint32_t *size, uint32_t *idx);
+
+int q6asm_is_dsp_buf_avail(int dir, struct audio_client *ac);
+
+/* File format specific configurations to be added below */
+
+int q6asm_enc_cfg_blk_aac(struct audio_client *ac,
+ uint32_t frames_per_buf,
+ uint32_t sample_rate, uint32_t channels,
+ uint32_t bit_rate,
+ uint32_t mode, uint32_t format);
+
+int q6asm_enc_cfg_blk_pcm(struct audio_client *ac,
+ uint32_t rate, uint32_t channels);
+
+int q6asm_enable_sbrps(struct audio_client *ac,
+ uint32_t sbr_ps);
+
+int q6asm_enc_cfg_blk_qcelp(struct audio_client *ac, uint32_t frames_per_buf,
+ uint16_t min_rate, uint16_t max_rate,
+ uint16_t reduced_rate_level, uint16_t rate_modulation_cmd);
+
+int q6asm_enc_cfg_blk_evrc(struct audio_client *ac, uint32_t frames_per_buf,
+ uint16_t min_rate, uint16_t max_rate,
+ uint16_t rate_modulation_cmd);
+
+int q6asm_enc_cfg_blk_amrnb(struct audio_client *ac, uint32_t frames_per_buf,
+ uint16_t band_mode, uint16_t dtx_enable);
+
+int q6asm_media_format_block_pcm(struct audio_client *ac,
+ uint32_t rate, uint32_t channels);
+
+int q6asm_media_format_block_aac(struct audio_client *ac,
+ struct asm_aac_cfg *cfg);
+
+int q6asm_media_format_block_wma(struct audio_client *ac,
+ void *cfg);
+
+int q6asm_media_format_block_wmapro(struct audio_client *ac,
+ void *cfg);
+
+/* PP specific */
+int q6asm_equalizer(struct audio_client *ac, void *eq);
+
+/* Send Volume Command */
+int q6asm_set_volume(struct audio_client *ac, int volume);
+
+/* Set SoftPause Params */
+int q6asm_set_softpause(struct audio_client *ac,
+ struct asm_softpause_params *param);
+
+/* Send left-right channel gain */
+int q6asm_set_lrgain(struct audio_client *ac, int left_gain, int right_gain);
+
+/* Enable Mute/unmute flag */
+int q6asm_set_mute(struct audio_client *ac, int muteflag);
+
+uint64_t q6asm_get_session_time(struct audio_client *ac);
+
+/* Client can set the IO mode to either AIO/SIO mode */
+int q6asm_set_io_mode(struct audio_client *ac, uint32_t mode);
+
+#ifdef CONFIG_MSM8X60_RTAC
+/* Get Service ID for APR communication */
+int q6asm_get_apr_service_id(int session_id);
+#endif
+
+#endif /* __Q6_ASM_H__ */
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v3/q6voice.h b/arch/arm/mach-msm/include/mach/qdsp6v3/q6voice.h
new file mode 100644
index 00000000000..25d4ca3a65c
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp6v3/q6voice.h
@@ -0,0 +1,757 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef __QDSP6VOICE_H__
+#define __QDSP6VOICE_H__
+
+#include
+
+/* Device Event */
+#define DEV_CHANGE_READY 0x1
+
+#define VOICE_CALL_START 0x1
+#define VOICE_CALL_END 0
+
+#define VOICE_DEV_ENABLED 0x1
+#define VOICE_DEV_DISABLED 0
+
+#define MAX_VOC_PKT_SIZE 322
+
+#define SESSION_NAME_LEN 20
+
+struct voice_header {
+ uint32_t id;
+ uint32_t data_len;
+};
+
+struct voice_init {
+ struct voice_header hdr;
+ void *cb_handle;
+};
+
+
+/* Device information payload structure */
+
+struct device_data {
+ uint32_t dev_acdb_id;
+ uint32_t volume; /* in percentage */
+ uint32_t mute;
+ uint32_t sample;
+ uint32_t enabled;
+ uint32_t dev_id;
+ uint32_t dev_port_id;
+};
+
+enum {
+ VOC_INIT = 0,
+ VOC_RUN,
+ VOC_CHANGE,
+ VOC_RELEASE,
+};
+
+/* TO MVM commands */
+#define VSS_IMVM_CMD_CREATE_PASSIVE_CONTROL_SESSION 0x000110FF
+/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_IMVM_CMD_CREATE_FULL_CONTROL_SESSION 0x000110FE
+/* Create a new full control MVM session. */
+
+#define APRV2_IBASIC_CMD_DESTROY_SESSION 0x0001003C
+/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_IMVM_CMD_ATTACH_STREAM 0x0001123C
+/* Attach a stream to the MVM. */
+
+#define VSS_IMVM_CMD_DETACH_STREAM 0x0001123D
+/* Detach a stream from the MVM. */
+
+#define VSS_IMVM_CMD_START_VOICE 0x00011190
+/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_IMVM_CMD_STOP_VOICE 0x00011192
+/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_ISTREAM_CMD_ATTACH_VOCPROC 0x000110F8
+/**< Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_ISTREAM_CMD_DETACH_VOCPROC 0x000110F9
+/**< Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+
+#define VSS_ISTREAM_CMD_SET_TTY_MODE 0x00011196
+/**< Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_ICOMMON_CMD_SET_NETWORK 0x0001119C
+/* Set the network type. */
+
+#define VSS_ICOMMON_CMD_SET_VOICE_TIMING 0x000111E0
+/* Set the voice timing parameters. */
+
+struct vss_imvm_cmd_create_control_session_t {
+ char name[SESSION_NAME_LEN]; /*
+ * A variable-sized stream name.
+ *
+ * The stream name size is the payload size minus the size of the other
+ * fields.
+ */
+} __packed;
+
+struct vss_istream_cmd_set_tty_mode_t {
+ uint32_t mode;
+ /**<
+ * TTY mode.
+ *
+ * 0 : TTY disabled
+ * 1 : HCO
+ * 2 : VCO
+ * 3 : FULL
+ */
+} __attribute__((packed));
+
+struct vss_istream_cmd_attach_vocproc_t {
+ uint16_t handle;
+ /**< Handle of vocproc being attached. */
+} __attribute__((packed));
+
+struct vss_istream_cmd_detach_vocproc_t {
+ uint16_t handle;
+ /**< Handle of vocproc being detached. */
+} __attribute__((packed));
+
+struct vss_imvm_cmd_attach_stream_t {
+ uint16_t handle;
+ /* The stream handle to attach. */
+} __attribute__((packed));
+
+struct vss_imvm_cmd_detach_stream_t {
+ uint16_t handle;
+ /* The stream handle to detach. */
+} __attribute__((packed));
+
+struct vss_icommon_cmd_set_network_t {
+ uint32_t network_id;
+ /* Network ID. (Refer to VSS_NETWORK_ID_XXX). */
+} __attribute__((packed));
+
+struct vss_icommon_cmd_set_voice_timing_t {
+ uint16_t mode;
+ /*
+ * The vocoder frame synchronization mode.
+ *
+ * 0 : No frame sync.
+ * 1 : Hard VFR (20ms Vocoder Frame Reference interrupt).
+ */
+ uint16_t enc_offset;
+ /*
+ * The offset in microseconds from the VFR to deliver a Tx vocoder
+ * packet. The offset should be less than 20000us.
+ */
+ uint16_t dec_req_offset;
+ /*
+ * The offset in microseconds from the VFR to request for an Rx vocoder
+ * packet. The offset should be less than 20000us.
+ */
+ uint16_t dec_offset;
+ /*
+ * The offset in microseconds from the VFR to indicate the deadline to
+ * receive an Rx vocoder packet. The offset should be less than 20000us.
+ * Rx vocoder packets received after this deadline are not guaranteed to
+ * be processed.
+ */
+} __attribute__((packed));
+
+struct mvm_attach_vocproc_cmd {
+ struct apr_hdr hdr;
+ struct vss_istream_cmd_attach_vocproc_t mvm_attach_cvp_handle;
+} __attribute__((packed));
+
+struct mvm_detach_vocproc_cmd {
+ struct apr_hdr hdr;
+ struct vss_istream_cmd_detach_vocproc_t mvm_detach_cvp_handle;
+} __attribute__((packed));
+
+struct mvm_create_ctl_session_cmd {
+ struct apr_hdr hdr;
+ struct vss_imvm_cmd_create_control_session_t mvm_session;
+} __packed;
+
+struct mvm_set_tty_mode_cmd {
+ struct apr_hdr hdr;
+ struct vss_istream_cmd_set_tty_mode_t tty_mode;
+} __attribute__((packed));
+
+struct mvm_attach_stream_cmd {
+ struct apr_hdr hdr;
+ struct vss_imvm_cmd_attach_stream_t attach_stream;
+} __attribute__((packed));
+
+struct mvm_detach_stream_cmd {
+ struct apr_hdr hdr;
+ struct vss_imvm_cmd_detach_stream_t detach_stream;
+} __attribute__((packed));
+
+struct mvm_set_network_cmd {
+ struct apr_hdr hdr;
+ struct vss_icommon_cmd_set_network_t network;
+} __attribute__((packed));
+
+struct mvm_set_voice_timing_cmd {
+ struct apr_hdr hdr;
+ struct vss_icommon_cmd_set_voice_timing_t timing;
+} __attribute__((packed));
+
+/* TO CVS commands */
+#define VSS_ISTREAM_CMD_CREATE_PASSIVE_CONTROL_SESSION 0x00011140
+/**< Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_ISTREAM_CMD_CREATE_FULL_CONTROL_SESSION 0x000110F7
+/* Create a new full control stream session. */
+
+#define APRV2_IBASIC_CMD_DESTROY_SESSION 0x0001003C
+
+#define VSS_ISTREAM_CMD_CACHE_CALIBRATION_DATA 0x000110FB
+
+#define VSS_ISTREAM_CMD_SET_MUTE 0x00011022
+
+#define VSS_ISTREAM_CMD_SET_MEDIA_TYPE 0x00011186
+/* Set media type on the stream. */
+
+#define VSS_ISTREAM_EVT_SEND_ENC_BUFFER 0x00011015
+/* Event sent by the stream to its client to provide an encoded packet. */
+
+#define VSS_ISTREAM_EVT_REQUEST_DEC_BUFFER 0x00011017
+/* Event sent by the stream to its client requesting for a decoder packet.
+ * The client should respond with a VSS_ISTREAM_EVT_SEND_DEC_BUFFER event.
+ */
+
+#define VSS_ISTREAM_EVT_SEND_DEC_BUFFER 0x00011016
+/* Event sent by the client to the stream in response to a
+ * VSS_ISTREAM_EVT_REQUEST_DEC_BUFFER event, providing a decoder packet.
+ */
+
+#define VSS_ISTREAM_CMD_VOC_AMR_SET_ENC_RATE 0x0001113E
+/* Set AMR encoder rate. */
+
+#define VSS_ISTREAM_CMD_VOC_AMRWB_SET_ENC_RATE 0x0001113F
+/* Set AMR-WB encoder rate. */
+
+#define VSS_ISTREAM_CMD_CDMA_SET_ENC_MINMAX_RATE 0x00011019
+/* Set encoder minimum and maximum rate. */
+
+#define VSS_ISTREAM_CMD_SET_ENC_DTX_MODE 0x0001101D
+/* Set encoder DTX mode. */
+
+#define VSS_ISTREAM_CMD_START_RECORD 0x00011236
+/* Start in-call conversation recording. */
+
+#define VSS_ISTREAM_CMD_STOP_RECORD 0x00011237
+/* Stop in-call conversation recording. */
+
+#define VSS_ISTREAM_CMD_START_PLAYBACK 0x00011238
+/* Start in-call music delivery on the Tx voice path. */
+
+#define VSS_ISTREAM_CMD_STOP_PLAYBACK 0x00011239
+/* Stop the in-call music delivery on the Tx voice path. */
+
+struct vss_istream_cmd_create_passive_control_session_t {
+ char name[SESSION_NAME_LEN];
+ /**<
+ * A variable-sized stream name.
+ *
+ * The stream name size is the payload size minus the size of the other
+ * fields.
+ */
+} __attribute__((packed));
+
+struct vss_istream_cmd_set_mute_t {
+ uint16_t direction;
+ /**<
+ * 0 : TX only
+ * 1 : RX only
+ * 2 : TX and Rx
+ */
+ uint16_t mute_flag;
+ /**<
+ * Mute, un-mute.
+ *
+ * 0 : Silence disable
+ * 1 : Silence enable
+ * 2 : CNG enable. Applicable to TX only. If set on RX behavior
+ * will be the same as 1
+ */
+} __attribute__((packed));
+
+struct vss_istream_cmd_create_full_control_session_t {
+ uint16_t direction;
+ /*
+ * Stream direction.
+ *
+ * 0 : TX only
+ * 1 : RX only
+ * 2 : TX and RX
+ * 3 : TX and RX loopback
+ */
+ uint32_t enc_media_type;
+ /* Tx vocoder type. (Refer to VSS_MEDIA_ID_XXX). */
+ uint32_t dec_media_type;
+ /* Rx vocoder type. (Refer to VSS_MEDIA_ID_XXX). */
+ uint32_t network_id;
+ /* Network ID. (Refer to VSS_NETWORK_ID_XXX). */
+ char name[SESSION_NAME_LEN];
+ /*
+ * A variable-sized stream name.
+ *
+ * The stream name size is the payload size minus the size of the other
+ * fields.
+ */
+} __attribute__((packed));
+
+struct vss_istream_cmd_set_media_type_t {
+ uint32_t rx_media_id;
+ /* Set the Rx vocoder type. (Refer to VSS_MEDIA_ID_XXX). */
+ uint32_t tx_media_id;
+ /* Set the Tx vocoder type. (Refer to VSS_MEDIA_ID_XXX). */
+} __attribute__((packed));
+
+struct vss_istream_evt_send_enc_buffer_t {
+ uint32_t media_id;
+ /* Media ID of the packet. */
+ uint8_t packet_data[MAX_VOC_PKT_SIZE];
+ /* Packet data buffer. */
+} __attribute__((packed));
+
+struct vss_istream_evt_send_dec_buffer_t {
+ uint32_t media_id;
+ /* Media ID of the packet. */
+ uint8_t packet_data[MAX_VOC_PKT_SIZE];
+ /* Packet data. */
+} __attribute__((packed));
+
+struct vss_istream_cmd_voc_amr_set_enc_rate_t {
+ uint32_t mode;
+ /* Set the AMR encoder rate.
+ *
+ * 0x00000000 : 4.75 kbps
+ * 0x00000001 : 5.15 kbps
+ * 0x00000002 : 5.90 kbps
+ * 0x00000003 : 6.70 kbps
+ * 0x00000004 : 7.40 kbps
+ * 0x00000005 : 7.95 kbps
+ * 0x00000006 : 10.2 kbps
+ * 0x00000007 : 12.2 kbps
+ */
+} __attribute__((packed));
+
+struct vss_istream_cmd_voc_amrwb_set_enc_rate_t {
+ uint32_t mode;
+ /* Set the AMR-WB encoder rate.
+ *
+ * 0x00000000 : 6.60 kbps
+ * 0x00000001 : 8.85 kbps
+ * 0x00000002 : 12.65 kbps
+ * 0x00000003 : 14.25 kbps
+ * 0x00000004 : 15.85 kbps
+ * 0x00000005 : 18.25 kbps
+ * 0x00000006 : 19.85 kbps
+ * 0x00000007 : 23.05 kbps
+ * 0x00000008 : 23.85 kbps
+ */
+} __attribute__((packed));
+
+struct vss_istream_cmd_cdma_set_enc_minmax_rate_t {
+ uint16_t min_rate;
+ /* Set the lower bound encoder rate.
+ *
+ * 0x0000 : Blank frame
+ * 0x0001 : Eighth rate
+ * 0x0002 : Quarter rate
+ * 0x0003 : Half rate
+ * 0x0004 : Full rate
+ */
+ uint16_t max_rate;
+ /* Set the upper bound encoder rate.
+ *
+ * 0x0000 : Blank frame
+ * 0x0001 : Eighth rate
+ * 0x0002 : Quarter rate
+ * 0x0003 : Half rate
+ * 0x0004 : Full rate
+ */
+} __attribute__((packed));
+
+struct vss_istream_cmd_set_enc_dtx_mode_t {
+ uint32_t enable;
+ /* Toggle DTX on or off.
+ *
+ * 0 : Disables DTX
+ * 1 : Enables DTX
+ */
+} __attribute__((packed));
+
+#define VSS_TAP_POINT_NONE 0x00010F78
+/* Indicates no tapping for specified path. */
+
+#define VSS_TAP_POINT_STREAM_END 0x00010F79
+/* Indicates that specified path should be tapped at the end of the stream. */
+
+struct vss_istream_cmd_start_record_t {
+ uint32_t rx_tap_point;
+ /* Tap point to use on the Rx path. Supported values are:
+ * VSS_TAP_POINT_NONE : Do not record Rx path.
+ * VSS_TAP_POINT_STREAM_END : Rx tap point is at the end of the stream.
+ */
+ uint32_t tx_tap_point;
+ /* Tap point to use on the Tx path. Supported values are:
+ * VSS_TAP_POINT_NONE : Do not record tx path.
+ * VSS_TAP_POINT_STREAM_END : Tx tap point is at the end of the stream.
+ */
+} __attribute__((packed));
+
+struct cvs_create_passive_ctl_session_cmd {
+ struct apr_hdr hdr;
+ struct vss_istream_cmd_create_passive_control_session_t cvs_session;
+} __attribute__((packed));
+
+struct cvs_create_full_ctl_session_cmd {
+ struct apr_hdr hdr;
+ struct vss_istream_cmd_create_full_control_session_t cvs_session;
+} __attribute__((packed));
+
+struct cvs_destroy_session_cmd {
+ struct apr_hdr hdr;
+} __attribute__((packed));
+
+struct cvs_cache_calibration_data_cmd {
+ struct apr_hdr hdr;
+} __attribute__ ((packed));
+
+struct cvs_set_mute_cmd {
+ struct apr_hdr hdr;
+ struct vss_istream_cmd_set_mute_t cvs_set_mute;
+} __attribute__((packed));
+
+struct cvs_set_media_type_cmd {
+ struct apr_hdr hdr;
+ struct vss_istream_cmd_set_media_type_t media_type;
+} __attribute__((packed));
+
+struct cvs_send_dec_buf_cmd {
+ struct apr_hdr hdr;
+ struct vss_istream_evt_send_dec_buffer_t dec_buf;
+} __attribute__((packed));
+
+struct cvs_set_amr_enc_rate_cmd {
+ struct apr_hdr hdr;
+ struct vss_istream_cmd_voc_amr_set_enc_rate_t amr_rate;
+} __attribute__((packed));
+
+struct cvs_set_amrwb_enc_rate_cmd {
+ struct apr_hdr hdr;
+ struct vss_istream_cmd_voc_amrwb_set_enc_rate_t amrwb_rate;
+} __attribute__((packed));
+
+struct cvs_set_cdma_enc_minmax_rate_cmd {
+ struct apr_hdr hdr;
+ struct vss_istream_cmd_cdma_set_enc_minmax_rate_t cdma_rate;
+} __attribute__((packed));
+
+struct cvs_set_enc_dtx_mode_cmd {
+ struct apr_hdr hdr;
+ struct vss_istream_cmd_set_enc_dtx_mode_t dtx_mode;
+} __attribute__((packed));
+
+struct cvs_start_record_cmd {
+ struct apr_hdr hdr;
+ struct vss_istream_cmd_start_record_t rec_mode;
+} __attribute__((packed));
+
+/* TO CVP commands */
+
+#define VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION 0x000100C3
+/**< Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define APRV2_IBASIC_CMD_DESTROY_SESSION 0x0001003C
+
+#define VSS_IVOCPROC_CMD_SET_DEVICE 0x000100C4
+
+#define VSS_IVOCPROC_CMD_CACHE_CALIBRATION_DATA 0x000110E3
+
+#define VSS_IVOCPROC_CMD_CACHE_VOLUME_CALIBRATION_TABLE 0x000110E4
+
+#define VSS_IVOCPROC_CMD_SET_VP3_DATA 0x000110EB
+
+#define VSS_IVOCPROC_CMD_SET_RX_VOLUME_INDEX 0x000110EE
+
+#define VSS_IVOCPROC_CMD_ENABLE 0x000100C6
+/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_IVOCPROC_CMD_DISABLE 0x000110E1
+/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_IVOCPROC_TOPOLOGY_ID_NONE 0x00010F70
+#define VSS_IVOCPROC_TOPOLOGY_ID_TX_SM_ECNS 0x00010F71
+#define VSS_IVOCPROC_TOPOLOGY_ID_TX_DM_FLUENCE 0x00010F72
+
+#define VSS_IVOCPROC_TOPOLOGY_ID_RX_DEFAULT 0x00010F77
+
+/* Newtwork IDs */
+#define VSS_NETWORK_ID_DEFAULT 0x00010037
+#define VSS_NETWORK_ID_VOIP_NB 0x00011240
+#define VSS_NETWORK_ID_VOIP_WB 0x00011241
+#define VSS_NETWORK_ID_VOIP_WV 0x00011242
+
+/* Media types */
+#define VSS_MEDIA_ID_EVRC_MODEM 0x00010FC2
+/* 80-VF690-47 CDMA enhanced variable rate vocoder modem format. */
+#define VSS_MEDIA_ID_AMR_NB_MODEM 0x00010FC6
+/* 80-VF690-47 UMTS AMR-NB vocoder modem format. */
+#define VSS_MEDIA_ID_AMR_WB_MODEM 0x00010FC7
+/* 80-VF690-47 UMTS AMR-WB vocoder modem format. */
+#define VSS_MEDIA_ID_PCM_NB 0x00010FCB
+/* Linear PCM (16-bit, little-endian). */
+#define VSS_MEDIA_ID_G711_ALAW 0x00010FCD
+/* G.711 a-law (contains two 10ms vocoder frames). */
+#define VSS_MEDIA_ID_G711_MULAW 0x00010FCE
+/* G.711 mu-law (contains two 10ms vocoder frames). */
+#define VSS_MEDIA_ID_G729 0x00010FD0
+/* G.729AB (contains two 10ms vocoder frames. */
+
+#define VOICE_CMD_SET_PARAM 0x00011006
+#define VOICE_CMD_GET_PARAM 0x00011007
+#define VOICE_EVT_GET_PARAM_ACK 0x00011008
+
+struct vss_ivocproc_cmd_create_full_control_session_t {
+ uint16_t direction;
+ /*
+ * stream direction.
+ * 0 : TX only
+ * 1 : RX only
+ * 2 : TX and RX
+ */
+ uint32_t tx_port_id;
+ /*
+ * TX device port ID which vocproc will connect to. If not supplying a
+ * port ID set to VSS_IVOCPROC_PORT_ID_NONE.
+ */
+ uint32_t tx_topology_id;
+ /*
+ * Tx leg topology ID. If not supplying a topology ID set to
+ * VSS_IVOCPROC_TOPOLOGY_ID_NONE.
+ */
+ uint32_t rx_port_id;
+ /*
+ * RX device port ID which vocproc will connect to. If not supplying a
+ * port ID set to VSS_IVOCPROC_PORT_ID_NONE.
+ */
+ uint32_t rx_topology_id;
+ /*
+ * Rx leg topology ID. If not supplying a topology ID set to
+ * VSS_IVOCPROC_TOPOLOGY_ID_NONE.
+ */
+ int32_t network_id;
+ /*
+ * Network ID. (Refer to VSS_NETWORK_ID_XXX). If not supplying a network
+ * ID set to VSS_NETWORK_ID_DEFAULT.
+ */
+} __attribute__((packed));
+
+struct vss_ivocproc_cmd_set_device_t {
+ uint32_t tx_port_id;
+ /**<
+ * TX device port ID which vocproc will connect to.
+ * VSS_IVOCPROC_PORT_ID_NONE means vocproc will not connect to any port.
+ */
+ uint32_t tx_topology_id;
+ /**<
+ * TX leg topology ID.
+ * VSS_IVOCPROC_TOPOLOGY_ID_NONE means vocproc does not contain any
+ * pre/post-processing blocks and is pass-through.
+ */
+ int32_t rx_port_id;
+ /**<
+ * RX device port ID which vocproc will connect to.
+ * VSS_IVOCPROC_PORT_ID_NONE means vocproc will not connect to any port.
+ */
+ uint32_t rx_topology_id;
+ /**<
+ * RX leg topology ID.
+ * VSS_IVOCPROC_TOPOLOGY_ID_NONE means vocproc does not contain any
+ * pre/post-processing blocks and is pass-through.
+ */
+} __attribute__((packed));
+
+struct vss_ivocproc_cmd_set_volume_index_t {
+ uint16_t vol_index;
+ /**<
+ * Volume index utilized by the vocproc to index into the volume table
+ * provided in VSS_IVOCPROC_CMD_CACHE_VOLUME_CALIBRATION_TABLE and set
+ * volume on the VDSP.
+ */
+} __attribute__((packed));
+
+struct cvp_create_full_ctl_session_cmd {
+ struct apr_hdr hdr;
+ struct vss_ivocproc_cmd_create_full_control_session_t cvp_session;
+} __attribute__ ((packed));
+
+struct cvp_command {
+ struct apr_hdr hdr;
+} __attribute__((packed));
+
+struct cvp_set_device_cmd {
+ struct apr_hdr hdr;
+ struct vss_ivocproc_cmd_set_device_t cvp_set_device;
+} __attribute__ ((packed));
+
+struct cvp_cache_calibration_data_cmd {
+ struct apr_hdr hdr;
+} __attribute__((packed));
+
+struct cvp_cache_volume_calibration_table_cmd {
+ struct apr_hdr hdr;
+} __attribute__((packed));
+
+struct cvp_set_vp3_data_cmd {
+ struct apr_hdr hdr;
+} __attribute__((packed));
+
+struct cvp_set_rx_volume_index_cmd {
+ struct apr_hdr hdr;
+ struct vss_ivocproc_cmd_set_volume_index_t cvp_set_vol_idx;
+} __attribute__((packed));
+
+/* CB for up-link packets. */
+typedef void (*ul_cb_fn)(uint8_t *voc_pkt,
+ uint32_t pkt_len,
+ void *private_data);
+
+/* CB for down-link packets. */
+typedef void (*dl_cb_fn)(uint8_t *voc_pkt,
+ uint32_t *pkt_len,
+ void *private_data);
+
+
+struct mvs_driver_info {
+ uint32_t media_type;
+ uint32_t rate;
+ uint32_t network_type;
+ uint32_t dtx_mode;
+ ul_cb_fn ul_cb;
+ dl_cb_fn dl_cb;
+ void *private_data;
+};
+
+struct incall_rec_info {
+ uint32_t pending;
+ uint32_t rec_mode;
+};
+
+struct incall_music_info {
+ uint32_t pending;
+ uint32_t playing;
+};
+
+struct voice_data {
+ int voc_state;/*INIT, CHANGE, RELEASE, RUN */
+ uint32_t voc_path;
+ uint32_t adsp_version;
+
+ wait_queue_head_t mvm_wait;
+ wait_queue_head_t cvs_wait;
+ wait_queue_head_t cvp_wait;
+
+ uint32_t device_events;
+
+ /* cache the values related to Rx and Tx */
+ struct device_data dev_rx;
+ struct device_data dev_tx;
+
+ /* these default values are for all devices */
+ uint32_t default_mute_val;
+ uint32_t default_vol_val;
+ uint32_t default_sample_val;
+
+ /* call status */
+ int v_call_status; /* Start or End */
+
+ /* APR to MVM in the modem */
+ void *apr_mvm;
+ /* APR to CVS in the modem */
+ void *apr_cvs;
+ /* APR to CVP in the modem */
+ void *apr_cvp;
+
+ /* APR to MVM in the Q6 */
+ void *apr_q6_mvm;
+ /* APR to CVS in the Q6 */
+ void *apr_q6_cvs;
+ /* APR to CVP in the Q6 */
+ void *apr_q6_cvp;
+
+ u32 mvm_state;
+ u32 cvs_state;
+ u32 cvp_state;
+
+ /* Handle to MVM in the modem */
+ u16 mvm_handle;
+ /* Handle to CVS in the modem */
+ u16 cvs_handle;
+ /* Handle to CVP in the modem */
+ u16 cvp_handle;
+
+ /* Handle to MVM in the Q6 */
+ u16 mvm_q6_handle;
+ /* Handle to CVS in the Q6 */
+ u16 cvs_q6_handle;
+ /* Handle to CVP in the Q6 */
+ u16 cvp_q6_handle;
+
+ struct mutex lock;
+
+ struct mvs_driver_info mvs_info;
+
+ struct incall_rec_info rec_info;
+
+ struct incall_music_info music_info;
+};
+
+int voice_set_voc_path_full(uint32_t set);
+
+void voice_register_mvs_cb(ul_cb_fn ul_cb,
+ dl_cb_fn dl_cb,
+ void *private_data);
+
+void voice_config_vocoder(uint32_t media_type,
+ uint32_t rate,
+ uint32_t network_type,
+ uint32_t dtx_mode);
+
+int voice_start_record(uint32_t rec_mode, uint32_t set);
+
+int voice_start_playback(uint32_t set);
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v3/snddev_ecodec.h b/arch/arm/mach-msm/include/mach/qdsp6v3/snddev_ecodec.h
new file mode 100644
index 00000000000..e07ad02505c
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp6v3/snddev_ecodec.h
@@ -0,0 +1,48 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef __MACH_QDSP6V2_SNDDEV_ECODEC_H
+#define __MACH_QDSP6V2_SNDDEV_ECODEC_H
+#include
+
+struct snddev_ecodec_data {
+ u32 capability; /* RX or TX */
+ const char *name;
+ u32 copp_id; /* audpp routing */
+ u8 channel_mode;
+ u32 conf_pcm_ctl_val;
+ u32 conf_aux_codec_intf;
+ u32 conf_data_format_padding_val;
+};
+
+struct q6v2audio_ecodec_ops {
+ void (*bt_sco_enable)(int en);
+};
+
+void htc_8x60_register_ecodec_ops(struct q6v2audio_ecodec_ops *ops);
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v3/snddev_hdmi.h b/arch/arm/mach-msm/include/mach/qdsp6v3/snddev_hdmi.h
new file mode 100644
index 00000000000..cdc81a1f03f
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp6v3/snddev_hdmi.h
@@ -0,0 +1,40 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef __MACH_QDSP6_V2_SNDDEV_HDMI_H
+#define __MACH_QDSP6_V2_SNDDEV_HDMI_H
+
+struct snddev_hdmi_data {
+ u32 capability; /* RX or TX */
+ const char *name;
+ u32 copp_id; /* audpp routing */
+ u32 acdb_id; /* Audio Cal purpose */
+ u8 channel_mode;
+ u32 default_sample_rate;
+};
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v3/snddev_icodec.h b/arch/arm/mach-msm/include/mach/qdsp6v3/snddev_icodec.h
new file mode 100644
index 00000000000..06f31f569dd
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp6v3/snddev_icodec.h
@@ -0,0 +1,98 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef __MACH_QDSP6V2_SNDDEV_ICODEC_H
+#define __MACH_QDSP6V2_SNDDEV_ICODEC_H
+#include
+#include
+#include
+#include
+
+struct snddev_icodec_data {
+ u32 capability; /* RX or TX */
+ const char *name;
+ u32 copp_id; /* audpp routing */
+ /* Adie profile */
+ struct adie_codec_dev_profile *profile;
+ /* Afe setting */
+ u8 channel_mode;
+ u32 default_sample_rate;
+ void (*pamp_on) (int on);
+ void (*voltage_on) (int on);
+ u32 dev_vol_type;
+ u32 aic3254_id;
+ u32 aic3254_voc_id;
+ u32 default_aic3254_id;
+};
+
+/* Context for each internal codec sound device */
+struct snddev_icodec_state {
+ struct snddev_icodec_data *data;
+ struct adie_codec_path *adie_path;
+ u32 sample_rate;
+ u32 enabled;
+};
+
+struct q6v2audio_analog_ops {
+ void (*speaker_enable)(int en);
+ void (*headset_enable)(int en);
+ void (*handset_enable)(int en);
+ void (*bt_sco_enable)(int en);
+ void (*headset_speaker_enable)(int en);
+ void (*int_mic_enable)(int en);
+ void (*back_mic_enable)(int en);
+ void (*ext_mic_enable)(int en);
+ void (*stereo_mic_enable)(int en);
+ void (*usb_headset_enable)(int en);
+ void (*fm_headset_enable)(int en);
+ void (*fm_speaker_enable)(int en);
+ void (*voltage_on) (int on);
+};
+
+struct q6v2audio_icodec_ops {
+ int (*support_aic3254) (void);
+ int (*support_adie) (void);
+ int (*is_msm_i2s_slave) (void);
+ int (*support_aic3254_use_mclk) (void);
+};
+
+struct q6v2audio_aic3254_ops {
+ void (*aic3254_set_mode)(int config, int mode);
+};
+
+struct aic3254_info {
+ u32 dev_id;
+ u32 path_id;
+};
+
+
+void htc_8x60_register_analog_ops(struct q6v2audio_analog_ops *ops);
+void htc_8x60_register_aic3254_ops(struct q6v2audio_aic3254_ops *ops);
+int update_aic3254_info(struct aic3254_info *info);
+void htc_8x60_register_icodec_ops(struct q6v2audio_icodec_ops *ops);
+#endif
diff --git a/arch/arm/mach-msm/include/mach/scm.h b/arch/arm/mach-msm/include/mach/scm.h
index 790430d985a..03f6cc81511 100644
--- a/arch/arm/mach-msm/include/mach/scm.h
+++ b/arch/arm/mach-msm/include/mach/scm.h
@@ -21,6 +21,7 @@
#define SCM_SVC_SSD 0x7
#define SCM_SVC_FUSE 0x8
#define SCM_SVC_PWR 0x9
+#define SCM_SVC_CP 0xC
#define SCM_SVC_TZSCHEDULER 0xFC
#define SCM_SVC_OEM 0xFE
diff --git a/arch/arm/mach-msm/include/mach/usb_bam.h b/arch/arm/mach-msm/include/mach/usb_bam.h
new file mode 100644
index 00000000000..4caa71bb3de
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/usb_bam.h
@@ -0,0 +1,40 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _USB_BAM_H_
+#define _USB_BAM_H_
+
+/**
+ * Connect USB-to-Periperal SPS connection.
+ *
+ * This function returns the allocated pipes number.
+ *
+ * @idx - Connection index.
+ *
+ * @src_pipe_idx - allocated pipe index - USB as a
+ * source (output)
+ *
+ * @dst_pipe_idx - allocated pipe index - USB as a
+ * destination (output)
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+#ifdef CONFIG_USB_BAM
+int usb_bam_connect(u8 idx, u8 *src_pipe_idx, u8 *dst_pipe_idx);
+#else
+int usb_bam_connect(u8 idx, u8 *src_pipe_idx, u8 *dst_pipe_idx)
+{
+ return -ENODEV;
+}
+#endif
+#endif /* _USB_BAM_H_ */
diff --git a/arch/arm/mach-msm/include/mach/usb_bridge.h b/arch/arm/mach-msm/include/mach/usb_bridge.h
new file mode 100644
index 00000000000..2b7e754b35c
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/usb_bridge.h
@@ -0,0 +1,122 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+#ifndef __LINUX_USB_BRIDGE_H__
+#define __LINUX_USB_BRIDGE_H__
+
+#include
+#include
+
+/* bridge device 0: DUN
+ * bridge device 1 : Tethered RMNET
+ */
+#define MAX_BRIDGE_DEVICES 2
+
+/*PID 9001*/
+#define DUN_IFACE_NUM 2
+#define TETHERED_RMNET_IFACE_NUM 3
+
+struct bridge_ops {
+ int (*send_pkt)(void *, void *, size_t actual);
+ void (*send_cbits)(void *, unsigned int);
+
+ /* flow control */
+ void (*unthrottle_tx)(void *);
+};
+
+#define TX_THROTTLED BIT(0)
+#define RX_THROTTLED BIT(1)
+
+struct bridge {
+ /* context of the gadget port using bridge driver */
+ void *ctx;
+
+ /* bridge device array index mapped to the gadget port array index.
+ * data bridge[ch_id] <-- bridge --> gadget port[ch_id]
+ */
+ unsigned int ch_id;
+
+ /* flow control bits */
+ unsigned long flags;
+
+ /* data/ctrl bridge callbacks */
+ struct bridge_ops ops;
+};
+
+#if defined(CONFIG_USB_QCOM_MDM_BRIDGE) || \
+ defined(CONFIG_USB_QCOM_MDM_BRIDGE_MODULE)
+
+/* Bridge APIs called by gadget driver */
+int ctrl_bridge_open(struct bridge *);
+void ctrl_bridge_close(unsigned int);
+int ctrl_bridge_write(unsigned int, char *, size_t);
+int ctrl_bridge_set_cbits(unsigned int, unsigned int);
+unsigned int ctrl_bridge_get_cbits_tohost(unsigned int);
+int data_bridge_open(struct bridge *brdg);
+void data_bridge_close(unsigned int);
+int data_bridge_write(unsigned int , struct sk_buff *);
+int data_bridge_unthrottle_rx(unsigned int);
+
+/* defined in control bridge */
+int ctrl_bridge_probe(struct usb_interface *, struct usb_host_endpoint *, int);
+void ctrl_bridge_disconnect(unsigned int);
+int ctrl_bridge_resume(unsigned int);
+int ctrl_bridge_suspend(unsigned int);
+
+#else
+
+static inline int __maybe_unused ctrl_bridge_open(struct bridge *brdg)
+{
+ return -ENODEV;
+}
+
+static inline void __maybe_unused ctrl_bridge_close(unsigned int id) { }
+
+static inline int __maybe_unused ctrl_bridge_write(unsigned int id,
+ char *data, size_t size)
+{
+ return -ENODEV;
+}
+
+static inline int __maybe_unused ctrl_bridge_set_cbits(unsigned int id,
+ unsigned int cbits)
+{
+ return -ENODEV;
+}
+
+static inline unsigned int __maybe_unused
+ctrl_bridge_get_cbits_tohost(unsigned int id)
+{
+ return -ENODEV;
+}
+
+static inline int __maybe_unused data_bridge_open(struct bridge *brdg)
+{
+ return -ENODEV;
+}
+
+static inline void __maybe_unused data_bridge_close(unsigned int id) { }
+
+static inline int __maybe_unused data_bridge_write(unsigned int id,
+ struct sk_buff *skb)
+{
+ return -ENODEV;
+}
+
+static inline int __maybe_unused data_bridge_unthrottle_rx(unsigned int id)
+{
+ return -ENODEV;
+}
+
+#endif
+#endif
diff --git a/arch/arm/mach-msm/include/mach/usb_gadget_xport.h b/arch/arm/mach-msm/include/mach/usb_gadget_xport.h
new file mode 100644
index 00000000000..d8a3e60f63d
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/usb_gadget_xport.h
@@ -0,0 +1,89 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __LINUX_USB_GADGET_XPORT_H__
+#define __LINUX_USB_GADGET_XPORT_H__
+
+enum transport_type {
+ USB_GADGET_XPORT_UNDEF,
+ USB_GADGET_XPORT_TTY,
+ USB_GADGET_XPORT_SDIO,
+ USB_GADGET_XPORT_SMD,
+ USB_GADGET_XPORT_BAM,
+ USB_GADGET_XPORT_BAM2BAM,
+ USB_GADGET_XPORT_HSIC,
+ USB_GADGET_XPORT_NONE,
+};
+
+#define XPORT_STR_LEN 10
+
+static char *xport_to_str(enum transport_type t)
+{
+ switch (t) {
+ case USB_GADGET_XPORT_TTY:
+ return "TTY";
+ case USB_GADGET_XPORT_SDIO:
+ return "SDIO";
+ case USB_GADGET_XPORT_SMD:
+ return "SMD";
+ case USB_GADGET_XPORT_BAM:
+ return "BAM";
+ case USB_GADGET_XPORT_BAM2BAM:
+ return "BAM2BAM";
+ case USB_GADGET_XPORT_HSIC:
+ return "HSIC";
+ case USB_GADGET_XPORT_NONE:
+ return "NONE";
+ default:
+ return "UNDEFINED";
+ }
+}
+
+static enum transport_type str_to_xport(const char *name)
+{
+ if (!strncasecmp("TTY", name, XPORT_STR_LEN))
+ return USB_GADGET_XPORT_TTY;
+ if (!strncasecmp("SDIO", name, XPORT_STR_LEN))
+ return USB_GADGET_XPORT_SDIO;
+ if (!strncasecmp("SMD", name, XPORT_STR_LEN))
+ return USB_GADGET_XPORT_SMD;
+ if (!strncasecmp("BAM", name, XPORT_STR_LEN))
+ return USB_GADGET_XPORT_BAM;
+ if (!strncasecmp("BAM2BAM", name, XPORT_STR_LEN))
+ return USB_GADGET_XPORT_BAM2BAM;
+ if (!strncasecmp("HSIC", name, XPORT_STR_LEN))
+ return USB_GADGET_XPORT_HSIC;
+ if (!strncasecmp("", name, XPORT_STR_LEN))
+ return USB_GADGET_XPORT_NONE;
+
+ return USB_GADGET_XPORT_UNDEF;
+}
+
+enum gadget_type {
+ USB_GADGET_SERIAL,
+ USB_GADGET_RMNET,
+};
+
+#define NUM_RMNET_HSIC_PORTS 1
+#define NUM_DUN_HSIC_PORTS 1
+#define NUM_PORTS (NUM_RMNET_HSIC_PORTS \
+ + NUM_DUN_HSIC_PORTS)
+
+int ghsic_ctrl_connect(void *, int);
+void ghsic_ctrl_disconnect(void *, int);
+int ghsic_ctrl_setup(unsigned int, enum gadget_type);
+int ghsic_data_connect(void *, int);
+void ghsic_data_disconnect(void *, int);
+int ghsic_data_setup(unsigned int, enum gadget_type);
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp6v3/Makefile b/arch/arm/mach-msm/qdsp6v3/Makefile
new file mode 100644
index 00000000000..a0aca30cf3c
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v3/Makefile
@@ -0,0 +1,15 @@
+obj-$(CONFIG_MSM8X60_RTAC) += rtac.o
+obj-y += audio_dev_ctl.o
+obj-y += board-msm8x60-audio.o
+obj-$(CONFIG_TIMPANI_CODEC) += snddev_icodec.o
+obj-y += snddev_ecodec.o snddev_mi2s.o snddev_virtual.o
+obj-y += apr.o apr_tal.o q6core.o dsp_debug.o
+obj-y += audio_acdb.o
+obj-y += q6asm.o q6adm.o q6afe.o
+obj-y += pcm_out.o pcm_in.o fm.o
+obj-y += audio_lpa.o
+obj-y += q6voice.o
+obj-y += snddev_hdmi.o
+obj-y += aac_in.o qcelp_in.o evrc_in.o amrnb_in.o audio_utils.o
+obj-y += audio_mvs.o
+obj-y += audio_wma.o audio_wmapro.o audio_aac.o
diff --git a/arch/arm/mach-msm/qdsp6v3/aac_in.c b/arch/arm/mach-msm/qdsp6v3/aac_in.c
new file mode 100644
index 00000000000..f01a1414ba2
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v3/aac_in.c
@@ -0,0 +1,435 @@
+/*
+ * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "audio_utils.h"
+
+
+/* Buffer with meta*/
+#define PCM_BUF_SIZE (4096 + sizeof(struct meta_in))
+
+/* Maximum 5 frames in buffer with meta */
+#define FRAME_SIZE (1 + ((1536+sizeof(struct meta_out_dsp)) * 5))
+
+#define AAC_FORMAT_ADTS 65535
+
+void q6asm_aac_in_cb(uint32_t opcode, uint32_t token,
+ uint32_t *payload, void *priv)
+{
+ struct q6audio_in * audio = (struct q6audio_in *)priv;
+ unsigned long flags;
+
+ pr_debug("%s:session id %d: opcode[0x%x]\n", __func__,
+ audio->ac->session, opcode);
+
+ spin_lock_irqsave(&audio->dsp_lock, flags);
+ switch (opcode) {
+ case ASM_DATA_EVENT_READ_DONE:
+ audio_in_get_dsp_frames(audio, token, payload);
+ break;
+ case ASM_DATA_EVENT_WRITE_DONE:
+ atomic_inc(&audio->in_count);
+ wake_up(&audio->write_wait);
+ break;
+ case ASM_DATA_CMDRSP_EOS:
+ audio->eos_rsp = 1;
+ wake_up(&audio->read_wait);
+ break;
+ case ASM_STREAM_CMDRSP_GET_ENCDEC_PARAM:
+ break;
+ case ASM_STREAM_CMDRSP_GET_PP_PARAMS:
+ break;
+ case ASM_SESSION_EVENT_TX_OVERFLOW:
+ pr_aud_err("%s:session id %d: ASM_SESSION_EVENT_TX_OVERFLOW\n",
+ __func__, audio->ac->session);
+ break;
+ default:
+ pr_aud_err("%s:session id %d: Ignore opcode[0x%x]\n", __func__,
+ audio->ac->session, opcode);
+ break;
+ }
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+/* ------------------- device --------------------- */
+static long aac_in_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_in *audio = file->private_data;
+ int rc = 0;
+ int cnt = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ struct msm_audio_aac_enc_config *enc_cfg;
+ struct msm_audio_aac_config *aac_config;
+ uint32_t aac_mode = AAC_ENC_MODE_AAC_LC;
+
+ enc_cfg = audio->enc_cfg;
+ aac_config = audio->codec_cfg;
+ /* ENCODE CFG (after new set of API's are published )bharath*/
+ pr_debug("%s:session id %d: default buf alloc[%d]\n", __func__,
+ audio->ac->session, audio->buf_alloc);
+ if (audio->enabled == 1) {
+ pr_aud_info("%s:AUDIO_START already over\n", __func__);
+ rc = 0;
+ break;
+ }
+
+ rc = audio_in_buf_alloc(audio);
+ if (rc < 0) {
+ pr_aud_err("%s:session id %d: buffer allocation failed\n",
+ __func__, audio->ac->session);
+ break;
+ }
+
+ pr_debug("%s:sbr_ps_flag = %d, sbr_flag = %d\n", __func__,
+ aac_config->sbr_ps_on_flag, aac_config->sbr_on_flag);
+ if (aac_config->sbr_ps_on_flag)
+ aac_mode = AAC_ENC_MODE_EAAC_P;
+ else if (aac_config->sbr_on_flag)
+ aac_mode = AAC_ENC_MODE_AAC_P;
+ else
+ aac_mode = AAC_ENC_MODE_AAC_LC;
+
+ rc = q6asm_enc_cfg_blk_aac(audio->ac,
+ audio->buf_cfg.frames_per_buf,
+ enc_cfg->sample_rate,
+ enc_cfg->channels,
+ enc_cfg->bit_rate,
+ aac_mode,
+ enc_cfg->stream_format);
+ if (rc < 0) {
+ pr_aud_err("%s:session id %d: cmd media format block\
+ failed\n", __func__, audio->ac->session);
+ break;
+ }
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ rc = q6asm_media_format_block_pcm(audio->ac,
+ audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count);
+ if (rc < 0) {
+ pr_aud_err("%s:session id %d: media format block\
+ failed\n", __func__, audio->ac->session);
+ break;
+ }
+ }
+ rc = audio_in_enable(audio);
+ if (!rc) {
+ audio->enabled = 1;
+ } else {
+ audio->enabled = 0;
+ pr_aud_err("%s:session id %d: Audio Start procedure\
+ failed rc=%d\n", __func__, audio->ac->session, rc);
+ break;
+ }
+ while (cnt++ < audio->str_cfg.buffer_count)
+ q6asm_read(audio->ac);
+ pr_debug("%s:session id %d: AUDIO_START success enable[%d]\n",
+ __func__, audio->ac->session, audio->enabled);
+ break;
+ }
+ case AUDIO_STOP: {
+ pr_debug("%s:session id %d: Rxed AUDIO_STOP\n", __func__,
+ audio->ac->session);
+ rc = audio_in_disable(audio);
+ if (rc < 0) {
+ pr_aud_err("%s:session id %d: Audio Stop procedure failed\
+ rc=%d\n", __func__, audio->ac->session, rc);
+ break;
+ }
+ break;
+ }
+ case AUDIO_GET_AAC_ENC_CONFIG: {
+ struct msm_audio_aac_enc_config cfg;
+ struct msm_audio_aac_enc_config *enc_cfg;
+ enc_cfg = audio->enc_cfg;
+ if (enc_cfg->channels == CH_MODE_MONO)
+ cfg.channels = 1;
+ else
+ cfg.channels = 2;
+ cfg.sample_rate = enc_cfg->sample_rate;
+ cfg.bit_rate = enc_cfg->bit_rate;
+ /* ADTS(-1) to ADTS(0x00), RAW(0x00) to RAW(0x03) */
+ cfg.stream_format = ((enc_cfg->stream_format == \
+ 0x00) ? AUDIO_AAC_FORMAT_ADTS : AUDIO_AAC_FORMAT_RAW);
+ pr_debug("%s:session id %d: Get-aac-cfg: format=%d sr=%d\
+ bitrate=%d\n", __func__, audio->ac->session,
+ cfg.stream_format, cfg.sample_rate, cfg.bit_rate);
+ if (copy_to_user((void *)arg, &cfg, sizeof(cfg)))
+ rc = -EFAULT;
+ break;
+ }
+ case AUDIO_SET_AAC_ENC_CONFIG: {
+ struct msm_audio_aac_enc_config cfg;
+ struct msm_audio_aac_enc_config *enc_cfg;
+ enc_cfg = audio->enc_cfg;
+ if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
+ rc = -EFAULT;
+ break;
+ }
+ pr_debug("%s:session id %d: Set-aac-cfg: stream=%d\n", __func__,
+ audio->ac->session, cfg.stream_format);
+
+ if ((cfg.stream_format != AUDIO_AAC_FORMAT_RAW) &&
+ (cfg.stream_format != AAC_FORMAT_ADTS)) {
+ pr_aud_err("%s:session id %d: unsupported AAC format\n",
+ __func__, audio->ac->session);
+ rc = -EINVAL;
+ break;
+ }
+
+ if (cfg.channels == 1) {
+ cfg.channels = CH_MODE_MONO;
+ } else if (cfg.channels == 2) {
+ cfg.channels = CH_MODE_STEREO;
+ } else {
+ rc = -EINVAL;
+ break;
+ }
+ if ((cfg.sample_rate < 8000) && (cfg.sample_rate > 48000)) {
+ pr_aud_err("%s: ERROR in setting samplerate = %d\n",
+ __func__, cfg.sample_rate);
+ rc = -EINVAL;
+ break;
+ }
+ enc_cfg->sample_rate = cfg.sample_rate;
+ enc_cfg->channels = cfg.channels;
+ enc_cfg->bit_rate = cfg.bit_rate;
+ enc_cfg->stream_format =
+ ((cfg.stream_format == AUDIO_AAC_FORMAT_RAW) ? \
+ 0x03 : 0x00);
+ pr_debug("%s:session id %d: Set-aac-cfg:SR= 0x%x ch=0x%x\
+ bitrate=0x%x, format(adts/raw) = %d\n",
+ __func__, audio->ac->session, enc_cfg->sample_rate,
+ enc_cfg->channels, enc_cfg->bit_rate,
+ enc_cfg->stream_format);
+ break;
+ }
+ case AUDIO_GET_AAC_CONFIG: {
+ if (copy_to_user((void *)arg, &audio->codec_cfg,
+ sizeof(struct msm_audio_aac_config))) {
+ rc = -EFAULT;
+ break;
+ }
+ break;
+ }
+ case AUDIO_SET_AAC_CONFIG: {
+ struct msm_audio_aac_config aac_cfg;
+ struct msm_audio_aac_config *audio_aac_cfg;
+ struct msm_audio_aac_enc_config *enc_cfg;
+ enc_cfg = audio->enc_cfg;
+ audio_aac_cfg = audio->codec_cfg;
+
+ if (copy_from_user(&aac_cfg, (void *)arg,
+ sizeof(struct msm_audio_aac_config))) {
+ rc = -EFAULT;
+ break;
+ }
+ pr_debug("%s:session id %d: AUDIO_SET_AAC_CONFIG: sbr_flag = %d"
+ " sbr_ps_flag = %d\n", __func__,
+ audio->ac->session, aac_cfg.sbr_on_flag,
+ aac_cfg.sbr_ps_on_flag);
+ audio_aac_cfg->sbr_on_flag = aac_cfg.sbr_on_flag;
+ audio_aac_cfg->sbr_ps_on_flag = aac_cfg.sbr_ps_on_flag;
+ if ((audio_aac_cfg->sbr_on_flag == 1) ||
+ (audio_aac_cfg->sbr_ps_on_flag == 1)) {
+ if (enc_cfg->sample_rate < 24000) {
+ pr_aud_err("%s: ERROR in setting samplerate = %d"
+ "\n", __func__, enc_cfg->sample_rate);
+ rc = -EINVAL;
+ break;
+ }
+ }
+ break;
+ }
+ default:
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+static int aac_in_open(struct inode *inode, struct file *file)
+{
+ struct q6audio_in *audio = NULL;
+ struct msm_audio_aac_enc_config *enc_cfg;
+ struct msm_audio_aac_config *aac_config;
+ int rc = 0;
+
+ audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL);
+
+ if (audio == NULL) {
+ pr_aud_err("%s:Could not allocate memory for aac\
+ driver\n", __func__);
+ return -ENOMEM;
+ }
+ /* Allocate memory for encoder config param */
+ audio->enc_cfg = kzalloc(sizeof(struct msm_audio_aac_enc_config),
+ GFP_KERNEL);
+ if (audio->enc_cfg == NULL) {
+ pr_aud_err("%s:session id %d: Could not allocate memory for aac\
+ config param\n", __func__, audio->ac->session);
+ kfree(audio);
+ return -ENOMEM;
+ }
+ enc_cfg = audio->enc_cfg;
+
+ audio->codec_cfg = kzalloc(sizeof(struct msm_audio_aac_config),
+ GFP_KERNEL);
+ if (audio->codec_cfg == NULL) {
+ pr_aud_err("%s:session id %d: Could not allocate memory for aac\
+ config\n", __func__, audio->ac->session);
+ kfree(audio->enc_cfg);
+ kfree(audio);
+ return -ENOMEM;
+ }
+ aac_config = audio->codec_cfg;
+
+ mutex_init(&audio->lock);
+ mutex_init(&audio->read_lock);
+ mutex_init(&audio->write_lock);
+ spin_lock_init(&audio->dsp_lock);
+ init_waitqueue_head(&audio->read_wait);
+ init_waitqueue_head(&audio->write_wait);
+
+ /* Settings will be re-config at AUDIO_SET_CONFIG,
+ * but at least we need to have initial config
+ */
+ audio->str_cfg.buffer_size = FRAME_SIZE;
+ audio->str_cfg.buffer_count = FRAME_NUM;
+ audio->min_frame_size = 1536;
+ audio->max_frames_per_buf = 5;
+ enc_cfg->sample_rate = 8000;
+ enc_cfg->channels = 1;
+ enc_cfg->bit_rate = 16000;
+ enc_cfg->stream_format = 0x00;/* 0:ADTS, 3:RAW */
+ audio->buf_cfg.meta_info_enable = 0x01;
+ audio->buf_cfg.frames_per_buf = 0x01;
+ audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
+ audio->pcm_cfg.buffer_size = PCM_BUF_SIZE;
+ aac_config->format = AUDIO_AAC_FORMAT_ADTS;
+ aac_config->audio_object = AUDIO_AAC_OBJECT_LC;
+ aac_config->sbr_on_flag = 0;
+ aac_config->sbr_ps_on_flag = 0;
+ aac_config->channel_configuration = 1;
+
+ audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_aac_in_cb,
+ (void *)audio);
+
+ if (!audio->ac) {
+ pr_aud_err("%s: Could not allocate memory for\
+ audio client\n", __func__);
+ kfree(audio->enc_cfg);
+ kfree(audio->codec_cfg);
+ kfree(audio);
+ return -ENOMEM;
+ }
+ /* open aac encoder in tunnel mode */
+ audio->buf_cfg.frames_per_buf = 0x01;
+
+ if ((file->f_mode & FMODE_WRITE) &&
+ (file->f_mode & FMODE_READ)) {
+ audio->feedback = NON_TUNNEL_MODE;
+ rc = q6asm_open_read_write(audio->ac, FORMAT_MPEG4_AAC,
+ FORMAT_LINEAR_PCM);
+
+ if (rc < 0) {
+ pr_aud_err("%s:session id %d: NT Open failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->buf_cfg.meta_info_enable = 0x01;
+ pr_aud_info("%s:session id %d: NT mode encoder success\n", __func__,
+ audio->ac->session);
+ } else if (!(file->f_mode & FMODE_WRITE) &&
+ (file->f_mode & FMODE_READ)) {
+ audio->feedback = TUNNEL_MODE;
+ rc = q6asm_open_read(audio->ac, FORMAT_MPEG4_AAC);
+
+ if (rc < 0) {
+ pr_aud_err("%s:session id %d: Tunnel Open failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ /* register for tx overflow (valid for tunnel mode only) */
+ rc = q6asm_reg_tx_overflow(audio->ac, 0x01);
+ if (rc < 0) {
+ pr_aud_err("%s:session id %d: TX Overflow registration\
+ failed rc=%d\n", __func__,
+ audio->ac->session, rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->buf_cfg.meta_info_enable = 0x00;
+ pr_aud_info("%s:session id %d: T mode encoder success\n", __func__,
+ audio->ac->session);
+ } else {
+ pr_aud_err("%s:session id %d: Unexpected mode\n", __func__,
+ audio->ac->session);
+ rc = -EACCES;
+ goto fail;
+ }
+ audio->opened = 1;
+ atomic_set(&audio->in_count, PCM_BUF_COUNT);
+ atomic_set(&audio->out_count, 0x00);
+ audio->enc_ioctl = aac_in_ioctl;
+ file->private_data = audio;
+
+ pr_aud_info("%s:session id %d: success\n", __func__, audio->ac->session);
+ return 0;
+fail:
+ q6asm_audio_client_free(audio->ac);
+ kfree(audio->enc_cfg);
+ kfree(audio->codec_cfg);
+ kfree(audio);
+ return rc;
+}
+
+static const struct file_operations audio_in_fops = {
+ .owner = THIS_MODULE,
+ .open = aac_in_open,
+ .release = audio_in_release,
+ .read = audio_in_read,
+ .write = audio_in_write,
+ .unlocked_ioctl = audio_in_ioctl,
+};
+
+struct miscdevice audio_aac_in_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_aac_in",
+ .fops = &audio_in_fops,
+};
+
+static int __init aac_in_init(void)
+{
+ return misc_register(&audio_aac_in_misc);
+}
+device_initcall(aac_in_init);
diff --git a/arch/arm/mach-msm/qdsp6v3/amrnb_in.c b/arch/arm/mach-msm/qdsp6v3/amrnb_in.c
new file mode 100644
index 00000000000..35984c38ef5
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v3/amrnb_in.c
@@ -0,0 +1,330 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+*/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "audio_utils.h"
+
+/* Buffer with meta*/
+#define PCM_BUF_SIZE (4096 + sizeof(struct meta_in))
+
+/* Maximum 10 frames in buffer with meta */
+#define FRAME_SIZE (1 + ((32+sizeof(struct meta_out_dsp)) * 10))
+
+void q6asm_amrnb_in_cb(uint32_t opcode, uint32_t token,
+ uint32_t *payload, void *priv)
+{
+ struct q6audio_in * audio = (struct q6audio_in *)priv;
+ unsigned long flags;
+
+ pr_debug("%s:session id %d: opcode - %d\n", __func__,
+ audio->ac->session, opcode);
+
+ spin_lock_irqsave(&audio->dsp_lock, flags);
+ switch (opcode) {
+ case ASM_DATA_EVENT_READ_DONE:
+ audio_in_get_dsp_frames(audio, token, payload);
+ break;
+ case ASM_DATA_EVENT_WRITE_DONE:
+ atomic_inc(&audio->in_count);
+ wake_up(&audio->write_wait);
+ break;
+ case ASM_DATA_CMDRSP_EOS:
+ audio->eos_rsp = 1;
+ wake_up(&audio->read_wait);
+ break;
+ case ASM_STREAM_CMDRSP_GET_ENCDEC_PARAM:
+ break;
+ case ASM_STREAM_CMDRSP_GET_PP_PARAMS:
+ break;
+ case ASM_SESSION_EVENT_TX_OVERFLOW:
+ pr_aud_err("%s:session id %d: ASM_SESSION_EVENT_TX_OVERFLOW\n",
+ __func__, audio->ac->session);
+ break;
+ default:
+ pr_aud_err("%s:session id %d: Ignore opcode[0x%x]\n", __func__,
+ audio->ac->session, opcode);
+ break;
+ }
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+/* ------------------- device --------------------- */
+static long amrnb_in_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_in *audio = file->private_data;
+ int rc = 0;
+ int cnt = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ struct msm_audio_amrnb_enc_config_v2 *enc_cfg;
+ enc_cfg = audio->enc_cfg;
+ pr_debug("%s:session id %d: default buf alloc[%d]\n", __func__,
+ audio->ac->session, audio->buf_alloc);
+ if (audio->enabled == 1) {
+ pr_aud_info("%s:AUDIO_START already over\n", __func__);
+ rc = 0;
+ break;
+ }
+ rc = audio_in_buf_alloc(audio);
+ if (rc < 0) {
+ pr_aud_err("%s:session id %d: buffer allocation failed\n",
+ __func__, audio->ac->session);
+ break;
+ }
+
+ rc = q6asm_enc_cfg_blk_amrnb(audio->ac,
+ audio->buf_cfg.frames_per_buf,
+ enc_cfg->band_mode,
+ enc_cfg->dtx_enable);
+
+ if (rc < 0) {
+ pr_aud_err("%s:session id %d: cmd amrnb media format block\
+ failed\n", __func__, audio->ac->session);
+ break;
+ }
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ rc = q6asm_media_format_block_pcm(audio->ac,
+ audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count);
+
+ if (rc < 0) {
+ pr_aud_err("%s:session id %d: media format block\
+ failed\n", __func__, audio->ac->session);
+ break;
+ }
+ }
+ pr_debug("%s:session id %d: AUDIO_START enable[%d]\n",
+ __func__, audio->ac->session,
+ audio->enabled);
+ rc = audio_in_enable(audio);
+ if (!rc) {
+ audio->enabled = 1;
+ } else {
+ audio->enabled = 0;
+ pr_aud_err("%s:session id %d: Audio Start procedure failed\
+ rc=%d\n", __func__,
+ audio->ac->session, rc);
+ break;
+ }
+ while (cnt++ < audio->str_cfg.buffer_count)
+ q6asm_read(audio->ac); /* Push buffer to DSP */
+ rc = 0;
+ pr_debug("%s:session id %d: AUDIO_START success enable[%d]\n",
+ __func__, audio->ac->session, audio->enabled);
+ break;
+ }
+ case AUDIO_STOP: {
+ pr_debug("%s:AUDIO_STOP\n", __func__);
+ rc = audio_in_disable(audio);
+ if (rc < 0) {
+ pr_aud_err("%s:session id %d: Audio Stop procedure failed\
+ rc=%d\n", __func__,
+ audio->ac->session, rc);
+ break;
+ }
+ break;
+ }
+ case AUDIO_GET_AMRNB_ENC_CONFIG_V2: {
+ if (copy_to_user((void *)arg, audio->enc_cfg,
+ sizeof(struct msm_audio_amrnb_enc_config_v2)))
+ rc = -EFAULT;
+ break;
+ }
+ case AUDIO_SET_AMRNB_ENC_CONFIG_V2: {
+ struct msm_audio_amrnb_enc_config_v2 cfg;
+ struct msm_audio_amrnb_enc_config_v2 *enc_cfg;
+ enc_cfg = audio->enc_cfg;
+ if (copy_from_user(&cfg, (void *) arg,
+ sizeof(struct msm_audio_amrnb_enc_config_v2))) {
+ rc = -EFAULT;
+ break;
+ }
+ if (cfg.band_mode > 8 ||
+ cfg.band_mode < 1) {
+ pr_aud_err("%s:session id %d: invalid band mode\n",
+ __func__, audio->ac->session);
+ rc = -EINVAL;
+ break;
+ }
+ /* AMR NB encoder accepts values between 0-7
+ while openmax provides value between 1-8
+ as per spec */
+ enc_cfg->band_mode = (cfg.band_mode - 1);
+ enc_cfg->dtx_enable = (cfg.dtx_enable ? 1 : 0);
+ enc_cfg->frame_format = 0;
+ pr_debug("%s:session id %d: band_mode = 0x%x dtx_enable=0x%x\n",
+ __func__, audio->ac->session,
+ enc_cfg->band_mode, enc_cfg->dtx_enable);
+ break;
+ }
+ default:
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+static int amrnb_in_open(struct inode *inode, struct file *file)
+{
+ struct q6audio_in *audio = NULL;
+ struct msm_audio_amrnb_enc_config_v2 *enc_cfg;
+ int rc = 0;
+
+ audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL);
+
+ if (audio == NULL) {
+ pr_aud_err("%s:session id %d: Could not allocate memory for amrnb\
+ driver\n", __func__, audio->ac->session);
+ return -ENOMEM;
+ }
+ /* Allocate memory for encoder config param */
+ audio->enc_cfg = kzalloc(sizeof(struct msm_audio_amrnb_enc_config_v2),
+ GFP_KERNEL);
+ if (audio->enc_cfg == NULL) {
+ pr_aud_err("%s:session id %d: Could not allocate memory for aac\
+ config param\n", __func__, audio->ac->session);
+ kfree(audio);
+ return -ENOMEM;
+ }
+ enc_cfg = audio->enc_cfg;
+
+ mutex_init(&audio->lock);
+ mutex_init(&audio->read_lock);
+ mutex_init(&audio->write_lock);
+ spin_lock_init(&audio->dsp_lock);
+ init_waitqueue_head(&audio->read_wait);
+ init_waitqueue_head(&audio->write_wait);
+
+ /* Settings will be re-config at AUDIO_SET_CONFIG,
+ * but at least we need to have initial config
+ */
+ audio->str_cfg.buffer_size = FRAME_SIZE;
+ audio->str_cfg.buffer_count = FRAME_NUM;
+ audio->min_frame_size = 32;
+ audio->max_frames_per_buf = 10;
+ audio->pcm_cfg.buffer_size = PCM_BUF_SIZE;
+ audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
+ enc_cfg->band_mode = 7;
+ enc_cfg->dtx_enable = 0;
+ audio->pcm_cfg.channel_count = 1;
+ audio->pcm_cfg.sample_rate = 8000;
+ audio->buf_cfg.meta_info_enable = 0x01;
+ audio->buf_cfg.frames_per_buf = 0x01;
+
+ audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_amrnb_in_cb,
+ (void *)audio);
+
+ if (!audio->ac) {
+ pr_aud_err("%s:session id %d: Could not allocate memory for audio\
+ client\n", __func__, audio->ac->session);
+ kfree(audio->enc_cfg);
+ kfree(audio);
+ return -ENOMEM;
+ }
+
+ /* open amrnb encoder in T/NT mode */
+ if ((file->f_mode & FMODE_WRITE) &&
+ (file->f_mode & FMODE_READ)) {
+ audio->feedback = NON_TUNNEL_MODE;
+ rc = q6asm_open_read_write(audio->ac, FORMAT_AMRNB,
+ FORMAT_LINEAR_PCM);
+ if (rc < 0) {
+ pr_aud_err("%s:session id %d: NT mode Open failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ pr_aud_info("%s:session id %d: NT mode encoder success\n",
+ __func__, audio->ac->session);
+ } else if (!(file->f_mode & FMODE_WRITE) &&
+ (file->f_mode & FMODE_READ)) {
+ audio->feedback = TUNNEL_MODE;
+ rc = q6asm_open_read(audio->ac, FORMAT_AMRNB);
+ if (rc < 0) {
+ pr_aud_err("%s:session id %d: T mode Open failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ /* register for tx overflow (valid for tunnel mode only) */
+ rc = q6asm_reg_tx_overflow(audio->ac, 0x01);
+ if (rc < 0) {
+ pr_aud_err("%s:session id %d: TX Overflow registration\
+ failed rc=%d\n", __func__, audio->ac->session,
+ rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ pr_aud_info("%s:session id %d: T mode encoder success\n",
+ __func__, audio->ac->session);
+ } else {
+ pr_aud_err("%s:session id %d: Unexpected mode\n", __func__,
+ audio->ac->session);
+ rc = -EACCES;
+ goto fail;
+ }
+
+ audio->opened = 1;
+ atomic_set(&audio->in_count, PCM_BUF_COUNT);
+ atomic_set(&audio->out_count, 0x00);
+ audio->enc_ioctl = amrnb_in_ioctl;
+ file->private_data = audio;
+
+ pr_aud_info("%s:session id %d: success\n", __func__, audio->ac->session);
+ return 0;
+fail:
+ q6asm_audio_client_free(audio->ac);
+ kfree(audio->enc_cfg);
+ kfree(audio);
+ return rc;
+}
+
+static const struct file_operations audio_in_fops = {
+ .owner = THIS_MODULE,
+ .open = amrnb_in_open,
+ .release = audio_in_release,
+ .read = audio_in_read,
+ .write = audio_in_write,
+ .unlocked_ioctl = audio_in_ioctl,
+};
+
+struct miscdevice audio_amrnb_in_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_amrnb_in",
+ .fops = &audio_in_fops,
+};
+
+static int __init amrnb_in_init(void)
+{
+ return misc_register(&audio_amrnb_in_misc);
+}
+
+device_initcall(amrnb_in_init);
diff --git a/arch/arm/mach-msm/qdsp6v3/apr.c b/arch/arm/mach-msm/qdsp6v3/apr.c
new file mode 100644
index 00000000000..8ee12c576ab
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v3/apr.c
@@ -0,0 +1,681 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "apr_tal.h"
+#include "dsp_debug.h"
+
+struct apr_q6 q6;
+struct apr_client client[APR_DEST_MAX][APR_CLIENT_MAX];
+static atomic_t dsp_state;
+static atomic_t modem_state;
+
+static wait_queue_head_t dsp_wait;
+static wait_queue_head_t modem_wait;
+/* Subsystem restart: QDSP6 data, functions */
+static struct workqueue_struct *apr_reset_workqueue;
+static void apr_reset_deregister(struct work_struct *work);
+struct apr_reset_work {
+ void *handle;
+ struct work_struct work;
+};
+
+
+int apr_send_pkt(void *handle, uint32_t *buf)
+{
+ struct apr_svc *svc = handle;
+ struct apr_client *clnt;
+ struct apr_hdr *hdr;
+ uint16_t dest_id;
+ uint16_t client_id;
+ uint16_t w_len;
+ unsigned long flags;
+
+ if (!handle || !buf) {
+ pr_aud_err("APR: Wrong parameters\n");
+ return -EINVAL;
+ }
+ if (svc->need_reset) {
+ pr_aud_err("apr: send_pkt service need reset\n");
+ return -ENETRESET;
+ }
+
+ if ((svc->dest_id == APR_DEST_QDSP6) &&
+ (atomic_read(&dsp_state) == 0)) {
+ pr_aud_err("apr: Still dsp is not Up\n");
+ return -ENETRESET;
+ } else if ((svc->dest_id == APR_DEST_MODEM) &&
+ (atomic_read(&modem_state) == 0)) {
+ pr_aud_err("apr: Still Modem is not Up\n");
+ return -ENETRESET;
+ }
+
+
+ spin_lock_irqsave(&svc->w_lock, flags);
+ dest_id = svc->dest_id;
+ client_id = svc->client_id;
+ clnt = &client[dest_id][client_id];
+
+ if (!client[dest_id][client_id].handle) {
+ pr_aud_err("APR: Still service is not yet opened\n");
+ spin_unlock_irqrestore(&svc->w_lock, flags);
+ return -EINVAL;
+ }
+ hdr = (struct apr_hdr *)buf;
+
+ hdr->src_domain = APR_DOMAIN_APPS;
+ hdr->src_svc = svc->id;
+ if (dest_id == APR_DEST_MODEM)
+ hdr->dest_domain = APR_DOMAIN_MODEM;
+ else if (dest_id == APR_DEST_QDSP6)
+ hdr->dest_domain = APR_DOMAIN_ADSP;
+
+ hdr->dest_svc = svc->id;
+
+ w_len = apr_tal_write(clnt->handle, buf, hdr->pkt_size);
+ if (w_len != hdr->pkt_size)
+ pr_aud_err("Unable to write APR pkt successfully: %d\n", w_len);
+ spin_unlock_irqrestore(&svc->w_lock, flags);
+
+ return w_len;
+}
+
+static void apr_cb_func(void *buf, int len, void *priv)
+{
+ struct apr_client_data data;
+ struct apr_client *apr_client;
+ struct apr_svc *c_svc;
+ struct apr_hdr *hdr;
+ uint16_t hdr_size;
+ uint16_t msg_type;
+ uint16_t ver;
+ uint16_t src;
+ uint16_t svc;
+ uint16_t clnt;
+ int i;
+ int temp_port = 0;
+ uint32_t *ptr;
+
+ pr_debug("APR2: len = %d\n", len);
+ ptr = buf;
+ pr_debug("\n*****************\n");
+ for (i = 0; i < len/4; i++)
+ pr_debug("%x ", ptr[i]);
+ pr_debug("\n");
+ pr_debug("\n*****************\n");
+
+ if (!buf || len <= APR_HDR_SIZE) {
+ pr_aud_err("APR: Improper apr pkt received:%p %d\n",
+ buf, len);
+ return;
+ }
+ hdr = buf;
+
+ ver = hdr->hdr_field;
+ ver = (ver & 0x000F);
+ if (ver > APR_PKT_VER + 1) {
+ pr_aud_err("APR: Wrong version: %d\n", ver);
+ return;
+ }
+
+ hdr_size = hdr->hdr_field;
+ hdr_size = ((hdr_size & 0x00F0) >> 0x4) * 4;
+ if (hdr_size < APR_HDR_SIZE) {
+ pr_aud_err("APR: Wrong hdr size:%d\n", hdr_size);
+ return;
+ }
+
+ if (hdr->pkt_size < APR_HDR_SIZE) {
+ pr_aud_err("APR: Wrong paket size\n");
+ return;
+ }
+ msg_type = hdr->hdr_field;
+ msg_type = (msg_type >> 0x08) & 0x0003;
+ if (msg_type >= APR_MSG_TYPE_MAX &&
+ msg_type != APR_BASIC_RSP_RESULT) {
+ pr_aud_err("APR: Wrong message type: %d\n", msg_type);
+ return;
+ }
+
+ if (hdr->src_domain >= APR_DOMAIN_MAX ||
+ hdr->dest_domain >= APR_DOMAIN_MAX ||
+ hdr->src_svc >= APR_SVC_MAX ||
+ hdr->dest_svc >= APR_SVC_MAX) {
+ pr_aud_err("APR: Wrong APR header\n");
+ return;
+ }
+
+ svc = hdr->dest_svc;
+ if (hdr->src_domain == APR_DOMAIN_MODEM) {
+ src = APR_DEST_MODEM;
+ if (svc == APR_SVC_MVS || svc == APR_SVC_MVM ||
+ svc == APR_SVC_CVS || svc == APR_SVC_CVP ||
+ svc == APR_SVC_TEST_CLIENT)
+ clnt = APR_CLIENT_VOICE;
+ else {
+ pr_aud_err("APR: Wrong svc :%d\n", svc);
+ return;
+ }
+ } else if (hdr->src_domain == APR_DOMAIN_ADSP) {
+ src = APR_DEST_QDSP6;
+ if (svc == APR_SVC_AFE || svc == APR_SVC_ASM ||
+ svc == APR_SVC_VSM || svc == APR_SVC_VPM ||
+ svc == APR_SVC_ADM || svc == APR_SVC_ADSP_CORE ||
+ svc == APR_SVC_TEST_CLIENT || svc == APR_SVC_ADSP_MVM ||
+ svc == APR_SVC_ADSP_CVS || svc == APR_SVC_ADSP_CVP)
+ clnt = APR_CLIENT_AUDIO;
+ else {
+ pr_aud_err("APR: Wrong svc :%d\n", svc);
+ return;
+ }
+ } else {
+ pr_aud_err("APR: Pkt from wrong source: %d\n", hdr->src_domain);
+ return;
+ }
+
+ pr_debug("src =%d clnt = %d\n", src, clnt);
+ apr_client = &client[src][clnt];
+ for (i = 0; i < APR_SVC_MAX; i++)
+ if (apr_client->svc[i].id == svc) {
+ pr_debug("%d\n", apr_client->svc[i].id);
+ c_svc = &apr_client->svc[i];
+ break;
+ }
+
+ if (i == APR_SVC_MAX) {
+ pr_aud_err("APR: service is not registered\n");
+ return;
+ }
+ pr_debug("svc_idx = %d\n", i);
+ pr_debug("%x %x %x %p %p\n", c_svc->id, c_svc->dest_id,
+ c_svc->client_id, c_svc->fn, c_svc->priv);
+ data.payload_size = hdr->pkt_size - hdr_size;
+ data.opcode = hdr->opcode;
+ data.src = src;
+ data.src_port = hdr->src_port;
+ data.dest_port = hdr->dest_port;
+ data.token = hdr->token;
+ data.msg_type = msg_type;
+ if (data.payload_size > 0)
+ data.payload = (char *)hdr + hdr_size;
+
+ temp_port = ((data.src_port >> 8) * 8) + (data.src_port & 0xFF);
+ pr_debug("port = %d t_port = %d\n", data.src_port, temp_port);
+ if (c_svc->port_cnt && c_svc->port_fn[temp_port])
+ c_svc->port_fn[temp_port](&data, c_svc->port_priv[temp_port]);
+ else if (c_svc->fn)
+ c_svc->fn(&data, c_svc->priv);
+ else
+ pr_aud_err("APR: Rxed a packet for NULL callback\n");
+}
+
+struct apr_svc *apr_register(char *dest, char *svc_name, apr_fn svc_fn,
+ uint32_t src_port, void *priv)
+{
+ int client_id = 0;
+ int svc_idx = 0;
+ int svc_id = 0;
+ int dest_id = 0;
+ int temp_port = 0;
+ struct apr_svc *svc = NULL;
+ int rc = 0;
+
+ if (!dest || !svc_name || !svc_fn)
+ return NULL;
+
+ if (!strcmp(dest, "ADSP"))
+ dest_id = APR_DEST_QDSP6;
+ else if (!strcmp(dest, "MODEM")) {
+ dest_id = APR_DEST_MODEM;
+ } else {
+ pr_aud_err("APR: wrong destination\n");
+ goto done;
+ }
+
+ if ((dest_id == APR_DEST_QDSP6) &&
+ (atomic_read(&dsp_state) == 0)) {
+ rc = wait_event_timeout(dsp_wait,
+ (atomic_read(&dsp_state) == 1), 5*HZ);
+ if (rc == 0) {
+ pr_aud_err("apr: Still dsp is not Up\n");
+ return NULL;
+ }
+ } else if ((dest_id == APR_DEST_MODEM) &&
+ (atomic_read(&modem_state) == 0)) {
+ rc = wait_event_timeout(modem_wait,
+ (atomic_read(&modem_state) == 1), 5*HZ);
+ if (rc == 0) {
+ pr_aud_err("apr: Still Modem is not Up\n");
+ return NULL;
+ }
+ }
+
+ if (!strcmp(svc_name, "AFE")) {
+ client_id = APR_CLIENT_AUDIO;
+ svc_idx = 0;
+ svc_id = APR_SVC_AFE;
+ } else if (!strcmp(svc_name, "ASM")) {
+ client_id = APR_CLIENT_AUDIO;
+ svc_idx = 1;
+ svc_id = APR_SVC_ASM;
+ } else if (!strcmp(svc_name, "ADM")) {
+ client_id = APR_CLIENT_AUDIO;
+ svc_idx = 2;
+ svc_id = APR_SVC_ADM;
+ } else if (!strcmp(svc_name, "CORE")) {
+ client_id = APR_CLIENT_AUDIO;
+ svc_idx = 3;
+ svc_id = APR_SVC_ADSP_CORE;
+ } else if (!strcmp(svc_name, "TEST")) {
+ if (dest_id == APR_DEST_QDSP6) {
+ client_id = APR_CLIENT_AUDIO;
+ svc_idx = 4;
+ } else {
+ client_id = APR_CLIENT_VOICE;
+ svc_idx = 7;
+ }
+ svc_id = APR_SVC_TEST_CLIENT;
+ } else if (!strcmp(svc_name, "VSM")) {
+ client_id = APR_CLIENT_VOICE;
+ svc_idx = 0;
+ svc_id = APR_SVC_VSM;
+ } else if (!strcmp(svc_name, "VPM")) {
+ client_id = APR_CLIENT_VOICE;
+ svc_idx = 1;
+ svc_id = APR_SVC_VPM;
+ } else if (!strcmp(svc_name, "MVS")) {
+ client_id = APR_CLIENT_VOICE;
+ svc_idx = 2;
+ svc_id = APR_SVC_MVS;
+ } else if (!strcmp(svc_name, "MVM")) {
+ if (dest_id == APR_DEST_MODEM) {
+ client_id = APR_CLIENT_VOICE;
+ svc_idx = 3;
+ svc_id = APR_SVC_MVM;
+ } else {
+ client_id = APR_CLIENT_AUDIO;
+ svc_idx = 5;
+ svc_id = APR_SVC_ADSP_MVM;
+ }
+ } else if (!strcmp(svc_name, "CVS")) {
+ if (dest_id == APR_DEST_MODEM) {
+ client_id = APR_CLIENT_VOICE;
+ svc_idx = 4;
+ svc_id = APR_SVC_CVS;
+ } else {
+ client_id = APR_CLIENT_AUDIO;
+ svc_idx = 6;
+ svc_id = APR_SVC_ADSP_CVS;
+ }
+ } else if (!strcmp(svc_name, "CVP")) {
+ if (dest_id == APR_DEST_MODEM) {
+ client_id = APR_CLIENT_VOICE;
+ svc_idx = 5;
+ svc_id = APR_SVC_CVP;
+ } else {
+ client_id = APR_CLIENT_AUDIO;
+ svc_idx = 7;
+ svc_id = APR_SVC_ADSP_CVP;
+ }
+ } else if (!strcmp(svc_name, "SRD")) {
+ client_id = APR_CLIENT_VOICE;
+ svc_idx = 6;
+ svc_id = APR_SVC_SRD;
+ } else {
+ pr_aud_err("APR: Wrong svc name\n");
+ goto done;
+ }
+
+ pr_debug("svc name = %s c_id = %d dest_id = %d\n",
+ svc_name, client_id, dest_id);
+ mutex_lock(&q6.lock);
+ if (q6.state == APR_Q6_NOIMG) {
+ q6.pil = pil_get("q6");
+ if (!q6.pil) {
+ pr_aud_err("APR: Unable to load q6 image\n");
+ mutex_unlock(&q6.lock);
+ return svc;
+ }
+ q6.state = APR_Q6_LOADED;
+ }
+ mutex_unlock(&q6.lock);
+ mutex_lock(&client[dest_id][client_id].m_lock);
+ if (!client[dest_id][client_id].handle) {
+ client[dest_id][client_id].handle = apr_tal_open(client_id,
+ dest_id, APR_DL_SMD, apr_cb_func, NULL);
+ if (!client[dest_id][client_id].handle) {
+ svc = NULL;
+ pr_aud_err("APR: Unable to open handle\n");
+ mutex_unlock(&client[dest_id][client_id].m_lock);
+ goto done;
+ }
+ }
+ mutex_unlock(&client[dest_id][client_id].m_lock);
+ svc = &client[dest_id][client_id].svc[svc_idx];
+ mutex_lock(&svc->m_lock);
+ client[dest_id][client_id].id = client_id;
+ if (svc->need_reset) {
+ mutex_unlock(&svc->m_lock);
+ pr_aud_err("APR: Service needs reset\n");
+ goto done;
+ }
+ svc->priv = priv;
+ svc->id = svc_id;
+ svc->dest_id = dest_id;
+ svc->client_id = client_id;
+ if (src_port != 0xFFFFFFFF) {
+ temp_port = ((src_port >> 8) * 8) + (src_port & 0xFF);
+ if (temp_port >= APR_MAX_PORTS) {
+ mutex_unlock(&svc->m_lock);
+ pr_aud_err("APR: illegal port ID %d\n", temp_port);
+ svc = NULL;
+ goto done;
+ }
+ pr_debug("port = %d t_port = %d\n", src_port, temp_port);
+ if (!svc->port_cnt && !svc->svc_cnt)
+ client[dest_id][client_id].svc_cnt++;
+ svc->port_cnt++;
+ svc->port_fn[temp_port] = svc_fn;
+ svc->port_priv[temp_port] = priv;
+ } else {
+ if (!svc->fn) {
+ if (!svc->port_cnt && !svc->svc_cnt)
+ client[dest_id][client_id].svc_cnt++;
+ svc->fn = svc_fn;
+ if (svc->port_cnt)
+ svc->svc_cnt++;
+ }
+ }
+
+ mutex_unlock(&svc->m_lock);
+done:
+ return svc;
+}
+
+static void apr_reset_deregister(struct work_struct *work)
+{
+ struct apr_svc *handle = NULL;
+ struct apr_reset_work *apr_reset =
+ container_of(work, struct apr_reset_work, work);
+
+ handle = apr_reset->handle;
+ pr_debug("%s:handle[%p]\n", __func__, handle);
+ apr_deregister(handle);
+ kfree(apr_reset);
+ msleep(5);
+}
+
+int apr_deregister(void *handle)
+{
+ struct apr_svc *svc = handle;
+ struct apr_client *clnt;
+ uint16_t dest_id;
+ uint16_t client_id;
+
+ if (!handle)
+ return -EINVAL;
+
+ mutex_lock(&svc->m_lock);
+ dest_id = svc->dest_id;
+ client_id = svc->client_id;
+ clnt = &client[dest_id][client_id];
+
+ if (svc->port_cnt > 0 || svc->svc_cnt > 0) {
+ if (svc->port_cnt)
+ svc->port_cnt--;
+ else if (svc->svc_cnt)
+ svc->svc_cnt--;
+ if (!svc->port_cnt && !svc->svc_cnt) {
+ client[dest_id][client_id].svc_cnt--;
+ svc->need_reset = 0x0;
+ }
+ } else if (client[dest_id][client_id].svc_cnt > 0) {
+ client[dest_id][client_id].svc_cnt--;
+ if (!client[dest_id][client_id].svc_cnt) {
+ svc->need_reset = 0x0;
+ pr_debug("%s: service is reset %p\n", __func__, svc);
+ }
+ }
+
+ if (!svc->port_cnt && !svc->svc_cnt) {
+ svc->priv = NULL;
+ svc->id = 0;
+ svc->fn = NULL;
+ svc->dest_id = 0;
+ svc->client_id = 0;
+ svc->need_reset = 0x0;
+ }
+ if (client[dest_id][client_id].handle &&
+ !client[dest_id][client_id].svc_cnt) {
+ apr_tal_close(client[dest_id][client_id].handle);
+ client[dest_id][client_id].handle = NULL;
+ }
+ mutex_unlock(&svc->m_lock);
+
+ return 0;
+}
+
+void apr_reset(void *handle)
+{
+ struct apr_reset_work *apr_reset_worker = NULL;
+
+ if (!handle)
+ return;
+ pr_debug("%s: handle[%p]\n", __func__, handle);
+
+ apr_reset_worker = kzalloc(sizeof(struct apr_reset_work),
+ GFP_ATOMIC);
+ if (apr_reset_worker == NULL || apr_reset_workqueue == NULL) {
+ pr_aud_err("%s: mem failure\n", __func__);
+ return;
+ }
+ apr_reset_worker->handle = handle;
+ INIT_WORK(&apr_reset_worker->work, apr_reset_deregister);
+ queue_work(apr_reset_workqueue, &apr_reset_worker->work);
+}
+
+void change_q6_state(int state)
+{
+ mutex_lock(&q6.lock);
+ q6.state = state;
+ mutex_unlock(&q6.lock);
+}
+
+int adsp_state(int state)
+{
+ pr_aud_info("dsp state = %d\n", state);
+ return 0;
+}
+
+/* Dispatch the Reset events to Modem and audio clients */
+void dispatch_event(unsigned long code, unsigned short proc)
+{
+ struct apr_client *apr_client;
+ struct apr_client_data data;
+ struct apr_svc *svc;
+ uint16_t clnt;
+ int i, j;
+
+ data.opcode = RESET_EVENTS;
+ data.reset_event = code;
+ data.reset_proc = proc;
+
+ clnt = APR_CLIENT_AUDIO;
+ apr_client = &client[proc][clnt];
+ for (i = 0; i < APR_SVC_MAX; i++) {
+ mutex_lock(&apr_client->svc[i].m_lock);
+ if (apr_client->svc[i].fn) {
+ apr_client->svc[i].need_reset = 0x1;
+ apr_client->svc[i].fn(&data, apr_client->svc[i].priv);
+ }
+ if (apr_client->svc[i].port_cnt) {
+ svc = &(apr_client->svc[i]);
+ svc->need_reset = 0x1;
+ for (j = 0; j < APR_MAX_PORTS; j++)
+ if (svc->port_fn[j])
+ svc->port_fn[j](&data,
+ svc->port_priv[j]);
+ }
+ mutex_unlock(&apr_client->svc[i].m_lock);
+ }
+
+ clnt = APR_CLIENT_VOICE;
+ apr_client = &client[proc][clnt];
+ for (i = 0; i < APR_SVC_MAX; i++) {
+ mutex_lock(&apr_client->svc[i].m_lock);
+ if (apr_client->svc[i].fn) {
+ apr_client->svc[i].need_reset = 0x1;
+ apr_client->svc[i].fn(&data, apr_client->svc[i].priv);
+ }
+ if (apr_client->svc[i].port_cnt) {
+ svc = &(apr_client->svc[i]);
+ svc->need_reset = 0x1;
+ for (j = 0; j < APR_MAX_PORTS; j++)
+ if (svc->port_fn[j])
+ svc->port_fn[j](&data,
+ svc->port_priv[j]);
+ }
+ mutex_unlock(&apr_client->svc[i].m_lock);
+ }
+}
+
+static int modem_notifier_cb(struct notifier_block *this, unsigned long code,
+ void *_cmd)
+{
+ switch (code) {
+ case SUBSYS_BEFORE_SHUTDOWN:
+ pr_debug("M-Notify: Shutdown started\n");
+ atomic_set(&modem_state, 0);
+ dispatch_event(code, APR_DEST_MODEM);
+ break;
+ case SUBSYS_AFTER_SHUTDOWN:
+ pr_debug("M-Notify: Shutdown Completed\n");
+ break;
+ case SUBSYS_BEFORE_POWERUP:
+ pr_debug("M-notify: Bootup started\n");
+ break;
+ case SUBSYS_AFTER_POWERUP:
+ if (atomic_read(&modem_state) == 0) {
+ atomic_set(&modem_state, 1);
+ wake_up(&modem_wait);
+ }
+ pr_debug("M-Notify: Bootup Completed\n");
+ break;
+ default:
+ pr_aud_err("M-Notify: General: %lu\n", code);
+ break;
+ }
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block mnb = {
+ .notifier_call = modem_notifier_cb,
+};
+
+static int lpass_notifier_cb(struct notifier_block *this, unsigned long code,
+ void *_cmd)
+{
+ switch (code) {
+ case SUBSYS_BEFORE_SHUTDOWN:
+ pr_debug("L-Notify: Shutdown started\n");
+ atomic_set(&dsp_state, 0);
+ dispatch_event(code, APR_DEST_QDSP6);
+ break;
+ case SUBSYS_AFTER_SHUTDOWN:
+ pr_debug("L-Notify: Shutdown Completed\n");
+ break;
+ case SUBSYS_BEFORE_POWERUP:
+ pr_debug("L-notify: Bootup started\n");
+ break;
+ case SUBSYS_AFTER_POWERUP:
+ if (atomic_read(&dsp_state) == 0) {
+ atomic_set(&dsp_state, 1);
+ wake_up(&dsp_wait);
+ }
+ pr_debug("L-Notify: Bootup Completed\n");
+ break;
+ default:
+ pr_aud_err("L-Notify: Generel: %lu\n", code);
+ break;
+ }
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block lnb = {
+ .notifier_call = lpass_notifier_cb,
+};
+
+
+static int __init apr_init(void)
+{
+ int i, j, k;
+
+ pr_aud_info("apr_probe\n");
+ for (i = 0; i < APR_DEST_MAX; i++)
+ for (j = 0; j < APR_CLIENT_MAX; j++) {
+ mutex_init(&client[i][j].m_lock);
+ for (k = 0; k < APR_SVC_MAX; k++) {
+ mutex_init(&client[i][j].svc[k].m_lock);
+ spin_lock_init(&client[i][j].svc[k].w_lock);
+ }
+ }
+ mutex_init(&q6.lock);
+ dsp_debug_register(adsp_state);
+ apr_reset_workqueue =
+ create_singlethread_workqueue("apr_driver");
+ if (!apr_reset_workqueue)
+ return -ENOMEM;
+ return 0;
+}
+device_initcall(apr_init);
+
+static int __init apr_late_init(void)
+{
+ void *ret;
+ init_waitqueue_head(&dsp_wait);
+ init_waitqueue_head(&modem_wait);
+ atomic_set(&dsp_state, 1);
+ atomic_set(&modem_state, 1);
+ ret = subsys_notif_register_notifier("modem", &mnb);
+ pr_debug("subsys_register_notifier: ret1 = %p\n", ret);
+ ret = subsys_notif_register_notifier("lpass", &lnb);
+ pr_debug("subsys_register_notifier: ret2 = %p\n", ret);
+
+ return 0;
+}
+late_initcall(apr_late_init);
diff --git a/arch/arm/mach-msm/qdsp6v3/apr_tal.c b/arch/arm/mach-msm/qdsp6v3/apr_tal.c
new file mode 100644
index 00000000000..44047bd8756
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v3/apr_tal.c
@@ -0,0 +1,288 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "apr_tal.h"
+#include "../clock-8x60.h"
+
+static char *svc_names[APR_DEST_MAX][APR_CLIENT_MAX] = {
+ {
+ "apr_audio_svc",
+ "apr_voice_svc",
+ },
+ {
+ "apr_audio_svc",
+ "apr_voice_svc",
+ },
+};
+
+struct apr_svc_ch_dev apr_svc_ch[APR_DL_MAX][APR_DEST_MAX][APR_CLIENT_MAX];
+
+int __apr_tal_write(struct apr_svc_ch_dev *apr_ch, void *data, int len)
+{
+ int w_len;
+ unsigned long flags;
+
+
+ spin_lock_irqsave(&apr_ch->w_lock, flags);
+ if (smd_write_avail(apr_ch->ch) < len) {
+ spin_unlock_irqrestore(&apr_ch->w_lock, flags);
+ return -EAGAIN;
+ }
+
+ w_len = smd_write(apr_ch->ch, data, len);
+ spin_unlock_irqrestore(&apr_ch->w_lock, flags);
+ pr_debug("apr_tal:w_len = %d\n", w_len);
+
+ if (w_len != len) {
+ pr_aud_err("apr_tal: Error in write\n");
+ return -ENETRESET;
+ }
+ return w_len;
+}
+
+int apr_tal_write(struct apr_svc_ch_dev *apr_ch, void *data, int len)
+{
+ int rc = 0, retries = 0;
+
+ if (!apr_ch->ch)
+ return -EINVAL;
+
+ do {
+ if (rc == -EAGAIN)
+ udelay(50);
+
+ rc = __apr_tal_write(apr_ch, data, len);
+ } while (rc == -EAGAIN && retries++ < 300);
+
+ if (rc == -EAGAIN)
+ pr_aud_err("apr_tal: TIMEOUT for write\n");
+
+ return rc;
+}
+
+static void apr_tal_notify(void *priv, unsigned event)
+{
+ struct apr_svc_ch_dev *apr_ch = priv;
+ int len, r_len, sz;
+ int pkt_cnt = 0;
+ unsigned long flags;
+
+ pr_debug("event = %d\n", event);
+ switch (event) {
+ case SMD_EVENT_DATA:
+ pkt_cnt = 0;
+ spin_lock_irqsave(&apr_ch->lock, flags);
+check_pending:
+ len = smd_read_avail(apr_ch->ch);
+ if (len < 0) {
+ pr_aud_err("apr_tal: Invalid Read Event :%d\n", len);
+ spin_unlock_irqrestore(&apr_ch->lock, flags);
+ return;
+ }
+ sz = smd_cur_packet_size(apr_ch->ch);
+ if (sz < 0) {
+ pr_debug("pkt size is zero\n");
+ spin_unlock_irqrestore(&apr_ch->lock, flags);
+ return;
+ }
+ if (!len && !sz && !pkt_cnt)
+ goto check_write_avail;
+ if (!len) {
+ pr_debug("len = %d pkt_cnt = %d\n", len, pkt_cnt);
+ spin_unlock_irqrestore(&apr_ch->lock, flags);
+ return;
+ }
+ r_len = smd_read_from_cb(apr_ch->ch, apr_ch->data, len);
+ if (len != r_len) {
+ pr_aud_err("apr_tal: Invalid Read\n");
+ spin_unlock_irqrestore(&apr_ch->lock, flags);
+ return;
+ }
+ pkt_cnt++;
+ pr_debug("%d %d %d\n", len, sz, pkt_cnt);
+ if (apr_ch->func)
+ apr_ch->func(apr_ch->data, r_len, apr_ch->priv);
+ goto check_pending;
+check_write_avail:
+ if (smd_write_avail(apr_ch->ch))
+ wake_up(&apr_ch->wait);
+ spin_unlock_irqrestore(&apr_ch->lock, flags);
+ break;
+ case SMD_EVENT_OPEN:
+ pr_aud_info("apr_tal: SMD_EVENT_OPEN\n");
+ apr_ch->smd_state = 1;
+ wake_up(&apr_ch->wait);
+ break;
+ case SMD_EVENT_CLOSE:
+ pr_aud_info("apr_tal: SMD_EVENT_CLOSE\n");
+ break;
+ }
+}
+
+struct apr_svc_ch_dev *apr_tal_open(uint32_t svc, uint32_t dest,
+ uint32_t dl, apr_svc_cb_fn func, void *priv)
+{
+ int rc;
+
+ if ((svc >= APR_CLIENT_MAX) || (dest >= APR_DEST_MAX) ||
+ (dl >= APR_DL_MAX)) {
+ pr_aud_err("apr_tal: Invalid params\n");
+ return NULL;
+ }
+
+ if (apr_svc_ch[dl][dest][svc].ch) {
+ pr_aud_err("apr_tal: This channel alreday openend\n");
+ return NULL;
+ }
+
+ mutex_lock(&apr_svc_ch[dl][dest][svc].m_lock);
+ if (!apr_svc_ch[dl][dest][svc].dest_state) {
+ rc = wait_event_timeout(apr_svc_ch[dl][dest][svc].dest,
+ apr_svc_ch[dl][dest][svc].dest_state,
+ msecs_to_jiffies(APR_OPEN_TIMEOUT_MS));
+ if (rc == 0) {
+ pr_aud_err("%s: TIMEOUT for dest %d svc %d\n", __func__, dest, svc);
+ mutex_unlock(&apr_svc_ch[dl][dest][svc].m_lock);
+ BUG();
+ }
+ pr_debug("apr_tal:Wakeup done\n");
+ apr_svc_ch[dl][dest][svc].dest_state = 0;
+ }
+ rc = smd_named_open_on_edge(svc_names[dest][svc], dest,
+ &apr_svc_ch[dl][dest][svc].ch,
+ &apr_svc_ch[dl][dest][svc],
+ apr_tal_notify);
+ if (rc < 0) {
+ pr_aud_err("apr_tal: smd_open failed %s\n",
+ svc_names[dest][svc]);
+ mutex_unlock(&apr_svc_ch[dl][dest][svc].m_lock);
+ return NULL;
+ }
+ rc = wait_event_timeout(apr_svc_ch[dl][dest][svc].wait,
+ (apr_svc_ch[dl][dest][svc].smd_state == 1), 5 * HZ);
+ if (rc == 0) {
+ pr_aud_err("apr_tal:TIMEOUT for OPEN event\n");
+ mutex_unlock(&apr_svc_ch[dl][dest][svc].m_lock);
+ BUG();
+ return NULL;
+ }
+ if (!apr_svc_ch[dl][dest][svc].dest_state) {
+ apr_svc_ch[dl][dest][svc].dest_state = 1;
+ pr_debug("apr_tal:Waiting for apr svc init\n");
+ msleep(200);
+ pr_debug("apr_tal:apr svc init done\n");
+ }
+ apr_svc_ch[dl][dest][svc].smd_state = 0;
+
+ apr_svc_ch[dl][dest][svc].func = func;
+ apr_svc_ch[dl][dest][svc].priv = priv;
+ mutex_unlock(&apr_svc_ch[dl][dest][svc].m_lock);
+
+ return &apr_svc_ch[dl][dest][svc];
+}
+
+int apr_tal_close(struct apr_svc_ch_dev *apr_ch)
+{
+ int r;
+
+ if (!apr_ch->ch)
+ return -EINVAL;
+
+ mutex_lock(&apr_ch->m_lock);
+ r = smd_close(apr_ch->ch);
+ apr_ch->ch = NULL;
+ apr_ch->func = NULL;
+ apr_ch->priv = NULL;
+ mutex_unlock(&apr_ch->m_lock);
+ return r;
+}
+
+static int apr_smd_probe(struct platform_device *pdev)
+{
+ int dest;
+ int clnt;
+
+ if (pdev->id == APR_DEST_MODEM) {
+ pr_aud_info("apr_tal:Modem Is Up\n");
+ dest = APR_DEST_MODEM;
+ clnt = APR_CLIENT_VOICE;
+ apr_svc_ch[APR_DL_SMD][dest][clnt].dest_state = 1;
+ wake_up(&apr_svc_ch[APR_DL_SMD][dest][clnt].dest);
+ } else if (pdev->id == APR_DEST_QDSP6) {
+ pr_aud_info("apr_tal:Q6 Is Up\n");
+ /*
+ local_src_disable(PLL_4);
+ */
+ dest = APR_DEST_QDSP6;
+ clnt = APR_CLIENT_AUDIO;
+ apr_svc_ch[APR_DL_SMD][dest][clnt].dest_state = 1;
+ wake_up(&apr_svc_ch[APR_DL_SMD][dest][clnt].dest);
+ } else
+ pr_aud_err("apr_tal:Invalid Dest Id: %d\n", pdev->id);
+ return 0;
+}
+
+static struct platform_driver apr_q6_driver = {
+ .probe = apr_smd_probe,
+ .driver = {
+ .name = "apr_audio_svc",
+ .owner = THIS_MODULE,
+ },
+};
+
+static struct platform_driver apr_modem_driver = {
+ .probe = apr_smd_probe,
+ .driver = {
+ .name = "apr_voice_svc",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init apr_tal_init(void)
+{
+ int i, j, k;
+
+ for (i = 0; i < APR_DL_MAX; i++)
+ for (j = 0; j < APR_DEST_MAX; j++)
+ for (k = 0; k < APR_CLIENT_MAX; k++) {
+ init_waitqueue_head(&apr_svc_ch[i][j][k].wait);
+ init_waitqueue_head(&apr_svc_ch[i][j][k].dest);
+ spin_lock_init(&apr_svc_ch[i][j][k].lock);
+ spin_lock_init(&apr_svc_ch[i][j][k].w_lock);
+ mutex_init(&apr_svc_ch[i][j][k].m_lock);
+ }
+ platform_driver_register(&apr_q6_driver);
+ platform_driver_register(&apr_modem_driver);
+ return 0;
+}
+device_initcall(apr_tal_init);
diff --git a/arch/arm/mach-msm/qdsp6v3/apr_tal.h b/arch/arm/mach-msm/qdsp6v3/apr_tal.h
new file mode 100644
index 00000000000..88f8ba459ea
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v3/apr_tal.h
@@ -0,0 +1,71 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef __APR_TAL_H_
+#define __APR_TAL_H_
+
+#include
+#include
+#include
+
+/* APR Client IDs */
+#define APR_CLIENT_AUDIO 0x0
+#define APR_CLIENT_VOICE 0x1
+#define APR_CLIENT_MAX 0x2
+
+#define APR_DL_SMD 0
+#define APR_DL_MAX 1
+
+#define APR_DEST_MODEM 0
+#define APR_DEST_QDSP6 1
+#define APR_DEST_MAX 2
+
+#define APR_MAX_BUF 8192
+
+#define APR_OPEN_TIMEOUT_MS 5000
+
+typedef void (*apr_svc_cb_fn)(void *buf, int len, void *priv);
+struct apr_svc_ch_dev *apr_tal_open(uint32_t svc, uint32_t dest,
+ uint32_t dl, apr_svc_cb_fn func, void *priv);
+int apr_tal_write(struct apr_svc_ch_dev *apr_ch, void *data, int len);
+int apr_tal_close(struct apr_svc_ch_dev *apr_ch);
+struct apr_svc_ch_dev {
+ struct smd_channel *ch;
+ spinlock_t lock;
+ spinlock_t w_lock;
+ struct mutex m_lock;
+ apr_svc_cb_fn func;
+ char data[APR_MAX_BUF];
+ wait_queue_head_t wait;
+ void *priv;
+ uint32_t smd_state;
+ wait_queue_head_t dest;
+ uint32_t dest_state;
+};
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp6v3/audio_aac.c b/arch/arm/mach-msm/qdsp6v3/audio_aac.c
new file mode 100644
index 00000000000..88f8ba459ea
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v3/audio_aac.c
@@ -0,0 +1,71 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef __APR_TAL_H_
+#define __APR_TAL_H_
+
+#include
+#include
+#include
+
+/* APR Client IDs */
+#define APR_CLIENT_AUDIO 0x0
+#define APR_CLIENT_VOICE 0x1
+#define APR_CLIENT_MAX 0x2
+
+#define APR_DL_SMD 0
+#define APR_DL_MAX 1
+
+#define APR_DEST_MODEM 0
+#define APR_DEST_QDSP6 1
+#define APR_DEST_MAX 2
+
+#define APR_MAX_BUF 8192
+
+#define APR_OPEN_TIMEOUT_MS 5000
+
+typedef void (*apr_svc_cb_fn)(void *buf, int len, void *priv);
+struct apr_svc_ch_dev *apr_tal_open(uint32_t svc, uint32_t dest,
+ uint32_t dl, apr_svc_cb_fn func, void *priv);
+int apr_tal_write(struct apr_svc_ch_dev *apr_ch, void *data, int len);
+int apr_tal_close(struct apr_svc_ch_dev *apr_ch);
+struct apr_svc_ch_dev {
+ struct smd_channel *ch;
+ spinlock_t lock;
+ spinlock_t w_lock;
+ struct mutex m_lock;
+ apr_svc_cb_fn func;
+ char data[APR_MAX_BUF];
+ wait_queue_head_t wait;
+ void *priv;
+ uint32_t smd_state;
+ wait_queue_head_t dest;
+ uint32_t dest_state;
+};
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp6v3/audio_acdb.c b/arch/arm/mach-msm/qdsp6v3/audio_acdb.c
new file mode 100644
index 00000000000..dca0df60769
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v3/audio_acdb.c
@@ -0,0 +1,780 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "audio_acdb.h"
+
+
+#define MAX_NETWORKS 9
+#define NUM_ACTIVE_NETWORKS 6
+#define VOCPROC_STREAM_OFFSET NUM_ACTIVE_NETWORKS
+#define VOCPROC_VOL_OFFSET (NUM_ACTIVE_NETWORKS * 2)
+#define NUM_VOCPROC_CAL_TYPES (NUM_ACTIVE_NETWORKS * 3)
+#define NUM_AUDPROC_CAL_TYPES 3
+#define ACDB_BLOCK_SIZE 4096
+#define NUM_VOCPROC_BLOCKS 18
+
+enum {
+ RX_CAL,
+ TX_CAL,
+ MAX_AUDPROC_TYPES
+};
+
+struct acdb_data {
+ struct mutex acdb_mutex;
+
+ /* ANC Cal */
+ struct acdb_cal_block anc_cal;
+
+ /* AudProc Cal */
+ struct acdb_cal_block audproc_cal[MAX_AUDPROC_TYPES];
+ struct acdb_cal_block audstrm_cal[MAX_AUDPROC_TYPES];
+ struct acdb_cal_block audvol_cal[MAX_AUDPROC_TYPES];
+
+ /* VocProc Cal */
+ struct acdb_cal_block vocproc_cal[MAX_NETWORKS];
+ struct acdb_cal_block vocstrm_cal[MAX_NETWORKS];
+ struct acdb_cal_block vocvol_cal[MAX_NETWORKS];
+ uint32_t vocproc_cal_size;
+ uint32_t vocstrm_cal_size;
+ uint32_t vocvol_cal_size;
+
+ /* Sidetone Cal */
+ struct sidetone_cal sidetone_cal;
+
+ /* PMEM information */
+ int pmem_fd;
+ unsigned long paddr;
+ unsigned long kvaddr;
+ unsigned long pmem_len;
+ struct file *file;
+
+};
+
+static struct acdb_data acdb_data;
+static atomic_t usage_count;
+
+void get_anc_cal(struct acdb_cal_block *cal_block)
+{
+ pr_debug("%s\n", __func__);
+
+ if (cal_block == NULL) {
+ pr_aud_err("ACDB=> NULL pointer sent to %s\n", __func__);
+ goto done;
+ }
+
+ mutex_lock(&acdb_data.acdb_mutex);
+
+ cal_block->cal_kvaddr = acdb_data.anc_cal.cal_kvaddr;
+ cal_block->cal_paddr = acdb_data.anc_cal.cal_paddr;
+ cal_block->cal_size = acdb_data.anc_cal.cal_size;
+
+ mutex_unlock(&acdb_data.acdb_mutex);
+done:
+ return;
+}
+
+void store_anc_cal(struct cal_block *cal_block)
+{
+ pr_debug("%s,\n", __func__);
+
+ if (cal_block->cal_offset > acdb_data.pmem_len) {
+ pr_aud_err("%s: offset %d is > pmem_len %ld\n",
+ __func__, cal_block->cal_offset,
+ acdb_data.pmem_len);
+ goto done;
+ }
+
+ mutex_lock(&acdb_data.acdb_mutex);
+
+ acdb_data.anc_cal.cal_kvaddr =
+ cal_block->cal_offset + acdb_data.kvaddr;
+ acdb_data.anc_cal.cal_paddr =
+ cal_block->cal_offset + acdb_data.paddr;
+ acdb_data.anc_cal.cal_size =
+ cal_block->cal_size;
+
+ mutex_unlock(&acdb_data.acdb_mutex);
+done:
+ return;
+}
+
+void get_audproc_buffer_data(struct audproc_buffer_data *cal_buffers)
+{
+ int i;
+ pr_debug("%s\n", __func__);
+
+ if (cal_buffers == NULL) {
+ pr_aud_err("ACDB=> NULL pointer sent to %s\n", __func__);
+ goto done;
+ }
+
+ for (i = 0; i < NUM_AUDPROC_BUFFERS; i++) {
+ cal_buffers->phys_addr[i] = (uint32_t)
+ (acdb_data.paddr +
+ (NUM_VOCPROC_BLOCKS + i) * ACDB_BLOCK_SIZE);
+ cal_buffers->buf_size[i] = ACDB_BLOCK_SIZE;
+ }
+done:
+ return;
+}
+
+void store_audproc_cal(int32_t path, struct cal_block *cal_block)
+{
+ pr_debug("%s, path = %d\n", __func__, path);
+
+ mutex_lock(&acdb_data.acdb_mutex);
+
+ if (cal_block->cal_offset > acdb_data.pmem_len) {
+ pr_aud_err("%s: offset %d is > pmem_len %ld\n",
+ __func__, cal_block->cal_offset,
+ acdb_data.pmem_len);
+ goto done;
+ }
+ if (path >= MAX_AUDPROC_TYPES) {
+ pr_aud_err("ACDB=> Bad path sent to %s, path: %d\n",
+ __func__, path);
+ goto done;
+ }
+
+ acdb_data.audproc_cal[path].cal_kvaddr =
+ cal_block->cal_offset + acdb_data.kvaddr;
+ acdb_data.audproc_cal[path].cal_paddr =
+ cal_block->cal_offset + acdb_data.paddr;
+ acdb_data.audproc_cal[path].cal_size =
+ cal_block->cal_size;
+
+done:
+ mutex_unlock(&acdb_data.acdb_mutex);
+ return;
+}
+
+void get_audproc_cal(int32_t path, struct acdb_cal_block *cal_block)
+{
+ pr_aud_info("%s, path = %d\n", __func__, path);
+
+ if (cal_block == NULL) {
+ pr_aud_err("ACDB=> NULL pointer sent to %s\n", __func__);
+ goto done;
+ }
+ if (path >= MAX_AUDPROC_TYPES) {
+ pr_aud_err("ACDB=> Bad path sent to %s, path: %d\n",
+ __func__, path);
+ goto done;
+ }
+
+ mutex_lock(&acdb_data.acdb_mutex);
+
+ cal_block->cal_kvaddr = acdb_data.audproc_cal[path].cal_kvaddr;
+ cal_block->cal_paddr = acdb_data.audproc_cal[path].cal_paddr;
+ cal_block->cal_size = acdb_data.audproc_cal[path].cal_size;
+
+ mutex_unlock(&acdb_data.acdb_mutex);
+done:
+ return;
+}
+
+void store_audstrm_cal(int32_t path, struct cal_block *cal_block)
+{
+ pr_debug("%s, path = %d\n", __func__, path);
+
+ mutex_lock(&acdb_data.acdb_mutex);
+
+ if (cal_block->cal_offset > acdb_data.pmem_len) {
+ pr_aud_err("%s: offset %d is > pmem_len %ld\n",
+ __func__, cal_block->cal_offset,
+ acdb_data.pmem_len);
+ goto done;
+ }
+ if (path >= MAX_AUDPROC_TYPES) {
+ pr_aud_err("ACDB=> Bad path sent to %s, path: %d\n",
+ __func__, path);
+ goto done;
+ }
+
+ acdb_data.audstrm_cal[path].cal_kvaddr =
+ cal_block->cal_offset + acdb_data.kvaddr;
+ acdb_data.audstrm_cal[path].cal_paddr =
+ cal_block->cal_offset + acdb_data.paddr;
+ acdb_data.audstrm_cal[path].cal_size =
+ cal_block->cal_size;
+
+done:
+ mutex_unlock(&acdb_data.acdb_mutex);
+ return;
+}
+
+void get_audstrm_cal(int32_t path, struct acdb_cal_block *cal_block)
+{
+ pr_debug("%s, path = %d\n", __func__, path);
+
+ if (cal_block == NULL) {
+ pr_aud_err("ACDB=> NULL pointer sent to %s\n", __func__);
+ goto done;
+ }
+ if (path >= MAX_AUDPROC_TYPES) {
+ pr_aud_err("ACDB=> Bad path sent to %s, path: %d\n",
+ __func__, path);
+ goto done;
+ }
+
+ mutex_lock(&acdb_data.acdb_mutex);
+
+ cal_block->cal_kvaddr = acdb_data.audstrm_cal[path].cal_kvaddr;
+ cal_block->cal_paddr = acdb_data.audstrm_cal[path].cal_paddr;
+ cal_block->cal_size = acdb_data.audstrm_cal[path].cal_size;
+
+ mutex_unlock(&acdb_data.acdb_mutex);
+done:
+ return;
+}
+
+void store_audvol_cal(int32_t path, struct cal_block *cal_block)
+{
+ pr_debug("%s, path = %d\n", __func__, path);
+
+ mutex_lock(&acdb_data.acdb_mutex);
+
+ if (cal_block->cal_offset > acdb_data.pmem_len) {
+ pr_aud_err("%s: offset %d is > pmem_len %ld\n",
+ __func__, cal_block->cal_offset,
+ acdb_data.pmem_len);
+ goto done;
+ }
+ if (path >= MAX_AUDPROC_TYPES) {
+ pr_aud_err("ACDB=> Bad path sent to %s, path: %d\n",
+ __func__, path);
+ goto done;
+ }
+
+ acdb_data.audvol_cal[path].cal_kvaddr =
+ cal_block->cal_offset + acdb_data.kvaddr;
+ acdb_data.audvol_cal[path].cal_paddr =
+ cal_block->cal_offset + acdb_data.paddr;
+ acdb_data.audvol_cal[path].cal_size =
+ cal_block->cal_size;
+
+done:
+ mutex_unlock(&acdb_data.acdb_mutex);
+ return;
+}
+
+void get_audvol_cal(int32_t path, struct acdb_cal_block *cal_block)
+{
+ pr_aud_info("%s, path = %d\n", __func__, path);
+
+ if (cal_block == NULL) {
+ pr_aud_err("ACDB=> NULL pointer sent to %s\n", __func__);
+ goto done;
+ }
+ if (path >= MAX_AUDPROC_TYPES) {
+ pr_aud_err("ACDB=> Bad path sent to %s, path: %d\n",
+ __func__, path);
+ goto done;
+ }
+
+ mutex_lock(&acdb_data.acdb_mutex);
+
+ cal_block->cal_kvaddr = acdb_data.audvol_cal[path].cal_kvaddr;
+ cal_block->cal_paddr = acdb_data.audvol_cal[path].cal_paddr;
+ cal_block->cal_size = acdb_data.audvol_cal[path].cal_size;
+
+ mutex_unlock(&acdb_data.acdb_mutex);
+done:
+ return;
+}
+
+
+void store_vocproc_cal(int32_t len, struct cal_block *cal_blocks)
+{
+ int i;
+ pr_debug("%s\n", __func__);
+
+ if (len > MAX_NETWORKS) {
+ pr_aud_err("%s: Calibration sent for %d networks, only %d are "
+ "supported!\n", __func__, len, MAX_NETWORKS);
+ goto done;
+ }
+
+
+ mutex_lock(&acdb_data.acdb_mutex);
+
+ for (i = 0; i < len; i++) {
+ if (cal_blocks[i].cal_offset > acdb_data.pmem_len) {
+ pr_aud_err("%s: offset %d is > pmem_len %ld\n",
+ __func__, cal_blocks[i].cal_offset,
+ acdb_data.pmem_len);
+ acdb_data.vocproc_cal[i].cal_size = 0;
+ } else {
+ acdb_data.vocproc_cal[i].cal_size =
+ cal_blocks[i].cal_size;
+ acdb_data.vocproc_cal[i].cal_paddr =
+ cal_blocks[i].cal_offset +
+ acdb_data.paddr;
+ acdb_data.vocproc_cal[i].cal_kvaddr =
+ cal_blocks[i].cal_offset +
+ acdb_data.kvaddr;
+ }
+ }
+ acdb_data.vocproc_cal_size = len;
+ mutex_unlock(&acdb_data.acdb_mutex);
+done:
+ return;
+}
+
+void get_vocproc_cal(struct acdb_cal_data *cal_data)
+{
+ pr_debug("%s\n", __func__);
+
+ if (cal_data == NULL) {
+ pr_aud_err("ACDB=> NULL pointer sent to %s\n", __func__);
+ goto done;
+ }
+
+ mutex_lock(&acdb_data.acdb_mutex);
+
+ cal_data->num_cal_blocks = acdb_data.vocproc_cal_size;
+ cal_data->cal_blocks = &acdb_data.vocproc_cal[0];
+
+ mutex_unlock(&acdb_data.acdb_mutex);
+done:
+ return;
+}
+
+void store_vocstrm_cal(int32_t len, struct cal_block *cal_blocks)
+{
+ int i;
+ pr_debug("%s\n", __func__);
+
+ if (len > MAX_NETWORKS) {
+ pr_aud_err("%s: Calibration sent for %d networks, only %d are "
+ "supported!\n", __func__, len, MAX_NETWORKS);
+ goto done;
+ }
+
+ mutex_lock(&acdb_data.acdb_mutex);
+
+ for (i = 0; i < len; i++) {
+ if (cal_blocks[i].cal_offset > acdb_data.pmem_len) {
+ pr_aud_err("%s: offset %d is > pmem_len %ld\n",
+ __func__, cal_blocks[i].cal_offset,
+ acdb_data.pmem_len);
+ acdb_data.vocstrm_cal[i].cal_size = 0;
+ } else {
+ acdb_data.vocstrm_cal[i].cal_size =
+ cal_blocks[i].cal_size;
+ acdb_data.vocstrm_cal[i].cal_paddr =
+ cal_blocks[i].cal_offset +
+ acdb_data.paddr;
+ acdb_data.vocstrm_cal[i].cal_kvaddr =
+ cal_blocks[i].cal_offset +
+ acdb_data.kvaddr;
+ }
+ }
+ acdb_data.vocstrm_cal_size = len;
+ mutex_unlock(&acdb_data.acdb_mutex);
+done:
+ return;
+}
+
+void get_vocstrm_cal(struct acdb_cal_data *cal_data)
+{
+ pr_debug("%s\n", __func__);
+
+ if (cal_data == NULL) {
+ pr_aud_err("ACDB=> NULL pointer sent to %s\n", __func__);
+ goto done;
+ }
+
+ mutex_lock(&acdb_data.acdb_mutex);
+
+ cal_data->num_cal_blocks = acdb_data.vocstrm_cal_size;
+ cal_data->cal_blocks = &acdb_data.vocstrm_cal[0];
+
+ mutex_unlock(&acdb_data.acdb_mutex);
+done:
+ return;
+}
+
+void store_vocvol_cal(int32_t len, struct cal_block *cal_blocks)
+{
+ int i;
+ pr_debug("%s\n", __func__);
+
+ if (len > MAX_NETWORKS) {
+ pr_aud_err("%s: Calibration sent for %d networks, only %d are "
+ "supported!\n", __func__, len, MAX_NETWORKS);
+ goto done;
+ }
+
+ mutex_lock(&acdb_data.acdb_mutex);
+
+ for (i = 0; i < len; i++) {
+ if (cal_blocks[i].cal_offset > acdb_data.pmem_len) {
+ pr_aud_err("%s: offset %d is > pmem_len %ld\n",
+ __func__, cal_blocks[i].cal_offset,
+ acdb_data.pmem_len);
+ acdb_data.vocvol_cal[i].cal_size = 0;
+ } else {
+ acdb_data.vocvol_cal[i].cal_size =
+ cal_blocks[i].cal_size;
+ acdb_data.vocvol_cal[i].cal_paddr =
+ cal_blocks[i].cal_offset +
+ acdb_data.paddr;
+ acdb_data.vocvol_cal[i].cal_kvaddr =
+ cal_blocks[i].cal_offset +
+ acdb_data.kvaddr;
+ }
+ }
+ acdb_data.vocvol_cal_size = len;
+ mutex_unlock(&acdb_data.acdb_mutex);
+done:
+ return;
+}
+
+void get_vocvol_cal(struct acdb_cal_data *cal_data)
+{
+ pr_debug("%s\n", __func__);
+
+ if (cal_data == NULL) {
+ pr_aud_err("ACDB=> NULL pointer sent to %s\n", __func__);
+ goto done;
+ }
+
+ mutex_lock(&acdb_data.acdb_mutex);
+
+ cal_data->num_cal_blocks = acdb_data.vocvol_cal_size;
+ cal_data->cal_blocks = &acdb_data.vocvol_cal[0];
+
+ mutex_unlock(&acdb_data.acdb_mutex);
+done:
+ return;
+}
+
+void store_sidetone_cal(struct sidetone_cal *cal_data)
+{
+ pr_debug("%s\n", __func__);
+
+ mutex_lock(&acdb_data.acdb_mutex);
+
+ acdb_data.sidetone_cal.enable = cal_data->enable;
+ acdb_data.sidetone_cal.gain = cal_data->gain;
+
+ mutex_unlock(&acdb_data.acdb_mutex);
+}
+
+
+void get_sidetone_cal(struct sidetone_cal *cal_data)
+{
+ pr_debug("%s\n", __func__);
+
+ if (cal_data == NULL) {
+ pr_aud_err("ACDB=> NULL pointer sent to %s\n", __func__);
+ goto done;
+ }
+
+ mutex_lock(&acdb_data.acdb_mutex);
+
+ cal_data->enable = acdb_data.sidetone_cal.enable;
+ cal_data->gain = acdb_data.sidetone_cal.gain;
+
+ mutex_unlock(&acdb_data.acdb_mutex);
+done:
+ return;
+}
+
+static int acdb_open(struct inode *inode, struct file *f)
+{
+ s32 result = 0;
+ pr_aud_info("%s\n", __func__);
+
+ mutex_lock(&acdb_data.acdb_mutex);
+ if (acdb_data.pmem_fd) {
+ pr_aud_info("%s: ACDB opened but PMEM allocated, using existing PMEM!\n",
+ __func__);
+ }
+ mutex_unlock(&acdb_data.acdb_mutex);
+
+ atomic_inc(&usage_count);
+ return result;
+}
+
+static int deregister_pmem(void)
+{
+ int result;
+ struct audproc_buffer_data buffer;
+
+ get_audproc_buffer_data(&buffer);
+
+ result = adm_memory_unmap_regions(buffer.phys_addr,
+ buffer.buf_size, NUM_AUDPROC_BUFFERS);
+
+ if (result < 0)
+ pr_aud_err("Audcal unmap did not work!\n");
+
+ if (acdb_data.pmem_fd) {
+ put_pmem_file(acdb_data.file);
+ acdb_data.pmem_fd = 0;
+ }
+ return result;
+}
+
+static int register_pmem(void)
+{
+ int result;
+ struct audproc_buffer_data buffer;
+
+ result = get_pmem_file(acdb_data.pmem_fd, &acdb_data.paddr,
+ &acdb_data.kvaddr, &acdb_data.pmem_len,
+ &acdb_data.file);
+ if (result != 0) {
+ acdb_data.pmem_fd = 0;
+ pr_aud_err("%s: Could not register PMEM!!!\n", __func__);
+ goto done;
+ }
+
+ pr_debug("AUDIO_REGISTER_PMEM done! paddr = 0x%lx, "
+ "kvaddr = 0x%lx, len = x%lx\n", acdb_data.paddr,
+ acdb_data.kvaddr, acdb_data.pmem_len);
+ get_audproc_buffer_data(&buffer);
+ result = adm_memory_map_regions(buffer.phys_addr, 0,
+ buffer.buf_size,
+ NUM_AUDPROC_BUFFERS);
+ if (result < 0)
+ pr_aud_err("Audcal mmap did not work!\n");
+ goto done;
+
+done:
+ return result;
+}
+static long acdb_ioctl(struct file *f,
+ unsigned int cmd, unsigned long arg)
+{
+ s32 result = 0;
+ s32 audproc_path;
+ s32 size;
+ struct cal_block data[MAX_NETWORKS];
+ pr_debug("%s\n", __func__);
+
+ switch (cmd) {
+ case AUDIO_REGISTER_PMEM:
+ pr_debug("AUDIO_REGISTER_PMEM\n");
+ mutex_lock(&acdb_data.acdb_mutex);
+ if (acdb_data.pmem_fd) {
+ deregister_pmem();
+ pr_aud_info("Remove the existing PMEM\n");
+ }
+
+ if (copy_from_user(&acdb_data.pmem_fd, (void *)arg,
+ sizeof(acdb_data.pmem_fd)))
+ result = -EFAULT;
+ else
+ result = register_pmem();
+ mutex_unlock(&acdb_data.acdb_mutex);
+ goto done;
+
+ case AUDIO_DEREGISTER_PMEM:
+ pr_debug("AUDIO_DEREGISTER_PMEM\n");
+ mutex_lock(&acdb_data.acdb_mutex);
+ deregister_pmem();
+ mutex_unlock(&acdb_data.acdb_mutex);
+ goto done;
+ }
+
+ if (copy_from_user(&size, (void *) arg, sizeof(size))) {
+
+ result = -EFAULT;
+ goto done;
+ }
+
+ if (size <= 0) {
+ pr_aud_err("%s: Invalid size sent to driver: %d\n",
+ __func__, size);
+ result = -EFAULT;
+ goto done;
+ }
+
+ if (copy_from_user(data, (void *)(arg + sizeof(size)), size)) {
+
+ pr_aud_err("%s: fail to copy table size %d\n", __func__, size);
+ result = -EFAULT;
+ goto done;
+ }
+
+ if (data == NULL) {
+ pr_aud_err("%s: NULL pointer sent to driver!\n", __func__);
+ result = -EFAULT;
+ goto done;
+ }
+
+ switch (cmd) {
+ case AUDIO_SET_AUDPROC_TX_CAL:
+ audproc_path = TX_CAL;
+ if (size > sizeof(struct cal_block))
+ pr_aud_err("%s: More Audproc Cal then expected, "
+ "size received: %d\n", __func__, size);
+ store_audproc_cal(audproc_path, data);
+ break;
+ case AUDIO_SET_AUDPROC_RX_CAL:
+ audproc_path = RX_CAL;
+ if (size > sizeof(struct cal_block))
+ pr_aud_err("%s: More Audproc Cal then expected, "
+ "size received: %d\n", __func__, size);
+ store_audproc_cal(audproc_path, data);
+ break;
+ case AUDIO_SET_AUDPROC_TX_STREAM_CAL:
+ audproc_path = TX_CAL;
+ if (size > sizeof(struct cal_block))
+ pr_aud_err("%s: More Audproc Cal then expected, "
+ "size received: %d\n", __func__, size);
+ store_audstrm_cal(audproc_path, data);
+ break;
+ case AUDIO_SET_AUDPROC_RX_STREAM_CAL:
+ audproc_path = RX_CAL;
+ if (size > sizeof(struct cal_block))
+ pr_aud_err("%s: More Audproc Cal then expected, "
+ "size received: %d\n", __func__, size);
+ store_audstrm_cal(audproc_path, data);
+ break;
+ case AUDIO_SET_AUDPROC_TX_VOL_CAL:
+ audproc_path = TX_CAL;
+ if (size > sizeof(struct cal_block))
+ pr_aud_err("%s: More Audproc Cal then expected, "
+ "size received: %d\n", __func__, size);
+ store_audvol_cal(audproc_path, data);
+ case AUDIO_SET_AUDPROC_RX_VOL_CAL:
+ audproc_path = RX_CAL;
+ if (size > sizeof(struct cal_block))
+ pr_aud_err("%s: More Audproc Cal then expected, "
+ "size received: %d\n", __func__, size);
+ store_audvol_cal(audproc_path, data);
+ break;
+ case AUDIO_SET_VOCPROC_CAL:
+ store_vocproc_cal(size / sizeof(struct cal_block), data);
+ break;
+ case AUDIO_SET_VOCPROC_STREAM_CAL:
+ store_vocstrm_cal(size / sizeof(struct cal_block), data);
+ break;
+ case AUDIO_SET_VOCPROC_VOL_CAL:
+ store_vocvol_cal(size / sizeof(struct cal_block), data);
+ break;
+ case AUDIO_SET_SIDETONE_CAL:
+ if (size > sizeof(struct sidetone_cal))
+ pr_aud_err("%s: More sidetone cal then expected, "
+ "size received: %d\n", __func__, size);
+ store_sidetone_cal((struct sidetone_cal *)data);
+ break;
+ case AUDIO_SET_ANC_CAL:
+ store_anc_cal(data);
+ break;
+ default:
+ pr_aud_err("ACDB=> ACDB ioctl not found!\n");
+ }
+
+done:
+ return result;
+}
+
+static int acdb_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ int result = 0;
+ int size = vma->vm_end - vma->vm_start;
+
+ pr_debug("%s\n", __func__);
+
+ mutex_lock(&acdb_data.acdb_mutex);
+ if (acdb_data.pmem_fd) {
+ if (size <= acdb_data.pmem_len) {
+ vma->vm_page_prot = pgprot_noncached(
+ vma->vm_page_prot);
+ result = remap_pfn_range(vma,
+ vma->vm_start,
+ acdb_data.paddr >> PAGE_SHIFT,
+ size,
+ vma->vm_page_prot);
+ } else {
+ pr_aud_err("%s: Not enough PMEM memory!\n", __func__);
+ result = -ENOMEM;
+ }
+ } else {
+ pr_aud_err("%s: PMEM is not allocated, yet!\n", __func__);
+ result = -ENODEV;
+ }
+ mutex_unlock(&acdb_data.acdb_mutex);
+
+ return result;
+}
+
+static int acdb_release(struct inode *inode, struct file *f)
+{
+ s32 result = 0;
+
+ atomic_dec(&usage_count);
+ atomic_read(&usage_count);
+
+ pr_aud_info("%s: ref count %d!\n", __func__,
+ atomic_read(&usage_count));
+
+ if (atomic_read(&usage_count) >= 1) {
+ result = -EBUSY;
+ } else {
+ mutex_lock(&acdb_data.acdb_mutex);
+ result = deregister_pmem();
+ mutex_unlock(&acdb_data.acdb_mutex);
+ }
+
+ return result;
+}
+
+static const struct file_operations acdb_fops = {
+ .owner = THIS_MODULE,
+ .open = acdb_open,
+ .release = acdb_release,
+ .unlocked_ioctl = acdb_ioctl,
+ .mmap = acdb_mmap,
+};
+
+struct miscdevice acdb_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_acdb",
+ .fops = &acdb_fops,
+};
+
+static int __init acdb_init(void)
+{
+ pr_aud_info("%s\n", __func__);
+ memset(&acdb_data, 0, sizeof(acdb_data));
+ mutex_init(&acdb_data.acdb_mutex);
+ atomic_set(&usage_count, 0);
+ return misc_register(&acdb_misc);
+}
+
+static void __exit acdb_exit(void)
+{
+}
+
+module_init(acdb_init);
+module_exit(acdb_exit);
+
+MODULE_DESCRIPTION("MSM 8x60 Audio ACDB driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp6v3/audio_acdb.h b/arch/arm/mach-msm/qdsp6v3/audio_acdb.h
new file mode 100644
index 00000000000..17f9a7c4624
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v3/audio_acdb.h
@@ -0,0 +1,63 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef _AUDIO_ACDB_H
+#define _AUDIO_ACDB_H
+
+#include
+#include "q6adm.h"
+
+#define NUM_AUDPROC_BUFFERS 6
+
+struct acdb_cal_block {
+ uint32_t cal_size;
+ uint32_t cal_kvaddr;
+ uint32_t cal_paddr;
+};
+
+struct acdb_cal_data {
+ uint32_t num_cal_blocks;
+ struct acdb_cal_block *cal_blocks;
+};
+
+struct audproc_buffer_data {
+ uint32_t buf_size[NUM_AUDPROC_BUFFERS];
+ uint32_t phys_addr[NUM_AUDPROC_BUFFERS];
+};
+
+void get_audproc_buffer_data(struct audproc_buffer_data *cal_buffers);
+void get_audproc_cal(int32_t path, struct acdb_cal_block *cal_block);
+void get_audstrm_cal(int32_t path, struct acdb_cal_block *cal_block);
+void get_audvol_cal(int32_t path, struct acdb_cal_block *cal_block);
+void get_vocproc_cal(struct acdb_cal_data *cal_data);
+void get_vocstrm_cal(struct acdb_cal_data *cal_data);
+void get_vocvol_cal(struct acdb_cal_data *cal_data);
+void get_sidetone_cal(struct sidetone_cal *cal_data);
+void get_anc_cal(struct acdb_cal_block *cal_block);
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp6v3/audio_dev_ctl.c b/arch/arm/mach-msm/qdsp6v3/audio_dev_ctl.c
new file mode 100644
index 00000000000..f170ae52131
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v3/audio_dev_ctl.c
@@ -0,0 +1,1757 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "q6adm.h"
+#include "rtac.h"
+
+#ifndef MAX
+#define MAX(x, y) (((x) > (y)) ? (x) : (y))
+#endif
+
+
+static DEFINE_MUTEX(session_lock);
+
+struct audio_dev_ctrl_state {
+ struct msm_snddev_info *devs[AUDIO_DEV_CTL_MAX_DEV];
+ u32 num_dev;
+ atomic_t opened;
+ struct msm_snddev_info *voice_rx_dev;
+ struct msm_snddev_info *voice_tx_dev;
+ wait_queue_head_t wait;
+};
+
+static struct audio_dev_ctrl_state audio_dev_ctrl;
+struct event_listner event;
+
+#define PLAYBACK 0x1
+#define LIVE_RECORDING 0x2
+#define NON_LIVE_RECORDING 0x3
+#define MAX_COPP_DEVICES 4
+static int voc_rx_freq = 0;
+static int voc_tx_freq = 0;
+
+struct session_freq {
+ int freq;
+ int evt;
+};
+
+struct audio_routing_info {
+ unsigned short mixer_mask[MAX_SESSIONS];
+ unsigned short audrec_mixer_mask[MAX_SESSIONS];
+ struct session_freq dec_freq[MAX_SESSIONS];
+ struct session_freq enc_freq[MAX_SESSIONS];
+ unsigned int copp_list[MAX_SESSIONS][AFE_MAX_PORTS];
+ int voice_tx_dev_id;
+ int voice_rx_dev_id;
+ int voice_tx_sample_rate;
+ int voice_rx_sample_rate;
+ signed int voice_tx_vol;
+ signed int voice_rx_vol;
+ int tx_mute;
+ int rx_mute;
+ int voice_state;
+ int call_state;
+ struct mutex copp_list_mutex;
+ struct mutex adm_mutex;
+};
+
+static struct audio_routing_info routing_info;
+
+struct audio_copp_topology {
+ struct mutex lock;
+ int session_cnt;
+ int session_id[MAX_SESSIONS];
+ int topolog_id[MAX_SESSIONS];
+};
+static struct audio_copp_topology adm_tx_topology_tbl;
+
+static struct dev_ctrl_ops default_ctrl_ops;
+static struct dev_ctrl_ops *ctrl_ops = &default_ctrl_ops;
+
+void htc_8x60_register_dev_ctrl_ops(struct dev_ctrl_ops *ops)
+{
+ ctrl_ops = ops;
+}
+
+int msm_reset_all_device(void)
+{
+ int rc = 0;
+ int dev_id = 0;
+ struct msm_snddev_info *dev_info = NULL;
+
+ for (dev_id = 0; dev_id < audio_dev_ctrl.num_dev; dev_id++) {
+ dev_info = audio_dev_ctrl_find_dev(dev_id);
+ if (IS_ERR(dev_info)) {
+ pr_aud_err("%s:pass invalid dev_id\n", __func__);
+ rc = PTR_ERR(dev_info);
+ return rc;
+ }
+ if (!dev_info->opened)
+ continue;
+ pr_debug("%s:Resetting device %d active on COPP %d"
+ "with %lld as routing\n", __func__,
+ dev_id, dev_info->copp_id, dev_info->sessions);
+ broadcast_event(AUDDEV_EVT_REL_PENDING,
+ dev_id,
+ SESSION_IGNORE);
+ rc = dev_info->dev_ops.close(dev_info);
+ if (rc < 0) {
+ pr_aud_err("%s:Snd device failed close!\n", __func__);
+ return rc;
+ } else {
+ dev_info->opened = 0;
+ broadcast_event(AUDDEV_EVT_DEV_RLS,
+ dev_id,
+ SESSION_IGNORE);
+
+ if (dev_info->copp_id == VOICE_PLAYBACK_TX)
+ voice_start_playback(0);
+ }
+ dev_info->sessions = 0;
+ }
+ msm_clear_all_session();
+ return 0;
+}
+EXPORT_SYMBOL(msm_reset_all_device);
+
+int msm_set_copp_id(int session_id, int copp_id)
+{
+ int rc = 0;
+ int index;
+
+ if (session_id < 1 || session_id > 8)
+ return -EINVAL;
+ if (afe_validate_port(copp_id) < 0)
+ return -EINVAL;
+
+ index = afe_get_port_index(copp_id);
+ pr_debug("%s: session[%d] copp_id[%d] index[%d]\n", __func__,
+ session_id, copp_id, index);
+ mutex_lock(&routing_info.copp_list_mutex);
+ if (routing_info.copp_list[session_id][index] == DEVICE_IGNORE)
+ routing_info.copp_list[session_id][index] = copp_id;
+ mutex_unlock(&routing_info.copp_list_mutex);
+
+ return rc;
+}
+EXPORT_SYMBOL(msm_set_copp_id);
+
+int msm_clear_copp_id(int session_id, int copp_id)
+{
+ int rc = 0;
+ int index = afe_get_port_index(copp_id);
+
+ if (session_id < 1 || session_id > 8) {
+ pr_aud_err("%s: invalid session_id %d\n", __func__, session_id);
+ return -EINVAL;
+ }
+
+ if (index < 0 || index >= AFE_MAX_PORTS) {
+ pr_aud_err("%s: invalid copp_id index %d\n", __func__, index);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: session[%d] copp_id[%d] index[%d]\n", __func__,
+ session_id, copp_id, index);
+ mutex_lock(&routing_info.copp_list_mutex);
+ if (routing_info.copp_list[session_id][index] == copp_id)
+ routing_info.copp_list[session_id][index] = DEVICE_IGNORE;
+ mutex_unlock(&routing_info.copp_list_mutex);
+
+ return rc;
+}
+EXPORT_SYMBOL(msm_clear_copp_id);
+
+int msm_clear_session_id(int session_id)
+{
+ int rc = 0;
+ int i = 0;
+ if (session_id < 1 || session_id > 8)
+ return -EINVAL;
+ pr_debug("%s: session[%d]\n", __func__, session_id);
+ mutex_lock(&routing_info.adm_mutex);
+ mutex_lock(&routing_info.copp_list_mutex);
+ for (i = 0; i < AFE_MAX_PORTS; i++) {
+ if (routing_info.copp_list[session_id][i] != DEVICE_IGNORE) {
+ rc = adm_close(routing_info.copp_list[session_id][i]);
+ if (rc < 0) {
+ pr_aud_err("%s: adm close fail port[%d] rc[%d]\n",
+ __func__,
+ routing_info.copp_list[session_id][i],
+ rc);
+ continue;
+ }
+ routing_info.copp_list[session_id][i] = DEVICE_IGNORE;
+ rc = 0;
+ }
+ }
+ mutex_unlock(&routing_info.copp_list_mutex);
+ mutex_unlock(&routing_info.adm_mutex);
+
+ return rc;
+}
+EXPORT_SYMBOL(msm_clear_session_id);
+
+int msm_clear_all_session()
+{
+ int rc = 0;
+ int i = 0, j = 0;
+ pr_aud_info("%s:\n", __func__);
+ mutex_lock(&routing_info.adm_mutex);
+ mutex_lock(&routing_info.copp_list_mutex);
+ for (j = 1; j < MAX_SESSIONS; j++) {
+ for (i = 0; i < AFE_MAX_PORTS; i++) {
+ if (routing_info.copp_list[j][i] != DEVICE_IGNORE) {
+ rc = adm_close(
+ routing_info.copp_list[j][i]);
+ if (rc < 0) {
+ pr_aud_err("%s: adm close fail copp[%d]"
+ "session[%d] rc[%d]\n",
+ __func__,
+ routing_info.copp_list[j][i],
+ j, rc);
+ continue;
+ }
+ routing_info.copp_list[j][i] = DEVICE_IGNORE;
+ rc = 0;
+ }
+ }
+ }
+ mutex_unlock(&routing_info.copp_list_mutex);
+ mutex_unlock(&routing_info.adm_mutex);
+ return rc;
+}
+EXPORT_SYMBOL(msm_clear_all_session);
+
+int msm_get_voice_state(void)
+{
+ pr_debug("voice state %d\n", routing_info.voice_state);
+ return routing_info.voice_state;
+}
+EXPORT_SYMBOL(msm_get_voice_state);
+
+int msm_get_call_state(void)
+{
+ pr_debug("call state %d\n", routing_info.call_state);
+ return routing_info.call_state;
+}
+EXPORT_SYMBOL(msm_get_call_state);
+
+int msm_set_voice_mute(int dir, int mute)
+{
+ pr_debug("dir %x mute %x\n", dir, mute);
+ if (dir == DIR_TX) {
+ routing_info.tx_mute = mute;
+ broadcast_event(AUDDEV_EVT_DEVICE_VOL_MUTE_CHG,
+ routing_info.voice_tx_dev_id, SESSION_IGNORE);
+ } else
+ return -EPERM;
+ return 0;
+}
+EXPORT_SYMBOL(msm_set_voice_mute);
+
+int msm_set_voice_vol(int dir, s32 volume)
+{
+ if (dir == DIR_TX) {
+ routing_info.voice_tx_vol = volume;
+ broadcast_event(AUDDEV_EVT_DEVICE_VOL_MUTE_CHG,
+ routing_info.voice_tx_dev_id,
+ SESSION_IGNORE);
+ } else if (dir == DIR_RX) {
+ routing_info.voice_rx_vol = volume;
+ broadcast_event(AUDDEV_EVT_DEVICE_VOL_MUTE_CHG,
+ routing_info.voice_rx_dev_id,
+ SESSION_IGNORE);
+ } else
+ return -EINVAL;
+ return 0;
+}
+EXPORT_SYMBOL(msm_set_voice_vol);
+
+void msm_snddev_register(struct msm_snddev_info *dev_info)
+{
+ mutex_lock(&session_lock);
+ if (audio_dev_ctrl.num_dev < AUDIO_DEV_CTL_MAX_DEV) {
+ audio_dev_ctrl.devs[audio_dev_ctrl.num_dev] = dev_info;
+ dev_info->dev_volume = 50; /* 50% */
+ dev_info->sessions = 0x0;
+ dev_info->usage_count = 0;
+ audio_dev_ctrl.num_dev++;
+ } else
+ pr_aud_err("%s: device registry max out\n", __func__);
+ mutex_unlock(&session_lock);
+}
+EXPORT_SYMBOL(msm_snddev_register);
+
+int msm_snddev_devcount(void)
+{
+ return audio_dev_ctrl.num_dev;
+}
+EXPORT_SYMBOL(msm_snddev_devcount);
+
+int msm_snddev_query(int dev_id)
+{
+ if (dev_id <= audio_dev_ctrl.num_dev)
+ return 0;
+ return -ENODEV;
+}
+EXPORT_SYMBOL(msm_snddev_query);
+
+int msm_snddev_is_set(int popp_id, int copp_id)
+{
+ return routing_info.mixer_mask[popp_id] & (0x1 << copp_id);
+}
+EXPORT_SYMBOL(msm_snddev_is_set);
+
+unsigned short msm_snddev_route_enc(int enc_id)
+{
+ if (enc_id >= MAX_SESSIONS)
+ return -EINVAL;
+ return routing_info.audrec_mixer_mask[enc_id];
+}
+EXPORT_SYMBOL(msm_snddev_route_enc);
+
+unsigned short msm_snddev_route_dec(int popp_id)
+{
+ if (popp_id >= MAX_SESSIONS)
+ return -EINVAL;
+ return routing_info.mixer_mask[popp_id];
+}
+EXPORT_SYMBOL(msm_snddev_route_dec);
+
+/*To check one->many case*/
+int msm_check_multicopp_per_stream(int session_id,
+ struct route_payload *payload)
+{
+ int i = 0;
+ int flag = 0;
+ pr_debug("%s: session_id=%d\n", __func__, session_id);
+ mutex_lock(&routing_info.copp_list_mutex);
+ for (i = 0; i < AFE_MAX_PORTS; i++) {
+ if (routing_info.copp_list[session_id][i] == DEVICE_IGNORE)
+ continue;
+ else {
+ pr_debug("Device enabled port_id = %d\n",
+ routing_info.copp_list[session_id][i]);
+ payload->copp_ids[flag++] =
+ routing_info.copp_list[session_id][i];
+ }
+ }
+ mutex_unlock(&routing_info.copp_list_mutex);
+ if (flag > 1) {
+ pr_debug("Multiple copp per stream case num_copps=%d\n", flag);
+ } else {
+ pr_debug("Stream routed to single copp\n");
+ }
+ payload->num_copps = flag;
+ return flag;
+}
+
+int msm_snddev_set_dec(int popp_id, int copp_id, int set,
+ int rate, int mode)
+{
+ int rc = 0, i = 0;
+ struct route_payload payload;
+ int topology = DEFAULT_COPP_TOPOLOGY;
+
+ if ((popp_id >= MAX_SESSIONS) || (popp_id <= 0)) {
+ pr_aud_err("%s: Invalid session id %d\n", __func__, popp_id);
+ return 0;
+ }
+
+ mutex_lock(&routing_info.adm_mutex);
+ if (set) {
+ if (ctrl_ops->support_opendsp) {
+ if (ctrl_ops->support_opendsp())
+ topology = HTC_COPP_TOPOLOGY;
+ }
+ pr_aud_info("%s, topology = 0x%x\n", __func__, topology);
+ rc = adm_open(copp_id, PLAYBACK, rate, mode,
+ topology);
+ if (rc < 0) {
+ pr_aud_err("%s: adm open fail rc[%d]\n", __func__, rc);
+ rc = -EINVAL;
+ mutex_unlock(&routing_info.adm_mutex);
+ return rc;
+ }
+ msm_set_copp_id(popp_id, copp_id);
+ pr_debug("%s:Session id=%d copp_id=%d\n",
+ __func__, popp_id, copp_id);
+ memset(payload.copp_ids, DEVICE_IGNORE,
+ (sizeof(unsigned int) * AFE_MAX_PORTS));
+ rc = msm_check_multicopp_per_stream(popp_id, &payload);
+ /* Multiple streams per copp is handled, one stream at a time */
+ rc = adm_matrix_map(popp_id, PLAYBACK, rc,
+ payload.copp_ids, copp_id);
+ if (rc < 0) {
+ pr_aud_err("%s: matrix map failed rc[%d]\n",
+ __func__, rc);
+ adm_close(copp_id);
+ rc = -EINVAL;
+ mutex_unlock(&routing_info.adm_mutex);
+ return rc;
+ }
+ } else {
+ for (i = 0; i < AFE_MAX_PORTS; i++) {
+ if (routing_info.copp_list[popp_id][i] == copp_id) {
+ rc = adm_close(copp_id);
+ if (rc < 0) {
+ pr_aud_err("%s: adm close fail copp[%d]"
+ "rc[%d]\n",
+ __func__, copp_id, rc);
+ rc = -EINVAL;
+ mutex_unlock(&routing_info.adm_mutex);
+ return rc;
+ }
+ msm_clear_copp_id(popp_id, copp_id);
+ break;
+ }
+ }
+ }
+
+ if (copp_id == VOICE_PLAYBACK_TX) {
+ /* Signal uplink playback. */
+ rc = voice_start_playback(set);
+ }
+ mutex_unlock(&routing_info.adm_mutex);
+ return rc;
+}
+EXPORT_SYMBOL(msm_snddev_set_dec);
+
+
+static int check_tx_copp_topology(int session_id)
+{
+ int cnt;
+ int ret_val = -ENOENT;
+
+ cnt = adm_tx_topology_tbl.session_cnt;
+ if (cnt) {
+ do {
+ if (adm_tx_topology_tbl.session_id[cnt-1]
+ == session_id)
+ ret_val = cnt-1;
+ } while (--cnt);
+ }
+
+ return ret_val;
+}
+
+static int add_to_tx_topology_lists(int session_id, int topology)
+{
+ int idx = 0, tbl_idx;
+ int ret_val = -ENOSPC;
+
+ mutex_lock(&adm_tx_topology_tbl.lock);
+
+ tbl_idx = check_tx_copp_topology(session_id);
+ if (tbl_idx == -ENOENT) {
+ while (adm_tx_topology_tbl.session_id[idx++])
+ ;
+ tbl_idx = idx-1;
+ }
+
+ if (tbl_idx < MAX_SESSIONS) {
+ adm_tx_topology_tbl.session_id[tbl_idx] = session_id;
+ adm_tx_topology_tbl.topolog_id[tbl_idx] = topology;
+ adm_tx_topology_tbl.session_cnt++;
+
+ ret_val = 0;
+ }
+ mutex_unlock(&adm_tx_topology_tbl.lock);
+ return ret_val;
+}
+
+static void remove_from_tx_topology_lists(int session_id)
+{
+ int tbl_idx;
+
+ mutex_lock(&adm_tx_topology_tbl.lock);
+ tbl_idx = check_tx_copp_topology(session_id);
+ if (tbl_idx != -ENOENT) {
+
+ adm_tx_topology_tbl.session_cnt--;
+ adm_tx_topology_tbl.session_id[tbl_idx] = 0;
+ adm_tx_topology_tbl.topolog_id[tbl_idx] = 0;
+ }
+ mutex_unlock(&adm_tx_topology_tbl.lock);
+}
+
+int auddev_cfg_tx_copp_topology(int session_id, int cfg)
+{
+ int ret = 0;
+
+ if (cfg == DEFAULT_COPP_TOPOLOGY)
+ remove_from_tx_topology_lists(session_id);
+ else {
+ switch (cfg) {
+ case VPM_TX_SM_ECNS_COPP_TOPOLOGY:
+ case VPM_TX_DM_FLUENCE_COPP_TOPOLOGY:
+ case HTC_STEREO_RECORD_TOPOLOGY:
+ ret = add_to_tx_topology_lists(session_id, cfg);
+ break;
+
+ default:
+ ret = -ENODEV;
+ break;
+ }
+ }
+ return ret;
+}
+
+int msm_snddev_set_enc(int popp_id, int copp_id, int set,
+ int rate, int mode)
+{
+ int topology;
+ int tbl_idx;
+ int rc = 0, i = 0;
+ mutex_lock(&routing_info.adm_mutex);
+ if (set) {
+ mutex_lock(&adm_tx_topology_tbl.lock);
+ tbl_idx = check_tx_copp_topology(popp_id);
+ if (tbl_idx == -ENOENT)
+ topology = DEFAULT_COPP_TOPOLOGY;
+ else {
+ topology = adm_tx_topology_tbl.topolog_id[tbl_idx];
+ rate = 16000;
+ }
+ mutex_unlock(&adm_tx_topology_tbl.lock);
+ pr_aud_info("%s, topology = 0x%x\n", __func__, topology);
+ rc = adm_open(copp_id, LIVE_RECORDING, rate, mode, topology);
+ if (rc < 0) {
+ pr_aud_err("%s: adm open fail rc[%d]\n", __func__, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ rc = adm_matrix_map(popp_id, LIVE_RECORDING, 1,
+ (unsigned int *)&copp_id, copp_id);
+ if (rc < 0) {
+ pr_aud_err("%s: matrix map failed rc[%d]\n", __func__, rc);
+ adm_close(copp_id);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ msm_set_copp_id(popp_id, copp_id);
+ } else {
+ for (i = 0; i < AFE_MAX_PORTS; i++) {
+ if (routing_info.copp_list[popp_id][i] == copp_id) {
+ rc = adm_close(copp_id);
+ if (rc < 0) {
+ pr_aud_err("%s: adm close fail copp[%d]"
+ "rc[%d]\n",
+ __func__, copp_id, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ msm_clear_copp_id(popp_id, copp_id);
+ break;
+ }
+ }
+ }
+fail_cmd:
+ mutex_unlock(&routing_info.adm_mutex);
+ return rc;
+}
+EXPORT_SYMBOL(msm_snddev_set_enc);
+
+int msm_device_is_voice(int dev_id)
+{
+ if ((dev_id == routing_info.voice_rx_dev_id)
+ || (dev_id == routing_info.voice_tx_dev_id))
+ return 0;
+ else
+ return -EINVAL;
+}
+EXPORT_SYMBOL(msm_device_is_voice);
+
+int msm_set_voc_route(struct msm_snddev_info *dev_info,
+ int stream_type, int dev_id)
+{
+ int rc = 0;
+ u64 session_mask = 0;
+
+ if (dev_info == NULL) {
+ pr_aud_err("%s: invalid param\n", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&session_lock);
+ switch (stream_type) {
+ case AUDIO_ROUTE_STREAM_VOICE_RX:
+ if (audio_dev_ctrl.voice_rx_dev)
+ audio_dev_ctrl.voice_rx_dev->sessions &= ~0xFFFF;
+
+ if (!(dev_info->capability & SNDDEV_CAP_RX) |
+ !(dev_info->capability & SNDDEV_CAP_VOICE)) {
+ rc = -EINVAL;
+ break;
+ }
+ audio_dev_ctrl.voice_rx_dev = dev_info;
+ if (audio_dev_ctrl.voice_rx_dev) {
+ session_mask =
+ ((u64)0x1) << (MAX_BIT_PER_CLIENT * \
+ ((int)AUDDEV_CLNT_VOC-1));
+ audio_dev_ctrl.voice_rx_dev->sessions |=
+ session_mask;
+ }
+ routing_info.voice_rx_dev_id = dev_id;
+ break;
+ case AUDIO_ROUTE_STREAM_VOICE_TX:
+ if (audio_dev_ctrl.voice_tx_dev)
+ audio_dev_ctrl.voice_tx_dev->sessions &= ~0xFFFF;
+
+ if (!(dev_info->capability & SNDDEV_CAP_TX) |
+ !(dev_info->capability & SNDDEV_CAP_VOICE)) {
+ rc = -EINVAL;
+ break;
+ }
+
+ audio_dev_ctrl.voice_tx_dev = dev_info;
+ if (audio_dev_ctrl.voice_rx_dev) {
+ session_mask =
+ ((u64)0x1) << (MAX_BIT_PER_CLIENT * \
+ ((int)AUDDEV_CLNT_VOC-1));
+ audio_dev_ctrl.voice_tx_dev->sessions |=
+ session_mask;
+ }
+ routing_info.voice_tx_dev_id = dev_id;
+ break;
+ default:
+ rc = -EINVAL;
+ }
+ mutex_unlock(&session_lock);
+ return rc;
+}
+EXPORT_SYMBOL(msm_set_voc_route);
+
+void msm_release_voc_thread(void)
+{
+ wake_up(&audio_dev_ctrl.wait);
+}
+EXPORT_SYMBOL(msm_release_voc_thread);
+
+int msm_snddev_get_enc_freq(session_id)
+{
+ return routing_info.enc_freq[session_id].freq;
+}
+EXPORT_SYMBOL(msm_snddev_get_enc_freq);
+
+int msm_get_voc_freq(int *tx_freq, int *rx_freq)
+{
+ *tx_freq = (0 == voc_tx_freq ? routing_info.voice_tx_sample_rate
+ : voc_tx_freq);
+ *rx_freq = (0 == voc_rx_freq ? routing_info.voice_rx_sample_rate
+ : voc_rx_freq);
+ return 0;
+}
+EXPORT_SYMBOL(msm_get_voc_freq);
+
+void msm_set_voc_freq(int tx_freq, int rx_freq)
+{
+ voc_tx_freq = tx_freq;
+ voc_rx_freq = rx_freq;
+}
+EXPORT_SYMBOL(msm_set_voc_freq);
+
+
+int msm_get_voc_route(u32 *rx_id, u32 *tx_id)
+{
+ int rc = 0;
+
+ if (!rx_id || !tx_id)
+ return -EINVAL;
+
+ mutex_lock(&session_lock);
+ if (!audio_dev_ctrl.voice_rx_dev || !audio_dev_ctrl.voice_tx_dev) {
+ rc = -ENODEV;
+ mutex_unlock(&session_lock);
+ return rc;
+ }
+
+ *rx_id = audio_dev_ctrl.voice_rx_dev->acdb_id;
+ *tx_id = audio_dev_ctrl.voice_tx_dev->acdb_id;
+
+ mutex_unlock(&session_lock);
+
+ return rc;
+}
+EXPORT_SYMBOL(msm_get_voc_route);
+
+struct msm_snddev_info *audio_dev_ctrl_find_dev(u32 dev_id)
+{
+ struct msm_snddev_info *info;
+
+ if ((audio_dev_ctrl.num_dev - 1) < dev_id) {
+ info = ERR_PTR(-ENODEV);
+ goto error;
+ }
+
+ info = audio_dev_ctrl.devs[dev_id];
+error:
+ return info;
+
+}
+EXPORT_SYMBOL(audio_dev_ctrl_find_dev);
+
+int snddev_voice_set_volume(int vol, int path)
+{
+ if (audio_dev_ctrl.voice_rx_dev
+ && audio_dev_ctrl.voice_tx_dev) {
+ if (path)
+ audio_dev_ctrl.voice_tx_dev->dev_volume = vol;
+ else
+ audio_dev_ctrl.voice_rx_dev->dev_volume = vol;
+ } else
+ return -ENODEV;
+ return 0;
+}
+EXPORT_SYMBOL(snddev_voice_set_volume);
+
+static int audio_dev_ctrl_get_devices(struct audio_dev_ctrl_state *dev_ctrl,
+ void __user *arg)
+{
+ int rc = 0;
+ u32 index;
+ struct msm_snd_device_list work_list;
+ struct msm_snd_device_info *work_tbl;
+
+ if (copy_from_user(&work_list, arg, sizeof(work_list))) {
+ rc = -EFAULT;
+ goto error;
+ }
+
+ if (work_list.num_dev > dev_ctrl->num_dev) {
+ rc = -EINVAL;
+ goto error;
+ }
+
+ work_tbl = kmalloc(work_list.num_dev *
+ sizeof(struct msm_snd_device_info), GFP_KERNEL);
+ if (!work_tbl) {
+ rc = -ENOMEM;
+ goto error;
+ }
+
+ for (index = 0; index < dev_ctrl->num_dev; index++) {
+ work_tbl[index].dev_id = index;
+ work_tbl[index].dev_cap = dev_ctrl->devs[index]->capability;
+ strlcpy(work_tbl[index].dev_name, dev_ctrl->devs[index]->name,
+ 64);
+ }
+
+ if (copy_to_user((void *) (work_list.list), work_tbl,
+ work_list.num_dev * sizeof(struct msm_snd_device_info)))
+ rc = -EFAULT;
+ kfree(work_tbl);
+error:
+ return rc;
+}
+
+
+int auddev_register_evt_listner(u32 evt_id, u32 clnt_type, u32 clnt_id,
+ void (*listner)(u32 evt_id,
+ union auddev_evt_data *evt_payload,
+ void *private_data),
+ void *private_data)
+{
+ int rc;
+ struct msm_snd_evt_listner *callback = NULL;
+ struct msm_snd_evt_listner *new_cb;
+
+ new_cb = kzalloc(sizeof(struct msm_snd_evt_listner), GFP_KERNEL);
+ if (!new_cb) {
+ pr_aud_err("No memory to add new listener node\n");
+ return -ENOMEM;
+ }
+
+ mutex_lock(&session_lock);
+ new_cb->cb_next = NULL;
+ new_cb->auddev_evt_listener = listner;
+ new_cb->evt_id = evt_id;
+ new_cb->clnt_type = clnt_type;
+ new_cb->clnt_id = clnt_id;
+ new_cb->private_data = private_data;
+ if (event.cb == NULL) {
+ event.cb = new_cb;
+ new_cb->cb_prev = NULL;
+ } else {
+ callback = event.cb;
+ for (; ;) {
+ if (callback->cb_next == NULL)
+ break;
+ else {
+ callback = callback->cb_next;
+ continue;
+ }
+ }
+ callback->cb_next = new_cb;
+ new_cb->cb_prev = callback;
+ }
+ event.num_listner++;
+ mutex_unlock(&session_lock);
+ rc = 0;
+ return rc;
+}
+EXPORT_SYMBOL(auddev_register_evt_listner);
+
+int auddev_unregister_evt_listner(u32 clnt_type, u32 clnt_id)
+{
+ struct msm_snd_evt_listner *callback = event.cb;
+ struct msm_snddev_info *info;
+ u64 session_mask = 0;
+ int i = 0;
+
+ mutex_lock(&session_lock);
+ while (callback != NULL) {
+ if ((callback->clnt_type == clnt_type)
+ && (callback->clnt_id == clnt_id))
+ break;
+ callback = callback->cb_next;
+ }
+ if (callback == NULL) {
+ mutex_unlock(&session_lock);
+ return -EINVAL;
+ }
+
+ if ((callback->cb_next == NULL) && (callback->cb_prev == NULL))
+ event.cb = NULL;
+ else if (callback->cb_next == NULL)
+ callback->cb_prev->cb_next = NULL;
+ else if (callback->cb_prev == NULL) {
+ callback->cb_next->cb_prev = NULL;
+ event.cb = callback->cb_next;
+ } else {
+ callback->cb_prev->cb_next = callback->cb_next;
+ callback->cb_next->cb_prev = callback->cb_prev;
+ }
+ kfree(callback);
+
+ session_mask = (((u64)0x1) << clnt_id) << (MAX_BIT_PER_CLIENT * \
+ ((int)clnt_type-1));
+ for (i = 0; i < audio_dev_ctrl.num_dev; i++) {
+ info = audio_dev_ctrl.devs[i];
+ info->sessions &= ~session_mask;
+ }
+ mutex_unlock(&session_lock);
+ return 0;
+}
+EXPORT_SYMBOL(auddev_unregister_evt_listner);
+
+int msm_snddev_withdraw_freq(u32 session_id, u32 capability, u32 clnt_type)
+{
+ int i = 0;
+ struct msm_snddev_info *info;
+ u64 session_mask = 0;
+
+ if ((clnt_type == AUDDEV_CLNT_VOC) && (session_id != 0))
+ return -EINVAL;
+ if ((clnt_type == AUDDEV_CLNT_DEC)
+ && (session_id >= MAX_SESSIONS))
+ return -EINVAL;
+ if ((clnt_type == AUDDEV_CLNT_ENC)
+ && (session_id >= MAX_SESSIONS))
+ return -EINVAL;
+
+ session_mask = (((u64)0x1) << session_id) << (MAX_BIT_PER_CLIENT * \
+ ((int)clnt_type-1));
+
+ for (i = 0; i < audio_dev_ctrl.num_dev; i++) {
+ info = audio_dev_ctrl.devs[i];
+ if ((info->sessions & session_mask)
+ && (info->capability & capability)) {
+ if (!(info->sessions & ~(session_mask)))
+ info->set_sample_rate = 0;
+ }
+ }
+ if (clnt_type == AUDDEV_CLNT_DEC)
+ routing_info.dec_freq[session_id].freq
+ = 0;
+ else if (clnt_type == AUDDEV_CLNT_ENC)
+ routing_info.enc_freq[session_id].freq
+ = 0;
+ else if (capability == SNDDEV_CAP_TX)
+ routing_info.voice_tx_sample_rate = 0;
+ else
+ routing_info.voice_rx_sample_rate = 48000;
+ return 0;
+}
+
+int msm_snddev_request_freq(int *freq, u32 session_id,
+ u32 capability, u32 clnt_type)
+{
+ int i = 0;
+ int rc = 0;
+ struct msm_snddev_info *info;
+ u32 set_freq;
+ u64 session_mask = 0;
+ u64 clnt_type_mask = 0;
+
+ pr_debug(": clnt_type 0x%08x\n", clnt_type);
+
+ if ((clnt_type == AUDDEV_CLNT_VOC) && (session_id != 0))
+ return -EINVAL;
+ if ((clnt_type == AUDDEV_CLNT_DEC)
+ && (session_id >= MAX_SESSIONS))
+ return -EINVAL;
+ if ((clnt_type == AUDDEV_CLNT_ENC)
+ && (session_id >= MAX_SESSIONS))
+ return -EINVAL;
+ session_mask = (((u64)0x1) << session_id) << (MAX_BIT_PER_CLIENT * \
+ ((int)clnt_type-1));
+ clnt_type_mask = (0xFFFF << (MAX_BIT_PER_CLIENT * (clnt_type-1)));
+ if (!(*freq == 8000) && !(*freq == 11025) &&
+ !(*freq == 12000) && !(*freq == 16000) &&
+ !(*freq == 22050) && !(*freq == 24000) &&
+ !(*freq == 32000) && !(*freq == 44100) &&
+ !(*freq == 48000))
+ return -EINVAL;
+
+ for (i = 0; i < audio_dev_ctrl.num_dev; i++) {
+ info = audio_dev_ctrl.devs[i];
+ if ((info->sessions & session_mask)
+ && (info->capability & capability)) {
+ rc = 0;
+ if ((info->sessions & ~clnt_type_mask)
+ && ((*freq != 8000) && (*freq != 16000)
+ && (*freq != 48000))) {
+ if (clnt_type == AUDDEV_CLNT_ENC) {
+ routing_info.enc_freq[session_id].freq
+ = 0;
+ return -EPERM;
+ } else if (clnt_type == AUDDEV_CLNT_DEC) {
+ routing_info.dec_freq[session_id].freq
+ = 0;
+ return -EPERM;
+ }
+ }
+ if (*freq == info->set_sample_rate) {
+ rc = info->set_sample_rate;
+ continue;
+ }
+ set_freq = MAX(*freq, info->set_sample_rate);
+
+
+ if (clnt_type == AUDDEV_CLNT_DEC) {
+ routing_info.dec_freq[session_id].evt = 1;
+ routing_info.dec_freq[session_id].freq
+ = set_freq;
+ } else if (clnt_type == AUDDEV_CLNT_ENC) {
+ routing_info.enc_freq[session_id].evt = 1;
+ routing_info.enc_freq[session_id].freq
+ = set_freq;
+ } else if (capability == SNDDEV_CAP_TX)
+ routing_info.voice_tx_sample_rate = set_freq;
+
+ rc = set_freq;
+ info->set_sample_rate = set_freq;
+ *freq = info->set_sample_rate;
+
+ if (info->opened) {
+ broadcast_event(AUDDEV_EVT_FREQ_CHG, i,
+ SESSION_IGNORE);
+ set_freq = info->dev_ops.set_freq(info,
+ set_freq);
+ broadcast_event(AUDDEV_EVT_DEV_RDY, i,
+ SESSION_IGNORE);
+ }
+ }
+ pr_debug("info->set_sample_rate = %d\n", info->set_sample_rate);
+ pr_debug("routing_info.enc_freq.freq = %d\n",
+ routing_info.enc_freq[session_id].freq);
+ }
+ return rc;
+}
+EXPORT_SYMBOL(msm_snddev_request_freq);
+
+int msm_snddev_enable_sidetone(u32 dev_id, u32 enable, uint16_t gain)
+{
+ int rc;
+ struct msm_snddev_info *dev_info;
+
+ pr_debug("dev_id %d enable %d\n", dev_id, enable);
+
+ dev_info = audio_dev_ctrl_find_dev(dev_id);
+
+ if (IS_ERR(dev_info)) {
+ pr_aud_err("bad dev_id %d\n", dev_id);
+ rc = -EINVAL;
+ } else if (!dev_info->dev_ops.enable_sidetone) {
+ pr_debug("dev %d no sidetone support\n", dev_id);
+ rc = -EPERM;
+ } else
+ rc = dev_info->dev_ops.enable_sidetone(dev_info, enable, gain);
+
+ return rc;
+}
+EXPORT_SYMBOL(msm_snddev_enable_sidetone);
+
+int msm_enable_incall_recording(int popp_id, int rec_mode, int rate,
+ int channel_mode)
+{
+ int rc = 0;
+ unsigned int port_id[2];
+ port_id[0] = VOICE_RECORD_TX;
+ port_id[1] = VOICE_RECORD_RX;
+
+ pr_debug("%s: popp_id %d, rec_mode %d, rate %d, channel_mode %d\n",
+ __func__, popp_id, rec_mode, rate, channel_mode);
+
+ mutex_lock(&routing_info.adm_mutex);
+
+ if (rec_mode == VOC_REC_UPLINK) {
+ rc = afe_start_pseudo_port(port_id[0]);
+ if (rc < 0) {
+ pr_aud_err("%s: Error %d in Tx pseudo port start\n",
+ __func__, rc);
+
+ goto fail_cmd;
+ }
+
+ rc = adm_open(port_id[0], LIVE_RECORDING, rate, channel_mode,
+ DEFAULT_COPP_TOPOLOGY);
+ if (rc < 0) {
+ pr_aud_err("%s: Error %d in ADM open %d\n",
+ __func__, rc, port_id[0]);
+
+ goto fail_cmd;
+ }
+
+ rc = adm_matrix_map(popp_id, LIVE_RECORDING, 1,
+ &port_id[0], port_id[0]);
+ if (rc < 0) {
+ pr_aud_err("%s: Error %d in ADM matrix map %d\n",
+ __func__, rc, port_id[0]);
+
+ goto fail_cmd;
+ }
+
+ msm_set_copp_id(popp_id, port_id[0]);
+
+ } else if (rec_mode == VOC_REC_DOWNLINK) {
+ rc = afe_start_pseudo_port(port_id[1]);
+ if (rc < 0) {
+ pr_aud_err("%s: Error %d in Rx pseudo port start\n",
+ __func__, rc);
+
+ goto fail_cmd;
+ }
+
+ rc = adm_open(port_id[1], LIVE_RECORDING, rate, channel_mode,
+ DEFAULT_COPP_TOPOLOGY);
+ if (rc < 0) {
+ pr_aud_err("%s: Error %d in ADM open %d\n",
+ __func__, rc, port_id[1]);
+
+ goto fail_cmd;
+ }
+
+ rc = adm_matrix_map(popp_id, LIVE_RECORDING, 1,
+ &port_id[1], port_id[1]);
+ if (rc < 0) {
+ pr_aud_err("%s: Error %d in ADM matrix map %d\n",
+ __func__, rc, port_id[1]);
+
+ goto fail_cmd;
+ }
+
+ msm_set_copp_id(popp_id, port_id[1]);
+
+ } else if (rec_mode == VOC_REC_BOTH) {
+ rc = afe_start_pseudo_port(port_id[0]);
+ if (rc < 0) {
+ pr_aud_err("%s: Error %d in Tx pseudo port start\n",
+ __func__, rc);
+
+ goto fail_cmd;
+ }
+
+ rc = adm_open(port_id[0], LIVE_RECORDING, rate, channel_mode,
+ DEFAULT_COPP_TOPOLOGY);
+ if (rc < 0) {
+ pr_aud_err("%s: Error %d in ADM open %d\n",
+ __func__, rc, port_id[0]);
+
+ goto fail_cmd;
+ }
+
+ msm_set_copp_id(popp_id, port_id[0]);
+
+ rc = afe_start_pseudo_port(port_id[1]);
+ if (rc < 0) {
+ pr_aud_err("%s: Error %d in Rx pseudo port start\n",
+ __func__, rc);
+
+ goto fail_cmd;
+ }
+
+ rc = adm_open(port_id[1], LIVE_RECORDING, rate, channel_mode,
+ DEFAULT_COPP_TOPOLOGY);
+ if (rc < 0) {
+ pr_aud_err("%s: Error %d in ADM open %d\n",
+ __func__, rc, port_id[0]);
+
+ goto fail_cmd;
+ }
+
+ rc = adm_matrix_map(popp_id, LIVE_RECORDING, 2,
+ &port_id[0], port_id[1]);
+ if (rc < 0) {
+ pr_aud_err("%s: Error %d in ADM matrix map\n",
+ __func__, rc);
+
+ goto fail_cmd;
+ }
+
+ msm_set_copp_id(popp_id, port_id[1]);
+ } else {
+ pr_aud_err("%s Unknown rec_mode %d\n", __func__, rec_mode);
+
+ goto fail_cmd;
+ }
+
+ rc = voice_start_record(rec_mode, 1);
+
+fail_cmd:
+ mutex_unlock(&routing_info.adm_mutex);
+ return rc;
+}
+
+int msm_disable_incall_recording(uint32_t popp_id, uint32_t rec_mode)
+{
+ int rc = 0;
+ uint32_t port_id[2];
+ port_id[0] = VOICE_RECORD_TX;
+ port_id[1] = VOICE_RECORD_RX;
+
+ pr_debug("%s: popp_id %d, rec_mode %d\n", __func__, popp_id, rec_mode);
+
+ mutex_lock(&routing_info.adm_mutex);
+
+ rc = voice_start_record(rec_mode, 0);
+ if (rc < 0) {
+ pr_aud_err("%s: Error %d stopping record\n", __func__, rc);
+
+ goto fail_cmd;
+ }
+
+ if (rec_mode == VOC_REC_UPLINK) {
+ rc = adm_close(port_id[0]);
+ if (rc < 0) {
+ pr_aud_err("%s: Error %d in ADM close %d\n",
+ __func__, rc, port_id[0]);
+
+ goto fail_cmd;
+ }
+
+ msm_clear_copp_id(popp_id, port_id[0]);
+
+ rc = afe_stop_pseudo_port(port_id[0]);
+ if (rc < 0) {
+ pr_aud_err("%s: Error %d in Tx pseudo port stop\n",
+ __func__, rc);
+ goto fail_cmd;
+ }
+
+ } else if (rec_mode == VOC_REC_DOWNLINK) {
+ rc = adm_close(port_id[1]);
+ if (rc < 0) {
+ pr_aud_err("%s: Error %d in ADM close %d\n",
+ __func__, rc, port_id[1]);
+
+ goto fail_cmd;
+ }
+
+ msm_clear_copp_id(popp_id, port_id[1]);
+
+ rc = afe_stop_pseudo_port(port_id[1]);
+ if (rc < 0) {
+ pr_aud_err("%s: Error %d in Rx pseudo port stop\n",
+ __func__, rc);
+ goto fail_cmd;
+ }
+ } else if (rec_mode == VOC_REC_BOTH) {
+ rc = adm_close(port_id[0]);
+ if (rc < 0) {
+ pr_aud_err("%s: Error %d in ADM close %d\n",
+ __func__, rc, port_id[0]);
+
+ goto fail_cmd;
+ }
+
+ msm_clear_copp_id(popp_id, port_id[0]);
+
+ rc = afe_stop_pseudo_port(port_id[0]);
+ if (rc < 0) {
+ pr_aud_err("%s: Error %d in Tx pseudo port stop\n",
+ __func__, rc);
+ goto fail_cmd;
+ }
+
+ rc = adm_close(port_id[1]);
+ if (rc < 0) {
+ pr_aud_err("%s: Error %d in ADM close %d\n",
+ __func__, rc, port_id[1]);
+
+ goto fail_cmd;
+ }
+
+ msm_clear_copp_id(popp_id, port_id[1]);
+
+ rc = afe_stop_pseudo_port(port_id[1]);
+ if (rc < 0) {
+ pr_aud_err("%s: Error %d in Rx pseudo port stop\n",
+ __func__, rc);
+ goto fail_cmd;
+ }
+ } else {
+ pr_aud_err("%s Unknown rec_mode %d\n", __func__, rec_mode);
+
+ goto fail_cmd;
+ }
+
+fail_cmd:
+ mutex_unlock(&routing_info.adm_mutex);
+ return rc;
+}
+
+static long audio_dev_ctrl_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int rc = 0;
+ struct audio_dev_ctrl_state *dev_ctrl = file->private_data;
+
+ mutex_lock(&session_lock);
+ switch (cmd) {
+ case AUDIO_GET_NUM_SND_DEVICE:
+ rc = put_user(dev_ctrl->num_dev, (uint32_t __user *) arg);
+ break;
+ case AUDIO_GET_SND_DEVICES:
+ rc = audio_dev_ctrl_get_devices(dev_ctrl, (void __user *) arg);
+ break;
+ case AUDIO_ENABLE_SND_DEVICE: {
+ struct msm_snddev_info *dev_info;
+ u32 dev_id;
+
+ if (get_user(dev_id, (u32 __user *) arg)) {
+ rc = -EFAULT;
+ break;
+ }
+ dev_info = audio_dev_ctrl_find_dev(dev_id);
+ if (IS_ERR(dev_info))
+ rc = PTR_ERR(dev_info);
+ else {
+ rc = dev_info->dev_ops.open(dev_info);
+ if (!rc)
+ dev_info->opened = 1;
+ wake_up(&audio_dev_ctrl.wait);
+ }
+ break;
+
+ }
+
+ case AUDIO_DISABLE_SND_DEVICE: {
+ struct msm_snddev_info *dev_info;
+ u32 dev_id;
+
+ if (get_user(dev_id, (u32 __user *) arg)) {
+ rc = -EFAULT;
+ break;
+ }
+ dev_info = audio_dev_ctrl_find_dev(dev_id);
+ if (IS_ERR(dev_info))
+ rc = PTR_ERR(dev_info);
+ else {
+ rc = dev_info->dev_ops.close(dev_info);
+ dev_info->opened = 0;
+ }
+ break;
+ }
+
+ case AUDIO_ROUTE_STREAM: {
+ struct msm_audio_route_config route_cfg;
+ struct msm_snddev_info *dev_info;
+
+ if (copy_from_user(&route_cfg, (void __user *) arg,
+ sizeof(struct msm_audio_route_config))) {
+ rc = -EFAULT;
+ break;
+ }
+ pr_debug("%s: route cfg %d %d type\n", __func__,
+ route_cfg.dev_id, route_cfg.stream_type);
+ dev_info = audio_dev_ctrl_find_dev(route_cfg.dev_id);
+ if (IS_ERR(dev_info)) {
+ pr_aud_err("%s: pass invalid dev_id\n", __func__);
+ rc = PTR_ERR(dev_info);
+ break;
+ }
+
+ switch (route_cfg.stream_type) {
+
+ case AUDIO_ROUTE_STREAM_VOICE_RX:
+ if (!(dev_info->capability & SNDDEV_CAP_RX) |
+ !(dev_info->capability & SNDDEV_CAP_VOICE)) {
+ rc = -EINVAL;
+ break;
+ }
+ dev_ctrl->voice_rx_dev = dev_info;
+ break;
+ case AUDIO_ROUTE_STREAM_VOICE_TX:
+ if (!(dev_info->capability & SNDDEV_CAP_TX) |
+ !(dev_info->capability & SNDDEV_CAP_VOICE)) {
+ rc = -EINVAL;
+ break;
+ }
+ dev_ctrl->voice_tx_dev = dev_info;
+ break;
+ }
+ break;
+ }
+
+ default:
+ rc = -EINVAL;
+ }
+ mutex_unlock(&session_lock);
+ return rc;
+}
+
+
+static int audio_dev_ctrl_open(struct inode *inode, struct file *file)
+{
+ pr_debug("open audio_dev_ctrl\n");
+ atomic_inc(&audio_dev_ctrl.opened);
+ file->private_data = &audio_dev_ctrl;
+ return 0;
+}
+
+static int audio_dev_ctrl_release(struct inode *inode, struct file *file)
+{
+ pr_debug("release audio_dev_ctrl\n");
+ atomic_dec(&audio_dev_ctrl.opened);
+ return 0;
+}
+
+static const struct file_operations audio_dev_ctrl_fops = {
+ .owner = THIS_MODULE,
+ .open = audio_dev_ctrl_open,
+ .release = audio_dev_ctrl_release,
+ .unlocked_ioctl = audio_dev_ctrl_ioctl,
+};
+
+
+struct miscdevice audio_dev_ctrl_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_audio_dev_ctrl",
+ .fops = &audio_dev_ctrl_fops,
+};
+
+/* session id is 64 bit routing mask per device
+ * 0-15 for voice clients
+ * 16-31 for Decoder clients
+ * 32-47 for Encoder clients
+ * 48-63 Do not care
+ */
+void broadcast_event(u32 evt_id, u32 dev_id, u64 session_id)
+{
+ int clnt_id = 0, i;
+ union auddev_evt_data *evt_payload = NULL;
+ struct msm_snd_evt_listner *callback;
+ struct msm_snddev_info *dev_info = NULL;
+ u64 session_mask = 0;
+ static int pending_sent;
+
+ pr_debug(": evt_id = %d\n", evt_id);
+
+ if ((evt_id != AUDDEV_EVT_START_VOICE)
+ && (evt_id != AUDDEV_EVT_END_VOICE)
+ && (evt_id != AUDDEV_EVT_STREAM_VOL_CHG)
+ && (evt_id != AUDDEV_EVT_VOICE_STATE_CHG))
+ dev_info = audio_dev_ctrl_find_dev(dev_id);
+
+#ifdef CONFIG_MSM8X60_RTAC
+ update_rtac(evt_id, dev_id, dev_info);
+#endif
+
+ if (event.cb != NULL)
+ callback = event.cb;
+ else
+ return;
+ mutex_lock(&session_lock);
+
+ if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
+ routing_info.voice_state = dev_id;
+
+ evt_payload = kzalloc(sizeof(union auddev_evt_data),
+ GFP_KERNEL);
+
+ if (evt_payload == NULL) {
+ pr_aud_err("%s: fail to allocate evt_payload", __func__);
+ return;
+ }
+
+ for (; ;) {
+ if (!(evt_id & callback->evt_id)) {
+ if (callback->cb_next == NULL)
+ break;
+ else {
+ callback = callback->cb_next;
+ continue;
+ }
+ }
+ clnt_id = callback->clnt_id;
+ memset(evt_payload, 0, sizeof(union auddev_evt_data));
+
+ if (evt_id == AUDDEV_EVT_START_VOICE)
+ routing_info.call_state = 1;
+ if (evt_id == AUDDEV_EVT_END_VOICE)
+ routing_info.call_state = 0;
+
+ if ((evt_id == AUDDEV_EVT_START_VOICE)
+ || (evt_id == AUDDEV_EVT_END_VOICE))
+ goto skip_check;
+ if (callback->clnt_type == AUDDEV_CLNT_AUDIOCAL)
+ goto aud_cal;
+
+ session_mask = (((u64)0x1) << clnt_id)
+ << (MAX_BIT_PER_CLIENT * \
+ ((int)callback->clnt_type-1));
+
+ if ((evt_id == AUDDEV_EVT_STREAM_VOL_CHG) || \
+ (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)) {
+ pr_debug("AUDDEV_EVT_STREAM_VOL_CHG or\
+ AUDDEV_EVT_VOICE_STATE_CHG\n");
+ goto volume_strm;
+ }
+ if (dev_info)
+ pr_debug("dev_info->sessions = %llu\n", dev_info->sessions);
+ else {
+ pr_aud_err("dev_info is NULL\n");
+ break;
+ }
+ if ((!session_id && !(dev_info->sessions & session_mask)) ||
+ (session_id && ((dev_info->sessions & session_mask) !=
+ session_id))) {
+ if (callback->cb_next == NULL)
+ break;
+ else {
+ callback = callback->cb_next;
+ continue;
+ }
+ }
+ if (evt_id == AUDDEV_EVT_DEV_CHG_VOICE)
+ goto voc_events;
+
+volume_strm:
+ if (callback->clnt_type == AUDDEV_CLNT_DEC) {
+ pr_debug("AUDDEV_CLNT_DEC\n");
+ if (evt_id == AUDDEV_EVT_STREAM_VOL_CHG) {
+ pr_debug("clnt_id = %d, session_id = %llu\n",
+ clnt_id, session_id);
+ if (session_mask != session_id)
+ goto sent_dec;
+ else
+ evt_payload->session_vol =
+ msm_vol_ctl.volume;
+ } else if (evt_id == AUDDEV_EVT_FREQ_CHG) {
+ if (routing_info.dec_freq[clnt_id].evt) {
+ routing_info.dec_freq[clnt_id].evt
+ = 0;
+ goto sent_dec;
+ } else if (routing_info.dec_freq[clnt_id].freq
+ == dev_info->set_sample_rate)
+ goto sent_dec;
+ else {
+ evt_payload->freq_info.sample_rate
+ = dev_info->set_sample_rate;
+ evt_payload->freq_info.dev_type
+ = dev_info->capability;
+ evt_payload->freq_info.acdb_dev_id
+ = dev_info->acdb_id;
+ }
+ } else if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
+ evt_payload->voice_state =
+ routing_info.voice_state;
+ else
+ evt_payload->routing_id = dev_info->copp_id;
+ callback->auddev_evt_listener(
+ evt_id,
+ evt_payload,
+ callback->private_data);
+sent_dec:
+ if ((evt_id != AUDDEV_EVT_STREAM_VOL_CHG) &&
+ (evt_id != AUDDEV_EVT_VOICE_STATE_CHG))
+ routing_info.dec_freq[clnt_id].freq
+ = dev_info->set_sample_rate;
+
+ if (callback->cb_next == NULL)
+ break;
+ else {
+ callback = callback->cb_next;
+ continue;
+ }
+ }
+ if (callback->clnt_type == AUDDEV_CLNT_ENC) {
+ pr_debug("AUDDEV_CLNT_ENC\n");
+ if (evt_id == AUDDEV_EVT_FREQ_CHG) {
+ if (routing_info.enc_freq[clnt_id].evt) {
+ routing_info.enc_freq[clnt_id].evt
+ = 0;
+ goto sent_enc;
+ } else {
+ evt_payload->freq_info.sample_rate
+ = dev_info->set_sample_rate;
+ evt_payload->freq_info.dev_type
+ = dev_info->capability;
+ evt_payload->freq_info.acdb_dev_id
+ = dev_info->acdb_id;
+ }
+ } else if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
+ evt_payload->voice_state =
+ routing_info.voice_state;
+ else {
+ if (dev_info)
+ evt_payload->routing_id = dev_info->copp_id;
+ else
+ pr_aud_info("dev_info == NULL\n");
+ }
+ callback->auddev_evt_listener(
+ evt_id,
+ evt_payload,
+ callback->private_data);
+sent_enc:
+ if (callback->cb_next == NULL)
+ break;
+ else {
+ callback = callback->cb_next;
+ continue;
+ }
+ }
+aud_cal:
+ if (callback->clnt_type == AUDDEV_CLNT_AUDIOCAL) {
+ pr_debug("AUDDEV_CLNT_AUDIOCAL\n");
+ if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
+ evt_payload->voice_state =
+ routing_info.voice_state;
+ else if (!dev_info->sessions)
+ goto sent_aud_cal;
+ else {
+ evt_payload->audcal_info.dev_id =
+ dev_info->copp_id;
+ evt_payload->audcal_info.acdb_id =
+ dev_info->acdb_id;
+ evt_payload->audcal_info.dev_type =
+ (dev_info->capability & SNDDEV_CAP_TX) ?
+ SNDDEV_CAP_TX : SNDDEV_CAP_RX;
+ evt_payload->audcal_info.sample_rate =
+ dev_info->set_sample_rate ?
+ dev_info->set_sample_rate :
+ dev_info->sample_rate;
+ }
+ callback->auddev_evt_listener(
+ evt_id,
+ evt_payload,
+ callback->private_data);
+
+sent_aud_cal:
+ if (callback->cb_next == NULL)
+ break;
+ else {
+ callback = callback->cb_next;
+ continue;
+ }
+ }
+skip_check:
+voc_events:
+ if (callback->clnt_type == AUDDEV_CLNT_VOC) {
+ pr_debug("AUDDEV_CLNT_VOC\n");
+ if (evt_id == AUDDEV_EVT_DEV_RLS) {
+ if (!pending_sent)
+ goto sent_voc;
+ else
+ pending_sent = 0;
+ }
+ if (evt_id == AUDDEV_EVT_REL_PENDING)
+ pending_sent = 1;
+
+ if (evt_id == AUDDEV_EVT_DEVICE_VOL_MUTE_CHG) {
+ if (dev_info->capability & SNDDEV_CAP_TX) {
+ evt_payload->voc_vm_info.dev_type =
+ SNDDEV_CAP_TX;
+ evt_payload->voc_vm_info.acdb_dev_id =
+ dev_info->acdb_id;
+ evt_payload->
+ voc_vm_info.dev_vm_val.mute =
+ routing_info.tx_mute;
+ } else {
+ evt_payload->voc_vm_info.dev_type =
+ SNDDEV_CAP_RX;
+ evt_payload->voc_vm_info.acdb_dev_id =
+ dev_info->acdb_id;
+ evt_payload->
+ voc_vm_info.dev_vm_val.vol =
+ routing_info.voice_rx_vol;
+ }
+ } else if ((evt_id == AUDDEV_EVT_START_VOICE)
+ || (evt_id == AUDDEV_EVT_END_VOICE))
+ memset(evt_payload, 0,
+ sizeof(union auddev_evt_data));
+ else if (evt_id == AUDDEV_EVT_FREQ_CHG) {
+ if (routing_info.voice_tx_sample_rate
+ != dev_info->set_sample_rate) {
+ routing_info.voice_tx_sample_rate
+ = dev_info->set_sample_rate;
+ evt_payload->freq_info.sample_rate
+ = dev_info->set_sample_rate;
+ evt_payload->freq_info.dev_type
+ = dev_info->capability;
+ evt_payload->freq_info.acdb_dev_id
+ = dev_info->acdb_id;
+ } else
+ goto sent_voc;
+ } else if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
+ evt_payload->voice_state =
+ routing_info.voice_state;
+ else {
+ evt_payload->voc_devinfo.dev_type =
+ (dev_info->capability & SNDDEV_CAP_TX) ?
+ SNDDEV_CAP_TX : SNDDEV_CAP_RX;
+ evt_payload->voc_devinfo.acdb_dev_id =
+ dev_info->acdb_id;
+ evt_payload->voc_devinfo.dev_port_id =
+ dev_info->copp_id;
+ evt_payload->voc_devinfo.dev_sample =
+ dev_info->set_sample_rate ?
+ dev_info->set_sample_rate :
+ dev_info->sample_rate;
+ evt_payload->voc_devinfo.dev_id = dev_id;
+ if (dev_info->capability & SNDDEV_CAP_RX) {
+ for (i = 0; i < VOC_RX_VOL_ARRAY_NUM;
+ i++) {
+ evt_payload->
+ voc_devinfo.max_rx_vol[i] =
+ dev_info->max_voc_rx_vol[i];
+ evt_payload
+ ->voc_devinfo.min_rx_vol[i] =
+ dev_info->min_voc_rx_vol[i];
+ }
+ }
+ }
+ callback->auddev_evt_listener(
+ evt_id,
+ evt_payload,
+ callback->private_data);
+ if (evt_id == AUDDEV_EVT_DEV_RLS)
+ dev_info->sessions &= ~(0xFFFF);
+sent_voc:
+ if (callback->cb_next == NULL)
+ break;
+ else {
+ callback = callback->cb_next;
+ continue;
+ }
+ }
+ }
+ kfree(evt_payload);
+ mutex_unlock(&session_lock);
+}
+EXPORT_SYMBOL(broadcast_event);
+
+
+void mixer_post_event(u32 evt_id, u32 id)
+{
+
+ pr_debug("evt_id = %d\n", evt_id);
+ switch (evt_id) {
+ case AUDDEV_EVT_DEV_CHG_VOICE: /* Called from Voice_route */
+ broadcast_event(AUDDEV_EVT_DEV_CHG_VOICE, id, SESSION_IGNORE);
+ break;
+ case AUDDEV_EVT_DEV_RDY:
+ broadcast_event(AUDDEV_EVT_DEV_RDY, id, SESSION_IGNORE);
+ break;
+ case AUDDEV_EVT_DEV_RLS:
+ broadcast_event(AUDDEV_EVT_DEV_RLS, id, SESSION_IGNORE);
+ break;
+ case AUDDEV_EVT_REL_PENDING:
+ broadcast_event(AUDDEV_EVT_REL_PENDING, id, SESSION_IGNORE);
+ break;
+ case AUDDEV_EVT_DEVICE_VOL_MUTE_CHG:
+ broadcast_event(AUDDEV_EVT_DEVICE_VOL_MUTE_CHG, id,
+ SESSION_IGNORE);
+ break;
+ case AUDDEV_EVT_STREAM_VOL_CHG:
+ broadcast_event(AUDDEV_EVT_STREAM_VOL_CHG, id,
+ SESSION_IGNORE);
+ break;
+ case AUDDEV_EVT_START_VOICE:
+ broadcast_event(AUDDEV_EVT_START_VOICE,
+ id, SESSION_IGNORE);
+ break;
+ case AUDDEV_EVT_END_VOICE:
+ broadcast_event(AUDDEV_EVT_END_VOICE,
+ id, SESSION_IGNORE);
+ break;
+ case AUDDEV_EVT_FREQ_CHG:
+ broadcast_event(AUDDEV_EVT_FREQ_CHG, id, SESSION_IGNORE);
+ break;
+ default:
+ break;
+ }
+}
+EXPORT_SYMBOL(mixer_post_event);
+
+static int __init audio_dev_ctrl_init(void)
+{
+ init_waitqueue_head(&audio_dev_ctrl.wait);
+
+ event.cb = NULL;
+
+ atomic_set(&audio_dev_ctrl.opened, 0);
+ audio_dev_ctrl.num_dev = 0;
+ audio_dev_ctrl.voice_tx_dev = NULL;
+ audio_dev_ctrl.voice_rx_dev = NULL;
+ routing_info.voice_state = VOICE_STATE_INVALID;
+ routing_info.call_state = 0;
+ mutex_init(&adm_tx_topology_tbl.lock);
+ mutex_init(&routing_info.copp_list_mutex);
+ mutex_init(&routing_info.adm_mutex);
+
+ memset(routing_info.copp_list, DEVICE_IGNORE,
+ (sizeof(unsigned int) * MAX_SESSIONS * AFE_MAX_PORTS));
+ return misc_register(&audio_dev_ctrl_misc);
+}
+
+static void __exit audio_dev_ctrl_exit(void)
+{
+}
+module_init(audio_dev_ctrl_init);
+module_exit(audio_dev_ctrl_exit);
+
+MODULE_DESCRIPTION("MSM 8K Audio Device Control driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp6v3/audio_lpa.c b/arch/arm/mach-msm/qdsp6v3/audio_lpa.c
new file mode 100644
index 00000000000..7845a35b3fc
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v3/audio_lpa.c
@@ -0,0 +1,1435 @@
+/* low power audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "audio_lpa.h"
+
+#include
+#include
+#include
+
+#include
+#include
+
+#define MAX_BUF 4
+#define BUFSZ (655360)
+
+#define AUDDEC_DEC_PCM 0
+
+#define AUDLPA_EVENT_NUM 10 /* Default number of pre-allocated event packets */
+
+#define __CONTAINS(r, v, l) ({ \
+ typeof(r) __r = r; \
+ typeof(v) __v = v; \
+ typeof(v) __e = __v + l; \
+ int res = ((__v >= __r->vaddr) && \
+ (__e <= __r->vaddr + __r->len)); \
+ res; \
+})
+
+#define CONTAINS(r1, r2) ({ \
+ typeof(r2) __r2 = r2; \
+ __CONTAINS(r1, __r2->vaddr, __r2->len); \
+})
+
+#define IN_RANGE(r, v) ({ \
+ typeof(r) __r = r; \
+ typeof(v) __vv = v; \
+ int res = ((__vv >= __r->vaddr) && \
+ (__vv < (__r->vaddr + __r->len))); \
+ res; \
+})
+
+#define OVERLAPS(r1, r2) ({ \
+ typeof(r1) __r1 = r1; \
+ typeof(r2) __r2 = r2; \
+ typeof(__r2->vaddr) __v = __r2->vaddr; \
+ typeof(__v) __e = __v + __r2->len - 1; \
+ int res = (IN_RANGE(__r1, __v) || IN_RANGE(__r1, __e)); \
+ res; \
+})
+
+struct audlpa_event {
+ struct list_head list;
+ int event_type;
+ union msm_audio_event_payload payload;
+};
+
+struct audlpa_pmem_region {
+ struct list_head list;
+ struct file *file;
+ int fd;
+ void *vaddr;
+ unsigned long paddr;
+ unsigned long kvaddr;
+ unsigned long len;
+ unsigned ref_cnt;
+};
+
+struct audlpa_buffer_node {
+ struct list_head list;
+ struct msm_audio_aio_buf buf;
+ unsigned long paddr;
+};
+
+struct audlpa_dec {
+ char *name;
+ int dec_attrb;
+ long (*ioctl)(struct file *, unsigned int, unsigned long);
+ int (*set_params)(void *);
+};
+
+static void audlpa_post_event(struct audio *audio, int type,
+ union msm_audio_event_payload payload);
+static unsigned long audlpa_pmem_fixup(struct audio *audio, void *addr,
+ unsigned long len, int ref_up);
+static void audlpa_async_send_data(struct audio *audio, unsigned needed,
+ uint32_t token);
+static int audlpa_pause(struct audio *audio);
+static void audlpa_unmap_pmem_region(struct audio *audio);
+static long pcm_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+static int audlpa_set_pcm_params(void *data);
+
+struct audlpa_dec audlpa_decs[] = {
+ {"msm_pcm_lp_dec", AUDDEC_DEC_PCM, &pcm_ioctl,
+ &audlpa_set_pcm_params},
+};
+
+static void lpa_listner(u32 evt_id, union auddev_evt_data *evt_payload,
+ void *private_data)
+{
+ struct audio *audio = (struct audio *) private_data;
+ int rc = 0;
+
+ switch (evt_id) {
+ case AUDDEV_EVT_STREAM_VOL_CHG:
+ audio->volume = evt_payload->session_vol;
+ pr_debug("%s: AUDDEV_EVT_STREAM_VOL_CHG, stream vol %d, "
+ "enabled = %d\n", __func__, audio->volume,
+ audio->out_enabled);
+ if (audio->out_enabled == 1) {
+ if (audio->ac) {
+ rc = q6asm_set_volume(audio->ac, audio->volume);
+ if (rc < 0) {
+ pr_aud_err("%s: Send Volume command failed"
+ " rc=%d\n", __func__, rc);
+ }
+ }
+ }
+ break;
+ default:
+ pr_aud_err("%s:ERROR:wrong event\n", __func__);
+ break;
+ }
+}
+
+static void audlpa_prevent_sleep(struct audio *audio)
+{
+ pr_debug("%s:\n", __func__);
+ wake_lock(&audio->wakelock);
+}
+
+static void audlpa_allow_sleep(struct audio *audio)
+{
+ pr_debug("%s:\n", __func__);
+ wake_unlock(&audio->wakelock);
+}
+
+/* must be called with audio->lock held */
+static int audio_enable(struct audio *audio)
+{
+ pr_aud_info("%s\n", __func__);
+
+ return q6asm_run(audio->ac, 0, 0, 0);
+
+}
+
+static int audlpa_async_flush(struct audio *audio)
+{
+ struct audlpa_buffer_node *buf_node;
+ struct list_head *ptr, *next;
+ union msm_audio_event_payload payload;
+ int rc = 0;
+
+ pr_aud_info("%s:out_enabled = %d, drv_status = 0x%x\n", __func__,
+ audio->out_enabled, audio->drv_status);
+ if (audio->out_enabled) {
+ list_for_each_safe(ptr, next, &audio->out_queue) {
+ buf_node = list_entry(ptr, struct audlpa_buffer_node,
+ list);
+ list_del(&buf_node->list);
+ payload.aio_buf = buf_node->buf;
+ audlpa_post_event(audio, AUDIO_EVENT_WRITE_DONE,
+ payload);
+ kfree(buf_node);
+ }
+ /* Implicitly issue a pause to the decoder before flushing if
+ it is not in pause state */
+ if (!(audio->drv_status & ADRV_STATUS_PAUSE)) {
+ rc = audlpa_pause(audio);
+ if (rc < 0)
+ pr_aud_err("%s: pause cmd failed rc=%d\n", __func__,
+ rc);
+ }
+
+ rc = q6asm_cmd(audio->ac, CMD_FLUSH);
+ if (rc < 0)
+ pr_aud_err("%s: flush cmd failed rc=%d\n", __func__, rc);
+
+ audio->drv_status &= ~ADRV_STATUS_OBUF_GIVEN;
+ audio->out_needed = 0;
+
+ if (audio->stopped == 0) {
+ rc = audio_enable(audio);
+ if (rc < 0)
+ pr_aud_err("%s: audio enable failed\n", __func__);
+ else {
+ audio->out_enabled = 1;
+ audio->out_needed = 1;
+ if (audio->drv_status & ADRV_STATUS_PAUSE)
+ audio->drv_status &= ~ADRV_STATUS_PAUSE;
+ }
+ }
+ wake_up(&audio->write_wait);
+ }
+ return rc;
+}
+
+/* must be called with audio->lock held */
+static int audio_disable(struct audio *audio)
+{
+ int rc = 0;
+
+ pr_aud_info("%s:%d %d\n", __func__, audio->opened, audio->out_enabled);
+
+ if (audio->opened) {
+ audio->out_enabled = 0;
+ audio->opened = 0;
+ rc = q6asm_cmd(audio->ac, CMD_CLOSE);
+ if (rc < 0)
+ pr_aud_err("%s: CLOSE cmd failed\n", __func__);
+ else
+ pr_debug("%s: rxed CLOSE resp\n", __func__);
+ audio->drv_status &= ~ADRV_STATUS_OBUF_GIVEN;
+ wake_up(&audio->write_wait);
+ audio->out_needed = 0;
+ }
+ return rc;
+}
+static int audlpa_pause(struct audio *audio)
+{
+ int rc = 0;
+
+ pr_aud_info("%s, enabled = %d\n", __func__,
+ audio->out_enabled);
+ if (audio->out_enabled) {
+ rc = q6asm_cmd(audio->ac, CMD_PAUSE);
+ if (rc < 0)
+ pr_aud_err("%s: pause cmd failed rc=%d\n", __func__, rc);
+
+ } else
+ pr_aud_err("%s: Driver not enabled\n", __func__);
+ return rc;
+}
+
+/* ------------------- dsp --------------------- */
+static void audlpa_async_send_data(struct audio *audio, unsigned needed,
+ uint32_t token)
+{
+ unsigned long flags;
+ struct audio_client *ac;
+ int rc = 0;
+
+ pr_debug("%s:\n", __func__);
+ spin_lock_irqsave(&audio->dsp_lock, flags);
+
+ pr_debug("%s: needed = %d, out_needed = %d, token = 0x%x\n",
+ __func__, needed, audio->out_needed, token);
+ if (needed && !audio->wflush) {
+ audio->out_needed = 1;
+ if (audio->drv_status & ADRV_STATUS_OBUF_GIVEN) {
+ /* pop one node out of queue */
+ union msm_audio_event_payload evt_payload;
+ struct audlpa_buffer_node *used_buf;
+
+ used_buf = list_first_entry(&audio->out_queue,
+ struct audlpa_buffer_node, list);
+ if (token == used_buf->paddr) {
+ pr_debug("%s, Release: addr: %lx,"
+ " token = 0x%x\n", __func__,
+ used_buf->paddr, token);
+ list_del(&used_buf->list);
+ evt_payload.aio_buf = used_buf->buf;
+ audlpa_post_event(audio, AUDIO_EVENT_WRITE_DONE,
+ evt_payload);
+ kfree(used_buf);
+ audio->drv_status &= ~ADRV_STATUS_OBUF_GIVEN;
+ }
+ }
+ }
+ pr_debug("%s: out_needed = %d, stopped = %d, drv_status = 0x%x\n",
+ __func__, audio->out_needed, audio->stopped,
+ audio->drv_status);
+ if (audio->out_needed && (audio->stopped == 0)) {
+ struct audlpa_buffer_node *next_buf;
+ struct audio_aio_write_param param;
+ if (!list_empty(&audio->out_queue)) {
+ pr_debug("%s: list not empty\n", __func__);
+ next_buf = list_first_entry(&audio->out_queue,
+ struct audlpa_buffer_node, list);
+ if (next_buf) {
+ pr_debug("%s: Send: addr: %lx\n", __func__,
+ next_buf->paddr);
+ ac = audio->ac;
+ param.paddr = next_buf->paddr;
+ param.len = next_buf->buf.data_len;
+ param.msw_ts = 0;
+ param.lsw_ts = 0;
+ /* No time stamp valid */
+ param.flags = NO_TIMESTAMP;
+ param.uid = next_buf->paddr;
+ rc = q6asm_async_write(ac, ¶m);
+ if (rc < 0)
+ pr_aud_err("%s:q6asm_async_write failed\n",
+ __func__);
+ audio->out_needed = 0;
+ audio->drv_status |= ADRV_STATUS_OBUF_GIVEN;
+ }
+ } else if (list_empty(&audio->out_queue) &&
+ (audio->drv_status & ADRV_STATUS_FSYNC)) {
+ pr_debug("%s: list is empty, reached EOS\n", __func__);
+ wake_up(&audio->write_wait);
+ }
+ }
+
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+static int audlpa_events_pending(struct audio *audio)
+{
+ int empty;
+
+ spin_lock(&audio->event_queue_lock);
+ empty = !list_empty(&audio->event_queue);
+ spin_unlock(&audio->event_queue_lock);
+ return empty || audio->event_abort;
+}
+
+static void audlpa_reset_event_queue(struct audio *audio)
+{
+ struct audlpa_event *drv_evt;
+ struct list_head *ptr, *next;
+
+ spin_lock(&audio->event_queue_lock);
+ list_for_each_safe(ptr, next, &audio->event_queue) {
+ drv_evt = list_first_entry(&audio->event_queue,
+ struct audlpa_event, list);
+ list_del(&drv_evt->list);
+ kfree(drv_evt);
+ }
+ list_for_each_safe(ptr, next, &audio->free_event_queue) {
+ drv_evt = list_first_entry(&audio->free_event_queue,
+ struct audlpa_event, list);
+ list_del(&drv_evt->list);
+ kfree(drv_evt);
+ }
+ spin_unlock(&audio->event_queue_lock);
+
+ return;
+}
+
+static long audlpa_process_event_req(struct audio *audio, void __user *arg)
+{
+ long rc;
+ struct msm_audio_event usr_evt;
+ struct audlpa_event *drv_evt = NULL;
+ int timeout;
+
+ if (copy_from_user(&usr_evt, arg, sizeof(struct msm_audio_event)))
+ return -EFAULT;
+
+ timeout = (int) usr_evt.timeout_ms;
+
+ if (timeout > 0) {
+ rc = wait_event_interruptible_timeout(
+ audio->event_wait, audlpa_events_pending(audio),
+ msecs_to_jiffies(timeout));
+ if (rc == 0)
+ return -ETIMEDOUT;
+ } else {
+ rc = wait_event_interruptible(
+ audio->event_wait, audlpa_events_pending(audio));
+ }
+
+ if (rc < 0)
+ return rc;
+
+ if (audio->event_abort) {
+ audio->event_abort = 0;
+ return -ENODEV;
+ }
+
+ rc = 0;
+
+ spin_lock(&audio->event_queue_lock);
+ if (!list_empty(&audio->event_queue)) {
+ drv_evt = list_first_entry(&audio->event_queue,
+ struct audlpa_event, list);
+ list_del(&drv_evt->list);
+ }
+ if (drv_evt) {
+ usr_evt.event_type = drv_evt->event_type;
+ usr_evt.event_payload = drv_evt->payload;
+ list_add_tail(&drv_evt->list, &audio->free_event_queue);
+ } else {
+ rc = -1;
+ spin_unlock(&audio->event_queue_lock);
+ return rc;
+ }
+ spin_unlock(&audio->event_queue_lock);
+
+ if (drv_evt->event_type == AUDIO_EVENT_WRITE_DONE ||
+ drv_evt->event_type == AUDIO_EVENT_READ_DONE) {
+ pr_debug("%s: AUDIO_EVENT_WRITE_DONE completing\n", __func__);
+ mutex_lock(&audio->lock);
+ audlpa_pmem_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
+ drv_evt->payload.aio_buf.buf_len, 0);
+ mutex_unlock(&audio->lock);
+ }
+ if (!rc && copy_to_user(arg, &usr_evt, sizeof(usr_evt)))
+ rc = -EFAULT;
+
+ return rc;
+}
+
+static int audlpa_pmem_check(struct audio *audio,
+ void *vaddr, unsigned long len)
+{
+ struct audlpa_pmem_region *region_elt;
+ struct audlpa_pmem_region t = { .vaddr = vaddr, .len = len };
+
+ list_for_each_entry(region_elt, &audio->pmem_region_queue, list) {
+ if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
+ OVERLAPS(region_elt, &t)) {
+ pr_aud_err("%s: region (vaddr %p len %ld)"
+ " clashes with registered region"
+ " (vaddr %p paddr %p len %ld)\n",
+ __func__, vaddr, len,
+ region_elt->vaddr,
+ (void *)region_elt->paddr,
+ region_elt->len);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int audlpa_pmem_add(struct audio *audio,
+ struct msm_audio_pmem_info *info)
+{
+ unsigned long paddr, kvaddr, len;
+ struct file *file;
+ struct audlpa_pmem_region *region;
+ int rc = -EINVAL;
+
+ pr_aud_info("%s:\n", __func__);
+ region = kmalloc(sizeof(*region), GFP_KERNEL);
+
+ if (!region) {
+ rc = -ENOMEM;
+ goto end;
+ }
+
+ if (get_pmem_file(info->fd, &paddr, &kvaddr, &len, &file)) {
+ kfree(region);
+ goto end;
+ }
+
+ rc = audlpa_pmem_check(audio, info->vaddr, len);
+ if (rc < 0) {
+ put_pmem_file(file);
+ kfree(region);
+ goto end;
+ }
+
+ region->vaddr = info->vaddr;
+ region->fd = info->fd;
+ region->paddr = paddr;
+ region->kvaddr = kvaddr;
+ region->len = len;
+ region->file = file;
+ region->ref_cnt = 0;
+ pr_debug("%s: add region paddr %lx vaddr %p, len %lu\n", __func__,
+ region->paddr, region->vaddr,
+ region->len);
+ list_add_tail(®ion->list, &audio->pmem_region_queue);
+ rc = q6asm_memory_map(audio->ac, (uint32_t)paddr, IN, (uint32_t)len, 1);
+ if (rc < 0)
+ pr_aud_err("%s: memory map failed\n", __func__);
+end:
+ return rc;
+}
+
+static int audlpa_pmem_remove(struct audio *audio,
+ struct msm_audio_pmem_info *info)
+{
+ struct audlpa_pmem_region *region;
+ struct list_head *ptr, *next;
+ int rc = -EINVAL;
+
+ list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
+ region = list_entry(ptr, struct audlpa_pmem_region, list);
+
+ if ((region != NULL) && (region->fd == info->fd) &&
+ (region->vaddr == info->vaddr)) {
+ if (region->ref_cnt) {
+ pr_debug("%s: region %p in use ref_cnt %d\n",
+ __func__, region, region->ref_cnt);
+ break;
+ }
+ rc = q6asm_memory_unmap(audio->ac,
+ (uint32_t)region->paddr,
+ IN);
+ if (rc < 0)
+ pr_aud_err("%s: memory unmap failed\n", __func__);
+
+ list_del(®ion->list);
+ put_pmem_file(region->file);
+ kfree(region);
+ rc = 0;
+ break;
+ }
+ }
+
+ return rc;
+}
+
+static int audlpa_pmem_lookup_vaddr(struct audio *audio, void *addr,
+ unsigned long len, struct audlpa_pmem_region **region)
+{
+ struct audlpa_pmem_region *region_elt;
+
+ int match_count = 0;
+
+ *region = NULL;
+
+ /* returns physical address or zero */
+ list_for_each_entry(region_elt, &audio->pmem_region_queue,
+ list) {
+ if (addr >= region_elt->vaddr &&
+ addr < region_elt->vaddr + region_elt->len &&
+ addr + len <= region_elt->vaddr + region_elt->len) {
+ /* offset since we could pass vaddr inside a registerd
+ * pmem buffer
+ */
+
+ match_count++;
+ if (!*region)
+ *region = region_elt;
+ }
+ }
+
+ if (match_count > 1) {
+ pr_aud_err("%s: multiple hits for vaddr %p, len %ld\n", __func__,
+ addr, len);
+ list_for_each_entry(region_elt,
+ &audio->pmem_region_queue, list) {
+ if (addr >= region_elt->vaddr &&
+ addr < region_elt->vaddr + region_elt->len &&
+ addr + len <= region_elt->vaddr + region_elt->len)
+ pr_aud_err("%s: \t%p, %ld --> %p\n", __func__,
+ region_elt->vaddr, region_elt->len,
+ (void *)region_elt->paddr);
+ }
+ }
+
+ return *region ? 0 : -1;
+}
+
+unsigned long audlpa_pmem_fixup(struct audio *audio, void *addr,
+ unsigned long len, int ref_up)
+{
+ struct audlpa_pmem_region *region;
+ unsigned long paddr;
+ int ret;
+
+ ret = audlpa_pmem_lookup_vaddr(audio, addr, len, ®ion);
+ if (ret) {
+ pr_aud_err("%s: lookup (%p, %ld) failed\n", __func__, addr, len);
+ return 0;
+ }
+ if (ref_up)
+ region->ref_cnt++;
+ else
+ region->ref_cnt--;
+ paddr = region->paddr + (addr - region->vaddr);
+ return paddr;
+}
+
+/* audio -> lock must be held at this point */
+static int audlpa_aio_buf_add(struct audio *audio, unsigned dir,
+ void __user *arg)
+{
+ struct audlpa_buffer_node *buf_node;
+
+ buf_node = kmalloc(sizeof(*buf_node), GFP_KERNEL);
+
+ if (!buf_node)
+ return -ENOMEM;
+
+ if (copy_from_user(&buf_node->buf, arg, sizeof(buf_node->buf))) {
+ kfree(buf_node);
+ return -EFAULT;
+ }
+
+ buf_node->paddr = audlpa_pmem_fixup(
+ audio, buf_node->buf.buf_addr,
+ buf_node->buf.buf_len, 1);
+ if (dir) {
+ /* write */
+ if (!buf_node->paddr ||
+ (buf_node->paddr & 0x1) ||
+ (buf_node->buf.data_len & 0x1)) {
+ kfree(buf_node);
+ return -EINVAL;
+ }
+ list_add_tail(&buf_node->list, &audio->out_queue);
+ pr_debug("%s, Added to list: addr: %lx, length = %d\n",
+ __func__, buf_node->paddr, buf_node->buf.data_len);
+ audlpa_async_send_data(audio, 0, 0);
+ } else {
+ /* read */
+ }
+ return 0;
+}
+
+static int config(struct audio *audio)
+{
+ int rc = 0;
+ if (!audio->out_prefill) {
+ if (audio->codec_ops.set_params != NULL) {
+ rc = audio->codec_ops.set_params(audio);
+ audio->out_prefill = 1;
+ }
+ }
+ return rc;
+}
+
+void q6_audlpa_out_cb(uint32_t opcode, uint32_t token,
+ uint32_t *payload, void *priv)
+{
+ struct audio *audio = (struct audio *) priv;
+
+ switch (opcode) {
+ case ASM_DATA_EVENT_WRITE_DONE:
+ pr_debug("%s: ASM_DATA_EVENT_WRITE_DONE, token = 0x%x\n",
+ __func__, token);
+ audlpa_async_send_data(audio, 1, token);
+ break;
+ case ASM_DATA_EVENT_EOS:
+ case ASM_DATA_CMDRSP_EOS:
+ pr_debug("%s: ASM_DATA_CMDRSP_EOS, teos = %d\n", __func__,
+ audio->teos);
+ if (audio->teos == 0) {
+ audio->teos = 1;
+ wake_up(&audio->write_wait);
+ }
+ break;
+ case ASM_SESSION_CMDRSP_GET_SESSION_TIME:
+ break;
+ default:
+ break;
+ }
+}
+
+static long pcm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ pr_debug("%s: cmd = %d\n", __func__, cmd);
+ return -EINVAL;
+}
+
+static int audlpa_set_pcm_params(void *data)
+{
+ struct audio *audio = (struct audio *)data;
+ int rc;
+
+ rc = q6asm_media_format_block_pcm(audio->ac, audio->out_sample_rate,
+ audio->out_channel_mode);
+ if (rc < 0)
+ pr_aud_err("%s: Format block pcm failed\n", __func__);
+ return rc;
+}
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct audio *audio = file->private_data;
+ int rc = -EINVAL;
+ uint64_t timestamp = 0;
+ uint64_t temp;
+
+ pr_debug("%s: audio_ioctl() cmd = %d\n", __func__, cmd);
+
+ if (cmd == AUDIO_GET_STATS) {
+ struct msm_audio_stats stats;
+
+ pr_aud_info("%s: audio_get_stats command\n", __func__);
+ memset(&stats, 0, sizeof(stats));
+ timestamp = q6asm_get_session_time(audio->ac);
+ if (timestamp < 0) {
+ pr_aud_err("%s: Get Session Time return value =%lld\n",
+ __func__, timestamp);
+ return -EAGAIN;
+ }
+ temp = (timestamp * 2 * audio->out_channel_mode);
+ temp = temp * (audio->out_sample_rate/1000);
+ temp = div_u64(temp, 1000);
+ audio->bytes_consumed = (uint32_t)(temp & 0xFFFFFFFF);
+ stats.byte_count = audio->bytes_consumed;
+ stats.unused[0] = (uint32_t)((temp >> 32) & 0xFFFFFFFF);
+ pr_debug("%s: bytes_consumed:lsb = %d, msb = %d,"
+ "timestamp = %lld\n", __func__,
+ audio->bytes_consumed, stats.unused[0], timestamp);
+ if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+ return -EFAULT;
+ return 0;
+ }
+
+ switch (cmd) {
+ case AUDIO_ENABLE_AUDPP:
+ break;
+
+ case AUDIO_SET_VOLUME:
+ break;
+
+ case AUDIO_SET_PAN:
+ break;
+
+ case AUDIO_SET_EQ:
+ break;
+ }
+
+ if (cmd == AUDIO_GET_EVENT) {
+ pr_debug("%s: AUDIO_GET_EVENT\n", __func__);
+ if (mutex_trylock(&audio->get_event_lock)) {
+ rc = audlpa_process_event_req(audio,
+ (void __user *) arg);
+ mutex_unlock(&audio->get_event_lock);
+ } else
+ rc = -EBUSY;
+ return rc;
+ }
+
+ if (cmd == AUDIO_ABORT_GET_EVENT) {
+ audio->event_abort = 1;
+ wake_up(&audio->event_wait);
+ return 0;
+ }
+
+ mutex_lock(&audio->lock);
+ switch (cmd) {
+ case AUDIO_START:
+ pr_aud_info("%s: AUDIO_START: Session %d\n", __func__,
+ audio->ac->session);
+ if (!audio->opened) {
+ pr_aud_err("%s: Driver not opened\n", __func__);
+ rc = -EFAULT;
+ goto fail;
+ }
+ rc = config(audio);
+ if (rc) {
+ pr_aud_err("%s: Out Configuration failed\n", __func__);
+ rc = -EFAULT;
+ goto fail;
+ }
+
+ rc = audio_enable(audio);
+ if (rc) {
+ pr_aud_err("%s: audio enable failed\n", __func__);
+ rc = -EFAULT;
+ goto fail;
+ } else {
+ struct asm_softpause_params param = {
+ .enable = SOFT_PAUSE_ENABLE,
+ .period = SOFT_PAUSE_PERIOD,
+ .step = SOFT_PAUSE_STEP,
+ .rampingcurve = SOFT_PAUSE_CURVE_LINEAR,
+ };
+ audio->out_enabled = 1;
+ audio->out_needed = 1;
+ rc = q6asm_set_volume(audio->ac, audio->volume);
+ if (rc < 0)
+ pr_aud_err("%s: Send Volume command failed rc=%d\n",
+ __func__, rc);
+ rc = q6asm_set_softpause(audio->ac, ¶m);
+ if (rc < 0)
+ pr_aud_err("%s: Send SoftPause Param failed rc=%d\n",
+ __func__, rc);
+ rc = q6asm_set_lrgain(audio->ac, 0x2000, 0x2000);
+ if (rc < 0)
+ pr_aud_err("%s: Send channel gain failed rc=%d\n",
+ __func__, rc);
+ /* disable mute by default */
+ rc = q6asm_set_mute(audio->ac, 0);
+ if (rc < 0)
+ pr_aud_err("%s: Send mute command failed rc=%d\n",
+ __func__, rc);
+ if (!list_empty(&audio->out_queue))
+ pr_aud_err("%s: write_list is not empty!!!\n",
+ __func__);
+ if (audio->stopped == 1)
+ audio->stopped = 0;
+ audlpa_prevent_sleep(audio);
+ }
+ break;
+
+ case AUDIO_STOP:
+ pr_aud_info("%s: AUDIO_STOP: session_id:%d\n", __func__,
+ audio->ac->session);
+ audio->stopped = 1;
+ audlpa_async_flush(audio);
+ audio->out_enabled = 0;
+ audio->out_needed = 0;
+ audio->drv_status &= ~ADRV_STATUS_PAUSE;
+ audlpa_allow_sleep(audio);
+ break;
+
+ case AUDIO_FLUSH:
+ pr_aud_info("%s: AUDIO_FLUSH: session_id:%d\n", __func__,
+ audio->ac->session);
+ audio->wflush = 1;
+ if (audio->out_enabled)
+ rc = audlpa_async_flush(audio);
+ else
+ audio->wflush = 0;
+ audio->wflush = 0;
+ break;
+
+ case AUDIO_SET_CONFIG:{
+ struct msm_audio_config config;
+ pr_aud_info("%s: AUDIO_SET_CONFIG\n", __func__);
+ if (copy_from_user(&config, (void *) arg, sizeof(config))) {
+ rc = -EFAULT;
+ pr_aud_err("%s: ERROR: copy from user\n", __func__);
+ break;
+ }
+ if (!((config.channel_count == 1) ||
+ (config.channel_count == 2))) {
+ rc = -EINVAL;
+ pr_aud_err("%s: ERROR: config.channel_count == %d\n",
+ __func__, config.channel_count);
+ break;
+ }
+
+ if (!((config.bits == 8) || (config.bits == 16) ||
+ (config.bits == 24))) {
+ rc = -EINVAL;
+ pr_aud_err("%s: ERROR: config.bits = %d\n", __func__,
+ config.bits);
+ break;
+ }
+ audio->out_sample_rate = config.sample_rate;
+ audio->out_channel_mode = config.channel_count;
+ audio->out_bits = config.bits;
+ audio->buffer_count = config.buffer_count;
+ audio->buffer_size = config.buffer_size;
+ rc = 0;
+ break;
+ }
+
+ case AUDIO_GET_CONFIG:{
+ struct msm_audio_config config;
+ config.buffer_count = audio->buffer_count;
+ config.buffer_size = audio->buffer_size;
+ config.sample_rate = audio->out_sample_rate;
+ config.channel_count = audio->out_channel_mode;
+ config.bits = audio->out_bits;
+
+ config.meta_field = 0;
+ config.unused[0] = 0;
+ config.unused[1] = 0;
+ config.unused[2] = 0;
+ if (copy_to_user((void *) arg, &config, sizeof(config)))
+ rc = -EFAULT;
+ else
+ rc = 0;
+ break;
+ }
+
+ case AUDIO_PAUSE:
+ pr_aud_info("%s: AUDIO_PAUSE %ld\n", __func__, arg);
+ if (arg == 1) {
+ rc = audlpa_pause(audio);
+ if (rc < 0)
+ pr_aud_err("%s: pause FAILED rc=%d\n", __func__,
+ rc);
+ audio->drv_status |= ADRV_STATUS_PAUSE;
+ } else if (arg == 0) {
+ if (audio->drv_status & ADRV_STATUS_PAUSE) {
+ rc = audio_enable(audio);
+ if (rc)
+ pr_aud_err("%s: audio enable failed\n",
+ __func__);
+ else {
+ audio->drv_status &= ~ADRV_STATUS_PAUSE;
+ audio->out_enabled = 1;
+ }
+ }
+ }
+ break;
+
+ case AUDIO_REGISTER_PMEM: {
+ struct msm_audio_pmem_info info;
+ pr_aud_info("%s: AUDIO_REGISTER_PMEM\n", __func__);
+ if (copy_from_user(&info, (void *) arg, sizeof(info)))
+ rc = -EFAULT;
+ else
+ rc = audlpa_pmem_add(audio, &info);
+ break;
+ }
+
+ case AUDIO_DEREGISTER_PMEM: {
+ struct msm_audio_pmem_info info;
+ pr_aud_info("%s: AUDIO_DEREGISTER_PMEM\n", __func__);
+ if (copy_from_user(&info, (void *) arg, sizeof(info)))
+ rc = -EFAULT;
+ else
+ rc = audlpa_pmem_remove(audio, &info);
+ break;
+ }
+ case AUDIO_ASYNC_WRITE:
+ pr_debug("%s: AUDIO_ASYNC_WRITE\n", __func__);
+ if (audio->drv_status & ADRV_STATUS_FSYNC)
+ rc = -EBUSY;
+ else
+ rc = audlpa_aio_buf_add(audio, 1, (void __user *) arg);
+ break;
+
+ case AUDIO_GET_SESSION_ID:
+ if (copy_to_user((void *) arg, &audio->ac->session,
+ sizeof(unsigned short)))
+ return -EFAULT;
+ rc = 0;
+ break;
+
+ default:
+ rc = audio->codec_ops.ioctl(file, cmd, arg);
+ }
+fail:
+ mutex_unlock(&audio->lock);
+ return rc;
+}
+
+/* Only useful in tunnel-mode */
+int audlpa_async_fsync(struct audio *audio)
+{
+ int rc = 0;
+
+ pr_aud_info("%s:Session %d\n", __func__, audio->ac->session);
+
+ /* Blocking client sends more data */
+ mutex_lock(&audio->lock);
+ audio->drv_status |= ADRV_STATUS_FSYNC;
+ mutex_unlock(&audio->lock);
+
+ mutex_lock(&audio->write_lock);
+ audio->teos = 0;
+
+ rc = wait_event_interruptible(audio->write_wait,
+ ((list_empty(&audio->out_queue)) ||
+ audio->wflush || audio->stopped));
+
+ if (audio->wflush || audio->stopped)
+ goto flush_event;
+
+ if (rc < 0) {
+ pr_aud_err("%s: wait event for list_empty failed, rc = %d\n",
+ __func__, rc);
+ goto done;
+ }
+
+ rc = q6asm_cmd(audio->ac, CMD_EOS);
+
+ if (rc < 0) {
+ pr_aud_err("%s: q6asm_cmd failed, rc = %d", __func__, rc);
+ goto done;
+ }
+ rc = wait_event_interruptible_timeout(audio->write_wait,
+ (audio->teos || audio->wflush ||
+ audio->stopped), 5*HZ);
+
+ if (rc < 0) {
+ pr_aud_err("%s: wait event for teos failed, rc = %d\n", __func__,
+ rc);
+ goto done;
+ }
+
+ if (audio->teos == 1) {
+ rc = audio_enable(audio);
+ if (rc)
+ pr_aud_err("%s: audio enable failed\n", __func__);
+ else {
+ audio->drv_status &= ~ADRV_STATUS_PAUSE;
+ audio->out_enabled = 1;
+ audio->out_needed = 1;
+ }
+ }
+
+flush_event:
+ if (audio->stopped || audio->wflush)
+ rc = -EBUSY;
+
+done:
+ mutex_unlock(&audio->write_lock);
+ mutex_lock(&audio->lock);
+ audio->drv_status &= ~ADRV_STATUS_FSYNC;
+ mutex_unlock(&audio->lock);
+
+ return rc;
+}
+
+int audlpa_fsync(struct file *file, int datasync)
+{
+ struct audio *audio = file->private_data;
+
+ return audlpa_async_fsync(audio);
+}
+
+static void audlpa_reset_pmem_region(struct audio *audio)
+{
+ struct audlpa_pmem_region *region;
+ struct list_head *ptr, *next;
+
+ list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
+ region = list_entry(ptr, struct audlpa_pmem_region, list);
+ list_del(®ion->list);
+ put_pmem_file(region->file);
+ kfree(region);
+ }
+
+ return;
+}
+
+static void audlpa_unmap_pmem_region(struct audio *audio)
+{
+ struct audlpa_pmem_region *region;
+ struct list_head *ptr, *next;
+ int rc = -EINVAL;
+
+ pr_aud_info("%s:\n", __func__);
+ list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
+ region = list_entry(ptr, struct audlpa_pmem_region, list);
+ if (region != NULL) {
+ pr_aud_info("%s: phy_address = 0x%lx\n", __func__,
+ region->paddr);
+ rc = q6asm_memory_unmap(audio->ac,
+ (uint32_t)region->paddr, IN);
+ if (rc < 0)
+ pr_aud_err("%s: memory unmap failed\n", __func__);
+ }
+ }
+}
+
+static int audio_release(struct inode *inode, struct file *file)
+{
+ struct audio *audio = file->private_data;
+
+ pr_aud_info("%s: audio instance 0x%08x freeing, session %d\n", __func__,
+ (int)audio, audio->ac->session);
+
+ mutex_lock(&audio->lock);
+ audio->wflush = 1;
+ if (audio->out_enabled)
+ audlpa_async_flush(audio);
+ audio->wflush = 0;
+ audlpa_unmap_pmem_region(audio);
+ audio_disable(audio);
+ msm_clear_session_id(audio->ac->session);
+ auddev_unregister_evt_listner(AUDDEV_CLNT_DEC, audio->ac->session);
+ q6asm_audio_client_free(audio->ac);
+ audlpa_reset_pmem_region(audio);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ unregister_early_suspend(&audio->suspend_ctl.node);
+#endif
+ audio->opened = 0;
+ audio->out_enabled = 0;
+ audio->out_prefill = 0;
+ audio->event_abort = 1;
+ wake_up(&audio->event_wait);
+ audlpa_reset_event_queue(audio);
+ iounmap(audio->data);
+ pmem_kfree(audio->phys);
+ if (audio->stopped == 0)
+ audlpa_allow_sleep(audio);
+ wake_lock_destroy(&audio->wakelock);
+
+ mutex_unlock(&audio->lock);
+#ifdef CONFIG_DEBUG_FS
+ if (audio->dentry)
+ debugfs_remove(audio->dentry);
+#endif
+ kfree(audio);
+ return 0;
+}
+
+static void audlpa_post_event(struct audio *audio, int type,
+ union msm_audio_event_payload payload)
+{
+ struct audlpa_event *e_node = NULL;
+
+ spin_lock(&audio->event_queue_lock);
+
+ pr_debug("%s:\n", __func__);
+ if (!list_empty(&audio->free_event_queue)) {
+ e_node = list_first_entry(&audio->free_event_queue,
+ struct audlpa_event, list);
+ list_del(&e_node->list);
+ } else {
+ e_node = kmalloc(sizeof(struct audlpa_event), GFP_ATOMIC);
+ if (!e_node) {
+ pr_aud_err("%s: No mem to post event %d\n", __func__, type);
+ return;
+ }
+ }
+
+ e_node->event_type = type;
+ e_node->payload = payload;
+
+ list_add_tail(&e_node->list, &audio->event_queue);
+ spin_unlock(&audio->event_queue_lock);
+ wake_up(&audio->event_wait);
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audlpa_suspend(struct early_suspend *h)
+{
+ struct audlpa_suspend_ctl *ctl =
+ container_of(h, struct audlpa_suspend_ctl, node);
+ union msm_audio_event_payload payload;
+
+ pr_aud_info("%s:\n", __func__);
+ audlpa_post_event(ctl->audio, AUDIO_EVENT_SUSPEND, payload);
+}
+
+static void audlpa_resume(struct early_suspend *h)
+{
+ struct audlpa_suspend_ctl *ctl =
+ container_of(h, struct audlpa_suspend_ctl, node);
+ union msm_audio_event_payload payload;
+
+ pr_aud_info("%s:\n", __func__);
+ audlpa_post_event(ctl->audio, AUDIO_EVENT_RESUME, payload);
+}
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+static ssize_t audlpa_debug_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static ssize_t audlpa_debug_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ const int debug_bufmax = 4096;
+ static char buffer[4096];
+ int n = 0;
+ struct audio *audio = file->private_data;
+
+ mutex_lock(&audio->lock);
+ n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "out_enabled %d\n", audio->out_enabled);
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "stopped %d\n", audio->stopped);
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "volume %x\n", audio->volume);
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "sample rate %d\n",
+ audio->out_sample_rate);
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "channel mode %d\n",
+ audio->out_channel_mode);
+ mutex_unlock(&audio->lock);
+ /* Following variables are only useful for debugging when
+ * when playback halts unexpectedly. Thus, no mutual exclusion
+ * enforced
+ */
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "wflush %d\n", audio->wflush);
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "running %d\n", audio->running);
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "out_needed %d\n", audio->out_needed);
+ buffer[n] = 0;
+ return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static const struct file_operations audlpa_debug_fops = {
+ .read = audlpa_debug_read,
+ .open = audlpa_debug_open,
+};
+#endif
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+ struct audio *audio = NULL;
+ int rc, i, dec_attrb = 0;
+ struct audlpa_event *e_node = NULL;
+#ifdef CONFIG_DEBUG_FS
+ /* 4 bytes represents decoder number, 1 byte for terminate string */
+ char name[sizeof "msm_lpa_" + 5];
+#endif
+ char wake_lock_name[24];
+
+ /* Allocate audio instance, set to zero */
+ audio = kzalloc(sizeof(struct audio), GFP_KERNEL);
+ if (!audio) {
+ pr_aud_err("%s: no memory to allocate audio instance\n", __func__);
+ rc = -ENOMEM;
+ goto done;
+ }
+
+ if ((file->f_mode & FMODE_WRITE) && !(file->f_mode & FMODE_READ)) {
+ pr_aud_info("%s: Tunnel Mode playback\n", __func__);
+ } else {
+ kfree(audio);
+ rc = -EACCES;
+ goto done;
+ }
+
+ /* Allocate the decoder based on inode minor number*/
+ audio->minor_no = iminor(inode);
+
+ if (audio->minor_no >= ARRAY_SIZE(audlpa_decs)) {
+ pr_aud_err("%s: incorrect inode %d\n", __func__, audio->minor_no);
+ kfree(audio);
+ rc = -EINVAL;
+ goto done;
+ }
+
+ dec_attrb |= audlpa_decs[audio->minor_no].dec_attrb;
+ audio->codec_ops.ioctl = audlpa_decs[audio->minor_no].ioctl;
+ audio->codec_ops.set_params = audlpa_decs[audio->minor_no].set_params;
+ audio->buffer_size = BUFSZ;
+ audio->buffer_count = MAX_BUF;
+
+ audio->ac = q6asm_audio_client_alloc((app_cb)q6_audlpa_out_cb,
+ (void *)audio);
+ if (!audio->ac) {
+ pr_aud_err("%s: Could not allocate memory for lpa client\n",
+ __func__);
+ rc = -ENOMEM;
+ goto err;
+ }
+ rc = q6asm_open_write(audio->ac, FORMAT_LINEAR_PCM);
+ if (rc < 0) {
+ pr_aud_info("%s: lpa out open failed\n", __func__);
+ goto err;
+ }
+
+ pr_debug("%s: Set mode to AIO session[%d]\n",
+ __func__,
+ audio->ac->session);
+ rc = q6asm_set_io_mode(audio->ac, ASYNC_IO_MODE);
+ if (rc < 0)
+ pr_aud_err("%s: Set IO mode failed\n", __func__);
+
+
+ /* Initialize all locks of audio instance */
+ mutex_init(&audio->lock);
+ mutex_init(&audio->write_lock);
+ mutex_init(&audio->get_event_lock);
+ spin_lock_init(&audio->dsp_lock);
+ init_waitqueue_head(&audio->write_wait);
+ INIT_LIST_HEAD(&audio->out_queue);
+ INIT_LIST_HEAD(&audio->pmem_region_queue);
+ INIT_LIST_HEAD(&audio->free_event_queue);
+ INIT_LIST_HEAD(&audio->event_queue);
+ init_waitqueue_head(&audio->wait);
+ init_waitqueue_head(&audio->event_wait);
+ spin_lock_init(&audio->event_queue_lock);
+ snprintf(wake_lock_name, sizeof wake_lock_name, "audio_lpa_%x",
+ audio->ac->session);
+ wake_lock_init(&audio->wakelock, WAKE_LOCK_SUSPEND, wake_lock_name);
+
+ audio->out_sample_rate = 44100;
+ audio->out_channel_mode = 2;
+ audio->out_bits = 16;
+ audio->volume = 0x2000;
+
+ file->private_data = audio;
+ audio->opened = 1;
+ audio->out_enabled = 0;
+ audio->out_prefill = 0;
+ audio->bytes_consumed = 0;
+
+ audio->device_events = AUDDEV_EVT_STREAM_VOL_CHG;
+ audio->drv_status &= ~ADRV_STATUS_PAUSE;
+
+ rc = auddev_register_evt_listner(audio->device_events,
+ AUDDEV_CLNT_DEC,
+ audio->ac->session,
+ lpa_listner,
+ (void *)audio);
+ if (rc) {
+ pr_aud_err("%s: failed to register listner\n", __func__);
+ goto err;
+ }
+
+#ifdef CONFIG_DEBUG_FS
+ snprintf(name, sizeof name, "msm_lpa_%04x", audio->ac->session);
+ audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+ NULL, (void *) audio, &audlpa_debug_fops);
+
+ if (IS_ERR(audio->dentry))
+ pr_aud_info("%s: debugfs_create_file failed\n", __func__);
+#endif
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ audio->suspend_ctl.node.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
+ audio->suspend_ctl.node.resume = audlpa_resume;
+ audio->suspend_ctl.node.suspend = audlpa_suspend;
+ audio->suspend_ctl.audio = audio;
+ register_early_suspend(&audio->suspend_ctl.node);
+#endif
+ for (i = 0; i < AUDLPA_EVENT_NUM; i++) {
+ e_node = kmalloc(sizeof(struct audlpa_event), GFP_KERNEL);
+ if (e_node)
+ list_add_tail(&e_node->list, &audio->free_event_queue);
+ else {
+ pr_aud_err("%s: event pkt alloc failed\n", __func__);
+ break;
+ }
+ }
+ pr_aud_info("%s: audio instance 0x%08x created session[%d]\n", __func__,
+ (int)audio,
+ audio->ac->session);
+done:
+ return rc;
+err:
+ q6asm_audio_client_free(audio->ac);
+ iounmap(audio->data);
+ pmem_kfree(audio->phys);
+ kfree(audio);
+ return rc;
+}
+
+static const struct file_operations audio_lpa_fops = {
+ .owner = THIS_MODULE,
+ .open = audio_open,
+ .release = audio_release,
+ .unlocked_ioctl = audio_ioctl,
+ .fsync = audlpa_fsync,
+};
+
+static dev_t audlpa_devno;
+static struct class *audlpa_class;
+struct audlpa_device {
+ const char *name;
+ struct device *device;
+ struct cdev cdev;
+};
+
+static struct audlpa_device *audlpa_devices;
+
+static void audlpa_create(struct audlpa_device *adev, const char *name,
+ struct device *parent, dev_t devt)
+{
+ struct device *dev;
+ int rc;
+
+ dev = device_create(audlpa_class, parent, devt, "%s", name);
+ if (IS_ERR(dev))
+ return;
+
+ cdev_init(&adev->cdev, &audio_lpa_fops);
+ adev->cdev.owner = THIS_MODULE;
+
+ rc = cdev_add(&adev->cdev, devt, 1);
+ if (rc < 0) {
+ device_destroy(audlpa_class, devt);
+ } else {
+ adev->device = dev;
+ adev->name = name;
+ }
+}
+
+static int __init audio_init(void)
+{
+ int rc;
+ int n = ARRAY_SIZE(audlpa_decs);
+
+ audlpa_devices = kzalloc(sizeof(struct audlpa_device) * n, GFP_KERNEL);
+ if (!audlpa_devices)
+ return -ENOMEM;
+
+ audlpa_class = class_create(THIS_MODULE, "audlpa");
+ if (IS_ERR(audlpa_class))
+ goto fail_create_class;
+
+ rc = alloc_chrdev_region(&audlpa_devno, 0, n, "msm_audio_lpa");
+ if (rc < 0)
+ goto fail_alloc_region;
+
+ for (n = 0; n < ARRAY_SIZE(audlpa_decs); n++) {
+ audlpa_create(audlpa_devices + n,
+ audlpa_decs[n].name, NULL,
+ MKDEV(MAJOR(audlpa_devno), n));
+ }
+
+ return 0;
+
+fail_alloc_region:
+ class_unregister(audlpa_class);
+ return rc;
+fail_create_class:
+ kfree(audlpa_devices);
+ return -ENOMEM;
+}
+
+static void __exit audio_exit(void)
+{
+ class_unregister(audlpa_class);
+ kfree(audlpa_devices);
+}
+
+module_init(audio_init);
+module_exit(audio_exit);
+
+MODULE_DESCRIPTION("MSM LPA driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp6v3/audio_lpa.h b/arch/arm/mach-msm/qdsp6v3/audio_lpa.h
new file mode 100644
index 00000000000..8e7a22cd9c8
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v3/audio_lpa.h
@@ -0,0 +1,129 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Code Aurora nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef AUDIO_LPA_H
+#define AUDIO_LPA_H
+
+#include
+#include
+
+#define ADRV_STATUS_OBUF_GIVEN 0x00000001
+#define ADRV_STATUS_IBUF_GIVEN 0x00000002
+#define ADRV_STATUS_FSYNC 0x00000004
+#define ADRV_STATUS_PAUSE 0x00000008
+
+#define SOFT_PAUSE_PERIOD 30 /* ramp up/down for 30ms */
+#define SOFT_PAUSE_STEP 2000 /* Step value 2ms or 2000us */
+enum {
+ SOFT_PAUSE_CURVE_LINEAR = 0,
+ SOFT_PAUSE_CURVE_EXP,
+ SOFT_PAUSE_CURVE_LOG,
+};
+
+struct buffer {
+ void *data;
+ unsigned size;
+ unsigned used; /* Input usage actual DSP produced PCM size */
+ unsigned addr;
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+struct audlpa_suspend_ctl {
+ struct early_suspend node;
+ struct audio *audio;
+};
+#endif
+
+struct codec_operations {
+ long (*ioctl)(struct file *, unsigned int, unsigned long);
+ int (*set_params)(void *);
+};
+
+struct audio {
+ spinlock_t dsp_lock;
+
+ uint8_t out_needed; /* number of buffers the dsp is waiting for */
+ struct list_head out_queue; /* queue to retain output buffers */
+
+ struct mutex lock;
+ struct mutex write_lock;
+ wait_queue_head_t write_wait;
+
+ struct audio_client *ac;
+
+ /* configuration to use on next enable */
+ uint32_t out_sample_rate;
+ uint32_t out_channel_mode;
+ uint32_t out_bits; /* bits per sample (used by PCM decoder) */
+
+ /* data allocated for various buffers */
+ char *data;
+ int32_t phys; /* physical address of write buffer */
+
+ uint32_t drv_status;
+ int wflush; /* Write flush */
+ int opened;
+ int out_enabled;
+ int out_prefill;
+ int running;
+ int stopped; /* set when stopped, cleared on flush */
+ int buf_refresh;
+ int teos; /* valid only if tunnel mode & no data left for decoder */
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ struct audlpa_suspend_ctl suspend_ctl;
+#endif
+
+ struct wake_lock wakelock;
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *dentry;
+#endif
+
+ wait_queue_head_t wait;
+ struct list_head free_event_queue;
+ struct list_head event_queue;
+ wait_queue_head_t event_wait;
+ spinlock_t event_queue_lock;
+ struct mutex get_event_lock;
+ int event_abort;
+
+ uint32_t device_events;
+
+ struct list_head pmem_region_queue; /* protected by lock */
+
+ int eq_enable;
+ int eq_needs_commit;
+ uint32_t volume;
+
+ unsigned int minor_no;
+ struct codec_operations codec_ops;
+ uint32_t buffer_size;
+ uint32_t buffer_count;
+ uint32_t bytes_consumed;
+};
+
+#endif /* !AUDIO_LPA_H */
diff --git a/arch/arm/mach-msm/qdsp6v3/audio_mvs.c b/arch/arm/mach-msm/qdsp6v3/audio_mvs.c
new file mode 100644
index 00000000000..529b5840b06
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v3/audio_mvs.c
@@ -0,0 +1,998 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* Each buffer is 20 ms, queue holds 200 ms of data. */
+#define MVS_MAX_Q_LEN 10
+
+/* Length of the DSP frame info header added to the voc packet. */
+#define DSP_FRAME_HDR_LEN 1
+
+enum audio_mvs_state_type {
+ AUDIO_MVS_CLOSED,
+ AUDIO_MVS_STARTED,
+ AUDIO_MVS_STOPPED
+};
+
+struct audio_mvs_buf_node {
+ struct list_head list;
+ struct msm_audio_mvs_frame frame;
+};
+
+struct audio_mvs_info_type {
+ enum audio_mvs_state_type state;
+
+ uint32_t mvs_mode;
+ uint32_t rate_type;
+ uint32_t dtx_mode;
+
+ struct list_head in_queue;
+ struct list_head free_in_queue;
+
+ struct list_head out_queue;
+ struct list_head free_out_queue;
+
+ wait_queue_head_t out_wait;
+
+ struct mutex lock;
+ struct mutex in_lock;
+ struct mutex out_lock;
+
+ spinlock_t dsp_lock;
+
+ struct wake_lock suspend_lock;
+ struct wake_lock idle_lock;
+
+ void *memory_chunk;
+};
+
+static struct audio_mvs_info_type audio_mvs_info;
+
+static uint32_t audio_mvs_get_rate(uint32_t mvs_mode, uint32_t rate_type)
+{
+ uint32_t cvs_rate;
+
+ if (mvs_mode == MVS_MODE_AMR_WB)
+ cvs_rate = rate_type - MVS_AMR_MODE_0660;
+ else
+ cvs_rate = rate_type;
+
+ pr_debug("%s: CVS rate is %d for MVS mode %d\n",
+ __func__, cvs_rate, mvs_mode);
+
+ return cvs_rate;
+}
+
+static void audio_mvs_process_ul_pkt(uint8_t *voc_pkt,
+ uint32_t pkt_len,
+ void *private_data)
+{
+ struct audio_mvs_buf_node *buf_node = NULL;
+ struct audio_mvs_info_type *audio = private_data;
+ unsigned long dsp_flags;
+
+ /* Copy up-link packet into out_queue. */
+ spin_lock_irqsave(&audio->dsp_lock, dsp_flags);
+
+ if (!list_empty(&audio->free_out_queue)) {
+ buf_node = list_first_entry(&audio->free_out_queue,
+ struct audio_mvs_buf_node,
+ list);
+ list_del(&buf_node->list);
+
+ switch (audio->mvs_mode) {
+ case MVS_MODE_AMR:
+ case MVS_MODE_AMR_WB: {
+ /* Remove the DSP frame info header. Header format:
+ * Bits 0-3: Frame rate
+ * Bits 4-7: Frame type
+ */
+ buf_node->frame.frame_type = ((*voc_pkt) & 0xF0) >> 4;
+ buf_node->frame.frame_rate = ((*voc_pkt) & 0x0F);
+ voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+ buf_node->frame.len = pkt_len - DSP_FRAME_HDR_LEN;
+
+ memcpy(&buf_node->frame.voc_pkt[0],
+ voc_pkt,
+ buf_node->frame.len);
+
+ list_add_tail(&buf_node->list, &audio->out_queue);
+ break;
+ }
+
+ case MVS_MODE_IS127: {
+ buf_node->frame.frame_type = 0;
+ voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+ buf_node->frame.len = pkt_len - DSP_FRAME_HDR_LEN;
+
+ memcpy(&buf_node->frame.voc_pkt[0],
+ voc_pkt,
+ buf_node->frame.len);
+
+ list_add_tail(&buf_node->list, &audio->out_queue);
+ break;
+ }
+
+ case MVS_MODE_G729A: {
+ /* G729 frames are 10ms each, but the DSP works with
+ * 20ms frames and sends two 10ms frames per buffer.
+ * Extract the two frames and put them in separate
+ * buffers.
+ */
+ /* Remove the first DSP frame info header.
+ * Header format:
+ * Bits 0-1: Frame type
+ */
+ buf_node->frame.frame_type = (*voc_pkt) & 0x03;
+ voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+ /* There are two frames in the buffer. Length of the
+ * first frame:
+ */
+ buf_node->frame.len = (pkt_len -
+ 2 * DSP_FRAME_HDR_LEN) / 2;
+
+ memcpy(&buf_node->frame.voc_pkt[0],
+ voc_pkt,
+ buf_node->frame.len);
+ voc_pkt = voc_pkt + buf_node->frame.len;
+
+ list_add_tail(&buf_node->list, &audio->out_queue);
+
+ /* Get another buffer from the free Q and fill in the
+ * second frame.
+ */
+ if (!list_empty(&audio->free_out_queue)) {
+ buf_node =
+ list_first_entry(&audio->free_out_queue,
+ struct audio_mvs_buf_node,
+ list);
+ list_del(&buf_node->list);
+
+ /* Remove the second DSP frame info header.
+ * Header format:
+ * Bits 0-1: Frame type
+ */
+ buf_node->frame.frame_type = (*voc_pkt) & 0x03;
+ voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+ /* There are two frames in the buffer. Length
+ * of the first frame:
+ */
+ buf_node->frame.len = (pkt_len -
+ 2 * DSP_FRAME_HDR_LEN) / 2;
+
+ memcpy(&buf_node->frame.voc_pkt[0],
+ voc_pkt,
+ buf_node->frame.len);
+
+ list_add_tail(&buf_node->list,
+ &audio->out_queue);
+
+ } else {
+ /* Drop the second frame. */
+ pr_aud_err("%s: UL data dropped, read is slow\n",
+ __func__);
+ }
+
+ break;
+ }
+
+ case MVS_MODE_G711A: {
+ /* G711 frames are 10ms each, but the DSP works with
+ * 20ms frames and sends two 10ms frames per buffer.
+ * Extract the two frames and put them in separate
+ * buffers.
+ */
+ /* Remove the first DSP frame info header.
+ * Header format:
+ * Bits 0-1: Frame type
+ * Bits 2-3: Frame rate
+ */
+ buf_node->frame.frame_type = (*voc_pkt) & 0x03;
+ voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+ /* There are two frames in the buffer. Length of the
+ * first frame:
+ */
+ buf_node->frame.len = (pkt_len -
+ 2 * DSP_FRAME_HDR_LEN) / 2;
+
+ memcpy(&buf_node->frame.voc_pkt[0],
+ voc_pkt,
+ buf_node->frame.len);
+ voc_pkt = voc_pkt + buf_node->frame.len;
+
+ list_add_tail(&buf_node->list, &audio->out_queue);
+
+ /* Get another buffer from the free Q and fill in the
+ * second frame.
+ */
+ if (!list_empty(&audio->free_out_queue)) {
+ buf_node =
+ list_first_entry(&audio->free_out_queue,
+ struct audio_mvs_buf_node,
+ list);
+ list_del(&buf_node->list);
+
+ /* Remove the second DSP frame info header.
+ * Header format:
+ * Bits 0-1: Frame type
+ * Bits 2-3: Frame rate
+ */
+ buf_node->frame.frame_type = (*voc_pkt) & 0x03;
+ voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+ /* There are two frames in the buffer. Length
+ * of the second frame:
+ */
+ buf_node->frame.len = (pkt_len -
+ 2 * DSP_FRAME_HDR_LEN) / 2;
+
+ memcpy(&buf_node->frame.voc_pkt[0],
+ voc_pkt,
+ buf_node->frame.len);
+
+ list_add_tail(&buf_node->list,
+ &audio->out_queue);
+ } else {
+ /* Drop the second frame. */
+ pr_aud_err("%s: UL data dropped, read is slow\n",
+ __func__);
+ }
+ break;
+ }
+
+ default: {
+ buf_node->frame.frame_type = 0;
+
+ buf_node->frame.len = pkt_len;
+
+ memcpy(&buf_node->frame.voc_pkt[0],
+ voc_pkt,
+ buf_node->frame.len);
+
+ list_add_tail(&buf_node->list, &audio->out_queue);
+ }
+ }
+ } else {
+ pr_aud_err("%s: UL data dropped, read is slow\n", __func__);
+ }
+
+ spin_unlock_irqrestore(&audio->dsp_lock, dsp_flags);
+
+ wake_up(&audio->out_wait);
+}
+
+static void audio_mvs_process_dl_pkt(uint8_t *voc_pkt,
+ uint32_t *pkt_len,
+ void *private_data)
+{
+ struct audio_mvs_buf_node *buf_node = NULL;
+ struct audio_mvs_info_type *audio = private_data;
+ unsigned long dsp_flags;
+
+ spin_lock_irqsave(&audio->dsp_lock, dsp_flags);
+
+ if (!list_empty(&audio->in_queue)) {
+ uint32_t rate_type = audio_mvs_get_rate(audio->mvs_mode,
+ audio->rate_type);
+
+ buf_node = list_first_entry(&audio->in_queue,
+ struct audio_mvs_buf_node,
+ list);
+ list_del(&buf_node->list);
+
+ switch (audio->mvs_mode) {
+ case MVS_MODE_AMR:
+ case MVS_MODE_AMR_WB: {
+ /* Add the DSP frame info header. Header format:
+ * Bits 0-3: Frame rate
+ * Bits 4-7: Frame type
+ */
+ *voc_pkt = ((buf_node->frame.frame_type & 0x0F) << 4) |
+ (rate_type & 0x0F);
+ voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+ *pkt_len = buf_node->frame.len + DSP_FRAME_HDR_LEN;
+
+ memcpy(voc_pkt,
+ &buf_node->frame.voc_pkt[0],
+ buf_node->frame.len);
+
+ list_add_tail(&buf_node->list, &audio->free_in_queue);
+ break;
+ }
+
+ case MVS_MODE_IS127: {
+ /* Add the DSP frame info header. Header format:
+ * Bits 0-3: Frame rate
+ * Bits 4-7: Frame type
+ */
+ *voc_pkt = rate_type & 0x0F;
+ voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+ *pkt_len = buf_node->frame.len + DSP_FRAME_HDR_LEN;
+
+ memcpy(voc_pkt,
+ &buf_node->frame.voc_pkt[0],
+ buf_node->frame.len);
+
+ list_add_tail(&buf_node->list, &audio->free_in_queue);
+ break;
+ }
+
+ case MVS_MODE_G729A: {
+ /* G729 frames are 10ms each but the DSP expects 20ms
+ * worth of data, so send two 10ms frames per buffer.
+ */
+ /* Add the first DSP frame info header. Header format:
+ * Bits 0-1: Frame type
+ */
+ *voc_pkt = buf_node->frame.frame_type & 0x03;
+ voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+ *pkt_len = buf_node->frame.len + DSP_FRAME_HDR_LEN;
+
+ memcpy(voc_pkt,
+ &buf_node->frame.voc_pkt[0],
+ buf_node->frame.len);
+ voc_pkt = voc_pkt + buf_node->frame.len;
+
+ list_add_tail(&buf_node->list, &audio->free_in_queue);
+
+ if (!list_empty(&audio->in_queue)) {
+ /* Get the second buffer. */
+ buf_node = list_first_entry(&audio->in_queue,
+ struct audio_mvs_buf_node,
+ list);
+ list_del(&buf_node->list);
+
+ /* Add the second DSP frame info header.
+ * Header format:
+ * Bits 0-1: Frame type
+ */
+ *voc_pkt = buf_node->frame.frame_type & 0x03;
+ voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+ *pkt_len = *pkt_len +
+ buf_node->frame.len + DSP_FRAME_HDR_LEN;
+
+ memcpy(voc_pkt,
+ &buf_node->frame.voc_pkt[0],
+ buf_node->frame.len);
+
+ list_add_tail(&buf_node->list,
+ &audio->free_in_queue);
+ } else {
+ /* Only 10ms worth of data is available, signal
+ * erasure frame.
+ */
+ *voc_pkt = MVS_G729A_ERASURE & 0x03;
+
+ *pkt_len = *pkt_len + DSP_FRAME_HDR_LEN;
+ }
+
+ break;
+ }
+
+ case MVS_MODE_G711A: {
+ /* G711 frames are 10ms each but the DSP expects 20ms
+ * worth of data, so send two 10ms frames per buffer.
+ */
+ /* Add the first DSP frame info header. Header format:
+ * Bits 0-1: Frame type
+ * Bits 2-3: Frame rate
+ */
+ *voc_pkt = ((rate_type & 0x0F) << 2) |
+ (buf_node->frame.frame_type & 0x03);
+ voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+ *pkt_len = buf_node->frame.len + DSP_FRAME_HDR_LEN;
+
+ memcpy(voc_pkt,
+ &buf_node->frame.voc_pkt[0],
+ buf_node->frame.len);
+ voc_pkt = voc_pkt + buf_node->frame.len;
+
+ list_add_tail(&buf_node->list, &audio->free_in_queue);
+
+ if (!list_empty(&audio->in_queue)) {
+ /* Get the second buffer. */
+ buf_node = list_first_entry(&audio->in_queue,
+ struct audio_mvs_buf_node,
+ list);
+ list_del(&buf_node->list);
+
+ /* Add the second DSP frame info header.
+ * Header format:
+ * Bits 0-1: Frame type
+ * Bits 2-3: Frame rate
+ */
+ *voc_pkt = ((rate_type & 0x0F) << 2) |
+ (buf_node->frame.frame_type & 0x03);
+ voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+ *pkt_len = *pkt_len +
+ buf_node->frame.len + DSP_FRAME_HDR_LEN;
+
+ memcpy(voc_pkt,
+ &buf_node->frame.voc_pkt[0],
+ buf_node->frame.len);
+
+ list_add_tail(&buf_node->list,
+ &audio->free_in_queue);
+ } else {
+ /* Only 10ms worth of data is available, signal
+ * erasure frame.
+ */
+ *voc_pkt = ((rate_type & 0x0F) << 2) |
+ (MVS_G711A_ERASURE & 0x03);
+
+ *pkt_len = *pkt_len + DSP_FRAME_HDR_LEN;
+ }
+ break;
+ }
+
+ default: {
+ *pkt_len = buf_node->frame.len;
+
+ memcpy(voc_pkt,
+ &buf_node->frame.voc_pkt[0],
+ buf_node->frame.len);
+
+ list_add_tail(&buf_node->list, &audio->free_in_queue);
+ }
+ }
+ } else {
+ *pkt_len = 0;
+
+ pr_aud_info("%s: No DL data available to send to MVS\n", __func__);
+ }
+
+ spin_unlock_irqrestore(&audio->dsp_lock, dsp_flags);
+}
+
+static uint32_t audio_mvs_get_media_type(uint32_t mvs_mode, uint32_t rate_type)
+{
+ uint32_t media_type;
+
+ switch (mvs_mode) {
+ case MVS_MODE_IS127:
+ media_type = VSS_MEDIA_ID_EVRC_MODEM;
+ break;
+
+ case MVS_MODE_AMR:
+ media_type = VSS_MEDIA_ID_AMR_NB_MODEM;
+ break;
+
+ case MVS_MODE_LINEAR_PCM:
+ media_type = VSS_MEDIA_ID_PCM_NB;
+ break;
+
+ case MVS_MODE_PCM:
+ media_type = VSS_MEDIA_ID_PCM_NB;
+ break;
+
+ case MVS_MODE_AMR_WB:
+ media_type = VSS_MEDIA_ID_AMR_WB_MODEM;
+ break;
+
+ case MVS_MODE_G729A:
+ media_type = VSS_MEDIA_ID_G729;
+ break;
+
+ case MVS_MODE_G711A:
+ if (rate_type == MVS_G711A_MODE_MULAW)
+ media_type = VSS_MEDIA_ID_G711_MULAW;
+ else
+ media_type = VSS_MEDIA_ID_G711_ALAW;
+ break;
+
+ default:
+ media_type = VSS_MEDIA_ID_PCM_NB;
+ }
+
+ pr_debug("%s: media_type is 0x%x\n", __func__, media_type);
+
+ return media_type;
+}
+
+static uint32_t audio_mvs_get_network_type(uint32_t mvs_mode)
+{
+ uint32_t network_type;
+
+ switch (mvs_mode) {
+ case MVS_MODE_IS127:
+ case MVS_MODE_AMR:
+ case MVS_MODE_LINEAR_PCM:
+ case MVS_MODE_PCM:
+ case MVS_MODE_G729A:
+ case MVS_MODE_G711A:
+ network_type = VSS_NETWORK_ID_VOIP_NB;
+ break;
+
+ case MVS_MODE_AMR_WB:
+ network_type = VSS_NETWORK_ID_VOIP_WB;
+ break;
+
+ default:
+ network_type = VSS_NETWORK_ID_DEFAULT;
+ }
+
+ pr_debug("%s: network_type is 0x%x\n", __func__, network_type);
+
+ return network_type;
+}
+
+static int audio_mvs_start(struct audio_mvs_info_type *audio)
+{
+ int rc = 0;
+
+ pr_aud_info("%s\n", __func__);
+
+ /* Prevent sleep. */
+ wake_lock(&audio->suspend_lock);
+ wake_lock(&audio->idle_lock);
+
+ rc = voice_set_voc_path_full(1);
+
+ if (rc == 0) {
+ voice_register_mvs_cb(audio_mvs_process_ul_pkt,
+ audio_mvs_process_dl_pkt,
+ audio);
+
+ voice_config_vocoder(
+ audio_mvs_get_media_type(audio->mvs_mode, audio->rate_type),
+ audio_mvs_get_rate(audio->mvs_mode, audio->rate_type),
+ audio_mvs_get_network_type(audio->mvs_mode),
+ audio->dtx_mode);
+
+ audio->state = AUDIO_MVS_STARTED;
+ } else {
+ pr_aud_err("%s: Error %d setting voc path to full\n", __func__, rc);
+ }
+
+ return rc;
+}
+
+static int audio_mvs_stop(struct audio_mvs_info_type *audio)
+{
+ int rc = 0;
+
+ pr_aud_info("%s\n", __func__);
+
+ voice_set_voc_path_full(0);
+
+ audio->state = AUDIO_MVS_STOPPED;
+
+ /* Allow sleep. */
+ wake_unlock(&audio->suspend_lock);
+ wake_unlock(&audio->idle_lock);
+
+ return rc;
+}
+
+static int audio_mvs_open(struct inode *inode, struct file *file)
+{
+ int rc = 0;
+ int i;
+ int offset = 0;
+ struct audio_mvs_buf_node *buf_node = NULL;
+
+ pr_aud_info("%s\n", __func__);
+
+ mutex_lock(&audio_mvs_info.lock);
+
+ /* Allocate input and output buffers. */
+ audio_mvs_info.memory_chunk = kmalloc(2 * MVS_MAX_Q_LEN *
+ sizeof(struct audio_mvs_buf_node),
+ GFP_KERNEL);
+
+ if (audio_mvs_info.memory_chunk != NULL) {
+ for (i = 0; i < MVS_MAX_Q_LEN; i++) {
+ buf_node = audio_mvs_info.memory_chunk + offset;
+
+ list_add_tail(&buf_node->list,
+ &audio_mvs_info.free_in_queue);
+
+ offset = offset + sizeof(struct audio_mvs_buf_node);
+ }
+
+ for (i = 0; i < MVS_MAX_Q_LEN; i++) {
+ buf_node = audio_mvs_info.memory_chunk + offset;
+
+ list_add_tail(&buf_node->list,
+ &audio_mvs_info.free_out_queue);
+
+ offset = offset + sizeof(struct audio_mvs_buf_node);
+ }
+
+ audio_mvs_info.state = AUDIO_MVS_STOPPED;
+
+ file->private_data = &audio_mvs_info;
+
+ } else {
+ pr_aud_err("%s: No memory for IO buffers\n", __func__);
+
+ rc = -ENOMEM;
+ }
+
+ mutex_unlock(&audio_mvs_info.lock);
+
+ return rc;
+}
+
+static int audio_mvs_release(struct inode *inode, struct file *file)
+{
+ struct list_head *ptr = NULL;
+ struct list_head *next = NULL;
+ struct audio_mvs_buf_node *buf_node = NULL;
+ struct audio_mvs_info_type *audio = file->private_data;
+
+ pr_aud_info("%s\n", __func__);
+
+ mutex_lock(&audio->lock);
+
+ if (audio->state == AUDIO_MVS_STARTED)
+ audio_mvs_stop(audio);
+
+ /* Free input and output memory. */
+ mutex_lock(&audio->in_lock);
+
+ list_for_each_safe(ptr, next, &audio->in_queue) {
+ buf_node = list_entry(ptr, struct audio_mvs_buf_node, list);
+ list_del(&buf_node->list);
+ }
+
+ list_for_each_safe(ptr, next, &audio->free_in_queue) {
+ buf_node = list_entry(ptr, struct audio_mvs_buf_node, list);
+ list_del(&buf_node->list);
+ }
+
+ mutex_unlock(&audio->in_lock);
+
+
+ mutex_lock(&audio->out_lock);
+
+ list_for_each_safe(ptr, next, &audio->out_queue) {
+ buf_node = list_entry(ptr, struct audio_mvs_buf_node, list);
+ list_del(&buf_node->list);
+ }
+
+ list_for_each_safe(ptr, next, &audio->free_out_queue) {
+ buf_node = list_entry(ptr, struct audio_mvs_buf_node, list);
+ list_del(&buf_node->list);
+ }
+
+ mutex_unlock(&audio->out_lock);
+
+ kfree(audio->memory_chunk);
+ audio->memory_chunk = NULL;
+
+ audio->state = AUDIO_MVS_CLOSED;
+
+ mutex_unlock(&audio->lock);
+
+ return 0;
+}
+
+static ssize_t audio_mvs_read(struct file *file,
+ char __user *buf,
+ size_t count,
+ loff_t *pos)
+{
+ int rc = 0;
+ struct audio_mvs_buf_node *buf_node = NULL;
+ struct audio_mvs_info_type *audio = file->private_data;
+
+ pr_debug("%s:\n", __func__);
+
+ rc = wait_event_interruptible_timeout(audio->out_wait,
+ (!list_empty(&audio->out_queue) ||
+ audio->state == AUDIO_MVS_STOPPED),
+ 1 * HZ);
+
+ if (rc > 0) {
+ mutex_lock(&audio->out_lock);
+
+ if ((audio->state == AUDIO_MVS_STARTED) &&
+ (!list_empty(&audio->out_queue))) {
+
+ if (count >= sizeof(struct msm_audio_mvs_frame)) {
+ buf_node = list_first_entry(&audio->out_queue,
+ struct audio_mvs_buf_node,
+ list);
+ list_del(&buf_node->list);
+
+ rc = copy_to_user(buf,
+ &buf_node->frame,
+ sizeof(struct msm_audio_mvs_frame));
+
+ if (rc == 0) {
+ rc = buf_node->frame.len +
+ sizeof(buf_node->frame.frame_type) +
+ sizeof(buf_node->frame.len);
+ } else {
+ pr_aud_err("%s: Copy to user retuned %d",
+ __func__, rc);
+
+ rc = -EFAULT;
+ }
+
+ list_add_tail(&buf_node->list,
+ &audio->free_out_queue);
+ } else {
+ pr_aud_err("%s: Read count %d < sizeof(frame) %d",
+ __func__, count,
+ sizeof(struct msm_audio_mvs_frame));
+
+ rc = -ENOMEM;
+ }
+ } else {
+ pr_aud_err("%s: Read performed in state %d\n",
+ __func__, audio->state);
+
+ rc = -EPERM;
+ }
+
+ mutex_unlock(&audio->out_lock);
+
+ } else if (rc == 0) {
+ pr_aud_err("%s: No UL data available\n", __func__);
+
+ rc = -ETIMEDOUT;
+ } else {
+ pr_aud_err("%s: Read was interrupted\n", __func__);
+
+ rc = -ERESTARTSYS;
+ }
+
+ return rc;
+}
+
+static ssize_t audio_mvs_write(struct file *file,
+ const char __user *buf,
+ size_t count,
+ loff_t *pos)
+{
+ int rc = 0;
+ struct audio_mvs_buf_node *buf_node = NULL;
+ struct audio_mvs_info_type *audio = file->private_data;
+
+ pr_debug("%s:\n", __func__);
+
+ mutex_lock(&audio->in_lock);
+
+ if (audio->state == AUDIO_MVS_STARTED) {
+ if (count <= sizeof(struct msm_audio_mvs_frame)) {
+ if (!list_empty(&audio->free_in_queue)) {
+ buf_node =
+ list_first_entry(&audio->free_in_queue,
+ struct audio_mvs_buf_node,
+ list);
+ list_del(&buf_node->list);
+
+ rc = copy_from_user(&buf_node->frame,
+ buf,
+ count);
+
+ list_add_tail(&buf_node->list,
+ &audio->in_queue);
+ } else {
+ pr_aud_err("%s: No free DL buffs\n", __func__);
+ }
+ } else {
+ pr_aud_err("%s: Write count %d < sizeof(frame) %d",
+ __func__, count,
+ sizeof(struct msm_audio_mvs_frame));
+
+ rc = -ENOMEM;
+ }
+ } else {
+ pr_aud_err("%s: Write performed in invalid state %d\n",
+ __func__, audio->state);
+
+ rc = -EPERM;
+ }
+
+ mutex_unlock(&audio->in_lock);
+
+ return rc;
+}
+
+static long audio_mvs_ioctl(struct file *file,
+ unsigned int cmd,
+ unsigned long arg)
+{
+ int rc = 0;
+ struct audio_mvs_info_type *audio = file->private_data;
+
+ pr_aud_info("%s:\n", __func__);
+
+ switch (cmd) {
+ case AUDIO_GET_MVS_CONFIG: {
+ struct msm_audio_mvs_config config;
+
+ pr_aud_info("%s: IOCTL GET_MVS_CONFIG\n", __func__);
+
+ mutex_lock(&audio->lock);
+
+ config.mvs_mode = audio->mvs_mode;
+ config.rate_type = audio->rate_type;
+ config.dtx_mode = audio->dtx_mode;
+
+ mutex_unlock(&audio->lock);
+
+ rc = copy_to_user((void *)arg, &config, sizeof(config));
+ if (rc == 0)
+ rc = sizeof(config);
+ else
+ pr_aud_err("%s: Config copy failed %d\n", __func__, rc);
+
+ break;
+ }
+
+ case AUDIO_SET_MVS_CONFIG: {
+ struct msm_audio_mvs_config config;
+
+ pr_aud_info("%s: IOCTL SET_MVS_CONFIG\n", __func__);
+
+ rc = copy_from_user(&config, (void *)arg, sizeof(config));
+ if (rc == 0) {
+ mutex_lock(&audio->lock);
+
+ if (audio->state == AUDIO_MVS_STOPPED) {
+ audio->mvs_mode = config.mvs_mode;
+ audio->rate_type = config.rate_type;
+ audio->dtx_mode = config.dtx_mode;
+ } else {
+ pr_aud_err("%s: Set confg called in state %d\n",
+ __func__, audio->state);
+
+ rc = -EPERM;
+ }
+
+ mutex_unlock(&audio->lock);
+ } else {
+ pr_aud_err("%s: Config copy failed %d\n", __func__, rc);
+ }
+
+ break;
+ }
+
+ case AUDIO_START: {
+ pr_aud_info("%s: IOCTL START\n", __func__);
+
+ mutex_lock(&audio->lock);
+
+ if (audio->state == AUDIO_MVS_STOPPED) {
+ rc = audio_mvs_start(audio);
+
+ if (rc != 0)
+ audio_mvs_stop(audio);
+ } else {
+ pr_aud_err("%s: Start called in invalid state %d\n",
+ __func__, audio->state);
+
+ rc = -EPERM;
+ }
+
+ mutex_unlock(&audio->lock);
+
+ break;
+ }
+
+ case AUDIO_STOP: {
+ pr_aud_info("%s: IOCTL STOP\n", __func__);
+
+ mutex_lock(&audio->lock);
+
+ if (audio->state == AUDIO_MVS_STARTED) {
+ rc = audio_mvs_stop(audio);
+ } else {
+ pr_aud_err("%s: Stop called in invalid state %d\n",
+ __func__, audio->state);
+
+ rc = -EPERM;
+ }
+
+ mutex_unlock(&audio->lock);
+
+ break;
+ }
+
+ default: {
+ pr_aud_err("%s: Unknown IOCTL %d\n", __func__, cmd);
+ }
+ }
+
+ return rc;
+}
+
+static const struct file_operations audio_mvs_fops = {
+ .owner = THIS_MODULE,
+ .open = audio_mvs_open,
+ .release = audio_mvs_release,
+ .read = audio_mvs_read,
+ .write = audio_mvs_write,
+ .unlocked_ioctl = audio_mvs_ioctl
+};
+
+struct miscdevice audio_mvs_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_mvs",
+ .fops = &audio_mvs_fops
+};
+
+static int __init audio_mvs_init(void)
+{
+ int rc = 0;
+
+ memset(&audio_mvs_info, 0, sizeof(audio_mvs_info));
+
+ init_waitqueue_head(&audio_mvs_info.out_wait);
+
+ mutex_init(&audio_mvs_info.lock);
+ mutex_init(&audio_mvs_info.in_lock);
+ mutex_init(&audio_mvs_info.out_lock);
+
+ spin_lock_init(&audio_mvs_info.dsp_lock);
+
+ INIT_LIST_HEAD(&audio_mvs_info.in_queue);
+ INIT_LIST_HEAD(&audio_mvs_info.free_in_queue);
+ INIT_LIST_HEAD(&audio_mvs_info.out_queue);
+ INIT_LIST_HEAD(&audio_mvs_info.free_out_queue);
+
+ wake_lock_init(&audio_mvs_info.suspend_lock,
+ WAKE_LOCK_SUSPEND,
+ "audio_mvs_suspend");
+ wake_lock_init(&audio_mvs_info.idle_lock,
+ WAKE_LOCK_IDLE,
+ "audio_mvs_idle");
+
+ rc = misc_register(&audio_mvs_misc);
+
+ return rc;
+}
+
+static void __exit audio_mvs_exit(void){
+ pr_aud_info("%s:\n", __func__);
+
+ misc_deregister(&audio_mvs_misc);
+}
+
+module_init(audio_mvs_init);
+module_exit(audio_mvs_exit);
+
+MODULE_DESCRIPTION("MSM MVS driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp6v3/audio_utils.c b/arch/arm/mach-msm/qdsp6v3/audio_utils.c
new file mode 100644
index 00000000000..aa641af7ee8
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v3/audio_utils.c
@@ -0,0 +1,644 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+*/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "audio_utils.h"
+
+static int audio_in_pause(struct q6audio_in *audio)
+{
+ int rc;
+
+ rc = q6asm_cmd(audio->ac, CMD_PAUSE);
+ if (rc < 0)
+ pr_aud_err("%s:session id %d: pause cmd failed rc=%d\n", __func__,
+ audio->ac->session, rc);
+
+ return rc;
+}
+
+static int audio_in_flush(struct q6audio_in *audio)
+{
+ int rc;
+
+ pr_debug("%s:session id %d: flush\n", __func__, audio->ac->session);
+ /* Implicitly issue a pause to the decoder before flushing */
+ rc = audio_in_pause(audio);
+ if (rc < 0) {
+ pr_aud_err("%s:session id %d: pause cmd failed rc=%d\n", __func__,
+ audio->ac->session, rc);
+ return rc;
+ }
+
+ rc = q6asm_cmd(audio->ac, CMD_FLUSH);
+ if (rc < 0) {
+ pr_aud_err("%s:session id %d: flush cmd failed rc=%d\n", __func__,
+ audio->ac->session, rc);
+ return rc;
+ }
+ audio->rflush = 1;
+ audio->wflush = 1;
+ memset(audio->out_frame_info, 0, sizeof(audio->out_frame_info));
+ wake_up(&audio->read_wait);
+ /* get read_lock to ensure no more waiting read thread */
+ mutex_lock(&audio->read_lock);
+ audio->rflush = 0;
+ mutex_unlock(&audio->read_lock);
+ wake_up(&audio->write_wait);
+ /* get write_lock to ensure no more waiting write thread */
+ mutex_lock(&audio->write_lock);
+ audio->wflush = 0;
+ mutex_unlock(&audio->write_lock);
+ pr_debug("%s:session id %d: in_bytes %d\n", __func__,
+ audio->ac->session, atomic_read(&audio->in_bytes));
+ pr_debug("%s:session id %d: in_samples %d\n", __func__,
+ audio->ac->session, atomic_read(&audio->in_samples));
+ atomic_set(&audio->in_bytes, 0);
+ atomic_set(&audio->in_samples, 0);
+ return 0;
+}
+
+void audio_in_get_dsp_frames(struct q6audio_in *audio,
+ uint32_t token, uint32_t *payload)
+{
+ uint32_t index;
+
+ index = token;
+ pr_debug("%s:session id %d: index=%d nr frames=%d offset[%d]\n",
+ __func__, audio->ac->session, token, payload[7],
+ payload[3]);
+ pr_debug("%s:session id %d: timemsw=%d lsw=%d\n", __func__,
+ audio->ac->session, payload[4], payload[5]);
+ pr_debug("%s:session id %d: uflags=0x%8x uid=0x%8x\n", __func__,
+ audio->ac->session, payload[6], payload[8]);
+ pr_debug("%s:session id %d: enc frame size=0x%8x\n", __func__,
+ audio->ac->session, payload[2]);
+
+ audio->out_frame_info[index][0] = payload[7];
+ audio->out_frame_info[index][1] = payload[3];
+
+ /* statistics of read */
+ atomic_add(payload[2], &audio->in_bytes);
+ atomic_add(payload[7], &audio->in_samples);
+
+ if (atomic_read(&audio->out_count) <= audio->str_cfg.buffer_count) {
+ atomic_inc(&audio->out_count);
+ wake_up(&audio->read_wait);
+ }
+}
+
+/* must be called with audio->lock held */
+int audio_in_enable(struct q6audio_in *audio)
+{
+ if (audio->enabled)
+ return 0;
+
+ /* 2nd arg: 0 -> run immediately
+ 3rd arg: 0 -> msw_ts, 4th arg: 0 ->lsw_ts */
+ return q6asm_run(audio->ac, 0x00, 0x00, 0x00);
+}
+
+/* must be called with audio->lock held */
+int audio_in_disable(struct q6audio_in *audio)
+{
+ int rc = 0;
+ if (audio->opened) {
+ audio->enabled = 0;
+ audio->opened = 0;
+ pr_debug("%s:session id %d: inbytes[%d] insamples[%d]\n",
+ __func__, audio->ac->session,
+ atomic_read(&audio->in_bytes),
+ atomic_read(&audio->in_samples));
+
+ rc = q6asm_cmd(audio->ac, CMD_CLOSE);
+ if (rc < 0)
+ pr_aud_err("%s:session id %d: Failed to close the\
+ session rc=%d\n", __func__, audio->ac->session,
+ rc);
+ audio->stopped = 1;
+ memset(audio->out_frame_info, 0,
+ sizeof(audio->out_frame_info));
+ wake_up(&audio->read_wait);
+ wake_up(&audio->write_wait);
+ }
+ pr_debug("%s:session id %d: enabled[%d]\n", __func__,
+ audio->ac->session, audio->enabled);
+ return rc;
+}
+
+int audio_in_buf_alloc(struct q6audio_in *audio)
+{
+ int rc = 0;
+
+ switch (audio->buf_alloc) {
+ case NO_BUF_ALLOC:
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ rc = q6asm_audio_client_buf_alloc(IN,
+ audio->ac,
+ ALIGN_BUF_SIZE(audio->pcm_cfg.buffer_size),
+ audio->pcm_cfg.buffer_count);
+ if (rc < 0) {
+ pr_aud_err("%s:session id %d: Buffer Alloc\
+ failed\n", __func__,
+ audio->ac->session);
+ rc = -ENOMEM;
+ break;
+ }
+ audio->buf_alloc |= BUF_ALLOC_IN;
+ }
+ rc = q6asm_audio_client_buf_alloc(OUT, audio->ac,
+ ALIGN_BUF_SIZE(audio->str_cfg.buffer_size),
+ audio->str_cfg.buffer_count);
+ if (rc < 0) {
+ pr_aud_err("%s:session id %d: Buffer Alloc failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ rc = -ENOMEM;
+ break;
+ }
+ audio->buf_alloc |= BUF_ALLOC_OUT;
+ break;
+ case BUF_ALLOC_IN:
+ rc = q6asm_audio_client_buf_alloc(OUT, audio->ac,
+ ALIGN_BUF_SIZE(audio->str_cfg.buffer_size),
+ audio->str_cfg.buffer_count);
+ if (rc < 0) {
+ pr_aud_err("%s:session id %d: Buffer Alloc failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ rc = -ENOMEM;
+ break;
+ }
+ audio->buf_alloc |= BUF_ALLOC_OUT;
+ break;
+ case BUF_ALLOC_OUT:
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ rc = q6asm_audio_client_buf_alloc(IN, audio->ac,
+ ALIGN_BUF_SIZE(audio->pcm_cfg.buffer_size),
+ audio->pcm_cfg.buffer_count);
+ if (rc < 0) {
+ pr_aud_err("%s:session id %d: Buffer Alloc\
+ failed\n", __func__,
+ audio->ac->session);
+ rc = -ENOMEM;
+ break;
+ }
+ audio->buf_alloc |= BUF_ALLOC_IN;
+ }
+ break;
+ default:
+ pr_debug("%s:session id %d: buf[%d]\n", __func__,
+ audio->ac->session, audio->buf_alloc);
+ }
+
+ return rc;
+}
+/* ------------------- device --------------------- */
+long audio_in_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_in *audio = file->private_data;
+ int rc = 0;
+
+ if (cmd == AUDIO_GET_STATS) {
+ struct msm_audio_stats stats;
+ stats.byte_count = atomic_read(&audio->in_bytes);
+ stats.sample_count = atomic_read(&audio->in_samples);
+ if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+ return -EFAULT;
+ return rc;
+ }
+
+ mutex_lock(&audio->lock);
+ switch (cmd) {
+ case AUDIO_FLUSH: {
+ /* Make sure we're stopped and we wake any threads
+ * that might be blocked holding the read_lock.
+ * While audio->stopped read threads will always
+ * exit immediately.
+ */
+ rc = audio_in_flush(audio);
+ if (rc < 0)
+ pr_aud_err("%s:session id %d: Flush Fail rc=%d\n",
+ __func__, audio->ac->session, rc);
+ break;
+ }
+ case AUDIO_PAUSE: {
+ pr_debug("%s:session id %d: AUDIO_PAUSE\n", __func__,
+ audio->ac->session);
+ if (audio->enabled)
+ audio_in_pause(audio);
+ break;
+ }
+ case AUDIO_GET_STREAM_CONFIG: {
+ struct msm_audio_stream_config cfg;
+ memset(&cfg, 0, sizeof(cfg));
+ cfg.buffer_size = audio->str_cfg.buffer_size;
+ cfg.buffer_count = audio->str_cfg.buffer_count;
+ if (copy_to_user((void *)arg, &cfg, sizeof(cfg)))
+ rc = -EFAULT;
+ pr_debug("%s:session id %d: AUDIO_GET_STREAM_CONFIG %d %d\n",
+ __func__, audio->ac->session, cfg.buffer_size,
+ cfg.buffer_count);
+ break;
+ }
+ case AUDIO_SET_STREAM_CONFIG: {
+ struct msm_audio_stream_config cfg;
+ if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
+ rc = -EFAULT;
+ break;
+ }
+ /* Minimum single frame size,
+ but with in maximum frames number */
+ if ((cfg.buffer_size < (audio->min_frame_size+ \
+ sizeof(struct meta_out_dsp))) ||
+ (cfg.buffer_count < FRAME_NUM)) {
+ rc = -EINVAL;
+ break;
+ }
+ audio->str_cfg.buffer_size = cfg.buffer_size;
+ audio->str_cfg.buffer_count = cfg.buffer_count;
+ rc = q6asm_audio_client_buf_alloc(OUT, audio->ac,
+ ALIGN_BUF_SIZE(audio->str_cfg.buffer_size),
+ audio->str_cfg.buffer_count);
+ if (rc < 0) {
+ pr_aud_err("%s: session id %d: Buffer Alloc failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ rc = -ENOMEM;
+ break;
+ }
+ audio->buf_alloc |= BUF_ALLOC_OUT;
+ rc = 0;
+ pr_debug("%s:session id %d: AUDIO_SET_STREAM_CONFIG %d %d\n",
+ __func__, audio->ac->session,
+ audio->str_cfg.buffer_size,
+ audio->str_cfg.buffer_count);
+ break;
+ }
+ case AUDIO_GET_SESSION_ID: {
+ if (copy_to_user((void *) arg, &audio->ac->session,
+ sizeof(unsigned short))) {
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case AUDIO_SET_BUF_CFG: {
+ struct msm_audio_buf_cfg cfg;
+ if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
+ rc = -EFAULT;
+ break;
+ }
+ if ((audio->feedback == NON_TUNNEL_MODE) &&
+ !cfg.meta_info_enable) {
+ rc = -EFAULT;
+ break;
+ }
+
+ /* Restrict the num of frames per buf to coincide with
+ * default buf size */
+ if (cfg.frames_per_buf > audio->max_frames_per_buf) {
+ rc = -EFAULT;
+ break;
+ }
+ audio->buf_cfg.meta_info_enable = cfg.meta_info_enable;
+ audio->buf_cfg.frames_per_buf = cfg.frames_per_buf;
+ pr_debug("%s:session id %d: Set-buf-cfg: meta[%d]\
+ framesperbuf[%d]\n", __func__,
+ audio->ac->session, cfg.meta_info_enable,
+ cfg.frames_per_buf);
+ break;
+ }
+ case AUDIO_GET_BUF_CFG: {
+ pr_debug("%s:session id %d: Get-buf-cfg: meta[%d]\
+ framesperbuf[%d]\n", __func__,
+ audio->ac->session, audio->buf_cfg.meta_info_enable,
+ audio->buf_cfg.frames_per_buf);
+
+ if (copy_to_user((void *)arg, &audio->buf_cfg,
+ sizeof(struct msm_audio_buf_cfg)))
+ rc = -EFAULT;
+ break;
+ }
+ case AUDIO_GET_CONFIG: {
+ if (copy_to_user((void *)arg, &audio->pcm_cfg,
+ sizeof(struct msm_audio_config)))
+ rc = -EFAULT;
+ break;
+
+ }
+ case AUDIO_SET_CONFIG: {
+ struct msm_audio_config cfg;
+ if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
+ rc = -EFAULT;
+ break;
+ }
+ if (audio->feedback != NON_TUNNEL_MODE) {
+ pr_aud_err("%s:session id %d: Not sufficient permission to"
+ "change the record mode\n", __func__,
+ audio->ac->session);
+ rc = -EACCES;
+ break;
+ }
+ if ((cfg.buffer_count > PCM_BUF_COUNT) ||
+ (cfg.buffer_count == 1))
+ cfg.buffer_count = PCM_BUF_COUNT;
+
+ audio->pcm_cfg.buffer_count = cfg.buffer_count;
+ audio->pcm_cfg.buffer_size = cfg.buffer_size;
+ audio->pcm_cfg.channel_count = cfg.channel_count;
+ audio->pcm_cfg.sample_rate = cfg.sample_rate;
+ rc = q6asm_audio_client_buf_alloc(IN, audio->ac,
+ ALIGN_BUF_SIZE(audio->pcm_cfg.buffer_size),
+ audio->pcm_cfg.buffer_count);
+ if (rc < 0) {
+ pr_aud_err("%s:session id %d: Buffer Alloc failed\n",
+ __func__, audio->ac->session);
+ rc = -ENOMEM;
+ break;
+ }
+ audio->buf_alloc |= BUF_ALLOC_IN;
+ rc = 0;
+ pr_debug("%s:session id %d: AUDIO_SET_CONFIG %d %d\n", __func__,
+ audio->ac->session, audio->pcm_cfg.buffer_count,
+ audio->pcm_cfg.buffer_size);
+ break;
+ }
+ default:
+ /* call codec specific ioctl */
+ rc = audio->enc_ioctl(file, cmd, arg);
+ }
+ mutex_unlock(&audio->lock);
+ return rc;
+}
+
+ssize_t audio_in_read(struct file *file,
+ char __user *buf,
+ size_t count, loff_t *pos)
+{
+ struct q6audio_in *audio = file->private_data;
+ const char __user *start = buf;
+ unsigned char *data;
+ uint32_t offset = 0;
+ uint32_t size = 0;
+ int rc = 0;
+ uint32_t idx;
+ struct meta_out_dsp meta;
+ uint32_t bytes_to_copy = 0;
+ uint32_t mfield_size = (audio->buf_cfg.meta_info_enable == 0) ? 0 :
+ (sizeof(unsigned char) +
+ (sizeof(struct meta_out_dsp)*(audio->buf_cfg.frames_per_buf)));
+
+ pr_debug("%s:session id %d: read - %d\n", __func__, audio->ac->session,
+ count);
+ if (!audio->enabled)
+ return -EFAULT;
+ mutex_lock(&audio->read_lock);
+ while (count > 0) {
+ rc = wait_event_interruptible(
+ audio->read_wait,
+ ((atomic_read(&audio->out_count) > 0) ||
+ (audio->stopped) ||
+ audio->rflush || audio->eos_rsp));
+
+ if (rc < 0)
+ break;
+
+ if ((audio->stopped && !(atomic_read(&audio->out_count))) ||
+ audio->rflush) {
+ pr_debug("%s:session id %d: driver in stop state or\
+ flush,No more buf to read", __func__,
+ audio->ac->session);
+ rc = 0;/* End of File */
+ break;
+ }
+ if (!(atomic_read(&audio->out_count)) &&
+ (audio->eos_rsp == 1) &&
+ (count >= (sizeof(unsigned char) +
+ sizeof(struct meta_out_dsp)))) {
+ unsigned char num_of_frames;
+ pr_aud_info("%s:session id %d: eos %d at output\n",
+ __func__, audio->ac->session, audio->eos_rsp);
+ if (buf != start)
+ break;
+ num_of_frames = 0xFF;
+ if (copy_to_user(buf, &num_of_frames,
+ sizeof(unsigned char))) {
+ rc = -EFAULT;
+ break;
+ }
+ buf += sizeof(unsigned char);
+ meta.frame_size = 0xFFFF;
+ meta.encoded_pcm_samples = 0xFFFF;
+ meta.msw_ts = 0x00;
+ meta.lsw_ts = 0x00;
+ meta.nflags = AUD_EOS_SET;
+ audio->eos_rsp = 0;
+ if (copy_to_user(buf, &meta, sizeof(meta))) {
+ rc = -EFAULT;
+ break;
+ }
+ buf += sizeof(meta);
+ break;
+ }
+ data = (unsigned char *)q6asm_is_cpu_buf_avail(OUT, audio->ac,
+ &size, &idx);
+ if ((count >= (size + mfield_size)) && data) {
+ if (audio->buf_cfg.meta_info_enable) {
+ if (copy_to_user(buf,
+ &audio->out_frame_info[idx][0],
+ sizeof(unsigned char))) {
+ rc = -EFAULT;
+ break;
+ }
+ bytes_to_copy =
+ (size + audio->out_frame_info[idx][1]);
+ /* Number of frames information copied */
+ buf += sizeof(unsigned char);
+ count -= sizeof(unsigned char);
+ } else {
+ offset = audio->out_frame_info[idx][1];
+ bytes_to_copy = size;
+ }
+
+ pr_debug("%s:session id %d: offset=%d nr of frames= %d\n",
+ __func__, audio->ac->session,
+ audio->out_frame_info[idx][1],
+ audio->out_frame_info[idx][0]);
+
+ if (copy_to_user(buf, &data[offset], bytes_to_copy)) {
+ rc = -EFAULT;
+ break;
+ }
+ count -= bytes_to_copy;
+ buf += bytes_to_copy;
+ } else {
+ pr_aud_err("%s:session id %d: short read data[%p]\
+ bytesavail[%d]bytesrequest[%d]\n", __func__,
+ audio->ac->session,
+ data, size, count);
+ }
+ atomic_dec(&audio->out_count);
+ q6asm_read(audio->ac);
+ break;
+ }
+ mutex_unlock(&audio->read_lock);
+
+ pr_debug("%s:session id %d: read: %d bytes\n", __func__,
+ audio->ac->session, (buf-start));
+ if (buf > start)
+ return buf - start;
+ return rc;
+}
+
+static int extract_meta_info(char *buf, unsigned long *msw_ts,
+ unsigned long *lsw_ts, unsigned int *flags)
+{
+ struct meta_in *meta = (struct meta_in *)buf;
+ *msw_ts = meta->ntimestamp.highpart;
+ *lsw_ts = meta->ntimestamp.lowpart;
+ *flags = meta->nflags;
+ return 0;
+}
+
+ssize_t audio_in_write(struct file *file,
+ const char __user *buf,
+ size_t count, loff_t *pos)
+{
+ struct q6audio_in *audio = file->private_data;
+ const char __user *start = buf;
+ size_t xfer = 0;
+ char *cpy_ptr;
+ int rc = 0;
+ unsigned char *data;
+ uint32_t size = 0;
+ uint32_t idx = 0;
+ uint32_t nflags = 0;
+ unsigned long msw_ts = 0;
+ unsigned long lsw_ts = 0;
+ uint32_t mfield_size = (audio->buf_cfg.meta_info_enable == 0) ? 0 :
+ sizeof(struct meta_in);
+
+ pr_debug("%s:session id %d: to write[%d]\n", __func__,
+ audio->ac->session, count);
+ if (!audio->enabled)
+ return -EFAULT;
+ mutex_lock(&audio->write_lock);
+
+ while (count > 0) {
+ rc = wait_event_interruptible(audio->write_wait,
+ ((atomic_read(&audio->in_count) > 0) ||
+ (audio->stopped) ||
+ (audio->wflush)));
+ if (rc < 0)
+ break;
+ if (audio->stopped || audio->wflush) {
+ pr_debug("%s: session id %d: stop or flush\n", __func__,
+ audio->ac->session);
+ rc = -EBUSY;
+ break;
+ }
+ data = (unsigned char *)q6asm_is_cpu_buf_avail(IN, audio->ac,
+ &size, &idx);
+ if (!data) {
+ pr_debug("%s:session id %d: No buf available\n",
+ __func__, audio->ac->session);
+ continue;
+ }
+ cpy_ptr = data;
+ if (audio->buf_cfg.meta_info_enable) {
+ if (buf == start) {
+ /* Processing beginning of user buffer */
+ if (copy_from_user(cpy_ptr, buf, mfield_size)) {
+ rc = -EFAULT;
+ break;
+ }
+ /* Check if EOS flag is set and buffer has
+ * contains just meta field
+ */
+ extract_meta_info(cpy_ptr, &msw_ts, &lsw_ts,
+ &nflags);
+ buf += mfield_size;
+ if (count == mfield_size) {
+ /* send the EOS and return */
+ pr_debug("%s:session id %d: send EOS\
+ 0x%8x\n", __func__,
+ audio->ac->session, nflags);
+ break;
+ }
+ count -= mfield_size;
+ } else {
+ pr_debug("%s:session id %d: continuous\
+ buffer\n", __func__, audio->ac->session);
+ }
+ }
+ xfer = (count > (audio->pcm_cfg.buffer_size)) ?
+ (audio->pcm_cfg.buffer_size) : count;
+
+ if (copy_from_user(cpy_ptr, buf, xfer)) {
+ rc = -EFAULT;
+ break;
+ }
+ rc = q6asm_write(audio->ac, xfer, msw_ts, lsw_ts, 0x00);
+ if (rc < 0) {
+ rc = -EFAULT;
+ break;
+ }
+ atomic_dec(&audio->in_count);
+ count -= xfer;
+ buf += xfer;
+ }
+ mutex_unlock(&audio->write_lock);
+ pr_debug("%s:session id %d: eos_condition 0x%8x buf[0x%x]\
+ start[0x%x]\n", __func__, audio->ac->session,
+ nflags, (int) buf, (int) start);
+ if (nflags & AUD_EOS_SET) {
+ rc = q6asm_cmd(audio->ac, CMD_EOS);
+ pr_aud_info("%s:session id %d: eos %d at input\n", __func__,
+ audio->ac->session, audio->eos_rsp);
+ }
+ pr_debug("%s:session id %d: Written %d Avail Buf[%d]", __func__,
+ audio->ac->session, (buf - start - mfield_size),
+ atomic_read(&audio->in_count));
+ if (!rc) {
+ if (buf > start)
+ return buf - start;
+ }
+ return rc;
+}
+
+int audio_in_release(struct inode *inode, struct file *file)
+{
+ struct q6audio_in *audio = file->private_data;
+ pr_aud_info("%s: session id %d\n", __func__, audio->ac->session);
+ mutex_lock(&audio->lock);
+ audio_in_disable(audio);
+ q6asm_audio_client_free(audio->ac);
+ mutex_unlock(&audio->lock);
+ kfree(audio->enc_cfg);
+ kfree(audio);
+ return 0;
+}
+
diff --git a/arch/arm/mach-msm/qdsp6v3/audio_utils.h b/arch/arm/mach-msm/qdsp6v3/audio_utils.h
new file mode 100644
index 00000000000..da4a520da4a
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v3/audio_utils.h
@@ -0,0 +1,109 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+*/
+#include
+
+#define FRAME_NUM (8)
+
+#define PCM_BUF_COUNT (2)
+
+#define AUD_EOS_SET 0x01
+#define TUNNEL_MODE 0x0000
+#define NON_TUNNEL_MODE 0x0001
+
+#define NO_BUF_ALLOC 0x00
+#define BUF_ALLOC_IN 0x01
+#define BUF_ALLOC_OUT 0x02
+#define BUF_ALLOC_INOUT 0x03
+#define ALIGN_BUF_SIZE(size) ((size + 4095) & (~4095))
+
+struct timestamp{
+ unsigned long lowpart;
+ unsigned long highpart;
+} __attribute__ ((packed));
+
+struct meta_in{
+ unsigned short offset;
+ struct timestamp ntimestamp;
+ unsigned int nflags;
+} __attribute__ ((packed));
+
+struct meta_out_dsp{
+ u32 offset_to_frame;
+ u32 frame_size;
+ u32 encoded_pcm_samples;
+ u32 msw_ts;
+ u32 lsw_ts;
+ u32 nflags;
+} __attribute__ ((packed));
+
+struct meta_out{
+ unsigned char num_of_frames;
+ struct meta_out_dsp meta_out_dsp[];
+} __attribute__ ((packed));
+
+struct q6audio_in{
+ spinlock_t dsp_lock;
+ atomic_t in_bytes;
+ atomic_t in_samples;
+
+ struct mutex lock;
+ struct mutex read_lock;
+ struct mutex write_lock;
+ wait_queue_head_t read_wait;
+ wait_queue_head_t write_wait;
+
+ struct audio_client *ac;
+ struct msm_audio_stream_config str_cfg;
+ void *enc_cfg;
+ struct msm_audio_buf_cfg buf_cfg;
+ struct msm_audio_config pcm_cfg;
+ void *codec_cfg;
+
+ /* number of buffers available to read/write */
+ atomic_t in_count;
+ atomic_t out_count;
+
+ /* first idx: num of frames per buf, second idx: offset to frame */
+ uint32_t out_frame_info[FRAME_NUM][2];
+ int eos_rsp;
+ int opened;
+ int enabled;
+ int stopped;
+ int feedback; /* Flag indicates whether used
+ in Non Tunnel mode */
+ int rflush;
+ int wflush;
+ int buf_alloc;
+ uint16_t min_frame_size;
+ uint16_t max_frames_per_buf;
+ long (*enc_ioctl)(struct file *, unsigned int, unsigned long);
+};
+
+void audio_in_get_dsp_frames(struct q6audio_in *audio,
+ uint32_t token, uint32_t *payload);
+int audio_in_enable(struct q6audio_in *audio);
+int audio_in_disable(struct q6audio_in *audio);
+int audio_in_buf_alloc(struct q6audio_in *audio);
+long audio_in_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg);
+ssize_t audio_in_read(struct file *file, char __user *buf,
+ size_t count, loff_t *pos);
+ssize_t audio_in_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *pos);
+int audio_in_release(struct inode *inode, struct file *file);
+
diff --git a/arch/arm/mach-msm/qdsp6v3/audio_wma.c b/arch/arm/mach-msm/qdsp6v3/audio_wma.c
new file mode 100644
index 00000000000..f2deb4f5f46
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v3/audio_wma.c
@@ -0,0 +1,1585 @@
+/* wma audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include