This file is indexed.

/usr/include/xenomai/analogy/buffer.h is in libxenomai-dev 2.6.4+dfsg-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
/**
 * @file
 * Analogy for Linux, buffer related features
 *
 * Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org>
 * Copyright (C) 2008 Alexis Berlemont <alexis.berlemont@free.fr>
 *
 * Xenomai is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Xenomai is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Xenomai; if not, write to the Free Software Foundation,
 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#ifndef __ANALOGY_BUFFER_H__
#define __ANALOGY_BUFFER_H__

#ifndef DOXYGEN_CPP

#ifdef __KERNEL__

#include <linux/version.h>
#include <linux/mm.h>

#include <rtdm/rtdm_driver.h>

#include <analogy/os_facilities.h>
#include <analogy/context.h>

/* --- Events bits / flags --- */

#define A4L_BUF_EOBUF_NR 0
#define A4L_BUF_EOBUF (1 << A4L_BUF_EOBUF_NR)

#define A4L_BUF_ERROR_NR 1
#define A4L_BUF_ERROR (1 << A4L_BUF_ERROR_NR)

#define A4L_BUF_EOA_NR 2
#define A4L_BUF_EOA (1 << A4L_BUF_EOA_NR)

/* --- Status bits / flags --- */

#define A4L_BUF_BULK_NR 8
#define A4L_BUF_BULK (1 << A4L_BUF_BULK_NR)

#define A4L_BUF_MAP_NR 9
#define A4L_BUF_MAP (1 << A4L_BUF_MAP_NR)

struct a4l_subdevice;

/* Buffer descriptor structure */
struct a4l_buffer {

	/* Added by the structure update */
	struct a4l_subdevice *subd;

	/* Buffer's first virtual page pointer */
	void *buf;

	/* Buffer's global size */
	unsigned long size;
	/* Tab containing buffer's pages pointers */
	unsigned long *pg_list;

	/* RT/NRT synchronization element */
	a4l_sync_t sync;

	/* Counters needed for transfer */
	unsigned long end_count;
	unsigned long prd_count;
	unsigned long cns_count;
	unsigned long tmp_count;

	/* Status + events occuring during transfer */
	unsigned long flags;

	/* Command on progress */
	a4l_cmd_t *cur_cmd;

	/* Munge counter */
	unsigned long mng_count;

	/* Theshold below which the user process should not be
	   awakened */
	unsigned long wake_count;
};
typedef struct a4l_buffer a4l_buf_t;

/* --- Static inline functions related with
   user<->kernel data transfers --- */

/* The function __produce is an inline function which copies data into
   the asynchronous buffer and takes care of the non-contiguous issue
   when looping. This function is used in read and write operations */
static inline int __produce(a4l_cxt_t *cxt,
			    a4l_buf_t *buf, void *pin, unsigned long count)
{
	unsigned long start_ptr = (buf->prd_count % buf->size);
	unsigned long tmp_cnt = count;
	int ret = 0;

	while (ret == 0 && tmp_cnt != 0) {
		/* Check the data copy can be performed contiguously */
		unsigned long blk_size = (start_ptr + tmp_cnt > buf->size) ?
			buf->size - start_ptr : tmp_cnt;

		/* Perform the copy */
		if (cxt == NULL)
			memcpy(buf->buf + start_ptr, pin, blk_size);
		else
			ret = rtdm_safe_copy_from_user(cxt->user_info,
						       buf->buf + start_ptr,
						       pin, blk_size);

		/* Update pointers/counts */
		pin += blk_size;
		tmp_cnt -= blk_size;
		start_ptr = 0;
	}

	return ret;
}

/* The function __consume is an inline function which copies data from
   the asynchronous buffer and takes care of the non-contiguous issue
   when looping. This function is used in read and write operations */
