diff options
author | Wai Yew CHAY <wychay@ctl.creative.com> | 2009-05-14 02:05:58 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-05-14 02:24:10 -0400 |
commit | 8cc72361481f00253f1e468ade5795427386d593 (patch) | |
tree | ec6f3ea304f90fa9c99abb1bf2354fc5d357db27 /sound/pci/ctxfi/ctresource.c | |
parent | 091bf7624d1c90cec9e578a18529f615213ff847 (diff) |
ALSA: SB X-Fi driver merge
The Sound Blaster X-Fi driver supports Creative solutions based on
20K1 and 20K2 chipsets.
Supported hardware :
Creative Sound Blaster X-Fi Titanium Fatal1ty® Champion Series
Creative Sound Blaster X-Fi Titanium Fatal1ty Professional Series
Creative Sound Blaster X-Fi Titanium Professional Audio
Creative Sound Blaster X-Fi Titanium
Creative Sound Blaster X-Fi Elite Pro
Creative Sound Blaster X-Fi Platinum
Creative Sound Blaster X-Fi Fatal1ty
Creative Sound Blaster X-Fi XtremeGamer
Creative Sound Blaster X-Fi XtremeMusic
Current release features:
* ALSA PCM Playback
* ALSA Record
* ALSA Mixer
Note:
* External I/O modules detection not included.
Signed-off-by: Wai Yew CHAY <wychay@ctl.creative.com>
Singed-off-by: Ryan RICHARDS <ryan_richards@creativelabs.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/ctxfi/ctresource.c')
-rw-r--r-- | sound/pci/ctxfi/ctresource.c | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/sound/pci/ctxfi/ctresource.c b/sound/pci/ctxfi/ctresource.c new file mode 100644 index 000000000000..414fc23267cd --- /dev/null +++ b/sound/pci/ctxfi/ctresource.c | |||
@@ -0,0 +1,297 @@ | |||
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 = 0, j = 0, k = 0, n = 0; | ||
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 = 0, j = 0, k = 0, n = 0; | ||
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 = 0; | ||
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 "Invalid resource type value %d!\n", type); | ||
166 | return -EINVAL; | ||
167 | } | ||
168 | |||
169 | if (err) { | ||
170 | printk(KERN_ERR "Failed to get resource control block!\n"); | ||
171 | return err; | ||
172 | } | ||
173 | |||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | int rsc_uninit(struct rsc *rsc) | ||
178 | { | ||
179 | if ((NULL != rsc->hw) && (NULL != rsc->ctrl_blk)) { | ||
180 | switch (rsc->type) { | ||
181 | case SRC: | ||
182 | ((struct hw *)rsc->hw)-> | ||
183 | src_rsc_put_ctrl_blk(rsc->ctrl_blk); | ||
184 | break; | ||
185 | case AMIXER: | ||
186 | ((struct hw *)rsc->hw)-> | ||
187 | amixer_rsc_put_ctrl_blk(rsc->ctrl_blk); | ||
188 | break; | ||
189 | case SUM: | ||
190 | case DAIO: | ||
191 | break; | ||
192 | default: | ||
193 | printk(KERN_ERR "Invalid resource type value %d!\n", | ||
194 | rsc->type); | ||
195 | break; | ||
196 | } | ||
197 | |||
198 | rsc->hw = rsc->ctrl_blk = NULL; | ||
199 | } | ||
200 | |||
201 | rsc->idx = rsc->conj = 0; | ||
202 | rsc->type = NUM_RSCTYP; | ||
203 | rsc->msr = 0; | ||
204 | |||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | int rsc_mgr_init(struct rsc_mgr *mgr, enum RSCTYP type, | ||
209 | unsigned int amount, void *hw_obj) | ||
210 | { | ||
211 | int err = 0; | ||
212 | struct hw *hw = hw_obj; | ||
213 | |||
214 | mgr->type = NUM_RSCTYP; | ||
215 | |||
216 | mgr->rscs = kzalloc(((amount + 8 - 1) / 8), GFP_KERNEL); | ||
217 | if (NULL == mgr->rscs) | ||
218 | return -ENOMEM; | ||
219 | |||
220 | switch (type) { | ||
221 | case SRC: | ||
222 | err = hw->src_mgr_get_ctrl_blk(&mgr->ctrl_blk); | ||
223 | break; | ||
224 | case SRCIMP: | ||
225 | err = hw->srcimp_mgr_get_ctrl_blk(&mgr->ctrl_blk); | ||
226 | break; | ||
227 | case AMIXER: | ||
228 | err = hw->amixer_mgr_get_ctrl_blk(&mgr->ctrl_blk); | ||
229 | break; | ||
230 | case DAIO: | ||
231 | err = hw->daio_mgr_get_ctrl_blk(hw, &mgr->ctrl_blk); | ||
232 | break; | ||
233 | case SUM: | ||
234 | break; | ||
235 | default: | ||
236 | printk(KERN_ERR "Invalid resource type value %d!\n", type); | ||
237 | err = -EINVAL; | ||
238 | goto error; | ||
239 | } | ||
240 | |||
241 | if (err) { | ||
242 | printk(KERN_ERR "Failed to get manager control block!\n"); | ||
243 | goto error; | ||
244 | } | ||
245 | |||
246 | mgr->type = type; | ||
247 | mgr->avail = mgr->amount = amount; | ||
248 | mgr->hw = hw; | ||
249 | |||
250 | return 0; | ||
251 | |||
252 | error: | ||
253 | kfree(mgr->rscs); | ||
254 | return err; | ||
255 | } | ||
256 | |||
257 | int rsc_mgr_uninit(struct rsc_mgr *mgr) | ||
258 | { | ||
259 | if (NULL != mgr->rscs) { | ||
260 | kfree(mgr->rscs); | ||
261 | mgr->rscs = NULL; | ||
262 | } | ||
263 | |||
264 | if ((NULL != mgr->hw) && (NULL != mgr->ctrl_blk)) { | ||
265 | switch (mgr->type) { | ||
266 | case SRC: | ||
267 | ((struct hw *)mgr->hw)-> | ||
268 | src_mgr_put_ctrl_blk(mgr->ctrl_blk); | ||
269 | break; | ||
270 | case SRCIMP: | ||
271 | ((struct hw *)mgr->hw)-> | ||
272 | srcimp_mgr_put_ctrl_blk(mgr->ctrl_blk); | ||
273 | break; | ||
274 | case AMIXER: | ||
275 | ((struct hw *)mgr->hw)-> | ||
276 | amixer_mgr_put_ctrl_blk(mgr->ctrl_blk); | ||
277 | break; | ||
278 | case DAIO: | ||
279 | ((struct hw *)mgr->hw)-> | ||
280 | daio_mgr_put_ctrl_blk(mgr->ctrl_blk); | ||
281 | break; | ||
282 | case SUM: | ||
283 | break; | ||
284 | default: | ||
285 | printk(KERN_ERR "Invalid resource type value %d!\n", | ||
286 | mgr->type); | ||
287 | break; | ||
288 | } | ||
289 | |||
290 | mgr->hw = mgr->ctrl_blk = NULL; | ||
291 | } | ||
292 | |||
293 | mgr->type = NUM_RSCTYP; | ||
294 | mgr->avail = mgr->amount = 0; | ||
295 | |||
296 | return 0; | ||
297 | } | ||