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