Пример #1
0
/* In this function, 2 means input and output */
int snd_bebob_discover(struct snd_bebob *bebob)
{
	/* the number of plugs for input and output */
	unsigned short bus_plugs[2];
	unsigned short ext_plugs[2];
	int type, i;
	int err;

	err = avc_generic_get_plug_info(bebob->unit, bus_plugs, ext_plugs);
	if (err < 0)
		goto end;

	/*
	 * This module supports one PCR input plug and one PCR output plug
	 * then ignores the others.
	 */
	for (i = 0; i < 2; i += 1) {
		if (bus_plugs[i]  == 0) {
			err = -EIO;
			goto end;
		}

		err = avc_bridgeco_get_plug_type(bebob->unit, i, 0, &type);
		if (err < 0)
			goto end;
		else if (type != 0x00) {
			err = -EIO;
			goto end;
		}
	}

	/* store formations */
	for (i = 0; i < 2; i += 1) {
		err = fill_stream_formations(bebob, i, 0);
		if (err < 0)
			goto end;
	}

	err = 0;

end:
	return err;
}
Пример #2
0
static int
seek_msu_sync_input_plug(struct snd_bebob *bebob)
{
	u8 plugs[AVC_PLUG_INFO_BUF_BYTES], addr[AVC_BRIDGECO_ADDR_BYTES];
	unsigned int i;
	enum avc_bridgeco_plug_type type;
	int err;

	/* Get the number of Music Sub Unit for both direction. */
	err = avc_general_get_plug_info(bebob->unit, 0x0c, 0x00, 0x00, plugs);
	if (err < 0) {
		dev_err(&bebob->unit->device,
			"fail to get info for MSU in/out plugs: %d\n",
			err);
		goto end;
	}

	/* seek destination plugs for 'MSU sync input' */
	bebob->sync_input_plug = -1;
	for (i = 0; i < plugs[0]; i++) {
		avc_bridgeco_fill_msu_addr(addr, AVC_BRIDGECO_PLUG_DIR_IN, i);
		err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type);
		if (err < 0) {
			dev_err(&bebob->unit->device,
				"fail to get type for MSU in plug %d: %d\n",
				i, err);
			goto end;
		}

		if (type == AVC_BRIDGECO_PLUG_TYPE_SYNC) {
			bebob->sync_input_plug = i;
			break;
		}
	}
end:
	return err;
}
Пример #3
0
int snd_bebob_stream_discover(struct snd_bebob *bebob)
{
	const struct snd_bebob_clock_spec *clk_spec = bebob->spec->clock;
	u8 plugs[AVC_PLUG_INFO_BUF_BYTES], addr[AVC_BRIDGECO_ADDR_BYTES];
	enum avc_bridgeco_plug_type type;
	unsigned int i;
	int err;

	/* the number of plugs for isoc in/out, ext in/out  */
	err = avc_general_get_plug_info(bebob->unit, 0x1f, 0x07, 0x00, plugs);
	if (err < 0) {
		dev_err(&bebob->unit->device,
		"fail to get info for isoc/external in/out plugs: %d\n",
			err);
		goto end;
	}

	/*
	 * This module supports at least one isoc input plug and one isoc
	 * output plug.
	 */
	if ((plugs[0] == 0) || (plugs[1] == 0)) {
		err = -ENOSYS;
		goto end;
	}

	avc_bridgeco_fill_unit_addr(addr, AVC_BRIDGECO_PLUG_DIR_IN,
				    AVC_BRIDGECO_PLUG_UNIT_ISOC, 0);
	err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type);
	if (err < 0) {
		dev_err(&bebob->unit->device,
			"fail to get type for isoc in plug 0: %d\n", err);
		goto end;
	} else if (type != AVC_BRIDGECO_PLUG_TYPE_ISOC) {
		err = -ENOSYS;
		goto end;
	}
	err = fill_stream_formations(bebob, AVC_BRIDGECO_PLUG_DIR_IN, 0);
	if (err < 0)
		goto end;

	avc_bridgeco_fill_unit_addr(addr, AVC_BRIDGECO_PLUG_DIR_OUT,
				    AVC_BRIDGECO_PLUG_UNIT_ISOC, 0);
	err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type);
	if (err < 0) {
		dev_err(&bebob->unit->device,
			"fail to get type for isoc out plug 0: %d\n", err);
		goto end;
	} else if (type != AVC_BRIDGECO_PLUG_TYPE_ISOC) {
		err = -ENOSYS;
		goto end;
	}
	err = fill_stream_formations(bebob, AVC_BRIDGECO_PLUG_DIR_OUT, 0);
	if (err < 0)
		goto end;

	/* count external input plugs for MIDI */
	bebob->midi_input_ports = 0;
	for (i = 0; i < plugs[2]; i++) {
		avc_bridgeco_fill_unit_addr(addr, AVC_BRIDGECO_PLUG_DIR_IN,
					    AVC_BRIDGECO_PLUG_UNIT_EXT, i);
		err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type);
		if (err < 0) {
			dev_err(&bebob->unit->device,
			"fail to get type for external in plug %d: %d\n",
				i, err);
			goto end;
		} else if (type == AVC_BRIDGECO_PLUG_TYPE_MIDI) {
			bebob->midi_input_ports++;
		}
	}

	/* count external output plugs for MIDI */
	bebob->midi_output_ports = 0;
	for (i = 0; i < plugs[3]; i++) {
		avc_bridgeco_fill_unit_addr(addr, AVC_BRIDGECO_PLUG_DIR_OUT,
					    AVC_BRIDGECO_PLUG_UNIT_EXT, i);
		err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type);
		if (err < 0) {
			dev_err(&bebob->unit->device,
			"fail to get type for external out plug %d: %d\n",
				i, err);
			goto end;
		} else if (type == AVC_BRIDGECO_PLUG_TYPE_MIDI) {
			bebob->midi_output_ports++;
		}
	}

	/* for check source of clock later */
	if (!clk_spec)
		err = seek_msu_sync_input_plug(bebob);
