1 /* 2 * dice_stream.c - a part of driver for DICE based devices 3 * 4 * Copyright (c) Clemens Ladisch <clemens@ladisch.de> 5 * Copyright (c) 2014 Takashi Sakamoto <o-takashi@sakamocchi.jp> 6 * 7 * Licensed under the terms of the GNU General Public License, version 2. 8 */ 9 10 #include "dice.h" 11 12 const unsigned int snd_dice_rates[SND_DICE_RATES_COUNT] = { 13 /* mode 0 */ 14 [0] = 32000, 15 [1] = 44100, 16 [2] = 48000, 17 /* mode 1 */ 18 [3] = 88200, 19 [4] = 96000, 20 /* mode 2 */ 21 [5] = 176400, 22 [6] = 192000, 23 }; 24 25 int snd_dice_stream_get_rate_mode(struct snd_dice *dice, unsigned int rate, 26 unsigned int *mode) 27 { 28 int i; 29 30 for (i = 0; i < ARRAY_SIZE(snd_dice_rates); i++) { 31 if (!(dice->clock_caps & BIT(i))) 32 continue; 33 if (snd_dice_rates[i] != rate) 34 continue; 35 36 *mode = (i - 1) / 2; 37 return 0; 38 } 39 return -EINVAL; 40 } 41 42 int snd_dice_stream_start_packets(struct snd_dice *dice) 43 { 44 int err; 45 46 if (amdtp_stream_running(&dice->rx_stream)) 47 return 0; 48 49 err = amdtp_stream_start(&dice->rx_stream, dice->rx_resources.channel, 50 fw_parent_device(dice->unit)->max_speed); 51 if (err < 0) 52 return err; 53 54 err = snd_dice_transaction_set_enable(dice); 55 if (err < 0) { 56 amdtp_stream_stop(&dice->rx_stream); 57 return err; 58 } 59 60 return 0; 61 } 62 63 int snd_dice_stream_start(struct snd_dice *dice) 64 { 65 __be32 channel; 66 int err; 67 68 if (!dice->rx_resources.allocated) { 69 err = fw_iso_resources_allocate(&dice->rx_resources, 70 amdtp_stream_get_max_payload(&dice->rx_stream), 71 fw_parent_device(dice->unit)->max_speed); 72 if (err < 0) 73 goto error; 74 75 channel = cpu_to_be32(dice->rx_resources.channel); 76 err = snd_dice_transaction_write_tx(dice, RX_ISOCHRONOUS, 77 &channel, 4); 78 if (err < 0) 79 goto err_resources; 80 } 81 82 err = snd_dice_stream_start_packets(dice); 83 if (err < 0) 84 goto err_rx_channel; 85 86 return 0; 87 88 err_rx_channel: 89 channel = cpu_to_be32((u32)-1); 90 snd_dice_transaction_write_rx(dice, RX_ISOCHRONOUS, &channel, 4); 91 err_resources: 92 fw_iso_resources_free(&dice->rx_resources); 93 error: 94 return err; 95 } 96 97 void snd_dice_stream_stop_packets(struct snd_dice *dice) 98 { 99 if (!amdtp_stream_running(&dice->rx_stream)) 100 return; 101 102 snd_dice_transaction_clear_enable(dice); 103 amdtp_stream_stop(&dice->rx_stream); 104 } 105 106 void snd_dice_stream_stop(struct snd_dice *dice) 107 { 108 __be32 channel; 109 110 snd_dice_stream_stop_packets(dice); 111 112 if (!dice->rx_resources.allocated) 113 return; 114 115 channel = cpu_to_be32((u32)-1); 116 snd_dice_transaction_write_rx(dice, RX_ISOCHRONOUS, &channel, 4); 117 118 fw_iso_resources_free(&dice->rx_resources); 119 } 120 121 int snd_dice_stream_init(struct snd_dice *dice) 122 { 123 int err; 124 125 err = fw_iso_resources_init(&dice->rx_resources, dice->unit); 126 if (err < 0) 127 goto end; 128 dice->rx_resources.channels_mask = 0x00000000ffffffffuLL; 129 130 err = amdtp_stream_init(&dice->rx_stream, dice->unit, AMDTP_OUT_STREAM, 131 CIP_BLOCKING); 132 if (err < 0) 133 goto error; 134 135 err = snd_dice_transaction_set_clock_source(dice, CLOCK_SOURCE_ARX1); 136 if (err < 0) 137 goto error; 138 end: 139 return err; 140 error: 141 amdtp_stream_destroy(&dice->rx_stream); 142 fw_iso_resources_destroy(&dice->rx_resources); 143 return err; 144 } 145 146 void snd_dice_stream_destroy(struct snd_dice *dice) 147 { 148 amdtp_stream_pcm_abort(&dice->rx_stream); 149 snd_dice_stream_stop(dice); 150 amdtp_stream_destroy(&dice->rx_stream); 151 fw_iso_resources_destroy(&dice->rx_resources); 152 } 153 154 void snd_dice_stream_update(struct snd_dice *dice) 155 { 156 /* 157 * On a bus reset, the DICE firmware disables streaming and then goes 158 * off contemplating its own navel for hundreds of milliseconds before 159 * it can react to any of our attempts to reenable streaming. This 160 * means that we lose synchronization anyway, so we force our streams 161 * to stop so that the application can restart them in an orderly 162 * manner. 163 */ 164 dice->global_enabled = false; 165 166 amdtp_stream_pcm_abort(&dice->rx_stream); 167 snd_dice_stream_stop_packets(dice); 168 fw_iso_resources_update(&dice->rx_resources); 169 } 170 171 static void dice_lock_changed(struct snd_dice *dice) 172 { 173 dice->dev_lock_changed = true; 174 wake_up(&dice->hwdep_wait); 175 } 176 177 int snd_dice_stream_lock_try(struct snd_dice *dice) 178 { 179 int err; 180 181 spin_lock_irq(&dice->lock); 182 183 if (dice->dev_lock_count < 0) { 184 err = -EBUSY; 185 goto out; 186 } 187 188 if (dice->dev_lock_count++ == 0) 189 dice_lock_changed(dice); 190 err = 0; 191 out: 192 spin_unlock_irq(&dice->lock); 193 return err; 194 } 195 196 void snd_dice_stream_lock_release(struct snd_dice *dice) 197 { 198 spin_lock_irq(&dice->lock); 199 200 if (WARN_ON(dice->dev_lock_count <= 0)) 201 goto out; 202 203 if (--dice->dev_lock_count == 0) 204 dice_lock_changed(dice); 205 out: 206 spin_unlock_irq(&dice->lock); 207 } 208