Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
679685c315 | ||
|
|
d3102c8d7b | ||
|
|
051aebb340 | ||
|
|
c19cf8dd72 | ||
|
|
796a83018f | ||
|
|
5245848110 |
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <mouse.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
#include <sysreset.h>
|
||||
@@ -67,15 +68,11 @@ static struct sdl_info {
|
||||
SDL_Renderer *renderer;
|
||||
SDL_Window *screen;
|
||||
int src_depth;
|
||||
struct mouse_event mouse;
|
||||
} sdl;
|
||||
|
||||
static void sandbox_sdl_poll_events(void)
|
||||
{
|
||||
/*
|
||||
* We don't want to include cpu_func.h in this file since it uses
|
||||
* system headers. So add a declation here.
|
||||
*/
|
||||
extern void reset_cpu(void);
|
||||
SDL_Event event;
|
||||
|
||||
while (SDL_PollEvent(&event)) {
|
||||
@@ -84,10 +81,50 @@ static void sandbox_sdl_poll_events(void)
|
||||
puts("LCD window closed - quitting\n");
|
||||
sysreset_walk(SYSRESET_POWER_OFF);
|
||||
break;
|
||||
case SDL_MOUSEMOTION: {
|
||||
struct mouse_event *m = &sdl.mouse;
|
||||
|
||||
m->type = MOUSE_EV_MOTION;
|
||||
m->motion.state = 0;
|
||||
m->motion.x = event.motion.x;
|
||||
m->motion.y = event.motion.y;
|
||||
m->motion.xrel = event.motion.xrel;
|
||||
m->motion.yrel = event.motion.yrel;
|
||||
break;
|
||||
}
|
||||
case SDL_MOUSEBUTTONDOWN :
|
||||
case SDL_MOUSEBUTTONUP : {
|
||||
struct mouse_event *m = &sdl.mouse;
|
||||
|
||||
m->type = MOUSE_EV_BUTTON;
|
||||
if (event.button.button == SDL_BUTTON_LEFT)
|
||||
m->button.button = BUTTON_LEFT;
|
||||
else if (event.button.button == SDL_BUTTON_MIDDLE)
|
||||
m->button.button = BUTTON_MIDDLE;
|
||||
else if (event.button.button == SDL_BUTTON_RIGHT)
|
||||
m->button.button = BUTTON_RIGHT;
|
||||
m->button.press_state = event.type ==
|
||||
SDL_MOUSEBUTTONDOWN ?
|
||||
BUTTON_PRESSED : BUTTON_RELEASED;
|
||||
m->button.x = event.button.x;
|
||||
m->button.y = event.motion.y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int sandbox_sdl_get_mouse_event(struct mouse_event *evt)
|
||||
{
|
||||
if (sdl.mouse.type == MOUSE_EV_NULL)
|
||||
return -EAGAIN;
|
||||
|
||||
*evt = sdl.mouse;
|
||||
sdl.mouse.type = MOUSE_EV_NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sandbox_sdl_ensure_init(void)
|
||||
{
|
||||
if (!sdl.inited) {
|
||||
@@ -521,6 +558,7 @@ int sandbox_sdl_sound_init(int rate, int channels)
|
||||
sdl.sample_rate = wanted.freq;
|
||||
sdl.cur_buf = 0;
|
||||
sdl.running = false;
|
||||
sdl.mouse.type = MOUSE_EV_NULL;
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -203,6 +203,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
mouse {
|
||||
compatible = "sandbox,mouse";
|
||||
};
|
||||
|
||||
pci@0 {
|
||||
pci@1e,0 {
|
||||
compatible = "sandbox,pmc";
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#include <errno.h>
|
||||
#include <video.h>
|
||||
|
||||
struct mouse_event;
|
||||
|
||||
#ifdef CONFIG_SANDBOX_SDL
|
||||
|
||||
/**
|
||||
@@ -104,6 +106,8 @@ int sandbox_sdl_sound_init(int rate, int channels);
|
||||
*/
|
||||
int sandbox_sdl_set_bpp(struct udevice *dev, enum video_log2_bpp l2bpp);
|
||||
|
||||
int sandbox_sdl_get_mouse_event(struct mouse_event *evt);
|
||||
|
||||
#else
|
||||
static inline int sandbox_sdl_init_display(int width, int height, int log2_bpp,
|
||||
bool double_size)
|
||||
|
||||
@@ -2934,6 +2934,15 @@ config CMD_LOG
|
||||
maximum log level for emitting of records). It also provides access
|
||||
to a command used for testing the log system.
|
||||
|
||||
config CMD_MOUSE
|
||||
bool "mouse - Show mouse input"
|
||||
default y if MOUSE
|
||||
help
|
||||
This shows the data produced by a mouse. If a mouse device is
|
||||
available records are printed when the mouse is moved. This can be
|
||||
useful for checking that a mouse is working correctly within
|
||||
U-Boot.
|
||||
|
||||
config CMD_TRACE
|
||||
bool "trace - Support tracing of function calls and timing"
|
||||
depends on TRACE
|
||||
|
||||
@@ -128,6 +128,7 @@ obj-$(CONFIG_CMD_CLONE) += clone.o
|
||||
ifneq ($(CONFIG_CMD_NAND)$(CONFIG_CMD_SF),)
|
||||
obj-y += legacy-mtd-utils.o
|
||||
endif
|
||||
obj-$(CONFIG_CMD_MOUSE) += mouse.o
|
||||
obj-$(CONFIG_CMD_MUX) += mux.o
|
||||
obj-$(CONFIG_CMD_NAND) += nand.o
|
||||
ifdef CONFIG_NET
|
||||
|
||||
70
cmd/mouse.c
Normal file
70
cmd/mouse.c
Normal file
@@ -0,0 +1,70 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Mouse testing
|
||||
*
|
||||
* Copyright 2020 Google LLC
|
||||
* Written by Simon Glass <sjg@chromium.org>
|
||||
*/
|
||||
|
||||
#include <command.h>
|
||||
#include <console.h>
|
||||
#include <dm.h>
|
||||
#include <mouse.h>
|
||||
#include <u-boot/schedule.h>
|
||||
|
||||
static int do_mouse_dump(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||
char *const argv[])
|
||||
{
|
||||
struct udevice *dev;
|
||||
bool running;
|
||||
int count;
|
||||
int ret;
|
||||
|
||||
ret = uclass_first_device_err(UCLASS_MOUSE, &dev);
|
||||
if (ret) {
|
||||
printf("Mouse not found (err=%d)\n", ret);
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
for (running = true, count = 0; running;) {
|
||||
struct mouse_event evt;
|
||||
|
||||
ret = mouse_get_event(dev, &evt);
|
||||
if (!ret) {
|
||||
switch (evt.type) {
|
||||
case MOUSE_EV_BUTTON: {
|
||||
struct mouse_button *but = &evt.button;
|
||||
|
||||
printf("button: button==%d, press=%d, clicks=%d, X=%d, Y=%d\n",
|
||||
but->button, but->press_state,
|
||||
but->clicks, but->x, but->y);
|
||||
break;
|
||||
}
|
||||
case MOUSE_EV_MOTION: {
|
||||
struct mouse_motion *motion = &evt.motion;
|
||||
printf("motion: Xrel=%d, Yrel=%d, X=%d, Y=%d, but=%d\n",
|
||||
motion->xrel, motion->yrel, motion->x,
|
||||
motion->y, motion->state);
|
||||
break;
|
||||
}
|
||||
case MOUSE_EV_NULL:
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
} else if (ret != -EAGAIN) {
|
||||
return log_msg_ret("get_event", ret);
|
||||
}
|
||||
schedule();
|
||||
if (ctrlc())
|
||||
running = false;
|
||||
}
|
||||
printf("%d events received\n", count);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static char mouse_help_text[] =
|
||||
"dump - Dump input from a mouse";
|
||||
|
||||
U_BOOT_CMD_WITH_SUBCMDS(mouse, "Mouse input", mouse_help_text,
|
||||
U_BOOT_SUBCMD_MKENT(dump, 1, 1, do_mouse_dump));
|
||||
@@ -100,3 +100,20 @@ config TWL4030_INPUT
|
||||
bool "Enable TWL4030 Input controller"
|
||||
help
|
||||
Enable TWL4030 Input controller
|
||||
|
||||
config MOUSE
|
||||
bool "Support for mice and other pointing devices"
|
||||
default y if SANDBOX
|
||||
help
|
||||
This allows U-Boot to access mouse input, typically needed for
|
||||
graphics boot menus and the like. The driver can provide mouse
|
||||
events based on user interaction and these can be used to control
|
||||
U-Boot's operation.
|
||||
|
||||
config USB_MOUSE
|
||||
bool "USB mouse support"
|
||||
help
|
||||
This enables using a USB mouse to control a feature in U-Boot,
|
||||
typically a boot menu. The driver uses the USB boot interface of
|
||||
the mouse and attempts to auto-configure itself for normal
|
||||
operation.
|
||||
|
||||
@@ -15,3 +15,7 @@ obj-$(CONFIG_I8042_KEYB) += i8042.o
|
||||
obj-$(CONFIG_TEGRA_KEYBOARD) += input.o tegra-kbc.o
|
||||
obj-$(CONFIG_TWL4030_INPUT) += twl4030.o
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_MOUSE) += mouse-uclass.o
|
||||
obj-$(CONFIG_SANDBOX) += sandbox_mouse.o
|
||||
obj-$(CONFIG_USB_MOUSE) += usb_mouse.o
|
||||
|
||||
28
drivers/input/mouse-uclass.c
Normal file
28
drivers/input/mouse-uclass.c
Normal file
@@ -0,0 +1,28 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2019 Google LLC
|
||||
* Written by Simon Glass <sjg@chromium.org>
|
||||
*/
|
||||
|
||||
#include <dm.h>
|
||||
#include <mouse.h>
|
||||
|
||||
int mouse_get_event(struct udevice *dev, struct mouse_event *evt)
|
||||
{
|
||||
struct mouse_ops *ops = mouse_get_ops(dev);
|
||||
int ret;
|
||||
|
||||
if (!ops->get_event)
|
||||
return -ENOSYS;
|
||||
|
||||
ret = ops->get_event(dev, evt);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
UCLASS_DRIVER(mouse) = {
|
||||
.id = UCLASS_MOUSE,
|
||||
.name = "mouse",
|
||||
};
|
||||
35
drivers/input/sandbox_mouse.c
Normal file
35
drivers/input/sandbox_mouse.c
Normal file
@@ -0,0 +1,35 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2020 Google LLC
|
||||
* Written by Simon Glass <sjg@chromium.org>
|
||||
*/
|
||||
|
||||
#include <dm.h>
|
||||
#include <mouse.h>
|
||||
#include <asm/sdl.h>
|
||||
|
||||
static int mouse_sandbox_get_event(struct udevice *dev,
|
||||
struct mouse_event *event)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = sandbox_sdl_get_mouse_event(event);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const struct mouse_ops mouse_sandbox_ops = {
|
||||
.get_event = mouse_sandbox_get_event,
|
||||
};
|
||||
|
||||
static const struct udevice_id mouse_sandbox_ids[] = {
|
||||
{ .compatible = "sandbox,mouse" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(mouse_sandbox) = {
|
||||
.name = "mouse_sandbox",
|
||||
.id = UCLASS_MOUSE,
|
||||
.of_match = mouse_sandbox_ids,
|
||||
.ops = &mouse_sandbox_ops,
|
||||
};
|
||||
327
drivers/input/usb_mouse.c
Normal file
327
drivers/input/usb_mouse.c
Normal file
@@ -0,0 +1,327 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* USB mouse driver (parts taken from usb_kbd.c)
|
||||
*
|
||||
* (C) Copyright 2001
|
||||
* Denis Peter, MPL AG Switzerland
|
||||
*
|
||||
* Part of this source has been derived from the Linux USB
|
||||
* project.
|
||||
*
|
||||
* Copyright 2020 Google LLC
|
||||
*/
|
||||
|
||||
#define LOG_CATEGORY UCLASS_MOUSE
|
||||
|
||||
#include <dm.h>
|
||||
#include <log.h>
|
||||
#include <malloc.h>
|
||||
#include <mouse.h>
|
||||
#include <usb.h>
|
||||
|
||||
enum {
|
||||
RPT_BUTTON,
|
||||
RPT_XREL,
|
||||
RPT_YREL,
|
||||
RPT_SCROLLY,
|
||||
};
|
||||
|
||||
struct usb_mouse_priv {
|
||||
unsigned long intpipe;
|
||||
int intpktsize;
|
||||
int intinterval;
|
||||
unsigned long last_report;
|
||||
struct int_queue *intq;
|
||||
|
||||
u32 repeat_delay;
|
||||
|
||||
int xrel;
|
||||
int yrel;
|
||||
int x;
|
||||
int y;
|
||||
int buttons;
|
||||
int old_buttons;
|
||||
int yscroll;
|
||||
/*
|
||||
* TODO(sjg@chromium.org): Use an array instead, with the
|
||||
* DM_FLAG_ALLOC_PRIV_DMA flag
|
||||
*/
|
||||
s8 *buf;
|
||||
|
||||
u8 flags;
|
||||
};
|
||||
|
||||
/* Interrupt service routine */
|
||||
static int usb_mouse_irq_worker(struct udevice *dev)
|
||||
{
|
||||
struct usb_mouse_priv *priv = dev_get_priv(dev);
|
||||
s8 *buf = priv->buf;
|
||||
|
||||
priv->buttons = buf[RPT_BUTTON];
|
||||
priv->xrel = buf[RPT_XREL];
|
||||
if (priv->xrel < -127)
|
||||
priv->xrel = 0;
|
||||
priv->yrel = buf[RPT_YREL];
|
||||
if (priv->yrel < -127)
|
||||
priv->yrel = 0;
|
||||
priv->yscroll = buf[RPT_SCROLLY];
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Mouse interrupt handler */
|
||||
static int usb_mouse_irq(struct usb_device *udev)
|
||||
{
|
||||
struct udevice *dev = udev->dev;
|
||||
|
||||
if (udev->irq_status || udev->irq_act_len != USB_MOUSE_BOOT_REPORT_SIZE) {
|
||||
log_warning("Error %lx, len %d\n", udev->irq_status,
|
||||
udev->irq_act_len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return usb_mouse_irq_worker(dev);
|
||||
}
|
||||
|
||||
/* Interrupt polling */
|
||||
static void usb_mouse_poll_for_event(struct udevice *dev)
|
||||
{
|
||||
struct usb_device *udev = dev_get_parent_priv(dev);
|
||||
struct usb_mouse_priv *priv = dev_get_priv(dev);
|
||||
int ret;
|
||||
|
||||
if (IS_ENABLED(CONFIG_SYS_USB_EVENT_POLL)) {
|
||||
/* Submit an interrupt transfer request */
|
||||
if (usb_int_msg(udev, priv->intpipe, priv->buf,
|
||||
priv->intpktsize, priv->intinterval, true) >= 0)
|
||||
usb_mouse_irq_worker(dev);
|
||||
} else if (IS_ENABLED(CONFIG_SYS_USB_EVENT_POLL_VIA_CONTROL_EP) ||
|
||||
IS_ENABLED(CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE)) {
|
||||
bool got_report = false;
|
||||
|
||||
if (IS_ENABLED(CONFIG_SYS_USB_EVENT_POLL_VIA_CONTROL_EP)) {
|
||||
struct usb_interface *iface;
|
||||
|
||||
iface = &udev->config.if_desc[0];
|
||||
ret = usb_get_report(udev, iface->desc.bInterfaceNumber,
|
||||
1, 0, priv->buf,
|
||||
USB_MOUSE_BOOT_REPORT_SIZE);
|
||||
printf("control ret=%d\b", ret);
|
||||
} else {
|
||||
if (poll_int_queue(udev, priv->intq)) {
|
||||
usb_mouse_irq_worker(dev);
|
||||
/* We've consumed all queued int packets, create new */
|
||||
destroy_int_queue(udev, priv->intq);
|
||||
priv->intq = create_int_queue(udev,
|
||||
priv->intpipe, 1,
|
||||
USB_MOUSE_BOOT_REPORT_SIZE, priv->buf,
|
||||
priv->intinterval);
|
||||
got_report = true;
|
||||
}
|
||||
}
|
||||
if (got_report)
|
||||
priv->last_report = get_timer(0);
|
||||
}
|
||||
}
|
||||
|
||||
static int usb_mouse_get_event(struct udevice *dev, struct mouse_event *event)
|
||||
{
|
||||
struct usb_mouse_priv *priv = dev_get_priv(dev);
|
||||
|
||||
if (priv->buttons != priv->old_buttons) {
|
||||
struct mouse_button *but = &event->button;
|
||||
u8 diff;
|
||||
int i;
|
||||
|
||||
event->type = MOUSE_EV_BUTTON;
|
||||
diff = priv->buttons ^ priv->old_buttons;
|
||||
log_debug("buttons=%d, old=%d, diff=%d\n", priv->buttons,
|
||||
priv->old_buttons, diff);
|
||||
for (i = 0; i < 3; i++) {
|
||||
u8 mask = 1 << i;
|
||||
|
||||
if (diff && mask) {
|
||||
but->button = i;
|
||||
but->press_state = priv->buttons & mask;
|
||||
but->clicks = 1;
|
||||
but->x = priv->x;
|
||||
but->y = priv->y;
|
||||
priv->old_buttons ^= mask;
|
||||
break;
|
||||
}
|
||||
}
|
||||
log_debug(" end: buttons=%d, old=%d, diff=%d\n", priv->buttons,
|
||||
priv->old_buttons, diff);
|
||||
} else if (priv->xrel || priv->yrel) {
|
||||
struct mouse_motion *motion = &event->motion;
|
||||
|
||||
priv->x += priv->xrel;
|
||||
priv->x = max(priv->x, 0);
|
||||
priv->x = min(priv->x, 0xffff);
|
||||
|
||||
priv->y += priv->yrel;
|
||||
priv->y = max(priv->y, 0);
|
||||
priv->y = min(priv->y, 0xffff);
|
||||
|
||||
event->type = MOUSE_EV_MOTION;
|
||||
motion->state = priv->buttons;
|
||||
motion->x = priv->x;
|
||||
motion->y = priv->y;
|
||||
motion->xrel = priv->xrel;
|
||||
motion->yrel = priv->yrel;
|
||||
priv->xrel = 0;
|
||||
priv->yrel = 0;
|
||||
} else {
|
||||
usb_mouse_poll_for_event(dev);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_mouse(struct usb_device *udev, int ifnum)
|
||||
{
|
||||
struct usb_endpoint_descriptor *ep;
|
||||
struct usb_interface *iface;
|
||||
|
||||
if (udev->descriptor.bNumConfigurations != 1)
|
||||
return log_msg_ret("numcfg", -EINVAL);
|
||||
|
||||
iface = &udev->config.if_desc[ifnum];
|
||||
|
||||
if (iface->desc.bInterfaceClass != USB_CLASS_HID)
|
||||
return log_msg_ret("if class", -EINVAL);
|
||||
|
||||
if (iface->desc.bInterfaceSubClass != USB_SUB_HID_BOOT)
|
||||
return log_msg_ret("if subclass", -EINVAL);
|
||||
|
||||
if (iface->desc.bInterfaceProtocol != USB_PROT_HID_MOUSE)
|
||||
return log_msg_ret("if protocol", -EINVAL);
|
||||
|
||||
if (iface->desc.bNumEndpoints != 1)
|
||||
return log_msg_ret("num endpoints", -EINVAL);
|
||||
|
||||
ep = &iface->ep_desc[0];
|
||||
|
||||
/* Check if endpoint 1 is interrupt endpoint */
|
||||
if (!(ep->bEndpointAddress & 0x80))
|
||||
return log_msg_ret("ep not irq", -EINVAL);
|
||||
|
||||
if ((ep->bmAttributes & 3) != 3)
|
||||
return log_msg_ret("ep attr", -EINVAL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* probes the USB device dev for mouse type */
|
||||
static int usb_mouse_probe(struct udevice *dev)
|
||||
{
|
||||
struct usb_device *udev = dev_get_parent_priv(dev);
|
||||
struct usb_mouse_priv *priv = dev_get_priv(dev);
|
||||
struct usb_endpoint_descriptor *ep;
|
||||
struct usb_interface *iface;
|
||||
const int ifnum = 0;
|
||||
int ret;
|
||||
|
||||
ret = check_mouse(udev, ifnum);
|
||||
if (ret) {
|
||||
log_warning("Mouse detect fail (err=%d)\n", ret);
|
||||
return log_msg_ret("probe", ret);
|
||||
}
|
||||
log_debug("USB mouse: found set protocol...\n");
|
||||
|
||||
/* allocate input buffer aligned and sized to USB DMA alignment */
|
||||
priv->buf = memalign(USB_DMA_MINALIGN,
|
||||
roundup(USB_MOUSE_BOOT_REPORT_SIZE, USB_DMA_MINALIGN));
|
||||
|
||||
/* Insert private data into USB device structure */
|
||||
udev->privptr = priv;
|
||||
|
||||
/* Set IRQ handler */
|
||||
udev->irq_handle = usb_mouse_irq;
|
||||
|
||||
iface = &udev->config.if_desc[ifnum];
|
||||
ep = &iface->ep_desc[0];
|
||||
priv->intpipe = usb_rcvintpipe(udev, ep->bEndpointAddress);
|
||||
priv->intpktsize = min(usb_maxpacket(udev, priv->intpipe),
|
||||
USB_MOUSE_BOOT_REPORT_SIZE);
|
||||
priv->intinterval = ep->bInterval;
|
||||
priv->last_report = -1;
|
||||
|
||||
/* We found a USB Keyboard, install it. */
|
||||
usb_set_protocol(udev, iface->desc.bInterfaceNumber, 0);
|
||||
|
||||
log_debug("Found set idle...\n");
|
||||
usb_set_idle(udev, iface->desc.bInterfaceNumber, 0, 0);
|
||||
|
||||
log_debug("Enable interrupt pipe...\n");
|
||||
if (IS_ENABLED(CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE)) {
|
||||
priv->intq = create_int_queue(udev, priv->intpipe, 1,
|
||||
USB_MOUSE_BOOT_REPORT_SIZE,
|
||||
priv->buf, priv->intinterval);
|
||||
printf("priv->intq %p\n", priv->intq);
|
||||
ret = priv->intq ? 0 : -EBUSY;
|
||||
} else if (IS_ENABLED(CONFIG_SYS_USB_EVENT_POLL_VIA_CONTROL_EP)) {
|
||||
ret = usb_get_report(udev, iface->desc.bInterfaceNumber, 1, 0,
|
||||
priv->buf, USB_MOUSE_BOOT_REPORT_SIZE);
|
||||
} else {
|
||||
ret = usb_int_msg(udev, priv->intpipe, priv->buf,
|
||||
priv->intpktsize, priv->intinterval, false);
|
||||
}
|
||||
if (ret < 0) {
|
||||
log_warning("Failed to get mouse state from device %04x:%04x (err=%d)\n",
|
||||
udev->descriptor.idVendor,
|
||||
udev->descriptor.idProduct, ret);
|
||||
/* Abort, we don't want to use that non-functional keyboard */
|
||||
return ret;
|
||||
}
|
||||
log_info("USB mouse OK\n");
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usb_mouse_remove(struct udevice *dev)
|
||||
{
|
||||
struct usb_device *udev = dev_get_parent_priv(dev);
|
||||
struct usb_mouse_priv *priv = dev_get_priv(dev);
|
||||
|
||||
if (IS_ENABLED(CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE))
|
||||
destroy_int_queue(udev, priv->intq);
|
||||
free(priv->buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct mouse_ops usb_mouse_ops = {
|
||||
.get_event = usb_mouse_get_event,
|
||||
};
|
||||
|
||||
static const struct udevice_id usb_mouse_ids[] = {
|
||||
{ .compatible = "usb-mouse" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(usb_mouse) = {
|
||||
.name = "usb_mouse",
|
||||
.id = UCLASS_MOUSE,
|
||||
.of_match = usb_mouse_ids,
|
||||
.ops = &usb_mouse_ops,
|
||||
.probe = usb_mouse_probe,
|
||||
.remove = usb_mouse_remove,
|
||||
.priv_auto = sizeof(struct usb_mouse_priv),
|
||||
};
|
||||
|
||||
static const struct usb_device_id mouse_id_table[] = {
|
||||
{
|
||||
.match_flags = USB_DEVICE_ID_MATCH_INT_CLASS |
|
||||
USB_DEVICE_ID_MATCH_INT_SUBCLASS |
|
||||
USB_DEVICE_ID_MATCH_INT_PROTOCOL,
|
||||
.bInterfaceClass = USB_CLASS_HID,
|
||||
.bInterfaceSubClass = USB_SUB_HID_BOOT,
|
||||
.bInterfaceProtocol = USB_PROT_HID_MOUSE,
|
||||
},
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
|
||||
U_BOOT_USB_DEVICE(usb_mouse, mouse_id_table);
|
||||
@@ -97,6 +97,7 @@ enum uclass_id {
|
||||
UCLASS_MISC, /* Miscellaneous device */
|
||||
UCLASS_MMC, /* SD / MMC card or chip */
|
||||
UCLASS_MOD_EXP, /* RSA Mod Exp device */
|
||||
UCLASS_MOUSE, /* Mouse, trackpad or other pointing device */
|
||||
UCLASS_MTD, /* Memory Technology Device (MTD) device */
|
||||
UCLASS_MUX, /* Multiplexer device */
|
||||
UCLASS_NOP, /* No-op devices */
|
||||
|
||||
78
include/mouse.h
Normal file
78
include/mouse.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Mouse/trackpad/touchscreen input uclass
|
||||
*
|
||||
* Copyright 2020 Google LLC
|
||||
*/
|
||||
|
||||
#ifndef _MOUSE_H
|
||||
#define _MOUSE_H
|
||||
|
||||
enum mouse_ev_t {
|
||||
MOUSE_EV_NULL,
|
||||
MOUSE_EV_MOTION,
|
||||
MOUSE_EV_BUTTON,
|
||||
};
|
||||
|
||||
enum mouse_state_t {
|
||||
BUTTON_LEFT = 1 << 0,
|
||||
BUTTON_MIDDLE = 1 << 1,
|
||||
BUTTON_RIGHT = 1 << 2,
|
||||
BUTTON_SCROLL_PLUS = 1 << 3,
|
||||
BUTTON_SCROLL_MINUS = 1 << 4,
|
||||
};
|
||||
|
||||
enum mouse_press_state_t {
|
||||
BUTTON_RELEASED = 0,
|
||||
BUTTON_PRESSED,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mouse_event - information about a mouse event
|
||||
*
|
||||
* @type: Mouse event ype
|
||||
*/
|
||||
struct mouse_event {
|
||||
enum mouse_ev_t type;
|
||||
union {
|
||||
/**
|
||||
* @state: Mouse state (enum mouse_state_t bitmask)
|
||||
* @x: X position of mouse
|
||||
* @y: Y position of mouse
|
||||
* @xrel: Relative motion in X direction
|
||||
* @yrel: Relative motion in Y direction
|
||||
*/
|
||||
struct mouse_motion {
|
||||
unsigned char state;
|
||||
unsigned short x;
|
||||
unsigned short y;
|
||||
short xrel;
|
||||
short yrel;
|
||||
} motion;
|
||||
|
||||
/**
|
||||
* @button: Button number that was pressed/released (BUTTON_...)
|
||||
* @state: BUTTON_PRESSED / BUTTON_RELEASED
|
||||
* @clicks: number of clicks (normally 1; 2 = double-click)
|
||||
* @x: X position of mouse
|
||||
* @y: Y position of mouse
|
||||
*/
|
||||
struct mouse_button {
|
||||
unsigned char button;
|
||||
unsigned char press_state;
|
||||
unsigned char clicks;
|
||||
unsigned short x;
|
||||
unsigned short y;
|
||||
} button;
|
||||
};
|
||||
};
|
||||
|
||||
struct mouse_ops {
|
||||
int (*get_event)(struct udevice *dev, struct mouse_event *event);
|
||||
};
|
||||
|
||||
#define mouse_get_ops(dev) ((struct mouse_ops *)(dev)->driver->ops)
|
||||
|
||||
int mouse_get_event(struct udevice *dev, struct mouse_event *event);
|
||||
|
||||
#endif
|
||||
@@ -255,6 +255,7 @@ int usb_host_eth_scan(int mode);
|
||||
* Appendix B of HID Device Class Definition 1.11
|
||||
*/
|
||||
#define USB_KBD_BOOT_REPORT_SIZE 8
|
||||
#define USB_MOUSE_BOOT_REPORT_SIZE 8
|
||||
|
||||
/*
|
||||
* usb_init() - initialize the USB Controllers
|
||||
|
||||
@@ -364,4 +364,29 @@ int vsscanf(const char *inp, char const *fmt0, va_list ap);
|
||||
*/
|
||||
int sscanf(const char *buf, const char *fmt, ...);
|
||||
|
||||
/**
|
||||
* strtod() - Convert text floating-point number to double
|
||||
*
|
||||
* @str: String to convert
|
||||
* @entptr: If non-NULL, set to point to the character after the last one that
|
||||
* was part of the floating-point number
|
||||
* @return double-precision floating-point representation of the characters in
|
||||
* @str.
|
||||
*/
|
||||
double strtod(const char *str, char **endptr);
|
||||
|
||||
/**
|
||||
* strtod() - Convert text floating-point number to double
|
||||
*
|
||||
* @str: decimal ASCII floating-point number, optionally preceded by whitespace.
|
||||
* Must have form "-I.FE-X", where I is the integer part of the mantissa, F is
|
||||
* the fractional part of the mantissa, and X is the exponent. Either of the
|
||||
* signs may be "+", "-", or omitted. Either I or F may be omitted, or both.
|
||||
* The decimal point isn't necessary unless F is present. The "E" may actually
|
||||
* be an "e". E and X may both be omitted (but not just one).
|
||||
* @return double-precision floating-point representation of the characters in
|
||||
* @str.
|
||||
*/
|
||||
double atof(const char *str);
|
||||
|
||||
#endif
|
||||
|
||||
13
lib/Kconfig
13
lib/Kconfig
@@ -1246,6 +1246,19 @@ config PHANDLE_CHECK_SEQ
|
||||
enable this config option to distinguish them using
|
||||
phandles in fdtdec_get_alias_seq() function.
|
||||
|
||||
config FLOAT
|
||||
bool "Support floating-point functions"
|
||||
help
|
||||
U-Boot does not normally make use of floating point and it is
|
||||
generally possible and desirable to avoid it within a bootloader.
|
||||
|
||||
However there are libraries which need it. For example, U-Boot's
|
||||
Truetype font implementation needs floating point and some features
|
||||
such as the Nuklear GUI make use of it also.
|
||||
|
||||
Enable this to compile in some basic library functions for floating
|
||||
point.
|
||||
|
||||
endmenu
|
||||
|
||||
source "lib/fwu_updates/Kconfig"
|
||||
|
||||
@@ -155,6 +155,7 @@ obj-y += vsprintf.o strto.o
|
||||
obj-$(CONFIG_SSCANF) += sscanf.o
|
||||
endif
|
||||
obj-$(CONFIG_$(PHASE_)OID_REGISTRY) += oid_registry.o
|
||||
obj-$(CONFIG_FLOAT) += strtof.o
|
||||
|
||||
obj-y += abuf.o
|
||||
obj-y += alist.o
|
||||
|
||||
200
lib/strtof.c
Normal file
200
lib/strtof.c
Normal file
@@ -0,0 +1,200 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 1988-1993 The Regents of the University of California.
|
||||
* Copyright (c) 1994 Sun Microsystems, Inc.
|
||||
* Copyright 2020 Google LLC
|
||||
* Relicensed as GPL-2.0+ for U-Boot
|
||||
*
|
||||
* Modified from commit fae05bc at::
|
||||
* github.com/embeddedartistry/embedded-resources/tree/master/examples/libc/stdlib
|
||||
*/
|
||||
|
||||
#include <linux/ctype.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/*
|
||||
* Largest possible base--10 exponent. Any exponent larger than this will
|
||||
* already produce underflow or overflow, so there's no need to worry about
|
||||
* additional digits.
|
||||
*/
|
||||
static int maxExponent = 511;
|
||||
|
||||
/*
|
||||
* Table giving binary powers of 10. Entry is 10^2^i. Used to convert decimal
|
||||
* exponents into floating-point numbers
|
||||
*/
|
||||
static double powersOf10[] = {
|
||||
1.0e4,
|
||||
1.0e8,
|
||||
1.0e16,
|
||||
1.0e32,
|
||||
1.0e64,
|
||||
1.0e128,
|
||||
1.0e256
|
||||
};
|
||||
|
||||
/*
|
||||
* Details on @str:
|
||||
*/
|
||||
double strtod(const char *string, char **endptr)
|
||||
{
|
||||
int sign, expsign = false;
|
||||
double fraction, dblexp, *d;
|
||||
const char * p;
|
||||
int c;
|
||||
int exp = 0; /* Exponent read from "EX" field */
|
||||
/*
|
||||
* Exponent that derives from the fractional part. Under normal
|
||||
* circumstatnces, it is the negative of the number of digits in F.
|
||||
* However if I is very long, the last digits of I get dropped
|
||||
* (otherwise a long I with a large negative exponent could cause an
|
||||
* unnecessary overflow on I alone). In this case, fracexp is
|
||||
* incremented one for each dropped digit.
|
||||
*/
|
||||
int fracexp = 0;
|
||||
int mantsize; /* Number of digits in mantissa */
|
||||
int decpt; /* Number of mantissa digits BEFORE decimal point */
|
||||
/* Temporarily holds location of exponent in string */
|
||||
const char* pexp;
|
||||
|
||||
/* Strip off leading blanks and check for a sign */
|
||||
p = string;
|
||||
while (isspace(*p))
|
||||
p += 1;
|
||||
if (*p == '-') {
|
||||
sign = true;
|
||||
p += 1;
|
||||
} else {
|
||||
if (*p == '+')
|
||||
p += 1;
|
||||
sign = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Count the number of digits in the mantissa (including the decimal
|
||||
* point), and also locate the decimal point.
|
||||
*/
|
||||
decpt = -1;
|
||||
for (mantsize = 0;; mantsize += 1) {
|
||||
c = *p;
|
||||
if (!isdigit(c)) {
|
||||
if (c != '.' || decpt >= 0)
|
||||
break;
|
||||
decpt = mantsize;
|
||||
}
|
||||
p += 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now suck up the digits in the mantissa. Use two integers to
|
||||
* collect 9 digits each (this is faster than using floating-point).
|
||||
* If the mantissa has more than 18 digits, ignore the extras, since
|
||||
* they can't affect the value anyway.
|
||||
*/
|
||||
pexp = p;
|
||||
p -= mantsize;
|
||||
if (decpt < 0)
|
||||
decpt = mantsize;
|
||||
else
|
||||
mantsize -= 1; /* One of the digits was the point */
|
||||
if (mantsize > 18) {
|
||||
fracexp = decpt - 18;
|
||||
mantsize = 18;
|
||||
} else {
|
||||
fracexp = decpt - mantsize;
|
||||
}
|
||||
if (!mantsize) {
|
||||
fraction = 0.0;
|
||||
p = string;
|
||||
goto done;
|
||||
} else {
|
||||
int frac1, frac2;
|
||||
|
||||
frac1 = 0;
|
||||
for (; mantsize > 9; mantsize -= 1) {
|
||||
c = *p;
|
||||
p += 1;
|
||||
if (c == '.') {
|
||||
c = *p;
|
||||
p += 1;
|
||||
}
|
||||
frac1 = 10 * frac1 + (c - '0');
|
||||
}
|
||||
frac2 = 0;
|
||||
for (; mantsize > 0; mantsize -= 1) {
|
||||
c = *p;
|
||||
p += 1;
|
||||
if (c == '.') {
|
||||
c = *p;
|
||||
p += 1;
|
||||
}
|
||||
frac2 = 10 * frac2 + (c - '0');
|
||||
}
|
||||
fraction = (1.0e9 * frac1) + frac2;
|
||||
}
|
||||
|
||||
/* Skim off the exponent */
|
||||
p = pexp;
|
||||
if (*p == 'E' || *p == 'e') {
|
||||
p += 1;
|
||||
if (*p == '-') {
|
||||
expsign = true;
|
||||
p += 1;
|
||||
} else {
|
||||
if (*p == '+')
|
||||
p += 1;
|
||||
expsign = false;
|
||||
}
|
||||
if (!isdigit(*p)) {
|
||||
p = pexp;
|
||||
goto done;
|
||||
}
|
||||
while(isdigit(*p)) {
|
||||
exp = exp * 10 + (*p - '0');
|
||||
p += 1;
|
||||
}
|
||||
}
|
||||
if (expsign)
|
||||
exp = fracexp - exp;
|
||||
else
|
||||
exp = fracexp + exp;
|
||||
|
||||
/*
|
||||
* Generate a floating-point number that represents the exponent.
|
||||
* Do this by processing the exponent one bit at a time to combine
|
||||
* many powers of 2 of 10. Then combine the exponent with the
|
||||
* fraction.
|
||||
*/
|
||||
if (exp < 0) {
|
||||
expsign = true;
|
||||
exp = -exp;
|
||||
} else {
|
||||
expsign = false;
|
||||
}
|
||||
if (exp > maxExponent)
|
||||
exp = maxExponent; /* errno = ERANGE; */
|
||||
dblexp = 1.0;
|
||||
for (d = powersOf10; exp != 0; exp >>= 1, d += 1) {
|
||||
if (exp & 01)
|
||||
dblexp *= *d;
|
||||
}
|
||||
if (expsign)
|
||||
fraction /= dblexp;
|
||||
else
|
||||
fraction *= dblexp;
|
||||
|
||||
done:
|
||||
if (endptr)
|
||||
*endptr = (char*)p;
|
||||
|
||||
if (sign)
|
||||
return -fraction;
|
||||
|
||||
return fraction;
|
||||
}
|
||||
|
||||
double atof(const char *str)
|
||||
{
|
||||
return strtod(str, NULL);
|
||||
}
|
||||
Reference in New Issue
Block a user