]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/arm/plat-omap/dsp/fifo.h
46fc33ccc80ae45a56170d64a07cf0abe4794e47
[linux-2.6-omap-h63xx.git] / arch / arm / plat-omap / dsp / fifo.h
1 /*
2  * linux/arch/arm/mach-omap/dsp/fifo.h
3  *
4  * FIFO buffer operators
5  *
6  * Copyright (C) 2002-2005 Nokia Corporation
7  *
8  * Written by Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23  *
24  * 2005/02/24:  DSP Gateway version 3.3
25  */
26
27 struct fifo_struct {
28         spinlock_t lock;
29         char *buf;
30         size_t sz;
31         size_t cnt;
32         unsigned int wp;
33 };
34
35 static inline int alloc_fifo(struct fifo_struct *fifo, size_t sz)
36 {
37         if ((fifo->buf = kmalloc(sz, GFP_KERNEL)) == NULL) {
38                 fifo->sz = 0;
39                 return -ENOMEM;
40         }
41         fifo->sz = sz;
42         fifo->cnt = 0;
43         fifo->wp = 0;
44         return 0;
45 }
46
47 static inline int init_fifo(struct fifo_struct *fifo, size_t sz)
48 {
49         spin_lock_init(&fifo->lock);
50         return alloc_fifo(fifo, sz);
51 }
52
53 static inline void free_fifo(struct fifo_struct *fifo)
54 {
55         spin_lock(&fifo->lock);
56         if (fifo->buf == NULL)
57                 return;
58
59         kfree(fifo->buf);
60         fifo->buf = NULL;
61         fifo->sz = 0;
62         spin_unlock(&fifo->lock);
63 }
64
65 static inline void flush_fifo(struct fifo_struct *fifo)
66 {
67         spin_lock(&fifo->lock);
68         fifo->cnt = 0;
69         fifo->wp = 0;
70         spin_unlock(&fifo->lock);
71 }
72
73 #define fifo_empty(fifo)        ((fifo)->cnt == 0)
74
75 static inline int realloc_fifo(struct fifo_struct *fifo, size_t sz)
76 {
77         int ret = sz;
78
79         spin_lock(&fifo->lock);
80         if (!fifo_empty(fifo)) {
81                 ret = -EBUSY;
82                 goto out;
83         }
84
85         /* free */
86         if (fifo->buf)
87                 kfree(fifo->buf);
88
89         /* alloc */
90         if ((fifo->buf = kmalloc(sz, GFP_KERNEL)) == NULL) {
91                 fifo->sz = 0;
92                 ret = -ENOMEM;
93                 goto out;
94         }
95         fifo->sz = sz;
96         fifo->cnt = 0;
97         fifo->wp = 0;
98
99 out:
100         spin_unlock(&fifo->lock);
101         return ret;
102 }
103
104 static inline void write_word_to_fifo(struct fifo_struct *fifo,
105                                       unsigned short word)
106 {
107         spin_lock(&fifo->lock);
108         *(unsigned short *)&fifo->buf[fifo->wp] = word;
109         if ((fifo->wp += 2) == fifo->sz)
110                 fifo->wp = 0;
111         if ((fifo->cnt += 2) > fifo->sz)
112                 fifo->cnt = fifo->sz;
113         spin_unlock(&fifo->lock);
114 }
115
116 /*
117  * (before)
118  *
119  * [*******----------*************]
120  *         ^wp
121  *  <---------------------------->  sz = 30
122  *  <----->          <----------->  cnt = 20
123  *
124  * (read: count=16)
125  *  <->              <----------->  count = 16
126  *                   <----------->  cnt1 = 13
127  *                   ^rp
128  *
129  * (after)
130  * [---****-----------------------]
131  *         ^wp
132  */
133 static inline ssize_t copy_to_user_fm_fifo(char *dst, struct fifo_struct *fifo,
134                                            size_t count)
135 {
136         int rp;
137         ssize_t ret;
138
139         /* fifo size can be zero */
140         if (fifo->sz == 0)
141                 return 0;
142
143         spin_lock(&fifo->lock);
144         if (count > fifo->cnt)
145                 count = fifo->cnt;
146
147         if ((rp = fifo->wp - fifo->cnt) >= 0) {
148                 /* valid area is straight */
149                 if (copy_to_user(dst, &fifo->buf[rp], count)) {
150                         ret = -EFAULT;
151                         goto out;
152                 }
153         } else {
154                 int cnt1 = -rp;
155                 rp += fifo->sz;
156                 if (cnt1 >= count) {
157                         /* requested area is straight */
158                         if (copy_to_user(dst, &fifo->buf[rp], count)) {
159                                 ret = -EFAULT;
160                                 goto out;
161                         }
162                 } else {
163                         if (copy_to_user(dst, &fifo->buf[rp], cnt1)) {
164                                 ret = -EFAULT;
165                                 goto out;
166                         }
167                         if (copy_to_user(dst+cnt1, fifo->buf, count-cnt1)) {
168                                 ret = -EFAULT;
169                                 goto out;
170                         }
171                 }
172         }
173         fifo->cnt -= count;
174         ret = count;
175
176 out:
177         spin_unlock(&fifo->lock);
178         return ret;
179 }