// SPDX-License-Identifier: GPL-2.0-only
// Copyright (c) 2025 Šerif Rami <ramiserifpersia@gmail.com>

#include "us144mkii.h"

/**
 * @brief Text descriptions for playback output source options.
 *
 * Used by ALSA kcontrol elements to provide user-friendly names for
 * the playback routing options (e.g., "Playback 1-2", "Playback 3-4").
 */
<<<<<<< HEAD
static const char *const playback_source_texts[] = {"Playback 1-2",
                                                    "Playback 3-4"};
=======
static const char *const playback_source_texts[] = { "Playback 1-2",
						     "Playback 3-4" };
>>>>>>> f44b75094c078b0354fac280d769bc9a1bb6133b

/**
 * @brief Text descriptions for capture input source options.
 *
 * Used by ALSA kcontrol elements to provide user-friendly names for
 * the capture routing options (e.g., "Analog In", "Digital In").
 */
<<<<<<< HEAD
static const char *const capture_source_texts[] = {"Analog In", "Digital In"};
=======
static const char *const capture_source_texts[] = { "Analog In", "Digital In" };
>>>>>>> f44b75094c078b0354fac280d769bc9a1bb6133b

/**
 * tascam_playback_source_info() - ALSA control info callback for playback
 * source.
 * @kcontrol: The ALSA kcontrol instance.
 * @uinfo: The ALSA control element info structure to fill.
 *
 * This function provides information about the enumerated playback source
 * control, including its type, count, and available items (Playback 1-2,
 * Playback 3-4).
 *
 * Return: 0 on success.
 */
static int tascam_playback_source_info(struct snd_kcontrol *kcontrol,
<<<<<<< HEAD
                                       struct snd_ctl_elem_info *uinfo) {
  uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
  uinfo->count = 1;
  uinfo->value.enumerated.items = 2;
  if (uinfo->value.enumerated.item >= 2)
    uinfo->value.enumerated.item = 1;
  strscpy(uinfo->value.enumerated.name,
          playback_source_texts[uinfo->value.enumerated.item],
          sizeof(uinfo->value.enumerated.name));
  return 0;
=======
				       struct snd_ctl_elem_info *uinfo)
{
	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
	uinfo->count = 1;
	uinfo->value.enumerated.items = 2;
	if (uinfo->value.enumerated.item >= 2)
		uinfo->value.enumerated.item = 1;
	strscpy(uinfo->value.enumerated.name,
		playback_source_texts[uinfo->value.enumerated.item],
		sizeof(uinfo->value.enumerated.name));
	return 0;
>>>>>>> f44b75094c078b0354fac280d769bc9a1bb6133b
}

/**
 * tascam_line_out_get() - ALSA control get callback for Line Outputs Source.
 * @kcontrol: The ALSA kcontrol instance.
 * @ucontrol: The ALSA control element value structure to fill.
 *
 * This function retrieves the current selection for the Line Outputs source
 * (Playback 1-2 or Playback 3-4) from the driver's private data and populates
 * the ALSA control element value.
 *
 * Return: 0 on success.
 */
static int tascam_line_out_get(struct snd_kcontrol *kcontrol,
<<<<<<< HEAD
                               struct snd_ctl_elem_value *ucontrol) {
  struct tascam_card *tascam = snd_kcontrol_chip(kcontrol);
=======
			       struct snd_ctl_elem_value *ucontrol)
{
	struct tascam_card *tascam = snd_kcontrol_chip(kcontrol);
>>>>>>> f44b75094c078b0354fac280d769bc9a1bb6133b

  ucontrol->value.enumerated.item[0] = tascam->line_out_source;
  return 0;
}

/**
 * tascam_line_out_put() - ALSA control put callback for Line Outputs Source.
 * @kcontrol: The ALSA kcontrol instance.
 * @ucontrol: The ALSA control element value structure containing the new value.
 *
 * This function sets the Line Outputs source (Playback 1-2 or Playback 3-4)
 * based on the user's selection from the ALSA control element. It validates
 * the input and updates the driver's private data.
 *
 * Return: 1 if the value was changed, 0 if unchanged, or a negative error code.
 */
static int tascam_line_out_put(struct snd_kcontrol *kcontrol,
<<<<<<< HEAD
                               struct snd_ctl_elem_value *ucontrol) {
  struct tascam_card *tascam = snd_kcontrol_chip(kcontrol);
=======
			       struct snd_ctl_elem_value *ucontrol)
{
	struct tascam_card *tascam = snd_kcontrol_chip(kcontrol);
>>>>>>> f44b75094c078b0354fac280d769bc9a1bb6133b

