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