mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-20 08:03:56 +00:00
usb: session renewal & new client API
Replace the USB session API by one that provides a devices ROM only, which contains information about all USB devices available for this client, as well as methods to acquire and release a single device. The acquisition of an USB device returns the capability to a device session that includes a packet stream buffer to communicate control transfers in between the client and the USB host controller driver. Moreover, additional methods to acquire and release an USB interface can be used. The acquisition of an USB interface returns the capability to an interface session that includes a packet stream buffer to communicate either bulk, interrupt, or isochronous transfers in between the client and the USB host controller driver. This commit implements the API changes in behalf of the Genode C API's USB server and client side. Addtionally, it provides Usb::Device, Usb::Interface, and Usb::Endpoint utilities that can be used by native C++ clients to use the new API and hide the sophisticated packet stream API. The adaptations necessary target the following areas: * lx_emul layer for USB host and client side * Linux USB host controller driver port for PC * Linux USB client ports: usb_hid_drv and usb_net_drv, additionally reduce the Linux tasks used inside these drivers * Native usb_block_drv * black_hole component * Port of libusb, including smartcard and usb_webcam driver depending on it * Port of Qemu XHCI model library, including vbox5 & vbox6 depending on it * Adapt all run-scripts and drivers_interactive recipes to work with the new policy rules of the USB host controller driver Fix genodelabs/genode#5021
This commit is contained in:
committed by
Christian Helmuth
parent
6e437674f7
commit
7ec08af6d9
@ -1,21 +1,9 @@
|
||||
USB HID driver
|
||||
##############
|
||||
|
||||
Supports keyboard and mouse connected via USB. It connects to one or multiple
|
||||
USB sessions and reports input events to an event session. A run script can be
|
||||
found under 'run/usb_hid_raw.run'.
|
||||
|
||||
Configuration snippet:
|
||||
|
||||
!<start name="usb_hid_drv">
|
||||
! <resource name="RAM" quantum="10M"/>
|
||||
! <config use_report="yes"/>
|
||||
!</start>
|
||||
|
||||
When the use_report attribute is set, the HID driver will request a ROM called
|
||||
"report" that is used to iterate over all devices provided by the USB host
|
||||
controller driver (resp. a rom filter). In that mode the driver tries to
|
||||
claim all HID devices (class 0x3) via dedicated USB sessions.
|
||||
Supports keyboard and mouse connected via USB. It drives one or multiple devices
|
||||
depending on the provided ones in its USB sessions and reports input events to an
|
||||
event session. A run script can be found under 'run/usb_hid_raw.run'.
|
||||
|
||||
|
||||
Keyboard LED handling
|
||||
|
@ -166,29 +166,6 @@ int __init usb_devio_init(void)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
int usb_string(struct usb_device * dev,int index,char * buf,size_t size)
|
||||
{
|
||||
lx_emul_trace(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
extern char * usb_cache_string(struct usb_device * udev,int index);
|
||||
char * usb_cache_string(struct usb_device * udev,int index)
|
||||
{
|
||||
lx_emul_trace(__func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void usb_kill_urb(struct urb * urb)
|
||||
{
|
||||
lx_emul_trace(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
struct usb_hcd * usb_get_hcd(struct usb_hcd * hcd)
|
||||
@ -336,8 +313,53 @@ void usb_remove_sysfs_intf_files(struct usb_interface * intf)
|
||||
}
|
||||
|
||||
|
||||
extern void usb_disable_interface(struct usb_device * dev,struct usb_interface * intf,bool reset_hardware);
|
||||
void usb_disable_interface(struct usb_device * dev,struct usb_interface * intf,bool reset_hardware)
|
||||
const struct attribute_group *usb_interface_groups[] = { NULL };
|
||||
|
||||
|
||||
#include <linux/random.h>
|
||||
|
||||
void add_device_randomness(const void * buf,size_t len)
|
||||
{
|
||||
lx_emul_trace(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
int usb_hcd_alloc_bandwidth(struct usb_device * udev,struct usb_host_config * new_config,struct usb_host_interface * cur_alt,struct usb_host_interface * new_alt)
|
||||
{
|
||||
lx_emul_trace(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void usb_hcd_flush_endpoint(struct usb_device *udev,
|
||||
struct usb_host_endpoint *ep)
|
||||
{
|
||||
lx_emul_trace(__func__);
|
||||
}
|
||||
|
||||
|
||||
void usb_hcd_disable_endpoint(struct usb_device *udev,
|
||||
struct usb_host_endpoint *ep)
|
||||
{
|
||||
lx_emul_trace(__func__);
|
||||
}
|
||||
|
||||
|
||||
void usb_hcd_reset_endpoint(struct usb_device *udev,
|
||||
struct usb_host_endpoint *ep)
|
||||
{
|
||||
lx_emul_trace(__func__);
|
||||
}
|
||||
|
||||
|
||||
#if defined(CONFIG_OF)
|
||||
#include <linux/usb/of.h>
|
||||
|
||||
bool usb_of_has_combined_node(struct usb_device * udev)
|
||||
{
|
||||
lx_emul_trace(__func__);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
@ -23,36 +23,7 @@
|
||||
const struct attribute_group input_poller_attribute_group;
|
||||
pteval_t __default_kernel_pte_mask __read_mostly = ~0;
|
||||
|
||||
struct device_type usb_if_device_type = {
|
||||
.name = "usb_interface"
|
||||
};
|
||||
|
||||
struct usb_driver usbfs_driver = {
|
||||
.name = "usbfs"
|
||||
};
|
||||
const struct attribute_group *usb_device_groups[] = { };
|
||||
|
||||
|
||||
/*
|
||||
* Taken and ajdusted from linux/drivers/usb/core/message.c If this is required
|
||||
* by more drivers in the future, we will move it to
|
||||
* dde_linux/src/lib/virt/shadow/drivers/usb/core/message.c
|
||||
*/
|
||||
int usb_clear_halt(struct usb_device *dev, int pipe)
|
||||
{
|
||||
int result;
|
||||
int endp = usb_pipeendpoint(pipe);
|
||||
|
||||
if (usb_pipein(pipe))
|
||||
endp |= USB_DIR_IN;
|
||||
|
||||
/* we don't care if it wasn't halted first. in fact some devices
|
||||
* (like some ibmcam model 1 units) seem to expect hosts to make
|
||||
* this request for iso endpoints, which can't halt!
|
||||
*/
|
||||
result = usb_control_msg(dev, usb_sndctrlpipe(dev, endp),
|
||||
USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT,
|
||||
USB_ENDPOINT_HALT, endp, NULL, 0,
|
||||
USB_CTRL_SET_TIMEOUT);
|
||||
return result;
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
/*
|
||||
* \brief Post kernel activity
|
||||
* \author Sebastian Sumpf
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2023-06-29
|
||||
*/
|
||||
|
||||
@ -11,36 +12,20 @@
|
||||
* version 2.
|
||||
*/
|
||||
|
||||
#include <linux/sched/task.h>
|
||||
#include <usb_hid.h>
|
||||
|
||||
static struct task_struct *main_task = NULL;
|
||||
|
||||
|
||||
struct task_struct *lx_user_new_usb_task(int (*func)(void*), void *args)
|
||||
{
|
||||
int pid = kernel_thread(func, args, CLONE_FS | CLONE_FILES);
|
||||
return find_task_by_pid_ns(pid, NULL);
|
||||
}
|
||||
|
||||
|
||||
void lx_user_destroy_usb_task(struct task_struct *task)
|
||||
{
|
||||
if (task != current) {
|
||||
printk("%s: task: %px is not current: %px\n", __func__,
|
||||
task, current);
|
||||
return;
|
||||
}
|
||||
|
||||
/* unblock main task which initiated destruction */
|
||||
lx_emul_task_unblock(main_task);
|
||||
|
||||
do_exit(0);
|
||||
}
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <lx_emul/input_leds.h>
|
||||
#include <lx_emul/usb_client.h>
|
||||
#include <lx_user/init.h>
|
||||
#include <lx_user/io.h>
|
||||
|
||||
void lx_user_init(void)
|
||||
{
|
||||
int pid = kernel_thread(lx_user_main_task, &main_task, CLONE_FS | CLONE_FILES);
|
||||
main_task = find_task_by_pid_ns(pid, NULL);
|
||||
lx_emul_usb_client_init();
|
||||
lx_emul_input_leds_init();
|
||||
}
|
||||
|
||||
|
||||
void lx_user_handle_io(void)
|
||||
{
|
||||
lx_emul_usb_client_ticker();
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
/*
|
||||
* \brief C++ initialization, session, and client handling
|
||||
* \author Sebastian Sumpf
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2023-06-29
|
||||
*/
|
||||
|
||||
@ -19,6 +20,7 @@
|
||||
#include <lx_emul/init.h>
|
||||
#include <lx_emul/task.h>
|
||||
#include <lx_emul/input_leds.h>
|
||||
#include <lx_user/io.h>
|
||||
#include <lx_kit/env.h>
|
||||
|
||||
#include <genode_c_api/event.h>
|
||||
@ -30,343 +32,65 @@
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
struct Task_handler
|
||||
{
|
||||
task_struct *task;
|
||||
Signal_handler<Task_handler> handler;
|
||||
bool handling_signal { false };
|
||||
bool running { true };
|
||||
|
||||
/*
|
||||
* If the task is currently executing and the signal handler
|
||||
* is called again via 'block_and_schedule()', we need to
|
||||
* keep this information, so the task does not block at the
|
||||
* end when a new signal already occurred.
|
||||
*
|
||||
* Initialized as true for the initial run of the task.
|
||||
*/
|
||||
bool _signal_pending { true };
|
||||
|
||||
void handle_signal()
|
||||
{
|
||||
_signal_pending = true;
|
||||
lx_emul_task_unblock(task);
|
||||
handling_signal = true;
|
||||
Lx_kit::env().scheduler.execute();
|
||||
handling_signal = false;
|
||||
}
|
||||
|
||||
bool signal_pending()
|
||||
{
|
||||
bool ret = _signal_pending;
|
||||
_signal_pending = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void block_and_schedule()
|
||||
{
|
||||
lx_emul_task_schedule(true);
|
||||
}
|
||||
|
||||
void destroy_task()
|
||||
{
|
||||
running = false;
|
||||
lx_emul_task_unblock(task);
|
||||
/* will be unblocked by lx_user_destroy_usb_task */
|
||||
lx_emul_task_schedule(true);
|
||||
}
|
||||
|
||||
Task_handler(Entrypoint & ep, task_struct *task)
|
||||
: task(task), handler(ep, *this, &Task_handler::handle_signal) { }
|
||||
|
||||
/* non-copyable */
|
||||
Task_handler(const Task_handler&) = delete;
|
||||
Task_handler & operator=(const Task_handler&) = delete;
|
||||
};
|
||||
|
||||
|
||||
struct Leds
|
||||
struct Main
|
||||
{
|
||||
Env &env;
|
||||
|
||||
Attached_rom_dataspace &config_rom;
|
||||
|
||||
task_struct *led_task { lx_user_new_usb_task(led_task_entry, this) };
|
||||
|
||||
Task_handler led_task_handler { env.ep(), led_task };
|
||||
Attached_rom_dataspace config_rom { env, "config" };
|
||||
|
||||
Usb::Led_state capslock { env, "capslock" },
|
||||
numlock { env, "numlock" },
|
||||
scrlock { env, "scrlock" };
|
||||
|
||||
Leds(Env &env, Attached_rom_dataspace &config_rom)
|
||||
: env(env), config_rom(config_rom) { };
|
||||
Signal_handler<Main> signal_handler { env.ep(), *this,
|
||||
&Main::handle_signal };
|
||||
Signal_handler<Main> usb_rom_handler { env.ep(), *this,
|
||||
&Main::handle_usb_rom };
|
||||
Signal_handler<Main> config_handler { env.ep(), *this,
|
||||
&Main::handle_config };
|
||||
|
||||
/* non-copyable */
|
||||
Leds(const Leds&) = delete;
|
||||
Leds & operator=(const Leds&) = delete;
|
||||
Main(Env &env)
|
||||
:
|
||||
env(env)
|
||||
{
|
||||
Lx_kit::initialize(env, signal_handler);
|
||||
|
||||
Genode_c_api::initialize_usb_client(env, Lx_kit::env().heap,
|
||||
signal_handler, usb_rom_handler);
|
||||
|
||||
genode_event_init(genode_env_ptr(env),
|
||||
genode_allocator_ptr(Lx_kit::env().heap));
|
||||
|
||||
config_rom.sigh(config_handler);
|
||||
handle_config();
|
||||
|
||||
lx_emul_start_kernel(nullptr);
|
||||
}
|
||||
|
||||
void handle_signal()
|
||||
{
|
||||
lx_user_handle_io();
|
||||
Lx_kit::env().scheduler.execute();
|
||||
}
|
||||
|
||||
void handle_usb_rom()
|
||||
{
|
||||
lx_emul_usb_client_rom_update();
|
||||
Lx_kit::env().scheduler.execute();
|
||||
}
|
||||
|
||||
void handle_config()
|
||||
{
|
||||
config_rom.update();
|
||||
Genode::Xml_node config =config_rom.xml();
|
||||
|
||||
capslock.update(config, led_task_handler.handler);
|
||||
numlock .update(config, led_task_handler.handler);
|
||||
scrlock .update(config, led_task_handler.handler);
|
||||
}
|
||||
|
||||
|
||||
/**********
|
||||
** Task **
|
||||
**********/
|
||||
|
||||
static int led_task_entry(void *arg)
|
||||
{
|
||||
Leds &led = *reinterpret_cast<Leds *>(arg);
|
||||
|
||||
while (true) {
|
||||
led.handle_config();
|
||||
|
||||
lx_emul_input_leds_update(led.capslock.enabled(),
|
||||
led.numlock.enabled(),
|
||||
led.scrlock.enabled());
|
||||
|
||||
led.led_task_handler.block_and_schedule();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct Device : Registry<Device>::Element
|
||||
{
|
||||
using Label = String<64>;
|
||||
|
||||
Env &env;
|
||||
Label label;
|
||||
|
||||
/*
|
||||
* Dedicated allocator per device to notice dangling
|
||||
* allocations on device destruction.
|
||||
*/
|
||||
Allocator_avl alloc { &Lx_kit::env().heap };
|
||||
|
||||
task_struct *state_task { lx_user_new_usb_task(state_task_entry, this) };
|
||||
task_struct *urb_task { lx_user_new_usb_task(urb_task_entry, this) };
|
||||
|
||||
Task_handler state_task_handler { env.ep(), state_task };
|
||||
Task_handler urb_task_handler { env.ep(), urb_task };
|
||||
|
||||
genode_usb_client_handle_t usb_handle {
|
||||
genode_usb_client_create(genode_env_ptr(env),
|
||||
genode_allocator_ptr(Lx_kit::env().heap),
|
||||
genode_range_allocator_ptr(alloc),
|
||||
label.string(),
|
||||
genode_signal_handler_ptr(state_task_handler.handler)) };
|
||||
|
||||
bool updated { true };
|
||||
bool registered { false };
|
||||
|
||||
void *lx_device_handle { nullptr };
|
||||
|
||||
Device(Env &env, Registry<Device> ®istry, Label label)
|
||||
:
|
||||
Registry<Device>::Element(registry, *this),
|
||||
env(env), label(label)
|
||||
{
|
||||
genode_usb_client_sigh_ack_avail(usb_handle,
|
||||
genode_signal_handler_ptr(urb_task_handler.handler));
|
||||
}
|
||||
|
||||
~Device()
|
||||
{
|
||||
genode_usb_client_destroy(usb_handle,
|
||||
genode_allocator_ptr(Lx_kit::env().heap));
|
||||
|
||||
state_task_handler.destroy_task();
|
||||
urb_task_handler.destroy_task();
|
||||
}
|
||||
|
||||
/* non-copyable */
|
||||
Device(const Device&) = delete;
|
||||
Device & operator=(const Device&) = delete;
|
||||
|
||||
void register_device()
|
||||
{
|
||||
registered = true;
|
||||
lx_device_handle = lx_emul_usb_client_register_device(usb_handle, label.string());
|
||||
if (!lx_device_handle) registered = false;
|
||||
}
|
||||
|
||||
void unregister_device()
|
||||
{
|
||||
lx_emul_usb_client_unregister_device(usb_handle, lx_device_handle);
|
||||
registered = false;
|
||||
}
|
||||
|
||||
bool deinit() { return !registered &&
|
||||
!state_task_handler.handling_signal &&
|
||||
!urb_task_handler.handling_signal; }
|
||||
|
||||
/**********
|
||||
** Task **
|
||||
**********/
|
||||
|
||||
static int state_task_entry(void *arg)
|
||||
{
|
||||
Device &device = *reinterpret_cast<Device *>(arg);
|
||||
|
||||
while (device.state_task_handler.running) {
|
||||
while (device.state_task_handler.signal_pending()) {
|
||||
if (genode_usb_client_plugged(device.usb_handle) && !device.registered)
|
||||
device.register_device();
|
||||
|
||||
if (!genode_usb_client_plugged(device.usb_handle) && device.registered)
|
||||
device.unregister_device();
|
||||
}
|
||||
device.state_task_handler.block_and_schedule();
|
||||
}
|
||||
lx_user_destroy_usb_task(device.state_task_handler.task);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int urb_task_entry(void *arg)
|
||||
{
|
||||
Device &device = *reinterpret_cast<Device *>(arg);
|
||||
|
||||
while (device.urb_task_handler.running) {
|
||||
if (device.registered)
|
||||
genode_usb_client_execute_completions(device.usb_handle);
|
||||
|
||||
device.urb_task_handler.block_and_schedule();
|
||||
}
|
||||
lx_user_destroy_usb_task(device.urb_task_handler.task);
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct Driver
|
||||
{
|
||||
Env &env;
|
||||
|
||||
Task_handler task_handler;
|
||||
|
||||
Heap &heap { Lx_kit::env().heap };
|
||||
|
||||
bool use_report { false };
|
||||
|
||||
Constructible<Attached_rom_dataspace> report_rom { };
|
||||
|
||||
Attached_rom_dataspace config_rom { env, "config" };
|
||||
|
||||
Leds leds { env, config_rom };
|
||||
|
||||
Registry<Device> devices { };
|
||||
|
||||
Driver(Env &env, task_struct *task)
|
||||
: env(env), task_handler(env.ep(), task)
|
||||
{
|
||||
try {
|
||||
Xml_node config = config_rom.xml();
|
||||
use_report = config.attribute_value("use_report", false);
|
||||
} catch(...) { }
|
||||
|
||||
if (use_report)
|
||||
warning("use compatibility mode: ",
|
||||
"will claim all HID devices from USB report");
|
||||
}
|
||||
|
||||
void scan_report()
|
||||
{
|
||||
if (!report_rom.constructed()) {
|
||||
report_rom.construct(env, "report");
|
||||
report_rom->sigh(task_handler.handler);
|
||||
}
|
||||
|
||||
report_rom->update();
|
||||
|
||||
devices.for_each([&] (Device & d) { d.updated = false; });
|
||||
|
||||
try {
|
||||
Xml_node report_node = report_rom->xml();
|
||||
report_node.for_each_sub_node([&] (Xml_node & dev_node)
|
||||
{
|
||||
unsigned long c = 0;
|
||||
dev_node.attribute("class").value(c);
|
||||
if (c != 0x3 /* USB_CLASS_HID */) return;
|
||||
|
||||
Device::Label label;
|
||||
dev_node.attribute("label").value(label);
|
||||
|
||||
bool found = false;
|
||||
|
||||
devices.for_each([&] (Device & d) {
|
||||
if (d.label == label) d.updated = found = true; });
|
||||
|
||||
if (!found) new (heap) Device(env, devices, label);
|
||||
});
|
||||
} catch(...) {
|
||||
error("Error parsing USB devices report");
|
||||
throw;
|
||||
};
|
||||
|
||||
devices.for_each([&] (Device & d) {
|
||||
if (!d.updated && d.deinit()) {
|
||||
destroy(heap, &d);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct Main
|
||||
{
|
||||
Env &env;
|
||||
|
||||
Signal_handler<Main> signal_handler { env.ep(), *this, &Main::handle_signal };
|
||||
|
||||
Main(Env &env) : env(env) { }
|
||||
|
||||
void handle_signal()
|
||||
{
|
||||
Genode::Xml_node config = config_rom.xml();
|
||||
capslock.update(config, config_handler);
|
||||
numlock .update(config, config_handler);
|
||||
scrlock .update(config, config_handler);
|
||||
lx_emul_input_leds_update(capslock.enabled(), numlock.enabled(),
|
||||
scrlock.enabled());
|
||||
Lx_kit::env().scheduler.execute();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void Component::construct(Env & env)
|
||||
{
|
||||
static Main main { env };
|
||||
Lx_kit::initialize(env, main.signal_handler);
|
||||
|
||||
env.exec_static_constructors();
|
||||
|
||||
genode_event_init(genode_env_ptr(env),
|
||||
genode_allocator_ptr(Lx_kit::env().heap));
|
||||
|
||||
lx_emul_start_kernel(nullptr);
|
||||
}
|
||||
|
||||
|
||||
/**********
|
||||
** Task **
|
||||
**********/
|
||||
|
||||
int lx_user_main_task(void *data)
|
||||
{
|
||||
task_struct *task = *static_cast<task_struct **>(data);
|
||||
|
||||
static Driver driver { Lx_kit::env().env, task };
|
||||
|
||||
for (;;) {
|
||||
while (driver.task_handler.signal_pending()) {
|
||||
if (!driver.use_report)
|
||||
static Device dev(driver.env, driver.devices, Device::Label(""));
|
||||
else
|
||||
driver.scan_report();
|
||||
}
|
||||
driver.task_handler.block_and_schedule();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
void Component::construct(Env & env) { static Main main(env); }
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* \brief Dummy definitions of Linux Kernel functions
|
||||
* \author Automatically generated file - do no edit
|
||||
* \date 2024-02-05
|
||||
* \date 2024-02-22
|
||||
*/
|
||||
|
||||
#include <lx_emul.h>
|
||||
@ -89,14 +89,6 @@ int _printk_deferred(const char * fmt,...)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/random.h>
|
||||
|
||||
void add_device_randomness(const void * buf,size_t len)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/kobject.h>
|
||||
|
||||
int add_uevent_var(struct kobj_uevent_env * env,const char * format,...)
|
||||
@ -426,6 +418,14 @@ void led_trigger_event(struct led_trigger * trig,enum led_brightness brightness)
|
||||
unsigned long lpj_fine;
|
||||
|
||||
|
||||
#include <linux/of.h>
|
||||
|
||||
bool of_device_is_available(const struct device_node * device)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/of_device.h>
|
||||
|
||||
void of_device_uevent(struct device * dev,struct kobj_uevent_env * env)
|
||||
@ -487,6 +487,14 @@ int power_supply_powers(struct power_supply * psy,struct device * dev)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/scatterlist.h>
|
||||
|
||||
struct scatterlist * sg_next(struct scatterlist * sg)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/smp.h>
|
||||
|
||||
void smp_call_function_many(const struct cpumask * mask,smp_call_func_t func,void * info,bool wait)
|
||||
@ -532,14 +540,6 @@ struct timerqueue_node * timerqueue_iterate_next(struct timerqueue_node * node)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
void usb_block_urb(struct urb * urb)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
extern void usb_devio_cleanup(void);
|
||||
void usb_devio_cleanup(void)
|
||||
{
|
||||
@ -547,13 +547,6 @@ void usb_devio_cleanup(void)
|
||||
}
|
||||
|
||||
|
||||
extern void usb_disable_endpoint(struct usb_device * dev,unsigned int epaddr,bool reset_hardware);
|
||||
void usb_disable_endpoint(struct usb_device * dev,unsigned int epaddr,bool reset_hardware)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
int usb_free_streams(struct usb_interface * interface,struct usb_host_endpoint ** eps,unsigned int num_eps,gfp_t mem_flags)
|
||||
@ -562,29 +555,6 @@ int usb_free_streams(struct usb_interface * interface,struct usb_host_endpoint *
|
||||
}
|
||||
|
||||
|
||||
extern int usb_get_device_descriptor(struct usb_device * dev,unsigned int size);
|
||||
int usb_get_device_descriptor(struct usb_device * dev,unsigned int size)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
int usb_get_status(struct usb_device * dev,int recip,int type,int target,void * data)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
int usb_hcd_alloc_bandwidth(struct usb_device * udev,struct usb_host_config * new_config,struct usb_host_interface * cur_alt,struct usb_host_interface * new_alt)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
int usb_hcd_find_raw_port_number(struct usb_hcd * hcd,int port1)
|
||||
@ -607,14 +577,6 @@ void usb_hub_remove_port_device(struct usb_hub * hub,int port1)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
int usb_interrupt_msg(struct usb_device * usb_dev,unsigned int pipe,void * data,int len,int * actual_length,int timeout)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
extern void usb_major_cleanup(void);
|
||||
void usb_major_cleanup(void)
|
||||
{
|
||||
@ -630,8 +592,9 @@ struct device_node * usb_of_get_device_node(struct usb_device * hub,int port1)
|
||||
}
|
||||
|
||||
|
||||
extern int usb_set_isoch_delay(struct usb_device * dev);
|
||||
int usb_set_isoch_delay(struct usb_device * dev)
|
||||
#include <linux/usb/of.h>
|
||||
|
||||
struct device_node * usb_of_get_interface_node(struct usb_device * udev,u8 config,u8 ifnum)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
@ -645,22 +608,6 @@ const char * usb_speed_string(enum usb_device_speed speed)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
int usb_unlink_urb(struct urb * urb)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
void usb_unpoison_urb(struct urb * urb)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/uuid.h>
|
||||
|
||||
const u8 uuid_index[16] = {};
|
||||
|
@ -32,8 +32,11 @@ drivers/usb/core/config.c
|
||||
drivers/usb/core/driver.c
|
||||
drivers/usb/core/generic.c
|
||||
drivers/usb/core/hub.c
|
||||
drivers/usb/core/message.c
|
||||
drivers/usb/core/quirks.c
|
||||
drivers/usb/core/urb.c
|
||||
drivers/usb/core/usb.c
|
||||
fs/nls/nls_base.c
|
||||
kernel/kthread.c
|
||||
kernel/locking/mutex.c
|
||||
kernel/locking/osq_lock.c
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* \brief Dummy definitions of Linux Kernel functions
|
||||
* \author Automatically generated file - do no edit
|
||||
* \date 2024-02-05
|
||||
* \date 2024-02-22
|
||||
*/
|
||||
|
||||
#include <lx_emul.h>
|
||||
@ -79,14 +79,6 @@ int _printk_deferred(const char * fmt,...)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/random.h>
|
||||
|
||||
void add_device_randomness(const void * buf,size_t len)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/kobject.h>
|
||||
|
||||
int add_uevent_var(struct kobj_uevent_env * env,const char * format,...)
|
||||
@ -328,6 +320,14 @@ void led_trigger_event(struct led_trigger * trig,enum led_brightness brightness)
|
||||
unsigned long lpj_fine;
|
||||
|
||||
|
||||
#include <linux/of.h>
|
||||
|
||||
bool of_device_is_available(const struct device_node * device)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/of_device.h>
|
||||
|
||||
void of_device_uevent(struct device * dev,struct kobj_uevent_env * env)
|
||||
@ -384,6 +384,14 @@ int power_supply_powers(struct power_supply * psy,struct device * dev)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/scatterlist.h>
|
||||
|
||||
struct scatterlist * sg_next(struct scatterlist * sg)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/jump_label.h>
|
||||
|
||||
bool static_key_initialized;
|
||||
@ -413,14 +421,6 @@ struct timerqueue_node * timerqueue_iterate_next(struct timerqueue_node * node)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
void usb_block_urb(struct urb * urb)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
extern void usb_devio_cleanup(void);
|
||||
void usb_devio_cleanup(void)
|
||||
{
|
||||
@ -428,13 +428,6 @@ void usb_devio_cleanup(void)
|
||||
}
|
||||
|
||||
|
||||
extern void usb_disable_endpoint(struct usb_device * dev,unsigned int epaddr,bool reset_hardware);
|
||||
void usb_disable_endpoint(struct usb_device * dev,unsigned int epaddr,bool reset_hardware)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
int usb_free_streams(struct usb_interface * interface,struct usb_host_endpoint ** eps,unsigned int num_eps,gfp_t mem_flags)
|
||||
@ -443,29 +436,6 @@ int usb_free_streams(struct usb_interface * interface,struct usb_host_endpoint *
|
||||
}
|
||||
|
||||
|
||||
extern int usb_get_device_descriptor(struct usb_device * dev,unsigned int size);
|
||||
int usb_get_device_descriptor(struct usb_device * dev,unsigned int size)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
int usb_get_status(struct usb_device * dev,int recip,int type,int target,void * data)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
int usb_hcd_alloc_bandwidth(struct usb_device * udev,struct usb_host_config * new_config,struct usb_host_interface * cur_alt,struct usb_host_interface * new_alt)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
int usb_hcd_find_raw_port_number(struct usb_hcd * hcd,int port1)
|
||||
@ -488,14 +458,6 @@ void usb_hub_remove_port_device(struct usb_hub * hub,int port1)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
int usb_interrupt_msg(struct usb_device * usb_dev,unsigned int pipe,void * data,int len,int * actual_length,int timeout)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
extern void usb_major_cleanup(void);
|
||||
void usb_major_cleanup(void)
|
||||
{
|
||||
@ -511,8 +473,9 @@ struct device_node * usb_of_get_device_node(struct usb_device * hub,int port1)
|
||||
}
|
||||
|
||||
|
||||
extern int usb_set_isoch_delay(struct usb_device * dev);
|
||||
int usb_set_isoch_delay(struct usb_device * dev)
|
||||
#include <linux/usb/of.h>
|
||||
|
||||
struct device_node * usb_of_get_interface_node(struct usb_device * udev,u8 config,u8 ifnum)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
@ -526,22 +489,6 @@ const char * usb_speed_string(enum usb_device_speed speed)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
int usb_unlink_urb(struct urb * urb)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
void usb_unpoison_urb(struct urb * urb)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/uuid.h>
|
||||
|
||||
const u8 uuid_index[16] = {};
|
||||
|
@ -32,8 +32,11 @@ drivers/usb/core/config.c
|
||||
drivers/usb/core/driver.c
|
||||
drivers/usb/core/generic.c
|
||||
drivers/usb/core/hub.c
|
||||
drivers/usb/core/message.c
|
||||
drivers/usb/core/quirks.c
|
||||
drivers/usb/core/urb.c
|
||||
drivers/usb/core/usb.c
|
||||
fs/nls/nls_base.c
|
||||
kernel/kthread.c
|
||||
kernel/locking/mutex.c
|
||||
kernel/locking/osq_lock.c
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* \brief Dummy definitions of Linux Kernel functions
|
||||
* \author Automatically generated file - do no edit
|
||||
* \date 2024-02-05
|
||||
* \date 2024-02-22
|
||||
*/
|
||||
|
||||
#include <lx_emul.h>
|
||||
@ -89,14 +89,6 @@ int _printk_deferred(const char * fmt,...)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/random.h>
|
||||
|
||||
void add_device_randomness(const void * buf,size_t len)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/kobject.h>
|
||||
|
||||
int add_uevent_var(struct kobj_uevent_env * env,const char * format,...)
|
||||
@ -391,6 +383,14 @@ void led_trigger_event(struct led_trigger * trig,enum led_brightness brightness)
|
||||
unsigned long lpj_fine;
|
||||
|
||||
|
||||
#include <linux/of.h>
|
||||
|
||||
bool of_device_is_available(const struct device_node * device)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/of_device.h>
|
||||
|
||||
void of_device_uevent(struct device * dev,struct kobj_uevent_env * env)
|
||||
@ -452,6 +452,14 @@ int power_supply_powers(struct power_supply * psy,struct device * dev)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/scatterlist.h>
|
||||
|
||||
struct scatterlist * sg_next(struct scatterlist * sg)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/smp.h>
|
||||
|
||||
void smp_call_function_many(const struct cpumask * mask,smp_call_func_t func,void * info,bool wait)
|
||||
@ -497,14 +505,6 @@ struct timerqueue_node * timerqueue_iterate_next(struct timerqueue_node * node)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
void usb_block_urb(struct urb * urb)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
extern void usb_devio_cleanup(void);
|
||||
void usb_devio_cleanup(void)
|
||||
{
|
||||
@ -512,13 +512,6 @@ void usb_devio_cleanup(void)
|
||||
}
|
||||
|
||||
|
||||
extern void usb_disable_endpoint(struct usb_device * dev,unsigned int epaddr,bool reset_hardware);
|
||||
void usb_disable_endpoint(struct usb_device * dev,unsigned int epaddr,bool reset_hardware)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
int usb_free_streams(struct usb_interface * interface,struct usb_host_endpoint ** eps,unsigned int num_eps,gfp_t mem_flags)
|
||||
@ -527,29 +520,6 @@ int usb_free_streams(struct usb_interface * interface,struct usb_host_endpoint *
|
||||
}
|
||||
|
||||
|
||||
extern int usb_get_device_descriptor(struct usb_device * dev,unsigned int size);
|
||||
int usb_get_device_descriptor(struct usb_device * dev,unsigned int size)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
int usb_get_status(struct usb_device * dev,int recip,int type,int target,void * data)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
int usb_hcd_alloc_bandwidth(struct usb_device * udev,struct usb_host_config * new_config,struct usb_host_interface * cur_alt,struct usb_host_interface * new_alt)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
int usb_hcd_find_raw_port_number(struct usb_hcd * hcd,int port1)
|
||||
@ -572,14 +542,6 @@ void usb_hub_remove_port_device(struct usb_hub * hub,int port1)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
int usb_interrupt_msg(struct usb_device * usb_dev,unsigned int pipe,void * data,int len,int * actual_length,int timeout)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
extern void usb_major_cleanup(void);
|
||||
void usb_major_cleanup(void)
|
||||
{
|
||||
@ -595,8 +557,9 @@ struct device_node * usb_of_get_device_node(struct usb_device * hub,int port1)
|
||||
}
|
||||
|
||||
|
||||
extern int usb_set_isoch_delay(struct usb_device * dev);
|
||||
int usb_set_isoch_delay(struct usb_device * dev)
|
||||
#include <linux/usb/of.h>
|
||||
|
||||
struct device_node * usb_of_get_interface_node(struct usb_device * udev,u8 config,u8 ifnum)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
@ -610,22 +573,6 @@ const char * usb_speed_string(enum usb_device_speed speed)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
int usb_unlink_urb(struct urb * urb)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
void usb_unpoison_urb(struct urb * urb)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/uuid.h>
|
||||
|
||||
const u8 uuid_index[16] = {};
|
||||
|
@ -30,8 +30,11 @@ drivers/usb/core/config.c
|
||||
drivers/usb/core/driver.c
|
||||
drivers/usb/core/generic.c
|
||||
drivers/usb/core/hub.c
|
||||
drivers/usb/core/message.c
|
||||
drivers/usb/core/quirks.c
|
||||
drivers/usb/core/urb.c
|
||||
drivers/usb/core/usb.c
|
||||
fs/nls/nls_base.c
|
||||
kernel/kthread.c
|
||||
kernel/locking/mutex.c
|
||||
kernel/locking/osq_lock.c
|
||||
|
@ -75,14 +75,6 @@ void ack_bad_irq(unsigned int irq)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/random.h>
|
||||
|
||||
void add_device_randomness(const void * buf,size_t len)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/kobject.h>
|
||||
|
||||
int add_uevent_var(struct kobj_uevent_env * env,const char * format,...)
|
||||
@ -367,6 +359,14 @@ int power_supply_powers(struct power_supply * psy,struct device * dev)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/scatterlist.h>
|
||||
|
||||
struct scatterlist * sg_next(struct scatterlist * sg)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/smp.h>
|
||||
|
||||
void smp_call_function_many(const struct cpumask * mask,smp_call_func_t func,void * info,bool wait)
|
||||
@ -412,14 +412,6 @@ struct timerqueue_node * timerqueue_iterate_next(struct timerqueue_node * node)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
void usb_block_urb(struct urb * urb)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
extern void usb_devio_cleanup(void);
|
||||
void usb_devio_cleanup(void)
|
||||
{
|
||||
@ -427,13 +419,6 @@ void usb_devio_cleanup(void)
|
||||
}
|
||||
|
||||
|
||||
extern void usb_disable_endpoint(struct usb_device * dev,unsigned int epaddr,bool reset_hardware);
|
||||
void usb_disable_endpoint(struct usb_device * dev,unsigned int epaddr,bool reset_hardware)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
int usb_free_streams(struct usb_interface * interface,struct usb_host_endpoint ** eps,unsigned int num_eps,gfp_t mem_flags)
|
||||
@ -442,29 +427,6 @@ int usb_free_streams(struct usb_interface * interface,struct usb_host_endpoint *
|
||||
}
|
||||
|
||||
|
||||
extern int usb_get_device_descriptor(struct usb_device * dev,unsigned int size);
|
||||
int usb_get_device_descriptor(struct usb_device * dev,unsigned int size)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
int usb_get_status(struct usb_device * dev,int recip,int type,int target,void * data)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
int usb_hcd_alloc_bandwidth(struct usb_device * udev,struct usb_host_config * new_config,struct usb_host_interface * cur_alt,struct usb_host_interface * new_alt)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
int usb_hcd_find_raw_port_number(struct usb_hcd * hcd,int port1)
|
||||
@ -487,14 +449,6 @@ void usb_hub_remove_port_device(struct usb_hub * hub,int port1)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
int usb_interrupt_msg(struct usb_device * usb_dev,unsigned int pipe,void * data,int len,int * actual_length,int timeout)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
extern void usb_major_cleanup(void);
|
||||
void usb_major_cleanup(void)
|
||||
{
|
||||
@ -502,13 +456,6 @@ void usb_major_cleanup(void)
|
||||
}
|
||||
|
||||
|
||||
extern int usb_set_isoch_delay(struct usb_device * dev);
|
||||
int usb_set_isoch_delay(struct usb_device * dev)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb/ch9.h>
|
||||
|
||||
const char * usb_speed_string(enum usb_device_speed speed)
|
||||
@ -517,22 +464,6 @@ const char * usb_speed_string(enum usb_device_speed speed)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
int usb_unlink_urb(struct urb * urb)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
void usb_unpoison_urb(struct urb * urb)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/uuid.h>
|
||||
|
||||
const u8 uuid_index[16] = {};
|
||||
|
@ -25,8 +25,11 @@ drivers/usb/core/config.c
|
||||
drivers/usb/core/driver.c
|
||||
drivers/usb/core/generic.c
|
||||
drivers/usb/core/hub.c
|
||||
drivers/usb/core/message.c
|
||||
drivers/usb/core/quirks.c
|
||||
drivers/usb/core/urb.c
|
||||
drivers/usb/core/usb.c
|
||||
fs/nls/nls_base.c
|
||||
kernel/kthread.c
|
||||
kernel/locking/mutex.c
|
||||
kernel/locking/osq_lock.c
|
||||
|
@ -75,14 +75,6 @@ void ack_bad_irq(unsigned int irq)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/random.h>
|
||||
|
||||
void add_device_randomness(const void * buf,size_t len)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/kobject.h>
|
||||
|
||||
int add_uevent_var(struct kobj_uevent_env * env,const char * format,...)
|
||||
@ -335,6 +327,14 @@ int power_supply_powers(struct power_supply * psy,struct device * dev)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/scatterlist.h>
|
||||
|
||||
struct scatterlist * sg_next(struct scatterlist * sg)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/smp.h>
|
||||
|
||||
void smp_call_function_many(const struct cpumask * mask,smp_call_func_t func,void * info,bool wait)
|
||||
@ -380,14 +380,6 @@ struct timerqueue_node * timerqueue_iterate_next(struct timerqueue_node * node)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
void usb_block_urb(struct urb * urb)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
extern void usb_devio_cleanup(void);
|
||||
void usb_devio_cleanup(void)
|
||||
{
|
||||
@ -395,13 +387,6 @@ void usb_devio_cleanup(void)
|
||||
}
|
||||
|
||||
|
||||
extern void usb_disable_endpoint(struct usb_device * dev,unsigned int epaddr,bool reset_hardware);
|
||||
void usb_disable_endpoint(struct usb_device * dev,unsigned int epaddr,bool reset_hardware)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
int usb_free_streams(struct usb_interface * interface,struct usb_host_endpoint ** eps,unsigned int num_eps,gfp_t mem_flags)
|
||||
@ -410,29 +395,6 @@ int usb_free_streams(struct usb_interface * interface,struct usb_host_endpoint *
|
||||
}
|
||||
|
||||
|
||||
extern int usb_get_device_descriptor(struct usb_device * dev,unsigned int size);
|
||||
int usb_get_device_descriptor(struct usb_device * dev,unsigned int size)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
int usb_get_status(struct usb_device * dev,int recip,int type,int target,void * data)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
int usb_hcd_alloc_bandwidth(struct usb_device * udev,struct usb_host_config * new_config,struct usb_host_interface * cur_alt,struct usb_host_interface * new_alt)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
int usb_hcd_find_raw_port_number(struct usb_hcd * hcd,int port1)
|
||||
@ -455,14 +417,6 @@ void usb_hub_remove_port_device(struct usb_hub * hub,int port1)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
int usb_interrupt_msg(struct usb_device * usb_dev,unsigned int pipe,void * data,int len,int * actual_length,int timeout)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
extern void usb_major_cleanup(void);
|
||||
void usb_major_cleanup(void)
|
||||
{
|
||||
@ -470,13 +424,6 @@ void usb_major_cleanup(void)
|
||||
}
|
||||
|
||||
|
||||
extern int usb_set_isoch_delay(struct usb_device * dev);
|
||||
int usb_set_isoch_delay(struct usb_device * dev)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb/ch9.h>
|
||||
|
||||
const char * usb_speed_string(enum usb_device_speed speed)
|
||||
@ -485,22 +432,6 @@ const char * usb_speed_string(enum usb_device_speed speed)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
int usb_unlink_urb(struct urb * urb)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
void usb_unpoison_urb(struct urb * urb)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/uuid.h>
|
||||
|
||||
const u8 uuid_index[16] = {};
|
||||
|
@ -25,8 +25,11 @@ drivers/usb/core/config.c
|
||||
drivers/usb/core/driver.c
|
||||
drivers/usb/core/generic.c
|
||||
drivers/usb/core/hub.c
|
||||
drivers/usb/core/message.c
|
||||
drivers/usb/core/quirks.c
|
||||
drivers/usb/core/urb.c
|
||||
drivers/usb/core/usb.c
|
||||
fs/nls/nls_base.c
|
||||
kernel/kthread.c
|
||||
kernel/locking/mutex.c
|
||||
kernel/locking/osq_lock.c
|
||||
|
@ -8,11 +8,11 @@ SRC_C += dummies.c \
|
||||
lx_emul.c \
|
||||
lx_user.c
|
||||
|
||||
SRC_C += lx_emul/shadow/drivers/input/evdev.c \
|
||||
lx_emul/shadow/drivers/input/input-leds.c \
|
||||
lx_emul/virt/shadow/drivers/usb/core/message.c \
|
||||
lx_emul/virt/shadow/drivers/usb/core/urb.c \
|
||||
lx_emul/virt/usb_client.c
|
||||
SRC_C += lx_emul/shadow/drivers/input/evdev.c
|
||||
SRC_C += lx_emul/shadow/drivers/input/input-leds.c
|
||||
SRC_C += lx_emul/virt/shadow/drivers/usb/core/buffer.c
|
||||
SRC_C += lx_emul/virt/shadow/drivers/usb/core/hcd.c
|
||||
SRC_C += lx_emul/virt/usb_client.c
|
||||
|
||||
SRC_CC = main.cc
|
||||
|
||||
|
@ -18,14 +18,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct task_struct;
|
||||
|
||||
int lx_user_main_task(void *);
|
||||
struct task_struct *lx_user_new_usb_task(int (*func)(void*), void *args);
|
||||
void lx_user_destroy_usb_task(struct task_struct*);
|
||||
|
||||
void lx_led_state_update(bool capslock, bool numlock, bool scrlock);
|
||||
|
||||
void lx_emul_led_state_update(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
@ -157,42 +157,6 @@ void usb_hcd_synchronize_unlinks(struct usb_device * udev)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
struct urb * usb_get_from_anchor(struct usb_anchor * anchor)
|
||||
{
|
||||
lx_emul_trace(__func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
extern char * usb_cache_string(struct usb_device * udev,int index);
|
||||
char * usb_cache_string(struct usb_device * udev,int index)
|
||||
{
|
||||
lx_emul_trace(__func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void usb_kill_urb(struct urb * urb)
|
||||
{
|
||||
lx_emul_trace(__func__);
|
||||
}
|
||||
|
||||
|
||||
int usb_unlink_urb(struct urb * urb)
|
||||
{
|
||||
lx_emul_trace(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void usb_poison_urb(struct urb * urb)
|
||||
{
|
||||
lx_emul_trace(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
struct usb_hcd * usb_get_hcd(struct usb_hcd * hcd)
|
||||
@ -484,15 +448,51 @@ void usb_remove_ep_devs(struct usb_host_endpoint * endpoint)
|
||||
}
|
||||
|
||||
|
||||
extern void usb_disable_interface(struct usb_device * dev,struct usb_interface * intf,bool reset_hardware);
|
||||
void usb_disable_interface(struct usb_device * dev,struct usb_interface * intf,bool reset_hardware)
|
||||
{
|
||||
lx_emul_trace(__func__);
|
||||
}
|
||||
|
||||
|
||||
extern void netdev_unregister_kobject(struct net_device * ndev);
|
||||
void netdev_unregister_kobject(struct net_device * ndev)
|
||||
{
|
||||
lx_emul_trace(__func__);
|
||||
}
|
||||
|
||||
|
||||
void usb_hcd_flush_endpoint(struct usb_device *udev,
|
||||
struct usb_host_endpoint *ep)
|
||||
{
|
||||
lx_emul_trace(__func__);
|
||||
}
|
||||
|
||||
|
||||
void usb_hcd_disable_endpoint(struct usb_device *udev,
|
||||
struct usb_host_endpoint *ep)
|
||||
{
|
||||
lx_emul_trace(__func__);
|
||||
}
|
||||
|
||||
|
||||
void usb_hcd_reset_endpoint(struct usb_device *udev,
|
||||
struct usb_host_endpoint *ep)
|
||||
{
|
||||
lx_emul_trace(__func__);
|
||||
}
|
||||
|
||||
const struct attribute_group *usb_interface_groups[] = { NULL };
|
||||
|
||||
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
int usb_hcd_alloc_bandwidth(struct usb_device * udev,struct usb_host_config * new_config,struct usb_host_interface * cur_alt,struct usb_host_interface * new_alt)
|
||||
{
|
||||
lx_emul_trace(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#if defined(CONFIG_OF)
|
||||
#include <linux/usb/of.h>
|
||||
|
||||
bool usb_of_has_combined_node(struct usb_device * udev)
|
||||
{
|
||||
lx_emul_trace(__func__);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
@ -17,11 +17,6 @@
|
||||
pteval_t __default_kernel_pte_mask __read_mostly = ~0;
|
||||
|
||||
|
||||
struct device_type usb_if_device_type = {
|
||||
.name = "usb_interface"
|
||||
};
|
||||
|
||||
|
||||
struct usb_driver usbfs_driver = {
|
||||
.name = "usbfs"
|
||||
};
|
||||
@ -147,349 +142,3 @@ int netdev_register_kobject(struct net_device * ndev)
|
||||
if (use_mac_address) eth_hw_addr_set(ndev, mac_address);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* core/message.c
|
||||
*/
|
||||
#include <linux/nls.h>
|
||||
#include <linux/usb/quirks.h>
|
||||
#include <linux/usb/cdc.h>
|
||||
#include <linux/ctype.h>
|
||||
|
||||
int cdc_parse_cdc_header(struct usb_cdc_parsed_header *hdr,
|
||||
struct usb_interface *intf,
|
||||
u8 *buffer,
|
||||
int buflen)
|
||||
{
|
||||
/* duplicates are ignored */
|
||||
struct usb_cdc_union_desc *union_header = NULL;
|
||||
|
||||
/* duplicates are not tolerated */
|
||||
struct usb_cdc_header_desc *header = NULL;
|
||||
struct usb_cdc_ether_desc *ether = NULL;
|
||||
struct usb_cdc_mdlm_detail_desc *detail = NULL;
|
||||
struct usb_cdc_mdlm_desc *desc = NULL;
|
||||
|
||||
unsigned int elength;
|
||||
int cnt = 0;
|
||||
|
||||
memset(hdr, 0x00, sizeof(struct usb_cdc_parsed_header));
|
||||
hdr->phonet_magic_present = false;
|
||||
while (buflen > 0) {
|
||||
elength = buffer[0];
|
||||
if (!elength) {
|
||||
dev_err(&intf->dev, "skipping garbage byte\n");
|
||||
elength = 1;
|
||||
goto next_desc;
|
||||
}
|
||||
if ((buflen < elength) || (elength < 3)) {
|
||||
dev_err(&intf->dev, "invalid descriptor buffer length\n");
|
||||
break;
|
||||
}
|
||||
if (buffer[1] != USB_DT_CS_INTERFACE) {
|
||||
dev_err(&intf->dev, "skipping garbage\n");
|
||||
goto next_desc;
|
||||
}
|
||||
|
||||
switch (buffer[2]) {
|
||||
case USB_CDC_UNION_TYPE: /* we've found it */
|
||||
if (elength < sizeof(struct usb_cdc_union_desc))
|
||||
goto next_desc;
|
||||
if (union_header) {
|
||||
dev_err(&intf->dev, "More than one union descriptor, skipping ...\n");
|
||||
goto next_desc;
|
||||
}
|
||||
union_header = (struct usb_cdc_union_desc *)buffer;
|
||||
break;
|
||||
case USB_CDC_COUNTRY_TYPE:
|
||||
if (elength < sizeof(struct usb_cdc_country_functional_desc))
|
||||
goto next_desc;
|
||||
hdr->usb_cdc_country_functional_desc =
|
||||
(struct usb_cdc_country_functional_desc *)buffer;
|
||||
break;
|
||||
case USB_CDC_HEADER_TYPE:
|
||||
if (elength != sizeof(struct usb_cdc_header_desc))
|
||||
goto next_desc;
|
||||
if (header)
|
||||
return -EINVAL;
|
||||
header = (struct usb_cdc_header_desc *)buffer;
|
||||
break;
|
||||
case USB_CDC_ACM_TYPE:
|
||||
if (elength < sizeof(struct usb_cdc_acm_descriptor))
|
||||
goto next_desc;
|
||||
hdr->usb_cdc_acm_descriptor =
|
||||
(struct usb_cdc_acm_descriptor *)buffer;
|
||||
break;
|
||||
case USB_CDC_ETHERNET_TYPE:
|
||||
if (elength != sizeof(struct usb_cdc_ether_desc))
|
||||
goto next_desc;
|
||||
if (ether)
|
||||
return -EINVAL;
|
||||
ether = (struct usb_cdc_ether_desc *)buffer;
|
||||
break;
|
||||
case USB_CDC_CALL_MANAGEMENT_TYPE:
|
||||
if (elength < sizeof(struct usb_cdc_call_mgmt_descriptor))
|
||||
goto next_desc;
|
||||
hdr->usb_cdc_call_mgmt_descriptor =
|
||||
(struct usb_cdc_call_mgmt_descriptor *)buffer;
|
||||
break;
|
||||
case USB_CDC_DMM_TYPE:
|
||||
if (elength < sizeof(struct usb_cdc_dmm_desc))
|
||||
goto next_desc;
|
||||
hdr->usb_cdc_dmm_desc =
|
||||
(struct usb_cdc_dmm_desc *)buffer;
|
||||
break;
|
||||
case USB_CDC_MDLM_TYPE:
|
||||
if (elength < sizeof(struct usb_cdc_mdlm_desc))
|
||||
goto next_desc;
|
||||
if (desc)
|
||||
return -EINVAL;
|
||||
desc = (struct usb_cdc_mdlm_desc *)buffer;
|
||||
break;
|
||||
case USB_CDC_MDLM_DETAIL_TYPE:
|
||||
if (elength < sizeof(struct usb_cdc_mdlm_detail_desc))
|
||||
goto next_desc;
|
||||
if (detail)
|
||||
return -EINVAL;
|
||||
detail = (struct usb_cdc_mdlm_detail_desc *)buffer;
|
||||
break;
|
||||
case USB_CDC_NCM_TYPE:
|
||||
if (elength < sizeof(struct usb_cdc_ncm_desc))
|
||||
goto next_desc;
|
||||
hdr->usb_cdc_ncm_desc = (struct usb_cdc_ncm_desc *)buffer;
|
||||
break;
|
||||
case USB_CDC_MBIM_TYPE:
|
||||
if (elength < sizeof(struct usb_cdc_mbim_desc))
|
||||
goto next_desc;
|
||||
|
||||
hdr->usb_cdc_mbim_desc = (struct usb_cdc_mbim_desc *)buffer;
|
||||
break;
|
||||
case USB_CDC_MBIM_EXTENDED_TYPE:
|
||||
if (elength < sizeof(struct usb_cdc_mbim_extended_desc))
|
||||
break;
|
||||
hdr->usb_cdc_mbim_extended_desc =
|
||||
(struct usb_cdc_mbim_extended_desc *)buffer;
|
||||
break;
|
||||
case CDC_PHONET_MAGIC_NUMBER:
|
||||
hdr->phonet_magic_present = true;
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* there are LOTS more CDC descriptors that
|
||||
* could legitimately be found here.
|
||||
*/
|
||||
dev_dbg(&intf->dev, "Ignoring descriptor: type %02x, length %ud\n",
|
||||
buffer[2], elength);
|
||||
goto next_desc;
|
||||
}
|
||||
cnt++;
|
||||
next_desc:
|
||||
buflen -= elength;
|
||||
buffer += elength;
|
||||
}
|
||||
hdr->usb_cdc_union_desc = union_header;
|
||||
hdr->usb_cdc_header_desc = header;
|
||||
hdr->usb_cdc_mdlm_detail_desc = detail;
|
||||
hdr->usb_cdc_mdlm_desc = desc;
|
||||
hdr->usb_cdc_ether_desc = ether;
|
||||
return cnt;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* usb_get_string - gets a string descriptor
|
||||
* @dev: the device whose string descriptor is being retrieved
|
||||
* @langid: code for language chosen (from string descriptor zero)
|
||||
* @index: the number of the descriptor
|
||||
* @buf: where to put the string
|
||||
* @size: how big is "buf"?
|
||||
*
|
||||
* Context: task context, might sleep.
|
||||
*
|
||||
* Retrieves a string, encoded using UTF-16LE (Unicode, 16 bits per character,
|
||||
* in little-endian byte order).
|
||||
* The usb_string() function will often be a convenient way to turn
|
||||
* these strings into kernel-printable form.
|
||||
*
|
||||
* Strings may be referenced in device, configuration, interface, or other
|
||||
* descriptors, and could also be used in vendor-specific ways.
|
||||
*
|
||||
* This call is synchronous, and may not be used in an interrupt context.
|
||||
*
|
||||
* Return: The number of bytes received on success, or else the status code
|
||||
* returned by the underlying usb_control_msg() call.
|
||||
*/
|
||||
static int usb_get_string(struct usb_device *dev, unsigned short langid,
|
||||
unsigned char index, void *buf, int size)
|
||||
{
|
||||
int i;
|
||||
int result;
|
||||
|
||||
if (size <= 0) /* No point in asking for no data */
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < 3; ++i) {
|
||||
/* retry on length 0 or stall; some devices are flakey */
|
||||
result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
|
||||
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
|
||||
(USB_DT_STRING << 8) + index, langid, buf, size,
|
||||
USB_CTRL_GET_TIMEOUT);
|
||||
if (result == 0 || result == -EPIPE)
|
||||
continue;
|
||||
if (result > 1 && ((u8 *) buf)[1] != USB_DT_STRING) {
|
||||
result = -ENODATA;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void usb_try_string_workarounds(unsigned char *buf, int *length)
|
||||
{
|
||||
int newlength, oldlength = *length;
|
||||
|
||||
for (newlength = 2; newlength + 1 < oldlength; newlength += 2)
|
||||
if (!isprint(buf[newlength]) || buf[newlength + 1])
|
||||
break;
|
||||
|
||||
if (newlength > 2) {
|
||||
buf[0] = newlength;
|
||||
*length = newlength;
|
||||
}
|
||||
}
|
||||
|
||||
static int usb_string_sub(struct usb_device *dev, unsigned int langid,
|
||||
unsigned int index, unsigned char *buf)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* Try to read the string descriptor by asking for the maximum
|
||||
* possible number of bytes */
|
||||
if (dev->quirks & USB_QUIRK_STRING_FETCH_255)
|
||||
rc = -EIO;
|
||||
else
|
||||
rc = usb_get_string(dev, langid, index, buf, 255);
|
||||
|
||||
/* If that failed try to read the descriptor length, then
|
||||
* ask for just that many bytes */
|
||||
if (rc < 2) {
|
||||
rc = usb_get_string(dev, langid, index, buf, 2);
|
||||
if (rc == 2)
|
||||
rc = usb_get_string(dev, langid, index, buf, buf[0]);
|
||||
}
|
||||
|
||||
if (rc >= 2) {
|
||||
if (!buf[0] && !buf[1])
|
||||
usb_try_string_workarounds(buf, &rc);
|
||||
|
||||
/* There might be extra junk at the end of the descriptor */
|
||||
if (buf[0] < rc)
|
||||
rc = buf[0];
|
||||
|
||||
rc = rc - (rc & 1); /* force a multiple of two */
|
||||
}
|
||||
|
||||
if (rc < 2)
|
||||
rc = (rc < 0 ? rc : -EINVAL);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int usb_get_langid(struct usb_device *dev, unsigned char *tbuf)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (dev->have_langid)
|
||||
return 0;
|
||||
|
||||
if (dev->string_langid < 0)
|
||||
return -EPIPE;
|
||||
|
||||
err = usb_string_sub(dev, 0, 0, tbuf);
|
||||
|
||||
/* If the string was reported but is malformed, default to english
|
||||
* (0x0409) */
|
||||
if (err == -ENODATA || (err > 0 && err < 4)) {
|
||||
dev->string_langid = 0x0409;
|
||||
dev->have_langid = 1;
|
||||
dev_err(&dev->dev,
|
||||
"language id specifier not provided by device, defaulting to English\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* In case of all other errors, we assume the device is not able to
|
||||
* deal with strings at all. Set string_langid to -1 in order to
|
||||
* prevent any string to be retrieved from the device */
|
||||
if (err < 0) {
|
||||
dev_info(&dev->dev, "string descriptor 0 read error: %d\n",
|
||||
err);
|
||||
dev->string_langid = -1;
|
||||
return -EPIPE;
|
||||
}
|
||||
|
||||
/* always use the first langid listed */
|
||||
dev->string_langid = tbuf[2] | (tbuf[3] << 8);
|
||||
dev->have_langid = 1;
|
||||
dev_dbg(&dev->dev, "default language 0x%04x\n",
|
||||
dev->string_langid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_string - returns UTF-8 version of a string descriptor
|
||||
* @dev: the device whose string descriptor is being retrieved
|
||||
* @index: the number of the descriptor
|
||||
* @buf: where to put the string
|
||||
* @size: how big is "buf"?
|
||||
*
|
||||
* Context: task context, might sleep.
|
||||
*
|
||||
* This converts the UTF-16LE encoded strings returned by devices, from
|
||||
* usb_get_string_descriptor(), to null-terminated UTF-8 encoded ones
|
||||
* that are more usable in most kernel contexts. Note that this function
|
||||
* chooses strings in the first language supported by the device.
|
||||
*
|
||||
* This call is synchronous, and may not be used in an interrupt context.
|
||||
*
|
||||
* Return: length of the string (>= 0) or usb_control_msg status (< 0).
|
||||
*/
|
||||
int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
|
||||
{
|
||||
unsigned char *tbuf;
|
||||
int err;
|
||||
|
||||
if (dev->state == USB_STATE_SUSPENDED)
|
||||
return -EHOSTUNREACH;
|
||||
if (size <= 0 || !buf)
|
||||
return -EINVAL;
|
||||
buf[0] = 0;
|
||||
if (index <= 0 || index >= 256)
|
||||
return -EINVAL;
|
||||
tbuf = kmalloc(256, GFP_NOIO);
|
||||
if (!tbuf)
|
||||
return -ENOMEM;
|
||||
|
||||
err = usb_get_langid(dev, tbuf);
|
||||
if (err < 0)
|
||||
goto errout;
|
||||
|
||||
err = usb_string_sub(dev, dev->string_langid, index, tbuf);
|
||||
if (err < 0)
|
||||
goto errout;
|
||||
|
||||
size--; /* leave room for trailing NULL char in output buffer */
|
||||
err = utf16s_to_utf8s((wchar_t *) &tbuf[2], (err - 2) / 2,
|
||||
UTF16_LITTLE_ENDIAN, buf, size);
|
||||
buf[err] = 0;
|
||||
|
||||
if (tbuf[1] != USB_DT_STRING)
|
||||
dev_dbg(&dev->dev,
|
||||
"wrong descriptor type %02x for string %d (\"%s\")\n",
|
||||
tbuf[1], index, buf);
|
||||
|
||||
errout:
|
||||
kfree(tbuf);
|
||||
return err;
|
||||
}
|
||||
|
@ -165,7 +165,7 @@ static genode_uplink_rx_result_t uplink_rx_one_packet(struct genode_uplink_rx_co
|
||||
}
|
||||
|
||||
|
||||
static int user_task_function(void *arg)
|
||||
static int network_loop(void *arg)
|
||||
{
|
||||
for (;;) {
|
||||
|
||||
@ -206,18 +206,23 @@ static int user_task_function(void *arg)
|
||||
}
|
||||
|
||||
|
||||
struct task_struct *user_task_struct_ptr; /* used by 'Device' for lx_emul_task_unblock */
|
||||
static struct task_struct *net_task;
|
||||
|
||||
void lx_user_init(void)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
lx_user_main_task(NULL);
|
||||
lx_emul_usb_client_init();
|
||||
|
||||
pid = kernel_thread(user_task_function, NULL, CLONE_FS | CLONE_FILES);
|
||||
pid = kernel_thread(network_loop, NULL, CLONE_FS | CLONE_FILES);
|
||||
net_task = find_task_by_pid_ns(pid, NULL);
|
||||
}
|
||||
|
||||
user_task_struct_ptr = find_task_by_pid_ns(pid, NULL);
|
||||
|
||||
void lx_user_handle_io(void)
|
||||
{
|
||||
lx_emul_usb_client_ticker();
|
||||
if (net_task) lx_emul_task_unblock(net_task);
|
||||
}
|
||||
|
||||
|
||||
@ -232,8 +237,7 @@ bool force_uplink_destroy = false;
|
||||
void rtmsg_ifinfo(int type, struct net_device * dev, unsigned int change, gfp_t flags)
|
||||
{
|
||||
/* trigger handle_create_uplink / handle_destroy_uplink */
|
||||
if (user_task_struct_ptr)
|
||||
lx_emul_task_unblock(user_task_struct_ptr);
|
||||
if (net_task) lx_emul_task_unblock(net_task);
|
||||
|
||||
if (force_uplink_destroy) {
|
||||
struct genode_uplink *uplink = dev_genode_uplink(dev);
|
||||
|
@ -21,7 +21,7 @@
|
||||
#include <nic_session/nic_session.h>
|
||||
|
||||
#include <lx_kit/env.h>
|
||||
#include <lx_emul/task.h>
|
||||
#include <lx_user/io.h>
|
||||
#include <lx_emul/init.h>
|
||||
|
||||
/* C-interface */
|
||||
@ -29,106 +29,55 @@
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
extern task_struct *user_task_struct_ptr;
|
||||
extern bool force_uplink_destroy;
|
||||
extern bool use_mac_address;
|
||||
extern unsigned char mac_address[6];
|
||||
|
||||
struct Device
|
||||
struct Main
|
||||
{
|
||||
Env &env;
|
||||
Env &env;
|
||||
|
||||
Attached_rom_dataspace config_rom { env, "config" };
|
||||
|
||||
unsigned long usb_config { 0 };
|
||||
|
||||
/*
|
||||
* Dedicated allocator per device to notice dangling
|
||||
* allocations on device destruction.
|
||||
*/
|
||||
Allocator_avl alloc { &Lx_kit::env().heap };
|
||||
Signal_handler<Main> signal_handler { env.ep(), *this,
|
||||
&Main::handle_signal };
|
||||
Signal_handler<Main> usb_rom_handler { env.ep(), *this,
|
||||
&Main::handle_usb_rom };
|
||||
Signal_handler<Main> config_handler { env.ep(), *this,
|
||||
&Main::handle_config };
|
||||
|
||||
task_struct *state_task { lx_user_new_usb_task(state_task_entry, this) };
|
||||
task_struct *urb_task { lx_user_new_usb_task(urb_task_entry, this) };
|
||||
|
||||
Signal_handler<Device> task_state_handler { env.ep(), *this, &Device::handle_task_state };
|
||||
Signal_handler<Device> urb_handler { env.ep(), *this, &Device::handle_urb };
|
||||
|
||||
genode_usb_client_handle_t usb_handle {
|
||||
genode_usb_client_create(genode_env_ptr(env),
|
||||
genode_allocator_ptr(Lx_kit::env().heap),
|
||||
genode_range_allocator_ptr(alloc),
|
||||
"",
|
||||
genode_signal_handler_ptr(task_state_handler)) };
|
||||
|
||||
Signal_handler<Device> nic_handler { env.ep(), *this, &Device::handle_nic };
|
||||
Signal_handler<Device> config_handler { env.ep(), *this, &Device::handle_config };
|
||||
|
||||
bool registered { false };
|
||||
|
||||
void *lx_device_handle { nullptr };
|
||||
|
||||
Device(Env &env)
|
||||
Main(Env &env)
|
||||
:
|
||||
env(env)
|
||||
{
|
||||
genode_usb_client_sigh_ack_avail(usb_handle,
|
||||
genode_signal_handler_ptr(urb_handler));
|
||||
Lx_kit::initialize(env, signal_handler);
|
||||
|
||||
Genode_c_api::initialize_usb_client(env, Lx_kit::env().heap,
|
||||
signal_handler, usb_rom_handler);
|
||||
|
||||
genode_mac_address_reporter_init(env, Lx_kit::env().heap);
|
||||
|
||||
genode_uplink_init(genode_env_ptr(env),
|
||||
genode_allocator_ptr(Lx_kit::env().heap),
|
||||
genode_signal_handler_ptr(nic_handler));
|
||||
genode_signal_handler_ptr(signal_handler));
|
||||
|
||||
config_rom.sigh(config_handler);
|
||||
handle_config();
|
||||
|
||||
lx_emul_start_kernel(nullptr);
|
||||
}
|
||||
|
||||
/* non-copyable */
|
||||
Device(const Device&) = delete;
|
||||
Device & operator=(const Device&) = delete;
|
||||
|
||||
void register_device()
|
||||
void handle_signal()
|
||||
{
|
||||
registered = true;
|
||||
lx_device_handle = lx_emul_usb_client_register_device(usb_handle, "usb_nic");
|
||||
if (!lx_device_handle) {
|
||||
registered = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (usb_config != 0)
|
||||
lx_emul_usb_client_set_configuration(usb_handle, lx_device_handle, usb_config);
|
||||
|
||||
}
|
||||
|
||||
void unregister_device()
|
||||
{
|
||||
force_uplink_destroy = true;
|
||||
lx_emul_usb_client_unregister_device(usb_handle, lx_device_handle);
|
||||
registered = false;
|
||||
force_uplink_destroy = false;
|
||||
}
|
||||
|
||||
void handle_task_state()
|
||||
{
|
||||
lx_emul_task_unblock(state_task);
|
||||
Lx_kit::env().scheduler.execute();
|
||||
}
|
||||
|
||||
void handle_urb()
|
||||
{
|
||||
lx_emul_task_unblock(urb_task);
|
||||
lx_user_handle_io();
|
||||
Lx_kit::env().scheduler.execute();
|
||||
genode_uplink_notify_peers();
|
||||
}
|
||||
|
||||
void handle_nic()
|
||||
void handle_usb_rom()
|
||||
{
|
||||
if (!user_task_struct_ptr)
|
||||
return;
|
||||
|
||||
lx_emul_task_unblock(user_task_struct_ptr);
|
||||
lx_emul_usb_client_rom_update();
|
||||
Lx_kit::env().scheduler.execute();
|
||||
}
|
||||
|
||||
@ -138,15 +87,11 @@ struct Device
|
||||
genode_mac_address_reporter_config(config_rom.xml());
|
||||
|
||||
/* read USB configuration setting */
|
||||
unsigned long config = config_rom.xml().attribute_value("configuration", 0ul);
|
||||
if (registered && config != 0 && config != usb_config)
|
||||
lx_emul_usb_client_set_configuration(usb_handle, lx_device_handle, config);
|
||||
|
||||
usb_config = config;
|
||||
usb_config = config_rom.xml().attribute_value("configuration", 0ul);
|
||||
|
||||
/* retrieve possible MAC */
|
||||
Nic::Mac_address mac;
|
||||
try {
|
||||
Nic::Mac_address mac;
|
||||
Xml_node::Attribute mac_node = config_rom.xml().attribute("mac");
|
||||
mac_node.value(mac);
|
||||
mac.copy(mac_address);
|
||||
@ -156,79 +101,7 @@ struct Device
|
||||
use_mac_address = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**********
|
||||
** Task **
|
||||
**********/
|
||||
|
||||
static int state_task_entry(void *arg)
|
||||
{
|
||||
Device &device = *reinterpret_cast<Device *>(arg);
|
||||
|
||||
while (true) {
|
||||
if (genode_usb_client_plugged(device.usb_handle) && !device.registered)
|
||||
device.register_device();
|
||||
|
||||
if (!genode_usb_client_plugged(device.usb_handle) && device.registered)
|
||||
device.unregister_device();
|
||||
lx_emul_task_schedule(true);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int urb_task_entry(void *arg)
|
||||
{
|
||||
Device &device = *reinterpret_cast<Device *>(arg);
|
||||
|
||||
while (true) {
|
||||
if (device.registered) {
|
||||
genode_usb_client_execute_completions(device.usb_handle);
|
||||
}
|
||||
|
||||
lx_emul_task_schedule(true);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct Main
|
||||
{
|
||||
Env &env;
|
||||
|
||||
Signal_handler<Main> signal_handler { env.ep(), *this, &Main::handle_signal };
|
||||
|
||||
Main(Env &env) : env(env) { }
|
||||
|
||||
void handle_signal()
|
||||
{
|
||||
Lx_kit::env().scheduler.execute();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void Component::construct(Env & env)
|
||||
{
|
||||
static Main main { env };
|
||||
Lx_kit::initialize(env, main.signal_handler);
|
||||
|
||||
env.exec_static_constructors();
|
||||
|
||||
lx_emul_start_kernel(nullptr);
|
||||
}
|
||||
|
||||
|
||||
/**********
|
||||
** Task **
|
||||
**********/
|
||||
|
||||
int lx_user_main_task(void *)
|
||||
{
|
||||
/* one device only */
|
||||
static Device dev(Lx_kit::env().env);
|
||||
|
||||
return 0;
|
||||
}
|
||||
void Component::construct(Env & env) { static Main main { env }; }
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* \brief Dummy definitions of Linux Kernel functions
|
||||
* \author Automatically generated file - do no edit
|
||||
* \date 2024-01-23
|
||||
* \date 2024-02-22
|
||||
*/
|
||||
|
||||
#include <lx_emul.h>
|
||||
@ -651,6 +651,14 @@ loff_t noop_llseek(struct file * file,loff_t offset,int whence)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/of.h>
|
||||
|
||||
bool of_device_is_available(const struct device_node * device)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/of_device.h>
|
||||
|
||||
void of_device_uevent(struct device * dev,struct kobj_uevent_env * env)
|
||||
@ -888,14 +896,6 @@ void rtmsg_ifinfo_send(struct sk_buff * skb,struct net_device * dev,gfp_t flags)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/scatterlist.h>
|
||||
|
||||
void sg_init_table(struct scatterlist * sgl,unsigned int nents)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <net/sock.h>
|
||||
|
||||
void sk_error_report(struct sock * sk)
|
||||
@ -954,14 +954,6 @@ void tick_broadcast(const struct cpumask * mask)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
int usb_clear_halt(struct usb_device * dev,int pipe)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
extern void usb_devio_cleanup(void);
|
||||
void usb_devio_cleanup(void)
|
||||
{
|
||||
@ -969,13 +961,6 @@ void usb_devio_cleanup(void)
|
||||
}
|
||||
|
||||
|
||||
extern void usb_disable_endpoint(struct usb_device * dev,unsigned int epaddr,bool reset_hardware);
|
||||
void usb_disable_endpoint(struct usb_device * dev,unsigned int epaddr,bool reset_hardware)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
int usb_free_streams(struct usb_interface * interface,struct usb_host_endpoint ** eps,unsigned int num_eps,gfp_t mem_flags)
|
||||
@ -984,29 +969,6 @@ int usb_free_streams(struct usb_interface * interface,struct usb_host_endpoint *
|
||||
}
|
||||
|
||||
|
||||
extern int usb_get_device_descriptor(struct usb_device * dev,unsigned int size);
|
||||
int usb_get_device_descriptor(struct usb_device * dev,unsigned int size)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
int usb_get_status(struct usb_device * dev,int recip,int type,int target,void * data)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
int usb_hcd_alloc_bandwidth(struct usb_device * udev,struct usb_host_config * new_config,struct usb_host_interface * cur_alt,struct usb_host_interface * new_alt)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
int usb_hcd_find_raw_port_number(struct usb_hcd * hcd,int port1)
|
||||
@ -1044,8 +1006,9 @@ struct device_node * usb_of_get_device_node(struct usb_device * hub,int port1)
|
||||
}
|
||||
|
||||
|
||||
extern int usb_set_isoch_delay(struct usb_device * dev);
|
||||
int usb_set_isoch_delay(struct usb_device * dev)
|
||||
#include <linux/usb/of.h>
|
||||
|
||||
struct device_node * usb_of_get_interface_node(struct usb_device * udev,u8 config,u8 ifnum)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
@ -1059,14 +1022,6 @@ const char * usb_speed_string(enum usb_device_speed speed)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
void usb_unpoison_urb(struct urb * urb)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/uuid.h>
|
||||
|
||||
const u8 uuid_index[16] = {};
|
||||
|
@ -28,7 +28,9 @@ drivers/usb/core/config.c
|
||||
drivers/usb/core/driver.c
|
||||
drivers/usb/core/generic.c
|
||||
drivers/usb/core/hub.c
|
||||
drivers/usb/core/message.c
|
||||
drivers/usb/core/quirks.c
|
||||
drivers/usb/core/urb.c
|
||||
drivers/usb/core/usb.c
|
||||
fs/nls/nls_base.c
|
||||
kernel/kthread.c
|
||||
@ -71,6 +73,7 @@ lib/kstrtox.c
|
||||
lib/radix-tree.c
|
||||
lib/rbtree.c
|
||||
lib/rhashtable.c
|
||||
lib/scatterlist.c
|
||||
lib/siphash.c
|
||||
lib/string.c
|
||||
lib/string_helpers.c
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* \brief Dummy definitions of Linux Kernel functions
|
||||
* \author Automatically generated file - do no edit
|
||||
* \date 2024-02-01
|
||||
* \date 2024-02-22
|
||||
*/
|
||||
|
||||
#include <lx_emul.h>
|
||||
@ -474,6 +474,14 @@ loff_t noop_llseek(struct file * file,loff_t offset,int whence)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/of.h>
|
||||
|
||||
bool of_device_is_available(const struct device_node * device)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/of_device.h>
|
||||
|
||||
void of_device_uevent(struct device * dev,struct kobj_uevent_env * env)
|
||||
@ -682,14 +690,6 @@ void rtmsg_ifinfo_send(struct sk_buff * skb,struct net_device * dev,gfp_t flags)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/scatterlist.h>
|
||||
|
||||
void sg_init_table(struct scatterlist * sgl,unsigned int nents)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <net/sock.h>
|
||||
|
||||
void sk_error_report(struct sock * sk)
|
||||
@ -732,14 +732,6 @@ struct sk_buff * tcp_get_timestamping_opt_stats(const struct sock * sk,const str
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
int usb_clear_halt(struct usb_device * dev,int pipe)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
extern void usb_devio_cleanup(void);
|
||||
void usb_devio_cleanup(void)
|
||||
{
|
||||
@ -747,13 +739,6 @@ void usb_devio_cleanup(void)
|
||||
}
|
||||
|
||||
|
||||
extern void usb_disable_endpoint(struct usb_device * dev,unsigned int epaddr,bool reset_hardware);
|
||||
void usb_disable_endpoint(struct usb_device * dev,unsigned int epaddr,bool reset_hardware)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
int usb_free_streams(struct usb_interface * interface,struct usb_host_endpoint ** eps,unsigned int num_eps,gfp_t mem_flags)
|
||||
@ -762,29 +747,6 @@ int usb_free_streams(struct usb_interface * interface,struct usb_host_endpoint *
|
||||
}
|
||||
|
||||
|
||||
extern int usb_get_device_descriptor(struct usb_device * dev,unsigned int size);
|
||||
int usb_get_device_descriptor(struct usb_device * dev,unsigned int size)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
int usb_get_status(struct usb_device * dev,int recip,int type,int target,void * data)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
int usb_hcd_alloc_bandwidth(struct usb_device * udev,struct usb_host_config * new_config,struct usb_host_interface * cur_alt,struct usb_host_interface * new_alt)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
int usb_hcd_find_raw_port_number(struct usb_hcd * hcd,int port1)
|
||||
@ -822,8 +784,9 @@ struct device_node * usb_of_get_device_node(struct usb_device * hub,int port1)
|
||||
}
|
||||
|
||||
|
||||
extern int usb_set_isoch_delay(struct usb_device * dev);
|
||||
int usb_set_isoch_delay(struct usb_device * dev)
|
||||
#include <linux/usb/of.h>
|
||||
|
||||
struct device_node * usb_of_get_interface_node(struct usb_device * udev,u8 config,u8 ifnum)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
@ -837,14 +800,6 @@ const char * usb_speed_string(enum usb_device_speed speed)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
void usb_unpoison_urb(struct urb * urb)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/uuid.h>
|
||||
|
||||
const u8 uuid_index[16] = {};
|
||||
|
@ -27,7 +27,9 @@ drivers/usb/core/config.c
|
||||
drivers/usb/core/driver.c
|
||||
drivers/usb/core/generic.c
|
||||
drivers/usb/core/hub.c
|
||||
drivers/usb/core/message.c
|
||||
drivers/usb/core/quirks.c
|
||||
drivers/usb/core/urb.c
|
||||
drivers/usb/core/usb.c
|
||||
fs/nls/nls_base.c
|
||||
kernel/kthread.c
|
||||
@ -69,6 +71,7 @@ lib/radix-tree.c
|
||||
lib/rhashtable.c
|
||||
lib/rbtree.c
|
||||
lib/xarray.c
|
||||
lib/scatterlist.c
|
||||
lib/siphash.c
|
||||
lib/string.c
|
||||
lib/string_helpers.c
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* \brief Dummy definitions of Linux Kernel functions
|
||||
* \author Automatically generated file - do no edit
|
||||
* \date 2024-01-23
|
||||
* \date 2024-02-22
|
||||
*/
|
||||
|
||||
#include <lx_emul.h>
|
||||
@ -569,6 +569,14 @@ loff_t noop_llseek(struct file * file,loff_t offset,int whence)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/of.h>
|
||||
|
||||
bool of_device_is_available(const struct device_node * device)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/of_device.h>
|
||||
|
||||
void of_device_uevent(struct device * dev,struct kobj_uevent_env * env)
|
||||
@ -782,14 +790,6 @@ void rtmsg_ifinfo_send(struct sk_buff * skb,struct net_device * dev,gfp_t flags)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/scatterlist.h>
|
||||
|
||||
void sg_init_table(struct scatterlist * sgl,unsigned int nents)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <net/sock.h>
|
||||
|
||||
void sk_error_report(struct sock * sk)
|
||||
@ -848,14 +848,6 @@ void tick_broadcast(const struct cpumask * mask)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
int usb_clear_halt(struct usb_device * dev,int pipe)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
extern void usb_devio_cleanup(void);
|
||||
void usb_devio_cleanup(void)
|
||||
{
|
||||
@ -863,13 +855,6 @@ void usb_devio_cleanup(void)
|
||||
}
|
||||
|
||||
|
||||
extern void usb_disable_endpoint(struct usb_device * dev,unsigned int epaddr,bool reset_hardware);
|
||||
void usb_disable_endpoint(struct usb_device * dev,unsigned int epaddr,bool reset_hardware)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
int usb_free_streams(struct usb_interface * interface,struct usb_host_endpoint ** eps,unsigned int num_eps,gfp_t mem_flags)
|
||||
@ -878,29 +863,6 @@ int usb_free_streams(struct usb_interface * interface,struct usb_host_endpoint *
|
||||
}
|
||||
|
||||
|
||||
extern int usb_get_device_descriptor(struct usb_device * dev,unsigned int size);
|
||||
int usb_get_device_descriptor(struct usb_device * dev,unsigned int size)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
int usb_get_status(struct usb_device * dev,int recip,int type,int target,void * data)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
int usb_hcd_alloc_bandwidth(struct usb_device * udev,struct usb_host_config * new_config,struct usb_host_interface * cur_alt,struct usb_host_interface * new_alt)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
int usb_hcd_find_raw_port_number(struct usb_hcd * hcd,int port1)
|
||||
@ -938,8 +900,9 @@ struct device_node * usb_of_get_device_node(struct usb_device * hub,int port1)
|
||||
}
|
||||
|
||||
|
||||
extern int usb_set_isoch_delay(struct usb_device * dev);
|
||||
int usb_set_isoch_delay(struct usb_device * dev)
|
||||
#include <linux/usb/of.h>
|
||||
|
||||
struct device_node * usb_of_get_interface_node(struct usb_device * udev,u8 config,u8 ifnum)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
@ -953,14 +916,6 @@ const char * usb_speed_string(enum usb_device_speed speed)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
void usb_unpoison_urb(struct urb * urb)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/uuid.h>
|
||||
|
||||
const u8 uuid_index[16] = {};
|
||||
|
@ -26,7 +26,9 @@ drivers/usb/core/config.c
|
||||
drivers/usb/core/driver.c
|
||||
drivers/usb/core/generic.c
|
||||
drivers/usb/core/hub.c
|
||||
drivers/usb/core/message.c
|
||||
drivers/usb/core/quirks.c
|
||||
drivers/usb/core/urb.c
|
||||
drivers/usb/core/usb.c
|
||||
fs/nls/nls_base.c
|
||||
kernel/kthread.c
|
||||
@ -70,6 +72,7 @@ lib/radix-tree.c
|
||||
lib/rhashtable.c
|
||||
lib/rbtree.c
|
||||
lib/xarray.c
|
||||
lib/scatterlist.c
|
||||
lib/siphash.c
|
||||
lib/string.c
|
||||
lib/string_helpers.c
|
||||
|
@ -707,14 +707,6 @@ void rtmsg_ifinfo_send(struct sk_buff * skb,struct net_device * dev,gfp_t flags)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/scatterlist.h>
|
||||
|
||||
void sg_init_table(struct scatterlist * sgl,unsigned int nents)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <net/sock.h>
|
||||
|
||||
void sk_error_report(struct sock * sk)
|
||||
@ -773,14 +765,6 @@ struct sk_buff * tcp_get_timestamping_opt_stats(const struct sock * sk,const str
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
int usb_clear_halt(struct usb_device * dev,int pipe)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
extern void usb_devio_cleanup(void);
|
||||
void usb_devio_cleanup(void)
|
||||
{
|
||||
@ -788,13 +772,6 @@ void usb_devio_cleanup(void)
|
||||
}
|
||||
|
||||
|
||||
extern void usb_disable_endpoint(struct usb_device * dev,unsigned int epaddr,bool reset_hardware);
|
||||
void usb_disable_endpoint(struct usb_device * dev,unsigned int epaddr,bool reset_hardware)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
int usb_free_streams(struct usb_interface * interface,struct usb_host_endpoint ** eps,unsigned int num_eps,gfp_t mem_flags)
|
||||
@ -803,29 +780,6 @@ int usb_free_streams(struct usb_interface * interface,struct usb_host_endpoint *
|
||||
}
|
||||
|
||||
|
||||
extern int usb_get_device_descriptor(struct usb_device * dev,unsigned int size);
|
||||
int usb_get_device_descriptor(struct usb_device * dev,unsigned int size)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
int usb_get_status(struct usb_device * dev,int recip,int type,int target,void * data)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
int usb_hcd_alloc_bandwidth(struct usb_device * udev,struct usb_host_config * new_config,struct usb_host_interface * cur_alt,struct usb_host_interface * new_alt)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
int usb_hcd_find_raw_port_number(struct usb_hcd * hcd,int port1)
|
||||
@ -855,13 +809,6 @@ void usb_major_cleanup(void)
|
||||
}
|
||||
|
||||
|
||||
extern int usb_set_isoch_delay(struct usb_device * dev);
|
||||
int usb_set_isoch_delay(struct usb_device * dev)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb/ch9.h>
|
||||
|
||||
const char * usb_speed_string(enum usb_device_speed speed)
|
||||
@ -870,14 +817,6 @@ const char * usb_speed_string(enum usb_device_speed speed)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
void usb_unpoison_urb(struct urb * urb)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/uuid.h>
|
||||
|
||||
const u8 uuid_index[16] = {};
|
||||
|
@ -21,7 +21,9 @@ drivers/usb/core/config.c
|
||||
drivers/usb/core/driver.c
|
||||
drivers/usb/core/generic.c
|
||||
drivers/usb/core/hub.c
|
||||
drivers/usb/core/message.c
|
||||
drivers/usb/core/quirks.c
|
||||
drivers/usb/core/urb.c
|
||||
drivers/usb/core/usb.c
|
||||
fs/nls/nls_base.c
|
||||
kernel/kthread.c
|
||||
@ -63,6 +65,7 @@ lib/radix-tree.c
|
||||
lib/rhashtable.c
|
||||
lib/rbtree.c
|
||||
lib/xarray.c
|
||||
lib/scatterlist.c
|
||||
lib/siphash.c
|
||||
lib/string.c
|
||||
lib/string_helpers.c
|
||||
|
@ -680,14 +680,6 @@ void rtmsg_ifinfo_send(struct sk_buff * skb,struct net_device * dev,gfp_t flags)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/scatterlist.h>
|
||||
|
||||
void sg_init_table(struct scatterlist * sgl,unsigned int nents)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <net/sock.h>
|
||||
|
||||
void sk_error_report(struct sock * sk)
|
||||
@ -746,14 +738,6 @@ struct sk_buff * tcp_get_timestamping_opt_stats(const struct sock * sk,const str
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
int usb_clear_halt(struct usb_device * dev,int pipe)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
extern void usb_devio_cleanup(void);
|
||||
void usb_devio_cleanup(void)
|
||||
{
|
||||
@ -761,13 +745,6 @@ void usb_devio_cleanup(void)
|
||||
}
|
||||
|
||||
|
||||
extern void usb_disable_endpoint(struct usb_device * dev,unsigned int epaddr,bool reset_hardware);
|
||||
void usb_disable_endpoint(struct usb_device * dev,unsigned int epaddr,bool reset_hardware)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
int usb_free_streams(struct usb_interface * interface,struct usb_host_endpoint ** eps,unsigned int num_eps,gfp_t mem_flags)
|
||||
@ -776,29 +753,6 @@ int usb_free_streams(struct usb_interface * interface,struct usb_host_endpoint *
|
||||
}
|
||||
|
||||
|
||||
extern int usb_get_device_descriptor(struct usb_device * dev,unsigned int size);
|
||||
int usb_get_device_descriptor(struct usb_device * dev,unsigned int size)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
int usb_get_status(struct usb_device * dev,int recip,int type,int target,void * data)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
int usb_hcd_alloc_bandwidth(struct usb_device * udev,struct usb_host_config * new_config,struct usb_host_interface * cur_alt,struct usb_host_interface * new_alt)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
int usb_hcd_find_raw_port_number(struct usb_hcd * hcd,int port1)
|
||||
@ -828,13 +782,6 @@ void usb_major_cleanup(void)
|
||||
}
|
||||
|
||||
|
||||
extern int usb_set_isoch_delay(struct usb_device * dev);
|
||||
int usb_set_isoch_delay(struct usb_device * dev)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb/ch9.h>
|
||||
|
||||
const char * usb_speed_string(enum usb_device_speed speed)
|
||||
@ -843,14 +790,6 @@ const char * usb_speed_string(enum usb_device_speed speed)
|
||||
}
|
||||
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
void usb_unpoison_urb(struct urb * urb)
|
||||
{
|
||||
lx_emul_trace_and_stop(__func__);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/uuid.h>
|
||||
|
||||
const u8 uuid_index[16] = {};
|
||||
|
@ -21,7 +21,9 @@ drivers/usb/core/config.c
|
||||
drivers/usb/core/driver.c
|
||||
drivers/usb/core/generic.c
|
||||
drivers/usb/core/hub.c
|
||||
drivers/usb/core/message.c
|
||||
drivers/usb/core/quirks.c
|
||||
drivers/usb/core/urb.c
|
||||
drivers/usb/core/usb.c
|
||||
fs/nls/nls_base.c
|
||||
kernel/kthread.c
|
||||
@ -63,6 +65,7 @@ lib/radix-tree.c
|
||||
lib/rhashtable.c
|
||||
lib/rbtree.c
|
||||
lib/xarray.c
|
||||
lib/scatterlist.c
|
||||
lib/siphash.c
|
||||
lib/string.c
|
||||
lib/string_helpers.c
|
||||
|
@ -8,9 +8,9 @@ SRC_C += dummies.c \
|
||||
lx_emul.c \
|
||||
lx_user.c
|
||||
|
||||
SRC_C += lx_emul/virt/shadow/drivers/usb/core/message.c \
|
||||
lx_emul/virt/shadow/drivers/usb/core/urb.c \
|
||||
lx_emul/virt/usb_client.c
|
||||
SRC_C += lx_emul/virt/shadow/drivers/usb/core/buffer.c
|
||||
SRC_C += lx_emul/virt/shadow/drivers/usb/core/hcd.c
|
||||
SRC_C += lx_emul/virt/usb_client.c
|
||||
|
||||
SRC_CC = main.cc \
|
||||
wdm_terminal.cc
|
||||
|
@ -18,6 +18,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern void lx_emul_input_leds_init(void);
|
||||
extern void lx_emul_input_leds_update(bool capslock, bool numlock, bool scrolllock);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -14,11 +14,14 @@
|
||||
#ifndef _LX_EMUL__USB_H_
|
||||
#define _LX_EMUL__USB_H_
|
||||
|
||||
#include <genode_c_api/usb.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern struct genode_usb_rpc_callbacks lx_emul_usb_rpc_callbacks;
|
||||
extern void lx_emul_usb_release_device(genode_usb_bus_num_t bus,
|
||||
genode_usb_dev_num_t dev);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -4,9 +4,10 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void *lx_emul_usb_client_register_device(genode_usb_client_handle_t handle, char const *label);
|
||||
void lx_emul_usb_client_unregister_device(genode_usb_client_handle_t handle, void *data);
|
||||
int lx_emul_usb_client_set_configuration(genode_usb_client_handle_t, void *data, unsigned long config);
|
||||
int lx_emul_usb_client_set_configuration(genode_usb_client_dev_handle_t, void *data, unsigned long config);
|
||||
void lx_emul_usb_client_init(void);
|
||||
void lx_emul_usb_client_rom_update(void);
|
||||
void lx_emul_usb_client_ticker(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
@ -52,25 +52,49 @@ static void update_leds(struct led_handler *handler)
|
||||
}
|
||||
|
||||
|
||||
static int led_task_loop(void *arg)
|
||||
{
|
||||
for (;;) {
|
||||
|
||||
struct led_handler *handler;
|
||||
|
||||
list_for_each_entry(handler, &led_handlers, list) {
|
||||
update_leds(handler);
|
||||
}
|
||||
|
||||
if (led_update.state == BLOCKED)
|
||||
complete(&led_update.update);
|
||||
|
||||
led_update.state = NONE;
|
||||
|
||||
lx_emul_task_schedule(true);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct task_struct *led_task = NULL;
|
||||
|
||||
|
||||
void lx_emul_input_leds_init(void)
|
||||
{
|
||||
int pid = kernel_thread(led_task_loop, &led_task, CLONE_FS | CLONE_FILES);
|
||||
led_task = find_task_by_pid_ns(pid, NULL);
|
||||
}
|
||||
|
||||
|
||||
void lx_emul_input_leds_update(bool capslock, bool numlock, bool scrolllock)
|
||||
{
|
||||
|
||||
struct led_handler *handler;
|
||||
|
||||
led_update.state = UPDATE;
|
||||
|
||||
led_update.state = UPDATE;
|
||||
led_update.capsl = capslock;
|
||||
led_update.numl = numlock;
|
||||
led_update.scrolll = scrolllock;
|
||||
|
||||
list_for_each_entry(handler, &led_handlers, list) {
|
||||
update_leds(handler);
|
||||
}
|
||||
if (!led_task)
|
||||
return;
|
||||
|
||||
if (led_update.state == BLOCKED)
|
||||
complete(&led_update.update);
|
||||
|
||||
led_update.state = NONE;
|
||||
lx_emul_task_unblock(led_task);
|
||||
}
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,15 @@
|
||||
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
|
||||
void * hcd_buffer_alloc(struct usb_bus * bus, size_t size, gfp_t mem_flags, dma_addr_t * dma)
|
||||
{
|
||||
return kmalloc(size, GFP_KERNEL);
|
||||
}
|
||||
|
||||
|
||||
void hcd_buffer_free(struct usb_bus * bus, size_t size, void * addr, dma_addr_t dma)
|
||||
{
|
||||
kfree(addr);
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/hcd.h>
|
||||
#include <genode_c_api/usb_client.h>
|
||||
#include <lx_emul/usb_client.h>
|
||||
|
||||
/* wait queue for synchronous unlinks */
|
||||
DECLARE_WAIT_QUEUE_HEAD(usb_kill_urb_queue);
|
||||
|
||||
extern void lx_user_handle_io(void);
|
||||
|
||||
int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
|
||||
{
|
||||
genode_usb_client_dev_handle_t handle;
|
||||
genode_usb_client_ret_val_t r = INVALID;
|
||||
|
||||
/* increment urb's reference count as part of giving it to the HCD
|
||||
* (which will control it). HCD guarantees that it either returns
|
||||
* an error or calls giveback(), but not both.
|
||||
*/
|
||||
usb_get_urb(urb);
|
||||
atomic_inc(&urb->use_count);
|
||||
atomic_inc(&urb->dev->urbnum);
|
||||
|
||||
if (!urb->dev->bus)
|
||||
return -ENODEV;
|
||||
|
||||
handle = (genode_usb_client_dev_handle_t)urb->dev->filelist.prev;
|
||||
|
||||
switch(usb_pipetype(urb->pipe)) {
|
||||
case PIPE_CONTROL:
|
||||
{
|
||||
struct usb_ctrlrequest * ctrl = (struct usb_ctrlrequest *)
|
||||
urb->setup_packet;
|
||||
r = genode_usb_client_device_control(handle,
|
||||
ctrl->bRequest,
|
||||
ctrl->bRequestType,
|
||||
ctrl->wValue,
|
||||
ctrl->wIndex,
|
||||
urb->transfer_buffer_length,
|
||||
urb);
|
||||
break;
|
||||
}
|
||||
case PIPE_INTERRUPT:
|
||||
{
|
||||
r = genode_usb_client_iface_transfer(handle, IRQ,
|
||||
urb->ep->desc.bEndpointAddress,
|
||||
urb->transfer_buffer_length,
|
||||
urb);
|
||||
break;
|
||||
}
|
||||
case PIPE_BULK:
|
||||
r = genode_usb_client_iface_transfer(handle, BULK,
|
||||
urb->ep->desc.bEndpointAddress,
|
||||
urb->transfer_buffer_length,
|
||||
urb);
|
||||
break;
|
||||
default:
|
||||
printk("unknown URB requested: %d\n", usb_pipetype(urb->pipe));
|
||||
}
|
||||
|
||||
switch (r) {
|
||||
case NO_DEVICE: return -ENODEV;
|
||||
case NO_MEMORY: return -ENOMEM;
|
||||
case HALT: return -EPIPE;
|
||||
case INVALID: return -EINVAL;
|
||||
case TIMEOUT: return -ETIMEDOUT;
|
||||
case OK: break;
|
||||
};
|
||||
|
||||
lx_emul_usb_client_ticker();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int usb_hcd_unlink_urb (struct urb *urb, int status)
|
||||
{
|
||||
struct usb_device *udev = urb->dev;
|
||||
int ret = -EIDRM;
|
||||
|
||||
if (atomic_read(&urb->use_count) > 0 &&
|
||||
udev->state == USB_STATE_NOTATTACHED) {
|
||||
ret = 0;
|
||||
atomic_set(&urb->use_count, 0);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
@ -1,451 +0,0 @@
|
||||
/*
|
||||
* \brief message.c functions using genode_c_api/usb_client.h
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2023-06-20
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2023 Genode Labs GmbH
|
||||
*
|
||||
* This file is distributed under the terms of the GNU General Public License
|
||||
* version 2.
|
||||
*/
|
||||
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/hcd.h>
|
||||
#include <genode_c_api/usb_client.h>
|
||||
|
||||
#include "urb_helper.h"
|
||||
|
||||
extern struct bus_type usb_bus_type;
|
||||
extern struct device_type usb_if_device_type;
|
||||
|
||||
|
||||
static void sync_complete(struct genode_usb_client_request_packet *packet)
|
||||
{
|
||||
complete((struct completion *)packet->opaque_data);
|
||||
};
|
||||
|
||||
|
||||
int usb_control_msg(struct usb_device *dev, unsigned int pipe,
|
||||
__u8 request, __u8 requesttype, __u16 value,
|
||||
__u16 index, void *data, __u16 size, int timeout)
|
||||
{
|
||||
unsigned timeout_jiffies;
|
||||
int ret;
|
||||
struct urb *urb;
|
||||
struct completion comp;
|
||||
|
||||
struct genode_usb_client_request_packet packet;
|
||||
struct genode_usb_request_control control;
|
||||
struct genode_usb_config config;
|
||||
|
||||
genode_usb_client_handle_t handle;
|
||||
|
||||
if (!dev->bus) return -ENODEV;
|
||||
|
||||
handle = (genode_usb_client_handle_t)dev->bus->controller;
|
||||
|
||||
/*
|
||||
* If this function is called with a timeout of 0 to wait forever,
|
||||
* we wait in pieces of 10s each as 'schedule_timeout' might trigger
|
||||
* immediately otherwise. The intend to wait forever is reflected
|
||||
* back nonetheless when sending the urb.
|
||||
*/
|
||||
timeout_jiffies = timeout ? msecs_to_jiffies(timeout)
|
||||
: msecs_to_jiffies(10000u);
|
||||
|
||||
/* dummy alloc urb for wait_for_free_urb below */
|
||||
urb = (struct urb *)usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!urb) return -ENOMEM;
|
||||
|
||||
|
||||
/*
|
||||
* Set configuration also calls this function, but maps to different packet
|
||||
* Note: Some calls using set configuration do not change the profile but send
|
||||
* data to the device (e.g., keyboard led handling) where size != 0
|
||||
*/
|
||||
if (request == USB_REQ_SET_CONFIGURATION && size == 0) {
|
||||
packet.request.type = CONFIG;
|
||||
config.value = value;
|
||||
packet.request.req = &config;
|
||||
packet.buffer.size = 0;
|
||||
} else {
|
||||
packet.request.type = CTRL;
|
||||
control.request = request;
|
||||
control.request_type = requesttype;
|
||||
control.value = value;
|
||||
control.index = index;
|
||||
control.timeout = timeout ? jiffies_to_msecs(timeout_jiffies) : 0;
|
||||
packet.request.req = &control;
|
||||
packet.buffer.size = size;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
|
||||
if (genode_usb_client_request(handle, &packet)) break;
|
||||
|
||||
timeout_jiffies = wait_for_free_urb(timeout_jiffies);
|
||||
if (!timeout_jiffies && timeout) {
|
||||
ret = -ETIMEDOUT;
|
||||
goto err_request;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(requesttype & USB_DIR_IN))
|
||||
memcpy(packet.buffer.addr, data, size);
|
||||
|
||||
init_completion(&comp);
|
||||
packet.complete_callback = sync_complete;
|
||||
packet.free_callback = sync_complete;
|
||||
packet.opaque_data = ∁
|
||||
|
||||
genode_usb_client_request_submit(handle, &packet);
|
||||
wait_for_completion(&comp);
|
||||
|
||||
if (packet.actual_length && data && (size >= packet.actual_length))
|
||||
memcpy(data, packet.buffer.addr, packet.actual_length);
|
||||
|
||||
ret = packet.error ? packet_errno(packet.error) : packet.actual_length;
|
||||
genode_usb_client_request_finish(handle, &packet);
|
||||
|
||||
err_request:
|
||||
kfree(urb);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int usb_get_descriptor(struct usb_device *dev, unsigned char type,
|
||||
unsigned char index, void *buf, int size)
|
||||
{
|
||||
int i;
|
||||
int result;
|
||||
|
||||
if (size <= 0) /* No point in asking for no data */
|
||||
return -EINVAL;
|
||||
|
||||
memset(buf, 0, size); /* Make sure we parse really received data */
|
||||
|
||||
for (i = 0; i < 3; ++i) {
|
||||
/* retry on length 0 or error; some devices are flakey */
|
||||
result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
|
||||
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
|
||||
(type << 8) + index, 0, buf, size,
|
||||
USB_CTRL_GET_TIMEOUT);
|
||||
if (result <= 0 && result != -ETIMEDOUT)
|
||||
continue;
|
||||
if (result > 1 && ((u8 *)buf)[1] != type) {
|
||||
result = -ENODATA;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep, bool reset_ep)
|
||||
{
|
||||
int epnum = usb_endpoint_num(&ep->desc);
|
||||
int is_out = usb_endpoint_dir_out(&ep->desc);
|
||||
int is_control = usb_endpoint_xfer_control(&ep->desc);
|
||||
|
||||
if (is_out || is_control)
|
||||
dev->ep_out[epnum] = ep;
|
||||
if (!is_out || is_control)
|
||||
dev->ep_in[epnum] = ep;
|
||||
ep->enabled = 1;
|
||||
}
|
||||
|
||||
|
||||
void usb_enable_interface(struct usb_device *dev,
|
||||
struct usb_interface *intf, bool reset_eps)
|
||||
{
|
||||
struct usb_host_interface *alt = intf->cur_altsetting;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < alt->desc.bNumEndpoints; ++i) {
|
||||
usb_enable_endpoint(dev, &alt->endpoint[i], reset_eps);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int usb_set_interface(struct usb_device *udev, int ifnum, int alternate)
|
||||
{
|
||||
int ret;
|
||||
struct urb *urb;
|
||||
struct completion comp;
|
||||
unsigned timeout_jiffies = msecs_to_jiffies(10000u);
|
||||
|
||||
struct genode_usb_client_request_packet packet;
|
||||
struct genode_usb_altsetting alt_setting;
|
||||
|
||||
genode_usb_client_handle_t handle;
|
||||
|
||||
struct usb_interface *iface;
|
||||
|
||||
if (!udev->bus) return -ENODEV;
|
||||
|
||||
if (!udev->config)
|
||||
return -ENODEV;
|
||||
|
||||
if (ifnum >= USB_MAXINTERFACES || ifnum < 0)
|
||||
return -EINVAL;
|
||||
|
||||
iface = udev->actconfig->interface[ifnum];
|
||||
|
||||
handle = (genode_usb_client_handle_t)udev->bus->controller;
|
||||
|
||||
/* dummy alloc urb for wait_for_free_urb below */
|
||||
urb = (struct urb *)usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!urb) return -ENOMEM;
|
||||
|
||||
packet.request.type = ALT_SETTING;
|
||||
alt_setting.interface_number = ifnum;
|
||||
alt_setting.alt_setting = alternate;
|
||||
packet.request.req = &alt_setting;
|
||||
packet.buffer.size = 0;
|
||||
|
||||
for (;;) {
|
||||
|
||||
if (genode_usb_client_request(handle, &packet)) break;
|
||||
|
||||
timeout_jiffies = wait_for_free_urb(timeout_jiffies);
|
||||
if (!timeout_jiffies) {
|
||||
ret = -ETIMEDOUT;
|
||||
goto err_request;
|
||||
}
|
||||
}
|
||||
|
||||
init_completion(&comp);
|
||||
packet.complete_callback = sync_complete;
|
||||
packet.free_callback = sync_complete;
|
||||
packet.opaque_data = ∁
|
||||
|
||||
genode_usb_client_request_submit(handle, &packet);
|
||||
wait_for_completion(&comp);
|
||||
|
||||
ret = packet.error ? packet_errno(packet.error) : 0;
|
||||
genode_usb_client_request_finish(handle, &packet);
|
||||
|
||||
/* reset via alt setting 0 */
|
||||
if (!iface) {
|
||||
printk("%s:%d: Error: interface is null: infum: %d alt setting: %d\n",
|
||||
__func__, __LINE__, ifnum, alternate);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
iface->cur_altsetting = &iface->altsetting[alternate];
|
||||
}
|
||||
|
||||
usb_enable_interface(udev, iface, true);
|
||||
|
||||
err_request:
|
||||
kfree(urb);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static struct usb_interface_assoc_descriptor *find_iad(struct usb_device *dev,
|
||||
struct usb_host_config *config,
|
||||
u8 inum)
|
||||
{
|
||||
struct usb_interface_assoc_descriptor *retval = NULL;
|
||||
struct usb_interface_assoc_descriptor *intf_assoc;
|
||||
int first_intf;
|
||||
int last_intf;
|
||||
int i;
|
||||
|
||||
for (i = 0; (i < USB_MAXIADS && config->intf_assoc[i]); i++) {
|
||||
intf_assoc = config->intf_assoc[i];
|
||||
if (intf_assoc->bInterfaceCount == 0)
|
||||
continue;
|
||||
|
||||
first_intf = intf_assoc->bFirstInterface;
|
||||
last_intf = first_intf + (intf_assoc->bInterfaceCount - 1);
|
||||
if (inum >= first_intf && inum <= last_intf) {
|
||||
if (!retval)
|
||||
retval = intf_assoc;
|
||||
else
|
||||
dev_err(&dev->dev, "Interface #%d referenced"
|
||||
" by multiple IADs\n", inum);
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
int usb_set_configuration(struct usb_device *dev, int configuration)
|
||||
{
|
||||
int i, ret;
|
||||
struct usb_host_config *cp = NULL;
|
||||
struct usb_interface **new_interfaces = NULL;
|
||||
int n, nintf;
|
||||
|
||||
if (dev->authorized == 0 || configuration == -1)
|
||||
configuration = 0;
|
||||
else {
|
||||
for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
|
||||
if (dev->config[i].desc.bConfigurationValue ==
|
||||
configuration) {
|
||||
cp = &dev->config[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((!cp && configuration != 0))
|
||||
return -EINVAL;
|
||||
|
||||
/* The USB spec says configuration 0 means unconfigured.
|
||||
* But if a device includes a configuration numbered 0,
|
||||
* we will accept it as a correctly configured state.
|
||||
* Use -1 if you really want to unconfigure the device.
|
||||
*/
|
||||
if (cp && configuration == 0)
|
||||
dev_warn(&dev->dev, "config 0 descriptor??\n");
|
||||
|
||||
/* Allocate memory for new interfaces before doing anything else,
|
||||
* so that if we run out then nothing will have changed. */
|
||||
n = nintf = 0;
|
||||
if (cp) {
|
||||
nintf = cp->desc.bNumInterfaces;
|
||||
new_interfaces = (struct usb_interface **)
|
||||
kmalloc(nintf * sizeof(*new_interfaces), GFP_KERNEL);
|
||||
if (!new_interfaces)
|
||||
return -ENOMEM;
|
||||
|
||||
for (; n < nintf; ++n) {
|
||||
new_interfaces[n] = (struct usb_interface*)
|
||||
kzalloc( sizeof(struct usb_interface), GFP_KERNEL);
|
||||
if (!new_interfaces[n]) {
|
||||
ret = -ENOMEM;
|
||||
while (--n >= 0)
|
||||
kfree(new_interfaces[n]);
|
||||
kfree(new_interfaces);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the new interface structures and the
|
||||
* hc/hcd/usbcore interface/endpoint state.
|
||||
*/
|
||||
for (i = 0; i < nintf; ++i) {
|
||||
struct usb_interface_cache *intfc;
|
||||
struct usb_interface *intf;
|
||||
struct usb_host_interface *alt;
|
||||
u8 ifnum;
|
||||
|
||||
cp->interface[i] = intf = new_interfaces[i];
|
||||
intfc = cp->intf_cache[i];
|
||||
intf->altsetting = intfc->altsetting;
|
||||
intf->num_altsetting = intfc->num_altsetting;
|
||||
intf->authorized = 1; //FIXME
|
||||
|
||||
alt = usb_altnum_to_altsetting(intf, 0);
|
||||
|
||||
/* No altsetting 0? We'll assume the first altsetting.
|
||||
* We could use a GetInterface call, but if a device is
|
||||
* so non-compliant that it doesn't have altsetting 0
|
||||
* then I wouldn't trust its reply anyway.
|
||||
*/
|
||||
if (!alt)
|
||||
alt = &intf->altsetting[0];
|
||||
|
||||
ifnum = alt->desc.bInterfaceNumber;
|
||||
intf->intf_assoc = find_iad(dev, cp, ifnum);
|
||||
intf->cur_altsetting = alt;
|
||||
intf->dev.parent = &dev->dev;
|
||||
intf->dev.driver = NULL;
|
||||
intf->dev.bus = &usb_bus_type;
|
||||
intf->dev.type = &usb_if_device_type;
|
||||
intf->minor = -1;
|
||||
device_initialize(&intf->dev);
|
||||
dev_set_name(&intf->dev, "%d-%s:%d.%d", dev->bus->busnum,
|
||||
dev->devpath, configuration, ifnum);
|
||||
}
|
||||
kfree(new_interfaces);
|
||||
|
||||
ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
|
||||
USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
|
||||
NULL, 0, USB_CTRL_SET_TIMEOUT);
|
||||
if (ret < 0 && cp) {
|
||||
for (i = 0; i < nintf; ++i) {
|
||||
put_device(&cp->interface[i]->dev);
|
||||
cp->interface[i] = NULL;
|
||||
}
|
||||
cp = NULL;
|
||||
}
|
||||
dev->actconfig = cp;
|
||||
|
||||
if (!cp) {
|
||||
dev->state = USB_STATE_ADDRESS;
|
||||
return ret;
|
||||
}
|
||||
dev->state = USB_STATE_CONFIGURED;
|
||||
|
||||
for (i = 0; i < nintf; ++i) {
|
||||
struct usb_interface *intf = cp->interface[i];
|
||||
usb_enable_interface(dev, intf, true);
|
||||
|
||||
ret = device_add(&intf->dev);
|
||||
if (ret != 0) {
|
||||
printk("error: device_add(%s) --> %d\n", dev_name(&intf->dev), ret);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void usb_disable_device(struct usb_device *dev, int skip_ep0)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* getting rid of interfaces will disconnect
|
||||
* any drivers bound to them (a key side effect)
|
||||
*/
|
||||
if (dev->actconfig) {
|
||||
/*
|
||||
* FIXME: In order to avoid self-deadlock involving the
|
||||
* bandwidth_mutex, we have to mark all the interfaces
|
||||
* before unregistering any of them.
|
||||
*/
|
||||
for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++)
|
||||
dev->actconfig->interface[i]->unregistering = 1;
|
||||
|
||||
for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
|
||||
struct usb_interface *interface;
|
||||
|
||||
/* remove this interface if it has been registered */
|
||||
interface = dev->actconfig->interface[i];
|
||||
if (!device_is_registered(&interface->dev))
|
||||
continue;
|
||||
|
||||
dev_dbg(&dev->dev, "unregistering interface %s\n",
|
||||
dev_name(&interface->dev));
|
||||
device_del(&interface->dev);
|
||||
}
|
||||
|
||||
/* Now that the interfaces are unbound, nobody should
|
||||
* try to access them.
|
||||
*/
|
||||
for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
|
||||
put_device(&dev->actconfig->interface[i]->dev);
|
||||
dev->actconfig->interface[i] = NULL;
|
||||
}
|
||||
|
||||
dev->actconfig = NULL;
|
||||
if (dev->state == USB_STATE_CONFIGURED)
|
||||
usb_set_device_state(dev, USB_STATE_ADDRESS);
|
||||
}
|
||||
|
||||
dev_dbg(&dev->dev, "%s nuking %s URBs\n", __func__,
|
||||
skip_ep0 ? "non-ep0" : "all");
|
||||
}
|
@ -1,218 +0,0 @@
|
||||
/*
|
||||
* \brief urb.c functions using genode_c_api/usb_client.h
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2023-06-20
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2023 Genode Labs GmbH
|
||||
*
|
||||
* This file is distributed under the terms of the GNU General Public License
|
||||
* version 2.
|
||||
*/
|
||||
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/hcd.h>
|
||||
#include <genode_c_api/usb_client.h>
|
||||
|
||||
#include "urb_helper.h"
|
||||
|
||||
#define to_urb(d) container_of(d, struct urb, kref)
|
||||
|
||||
|
||||
static DECLARE_WAIT_QUEUE_HEAD(lx_emul_urb_wait);
|
||||
|
||||
int wait_for_free_urb(unsigned int timeout_jiffies)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
add_wait_queue(&lx_emul_urb_wait, &wait);
|
||||
|
||||
ret = schedule_timeout(timeout_jiffies);
|
||||
|
||||
remove_wait_queue(&lx_emul_urb_wait, &wait);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags)
|
||||
{
|
||||
struct urb *urb = (struct urb*)
|
||||
kmalloc(sizeof(struct urb) +
|
||||
iso_packets * sizeof(struct usb_iso_packet_descriptor),
|
||||
GFP_KERNEL);
|
||||
|
||||
if (!urb) return NULL;
|
||||
memset(urb, 0, sizeof(*urb));
|
||||
kref_init(&urb->kref);
|
||||
INIT_LIST_HEAD(&urb->urb_list);
|
||||
INIT_LIST_HEAD(&urb->anchor_list);
|
||||
|
||||
return urb;
|
||||
}
|
||||
|
||||
|
||||
static void free_packet(struct genode_usb_client_request_packet *packet)
|
||||
{
|
||||
kfree(packet->request.req);
|
||||
kfree(packet);
|
||||
}
|
||||
|
||||
|
||||
static void urb_submit_complete(struct genode_usb_client_request_packet *packet)
|
||||
{
|
||||
struct urb *urb = (struct urb *)packet->opaque_data;
|
||||
genode_usb_client_handle_t handle = (genode_usb_client_handle_t)urb->hcpriv;
|
||||
|
||||
urb->status = packet->error ? packet_errno(packet->error) : 0;
|
||||
|
||||
if (packet->error == 0 &&
|
||||
packet->actual_length && urb->transfer_buffer &&
|
||||
urb->transfer_buffer_length >= packet->actual_length)
|
||||
memcpy(urb->transfer_buffer, packet->buffer.addr, packet->actual_length);
|
||||
|
||||
urb->actual_length = packet->actual_length;
|
||||
|
||||
genode_usb_client_request_finish(handle, packet);
|
||||
|
||||
free_packet(packet);
|
||||
|
||||
if (urb->complete) urb->complete(urb);
|
||||
};
|
||||
|
||||
|
||||
int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
|
||||
{
|
||||
genode_usb_client_handle_t handle;
|
||||
struct genode_usb_client_request_packet *packet;
|
||||
struct genode_usb_request_transfer *transfer;
|
||||
struct genode_usb_request_control *control;
|
||||
int ret = 0;
|
||||
unsigned timeout_jiffies = msecs_to_jiffies(10000u);
|
||||
|
||||
if (!urb || !urb->complete)
|
||||
return -EINVAL;
|
||||
|
||||
if (!urb->dev->bus)
|
||||
return -ENODEV;
|
||||
|
||||
handle = (genode_usb_client_handle_t)urb->dev->bus->controller;
|
||||
|
||||
packet = (struct genode_usb_client_request_packet *)
|
||||
kzalloc(sizeof(*packet), GFP_KERNEL);
|
||||
|
||||
if (!packet) return -ENOMEM;
|
||||
|
||||
if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
|
||||
control = (struct genode_usb_request_control *)
|
||||
kzalloc(sizeof(*control), GFP_KERNEL);
|
||||
|
||||
if (!control) {
|
||||
ret = -ENOMEM;
|
||||
goto transfer;
|
||||
}
|
||||
}
|
||||
else {
|
||||
transfer = (struct genode_usb_request_transfer *)
|
||||
kzalloc(sizeof(*transfer), GFP_KERNEL);
|
||||
|
||||
if (!transfer) {
|
||||
ret = -ENOMEM;
|
||||
goto transfer;
|
||||
}
|
||||
}
|
||||
|
||||
switch(usb_pipetype(urb->pipe)) {
|
||||
case PIPE_CONTROL:
|
||||
{
|
||||
struct usb_ctrlrequest * ctrl = (struct usb_ctrlrequest *)
|
||||
urb->setup_packet;
|
||||
packet->request.type = CTRL;
|
||||
control->request = ctrl->bRequest;
|
||||
control->request_type = ctrl->bRequestType;
|
||||
control->value = ctrl->wValue;
|
||||
control->index = ctrl->wIndex;
|
||||
packet->request.req = control;
|
||||
break;
|
||||
}
|
||||
case PIPE_INTERRUPT:
|
||||
{
|
||||
packet->request.type = IRQ;
|
||||
transfer->polling_interval = urb->interval;
|
||||
transfer->ep = usb_pipeendpoint(urb->pipe)
|
||||
| (usb_pipein(urb->pipe) ? USB_DIR_IN : 0);
|
||||
packet->request.req = transfer;
|
||||
break;
|
||||
}
|
||||
case PIPE_BULK:
|
||||
{
|
||||
packet->request.type = BULK;
|
||||
transfer->ep = usb_pipeendpoint(urb->pipe)
|
||||
| (usb_pipein(urb->pipe) ? USB_DIR_IN : 0);
|
||||
packet->request.req = transfer;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printk("unknown URB requested: %d\n", usb_pipetype(urb->pipe));
|
||||
}
|
||||
|
||||
packet->buffer.size = urb->transfer_buffer_length;
|
||||
packet->complete_callback = urb_submit_complete;
|
||||
packet->opaque_data = urb;
|
||||
packet->free_callback = free_packet;
|
||||
|
||||
for (;;) {
|
||||
|
||||
if (genode_usb_client_request(handle, packet)) break;
|
||||
|
||||
timeout_jiffies = wait_for_free_urb(timeout_jiffies);
|
||||
if (!timeout_jiffies) {
|
||||
ret = -ETIMEDOUT;
|
||||
goto err_request;
|
||||
}
|
||||
}
|
||||
|
||||
if (usb_pipeout(urb->pipe))
|
||||
memcpy(packet->buffer.addr, urb->transfer_buffer, urb->transfer_buffer_length);
|
||||
|
||||
urb->hcpriv = (void *)handle;
|
||||
|
||||
genode_usb_client_request_submit(handle, packet);
|
||||
|
||||
return ret;
|
||||
|
||||
err_request:
|
||||
if (transfer) kfree(transfer);
|
||||
if (control) kfree(control);
|
||||
transfer:
|
||||
kfree(packet);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
struct urb *usb_get_urb(struct urb *urb)
|
||||
{
|
||||
if (urb)
|
||||
kref_get(&urb->kref);
|
||||
return urb;
|
||||
}
|
||||
|
||||
|
||||
static void urb_destroy(struct kref *kref)
|
||||
{
|
||||
struct urb *urb = to_urb(kref);
|
||||
|
||||
kfree(urb);
|
||||
wake_up(&lx_emul_urb_wait);
|
||||
}
|
||||
|
||||
|
||||
/* usb_put_urb is defined as usb_free_urb, therefore we need reference counting */
|
||||
void usb_free_urb(struct urb *urb)
|
||||
{
|
||||
if (urb)
|
||||
kref_put(&urb->kref, urb_destroy);
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
/*
|
||||
* \brief URB handling helpers
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2023-06-20
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2023 Genode Labs GmbH
|
||||
*
|
||||
* This file is distributed under the terms of the GNU General Public License
|
||||
* version 2.
|
||||
*/
|
||||
|
||||
#include <linux/usb.h>
|
||||
#include <genode_c_api/usb_client.h>
|
||||
|
||||
|
||||
/*
|
||||
* Translate USB-client packet errors to errno
|
||||
*/
|
||||
static inline int packet_errno(int error)
|
||||
{
|
||||
switch (error) {
|
||||
case INTERFACE_OR_ENDPOINT_ERROR: return -ENOENT;
|
||||
case MEMORY_ERROR: return -ENOMEM;
|
||||
case NO_DEVICE_ERROR: return -ESHUTDOWN;
|
||||
case PACKET_INVALID_ERROR: return -EINVAL;
|
||||
case PROTOCOL_ERROR: return -EPROTO;
|
||||
case STALL_ERROR: return -EPIPE;
|
||||
case TIMEOUT_ERROR: return -ETIMEDOUT;
|
||||
case UNKNOWN_ERROR:
|
||||
printk("%s: got UNKNOWN_ERROR code\n", __func__);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Wait for a call to 'urb_destroy'
|
||||
*/
|
||||
int wait_for_free_urb(unsigned int timeout_jiffies);
|
@ -1,9 +1,10 @@
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/hcd.h>
|
||||
#include <../drivers/usb/core/usb.h>
|
||||
|
||||
#include <lx_emul/usb_client.h>
|
||||
#include <genode_c_api/usb_client.h>
|
||||
|
||||
static struct hc_driver _hc_driver = { };
|
||||
|
||||
struct meta_data
|
||||
{
|
||||
@ -12,128 +13,208 @@ struct meta_data
|
||||
struct usb_device *udev;
|
||||
};
|
||||
|
||||
|
||||
void *lx_emul_usb_client_register_device(genode_usb_client_handle_t handle, char const *label)
|
||||
static struct usb_hcd * dummy_hc_device(void)
|
||||
{
|
||||
static int initialized = 0;
|
||||
static struct hc_driver _hc_driver = { };
|
||||
static struct usb_hcd hcd;
|
||||
static struct device sysdev;
|
||||
static struct mutex address0_mutex;
|
||||
static struct mutex bandwidth_mutex;
|
||||
|
||||
if (!initialized) {
|
||||
device_initialize(&sysdev);
|
||||
mutex_init(&address0_mutex);
|
||||
mutex_init(&bandwidth_mutex);
|
||||
kref_init(&hcd.kref);
|
||||
hcd.driver = &_hc_driver;
|
||||
hcd.self.bus_name = "usbbus";
|
||||
hcd.self.sysdev = &sysdev;
|
||||
hcd.dev_policy = USB_DEVICE_AUTHORIZE_ALL;
|
||||
hcd.address0_mutex = &address0_mutex;
|
||||
hcd.bandwidth_mutex = &bandwidth_mutex;
|
||||
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd.flags);
|
||||
set_bit(HCD_FLAG_INTF_AUTHORIZED, &hcd.flags);
|
||||
initialized = 1;
|
||||
}
|
||||
return &hcd;
|
||||
}
|
||||
|
||||
static void * register_device(genode_usb_client_dev_handle_t handle,
|
||||
char const *label, genode_usb_speed_t speed)
|
||||
{
|
||||
struct meta_data *meta;
|
||||
int err;
|
||||
struct genode_usb_device_descriptor dev_descr;
|
||||
struct genode_usb_config_descriptor conf_descr;
|
||||
static int num = 0;
|
||||
struct usb_device * udev;
|
||||
|
||||
err = genode_usb_client_config_descriptor(handle, &dev_descr, &conf_descr);
|
||||
if (err) {
|
||||
printk("error: failed to read config descriptor\n");
|
||||
return NULL;;
|
||||
}
|
||||
|
||||
meta = (struct meta_data *)kmalloc(sizeof(struct meta_data), GFP_KERNEL);
|
||||
if (!meta) return NULL;
|
||||
|
||||
meta->sysdev = (struct device*)kzalloc(sizeof(struct device), GFP_KERNEL);
|
||||
if (!meta->sysdev) goto sysdev;
|
||||
|
||||
device_initialize(meta->sysdev);
|
||||
|
||||
meta->hcd = (struct usb_hcd *)kzalloc(sizeof(struct usb_hcd), GFP_KERNEL);
|
||||
if (!meta->hcd) goto hcd;
|
||||
|
||||
/* hcd->self is usb_bus */
|
||||
meta->hcd->driver = &_hc_driver;
|
||||
meta->hcd->self.bus_name = "usbbus";
|
||||
meta->hcd->self.sysdev = meta->sysdev;
|
||||
|
||||
meta->udev = usb_alloc_dev(NULL, &meta->hcd->self, 0);
|
||||
if (!meta->udev) {
|
||||
udev = usb_alloc_dev(NULL, &dummy_hc_device()->self, 0);
|
||||
if (!udev) {
|
||||
printk("error: could not allocate udev for %s\n", label);
|
||||
goto udev;
|
||||
}
|
||||
|
||||
/* usb_alloc_dev sets parent to bus->controller if first argument is NULL */
|
||||
meta->hcd->self.controller = (struct device *)handle;
|
||||
|
||||
memcpy(&meta->udev->descriptor, &dev_descr, sizeof(struct usb_device_descriptor));
|
||||
meta->udev->devnum = dev_descr.num;
|
||||
meta->udev->speed = (enum usb_device_speed)dev_descr.speed;
|
||||
meta->udev->authorized = 1;
|
||||
meta->udev->bus_mA = 900; /* set to maximum USB3.0 */
|
||||
meta->udev->state = USB_STATE_NOTATTACHED;
|
||||
|
||||
dev_set_name(&meta->udev->dev, "%s", label);
|
||||
|
||||
err = usb_new_device(meta->udev);
|
||||
|
||||
if (err) {
|
||||
printk("error: usb_new_device failed %d\n", err);
|
||||
goto new_device;
|
||||
}
|
||||
return meta;
|
||||
|
||||
new_device:
|
||||
usb_put_dev(meta->udev);
|
||||
udev:
|
||||
kfree(meta->hcd);
|
||||
hcd:
|
||||
kfree(meta->sysdev);
|
||||
sysdev:
|
||||
kfree(meta);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void lx_emul_usb_client_unregister_device(genode_usb_client_handle_t handle, void *data)
|
||||
{
|
||||
struct meta_data *meta = (struct meta_data *)data;
|
||||
|
||||
usb_disconnect(&meta->udev);
|
||||
usb_put_dev(meta->udev);
|
||||
kfree(meta->hcd);
|
||||
kobject_put(&meta->sysdev->kobj);
|
||||
kfree(meta->sysdev);
|
||||
kfree(meta);
|
||||
}
|
||||
|
||||
|
||||
#define for_each_claimed_interface(udev, num, intf) \
|
||||
for (num = 0, intf = udev->actconfig->interface[num]; \
|
||||
num < udev->actconfig->desc.bNumInterfaces; \
|
||||
intf = udev->actconfig->interface[++num]) \
|
||||
if (!usb_interface_claimed(intf)) continue; else
|
||||
|
||||
|
||||
int lx_emul_usb_client_set_configuration(genode_usb_client_handle_t handle, void *data, unsigned long config)
|
||||
{
|
||||
struct meta_data *meta = (struct meta_data *)data;
|
||||
struct usb_device *udev = meta->udev;
|
||||
unsigned i = 0;
|
||||
struct usb_interface *intf;
|
||||
|
||||
/* release claimed interfaces at session */
|
||||
for_each_claimed_interface(udev, i, intf) {
|
||||
genode_usb_client_release_interface(handle, i);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Release claimed interfaces at driver, 'usb_driver_release_interface' may
|
||||
* release more than one interface
|
||||
* We store handle in filelist list head to be used in hcd urb submission
|
||||
* before sending any URB. The filelist member is referenced in devio.c
|
||||
* only which is not used here.
|
||||
*/
|
||||
for_each_claimed_interface(udev, i, intf) {
|
||||
usb_driver_release_interface(to_usb_driver(intf->dev.driver), intf);
|
||||
udev->filelist.prev = (struct list_head *) handle;
|
||||
|
||||
udev->devnum = num++;
|
||||
|
||||
switch (speed) {
|
||||
case GENODE_USB_SPEED_LOW: udev->speed = USB_SPEED_LOW; break;
|
||||
case GENODE_USB_SPEED_FULL: udev->speed = USB_SPEED_FULL; break;
|
||||
case GENODE_USB_SPEED_HIGH: udev->speed = USB_SPEED_HIGH; break;
|
||||
case GENODE_USB_SPEED_SUPER: udev->speed = USB_SPEED_SUPER; break;
|
||||
case GENODE_USB_SPEED_SUPER_PLUS:
|
||||
udev->speed = USB_SPEED_SUPER_PLUS;
|
||||
udev->ssp_rate = USB_SSP_GEN_2x1;
|
||||
break;
|
||||
case GENODE_USB_SPEED_SUPER_PLUS_2X2:
|
||||
udev->speed = USB_SPEED_SUPER_PLUS;
|
||||
udev->ssp_rate = USB_SSP_GEN_2x2;
|
||||
break;
|
||||
default:
|
||||
udev->speed = USB_SPEED_FULL;
|
||||
break;
|
||||
};
|
||||
|
||||
udev->authorized = 1;
|
||||
udev->bus_mA = 900; /* set to maximum USB3.0 */
|
||||
usb_set_device_state(udev, USB_STATE_ADDRESS);
|
||||
|
||||
dev_set_name(&udev->dev, "%s", label);
|
||||
device_set_wakeup_capable(&udev->dev, 1);
|
||||
udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
|
||||
err = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);
|
||||
if (err < 0) {
|
||||
dev_err(&udev->dev, "can't read device descriptor: %d\n", err);
|
||||
usb_put_dev(udev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* set unconfigured (internal reset in host driver) first */
|
||||
usb_set_configuration(meta->udev, 0);
|
||||
return usb_set_configuration(meta->udev, config);
|
||||
err = usb_new_device(udev);
|
||||
if (err) {
|
||||
printk("error: usb_new_device failed %d\n", err);
|
||||
usb_put_dev(udev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return udev;
|
||||
}
|
||||
|
||||
|
||||
void * hcd_buffer_alloc(struct usb_bus * bus, size_t size, gfp_t mem_flags, dma_addr_t * dma)
|
||||
static void urb_out(void * data, genode_buffer_t buf)
|
||||
{
|
||||
return kmalloc(size, GFP_KERNEL);
|
||||
struct urb *urb = (struct urb *) data;
|
||||
memcpy(buf.addr, urb->transfer_buffer,
|
||||
urb->transfer_buffer_length);
|
||||
}
|
||||
|
||||
|
||||
void hcd_buffer_free(struct usb_bus * bus, size_t size, void * addr, dma_addr_t dma)
|
||||
static void urb_in(void * data, genode_buffer_t buf)
|
||||
{
|
||||
kfree(addr);
|
||||
struct urb *urb = (struct urb *) data;
|
||||
memcpy(urb->transfer_buffer, buf.addr, buf.size);
|
||||
urb->actual_length = buf.size;
|
||||
}
|
||||
|
||||
|
||||
static genode_uint32_t isoc_urb_out(void * data, genode_uint32_t idx,
|
||||
genode_buffer_t buf)
|
||||
{
|
||||
printk("%s: not implemented yet, we had no isochronous Linux driver yet",
|
||||
__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void isoc_urb_in(void * data, genode_uint32_t idx, genode_buffer_t buf)
|
||||
{
|
||||
printk("%s: not implemented yet, we had no isochronous Linux driver yet",
|
||||
__func__);
|
||||
}
|
||||
|
||||
|
||||
static void urb_complete(void * data, genode_usb_client_ret_val_t result)
|
||||
{
|
||||
struct urb *urb = (struct urb *) data;
|
||||
switch (result) {
|
||||
case OK: urb->status = 0; break;
|
||||
case NO_DEVICE: urb->status = -ENOENT; break;
|
||||
case NO_MEMORY: urb->status = -ENOMEM; break;
|
||||
case HALT: urb->status = -EPIPE; break;
|
||||
case INVALID: urb->status = -EINVAL; break;
|
||||
case TIMEOUT: urb->status = -ETIMEDOUT;
|
||||
};
|
||||
if (urb->complete) urb->complete(urb);
|
||||
|
||||
atomic_dec(&urb->use_count);
|
||||
usb_put_urb(urb);
|
||||
}
|
||||
|
||||
|
||||
static void unregister_device(genode_usb_client_dev_handle_t handle, void *data)
|
||||
{
|
||||
struct usb_device *udev = (struct usb_device *)data;
|
||||
genode_usb_client_device_update(urb_out, urb_in, isoc_urb_out,
|
||||
isoc_urb_in, urb_complete);
|
||||
udev->filelist.prev = NULL;
|
||||
usb_disconnect(&udev);
|
||||
usb_put_dev(udev);
|
||||
}
|
||||
|
||||
|
||||
static int usb_loop(void *arg)
|
||||
{
|
||||
for (;;) {
|
||||
genode_usb_client_device_update(urb_out, urb_in, isoc_urb_out,
|
||||
isoc_urb_in, urb_complete);
|
||||
lx_emul_task_schedule(true);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static struct task_struct * usb_task = NULL;
|
||||
|
||||
|
||||
static int usb_rom_loop(void *arg)
|
||||
{
|
||||
for (;;) {
|
||||
|
||||
genode_usb_client_update(register_device, unregister_device);
|
||||
|
||||
/* block until lx_emul_task_unblock */
|
||||
lx_emul_task_schedule(true);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct task_struct *usb_rom_task = NULL;
|
||||
|
||||
|
||||
void lx_emul_usb_client_init(void)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
pid = kernel_thread(usb_rom_loop, NULL, CLONE_FS | CLONE_FILES);
|
||||
usb_rom_task = find_task_by_pid_ns(pid, NULL);
|
||||
|
||||
pid = kernel_thread(usb_loop, NULL, CLONE_FS | CLONE_FILES);
|
||||
usb_task = find_task_by_pid_ns(pid, NULL);
|
||||
}
|
||||
|
||||
|
||||
void lx_emul_usb_client_rom_update(void)
|
||||
{
|
||||
if (usb_rom_task) lx_emul_task_unblock(usb_rom_task);
|
||||
}
|
||||
|
||||
|
||||
void lx_emul_usb_client_ticker(void)
|
||||
{
|
||||
if (usb_task) lx_emul_task_unblock(usb_task);
|
||||
}
|
||||
|
Reference in New Issue
Block a user