Staging: Use kmemdup
[linux-2.6/libata-dev.git] / drivers / staging / dt3155v4l / dt3155-bufs.c
blobf93e431e786b3038e3d68a0e5ccde8c0f3b4eafa
1 /***************************************************************************
2 * Copyright (C) 2006-2010 by Marin Mitov *
3 * mitov@issp.bas.bg *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
21 #include "dt3155-bufs.h"
23 /**
24 * dt3155_init_chunks_buf - creates a chunk buffer and allocates memory for it
26 * returns: a pointer to the struct dt3155_buf or NULL if failed
28 * Creates a struct dt3155_buf, then allocates a chunk of memory of
29 * size DT3155_CHUNK_SIZE and sets all the pages in it as Reserved.
30 * This is done to be able to use remap_pfn_range() on these buffers
31 * (which do not work on normal memory if Reserved bit is not set)
33 struct dt3155_buf *
34 dt3155_init_chunks_buf(void)
35 { /* could sleep */
36 struct dt3155_buf *buf;
37 int i;
39 buf = kzalloc(sizeof(*buf), GFP_KERNEL);
40 if (!buf)
41 return NULL;
42 buf->cpu = (void *)__get_free_pages(DT3155_CHUNK_FLAGS,
43 get_order(DT3155_CHUNK_SIZE));
44 if (!buf->cpu) {
45 kfree(buf);
46 return NULL;
48 for (i = 0; i < DT3155_CHUNK_SIZE; i += PAGE_SIZE)
49 SetPageReserved(virt_to_page(buf->cpu + i));
50 return buf; /* success */
53 /**
54 * dt3155_free_chunks_buf - destroys the specified buffer
56 * @buf: the buffer to be freed
58 * Clears Reserved bit of all pages in the chunk, frees the chunk memory
59 * and destroys struct dt3155_buf.
61 void
62 dt3155_free_chunks_buf(struct dt3155_buf *buf)
64 int i;
66 for (i = 0; i < DT3155_CHUNK_SIZE; i += PAGE_SIZE)
67 ClearPageReserved(virt_to_page(buf->cpu + i));
68 free_pages((unsigned long)buf->cpu, get_order(DT3155_CHUNK_SIZE));
69 kfree(buf);
72 /**
73 * dt3155_init_fifo - creates and initializes a fifo
75 * returns: a pointer to the crated and initialized struct dt3155_fifo
76 * or NULL if failed
78 struct dt3155_fifo *
79 dt3155_init_fifo(void)
80 { /* could sleep */
81 struct dt3155_fifo *fifo = kzalloc(sizeof(*fifo), GFP_KERNEL);
82 if (fifo)
83 spin_lock_init(&fifo->lock);
84 return fifo;
87 /* dt3155_free_fifo(x) defined as macro in dt3155.h */
89 /**
90 * dt3155_get_buf - gets a buffer from the fifo
92 * @fifo: the fifo to get a buffer from
94 * returns: a pointer to the buffer or NULL if failed
96 * dt3155_get_buf gets the fifo's spin_lock and returns the
97 * buffer pointed by the head. Could be used in any context.
99 struct dt3155_buf *
100 dt3155_get_buf(struct dt3155_fifo *fifo)
102 unsigned long flags;
103 struct dt3155_buf *tmp_buf;
105 spin_lock_irqsave(&fifo->lock, flags);
106 tmp_buf = fifo->head;
107 if (fifo->head)
108 fifo->head = fifo->head->next;
109 if (!fifo->head)
110 fifo->tail = NULL;
111 spin_unlock_irqrestore(&fifo->lock, flags);
112 return tmp_buf;
116 * dt3155_put_buf - puts a buffer into a fifo
118 * @buf: the buffer to put
119 * @fifo: the fifo to put the buffer in
121 * dt3155_put_buf gets the fifo's spin_lock and puts the buf
122 * at the tail of the fifo. Could be used in any context.
124 void
125 dt3155_put_buf(struct dt3155_buf *buf, struct dt3155_fifo *fifo)
127 unsigned long flags;
129 spin_lock_irqsave(&fifo->lock, flags);
130 buf->next = NULL;
131 if (fifo->tail)
132 fifo->tail->next = buf;
133 fifo->tail = buf;
134 if (!fifo->head)
135 fifo->head = buf;
136 spin_unlock_irqrestore(&fifo->lock, flags);
140 * dt3155_init_chunks_fifo - creates and fills a chunks_fifo
142 * returns: a pointer to the fifo or NULL if failed
144 * dt3155_init_chunks_fifo creates and fills the fifo with
145 * a number of chunks <= DT3155_CHUNK_NUM. The returned fifo
146 * contains at least one chunk.
148 struct dt3155_fifo *
149 dt3155_init_chunks_fifo(void)
150 { /* could sleep */
151 int i;
153 struct dt3155_fifo *chunks;
154 struct dt3155_buf *tmp_buf;
156 chunks = dt3155_init_fifo();
157 if (!chunks)
158 return NULL;
159 tmp_buf = dt3155_init_chunks_buf();
160 if (!tmp_buf) {
161 dt3155_free_fifo(chunks);
162 return NULL;
164 dt3155_put_buf(tmp_buf, chunks);
165 for (i = 1; i < DT3155_CHUNK_NUM; i++) {
166 tmp_buf = dt3155_init_chunks_buf();
167 if (!tmp_buf)
168 break;
169 dt3155_put_buf(tmp_buf, chunks);
171 return chunks;
175 * dt3155_free_chunks_fifo - empties and destroys the chunks_fifo
177 * @chunks: the chunks_fifo to be freed
179 * dt3155_free_chunks_fifo deallocates all chunks in the fifo and
180 * destroys it.
182 void
183 dt3155_free_chunks_fifo(struct dt3155_fifo *chunks)
185 int buf_count = 0;
186 struct dt3155_buf *buf;
188 while ((buf = dt3155_get_buf(chunks))) {
189 dt3155_free_chunks_buf(buf);
190 buf_count++;
192 dt3155_free_fifo(chunks);
193 printk(KERN_INFO "dt3155: %i chunks freed\n", buf_count);
197 * dt3155_init_ibufs_fifo - creates and fills an image buffer fifo
199 * @chunks: chunks_fifo to take memory from
200 * @buf_size: the size of image buffers
202 * returns: a pointer to the fifo filled with image buffers
204 * dt3155_init_ibufs_fifo takes chunks from chunks_fifo, chops them
205 * into pieces of size buf_size and fills image fifo with them.
207 struct dt3155_fifo *
208 dt3155_init_ibufs_fifo(struct dt3155_fifo *chunks, int buf_size)
209 { /* could sleep */
210 int i, buf_count = 0;
211 struct dt3155_buf *tmp_ibuf, *chunks_buf, *last_chunk;
212 struct dt3155_fifo *tmp_fifo;
214 tmp_fifo = dt3155_init_fifo();
215 if (!tmp_fifo)
216 return NULL;
217 last_chunk = chunks->tail;
218 do {
219 chunks_buf = dt3155_get_buf(chunks);
220 dt3155_put_buf(chunks_buf, chunks);
221 for (i = 0; i < DT3155_CHUNK_SIZE / buf_size; i++) {
222 tmp_ibuf = kzalloc(sizeof(*tmp_ibuf), GFP_KERNEL);
223 if (tmp_ibuf) {
224 tmp_ibuf->cpu =
225 chunks_buf->cpu + DT3155_BUF_SIZE * i;
226 dt3155_put_buf(tmp_ibuf, tmp_fifo);
227 buf_count++;
228 } else {
229 if (buf_count) {
230 goto print_num_bufs;
231 } else {
232 dt3155_free_fifo(tmp_fifo);
233 return NULL;
237 } while (chunks_buf != last_chunk);
238 print_num_bufs:
239 printk(KERN_INFO "dt3155: %i image buffers available\n", buf_count);
240 return tmp_fifo;
244 * dt3155_free_ibufs_fifo - empties and destroys an image fifo
246 * @fifo: the fifo to free
248 void
249 dt3155_free_ibufs_fifo(struct dt3155_fifo *fifo)
251 struct dt3155_buf *tmp_ibuf;
253 while ((tmp_ibuf = dt3155_get_buf(fifo)))
254 kfree(tmp_ibuf);
255 kfree(fifo);