Beispiel #1
0
/* Acquire and start duplex streams:
 * type is either LINE6_STREAM_IMPULSE or LINE6_STREAM_MONITOR
 */
int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int type)
{
	struct line6_pcm_stream *pstr;
	int ret = 0, dir;

	mutex_lock(&line6pcm->state_mutex);
	for (dir = 0; dir < 2; dir++) {
		pstr = get_stream(line6pcm, dir);
		ret = line6_buffer_acquire(line6pcm, pstr, type);
		if (ret < 0)
			goto error;
		if (!pstr->running)
			line6_wait_clear_audio_urbs(line6pcm, pstr);
	}
	for (dir = 0; dir < 2; dir++) {
		ret = line6_stream_start(line6pcm, dir, type);
		if (ret < 0)
			goto error;
	}
 error:
	mutex_unlock(&line6pcm->state_mutex);
	if (ret < 0)
		line6_pcm_release(line6pcm, type);
	return ret;
}
/*
	Toneport device disconnected.
*/
void line6_toneport_disconnect(struct usb_interface *interface)
{
	struct usb_line6_toneport *toneport;

	if (interface == NULL)
		return;

	toneport = usb_get_intfdata(interface);
	del_timer_sync(&toneport->timer);

	if (toneport_has_led(toneport->line6.usbdev->descriptor.idProduct)) {
		device_remove_file(&interface->dev, &dev_attr_led_red);
		device_remove_file(&interface->dev, &dev_attr_led_green);
	}

	if (toneport != NULL) {
		struct snd_line6_pcm *line6pcm = toneport->line6.line6pcm;

		if (line6pcm != NULL) {
			line6_pcm_release(line6pcm, LINE6_BITS_PCM_MONITOR);
			line6_pcm_disconnect(line6pcm);
		}
	}

	toneport_destruct(interface);
}
Beispiel #3
0
/* Acquire and optionally start duplex streams:
 * type is either LINE6_STREAM_IMPULSE or LINE6_STREAM_MONITOR
 */
int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int type, bool start)
{
	struct line6_pcm_stream *pstr;
	int ret = 0, dir;

	/* TODO: We should assert SNDRV_PCM_STREAM_PLAYBACK/CAPTURE == 0/1 */
	mutex_lock(&line6pcm->state_mutex);
	for (dir = 0; dir < 2; dir++) {
		pstr = get_stream(line6pcm, dir);
		ret = line6_buffer_acquire(line6pcm, pstr, dir, type);
		if (ret < 0)
			goto error;
		if (!pstr->running)
			line6_wait_clear_audio_urbs(line6pcm, pstr);
	}
	if (start) {
		for (dir = 0; dir < 2; dir++) {
			ret = line6_stream_start(line6pcm, dir, type);
			if (ret < 0)
				goto error;
		}
	}
 error:
	mutex_unlock(&line6pcm->state_mutex);
	if (ret < 0)
		line6_pcm_release(line6pcm, type);
	return ret;
}
Beispiel #4
0
/* close capture callback */
static int snd_line6_capture_close(struct snd_pcm_substream *substream)
{
	struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);

	line6_pcm_release(line6pcm, LINE6_STREAM_CAPTURE_HELPER);
	return 0;
}
Beispiel #5
0
/* trigger callback */
int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd)
{
	int err;

	switch (cmd) {
	case SNDRV_PCM_TRIGGER_START:
#ifdef CONFIG_PM
	case SNDRV_PCM_TRIGGER_RESUME:
#endif
		err = line6_pcm_acquire(line6pcm,
					LINE6_BIT_PCM_ALSA_CAPTURE_STREAM);

		if (err < 0)
			return err;

		break;

	case SNDRV_PCM_TRIGGER_STOP:
#ifdef CONFIG_PM
	case SNDRV_PCM_TRIGGER_SUSPEND:
#endif
		err = line6_pcm_release(line6pcm,
					LINE6_BIT_PCM_ALSA_CAPTURE_STREAM);

		if (err < 0)
			return err;

		break;

	default:
		return -EINVAL;
	}

	return 0;
}
Beispiel #6
0
/* hw_params capture callback */
static int snd_line6_capture_hw_params(struct snd_pcm_substream *substream,
				       struct snd_pcm_hw_params *hw_params)
{
	int ret;
	struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);

	/* -- Florian Demski [FD] */
	/* don't ask me why, but this fixes the bug on my machine */
	if (line6pcm == NULL) {
		if (substream->pcm == NULL)
			return -ENOMEM;
		if (substream->pcm->private_data == NULL)
			return -ENOMEM;
		substream->private_data = substream->pcm->private_data;
		line6pcm = snd_pcm_substream_chip(substream);
	}
	/* -- [FD] end */

	ret = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER);

	if (ret < 0)
		return ret;

	ret = snd_pcm_lib_malloc_pages(substream,
				       params_buffer_bytes(hw_params));
	if (ret < 0) {
		line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER);
		return ret;
	}

	line6pcm->period_in = params_period_bytes(hw_params);
	return 0;
}
Beispiel #7
0
static int snd_line6_impulse_volume_put(struct snd_kcontrol *kcontrol,
					struct snd_ctl_elem_value *ucontrol)
{
	struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
	int value = ucontrol->value.integer.value[0];
	int err;

