OpenCores
URL https://opencores.org/ocsvn/or1k_soc_on_altera_embedded_dev_kit/or1k_soc_on_altera_embedded_dev_kit/trunk

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [sound/] [pcmcia/] [pdaudiocf/] [pdaudiocf_pcm.c] - Blame information for rev 3

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 xianfeng
/*
2
 * Driver for Sound Core PDAudioCF soundcards
3
 *
4
 * PCM part
5
 *
6
 * Copyright (c) 2003 by Jaroslav Kysela <perex@perex.cz>
7
 *
8
 *   This program is free software; you can redistribute it and/or modify
9
 *   it under the terms of the GNU General Public License as published by
10
 *   the Free Software Foundation; either version 2 of the License, or
11
 *   (at your option) any later version.
12
 *
13
 *   This program is distributed in the hope that it will be useful,
14
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 *   GNU General Public License for more details.
17
 *
18
 *   You should have received a copy of the GNU General Public License
19
 *   along with this program; if not, write to the Free Software
20
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
21
 */
22
 
23
#include <sound/driver.h>
24
#include <linux/slab.h>
25
#include <linux/vmalloc.h>
26
#include <linux/delay.h>
27
#include <sound/core.h>
28
#include <sound/asoundef.h>
29
#include "pdaudiocf.h"
30
 
31
 
32
/*
33
 * we use a vmalloc'ed (sg-)buffer
34
 */
35
 
36
/* get the physical page pointer on the given offset */
37
static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, unsigned long offset)
38
{
39
        void *pageptr = subs->runtime->dma_area + offset;
40
        return vmalloc_to_page(pageptr);
41
}
42
 
43
/*
44
 * hw_params callback
45
 * NOTE: this may be called not only once per pcm open!
46
 */
47
static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, size_t size)
48
{
49
        struct snd_pcm_runtime *runtime = subs->runtime;
50
        if (runtime->dma_area) {
51
                if (runtime->dma_bytes >= size)
52
                        return 0; /* already enough large */
53
                vfree(runtime->dma_area);
54
        }
55
        runtime->dma_area = vmalloc_32(size);
56
        if (! runtime->dma_area)
57
                return -ENOMEM;
58
        runtime->dma_bytes = size;
59
        return 0;
60
}
61
 
62
/*
63
 * hw_free callback
64
 * NOTE: this may be called not only once per pcm open!
65
 */
66
static int snd_pcm_free_vmalloc_buffer(struct snd_pcm_substream *subs)
67
{
68
        struct snd_pcm_runtime *runtime = subs->runtime;
69
 
70
        vfree(runtime->dma_area);
71
        runtime->dma_area = NULL;
72
        return 0;
73
}
74
 
75
/*
76
 * clear the SRAM contents
77
 */
78
static int pdacf_pcm_clear_sram(struct snd_pdacf *chip)
79
{
80
        int max_loop = 64 * 1024;
81
 
82
        while (inw(chip->port + PDAUDIOCF_REG_RDP) != inw(chip->port + PDAUDIOCF_REG_WDP)) {
83
                if (max_loop-- < 0)
84
                        return -EIO;
85
                inw(chip->port + PDAUDIOCF_REG_MD);
86
        }
87
        return 0;
88
}
89
 
90
/*
91
 * pdacf_pcm_trigger - trigger callback for capture
92
 */
93
static int pdacf_pcm_trigger(struct snd_pcm_substream *subs, int cmd)
94
{
95
        struct snd_pdacf *chip = snd_pcm_substream_chip(subs);
96
        struct snd_pcm_runtime *runtime = subs->runtime;
97
        int inc, ret = 0, rate;
98
        unsigned short mask, val, tmp;
99
 
100
        if (chip->chip_status & PDAUDIOCF_STAT_IS_STALE)
101
                return -EBUSY;
102
 
103
        switch (cmd) {
104
        case SNDRV_PCM_TRIGGER_START:
105
                chip->pcm_hwptr = 0;
106
                chip->pcm_tdone = 0;
107
                /* fall thru */
108
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
109
        case SNDRV_PCM_TRIGGER_RESUME:
110
                mask = 0;
111
                val = PDAUDIOCF_RECORD;
112
                inc = 1;
113
                rate = snd_ak4117_check_rate_and_errors(chip->ak4117, AK4117_CHECK_NO_STAT|AK4117_CHECK_NO_RATE);
114
                break;
115
        case SNDRV_PCM_TRIGGER_STOP:
116
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
117
        case SNDRV_PCM_TRIGGER_SUSPEND:
118
                mask = PDAUDIOCF_RECORD;
119
                val = 0;
120
                inc = -1;
121
                rate = 0;
122
                break;
123
        default:
124
                return -EINVAL;
125
        }
126
        spin_lock(&chip->reg_lock);
127
        chip->pcm_running += inc;
128
        tmp = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR);
