-
Notifications
You must be signed in to change notification settings - Fork 0
/
tdc_fifo.c
108 lines (93 loc) · 2.39 KB
/
tdc_fifo.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
#include "tdc_fifo.h"
struct tdc_fifo *tdc_fifo_new(unsigned int size)
{
struct tdc_fifo *fifo;
fifo = kzalloc(sizeof(*fifo), GFP_KERNEL);
if (!fifo)
return NULL;
fifo->buffer = kmalloc(size, GFP_KERNEL);
if (!fifo->buffer) {
kfree(fifo);
return NULL;
}
fifo->size = size;
fifo->lock = SPIN_LOCK_UNLOCKED;
return fifo;
}
void tdc_fifo_destroy(struct tdc_fifo *fifo)
{
kfree(fifo->buffer);
kfree(fifo);
}
void tdc_fifo_reset(struct tdc_fifo *fifo)
{
unsigned long flags;
spin_lock_irqsave(&fifo->lock, flags);
fifo->in = fifo->out = 0;
spin_unlock_irqrestore(&fifo->lock, flags);
}
/* Must be called with lock held: */
static inline unsigned int __tdc_fifo_len(struct tdc_fifo *fifo)
{
if (fifo->in == fifo->out)
return 0;
return (fifo->size - fifo->out + fifo->in) % fifo->size;
}
/* Must be called with lock held: */
static inline unsigned int __tdc_fifo_spacefree(struct tdc_fifo *fifo)
{
return fifo->size - 1 - __tdc_fifo_len(fifo);
}
inline unsigned int tdc_fifo_len(struct tdc_fifo *fifo)
{
unsigned long flags;
unsigned int result;
spin_lock_irqsave(&fifo->lock, flags);
result = __tdc_fifo_len(fifo);
spin_unlock_irqrestore(&fifo->lock, flags);
return result;
}
inline unsigned int tdc_fifo_spacefree(struct tdc_fifo *fifo)
{
unsigned long flags;
unsigned int result;
spin_lock_irqsave(&fifo->lock, flags);
result = __tdc_fifo_spacefree(fifo);
spin_unlock_irqrestore(&fifo->lock, flags);
return result;
}
/*
* Returns 0 on success, -1 on error (FIFO full)
*/
int tdc_fifo_putbyte(struct tdc_fifo *fifo,
unsigned char byte)
{
unsigned long flags;
int retval = -1;
spin_lock_irqsave(&fifo->lock, flags);
if (__tdc_fifo_spacefree(fifo) == 0)
goto out;
fifo->buffer[fifo->in] = byte;
fifo->in = (fifo->in + 1) % fifo->size;
retval = 0;
out:
spin_unlock_irqrestore(&fifo->lock, flags);
return retval;
}
/*
* Returns 0 on success, -1 on error.
*/
int tdc_fifo_getbyte(struct tdc_fifo *fifo, unsigned char *byte)
{
unsigned long flags;
int retval = -1;
spin_lock_irqsave(&fifo->lock, flags);
if (fifo->out == fifo->in)
goto out;
*byte = fifo->buffer[fifo->out];
fifo->out = (fifo->out + 1) % fifo->size;
retval = 0;
out:
spin_unlock_irqrestore(&fifo->lock, flags);
return retval;
}