aboutsummaryrefslogtreecommitdiffstats
path: root/app/src/usb/pipe/ext_reg.rs
blob: 023ce9f9f37b809447f5ed36c28656cba035e23d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/// §32.8.7.4
/// Extended Register.
///
/// Offset: 0x08
/// Reset: 0xxxxxxxx
/// Property: NA
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub(crate) struct ExtReg(u16);

pub(crate) struct R {
    bits: u16,
}

pub(crate) struct W {
    bits: u16,
}

impl ExtReg {
    pub fn read(&self) -> R {
        R { bits: self.0 }
    }

    pub fn write<F>(&mut self, f: F)
    where
        F: FnOnce(&mut W) -> &mut W,
    {
        let mut w = W { bits: self.0 };
        f(&mut w);
        self.0 = w.bits;
    }
}

impl From<u16> for ExtReg {
    fn from(v: u16) -> Self {
        Self(v)
    }
}

impl R {
    /// Value in raw bits.
    pub fn bits(&self) -> u16 {
        self.bits
    }

    pub fn variable(&self) -> VariableR {
        let bits = {
            const POS: u8 = 4;
            const MASK: u16 = 0x7ff;
            (self.bits >> POS) & MASK
        };

        VariableR(bits)
    }

    pub fn subpid(&self) -> SubPIDR {
        let bits = {
            const POS: u8 = 0;
            const MASK: u16 = 0xf;
            ((self.bits >> POS) & MASK) as u8
        };

        SubPIDR(bits)
    }
}

/// Variable field send with extended token
///
/// These bits define the VARIABLE field sent with extended token. See
/// “Section 2.1.1 Protocol Extension Token in the reference document
/// ENGINEERING CHANGE NOTICE, USB 2.0 Link Power Management
/// Addendum.”
///
/// To support the USB2.0 Link Power Management addition the VARIABLE
/// field should be set as described below.
///
/// | VARIABLE       | Description           |
/// +----------------+-----------------------+
/// | VARIABLE[3:0]  | bLinkState[1]         |
/// | VARIABLE[7:4]  | BESL (See LPM ECN)[2] |
/// | VARIABLE[8]    | bRemoteWake[1]        |
/// | VARIABLE[10:9] | Reserved              |
///
/// [1] for a definition of LPM Token bRemoteWake and bLinkState
/// fields, refer to "Table 2-3 in the reference document ENGINEERING
/// CHANGE NOTICE, USB 2.0 Link Power Management Addendum"
///
/// [2] for a definition of LPM Token BESL field, refer to "Table 2-3
/// in the reference document ENGINEERING CHANGE NOTICE, USB 2.0 Link
/// Power Management Addendum" and "Table X-X1 in Errata for ECN USB
/// 2.0 Link Power Management.
pub(crate) struct VariableR(u16);
impl VariableR {
    pub fn bits(&self) -> u16 {
        self.0
    }
}

/// SUBPID field with extended token
///
/// These bits define the SUBPID field sent with extended token. See
/// “Section 2.1.1 Protocol Extension Token in the reference document
/// ENGINEERING CHANGE NOTICE, USB 2.0 Link Power Management
/// Addendum”.
///
/// To support the USB2.0 Link Power Management addition the SUBPID
/// field should be set as described in “Table 2.2 SubPID Types in the
/// reference document ENGINEERING CHANGE NOTICE, USB 2.0 Link Power
/// Management Addendum”.
pub(crate) struct SubPIDR(u8);
impl SubPIDR {
    pub fn bits(&self) -> u8 {
        self.0
    }
}

impl W {
    /// Write raw bits.
    pub unsafe fn bits(&mut self, v: u16) -> &mut Self {
        self.bits = v;
        self
    }

    pub fn variable(&mut self) -> VariableW {
        VariableW { w: self }
    }
    pub fn subpid(&mut self) -> SubPIDW {
        SubPIDW { w: self }
    }
}

pub(crate) struct VariableW<'a> {
    w: &'a mut W,
}
impl<'a> VariableW<'a> {
    pub unsafe fn bits(self, v: u16) -> &'a mut W {
        const POS: u8 = 4;
        const MASK: u16 = 0x7ff;
        self.w.bits &= !((MASK as u16) << POS);
        self.w.bits |= ((v & MASK) as u16) << POS;
        self.w
    }
}

pub(crate) struct SubPIDW<'a> {
    w: &'a mut W,
}
impl<'a> SubPIDW<'a> {
    pub unsafe fn bits(self, v: u16) -> &'a mut W {
        const POS: u8 = 0;
        const MASK: u16 = 0xf;
        self.w.bits &= !((MASK as u16) << POS);
        self.w.bits |= ((v & MASK) as u16) << POS;
        self.w
    }
}