1 #include <linux/kernel.h>
3 #include <linux/init.h>
4 #include <linux/sound.h>
5 #include <linux/spinlock.h>
6 #include <linux/soundcard.h>
7 #include <linux/vmalloc.h>
8 #include <linux/proc_fs.h>
9 #include <linux/module.h>
10 #include <linux/gfp.h>
11 #include <sound/core.h>
12 #include <sound/pcm.h>
13 #include <sound/pcm_params.h>
14 #include <sound/info.h>
15 #include <sound/initval.h>
16 #include <sound/control.h>
17 #include <media/v4l2-common.h>
18 #include "pd-common.h"
19 #include "vendorcmds.h"
21 static void complete_handler_audio(struct urb *urb);
22 #define AUDIO_EP (0x83)
23 #define AUDIO_BUF_SIZE (512)
24 #define PERIOD_SIZE (1024 * 8)
25 #define PERIOD_MIN (4)
26 #define PERIOD_MAX PERIOD_MIN
28 static struct snd_pcm_hardware snd_pd_hw_capture = {
29 .info = SNDRV_PCM_INFO_BLOCK_TRANSFER |
31 SNDRV_PCM_INFO_INTERLEAVED |
32 SNDRV_PCM_INFO_MMAP_VALID,
34 .formats = SNDRV_PCM_FMTBIT_S16_LE,
35 .rates = SNDRV_PCM_RATE_48000,
41 .buffer_bytes_max = PERIOD_SIZE * PERIOD_MIN,
42 .period_bytes_min = PERIOD_SIZE,
43 .period_bytes_max = PERIOD_SIZE,
44 .periods_min = PERIOD_MIN,
45 .periods_max = PERIOD_MAX,
47 .buffer_bytes_max = 62720 * 8,
48 .period_bytes_min = 64,
49 .period_bytes_max = 12544,
55 static int snd_pd_capture_open(struct snd_pcm_substream *substream)
57 struct poseidon *p = snd_pcm_substream_chip(substream);
58 struct poseidon_audio *pa = &p->audio;
59 struct snd_pcm_runtime *runtime = substream->runtime;
65 pa->capture_pcm_substream = substream;
66 runtime->private_data = p;
68 runtime->hw = snd_pd_hw_capture;
69 snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
70 usb_autopm_get_interface(p->interface);
75 static int snd_pd_pcm_close(struct snd_pcm_substream *substream)
77 struct poseidon *p = snd_pcm_substream_chip(substream);
78 struct poseidon_audio *pa = &p->audio;
82 usb_autopm_put_interface(p->interface);
83 kref_put(&p->kref, poseidon_delete);
87 static int snd_pd_hw_capture_params(struct snd_pcm_substream *substream,
88 struct snd_pcm_hw_params *hw_params)
90 struct snd_pcm_runtime *runtime = substream->runtime;
93 size = params_buffer_bytes(hw_params);
94 if (runtime->dma_area) {
95 if (runtime->dma_bytes > size)
97 vfree(runtime->dma_area);
99 runtime->dma_area = vmalloc(size);
100 if (!runtime->dma_area)
103 runtime->dma_bytes = size;
107 static int audio_buf_free(struct poseidon *p)
109 struct poseidon_audio *pa = &p->audio;
112 for (i = 0; i < AUDIO_BUFS; i++)
113 if (pa->urb_array[i])
114 usb_kill_urb(pa->urb_array[i]);
115 free_all_urb_generic(pa->urb_array, AUDIO_BUFS);
120 static int snd_pd_hw_capture_free(struct snd_pcm_substream *substream)
122 struct poseidon *p = snd_pcm_substream_chip(substream);
129 static int snd_pd_prepare(struct snd_pcm_substream *substream)
134 #define AUDIO_TRAILER_SIZE (16)
135 static inline void handle_audio_data(struct urb *urb, int *period_elapsed)
137 struct poseidon_audio *pa = urb->context;
138 struct snd_pcm_runtime *runtime = pa->capture_pcm_substream->runtime;
140 int stride = runtime->frame_bits >> 3;
141 int len = urb->actual_length / stride;
142 unsigned char *cp = urb->transfer_buffer;
143 unsigned int oldptr = pa->rcv_position;
145 if (urb->actual_length == AUDIO_BUF_SIZE - 4)
146 len -= (AUDIO_TRAILER_SIZE / stride);
149 if (oldptr + len >= runtime->buffer_size) {
150 unsigned int cnt = runtime->buffer_size - oldptr;
152 memcpy(runtime->dma_area + oldptr * stride, cp, cnt * stride);
153 memcpy(runtime->dma_area, (cp + cnt * stride),
154 (len * stride - cnt * stride));
156 memcpy(runtime->dma_area + oldptr * stride, cp, len * stride);
158 /* update the statas */
159 snd_pcm_stream_lock(pa->capture_pcm_substream);
160 pa->rcv_position += len;
161 if (pa->rcv_position >= runtime->buffer_size)
162 pa->rcv_position -= runtime->buffer_size;
164 pa->copied_position += (len);
165 if (pa->copied_position >= runtime->period_size) {
166 pa->copied_position -= runtime->period_size;
169 snd_pcm_stream_unlock(pa->capture_pcm_substream);
172 static void complete_handler_audio(struct urb *urb)
174 struct poseidon_audio *pa = urb->context;
175 struct snd_pcm_substream *substream = pa->capture_pcm_substream;
176 int period_elapsed = 0;
179 if (1 == pa->card_close || pa->capture_stream != STREAM_ON)
182 if (urb->status != 0) {
183 /*if (urb->status == -ESHUTDOWN)*/
188 if (urb->actual_length) {
189 handle_audio_data(urb, &period_elapsed);
191 snd_pcm_period_elapsed(substream);
195 ret = usb_submit_urb(urb, GFP_ATOMIC);
197 log("audio urb failed (errcod = %i)", ret);
201 static int fire_audio_urb(struct poseidon *p)
204 struct poseidon_audio *pa = &p->audio;
206 alloc_bulk_urbs_generic(pa->urb_array, AUDIO_BUFS,
208 AUDIO_BUF_SIZE, GFP_ATOMIC,
209 complete_handler_audio, pa);
211 for (i = 0; i < AUDIO_BUFS; i++) {
212 ret = usb_submit_urb(pa->urb_array[i], GFP_KERNEL);
214 log("urb err : %d", ret);
220 static int snd_pd_capture_trigger(struct snd_pcm_substream *substream, int cmd)
222 struct poseidon *p = snd_pcm_substream_chip(substream);
223 struct poseidon_audio *pa = &p->audio;
226 log("cmd %d, audio stat : %d\n", cmd, pa->capture_stream);
229 case SNDRV_PCM_TRIGGER_RESUME:
230 case SNDRV_PCM_TRIGGER_START:
231 if (pa->capture_stream == STREAM_ON)
234 pa->rcv_position = pa->copied_position = 0;
235 pa->capture_stream = STREAM_ON;
237 if (in_hibernation(p))
242 case SNDRV_PCM_TRIGGER_SUSPEND:
243 pa->capture_stream = STREAM_SUSPEND;
245 case SNDRV_PCM_TRIGGER_STOP:
246 pa->capture_stream = STREAM_OFF;
253 static snd_pcm_uframes_t
254 snd_pd_capture_pointer(struct snd_pcm_substream *substream)
256 struct poseidon *p = snd_pcm_substream_chip(substream);
257 struct poseidon_audio *pa = &p->audio;
258 return pa->rcv_position;
261 static struct page *snd_pcm_pd_get_page(struct snd_pcm_substream *subs,
262 unsigned long offset)
264 void *pageptr = subs->runtime->dma_area + offset;
265 return vmalloc_to_page(pageptr);
268 static struct snd_pcm_ops pcm_capture_ops = {
269 .open = snd_pd_capture_open,
270 .close = snd_pd_pcm_close,
271 .ioctl = snd_pcm_lib_ioctl,
272 .hw_params = snd_pd_hw_capture_params,
273 .hw_free = snd_pd_hw_capture_free,
274 .prepare = snd_pd_prepare,
275 .trigger = snd_pd_capture_trigger,
276 .pointer = snd_pd_capture_pointer,
277 .page = snd_pcm_pd_get_page,
281 int pm_alsa_suspend(struct poseidon *p)
288 int pm_alsa_resume(struct poseidon *p)
296 int poseidon_audio_init(struct poseidon *p)
298 struct poseidon_audio *pa = &p->audio;
299 struct snd_card *card;
303 ret = snd_card_create(-1, "Telegent", THIS_MODULE, 0, &card);
307 ret = snd_pcm_new(card, "poseidon audio", 0, 0, 1, &pcm);
312 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_capture_ops);
314 pcm->private_data = p;
315 strcpy(pcm->name, "poseidon audio capture");
317 strcpy(card->driver, "ALSA driver");
318 strcpy(card->shortname, "poseidon Audio");
319 strcpy(card->longname, "poseidon ALSA Audio");
321 if (snd_card_register(card)) {
329 int poseidon_audio_free(struct poseidon *p)
331 struct poseidon_audio *pa = &p->audio;
334 snd_card_free(pa->card);