/home/hillier_g/checkout/most4linux/most-kernel/most-rxbuf.c

Go to the documentation of this file.
00001 /*
00002  *  Copyright(c) Siemens AG, Muenchen, Germany, 2005, 2006, 2007
00003  *                           Bernhard Walle <bernhard.walle@gmx.de>
00004  *                           Gernot Hillier <gernot.hillier@siemens.com>
00005  *
00006  * ----------------------------------------------------------------------------
00007  * This program is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License version 2 as 
00009  * published by the Free Software Foundation;
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00019  * ----------------------------------------------------------------------------
00020  */
00021 
00029 #ifdef HAVE_CONFIG_H
00030 #include "config/config.h"
00031 #endif
00032 #ifndef USP_TEST
00033 #  include <asm/uaccess.h>            /* copy_from_user() */
00034 #  include <linux/module.h>
00035 #  include <linux/wait.h>
00036 #  include <linux/vmalloc.h>
00037 #  include "most-constants.h"
00038 #  include "rt-nrt.h"
00039 #else
00040 #  include "usp-test.h"
00041 #endif
00042 
00043 #include "most-rxbuf.h"
00044 
00048 #define PR "rxbuf: "
00049 
00050 
00051 /*
00052  * Documentation: see header
00053  */
00054 struct rx_buffer *rxbuf_alloc(unsigned int reader_count, 
00055                      unsigned int frame_count, 
00056                      unsigned int bytes_per_frame)
00057 {
00058     unsigned int        i;
00059     struct rx_buffer    *ret;
00060 
00061     /* one element more to determine empty and full rings */
00062     frame_count++;
00063 
00064     /* allocate the structure */
00065     ret = ker_malloc(sizeof(struct rx_buffer));
00066     if (unlikely(!ret)) {
00067         rtnrt_err(PR "Allocating struct rx_buffer failed\n");
00068         return NULL;
00069     }
00070     memset(ret, 0, sizeof(struct rx_buffer));
00071 
00072     /* initialize all elements */
00073     ret->reader_count    = reader_count;
00074     ret->frame_count     = frame_count;
00075     ret->bytes_per_frame = bytes_per_frame;
00076 
00077     /* allocate the ring */
00078     ret->buffer = vmalloc(bytes_per_frame * frame_count);
00079     pr_rxbuf_debug(PR "Allocating %d bytes ringbuffer (0x%p)\n", 
00080                    bytes_per_frame * frame_count, ret->buffer);
00081     if (unlikely(!ret->buffer)) {
00082         rtnrt_err(PR "Allocating ring buffer failed\n");
00083         goto err_buf;
00084     }
00085 #ifdef DEBUG
00086     memset(ret->buffer, 0, bytes_per_frame * frame_count);
00087 #endif
00088 
00089     /* set the pointers right */
00090     for (i = 0; i < ret->reader_count; i++) {
00091         ret->readptr[i] = ret->buffer;
00092     }
00093     ret->writeptr = ret->buffer;
00094 
00095     return ret;
00096     
00097 err_buf:
00098     kfree(ret);
00099     return NULL;
00100 }
00101 
00102 /*
00103  * Documentation: see header
00104  */
00105 void rxbuf_free(struct rx_buffer *ring)
00106 {
00107     if (ring) {
00108         if (ring->buffer) {
00109             vfree(ring->buffer);
00110         }
00111         kfree(ring);
00112     }
00113 }
00114 
00115 /*
00116  * Documentation: see header
00117  */
00118 ssize_t rxbuf_get(struct rx_buffer              *ring,
00119                   unsigned int                  reader_index,
00120                   struct frame_part             frame_part,
00121                   unsigned char                 *buffer,
00122                   size_t                        bytes,
00123                   struct rtnrt_memcopy_desc     *copy)
00124 {
00125     int            frames_to_copy, still_to_copy;
00126     int            bytes_full;
00127     unsigned char  *readp        = ring->readptr[reader_index];
00128     unsigned int   ring_size     = ring->bytes_per_frame * ring->frame_count;
00129     unsigned char  *ring_end     = ring->buffer + ring_size;
00130     int            err;
00131     
00132     /* round down if necessary */
00133     bytes -= bytes % frame_part.count;
00134 
00135     /* check the ring size */
00136     if (bytes > ring_size) {
00137         rtnrt_err(PR "bytes (%d) must be smaller than ring_size (%d)\n",
00138                (int)bytes, ring_size);
00139         return -EINVAL;
00140     }
00141 
00142     /* get the number of elements to copy */
00143     bytes_full = ring->writeptr - readp;
00144     if (bytes_full < 0) {
00145         bytes_full = ring_size + bytes_full;
00146     }
00147     frames_to_copy = min((size_t)bytes_full / ring->bytes_per_frame, bytes / 
00148             frame_part.count);
00149     
00150     pr_rxbuf_debug(PR "bytes full: %d, frames to copy: %d\n", 
00151                    bytes_full, frames_to_copy);
00152 
00153     /* if the ring is empty, we return that */
00154     if (frames_to_copy == 0) {
00155         return 0;
00156     }
00157 
00158     /* now we have frames to copy, let's do it */
00159     still_to_copy = frames_to_copy;
00160     while (still_to_copy > 0) {
00161         //pr_debugm("frame_part.offset = %d, frame_part.count = %d\n", 
00162         //          frame_part.offset, frame_part.count);
00163         err = rtnrt_copy(copy, buffer, readp + frame_part.offset, frame_part.count);
00164 
00165         if (err != 0) {
00166             rtnrt_warn(PR "Error %d in copy, copied %d bytes\n", 
00167                        err, frames_to_copy - still_to_copy);
00168             return (frames_to_copy - still_to_copy) * frame_part.count;
00169         }
00170 
00171         readp += ring->bytes_per_frame;
00172         /* wrap at the end */
00173         if (readp >= ring_end) {
00174             readp = ring->buffer;
00175         }
00176         buffer += frame_part.count;
00177         still_to_copy--;
00178     }
00179 
00180     ring->readptr[reader_index] = readp;
00181 
00182     return frames_to_copy * frame_part.count;
00183 
00184 }
00185 
00186 /*
00187  * Documentation: see header
00188  */
00189 bool rxbuf_is_empty(struct rx_buffer *ring, int reader_index)
00190 {
00191     return ring->writeptr == ring->readptr[reader_index];
00192 }
00193 
00194 /*
00195  * Documentation: see header
00196  */
00197 ssize_t rxbuf_put(struct rx_buffer      *ring,
00198                   unsigned char         *buffer,
00199                   size_t                bytes)
00200 {
00201     int       to_copy;
00202     int       ring_size = ring->bytes_per_frame * ring->frame_count;
00203 
00204     return_value_if_fails_dbg(ring != NULL, -EINVAL);
00205     return_value_if_fails_dbg(buffer != NULL, -EINVAL);
00206     pr_rxbuf_debug(PR "rxbuf_put=%d\n", bytes);
00207 
00208     /* check if bytes is ok */
00209     if ((bytes % ring->bytes_per_frame != 0)) {
00210         rtnrt_err(PR "bytes (%d) must be dividable by %d or is too large\n",
00211                (int)bytes, ring->bytes_per_frame);
00212         return -EINVAL;
00213     }
00214 
00215     /* number of bytes to copy in the first step */
00216     to_copy = min((int)bytes,
00217                   (int)(ring_size - (unsigned long)(ring->writeptr - ring->buffer)));
00218 
00219     if (to_copy == 0) {
00220         return 0;
00221     }
00222 
00223     /* copy data */
00224     memcpy(ring->writeptr, buffer, to_copy);
00225 
00226     /* no overflow? */
00227     if ((unsigned int)to_copy == bytes) {
00228         /* adjust the ring */
00229         ring->writeptr += to_copy;
00230         if (ring->writeptr >= (ring->buffer + ring_size)) {
00231             ring->writeptr = ring->buffer;
00232         }
00233     } else {
00234         /* copy the rest */
00235         buffer += to_copy;
00236         to_copy = bytes - to_copy;
00237 
00238         memcpy(ring->buffer, buffer, to_copy);
00239 
00240         /* adjust the ring */
00241         ring->writeptr = ring->buffer + to_copy;
00242     }
00243 
00244     return bytes;
00245 }
00246 
00247 #ifdef DEBUG
00248 static spinlock_t print_lock = RTNRT_LSPINLOCK_UNLOCKED(print_lock);
00249 
00250 /*
00251  * Documentation: see header
00252  */
00253 void rxbuf_print_debug(struct rx_buffer *ring, bool data)
00254 {
00255     unsigned int i;
00256 
00257     spin_lock(&print_lock);
00258 
00259     rtnrt_debug("Frames in ring       : %d\n", ring->frame_count);
00260     rtnrt_debug("Bytes per frame      : %d\n", ring->bytes_per_frame);
00261     rtnrt_debug("Write offset         : %d\n", ring->writeptr - ring->buffer);
00262 
00263     /* now print the information per writer */
00264     for (i = 0; i < ring->reader_count; i++) {
00265         rtnrt_debug("Read offset    [%2d]  : %d\n", i, 
00266                 ring->readptr[i] - ring->buffer);
00267     }
00268 
00269     if (data) {
00270         for (i = 0; i < (ring->frame_count * ring->bytes_per_frame); i++)
00271         {
00272             rtnrt_printk("%-2.2X ", ring->buffer[i]);
00273         }
00274     }
00275 
00276     rtnrt_printk("\n");
00277 
00278     spin_unlock(&print_lock);
00279 }
00280 #endif
00281 
00282 #ifdef USP_TEST
00283 /* Use `gcc -DDEBUG -DUSP_TEST -o most-rxbuf most-rxbuf.c' */
00284 /* -------------------------------------------------------------------------- */
00285 int main(int argc, char *argv[])
00286 {
00287     int                 i;
00288     unsigned char       user_data[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 
00289                                         11, 12, 13, 14, 15, 16 };
00290     struct frame_part   part;
00291     unsigned char       data[1024];
00292     struct rx_buffer    *buffer;
00293     int                 err;
00294 
00295     pr_debugm("BEGIN\n");
00296 
00297     buffer = rxbuf_alloc(2, 5, 6);
00298     if (!buffer) {
00299         pr_debugm("Error in tvbuf_alloc\n\n\n");
00300         return -1;
00301     }
00302 
00303     printf("== Empty? %d, %d\n", rxbuf_is_empty(buffer, 0), rxbuf_is_empty(buffer, 1));
00304 
00305     err = rxbuf_put(buffer, user_data, 6);
00306     pr_debugm("Ret=%d\n", err);
00307     printf("== Empty? %d, %d\n", rxbuf_is_empty(buffer, 0), rxbuf_is_empty(buffer, 1));
00308 
00309     err = rxbuf_put(buffer, user_data + 6, 6);
00310     pr_debugm("Ret=%d\n", err);
00311     printf("== Empty? %d, %d\n", rxbuf_is_empty(buffer, 0), rxbuf_is_empty(buffer, 1));
00312 
00313     rxbuf_print_debug(buffer, true);
00314     part.count = 4;
00315     part.offset = 0;
00316     err = rxbuf_get(buffer, 0, part, data, 12);
00317     pr_debugm("*Ret=%d\n", err);
00318     printf("== Empty? %d, %d\n", rxbuf_is_empty(buffer, 0), rxbuf_is_empty(buffer, 1));
00319 
00320     for (i = 0; i < min(err, 12); i++) {
00321         most_printk("%-2.2X ", data[i]);
00322     }
00323     printf("\n");
00324 
00325     part.count = 4;
00326     part.offset = 0;
00327     err = rxbuf_get(buffer, 0, part, data, 4);
00328     pr_debugm("Ret=%d\n", err);
00329 
00330     for (i = 0; i < min(err, 4); i++) {
00331         printf("%-2.2X ", data[i]);
00332     }
00333     printf("\n");
00334 
00335     rxbuf_print_debug(buffer, true);
00336 
00337     err = rxbuf_put(buffer, user_data, 12);
00338     pr_debugm("Ret=%d\n", err);
00339     rxbuf_print_debug(buffer, true);
00340 
00341     part.count = 4;
00342     part.offset = 0;
00343     err = rxbuf_get(buffer, 0, part, data, 12);
00344     pr_debugm("Ret=%d\n", err);
00345 
00346     for (i = 0; i < min(err, 12); i++) {
00347         printf("%-2.2X ", data[i]);
00348     }
00349     printf("\n");
00350 
00351     rxbuf_free(buffer);
00352     
00353     return 0;
00354 }
00355 
00356 #endif
00357 
00358 /* vim: set ts=4 et sw=4: */

Generated on Fri Mar 9 14:48:58 2007 for MOST Linux Drivers (Linux and RTAI) by  doxygen 1.5.0