]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
ALSA: hda - Create Capture controls dynamically
authorTakashi Iwai <tiwai@suse.de>
Tue, 28 Jul 2009 16:20:25 +0000 (18:20 +0200)
committerTakashi Iwai <tiwai@suse.de>
Tue, 28 Jul 2009 16:25:03 +0000 (18:25 +0200)
Instead of static snd_kcontrol_new arrays, create "Capture Volume"
and "Capture Switch" controls dynamically based on the mixer attr
values (made via HDA_COMPOSE_AMP_VAL()).
This reduces the code size and gives more flexibility to change
the number of controls later.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/pci/hda/patch_sigmatel.c

index 4e3531b42e10aa84b86f76f84eac37012ef5afc6..be6cf2cfb192b84f67801229a25096101ae618e3 100644 (file)
@@ -238,6 +238,11 @@ struct sigmatel_spec {
        unsigned int num_dmuxes;
        hda_nid_t *smux_nids;
        unsigned int num_smuxes;
+
+       unsigned long *capvols; /* amp-volume attr: HDA_COMPOSE_AMP_VAL() */
+       unsigned long *capsws; /* amp-mute attr: HDA_COMPOSE_AMP_VAL() */
+       unsigned int num_caps; /* number of capture volume/switch elements */
+
        const char **spdif_labels;
 
        hda_nid_t dig_in_nid;
@@ -334,6 +339,13 @@ static hda_nid_t stac92hd73xx_smux_nids[2] = {
        0x22, 0x23,
 };
 
+#define STAC92HD73XX_NUM_CAPS  2
+static unsigned long stac92hd73xx_capvols[] = {
+       HDA_COMPOSE_AMP_VAL(0x20, 3, 0, HDA_OUTPUT),
+       HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
+};
+#define stac92hd73xx_capsws    stac92hd73xx_capvols
+
 #define STAC92HD83XXX_NUM_DMICS        2
 static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = {
        0x11, 0x12, 0
@@ -365,6 +377,13 @@ static hda_nid_t stac92hd83xxx_amp_nids[1] = {
        0xc,
 };
 
+#define STAC92HD83XXX_NUM_CAPS 2
+static unsigned long stac92hd83xxx_capvols[] = {
+       HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
+       HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_OUTPUT),
+};
+#define stac92hd83xxx_capsws   stac92hd83xxx_capvols
+
 static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
        0x0a, 0x0d, 0x0f
 };
@@ -394,6 +413,13 @@ static hda_nid_t stac92hd71bxx_slave_dig_outs[2] = {
        0x22, 0
 };
 
+#define STAC92HD71BXX_NUM_CAPS         2
+static unsigned long stac92hd71bxx_capvols[] = {
+       HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_OUTPUT),
+       HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT),
+};
+#define stac92hd71bxx_capsws   stac92hd71bxx_capvols
+
 static hda_nid_t stac925x_adc_nids[1] = {
         0x03,
 };
@@ -415,6 +441,13 @@ static hda_nid_t stac925x_dmux_nids[1] = {
        0x14,
 };
 
+static unsigned long stac925x_capvols[] = {
+       HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
+};
+static unsigned long stac925x_capsws[] = {
+       HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
+};
+
 static hda_nid_t stac922x_adc_nids[2] = {
         0x06, 0x07,
 };
@@ -423,6 +456,13 @@ static hda_nid_t stac922x_mux_nids[2] = {
         0x12, 0x13,
 };
 
+#define STAC922X_NUM_CAPS      2
+static unsigned long stac922x_capvols[] = {
+       HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT),
+       HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT),
+};
+#define stac922x_capsws                stac922x_capvols
+
 static hda_nid_t stac927x_slave_dig_outs[2] = {
        0x1f, 0,
 };
@@ -452,6 +492,18 @@ static hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = {
        0x13, 0x14, 0
 };
 
