Magellan Linux

Annotation of /alx-src/tags/kernel26-2.6.12-alx-r9/kernel/kfifo.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 630 - (hide annotations) (download)
Wed Mar 4 11:03:09 2009 UTC (15 years, 3 months ago) by niro
File MIME type: text/plain
File size: 4764 byte(s)
Tag kernel26-2.6.12-alx-r9
1 niro 628 /*
2     * A simple kernel FIFO implementation.
3     *
4     * Copyright (C) 2004 Stelian Pop <stelian@popies.net>
5     *
6     * This program is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19     *
20     */
21    
22     #include <linux/kernel.h>
23     #include <linux/module.h>
24     #include <linux/slab.h>
25     #include <linux/err.h>
26     #include <linux/kfifo.h>
27    
28     /**
29     * kfifo_init - allocates a new FIFO using a preallocated buffer
30     * @buffer: the preallocated buffer to be used.
31     * @size: the size of the internal buffer, this have to be a power of 2.
32     * @gfp_mask: get_free_pages mask, passed to kmalloc()
33     * @lock: the lock to be used to protect the fifo buffer
34     *
35     * Do NOT pass the kfifo to kfifo_free() after use ! Simply free the
36     * struct kfifo with kfree().
37     */
38     struct kfifo *kfifo_init(unsigned char *buffer, unsigned int size,
39     unsigned int __nocast gfp_mask, spinlock_t *lock)
40     {
41     struct kfifo *fifo;
42    
43     /* size must be a power of 2 */
44     BUG_ON(size & (size - 1));
45    
46     fifo = kmalloc(sizeof(struct kfifo), gfp_mask);
47     if (!fifo)
48     return ERR_PTR(-ENOMEM);
49    
50     fifo->buffer = buffer;
51     fifo->size = size;
52     fifo->in = fifo->out = 0;
53     fifo->lock = lock;
54    
55     return fifo;
56     }
57     EXPORT_SYMBOL(kfifo_init);
58    
59     /**
60     * kfifo_alloc - allocates a new FIFO and its internal buffer
61     * @size: the size of the internal buffer to be allocated.
62     * @gfp_mask: get_free_pages mask, passed to kmalloc()
63     * @lock: the lock to be used to protect the fifo buffer
64     *
65     * The size will be rounded-up to a power of 2.
66     */
67     struct kfifo *kfifo_alloc(unsigned int size, unsigned int __nocast gfp_mask, spinlock_t *lock)
68     {
69     unsigned char *buffer;
70     struct kfifo *ret;
71    
72     /*
73     * round up to the next power of 2, since our 'let the indices
74     * wrap' tachnique works only in this case.
75     */
76     if (size & (size - 1)) {
77     BUG_ON(size > 0x80000000);
78     size = roundup_pow_of_two(size);
79     }
80    
81     buffer = kmalloc(size, gfp_mask);
82     if (!buffer)
83     return ERR_PTR(-ENOMEM);
84    
85     ret = kfifo_init(buffer, size, gfp_mask, lock);
86    
87     if (IS_ERR(ret))
88     kfree(buffer);
89    
90     return ret;
91     }
92     EXPORT_SYMBOL(kfifo_alloc);
93    
94     /**
95     * kfifo_free - frees the FIFO
96     * @fifo: the fifo to be freed.
97     */
98     void kfifo_free(struct kfifo *fifo)
99     {
100     kfree(fifo->buffer);
101     kfree(fifo);
102     }
103     EXPORT_SYMBOL(kfifo_free);
104    
105     /**
106     * __kfifo_put - puts some data into the FIFO, no locking version
107     * @fifo: the fifo to be used.
108     * @buffer: the data to be added.
109     * @len: the length of the data to be added.
110     *
111     * This function copies at most 'len' bytes from the 'buffer' into
112     * the FIFO depending on the free space, and returns the number of
113     * bytes copied.
114     *
115     * Note that with only one concurrent reader and one concurrent
116     * writer, you don't need extra locking to use these functions.
117     */
118     unsigned int __kfifo_put(struct kfifo *fifo,
119     unsigned char *buffer, unsigned int len)
120     {
121     unsigned int l;
122    
123     len = min(len, fifo->size - fifo->in + fifo->out);
124    
125     /* first put the data starting from fifo->in to buffer end */
126     l = min(len, fifo->size - (fifo->in & (fifo->size - 1)));
127     memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, l);
128    
129     /* then put the rest (if any) at the beginning of the buffer */
130     memcpy(fifo->buffer, buffer + l, len - l);
131    
132     fifo->in += len;
133    
134     return len;
135     }
136     EXPORT_SYMBOL(__kfifo_put);
137    
138     /**
139     * __kfifo_get - gets some data from the FIFO, no locking version
140     * @fifo: the fifo to be used.
141     * @buffer: where the data must be copied.
142     * @len: the size of the destination buffer.
143     *
144     * This function copies at most 'len' bytes from the FIFO into the
145     * 'buffer' and returns the number of copied bytes.
146     *
147     * Note that with only one concurrent reader and one concurrent
148     * writer, you don't need extra locking to use these functions.
149     */
150     unsigned int __kfifo_get(struct kfifo *fifo,
151     unsigned char *buffer, unsigned int len)
152     {
153     unsigned int l;
154    
155     len = min(len, fifo->in - fifo->out);
156    
157     /* first get the data from fifo->out until the end of the buffer */
158     l = min(len, fifo->size - (fifo->out & (fifo->size - 1)));
159     memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size - 1)), l);
160    
161     /* then get the rest (if any) from the beginning of the buffer */
162     memcpy(buffer + l, fifo->buffer, len - l);
163    
164     fifo->out += len;
165    
166     return len;
167     }
168     EXPORT_SYMBOL(__kfifo_get);