]> git.karo-electronics.de Git - mv-sheeva.git/blob - drivers/staging/line6/capture.c
Staging: line6: workaround for null pointer bug
[mv-sheeva.git] / drivers / staging / line6 / capture.c
1 /*
2  * Line6 Linux USB driver - 0.9.1beta
3  *
4  * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
5  *
6  *      This program is free software; you can redistribute it and/or
7  *      modify it under the terms of the GNU General Public License as
8  *      published by the Free Software Foundation, version 2.
9  *
10  */
11
12 #include <sound/core.h>
13 #include <sound/pcm.h>
14 #include <sound/pcm_params.h>
15
16 #include "audio.h"
17 #include "capture.h"
18 #include "driver.h"
19 #include "pcm.h"
20 #include "pod.h"
21
22 /*
23         Find a free URB and submit it.
24 */
25 static int submit_audio_in_urb(struct snd_line6_pcm *line6pcm)
26 {
27         int index;
28         unsigned long flags;
29         int i, urb_size;
30         int ret;
31         struct urb *urb_in;
32
33         spin_lock_irqsave(&line6pcm->lock_audio_in, flags);
34         index =
35             find_first_zero_bit(&line6pcm->active_urb_in, LINE6_ISO_BUFFERS);
36
37         if (index < 0 || index >= LINE6_ISO_BUFFERS) {
38                 spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags);
39                 dev_err(line6pcm->line6->ifcdev, "no free URB found\n");
40                 return -EINVAL;
41         }
42
43         urb_in = line6pcm->urb_audio_in[index];
44         urb_size = 0;
45
46         for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
47                 struct usb_iso_packet_descriptor *fin =
48                     &urb_in->iso_frame_desc[i];
49                 fin->offset = urb_size;
50                 fin->length = line6pcm->max_packet_size;
51                 urb_size += line6pcm->max_packet_size;
52         }
53
54         urb_in->transfer_buffer =
55             line6pcm->buffer_in +
56             index * LINE6_ISO_PACKETS * line6pcm->max_packet_size;
57         urb_in->transfer_buffer_length = urb_size;
58         urb_in->context = line6pcm;
59
60         ret = usb_submit_urb(urb_in, GFP_ATOMIC);
61
62         if (ret == 0)
63                 set_bit(index, &line6pcm->active_urb_in);
64         else
65                 dev_err(line6pcm->line6->ifcdev,
66                         "URB in #%d submission failed (%d)\n", index, ret);
67
68         spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags);
69         return 0;
70 }
71
72 /*
73         Submit all currently available capture URBs.
74 */
75 int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm)
76 {
77         int ret, i;
78
79         for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
80                 ret = submit_audio_in_urb(line6pcm);
81                 if (ret < 0)
82                         return ret;
83         }
84
85         return 0;
86 }
87
88 /*
89         Unlink all currently active capture URBs.
90 */
91 void line6_unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm)
92 {
93         unsigned int i;
94
95         for (i = LINE6_ISO_BUFFERS; i--;) {
96                 if (test_bit(i, &line6pcm->active_urb_in)) {
97                         if (!test_and_set_bit(i, &line6pcm->unlink_urb_in)) {
98                                 struct urb *u = line6pcm->urb_audio_in[i];
99                                 usb_unlink_urb(u);
100                         }
101                 }
102         }
103 }
104
105 /*
106         Wait until unlinking of all currently active capture URBs has been
107         finished.
108 */
109 static void wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm)
110 {
111         int timeout = HZ;
112         unsigned int i;
113         int alive;
114
115         do {
116                 alive = 0;
117                 for (i = LINE6_ISO_BUFFERS; i--;) {
118                         if (test_bit(i, &line6pcm->active_urb_in))
119                                 alive++;
120                 }
121                 if (!alive)
122                         break;
123                 set_current_state(TASK_UNINTERRUPTIBLE);
124                 schedule_timeout(1);
125         } while (--timeout > 0);
126         if (alive)
127                 snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive);
128 }
129
130 /*
131         Unlink all currently active capture URBs, and wait for finishing.
132 */
133 void line6_unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm)
134 {
135         line6_unlink_audio_in_urbs(line6pcm);
136         wait_clear_audio_in_urbs(line6pcm);
137 }
138
139 /*
140         Copy data into ALSA capture buffer.
141 */
142 void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, int fsize)
143 {
144         struct snd_pcm_substream *substream =
145             get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE);
146         struct snd_pcm_runtime *runtime = substream->runtime;
147         const int bytes_per_frame = line6pcm->properties->bytes_per_frame;
148         int frames = fsize / bytes_per_frame;
149
150         if (runtime == 0)
151                 return;
152
153         if (line6pcm->pos_in_done + frames > runtime->buffer_size) {
154                 /*
155                    The transferred area goes over buffer boundary,
156                    copy two separate chunks.
157                  */
158                 int len;
159                 len = runtime->buffer_size - line6pcm->pos_in_done;
160
161                 if (len > 0) {
162                         memcpy(runtime->dma_area +
163                                line6pcm->pos_in_done * bytes_per_frame, fbuf,
164                                len * bytes_per_frame);
165                         memcpy(runtime->dma_area, fbuf + len * bytes_per_frame,
166                                (frames - len) * bytes_per_frame);
167                 } else
168                         dev_err(line6pcm->line6->ifcdev, "driver bug: len = %d\n", len);        /* this is somewhat paranoid */
169         } else {
170                 /* copy single chunk */
171                 memcpy(runtime->dma_area +
172                        line6pcm->pos_in_done * bytes_per_frame, fbuf, fsize);
173         }
174
175         if ((line6pcm->pos_in_done += frames) >= runtime->buffer_size)
176                 line6pcm->pos_in_done -= runtime->buffer_size;
177 }
178
179 void line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length)
180 {
181         struct snd_pcm_substream *substream =
182             get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE);
183
184         if ((line6pcm->bytes_in += length) >= line6pcm->period_in) {
185                 line6pcm->bytes_in %= line6pcm->period_in;
186                 snd_pcm_period_elapsed(substream);
187         }
188 }
189
190 /*
191   Callback for completed capture URB.
192 */
193 static void audio_in_callback(struct urb *urb)
194 {
195         int i, index, length = 0, shutdown = 0;
196         unsigned long flags;
197
198         struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context;
199
200         line6pcm->last_frame_in = urb->start_frame;
201
202         /* find index of URB */
203         for (index = 0; index < LINE6_ISO_BUFFERS; ++index)
204                 if (urb == line6pcm->urb_audio_in[index])
205                         break;
206
207 #ifdef CONFIG_LINE6_USB_DUMP_PCM
208         for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
209                 struct usb_iso_packet_descriptor *fout =
210                     &urb->iso_frame_desc[i];
211                 line6_write_hexdump(line6pcm->line6, 'C',
212                                     urb->transfer_buffer + fout->offset,
213                                     fout->length);
214         }
215 #endif
216
217         spin_lock_irqsave(&line6pcm->lock_audio_in, flags);
218
219         for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
220                 char *fbuf;
221                 int fsize;
222                 struct usb_iso_packet_descriptor *fin = &urb->iso_frame_desc[i];
223
224                 if (fin->status == -EXDEV) {
225                         shutdown = 1;
226                         break;
227                 }
228
229                 fbuf = urb->transfer_buffer + fin->offset;
230                 fsize = fin->actual_length;
231
232                 if (fsize > line6pcm->max_packet_size) {
233                         dev_err(line6pcm->line6->ifcdev,
234                                 "driver and/or device bug: packet too large (%d > %d)\n",
235                                 fsize, line6pcm->max_packet_size);
236                 }
237
238                 length += fsize;
239
240                 /* the following assumes LINE6_ISO_PACKETS == 1: */
241 #if LINE6_BACKUP_MONITOR_SIGNAL
242                 memcpy(line6pcm->prev_fbuf, fbuf, fsize);
243 #else
244                 line6pcm->prev_fbuf = fbuf;
245 #endif
246                 line6pcm->prev_fsize = fsize;
247
248 #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
249                 if (!(line6pcm->flags & MASK_PCM_IMPULSE))
250 #endif
251                         if (test_bit(BIT_PCM_ALSA_CAPTURE, &line6pcm->flags)
252                             && (fsize > 0))
253                                 line6_capture_copy(line6pcm, fbuf, fsize);
254         }
255
256         clear_bit(index, &line6pcm->active_urb_in);
257
258         if (test_and_clear_bit(index, &line6pcm->unlink_urb_in))
259                 shutdown = 1;
260
261         spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags);
262
263         if (!shutdown) {
264                 submit_audio_in_urb(line6pcm);
265
266 #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
267                 if (!(line6pcm->flags & MASK_PCM_IMPULSE))
268 #endif
269                         if (test_bit(BIT_PCM_ALSA_CAPTURE, &line6pcm->flags))
270                                 line6_capture_check_period(line6pcm, length);
271         }
272 }
273
274 /* open capture callback */
275 static int snd_line6_capture_open(struct snd_pcm_substream *substream)
276 {
277         int err;
278         struct snd_pcm_runtime *runtime = substream->runtime;
279         struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
280
281         err = snd_pcm_hw_constraint_ratdens(runtime, 0,
282                                             SNDRV_PCM_HW_PARAM_RATE,
283                                             (&line6pcm->
284                                              properties->snd_line6_rates));
285         if (err < 0)
286                 return err;
287
288         runtime->hw = line6pcm->properties->snd_line6_capture_hw;
289         return 0;
290 }
291
292 /* close capture callback */
293 static int snd_line6_capture_close(struct snd_pcm_substream *substream)
294 {
295         return 0;
296 }
297
298 /* hw_params capture callback */
299 static int snd_line6_capture_hw_params(struct snd_pcm_substream *substream,
300                                        struct snd_pcm_hw_params *hw_params)
301 {
302         int ret;
303         struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
304
305         /* -- Florian Demski [FD] */
306         /* don't ask me why, but this fixes the bug on my machine */
307         if (line6pcm == NULL) {
308                 if (substream->pcm == NULL)
309                         return -ENOMEM;
310                 if (substream->pcm->private_data == NULL)
311                         return -ENOMEM;
312                 substream->private_data = substream->pcm->private_data;
313                 line6pcm = snd_pcm_substream_chip(substream);
314         }
315         /* -- [FD] end */
316
317         ret = snd_pcm_lib_malloc_pages(substream,
318                                        params_buffer_bytes(hw_params));
319         if (ret < 0)
320                 return ret;
321
322         line6pcm->period_in = params_period_bytes(hw_params);
323         return 0;
324 }
325
326 /* hw_free capture callback */
327 static int snd_line6_capture_hw_free(struct snd_pcm_substream *substream)
328 {
329         return snd_pcm_lib_free_pages(substream);
330 }
331
332 /* trigger callback */
333 int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd)
334 {
335         int err;
336
337         switch (cmd) {
338         case SNDRV_PCM_TRIGGER_START:
339 #ifdef CONFIG_PM
340         case SNDRV_PCM_TRIGGER_RESUME:
341 #endif
342                 err = line6_pcm_start(line6pcm, MASK_PCM_ALSA_CAPTURE);
343
344                 if (err < 0)
345                         return err;
346
347                 break;
348
349         case SNDRV_PCM_TRIGGER_STOP:
350 #ifdef CONFIG_PM
351         case SNDRV_PCM_TRIGGER_SUSPEND:
352 #endif
353                 err = line6_pcm_stop(line6pcm, MASK_PCM_ALSA_CAPTURE);
354
355                 if (err < 0)
356                         return err;
357
358                 break;
359
360         default:
361                 return -EINVAL;
362         }
363
364         return 0;
365 }
366
367 /* capture pointer callback */
368 static snd_pcm_uframes_t
369 snd_line6_capture_pointer(struct snd_pcm_substream *substream)
370 {
371         struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
372         return line6pcm->pos_in_done;
373 }
374
375 /* capture operators */
376 struct snd_pcm_ops snd_line6_capture_ops = {
377         .open = snd_line6_capture_open,
378         .close = snd_line6_capture_close,
379         .ioctl = snd_pcm_lib_ioctl,
380         .hw_params = snd_line6_capture_hw_params,
381         .hw_free = snd_line6_capture_hw_free,
382         .prepare = snd_line6_prepare,
383         .trigger = snd_line6_trigger,
384         .pointer = snd_line6_capture_pointer,
385 };
386
387 int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm)
388 {
389         int i;
390
391         /* create audio URBs and fill in constant values: */
392         for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
393                 struct urb *urb;
394
395                 /* URB for audio in: */
396                 urb = line6pcm->urb_audio_in[i] =
397                     usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL);
398
399                 if (urb == NULL) {
400                         dev_err(line6pcm->line6->ifcdev, "Out of memory\n");
401                         return -ENOMEM;
402                 }
403
404                 urb->dev = line6pcm->line6->usbdev;
405                 urb->pipe =
406                     usb_rcvisocpipe(line6pcm->line6->usbdev,
407                                     line6pcm->ep_audio_read &
408                                     USB_ENDPOINT_NUMBER_MASK);
409                 urb->transfer_flags = URB_ISO_ASAP;
410                 urb->start_frame = -1;
411                 urb->number_of_packets = LINE6_ISO_PACKETS;
412                 urb->interval = LINE6_ISO_INTERVAL;
413                 urb->error_count = 0;
414                 urb->complete = audio_in_callback;
415         }
416
417         return 0;
418 }