	if (line6pcm->impulse_volume == value)
		return 0;

	line6pcm->impulse_volume = value;
	if (value > 0) {
		err = line6_pcm_acquire(line6pcm, LINE6_STREAM_IMPULSE);
		if (err < 0) {
			line6pcm->impulse_volume = 0;
			line6_pcm_release(line6pcm, LINE6_STREAM_IMPULSE);
			return err;
		}
	} else {
		line6_pcm_release(line6pcm, LINE6_STREAM_IMPULSE);
	}
	return 1;
}
/* monitor put callback */
static int snd_toneport_monitor_put(struct snd_kcontrol *kcontrol,
				    struct snd_ctl_elem_value *ucontrol)
{
	struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);

	if (ucontrol->value.integer.value[0] == line6pcm->volume_monitor)
		return 0;

	line6pcm->volume_monitor = ucontrol->value.integer.value[0];

	if (line6pcm->volume_monitor > 0)
		line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_MONITOR);
	else
		line6_pcm_release(line6pcm, LINE6_BITS_PCM_MONITOR);

	return 1;
}
Beispiel #9
0
/*
	"write" request on "impulse_volume" special file.
*/
static ssize_t pcm_set_impulse_volume(struct device *dev,
				      struct device_attribute *attr,
				      const char *buf, size_t count)
{
	struct snd_line6_pcm *line6pcm = dev2pcm(dev);
	int value;
	int ret;

	ret = kstrtoint(buf, 10, &value);
	if (ret < 0)
		return ret;

	line6pcm->impulse_volume = value;

	if (value > 0)
		line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_IMPULSE);
	else
		line6_pcm_release(line6pcm, LINE6_BITS_PCM_IMPULSE);

	return count;
}
Beispiel #10
0
int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels)
{
	unsigned long flags_old, flags_new, flags_final;
	int err;

	do {
		flags_old = ACCESS_ONCE(line6pcm->flags);
		flags_new = flags_old | channels;
	} while (cmpxchg(&line6pcm->flags, flags_old, flags_new) != flags_old);

	flags_final = flags_old;

	line6pcm->prev_fbuf = NULL;

	if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_BUFFER)) {
		/* Invoked multiple times in a row so allocate once only */
		if (!line6pcm->buffer_in) {
			line6pcm->buffer_in =
				kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS *
					line6pcm->max_packet_size, GFP_KERNEL);
			if (!line6pcm->buffer_in) {
				err = -ENOMEM;
				goto pcm_acquire_error;
			}

			flags_final |= channels & LINE6_BITS_CAPTURE_BUFFER;
		}
	}

	if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_STREAM)) {
		/*
		   Waiting for completion of active URBs in the stop handler is
		   a bug, we therefore report an error if capturing is restarted
		   too soon.
		 */
		if (line6pcm->active_urb_in | line6pcm->unlink_urb_in) {
			dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n");
			return -EBUSY;
		}

		line6pcm->count_in = 0;
		line6pcm->prev_fsize = 0;
		err = line6_submit_audio_in_all_urbs(line6pcm);

		if (err < 0)
			goto pcm_acquire_error;

		flags_final |= channels & LINE6_BITS_CAPTURE_STREAM;
	}

	if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_BUFFER)) {
		/* Invoked multiple times in a row so allocate once only */
		if (!line6pcm->buffer_out) {
			line6pcm->buffer_out =
				kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS *
					line6pcm->max_packet_size, GFP_KERNEL);
			if (!line6pcm->buffer_out) {
				err = -ENOMEM;
				goto pcm_acquire_error;
			}

			flags_final |= channels & LINE6_BITS_PLAYBACK_BUFFER;
		}
	}

	if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_STREAM)) {
		/*
		  See comment above regarding PCM restart.
		*/
		if (line6pcm->active_urb_out | line6pcm->unlink_urb_out) {
			dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n");
			return -EBUSY;
		}

		line6pcm->count_out = 0;
		err = line6_submit_audio_out_all_urbs(line6pcm);

		if (err < 0)
			goto pcm_acquire_error;

		flags_final |= channels & LINE6_BITS_PLAYBACK_STREAM;
	}

	return 0;

pcm_acquire_error:
	/*
	   If not all requested resources/streams could be obtained, release
	   those which were successfully obtained (if any).
	*/
	line6_pcm_release(line6pcm, flags_final & channels);
	return err;
}
Beispiel #11
0
/* hw_free capture callback */
static int snd_line6_capture_hw_free(struct snd_pcm_substream *substream)
{
	struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
	line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER);
	return snd_pcm_lib_free_pages(substream);
}