0001
0002
0003
0004
0005
0006
0007
0008 #include "./bebob.h"
0009 #include <sound/control.h>
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038 #define INFO_OFFSET_SW_DATE 0x20
0039
0040
0041 #define MAUDIO_BOOTLOADER_CUE1 0x00000001
0042
0043
0044
0045
0046
0047 #define MAUDIO_BOOTLOADER_CUE2 0x01110000
0048
0049 #define MAUDIO_BOOTLOADER_CUE3 0x00000000
0050
0051 #define MAUDIO_SPECIFIC_ADDRESS 0xffc700000000ULL
0052
0053 #define METER_OFFSET 0x00600000
0054
0055
0056 #define METER_SIZE_SPECIAL 84
0057 #define METER_SIZE_FW410 76
0058 #define METER_SIZE_AUDIOPHILE 60
0059 #define METER_SIZE_SOLO 52
0060 #define METER_SIZE_OZONIC 48
0061 #define METER_SIZE_NRV10 80
0062
0063
0064 #define ANA_IN "Analog In"
0065 #define ANA_OUT "Analog Out"
0066 #define DIG_IN "Digital In"
0067 #define SPDIF_IN "S/PDIF In"
0068 #define ADAT_IN "ADAT In"
0069 #define DIG_OUT "Digital Out"
0070 #define SPDIF_OUT "S/PDIF Out"
0071 #define ADAT_OUT "ADAT Out"
0072 #define STRM_IN "Stream In"
0073 #define AUX_OUT "Aux Out"
0074 #define HP_OUT "HP Out"
0075
0076 #define UNKNOWN_METER "Unknown"
0077
0078 struct special_params {
0079 bool is1814;
0080 unsigned int clk_src;
0081 unsigned int dig_in_fmt;
0082 unsigned int dig_out_fmt;
0083 unsigned int clk_lock;
0084 struct snd_ctl_elem_id *ctl_id_sync;
0085 };
0086
0087
0088
0089
0090
0091
0092
0093 int snd_bebob_maudio_load_firmware(struct fw_unit *unit)
0094 {
0095 struct fw_device *device = fw_parent_device(unit);
0096 int err, rcode;
0097 u64 date;
0098 __le32 *cues;
0099
0100
0101 err = snd_bebob_read_block(unit, INFO_OFFSET_SW_DATE,
0102 &date, sizeof(u64));
0103 if (err < 0)
0104 return err;
0105
0106
0107
0108
0109 if (date < 0x3230303730343031LL) {
0110 dev_err(&unit->device,
0111 "Use firmware version 5058 or later\n");
0112 return -ENXIO;
0113 }
0114
0115 cues = kmalloc_array(3, sizeof(*cues), GFP_KERNEL);
0116 if (!cues)
0117 return -ENOMEM;
0118
0119 cues[0] = cpu_to_le32(MAUDIO_BOOTLOADER_CUE1);
0120 cues[1] = cpu_to_le32(MAUDIO_BOOTLOADER_CUE2);
0121 cues[2] = cpu_to_le32(MAUDIO_BOOTLOADER_CUE3);
0122
0123 rcode = fw_run_transaction(device->card, TCODE_WRITE_BLOCK_REQUEST,
0124 device->node_id, device->generation,
0125 device->max_speed, BEBOB_ADDR_REG_REQ,
0126 cues, 3 * sizeof(*cues));
0127 kfree(cues);
0128 if (rcode != RCODE_COMPLETE) {
0129 dev_err(&unit->device,
0130 "Failed to send a cue to load firmware\n");
0131 err = -EIO;
0132 }
0133
0134 return err;
0135 }
0136
0137 static inline int
0138 get_meter(struct snd_bebob *bebob, void *buf, unsigned int size)
0139 {
0140 return snd_fw_transaction(bebob->unit, TCODE_READ_BLOCK_REQUEST,
0141 MAUDIO_SPECIFIC_ADDRESS + METER_OFFSET,
0142 buf, size, 0);
0143 }
0144
0145 static int
0146 check_clk_sync(struct snd_bebob *bebob, unsigned int size, bool *sync)
0147 {
0148 int err;
0149 u8 *buf;
0150
0151 buf = kmalloc(size, GFP_KERNEL);
0152 if (buf == NULL)
0153 return -ENOMEM;
0154
0155 err = get_meter(bebob, buf, size);
0156 if (err < 0)
0157 goto end;
0158
0159
0160 *sync = (buf[size - 2] != 0xff);
0161 end:
0162 kfree(buf);
0163 return err;
0164 }
0165
0166
0167
0168
0169
0170 static int
0171 avc_maudio_set_special_clk(struct snd_bebob *bebob, unsigned int clk_src,
0172 unsigned int dig_in_fmt, unsigned int dig_out_fmt,
0173 unsigned int clk_lock)
0174 {
0175 struct special_params *params = bebob->maudio_special_quirk;
0176 int err;
0177 u8 *buf;
0178
0179 if (amdtp_stream_running(&bebob->rx_stream) ||
0180 amdtp_stream_running(&bebob->tx_stream))
0181 return -EBUSY;
0182
0183 buf = kmalloc(12, GFP_KERNEL);
0184 if (buf == NULL)
0185 return -ENOMEM;
0186
0187 buf[0] = 0x00;
0188 buf[1] = 0xff;
0189 buf[2] = 0x00;
0190 buf[3] = 0x04;
0191 buf[4] = 0x00;
0192 buf[5] = 0x04;
0193 buf[6] = 0xff & clk_src;
0194 buf[7] = 0xff & dig_in_fmt;
0195 buf[8] = 0xff & dig_out_fmt;
0196 buf[9] = 0xff & clk_lock;
0197 buf[10] = 0x00;
0198 buf[11] = 0x00;
0199
0200 err = fcp_avc_transaction(bebob->unit, buf, 12, buf, 12,
0201 BIT(1) | BIT(2) | BIT(3) | BIT(4) |
0202 BIT(5) | BIT(6) | BIT(7) | BIT(8) |
0203 BIT(9));
0204 if ((err > 0) && (err < 10))
0205 err = -EIO;
0206 else if (buf[0] == 0x08)
0207 err = -ENOSYS;
0208 else if (buf[0] == 0x0a)
0209 err = -EINVAL;
0210 if (err < 0)
0211 goto end;
0212
0213 params->clk_src = buf[6];
0214 params->dig_in_fmt = buf[7];
0215 params->dig_out_fmt = buf[8];
0216 params->clk_lock = buf[9];
0217
0218 if (params->ctl_id_sync)
0219 snd_ctl_notify(bebob->card, SNDRV_CTL_EVENT_MASK_VALUE,
0220 params->ctl_id_sync);
0221
0222 err = 0;
0223 end:
0224 kfree(buf);
0225 return err;
0226 }
0227 static void
0228 special_stream_formation_set(struct snd_bebob *bebob)
0229 {
0230 static const unsigned int ch_table[2][2][3] = {
0231
0232 { { 6, 6, 4 },
0233 { 12, 8, 4 } },
0234
0235 { { 10, 10, 2 },
0236 { 16, 12, 2 } }
0237 };
0238 struct special_params *params = bebob->maudio_special_quirk;
0239 unsigned int i, max;
0240
0241 max = SND_BEBOB_STRM_FMT_ENTRIES - 1;
0242 if (!params->is1814)
0243 max -= 2;
0244
0245 for (i = 0; i < max; i++) {
0246 bebob->tx_stream_formations[i + 1].pcm =
0247 ch_table[AMDTP_IN_STREAM][params->dig_in_fmt][i / 2];
0248 bebob->tx_stream_formations[i + 1].midi = 1;
0249
0250 bebob->rx_stream_formations[i + 1].pcm =
0251 ch_table[AMDTP_OUT_STREAM][params->dig_out_fmt][i / 2];
0252 bebob->rx_stream_formations[i + 1].midi = 1;
0253 }
0254 }
0255
0256 static int add_special_controls(struct snd_bebob *bebob);
0257 int
0258 snd_bebob_maudio_special_discover(struct snd_bebob *bebob, bool is1814)
0259 {
0260 struct special_params *params;
0261 int err;
0262
0263 params = devm_kzalloc(&bebob->card->card_dev,
0264 sizeof(struct special_params), GFP_KERNEL);
0265 if (!params)
0266 return -ENOMEM;
0267
0268 mutex_lock(&bebob->mutex);
0269
0270 bebob->maudio_special_quirk = (void *)params;
0271 params->is1814 = is1814;
0272
0273
0274 bebob->rx_stream.context = ERR_PTR(-1);
0275 bebob->tx_stream.context = ERR_PTR(-1);
0276 err = avc_maudio_set_special_clk(bebob, 0x03, 0x00, 0x00, 0x00);
0277 if (err < 0) {
0278 dev_err(&bebob->unit->device,
0279 "fail to initialize clock params: %d\n", err);
0280 goto end;
0281 }
0282
0283 err = add_special_controls(bebob);
0284 if (err < 0)
0285 goto end;
0286
0287 special_stream_formation_set(bebob);
0288
0289 if (params->is1814) {
0290 bebob->midi_input_ports = 1;
0291 bebob->midi_output_ports = 1;
0292 } else {
0293 bebob->midi_input_ports = 2;
0294 bebob->midi_output_ports = 2;
0295 }
0296 end:
0297 mutex_unlock(&bebob->mutex);
0298 return err;
0299 }
0300
0301
0302 static int special_get_rate(struct snd_bebob *bebob, unsigned int *rate)
0303 {
0304 int err, trials;
0305
0306 trials = 0;
0307 do {
0308 err = avc_general_get_sig_fmt(bebob->unit, rate,
0309 AVC_GENERAL_PLUG_DIR_IN, 0);
0310 } while (err == -EAGAIN && ++trials < 3);
0311
0312 return err;
0313 }
0314 static int special_set_rate(struct snd_bebob *bebob, unsigned int rate)
0315 {
0316 struct special_params *params = bebob->maudio_special_quirk;
0317 int err;
0318
0319 err = avc_general_set_sig_fmt(bebob->unit, rate,
0320 AVC_GENERAL_PLUG_DIR_OUT, 0);
0321 if (err < 0)
0322 goto end;
0323
0324
0325
0326
0327
0328 msleep(100);
0329
0330 err = avc_general_set_sig_fmt(bebob->unit, rate,
0331 AVC_GENERAL_PLUG_DIR_IN, 0);
0332 if (err < 0)
0333 goto end;
0334
0335 if (params->ctl_id_sync)
0336 snd_ctl_notify(bebob->card, SNDRV_CTL_EVENT_MASK_VALUE,
0337 params->ctl_id_sync);
0338 end:
0339 return err;
0340 }
0341
0342
0343 static const enum snd_bebob_clock_type special_clk_types[] = {
0344 SND_BEBOB_CLOCK_TYPE_INTERNAL,
0345 SND_BEBOB_CLOCK_TYPE_EXTERNAL,
0346 SND_BEBOB_CLOCK_TYPE_EXTERNAL,
0347 SND_BEBOB_CLOCK_TYPE_INTERNAL,
0348 };
0349 static int special_clk_get(struct snd_bebob *bebob, unsigned int *id)
0350 {
0351 struct special_params *params = bebob->maudio_special_quirk;
0352 *id = params->clk_src;
0353 return 0;
0354 }
0355 static int special_clk_ctl_info(struct snd_kcontrol *kctl,
0356 struct snd_ctl_elem_info *einf)
0357 {
0358 static const char *const special_clk_labels[] = {
0359 "Internal with Digital Mute",
0360 "Digital",
0361 "Word Clock",
0362 "Internal"
0363 };
0364 return snd_ctl_enum_info(einf, 1, ARRAY_SIZE(special_clk_types),
0365 special_clk_labels);
0366 }
0367 static int special_clk_ctl_get(struct snd_kcontrol *kctl,
0368 struct snd_ctl_elem_value *uval)
0369 {
0370 struct snd_bebob *bebob = snd_kcontrol_chip(kctl);
0371 struct special_params *params = bebob->maudio_special_quirk;
0372 uval->value.enumerated.item[0] = params->clk_src;
0373 return 0;
0374 }
0375 static int special_clk_ctl_put(struct snd_kcontrol *kctl,
0376 struct snd_ctl_elem_value *uval)
0377 {
0378 struct snd_bebob *bebob = snd_kcontrol_chip(kctl);
0379 struct special_params *params = bebob->maudio_special_quirk;
0380 int err, id;
0381
0382 id = uval->value.enumerated.item[0];
0383 if (id >= ARRAY_SIZE(special_clk_types))
0384 return -EINVAL;
0385
0386 mutex_lock(&bebob->mutex);
0387
0388 err = avc_maudio_set_special_clk(bebob, id,
0389 params->dig_in_fmt,
0390 params->dig_out_fmt,
0391 params->clk_lock);
0392 mutex_unlock(&bebob->mutex);
0393
0394 if (err >= 0)
0395 err = 1;
0396
0397 return err;
0398 }
0399 static const struct snd_kcontrol_new special_clk_ctl = {
0400 .name = "Clock Source",
0401 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
0402 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
0403 .info = special_clk_ctl_info,
0404 .get = special_clk_ctl_get,
0405 .put = special_clk_ctl_put
0406 };
0407
0408
0409 static int special_sync_ctl_info(struct snd_kcontrol *kctl,
0410 struct snd_ctl_elem_info *einf)
0411 {
0412 einf->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
0413 einf->count = 1;
0414 einf->value.integer.min = 0;
0415 einf->value.integer.max = 1;
0416
0417 return 0;
0418 }
0419 static int special_sync_ctl_get(struct snd_kcontrol *kctl,
0420 struct snd_ctl_elem_value *uval)
0421 {
0422 struct snd_bebob *bebob = snd_kcontrol_chip(kctl);
0423 int err;
0424 bool synced = 0;
0425
0426 err = check_clk_sync(bebob, METER_SIZE_SPECIAL, &synced);
0427 if (err >= 0)
0428 uval->value.integer.value[0] = synced;
0429
0430 return 0;
0431 }
0432 static const struct snd_kcontrol_new special_sync_ctl = {
0433 .name = "Sync Status",
0434 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
0435 .access = SNDRV_CTL_ELEM_ACCESS_READ,
0436 .info = special_sync_ctl_info,
0437 .get = special_sync_ctl_get,
0438 };
0439
0440
0441 static const char *const special_dig_in_iface_labels[] = {
0442 "S/PDIF Optical", "S/PDIF Coaxial", "ADAT Optical"
0443 };
0444 static int special_dig_in_iface_ctl_info(struct snd_kcontrol *kctl,
0445 struct snd_ctl_elem_info *einf)
0446 {
0447 return snd_ctl_enum_info(einf, 1,
0448 ARRAY_SIZE(special_dig_in_iface_labels),
0449 special_dig_in_iface_labels);
0450 }
0451 static int special_dig_in_iface_ctl_get(struct snd_kcontrol *kctl,
0452 struct snd_ctl_elem_value *uval)
0453 {
0454 struct snd_bebob *bebob = snd_kcontrol_chip(kctl);
0455 struct special_params *params = bebob->maudio_special_quirk;
0456 unsigned int dig_in_iface;
0457 int err, val;
0458
0459 mutex_lock(&bebob->mutex);
0460
0461 err = avc_audio_get_selector(bebob->unit, 0x00, 0x04,
0462 &dig_in_iface);
0463 if (err < 0) {
0464 dev_err(&bebob->unit->device,
0465 "fail to get digital input interface: %d\n", err);
0466 goto end;
0467 }
0468
0469
0470 val = (params->dig_in_fmt << 1) | (dig_in_iface & 0x01);
0471
0472
0473 if (val > 2)
0474 val = 2;
0475
0476 uval->value.enumerated.item[0] = val;
0477 end:
0478 mutex_unlock(&bebob->mutex);
0479 return err;
0480 }
0481 static int special_dig_in_iface_ctl_set(struct snd_kcontrol *kctl,
0482 struct snd_ctl_elem_value *uval)
0483 {
0484 struct snd_bebob *bebob = snd_kcontrol_chip(kctl);
0485 struct special_params *params = bebob->maudio_special_quirk;
0486 unsigned int id, dig_in_fmt, dig_in_iface;
0487 int err;
0488
0489 id = uval->value.enumerated.item[0];
0490 if (id >= ARRAY_SIZE(special_dig_in_iface_labels))
0491 return -EINVAL;
0492
0493
0494 dig_in_fmt = (id >> 1) & 0x01;
0495 dig_in_iface = id & 0x01;
0496
0497 mutex_lock(&bebob->mutex);
0498
0499 err = avc_maudio_set_special_clk(bebob,
0500 params->clk_src,
0501 dig_in_fmt,
0502 params->dig_out_fmt,
0503 params->clk_lock);
0504 if (err < 0)
0505 goto end;
0506
0507
0508 if (params->dig_in_fmt > 0) {
0509 err = 1;
0510 goto end;
0511 }
0512
0513
0514 err = avc_audio_set_selector(bebob->unit, 0x00, 0x04, dig_in_iface);
0515 if (err < 0)
0516 dev_err(&bebob->unit->device,
0517 "fail to set digital input interface: %d\n", err);
0518 err = 1;
0519 end:
0520 special_stream_formation_set(bebob);
0521 mutex_unlock(&bebob->mutex);
0522 return err;
0523 }
0524 static const struct snd_kcontrol_new special_dig_in_iface_ctl = {
0525 .name = "Digital Input Interface",
0526 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
0527 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
0528 .info = special_dig_in_iface_ctl_info,
0529 .get = special_dig_in_iface_ctl_get,
0530 .put = special_dig_in_iface_ctl_set
0531 };
0532
0533
0534 static const char *const special_dig_out_iface_labels[] = {
0535 "S/PDIF Optical and Coaxial", "ADAT Optical"
0536 };
0537 static int special_dig_out_iface_ctl_info(struct snd_kcontrol *kctl,
0538 struct snd_ctl_elem_info *einf)
0539 {
0540 return snd_ctl_enum_info(einf, 1,
0541 ARRAY_SIZE(special_dig_out_iface_labels),
0542 special_dig_out_iface_labels);
0543 }
0544 static int special_dig_out_iface_ctl_get(struct snd_kcontrol *kctl,
0545 struct snd_ctl_elem_value *uval)
0546 {
0547 struct snd_bebob *bebob = snd_kcontrol_chip(kctl);
0548 struct special_params *params = bebob->maudio_special_quirk;
0549 mutex_lock(&bebob->mutex);
0550 uval->value.enumerated.item[0] = params->dig_out_fmt;
0551 mutex_unlock(&bebob->mutex);
0552 return 0;
0553 }
0554 static int special_dig_out_iface_ctl_set(struct snd_kcontrol *kctl,
0555 struct snd_ctl_elem_value *uval)
0556 {
0557 struct snd_bebob *bebob = snd_kcontrol_chip(kctl);
0558 struct special_params *params = bebob->maudio_special_quirk;
0559 unsigned int id;
0560 int err;
0561
0562 id = uval->value.enumerated.item[0];
0563 if (id >= ARRAY_SIZE(special_dig_out_iface_labels))
0564 return -EINVAL;
0565
0566 mutex_lock(&bebob->mutex);
0567
0568 err = avc_maudio_set_special_clk(bebob,
0569 params->clk_src,
0570 params->dig_in_fmt,
0571 id, params->clk_lock);
0572 if (err >= 0) {
0573 special_stream_formation_set(bebob);
0574 err = 1;
0575 }
0576
0577 mutex_unlock(&bebob->mutex);
0578 return err;
0579 }
0580 static const struct snd_kcontrol_new special_dig_out_iface_ctl = {
0581 .name = "Digital Output Interface",
0582 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
0583 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
0584 .info = special_dig_out_iface_ctl_info,
0585 .get = special_dig_out_iface_ctl_get,
0586 .put = special_dig_out_iface_ctl_set
0587 };
0588
0589 static int add_special_controls(struct snd_bebob *bebob)
0590 {
0591 struct snd_kcontrol *kctl;
0592 struct special_params *params = bebob->maudio_special_quirk;
0593 int err;
0594
0595 kctl = snd_ctl_new1(&special_clk_ctl, bebob);
0596 err = snd_ctl_add(bebob->card, kctl);
0597 if (err < 0)
0598 goto end;
0599
0600 kctl = snd_ctl_new1(&special_sync_ctl, bebob);
0601 err = snd_ctl_add(bebob->card, kctl);
0602 if (err < 0)
0603 goto end;
0604 params->ctl_id_sync = &kctl->id;
0605
0606 kctl = snd_ctl_new1(&special_dig_in_iface_ctl, bebob);
0607 err = snd_ctl_add(bebob->card, kctl);
0608 if (err < 0)
0609 goto end;
0610
0611 kctl = snd_ctl_new1(&special_dig_out_iface_ctl, bebob);
0612 err = snd_ctl_add(bebob->card, kctl);
0613 end:
0614 return err;
0615 }
0616
0617
0618 static const char *const special_meter_labels[] = {
0619 ANA_IN, ANA_IN, ANA_IN, ANA_IN,
0620 SPDIF_IN,
0621 ADAT_IN, ADAT_IN, ADAT_IN, ADAT_IN,
0622 ANA_OUT, ANA_OUT,
0623 SPDIF_OUT,
0624 ADAT_OUT, ADAT_OUT, ADAT_OUT, ADAT_OUT,
0625 HP_OUT, HP_OUT,
0626 AUX_OUT
0627 };
0628 static int
0629 special_meter_get(struct snd_bebob *bebob, u32 *target, unsigned int size)
0630 {
0631 __be16 *buf;
0632 unsigned int i, c, channels;
0633 int err;
0634
0635 channels = ARRAY_SIZE(special_meter_labels) * 2;
0636 if (size < channels * sizeof(u32))
0637 return -EINVAL;
0638
0639
0640 buf = kmalloc(METER_SIZE_SPECIAL - 4, GFP_KERNEL);
0641 if (buf == NULL)
0642 return -ENOMEM;
0643
0644 err = get_meter(bebob, (void *)buf, METER_SIZE_SPECIAL - 4);
0645 if (err < 0)
0646 goto end;
0647
0648
0649 i = 0;
0650 for (c = 2; c < channels + 2; c++)
0651 target[i++] = be16_to_cpu(buf[c]) << 16;
0652 end:
0653 kfree(buf);
0654 return err;
0655 }
0656
0657
0658 static const char *const fw410_meter_labels[] = {
0659 ANA_IN, DIG_IN,
0660 ANA_OUT, ANA_OUT, ANA_OUT, ANA_OUT, DIG_OUT,
0661 HP_OUT
0662 };
0663 static const char *const audiophile_meter_labels[] = {
0664 ANA_IN, DIG_IN,
0665 ANA_OUT, ANA_OUT, DIG_OUT,
0666 HP_OUT, AUX_OUT,
0667 };
0668 static const char *const solo_meter_labels[] = {
0669 ANA_IN, DIG_IN,
0670 STRM_IN, STRM_IN,
0671 ANA_OUT, DIG_OUT
0672 };
0673
0674
0675 static const char *const ozonic_meter_labels[] = {
0676 ANA_IN, ANA_IN,
0677 STRM_IN, STRM_IN,
0678 ANA_OUT, ANA_OUT
0679 };
0680
0681 static const char *const nrv10_meter_labels[] = {
0682 ANA_IN, ANA_IN, ANA_IN, ANA_IN,
0683 DIG_IN,
0684 ANA_OUT, ANA_OUT, ANA_OUT, ANA_OUT,
0685 DIG_IN
0686 };
0687 static int
0688 normal_meter_get(struct snd_bebob *bebob, u32 *buf, unsigned int size)
0689 {
0690 const struct snd_bebob_meter_spec *spec = bebob->spec->meter;
0691 unsigned int c, channels;
0692 int err;
0693
0694 channels = spec->num * 2;
0695 if (size < channels * sizeof(u32))
0696 return -EINVAL;
0697
0698 err = get_meter(bebob, (void *)buf, size);
0699 if (err < 0)
0700 goto end;
0701
0702 for (c = 0; c < channels; c++)
0703 be32_to_cpus(&buf[c]);
0704
0705
0706 if (spec->labels == solo_meter_labels) {
0707 swap(buf[4], buf[6]);
0708 swap(buf[5], buf[7]);
0709 }
0710 end:
0711 return err;
0712 }
0713
0714
0715 static const struct snd_bebob_rate_spec special_rate_spec = {
0716 .get = &special_get_rate,
0717 .set = &special_set_rate,
0718 };
0719 static const struct snd_bebob_clock_spec special_clk_spec = {
0720 .num = ARRAY_SIZE(special_clk_types),
0721 .types = special_clk_types,
0722 .get = &special_clk_get,
0723 };
0724 static const struct snd_bebob_meter_spec special_meter_spec = {
0725 .num = ARRAY_SIZE(special_meter_labels),
0726 .labels = special_meter_labels,
0727 .get = &special_meter_get
0728 };
0729 const struct snd_bebob_spec maudio_special_spec = {
0730 .clock = &special_clk_spec,
0731 .rate = &special_rate_spec,
0732 .meter = &special_meter_spec
0733 };
0734
0735
0736 static const struct snd_bebob_rate_spec usual_rate_spec = {
0737 .get = &snd_bebob_stream_get_rate,
0738 .set = &snd_bebob_stream_set_rate,
0739 };
0740 static const struct snd_bebob_meter_spec fw410_meter_spec = {
0741 .num = ARRAY_SIZE(fw410_meter_labels),
0742 .labels = fw410_meter_labels,
0743 .get = &normal_meter_get
0744 };
0745 const struct snd_bebob_spec maudio_fw410_spec = {
0746 .clock = NULL,
0747 .rate = &usual_rate_spec,
0748 .meter = &fw410_meter_spec
0749 };
0750
0751
0752 static const struct snd_bebob_meter_spec audiophile_meter_spec = {
0753 .num = ARRAY_SIZE(audiophile_meter_labels),
0754 .labels = audiophile_meter_labels,
0755 .get = &normal_meter_get
0756 };
0757 const struct snd_bebob_spec maudio_audiophile_spec = {
0758 .clock = NULL,
0759 .rate = &usual_rate_spec,
0760 .meter = &audiophile_meter_spec
0761 };
0762
0763
0764 static const struct snd_bebob_meter_spec solo_meter_spec = {
0765 .num = ARRAY_SIZE(solo_meter_labels),
0766 .labels = solo_meter_labels,
0767 .get = &normal_meter_get
0768 };
0769 const struct snd_bebob_spec maudio_solo_spec = {
0770 .clock = NULL,
0771 .rate = &usual_rate_spec,
0772 .meter = &solo_meter_spec
0773 };
0774
0775
0776 static const struct snd_bebob_meter_spec ozonic_meter_spec = {
0777 .num = ARRAY_SIZE(ozonic_meter_labels),
0778 .labels = ozonic_meter_labels,
0779 .get = &normal_meter_get
0780 };
0781 const struct snd_bebob_spec maudio_ozonic_spec = {
0782 .clock = NULL,
0783 .rate = &usual_rate_spec,
0784 .meter = &ozonic_meter_spec
0785 };
0786
0787
0788 static const struct snd_bebob_meter_spec nrv10_meter_spec = {
0789 .num = ARRAY_SIZE(nrv10_meter_labels),
0790 .labels = nrv10_meter_labels,
0791 .get = &normal_meter_get
0792 };
0793 const struct snd_bebob_spec maudio_nrv10_spec = {
0794 .clock = NULL,
0795 .rate = &usual_rate_spec,
0796 .meter = &nrv10_meter_spec
0797 };