From 5e8c7c54a9b297dae0081dd19a7bb94e23040a3d Mon Sep 17 00:00:00 2001 From: Joshua Lock Date: Tue, 18 May 2010 14:51:13 +0100 Subject: linux-moblin: add 2.6.33.2 kernel from MeeGo 1.0 Signed-off-by: Joshua Lock --- ...ux-2.6.34-moorestown-audio-driver-6.0-3-8.patch | 2532 ++++++++++++++++++++ 1 file changed, 2532 insertions(+) create mode 100644 meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-audio-driver-6.0-3-8.patch (limited to 'meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-audio-driver-6.0-3-8.patch') diff --git a/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-audio-driver-6.0-3-8.patch b/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-audio-driver-6.0-3-8.patch new file mode 100644 index 000000000..aca3e467d --- /dev/null +++ b/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-audio-driver-6.0-3-8.patch @@ -0,0 +1,2532 @@ +From 3657fc661cea2b120a7516cb66002fcd3af34e35 Mon Sep 17 00:00:00 2001 +From: R, Dharageswari +Date: Thu, 29 Apr 2010 20:23:41 +0530 +Subject: [PATCH] ADR-Post-Beta-0.05.002.03-3/8-Moorestown Audio Drivers: SST interface modules + +This patch adds the SST driver interface module. Interface module is the +one which talks to upper/other layer in the SST Driver +intel_sst_interface.c - implements the MAD driver registration & deregistration +functions. SST driver is also a character driver, so that player/middleware can +communicate with SST driver. All char driver routines like open, close, read, +write and ioctl are implemented here. The ioctl operations are used by +middleware/players to open/close, control and configure astream as well as to +transfer the data. +intel_sst_ioctl.h - exposes the IOCTL definition for players/middleware +as well as the various structure for passing stream parameters + +Signed-off-by: Vinod Koul + + new file: include/sound/intel_sst_ioctl.h + new file: sound/pci/sst/intel_sst_interface.c +Patch-mainline: 2.6.35? +--- + include/sound/intel_sst_ioctl.h | 390 +++++++ + sound/pci/sst/intel_sst_interface.c | 2099 +++++++++++++++++++++++++++++++++++ + 2 files changed, 2489 insertions(+), 0 deletions(-) + create mode 100644 include/sound/intel_sst_ioctl.h + create mode 100644 sound/pci/sst/intel_sst_interface.c + +diff --git a/include/sound/intel_sst_ioctl.h b/include/sound/intel_sst_ioctl.h +new file mode 100644 +index 0000000..442b388 +--- /dev/null ++++ b/include/sound/intel_sst_ioctl.h +@@ -0,0 +1,390 @@ ++#ifndef __INTEL_SST_IOCTL_H__ ++#define __INTEL_SST_IOCTL_H__ ++/* ++ * intel_sst_ipc.h - Intel SST Driver for audio engine ++ * ++ * Copyright (C) 2008-10 Intel Corporation ++ * Authors: Vinod Koul ++ * Harsha Priya ++ * Dharageswari R ++ * KP Jeeja ++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ * ++ * 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 */ ++ SST_CODEC_SRC = 0x64, ++ SST_CODEC_MIXER = 0x65, ++ SST_CODEC_DOWN_MIXER = 0x66, ++ SST_CODEC_VOLUME_CONTROL = 0x67, ++ SST_CODEC_OEM1 = 0xC8, ++ SST_CODEC_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 buffer_size; ++ __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 */ ++ __u8 jstereo; /* Joint stereo Flag */ ++ __u8 sbr_present; /* 1 = SBR Present, 0 = SBR absent, for RAW */ ++ __u8 downsample; /* 1 = Downsampling ON, 0 = Downsampling OFF */ ++ __u8 num_syntc_elems; /* 1- Mono/stereo, 0 - Dual Mono, 0 - for raw */ ++ __s8 syntc_id[2]; /* 0 for ID_SCE(Dula Mono), -1 for raw */ ++ __s8 syntc_tag[2]; /* raw - -1 and 0 -16 for rest of the streams */ ++ __u8 pce_present; /* Flag. 1- present 0 - not present, for RAW */ ++ __u8 sbr_type; /* sbr_type: 0-plain aac, 1-aac-v1, 2-aac-v2 */ ++ __u8 outchmode; /* 0- mono, 1-stereo, 2-dual mono 3-Parametric stereo */ ++ __u8 ps_present; ++ ++}; ++ ++/* 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 pcm_src; /* input pcm bit width */ ++}; ++ ++/* Pre processing param structure */ ++struct snd_prp_params { ++ __u32 reserved; /* No pre-processing defined yet */ ++}; ++ ++/* 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 */ ++ __u8 mute_control; /* 0=No Mute, 1=Mute */ ++ __u8 reserved1; ++ __u16 reserved2; ++}; ++ ++/* 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 Lowpower Playback */ ++ __u8 max_pcm_streams_supported; /* Max num 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; ++ ++/* 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; ++} __attribute__ ((packed)); ++ ++struct snd_sst_params { ++ __u32 result; ++ __u32 stream_id; ++ __u8 codec; ++ __u8 ops; ++ __u8 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_LPE, ++ SND_SST_TARGET_OTHER, ++}; ++ ++enum snd_sst_device_type { ++ SND_SST_DEVICE_SSP = 1, ++ SND_SST_DEVICE_PCM, ++ SND_SST_DEVICE_OTHER, ++}; ++ ++/*enum snd_sst_device_mode { ++ SND_SST_PCM_MODE_I2S = 0, ++ SND_SST_PCM_MODE_PCM1, ++};*/ ++enum snd_sst_device_mode { ++ ++ SND_SST_DEV_MODE_PCM_MODE1 = 1, /*(1 16-bit word, bit-length frame sync)*/ ++ SND_SST_DEV_MODE_PCM_MODE2, ++ SND_SST_DEV_MODE_PCM_MODE3, ++ SND_SST_DEV_MODE_PCM_MODE4_RIGHT_JUSTIFIED, ++ SND_SST_DEV_MODE_PCM_MODE4_LEFT_JUSTIFIED, ++ SND_SST_DEV_MODE_PCM_MODE4_I2S, /*(I2S mode, 16-bit words)*/ ++}; ++ ++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 */ ++ __u8 target_type; ++ __u16 slot[2]; ++ __u8 master; ++ __u8 action; ++ __u16 device_mode; ++ struct snd_sst_pmic_config pcm_params; ++} __attribute__ ((packed)); ++ ++#define SST_MAX_TARGET_DEVICES 3 ++/* Target device list structure */ ++struct snd_sst_target_device { ++ __u32 device_route; ++ struct snd_sst_slot_info devices[SST_MAX_TARGET_DEVICES]; ++} __attribute__ ((packed)); ++ ++struct snd_sst_driver_info { ++ __u32 version; /* Version of the driver */ ++ __u32 active_pcm_streams; ++ __u32 active_enc_streams; ++ __u32 max_pcm_streams; ++ __u32 max_enc_streams; ++ __u32 buf_per_stream; ++}; ++ ++struct snd_sst_vol { ++ __u32 stream_id; ++ __s32 volume; ++ __u32 ramp_duration; ++ __u32 ramp_type; /* Ramp type, default=0 */ ++}; ++ ++struct snd_sst_mute { ++ __u32 stream_id; ++ __u32 mute; ++}; ++ ++enum snd_sst_buff_type { ++ SST_BUF_USER = 1, ++ SST_BUF_MMAP, ++ SST_BUF_RAR, ++}; ++ ++struct snd_sst_mmap_buff_entry { ++ unsigned int offset; ++ unsigned int size; ++}; ++ ++struct snd_sst_mmap_buffs { ++ unsigned int entries; ++ enum snd_sst_buff_type type; ++ struct snd_sst_mmap_buff_entry *buff; ++}; ++ ++struct snd_sst_buff_entry { ++ void *buffer; ++ unsigned int size; ++}; ++ ++struct snd_sst_buffs { ++ unsigned int entries; ++ __u8 type; ++ struct snd_sst_buff_entry *buff_entry; ++}; ++ ++struct snd_sst_dbufs { ++ unsigned long long input_bytes_consumed; ++ unsigned long long output_bytes_produced; ++ struct snd_sst_buffs *ibufs; ++ struct snd_sst_buffs *obufs; ++}; ++ ++/*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, __u64 *) ++#define SNDRV_SST_STREAM_DECODE _IOWR('L', 0x03, struct snd_sst_dbufs *) ++#define SNDRV_SST_STREAM_BYTES_DECODED _IOWR('L', 0x04, __u64 *) ++#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_mmap_buffs *) ++#define SNDRV_SST_MMAP_CAPTURE _IOW('L', 0x06, struct snd_sst_mmap_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__ */ +diff --git a/sound/pci/sst/intel_sst_interface.c b/sound/pci/sst/intel_sst_interface.c +new file mode 100644 +index 0000000..5f84245 +--- /dev/null ++++ b/sound/pci/sst/intel_sst_interface.c +@@ -0,0 +1,2099 @@ ++/* ++ * intel_sst_interface.c - Intel SST Driver for audio engine ++ * ++ * Copyright (C) 2008-10 Intel Corporation ++ * Authors: Vinod Koul ++ * Harsha Priya ++ * Dharageswari R ++ * KP Jeeja ++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "intel_sst_fw_ipc.h" ++#include "intel_sst_common.h" ++ ++#define AM_MODULE 1 ++#define STREAM_MODULE 0 ++ ++/** ++* This function is called when the FW needs to be downloaded to SST DSP engine ++*/ ++static int sst_download_fw(void) ++{ ++ int retval; ++ const struct firmware *fw_sst; ++ ++ printk(KERN_DEBUG "SST DBG:SST Downloading FW now...\n"); ++ retval = request_firmware(&fw_sst, ++ SST_FW_STD_FILENAME, ++ &sst_drv_ctx->pci->dev); ++ if (retval) { ++ printk(KERN_ERR ++ "SST ERR: req fw failed %d \n", retval); ++ return retval; ++ } ++ sst_drv_ctx->alloc_block[0].sst_id = FW_DWNL_ID; ++ retval = sst_load_fw(fw_sst, NULL); ++ if (retval) ++ goto end_restore; ++ ++ sst_drv_ctx->alloc_block[0].ops_block.condition = false; ++ retval = sst_wait_timeout(sst_drv_ctx, &sst_drv_ctx->alloc_block[0]); ++ if (retval) ++ printk(KERN_ERR ++ "SST ERR: fw download failed %d \n" , retval); ++end_restore: ++ release_firmware(fw_sst); ++ sst_drv_ctx->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; ++ ++ if (sst_drv_ctx->pmic_state != SND_MAD_INIT_DONE) { ++ printk(KERN_ERR ++ "SST ERR: Sound card not availble \n "); ++ return -EIO; ++ } ++ ++ if (sst_drv_ctx->sst_state == SST_UN_INIT) { ++ /* FW is not downloaded */ ++ retval = sst_download_fw(); ++ if (retval) { ++ printk(KERN_ERR ++ "SST ERR: FW download failed...abort\n"); ++ return -ENODEV; ++ } ++ } ++ if (device == MKDEV(INTEL_SST_MAJOR, 0)) { ++ /* app open */ ++ mutex_lock(&sst_drv_ctx->stream_cnt_lock); ++ if (sst_drv_ctx->encoded_cnt < MAX_ENC_STREAM) { ++ struct ioctl_pvt_data *data = ++ kzalloc(sizeof(struct ioctl_pvt_data), ++ GFP_KERNEL); ++ if (!data) { ++ printk(KERN_ERR ++ "SST ERR:error rsrvin data mry\n"); ++ mutex_unlock(&sst_drv_ctx->stream_cnt_lock); ++ return -ENOMEM; ++ } ++ ++ ++ sst_drv_ctx->encoded_cnt++; ++ /*sst_drv_ctx->stream_cnt++;*/ ++ mutex_unlock(&sst_drv_ctx->stream_cnt_lock); ++ data->pvt_id = sst_assign_pvt_id(sst_drv_ctx); ++ data->str_id = 0; ++ file_ptr->private_data = (void *)data; ++ printk(KERN_DEBUG "SST DBG:sst id allocated = %d!\n", data->pvt_id); ++ } else ++ retval = -EACCES; ++ } else if (device == MKDEV(INTEL_SST_MAJOR, 1)) { ++ /* audio manager open */ ++ mutex_lock(&sst_drv_ctx->stream_cnt_lock); ++ if (sst_drv_ctx->am_cnt < MAX_AM_HANDLES) { ++ sst_drv_ctx->am_cnt++; ++ printk(KERN_DEBUG "SST DBG:AM handle opened...\n"); ++ } else ++ retval = -EACCES; ++ ++ mutex_unlock(&sst_drv_ctx->stream_cnt_lock); ++ } else ++ retval = -EINVAL; ++ return retval; ++} ++ ++void free_stream_context(unsigned int str_id) ++{ ++ struct stream_info *stream; ++ ++ if (!sst_validate_strid(str_id)) { ++ /* str_id is valid, so stream is alloacted */ ++ stream = &sst_drv_ctx->streams[str_id]; ++ if (stream->ops == STREAM_OPS_PLAYBACK || ++ stream->ops == STREAM_OPS_PLAYBACK_DRM) { ++ sst_drv_ctx->pb_streams--; ++ if (sst_drv_ctx->pb_streams == 0 && sst_drv_ctx->cp_streams > 0) ++ sst_drv_ctx->scard_ops->power_down_pmic_pb(); ++ } else if (stream->ops == STREAM_OPS_CAPTURE) { ++ sst_drv_ctx->cp_streams--; ++ if (sst_drv_ctx->cp_streams == 0 && sst_drv_ctx->pb_streams > 0) ++ sst_drv_ctx->scard_ops->power_down_pmic_cp(); ++ } ++#ifdef CONFIG_MSTWN_POWER_MGMT ++ if(stream->codec == SST_CODEC_TYPE_MP3){ ++ sst_drv_ctx->lpaudio_start--; ++ if(!sst_drv_ctx->lpaudio_start) { ++ sst_ospm_send_event(OSPM_EVENT_LPAUDIO_STOP); ++ printk(KERN_DEBUG "SST DBG:Free_stream:lpaudio_start:%d", sst_drv_ctx->lpaudio_start); ++ printk(KERN_DEBUG "SST DBG:Free_stream:Sending OSPM_EVENT_LPAUDIO_STOP...\n"); ++ } ++ }else { ++ sst_drv_ctx->audio_start--; ++ if(!sst_drv_ctx->audio_start) { ++ sst_ospm_send_event(OSPM_EVENT_SUBSYS_STOP_PLAY); ++ printk(KERN_DEBUG "SST DBG:Free_stream:audio_start:%d", sst_drv_ctx->audio_start); ++ printk(KERN_DEBUG "SST DBG:Free_stream:Sending OSPM_EVENT_SUBSYS_STOP_PLAY...\n"); ++ } ++ } ++#endif ++ if(sst_drv_ctx->pb_streams == 0 && ++ sst_drv_ctx->cp_streams == 0) { ++ sst_drv_ctx->scard_ops->power_down_pmic(); ++ } ++ ++ if (sst_free_stream(str_id)) ++ sst_clean_stream(&sst_drv_ctx->streams[str_id]); ++ } ++} ++ ++/** ++* 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; ++ ++ printk(KERN_DEBUG "SST DBG:Release called \n"); ++ if (device == MKDEV(INTEL_SST_MAJOR, 0)) { ++ struct ioctl_pvt_data *data = ++ (struct ioctl_pvt_data *)file_ptr->private_data; ++ ++ /* app close */ ++ printk(KERN_DEBUG "SST DBG:Closing app handle \n"); ++ mutex_lock(&sst_drv_ctx->stream_cnt_lock); ++ sst_drv_ctx->encoded_cnt--; ++ sst_drv_ctx->stream_cnt--; ++ mutex_unlock(&sst_drv_ctx->stream_cnt_lock); ++ free_stream_context(data->str_id); ++ kfree(data); ++ } else if (device == MKDEV(INTEL_SST_MAJOR, 1)) { ++ /* audio manager close */ ++ mutex_lock(&sst_drv_ctx->stream_cnt_lock); ++ sst_drv_ctx->am_cnt--; ++ mutex_unlock(&sst_drv_ctx->stream_cnt_lock); ++ printk(KERN_DEBUG "SST DBG:AM handle closed \n"); ++ } ++ return 0; ++} ++ ++/** ++* intel_sst_mmap - mmaps a kernel buffer to user space for copying data ++* @vma: vm area structure instance ++* @file_ptr: pointer to file ++* ++* This function is called by OS when a user space component ++* tries to get mmap memory from driver ++*/ ++int intel_sst_mmap(struct file *file_ptr, struct vm_area_struct *vma) ++{ ++ int retval, length; ++ struct ioctl_pvt_data *data = ++ (struct ioctl_pvt_data *)file_ptr->private_data; ++ int str_id = data->str_id; ++ void *mem_area; ++ ++ retval = sst_validate_strid(str_id); ++ if (retval) ++ return -EINVAL; ++ ++ length = vma->vm_end - vma->vm_start; ++ printk(KERN_DEBUG "SST DBG:called for stream %d length 0x%x\n", str_id, length); ++ ++ if (length > sst_drv_ctx->mmap_len) ++ return -ENOMEM; ++ if (!sst_drv_ctx->mmap_mem) ++ return -EIO; ++ ++ /* round it up to the page bondary */ ++ /*mem_area = (void *)((((unsigned long)sst_drv_ctx->mmap_mem) ++ + PAGE_SIZE - 1) & PAGE_MASK);*/ ++ mem_area = (void *) PAGE_ALIGN((unsigned int) sst_drv_ctx->mmap_mem); ++ ++ /* 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) { ++ sst_drv_ctx->streams[str_id].mmapped = false; ++ printk(KERN_ERR "SST ERR: mapping failed %d ",retval); ++ } else ++ sst_drv_ctx->streams[str_id].mmapped = true; ++ ++ printk(KERN_DEBUG "SST DBG:mmap ret 0x%x \n", retval); ++ return retval; ++} ++ ++/** ++* intel_sst_mmap_play_capture - sets mmap data buffers to play/capture ++*/ ++static int intel_sst_mmap_play_capture(u32 str_id, ++ struct snd_sst_mmap_buffs *mmap_buf) ++{ ++ struct sst_stream_bufs *bufs; ++ int retval, i; ++ struct stream_info *stream; ++ struct snd_sst_mmap_buff_entry *buf_entry; ++ ++ printk(KERN_DEBUG "SST DBG:called for str_id %d \n", str_id); ++ retval = sst_validate_strid(str_id); ++ if (retval) { ++ printk(KERN_ERR "SST ERR: val +\ ++ failed %d ", retval); ++ return -EINVAL; ++ } ++ BUG_ON(!mmap_buf); ++ ++ stream = &sst_drv_ctx->streams[str_id]; ++ if (stream->mmapped != true) { ++ printk(KERN_ERR "SST ERR: stream not mapped! "); ++ return -EIO; ++ } ++ ++ if (stream->status == STREAM_UN_INIT || ++ stream->status == STREAM_DECODE) { ++ printk(KERN_ERR ++ "SST ERR: BAD REQUEST!, streamstate +\ ++ is %d\n", stream->status); ++ return -EBADRQC; ++ } ++ stream->curr_bytes = 0; ++ stream->cumm_bytes = 0; ++ ++ printk(KERN_DEBUG "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) { ++ printk(KERN_ERR ++ "SST ERR: mem allocation failed \n "); ++ return -ENOMEM; ++ } ++ bufs->size = buf_entry->size; ++ bufs->offset = buf_entry->offset; ++ bufs->addr = sst_drv_ctx->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->need_draining != true) { ++ stream->prev = stream->status; ++ stream->status = STREAM_RUNNING; ++ if (stream->ops == STREAM_OPS_PLAYBACK) { ++ printk(KERN_DEBUG "SST DBG:play frames...\n"); ++ if (sst_play_frame(str_id) < 0) { ++ printk(KERN_ERR ++ "SST ERR: play frames failed \n"); ++ mutex_unlock(&stream->lock); ++ return -EIO; ++ } ++ } else if (stream->ops == STREAM_OPS_CAPTURE) { ++ printk(KERN_DEBUG "SST DBG:capture frames...\n"); ++ if (sst_capture_frame(str_id) < 0) { ++ printk(KERN_ERR ++ "SST ERR: capture frames failed \n"); ++ mutex_unlock(&stream->lock); ++ return -EIO; ++ } ++ } ++ } ++ mutex_unlock(&stream->lock); ++ /* Block the call for reply */ ++ if (!list_empty(&stream->bufs)) { ++ printk(KERN_DEBUG "SST DBG:ioctl waiting...\n"); ++ stream->data_blk.on = true; ++ retval = sst_wait_interruptible(sst_drv_ctx, ++ &stream->data_blk); ++ } ++ ++ if (retval >= 0) ++ retval = stream->cumm_bytes; ++ printk(KERN_DEBUG "SST DBG:end of play/rec +\ ++ ioctl bytes = %d!!\n", retval); ++ return retval; ++} ++ ++/** ++* intel_sst_play_capture - sets user data buffers to play/capture ++*/ ++static int intel_sst_play_capture(struct stream_info *stream, int str_id) ++{ ++ int retval; ++ ++ stream->data_blk.ret_code = 0; ++ stream->data_blk.on = true; ++ stream->data_blk.condition = false; ++ ++ 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 */ ++ printk(KERN_DEBUG "SST DBG:Stream isnt started yet state %d, prev %d \n", ++ stream->status, stream->prev); ++ } else if ((stream->status == STREAM_RUNNING || ++ stream->status == STREAM_PAUSED) && ++ stream->need_draining != true) { ++ /* stream is started */ ++ if (stream->ops == STREAM_OPS_PLAYBACK || ++ stream->ops == STREAM_OPS_PLAYBACK_DRM) { ++ if (sst_play_frame(str_id) < 0) { ++ printk(KERN_ERR ++ "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) { ++ printk(KERN_ERR ++ "SST ERR: capture frames failed \n "); ++ mutex_unlock(&stream->lock); ++ return -EIO; ++ } ++ } ++ } else { ++ printk(KERN_ERR ++ "SST ERR: Streamstate %d invalid,prev %d\n",\ ++ stream->status, stream->prev); ++ mutex_unlock(&stream->lock); ++ return -EIO; ++ } ++ mutex_unlock(&stream->lock); ++ /* Block the call for reply */ ++ printk(KERN_DEBUG "SST DBG:write waiting...\n"); ++ ++ retval = sst_wait_interruptible(sst_drv_ctx, &stream->data_blk); ++ if (retval) { ++ stream->status = STREAM_INIT; ++ printk(KERN_DEBUG "SST DBG:wait returned error...\n"); ++ } ++ printk(KERN_DEBUG "SST DBG:write returning\n"); ++ return retval; ++} ++ ++/** ++* snd_sst_fill_kernel_list - fills kernel list with buffer addresses for ++* SST DSP driver to process ++*/ ++static 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; ++ 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) { ++ printk(KERN_ERR ++ "SST ERR: memory allocation failed \n "); ++ return -ENOMEM; ++ } ++ stream_bufs->addr = sst_drv_ctx->mmap_mem; ++ if (stream->ops == STREAM_OPS_PLAYBACK_DRM) { ++ for (index = stream->sg_index; index < nr_segs; index++) { ++ __u32 rar_handle; ++ struct sst_stream_bufs *stream_bufs = ++ kzalloc(sizeof(*stream_bufs), GFP_KERNEL); ++ ++ stream->sg_index = index; ++ if (!stream_bufs) { ++ printk(KERN_ERR ++ "SST ERR: mry alocation failed \n"); ++ return -ENOMEM; ++ } ++ retval = copy_from_user((void *) &rar_handle, ++ iovec[index].iov_base, ++ sizeof(__u32)); ++ if (retval != 0) { ++ printk(KERN_ERR ++ "SST ERR: copy from user +\ ++ failed\n"); ++ return -EIO; ++ } ++ stream_bufs->addr = (char *)rar_handle; ++ printk(KERN_DEBUG "SST DBG:rar handle +\ ++ received = 0x%x\n", (__u32)stream_bufs->addr); ++ stream_bufs->in_use = false; ++ stream_bufs->size = iovec[0].iov_len; ++ printk(KERN_DEBUG "size = 0x%x", stream_bufs->size); ++ /* locking here */ ++ mutex_lock(&stream->lock); ++ list_add_tail(&stream_bufs->node, &stream->bufs); ++ mutex_unlock(&stream->lock); ++ } ++ stream->sg_index = index; ++ return retval; ++ } ++ mmap_len = sst_drv_ctx->mmap_len; ++ stream_bufs->addr = sst_drv_ctx->mmap_mem; ++ bufp = stream->cur_ptr; ++ ++ printk(KERN_DEBUG "SST DBG:mmap_len - %lx\n", mmap_len); ++ copied_size = 0; ++ ++ if (!stream->sg_index) ++ sent_index = sent_offset = 0; ++ ++ for (index = stream->sg_index; index < nr_segs; index++) { ++ stream->sg_index = index; ++ printk(KERN_DEBUG "SST DBG:index - %lx, cur_ptr - %p\n", index, stream->cur_ptr); ++ printk(KERN_DEBUG "SST DBG:base - %p, size - 0x%x\n", iovec[index].iov_base, ++ iovec[index].iov_len); ++ printk(KERN_DEBUG "SST DBG:bufp - %p\n", bufp); ++ if (!stream->cur_ptr) ++ bufp = iovec[index].iov_base; ++ ++ size = ((unsigned long)iovec[index].iov_base ++ + iovec[index].iov_len) - (unsigned long) bufp; ++ ++ printk(KERN_DEBUG "SST DBG:size - %lx\n", size); ++ if ((copied_size + size) > mmap_len) ++ size = mmap_len - copied_size; ++ ++ printk(KERN_DEBUG "SST DBG:size - %lx\n", size); ++ ++ if (stream->ops == STREAM_OPS_PLAYBACK) { ++ printk(KERN_DEBUG "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 */ ++ printk(KERN_ERR ++ "SST ERR: cpyfrmusr not coped -%ld", data_not_copied); ++ retval = -EIO; ++ break; ++ } ++ } else if (stream->ops == STREAM_OPS_CAPTURE) { ++ struct snd_sst_user_cap_list *entry = ++ kzalloc(sizeof(*entry), GFP_KERNEL); ++ ++ if (!entry) { ++ printk(KERN_ERR ++ "SST ERR: mem allocation failed \n"); ++ /* FIXME cleanup prev */ ++ 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; ++ printk(KERN_DEBUG "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); ++ } ++ ++ printk(KERN_DEBUG "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)iovec[index].iov_base) ) { ++ printk(KERN_DEBUG "SST DBG:Buffer overflows"); ++ return -EINVAL; ++ } ++ ++ 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; ++ printk(KERN_DEBUG "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; ++} ++ ++/** ++* snd_sst_copy_userbuf_capture - This function copies the captured data ++* returned from SST DSP engine to the user buffers ++*/ ++static 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 */ ++ /* FIXME optimze */ ++ printk(KERN_DEBUG "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) { ++ printk(KERN_DEBUG "SST DBG:filling now... \n"); ++ printk(KERN_DEBUG "SST DBG:iindx %d,ioff %ld,koff %ld,ksz %ld \n", ++ entry->iov_index, entry->iov_offset, ++ entry->offset, entry->size); ++ printk(KERN_DEBUG "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 */ ++ printk(KERN_ERR ++ "SST ERR: copy to user err -%ld\n ", data_not_copied); ++ retval = -EIO; ++ break; ++ } ++ list_del(&entry->node); ++ kfree(entry); ++ } ++ printk(KERN_DEBUG "SST DBG:coming out of loop\n"); ++ } ++ } ++ printk(KERN_DEBUG "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. ++ */ /* FIXME cleanups in this fn no mem leaks due to link list */ ++static int snd_sst_userbufs_play_cap(const struct iovec *iovec, ++ unsigned long nr_segs, unsigned int str_id, ++ struct stream_info *stream) ++{ ++ int retval; ++ LIST_HEAD(copy_to_list); ++ ++ ++ retval = snd_sst_fill_kernel_list(stream, iovec, nr_segs, ++ ©_to_list); ++ ++ retval = intel_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; ++} ++ ++/** ++* intel_sst_read_write - This function is common function across read/write ++* for user buffers called from system calls ++*/ ++static int intel_sst_read_write(unsigned int str_id, char __user *buf, ++ size_t count) ++{ ++ int retval; ++ struct stream_info *stream; ++ struct iovec iovec; ++ unsigned long nr_segs; ++ ++ retval = sst_validate_strid(str_id); ++ if (retval) ++ return -EINVAL; ++ stream = &sst_drv_ctx->streams[str_id]; ++ if (stream->mmapped == true) { ++ printk(KERN_ERR ++ "SST ERR: user write and stream is mapped"); ++ return -EIO; ++ } ++ if (!count) { ++ printk(KERN_ERR ++ "SST ERR: args invalid %d", retval); ++ return -EINVAL; ++ } ++ stream->curr_bytes = 0; ++ stream->cumm_bytes = 0; ++ /* copy user buf details */ ++ printk(KERN_DEBUG "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; ++ if (retval >= 0) ++ retval = stream->cumm_bytes; ++ printk(KERN_DEBUG "SST DBG:end of play/rec bytes = %d!!\n", retval); ++ return retval; ++} ++ ++/* ++ * intel_sst_write - This function is called when user tries to play out data ++ * @file_ptr: pointer to file ++ * @buf: user buffer to be played out ++ * @count: size of tthe buffer ++ * @offset: offset to start from ++ */ ++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; ++ struct stream_info *stream = &sst_drv_ctx->streams[str_id]; ++ ++ printk(KERN_DEBUG "SST DBG:called for %d\n", str_id); ++ if (stream->status == STREAM_UN_INIT || ++ stream->status == STREAM_DECODE) { ++ printk(KERN_ERR "SST ERR: BAD REQUEST "); ++ return -EBADRQC; ++ } ++ return intel_sst_read_write(str_id, (char __user *)buf, count); ++} ++ ++/* ++ * intel_sst_aio_write - This function is called when user tries to play out ++ * multiple data buffers ++ * @kiocb: pointer to a structure containing file pointer ++ * @iov: list of user buffer to be played out ++ * @nr_segs: number of entries ++ * @offset: offset to start from ++ */ ++ssize_t intel_sst_aio_write(struct kiocb *kiocb, const struct iovec *iov, ++ unsigned long nr_segs, loff_t offset) ++{ ++ int retval; ++ struct ioctl_pvt_data *data = ++ (struct ioctl_pvt_data *)kiocb->ki_filp->private_data; ++ int str_id = data->str_id; ++ struct stream_info *stream; ++ ++ printk(KERN_DEBUG "SST DBG:entry - %ld\n", nr_segs); ++ ++ if (is_sync_kiocb(kiocb) == false) { ++ printk(KERN_ERR ++ "SST ERR: aio_writ frm userspace is not alowed\n"); ++ return -EINVAL; ++ } ++ ++ printk(KERN_DEBUG "SST DBG:called for str_id %d \n", str_id); ++ retval = sst_validate_strid(str_id); ++ if (retval) { ++ printk(KERN_ERR ++ "SST ERR: invalid stream id \n "); ++ return -EINVAL; ++ } ++ stream = &sst_drv_ctx->streams[str_id]; ++ if (stream->mmapped == true) { ++ printk(KERN_ERR ++ "SST ERR: user write & stream is mapped"); ++ return -EIO; ++ } ++ if (stream->status == STREAM_UN_INIT || ++ stream->status == STREAM_DECODE) { ++ printk(KERN_ERR "SST ERR: BAD REQUEST"); ++ return -EBADRQC; ++ } ++ stream->curr_bytes = 0; ++ stream->cumm_bytes = 0; ++ printk(KERN_DEBUG "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; ++ if (retval >= 0) ++ retval = stream->cumm_bytes; ++ printk(KERN_DEBUG "SST DBG:end of play/rec bytes = %d!!\n", retval); ++ return retval; ++} ++ ++/* ++ * intel_sst_read - This function is called when user tries to capture data ++ * @file_ptr: pointer to file ++ * @buf: user buffer to be filled with captured data ++ * @count: size of tthe buffer ++ * @offset: offset to start from ++ */ ++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; ++ struct stream_info *stream = &sst_drv_ctx->streams[str_id]; ++ ++ printk(KERN_DEBUG "SST DBG:called for %d\n", str_id); ++ if (stream->status == STREAM_UN_INIT || ++ stream->status == STREAM_DECODE) { ++ printk(KERN_ERR"SST ERR: BAD REQUEST!\n"); ++ return -EBADRQC; ++ } ++ return intel_sst_read_write(str_id, buf, count); ++} ++ ++/* ++ * intel_sst_aio_read - This function is called when user tries to capture out ++ * multiple data buffers ++ * @kiocb: pointer to a structure containing file pointer ++ * @iov: list of user buffer to be filled with captured ++ * @nr_segs: number of entries ++ * @offset: offset to start from ++ */ ++ ++ssize_t intel_sst_aio_read(struct kiocb *kiocb, const struct iovec *iov, ++ unsigned long nr_segs, loff_t offset) ++{ ++ int retval; ++ struct ioctl_pvt_data *data = ++ (struct ioctl_pvt_data *)kiocb->ki_filp->private_data; ++ int str_id = data->str_id; ++ struct stream_info *stream; ++ ++ printk(KERN_DEBUG "SST DBG:entry - %ld\n", nr_segs); ++ ++ if (is_sync_kiocb(kiocb) == false) { ++ printk(KERN_DEBUG "SST DBG:aio_read from user space is not allowed\n"); ++ return -EINVAL; ++ } ++ ++ printk(KERN_DEBUG "SST DBG:called for str_id %d \n", str_id); ++ retval = sst_validate_strid(str_id); ++ if (retval) ++ return -EINVAL; ++ stream = &sst_drv_ctx->streams[str_id]; ++ if (stream->mmapped == true) { ++ printk(KERN_ERR ++ "SST ERR: user write stream is mapped!!! "); ++ return -EIO; ++ } ++ if (stream->status == STREAM_UN_INIT || ++ stream->status == STREAM_DECODE) { ++ printk(KERN_ERR "SST ERR: BAD REQUEST!\n "); ++ return -EBADRQC; ++ } ++ stream->curr_bytes = 0; ++ stream->cumm_bytes = 0; ++ ++ printk(KERN_DEBUG "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; ++ if (retval >= 0) ++ retval = stream->cumm_bytes; ++ printk(KERN_DEBUG "SST DBG:end of play/rec bytes = %d!!\n", retval); ++ return retval; ++} ++ ++/* ++ * sst_print_stream_params - prints the stream parameters (debug fn) ++ */ ++static void sst_print_stream_params(struct snd_sst_get_stream_params *get_prm) ++{ ++ printk(KERN_DEBUG "SST DBG:codec params:result =%d\n", ++ get_prm->codec_params.result); ++ printk(KERN_DEBUG "SST DBG:codec params:stream = %d\n", ++ get_prm->codec_params.stream_id); ++ printk(KERN_DEBUG "SST DBG:codec params:codec = %d\n", ++ get_prm->codec_params.codec); ++ printk(KERN_DEBUG "SST DBG:codec params:ops = %d\n", ++ get_prm->codec_params.ops); ++ printk(KERN_DEBUG "SST DBG:codec params:stream_type= %d\n", ++ get_prm->codec_params.stream_type); ++ printk(KERN_DEBUG "SST DBG:pcmparams:sfreq= %d\n", ++ get_prm->pcm_params.sfreq); ++ printk(KERN_DEBUG "SST DBG:pcmparams:num_chan= %d\n", ++ get_prm->pcm_params.num_chan); ++ printk(KERN_DEBUG "SST DBG:pcmparams:pcm_wd_sz= %d\n", ++ get_prm->pcm_params.pcm_wd_sz); ++ return; ++} ++ ++/* ++ * sst_print_fw_info - prints the firmware information (debug fn) ++ */ ++static void sst_print_fw_info(struct snd_sst_fw_info *fw_info) ++{ ++ printk(KERN_DEBUG "SST DBG:build = %d\n", fw_info->fw_version.build); ++ printk(KERN_DEBUG "SST DBG:minor = %d\n", fw_info->fw_version.minor); ++ printk(KERN_DEBUG "SST DBG:major= %d\n", fw_info->fw_version.major); ++ printk(KERN_DEBUG "SST DBG:max pcm = %d\n", fw_info->max_pcm_streams_supported); ++ printk(KERN_DEBUG "SST DBG:max enc = %d\n", fw_info->max_enc_streams_supported); ++ printk(KERN_DEBUG "SST DBG:min input buf = %d\n", fw_info->min_input_buf); ++ printk(KERN_DEBUG "SST DBG:pop:src_min= %d\n", fw_info->pop_info.src_min); ++ printk(KERN_DEBUG "SST DBG:pop:src_max= %d\n", fw_info->pop_info.src_max); ++ printk(KERN_DEBUG "SST DBG:pop:src= %d\n", fw_info->pop_info.src); ++ printk(KERN_DEBUG "SST DBG:pop:bass_boost= %d\n", fw_info->pop_info.bass_boost); ++ printk(KERN_DEBUG "SST DBG:pop:stereo_widening= %d\n", fw_info->pop_info.stereo_widening); ++ printk(KERN_DEBUG "SST DBG:pop:volume_control= %d\n", fw_info->pop_info.volume_control); ++ printk(KERN_DEBUG "SST DBG:pop:min_vol= %d\n", fw_info->pop_info.min_vol); ++ printk(KERN_DEBUG "SST DBG:pop:max_vol= %d\n", fw_info->pop_info.max_vol); ++ printk(KERN_DEBUG "SST DBG:prp:min_vol= %d\n", fw_info->prp_info.min_vol); ++ printk(KERN_DEBUG "SST DBG:prp:max_vol= %d\n", fw_info->prp_info.max_vol); ++ printk(KERN_DEBUG "SST DBG:prp:volume_control= %d\n", fw_info->prp_info.volume_control); ++ printk(KERN_DEBUG "SST DBG:mix:max streams = %d\n", fw_info->mix_info.max_streams); ++ printk(KERN_DEBUG "SST DBG:port0:port_type = %d\n", fw_info->port_info[0].port_type); ++ printk(KERN_DEBUG "SST DBG:port1:port_type = %d\n", fw_info->port_info[1].port_type); ++ return; ++} ++ ++/* ++ * sst_get_stream_allocated - this function gets a stream allocated with ++ * the given params ++ */ ++static int sst_get_stream_allocated(struct snd_sst_params *str_param, ++ u32 block, u32 pvt_id) ++{ ++ int retval; ++ retval = sst_alloc_stream((char *) &str_param->sparams, str_param->ops, ++ str_param->codec, pvt_id); ++ if (retval) { ++ printk(KERN_ERR ++ "SST ERR: sst_alloc_stream failed %d \n", retval); ++ return retval; ++ } ++ /* Block the call for reply */ ++ retval = sst_wait_timeout(sst_drv_ctx, ++ &sst_drv_ctx->alloc_block[block]); ++ ++ return retval; ++} ++ ++/* ++ * set_port_params - this function sets the port parameters at Sound card end ++ */ ++static 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; ++ ++ printk(KERN_DEBUG "SST DBG:sampling frequency = %d wd_size = %d \n", sfreq, word_size); ++ ++ if (ops == STREAM_OPS_PLAYBACK || ++ ops == STREAM_OPS_PLAYBACK_DRM) { ++ printk(KERN_DEBUG "SST DBG:Setting playback path and port settings...\n"); ++ sst_drv_ctx->scard_ops.set_pcm_audio_params(sfreq, ++ word_size); ++ } else if (ops == STREAM_OPS_CAPTURE) { ++ printk(KERN_DEBUG "SST DBG:Setting capture path...\n"); ++ sst_drv_ctx->scard_ops->set_pcm_audio_params(sfreq, word_size); ++ }*/ ++ return; ++} ++ ++/* ++ * sst_get_sfreq - this function returns the frequency of the stream ++ */ ++static int sst_get_sfreq(struct snd_sst_params *str_param) ++{ ++ switch (str_param->codec) { ++ case SST_CODEC_TYPE_PCM: ++ return str_param->sparams.uc.pcm_params.sfreq; ++ case SST_CODEC_TYPE_MP3: ++ return str_param->sparams.uc.mp3_params.sfreq; ++ case SST_CODEC_TYPE_AAC: ++ return str_param->sparams.uc.aac_params.sfreq;; ++ case SST_CODEC_TYPE_WMA9: ++ return str_param->sparams.uc.wma_params.sfreq;; ++ default: ++ return 0; ++ } ++} ++ ++/* ++ * sst_stalled - this function checks if the lpe is in stalled state ++ */ ++int sst_stalled(void) ++{ ++ int retry = 1000; ++ int retval = -1; ++ ++ while(retry) { ++ if ( !sst_drv_ctx->lpe_stalled ) ++ return 0; ++ //wait for time and re-check ++ mdelay(1); ++ ++ retry--; ++ } ++ ++ printk(KERN_DEBUG "SST DBG:LPE is in Stalled State\n"); ++ return retval; ++} ++/* ++ * sst_get_stream - this function prepares for stream allocation ++ */ ++static int sst_get_stream(struct snd_sst_params *str_param, u32 pvt_id) ++{ ++ int i, retval; ++ struct stream_info *str_info; ++ ++ /* stream is not allocated, we are allocating */ ++ i = sst_get_block_stream(sst_drv_ctx); ++ printk(KERN_DEBUG "SST DBG:alloc block allocated = %d\n", i); ++ if (i < 0) ++ return -ENOMEM; ++ sst_drv_ctx->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_drv_ctx->alloc_block[i].ops_block.data; ++ printk(KERN_DEBUG "SST DBG:Codec is required.... trying that\n"); ++ retval = sst_load_library(&response->lib_dnld, ++ str_param->ops, pvt_id); ++ kfree(response); ++ ++ if (!retval) { ++ printk(KERN_DEBUG "SST DBG:codec was downloaded sucesfully \n"); ++ printk(KERN_DEBUG "SST DBG:try alloac again\n"); ++ sst_drv_ctx->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); ++ ++ printk(KERN_DEBUG "SST DBG:Allocation done stream id %d \n", retval); ++ } else { ++ printk(KERN_DEBUG "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); ++ ++ /* store sampling freq */ ++ str_info = &sst_drv_ctx->streams[retval]; ++ str_info->sfreq = sst_get_sfreq(str_param); ++ ++ /* power on the analog, if reqd */ ++ if (str_param->ops == STREAM_OPS_PLAYBACK || ++ str_param->ops == STREAM_OPS_PLAYBACK_DRM) { ++ ++ sst_drv_ctx->scard_ops->power_up_pmic_pb( ++ sst_drv_ctx->pmic_port_instance); ++ /*Only if the playback is MP3 - Send a message*/ ++#ifdef CONFIG_MSTWN_POWER_MGMT ++ if(str_info->codec == SST_CODEC_TYPE_MP3) { ++ sst_ospm_send_event(OSPM_EVENT_LPAUDIO_START); ++ sst_drv_ctx->lpaudio_start++; ++ printk(KERN_DEBUG "SST DBG:lpaudio_start:%d", sst_drv_ctx->lpaudio_start); ++ printk(KERN_DEBUG "SST DBG:Sending OSPM_EVENT_LPAUDIO_START...\n"); ++ }else {/*Only if the playback is non - MP3- Send a messageif not sent already*/ ++ if(sst_drv_ctx->audio_start == 0) { ++ sst_ospm_send_event(OSPM_EVENT_SUBSYS_START_PLAY); ++ sst_drv_ctx->audio_start++; ++ printk(KERN_DEBUG "SST DBG:audio_start:%d", sst_drv_ctx->audio_start); ++ printk(KERN_DEBUG "SST DBG:Sending OSPM_EVENT_SUBSYS_START_PLAY...\n"); ++ ++ } ++ else { ++ sst_drv_ctx->audio_start++; ++ } ++ } ++#endif ++ sst_drv_ctx->pb_streams++; ++ } else if (str_param->ops == STREAM_OPS_CAPTURE) { ++ ++ sst_drv_ctx->scard_ops->power_up_pmic_cp( ++ sst_drv_ctx->pmic_port_instance); ++ /*Send a messageif not sent already*/ ++#ifdef CONFIG_MSTWN_POWER_MGMT ++ if(sst_drv_ctx->audio_start == 0) { ++ sst_ospm_send_event(OSPM_EVENT_SUBSYS_START_PLAY); ++ printk(KERN_DEBUG "SST DBG:audio_start:%d", sst_drv_ctx->audio_start); ++ printk(KERN_DEBUG "SST DBG:Sending OSPM_EVENT_SUBSYS_START_PLAY...\n"); ++ sst_drv_ctx->audio_start++; ++ }else { ++ sst_drv_ctx->audio_start++; ++ } ++#endif ++ sst_drv_ctx->cp_streams++; ++ } ++ ++err: ++ sst_drv_ctx->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; ++ struct ioctl_pvt_data *data = NULL; ++ int str_id = 0, minor = 0; ++ dev_t device = i_node->i_rdev; ++ ++ if (device == MKDEV(INTEL_SST_MAJOR, 0)) { ++ minor = 0; ++ data = (struct ioctl_pvt_data *) ++ file_ptr->private_data; ++ str_id = data->str_id; ++ } else if (device == MKDEV(INTEL_SST_MAJOR, 1)) ++ minor = 1; ++ else ++ return -EINVAL; ++ ++ if (sst_drv_ctx->sst_state != SST_FW_RUNNING) { ++ printk(KERN_ERR ++ "SST ERR: SST Not runng %d\n " , sst_drv_ctx->sst_state); ++ return -EBUSY; ++ } ++ ++ switch (_IOC_NR(cmd)) { ++ case _IOC_NR(SNDRV_SST_STREAM_PAUSE): ++ printk(KERN_DEBUG "SST DBG:SNDRV_SST_IOCTL_PAUSE recieved for %d!\n", str_id); ++ if (minor != STREAM_MODULE) { ++ printk(KERN_ERR ++ "SST ERR: called for AM handle minor%d\n", minor); ++ retval = -EINVAL; ++ break; ++ } ++ retval = sst_pause_stream(str_id); ++ break; ++ ++ case _IOC_NR(SNDRV_SST_STREAM_RESUME): ++ printk(KERN_DEBUG "SST DBG:SNDRV_SST_IOCTL_RESUME recieved!\n"); ++ if (minor != STREAM_MODULE) { ++ printk(KERN_ERR ++ "SST ERR: caled for AM handle minor %d\n", minor); ++ 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; ++ ++ printk(KERN_DEBUG "SST DBG:IOCTL_SET_PARAMS recieved!\n"); ++ if (minor != STREAM_MODULE) { ++ printk(KERN_ERR ++ "SST ERR: caled for AM handle minor %d\n", minor); ++ retval = -EINVAL; ++ break; ++ } ++ sst_print_params(str_param); ++ ++ if (!str_id) { ++ retval = sst_get_stream(str_param, data->pvt_id); ++ if (retval > 0) { ++ struct stream_info *str_info; ++ sst_drv_ctx->stream_cnt++; ++ data->str_id = retval; ++ str_info = &sst_drv_ctx->streams[retval]; ++ str_info->src = SST_DRV; ++ retval = copy_to_user(&str_param->stream_id, ++ &retval, sizeof(__u32)); ++ } else { ++ if (retval == -SST_ERR_INVALID_PARAMS) ++ retval = -EINVAL; ++ } ++ } else { ++ printk(KERN_DEBUG "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) { ++ int sfreq = 0, word_size = 0, num_channel = 0; ++ sfreq = str_param->sparams.uc.pcm_params.sfreq; ++ word_size = str_param->sparams. ++ uc.pcm_params.pcm_wd_sz; ++ num_channel = str_param->sparams.uc.pcm_params.num_chan; ++ if (str_param->ops == STREAM_OPS_CAPTURE) { ++ printk(KERN_DEBUG "SST DBG:SST sampling frequency= %d\n", ++ sfreq); ++ sst_drv_ctx->scard_ops->\ ++ set_pcm_audio_params(sfreq, word_size, num_channel); ++ } ++ } ++ } ++ break; ++ } ++ case _IOC_NR(SNDRV_SST_SET_VOL): { ++ struct snd_sst_vol *set_vol; ++ struct snd_sst_vol *rec_vol = (struct snd_sst_vol *)arg; ++ printk(KERN_DEBUG "SST DBG:SNDRV_SST_SET_VOLUME recieved for %d!\n", ++ rec_vol->stream_id); ++ if (minor == STREAM_MODULE && rec_vol->stream_id == 0) { ++ printk(KERN_DEBUG "SST DBG:invalid operation!\n"); ++ retval = -EPERM; ++ break; ++ } ++ set_vol = kzalloc(sizeof(*set_vol), GFP_ATOMIC); ++ if (!set_vol) { ++ printk(KERN_DEBUG "SST DBG:mem allocation failed\n"); ++ retval = -ENOMEM; ++ break; ++ } ++ retval = copy_from_user(set_vol, rec_vol, sizeof(*set_vol)); ++ if (retval) { ++ printk(KERN_DEBUG "SST DBG:copy failed\n"); ++ retval = -EAGAIN; ++ break; ++ } ++ retval = sst_set_vol(set_vol); ++ kfree(set_vol); ++ break; ++ } ++ case _IOC_NR(SNDRV_SST_GET_VOL): { ++ struct snd_sst_vol *rec_vol = (struct snd_sst_vol *)arg; ++ struct snd_sst_vol get_vol; ++ printk(KERN_DEBUG "SST DBG:IOCTL_GET_VOLUME recieved for stream = %d!\n", ++ rec_vol->stream_id); ++ if (minor == STREAM_MODULE && rec_vol->stream_id == 0) { ++ printk(KERN_DEBUG "SST DBG:invalid operation!\n"); ++ retval = -EPERM; ++ break; ++ } ++ get_vol.stream_id = rec_vol->stream_id; ++ retval = sst_get_vol(&get_vol); ++ if (retval) { ++ printk(KERN_ERR ++ "SST ERR: Get volume failed = %d\n", retval); ++ retval = -EIO; ++ break; ++ } ++ printk(KERN_DEBUG "SST DBG:id = %d\n, vol = %d, ramp_dur = %d, ramp_type=%d\n", ++ get_vol.stream_id, get_vol.volume, ++ get_vol.ramp_duration, get_vol.ramp_type); ++ retval = copy_to_user((struct snd_sst_vol *)arg, ++ &get_vol, sizeof(get_vol)); ++ if (retval) { ++ printk(KERN_ERR ++ "SST ERR: copy to user failed %d\n", retval); ++ retval = -EIO; ++ break; ++ } ++ /*sst_print_get_vol_info(str_id, &get_vol);*/ ++ break; ++ } ++ ++ case _IOC_NR(SNDRV_SST_MUTE): { ++ struct snd_sst_mute *set_mute; ++ struct snd_sst_vol *rec_mute = (struct snd_sst_vol *)arg; ++ printk(KERN_DEBUG "SST DBG:SNDRV_SST_SET_VOLUME recieved for %d!\n", ++ rec_mute->stream_id); ++ if (minor == STREAM_MODULE && rec_mute->stream_id == 0) { ++ printk(KERN_DEBUG "SST DBG:invalid operation!\n"); ++ retval = -EPERM; ++ break; ++ } ++ set_mute = kzalloc(sizeof(*set_mute), GFP_ATOMIC); ++ if (!set_mute) { ++ printk(KERN_DEBUG "SST DBG:mem allocation failed\n"); ++ retval = -ENOMEM; ++ break; ++ } ++ retval = copy_from_user(set_mute, rec_mute, sizeof(*set_mute)); ++ if (retval) { ++ printk(KERN_DEBUG "SST DBG:copy failed\n"); ++ retval = -EAGAIN; ++ break; ++ } ++ retval = sst_set_mute(set_mute); ++ kfree(set_mute); ++ break; ++ } ++ case _IOC_NR(SNDRV_SST_STREAM_GET_PARAMS): { ++ struct snd_sst_get_stream_params get_params; ++ ++ printk(KERN_DEBUG "SST DBG:IOCTL_GET_PARAMS recieved!\n"); ++ if (minor != 0) { ++ printk(KERN_ERR ++ "SST ERR: called for AM handle minor %d\n", minor); ++ retval = -EINVAL; ++ break; ++ } ++ ++ retval = sst_get_stream_params(str_id, &get_params); ++ if (retval) { ++ printk(KERN_ERR ++ "SST ERR: Get params failed = %d\n", retval); ++ retval = -EIO; ++ break; ++ } ++ retval = copy_to_user((struct snd_sst_get_stream_params *)arg, ++ &get_params, sizeof(get_params)); ++ if (retval) { ++ printk(KERN_ERR ++ "SST ERR: copy to user failed %d\n" , retval); ++ retval = -EIO; ++ break; ++ } ++ sst_print_stream_params(&get_params); ++ break; ++ } ++ ++ case _IOC_NR(SNDRV_SST_MMAP_PLAY): ++ case _IOC_NR(SNDRV_SST_MMAP_CAPTURE): ++ printk(KERN_DEBUG "SST DBG:SNDRV_SST_MMAP_PLAY/CAPTURE recieved!\n"); ++ if (minor != STREAM_MODULE) { ++ printk(KERN_ERR ++ "SST ERR: called for AM handle minor %d\n" , minor); ++ retval = -EINVAL; ++ break; ++ } ++ retval = intel_sst_mmap_play_capture(str_id, ++ (struct snd_sst_mmap_buffs *)arg); ++ break; ++ ++ case _IOC_NR(SNDRV_SST_STREAM_DROP): ++ printk(KERN_DEBUG "SST DBG:SNDRV_SST_IOCTL_DROP recieved!\n"); ++ if (minor != STREAM_MODULE) { ++ 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, freq, mod; ++ ++ printk(KERN_DEBUG "SST DBG:SNDRV_SST_STREAM_GET_TSTAMP recieved!\n"); ++ if (minor != STREAM_MODULE) { ++ printk(KERN_ERR ++ "SST ERR: called for AM handle minor %d\n", minor); ++ retval = -EINVAL; ++ break; ++ } ++ memcpy_fromio(&tstamp, ++ ((void *)(sst_drv_ctx->mailbox + SST_TIME_STAMP) ++ +(str_id * sizeof(tstamp))), ++ sizeof(tstamp)); ++ time = tstamp.samples_rendered; ++ printk(KERN_DEBUG "SST DBG:samples rendered! = 0x%llx\n", time); ++ freq = (unsigned long long) tstamp.sampling_frequency; ++ printk(KERN_DEBUG "SST DBG:freq = %llx\n", freq); ++ time = time * 1000; /* converting it to ms */ ++ mod = do_div(time, freq); ++ printk(KERN_DEBUG "SST DBG:mod = 0x%llx\n", mod); ++ printk(KERN_DEBUG "SST DBG:msec = 0x%llx\n", time); ++ retval = copy_to_user(ms, &time, sizeof(*ms)); ++ if (retval) ++ printk(KERN_ERR ++ "SST ERR: copy failed = %d\n", retval); ++ break; ++ } ++ ++ case _IOC_NR(SNDRV_SST_STREAM_START):{ ++ struct stream_info *stream; ++ ++ printk(KERN_DEBUG "SST DBG:SNDRV_SST_STREAM_START recieved!\n"); ++ if (minor != STREAM_MODULE) { ++ printk(KERN_ERR ++ "SST ERR: called for AM handle minor %d\n", minor); ++ retval = -EINVAL; ++ break; ++ } ++ retval = sst_validate_strid(str_id); ++ if (retval) ++ break; ++ stream = &sst_drv_ctx->streams[str_id]; ++ mutex_lock(&stream->lock); ++ if (stream->status == STREAM_INIT && ++ stream->need_draining != true) { ++ printk(KERN_DEBUG "SST DBG:calling play frames...\n"); ++ stream->prev = stream->status; ++ stream->status = STREAM_RUNNING; ++ if (stream->ops == STREAM_OPS_PLAYBACK || ++ stream->ops == STREAM_OPS_PLAYBACK_DRM) { ++ retval = sst_play_frame(str_id); ++ /*sst_ospm_send_event( ++ OSPM_EVENT_SUBSYS_START_PLAY);*/ ++ } else if (stream->ops == STREAM_OPS_CAPTURE) ++ retval = sst_capture_frame(str_id); ++ else { ++ printk(KERN_ERR ++ "SST ERR: Invalid ops 0x%x\n" , stream->ops); ++ retval = -EINVAL; ++ mutex_unlock( ++ &sst_drv_ctx->streams[str_id].lock); ++ break; ++ } ++ if (retval < 0) { ++ printk(KERN_ERR ++ "SST ERR: play/cptur frame fail \n"); ++ stream->status = STREAM_INIT; ++ mutex_unlock( ++ &sst_drv_ctx->streams[str_id].lock); ++ break; ++ } ++ } else { ++ printk(KERN_ERR ++ "SST ERR: Inv strt for stream%d state0x%x\n", \ ++ str_id, stream->status); ++ retval = -EINVAL; ++ } ++ mutex_unlock(&sst_drv_ctx->streams[str_id].lock); ++ break; ++ } ++ ++ case _IOC_NR(SNDRV_SST_SET_TARGET_DEVICE): { ++ struct snd_sst_target_device *target_device; ++ ++ printk(KERN_DEBUG "SST DBG:SNDRV_SST_SET_TARGET_PLAYBACK DEVICE recieved!\n"); ++ target_device = (struct snd_sst_target_device *)arg; ++ BUG_ON(!target_device); ++ if (minor != AM_MODULE) { ++ printk(KERN_ERR ++ "SST ERR: called for non AM handle minor %d\n", minor); ++ retval = -EINVAL; ++ break; ++ } ++ retval = sst_target_device_select(target_device); ++ break; ++ } ++ ++ case _IOC_NR(SNDRV_SST_DRIVER_INFO): { ++ struct snd_sst_driver_info *info = ++ (struct snd_sst_driver_info *)arg; ++ ++ printk(KERN_DEBUG "SST DBG:SNDRV_SST_DRIVER_INFO recived \n"); ++ info->version = SST_VERSION_NUM; ++ /* hard coding, shud get sumhow later */ ++ info->active_pcm_streams = sst_drv_ctx->stream_cnt - ++ sst_drv_ctx->encoded_cnt; ++ info->active_enc_streams = sst_drv_ctx->encoded_cnt; ++ info->max_pcm_streams = MAX_ACTIVE_STREAM - MAX_ENC_STREAM; ++ info->max_enc_streams = MAX_ENC_STREAM; ++ info->buf_per_stream = sst_drv_ctx->mmap_len; ++ break; ++ } ++ ++ case _IOC_NR(SNDRV_SST_STREAM_DECODE): { ++ struct snd_sst_dbufs *param = ++ (struct snd_sst_dbufs *)arg, dbufs_local; ++ int i; ++ struct snd_sst_buffs ibufs, obufs; ++ struct snd_sst_buff_entry ibuf_temp[param->ibufs->entries], ++ obuf_temp[param->obufs->entries]; ++ ++ printk(KERN_DEBUG "SST DBG:SNDRV_SST_STREAM_DECODE recived \n"); ++ if (minor != STREAM_MODULE) { ++ printk(KERN_ERR ++ "SST ERR: called for AM handle minor %d\n", minor); ++ retval = -EINVAL; ++ break; ++ } ++ if (!param) { ++ printk(KERN_ERR "SST ERR: null param passed\n"); ++ retval = -EINVAL; ++ break; ++ } ++ ++ dbufs_local.input_bytes_consumed = param->input_bytes_consumed; ++ dbufs_local.output_bytes_produced = ++ param->output_bytes_produced; ++ dbufs_local.ibufs = &ibufs; ++ dbufs_local.obufs = &obufs; ++ dbufs_local.ibufs->entries = param->ibufs->entries; ++ dbufs_local.ibufs->type = param->ibufs->type; ++ dbufs_local.obufs->entries = param->obufs->entries; ++ dbufs_local.obufs->type = param->obufs->type; ++ ++ dbufs_local.ibufs->buff_entry = ibuf_temp; ++ for (i = 0; i < dbufs_local.ibufs->entries; i++) { ++ ibuf_temp[i].buffer = ++ param->ibufs->buff_entry[i].buffer; ++ ibuf_temp[i].size = ++ param->ibufs->buff_entry[i].size; ++ } ++ dbufs_local.obufs->buff_entry = obuf_temp; ++ for (i = 0; i < dbufs_local.obufs->entries; i++) { ++ obuf_temp[i].buffer = ++ param->obufs->buff_entry[i].buffer; ++ obuf_temp[i].size = ++ param->obufs->buff_entry[i].size; ++ } ++ retval = sst_decode(str_id, &dbufs_local); ++ if (retval) { ++ printk(KERN_ERR"SST ERR: decoding failed \n"); ++ retval = -EAGAIN; ++ } ++ retval = copy_to_user(¶m->input_bytes_consumed, ++ &dbufs_local.input_bytes_consumed, ++ sizeof(unsigned long long)); ++ if (retval) { ++ printk(KERN_ERR"SST ERR: copy to user failed \n"); ++ retval = -EAGAIN; ++ break; ++ } ++ retval = copy_to_user(¶m->output_bytes_produced, ++ &dbufs_local.output_bytes_produced, ++ sizeof(unsigned long long)); ++ if (retval) { ++ printk(KERN_ERR"SST ERR: copy to user failed \n"); ++ retval = -EAGAIN; ++ break; ++ } ++ printk(KERN_DEBUG "SST DBG:input_bytes_consumed=%lld\n", ++ param->input_bytes_consumed); ++ printk(KERN_DEBUG "SST DBG:output_bytes_produced=%lld\n", ++ param->output_bytes_produced); ++ printk(KERN_DEBUG "SST DBG:ibufs->entries=%d\n", param->ibufs->entries); ++ printk(KERN_DEBUG "SST DBG:input_consumed = %lld, output_produced = %lld \n", ++ param->input_bytes_consumed, ++ param->output_bytes_produced); ++ printk(KERN_DEBUG "SST DBG:first ibufs size=%d\n", ++ param->ibufs->buff_entry[0].size); ++ printk(KERN_DEBUG "SST DBG:first ibufs addr=%p\n", ++ param->ibufs->buff_entry[0].buffer); ++ printk(KERN_DEBUG "SST DBG:obufs->entries=%d\n", param->obufs->entries); ++ printk(KERN_DEBUG "SST DBG:first obufs size=%d\n", ++ param->obufs->buff_entry[0].size); ++ printk(KERN_DEBUG "SST DBG:first obufs addr=%p\n", ++ param->obufs->buff_entry[0].buffer); ++ break; ++ } ++ ++ case _IOC_NR(SNDRV_SST_STREAM_DRAIN): ++ printk(KERN_DEBUG "SST DBG:SNDRV_SST_STREAM_DRAIN recived \n"); ++ if (minor != STREAM_MODULE) { ++ printk(KERN_ERR ++ "SST ERR: caled for AM handle minr %d\n", minor); ++ retval = -EINVAL; ++ break; ++ } ++ retval = sst_drain_stream(str_id); ++ break; ++ ++ case _IOC_NR(SNDRV_SST_STREAM_BYTES_DECODED): { ++ unsigned long long *bytes = (unsigned long long *)arg; ++ struct snd_sst_tstamp tstamp = {0}; ++ ++ printk(KERN_DEBUG "SST DBG:SNDRV_SST_STREAM_BYTES_DECODED recieved!\n"); ++ if (minor != STREAM_MODULE) { ++ printk(KERN_ERR ++ "SST ERR: caled for AM hndle minr %d\n", minor); ++ retval = -EINVAL; ++ break; ++ } ++ memcpy_fromio(&tstamp, ++ ((void *)(sst_drv_ctx->mailbox + SST_TIME_STAMP) ++ +(str_id * sizeof(tstamp))), ++ sizeof(tstamp)); ++ retval = copy_to_user(bytes, &tstamp.bytes_processed, ++ sizeof(*bytes)); ++ printk(KERN_DEBUG "SST DBG:bytes processed =%lld\n", tstamp.bytes_processed); ++ if (retval) ++ printk(KERN_ERR ++ "SST ERR: copy failed = %d\n", retval); ++ break; ++ } ++ case _IOC_NR(SNDRV_SST_FW_INFO): { ++ struct snd_sst_fw_info *fw_info; ++ ++ printk(KERN_DEBUG "SST DBG:SNDRV_SST_FW_INFO recived \n"); ++ ++ fw_info = kzalloc(sizeof(*fw_info), GFP_ATOMIC); ++ if (!fw_info) { ++ printk(KERN_ERR "SST ERR: mem alocation fail\n"); ++ retval = -ENOMEM; ++ break; ++ } ++ retval = sst_get_fw_info(fw_info); ++ if (retval) { ++ printk(KERN_ERR ++ "SST ERR: sst_get_fw_info fail = %d\n", retval); ++ kfree(fw_info); ++ break; ++ } ++ retval = copy_to_user((struct snd_sst_dbufs *)arg, ++ fw_info, sizeof(*fw_info)); ++ if (retval) { ++ printk(KERN_ERR ++ "SST ERR: copy to user failed %d\n", retval); ++ kfree(fw_info); ++ retval = -EIO; ++ break; ++ } ++ sst_print_fw_info(fw_info); ++ kfree(fw_info); ++ break; ++ } ++ default: ++ printk(KERN_DEBUG "SST DBG:IOCTL not supported yet !\n"); ++ retval = -ENOTTY; ++ } ++ printk(KERN_DEBUG "SST DBG:...complete ret code = %d\n", retval); ++ ++ return retval; ++} ++ ++/* ++ Intelmid driver interface Routines ++*/ ++ ++void sst_process_mad_ops(struct work_struct *work) ++{ ++ struct mad_ops_wq *mad_ops = ++ container_of(work, struct mad_ops_wq, wq); ++ int retval = 0; ++ struct stream_info *stream; ++ ++ switch (mad_ops->control_op) { ++ case SST_SND_PAUSE: ++ retval = sst_pause_stream(mad_ops->stream_id); ++ break; ++ case SST_SND_RESUME: ++ retval = sst_resume_stream(mad_ops->stream_id); ++ break; ++ case SST_SND_DROP: ++ retval = sst_drop_stream(mad_ops->stream_id); ++ break; ++ case SST_SND_STREAM_PROCESS: ++ printk(KERN_DEBUG "SST DBG:play/capt frames...\n"); ++ stream = &sst_drv_ctx->streams[mad_ops->stream_id]; ++ if (stream->status == STREAM_UN_INIT) ++ return; ++ stream->prev = stream->status; ++ stream->status = STREAM_RUNNING; ++ stream->data_blk.on = false; ++ if (stream->ops == STREAM_OPS_PLAYBACK) ++ retval = sst_play_frame(mad_ops->stream_id); ++ else if (stream->ops == STREAM_OPS_CAPTURE) ++ retval = sst_capture_frame(mad_ops->stream_id); ++ else ++ printk(KERN_ERR ++ "SST ERR: invalid stream ops invoked \n"); ++ if (retval < 0) ++ printk(KERN_ERR ++ "SST ERR: play/captur frames failed \n"); ++ break; ++ default: ++ printk(KERN_ERR ++ "SST ERR: wrong control_ops reported\n"); ++ } ++ return; ++} ++/** ++* 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, status; ++ struct stream_info *stream; ++ ++ if (sst_drv_ctx->sst_state == SST_UN_INIT) { ++ /* FW is not downloaded */ ++ printk(KERN_DEBUG "SST DBG:DSP Downloading FW now...\n"); ++ retval = sst_download_fw(); ++ if (retval) { ++ printk(KERN_ERR ++ "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; ++ int pcm_id = sst_assign_pvt_id(sst_drv_ctx); ++ struct stream_info *str_info; ++ ++ str_param = (struct snd_sst_params *)value; ++ BUG_ON(!str_param); ++ sst_print_params(str_param); ++ retval = sst_get_stream(str_param, pcm_id); ++ if (retval >= 0) ++ sst_drv_ctx->stream_cnt++; ++ /*if (str_param->ops == STREAM_OPS_PLAYBACK || ++ str_param->ops == STREAM_OPS_PLAYBACK_DRM) ++ sst_ospm_send_event(OSPM_EVENT_SUBSYS_START_PLAY);*/ ++ str_info = &sst_drv_ctx->streams[retval]; ++ str_info->src = MAD_DRV; ++ break; ++ } ++ ++ case SST_SND_PAUSE: ++ case SST_SND_RESUME: ++ case SST_SND_DROP: ++ sst_drv_ctx->mad_ops.control_op = control_element; ++ sst_drv_ctx->mad_ops.stream_id = *(int *)value; ++ queue_work(sst_drv_ctx->mad_wq, &sst_drv_ctx->mad_ops.wq); ++ break; ++ ++ case SST_SND_FREE: ++ str_id = *(int *)value; ++ stream = &sst_drv_ctx->streams[str_id]; ++ free_stream_context(str_id); ++ stream->pcm_substream = NULL; ++ stream->period_elapsed = NULL; ++ sst_drv_ctx->stream_cnt--; ++ break; ++ ++ case SST_SND_STREAM_INIT: { ++ struct pcm_stream_info *str_info; ++ struct stream_info *stream; ++ ++ printk(KERN_DEBUG "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) ++ break; ++ ++ stream = &sst_drv_ctx->streams[str_id]; ++ printk(KERN_DEBUG "SST DBG:setting the period ptrs\n"); ++ stream->pcm_substream = str_info->mad_substream; ++ stream->period_elapsed = str_info->period_elapsed; ++ stream->sfreq = str_info->sfreq; ++ stream->prev = stream->status; ++ stream->status = STREAM_INIT; ++ break; ++ } ++ ++ case SST_SND_BUFFER_POINTER: { ++ struct pcm_stream_info *stream_info; ++ struct snd_sst_tstamp fw_tstamp = {0,}; ++ struct stream_info *stream; ++ ++ // printk(KERN_DEBUG "SST DBG:buffer pointer query\n"); ++ ++ stream_info = (struct pcm_stream_info *)value; ++ str_id = stream_info->str_id; ++ retval = sst_validate_strid(str_id); ++ if (retval) ++ break; ++ stream = &sst_drv_ctx->streams[str_id]; ++ ++ if (!stream->pcm_substream) ++ break; ++ memcpy_fromio(&fw_tstamp, ++ ((void *)(sst_drv_ctx->mailbox + SST_TIME_STAMP) ++ +(str_id * sizeof(fw_tstamp))), ++ sizeof(fw_tstamp)); ++ ++ // printk(KERN_DEBUG "SST DBG:strid = %d\n", str_id); ++ ++ if (stream->ops == STREAM_OPS_PLAYBACK) ++ stream_info->buffer_ptr = fw_tstamp.samples_rendered; ++ else ++ stream_info->buffer_ptr = fw_tstamp.samples_processed; ++ /* printk(KERN_DEBUG "SST DBG:samples played = %lld\n", ++ stream_info->buffer_ptr); ++ */ ++ break; ++ } ++ case SST_ENABLE_RX_TIME_SLOT: { ++ status = *(int *)value; ++ sst_drv_ctx->rx_time_slot_status = status ; ++ printk(KERN_DEBUG "SST DBG:in case:: **********SST_ENABLE_RX_TIME_SLOT*********** \n"); ++ sst_enable_rx_timeslot(status); ++ break; ++ } ++ default: ++ /* Illegal case */ ++ printk(KERN_ERR"SST ERR: illegal req\n"); ++ return -EINVAL; ++ } ++// printk(KERN_DEBUG "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, *_sst_buf; ++ struct stream_info *stream; ++ ++ if (!mad_buf || !mad_buf->addr || !mad_buf->length) { ++ printk(KERN_ERR ++ "SST ERR: Null Ptr or buf size = 0\n"); ++ return -EINVAL; ++ } ++ ++ if (sst_drv_ctx->sst_state != SST_FW_RUNNING) { ++ printk(KERN_ERR ++ "SST ERR: SST Not runng: %d\n", sst_drv_ctx->sst_state); ++ return -EBUSY; ++ } ++ ++ retval = sst_validate_strid(str_id); ++ if (retval < 0) ++ return -EINVAL; ++ ++ stream = &sst_drv_ctx->streams[str_id]; ++ printk(KERN_DEBUG "SST DBG:stream status = %d strid=%d\n", stream->status, str_id); ++ printk(KERN_DEBUG "SST DBG:stream codec = %d, prevstate=%d\n", ++ stream->codec, stream->prev); ++ if (stream->status == STREAM_UN_INIT) { ++ printk(KERN_ERR"SST ERR: BAD REQUEST!\n"); ++ return -EBADRQC; ++ } ++ printk(KERN_DEBUG "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_safe(sst_buf, _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; ++ printk(KERN_DEBUG "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) ++ return -ENOMEM; ++ sst_buf->size = mad_buf->length; ++ sst_buf->addr = (void *)mad_buf->addr; ++ sst_buf->offset = 0; ++ sst_buf->in_use = false; ++ /*adding without locking FIXME*/ ++ if( in_interrupt()) { ++ list_add_tail(&sst_buf->node, &stream->bufs); ++ } else { ++ spin_lock(&stream->pcm_lock); ++ list_add_tail(&sst_buf->node, &stream->bufs); ++ spin_unlock(&stream->pcm_lock); ++ } ++ ++ ++ flag_add = true; ++ printk(KERN_DEBUG "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_drv_ctx->mad_ops.control_op = SST_SND_STREAM_PROCESS; ++ sst_drv_ctx->mad_ops.stream_id = str_id; ++ queue_work(sst_drv_ctx->mad_wq, &sst_drv_ctx->mad_ops.wq); ++ } ++ ++ 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 (!card || !card->module_name) { ++ printk(KERN_ERR "SST ERR: Null Pointer Passed\n"); ++ return -EINVAL; ++ } ++ ++ if (sst_drv_ctx->pmic_state == SND_MAD_UN_INIT) { ++ /* register this driver */ ++ if ((strncmp(SST_CARD_NAMES, card->module_name, ++ strlen(SST_CARD_NAMES))) == 0) { ++ sst_drv_ctx->pmic_vendor = card->vendor_id; ++ sst_drv_ctx->scard_ops = card->scard_ops; ++ sst_pmic_ops.module_name = card->module_name; ++ sst_drv_ctx->pmic_state = SND_MAD_INIT_DONE; ++ sst_drv_ctx->rx_time_slot_status = RX_TIMESLOT_UNINIT; ++ card->control_set = sst_pmic_ops.control_set; ++ card->send_buffer = sst_pmic_ops.send_buffer; ++ sst_drv_ctx->scard_ops->card_status = SND_CARD_UN_INIT; ++ /* initialize card to know good state */ ++ /*sst_drv_ctx->scard_ops->init_card();*/ ++ return 0; ++ } else { ++ printk(KERN_ERR ++ "SST ERR: strcmp failed %s \n", card->module_name); ++ return -EINVAL; ++ } ++ ++ } else { ++ /* already registered a driver */ ++ printk(KERN_ERR ++ "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_drv_ctx->pmic_state = SND_MAD_UN_INIT; ++ printk(KERN_DEBUG "SST DBG:Unregistered %s\n", card->module_name); ++ } ++ return; ++} ++EXPORT_SYMBOL_GPL(unregister_sst_card); ++ ++/** ++* lpe_mask_periphral_intr- function to mask SST DSP peripheral interrupt ++* @device: device interrupt that needs masking ++*/ ++int lpe_mask_periphral_intr(enum lpe_periphral device) ++{ ++ union sst_pimr_reg pimr = {{0},}; ++ if (!sst_drv_ctx) ++ return -EIO; ++ ++ pimr.full = readl(sst_drv_ctx->shim + SST_PIMR); ++ ++ switch (device) { ++ case LPE_DMA: ++ pimr.part.dmac_sc = 1; ++ /* dummy register for shim workaround */ ++ writel(pimr.full, sst_drv_ctx->shim + SST_ISRD); ++ writel(pimr.full, sst_drv_ctx->shim + SST_PIMR); ++ break; ++ ++ case LPE_SSP0: ++ break; ++ ++ case LPE_SSP1: ++ break; ++ ++ default: ++ break; ++ } ++ return 0; ++} ++EXPORT_SYMBOL_GPL(lpe_mask_periphral_intr); ++ ++/** ++* lpe_unmask_periphral_intr- function to unmask SST DSP peripheral interrupt ++* @device: device interrupt that needs unmasking ++*/ ++int lpe_unmask_periphral_intr(enum lpe_periphral device) ++{ ++ union sst_pimr_reg pimr = {{0},}; ++ if (!sst_drv_ctx) ++ return -EIO; ++ ++ pimr.full = readl(sst_drv_ctx->shim + SST_PIMR); ++ ++ switch (device) { ++ case LPE_DMA: ++ pimr.part.dmac_sc = 0; ++ /* dummy register for shim workaround */ ++ writel(pimr.full, sst_drv_ctx->shim + SST_ISRD); ++ writel(pimr.full, sst_drv_ctx->shim + SST_PIMR); ++ break; ++ ++ case LPE_SSP0: ++ break; ++ ++ case LPE_SSP1: ++ break; ++ ++ default: ++ break; ++ } ++ return 0; ++ ++} ++EXPORT_SYMBOL_GPL(lpe_unmask_periphral_intr); ++ ++/** ++* lpe_periphral_intr_status- function returns SST peripheral interrupt status ++* @device: device for which the status is enquired ++* @status: out parameters with the status of the peripheral device ++*/ ++int lpe_periphral_intr_status(enum lpe_periphral device, int *status) ++{ ++ union sst_pisr_reg pisr = {{0},}; ++ if (!sst_drv_ctx) ++ return -EIO; ++ ++ pisr.full = readl(sst_drv_ctx->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.6.2.2 + -- cgit v1.2.3