13713d93aSTakashi Sakamoto /* 23713d93aSTakashi Sakamoto * oxfw_pcm.c - a part of driver for OXFW970/971 based devices 33713d93aSTakashi Sakamoto * 43713d93aSTakashi Sakamoto * Copyright (c) Clemens Ladisch <clemens@ladisch.de> 53713d93aSTakashi Sakamoto * Licensed under the terms of the GNU General Public License, version 2. 63713d93aSTakashi Sakamoto */ 73713d93aSTakashi Sakamoto 83713d93aSTakashi Sakamoto #include "oxfw.h" 93713d93aSTakashi Sakamoto 10*5cd1d3f4STakashi Sakamoto static int hw_rule_rate(struct snd_pcm_hw_params *params, 113713d93aSTakashi Sakamoto struct snd_pcm_hw_rule *rule) 123713d93aSTakashi Sakamoto { 13*5cd1d3f4STakashi Sakamoto u8 **formats = rule->private; 14*5cd1d3f4STakashi Sakamoto struct snd_interval *r = 153713d93aSTakashi Sakamoto hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); 16*5cd1d3f4STakashi Sakamoto const struct snd_interval *c = 17*5cd1d3f4STakashi Sakamoto hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS); 18*5cd1d3f4STakashi Sakamoto struct snd_interval t = { 19*5cd1d3f4STakashi Sakamoto .min = UINT_MAX, .max = 0, .integer = 1 203713d93aSTakashi Sakamoto }; 21*5cd1d3f4STakashi Sakamoto struct snd_oxfw_stream_formation formation; 22*5cd1d3f4STakashi Sakamoto unsigned int i, err; 233713d93aSTakashi Sakamoto 24*5cd1d3f4STakashi Sakamoto for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) { 25*5cd1d3f4STakashi Sakamoto if (formats[i] == NULL) 26*5cd1d3f4STakashi Sakamoto continue; 273713d93aSTakashi Sakamoto 28*5cd1d3f4STakashi Sakamoto err = snd_oxfw_stream_parse_format(formats[i], &formation); 293713d93aSTakashi Sakamoto if (err < 0) 30*5cd1d3f4STakashi Sakamoto continue; 31*5cd1d3f4STakashi Sakamoto if (!snd_interval_test(c, formation.pcm)) 32*5cd1d3f4STakashi Sakamoto continue; 333713d93aSTakashi Sakamoto 34*5cd1d3f4STakashi Sakamoto t.min = min(t.min, formation.rate); 35*5cd1d3f4STakashi Sakamoto t.max = max(t.max, formation.rate); 36*5cd1d3f4STakashi Sakamoto 37*5cd1d3f4STakashi Sakamoto } 38*5cd1d3f4STakashi Sakamoto return snd_interval_refine(r, &t); 393713d93aSTakashi Sakamoto } 403713d93aSTakashi Sakamoto 41*5cd1d3f4STakashi Sakamoto static int hw_rule_channels(struct snd_pcm_hw_params *params, 42*5cd1d3f4STakashi Sakamoto struct snd_pcm_hw_rule *rule) 433713d93aSTakashi Sakamoto { 44*5cd1d3f4STakashi Sakamoto u8 **formats = rule->private; 45*5cd1d3f4STakashi Sakamoto struct snd_interval *c = 46*5cd1d3f4STakashi Sakamoto hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); 47*5cd1d3f4STakashi Sakamoto const struct snd_interval *r = 48*5cd1d3f4STakashi Sakamoto hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE); 49*5cd1d3f4STakashi Sakamoto struct snd_oxfw_stream_formation formation; 50*5cd1d3f4STakashi Sakamoto unsigned int i, j, err; 51*5cd1d3f4STakashi Sakamoto unsigned int count, list[SND_OXFW_STREAM_FORMAT_ENTRIES] = {0}; 523713d93aSTakashi Sakamoto 53*5cd1d3f4STakashi Sakamoto count = 0; 54*5cd1d3f4STakashi Sakamoto for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) { 55*5cd1d3f4STakashi Sakamoto if (formats[i] == NULL) 56*5cd1d3f4STakashi Sakamoto break; 57*5cd1d3f4STakashi Sakamoto 58*5cd1d3f4STakashi Sakamoto err = snd_oxfw_stream_parse_format(formats[i], &formation); 59*5cd1d3f4STakashi Sakamoto if (err < 0) 60*5cd1d3f4STakashi Sakamoto continue; 61*5cd1d3f4STakashi Sakamoto if (!snd_interval_test(r, formation.rate)) 62*5cd1d3f4STakashi Sakamoto continue; 63*5cd1d3f4STakashi Sakamoto if (list[count] == formation.pcm) 64*5cd1d3f4STakashi Sakamoto continue; 65*5cd1d3f4STakashi Sakamoto 66*5cd1d3f4STakashi Sakamoto for (j = 0; j < ARRAY_SIZE(list); j++) { 67*5cd1d3f4STakashi Sakamoto if (list[j] == formation.pcm) 68*5cd1d3f4STakashi Sakamoto break; 69*5cd1d3f4STakashi Sakamoto } 70*5cd1d3f4STakashi Sakamoto if (j == ARRAY_SIZE(list)) { 71*5cd1d3f4STakashi Sakamoto list[count] = formation.pcm; 72*5cd1d3f4STakashi Sakamoto if (++count == ARRAY_SIZE(list)) 73*5cd1d3f4STakashi Sakamoto break; 74*5cd1d3f4STakashi Sakamoto } 75*5cd1d3f4STakashi Sakamoto } 76*5cd1d3f4STakashi Sakamoto 77*5cd1d3f4STakashi Sakamoto return snd_interval_list(c, count, list, 0); 78*5cd1d3f4STakashi Sakamoto } 79*5cd1d3f4STakashi Sakamoto 80*5cd1d3f4STakashi Sakamoto static void limit_channels_and_rates(struct snd_pcm_hardware *hw, u8 **formats) 81*5cd1d3f4STakashi Sakamoto { 82*5cd1d3f4STakashi Sakamoto struct snd_oxfw_stream_formation formation; 83*5cd1d3f4STakashi Sakamoto unsigned int i, err; 84*5cd1d3f4STakashi Sakamoto 85*5cd1d3f4STakashi Sakamoto hw->channels_min = UINT_MAX; 86*5cd1d3f4STakashi Sakamoto hw->channels_max = 0; 87*5cd1d3f4STakashi Sakamoto 88*5cd1d3f4STakashi Sakamoto hw->rate_min = UINT_MAX; 89*5cd1d3f4STakashi Sakamoto hw->rate_max = 0; 90*5cd1d3f4STakashi Sakamoto hw->rates = 0; 91*5cd1d3f4STakashi Sakamoto 92*5cd1d3f4STakashi Sakamoto for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) { 93*5cd1d3f4STakashi Sakamoto if (formats[i] == NULL) 94*5cd1d3f4STakashi Sakamoto break; 95*5cd1d3f4STakashi Sakamoto 96*5cd1d3f4STakashi Sakamoto err = snd_oxfw_stream_parse_format(formats[i], &formation); 97*5cd1d3f4STakashi Sakamoto if (err < 0) 98*5cd1d3f4STakashi Sakamoto continue; 99*5cd1d3f4STakashi Sakamoto 100*5cd1d3f4STakashi Sakamoto hw->channels_min = min(hw->channels_min, formation.pcm); 101*5cd1d3f4STakashi Sakamoto hw->channels_max = max(hw->channels_max, formation.pcm); 102*5cd1d3f4STakashi Sakamoto 103*5cd1d3f4STakashi Sakamoto hw->rate_min = min(hw->rate_min, formation.rate); 104*5cd1d3f4STakashi Sakamoto hw->rate_max = max(hw->rate_max, formation.rate); 105*5cd1d3f4STakashi Sakamoto hw->rates |= snd_pcm_rate_to_rate_bit(formation.rate); 106*5cd1d3f4STakashi Sakamoto } 107*5cd1d3f4STakashi Sakamoto } 108*5cd1d3f4STakashi Sakamoto 109*5cd1d3f4STakashi Sakamoto static void limit_period_and_buffer(struct snd_pcm_hardware *hw) 110*5cd1d3f4STakashi Sakamoto { 111*5cd1d3f4STakashi Sakamoto hw->periods_min = 2; /* SNDRV_PCM_INFO_BATCH */ 112*5cd1d3f4STakashi Sakamoto hw->periods_max = UINT_MAX; 113*5cd1d3f4STakashi Sakamoto 114*5cd1d3f4STakashi Sakamoto hw->period_bytes_min = 4 * hw->channels_max; /* bytes for a frame */ 115*5cd1d3f4STakashi Sakamoto 116*5cd1d3f4STakashi Sakamoto /* Just to prevent from allocating much pages. */ 117*5cd1d3f4STakashi Sakamoto hw->period_bytes_max = hw->period_bytes_min * 2048; 118*5cd1d3f4STakashi Sakamoto hw->buffer_bytes_max = hw->period_bytes_max * hw->periods_min; 1193713d93aSTakashi Sakamoto } 1203713d93aSTakashi Sakamoto 1213713d93aSTakashi Sakamoto static int pcm_open(struct snd_pcm_substream *substream) 1223713d93aSTakashi Sakamoto { 1233713d93aSTakashi Sakamoto struct snd_oxfw *oxfw = substream->private_data; 1243713d93aSTakashi Sakamoto struct snd_pcm_runtime *runtime = substream->runtime; 125*5cd1d3f4STakashi Sakamoto u8 **formats; 1263713d93aSTakashi Sakamoto int err; 1273713d93aSTakashi Sakamoto 128*5cd1d3f4STakashi Sakamoto formats = oxfw->rx_stream_formats; 1293713d93aSTakashi Sakamoto 130*5cd1d3f4STakashi Sakamoto runtime->hw.info = SNDRV_PCM_INFO_BATCH | 131*5cd1d3f4STakashi Sakamoto SNDRV_PCM_INFO_BLOCK_TRANSFER | 132*5cd1d3f4STakashi Sakamoto SNDRV_PCM_INFO_INTERLEAVED | 133*5cd1d3f4STakashi Sakamoto SNDRV_PCM_INFO_MMAP | 134*5cd1d3f4STakashi Sakamoto SNDRV_PCM_INFO_MMAP_VALID; 1353713d93aSTakashi Sakamoto 136*5cd1d3f4STakashi Sakamoto limit_channels_and_rates(&runtime->hw, formats); 137*5cd1d3f4STakashi Sakamoto limit_period_and_buffer(&runtime->hw); 138*5cd1d3f4STakashi Sakamoto 139*5cd1d3f4STakashi Sakamoto err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 140*5cd1d3f4STakashi Sakamoto hw_rule_channels, formats, 141*5cd1d3f4STakashi Sakamoto SNDRV_PCM_HW_PARAM_RATE, -1); 1423713d93aSTakashi Sakamoto if (err < 0) 1433713d93aSTakashi Sakamoto goto end; 144*5cd1d3f4STakashi Sakamoto 145*5cd1d3f4STakashi Sakamoto err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 146*5cd1d3f4STakashi Sakamoto hw_rule_rate, formats, 147*5cd1d3f4STakashi Sakamoto SNDRV_PCM_HW_PARAM_CHANNELS, -1); 1483713d93aSTakashi Sakamoto if (err < 0) 1493713d93aSTakashi Sakamoto goto end; 1503713d93aSTakashi Sakamoto 1513713d93aSTakashi Sakamoto err = amdtp_stream_add_pcm_hw_constraints(&oxfw->rx_stream, runtime); 152*5cd1d3f4STakashi Sakamoto if (err < 0) 153*5cd1d3f4STakashi Sakamoto goto end; 154*5cd1d3f4STakashi Sakamoto 155*5cd1d3f4STakashi Sakamoto snd_pcm_set_sync(substream); 1563713d93aSTakashi Sakamoto end: 1573713d93aSTakashi Sakamoto return err; 1583713d93aSTakashi Sakamoto } 1593713d93aSTakashi Sakamoto 1603713d93aSTakashi Sakamoto static int pcm_close(struct snd_pcm_substream *substream) 1613713d93aSTakashi Sakamoto { 1623713d93aSTakashi Sakamoto return 0; 1633713d93aSTakashi Sakamoto } 1643713d93aSTakashi Sakamoto 1653713d93aSTakashi Sakamoto static int pcm_hw_params(struct snd_pcm_substream *substream, 1663713d93aSTakashi Sakamoto struct snd_pcm_hw_params *hw_params) 1673713d93aSTakashi Sakamoto { 1683713d93aSTakashi Sakamoto struct snd_oxfw *oxfw = substream->private_data; 1693713d93aSTakashi Sakamoto int err; 1703713d93aSTakashi Sakamoto 1713713d93aSTakashi Sakamoto mutex_lock(&oxfw->mutex); 1723713d93aSTakashi Sakamoto 1733713d93aSTakashi Sakamoto snd_oxfw_stream_stop_simplex(oxfw); 1743713d93aSTakashi Sakamoto 1753713d93aSTakashi Sakamoto err = snd_pcm_lib_alloc_vmalloc_buffer(substream, 1763713d93aSTakashi Sakamoto params_buffer_bytes(hw_params)); 1773713d93aSTakashi Sakamoto if (err < 0) 1783713d93aSTakashi Sakamoto goto error; 1793713d93aSTakashi Sakamoto 1803713d93aSTakashi Sakamoto amdtp_stream_set_parameters(&oxfw->rx_stream, 1813713d93aSTakashi Sakamoto params_rate(hw_params), 1823713d93aSTakashi Sakamoto params_channels(hw_params), 1833713d93aSTakashi Sakamoto 0); 1843713d93aSTakashi Sakamoto 1853713d93aSTakashi Sakamoto amdtp_stream_set_pcm_format(&oxfw->rx_stream, 1863713d93aSTakashi Sakamoto params_format(hw_params)); 1873713d93aSTakashi Sakamoto 1883713d93aSTakashi Sakamoto err = avc_general_set_sig_fmt(oxfw->unit, params_rate(hw_params), 1893713d93aSTakashi Sakamoto AVC_GENERAL_PLUG_DIR_IN, 0); 1903713d93aSTakashi Sakamoto if (err < 0) { 1913713d93aSTakashi Sakamoto dev_err(&oxfw->unit->device, "failed to set sample rate\n"); 1923713d93aSTakashi Sakamoto goto err_buffer; 1933713d93aSTakashi Sakamoto } 1943713d93aSTakashi Sakamoto 1953713d93aSTakashi Sakamoto return 0; 1963713d93aSTakashi Sakamoto 1973713d93aSTakashi Sakamoto err_buffer: 1983713d93aSTakashi Sakamoto snd_pcm_lib_free_vmalloc_buffer(substream); 1993713d93aSTakashi Sakamoto error: 2003713d93aSTakashi Sakamoto mutex_unlock(&oxfw->mutex); 2013713d93aSTakashi Sakamoto return err; 2023713d93aSTakashi Sakamoto } 2033713d93aSTakashi Sakamoto 2043713d93aSTakashi Sakamoto static int pcm_hw_free(struct snd_pcm_substream *substream) 2053713d93aSTakashi Sakamoto { 2063713d93aSTakashi Sakamoto struct snd_oxfw *oxfw = substream->private_data; 2073713d93aSTakashi Sakamoto 2083713d93aSTakashi Sakamoto mutex_lock(&oxfw->mutex); 2093713d93aSTakashi Sakamoto snd_oxfw_stream_stop_simplex(oxfw); 2103713d93aSTakashi Sakamoto mutex_unlock(&oxfw->mutex); 2113713d93aSTakashi Sakamoto 2123713d93aSTakashi Sakamoto return snd_pcm_lib_free_vmalloc_buffer(substream); 2133713d93aSTakashi Sakamoto } 2143713d93aSTakashi Sakamoto 2153713d93aSTakashi Sakamoto static int pcm_prepare(struct snd_pcm_substream *substream) 2163713d93aSTakashi Sakamoto { 2173713d93aSTakashi Sakamoto struct snd_oxfw *oxfw = substream->private_data; 2183713d93aSTakashi Sakamoto int err; 2193713d93aSTakashi Sakamoto 2203713d93aSTakashi Sakamoto mutex_lock(&oxfw->mutex); 2213713d93aSTakashi Sakamoto 2223713d93aSTakashi Sakamoto snd_oxfw_stream_stop_simplex(oxfw); 2233713d93aSTakashi Sakamoto 2243713d93aSTakashi Sakamoto err = snd_oxfw_stream_start_simplex(oxfw); 2253713d93aSTakashi Sakamoto if (err < 0) 2263713d93aSTakashi Sakamoto goto end; 2273713d93aSTakashi Sakamoto 2283713d93aSTakashi Sakamoto amdtp_stream_pcm_prepare(&oxfw->rx_stream); 2293713d93aSTakashi Sakamoto end: 2303713d93aSTakashi Sakamoto mutex_unlock(&oxfw->mutex); 2313713d93aSTakashi Sakamoto return err; 2323713d93aSTakashi Sakamoto } 2333713d93aSTakashi Sakamoto 2343713d93aSTakashi Sakamoto static int pcm_trigger(struct snd_pcm_substream *substream, int cmd) 2353713d93aSTakashi Sakamoto { 2363713d93aSTakashi Sakamoto struct snd_oxfw *oxfw = substream->private_data; 2373713d93aSTakashi Sakamoto struct snd_pcm_substream *pcm; 2383713d93aSTakashi Sakamoto 2393713d93aSTakashi Sakamoto switch (cmd) { 2403713d93aSTakashi Sakamoto case SNDRV_PCM_TRIGGER_START: 2413713d93aSTakashi Sakamoto pcm = substream; 2423713d93aSTakashi Sakamoto break; 2433713d93aSTakashi Sakamoto case SNDRV_PCM_TRIGGER_STOP: 2443713d93aSTakashi Sakamoto pcm = NULL; 2453713d93aSTakashi Sakamoto break; 2463713d93aSTakashi Sakamoto default: 2473713d93aSTakashi Sakamoto return -EINVAL; 2483713d93aSTakashi Sakamoto } 2493713d93aSTakashi Sakamoto amdtp_stream_pcm_trigger(&oxfw->rx_stream, pcm); 2503713d93aSTakashi Sakamoto return 0; 2513713d93aSTakashi Sakamoto } 2523713d93aSTakashi Sakamoto 2533713d93aSTakashi Sakamoto static snd_pcm_uframes_t pcm_pointer(struct snd_pcm_substream *substream) 2543713d93aSTakashi Sakamoto { 2553713d93aSTakashi Sakamoto struct snd_oxfw *oxfw = substream->private_data; 2563713d93aSTakashi Sakamoto 2573713d93aSTakashi Sakamoto return amdtp_stream_pcm_pointer(&oxfw->rx_stream); 2583713d93aSTakashi Sakamoto } 2593713d93aSTakashi Sakamoto 2603713d93aSTakashi Sakamoto int snd_oxfw_create_pcm(struct snd_oxfw *oxfw) 2613713d93aSTakashi Sakamoto { 2623713d93aSTakashi Sakamoto static struct snd_pcm_ops ops = { 2633713d93aSTakashi Sakamoto .open = pcm_open, 2643713d93aSTakashi Sakamoto .close = pcm_close, 2653713d93aSTakashi Sakamoto .ioctl = snd_pcm_lib_ioctl, 2663713d93aSTakashi Sakamoto .hw_params = pcm_hw_params, 2673713d93aSTakashi Sakamoto .hw_free = pcm_hw_free, 2683713d93aSTakashi Sakamoto .prepare = pcm_prepare, 2693713d93aSTakashi Sakamoto .trigger = pcm_trigger, 2703713d93aSTakashi Sakamoto .pointer = pcm_pointer, 2713713d93aSTakashi Sakamoto .page = snd_pcm_lib_get_vmalloc_page, 2723713d93aSTakashi Sakamoto .mmap = snd_pcm_lib_mmap_vmalloc, 2733713d93aSTakashi Sakamoto }; 2743713d93aSTakashi Sakamoto struct snd_pcm *pcm; 2753713d93aSTakashi Sakamoto int err; 2763713d93aSTakashi Sakamoto 2773713d93aSTakashi Sakamoto err = snd_pcm_new(oxfw->card, oxfw->card->driver, 0, 1, 0, &pcm); 2783713d93aSTakashi Sakamoto if (err < 0) 2793713d93aSTakashi Sakamoto return err; 2803713d93aSTakashi Sakamoto pcm->private_data = oxfw; 2813713d93aSTakashi Sakamoto strcpy(pcm->name, oxfw->card->shortname); 2823713d93aSTakashi Sakamoto snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &ops); 2833713d93aSTakashi Sakamoto return 0; 2843713d93aSTakashi Sakamoto } 285