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