static int set_rate(struct snd_oxfw *oxfw, unsigned int rate) { int err; err = avc_general_set_sig_fmt(oxfw->unit, rate, AVC_GENERAL_PLUG_DIR_IN, 0); if (err < 0) goto end; if (oxfw->has_output) err = avc_general_set_sig_fmt(oxfw->unit, rate, AVC_GENERAL_PLUG_DIR_OUT, 0); end: return err; }
int snd_bebob_stream_get_rate(struct snd_bebob *bebob, unsigned int *curr_rate) { unsigned int tx_rate, rx_rate, trials; int err; trials = 0; do { err = avc_general_get_sig_fmt(bebob->unit, &tx_rate, AVC_GENERAL_PLUG_DIR_OUT, 0); } while (err == -EAGAIN && ++trials < 3); if (err < 0) goto end; trials = 0; do { err = avc_general_get_sig_fmt(bebob->unit, &rx_rate, AVC_GENERAL_PLUG_DIR_IN, 0); } while (err == -EAGAIN && ++trials < 3); if (err < 0) goto end; *curr_rate = rx_rate; if (rx_rate == tx_rate) goto end; /* synchronize receive stream rate to transmit stream rate */ err = avc_general_set_sig_fmt(bebob->unit, rx_rate, AVC_GENERAL_PLUG_DIR_IN, 0); end: return err; }
int snd_bebob_stream_set_rate(struct snd_bebob *bebob, unsigned int rate) { int err; err = avc_general_set_sig_fmt(bebob->unit, rate, AVC_GENERAL_PLUG_DIR_OUT, 0); if (err < 0) goto end; err = avc_general_set_sig_fmt(bebob->unit, rate, AVC_GENERAL_PLUG_DIR_IN, 0); if (err < 0) goto end; /* * Some devices need a bit time for transition. * 300msec is got by some experiments. */ msleep(300); end: return err; }
int snd_bebob_set_rate(struct snd_bebob *bebob, unsigned int rate, enum avc_general_plug_dir dir) { int err; err = avc_general_set_sig_fmt(bebob->unit, rate, dir, 0); if (err < 0) goto end; /* ACCEPTED or INTERIM is OK */ if ((err != 0x0f) && (err != 0x09)) { dev_err(&bebob->unit->device, "failed to set sampling rate\n"); err = -EIO; } end: return err; }
static int firewave_channels_constraint(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { static const struct snd_interval all_channels = { .min = 6, .max = 6 }; struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); /* 32/44.1 kHz work only with all six channels */ if (snd_interval_max(rate) < 48000) return snd_interval_refine(channels, &all_channels); return 0; } static int firewave_constraints(struct snd_pcm_runtime *runtime) { static unsigned int channels_list[] = { 2, 6 }; static struct snd_pcm_hw_constraint_list channels_list_constraint = { .count = 2, .list = channels_list, }; int err; runtime->hw.rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000; runtime->hw.channels_max = 6; err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &channels_list_constraint); if (err < 0) return err; err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, firewave_rate_constraint, NULL, SNDRV_PCM_HW_PARAM_CHANNELS, -1); if (err < 0) return err; err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, firewave_channels_constraint, NULL, SNDRV_PCM_HW_PARAM_RATE, -1); if (err < 0) return err; return 0; } static int lacie_speakers_constraints(struct snd_pcm_runtime *runtime) { runtime->hw.rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000; return 0; } static int fwspk_open(struct snd_pcm_substream *substream) { static const struct snd_pcm_hardware hardware = { .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BATCH | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER, .formats = AMDTP_OUT_PCM_FORMAT_BITS, .channels_min = 2, .channels_max = 2, .buffer_bytes_max = 4 * 1024 * 1024, .period_bytes_min = 1, .period_bytes_max = UINT_MAX, .periods_min = 1, .periods_max = UINT_MAX, }; struct fwspk *fwspk = substream->private_data; struct snd_pcm_runtime *runtime = substream->runtime; int err; runtime->hw = hardware; err = fwspk->device_info->pcm_constraints(runtime); if (err < 0) return err; err = snd_pcm_limit_hw_rates(runtime); if (err < 0) return err; err = amdtp_stream_add_pcm_hw_constraints(&fwspk->stream, runtime); if (err < 0) return err; return 0; } static int fwspk_close(struct snd_pcm_substream *substream) { return 0; } static void fwspk_stop_stream(struct fwspk *fwspk) { if (amdtp_stream_running(&fwspk->stream)) { amdtp_stream_stop(&fwspk->stream); cmp_connection_break(&fwspk->connection); } } static int fwspk_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { struct fwspk *fwspk = substream->private_data; int err; mutex_lock(&fwspk->mutex); fwspk_stop_stream(fwspk); mutex_unlock(&fwspk->mutex); err = snd_pcm_lib_alloc_vmalloc_buffer(substream, params_buffer_bytes(hw_params)); if (err < 0) goto error; amdtp_stream_set_parameters(&fwspk->stream, params_rate(hw_params), params_channels(hw_params), 0); amdtp_stream_set_pcm_format(&fwspk->stream, params_format(hw_params)); err = avc_general_set_sig_fmt(fwspk->unit, params_rate(hw_params), AVC_GENERAL_PLUG_DIR_IN, 0); if (err < 0) { dev_err(&fwspk->unit->device, "failed to set sample rate\n"); goto err_buffer; } return 0; err_buffer: snd_pcm_lib_free_vmalloc_buffer(substream); error: return err; } static int fwspk_hw_free(struct snd_pcm_substream *substream) { struct fwspk *fwspk = substream->private_data; mutex_lock(&fwspk->mutex); fwspk_stop_stream(fwspk); mutex_unlock(&fwspk->mutex); return snd_pcm_lib_free_vmalloc_buffer(substream); } static int fwspk_prepare(struct snd_pcm_substream *substream) { struct fwspk *fwspk = substream->private_data; int err; mutex_lock(&fwspk->mutex); if (amdtp_streaming_error(&fwspk->stream)) fwspk_stop_stream(fwspk); if (!amdtp_stream_running(&fwspk->stream)) { err = cmp_connection_establish(&fwspk->connection, amdtp_stream_get_max_payload(&fwspk->stream)); if (err < 0) goto err_mutex; err = amdtp_stream_start(&fwspk->stream, fwspk->connection.resources.channel, fwspk->connection.speed); if (err < 0) goto err_connection; } mutex_unlock(&fwspk->mutex); amdtp_stream_pcm_prepare(&fwspk->stream); return 0; err_connection: cmp_connection_break(&fwspk->connection); err_mutex: mutex_unlock(&fwspk->mutex); return err; } static int fwspk_trigger(struct snd_pcm_substream *substream, int cmd) { struct fwspk *fwspk = substream->private_data; struct snd_pcm_substream *pcm; switch (cmd) { case SNDRV_PCM_TRIGGER_START: pcm = substream; break; case SNDRV_PCM_TRIGGER_STOP: pcm = NULL; break; default: return -EINVAL; } amdtp_stream_pcm_trigger(&fwspk->stream, pcm); return 0; } static snd_pcm_uframes_t fwspk_pointer(struct snd_pcm_substream *substream) { struct fwspk *fwspk = substream->private_data; return amdtp_stream_pcm_pointer(&fwspk->stream); } static int fwspk_create_pcm(struct fwspk *fwspk) { static struct snd_pcm_ops ops = { .open = fwspk_open, .close = fwspk_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = fwspk_hw_params, .hw_free = fwspk_hw_free, .prepare = fwspk_prepare, .trigger = fwspk_trigger, .pointer = fwspk_pointer, .page = snd_pcm_lib_get_vmalloc_page, .mmap = snd_pcm_lib_mmap_vmalloc, }; struct snd_pcm *pcm; int err; err = snd_pcm_new(fwspk->card, "OXFW970", 0, 1, 0, &pcm); if (err < 0) return err; pcm->private_data = fwspk; strcpy(pcm->name, fwspk->device_info->short_name); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &ops); return 0; } enum control_action { CTL_READ, CTL_WRITE }; enum control_attribute { CTL_MIN = 0x02, CTL_MAX = 0x03, CTL_CURRENT = 0x10, }; static int fwspk_mute_command(struct fwspk *fwspk, bool *value, enum control_action action) { u8 *buf; u8 response_ok; int err; buf = kmalloc(11, GFP_KERNEL); if (!buf) return -ENOMEM; if (action == CTL_READ) { buf[0] = 0x01; /* AV/C, STATUS */ response_ok = 0x0c; /* STABLE */ } else { buf[0] = 0x00; /* AV/C, CONTROL */ response_ok = 0x09; /* ACCEPTED */ } buf[1] = 0x08; /* audio unit 0 */ buf[2] = 0xb8; /* FUNCTION BLOCK */ buf[3] = 0x81; /* function block type: feature */ buf[4] = fwspk->device_info->mute_fb_id; /* function block ID */ buf[5] = 0x10; /* control attribute: current */ buf[6] = 0x02; /* selector length */ buf[7] = 0x00; /* audio channel number */ buf[8] = 0x01; /* control selector: mute */ buf[9] = 0x01; /* control data length */ if (action == CTL_READ) buf[10] = 0xff; else buf[10] = *value ? 0x70 : 0x60; err = fcp_avc_transaction(fwspk->unit, buf, 11, buf, 11, 0x3fe); if (err < 0) goto error; if (err < 11) { dev_err(&fwspk->unit->device, "short FCP response\n"); err = -EIO; goto error; } if (buf[0] != response_ok) { dev_err(&fwspk->unit->device, "mute command failed\n"); err = -EIO; goto error; } if (action == CTL_READ) *value = buf[10] == 0x70; err = 0; error: kfree(buf); return err; } static int fwspk_volume_command(struct fwspk *fwspk, s16 *value, unsigned int channel, enum control_attribute attribute, enum control_action action) { u8 *buf; u8 response_ok; int err; buf = kmalloc(12, GFP_KERNEL); if (!buf) return -ENOMEM; if (action == CTL_READ) { buf[0] = 0x01; /* AV/C, STATUS */ response_ok = 0x0c; /* STABLE */ } else { buf[0] = 0x00; /* AV/C, CONTROL */ response_ok = 0x09; /* ACCEPTED */ } buf[1] = 0x08; /* audio unit 0 */ buf[2] = 0xb8; /* FUNCTION BLOCK */ buf[3] = 0x81; /* function block type: feature */ buf[4] = fwspk->device_info->volume_fb_id; /* function block ID */ buf[5] = attribute; /* control attribute */ buf[6] = 0x02; /* selector length */ buf[7] = channel; /* audio channel number */ buf[8] = 0x02; /* control selector: volume */ buf[9] = 0x02; /* control data length */ if (action == CTL_READ) { buf[10] = 0xff; buf[11] = 0xff; } else { buf[10] = *value >> 8; buf[11] = *value; } err = fcp_avc_transaction(fwspk->unit, buf, 12, buf, 12, 0x3fe); if (err < 0) goto error; if (err < 12) { dev_err(&fwspk->unit->device, "short FCP response\n"); err = -EIO; goto error; } if (buf[0] != response_ok) { dev_err(&fwspk->unit->device, "volume command failed\n"); err = -EIO; goto error; } if (action == CTL_READ) *value = (buf[10] << 8) | buf[11]; err = 0; error: kfree(buf); return err; }