#
# This run script tests the VirtualBox USB device pass-through feature
# by running the 'usb_hid' test in a VM.
#
# See 'usb_hid.run' for more information about the setup of the 'Pro Micro' USB
# device for automated testing.
#
# Note: the USB device(s) to be passed through must be included in the whitelist.
#

if { [have_include "power_on/qemu"] || ![have_spec nova] || ![have_spec x86_64]} {
	puts "Run script is only supported on 64-bit NOVA on real hardware"
	exit 0
}

set build_components {
	core init
	drivers/framebuffer
	drivers/input
	drivers/timer
	drivers/usb
	server/log_terminal
	server/fs_rom
	server/ram_fs
	server/report_rom
	app/usb_report_filter
	virtualbox5
}

source ${genode_dir}/repos/base/run/platform_drv.inc

# override defaults of platform_drv.inc
proc platform_drv_priority {} { return { priority="-1"} }

append_platform_drv_build_components

build $build_components

create_boot_directory

set config {
<config prio_levels="4">
	<parent-provides>
		<service name="ROM"/>
		<service name="IRQ"/>
		<service name="IO_MEM"/>
		<service name="IO_PORT"/>
		<service name="PD"/>
		<service name="RM"/>
		<service name="CPU"/>
		<service name="LOG"/>
	</parent-provides>
	<default-route>
		<any-service> <parent/> <any-child/> </any-service>
	</default-route>
	<default caps="150"/>}

append_platform_drv_config

append config {

	<start name="timer">
		<resource name="RAM" quantum="1M"/>
		<provides><service name="Timer"/></provides>
	</start>

	<start name="ps2_drv" priority="-1">
		<resource name="RAM" quantum="1M"/>
		<provides><service name="Input"/></provides>
	</start>

	<start name="usb_config_fs" priority="-1">
		<binary name="ram_fs"/>
		<resource name="RAM" quantum="1M"/>
		<provides><service name="File_system"/></provides>
		<config verbose="yes">
			<content>
				<inline name="usb_drv.config">
<config uhci="yes" ehci="yes" xhci="yes">
	<raw>
		<report devices="yes"/>
	</raw>
</config>
				</inline>
				<inline name="usb_report_filter.config">
<config>
	<!-- USB device whitelist -->
	<client label="virtualbox"/>
	<device vendor_id="0x03eb" product_id="0x204d"/> <!-- 'Pro Micro' test device -->
</config>
				</inline>
			</content>
			<policy label_prefix="usb_report_filter" root="/" writeable="yes" />
			<policy label_prefix="usb_config_rom" root="/"/>
		</config>
	</start>

	<start name="usb_config_rom" priority="-1">
		<binary name="fs_rom"/>
		<resource name="RAM" quantum="1200K"/>
		<provides><service name="ROM"/></provides>
		<route>
			<service name="File_system"><child name="usb_config_fs"/></service>
			<any-service><parent/><any-child/></any-service>
		</route>
	</start>

	<start name="usb_report_filter" priority="-1">
		<resource name="RAM" quantum="1200K"/>
		<configfile name="usb_report_filter.config"/>
		<route>
			<service name="Report"><child name="report_rom" /></service>
			<service name="ROM" label="usb_report_filter.config">
				<child name="usb_config_rom"/>
			</service>
			<service name="ROM" label="devices">
				<child name="report_rom"/>
			</service>
			<service name="ROM" label="usb_drv_config">
				<child name="report_rom"/>
			</service>
			<service name="File_system" label="usb_drv.config">
				<child name="usb_config_fs"/>
			</service>
			<any-service><parent/><any-child /></any-service>
		</route>
	</start>

	<start name="usb_drv" priority="-1">
		<resource name="RAM" quantum="16M"/>
		<provides><service name="Usb"/></provides>
		<configfile name="usb_drv.config"/>
		<route>
			<service name="IRQ"><child name="acpi_drv" /></service>
			<service name="Report"> <child name="report_rom" /> </service>
			<service name="ROM" label="usb_drv.config"><child name="usb_config_rom"/></service>
			<any-service> <parent/> <any-child/> </any-service>
		</route>
	</start>

	<start name="fb_drv" priority="-1">
		<resource name="RAM" quantum="4M"/>
		<provides><service name="Framebuffer"/></provides>
	</start>

	<start name="log_terminal" priority="-1">
		<resource name="RAM" quantum="2M"/>
		<provides>
			<service name="Terminal"/>
		</provides>
	</start>

	<start name="report_rom" priority="-1">
		<resource name="RAM" quantum="1M"/>
		<provides> <service name="Report"/> <service name="ROM"/> </provides>
		<config>
			<policy label="usb_report_filter -> devices"        report="usb_drv -> devices"/>
			<policy label="usb_report_filter -> usb_drv_config" report="usb_drv -> config"/>
			<policy label="virtualbox -> usb_devices"           report="usb_report_filter -> usb_devices"/>
		</config>
	</start>

	<start name="virtualbox" caps="800" priority="-2">
		<binary name="virtualbox5-nova"/>
		<resource name="RAM" quantum="448M"/>
		<config vbox_file="vm_genode_usb_hid.vbox" vm_name="TestVM" xhci="yes">
			<vfs>
				<dir name="dev"> <log/> </dir>
				<dir name="dev"> <terminal/> </dir>
				<rom name="vm_genode_usb_hid.vbox" />
				<rom name="usb_hid.iso" />
			</vfs>
			<libc stdout="/dev/log" stderr="/dev/log"/>
		</config>
		<route>
			<service name="Report"><child name="report_rom" /></service>
			<service name="ROM" label="usb_devices"> <child name="report_rom"/> </service>
			<any-service> <parent/> <any-child /> </any-service>
		</route>
	</start>
</config>
}

