capsules_extra/usb/
keyboard_hid.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2023.
4
5//! Keyboard USB HID device
6
7use super::descriptors;
8use super::descriptors::Buffer64;
9use super::descriptors::DescriptorType;
10use super::descriptors::EndpointAddress;
11use super::descriptors::EndpointDescriptor;
12use super::descriptors::HIDCountryCode;
13use super::descriptors::HIDDescriptor;
14use super::descriptors::HIDSubordinateDescriptor;
15use super::descriptors::InterfaceDescriptor;
16use super::descriptors::ReportDescriptor;
17use super::descriptors::TransferDirection;
18use super::usbc_client_ctrl::ClientCtrl;
19
20use kernel::hil;
21use kernel::hil::usb::TransferType;
22use kernel::utilities::cells::OptionalCell;
23use kernel::utilities::cells::TakeCell;
24use kernel::ErrorCode;
25
26/// Use 1 Interrupt transfer IN/OUT endpoint
27const ENDPOINT_NUM: usize = 1;
28
29const IN_BUFFER: usize = 0;
30
31static LANGUAGES: &[u16; 1] = &[
32    0x0409, // English (United States)
33];
34/// Max packet size specified by spec
35pub const MAX_CTRL_PACKET_SIZE: u8 = 64;
36
37const N_ENDPOINTS: usize = 1;
38
39/// The HID report descriptor for keyboard from
40/// <https://www.usb.org/sites/default/files/hid1_11.pdf>.
41static REPORT_DESCRIPTOR: &[u8] = &[
42    0x05, 0x01, // Usage Page (Generic Desktop),
43    0x09, 0x06, // Usage (Keyboard),
44    0xA1, 0x01, // Collection (Application),
45    0x75, 0x01, // Report Size (1),
46    0x95, 0x08, // Report Count (8),
47    0x05, 0x07, // Usage Page (Key Codes),
48    0x19, 0xE0, // Usage Minimum (224),
49    0x29, 0xE7, // Usage Maximum (231),
50    0x15, 0x00, // Logical Minimum (0),
51    0x25, 0x01, // Logical Maximum (1),
52    0x81, 0x02, // Input (Data, Variable, Absolute),
53    // ;Modifier byte
54    0x95, 0x01, // Report Count (1),
55    0x75, 0x08, // Report Size (8),
56    0x81, 0x03, // Input (Constant),
57    // ;Reserved byte
58    0x95, 0x05, // Report Count (5),
59    0x75, 0x01, // Report Size (1),
60    0x05, 0x08, // Usage Page (LEDs),
61    0x19, 0x01, // Usage Minimum (1),
62    0x29, 0x05, // Usage Maximum (5),
63    0x91, 0x02, // Output (Data, Variable, Absolute),
64    // ;LED report
65    0x95, 0x01, // Report Count (1),
66    0x75, 0x03, // Report Size (3),
67    0x91, 0x03, // Output (Constant), ;LED report
68    // padding
69    0x95, 0x06, //................// Report Count (6),
70    0x75, 0x08, // Report Size (8),
71    0x15, 0x00, // Logical Minimum (0),
72    0x25, 0x68, // Logical Maximum(104),
73    0x05, 0x07, // Usage Page (Key Codes),
74    0x19, 0x00, // Usage Minimum (0),
75    0x29, 0x68, // Usage Maximum (104),
76    0x81, 0x00, // Input (Data, Array),
77    0xc0, // End Collection
78];
79
80static REPORT: ReportDescriptor<'static> = ReportDescriptor {
81    desc: REPORT_DESCRIPTOR,
82};
83
84static SUB_HID_DESCRIPTOR: &[HIDSubordinateDescriptor] = &[HIDSubordinateDescriptor {
85    typ: DescriptorType::Report,
86    len: REPORT_DESCRIPTOR.len() as u16,
87}];
88
89static HID_DESCRIPTOR: HIDDescriptor<'static> = HIDDescriptor {
90    hid_class: 0x0111,
91    country_code: HIDCountryCode::NotSupported,
92    sub_descriptors: SUB_HID_DESCRIPTOR,
93};
94
95/// Implementation of the CTAP HID (Human Interface Device)
96pub struct KeyboardHid<'a, U: 'a> {
97    /// Helper USB client library for handling many USB operations.
98    client_ctrl: ClientCtrl<'a, 'static, U>,
99
100    /// 64 byte buffers for each endpoint.
101    buffers: [Buffer64; N_ENDPOINTS],
102
103    client: OptionalCell<&'a dyn hil::usb_hid::Client<'a, [u8; 64]>>,
104
105    /// A buffer to hold the data we want to send
106    send_buffer: TakeCell<'static, [u8; 64]>,
107}
108
109impl<'a, U: hil::usb::UsbController<'a>> KeyboardHid<'a, U> {
110    pub fn new(
111        controller: &'a U,
112        vendor_id: u16,
113        product_id: u16,
114        strings: &'static [&'static str; 3],
115    ) -> Self {
116        let interfaces: &mut [InterfaceDescriptor] = &mut [InterfaceDescriptor {
117            interface_number: 0,
118            interface_class: 0x03,    // HID
119            interface_subclass: 0x01, // Boot subclass
120            interface_protocol: 0x01, // Keyboard
121            ..InterfaceDescriptor::default()
122        }];
123
124        let endpoints: &[&[EndpointDescriptor]] = &[&[EndpointDescriptor {
125            endpoint_address: EndpointAddress::new_const(
126                ENDPOINT_NUM,
127                TransferDirection::DeviceToHost,
128            ),
129            transfer_type: TransferType::Interrupt,
130            max_packet_size: 8,
131            interval: 10,
132        }]];
133
134        let (device_descriptor_buffer, other_descriptor_buffer) =
135            descriptors::create_descriptor_buffers(
136                descriptors::DeviceDescriptor {
137                    vendor_id,
138                    product_id,
139                    manufacturer_string: 1,
140                    product_string: 2,
141                    serial_number_string: 3,
142                    max_packet_size_ep0: MAX_CTRL_PACKET_SIZE,
143                    ..descriptors::DeviceDescriptor::default()
144                },
145                descriptors::ConfigurationDescriptor {
146                    attributes: descriptors::ConfigurationAttributes::new(true, true),
147                    max_power: 0x32,
148                    ..descriptors::ConfigurationDescriptor::default()
149                },
150                interfaces,
151                endpoints,
152                Some(&HID_DESCRIPTOR),
153                None,
154            );
155
156        KeyboardHid {
157            client_ctrl: ClientCtrl::new(
158                controller,
159                device_descriptor_buffer,
160                other_descriptor_buffer,
161                Some(&HID_DESCRIPTOR),
162                Some(&REPORT),
163                LANGUAGES,
164                strings,
165            ),
166            buffers: [Buffer64::default()],
167            client: OptionalCell::empty(),
168            send_buffer: TakeCell::empty(),
169        }
170    }
171
172    #[inline]
173    fn controller(&self) -> &'a U {
174        self.client_ctrl.controller()
175    }
176
177    pub fn set_client(&'a self, client: &'a dyn hil::usb_hid::Client<'a, [u8; 64]>) {
178        self.client.set(client);
179    }
180}
181
182impl<'a, U: hil::usb::UsbController<'a>> hil::usb_hid::UsbHid<'a, [u8; 64]> for KeyboardHid<'a, U> {
183    fn send_buffer(
184        &'a self,
185        send: &'static mut [u8; 64],
186    ) -> Result<usize, (ErrorCode, &'static mut [u8; 64])> {
187        let len = send.len();
188
189        self.send_buffer.replace(send);
190        self.controller().endpoint_resume_in(ENDPOINT_NUM);
191
192        Ok(len)
193    }
194
195    fn send_cancel(&'a self) -> Result<&'static mut [u8; 64], ErrorCode> {
196        match self.send_buffer.take() {
197            Some(buf) => Ok(buf),
198            None => Err(ErrorCode::BUSY),
199        }
200    }
201
202    // Keyboard doesn't use receive so this is unimplemented.
203    fn receive_buffer(
204        &'a self,
205        _recv: &'static mut [u8; 64],
206    ) -> Result<(), (ErrorCode, &'static mut [u8; 64])> {
207        Ok(())
208    }
209
210    // Keyboard doesn't use receive so this is unimplemented.
211    fn receive_cancel(&'a self) -> Result<&'static mut [u8; 64], ErrorCode> {
212        Err(ErrorCode::BUSY)
213    }
214}
215
216impl<'a, U: hil::usb::UsbController<'a>> hil::usb::Client<'a> for KeyboardHid<'a, U> {
217    fn enable(&'a self) {
218        // Set up the default control endpoint
219        self.client_ctrl.enable();
220
221        // Setup buffers for IN data transfer.
222        self.controller()
223            .endpoint_set_in_buffer(ENDPOINT_NUM, &self.buffers[IN_BUFFER].buf);
224        self.controller()
225            .endpoint_in_out_enable(TransferType::Interrupt, ENDPOINT_NUM);
226    }
227
228    fn attach(&'a self) {
229        self.client_ctrl.attach();
230    }
231
232    fn bus_reset(&'a self) {}
233
234    /// Handle a Control Setup transaction.
235    fn ctrl_setup(&'a self, endpoint: usize) -> hil::usb::CtrlSetupResult {
236        self.client_ctrl.ctrl_setup(endpoint)
237    }
238
239    /// Handle a Control In transaction
240    fn ctrl_in(&'a self, endpoint: usize) -> hil::usb::CtrlInResult {
241        self.client_ctrl.ctrl_in(endpoint)
242    }
243
244    /// Handle a Control Out transaction
245    fn ctrl_out(&'a self, _endpoint: usize, _packet_bytes: u32) -> hil::usb::CtrlOutResult {
246        // self.client_ctrl.ctrl_out(endpoint, packet_bytes)
247        hil::usb::CtrlOutResult::Ok
248    }
249
250    fn ctrl_status(&'a self, endpoint: usize) {
251        self.client_ctrl.ctrl_status(endpoint)
252    }
253
254    /// Handle the completion of a Control transfer
255    fn ctrl_status_complete(&'a self, endpoint: usize) {
256        self.client_ctrl.ctrl_status_complete(endpoint)
257    }
258
259    /// Handle a Bulk/Interrupt IN transaction.
260    ///
261    /// This is called when we can send data to the host. It should get called
262    /// when we tell the controller we want to resume the IN endpoint (meaning
263    /// we know we have data to send) and afterwards until we return
264    /// `hil::usb::InResult::Delay` from this function. That means we can use
265    /// this as a callback to mean that the transmission finished by waiting
266    /// until this function is called when we don't have anything left to send.
267    fn packet_in(&'a self, transfer_type: TransferType, _endpoint: usize) -> hil::usb::InResult {
268        match transfer_type {
269            TransferType::Interrupt => {
270                self.send_buffer
271                    .take()
272                    .map_or(hil::usb::InResult::Delay, |buf| {
273                        // Get packet that we have shared with the underlying
274                        // USB stack to copy the tx into.
275                        let packet = &self.buffers[IN_BUFFER].buf;
276
277                        // Copy from the TX buffer to the outgoing USB packet.
278                        // Our endpoint supports exactly 8 bytes so we use that
279                        // length.
280                        for i in 0..8 {
281                            packet[i].set(buf[i]);
282                        }
283
284                        // Put the TX buffer back so we can keep sending from
285                        // it.
286                        self.send_buffer.replace(buf);
287
288                        // Return that we have data to send.
289                        hil::usb::InResult::Packet(8)
290                    })
291            }
292            TransferType::Bulk | TransferType::Control | TransferType::Isochronous => {
293                hil::usb::InResult::Error
294            }
295        }
296    }
297
298    /// Handle a Bulk/Interrupt OUT transaction
299    ///
300    /// Unused for keyboard.
301    fn packet_out(
302        &'a self,
303        transfer_type: TransferType,
304        _endpoint: usize,
305        _packet_bytes: u32,
306    ) -> hil::usb::OutResult {
307        match transfer_type {
308            TransferType::Interrupt => hil::usb::OutResult::Ok,
309
310            TransferType::Bulk | TransferType::Control | TransferType::Isochronous => {
311                hil::usb::OutResult::Error
312            }
313        }
314    }
315
316    fn packet_transmitted(&'a self, endpoint: usize) {
317        self.send_buffer.take().map(|buf| {
318            self.client.map(move |client| {
319                client.packet_transmitted(Ok(()), buf, endpoint);
320            });
321        });
322    }
323}