1*3713d93aSTakashi Sakamoto /* 2*3713d93aSTakashi Sakamoto * oxfw_pcm.c - a part of driver for OXFW970/971 based devices 3*3713d93aSTakashi Sakamoto * 4*3713d93aSTakashi Sakamoto * Copyright (c) Clemens Ladisch <clemens@ladisch.de> 5*3713d93aSTakashi Sakamoto * Licensed under the terms of the GNU General Public License, version 2. 6*3713d93aSTakashi Sakamoto */ 7*3713d93aSTakashi Sakamoto 8*3713d93aSTakashi Sakamoto #include "oxfw.h" 9*3713d93aSTakashi Sakamoto 10*3713d93aSTakashi Sakamoto static int firewave_rate_constraint(struct snd_pcm_hw_params *params, 11*3713d93aSTakashi Sakamoto struct snd_pcm_hw_rule *rule) 12*3713d93aSTakashi Sakamoto { 13*3713d93aSTakashi Sakamoto static unsigned int stereo_rates[] = { 48000, 96000 }; 14*3713d93aSTakashi Sakamoto struct snd_interval *channels = 15*3713d93aSTakashi Sakamoto hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); 16*3713d93aSTakashi Sakamoto struct snd_interval *rate = 17*3713d93aSTakashi Sakamoto hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); 18*3713d93aSTakashi Sakamoto 19*3713d93aSTakashi Sakamoto /* two channels work only at 48/96 kHz */ 20*3713d93aSTakashi Sakamoto if (snd_interval_max(channels) < 6) 21*3713d93aSTakashi Sakamoto return snd_interval_list(rate, 2, stereo_rates, 0); 22*3713d93aSTakashi Sakamoto return 0; 23*3713d93aSTakashi Sakamoto } 24*3713d93aSTakashi Sakamoto 25*3713d93aSTakashi Sakamoto static int firewave_channels_constraint(struct snd_pcm_hw_params *params, 26*3713d93aSTakashi Sakamoto struct snd_pcm_hw_rule *rule) 27*3713d93aSTakashi Sakamoto { 28*3713d93aSTakashi Sakamoto static const struct snd_interval all_channels = { .min = 6, .max = 6 }; 29*3713d93aSTakashi Sakamoto struct snd_interval *rate = 30*3713d93aSTakashi Sakamoto hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); 31*3713d93aSTakashi Sakamoto struct snd_interval *channels = 32*3713d93aSTakashi Sakamoto hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); 33*3713d93aSTakashi Sakamoto 34*3713d93aSTakashi Sakamoto /* 32/44.1 kHz work only with all six channels */ 35*3713d93aSTakashi Sakamoto if (snd_interval_max(rate) < 48000) 36*3713d93aSTakashi Sakamoto return snd_interval_refine(channels, &all_channels); 37*3713d93aSTakashi Sakamoto return 0; 38*3713d93aSTakashi Sakamoto } 39*3713d93aSTakashi Sakamoto 40*3713d93aSTakashi Sakamoto int firewave_constraints(struct snd_pcm_runtime *runtime) 41*3713d93aSTakashi Sakamoto { 42*3713d93aSTakashi Sakamoto static unsigned int channels_list[] = { 2, 6 }; 43*3713d93aSTakashi Sakamoto static struct snd_pcm_hw_constraint_list channels_list_constraint = { 44*3713d93aSTakashi Sakamoto .count = 2, 45*3713d93aSTakashi Sakamoto .list = channels_list, 46*3713d93aSTakashi Sakamoto }; 47*3713d93aSTakashi Sakamoto int err; 48*3713d93aSTakashi Sakamoto 49*3713d93aSTakashi Sakamoto runtime->hw.rates = SNDRV_PCM_RATE_32000 | 50*3713d93aSTakashi Sakamoto SNDRV_PCM_RATE_44100 | 51*3713d93aSTakashi Sakamoto SNDRV_PCM_RATE_48000 | 52*3713d93aSTakashi Sakamoto SNDRV_PCM_RATE_96000; 53*3713d93aSTakashi Sakamoto runtime->hw.channels_max = 6; 54*3713d93aSTakashi Sakamoto 55*3713d93aSTakashi Sakamoto err = snd_pcm_hw_constraint_list(runtime, 0, 56*3713d93aSTakashi Sakamoto SNDRV_PCM_HW_PARAM_CHANNELS, 57*3713d93aSTakashi Sakamoto &channels_list_constraint); 58*3713d93aSTakashi Sakamoto if (err < 0) 59*3713d93aSTakashi Sakamoto return err; 60*3713d93aSTakashi Sakamoto err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 61*3713d93aSTakashi Sakamoto firewave_rate_constraint, NULL, 62*3713d93aSTakashi Sakamoto SNDRV_PCM_HW_PARAM_CHANNELS, -1); 63*3713d93aSTakashi Sakamoto if (err < 0) 64*3713d93aSTakashi Sakamoto return err; 65*3713d93aSTakashi Sakamoto err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 66*3713d93aSTakashi Sakamoto firewave_channels_constraint, NULL, 67*3713d93aSTakashi Sakamoto SNDRV_PCM_HW_PARAM_RATE, -1); 68*3713d93aSTakashi Sakamoto if (err < 0) 69*3713d93aSTakashi Sakamoto return err; 70*3713d93aSTakashi Sakamoto 71*3713d93aSTakashi Sakamoto return 0; 72*3713d93aSTakashi Sakamoto } 73*3713d93aSTakashi Sakamoto 74*3713d93aSTakashi Sakamoto int lacie_speakers_constraints(struct snd_pcm_runtime *runtime) 75*3713d93aSTakashi Sakamoto { 76*3713d93aSTakashi Sakamoto runtime->hw.rates = SNDRV_PCM_RATE_32000 | 77*3713d93aSTakashi Sakamoto SNDRV_PCM_RATE_44100 | 78*3713d93aSTakashi Sakamoto SNDRV_PCM_RATE_48000 | 79*3713d93aSTakashi Sakamoto SNDRV_PCM_RATE_88200 | 80*3713d93aSTakashi Sakamoto SNDRV_PCM_RATE_96000; 81*3713d93aSTakashi Sakamoto 82*3713d93aSTakashi Sakamoto return 0; 83*3713d93aSTakashi Sakamoto } 84*3713d93aSTakashi Sakamoto 85*3713d93aSTakashi Sakamoto static int pcm_open(struct snd_pcm_substream *substream) 86*3713d93aSTakashi Sakamoto { 87*3713d93aSTakashi Sakamoto static const struct snd_pcm_hardware hardware = { 88*3713d93aSTakashi Sakamoto .info = SNDRV_PCM_INFO_MMAP | 89*3713d93aSTakashi Sakamoto SNDRV_PCM_INFO_MMAP_VALID | 90*3713d93aSTakashi Sakamoto SNDRV_PCM_INFO_BATCH | 91*3713d93aSTakashi Sakamoto SNDRV_PCM_INFO_INTERLEAVED | 92*3713d93aSTakashi Sakamoto SNDRV_PCM_INFO_BLOCK_TRANSFER, 93*3713d93aSTakashi Sakamoto .formats = AMDTP_OUT_PCM_FORMAT_BITS, 94*3713d93aSTakashi Sakamoto .channels_min = 2, 95*3713d93aSTakashi Sakamoto .channels_max = 2, 96*3713d93aSTakashi Sakamoto .buffer_bytes_max = 4 * 1024 * 1024, 97*3713d93aSTakashi Sakamoto .period_bytes_min = 1, 98*3713d93aSTakashi Sakamoto .period_bytes_max = UINT_MAX, 99*3713d93aSTakashi Sakamoto .periods_min = 1, 100*3713d93aSTakashi Sakamoto .periods_max = UINT_MAX, 101*3713d93aSTakashi Sakamoto }; 102*3713d93aSTakashi Sakamoto struct snd_oxfw *oxfw = substream->private_data; 103*3713d93aSTakashi Sakamoto struct snd_pcm_runtime *runtime = substream->runtime; 104*3713d93aSTakashi Sakamoto bool used; 105*3713d93aSTakashi Sakamoto int err; 106*3713d93aSTakashi Sakamoto 107*3713d93aSTakashi Sakamoto err = cmp_connection_check_used(&oxfw->in_conn, &used); 108*3713d93aSTakashi Sakamoto if ((err < 0) || used) 109*3713d93aSTakashi Sakamoto goto end; 110*3713d93aSTakashi Sakamoto 111*3713d93aSTakashi Sakamoto runtime->hw = hardware; 112*3713d93aSTakashi Sakamoto 113*3713d93aSTakashi Sakamoto err = oxfw->device_info->pcm_constraints(runtime); 114*3713d93aSTakashi Sakamoto if (err < 0) 115*3713d93aSTakashi Sakamoto goto end; 116*3713d93aSTakashi Sakamoto err = snd_pcm_limit_hw_rates(runtime); 117*3713d93aSTakashi Sakamoto if (err < 0) 118*3713d93aSTakashi Sakamoto goto end; 119*3713d93aSTakashi Sakamoto 120*3713d93aSTakashi Sakamoto err = amdtp_stream_add_pcm_hw_constraints(&oxfw->rx_stream, runtime); 121*3713d93aSTakashi Sakamoto end: 122*3713d93aSTakashi Sakamoto return err; 123*3713d93aSTakashi Sakamoto } 124*3713d93aSTakashi Sakamoto 125*3713d93aSTakashi Sakamoto static int pcm_close(struct snd_pcm_substream *substream) 126*3713d93aSTakashi Sakamoto { 127*3713d93aSTakashi Sakamoto return 0; 128*3713d93aSTakashi Sakamoto } 129*3713d93aSTakashi Sakamoto 130*3713d93aSTakashi Sakamoto static int pcm_hw_params(struct snd_pcm_substream *substream, 131*3713d93aSTakashi Sakamoto struct snd_pcm_hw_params *hw_params) 132*3713d93aSTakashi Sakamoto { 133*3713d93aSTakashi Sakamoto struct snd_oxfw *oxfw = substream->private_data; 134*3713d93aSTakashi Sakamoto int err; 135*3713d93aSTakashi Sakamoto 136*3713d93aSTakashi Sakamoto mutex_lock(&oxfw->mutex); 137*3713d93aSTakashi Sakamoto 138*3713d93aSTakashi Sakamoto snd_oxfw_stream_stop_simplex(oxfw); 139*3713d93aSTakashi Sakamoto 140*3713d93aSTakashi Sakamoto err = snd_pcm_lib_alloc_vmalloc_buffer(substream, 141*3713d93aSTakashi Sakamoto params_buffer_bytes(hw_params)); 142*3713d93aSTakashi Sakamoto if (err < 0) 143*3713d93aSTakashi Sakamoto goto error; 144*3713d93aSTakashi Sakamoto 145*3713d93aSTakashi Sakamoto amdtp_stream_set_parameters(&oxfw->rx_stream, 146*3713d93aSTakashi Sakamoto params_rate(hw_params), 147*3713d93aSTakashi Sakamoto params_channels(hw_params), 148*3713d93aSTakashi Sakamoto 0); 149*3713d93aSTakashi Sakamoto 150*3713d93aSTakashi Sakamoto amdtp_stream_set_pcm_format(&oxfw->rx_stream, 151*3713d93aSTakashi Sakamoto params_format(hw_params)); 152*3713d93aSTakashi Sakamoto 153*3713d93aSTakashi Sakamoto err = avc_general_set_sig_fmt(oxfw->unit, params_rate(hw_params), 154*3713d93aSTakashi Sakamoto AVC_GENERAL_PLUG_DIR_IN, 0); 155*3713d93aSTakashi Sakamoto if (err < 0) { 156*3713d93aSTakashi Sakamoto dev_err(&oxfw->unit->device, "failed to set sample rate\n"); 157*3713d93aSTakashi Sakamoto goto err_buffer; 158*3713d93aSTakashi Sakamoto } 159*3713d93aSTakashi Sakamoto 160*3713d93aSTakashi Sakamoto return 0; 161*3713d93aSTakashi Sakamoto 162*3713d93aSTakashi Sakamoto err_buffer: 163*3713d93aSTakashi Sakamoto snd_pcm_lib_free_vmalloc_buffer(substream); 164*3713d93aSTakashi Sakamoto error: 165*3713d93aSTakashi Sakamoto mutex_unlock(&oxfw->mutex); 166*3713d93aSTakashi Sakamoto return err; 167*3713d93aSTakashi Sakamoto } 168*3713d93aSTakashi Sakamoto 169*3713d93aSTakashi Sakamoto static int pcm_hw_free(struct snd_pcm_substream *substream) 170*3713d93aSTakashi Sakamoto { 171*3713d93aSTakashi Sakamoto struct snd_oxfw *oxfw = substream->private_data; 172*3713d93aSTakashi Sakamoto 173*3713d93aSTakashi Sakamoto mutex_lock(&oxfw->mutex); 174*3713d93aSTakashi Sakamoto snd_oxfw_stream_stop_simplex(oxfw); 175*3713d93aSTakashi Sakamoto mutex_unlock(&oxfw->mutex); 176*3713d93aSTakashi Sakamoto 177*3713d93aSTakashi Sakamoto return snd_pcm_lib_free_vmalloc_buffer(substream); 178*3713d93aSTakashi Sakamoto } 179*3713d93aSTakashi Sakamoto 180*3713d93aSTakashi Sakamoto static int pcm_prepare(struct snd_pcm_substream *substream) 181*3713d93aSTakashi Sakamoto { 182*3713d93aSTakashi Sakamoto struct snd_oxfw *oxfw = substream->private_data; 183*3713d93aSTakashi Sakamoto int err; 184*3713d93aSTakashi Sakamoto 185*3713d93aSTakashi Sakamoto mutex_lock(&oxfw->mutex); 186*3713d93aSTakashi Sakamoto 187*3713d93aSTakashi Sakamoto snd_oxfw_stream_stop_simplex(oxfw); 188*3713d93aSTakashi Sakamoto 189*3713d93aSTakashi Sakamoto err = snd_oxfw_stream_start_simplex(oxfw); 190*3713d93aSTakashi Sakamoto if (err < 0) 191*3713d93aSTakashi Sakamoto goto end; 192*3713d93aSTakashi Sakamoto 193*3713d93aSTakashi Sakamoto amdtp_stream_pcm_prepare(&oxfw->rx_stream); 194*3713d93aSTakashi Sakamoto end: 195*3713d93aSTakashi Sakamoto mutex_unlock(&oxfw->mutex); 196*3713d93aSTakashi Sakamoto return err; 197*3713d93aSTakashi Sakamoto } 198*3713d93aSTakashi Sakamoto 199*3713d93aSTakashi Sakamoto static int pcm_trigger(struct snd_pcm_substream *substream, int cmd) 200*3713d93aSTakashi Sakamoto { 201*3713d93aSTakashi Sakamoto struct snd_oxfw *oxfw = substream->private_data; 202*3713d93aSTakashi Sakamoto struct snd_pcm_substream *pcm; 203*3713d93aSTakashi Sakamoto 204*3713d93aSTakashi Sakamoto switch (cmd) { 205*3713d93aSTakashi Sakamoto case SNDRV_PCM_TRIGGER_START: 206*3713d93aSTakashi Sakamoto pcm = substream; 207*3713d93aSTakashi Sakamoto break; 208*3713d93aSTakashi Sakamoto case SNDRV_PCM_TRIGGER_STOP: 209*3713d93aSTakashi Sakamoto pcm = NULL; 210*3713d93aSTakashi Sakamoto break; 211*3713d93aSTakashi Sakamoto default: 212*3713d93aSTakashi Sakamoto return -EINVAL; 213*3713d93aSTakashi Sakamoto } 214*3713d93aSTakashi Sakamoto amdtp_stream_pcm_trigger(&oxfw->rx_stream, pcm); 215*3713d93aSTakashi Sakamoto return 0; 216*3713d93aSTakashi Sakamoto } 217*3713d93aSTakashi Sakamoto 218*3713d93aSTakashi Sakamoto static snd_pcm_uframes_t pcm_pointer(struct snd_pcm_substream *substream) 219*3713d93aSTakashi Sakamoto { 220*3713d93aSTakashi Sakamoto struct snd_oxfw *oxfw = substream->private_data; 221*3713d93aSTakashi Sakamoto 222*3713d93aSTakashi Sakamoto return amdtp_stream_pcm_pointer(&oxfw->rx_stream); 223*3713d93aSTakashi Sakamoto } 224*3713d93aSTakashi Sakamoto 225*3713d93aSTakashi Sakamoto int snd_oxfw_create_pcm(struct snd_oxfw *oxfw) 226*3713d93aSTakashi Sakamoto { 227*3713d93aSTakashi Sakamoto static struct snd_pcm_ops ops = { 228*3713d93aSTakashi Sakamoto .open = pcm_open, 229*3713d93aSTakashi Sakamoto .close = pcm_close, 230*3713d93aSTakashi Sakamoto .ioctl = snd_pcm_lib_ioctl, 231*3713d93aSTakashi Sakamoto .hw_params = pcm_hw_params, 232*3713d93aSTakashi Sakamoto .hw_free = pcm_hw_free, 233*3713d93aSTakashi Sakamoto .prepare = pcm_prepare, 234*3713d93aSTakashi Sakamoto .trigger = pcm_trigger, 235*3713d93aSTakashi Sakamoto .pointer = pcm_pointer, 236*3713d93aSTakashi Sakamoto .page = snd_pcm_lib_get_vmalloc_page, 237*3713d93aSTakashi Sakamoto .mmap = snd_pcm_lib_mmap_vmalloc, 238*3713d93aSTakashi Sakamoto }; 239*3713d93aSTakashi Sakamoto struct snd_pcm *pcm; 240*3713d93aSTakashi Sakamoto int err; 241*3713d93aSTakashi Sakamoto 242*3713d93aSTakashi Sakamoto err = snd_pcm_new(oxfw->card, oxfw->card->driver, 0, 1, 0, &pcm); 243*3713d93aSTakashi Sakamoto if (err < 0) 244*3713d93aSTakashi Sakamoto return err; 245*3713d93aSTakashi Sakamoto pcm->private_data = oxfw; 246*3713d93aSTakashi Sakamoto strcpy(pcm->name, oxfw->card->shortname); 247*3713d93aSTakashi Sakamoto snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &ops); 248*3713d93aSTakashi Sakamoto return 0; 249*3713d93aSTakashi Sakamoto } 250