static inline int __consume(a4l_cxt_t *cxt,
			    a4l_buf_t *buf, void *pout, unsigned long count)
{
	unsigned long start_ptr = (buf->cns_count % buf->size);
	unsigned long tmp_cnt = count;
	int ret = 0;

	while (ret == 0 && tmp_cnt != 0) {
		/* Check the data copy can be performed contiguously */
		unsigned long blk_size = (start_ptr + tmp_cnt > buf->size) ?
			buf->size - start_ptr : tmp_cnt;

		/* Perform the copy */
		if (cxt == NULL)
			memcpy(pout, buf->buf + start_ptr, blk_size);
		else
			ret = rtdm_safe_copy_to_user(cxt->user_info,
						     pout,
						     buf->buf + start_ptr,
						     blk_size);

		/* Update pointers/counts */
		pout += blk_size;
		tmp_cnt -= blk_size;
		start_ptr = 0;
	}

	return ret;
}

/* The function __munge is an inline function which calls the
   subdevice specific munge callback on contiguous windows within the
   whole buffer. This function is used in read and write operations */
static inline void __munge(struct a4l_subdevice * subd,
			   void (*munge) (struct a4l_subdevice *,
					  void *, unsigned long),
			   a4l_buf_t * buf, unsigned long count)
{
	unsigned long start_ptr = (buf->mng_count % buf->size);
	unsigned long tmp_cnt = count;

	while (tmp_cnt != 0) {
		/* Check the data copy can be performed contiguously */
		unsigned long blk_size = (start_ptr + tmp_cnt > buf->size) ?
			buf->size - start_ptr : tmp_cnt;

		/* Perform the munge operation */
		munge(subd, buf->buf + start_ptr, blk_size);

		/* Update the start pointer and the count */
		tmp_cnt -= blk_size;
		start_ptr = 0;
	}
}

/* The function __handle_event can only be called from process context
   (not interrupt service routine). It allows the client process to
   retrieve the buffer status which has been updated by the driver */
static inline int __handle_event(a4l_buf_t * buf)
{
	int ret = 0;

	/* The event "End of acquisition" must not be cleaned
	   before the complete flush of the buffer */
	if (test_bit(A4L_BUF_EOA_NR, &buf->flags)) {
		ret = -ENOENT;
	}

	if (test_bit(A4L_BUF_ERROR_NR, &buf->flags)) {
		ret = -EPIPE;
	}

	return ret;
}

/* --- Counters management functions --- */

/* Here, we may wonder why we need more than two counters / pointers.

   Theoretically, we only need two counters (or two pointers):
   - one which tells where the reader should be within the buffer
   - one which tells where the writer should be within the buffer

   With these two counters (or pointers), we just have to check that
   the writer does not overtake the reader inside the ring buffer
   BEFORE any read / write operations.

   However, if one element is a DMA controller, we have to be more
   careful. Generally a DMA transfer occurs like this:
   DMA shot
      |-> then DMA interrupt
	 |-> then DMA soft handler which checks the counter

   So, the checkings occur AFTER the write operations.

   Let's take an example: the reader is a software task and the writer
   is a DMA controller. At the end of the DMA shot, the write counter
   is higher than the read counter. Unfortunately, a read operation
   occurs between the DMA shot and the DMA interrupt, so the handler
   will not notice that an overflow occured.

   That is why tmp_count comes into play: tmp_count records the
   read/consumer current counter before the next DMA shot and once the
   next DMA shot is done, we check that the updated writer/producer
   counter is not higher than tmp_count. Thus we are sure that the DMA
   writer has not overtaken the reader because it was not able to
   overtake the n-1 value. */

static inline int __pre_abs_put(a4l_buf_t * buf, unsigned long count)
{
	if (count - buf->tmp_count > buf->size) {
		set_bit(A4L_BUF_ERROR_NR, &buf->flags);
		return -EPIPE;
	}

	buf->tmp_count = buf->cns_count;

	return 0;
}

static inline int __pre_put(a4l_buf_t * buf, unsigned long count)
{
	return __pre_abs_put(buf, buf->tmp_count + count);
}

