Setting up repository
[linux-libre-firmware.git] / carl9170fw / tools / include / frame.h
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation version 2 of the License.
5  *
6  * This program is distributed in the hope that it will be useful,
7  * but WITHOUT ANY WARRANTY; without even the implied warranty of
8  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
9  * GNU General Public License for more details.
10  *
11  * You should have received a copy of the GNU General Public License along
12  * with this program; if not, write to the Free Software Foundation, Inc.,
13  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
14  *
15  * Most ideas and some code are copied from the linux' kernels
16  *      include/linux/skbuff.h
17  */
18
19 #ifndef __TOOLS_FRAME_H
20 #define __TOOLS_FRAME_H
21
22 #include "SDL.h"
23 #include "list.h"
24
25 /**
26  * struct frame_queue - sk_buff_head like frame queue
27  *
28  * @list: pointer to head and tail
29  * @lock: mutex lock for serialize access
30  * @len: exact number of queued frames
31  */
32
33 struct frame_queue {
34         struct list_head list;
35         SDL_mutex *lock;
36         size_t len;
37 };
38
39 /**
40  * struct frame - frame data structure (like sk_buff)
41  *
42  * @list: storage for double-linked &struct frame_queue list
43  * @dev: pointer to private device/driver structure
44  * @timestamp: space for the current timestamp
45  * @cb: private driver data
46  * @dcb: more reserved space for low-level / backend driver
47  * @queue: selected frame queue / priority
48  * @ref: reference counter
49  * @alloced: maximum available space
50  * @total_len: currently consumed and reserved memory
51  * @len: current frame length
52  * @head: points to the buffer head
53  * @data: current frame data pointer
54  * @tail: frame data tail pointer
55  * @payload: frame data storage container
56  */
57
58 struct frame {
59         struct list_head list;
60         void *dev;
61         unsigned long timestamp;
62         uint8_t cb[64];
63         union {
64                 struct list_head list;
65                 uint8_t raw_data[32];
66         } dcb;
67
68         unsigned int queue;
69         unsigned int ref;
70         unsigned int alloced;
71         unsigned int total_len;
72         unsigned int len;
73         uint8_t *head;
74         uint8_t *data;
75         uint8_t *tail;
76
77         /* payload must be the last entry */
78         uint8_t payload[0];
79 };
80
81 /**
82  * frame_put - append more data to &struct frame
83  *
84  * Allocate @size bytes from &struct frame tail and
85  * returns a pointer to the requested location.
86  *
87  * @frame: frame to alter
88  * @size: extra size
89  */
90 static inline void *frame_put(struct frame *frame, unsigned int size)
91 {
92         void *tmp;
93
94         BUG_ON(frame->total_len + size > frame->alloced);
95
96         frame->len += size;
97         frame->total_len += size;
98
99         tmp = (void *) frame->tail;
100         frame->tail += size;
101
102         BUG_ON(frame->tail > (frame->payload + frame->alloced));
103
104         return tmp;
105 }
106
107 /**
108  * frame_push - allocate head
109  *
110  * returns a pointer to a newly allocate area at &struct frame head.
111  *
112  * @frame: frame to modify
113  * @size: requested extra size
114  */
115 static inline void *frame_push(struct frame *frame, unsigned int size)
116 {
117         frame->len += size;
118         frame->data -= size;
119
120         BUG_ON(frame->data < frame->payload);
121         return frame->data;
122 }
123
124 /**
125  * frame_get - reference frame buffer
126  *
127  * grab a reference from the frame buffer, in order to
128  * prevent it from being freed prematurely by a different user.
129  *
130  * @frame: frame pointer
131  */
132 static inline struct frame *frame_get(struct frame *frame)
133 {
134         frame->ref++;
135         return frame;
136 }
137
138 /**
139  * frame_pull - remove space from &struct frame head
140  *
141  * Does the opposite of frame_push() and removes freed-up
142  * space at the frames's head.
143  *
144  * @frame: pointer to frame structure
145  * @size: bytes to remove from head
146  */
147 static inline void *frame_pull(struct frame *frame, unsigned int size)
148 {
149         BUG_ON(frame->len < size);
150
151         frame->len -= size;
152         frame->total_len -= size;
153         frame->data += size;
154
155         return frame->data;
156 }
157
158 /**
159  * frame_reserve - reserve frame headroom
160  *
161  * Reserve a certain amount of space to allow headroom manipulations
162  * in the future.
163  *
164  * @frame: frame to adjust
165  * @size: bytes to reserve
166  */
167 static inline void frame_reserve(struct frame *frame, unsigned int size)
168 {
169         BUG_ON(frame->total_len + size > frame->alloced);
170         BUG_ON(frame->len != 0);
171
172         frame->total_len += size;
173         frame->data += size;
174         frame->tail += size;
175 }
176
177 /**
178  * frame_trim - set frame length
179  *
180  * cut the frame to @size length.
181  *
182  * @frame: frame to be trimmed
183  * @size: new length
184  */
185 static inline void frame_trim(struct frame *frame, unsigned int size)
186 {
187         BUG_ON(size > frame->total_len);
188
189         frame->len = size;
190         frame->total_len = size;
191         frame->data = frame->head;
192         frame->tail = frame->head + size;
193 }
194
195 /**
196  * frame_alloc - alloc and initialize new frame
197  *
198  * returns a newly created &struct frame object.
199  *
200  * @size: maximum frame size of the new frame
201  */
202 static inline struct frame *frame_alloc(unsigned int size)
203 {
204         struct frame *tmp;
205
206         tmp = malloc(size + sizeof(*tmp));
207         if (tmp != NULL) {
208                 memset(tmp, 0, sizeof(*tmp));
209                 init_list_head(&tmp->list);
210                 init_list_head(&tmp->dcb.list);
211                 tmp->len = 0;
212                 tmp->total_len = 0;
213                 tmp->alloced = size;
214
215                 tmp->head = tmp->payload;
216                 tmp->data = tmp->payload;
217                 tmp->tail = tmp->payload;
218                 tmp->ref = 1;
219         }
220         return tmp;
221 }
222
223 /**
224  * frame_free - unref and free frame
225  *
226  * Unreference frame and free it up, if all users are gone.
227  *
228  * @frame: frame to be freed
229  */
230 static inline void frame_free(struct frame *frame)
231 {
232         if (!--frame->ref)
233                 free(frame);
234 }
235
236 /**
237  * FRAME_WALK - MACRO walker
238  *
239  * Walks over all queued elements in &struct frame_queue
240  *
241  * NOTE: This function is vulnerable in concurrent access
242  *       scenarios without proper locking.
243  *
244  * @pos: current position inside the queue
245  * @head: &struct frame_queue head
246  */
247 #define FRAME_WALK(pos, head)                                   \
248         list_for_each_entry((pos), &(head)->list, list)
249
250 static inline void __frame_queue_init(struct frame_queue *queue)
251 {
252         queue->len = 0;
253         init_list_head(&queue->list);
254 }
255
256 /**
257  * frame_queue_init - initialize frame_queue
258  *
259  * Initialize the given &struct frame_queue object.
260  *
261  * @queue: frame_queue to be initialized
262  */
263 static inline void frame_queue_init(struct frame_queue *queue)
264 {
265         queue->lock = SDL_CreateMutex();
266         __frame_queue_init(queue);
267 }
268
269 /**
270  * frame_queue_len - returns number of queue elements
271  *
272  * @queue: frame_queue object
273  */
274 static inline unsigned int frame_queue_len(struct frame_queue *queue)
275 {
276         return queue->len;
277 }
278
279 /**
280  * frame_queue_empty - returns %TRUE whenever queue is empty
281  *
282  * @queue: frame_queue object
283  */
284 static inline bool frame_queue_empty(struct frame_queue *queue)
285 {
286         return list_empty(&queue->list);
287 }
288
289 static inline void __frame_queue_head(struct frame_queue *queue, struct frame *frame)
290 {
291         list_add_head(&frame->list, &queue->list);
292         queue->len++;
293 }
294
295 /**
296  * frame_queue_head - queue a frame at the queues head
297  * @queue: queue to use
298  */
299 static inline void frame_queue_head(struct frame_queue *queue, struct frame *frame)
300 {
301         BUG_ON((SDL_mutexP(queue->lock) != 0));
302         __frame_queue_head(queue, frame);
303         SDL_mutexV(queue->lock);
304 }
305
306 static inline void __frame_queue_tail(struct frame_queue *queue, struct frame *frame)
307 {
308         list_add_tail(&frame->list, &queue->list);
309         queue->len++;
310 }
311
312 /**
313  * frame_queue_head - queue a frame at the queues tail
314  * @queue: queue to use
315  */
316 static inline void frame_queue_tail(struct frame_queue *queue, struct frame *frame)
317 {
318         BUG_ON((SDL_mutexP(queue->lock) != 0));
319         __frame_queue_tail(queue, frame);
320         SDL_mutexV(queue->lock);
321 }
322
323 static inline void __frame_unlink(struct frame_queue *queue, struct frame *frame)
324 {
325         list_del(&frame->list);
326         queue->len--;
327 }
328
329 /**
330  * frame_queue_unlink - remove a frame from the queue
331  * @queue: queue to use
332  * @frame: frame to remove
333  */
334 static inline void frame_unlink(struct frame_queue *queue, struct frame *frame)
335 {
336         BUG_ON((SDL_mutexP(queue->lock) != 0));
337         __frame_unlink(queue, frame);
338         SDL_mutexV(queue->lock);
339 }
340
341
342 static inline struct frame *__frame_dequeue(struct frame_queue *queue)
343 {
344         struct frame *tmp = NULL;
345
346         if (!frame_queue_empty(queue)) {
347                 tmp = list_entry(queue->list.next, struct frame, list);
348                 __frame_unlink(queue, tmp);
349         }
350
351         return tmp;
352 }
353
354 /**
355  * frame_dequeue - remove frame from the head of the queue
356  *
357  * @queue: queue to dequeue from
358  */
359 static inline struct frame *frame_dequeue(struct frame_queue *queue)
360 {
361         struct frame *tmp;
362
363         BUG_ON((SDL_mutexP(queue->lock) != 0));
364
365         tmp = __frame_dequeue(queue);
366         SDL_mutexV(queue->lock);
367         return tmp;
368 }
369
370 static inline void __frame_queue_purge(struct frame_queue *queue)
371 {
372         while (list_empty(&queue->list) == false)
373                 frame_free(__frame_dequeue(queue));
374 }
375
376 /**
377  * frame_queue_purge - frees all queued &struct frame objects
378  *
379  * @queue: queue to be freed
380  */
381 static inline void frame_queue_purge(struct frame_queue *queue)
382 {
383         BUG_ON((SDL_mutexP(queue->lock) != 0));
384         __frame_queue_purge(queue);
385         SDL_mutexV(queue->lock);
386 }
387
388 /**
389  * frame_queue_kill - destroys frame_queue object
390  *
391  * Destroy object and frees up all remaining elements
392  *
393  * @queue: frame_queue victim
394  */
395 static inline void frame_queue_kill(struct frame_queue *queue)
396 {
397         SDL_DestroyMutex(queue->lock);
398         __frame_queue_purge(queue);
399 }
400
401 #endif /* __TOOLS_FRAME_H */