firewire_tascam_protocols/
asynch.rs

1// SPDX-License-Identifier: LGPL-3.0-or-later
2// Copyright (c) 2021 Takashi Sakamoto
3
4//! Protocols defined for Tascam for FireWire series only with asynchronous communication.
5//!
6//! The module includes protocol implementation defined by Tascam for FireWire series only with
7//! asynchronous communication.
8
9pub mod fe8;
10
11use {
12    super::*,
13    glib::{
14        subclass::{object::*, types::*},
15        *,
16    },
17    hinawa::{prelude::*, subclass::prelude::*, *},
18    hitaki::{prelude::*, subclass::prelude::*, *},
19    std::{cell::RefCell, sync::Mutex},
20};
21
22const ASYNCH_IMAGE_QUADLET_COUNT: usize = TascamExpander::QUADLET_COUNT;
23
24glib::wrapper! {
25    /// The implementation of `hitaki::TascamProtocol` so that it can cache status of hardware
26    /// from message in asynchronous packet from the hardware as ALSA firewire-tascam driver does
27    /// for message in isochronous packet.
28    pub struct TascamExpander(ObjectSubclass<imp::TascamExpanderPrivate>)
29        @extends FwResp, @implements TascamProtocol;
30}
31
32impl TascamExpander {
33    pub const QUADLET_COUNT: usize = imp::RESPONSE_FRAME_SIZE / 4;
34
35    pub fn new() -> Self {
36        Object::new(&[]).expect("Failed to create TascamExpander")
37    }
38
39    fn node(&self) -> FwNode {
40        self.property::<FwNode>("node")
41    }
42
43    pub fn bind(&self, node: &FwNode) -> Result<(), Error> {
44        self.reserve_within_region(
45            node,
46            imp::RESPONSE_REGION_START,
47            imp::RESPONSE_REGION_END,
48            imp::RESPONSE_FRAME_SIZE as u32,
49        )?;
50
51        let mut addr = self.offset();
52        addr |= (node.local_node_id() as u64) << 48;
53
54        let mut req = FwReq::new();
55
56        let mut addr_hi = ((addr >> 32) as u32).to_be_bytes();
57        write_quadlet(&mut req, node, imp::ADDR_HIGH_OFFSET, &mut addr_hi, 100)?;
58
59        let mut addr_lo = ((addr & 0xffffffff) as u32).to_be_bytes();
60        write_quadlet(&mut req, node, imp::ADDR_LOW_OFFSET, &mut addr_lo, 100)?;
61
62        self.set_property("node", node);
63
64        Ok(())
65    }
66
67    pub fn listen(&self) -> Result<(), Error> {
68        let mut frames = 1u32.to_be_bytes();
69        let mut req = FwReq::new();
70        write_quadlet(
71            &mut req,
72            &self.node(),
73            imp::ENABLE_NOTIFICATION,
74            &mut frames,
75            100,
76        )
77    }
78
79    pub fn unlisten(&self) {
80        let mut frames = 0u32.to_be_bytes();
81        let mut req = FwReq::new();
82        let _ = write_quadlet(
83            &mut req,
84            &self.node(),
85            imp::ENABLE_NOTIFICATION,
86            &mut frames,
87            100,
88        );
89    }
90
91    pub fn unbind(&self) {
92        self.release();
93
94        let mut req = FwReq::new();
95        let _ = write_quadlet(
96            &mut req,
97            &self.node(),
98            imp::ADDR_HIGH_OFFSET,
99            &mut [0; 4],
100            100,
101        );
102        let _ = write_quadlet(
103            &mut req,
104            &self.node(),
105            imp::ADDR_LOW_OFFSET,
106            &mut [0; 4],
107            100,
108        );
109
110        let private = imp::TascamExpanderPrivate::from_instance(self);
111        *private.0.borrow_mut() = None;
112    }
113}
114
115mod imp {
116    use {super::*, once_cell::sync::Lazy};
117
118    pub const RESPONSE_REGION_START: u64 = 0xffffe0000000;
119    pub const RESPONSE_REGION_END: u64 = 0xfffff0000000;
120    pub const RESPONSE_FRAME_SIZE: usize = 0x80;
121
122    pub const ENABLE_NOTIFICATION: u64 = 0x0310;
123    pub const ADDR_HIGH_OFFSET: u64 = 0x0314;
124    pub const ADDR_LOW_OFFSET: u64 = 0x0318;
125
126    #[derive(Default)]
127    pub struct TascamExpanderPrivate(
128        pub RefCell<Option<FwNode>>,
129        RefCell<Mutex<[u32; super::TascamExpander::QUADLET_COUNT]>>,
130    );
131
132    #[glib::object_subclass]
133    impl ObjectSubclass for TascamExpanderPrivate {
134        const NAME: &'static str = "TascamExpander";
135        type Type = super::TascamExpander;
136        type ParentType = FwResp;
137        type Interfaces = (TascamProtocol,);
138
139        fn new() -> Self {
140            Self::default()
141        }
142    }
143
144    impl ObjectImpl for TascamExpanderPrivate {
145        fn properties() -> &'static [ParamSpec] {
146            static PROPERTIES: Lazy<Vec<ParamSpec>> = Lazy::new(|| {
147                vec![ParamSpecObject::new(
148                    "node",
149                    "node",
150                    "An instance of FwNode",
151                    FwNode::static_type(),
152                    ParamFlags::READWRITE,
153                )]
154            });
155
156            PROPERTIES.as_ref()
157        }
158
159        fn property(&self, _obj: &Self::Type, _id: usize, pspec: &ParamSpec) -> Value {
160            match pspec.name() {
161                "node" => self.0.borrow().as_ref().unwrap().to_value(),
162                _ => unimplemented!(),
163            }
164        }
165
166        fn set_property(&self, _unit: &Self::Type, _id: usize, value: &Value, pspec: &ParamSpec) {
167            match pspec.name() {
168                "node" => {
169                    let node = value
170                        .get()
171                        .expect("type conformity checked by `Object::set_property`");
172                    *self.0.borrow_mut() = node;
173                }
174                _ => unimplemented!(),
175            }
176        }
177    }
178
179    fn parse_notification(
180        image: &mut [u32],
181        events: &mut Vec<(u32, u32, u32)>,
182        tcode: FwTcode,
183        frame: &[u8],
184    ) -> FwRcode {
185        if tcode == FwTcode::WriteQuadletRequest || tcode == FwTcode::WriteBlockRequest {
186            let mut quadlet = [0; 4];
187            (0..frame.len()).step_by(4).for_each(|pos| {
188                quadlet.copy_from_slice(&frame[pos..(pos + 4)]);
189                let value = u32::from_be_bytes(quadlet);
190                let index = ((value & 0x00ff0000) >> 16) as usize;
191                let state = value & 0x0000ffff;
192                if index < image.len() && image[index] != state {
193                    events.push((index as u32, image[index], state));
194                    image[index] = state;
195                }
196            });
197            FwRcode::Complete
198        } else {
199            FwRcode::TypeError
200        }
201    }
202
203    impl FwRespImpl for TascamExpanderPrivate {
204        fn requested2(
205            &self,
206            resp: &Self::Type,
207            tcode: FwTcode,
208            offset: u64,
209            src: u32,
210            _dst: u32,
211            _card: u32,
212            _generation: u32,
213            frame: &[u8],
214        ) -> FwRcode {
215            if !resp.is_reserved() {
216                return FwRcode::DataError;
217            }
218
219            let inst = match resp.downcast_ref::<super::TascamExpander>() {
220                Some(inst) => inst,
221                None => return FwRcode::DataError,
222            };
223
224            match self.0.borrow().as_ref() {
225                Some(node) => {
226                    if src != node.node_id() || offset != resp.offset() {
227                        return FwRcode::AddressError;
228                    }
229                }
230                None => return FwRcode::DataError,
231            }
232
233            let mut events = Vec::<(u32, u32, u32)>::new();
234
235            let rcode = self
236                .1
237                .borrow_mut()
238                .lock()
239                .map(|mut image| {
240                    parse_notification(&mut image[..], &mut events, tcode, frame);
241                    FwRcode::Complete
242                })
243                .unwrap_or(FwRcode::DataError);
244
245            events
246                .iter()
247                .for_each(|ev| inst.emit_changed(ev.0, ev.1, ev.2));
248
249            rcode
250        }
251    }
252
253    impl TascamProtocolImpl for TascamExpanderPrivate {
254        fn read_state(&self, _unit: &Self::Type, state: &mut Vec<u32>) -> Result<(), Error> {
255            if state.len() < super::TascamExpander::QUADLET_COUNT {
256                let msg = format!(
257                    "The size of buffer should be greater than 32 but {}",
258                    state.len()
259                );
260                Err(Error::new(FileError::Inval, &msg))
261            } else {
262                self.1
263                    .borrow()
264                    .lock()
265                    .map(|image| {
266                        state.copy_from_slice(&image[..]);
267                        state.truncate(super::TascamExpander::QUADLET_COUNT);
268                    })
269                    .map_err(|e| {
270                        let msg = format!("{:?}", e);
271                        Error::new(FileError::Io, &msg)
272                    })
273            }
274        }
275
276        fn changed(&self, _unit: &Self::Type, _index: u32, _before: u32, _after: u32) {}
277    }
278}