Add and enable virtio multi-touch touchscreen device

BUG=b:124121375
TEST=compile and run

Change-Id: I795ec238cb4ba7551a98fdfd4258fcae38e8a7a8
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2439297
Tested-by: Tristan Muntsinger <muntsinger@google.com>
Commit-Queue: Tristan Muntsinger <muntsinger@google.com>
Reviewed-by: Zach Reizner <zachr@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
Auto-Submit: Tristan Muntsinger <muntsinger@google.com>
This commit is contained in:
Tristan Muntsinger 2020-09-29 22:05:41 +00:00 committed by Commit Bot
parent 18d5733e15
commit 486cffc41d
6 changed files with 146 additions and 6 deletions

View file

@ -62,6 +62,19 @@ pub fn new_single_touch_config(width: u32, height: u32) -> VirtioInputConfig {
)
}
/// Instantiates a VirtioInputConfig object with the default configuration for a multitouch
/// touchscreen.
pub fn new_multi_touch_config(width: u32, height: u32) -> VirtioInputConfig {
VirtioInputConfig::new(
virtio_input_device_ids::new(0, 0, 0, 0),
b"Crosvm Virtio Multitouch Touchscreen".to_vec(),
b"virtio-touchscreen".to_vec(),
virtio_input_bitmap::from_bits(&[INPUT_PROP_DIRECT]),
default_multitouchscreen_events(),
default_multitouchscreen_absinfo(width, height, 0, 0),
)
}
fn default_touchscreen_absinfo(width: u32, height: u32) -> BTreeMap<u16, virtio_input_absinfo> {
let mut absinfo: BTreeMap<u16, virtio_input_absinfo> = BTreeMap::new();
absinfo.insert(ABS_X, virtio_input_absinfo::new(0, width, 0, 0));
@ -76,6 +89,38 @@ fn default_touchscreen_events() -> BTreeMap<u16, virtio_input_bitmap> {
supported_events
}
fn default_multitouchscreen_absinfo(
width: u32,
height: u32,
slot: u32,
id: u32,
) -> BTreeMap<u16, virtio_input_absinfo> {
let mut absinfo: BTreeMap<u16, virtio_input_absinfo> = BTreeMap::new();
absinfo.insert(ABS_MT_SLOT, virtio_input_absinfo::new(0, slot, 0, 0));
absinfo.insert(ABS_MT_TRACKING_ID, virtio_input_absinfo::new(0, id, 0, 0));
absinfo.insert(ABS_MT_POSITION_X, virtio_input_absinfo::new(0, width, 0, 0));
absinfo.insert(
ABS_MT_POSITION_Y,
virtio_input_absinfo::new(0, height, 0, 0),
);
absinfo
}
fn default_multitouchscreen_events() -> BTreeMap<u16, virtio_input_bitmap> {
let mut supported_events: BTreeMap<u16, virtio_input_bitmap> = BTreeMap::new();
supported_events.insert(EV_KEY, virtio_input_bitmap::from_bits(&[BTN_TOUCH]));
supported_events.insert(
EV_ABS,
virtio_input_bitmap::from_bits(&[
ABS_MT_SLOT,
ABS_MT_TRACKING_ID,
ABS_MT_POSITION_X,
ABS_MT_POSITION_Y,
]),
);
supported_events
}
fn default_trackpad_absinfo(width: u32, height: u32) -> BTreeMap<u16, virtio_input_absinfo> {
let mut absinfo: BTreeMap<u16, virtio_input_absinfo> = BTreeMap::new();
absinfo.insert(ABS_X, virtio_input_absinfo::new(0, width, 0, 0));

View file

@ -693,6 +693,25 @@ where
})
}
/// Creates a new virtio touch device which supports multi touch.
pub fn new_multi_touch<T>(
source: T,
width: u32,
height: u32,
virtio_features: u64,
) -> Result<Input<SocketEventSource<T>>>
where
T: Read + Write + AsRawDescriptor,
{
Ok(Input {
kill_evt: None,
worker_thread: None,
config: defaults::new_multi_touch_config(width, height),
source: Some(SocketEventSource::new(source)),
virtio_features,
})
}
/// Creates a new virtio trackpad device which supports (single) touch, primary and secondary
/// buttons as well as X and Y axis.
pub fn new_trackpad<T>(

View file

@ -15,6 +15,10 @@ const SYN_REPORT: u16 = 0;
const REL_X: u16 = 0x00;
#[allow(dead_code)]
const REL_Y: u16 = 0x01;
const ABS_MT_TRACKING_ID: u16 = 0x39;
const ABS_MT_SLOT: u16 = 0x2f;
const ABS_MT_POSITION_X: u16 = 0x35;
const ABS_MT_POSITION_Y: u16 = 0x36;
const ABS_X: u16 = 0x00;
const ABS_Y: u16 = 0x01;
const BTN_TOUCH: u16 = 0x14a;
@ -106,6 +110,26 @@ impl virtio_input_event {
}
}
#[inline]
pub fn multitouch_tracking_id(id: u32) -> virtio_input_event {
Self::absolute(ABS_MT_TRACKING_ID, id)
}
#[inline]
pub fn multitouch_slot(slot: u32) -> virtio_input_event {
Self::absolute(ABS_MT_SLOT, slot)
}
#[inline]
pub fn multitouch_absolute_x(x: u32) -> virtio_input_event {
Self::absolute(ABS_MT_POSITION_X, x)
}
#[inline]
pub fn multitouch_absolute_y(y: u32) -> virtio_input_event {
Self::absolute(ABS_MT_POSITION_Y, y)
}
#[inline]
pub fn absolute_x(x: u32) -> virtio_input_event {
Self::absolute(ABS_X, x)

View file

@ -213,6 +213,7 @@ pub struct Config {
pub serial_parameters: BTreeMap<(SerialHardware, u8), SerialParameters>,
pub syslog_tag: Option<String>,
pub virtio_single_touch: Option<TouchDeviceOption>,
pub virtio_multi_touch: Option<TouchDeviceOption>,
pub virtio_trackpad: Option<TouchDeviceOption>,
pub virtio_mouse: Option<PathBuf>,
pub virtio_keyboard: Option<PathBuf>,
@ -272,6 +273,7 @@ impl Default for Config {
serial_parameters: BTreeMap::new(),
syslog_tag: None,
virtio_single_touch: None,
virtio_multi_touch: None,
virtio_trackpad: None,
virtio_mouse: None,
virtio_keyboard: None,

View file

@ -598,6 +598,30 @@ fn create_single_touch_device(cfg: &Config, single_touch_spec: &TouchDeviceOptio
})
}
fn create_multi_touch_device(cfg: &Config, multi_touch_spec: &TouchDeviceOption) -> DeviceResult {
let socket = multi_touch_spec
.get_path()
.into_unix_stream()
.map_err(|e| {
error!("failed configuring virtio multi touch: {:?}", e);
e
})?;
let (width, height) = multi_touch_spec.get_size();
let dev = virtio::new_multi_touch(
socket,
width,
height,
virtio::base_features(cfg.protected_vm),
)
.map_err(Error::InputDeviceNew)?;
Ok(VirtioDeviceStub {
dev: Box::new(dev),
jail: simple_jail(&cfg, "input_device")?,
})
}
fn create_trackpad_device(cfg: &Config, trackpad_spec: &TouchDeviceOption) -> DeviceResult {
let socket = trackpad_spec.get_path().into_unix_stream().map_err(|e| {
error!("failed configuring virtio trackpad: {}", e);
@ -1298,6 +1322,10 @@ fn create_virtio_devices(
devs.push(create_single_touch_device(cfg, single_touch_spec)?);
}
if let Some(multi_touch_spec) = &cfg.virtio_multi_touch {
devs.push(create_multi_touch_device(cfg, multi_touch_spec)?);
}
if let Some(trackpad_spec) = &cfg.virtio_trackpad {
devs.push(create_trackpad_device(cfg, trackpad_spec)?);
}
@ -1382,15 +1410,15 @@ fn create_virtio_devices(
if cfg.display_window_mouse {
let (event_device_socket, virtio_dev_socket) =
UnixStream::pair().map_err(Error::CreateSocket)?;
let (single_touch_width, single_touch_height) = cfg
.virtio_single_touch
let (multi_touch_width, multi_touch_height) = cfg
.virtio_multi_touch
.as_ref()
.map(|single_touch_spec| single_touch_spec.get_size())
.map(|multi_touch_spec| multi_touch_spec.get_size())
.unwrap_or((gpu_parameters.display_width, gpu_parameters.display_height));
let dev = virtio::new_single_touch(
let dev = virtio::new_multi_touch(
virtio_dev_socket,
single_touch_width,
single_touch_height,
multi_touch_width,
multi_touch_height,
virtio::base_features(cfg.protected_vm),
)
.map_err(Error::InputDeviceNew)?;

View file

@ -1357,6 +1357,24 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument::
}
cfg.virtio_single_touch = Some(single_touch_spec);
}
"multi-touch" => {
if cfg.virtio_multi_touch.is_some() {
return Err(argument::Error::TooManyArguments(
"`multi-touch` already given".to_owned(),
));
}
let mut it = value.unwrap().split(':');
let mut multi_touch_spec =
TouchDeviceOption::new(PathBuf::from(it.next().unwrap().to_owned()));
if let Some(width) = it.next() {
multi_touch_spec.set_width(width.trim().parse().unwrap());
}
if let Some(height) = it.next() {
multi_touch_spec.set_height(height.trim().parse().unwrap());
}
cfg.virtio_multi_touch = Some(multi_touch_spec);
}
"trackpad" => {
if cfg.virtio_trackpad.is_some() {
return Err(argument::Error::TooManyArguments(
@ -1523,6 +1541,9 @@ fn validate_arguments(cfg: &mut Config) -> std::result::Result<(), argument::Err
{
if let Some(gpu_parameters) = cfg.gpu_parameters.as_ref() {
let (width, height) = (gpu_parameters.display_width, gpu_parameters.display_height);
if let Some(virtio_multi_touch) = cfg.virtio_multi_touch.as_mut() {
virtio_multi_touch.set_default_size(width, height);
}
if let Some(virtio_single_touch) = cfg.virtio_single_touch.as_mut() {
virtio_single_touch.set_default_size(width, height);
}
@ -1665,6 +1686,7 @@ writeback=BOOL - Indicates whether the VM can use writeback caching (default: fa
Argument::flag("software-tpm", "enable a software emulated trusted platform module device"),
Argument::value("evdev", "PATH", "Path to an event device node. The device will be grabbed (unusable from the host) and made available to the guest with the same configuration it shows on the host"),
Argument::value("single-touch", "PATH:WIDTH:HEIGHT", "Path to a socket from where to read single touch input events (such as those from a touchscreen) and write status updates to, optionally followed by width and height (defaults to 800x1280)."),
Argument::value("multi-touch", "PATH:WIDTH:HEIGHT", "Path to a socket from where to read multi touch input events (such as those from a touchscreen) and write status updates to, optionally followed by width and height (defaults to 800x1280)."),
Argument::value("trackpad", "PATH:WIDTH:HEIGHT", "Path to a socket from where to read trackpad input events and write status updates to, optionally followed by screen width and height (defaults to 800x1280)."),
Argument::value("mouse", "PATH", "Path to a socket from where to read mouse input events and write status updates to."),
Argument::value("keyboard", "PATH", "Path to a socket from where to read keyboard input events and write status updates to."),