mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-19 11:16:57 +00:00
dde_linux: enable QEMU support for new usb_hid_drv
This commit is contained in:
parent
1ec2f43713
commit
9221f7916a
@ -1 +1 @@
|
||||
477b1b59ec591bd7ef01c853f15df4acabca6624
|
||||
b88acdf93d8db71180a25937fba45ec6b39a2841
|
||||
|
@ -68,9 +68,6 @@ struct Driver
|
||||
static void urb_task_entry(void *);
|
||||
void register_device();
|
||||
void unregister_device();
|
||||
void scan_interfaces(unsigned iface_idx);
|
||||
void scan_altsettings(usb_interface * iface,
|
||||
unsigned iface_idx, unsigned alt_idx);
|
||||
void probe_interface(usb_interface *, usb_device_id *);
|
||||
void remove_interface(usb_interface *);
|
||||
};
|
||||
|
@ -334,7 +334,7 @@ void kref_get(struct kref *kref)
|
||||
|
||||
void kref_init(struct kref *kref)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
TRACE;
|
||||
}
|
||||
|
||||
int kref_put(struct kref *kref, void (*release) (struct kref *kref))
|
||||
@ -660,3 +660,9 @@ void up(struct semaphore *sem)
|
||||
{
|
||||
TRACE;
|
||||
}
|
||||
|
||||
bool usb_device_is_owned(struct usb_device *udev)
|
||||
{
|
||||
TRACE;
|
||||
return false;
|
||||
}
|
||||
|
@ -25,6 +25,73 @@
|
||||
|
||||
#include <lx_kit/backend_alloc.h>
|
||||
|
||||
extern "C" int usb_match_device(struct usb_device *dev,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
|
||||
id->idVendor != le16_to_cpu(dev->descriptor.idVendor))
|
||||
return 0;
|
||||
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
|
||||
id->idProduct != le16_to_cpu(dev->descriptor.idProduct))
|
||||
return 0;
|
||||
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
|
||||
(id->bcdDevice_lo > le16_to_cpu(dev->descriptor.bcdDevice)))
|
||||
return 0;
|
||||
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
|
||||
(id->bcdDevice_hi < le16_to_cpu(dev->descriptor.bcdDevice)))
|
||||
return 0;
|
||||
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
|
||||
(id->bDeviceClass != dev->descriptor.bDeviceClass))
|
||||
return 0;
|
||||
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
|
||||
(id->bDeviceSubClass != dev->descriptor.bDeviceSubClass))
|
||||
return 0;
|
||||
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
|
||||
(id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
extern "C" int usb_match_one_id_intf(struct usb_device *dev,
|
||||
struct usb_host_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
if (dev->descriptor.bDeviceClass == USB_CLASS_VENDOR_SPEC &&
|
||||
!(id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
|
||||
(id->match_flags & (USB_DEVICE_ID_MATCH_INT_CLASS |
|
||||
USB_DEVICE_ID_MATCH_INT_SUBCLASS |
|
||||
USB_DEVICE_ID_MATCH_INT_PROTOCOL |
|
||||
USB_DEVICE_ID_MATCH_INT_NUMBER)))
|
||||
return 0;
|
||||
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) &&
|
||||
(id->bInterfaceClass != intf->desc.bInterfaceClass))
|
||||
return 0;
|
||||
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_SUBCLASS) &&
|
||||
(id->bInterfaceSubClass != intf->desc.bInterfaceSubClass))
|
||||
return 0;
|
||||
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_PROTOCOL) &&
|
||||
(id->bInterfaceProtocol != intf->desc.bInterfaceProtocol))
|
||||
return 0;
|
||||
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_NUMBER) &&
|
||||
(id->bInterfaceNumber != intf->desc.bInterfaceNumber))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
struct Lx_driver
|
||||
{
|
||||
using Element = Genode::List_element<Lx_driver>;
|
||||
@ -93,12 +160,6 @@ void Driver::Device::probe_interface(usb_interface * iface, usb_device_id * id)
|
||||
void Driver::Device::remove_interface(usb_interface * iface)
|
||||
{
|
||||
hid_driver->disconnect(iface);
|
||||
for (unsigned i = 0; i < iface->num_altsetting; i++) {
|
||||
if (iface->altsetting[i].extra)
|
||||
kfree(iface->altsetting[i].extra);
|
||||
kfree(iface->altsetting[i].endpoint);
|
||||
kfree(iface->altsetting);
|
||||
}
|
||||
kfree(iface);
|
||||
}
|
||||
|
||||
@ -308,3 +369,185 @@ void *devm_kzalloc(struct device *dev, size_t size, gfp_t gfp)
|
||||
{
|
||||
return kzalloc(size, gfp);
|
||||
}
|
||||
|
||||
|
||||
int usb_get_descriptor(struct usb_device *dev, unsigned char type,
|
||||
unsigned char index, void *buf, int size)
|
||||
{
|
||||
int i;
|
||||
int result;
|
||||
|
||||
memset(buf, 0, size);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
struct usb_host_interface *usb_altnum_to_altsetting(const struct usb_interface *intf,
|
||||
unsigned int altnum)
|
||||
{
|
||||
for (unsigned i = 0; i < intf->num_altsetting; i++) {
|
||||
if (intf->altsetting[i].desc.bAlternateSetting == altnum)
|
||||
return &intf->altsetting[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
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 = (bus_type*) 0xdeadbeef /*&usb_bus_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;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -19,8 +19,6 @@
|
||||
|
||||
#include <lx_emul/extern_c_begin.h>
|
||||
|
||||
#define __KERNEL__ 1
|
||||
|
||||
#include <lx_emul/compiler.h>
|
||||
#include <lx_emul/printf.h>
|
||||
#include <lx_emul/types.h>
|
||||
@ -615,6 +613,13 @@ int module_wacom_driver_init();
|
||||
struct input_handle;
|
||||
void genode_evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value);
|
||||
|
||||
struct usb_device;
|
||||
extern int usb_get_configuration(struct usb_device *dev);
|
||||
|
||||
struct usb_hcd { unsigned amd_resume_bug:1; };
|
||||
|
||||
bool usb_device_is_owned(struct usb_device *udev);
|
||||
|
||||
#include <lx_emul/extern_c_end.h>
|
||||
|
||||
#endif /* _SRC__DRIVERS__USB_HID__LX_EMUL_H_ */
|
||||
|
@ -26,66 +26,7 @@
|
||||
#include <linux/usb.h>
|
||||
#include <lx_emul/extern_c_end.h>
|
||||
|
||||
void Driver::Device::scan_altsettings(usb_interface * iface,
|
||||
unsigned iface_idx, unsigned alt_idx)
|
||||
{
|
||||
Usb::Interface_descriptor iface_desc;
|
||||
usb.interface_descriptor(iface_idx, alt_idx, &iface_desc);
|
||||
Genode::memcpy(&iface->altsetting[alt_idx].desc, &iface_desc,
|
||||
sizeof(usb_interface_descriptor));
|
||||
if (iface_desc.active)
|
||||
iface->cur_altsetting = &iface->altsetting[alt_idx];
|
||||
|
||||
if (iface_desc.iclass == USB_CLASS_HID) {
|
||||
hid_descriptor * hd = (hid_descriptor*)
|
||||
kzalloc(sizeof(hid_descriptor), GFP_KERNEL);
|
||||
if (usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
|
||||
USB_REQ_GET_DESCRIPTOR,
|
||||
USB_RECIP_INTERFACE | USB_DIR_IN,
|
||||
(HID_DT_HID << 8), iface_idx, (void*)hd,
|
||||
sizeof(hid_descriptor), USB_CTRL_GET_TIMEOUT) < 0) {
|
||||
Genode::warning("could not get HID descriptor");
|
||||
} else {
|
||||
iface->altsetting[alt_idx].extra = (unsigned char*)hd;
|
||||
iface->altsetting[alt_idx].extralen = sizeof(hid_descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
iface->altsetting[alt_idx].endpoint = (usb_host_endpoint*)
|
||||
kzalloc(sizeof(usb_host_endpoint)*iface->altsetting[alt_idx].desc.bNumEndpoints, GFP_KERNEL);
|
||||
|
||||
for (unsigned i = 0; i < iface->altsetting[alt_idx].desc.bNumEndpoints; i++) {
|
||||
Usb::Endpoint_descriptor ep_desc;
|
||||
usb.endpoint_descriptor(iface_idx, alt_idx, i, &ep_desc);
|
||||
Genode::memcpy(&iface->altsetting[alt_idx].endpoint[i].desc,
|
||||
&ep_desc, sizeof(usb_endpoint_descriptor));
|
||||
int epnum = usb_endpoint_num(&iface->altsetting[alt_idx].endpoint[i].desc);
|
||||
if (usb_endpoint_dir_out(&iface->altsetting[alt_idx].endpoint[i].desc))
|
||||
udev->ep_out[epnum] = &iface->altsetting[alt_idx].endpoint[i];
|
||||
else
|
||||
udev->ep_in[epnum] = &iface->altsetting[alt_idx].endpoint[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Driver::Device::scan_interfaces(unsigned iface_idx)
|
||||
{
|
||||
struct usb_interface * iface =
|
||||
(usb_interface*) kzalloc(sizeof(usb_interface), GFP_KERNEL);
|
||||
iface->num_altsetting = usb.alt_settings(iface_idx);
|
||||
iface->altsetting = (usb_host_interface*)
|
||||
kzalloc(sizeof(usb_host_interface)*iface->num_altsetting, GFP_KERNEL);
|
||||
iface->dev.parent = &udev->dev;
|
||||
iface->dev.bus = (bus_type*) 0xdeadbeef;
|
||||
|
||||
for (unsigned i = 0; i < iface->num_altsetting; i++)
|
||||
scan_altsettings(iface, iface_idx, i);
|
||||
|
||||
struct usb_device_id id;
|
||||
probe_interface(iface, &id);
|
||||
udev->config->interface[iface_idx] = iface;
|
||||
};
|
||||
|
||||
extern "C" void usb_detect_interface_quirks(struct usb_device *udev);
|
||||
|
||||
void Driver::Device::register_device()
|
||||
{
|
||||
@ -103,13 +44,38 @@ void Driver::Device::register_device()
|
||||
udev->config = (usb_host_config*) kzalloc(sizeof(usb_host_config), GFP_KERNEL);
|
||||
udev->bus->bus_name = "usbbus";
|
||||
udev->bus->controller = (device*) (&usb);
|
||||
udev->bus_mA = 900; /* set to maximum USB3.0 */
|
||||
|
||||
udev->descriptor.idVendor = dev_desc.vendor_id;
|
||||
udev->descriptor.idProduct = dev_desc.product_id;
|
||||
udev->descriptor.bcdDevice = dev_desc.device_release;
|
||||
Genode::memcpy(&udev->descriptor, &dev_desc, sizeof(usb_device_descriptor));
|
||||
Genode::memcpy(&udev->config->desc, &config_desc, sizeof(usb_config_descriptor));
|
||||
udev->devnum = dev_desc.num;
|
||||
udev->speed = (usb_device_speed) dev_desc.speed;
|
||||
udev->authorized = 1;
|
||||
|
||||
for (unsigned i = 0; i < config_desc.num_interfaces; i++)
|
||||
scan_interfaces(i);
|
||||
int cfg = usb_get_configuration(udev);
|
||||
if (cfg < 0) {
|
||||
Genode::error("usb_get_configuration returned error ", cfg);
|
||||
return;
|
||||
}
|
||||
usb_detect_interface_quirks(udev);
|
||||
cfg = usb_choose_configuration(udev);
|
||||
usb_set_configuration(udev, cfg);
|
||||
|
||||
for (int i = 0; i < udev->config->desc.bNumInterfaces; i++) {
|
||||
struct usb_interface * iface = udev->config->interface[i];
|
||||
struct usb_host_interface * alt = iface->cur_altsetting;
|
||||
|
||||
for (int j = 0; j < alt->desc.bNumEndpoints; ++j) {
|
||||
struct usb_host_endpoint * ep = &alt->endpoint[j];
|
||||
int epnum = usb_endpoint_num(&ep->desc);
|
||||
int is_out = usb_endpoint_dir_out(&ep->desc);
|
||||
if (is_out) udev->ep_out[epnum] = ep;
|
||||
else udev->ep_in[epnum] = ep;
|
||||
}
|
||||
|
||||
struct usb_device_id id;
|
||||
probe_interface(iface, &id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -7,6 +7,7 @@ LIBS := base usb_hid_include lx_kit_setjmp
|
||||
|
||||
USB_CONTRIB_DIR := $(call select_from_ports,dde_linux)/src/drivers/usb_hid
|
||||
|
||||
INC_DIR += $(USB_CONTRIB_DIR)/drivers/usb/core
|
||||
INC_DIR += $(PRG_DIR)
|
||||
INC_DIR += $(REP_DIR)/src/include
|
||||
|
||||
@ -23,7 +24,11 @@ SRC_C += drivers/hid/usbhid/hid-core.c
|
||||
SRC_C += drivers/input/evdev.c
|
||||
SRC_C += drivers/input/input-mt.c
|
||||
SRC_C += drivers/input/input.c
|
||||
SRC_C += drivers/usb/core/config.c
|
||||
SRC_C += drivers/usb/core/generic.c
|
||||
SRC_C += drivers/usb/core/quirks.c
|
||||
|
||||
CC_OPT += -D__KERNEL__
|
||||
CC_C_OPT += -Wno-unused-but-set-variable -Wno-pointer-sign \
|
||||
-Wno-incompatible-pointer-types -Wno-unused-variable \
|
||||
-Wno-unused-function -Wno-uninitialized -Wno-maybe-uninitialized
|
||||
|
@ -16,6 +16,10 @@ linux-x.x.x/drivers/input/evdev.c
|
||||
linux-x.x.x/drivers/input/input-compat.h
|
||||
linux-x.x.x/drivers/input/input-mt.c
|
||||
linux-x.x.x/drivers/input/input.c
|
||||
linux-x.x.x/drivers/usb/core/config.c
|
||||
linux-x.x.x/drivers/usb/core/generic.c
|
||||
linux-x.x.x/drivers/usb/core/quirks.c
|
||||
linux-x.x.x/drivers/usb/core/usb.h
|
||||
linux-x.x.x/include/asm-generic/atomic64.h
|
||||
linux-x.x.x/include/asm-generic/bitops/__ffs.h
|
||||
linux-x.x.x/include/asm-generic/bitops/__fls.h
|
||||
@ -35,6 +39,7 @@ linux-x.x.x/include/linux/power_supply.h
|
||||
linux-x.x.x/include/linux/swab.h
|
||||
linux-x.x.x/include/linux/usb.h
|
||||
linux-x.x.x/include/linux/usb/ch9.h
|
||||
linux-x.x.x/include/linux/usb/quirks.h
|
||||
linux-x.x.x/include/uapi/linux/byteorder/little_endian.h
|
||||
linux-x.x.x/include/uapi/linux/hid.h
|
||||
linux-x.x.x/include/uapi/linux/input.h
|
||||
|
Loading…
Reference in New Issue
Block a user