static inline int __pre_abs_get(a4l_buf_t * buf, unsigned long count)
{
	/* The first time, we expect the buffer to be properly filled
	before the trigger occurence; by the way, we need tmp_count to
	have been initialized and tmp_count is updated right here */
	if (buf->tmp_count == 0 || buf->cns_count == 0)
		goto out;

	/* At the end of the acquisition, the user application has
	written the defined amount of data into the buffer; so the
	last time, the DMA channel can easily overtake the tmp
	frontier because no more data were sent from user space;
	therefore no useless alarm should be sent */
	if (buf->end_count != 0 && (long)(count - buf->end_count) > 0)
		goto out;

	/* Once the exception are passed, we check that the DMA
	transfer has not overtaken the last record of the production
	count (tmp_count was updated with prd_count the last time
	__pre_abs_get was called). We must understand that we cannot
	compare the current DMA count with the current production
	count because even if, right now, the production count is
	higher than the DMA count, it does not mean that the DMA count
	was not greater a few cycles before; in such case, the DMA
	channel would have retrieved the wrong data */
	if ((long)(count - buf->tmp_count) > 0) {
		set_bit(A4L_BUF_ERROR_NR, &buf->flags);
		return -EPIPE;
	}

out:
	buf->tmp_count = buf->prd_count;

	return 0;
}

static inline int __pre_get(a4l_buf_t * buf, unsigned long count)
{
	return __pre_abs_get(buf, buf->tmp_count + count);
}

static inline int __abs_put(a4l_buf_t * buf, unsigned long count)
{
	unsigned long old = buf->prd_count;

	if ((long)(buf->prd_count - count) >= 0)
		return -EINVAL;

	buf->prd_count = count;

	if ((old / buf->size) != (count / buf->size))
		set_bit(A4L_BUF_EOBUF_NR, &buf->flags);

	if (buf->end_count != 0 && (long)(count - buf->end_count) >= 0)
		set_bit(A4L_BUF_EOA_NR, &buf->flags);

	return 0;
}

static inline int __put(a4l_buf_t * buf, unsigned long count)
{
	return __abs_put(buf, buf->prd_count + count);
}

static inline int __abs_get(a4l_buf_t * buf, unsigned long count)
{
	unsigned long old = buf->cns_count;

	if ((long)(buf->cns_count - count) >= 0)
		return -EINVAL;

	buf->cns_count = count;

	if ((old / buf->size) != count / buf->size)
		set_bit(A4L_BUF_EOBUF_NR, &buf->flags);

	if (buf->end_count != 0 && (long)(count - buf->end_count) >= 0)
		set_bit(A4L_BUF_EOA_NR, &buf->flags);

	return 0;
}

static inline int __get(a4l_buf_t * buf, unsigned long count)
{
	return __abs_get(buf, buf->cns_count + count);
}

static inline unsigned long __count_to_put(a4l_buf_t * buf)
{
	unsigned long ret;

	if ((long) (buf->size + buf->cns_count - buf->prd_count) > 0)
		ret = buf->size + buf->cns_count - buf->prd_count;
	else
		ret = 0;

	return ret;
}

static inline unsigned long __count_to_get(a4l_buf_t * buf)
{
	unsigned long ret;

	/* If the acquisition is unlimited (end_count == 0), we must
	   not take into account end_count */
	if (buf->end_count == 0 || (long)(buf->end_count - buf->prd_count) > 0)
		ret = buf->prd_count;
	else
		ret = buf->end_count;

	if ((long)(ret - buf->cns_count) > 0)
		ret -= buf->cns_count;
	else
		ret = 0;

	return ret;
}

static inline unsigned long __count_to_end(a4l_buf_t * buf)
{
	unsigned long ret = buf->end_count - buf->cns_count;

	if (buf->end_count == 0)
		return ULONG_MAX;

	return ((long)ret) < 0 ? 0 : ret;
}

/* --- Buffer internal functions --- */

int a4l_alloc_buffer(a4l_buf_t *buf_desc, int buf_size);

void a4l_free_buffer(a4l_buf_t *buf_desc);

void a4l_init_buffer(a4l_buf_t * buf_desc);

void a4l_cleanup_buffer(a4l_buf_t * buf_desc);

int a4l_setup_buffer(a4l_cxt_t *cxt, a4l_cmd_t *cmd);

int a4l_cancel_buffer(a4l_cxt_t *cxt);

int a4l_buf_prepare_absput(struct a4l_subdevice *subd,
			   unsigned long count);

