diff options
Diffstat (limited to 'sound/pci/ctxfi/ctresource.c')
-rw-r--r-- | sound/pci/ctxfi/ctresource.c | 301 |
1 files changed, 301 insertions, 0 deletions
diff --git a/sound/pci/ctxfi/ctresource.c b/sound/pci/ctxfi/ctresource.c new file mode 100644 index 000000000000..889c495bb7d1 --- /dev/null +++ b/sound/pci/ctxfi/ctresource.c | |||
@@ -0,0 +1,301 @@ | |||
1 | /** | ||
2 | * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. | ||
3 | * | ||
4 | * This source file is released under GPL v2 license (no other versions). | ||
5 | * See the COPYING file included in the main directory of this source | ||
6 | * distribution for the license terms and conditions. | ||
7 | * | ||
8 | * @File ctresource.c | ||
9 | * | ||
10 | * @Brief | ||
11 | * This file contains the implementation of some generic helper functions. | ||
12 | * | ||
13 | * @Author Liu Chun | ||
14 | * @Date May 15 2008 | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include "ctresource.h" | ||
19 | #include "cthardware.h" | ||
20 | #include <linux/err.h> | ||
21 | #include <linux/slab.h> | ||
22 | |||
23 | #define AUDIO_SLOT_BLOCK_NUM 256 | ||
24 | |||
25 | /* Resource allocation based on bit-map management mechanism */ | ||
26 | static int | ||
27 | get_resource(u8 *rscs, unsigned int amount, | ||
28 | unsigned int multi, unsigned int *ridx) | ||
29 | { | ||
30 | int i, j, k, n; | ||
31 | |||
32 | /* Check whether there are sufficient resources to meet request. */ | ||
33 | for (i = 0, n = multi; i < amount; i++) { | ||
34 | j = i / 8; | ||
35 | k = i % 8; | ||
36 | if (rscs[j] & ((u8)1 << k)) { | ||
37 | n = multi; | ||
38 | continue; | ||
39 | } | ||
40 | if (!(--n)) | ||
41 | break; /* found sufficient contiguous resources */ | ||
42 | } | ||
43 | |||
44 | if (i >= amount) { | ||
45 | /* Can not find sufficient contiguous resources */ | ||
46 | return -ENOENT; | ||
47 | } | ||
48 | |||
49 | /* Mark the contiguous bits in resource bit-map as used */ | ||
50 | for (n = multi; n > 0; n--) { | ||
51 | j = i / 8; | ||
52 | k = i % 8; | ||
53 | rscs[j] |= ((u8)1 << k); | ||
54 | i--; | ||
55 | } | ||
56 | |||
57 | *ridx = i + 1; | ||
58 | |||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | static int put_resource(u8 *rscs, unsigned int multi, unsigned int idx) | ||
63 | { | ||
64 | unsigned int i, j, k, n; | ||
65 | |||
66 | /* Mark the contiguous bits in resource bit-map as used */ | ||
67 | for (n = multi, i = idx; n > 0; n--) { | ||
68 | j = i / 8; | ||
69 | k = i % 8; | ||
70 | rscs[j] &= ~((u8)1 << k); | ||
71 | i++; | ||
72 | } | ||
73 | |||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | int mgr_get_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int *ridx) | ||
78 | { | ||
79 | int err; | ||
80 | |||
81 | if (n > mgr->avail) | ||
82 | return -ENOENT; | ||
83 | |||
84 | err = get_resource(mgr->rscs, mgr->amount, n, ridx); | ||
85 | if (!err) | ||
86 | mgr->avail -= n; | ||
87 | |||
88 | return err; | ||
89 | } | ||
90 | |||
91 | int mgr_put_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int idx) | ||
92 | { | ||
93 | put_resource(mgr->rscs, n, idx); | ||
94 | mgr->avail += n; | ||
95 | |||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | static unsigned char offset_in_audio_slot_block[NUM_RSCTYP] = { | ||
100 | /* SRC channel is at Audio Ring slot 1 every 16 slots. */ | ||
101 | [SRC] = 0x1, | ||
102 | [AMIXER] = 0x4, | ||
103 | [SUM] = 0xc, | ||
104 | }; | ||
105 | |||
106 | static int rsc_index(const struct rsc *rsc) | ||
107 | { | ||
108 | return rsc->conj; | ||
109 | } | ||
110 | |||
111 | static int audio_ring_slot(const struct rsc *rsc) | ||
112 | { | ||
113 | return (rsc->conj << 4) + offset_in_audio_slot_block[rsc->type]; | ||
114 | } | ||
115 | |||
116 | static int rsc_next_conj(struct rsc *rsc) | ||
117 | { | ||
118 | unsigned int i; | ||
119 | for (i = 0; (i < 8) && (!(rsc->msr & (0x1 << i))); ) | ||
120 | i++; | ||
121 | rsc->conj += (AUDIO_SLOT_BLOCK_NUM >> i); | ||
122 | return rsc->conj; | ||
123 | } | ||
124 | |||
125 | static int rsc_master(struct rsc *rsc) | ||
126 | { | ||
127 | return rsc->conj = rsc->idx; | ||
128 | } | ||
129 | |||
130 | static struct rsc_ops rsc_generic_ops = { | ||
131 | .index = rsc_index, | ||
132 | .output_slot = audio_ring_slot, | ||
133 | .master = rsc_master, | ||
134 | .next_conj = rsc_next_conj, | ||
135 | }; | ||
136 | |||
137 | int rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, void *hw) | ||
138 | { | ||
139 | int err = 0; | ||
140 | |||
141 | rsc->idx = idx; | ||
142 | rsc->conj = idx; | ||
143 | rsc->type = type; | ||
144 | rsc->msr = msr; | ||
145 | rsc->hw = hw; | ||
146 | rsc->ops = &rsc_generic_ops; | ||
147 | if (NULL == hw) { | ||
148 | rsc->ctrl_blk = NULL; | ||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | switch (type) { | ||
153 | case SRC: | ||
154 | err = ((struct hw *)hw)->src_rsc_get_ctrl_blk(&rsc->ctrl_blk); | ||
155 | break; | ||
156 | case AMIXER: | ||
157 | err = ((struct hw *)hw)-> | ||
158 | amixer_rsc_get_ctrl_blk(&rsc->ctrl_blk); | ||
159 | break; | ||
160 | case SRCIMP: | ||
161 | case SUM: | ||
162 | case DAIO: | ||
163 | break; | ||
164 | default: | ||
165 | printk(KERN_ERR | ||
166 | "ctxfi: Invalid resource type value %d!\n", type); | ||
167 | return -EINVAL; | ||
168 | } | ||
169 | |||
170 | if (err) { | ||
171 | printk(KERN_ERR | ||
172 | "ctxfi: Failed to get resource control block!\n"); | ||
173 | return err; | ||
174 | } | ||
175 | |||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | int rsc_uninit(struct rsc *rsc) | ||
180 | { | ||
181 | if ((NULL != rsc->hw) && (NULL != rsc->ctrl_blk)) { | ||
182 | switch (rsc->type) { | ||
183 | case SRC: | ||
184 | ((struct hw *)rsc->hw)-> | ||
185 | src_rsc_put_ctrl_blk(rsc->ctrl_blk); | ||
186 | break; | ||
187 | case AMIXER: | ||
188 | ((struct hw *)rsc->hw)-> | ||
189 | amixer_rsc_put_ctrl_blk(rsc->ctrl_blk); | ||
190 | break; | ||
191 | case SUM: | ||
192 | case DAIO: | ||
193 | break; | ||
194 | default: | ||
195 | printk(KERN_ERR "ctxfi: " | ||
196 | "Invalid resource type value %d!\n", rsc->type); | ||
197 | break; | ||
198 | } | ||
199 | |||
200 | rsc->hw = rsc->ctrl_blk = NULL; | ||
201 | } | ||
202 | |||
203 | rsc->idx = rsc->conj = 0; | ||
204 | rsc->type = NUM_RSCTYP; | ||
205 | rsc->msr = 0; | ||
206 | |||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | int rsc_mgr_init(struct rsc_mgr *mgr, enum RSCTYP type, | ||
211 | unsigned int amount, void *hw_obj) | ||
212 | { | ||
213 | int err = 0; | ||
214 | struct hw *hw = hw_obj; | ||
215 | |||
216 | mgr->type = NUM_RSCTYP; | ||
217 | |||
218 | mgr->rscs = kzalloc(((amount + 8 - 1) / 8), GFP_KERNEL); | ||
219 | if (NULL == mgr->rscs) | ||
220 | return -ENOMEM; | ||
221 | |||
222 | switch (type) { | ||
223 | case SRC: | ||
224 | err = hw->src_mgr_get_ctrl_blk(&mgr->ctrl_blk); | ||
225 | break; | ||
226 | case SRCIMP: | ||
227 | err = hw->srcimp_mgr_get_ctrl_blk(&mgr->ctrl_blk); | ||
228 | break; | ||
229 | case AMIXER: | ||
230 | err = hw->amixer_mgr_get_ctrl_blk(&mgr->ctrl_blk); | ||
231 | break; | ||
232 | case DAIO: | ||
233 | err = hw->daio_mgr_get_ctrl_blk(hw, &mgr->ctrl_blk); | ||
234 | break; | ||
235 | case SUM: | ||
236 | break; | ||
237 | default: | ||
238 | printk(KERN_ERR | ||
239 | "ctxfi: Invalid resource type value %d!\n", type); | ||
240 | err = -EINVAL; | ||
241 | goto error; | ||
242 | } | ||
243 | |||
244 | if (err) { | ||
245 | printk(KERN_ERR | ||
246 | "ctxfi: Failed to get manager control block!\n"); | ||
247 | goto error; | ||
248 | } | ||
249 | |||
250 | mgr->type = type; | ||
251 | mgr->avail = mgr->amount = amount; | ||
252 | mgr->hw = hw; | ||
253 | |||
254 | return 0; | ||
255 | |||
256 | error: | ||
257 | kfree(mgr->rscs); | ||
258 | return err; | ||
259 | } | ||
260 | |||
261 | int rsc_mgr_uninit(struct rsc_mgr *mgr) | ||
262 | { | ||
263 | if (NULL != mgr->rscs) { | ||
264 | kfree(mgr->rscs); | ||
265 | mgr->rscs = NULL; | ||
266 | } | ||
267 | |||
268 | if ((NULL != mgr->hw) && (NULL != mgr->ctrl_blk)) { | ||
269 | switch (mgr->type) { | ||
270 | case SRC: | ||
271 | ((struct hw *)mgr->hw)-> | ||
272 | src_mgr_put_ctrl_blk(mgr->ctrl_blk); | ||
273 | break; | ||
274 | case SRCIMP: | ||
275 | ((struct hw *)mgr->hw)-> | ||
276 | srcimp_mgr_put_ctrl_blk(mgr->ctrl_blk); | ||
277 | break; | ||
278 | case AMIXER: | ||
279 | ((struct hw *)mgr->hw)-> | ||
280 | amixer_mgr_put_ctrl_blk(mgr->ctrl_blk); | ||
281 | break; | ||
282 | case DAIO: | ||
283 | ((struct hw *)mgr->hw)-> | ||
284 | daio_mgr_put_ctrl_blk(mgr->ctrl_blk); | ||
285 | break; | ||
286 | case SUM: | ||
287 | break; | ||
288 | default: | ||
289 | printk(KERN_ERR "ctxfi: " | ||
290 | "Invalid resource type value %d!\n", mgr->type); | ||
291 | break; | ||
292 | } | ||
293 | |||
294 | mgr->hw = mgr->ctrl_blk = NULL; | ||
295 | } | ||
296 | |||
297 | mgr->type = NUM_RSCTYP; | ||
298 | mgr->avail = mgr->amount = 0; | ||
299 | |||
300 | return 0; | ||
301 | } | ||