brintos

brintos / linux-shallow public Read only

0
0
Text · 15.5 KiB · d4dbbc4 Raw
608 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Line 6 Linux USB driver4 *5 * Copyright (C) 2004-2010 Markus Grabner (line6@grabner-graz.at)6 */7 8#include <linux/slab.h>9#include <linux/export.h>10#include <sound/core.h>11#include <sound/control.h>12#include <sound/pcm.h>13#include <sound/pcm_params.h>14 15#include "capture.h"16#include "driver.h"17#include "playback.h"18 19/* impulse response volume controls */20static int snd_line6_impulse_volume_info(struct snd_kcontrol *kcontrol,21					 struct snd_ctl_elem_info *uinfo)22{23	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;24	uinfo->count = 1;25	uinfo->value.integer.min = 0;26	uinfo->value.integer.max = 255;27	return 0;28}29 30static int snd_line6_impulse_volume_get(struct snd_kcontrol *kcontrol,31					struct snd_ctl_elem_value *ucontrol)32{33	struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);34 35	ucontrol->value.integer.value[0] = line6pcm->impulse_volume;36	return 0;37}38 39static int snd_line6_impulse_volume_put(struct snd_kcontrol *kcontrol,40					struct snd_ctl_elem_value *ucontrol)41{42	struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);43	int value = ucontrol->value.integer.value[0];44	int err;45 46	if (line6pcm->impulse_volume == value)47		return 0;48 49	line6pcm->impulse_volume = value;50	if (value > 0) {51		err = line6_pcm_acquire(line6pcm, LINE6_STREAM_IMPULSE, true);52		if (err < 0) {53			line6pcm->impulse_volume = 0;54			return err;55		}56	} else {57		line6_pcm_release(line6pcm, LINE6_STREAM_IMPULSE);58	}59	return 1;60}61 62/* impulse response period controls */63static int snd_line6_impulse_period_info(struct snd_kcontrol *kcontrol,64					 struct snd_ctl_elem_info *uinfo)65{66	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;67	uinfo->count = 1;68	uinfo->value.integer.min = 0;69	uinfo->value.integer.max = 2000;70	return 0;71}72 73static int snd_line6_impulse_period_get(struct snd_kcontrol *kcontrol,74					struct snd_ctl_elem_value *ucontrol)75{76	struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);77 78	ucontrol->value.integer.value[0] = line6pcm->impulse_period;79	return 0;80}81 82static int snd_line6_impulse_period_put(struct snd_kcontrol *kcontrol,83					struct snd_ctl_elem_value *ucontrol)84{85	struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);86	int value = ucontrol->value.integer.value[0];87 88	if (line6pcm->impulse_period == value)89		return 0;90 91	line6pcm->impulse_period = value;92	return 1;93}94 95/*96	Unlink all currently active URBs.97*/98static void line6_unlink_audio_urbs(struct snd_line6_pcm *line6pcm,99				    struct line6_pcm_stream *pcms)100{101	int i;102 103	for (i = 0; i < line6pcm->line6->iso_buffers; i++) {104		if (test_bit(i, &pcms->active_urbs)) {105			if (!test_and_set_bit(i, &pcms->unlink_urbs))106				usb_unlink_urb(pcms->urbs[i]);107		}108	}109}110 111/*112	Wait until unlinking of all currently active URBs has been finished.113*/114static void line6_wait_clear_audio_urbs(struct snd_line6_pcm *line6pcm,115					struct line6_pcm_stream *pcms)116{117	int timeout = HZ;118	int i;119	int alive;120 121	do {122		alive = 0;123		for (i = 0; i < line6pcm->line6->iso_buffers; i++) {124			if (test_bit(i, &pcms->active_urbs))125				alive++;126		}127		if (!alive)128			break;129		set_current_state(TASK_UNINTERRUPTIBLE);130		schedule_timeout(1);131	} while (--timeout > 0);132	if (alive)133		dev_err(line6pcm->line6->ifcdev,134			"timeout: still %d active urbs..\n", alive);135}136 137static inline struct line6_pcm_stream *138get_stream(struct snd_line6_pcm *line6pcm, int direction)139{140	return (direction == SNDRV_PCM_STREAM_PLAYBACK) ?141		&line6pcm->out : &line6pcm->in;142}143 144/* allocate a buffer if not opened yet;145 * call this in line6pcm.state_mutex146 */147static int line6_buffer_acquire(struct snd_line6_pcm *line6pcm,148				struct line6_pcm_stream *pstr, int direction, int type)149{150	const int pkt_size =151		(direction == SNDRV_PCM_STREAM_PLAYBACK) ?152			line6pcm->max_packet_size_out :153			line6pcm->max_packet_size_in;154 155	/* Invoked multiple times in a row so allocate once only */156	if (!test_and_set_bit(type, &pstr->opened) && !pstr->buffer) {157		pstr->buffer =158			kmalloc(array3_size(line6pcm->line6->iso_buffers,159					    LINE6_ISO_PACKETS, pkt_size),160				GFP_KERNEL);161		if (!pstr->buffer)162			return -ENOMEM;163	}164	return 0;165}166 167/* free a buffer if all streams are closed;168 * call this in line6pcm.state_mutex169 */170static void line6_buffer_release(struct snd_line6_pcm *line6pcm,171				 struct line6_pcm_stream *pstr, int type)172{173	clear_bit(type, &pstr->opened);174	if (!pstr->opened) {175		line6_wait_clear_audio_urbs(line6pcm, pstr);176		kfree(pstr->buffer);177		pstr->buffer = NULL;178	}179}180 181/* start a PCM stream */182static int line6_stream_start(struct snd_line6_pcm *line6pcm, int direction,183			      int type)184{185	unsigned long flags;186	struct line6_pcm_stream *pstr = get_stream(line6pcm, direction);187	int ret = 0;188 189	spin_lock_irqsave(&pstr->lock, flags);190	if (!test_and_set_bit(type, &pstr->running) &&191	    !(pstr->active_urbs || pstr->unlink_urbs)) {192		pstr->count = 0;193		/* Submit all currently available URBs */194		if (direction == SNDRV_PCM_STREAM_PLAYBACK)195			ret = line6_submit_audio_out_all_urbs(line6pcm);196		else197			ret = line6_submit_audio_in_all_urbs(line6pcm);198	}199 200	if (ret < 0)201		clear_bit(type, &pstr->running);202	spin_unlock_irqrestore(&pstr->lock, flags);203	return ret;204}205 206/* stop a PCM stream; this doesn't sync with the unlinked URBs */207static void line6_stream_stop(struct snd_line6_pcm *line6pcm, int direction,208			  int type)209{210	unsigned long flags;211	struct line6_pcm_stream *pstr = get_stream(line6pcm, direction);212 213	spin_lock_irqsave(&pstr->lock, flags);214	clear_bit(type, &pstr->running);215	if (!pstr->running) {216		spin_unlock_irqrestore(&pstr->lock, flags);217		line6_unlink_audio_urbs(line6pcm, pstr);218		spin_lock_irqsave(&pstr->lock, flags);219		if (direction == SNDRV_PCM_STREAM_CAPTURE) {220			line6pcm->prev_fbuf = NULL;221			line6pcm->prev_fsize = 0;222		}223	}224	spin_unlock_irqrestore(&pstr->lock, flags);225}226 227/* common PCM trigger callback */228int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd)229{230	struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);231	struct snd_pcm_substream *s;232	int err;233 234	clear_bit(LINE6_FLAG_PREPARED, &line6pcm->flags);235 236	snd_pcm_group_for_each_entry(s, substream) {237		if (s->pcm->card != substream->pcm->card)238			continue;239 240		switch (cmd) {241		case SNDRV_PCM_TRIGGER_START:242		case SNDRV_PCM_TRIGGER_RESUME:243			if (s->stream == SNDRV_PCM_STREAM_CAPTURE &&244				(line6pcm->line6->properties->capabilities &245					LINE6_CAP_IN_NEEDS_OUT)) {246				err = line6_stream_start(line6pcm, SNDRV_PCM_STREAM_PLAYBACK,247						 LINE6_STREAM_CAPTURE_HELPER);248				if (err < 0)249					return err;250			}251			err = line6_stream_start(line6pcm, s->stream,252						 LINE6_STREAM_PCM);253			if (err < 0)254				return err;255			break;256 257		case SNDRV_PCM_TRIGGER_STOP:258		case SNDRV_PCM_TRIGGER_SUSPEND:259			if (s->stream == SNDRV_PCM_STREAM_CAPTURE &&260				(line6pcm->line6->properties->capabilities &261					LINE6_CAP_IN_NEEDS_OUT)) {262				line6_stream_stop(line6pcm, SNDRV_PCM_STREAM_PLAYBACK,263					  LINE6_STREAM_CAPTURE_HELPER);264			}265			line6_stream_stop(line6pcm, s->stream,266					  LINE6_STREAM_PCM);267			break;268 269		case SNDRV_PCM_TRIGGER_PAUSE_PUSH:270			if (s->stream != SNDRV_PCM_STREAM_PLAYBACK)271				return -EINVAL;272			set_bit(LINE6_FLAG_PAUSE_PLAYBACK, &line6pcm->flags);273			break;274 275		case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:276			if (s->stream != SNDRV_PCM_STREAM_PLAYBACK)277				return -EINVAL;278			clear_bit(LINE6_FLAG_PAUSE_PLAYBACK, &line6pcm->flags);279			break;280 281		default:282			return -EINVAL;283		}284	}285 286	return 0;287}288 289/* common PCM pointer callback */290snd_pcm_uframes_t snd_line6_pointer(struct snd_pcm_substream *substream)291{292	struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);293	struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream);294 295	return pstr->pos_done;296}297 298/* Acquire and optionally start duplex streams:299 * type is either LINE6_STREAM_IMPULSE or LINE6_STREAM_MONITOR300 */301int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int type, bool start)302{303	struct line6_pcm_stream *pstr;304	int ret = 0, dir;305 306	/* TODO: We should assert SNDRV_PCM_STREAM_PLAYBACK/CAPTURE == 0/1 */307	mutex_lock(&line6pcm->state_mutex);308	for (dir = 0; dir < 2; dir++) {309		pstr = get_stream(line6pcm, dir);310		ret = line6_buffer_acquire(line6pcm, pstr, dir, type);311		if (ret < 0)312			goto error;313		if (!pstr->running)314			line6_wait_clear_audio_urbs(line6pcm, pstr);315	}316	if (start) {317		for (dir = 0; dir < 2; dir++) {318			ret = line6_stream_start(line6pcm, dir, type);319			if (ret < 0)320				goto error;321		}322	}323 error:324	mutex_unlock(&line6pcm->state_mutex);325	if (ret < 0)326		line6_pcm_release(line6pcm, type);327	return ret;328}329EXPORT_SYMBOL_GPL(line6_pcm_acquire);330 331/* Stop and release duplex streams */332void line6_pcm_release(struct snd_line6_pcm *line6pcm, int type)333{334	struct line6_pcm_stream *pstr;335	int dir;336 337	mutex_lock(&line6pcm->state_mutex);338	for (dir = 0; dir < 2; dir++)339		line6_stream_stop(line6pcm, dir, type);340	for (dir = 0; dir < 2; dir++) {341		pstr = get_stream(line6pcm, dir);342		line6_buffer_release(line6pcm, pstr, type);343	}344	mutex_unlock(&line6pcm->state_mutex);345}346EXPORT_SYMBOL_GPL(line6_pcm_release);347 348/* common PCM hw_params callback */349int snd_line6_hw_params(struct snd_pcm_substream *substream,350			struct snd_pcm_hw_params *hw_params)351{352	int ret;353	struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);354	struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream);355 356	mutex_lock(&line6pcm->state_mutex);357	ret = line6_buffer_acquire(line6pcm, pstr, substream->stream,358	                           LINE6_STREAM_PCM);359	if (ret < 0)360		goto error;361 362	pstr->period = params_period_bytes(hw_params);363 error:364	mutex_unlock(&line6pcm->state_mutex);365	return ret;366}367 368/* common PCM hw_free callback */369int snd_line6_hw_free(struct snd_pcm_substream *substream)370{371	struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);372	struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream);373 374	mutex_lock(&line6pcm->state_mutex);375	line6_buffer_release(line6pcm, pstr, LINE6_STREAM_PCM);376	mutex_unlock(&line6pcm->state_mutex);377	return 0;378}379 380 381/* control info callback */382static int snd_line6_control_playback_info(struct snd_kcontrol *kcontrol,383					   struct snd_ctl_elem_info *uinfo)384{385	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;386	uinfo->count = 2;387	uinfo->value.integer.min = 0;388	uinfo->value.integer.max = 256;389	return 0;390}391 392/* control get callback */393static int snd_line6_control_playback_get(struct snd_kcontrol *kcontrol,394					  struct snd_ctl_elem_value *ucontrol)395{396	int i;397	struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);398 399	for (i = 0; i < 2; i++)400		ucontrol->value.integer.value[i] = line6pcm->volume_playback[i];401 402	return 0;403}404 405/* control put callback */406static int snd_line6_control_playback_put(struct snd_kcontrol *kcontrol,407					  struct snd_ctl_elem_value *ucontrol)408{409	int i, changed = 0;410	struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);411 412	for (i = 0; i < 2; i++)413		if (line6pcm->volume_playback[i] !=414		    ucontrol->value.integer.value[i]) {415			line6pcm->volume_playback[i] =416			    ucontrol->value.integer.value[i];417			changed = 1;418		}419 420	return changed;421}422 423/* control definition */424static const struct snd_kcontrol_new line6_controls[] = {425	{426		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,427		.name = "PCM Playback Volume",428		.info = snd_line6_control_playback_info,429		.get = snd_line6_control_playback_get,430		.put = snd_line6_control_playback_put431	},432	{433		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,434		.name = "Impulse Response Volume",435		.info = snd_line6_impulse_volume_info,436		.get = snd_line6_impulse_volume_get,437		.put = snd_line6_impulse_volume_put438	},439	{440		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,441		.name = "Impulse Response Period",442		.info = snd_line6_impulse_period_info,443		.get = snd_line6_impulse_period_get,444		.put = snd_line6_impulse_period_put445	},446};447 448/*449	Cleanup the PCM device.450*/451static void cleanup_urbs(struct line6_pcm_stream *pcms, int iso_buffers)452{453	int i;454 455	/* Most likely impossible in current code... */456	if (pcms->urbs == NULL)457		return;458 459	for (i = 0; i < iso_buffers; i++) {460		if (pcms->urbs[i]) {461			usb_kill_urb(pcms->urbs[i]);462			usb_free_urb(pcms->urbs[i]);463		}464	}465	kfree(pcms->urbs);466	pcms->urbs = NULL;467}468 469static void line6_cleanup_pcm(struct snd_pcm *pcm)470{471	struct snd_line6_pcm *line6pcm = snd_pcm_chip(pcm);472 473	cleanup_urbs(&line6pcm->out, line6pcm->line6->iso_buffers);474	cleanup_urbs(&line6pcm->in, line6pcm->line6->iso_buffers);475	kfree(line6pcm);476}477 478/* create a PCM device */479static int snd_line6_new_pcm(struct usb_line6 *line6, struct snd_pcm **pcm_ret)480{481	struct snd_pcm *pcm;482	int err;483 484	err = snd_pcm_new(line6->card, (char *)line6->properties->name,485			  0, 1, 1, pcm_ret);486	if (err < 0)487		return err;488	pcm = *pcm_ret;489	strcpy(pcm->name, line6->properties->name);490 491	/* set operators */492	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,493			&snd_line6_playback_ops);494	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_line6_capture_ops);495 496	/* pre-allocation of buffers */497	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,498				       NULL, 64 * 1024, 128 * 1024);499	return 0;500}501 502/*503	Sync with PCM stream stops.504*/505void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm)506{507	line6_unlink_audio_urbs(line6pcm, &line6pcm->out);508	line6_unlink_audio_urbs(line6pcm, &line6pcm->in);509	line6_wait_clear_audio_urbs(line6pcm, &line6pcm->out);510	line6_wait_clear_audio_urbs(line6pcm, &line6pcm->in);511}512 513/*514	Create and register the PCM device and mixer entries.515	Create URBs for playback and capture.516*/517int line6_init_pcm(struct usb_line6 *line6,518		   struct line6_pcm_properties *properties)519{520	int i, err;521	unsigned ep_read = line6->properties->ep_audio_r;522	unsigned ep_write = line6->properties->ep_audio_w;523	struct snd_pcm *pcm;524	struct snd_line6_pcm *line6pcm;525 526	if (!(line6->properties->capabilities & LINE6_CAP_PCM))527		return 0;	/* skip PCM initialization and report success */528 529	err = snd_line6_new_pcm(line6, &pcm);530	if (err < 0)531		return err;532 533	line6pcm = kzalloc(sizeof(*line6pcm), GFP_KERNEL);534	if (!line6pcm)535		return -ENOMEM;536 537	mutex_init(&line6pcm->state_mutex);538	line6pcm->pcm = pcm;539	line6pcm->properties = properties;540	line6pcm->volume_playback[0] = line6pcm->volume_playback[1] = 255;541	line6pcm->volume_monitor = 255;542	line6pcm->line6 = line6;543 544	spin_lock_init(&line6pcm->out.lock);545	spin_lock_init(&line6pcm->in.lock);546	line6pcm->impulse_period = LINE6_IMPULSE_DEFAULT_PERIOD;547 548	line6->line6pcm = line6pcm;549 550	pcm->private_data = line6pcm;551	pcm->private_free = line6_cleanup_pcm;552 553	line6pcm->max_packet_size_in =554		usb_maxpacket(line6->usbdev,555			usb_rcvisocpipe(line6->usbdev, ep_read));556	line6pcm->max_packet_size_out =557		usb_maxpacket(line6->usbdev,558			usb_sndisocpipe(line6->usbdev, ep_write));559	if (!line6pcm->max_packet_size_in || !line6pcm->max_packet_size_out) {560		dev_err(line6pcm->line6->ifcdev,561			"cannot get proper max packet size\n");562		return -EINVAL;563	}564 565	err = line6_create_audio_out_urbs(line6pcm);566	if (err < 0)567		return err;568 569	err = line6_create_audio_in_urbs(line6pcm);570	if (err < 0)571		return err;572 573	/* mixer: */574	for (i = 0; i < ARRAY_SIZE(line6_controls); i++) {575		err = snd_ctl_add(line6->card,576				  snd_ctl_new1(&line6_controls[i], line6pcm));577		if (err < 0)578			return err;579	}580 581	return 0;582}583EXPORT_SYMBOL_GPL(line6_init_pcm);584 585/* prepare pcm callback */586int snd_line6_prepare(struct snd_pcm_substream *substream)587{588	struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);589	struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream);590 591	mutex_lock(&line6pcm->state_mutex);592	if (!pstr->running)593		line6_wait_clear_audio_urbs(line6pcm, pstr);594 595	if (!test_and_set_bit(LINE6_FLAG_PREPARED, &line6pcm->flags)) {596		line6pcm->out.count = 0;597		line6pcm->out.pos = 0;598		line6pcm->out.pos_done = 0;599		line6pcm->out.bytes = 0;600		line6pcm->in.count = 0;601		line6pcm->in.pos_done = 0;602		line6pcm->in.bytes = 0;603	}604 605	mutex_unlock(&line6pcm->state_mutex);606	return 0;607}608