if (s == &oxfw->tx_stream) {
formats = oxfw->tx_stream_formats;
dir = AVC_GENERAL_PLUG_DIR_OUT;
} else {
formats = oxfw->rx_stream_formats;
dir = AVC_GENERAL_PLUG_DIR_IN;
}
/* Seek stream format for requirements. */ for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
err = snd_oxfw_stream_parse_format(formats[i], &formation); if (err < 0) return err;
if ((formation.rate == rate) && (formation.pcm == pcm_channels)) break;
} if (i == SND_OXFW_STREAM_FORMAT_ENTRIES) return -EINVAL;
/* If assumed, just change rate. */ if (oxfw->assumed) return set_rate(oxfw, rate);
/* Calculate format length. */
len = 5 + formats[i][4] * 2;
// OXFW 970/971 has no function to generate playback timing according to the sequence // of value in syt field, thus the packet should include NO_INFO value in the field. // However, some models just ignore data blocks in packet with NO_INFO for audio data // processing. if (!(oxfw->quirks & SND_OXFW_QUIRK_IGNORE_NO_INFO_PACKET))
flags |= CIP_UNAWARE_SYT;
err = start_stream(oxfw, &oxfw->rx_stream); if (err < 0) {
dev_err(&oxfw->unit->device, "fail to prepare rx stream: %d\n", err); goto error;
}
if (oxfw->has_output &&
!amdtp_stream_running(&oxfw->tx_stream)) {
err = start_stream(oxfw, &oxfw->tx_stream); if (err < 0) {
dev_err(&oxfw->unit->device, "fail to prepare tx stream: %d\n", err); goto error;
}
if (oxfw->quirks & SND_OXFW_QUIRK_JUMBO_PAYLOAD) { // Just after changing sampling transfer frequency, many cycles are // skipped for packet transmission.
tx_init_skip_cycles = 400;
} elseif (oxfw->quirks & SND_OXFW_QUIRK_VOLUNTARY_RECOVERY) { // It takes a bit time for target device to adjust event frequency // according to nominal event frequency in isochronous packets from // ALSA oxfw driver.
tx_init_skip_cycles = 4000;
} else {
replay_seq = true;
}
}
// NOTE: The device ignores presentation time expressed by the value of syt field // of CIP header in received packets. The sequence of the number of data blocks per // packet is important for media clock recovery.
err = amdtp_domain_start(&oxfw->domain, tx_init_skip_cycles, replay_seq, false); if (err < 0) goto error;
int snd_oxfw_stream_init_duplex(struct snd_oxfw *oxfw)
{ int err;
err = init_stream(oxfw, &oxfw->rx_stream); if (err < 0) return err;
if (oxfw->has_output) {
err = init_stream(oxfw, &oxfw->tx_stream); if (err < 0) {
destroy_stream(oxfw, &oxfw->rx_stream); return err;
}
}
err = amdtp_domain_init(&oxfw->domain); if (err < 0) {
destroy_stream(oxfw, &oxfw->rx_stream); if (oxfw->has_output)
destroy_stream(oxfw, &oxfw->tx_stream);
}
return err;
}
// This function should be called before starting the stream or after stopping // the streams. void snd_oxfw_stream_destroy_duplex(struct snd_oxfw *oxfw)
{
amdtp_domain_destroy(&oxfw->domain);
destroy_stream(oxfw, &oxfw->rx_stream);
if (oxfw->has_output)
destroy_stream(oxfw, &oxfw->tx_stream);
}
if (oxfw->has_output) {
cmp_connection_break(&oxfw->out_conn);
amdtp_stream_pcm_abort(&oxfw->tx_stream);
}
}
int snd_oxfw_stream_get_current_formation(struct snd_oxfw *oxfw, enum avc_general_plug_dir dir, struct snd_oxfw_stream_formation *formation)
{ int err;
if (!(oxfw->quirks & SND_OXFW_QUIRK_STREAM_FORMAT_INFO_UNSUPPORTED)) {
u8 *format; unsignedint len;
len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
format = kmalloc(len, GFP_KERNEL); if (format == NULL) return -ENOMEM;
err = avc_stream_get_format_single(oxfw->unit, dir, 0, format, &len); if (err >= 0) { if (len < 3)
err = -EIO; else
err = snd_oxfw_stream_parse_format(format, formation);
}
kfree(format);
} else { // Miglia Harmony Audio does not support Extended Stream Format Information // command. Use the duplicated hard-coded format, instead. unsignedint rate;
u8 *const *formats; int i;
/* check the sampling rate */ for (i = 0; i < ARRAY_SIZE(avc_stream_rate_table); i++) { if (format[2] == avc_stream_rate_table[i]) break;
} if (i == ARRAY_SIZE(avc_stream_rate_table)) return -ENXIO;
formation->rate = oxfw_rate_table[i];
for (e = 0; e < format[4]; e++) {
channels = format[5 + e * 2];
type = format[6 + e * 2];
switch (type) { /* IEC 60958 Conformant, currently handled as MBLA */ case0x00: /* Multi Bit Linear Audio (Raw) */ case0x06:
formation->pcm += channels; break; /* MIDI Conformant */ case0x0d:
formation->midi = channels; break; /* IEC 61937-3 to 7 */ case0x01: case0x02: case0x03: case0x04: case0x05: /* Multi Bit Linear Audio */ case0x07: /* DVD-Audio */ case0x0c: /* High Precision */ /* One Bit Audio */ case0x08: /* (Plain) Raw */ case0x09: /* (Plain) SACD */ case0x0a: /* (Encoded) Raw */ case0x0b: /* (Encoded) SACD */ /* SMPTE Time-Code conformant */ case0x0e: /* Sample Count */ case0x0f: /* Anciliary Data */ case0x10: /* Synchronization Stream (Stereo Raw audio) */ case0x40: /* Don't care */ case0xff: default: return -ENXIO; /* not supported */
}
}
if (formation->pcm > AM824_MAX_CHANNELS_FOR_PCM ||
formation->midi > AM824_MAX_CHANNELS_FOR_MIDI) return -ENXIO;
// get format at current sampling rate. if (!(oxfw->quirks & SND_OXFW_QUIRK_STREAM_FORMAT_INFO_UNSUPPORTED)) {
err = avc_stream_get_format_single(oxfw->unit, dir, pid, buf, len); if (err < 0) {
dev_err(&oxfw->unit->device, "fail to get current stream format for isoc %s plug %d:%d\n",
(dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" : "out",
pid, err); goto end;
}
} else { // Miglia Harmony Audio does not support Extended Stream Format Information // command. Use the hard-coded format, instead.
buf[0] = 0x90;
buf[1] = 0x40;
buf[2] = avc_stream_rate_table[0];
buf[3] = 0x00;
buf[4] = 0x01;
/* apply the format for each available sampling rate */ for (i = 0; i < ARRAY_SIZE(oxfw_rate_table); i++) { if (formation.rate == oxfw_rate_table[i]) continue;
/* get first entry */
len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
err = avc_stream_get_format_list(oxfw->unit, dir, 0, buf, &len, 0); if (err == -ENXIO) { /* LIST subfunction is not implemented */
len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
err = assume_stream_formats(oxfw, dir, pid, buf, &len,
formats); goto end;
} elseif (err < 0) {
dev_err(&oxfw->unit->device, "fail to get stream format %d for isoc %s plug %d:%d\n",
eid, (dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" : "out",
pid, err); goto end;
}
/* LIST subfunction is implemented */ while (eid < SND_OXFW_STREAM_FORMAT_ENTRIES) { /* The format is too short. */ if (len < 3) {
err = -EIO; break;
}
/* parse and set stream format */
err = snd_oxfw_stream_parse_format(buf, &dummy); if (err < 0) break;
/* get next entry */
len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
err = avc_stream_get_format_list(oxfw->unit, dir, 0,
buf, &len, ++eid); /* No entries remained. */ if (err == -EINVAL) {
err = 0; break;
} elseif (err < 0) {
dev_err(&oxfw->unit->device, "fail to get stream format %d for isoc %s plug %d:%d\n",
eid, (dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" : "out",
pid, err); break;
}
}
end:
kfree(buf); return err;
}
int snd_oxfw_stream_discover(struct snd_oxfw *oxfw)
{
u8 plugs[AVC_PLUG_INFO_BUF_BYTES]; struct snd_oxfw_stream_formation formation;
u8 *format; unsignedint i; int err;
/* the number of plugs for isoc in/out, ext in/out */
err = avc_general_get_plug_info(oxfw->unit, 0x1f, 0x07, 0x00, plugs); if (err < 0) {
dev_err(&oxfw->unit->device, "fail to get info for isoc/external in/out plugs: %d\n",
err); goto end;
} elseif ((plugs[0] == 0) && (plugs[1] == 0)) {
err = -ENXIO; goto end;
}
/* use oPCR[0] if exists */ if (plugs[1] > 0) {
err = fill_stream_formats(oxfw, AVC_GENERAL_PLUG_DIR_OUT, 0); if (err < 0) { if (err != -ENXIO) return err;
// The oPCR is not available for isoc communication.
err = 0;
} else { for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
format = oxfw->tx_stream_formats[i]; if (format == NULL) continue;
err = snd_oxfw_stream_parse_format(format,
&formation); if (err < 0) continue;
/* Add one MIDI port. */ if (formation.midi > 0)
oxfw->midi_input_ports = 1;
}
oxfw->has_output = true;
}
}
/* use iPCR[0] if exists */ if (plugs[0] > 0) {
err = fill_stream_formats(oxfw, AVC_GENERAL_PLUG_DIR_IN, 0); if (err < 0) { if (err != -ENXIO) return err;
// The iPCR is not available for isoc communication.
err = 0;
} else { for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
format = oxfw->rx_stream_formats[i]; if (format == NULL) continue;
err = snd_oxfw_stream_parse_format(format,
&formation); if (err < 0) continue;
/* Add one MIDI port. */ if (formation.midi > 0)
oxfw->midi_output_ports = 1;
}
int snd_oxfw_stream_lock_try(struct snd_oxfw *oxfw)
{ int err;
spin_lock_irq(&oxfw->lock);
/* user land lock this */ if (oxfw->dev_lock_count < 0) {
err = -EBUSY; goto end;
}
/* this is the first time */ if (oxfw->dev_lock_count++ == 0)
snd_oxfw_stream_lock_changed(oxfw);
err = 0;
end:
spin_unlock_irq(&oxfw->lock); return err;
}
if (WARN_ON(oxfw->dev_lock_count <= 0)) goto end; if (--oxfw->dev_lock_count == 0)
snd_oxfw_stream_lock_changed(oxfw);
end:
spin_unlock_irq(&oxfw->lock);
}
Messung V0.5 in Prozent
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.15Bemerkung:
(vorverarbeitet am 2026-09-28)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Angebot
Hier finden Sie eine Liste der Produkte des Unternehmens