^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * US-X2Y AUDIO
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (c) 2002-2004 by Karsten Wiese
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * based on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * (Tentative) USB Audio Driver for ALSA
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Main and PCM part
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * Many codes borrowed from audio.c by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * Alan Cox (alan@lxorguk.ukuu.org.uk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * Thomas Sailer (sailer@ife.ee.ethz.ch)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/usb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/moduleparam.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <sound/core.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <sound/info.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <sound/pcm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <sound/pcm_params.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include "usx2y.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include "usbusx2y.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define USX2Y_NRPACKS 4 /* Default value used for nr of packs per urb.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) 1 to 4 have been tested ok on uhci.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) To use 3 on ohci, you'd need a patch:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) look for "0000425-linux-2.6.9-rc4-mm1_ohci-hcd.patch.gz" on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) "https://bugtrack.alsa-project.org/alsa-bug/bug_view_page.php?bug_id=0000425"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) .
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) 1, 2 and 4 work out of the box on ohci, if I recall correctly.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) Bigger is safer operation,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) smaller gives lower latencies.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define USX2Y_NRPACKS_VARIABLE y /* If your system works ok with this module's parameter
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) nrpacks set to 1, you might as well comment
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) this #define out, and thereby produce smaller, faster code.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) You'd also set USX2Y_NRPACKS to 1 then.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #ifdef USX2Y_NRPACKS_VARIABLE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) static int nrpacks = USX2Y_NRPACKS; /* number of packets per urb */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #define nr_of_packs() nrpacks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) module_param(nrpacks, int, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) MODULE_PARM_DESC(nrpacks, "Number of packets per URB.");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #define nr_of_packs() USX2Y_NRPACKS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) static int usx2y_urb_capt_retire(struct snd_usx2y_substream *subs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) struct urb *urb = subs->completed_urb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) unsigned char *cp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) int i, len, lens = 0, hwptr_done = subs->hwptr_done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) struct usx2ydev *usx2y = subs->usx2y;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) for (i = 0; i < nr_of_packs(); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) cp = (unsigned char*)urb->transfer_buffer + urb->iso_frame_desc[i].offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) if (urb->iso_frame_desc[i].status) { /* active? hmm, skip this */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) snd_printk(KERN_ERR "active frame status %i. "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) "Most probably some hardware problem.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) urb->iso_frame_desc[i].status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) return urb->iso_frame_desc[i].status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) len = urb->iso_frame_desc[i].actual_length / usx2y->stride;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) if (! len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) snd_printd("0 == len ERROR!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) /* copy a data chunk */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) if ((hwptr_done + len) > runtime->buffer_size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) int cnt = runtime->buffer_size - hwptr_done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) int blen = cnt * usx2y->stride;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) memcpy(runtime->dma_area + hwptr_done * usx2y->stride, cp, blen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) memcpy(runtime->dma_area, cp + blen, len * usx2y->stride - blen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) memcpy(runtime->dma_area + hwptr_done * usx2y->stride, cp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) len * usx2y->stride);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) lens += len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) if ((hwptr_done += len) >= runtime->buffer_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) hwptr_done -= runtime->buffer_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) subs->hwptr_done = hwptr_done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) subs->transfer_done += lens;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) /* update the pointer, call callback if necessary */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) if (subs->transfer_done >= runtime->period_size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) subs->transfer_done -= runtime->period_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) snd_pcm_period_elapsed(subs->pcm_substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) * prepare urb for playback data pipe
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) * we copy the data directly from the pcm buffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) * the current position to be copied is held in hwptr field.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) * since a urb can handle only a single linear buffer, if the total
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) * transferred area overflows the buffer boundary, we cannot send
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) * it directly from the buffer. thus the data is once copied to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) * a temporary buffer and urb points to that.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) static int usx2y_urb_play_prepare(struct snd_usx2y_substream *subs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) struct urb *cap_urb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) struct urb *urb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) int count, counts, pack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) struct usx2ydev *usx2y = subs->usx2y;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) for (pack = 0; pack < nr_of_packs(); pack++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) /* calculate the size of a packet */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) counts = cap_urb->iso_frame_desc[pack].actual_length / usx2y->stride;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) count += counts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) if (counts < 43 || counts > 50) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) snd_printk(KERN_ERR "should not be here with counts=%i\n", counts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) return -EPIPE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) /* set up descriptor */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) urb->iso_frame_desc[pack].offset = pack ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) urb->iso_frame_desc[pack - 1].offset +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) urb->iso_frame_desc[pack - 1].length :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) urb->iso_frame_desc[pack].length = cap_urb->iso_frame_desc[pack].actual_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) if (atomic_read(&subs->state) >= STATE_PRERUNNING)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) if (subs->hwptr + count > runtime->buffer_size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) /* err, the transferred area goes over buffer boundary.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) * copy the data to the temp buffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) int len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) len = runtime->buffer_size - subs->hwptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) urb->transfer_buffer = subs->tmpbuf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) memcpy(subs->tmpbuf, runtime->dma_area +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) subs->hwptr * usx2y->stride, len * usx2y->stride);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) memcpy(subs->tmpbuf + len * usx2y->stride,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) runtime->dma_area, (count - len) * usx2y->stride);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) subs->hwptr += count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) subs->hwptr -= runtime->buffer_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) /* set the buffer pointer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) urb->transfer_buffer = runtime->dma_area + subs->hwptr * usx2y->stride;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) if ((subs->hwptr += count) >= runtime->buffer_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) subs->hwptr -= runtime->buffer_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) urb->transfer_buffer = subs->tmpbuf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) urb->transfer_buffer_length = count * usx2y->stride;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) * process after playback data complete
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) * update the current position and call callback if a period is processed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) static void usx2y_urb_play_retire(struct snd_usx2y_substream *subs, struct urb *urb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) int len = urb->actual_length / subs->usx2y->stride;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) subs->transfer_done += len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) subs->hwptr_done += len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) if (subs->hwptr_done >= runtime->buffer_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) subs->hwptr_done -= runtime->buffer_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) if (subs->transfer_done >= runtime->period_size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) subs->transfer_done -= runtime->period_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) snd_pcm_period_elapsed(subs->pcm_substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) static int usx2y_urb_submit(struct snd_usx2y_substream *subs, struct urb *urb, int frame)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) if (!urb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) urb->start_frame = (frame + NRURBS * nr_of_packs()); // let hcd do rollover sanity checks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) urb->hcpriv = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) urb->dev = subs->usx2y->dev; /* we need to set this at each time */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) if ((err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) snd_printk(KERN_ERR "usb_submit_urb() returned %i\n", err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) static inline int usx2y_usbframe_complete(struct snd_usx2y_substream *capsubs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) struct snd_usx2y_substream *playbacksubs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) int frame)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) int err, state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) struct urb *urb = playbacksubs->completed_urb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) state = atomic_read(&playbacksubs->state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) if (NULL != urb) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) if (state == STATE_RUNNING)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) usx2y_urb_play_retire(playbacksubs, urb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) else if (state >= STATE_PRERUNNING)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) atomic_inc(&playbacksubs->state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) switch (state) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) case STATE_STARTING1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) urb = playbacksubs->urb[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) atomic_inc(&playbacksubs->state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) case STATE_STARTING2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) urb = playbacksubs->urb[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) atomic_inc(&playbacksubs->state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) if (urb) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) if ((err = usx2y_urb_play_prepare(playbacksubs, capsubs->completed_urb, urb)) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) (err = usx2y_urb_submit(playbacksubs, urb, frame))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) playbacksubs->completed_urb = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) state = atomic_read(&capsubs->state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) if (state >= STATE_PREPARED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) if (state == STATE_RUNNING) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) if ((err = usx2y_urb_capt_retire(capsubs)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) } else if (state >= STATE_PRERUNNING)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) atomic_inc(&capsubs->state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) if ((err = usx2y_urb_submit(capsubs, capsubs->completed_urb, frame)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) capsubs->completed_urb = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) static void usx2y_clients_stop(struct usx2ydev *usx2y)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) int s, u;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) for (s = 0; s < 4; s++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) struct snd_usx2y_substream *subs = usx2y->subs[s];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) if (subs) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) snd_printdd("%i %p state=%i\n", s, subs, atomic_read(&subs->state));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) atomic_set(&subs->state, STATE_STOPPED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) for (s = 0; s < 4; s++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) struct snd_usx2y_substream *subs = usx2y->subs[s];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) if (subs) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) if (atomic_read(&subs->state) >= STATE_PRERUNNING)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) snd_pcm_stop_xrun(subs->pcm_substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) for (u = 0; u < NRURBS; u++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) struct urb *urb = subs->urb[u];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) if (NULL != urb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) snd_printdd("%i status=%i start_frame=%i\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) u, urb->status, urb->start_frame);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) usx2y->prepare_subs = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) wake_up(&usx2y->prepare_wait_queue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) static void usx2y_error_urb_status(struct usx2ydev *usx2y,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) struct snd_usx2y_substream *subs, struct urb *urb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) snd_printk(KERN_ERR "ep=%i stalled with status=%i\n", subs->endpoint, urb->status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) urb->status = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) usx2y_clients_stop(usx2y);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) static void i_usx2y_urb_complete(struct urb *urb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) struct snd_usx2y_substream *subs = urb->context;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) struct usx2ydev *usx2y = subs->usx2y;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) if (unlikely(atomic_read(&subs->state) < STATE_PREPARED)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) snd_printdd("hcd_frame=%i ep=%i%s status=%i start_frame=%i\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) usb_get_current_frame_number(usx2y->dev),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) urb->status, urb->start_frame);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) if (unlikely(urb->status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) usx2y_error_urb_status(usx2y, subs, urb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) subs->completed_urb = urb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) struct snd_usx2y_substream *capsubs = usx2y->subs[SNDRV_PCM_STREAM_CAPTURE],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) *playbacksubs = usx2y->subs[SNDRV_PCM_STREAM_PLAYBACK];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) if (capsubs->completed_urb &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) atomic_read(&capsubs->state) >= STATE_PREPARED &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) (playbacksubs->completed_urb ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) atomic_read(&playbacksubs->state) < STATE_PREPARED)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) if (!usx2y_usbframe_complete(capsubs, playbacksubs, urb->start_frame))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) usx2y->wait_iso_frame += nr_of_packs();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) snd_printdd("\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) usx2y_clients_stop(usx2y);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) static void usx2y_urbs_set_complete(struct usx2ydev * usx2y,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) void (*complete)(struct urb *))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) int s, u;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) for (s = 0; s < 4; s++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) struct snd_usx2y_substream *subs = usx2y->subs[s];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) if (NULL != subs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) for (u = 0; u < NRURBS; u++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) struct urb * urb = subs->urb[u];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) if (NULL != urb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) urb->complete = complete;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) static void usx2y_subs_startup_finish(struct usx2ydev * usx2y)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) usx2y_urbs_set_complete(usx2y, i_usx2y_urb_complete);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) usx2y->prepare_subs = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) static void i_usx2y_subs_startup(struct urb *urb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) struct snd_usx2y_substream *subs = urb->context;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) struct usx2ydev *usx2y = subs->usx2y;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) struct snd_usx2y_substream *prepare_subs = usx2y->prepare_subs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) if (NULL != prepare_subs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) if (urb->start_frame == prepare_subs->urb[0]->start_frame) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) usx2y_subs_startup_finish(usx2y);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) atomic_inc(&prepare_subs->state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) wake_up(&usx2y->prepare_wait_queue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) i_usx2y_urb_complete(urb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) static void usx2y_subs_prepare(struct snd_usx2y_substream *subs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) snd_printdd("usx2y_substream_prepare(%p) ep=%i urb0=%p urb1=%p\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) subs, subs->endpoint, subs->urb[0], subs->urb[1]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) /* reset the pointer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) subs->hwptr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) subs->hwptr_done = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) subs->transfer_done = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) static void usx2y_urb_release(struct urb **urb, int free_tb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) if (*urb) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) usb_kill_urb(*urb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) if (free_tb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) kfree((*urb)->transfer_buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) usb_free_urb(*urb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) *urb = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) * release a substreams urbs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) static void usx2y_urbs_release(struct snd_usx2y_substream *subs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) snd_printdd("usx2y_urbs_release() %i\n", subs->endpoint);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) for (i = 0; i < NRURBS; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) usx2y_urb_release(subs->urb + i,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) subs != subs->usx2y->subs[SNDRV_PCM_STREAM_PLAYBACK]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) kfree(subs->tmpbuf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) subs->tmpbuf = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) * initialize a substream's urbs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) static int usx2y_urbs_allocate(struct snd_usx2y_substream *subs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) unsigned int pipe;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) int is_playback = subs == subs->usx2y->subs[SNDRV_PCM_STREAM_PLAYBACK];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) struct usb_device *dev = subs->usx2y->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) pipe = is_playback ? usb_sndisocpipe(dev, subs->endpoint) :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) usb_rcvisocpipe(dev, subs->endpoint);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) subs->maxpacksize = usb_maxpacket(dev, pipe, is_playback);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) if (!subs->maxpacksize)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) if (is_playback && NULL == subs->tmpbuf) { /* allocate a temporary buffer for playback */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) subs->tmpbuf = kcalloc(nr_of_packs(), subs->maxpacksize, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) if (!subs->tmpbuf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) /* allocate and initialize data urbs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) for (i = 0; i < NRURBS; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) struct urb **purb = subs->urb + i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) if (*purb) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) usb_kill_urb(*purb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) *purb = usb_alloc_urb(nr_of_packs(), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) if (NULL == *purb) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) usx2y_urbs_release(subs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) if (!is_playback && !(*purb)->transfer_buffer) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) /* allocate a capture buffer per urb */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) (*purb)->transfer_buffer =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) kmalloc_array(subs->maxpacksize,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) nr_of_packs(), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) if (NULL == (*purb)->transfer_buffer) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) usx2y_urbs_release(subs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) (*purb)->dev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) (*purb)->pipe = pipe;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) (*purb)->number_of_packets = nr_of_packs();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) (*purb)->context = subs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) (*purb)->interval = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) (*purb)->complete = i_usx2y_subs_startup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) static void usx2y_subs_startup(struct snd_usx2y_substream *subs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) struct usx2ydev *usx2y = subs->usx2y;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) usx2y->prepare_subs = subs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) subs->urb[0]->start_frame = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) wmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) usx2y_urbs_set_complete(usx2y, i_usx2y_subs_startup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) static int usx2y_urbs_start(struct snd_usx2y_substream *subs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) int i, err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) struct usx2ydev *usx2y = subs->usx2y;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) if ((err = usx2y_urbs_allocate(subs)) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) subs->completed_urb = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) for (i = 0; i < 4; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) struct snd_usx2y_substream *subs = usx2y->subs[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) if (subs != NULL && atomic_read(&subs->state) >= STATE_PREPARED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) goto start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) start:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) usx2y_subs_startup(subs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) for (i = 0; i < NRURBS; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) struct urb *urb = subs->urb[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) if (usb_pipein(urb->pipe)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) unsigned long pack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) if (0 == i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) atomic_set(&subs->state, STATE_STARTING3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) urb->dev = usx2y->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) for (pack = 0; pack < nr_of_packs(); pack++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) urb->iso_frame_desc[pack].offset = subs->maxpacksize * pack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) urb->iso_frame_desc[pack].length = subs->maxpacksize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) urb->transfer_buffer_length = subs->maxpacksize * nr_of_packs();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) if ((err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) snd_printk (KERN_ERR "cannot submit datapipe for urb %d, err = %d\n", i, err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) err = -EPIPE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) if (i == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) usx2y->wait_iso_frame = urb->start_frame;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) urb->transfer_flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) atomic_set(&subs->state, STATE_STARTING1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) wait_event(usx2y->prepare_wait_queue, NULL == usx2y->prepare_subs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) if (atomic_read(&subs->state) != STATE_PREPARED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) err = -EPIPE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) cleanup:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) usx2y_subs_startup_finish(usx2y);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) usx2y_clients_stop(usx2y); // something is completely wroong > stop evrything
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) * return the current pcm pointer. just return the hwptr_done value.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) static snd_pcm_uframes_t snd_usx2y_pcm_pointer(struct snd_pcm_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) struct snd_usx2y_substream *subs = substream->runtime->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) return subs->hwptr_done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) * start/stop substream
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) static int snd_usx2y_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) struct snd_usx2y_substream *subs = substream->runtime->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) switch (cmd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) case SNDRV_PCM_TRIGGER_START:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) snd_printdd("snd_usx2y_pcm_trigger(START)\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) if (atomic_read(&subs->state) == STATE_PREPARED &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) atomic_read(&subs->usx2y->subs[SNDRV_PCM_STREAM_CAPTURE]->state) >= STATE_PREPARED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) atomic_set(&subs->state, STATE_PRERUNNING);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) snd_printdd("\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) return -EPIPE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) case SNDRV_PCM_TRIGGER_STOP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) snd_printdd("snd_usx2y_pcm_trigger(STOP)\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) if (atomic_read(&subs->state) >= STATE_PRERUNNING)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) atomic_set(&subs->state, STATE_PREPARED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) * allocate a buffer, setup samplerate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) * so far we use a physically linear buffer although packetize transfer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) * doesn't need a continuous area.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) * if sg buffer is supported on the later version of alsa, we'll follow
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) * that.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) static const struct s_c2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) char c1, c2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) setrate_44100[] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) { 0x14, 0x08}, // this line sets 44100, well actually a little less
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) { 0x18, 0x40}, // only tascam / frontier design knows the further lines .......
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) { 0x18, 0x42},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) { 0x18, 0x45},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) { 0x18, 0x46},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) { 0x18, 0x48},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) { 0x18, 0x4A},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) { 0x18, 0x4C},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) { 0x18, 0x4E},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) { 0x18, 0x50},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) { 0x18, 0x52},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) { 0x18, 0x54},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) { 0x18, 0x56},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) { 0x18, 0x58},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) { 0x18, 0x5A},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) { 0x18, 0x5C},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) { 0x18, 0x5E},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) { 0x18, 0x60},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) { 0x18, 0x62},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) { 0x18, 0x64},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) { 0x18, 0x66},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) { 0x18, 0x68},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) { 0x18, 0x6A},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) { 0x18, 0x6C},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) { 0x18, 0x6E},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) { 0x18, 0x70},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) { 0x18, 0x72},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) { 0x18, 0x74},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) { 0x18, 0x76},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) { 0x18, 0x78},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) { 0x18, 0x7A},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) { 0x18, 0x7C},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) { 0x18, 0x7E}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) static const struct s_c2 setrate_48000[] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) { 0x14, 0x09}, // this line sets 48000, well actually a little less
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) { 0x18, 0x40}, // only tascam / frontier design knows the further lines .......
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) { 0x18, 0x42},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) { 0x18, 0x45},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) { 0x18, 0x46},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) { 0x18, 0x48},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) { 0x18, 0x4A},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) { 0x18, 0x4C},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) { 0x18, 0x4E},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) { 0x18, 0x50},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) { 0x18, 0x52},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) { 0x18, 0x54},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) { 0x18, 0x56},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) { 0x18, 0x58},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) { 0x18, 0x5A},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) { 0x18, 0x5C},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) { 0x18, 0x5E},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) { 0x18, 0x60},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) { 0x18, 0x62},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) { 0x18, 0x64},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) { 0x18, 0x66},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) { 0x18, 0x68},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) { 0x18, 0x6A},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) { 0x18, 0x6C},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) { 0x18, 0x6E},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) { 0x18, 0x70},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) { 0x18, 0x73},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) { 0x18, 0x74},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) { 0x18, 0x76},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) { 0x18, 0x78},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) { 0x18, 0x7A},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) { 0x18, 0x7C},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) { 0x18, 0x7E}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) #define NOOF_SETRATE_URBS ARRAY_SIZE(setrate_48000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) static void i_usx2y_04int(struct urb *urb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) struct usx2ydev *usx2y = urb->context;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) if (urb->status)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) snd_printk(KERN_ERR "snd_usx2y_04int() urb->status=%i\n", urb->status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) if (0 == --usx2y->us04->len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) wake_up(&usx2y->in04_wait_queue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) static int usx2y_rate_set(struct usx2ydev *usx2y, int rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) int err = 0, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) struct snd_usx2y_urb_seq *us = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) int *usbdata = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) const struct s_c2 *ra = rate == 48000 ? setrate_48000 : setrate_44100;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) if (usx2y->rate != rate) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) us = kzalloc(sizeof(*us) + sizeof(struct urb*) * NOOF_SETRATE_URBS, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) if (NULL == us) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) usbdata = kmalloc_array(NOOF_SETRATE_URBS, sizeof(int),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) if (NULL == usbdata) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) for (i = 0; i < NOOF_SETRATE_URBS; ++i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) if (NULL == (us->urb[i] = usb_alloc_urb(0, GFP_KERNEL))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) ((char*)(usbdata + i))[0] = ra[i].c1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) ((char*)(usbdata + i))[1] = ra[i].c2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) usb_fill_bulk_urb(us->urb[i], usx2y->dev, usb_sndbulkpipe(usx2y->dev, 4),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) usbdata + i, 2, i_usx2y_04int, usx2y);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) err = usb_urb_ep_type_check(us->urb[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) us->submitted = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) us->len = NOOF_SETRATE_URBS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) usx2y->us04 = us;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) wait_event_timeout(usx2y->in04_wait_queue, 0 == us->len, HZ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) usx2y->us04 = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) if (us->len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) err = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) cleanup:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) if (us) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) us->submitted = 2*NOOF_SETRATE_URBS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) for (i = 0; i < NOOF_SETRATE_URBS; ++i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) struct urb *urb = us->urb[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) if (!urb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) if (urb->status) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) if (!err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) err = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) usb_kill_urb(urb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) usb_free_urb(urb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) usx2y->us04 = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) kfree(usbdata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) kfree(us);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) if (!err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) usx2y->rate = rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) static int usx2y_format_set(struct usx2ydev *usx2y, snd_pcm_format_t format)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) int alternate, err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) struct list_head* p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) if (format == SNDRV_PCM_FORMAT_S24_3LE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) alternate = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) usx2y->stride = 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) alternate = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) usx2y->stride = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) list_for_each(p, &usx2y->midi_list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) snd_usbmidi_input_stop(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) usb_kill_urb(usx2y->in04_urb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) if ((err = usb_set_interface(usx2y->dev, 0, alternate))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) snd_printk(KERN_ERR "usb_set_interface error \n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) usx2y->in04_urb->dev = usx2y->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) err = usb_submit_urb(usx2y->in04_urb, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) list_for_each(p, &usx2y->midi_list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) snd_usbmidi_input_start(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) usx2y->format = format;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) usx2y->rate = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) static int snd_usx2y_pcm_hw_params(struct snd_pcm_substream *substream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) struct snd_pcm_hw_params *hw_params)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) int err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) unsigned int rate = params_rate(hw_params);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) snd_pcm_format_t format = params_format(hw_params);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) struct snd_card *card = substream->pstr->pcm->card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) struct usx2ydev *dev = usx2y(card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) mutex_lock(&usx2y(card)->pcm_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) snd_printdd("snd_usx2y_hw_params(%p, %p)\n", substream, hw_params);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) /* all pcm substreams off one usx2y have to operate at the same
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) * rate & format
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) for (i = 0; i < dev->pcm_devs * 2; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) struct snd_usx2y_substream *subs = dev->subs[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) struct snd_pcm_substream *test_substream;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) if (!subs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) test_substream = subs->pcm_substream;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) if (!test_substream || test_substream == substream ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) !test_substream->runtime)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) if ((test_substream->runtime->format &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) test_substream->runtime->format != format) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) (test_substream->runtime->rate &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) test_substream->runtime->rate != rate)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) err = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) mutex_unlock(&usx2y(card)->pcm_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) * free the buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) static int snd_usx2y_pcm_hw_free(struct snd_pcm_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) struct snd_pcm_runtime *runtime = substream->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) struct snd_usx2y_substream *subs = runtime->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) mutex_lock(&subs->usx2y->pcm_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) snd_printdd("snd_usx2y_hw_free(%p)\n", substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) struct snd_usx2y_substream *cap_subs = subs->usx2y->subs[SNDRV_PCM_STREAM_CAPTURE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) atomic_set(&subs->state, STATE_STOPPED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) usx2y_urbs_release(subs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) if (!cap_subs->pcm_substream ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) !cap_subs->pcm_substream->runtime ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) !cap_subs->pcm_substream->runtime->status ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) cap_subs->pcm_substream->runtime->status->state < SNDRV_PCM_STATE_PREPARED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) atomic_set(&cap_subs->state, STATE_STOPPED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) usx2y_urbs_release(cap_subs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) struct snd_usx2y_substream *playback_subs = subs->usx2y->subs[SNDRV_PCM_STREAM_PLAYBACK];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) if (atomic_read(&playback_subs->state) < STATE_PREPARED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) atomic_set(&subs->state, STATE_STOPPED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) usx2y_urbs_release(subs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) mutex_unlock(&subs->usx2y->pcm_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) * prepare callback
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) * set format and initialize urbs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) static int snd_usx2y_pcm_prepare(struct snd_pcm_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) struct snd_pcm_runtime *runtime = substream->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) struct snd_usx2y_substream *subs = runtime->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) struct usx2ydev *usx2y = subs->usx2y;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) struct snd_usx2y_substream *capsubs = subs->usx2y->subs[SNDRV_PCM_STREAM_CAPTURE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) int err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) snd_printdd("snd_usx2y_pcm_prepare(%p)\n", substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) mutex_lock(&usx2y->pcm_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) usx2y_subs_prepare(subs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) // Start hardware streams
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) // SyncStream first....
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) if (atomic_read(&capsubs->state) < STATE_PREPARED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) if (usx2y->format != runtime->format)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) if ((err = usx2y_format_set(usx2y, runtime->format)) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) goto up_prepare_mutex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) if (usx2y->rate != runtime->rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) if ((err = usx2y_rate_set(usx2y, runtime->rate)) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) goto up_prepare_mutex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) snd_printdd("starting capture pipe for %s\n", subs == capsubs ? "self" : "playpipe");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) if (0 > (err = usx2y_urbs_start(capsubs)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) goto up_prepare_mutex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) if (subs != capsubs && atomic_read(&subs->state) < STATE_PREPARED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) err = usx2y_urbs_start(subs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) up_prepare_mutex:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) mutex_unlock(&usx2y->pcm_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) static const struct snd_pcm_hardware snd_usx2y_2c =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) SNDRV_PCM_INFO_BLOCK_TRANSFER |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) SNDRV_PCM_INFO_MMAP_VALID |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) SNDRV_PCM_INFO_BATCH),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) .rate_min = 44100,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) .rate_max = 48000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) .channels_min = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) .channels_max = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) .buffer_bytes_max = (2*128*1024),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) .period_bytes_min = 64,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) .period_bytes_max = (128*1024),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) .periods_min = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) .periods_max = 1024,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) .fifo_size = 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) static int snd_usx2y_pcm_open(struct snd_pcm_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) struct snd_usx2y_substream *subs = ((struct snd_usx2y_substream **)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) snd_pcm_substream_chip(substream))[substream->stream];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) struct snd_pcm_runtime *runtime = substream->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) if (subs->usx2y->chip_status & USX2Y_STAT_CHIP_MMAP_PCM_URBS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) runtime->hw = snd_usx2y_2c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) runtime->private_data = subs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) subs->pcm_substream = substream;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 1000, 200000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) static int snd_usx2y_pcm_close(struct snd_pcm_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) struct snd_pcm_runtime *runtime = substream->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) struct snd_usx2y_substream *subs = runtime->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) subs->pcm_substream = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) static const struct snd_pcm_ops snd_usx2y_pcm_ops =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) .open = snd_usx2y_pcm_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) .close = snd_usx2y_pcm_close,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) .hw_params = snd_usx2y_pcm_hw_params,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) .hw_free = snd_usx2y_pcm_hw_free,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) .prepare = snd_usx2y_pcm_prepare,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) .trigger = snd_usx2y_pcm_trigger,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) .pointer = snd_usx2y_pcm_pointer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) * free a usb stream instance
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) static void usx2y_audio_stream_free(struct snd_usx2y_substream **usx2y_substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) int stream;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) for_each_pcm_streams(stream) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) kfree(usx2y_substream[stream]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) usx2y_substream[stream] = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) static void snd_usx2y_pcm_private_free(struct snd_pcm *pcm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) struct snd_usx2y_substream **usx2y_stream = pcm->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) if (usx2y_stream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) usx2y_audio_stream_free(usx2y_stream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) static int usx2y_audio_stream_new(struct snd_card *card, int playback_endpoint, int capture_endpoint)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) struct snd_pcm *pcm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) int err, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) struct snd_usx2y_substream **usx2y_substream =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) usx2y(card)->subs + 2 * usx2y(card)->pcm_devs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) for (i = playback_endpoint ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) i <= SNDRV_PCM_STREAM_CAPTURE; ++i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) usx2y_substream[i] = kzalloc(sizeof(struct snd_usx2y_substream), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) if (!usx2y_substream[i])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) usx2y_substream[i]->usx2y = usx2y(card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) if (playback_endpoint)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) usx2y_substream[SNDRV_PCM_STREAM_PLAYBACK]->endpoint = playback_endpoint;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) usx2y_substream[SNDRV_PCM_STREAM_CAPTURE]->endpoint = capture_endpoint;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) err = snd_pcm_new(card, NAME_ALLCAPS" Audio", usx2y(card)->pcm_devs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) playback_endpoint ? 1 : 0, 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) &pcm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) if (err < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) usx2y_audio_stream_free(usx2y_substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) if (playback_endpoint)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_usx2y_pcm_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usx2y_pcm_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) pcm->private_data = usx2y_substream;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) pcm->private_free = snd_usx2y_pcm_private_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) pcm->info_flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) sprintf(pcm->name, NAME_ALLCAPS" Audio #%d", usx2y(card)->pcm_devs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) if (playback_endpoint) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) SNDRV_DMA_TYPE_CONTINUOUS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) 64*1024, 128*1024);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) SNDRV_DMA_TYPE_CONTINUOUS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) 64*1024, 128*1024);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) usx2y(card)->pcm_devs++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) * create a chip instance and set its names.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) int usx2y_audio_create(struct snd_card *card)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) int err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) INIT_LIST_HEAD(&usx2y(card)->pcm_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) if (0 > (err = usx2y_audio_stream_new(card, 0xA, 0x8)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) if (le16_to_cpu(usx2y(card)->dev->descriptor.idProduct) == USB_ID_US428)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) if (0 > (err = usx2y_audio_stream_new(card, 0, 0xA)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) if (le16_to_cpu(usx2y(card)->dev->descriptor.idProduct) != USB_ID_US122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) err = usx2y_rate_set(usx2y(card), 44100); // Lets us428 recognize output-volume settings, disturbs us122.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) }