File: /usr/src/linux/drivers/sound/emu10k1/cardwi.c
1 /*
2 **********************************************************************
3 * cardwi.c - PCM input HAL for emu10k1 driver
4 * Copyright 1999, 2000 Creative Labs, Inc.
5 *
6 **********************************************************************
7 *
8 * Date Author Summary of changes
9 * ---- ------ ------------------
10 * October 20, 1999 Bertrand Lee base code release
11 *
12 **********************************************************************
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License as
16 * published by the Free Software Foundation; either version 2 of
17 * the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public
25 * License along with this program; if not, write to the Free
26 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
27 * USA.
28 *
29 **********************************************************************
30 */
31
32 #include <linux/poll.h>
33 #include "hwaccess.h"
34 #include "timer.h"
35 #include "recmgr.h"
36 #include "audio.h"
37 #include "cardwi.h"
38
39 /**
40 * query_format - returns a valid sound format
41 *
42 * This function will return a valid sound format as close
43 * to the requested one as possible.
44 */
45 void query_format(int recsrc, struct wave_format *wave_fmt)
46 {
47
48 switch (recsrc) {
49 case WAVERECORD_AC97:
50
51 if ((wave_fmt->channels != 1) && (wave_fmt->channels != 2))
52 wave_fmt->channels = 2;
53
54 if (wave_fmt->samplingrate >= (0xBB80 + 0xAC44) / 2)
55 wave_fmt->samplingrate = 0xBB80;
56 else if (wave_fmt->samplingrate >= (0xAC44 + 0x7D00) / 2)
57 wave_fmt->samplingrate = 0xAC44;
58 else if (wave_fmt->samplingrate >= (0x7D00 + 0x5DC0) / 2)
59 wave_fmt->samplingrate = 0x7D00;
60 else if (wave_fmt->samplingrate >= (0x5DC0 + 0x5622) / 2)
61 wave_fmt->samplingrate = 0x5DC0;
62 else if (wave_fmt->samplingrate >= (0x5622 + 0x3E80) / 2)
63 wave_fmt->samplingrate = 0x5622;
64 else if (wave_fmt->samplingrate >= (0x3E80 + 0x2B11) / 2)
65 wave_fmt->samplingrate = 0x3E80;
66 else if (wave_fmt->samplingrate >= (0x2B11 + 0x1F40) / 2)
67 wave_fmt->samplingrate = 0x2B11;
68 else
69 wave_fmt->samplingrate = 0x1F40;
70
71 switch (wave_fmt->id) {
72 case AFMT_S16_LE:
73 wave_fmt->bitsperchannel = 16;
74 break;
75 case AFMT_U8:
76 wave_fmt->bitsperchannel = 8;
77 break;
78 default:
79 wave_fmt->id = AFMT_S16_LE;
80 wave_fmt->bitsperchannel = 16;
81 break;
82 }
83
84 break;
85
86 /* these can't be changed from the original values */
87 case WAVERECORD_MIC:
88 case WAVERECORD_FX:
89 break;
90
91 default:
92 BUG();
93 break;
94 }
95
96 wave_fmt->bytesperchannel = wave_fmt->bitsperchannel >> 3;
97 wave_fmt->bytespersample = wave_fmt->channels * wave_fmt->bytesperchannel;
98 wave_fmt->bytespersec = wave_fmt->bytespersample * wave_fmt->samplingrate;
99 }
100
101 static int alloc_buffer(struct emu10k1_card *card, struct wavein_buffer *buffer)
102 {
103 buffer->addr = pci_alloc_consistent(card->pci_dev, buffer->size * buffer->cov,
104 &buffer->dma_handle);
105 if (buffer->addr == NULL)
106 return -1;
107
108 return 0;
109 }
110
111 static void free_buffer(struct emu10k1_card *card, struct wavein_buffer *buffer)
112 {
113 if (buffer->addr != NULL)
114 pci_free_consistent(card->pci_dev, buffer->size * buffer->cov,
115 buffer->addr, buffer->dma_handle);
116 }
117
118 int emu10k1_wavein_open(struct emu10k1_wavedevice *wave_dev)
119 {
120 struct emu10k1_card *card = wave_dev->card;
121 struct wiinst *wiinst = wave_dev->wiinst;
122 struct wiinst **wiinst_tmp = NULL;
123 u32 delay;
124 unsigned long flags;
125
126 DPF(2, "emu10k1_wavein_open()\n");
127
128 switch (wiinst->recsrc) {
129 case WAVERECORD_AC97:
130 wiinst_tmp = &card->wavein.ac97;
131 break;
132 case WAVERECORD_MIC:
133 wiinst_tmp = &card->wavein.mic;
134 break;
135 case WAVERECORD_FX:
136 wiinst_tmp = &card->wavein.fx;
137 break;
138 default:
139 BUG();
140 break;
141 }
142
143 spin_lock_irqsave(&card->lock, flags);
144 if (*wiinst_tmp != NULL) {
145 spin_unlock_irqrestore(&card->lock, flags);
146 return -1;
147 }
148
149 *wiinst_tmp = wiinst;
150 spin_unlock_irqrestore(&card->lock, flags);
151
152 /* handle 8 bit recording */
153 if (wiinst->format.bytesperchannel == 1) {
154 if (wiinst->buffer.size > 0x8000) {
155 wiinst->buffer.size = 0x8000;
156 wiinst->buffer.sizeregval = 0x1f;
157 } else
158 wiinst->buffer.sizeregval += 4;
159
160 wiinst->buffer.cov = 2;
161 } else
162 wiinst->buffer.cov = 1;
163
164 if (alloc_buffer(card, &wiinst->buffer) < 0) {
165 ERROR();
166 emu10k1_wavein_close(wave_dev);
167 return -1;
168 }
169
170 emu10k1_set_record_src(card, wiinst);
171
172 delay = (48000 * wiinst->buffer.fragment_size) / wiinst->format.bytespersec;
173
174 emu10k1_timer_install(card, &wiinst->timer, delay / 2);
175
176 wiinst->state = WAVE_STATE_OPEN;
177
178 return 0;
179 }
180
181 void emu10k1_wavein_close(struct emu10k1_wavedevice *wave_dev)
182 {
183 struct emu10k1_card *card = wave_dev->card;
184 struct wiinst *wiinst = wave_dev->wiinst;
185 unsigned long flags;
186
187 DPF(2, "emu10k1_wavein_close()\n");
188
189 emu10k1_wavein_stop(wave_dev);
190
191 emu10k1_timer_uninstall(card, &wiinst->timer);
192
193 free_buffer(card, &wiinst->buffer);
194
195 spin_lock_irqsave(&card->lock, flags);
196 switch (wave_dev->wiinst->recsrc) {
197 case WAVERECORD_AC97:
198 card->wavein.ac97 = NULL;
199 break;
200 case WAVERECORD_MIC:
201 card->wavein.mic = NULL;
202 break;
203 case WAVERECORD_FX:
204 card->wavein.fx = NULL;
205 break;
206 default:
207 BUG();
208 break;
209 }
210 spin_unlock_irqrestore(&card->lock, flags);
211
212 wiinst->state = WAVE_STATE_CLOSED;
213 }
214
215 void emu10k1_wavein_start(struct emu10k1_wavedevice *wave_dev)
216 {
217 struct emu10k1_card *card = wave_dev->card;
218 struct wiinst *wiinst = wave_dev->wiinst;
219
220 DPF(2, "emu10k1_wavein_start()\n");
221
222 emu10k1_start_record(card, &wiinst->buffer);
223 emu10k1_timer_enable(wave_dev->card, &wiinst->timer);
224
225 wiinst->buffer.hw_pos = 0;
226 wiinst->buffer.pos = 0;
227 wiinst->buffer.bytestocopy = 0;
228
229 wiinst->state |= WAVE_STATE_STARTED;
230 }
231
232 void emu10k1_wavein_stop(struct emu10k1_wavedevice *wave_dev)
233 {
234 struct emu10k1_card *card = wave_dev->card;
235 struct wiinst *wiinst = wave_dev->wiinst;
236
237 DPF(2, "emu10k1_wavein_stop()\n");
238
239 if (!(wiinst->state & WAVE_STATE_STARTED))
240 return;
241
242 emu10k1_timer_disable(card, &wiinst->timer);
243 emu10k1_stop_record(card, &wiinst->buffer);
244
245 wiinst->state &= ~WAVE_STATE_STARTED;
246 }
247
248 int emu10k1_wavein_setformat(struct emu10k1_wavedevice *wave_dev, struct wave_format *format)
249 {
250 struct emu10k1_card *card = wave_dev->card;
251 struct wiinst *wiinst = wave_dev->wiinst;
252 u32 delay;
253
254 DPF(2, "emu10k1_wavein_setformat()\n");
255
256 if (wiinst->state & WAVE_STATE_STARTED)
257 return -1;
258
259 query_format(wiinst->recsrc, format);
260
261 if ((wiinst->format.samplingrate != format->samplingrate)
262 || (wiinst->format.bitsperchannel != format->bitsperchannel)
263 || (wiinst->format.channels != format->channels)) {
264
265 wiinst->format = *format;
266
267 if (wiinst->state == WAVE_STATE_CLOSED)
268 return 0;
269
270 wiinst->buffer.size *= wiinst->buffer.cov;
271
272 if (wiinst->format.bytesperchannel == 1) {
273 wiinst->buffer.cov = 2;
274 wiinst->buffer.size /= wiinst->buffer.cov;
275 } else
276 wiinst->buffer.cov = 1;
277
278 emu10k1_timer_uninstall(card, &wiinst->timer);
279
280 delay = (48000 * wiinst->buffer.fragment_size) / wiinst->format.bytespersec;
281
282 emu10k1_timer_install(card, &wiinst->timer, delay / 2);
283 }
284
285 return 0;
286 }
287
288 void emu10k1_wavein_getxfersize(struct wiinst *wiinst, u32 * size)
289 {
290 struct wavein_buffer *buffer = &wiinst->buffer;
291
292 *size = buffer->bytestocopy;
293
294 if (wiinst->mmapped)
295 return;
296
297 if (*size > buffer->size) {
298 *size = buffer->size;
299 buffer->pos = buffer->hw_pos;
300 buffer->bytestocopy = buffer->size;
301 DPF(1, "buffer overrun\n");
302 }
303 }
304
305 static void copy_block(u8 *dst, u8 * src, u32 str, u32 len, u8 cov)
306 {
307 if (cov == 1)
308 __copy_to_user(dst, src + str, len);
309 else {
310 u8 byte;
311 u32 i;
312
313 src += 1 + 2 * str;
314
315 for (i = 0; i < len; i++) {
316 byte = src[2 * i] ^ 0x80;
317 __copy_to_user(dst + i, &byte, 1);
318 }
319 }
320 }
321
322 void emu10k1_wavein_xferdata(struct wiinst *wiinst, u8 * data, u32 * size)
323 {
324 struct wavein_buffer *buffer = &wiinst->buffer;
325 u32 sizetocopy, sizetocopy_now, start;
326 unsigned long flags;
327
328 sizetocopy = min_t(u32, buffer->size, *size);
329 *size = sizetocopy;
330
331 if (!sizetocopy)
332 return;
333
334 spin_lock_irqsave(&wiinst->lock, flags);
335 start = buffer->pos;
336 buffer->pos += sizetocopy;
337 buffer->pos %= buffer->size;
338 buffer->bytestocopy -= sizetocopy;
339 sizetocopy_now = buffer->size - start;
340
341 spin_unlock_irqrestore(&wiinst->lock, flags);
342
343 if (sizetocopy > sizetocopy_now) {
344 sizetocopy -= sizetocopy_now;
345
346 copy_block(data, buffer->addr, start, sizetocopy_now, buffer->cov);
347 copy_block(data + sizetocopy_now, buffer->addr, 0, sizetocopy, buffer->cov);
348 } else {
349 copy_block(data, buffer->addr, start, sizetocopy, buffer->cov);
350 }
351 }
352
353 void emu10k1_wavein_update(struct emu10k1_card *card, struct wiinst *wiinst)
354 {
355 u32 hw_pos;
356 u32 diff;
357
358 /* There is no actual start yet */
359 if (!(wiinst->state & WAVE_STATE_STARTED)) {
360 hw_pos = wiinst->buffer.hw_pos;
361 } else {
362 /* hw_pos in byte units */
363 hw_pos = sblive_readptr(card, wiinst->buffer.idxreg, 0) / wiinst->buffer.cov;
364 }
365
366 diff = (wiinst->buffer.size + hw_pos - wiinst->buffer.hw_pos) % wiinst->buffer.size;
367 wiinst->total_recorded += diff;
368 wiinst->buffer.bytestocopy += diff;
369
370 wiinst->buffer.hw_pos = hw_pos;
371 }
372