Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^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)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5) /* USX2Y "rawusb" aka hwdep_pcm implementation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  Its usb's unableness to atomically handle power of 2 period sized data chuncs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8)  at standard samplerates,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9)  what led to this part of the usx2y module: 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10)  It provides the alsa kernel half of the usx2y-alsa-jack driver pair.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11)  The pair uses a hardware dependent alsa-device for mmaped pcm transport.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12)  Advantage achieved:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13)          The usb_hc moves pcm data from/into memory via DMA.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14)          That memory is mmaped by jack's usx2y driver.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15)          Jack's usx2y driver is the first/last to read/write pcm data.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16)          Read/write is a combination of power of 2 period shaping and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17)          float/int conversation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18)          Compared to mainline alsa/jack we leave out power of 2 period shaping inside
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19)          snd-usb-usx2y which needs memcpy() and additional buffers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20)          As a side effect possible unwanted pcm-data coruption resulting of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21)          standard alsa's snd-usb-usx2y period shaping scheme falls away.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22)          Result is sane jack operation at buffering schemes down to 128frames,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23)          2 periods.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24)          plain usx2y alsa mode is able to achieve 64frames, 4periods, but only at the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25)          cost of easier triggered i.e. aeolus xruns (128 or 256frames,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26)          2periods works but is useless cause of crackling).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28)  This is a first "proof of concept" implementation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29)  Later, functionalities should migrate to more appropriate places:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30)  Userland:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31)  - The jackd could mmap its float-pcm buffers directly from alsa-lib.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32)  - alsa-lib could provide power of 2 period sized shaping combined with int/float
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33)    conversation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34)    Currently the usx2y jack driver provides above 2 services.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35)  Kernel:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36)  - rawusb dma pcm buffer transport should go to snd-usb-lib, so also snd-usb-audio
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37)    devices can use it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38)    Currently rawusb dma pcm buffer transport (this file) is only available to snd-usb-usx2y. 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) #include <linux/gfp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) #include "usbusx2yaudio.c"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) #if defined(USX2Y_NRPACKS_VARIABLE) || USX2Y_NRPACKS == 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) #include <sound/hwdep.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) static int usx2y_usbpcm_urb_capt_retire(struct snd_usx2y_substream *subs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 	struct urb	*urb = subs->completed_urb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 	struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 	int 		i, lens = 0, hwptr_done = subs->hwptr_done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 	struct usx2ydev	*usx2y = subs->usx2y;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 	if (0 > usx2y->hwdep_pcm_shm->capture_iso_start) { //FIXME
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 		int head = usx2y->hwdep_pcm_shm->captured_iso_head + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 		if (head >= ARRAY_SIZE(usx2y->hwdep_pcm_shm->captured_iso))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 			head = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 		usx2y->hwdep_pcm_shm->capture_iso_start = head;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) 		snd_printdd("cap start %i\n", head);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 	for (i = 0; i < nr_of_packs(); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 		if (urb->iso_frame_desc[i].status) { /* active? hmm, skip this */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 			snd_printk(KERN_ERR "active frame status %i. Most probably some hardware problem.\n", urb->iso_frame_desc[i].status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 			return urb->iso_frame_desc[i].status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 		lens += urb->iso_frame_desc[i].actual_length / usx2y->stride;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 	if ((hwptr_done += lens) >= runtime->buffer_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 		hwptr_done -= runtime->buffer_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 	subs->hwptr_done = hwptr_done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 	subs->transfer_done += lens;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 	/* update the pointer, call callback if necessary */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 	if (subs->transfer_done >= runtime->period_size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 		subs->transfer_done -= runtime->period_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 		snd_pcm_period_elapsed(subs->pcm_substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) static inline int usx2y_iso_frames_per_buffer(struct snd_pcm_runtime *runtime,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 					      struct usx2ydev * usx2y)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) 	return (runtime->buffer_size * 1000) / usx2y->rate + 1;	//FIXME: so far only correct period_size == 2^x ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89)  * prepare urb for playback data pipe
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91)  * we copy the data directly from the pcm buffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92)  * the current position to be copied is held in hwptr field.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93)  * since a urb can handle only a single linear buffer, if the total
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94)  * transferred area overflows the buffer boundary, we cannot send
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95)  * it directly from the buffer.  thus the data is once copied to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96)  * a temporary buffer and urb points to that.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) static int usx2y_hwdep_urb_play_prepare(struct snd_usx2y_substream *subs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 					struct urb *urb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 	int count, counts, pack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 	struct usx2ydev *usx2y = subs->usx2y;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 	struct snd_usx2y_hwdep_pcm_shm *shm = usx2y->hwdep_pcm_shm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 	struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 	if (0 > shm->playback_iso_start) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 		shm->playback_iso_start = shm->captured_iso_head -
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 			usx2y_iso_frames_per_buffer(runtime, usx2y);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 		if (0 > shm->playback_iso_start)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 			shm->playback_iso_start += ARRAY_SIZE(shm->captured_iso);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 		shm->playback_iso_head = shm->playback_iso_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 	count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 	for (pack = 0; pack < nr_of_packs(); pack++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 		/* calculate the size of a packet */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 		counts = shm->captured_iso[shm->playback_iso_head].length / usx2y->stride;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 		if (counts < 43 || counts > 50) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 			snd_printk(KERN_ERR "should not be here with counts=%i\n", counts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 			return -EPIPE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 		/* set up descriptor */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 		urb->iso_frame_desc[pack].offset = shm->captured_iso[shm->playback_iso_head].offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 		urb->iso_frame_desc[pack].length = shm->captured_iso[shm->playback_iso_head].length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 		if (atomic_read(&subs->state) != STATE_RUNNING)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 			memset((char *)urb->transfer_buffer + urb->iso_frame_desc[pack].offset, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 			       urb->iso_frame_desc[pack].length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 		if (++shm->playback_iso_head >= ARRAY_SIZE(shm->captured_iso))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 			shm->playback_iso_head = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 		count += counts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 	urb->transfer_buffer_length = count * usx2y->stride;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) static inline void usx2y_usbpcm_urb_capt_iso_advance(struct snd_usx2y_substream *subs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 						     struct urb *urb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 	int pack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 	for (pack = 0; pack < nr_of_packs(); ++pack) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 		struct usb_iso_packet_descriptor *desc = urb->iso_frame_desc + pack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 		if (NULL != subs) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 			struct snd_usx2y_hwdep_pcm_shm *shm = subs->usx2y->hwdep_pcm_shm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 			int head = shm->captured_iso_head + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 			if (head >= ARRAY_SIZE(shm->captured_iso))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 				head = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 			shm->captured_iso[head].frame = urb->start_frame + pack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 			shm->captured_iso[head].offset = desc->offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 			shm->captured_iso[head].length = desc->actual_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 			shm->captured_iso_head = head;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 			shm->captured_iso_frames++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 		if ((desc->offset += desc->length * NRURBS*nr_of_packs()) +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 		    desc->length >= SSS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 			desc->offset -= (SSS - desc->length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) static inline int usx2y_usbpcm_usbframe_complete(struct snd_usx2y_substream *capsubs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 						 struct snd_usx2y_substream *capsubs2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 						 struct snd_usx2y_substream *playbacksubs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 						 int frame)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 	int err, state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 	struct urb *urb = playbacksubs->completed_urb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 	state = atomic_read(&playbacksubs->state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 	if (NULL != urb) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 		if (state == STATE_RUNNING)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 			usx2y_urb_play_retire(playbacksubs, urb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 		else if (state >= STATE_PRERUNNING)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 			atomic_inc(&playbacksubs->state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 		switch (state) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 		case STATE_STARTING1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 			urb = playbacksubs->urb[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 			atomic_inc(&playbacksubs->state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 		case STATE_STARTING2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 			urb = playbacksubs->urb[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 			atomic_inc(&playbacksubs->state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 	if (urb) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 		if ((err = usx2y_hwdep_urb_play_prepare(playbacksubs, urb)) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 		    (err = usx2y_urb_submit(playbacksubs, urb, frame))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 			return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) 	
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 	playbacksubs->completed_urb = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 	state = atomic_read(&capsubs->state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) 	if (state >= STATE_PREPARED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 		if (state == STATE_RUNNING) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) 			if ((err = usx2y_usbpcm_urb_capt_retire(capsubs)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) 				return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) 		} else if (state >= STATE_PRERUNNING)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) 			atomic_inc(&capsubs->state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) 		usx2y_usbpcm_urb_capt_iso_advance(capsubs, capsubs->completed_urb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) 		if (NULL != capsubs2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) 			usx2y_usbpcm_urb_capt_iso_advance(NULL, capsubs2->completed_urb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) 		if ((err = usx2y_urb_submit(capsubs, capsubs->completed_urb, frame)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) 			return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) 		if (NULL != capsubs2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) 			if ((err = usx2y_urb_submit(capsubs2, capsubs2->completed_urb, frame)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) 				return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 	capsubs->completed_urb = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 	if (NULL != capsubs2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) 		capsubs2->completed_urb = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) static void i_usx2y_usbpcm_urb_complete(struct urb *urb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) 	struct snd_usx2y_substream *subs = urb->context;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) 	struct usx2ydev *usx2y = subs->usx2y;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) 	struct snd_usx2y_substream *capsubs, *capsubs2, *playbacksubs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) 	if (unlikely(atomic_read(&subs->state) < STATE_PREPARED)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) 		snd_printdd("hcd_frame=%i ep=%i%s status=%i start_frame=%i\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) 			    usb_get_current_frame_number(usx2y->dev),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) 			    subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) 			    urb->status, urb->start_frame);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) 	if (unlikely(urb->status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) 		usx2y_error_urb_status(usx2y, subs, urb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) 	subs->completed_urb = urb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) 	capsubs = usx2y->subs[SNDRV_PCM_STREAM_CAPTURE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 	capsubs2 = usx2y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) 	playbacksubs = usx2y->subs[SNDRV_PCM_STREAM_PLAYBACK];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) 	if (capsubs->completed_urb && atomic_read(&capsubs->state) >= STATE_PREPARED &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 	    (NULL == capsubs2 || capsubs2->completed_urb) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) 	    (playbacksubs->completed_urb || atomic_read(&playbacksubs->state) < STATE_PREPARED)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 		if (!usx2y_usbpcm_usbframe_complete(capsubs, capsubs2, playbacksubs, urb->start_frame))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) 			usx2y->wait_iso_frame += nr_of_packs();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) 		else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) 			snd_printdd("\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) 			usx2y_clients_stop(usx2y);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) static void usx2y_hwdep_urb_release(struct urb **urb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 	usb_kill_urb(*urb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) 	usb_free_urb(*urb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) 	*urb = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)  * release a substream
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) static void usx2y_usbpcm_urbs_release(struct snd_usx2y_substream *subs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) 	int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) 	snd_printdd("snd_usx2y_urbs_release() %i\n", subs->endpoint);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) 	for (i = 0; i < NRURBS; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) 		usx2y_hwdep_urb_release(subs->urb + i);
^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) static void usx2y_usbpcm_subs_startup_finish(struct usx2ydev * usx2y)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) 	usx2y_urbs_set_complete(usx2y, i_usx2y_usbpcm_urb_complete);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) 	usx2y->prepare_subs = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) static void i_usx2y_usbpcm_subs_startup(struct urb *urb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) 	struct snd_usx2y_substream *subs = urb->context;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) 	struct usx2ydev *usx2y = subs->usx2y;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) 	struct snd_usx2y_substream *prepare_subs = usx2y->prepare_subs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) 	if (NULL != prepare_subs &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) 	    urb->start_frame == prepare_subs->urb[0]->start_frame) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) 		atomic_inc(&prepare_subs->state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) 		if (prepare_subs == usx2y->subs[SNDRV_PCM_STREAM_CAPTURE]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) 			struct snd_usx2y_substream *cap_subs2 = usx2y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) 			if (cap_subs2 != NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) 				atomic_inc(&cap_subs2->state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) 		usx2y_usbpcm_subs_startup_finish(usx2y);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) 		wake_up(&usx2y->prepare_wait_queue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) 	i_usx2y_usbpcm_urb_complete(urb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)  * initialize a substream's urbs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) static int usx2y_usbpcm_urbs_allocate(struct snd_usx2y_substream *subs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) 	int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) 	unsigned int pipe;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) 	int is_playback = subs == subs->usx2y->subs[SNDRV_PCM_STREAM_PLAYBACK];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) 	struct usb_device *dev = subs->usx2y->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) 	pipe = is_playback ? usb_sndisocpipe(dev, subs->endpoint) :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) 			usb_rcvisocpipe(dev, subs->endpoint);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) 	subs->maxpacksize = usb_maxpacket(dev, pipe, is_playback);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) 	if (!subs->maxpacksize)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) 	/* allocate and initialize data urbs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) 	for (i = 0; i < NRURBS; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) 		struct urb **purb = subs->urb + i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) 		if (*purb) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) 			usb_kill_urb(*purb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) 		*purb = usb_alloc_urb(nr_of_packs(), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) 		if (NULL == *purb) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) 			usx2y_usbpcm_urbs_release(subs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) 			return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) 		(*purb)->transfer_buffer = is_playback ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) 			subs->usx2y->hwdep_pcm_shm->playback : (
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) 				subs->endpoint == 0x8 ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) 				subs->usx2y->hwdep_pcm_shm->capture0x8 :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) 				subs->usx2y->hwdep_pcm_shm->capture0xA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) 		(*purb)->dev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) 		(*purb)->pipe = pipe;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) 		(*purb)->number_of_packets = nr_of_packs();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) 		(*purb)->context = subs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) 		(*purb)->interval = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) 		(*purb)->complete = i_usx2y_usbpcm_subs_startup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342)  * free the buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) static int snd_usx2y_usbpcm_hw_free(struct snd_pcm_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) 	struct snd_pcm_runtime *runtime = substream->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) 	struct snd_usx2y_substream *subs = runtime->private_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) 		*cap_subs2 = subs->usx2y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) 	mutex_lock(&subs->usx2y->pcm_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) 	snd_printdd("snd_usx2y_usbpcm_hw_free(%p)\n", substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) 	if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) 		struct snd_usx2y_substream *cap_subs = subs->usx2y->subs[SNDRV_PCM_STREAM_CAPTURE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) 		atomic_set(&subs->state, STATE_STOPPED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) 		usx2y_usbpcm_urbs_release(subs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) 		if (!cap_subs->pcm_substream ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) 		    !cap_subs->pcm_substream->runtime ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) 		    !cap_subs->pcm_substream->runtime->status ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) 		    cap_subs->pcm_substream->runtime->status->state < SNDRV_PCM_STATE_PREPARED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) 			atomic_set(&cap_subs->state, STATE_STOPPED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) 			if (NULL != cap_subs2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) 				atomic_set(&cap_subs2->state, STATE_STOPPED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) 			usx2y_usbpcm_urbs_release(cap_subs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) 			if (NULL != cap_subs2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) 				usx2y_usbpcm_urbs_release(cap_subs2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) 		struct snd_usx2y_substream *playback_subs = subs->usx2y->subs[SNDRV_PCM_STREAM_PLAYBACK];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) 		if (atomic_read(&playback_subs->state) < STATE_PREPARED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) 			atomic_set(&subs->state, STATE_STOPPED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) 			if (NULL != cap_subs2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) 				atomic_set(&cap_subs2->state, STATE_STOPPED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) 			usx2y_usbpcm_urbs_release(subs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) 			if (NULL != cap_subs2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) 				usx2y_usbpcm_urbs_release(cap_subs2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) 	mutex_unlock(&subs->usx2y->pcm_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) static void usx2y_usbpcm_subs_startup(struct snd_usx2y_substream *subs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) 	struct usx2ydev * usx2y = subs->usx2y;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) 	usx2y->prepare_subs = subs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) 	subs->urb[0]->start_frame = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) 	smp_wmb();	// Make sure above modifications are seen by i_usx2y_subs_startup()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) 	usx2y_urbs_set_complete(usx2y, i_usx2y_usbpcm_subs_startup);
^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) static int usx2y_usbpcm_urbs_start(struct snd_usx2y_substream *subs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) 	int	p, u, err,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) 		stream = subs->pcm_substream->stream;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) 	struct usx2ydev *usx2y = subs->usx2y;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) 	if (SNDRV_PCM_STREAM_CAPTURE == stream) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) 		usx2y->hwdep_pcm_shm->captured_iso_head = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) 		usx2y->hwdep_pcm_shm->captured_iso_frames = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) 	for (p = 0; 3 >= (stream + p); p += 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) 		struct snd_usx2y_substream *subs = usx2y->subs[stream + p];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) 		if (subs != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) 			if ((err = usx2y_usbpcm_urbs_allocate(subs)) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) 				return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) 			subs->completed_urb = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) 	for (p = 0; p < 4; p++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) 		struct snd_usx2y_substream *subs = usx2y->subs[p];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) 		if (subs != NULL && atomic_read(&subs->state) >= STATE_PREPARED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) 			goto start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417)  start:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) 	usx2y_usbpcm_subs_startup(subs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) 	for (u = 0; u < NRURBS; u++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) 		for (p = 0; 3 >= (stream + p); p += 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) 			struct snd_usx2y_substream *subs = usx2y->subs[stream + p];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) 			if (subs != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) 				struct urb *urb = subs->urb[u];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) 				if (usb_pipein(urb->pipe)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) 					unsigned long pack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) 					if (0 == u)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) 						atomic_set(&subs->state, STATE_STARTING3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) 					urb->dev = usx2y->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) 					for (pack = 0; pack < nr_of_packs(); pack++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) 						urb->iso_frame_desc[pack].offset = subs->maxpacksize * (pack + u * nr_of_packs());
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) 						urb->iso_frame_desc[pack].length = subs->maxpacksize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) 					}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) 					urb->transfer_buffer_length = subs->maxpacksize * nr_of_packs(); 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) 					if ((err = usb_submit_urb(urb, GFP_KERNEL)) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) 						snd_printk (KERN_ERR "cannot usb_submit_urb() for urb %d, err = %d\n", u, err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) 						err = -EPIPE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) 						goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) 					}  else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) 						snd_printdd("%i\n", urb->start_frame);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) 						if (u == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) 							usx2y->wait_iso_frame = urb->start_frame;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) 					}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) 					urb->transfer_flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) 				} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) 					atomic_set(&subs->state, STATE_STARTING1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) 					break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) 				}			
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) 	err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) 	wait_event(usx2y->prepare_wait_queue, NULL == usx2y->prepare_subs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) 	if (atomic_read(&subs->state) != STATE_PREPARED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) 		err = -EPIPE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) 		
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456)  cleanup:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) 	if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) 		usx2y_subs_startup_finish(usx2y);	// Call it now
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) 		usx2y_clients_stop(usx2y);		// something is completely wroong > stop evrything			
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) 	return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)  * prepare callback
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467)  * set format and initialize urbs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) static int snd_usx2y_usbpcm_prepare(struct snd_pcm_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) 	struct snd_pcm_runtime *runtime = substream->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) 	struct snd_usx2y_substream *subs = runtime->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) 	struct usx2ydev *usx2y = subs->usx2y;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) 	struct snd_usx2y_substream *capsubs = subs->usx2y->subs[SNDRV_PCM_STREAM_CAPTURE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) 	int err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) 	snd_printdd("snd_usx2y_pcm_prepare(%p)\n", substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) 	if (NULL == usx2y->hwdep_pcm_shm) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) 		usx2y->hwdep_pcm_shm = alloc_pages_exact(sizeof(struct snd_usx2y_hwdep_pcm_shm),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) 							 GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) 		if (!usx2y->hwdep_pcm_shm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) 			return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) 		memset(usx2y->hwdep_pcm_shm, 0, sizeof(struct snd_usx2y_hwdep_pcm_shm));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) 	mutex_lock(&usx2y->pcm_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) 	usx2y_subs_prepare(subs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) // Start hardware streams
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) // SyncStream first....
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) 	if (atomic_read(&capsubs->state) < STATE_PREPARED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) 		if (usx2y->format != runtime->format)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) 			if ((err = usx2y_format_set(usx2y, runtime->format)) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) 				goto up_prepare_mutex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) 		if (usx2y->rate != runtime->rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) 			if ((err = usx2y_rate_set(usx2y, runtime->rate)) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) 				goto up_prepare_mutex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) 		snd_printdd("starting capture pipe for %s\n", subs == capsubs ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) 			    "self" : "playpipe");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) 		if (0 > (err = usx2y_usbpcm_urbs_start(capsubs)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) 			goto up_prepare_mutex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) 	if (subs != capsubs) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) 		usx2y->hwdep_pcm_shm->playback_iso_start = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) 		if (atomic_read(&subs->state) < STATE_PREPARED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) 			while (usx2y_iso_frames_per_buffer(runtime, usx2y) >
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) 			       usx2y->hwdep_pcm_shm->captured_iso_frames) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) 				snd_printdd("Wait: iso_frames_per_buffer=%i,"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) 					    "captured_iso_frames=%i\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) 					    usx2y_iso_frames_per_buffer(runtime, usx2y),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) 					    usx2y->hwdep_pcm_shm->captured_iso_frames);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) 				if (msleep_interruptible(10)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) 					err = -ERESTARTSYS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) 					goto up_prepare_mutex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) 				}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) 			} 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) 			if (0 > (err = usx2y_usbpcm_urbs_start(subs)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) 				goto up_prepare_mutex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) 		snd_printdd("Ready: iso_frames_per_buffer=%i,captured_iso_frames=%i\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) 			    usx2y_iso_frames_per_buffer(runtime, usx2y),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) 			    usx2y->hwdep_pcm_shm->captured_iso_frames);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) 	} else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) 		usx2y->hwdep_pcm_shm->capture_iso_start = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526)  up_prepare_mutex:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) 	mutex_unlock(&usx2y->pcm_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) 	return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) static const struct snd_pcm_hardware snd_usx2y_4c =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) 				 SNDRV_PCM_INFO_MMAP_VALID),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) 	.formats =                 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) 	.rates =                   SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) 	.rate_min =                44100,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) 	.rate_max =                48000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) 	.channels_min =            2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) 	.channels_max =            4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) 	.buffer_bytes_max =	(2*128*1024),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) 	.period_bytes_min =	64,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) 	.period_bytes_max =	(128*1024),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) 	.periods_min =		2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) 	.periods_max =		1024,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) 	.fifo_size =              0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) static int snd_usx2y_usbpcm_open(struct snd_pcm_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) 	struct snd_usx2y_substream	*subs = ((struct snd_usx2y_substream **)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) 					 snd_pcm_substream_chip(substream))[substream->stream];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) 	struct snd_pcm_runtime	*runtime = substream->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) 	if (!(subs->usx2y->chip_status & USX2Y_STAT_CHIP_MMAP_PCM_URBS))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) 		return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) 	runtime->hw = SNDRV_PCM_STREAM_PLAYBACK == substream->stream ? snd_usx2y_2c :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) 		(subs->usx2y->subs[3] ? snd_usx2y_4c : snd_usx2y_2c);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) 	runtime->private_data = subs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) 	subs->pcm_substream = substream;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) 	snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 1000, 200000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) static int snd_usx2y_usbpcm_close(struct snd_pcm_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) 	struct snd_pcm_runtime *runtime = substream->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) 	struct snd_usx2y_substream *subs = runtime->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) 	subs->pcm_substream = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) static const struct snd_pcm_ops snd_usx2y_usbpcm_ops =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) 	.open =		snd_usx2y_usbpcm_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) 	.close =	snd_usx2y_usbpcm_close,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) 	.hw_params =	snd_usx2y_pcm_hw_params,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) 	.hw_free =	snd_usx2y_usbpcm_hw_free,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) 	.prepare =	snd_usx2y_usbpcm_prepare,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) 	.trigger =	snd_usx2y_pcm_trigger,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) 	.pointer =	snd_usx2y_pcm_pointer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) static int usx2y_pcms_busy_check(struct snd_card *card)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) 	struct usx2ydev	*dev = usx2y(card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) 	int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) 	for (i = 0; i < dev->pcm_devs * 2; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) 		struct snd_usx2y_substream *subs = dev->subs[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) 		if (subs && subs->pcm_substream &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) 		    SUBSTREAM_BUSY(subs->pcm_substream))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) 			return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) static int snd_usx2y_hwdep_pcm_open(struct snd_hwdep *hw, struct file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) 	struct snd_card *card = hw->card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) 	int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) 	mutex_lock(&usx2y(card)->pcm_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) 	err = usx2y_pcms_busy_check(card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) 	if (!err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) 		usx2y(card)->chip_status |= USX2Y_STAT_CHIP_MMAP_PCM_URBS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) 	mutex_unlock(&usx2y(card)->pcm_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) 	return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) static int snd_usx2y_hwdep_pcm_release(struct snd_hwdep *hw, struct file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) 	struct snd_card *card = hw->card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) 	int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) 	mutex_lock(&usx2y(card)->pcm_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) 	err = usx2y_pcms_busy_check(card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) 	if (!err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) 		usx2y(hw->card)->chip_status &= ~USX2Y_STAT_CHIP_MMAP_PCM_URBS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) 	mutex_unlock(&usx2y(card)->pcm_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) 	return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) static void snd_usx2y_hwdep_pcm_vm_open(struct vm_area_struct *area)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) static void snd_usx2y_hwdep_pcm_vm_close(struct vm_area_struct *area)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) static vm_fault_t snd_usx2y_hwdep_pcm_vm_fault(struct vm_fault *vmf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) 	unsigned long offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) 	void *vaddr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) 	offset = vmf->pgoff << PAGE_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) 	vaddr = (char *)((struct usx2ydev *)vmf->vma->vm_private_data)->hwdep_pcm_shm + offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) 	vmf->page = virt_to_page(vaddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) 	get_page(vmf->page);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) static const struct vm_operations_struct snd_usx2y_hwdep_pcm_vm_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) 	.open = snd_usx2y_hwdep_pcm_vm_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) 	.close = snd_usx2y_hwdep_pcm_vm_close,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) 	.fault = snd_usx2y_hwdep_pcm_vm_fault,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) static int snd_usx2y_hwdep_pcm_mmap(struct snd_hwdep * hw, struct file *filp, struct vm_area_struct *area)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) 	unsigned long	size = (unsigned long)(area->vm_end - area->vm_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) 	struct usx2ydev	*usx2y = hw->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) 	if (!(usx2y->chip_status & USX2Y_STAT_CHIP_INIT))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) 		return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) 	/* if userspace tries to mmap beyond end of our buffer, fail */ 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) 	if (size > PAGE_ALIGN(sizeof(struct snd_usx2y_hwdep_pcm_shm))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) 		snd_printd("%lu > %lu\n", size, (unsigned long)sizeof(struct snd_usx2y_hwdep_pcm_shm)); 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) 	if (!usx2y->hwdep_pcm_shm) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) 		return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) 	area->vm_ops = &snd_usx2y_hwdep_pcm_vm_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) 	area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) 	area->vm_private_data = hw->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) static void snd_usx2y_hwdep_pcm_private_free(struct snd_hwdep *hwdep)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) 	struct usx2ydev *usx2y = hwdep->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) 	if (NULL != usx2y->hwdep_pcm_shm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) 		free_pages_exact(usx2y->hwdep_pcm_shm, sizeof(struct snd_usx2y_hwdep_pcm_shm));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) int usx2y_hwdep_pcm_new(struct snd_card *card)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) 	int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) 	struct snd_hwdep *hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) 	struct snd_pcm *pcm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) 	struct usb_device *dev = usx2y(card)->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) 	if (1 != nr_of_packs())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) 	if ((err = snd_hwdep_new(card, SND_USX2Y_USBPCM_ID, 1, &hw)) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) 		return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) 	hw->iface = SNDRV_HWDEP_IFACE_USX2Y_PCM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) 	hw->private_data = usx2y(card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) 	hw->private_free = snd_usx2y_hwdep_pcm_private_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) 	hw->ops.open = snd_usx2y_hwdep_pcm_open;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) 	hw->ops.release = snd_usx2y_hwdep_pcm_release;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) 	hw->ops.mmap = snd_usx2y_hwdep_pcm_mmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) 	hw->exclusive = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) 	sprintf(hw->name, "/dev/bus/usb/%03d/%03d/hwdeppcm", dev->bus->busnum, dev->devnum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) 	err = snd_pcm_new(card, NAME_ALLCAPS" hwdep Audio", 2, 1, 1, &pcm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) 	if (err < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) 		return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_usx2y_usbpcm_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usx2y_usbpcm_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) 	pcm->private_data = usx2y(card)->subs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) 	pcm->info_flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) 	sprintf(pcm->name, NAME_ALLCAPS" hwdep Audio");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) 	snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) 				   SNDRV_DMA_TYPE_CONTINUOUS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) 				   NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) 				   64*1024, 128*1024);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) 	snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) 				   SNDRV_DMA_TYPE_CONTINUOUS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) 				   NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) 				   64*1024, 128*1024);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) int usx2y_hwdep_pcm_new(struct snd_card *card)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) #endif