uhid_virt/
codec.rs

1use std::convert::TryFrom;
2use std::mem;
3use std::slice;
4
5use enumflags2::BitFlags;
6
7use enumflags2::bitflags;
8use uhidrs_sys as sys;
9
10use crate::uhid_device::CreateParams;
11
12/// Any IO error will probably be 'permission-denied' if you don't have access to open /dev/uhid
13/// An unknown event type error should only occur if a new event has been added to `uhid-sys` that this wrapper is unaware of.
14pub enum StreamError {
15    Io(std::io::Error),
16    UnknownEventType(u32),
17}
18
19/// Each of these flags defines whether a given report-type uses numbered reports.
20/// If numbered reports are used for a type, all messages from the kernel already have the report-number as prefix. Otherwise, no prefix is added by the kernel.
21/// For messages sent by user-space to the kernel, you must adjust the prefixes according to these flags.
22#[bitflags]
23#[derive(Copy, Clone, PartialEq)]
24#[repr(u64)]
25pub enum DevFlags {
26    FeatureReportsNumbered = 0b0000_0001,
27    OutputReportsNumbered = 0b0000_0010,
28    InputReportsNumbered = 0b0000_0100,
29}
30
31/// See https://www.kernel.org/doc/html/latest/hid/uhid.html#read
32#[derive(Debug, Copy, Clone, PartialEq)]
33pub enum ReportType {
34    Feature = 0,
35    Output = 1,
36    Input = 2,
37}
38
39/// See https://elixir.bootlin.com/linux/latest/ident/BUS_INTEL_ISHTP
40#[derive(Debug, Copy, Clone, PartialEq)]
41#[allow(non_camel_case_types)]
42pub enum Bus {
43    PCI = 1,
44    ISAPNP = 2,
45    USB = 3,
46    HIL = 4,
47    BLUETOOTH = 5,
48    VIRTUAL = 6,
49    ISA = 16,
50    I8042 = 17,
51    XTKBD = 18,
52    RS232 = 19,
53    GAMEPORT = 20,
54    PARPORT = 21,
55    AMIGA = 22,
56    ADB = 23,
57    I2C = 24,
58    HOST = 25,
59    GSC = 26,
60    ATARI = 27,
61    SPI = 28,
62    RMI = 29,
63    CEC = 30,
64    INTEL_ISHTP = 31,
65}
66
67pub const UHID_EVENT_SIZE: usize = mem::size_of::<sys::uhid_event>();
68
69/// See https://www.kernel.org/doc/html/latest/hid/uhid.html#write
70pub enum InputEvent<'a> {
71    Create(CreateParams),
72    Destroy,
73    Input {
74        data: &'a [u8],
75    },
76    Output {
77        data: Vec<u8>,
78    },
79    OutputEv {
80        type_: u16,
81        code: u16,
82        value: i32,
83    },
84    GetReportReply {
85        id: u32,
86        err: u16,
87        data: Vec<u8>,
88    },
89    SetReportReply {
90        id: u32,
91        err: u16,
92    },
93    Feature {
94        id: u32,
95        report_num: u8,
96    },
97    FeatureAnswer {
98        id: u32,
99        err: u16,
100        data: Vec<u8>,
101    },
102    SetReport {
103        id: u32,
104        report_num: u8,
105        data: Vec<u8>,
106    },
107}
108
109impl<'a> From<InputEvent<'a>> for sys::uhid_event {
110    fn from(input: InputEvent<'a>) -> Self {
111        let mut event: sys::uhid_event = unsafe { mem::zeroed() };
112
113        match input {
114            InputEvent::Create(CreateParams {
115                name,
116                phys,
117                uniq,
118                bus,
119                vendor,
120                product,
121                version,
122                country,
123                rd_data,
124            }) => {
125                event.type_ = sys::uhid_event_type_UHID_CREATE2;
126                let payload = unsafe { &mut event.u.create2 };
127                name.as_bytes()
128                    .iter()
129                    .enumerate()
130                    .for_each(|(i, x)| payload.name[i] = *x);
131                phys.as_bytes()
132                    .iter()
133                    .enumerate()
134                    .for_each(|(i, x)| payload.phys[i] = *x);
135                uniq.as_bytes()
136                    .iter()
137                    .enumerate()
138                    .for_each(|(i, x)| payload.uniq[i] = *x);
139                rd_data
140                    .iter()
141                    .enumerate()
142                    .for_each(|(i, x)| payload.rd_data[i] = *x);
143                payload.rd_size = rd_data.len() as u16;
144                payload.bus = bus as u16;
145                payload.vendor = vendor;
146                payload.product = product;
147                payload.version = version;
148                payload.country = country;
149            }
150            InputEvent::Destroy => {
151                event.type_ = sys::uhid_event_type_UHID_DESTROY;
152            }
153            InputEvent::Input { data } => {
154                event.type_ = sys::uhid_event_type_UHID_INPUT2;
155                let payload = unsafe { &mut event.u.input2 };
156                data.iter()
157                    .enumerate()
158                    .for_each(|(i, x)| payload.data[i] = *x);
159                payload.size = data.len() as u16;
160            }
161            InputEvent::Output { data } => {
162                event.type_ = sys::uhid_event_type_UHID_OUTPUT;
163                let payload = unsafe { &mut event.u.output };
164                data.iter()
165                    .enumerate()
166                    .for_each(|(i, x)| payload.data[i] = *x);
167                payload.size = data.len() as u16;
168                payload.rtype = sys::hid_report_type_HID_OUTPUT_REPORT as u8;
169            }
170            InputEvent::OutputEv { type_, code, value } => {
171                event.type_ = sys::uhid_event_type___UHID_LEGACY_OUTPUT_EV;
172                let payload = unsafe { &mut event.u.output_ev };
173                payload.type_ = type_;
174                payload.code = code;
175                payload.value = value;
176            }
177            InputEvent::GetReportReply { err, id, data, .. } => {
178                event.type_ = sys::uhid_event_type_UHID_GET_REPORT_REPLY;
179                let payload = unsafe { &mut event.u.get_report_reply };
180                payload.err = err;
181                data.iter()
182                    .enumerate()
183                    .for_each(|(i, x)| payload.data[i] = *x);
184                payload.size = data.len() as u16;
185                payload.id = id;
186            }
187            InputEvent::SetReportReply { err, id, .. } => {
188                event.type_ = sys::uhid_event_type_UHID_SET_REPORT_REPLY;
189                let payload = unsafe { &mut event.u.set_report_reply };
190                payload.err = err;
191                payload.id = id;
192            }
193            InputEvent::Feature { id, report_num } => {
194                event.type_ = sys::uhid_legacy_event_type_UHID_FEATURE;
195                let payload = unsafe { &mut event.u.feature };
196                payload.id = id;
197                payload.rnum = report_num;
198                payload.rtype = sys::hid_report_type_HID_INPUT_REPORT as u8;
199            }
200            InputEvent::FeatureAnswer { err, id, data, .. } => {
201                event.type_ = sys::uhid_event_type_UHID_GET_REPORT_REPLY;
202                let payload = unsafe { &mut event.u.get_report_reply };
203                payload.err = err;
204                data.iter()
205                    .enumerate()
206                    .for_each(|(i, x)| payload.data[i] = *x);
207                payload.size = data.len() as u16;
208                payload.id = id;
209            }
210            InputEvent::SetReport {
211                id,
212                report_num,
213                data,
214            } => {
215                event.type_ = sys::uhid_event_type_UHID_SET_REPORT;
216                let payload = unsafe { &mut event.u.set_report };
217                data.iter()
218                    .enumerate()
219                    .for_each(|(i, x)| payload.data[i] = *x);
220                payload.size = data.len() as u16;
221                payload.id = id;
222                payload.rnum = report_num;
223                payload.rtype = sys::hid_report_type_HID_INPUT_REPORT as u8;
224            }
225        };
226
227        event
228    }
229}
230
231/// See https://www.kernel.org/doc/html/latest/hid/uhid.html#read
232pub enum OutputEvent {
233    Start {
234        dev_flags: Vec<DevFlags>,
235    },
236    Stop,
237    Open,
238    Close,
239    Output {
240        data: Vec<u8>,
241    },
242    GetReport {
243        id: u32,
244        report_number: u8,
245        report_type: ReportType,
246    },
247    SetReport {
248        id: u32,
249        report_number: u8,
250        report_type: ReportType,
251        data: Vec<u8>,
252    },
253}
254
255fn to_uhid_event_type(value: u32) -> Option<sys::uhid_event_type> {
256    let last_valid_value = sys::uhid_event_type_UHID_SET_REPORT_REPLY;
257    if value <= last_valid_value {
258        Some(value)
259    } else {
260        None
261    }
262}
263
264impl TryFrom<sys::uhid_event> for OutputEvent {
265    type Error = StreamError;
266    fn try_from(event: sys::uhid_event) -> Result<Self, Self::Error> {
267        if let Some(event_type) = to_uhid_event_type(event.type_) {
268            match event_type {
269                sys::uhid_event_type_UHID_START => Ok(unsafe {
270                    OutputEvent::Start {
271                        dev_flags: BitFlags::from_bits_truncate(event.u.start.dev_flags)
272                            .iter()
273                            .collect(),
274                    }
275                }),
276                sys::uhid_event_type_UHID_STOP => Ok(OutputEvent::Stop),
277                sys::uhid_event_type_UHID_OPEN => Ok(OutputEvent::Open),
278                sys::uhid_event_type_UHID_CLOSE => Ok(OutputEvent::Close),
279                sys::uhid_event_type_UHID_OUTPUT => Ok(unsafe {
280                    let payload = &event.u.output;
281                    assert_eq!(
282                        payload.rtype,
283                        sys::uhid_report_type_UHID_OUTPUT_REPORT as u8
284                    );
285                    OutputEvent::Output {
286                        data: slice::from_raw_parts(
287                            &payload.data[0] as *const u8,
288                            payload.size as usize,
289                        )
290                        .to_vec(),
291                    }
292                }),
293                sys::uhid_event_type_UHID_GET_REPORT => Ok(unsafe {
294                    let payload = &event.u.get_report;
295                    OutputEvent::GetReport {
296                        id: payload.id,
297                        report_number: payload.rnum,
298                        report_type: mem::transmute(payload.rtype),
299                    }
300                }),
301                sys::uhid_event_type_UHID_SET_REPORT => Ok(unsafe {
302                    let payload = &event.u.set_report;
303                    OutputEvent::SetReport {
304                        id: payload.id,
305                        report_number: payload.rnum,
306                        report_type: mem::transmute(payload.rtype),
307                        data: slice::from_raw_parts(
308                            &payload.data[0] as *const u8,
309                            payload.size as usize,
310                        )
311                        .to_vec(),
312                    }
313                }),
314                _ => Err(StreamError::UnknownEventType(event.type_)),
315            }
316        } else {
317            Err(StreamError::UnknownEventType(event.type_))
318        }
319    }
320}
321
322impl TryFrom<[u8; UHID_EVENT_SIZE]> for OutputEvent {
323    type Error = StreamError;
324    fn try_from(src: [u8; UHID_EVENT_SIZE]) -> Result<Self, Self::Error> {
325        OutputEvent::try_from(unsafe { *(src.as_ptr() as *const sys::uhid_event) })
326    }
327}
328
329impl<'a> From<InputEvent<'a>> for [u8; UHID_EVENT_SIZE] {
330    fn from(input: InputEvent<'a>) -> Self {
331        let event: sys::uhid_event = input.into();
332        unsafe { mem::transmute_copy(&event) }
333    }
334}
335
336#[cfg(test)]
337mod tests {
338    use super::*;
339
340    const RDESC: [u8; 85] = [
341        0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
342        0x09, 0x02, /* USAGE (Mouse) */
343        0xa1, 0x01, /* COLLECTION (Application) */
344        0x09, 0x01, /* USAGE (Pointer) */
345        0xa1, 0x00, /* COLLECTION (Physical) */
346        0x85, 0x01, /* REPORT_ID (1) */
347        0x05, 0x09, /* USAGE_PAGE (Button) */
348        0x19, 0x01, /* USAGE_MINIMUM (Button 1) */
349        0x29, 0x03, /* USAGE_MAXIMUM (Button 3) */
350        0x15, 0x00, /* LOGICAL_MINIMUM (0) */
351        0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
352        0x95, 0x03, /* REPORT_COUNT (3) */
353        0x75, 0x01, /* REPORT_SIZE (1) */
354        0x81, 0x02, /* INPUT (Data,Var,Abs) */
355        0x95, 0x01, /* REPORT_COUNT (1) */
356        0x75, 0x05, /* REPORT_SIZE (5) */
357        0x81, 0x01, /* INPUT (Cnst,Var,Abs) */
358        0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
359        0x09, 0x30, /* USAGE (X) */
360        0x09, 0x31, /* USAGE (Y) */
361        0x09, 0x38, /* USAGE (WHEEL) */
362        0x15, 0x81, /* LOGICAL_MINIMUM (-127) */
363        0x25, 0x7f, /* LOGICAL_MAXIMUM (127) */
364        0x75, 0x08, /* REPORT_SIZE (8) */
365        0x95, 0x03, /* REPORT_COUNT (3) */
366        0x81, 0x06, /* INPUT (Data,Var,Rel) */
367        0xc0, /* END_COLLECTION */
368        0xc0, /* END_COLLECTION */
369        0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
370        0x09, 0x06, /* USAGE (Keyboard) */
371        0xa1, 0x01, /* COLLECTION (Application) */
372        0x85, 0x02, /* REPORT_ID (2) */
373        0x05, 0x08, /* USAGE_PAGE (Led) */
374        0x19, 0x01, /* USAGE_MINIMUM (1) */
375        0x29, 0x03, /* USAGE_MAXIMUM (3) */
376        0x15, 0x00, /* LOGICAL_MINIMUM (0) */
377        0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
378        0x95, 0x03, /* REPORT_COUNT (3) */
379        0x75, 0x01, /* REPORT_SIZE (1) */
380        0x91, 0x02, /* Output (Data,Var,Abs) */
381        0x95, 0x01, /* REPORT_COUNT (1) */
382        0x75, 0x05, /* REPORT_SIZE (5) */
383        0x91, 0x01, /* Output (Cnst,Var,Abs) */
384        0xc0, /* END_COLLECTION */
385    ];
386
387    fn assert_bytes_eq(actual: &[u8], expected: &[u8]) {
388        assert_eq!(actual.len(), expected.len(), "Size of slices differs");
389        for index in 0..actual.len() {
390            assert_eq!(
391                actual[index], expected[index],
392                "Bytes differ at index {}",
393                index
394            );
395        }
396    }
397
398    #[test]
399    fn encode_create_request() {
400        let mut expected = [0; UHID_EVENT_SIZE];
401        expected[0] = 0x0b;
402        expected[4] = 0x74;
403        expected[5] = 0x65;
404        expected[6] = 0x73;
405        expected[7] = 0x74;
406        expected[8] = 0x2d;
407        expected[9] = 0x75;
408        expected[10] = 0x68;
409        expected[11] = 0x69;
410        expected[12] = 0x64;
411        expected[13] = 0x2d;
412        expected[14] = 0x64;
413        expected[15] = 0x65;
414        expected[16] = 0x76;
415        expected[17] = 0x69;
416        expected[18] = 0x63;
417        expected[19] = 0x65;
418        expected[260] = 0x55;
419        expected[262] = 0x03;
420        expected[264] = 0xd9;
421        expected[265] = 0x15;
422        expected[268] = 0x37;
423        expected[269] = 0x0a;
424        expected[280] = 0x05;
425        expected[281] = 0x01;
426        expected[282] = 0x09;
427        expected[283] = 0x02;
428        expected[284] = 0xa1;
429        expected[285] = 0x01;
430        expected[286] = 0x09;
431        expected[287] = 0x01;
432        expected[288] = 0xa1;
433        expected[290] = 0x85;
434        expected[291] = 0x01;
435        expected[292] = 0x05;
436        expected[293] = 0x09;
437        expected[294] = 0x19;
438        expected[295] = 0x01;
439        expected[296] = 0x29;
440        expected[297] = 0x03;
441        expected[298] = 0x15;
442        expected[300] = 0x25;
443        expected[301] = 0x01;
444        expected[302] = 0x95;
445        expected[303] = 0x03;
446        expected[304] = 0x75;
447        expected[305] = 0x01;
448        expected[306] = 0x81;
449        expected[307] = 0x02;
450        expected[308] = 0x95;
451        expected[309] = 0x01;
452        expected[310] = 0x75;
453        expected[311] = 0x05;
454        expected[312] = 0x81;
455        expected[313] = 0x01;
456        expected[314] = 0x05;
457        expected[315] = 0x01;
458        expected[316] = 0x09;
459        expected[317] = 0x30;
460        expected[318] = 0x09;
461        expected[319] = 0x31;
462        expected[320] = 0x09;
463        expected[321] = 0x38;
464        expected[322] = 0x15;
465        expected[323] = 0x81;
466        expected[324] = 0x25;
467        expected[325] = 0x7f;
468        expected[326] = 0x75;
469        expected[327] = 0x08;
470        expected[328] = 0x95;
471        expected[329] = 0x03;
472        expected[330] = 0x81;
473        expected[331] = 0x06;
474        expected[332] = 0xc0;
475        expected[333] = 0xc0;
476        expected[334] = 0x05;
477        expected[335] = 0x01;
478        expected[336] = 0x09;
479        expected[337] = 0x06;
480        expected[338] = 0xa1;
481        expected[339] = 0x01;
482        expected[340] = 0x85;
483        expected[341] = 0x02;
484        expected[342] = 0x05;
485        expected[343] = 0x08;
486        expected[344] = 0x19;
487        expected[345] = 0x01;
488        expected[346] = 0x29;
489        expected[347] = 0x03;
490        expected[348] = 0x15;
491        expected[350] = 0x25;
492        expected[351] = 0x01;
493        expected[352] = 0x95;
494        expected[353] = 0x03;
495        expected[354] = 0x75;
496        expected[355] = 0x01;
497        expected[356] = 0x91;
498        expected[357] = 0x02;
499        expected[358] = 0x95;
500        expected[359] = 0x01;
501        expected[360] = 0x75;
502        expected[361] = 0x05;
503        expected[362] = 0x91;
504        expected[363] = 0x01;
505        expected[364] = 0xc0;
506
507        let result: [u8; UHID_EVENT_SIZE] = InputEvent::Create(CreateParams {
508            name: String::from("test-uhid-device"),
509            phys: String::from(""),
510            uniq: String::from(""),
511            bus: Bus::USB,
512            vendor: 0x15d9,
513            product: 0x0a37,
514            version: 0,
515            country: 0,
516            rd_data: RDESC.to_vec(),
517        })
518        .into();
519
520        assert_bytes_eq(&result[..], &expected);
521    }
522
523    #[test]
524    fn encode_destroy_request() {
525        let mut expected = vec![0; mem::size_of::<sys::uhid_event>()];
526        expected[0] = 0x01;
527
528        let result: [u8; UHID_EVENT_SIZE] = InputEvent::Destroy.into();
529        assert_bytes_eq(&result[..], &expected);
530    }
531}