+#define STAC927X_NUM_CAPS      3
+static unsigned long stac927x_capvols[] = {
+       HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT),
+       HDA_COMPOSE_AMP_VAL(0x19, 3, 0, HDA_INPUT),
+       HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_INPUT),
+};
+static unsigned long stac927x_capsws[] = {
+       HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
+       HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_OUTPUT),
+       HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT),
+};
+
 static const char *stac927x_spdif_labels[5] = {
        "Digital Playback", "ADAT", "Analog Mux 1",
        "Analog Mux 2", "Analog Mux 3"
@@ -478,6 +530,16 @@ static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = {
         0x17, 0x18, 0
 };
 
+#define STAC9205_NUM_CAPS      2
+static unsigned long stac9205_capvols[] = {
+       HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_INPUT),
+       HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_INPUT),
+};
+static unsigned long stac9205_capsws[] = {
+       HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT),
+       HDA_COMPOSE_AMP_VAL(0x1e, 3, 0, HDA_OUTPUT),
+};
+
 static hda_nid_t stac9200_pin_nids[8] = {
        0x08, 0x09, 0x0d, 0x0e, 
        0x0f, 0x10, 0x11, 0x12,
@@ -1069,12 +1131,6 @@ static struct snd_kcontrol_new stac92hd73xx_6ch_mixer[] = {
        HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
        HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
 
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
-
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
-
        { } /* end */
 };
 
@@ -1094,12 +1150,6 @@ static struct snd_kcontrol_new stac92hd73xx_10ch_loopback[] = {
 };
 
 static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = {
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
-
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
-
        HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
 
@@ -1118,12 +1168,6 @@ static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = {
 };
 
 static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = {
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
-
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
-
        HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
 
@@ -1143,12 +1187,6 @@ static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = {
 
 
 static struct snd_kcontrol_new stac92hd83xxx_mixer[] = {
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_OUTPUT),
-
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_OUTPUT),
-
        HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x1b, 0x3, HDA_INPUT),
        HDA_CODEC_MUTE("DAC0 Capture Switch", 0x1b, 0x3, HDA_INPUT),
 
@@ -1169,17 +1207,6 @@ static struct snd_kcontrol_new stac92hd83xxx_mixer[] = {
 };
 
 static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
-
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
-       /* analog pc-beep replaced with digital beep support */
-       /*
-       HDA_CODEC_VOLUME("PC Beep Volume", 0x17, 0x2, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Beep Switch", 0x17, 0x2, HDA_INPUT),
-       */
-
        HDA_CODEC_MUTE("Import0 Mux Capture Switch", 0x17, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Import0 Mux Capture Volume", 0x17, 0x0, HDA_INPUT),
 
@@ -1198,29 +1225,9 @@ static struct snd_kcontrol_new stac92hd71bxx_loopback[] = {
        STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2)
 };
 
-static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
-
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
-       { } /* end */
-};
-
 static struct snd_kcontrol_new stac925x_mixer[] = {
        HDA_CODEC_VOLUME("Master Playback Volume", 0x0e, 0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Master Playback Switch", 0x0e, 0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x14, 0, HDA_OUTPUT),
-       { } /* end */
-};
-
-static struct snd_kcontrol_new stac9205_mixer[] = {
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT),
-
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1c, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1e, 0x0, HDA_OUTPUT),
        { } /* end */
 };
 
@@ -1229,29 +1236,6 @@ static struct snd_kcontrol_new stac9205_loopback[] = {
        {}
 };
 