129
        if (chip->pcm_running) {
130
                if ((chip->ak4117->rcs0 & AK4117_UNLCK) || runtime->rate != rate) {
131
                        chip->pcm_running -= inc;
132
                        ret = -EIO;
133
                        goto __end;
134
                }
135
        }
136
        tmp &= ~mask;
137
        tmp |= val;
138
        pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, tmp);
139
      __end:
140
        spin_unlock(&chip->reg_lock);
141
        snd_ak4117_check_rate_and_errors(chip->ak4117, AK4117_CHECK_NO_RATE);
142
        return ret;
143
}
144
 
145
/*
146
 * pdacf_pcm_hw_params - hw_params callback for playback and capture
147
 */
148
static int pdacf_pcm_hw_params(struct snd_pcm_substream *subs,
149
                                     struct snd_pcm_hw_params *hw_params)
150
{
151
        return snd_pcm_alloc_vmalloc_buffer(subs, params_buffer_bytes(hw_params));
152
}
153
 
154
/*
155
 * pdacf_pcm_hw_free - hw_free callback for playback and capture
156
 */
157
static int pdacf_pcm_hw_free(struct snd_pcm_substream *subs)
158
{
159
        return snd_pcm_free_vmalloc_buffer(subs);
160
}
161
 
162
/*
163
 * pdacf_pcm_prepare - prepare callback for playback and capture
164
 */
165
static int pdacf_pcm_prepare(struct snd_pcm_substream *subs)
166
{
167
        struct snd_pdacf *chip = snd_pcm_substream_chip(subs);
168
        struct snd_pcm_runtime *runtime = subs->runtime;
169
        u16 val, nval, aval;
170
 
171
        if (chip->chip_status & PDAUDIOCF_STAT_IS_STALE)
172
                return -EBUSY;
173
 
174
        chip->pcm_channels = runtime->channels;
175
 
176
        chip->pcm_little = snd_pcm_format_little_endian(runtime->format) > 0;
177
#ifdef SNDRV_LITTLE_ENDIAN
178
        chip->pcm_swab = snd_pcm_format_big_endian(runtime->format) > 0;
179
#else
180
        chip->pcm_swab = chip->pcm_little;
181
#endif
182
 
183
        if (snd_pcm_format_unsigned(runtime->format))
184
                chip->pcm_xor = 0x80008000;
185
 
186
        if (pdacf_pcm_clear_sram(chip) < 0)
187
                return -EIO;
188
 
189
        val = nval = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR);
190
        nval &= ~(PDAUDIOCF_DATAFMT0|PDAUDIOCF_DATAFMT1);
191
        switch (runtime->format) {
192
        case SNDRV_PCM_FORMAT_S16_LE:
193
        case SNDRV_PCM_FORMAT_S16_BE:
194
                break;
195
        default: /* 24-bit */
196
                nval |= PDAUDIOCF_DATAFMT0 | PDAUDIOCF_DATAFMT1;
197
                break;
198
        }
199
        aval = 0;
200
        chip->pcm_sample = 4;
201
        switch (runtime->format) {
202
        case SNDRV_PCM_FORMAT_S16_LE:
203
        case SNDRV_PCM_FORMAT_S16_BE:
204
                aval = AK4117_DIF_16R;
205
                chip->pcm_frame = 2;
206
                chip->pcm_sample = 2;
207
                break;
208
        case SNDRV_PCM_FORMAT_S24_3LE:
209
        case SNDRV_PCM_FORMAT_S24_3BE:
210
                chip->pcm_sample = 3;
211
                /* fall through */
212
        default: /* 24-bit */
213
                aval = AK4117_DIF_24R;
214
                chip->pcm_frame = 3;
215
                chip->pcm_xor &= 0xffff0000;
216
                break;
217
        }
218
 
219
        if (val != nval) {
220
                snd_ak4117_reg_write(chip->ak4117, AK4117_REG_IO, AK4117_DIF2|AK4117_DIF1|AK4117_DIF0, aval);
221
                pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, nval);
222
        }
223
 
224
        val = pdacf_reg_read(chip,  PDAUDIOCF_REG_IER);
225
        val &= ~(PDAUDIOCF_IRQLVLEN1);
226
        val |= PDAUDIOCF_IRQLVLEN0;
