-
Notifications
You must be signed in to change notification settings - Fork 0
/
testD_ringbuffer.c
118 lines (107 loc) · 2.98 KB
/
testD_ringbuffer.c
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
#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/pci.h>
#include "tD_ringbuffer.h"
//
// This is an attempt at a doofy DMA ring buffer.
// Since interrupts can't vmalloc/vfree, the ring buffer
// is primed when it's initialized - that is, it
// No one else needs to have this macro.
#define TD_RING_NEXT(x,i) (((i)<((x)->depth - 1)) ? (i)+1 : 0)
int mcpPciDriver_initRing(struct tD_ring *rp,
unsigned int depth) {
unsigned int i;
rp->ring = kmalloc(sizeof(struct tD_ringbuf)*depth, GFP_KERNEL);
if (!rp->ring)
return -ENOMEM;
for (i=0;i<depth;i++) {
rp->ring[i].active = 0;
rp->ring[i].buffer = NULL;
rp->ring[i].size = 0;
}
rp->depth = depth;
rp->first = 0;
spin_lock_init(&rp->lock);
return 0;
}
void mcpPciDriver_deleteRing(struct tD_ring *rp) {
unsigned long flags;
int i;
if (unlikely(rp->ring == NULL)) {
printk(KERN_ERR "mcpPciDriver: ring buffer uninitialized!\n");
return;
}
spin_lock_irqsave(&rp->lock, flags);
for (i=0;i<rp->depth;i++) {
if (rp->ring[i].active) {
if (rp->ring[i].buffer) {
vfree(rp->ring[i].buffer);
rp->ring[i].buffer = NULL;
}
}
}
kfree(rp->ring);
rp->ring = NULL;
spin_unlock_irqrestore(&rp->lock, flags);
}
//
// if (!buf->active), then there was no data to get.
//
// The ring should be locked when this function is called.
//
void mcpPciDriver_takeFromRing(struct tD_ring *rp,
struct tD_ringbuf *buf) {
if (unlikely(rp->ring == NULL)) {
printk(KERN_ERR "mcpPciDriver: ring buffer uninitialized!\n");
buf->active = 0;
return;
}
buf->active = rp->ring[rp->first].active;
buf->buffer = rp->ring[rp->first].buffer;
buf->size = rp->ring[rp->first].size;
if (rp->ring[rp->first].active) {
rp->ring[rp->first].active = 0;
rp->ring[rp->first].buffer = NULL;
rp->first = TD_RING_NEXT(rp,rp->first);
}
}
int mcpPciDriver_fastRingEmpty(struct tD_ring *rp) {
return (rp->ring[rp->first].active == 0);
}
// This will only fail if the ring buffer isn't initialized.
// In that case we promptly trash the buffer. We don't return
// an error code, as this can only happen via stupid coding, but
// it'd be nice to see it happen.
//
// The ring should be locked when this function is called.
//
void mcpPciDriver_addToRing(struct tD_ring *rp,
unsigned int *buffer,
unsigned int size) {
int i;
if (unlikely(rp->ring == NULL)) {
printk(KERN_ERR "mcpPciDriver: ring buffer uninitialized!\n");
if (buffer) vfree(buffer);
return;
}
i = rp->first;
do {
if (!rp->ring[i].active)
break;
i = TD_RING_NEXT(rp,i);
} while (i != rp->first);
if (i == rp->first) {
if (rp->ring[rp->first].active) {
// ring buffer is full.
if (rp->ring[rp->first].buffer) {
vfree(rp->ring[rp->first].buffer);
rp->ring[rp->first].buffer = NULL;
}
rp->first = TD_RING_NEXT(rp,rp->first);
}
}
rp->ring[i].buffer = buffer;
rp->ring[i].size = size;
rp->ring[i].active = 1;
}