1 /* 2 * bebob_maudio.c - a part of driver for BeBoB based devices 3 * 4 * Copyright (c) 2013-2014 Takashi Sakamoto 5 * 6 * Licensed under the terms of the GNU General Public License, version 2. 7 */ 8 9 #include "./bebob.h" 10 11 /* 12 * Just powering on, Firewire 410/Audiophile wait to 13 * download firmware blob. To enable these devices, drivers should upload 14 * firmware blob and send a command to initialize configuration to factory 15 * settings when completing uploading. Then these devices generate bus reset 16 * and are recognized as new devices with the firmware. 17 * 18 * For streaming, both of output and input streams are needed for Firewire 410 19 * and Ozonic. The single stream is OK for the other devices even if the clock 20 * source is not SYT-Match (I note no devices use SYT-Match). 21 * 22 * Without streaming, the devices except for Firewire Audiophile can mix any 23 * input and output. For this reason, Audiophile cannot be used as standalone 24 * mixer. 25 */ 26 27 #define MAUDIO_SPECIFIC_ADDRESS 0xffc700000000 28 29 #define METER_OFFSET 0x00600000 30 31 /* some device has sync info after metering data */ 32 #define METER_SIZE_FW410 76 /* with sync info */ 33 #define METER_SIZE_AUDIOPHILE 60 /* with sync info */ 34 #define METER_SIZE_SOLO 52 /* with sync info */ 35 #define METER_SIZE_OZONIC 48 36 #define METER_SIZE_NRV10 80 37 38 /* labels for metering */ 39 #define ANA_IN "Analog In" 40 #define ANA_OUT "Analog Out" 41 #define DIG_IN "Digital In" 42 #define SPDIF_IN "S/PDIF In" 43 #define ADAT_IN "ADAT In" 44 #define DIG_OUT "Digital Out" 45 #define SPDIF_OUT "S/PDIF Out" 46 #define ADAT_OUT "ADAT Out" 47 #define STRM_IN "Stream In" 48 #define AUX_OUT "Aux Out" 49 #define HP_OUT "HP Out" 50 /* for NRV */ 51 #define UNKNOWN_METER "Unknown" 52 53 static inline int 54 get_meter(struct snd_bebob *bebob, void *buf, unsigned int size) 55 { 56 return snd_fw_transaction(bebob->unit, TCODE_READ_BLOCK_REQUEST, 57 MAUDIO_SPECIFIC_ADDRESS + METER_OFFSET, 58 buf, size, 0); 59 } 60 61 /* last 4 bytes are omitted because it's clock info. */ 62 static char *const fw410_meter_labels[] = { 63 ANA_IN, DIG_IN, 64 ANA_OUT, ANA_OUT, ANA_OUT, ANA_OUT, DIG_OUT, 65 HP_OUT 66 }; 67 static char *const audiophile_meter_labels[] = { 68 ANA_IN, DIG_IN, 69 ANA_OUT, ANA_OUT, DIG_OUT, 70 HP_OUT, AUX_OUT, 71 }; 72 static char *const solo_meter_labels[] = { 73 ANA_IN, DIG_IN, 74 STRM_IN, STRM_IN, 75 ANA_OUT, DIG_OUT 76 }; 77 78 /* no clock info */ 79 static char *const ozonic_meter_labels[] = { 80 ANA_IN, ANA_IN, 81 STRM_IN, STRM_IN, 82 ANA_OUT, ANA_OUT 83 }; 84 /* TODO: need testers. these positions are based on authour's assumption */ 85 static char *const nrv10_meter_labels[] = { 86 ANA_IN, ANA_IN, ANA_IN, ANA_IN, 87 DIG_IN, 88 ANA_OUT, ANA_OUT, ANA_OUT, ANA_OUT, 89 DIG_IN 90 }; 91 static int 92 normal_meter_get(struct snd_bebob *bebob, u32 *buf, unsigned int size) 93 { 94 struct snd_bebob_meter_spec *spec = bebob->spec->meter; 95 unsigned int c, channels; 96 int err; 97 98 channels = spec->num * 2; 99 if (size < channels * sizeof(u32)) 100 return -EINVAL; 101 102 err = get_meter(bebob, (void *)buf, size); 103 if (err < 0) 104 goto end; 105 106 for (c = 0; c < channels; c++) 107 be32_to_cpus(&buf[c]); 108 109 /* swap stream channels because inverted */ 110 if (spec->labels == solo_meter_labels) { 111 swap(buf[4], buf[6]); 112 swap(buf[5], buf[7]); 113 } 114 end: 115 return err; 116 } 117 118 /* Firewire 410 specification */ 119 static struct snd_bebob_rate_spec usual_rate_spec = { 120 .get = &snd_bebob_stream_get_rate, 121 .set = &snd_bebob_stream_set_rate, 122 }; 123 static struct snd_bebob_meter_spec fw410_meter_spec = { 124 .num = ARRAY_SIZE(fw410_meter_labels), 125 .labels = fw410_meter_labels, 126 .get = &normal_meter_get 127 }; 128 struct snd_bebob_spec maudio_fw410_spec = { 129 .clock = NULL, 130 .rate = &usual_rate_spec, 131 .meter = &fw410_meter_spec 132 }; 133 134 /* Firewire Audiophile specification */ 135 static struct snd_bebob_meter_spec audiophile_meter_spec = { 136 .num = ARRAY_SIZE(audiophile_meter_labels), 137 .labels = audiophile_meter_labels, 138 .get = &normal_meter_get 139 }; 140 struct snd_bebob_spec maudio_audiophile_spec = { 141 .clock = NULL, 142 .rate = &usual_rate_spec, 143 .meter = &audiophile_meter_spec 144 }; 145 146 /* Firewire Solo specification */ 147 static struct snd_bebob_meter_spec solo_meter_spec = { 148 .num = ARRAY_SIZE(solo_meter_labels), 149 .labels = solo_meter_labels, 150 .get = &normal_meter_get 151 }; 152 struct snd_bebob_spec maudio_solo_spec = { 153 .clock = NULL, 154 .rate = &usual_rate_spec, 155 .meter = &solo_meter_spec 156 }; 157 158 /* Ozonic specification */ 159 static struct snd_bebob_meter_spec ozonic_meter_spec = { 160 .num = ARRAY_SIZE(ozonic_meter_labels), 161 .labels = ozonic_meter_labels, 162 .get = &normal_meter_get 163 }; 164 struct snd_bebob_spec maudio_ozonic_spec = { 165 .clock = NULL, 166 .rate = &usual_rate_spec, 167 .meter = &ozonic_meter_spec 168 }; 169 170 /* NRV10 specification */ 171 static struct snd_bebob_meter_spec nrv10_meter_spec = { 172 .num = ARRAY_SIZE(nrv10_meter_labels), 173 .labels = nrv10_meter_labels, 174 .get = &normal_meter_get 175 }; 176 struct snd_bebob_spec maudio_nrv10_spec = { 177 .clock = NULL, 178 .rate = &usual_rate_spec, 179 .meter = &nrv10_meter_spec 180 }; 181