]> Pileus Git - ~andy/linux/blob - drivers/staging/tidspbridge/rmgr/strm.c
Merge tag 'sound-3.10' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
[~andy/linux] / drivers / staging / tidspbridge / rmgr / strm.c
1 /*
2  * strm.c
3  *
4  * DSP-BIOS Bridge driver support functions for TI OMAP processors.
5  *
6  * DSP/BIOS Bridge Stream Manager.
7  *
8  * Copyright (C) 2005-2006 Texas Instruments, Inc.
9  *
10  * This package is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software Foundation.
13  *
14  * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
16  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
17  */
18
19 #include <linux/types.h>
20
21 /*  ----------------------------------- Host OS */
22 #include <dspbridge/host_os.h>
23
24 /*  ----------------------------------- DSP/BIOS Bridge */
25 #include <dspbridge/dbdefs.h>
26
27 /*  ----------------------------------- OS Adaptation Layer */
28 #include <dspbridge/sync.h>
29
30 /*  ----------------------------------- Bridge Driver */
31 #include <dspbridge/dspdefs.h>
32
33 /*  ----------------------------------- Resource Manager */
34 #include <dspbridge/nodepriv.h>
35
36 /*  ----------------------------------- Others */
37 #include <dspbridge/cmm.h>
38
39 /*  ----------------------------------- This */
40 #include <dspbridge/strm.h>
41
42 #include <dspbridge/resourcecleanup.h>
43
44 /*  ----------------------------------- Defines, Data Structures, Typedefs */
45 #define DEFAULTTIMEOUT      10000
46 #define DEFAULTNUMBUFS      2
47
48 /*
49  *  ======== strm_mgr ========
50  *  The strm_mgr contains device information needed to open the underlying
51  *  channels of a stream.
52  */
53 struct strm_mgr {
54         struct dev_object *dev_obj;     /* Device for this processor */
55         struct chnl_mgr *chnl_mgr;      /* Channel manager */
56         /* Function interface to Bridge driver */
57         struct bridge_drv_interface *intf_fxns;
58 };
59
60 /*
61  *  ======== strm_object ========
62  *  This object is allocated in strm_open().
63  */
64 struct strm_object {
65         struct strm_mgr *strm_mgr_obj;
66         struct chnl_object *chnl_obj;
67         u32 dir;                /* DSP_TONODE or DSP_FROMNODE */
68         u32 timeout;
69         u32 num_bufs;           /* Max # of bufs allowed in stream */
70         u32 bufs_in_strm;       /* Current # of bufs in stream */
71         u32 bytes;              /* bytes transferred since idled */
72         /* STREAM_IDLE, STREAM_READY, ... */
73         enum dsp_streamstate strm_state;
74         void *user_event;       /* Saved for strm_get_info() */
75         enum dsp_strmmode strm_mode;    /* STRMMODE_[PROCCOPY][ZEROCOPY]... */
76         u32 dma_chnl_id;        /* DMA chnl id */
77         u32 dma_priority;       /* DMA priority:DMAPRI_[LOW][HIGH] */
78         u32 segment_id;         /* >0 is SM segment.=0 is local heap */
79         u32 buf_alignment;      /* Alignment for stream bufs */
80         /* Stream's SM address translator */
81         struct cmm_xlatorobject *xlator;
82 };
83
84 /*  ----------------------------------- Function Prototypes */
85 static int delete_strm(struct strm_object *stream_obj);
86
87 /*
88  *  ======== strm_allocate_buffer ========
89  *  Purpose:
90  *      Allocates buffers for a stream.
91  */
92 int strm_allocate_buffer(struct strm_res_object *strmres, u32 usize,
93                                 u8 **ap_buffer, u32 num_bufs,
94                                 struct process_context *pr_ctxt)
95 {
96         int status = 0;
97         u32 alloc_cnt = 0;
98         u32 i;
99         struct strm_object *stream_obj = strmres->stream;
100
101         if (stream_obj) {
102                 /*
103                  * Allocate from segment specified at time of stream open.
104                  */
105                 if (usize == 0)
106                         status = -EINVAL;
107
108         } else {
109                 status = -EFAULT;
110         }
111
112         if (status)
113                 goto func_end;
114
115         for (i = 0; i < num_bufs; i++) {
116                 (void)cmm_xlator_alloc_buf(stream_obj->xlator, &ap_buffer[i],
117                                            usize);
118                 if (ap_buffer[i] == NULL) {
119                         status = -ENOMEM;
120                         alloc_cnt = i;
121                         break;
122                 }
123         }
124         if (status)
125                 strm_free_buffer(strmres, ap_buffer, alloc_cnt, pr_ctxt);
126
127         if (status)
128                 goto func_end;
129
130         drv_proc_update_strm_res(num_bufs, strmres);
131
132 func_end:
133         return status;
134 }
135
136 /*
137  *  ======== strm_close ========
138  *  Purpose:
139  *      Close a stream opened with strm_open().
140  */
141 int strm_close(struct strm_res_object *strmres,
142                       struct process_context *pr_ctxt)
143 {
144         struct bridge_drv_interface *intf_fxns;
145         struct chnl_info chnl_info_obj;
146         int status = 0;
147         struct strm_object *stream_obj = strmres->stream;
148
149         if (!stream_obj) {
150                 status = -EFAULT;
151         } else {
152                 /* Have all buffers been reclaimed? If not, return
153                  * -EPIPE */
154                 intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
155                 status =
156                     (*intf_fxns->chnl_get_info) (stream_obj->chnl_obj,
157                                                      &chnl_info_obj);
158
159                 if (chnl_info_obj.cio_cs > 0 || chnl_info_obj.cio_reqs > 0)
160                         status = -EPIPE;
161                 else
162                         status = delete_strm(stream_obj);
163         }
164
165         if (status)
166                 goto func_end;
167
168         idr_remove(pr_ctxt->stream_id, strmres->id);
169 func_end:
170         dev_dbg(bridge, "%s: stream_obj: %p, status 0x%x\n", __func__,
171                 stream_obj, status);
172         return status;
173 }
174
175 /*
176  *  ======== strm_create ========
177  *  Purpose:
178  *      Create a STRM manager object.
179  */
180 int strm_create(struct strm_mgr **strm_man,
181                        struct dev_object *dev_obj)
182 {
183         struct strm_mgr *strm_mgr_obj;
184         int status = 0;
185
186         *strm_man = NULL;
187         /* Allocate STRM manager object */
188         strm_mgr_obj = kzalloc(sizeof(struct strm_mgr), GFP_KERNEL);
189         if (strm_mgr_obj == NULL)
190                 status = -ENOMEM;
191         else
192                 strm_mgr_obj->dev_obj = dev_obj;
193
194         /* Get Channel manager and Bridge function interface */
195         if (!status) {
196                 status = dev_get_chnl_mgr(dev_obj, &(strm_mgr_obj->chnl_mgr));
197                 if (!status) {
198                         (void)dev_get_intf_fxns(dev_obj,
199                                                 &(strm_mgr_obj->intf_fxns));
200                 }
201         }
202
203         if (!status)
204                 *strm_man = strm_mgr_obj;
205         else
206                 kfree(strm_mgr_obj);
207
208         return status;
209 }
210
211 /*
212  *  ======== strm_delete ========
213  *  Purpose:
214  *      Delete the STRM Manager Object.
215  */
216 void strm_delete(struct strm_mgr *strm_mgr_obj)
217 {
218         kfree(strm_mgr_obj);
219 }
220
221 /*
222  *  ======== strm_free_buffer ========
223  *  Purpose:
224  *      Frees the buffers allocated for a stream.
225  */
226 int strm_free_buffer(struct strm_res_object *strmres, u8 **ap_buffer,
227                             u32 num_bufs, struct process_context *pr_ctxt)
228 {
229         int status = 0;
230         u32 i = 0;
231         struct strm_object *stream_obj = strmres->stream;
232
233         if (!stream_obj)
234                 status = -EFAULT;
235
236         if (!status) {
237                 for (i = 0; i < num_bufs; i++) {
238                         status =
239                             cmm_xlator_free_buf(stream_obj->xlator,
240                                                 ap_buffer[i]);
241                         if (status)
242                                 break;
243                         ap_buffer[i] = NULL;
244                 }
245         }
246         drv_proc_update_strm_res(num_bufs - i, strmres);
247
248         return status;
249 }
250
251 /*
252  *  ======== strm_get_info ========
253  *  Purpose:
254  *      Retrieves information about a stream.
255  */
256 int strm_get_info(struct strm_object *stream_obj,
257                          struct stream_info *stream_info,
258                          u32 stream_info_size)
259 {
260         struct bridge_drv_interface *intf_fxns;
261         struct chnl_info chnl_info_obj;
262         int status = 0;
263         void *virt_base = NULL; /* NULL if no SM used */
264
265         if (!stream_obj) {
266                 status = -EFAULT;
267         } else {
268                 if (stream_info_size < sizeof(struct stream_info)) {
269                         /* size of users info */
270                         status = -EINVAL;
271                 }
272         }
273         if (status)
274                 goto func_end;
275
276         intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
277         status =
278             (*intf_fxns->chnl_get_info) (stream_obj->chnl_obj,
279                                                   &chnl_info_obj);
280         if (status)
281                 goto func_end;
282
283         if (stream_obj->xlator) {
284                 /* We have a translator */
285                 cmm_xlator_info(stream_obj->xlator, (u8 **) &virt_base, 0,
286                                 stream_obj->segment_id, false);
287         }
288         stream_info->segment_id = stream_obj->segment_id;
289         stream_info->strm_mode = stream_obj->strm_mode;
290         stream_info->virt_base = virt_base;
291         stream_info->user_strm->number_bufs_allowed = stream_obj->num_bufs;
292         stream_info->user_strm->number_bufs_in_stream = chnl_info_obj.cio_cs +
293             chnl_info_obj.cio_reqs;
294         /* # of bytes transferred since last call to DSPStream_Idle() */
295         stream_info->user_strm->number_bytes = chnl_info_obj.bytes_tx;
296         stream_info->user_strm->sync_object_handle = chnl_info_obj.event_obj;
297         /* Determine stream state based on channel state and info */
298         if (chnl_info_obj.state & CHNL_STATEEOS) {
299                 stream_info->user_strm->ss_stream_state = STREAM_DONE;
300         } else {
301                 if (chnl_info_obj.cio_cs > 0)
302                         stream_info->user_strm->ss_stream_state = STREAM_READY;
303                 else if (chnl_info_obj.cio_reqs > 0)
304                         stream_info->user_strm->ss_stream_state =
305                             STREAM_PENDING;
306                 else
307                         stream_info->user_strm->ss_stream_state = STREAM_IDLE;
308
309         }
310 func_end:
311         return status;
312 }
313
314 /*
315  *  ======== strm_idle ========
316  *  Purpose:
317  *      Idles a particular stream.
318  */
319 int strm_idle(struct strm_object *stream_obj, bool flush_data)
320 {
321         struct bridge_drv_interface *intf_fxns;
322         int status = 0;
323
324         if (!stream_obj) {
325                 status = -EFAULT;
326         } else {
327                 intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
328
329                 status = (*intf_fxns->chnl_idle) (stream_obj->chnl_obj,
330                                                       stream_obj->timeout,
331                                                       flush_data);
332         }
333
334         dev_dbg(bridge, "%s: stream_obj: %p flush_data: 0x%x status: 0x%x\n",
335                 __func__, stream_obj, flush_data, status);
336         return status;
337 }
338
339 /*
340  *  ======== strm_issue ========
341  *  Purpose:
342  *      Issues a buffer on a stream
343  */
344 int strm_issue(struct strm_object *stream_obj, u8 *pbuf, u32 ul_bytes,
345                       u32 ul_buf_size, u32 dw_arg)
346 {
347         struct bridge_drv_interface *intf_fxns;
348         int status = 0;
349         void *tmp_buf = NULL;
350
351         if (!stream_obj) {
352                 status = -EFAULT;
353         } else {
354                 intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
355
356                 if (stream_obj->segment_id != 0) {
357                         tmp_buf = cmm_xlator_translate(stream_obj->xlator,
358                                                        (void *)pbuf,
359                                                        CMM_VA2DSPPA);
360                         if (tmp_buf == NULL)
361                                 status = -ESRCH;
362
363                 }
364                 if (!status) {
365                         status = (*intf_fxns->chnl_add_io_req)
366                             (stream_obj->chnl_obj, pbuf, ul_bytes, ul_buf_size,
367                              (u32) tmp_buf, dw_arg);
368                 }
369                 if (status == -EIO)
370                         status = -ENOSR;
371         }
372
373         dev_dbg(bridge, "%s: stream_obj: %p pbuf: %p ul_bytes: 0x%x dw_arg:"
374                 " 0x%x status: 0x%x\n", __func__, stream_obj, pbuf,
375                 ul_bytes, dw_arg, status);
376         return status;
377 }
378
379 /*
380  *  ======== strm_open ========
381  *  Purpose:
382  *      Open a stream for sending/receiving data buffers to/from a task or
383  *      XDAIS socket node on the DSP.
384  */
385 int strm_open(struct node_object *hnode, u32 dir, u32 index,
386                      struct strm_attr *pattr,
387                      struct strm_res_object **strmres,
388                      struct process_context *pr_ctxt)
389 {
390         struct strm_mgr *strm_mgr_obj;
391         struct bridge_drv_interface *intf_fxns;
392         u32 ul_chnl_id;
393         struct strm_object *strm_obj = NULL;
394         s8 chnl_mode;
395         struct chnl_attr chnl_attr_obj;
396         int status = 0;
397         struct cmm_object *hcmm_mgr = NULL;     /* Shared memory manager hndl */
398
399         void *stream_res;
400
401         *strmres = NULL;
402         if (dir != DSP_TONODE && dir != DSP_FROMNODE) {
403                 status = -EPERM;
404         } else {
405                 /* Get the channel id from the node (set in node_connect()) */
406                 status = node_get_channel_id(hnode, dir, index, &ul_chnl_id);
407         }
408         if (!status)
409                 status = node_get_strm_mgr(hnode, &strm_mgr_obj);
410
411         if (!status) {
412                 strm_obj = kzalloc(sizeof(struct strm_object), GFP_KERNEL);
413                 if (strm_obj == NULL) {
414                         status = -ENOMEM;
415                 } else {
416                         strm_obj->strm_mgr_obj = strm_mgr_obj;
417                         strm_obj->dir = dir;
418                         strm_obj->strm_state = STREAM_IDLE;
419                         strm_obj->user_event = pattr->user_event;
420                         if (pattr->stream_attr_in != NULL) {
421                                 strm_obj->timeout =
422                                     pattr->stream_attr_in->timeout;
423                                 strm_obj->num_bufs =
424                                     pattr->stream_attr_in->num_bufs;
425                                 strm_obj->strm_mode =
426                                     pattr->stream_attr_in->strm_mode;
427                                 strm_obj->segment_id =
428                                     pattr->stream_attr_in->segment_id;
429                                 strm_obj->buf_alignment =
430                                     pattr->stream_attr_in->buf_alignment;
431                                 strm_obj->dma_chnl_id =
432                                     pattr->stream_attr_in->dma_chnl_id;
433                                 strm_obj->dma_priority =
434                                     pattr->stream_attr_in->dma_priority;
435                                 chnl_attr_obj.uio_reqs =
436                                     pattr->stream_attr_in->num_bufs;
437                         } else {
438                                 strm_obj->timeout = DEFAULTTIMEOUT;
439                                 strm_obj->num_bufs = DEFAULTNUMBUFS;
440                                 strm_obj->strm_mode = STRMMODE_PROCCOPY;
441                                 strm_obj->segment_id = 0;       /* local mem */
442                                 strm_obj->buf_alignment = 0;
443                                 strm_obj->dma_chnl_id = 0;
444                                 strm_obj->dma_priority = 0;
445                                 chnl_attr_obj.uio_reqs = DEFAULTNUMBUFS;
446                         }
447                         chnl_attr_obj.reserved1 = NULL;
448                         /* DMA chnl flush timeout */
449                         chnl_attr_obj.reserved2 = strm_obj->timeout;
450                         chnl_attr_obj.event_obj = NULL;
451                         if (pattr->user_event != NULL)
452                                 chnl_attr_obj.event_obj = pattr->user_event;
453
454                 }
455         }
456         if (status)
457                 goto func_cont;
458
459         if ((pattr->virt_base == NULL) || !(pattr->virt_size > 0))
460                 goto func_cont;
461
462         /* No System DMA */
463         /* Get the shared mem mgr for this streams dev object */
464         status = dev_get_cmm_mgr(strm_mgr_obj->dev_obj, &hcmm_mgr);
465         if (!status) {
466                 /*Allocate a SM addr translator for this strm. */
467                 status = cmm_xlator_create(&strm_obj->xlator, hcmm_mgr, NULL);
468                 if (!status) {
469                         /*  Set translators Virt Addr attributes */
470                         status = cmm_xlator_info(strm_obj->xlator,
471                                                  (u8 **) &pattr->virt_base,
472                                                  pattr->virt_size,
473                                                  strm_obj->segment_id, true);
474                 }
475         }
476 func_cont:
477         if (!status) {
478                 /* Open channel */
479                 chnl_mode = (dir == DSP_TONODE) ?
480                     CHNL_MODETODSP : CHNL_MODEFROMDSP;
481                 intf_fxns = strm_mgr_obj->intf_fxns;
482                 status = (*intf_fxns->chnl_open) (&(strm_obj->chnl_obj),
483                                                       strm_mgr_obj->chnl_mgr,
484                                                       chnl_mode, ul_chnl_id,
485                                                       &chnl_attr_obj);
486                 if (status) {
487                         /*
488                          * over-ride non-returnable status codes so we return
489                          * something documented
490                          */
491                         if (status != -ENOMEM && status !=
492                             -EINVAL && status != -EPERM) {
493                                 /*
494                                  * We got a status that's not return-able.
495                                  * Assert that we got something we were
496                                  * expecting (-EFAULT isn't acceptable,
497                                  * strm_mgr_obj->chnl_mgr better be valid or we
498                                  * assert here), and then return -EPERM.
499                                  */
500                                 status = -EPERM;
501                         }
502                 }
503         }
504         if (!status) {
505                 status = drv_proc_insert_strm_res_element(strm_obj,
506                                                         &stream_res, pr_ctxt);
507                 if (status)
508                         delete_strm(strm_obj);
509                 else
510                         *strmres = (struct strm_res_object *)stream_res;
511         } else {
512                 (void)delete_strm(strm_obj);
513         }
514
515         dev_dbg(bridge, "%s: hnode: %p dir: 0x%x index: 0x%x pattr: %p "
516                 "strmres: %p status: 0x%x\n", __func__,
517                 hnode, dir, index, pattr, strmres, status);
518         return status;
519 }
520
521 /*
522  *  ======== strm_reclaim ========
523  *  Purpose:
524  *      Relcaims a buffer from a stream.
525  */
526 int strm_reclaim(struct strm_object *stream_obj, u8 **buf_ptr,
527                         u32 *nbytes, u32 *buff_size, u32 *pdw_arg)
528 {
529         struct bridge_drv_interface *intf_fxns;
530         struct chnl_ioc chnl_ioc_obj;
531         int status = 0;
532         void *tmp_buf = NULL;
533
534         if (!stream_obj) {
535                 status = -EFAULT;
536                 goto func_end;
537         }
538         intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
539
540         status =
541             (*intf_fxns->chnl_get_ioc) (stream_obj->chnl_obj,
542                                             stream_obj->timeout,
543                                             &chnl_ioc_obj);
544         if (!status) {
545                 *nbytes = chnl_ioc_obj.byte_size;
546                 if (buff_size)
547                         *buff_size = chnl_ioc_obj.buf_size;
548
549                 *pdw_arg = chnl_ioc_obj.arg;
550                 if (!CHNL_IS_IO_COMPLETE(chnl_ioc_obj)) {
551                         if (CHNL_IS_TIMED_OUT(chnl_ioc_obj)) {
552                                 status = -ETIME;
553                         } else {
554                                 /* Allow reclaims after idle to succeed */
555                                 if (!CHNL_IS_IO_CANCELLED(chnl_ioc_obj))
556                                         status = -EPERM;
557
558                         }
559                 }
560                 /* Translate zerocopy buffer if channel not canceled. */
561                 if (!status
562                     && (!CHNL_IS_IO_CANCELLED(chnl_ioc_obj))
563                     && (stream_obj->strm_mode == STRMMODE_ZEROCOPY)) {
564                         /*
565                          *  This is a zero-copy channel so chnl_ioc_obj.buf
566                          *  contains the DSP address of SM. We need to
567                          *  translate it to a virtual address for the user
568                          *  thread to access.
569                          *  Note: Could add CMM_DSPPA2VA to CMM in the future.
570                          */
571                         tmp_buf = cmm_xlator_translate(stream_obj->xlator,
572                                                        chnl_ioc_obj.buf,
573                                                        CMM_DSPPA2PA);
574                         if (tmp_buf != NULL) {
575                                 /* now convert this GPP Pa to Va */
576                                 tmp_buf = cmm_xlator_translate(stream_obj->
577                                                                xlator,
578                                                                tmp_buf,
579                                                                CMM_PA2VA);
580                         }
581                         if (tmp_buf == NULL)
582                                 status = -ESRCH;
583
584                         chnl_ioc_obj.buf = tmp_buf;
585                 }
586                 *buf_ptr = chnl_ioc_obj.buf;
587         }
588 func_end:
589         dev_dbg(bridge, "%s: stream_obj: %p buf_ptr: %p nbytes: %p "
590                 "pdw_arg: %p status 0x%x\n", __func__, stream_obj,
591                 buf_ptr, nbytes, pdw_arg, status);
592         return status;
593 }
594
595 /*
596  *  ======== strm_register_notify ========
597  *  Purpose:
598  *      Register to be notified on specific events for this stream.
599  */
600 int strm_register_notify(struct strm_object *stream_obj, u32 event_mask,
601                                 u32 notify_type, struct dsp_notification
602                                 *hnotification)
603 {
604         struct bridge_drv_interface *intf_fxns;
605         int status = 0;
606
607         if (!stream_obj) {
608                 status = -EFAULT;
609         } else if ((event_mask & ~((DSP_STREAMIOCOMPLETION) |
610                                    DSP_STREAMDONE)) != 0) {
611                 status = -EINVAL;
612         } else {
613                 if (notify_type != DSP_SIGNALEVENT)
614                         status = -ENOSYS;
615
616         }
617         if (!status) {
618                 intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
619
620                 status =
621                     (*intf_fxns->chnl_register_notify) (stream_obj->
622                                                             chnl_obj,
623                                                             event_mask,
624                                                             notify_type,
625                                                             hnotification);
626         }
627
628         return status;
629 }
630
631 /*
632  *  ======== strm_select ========
633  *  Purpose:
634  *      Selects a ready stream.
635  */
636 int strm_select(struct strm_object **strm_tab, u32 strms,
637                        u32 *pmask, u32 utimeout)
638 {
639         u32 index;
640         struct chnl_info chnl_info_obj;
641         struct bridge_drv_interface *intf_fxns;
642         struct sync_object **sync_events = NULL;
643         u32 i;
644         int status = 0;
645
646         *pmask = 0;
647         for (i = 0; i < strms; i++) {
648                 if (!strm_tab[i]) {
649                         status = -EFAULT;
650                         break;
651                 }
652         }
653         if (status)
654                 goto func_end;
655
656         /* Determine which channels have IO ready */
657         for (i = 0; i < strms; i++) {
658                 intf_fxns = strm_tab[i]->strm_mgr_obj->intf_fxns;
659                 status = (*intf_fxns->chnl_get_info) (strm_tab[i]->chnl_obj,
660                                                           &chnl_info_obj);
661                 if (status) {
662                         break;
663                 } else {
664                         if (chnl_info_obj.cio_cs > 0)
665                                 *pmask |= (1 << i);
666
667                 }
668         }
669         if (!status && utimeout > 0 && *pmask == 0) {
670                 /* Non-zero timeout */
671                 sync_events = kmalloc(strms * sizeof(struct sync_object *),
672                                                                 GFP_KERNEL);
673
674                 if (sync_events == NULL) {
675                         status = -ENOMEM;
676                 } else {
677                         for (i = 0; i < strms; i++) {
678                                 intf_fxns =
679                                     strm_tab[i]->strm_mgr_obj->intf_fxns;
680                                 status = (*intf_fxns->chnl_get_info)
681                                     (strm_tab[i]->chnl_obj, &chnl_info_obj);
682                                 if (status)
683                                         break;
684                                 else
685                                         sync_events[i] =
686                                             chnl_info_obj.sync_event;
687
688                         }
689                 }
690                 if (!status) {
691                         status =
692                             sync_wait_on_multiple_events(sync_events, strms,
693                                                          utimeout, &index);
694                         if (!status) {
695                                 /* Since we waited on the event, we have to
696                                  * reset it */
697                                 sync_set_event(sync_events[index]);
698                                 *pmask = 1 << index;
699                         }
700                 }
701         }
702 func_end:
703         kfree(sync_events);
704
705         return status;
706 }
707
708 /*
709  *  ======== delete_strm ========
710  *  Purpose:
711  *      Frees the resources allocated for a stream.
712  */
713 static int delete_strm(struct strm_object *stream_obj)
714 {
715         struct bridge_drv_interface *intf_fxns;
716         int status = 0;
717
718         if (stream_obj) {
719                 if (stream_obj->chnl_obj) {
720                         intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
721                         /* Channel close can fail only if the channel handle
722                          * is invalid. */
723                         status = (*intf_fxns->chnl_close)
724                                         (stream_obj->chnl_obj);
725                 }
726                 /* Free all SM address translator resources */
727                 kfree(stream_obj->xlator);
728                 kfree(stream_obj);
729         } else {
730                 status = -EFAULT;
731         }
732         return status;
733 }