tokio_linux_uhid/
uhid_device.rs1use 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
26pub 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
39impl UHIDDevice<PollEventedRead<CharacterDeviceFile<File>>> {
42 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 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 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 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}