tokio_linux_uhid/
uhid_device.rs

1use std::fs::File;
2use std::io::{self, Write};
3use std::os::unix::io::FromRawFd;
4use std::path::Path;
5
6use futures::{Async, AsyncSink, Poll, Sink, StartSend, Stream};
7use nix;
8use nix::fcntl;
9use nix::libc;
10use slog_stdlog;
11use slog;
12use slog::Drain;
13use tokio_core::reactor::Handle;
14use tokio_io::AsyncRead;
15
16use poll_evented_read_wrapper::PollEventedRead;
17use character_device_file::CharacterDeviceFile;
18use character_device::{CharacterDevice, Decoder, Encoder, SyncSink};
19use uhid_codec::*;
20
21pub struct UHIDDevice<T> {
22    inner: CharacterDevice<T, UHIDCodec, UHIDCodec>,
23    logger: slog::Logger,
24}
25
26/// The paramters used to create the UHID device
27pub struct CreateParams {
28    pub name: String,
29    pub phys: String,
30    pub uniq: String,
31    pub bus: Bus,
32    pub vendor: u32,
33    pub product: u32,
34    pub version: u32,
35    pub country: u32,
36    pub data: Vec<u8>,
37}
38
39// ===== impl UHIDDevice =====
40
41impl UHIDDevice<PollEventedRead<CharacterDeviceFile<File>>> {
42    /// Create a UHID device using '/dev/uhid'
43    pub fn create<L: Into<Option<slog::Logger>>>(
44        handle: &Handle,
45        params: CreateParams,
46        logger: L,
47    ) -> io::Result<UHIDDevice<PollEventedRead<CharacterDeviceFile<File>>>> {
48        Self::create_with_path(Path::new("/dev/uhid"), handle, params, logger)
49    }
50
51    /// Create a UHID device, using the specified UHID device file path
52    pub fn create_with_path<L: Into<Option<slog::Logger>>>(
53        path: &Path,
54        handle: &Handle,
55        params: CreateParams,
56        logger: L,
57    ) -> io::Result<UHIDDevice<PollEventedRead<CharacterDeviceFile<File>>>> {
58        let fd = fcntl::open(
59            path,
60            fcntl::OFlag::from_bits(libc::O_RDWR | libc::O_CLOEXEC | libc::O_NONBLOCK).unwrap(),
61            nix::sys::stat::Mode::from_bits(libc::S_IRUSR | libc::S_IWUSR | libc::S_IRGRP | libc::S_IWGRP).unwrap(),
62        ).map_err(|err| {
63            io::Error::new(
64                io::ErrorKind::Other,
65                format!("Cannot open uhid-cdev {}: {}", path.to_str().unwrap(), err),
66            )
67        })?;
68        let file: File = unsafe { File::from_raw_fd(fd) };
69        let device_file = CharacterDeviceFile::new(file);
70        Ok(Self::create_with(
71            device_file.into_io(handle)?,
72            params,
73            logger,
74        ))
75    }
76}
77
78impl<T> UHIDDevice<T>
79where
80    T: AsyncRead + Write,
81{
82    fn create_with<L: Into<Option<slog::Logger>>>(
83        inner: T,
84        params: CreateParams,
85        logger: L,
86    ) -> UHIDDevice<T> {
87        let logger = logger
88            .into()
89            .unwrap_or(slog::Logger::root(slog_stdlog::StdLog.fuse(), o!()));
90        let mut device = UHIDDevice {
91            inner: CharacterDevice::new(inner, UHIDCodec, UHIDCodec, logger.clone()),
92            logger: logger,
93        };
94        debug!(device.logger, "Send create device event");
95        device
96            .inner
97            .send(InputEvent::Create {
98                name: params.name,
99                phys: params.phys,
100                uniq: params.uniq,
101                bus: params.bus,
102                vendor: params.vendor,
103                product: params.product,
104                version: params.version,
105                country: params.country,
106                data: params.data,
107            })
108            .unwrap();
109        debug!(device.logger, "Sent create device event");
110        device
111    }
112
113    /// Send a HID packet to the UHID device
114    pub fn send_input(&mut self, data: &[u8]) -> Result<(), <UHIDCodec as Encoder>::Error> {
115        debug!(self.logger, "Send input event");
116        self.inner.send(InputEvent::Input {
117            data: data.to_vec(),
118        })
119    }
120
121    /// Send a 'destroy' to the UHID device and close it
122    pub fn destroy(mut self) -> Result<(), <UHIDCodec as Encoder>::Error> {
123        self.inner.send(InputEvent::Destroy)?;
124        self.inner.close()?;
125        Ok(())
126    }
127}
128
129impl<T: AsyncRead> Stream for UHIDDevice<T> {
130    type Item = <UHIDCodec as Decoder>::Item;
131    type Error = <UHIDCodec as Decoder>::Error;
132
133    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
134        self.inner.poll()
135    }
136}
137
138impl<T: Write> Sink for UHIDDevice<T> {
139    type SinkItem = <UHIDCodec as Encoder>::Item;
140    type SinkError = <UHIDCodec as Encoder>::Error;
141
142    fn start_send(&mut self, item: Self::SinkItem) -> StartSend<Self::SinkItem, Self::SinkError> {
143        debug!(self.logger, "start_send");
144        self.inner.send(item)?;
145        Ok(AsyncSink::Ready)
146    }
147
148    fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
149        debug!(self.logger, "poll_complete");
150        self.inner.flush()?;
151        Ok(Async::Ready(()))
152    }
153}