1use std::convert::TryFrom;
2use std::fs::{File, OpenOptions};
3use std::io::{self, prelude::*};
4use std::os::unix::fs::OpenOptionsExt;
5use std::path::Path;
6
7use crate::codec::*;
8
9pub struct UHIDDevice<T: Read + Write> {
10 handle: T,
11}
12
13#[derive(Debug, Clone, PartialEq)]
15pub struct CreateParams {
16 pub name: String,
17 pub phys: String,
18 pub uniq: String,
19 pub bus: Bus,
20 pub vendor: u32,
21 pub product: u32,
22 pub version: u32,
23 pub country: u32,
24 pub rd_data: Vec<u8>,
25}
26
27impl<T: Read + Write> UHIDDevice<T> {
29 pub fn write(&mut self, data: &[u8]) -> io::Result<usize> {
31 let event: [u8; UHID_EVENT_SIZE] = InputEvent::Input { data }.into();
32 self.handle.write(&event)
33 }
34
35 pub fn write_set_report_reply(&mut self, id: u32, err: u16) -> io::Result<usize> {
37 let event: [u8; UHID_EVENT_SIZE] = InputEvent::SetReportReply { id, err }.into();
38 self.handle.write(&event)
39 }
40
41 pub fn write_get_report_reply(
43 &mut self,
44 id: u32,
45 err: u16,
46 data: Vec<u8>,
47 ) -> io::Result<usize> {
48 let event: [u8; UHID_EVENT_SIZE] = InputEvent::GetReportReply { id, err, data }.into();
49 self.handle.write(&event)
50 }
51
52 pub fn read(&mut self) -> Result<OutputEvent, StreamError> {
54 let mut event = [0u8; UHID_EVENT_SIZE];
55 self.handle
56 .read_exact(&mut event)
57 .map_err(StreamError::Io)?;
58 OutputEvent::try_from(event)
59 }
60
61 pub fn destroy(&mut self) -> io::Result<usize> {
63 let event: [u8; UHID_EVENT_SIZE] = InputEvent::Destroy.into();
64 self.handle.write(&event)
65 }
66}
67
68impl UHIDDevice<File> {
69 pub fn create(params: CreateParams) -> io::Result<UHIDDevice<File>> {
71 UHIDDevice::create_with_path(params, Path::new("/dev/uhid"))
72 }
73 pub fn create_with_path(params: CreateParams, path: &Path) -> io::Result<UHIDDevice<File>> {
74 let mut options = OpenOptions::new();
75 options.read(true);
76 options.write(true);
77 if cfg!(unix) {
78 options.custom_flags(libc::O_RDWR | libc::O_CLOEXEC | libc::O_NONBLOCK);
79 }
80 let mut handle = options.open(path)?;
81 let event: [u8; UHID_EVENT_SIZE] = InputEvent::Create(params).into();
82 handle.write_all(&event)?;
83 Ok(UHIDDevice { handle })
84 }
85}