int a4l_buf_commit_absput(struct a4l_subdevice *subd,
			  unsigned long count);

int a4l_buf_prepare_put(struct a4l_subdevice *subd,
			unsigned long count);

int a4l_buf_commit_put(struct a4l_subdevice *subd,
		       unsigned long count);

int a4l_buf_put(struct a4l_subdevice *subd,
		void *bufdata, unsigned long count);

int a4l_buf_prepare_absget(struct a4l_subdevice *subd,
			   unsigned long count);

int a4l_buf_commit_absget(struct a4l_subdevice *subd,
			  unsigned long count);

int a4l_buf_prepare_get(struct a4l_subdevice *subd,
			unsigned long count);

int a4l_buf_commit_get(struct a4l_subdevice *subd,
		       unsigned long count);

int a4l_buf_get(struct a4l_subdevice *subd,
		void *bufdata, unsigned long count);

int a4l_buf_evt(struct a4l_subdevice *subd, unsigned long evts);

unsigned long a4l_buf_count(struct a4l_subdevice *subd);

/* --- Current Command management function --- */

static inline a4l_cmd_t *a4l_get_cmd(a4l_subd_t *subd)
{
	return (subd->buf) ? subd->buf->cur_cmd : NULL;
}

/* --- Munge related function --- */

int a4l_get_chan(struct a4l_subdevice *subd);

/* --- IOCTL / FOPS functions --- */

int a4l_ioctl_mmap(a4l_cxt_t * cxt, void *arg);
int a4l_ioctl_bufcfg(a4l_cxt_t * cxt, void *arg);
int a4l_ioctl_bufcfg2(a4l_cxt_t * cxt, void *arg);
int a4l_ioctl_bufinfo(a4l_cxt_t * cxt, void *arg);
int a4l_ioctl_bufinfo2(a4l_cxt_t * cxt, void *arg);
int a4l_ioctl_poll(a4l_cxt_t * cxt, void *arg);
ssize_t a4l_read_buffer(a4l_cxt_t * cxt, void *bufdata, size_t nbytes);
ssize_t a4l_write_buffer(a4l_cxt_t * cxt, const void *bufdata, size_t nbytes);
int a4l_select(a4l_cxt_t *cxt,
	       rtdm_selector_t *selector,
	       enum rtdm_selecttype type, unsigned fd_index);

#endif /* __KERNEL__ */

/* MMAP ioctl argument structure */
struct a4l_mmap_arg {
	unsigned int idx_subd;
	unsigned long size;
	void *ptr;
};
typedef struct a4l_mmap_arg a4l_mmap_t;

/* Constants related with buffer size
   (might be used with BUFCFG ioctl) */
#define A4L_BUF_MAXSIZE 0x1000000
#define A4L_BUF_DEFSIZE 0x10000
#define A4L_BUF_DEFMAGIC 0xffaaff55

/* BUFCFG ioctl argument structure */
struct a4l_buffer_config {
	/* NOTE: with the last buffer implementation, the field
	   idx_subd became useless; the buffer are now
	   per-context. So, the buffer size configuration is specific
	   to an opened device. There is a little exception: we can
	   define a default buffer size for a device.
	   So far, a hack is used to implement the configuration of
	   the default buffer size */
	unsigned int idx_subd;
	unsigned long buf_size;
};
typedef struct a4l_buffer_config a4l_bufcfg_t;

/* BUFINFO ioctl argument structure */
struct a4l_buffer_info {
	unsigned int idx_subd;
	unsigned long buf_size;
	unsigned long rw_count;
};
typedef struct a4l_buffer_info a4l_bufinfo_t;

/* BUFCFG2 / BUFINFO2 ioctl argument structure */
struct a4l_buffer_config2 {
	unsigned long wake_count;
	unsigned long reserved[3];
};
typedef struct a4l_buffer_config2 a4l_bufcfg2_t;

/* POLL ioctl argument structure */
struct a4l_poll {
	unsigned int idx_subd;
	unsigned long arg;
};
typedef struct a4l_poll a4l_poll_t;

#endif /* !DOXYGEN_CPP */

#endif /* __ANALOGY_BUFFER_H__ */