rpk_firmware/
usb.rs

1use core::{
2    mem::MaybeUninit,
3    sync::atomic::{AtomicUsize, Ordering},
4};
5use embassy_usb::{
6    class::hid::{ReportId, RequestHandler},
7    control::{InResponse, OutResponse, Recipient, Request, RequestType},
8    driver::Driver,
9    types::InterfaceNumber,
10    Builder, Config, Handler,
11};
12
13use crate::hid::{HidReader, HidWriter};
14
15// HID
16const HID_DESC_DESCTYPE_HID: u8 = 0x21;
17const HID_DESC_DESCTYPE_HID_REPORT: u8 = 0x22;
18const HID_DESC_SPEC_1_11: [u8; 2] = [0x11, 0x01];
19const HID_DESC_COUNTRY_UNSPEC: u8 = 0x00;
20
21const HID_REQ_SET_IDLE: u8 = 0x0a;
22const HID_REQ_GET_IDLE: u8 = 0x02;
23const HID_REQ_GET_REPORT: u8 = 0x01;
24const HID_REQ_SET_REPORT: u8 = 0x09;
25const HID_REQ_GET_PROTOCOL: u8 = 0x03;
26const HID_REQ_SET_PROTOCOL: u8 = 0x0b;
27
28#[rustfmt::skip]
29pub const SHARED_REPORT_DESC: [u8; 59 + 73 + 25 + 25] = [
30    // NKRO_DESC [u8; 59]
31    0x05, 0x01, // (GLOBAL) USAGE_PAGE         0x0001 Generic Desktop Page
32    0x09, 0x06, // (LOCAL)  USAGE              0x00010006 Keyboard (Application Collection)
33    0xA1, 0x01, // (MAIN) COLLECTION 0x01 Application (Usage=0x00010006: Page=Generic Desktop Page,
34                // Usage=Keyboard, Type=Application Collection)
35    0x85, 0x06, //   (GLOBAL) REPORT_ID          0x06 (6)
36    0x05, 0x07, //   (GLOBAL) USAGE_PAGE         0x0007 Keyboard/Keypad Page
37    0x19, 0xE0, //   (LOCAL)  USAGE_MINIMUM      0x000700E0 Keyboard LeftControl (Dynamic Value)
38    0x29, 0xE7, //   (LOCAL)  USAGE_MAXIMUM      0x000700E7 Keyboard Right GUI (Dynamic Value)
39    0x15, 0x00, //   (GLOBAL) LOGICAL_MINIMUM    0x00 (0)
40    0x25, 0x01, //   (GLOBAL) LOGICAL_MAXIMUM    0x01 (1)
41    0x95, 0x08, //   (GLOBAL) REPORT_COUNT       0x08 (8) Number of fields
42    0x75, 0x01, //   (GLOBAL) REPORT_SIZE        0x01 (1) Number of bits per field
43    0x81, 0x02, //   (MAIN) INPUT 0x00000002 (8 fields x 1 bit) 0=Data 1=Variable 0=Absolute
44                //     0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
45    0x05, 0x07, //   (GLOBAL) USAGE_PAGE         0x0007 Keyboard/Keypad Page
46    0x19, 0x00, //   (LOCAL) USAGE_MINIMUM 0x00070000 Keyboard No event indicated (Selector)
47    0x29, 0xFE, //   (LOCAL)  USAGE_MAXIMUM      0x000700FE
48    0x15, 0x00, //   (GLOBAL) LOGICAL_MINIMUM    0x00 (0)
49    0x25, 0x01, //   (GLOBAL) LOGICAL_MAXIMUM    0x01 (1)
50    0x95, 0xFF, //   (GLOBAL) REPORT_COUNT       0xFF (255) Number of fields
51    0x75, 0x01, //   (GLOBAL) REPORT_SIZE        0x01 (1) Number of bits per field
52    0x81, 0x02, //   (MAIN) INPUT 0x00000002 (255 fields x 1 bit) 0=Data 1=Variable 0=Absolute
53                //     0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
54    0x05, 0x08, //   (GLOBAL) USAGE_PAGE         0x0008 LED Page
55    0x19, 0x01, //   (LOCAL)  USAGE_MINIMUM      0x00080001 Num Lock (On/Off Control)
56    0x29, 0x05, //   (LOCAL)  USAGE_MAXIMUM      0x00080005 Kana (On/Off Control)
57    0x95, 0x05, //   (GLOBAL) REPORT_COUNT       0x05 (5) Number of fields
58    0x75, 0x01, //   (GLOBAL) REPORT_SIZE        0x01 (1) Number of bits per field
59    0x91, 0x02, //   (MAIN) OUTPUT 0x00000002 (5 fields x 1 bit) 0=Data 1=Variable 0=Absolute
60                //   0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
61    0x95, 0x01, //   (GLOBAL) REPORT_COUNT       0x01 (1) Number of fields
62    0x75, 0x03, //   (GLOBAL) REPORT_SIZE        0x03 (3) Number of bits per field
63    0x91, 0x01, //   (MAIN) OUTPUT 0x00000001 (1 field x 3 bits) 1=Constant 0=Array 0=Absolute
64                //     0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
65    0xC0,       // (MAIN)   END_COLLECTION     Application
66
67    // MOUSE_DESC  [u8; 73]
68    0x05, 0x01, // (GLOBAL) USAGE_PAGE         0x0001 Generic Desktop Page
69    0x09, 0x02, // (LOCAL)  USAGE              0x00010002 Mouse (Application Collection)
70    0xA1, 0x01, // (MAIN) COLLECTION 0x01 Application (Usage=0x00010002: Page=Generic Desktop Page,
71                //  Usage=Mouse, Type=Application Collection)
72    0x85, 0x02, //   (GLOBAL) REPORT_ID          0x02 (2)
73    0x09, 0x01, //   (LOCAL)  USAGE              0x00010001 Pointer (Physical Collection)
74    0xA1, 0x00, //   (MAIN) COLLECTION 0x00 Physical (Usage=0x00010001: Page=Generic Desktop Page,
75                //    Usage=Pointer, Type=Physical Collection)
76    0x05, 0x09, //     (GLOBAL) USAGE_PAGE         0x0009 Button Page
77    0x19, 0x01, //     (LOCAL) USAGE_MINIMUM 0x00090001 Button 1 Primary/trigger (Selector, On/Off
78                //      Control, Momentary Control, or One Shot Control)
79    0x29, 0x08, //     (LOCAL) USAGE_MAXIMUM 0x00090008 Button 8 (Selector, On/Off Control,
80                //      Momentary Control, or One Shot Control)
81    0x15, 0x00, //     (GLOBAL) LOGICAL_MINIMUM    0x00 (0)
82    0x25, 0x01, //     (GLOBAL) LOGICAL_MAXIMUM    0x01 (1)
83    0x95, 0x08, //     (GLOBAL) REPORT_COUNT       0x08 (8) Number of fields
84    0x75, 0x01, //     (GLOBAL) REPORT_SIZE        0x01 (1) Number of bits per field
85    0x81, 0x02, //     (MAIN) INPUT 0x00000002 (8 fields x 1 bit) 0=Data 1=Variable 0=Absolute
86                //       0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
87    0x05, 0x01, //     (GLOBAL) USAGE_PAGE         0x0001 Generic Desktop Page
88    0x09, 0x30, //     (LOCAL)  USAGE              0x00010030 X (Dynamic Value)
89    0x09, 0x31, //     (LOCAL)  USAGE              0x00010031 Y (Dynamic Value)
90    0x15, 0x81, //     (GLOBAL) LOGICAL_MINIMUM    0x81 (-127)
91    0x25, 0x7F, //     (GLOBAL) LOGICAL_MAXIMUM    0x7F (127)
92    0x95, 0x02, //     (GLOBAL) REPORT_COUNT       0x02 (2) Number of fields
93    0x75, 0x08, //     (GLOBAL) REPORT_SIZE        0x08 (8) Number of bits per field
94    0x81, 0x06, //     (MAIN) INPUT 0x00000006 (2 fields x 8 bits) 0=Data 1=Variable 1=Relative
95                //       0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
96    0x09, 0x38, //     (LOCAL)  USAGE              0x00010038 Wheel (Dynamic Value)
97    0x15, 0x81, //     (GLOBAL) LOGICAL_MINIMUM    0x81 (-127)
98    0x25, 0x7F, //     (GLOBAL) LOGICAL_MAXIMUM    0x7F (127)
99    0x95, 0x01, //     (GLOBAL) REPORT_COUNT       0x01 (1) Number of fields
100    0x75, 0x08, //     (GLOBAL) REPORT_SIZE        0x08 (8) Number of bits per field
101    0x81, 0x06, //     (MAIN) INPUT 0x00000006 (1 field x 8 bits) 0=Data 1=Variable 1=Relative
102                //       0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
103    0x05, 0x0C, //     (GLOBAL) USAGE_PAGE         0x000C Consumer Page
104    0x0A, 0x38, 0x02,//(LOCAL)  USAGE              0x000C0238 AC Pan (Linear Control)
105    0x15, 0x81, //     (GLOBAL) LOGICAL_MINIMUM    0x81 (-127)
106    0x25, 0x7F, //     (GLOBAL) LOGICAL_MAXIMUM    0x7F (127)
107    0x95, 0x01, //     (GLOBAL) REPORT_COUNT       0x01 (1) Number of fields
108    0x75, 0x08, //     (GLOBAL) REPORT_SIZE        0x08 (8) Number of bits per field
109    0x81, 0x06, //     (MAIN) INPUT 0x00000006 (1 field x 8 bits) 0=Data 1=Variable 1=Relative
110                //       0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
111    0xC0,       //   (MAIN)   END_COLLECTION     Physical
112    0xC0,       // (MAIN)   END_COLLECTION     Application
113
114    //  SYS_CTL_DESC: [u8; 25]
115    0x05, 0x01, // (GLOBAL) USAGE_PAGE         0x0001 Generic Desktop Page
116    0x09, 0x80, // (LOCAL)  USAGE              0x00010080 System Control (Application Collection)
117    0xA1, 0x01, // (MAIN) COLLECTION 0x01 Application (Usage=0x00010080: Page=Generic Desktop Page,
118                //  Usage=System Control, Type=Application Collection)
119    0x85, 0x03, //   (GLOBAL) REPORT_ID          0x03 (3)
120    0x19, 0x01, //   (LOCAL)  USAGE_MINIMUM      0x00010001 Pointer (Physical Collection)
121    0x2A, 0xB7,0,//  (LOCAL)  USAGE_MAXIMUM      0x000100B7 System Display Toggle LCD Autoscale (One Shot Control)
122    0x15, 0x01, //   (GLOBAL) LOGICAL_MINIMUM    0x01 (1)
123    0x26, 0xB7,0,//  (GLOBAL) LOGICAL_MAXIMUM    0x00B7 (183)
124    0x95, 0x01, //   (GLOBAL) REPORT_COUNT       0x01 (1) Number of fields
125    0x75, 0x10, //   (GLOBAL) REPORT_SIZE        0x10 (16) Number of bits per field
126    0x81, 0x00, //   (MAIN)   INPUT              0x00000000 (1 field x 16 bits) 0=Data 0=Array 0=Absolute
127    0xC0,       // (MAIN)   END_COLLECTION     Application
128
129
130    // CONSUMER_CTL_DESC: [u8; 25]
131    0x05, 0x0C, // (GLOBAL) USAGE_PAGE         0x000C Consumer Page
132    0x09, 0x01, // (LOCAL)  USAGE              0x000C0001 Consumer Control (Application Collection)
133    0xA1, 0x01, // (MAIN) COLLECTION 0x01 Application (Usage=0x000C0001: Page=Consumer Page,
134                //  Usage=Consumer Control, Type=Application Collection)
135    0x85, 0x04, //   (GLOBAL) REPORT_ID          0x04 (4)
136    0x19, 0x01, //   (LOCAL)  USAGE_MINIMUM      0x000C0001 Consumer Control (Application Collection)
137    0x2A, 0xA0,2,//  (LOCAL)  USAGE_MAXIMUM      0x000C02A0 AC Soft Key Left (Selector)
138    0x15, 0x01, //   (GLOBAL) LOGICAL_MINIMUM    0x01 (1)
139    0x26, 0xA0,2,//  (GLOBAL) LOGICAL_MAXIMUM    0x02A0 (672)
140    0x95, 0x01, //   (GLOBAL) REPORT_COUNT       0x01 (1) Number of fields
141    0x75, 0x10, //   (GLOBAL) REPORT_SIZE        0x10 (16) Number of bits per field
142    0x81, 0x00, //   (MAIN)   INPUT              0x00000000 (1 field x 16 bits) 0=Data 0=Array 0=Absolute
143    0xC0,       // (MAIN)   END_COLLECTION     Application
144];
145
146/// Internal state for USB HID.
147pub struct State<'d> {
148    control: MaybeUninit<Control<'d>>,
149    out_report_offset: AtomicUsize,
150}
151impl Default for State<'_> {
152    fn default() -> Self {
153        Self::new()
154    }
155}
156impl State<'_> {
157    /// Create a new `State`.
158    pub const fn new() -> Self {
159        State {
160            control: MaybeUninit::uninit(),
161            out_report_offset: AtomicUsize::new(0),
162        }
163    }
164}
165
166const CONFIG_SIZE: usize = 128;
167const BOS_SIZE: usize = 32;
168const MSOS_SIZE: usize = 0;
169const CONTROL_SIZE: usize = 256;
170
171pub struct UsbBuffers {
172    config_descriptor_buf: [u8; CONFIG_SIZE],
173    bos_descriptor_buf: [u8; BOS_SIZE],
174    msos_descriptor_buf: [u8; MSOS_SIZE],
175    control_buf: [u8; CONTROL_SIZE],
176}
177
178impl Default for UsbBuffers {
179    fn default() -> Self {
180        Self {
181            config_descriptor_buf: [0; CONFIG_SIZE],
182            bos_descriptor_buf: [0; BOS_SIZE],
183            msos_descriptor_buf: [0; MSOS_SIZE],
184            control_buf: [0; CONTROL_SIZE],
185        }
186    }
187}
188
189pub struct Configurator<'d> {
190    device_config: Option<Config<'d>>,
191    max_packet_size: u16,
192    poll_ms: u8,
193}
194
195impl<'d> Configurator<'d> {
196    pub fn new(device_config: Config<'d>) -> Self {
197        Self {
198            device_config: Some(device_config),
199            max_packet_size: device_config.max_packet_size_0 as u16,
200            poll_ms: 1,
201        }
202    }
203
204    pub fn usb_builder<D: Driver<'d>>(
205        &mut self,
206        driver: D,
207        buffers: &'d mut UsbBuffers,
208    ) -> Option<Builder<'d, D>> {
209        //        return a tuple with the builder and the buffers which we create here; not in new func
210
211        self.device_config.take().map(|device_config| {
212            Builder::new(
213                driver,
214                device_config,
215                &mut buffers.config_descriptor_buf,
216                &mut buffers.bos_descriptor_buf,
217                &mut buffers.msos_descriptor_buf,
218                &mut buffers.control_buf,
219            )
220        })
221    }
222
223    pub fn add_iface<'a, D: Driver<'d>, const READ_N: usize, const WRITE_N: usize>(
224        &'d self,
225        builder: &'a mut Builder<'d, D>,
226        descriptor: &'static [u8],
227        need_reader: bool,
228        subclass: u8,
229        protocol: u8,
230        state: &'d mut State<'d>,
231    ) -> (HidWriter<'d, D, WRITE_N>, Option<HidReader<'d, D, READ_N>>) {
232        let mut func = builder.function(3, subclass, protocol);
233        let mut iface = func.interface();
234        let if_num = iface.interface_number();
235        let mut alt = iface.alt_setting(3, subclass, protocol, None);
236
237        let len = descriptor.len();
238        alt.descriptor(
239            HID_DESC_DESCTYPE_HID,
240            &[
241                0x11,               // HID Class spec Version
242                0x01,               //
243                0,                  // Country code not supported
244                1,                  // Number of following descriptors
245                34,                 // We have a HID report descriptor the host should read
246                (len & 0xFF) as u8, // HID report descriptor size,
247                (len >> 8 & 0xFF) as u8,
248            ],
249        );
250
251        let ep_in = alt.endpoint_interrupt_in(self.max_packet_size, self.poll_ms);
252        let ep_out = if need_reader {
253            Some(alt.endpoint_interrupt_out(self.max_packet_size, self.poll_ms))
254        } else {
255            None
256        };
257
258        drop(func);
259
260        let control = Control::new(
261            if_num,
262            descriptor,
263            None, // TODO  &self.request_handler,
264            &state.out_report_offset,
265        );
266        let control = state.control.write(control);
267        builder.handler(control);
268        (
269            HidWriter::new(ep_in),
270            ep_out.map(|ep_out| HidReader::new(ep_out, &state.out_report_offset)),
271        )
272    }
273}
274
275struct Control<'d> {
276    if_num: InterfaceNumber,
277    report_descriptor: &'d [u8],
278    request_handler: Option<&'d mut dyn RequestHandler>,
279    out_report_offset: &'d AtomicUsize,
280    hid_descriptor: [u8; 9],
281}
282impl<'d> Control<'d> {
283    fn new(
284        if_num: InterfaceNumber,
285        report_descriptor: &'d [u8],
286        request_handler: Option<&'d mut dyn RequestHandler>,
287        out_report_offset: &'d AtomicUsize,
288    ) -> Self {
289        Control {
290            if_num,
291            report_descriptor,
292            request_handler,
293            out_report_offset,
294            hid_descriptor: [
295                9,                                           // Length of buf inclusive of size prefix
296                HID_DESC_DESCTYPE_HID,                       // Descriptor type
297                HID_DESC_SPEC_1_11[0],                       // HID Class spec version
298                HID_DESC_SPEC_1_11[1],                       //
299                HID_DESC_COUNTRY_UNSPEC,                     // Country code not supported
300                1,                                           // Number of following descriptors
301                HID_DESC_DESCTYPE_HID_REPORT, // We have a HID report descriptor the host should read
302                (report_descriptor.len() & 0xFF) as u8, // HID report descriptor size,
303                (report_descriptor.len() >> 8 & 0xFF) as u8, //
304            ],
305        }
306    }
307}
308impl Handler for Control<'_> {
309    fn reset(&mut self) {
310        self.out_report_offset.store(0, Ordering::Release);
311    }
312
313    fn control_out(&mut self, req: Request, data: &[u8]) -> Option<OutResponse> {
314        if (req.request_type, req.recipient, req.index)
315            != (
316                RequestType::Class,
317                Recipient::Interface,
318                self.if_num.0 as u16,
319            )
320        {
321            return None;
322        }
323
324        match req.request {
325            HID_REQ_SET_IDLE => {
326                // How often we should send the keyboard state
327                if let Some(handler) = self.request_handler.as_mut() {
328                    let id = req.value as u8;
329                    let id = (id != 0).then_some(ReportId::In(id));
330                    let dur = u32::from(req.value >> 8);
331                    let dur = if dur == 0 { u32::MAX } else { 4 * dur };
332                    handler.set_idle_ms(id, dur);
333                }
334                Some(OutResponse::Accepted)
335            }
336            HID_REQ_SET_REPORT => {
337                match (report_id_try_from(req.value), self.request_handler.as_mut()) {
338                    (Ok(id), Some(handler)) => Some(handler.set_report(id, data)),
339                    _ => Some(OutResponse::Rejected),
340                }
341            }
342            HID_REQ_SET_PROTOCOL => {
343                if req.value == 1 {
344                    Some(OutResponse::Accepted)
345                } else {
346                    crate::warn!("HID Boot Protocol is unsupported.");
347                    Some(OutResponse::Rejected) // UNSUPPORTED: Boot Protocol
348                }
349            }
350            _ => Some(OutResponse::Rejected),
351        }
352    }
353
354    fn control_in<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> Option<InResponse<'a>> {
355        if req.index != self.if_num.0 as u16 {
356            return None;
357        }
358
359        match (req.request_type, req.recipient) {
360            (RequestType::Standard, Recipient::Interface) => match req.request {
361                Request::GET_DESCRIPTOR => match (req.value >> 8) as u8 {
362                    HID_DESC_DESCTYPE_HID_REPORT => {
363                        Some(InResponse::Accepted(self.report_descriptor))
364                    }
365                    HID_DESC_DESCTYPE_HID => Some(InResponse::Accepted(&self.hid_descriptor)),
366                    _ => Some(InResponse::Rejected),
367                },
368
369                _ => Some(InResponse::Rejected),
370            },
371            (RequestType::Class, Recipient::Interface) => {
372                match req.request {
373                    HID_REQ_GET_REPORT => {
374                        let size = match report_id_try_from(req.value) {
375                            Ok(id) => self
376                                .request_handler
377                                .as_mut()
378                                .and_then(|x| x.get_report(id, buf)),
379                            Err(_) => None,
380                        };
381
382                        if let Some(size) = size {
383                            Some(InResponse::Accepted(&buf[0..size]))
384                        } else {
385                            Some(InResponse::Rejected)
386                        }
387                    }
388                    HID_REQ_GET_IDLE => {
389                        if let Some(handler) = self.request_handler.as_mut() {
390                            let id = req.value as u8;
391                            let id = (id != 0).then_some(ReportId::In(id));
392                            if let Some(dur) = handler.get_idle_ms(id) {
393                                let dur = u8::try_from(dur / 4).unwrap_or(0);
394                                buf[0] = dur;
395                                Some(InResponse::Accepted(&buf[0..1]))
396                            } else {
397                                Some(InResponse::Rejected)
398                            }
399                        } else {
400                            Some(InResponse::Rejected)
401                        }
402                    }
403                    HID_REQ_GET_PROTOCOL => {
404                        // UNSUPPORTED: Boot Protocol
405                        buf[0] = 1;
406                        Some(InResponse::Accepted(&buf[0..1]))
407                    }
408                    _ => Some(InResponse::Rejected),
409                }
410            }
411            _ => None,
412        }
413    }
414}
415
416const fn report_id_try_from(value: u16) -> Result<ReportId, ()> {
417    match value >> 8 {
418        1 => Ok(ReportId::In(value as u8)),
419        2 => Ok(ReportId::Out(value as u8)),
420        3 => Ok(ReportId::Feature(value as u8)),
421        _ => Err(()),
422    }
423}