0001
0002
0003
0004
0005
0006
0007
0008 #include "./bebob.h"
0009
0010 #define READY_TIMEOUT_MS 4000
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022 #define FORMAT_MAXIMUM_LENGTH 128
0023
0024 const unsigned int snd_bebob_rate_table[SND_BEBOB_STRM_FMT_ENTRIES] = {
0025 [0] = 32000,
0026 [1] = 44100,
0027 [2] = 48000,
0028 [3] = 88200,
0029 [4] = 96000,
0030 [5] = 176400,
0031 [6] = 192000,
0032 };
0033
0034
0035
0036
0037
0038 static const unsigned int bridgeco_freq_table[] = {
0039 [0] = 0x02,
0040 [1] = 0x03,
0041 [2] = 0x04,
0042 [3] = 0x0a,
0043 [4] = 0x05,
0044 [5] = 0x06,
0045 [6] = 0x07,
0046 };
0047
0048 static int
0049 get_formation_index(unsigned int rate, unsigned int *index)
0050 {
0051 unsigned int i;
0052
0053 for (i = 0; i < ARRAY_SIZE(snd_bebob_rate_table); i++) {
0054 if (snd_bebob_rate_table[i] == rate) {
0055 *index = i;
0056 return 0;
0057 }
0058 }
0059 return -EINVAL;
0060 }
0061
0062 int
0063 snd_bebob_stream_get_rate(struct snd_bebob *bebob, unsigned int *curr_rate)
0064 {
0065 unsigned int tx_rate, rx_rate, trials;
0066 int err;
0067
0068 trials = 0;
0069 do {
0070 err = avc_general_get_sig_fmt(bebob->unit, &tx_rate,
0071 AVC_GENERAL_PLUG_DIR_OUT, 0);
0072 } while (err == -EAGAIN && ++trials < 3);
0073 if (err < 0)
0074 goto end;
0075
0076 trials = 0;
0077 do {
0078 err = avc_general_get_sig_fmt(bebob->unit, &rx_rate,
0079 AVC_GENERAL_PLUG_DIR_IN, 0);
0080 } while (err == -EAGAIN && ++trials < 3);
0081 if (err < 0)
0082 goto end;
0083
0084 *curr_rate = rx_rate;
0085 if (rx_rate == tx_rate)
0086 goto end;
0087
0088
0089 err = avc_general_set_sig_fmt(bebob->unit, rx_rate,
0090 AVC_GENERAL_PLUG_DIR_IN, 0);
0091 end:
0092 return err;
0093 }
0094
0095 int
0096 snd_bebob_stream_set_rate(struct snd_bebob *bebob, unsigned int rate)
0097 {
0098 int err;
0099
0100 err = avc_general_set_sig_fmt(bebob->unit, rate,
0101 AVC_GENERAL_PLUG_DIR_OUT, 0);
0102 if (err < 0)
0103 goto end;
0104
0105 err = avc_general_set_sig_fmt(bebob->unit, rate,
0106 AVC_GENERAL_PLUG_DIR_IN, 0);
0107 if (err < 0)
0108 goto end;
0109
0110
0111
0112
0113
0114 msleep(300);
0115 end:
0116 return err;
0117 }
0118
0119 int snd_bebob_stream_get_clock_src(struct snd_bebob *bebob,
0120 enum snd_bebob_clock_type *src)
0121 {
0122 const struct snd_bebob_clock_spec *clk_spec = bebob->spec->clock;
0123 u8 addr[AVC_BRIDGECO_ADDR_BYTES], input[7];
0124 unsigned int id;
0125 enum avc_bridgeco_plug_type type;
0126 int err = 0;
0127
0128
0129 if (clk_spec) {
0130 err = clk_spec->get(bebob, &id);
0131 if (err < 0) {
0132 dev_err(&bebob->unit->device,
0133 "fail to get clock source: %d\n", err);
0134 goto end;
0135 }
0136
0137 if (id >= clk_spec->num) {
0138 dev_err(&bebob->unit->device,
0139 "clock source %d out of range 0..%d\n",
0140 id, clk_spec->num - 1);
0141 err = -EIO;
0142 goto end;
0143 }
0144
0145 *src = clk_spec->types[id];
0146 goto end;
0147 }
0148
0149
0150
0151
0152
0153 if (bebob->sync_input_plug < 0) {
0154 *src = SND_BEBOB_CLOCK_TYPE_INTERNAL;
0155 goto end;
0156 }
0157
0158
0159
0160
0161
0162 avc_bridgeco_fill_msu_addr(addr, AVC_BRIDGECO_PLUG_DIR_IN,
0163 bebob->sync_input_plug);
0164 err = avc_bridgeco_get_plug_input(bebob->unit, addr, input);
0165 if (err < 0) {
0166 dev_err(&bebob->unit->device,
0167 "fail to get an input for MSU in plug %d: %d\n",
0168 bebob->sync_input_plug, err);
0169 goto end;
0170 }
0171
0172
0173
0174
0175
0176 if (input[0] == 0xff) {
0177 *src = SND_BEBOB_CLOCK_TYPE_INTERNAL;
0178 goto end;
0179 }
0180
0181
0182 if (input[0] == AVC_BRIDGECO_PLUG_DIR_OUT) {
0183
0184
0185
0186
0187
0188 if (input[1] == AVC_BRIDGECO_PLUG_MODE_SUBUNIT &&
0189 input[2] == 0x0c) {
0190 *src = SND_BEBOB_CLOCK_TYPE_INTERNAL;
0191 goto end;
0192 }
0193
0194 } else if (input[1] == AVC_BRIDGECO_PLUG_MODE_UNIT) {
0195 if (input[2] == AVC_BRIDGECO_PLUG_UNIT_ISOC) {
0196 if (input[3] == 0x00) {
0197
0198
0199
0200
0201
0202
0203
0204 *src = SND_BEBOB_CLOCK_TYPE_SYT;
0205 goto end;
0206 } else {
0207
0208
0209
0210
0211
0212 *src = SND_BEBOB_CLOCK_TYPE_EXTERNAL;
0213 goto end;
0214 }
0215 } else if (input[2] == AVC_BRIDGECO_PLUG_UNIT_EXT) {
0216
0217 avc_bridgeco_fill_unit_addr(addr,
0218 AVC_BRIDGECO_PLUG_DIR_IN,
0219 AVC_BRIDGECO_PLUG_UNIT_EXT,
0220 input[3]);
0221 err = avc_bridgeco_get_plug_type(bebob->unit, addr,
0222 &type);
0223 if (err < 0)
0224 goto end;
0225
0226 if (type == AVC_BRIDGECO_PLUG_TYPE_DIG) {
0227
0228
0229
0230
0231 *src = SND_BEBOB_CLOCK_TYPE_EXTERNAL;
0232 goto end;
0233 } else if (type == AVC_BRIDGECO_PLUG_TYPE_SYNC) {
0234
0235 *src = SND_BEBOB_CLOCK_TYPE_EXTERNAL;
0236 goto end;
0237 } else if (type == AVC_BRIDGECO_PLUG_TYPE_ADDITION) {
0238
0239
0240
0241
0242 *src = SND_BEBOB_CLOCK_TYPE_INTERNAL;
0243 goto end;
0244 }
0245 }
0246 }
0247
0248
0249 err = -EIO;
0250 end:
0251 return err;
0252 }
0253
0254 static int map_data_channels(struct snd_bebob *bebob, struct amdtp_stream *s)
0255 {
0256 unsigned int sec, sections, ch, channels;
0257 unsigned int pcm, midi, location;
0258 unsigned int stm_pos, sec_loc, pos;
0259 u8 *buf, addr[AVC_BRIDGECO_ADDR_BYTES], type;
0260 enum avc_bridgeco_plug_dir dir;
0261 int err;
0262
0263
0264
0265
0266
0267 buf = kzalloc(256, GFP_KERNEL);
0268 if (buf == NULL)
0269 return -ENOMEM;
0270
0271 if (s == &bebob->tx_stream)
0272 dir = AVC_BRIDGECO_PLUG_DIR_OUT;
0273 else
0274 dir = AVC_BRIDGECO_PLUG_DIR_IN;
0275
0276 avc_bridgeco_fill_unit_addr(addr, dir, AVC_BRIDGECO_PLUG_UNIT_ISOC, 0);
0277 err = avc_bridgeco_get_plug_ch_pos(bebob->unit, addr, buf, 256);
0278 if (err < 0) {
0279 dev_err(&bebob->unit->device,
0280 "fail to get channel position for isoc %s plug 0: %d\n",
0281 (dir == AVC_BRIDGECO_PLUG_DIR_IN) ? "in" : "out",
0282 err);
0283 goto end;
0284 }
0285 pos = 0;
0286
0287
0288 pcm = 0;
0289 midi = 0;
0290
0291
0292 sections = buf[pos++];
0293
0294 for (sec = 0; sec < sections; sec++) {
0295
0296 avc_bridgeco_fill_unit_addr(addr, dir,
0297 AVC_BRIDGECO_PLUG_UNIT_ISOC, 0);
0298 err = avc_bridgeco_get_plug_section_type(bebob->unit, addr,
0299 sec, &type);
0300 if (err < 0) {
0301 dev_err(&bebob->unit->device,
0302 "fail to get section type for isoc %s plug 0: %d\n",
0303 (dir == AVC_BRIDGECO_PLUG_DIR_IN) ? "in" :
0304 "out",
0305 err);
0306 goto end;
0307 }
0308
0309 if (type == 0xff) {
0310 err = -ENOSYS;
0311 goto end;
0312 }
0313
0314
0315 channels = buf[pos++];
0316
0317 for (ch = 0; ch < channels; ch++) {
0318
0319 stm_pos = buf[pos++] - 1;
0320
0321 sec_loc = buf[pos++] - 1;
0322
0323
0324
0325
0326
0327
0328
0329 if (sec_loc >= channels)
0330 sec_loc = ch;
0331
0332 switch (type) {
0333
0334 case 0x0a:
0335
0336 if ((midi > 0) && (stm_pos != midi)) {
0337 err = -ENOSYS;
0338 goto end;
0339 }
0340 amdtp_am824_set_midi_position(s, stm_pos);
0341 midi = stm_pos;
0342 break;
0343
0344 case 0x01:
0345 case 0x02:
0346 case 0x03:
0347 case 0x04:
0348 case 0x05:
0349 case 0x06:
0350 case 0x07:
0351
0352 case 0x08:
0353 case 0x09:
0354 default:
0355 location = pcm + sec_loc;
0356 if (location >= AM824_MAX_CHANNELS_FOR_PCM) {
0357 err = -ENOSYS;
0358 goto end;
0359 }
0360 amdtp_am824_set_pcm_position(s, location,
0361 stm_pos);
0362 break;
0363 }
0364 }
0365
0366 if (type != 0x0a)
0367 pcm += channels;
0368 else
0369 midi += channels;
0370 }
0371 end:
0372 kfree(buf);
0373 return err;
0374 }
0375
0376 static int
0377 check_connection_used_by_others(struct snd_bebob *bebob, struct amdtp_stream *s)
0378 {
0379 struct cmp_connection *conn;
0380 bool used;
0381 int err;
0382
0383 if (s == &bebob->tx_stream)
0384 conn = &bebob->out_conn;
0385 else
0386 conn = &bebob->in_conn;
0387
0388 err = cmp_connection_check_used(conn, &used);
0389 if ((err >= 0) && used && !amdtp_stream_running(s)) {
0390 dev_err(&bebob->unit->device,
0391 "Connection established by others: %cPCR[%d]\n",
0392 (conn->direction == CMP_OUTPUT) ? 'o' : 'i',
0393 conn->pcr_index);
0394 err = -EBUSY;
0395 }
0396
0397 return err;
0398 }
0399
0400 static void break_both_connections(struct snd_bebob *bebob)
0401 {
0402 cmp_connection_break(&bebob->in_conn);
0403 cmp_connection_break(&bebob->out_conn);
0404 }
0405
0406 static int start_stream(struct snd_bebob *bebob, struct amdtp_stream *stream)
0407 {
0408 struct cmp_connection *conn;
0409 int err = 0;
0410
0411 if (stream == &bebob->rx_stream)
0412 conn = &bebob->in_conn;
0413 else
0414 conn = &bebob->out_conn;
0415
0416
0417 if (bebob->maudio_special_quirk == NULL) {
0418 err = map_data_channels(bebob, stream);
0419 if (err < 0)
0420 return err;
0421 }
0422
0423 err = cmp_connection_establish(conn);
0424 if (err < 0)
0425 return err;
0426
0427 return amdtp_domain_add_stream(&bebob->domain, stream,
0428 conn->resources.channel, conn->speed);
0429 }
0430
0431 static int init_stream(struct snd_bebob *bebob, struct amdtp_stream *stream)
0432 {
0433 unsigned int flags = CIP_BLOCKING;
0434 enum amdtp_stream_direction dir_stream;
0435 struct cmp_connection *conn;
0436 enum cmp_direction dir_conn;
0437 int err;
0438
0439 if (stream == &bebob->tx_stream) {
0440 dir_stream = AMDTP_IN_STREAM;
0441 conn = &bebob->out_conn;
0442 dir_conn = CMP_OUTPUT;
0443 } else {
0444 dir_stream = AMDTP_OUT_STREAM;
0445 conn = &bebob->in_conn;
0446 dir_conn = CMP_INPUT;
0447 }
0448
0449 if (stream == &bebob->tx_stream) {
0450 if (bebob->quirks & SND_BEBOB_QUIRK_WRONG_DBC)
0451 flags |= CIP_EMPTY_HAS_WRONG_DBC;
0452 }
0453
0454 err = cmp_connection_init(conn, bebob->unit, dir_conn, 0);
0455 if (err < 0)
0456 return err;
0457
0458 err = amdtp_am824_init(stream, bebob->unit, dir_stream, flags);
0459 if (err < 0) {
0460 cmp_connection_destroy(conn);
0461 return err;
0462 }
0463
0464 return 0;
0465 }
0466
0467 static void destroy_stream(struct snd_bebob *bebob, struct amdtp_stream *stream)
0468 {
0469 amdtp_stream_destroy(stream);
0470
0471 if (stream == &bebob->tx_stream)
0472 cmp_connection_destroy(&bebob->out_conn);
0473 else
0474 cmp_connection_destroy(&bebob->in_conn);
0475 }
0476
0477 int snd_bebob_stream_init_duplex(struct snd_bebob *bebob)
0478 {
0479 int err;
0480
0481 err = init_stream(bebob, &bebob->tx_stream);
0482 if (err < 0)
0483 return err;
0484
0485 err = init_stream(bebob, &bebob->rx_stream);
0486 if (err < 0) {
0487 destroy_stream(bebob, &bebob->tx_stream);
0488 return err;
0489 }
0490
0491 err = amdtp_domain_init(&bebob->domain);
0492 if (err < 0) {
0493 destroy_stream(bebob, &bebob->tx_stream);
0494 destroy_stream(bebob, &bebob->rx_stream);
0495 }
0496
0497 return err;
0498 }
0499
0500 static int keep_resources(struct snd_bebob *bebob, struct amdtp_stream *stream,
0501 unsigned int rate, unsigned int index)
0502 {
0503 unsigned int pcm_channels;
0504 unsigned int midi_ports;
0505 struct cmp_connection *conn;
0506 int err;
0507
0508 if (stream == &bebob->tx_stream) {
0509 pcm_channels = bebob->tx_stream_formations[index].pcm;
0510 midi_ports = bebob->midi_input_ports;
0511 conn = &bebob->out_conn;
0512 } else {
0513 pcm_channels = bebob->rx_stream_formations[index].pcm;
0514 midi_ports = bebob->midi_output_ports;
0515 conn = &bebob->in_conn;
0516 }
0517
0518 err = amdtp_am824_set_parameters(stream, rate, pcm_channels, midi_ports, false);
0519 if (err < 0)
0520 return err;
0521
0522 return cmp_connection_reserve(conn, amdtp_stream_get_max_payload(stream));
0523 }
0524
0525 int snd_bebob_stream_reserve_duplex(struct snd_bebob *bebob, unsigned int rate,
0526 unsigned int frames_per_period,
0527 unsigned int frames_per_buffer)
0528 {
0529 unsigned int curr_rate;
0530 int err;
0531
0532
0533
0534 err = check_connection_used_by_others(bebob, &bebob->rx_stream);
0535 if (err < 0)
0536 return err;
0537
0538 err = bebob->spec->rate->get(bebob, &curr_rate);
0539 if (err < 0)
0540 return err;
0541 if (rate == 0)
0542 rate = curr_rate;
0543 if (curr_rate != rate) {
0544 amdtp_domain_stop(&bebob->domain);
0545 break_both_connections(bebob);
0546
0547 cmp_connection_release(&bebob->out_conn);
0548 cmp_connection_release(&bebob->in_conn);
0549 }
0550
0551 if (bebob->substreams_counter == 0 || curr_rate != rate) {
0552 unsigned int index;
0553
0554
0555
0556
0557
0558
0559 err = bebob->spec->rate->set(bebob, rate);
0560 if (err < 0) {
0561 dev_err(&bebob->unit->device,
0562 "fail to set sampling rate: %d\n",
0563 err);
0564 return err;
0565 }
0566
0567 err = get_formation_index(rate, &index);
0568 if (err < 0)
0569 return err;
0570
0571 err = keep_resources(bebob, &bebob->tx_stream, rate, index);
0572 if (err < 0)
0573 return err;
0574
0575 err = keep_resources(bebob, &bebob->rx_stream, rate, index);
0576 if (err < 0) {
0577 cmp_connection_release(&bebob->out_conn);
0578 return err;
0579 }
0580
0581 err = amdtp_domain_set_events_per_period(&bebob->domain,
0582 frames_per_period, frames_per_buffer);
0583 if (err < 0) {
0584 cmp_connection_release(&bebob->out_conn);
0585 cmp_connection_release(&bebob->in_conn);
0586 return err;
0587 }
0588 }
0589
0590 return 0;
0591 }
0592
0593 int snd_bebob_stream_start_duplex(struct snd_bebob *bebob)
0594 {
0595 int err;
0596
0597
0598 if (bebob->substreams_counter == 0)
0599 return -EIO;
0600
0601
0602 if (amdtp_streaming_error(&bebob->rx_stream) ||
0603 amdtp_streaming_error(&bebob->tx_stream)) {
0604 amdtp_domain_stop(&bebob->domain);
0605 break_both_connections(bebob);
0606 }
0607
0608 if (!amdtp_stream_running(&bebob->rx_stream)) {
0609 enum snd_bebob_clock_type src;
0610 unsigned int curr_rate;
0611 unsigned int tx_init_skip_cycles;
0612
0613 if (bebob->maudio_special_quirk) {
0614 err = bebob->spec->rate->get(bebob, &curr_rate);
0615 if (err < 0)
0616 return err;
0617 }
0618
0619 err = snd_bebob_stream_get_clock_src(bebob, &src);
0620 if (err < 0)
0621 return err;
0622
0623 err = start_stream(bebob, &bebob->rx_stream);
0624 if (err < 0)
0625 goto error;
0626
0627 err = start_stream(bebob, &bebob->tx_stream);
0628 if (err < 0)
0629 goto error;
0630
0631 if (!(bebob->quirks & SND_BEBOB_QUIRK_INITIAL_DISCONTINUOUS_DBC))
0632 tx_init_skip_cycles = 0;
0633 else
0634 tx_init_skip_cycles = 16000;
0635
0636
0637
0638
0639
0640
0641
0642
0643
0644 err = amdtp_domain_start(&bebob->domain, tx_init_skip_cycles, true, false);
0645 if (err < 0)
0646 goto error;
0647
0648
0649
0650
0651 if (bebob->maudio_special_quirk) {
0652 err = bebob->spec->rate->set(bebob, curr_rate);
0653 if (err < 0) {
0654 dev_err(&bebob->unit->device,
0655 "fail to ensure sampling rate: %d\n",
0656 err);
0657 goto error;
0658 }
0659 }
0660
0661
0662
0663 if (!amdtp_domain_wait_ready(&bebob->domain, READY_TIMEOUT_MS)) {
0664 err = -ETIMEDOUT;
0665 goto error;
0666 }
0667 }
0668
0669 return 0;
0670 error:
0671 amdtp_domain_stop(&bebob->domain);
0672 break_both_connections(bebob);
0673 return err;
0674 }
0675
0676 void snd_bebob_stream_stop_duplex(struct snd_bebob *bebob)
0677 {
0678 if (bebob->substreams_counter == 0) {
0679 amdtp_domain_stop(&bebob->domain);
0680 break_both_connections(bebob);
0681
0682 cmp_connection_release(&bebob->out_conn);
0683 cmp_connection_release(&bebob->in_conn);
0684 }
0685 }
0686
0687
0688
0689
0690
0691 void snd_bebob_stream_destroy_duplex(struct snd_bebob *bebob)
0692 {
0693 amdtp_domain_destroy(&bebob->domain);
0694
0695 destroy_stream(bebob, &bebob->tx_stream);
0696 destroy_stream(bebob, &bebob->rx_stream);
0697 }
0698
0699
0700
0701
0702
0703
0704 static int
0705 parse_stream_formation(u8 *buf, unsigned int len,
0706 struct snd_bebob_stream_formation *formation)
0707 {
0708 unsigned int i, e, channels, format;
0709
0710
0711
0712
0713
0714
0715 if ((buf[0] != 0x90) || (buf[1] != 0x40))
0716 return -ENOSYS;
0717
0718
0719 for (i = 0; i < ARRAY_SIZE(bridgeco_freq_table); i++) {
0720 if (buf[2] == bridgeco_freq_table[i])
0721 break;
0722 }
0723 if (i == ARRAY_SIZE(bridgeco_freq_table))
0724 return -ENOSYS;
0725
0726
0727 memset(&formation[i], 0, sizeof(struct snd_bebob_stream_formation));
0728
0729 for (e = 0; e < buf[4]; e++) {
0730 channels = buf[5 + e * 2];
0731 format = buf[6 + e * 2];
0732
0733 switch (format) {
0734
0735 case 0x00:
0736
0737 case 0x06:
0738 formation[i].pcm += channels;
0739 break;
0740
0741 case 0x0d:
0742 formation[i].midi += channels;
0743 break;
0744
0745 case 0x01:
0746 case 0x02:
0747 case 0x03:
0748 case 0x04:
0749 case 0x05:
0750
0751 case 0x07:
0752 case 0x0c:
0753
0754 case 0x08:
0755 case 0x09:
0756 case 0x0a:
0757 case 0x0b:
0758
0759 case 0x40:
0760
0761 case 0xff:
0762 default:
0763 return -ENOSYS;
0764 }
0765 }
0766
0767 if (formation[i].pcm > AM824_MAX_CHANNELS_FOR_PCM ||
0768 formation[i].midi > AM824_MAX_CHANNELS_FOR_MIDI)
0769 return -ENOSYS;
0770
0771 return 0;
0772 }
0773
0774 static int fill_stream_formations(struct snd_bebob *bebob, u8 addr[AVC_BRIDGECO_ADDR_BYTES],
0775 enum avc_bridgeco_plug_dir plug_dir, unsigned int plug_id,
0776 struct snd_bebob_stream_formation *formations)
0777 {
0778 enum avc_bridgeco_plug_type plug_type;
0779 u8 *buf;
0780 unsigned int len, eid;
0781 int err;
0782
0783 avc_bridgeco_fill_unit_addr(addr, plug_dir, AVC_BRIDGECO_PLUG_UNIT_ISOC, plug_id);
0784
0785 err = avc_bridgeco_get_plug_type(bebob->unit, addr, &plug_type);
0786 if (err < 0) {
0787 dev_err(&bebob->unit->device,
0788 "Fail to get type for isoc %d plug 0: %d\n", plug_dir, err);
0789 return err;
0790 } else if (plug_type != AVC_BRIDGECO_PLUG_TYPE_ISOC)
0791 return -ENXIO;
0792
0793 buf = kmalloc(FORMAT_MAXIMUM_LENGTH, GFP_KERNEL);
0794 if (buf == NULL)
0795 return -ENOMEM;
0796
0797 for (eid = 0; eid < SND_BEBOB_STRM_FMT_ENTRIES; ++eid) {
0798 avc_bridgeco_fill_unit_addr(addr, plug_dir, AVC_BRIDGECO_PLUG_UNIT_ISOC, plug_id);
0799
0800 len = FORMAT_MAXIMUM_LENGTH;
0801 err = avc_bridgeco_get_plug_strm_fmt(bebob->unit, addr, buf, &len, eid);
0802
0803 if (err == -EINVAL && eid > 0) {
0804 err = 0;
0805 break;
0806 } else if (err < 0) {
0807 dev_err(&bebob->unit->device,
0808 "fail to get stream format %d for isoc %d plug %d:%d\n",
0809 eid, plug_dir, plug_id, err);
0810 break;
0811 }
0812
0813 err = parse_stream_formation(buf, len, formations);
0814 if (err < 0)
0815 break;
0816 }
0817
0818 kfree(buf);
0819 return err;
0820 }
0821
0822 static int detect_midi_ports(struct snd_bebob *bebob,
0823 const struct snd_bebob_stream_formation *formats,
0824 u8 addr[AVC_BRIDGECO_ADDR_BYTES], enum avc_bridgeco_plug_dir plug_dir,
0825 unsigned int plug_count, unsigned int *midi_ports)
0826 {
0827 int i;
0828 int err = 0;
0829
0830 *midi_ports = 0;
0831
0832
0833 for (i = 0; i < SND_BEBOB_STRM_FMT_ENTRIES; ++i) {
0834 if (formats[i].midi > 0)
0835 break;
0836 }
0837 if (i >= SND_BEBOB_STRM_FMT_ENTRIES)
0838 return 0;
0839
0840 for (i = 0; i < plug_count; ++i) {
0841 enum avc_bridgeco_plug_type plug_type;
0842 unsigned int ch_count;
0843
0844 avc_bridgeco_fill_unit_addr(addr, plug_dir, AVC_BRIDGECO_PLUG_UNIT_EXT, i);
0845
0846 err = avc_bridgeco_get_plug_type(bebob->unit, addr, &plug_type);
0847 if (err < 0) {
0848 dev_err(&bebob->unit->device,
0849 "fail to get type for external %d plug %d: %d\n",
0850 plug_dir, i, err);
0851 break;
0852 } else if (plug_type != AVC_BRIDGECO_PLUG_TYPE_MIDI) {
0853 continue;
0854 }
0855
0856 err = avc_bridgeco_get_plug_ch_count(bebob->unit, addr, &ch_count);
0857 if (err < 0)
0858 break;
0859
0860
0861
0862 if (ch_count == 0)
0863 ch_count = 1;
0864 *midi_ports += ch_count;
0865 }
0866
0867 return err;
0868 }
0869
0870 static int
0871 seek_msu_sync_input_plug(struct snd_bebob *bebob)
0872 {
0873 u8 plugs[AVC_PLUG_INFO_BUF_BYTES], addr[AVC_BRIDGECO_ADDR_BYTES];
0874 unsigned int i;
0875 enum avc_bridgeco_plug_type type;
0876 int err;
0877
0878
0879 err = avc_general_get_plug_info(bebob->unit, 0x0c, 0x00, 0x00, plugs);
0880 if (err < 0) {
0881 dev_err(&bebob->unit->device,
0882 "fail to get info for MSU in/out plugs: %d\n",
0883 err);
0884 goto end;
0885 }
0886
0887
0888 bebob->sync_input_plug = -1;
0889 for (i = 0; i < plugs[0]; i++) {
0890 avc_bridgeco_fill_msu_addr(addr, AVC_BRIDGECO_PLUG_DIR_IN, i);
0891 err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type);
0892 if (err < 0) {
0893 dev_err(&bebob->unit->device,
0894 "fail to get type for MSU in plug %d: %d\n",
0895 i, err);
0896 goto end;
0897 }
0898
0899 if (type == AVC_BRIDGECO_PLUG_TYPE_SYNC) {
0900 bebob->sync_input_plug = i;
0901 break;
0902 }
0903 }
0904 end:
0905 return err;
0906 }
0907
0908 int snd_bebob_stream_discover(struct snd_bebob *bebob)
0909 {
0910 const struct snd_bebob_clock_spec *clk_spec = bebob->spec->clock;
0911 u8 plugs[AVC_PLUG_INFO_BUF_BYTES], addr[AVC_BRIDGECO_ADDR_BYTES];
0912 int err;
0913
0914
0915 err = avc_general_get_plug_info(bebob->unit, 0x1f, 0x07, 0x00, plugs);
0916 if (err < 0) {
0917 dev_err(&bebob->unit->device,
0918 "fail to get info for isoc/external in/out plugs: %d\n",
0919 err);
0920 goto end;
0921 }
0922
0923
0924
0925
0926
0927 if ((plugs[0] == 0) || (plugs[1] == 0)) {
0928 err = -ENOSYS;
0929 goto end;
0930 }
0931
0932 err = fill_stream_formations(bebob, addr, AVC_BRIDGECO_PLUG_DIR_IN, 0,
0933 bebob->rx_stream_formations);
0934 if (err < 0)
0935 goto end;
0936
0937 err = fill_stream_formations(bebob, addr, AVC_BRIDGECO_PLUG_DIR_OUT, 0,
0938 bebob->tx_stream_formations);
0939 if (err < 0)
0940 goto end;
0941
0942 err = detect_midi_ports(bebob, bebob->tx_stream_formations, addr, AVC_BRIDGECO_PLUG_DIR_IN,
0943 plugs[2], &bebob->midi_input_ports);
0944 if (err < 0)
0945 goto end;
0946
0947 err = detect_midi_ports(bebob, bebob->rx_stream_formations, addr, AVC_BRIDGECO_PLUG_DIR_OUT,
0948 plugs[3], &bebob->midi_output_ports);
0949 if (err < 0)
0950 goto end;
0951
0952
0953 if (!clk_spec)
0954 err = seek_msu_sync_input_plug(bebob);
0955 end:
0956 return err;
0957 }
0958
0959 void snd_bebob_stream_lock_changed(struct snd_bebob *bebob)
0960 {
0961 bebob->dev_lock_changed = true;
0962 wake_up(&bebob->hwdep_wait);
0963 }
0964
0965 int snd_bebob_stream_lock_try(struct snd_bebob *bebob)
0966 {
0967 int err;
0968
0969 spin_lock_irq(&bebob->lock);
0970
0971
0972 if (bebob->dev_lock_count < 0) {
0973 err = -EBUSY;
0974 goto end;
0975 }
0976
0977
0978 if (bebob->dev_lock_count++ == 0)
0979 snd_bebob_stream_lock_changed(bebob);
0980 err = 0;
0981 end:
0982 spin_unlock_irq(&bebob->lock);
0983 return err;
0984 }
0985
0986 void snd_bebob_stream_lock_release(struct snd_bebob *bebob)
0987 {
0988 spin_lock_irq(&bebob->lock);
0989
0990 if (WARN_ON(bebob->dev_lock_count <= 0))
0991 goto end;
0992 if (--bebob->dev_lock_count == 0)
0993 snd_bebob_stream_lock_changed(bebob);
0994 end:
0995 spin_unlock_irq(&bebob->lock);
0996 }