1e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe/*
2e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe * A simple kernel FIFO implementation.
3e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe *
4e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe * Copyright (C) 2004 Stelian Pop <stelian@popies.net>
5e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe *
6e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe * This program is free software; you can redistribute it and/or modify
7e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe * it under the terms of the GNU General Public License as published by
8e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe * the Free Software Foundation; either version 2 of the License, or
9e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe * (at your option) any later version.
10e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe *
11e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe * This program is distributed in the hope that it will be useful,
12e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe * but WITHOUT ANY WARRANTY; without even the implied warranty of
13e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe * GNU General Public License for more details.
15e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe *
16e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe * You should have received a copy of the GNU General Public License
17e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe * along with this program; if not, write to the Free Software
18e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe *
20e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe */
21e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe
22e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe#include <stdio.h>
23e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe#include <stdlib.h>
24e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe#include <string.h>
25e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe
26e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe#include "fifo.h"
27e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe
28e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboestruct fifo *fifo_alloc(unsigned int size)
29e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe{
30e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe	struct fifo *fifo;
31e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe
32e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe	fifo = malloc(sizeof(struct fifo));
33e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe	if (!fifo)
34cc62ea704e4de10eb595b551f29af41266cf225dJens Axboe		return NULL;
35e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe
36e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe	fifo->buffer = malloc(size);
37e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe	fifo->size = size;
38f12b323f5d5ca40cd966ebbcfbbfcdf0a1fc229eJens Axboe	fifo->in = fifo->out = 0;
39e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe
40e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe	return fifo;
41e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe}
42e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe
43e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboevoid fifo_free(struct fifo *fifo)
44e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe{
45e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe	free(fifo->buffer);
46e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe	free(fifo);
47e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe}
48e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe
49e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboeunsigned int fifo_put(struct fifo *fifo, void *buffer, unsigned int len)
50e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe{
51e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe	unsigned int l;
52e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe
53104bc4bdf55bd79c2b3f9087601c3df4aa884b2aJens Axboe	len = min(len, fifo_room(fifo));
54e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe
55e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe	/* first put the data starting from fifo->in to buffer end */
56e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe	l = min(len, fifo->size - (fifo->in & (fifo->size - 1)));
57e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe	memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, l);
58e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe
59e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe	/* then put the rest (if any) at the beginning of the buffer */
60e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe	memcpy(fifo->buffer, buffer + l, len - l);
61e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe
62e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe	/*
63e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe	 * Ensure that we add the bytes to the fifo -before-
64e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe	 * we update the fifo->in index.
65e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe	 */
66e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe
67e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe	fifo->in += len;
68e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe
69e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe	return len;
70e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe}
71e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe
725ec10eaad3b09875b91e19a20bbdfa06f2117562Jens Axboeunsigned int fifo_get(struct fifo *fifo, void *buf, unsigned int len)
73e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe{
74e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe	len = min(len, fifo->in - fifo->out);
75e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe
765ec10eaad3b09875b91e19a20bbdfa06f2117562Jens Axboe	if (buf) {
77104bc4bdf55bd79c2b3f9087601c3df4aa884b2aJens Axboe		unsigned int l;
78e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe
79104bc4bdf55bd79c2b3f9087601c3df4aa884b2aJens Axboe		/*
80104bc4bdf55bd79c2b3f9087601c3df4aa884b2aJens Axboe		 * first get the data from fifo->out until the end of the buffer
81104bc4bdf55bd79c2b3f9087601c3df4aa884b2aJens Axboe		 */
82104bc4bdf55bd79c2b3f9087601c3df4aa884b2aJens Axboe		l = min(len, fifo->size - (fifo->out & (fifo->size - 1)));
835ec10eaad3b09875b91e19a20bbdfa06f2117562Jens Axboe		memcpy(buf, fifo->buffer + (fifo->out & (fifo->size - 1)), l);
84104bc4bdf55bd79c2b3f9087601c3df4aa884b2aJens Axboe
85104bc4bdf55bd79c2b3f9087601c3df4aa884b2aJens Axboe		/*
86104bc4bdf55bd79c2b3f9087601c3df4aa884b2aJens Axboe		 * then get the rest (if any) from the beginning of the buffer
87104bc4bdf55bd79c2b3f9087601c3df4aa884b2aJens Axboe		 */
885ec10eaad3b09875b91e19a20bbdfa06f2117562Jens Axboe		memcpy(buf + l, fifo->buffer, len - l);
89104bc4bdf55bd79c2b3f9087601c3df4aa884b2aJens Axboe	}
90e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe
91e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe	fifo->out += len;
92e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe
93104bc4bdf55bd79c2b3f9087601c3df4aa884b2aJens Axboe	if (fifo->in == fifo->out)
94104bc4bdf55bd79c2b3f9087601c3df4aa884b2aJens Axboe		fifo->in = fifo->out = 0;
95104bc4bdf55bd79c2b3f9087601c3df4aa884b2aJens Axboe
96e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe	return len;
97e28875637094451a3c5ec4071f964c1a02dd8f5bJens Axboe}
98