-/* This needs to be generated dynamically based on sequence */
-static struct snd_kcontrol_new stac922x_mixer[] = {
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT),
-
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_INPUT),
-       { } /* end */
-};
-
-
-static struct snd_kcontrol_new stac927x_mixer[] = {
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT),
-
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x19, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1c, 0x0, HDA_OUTPUT),
-
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x2, 0x1A, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 0x2, 0x1d, 0x0, HDA_OUTPUT),
-       { } /* end */
-};
-
 static struct snd_kcontrol_new stac927x_loopback[] = {
        STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
        {}
@@ -1309,9 +1293,11 @@ static int stac92xx_build_controls(struct hda_codec *codec)
        int err;
        int i;
 
-       err = snd_hda_add_new_ctls(codec, spec->mixer);
-       if (err < 0)
-               return err;
+       if (spec->mixer) {
+               err = snd_hda_add_new_ctls(codec, spec->mixer);
+               if (err < 0)
+                       return err;
+       }
 
        for (i = 0; i < spec->num_mixers; i++) {
                err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
@@ -3317,6 +3303,21 @@ static int create_multi_out_ctls(struct hda_codec *codec, int num_outs,
        return 0;
 }
 
+static int stac92xx_add_capvol_ctls(struct hda_codec *codec, unsigned long vol,
+                                   unsigned long sw, int idx)
+{
+       int err;
+       err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_VOL, idx,
+                                      "Captuer Volume", vol);
+       if (err < 0)
+               return err;
+       err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_MUTE, idx,
+                                      "Captuer Switch", sw);
+       if (err < 0)
+               return err;
+       return 0;
+}
+
 /* add playback controls from the parsed DAC table */
 static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
                                               const struct auto_pin_cfg *cfg)
