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