diff options
author | Joshua Lock <josh@linux.intel.com> | 2010-05-18 14:51:13 +0100 |
---|---|---|
committer | Joshua Lock <josh@linux.intel.com> | 2010-05-19 12:20:16 +0100 |
commit | 5e8c7c54a9b297dae0081dd19a7bb94e23040a3d (patch) | |
tree | 948e3642c1bf426870b83c72c68c997dce66766c /meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-audio-driver-6.0-4-8.patch | |
parent | 5e07bc91281969d54896dd0a13e3d6134e432027 (diff) | |
download | openembedded-core-5e8c7c54a9b297dae0081dd19a7bb94e23040a3d.tar.gz openembedded-core-5e8c7c54a9b297dae0081dd19a7bb94e23040a3d.tar.bz2 openembedded-core-5e8c7c54a9b297dae0081dd19a7bb94e23040a3d.tar.xz openembedded-core-5e8c7c54a9b297dae0081dd19a7bb94e23040a3d.zip |
linux-moblin: add 2.6.33.2 kernel from MeeGo 1.0
Signed-off-by: Joshua Lock <josh@linux.intel.com>
Diffstat (limited to 'meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-audio-driver-6.0-4-8.patch')
-rw-r--r-- | meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-audio-driver-6.0-4-8.patch | 1285 |
1 files changed, 1285 insertions, 0 deletions
diff --git a/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-audio-driver-6.0-4-8.patch b/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-audio-driver-6.0-4-8.patch new file mode 100644 index 000000000..da2912b4e --- /dev/null +++ b/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-audio-driver-6.0-4-8.patch @@ -0,0 +1,1285 @@ +From 395150e235d193ad9c9e5071d4752e8f436db99c Mon Sep 17 00:00:00 2001 +From: R, Dharageswari <dharageswari.r@intel.com> +Date: Thu, 29 Apr 2010 20:25:00 +0530 +Subject: [PATCH] ADR-Post-Beta-0.05.002.03-4/8-Adding Moorestown Audio Drivers: SST IPC modules + +This adds the IPC module which uses Inter process mechanism to communicate +between driver & SST engine. The SST engine is a DSP processor. +To communicate between IA processor and DSP, IPC doorbell registers are used. +A write to these registers triggers an interrupt to other side. +The format of messages and "mailbox" for message payload is defined +in intel_sst_fw_ipc.h + +Signed-off-by: Vinod Koul <vinod.koul@intel.com> + + new file: sound/pci/sst/intel_sst_fw_ipc.h + new file: sound/pci/sst/intel_sst_ipc.c +Patch-mainline: 2.6.35? +--- + sound/pci/sst/intel_sst_fw_ipc.h | 403 ++++++++++++++++++ + sound/pci/sst/intel_sst_ipc.c | 843 ++++++++++++++++++++++++++++++++++++++ + 2 files changed, 1246 insertions(+), 0 deletions(-) + create mode 100644 sound/pci/sst/intel_sst_fw_ipc.h + create mode 100644 sound/pci/sst/intel_sst_ipc.c + +diff --git a/sound/pci/sst/intel_sst_fw_ipc.h b/sound/pci/sst/intel_sst_fw_ipc.h +new file mode 100644 +index 0000000..f2fad9c +--- /dev/null ++++ b/sound/pci/sst/intel_sst_fw_ipc.h +@@ -0,0 +1,403 @@ ++#ifndef __INTEL_SST_FW_IPC_H__ ++#define __INTEL_SST_FW_IPC_H__ ++/* ++* intel_sst_fw_ipc.h - Intel SST Driver for audio engine ++* ++* Copyright (C) 2008-10 Intel Corporation ++* Author: Vinod Koul <vinod.koul@intel.com> ++* Harsha Priya <priya.harsha@intel.com> ++* Dharageswari R <dharageswari.r@intel.com> ++* KP Jeeja <jeeja.kp@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 has definitions shared between the firmware and driver ++*/ ++ ++#define MAX_NUM_STREAMS 4 ++#define MAX_DBG_RW_BYTES 80 ++#define MAX_NUM_SCATTER_BUFFERS 8 ++#define MAX_LOOP_BACK_DWORDS 8 ++/* IPC base address and mailbox, timestamp offsets */ ++#define SST_MAILBOX_SIZE 0x0400 ++#define SST_MAILBOX_SEND 0x0000 ++#define SST_MAILBOX_RCV 0x0804 ++#define SST_TIME_STAMP 0x1800 ++#define SST_RESERVED_OFFSET 0x1840 ++#define SST_CHEKPOINT_OFFSET 0x1C00 ++#define REPLY_MSG 0x80 ++ ++/* Message ID's for IPC messages */ ++/* Bits B7: SST or IA/SC ; B6-B4: Msg Category; B3-B0: Msg Type */ ++ ++/* I2L Firmware/Codec Download msgs */ ++#define IPC_IA_PREP_LIB_DNLD 0x01 ++#define IPC_IA_LIB_DNLD_CMPLT 0x02 ++ ++#define IPC_IA_SET_PMIC_TYPE 0x03 ++#define IPC_IA_GET_FW_VERSION 0x04 ++#define IPC_IA_GET_FW_BUILD_INF 0x05 ++#define IPC_IA_GET_FW_INFO 0x06 ++ ++/* I2L Codec Config/control msgs */ ++#define IPC_IA_SET_CODEC_PARAMS 0x10 ++#define IPC_IA_GET_CODEC_PARAMS 0x11 ++#define IPC_IA_SET_PPP_PARAMS 0x12 ++#define IPC_IA_GET_PPP_PARAMS 0x13 ++#define IPC_IA_PLAY_FRAMES 0x14 ++#define IPC_IA_CAPT_FRAMES 0x15 ++#define IPC_IA_PLAY_VOICE 0x16 ++#define IPC_IA_CAPT_VOICE 0x17 ++#define IPC_IA_DECODE_FRAMES 0x18 ++ ++/* I2L Stream config/control msgs */ ++#define IPC_IA_ALLOC_STREAM 0x20 /* Allocate a stream ID */ ++#define IPC_IA_FREE_STREAM 0x21 /* Free the stream ID */ ++#define IPC_IA_SET_STREAM_PARAMS 0x22 ++#define IPC_IA_GET_STREAM_PARAMS 0x23 ++#define IPC_IA_PAUSE_STREAM 0x24 ++#define IPC_IA_RESUME_STREAM 0x25 ++#define IPC_IA_DROP_STREAM 0x26 ++#define IPC_IA_DRAIN_STREAM 0x27 /* Short msg with str_id */ ++#define IPC_IA_TARGET_DEV_SELECT 0x28 ++#define IPC_IA_CONTROL_ROUTING 0x29 ++ ++#define IPC_IA_SET_STREAM_VOL 0x2A /*Vol for stream, pre mixer */ ++#define IPC_IA_GET_STREAM_VOL 0x2B ++#define IPC_IA_SET_STREAM_MUTE 0x2C ++#define IPC_IA_GET_STREAM_MUTE 0x2D ++#define IPC_IA_SET_MASTER_VOL 0x2E /* set vol for post mixer */ ++#define IPC_IA_GET_MASTER_VOL 0x2F /* Get Volume for post mixer */ ++#define IPC_IA_SET_MASTER_MUTE 0x30 /* Set Master Mute post mixer */ ++#define IPC_IA_GET_MASTER_MUTE 0x31 /* Get Master Mute; post mixer */ ++ ++/* Debug msgs */ ++#define IPC_IA_DBG_MEM_READ 0x40 ++#define IPC_IA_DBG_MEM_WRITE 0x41 ++#define IPC_IA_DBG_LOOP_BACK 0x42 ++ ++/* L2I Firmware/Codec Download msgs */ ++#define IPC_IA_FW_INIT_CMPLT 0x81 ++#define IPC_IA_LPE_GETTING_STALLED 0x82 ++#define IPC_IA_LPE_UNSTALLED 0x83 ++ ++/* L2I Codec Config/control msgs */ ++#define IPC_SST_GET_PLAY_FRAMES 0x90 /* Request IA more data */ ++#define IPC_SST_GET_CAPT_FRAMES 0x91 /* Request IA more data */ ++#define IPC_SST_BUF_UNDER_RUN 0x92 /* PB Under run and stopped */ ++#define IPC_SST_BUF_OVER_RUN 0x93 /* CAP Under run and stopped */ ++#define IPC_SST_DRAIN_END 0x94 /* PB Drain complete and stopped */ ++#define IPC_SST_CHNGE_SSP_PARAMS 0x95 /* PB SSP parameters changed */ ++#define IPC_SST_STREAM_PROCESS_FATAL_ERR 0x96/* error in processing a stream */ ++#define IPC_SST_PERIOD_ELAPSED 0x97 /* period elapsed */ ++#define IPC_IA_TARGET_DEV_CHNGD 0x98 /* error in processing a stream */ ++ ++/* L2S messages */ ++#define IPC_SC_DDR_LINK_UP 0xC0 ++#define IPC_SC_DDR_LINK_DOWN 0xC1 ++ ++/* L2I Error reporting msgs */ ++#define IPC_IA_MEM_ALLOC_FAIL 0xE0 ++#define IPC_IA_PROC_ERR 0xE1 /* error in processing a ++ stream can be used by playback and ++ capture modules */ ++ ++/* L2I Debug msgs */ ++#define IPC_IA_PRINT_STRING 0xF0 ++ ++#define IPC_IA_ENABLE_RX_TIME_SLOT 0x2E /* Enable Rx time slot 0 or 1 */ ++ ++ ++/* Command Response or Acknowledge message to any IPC message will have ++ * same message ID and stream ID information which is sent. ++ * There is no specific Ack message ID. The data field is used as response ++ * meaning. ++ */ ++enum ackData { ++ IPC_ACK_SUCCESS = 0, ++ IPC_ACK_FAILURE ++}; ++ ++ ++enum sst_error_codes { ++ /* Error code,response to msgId: Description */ ++ /* Common error codes */ ++ SST_SUCCESS = 0, /* Success */ ++ SST_ERR_INVALID_STREAM_ID, /* Invalid stream ID */ ++ SST_ERR_INVALID_MSG_ID, /* Invalid message ID */ ++ SST_ERR_INVALID_STREAM_OP, /* Invalid stream operation request */ ++ SST_ERR_INVALID_PARAMS, /* Invalid params */ ++ SST_ERR_INVALID_CODEC, /* Invalid codec type */ ++ SST_ERR_INVALID_MEDIA_TYPE, /* Invalid media type */ ++ SST_ERR_STREAM_ERR, /* ANY: Stream control or config or ++ processing error */ ++ ++ /* IPC specific error codes */ ++ SST_IPC_ERR_CALL_BACK_NOT_REGD, /* Call back for msg not regd */ ++ SST_IPC_ERR_STREAM_NOT_ALLOCATED, /* Stream is not allocated */ ++ SST_IPC_ERR_STREAM_ALLOC_FAILED, /* ALLOC:Stream alloc failed */ ++ SST_IPC_ERR_GET_STREAM_FAILED, /* ALLOC:Get stream id failed*/ ++ SST_ERR_MOD_NOT_AVAIL, /* SET/GET: Mod(AEC/AGC/ALC) not available */ ++ SST_ERR_MOD_DNLD_RQD, /* SET/GET: Mod(AEC/AGC/ALC) download required */ ++ SST_ERR_STREAM_STOPPED, /* ANY: Stream is in stopped state */ ++ SST_ERR_STREAM_IN_USE, /* ANY: Stream is already in use */ ++ ++ /* Capture specific error codes */ ++ SST_CAP_ERR_INCMPLTE_CAPTURE_MSG,/* ANY:Incomplete message */ ++ SST_CAP_ERR_CAPTURE_FAIL, /* ANY:Capture op failed */ ++ SST_CAP_ERR_GET_DDR_NEW_SGLIST, ++ SST_CAP_ERR_UNDER_RUN, /* lack of input data */ ++ SST_CAP_ERR_OVERFLOW, /* lack of output space */ ++ ++ /* Playback specific error codes*/ ++ SST_PB_ERR_INCMPLTE_PLAY_MSG, /* ANY: Incomplete message */ ++ SST_PB_ERR_PLAY_FAIL, /* ANY: Playback operation failed */ ++ SST_PB_ERR_GET_DDR_NEW_SGLIST, ++ ++ /* Codec manager specific error codes */ ++ SST_LIB_ERR_LIB_DNLD_REQUIRED, /* ALLOC: Codec download required */ ++ SST_LIB_ERR_LIB_NOT_SUPPORTED, /* Library is not supported */ ++ ++ /* Library manager specific error codes */ ++ SST_SCC_ERR_PREP_DNLD_FAILED, /* Failed to prepare for codec download */ ++ SST_SCC_ERR_LIB_DNLD_RES_FAILED, /* Lib download resume failed */ ++ /* Scheduler specific error codes */ ++ SST_SCH_ERR_FAIL, /* REPORT: */ ++ ++ /* DMA specific error codes */ ++ SST_DMA_ERR_NO_CHNL_AVAILABLE, /* DMA Ch not available */ ++ SST_DMA_ERR_INVALID_INPUT_PARAMS, /* Invalid input params */ ++ SST_DMA_ERR_CHNL_ALREADY_SUSPENDED, /* Ch is suspended */ ++ SST_DMA_ERR_CHNL_ALREADY_STARTED, /* Ch already started */ ++ SST_DMA_ERR_CHNL_NOT_ENABLED, /* Ch not enabled */ ++ SST_DMA_ERR_TRANSFER_FAILED, /* Transfer failed */ ++ SST_SSP_ERR_ALREADY_ENABLED, /* REPORT: SSP already enabled */ ++ SST_SSP_ERR_ALREADY_DISABLED, /* REPORT: SSP already disabled */ ++ SST_SSP_ERR_NOT_INITIALIZED, ++ ++ /* Other error codes */ ++ SST_ERR_MOD_INIT_FAIL, /* Firmware Module init failed */ ++ ++ /* FW init error codes */ ++ SST_RDR_ERR_IO_DEV_SEL_NOT_ALLOWED, ++ SST_RDR_ERR_ROUTE_ALREADY_STARTED, ++ SST_RDR_PREP_CODEC_DNLD_FAILED, ++ ++ /* Memory debug error codes */ ++ SST_ERR_DBG_MEM_READ_FAIL, ++ SST_ERR_DBG_MEM_WRITE_FAIL, ++ ++ /* Decode error codes */ ++ SST_ERR_DEC_NEED_INPUT_BUF, ++ ++}; ++ ++enum dbg_mem_data_type { ++ /* Data type of debug read/write */ ++ DATA_TYPE_U32, ++ DATA_TYPE_U16, ++ DATA_TYPE_U8, ++}; ++ ++/* CAUTION NOTE: All IPC message body must be multiple of 32 bits.*/ ++ ++/* IPC Header */ ++union ipc_header { ++ struct { ++ u32 msg_id:8; /* Message ID - Max 256 Message Types */ ++ u32 str_id:3; /* Undefined for SC communication */ ++ u32 large:1; /* Large Message if large = 1 */ ++ u32 reserved:4;/* Reserved for future use */ ++ u32 data:14; /* Ack/Info for msg, size of msg in Mailbox */ ++ u32 done:1; /* bit 30 */ ++ u32 busy:1; /* bit 31 */ ++ } part; ++ u32 full; ++} __attribute__ ((packed)); ++ ++struct ipc_header_fw_init { ++ struct snd_sst_fw_version fw_version;/* Firmware version details */ ++ u16 result; /* Fw init result */ ++ u8 module_id; /* Module ID in case of error */ ++ u8 debug_info; /* Debug info from Module ID in case of fail */ ++} __attribute__ ((packed)); ++ ++/* Firmware build info */ ++struct sst_fw_build_info { ++ unsigned char date[16]; /* Firmware build date */ ++ unsigned char time[16]; /* Firmware build time */ ++} __attribute__ ((packed)); ++ ++/* Address and size info of a frame buffer in DDR */ ++struct sst_address_info { ++ u32 addr; /* Address at IA */ ++ u32 size; /* Size of the buffer */ ++} __attribute__ ((packed)); ++ ++/* Time stamp */ ++struct snd_sst_tstamp { ++ u64 samples_processed; /* capture - data in DDR */ ++ u64 samples_rendered; /* playback - data rendered */ ++ u64 bytes_processed; /* bytes decoded or encoded */ ++ u32 sampling_frequency; /* eg: 48000, 44100 */ ++ ++}; ++ ++/* Frame info to play or capture */ ++struct sst_frame_info { ++ u16 num_entries; /* number of entries to follow */ ++ u16 rsrvd; ++ struct sst_address_info addr[MAX_NUM_SCATTER_BUFFERS]; ++} __attribute__ ((packed)); ++ ++/* Frames info for decode */ ++struct snd_sst_decode_info { ++ unsigned long long input_bytes_consumed; ++ unsigned long long output_bytes_produced; ++ struct sst_frame_info frames_in; ++ struct sst_frame_info frames_out; ++} __attribute__ ((packed)); ++/* SST to IA print debug message*/ ++struct ipc_sst_ia_print_params { ++ u32 string_size; /* Max value is 160 */ ++ u8 prt_string[160]; /* Null terminated Char string */ ++} __attribute__ ((packed)); ++/* Voice data message */ ++struct snd_sst_voice_data { ++ u16 num_bytes; /* Number of valid voice data bytes */ ++ u8 pcm_wd_size; /* 0=8 bit, 1=16 bit 2=32 bit */ ++ u8 reserved; /* Reserved */ ++ u8 voice_data_buf[0]; /* Voice data buffer in bytes, little endian */ ++} __attribute__ ((packed)); ++ ++/* SST to IA memory read debug message */ ++struct ipc_sst_ia_dbg_mem_rw { ++ u16 num_bytes; /* Maximum of MAX_DBG_RW_BYTES */ ++ u16 data_type; /* enum: dbg_mem_data_type */ ++ u32 address; /* Memory address of data memory of data_type */ ++ u8 rw_bytes[MAX_DBG_RW_BYTES];/* Maximum of 64 bytes can be RW */ ++} __attribute__ ((packed)); ++ ++struct ipc_sst_ia_dbg_loop_back { ++ u16 num_dwords; /* Maximum of MAX_DBG_RW_BYTES */ ++ u16 increment_val;/* Increments dwords by this value, 0- no increment */ ++ u32 lpbk_dwords[MAX_LOOP_BACK_DWORDS];/* Maximum of 8 dwords loopback */ ++} __attribute__ ((packed)); ++ ++/* Stream type params struture for Alloc stream */ ++struct snd_sst_str_type { ++ u8 codec_type; /* Codec type */ ++ u8 str_type; /* 1 = voice 2 = music */ ++ u8 operation; /* Playback or Capture */ ++ u8 protected_str; /* 0=Non DRM, 1=DRM */ ++ u8 pvt_id; /* Driver Private ID */ ++ u8 reserved; /* Reserved */ ++ u16 result; /* Result used for acknowledgment */ ++} __attribute__ ((packed)); ++ ++/* Library info structure */ ++struct module_info { ++ u32 lib_version; ++ u32 lib_type;/*TBD- KLOCKWORK u8 lib_type;*/ ++ u32 media_type; ++ u8 lib_name[12]; ++ u32 lib_caps; ++ unsigned char b_date[16]; /* Lib build date */ ++ unsigned char b_time[16]; /* Lib build time */ ++} __attribute__ ((packed)); ++ ++/* Library slot info */ ++struct lib_slot_info { ++ u8 slot_num; /* 1 or 2 */ ++ u8 reserved1; ++ u16 reserved2; ++ u32 iram_size; /* slot size in IRAM */ ++ u32 dram_size; /* slot size in DRAM */ ++ u32 iram_offset; /* starting offset of slot in IRAM */ ++ u32 dram_offset; /* starting offset of slot in DRAM */ ++} __attribute__ ((packed)); ++ ++struct snd_sst_lib_download { ++ struct module_info lib_info; /* library info type, capabilities etc */ ++ struct lib_slot_info slot_info; /* slot info to be downloaded */ ++ u32 mod_entry_pt; ++}; ++ ++struct snd_sst_lib_download_info { ++ struct snd_sst_lib_download dload_lib; ++ u16 result; /* Result used for acknowledgment */ ++ u8 pvt_id; /* Private ID */ ++ u8 reserved; /* for alignment */ ++}; ++ ++/* Alloc stream params structure */ ++struct snd_sst_alloc_params { ++ struct snd_sst_str_type str_type; ++ struct snd_sst_stream_params stream_params; ++}; ++ ++struct snd_sst_fw_get_stream_params { ++ struct snd_sst_stream_params codec_params; ++ struct snd_sst_pmic_config pcm_params; ++}; ++ ++/* Alloc stream response message */ ++struct snd_sst_alloc_response { ++ struct snd_sst_str_type str_type; /* Stream type for allocation */ ++ struct snd_sst_lib_download lib_dnld; /* Valid only for codec dnld */ ++}; ++ ++/* Drop response */ ++struct snd_sst_drop_response { ++ u32 result; ++ u32 bytes; ++}; ++ ++/* CSV Voice call routing structure */ ++struct snd_sst_control_routing { ++ u8 control; /* 0=start, 1=Stop */ ++ u8 reserved[3]; /* Reserved- for 32 bit alignment */ ++}; ++ ++ ++ ++/* struct ipc_msg_body { ++ union { ++ CODEC_PARAM_STRUCTURES; ++ PPP_PARAM_STRUCTURES; ++ struct snd_sst_alloc_params alloc_params; ++ struct snd_sst_alloc_response alloc_response; ++ struct snd_sst_stream_params stream_params; ++ struct sst_frame_info frames_info; ++ struct ipc_sst_ia_print_params print_params; ++ struct ipc_sst_ia_dbg_mem_rw dbg_mem_rw; ++ struct ipc_sst_ia_dbg_loop_back loop_back; ++ struct pmic_pcm_params ssp_params; ++ } u; ++};*/ ++ ++ ++ ++struct ipc_post { ++ struct list_head node; ++ union ipc_header header; /* driver specific */ ++ char *mailbox_data; ++}; ++ ++#endif /* __INTEL_SST_FW_IPC_H__ */ +diff --git a/sound/pci/sst/intel_sst_ipc.c b/sound/pci/sst/intel_sst_ipc.c +new file mode 100644 +index 0000000..710cf8f +--- /dev/null ++++ b/sound/pci/sst/intel_sst_ipc.c +@@ -0,0 +1,843 @@ ++/* ++ * intel_sst_ipc.c - Intel SST Driver for audio engine ++ * ++ * Copyright (C) 2008-10 Intel Corporation ++ * Authors: Vinod Koul <vinod.koul@intel.com> ++ * Harsha Priya <priya.harsha@intel.com> ++ * Dharageswari R <dharageswari.r@intel.com> ++ * KP Jeeja <jeeja.kp@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 ipc functions ++ */ ++ ++#include <linux/cdev.h> ++#include <linux/pci.h> ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/syscalls.h> ++#include <linux/file.h> ++#include <linux/interrupt.h> ++#include <linux/list.h> ++#include <linux/workqueue.h> ++#include <linux/mutex.h> ++#include <linux/firmware.h> ++#include <sound/intel_lpe.h> ++#include <sound/intel_sst_ioctl.h> ++#include "intel_sst_fw_ipc.h" ++#include "intel_sst_common.h" ++ ++/** ++* Debug function to test basic IPC between driver and SST firmware ++*/ ++static void sst_send_loop_test(int loop_no) ++{ ++ struct ipc_post *msg = NULL; ++ struct ipc_sst_ia_dbg_loop_back loop_msg; ++ static int large_num; ++ ++ printk(KERN_DEBUG "SST DBG:Loop testing %d \n", loop_no); ++ ++ if (large_num >= 4) { ++ printk(KERN_DEBUG "SST DBG:Loop testing complete.....\n"); ++ return; ++ } ++ if (loop_no >= 4) { ++ /* large loop */ ++ large_num++; ++ printk(KERN_DEBUG "SST DBG:Large msg \n"); ++ if (sst_create_large_msg(&msg)) ++ return; ++ ++ loop_msg.increment_val = 1; ++ loop_msg.lpbk_dwords[0] = LOOP1; ++ loop_msg.lpbk_dwords[1] = LOOP2; ++ loop_msg.lpbk_dwords[2] = LOOP3; ++ loop_msg.lpbk_dwords[3] = LOOP4; ++ loop_msg.num_dwords = 4; ++ sst_fill_header(&msg->header, IPC_IA_DBG_LOOP_BACK, 1, loop_no); ++ msg->header.part.data = sizeof(u32) + sizeof(loop_msg); ++ memcpy(msg->mailbox_data, &msg->header, sizeof(u32)); ++ memcpy(msg->mailbox_data + sizeof(u32), ++ &loop_msg, sizeof(loop_msg)); ++ } else { ++ /* short loop */ ++ printk(KERN_DEBUG "SST DBG:Loop Short msg \n"); ++ if (sst_create_short_msg(&msg)) ++ return; ++ sst_fill_header(&msg->header, IPC_IA_DBG_LOOP_BACK, 0, loop_no); ++ } ++ mutex_lock(&sst_drv_ctx->list_lock); ++ list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); ++ mutex_unlock(&sst_drv_ctx->list_lock); ++ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); ++ return; ++} ++ ++/** ++* this function sends the sound card type to sst dsp engine ++*/ ++static void sst_send_sound_card_type(void) ++{ ++ struct ipc_post *msg = NULL; ++ ++ printk(KERN_DEBUG "SST DBG:...called\n"); ++ ++ if (sst_create_short_msg(&msg)) ++ return; ++ ++ sst_fill_header(&msg->header, IPC_IA_SET_PMIC_TYPE, 0, 0); ++ msg->header.part.data = sst_drv_ctx->pmic_vendor; ++ mutex_lock(&sst_drv_ctx->list_lock); ++ list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); ++ mutex_unlock(&sst_drv_ctx->list_lock); ++ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); ++ return; ++} ++ ++/** ++* sst_post_message - Posts message to SST ++* @work: Pointer to work structure ++* ++* This function is called by any component in driver which ++* wants to send an IPC message. This will post message only if ++* busy bit is free ++*/ ++void sst_post_message(struct work_struct *work) ++{ ++ struct ipc_post *msg; ++ union ipc_header header; ++ union interrupt_reg imr; ++ int retval = 0; ++ imr.full = 0; ++ ++ /*To check if LPE is in stalled state.*/ ++ retval = sst_stalled(); ++ if (retval < 0) { ++ printk(KERN_ERR "SST ERR: SST is in stalled state \n"); ++ return; ++ } ++ printk(KERN_DEBUG "SST DBG:..called \n"); ++ mutex_lock(&sst_drv_ctx->list_lock); ++ ++ /* check list */ ++ if (list_empty(&sst_drv_ctx->ipc_dispatch_list)) { ++ /* list is empty, mask imr */ ++ printk(KERN_DEBUG "SST DBG: Empty msg queue... masking \n"); ++ imr.full = readl(sst_drv_ctx->shim + SST_IMRX); ++ if( imr.part.done_interrupt == 0) { ++ imr.part.done_interrupt = 1; ++ /* dummy register for shim workaround */ ++ writel(imr.full, sst_drv_ctx->shim + SST_ISRD); ++ writel(imr.full, sst_drv_ctx->shim + SST_IMRX); ++ } ++ mutex_unlock(&sst_drv_ctx->list_lock); ++ return; ++ } ++ ++ /* check busy bit */ ++ header.full = readl(sst_drv_ctx->shim + SST_IPCX); ++ if (header.part.busy) { ++ /* busy, unmask */ ++ printk(KERN_DEBUG "SST DBG:Busy not free... unmasking\n"); ++ imr.full = readl(sst_drv_ctx->shim + SST_IMRX); ++ imr.part.done_interrupt = 0; ++ /* dummy register for shim workaround */ ++ writel(imr.full, sst_drv_ctx->shim + SST_ISRD); ++ writel(imr.full, sst_drv_ctx->shim + SST_IMRX); ++ mutex_unlock(&sst_drv_ctx->list_lock); ++ return; ++ } ++ /* copy msg from list */ ++ msg = list_entry(sst_drv_ctx->ipc_dispatch_list.next, ++ struct ipc_post, node); ++ list_del(&msg->node); ++ printk(KERN_DEBUG "SST DBG:Post message: \ ++ header = %x\n", msg->header.full); ++ printk(KERN_DEBUG "SST DBG:size: = %x\n", msg->header.part.data); ++ if (msg->header.part.large) ++ memcpy_toio(sst_drv_ctx->mailbox + SST_MAILBOX_SEND, ++ msg->mailbox_data, msg->header.part.data); ++ /* dummy register for shim workaround */ ++ writel(msg->header.full, sst_drv_ctx->shim + SST_ISRD); ++ writel(msg->header.full, sst_drv_ctx->shim + SST_IPCX); ++ mutex_unlock(&sst_drv_ctx->list_lock); ++ ++ kfree(msg->mailbox_data); ++ kfree(msg); ++ printk(KERN_DEBUG "SST DBG:...done\n"); ++ return; ++} ++ ++/** ++* this function clears the interrupt register after the interrupt ++* bottom half is complete allowing next interrupt to arrive ++*/ ++void sst_clear_interrupt(void) ++{ ++ union interrupt_reg isr; ++ union interrupt_reg imr; ++ union ipc_header clear_ipc; ++ ++// printk(KERN_DEBUG "SST DBG:sst clearing interrupt \n"); ++ imr.full = readl(sst_drv_ctx->shim + SST_IMRX); ++ isr.full = readl(sst_drv_ctx->shim + SST_ISRX); ++ /* write 1 to clear */; ++ isr.part.busy_interrupt = 1; ++ /* dummy register for shim workaround */ ++ writel(isr.full, sst_drv_ctx->shim + SST_ISRD); ++ writel(isr.full, sst_drv_ctx->shim + SST_ISRX); ++ /* Set IA done bit */ ++ clear_ipc.full = readl(sst_drv_ctx->shim + SST_IPCD); ++ clear_ipc.part.busy = 0; ++ clear_ipc.part.done = 1; ++ clear_ipc.part.data = IPC_ACK_SUCCESS; ++ /* dummy register for shim workaround */ ++ writel(clear_ipc.full, sst_drv_ctx->shim + SST_ISRD); ++ writel(clear_ipc.full, sst_drv_ctx->shim + SST_IPCD); ++ /* un mask busy interrupt */ ++ imr.part.busy_interrupt = 0; ++ /* dummy register for shim workaround */ ++ writel(imr.full, sst_drv_ctx->shim + SST_ISRD); ++ writel(imr.full, sst_drv_ctx->shim + SST_IMRX); ++} ++ ++/** ++* sst_process_message - Processes message from SST ++* @work: Pointer to work structure ++* ++* This function is scheduled by ISR ++* It take a msg from process_queue and does action based on msg ++*/ ++void sst_process_message(struct work_struct *work) ++{ ++ struct sst_ipc_msg_wq *msg = ++ container_of(work, struct sst_ipc_msg_wq, wq); ++ int str_id = msg->header.part.str_id; ++ struct stream_info *stream ; ++ ++ printk(KERN_DEBUG "SST DBG:called \n"); ++ ++ /* based on msg in list call respective handler */ ++ switch (msg->header.part.msg_id) { ++ case IPC_SST_BUF_UNDER_RUN: ++ case IPC_SST_BUF_OVER_RUN: ++ if (sst_validate_strid(str_id)) { ++ printk(KERN_ERR ++ "SST ERR: stream id %d invalid\n", str_id); ++ break; ++ } ++ printk(KERN_ERR ++ "SST ERR: Buffer under/overrun for %d\n",\ ++ msg->header.part.str_id); ++ printk(KERN_DEBUG "SST DBG:Got Underrun & not to send data...ignore\n"); ++ break; ++ ++ case IPC_SST_GET_PLAY_FRAMES: ++ { ++ struct stream_info *stream ; ++ ++ if (sst_validate_strid(str_id)) { ++ printk(KERN_ERR ++ "SST ERR: stream id %d invalid\n", str_id); ++ break; ++ } ++ /* call sst_play_frame */ ++ stream = &sst_drv_ctx->streams[str_id]; ++ printk(KERN_DEBUG "SST DBG:sst_play_frames for %d\n", \ ++ msg->header.part.str_id); ++ mutex_lock(&sst_drv_ctx->streams[str_id].lock); ++ sst_play_frame(msg->header.part.str_id); ++ mutex_unlock(&sst_drv_ctx->streams[str_id].lock); ++ break; ++ } ++ ++ case IPC_SST_PERIOD_ELAPSED: ++ { ++ struct snd_sst_tstamp fw_tstamp = {0,}; ++ if (sst_validate_strid(str_id)) { ++ printk(KERN_ERR ++ "SST ERR: stream id %d invalid\n", str_id); ++ break; ++ } ++ stream = &sst_drv_ctx->streams[str_id]; ++ ++ printk(KERN_DEBUG "SST DBG:Period elapsed \n"); ++ 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:samples \ ++ played = %lld\n", fw_tstamp.samples_processed); ++ printk(KERN_DEBUG "SST DBG:diff in \ ++ mesg = %d\n", msg->header.part.data); ++ sst_clear_interrupt(); ++ if (stream->period_elapsed) ++ stream->period_elapsed(stream->pcm_substream); ++ return; ++ } ++ ++ case IPC_SST_GET_CAPT_FRAMES: ++ /* call sst_capture_frame */ ++ if (sst_validate_strid(str_id)) { ++ printk(KERN_ERR ++ "SST ERR: stream id %d invalid\n", str_id); ++ break; ++ } ++ stream = &sst_drv_ctx->streams[str_id]; ++ printk(KERN_DEBUG "SST DBG:sst_capture_frames \ ++ for %d\n", msg->header.part.str_id); ++ mutex_lock(&stream->lock); ++ if (stream->mmapped == false && stream->src == SST_DRV) { ++ printk(KERN_DEBUG "SST DBG:waking up block for copy...\n"); ++ stream->data_blk.ret_code = 0; ++ stream->data_blk.condition = true; ++ stream->data_blk.on = false; ++ wake_up(&sst_drv_ctx->wait_queue); ++ } else ++ sst_capture_frame(msg->header.part.str_id); ++ mutex_unlock(&stream->lock); ++ break; ++ ++ case IPC_IA_PRINT_STRING: ++ printk(KERN_DEBUG "SST DBG:been asked to print something by fw\n"); ++ /* TBD */ ++ break; ++ ++ case IPC_IA_FW_INIT_CMPLT: { ++ /* send next data to FW */ ++ struct ipc_header_fw_init *init = ++ (struct ipc_header_fw_init *)msg->mailbox; ++ int major = init->fw_version.major; ++ int minor = init->fw_version.minor; ++ int build = init->fw_version.build; ++ ++ printk(KERN_DEBUG "SST DBG:*** FW Init msg came*** \n"); ++ if (!init->result) { ++ sst_drv_ctx->sst_state = SST_FW_RUNNING; ++ printk(KERN_DEBUG "SST DBG:FW Version %x.%x \n", ++ init->fw_version.major, init->fw_version.minor); ++ printk(KERN_DEBUG "SST DBG:Build No %x Type %x \n", ++ init->fw_version.build, init->fw_version.type); ++#ifdef SND_LOOP_TEST ++ sst_send_loop_test(0); ++#endif ++ sst_send_sound_card_type(); ++ ++ pr_info( ++ "INFO: ***SST FW VERSION*** +\ ++ = %02d.%02d.%02d\n", \ ++ major, \ ++ minor, build); ++ ++ printk(KERN_DEBUG "SST DBG:Time slot Status %d\n", sst_drv_ctx->rx_time_slot_status); ++ if((sst_drv_ctx->rx_time_slot_status != RX_TIMESLOT_UNINIT) && (sst_drv_ctx->sst_state == SST_FW_RUNNING)) ++ sst_enable_rx_timeslot(sst_drv_ctx->rx_time_slot_status); ++ ++ } else { ++ sst_drv_ctx->sst_state = SST_ERROR; ++ printk(KERN_DEBUG "SST DBG:FW Init \ ++ failed, Error %x\n", init->result); ++ printk(KERN_DEBUG "SST DBG:FW Init failed, Module %x, Debug Info %x \n", ++ init->module_id, init->debug_info); ++ } ++ printk(KERN_DEBUG "SST DBG:Waking up... open\n"); ++ sst_wake_up_alloc_block(sst_drv_ctx, FW_DWNL_ID, 0, NULL); ++ break; ++ } ++ ++ case IPC_SST_STREAM_PROCESS_FATAL_ERR: ++ if (sst_validate_strid(str_id)) { ++ printk(KERN_ERR ++ "SST ERR: stream id %d invalid\n", str_id); ++ break; ++ } ++ printk(KERN_ERR ++ "SST ERR: codec fatal error %x for +\ ++ stream %d... \n",\ ++ msg->header.full, \ ++ msg->header.part.str_id); ++ printk(KERN_ERR ++ "SST ERR: Dropping the stream \n"); ++ sst_drop_stream(msg->header.part.str_id); ++ break; ++ case IPC_IA_LPE_GETTING_STALLED: ++ sst_drv_ctx->lpe_stalled = 1; ++ break; ++ case IPC_IA_LPE_UNSTALLED: ++ sst_drv_ctx->lpe_stalled = 0; ++ break; ++ default: ++ /* Illegal case */ ++ printk(KERN_ERR ++ "SST ERR: Unhandled case msg_id %x +\ ++ message %x\n",\ ++ msg->header.part.msg_id, msg->header.full); ++ } ++ sst_clear_interrupt(); ++ return; ++} ++ ++/** ++* sst_process_reply - Processes reply message from SST ++* @work: Pointer to work structure ++* ++* This function is scheduled by ISR ++* It take a reply msg from response_queue and ++* does action based on msg ++*/ ++void sst_process_reply(struct work_struct *work) ++{ ++ struct sst_ipc_msg_wq *msg = ++ container_of(work, struct sst_ipc_msg_wq, wq); ++ ++ int str_id = msg->header.part.str_id; ++ struct stream_info *str_info; ++ switch (msg->header.part.msg_id) { ++ case IPC_IA_TARGET_DEV_SELECT: { ++ if (!msg->header.part.data) { ++ sst_drv_ctx->tgt_dev_blk.ret_code = 0; ++ } else { ++ printk(KERN_ERR ++ "SST ERR: Msg %x reply +\ ++ error %x \n",\ ++ msg->header.part.msg_id, msg->header.part.data); ++ sst_drv_ctx->tgt_dev_blk.ret_code = ++ -msg->header.part.data; ++ } ++ ++ if (sst_drv_ctx->tgt_dev_blk.on == true) { ++ sst_drv_ctx->tgt_dev_blk.condition = true; ++ wake_up(&sst_drv_ctx->wait_queue); ++ } ++ break; ++ } ++ case IPC_IA_GET_FW_INFO: { ++ struct snd_sst_fw_info *fw_info = ++ (struct snd_sst_fw_info *)msg->mailbox; ++ if (msg->header.part.large) { ++ int major = fw_info->fw_version.major; ++ int minor = fw_info->fw_version.minor; ++ int build = fw_info->fw_version.build; ++ printk(KERN_DEBUG "SST DBG:Msg \ ++ succedded %x \n", msg->header.part.msg_id); ++ dev_info(&sst_drv_ctx->pci->dev, \ ++ "INFO: ***FW VERSION*** +\ ++ = %02d.%02d.%02d\n", major, \ ++ minor, build); ++ ++ memcpy_fromio(sst_drv_ctx->fw_info_blk.data, ++ ((struct snd_sst_fw_info *)(msg->mailbox)), ++ sizeof(struct snd_sst_fw_info)); ++ sst_drv_ctx->fw_info_blk.ret_code = 0; ++ } else { ++ printk(KERN_ERR ++ "SST ERR: Msg %x reply +\ ++ error %x \n",\ ++ msg->header.part.msg_id, msg->header.part.data); ++ sst_drv_ctx->fw_info_blk.ret_code = ++ -msg->header.part.data; ++ } ++ if (sst_drv_ctx->fw_info_blk.on == true) { ++ printk(KERN_DEBUG "SST DBG:Memcopy succedded \n"); ++ sst_drv_ctx->fw_info_blk.on = false; ++ sst_drv_ctx->fw_info_blk.condition = true; ++ wake_up(&sst_drv_ctx->wait_queue); ++ } ++ break; ++ } ++ case IPC_IA_SET_STREAM_MUTE: { ++ if (!msg->header.part.data) { ++ printk(KERN_DEBUG "SST DBG:Msg \ ++ succedded %x \n", msg->header.part.msg_id); ++ sst_drv_ctx->mute_info_blk.ret_code = 0; ++ } else { ++ printk(KERN_ERR ++ "SST ERR: Msg %x reply +\ ++ error %x \n", \ ++ msg->header.part.msg_id, msg->header.part.data); ++ sst_drv_ctx->mute_info_blk.ret_code = ++ -msg->header.part.data; ++ ++ } ++ if (sst_drv_ctx->mute_info_blk.on == true) { ++ sst_drv_ctx->mute_info_blk.on = false; ++ sst_drv_ctx->mute_info_blk.condition = true; ++ wake_up(&sst_drv_ctx->wait_queue); ++ } ++ break; ++ } ++ case IPC_IA_SET_STREAM_VOL: { ++ if (!msg->header.part.data) { ++ printk(KERN_DEBUG "SST DBG:Msg \ ++ succedded %x \n", msg->header.part.msg_id); ++ sst_drv_ctx->vol_info_blk.ret_code = 0; ++ } else { ++ printk(KERN_ERR ++ "SST ERR: Msg %x reply +\ ++ error %x \n",\ ++ msg->header.part.msg_id, \ ++ msg->header.part.data); ++ sst_drv_ctx->vol_info_blk.ret_code = ++ -msg->header.part.data; ++ ++ } ++ ++ if (sst_drv_ctx->vol_info_blk.on == true) { ++ sst_drv_ctx->vol_info_blk.on = false; ++ sst_drv_ctx->vol_info_blk.condition = true; ++ wake_up(&sst_drv_ctx->wait_queue); ++ } ++ break; ++ } ++ case IPC_IA_GET_STREAM_VOL: ++ if (msg->header.part.large) { ++ printk(KERN_DEBUG "SST DBG:Large Msg Received Successfully\n"); ++ printk(KERN_DEBUG "SST DBG:Msg \ ++ succedded %x \n", msg->header.part.msg_id); ++ memcpy_fromio(sst_drv_ctx->vol_info_blk.data, ++ (void *) msg->mailbox, ++ sizeof(struct snd_sst_vol)); ++ sst_drv_ctx->vol_info_blk.ret_code = 0; ++ } else { ++ printk(KERN_ERR ++ "SST ERR: Msg %x +\ ++ reply error %x \n",\ ++ msg->header.part.msg_id, msg->header.part.data); ++ sst_drv_ctx->vol_info_blk.ret_code = ++ -msg->header.part.data; ++ } ++ if (sst_drv_ctx->vol_info_blk.on == true) { ++ sst_drv_ctx->vol_info_blk.on = false; ++ sst_drv_ctx->vol_info_blk.condition = true; ++ wake_up(&sst_drv_ctx->wait_queue); ++ } ++ break; ++ ++ case IPC_IA_GET_STREAM_PARAMS: ++ if (sst_validate_strid(str_id)) { ++ printk(KERN_ERR ++ "SST ERR: stream id %d invalid\n", str_id); ++ break; ++ } ++ str_info = &sst_drv_ctx->streams[str_id]; ++ if (msg->header.part.large) { ++ printk(KERN_DEBUG "SST DBG:The Large \ ++ message for get stream params\n"); ++ printk(KERN_DEBUG "SST DBG:Msg +\ ++ succedded %x \n", msg->header.part.msg_id); ++ memcpy_fromio(str_info->ctrl_blk.data, ++ ((void *)(msg->mailbox)), ++ sizeof(struct snd_sst_fw_get_stream_params)); ++ str_info->ctrl_blk.ret_code = 0; ++ } else { ++ printk(KERN_ERR ++ "SST ERR: The message for +\ ++ get params is not large\n"); ++ printk(KERN_ERR ++ "SST ERR: Msg %x reply error %x \n",\ ++ msg->header.part.msg_id, msg->header.part.data); ++ str_info->ctrl_blk.ret_code = ++ -msg->header.part.data; ++ } ++ if (str_info->ctrl_blk.on == true) { ++ str_info->ctrl_blk.on = false; ++ str_info->ctrl_blk.condition = true; ++ wake_up(&sst_drv_ctx->wait_queue); ++ } ++ break; ++ case IPC_IA_DECODE_FRAMES: ++ if (sst_validate_strid(str_id)) { ++ printk(KERN_ERR ++ "SST ERR: stream id %d invalid\n", str_id); ++ break; ++ } ++ str_info = &sst_drv_ctx->streams[str_id]; ++ if (msg->header.part.large) { ++ printk(KERN_DEBUG "SST DBG:Msg \ ++ succedded %x \n", msg->header.part.msg_id); ++ memcpy_fromio(str_info->data_blk.data, ++ ((void *)(msg->mailbox)), ++ sizeof(struct snd_sst_decode_info)); ++ str_info->data_blk.ret_code = 0; ++ } else { ++ printk(KERN_ERR ++ "SST ERR: Msg %x reply error %x \n",\ ++ msg->header.part.msg_id, msg->header.part.data); ++ str_info->data_blk.ret_code = ++ -msg->header.part.data; ++ } ++ if (str_info->data_blk.on == true) { ++ str_info->data_blk.on = false; ++ str_info->data_blk.condition = true; ++ wake_up(&sst_drv_ctx->wait_queue); ++ } ++ break; ++ case IPC_IA_DRAIN_STREAM: ++ if (sst_validate_strid(str_id)) { ++ printk(KERN_ERR ++ "SST ERR: stream id %d invalid\n", str_id); ++ break; ++ } ++ str_info = &sst_drv_ctx->streams[str_id]; ++ if (!msg->header.part.data) { ++ printk(KERN_DEBUG "SST DBG:Msg \ ++ succedded %x \n", msg->header.part.msg_id); ++ str_info->ctrl_blk.ret_code = 0; ++ ++ } else { ++ printk(KERN_ERR ++ "SST ERR: Msg %x reply error %x \n",\ ++ msg->header.part.msg_id, msg->header.part.data); ++ str_info->ctrl_blk.ret_code = -msg->header.part.data; ++ ++ } ++ str_info = &sst_drv_ctx->streams[str_id]; ++ if (str_info->data_blk.on == true) { ++ str_info->data_blk.on = false; ++ str_info->data_blk.condition = true; ++ wake_up(&sst_drv_ctx->wait_queue); ++ } ++ break; ++ ++ case IPC_IA_DROP_STREAM: ++ if (sst_validate_strid(str_id)) { ++ printk(KERN_ERR ++ "SST ERR: stream id %d invalid\n", str_id); ++ break; ++ } ++ str_info = &sst_drv_ctx->streams[str_id]; ++ if (msg->header.part.large) { ++ struct snd_sst_drop_response *drop_resp = ++ (struct snd_sst_drop_response *)msg->mailbox; ++ ++ printk(KERN_DEBUG "SST DBG:Drop returns with bytes 0x%x \n", ++ drop_resp->bytes); ++ ++ str_info->curr_bytes = drop_resp->bytes; ++ str_info->ctrl_blk.ret_code = 0; ++ } else { ++ printk(KERN_ERR ++ "SST ERR: Msg %x reply error %x \n", \ ++ msg->header.part.msg_id, msg->header.part.data); ++ str_info->ctrl_blk.ret_code = -msg->header.part.data; ++ } ++ if (str_info->ctrl_blk.on == true) { ++ str_info->ctrl_blk.on = false; ++ str_info->ctrl_blk.condition = true; ++ wake_up(&sst_drv_ctx->wait_queue); ++ } ++ break; ++ case IPC_IA_ENABLE_RX_TIME_SLOT: ++ if (!msg->header.part.data) { ++ printk(KERN_DEBUG "SST DBG:Msg \ ++ succedded IPC_IA_ENABLE_RX_TIME_SLOT %x \n", msg->header.part.msg_id); ++ sst_drv_ctx->hs_info_blk.ret_code = 0; ++ } else { ++ printk(KERN_ERR ++ "SST ERR: Msg %x +\ ++ reply error %x \n", msg->header.part.msg_id, \ ++ msg->header.part.data); ++ sst_drv_ctx->hs_info_blk.ret_code = -msg->header.part.data; ++ } ++ ++ ++ if (sst_drv_ctx->hs_info_blk.on == true) { ++ sst_drv_ctx->hs_info_blk.on = false; ++ sst_drv_ctx->hs_info_blk.condition = true; ++ wake_up(&sst_drv_ctx->wait_queue); ++ } ++ break; ++ case IPC_IA_PAUSE_STREAM: ++ case IPC_IA_RESUME_STREAM: ++ case IPC_IA_SET_STREAM_PARAMS: ++ str_info = &sst_drv_ctx->streams[str_id]; ++ if (!msg->header.part.data) { ++ printk(KERN_DEBUG "SST DBG:Msg \ ++ succedded %x \n", msg->header.part.msg_id); ++ str_info->ctrl_blk.ret_code = 0; ++ } else { ++ printk(KERN_ERR ++ "SST ERR: Msg %x +\ ++ reply error %x \n", msg->header.part.msg_id, \ ++ msg->header.part.data); ++ str_info->ctrl_blk.ret_code = -msg->header.part.data; ++ } ++ if (sst_validate_strid(str_id)) { ++ printk(KERN_ERR ++ "SST ERR: stream id %d +\ ++ invalid\n", str_id); ++ break; ++ } ++ ++ if (str_info->ctrl_blk.on == true) { ++ str_info->ctrl_blk.on = false; ++ str_info->ctrl_blk.condition = true; ++ wake_up(&sst_drv_ctx->wait_queue); ++ } ++ break; ++ ++ case IPC_IA_FREE_STREAM: ++ if (!msg->header.part.data) { ++ printk(KERN_DEBUG "SST DBG:Stream %d freed\n", str_id); ++ } else { ++ printk(KERN_ERR ++ "SST ERR: Free for %d +\ ++ returned error %x\n", str_id, msg->header.part.data); ++ } ++ break; ++ case IPC_IA_ALLOC_STREAM: { ++ /* map to stream, call play */ ++ struct snd_sst_alloc_response *resp = ++ (struct snd_sst_alloc_response *)msg->mailbox; ++ if (resp->str_type.result) { ++ /* error case */ ++ struct snd_sst_alloc_response *lib = NULL; ++ printk(KERN_ERR ++ "SST ERR: error +\ ++ alloc stream = %x \n", resp->str_type.result); ++ if (resp->str_type.result == ++ SST_LIB_ERR_LIB_DNLD_REQUIRED) { ++ lib = kzalloc(sizeof(*lib), GFP_ATOMIC); ++ if (!lib) { ++ printk(KERN_ERR ++ "SST ERR: +\ ++ mem allocation failed \n"); ++ break; ++ } ++ memcpy(lib, msg->mailbox, sizeof(*lib)); ++ /* library needs to be downloaded */ ++ printk(KERN_DEBUG "SST DBG:Codec Download required \n"); ++ } ++ sst_wake_up_alloc_block(sst_drv_ctx, ++ resp->str_type.pvt_id, ++ (-resp->str_type.result), lib); ++ break; ++ } ++ sst_alloc_stream_response(str_id, &resp->str_type); ++ break; ++ } ++ ++ case IPC_IA_DBG_LOOP_BACK: ++ /* Debug loop back msg */ ++ printk(KERN_DEBUG "SST DBG:Loop back came \n"); ++ if (msg->header.part.data) ++ printk(KERN_DEBUG "SST DBG:Possible error if not large \n"); ++ printk(KERN_DEBUG "SST DBG:Loop ID: %d\n", str_id); ++ if (msg->header.part.large) { ++ struct ipc_sst_ia_dbg_loop_back *loop_msg = ++ (struct ipc_sst_ia_dbg_loop_back *)msg->mailbox; ++ int i; ++ printk(KERN_DEBUG "SST DBG:Got large loop back: Words %d\n", ++ loop_msg->num_dwords); ++ for (i = 0; i < loop_msg->num_dwords; i++) { ++ printk(KERN_DEBUG "SST DBG:Loop \ ++ Word %d = %d \n", i, ++ loop_msg->lpbk_dwords[i]); ++ } ++ } ++ sst_send_loop_test((str_id + 1)); ++ break; ++ ++ case IPC_IA_PLAY_FRAMES: ++ case IPC_IA_CAPT_FRAMES: ++ if (sst_validate_strid(str_id)) { ++ printk(KERN_ERR ++ "SST ERR: stream id %d invalid\n" , str_id); ++ break; ++ } ++ printk(KERN_DEBUG "SST DBG:Ack for play/capt frames recived \n"); ++ break; ++ ++ case IPC_IA_PREP_LIB_DNLD: { ++ struct snd_sst_str_type *str_type = ++ (struct snd_sst_str_type *)msg->mailbox; ++ printk(KERN_DEBUG "SST DBG:Prep Lib \ ++ download %x\n", msg->header.part.msg_id); ++ if (str_type->result) { ++ printk(KERN_ERR ++ "SST ERR: Error in prep lib +\ ++ download 0x%x\n" ,\ ++ str_type->result); ++ } else ++ printk(KERN_DEBUG "SST DBG:Need to download codec now...\n"); ++ /* FIXME remove this workaround */ ++ str_type->result = 0; ++ sst_wake_up_alloc_block(sst_drv_ctx, str_type->pvt_id, ++ str_type->result, NULL); ++ break; ++ } ++ ++ case IPC_IA_LIB_DNLD_CMPLT: { ++ struct snd_sst_lib_download_info *resp = ++ (struct snd_sst_lib_download_info *)msg->mailbox; ++ int retval = resp->result; ++ ++ printk(KERN_DEBUG "SST DBG:Lib download \ ++ cmplt %x\n", msg->header.part.msg_id); ++ if (resp->result) { ++ printk(KERN_ERR ++ "SST ERR: Error in +\ ++ lib dload %x\n",\ ++ resp->result); ++ } else { ++ printk(KERN_DEBUG "SST DBG:Codec download complete...\n"); ++ printk(KERN_DEBUG "SST DBG:Downloaded codec Type %d Ver %d Built %s: %s\n", ++ resp->dload_lib.lib_info.lib_type, ++ resp->dload_lib.lib_info.lib_version, ++ resp->dload_lib.lib_info.b_date, ++ resp->dload_lib.lib_info.b_time); ++ } ++ sst_wake_up_alloc_block(sst_drv_ctx, resp->pvt_id, ++ retval, NULL); ++ break; ++ } ++ ++ case IPC_IA_GET_FW_VERSION: { ++ struct ipc_header_fw_init *version = ++ (struct ipc_header_fw_init *)msg->mailbox; ++ int major = version->fw_version.major; ++ int minor = version->fw_version.minor; ++ int build = version->fw_version.build; ++ dev_info(&sst_drv_ctx->pci->dev, \ ++ "INFO: ***LOADED SST FW +\ ++ VERSION*** = %02d.%02d.%02d\n",\ ++ major, minor, build); ++ break; ++ } ++ case IPC_IA_GET_FW_BUILD_INF: { ++ struct sst_fw_build_info *build = ++ (struct sst_fw_build_info *)msg->mailbox; ++ dev_info(&sst_drv_ctx->pci->dev, \ ++ "INFO: Build date %s +\ ++ Time %s",\ ++ build->date, build->time); ++ break; ++ } ++ case IPC_IA_SET_PMIC_TYPE: ++ break; ++ default: ++ /* Illegal case */ ++ printk(KERN_ERR ++ "SST ERR: process reply :default +\ ++ case = %x\n" , msg->header.full); ++ ++ } ++ sst_clear_interrupt(); ++ return; ++} +-- +1.6.2.2 + |