Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Line 6 Linux USB driver
0004  *
0005  * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
0006  */
0007 
0008 #include <linux/slab.h>
0009 #include <sound/core.h>
0010 #include <sound/pcm.h>
0011 #include <sound/pcm_params.h>
0012 
0013 #include "capture.h"
0014 #include "driver.h"
0015 #include "pcm.h"
0016 
0017 /*
0018     Find a free URB and submit it.
0019     must be called in line6pcm->in.lock context
0020 */
0021 static int submit_audio_in_urb(struct snd_line6_pcm *line6pcm)
0022 {
0023     int index;
0024     int i, urb_size;
0025     int ret;
0026     struct urb *urb_in;
0027 
0028     index = find_first_zero_bit(&line6pcm->in.active_urbs,
0029                     line6pcm->line6->iso_buffers);
0030 
0031     if (index < 0 || index >= line6pcm->line6->iso_buffers) {
0032         dev_err(line6pcm->line6->ifcdev, "no free URB found\n");
0033         return -EINVAL;
0034     }
0035 
0036     urb_in = line6pcm->in.urbs[index];
0037     urb_size = 0;
0038 
0039     for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
0040         struct usb_iso_packet_descriptor *fin =
0041             &urb_in->iso_frame_desc[i];
0042         fin->offset = urb_size;
0043         fin->length = line6pcm->max_packet_size_in;
0044         urb_size += line6pcm->max_packet_size_in;
0045     }
0046 
0047     urb_in->transfer_buffer =
0048         line6pcm->in.buffer +
0049         index * LINE6_ISO_PACKETS * line6pcm->max_packet_size_in;
0050     urb_in->transfer_buffer_length = urb_size;
0051     urb_in->context = line6pcm;
0052 
0053     ret = usb_submit_urb(urb_in, GFP_ATOMIC);
0054 
0055     if (ret == 0)
0056         set_bit(index, &line6pcm->in.active_urbs);
0057     else
0058         dev_err(line6pcm->line6->ifcdev,
0059             "URB in #%d submission failed (%d)\n", index, ret);
0060 
0061     return 0;
0062 }
0063 
0064 /*
0065     Submit all currently available capture URBs.
0066     must be called in line6pcm->in.lock context
0067 */
0068 int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm)
0069 {
0070     int ret = 0, i;
0071 
0072     for (i = 0; i < line6pcm->line6->iso_buffers; ++i) {
0073         ret = submit_audio_in_urb(line6pcm);
0074         if (ret < 0)
0075             break;
0076     }
0077 
0078     return ret;
0079 }
0080 
0081 /*
0082     Copy data into ALSA capture buffer.
0083 */
0084 void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, int fsize)
0085 {
0086     struct snd_pcm_substream *substream =
0087         get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE);
0088     struct snd_pcm_runtime *runtime = substream->runtime;
0089     const int bytes_per_frame =
0090         line6pcm->properties->bytes_per_channel *
0091         line6pcm->properties->capture_hw.channels_max;
0092     int frames = fsize / bytes_per_frame;
0093 
0094     if (runtime == NULL)
0095         return;
0096 
0097     if (line6pcm->in.pos_done + frames > runtime->buffer_size) {
0098         /*
0099            The transferred area goes over buffer boundary,
0100            copy two separate chunks.
0101          */
0102         int len;
0103 
0104         len = runtime->buffer_size - line6pcm->in.pos_done;
0105 
0106         if (len > 0) {
0107             memcpy(runtime->dma_area +
0108                    line6pcm->in.pos_done * bytes_per_frame, fbuf,
0109                    len * bytes_per_frame);
0110             memcpy(runtime->dma_area, fbuf + len * bytes_per_frame,
0111                    (frames - len) * bytes_per_frame);
0112         } else {
0113             /* this is somewhat paranoid */
0114             dev_err(line6pcm->line6->ifcdev,
0115                 "driver bug: len = %d\n", len);
0116         }
0117     } else {
0118         /* copy single chunk */
0119         memcpy(runtime->dma_area +
0120                line6pcm->in.pos_done * bytes_per_frame, fbuf, fsize);
0121     }
0122 
0123     line6pcm->in.pos_done += frames;
0124     if (line6pcm->in.pos_done >= runtime->buffer_size)
0125         line6pcm->in.pos_done -= runtime->buffer_size;
0126 }
0127 
0128 void line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length)
0129 {
0130     struct snd_pcm_substream *substream =
0131         get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE);
0132 
0133     line6pcm->in.bytes += length;
0134     if (line6pcm->in.bytes >= line6pcm->in.period) {
0135         line6pcm->in.bytes %= line6pcm->in.period;
0136         spin_unlock(&line6pcm->in.lock);
0137         snd_pcm_period_elapsed(substream);
0138         spin_lock(&line6pcm->in.lock);
0139     }
0140 }
0141 
0142 /*
0143  * Callback for completed capture URB.
0144  */
0145 static void audio_in_callback(struct urb *urb)
0146 {
0147     int i, index, length = 0, shutdown = 0;
0148     unsigned long flags;
0149 
0150     struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context;
0151 
0152     line6pcm->in.last_frame = urb->start_frame;
0153 
0154     /* find index of URB */
0155     for (index = 0; index < line6pcm->line6->iso_buffers; ++index)
0156         if (urb == line6pcm->in.urbs[index])
0157             break;
0158 
0159     spin_lock_irqsave(&line6pcm->in.lock, flags);
0160 
0161     for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
0162         char *fbuf;
0163         int fsize;
0164         struct usb_iso_packet_descriptor *fin = &urb->iso_frame_desc[i];
0165 
0166         if (fin->status == -EXDEV) {
0167             shutdown = 1;
0168             break;
0169         }
0170 
0171         fbuf = urb->transfer_buffer + fin->offset;
0172         fsize = fin->actual_length;
0173 
0174         if (fsize > line6pcm->max_packet_size_in) {
0175             dev_err(line6pcm->line6->ifcdev,
0176                 "driver and/or device bug: packet too large (%d > %d)\n",
0177                 fsize, line6pcm->max_packet_size_in);
0178         }
0179 
0180         length += fsize;
0181 
0182         BUILD_BUG_ON_MSG(LINE6_ISO_PACKETS != 1,
0183             "The following code assumes LINE6_ISO_PACKETS == 1");
0184         /* TODO:
0185          * Also, if iso_buffers != 2, the prev frame is almost random at
0186          * playback side.
0187          * This needs to be redesigned. It should be "stable", but we may
0188          * experience sync problems on such high-speed configs.
0189          */
0190 
0191         line6pcm->prev_fbuf = fbuf;
0192         line6pcm->prev_fsize = fsize /
0193             (line6pcm->properties->bytes_per_channel *
0194             line6pcm->properties->capture_hw.channels_max);
0195 
0196         if (!test_bit(LINE6_STREAM_IMPULSE, &line6pcm->in.running) &&
0197             test_bit(LINE6_STREAM_PCM, &line6pcm->in.running) &&
0198             fsize > 0)
0199             line6_capture_copy(line6pcm, fbuf, fsize);
0200     }
0201 
0202     clear_bit(index, &line6pcm->in.active_urbs);
0203 
0204     if (test_and_clear_bit(index, &line6pcm->in.unlink_urbs))
0205         shutdown = 1;
0206 
0207     if (!shutdown) {
0208         submit_audio_in_urb(line6pcm);
0209 
0210         if (!test_bit(LINE6_STREAM_IMPULSE, &line6pcm->in.running) &&
0211             test_bit(LINE6_STREAM_PCM, &line6pcm->in.running))
0212             line6_capture_check_period(line6pcm, length);
0213     }
0214 
0215     spin_unlock_irqrestore(&line6pcm->in.lock, flags);
0216 }
0217 
0218 /* open capture callback */
0219 static int snd_line6_capture_open(struct snd_pcm_substream *substream)
0220 {
0221     int err;
0222     struct snd_pcm_runtime *runtime = substream->runtime;
0223     struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
0224 
0225     err = snd_pcm_hw_constraint_ratdens(runtime, 0,
0226                         SNDRV_PCM_HW_PARAM_RATE,
0227                         &line6pcm->properties->rates);
0228     if (err < 0)
0229         return err;
0230 
0231     line6_pcm_acquire(line6pcm, LINE6_STREAM_CAPTURE_HELPER, false);
0232 
0233     runtime->hw = line6pcm->properties->capture_hw;
0234     return 0;
0235 }
0236 
0237 /* close capture callback */
0238 static int snd_line6_capture_close(struct snd_pcm_substream *substream)
0239 {
0240     struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
0241 
0242     line6_pcm_release(line6pcm, LINE6_STREAM_CAPTURE_HELPER);
0243     return 0;
0244 }
0245 
0246 /* capture operators */
0247 const struct snd_pcm_ops snd_line6_capture_ops = {
0248     .open = snd_line6_capture_open,
0249     .close = snd_line6_capture_close,
0250     .hw_params = snd_line6_hw_params,
0251     .hw_free = snd_line6_hw_free,
0252     .prepare = snd_line6_prepare,
0253     .trigger = snd_line6_trigger,
0254     .pointer = snd_line6_pointer,
0255 };
0256 
0257 int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm)
0258 {
0259     struct usb_line6 *line6 = line6pcm->line6;
0260     int i;
0261 
0262     line6pcm->in.urbs = kcalloc(line6->iso_buffers, sizeof(struct urb *),
0263                     GFP_KERNEL);
0264     if (line6pcm->in.urbs == NULL)
0265         return -ENOMEM;
0266 
0267     /* create audio URBs and fill in constant values: */
0268     for (i = 0; i < line6->iso_buffers; ++i) {
0269         struct urb *urb;
0270 
0271         /* URB for audio in: */
0272         urb = line6pcm->in.urbs[i] =
0273             usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL);
0274 
0275         if (urb == NULL)
0276             return -ENOMEM;
0277 
0278         urb->dev = line6->usbdev;
0279         urb->pipe =
0280             usb_rcvisocpipe(line6->usbdev,
0281                     line6->properties->ep_audio_r &
0282                     USB_ENDPOINT_NUMBER_MASK);
0283         urb->transfer_flags = URB_ISO_ASAP;
0284         urb->start_frame = -1;
0285         urb->number_of_packets = LINE6_ISO_PACKETS;
0286         urb->interval = LINE6_ISO_INTERVAL;
0287         urb->error_count = 0;
0288         urb->complete = audio_in_callback;
0289         if (usb_urb_ep_type_check(urb))
0290             return -EINVAL;
0291     }
0292 
0293     return 0;
0294 }