1    /* 
     2     * Copyright (c) 2012, Texas Instruments Incorporated
     3     * All rights reserved.
     4     *
     5     * Redistribution and use in source and binary forms, with or without
     6     * modification, are permitted provided that the following conditions
     7     * are met:
     8     *
     9     * *  Redistributions of source code must retain the above copyright
    10     *    notice, this list of conditions and the following disclaimer.
    11     *
    12     * *  Redistributions in binary form must reproduce the above copyright
    13     *    notice, this list of conditions and the following disclaimer in the
    14     *    documentation and/or other materials provided with the distribution.
    15     *
    16     * *  Neither the name of Texas Instruments Incorporated nor the names of
    17     *    its contributors may be used to endorse or promote products derived
    18     *    from this software without specific prior written permission.
    19     *
    20     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    21     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
    22     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
    23     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
    24     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
    25     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    26     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
    27     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
    28     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
    29     * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
    30     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    31     * */
    32    /*
    33     *  ======== Stream.xdc ========
    34     *
    35     */
    36    
    37    import xdc.rov.ViewInfo;
    38    
    39    import xdc.runtime.Error;
    40    import xdc.runtime.Assert;
    41    import xdc.runtime.IHeap;
    42    import xdc.runtime.IGateProvider;
    43    import ti.sdo.utils.List;
    44    import ti.sdo.utils.NameServer;
    45    import xdc.runtime.knl.Sync;
    46    import xdc.runtime.knl.ISync;
    47    
    48    /*!
    49     *  ======== Stream ========
    50     *
    51     *  Module to stream data to/from a driver.
    52     *
    53     *  This module offers both the issue/reclaim model and the read/write model to 
    54     *  send and receive data from drivers. 
    55     *
    56     *  In the issue/reclaim model, the client calls {@link #issue} when he has
    57     *  a buffer of data. issue() is non-blocking and returns. The buffer 
    58     *  has been issued for IO. To get the buffer back the client has to call 
    59     *  {@link #reclaim}. A call to reclaim() can block. Upon return from reclaim(),
    60     *  the client can re-use his buffer. 
    61     *
    62     *  The client can issue many buffers before reclaiming them.
    63     *  Buffers are always reclaimed in the order that they were issued.
    64     *  The client can optionally pass a user argument to issue().
    65     *
    66     *  In the read/write model, clients will call {@link #read} or {@link #write}
    67     *  to send/receive data. Here the client may block until buffer is ready or 
    68     *  a timeout occurs.
    69     *
    70     *  Stream also provides {@link #control} to send down driver specific control 
    71     *  commands. There is {@link #abort} function to abort the stream.
    72     *
    73     *  Stream also maintains a name table of {@link IConverter} handles. 
    74     *  This table is used by Stream to create an IO stack. The name passed to
    75     *  {@link #create} is usually of the form "/scale/uart". This name may
    76     *  correspond to the following IO stack.
    77     *
    78     *         Stream Instance
    79     *
    80     *                 |
    81    
    82     *                 V
    83     *
    84     *         IConverter Instance (/scale)
    85     *
    86     *                 |
    87     *
    88     *                 V
    89     *
    90     *         IDriver Instance (/uart)
    91     *
    92     *  In this case the Stream requires "/scale" to be in its IConverter table 
    93     *  and "/uart" to be in {@link DriverTable}. The IConverter table associates
    94     *  a name with an IConverter Handle. Note that these names have to be of the
    95     *  form "/name1".
    96     *
    97     *  This module uses {@link ti.sdo.utils.NameServer} to maintain its IConverter
    98     *  table
    99     *
   100     *  Stream uses the {@link xdc.runtime.knl.Sync} module for synchronization.
   101     *  Stream will call {@link xdc.runtime.knl.Sync#signal} when IO completes and
   102     *  {@link xdc.runtime.knl.Sync#wait} to wait for IO completion.
   103     *
   104     *  Stream will create a Sync.Handle passing NULL for ISync 
   105     *  handle to {@link #create}. 
   106     */
   107    
   108    @InstanceFinalize
   109    @InstanceInitError
   110    @ModuleStartup
   111    
   112    module Stream 
   113    {
   114        const UInt INPUT = 0;       /*! mode for input */
   115        const UInt OUTPUT = 1;      /*! mode for output */
   116        const UInt INOUT = 2;       /*! mode for input & output */
   117        
   118        /*! 
   119         *  Error raised when name not found in IConverter Table and DriverTable.
   120         */
   121        config Error.Id E_notFound  = {
   122            msg: "E_notFound: %s name not found"
   123        };
   124        
   125        /*! 
   126         *  Error raised when there are no packets for IO
   127         */
   128        config Error.Id E_noPackets  = {
   129            msg: "E_noPackets: No packets available. maxIssues is %d"
   130        };
   131    
   132        /*! 
   133         *  Error raised when reclaim called but no outstanding buffers issued
   134         *
   135         *  Clients can check for this error while calling {@link #reclaim} to make 
   136         *  sure they got all their buffers back.
   137         *  @p(code)
   138         *  #include <xdc/runtime/Error.h>
   139         *  #include <ti/sdo/io/Stream.h>
   140         *
   141         *  Error_Block eb;
   142         *  Stream_Handle streamHdl;
   143         *  SizeT len;
   144         *  Ptr *bufp;
   145         *  
   146         *  Error_init(&eb); 
   147         *  
   148         *  do {
   149         *      len = Stream_reclaim(streamHdl, bufp, NULL, &eb); 
   150         *  }while (!Error_check(&eb));
   151         *  
   152         *  if (Error_getId == Stream_E_noBuffersIssued) {
   153         *      ....all issues buffers have been reclaimed
   154         *  }
   155         *  @p
   156         *  
   157         */
   158        config Error.Id E_noBuffersIssued  = {
   159            msg: "E_noBuffersIssued: No outstanding buffers"
   160        };
   161    
   162        /*! 
   163         *  Error raised when a timeout occurs during reclaim
   164         */
   165        config Error.Id E_timeout  = {
   166            msg: "E_timeout: Timeout"
   167        };    
   168    
   169        /*! 
   170         *  Assert when {@link #read} or {@link #write} on wrong channel
   171         *
   172         *  Assert when {@link #read} is called and mode = {@link #OUTPUT} or
   173         *  when {@link #write} is called and mode = {@link #INPUT}
   174         */
   175        config Assert.Id A_badMode  = {
   176            msg: "A_badMode: Bad Mode"
   177        };
   178    
   179        /*! 
   180         *  Assert when there are more packets to be reclaimed
   181         */
   182        config Assert.Id A_pendingReclaims  = {
   183            msg: "A_pendingReclaims: Packets issued but not reclaimed"
   184        };
   185    
   186        /*! 
   187         *  Assert when ISync is non-blocking but Stream_read/write called
   188         */
   189        config Assert.Id A_syncNonBlocking  = {
   190            msg: "A_syncNonBlocking: ISync should have blocking quality"
   191        };
   192    
   193        /*! 
   194         *  Max entries that can be added at runtime
   195         *
   196         *  This module requires total number of converters that need
   197         *  to be added at runtime to be identified at configuration time.
   198         */
   199        config UInt maxRuntimeEntries = 0;
   200    
   201        /*! 
   202         *  For making the table thread safe.
   203         */
   204        config IGateProvider.Handle gate = null;
   205        
   206        /*! 
   207         *  Length, in MAUs, of the name field in the table.
   208         */
   209        config UInt maxNameLen = 16;
   210    
   211        /*! 
   212         *  Section name used to place the IConverter table.
   213         */
   214        metaonly config String tableSection = null;
   215        
   216        metaonly struct BasicView {
   217            String              label;
   218            UInt                maxIssues;
   219            UInt                issued;
   220            UInt                ready;
   221            String              mode;
   222            Bool                userSuppliedSync;
   223            //List.Object        abortList;      /* reclaimed abort packets */
   224        }
   225        
   226        @Facet
   227        metaonly config ViewInfo.Instance rovViewInfo = 
   228            ViewInfo.create({
   229                viewMap: [
   230                    ['Basic', {type: ViewInfo.INSTANCE, viewInitFxn: 'viewInitBasic', structName: 'BasicView'}],
   231                ]
   232            });
   233    
   234        /*!
   235         *  ======== add ========
   236         *  Add to IConverter table at runtime.
   237         *
   238         *  This API is not thread safe. Set {@link #gate} parameter
   239         *  to protect table if called from multiple threads.
   240         *
   241         *  @param(name)    Name of entry
   242         *  @param(handle)  IConverter handle
   243         *  @param(eb)      Error Block
   244         */
   245        Void add(String name, IConverter.Handle handle,  Error.Block *eb);
   246    
   247        /*!
   248         *  ======== addMeta ========
   249         *  Add to IConverter table at configuration time.
   250         *
   251         *  @param(name)            name of entry
   252         *  @param(handle)          IConverter handle
   253         */
   254        metaonly Void addMeta(String name, IConverter.Handle handle);
   255    
   256        /*!
   257         *  ======== remove ========
   258         *  Remove entry from IConverter table at runtime.
   259         *
   260         *  This API is not thread safe. Set {@link #gate} parameter
   261         *  to protect table if called from multiple threads.
   262         *
   263         *  @param(name)    name of entry
   264         *  @param(eb)      error block
   265         */
   266        Void remove(String name, Error.Block *eb);
   267    
   268        /*! 
   269         * @_nodoc
   270         * Match a name to name in IConverter table. return length matched. 
   271         */
   272        Int match(String name, IConverter.Handle *handle, Error.Block *eb);    
   273    
   274        /*! 
   275         *  @_nodoc
   276         *  io completed log functions called by DriverAdapter 
   277         */
   278        Void completedLog(UArg buf, UArg size, UArg arg);
   279        
   280    instance:
   281    
   282        /*! Max outstanding issues */
   283        config UInt maxIssues = 2;
   284    
   285        /*!  Heap used to allocate {@link DriverTypes#Packet} in dynamic create */
   286        config IHeap.Handle packetHeap = null;
   287        
   288        /*!
   289         *  Section name used to place {@link DriverTypes#Packet}
   290         * 
   291         *  Default of null results in no explicit section placement.
   292         */
   293        metaonly config String packetSection = null;
   294    
   295        /*! ISync handle used to signal IO completion */
   296        config ISync.Handle sync = null;
   297    
   298        /*! Channel params for driver if present in IO stack */
   299        config UArg chanParams = null;
   300        
   301        /*!
   302         *  ======== create ========
   303         *  Create a Stream Instance.
   304         *
   305         *  Creates a new Stream instance and sets up the IO stack specified by 
   306         *  name.
   307         *  The name is usually of the following form "/scale/uart".
   308         *  The mode is either {@link #INPUT} or {@link #OUTPUT}.
   309         *
   310         *  @param(name)    name that identifies the IO stack
   311         *  @param(mode)    mode of channel.
   312         */
   313        create(String name, UInt mode);
   314    
   315        /*!
   316         *  ======== issue ========
   317         *  Issue a buffer to the stream.
   318         *
   319         *  This function issues a buffer to the stream for IO. This API is
   320         *  non-blocking.
   321         *
   322         *  Failure of issue() indicates that the stream was not able to accept the
   323         *  buffer being issued or that there was a error from the underlying
   324         *  IConverter or IDriver. Note that the error could be driver specific.
   325         *  If issue() fails because of an underlying driver problem
   326         *  {@link #abort} should be called before attempting more I/O through the 
   327         *  stream.
   328         *
   329         *  The interpretation of the logical size of a buffer, is 
   330         *  direction dependent.
   331         *  For a stream opened in {@link DriverTypes#OUTPUT} mode, the logical size
   332         *  of the buffer indicates the number of minimum addressable units of of 
   333         *  data it contains. 
   334         *
   335         *  For a stream opened in {@link DriverTypes#INPUT} mode, the logical size 
   336         *  of a buffer indicates the number of minimum addressable units being 
   337         *  requested by the client. In either case, the logical size of the buffer 
   338         *  must be less than or equal to the physical size of the buffer.
   339         *
   340         *  issue() is used in conjunction with {@link #reclaim}. The issue() call 
   341         *  sends a buffer to a stream, and reclaim() retrieves a buffer 
   342         *  from a stream. In normal operation each issue() call is followed by an 
   343         *  reclaim() call.
   344         *
   345         *  Short bursts of multiple issue() calls can be made without an
   346         *  intervening reclaim() call followed by short bursts of reclaim() calls, 
   347         *  but over the life of the stream issue() and reclaim() must be called 
   348         *  the same number of times. The number of issue() calls can exceed the 
   349         *  number of reclaim() calls by {@link #maxIssues}.
   350         *
   351         *  The client argument is not interpreted by Stream or the underlying 
   352         *  modules, but is offered as a service to the stream client. All compliant
   353         *  device drivers preserve the value of arg and maintain its association 
   354         *  with the data that it was issued with. arg provides a method for a 
   355         *  client to associate additional information with a particular buffer of 
   356         *  data. The arg is returned during reclaim().
   357         *
   358         *  @param(buf)    buffer pointer
   359         *  @param(size)    size of buffer
   360         *  @param(arg)     app arg
   361         *  @param(eb)      error block
   362         *  
   363         */
   364        Void issue(Ptr buf, SizeT size, UArg arg, Error.Block *eb);
   365    
   366        /*!
   367         *  ======== reclaim ========
   368         *  Reclaim a buffer that was previously issued by calling {@link #issue}.
   369         *
   370         *  reclaim() is used to request a buffer back from a stream. 
   371         *
   372         *  If a stream was created in {@link DriverTypes#OUTPUT} mode, then 
   373         *  reclaim() returns a processed buffer, and size is zero.
   374         *  If a stream was opened in {@link DriverTypes#INPUT} mode, reclaim() 
   375         *  returns a full buffer, and size is the number of minimum addressable 
   376         *  units of data in the buffer.
   377         *
   378         *  reclaim() blocks until a buffer can be returned to the caller, or until 
   379         *  a timeout occurs.
   380         *
   381         *  Failure of reclaim() indicates that no buffer was returned to 
   382         *  the  client. Therefore, if reclaim() fails, the client should 
   383         *  not attempt to de-reference pbufp, since it is not guaranteed to contain
   384         *  a valid buffer pointer.
   385         *
   386         *  reclaim() is used in conjunction with {@link #issue} to operate 
   387         *  a stream. The issue() call sends a buffer to a stream, and 
   388         *  reclaim() retrieves a  buffer from a stream. In normal operation
   389         *  each issue call is followed by an reclaim call.
   390         *
   391         *  Short bursts of multiple issue() calls can be made without an
   392         *  intervening reclaim() call followed by short bursts of reclaim() calls, 
   393         *  but over the life of the stream issue() and reclaim() must be called 
   394         *  the same number of times. The number of issue() calls can exceed the 
   395         *  number of reclaim() calls by {@link #maxIssues}.
   396         *
   397         *  A reclaim() call should not be made without at least one 
   398         *  outstanding issue() call. Calling reclaim() with no 
   399         *  outstanding issue() calls results in an error {@link #E_noBuffersIssued}
   400         *
   401         *  reclaim() only returns buffers that were passed in using issue(). It 
   402         *  also returns the buffers in the same order that they were issued.
   403         *
   404         *  reclaim() returns the size transferred in case of success.
   405         *  It returns zero when an error is caught. In case of timeout, the error 
   406         *  is {@link #E_timeout}.
   407         *
   408         *  @param(pbufp)       returned buffer pointer
   409         *  @param(timeout)     timeout in microseconds
   410         *  @param(parg)        pointer to client arg. Can be null.
   411         *  @param(eb)          error block
   412         *  @b(returns)         size transferred
   413         *  
   414         */
   415        SizeT reclaim(Ptr *pbufp, UInt timeout, UArg *parg, Error.Block *eb);
   416    
   417        /*!
   418         *  ======== read ========
   419         *  Read data from a stream.
   420         *
   421         *  Equivalent to an issue/reclaim pair for a instance with 
   422         *  mode = DriverTypes.INPUT. This call is synchronous and the buffer
   423         *  has data upon return from this API.
   424         *
   425         *  @param(bufp)        buffer pointer
   426         *  @param(size)        size of buffer
   427         *  @param(timeout)     timeout in microseconds
   428         *  @param(eb)          error block
   429         *  @b(returns)         size transferred
   430         */
   431        SizeT read (Ptr bufp, SizeT size, UInt timeout, Error.Block *eb);  
   432    
   433        /*!
   434         *  ======== write ========
   435         *  Write data to a stream
   436         *
   437         *  Equivalent to an issue/reclaim pair for a instance with 
   438         *  mode = DriverTypes.OUTPUT.
   439         *  This call is synchronous and the driver has finished processing the
   440         *  buffer upon return from this API.
   441         *
   442         *  @param(bufp)    buffer pointer
   443         *  @param(size)    size of buffer
   444         *  @param(timeout) timeout in microseconds
   445         *  @param(eb)      error block
   446         *  @b(returns)     size transferred
   447         */
   448        SizeT write (Ptr bufp, SizeT size, UInt timeout, Error.Block *eb);  
   449    
   450        /*!
   451         *  ======== submit ========
   452         *  @_nodoc
   453         *  Convenience API to send driver specific command.
   454         *
   455         *  Equivalent to an issue/reclaim pair for a instance with 
   456         *  driver specific command.
   457         *
   458         *  @param(bufp)    buffer pointer
   459         *  @param(size)    size of buffer
   460         *  @param(cmd)     driver specific packet command
   461         *  @param(timeout) timeout in microseconds
   462         *  @param(eb)      error block
   463         *  @b(returns)     size transferred
   464         */
   465        SizeT submit (Ptr bufp, SizeT size, DriverTypes.PacketCmd cmd, UInt timeout, Error.Block *eb); 
   466        
   467        /*!
   468         *  ======== control ========
   469         *  Send a control command to the driver.
   470         *
   471         *  @param(cmd)     device specific command
   472         *  @param(cmdArg)  command specific arg
   473         *  @param(eb)      error block
   474         */
   475        Void control(DriverTypes.ControlCmd cmd, UArg cmdArg, Error.Block *eb);
   476      
   477        /*!
   478         *  ======== abort ========
   479         *  Abort all pending IO.
   480         *
   481         *  The underlying device connected to stream is idled as a result of 
   482         *  calling abort and all buffers are ready for reclaim().
   483         *
   484         *  The client still needs to call {@link #reclaim} to get back his
   485         *  buffers. However the client will NOT block when calling reclaim()
   486         *  after an abort().
   487         *
   488         *  @param(eb)              error block
   489         *  @b(returns)             number of buffers aborted
   490         */
   491        UInt abort(Error.Block *eb);
   492    
   493        /*!
   494         *  ======== prime ========
   495         *  Prime an {@link #OUTPUT} stream instance.
   496         *
   497         *  This API facilitates buffering of an output channel. Consider a
   498         *  task that constantly gets data from input channel and sends to an 
   499         *  output channel. To start with it may want to issue buffers to the 
   500         *  input channel and output channel to enable double buffering.
   501         *  For an input channel there is no problem. For an output channel however
   502         *  the buffer data is sent out through the peripheral and in the case of a
   503         *  heterogenous system, the data will be sent to the other processor.
   504         *
   505         *  In such cases where the driver cannot handle dummy buffers, 
   506         *  Stream_prime can be used to make buffers available instantly for 
   507         *  reclaim without actually sending the buffers to the driver. 
   508         *  This API is non-blocking.
   509         *
   510         *  The primary use of prime() is used when applications want to prime
   511         *  an output channel at startup, without sending data to the driver.
   512         *  This allows them to reclaim and issue in their task.
   513         *  
   514         *  Failure of prime() indicates that the stream was not able to accept the
   515         *  buffer being issued  due to un-avaibailibity of IO packets.
   516         *
   517         *  The client argument is not interpreted by Stream.
   518         *
   519         *  @param(buf)     buffer pointer
   520         *  @param(arg)     app arg
   521         *  @param(eb)      error block
   522         */
   523        Void prime(Ptr buf, UArg arg, Error.Block *eb);
   524    
   525    internal:
   526    
   527        /*!
   528         *  Structure of entry in IConverter Table
   529         *
   530         *  @field(name)
   531         *  Name of table entry.
   532         *
   533         *  @field(handle)
   534         *  {@link IConverter#Handle} instance to be used in the IO stack
   535         *
   536         */
   537        struct Entry {
   538            String              name;
   539            IConverter.Handle   handle;
   540        };
   541        
   542        /*! 
   543         *  Array for all statically configured IConverter table entries 
   544         */
   545        metaonly config Entry staticEntries[];
   546            
   547        /*! callback for lower layer */
   548        Void internalCallback(UArg arg);
   549    
   550        /*! instance postInit */
   551        Int postInit(Object *obj, Error.Block *eb);
   552       
   553        /*! extension to pass down driver specific command */
   554        Void issueX(Object *obj, Ptr bufp, SizeT size, UArg arg, 
   555            DriverTypes.PacketCmd cmd, Error.Block *eb);
   556       
   557        /* -------- Internal Structures -------- */
   558        struct Instance_State {
   559            String              name;           /* name used to create inst */
   560            UArg                chanParams;     /* used to open IConverter */
   561            Bool                drvAdapHdl;     /* Created DriverAdapter */
   562            DriverTypes.Packet  packets[];      /* used only in static create */
   563            UInt                maxIssues;      /* used only in static create */
   564            UInt                issued;         /* # bufs issued */
   565            UInt                ready;          /* # bufs ready for reclaim */
   566            UInt                mode;           /* input or output */
   567            IHeap.Handle        packetHeap;     /* heap used to alloc packets */
   568            ISync.Handle        complete;       /* completion sync */
   569            Bool                userSync;       /* user supplied sync handle*/
   570            IConverter.Handle   convHandle;     /* handle to IConverter below */
   571            List.Object         freeList;       /* free packets */
   572        };
   573    
   574        /* -------- Internal Structures -------- */
   575        struct Module_State {
   576            NameServer.Handle   convTable;    /* IConverter table */
   577        };
   578    }
   579    /*
   580     *  @(#) ti.sdo.io; 1, 0, 0, 0,1; 5-22-2012 16:16:42; /db/vtree/library/trees/ipc/ipc-h32/src/ xlibrary
   581    
   582     */
   583