0001
0002
0003
0004
0005
0006
0007
0008 #include "digi00x.h"
0009
0010 #define READY_TIMEOUT_MS 200
0011
0012 const unsigned int snd_dg00x_stream_rates[SND_DG00X_RATE_COUNT] = {
0013 [SND_DG00X_RATE_44100] = 44100,
0014 [SND_DG00X_RATE_48000] = 48000,
0015 [SND_DG00X_RATE_88200] = 88200,
0016 [SND_DG00X_RATE_96000] = 96000,
0017 };
0018
0019
0020 const unsigned int
0021 snd_dg00x_stream_pcm_channels[SND_DG00X_RATE_COUNT] = {
0022
0023 [SND_DG00X_RATE_44100] = (8 + 8 + 2),
0024 [SND_DG00X_RATE_48000] = (8 + 8 + 2),
0025
0026 [SND_DG00X_RATE_88200] = (8 + 2),
0027 [SND_DG00X_RATE_96000] = (8 + 2),
0028 };
0029
0030 int snd_dg00x_stream_get_local_rate(struct snd_dg00x *dg00x, unsigned int *rate)
0031 {
0032 u32 data;
0033 __be32 reg;
0034 int err;
0035
0036 err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST,
0037 DG00X_ADDR_BASE + DG00X_OFFSET_LOCAL_RATE,
0038 ®, sizeof(reg), 0);
0039 if (err < 0)
0040 return err;
0041
0042 data = be32_to_cpu(reg) & 0x0f;
0043 if (data < ARRAY_SIZE(snd_dg00x_stream_rates))
0044 *rate = snd_dg00x_stream_rates[data];
0045 else
0046 err = -EIO;
0047
0048 return err;
0049 }
0050
0051 int snd_dg00x_stream_set_local_rate(struct snd_dg00x *dg00x, unsigned int rate)
0052 {
0053 __be32 reg;
0054 unsigned int i;
0055
0056 for (i = 0; i < ARRAY_SIZE(snd_dg00x_stream_rates); i++) {
0057 if (rate == snd_dg00x_stream_rates[i])
0058 break;
0059 }
0060 if (i == ARRAY_SIZE(snd_dg00x_stream_rates))
0061 return -EINVAL;
0062
0063 reg = cpu_to_be32(i);
0064 return snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
0065 DG00X_ADDR_BASE + DG00X_OFFSET_LOCAL_RATE,
0066 ®, sizeof(reg), 0);
0067 }
0068
0069 int snd_dg00x_stream_get_clock(struct snd_dg00x *dg00x,
0070 enum snd_dg00x_clock *clock)
0071 {
0072 __be32 reg;
0073 int err;
0074
0075 err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST,
0076 DG00X_ADDR_BASE + DG00X_OFFSET_CLOCK_SOURCE,
0077 ®, sizeof(reg), 0);
0078 if (err < 0)
0079 return err;
0080
0081 *clock = be32_to_cpu(reg) & 0x0f;
0082 if (*clock >= SND_DG00X_CLOCK_COUNT)
0083 err = -EIO;
0084
0085 return err;
0086 }
0087
0088 int snd_dg00x_stream_check_external_clock(struct snd_dg00x *dg00x, bool *detect)
0089 {
0090 __be32 reg;
0091 int err;
0092
0093 err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST,
0094 DG00X_ADDR_BASE + DG00X_OFFSET_DETECT_EXTERNAL,
0095 ®, sizeof(reg), 0);
0096 if (err >= 0)
0097 *detect = be32_to_cpu(reg) > 0;
0098
0099 return err;
0100 }
0101
0102 int snd_dg00x_stream_get_external_rate(struct snd_dg00x *dg00x,
0103 unsigned int *rate)
0104 {
0105 u32 data;
0106 __be32 reg;
0107 int err;
0108
0109 err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST,
0110 DG00X_ADDR_BASE + DG00X_OFFSET_EXTERNAL_RATE,
0111 ®, sizeof(reg), 0);
0112 if (err < 0)
0113 return err;
0114
0115 data = be32_to_cpu(reg) & 0x0f;
0116 if (data < ARRAY_SIZE(snd_dg00x_stream_rates))
0117 *rate = snd_dg00x_stream_rates[data];
0118
0119 else
0120 err = -EBUSY;
0121
0122 return err;
0123 }
0124
0125 static void finish_session(struct snd_dg00x *dg00x)
0126 {
0127 __be32 data;
0128
0129 data = cpu_to_be32(0x00000003);
0130 snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
0131 DG00X_ADDR_BASE + DG00X_OFFSET_STREAMING_SET,
0132 &data, sizeof(data), 0);
0133
0134
0135 data = 0;
0136 snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
0137 DG00X_ADDR_BASE + DG00X_OFFSET_ISOC_CHANNELS,
0138 &data, sizeof(data), 0);
0139
0140
0141
0142 msleep(50);
0143 }
0144
0145 static int begin_session(struct snd_dg00x *dg00x)
0146 {
0147 __be32 data;
0148 u32 curr;
0149 int err;
0150
0151
0152 data = cpu_to_be32((dg00x->tx_resources.channel << 16) |
0153 dg00x->rx_resources.channel);
0154 err = snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
0155 DG00X_ADDR_BASE + DG00X_OFFSET_ISOC_CHANNELS,
0156 &data, sizeof(data), 0);
0157 if (err < 0)
0158 return err;
0159
0160 err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST,
0161 DG00X_ADDR_BASE + DG00X_OFFSET_STREAMING_STATE,
0162 &data, sizeof(data), 0);
0163 if (err < 0)
0164 return err;
0165 curr = be32_to_cpu(data);
0166
0167 if (curr == 0)
0168 curr = 2;
0169
0170 curr--;
0171 while (curr > 0) {
0172 data = cpu_to_be32(curr);
0173 err = snd_fw_transaction(dg00x->unit,
0174 TCODE_WRITE_QUADLET_REQUEST,
0175 DG00X_ADDR_BASE +
0176 DG00X_OFFSET_STREAMING_SET,
0177 &data, sizeof(data), 0);
0178 if (err < 0)
0179 break;
0180
0181 msleep(20);
0182 curr--;
0183 }
0184
0185 return err;
0186 }
0187
0188 static int keep_resources(struct snd_dg00x *dg00x, struct amdtp_stream *stream,
0189 unsigned int rate)
0190 {
0191 struct fw_iso_resources *resources;
0192 int i;
0193 int err;
0194
0195
0196 for (i = 0; i < SND_DG00X_RATE_COUNT; i++) {
0197 if (snd_dg00x_stream_rates[i] == rate)
0198 break;
0199 }
0200 if (i == SND_DG00X_RATE_COUNT)
0201 return -EINVAL;
0202
0203 if (stream == &dg00x->tx_stream)
0204 resources = &dg00x->tx_resources;
0205 else
0206 resources = &dg00x->rx_resources;
0207
0208 err = amdtp_dot_set_parameters(stream, rate,
0209 snd_dg00x_stream_pcm_channels[i]);
0210 if (err < 0)
0211 return err;
0212
0213 return fw_iso_resources_allocate(resources,
0214 amdtp_stream_get_max_payload(stream),
0215 fw_parent_device(dg00x->unit)->max_speed);
0216 }
0217
0218 static int init_stream(struct snd_dg00x *dg00x, struct amdtp_stream *s)
0219 {
0220 struct fw_iso_resources *resources;
0221 enum amdtp_stream_direction dir;
0222 int err;
0223
0224 if (s == &dg00x->tx_stream) {
0225 resources = &dg00x->tx_resources;
0226 dir = AMDTP_IN_STREAM;
0227 } else {
0228 resources = &dg00x->rx_resources;
0229 dir = AMDTP_OUT_STREAM;
0230 }
0231
0232 err = fw_iso_resources_init(resources, dg00x->unit);
0233 if (err < 0)
0234 return err;
0235
0236 err = amdtp_dot_init(s, dg00x->unit, dir);
0237 if (err < 0)
0238 fw_iso_resources_destroy(resources);
0239
0240 return err;
0241 }
0242
0243 static void destroy_stream(struct snd_dg00x *dg00x, struct amdtp_stream *s)
0244 {
0245 amdtp_stream_destroy(s);
0246
0247 if (s == &dg00x->tx_stream)
0248 fw_iso_resources_destroy(&dg00x->tx_resources);
0249 else
0250 fw_iso_resources_destroy(&dg00x->rx_resources);
0251 }
0252
0253 int snd_dg00x_stream_init_duplex(struct snd_dg00x *dg00x)
0254 {
0255 int err;
0256
0257 err = init_stream(dg00x, &dg00x->rx_stream);
0258 if (err < 0)
0259 return err;
0260
0261 err = init_stream(dg00x, &dg00x->tx_stream);
0262 if (err < 0)
0263 destroy_stream(dg00x, &dg00x->rx_stream);
0264
0265 err = amdtp_domain_init(&dg00x->domain);
0266 if (err < 0) {
0267 destroy_stream(dg00x, &dg00x->rx_stream);
0268 destroy_stream(dg00x, &dg00x->tx_stream);
0269 }
0270
0271 return err;
0272 }
0273
0274
0275
0276
0277
0278 void snd_dg00x_stream_destroy_duplex(struct snd_dg00x *dg00x)
0279 {
0280 amdtp_domain_destroy(&dg00x->domain);
0281
0282 destroy_stream(dg00x, &dg00x->rx_stream);
0283 destroy_stream(dg00x, &dg00x->tx_stream);
0284 }
0285
0286 int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate,
0287 unsigned int frames_per_period,
0288 unsigned int frames_per_buffer)
0289 {
0290 unsigned int curr_rate;
0291 int err;
0292
0293 err = snd_dg00x_stream_get_local_rate(dg00x, &curr_rate);
0294 if (err < 0)
0295 return err;
0296 if (rate == 0)
0297 rate = curr_rate;
0298
0299 if (dg00x->substreams_counter == 0 || curr_rate != rate) {
0300 amdtp_domain_stop(&dg00x->domain);
0301
0302 finish_session(dg00x);
0303
0304 fw_iso_resources_free(&dg00x->tx_resources);
0305 fw_iso_resources_free(&dg00x->rx_resources);
0306
0307 err = snd_dg00x_stream_set_local_rate(dg00x, rate);
0308 if (err < 0)
0309 return err;
0310
0311 err = keep_resources(dg00x, &dg00x->rx_stream, rate);
0312 if (err < 0)
0313 return err;
0314
0315 err = keep_resources(dg00x, &dg00x->tx_stream, rate);
0316 if (err < 0) {
0317 fw_iso_resources_free(&dg00x->rx_resources);
0318 return err;
0319 }
0320
0321 err = amdtp_domain_set_events_per_period(&dg00x->domain,
0322 frames_per_period, frames_per_buffer);
0323 if (err < 0) {
0324 fw_iso_resources_free(&dg00x->rx_resources);
0325 fw_iso_resources_free(&dg00x->tx_resources);
0326 return err;
0327 }
0328 }
0329
0330 return 0;
0331 }
0332
0333 int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x)
0334 {
0335 unsigned int generation = dg00x->rx_resources.generation;
0336 int err = 0;
0337
0338 if (dg00x->substreams_counter == 0)
0339 return 0;
0340
0341 if (amdtp_streaming_error(&dg00x->tx_stream) ||
0342 amdtp_streaming_error(&dg00x->rx_stream)) {
0343 amdtp_domain_stop(&dg00x->domain);
0344 finish_session(dg00x);
0345 }
0346
0347 if (generation != fw_parent_device(dg00x->unit)->card->generation) {
0348 err = fw_iso_resources_update(&dg00x->tx_resources);
0349 if (err < 0)
0350 goto error;
0351
0352 err = fw_iso_resources_update(&dg00x->rx_resources);
0353 if (err < 0)
0354 goto error;
0355 }
0356
0357
0358
0359
0360
0361 if (!amdtp_stream_running(&dg00x->rx_stream)) {
0362 int spd = fw_parent_device(dg00x->unit)->max_speed;
0363
0364 err = begin_session(dg00x);
0365 if (err < 0)
0366 goto error;
0367
0368 err = amdtp_domain_add_stream(&dg00x->domain, &dg00x->rx_stream,
0369 dg00x->rx_resources.channel, spd);
0370 if (err < 0)
0371 goto error;
0372
0373 err = amdtp_domain_add_stream(&dg00x->domain, &dg00x->tx_stream,
0374 dg00x->tx_resources.channel, spd);
0375 if (err < 0)
0376 goto error;
0377
0378
0379
0380
0381
0382 err = amdtp_domain_start(&dg00x->domain, 0, true, true);
0383 if (err < 0)
0384 goto error;
0385
0386 if (!amdtp_domain_wait_ready(&dg00x->domain, READY_TIMEOUT_MS)) {
0387 err = -ETIMEDOUT;
0388 goto error;
0389 }
0390 }
0391
0392 return 0;
0393 error:
0394 amdtp_domain_stop(&dg00x->domain);
0395 finish_session(dg00x);
0396
0397 return err;
0398 }
0399
0400 void snd_dg00x_stream_stop_duplex(struct snd_dg00x *dg00x)
0401 {
0402 if (dg00x->substreams_counter == 0) {
0403 amdtp_domain_stop(&dg00x->domain);
0404 finish_session(dg00x);
0405
0406 fw_iso_resources_free(&dg00x->tx_resources);
0407 fw_iso_resources_free(&dg00x->rx_resources);
0408 }
0409 }
0410
0411 void snd_dg00x_stream_update_duplex(struct snd_dg00x *dg00x)
0412 {
0413 fw_iso_resources_update(&dg00x->tx_resources);
0414 fw_iso_resources_update(&dg00x->rx_resources);
0415
0416 amdtp_stream_update(&dg00x->tx_stream);
0417 amdtp_stream_update(&dg00x->rx_stream);
0418 }
0419
0420 void snd_dg00x_stream_lock_changed(struct snd_dg00x *dg00x)
0421 {
0422 dg00x->dev_lock_changed = true;
0423 wake_up(&dg00x->hwdep_wait);
0424 }
0425
0426 int snd_dg00x_stream_lock_try(struct snd_dg00x *dg00x)
0427 {
0428 int err;
0429
0430 spin_lock_irq(&dg00x->lock);
0431
0432
0433 if (dg00x->dev_lock_count < 0) {
0434 err = -EBUSY;
0435 goto end;
0436 }
0437
0438
0439 if (dg00x->dev_lock_count++ == 0)
0440 snd_dg00x_stream_lock_changed(dg00x);
0441 err = 0;
0442 end:
0443 spin_unlock_irq(&dg00x->lock);
0444 return err;
0445 }
0446
0447 void snd_dg00x_stream_lock_release(struct snd_dg00x *dg00x)
0448 {
0449 spin_lock_irq(&dg00x->lock);
0450
0451 if (WARN_ON(dg00x->dev_lock_count <= 0))
0452 goto end;
0453 if (--dg00x->dev_lock_count == 0)
0454 snd_dg00x_stream_lock_changed(dg00x);
0455 end:
0456 spin_unlock_irq(&dg00x->lock);
0457 }