Alsa-devel
Threads by month
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
July 2009
- 135 participants
- 252 discussions
Hi, i'd like to report a bug in alsa, up to 1.0.20, in combination with the
via vt1708s codec used for example in the asus X5DIJ laptop
per default, patch_via.c enables EAPD during initialization. That's not the
case especially for the 1708S, so theres no sound at all from internal
laptop speakers and
line-out.
Enabling EAPD using hda_analyzer fixes this issue.
I believe there should be some easy fix by initializing the codec with EAPD.
I myself can't commit a patch, because my C -kills suck ;)
i'd be really glad if someone could take a look at patch_via.c
regards
didi2002
2
3
Re: [alsa-devel] [LAD] implementing audio device driver on embedded platforms
by Clemens Ladisch 07 Jul '09
by Clemens Ladisch 07 Jul '09
07 Jul '09
Jugalkishore Darak, Pankaj wrote:
> We are porting Linux 2.6.25.4 to a platform which has ARM11 as its core
> processor. My job is to implement audio device driver.
Then you'd better ask on alsa-devel (CC'd).
> Most of the docs are meant for PC audio which has sound cards on PCI.
> And the source code resides in sound folder under the kernel root.
>
> Since mine is an embedded platform, where will my architecture specific
> code resides?
Any platform-specific code will be below your arch/ directory.
The DMA controller and the codecs are likely to be used on other
platforms too, so they'd go into sound/.
> Which all folders under sound folder will be used for embedded devices
mostly soc/
> and which APIs to look into?
linux/Documentation/sound/alsa/soc/*.txt
http://alsa-project.org/main/index.php/ASoC
http://opensource.wolfsonmicro.com/content/asoc-audio-embedded-linux-systems
HTH
Clemens
1
0
[alsa-devel] Fwd: Re: No sound with nVidia Corporation MCP79 High Definition Audio (rev b1) (Macbook Pro 5, 5)
by Andreas Nüßlein 07 Jul '09
by Andreas Nüßlein 07 Jul '09
07 Jul '09
On Tuesday 07 July 2009 08:00:19 you wrote:
> At Mon, 6 Jul 2009 22:14:56 +0200,
>
> Andreas Nüßlein wrote:
> > On Monday 06 July 2009 21:26:18 you wrote:
> > > At Mon, 06 Jul 2009 11:16:35 -0600,
> > >
> > > Sean Burke wrote:
> > > > Scríobh Takashi Iwai:
> > > > > At Mon, 6 Jul 2009 17:53:46 +0200,
> > > > >
> > > > > Andreas Nüßlein wrote:
> > > > >>> The missing pin configuration initialization was already fixed by
> > > > >>> the driver overriding it after checking PCI SSID (which is
> > > > >>> different from the codec SSID). So, this should be no problem.
> > > > >>>
> > > > >>> However, the reason why the analog output doesn't work might be
> > > > >>> different from that. There might be something else missing, but
> > > > >>> I don't know.
> > > > >>>
> > > > >>>
> > > > >>> Takashi
> > > > >>
> > > > >> oh =(
> > > > >>
> > > > >>
> > > > >> hmm.. anything i can do? would it help if i tried changing values
> > > > >> randomly with hda-analyzer.py?
> > > > >
> > > > > Well, did the driver without my change work more or less with
> > > > > the analog audio, or have you never gotten the analog output?
> > > > > You can use the generic parser (i.e. the state without cirrus
> > > > > patch) by passing model=generic option to snd-hda-intel.
> > > >
> > > > For my part, nothing worked with the generic driver. I can't confirm
> > > > digital out, but I can confirm that the kfree error is gone. What
> > > > options are open for figuring out what remains?
> > >
> > > Easy things to test are GPIO bits. Run hda-verb like
> > >
> > > hda-verb /dev/snd/hwC0D0 0x01 SET_GPIO_MASK 0x0f
> > > hda-verb /dev/snd/hwC0D0 0x01 SET_GPIO_DATA 0x0f
> > > or
> > > hda-verb /dev/snd/hwC0D0 0x01 SET_GPIO_DIR 0x0f
> > > hda-verb /dev/snd/hwC0D0 0x01 SET_GPIO_DATA 0x0f
> > >
> > > etc. CS4206 seems to have 4 GPIO lines, and each bit (0-3)
> > > corresponds to each GPIO. In many case, GPIO0 or GPIO1 corresponds to
> > > the amplifier (EAPD) bit.
> > > Define the GPIO direction of each GPIO bit by SET_GPIO_DIR, and
> > > turn on/off the GPIO bits by SET_GPIO_DATA. Running
> > > hda-verb /dev/snd/hwC0D0 0x01 GET_GPIO_DATA 0
> > > will show the current GPIO data bits. Or you can check it in codec#*
> > > proc file.
> > >
> > >
> > > Takashi
> >
> > w000000000000000000000000000000000t! =)
> >
> > takashi, thank you _so_ much!
> >
> > after running all 4 of those:
> > > hda-verb /dev/snd/hwC0D0 0x01 SET_GPIO_MASK 0x0f
> > > hda-verb /dev/snd/hwC0D0 0x01 SET_GPIO_DATA 0x0f
> > > or
> > > hda-verb /dev/snd/hwC0D0 0x01 SET_GPIO_DIR 0x0f
> > > hda-verb /dev/snd/hwC0D0 0x01 SET_GPIO_DATA 0x0f
> >
> > i suddendly had sound!! :D :D :D :D :D :D :D
> > only via speakers though - there is no sound via headphones right now.
> >
> > mixer channels:
> > - Master (with Mutebutton), PCM and Front (also with Mute) all work =)
> > - i don't know what surround would do (or it's extra switch)
> > - headphones-volumes and mute button don't affect the speakers, which is
> > good =)
> >
> >
> > is there a way to reset what i did with hda-verb, so that i can figure
> > out which combination it was exactly?
>
> You can just change the value 0x0f to a different value.
> At least, you can try commands like
> hda-verb /dev/snd/hwC0D0 0x01 SET_GPIO_DATA 0x01
> hda-verb /dev/snd/hwC0D0 0x01 SET_GPIO_DATA 0x02
> hda-verb /dev/snd/hwC0D0 0x01 SET_GPIO_DATA 0x04
> hda-verb /dev/snd/hwC0D0 0x01 SET_GPIO_DATA 0x08
> and check the speaker output at each time.
> Also, check the GPIO direction,
> hda-verb /dev/snd/hwC0D0 0x01 SET_GPIO_DIR 0x01
> hda-verb /dev/snd/hwC0D0 0x01 SET_GPIO_DATA 0x01
> hda-verb /dev/snd/hwC0D0 0x01 SET_GPIO_DIR 0x02
> hda-verb /dev/snd/hwC0D0 0x01 SET_GPIO_DATA 0x02
> ...
>
> Regarding the headphone: is the speaker muted when you plug in the
> headphone? If not, it's likely an issue of the jack detection. If
> the speaker is muted but no headphone output, it's a missing
> initialization (or wrong GPIO setup).
>
>
> Takashi
so here are my findings so far:
hda-verb /dev/snd/hwC0D0 0x01 SET_GPIO_DATA 0x08
is sufficient to turn on the right functionality for the speakers; meaning:
- 'front speaker'-channel actually controls the two front speakers within the
macbookpro - even controlling left and right channel seperately works =)
- 'surround' mute-switch and volume-control (why are those not within on
thing btw?) also work and control a third speaker in the mac, which
really seems responsibly for surround :)
headphones do not yet work, however i made a diff of
"/proc/asound/card0/codec#0" with and without something plugged in:
$ diff -u without_headphones.txt with_headphones.txt
--- without_headphones.txt 2009-07-07 11:41:36.558833270 +0200
+++ with_headphones.txt 2009-07-07 11:41:44.286832992 +0200
@@ -113,7 +113,7 @@
Conn = Unknown, Color = Unknown
DefAssociation = 0x2, Sequence = 0x1
Misc = NO_PRESENCE
- Pin-ctls: 0x40: OUT
+ Pin-ctls: 0x00:
Unsolicited: tag=00, enabled=0
Power: setting=D0, actual=D0
Delay: 1 samples
@@ -125,7 +125,7 @@
Conn = Unknown, Color = Unknown
DefAssociation = 0x2, Sequence = 0x0
Misc = NO_PRESENCE
- Pin-ctls: 0x40: OUT
+ Pin-ctls: 0x00:
Delay: 1 samples
Connection: 1
0x04
thanks =)
nutz
1
0
Re: [alsa-devel] No sound with nVidia Corporation MCP79 High Definition Audio (rev b1) (Macbook Pro 5, 5)
by Takashi Iwai 07 Jul '09
by Takashi Iwai 07 Jul '09
07 Jul '09
At Tue, 07 Jul 2009 00:24:51 -0600,
Sean Burke wrote:
>
> Scríobh Takashi Iwai:
> > At Mon, 6 Jul 2009 22:14:56 +0200,
> > Andreas Nüßlein wrote:
> >
> >> On Monday 06 July 2009 21:26:18 you wrote:
> >>
> >>> At Mon, 06 Jul 2009 11:16:35 -0600,
> >>>
> >>> Easy things to test are GPIO bits. Run hda-verb like
> >>>
> >>> hda-verb /dev/snd/hwC0D0 0x01 SET_GPIO_MASK 0x0f
> >>> hda-verb /dev/snd/hwC0D0 0x01 SET_GPIO_DATA 0x0f
> >>> or
> >>> hda-verb /dev/snd/hwC0D0 0x01 SET_GPIO_DIR 0x0f
> >>> hda-verb /dev/snd/hwC0D0 0x01 SET_GPIO_DATA 0x0f
> >>>
> >>> etc. CS4206 seems to have 4 GPIO lines, and each bit (0-3)
> >>> corresponds to each GPIO. In many case, GPIO0 or GPIO1 corresponds to
> >>> the amplifier (EAPD) bit.
> >>> Define the GPIO direction of each GPIO bit by SET_GPIO_DIR, and
> >>> turn on/off the GPIO bits by SET_GPIO_DATA. Running
> >>> hda-verb /dev/snd/hwC0D0 0x01 GET_GPIO_DATA 0
> >>> will show the current GPIO data bits. Or you can check it in codec#*
> >>> proc file.
> >>>
> >>>
> >>> Takashi
> >>>
> >> w000000000000000000000000000000000t! =)
> >>
> >> takashi, thank you _so_ much!
> >>
> >> after running all 4 of those:
> >>
> >>> hda-verb /dev/snd/hwC0D0 0x01 SET_GPIO_MASK 0x0f
> >>> hda-verb /dev/snd/hwC0D0 0x01 SET_GPIO_DATA 0x0f
> >>> or
> >>> hda-verb /dev/snd/hwC0D0 0x01 SET_GPIO_DIR 0x0f
> >>> hda-verb /dev/snd/hwC0D0 0x01 SET_GPIO_DATA 0x0f
> >>>
> >>>
> >> i suddendly had sound!! :D :D :D :D :D :D :D
> >> only via speakers though - there is no sound via headphones right now.
> >>
> >> mixer channels:
> >> - Master (with Mutebutton), PCM and Front (also with Mute) all work =)
> >> - i don't know what surround would do (or it's extra switch)
> >> - headphones-volumes and mute button don't affect the speakers, which is good
> >> =)
> >>
> >>
> >> is there a way to reset what i did with hda-verb, so that i can figure out
> >> which combination it was exactly?
> >>
> >
> > You can just change the value 0x0f to a different value.
> > At least, you can try commands like
> > hda-verb /dev/snd/hwC0D0 0x01 SET_GPIO_DATA 0x01
> > hda-verb /dev/snd/hwC0D0 0x01 SET_GPIO_DATA 0x02
> > hda-verb /dev/snd/hwC0D0 0x01 SET_GPIO_DATA 0x04
> > hda-verb /dev/snd/hwC0D0 0x01 SET_GPIO_DATA 0x08
> > and check the speaker output at each time.
> > Also, check the GPIO direction,
> > hda-verb /dev/snd/hwC0D0 0x01 SET_GPIO_DIR 0x01
> > hda-verb /dev/snd/hwC0D0 0x01 SET_GPIO_DATA 0x01
> > hda-verb /dev/snd/hwC0D0 0x01 SET_GPIO_DIR 0x02
> > hda-verb /dev/snd/hwC0D0 0x01 SET_GPIO_DATA 0x02
> > ...
> >
> > Regarding the headphone: is the speaker muted when you plug in the
> > headphone? If not, it's likely an issue of the jack detection. If
> > the speaker is muted but no headphone output, it's a missing
> > initialization (or wrong GPIO setup).
> Setting both _DIR and _DATA to 0x08 worked, as did 0x0f.
OK, then GPIO2 is EAPD.
> Plugging in
> headphones does not mute the speaker.
I'll check this later.
thanks,
Takashi
1
1
Hi,
A user reports that toshiba model is working fine with its
laptop(Subsystem: 152d:0763). I checked the patch_realtek file and saw
that the exact ID was mapped against ALC268_ACER 2 years ago for ALSA
issue #3343.
Both laptops are not-so-popular local brands and checking against 152d
points to:
152d QUANTA Computer Inc
according to the pci.ids database.
So how should we act on those situations seen that we can't match against DMI data(which would possibly be crap on those laptops)?
Thanks,
Ozan Caglayan
2
2
07 Jul '09
This patch adds the intel_sst.h header file that is places in the
include folder for MAD driver (ALSA sound card driver for the platform
given in later patches) to use. This file contains the definitions
of interfaces exposed by the SST drivers along with the definitions of
all the controls for the sound card to be used by MAD driver.
intel_sst_ioctl.h - this file exposes the ioctls definitions
for player/middleware to use. Many of the definitions are reuse from ALSA
Signed-off-by: Vinod Koul <vinod.koul(a)intel.com>
Signed-off-by: Harsha Priya <priya.harsha(a)intel.com>
new file: include/sound/intel_sst.h
new file: include/sound/intel_sst_ioctl.h
---
include/sound/intel_sst.h | 259 +++++++++++++++++++++++++++++
include/sound/intel_sst_ioctl.h | 351 +++++++++++++++++++++++++++++++++++++++
2 files changed, 610 insertions(+), 0 deletions(-)
create mode 100644 include/sound/intel_sst.h
create mode 100644 include/sound/intel_sst_ioctl.h
diff --git a/include/sound/intel_sst.h b/include/sound/intel_sst.h
new file mode 100644
index 0000000..c709390
--- /dev/null
+++ b/include/sound/intel_sst.h
@@ -0,0 +1,259 @@
+#ifndef __INTEL_SST_H__
+#define __INTEL_SST_H__
+/*
+ * intel_sst.h - Intel SST Driver for audio engine
+ *
+ * Copyright (C) 2008-09 Intel Corporation
+ * Authors: Vinod Koul <vinod.koul(a)intel.com>
+ * Harsha Priya <priya.harsha(a)intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This driver exposes the audio engine functionalities to the ALSA
+ * and middleware.
+ * This file is shared between the SST and MAD drivers
+ */
+
+#ifndef CONFIG_SST_IPC_NOT_INCLUDED
+#include <asm/ipc_defs.h>
+#endif
+
+#define SST_CARD_NAMES "intel_mid_card"
+
+/*
+control list Pmic & Lpe
+*/
+/*Input controls*/
+
+enum sst_controls {
+ SST_SND_ALLOC = 0x1000,
+ SST_SND_PAUSE = 0x1001,
+ SST_SND_RESUME = 0x1002,
+ SST_SND_DROP = 0x1003,
+ SST_SND_FREE = 0x1004,
+ SST_SND_BUFFER_POINTER = 0x1005,
+ SST_SND_STREAM_INIT = 0x1006,
+ SST_MAX_CONTROLS = 0x1006,
+ SST_CONTROL_BASE = 0x1000,
+};
+
+struct pcm_stream_info {
+ int str_id;
+ void *mad_substream;
+ void (*period_elapsed) (void *mad_substream);
+ unsigned long buffer_ptr;
+};
+
+struct sst_control_list {
+ int control_element;
+ char *value;
+ struct sst_control_list *next_elem;
+};
+
+struct stream_buffer {
+ unsigned long addr;
+ int length;
+};
+
+
+/*
+SST debug print statement definition
+*/
+
+static inline long sst_get_time(void)
+{
+ struct timeval t;
+ do_gettimeofday(&t);
+ return t.tv_usec;
+}
+
+#define _sst_printk_(level, format, arg...) \
+ printk(level "Time:%8ld::%8ld >> SST: %s %d " format, \
+ get_seconds(), sst_get_time(), __func__ , __LINE__, ## arg)
+
+#define sst_err(format, arg...) _sst_printk_(KERN_ERR, "ERR: " format, ## arg)
+#define sst_info(format, arg...) \
+ _sst_printk_(KERN_INFO, "INFO: " format, ## arg)
+
+#ifdef CONFIG_SST_DBG_PRINT
+#define sst_dbg(format, arg...) _sst_printk_(KERN_DEBUG, "DBG: " format, ## arg)
+#else
+#define sst_dbg(format, arg...) do {} while (0);
+#endif
+struct snd_pmic_ops {
+ int (*set_input_dev) (int value);
+ int (*get_input_dev) (int *value);
+
+ int (*set_output_dev) (int value);
+ int (*get_output_dev) (int *value);
+
+ int (*set_mute) (int dev_id, int value);
+ int (*get_mute) (int dev_id, int *value);
+
+ int (*set_vol) (int dev_id, int value);
+ int (*get_vol) (int dev_id, int *value);
+
+ int(*init_card) (void);
+ void (*set_pcm_params) (int sfreq, int word_size);
+
+ int (*init_card_capture) (void);
+
+};
+
+struct intel_sst_card_ops {
+ char *module_name;
+ int vendor_id;
+ int (*control_set) (int control_element, void *value);
+ int (*send_buffer) (int str_id, struct stream_buffer *mad_buf);
+ struct snd_pmic_ops *scard_ops;
+};
+
+int register_sst_card(struct intel_sst_card_ops *card);
+void unregister_sst_card(struct intel_sst_card_ops *card);
+
+/*periphral interrupt interface*/
+enum lpe_periphral {
+ LPE_DMA = 1,
+ LPE_SSP0,
+ LPE_SSP1
+};
+
+/*modified for generic access*/
+struct sc_reg_access {
+ u16 reg_addr;
+ u8 value;
+ u8 mask;
+};
+enum sc_reg_access_type {
+ PMIC_READ = 0,
+ PMIC_WRITE,
+ PMIC_READ_MODIFY,
+};
+
+static inline int sst_sc_reg_access(struct sc_reg_access *sc_access,
+ int type, int num_val)
+{
+#ifndef CONFIG_SST_IPC_NOT_INCLUDED
+ int i, retval = 0, j = 0, k = 0, count = 0;
+ struct ipc_pmic_reg_data reg_data;
+ struct ipc_pmic_mod_reg_data pmic_mod_reg = {0};
+
+ reg_data.ioc = TRUE;
+ if (type == PMIC_WRITE) {
+ do {
+ int max_retries = 0;
+
+ if (num_val <= 4)
+ count = num_val;
+ else
+ count = 4;
+retry_write:
+ for (i = 0; i < count; i++, j++) {
+ reg_data.pmic_reg_data[i].
+ register_address = sc_access[j].reg_addr;
+
+ reg_data.pmic_reg_data[i].value =
+ sc_access[j].value;
+ }
+ reg_data.num_entries = count;
+ retval = ipc_pmic_register_write(®_data, 0);
+ if (E_NO_INTERRUPT_ON_IOC == retval &&
+ max_retries < 10) {
+ sst_err("write communcation needs retry\n");
+ max_retries++;
+ goto retry_write;
+ }
+ if (0 != retval) {
+ /*pmic communication fails*/
+ sst_err("pmic write failed \n");
+ return retval;
+ }
+ num_val -= count;
+ } while (num_val > 0);
+ } else if (type == PMIC_READ) {
+ do {
+ int max_retries = 0;
+ if (num_val <= 4)
+ count = num_val;
+ else
+ count = 4;
+retry_read:
+ for (i = 0; i < count; i++, j++)
+ reg_data.pmic_reg_data[i].register_address
+ = sc_access[j].reg_addr;
+ reg_data.num_entries = count;
+ retval = ipc_pmic_register_read(®_data);
+ if (E_NO_INTERRUPT_ON_IOC == retval &&
+ max_retries < 10) {
+ sst_err("read communcation needs retry\n");
+ max_retries++;
+ goto retry_read;
+ }
+ if (0 != retval) {
+ /*pmic communication fails*/
+ sst_err("pmic read failed \n");
+ return retval;
+ }
+
+ for (i = 0; i < count; i++, k++)
+ sc_access[k].value =
+ reg_data.pmic_reg_data[i].value;
+ num_val -= count;
+ } while (num_val > 0);
+ } else {
+ pmic_mod_reg.ioc = TRUE;
+ do {
+ int max_retries = 0;
+ if (num_val <= 4)
+ count = num_val;
+ else
+ count = 4;
+retry_readmod:
+ for (i = 0; i < count; i++, j++) {
+ pmic_mod_reg.pmic_mod_reg_data[i].
+ register_address = sc_access[j].reg_addr;
+ pmic_mod_reg.pmic_mod_reg_data[i].value =
+ sc_access[j].value;
+ pmic_mod_reg.pmic_mod_reg_data[i].bit_map =
+ sc_access[j].mask;
+ }
+ pmic_mod_reg.num_entries = count;
+ retval = ipc_pmic_register_read_modify(&pmic_mod_reg);
+ if (E_NO_INTERRUPT_ON_IOC == retval &&
+ max_retries < 10) {
+ sst_err("read/modify retry\n");
+ max_retries++;
+ goto retry_readmod;
+ }
+ if (0 != retval) {
+ /*pmic communication fails*/
+ sst_err("pmic read_modify failed \n");
+ return retval;
+ }
+ num_val -= count;
+ } while (num_val > 0);
+ }
+ return retval;
+#else
+ return 0;
+#endif
+}
+
+int lpe_mask_periphral_intr(enum lpe_periphral device);
+int lpe_unmask_periphral_intr(enum lpe_periphral device);
+int lpe_periphral_intr_status(enum lpe_periphral device, int *status);
+#endif /*__INTEL_SST_H__*/
diff --git a/include/sound/intel_sst_ioctl.h b/include/sound/intel_sst_ioctl.h
new file mode 100644
index 0000000..848ea26
--- /dev/null
+++ b/include/sound/intel_sst_ioctl.h
@@ -0,0 +1,351 @@
+#ifndef __INTEL_SST_IOCTL_H__
+#define __INTEL_SST_IOCTL_H__
+/*
+ * intel_sst_ipc.h - Intel SST Driver for audio engine
+ *
+ * Copyright (C) 2008-09 Intel Corporation
+ * Authors: Vinod Koul <vinod.koul(a)intel.com>
+ * Harsha Priya <priya.harsha(a)intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This file defines all sst ioctls
+ */
+
+/*codec and post/pre processing related info*/
+
+enum sst_codec_types {
+/* AUDIO/MUSIC CODEC Type Definitions */
+ SST_CODEC_TYPE_UNKNOWN = 0,
+ SST_CODEC_TYPE_PCM, /* Pass through Audio codec */
+ SST_CODEC_TYPE_MP3,
+ SST_CODEC_TYPE_MP24,
+ SST_CODEC_TYPE_AAC,
+ SST_CODEC_TYPE_AACP,
+ SST_CODEC_TYPE_eAACP,
+ SST_CODEC_TYPE_WMA9,
+ SST_CODEC_TYPE_WMA10,
+ SST_CODEC_TYPE_WMA10P,
+ SST_CODEC_TYPE_RA,
+ SST_CODEC_TYPE_DDAC3,
+ SST_CODEC_TYPE_STEREO_TRUE_HD,
+ SST_CODEC_TYPE_STEREO_HD_PLUS,
+
+ /* VOICE CODEC Type Definitions */
+ SST_CODEC_TYPE_VOICE_PCM = 0x21, /* Pass through voice codec */
+ SRC = 0x64,
+ MIXER = 0x65,
+ DOWN_MIXER = 0x66,
+ VOLUME_CONTROL = 0x67,
+ OEM1 = 0xC8,
+ OEM2 = 0xC9,
+};
+
+enum snd_sst_stream_ops {
+ STREAM_OPS_PLAYBACK = 0, /* Decode */
+ STREAM_OPS_CAPTURE, /* Encode */
+ STREAM_OPS_PLAYBACK_DRM, /* Play Audio/Voice */
+ STREAM_OPS_PLAYBACK_ALERT, /* Play Audio/Voice */
+ STREAM_OPS_CAPTURE_VOICE_CALL, /* CSV Voice recording */
+};
+
+enum stream_type {
+ STREAM_TYPE_MUSIC = 1,
+ STREAM_TYPE_VOICE
+};
+
+/* Firmware Version info */
+struct snd_sst_fw_version {
+ __u8 build; /* build number*/
+ __u8 minor; /* minor number*/
+ __u8 major; /* major number*/
+ __u8 type; /* build type*/
+};
+
+/* Port info structure */
+struct snd_sst_port_info {
+ __u16 port_type;
+ __u16 reserved;
+};
+
+/* Mixer info structure */
+struct snd_sst_mix_info {
+ __u16 max_streams;
+ __u16 reserved;
+};
+
+/* PCM Parameters */
+struct snd_pcm_params {
+ __u16 codec; /* codec type */
+ __u8 num_chan; /* 1=Mono, 2=Stereo */
+ __u8 pcm_wd_sz; /* 16/24 - bit*/
+ __u32 brate; /* Bitrate in bits per second */
+ __u32 sfreq; /* Sampling rate in Hz */
+ __u16 frame_size;
+ __u16 samples_per_frame; /* Frame size num samples per frame */
+ __u32 period_count; /* period elapsed time count, in samples,*/
+};
+
+/* MP3 Music Parameters Message */
+struct snd_mp3_params {
+ __u16 codec;
+ __u8 num_chan; /* 1=Mono, 2=Stereo */
+ __u8 pcm_wd_sz; /* 16/24 - bit*/
+ __u32 brate; /* Use the hard coded value. */
+ __u32 sfreq; /* Sampling freq eg. 8000, 441000, 48000 */
+ __u8 crc_check; /* crc_check - disable (0) or enable (1) */
+ __u8 op_align; /* op align 0- 16 bit, 1- MSB, 2 LSB*/
+ __u16 reserved; /* Unused */
+};
+
+#define AAC_BIT_STREAM_ADTS 0
+#define AAC_BIT_STREAM_ADIF 1
+#define AAC_BIT_STREAM_RAW 2
+
+/* AAC Music Parameters Message */
+struct snd_aac_params {
+ __u16 codec;
+ __u8 num_chan; /* 1=Mono, 2=Stereo*/
+ __u8 pcm_wd_sz; /* 16/24 - bit*/
+ __u32 brate;
+ __u32 sfreq; /* Sampling freq eg. 8000, 441000, 48000 */
+ __u32 aac_srate; /* Plain AAC decoder operating sample rate */
+ __u8 mpg_id; /* 0=MPEG-2, 1=MPEG-4 */
+ __u8 bs_format; /* input bit stream format adts=0, adif=1, raw=2 */
+ __u8 aac_profile; /* 0=Main Profile, 1=LC profile, 3=SSR profile */
+ __u8 ext_chl; /* No.of external channels */
+ __u8 aot; /* Audio object type. 1=Main , 2=LC , 3=SSR, 4=SBR*/
+ __u8 op_align; /* output alignment 0=16 bit , 1=MSB, 2= LSB align */
+ __u8 brate_type; /* 0=CBR, 1=VBR */
+ __u8 crc_check; /* crc check 0= disable, 1=enable */
+ __s8 bit_stream_format[8]; /* input bit stream format adts/adif/raw */
+};
+
+/* WMA Music Parameters Message */
+struct snd_wma_params {
+ __u16 codec;
+ __u8 num_chan; /* 1=Mono, 2=Stereo */
+ __u8 pcm_wd_sz; /* 16/24 - bit*/
+ __u32 brate; /* Use the hard coded value. */
+ __u32 sfreq; /* Sampling freq eg. 8000, 441000, 48000 */
+ __u32 channel_mask; /* Channel Mask */
+ __u16 format_tag; /* Format Tag */
+ __u16 block_align; /* packet size */
+ __u16 wma_encode_opt;/* Encoder option */
+ __u8 op_align; /* op align 0- 16 bit, 1- MSB, 2 LSB*/
+ __u8 reserved; /* reserved */
+};
+
+/* Pre processing param structure */
+struct snd_prp_params {
+ __u32 reserved; /* No pre-processing defined yet */
+};
+
+/* Post processing param structure */
+struct snd_pop_params {
+ s16 volume; /* Voulme in db */
+ u16 ramp_duration; /* Ramp duration in ms */
+ u16 mute; /* 0=Un-mute, 1=Mute*/
+ u16 reserved; /* */
+};
+
+/* Post processing Capability info structure */
+struct snd_sst_postproc_info {
+ __u32 src_min; /* Supported SRC Min sampling freq */
+ __u32 src_max; /* Supported SRC Max sampling freq */
+ __u8 src; /* 0=Not supported, 1=Supported */
+ __u8 bass_boost; /* 0=Not Supported, 1=Supported */
+ __u8 stereo_widening; /* 0=Not Supported, 1=Supported */
+ __u8 volume_control; /* 0=Not Supported, 1=Supported */
+ __s16 min_vol; /* Minimum value of Volume in dB */
+ __s16 max_vol; /* Maximum value of Volume in dB */
+};
+
+/* pre processing Capability info structure */
+struct snd_sst_prp_info {
+ __s16 min_vol; /* Minimum value of Volume in dB */
+ __s16 max_vol; /* Maximum value of Volume in dB */
+ __u8 volume_control; /* 0=Not Supported, 1=Supported */
+ __u8 reserved1; /* for 32 bit alignment */
+ __u16 reserved2; /* for 32 bit alignment */
+} __attribute__ ((packed));
+
+/* Firmware capabilities info */
+struct snd_sst_fw_info {
+ struct snd_sst_fw_version fw_version; /* Firmware version */
+ __u8 audio_codecs_supported[8]; /* Codecs supported by FW */
+ __u32 recommend_min_duration; /* Min duration for Low power Playback*/
+ __u8 max_pcm_streams_supported; /*Max number of PCM streams supported */
+ __u8 max_enc_streams_supported; /*Max number of Encoded streams */
+ __u16 reserved; /* 32 bit alignment*/
+ struct snd_sst_postproc_info pop_info; /* Post processing capability*/
+ struct snd_sst_prp_info prp_info; /* pre_processing mod cap info */
+ struct snd_sst_port_info port_info[2]; /* Port info */
+ struct snd_sst_mix_info mix_info; /* Mixer info */
+ __u32 min_input_buf; /*minmum i/p buffer for decode*/
+};
+
+/* Add the codec parameter structures for new codecs to be supported */
+#define CODEC_PARAM_STRUCTURES \
+ struct snd_pcm_params pcm_params; \
+ struct snd_mp3_params mp3_params; \
+ struct snd_aac_params aac_params; \
+ struct snd_wma_params wma_params;
+
+/* Pre and Post Processing param structures */
+#define PPP_PARAM_STRUCTURES \
+ struct snd_prp_params prp_params;\
+ struct snd_pop_params pop_params;
+
+/* Codec params struture */
+union snd_sst_codec_params {
+ CODEC_PARAM_STRUCTURES;
+};
+
+/* Pre-processing params struture */
+union snd_sst_ppp_params{
+ PPP_PARAM_STRUCTURES;
+};
+
+struct snd_sst_stream_params {
+ union snd_sst_codec_params uc;
+ union snd_sst_ppp_params up;
+} __attribute__ ((packed));
+
+struct snd_sst_params {
+ unsigned long result;
+ unsigned int stream_id;
+ enum sst_codec_types codec;
+ enum snd_sst_stream_ops ops;
+ unsigned int stream_type;
+ struct snd_sst_stream_params sparams;
+};
+
+/*ioctl related stuff here*/
+struct snd_sst_pmic_config {
+ __u32 sfreq; /* Sampling rate in Hz */
+ __u16 num_chan; /* Mono =1 or Stereo =2 */
+ __u16 pcm_wd_sz; /* Number of bits per sample */
+} __attribute__ ((packed));
+
+struct snd_sst_get_stream_params {
+ struct snd_sst_params codec_params;
+ struct snd_sst_pmic_config pcm_params;
+};
+
+enum snd_sst_target_type {
+ SND_SST_TARGET_PMIC = 1,
+ SND_SST_TARGET_OTHER,
+};
+
+enum snd_sst_port_action {
+ SND_SST_PORT_PREPARE = 1,
+ SND_SST_PORT_ACTIVATE,
+};
+
+/* Target selection per device structure */
+struct snd_sst_slot_info {
+ __u8 mix_enable; /* Mixer enable or disable */
+ __u8 device_type;
+ __u8 device_instance; /* 0, 1, 2 */
+ __u16 slot[2];
+ struct snd_sst_pmic_config pcm_params;
+ enum snd_sst_target_type type;
+ __s8 master;
+ enum snd_sst_port_action action;
+} __attribute__ ((packed));
+
+/* Target device list structure */
+struct snd_sst_target_device {
+ __u32 device_route;
+ struct snd_sst_slot_info devices[2];
+} __attribute__ ((packed));
+
+struct snd_sst_driver_info {
+ unsigned int version; /* Version of the driver */
+ unsigned int active_pcm_streams;
+ unsigned int active_enc_streams;
+ unsigned int max_pcm_streams;
+ unsigned int max_enc_streams;
+ unsigned int buf_per_stream;
+};
+
+struct snd_sst_vol {
+ unsigned int stream_id;
+ int volume;
+ unsigned long ramp_duration;
+ __u32 ramp_type; /* Ramp type, default=0 */
+};
+
+struct snd_sst_mute {
+ unsigned int stream_id;
+ int mute;
+};
+
+enum snd_sst_buff_type {
+ SST_BUF_USER = 1,
+ SST_BUF_MMAP,
+ SST_BUF_RAR,
+};
+
+struct snd_sst_buff_entry {
+ union {
+ void *user;
+ unsigned int offset;
+ } buffer;
+ unsigned int size;
+};
+
+struct snd_sst_buffs {
+ unsigned int entries;
+ enum snd_sst_buff_type type;
+ struct snd_sst_buff_entry *buff;
+};
+
+struct snd_sst_dbufs {
+ struct snd_sst_buff_entry *ibufs;
+ struct snd_sst_buff_entry *obufs;
+ __s8 force;
+};
+
+/*IOCTL defined here*/
+/*SST MMF IOCTLS only*/
+#define SNDRV_SST_STREAM_SET_PARAMS _IOR('L', 0x00, \
+ struct snd_sst_stream_params *)
+#define SNDRV_SST_STREAM_GET_PARAMS _IOWR('L', 0x01, \
+ struct snd_sst_get_stream_params *)
+#define SNDRV_SST_STREAM_GET_TSTAMP _IOWR('L', 0x02, unsigned long long *)
+#define SNDRV_SST_STREAM_DECODE _IOWR('L', 0x03, struct snd_sst_dbufs *)
+#define SNDRV_SST_STREAM_START _IO('A', 0x42)
+#define SNDRV_SST_STREAM_DROP _IO('A', 0x43)
+#define SNDRV_SST_STREAM_DRAIN _IO('A', 0x44)
+#define SNDRV_SST_STREAM_PAUSE _IOW('A', 0x45, int)
+#define SNDRV_SST_STREAM_RESUME _IO('A', 0x47)
+#define SNDRV_SST_MMAP_PLAY _IOW('L', 0x05, struct snd_sst_buffs *)
+#define SNDRV_SST_MMAP_CAPTURE _IOW('L', 0x06, struct snd_sst_buffs *)
+/*SST common ioctls */
+#define SNDRV_SST_DRIVER_INFO _IOR('L', 0x10, struct snd_sst_driver_info *)
+#define SNDRV_SST_SET_VOL _IOW('L', 0x11, struct snd_sst_vol *)
+#define SNDRV_SST_GET_VOL _IOW('L', 0x12, struct snd_sst_vol *)
+#define SNDRV_SST_MUTE _IOW('L', 0x13, struct snd_sst_mute *)
+
+/*AM Ioctly only*/
+#define SNDRV_SST_FW_INFO _IOR('L', 0x20, struct snd_sst_fw_info *)
+#define SNDRV_SST_SET_TARGET_DEVICE _IOW('L', 0x21, \
+ struct snd_sst_target_device *)
+
+#endif /*__INTEL_SST_IOCTL_H__*/
--
1.5.4.5
4
9
07 Jul '09
This patch adds the SST driver interface modules. Interface
module is the one which talks to other layers of SST drivers.
intel_sst_interface.c - This file implements the MAD driver
registration and de registration functions. SST driver is also
a character driver that allows players/middleware to communicate
with SST driver. All char driver routines are implemented here.
The ioctls used by middleware to open/close, control and
configure stream and transfer the data are implemented here
Signed-off-by: Vinod Koul <vinod.koul(a)intel.com>
Signed-off-by: Harsha Priya <priya.harsha(a)intel.com>
Signed-off-by: R Dharageswari <dharageswari.r(a)intel.com>
new file: sound/pci/sst/intel_sst_interface.c
---
sound/pci/sst/intel_sst_interface.c | 1359 +++++++++++++++++++++++++++++++++++
1 files changed, 1359 insertions(+), 0 deletions(-)
create mode 100644 sound/pci/sst/intel_sst_interface.c
diff --git a/sound/pci/sst/intel_sst_interface.c b/sound/pci/sst/intel_sst_interface.c
new file mode 100644
index 0000000..f8cefa5
--- /dev/null
+++ b/sound/pci/sst/intel_sst_interface.c
@@ -0,0 +1,1359 @@
+/*
+ * intel_sst_interface.c - Intel SST Driver for audio engine
+ *
+ * Copyright (C) 2008-09 Intel Corporation
+ * Authors: Vinod Koul <vinod.koul(a)intel.com>
+ * Harsha Priya <priya.harsha(a)intel.com>
+ * R Dharageswari <dharageswari.r(a)intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * This driver exposes the audio engine functionalities to the ALSA
+ * and middleware.
+ * Upper layer interfaces (MAD driver, MMF) to SST driver
+ */
+
+#include <linux/cdev.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/syscalls.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/fcntl.h>
+#include <linux/uaccess.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/workqueue.h>
+#include <linux/pci.h>
+#include <linux/firmware.h>
+#include <asm/div64.h>
+#include <linux/ioctl.h>
+#include <sound/intel_sst.h>
+#include <sound/intel_sst_ioctl.h>
+#include "intel_sst_fw_ipc.h"
+#include "intel_sst_common.h"
+#include "intel_sst_pvt.h"
+#ifdef CONFIG_SST_OSPM_SUPPORT
+#include <linux/intel_mid.h>
+#endif
+
+
+int sst_download_fw(void)
+{
+ int retval = 0;
+ const struct firmware *fw_sst;
+
+ sst_dbg("SST Downloading FW now...\n");
+ retval = request_firmware(&fw_sst,
+ SST_FW_STD_FILENAME,
+ &sst_ops->pci->dev);
+ if (0 != retval) {
+ sst_err("fw load failed %d \n", retval);
+ return retval;
+ }
+ sst_ops->alloc_block[0].sst_id = 0xFF;
+ sst_load_fw(fw_sst, NULL);
+ retval = sst_wait_timeout(sst_ops, &sst_ops->alloc_block[0]);
+ release_firmware(fw_sst);
+ sst_ops->alloc_block[0].sst_id = BLOCK_UNINIT;
+ return retval;
+}
+
+/**
+* intel_sst_open - opens a handle to driver
+* @i_node: inode structure
+* @file_ptr:pointer to file
+*
+* This function is called by OS when a user space component
+* tries to get a driver handle. Only one handle at a time
+* will be allowed
+*/
+int intel_sst_open(struct inode *i_node, struct file *file_ptr)
+{
+ dev_t device = i_node->i_rdev;
+ unsigned int retval = 0;
+ struct ioctl_pvt_data *data = NULL;
+
+ if (sst_ops->pmic_state != PMIC_SND_INIT_DONE) {
+ sst_err("Sound card not availble \n");
+ return -EIO;
+ }
+
+ if (SST_UN_INIT == sst_ops->sst_state) {
+ /*FW is not downloaded*/
+ retval = sst_download_fw();
+ if (retval != 0) {
+ sst_err("FW download failed...abort\n");
+ return -ENODEV;
+ }
+ }
+ if (device == MKDEV(INTEL_SST_MAJOR, 0)) {
+ /*app open*/
+ if (sst_ops->active_cnt < MAX_ENC_STREAM) {
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (NULL == data)
+ return -ENOMEM;
+ sst_ops->active_cnt++;
+ sst_ops->stream_cnt++;
+ data->pvt_id = sst_assign_pvt_id(sst_ops);
+ data->str_id = 0;
+ file_ptr->private_data = (void *)data;
+ sst_dbg("sst id allocated = %d!\n", data->pvt_id);
+ } else
+ retval = -EACCES;
+ } else if (device == MKDEV(INTEL_SST_MAJOR, 1)) {
+ /*audio manager open*/
+ if (sst_ops->am_cnt < MAX_AM_HANDLES) {
+ sst_ops->am_cnt++;
+ sst_dbg("AM handle opened...\n");
+ } else
+ retval = -EACCES;
+ } else
+ retval = -EINVAL;
+ return retval;
+}
+
+/**
+* intel_sst_release - releases a handle to driver
+* @i_node: inode structure
+* @file_ptr: pointer to file
+*
+* This function is called by OS when a user space component
+* tries to release a driver handle.
+*/
+int intel_sst_release(struct inode *i_node, struct file *file_ptr)
+{
+ dev_t device = i_node->i_rdev;
+ struct ioctl_pvt_data *data =
+ (struct ioctl_pvt_data *)file_ptr->private_data;
+
+ sst_dbg("Release called \n");
+ if (device == MKDEV(INTEL_SST_MAJOR, 0)) {
+ /*app close*/
+ sst_dbg("Closing app handle \n");
+ sst_ops->active_cnt--;
+ sst_ops->stream_cnt--;
+ if (0 != sst_free_stream(data->str_id)) {
+ if (sst_validate_strid(data->str_id) == 0)
+ sst_clean_stream(
+ &sst_ops->streams[data->str_id]);
+ }
+ kfree(data);
+ } else if (device == MKDEV(INTEL_SST_MAJOR, 1))
+ /*audio manager close*/
+ sst_dbg("AM handle closed \n");
+ sst_ops->am_cnt--;
+ return 0;
+}
+
+int intel_sst_mmap(struct file *file_ptr, struct vm_area_struct *vma)
+{
+ int retval = 0, length = 0;
+ struct ioctl_pvt_data *data =
+ (struct ioctl_pvt_data *)file_ptr->private_data;
+ int str_id = data->str_id;
+ void *mem_area = NULL;
+
+ retval = sst_validate_strid(str_id);
+ if (retval != 0)
+ return -EINVAL;
+
+ length = vma->vm_end - vma->vm_start;
+ sst_dbg("called for stream %d length 0x%x\n", str_id, length);
+
+ if (length > sst_ops->mmap_len)
+ return -ENOMEM;
+ if (sst_ops->mmap_mem == NULL)
+ return -EIO;
+
+ /* round it up to the page bondary */
+ mem_area = (void *)((((unsigned long)sst_ops->mmap_mem) + PAGE_SIZE - 1)
+ & PAGE_MASK);
+
+ /* map the whole physically contiguous area in one piece */
+ retval = remap_pfn_range(vma,
+ vma->vm_start,
+ virt_to_phys((void *)mem_area) >> PAGE_SHIFT,
+ length,
+ vma->vm_page_prot);
+ if (retval != 0) {
+ sst_ops->streams[str_id].mmapped = false;
+ sst_err("mapping failed %d", retval);
+ } else
+ sst_ops->streams[str_id].mmapped = true;
+
+ sst_dbg("mmap ret 0x%x \n", retval);
+ return retval;
+}
+/**
+* intel_sst_write- send data to play out
+*/
+int intel_sst_mmap_play_capture(u32 str_id, struct snd_sst_buffs *mmap_buf)
+{
+ struct sst_stream_bufs *bufs = NULL;
+ int retval = 0, i;
+ struct stream_info *stream = NULL;
+ struct snd_sst_buff_entry *buf_entry = NULL;
+
+ sst_dbg("called for str_id %d \n", str_id);
+ retval = sst_validate_strid(str_id);
+ if (retval != 0) {
+ sst_err("val failed %d", retval);
+ return -EINVAL;
+ }
+ BUG_ON(!mmap_buf);
+
+ stream = &sst_ops->streams[str_id];
+ if (stream->mmapped != true) {
+ sst_err("stream not mapped!!!");
+ return -EIO;
+ }
+
+ if (stream->status != STREAM_RUNNING &&
+ stream->status != STREAM_INIT) {
+ sst_err("BAD REQUEST!, stream state is %d\n", stream->status);
+ return -EBADRQC;
+ }
+
+ sst_dbg("new buffers count %d status %d\n",
+ mmap_buf->entries, stream->status);
+ buf_entry = mmap_buf->buff;
+ for (i = 0; i < mmap_buf->entries; i++) {
+ BUG_ON(!buf_entry);
+ bufs = kzalloc(sizeof(*bufs), GFP_KERNEL);
+ if (bufs == NULL)
+ return -ENOMEM;
+ bufs->size = buf_entry->size;
+ bufs->offset = buf_entry->buffer.offset;
+ bufs->addr = sst_ops->mmap_mem;
+ bufs->in_use = false;
+ buf_entry++;
+ /*locking here*/
+ mutex_lock(&stream->lock);
+ list_add_tail(&bufs->node, &stream->bufs);
+ mutex_unlock(&stream->lock);
+ }
+
+ mutex_lock(&stream->lock);
+ stream->data_blk.condition = false;
+ stream->data_blk.ret_code = 0;
+ if (stream->status == STREAM_INIT && stream->prev != STREAM_UN_INIT) {
+ stream->prev = stream->status;
+ stream->status = STREAM_RUNNING;
+ if (stream->ops == STREAM_OPS_PLAYBACK) {
+ sst_dbg("play frames...\n");
+ if (sst_play_frame(str_id) < 0) {
+ sst_err("play frames failed \n");
+ mutex_unlock(&stream->lock);
+ return -EIO;
+ }
+ } else if (stream->ops == STREAM_OPS_CAPTURE) {
+ sst_dbg("capture frames...\n");
+ if (sst_capture_frame(str_id) < 0) {
+ sst_err("capture frames failed \n");
+ mutex_unlock(&stream->lock);
+ return -EIO;
+ }
+ }
+ }
+ mutex_unlock(&stream->lock);
+ /*Block the call for reply*/
+ if (0 == list_empty(&stream->bufs)) {
+ sst_dbg("ioctl waiting...\n");
+ stream->data_blk.on = true;
+ retval = sst_wait_interruptible(sst_ops, &stream->data_blk);
+ }
+
+ sst_dbg("end of play/rec ioctl!!\n");
+ return retval;
+}
+
+int sst_play_capture(struct stream_info *stream, int str_id)
+{
+ int retval;
+
+ stream->data_blk.condition = false;
+ stream->data_blk.ret_code = 0;
+ mutex_lock(&stream->lock);
+ if (stream->status == STREAM_INIT && stream->prev != STREAM_UN_INIT) {
+ /*stream is started*/
+ stream->prev = stream->status;
+ stream->status = STREAM_RUNNING;
+ }
+
+ if (stream->status == STREAM_INIT && stream->prev == STREAM_UN_INIT) {
+ /*stream is not started yet*/
+ sst_err("Stream isnt started yet state %d, prev %d \n",
+ stream->status, stream->prev);
+ } else if (stream->status == STREAM_RUNNING) {
+ /*stream is started*/
+ if (stream->ops == STREAM_OPS_PLAYBACK) {
+ if (sst_play_frame(str_id) < 0) {
+ sst_err("play frames failed \n");
+ mutex_unlock(&stream->lock);
+ return -EIO;
+ }
+ } else if (stream->ops == STREAM_OPS_CAPTURE) {
+ if (sst_capture_frame(str_id) < 0) {
+ sst_err("capture frames failed \n");
+ mutex_unlock(&stream->lock);
+ return -EIO;
+ }
+ }
+ } else
+ sst_err("Stream state %d invalid will still block, prev %d\n",
+ stream->status, stream->prev);
+ mutex_unlock(&stream->lock);
+ /*Block the call for reply*/
+ sst_dbg("write waiting...\n");
+ stream->data_blk.on = true;
+ retval = sst_wait_interruptible(sst_ops, &stream->data_blk);
+ if (retval != 0) {
+ stream->status = STREAM_INIT;
+ sst_dbg("wait returned error...\n");
+ }
+ return retval;
+}
+
+int snd_sst_fill_kernel_list(struct stream_info *stream,
+ const struct iovec *iovec, unsigned long nr_segs,
+ struct list_head *copy_to_list)
+{
+ struct sst_stream_bufs *stream_bufs = NULL;
+ unsigned long index, data_not_copied, mmap_len;
+ unsigned char *bufp;
+ unsigned long size, copied_size;
+ int retval = 0, add_to_list = 0;
+ static int sent_offset;
+ static unsigned long sent_index;
+
+ stream_bufs = kzalloc(sizeof(*stream_bufs), GFP_KERNEL);
+ if (stream_bufs == NULL) {
+ sst_err("memory allocation failed \n");
+ return -ENOMEM;
+ }
+
+ mmap_len = sst_ops->mmap_len;
+ stream_bufs->addr = sst_ops->mmap_mem;
+ bufp = stream->cur_ptr;
+
+ sst_dbg("mmap_len - %lx\n", mmap_len);
+ copied_size = 0;
+
+ if (stream->sg_index == 0)
+ sent_index = sent_offset = 0;
+
+ for (index = stream->sg_index; index < nr_segs; index++) {
+ stream->sg_index = index;
+ sst_dbg("index - %lx, cur_ptr - %p\n", index, stream->cur_ptr);
+ sst_dbg("base - %p, size - 0x%x\n", iovec[index].iov_base,
+ iovec[index].iov_len);
+ sst_dbg("bufp - %p\n", bufp);
+ if (stream->cur_ptr == NULL)
+ bufp = iovec[index].iov_base;
+
+ size = ((unsigned long)iovec[index].iov_base
+ + iovec[index].iov_len) - (unsigned long) bufp;
+
+ sst_dbg("size - %lx\n", size);
+ if ((copied_size + size) > mmap_len)
+ size = mmap_len - copied_size;
+
+ sst_dbg("size - %lx\n", size);
+
+ if (stream->ops == STREAM_OPS_PLAYBACK) {
+ sst_dbg("Playback stream copying now....\n");
+ data_not_copied = copy_from_user(
+ (void *)(stream_bufs->addr + copied_size),
+ bufp, size);
+ if (data_not_copied > 0) {
+ /*Clean up the list and return error code */
+ sst_err("copy from user not copied -%ld\n",
+ data_not_copied);
+ retval = -EIO;
+ break;
+ }
+ } else {
+ struct snd_sst_user_cap_list *entry =
+ kzalloc(sizeof(*entry), GFP_KERNEL);
+
+ if (entry == NULL) {
+ sst_err("mem alloacation failed \n");
+ return -ENOMEM;
+ }
+ entry->iov_index = index;
+ entry->iov_offset = (unsigned long) bufp -
+ (unsigned long)iovec[index].iov_base;
+ entry->offset = copied_size;
+ entry->size = size;
+ sst_dbg("ENTRY:ioindx %d,iooff %ld,koff %ld,ksz %ld \n",
+ entry->iov_index, entry->iov_offset,
+ entry->offset, entry->size);
+ list_add_tail(&entry->node, copy_to_list);
+ }
+
+ sst_dbg("cur_ptr - %lx\n", (unsigned long) stream->cur_ptr);
+ stream->cur_ptr = bufp + size;
+
+ if (((unsigned long)iovec[index].iov_base
+ + iovec[index].iov_len) ==
+ (unsigned long)stream->cur_ptr) {
+ stream->cur_ptr = NULL;
+ stream->sg_index++;
+ }
+
+ copied_size += size;
+ sst_dbg("copied_size - %lx\n", copied_size);
+ if ((copied_size >= mmap_len) ||
+ (stream->sg_index == nr_segs)) {
+ add_to_list = 1;
+ }
+
+ if (add_to_list) {
+ stream_bufs->in_use = false;
+ stream_bufs->size = copied_size;
+ /*locking here*/
+ mutex_lock(&stream->lock);
+ list_add_tail(&stream_bufs->node, &stream->bufs);
+ mutex_unlock(&stream->lock);
+ break;
+ }
+ }
+ return retval;
+}
+
+int snd_sst_copy_userbuf_capture(struct stream_info *stream,
+ const struct iovec *iovec,
+ struct list_head *copy_to_list)
+{
+ struct snd_sst_user_cap_list *entry, *_entry;
+ struct sst_stream_bufs *kbufs = NULL, *_kbufs;
+ int retval = 0;
+ unsigned long data_not_copied;
+
+ /*copy sent buffers*/
+ sst_dbg("capture stream copying to user now...\n");
+ list_for_each_entry_safe(kbufs, _kbufs, &stream->bufs, node) {
+ if (kbufs->in_use == true) {
+ /*copy to user*/
+ list_for_each_entry_safe(entry, _entry,
+ copy_to_list, node) {
+ sst_dbg("filling now... \n");
+ sst_dbg("iindx %d,ioff %ld,koff %ld,ksz %ld \n",
+ entry->iov_index, entry->iov_offset,
+ entry->offset, entry->size);
+ sst_dbg("Copying at %p size %lx\n",
+ iovec[entry->iov_index].iov_base +
+ entry->iov_offset,
+ entry->size);
+ data_not_copied = copy_to_user((void *)
+ iovec[entry->iov_index].iov_base +
+ entry->iov_offset,
+ kbufs->addr + entry->offset,
+ entry->size);
+ if (data_not_copied > 0) {
+ /*Clean up the list and return error*/
+ sst_err("copy to user err -%ld\n",
+ data_not_copied);
+ retval = -EIO;
+ break;
+ }
+ list_del(&entry->node);
+ kfree(entry);
+ }
+ sst_dbg("coming out of loop\n");
+ }
+ }
+ sst_dbg("end of cap copy\n");
+ return retval;
+}
+/*
+ * snd_sst_userbufs_play_cap - constructs the list from user buffers
+ * @iovec: pointer to iovec structure
+ * @nr_segs: number entries in the iovec structure
+ * @str_id: stream id
+ * @stream: pointer to stream_info structure
+ * This function will traverse the user list and copy the data to the kernel
+ * space buffers.
+ */
+int snd_sst_userbufs_play_cap(const struct iovec *iovec,
+ unsigned long nr_segs, unsigned int str_id,
+ struct stream_info *stream)
+{
+ int retval = 0;
+ LIST_HEAD(copy_to_list);
+
+
+ retval = snd_sst_fill_kernel_list(stream, iovec, nr_segs,
+ ©_to_list);
+
+ retval = sst_play_capture(stream, str_id);
+ if (retval < 0)
+ return retval;
+
+ if (stream->ops == STREAM_OPS_CAPTURE) {
+ retval = snd_sst_copy_userbuf_capture(stream, iovec,
+ ©_to_list);
+ }
+ return retval;
+}
+
+int intel_sst_read_write(unsigned int str_id, char __user *buf, size_t count)
+{
+ int retval = 0;
+ struct stream_info *stream = NULL;
+ struct iovec iovec;
+ unsigned long nr_segs;
+
+ retval = sst_validate_strid(str_id);
+ if (retval != 0)
+ return -EINVAL;
+ stream = &sst_ops->streams[str_id];
+ if (stream->mmapped == true) {
+ sst_err("user write & stream is mapped!!!");
+ return -EIO;
+ }
+ if (count == 0) {
+ sst_err("args invalid %d", retval);
+ return -EINVAL;
+ }
+ /*copy user buf details*/
+ if (stream->status != STREAM_RUNNING && stream->status != STREAM_INIT) {
+ sst_err("BAD REQUEST!\n");
+ return -EBADRQC;
+ }
+ sst_dbg("new buffers %p, copy size %d, status %d\n" ,
+ buf, (int) count, (int) stream->status);
+
+ stream->buf_type = SST_BUF_USER_STATIC;
+ iovec.iov_base = (void *)buf;
+ iovec.iov_len = count;
+ nr_segs = 1;
+
+ do {
+ retval = snd_sst_userbufs_play_cap(&iovec, nr_segs,
+ str_id, stream);
+
+ if (retval < 0)
+ break;
+
+ } while (stream->sg_index < nr_segs);
+
+ stream->sg_index = 0;
+ stream->cur_ptr = NULL;
+ return retval;
+}
+
+int intel_sst_write(struct file *file_ptr, const char __user *buf,
+ size_t count, loff_t *offset)
+{
+ struct ioctl_pvt_data *data =
+ (struct ioctl_pvt_data *)file_ptr->private_data;
+ int str_id = data->str_id;
+
+ sst_dbg("called for %d\n", str_id);
+ return intel_sst_read_write(str_id, (char __user *)buf, count);
+}
+
+/*
+ *
+ * intel_sst_aio_write- send data to play out
+ *
+ */
+ssize_t intel_sst_aio_write(struct kiocb *kiocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t offset)
+{
+ int retval = 0;
+ struct ioctl_pvt_data *data =
+ (struct ioctl_pvt_data *)kiocb->ki_filp->private_data;
+ int str_id = data->str_id;
+ struct stream_info *stream = NULL;
+
+ sst_dbg("entry - %ld\n", nr_segs);
+
+ if (is_sync_kiocb(kiocb) == false) {
+ sst_dbg("aio_read from user space is not allowed\n");
+ return -EINVAL;
+ }
+
+ sst_dbg("called for str_id %d \n", str_id);
+ retval = sst_validate_strid(str_id);
+ if (retval != 0)
+ return -EINVAL;
+ stream = &sst_ops->streams[str_id];
+ if (stream->mmapped == true) {
+ sst_err("user write & stream is mapped!!!");
+ return -EIO;
+ }
+ if (stream->status != STREAM_RUNNING && stream->status != STREAM_INIT) {
+ sst_err("BAD REQUEST!\n");
+ return -EBADRQC;
+ }
+ sst_dbg("new segs %ld, offset %d, status %d\n" ,
+ nr_segs, (int) offset, (int) stream->status);
+ stream->buf_type = SST_BUF_USER_STATIC;
+ do {
+ retval = snd_sst_userbufs_play_cap(iov, nr_segs,
+ str_id, stream);
+ if (retval < 0)
+ break;
+
+ } while (stream->sg_index < nr_segs);
+
+ stream->sg_index = 0;
+ stream->cur_ptr = NULL;
+
+ return retval;
+}
+
+/*
+* intel_sst_read- get captured data
+*/
+int intel_sst_read(struct file *file_ptr, char __user *buf,
+ size_t count, loff_t *offset)
+{
+ struct ioctl_pvt_data *data =
+ (struct ioctl_pvt_data *)file_ptr->private_data;
+ int str_id = data->str_id;
+
+ sst_dbg("called for %d\n", str_id);
+ return intel_sst_read_write(str_id, buf, count);
+}
+
+ssize_t intel_sst_aio_read(struct kiocb *kiocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t offset)
+{
+ int retval = 0;
+ struct ioctl_pvt_data *data =
+ (struct ioctl_pvt_data *)kiocb->ki_filp->private_data;
+ int str_id = data->str_id;
+ struct stream_info *stream = NULL;
+
+ sst_dbg("entry - %ld\n", nr_segs);
+
+ if (is_sync_kiocb(kiocb) == false) {
+ sst_dbg("aio_read from user space is not allowed\n");
+ return -EINVAL;
+ }
+
+ sst_dbg("called for str_id %d \n", str_id);
+ retval = sst_validate_strid(str_id);
+ if (retval != 0)
+ return -EINVAL;
+ stream = &sst_ops->streams[str_id];
+ if (stream->mmapped == true) {
+ sst_err("user write & stream is mapped!!!");
+ return -EIO;
+ }
+ if (stream->status != STREAM_RUNNING && stream->status != STREAM_INIT) {
+ sst_err("BAD REQUEST!\n");
+ return -EBADRQC;
+ }
+ sst_dbg("new segs %ld, offset %d, status %d\n" ,
+ nr_segs, (int) offset, (int) stream->status);
+ stream->buf_type = SST_BUF_USER_STATIC;
+ do {
+ retval = snd_sst_userbufs_play_cap(iov, nr_segs,
+ str_id, stream);
+ if (retval < 0)
+ break;
+
+ } while (stream->sg_index < nr_segs);
+
+ stream->sg_index = 0;
+ stream->cur_ptr = NULL;
+
+ return retval;
+}
+
+int sst_get_stream_allocated(struct snd_sst_params *str_param,
+ u32 block, u32 pvt_id)
+{
+ int retval = 0;
+
+ retval = sst_alloc_stream((char *) &str_param->sparams, str_param->ops,
+ str_param->codec, pvt_id);
+ if (0 != retval) {
+ sst_err("sst_alloc_stream failed %d", retval);
+ goto err;
+ }
+ /*Block the call for reply*/
+ retval = sst_wait_timeout(sst_ops, &sst_ops->alloc_block[block]);
+err: return retval;
+}
+
+void set_port_params(struct snd_sst_params *str_param,
+ enum snd_sst_stream_ops ops)
+{
+ int sfreq = str_param->sparams.uc.pcm_params.sfreq;
+ int word_size = str_param->sparams.uc.pcm_params.pcm_wd_sz;
+
+ sst_dbg("sampling frequency = %d wd_size = %d \n", sfreq, word_size);
+
+ if (ops == STREAM_OPS_PLAYBACK) {
+ sst_dbg("Setting playback path and port settings...\n");
+ sst_ops->scard_ops.init_card();
+ sst_ops->scard_ops.set_pcm_params(sfreq, word_size);
+ } else if (ops == STREAM_OPS_CAPTURE) {
+ sst_dbg("Setting capture path...\n");
+ if (sst_ops->scard_ops.init_card_capture != NULL)
+ sst_ops->scard_ops.init_card_capture();
+ }
+ return;
+}
+
+int sst_get_stream(struct snd_sst_params *str_param, u32 pvt_id)
+{
+ int i = 0, retval = 0;
+
+ /*stream is not allocated, we are allocating*/
+ i = sst_get_block_stream(sst_ops);
+ sst_dbg("alloc block allocated = %d\n", i);
+ if (i < 0)
+ return -ENOMEM;
+ sst_ops->alloc_block[i].sst_id = pvt_id;
+
+ retval = sst_get_stream_allocated(str_param, i, pvt_id);
+ if (retval == -(SST_LIB_ERR_LIB_DNLD_REQUIRED)) {
+ /*codec download is required*/
+ struct snd_sst_alloc_response *response =
+ sst_ops->alloc_block[i].ops_block.data;
+ sst_dbg("Codec is required.... trying that\n");
+ retval = sst_load_library(&response->lib_dnld,
+ str_param->ops, pvt_id);
+ kfree(response);
+
+ if (retval == 0) {
+ sst_dbg("codec was downloaded sucesfully \n");
+ sst_dbg("try alloac again\n");
+ sst_ops->alloc_block[i].ops_block.condition = false;
+
+ retval = sst_get_stream_allocated(str_param, i, pvt_id);
+
+ if (retval <= 0)
+ goto err;
+ set_port_params(str_param, str_param->ops);
+
+ sst_dbg("Allocation done stream id %d \n", retval);
+ } else {
+ sst_dbg("codec download failed \n");
+ retval = -EIO;
+ goto err;
+ }
+ } else if (retval <= 0)
+ goto err;
+ else
+ set_port_params(str_param, str_param->ops);
+
+err:
+ sst_ops->alloc_block[i].sst_id = BLOCK_UNINIT;
+ return retval;
+}
+
+/**
+* intel_sst_ioctl - recieves the device ioctl's
+* @i_node: inode structure
+* @file_ptr: pointer to file
+* @cmd: Ioctl cmd
+* @arg: data
+*
+* This function is called by OS when a user space component
+* sends an Ioctl to SST driver
+*/
+int intel_sst_ioctl(struct inode *i_node, struct file *file_ptr,
+ unsigned int cmd, unsigned long arg)
+{
+ int retval = 0, i = 0;
+ struct ioctl_pvt_data *data = (struct ioctl_pvt_data *)
+ file_ptr->private_data;
+ int str_id = data->str_id, minor;
+
+ dev_t device = i_node->i_rdev;
+
+ if (device == MKDEV(INTEL_SST_MAJOR, 0))
+ minor = 0;
+ else if (device == MKDEV(INTEL_SST_MAJOR, 1))
+ minor = 1;
+ else
+ return -EINVAL;
+
+ if (SST_FW_RUNNING != sst_ops->sst_state) {
+ sst_err("SST Not runng %d\n", sst_ops->sst_state);
+ return -EBUSY;
+ }
+ switch (_IOC_NR(cmd)) {
+ case _IOC_NR(SNDRV_SST_STREAM_PAUSE):
+ sst_dbg("SNDRV_SST_IOCTL_PAUSE recieved for %d!\n", str_id);
+ if (minor != 0) {
+ retval = -EINVAL;
+ break;
+ }
+ retval = sst_pause_stream(str_id);
+ break;
+
+ case _IOC_NR(SNDRV_SST_STREAM_RESUME):
+ sst_dbg("SNDRV_SST_IOCTL_RESUME recieved!\n");
+ if (minor != 0) {
+ retval = -EINVAL;
+ break;
+ }
+ retval = sst_resume_stream(str_id);
+ break;
+
+ case _IOC_NR(SNDRV_SST_STREAM_SET_PARAMS): {
+ struct snd_sst_params *str_param = (struct snd_sst_params *)arg;
+
+ sst_dbg("IOCTL_SET_PARAMS recieved!\n");
+ if (minor != 0) {
+ retval = -EINVAL;
+ break;
+ }
+ sst_print_params(&str_param->sparams);
+
+ if (str_id == 0) {
+ retval = sst_get_stream(str_param, data->pvt_id);
+ if (retval > 0) {
+ data->str_id = retval;
+ retval = 0;
+ } else {
+ if (retval == -SST_ERR_INVALID_PARAMS)
+ retval = -EINVAL;
+ }
+ } else {
+ sst_dbg("SET_STREAM_PARAMS recieved!\n");
+ /*allocated set params only*/
+ retval = sst_set_stream_param(str_id, str_param);
+ /*Block the call for reply*/
+ if (retval == 0) {
+ int sfreq = 0, word_size = 0;
+ sfreq = str_param->sparams.uc.pcm_params.sfreq;
+ word_size = str_param->sparams.
+ uc.pcm_params.pcm_wd_sz;
+ retval = sst_wait_timeout(sst_ops,
+ &sst_ops->alloc_block[i]);
+ sst_dbg("SST sampling frequency= %d\n" , sfreq);
+ sst_ops->scard_ops.set_pcm_params(sfreq,
+ word_size);
+ }
+ }
+ break;
+ }
+
+ case _IOC_NR(SNDRV_SST_MMAP_PLAY):
+ case _IOC_NR(SNDRV_SST_MMAP_CAPTURE):
+ sst_dbg("SNDRV_SST_MMAP_PLAY/CAPTURE recieved!\n");
+ if (minor != 0) {
+ retval = -EINVAL;
+ break;
+ }
+ retval = intel_sst_mmap_play_capture(str_id,
+ (struct snd_sst_buffs *)arg);
+ break;
+
+ case _IOC_NR(SNDRV_SST_STREAM_DROP):
+ sst_dbg("SNDRV_SST_IOCTL_DROP recieved!\n");
+ if (minor != 0) {
+ retval = -EINVAL;
+ break;
+ }
+ retval = sst_drop_stream(str_id);
+ break;
+
+ case _IOC_NR(SNDRV_SST_STREAM_GET_TSTAMP): {
+ unsigned long long *ms = (unsigned long long *)arg;
+ struct snd_sst_tstamp tstamp = {0};
+ unsigned long long time = 0, freq = 0;
+ unsigned long mod = 0;
+
+ sst_dbg("SNDRV_SST_STREAM_GET_TSTAMP recieved!\n");
+ if (minor != 0) {
+ retval = -EINVAL;
+ break;
+ }
+ memcpy_fromio(&tstamp,
+ ((void *)(sst_ops->mailbox + SST_TIME_STAMP)
+ +(str_id * sizeof(tstamp))),
+ sizeof(tstamp));
+ time = tstamp.samples_rendered;
+ sst_dbg("samples rendered! = 0x%llx\n", time);
+ freq = (unsigned long long) tstamp.sampling_frequency;
+ sst_dbg("freq = %llx\n", freq);
+ mod = do_div(time, freq);
+ sst_dbg("mod = 0x%lx\n", mod);
+ sst_dbg("sec = 0x%llx\n", time);
+ time = time * 1000;
+ sst_dbg("msec = 0x%llx\n", time);
+ retval = copy_to_user(ms, &time, sizeof(*ms));
+ if (retval != 0)
+ sst_err("copy failed = %d\n", retval);
+ break;
+ }
+
+ case _IOC_NR(SNDRV_SST_STREAM_START):{
+ struct stream_info *stream = NULL;
+
+ sst_dbg("SNDRV_SST_STREAM_START recieved!\n");
+ if (minor != 0) {
+ retval = -EINVAL;
+ break;
+ }
+ retval = sst_validate_strid(str_id);
+ if (retval != 0)
+ break;
+ stream = &sst_ops->streams[str_id];
+ mutex_lock(&stream->lock);
+ if (stream->status == STREAM_INIT) {
+ sst_dbg("calling play frames...\n");
+ stream->prev = stream->status;
+ stream->status = STREAM_RUNNING;
+ if (stream->ops == STREAM_OPS_PLAYBACK) {
+ retval = sst_play_frame(str_id);
+#ifdef CONFIG_SST_OSPM_SUPPORT
+ sst_ospm_send_event(
+ OSPM_EVENT_SUBSYS_START_PLAY);
+#endif
+ } else if (stream->ops == STREAM_OPS_CAPTURE)
+ retval = sst_capture_frame(str_id);
+ else {
+ sst_err("Invalid ops 0x%x\n", stream->ops);
+ retval = -EINVAL;
+ mutex_unlock(&sst_ops->streams[str_id].lock);
+ break;
+ }
+ if (retval < 0) {
+ sst_err("play/capture frames failed \n");
+ stream->status = STREAM_INIT;
+ mutex_unlock(&sst_ops->streams[str_id].lock);
+ break;
+ }
+ } else {
+ sst_err("Invalid start for stream %d state 0x%x\n",
+ str_id, stream->status);
+ retval = -EINVAL;
+ }
+ mutex_unlock(&sst_ops->streams[str_id].lock);
+ break;
+ }
+ case _IOC_NR(SNDRV_SST_SET_TARGET_DEVICE): {
+ struct snd_sst_target_device *target_device = NULL;
+
+ sst_info("SNDRV_SST_SET_TARGET_PLAYBACK DEVICE recieved!\n");
+ target_device = (struct snd_sst_target_device *)arg;
+ BUG_ON(!target_device);
+ if (minor != 1) {
+ sst_err("called for non AM handle minor %d\n", minor);
+ retval = -EINVAL;
+ break;
+ }
+ retval = sst_target_device_select(target_device);
+ if (0 != retval)
+ return retval;
+ break;
+
+ }
+
+ case _IOC_NR(SNDRV_SST_DRIVER_INFO): {
+ struct snd_sst_driver_info *info =
+ (struct snd_sst_driver_info *)arg;
+ sst_dbg("SNDRV_SST_DRIVER_INFO recived \n");
+ info->version = SST_VERSION_NUM;
+ /*hard coding, shud get sumhow later*/
+ info->active_pcm_streams = sst_ops->stream_cnt -
+ sst_ops->active_cnt;
+ info->active_enc_streams = sst_ops->active_cnt;
+ info->max_pcm_streams = MAX_ACTIVE_STREAM - MAX_ENC_STREAM;
+ info->max_enc_streams = MAX_ENC_STREAM;
+ info->buf_per_stream = sst_ops->mmap_len;
+ break;
+ }
+
+ default:
+ sst_dbg("IOCTL not supported yet !\n");
+ retval = -ENOTTY;
+ }
+ sst_dbg("...complete ret code = %d\n", retval);
+
+ return retval;
+}
+
+/*
+ MAD Routines
+*/
+
+/**
+* sst_control_set - Set Control params
+* @control_list: list of controls to be set
+*
+* This function is called by MID sound card driver to set
+* SST/Sound card controls. This is registered with MID driver
+*/
+int sst_control_set(int control_element, void *value)
+{
+ int retval = 0, str_id = 0;
+
+ if (SST_UN_INIT == sst_ops->sst_state) {
+ /*FW is not downloaded*/
+ sst_dbg("DSP Downloading FW now...\n");
+ retval = sst_download_fw();
+ if (retval != 0) {
+ sst_err("FW download failed = 0x%x, abort\n", retval);
+ return retval;
+ }
+ }
+
+ switch (control_element) {
+ case SST_SND_ALLOC: {
+ struct snd_sst_params *str_param = NULL;
+ int pcm_id = sst_assign_pvt_id(sst_ops);
+
+ str_param = (struct snd_sst_params *)value;
+ BUG_ON(!str_param);
+ sst_print_params(&str_param->sparams);
+ retval = sst_get_stream(str_param, pcm_id);
+ if (retval >= 0)
+ sst_ops->stream_cnt++;
+#ifdef CONFIG_SST_OSPM_SUPPORT
+ if (str_param->ops == STREAM_OPS_PLAYBACK)
+ sst_ospm_send_event(OSPM_EVENT_SUBSYS_START_PLAY);
+#endif
+
+ break;
+ }
+
+ case SST_SND_PAUSE:
+ retval = sst_pause_stream(*(int *)value);
+ break;
+
+ case SST_SND_RESUME:
+ retval = sst_resume_stream(*(int *)value);
+ break;
+
+ case SST_SND_DROP:
+ retval = sst_drop_stream(*(int *)value);
+ break;
+
+ case SST_SND_FREE: {
+ struct stream_info *stream = NULL;
+
+ str_id = *(int *)value;
+ stream = &sst_ops->streams[str_id];
+ retval = sst_free_stream(str_id);
+ if (retval == 0) {
+ stream->pcm_substream = NULL;
+ stream->period_elapsed = NULL;
+ sst_ops->stream_cnt--;
+ }
+ break;
+ }
+
+ case SST_SND_STREAM_INIT: {
+ struct pcm_stream_info *str_info = NULL;
+ struct stream_info *stream = NULL;
+
+ sst_dbg("stream init called\n");
+ str_info = (struct pcm_stream_info *)value;
+ str_id = str_info->str_id;
+ retval = sst_validate_strid(str_id);
+ if (retval != 0)
+ break;
+
+ stream = &sst_ops->streams[str_id];
+ sst_dbg("setting the period ptrs\n");
+ stream->pcm_substream = str_info->mad_substream;
+ stream->period_elapsed = str_info->period_elapsed;
+ break;
+ }
+
+ case SST_SND_BUFFER_POINTER: {
+ struct pcm_stream_info *buf_ptr;
+ struct snd_sst_tstamp fw_tstamp = {0,};
+ struct stream_info *stream = NULL;
+
+ sst_dbg("buffer pointer query\n");
+
+ buf_ptr = (struct pcm_stream_info *)value;
+ str_id = buf_ptr->str_id;
+ retval = sst_validate_strid(str_id);
+ if (retval != 0)
+ break;
+ stream = &sst_ops->streams[str_id];
+
+ if (stream->pcm_substream == NULL)
+ break;
+ memcpy_fromio(&fw_tstamp,
+ ((void *)(sst_ops->mailbox + SST_TIME_STAMP)
+ +(str_id * sizeof(fw_tstamp))),
+ sizeof(fw_tstamp));
+
+ sst_dbg("strid = %d\n", str_id);
+
+ if (stream->ops == STREAM_OPS_PLAYBACK)
+ buf_ptr->buffer_ptr = fw_tstamp.samples_rendered;
+ else
+ buf_ptr->buffer_ptr = fw_tstamp.samples_processed;
+ sst_dbg("samples played = %ld\n",
+ buf_ptr->buffer_ptr);
+ break;
+ }
+
+ default:
+ /*Illegal case*/
+ sst_err("illegal req\n");
+ return -EINVAL;
+ }
+ sst_dbg("...complete ret code = %d\n", retval);
+
+ return retval;
+}
+
+
+/**
+* sst_send_data_to_HW - send data buffers
+* @buffer_data: user buffer
+*
+* This function is called by MID sound card driver to send buffer
+* to HW. This is registered with MID driver
+*/
+int sst_send_buffer_to_HW(int str_id, struct stream_buffer *mad_buf)
+{
+ /*recvd a buffer map it to stream*/
+ /*this is a PCM stream and playback*/
+ int retval = 0;
+ bool flag_add = false;
+ struct sst_stream_bufs *sst_buf = NULL;
+ struct stream_info *stream = NULL;
+
+ if (NULL == mad_buf ||
+ 0 == mad_buf->addr ||
+ 0 == mad_buf->length) {
+ sst_err("Null Ptr or buf size = 0\n");
+ return -EINVAL;
+ }
+
+ if (SST_FW_RUNNING != sst_ops->sst_state) {
+ sst_err("SST Not runng: %d\n", sst_ops->sst_state);
+ return -EBUSY;
+ }
+
+ retval = sst_validate_strid(str_id);
+ if (retval < 0)
+ return -EINVAL;
+
+ stream = &sst_ops->streams[str_id];
+ sst_dbg("stream status = %d strid=%d\n", stream->status, str_id);
+ sst_dbg("stream codec = %d, prevstate=%d\n",
+ stream->codec, stream->prev);
+ if (stream->status == STREAM_UN_INIT) {
+ sst_err("BAD REQUEST!\n");
+ return -EBADRQC;
+ }
+ sst_dbg("received addr=0x%x size = 0x%x\n",
+ (unsigned int)mad_buf->addr, mad_buf->length);
+ /*list is not empty*/
+ list_for_each_entry(sst_buf, &stream->bufs, node) {
+ if (sst_buf->in_use == true)
+ continue;
+ else if ((int) mad_buf->addr !=
+ (int)sst_buf->addr + sst_buf->size)
+ continue;
+ else {
+ sst_buf->size += mad_buf->length;
+ flag_add = true;
+ sst_dbg("inc addr = 0x%p, base = 0x%x inc_val = 0x%x\n",
+ sst_buf->addr, sst_buf->size, mad_buf->length);
+ break;
+ }
+ }
+
+ if (flag_add == false) {
+ sst_buf = kzalloc(sizeof(*sst_buf), GFP_ATOMIC);
+ if (sst_buf == NULL)
+ return -ENOMEM;
+ sst_buf->size = mad_buf->length;
+ sst_buf->addr = (void *)mad_buf->addr;
+ sst_buf->offset = 0;
+ sst_buf->in_use = false;
+ list_add_tail(&sst_buf->node, &stream->bufs);
+ flag_add = true;
+ sst_dbg("entry added addr = 0x%x size = 0x%x\n",
+ (unsigned int)mad_buf->addr, mad_buf->length);
+ }
+
+ if (stream->status == STREAM_INIT) {
+ sst_dbg("play/capt frames...\n");
+ stream->prev = stream->status;
+ stream->status = STREAM_RUNNING;
+ stream->data_blk.on = false;
+ if (stream->ops == STREAM_OPS_PLAYBACK)
+ retval = sst_play_frame(str_id);
+ else if (stream->ops == STREAM_OPS_CAPTURE)
+ retval = sst_capture_frame(str_id);
+ else
+ return -EINVAL;
+ if (retval < 0) {
+ sst_err("play/capture frames failed \n");
+ return -EIO;
+ }
+ }
+
+ return retval;
+}
+
+struct intel_sst_card_ops sst_pmic_ops = {
+ .control_set = sst_control_set,
+ .send_buffer = sst_send_buffer_to_HW,
+};
+
+/**
+* register_sst_card- function for sound card to register
+*@card: pointer to structure of operations
+* This function is called card driver loads and is ready for registration
+*/
+int register_sst_card(struct intel_sst_card_ops *card)
+{
+
+ if (NULL == card ||
+ NULL == card->module_name) {
+ sst_err(" Null Pointer Passed\n");
+ return -EINVAL;
+ }
+
+ if (PMIC_SND_UN_INIT == sst_ops->pmic_state) {
+ /*register this driver*/
+ if (0 == (strncmp(SST_CARD_NAMES, card->module_name,
+ strlen(SST_CARD_NAMES)))) {
+ sst_ops->pmic_vendor = card->vendor_id;
+ sst_ops->scard_ops = *card->scard_ops;
+ sst_pmic_ops.module_name = card->module_name;
+ sst_ops->pmic_state = PMIC_SND_INIT_DONE;
+ card->control_set = sst_pmic_ops.control_set;
+ card->send_buffer = sst_pmic_ops.send_buffer;
+ return 0;
+ } else {
+ sst_err("strcmp failed %s \n", card->module_name);
+ return -EINVAL;
+ }
+
+ } else {
+ /*already registered a driver*/
+ sst_err("Repeat for register..denied\n");
+ return -EBADRQC;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(register_sst_card);
+
+/**
+* unregister_sst_card- function for sound card to un-register
+*@card: pointer to structure of operations
+* This function is called when card driver unloads
+*/
+void unregister_sst_card(struct intel_sst_card_ops *card)
+{
+ if (sst_pmic_ops.module_name == card->module_name) {
+ /*unreg*/
+ sst_pmic_ops.module_name = "";
+ sst_ops->pmic_state = PMIC_SND_UN_INIT;
+ sst_dbg("Unregistered %s\n", card->module_name);
+ }
+ return;
+}
+EXPORT_SYMBOL_GPL(unregister_sst_card);
+
+int lpe_mask_periphral_intr(enum lpe_periphral device)
+{
+ union sst_pimr_reg pimr = {{0},};
+ if (sst_ops == NULL)
+ return -EIO;
+
+ pimr.full = readl(sst_ops->shim + SST_PIMR);
+
+ switch (device) {
+ case LPE_DMA:
+ pimr.part.dmac_sc = 1;
+ writel(pimr.full, sst_ops->shim + SST_PIMR);
+ break;
+
+ case LPE_SSP0:
+ break;
+
+ case LPE_SSP1:
+ break;
+
+ default:
+ break;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(lpe_mask_periphral_intr);
+
+int lpe_unmask_periphral_intr(enum lpe_periphral device)
+{
+ union sst_pimr_reg pimr = {{0},};
+ if (sst_ops == NULL)
+ return -EIO;
+
+ pimr.full = readl(sst_ops->shim + SST_PIMR);
+
+ switch (device) {
+ case LPE_DMA:
+ pimr.part.dmac_sc = 0;
+ writel(pimr.full, sst_ops->shim + SST_PIMR);
+ break;
+
+ case LPE_SSP0:
+ break;
+
+ case LPE_SSP1:
+ break;
+
+ default:
+ break;
+ }
+ return 0;
+
+}
+EXPORT_SYMBOL_GPL(lpe_unmask_periphral_intr);
+
+int lpe_periphral_intr_status(enum lpe_periphral device, int *status)
+{
+ union sst_pisr_reg pisr = {{0},};
+ if (sst_ops == NULL)
+ return -EIO;
+
+ pisr.full = readl(sst_ops->shim + SST_PISR);
+
+ switch (device) {
+ case LPE_DMA:
+ *status = pisr.part.dmac;
+ break;
+
+ case LPE_SSP0:
+ break;
+
+ case LPE_SSP1:
+ break;
+
+ default:
+ break;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(lpe_periphral_intr_status);
--
1.5.4.5
3
5
Following emails are a of series 13 patches for Intel SST drivers (including documentation). These drivers are for the audio engine/sound card in upcoming Intel based Mobile Internet Devices (MID) platform
There are 2 drivers involved. One is for the audio DSP engine that can decode and do audio processing and one is for the ALSA sound card driver with support for three different sound cards that are supported on the platform.
The dependant drivers for the platform are not yet available in the upstream. So please consider these patches only for RFC and provide your comments/suggestions.
The audio firmware binary associated with this platform that is downloaded by the driver at runtime will be shared in a public location and made available in firmware git when we release the drivers for up streaming.
The patches are compiled with 0 warnings and checkpatch-ed.
The first patch in the series [RFC 1/13] Intel SST driver's documentation gives the documentation about the drivers and the interface for the audio DSP driver. The rest of the patches that follow have a brief description about the contents.
Thanks
-Vinod Koul & Harsha Priya
4
4
This adds the SST driver for the SST DSP engine. This patch
adds the main file intel_sst.c which contains the init, exit
probe, interrupt routine and PCI suspend/resume implementation.
This file also implements the SST Firmware initialization and
firmware and codec libraries download steps
Signed-off-by: Vinod Koul <vinod.koul(a)intel.com>
Signed-off-by: Harsha Priya <priya.harsha(a)intel.com>
new file: sound/pci/sst/intel_sst.c
---
sound/pci/sst/intel_sst.c | 877 +++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 877 insertions(+), 0 deletions(-)
create mode 100644 sound/pci/sst/intel_sst.c
diff --git a/sound/pci/sst/intel_sst.c b/sound/pci/sst/intel_sst.c
new file mode 100644
index 0000000..bd30833
--- /dev/null
+++ b/sound/pci/sst/intel_sst.c
@@ -0,0 +1,877 @@
+/*
+ * intel_sst.c - Intel SST Driver for audio engine
+ *
+ * Copyright (C) 2008-09 Intel Corp
+ * Authors: Vinod Koul <vinod.koul(a)intel.com>
+ * Harsha Priya <priya.harsha(a)intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This driver exposes the audio engine functionalities to the ALSA
+ * and middleware.
+ *
+ * This file contains all init functions
+ */
+
+#include <linux/cdev.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/syscalls.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/workqueue.h>
+#include <linux/firmware.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#ifndef CONFIG_SST_IPC_NOT_INCLUDED
+#include <asm/ipc_defs.h>
+#endif
+#include <sound/intel_sst.h>
+#include <sound/intel_sst_ioctl.h>
+#include "intel_sst_fw_ipc.h"
+#include "intel_sst_common.h"
+#include "intel_sst_pvt.h"
+#ifdef CONFIG_SST_OSPM_SUPPORT
+#include <linux/intel_mid.h>
+#endif
+
+
+MODULE_AUTHOR("Vinod Koul <vinod.koul(a)intel.com>");
+MODULE_DESCRIPTION("Intel (R) Moorestown Audio Engine Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(SST_DRIVER_VERSION);
+
+struct intel_sst_drv *sst_ops;
+
+void sst_reset(void)
+{
+ int retval;
+
+ /*Disable Audio Core clock and Audio Fabric clock*/
+ retval = sst_scu_ipc_write(0xff11d83c, 0x80008008);
+ if (retval != 0)
+ sst_err("scu ipc write1 failed %d", retval);
+ /*Reset the Audio subsystem*/
+ retval = sst_scu_ipc_write(0xff11d118, 0x7ffffcff);
+ if (retval != 0)
+ sst_err("scu ipc write2 failed %d", retval);
+ /*Bring it out of Audio subsystem reset*/
+ retval = sst_scu_ipc_write(0xff11d118, 0x7fffffff);
+ if (retval != 0)
+ sst_err("scu ipc write3 failed %d", retval);
+ /*Enable fabric clock at 50MHz*/
+ retval = sst_scu_ipc_write(0xff11d83c, 0x80008301);
+ if (retval != 0)
+ sst_err("scu ipc write4 failed %d", retval);
+ /*Write to the Shim register for ratio 1:1*/
+ retval = sst_scu_ipc_write(0xffae8000, 0x382);
+ if (retval != 0)
+ sst_err("scu ipc write5 failed %d", retval);
+ /*Enable the core clock at 1:2*/
+ retval = sst_scu_ipc_write(0xff11d83c, 0x80000301);
+ if (retval != 0)
+ sst_err("scu ipc write6 failed %d", retval);
+ return;
+}
+
+void sst_start(void)
+{
+ union config_status_reg csr;
+ int retval;
+
+ csr.full = readl(sst_ops->shim + SST_CSR);
+ csr.part.sst_reset = 0;
+ csr.part.run_stall = 0;
+ csr.part.bypass = 0;
+ /*csr.full = 0x1800;*/
+ sst_dbg("Setting SST to execute 0x%x \n", csr.full);
+
+ retval = sst_scu_ipc_write(sst_ops->shim_phy_add + SST_CSR, csr.full);
+ if (retval != 0)
+ sst_err("scu ipc write start failed %d", retval);
+ return;
+}
+int sst_parse_module(struct fw_module_header *module)
+{
+ struct dma_block_info *block = NULL;
+ u32 count;
+ void __iomem *ram;
+
+ sst_dbg("module sign=%s sz=0x%x blks=0x%x typ=0x%x ep=0x%x sz=0x%x\n",
+ module->signature, module->mod_size,
+ module->blocks, module->type,
+ module->entry_point, sizeof(*module));
+
+ block = (void *)module + sizeof(*module);
+
+ for (count = 0; count < module->blocks; count++) {
+ if (0 >= block->size) {
+ sst_err("block size invalid\n");
+ return -EINVAL;
+ }
+ switch (block->type) {
+ case SST_IRAM:
+ ram = sst_ops->iram;
+ break;
+ case SST_DRAM:
+ ram = sst_ops->dram;
+ break;
+ default:
+ sst_err("wrong ram type 0x%x in block 0x%x-abort\n",
+ block->type, count);
+ return -EINVAL;
+ }
+ memcpy_toio(ram + block->ram_offset,
+ (void *)block + sizeof(*block), block->size);
+ block = (void *)block + sizeof(*block) + block->size;
+ }
+ return 0;
+}
+
+/**
+* sst_parse_fw_image - FW parse and load
+* @fw: Pointer to loaded FW
+*
+* This function is called to parse and download the FW image
+*/
+int sst_parse_fw_image(const struct firmware *sst_fw)
+{
+ struct fw_header *header = NULL;
+ u32 count;
+ int ret_val = 0;
+ struct fw_module_header *module = NULL;
+
+ BUG_ON(!sst_fw);
+
+ /*Read the header information from the data pointer*/
+ header = (struct fw_header *)sst_fw->data;
+
+ /*verify FW*/
+ if ((0 != strncmp(header->signature, SST_FW_SIGN, 4)) ||
+ (sst_fw->size != header->file_size + sizeof(*header))) {
+ /*Invalid FW signature*/
+ sst_err("Invalid FW sign/file size mismatch\n");
+ return -EINVAL;
+ }
+ sst_dbg("header sign=%s size=0x%x modules=0x%x fmt=0x%x size=0x%x\n",
+ header->signature, header->file_size, header->modules,
+ header->file_format, sizeof(*header));
+ module = (void *)sst_fw->data + sizeof(*header);
+ for (count = 0; count < header->modules; count++) {
+ /*module*/
+ ret_val = sst_parse_module(module);
+ if (0 != ret_val)
+ return ret_val;
+ module = (void *)module + sizeof(*module) + module->mod_size ;
+ }
+
+ sst_dbg("done....\n");
+ return 0;
+}
+
+/**
+* sst_load_fw - function to reset FW
+* @fw: Pointer to loaded FW
+* This function is called when the FW is loaded
+*/
+void sst_load_fw(const struct firmware *fw, void *context)
+{
+ int ret;
+
+ sst_dbg("called \n");
+ BUG_ON(!fw);
+
+ sst_reset();
+ /*putting the sst state to init*/
+ sst_ops->sst_state = SST_UN_INIT;
+
+ ret = sst_parse_fw_image(fw);
+ if (0 != ret) {
+ sst_err("error in FW dma\n");
+ return;
+ }
+ sst_ops->sst_state = SST_FW_LOADED;
+ /* 7. ask scu to reset the bypass bits*/
+ /* 8.bring sst out of reset */
+ sst_start();
+ sst_dbg("...successful!!!\n");
+ return;
+}
+
+int sst_download_library(const struct firmware *fw_lib,
+ struct snd_sst_lib_download_info *lib)
+{
+ /*send IPC message and wait*/
+ unsigned int i, pvt_id;
+ struct ipc_post *msg = NULL;
+ union config_status_reg csr;
+ struct snd_sst_str_type str_type = {0};
+ int retval = 0;
+
+ if (sst_create_large_msg(&msg) != 0)
+ return -ENOMEM;
+
+ pvt_id = sst_assign_pvt_id(sst_ops);
+ i = sst_get_block_stream(sst_ops);
+ sst_dbg("alloc block allocated = %d, pvt_id %d\n", i, pvt_id);
+ if (i < 0) {
+ kfree(msg);
+ return -ENOMEM;
+ }
+ sst_ops->alloc_block[i].sst_id = pvt_id;
+ sst_fill_header(&msg->header, IPC_IA_PREP_LIB_DNLD, 1, 0);
+ msg->header.part.data = sizeof(u32) + sizeof(str_type);
+ str_type.codec_type = lib->dload_lib.lib_info.lib_type;
+ str_type.pvt_id = pvt_id;
+ memcpy(msg->mailbox_data, &msg->header, sizeof(u32));
+ memcpy(msg->mailbox_data + sizeof(u32), &str_type, sizeof(str_type));
+ list_add_tail(&msg->node, &sst_ops->ipc_dispatch_list);
+ sst_post_message(&sst_ops->ipc_post_msg_wq);
+ retval = sst_wait_timeout(sst_ops, &sst_ops->alloc_block[i]);
+ if (retval != 0) {
+ /*error*/
+ sst_ops->alloc_block[i].sst_id = BLOCK_UNINIT;
+ sst_err("Prep codec downloaded failed %d\n", retval);
+ return -EIO;
+ }
+ sst_dbg("FW responded, ready for download now...\n");
+ /*downloading on success*/
+ sst_ops->sst_state = SST_FW_LOADED;
+ csr.full = readl(sst_ops->shim + SST_CSR);
+ sst_dbg("CSR reg 0x%x \n", csr.full);
+ csr.part.run_stall = 1;
+ writel(csr.full, sst_ops->shim + SST_ISRX);
+ sst_dbg("HALT CSR reg setting to 0x%x \n", csr.full);
+ retval = sst_scu_ipc_write(sst_ops->shim_phy_add + SST_CSR, csr.full);
+ if (retval != 0) {
+ /*error*/
+ sst_ops->alloc_block[i].sst_id = BLOCK_UNINIT;
+ sst_err("IPC failed to Halt SST 0x%x\n", retval);
+ return -EAGAIN;
+ }
+ csr.full = readl(sst_ops->shim + SST_CSR);
+ csr.part.bypass = 0x7;
+ writel(csr.full, sst_ops->shim + SST_ISRX);
+ sst_dbg("Bypass CSR reg setting to 0x%x \n", csr.full);
+ retval = sst_scu_ipc_write(sst_ops->shim_phy_add + SST_CSR, csr.full);
+ if (retval != 0) {
+ /*error*/
+ sst_ops->alloc_block[i].sst_id = BLOCK_UNINIT;
+ sst_err("IPC failed to Bypass SST 0x%x\n", retval);
+ csr.part.bypass = 0x0;
+ /*bring LPE out of run stall*/
+ csr.part.run_stall = 0x0;
+ writel(csr.full, sst_ops->shim + SST_ISRX);
+ sst_dbg("Bypass CSR reg setting to 0x%x \n", csr.full);
+ retval = sst_scu_ipc_write(sst_ops->shim_phy_add + SST_CSR,
+ csr.full);
+ if (retval != 0)
+ sst_ops->sst_state = SST_UN_INIT;
+ return -EAGAIN;
+ }
+ sst_parse_fw_image(fw_lib);
+
+ /*set the FW to running again*/
+ csr.full = readl(sst_ops->shim + SST_CSR);
+ csr.part.bypass = 0x0;
+ writel(csr.full, sst_ops->shim + SST_ISRX);
+ sst_dbg("Bypass CSR reg clearing to 0x%x \n", csr.full);
+ retval = sst_scu_ipc_write(sst_ops->shim_phy_add + SST_CSR, csr.full);
+ if (retval != 0) {
+ sst_ops->alloc_block[i].sst_id = BLOCK_UNINIT;
+ sst_err("Bypass CSR reg clear failed 0x%x \n", retval);
+ /*bring LPE out of run stall*/
+ csr.part.run_stall = 0x0;
+ writel(csr.full, sst_ops->shim + SST_ISRX);
+ sst_dbg("Bypass CSR reg setting to 0x%x \n", csr.full);
+ retval = sst_scu_ipc_write(sst_ops->shim_phy_add + SST_CSR,
+ csr.full);
+ if (retval != 0)
+ sst_ops->sst_state = SST_UN_INIT;
+ return -EAGAIN;
+ }
+
+ csr.full = readl(sst_ops->shim + SST_CSR);
+ csr.part.run_stall = 0;
+ writel(csr.full, sst_ops->shim + SST_ISRX);
+ sst_dbg("Stalll CSR reg clearing to 0x%x \n", csr.full);
+ retval = sst_scu_ipc_write(sst_ops->shim_phy_add + SST_CSR, csr.full);
+ if (retval != 0) {
+ sst_ops->alloc_block[i].sst_id = BLOCK_UNINIT;
+ sst_err("Stall CSR reg clear failed 0x%x \n", retval);
+ if (retval != 0)
+ sst_ops->sst_state = SST_UN_INIT;
+ return -EAGAIN;
+ }
+ /*send download complete and wait*/
+ if (sst_create_large_msg(&msg) != 0) {
+ sst_ops->alloc_block[i].sst_id = BLOCK_UNINIT;
+ return -ENOMEM;
+ }
+
+ sst_fill_header(&msg->header, IPC_IA_LIB_DNLD_CMPLT, 1, 0);
+ msg->header.part.data = sizeof(u32) + sizeof(*lib);
+ lib->pvt_id = pvt_id;
+ memcpy(msg->mailbox_data, &msg->header, sizeof(u32));
+ memcpy(msg->mailbox_data + sizeof(u32), lib, sizeof(*lib));
+
+ list_add_tail(&msg->node, &sst_ops->ipc_dispatch_list);
+ sst_post_message(&sst_ops->ipc_post_msg_wq);
+ sst_dbg("Waiting for FW to respond on Download complete \n");
+ sst_ops->alloc_block[i].ops_block.condition = false;
+ retval = sst_wait_timeout(sst_ops, &sst_ops->alloc_block[i]);
+ if (retval != 0) {
+ /*error*/
+ sst_ops->sst_state = SST_FW_RUNNING;
+ sst_ops->alloc_block[i].sst_id = BLOCK_UNINIT;
+ return -EIO;
+ }
+
+ sst_dbg("FW responded sucess on Download complete \n");
+ sst_ops->alloc_block[i].sst_id = BLOCK_UNINIT;
+ sst_ops->sst_state = SST_FW_RUNNING;
+ return 0;
+
+}
+
+int sst_validate_library(const struct firmware *fw_lib,
+ struct lib_slot_info *slot,
+ u32 *entry_point)
+{
+ struct fw_header *header = NULL;
+ struct fw_module_header *module = NULL;
+ struct dma_block_info *block = NULL;
+ unsigned int n_blk, isize = 0, dsize = 0;
+ int err = 0;
+
+ header = (struct fw_header *)fw_lib->data;
+ if (header->modules != 1) {
+ sst_err("Module no mismatch found\n");
+ err = -EINVAL;
+ goto exit;
+ }
+ module = (void *)fw_lib->data + sizeof(*header);
+ *entry_point = module->entry_point;
+ sst_dbg("Module entry point 0x%x \n", *entry_point);
+ sst_dbg("Module Sign %s, Size 0x%x, Blocks 0x%x Type 0x%x \n",
+ module->signature, module->mod_size,
+ module->blocks, module->type);
+
+ block = (void *)module + sizeof(*module);
+ for (n_blk = 0; n_blk < module->blocks; n_blk++) {
+ switch (block->type) {
+ case SST_IRAM:
+ isize += block->size;
+ break;
+ case SST_DRAM:
+ dsize += block->size;
+ break;
+ default:
+ sst_err("Invalid block type found for 0x%x\n", n_blk);
+ err = -EINVAL;
+ goto exit;
+ }
+ block = (void *)block + sizeof(*block) + block->size;
+ }
+ if (isize > slot->iram_size || dsize > slot->dram_size) {
+ sst_err("libarary exceeds size allocated \n");
+ err = -EINVAL;
+ goto exit;
+ } else
+ sst_dbg("Library is safe for download...\n");
+
+ sst_dbg("iram 0x%x, dram 0x%x, allowed iram 0x%x, allowed dram 0x%x\n",
+ isize, dsize, slot->iram_size, slot->dram_size);
+exit:
+ return err;
+
+}
+
+int sst_load_library(struct snd_sst_lib_download *lib, u8 ops, u32 pvt_id)
+{
+ char buf[20];
+ int len = 0, error = 0;
+ u32 entry_point;
+ const struct firmware *fw_lib;
+ struct snd_sst_lib_download_info dload_info = {{{0},},};
+
+ memset(buf, 0, sizeof(buf));
+
+ sst_dbg("Lib Type 0x%x, Slot 0x%x, ops 0x%x \n",
+ lib->lib_info.lib_type, lib->slot_info.slot_num, ops);
+ sst_dbg("Version 0x%x, name %s, caps 0x%x media type 0x%x \n",
+ lib->lib_info.lib_version, lib->lib_info.lib_name,
+ lib->lib_info.lib_caps, lib->lib_info.media_type);
+
+ sst_dbg("IRAM Size 0x%x, offset 0x%x, DRAM Size 0x%x, offset 0x%x \n",
+ lib->slot_info.iram_size, lib->slot_info.iram_offset,
+ lib->slot_info.dram_size, lib->slot_info.dram_offset);
+
+ switch (lib->lib_info.lib_type) {
+ case SST_CODEC_TYPE_MP3:
+ len += snprintf(buf + len, sizeof(buf) - len, "mp3_");
+ break;
+ case SST_CODEC_TYPE_AAC:
+ len += snprintf(buf + len, sizeof(buf) - len, "aac_");
+ break;
+ case SST_CODEC_TYPE_WMA9:
+ len += snprintf(buf + len, sizeof(buf) - len, "wma9_");
+ break;
+ default:
+ sst_err("Invalid codec type \n");
+ error = -EINVAL;
+ goto wake;
+ }
+
+ if (ops == STREAM_OPS_CAPTURE)
+ len += snprintf(buf + len, sizeof(buf) - len, "enc_");
+ else
+ len += snprintf(buf + len, sizeof(buf) - len, "dec_");
+
+ len += snprintf(buf + len, sizeof(buf) - len, "%d",
+ lib->slot_info.slot_num);
+ len += snprintf(buf + len, sizeof(buf) - len, ".bin");
+
+ sst_dbg("Requesting %s \n", buf);
+
+ error = request_firmware(&fw_lib, buf, &sst_ops->pci->dev);
+ if (0 != error) {
+ sst_err("library load failed %d \n", error);
+ goto wake;
+ }
+ error = sst_validate_library(fw_lib, &lib->slot_info, &entry_point);
+ if (0 != error) {
+ sst_err("validate lib failed %d \n", error);
+ goto wake_free;
+ }
+ lib->mod_entry_pt = entry_point;
+ memcpy(&dload_info.dload_lib, lib, sizeof(*lib));
+ error = sst_download_library(fw_lib, &dload_info);
+ if (0 != error) {
+ sst_err("download lib failed %d \n", error);
+ goto wake_free;
+ }
+ /*lib is downloaded and init send alloc again*/
+ sst_dbg("Library is downloaded now... \n");
+wake_free:
+ /*sst_wake_up_alloc_block(sst_ops, pvt_id, error, NULL);*/
+ release_firmware(fw_lib);
+wake:
+ return error;
+}
+
+/*fops Routines*/
+const struct file_operations intel_sst_fops = {
+ .owner = THIS_MODULE,
+ .open = intel_sst_open,
+ .release = intel_sst_release,
+ .read = intel_sst_read,
+ .write = intel_sst_write,
+ .ioctl = intel_sst_ioctl,
+ .mmap = intel_sst_mmap,
+ .aio_read = intel_sst_aio_read,
+ .aio_write = intel_sst_aio_write,
+};
+
+/*
+ ISR Routines
+*/
+/**
+* intel_sst_interrupt - Interrupt service routine for SST
+* @irq: irq number of interrupt
+* @dev_id: pointer to device structre
+*
+* This function is called by OS when SST device raises
+* an interrupt. This will be result of write in IPC register
+* Source can be busy or done interrupt
+*/
+static irqreturn_t intel_sst_interrupt(int irq, void *context)
+{
+ union interrupt_reg isr;
+ union ipc_header header;
+ union interrupt_reg imr;
+ struct intel_sst_drv *drv = (struct intel_sst_drv *) context;
+ unsigned int size = 0;
+
+ /*Interrupt arrived, check src*/
+ isr.full = readl(drv->shim + SST_ISRX);
+ imr.full = readl(drv->shim + SST_IMRX);
+ if (1 == isr.part.busy_interrupt) {
+ header.full = readl(drv->shim + SST_IPCD);
+ if (1 == header.part.large)
+ size = header.part.data;
+ if (0 != (header.part.msg_id & REPLY_MSG)) {
+ sst_ops->ipc_process_msg.header = header;
+ memcpy_fromio(sst_ops->ipc_process_msg.mailbox,
+ drv->mailbox + SST_MAILBOX_RCV, size);
+ schedule_work(&sst_ops->ipc_process_msg.wq);
+ } else {
+ sst_ops->ipc_process_reply.header = header;
+ memcpy_fromio(sst_ops->ipc_process_reply.mailbox,
+ drv->mailbox + SST_MAILBOX_RCV, size);
+ schedule_work(&sst_ops->ipc_process_reply.wq);
+ }
+ /*mask busy inetrrupt*/
+ imr.part.busy_interrupt = 1;
+ writel(imr.full, drv->shim + SST_IMRX);
+
+ } else if (1 == isr.part.done_interrupt) {
+ /*Clear done bit*/
+ header.full = readl(drv->shim + SST_IPCX);
+ header.part.done = 0;
+ writel(header.full, drv->shim + SST_IPCX);
+ /* write 1 to clear status register*/;
+ isr.part.done_interrupt = 1;
+ writel(isr.full, drv->shim + SST_ISRX);
+ schedule_work(&sst_ops->ipc_post_msg.wq);
+ }
+ return IRQ_HANDLED;
+}
+
+
+/*
+ PCI Routines
+*/
+static struct pci_device_id intel_sst_ids[] = {
+ { 0x8086, 0x080A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, intel_sst_ids);
+
+
+/*
+* intel_sst_probe - PCI probe function
+* @pci: PCI device structure
+* @pci_id: PCI device ID structure
+*
+* This function is called by OS when a device is found
+* This enables the device, interrupt etc
+*/
+static int __devinit intel_sst_probe(struct pci_dev *pci,
+ const struct pci_device_id *pci_id)
+{
+ int ret = 0;
+ u32 bar = 0, size = 0;
+
+ /*Init the device*/
+ ret = pci_enable_device(pci);
+ if (0 != ret) {
+ sst_err("device cant be enabled\n");
+ return ret;
+ }
+ sst_ops->pci = pci;
+ /*map registers*/
+ /*SST Shim*/
+ bar = pci_resource_start(pci, 1);
+ size = pci_resource_len(pci, 1);
+ ret = pci_request_region(pci, 2, SST_DRV_NAME);
+ if (ret != 0)
+ goto err_1;
+ sst_ops->shim_phy_add = bar;
+ sst_ops->shim = ioremap_nocache(bar, size);
+ if (sst_ops->shim == NULL)
+ goto err_2;
+ sst_dbg("SST Shim 0x%x,Size 0x%x,Ptr %p \n", bar, size, sst_ops->shim);
+
+ /*Shared SRAM*/
+ bar = pci_resource_start(pci, 2);
+ size = pci_resource_len(pci, 2);
+ ret = pci_request_region(pci, 3, SST_DRV_NAME);
+ if (ret != 0)
+ goto err_2;
+ sst_ops->mailbox = ioremap_nocache(bar, size);
+ if (NULL == sst_ops->mailbox)
+ goto err_3;
+ sst_dbg("SRAM 0x%x, Size 0x%x, Ptr %p \n", bar, size, sst_ops->mailbox);
+
+ /* IRAM*/
+ bar = pci_resource_start(pci, 3);
+ size = pci_resource_len(pci, 3);
+ ret = pci_request_region(pci, 4, SST_DRV_NAME);
+ if (ret != 0)
+ goto err_3;
+ sst_ops->iram = ioremap_nocache(bar, size);
+ if (sst_ops->iram == NULL)
+ goto err_4;
+ sst_dbg("IRAM 0x%x, Size 0x%x, Ptr %p \n", bar, size, sst_ops->iram);
+
+ /*DRAM*/
+ bar = pci_resource_start(pci, 4);
+ size = pci_resource_len(pci, 4);
+ ret = pci_request_region(pci, 5, SST_DRV_NAME);
+ if (ret != 0)
+ goto err_4;
+ sst_ops->dram = ioremap_nocache(bar, size);
+ if (sst_ops->dram == NULL)
+ goto err_5;
+ sst_dbg("DRAM 0x%x, Size 0x%x, Ptr %p \n", bar, size, sst_ops->dram);
+
+ /*Register the ISR*/
+ ret = request_irq(pci->irq, intel_sst_interrupt,
+ IRQF_SHARED, SST_DRV_NAME, sst_ops);
+ if (0 != ret)
+ goto err_5;
+ sst_dbg("Registered IRQ 0x%x\n", pci->irq);
+ sst_ops->sst_state = SST_UN_INIT;
+
+ /* Register with /dev */
+ ret = register_chrdev(INTEL_SST_MAJOR, SST_DRV_NAME, &intel_sst_fops);
+ if (0 != ret) {
+ sst_err("couldn't register device number\n");
+ goto err_6;
+ }
+
+ sst_dbg("...successfully done!!!\n");
+ return 0;
+
+err_6: free_irq(pci->irq, sst_ops);
+err_5: iounmap(sst_ops->dram);
+err_4: iounmap(sst_ops->iram);
+err_3: iounmap(sst_ops->mailbox);
+err_2: iounmap(sst_ops->shim);
+err_1: sst_err("Probe failed with 0x%x \n", ret);
+ return ret;
+}
+
+/**
+* intel_sst_remove - PCI remove function
+* @pci: PCI device structure
+*
+* This function is called by OS when a device is unloaded
+* This frees the interrupt etc
+*/
+static void __devexit intel_sst_remove(struct pci_dev *pci)
+{
+ sst_ops->sst_state = SST_UN_INIT;
+ unregister_chrdev(INTEL_SST_MAJOR, SST_DRV_NAME);
+ free_irq(pci->irq, sst_ops);
+ iounmap(sst_ops->dram);
+ iounmap(sst_ops->iram);
+ iounmap(sst_ops->mailbox);
+ iounmap(sst_ops->shim);
+}
+
+#ifdef CONFIG_SST_OSPM_SUPPORT
+/*
+ Power Management
+
+*/
+/**
+* intel_sst_suspend - PCI suspend function
+* @pci: PCI device structure
+* @state: PM message
+*
+* This function is called by OS when a power event occurs
+*/
+static int intel_sst_suspend(struct pci_dev *pci, pm_message_t state)
+{
+ int i = 0;
+ sst_dbg("intel_sst_suspend called\n");
+
+ /*Pause all running streams*/
+ for (i = 1; i < MAX_NUM_STREAMS; i++) {
+ if (sst_ops->streams[i].status == STREAM_RUNNING) {
+ sst_ops->active_streams[i] = true;
+ sst_pause_stream(i);
+ } else
+ sst_ops->active_streams[i] = false;
+ }
+
+ pci_set_drvdata(pci, sst_ops);
+
+ /*Disable everything*/
+ /*free_irq(pci->irq, sst_ops);*/
+ pci_disable_device(pci);
+ pci_save_state(pci);
+ pci_set_power_state(pci, pci_choose_state(pci, state));
+ return 0;
+}
+
+/**
+* intel_sst_resume - PCI resume function
+* @pci: PCI device structure
+* @state: PM message
+*
+* This function is called by OS when a power event occurs
+*/
+static int intel_sst_resume(struct pci_dev *pci)
+{
+ int i = 0;
+
+ sst_dbg("\nintel_sst_resume called\n");
+ if (pci != NULL)
+ sst_dbg("pci is not null \n");
+ /*Enable*/
+ sst_ops = pci_get_drvdata(pci);
+ if (sst_ops != NULL)
+ sst_dbg("sst_ops is not null\n");
+ if (pci->irq)
+ sst_dbg("irq %d \n", pci->irq);
+
+ pci_set_power_state(pci, PCI_D0);
+ pci_restore_state(pci);
+
+ /*ret = request_irq(pci->irq, intel_sst_interrupt,
+ IRQF_SHARED, "intel_sst_engine", sst_ops);
+ if (0 != ret) {
+ sst_err("\tIRQ %d reg error %d\n", pci->irq, ret);
+ return ret;
+ }*/
+
+ /*Start all paused streams*/
+ for (i = 1; i < MAX_NUM_STREAMS; i++) {
+ if (sst_ops->active_streams[i] == true)
+ sst_resume_stream(i);
+ }
+ return 0;
+}
+/**
+* sst_ospm_send_event - Send PM events to OSPM
+* @event: OSPM Event
+*
+* This function is called when stream is started/stopped/paused...
+*/
+int sst_ospm_send_event(int event)
+{
+ return ospm_generate_netlink_event(AUDIO_SUBSYTEM_ID, event);
+
+}
+#endif /* CONFIG_SST_OSPM_SUPPORT */
+static struct pci_driver driver = {
+ .name = SST_DRV_NAME,
+ .id_table = intel_sst_ids,
+ .probe = intel_sst_probe,
+ .remove = __devexit_p(intel_sst_remove),
+#ifdef CONFIG_SST_OSPM_SUPPORT
+ .suspend = intel_sst_suspend,
+ .resume = intel_sst_resume,
+#endif
+};
+
+/**
+* intel_sst_init - Module init function
+*
+* Registers with PCI
+* Registers with /dev
+*Init all data strutures
+*/
+/*Module init function*/
+static int __init intel_sst_init(void)
+{
+ /*
+ Init all variables, data structure etc....
+ */
+ int ret = 0, i = 0;
+ struct stream_info *stream = NULL;
+
+ sst_info("******** SST DRIVER loading.. Ver: %s\n", SST_DRIVER_VERSION);
+
+ sst_ops = kzalloc(sizeof(*sst_ops), GFP_KERNEL);
+ if (NULL == sst_ops) {
+ sst_err("intel_sst malloc fail\n");
+ return -ENOMEM;
+ }
+
+ sst_ops->pmic_state = PMIC_SND_UN_INIT;
+ sst_ops->stream_cnt = 0;
+ sst_ops->active_cnt = 0;
+ sst_ops->am_cnt = 0;
+ sst_ops->unique_id = 0;
+
+ INIT_LIST_HEAD(&sst_ops->ipc_dispatch_list);
+ INIT_WORK(&sst_ops->ipc_post_msg.wq, sst_post_message);
+ INIT_WORK(&sst_ops->ipc_process_msg.wq, sst_process_message);
+ INIT_WORK(&sst_ops->ipc_process_reply.wq, sst_process_reply);
+ init_waitqueue_head(&sst_ops->wait_queue);
+
+ for (i = 0; i < MAX_ACTIVE_STREAM; i++) {
+ sst_ops->alloc_block[i].sst_id = BLOCK_UNINIT;
+ sst_ops->alloc_block[i].ops_block.condition = false;
+ }
+ mutex_init(&sst_ops->list_lock);
+
+ for (i = 1; i < MAX_NUM_STREAMS; i++) {
+ stream = &sst_ops->streams[i];
+ INIT_LIST_HEAD(&stream->bufs);
+ mutex_init(&stream->lock);
+ }
+ sst_ops->mmap_mem = NULL;
+ sst_ops->mmap_len = SST_MMAP_PAGES * PAGE_SIZE;
+ while (sst_ops->mmap_len > 0) {
+ sst_ops->mmap_mem = kzalloc(sst_ops->mmap_len, GFP_KERNEL);
+ if (sst_ops->mmap_mem != NULL) {
+ sst_dbg("Got memory %p size 0x%x \n", sst_ops->mmap_mem,
+ sst_ops->mmap_len);
+ break;
+ }
+ sst_ops->mmap_len -= (SST_MMAP_STEP * PAGE_SIZE);
+ if (sst_ops->mmap_len <= 0) {
+ sst_err("Couldnt get any mem...abort!!\n");
+ goto exit_p;
+ }
+ sst_dbg("Failed...trying %d\n", sst_ops->mmap_len);
+ }
+ /* Register with PCI */
+ ret = pci_register_driver(&driver);
+ if (0 != ret) {
+ sst_err("PCI register failed, unregister char drv\n");
+ goto exit;
+ }
+
+
+
+ sst_dbg("...sucessful\n");
+ return 0;
+
+exit:
+ pci_unregister_driver(&driver);
+exit_p:
+ kfree(sst_ops->mmap_mem);
+ kfree(sst_ops);
+ sst_err("Error in init %d\n", ret);
+
+ return ret;
+}
+
+/*Module exit function*/
+static void __exit intel_sst_exit(void)
+{
+ int i;
+ struct stream_info *stream = NULL;
+
+ for (i = 0; i < MAX_NUM_STREAMS; i++) {
+ stream = &sst_ops->streams[i];
+ sst_free_stream(i);
+ }
+ sst_ops->pmic_state = PMIC_SND_UN_INIT;
+ pci_unregister_driver(&driver);
+
+ flush_scheduled_work();
+ kfree(sst_ops->mmap_mem);
+ kfree(sst_ops);
+
+ sst_dbg("...unloaded\n");
+ return;
+}
+
+module_init(intel_sst_init);
+module_exit(intel_sst_exit);
--
1.5.4.5
3
4
07 Jul '09
This patch adds header files private to the SST
driver and contains the common structures like driver context,
DSP register definitions, and inline utility
functions used by the SST driver and function prototypes of
common functions that are implemented in SST driver
Signed-off-by: Vinod Koul <vinod.koul(a)intel.com>
Signed-off-by: Harsha Priya <priya.harsha(a)intel.com>
new file: sound/pci/sst/intel_sst_common.h
new file: sound/pci/sst/intel_sst_pvt.h
---
sound/pci/sst/intel_sst_common.h | 292 +++++++++++++++++++++++++++++
sound/pci/sst/intel_sst_pvt.h | 378 ++++++++++++++++++++++++++++++++++++++
2 files changed, 670 insertions(+), 0 deletions(-)
create mode 100644 sound/pci/sst/intel_sst_common.h
create mode 100644 sound/pci/sst/intel_sst_pvt.h
diff --git a/sound/pci/sst/intel_sst_common.h b/sound/pci/sst/intel_sst_common.h
new file mode 100644
index 0000000..e039489
--- /dev/null
+++ b/sound/pci/sst/intel_sst_common.h
@@ -0,0 +1,292 @@
+#ifndef __INTEL_SST_COMMON_H__
+#define __INTEL_SST_COMMON_H__
+/*
+ * intel_sst_common.h - Intel SST Driver for audio engine
+ *
+ * Copyright (C) 2008-09 Intel Corporation
+ * Authors: Vinod Koul <vinod.koul(a)intel.com>
+ * Harsha Priya <priya.harsha(a)intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * Common private declarations for SST
+ */
+#include <linux/time.h>
+
+/*#define SND_LOOP_TEST*/
+
+#define SST_DRIVER_VERSION "0.04.002"
+#define SST_VERSION_NUM 0x0402
+
+/*
+driver names
+*/
+#define SST_DRV_NAME "intel_sst_driver"
+#define SST_FW_STD_FILENAME "fw_sst.bin"
+
+
+/*
+PMIC and SST hardware states
+*/
+enum sst_pmic_states {
+ PMIC_SND_UN_INIT = 0,
+ PMIC_SND_INIT_DONE,
+};
+
+enum sst_states {
+ SST_FW_LOADED = 1,
+ SST_FW_RUNNING,
+ SST_UN_INIT,
+ SST_ERROR,
+};
+
+#define MAX_ACTIVE_STREAM 3
+#define MAX_ENC_STREAM 1
+#define MAX_AM_HANDLES 1
+#define ALLOC_TIMEOUT 5000
+/*
+SST numbers
+*/
+#define SST_BLOCK_TIMEOUT 5000
+
+#define INTEL_SST_MAJOR 255
+#define BLOCK_UNINIT -1
+
+/*SST register map*/
+#define SST_CSR 0x00
+#define SST_PISR 0x08
+#define SST_PIMR 0x10
+#define SST_ISRX 0x18
+#define SST_IMRX 0x28
+#define SST_IPCX 0x38 /*IPC IA-SST*/
+#define SST_IPCD 0x40 /*IPC SST-IA*/
+#define SST_SHIM_SIZE 0X44
+
+#define FW_SIGNATURE_SIZE 4
+
+/*
+stream states
+*/
+enum sst_stream_states {
+ STREAM_UN_INIT = 0, /*Freed/Not used stream*/
+ STREAM_RUNNING = 1, /*Running*/
+ STREAM_PAUSED = 2, /*Paused stream*/
+ STREAM_INIT_WT = 4, /*stream is init and waiting for FW*/
+ STREAM_INIT = 5, /*stream init, waiting for data*/
+};
+
+
+enum sst_ram_type{
+ SST_IRAM = 1,
+ SST_DRAM = 2,
+};
+/*
+SST shim registers to structure mapping
+*/
+union config_status_reg {
+ struct {
+ u32 rsvd0:1;
+ u32 sst_reset:1;
+ u32 hw_rsvd:3;
+ u32 sst_clk:2;
+ u32 bypass:3;
+ u32 run_stall:1;
+ u32 rsvd:21;
+ } part;
+ u32 full;
+};
+
+union interrupt_reg {
+ struct {
+ u32 done_interrupt:1;
+ u32 busy_interrupt:1;
+ u32 rsvd:30;
+ } part;
+ u32 full;
+};
+
+union sst_pisr_reg {
+ struct {
+ u32 pssp0:1;
+ u32 pssp1:1;
+ u32 rsvd0:3;
+ u32 dmac:1;
+ u32 rsvd1:26;
+ } part;
+ u32 full;
+};
+
+union sst_pimr_reg {
+ struct {
+ u32 ssp0:1;
+ u32 ssp1:1;
+ u32 rsvd0:3;
+ u32 dmac:1;
+ u32 rsvd1:10;
+ u32 ssp0_sc:1;
+ u32 ssp1_sc:1;
+ u32 rsvd2:3;
+ u32 dmac_sc:1;
+ u32 rsvd3:10;
+ } part;
+ u32 full;
+};
+
+
+struct sst_stream_bufs {
+ struct list_head node;
+ u32 size;
+ const char *addr;
+ u32 data_copied;
+ bool in_use;
+ u32 offset;
+};
+
+struct snd_sst_user_cap_list {
+ unsigned int iov_index; /*index of iov*/
+ unsigned long iov_offset; /*offset in iov*/
+ unsigned long offset; /*offset in kmem*/
+ unsigned long size; /*size copied*/
+ struct list_head node;
+};
+/*
+This structure is used to block a user/fw data call to another
+fw/user call
+*/
+struct sst_block {
+ bool condition; /*condition for blocking check*/
+ int ret_code; /*ret code when block is released*/
+ void *data; /*data to be appsed for block if any*/
+ bool on;
+};
+
+enum snd_sst_buf_type {
+ SST_BUF_USER_STATIC = 1,
+ SST_BUF_USER_DYNAMIC,
+ SST_BUF_MMAP_STATIC,
+ SST_BUF_MMAP_DYNAMIC,
+};
+/*
+structure that holds the stream information
+*/
+struct stream_info {
+ unsigned int status;
+ unsigned int prev;
+ unsigned int codec;
+ unsigned int sst_id;
+ unsigned int ops;
+ struct list_head bufs;
+ struct mutex lock; /*mutex*/
+ void *get_parameters;
+ bool mmapped;
+ unsigned int sg_index; /* current buf Index */
+ unsigned char *cur_ptr; /* Current static bufs */
+ struct snd_sst_buf_entry *buf_entry;
+ struct sst_block data_blk; /*stream ops block*/
+ struct sst_block ctrl_blk; /*stream control cmd block*/
+ enum snd_sst_buf_type buf_type;
+ void *pcm_substream;
+ void (*period_elapsed) (void *pcm_substream);
+};
+
+
+
+/*
+this structure is used for blocking the user's alloc calls to
+fw's response to alloc calls
+*/
+struct stream_alloc_block {
+ int sst_id; /*session id of blocked stream*/
+ struct sst_block ops_block; /*ops block struture*/
+};
+
+#define SST_FW_SIGN "$SST"
+#define SST_FW_LIB_SIGN "$LIB"
+
+/*FW file headers*/
+struct fw_header {
+ unsigned char signature[FW_SIGNATURE_SIZE]; /*FW signature*/
+ u32 file_size; /*size of fw minus this header*/
+ u32 modules; /* # of modules*/
+ u32 file_format; /*version of header format*/
+ u32 reserved[4];
+};
+
+struct fw_module_header {
+ unsigned char signature[FW_SIGNATURE_SIZE]; /*module signature*/
+ u32 mod_size; /*size of module*/
+ u32 blocks; /*# of blocks*/
+ u32 type; /*codec type, pp lib*/
+ u32 entry_point;
+};
+
+struct dma_block_info {
+ enum sst_ram_type type; /*IRAM/DRAM*/
+ u32 size; /*Bytes*/
+ u32 ram_offset; /*Offset in I/DRAM*/
+ u32 rsvd; /*Reserved field*/
+};
+
+struct ioctl_pvt_data {
+ int str_id;
+ int pvt_id;
+};
+
+struct sst_ipc_msg_wq {
+ union ipc_header header;
+ char mailbox[SST_MAILBOX_SIZE];
+ struct work_struct wq;
+};
+#define SST_MMAP_PAGES (640*1024 / PAGE_SIZE)
+#define SST_MMAP_STEP (40*1024 / PAGE_SIZE)
+
+/*driver ops*/
+struct intel_sst_drv{
+ bool pmic_state;
+ int pmic_vendor;
+ int sst_state;
+ void __iomem *shim;
+ void __iomem *mailbox;
+ void __iomem *iram;
+ void __iomem *dram;
+ unsigned int shim_phy_add;
+ struct list_head ipc_dispatch_list;
+ struct work_struct ipc_post_msg_wq;
+ struct sst_ipc_msg_wq ipc_process_msg;
+ struct sst_ipc_msg_wq ipc_process_reply;
+ struct sst_ipc_msg_wq ipc_post_msg;
+ wait_queue_head_t wait_queue;
+
+ struct stream_info streams[MAX_NUM_STREAMS];
+ struct stream_alloc_block alloc_block[MAX_ACTIVE_STREAM];
+
+ struct mutex list_lock; /*mutex for IPC list locking*/
+ struct snd_pmic_ops scard_ops;
+ struct pci_dev *pci;
+ int active_streams[MAX_NUM_STREAMS];
+ struct sst_block block_status;
+
+ void *mmap_mem;
+ unsigned int mmap_len;
+ unsigned int unique_id;
+ unsigned int stream_cnt;
+ unsigned int active_cnt;
+ unsigned int am_cnt;
+};
+
+extern struct intel_sst_drv *sst_ops;
+#endif /*__INTEL_SST_COMMON_H */
diff --git a/sound/pci/sst/intel_sst_pvt.h b/sound/pci/sst/intel_sst_pvt.h
new file mode 100644
index 0000000..a1e786e
--- /dev/null
+++ b/sound/pci/sst/intel_sst_pvt.h
@@ -0,0 +1,378 @@
+#ifndef __INTEL_SST_PVT_H__
+#define __INTEL_SST_PVT_H__
+/*
+ * intel_sst_pvt.h - Intel SST Driver for audio engine
+ *
+ * Copyright (C) 2008-09 Intel Corporation
+ * Authors: Vinod Koul <vinod.koul(a)intel.com>
+ * Harsha Priya <priya.harsha(a)intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This file defines all pvt functions
+ */
+int sst_alloc_stream(char *params, int stream_ops, int codec, int session_id);
+int sst_alloc_stream_response(unsigned int str_id,
+ struct snd_sst_str_type *type);
+int sst_pause_stream(int id);
+int sst_resume_stream(int id);
+int sst_drop_stream(int id);
+int sst_free_stream(int id);
+int sst_play_frame(int streamID);
+int sst_capture_frame(int streamID);
+int sst_set_stream_param(int streamID, struct snd_sst_params *str_param);
+int sst_route_control(int streamID);
+int sst_target_device_select(struct snd_sst_target_device *target_device);
+int sst_set_pmic_config(int streamID, struct snd_sst_pmic_config *pc);
+
+void sst_post_message(struct work_struct *work);
+void sst_process_message(struct work_struct *work);
+void sst_process_reply(struct work_struct *work);
+void sst_send_loop_test(int x);
+
+int intel_sst_ioctl(struct inode *i_node, struct file *file_ptr,
+ unsigned int cmd, unsigned long arg);
+int intel_sst_open(struct inode *i_node, struct file *file_ptr);
+int intel_sst_release(struct inode *i_node, struct file *file_ptr);
+int intel_sst_read(struct file *file_ptr, char __user *buf,
+ size_t count, loff_t *ppos);
+int intel_sst_write(struct file *file_ptr, const char __user *buf,
+ size_t count, loff_t *ppos);
+int intel_sst_mmap(struct file *fp, struct vm_area_struct *vma);
+ssize_t intel_sst_aio_write(struct kiocb *kiocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t offset);
+ssize_t intel_sst_aio_read(struct kiocb *kiocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t offset);
+
+int sst_ospm_send_event(int event);
+void sst_load_fw(const struct firmware *fw, void *context);
+int sst_load_library(struct snd_sst_lib_download *lib, u8 ops, u32 pvt_id);
+
+static inline int sst_scu_ipc_write(u32 addr, u32 value)
+{
+#ifndef CONFIG_SST_IPC_NOT_INCLUDED
+ int retval = 0, retry = 3;
+ struct ipc_reg_data ipc_reg = {0};
+
+ ipc_reg.address = addr;
+ ipc_reg.data = value;
+ ipc_reg.ioc = 1;
+
+ while (retry) {
+ retval = mrst_ipc_write32(&ipc_reg);
+ if (retval == 0)
+ break;
+ retry--;
+ /*error*/
+ sst_err("IPC write failed %x\n", retval);
+ }
+ return retval;
+#else
+ return 0;
+#endif
+}
+static inline void sst_fill_header(union ipc_header *header,
+ int msg, int large, int strID)
+{
+ header->part.msg_id = msg;
+ header->part.str_id = strID;
+ header->part.large = large;
+ header->part.done = 0;
+ header->part.busy = 1;
+ header->part.data = 0;
+}
+
+static inline int sst_get_stream_id(struct intel_sst_drv *sst_ops, int pvt_id)
+{
+ int i;
+
+ for (i = 1; i < MAX_NUM_STREAMS; i++) {
+ if (pvt_id == sst_ops->streams[i].sst_id)
+ return i;
+ }
+ return -EINVAL;
+}
+
+static inline unsigned int sst_assign_pvt_id(struct intel_sst_drv *sst_ops)
+{
+ sst_ops->unique_id++;
+ if (sst_ops->unique_id >= MAX_NUM_STREAMS)
+ sst_ops->unique_id = 1;
+ return sst_ops->unique_id;
+}
+
+static inline int sst_get_block_stream(struct intel_sst_drv *sst_ops)
+{
+ int i;
+
+ for (i = 0; i < MAX_ACTIVE_STREAM; i++) {
+ if (BLOCK_UNINIT == sst_ops->alloc_block[i].sst_id) {
+ sst_ops->alloc_block[i].ops_block.condition = false;
+ sst_ops->alloc_block[i].ops_block.ret_code = 0;
+ sst_ops->alloc_block[i].sst_id = 0;
+ break;
+ }
+ }
+ if (MAX_ACTIVE_STREAM == i) {
+ sst_err("max alloc_stream reached \n");
+ i = -EBUSY; /*active stream limit reached*/
+ }
+ return i;
+}
+
+
+
+static inline void sst_print_hex(unsigned char *buf, unsigned int size)
+{
+ unsigned int i;
+
+ for (i = 0; i < size; i++) {
+ sst_dbg("%02x ", buf[i]);
+ if ((i != 0) && ((i % 8) == 0))
+ sst_dbg("\n");
+ }
+}
+
+static inline void sst_init_stream(struct stream_info *stream,
+ int codec, int sst_id, int ops)
+{
+ stream->status = STREAM_INIT;
+ stream->prev = STREAM_UN_INIT;
+ stream->codec = codec;
+ stream->sst_id = sst_id;
+ stream->ops = ops;
+ stream->data_blk.on = false;
+ stream->data_blk.condition = false;
+ stream->data_blk.ret_code = 0;
+ stream->data_blk.data = NULL;
+ stream->ctrl_blk.on = false;
+ stream->ctrl_blk.condition = false;
+ stream->ctrl_blk.ret_code = 0;
+ stream->ctrl_blk.data = NULL;
+ stream->mmapped = false;
+}
+
+static inline void sst_clean_stream(struct stream_info *stream)
+{
+ struct sst_stream_bufs *bufs = NULL, *_bufs = NULL;
+ stream->status = STREAM_UN_INIT;
+ stream->prev = STREAM_UN_INIT;
+ list_for_each_entry_safe(bufs, _bufs, &stream->bufs, node) {
+ list_del(&bufs->node);
+ kfree(bufs);
+ }
+}
+
+static inline int sst_wait_interruptible(struct intel_sst_drv *sst_ops,
+ struct sst_block *block)
+{
+ int retval = 0;
+
+ if (!wait_event_interruptible(sst_ops->wait_queue, block->condition)) {
+ /*event wake*/
+ if (0 != block->ret_code) {
+ sst_err("stream failed %d\n", block->ret_code);
+ retval = -EBUSY;
+ } else {
+ sst_dbg("event up\n");
+ retval = 0;
+ }
+ } else {
+ sst_err("signal interrupted\n");
+ retval = -EINTR;
+ }
+ return retval;
+
+}
+
+static inline int sst_wait_interruptible_timeout(struct intel_sst_drv *sst_ops,
+ struct sst_block *block, int timeout)
+{
+ int retval = 0;
+
+ sst_dbg("waiting....\n");
+ if (wait_event_interruptible_timeout(sst_ops->wait_queue,
+ block->condition,
+ msecs_to_jiffies(timeout))) {
+ /*event wake*/
+ sst_dbg("Event wake ...\n");
+ if (0 != block->ret_code)
+ sst_err("stream failed %d\n", block->ret_code);
+ else
+ sst_dbg("event up\n");
+ retval = block->ret_code;
+ } else {
+ sst_err("timeout occured...\n");
+ retval = -EBUSY;
+ }
+ return retval;
+
+}
+
+static inline int sst_wait_timeout(struct intel_sst_drv *sst_ops,
+ struct stream_alloc_block *block)
+{
+ int retval = 0;
+
+ /*NOTE:
+ Observed that FW processes the alloc msg and replies even
+ before the alloc thread has finished execution*/
+ sst_dbg("waiting for %x, condition %x \n", block->sst_id,
+ block->ops_block.condition);
+ if (wait_event_interruptible_timeout(sst_ops->wait_queue,
+ block->ops_block.condition,
+ msecs_to_jiffies(SST_BLOCK_TIMEOUT))) {
+ /*event wake*/
+ sst_dbg("Event wake ... %x \n", block->ops_block.condition);
+ /*check return*/
+ if (0 > block->ops_block.ret_code)
+ sst_err("blk failed %d\n", block->ops_block.ret_code);
+ else
+ sst_dbg("blk ret: %d\n", block->ops_block.ret_code);
+ retval = block->ops_block.ret_code;
+ } else {
+ sst_err("Wait timed-out %x\n", block->ops_block.condition);
+ retval = -EBUSY;
+ }
+ return retval;
+
+}
+
+
+static inline int sst_create_large_msg(struct ipc_post **arg)
+{
+ struct ipc_post *msg;
+
+ msg = kzalloc(sizeof(struct ipc_post), GFP_ATOMIC);
+ if (NULL == msg) {
+ sst_err("kzalloc msg failed \n");
+ return -ENOMEM;
+ }
+
+ msg->mailbox_data = kzalloc(SST_MAILBOX_SIZE, GFP_ATOMIC);
+ if (NULL == msg->mailbox_data) {
+ kfree(msg);
+ sst_err("kzalloc mailbox_data failed \n");
+ return -ENOMEM;
+ };
+ *arg = msg;
+ return 0;
+}
+
+static inline int sst_create_short_msg(struct ipc_post **arg)
+{
+ struct ipc_post *msg;
+
+ msg = kzalloc(sizeof(*msg), GFP_ATOMIC);
+ if (NULL == msg) {
+ sst_err("kzalloc msg failed \n");
+ return -ENOMEM;
+ }
+ msg->mailbox_data = NULL;
+ *arg = msg;
+ return 0;
+}
+
+static inline void sst_print_params(struct snd_sst_stream_params *sparam)
+{
+ switch (sparam->uc.pcm_params.codec) {
+ case SST_CODEC_TYPE_PCM:
+ sst_dbg("pcm \n");
+ sst_dbg("chan=%d, sfreq = %d, wd_sz = %d \
+ brate = %d framesize = %d \
+ samples_per_frame = %d \
+ period_cnt = %d\n",
+ sparam->uc.pcm_params.num_chan,
+ sparam->uc.pcm_params.sfreq,
+ sparam->uc.pcm_params.pcm_wd_sz,
+ sparam->uc.pcm_params.brate,
+ sparam->uc.pcm_params.frame_size,
+ sparam->uc.pcm_params.samples_per_frame,
+ sparam->uc.pcm_params.period_count);
+ break;
+
+ case SST_CODEC_TYPE_MP3:
+ sst_dbg("mp3 \n");
+ sst_dbg("chan=%d, brate=%d, sfreq = %d, wd_sz = %d\n",
+ sparam->uc.mp3_params.num_chan,
+ sparam->uc.mp3_params.brate,
+ sparam->uc.mp3_params.sfreq,
+ sparam->uc.mp3_params.pcm_wd_sz);
+ break;
+
+ case SST_CODEC_TYPE_AAC:
+ sst_dbg("aac \n");
+ sst_dbg("chan=%d, brate=%d, sfreq = %d, wd_sz = %d,asrate=%d\n",
+ sparam->uc.aac_params.num_chan,
+ sparam->uc.aac_params.brate,
+ sparam->uc.aac_params.sfreq,
+ sparam->uc.aac_params.pcm_wd_sz,
+ sparam->uc.aac_params.aac_srate);
+ sst_dbg("mpgid=%d profile=%d, aot = %d\n",
+ sparam->uc.aac_params.mpg_id,
+ sparam->uc.aac_params.aac_profile,
+ sparam->uc.aac_params.aot);
+ break;
+ case SST_CODEC_TYPE_WMA9:
+ sst_dbg("wma type \n");
+ sst_dbg("chan=%d, brate=%d, sfreq = %d, wd_sz = %d, tag=%d\n",
+ sparam->uc.wma_params.num_chan,
+ sparam->uc.wma_params.brate,
+ sparam->uc.wma_params.sfreq,
+ sparam->uc.wma_params.pcm_wd_sz,
+ sparam->uc.wma_params.format_tag);
+ sst_dbg("mask=%d, b align=%d, enc opt =%d, op align =%d\n",
+ sparam->uc.wma_params.channel_mask,
+ sparam->uc.wma_params.block_align,
+ sparam->uc.wma_params.wma_encode_opt,
+ sparam->uc.wma_params.op_align);
+ break;
+ default:
+ sst_dbg("other codec 0x%x\n", sparam->uc.pcm_params.codec);
+ }
+}
+static inline int sst_validate_strid(int str_id)
+{
+ if (str_id <= 0 || str_id >= MAX_NUM_STREAMS) {
+ sst_err("invalid stream id \n");
+ return -EINVAL;
+ } else
+ return 0;
+}
+
+/*NOTE: status will +ve for good cases and -ve for error ones*/
+#define MAX_STREAM_FIELD 255
+static inline void sst_wake_up_alloc_block(struct intel_sst_drv *sst_ops,
+ u8 sst_id, int status, void *data)
+{
+ int i;
+
+ /*Unblock with retval code*/
+ for (i = 0; i < MAX_STREAM_FIELD; i++) {
+ if (sst_id == sst_ops->alloc_block[i].sst_id) {
+ sst_ops->alloc_block[i].ops_block.condition = true;
+ sst_ops->alloc_block[i].ops_block.ret_code = status;
+ sst_ops->alloc_block[i].ops_block.data = data;
+ sst_dbg("wake id %d, sst_id %d condition %x\n", i,
+ sst_ops->alloc_block[i].sst_id,
+ sst_ops->alloc_block[i].ops_block.condition);
+ wake_up(&sst_ops->wait_queue);
+ break;
+ }
+ }
+}
+#endif /*__INTEL_SST_PVT_H__*/
--
1.5.4.5
3
2