@@ -3703,7 +3704,7 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
 {
        struct sigmatel_spec *spec = codec->spec;
        int hp_swap = 0;
-       int err;
+       int i, err;
 
        if ((err = snd_hda_parse_pin_def_config(codec,
                                                &spec->autocfg,
@@ -3837,6 +3838,13 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
                spec->autocfg.line_outs = 0;
        }
 
+       for (i = 0; i < spec->num_caps; i++) {
+               err = stac92xx_add_capvol_ctls(codec, spec->capvols[i],
+                                              spec->capsws[i], i);
+               if (err < 0)
+                       return err;
+       }
+
        err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
@@ -4898,6 +4906,9 @@ static int patch_stac925x(struct hda_codec *codec)
 
        spec->init = stac925x_core_init;
        spec->mixer = stac925x_mixer;
+       spec->num_caps = 1;
+       spec->capvols = stac925x_capvols;
+       spec->capsws = stac925x_capsws;
 
        err = stac92xx_parse_auto_config(codec, 0x8, 0x7);
        if (!err) {
@@ -5001,6 +5012,10 @@ again:
        memcpy(&spec->private_dimux, &stac92hd73xx_dmux,
                        sizeof(stac92hd73xx_dmux));
 
+       spec->num_caps = STAC92HD73XX_NUM_CAPS;
+       spec->capvols = stac92hd73xx_capvols;
+       spec->capsws = stac92hd73xx_capsws;
+
        switch (spec->board_config) {
        case STAC_DELL_EQ:
                spec->init = dell_eq_core_init;
@@ -5120,6 +5135,10 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
        spec->num_dmics = STAC92HD83XXX_NUM_DMICS;
        spec->dinput_mux = &stac92hd83xxx_dmux;
        spec->pin_nids = stac92hd83xxx_pin_nids;
+       spec->num_caps = STAC92HD83XXX_NUM_CAPS;
+       spec->capvols = stac92hd83xxx_capvols;
+       spec->capsws = stac92hd83xxx_capsws;
+
        spec->board_config = snd_hda_check_board_config(codec,
                                                        STAC_92HD83XXX_MODELS,
                                                        stac92hd83xxx_models,
@@ -5308,6 +5327,10 @@ again:
        spec->dmic_nids = stac92hd71bxx_dmic_nids;
        spec->dmux_nids = stac92hd71bxx_dmux_nids;
 
+       spec->num_caps = STAC92HD71BXX_NUM_CAPS;
+       spec->capvols = stac92hd71bxx_capvols;
+       spec->capsws = stac92hd71bxx_capsws;
+
        switch (codec->vendor_id) {
        case 0x111d76b6: /* 4 Port without Analog Mixer */
        case 0x111d76b7:
@@ -5317,7 +5340,6 @@ again:
        case 0x111d76b5:
                memcpy(&spec->private_dimux, &stac92hd71bxx_dmux_nomixer,
                       sizeof(stac92hd71bxx_dmux_nomixer));
-               spec->mixer = stac92hd71bxx_mixer;
                spec->init = stac92hd71bxx_core_init;
                codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
                spec->num_dmics = stac92hd71bxx_connected_ports(codec,
@@ -5566,7 +5588,10 @@ static int patch_stac922x(struct hda_codec *codec)
        spec->num_pwrs = 0;
 
        spec->init = stac922x_core_init;
-       spec->mixer = stac922x_mixer;
+
+       spec->num_caps = STAC922X_NUM_CAPS;
+       spec->capvols = stac922x_capvols;
+       spec->capsws = stac922x_capsws;
 
        spec->multiout.dac_nids = spec->dac_nids;
        
@@ -5641,7 +5666,6 @@ static int patch_stac927x(struct hda_codec *codec)
                spec->num_dmics = 0;
 
                spec->init = d965_core_init;
-               spec->mixer = stac927x_mixer;
                break;
        case STAC_DELL_BIOS:
                switch (codec->subsystem_id) {
@@ -5666,7 +5690,6 @@ static int patch_stac927x(struct hda_codec *codec)
                spec->num_dmics = STAC927X_NUM_DMICS;
 
                spec->init = d965_core_init;
-               spec->mixer = stac927x_mixer;
                spec->dmux_nids = stac927x_dmux_nids;
                spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids);
                break;
@@ -5679,9 +5702,12 @@ static int patch_stac927x(struct hda_codec *codec)
                spec->num_dmics = 0;
 
                spec->init = stac927x_core_init;
-               spec->mixer = stac927x_mixer;
        }
 
+       spec->num_caps = STAC927X_NUM_CAPS;
+       spec->capvols = stac927x_capvols;
+       spec->capsws = stac927x_capsws;
+
        spec->num_pwrs = 0;
        spec->aloopback_ctl = stac927x_loopback;
        spec->aloopback_mask = 0x40;
@@ -5763,9 +5789,12 @@ static int patch_stac9205(struct hda_codec *codec)
        spec->num_pwrs = 0;
 
        spec->init = stac9205_core_init;
-       spec->mixer = stac9205_mixer;
        spec->aloopback_ctl = stac9205_loopback;
 
+       spec->num_caps = STAC9205_NUM_CAPS;
+       spec->capvols = stac9205_capvols;
+       spec->capsws = stac9205_capsws;
+
        spec->aloopback_mask = 0x40;
        spec->aloopback_shift = 0;
        /* Turn on/off EAPD per HP plugging */
@@ -5840,12 +5869,6 @@ static struct hda_verb stac9872_core_init[] = {
        {}
 };
 
-static struct snd_kcontrol_new stac9872_mixer[] = {
-       HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
-       { } /* end */
-};
-
 static hda_nid_t stac9872_pin_nids[] = {
        0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
        0x11, 0x13, 0x14,
@@ -5859,6 +5882,11 @@ static hda_nid_t stac9872_mux_nids[] = {
        0x15
 };
 
+static unsigned long stac9872_capvols[] = {
+       HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
+};
+#define stac9872_capsws                stac9872_capvols
+
 static unsigned int stac9872_vaio_pin_configs[9] = {
        0x03211020, 0x411111f0, 0x411111f0, 0x03a15030,
        0x411111f0, 0x90170110, 0x411111f0, 0x411111f0,
@@ -5907,8 +5935,10 @@ static int patch_stac9872(struct hda_codec *codec)
        spec->adc_nids = stac9872_adc_nids;
        spec->num_muxes = ARRAY_SIZE(stac9872_mux_nids);
        spec->mux_nids = stac9872_mux_nids;
-       spec->mixer = stac9872_mixer;
        spec->init = stac9872_core_init;
+       spec->num_caps = 1;
+       spec->capvols = stac9872_capvols;
+       spec->capsws = stac9872_capsws;
 
        err = stac92xx_parse_auto_config(codec, 0x10, 0x12);
        if (err < 0) {