  if (ucontrol->value.enumerated.item[0] > 1)
    return -EINVAL;
  if (tascam->line_out_source == ucontrol->value.enumerated.item[0])
    return 0;
  tascam->line_out_source = ucontrol->value.enumerated.item[0];
  return 1;
}

/**
 * tascam_line_out_control - ALSA kcontrol definition for Line Outputs Source.
 *
 * This defines a new ALSA mixer control named "Line OUTPUTS Source" that allows
 * the user to select between "Playback 1-2" and "Playback 3-4" for the analog
 * line outputs of the device. It uses the `tascam_playback_source_info` for
 * information and `tascam_line_out_get`/`tascam_line_out_put` for value
 * handling.
 */
static const struct snd_kcontrol_new tascam_line_out_control = {
<<<<<<< HEAD
    .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
    .name = "Line OUTPUTS Source",
    .info = tascam_playback_source_info,
    .get = tascam_line_out_get,
    .put = tascam_line_out_put,
=======
	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
	.name = "Line OUTPUTS Source",
	.info = tascam_playback_source_info,
	.get = tascam_line_out_get,
	.put = tascam_line_out_put,
>>>>>>> f44b75094c078b0354fac280d769bc9a1bb6133b
};

/**
 * tascam_digital_out_get() - ALSA control get callback for Digital Outputs
 * Source.
 * @kcontrol: The ALSA kcontrol instance.
 * @ucontrol: The ALSA control element value structure to fill.
 *
 * This function retrieves the current selection for the Digital Outputs source
 * (Playback 1-2 or Playback 3-4) from the driver's private data and populates
 * the ALSA control element value.
 *
 * Return: 0 on success.
 */
static int tascam_digital_out_get(struct snd_kcontrol *kcontrol,
<<<<<<< HEAD
                                  struct snd_ctl_elem_value *ucontrol) {
  struct tascam_card *tascam = snd_kcontrol_chip(kcontrol);
=======
				  struct snd_ctl_elem_value *ucontrol)
{
	struct tascam_card *tascam = snd_kcontrol_chip(kcontrol);
>>>>>>> f44b75094c078b0354fac280d769bc9a1bb6133b

  ucontrol->value.enumerated.item[0] = tascam->digital_out_source;
  return 0;
}

/**
 * tascam_digital_out_put() - ALSA control put callback for Digital Outputs
 * Source.
 * @kcontrol: The ALSA kcontrol instance.
 * @ucontrol: The ALSA control element value structure containing the new value.
 *
 * This function sets the Digital Outputs source (Playback 1-2 or Playback 3-4)
 * based on the user's selection from the ALSA control element. It validates
 * the input and updates the driver's private data.
 *
 * Return: 1 if the value was changed, 0 if unchanged, or a negative error code.
 */
static int tascam_digital_out_put(struct snd_kcontrol *kcontrol,
<<<<<<< HEAD
                                  struct snd_ctl_elem_value *ucontrol) {
  struct tascam_card *tascam = snd_kcontrol_chip(kcontrol);
=======
				  struct snd_ctl_elem_value *ucontrol)
{
	struct tascam_card *tascam = snd_kcontrol_chip(kcontrol);
>>>>>>> f44b75094c078b0354fac280d769bc9a1bb6133b

  if (ucontrol->value.enumerated.item[0] > 1)
    return -EINVAL;
  if (tascam->digital_out_source == ucontrol->value.enumerated.item[0])
    return 0;
  tascam->digital_out_source = ucontrol->value.enumerated.item[0];
  return 1;
}

/**
 * tascam_digital_out_control - ALSA kcontrol definition for Digital Outputs
 * Source.
 *
 * This defines a new ALSA mixer control named "Digital OUTPUTS Source" that
 * allows the user to select between "Playback 1-2" and "Playback 3-4" for the
 * digital outputs of the device. It uses the `tascam_playback_source_info` for
 * information and `tascam_digital_out_get`/`tascam_digital_out_put` for value
 * handling.
 */
static const struct snd_kcontrol_new tascam_digital_out_control = {
<<<<<<< HEAD
    .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
    .name = "Digital OUTPUTS Source",
    .info = tascam_playback_source_info,
    .get = tascam_digital_out_get,
    .put = tascam_digital_out_put,
=======
	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
	.name = "Digital OUTPUTS Source",
	.info = tascam_playback_source_info,
	.get = tascam_digital_out_get,
	.put = tascam_digital_out_put,
>>>>>>> f44b75094c078b0354fac280d769bc9a1bb6133b
};

