Abstract:
The invention provides the data flow communication control between the source (flash/IO) and destination (IO/flash) cores. The source and destination cores are started simultaneously instead of serially and get instructions from the descriptors provided and set-up by the processor. Each source and destination core&#39;s descriptors 1  are correlated or tied with each other by the processor by providing information to the hardware assist mechanism. The hardware assist mechanism responsible for moderating the data transfer from source to destination. The flow tracker guarantees that data needed by destination exists.  1  Descriptors are set of instructions that is used to activate the DMA controller. 
     By applying the invention to the prior approach/solution, the data latency between the flash &amp; IO bus will be reduced. Processor interrupts will be minimized while data transfer between the flash &amp; IO bus is ongoing.

Description:
CROSS-REFERENCE(S) TO RELATED APPLICATIONS 
     This application claims the benefit of and priority to U.S. Provisional Application 61/802,367, filed 15 Mar. 2013. This U.S. Provisional Application 61/802,367 is hereby fully incorporated herein by reference. 
    
    
     BACKGROUND 
     1. Field 
     The present invention relates to a data storage system which is applied to a computer system, that includes volatile (e.g. SRAM, SDRAM) and non-volatile (e.g. flash memory, mechanical hard disk) storage components. 
     2. Description of the Related Art 
     In conventional storage device system, data transfer from memory to IO bus has to go through an intermediate volatile memory (cache). Data transfer therefore can be completed in two steps—data is transferred from memory to cache and then from cache to the IO bus. Memory-to-cache data transfer is handled by one DMA engine and another DMA engine for cache-to-IO bus data transfer. To start the transfer, the processor prepares the DMA transfer from memory to cache. Upon completion of the memory-to-cache transfer, the processor is interrupted to prepare the transfer from cache to IO. While the first data buffer in the cache is being drained, another data buffer can be filled concurrently in memory. The data transfer continues in this fashion, two DMA engines operating in parallel utilizing multiple data buffer spaces in the cache. Notice that in between transfers, the processor has to intervene to setup the next transfer utilizing the precious processor cycles. Note that each of the transfers, memory-to-cache and cache-to-IO, can also be handled using two or more DMA engines; either DMA engines are used sequentially or simultaneously. 
    
    
     
       BRIEF DESCRIPTION OF THE DRAWINGS 
         FIG. 1  is a diagram illustrating the conventional way of transferring data from memory (flash) to IO bus where the processor must periodically interfere with the transfer. 
         FIG. 2  is a diagram illustrating the novel way of transferring data from memory (flash) to IO bus where the process is handled with less intervention from the processor. 
         FIG. 3  is a diagram illustrating the conventional way of transferring data from IO bus to memory (flash) where the processor must periodically interfere with the transfer. 
         FIG. 4  is a diagram illustrating the novel way of transferring data from IO bus to memory (flash) where the process is handled with less intervention from the processor. 
         FIG. 5  is a diagram illustrating the DMA process with dependency from memory (flash) to IO bus. 
         FIG. 6  is a diagram illustrating the DMA process with dependency from IO bus to memory (flash). 
         FIG. 7  is a diagram illustrating a variation of DMA process with dependency from memory (flash) to IO bus with the addition of a third DMA engine for intermediate processing. 
         FIG. 8  is a diagram illustrating a variation of DMA process with dependency from IO bus to memory (flash) with the addition of a third DMA engine for intermediate processing. 
         FIG. 9  is a diagram illustrating another variation of DMA process with dependency with the addition of a third DMA engine for intermediate processing by performing XOR operation. 
         FIG. 10  is a diagram illustrating the Data Buffer-Descriptor-Dependency Table relationship. 
     
    
    
     DETAILED DESCRIPTION 
     In conventional storage device system as shown in  FIG. 1 , where data has to be transferred from memory  103  to cache  104 , the processor has to periodically interfere the process preparing and enabling DMA engines between transfer boundaries. Before a DMA transfer can start, information like the source and destination start address, size of the data to transfer, etc are normally supplied first. One set of this information can be called as descriptor. Instead of preparing another descriptor after completing a DMA transfer just before starting the next transfer, it can be done more efficiently by initially preparing a reasonable number of descriptors then let the DMA engines do the fetching, decoding and execution of descriptors by itself. The FW then will just keep adding more descriptors to the list of descriptors. In  FIG. 1 , DMA 1   101  has to do 4 DMA transfers from memory  103  to cache  104  utilizing 4 data buffers. DMA 2   102  has to transfer the data from data buffers to the IO bus. DMA 1   101  and DMA 2   102  will need 4 descriptors each. Assuming that all descriptors have already been prepared, DMA 1   101  now has to start transferring data. After DMA 1   101  has filled the first data buffer  105 , the FW is notified through interrupt. FW then enables the corresponding descriptor  106  of DMA 2   102 . The rest of the descriptors will not be enabled since the corresponding data buffers are not yet ready for draining. DMA 2102  starts draining the first data buffer  105  while DMA 1   101  is filling up the next data buffer  107 . The processor is interrupted again after DMA 1   101  has filled up the second data buffer  107 . FW enables the next descriptor  108  so DMA 2   102  can start draining the second data buffer  107  as soon as it is done with the first data buffer  105 . The sequence continues until all 4 data buffers are filled from memory  103  and drained to the IO bus. Notice that the processor is interrupted each time DMA 1   101  has finished filling up a data buffer. Note also that DMA 2   102  must interrupt the processor after draining a data buffer to free up the used resources. The above process can be improved by minimizing the intervention of the processor. This means that while DMA 1   101  is filling up a data buffer, DMA 2   102  must have a way to know when it can start draining the data buffer and that DMA 2   102  must have a way to free up used resources all without the help of the processor. This can be done with the use of a dependency table  209  as shown in  FIG. 2 . 
     The Index field  210  in the dependency table  209  corresponds to a transfer where all the descriptors  206 ,  208  &amp;  212  of the DMA controllers  201  &amp;  202  are tied to. An Index contains 3 Buffers  210 , BufRdy 0 , BufRdy 1  and BufRdy 2 . A Buffer may hold the sub-indices of an Index of the DMA controllers involved in the transfer. For example, BufRdy 0  may hold the sub-indices of DMA 1   201 . Each bit in the BufRdy field corresponds to a sub-index  211  which is a section stored/fetched on single cache buffer  205  &amp;  207  on the SDRAM/SRAM. A sub-index  210  is said to be “allocated or pending” when its bit is set to 0 and “done” when set to its default value of 1. An Index field  210  is considered to be “free” when all the sub-indices of the 3 Buffers  210  are “done”. Assuming a read command is received from the IO bus, the FW recognizes that the requested data is in the memory  203 . The FW prepares the descriptors for DMA 2   202 . During preparation of DMA 2   202  first descriptor  206 , the processor checks the dependency table  209  to see if there is an available Index  210 . The processor sees Index 0 is free. Index number 0 is assigned to DMA 2   202  first descriptor  206 . The processor allocates the sub-index  211  bits, from 1 to 0, of Index 0 based on the section(s) of the data buffers  205  &amp;  207  that to be used in data transfer and for example, the processor assigns BufRdy 0  sub-indices  211  to DMA 1   201  as the Source and BufRdy 1  sub-indices  211  to DMA 2   202  as the Destination. As an overview, the Source is the one responsible for updating the allocated sub-indices of the chosen Index when the data is already transferred to cache  204 . The Destination, on the other hand, is the one responsible for monitoring the allocated sub-indices of the chosen Index when a particular allocated sub-index is already done, from 0 to 1. While DMA 2   202  descriptors are being prepared, DMA 1201  descriptors can be prepared in parallel. Each descriptor pair must point to the same data buffer. In this case, both DMA 1   201  first descriptor  212  and DMA 2   202  first descriptor  206  point to the first data buffer  205 . Since Index 0 is “free”, once the first descriptor  212  of DMA 1   201  is ready, DMA 1   201  can start transferring data from memory  203  to cache  204  filling up the first data buffer  205 . Once the data needed are already transferred to the first data buffer  205 , DMA 1   201  will update the allocated sub-indices, from 0 to 1. DMA 2   202  is monitoring the state of the allocated sub-indices. When all of the allocated sub-indices of Index 0 are updated, it will become “free”. Every time an allocated sub-index of Index 0 is updated, DMA 2   202  may start draining the data from the data buffer section pointed by the updated sub-index. When Index 0 becomes “free” it will be available for another transfer. While the first data buffer  205  is being drained, DMA 1   201  can start filling up the next data buffer  207 . The transfer continues in this fashion, the invention updating and monitoring the dependency table  209 , until all data is transferred from memory  203  to IO bus. As mentioned, saves the system precious cycles by eliminating the need for processor intervention for every completed transfer. 
       FIG. 3  is almost the same as  FIG. 1  except that the source of data is from the IO Bus Interface  303 . The data has to be transferred from IO Bus Interface  303  to cache  304 , the processor has to periodically interfere the process preparing and enabling DMA engines between transfer boundaries. Before a DMA transfer can start, information like the source and destination start address, size of the data to transfer, etc are normally supplied first. One set of this information can be called as descriptor. Instead of preparing another descriptor after completing a DMA transfer just before starting the next transfer, it can be done more efficiently by initially preparing a reasonable number of descriptors then let the DMA engines do the fetching, decoding and execution of descriptors by itself. The FW then will just keep adding more descriptors to the list of descriptors. In  FIG. 3 , DMA 2   301  has to do 4 DMA transfers from IO Bus Interface  303  to cache  304  utilizing 4 data buffers. DMA 1   302  has to transfer the data from data buffers to the memory. DMA 2   301  and DMA 1   302  will need 4 descriptors each. Assuming that all descriptors have already been prepared, DMA 2   301  now has to start transferring data. After DMA 3   301  has filled the first data buffer  305 , the FW is notified through interrupt. FW then enables the corresponding descriptor  306  of DMA 1   302 . The rest of the descriptors will not be enabled since the corresponding data buffers are not yet ready for draining. DMA 1   302  starts draining the first data buffer  305  while DMA 2   301  is filling up the next data buffer  307 . The processor is interrupted again after DMA 2   301  has filled up the second data buffer  307 . FW enables the next descriptor  308  so DMA 1   302  can start draining the second data buffer  307  as soon as it is done with the first data buffer  305 . The sequence continues until all 4 data buffers are filled from IO Bus Interface  303  and drained to the memory. Notice that the processor is interrupted each time DMA 2   301  has finished filling up a data buffer. Note also that DMA 1   302  must interrupt the processor after draining a data buffer to free up the used resources. The above process can be improved by minimizing the intervention of the processor. This means that while DMA 2   301  is filling up a data buffer, DMA 1   302  must have a way to know when it can start draining the data buffer and that DMA 1   302  must have a way to free up used resources all without the help of the processor. 
       FIG. 4  is almost the same as  FIG. 2  except that the source of data is from the IO Bus Interface  403 . The Index field  410  in the dependency table  409  corresponds to a transfer where all the descriptors  406 ,  408  &amp;  412  of the DMA controllers  401  &amp;  402  are tied to. An Index contains 3 Buffers  410 , BufRdy 0 , BufRdy 1  and BufRdy 2 . A Buffer may hold the sub-indices of an Index of the DMA controllers involved in the transfer. For example, BufRdy 0  may hold the sub-indices of DMA 2   401 . Each bit in the BufRdy field corresponds to a sub-index  411  which is a section stored/fetched on single cache buffer  405  &amp;  407  on the SDRAM/SRAM. A sub-index  410  is said to be “allocated or pending” when its bit is set to 0 and “done” when set to its default value of 1. An Index field  410  is considered to be “free” when all the sub-indices of the 3 Buffers  410  are “done”. Assuming a read command is received from the memory, the FW recognizes that the requested data is in the IO bus  403 . The FW prepares the descriptors for DMA 1   402 . During preparation of DMA 1   402  first descriptor  406 , the processor checks the dependency table  409  to see if there is an available Index  410 . The processor sees Index 0 is free. Index number 0 is assigned to DMA 1   402  first descriptor  406 . The processor allocates the sub-index  411  bits, from 1 to 0, of Index 0 based on the section(s) of the data buffers  405  &amp;  407  that to be used in data transfer and for example, the processor assigns BufRdy 0  sub-indices  411  to DMA 2   401  as the Source and BufRdy 1  sub-indices  411  to DMA 1   402  as the Destination. As an overview, the Source is the one responsible for updating the allocated sub-indices of the chosen Index when the data is already transferred to cache  404 . The Destination, on the other hand, is the one responsible for monitoring the allocated sub-indices of the chosen Index when a particular allocated sub-index is already done, from 0 to 1. While DMA 1   402  descriptors are being prepared, DMA 2   401  descriptors can be prepared in parallel. Each descriptor pair must point to the same data buffer. In this case, both DMA 2   401  first descriptor  412  and DMA 1   402  first descriptor  406  point to the first data buffer  405 . Since Index 0 is “free”, once the first descriptor  412  of DMA 2   401  is ready, DMA 2   401  can start transferring data from IO bus  403  to cache  404  filling up the first data buffer  405 . Once the data needed are already transferred to the first data buffer  405 , DMA 2   401  will update the allocated sub-indices, from 0 to 1. DMA 1   402  is monitoring the state of the allocated sub-indices. When all of the allocated sub-indices of Index 0 are updated, it will become “free”. Every time an allocated sub-index of Index 0 is updated, DMA 1   402  may start draining the data from the data buffer section pointed by the updated sub-index. When Index 0 becomes “free” it will be available for another transfer. While the first data buffer  405  is being drained, DMA 2   401  can start filling up the next data buffer  407 . The transfer continues in this fashion, the invention updating and monitoring the dependency table  409 , until all data is transferred from IO bus  403  to memory. As mentioned, the whole process saves the processor precious processor cycle by eliminating the need for processor intervention for every completed transfer. 
       FIG. 5  shows the basic process flow for the DMA using the dependency according to an embodiment of the present invention. This figure describes the steps the Memory DMA and the IOC DMA perform. The direction of the data transfer is from the memory to the IO bus. Steps  500  to  502  describes the Memory DMA side dependency. In step  500 , an Index in the Dependency table is free. Memory DMA receives the descriptor, sees that it has a free Index allocated by the firmware in Dependency table to be updated/freed. Memory DMA also sees the assigned BufRdy Group containing the allocated sub-indices for update. In step  501 , the Memory DMA starts to transfer the data to the data buffer section in the cache, it also updates the sub-index of the corresponding data buffer section where the data is sent. In step  502 , the Memory DMA repeats the process mentioned above until all the sections of the data buffer are filled-up and all the sub-indices of the allocated Index are updated. The Index will be free, which will indicate that all the needed data dictated by the received descriptor is transferred by the Memory DMA from the memory to the cache. Steps  503  to  505  describes the IOC DMA side dependency. In step  503 , IOC DMA receives a descriptor, sees that it has a free Index allocated by the firmware in Dependency table to monitored. IOC DMA also sees the assigned BufRdy Group containing the allocated sub-indices for monitor. In step  504 , IOC DMA monitors the sub-index corresponding to the data buffer section where the data will be filled by the Memory DMA. When the data is already transferred, the monitored sub-index will be updated and the IOC DMA starts to DMA the data from the cache to the IO bus. In step  505 , IOC DMA repeats the process mentioned above for all the monitored sub-indices until all the needed data dictated by the received descriptor is transferred from the cache to the IO bus. 
       FIG. 6  is the same as  FIG. 5  except that the direction of the data transfer is from the IO bus to the memory. Steps  600  to  602  describes the IOC DMA side dependency. In step  600 , an Index in the Dependency table is free. IOC DMA receives the descriptor, sees that it has a free Index allocated by the firmware in Dependency table to be updated/freed. IOC DMA also sees the assigned BufRdy Group containing the allocated sub-indices for update. In step  601 , the IOC DMA starts to transfer the data to the data buffer section in the cache, it also updates the sub-index of the corresponding data buffer section where the data is sent. In step  602 , the IOC DMA repeats the process mentioned above until all the sections of the data buffer are filled-up and all the sub-indices of the allocated Index are updated. The Index will be free, which will indicate that all the needed data dictated by the received descriptor is transferred by the IOC DMA from the IO bus to the cache. Steps  603  to  605  describes the Memory DMA side dependency. In step  603 , Memory DMA receives a descriptor, sees that it has a free Index allocated by the firmware in Dependency table to monitored. Memory DMA also sees the assigned BufRdy Group containing the allocated sub-indices for monitor. In step  604 , Memory DMA monitors the sub-index corresponding to the data buffer section where the data will be filled by the IOC DMA. When the data is already transferred, the monitored sub-index will be updated and the Memory DMA starts to DMA the data from the cache to the memory. In step  605 , Memory DMA repeats the process mentioned above for all the monitored sub-indices until all the needed data dictated by the received descriptor is transferred from the cache to the memory. 
       FIG. 7  describes a variation a DMA process applying the invention for data transfer from memory (flash)  703  to IO bus. The process flow is almost the same as the process flow in  FIG. 2  except that instead the data transferred from the memory (flash)  703  to the cache  704  will be fetched from it  704  and will be transferred directly to the IO bus, the data from the cache  704  will be sent first to the third DMA engine  700  for intermediate processing and the processed data will now be transferred to IO bus. The processor will check the Dependency table  709  for a free Index and the processor sees Index 0  710  is free and ready for allocation. The processor sets up the tied descriptors  708 ,  706  and  707  for DMA 1   701 , DMA 2   702  and Intermediate Processing DMA  700 . Each of these descriptors corresponds to the free Index 0  710  and its sub-indices  710  are pointed to the data buffer sections dictated by the descriptor. Also, the processor assigned BufRdy 0   710  to DMA 1   701  for updating data transfer from memory (flash)  703  to cache  704 , BufRdy 1   710  to Intermediate Processing DMA  700  for updating transfer of processed data from intermediate processing  700  back to cache  704  and BufRdy 2  to DMA 2   702  for updating transfer of processed data from cache  704  to IO bus. The descriptors for the 3 DMA engines will be executed simultaneously promoting less processor intervention. DMA 1   701  will start transferring data from memory (flash)  703  to cache  704 . Once data is transferred to a section of the data buffer  705  in the cache  704 , DMA 1   701  will update the corresponding sub-index  710  in BufRdy 0   710 , from 0 to 1 and Intermediate Processing DMA  700  monitoring the sub-index will be informed that it  700  can start draining the data from the cache  704  for processing. Note that while an intermediate processing is ongoing, data transfer from the memory  703  to cache  704  and from cache  704  to intermediate processing will continue. When the intermediate processing is finished, the processed data will be sent back to cache  704  and Intermediate Processing DMA  700  will be the one to update the corresponding sub-index  710  in BufRdy 1   710 , from 0 to 1 and DMA 2   702  monitoring the sub-index will be informed that it  702  can start draining the processed data from cache  704  to IO bus. Once the processed data is transferred already to IO bus, DMA 2   702  will update the corresponding sub-index  710  in BufRdy 2   710 . This process flow will be repeated until all allocated sub-indices in all BufRdy Groups  710  of Index 0  710  are updated indicating the data transfer dictated by the descriptor is finished and Index 0 will be freed up; ready for another data transfer. 
       FIG. 8  describes a variation a DMA process applying the invention for data transfer from IO bus  803  to memory (flash). The process flow is almost the same as the process flow in  FIG. 4  except that instead the data transferred from the IO bus  803  to the cache  804  will be fetched from it  804  and will be transferred directly to the memory (flash), the data from the cache  804  will be sent first to the third DMA engine  800  for intermediate processing and the processed data will now be transferred to memory (flash). The processor will check the Dependency table  809  for a free Index and the processor sees Index 0  810  is free and ready for allocation. The processor sets up the tied descriptors  808 ,  806  and  807  for DMA 1   801 , DMA 2   802  and Intermediate Processing DMA  800 . Each of these descriptors corresponds to the free Index 0  810  and its sub-indices  810  are pointed to the data buffer sections dictated by the descriptor. Also, the processor assigned BufRdy 0   810  to DMA 2   802  for updating data transfer from IO bus  803  to cache  804 , BufRdy 1   810  to Intermediate Processing DMA  800  for updating transfer of processed data from intermediate processing  800  back to cache  804  and BufRdy 2  to DMA 1   801  for updating transfer of processed data from cache  804  to memory (flash). The descriptors for the 3 DMA engines will be executed simultaneously promoting less processor intervention. DMA 2   802  will start transferring data from IO bus  803  to cache  804 . Once data is transferred to a section of the data buffer  805  in the cache  804 , DMA 2   802  will update the corresponding sub-index  810  in BufRdy 0   810 , from 0 to 1 and Intermediate Processing DMA  800  monitoring the sub-index will be informed that it  800  can start draining the data from the cache  804  for processing. Note that while an intermediate processing is ongoing, data transfer from the IO bus  803  to cache  804  and from cache  804  to intermediate processing will continue. When the intermediate processing is finished, the processed data will be sent back to cache  804  and Intermediate Processing DMA  800  will be the one to update the corresponding sub-index  810  in BufRdy 1   810 , from 0 to 1 and DMA 1   801  monitoring the sub-index will be informed that it  801  can start draining the processed data from cache  804  to memory (flash). Once the processed data is transferred already to memory (flash), DMA 1   801  will update the corresponding sub-index  810  in BufRdy 2   810 . This process flow will be repeated until all allocated sub-indices in all BufRdy Groups  810  of Index 0  810  are updated indicating the data transfer dictated by the descriptor is finished and Index 0 will be freed up; ready for another data transfer. 
       FIG. 9  describes the other variation of DMA transfer with dependency where a third DMA engine for intermediate processing is involved. Here, the intermediate processing is different from what is described in  FIG. 8  because a XOR operation will be performed. The processor sets up the tied descriptors  908 ,  907  and  906  for DMA 1   901 , Intermediate Processing DMA  900  and DMA 2   902  pointing to the free Index 0  910  on Dependency Table  909 . sub-index 0  911  of BufRdy 0   910  is assigned to DMA 2   902  for updating data transfer  913  from IO bus  912  to cache  904 . sub-index 0  911  of BufRdy 1   910  is assigned to DMA 1   901  for updating data transfer  914  from memory (flash)  903  to cache  904 . sub-index 1  911  of BufRdy 0   910  is assigned to Intermediate Processing DMA  900  for updating transfer of processed data  916  from Intermediate Processing DMA  900  to cache  904 . sub-index 1  911  of BufRdy 1   910  is assigned to DMA 2   902  for updating the transfer of processed data  917  from cache  904  to IO bus  912 . The sub-indices  911  of BufRdy 2   910  will not be used in the data transfer and the sub-indices  911  value will remain to 1. When the processor finished the setup of the Dependency Table  909  and the descriptors  906 ,  907  and  908  are executed, the data transfer begins. DMA 2   902  will start transferring the data  913  from IO bus  912  to cache  904 . Once the data  913  is transferred to cache  904 , DMA 2   902  will update sub-index 0  911  of BufRdy 0   910 , from 0 to 1 and Intermediate Processing DMA  900  monitoring the sub-index will be informed that it  900  can start draining the data  915  from cache  904  for processing. In parallel with the data transfer of DMA 2   902 , DMA 1   901  will also start transferring the data  914  from memory (flash)  903  to cache  904 . Once the data  914  is transferred to cache  904 , DMA 1   901  will update sub-index 0  911  of BufRdy 1   910 , from 0 to 1 and Intermediate Processing DMA  900  monitoring the sub-index will be informed that it  900  can start draining the data  915  from cache  904  for processing. After the XOR operation is performed for the data  913  and data  914  (collectively known as data  915 ), the XOR result data  916  will be transferred to cache  904 . Once the data  916  is transferred to cache  904 , Intermediate Processing DMA  900  will update sub-index 1  911  of BufRdy 0   910 , from 0 to 1 and DMA 2   902  monitoring the sub-index will be informed that it  902  can start draining the XOR result data  917  (formerly XOR result data  916 ) from cache  904  to IO bus  912 . Once the XOR result data  917  is transferred to IO bus  912 , DMA 2   902  will update sub-index 1  911  of BufRdy 1   910 , from 0 to 1. After this, Index 0  910  will be freed up indicating that the data transfer is completed. 
       FIG. 10  illustrates the relationship between the Data Buffer, Descriptor &amp; Dependency Table. Each of the tied descriptors made by the processor corresponds to a free Index, as an example in  FIG. 10 , the free Index is Index 0. In the figure, the Memory DMA Descriptor is assigned to BufRdy 0 , the Intermediate Processing DMA Descriptor to BufRdy 1  and the IO Bus DMA Descriptor to BufRdy 2 . Note that the three DMA engines can be assigned to other BufRdy. Each of the sub-indices in a BufRdy corresponds to a section of the Data Buffer. 
     Foregoing described embodiments of the invention are provided as illustrations and descriptions. They are not intended to limit the invention to precise form described. In particular, it is contemplated that functional implementation of invention described herein may be implemented equivalently in hardware, software, firmware, and/or other available functional components or building blocks, and that networks may be wired, wireless, or a combination of wired and wireless. 
     It is also within the scope of the present invention to implement a program or code that can be stored in a machine-readable or computer-readable medium to permit a computer to perform any of the inventive techniques described above, or a program or code that can be stored in an article of manufacture that includes a computer readable medium on which computer-readable instructions for carrying out embodiments of the inventive techniques are stored. Other variations and modifications of the above-described embodiments and methods are possible in light of the teaching discussed herein. 
     The above description of illustrated embodiments of the invention, including what is described in the Abstract, is not intended to be exhaustive or to limit the invention to the precise forms disclosed. While specific embodiments of, and examples for, the invention are described herein for illustrative purposes, various equivalent modifications are possible within the scope of the invention, as those skilled in the relevant art will recognize. 
     These modifications can be made to the invention in light of the above detailed description. The terms used in the following claims should not be construed to limit the invention to the specific embodiments disclosed in the specification and the claims. Rather, the scope of the invention is to be determined entirely by the following claims, which are to be construed in accordance with established doctrines of claim interpretation.