linux/drivers/staging/tidspbridge/rmgr/strm.c
<<
>>
Prefs
   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 */
  53struct 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 */
  64struct 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 */
  85static int delete_strm(struct strm_object *stream_obj);
  86
  87/*
  88 *  ======== strm_allocate_buffer ========
  89 *  Purpose:
  90 *      Allocates buffers for a stream.
  91 */
  92int 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
 132func_end:
 133        return status;
 134}
 135
 136/*
 137 *  ======== strm_close ========
 138 *  Purpose:
 139 *      Close a stream opened with strm_open().
 140 */
 141int 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);
 169func_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 */
 180int 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 */
 216void 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 */
 226int 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 */
 256int 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        }
 310func_end:
 311        return status;
 312}
 313
 314/*
 315 *  ======== strm_idle ========
 316 *  Purpose:
 317 *      Idles a particular stream.
 318 */
 319int 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 */
 344int 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 */
 385int 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        }
 476func_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 */
 526int 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        }
 588func_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 */
 600int 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 */
 636int 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        }
 702func_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 */
 713static 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}
 734