]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/arm/plat-omap/dsp/fifo.h
OMAP: DSP: N800: remaining updates for dsp parts
[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 #ifndef __PLAT_OMAP_DSP_FIFO_H
25 #define __PLAT_OMAP_DSP_FIFO_H
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                 spin_unlock(&fifo->lock);
58                 return;
59         }
60
61         kfree(fifo->buf);
62         fifo->buf = NULL;
63         fifo->sz = 0;
64         spin_unlock(&fifo->lock);
65 }
66
67 static inline void flush_fifo(struct fifo_struct *fifo)
68 {
69         spin_lock(&fifo->lock);
70         fifo->cnt = 0;
71         fifo->wp = 0;
72         spin_unlock(&fifo->lock);
73 }
74
75 #define fifo_empty(fifo)        ((fifo)->cnt == 0)
76
77 static inline int realloc_fifo(struct fifo_struct *fifo, size_t sz)
78 {
79         int ret = sz;
80
81         spin_lock(&fifo->lock);
82         if (!fifo_empty(fifo)) {
83                 ret = -EBUSY;
84                 goto out;
85         }
86
87         /* free */
88         if (fifo->buf)
89                 kfree(fifo->buf);
90
91         /* alloc */
92         ret = alloc_fifo(fifo, sz);
93
94 out:
95         spin_unlock(&fifo->lock);
96         return ret;
97 }
98
99 static inline void write_word_to_fifo(struct fifo_struct *fifo, u16 word)
100 {
101         spin_lock(&fifo->lock);
102         *(u16 *)&fifo->buf[fifo->wp] = word;
103         if ((fifo->wp += 2) == fifo->sz)
104                 fifo->wp = 0;
105         if ((fifo->cnt += 2) > fifo->sz)
106                 fifo->cnt = fifo->sz;
107         spin_unlock(&fifo->lock);
108 }
109
110 /*
111  * (before)
112  *
113  * [*******----------*************]
114  *         ^wp
115  *  <---------------------------->  sz = 30
116  *  <----->          <----------->  cnt = 20
117  *
118  * (read: count=16)
119  *  <->              <----------->  count = 16
120  *                   <----------->  cnt1 = 13
121  *                   ^rp
122  *
123  * (after)
124  * [---****-----------------------]
125  *         ^wp
126  */
127 static inline ssize_t copy_to_user_fm_fifo(char *dst, struct fifo_struct *fifo,
128                                            size_t count)
129 {
130         int rp;
131         ssize_t ret;
132
133         /* fifo size can be zero */
134         if (fifo->sz == 0)
135                 return 0;
136
137         spin_lock(&fifo->lock);
138         if (count > fifo->cnt)
139                 count = fifo->cnt;
140
141         if ((rp = fifo->wp - fifo->cnt) >= 0) {
142                 /* valid area is straight */
143                 if (copy_to_user(dst, &fifo->buf[rp], count)) {
144                         ret = -EFAULT;
145                         goto out;
146                 }
147         } else {
148                 int cnt1 = -rp;
149                 rp += fifo->sz;
150                 if (cnt1 >= count) {
151                         /* requested area is straight */
152                         if (copy_to_user(dst, &fifo->buf[rp], count)) {
153                                 ret = -EFAULT;
154                                 goto out;
155                         }
156                 } else {
157                         if (copy_to_user(dst, &fifo->buf[rp], cnt1)) {
158                                 ret = -EFAULT;
159                                 goto out;
160                         }
161                         if (copy_to_user(dst+cnt1, fifo->buf, count-cnt1)) {
162                                 ret = -EFAULT;
163                                 goto out;
164                         }
165                 }
166         }
167         fifo->cnt -= count;
168         ret = count;
169
170 out:
171         spin_unlock(&fifo->lock);
172         return ret;
173 }
174
175 #endif /* __PLAT_OMAP_DSP_FIFO_H */