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/spinlock.h>
22 #include <linux/delay.h>
23 #include <linux/sched.h>
24 #include <linux/vmalloc.h>
25 #include <linux/time.h>
27 #include <linux/i2c.h>
28 #include <linux/mutex.h>
29 #include <linux/uaccess.h>
30 #include <linux/slab.h>
31 #include <sound/core.h>
32 #include <sound/pcm.h>
33 #include <sound/initval.h>
35 #include "go7007-priv.h"
37 static int index
[SNDRV_CARDS
] = SNDRV_DEFAULT_IDX
;
38 static char *id
[SNDRV_CARDS
] = SNDRV_DEFAULT_STR
;
39 static bool enable
[SNDRV_CARDS
] = SNDRV_DEFAULT_ENABLE_PNP
;
41 module_param_array(index
, int, NULL
, 0444);
42 module_param_array(id
, charp
, NULL
, 0444);
43 module_param_array(enable
, bool, NULL
, 0444);
44 MODULE_PARM_DESC(index
, "Index value for the go7007 audio driver");
45 MODULE_PARM_DESC(id
, "ID string for the go7007 audio driver");
46 MODULE_PARM_DESC(enable
, "Enable for the go7007 audio driver");
49 struct snd_card
*card
;
51 struct snd_pcm_substream
*substream
;
59 static struct snd_pcm_hardware go7007_snd_capture_hw
= {
60 .info
= (SNDRV_PCM_INFO_MMAP
|
61 SNDRV_PCM_INFO_INTERLEAVED
|
62 SNDRV_PCM_INFO_BLOCK_TRANSFER
|
63 SNDRV_PCM_INFO_MMAP_VALID
),
64 .formats
= SNDRV_PCM_FMTBIT_S16_LE
,
65 .rates
= SNDRV_PCM_RATE_48000
,
70 .buffer_bytes_max
= (128*1024),
71 .period_bytes_min
= 4096,
72 .period_bytes_max
= (128*1024),
77 static void parse_audio_stream_data(struct go7007
*go
, u8
*buf
, int length
)
79 struct go7007_snd
*gosnd
= go
->snd_context
;
80 struct snd_pcm_runtime
*runtime
= gosnd
->substream
->runtime
;
81 int frames
= bytes_to_frames(runtime
, length
);
83 spin_lock(&gosnd
->lock
);
84 gosnd
->hw_ptr
+= frames
;
85 if (gosnd
->hw_ptr
>= runtime
->buffer_size
)
86 gosnd
->hw_ptr
-= runtime
->buffer_size
;
87 gosnd
->avail
+= frames
;
88 spin_unlock(&gosnd
->lock
);
89 if (gosnd
->w_idx
+ length
> runtime
->dma_bytes
) {
90 int cpy
= runtime
->dma_bytes
- gosnd
->w_idx
;
92 memcpy(runtime
->dma_area
+ gosnd
->w_idx
, buf
, cpy
);
97 memcpy(runtime
->dma_area
+ gosnd
->w_idx
, buf
, length
);
98 gosnd
->w_idx
+= length
;
99 spin_lock(&gosnd
->lock
);
100 if (gosnd
->avail
< runtime
->period_size
) {
101 spin_unlock(&gosnd
->lock
);
104 gosnd
->avail
-= runtime
->period_size
;
105 spin_unlock(&gosnd
->lock
);
106 if (gosnd
->capturing
)
107 snd_pcm_period_elapsed(gosnd
->substream
);
110 static int go7007_snd_hw_params(struct snd_pcm_substream
*substream
,
111 struct snd_pcm_hw_params
*hw_params
)
113 struct go7007
*go
= snd_pcm_substream_chip(substream
);
116 bytes
= params_buffer_bytes(hw_params
);
117 if (substream
->runtime
->dma_bytes
> 0)
118 vfree(substream
->runtime
->dma_area
);
119 substream
->runtime
->dma_bytes
= 0;
120 substream
->runtime
->dma_area
= vmalloc(bytes
);
121 if (substream
->runtime
->dma_area
== NULL
)
123 substream
->runtime
->dma_bytes
= bytes
;
124 go
->audio_deliver
= parse_audio_stream_data
;
128 static int go7007_snd_hw_free(struct snd_pcm_substream
*substream
)
130 struct go7007
*go
= snd_pcm_substream_chip(substream
);
132 go
->audio_deliver
= NULL
;
133 if (substream
->runtime
->dma_bytes
> 0)
134 vfree(substream
->runtime
->dma_area
);
135 substream
->runtime
->dma_bytes
= 0;
139 static int go7007_snd_capture_open(struct snd_pcm_substream
*substream
)
141 struct go7007
*go
= snd_pcm_substream_chip(substream
);
142 struct go7007_snd
*gosnd
= go
->snd_context
;
146 spin_lock_irqsave(&gosnd
->lock
, flags
);
147 if (gosnd
->substream
== NULL
) {
148 gosnd
->substream
= substream
;
149 substream
->runtime
->hw
= go7007_snd_capture_hw
;
153 spin_unlock_irqrestore(&gosnd
->lock
, flags
);
157 static int go7007_snd_capture_close(struct snd_pcm_substream
*substream
)
159 struct go7007
*go
= snd_pcm_substream_chip(substream
);
160 struct go7007_snd
*gosnd
= go
->snd_context
;
162 gosnd
->substream
= NULL
;
166 static int go7007_snd_pcm_prepare(struct snd_pcm_substream
*substream
)
171 static int go7007_snd_pcm_trigger(struct snd_pcm_substream
*substream
, int cmd
)
173 struct go7007
*go
= snd_pcm_substream_chip(substream
);
174 struct go7007_snd
*gosnd
= go
->snd_context
;
177 case SNDRV_PCM_TRIGGER_START
:
178 /* Just set a flag to indicate we should signal ALSA when
180 gosnd
->capturing
= 1;
182 case SNDRV_PCM_TRIGGER_STOP
:
183 gosnd
->hw_ptr
= gosnd
->w_idx
= gosnd
->avail
= 0;
184 gosnd
->capturing
= 0;
191 static snd_pcm_uframes_t
go7007_snd_pcm_pointer(struct snd_pcm_substream
*substream
)
193 struct go7007
*go
= snd_pcm_substream_chip(substream
);
194 struct go7007_snd
*gosnd
= go
->snd_context
;
196 return gosnd
->hw_ptr
;
199 static struct page
*go7007_snd_pcm_page(struct snd_pcm_substream
*substream
,
200 unsigned long offset
)
202 return vmalloc_to_page(substream
->runtime
->dma_area
+ offset
);
205 static struct snd_pcm_ops go7007_snd_capture_ops
= {
206 .open
= go7007_snd_capture_open
,
207 .close
= go7007_snd_capture_close
,
208 .ioctl
= snd_pcm_lib_ioctl
,
209 .hw_params
= go7007_snd_hw_params
,
210 .hw_free
= go7007_snd_hw_free
,
211 .prepare
= go7007_snd_pcm_prepare
,
212 .trigger
= go7007_snd_pcm_trigger
,
213 .pointer
= go7007_snd_pcm_pointer
,
214 .page
= go7007_snd_pcm_page
,
217 static int go7007_snd_free(struct snd_device
*device
)
219 struct go7007
*go
= device
->device_data
;
221 kfree(go
->snd_context
);
222 go
->snd_context
= NULL
;
226 static struct snd_device_ops go7007_snd_device_ops
= {
227 .dev_free
= go7007_snd_free
,
230 int go7007_snd_init(struct go7007
*go
)
233 struct go7007_snd
*gosnd
;
236 if (dev
>= SNDRV_CARDS
)
242 gosnd
= kmalloc(sizeof(struct go7007_snd
), GFP_KERNEL
);
245 spin_lock_init(&gosnd
->lock
);
246 gosnd
->hw_ptr
= gosnd
->w_idx
= gosnd
->avail
= 0;
247 gosnd
->capturing
= 0;
248 ret
= snd_card_create(index
[dev
], id
[dev
], THIS_MODULE
, 0,
254 ret
= snd_device_new(gosnd
->card
, SNDRV_DEV_LOWLEVEL
, go
,
255 &go7007_snd_device_ops
);
260 snd_card_set_dev(gosnd
->card
, go
->dev
);
261 ret
= snd_pcm_new(gosnd
->card
, "go7007", 0, 0, 1, &gosnd
->pcm
);
263 snd_card_free(gosnd
->card
);
267 strlcpy(gosnd
->card
->driver
, "go7007", sizeof(gosnd
->card
->driver
));
268 strlcpy(gosnd
->card
->shortname
, go
->name
, sizeof(gosnd
->card
->driver
));
269 strlcpy(gosnd
->card
->longname
, gosnd
->card
->shortname
,
270 sizeof(gosnd
->card
->longname
));
272 gosnd
->pcm
->private_data
= go
;
273 snd_pcm_set_ops(gosnd
->pcm
, SNDRV_PCM_STREAM_CAPTURE
,
274 &go7007_snd_capture_ops
);
276 ret
= snd_card_register(gosnd
->card
);
278 snd_card_free(gosnd
->card
);
283 gosnd
->substream
= NULL
;
284 go
->snd_context
= gosnd
;
285 v4l2_device_get(&go
->v4l2_dev
);
290 EXPORT_SYMBOL(go7007_snd_init
);
292 int go7007_snd_remove(struct go7007
*go
)
294 struct go7007_snd
*gosnd
= go
->snd_context
;
296 snd_card_disconnect(gosnd
->card
);
297 snd_card_free_when_closed(gosnd
->card
);
298 v4l2_device_put(&go
->v4l2_dev
);
301 EXPORT_SYMBOL(go7007_snd_remove
);
303 MODULE_LICENSE("GPL v2");