227
        pdacf_reg_write(chip, PDAUDIOCF_REG_IER, val);
228
 
229
        chip->pcm_size = runtime->buffer_size;
230
        chip->pcm_period = runtime->period_size;
231
        chip->pcm_area = runtime->dma_area;
232
 
233
        return 0;
234
}
235
 
236
 
237
/*
238
 * capture hw information
239
 */
240
 
241
static struct snd_pcm_hardware pdacf_pcm_capture_hw = {
242
        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
243
                                 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME |
244
                                 SNDRV_PCM_INFO_MMAP_VALID),
245
        .formats =              SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
246
                                SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |
247
                                SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE,
248
        .rates =                SNDRV_PCM_RATE_32000 |
249
                                SNDRV_PCM_RATE_44100 |
250
                                SNDRV_PCM_RATE_48000 |
251
                                SNDRV_PCM_RATE_88200 |
252
                                SNDRV_PCM_RATE_96000 |
253
                                SNDRV_PCM_RATE_176400 |
254
                                SNDRV_PCM_RATE_192000,
255
        .rate_min =             32000,
256
        .rate_max =             192000,
257
        .channels_min =         1,
258
        .channels_max =         2,
259
        .buffer_bytes_max =     (512*1024),
260
        .period_bytes_min =     8*1024,
261
        .period_bytes_max =     (64*1024),
262
        .periods_min =          2,
263
        .periods_max =          128,
264
        .fifo_size =            0,
265
};
266
 
267
 
268
/*
269
 * pdacf_pcm_capture_open - open callback for capture
270
 */
271
static int pdacf_pcm_capture_open(struct snd_pcm_substream *subs)
272
{
273
        struct snd_pcm_runtime *runtime = subs->runtime;
274
        struct snd_pdacf *chip = snd_pcm_substream_chip(subs);
275
 
276
        if (chip->chip_status & PDAUDIOCF_STAT_IS_STALE)
277
                return -EBUSY;
278
 
279
        runtime->hw = pdacf_pcm_capture_hw;
280
        runtime->private_data = chip;
281
        chip->pcm_substream = subs;
282
 
283
        return 0;
284
}
285
 
286
/*
287
 * pdacf_pcm_capture_close - close callback for capture
288
 */
289
static int pdacf_pcm_capture_close(struct snd_pcm_substream *subs)
290
{
291
        struct snd_pdacf *chip = snd_pcm_substream_chip(subs);
292
 
293
        if (!chip)
294
                return -EINVAL;
295
        pdacf_reinit(chip, 0);
296
        chip->pcm_substream = NULL;
297
        return 0;
298
}
299
 
300
 
301
/*
302
 * pdacf_pcm_capture_pointer - pointer callback for capture
303
 */
304
static snd_pcm_uframes_t pdacf_pcm_capture_pointer(struct snd_pcm_substream *subs)
305
{
306
        struct snd_pdacf *chip = snd_pcm_substream_chip(subs);
307
        return chip->pcm_hwptr;
308
}
309
 
310
/*
311
 * operators for PCM capture
312
 */
313
static struct snd_pcm_ops pdacf_pcm_capture_ops = {
314
        .open =         pdacf_pcm_capture_open,
315
        .close =        pdacf_pcm_capture_close,
316
        .ioctl =        snd_pcm_lib_ioctl,
317
        .hw_params =    pdacf_pcm_hw_params,
318
        .hw_free =      pdacf_pcm_hw_free,
319
        .prepare =      pdacf_pcm_prepare,
320
        .trigger =      pdacf_pcm_trigger,
321
        .pointer =      pdacf_pcm_capture_pointer,
322
        .page =         snd_pcm_get_vmalloc_page,
323
};
324
 
325
 
326
/*
327
 * snd_pdacf_pcm_new - create and initialize a pcm
328
 */
329
int snd_pdacf_pcm_new(struct snd_pdacf *chip)
330
{
331
        struct snd_pcm *pcm;
332
        int err;
333
 
334
        err = snd_pcm_new(chip->card, "PDAudioCF", 0, 0, 1, &pcm);
335
        if (err < 0)
336
                return err;
337
 
338
        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pdacf_pcm_capture_ops);
339
 
340
        pcm->private_data = chip;
341
        pcm->info_flags = 0;
342
        strcpy(pcm->name, chip->card->shortname);
343
        chip->pcm = pcm;
344
 
345
        err = snd_ak4117_build(chip->ak4117, pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream);
346
        if (err < 0)
347
                return err;
348
 
349
        return 0;
350
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.