Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
679685c315 | ||
|
|
d3102c8d7b | ||
|
|
051aebb340 | ||
|
|
c19cf8dd72 | ||
|
|
796a83018f | ||
|
|
5245848110 |
@@ -4,6 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <mouse.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <sysreset.h>
|
#include <sysreset.h>
|
||||||
@@ -67,15 +68,11 @@ static struct sdl_info {
|
|||||||
SDL_Renderer *renderer;
|
SDL_Renderer *renderer;
|
||||||
SDL_Window *screen;
|
SDL_Window *screen;
|
||||||
int src_depth;
|
int src_depth;
|
||||||
|
struct mouse_event mouse;
|
||||||
} sdl;
|
} sdl;
|
||||||
|
|
||||||
static void sandbox_sdl_poll_events(void)
|
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;
|
SDL_Event event;
|
||||||
|
|
||||||
while (SDL_PollEvent(&event)) {
|
while (SDL_PollEvent(&event)) {
|
||||||
@@ -84,10 +81,50 @@ static void sandbox_sdl_poll_events(void)
|
|||||||
puts("LCD window closed - quitting\n");
|
puts("LCD window closed - quitting\n");
|
||||||
sysreset_walk(SYSRESET_POWER_OFF);
|
sysreset_walk(SYSRESET_POWER_OFF);
|
||||||
break;
|
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)
|
static int sandbox_sdl_ensure_init(void)
|
||||||
{
|
{
|
||||||
if (!sdl.inited) {
|
if (!sdl.inited) {
|
||||||
@@ -521,6 +558,7 @@ int sandbox_sdl_sound_init(int rate, int channels)
|
|||||||
sdl.sample_rate = wanted.freq;
|
sdl.sample_rate = wanted.freq;
|
||||||
sdl.cur_buf = 0;
|
sdl.cur_buf = 0;
|
||||||
sdl.running = false;
|
sdl.running = false;
|
||||||
|
sdl.mouse.type = MOUSE_EV_NULL;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|||||||
@@ -203,6 +203,10 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mouse {
|
||||||
|
compatible = "sandbox,mouse";
|
||||||
|
};
|
||||||
|
|
||||||
pci@0 {
|
pci@0 {
|
||||||
pci@1e,0 {
|
pci@1e,0 {
|
||||||
compatible = "sandbox,pmc";
|
compatible = "sandbox,pmc";
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <video.h>
|
#include <video.h>
|
||||||
|
|
||||||
|
struct mouse_event;
|
||||||
|
|
||||||
#ifdef CONFIG_SANDBOX_SDL
|
#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_set_bpp(struct udevice *dev, enum video_log2_bpp l2bpp);
|
||||||
|
|
||||||
|
int sandbox_sdl_get_mouse_event(struct mouse_event *evt);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
static inline int sandbox_sdl_init_display(int width, int height, int log2_bpp,
|
static inline int sandbox_sdl_init_display(int width, int height, int log2_bpp,
|
||||||
bool double_size)
|
bool double_size)
|
||||||
|
|||||||
@@ -2934,6 +2934,15 @@ config CMD_LOG
|
|||||||
maximum log level for emitting of records). It also provides access
|
maximum log level for emitting of records). It also provides access
|
||||||
to a command used for testing the log system.
|
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
|
config CMD_TRACE
|
||||||
bool "trace - Support tracing of function calls and timing"
|
bool "trace - Support tracing of function calls and timing"
|
||||||
depends on TRACE
|
depends on TRACE
|
||||||
|
|||||||
@@ -128,6 +128,7 @@ obj-$(CONFIG_CMD_CLONE) += clone.o
|
|||||||
ifneq ($(CONFIG_CMD_NAND)$(CONFIG_CMD_SF),)
|
ifneq ($(CONFIG_CMD_NAND)$(CONFIG_CMD_SF),)
|
||||||
obj-y += legacy-mtd-utils.o
|
obj-y += legacy-mtd-utils.o
|
||||||
endif
|
endif
|
||||||
|
obj-$(CONFIG_CMD_MOUSE) += mouse.o
|
||||||
obj-$(CONFIG_CMD_MUX) += mux.o
|
obj-$(CONFIG_CMD_MUX) += mux.o
|
||||||
obj-$(CONFIG_CMD_NAND) += nand.o
|
obj-$(CONFIG_CMD_NAND) += nand.o
|
||||||
ifdef CONFIG_NET
|
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"
|
bool "Enable TWL4030 Input controller"
|
||||||
help
|
help
|
||||||
Enable TWL4030 Input controller
|
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_TEGRA_KEYBOARD) += input.o tegra-kbc.o
|
||||||
obj-$(CONFIG_TWL4030_INPUT) += twl4030.o
|
obj-$(CONFIG_TWL4030_INPUT) += twl4030.o
|
||||||
endif
|
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_MISC, /* Miscellaneous device */
|
||||||
UCLASS_MMC, /* SD / MMC card or chip */
|
UCLASS_MMC, /* SD / MMC card or chip */
|
||||||
UCLASS_MOD_EXP, /* RSA Mod Exp device */
|
UCLASS_MOD_EXP, /* RSA Mod Exp device */
|
||||||
|
UCLASS_MOUSE, /* Mouse, trackpad or other pointing device */
|
||||||
UCLASS_MTD, /* Memory Technology Device (MTD) device */
|
UCLASS_MTD, /* Memory Technology Device (MTD) device */
|
||||||
UCLASS_MUX, /* Multiplexer device */
|
UCLASS_MUX, /* Multiplexer device */
|
||||||
UCLASS_NOP, /* No-op devices */
|
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
|
* Appendix B of HID Device Class Definition 1.11
|
||||||
*/
|
*/
|
||||||
#define USB_KBD_BOOT_REPORT_SIZE 8
|
#define USB_KBD_BOOT_REPORT_SIZE 8
|
||||||
|
#define USB_MOUSE_BOOT_REPORT_SIZE 8
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* usb_init() - initialize the USB Controllers
|
* 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, ...);
|
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
|
#endif
|
||||||
|
|||||||
13
lib/Kconfig
13
lib/Kconfig
@@ -1246,6 +1246,19 @@ config PHANDLE_CHECK_SEQ
|
|||||||
enable this config option to distinguish them using
|
enable this config option to distinguish them using
|
||||||
phandles in fdtdec_get_alias_seq() function.
|
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
|
endmenu
|
||||||
|
|
||||||
source "lib/fwu_updates/Kconfig"
|
source "lib/fwu_updates/Kconfig"
|
||||||
|
|||||||
@@ -155,6 +155,7 @@ obj-y += vsprintf.o strto.o
|
|||||||
obj-$(CONFIG_SSCANF) += sscanf.o
|
obj-$(CONFIG_SSCANF) += sscanf.o
|
||||||
endif
|
endif
|
||||||
obj-$(CONFIG_$(PHASE_)OID_REGISTRY) += oid_registry.o
|
obj-$(CONFIG_$(PHASE_)OID_REGISTRY) += oid_registry.o
|
||||||
|
obj-$(CONFIG_FLOAT) += strtof.o
|
||||||
|
|
||||||
obj-y += abuf.o
|
obj-y += abuf.o
|
||||||
obj-y += alist.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