diff options
Diffstat (limited to 'meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-moorestown-audio-driver-6.0-2-8.patch')
-rw-r--r-- | meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-moorestown-audio-driver-6.0-2-8.patch | 900 |
1 files changed, 900 insertions, 0 deletions
diff --git a/meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-moorestown-audio-driver-6.0-2-8.patch b/meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-moorestown-audio-driver-6.0-2-8.patch new file mode 100644 index 000000000..cc3616f6a --- /dev/null +++ b/meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-moorestown-audio-driver-6.0-2-8.patch @@ -0,0 +1,900 @@ +From 4f7fcea7402d7d788fe959bc9b7ced86af72d806 Mon Sep 17 00:00:00 2001 +From: R, Dharageswari <dharageswari.r@intel.com> +Date: Thu, 29 Apr 2010 20:20:22 +0530 +Subject: [PATCH] ADR-Post-Beta-0.05.002.03-2/8-Adding Moorestown Audio Drivers: SST header files + +This patch adds the common header files. +intel_sst_common.h - This header files is private to SST driver and contain the +common structures like SST ops, SST register offsets, debugging macro, +sst stream definitions, and Shim register definitions. +intel_sst_pvt.c - Utility functions used by SST driver and function +prototypes of common functions are implemented in this file + +Signed-off-by: Vinod Koul <vinod.koul@intel.com> + + new file: sound/pci/sst/intel_sst_common.h + new file: sound/pci/sst/intel_sst_pvt.c +Patch-mainline: 2.6.35? +--- + sound/pci/sst/intel_sst_common.h | 538 ++++++++++++++++++++++++++++++++++++++ + sound/pci/sst/intel_sst_pvt.c | 323 +++++++++++++++++++++++ + 2 files changed, 861 insertions(+), 0 deletions(-) + create mode 100644 sound/pci/sst/intel_sst_common.h + create mode 100644 sound/pci/sst/intel_sst_pvt.c + +diff --git a/sound/pci/sst/intel_sst_common.h b/sound/pci/sst/intel_sst_common.h +new file mode 100644 +index 0000000..d9a720d +--- /dev/null ++++ b/sound/pci/sst/intel_sst_common.h +@@ -0,0 +1,538 @@ ++#ifndef __INTEL_SST_COMMON_H__ ++#define __INTEL_SST_COMMON_H__ ++/* ++ * intel_sst_common.h - 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. ++ * ++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ * ++ * Common private declarations for SST ++ */ ++#include <linux/time.h> ++#ifdef CONFIG_MSTWN_POWER_MGMT ++#include <linux/intel_mid.h> ++#endif ++/* #define SND_LOOP_TEST */ ++ ++#define SST_DRIVER_VERSION "0.05.002.03" ++#define SST_VERSION_NUM 0x050203 ++ ++/* driver names */ ++#define SST_DRV_NAME "intel_sst_driver" ++#define SST_FW_STD_FILENAME "fw_sst.bin" ++ ++ ++enum sst_states { ++ SST_FW_LOADED = 1, ++ SST_FW_RUNNING, ++ SST_UN_INIT, ++ SST_ERROR, ++}; ++ ++#define MAX_ACTIVE_STREAM 3 ++#define MAX_ENC_STREAM 1 ++#define MAX_AM_HANDLES 1 ++#define ALLOC_TIMEOUT 5000 ++/* SST numbers */ ++#define SST_BLOCK_TIMEOUT 5000 ++#define TARGET_DEV_BLOCK_TIMEOUT 5000 ++ ++/* FIXME */ ++#define INTEL_SST_MAJOR 255 ++#define BLOCK_UNINIT -1 ++#define RX_TIMESLOT_UNINIT -1 ++/* Chip revision ID */ ++ ++/* ++#define CHIP_A1_50 0x01 ++#define CHIP_A2_50 0x02 ++#define CHIP_A2_100 0x03 ++*/ ++ ++/* ++#define DSP_CLOCK_SPEED 100 */ /* 50: 50MHz, 100: 100MHz */ ++ ++/* SST register map */ ++#define SST_CSR 0x00 ++#define SST_PISR 0x08 ++#define SST_PIMR 0x10 ++#define SST_ISRX 0x18 ++#define SST_IMRX 0x28 ++#define SST_IPCX 0x38 /* IPC IA-SST */ ++#define SST_IPCD 0x40 /* IPC SST-IA */ ++#define SST_ISRD 0x20 /* dummy register for shim workaround */ ++#define SST_SHIM_SIZE 0X44 ++ ++#define SPI_MODE_ENABLE_BASE_ADDR 0xffae4000 ++#define FW_SIGNATURE_SIZE 4 ++ ++/* PMIC and SST hardware states */ ++enum sst_mad_states { ++ SND_MAD_UN_INIT = 0, ++ SND_MAD_INIT_DONE, ++}; ++ ++/* stream states */ ++enum sst_stream_states { ++ STREAM_UN_INIT = 0, /* Freed/Not used stream */ ++ STREAM_RUNNING = 1, /* Running */ ++ STREAM_PAUSED = 2, /* Paused stream */ ++ STREAM_DECODE = 4, /* stream is in decoding only state */ ++ STREAM_INIT = 5, /* stream init, waiting for data */ ++}; ++ ++ ++enum sst_ram_type{ ++ SST_IRAM = 1, ++ SST_DRAM = 2, ++}; ++/* SST shim registers to structure mapping */ ++union config_status_reg { ++ struct { ++ u32 rsvd0:1; ++ u32 sst_reset:1; ++ u32 hw_rsvd:3; ++ u32 sst_clk:2; ++ u32 bypass:3; ++ u32 run_stall:1; ++ u32 rsvd1:2; ++ u32 strb_cntr_rst:1; ++ u32 rsvd:18; ++ } part; ++ u32 full; ++}; ++ ++union interrupt_reg { ++ struct { ++ u32 done_interrupt:1; ++ u32 busy_interrupt:1; ++ u32 rsvd:30; ++ } part; ++ u32 full; ++}; ++ ++union sst_pisr_reg { ++ struct { ++ u32 pssp0:1; ++ u32 pssp1:1; ++ u32 rsvd0:3; ++ u32 dmac:1; ++ u32 rsvd1:26; ++ } part; ++ u32 full; ++}; ++ ++union sst_pimr_reg { ++ struct { ++ u32 ssp0:1; ++ u32 ssp1:1; ++ u32 rsvd0:3; ++ u32 dmac:1; ++ u32 rsvd1:10; ++ u32 ssp0_sc:1; ++ u32 ssp1_sc:1; ++ u32 rsvd2:3; ++ u32 dmac_sc:1; ++ u32 rsvd3:10; ++ } part; ++ u32 full; ++}; ++ ++ ++struct sst_stream_bufs { ++ struct list_head node; ++ u32 size; ++ const char *addr; ++ u32 data_copied; ++ bool in_use; ++ u32 offset; ++}; ++ ++struct snd_sst_user_cap_list { ++ unsigned int iov_index; /* index of iov */ ++ unsigned long iov_offset; /* offset in iov */ ++ unsigned long offset; /* offset in kmem */ ++ unsigned long size; /* size copied */ ++ struct list_head node; ++}; ++/* ++This structure is used to block a user/fw data call to another ++fw/user call ++*/ ++struct sst_block { ++ bool condition; /* condition for blocking check */ ++ int ret_code; /* ret code when block is released */ ++ void *data; /* data to be appsed for block if any */ ++ bool on; ++}; ++ ++enum snd_sst_buf_type { ++ SST_BUF_USER_STATIC = 1, ++ SST_BUF_USER_DYNAMIC, ++ SST_BUF_MMAP_STATIC, ++ SST_BUF_MMAP_DYNAMIC, ++}; ++enum snd_src { ++ SST_DRV = 1, ++ MAD_DRV = 2 ++}; ++/* ++structure that holds the stream information ++*/ ++struct stream_info { ++ unsigned int status; ++ unsigned int prev; ++ u8 codec; ++ unsigned int sst_id; ++ unsigned int ops; ++ struct list_head bufs; ++ struct mutex lock; /* mutex */ ++ spinlock_t pcm_lock; ++ bool mmapped; ++ unsigned int sg_index; /* current buf Index */ ++ unsigned char *cur_ptr; /* Current static bufs */ ++ struct snd_sst_buf_entry *buf_entry; ++ struct sst_block data_blk; /* stream ops block */ ++ struct sst_block ctrl_blk; /* stream control cmd block */ ++ enum snd_sst_buf_type buf_type; ++ void *pcm_substream; ++ void (*period_elapsed) (void *pcm_substream); ++ unsigned int sfreq; ++ void *decode_ibuf, *decode_obuf; ++ unsigned int decode_isize, decode_osize; ++ u8 decode_ibuf_type, decode_obuf_type; ++ unsigned int idecode_alloc; ++ unsigned int need_draining; ++ unsigned int str_type; ++ u32 curr_bytes; ++ u32 cumm_bytes; ++ u32 src; /* hack to remove */ ++}; ++ ++ ++ ++/* ++this structure is used for blocking the user's alloc calls to ++fw's response to alloc calls ++*/ ++struct stream_alloc_block { ++ int sst_id; /* session id of blocked stream */ ++ struct sst_block ops_block; /* ops block struture */ ++}; ++ ++#define SST_FW_SIGN "$SST" ++#define SST_FW_LIB_SIGN "$LIB" ++ ++/* FW file headers */ ++struct fw_header { ++ unsigned char signature[FW_SIGNATURE_SIZE]; /* FW signature */ ++ u32 file_size; /* size of fw minus this header */ ++ u32 modules; /* # of modules */ ++ u32 file_format; /* version of header format */ ++ u32 reserved[4]; ++}; ++ ++struct fw_module_header { ++ unsigned char signature[FW_SIGNATURE_SIZE]; /* module signature */ ++ u32 mod_size; /* size of module */ ++ u32 blocks; /* # of blocks */ ++ u32 type; /* codec type, pp lib */ ++ u32 entry_point; ++}; ++ ++struct dma_block_info { ++ enum sst_ram_type type; /* IRAM/DRAM */ ++ u32 size; /* Bytes */ ++ u32 ram_offset; /* Offset in I/DRAM */ ++ u32 rsvd; /* Reserved field */ ++}; ++ ++struct ioctl_pvt_data { ++ int str_id; ++ int pvt_id; ++}; ++ ++struct sst_ipc_msg_wq { ++ union ipc_header header; ++ char mailbox[SST_MAILBOX_SIZE]; ++ struct work_struct wq; ++}; ++ ++struct mad_ops_wq { ++ int stream_id; ++ enum sst_controls control_op; ++ struct work_struct wq; ++ ++}; ++ ++#define SST_MMAP_PAGES (640*1024 / PAGE_SIZE) ++#define SST_MMAP_STEP (40*1024 / PAGE_SIZE) ++ ++/* driver ops */ ++struct intel_sst_drv { ++ bool pmic_state; ++ int pmic_vendor; ++ int sst_state; ++/* int chip_rev_id; */ ++ void __iomem *shim; ++ void __iomem *mailbox; ++ void __iomem *iram; ++ void __iomem *dram; ++ unsigned int shim_phy_add; ++ struct list_head ipc_dispatch_list; ++ struct work_struct ipc_post_msg_wq; ++ struct sst_ipc_msg_wq ipc_process_msg; ++ struct sst_ipc_msg_wq ipc_process_reply; ++ struct sst_ipc_msg_wq ipc_post_msg; ++ struct mad_ops_wq mad_ops; ++ wait_queue_head_t wait_queue; ++ struct workqueue_struct *mad_wq; ++ struct workqueue_struct *post_msg_wq; ++ struct workqueue_struct *process_msg_wq; ++ struct workqueue_struct *process_reply_wq; ++ ++ struct stream_info streams[MAX_NUM_STREAMS]; ++ struct stream_alloc_block alloc_block[MAX_ACTIVE_STREAM]; ++ struct sst_block tgt_dev_blk, fw_info_blk, ++ vol_info_blk, mute_info_blk, hs_info_blk; ++ struct mutex list_lock;/* mutex for IPC list locking */ ++ struct snd_pmic_ops *scard_ops; ++ struct pci_dev *pci; ++ int active_streams[MAX_NUM_STREAMS]; ++ void *mmap_mem; ++ struct mutex stream_cnt_lock; ++ unsigned int mmap_len; ++ unsigned int unique_id; ++ unsigned int stream_cnt; /* total streams */ ++ unsigned int encoded_cnt; /* enocded streams only */ ++ unsigned int am_cnt; ++ unsigned int pb_streams; /* pb streams active */ ++ unsigned int cp_streams; /* cp streams active */ ++ unsigned int lpe_stalled; /* LPE is stalled or not */ ++ unsigned int pmic_port_instance; /*pmic port instance enabled*/ ++ int rx_time_slot_status; ++ unsigned int lpaudio_start; /* 1 - LPA stream(MP3 pb) in progress*/ ++ unsigned int audio_start; /* 1 - LPA stream(Non-MP3 pb) in progress*/ ++}; ++ ++extern struct intel_sst_drv *sst_drv_ctx; ++ ++/* register definitions */ ++/*SCU FW Changes*/ ++/*#define AUD_CLK_ADDR 0xff11d83c ++#define AUD_CLK_DISABLE 0x80008008 ++#define AUD_CLK_50MHZ 0x80008301 ++#define AUD_CLK_RATIO_1_2 0x80000301 ++#define AUD_CLK_RATIO_8008 0x80008008 ++#define AUD_CLK_RATIO_8101 0x80008101 ++#define AUD_CLK_RATIO_0101 0x80000101 ++#define AUD_SYS_ADDR 0xff11d118 ++#define AUD_SYS_RESET 0x7ffffcff ++#define AUD_SYS_SET 0x7fffffff ++#define AUD_SHIM_BASE_ADDR 0xffae8000 */ ++/* ++#define AUD_SHIM_RATIO_1_1 0x382 ++#define AUD_SHIM_RATIO 0x3a2 ++*/ ++/*SCU FW Changes*/ ++/*#define AUD_CLK_200 0xff11d200 ++#define AUD_CLK_204 0xff11d204 ++#define AUD_INIT_VAL 0x0*/ ++#define CHIP_REV_REG 0xff108000 ++#define CHIP_REV_ADDR 0x78 ++/* ++#define CHIP_REV_A1 0x0 ++#define CHIP_REV_A2 0x3 ++#define CLK_50MHZ 50 ++#define CLK_100MHZ 100 ++*/ ++/* misc definitions */ ++#define FW_DWNL_ID 0xFF ++#define LOOP1 0x11111111 ++#define LOOP2 0x22222222 ++#define LOOP3 0x33333333 ++#define LOOP4 0x44444444 ++ ++#define SST_DEFAULT_PMIC_PORT 1 /*audio port*/ ++/* NOTE: status will +ve for good cases and -ve for error ones */ ++#define MAX_STREAM_FIELD 255 ++ ++int sst_alloc_stream(char *params, unsigned int stream_ops, u8 codec, ++ unsigned int session_id); ++int sst_alloc_stream_response(unsigned int str_id, ++ struct snd_sst_str_type *type); ++int sst_stalled(void); ++int sst_pause_stream(int id); ++int sst_resume_stream(int id); ++int sst_enable_rx_timeslot(int status); ++int sst_drop_stream(int id); ++int sst_free_stream(int id); ++int sst_play_frame(int streamID); ++int sst_capture_frame(int streamID); ++int sst_set_stream_param(int streamID, struct snd_sst_params *str_param); ++int sst_target_device_select(struct snd_sst_target_device *target_device); ++int sst_decode(int str_id, struct snd_sst_dbufs *dbufs); ++int sst_get_decoded_bytes(int str_id, unsigned long long *bytes); ++int sst_get_fw_info(struct snd_sst_fw_info *info); ++int sst_get_stream_params(int str_id, ++ struct snd_sst_get_stream_params *get_params); ++int sst_drain_stream(int str_id); ++int sst_get_vol(struct snd_sst_vol *set_vol); ++int sst_set_vol(struct snd_sst_vol *set_vol); ++int sst_set_mute(struct snd_sst_mute *set_mute); ++ ++ ++void sst_post_message(struct work_struct *work); ++void sst_process_message(struct work_struct *work); ++void sst_process_reply(struct work_struct *work); ++void sst_process_mad_ops(struct work_struct *work); ++void sst_process_mad_jack_detection(struct work_struct *work); ++ ++int intel_sst_ioctl(struct inode *i_node, struct file *file_ptr, ++ unsigned int cmd, unsigned long arg); ++int intel_sst_open(struct inode *i_node, struct file *file_ptr); ++int intel_sst_release(struct inode *i_node, struct file *file_ptr); ++int intel_sst_read(struct file *file_ptr, char __user *buf, ++ size_t count, loff_t *ppos); ++int intel_sst_write(struct file *file_ptr, const char __user *buf, ++ size_t count, loff_t *ppos); ++int intel_sst_mmap(struct file *fp, struct vm_area_struct *vma); ++ssize_t intel_sst_aio_write(struct kiocb *kiocb, const struct iovec *iov, ++ unsigned long nr_segs, loff_t offset); ++ssize_t intel_sst_aio_read(struct kiocb *kiocb, const struct iovec *iov, ++ unsigned long nr_segs, loff_t offset); ++ ++int sst_load_fw(const struct firmware *fw, void *context); ++int sst_load_library(struct snd_sst_lib_download *lib, u8 ops, u32 pvt_id); ++int sst_spi_mode_enable(void); ++int sst_get_block_stream(struct intel_sst_drv *sst_drv_ctx); ++ ++void sst_print_hex(unsigned char *buf, unsigned int size); ++int sst_wait_interruptible(struct intel_sst_drv *sst_drv_ctx, ++ struct sst_block *block); ++int sst_wait_interruptible_timeout(struct intel_sst_drv *sst_drv_ctx, ++ struct sst_block *block, int timeout); ++int sst_wait_timeout(struct intel_sst_drv *sst_drv_ctx, ++ struct stream_alloc_block *block); ++int sst_create_large_msg(struct ipc_post **arg); ++int sst_create_short_msg(struct ipc_post **arg); ++void sst_print_params(struct snd_sst_params *str_params); ++void sst_wake_up_alloc_block(struct intel_sst_drv *sst_drv_ctx, ++ u8 sst_id, int status, void *data); ++void sst_clear_interrupt(void); ++ ++/** ++* this function is an inline function that sets the headers before ++* sending a message ++*/ ++static inline void sst_fill_header(union ipc_header *header, ++ int msg, int large, int strID) ++{ ++ header->part.msg_id = msg; ++ header->part.str_id = strID; ++ header->part.large = large; ++ header->part.done = 0; ++ header->part.busy = 1; ++ header->part.data = 0; ++} ++ ++/** ++* this inline function assigns a private id for calls that dont have stream ++* context yet ++*/ ++static inline unsigned int sst_assign_pvt_id(struct intel_sst_drv *sst_drv_ctx) ++{ ++ sst_drv_ctx->unique_id++; ++ if (sst_drv_ctx->unique_id >= MAX_NUM_STREAMS) ++ sst_drv_ctx->unique_id = 1; ++ return sst_drv_ctx->unique_id; ++} ++ ++/** ++* this function initialzes stream context ++*/ ++static inline void sst_init_stream(struct stream_info *stream, ++ int codec, int str_type, int sst_id, int ops) ++{ ++ stream->status = STREAM_INIT; ++ stream->prev = STREAM_UN_INIT; ++ stream->codec = codec; ++ stream->sst_id = sst_id; ++ stream->str_type = str_type; ++ stream->ops = ops; ++ stream->data_blk.on = false; ++ stream->data_blk.condition = false; ++ stream->data_blk.ret_code = 0; ++ stream->data_blk.data = NULL; ++ stream->ctrl_blk.on = false; ++ stream->ctrl_blk.condition = false; ++ stream->ctrl_blk.ret_code = 0; ++ stream->ctrl_blk.data = NULL; ++ stream->need_draining = false; ++ stream->decode_ibuf = NULL; ++ stream->decode_isize = 0; ++ stream->mmapped = false; ++} ++ ++/** ++* this function resets the stream contexts ++*/ ++static inline void sst_clean_stream(struct stream_info *stream) ++{ ++ struct sst_stream_bufs *bufs = NULL, *_bufs; ++ stream->status = STREAM_UN_INIT; ++ stream->prev = STREAM_UN_INIT; ++ mutex_lock(&stream->lock); ++ list_for_each_entry_safe(bufs, _bufs, &stream->bufs, node) { ++ list_del(&bufs->node); ++ kfree(bufs); ++ } ++ mutex_unlock(&stream->lock); ++ ++ if (stream->ops != STREAM_OPS_PLAYBACK_DRM) ++ kfree(stream->decode_ibuf); ++} ++ ++/** ++* this function generates events for OSPM ++*/ ++static inline int sst_ospm_send_event(int event) ++{ ++#ifdef CONFIG_MSTWN_POWER_MGMT ++ return ospm_generate_netlink_event(AUDIO_SUBSYTEM_ID, event); ++#else ++ return 0; ++#endif ++} ++ ++/** ++* this function validates the stream id ++*/ ++static inline int sst_validate_strid(int str_id) ++{ ++ if (str_id <= 0 || str_id >= MAX_NUM_STREAMS) ++ return -EINVAL; ++ else ++ return 0; ++} ++ ++#endif /* __INTEL_SST_COMMON_H__ */ +diff --git a/sound/pci/sst/intel_sst_pvt.c b/sound/pci/sst/intel_sst_pvt.c +new file mode 100644 +index 0000000..95d79be +--- /dev/null ++++ b/sound/pci/sst/intel_sst_pvt.c +@@ -0,0 +1,323 @@ ++/* ++ * intel_sst_pvt.c - Intel SST Driver for audio engine ++ * ++ * Copyright (C) 2008-10 Intel Corp ++ * 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 driver exposes the audio engine functionalities to the ALSA ++ * and middleware. ++ * ++ * This file contains all private functions ++ */ ++ ++#include <linux/cdev.h> ++#include <linux/pci.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/syscalls.h> ++#include <linux/fs.h> ++#include <linux/file.h> ++#include <linux/interrupt.h> ++#include <linux/list.h> ++#include <linux/workqueue.h> ++#include <linux/firmware.h> ++#include <linux/mutex.h> ++#include <linux/delay.h> ++#include <linux/sched.h> ++#include <sound/intel_lpe.h> ++#include <sound/intel_sst_ioctl.h> ++#include "intel_sst_fw_ipc.h" ++#include "intel_sst_common.h" ++ ++/** ++* this function assigns a block for the calls that dont have stream context yet ++* the blocks are used for waiting on Firmware's response for any operation ++*/ ++int sst_get_block_stream(struct intel_sst_drv *sst_drv_ctx) ++{ ++ int i; ++ ++ for (i = 0; i < MAX_ACTIVE_STREAM; i++) { ++ if (sst_drv_ctx->alloc_block[i].sst_id == BLOCK_UNINIT) { ++ sst_drv_ctx->alloc_block[i].ops_block.condition = false; ++ sst_drv_ctx->alloc_block[i].ops_block.ret_code = 0; ++ sst_drv_ctx->alloc_block[i].sst_id = 0; ++ break; ++ } ++ } ++ if (i == MAX_ACTIVE_STREAM) { ++ printk(KERN_ERR ++ "SST ERR: max alloc_stream reached"); ++ i = -EBUSY; /* active stream limit reached */ ++ } ++ return i; ++} ++ ++/** ++* this function is a debug function that is used to print contents of a buffer ++*/ ++void sst_print_hex(unsigned char *buf, unsigned int size) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < size; i++) { ++ printk(KERN_DEBUG "SST DBG:%02x ", buf[i]); ++ if ((i != 0) && ((i % 8) == 0)) ++ printk(KERN_DEBUG "SST DBG:\n"); ++ } ++} ++/** ++* this function waits without a timeout (and is interruptable) for a ++* given block event ++*/ ++int sst_wait_interruptible(struct intel_sst_drv *sst_drv_ctx, ++ struct sst_block *block) ++{ ++ int retval = 0; ++ ++ if (!wait_event_interruptible(sst_drv_ctx->wait_queue, ++ block->condition)) { ++ /* event wake */ ++ if (block->ret_code < 0) { ++ printk(KERN_ERR ++ "SST ERR: stream failed %d\n"\ ++ , block->ret_code); ++ retval = -EBUSY; ++ } else { ++ printk(KERN_DEBUG "SST DBG:event up\n"); ++ retval = 0; ++ } ++ } else { ++ printk(KERN_ERR ++ "SST ERR: signal interrupted\n"); ++ retval = -EINTR; ++ } ++ return retval; ++ ++} ++ ++/** ++* this function waits with a timeout value (and is interruptle) on a ++* given block event ++*/ ++int sst_wait_interruptible_timeout( ++ struct intel_sst_drv *sst_drv_ctx, ++ struct sst_block *block, int timeout) ++{ ++ int retval = 0; ++ ++ printk(KERN_DEBUG "SST DBG:waiting....\n"); ++ if (wait_event_interruptible_timeout(sst_drv_ctx->wait_queue, ++ block->condition, ++ msecs_to_jiffies(timeout))) { ++ if (block->ret_code < 0) { ++ printk(KERN_ERR ++ "SST ERR: stream failed %d\n"\ ++ , block->ret_code); ++ } else ++ printk(KERN_DEBUG "SST DBG:event up\n"); ++ retval = block->ret_code; ++ } else { ++ block->on = false; ++ printk(KERN_ERR ++ "SST ERR: timeout occured...\n"); ++ /* settign firmware state as uninit so that the ++ firmware will get redownloaded on next request ++ this is because firmare not responding for 5 sec ++ is equalant to some unrecoverable error of FW ++ sst_drv_ctx->sst_state = SST_UN_INIT;*/ ++ retval = -EBUSY; ++ } ++ return retval; ++ ++} ++ ++/** ++* this function waits with on a given block event ++*/ ++int sst_wait_timeout(struct intel_sst_drv *sst_drv_ctx, ++ struct stream_alloc_block *block) ++{ ++ int retval = 0; ++ ++ /* NOTE: ++ Observed that FW processes the alloc msg and replies even ++ before the alloc thread has finished execution */ ++ printk(KERN_DEBUG "SST DBG:waiting for %x, +\ ++ condition %x \n", block->sst_id, ++ block->ops_block.condition); ++ if (wait_event_interruptible_timeout(sst_drv_ctx->wait_queue, ++ block->ops_block.condition, ++ msecs_to_jiffies(SST_BLOCK_TIMEOUT))) { ++ /* event wake */ ++ printk(KERN_DEBUG "SST DBG:Event wake +\ ++ ... %x \n", block->ops_block.condition); ++ printk(KERN_DEBUG "SST DBG:message +\ ++ ret: %d\n", block->ops_block.ret_code); ++ retval = block->ops_block.ret_code; ++ } else { ++ block->ops_block.on = false; ++ printk(KERN_ERR ++ "SST ERR: Wait timed-out %x \n",\ ++ block->ops_block.condition); ++ /* settign firmware state as uninit so that the ++ firmware will get redownloaded on next request ++ this is because firmare not responding for 5 sec ++ is equalant to some unrecoverable error of FW ++ sst_drv_ctx->sst_state = SST_UN_INIT;*/ ++ retval = -EBUSY; ++ } ++ return retval; ++ ++} ++ ++/** ++* this function allocats structures to send a large message to the firmware ++*/ ++int sst_create_large_msg(struct ipc_post **arg) ++{ ++ struct ipc_post *msg; ++ ++ msg = kzalloc(sizeof(struct ipc_post), GFP_ATOMIC); ++ if (!msg) { ++ printk(KERN_ERR ++ "SST ERR: kzalloc msg failed \n"); ++ return -ENOMEM; ++ } ++ ++ msg->mailbox_data = kzalloc(SST_MAILBOX_SIZE, GFP_ATOMIC); ++ if (!msg->mailbox_data) { ++ kfree(msg); ++ printk(KERN_ERR ++ "SST ERR: kzalloc mailbox_data failed"); ++ return -ENOMEM; ++ }; ++ *arg = msg; ++ return 0; ++} ++ ++/** ++* this function allocats structures to send a short message to the firmware ++*/ ++int sst_create_short_msg(struct ipc_post **arg) ++{ ++ struct ipc_post *msg; ++ ++ msg = kzalloc(sizeof(*msg), GFP_ATOMIC); ++ if (!msg) { ++ printk(KERN_ERR ++ "SST ERR: kzalloc msg failed \n"); ++ return -ENOMEM; ++ } ++ msg->mailbox_data = NULL; ++ *arg = msg; ++ return 0; ++} ++ ++/** ++* this function is a debug funtion to print the stream parameters ++*/ ++void sst_print_params(struct snd_sst_params *str_params) ++{ ++ switch (str_params->codec) { ++ case SST_CODEC_TYPE_PCM: ++ printk(KERN_DEBUG "SST DBG:pcm \n"); ++ printk(KERN_DEBUG "SST DBG:chan=%d, sfreq = %d, wd_sz = %d \ ++ brate = %d buffer_size= 0x%d\ ++ period_cnt = %d\n", ++ str_params->sparams.uc.pcm_params.num_chan, ++ str_params->sparams.uc.pcm_params.sfreq, ++ str_params->sparams.uc.pcm_params.pcm_wd_sz, ++ str_params->sparams.uc.pcm_params.brate, ++ // str_params->sparams.uc.pcm_params.frame_size, ++ // str_params->sparams.uc.pcm_params.samples_per_frame, ++ str_params->sparams.uc.pcm_params.buffer_size, ++ str_params->sparams.uc.pcm_params.period_count); ++ break; ++ ++ case SST_CODEC_TYPE_MP3: ++ printk(KERN_DEBUG "SST DBG:mp3 \n"); ++ printk(KERN_DEBUG "SST DBG:chan=%d, brate=%d, sfreq = %d, wd_sz = %d\n", ++ str_params->sparams.uc.mp3_params.num_chan, ++ str_params->sparams.uc.mp3_params.brate, ++ str_params->sparams.uc.mp3_params.sfreq, ++ str_params->sparams.uc.mp3_params.pcm_wd_sz); ++ break; ++ ++ case SST_CODEC_TYPE_AAC: ++ printk(KERN_DEBUG "SST DBG:aac \n"); ++ printk(KERN_DEBUG "SST DBG:chan=%d, brate=%d, sfreq = %d, wd_sz = %d,asrate=%d\n", ++ str_params->sparams. uc.aac_params.num_chan, ++ str_params->sparams.uc.aac_params.brate, ++ str_params->sparams.uc.aac_params.sfreq, ++ str_params->sparams.uc.aac_params.pcm_wd_sz, ++ str_params->sparams.uc.aac_params.aac_srate); ++ printk(KERN_DEBUG "SST DBG:mpgid=%d profile=%d, aot = %d\n", ++ str_params->sparams.uc.aac_params.mpg_id, ++ str_params->sparams.uc.aac_params.aac_profile, ++ str_params->sparams.uc.aac_params.aot); ++ break; ++ case SST_CODEC_TYPE_WMA9: ++ printk(KERN_DEBUG "SST DBG:wma type \n"); ++ printk(KERN_DEBUG "SST DBG:chan=%d, brate=%d, sfreq = %d, wd_sz = %d, tag=%d\n", ++ str_params->sparams. uc.wma_params.num_chan, ++ str_params->sparams.uc.wma_params.brate, ++ str_params->sparams.uc.wma_params.sfreq, ++ str_params->sparams.uc.wma_params.pcm_wd_sz, ++ str_params->sparams.uc.wma_params.format_tag); ++ printk(KERN_DEBUG "SST DBG:mask=%d, +\ ++ b align=%d, enc opt =%d, op align =%d\n", ++ str_params->sparams.uc.wma_params.channel_mask, ++ str_params->sparams.uc.wma_params.block_align, ++ str_params->sparams.uc.wma_params.wma_encode_opt, ++ str_params->sparams.uc.wma_params.op_align); ++ break; ++ default: ++ printk(KERN_DEBUG "SST DBG:other +\ ++ codec 0x%x\n", str_params->codec); ++ } ++} ++ ++/** ++* this function wakes up a sleeping block event based on the response ++*/ ++void sst_wake_up_alloc_block(struct intel_sst_drv *sst_drv_ctx, ++ u8 sst_id, int status, void *data) ++{ ++ int i; ++ ++ /* Unblock with retval code */ ++ for (i = 0; i < MAX_ACTIVE_STREAM; i++) { ++ if (sst_id == sst_drv_ctx->alloc_block[i].sst_id) { ++ sst_drv_ctx->alloc_block[i].ops_block.condition = true; ++ sst_drv_ctx->alloc_block[i].ops_block.ret_code = status; ++ sst_drv_ctx->alloc_block[i].ops_block.data = data; ++ printk(KERN_DEBUG "SST DBG:wake id %d, +\ ++ sst_id %d condition %x\n", i, ++ sst_drv_ctx->alloc_block[i].sst_id, ++ sst_drv_ctx->alloc_block[i].ops_block.condition); ++ wake_up(&sst_drv_ctx->wait_queue); ++ break; ++ } ++ } ++} +-- +1.6.2.2 + |