end:
	return err;
}
Пример #4
0
int snd_bebob_stream_get_clock_src(struct snd_bebob *bebob,
				   enum snd_bebob_clock_type *src)
{
	const struct snd_bebob_clock_spec *clk_spec = bebob->spec->clock;
	u8 addr[AVC_BRIDGECO_ADDR_BYTES], input[7];
	unsigned int id;
	enum avc_bridgeco_plug_type type;
	int err = 0;

	/* 1.The device has its own operation to switch source of clock */
	if (clk_spec) {
		err = clk_spec->get(bebob, &id);
		if (err < 0) {
			dev_err(&bebob->unit->device,
				"fail to get clock source: %d\n", err);
			goto end;
		}

		if (id >= clk_spec->num) {
			dev_err(&bebob->unit->device,
				"clock source %d out of range 0..%d\n",
				id, clk_spec->num - 1);
			err = -EIO;
			goto end;
		}

		*src = clk_spec->types[id];
		goto end;
	}

	/*
	 * 2.The device don't support to switch source of clock then assumed
	 *   to use internal clock always
	 */
	if (bebob->sync_input_plug < 0) {
		*src = SND_BEBOB_CLOCK_TYPE_INTERNAL;
		goto end;
	}

	/*
	 * 3.The device supports to switch source of clock by an usual way.
	 *   Let's check input for 'Music Sub Unit Sync Input' plug.
	 */
	avc_bridgeco_fill_msu_addr(addr, AVC_BRIDGECO_PLUG_DIR_IN,
				   bebob->sync_input_plug);
	err = avc_bridgeco_get_plug_input(bebob->unit, addr, input);
	if (err < 0) {
		dev_err(&bebob->unit->device,
			"fail to get an input for MSU in plug %d: %d\n",
			bebob->sync_input_plug, err);
		goto end;
	}

	/*
	 * If there are no input plugs, all of fields are 0xff.
	 * Here check the first field. This field is used for direction.
	 */
	if (input[0] == 0xff) {
		*src = SND_BEBOB_CLOCK_TYPE_INTERNAL;
		goto end;
	}

	/* The source from any output plugs is for one purpose only. */
	if (input[0] == AVC_BRIDGECO_PLUG_DIR_OUT) {
		/*
		 * In BeBoB architecture, the source from music subunit may
		 * bypass from oPCR[0]. This means that this source gives
		 * synchronization to IEEE 1394 cycle start packet.
		 */
		if (input[1] == AVC_BRIDGECO_PLUG_MODE_SUBUNIT &&
		    input[2] == 0x0c) {
			*src = SND_BEBOB_CLOCK_TYPE_INTERNAL;
			goto end;
		}
	/* The source from any input units is for several purposes. */
	} else if (input[1] == AVC_BRIDGECO_PLUG_MODE_UNIT) {
		if (input[2] == AVC_BRIDGECO_PLUG_UNIT_ISOC) {
			if (input[3] == 0x00) {
				/*
				 * This source comes from iPCR[0]. This means
				 * that presentation timestamp calculated by
				 * SYT series of the received packets. In
				 * short, this driver is the master of
				 * synchronization.
				 */
				*src = SND_BEBOB_CLOCK_TYPE_SYT;
				goto end;
			} else {
				/*
				 * This source comes from iPCR[1-29]. This
				 * means that the synchronization stream is not
				 * the Audio/MIDI compound stream.
				 */
				*src = SND_BEBOB_CLOCK_TYPE_EXTERNAL;
				goto end;
			}
		} else if (input[2] == AVC_BRIDGECO_PLUG_UNIT_EXT) {
			/* Check type of this plug.  */
			avc_bridgeco_fill_unit_addr(addr,
						    AVC_BRIDGECO_PLUG_DIR_IN,
						    AVC_BRIDGECO_PLUG_UNIT_EXT,
						    input[3]);
			err = avc_bridgeco_get_plug_type(bebob->unit, addr,
							 &type);
			if (err < 0)
				goto end;

			if (type == AVC_BRIDGECO_PLUG_TYPE_DIG) {
				/*
				 * SPDIF/ADAT or sometimes (not always) word
				 * clock.
				 */
				*src = SND_BEBOB_CLOCK_TYPE_EXTERNAL;
				goto end;
			} else if (type == AVC_BRIDGECO_PLUG_TYPE_SYNC) {
				/* Often word clock. */
				*src = SND_BEBOB_CLOCK_TYPE_EXTERNAL;
				goto end;
			} else if (type == AVC_BRIDGECO_PLUG_TYPE_ADDITION) {
				/*
				 * Not standard.
				 * Mostly, additional internal clock.
				 */
				*src = SND_BEBOB_CLOCK_TYPE_INTERNAL;
				goto end;
			}
		}
	}

	/* Not supported. */
	err = -EIO;
end:
	return err;
}