Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pd-alsa.c
Go to the documentation of this file.
1 #include <linux/kernel.h>
2 #include <linux/usb.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"
20 
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
27 
28 static struct snd_pcm_hardware snd_pd_hw_capture = {
33 
34  .formats = SNDRV_PCM_FMTBIT_S16_LE,
35  .rates = SNDRV_PCM_RATE_48000,
36 
37  .rate_min = 48000,
38  .rate_max = 48000,
39  .channels_min = 2,
40  .channels_max = 2,
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,
46  /*
47  .buffer_bytes_max = 62720 * 8,
48  .period_bytes_min = 64,
49  .period_bytes_max = 12544,
50  .periods_min = 2,
51  .periods_max = 98
52  */
53 };
54 
55 static int snd_pd_capture_open(struct snd_pcm_substream *substream)
56 {
57  struct poseidon *p = snd_pcm_substream_chip(substream);
58  struct poseidon_audio *pa = &p->audio;
59  struct snd_pcm_runtime *runtime = substream->runtime;
60 
61  if (!p)
62  return -ENODEV;
63  pa->users++;
64  pa->card_close = 0;
65  pa->capture_pcm_substream = substream;
66  runtime->private_data = p;
67 
68  runtime->hw = snd_pd_hw_capture;
70  usb_autopm_get_interface(p->interface);
71  kref_get(&p->kref);
72  return 0;
73 }
74 
75 static int snd_pd_pcm_close(struct snd_pcm_substream *substream)
76 {
77  struct poseidon *p = snd_pcm_substream_chip(substream);
78  struct poseidon_audio *pa = &p->audio;
79 
80  pa->users--;
81  pa->card_close = 1;
82  usb_autopm_put_interface(p->interface);
83  kref_put(&p->kref, poseidon_delete);
84  return 0;
85 }
86 
87 static int snd_pd_hw_capture_params(struct snd_pcm_substream *substream,
88  struct snd_pcm_hw_params *hw_params)
89 {
90  struct snd_pcm_runtime *runtime = substream->runtime;
91  unsigned int size;
92 
93  size = params_buffer_bytes(hw_params);
94  if (runtime->dma_area) {
95  if (runtime->dma_bytes > size)
96  return 0;
97  vfree(runtime->dma_area);
98  }
99  runtime->dma_area = vmalloc(size);
100  if (!runtime->dma_area)
101  return -ENOMEM;
102  else
103  runtime->dma_bytes = size;
104  return 0;
105 }
106 
107 static int audio_buf_free(struct poseidon *p)
108 {
109  struct poseidon_audio *pa = &p->audio;
110  int i;
111 
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);
116  logpm();
117  return 0;
118 }
119 
120 static int snd_pd_hw_capture_free(struct snd_pcm_substream *substream)
121 {
122  struct poseidon *p = snd_pcm_substream_chip(substream);
123 
124  logpm();
125  audio_buf_free(p);
126  return 0;
127 }
128 
129 static int snd_pd_prepare(struct snd_pcm_substream *substream)
130 {
131  return 0;
132 }
133 
134 #define AUDIO_TRAILER_SIZE (16)
135 static inline void handle_audio_data(struct urb *urb, int *period_elapsed)
136 {
137  struct poseidon_audio *pa = urb->context;
138  struct snd_pcm_runtime *runtime = pa->capture_pcm_substream->runtime;
139 
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;
144 
145  if (urb->actual_length == AUDIO_BUF_SIZE - 4)
146  len -= (AUDIO_TRAILER_SIZE / stride);
147 
148  /* do the copy */
149  if (oldptr + len >= runtime->buffer_size) {
150  unsigned int cnt = runtime->buffer_size - oldptr;
151 
152  memcpy(runtime->dma_area + oldptr * stride, cp, cnt * stride);
153  memcpy(runtime->dma_area, (cp + cnt * stride),
154  (len * stride - cnt * stride));
155  } else
156  memcpy(runtime->dma_area + oldptr * stride, cp, len * stride);
157 
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;
163 
164  pa->copied_position += (len);
165  if (pa->copied_position >= runtime->period_size) {
166  pa->copied_position -= runtime->period_size;
167  *period_elapsed = 1;
168  }
169  snd_pcm_stream_unlock(pa->capture_pcm_substream);
170 }
171 
172 static void complete_handler_audio(struct urb *urb)
173 {
174  struct poseidon_audio *pa = urb->context;
175  struct snd_pcm_substream *substream = pa->capture_pcm_substream;
176  int period_elapsed = 0;
177  int ret;
178 
179  if (1 == pa->card_close || pa->capture_stream != STREAM_ON)
180  return;
181 
182  if (urb->status != 0) {
183  /*if (urb->status == -ESHUTDOWN)*/
184  return;
185  }
186 
187  if (substream) {
188  if (urb->actual_length) {
189  handle_audio_data(urb, &period_elapsed);
190  if (period_elapsed)
191  snd_pcm_period_elapsed(substream);
192  }
193  }
194 
195  ret = usb_submit_urb(urb, GFP_ATOMIC);
196  if (ret < 0)
197  log("audio urb failed (errcod = %i)", ret);
198  return;
199 }
200 
201 static int fire_audio_urb(struct poseidon *p)
202 {
203  int i, ret = 0;
204  struct poseidon_audio *pa = &p->audio;
205 
206  alloc_bulk_urbs_generic(pa->urb_array, AUDIO_BUFS,
207  p->udev, AUDIO_EP,
209  complete_handler_audio, pa);
210 
211  for (i = 0; i < AUDIO_BUFS; i++) {
212  ret = usb_submit_urb(pa->urb_array[i], GFP_KERNEL);
213  if (ret)
214  log("urb err : %d", ret);
215  }
216  log();
217  return ret;
218 }
219 
220 static int snd_pd_capture_trigger(struct snd_pcm_substream *substream, int cmd)
221 {
222  struct poseidon *p = snd_pcm_substream_chip(substream);
223  struct poseidon_audio *pa = &p->audio;
224 
225  if (debug_mode)
226  log("cmd %d, audio stat : %d\n", cmd, pa->capture_stream);
227 
228  switch (cmd) {
231  if (pa->capture_stream == STREAM_ON)
232  return 0;
233 
234  pa->rcv_position = pa->copied_position = 0;
236 
237  if (in_hibernation(p))
238  return 0;
239  fire_audio_urb(p);
240  return 0;
241 
244  return 0;
247  return 0;
248  default:
249  return -EINVAL;
250  }
251 }
252 
253 static snd_pcm_uframes_t
254 snd_pd_capture_pointer(struct snd_pcm_substream *substream)
255 {
256  struct poseidon *p = snd_pcm_substream_chip(substream);
257  struct poseidon_audio *pa = &p->audio;
258  return pa->rcv_position;
259 }
260 
261 static struct page *snd_pcm_pd_get_page(struct snd_pcm_substream *subs,
262  unsigned long offset)
263 {
264  void *pageptr = subs->runtime->dma_area + offset;
265  return vmalloc_to_page(pageptr);
266 }
267 
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,
278 };
279 
280 #ifdef CONFIG_PM
281 int pm_alsa_suspend(struct poseidon *p)
282 {
283  logpm(p);
284  audio_buf_free(p);
285  return 0;
286 }
287 
288 int pm_alsa_resume(struct poseidon *p)
289 {
290  logpm(p);
291  fire_audio_urb(p);
292  return 0;
293 }
294 #endif
295 
297 {
298  struct poseidon_audio *pa = &p->audio;
299  struct snd_card *card;
300  struct snd_pcm *pcm;
301  int ret;
302 
303  ret = snd_card_create(-1, "Telegent", THIS_MODULE, 0, &card);
304  if (ret != 0)
305  return ret;
306 
307  ret = snd_pcm_new(card, "poseidon audio", 0, 0, 1, &pcm);
308  if (ret < 0) {
309  snd_card_free(card);
310  return ret;
311  }
312  snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_capture_ops);
313  pcm->info_flags = 0;
314  pcm->private_data = p;
315  strcpy(pcm->name, "poseidon audio capture");
316 
317  strcpy(card->driver, "ALSA driver");
318  strcpy(card->shortname, "poseidon Audio");
319  strcpy(card->longname, "poseidon ALSA Audio");
320 
321  if (snd_card_register(card)) {
322  snd_card_free(card);
323  return -ENOMEM;
324  }
325  pa->card = card;
326  return 0;
327 }
328 
330 {
331  struct poseidon_audio *pa = &p->audio;
332 
333  if (pa->card)
334  snd_card_free(pa->card);
335  return 0;
336 }