/**
 * tascam_capture_source_info() - ALSA control info callback for capture source.
 * @kcontrol: The ALSA kcontrol instance.
 * @uinfo: The ALSA control element info structure to fill.
 *
 * This function provides information about the enumerated capture source
 * control, including its type, count, and available items (Analog In, Digital
 * In).
 *
 * Return: 0 on success.
 */
static int tascam_capture_source_info(struct snd_kcontrol *kcontrol,
<<<<<<< HEAD
                                      struct snd_ctl_elem_info *uinfo) {
  uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
  uinfo->count = 1;
  uinfo->value.enumerated.items = 2;
  if (uinfo->value.enumerated.item >= 2)
    uinfo->value.enumerated.item = 1;
  strscpy(uinfo->value.enumerated.name,
          capture_source_texts[uinfo->value.enumerated.item],
          sizeof(uinfo->value.enumerated.name));
  return 0;
=======
				      struct snd_ctl_elem_info *uinfo)
{
	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
	uinfo->count = 1;
	uinfo->value.enumerated.items = 2;
	if (uinfo->value.enumerated.item >= 2)
		uinfo->value.enumerated.item = 1;
	strscpy(uinfo->value.enumerated.name,
		capture_source_texts[uinfo->value.enumerated.item],
		sizeof(uinfo->value.enumerated.name));
	return 0;
>>>>>>> f44b75094c078b0354fac280d769bc9a1bb6133b
}

/**
 * tascam_capture_12_get() - ALSA control get callback for Capture channels 1
 * and 2 Source.
 * @kcontrol: The ALSA kcontrol instance.
 * @ucontrol: The ALSA control element value structure to fill.
 *
 * This function retrieves the current selection for the Capture channels 1 and
 * 2 source (Analog In or Digital In) from the driver's private data and
 * populates the ALSA control element value.
 *
 * Return: 0 on success.
 */
static int tascam_capture_12_get(struct snd_kcontrol *kcontrol,
<<<<<<< HEAD
                                 struct snd_ctl_elem_value *ucontrol) {
  struct tascam_card *tascam = snd_kcontrol_chip(kcontrol);
=======
				 struct snd_ctl_elem_value *ucontrol)
{
	struct tascam_card *tascam = snd_kcontrol_chip(kcontrol);
>>>>>>> f44b75094c078b0354fac280d769bc9a1bb6133b

  ucontrol->value.enumerated.item[0] = tascam->capture_12_source;
  return 0;
}

/**
 * tascam_capture_12_put() - ALSA control put callback for Capture channels 1
 * and 2 Source.
 * @kcontrol: The ALSA kcontrol instance.
 * @ucontrol: The ALSA control element value structure containing the new value.
 *
 * This function sets the Capture channels 1 and 2 source (Analog In or Digital
 * In) based on the user's selection from the ALSA control element. It validates
 * the input and updates the driver's private data.
 *
 * Return: 1 if the value was changed, 0 if unchanged, or a negative error code.
 */
static int tascam_capture_12_put(struct snd_kcontrol *kcontrol,
<<<<<<< HEAD
                                 struct snd_ctl_elem_value *ucontrol) {
  struct tascam_card *tascam = snd_kcontrol_chip(kcontrol);
=======
				 struct snd_ctl_elem_value *ucontrol)
{
	struct tascam_card *tascam = snd_kcontrol_chip(kcontrol);
>>>>>>> f44b75094c078b0354fac280d769bc9a1bb6133b

  if (ucontrol->value.enumerated.item[0] > 1)
    return -EINVAL;
  if (tascam->capture_12_source == ucontrol->value.enumerated.item[0])
    return 0;
  tascam->capture_12_source = ucontrol->value.enumerated.item[0];
  return 1;
}

/**
 * tascam_capture_12_control - ALSA kcontrol definition for Capture channels 1
 * and 2 Source.
 *
 * This defines a new ALSA mixer control named "ch1 and ch2 Source" that allows
 * the user to select between "Analog In" and "Digital In" for the first two
 * capture channels of the device. It uses the `tascam_capture_source_info` for
 * information and `tascam_capture_12_get`/`tascam_capture_12_put` for value
 * handling.
 */
static const struct snd_kcontrol_new tascam_capture_12_control = {
<<<<<<< HEAD
    .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
    .name = "ch1 and ch2 Source",
    .info = tascam_capture_source_info,
    .get = tascam_capture_12_get,
    .put = tascam_capture_12_put,
=======
	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
	.name = "ch1 and ch2 Source",
	.info = tascam_capture_source_info,
	.get = tascam_capture_12_get,
	.put = tascam_capture_12_put,
>>>>>>> f44b75094c078b0354fac280d769bc9a1bb6133b
};

