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/semaphore.h>
30 #include <linux/uaccess.h>
31 #include <asm/system.h>
32 #include <sound/core.h>
33 #include <sound/pcm.h>
34 #include <sound/initval.h>
36 #include "go7007-priv.h"
38 static int index
[SNDRV_CARDS
] = SNDRV_DEFAULT_IDX
;
39 static char *id
[SNDRV_CARDS
] = SNDRV_DEFAULT_STR
;
40 static int enable
[SNDRV_CARDS
] = SNDRV_DEFAULT_ENABLE_PNP
;
42 module_param_array(index
, int, NULL
, 0444);
43 module_param_array(id
, charp
, NULL
, 0444);
44 module_param_array(enable
, bool, NULL
, 0444);
45 MODULE_PARM_DESC(index
, "Index value for the go7007 audio driver");
46 MODULE_PARM_DESC(id
, "ID string for the go7007 audio driver");
47 MODULE_PARM_DESC(enable
, "Enable for the go7007 audio driver");
50 struct snd_card
*card
;
52 struct snd_pcm_substream
*substream
;
60 static struct snd_pcm_hardware go7007_snd_capture_hw
= {
61 .info
= (SNDRV_PCM_INFO_MMAP
|
62 SNDRV_PCM_INFO_INTERLEAVED
|
63 SNDRV_PCM_INFO_BLOCK_TRANSFER
|
64 SNDRV_PCM_INFO_MMAP_VALID
),
65 .formats
= SNDRV_PCM_FMTBIT_S16_LE
,
66 .rates
= SNDRV_PCM_RATE_48000
,
71 .buffer_bytes_max
= (128*1024),
72 .period_bytes_min
= 4096,
73 .period_bytes_max
= (128*1024),
78 static void parse_audio_stream_data(struct go7007
*go
, u8
*buf
, int length
)
80 struct go7007_snd
*gosnd
= go
->snd_context
;
81 struct snd_pcm_runtime
*runtime
= gosnd
->substream
->runtime
;
82 int frames
= bytes_to_frames(runtime
, length
);
84 spin_lock(&gosnd
->lock
);
85 gosnd
->hw_ptr
+= frames
;
86 if (gosnd
->hw_ptr
>= runtime
->buffer_size
)
87 gosnd
->hw_ptr
-= runtime
->buffer_size
;
88 gosnd
->avail
+= frames
;
89 spin_unlock(&gosnd
->lock
);
90 if (gosnd
->w_idx
+ length
> runtime
->dma_bytes
) {
91 int cpy
= runtime
->dma_bytes
- gosnd
->w_idx
;
93 memcpy(runtime
->dma_area
+ gosnd
->w_idx
, buf
, cpy
);
98 memcpy(runtime
->dma_area
+ gosnd
->w_idx
, buf
, length
);
99 gosnd
->w_idx
+= length
;
100 spin_lock(&gosnd
->lock
);
101 if (gosnd
->avail
< runtime
->period_size
) {
102 spin_unlock(&gosnd
->lock
);
105 gosnd
->avail
-= runtime
->period_size
;
106 spin_unlock(&gosnd
->lock
);
107 if (gosnd
->capturing
)
108 snd_pcm_period_elapsed(gosnd
->substream
);
111 static int go7007_snd_hw_params(struct snd_pcm_substream
*substream
,
112 struct snd_pcm_hw_params
*hw_params
)
114 struct go7007
*go
= snd_pcm_substream_chip(substream
);
117 bytes
= params_buffer_bytes(hw_params
);
118 if (substream
->runtime
->dma_bytes
> 0)
119 vfree(substream
->runtime
->dma_area
);
120 substream
->runtime
->dma_bytes
= 0;
121 substream
->runtime
->dma_area
= vmalloc(bytes
);
122 if (substream
->runtime
->dma_area
== NULL
)
124 substream
->runtime
->dma_bytes
= bytes
;
125 go
->audio_deliver
= parse_audio_stream_data
;
129 static int go7007_snd_hw_free(struct snd_pcm_substream
*substream
)
131 struct go7007
*go
= snd_pcm_substream_chip(substream
);
133 go
->audio_deliver
= NULL
;
134 if (substream
->runtime
->dma_bytes
> 0)
135 vfree(substream
->runtime
->dma_area
);
136 substream
->runtime
->dma_bytes
= 0;
140 static int go7007_snd_capture_open(struct snd_pcm_substream
*substream
)
142 struct go7007
*go
= snd_pcm_substream_chip(substream
);
143 struct go7007_snd
*gosnd
= go
->snd_context
;
147 spin_lock_irqsave(&gosnd
->lock
, flags
);
148 if (gosnd
->substream
== NULL
) {
149 gosnd
->substream
= substream
;
150 substream
->runtime
->hw
= go7007_snd_capture_hw
;
154 spin_unlock_irqrestore(&gosnd
->lock
, flags
);
158 static int go7007_snd_capture_close(struct snd_pcm_substream
*substream
)
160 struct go7007
*go
= snd_pcm_substream_chip(substream
);
161 struct go7007_snd
*gosnd
= go
->snd_context
;
163 gosnd
->substream
= NULL
;
167 static int go7007_snd_pcm_prepare(struct snd_pcm_substream
*substream
)
172 static int go7007_snd_pcm_trigger(struct snd_pcm_substream
*substream
, int cmd
)
174 struct go7007
*go
= snd_pcm_substream_chip(substream
);
175 struct go7007_snd
*gosnd
= go
->snd_context
;
178 case SNDRV_PCM_TRIGGER_START
:
179 /* Just set a flag to indicate we should signal ALSA when
181 gosnd
->capturing
= 1;
183 case SNDRV_PCM_TRIGGER_STOP
:
184 gosnd
->hw_ptr
= gosnd
->w_idx
= gosnd
->avail
= 0;
185 gosnd
->capturing
= 0;
192 static snd_pcm_uframes_t
go7007_snd_pcm_pointer(struct snd_pcm_substream
*substream
)
194 struct go7007
*go
= snd_pcm_substream_chip(substream
);
195 struct go7007_snd
*gosnd
= go
->snd_context
;
197 return gosnd
->hw_ptr
;
200 static struct page
*go7007_snd_pcm_page(struct snd_pcm_substream
*substream
,
201 unsigned long offset
)
203 return vmalloc_to_page(substream
->runtime
->dma_area
+ offset
);
206 static struct snd_pcm_ops go7007_snd_capture_ops
= {
207 .open
= go7007_snd_capture_open
,
208 .close
= go7007_snd_capture_close
,
209 .ioctl
= snd_pcm_lib_ioctl
,
210 .hw_params
= go7007_snd_hw_params
,
211 .hw_free
= go7007_snd_hw_free
,
212 .prepare
= go7007_snd_pcm_prepare
,
213 .trigger
= go7007_snd_pcm_trigger
,
214 .pointer
= go7007_snd_pcm_pointer
,
215 .page
= go7007_snd_pcm_page
,
218 static int go7007_snd_free(struct snd_device
*device
)
220 struct go7007
*go
= device
->device_data
;
222 kfree(go
->snd_context
);
223 go
->snd_context
= NULL
;
224 if (--go
->ref_count
== 0)
229 static struct snd_device_ops go7007_snd_device_ops
= {
230 .dev_free
= go7007_snd_free
,
233 int go7007_snd_init(struct go7007
*go
)
236 struct go7007_snd
*gosnd
;
239 if (dev
>= SNDRV_CARDS
)
245 gosnd
= kmalloc(sizeof(struct go7007_snd
), GFP_KERNEL
);
248 spin_lock_init(&gosnd
->lock
);
249 gosnd
->hw_ptr
= gosnd
->w_idx
= gosnd
->avail
= 0;
250 gosnd
->capturing
= 0;
251 ret
= snd_card_create(index
[dev
], id
[dev
], THIS_MODULE
, 0,
257 ret
= snd_device_new(gosnd
->card
, SNDRV_DEV_LOWLEVEL
, go
,
258 &go7007_snd_device_ops
);
263 snd_card_set_dev(gosnd
->card
, go
->dev
);
264 ret
= snd_pcm_new(gosnd
->card
, "go7007", 0, 0, 1, &gosnd
->pcm
);
266 snd_card_free(gosnd
->card
);
270 strncpy(gosnd
->card
->driver
, "go7007", sizeof(gosnd
->card
->driver
));
271 strncpy(gosnd
->card
->shortname
, go
->name
, sizeof(gosnd
->card
->driver
));
272 strncpy(gosnd
->card
->longname
, gosnd
->card
->shortname
,
273 sizeof(gosnd
->card
->longname
));
275 gosnd
->pcm
->private_data
= go
;
276 snd_pcm_set_ops(gosnd
->pcm
, SNDRV_PCM_STREAM_CAPTURE
,
277 &go7007_snd_capture_ops
);
279 ret
= snd_card_register(gosnd
->card
);
281 snd_card_free(gosnd
->card
);
286 gosnd
->substream
= NULL
;
287 go
->snd_context
= gosnd
;
293 EXPORT_SYMBOL(go7007_snd_init
);
295 int go7007_snd_remove(struct go7007
*go
)
297 struct go7007_snd
*gosnd
= go
->snd_context
;
299 snd_card_disconnect(gosnd
->card
);
300 snd_card_free_when_closed(gosnd
->card
);
303 EXPORT_SYMBOL(go7007_snd_remove
);
305 MODULE_LICENSE("GPL v2");