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