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
);