mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-27 03:10:12 +00:00
![Devendra Naga](/assets/img/avatar_default.png)
fixes the following errors ERROR: "foo ** bar" should be "foo **bar" +int strm_free_buffer(struct strm_res_object *strmres, u8 ** ap_buffer, ERROR: "foo ** bar" should be "foo **bar" +int strm_reclaim(struct strm_object *stream_obj, u8 ** buf_ptr, ERROR: space prohibited after that '*' (ctx:ExW) + * hnotification) ^ Signed-off-by: Devendra Naga <devendra.aaru@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
733 lines
18 KiB
C
733 lines
18 KiB
C
/*
|
|
* strm.c
|
|
*
|
|
* DSP-BIOS Bridge driver support functions for TI OMAP processors.
|
|
*
|
|
* DSP/BIOS Bridge Stream Manager.
|
|
*
|
|
* Copyright (C) 2005-2006 Texas Instruments, Inc.
|
|
*
|
|
* This package is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|
*/
|
|
|
|
#include <linux/types.h>
|
|
|
|
/* ----------------------------------- Host OS */
|
|
#include <dspbridge/host_os.h>
|
|
|
|
/* ----------------------------------- DSP/BIOS Bridge */
|
|
#include <dspbridge/dbdefs.h>
|
|
|
|
/* ----------------------------------- OS Adaptation Layer */
|
|
#include <dspbridge/sync.h>
|
|
|
|
/* ----------------------------------- Bridge Driver */
|
|
#include <dspbridge/dspdefs.h>
|
|
|
|
/* ----------------------------------- Resource Manager */
|
|
#include <dspbridge/nodepriv.h>
|
|
|
|
/* ----------------------------------- Others */
|
|
#include <dspbridge/cmm.h>
|
|
|
|
/* ----------------------------------- This */
|
|
#include <dspbridge/strm.h>
|
|
|
|
#include <dspbridge/resourcecleanup.h>
|
|
|
|
/* ----------------------------------- Defines, Data Structures, Typedefs */
|
|
#define DEFAULTTIMEOUT 10000
|
|
#define DEFAULTNUMBUFS 2
|
|
|
|
/*
|
|
* ======== strm_mgr ========
|
|
* The strm_mgr contains device information needed to open the underlying
|
|
* channels of a stream.
|
|
*/
|
|
struct strm_mgr {
|
|
struct dev_object *dev_obj; /* Device for this processor */
|
|
struct chnl_mgr *chnl_mgr; /* Channel manager */
|
|
/* Function interface to Bridge driver */
|
|
struct bridge_drv_interface *intf_fxns;
|
|
};
|
|
|
|
/*
|
|
* ======== strm_object ========
|
|
* This object is allocated in strm_open().
|
|
*/
|
|
struct strm_object {
|
|
struct strm_mgr *strm_mgr_obj;
|
|
struct chnl_object *chnl_obj;
|
|
u32 dir; /* DSP_TONODE or DSP_FROMNODE */
|
|
u32 timeout;
|
|
u32 num_bufs; /* Max # of bufs allowed in stream */
|
|
u32 bufs_in_strm; /* Current # of bufs in stream */
|
|
u32 bytes; /* bytes transferred since idled */
|
|
/* STREAM_IDLE, STREAM_READY, ... */
|
|
enum dsp_streamstate strm_state;
|
|
void *user_event; /* Saved for strm_get_info() */
|
|
enum dsp_strmmode strm_mode; /* STRMMODE_[PROCCOPY][ZEROCOPY]... */
|
|
u32 dma_chnl_id; /* DMA chnl id */
|
|
u32 dma_priority; /* DMA priority:DMAPRI_[LOW][HIGH] */
|
|
u32 segment_id; /* >0 is SM segment.=0 is local heap */
|
|
u32 buf_alignment; /* Alignment for stream bufs */
|
|
/* Stream's SM address translator */
|
|
struct cmm_xlatorobject *xlator;
|
|
};
|
|
|
|
/* ----------------------------------- Function Prototypes */
|
|
static int delete_strm(struct strm_object *stream_obj);
|
|
|
|
/*
|
|
* ======== strm_allocate_buffer ========
|
|
* Purpose:
|
|
* Allocates buffers for a stream.
|
|
*/
|
|
int strm_allocate_buffer(struct strm_res_object *strmres, u32 usize,
|
|
u8 **ap_buffer, u32 num_bufs,
|
|
struct process_context *pr_ctxt)
|
|
{
|
|
int status = 0;
|
|
u32 alloc_cnt = 0;
|
|
u32 i;
|
|
struct strm_object *stream_obj = strmres->stream;
|
|
|
|
if (stream_obj) {
|
|
/*
|
|
* Allocate from segment specified at time of stream open.
|
|
*/
|
|
if (usize == 0)
|
|
status = -EINVAL;
|
|
|
|
} else {
|
|
status = -EFAULT;
|
|
}
|
|
|
|
if (status)
|
|
goto func_end;
|
|
|
|
for (i = 0; i < num_bufs; i++) {
|
|
(void)cmm_xlator_alloc_buf(stream_obj->xlator, &ap_buffer[i],
|
|
usize);
|
|
if (ap_buffer[i] == NULL) {
|
|
status = -ENOMEM;
|
|
alloc_cnt = i;
|
|
break;
|
|
}
|
|
}
|
|
if (status)
|
|
strm_free_buffer(strmres, ap_buffer, alloc_cnt, pr_ctxt);
|
|
|
|
if (status)
|
|
goto func_end;
|
|
|
|
drv_proc_update_strm_res(num_bufs, strmres);
|
|
|
|
func_end:
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* ======== strm_close ========
|
|
* Purpose:
|
|
* Close a stream opened with strm_open().
|
|
*/
|
|
int strm_close(struct strm_res_object *strmres,
|
|
struct process_context *pr_ctxt)
|
|
{
|
|
struct bridge_drv_interface *intf_fxns;
|
|
struct chnl_info chnl_info_obj;
|
|
int status = 0;
|
|
struct strm_object *stream_obj = strmres->stream;
|
|
|
|
if (!stream_obj) {
|
|
status = -EFAULT;
|
|
} else {
|
|
/* Have all buffers been reclaimed? If not, return
|
|
* -EPIPE */
|
|
intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
|
|
status =
|
|
(*intf_fxns->chnl_get_info) (stream_obj->chnl_obj,
|
|
&chnl_info_obj);
|
|
|
|
if (chnl_info_obj.cio_cs > 0 || chnl_info_obj.cio_reqs > 0)
|
|
status = -EPIPE;
|
|
else
|
|
status = delete_strm(stream_obj);
|
|
}
|
|
|
|
if (status)
|
|
goto func_end;
|
|
|
|
idr_remove(pr_ctxt->stream_id, strmres->id);
|
|
func_end:
|
|
dev_dbg(bridge, "%s: stream_obj: %p, status 0x%x\n", __func__,
|
|
stream_obj, status);
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* ======== strm_create ========
|
|
* Purpose:
|
|
* Create a STRM manager object.
|
|
*/
|
|
int strm_create(struct strm_mgr **strm_man,
|
|
struct dev_object *dev_obj)
|
|
{
|
|
struct strm_mgr *strm_mgr_obj;
|
|
int status = 0;
|
|
|
|
*strm_man = NULL;
|
|
/* Allocate STRM manager object */
|
|
strm_mgr_obj = kzalloc(sizeof(struct strm_mgr), GFP_KERNEL);
|
|
if (strm_mgr_obj == NULL)
|
|
status = -ENOMEM;
|
|
else
|
|
strm_mgr_obj->dev_obj = dev_obj;
|
|
|
|
/* Get Channel manager and Bridge function interface */
|
|
if (!status) {
|
|
status = dev_get_chnl_mgr(dev_obj, &(strm_mgr_obj->chnl_mgr));
|
|
if (!status) {
|
|
(void)dev_get_intf_fxns(dev_obj,
|
|
&(strm_mgr_obj->intf_fxns));
|
|
}
|
|
}
|
|
|
|
if (!status)
|
|
*strm_man = strm_mgr_obj;
|
|
else
|
|
kfree(strm_mgr_obj);
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* ======== strm_delete ========
|
|
* Purpose:
|
|
* Delete the STRM Manager Object.
|
|
*/
|
|
void strm_delete(struct strm_mgr *strm_mgr_obj)
|
|
{
|
|
kfree(strm_mgr_obj);
|
|
}
|
|
|
|
/*
|
|
* ======== strm_free_buffer ========
|
|
* Purpose:
|
|
* Frees the buffers allocated for a stream.
|
|
*/
|
|
int strm_free_buffer(struct strm_res_object *strmres, u8 **ap_buffer,
|
|
u32 num_bufs, struct process_context *pr_ctxt)
|
|
{
|
|
int status = 0;
|
|
u32 i = 0;
|
|
struct strm_object *stream_obj = strmres->stream;
|
|
|
|
if (!stream_obj)
|
|
status = -EFAULT;
|
|
|
|
if (!status) {
|
|
for (i = 0; i < num_bufs; i++) {
|
|
status =
|
|
cmm_xlator_free_buf(stream_obj->xlator,
|
|
ap_buffer[i]);
|
|
if (status)
|
|
break;
|
|
ap_buffer[i] = NULL;
|
|
}
|
|
}
|
|
drv_proc_update_strm_res(num_bufs - i, strmres);
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* ======== strm_get_info ========
|
|
* Purpose:
|
|
* Retrieves information about a stream.
|
|
*/
|
|
int strm_get_info(struct strm_object *stream_obj,
|
|
struct stream_info *stream_info,
|
|
u32 stream_info_size)
|
|
{
|
|
struct bridge_drv_interface *intf_fxns;
|
|
struct chnl_info chnl_info_obj;
|
|
int status = 0;
|
|
void *virt_base = NULL; /* NULL if no SM used */
|
|
|
|
if (!stream_obj) {
|
|
status = -EFAULT;
|
|
} else {
|
|
if (stream_info_size < sizeof(struct stream_info)) {
|
|
/* size of users info */
|
|
status = -EINVAL;
|
|
}
|
|
}
|
|
if (status)
|
|
goto func_end;
|
|
|
|
intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
|
|
status =
|
|
(*intf_fxns->chnl_get_info) (stream_obj->chnl_obj,
|
|
&chnl_info_obj);
|
|
if (status)
|
|
goto func_end;
|
|
|
|
if (stream_obj->xlator) {
|
|
/* We have a translator */
|
|
cmm_xlator_info(stream_obj->xlator, (u8 **) &virt_base, 0,
|
|
stream_obj->segment_id, false);
|
|
}
|
|
stream_info->segment_id = stream_obj->segment_id;
|
|
stream_info->strm_mode = stream_obj->strm_mode;
|
|
stream_info->virt_base = virt_base;
|
|
stream_info->user_strm->number_bufs_allowed = stream_obj->num_bufs;
|
|
stream_info->user_strm->number_bufs_in_stream = chnl_info_obj.cio_cs +
|
|
chnl_info_obj.cio_reqs;
|
|
/* # of bytes transferred since last call to DSPStream_Idle() */
|
|
stream_info->user_strm->number_bytes = chnl_info_obj.bytes_tx;
|
|
stream_info->user_strm->sync_object_handle = chnl_info_obj.event_obj;
|
|
/* Determine stream state based on channel state and info */
|
|
if (chnl_info_obj.state & CHNL_STATEEOS) {
|
|
stream_info->user_strm->ss_stream_state = STREAM_DONE;
|
|
} else {
|
|
if (chnl_info_obj.cio_cs > 0)
|
|
stream_info->user_strm->ss_stream_state = STREAM_READY;
|
|
else if (chnl_info_obj.cio_reqs > 0)
|
|
stream_info->user_strm->ss_stream_state =
|
|
STREAM_PENDING;
|
|
else
|
|
stream_info->user_strm->ss_stream_state = STREAM_IDLE;
|
|
|
|
}
|
|
func_end:
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* ======== strm_idle ========
|
|
* Purpose:
|
|
* Idles a particular stream.
|
|
*/
|
|
int strm_idle(struct strm_object *stream_obj, bool flush_data)
|
|
{
|
|
struct bridge_drv_interface *intf_fxns;
|
|
int status = 0;
|
|
|
|
if (!stream_obj) {
|
|
status = -EFAULT;
|
|
} else {
|
|
intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
|
|
|
|
status = (*intf_fxns->chnl_idle) (stream_obj->chnl_obj,
|
|
stream_obj->timeout,
|
|
flush_data);
|
|
}
|
|
|
|
dev_dbg(bridge, "%s: stream_obj: %p flush_data: 0x%x status: 0x%x\n",
|
|
__func__, stream_obj, flush_data, status);
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* ======== strm_issue ========
|
|
* Purpose:
|
|
* Issues a buffer on a stream
|
|
*/
|
|
int strm_issue(struct strm_object *stream_obj, u8 *pbuf, u32 ul_bytes,
|
|
u32 ul_buf_size, u32 dw_arg)
|
|
{
|
|
struct bridge_drv_interface *intf_fxns;
|
|
int status = 0;
|
|
void *tmp_buf = NULL;
|
|
|
|
if (!stream_obj) {
|
|
status = -EFAULT;
|
|
} else {
|
|
intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
|
|
|
|
if (stream_obj->segment_id != 0) {
|
|
tmp_buf = cmm_xlator_translate(stream_obj->xlator,
|
|
(void *)pbuf,
|
|
CMM_VA2DSPPA);
|
|
if (tmp_buf == NULL)
|
|
status = -ESRCH;
|
|
|
|
}
|
|
if (!status) {
|
|
status = (*intf_fxns->chnl_add_io_req)
|
|
(stream_obj->chnl_obj, pbuf, ul_bytes, ul_buf_size,
|
|
(u32) tmp_buf, dw_arg);
|
|
}
|
|
if (status == -EIO)
|
|
status = -ENOSR;
|
|
}
|
|
|
|
dev_dbg(bridge, "%s: stream_obj: %p pbuf: %p ul_bytes: 0x%x dw_arg:"
|
|
" 0x%x status: 0x%x\n", __func__, stream_obj, pbuf,
|
|
ul_bytes, dw_arg, status);
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* ======== strm_open ========
|
|
* Purpose:
|
|
* Open a stream for sending/receiving data buffers to/from a task or
|
|
* XDAIS socket node on the DSP.
|
|
*/
|
|
int strm_open(struct node_object *hnode, u32 dir, u32 index,
|
|
struct strm_attr *pattr,
|
|
struct strm_res_object **strmres,
|
|
struct process_context *pr_ctxt)
|
|
{
|
|
struct strm_mgr *strm_mgr_obj;
|
|
struct bridge_drv_interface *intf_fxns;
|
|
u32 ul_chnl_id;
|
|
struct strm_object *strm_obj = NULL;
|
|
s8 chnl_mode;
|
|
struct chnl_attr chnl_attr_obj;
|
|
int status = 0;
|
|
struct cmm_object *hcmm_mgr = NULL; /* Shared memory manager hndl */
|
|
|
|
void *stream_res;
|
|
|
|
*strmres = NULL;
|
|
if (dir != DSP_TONODE && dir != DSP_FROMNODE) {
|
|
status = -EPERM;
|
|
} else {
|
|
/* Get the channel id from the node (set in node_connect()) */
|
|
status = node_get_channel_id(hnode, dir, index, &ul_chnl_id);
|
|
}
|
|
if (!status)
|
|
status = node_get_strm_mgr(hnode, &strm_mgr_obj);
|
|
|
|
if (!status) {
|
|
strm_obj = kzalloc(sizeof(struct strm_object), GFP_KERNEL);
|
|
if (strm_obj == NULL) {
|
|
status = -ENOMEM;
|
|
} else {
|
|
strm_obj->strm_mgr_obj = strm_mgr_obj;
|
|
strm_obj->dir = dir;
|
|
strm_obj->strm_state = STREAM_IDLE;
|
|
strm_obj->user_event = pattr->user_event;
|
|
if (pattr->stream_attr_in != NULL) {
|
|
strm_obj->timeout =
|
|
pattr->stream_attr_in->timeout;
|
|
strm_obj->num_bufs =
|
|
pattr->stream_attr_in->num_bufs;
|
|
strm_obj->strm_mode =
|
|
pattr->stream_attr_in->strm_mode;
|
|
strm_obj->segment_id =
|
|
pattr->stream_attr_in->segment_id;
|
|
strm_obj->buf_alignment =
|
|
pattr->stream_attr_in->buf_alignment;
|
|
strm_obj->dma_chnl_id =
|
|
pattr->stream_attr_in->dma_chnl_id;
|
|
strm_obj->dma_priority =
|
|
pattr->stream_attr_in->dma_priority;
|
|
chnl_attr_obj.uio_reqs =
|
|
pattr->stream_attr_in->num_bufs;
|
|
} else {
|
|
strm_obj->timeout = DEFAULTTIMEOUT;
|
|
strm_obj->num_bufs = DEFAULTNUMBUFS;
|
|
strm_obj->strm_mode = STRMMODE_PROCCOPY;
|
|
strm_obj->segment_id = 0; /* local mem */
|
|
strm_obj->buf_alignment = 0;
|
|
strm_obj->dma_chnl_id = 0;
|
|
strm_obj->dma_priority = 0;
|
|
chnl_attr_obj.uio_reqs = DEFAULTNUMBUFS;
|
|
}
|
|
chnl_attr_obj.reserved1 = NULL;
|
|
/* DMA chnl flush timeout */
|
|
chnl_attr_obj.reserved2 = strm_obj->timeout;
|
|
chnl_attr_obj.event_obj = NULL;
|
|
if (pattr->user_event != NULL)
|
|
chnl_attr_obj.event_obj = pattr->user_event;
|
|
|
|
}
|
|
}
|
|
if (status)
|
|
goto func_cont;
|
|
|
|
if ((pattr->virt_base == NULL) || !(pattr->virt_size > 0))
|
|
goto func_cont;
|
|
|
|
/* No System DMA */
|
|
/* Get the shared mem mgr for this streams dev object */
|
|
status = dev_get_cmm_mgr(strm_mgr_obj->dev_obj, &hcmm_mgr);
|
|
if (!status) {
|
|
/*Allocate a SM addr translator for this strm. */
|
|
status = cmm_xlator_create(&strm_obj->xlator, hcmm_mgr, NULL);
|
|
if (!status) {
|
|
/* Set translators Virt Addr attributes */
|
|
status = cmm_xlator_info(strm_obj->xlator,
|
|
(u8 **) &pattr->virt_base,
|
|
pattr->virt_size,
|
|
strm_obj->segment_id, true);
|
|
}
|
|
}
|
|
func_cont:
|
|
if (!status) {
|
|
/* Open channel */
|
|
chnl_mode = (dir == DSP_TONODE) ?
|
|
CHNL_MODETODSP : CHNL_MODEFROMDSP;
|
|
intf_fxns = strm_mgr_obj->intf_fxns;
|
|
status = (*intf_fxns->chnl_open) (&(strm_obj->chnl_obj),
|
|
strm_mgr_obj->chnl_mgr,
|
|
chnl_mode, ul_chnl_id,
|
|
&chnl_attr_obj);
|
|
if (status) {
|
|
/*
|
|
* over-ride non-returnable status codes so we return
|
|
* something documented
|
|
*/
|
|
if (status != -ENOMEM && status !=
|
|
-EINVAL && status != -EPERM) {
|
|
/*
|
|
* We got a status that's not return-able.
|
|
* Assert that we got something we were
|
|
* expecting (-EFAULT isn't acceptable,
|
|
* strm_mgr_obj->chnl_mgr better be valid or we
|
|
* assert here), and then return -EPERM.
|
|
*/
|
|
status = -EPERM;
|
|
}
|
|
}
|
|
}
|
|
if (!status) {
|
|
status = drv_proc_insert_strm_res_element(strm_obj,
|
|
&stream_res, pr_ctxt);
|
|
if (status)
|
|
delete_strm(strm_obj);
|
|
else
|
|
*strmres = (struct strm_res_object *)stream_res;
|
|
} else {
|
|
(void)delete_strm(strm_obj);
|
|
}
|
|
|
|
dev_dbg(bridge, "%s: hnode: %p dir: 0x%x index: 0x%x pattr: %p "
|
|
"strmres: %p status: 0x%x\n", __func__,
|
|
hnode, dir, index, pattr, strmres, status);
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* ======== strm_reclaim ========
|
|
* Purpose:
|
|
* Relcaims a buffer from a stream.
|
|
*/
|
|
int strm_reclaim(struct strm_object *stream_obj, u8 **buf_ptr,
|
|
u32 *nbytes, u32 *buff_size, u32 *pdw_arg)
|
|
{
|
|
struct bridge_drv_interface *intf_fxns;
|
|
struct chnl_ioc chnl_ioc_obj;
|
|
int status = 0;
|
|
void *tmp_buf = NULL;
|
|
|
|
if (!stream_obj) {
|
|
status = -EFAULT;
|
|
goto func_end;
|
|
}
|
|
intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
|
|
|
|
status =
|
|
(*intf_fxns->chnl_get_ioc) (stream_obj->chnl_obj,
|
|
stream_obj->timeout,
|
|
&chnl_ioc_obj);
|
|
if (!status) {
|
|
*nbytes = chnl_ioc_obj.byte_size;
|
|
if (buff_size)
|
|
*buff_size = chnl_ioc_obj.buf_size;
|
|
|
|
*pdw_arg = chnl_ioc_obj.arg;
|
|
if (!CHNL_IS_IO_COMPLETE(chnl_ioc_obj)) {
|
|
if (CHNL_IS_TIMED_OUT(chnl_ioc_obj)) {
|
|
status = -ETIME;
|
|
} else {
|
|
/* Allow reclaims after idle to succeed */
|
|
if (!CHNL_IS_IO_CANCELLED(chnl_ioc_obj))
|
|
status = -EPERM;
|
|
|
|
}
|
|
}
|
|
/* Translate zerocopy buffer if channel not canceled. */
|
|
if (!status
|
|
&& (!CHNL_IS_IO_CANCELLED(chnl_ioc_obj))
|
|
&& (stream_obj->strm_mode == STRMMODE_ZEROCOPY)) {
|
|
/*
|
|
* This is a zero-copy channel so chnl_ioc_obj.buf
|
|
* contains the DSP address of SM. We need to
|
|
* translate it to a virtual address for the user
|
|
* thread to access.
|
|
* Note: Could add CMM_DSPPA2VA to CMM in the future.
|
|
*/
|
|
tmp_buf = cmm_xlator_translate(stream_obj->xlator,
|
|
chnl_ioc_obj.buf,
|
|
CMM_DSPPA2PA);
|
|
if (tmp_buf != NULL) {
|
|
/* now convert this GPP Pa to Va */
|
|
tmp_buf = cmm_xlator_translate(stream_obj->
|
|
xlator,
|
|
tmp_buf,
|
|
CMM_PA2VA);
|
|
}
|
|
if (tmp_buf == NULL)
|
|
status = -ESRCH;
|
|
|
|
chnl_ioc_obj.buf = tmp_buf;
|
|
}
|
|
*buf_ptr = chnl_ioc_obj.buf;
|
|
}
|
|
func_end:
|
|
dev_dbg(bridge, "%s: stream_obj: %p buf_ptr: %p nbytes: %p "
|
|
"pdw_arg: %p status 0x%x\n", __func__, stream_obj,
|
|
buf_ptr, nbytes, pdw_arg, status);
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* ======== strm_register_notify ========
|
|
* Purpose:
|
|
* Register to be notified on specific events for this stream.
|
|
*/
|
|
int strm_register_notify(struct strm_object *stream_obj, u32 event_mask,
|
|
u32 notify_type, struct dsp_notification
|
|
*hnotification)
|
|
{
|
|
struct bridge_drv_interface *intf_fxns;
|
|
int status = 0;
|
|
|
|
if (!stream_obj) {
|
|
status = -EFAULT;
|
|
} else if ((event_mask & ~((DSP_STREAMIOCOMPLETION) |
|
|
DSP_STREAMDONE)) != 0) {
|
|
status = -EINVAL;
|
|
} else {
|
|
if (notify_type != DSP_SIGNALEVENT)
|
|
status = -ENOSYS;
|
|
|
|
}
|
|
if (!status) {
|
|
intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
|
|
|
|
status =
|
|
(*intf_fxns->chnl_register_notify) (stream_obj->
|
|
chnl_obj,
|
|
event_mask,
|
|
notify_type,
|
|
hnotification);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* ======== strm_select ========
|
|
* Purpose:
|
|
* Selects a ready stream.
|
|
*/
|
|
int strm_select(struct strm_object **strm_tab, u32 strms,
|
|
u32 *pmask, u32 utimeout)
|
|
{
|
|
u32 index;
|
|
struct chnl_info chnl_info_obj;
|
|
struct bridge_drv_interface *intf_fxns;
|
|
struct sync_object **sync_events = NULL;
|
|
u32 i;
|
|
int status = 0;
|
|
|
|
*pmask = 0;
|
|
for (i = 0; i < strms; i++) {
|
|
if (!strm_tab[i]) {
|
|
status = -EFAULT;
|
|
break;
|
|
}
|
|
}
|
|
if (status)
|
|
goto func_end;
|
|
|
|
/* Determine which channels have IO ready */
|
|
for (i = 0; i < strms; i++) {
|
|
intf_fxns = strm_tab[i]->strm_mgr_obj->intf_fxns;
|
|
status = (*intf_fxns->chnl_get_info) (strm_tab[i]->chnl_obj,
|
|
&chnl_info_obj);
|
|
if (status) {
|
|
break;
|
|
} else {
|
|
if (chnl_info_obj.cio_cs > 0)
|
|
*pmask |= (1 << i);
|
|
|
|
}
|
|
}
|
|
if (!status && utimeout > 0 && *pmask == 0) {
|
|
/* Non-zero timeout */
|
|
sync_events = kmalloc(strms * sizeof(struct sync_object *),
|
|
GFP_KERNEL);
|
|
|
|
if (sync_events == NULL) {
|
|
status = -ENOMEM;
|
|
} else {
|
|
for (i = 0; i < strms; i++) {
|
|
intf_fxns =
|
|
strm_tab[i]->strm_mgr_obj->intf_fxns;
|
|
status = (*intf_fxns->chnl_get_info)
|
|
(strm_tab[i]->chnl_obj, &chnl_info_obj);
|
|
if (status)
|
|
break;
|
|
else
|
|
sync_events[i] =
|
|
chnl_info_obj.sync_event;
|
|
|
|
}
|
|
}
|
|
if (!status) {
|
|
status =
|
|
sync_wait_on_multiple_events(sync_events, strms,
|
|
utimeout, &index);
|
|
if (!status) {
|
|
/* Since we waited on the event, we have to
|
|
* reset it */
|
|
sync_set_event(sync_events[index]);
|
|
*pmask = 1 << index;
|
|
}
|
|
}
|
|
}
|
|
func_end:
|
|
kfree(sync_events);
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* ======== delete_strm ========
|
|
* Purpose:
|
|
* Frees the resources allocated for a stream.
|
|
*/
|
|
static int delete_strm(struct strm_object *stream_obj)
|
|
{
|
|
struct bridge_drv_interface *intf_fxns;
|
|
int status = 0;
|
|
|
|
if (stream_obj) {
|
|
if (stream_obj->chnl_obj) {
|
|
intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
|
|
/* Channel close can fail only if the channel handle
|
|
* is invalid. */
|
|
status = (*intf_fxns->chnl_close)
|
|
(stream_obj->chnl_obj);
|
|
}
|
|
/* Free all SM address translator resources */
|
|
kfree(stream_obj->xlator);
|
|
kfree(stream_obj);
|
|
} else {
|
|
status = -EFAULT;
|
|
}
|
|
return status;
|
|
}
|