/**
 * tascam_capture_34_get() - ALSA control get callback for Capture channels 3
 * and 4 Source.
 * @kcontrol: The ALSA kcontrol instance.
 * @ucontrol: The ALSA control element value structure to fill.
 *
 * This function retrieves the current selection for the Capture channels 3 and
 * 4 source (Analog In or Digital In) from the driver's private data and
 * populates the ALSA control element value.
 *
 * Return: 0 on success.
 */
static int tascam_capture_34_get(struct snd_kcontrol *kcontrol,
<<<<<<< HEAD
                                 struct snd_ctl_elem_value *ucontrol) {
  struct tascam_card *tascam = snd_kcontrol_chip(kcontrol);
=======
				 struct snd_ctl_elem_value *ucontrol)
{
	struct tascam_card *tascam = snd_kcontrol_chip(kcontrol);
>>>>>>> f44b75094c078b0354fac280d769bc9a1bb6133b

  ucontrol->value.enumerated.item[0] = tascam->capture_34_source;
  return 0;
}

/**
 * tascam_capture_34_put() - ALSA control put callback for Capture channels 3
 * and 4 Source.
 * @kcontrol: The ALSA kcontrol instance.
 * @ucontrol: The ALSA control element value structure containing the new value.
 *
 * This function sets the Capture channels 3 and 4 source (Analog In or Digital
 * In) based on the user's selection from the ALSA control element. It validates
 * the input and updates the driver's private data.
 *
 * Return: 1 if the value was changed, 0 if unchanged, or a negative error code.
 */
static int tascam_capture_34_put(struct snd_kcontrol *kcontrol,
<<<<<<< HEAD
                                 struct snd_ctl_elem_value *ucontrol) {
  struct tascam_card *tascam = snd_kcontrol_chip(kcontrol);
=======
				 struct snd_ctl_elem_value *ucontrol)
{
	struct tascam_card *tascam = snd_kcontrol_chip(kcontrol);
>>>>>>> f44b75094c078b0354fac280d769bc9a1bb6133b

  if (ucontrol->value.enumerated.item[0] > 1)
    return -EINVAL;
  if (tascam->capture_34_source == ucontrol->value.enumerated.item[0])
    return 0;
  tascam->capture_34_source = ucontrol->value.enumerated.item[0];
  return 1;
}

/**
 * tascam_capture_34_control - ALSA kcontrol definition for Capture channels 3
 * and 4 Source.
 *
 * This defines a new ALSA mixer control named "ch3 and ch4 Source" that allows
 * the user to select between "Analog In" and "Digital In" for the third and
 * fourth capture channels of the device. It uses the
 * `tascam_capture_source_info` for information and
 * `tascam_capture_34_get`/`tascam_capture_34_put` for value handling.
 */
static const struct snd_kcontrol_new tascam_capture_34_control = {
<<<<<<< HEAD
    .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
    .name = "ch3 and ch4 Source",
    .info = tascam_capture_source_info,
    .get = tascam_capture_34_get,
    .put = tascam_capture_34_put,
=======
	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
	.name = "ch3 and ch4 Source",
	.info = tascam_capture_source_info,
	.get = tascam_capture_34_get,
	.put = tascam_capture_34_put,
>>>>>>> f44b75094c078b0354fac280d769bc9a1bb6133b
};

/**
 * tascam_samplerate_info() - ALSA control info callback for Sample Rate.
 * @kcontrol: The ALSA kcontrol instance.
 * @uinfo: The ALSA control element info structure to fill.
 *
 * This function provides information about the Sample Rate control, defining
 * it as an integer type with a minimum value of 0 and a maximum of 96000.
 *
 * Return: 0 on success.
 */
static int tascam_samplerate_info(struct snd_kcontrol *kcontrol,
<<<<<<< HEAD
                                  struct snd_ctl_elem_info *uinfo) {
  uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
  uinfo->count = 1;
  uinfo->value.integer.min = 0;
  uinfo->value.integer.max = 96000;
  return 0;
=======
				  struct snd_ctl_elem_info *uinfo)
{
	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
	uinfo->count = 1;
	uinfo->value.integer.min = 0;
	uinfo->value.integer.max = 96000;
	return 0;
>>>>>>> f44b75094c078b0354fac280d769bc9a1bb6133b
}

/**
 * tascam_samplerate_get() - ALSA control get callback for Sample Rate.
 * @kcontrol: The ALSA kcontrol instance.
 * @ucontrol: The ALSA control element value structure to fill.
 *
 * This function retrieves the current sample rate from the device via a USB
 * control message and populates the ALSA control element value. If the rate
 * is already known (i.e., `current_rate` is set), it returns that value
 * directly.
 *
 * Return: 0 on success, or a negative error code on failure.
 */
