/home/hillier_g/checkout/most4linux/most-kernel/most-txbuf.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 #else
00039 #  include "usp-test.h"
00040 #endif
00041 
00042 #include "most-txbuf.h"
00043 
00044 
00048 #define PR "txbuf: "
00049 
00050 
00051 /*
00052  * Documentation: see header
00053  */
00054 struct tx_buffer *txbuf_alloc(unsigned int writer_count, 
00055                               unsigned int frame_count,
00056                               unsigned int bytes_per_frame)
00057 {
00058     int                 i;
00059     struct tx_buffer    *ret;
00060 
00061     /* one element more to detemerine emtpy and full rings */
00062     frame_count++;
00063  
00064     /* allocate the structure */
00065     ret = ker_malloc(sizeof(struct tx_buffer));
00066     if (unlikely(!ret)) {
00067         rtnrt_err(PR "Allocating struct tx_buffer failed\n");
00068         return NULL;
00069     }
00070     memset(ret, 0, sizeof(struct tx_buffer));
00071 
00072     /* initialize all elements */
00073     ret->writer_count    = writer_count;
00074     ret->frame_count     = frame_count;
00075     ret->bytes_per_frame = bytes_per_frame;
00076     ret->full_count      = 0;
00077     rtnrt_lock_init(&ret->lock);
00078 
00079     /* allocate the ring */
00080     ret->buffer = vmalloc(bytes_per_frame * frame_count);
00081     pr_txbuf_debug(PR "Allocating %d bytes ringbuffer (0x%p)\n", 
00082              bytes_per_frame * frame_count, ret->buffer);
00083     if (unlikely(!ret->buffer)) {
00084         pr_txbuf_debug(PR "Allocating ring buffer failed\n");
00085         goto err_buf;
00086     }
00087 #ifdef DEBUG
00088     memset(ret->buffer, 0, bytes_per_frame * frame_count);
00089 #endif
00090 
00091     /* set the pointers right */
00092     for (i = 0; i < ret->writer_count; i++) {
00093         ret->writeptr[i] = ret->buffer;
00094     }
00095     ret->readptr = ret->buffer;
00096 
00097     return ret;
00098     
00099 err_buf:
00100     kfree(ret);
00101     return NULL;
00102 }
00103 
00104 /*
00105  * Documentation: see header
00106  */
00107 void txbuf_free(struct tx_buffer *ring)
00108 {
00109     if (ring) {
00110         if (ring->buffer) {
00111             vfree(ring->buffer);
00112         }
00113         kfree(ring);
00114     }
00115 }
00116 
00117 /*
00118  * Documentation: see header
00119  */
00120 ssize_t txbuf_get(struct tx_buffer     *ring, 
00121                   unsigned char         *buffer,
00122                   size_t                bytes)
00123 {
00124     int           to_copy;
00125     unsigned long flags;
00126     int           byte_count; 
00127     unsigned int  ring_size   = ring->frame_count * ring->bytes_per_frame;
00128 
00129     if ((bytes % ring->bytes_per_frame != 0) || (bytes > ring_size)) {
00130         rtnrt_err(PR "bytes (%d) must be dividable by %d\n",
00131                (int)bytes, ring->bytes_per_frame);
00132         return -EINVAL;
00133     }
00134 
00135     /* only copy the number of ring elements */
00136     byte_count = min((size_t)ring->full_count, bytes);
00137 
00138     /* number of bytes to copy in the first step */
00139     to_copy = min(byte_count,
00140                  (int)(ring_size - (unsigned long)(ring->readptr - ring->buffer)));
00141 
00142     /* ring is empty */
00143     if (to_copy == 0) {
00144         return 0;
00145     }
00146 
00147     /* copy the data */
00148     memcpy(buffer, ring->readptr, to_copy);
00149 
00150     /* no overflow? */
00151     if (to_copy == byte_count) {
00152         /* adjust the ring */
00153         if ((ring->readptr + to_copy) >= (ring->buffer + ring_size)) {
00154             ring->readptr = ring->buffer;
00155         } else {
00156             ring->readptr += to_copy;
00157         }
00158     } else {
00159         /* copy the rest */
00160         buffer += to_copy;
00161         to_copy = byte_count - to_copy;
00162         
00163         memcpy(buffer, ring->buffer, to_copy);
00164 
00165         /* adjust the ring */
00166         ring->readptr = ring->buffer + to_copy;
00167     }
00168     
00169     rtnrt_lock_get_irqsave(&ring->lock, flags);
00170     ring->full_count -= byte_count;
00171     rtnrt_lock_put_irqrestore(&ring->lock, flags);
00172     
00173     return byte_count;
00174 }
00175 
00181 static void txbuf_update_full_frame_count(struct tx_buffer *ring)
00182 {
00183     unsigned int  ring_size   = ring->frame_count * ring->bytes_per_frame;
00184     int           min_val     = ring_size;
00185     int           i;
00186 
00187     for (i = 0; i < ring->writer_count; i++) {
00188         int bytes_full = ring->writeptr[i] - ring->readptr;
00189         if (bytes_full < 0) {
00190             bytes_full = ring_size + bytes_full;
00191         }
00192         min_val = min(min_val, bytes_full);
00193     }
00194     ring->full_count = min_val;
00195 }
00196 
00197 /*
00198  * Documentation: see header
00199  */
00200 bool txbuf_is_full(struct tx_buffer *ring, int writer_index)
00201 {
00202     unsigned int   ring_size    = ring->frame_count * ring->bytes_per_frame;
00203     int            bytes_full;
00204 
00205     bytes_full = ring->writeptr[writer_index] - ring->readptr;
00206     if (bytes_full < 0) {
00207         bytes_full = ring_size + bytes_full;
00208     }
00209 
00210     return bytes_full == (int)(ring_size - ring->bytes_per_frame);
00211 }
00212 
00213 /*
00214  * Documentation: see header
00215  */
00216 ssize_t txbuf_put(struct tx_buffer              *ring,
00217                   int                           writer_index,
00218                   struct frame_part             frame_part,
00219                   const char                    *buffer,
00220                   size_t                        bytes,
00221                   struct rtnrt_memcopy_desc     *copy)
00222 {
00223     int            frames_to_copy, still_to_copy;
00224     unsigned long  flags;
00225     int            bytes_full;
00226     unsigned int   elements_free;
00227     int            err;
00228     int            offset_bytes = frame_part.offset;
00229     int            count_bytes  = frame_part.count;
00230     unsigned int   ring_size    = ring->frame_count * ring->bytes_per_frame;
00231     unsigned char  *writep      = ring->writeptr[writer_index];
00232     unsigned char  *ring_end    = ring->buffer + ring_size;
00233 
00234 #ifdef DEBUG
00235     /* check the bytes */
00236     if (bytes % count_bytes != 0) {
00237         rtnrt_err(PR "bytes (%d) must be dividable by %d\n", 
00238                 bytes, count_bytes);
00239         return -EINVAL;
00240     }
00241 #endif
00242 
00243     /* don't overwrite something, get the number of elements to copy */
00244     bytes_full = writep - ring->readptr;
00245     if (bytes_full < 0) {
00246         bytes_full = ring_size + bytes_full;
00247     }
00248     elements_free  = ring->frame_count - (bytes_full / (ring->bytes_per_frame));
00249     frames_to_copy = min((size_t)elements_free - 1, bytes / count_bytes);
00250 
00251     pr_txbuf_debug(PR "elements free: %d, frames to copy: %d\n", 
00252                            elements_free, frames_to_copy);
00253 
00254     /* if the ring is full, we return that */
00255     if (elements_free == 0) {
00256         return 0;
00257     }
00258     
00259     /* now we have frames to copy in the ring, then let's do it! */
00260     still_to_copy = frames_to_copy;
00261     while (still_to_copy > 0) {
00262         err = rtnrt_copy(copy, writep + offset_bytes, buffer, count_bytes);
00263 
00264         if (err != 0) {
00265             rtnrt_err(PR "Error %d in copy, copied %d frames\n", 
00266                    err, frames_to_copy - still_to_copy);
00267             return (frames_to_copy - still_to_copy) * count_bytes;
00268         }
00269 
00270         writep += ring->bytes_per_frame;
00271 
00272         /* wrap at the end */
00273         if (writep >= ring_end) {
00274             writep = ring->buffer;
00275         }
00276         buffer += count_bytes;
00277         still_to_copy--;
00278     }
00279 
00280     /* adjust the ring */
00281     rtnrt_lock_get_irqsave(&ring->lock, flags);
00282     ring->writeptr[writer_index] = writep;
00283     txbuf_update_full_frame_count(ring);
00284     rtnrt_lock_put_irqrestore(&ring->lock, flags);
00285 
00286     return frames_to_copy * count_bytes;
00287 
00288 }
00289 
00290 #ifdef DEBUG
00291 static spinlock_t print_lock = RTNRT_LSPINLOCK_UNLOCKED(print_lock);
00292 
00293 /*
00294  * Documentation: see header
00295  */
00296 void txbuf_print_debug(struct tx_buffer *ring)
00297 {
00298     unsigned int ring_size = ring->bytes_per_frame * ring->frame_count;
00299     int i;
00300 
00301     spin_lock(&print_lock);
00302     rtnrt_debug("Frames in ring       : %d\n", ring->frame_count);
00303     rtnrt_debug("Full bytes           : %d\n", ring->full_count);
00304     rtnrt_debug("Bytes per frame      : %d\n", ring->bytes_per_frame);
00305     rtnrt_debug("Read offset          : %d\n", ring->readptr - ring->buffer);
00306 
00307     /* now print the information per writer */
00308     for (i = 0; i < ring->writer_count; i++) {
00309         rtnrt_debug("Write offset   [%2d]  : %d\n", i, 
00310                 ring->writeptr[i] - ring->buffer);
00311     }
00312 
00313     for (i = 0; i < min(16, (int)ring_size); i++) {
00314         rtnrt_printk("%-2.2X ", ring->buffer[i]);
00315     }
00316 
00317     printk("\n");
00318     spin_unlock(&print_lock);
00319 }
00320 #endif
00321 
00322 
00323 #ifdef USP_TEST
00324 /* gcc -g -DDEBUG -DUSP_TEST -o most-txbuf most-txbuf.c */
00325 int main(int argc, char *argv[])
00326 {
00327     struct frame_part frame_part;
00328     unsigned char       user_data[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 
00329                                        10, 11, 12, 13, 14, 15, 16 };
00330     unsigned char       data[1024];
00331     struct tx_buffer    *buffer;
00332     int                 err;
00333 
00334     pr_debugm("BEGIN\n");
00335 
00336     buffer = txbuf_alloc(2, 5, 6);
00337     if (!buffer) {
00338         pr_err("Error in tvbuf_alloc\n\n\n");
00339         return -1;
00340     }
00341 
00342     frame_part.offset = 0;
00343     frame_part.count  = 4;
00344     err = txbuf_put(buffer, 0, frame_part, user_data, 4);
00345     pr_debugm("Err=%d\n", err);
00346     printf("==Full=%d, %d\n", txbuf_is_full(buffer, 0), txbuf_is_full(buffer, 1));
00347 
00348     err = txbuf_put(buffer, 0, frame_part, user_data + 4, 8);
00349     pr_debugm("Err=%d\n", err);
00350     printf("==Full=%d, %d\n", txbuf_is_full(buffer, 0), txbuf_is_full(buffer, 1));
00351 
00352     err = txbuf_put(buffer, 0, frame_part, user_data, 12);
00353     pr_debugm("Err=%d\n", err);
00354     printf("==Full=%d, %d\n", txbuf_is_full(buffer, 0), txbuf_is_full(buffer, 1));
00355 
00356     frame_part.offset = 4;
00357     frame_part.count = 2;
00358     err = txbuf_put(buffer, 1, frame_part, user_data, 6);
00359     pr_debugm("Err=%d\n", err);
00360 
00361     err = txbuf_get(buffer, data, 24);
00362     pr_debugm("Err=*%d\n", err);
00363 
00364     txbuf_print_debug(buffer);
00365 
00366     frame_part.offset = 0;
00367     frame_part.count  = 4;
00368     err = txbuf_put(buffer, 0, frame_part, user_data, 12);
00369     pr_debugm("Err=%d\n", err);
00370     txbuf_print_debug(buffer);
00371 
00372     txbuf_free(buffer);
00373     
00374     return 0;
00375 }
00376 #endif
00377 
00378 /* 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