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
);
80 spin_lock_irqsave(&gosnd
->lock
, flags
);
81 gosnd
->hw_ptr
+= frames
;
82 if (gosnd
->hw_ptr
>= runtime
->buffer_size
)
83 gosnd
->hw_ptr
-= runtime
->buffer_size
;
84 gosnd
->avail
+= frames
;
85 spin_unlock_irqrestore(&gosnd
->lock
, flags
);
86 if (gosnd
->w_idx
+ length
> runtime
->dma_bytes
) {
87 int cpy
= runtime
->dma_bytes
- gosnd
->w_idx
;
89 memcpy(runtime
->dma_area
+ gosnd
->w_idx
, buf
, cpy
);
94 memcpy(runtime
->dma_area
+ gosnd
->w_idx
, buf
, length
);
95 gosnd
->w_idx
+= length
;
96 spin_lock_irqsave(&gosnd
->lock
, flags
);
97 if (gosnd
->avail
< runtime
->period_size
) {
98 spin_unlock_irqrestore(&gosnd
->lock
, flags
);
101 gosnd
->avail
-= runtime
->period_size
;
102 spin_unlock_irqrestore(&gosnd
->lock
, flags
);
103 if (gosnd
->capturing
)
104 snd_pcm_period_elapsed(gosnd
->substream
);
107 static int go7007_snd_hw_params(struct snd_pcm_substream
*substream
,
108 struct snd_pcm_hw_params
*hw_params
)
110 struct go7007
*go
= snd_pcm_substream_chip(substream
);
113 bytes
= params_buffer_bytes(hw_params
);
114 if (substream
->runtime
->dma_bytes
> 0)
115 vfree(substream
->runtime
->dma_area
);
116 substream
->runtime
->dma_bytes
= 0;
117 substream
->runtime
->dma_area
= vmalloc(bytes
);
118 if (substream
->runtime
->dma_area
== NULL
)
120 substream
->runtime
->dma_bytes
= bytes
;
121 go
->audio_deliver
= parse_audio_stream_data
;
125 static int go7007_snd_hw_free(struct snd_pcm_substream
*substream
)
127 struct go7007
*go
= snd_pcm_substream_chip(substream
);
129 go
->audio_deliver
= NULL
;
130 if (substream
->runtime
->dma_bytes
> 0)
131 vfree(substream
->runtime
->dma_area
);
132 substream
->runtime
->dma_bytes
= 0;
136 static int go7007_snd_capture_open(struct snd_pcm_substream
*substream
)
138 struct go7007
*go
= snd_pcm_substream_chip(substream
);
139 struct go7007_snd
*gosnd
= go
->snd_context
;
143 spin_lock_irqsave(&gosnd
->lock
, flags
);
144 if (gosnd
->substream
== NULL
) {
145 gosnd
->substream
= substream
;
146 substream
->runtime
->hw
= go7007_snd_capture_hw
;
150 spin_unlock_irqrestore(&gosnd
->lock
, flags
);
154 static int go7007_snd_capture_close(struct snd_pcm_substream
*substream
)
156 struct go7007
*go
= snd_pcm_substream_chip(substream
);
157 struct go7007_snd
*gosnd
= go
->snd_context
;
159 gosnd
->substream
= NULL
;
163 static int go7007_snd_pcm_prepare(struct snd_pcm_substream
*substream
)
168 static int go7007_snd_pcm_trigger(struct snd_pcm_substream
*substream
, int cmd
)
170 struct go7007
*go
= snd_pcm_substream_chip(substream
);
171 struct go7007_snd
*gosnd
= go
->snd_context
;
174 case SNDRV_PCM_TRIGGER_START
:
175 /* Just set a flag to indicate we should signal ALSA when
177 gosnd
->capturing
= 1;
179 case SNDRV_PCM_TRIGGER_STOP
:
180 gosnd
->hw_ptr
= gosnd
->w_idx
= gosnd
->avail
= 0;
181 gosnd
->capturing
= 0;
188 static snd_pcm_uframes_t
go7007_snd_pcm_pointer(struct snd_pcm_substream
*substream
)
190 struct go7007
*go
= snd_pcm_substream_chip(substream
);
191 struct go7007_snd
*gosnd
= go
->snd_context
;
193 return gosnd
->hw_ptr
;
196 static struct page
*go7007_snd_pcm_page(struct snd_pcm_substream
*substream
,
197 unsigned long offset
)
199 return vmalloc_to_page(substream
->runtime
->dma_area
+ offset
);
202 static const struct snd_pcm_ops go7007_snd_capture_ops
= {
203 .open
= go7007_snd_capture_open
,
204 .close
= go7007_snd_capture_close
,
205 .ioctl
= snd_pcm_lib_ioctl
,
206 .hw_params
= go7007_snd_hw_params
,
207 .hw_free
= go7007_snd_hw_free
,
208 .prepare
= go7007_snd_pcm_prepare
,
209 .trigger
= go7007_snd_pcm_trigger
,
210 .pointer
= go7007_snd_pcm_pointer
,
211 .page
= go7007_snd_pcm_page
,
214 static int go7007_snd_free(struct snd_device
*device
)
216 struct go7007
*go
= device
->device_data
;
218 kfree(go
->snd_context
);
219 go
->snd_context
= NULL
;
223 static struct snd_device_ops go7007_snd_device_ops
= {
224 .dev_free
= go7007_snd_free
,
227 int go7007_snd_init(struct go7007
*go
)
230 struct go7007_snd
*gosnd
;
233 if (dev
>= SNDRV_CARDS
)
239 gosnd
= kmalloc(sizeof(struct go7007_snd
), GFP_KERNEL
);
242 spin_lock_init(&gosnd
->lock
);
243 gosnd
->hw_ptr
= gosnd
->w_idx
= gosnd
->avail
= 0;
244 gosnd
->capturing
= 0;
245 ret
= snd_card_new(go
->dev
, index
[dev
], id
[dev
], THIS_MODULE
, 0,
251 ret
= snd_device_new(gosnd
->card
, SNDRV_DEV_LOWLEVEL
, go
,
252 &go7007_snd_device_ops
);
257 ret
= snd_pcm_new(gosnd
->card
, "go7007", 0, 0, 1, &gosnd
->pcm
);
259 snd_card_free(gosnd
->card
);
263 strlcpy(gosnd
->card
->driver
, "go7007", sizeof(gosnd
->card
->driver
));
264 strlcpy(gosnd
->card
->shortname
, go
->name
, sizeof(gosnd
->card
->driver
));
265 strlcpy(gosnd
->card
->longname
, gosnd
->card
->shortname
,
266 sizeof(gosnd
->card
->longname
));
268 gosnd
->pcm
->private_data
= go
;
269 snd_pcm_set_ops(gosnd
->pcm
, SNDRV_PCM_STREAM_CAPTURE
,
270 &go7007_snd_capture_ops
);
272 ret
= snd_card_register(gosnd
->card
);
274 snd_card_free(gosnd
->card
);
279 gosnd
->substream
= NULL
;
280 go
->snd_context
= gosnd
;
281 v4l2_device_get(&go
->v4l2_dev
);
286 EXPORT_SYMBOL(go7007_snd_init
);
288 int go7007_snd_remove(struct go7007
*go
)
290 struct go7007_snd
*gosnd
= go
->snd_context
;
292 snd_card_disconnect(gosnd
->card
);
293 snd_card_free_when_closed(gosnd
->card
);
294 v4l2_device_put(&go
->v4l2_dev
);
297 EXPORT_SYMBOL(go7007_snd_remove
);
299 MODULE_LICENSE("GPL v2");