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