install_config $config

puts "--- executing the 'usb_hid' run script to generate the 'usb_hid.iso' image ---"

global specs
global repositories

exec -ignorestderr \
     $::argv0 \
     --genode-dir [genode_dir] \
     --name usb_hid \
     --specs "$specs" \
     --repositories "$repositories" \
     --cross-dev-prefix "[cross_dev_prefix]" \
     --include boot_dir/nova \
     --include image/iso \
     --include [repository_contains /run/usb_hid.run]/run/usb_hid.run

exec ln -sf ${genode_dir}/repos/ports/run/vm_genode_usb_hid.vbox bin/
exec ln -sf ../../usb_hid.iso bin/

set boot_modules {
	core
	init
	timer
	fb_drv
	ps2_drv
	log_terminal
	usb_drv
	usb_report_filter
	fs_rom
	ram_fs
	report_rom
	virtualbox5-nova
	usb_hid.iso
	vm_genode_usb_hid.vbox
	ld.lib.so libc.lib.so vfs.lib.so libm.lib.so pthread.lib.so libc_pipe.lib.so
	libc_terminal.lib.so libiconv.lib.so stdcxx.lib.so
	qemu-usb.lib.so
}

append_platform_drv_boot_modules

build_boot_image $boot_modules

if { ![get_cmd_switch --autopilot] } { run_genode_until forever }

# autopilot test

run_genode_until {\[init -\> log_terminal\] \[init -\> test-input\] Input event #0\t} 90

# remove everything before the first interesting line
regexp {(\[init -\> log_terminal\] \[init -\> test-input\] Input event #0\t.*)} $output all output

run_genode_until {.*\[init -\> test-input\] Input event #11.*\n} 60 [output_spawn_id]

unify_output { number [0-9]+} ""
unify_output {(?n)on usb-dummy.*$} ""
unify_output {(?n)using .*$} ""
unify_output {(?n)^.*__wait_event.*$} ""
unify_output {(?n)^.*Failed to submit URB.*$} ""
unify_output {(?n)^.*dev_warn.*$} ""
unify_output {(?n)^.*dangling allocation.*$} ""
unify_output {(?n)^.*Warning:.*$} ""
unify_output { [0-9][0-9][0-9][0-9]:[0-9][0-9][0-9][0-9] } " "
filter_out_color_escape_sequences
trim_lines

compare_output_to {
[init -> log_terminal] [init -> test-input] Input event #0	PRESS KEY_X 0
[init -> log_terminal] [init -> test-input] Input event #1	RELEASE KEY_X
[init -> log_terminal] [init -> test-input] Input event #2	PRESS BTN_LEFT 0
[init -> log_terminal] [init -> test-input] Input event #3	REL_MOTION -1+0
[init -> log_terminal] [init -> test-input] Input event #4	REL_MOTION +0+1
[init -> log_terminal] [init -> test-input] Input event #5	RELEASE BTN_LEFT
[init -> usb_drv] dev_info: USB disconnect, device
[init -> log_terminal] [init -> usb_drv] dev_info: USB disconnect, device
[init -> usb_drv] dev_info: new full-speed USB device
[init -> virtualbox] Attach USB device (vendor=3eb, product=204d)
[init -> log_terminal] [init -> usb_drv] dev_info: new full-speed USB device
[init -> log_terminal] [init -> usb_drv] dev_info: D L
[init -> log_terminal] [init -> usb_drv] dev_info: input: USB HID v1.11 Keyboard [D L]
[init -> log_terminal] [init -> usb_drv] dev_info: D L
[init -> log_terminal] [init -> usb_drv] dev_info: input: USB HID v1.11 Mouse [D L]
[init -> log_terminal] [init -> test-input] Input event #6	PRESS KEY_X 0
[init -> log_terminal] [init -> test-input] Input event #7	RELEASE KEY_X
[init -> log_terminal] [init -> test-input] Input event #8	PRESS BTN_LEFT 0
[init -> log_terminal] [init -> test-input] Input event #9	REL_MOTION -1+0
[init -> log_terminal] [init -> test-input] Input event #10	REL_MOTION +0+1
[init -> log_terminal] [init -> test-input] Input event #11	RELEASE BTN_LEFT
}