1use super::*;
10
11const CATEGORY_PORT_CONF: u32 = 9;
12
13const CMD_SET_MIRROR: u32 = 0;
14const CMD_GET_MIRROR: u32 = 1;
15const CMD_SET_DIG_MODE: u32 = 2;
16const CMD_GET_DIG_MODE: u32 = 3;
17const CMD_SET_PHANTOM: u32 = 4;
18const CMD_GET_PHANTOM: u32 = 5;
19const CMD_SET_STREAM_MAP: u32 = 6;
20const CMD_GET_STREAM_MAP: u32 = 7;
21
22#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
24pub struct EfwControlRoomSource(pub usize);
25
26const CONTROL_ROOM_SOURCES: &[PhysGroupType] = &[
27 PhysGroupType::Analog,
28 PhysGroupType::Headphones,
29 PhysGroupType::Spdif,
30];
31
32pub trait EfwControlRoomSpecification: EfwHardwareSpecification {
34 fn control_room_source_pairs() -> Vec<(PhysGroupType, usize)> {
35 Self::PHYS_OUTPUT_GROUPS
36 .iter()
37 .filter(|(group_type, _)| {
38 CONTROL_ROOM_SOURCES
39 .iter()
40 .find(|t| group_type.eq(t))
41 .is_some()
42 })
43 .flat_map(|&(group_type, count)| {
44 let entries: Vec<(PhysGroupType, usize)> =
45 (0..count).step_by(2).map(|i| (group_type, i)).collect();
46 entries
47 })
48 .collect()
49 }
50}
51
52fn phys_group_pairs(groups: &[(PhysGroupType, usize)]) -> Vec<(PhysGroupType, usize)> {
53 groups
54 .iter()
55 .flat_map(|&(group_type, count)| {
56 let entries: Vec<(PhysGroupType, usize)> =
57 (0..count).step_by(2).map(|pos| (group_type, pos)).collect();
58 entries
59 })
60 .collect()
61}
62
63impl<O, P> EfwWhollyCachableParamsOperation<P, EfwControlRoomSource> for O
64where
65 O: EfwControlRoomSpecification,
66 P: EfwProtocolExtManual,
67{
68 fn cache_wholly(
69 proto: &mut P,
70 states: &mut EfwControlRoomSource,
71 timeout_ms: u32,
72 ) -> Result<(), Error> {
73 let args = Vec::new();
74 let mut params = vec![0];
75 proto.transaction(
76 CATEGORY_PORT_CONF,
77 CMD_GET_MIRROR,
78 &args,
79 &mut params,
80 timeout_ms,
81 )?;
82 let pos = (params[0] / 2) as usize;
83 let entries = phys_group_pairs(Self::PHYS_OUTPUT_GROUPS);
84 let entry = entries.iter().nth(pos).ok_or_else(|| {
85 let msg = format!("Unexpected value {} for source of control room", pos);
86 Error::new(FileError::Nxio, &msg)
87 })?;
88
89 states.0 = Self::control_room_source_pairs()
90 .iter()
91 .position(|e| entry.eq(e))
92 .ok_or_else(|| {
93 let msg = format!(
94 "Unexpected entry for source of control room: {:?},{}",
95 entry.0, entry.1
96 );
97 Error::new(FileError::Nxio, &msg)
98 })?;
99
100 Ok(())
101 }
102}
103
104impl<O, P> EfwWhollyUpdatableParamsOperation<P, EfwControlRoomSource> for O
105where
106 O: EfwControlRoomSpecification,
107 P: EfwProtocolExtManual,
108{
109 fn update_wholly(
110 proto: &mut P,
111 states: &EfwControlRoomSource,
112 timeout_ms: u32,
113 ) -> Result<(), Error> {
114 let pairs = Self::control_room_source_pairs();
115 let entry = pairs.iter().nth(states.0).ok_or_else(|| {
116 let msg = format!("Invalid value for source of control room: {}", states.0);
117 Error::new(FileError::Inval, &msg)
118 })?;
119
120 let pos = phys_group_pairs(Self::PHYS_OUTPUT_GROUPS)
121 .iter()
122 .position(|e| entry.eq(&e))
123 .map(|pos| pos * 2)
124 .ok_or_else(|| {
125 let msg = format!(
126 "Invalid entry for source of control room: {:?},{}",
127 entry.0, entry.1
128 );
129 Error::new(FileError::Inval, &msg)
130 })?;
131
132 let args = [pos as u32];
133 let mut params = Vec::new();
134 proto.transaction(
135 CATEGORY_PORT_CONF,
136 CMD_SET_MIRROR,
137 &args,
138 &mut params,
139 timeout_ms,
140 )
141 }
142}
143
144#[derive(Debug, Copy, Clone, PartialEq, Eq)]
146pub enum EfwDigitalMode {
147 SpdifCoax,
149 AesebuXlr,
151 SpdifOpt,
153 AdatOpt,
155 Unknown(u32),
156}
157
158impl Default for EfwDigitalMode {
159 fn default() -> Self {
160 Self::Unknown(u32::MAX)
161 }
162}
163
164fn serialize_digital_mode(mode: &EfwDigitalMode, val: &mut u32) {
165 *val = match *mode {
166 EfwDigitalMode::SpdifCoax => 0,
167 EfwDigitalMode::AesebuXlr => 1,
168 EfwDigitalMode::SpdifOpt => 2,
169 EfwDigitalMode::AdatOpt => 3,
170 EfwDigitalMode::Unknown(val) => val,
171 };
172}
173
174fn deserialize_digital_mode(val: u32) -> EfwDigitalMode {
175 match val {
176 0 => EfwDigitalMode::SpdifCoax,
177 1 => EfwDigitalMode::AesebuXlr,
178 2 => EfwDigitalMode::SpdifOpt,
179 3 => EfwDigitalMode::AdatOpt,
180 _ => EfwDigitalMode::Unknown(val),
181 }
182}
183
184pub trait EfwDigitalModeSpecification: EfwHardwareSpecification {
186 const DIG_MODES: &'static [(HwCap, EfwDigitalMode)] = &[
187 (HwCap::OptionalSpdifCoax, EfwDigitalMode::SpdifCoax),
188 (HwCap::OptionalAesebuXlr, EfwDigitalMode::AesebuXlr),
189 (HwCap::OptionalSpdifOpt, EfwDigitalMode::SpdifOpt),
190 (HwCap::OptionalAdatOpt, EfwDigitalMode::AdatOpt),
191 ];
192
193 fn create_digital_mode() -> EfwDigitalMode {
194 Self::DIG_MODES
195 .iter()
196 .find(|(cap, _)| Self::CAPABILITIES.iter().find(|c| cap.eq(c)).is_some())
197 .map(|(_, mode)| *mode)
198 .unwrap()
199 }
200
201 fn create_digital_modes() -> Vec<EfwDigitalMode> {
202 Self::DIG_MODES
203 .iter()
204 .filter(|(cap, _)| Self::CAPABILITIES.iter().find(|c| cap.eq(c)).is_some())
205 .map(|(_, mode)| *mode)
206 .collect()
207 }
208}
209
210impl<O, P> EfwWhollyCachableParamsOperation<P, EfwDigitalMode> for O
211where
212 O: EfwDigitalModeSpecification,
213 P: EfwProtocolExtManual,
214{
215 fn cache_wholly(
216 proto: &mut P,
217 states: &mut EfwDigitalMode,
218 timeout_ms: u32,
219 ) -> Result<(), Error> {
220 assert!(Self::CAPABILITIES
221 .iter()
222 .find(|cap| Self::DIG_MODES.iter().find(|(c, _)| c.eq(cap)).is_some())
223 .is_some());
224
225 let args = Vec::new();
226 let mut params = vec![0];
227 proto
228 .transaction(
229 CATEGORY_PORT_CONF,
230 CMD_GET_DIG_MODE,
231 &args,
232 &mut params,
233 timeout_ms,
234 )
235 .map(|_| *states = deserialize_digital_mode(params[0]))
236 }
237}
238
239impl<O, P> EfwWhollyUpdatableParamsOperation<P, EfwDigitalMode> for O
240where
241 O: EfwDigitalModeSpecification,
242 P: EfwProtocolExtManual,
243{
244 fn update_wholly(proto: &mut P, states: &EfwDigitalMode, timeout_ms: u32) -> Result<(), Error> {
245 assert!(Self::CAPABILITIES
246 .iter()
247 .find(|cap| Self::DIG_MODES.iter().find(|(c, _)| c.eq(cap)).is_some())
248 .is_some());
249
250 let mut args = [0];
251 let mut params = Vec::new();
252 serialize_digital_mode(&states, &mut args[0]);
253 proto.transaction(
254 CATEGORY_PORT_CONF,
255 CMD_SET_DIG_MODE,
256 &args,
257 &mut params,
258 timeout_ms,
259 )
260 }
261}
262
263#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
265pub struct EfwPhantomPowering(pub bool);
266
267pub trait EfwPhantomPoweringSpecification: EfwHardwareSpecification {}
269
270impl<O, P> EfwWhollyCachableParamsOperation<P, EfwPhantomPowering> for O
271where
272 O: EfwPhantomPoweringSpecification,
273 P: EfwProtocolExtManual,
274{
275 fn cache_wholly(
276 proto: &mut P,
277 states: &mut EfwPhantomPowering,
278 timeout_ms: u32,
279 ) -> Result<(), Error> {
280 let args = Vec::new();
281 let mut params = vec![0];
282 proto
283 .transaction(
284 CATEGORY_PORT_CONF,
285 CMD_GET_PHANTOM,
286 &args,
287 &mut params,
288 timeout_ms,
289 )
290 .map(|_| states.0 = params[0] > 0)
291 }
292}
293
294impl<O, P> EfwWhollyUpdatableParamsOperation<P, EfwPhantomPowering> for O
295where
296 O: EfwPhantomPoweringSpecification,
297 P: EfwProtocolExtManual,
298{
299 fn update_wholly(
300 proto: &mut P,
301 states: &EfwPhantomPowering,
302 timeout_ms: u32,
303 ) -> Result<(), Error> {
304 let args = [states.0 as u32];
305 let mut params = Vec::new();
306 proto.transaction(
307 CATEGORY_PORT_CONF,
308 CMD_SET_PHANTOM,
309 &args,
310 &mut params,
311 timeout_ms,
312 )
313 }
314}
315
316#[derive(Debug, Clone, PartialEq, Eq)]
319pub struct EfwRxStreamMaps(pub Vec<Vec<usize>>);
320
321pub trait EfwRxStreamMapsSpecification: EfwHardwareSpecification {
323 const STREAM_MAPPING_RATE_TABLE: [&'static [u32]; 3] =
324 [&[44100, 48000, 32000], &[88200, 96000], &[176400, 192000]];
325
326 fn create_rx_stream_maps() -> EfwRxStreamMaps {
327 let maps = Self::RX_CHANNEL_COUNTS
328 .iter()
329 .map(|&count| vec![Default::default(); count])
330 .collect();
331 EfwRxStreamMaps(maps)
332 }
333}
334
335const MAP_SIZE: usize = 70;
336const MAP_ENTRY_UNABAILABLE: u32 = 0xffffffff;
337
338impl<O, P> EfwWhollyCachableParamsOperation<P, EfwRxStreamMaps> for O
339where
340 O: EfwRxStreamMapsSpecification,
341 P: EfwProtocolExtManual,
342{
343 fn cache_wholly(
344 proto: &mut P,
345 states: &mut EfwRxStreamMaps,
346 timeout_ms: u32,
347 ) -> Result<(), Error> {
348 states
349 .0
350 .iter_mut()
351 .zip(Self::STREAM_MAPPING_RATE_TABLE)
352 .try_for_each(|(state, rates)| {
353 let args = [rates[0] as u32];
354 let mut params = vec![0; MAP_SIZE];
355
356 proto
357 .transaction(
358 CATEGORY_PORT_CONF,
359 CMD_GET_STREAM_MAP,
360 &args,
361 &mut params,
362 timeout_ms,
363 )
364 .map(|_| {
365 params[4..]
366 .iter()
367 .zip(state.iter_mut())
368 .for_each(|(&quad, src)| *src = (quad / 2) as usize);
369 })
370 })
371 }
372}
373
374impl<O, P> EfwPartiallyUpdatableParamsOperation<P, EfwRxStreamMaps> for O
375where
376 O: EfwRxStreamMapsSpecification,
377 P: EfwProtocolExtManual,
378{
379 fn update_partially(
380 proto: &mut P,
381 states: &mut EfwRxStreamMaps,
382 updates: EfwRxStreamMaps,
383 timeout_ms: u32,
384 ) -> Result<(), Error> {
385 states
386 .0
387 .iter_mut()
388 .zip(&updates.0)
389 .zip(Self::STREAM_MAPPING_RATE_TABLE)
390 .zip(Self::RX_CHANNEL_COUNTS)
391 .zip(Self::TX_CHANNEL_COUNTS)
392 .filter(|((((o, n), _), _), _)| !n.eq(o))
393 .try_for_each(
394 |((((curr, update), rates), rx_channel_count), tx_channel_count)| {
395 let mut args = [0; MAP_SIZE];
396
397 args[0] = rates[0];
398 args[1] = 0;
400 args[2] = (rx_channel_count / 2) as u32;
401 args[3] = (Self::phys_output_count() / 2) as u32;
402 args[4..36].fill(MAP_ENTRY_UNABAILABLE);
403 args[36] = (tx_channel_count / 2) as u32;
404 args[37] = (Self::phys_input_count() / 2) as u32;
405 args[38..70].fill(MAP_ENTRY_UNABAILABLE);
406
407 args[4..]
408 .iter_mut()
409 .zip(update.iter())
410 .for_each(|(quad, &src)| *quad = (src * 2) as u32);
411
412 proto
415 .transaction(
416 CATEGORY_PORT_CONF,
417 CMD_SET_STREAM_MAP,
418 &args,
419 &mut Vec::new(),
420 timeout_ms,
421 )
422 .map(|_| curr.copy_from_slice(&update))
423 },
424 )
425 }
426}