static int tascam_samplerate_get(struct snd_kcontrol *kcontrol,
<<<<<<< HEAD
                                 struct snd_ctl_elem_value *ucontrol) {
  struct tascam_card *tascam =
      (struct tascam_card *)snd_kcontrol_chip(kcontrol);
  u8 *buf;
  int err;
  u32 rate = 0;
=======
				 struct snd_ctl_elem_value *ucontrol)
{
	struct tascam_card *tascam =
		(struct tascam_card *)snd_kcontrol_chip(kcontrol);
	u8 *buf;
	int err;
	u32 rate = 0;
>>>>>>> f44b75094c078b0354fac280d769bc9a1bb6133b

  if (tascam->current_rate > 0) {
    ucontrol->value.integer.value[0] = tascam->current_rate;
    return 0;
  }

  buf = kmalloc(3, GFP_KERNEL);
  if (!buf)
    return -ENOMEM;

<<<<<<< HEAD
  err = usb_control_msg(tascam->dev, usb_rcvctrlpipe(tascam->dev, 0),
                        UAC_GET_CUR, RT_D2H_CLASS_EP, UAC_SAMPLING_FREQ_CONTROL,
                        EP_AUDIO_IN, buf, 3, USB_CTRL_TIMEOUT_MS);
=======
	err = usb_control_msg(tascam->dev, usb_rcvctrlpipe(tascam->dev, 0),
			      UAC_GET_CUR, RT_D2H_CLASS_EP,
			      UAC_SAMPLING_FREQ_CONTROL, EP_AUDIO_IN, buf, 3,
			      USB_CTRL_TIMEOUT_MS);
>>>>>>> f44b75094c078b0354fac280d769bc9a1bb6133b

  if (err >= 3)
    rate = buf[0] | (buf[1] << 8) | (buf[2] << 16);

  ucontrol->value.integer.value[0] = rate;
  kfree(buf);
  return 0;
}

/**
 * tascam_samplerate_control - ALSA kcontrol definition for Sample Rate.
 *
 * This defines a new ALSA mixer control named "Sample Rate" that displays
 * the current sample rate of the device. It is a read-only control.
 */
static const struct snd_kcontrol_new tascam_samplerate_control = {
    .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
    .name = "Sample Rate",
    .info = tascam_samplerate_info,
    .get = tascam_samplerate_get,
    .access = SNDRV_CTL_ELEM_ACCESS_READ,
};

/**
 * tascam_create_controls() - Creates and adds ALSA mixer controls for the
 * device.
 * @tascam: The driver instance.
 *
 * This function registers custom ALSA controls for managing audio routing
 * (line out source, digital out source, capture 1-2 source, capture 3-4 source)
 * and displaying the current sample rate.
 *
 * Return: 0 on success, or a negative error code on failure.
 */
int tascam_create_controls(struct tascam_card *tascam) {
  int err;

<<<<<<< HEAD
  err =
      snd_ctl_add(tascam->card, snd_ctl_new1(&tascam_line_out_control, tascam));
  if (err < 0)
    return err;
  err = snd_ctl_add(tascam->card,
                    snd_ctl_new1(&tascam_digital_out_control, tascam));
  if (err < 0)
    return err;
  err = snd_ctl_add(tascam->card,
                    snd_ctl_new1(&tascam_capture_12_control, tascam));
  if (err < 0)
    return err;
  err = snd_ctl_add(tascam->card,
                    snd_ctl_new1(&tascam_capture_34_control, tascam));
  if (err < 0)
    return err;

  err = snd_ctl_add(tascam->card,
                    snd_ctl_new1(&tascam_samplerate_control, tascam));
  if (err < 0)
    return err;
=======
	err = snd_ctl_add(tascam->card,
			  snd_ctl_new1(&tascam_line_out_control, tascam));
	if (err < 0)
		return err;
	err = snd_ctl_add(tascam->card,
			  snd_ctl_new1(&tascam_digital_out_control, tascam));
	if (err < 0)
		return err;
	err = snd_ctl_add(tascam->card,
			  snd_ctl_new1(&tascam_capture_12_control, tascam));
	if (err < 0)
		return err;
	err = snd_ctl_add(tascam->card,
			  snd_ctl_new1(&tascam_capture_34_control, tascam));
	if (err < 0)
		return err;

	err = snd_ctl_add(tascam->card,
			  snd_ctl_new1(&tascam_samplerate_control, tascam));
	if (err < 0)
		return err;
>>>>>>> f44b75094c078b0354fac280d769bc9a1bb6133b

  return 0;
}
