2 * Copyright (C) 2005-2006 Micronas USA Inc.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License (Version 2) as
6 * published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software Foundation,
15 * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
18 #include <linux/kernel.h>
19 #include <linux/module.h>
20 #include <linux/moduleparam.h>
21 #include <linux/init.h>
22 #include <linux/spinlock.h>
23 #include <linux/delay.h>
24 #include <linux/sched.h>
25 #include <linux/vmalloc.h>
26 #include <linux/time.h>
28 #include <linux/i2c.h>
29 #include <linux/mutex.h>
30 #include <linux/uaccess.h>
31 #include <linux/slab.h>
32 #include <asm/system.h>
33 #include <sound/core.h>
34 #include <sound/pcm.h>
35 #include <sound/initval.h>
37 #include "go7007-priv.h"
39 static int index
[SNDRV_CARDS
] = SNDRV_DEFAULT_IDX
;
40 static char *id
[SNDRV_CARDS
] = SNDRV_DEFAULT_STR
;
41 static int enable
[SNDRV_CARDS
] = SNDRV_DEFAULT_ENABLE_PNP
;
43 module_param_array(index
, int, NULL
, 0444);
44 module_param_array(id
, charp
, NULL
, 0444);
45 module_param_array(enable
, bool, NULL
, 0444);
46 MODULE_PARM_DESC(index
, "Index value for the go7007 audio driver");
47 MODULE_PARM_DESC(id
, "ID string for the go7007 audio driver");
48 MODULE_PARM_DESC(enable
, "Enable for the go7007 audio driver");
51 struct snd_card
*card
;
53 struct snd_pcm_substream
*substream
;
61 static struct snd_pcm_hardware go7007_snd_capture_hw
= {
62 .info
= (SNDRV_PCM_INFO_MMAP
|
63 SNDRV_PCM_INFO_INTERLEAVED
|
64 SNDRV_PCM_INFO_BLOCK_TRANSFER
|
65 SNDRV_PCM_INFO_MMAP_VALID
),
66 .formats
= SNDRV_PCM_FMTBIT_S16_LE
,
67 .rates
= SNDRV_PCM_RATE_48000
,
72 .buffer_bytes_max
= (128*1024),
73 .period_bytes_min
= 4096,
74 .period_bytes_max
= (128*1024),
79 static void parse_audio_stream_data(struct go7007
*go
, u8
*buf
, int length
)
81 struct go7007_snd
*gosnd
= go
->snd_context
;
82 struct snd_pcm_runtime
*runtime
= gosnd
->substream
->runtime
;
83 int frames
= bytes_to_frames(runtime
, length
);
85 spin_lock(&gosnd
->lock
);
86 gosnd
->hw_ptr
+= frames
;
87 if (gosnd
->hw_ptr
>= runtime
->buffer_size
)
88 gosnd
->hw_ptr
-= runtime
->buffer_size
;
89 gosnd
->avail
+= frames
;
90 spin_unlock(&gosnd
->lock
);
91 if (gosnd
->w_idx
+ length
> runtime
->dma_bytes
) {
92 int cpy
= runtime
->dma_bytes
- gosnd
->w_idx
;
94 memcpy(runtime
->dma_area
+ gosnd
->w_idx
, buf
, cpy
);
99 memcpy(runtime
->dma_area
+ gosnd
->w_idx
, buf
, length
);
100 gosnd
->w_idx
+= length
;
101 spin_lock(&gosnd
->lock
);
102 if (gosnd
->avail
< runtime
->period_size
) {
103 spin_unlock(&gosnd
->lock
);
106 gosnd
->avail
-= runtime
->period_size
;
107 spin_unlock(&gosnd
->lock
);
108 if (gosnd
->capturing
)
109 snd_pcm_period_elapsed(gosnd
->substream
);
112 static int go7007_snd_hw_params(struct snd_pcm_substream
*substream
,
113 struct snd_pcm_hw_params
*hw_params
)
115 struct go7007
*go
= snd_pcm_substream_chip(substream
);
118 bytes
= params_buffer_bytes(hw_params
);
119 if (substream
->runtime
->dma_bytes
> 0)
120 vfree(substream
->runtime
->dma_area
);
121 substream
->runtime
->dma_bytes
= 0;
122 substream
->runtime
->dma_area
= vmalloc(bytes
);
123 if (substream
->runtime
->dma_area
== NULL
)
125 substream
->runtime
->dma_bytes
= bytes
;
126 go
->audio_deliver
= parse_audio_stream_data
;
130 static int go7007_snd_hw_free(struct snd_pcm_substream
*substream
)
132 struct go7007
*go
= snd_pcm_substream_chip(substream
);
134 go
->audio_deliver
= NULL
;
135 if (substream
->runtime
->dma_bytes
> 0)
136 vfree(substream
->runtime
->dma_area
);
137 substream
->runtime
->dma_bytes
= 0;
141 static int go7007_snd_capture_open(struct snd_pcm_substream
*substream
)
143 struct go7007
*go
= snd_pcm_substream_chip(substream
);
144 struct go7007_snd
*gosnd
= go
->snd_context
;
148 spin_lock_irqsave(&gosnd
->lock
, flags
);
149 if (gosnd
->substream
== NULL
) {
150 gosnd
->substream
= substream
;
151 substream
->runtime
->hw
= go7007_snd_capture_hw
;
155 spin_unlock_irqrestore(&gosnd
->lock
, flags
);
159 static int go7007_snd_capture_close(struct snd_pcm_substream
*substream
)
161 struct go7007
*go
= snd_pcm_substream_chip(substream
);
162 struct go7007_snd
*gosnd
= go
->snd_context
;
164 gosnd
->substream
= NULL
;
168 static int go7007_snd_pcm_prepare(struct snd_pcm_substream
*substream
)
173 static int go7007_snd_pcm_trigger(struct snd_pcm_substream
*substream
, int cmd
)
175 struct go7007
*go
= snd_pcm_substream_chip(substream
);
176 struct go7007_snd
*gosnd
= go
->snd_context
;
179 case SNDRV_PCM_TRIGGER_START
:
180 /* Just set a flag to indicate we should signal ALSA when
182 gosnd
->capturing
= 1;
184 case SNDRV_PCM_TRIGGER_STOP
:
185 gosnd
->hw_ptr
= gosnd
->w_idx
= gosnd
->avail
= 0;
186 gosnd
->capturing
= 0;
193 static snd_pcm_uframes_t
go7007_snd_pcm_pointer(struct snd_pcm_substream
*substream
)
195 struct go7007
*go
= snd_pcm_substream_chip(substream
);
196 struct go7007_snd
*gosnd
= go
->snd_context
;
198 return gosnd
->hw_ptr
;
201 static struct page
*go7007_snd_pcm_page(struct snd_pcm_substream
*substream
,
202 unsigned long offset
)
204 return vmalloc_to_page(substream
->runtime
->dma_area
+ offset
);
207 static struct snd_pcm_ops go7007_snd_capture_ops
= {
208 .open
= go7007_snd_capture_open
,
209 .close
= go7007_snd_capture_close
,
210 .ioctl
= snd_pcm_lib_ioctl
,
211 .hw_params
= go7007_snd_hw_params
,
212 .hw_free
= go7007_snd_hw_free
,
213 .prepare
= go7007_snd_pcm_prepare
,
214 .trigger
= go7007_snd_pcm_trigger
,
215 .pointer
= go7007_snd_pcm_pointer
,
216 .page
= go7007_snd_pcm_page
,
219 static int go7007_snd_free(struct snd_device
*device
)
221 struct go7007
*go
= device
->device_data
;
223 kfree(go
->snd_context
);
224 go
->snd_context
= NULL
;
225 if (--go
->ref_count
== 0)
230 static struct snd_device_ops go7007_snd_device_ops
= {
231 .dev_free
= go7007_snd_free
,
234 int go7007_snd_init(struct go7007
*go
)
237 struct go7007_snd
*gosnd
;
240 if (dev
>= SNDRV_CARDS
)
246 gosnd
= kmalloc(sizeof(struct go7007_snd
), GFP_KERNEL
);
249 spin_lock_init(&gosnd
->lock
);
250 gosnd
->hw_ptr
= gosnd
->w_idx
= gosnd
->avail
= 0;
251 gosnd
->capturing
= 0;
252 ret
= snd_card_create(index
[dev
], id
[dev
], THIS_MODULE
, 0,
258 ret
= snd_device_new(gosnd
->card
, SNDRV_DEV_LOWLEVEL
, go
,
259 &go7007_snd_device_ops
);
264 snd_card_set_dev(gosnd
->card
, go
->dev
);
265 ret
= snd_pcm_new(gosnd
->card
, "go7007", 0, 0, 1, &gosnd
->pcm
);
267 snd_card_free(gosnd
->card
);
271 strncpy(gosnd
->card
->driver
, "go7007", sizeof(gosnd
->card
->driver
));
272 strncpy(gosnd
->card
->shortname
, go
->name
, sizeof(gosnd
->card
->driver
));
273 strncpy(gosnd
->card
->longname
, gosnd
->card
->shortname
,
274 sizeof(gosnd
->card
->longname
));
276 gosnd
->pcm
->private_data
= go
;
277 snd_pcm_set_ops(gosnd
->pcm
, SNDRV_PCM_STREAM_CAPTURE
,
278 &go7007_snd_capture_ops
);
280 ret
= snd_card_register(gosnd
->card
);
282 snd_card_free(gosnd
->card
);
287 gosnd
->substream
= NULL
;
288 go
->snd_context
= gosnd
;
294 EXPORT_SYMBOL(go7007_snd_init
);
296 int go7007_snd_remove(struct go7007
*go
)
298 struct go7007_snd
*gosnd
= go
->snd_context
;
300 snd_card_disconnect(gosnd
->card
);
301 snd_card_free_when_closed(gosnd
->card
);
304 EXPORT_SYMBOL(go7007_snd_remove
);
306 MODULE_LICENSE("GPL v2");