1eb7b3a05STakashi Sakamoto /* 2eb7b3a05STakashi Sakamoto * bebob_stream.c - a part of driver for BeBoB based devices 3eb7b3a05STakashi Sakamoto * 4eb7b3a05STakashi Sakamoto * Copyright (c) 2013-2014 Takashi Sakamoto 5eb7b3a05STakashi Sakamoto * 6eb7b3a05STakashi Sakamoto * Licensed under the terms of the GNU General Public License, version 2. 7eb7b3a05STakashi Sakamoto */ 8eb7b3a05STakashi Sakamoto 9eb7b3a05STakashi Sakamoto #include "./bebob.h" 10eb7b3a05STakashi Sakamoto 11eb7b3a05STakashi Sakamoto #define CALLBACK_TIMEOUT 1000 12b6bc8123STakashi Sakamoto #define FW_ISO_RESOURCE_DELAY 1000 13eb7b3a05STakashi Sakamoto 14eb7b3a05STakashi Sakamoto /* 15eb7b3a05STakashi Sakamoto * NOTE; 16eb7b3a05STakashi Sakamoto * For BeBoB streams, Both of input and output CMP connection are important. 17eb7b3a05STakashi Sakamoto * 18eb7b3a05STakashi Sakamoto * For most devices, each CMP connection starts to transmit/receive a 19eb7b3a05STakashi Sakamoto * corresponding stream. But for a few devices, both of CMP connection needs 20eb7b3a05STakashi Sakamoto * to start transmitting stream. An example is 'M-Audio Firewire 410'. 21eb7b3a05STakashi Sakamoto */ 22eb7b3a05STakashi Sakamoto 23eb7b3a05STakashi Sakamoto /* 128 is an arbitrary length but it seems to be enough */ 24eb7b3a05STakashi Sakamoto #define FORMAT_MAXIMUM_LENGTH 128 25eb7b3a05STakashi Sakamoto 26eb7b3a05STakashi Sakamoto const unsigned int snd_bebob_rate_table[SND_BEBOB_STRM_FMT_ENTRIES] = { 27eb7b3a05STakashi Sakamoto [0] = 32000, 28eb7b3a05STakashi Sakamoto [1] = 44100, 29eb7b3a05STakashi Sakamoto [2] = 48000, 30eb7b3a05STakashi Sakamoto [3] = 88200, 31eb7b3a05STakashi Sakamoto [4] = 96000, 32eb7b3a05STakashi Sakamoto [5] = 176400, 33eb7b3a05STakashi Sakamoto [6] = 192000, 34eb7b3a05STakashi Sakamoto }; 35eb7b3a05STakashi Sakamoto 36eb7b3a05STakashi Sakamoto /* 37eb7b3a05STakashi Sakamoto * See: Table 51: Extended Stream Format Info ‘Sampling Frequency’ 38eb7b3a05STakashi Sakamoto * in Additional AVC commands (Nov 2003, BridgeCo) 39eb7b3a05STakashi Sakamoto */ 40eb7b3a05STakashi Sakamoto static const unsigned int bridgeco_freq_table[] = { 41eb7b3a05STakashi Sakamoto [0] = 0x02, 42eb7b3a05STakashi Sakamoto [1] = 0x03, 43eb7b3a05STakashi Sakamoto [2] = 0x04, 44eb7b3a05STakashi Sakamoto [3] = 0x0a, 45eb7b3a05STakashi Sakamoto [4] = 0x05, 46eb7b3a05STakashi Sakamoto [5] = 0x06, 47eb7b3a05STakashi Sakamoto [6] = 0x07, 48eb7b3a05STakashi Sakamoto }; 49eb7b3a05STakashi Sakamoto 50eb7b3a05STakashi Sakamoto static unsigned int 51eb7b3a05STakashi Sakamoto get_formation_index(unsigned int rate) 52eb7b3a05STakashi Sakamoto { 53eb7b3a05STakashi Sakamoto unsigned int i; 54eb7b3a05STakashi Sakamoto 55eb7b3a05STakashi Sakamoto for (i = 0; i < ARRAY_SIZE(snd_bebob_rate_table); i++) { 56eb7b3a05STakashi Sakamoto if (snd_bebob_rate_table[i] == rate) 57eb7b3a05STakashi Sakamoto return i; 58eb7b3a05STakashi Sakamoto } 59eb7b3a05STakashi Sakamoto return -EINVAL; 60eb7b3a05STakashi Sakamoto } 61eb7b3a05STakashi Sakamoto 62eb7b3a05STakashi Sakamoto int 63eb7b3a05STakashi Sakamoto snd_bebob_stream_get_rate(struct snd_bebob *bebob, unsigned int *curr_rate) 64eb7b3a05STakashi Sakamoto { 65eb7b3a05STakashi Sakamoto unsigned int tx_rate, rx_rate, trials; 66eb7b3a05STakashi Sakamoto int err; 67eb7b3a05STakashi Sakamoto 68eb7b3a05STakashi Sakamoto trials = 0; 69eb7b3a05STakashi Sakamoto do { 70eb7b3a05STakashi Sakamoto err = avc_general_get_sig_fmt(bebob->unit, &tx_rate, 71eb7b3a05STakashi Sakamoto AVC_GENERAL_PLUG_DIR_OUT, 0); 72eb7b3a05STakashi Sakamoto } while (err == -EAGAIN && ++trials < 3); 73eb7b3a05STakashi Sakamoto if (err < 0) 74eb7b3a05STakashi Sakamoto goto end; 75eb7b3a05STakashi Sakamoto 76eb7b3a05STakashi Sakamoto trials = 0; 77eb7b3a05STakashi Sakamoto do { 78eb7b3a05STakashi Sakamoto err = avc_general_get_sig_fmt(bebob->unit, &rx_rate, 79eb7b3a05STakashi Sakamoto AVC_GENERAL_PLUG_DIR_IN, 0); 80eb7b3a05STakashi Sakamoto } while (err == -EAGAIN && ++trials < 3); 81eb7b3a05STakashi Sakamoto if (err < 0) 82eb7b3a05STakashi Sakamoto goto end; 83eb7b3a05STakashi Sakamoto 84eb7b3a05STakashi Sakamoto *curr_rate = rx_rate; 85eb7b3a05STakashi Sakamoto if (rx_rate == tx_rate) 86eb7b3a05STakashi Sakamoto goto end; 87eb7b3a05STakashi Sakamoto 88eb7b3a05STakashi Sakamoto /* synchronize receive stream rate to transmit stream rate */ 89eb7b3a05STakashi Sakamoto err = avc_general_set_sig_fmt(bebob->unit, rx_rate, 90eb7b3a05STakashi Sakamoto AVC_GENERAL_PLUG_DIR_IN, 0); 91eb7b3a05STakashi Sakamoto end: 92eb7b3a05STakashi Sakamoto return err; 93eb7b3a05STakashi Sakamoto } 94eb7b3a05STakashi Sakamoto 95eb7b3a05STakashi Sakamoto int 96eb7b3a05STakashi Sakamoto snd_bebob_stream_set_rate(struct snd_bebob *bebob, unsigned int rate) 97eb7b3a05STakashi Sakamoto { 98eb7b3a05STakashi Sakamoto int err; 99eb7b3a05STakashi Sakamoto 100eb7b3a05STakashi Sakamoto err = avc_general_set_sig_fmt(bebob->unit, rate, 101eb7b3a05STakashi Sakamoto AVC_GENERAL_PLUG_DIR_OUT, 0); 102eb7b3a05STakashi Sakamoto if (err < 0) 103eb7b3a05STakashi Sakamoto goto end; 104eb7b3a05STakashi Sakamoto 105eb7b3a05STakashi Sakamoto err = avc_general_set_sig_fmt(bebob->unit, rate, 106eb7b3a05STakashi Sakamoto AVC_GENERAL_PLUG_DIR_IN, 0); 107eb7b3a05STakashi Sakamoto if (err < 0) 108eb7b3a05STakashi Sakamoto goto end; 109eb7b3a05STakashi Sakamoto 110eb7b3a05STakashi Sakamoto /* 111eb7b3a05STakashi Sakamoto * Some devices need a bit time for transition. 112eb7b3a05STakashi Sakamoto * 300msec is got by some experiments. 113eb7b3a05STakashi Sakamoto */ 114eb7b3a05STakashi Sakamoto msleep(300); 115eb7b3a05STakashi Sakamoto end: 116eb7b3a05STakashi Sakamoto return err; 117eb7b3a05STakashi Sakamoto } 118eb7b3a05STakashi Sakamoto 119eb7b3a05STakashi Sakamoto int 120eb7b3a05STakashi Sakamoto snd_bebob_stream_check_internal_clock(struct snd_bebob *bebob, bool *internal) 121eb7b3a05STakashi Sakamoto { 122eb7b3a05STakashi Sakamoto u8 addr[AVC_BRIDGECO_ADDR_BYTES], input[7]; 123eb7b3a05STakashi Sakamoto int err = 0; 124eb7b3a05STakashi Sakamoto 125eb7b3a05STakashi Sakamoto *internal = false; 126eb7b3a05STakashi Sakamoto 127eb7b3a05STakashi Sakamoto /* 128eb7b3a05STakashi Sakamoto * 1.The device don't support to switch source of clock then assumed 129eb7b3a05STakashi Sakamoto * to use internal clock always 130eb7b3a05STakashi Sakamoto */ 131eb7b3a05STakashi Sakamoto if (bebob->sync_input_plug < 0) { 132eb7b3a05STakashi Sakamoto *internal = true; 133eb7b3a05STakashi Sakamoto goto end; 134eb7b3a05STakashi Sakamoto } 135eb7b3a05STakashi Sakamoto 136eb7b3a05STakashi Sakamoto /* 137eb7b3a05STakashi Sakamoto * 2.The device supports to switch source of clock by an usual way. 138eb7b3a05STakashi Sakamoto * Let's check input for 'Music Sub Unit Sync Input' plug. 139eb7b3a05STakashi Sakamoto */ 140eb7b3a05STakashi Sakamoto avc_bridgeco_fill_msu_addr(addr, AVC_BRIDGECO_PLUG_DIR_IN, 141eb7b3a05STakashi Sakamoto bebob->sync_input_plug); 142eb7b3a05STakashi Sakamoto err = avc_bridgeco_get_plug_input(bebob->unit, addr, input); 143eb7b3a05STakashi Sakamoto if (err < 0) { 144eb7b3a05STakashi Sakamoto dev_err(&bebob->unit->device, 145eb7b3a05STakashi Sakamoto "fail to get an input for MSU in plug %d: %d\n", 146eb7b3a05STakashi Sakamoto bebob->sync_input_plug, err); 147eb7b3a05STakashi Sakamoto goto end; 148eb7b3a05STakashi Sakamoto } 149eb7b3a05STakashi Sakamoto 150eb7b3a05STakashi Sakamoto /* 151eb7b3a05STakashi Sakamoto * If there are no input plugs, all of fields are 0xff. 152eb7b3a05STakashi Sakamoto * Here check the first field. This field is used for direction. 153eb7b3a05STakashi Sakamoto */ 154eb7b3a05STakashi Sakamoto if (input[0] == 0xff) { 155eb7b3a05STakashi Sakamoto *internal = true; 156eb7b3a05STakashi Sakamoto goto end; 157eb7b3a05STakashi Sakamoto } 158eb7b3a05STakashi Sakamoto 159eb7b3a05STakashi Sakamoto /* 160eb7b3a05STakashi Sakamoto * If source of clock is internal CSR, Music Sub Unit Sync Input is 161eb7b3a05STakashi Sakamoto * a destination of Music Sub Unit Sync Output. 162eb7b3a05STakashi Sakamoto */ 163eb7b3a05STakashi Sakamoto *internal = ((input[0] == AVC_BRIDGECO_PLUG_DIR_OUT) && 164eb7b3a05STakashi Sakamoto (input[1] == AVC_BRIDGECO_PLUG_MODE_SUBUNIT) && 165eb7b3a05STakashi Sakamoto (input[2] == 0x0c) && 166eb7b3a05STakashi Sakamoto (input[3] == 0x00)); 167eb7b3a05STakashi Sakamoto end: 168eb7b3a05STakashi Sakamoto return err; 169eb7b3a05STakashi Sakamoto } 170eb7b3a05STakashi Sakamoto 171eb7b3a05STakashi Sakamoto static unsigned int 172eb7b3a05STakashi Sakamoto map_data_channels(struct snd_bebob *bebob, struct amdtp_stream *s) 173eb7b3a05STakashi Sakamoto { 174eb7b3a05STakashi Sakamoto unsigned int sec, sections, ch, channels; 175eb7b3a05STakashi Sakamoto unsigned int pcm, midi, location; 176eb7b3a05STakashi Sakamoto unsigned int stm_pos, sec_loc, pos; 177eb7b3a05STakashi Sakamoto u8 *buf, addr[AVC_BRIDGECO_ADDR_BYTES], type; 178eb7b3a05STakashi Sakamoto enum avc_bridgeco_plug_dir dir; 179eb7b3a05STakashi Sakamoto int err; 180eb7b3a05STakashi Sakamoto 181eb7b3a05STakashi Sakamoto /* 182eb7b3a05STakashi Sakamoto * The length of return value of this command cannot be expected. Here 183eb7b3a05STakashi Sakamoto * use the maximum length of FCP. 184eb7b3a05STakashi Sakamoto */ 185eb7b3a05STakashi Sakamoto buf = kzalloc(256, GFP_KERNEL); 186eb7b3a05STakashi Sakamoto if (buf == NULL) 187eb7b3a05STakashi Sakamoto return -ENOMEM; 188eb7b3a05STakashi Sakamoto 189eb7b3a05STakashi Sakamoto if (s == &bebob->tx_stream) 190eb7b3a05STakashi Sakamoto dir = AVC_BRIDGECO_PLUG_DIR_OUT; 191eb7b3a05STakashi Sakamoto else 192eb7b3a05STakashi Sakamoto dir = AVC_BRIDGECO_PLUG_DIR_IN; 193eb7b3a05STakashi Sakamoto 194eb7b3a05STakashi Sakamoto avc_bridgeco_fill_unit_addr(addr, dir, AVC_BRIDGECO_PLUG_UNIT_ISOC, 0); 195eb7b3a05STakashi Sakamoto err = avc_bridgeco_get_plug_ch_pos(bebob->unit, addr, buf, 256); 196eb7b3a05STakashi Sakamoto if (err < 0) { 197eb7b3a05STakashi Sakamoto dev_err(&bebob->unit->device, 198eb7b3a05STakashi Sakamoto "fail to get channel position for isoc %s plug 0: %d\n", 199eb7b3a05STakashi Sakamoto (dir == AVC_BRIDGECO_PLUG_DIR_IN) ? "in" : "out", 200eb7b3a05STakashi Sakamoto err); 201eb7b3a05STakashi Sakamoto goto end; 202eb7b3a05STakashi Sakamoto } 203eb7b3a05STakashi Sakamoto pos = 0; 204eb7b3a05STakashi Sakamoto 205eb7b3a05STakashi Sakamoto /* positions in I/O buffer */ 206eb7b3a05STakashi Sakamoto pcm = 0; 207eb7b3a05STakashi Sakamoto midi = 0; 208eb7b3a05STakashi Sakamoto 209eb7b3a05STakashi Sakamoto /* the number of sections in AMDTP packet */ 210eb7b3a05STakashi Sakamoto sections = buf[pos++]; 211eb7b3a05STakashi Sakamoto 212eb7b3a05STakashi Sakamoto for (sec = 0; sec < sections; sec++) { 213eb7b3a05STakashi Sakamoto /* type of this section */ 214eb7b3a05STakashi Sakamoto avc_bridgeco_fill_unit_addr(addr, dir, 215eb7b3a05STakashi Sakamoto AVC_BRIDGECO_PLUG_UNIT_ISOC, 0); 216eb7b3a05STakashi Sakamoto err = avc_bridgeco_get_plug_section_type(bebob->unit, addr, 217eb7b3a05STakashi Sakamoto sec, &type); 218eb7b3a05STakashi Sakamoto if (err < 0) { 219eb7b3a05STakashi Sakamoto dev_err(&bebob->unit->device, 220eb7b3a05STakashi Sakamoto "fail to get section type for isoc %s plug 0: %d\n", 221eb7b3a05STakashi Sakamoto (dir == AVC_BRIDGECO_PLUG_DIR_IN) ? "in" : 222eb7b3a05STakashi Sakamoto "out", 223eb7b3a05STakashi Sakamoto err); 224eb7b3a05STakashi Sakamoto goto end; 225eb7b3a05STakashi Sakamoto } 226eb7b3a05STakashi Sakamoto /* NoType */ 227eb7b3a05STakashi Sakamoto if (type == 0xff) { 228eb7b3a05STakashi Sakamoto err = -ENOSYS; 229eb7b3a05STakashi Sakamoto goto end; 230eb7b3a05STakashi Sakamoto } 231eb7b3a05STakashi Sakamoto 232eb7b3a05STakashi Sakamoto /* the number of channels in this section */ 233eb7b3a05STakashi Sakamoto channels = buf[pos++]; 234eb7b3a05STakashi Sakamoto 235eb7b3a05STakashi Sakamoto for (ch = 0; ch < channels; ch++) { 236eb7b3a05STakashi Sakamoto /* position of this channel in AMDTP packet */ 237eb7b3a05STakashi Sakamoto stm_pos = buf[pos++] - 1; 238eb7b3a05STakashi Sakamoto /* location of this channel in this section */ 239eb7b3a05STakashi Sakamoto sec_loc = buf[pos++] - 1; 240eb7b3a05STakashi Sakamoto 241eb7b3a05STakashi Sakamoto switch (type) { 242eb7b3a05STakashi Sakamoto /* for MIDI conformant data channel */ 243eb7b3a05STakashi Sakamoto case 0x0a: 244eb7b3a05STakashi Sakamoto /* AMDTP_MAX_CHANNELS_FOR_MIDI is 1. */ 245eb7b3a05STakashi Sakamoto if ((midi > 0) && (stm_pos != midi)) { 246eb7b3a05STakashi Sakamoto err = -ENOSYS; 247eb7b3a05STakashi Sakamoto goto end; 248eb7b3a05STakashi Sakamoto } 249eb7b3a05STakashi Sakamoto s->midi_position = stm_pos; 250eb7b3a05STakashi Sakamoto midi = stm_pos; 251eb7b3a05STakashi Sakamoto break; 252eb7b3a05STakashi Sakamoto /* for PCM data channel */ 253eb7b3a05STakashi Sakamoto case 0x01: /* Headphone */ 254eb7b3a05STakashi Sakamoto case 0x02: /* Microphone */ 255eb7b3a05STakashi Sakamoto case 0x03: /* Line */ 256eb7b3a05STakashi Sakamoto case 0x04: /* SPDIF */ 257eb7b3a05STakashi Sakamoto case 0x05: /* ADAT */ 258eb7b3a05STakashi Sakamoto case 0x06: /* TDIF */ 259eb7b3a05STakashi Sakamoto case 0x07: /* MADI */ 260eb7b3a05STakashi Sakamoto /* for undefined/changeable signal */ 261eb7b3a05STakashi Sakamoto case 0x08: /* Analog */ 262eb7b3a05STakashi Sakamoto case 0x09: /* Digital */ 263eb7b3a05STakashi Sakamoto default: 264eb7b3a05STakashi Sakamoto location = pcm + sec_loc; 265eb7b3a05STakashi Sakamoto if (location >= AMDTP_MAX_CHANNELS_FOR_PCM) { 266eb7b3a05STakashi Sakamoto err = -ENOSYS; 267eb7b3a05STakashi Sakamoto goto end; 268eb7b3a05STakashi Sakamoto } 269eb7b3a05STakashi Sakamoto s->pcm_positions[location] = stm_pos; 270eb7b3a05STakashi Sakamoto break; 271eb7b3a05STakashi Sakamoto } 272eb7b3a05STakashi Sakamoto } 273eb7b3a05STakashi Sakamoto 274eb7b3a05STakashi Sakamoto if (type != 0x0a) 275eb7b3a05STakashi Sakamoto pcm += channels; 276eb7b3a05STakashi Sakamoto else 277eb7b3a05STakashi Sakamoto midi += channels; 278eb7b3a05STakashi Sakamoto } 279eb7b3a05STakashi Sakamoto end: 280eb7b3a05STakashi Sakamoto kfree(buf); 281eb7b3a05STakashi Sakamoto return err; 282eb7b3a05STakashi Sakamoto } 283eb7b3a05STakashi Sakamoto 284eb7b3a05STakashi Sakamoto static int 285eb7b3a05STakashi Sakamoto init_both_connections(struct snd_bebob *bebob) 286eb7b3a05STakashi Sakamoto { 287eb7b3a05STakashi Sakamoto int err; 288eb7b3a05STakashi Sakamoto 289eb7b3a05STakashi Sakamoto err = cmp_connection_init(&bebob->in_conn, 290eb7b3a05STakashi Sakamoto bebob->unit, CMP_INPUT, 0); 291eb7b3a05STakashi Sakamoto if (err < 0) 292eb7b3a05STakashi Sakamoto goto end; 293eb7b3a05STakashi Sakamoto 294eb7b3a05STakashi Sakamoto err = cmp_connection_init(&bebob->out_conn, 295eb7b3a05STakashi Sakamoto bebob->unit, CMP_OUTPUT, 0); 296eb7b3a05STakashi Sakamoto if (err < 0) 297eb7b3a05STakashi Sakamoto cmp_connection_destroy(&bebob->in_conn); 298eb7b3a05STakashi Sakamoto end: 299eb7b3a05STakashi Sakamoto return err; 300eb7b3a05STakashi Sakamoto } 301eb7b3a05STakashi Sakamoto 302eb7b3a05STakashi Sakamoto static int 303eb7b3a05STakashi Sakamoto check_connection_used_by_others(struct snd_bebob *bebob, struct amdtp_stream *s) 304eb7b3a05STakashi Sakamoto { 305eb7b3a05STakashi Sakamoto struct cmp_connection *conn; 306eb7b3a05STakashi Sakamoto bool used; 307eb7b3a05STakashi Sakamoto int err; 308eb7b3a05STakashi Sakamoto 309eb7b3a05STakashi Sakamoto if (s == &bebob->tx_stream) 310eb7b3a05STakashi Sakamoto conn = &bebob->out_conn; 311eb7b3a05STakashi Sakamoto else 312eb7b3a05STakashi Sakamoto conn = &bebob->in_conn; 313eb7b3a05STakashi Sakamoto 314eb7b3a05STakashi Sakamoto err = cmp_connection_check_used(conn, &used); 315eb7b3a05STakashi Sakamoto if ((err >= 0) && used && !amdtp_stream_running(s)) { 316eb7b3a05STakashi Sakamoto dev_err(&bebob->unit->device, 317eb7b3a05STakashi Sakamoto "Connection established by others: %cPCR[%d]\n", 318eb7b3a05STakashi Sakamoto (conn->direction == CMP_OUTPUT) ? 'o' : 'i', 319eb7b3a05STakashi Sakamoto conn->pcr_index); 320eb7b3a05STakashi Sakamoto err = -EBUSY; 321eb7b3a05STakashi Sakamoto } 322eb7b3a05STakashi Sakamoto 323eb7b3a05STakashi Sakamoto return err; 324eb7b3a05STakashi Sakamoto } 325eb7b3a05STakashi Sakamoto 326eb7b3a05STakashi Sakamoto static int 327eb7b3a05STakashi Sakamoto make_both_connections(struct snd_bebob *bebob, unsigned int rate) 328eb7b3a05STakashi Sakamoto { 329b6bc8123STakashi Sakamoto int index, pcm_channels, midi_channels, err = 0; 330b6bc8123STakashi Sakamoto 331b6bc8123STakashi Sakamoto if (bebob->connected) 332b6bc8123STakashi Sakamoto goto end; 333eb7b3a05STakashi Sakamoto 334eb7b3a05STakashi Sakamoto /* confirm params for both streams */ 335eb7b3a05STakashi Sakamoto index = get_formation_index(rate); 336eb7b3a05STakashi Sakamoto pcm_channels = bebob->tx_stream_formations[index].pcm; 337eb7b3a05STakashi Sakamoto midi_channels = bebob->tx_stream_formations[index].midi; 338eb7b3a05STakashi Sakamoto amdtp_stream_set_parameters(&bebob->tx_stream, 339eb7b3a05STakashi Sakamoto rate, pcm_channels, midi_channels * 8); 340eb7b3a05STakashi Sakamoto pcm_channels = bebob->rx_stream_formations[index].pcm; 341eb7b3a05STakashi Sakamoto midi_channels = bebob->rx_stream_formations[index].midi; 342eb7b3a05STakashi Sakamoto amdtp_stream_set_parameters(&bebob->rx_stream, 343eb7b3a05STakashi Sakamoto rate, pcm_channels, midi_channels * 8); 344eb7b3a05STakashi Sakamoto 345eb7b3a05STakashi Sakamoto /* establish connections for both streams */ 346eb7b3a05STakashi Sakamoto err = cmp_connection_establish(&bebob->out_conn, 347eb7b3a05STakashi Sakamoto amdtp_stream_get_max_payload(&bebob->tx_stream)); 348eb7b3a05STakashi Sakamoto if (err < 0) 349eb7b3a05STakashi Sakamoto goto end; 350eb7b3a05STakashi Sakamoto err = cmp_connection_establish(&bebob->in_conn, 351eb7b3a05STakashi Sakamoto amdtp_stream_get_max_payload(&bebob->rx_stream)); 352b6bc8123STakashi Sakamoto if (err < 0) { 353eb7b3a05STakashi Sakamoto cmp_connection_break(&bebob->out_conn); 354b6bc8123STakashi Sakamoto goto end; 355b6bc8123STakashi Sakamoto } 356b6bc8123STakashi Sakamoto 357b6bc8123STakashi Sakamoto bebob->connected = true; 358eb7b3a05STakashi Sakamoto end: 359eb7b3a05STakashi Sakamoto return err; 360eb7b3a05STakashi Sakamoto } 361eb7b3a05STakashi Sakamoto 362eb7b3a05STakashi Sakamoto static void 363eb7b3a05STakashi Sakamoto break_both_connections(struct snd_bebob *bebob) 364eb7b3a05STakashi Sakamoto { 365eb7b3a05STakashi Sakamoto cmp_connection_break(&bebob->in_conn); 366eb7b3a05STakashi Sakamoto cmp_connection_break(&bebob->out_conn); 367b6bc8123STakashi Sakamoto 368b6bc8123STakashi Sakamoto bebob->connected = false; 369eb7b3a05STakashi Sakamoto } 370eb7b3a05STakashi Sakamoto 371eb7b3a05STakashi Sakamoto static void 372eb7b3a05STakashi Sakamoto destroy_both_connections(struct snd_bebob *bebob) 373eb7b3a05STakashi Sakamoto { 374eb7b3a05STakashi Sakamoto break_both_connections(bebob); 375eb7b3a05STakashi Sakamoto 376eb7b3a05STakashi Sakamoto cmp_connection_destroy(&bebob->in_conn); 377eb7b3a05STakashi Sakamoto cmp_connection_destroy(&bebob->out_conn); 378eb7b3a05STakashi Sakamoto } 379eb7b3a05STakashi Sakamoto 380eb7b3a05STakashi Sakamoto static int 381eb7b3a05STakashi Sakamoto get_sync_mode(struct snd_bebob *bebob, enum cip_flags *sync_mode) 382eb7b3a05STakashi Sakamoto { 383eb7b3a05STakashi Sakamoto /* currently this module doesn't support SYT-Match mode */ 384eb7b3a05STakashi Sakamoto *sync_mode = CIP_SYNC_TO_DEVICE; 385eb7b3a05STakashi Sakamoto return 0; 386eb7b3a05STakashi Sakamoto } 387eb7b3a05STakashi Sakamoto 388eb7b3a05STakashi Sakamoto static int 389eb7b3a05STakashi Sakamoto start_stream(struct snd_bebob *bebob, struct amdtp_stream *stream, 390eb7b3a05STakashi Sakamoto unsigned int rate) 391eb7b3a05STakashi Sakamoto { 392eb7b3a05STakashi Sakamoto struct cmp_connection *conn; 393eb7b3a05STakashi Sakamoto int err = 0; 394eb7b3a05STakashi Sakamoto 395eb7b3a05STakashi Sakamoto if (stream == &bebob->rx_stream) 396eb7b3a05STakashi Sakamoto conn = &bebob->in_conn; 397eb7b3a05STakashi Sakamoto else 398eb7b3a05STakashi Sakamoto conn = &bebob->out_conn; 399eb7b3a05STakashi Sakamoto 400eb7b3a05STakashi Sakamoto /* channel mapping */ 401eb7b3a05STakashi Sakamoto err = map_data_channels(bebob, stream); 402eb7b3a05STakashi Sakamoto if (err < 0) 403eb7b3a05STakashi Sakamoto goto end; 404eb7b3a05STakashi Sakamoto 405eb7b3a05STakashi Sakamoto /* start amdtp stream */ 406eb7b3a05STakashi Sakamoto err = amdtp_stream_start(stream, 407eb7b3a05STakashi Sakamoto conn->resources.channel, 408eb7b3a05STakashi Sakamoto conn->speed); 409eb7b3a05STakashi Sakamoto end: 410eb7b3a05STakashi Sakamoto return err; 411eb7b3a05STakashi Sakamoto } 412eb7b3a05STakashi Sakamoto 413eb7b3a05STakashi Sakamoto int snd_bebob_stream_init_duplex(struct snd_bebob *bebob) 414eb7b3a05STakashi Sakamoto { 415eb7b3a05STakashi Sakamoto int err; 416eb7b3a05STakashi Sakamoto 417eb7b3a05STakashi Sakamoto err = init_both_connections(bebob); 418eb7b3a05STakashi Sakamoto if (err < 0) 419eb7b3a05STakashi Sakamoto goto end; 420eb7b3a05STakashi Sakamoto 421eb7b3a05STakashi Sakamoto err = amdtp_stream_init(&bebob->tx_stream, bebob->unit, 422eb7b3a05STakashi Sakamoto AMDTP_IN_STREAM, CIP_BLOCKING); 423eb7b3a05STakashi Sakamoto if (err < 0) { 424eb7b3a05STakashi Sakamoto amdtp_stream_destroy(&bebob->tx_stream); 425eb7b3a05STakashi Sakamoto destroy_both_connections(bebob); 426eb7b3a05STakashi Sakamoto goto end; 427eb7b3a05STakashi Sakamoto } 428b6bc8123STakashi Sakamoto /* See comments in next function */ 429b6bc8123STakashi Sakamoto init_completion(&bebob->bus_reset); 430b6bc8123STakashi Sakamoto bebob->tx_stream.flags |= CIP_SKIP_INIT_DBC_CHECK; 431eb7b3a05STakashi Sakamoto 432eb7b3a05STakashi Sakamoto err = amdtp_stream_init(&bebob->rx_stream, bebob->unit, 433eb7b3a05STakashi Sakamoto AMDTP_OUT_STREAM, CIP_BLOCKING); 434eb7b3a05STakashi Sakamoto if (err < 0) { 435eb7b3a05STakashi Sakamoto amdtp_stream_destroy(&bebob->tx_stream); 436eb7b3a05STakashi Sakamoto amdtp_stream_destroy(&bebob->rx_stream); 437eb7b3a05STakashi Sakamoto destroy_both_connections(bebob); 438eb7b3a05STakashi Sakamoto } 439eb7b3a05STakashi Sakamoto end: 440eb7b3a05STakashi Sakamoto return err; 441eb7b3a05STakashi Sakamoto } 442eb7b3a05STakashi Sakamoto 443eb7b3a05STakashi Sakamoto int snd_bebob_stream_start_duplex(struct snd_bebob *bebob, int rate) 444eb7b3a05STakashi Sakamoto { 445eb7b3a05STakashi Sakamoto struct amdtp_stream *master, *slave; 446eb7b3a05STakashi Sakamoto atomic_t *slave_substreams; 447eb7b3a05STakashi Sakamoto enum cip_flags sync_mode; 448eb7b3a05STakashi Sakamoto unsigned int curr_rate; 449b6bc8123STakashi Sakamoto bool updated = false; 450eb7b3a05STakashi Sakamoto int err = 0; 451eb7b3a05STakashi Sakamoto 452b6bc8123STakashi Sakamoto /* 453b6bc8123STakashi Sakamoto * Normal BeBoB firmware has a quirk at bus reset to transmits packets 454b6bc8123STakashi Sakamoto * with discontinuous value in dbc field. 455b6bc8123STakashi Sakamoto * 456b6bc8123STakashi Sakamoto * This 'struct completion' is used to call .update() at first to update 457b6bc8123STakashi Sakamoto * connections/streams. Next following codes handle streaming error. 458b6bc8123STakashi Sakamoto */ 459b6bc8123STakashi Sakamoto if (amdtp_streaming_error(&bebob->tx_stream)) { 460b6bc8123STakashi Sakamoto if (completion_done(&bebob->bus_reset)) 461b6bc8123STakashi Sakamoto reinit_completion(&bebob->bus_reset); 462b6bc8123STakashi Sakamoto 463b6bc8123STakashi Sakamoto updated = (wait_for_completion_interruptible_timeout( 464b6bc8123STakashi Sakamoto &bebob->bus_reset, 465b6bc8123STakashi Sakamoto msecs_to_jiffies(FW_ISO_RESOURCE_DELAY)) > 0); 466b6bc8123STakashi Sakamoto } 467b6bc8123STakashi Sakamoto 468eb7b3a05STakashi Sakamoto mutex_lock(&bebob->mutex); 469eb7b3a05STakashi Sakamoto 470eb7b3a05STakashi Sakamoto /* Need no substreams */ 471eb7b3a05STakashi Sakamoto if (atomic_read(&bebob->playback_substreams) == 0 && 472eb7b3a05STakashi Sakamoto atomic_read(&bebob->capture_substreams) == 0) 473eb7b3a05STakashi Sakamoto goto end; 474eb7b3a05STakashi Sakamoto 475eb7b3a05STakashi Sakamoto err = get_sync_mode(bebob, &sync_mode); 476eb7b3a05STakashi Sakamoto if (err < 0) 477eb7b3a05STakashi Sakamoto goto end; 478eb7b3a05STakashi Sakamoto if (sync_mode == CIP_SYNC_TO_DEVICE) { 479eb7b3a05STakashi Sakamoto master = &bebob->tx_stream; 480eb7b3a05STakashi Sakamoto slave = &bebob->rx_stream; 481eb7b3a05STakashi Sakamoto slave_substreams = &bebob->playback_substreams; 482eb7b3a05STakashi Sakamoto } else { 483eb7b3a05STakashi Sakamoto master = &bebob->rx_stream; 484eb7b3a05STakashi Sakamoto slave = &bebob->tx_stream; 485eb7b3a05STakashi Sakamoto slave_substreams = &bebob->capture_substreams; 486eb7b3a05STakashi Sakamoto } 487eb7b3a05STakashi Sakamoto 488eb7b3a05STakashi Sakamoto /* 489eb7b3a05STakashi Sakamoto * Considering JACK/FFADO streaming: 490eb7b3a05STakashi Sakamoto * TODO: This can be removed hwdep functionality becomes popular. 491eb7b3a05STakashi Sakamoto */ 492eb7b3a05STakashi Sakamoto err = check_connection_used_by_others(bebob, master); 493eb7b3a05STakashi Sakamoto if (err < 0) 494eb7b3a05STakashi Sakamoto goto end; 495eb7b3a05STakashi Sakamoto 496b6bc8123STakashi Sakamoto /* 497b6bc8123STakashi Sakamoto * packet queueing error or detecting discontinuity 498b6bc8123STakashi Sakamoto * 499b6bc8123STakashi Sakamoto * At bus reset, connections should not be broken here. So streams need 500b6bc8123STakashi Sakamoto * to be re-started. This is a reason to use SKIP_INIT_DBC_CHECK flag. 501b6bc8123STakashi Sakamoto */ 502b6bc8123STakashi Sakamoto if (amdtp_streaming_error(master)) 503eb7b3a05STakashi Sakamoto amdtp_stream_stop(master); 504eb7b3a05STakashi Sakamoto if (amdtp_streaming_error(slave)) 505eb7b3a05STakashi Sakamoto amdtp_stream_stop(slave); 506b6bc8123STakashi Sakamoto if (!updated && 507b6bc8123STakashi Sakamoto !amdtp_stream_running(master) && !amdtp_stream_running(slave)) 508b6bc8123STakashi Sakamoto break_both_connections(bebob); 509eb7b3a05STakashi Sakamoto 510eb7b3a05STakashi Sakamoto /* stop streams if rate is different */ 511eb7b3a05STakashi Sakamoto err = snd_bebob_stream_get_rate(bebob, &curr_rate); 512eb7b3a05STakashi Sakamoto if (err < 0) { 513eb7b3a05STakashi Sakamoto dev_err(&bebob->unit->device, 514eb7b3a05STakashi Sakamoto "fail to get sampling rate: %d\n", err); 515eb7b3a05STakashi Sakamoto goto end; 516eb7b3a05STakashi Sakamoto } 517eb7b3a05STakashi Sakamoto if (rate == 0) 518eb7b3a05STakashi Sakamoto rate = curr_rate; 519eb7b3a05STakashi Sakamoto if (rate != curr_rate) { 520eb7b3a05STakashi Sakamoto amdtp_stream_stop(master); 521eb7b3a05STakashi Sakamoto amdtp_stream_stop(slave); 522eb7b3a05STakashi Sakamoto break_both_connections(bebob); 523eb7b3a05STakashi Sakamoto } 524eb7b3a05STakashi Sakamoto 525eb7b3a05STakashi Sakamoto /* master should be always running */ 526eb7b3a05STakashi Sakamoto if (!amdtp_stream_running(master)) { 527eb7b3a05STakashi Sakamoto amdtp_stream_set_sync(sync_mode, master, slave); 528eb7b3a05STakashi Sakamoto bebob->master = master; 529eb7b3a05STakashi Sakamoto 530eb7b3a05STakashi Sakamoto /* 531eb7b3a05STakashi Sakamoto * NOTE: 532eb7b3a05STakashi Sakamoto * If establishing connections at first, Yamaha GO46 533eb7b3a05STakashi Sakamoto * (and maybe Terratec X24) don't generate sound. 534eb7b3a05STakashi Sakamoto */ 535eb7b3a05STakashi Sakamoto err = snd_bebob_stream_set_rate(bebob, rate); 536eb7b3a05STakashi Sakamoto if (err < 0) { 537eb7b3a05STakashi Sakamoto dev_err(&bebob->unit->device, 538eb7b3a05STakashi Sakamoto "fail to set sampling rate: %d\n", 539eb7b3a05STakashi Sakamoto err); 540eb7b3a05STakashi Sakamoto goto end; 541eb7b3a05STakashi Sakamoto } 542eb7b3a05STakashi Sakamoto 543eb7b3a05STakashi Sakamoto err = make_both_connections(bebob, rate); 544eb7b3a05STakashi Sakamoto if (err < 0) 545eb7b3a05STakashi Sakamoto goto end; 546eb7b3a05STakashi Sakamoto 547eb7b3a05STakashi Sakamoto err = start_stream(bebob, master, rate); 548eb7b3a05STakashi Sakamoto if (err < 0) { 549eb7b3a05STakashi Sakamoto dev_err(&bebob->unit->device, 550eb7b3a05STakashi Sakamoto "fail to run AMDTP master stream:%d\n", err); 551eb7b3a05STakashi Sakamoto break_both_connections(bebob); 552eb7b3a05STakashi Sakamoto goto end; 553eb7b3a05STakashi Sakamoto } 554eb7b3a05STakashi Sakamoto 555eb7b3a05STakashi Sakamoto /* wait first callback */ 556eb7b3a05STakashi Sakamoto if (!amdtp_stream_wait_callback(master, CALLBACK_TIMEOUT)) { 557eb7b3a05STakashi Sakamoto amdtp_stream_stop(master); 558eb7b3a05STakashi Sakamoto break_both_connections(bebob); 559eb7b3a05STakashi Sakamoto err = -ETIMEDOUT; 560eb7b3a05STakashi Sakamoto goto end; 561eb7b3a05STakashi Sakamoto } 562eb7b3a05STakashi Sakamoto } 563eb7b3a05STakashi Sakamoto 564eb7b3a05STakashi Sakamoto /* start slave if needed */ 565eb7b3a05STakashi Sakamoto if (atomic_read(slave_substreams) > 0 && !amdtp_stream_running(slave)) { 566eb7b3a05STakashi Sakamoto err = start_stream(bebob, slave, rate); 567eb7b3a05STakashi Sakamoto if (err < 0) { 568eb7b3a05STakashi Sakamoto dev_err(&bebob->unit->device, 569eb7b3a05STakashi Sakamoto "fail to run AMDTP slave stream:%d\n", err); 570eb7b3a05STakashi Sakamoto amdtp_stream_stop(master); 571eb7b3a05STakashi Sakamoto break_both_connections(bebob); 572eb7b3a05STakashi Sakamoto goto end; 573eb7b3a05STakashi Sakamoto } 574eb7b3a05STakashi Sakamoto 575eb7b3a05STakashi Sakamoto /* wait first callback */ 576eb7b3a05STakashi Sakamoto if (!amdtp_stream_wait_callback(slave, CALLBACK_TIMEOUT)) { 577eb7b3a05STakashi Sakamoto amdtp_stream_stop(slave); 578eb7b3a05STakashi Sakamoto amdtp_stream_stop(master); 579eb7b3a05STakashi Sakamoto break_both_connections(bebob); 580eb7b3a05STakashi Sakamoto err = -ETIMEDOUT; 581eb7b3a05STakashi Sakamoto } 582eb7b3a05STakashi Sakamoto } 583eb7b3a05STakashi Sakamoto end: 584eb7b3a05STakashi Sakamoto mutex_unlock(&bebob->mutex); 585eb7b3a05STakashi Sakamoto return err; 586eb7b3a05STakashi Sakamoto } 587eb7b3a05STakashi Sakamoto 588eb7b3a05STakashi Sakamoto void snd_bebob_stream_stop_duplex(struct snd_bebob *bebob) 589eb7b3a05STakashi Sakamoto { 590eb7b3a05STakashi Sakamoto struct amdtp_stream *master, *slave; 591eb7b3a05STakashi Sakamoto atomic_t *master_substreams, *slave_substreams; 592eb7b3a05STakashi Sakamoto 593eb7b3a05STakashi Sakamoto mutex_lock(&bebob->mutex); 594eb7b3a05STakashi Sakamoto 595eb7b3a05STakashi Sakamoto if (bebob->master == &bebob->rx_stream) { 596eb7b3a05STakashi Sakamoto slave = &bebob->tx_stream; 597eb7b3a05STakashi Sakamoto master = &bebob->rx_stream; 598eb7b3a05STakashi Sakamoto slave_substreams = &bebob->capture_substreams; 599eb7b3a05STakashi Sakamoto master_substreams = &bebob->playback_substreams; 600eb7b3a05STakashi Sakamoto } else { 601eb7b3a05STakashi Sakamoto slave = &bebob->rx_stream; 602eb7b3a05STakashi Sakamoto master = &bebob->tx_stream; 603eb7b3a05STakashi Sakamoto slave_substreams = &bebob->playback_substreams; 604eb7b3a05STakashi Sakamoto master_substreams = &bebob->capture_substreams; 605eb7b3a05STakashi Sakamoto } 606eb7b3a05STakashi Sakamoto 607eb7b3a05STakashi Sakamoto if (atomic_read(slave_substreams) == 0) { 608eb7b3a05STakashi Sakamoto amdtp_stream_pcm_abort(slave); 609eb7b3a05STakashi Sakamoto amdtp_stream_stop(slave); 610eb7b3a05STakashi Sakamoto 611eb7b3a05STakashi Sakamoto if (atomic_read(master_substreams) == 0) { 612eb7b3a05STakashi Sakamoto amdtp_stream_pcm_abort(master); 613eb7b3a05STakashi Sakamoto amdtp_stream_stop(master); 614eb7b3a05STakashi Sakamoto break_both_connections(bebob); 615eb7b3a05STakashi Sakamoto } 616eb7b3a05STakashi Sakamoto } 617eb7b3a05STakashi Sakamoto 618eb7b3a05STakashi Sakamoto mutex_unlock(&bebob->mutex); 619eb7b3a05STakashi Sakamoto } 620eb7b3a05STakashi Sakamoto 621eb7b3a05STakashi Sakamoto void snd_bebob_stream_update_duplex(struct snd_bebob *bebob) 622eb7b3a05STakashi Sakamoto { 623eb7b3a05STakashi Sakamoto /* vs. XRUN recovery due to discontinuity at bus reset */ 624eb7b3a05STakashi Sakamoto mutex_lock(&bebob->mutex); 625eb7b3a05STakashi Sakamoto 626eb7b3a05STakashi Sakamoto if ((cmp_connection_update(&bebob->in_conn) < 0) || 627eb7b3a05STakashi Sakamoto (cmp_connection_update(&bebob->out_conn) < 0)) { 628eb7b3a05STakashi Sakamoto amdtp_stream_pcm_abort(&bebob->rx_stream); 629eb7b3a05STakashi Sakamoto amdtp_stream_pcm_abort(&bebob->tx_stream); 630eb7b3a05STakashi Sakamoto amdtp_stream_stop(&bebob->rx_stream); 631eb7b3a05STakashi Sakamoto amdtp_stream_stop(&bebob->tx_stream); 632eb7b3a05STakashi Sakamoto break_both_connections(bebob); 633eb7b3a05STakashi Sakamoto } else { 634eb7b3a05STakashi Sakamoto amdtp_stream_update(&bebob->rx_stream); 635eb7b3a05STakashi Sakamoto amdtp_stream_update(&bebob->tx_stream); 636eb7b3a05STakashi Sakamoto } 637eb7b3a05STakashi Sakamoto 638b6bc8123STakashi Sakamoto /* wake up stream_start_duplex() */ 639b6bc8123STakashi Sakamoto if (!completion_done(&bebob->bus_reset)) 640b6bc8123STakashi Sakamoto complete_all(&bebob->bus_reset); 641b6bc8123STakashi Sakamoto 642eb7b3a05STakashi Sakamoto mutex_unlock(&bebob->mutex); 643eb7b3a05STakashi Sakamoto } 644eb7b3a05STakashi Sakamoto 645eb7b3a05STakashi Sakamoto void snd_bebob_stream_destroy_duplex(struct snd_bebob *bebob) 646eb7b3a05STakashi Sakamoto { 647eb7b3a05STakashi Sakamoto mutex_lock(&bebob->mutex); 648eb7b3a05STakashi Sakamoto 649eb7b3a05STakashi Sakamoto amdtp_stream_pcm_abort(&bebob->rx_stream); 650eb7b3a05STakashi Sakamoto amdtp_stream_pcm_abort(&bebob->tx_stream); 651eb7b3a05STakashi Sakamoto 652eb7b3a05STakashi Sakamoto amdtp_stream_stop(&bebob->rx_stream); 653eb7b3a05STakashi Sakamoto amdtp_stream_stop(&bebob->tx_stream); 654eb7b3a05STakashi Sakamoto 655eb7b3a05STakashi Sakamoto amdtp_stream_destroy(&bebob->rx_stream); 656eb7b3a05STakashi Sakamoto amdtp_stream_destroy(&bebob->tx_stream); 657eb7b3a05STakashi Sakamoto 658eb7b3a05STakashi Sakamoto destroy_both_connections(bebob); 659eb7b3a05STakashi Sakamoto 660eb7b3a05STakashi Sakamoto mutex_unlock(&bebob->mutex); 661eb7b3a05STakashi Sakamoto } 662eb7b3a05STakashi Sakamoto 663eb7b3a05STakashi Sakamoto /* 664eb7b3a05STakashi Sakamoto * See: Table 50: Extended Stream Format Info Format Hierarchy Level 2’ 665eb7b3a05STakashi Sakamoto * in Additional AVC commands (Nov 2003, BridgeCo) 666eb7b3a05STakashi Sakamoto * Also 'Clause 12 AM824 sequence adaption layers' in IEC 61883-6:2005 667eb7b3a05STakashi Sakamoto */ 668eb7b3a05STakashi Sakamoto static int 669eb7b3a05STakashi Sakamoto parse_stream_formation(u8 *buf, unsigned int len, 670eb7b3a05STakashi Sakamoto struct snd_bebob_stream_formation *formation) 671eb7b3a05STakashi Sakamoto { 672eb7b3a05STakashi Sakamoto unsigned int i, e, channels, format; 673eb7b3a05STakashi Sakamoto 674eb7b3a05STakashi Sakamoto /* 675eb7b3a05STakashi Sakamoto * this module can support a hierarchy combination that: 676eb7b3a05STakashi Sakamoto * Root: Audio and Music (0x90) 677eb7b3a05STakashi Sakamoto * Level 1: AM824 Compound (0x40) 678eb7b3a05STakashi Sakamoto */ 679eb7b3a05STakashi Sakamoto if ((buf[0] != 0x90) || (buf[1] != 0x40)) 680eb7b3a05STakashi Sakamoto return -ENOSYS; 681eb7b3a05STakashi Sakamoto 682eb7b3a05STakashi Sakamoto /* check sampling rate */ 683eb7b3a05STakashi Sakamoto for (i = 0; i < ARRAY_SIZE(bridgeco_freq_table); i++) { 684eb7b3a05STakashi Sakamoto if (buf[2] == bridgeco_freq_table[i]) 685eb7b3a05STakashi Sakamoto break; 686eb7b3a05STakashi Sakamoto } 687eb7b3a05STakashi Sakamoto if (i == sizeof(bridgeco_freq_table)) 688eb7b3a05STakashi Sakamoto return -ENOSYS; 689eb7b3a05STakashi Sakamoto 690eb7b3a05STakashi Sakamoto /* Avoid double count by different entries for the same rate. */ 691eb7b3a05STakashi Sakamoto memset(&formation[i], 0, sizeof(struct snd_bebob_stream_formation)); 692eb7b3a05STakashi Sakamoto 693eb7b3a05STakashi Sakamoto for (e = 0; e < buf[4]; e++) { 694eb7b3a05STakashi Sakamoto channels = buf[5 + e * 2]; 695eb7b3a05STakashi Sakamoto format = buf[6 + e * 2]; 696eb7b3a05STakashi Sakamoto 697eb7b3a05STakashi Sakamoto switch (format) { 698eb7b3a05STakashi Sakamoto /* IEC 60958-3, currently handle as MBLA */ 699eb7b3a05STakashi Sakamoto case 0x00: 700eb7b3a05STakashi Sakamoto /* Multi bit linear audio */ 701eb7b3a05STakashi Sakamoto case 0x06: /* Raw */ 702eb7b3a05STakashi Sakamoto formation[i].pcm += channels; 703eb7b3a05STakashi Sakamoto break; 704eb7b3a05STakashi Sakamoto /* MIDI Conformant */ 705eb7b3a05STakashi Sakamoto case 0x0d: 706eb7b3a05STakashi Sakamoto formation[i].midi += channels; 707eb7b3a05STakashi Sakamoto break; 708eb7b3a05STakashi Sakamoto /* IEC 61937-3 to 7 */ 709eb7b3a05STakashi Sakamoto case 0x01: 710eb7b3a05STakashi Sakamoto case 0x02: 711eb7b3a05STakashi Sakamoto case 0x03: 712eb7b3a05STakashi Sakamoto case 0x04: 713eb7b3a05STakashi Sakamoto case 0x05: 714eb7b3a05STakashi Sakamoto /* Multi bit linear audio */ 715eb7b3a05STakashi Sakamoto case 0x07: /* DVD-Audio */ 716eb7b3a05STakashi Sakamoto case 0x0c: /* High Precision */ 717eb7b3a05STakashi Sakamoto /* One Bit Audio */ 718eb7b3a05STakashi Sakamoto case 0x08: /* (Plain) Raw */ 719eb7b3a05STakashi Sakamoto case 0x09: /* (Plain) SACD */ 720eb7b3a05STakashi Sakamoto case 0x0a: /* (Encoded) Raw */ 721eb7b3a05STakashi Sakamoto case 0x0b: /* (Encoded) SACD */ 722eb7b3a05STakashi Sakamoto /* Synchronization Stream (Stereo Raw audio) */ 723eb7b3a05STakashi Sakamoto case 0x40: 724eb7b3a05STakashi Sakamoto /* Don't care */ 725eb7b3a05STakashi Sakamoto case 0xff: 726eb7b3a05STakashi Sakamoto default: 727eb7b3a05STakashi Sakamoto return -ENOSYS; /* not supported */ 728eb7b3a05STakashi Sakamoto } 729eb7b3a05STakashi Sakamoto } 730eb7b3a05STakashi Sakamoto 731eb7b3a05STakashi Sakamoto if (formation[i].pcm > AMDTP_MAX_CHANNELS_FOR_PCM || 732eb7b3a05STakashi Sakamoto formation[i].midi > AMDTP_MAX_CHANNELS_FOR_MIDI) 733eb7b3a05STakashi Sakamoto return -ENOSYS; 734eb7b3a05STakashi Sakamoto 735eb7b3a05STakashi Sakamoto return 0; 736eb7b3a05STakashi Sakamoto } 737eb7b3a05STakashi Sakamoto 738eb7b3a05STakashi Sakamoto static int 739eb7b3a05STakashi Sakamoto fill_stream_formations(struct snd_bebob *bebob, enum avc_bridgeco_plug_dir dir, 740eb7b3a05STakashi Sakamoto unsigned short pid) 741eb7b3a05STakashi Sakamoto { 742eb7b3a05STakashi Sakamoto u8 *buf; 743eb7b3a05STakashi Sakamoto struct snd_bebob_stream_formation *formations; 744eb7b3a05STakashi Sakamoto unsigned int len, eid; 745eb7b3a05STakashi Sakamoto u8 addr[AVC_BRIDGECO_ADDR_BYTES]; 746eb7b3a05STakashi Sakamoto int err; 747eb7b3a05STakashi Sakamoto 748eb7b3a05STakashi Sakamoto buf = kmalloc(FORMAT_MAXIMUM_LENGTH, GFP_KERNEL); 749eb7b3a05STakashi Sakamoto if (buf == NULL) 750eb7b3a05STakashi Sakamoto return -ENOMEM; 751eb7b3a05STakashi Sakamoto 752eb7b3a05STakashi Sakamoto if (dir == AVC_BRIDGECO_PLUG_DIR_IN) 753eb7b3a05STakashi Sakamoto formations = bebob->rx_stream_formations; 754eb7b3a05STakashi Sakamoto else 755eb7b3a05STakashi Sakamoto formations = bebob->tx_stream_formations; 756eb7b3a05STakashi Sakamoto 757eb7b3a05STakashi Sakamoto for (eid = 0; eid < SND_BEBOB_STRM_FMT_ENTRIES; eid++) { 758eb7b3a05STakashi Sakamoto len = FORMAT_MAXIMUM_LENGTH; 759eb7b3a05STakashi Sakamoto avc_bridgeco_fill_unit_addr(addr, dir, 760eb7b3a05STakashi Sakamoto AVC_BRIDGECO_PLUG_UNIT_ISOC, pid); 761eb7b3a05STakashi Sakamoto err = avc_bridgeco_get_plug_strm_fmt(bebob->unit, addr, buf, 762eb7b3a05STakashi Sakamoto &len, eid); 763eb7b3a05STakashi Sakamoto /* No entries remained. */ 764eb7b3a05STakashi Sakamoto if (err == -EINVAL && eid > 0) { 765eb7b3a05STakashi Sakamoto err = 0; 766eb7b3a05STakashi Sakamoto break; 767eb7b3a05STakashi Sakamoto } else if (err < 0) { 768eb7b3a05STakashi Sakamoto dev_err(&bebob->unit->device, 769eb7b3a05STakashi Sakamoto "fail to get stream format %d for isoc %s plug %d:%d\n", 770eb7b3a05STakashi Sakamoto eid, 771eb7b3a05STakashi Sakamoto (dir == AVC_BRIDGECO_PLUG_DIR_IN) ? "in" : 772eb7b3a05STakashi Sakamoto "out", 773eb7b3a05STakashi Sakamoto pid, err); 774eb7b3a05STakashi Sakamoto break; 775eb7b3a05STakashi Sakamoto } 776eb7b3a05STakashi Sakamoto 777eb7b3a05STakashi Sakamoto err = parse_stream_formation(buf, len, formations); 778eb7b3a05STakashi Sakamoto if (err < 0) 779eb7b3a05STakashi Sakamoto break; 780eb7b3a05STakashi Sakamoto } 781eb7b3a05STakashi Sakamoto 782eb7b3a05STakashi Sakamoto kfree(buf); 783eb7b3a05STakashi Sakamoto return err; 784eb7b3a05STakashi Sakamoto } 785eb7b3a05STakashi Sakamoto 786eb7b3a05STakashi Sakamoto static int 787eb7b3a05STakashi Sakamoto seek_msu_sync_input_plug(struct snd_bebob *bebob) 788eb7b3a05STakashi Sakamoto { 789eb7b3a05STakashi Sakamoto u8 plugs[AVC_PLUG_INFO_BUF_BYTES], addr[AVC_BRIDGECO_ADDR_BYTES]; 790eb7b3a05STakashi Sakamoto unsigned int i, type; 791eb7b3a05STakashi Sakamoto int err; 792eb7b3a05STakashi Sakamoto 793eb7b3a05STakashi Sakamoto /* Get the number of Music Sub Unit for both direction. */ 794eb7b3a05STakashi Sakamoto err = avc_general_get_plug_info(bebob->unit, 0x0c, 0x00, 0x00, plugs); 795eb7b3a05STakashi Sakamoto if (err < 0) { 796eb7b3a05STakashi Sakamoto dev_err(&bebob->unit->device, 797eb7b3a05STakashi Sakamoto "fail to get info for MSU in/out plugs: %d\n", 798eb7b3a05STakashi Sakamoto err); 799eb7b3a05STakashi Sakamoto goto end; 800eb7b3a05STakashi Sakamoto } 801eb7b3a05STakashi Sakamoto 802eb7b3a05STakashi Sakamoto /* seek destination plugs for 'MSU sync input' */ 803eb7b3a05STakashi Sakamoto bebob->sync_input_plug = -1; 804eb7b3a05STakashi Sakamoto for (i = 0; i < plugs[0]; i++) { 805eb7b3a05STakashi Sakamoto avc_bridgeco_fill_msu_addr(addr, AVC_BRIDGECO_PLUG_DIR_IN, i); 806eb7b3a05STakashi Sakamoto err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type); 807eb7b3a05STakashi Sakamoto if (err < 0) { 808eb7b3a05STakashi Sakamoto dev_err(&bebob->unit->device, 809eb7b3a05STakashi Sakamoto "fail to get type for MSU in plug %d: %d\n", 810eb7b3a05STakashi Sakamoto i, err); 811eb7b3a05STakashi Sakamoto goto end; 812eb7b3a05STakashi Sakamoto } 813eb7b3a05STakashi Sakamoto 814eb7b3a05STakashi Sakamoto if (type == AVC_BRIDGECO_PLUG_TYPE_SYNC) { 815eb7b3a05STakashi Sakamoto bebob->sync_input_plug = i; 816eb7b3a05STakashi Sakamoto break; 817eb7b3a05STakashi Sakamoto } 818eb7b3a05STakashi Sakamoto } 819eb7b3a05STakashi Sakamoto end: 820eb7b3a05STakashi Sakamoto return err; 821eb7b3a05STakashi Sakamoto } 822eb7b3a05STakashi Sakamoto 823eb7b3a05STakashi Sakamoto int snd_bebob_stream_discover(struct snd_bebob *bebob) 824eb7b3a05STakashi Sakamoto { 825eb7b3a05STakashi Sakamoto u8 plugs[AVC_PLUG_INFO_BUF_BYTES], addr[AVC_BRIDGECO_ADDR_BYTES]; 826eb7b3a05STakashi Sakamoto enum avc_bridgeco_plug_type type; 827eb7b3a05STakashi Sakamoto unsigned int i; 828eb7b3a05STakashi Sakamoto int err; 829eb7b3a05STakashi Sakamoto 830eb7b3a05STakashi Sakamoto /* the number of plugs for isoc in/out, ext in/out */ 831eb7b3a05STakashi Sakamoto err = avc_general_get_plug_info(bebob->unit, 0x1f, 0x07, 0x00, plugs); 832eb7b3a05STakashi Sakamoto if (err < 0) { 833eb7b3a05STakashi Sakamoto dev_err(&bebob->unit->device, 834eb7b3a05STakashi Sakamoto "fail to get info for isoc/external in/out plugs: %d\n", 835eb7b3a05STakashi Sakamoto err); 836eb7b3a05STakashi Sakamoto goto end; 837eb7b3a05STakashi Sakamoto } 838eb7b3a05STakashi Sakamoto 839eb7b3a05STakashi Sakamoto /* 840eb7b3a05STakashi Sakamoto * This module supports at least one isoc input plug and one isoc 841eb7b3a05STakashi Sakamoto * output plug. 842eb7b3a05STakashi Sakamoto */ 843eb7b3a05STakashi Sakamoto if ((plugs[0] == 0) || (plugs[1] == 0)) { 844eb7b3a05STakashi Sakamoto err = -ENOSYS; 845eb7b3a05STakashi Sakamoto goto end; 846eb7b3a05STakashi Sakamoto } 847eb7b3a05STakashi Sakamoto 848eb7b3a05STakashi Sakamoto avc_bridgeco_fill_unit_addr(addr, AVC_BRIDGECO_PLUG_DIR_IN, 849eb7b3a05STakashi Sakamoto AVC_BRIDGECO_PLUG_UNIT_ISOC, 0); 850eb7b3a05STakashi Sakamoto err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type); 851eb7b3a05STakashi Sakamoto if (err < 0) { 852eb7b3a05STakashi Sakamoto dev_err(&bebob->unit->device, 853eb7b3a05STakashi Sakamoto "fail to get type for isoc in plug 0: %d\n", err); 854eb7b3a05STakashi Sakamoto goto end; 855eb7b3a05STakashi Sakamoto } else if (type != AVC_BRIDGECO_PLUG_TYPE_ISOC) { 856eb7b3a05STakashi Sakamoto err = -ENOSYS; 857eb7b3a05STakashi Sakamoto goto end; 858eb7b3a05STakashi Sakamoto } 859eb7b3a05STakashi Sakamoto err = fill_stream_formations(bebob, AVC_BRIDGECO_PLUG_DIR_IN, 0); 860eb7b3a05STakashi Sakamoto if (err < 0) 861eb7b3a05STakashi Sakamoto goto end; 862eb7b3a05STakashi Sakamoto 863eb7b3a05STakashi Sakamoto avc_bridgeco_fill_unit_addr(addr, AVC_BRIDGECO_PLUG_DIR_OUT, 864eb7b3a05STakashi Sakamoto AVC_BRIDGECO_PLUG_UNIT_ISOC, 0); 865eb7b3a05STakashi Sakamoto err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type); 866eb7b3a05STakashi Sakamoto if (err < 0) { 867eb7b3a05STakashi Sakamoto dev_err(&bebob->unit->device, 868eb7b3a05STakashi Sakamoto "fail to get type for isoc out plug 0: %d\n", err); 869eb7b3a05STakashi Sakamoto goto end; 870eb7b3a05STakashi Sakamoto } else if (type != AVC_BRIDGECO_PLUG_TYPE_ISOC) { 871eb7b3a05STakashi Sakamoto err = -ENOSYS; 872eb7b3a05STakashi Sakamoto goto end; 873eb7b3a05STakashi Sakamoto } 874eb7b3a05STakashi Sakamoto err = fill_stream_formations(bebob, AVC_BRIDGECO_PLUG_DIR_OUT, 0); 875eb7b3a05STakashi Sakamoto if (err < 0) 876eb7b3a05STakashi Sakamoto goto end; 877eb7b3a05STakashi Sakamoto 878eb7b3a05STakashi Sakamoto /* count external input plugs for MIDI */ 879eb7b3a05STakashi Sakamoto bebob->midi_input_ports = 0; 880eb7b3a05STakashi Sakamoto for (i = 0; i < plugs[2]; i++) { 881eb7b3a05STakashi Sakamoto avc_bridgeco_fill_unit_addr(addr, AVC_BRIDGECO_PLUG_DIR_IN, 882eb7b3a05STakashi Sakamoto AVC_BRIDGECO_PLUG_UNIT_EXT, i); 883eb7b3a05STakashi Sakamoto err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type); 884eb7b3a05STakashi Sakamoto if (err < 0) { 885eb7b3a05STakashi Sakamoto dev_err(&bebob->unit->device, 886eb7b3a05STakashi Sakamoto "fail to get type for external in plug %d: %d\n", 887eb7b3a05STakashi Sakamoto i, err); 888eb7b3a05STakashi Sakamoto goto end; 889eb7b3a05STakashi Sakamoto } else if (type == AVC_BRIDGECO_PLUG_TYPE_MIDI) { 890eb7b3a05STakashi Sakamoto bebob->midi_input_ports++; 891eb7b3a05STakashi Sakamoto } 892eb7b3a05STakashi Sakamoto } 893eb7b3a05STakashi Sakamoto 894eb7b3a05STakashi Sakamoto /* count external output plugs for MIDI */ 895eb7b3a05STakashi Sakamoto bebob->midi_output_ports = 0; 896eb7b3a05STakashi Sakamoto for (i = 0; i < plugs[3]; i++) { 897eb7b3a05STakashi Sakamoto avc_bridgeco_fill_unit_addr(addr, AVC_BRIDGECO_PLUG_DIR_OUT, 898eb7b3a05STakashi Sakamoto AVC_BRIDGECO_PLUG_UNIT_EXT, i); 899eb7b3a05STakashi Sakamoto err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type); 900eb7b3a05STakashi Sakamoto if (err < 0) { 901eb7b3a05STakashi Sakamoto dev_err(&bebob->unit->device, 902eb7b3a05STakashi Sakamoto "fail to get type for external out plug %d: %d\n", 903eb7b3a05STakashi Sakamoto i, err); 904eb7b3a05STakashi Sakamoto goto end; 905eb7b3a05STakashi Sakamoto } else if (type == AVC_BRIDGECO_PLUG_TYPE_MIDI) { 906eb7b3a05STakashi Sakamoto bebob->midi_output_ports++; 907eb7b3a05STakashi Sakamoto } 908eb7b3a05STakashi Sakamoto } 909eb7b3a05STakashi Sakamoto 910eb7b3a05STakashi Sakamoto /* for check source of clock later */ 911eb7b3a05STakashi Sakamoto err = seek_msu_sync_input_plug(bebob); 912eb7b3a05STakashi Sakamoto end: 913eb7b3a05STakashi Sakamoto return err; 914eb7b3a05STakashi Sakamoto } 915