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.
14 #include <linux/kernel.h>
15 #include <linux/module.h>
16 #include <linux/moduleparam.h>
17 #include <linux/spinlock.h>
18 #include <linux/delay.h>
19 #include <linux/sched.h>
20 #include <linux/vmalloc.h>
21 #include <linux/time.h>
23 #include <linux/i2c.h>
24 #include <linux/mutex.h>
25 #include <linux/uaccess.h>
26 #include <linux/slab.h>
27 #include <sound/core.h>
28 #include <sound/pcm.h>
29 #include <sound/initval.h>
31 #include "go7007-priv.h"
33 static int index
[SNDRV_CARDS
] = SNDRV_DEFAULT_IDX
;
34 static char *id
[SNDRV_CARDS
] = SNDRV_DEFAULT_STR
;
35 static bool enable
[SNDRV_CARDS
] = SNDRV_DEFAULT_ENABLE_PNP
;
37 module_param_array(index
, int, NULL
, 0444);
38 module_param_array(id
, charp
, NULL
, 0444);
39 module_param_array(enable
, bool, NULL
, 0444);
40 MODULE_PARM_DESC(index
, "Index value for the go7007 audio driver");
41 MODULE_PARM_DESC(id
, "ID string for the go7007 audio driver");
42 MODULE_PARM_DESC(enable
, "Enable for the go7007 audio driver");
45 struct snd_card
*card
;
47 struct snd_pcm_substream
*substream
;
55 static const struct snd_pcm_hardware go7007_snd_capture_hw
= {
56 .info
= (SNDRV_PCM_INFO_MMAP
|
57 SNDRV_PCM_INFO_INTERLEAVED
|
58 SNDRV_PCM_INFO_BLOCK_TRANSFER
|
59 SNDRV_PCM_INFO_MMAP_VALID
),
60 .formats
= SNDRV_PCM_FMTBIT_S16_LE
,
61 .rates
= SNDRV_PCM_RATE_48000
,
66 .buffer_bytes_max
= (128*1024),
67 .period_bytes_min
= 4096,
68 .period_bytes_max
= (128*1024),
73 static void parse_audio_stream_data(struct go7007
*go
, u8
*buf
, int length
)
75 struct go7007_snd
*gosnd
= go
->snd_context
;
76 struct snd_pcm_runtime
*runtime
= gosnd
->substream
->runtime
;
77 int frames
= bytes_to_frames(runtime
, length
);
79 spin_lock(&gosnd
->lock
);
80 gosnd
->hw_ptr
+= frames
;
81 if (gosnd
->hw_ptr
>= runtime
->buffer_size
)
82 gosnd
->hw_ptr
-= runtime
->buffer_size
;
83 gosnd
->avail
+= frames
;
84 spin_unlock(&gosnd
->lock
);
85 if (gosnd
->w_idx
+ length
> runtime
->dma_bytes
) {
86 int cpy
= runtime
->dma_bytes
- gosnd
->w_idx
;
88 memcpy(runtime
->dma_area
+ gosnd
->w_idx
, buf
, cpy
);
93 memcpy(runtime
->dma_area
+ gosnd
->w_idx
, buf
, length
);
94 gosnd
->w_idx
+= length
;
95 spin_lock(&gosnd
->lock
);
96 if (gosnd
->avail
< runtime
->period_size
) {
97 spin_unlock(&gosnd
->lock
);
100 gosnd
->avail
-= runtime
->period_size
;
101 spin_unlock(&gosnd
->lock
);
102 if (gosnd
->capturing
)
103 snd_pcm_period_elapsed(gosnd
->substream
);
106 static int go7007_snd_hw_params(struct snd_pcm_substream
*substream
,
107 struct snd_pcm_hw_params
*hw_params
)
109 struct go7007
*go
= snd_pcm_substream_chip(substream
);
112 bytes
= params_buffer_bytes(hw_params
);
113 if (substream
->runtime
->dma_bytes
> 0)
114 vfree(substream
->runtime
->dma_area
);
115 substream
->runtime
->dma_bytes
= 0;
116 substream
->runtime
->dma_area
= vmalloc(bytes
);
117 if (substream
->runtime
->dma_area
== NULL
)
119 substream
->runtime
->dma_bytes
= bytes
;
120 go
->audio_deliver
= parse_audio_stream_data
;
124 static int go7007_snd_hw_free(struct snd_pcm_substream
*substream
)
126 struct go7007
*go
= snd_pcm_substream_chip(substream
);
128 go
->audio_deliver
= NULL
;
129 if (substream
->runtime
->dma_bytes
> 0)
130 vfree(substream
->runtime
->dma_area
);
131 substream
->runtime
->dma_bytes
= 0;
135 static int go7007_snd_capture_open(struct snd_pcm_substream
*substream
)
137 struct go7007
*go
= snd_pcm_substream_chip(substream
);
138 struct go7007_snd
*gosnd
= go
->snd_context
;
142 spin_lock_irqsave(&gosnd
->lock
, flags
);
143 if (gosnd
->substream
== NULL
) {
144 gosnd
->substream
= substream
;
145 substream
->runtime
->hw
= go7007_snd_capture_hw
;
149 spin_unlock_irqrestore(&gosnd
->lock
, flags
);
153 static int go7007_snd_capture_close(struct snd_pcm_substream
*substream
)
155 struct go7007
*go
= snd_pcm_substream_chip(substream
);
156 struct go7007_snd
*gosnd
= go
->snd_context
;
158 gosnd
->substream
= NULL
;
162 static int go7007_snd_pcm_prepare(struct snd_pcm_substream
*substream
)
167 static int go7007_snd_pcm_trigger(struct snd_pcm_substream
*substream
, int cmd
)
169 struct go7007
*go
= snd_pcm_substream_chip(substream
);
170 struct go7007_snd
*gosnd
= go
->snd_context
;
173 case SNDRV_PCM_TRIGGER_START
:
174 /* Just set a flag to indicate we should signal ALSA when
176 gosnd
->capturing
= 1;
178 case SNDRV_PCM_TRIGGER_STOP
:
179 gosnd
->hw_ptr
= gosnd
->w_idx
= gosnd
->avail
= 0;
180 gosnd
->capturing
= 0;
187 static snd_pcm_uframes_t
go7007_snd_pcm_pointer(struct snd_pcm_substream
*substream
)
189 struct go7007
*go
= snd_pcm_substream_chip(substream
);
190 struct go7007_snd
*gosnd
= go
->snd_context
;
192 return gosnd
->hw_ptr
;
195 static struct page
*go7007_snd_pcm_page(struct snd_pcm_substream
*substream
,
196 unsigned long offset
)
198 return vmalloc_to_page(substream
->runtime
->dma_area
+ offset
);
201 static const struct snd_pcm_ops go7007_snd_capture_ops
= {
202 .open
= go7007_snd_capture_open
,
203 .close
= go7007_snd_capture_close
,
204 .ioctl
= snd_pcm_lib_ioctl
,
205 .hw_params
= go7007_snd_hw_params
,
206 .hw_free
= go7007_snd_hw_free
,
207 .prepare
= go7007_snd_pcm_prepare
,
208 .trigger
= go7007_snd_pcm_trigger
,
209 .pointer
= go7007_snd_pcm_pointer
,
210 .page
= go7007_snd_pcm_page
,
213 static int go7007_snd_free(struct snd_device
*device
)
215 struct go7007
*go
= device
->device_data
;
217 kfree(go
->snd_context
);
218 go
->snd_context
= NULL
;
222 static struct snd_device_ops go7007_snd_device_ops
= {
223 .dev_free
= go7007_snd_free
,
226 int go7007_snd_init(struct go7007
*go
)
229 struct go7007_snd
*gosnd
;
232 if (dev
>= SNDRV_CARDS
)
238 gosnd
= kmalloc(sizeof(struct go7007_snd
), GFP_KERNEL
);
241 spin_lock_init(&gosnd
->lock
);
242 gosnd
->hw_ptr
= gosnd
->w_idx
= gosnd
->avail
= 0;
243 gosnd
->capturing
= 0;
244 ret
= snd_card_new(go
->dev
, index
[dev
], id
[dev
], THIS_MODULE
, 0,
250 ret
= snd_device_new(gosnd
->card
, SNDRV_DEV_LOWLEVEL
, go
,
251 &go7007_snd_device_ops
);
256 ret
= snd_pcm_new(gosnd
->card
, "go7007", 0, 0, 1, &gosnd
->pcm
);
258 snd_card_free(gosnd
->card
);
262 strlcpy(gosnd
->card
->driver
, "go7007", sizeof(gosnd
->card
->driver
));
263 strlcpy(gosnd
->card
->shortname
, go
->name
, sizeof(gosnd
->card
->driver
));
264 strlcpy(gosnd
->card
->longname
, gosnd
->card
->shortname
,
265 sizeof(gosnd
->card
->longname
));
267 gosnd
->pcm
->private_data
= go
;
268 snd_pcm_set_ops(gosnd
->pcm
, SNDRV_PCM_STREAM_CAPTURE
,
269 &go7007_snd_capture_ops
);
271 ret
= snd_card_register(gosnd
->card
);
273 snd_card_free(gosnd
->card
);
278 gosnd
->substream
= NULL
;
279 go
->snd_context
= gosnd
;
280 v4l2_device_get(&go
->v4l2_dev
);
285 EXPORT_SYMBOL(go7007_snd_init
);
287 int go7007_snd_remove(struct go7007
*go
)
289 struct go7007_snd
*gosnd
= go
->snd_context
;
291 snd_card_disconnect(gosnd
->card
);
292 snd_card_free_when_closed(gosnd
->card
);
293 v4l2_device_put(&go
->v4l2_dev
);
296 EXPORT_SYMBOL(go7007_snd_remove
);
298 MODULE_LICENSE("GPL v2");