Compare commits
49 Commits
vfio-pci-f
...
pull-input
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2082bac151 | ||
|
|
90525fe279 | ||
|
|
3503206a90 | ||
|
|
2deb4acc7c | ||
|
|
5a165668e7 | ||
|
|
2e377f1730 | ||
|
|
be1a717624 | ||
|
|
e00fcfeab3 | ||
|
|
278073ba29 | ||
|
|
82ea61c6da | ||
|
|
1673e89e93 | ||
|
|
3257fc8383 | ||
|
|
36f5db59cf | ||
|
|
7bafd8889e | ||
|
|
b52991537c | ||
|
|
4006617552 | ||
|
|
cf864569cd | ||
|
|
7bd3055ffd | ||
|
|
b791c3b38c | ||
|
|
322fd1f4f7 | ||
|
|
b88a3e01f5 | ||
|
|
d81d410635 | ||
|
|
381626a969 | ||
|
|
95dd1c4d7a | ||
|
|
9a1d111e70 | ||
|
|
ad489e9346 | ||
|
|
f2335791fd | ||
|
|
363f59d9e4 | ||
|
|
bdef972474 | ||
|
|
50ef467923 | ||
|
|
f72b49398f | ||
|
|
9bb931802e | ||
|
|
55d492d760 | ||
|
|
c13959c745 | ||
|
|
675036e4da | ||
|
|
bb9cd2ee99 | ||
|
|
2df5fee2db | ||
|
|
b122c3b6d0 | ||
|
|
6262bbd363 | ||
|
|
f25391c2a6 | ||
|
|
3cb0e25c4b | ||
|
|
6376f95223 | ||
|
|
543f7bef13 | ||
|
|
29f2601aa6 | ||
|
|
443422fde7 | ||
|
|
b20e61e0d5 | ||
|
|
a1904e48c4 | ||
|
|
75e347d66a | ||
|
|
ebee92b4fe |
1
block.c
1
block.c
@@ -1228,6 +1228,7 @@ int bdrv_open_image(BlockDriverState **pbs, const char *filename,
|
||||
bdref_key);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
QDECREF(image_options);
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
||||
@@ -475,6 +475,7 @@ static void dump_qobject(fprintf_function func_fprintf, void *f,
|
||||
case QTYPE_QERROR: {
|
||||
QString *value = qerror_human((QError *)obj);
|
||||
func_fprintf(f, "%s", qstring_get_str(value));
|
||||
QDECREF(value);
|
||||
break;
|
||||
}
|
||||
case QTYPE_NONE:
|
||||
|
||||
@@ -1308,6 +1308,7 @@ static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp)
|
||||
options = qdict_clone_shallow(bs->options);
|
||||
|
||||
ret = qcow2_open(bs, options, flags, &local_err);
|
||||
QDECREF(options);
|
||||
if (local_err) {
|
||||
error_setg(errp, "Could not reopen qcow2 layer: %s",
|
||||
error_get_pretty(local_err));
|
||||
@@ -1318,8 +1319,6 @@ static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
QDECREF(options);
|
||||
|
||||
if (crypt_method) {
|
||||
s->crypt_method = crypt_method;
|
||||
memcpy(&s->aes_encrypt_key, &aes_encrypt_key, sizeof(aes_encrypt_key));
|
||||
|
||||
@@ -1192,7 +1192,7 @@ again:
|
||||
if (size == 0)
|
||||
#endif
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
size = LONG_LONG_MAX;
|
||||
size = LLONG_MAX;
|
||||
#else
|
||||
size = lseek(fd, 0LL, SEEK_END);
|
||||
#endif
|
||||
|
||||
@@ -2176,6 +2176,7 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
|
||||
strncpy(s->inode.tag, sn_info->name, sizeof(s->inode.tag));
|
||||
/* we don't need to update entire object */
|
||||
datalen = SD_INODE_SIZE - sizeof(s->inode.data_vdi_id);
|
||||
inode = g_malloc(datalen);
|
||||
|
||||
/* refresh inode. */
|
||||
fd = connect_to_sdog(s, &local_err);
|
||||
@@ -2202,8 +2203,6 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
inode = (SheepdogInode *)g_malloc(datalen);
|
||||
|
||||
ret = read_object(fd, (char *)inode, vid_to_vdi_oid(new_vid),
|
||||
s->inode.nr_copies, datalen, 0, s->cache_flags);
|
||||
|
||||
@@ -2217,6 +2216,7 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
|
||||
s->inode.name, s->inode.snap_id, s->inode.vdi_id);
|
||||
|
||||
cleanup:
|
||||
g_free(inode);
|
||||
closesocket(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1534,7 +1534,7 @@ static int vmdk_create_extent(const char *filename, int64_t filesize,
|
||||
int ret, i;
|
||||
BlockDriverState *bs = NULL;
|
||||
VMDK4Header header;
|
||||
Error *local_err;
|
||||
Error *local_err = NULL;
|
||||
uint32_t tmp, magic, grains, gd_sectors, gt_size, gt_count;
|
||||
uint32_t *gd_buf = NULL;
|
||||
int gd_buf_size;
|
||||
@@ -1700,7 +1700,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
|
||||
{
|
||||
int idx = 0;
|
||||
BlockDriverState *new_bs = NULL;
|
||||
Error *local_err;
|
||||
Error *local_err = NULL;
|
||||
char *desc = NULL;
|
||||
int64_t total_size = 0, filesize;
|
||||
const char *adapter_type = NULL;
|
||||
@@ -1881,7 +1881,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
|
||||
} else {
|
||||
ret = bdrv_create_file(filename, options, &local_err);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Could not create image file");
|
||||
error_propagate(errp, local_err);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
@@ -1889,7 +1889,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
|
||||
ret = bdrv_open(&new_bs, filename, NULL, NULL,
|
||||
BDRV_O_RDWR | BDRV_O_PROTOCOL, NULL, &local_err);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Could not write description");
|
||||
error_propagate(errp, local_err);
|
||||
goto exit;
|
||||
}
|
||||
ret = bdrv_pwrite(new_bs, desc_offset, desc, desc_len);
|
||||
|
||||
@@ -787,7 +787,9 @@ static int read_directory(BDRVVVFATState* s, int mapping_index)
|
||||
s->current_mapping->path=buffer;
|
||||
s->current_mapping->read_only =
|
||||
(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0;
|
||||
}
|
||||
} else {
|
||||
g_free(buffer);
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
@@ -1866,7 +1868,7 @@ static int check_directory_consistency(BDRVVVFATState *s,
|
||||
|
||||
if (s->used_clusters[cluster_num] & USED_ANY) {
|
||||
fprintf(stderr, "cluster %d used more than once\n", (int)cluster_num);
|
||||
return 0;
|
||||
goto fail;
|
||||
}
|
||||
s->used_clusters[cluster_num] = USED_DIRECTORY;
|
||||
|
||||
@@ -2929,6 +2931,7 @@ static int enable_write_target(BDRVVVFATState *s, Error **errp)
|
||||
set_option_parameter(options, BLOCK_OPT_BACKING_FILE, "fat:");
|
||||
|
||||
ret = bdrv_create(bdrv_qcow, s->qcow_filename, options, errp);
|
||||
free_option_parameters(options);
|
||||
if (ret < 0) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -351,7 +351,7 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
|
||||
opts = qemu_opts_create(&qemu_common_drive_opts, id, 1, &error);
|
||||
if (error) {
|
||||
error_propagate(errp, error);
|
||||
return NULL;
|
||||
goto err_no_opts;
|
||||
}
|
||||
|
||||
qemu_opts_absorb_qdict(opts, bs_opts, &error);
|
||||
@@ -564,8 +564,9 @@ bdrv_new_err:
|
||||
g_free(dinfo->id);
|
||||
g_free(dinfo);
|
||||
early_err:
|
||||
QDECREF(bs_opts);
|
||||
qemu_opts_del(opts);
|
||||
err_no_opts:
|
||||
QDECREF(bs_opts);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -939,6 +940,7 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
|
||||
|
||||
/* Actual block device init: Functionality shared with blockdev-add */
|
||||
dinfo = blockdev_init(filename, bs_opts, &local_err);
|
||||
bs_opts = NULL;
|
||||
if (dinfo == NULL) {
|
||||
if (local_err) {
|
||||
error_report("%s", error_get_pretty(local_err));
|
||||
@@ -976,6 +978,7 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
|
||||
|
||||
fail:
|
||||
qemu_opts_del(legacy_opts);
|
||||
QDECREF(bs_opts);
|
||||
return dinfo;
|
||||
}
|
||||
|
||||
|
||||
@@ -183,7 +183,7 @@ int loader_exec(const char * filename, char ** argv, char ** envp,
|
||||
&& bprm.buf[3] == 'F') {
|
||||
retval = load_elf_binary(&bprm,regs,infop);
|
||||
} else {
|
||||
error_report("Unknown binary format");
|
||||
fprintf(stderr, "Unknown binary format\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -628,7 +628,7 @@ static abi_ulong copy_elf_strings(int argc,char ** argv, void **page,
|
||||
while (argc-- > 0) {
|
||||
tmp = argv[argc];
|
||||
if (!tmp) {
|
||||
error_report("VFS: argc is wrong");
|
||||
fprintf(stderr, "VFS: argc is wrong");
|
||||
exit(-1);
|
||||
}
|
||||
tmp1 = tmp;
|
||||
|
||||
@@ -378,8 +378,8 @@ void cpu_loop(CPUX86State *env)
|
||||
#endif
|
||||
default:
|
||||
pc = env->segs[R_CS].base + env->eip;
|
||||
error_report("qemu: 0x%08lx: unhandled CPU exception 0x%x"
|
||||
" - aborting", (long)pc, trapnr);
|
||||
fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
|
||||
(long)pc, trapnr);
|
||||
abort();
|
||||
}
|
||||
process_pending_signals(env);
|
||||
@@ -752,7 +752,7 @@ int main(int argc, char **argv)
|
||||
module_call_init(MODULE_INIT_QOM);
|
||||
|
||||
if ((envlist = envlist_create()) == NULL) {
|
||||
error_report("Unable to allocate envlist");
|
||||
(void) fprintf(stderr, "Unable to allocate envlist\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -794,7 +794,7 @@ int main(int argc, char **argv)
|
||||
} else if (!strcmp(r, "ignore-environment")) {
|
||||
envlist_free(envlist);
|
||||
if ((envlist = envlist_create()) == NULL) {
|
||||
error_report("Unable to allocate envlist");
|
||||
(void) fprintf(stderr, "Unable to allocate envlist\n");
|
||||
exit(1);
|
||||
}
|
||||
} else if (!strcmp(r, "U")) {
|
||||
@@ -816,7 +816,7 @@ int main(int argc, char **argv)
|
||||
qemu_host_page_size = atoi(argv[optind++]);
|
||||
if (qemu_host_page_size == 0 ||
|
||||
(qemu_host_page_size & (qemu_host_page_size - 1)) != 0) {
|
||||
error_report("page size must be a power of two");
|
||||
fprintf(stderr, "page size must be a power of two\n");
|
||||
exit(1);
|
||||
}
|
||||
} else if (!strcmp(r, "g")) {
|
||||
@@ -910,7 +910,7 @@ int main(int argc, char **argv)
|
||||
qemu_host_page_size */
|
||||
env = cpu_init(cpu_model);
|
||||
if (!env) {
|
||||
error_report("Unable to find CPU definition");
|
||||
fprintf(stderr, "Unable to find CPU definition\n");
|
||||
exit(1);
|
||||
}
|
||||
cpu = ENV_GET_CPU(env);
|
||||
@@ -1012,7 +1012,7 @@ int main(int argc, char **argv)
|
||||
#ifndef TARGET_ABI32
|
||||
/* enable 64 bit mode if possible */
|
||||
if (!(env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM)) {
|
||||
error_report("The selected x86 CPU does not support 64 bit mode");
|
||||
fprintf(stderr, "The selected x86 CPU does not support 64 bit mode\n");
|
||||
exit(1);
|
||||
}
|
||||
env->cr[4] |= CR4_PAE_MASK;
|
||||
|
||||
@@ -6,16 +6,20 @@ host side
|
||||
---------
|
||||
|
||||
First you must compile qemu with a user interface supporting
|
||||
multihead/multiseat and input event routing. Right now this list is
|
||||
pretty short: sdl2.
|
||||
multihead/multiseat and input event routing. Right now this
|
||||
list includes sdl2 and gtk (both 2+3):
|
||||
|
||||
./configure --enable-sdl --with-sdlabi=2.0
|
||||
|
||||
or
|
||||
|
||||
./configure --enable-gtk
|
||||
|
||||
|
||||
Next put together the qemu command line:
|
||||
|
||||
qemu -enable-kvm -usb $memory $disk $whatever \
|
||||
-display sdl \
|
||||
-display [ sdl | gtk ] \
|
||||
-vga std \
|
||||
-device usb-tablet
|
||||
|
||||
@@ -37,6 +41,20 @@ The "display=video2" sets up the input routing. Any input coming from
|
||||
the window which belongs to the video.2 display adapter will be routed
|
||||
to these input devices.
|
||||
|
||||
The sdl2 ui will start up with two windows, one for each display
|
||||
device. The gtk ui will start with a single window and each display
|
||||
in a separate tab. You can either simply switch tabs to switch heads,
|
||||
or use the "View / Detach tab" menu item to move one of the displays
|
||||
to its own window so you can see both display devices side-by-side.
|
||||
|
||||
Note on spice: Spice handles multihead just fine. But it can't do
|
||||
multiseat. For tablet events the event source is sent to the spice
|
||||
agent. But qemu can't figure it, so it can't do input routing.
|
||||
Fixing this needs a new or extended input interface between
|
||||
libspice-server and qemu. For keyboard events it is even worse: The
|
||||
event source isn't included in the spice protocol, so the wire
|
||||
protocol must be extended to support this.
|
||||
|
||||
|
||||
guest side
|
||||
----------
|
||||
@@ -46,29 +64,37 @@ You need a pretty recent linux guest. systemd with loginctl. kernel
|
||||
fully updated for the new kernel though, i.e. the live iso doesn't cut
|
||||
it.
|
||||
|
||||
Now we'll have to configure the guest. Boot and login. By default
|
||||
all devices belong to seat0. You can use "loginctl seat-status seat0"
|
||||
to list them all (and to get the sysfs paths for cut+paste). Now
|
||||
we'll go assign all pci devices connected the pci bridge in slot 12 to
|
||||
a new head:
|
||||
Now we'll have to configure the guest. Boot and login. "lspci -vt"
|
||||
should list the pci bridge with the display adapter and usb controller:
|
||||
|
||||
loginctl attach seat-qemu \
|
||||
/sys/devices/pci0000:00/0000:00:12.0/0000:01:02.0/drm/card1
|
||||
loginctl attach seat-qemu \
|
||||
/sys/devices/pci0000:00/0000:00:12.0/0000:01:02.0/graphics/fb1
|
||||
loginctl attach seat-qemu \
|
||||
/sys/devices/pci0000:00/0000:00:12.0/0000:01:0f.0/usb2
|
||||
[root@fedora ~]# lspci -vt
|
||||
-[0000:00]-+-00.0 Intel Corporation 440FX - 82441FX PMC [Natoma]
|
||||
[ ... ]
|
||||
\-12.0-[01]--+-02.0 Device 1234:1111
|
||||
\-0f.0 NEC Corporation USB 3.0 Host Controller
|
||||
|
||||
Use "loginctl seat-status seat-qemu" to check the result. It isn't
|
||||
needed to assign the usb devices to the head individually, assigning a
|
||||
usb (root) hub will automatically assign all usb devices connected to
|
||||
it too.
|
||||
Good. Now lets tell the system that the pci bridge and all devices
|
||||
below it belong to a separate seat by dropping a file into
|
||||
/etc/udev/rules.d:
|
||||
|
||||
BTW: loginctl writes udev rules to /etc/udev/rules.d to make these
|
||||
device assignments permanent, so you need to do this only once.
|
||||
[root@fedora ~]# cat /etc/udev/rules.d/70-qemu-autoseat.rules
|
||||
SUBSYSTEMS=="pci", DEVPATH=="*/0000:00:12.0", TAG+="seat", ENV{ID_AUTOSEAT}="1"
|
||||
|
||||
Now simply restart gdm (rebooting will do too), and a login screen
|
||||
should show up on the second head.
|
||||
Reboot. System should come up with two seats. With loginctl you can
|
||||
check the configuration:
|
||||
|
||||
[root@fedora ~]# loginctl list-seats
|
||||
SEAT
|
||||
seat0
|
||||
seat-pci-pci-0000_00_12_0
|
||||
|
||||
2 seats listed.
|
||||
|
||||
You can use "loginctl seat-status seat-pci-pci-0000_00_12_0" to list
|
||||
the devices attached to the seat.
|
||||
|
||||
Background info is here:
|
||||
http://www.freedesktop.org/wiki/Software/systemd/multiseat/
|
||||
|
||||
Enjoy!
|
||||
|
||||
|
||||
@@ -28,6 +28,26 @@
|
||||
#include "qemu/iov.h"
|
||||
#include "trace.h"
|
||||
|
||||
void usb_pick_speed(USBPort *port)
|
||||
{
|
||||
static const int speeds[] = {
|
||||
USB_SPEED_SUPER,
|
||||
USB_SPEED_HIGH,
|
||||
USB_SPEED_FULL,
|
||||
USB_SPEED_LOW,
|
||||
};
|
||||
USBDevice *udev = port->dev;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(speeds); i++) {
|
||||
if ((udev->speedmask & (1 << speeds[i])) &&
|
||||
(port->speedmask & (1 << speeds[i]))) {
|
||||
udev->speed = speeds[i];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void usb_attach(USBPort *port)
|
||||
{
|
||||
USBDevice *dev = port->dev;
|
||||
@@ -35,6 +55,7 @@ void usb_attach(USBPort *port)
|
||||
assert(dev != NULL);
|
||||
assert(dev->attached);
|
||||
assert(dev->state == USB_STATE_NOTATTACHED);
|
||||
usb_pick_speed(port);
|
||||
port->ops->attach(port);
|
||||
dev->state = USB_STATE_ATTACHED;
|
||||
usb_device_handle_attach(dev);
|
||||
|
||||
@@ -518,18 +518,6 @@ void usb_desc_init(USBDevice *dev)
|
||||
|
||||
void usb_desc_attach(USBDevice *dev)
|
||||
{
|
||||
const USBDesc *desc = usb_device_get_usb_desc(dev);
|
||||
|
||||
assert(desc != NULL);
|
||||
if (desc->super && (dev->port->speedmask & USB_SPEED_MASK_SUPER)) {
|
||||
dev->speed = USB_SPEED_SUPER;
|
||||
} else if (desc->high && (dev->port->speedmask & USB_SPEED_MASK_HIGH)) {
|
||||
dev->speed = USB_SPEED_HIGH;
|
||||
} else if (desc->full && (dev->port->speedmask & USB_SPEED_MASK_FULL)) {
|
||||
dev->speed = USB_SPEED_FULL;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
usb_desc_setdefaults(dev);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,87 +27,10 @@
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "hw/usb/ehci-regs.h"
|
||||
#include "hw/usb/hcd-ehci.h"
|
||||
#include "trace.h"
|
||||
|
||||
/* Capability Registers Base Address - section 2.2 */
|
||||
#define CAPLENGTH 0x0000 /* 1-byte, 0x0001 reserved */
|
||||
#define HCIVERSION 0x0002 /* 2-bytes, i/f version # */
|
||||
#define HCSPARAMS 0x0004 /* 4-bytes, structural params */
|
||||
#define HCCPARAMS 0x0008 /* 4-bytes, capability params */
|
||||
#define EECP HCCPARAMS + 1
|
||||
#define HCSPPORTROUTE1 0x000c
|
||||
#define HCSPPORTROUTE2 0x0010
|
||||
|
||||
#define USBCMD 0x0000
|
||||
#define USBCMD_RUNSTOP (1 << 0) // run / Stop
|
||||
#define USBCMD_HCRESET (1 << 1) // HC Reset
|
||||
#define USBCMD_FLS (3 << 2) // Frame List Size
|
||||
#define USBCMD_FLS_SH 2 // Frame List Size Shift
|
||||
#define USBCMD_PSE (1 << 4) // Periodic Schedule Enable
|
||||
#define USBCMD_ASE (1 << 5) // Asynch Schedule Enable
|
||||
#define USBCMD_IAAD (1 << 6) // Int Asynch Advance Doorbell
|
||||
#define USBCMD_LHCR (1 << 7) // Light Host Controller Reset
|
||||
#define USBCMD_ASPMC (3 << 8) // Async Sched Park Mode Count
|
||||
#define USBCMD_ASPME (1 << 11) // Async Sched Park Mode Enable
|
||||
#define USBCMD_ITC (0x7f << 16) // Int Threshold Control
|
||||
#define USBCMD_ITC_SH 16 // Int Threshold Control Shift
|
||||
|
||||
#define USBSTS 0x0004
|
||||
#define USBSTS_RO_MASK 0x0000003f
|
||||
#define USBSTS_INT (1 << 0) // USB Interrupt
|
||||
#define USBSTS_ERRINT (1 << 1) // Error Interrupt
|
||||
#define USBSTS_PCD (1 << 2) // Port Change Detect
|
||||
#define USBSTS_FLR (1 << 3) // Frame List Rollover
|
||||
#define USBSTS_HSE (1 << 4) // Host System Error
|
||||
#define USBSTS_IAA (1 << 5) // Interrupt on Async Advance
|
||||
#define USBSTS_HALT (1 << 12) // HC Halted
|
||||
#define USBSTS_REC (1 << 13) // Reclamation
|
||||
#define USBSTS_PSS (1 << 14) // Periodic Schedule Status
|
||||
#define USBSTS_ASS (1 << 15) // Asynchronous Schedule Status
|
||||
|
||||
/*
|
||||
* Interrupt enable bits correspond to the interrupt active bits in USBSTS
|
||||
* so no need to redefine here.
|
||||
*/
|
||||
#define USBINTR 0x0008
|
||||
#define USBINTR_MASK 0x0000003f
|
||||
|
||||
#define FRINDEX 0x000c
|
||||
#define CTRLDSSEGMENT 0x0010
|
||||
#define PERIODICLISTBASE 0x0014
|
||||
#define ASYNCLISTADDR 0x0018
|
||||
#define ASYNCLISTADDR_MASK 0xffffffe0
|
||||
|
||||
#define CONFIGFLAG 0x0040
|
||||
|
||||
/*
|
||||
* Bits that are reserved or are read-only are masked out of values
|
||||
* written to us by software
|
||||
*/
|
||||
#define PORTSC_RO_MASK 0x007001c0
|
||||
#define PORTSC_RWC_MASK 0x0000002a
|
||||
#define PORTSC_WKOC_E (1 << 22) // Wake on Over Current Enable
|
||||
#define PORTSC_WKDS_E (1 << 21) // Wake on Disconnect Enable
|
||||
#define PORTSC_WKCN_E (1 << 20) // Wake on Connect Enable
|
||||
#define PORTSC_PTC (15 << 16) // Port Test Control
|
||||
#define PORTSC_PTC_SH 16 // Port Test Control shift
|
||||
#define PORTSC_PIC (3 << 14) // Port Indicator Control
|
||||
#define PORTSC_PIC_SH 14 // Port Indicator Control Shift
|
||||
#define PORTSC_POWNER (1 << 13) // Port Owner
|
||||
#define PORTSC_PPOWER (1 << 12) // Port Power
|
||||
#define PORTSC_LINESTAT (3 << 10) // Port Line Status
|
||||
#define PORTSC_LINESTAT_SH 10 // Port Line Status Shift
|
||||
#define PORTSC_PRESET (1 << 8) // Port Reset
|
||||
#define PORTSC_SUSPEND (1 << 7) // Port Suspend
|
||||
#define PORTSC_FPRES (1 << 6) // Force Port Resume
|
||||
#define PORTSC_OCC (1 << 5) // Over Current Change
|
||||
#define PORTSC_OCA (1 << 4) // Over Current Active
|
||||
#define PORTSC_PEDC (1 << 3) // Port Enable/Disable Change
|
||||
#define PORTSC_PED (1 << 2) // Port Enable/Disable
|
||||
#define PORTSC_CSC (1 << 1) // Connect Status Change
|
||||
#define PORTSC_CONNECT (1 << 0) // Current Connect Status
|
||||
|
||||
#define FRAME_TIMER_FREQ 1000
|
||||
#define FRAME_TIMER_NS (1000000000 / FRAME_TIMER_FREQ)
|
||||
#define UFRAME_TIMER_NS (FRAME_TIMER_NS / 8)
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
*/
|
||||
#include "hw/hw.h"
|
||||
#include "hw/usb.h"
|
||||
#include "hw/usb/uhci-regs.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "qemu/iov.h"
|
||||
@@ -37,41 +38,6 @@
|
||||
//#define DEBUG
|
||||
//#define DEBUG_DUMP_DATA
|
||||
|
||||
#define UHCI_CMD_FGR (1 << 4)
|
||||
#define UHCI_CMD_EGSM (1 << 3)
|
||||
#define UHCI_CMD_GRESET (1 << 2)
|
||||
#define UHCI_CMD_HCRESET (1 << 1)
|
||||
#define UHCI_CMD_RS (1 << 0)
|
||||
|
||||
#define UHCI_STS_HCHALTED (1 << 5)
|
||||
#define UHCI_STS_HCPERR (1 << 4)
|
||||
#define UHCI_STS_HSERR (1 << 3)
|
||||
#define UHCI_STS_RD (1 << 2)
|
||||
#define UHCI_STS_USBERR (1 << 1)
|
||||
#define UHCI_STS_USBINT (1 << 0)
|
||||
|
||||
#define TD_CTRL_SPD (1 << 29)
|
||||
#define TD_CTRL_ERROR_SHIFT 27
|
||||
#define TD_CTRL_IOS (1 << 25)
|
||||
#define TD_CTRL_IOC (1 << 24)
|
||||
#define TD_CTRL_ACTIVE (1 << 23)
|
||||
#define TD_CTRL_STALL (1 << 22)
|
||||
#define TD_CTRL_BABBLE (1 << 20)
|
||||
#define TD_CTRL_NAK (1 << 19)
|
||||
#define TD_CTRL_TIMEOUT (1 << 18)
|
||||
|
||||
#define UHCI_PORT_SUSPEND (1 << 12)
|
||||
#define UHCI_PORT_RESET (1 << 9)
|
||||
#define UHCI_PORT_LSDA (1 << 8)
|
||||
#define UHCI_PORT_RD (1 << 6)
|
||||
#define UHCI_PORT_ENC (1 << 3)
|
||||
#define UHCI_PORT_EN (1 << 2)
|
||||
#define UHCI_PORT_CSC (1 << 1)
|
||||
#define UHCI_PORT_CCS (1 << 0)
|
||||
|
||||
#define UHCI_PORT_READ_ONLY (0x1bb)
|
||||
#define UHCI_PORT_WRITE_CLEAR (UHCI_PORT_CSC | UHCI_PORT_ENC)
|
||||
|
||||
#define FRAME_TIMER_FREQ 1000
|
||||
|
||||
#define FRAME_MAX_LOOPS 256
|
||||
|
||||
@@ -498,6 +498,7 @@ typedef struct XHCIEvRingSeg {
|
||||
enum xhci_flags {
|
||||
XHCI_FLAG_USE_MSI = 1,
|
||||
XHCI_FLAG_USE_MSI_X,
|
||||
XHCI_FLAG_SS_FIRST,
|
||||
};
|
||||
|
||||
static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
|
||||
@@ -714,10 +715,18 @@ static XHCIPort *xhci_lookup_port(XHCIState *xhci, struct USBPort *uport)
|
||||
case USB_SPEED_LOW:
|
||||
case USB_SPEED_FULL:
|
||||
case USB_SPEED_HIGH:
|
||||
index = uport->index;
|
||||
if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) {
|
||||
index = uport->index + xhci->numports_3;
|
||||
} else {
|
||||
index = uport->index;
|
||||
}
|
||||
break;
|
||||
case USB_SPEED_SUPER:
|
||||
index = uport->index + xhci->numports_2;
|
||||
if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) {
|
||||
index = uport->index;
|
||||
} else {
|
||||
index = uport->index + xhci->numports_2;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
@@ -2856,7 +2865,7 @@ static void xhci_port_update(XHCIPort *port, int is_detach)
|
||||
|
||||
static void xhci_port_reset(XHCIPort *port, bool warm_reset)
|
||||
{
|
||||
trace_usb_xhci_port_reset(port->portnr);
|
||||
trace_usb_xhci_port_reset(port->portnr, warm_reset);
|
||||
|
||||
if (!xhci_port_have_device(port)) {
|
||||
return;
|
||||
@@ -2972,7 +2981,11 @@ static uint64_t xhci_cap_read(void *ptr, hwaddr reg, unsigned size)
|
||||
ret = 0x20425355; /* "USB " */
|
||||
break;
|
||||
case 0x28: /* Supported Protocol:08 */
|
||||
ret = 0x00000001 | (xhci->numports_2<<8);
|
||||
if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) {
|
||||
ret = (xhci->numports_2<<8) | (xhci->numports_3+1);
|
||||
} else {
|
||||
ret = (xhci->numports_2<<8) | 1;
|
||||
}
|
||||
break;
|
||||
case 0x2c: /* Supported Protocol:0c */
|
||||
ret = 0x00000000; /* reserved */
|
||||
@@ -2984,7 +2997,11 @@ static uint64_t xhci_cap_read(void *ptr, hwaddr reg, unsigned size)
|
||||
ret = 0x20425355; /* "USB " */
|
||||
break;
|
||||
case 0x38: /* Supported Protocol:08 */
|
||||
ret = 0x00000000 | (xhci->numports_2+1) | (xhci->numports_3<<8);
|
||||
if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) {
|
||||
ret = (xhci->numports_3<<8) | 1;
|
||||
} else {
|
||||
ret = (xhci->numports_3<<8) | (xhci->numports_2+1);
|
||||
}
|
||||
break;
|
||||
case 0x3c: /* Supported Protocol:0c */
|
||||
ret = 0x00000000; /* reserved */
|
||||
@@ -3517,8 +3534,13 @@ static void usb_xhci_init(XHCIState *xhci)
|
||||
for (i = 0; i < usbports; i++) {
|
||||
speedmask = 0;
|
||||
if (i < xhci->numports_2) {
|
||||
port = &xhci->ports[i];
|
||||
port->portnr = i + 1;
|
||||
if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) {
|
||||
port = &xhci->ports[i + xhci->numports_3];
|
||||
port->portnr = i + 1 + xhci->numports_3;
|
||||
} else {
|
||||
port = &xhci->ports[i];
|
||||
port->portnr = i + 1;
|
||||
}
|
||||
port->uport = &xhci->uports[i];
|
||||
port->speedmask =
|
||||
USB_SPEED_MASK_LOW |
|
||||
@@ -3528,8 +3550,13 @@ static void usb_xhci_init(XHCIState *xhci)
|
||||
speedmask |= port->speedmask;
|
||||
}
|
||||
if (i < xhci->numports_3) {
|
||||
port = &xhci->ports[i + xhci->numports_2];
|
||||
port->portnr = i + 1 + xhci->numports_2;
|
||||
if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) {
|
||||
port = &xhci->ports[i];
|
||||
port->portnr = i + 1;
|
||||
} else {
|
||||
port = &xhci->ports[i + xhci->numports_2];
|
||||
port->portnr = i + 1 + xhci->numports_2;
|
||||
}
|
||||
port->uport = &xhci->uports[i];
|
||||
port->speedmask = USB_SPEED_MASK_SUPER;
|
||||
snprintf(port->name, sizeof(port->name), "usb3 port #%d", i+1);
|
||||
@@ -3788,6 +3815,8 @@ static const VMStateDescription vmstate_xhci = {
|
||||
static Property xhci_properties[] = {
|
||||
DEFINE_PROP_BIT("msi", XHCIState, flags, XHCI_FLAG_USE_MSI, true),
|
||||
DEFINE_PROP_BIT("msix", XHCIState, flags, XHCI_FLAG_USE_MSI_X, true),
|
||||
DEFINE_PROP_BIT("superspeed-ports-first",
|
||||
XHCIState, flags, XHCI_FLAG_SS_FIRST, true),
|
||||
DEFINE_PROP_UINT32("intrs", XHCIState, numintrs, MAXINTRS),
|
||||
DEFINE_PROP_UINT32("slots", XHCIState, numslots, MAXSLOTS),
|
||||
DEFINE_PROP_UINT32("p2", XHCIState, numports_2, 4),
|
||||
|
||||
@@ -111,6 +111,7 @@ struct USBHostRequest {
|
||||
unsigned char *buffer;
|
||||
unsigned char *cbuf;
|
||||
unsigned int clen;
|
||||
bool usb3ep0quirk;
|
||||
QTAILQ_ENTRY(USBHostRequest) next;
|
||||
};
|
||||
|
||||
@@ -146,6 +147,10 @@ static void usb_host_attach_kernel(USBHostDevice *s);
|
||||
#define BULK_TIMEOUT 0 /* unlimited */
|
||||
#define INTR_TIMEOUT 0 /* unlimited */
|
||||
|
||||
#if LIBUSBX_API_VERSION >= 0x01000103
|
||||
# define HAVE_STREAMS 1
|
||||
#endif
|
||||
|
||||
static const char *speed_name[] = {
|
||||
[LIBUSB_SPEED_UNKNOWN] = "?",
|
||||
[LIBUSB_SPEED_LOW] = "1.5",
|
||||
@@ -346,6 +351,13 @@ static void usb_host_req_complete_ctrl(struct libusb_transfer *xfer)
|
||||
r->p->actual_length = xfer->actual_length;
|
||||
if (r->in && xfer->actual_length) {
|
||||
memcpy(r->cbuf, r->buffer + 8, xfer->actual_length);
|
||||
|
||||
/* Fix up USB-3 ep0 maxpacket size to allow superspeed connected devices
|
||||
* to work redirected to a not superspeed capable hcd */
|
||||
if (r->usb3ep0quirk && xfer->actual_length >= 18 &&
|
||||
r->cbuf[7] == 9) {
|
||||
r->cbuf[7] = 64;
|
||||
}
|
||||
}
|
||||
trace_usb_host_req_complete(s->bus_num, s->addr, r->p,
|
||||
r->p->status, r->p->actual_length);
|
||||
@@ -672,11 +684,17 @@ static void usb_host_iso_data_out(USBHostDevice *s, USBPacket *p)
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
static bool usb_host_full_speed_compat(USBHostDevice *s)
|
||||
static void usb_host_speed_compat(USBHostDevice *s)
|
||||
{
|
||||
USBDevice *udev = USB_DEVICE(s);
|
||||
struct libusb_config_descriptor *conf;
|
||||
const struct libusb_interface_descriptor *intf;
|
||||
const struct libusb_endpoint_descriptor *endp;
|
||||
#ifdef HAVE_STREAMS
|
||||
struct libusb_ss_endpoint_companion_descriptor *endp_ss_comp;
|
||||
#endif
|
||||
bool compat_high = true;
|
||||
bool compat_full = true;
|
||||
uint8_t type;
|
||||
int rc, c, i, a, e;
|
||||
|
||||
@@ -693,10 +711,27 @@ static bool usb_host_full_speed_compat(USBHostDevice *s)
|
||||
type = endp->bmAttributes & 0x3;
|
||||
switch (type) {
|
||||
case 0x01: /* ISO */
|
||||
return false;
|
||||
compat_full = false;
|
||||
compat_high = false;
|
||||
break;
|
||||
case 0x02: /* BULK */
|
||||
#ifdef HAVE_STREAMS
|
||||
rc = libusb_get_ss_endpoint_companion_descriptor
|
||||
(ctx, endp, &endp_ss_comp);
|
||||
if (rc == LIBUSB_SUCCESS) {
|
||||
libusb_free_ss_endpoint_companion_descriptor
|
||||
(endp_ss_comp);
|
||||
compat_full = false;
|
||||
compat_high = false;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 0x03: /* INTERRUPT */
|
||||
if (endp->wMaxPacketSize > 64) {
|
||||
return false;
|
||||
compat_full = false;
|
||||
}
|
||||
if (endp->wMaxPacketSize > 1024) {
|
||||
compat_high = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -705,7 +740,17 @@ static bool usb_host_full_speed_compat(USBHostDevice *s)
|
||||
}
|
||||
libusb_free_config_descriptor(conf);
|
||||
}
|
||||
return true;
|
||||
|
||||
udev->speedmask = (1 << udev->speed);
|
||||
if (udev->speed == USB_SPEED_SUPER && compat_high) {
|
||||
udev->speedmask |= USB_SPEED_HIGH;
|
||||
}
|
||||
if (udev->speed == USB_SPEED_SUPER && compat_full) {
|
||||
udev->speedmask |= USB_SPEED_FULL;
|
||||
}
|
||||
if (udev->speed == USB_SPEED_HIGH && compat_full) {
|
||||
udev->speedmask |= USB_SPEED_FULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void usb_host_ep_update(USBHostDevice *s)
|
||||
@@ -720,7 +765,7 @@ static void usb_host_ep_update(USBHostDevice *s)
|
||||
struct libusb_config_descriptor *conf;
|
||||
const struct libusb_interface_descriptor *intf;
|
||||
const struct libusb_endpoint_descriptor *endp;
|
||||
#if LIBUSBX_API_VERSION >= 0x01000103
|
||||
#ifdef HAVE_STREAMS
|
||||
struct libusb_ss_endpoint_companion_descriptor *endp_ss_comp;
|
||||
#endif
|
||||
uint8_t devep, type;
|
||||
@@ -768,7 +813,7 @@ static void usb_host_ep_update(USBHostDevice *s)
|
||||
usb_ep_set_type(udev, pid, ep, type);
|
||||
usb_ep_set_ifnum(udev, pid, ep, i);
|
||||
usb_ep_set_halted(udev, pid, ep, 0);
|
||||
#if LIBUSBX_API_VERSION >= 0x01000103
|
||||
#ifdef HAVE_STREAMS
|
||||
if (type == LIBUSB_TRANSFER_TYPE_BULK &&
|
||||
libusb_get_ss_endpoint_companion_descriptor(ctx, endp,
|
||||
&endp_ss_comp) == LIBUSB_SUCCESS) {
|
||||
@@ -813,10 +858,7 @@ static int usb_host_open(USBHostDevice *s, libusb_device *dev)
|
||||
usb_host_ep_update(s);
|
||||
|
||||
udev->speed = speed_map[libusb_get_device_speed(dev)];
|
||||
udev->speedmask = (1 << udev->speed);
|
||||
if (udev->speed == USB_SPEED_HIGH && usb_host_full_speed_compat(s)) {
|
||||
udev->speedmask |= USB_SPEED_MASK_FULL;
|
||||
}
|
||||
usb_host_speed_compat(s);
|
||||
|
||||
if (s->ddesc.iProduct) {
|
||||
libusb_get_string_descriptor_ascii(s->dh, s->ddesc.iProduct,
|
||||
@@ -1162,6 +1204,14 @@ static void usb_host_handle_control(USBDevice *udev, USBPacket *p,
|
||||
memcpy(r->buffer + 8, r->cbuf, r->clen);
|
||||
}
|
||||
|
||||
/* Fix up USB-3 ep0 maxpacket size to allow superspeed connected devices
|
||||
* to work redirected to a not superspeed capable hcd */
|
||||
if (udev->speed == USB_SPEED_SUPER &&
|
||||
!((udev->port->speedmask & USB_SPEED_MASK_SUPER)) &&
|
||||
request == 0x8006 && value == 0x100 && index == 0) {
|
||||
r->usb3ep0quirk = true;
|
||||
}
|
||||
|
||||
libusb_fill_control_transfer(r->xfer, s->dh, r->buffer,
|
||||
usb_host_req_complete_ctrl, r,
|
||||
CONTROL_TIMEOUT);
|
||||
@@ -1215,7 +1265,7 @@ static void usb_host_handle_data(USBDevice *udev, USBPacket *p)
|
||||
}
|
||||
ep = p->ep->nr | (r->in ? USB_DIR_IN : 0);
|
||||
if (p->stream) {
|
||||
#if LIBUSBX_API_VERSION >= 0x01000103
|
||||
#ifdef HAVE_STREAMS
|
||||
libusb_fill_bulk_stream_transfer(r->xfer, s->dh, ep, p->stream,
|
||||
r->buffer, size,
|
||||
usb_host_req_complete_data, r,
|
||||
@@ -1296,7 +1346,7 @@ static void usb_host_handle_reset(USBDevice *udev)
|
||||
static int usb_host_alloc_streams(USBDevice *udev, USBEndpoint **eps,
|
||||
int nr_eps, int streams)
|
||||
{
|
||||
#if LIBUSBX_API_VERSION >= 0x01000103
|
||||
#ifdef HAVE_STREAMS
|
||||
USBHostDevice *s = USB_HOST_DEVICE(udev);
|
||||
unsigned char endpoints[30];
|
||||
int i, rc;
|
||||
@@ -1326,7 +1376,7 @@ static int usb_host_alloc_streams(USBDevice *udev, USBEndpoint **eps,
|
||||
static void usb_host_free_streams(USBDevice *udev, USBEndpoint **eps,
|
||||
int nr_eps)
|
||||
{
|
||||
#if LIBUSBX_API_VERSION >= 0x01000103
|
||||
#ifdef HAVE_STREAMS
|
||||
USBHostDevice *s = USB_HOST_DEVICE(udev);
|
||||
unsigned char endpoints[30];
|
||||
int i;
|
||||
|
||||
@@ -271,6 +271,10 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
|
||||
.driver = "apic",\
|
||||
.property = "version",\
|
||||
.value = stringify(0x11),\
|
||||
},{\
|
||||
.driver = "nec-usb-xhci",\
|
||||
.property = "superspeed-ports-first",\
|
||||
.value = "off",\
|
||||
}
|
||||
|
||||
#define PC_COMPAT_1_7 \
|
||||
|
||||
@@ -458,6 +458,7 @@ void usb_ep_combine_input_packets(USBEndpoint *ep);
|
||||
void usb_combined_input_packet_complete(USBDevice *dev, USBPacket *p);
|
||||
void usb_combined_packet_cancel(USBDevice *dev, USBPacket *p);
|
||||
|
||||
void usb_pick_speed(USBPort *port);
|
||||
void usb_attach(USBPort *port);
|
||||
void usb_detach(USBPort *port);
|
||||
void usb_port_reset(USBPort *port);
|
||||
|
||||
82
include/hw/usb/ehci-regs.h
Normal file
82
include/hw/usb/ehci-regs.h
Normal file
@@ -0,0 +1,82 @@
|
||||
#ifndef HW_USB_EHCI_REGS_H
|
||||
#define HW_USB_EHCI_REGS_H 1
|
||||
|
||||
/* Capability Registers Base Address - section 2.2 */
|
||||
#define CAPLENGTH 0x0000 /* 1-byte, 0x0001 reserved */
|
||||
#define HCIVERSION 0x0002 /* 2-bytes, i/f version # */
|
||||
#define HCSPARAMS 0x0004 /* 4-bytes, structural params */
|
||||
#define HCCPARAMS 0x0008 /* 4-bytes, capability params */
|
||||
#define EECP HCCPARAMS + 1
|
||||
#define HCSPPORTROUTE1 0x000c
|
||||
#define HCSPPORTROUTE2 0x0010
|
||||
|
||||
#define USBCMD 0x0000
|
||||
#define USBCMD_RUNSTOP (1 << 0) // run / Stop
|
||||
#define USBCMD_HCRESET (1 << 1) // HC Reset
|
||||
#define USBCMD_FLS (3 << 2) // Frame List Size
|
||||
#define USBCMD_FLS_SH 2 // Frame List Size Shift
|
||||
#define USBCMD_PSE (1 << 4) // Periodic Schedule Enable
|
||||
#define USBCMD_ASE (1 << 5) // Asynch Schedule Enable
|
||||
#define USBCMD_IAAD (1 << 6) // Int Asynch Advance Doorbell
|
||||
#define USBCMD_LHCR (1 << 7) // Light Host Controller Reset
|
||||
#define USBCMD_ASPMC (3 << 8) // Async Sched Park Mode Count
|
||||
#define USBCMD_ASPME (1 << 11) // Async Sched Park Mode Enable
|
||||
#define USBCMD_ITC (0x7f << 16) // Int Threshold Control
|
||||
#define USBCMD_ITC_SH 16 // Int Threshold Control Shift
|
||||
|
||||
#define USBSTS 0x0004
|
||||
#define USBSTS_RO_MASK 0x0000003f
|
||||
#define USBSTS_INT (1 << 0) // USB Interrupt
|
||||
#define USBSTS_ERRINT (1 << 1) // Error Interrupt
|
||||
#define USBSTS_PCD (1 << 2) // Port Change Detect
|
||||
#define USBSTS_FLR (1 << 3) // Frame List Rollover
|
||||
#define USBSTS_HSE (1 << 4) // Host System Error
|
||||
#define USBSTS_IAA (1 << 5) // Interrupt on Async Advance
|
||||
#define USBSTS_HALT (1 << 12) // HC Halted
|
||||
#define USBSTS_REC (1 << 13) // Reclamation
|
||||
#define USBSTS_PSS (1 << 14) // Periodic Schedule Status
|
||||
#define USBSTS_ASS (1 << 15) // Asynchronous Schedule Status
|
||||
|
||||
/*
|
||||
* Interrupt enable bits correspond to the interrupt active bits in USBSTS
|
||||
* so no need to redefine here.
|
||||
*/
|
||||
#define USBINTR 0x0008
|
||||
#define USBINTR_MASK 0x0000003f
|
||||
|
||||
#define FRINDEX 0x000c
|
||||
#define CTRLDSSEGMENT 0x0010
|
||||
#define PERIODICLISTBASE 0x0014
|
||||
#define ASYNCLISTADDR 0x0018
|
||||
#define ASYNCLISTADDR_MASK 0xffffffe0
|
||||
|
||||
#define CONFIGFLAG 0x0040
|
||||
|
||||
/*
|
||||
* Bits that are reserved or are read-only are masked out of values
|
||||
* written to us by software
|
||||
*/
|
||||
#define PORTSC_RO_MASK 0x007001c0
|
||||
#define PORTSC_RWC_MASK 0x0000002a
|
||||
#define PORTSC_WKOC_E (1 << 22) // Wake on Over Current Enable
|
||||
#define PORTSC_WKDS_E (1 << 21) // Wake on Disconnect Enable
|
||||
#define PORTSC_WKCN_E (1 << 20) // Wake on Connect Enable
|
||||
#define PORTSC_PTC (15 << 16) // Port Test Control
|
||||
#define PORTSC_PTC_SH 16 // Port Test Control shift
|
||||
#define PORTSC_PIC (3 << 14) // Port Indicator Control
|
||||
#define PORTSC_PIC_SH 14 // Port Indicator Control Shift
|
||||
#define PORTSC_POWNER (1 << 13) // Port Owner
|
||||
#define PORTSC_PPOWER (1 << 12) // Port Power
|
||||
#define PORTSC_LINESTAT (3 << 10) // Port Line Status
|
||||
#define PORTSC_LINESTAT_SH 10 // Port Line Status Shift
|
||||
#define PORTSC_PRESET (1 << 8) // Port Reset
|
||||
#define PORTSC_SUSPEND (1 << 7) // Port Suspend
|
||||
#define PORTSC_FPRES (1 << 6) // Force Port Resume
|
||||
#define PORTSC_OCC (1 << 5) // Over Current Change
|
||||
#define PORTSC_OCA (1 << 4) // Over Current Active
|
||||
#define PORTSC_PEDC (1 << 3) // Port Enable/Disable Change
|
||||
#define PORTSC_PED (1 << 2) // Port Enable/Disable
|
||||
#define PORTSC_CSC (1 << 1) // Connect Status Change
|
||||
#define PORTSC_CONNECT (1 << 0) // Current Connect Status
|
||||
|
||||
#endif /* HW_USB_EHCI_REGS_H */
|
||||
40
include/hw/usb/uhci-regs.h
Normal file
40
include/hw/usb/uhci-regs.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#ifndef HW_USB_UHCI_REGS_H
|
||||
#define HW_USB_UHCI_REGS_H 1
|
||||
|
||||
#define UHCI_CMD_FGR (1 << 4)
|
||||
#define UHCI_CMD_EGSM (1 << 3)
|
||||
#define UHCI_CMD_GRESET (1 << 2)
|
||||
#define UHCI_CMD_HCRESET (1 << 1)
|
||||
#define UHCI_CMD_RS (1 << 0)
|
||||
|
||||
#define UHCI_STS_HCHALTED (1 << 5)
|
||||
#define UHCI_STS_HCPERR (1 << 4)
|
||||
#define UHCI_STS_HSERR (1 << 3)
|
||||
#define UHCI_STS_RD (1 << 2)
|
||||
#define UHCI_STS_USBERR (1 << 1)
|
||||
#define UHCI_STS_USBINT (1 << 0)
|
||||
|
||||
#define TD_CTRL_SPD (1 << 29)
|
||||
#define TD_CTRL_ERROR_SHIFT 27
|
||||
#define TD_CTRL_IOS (1 << 25)
|
||||
#define TD_CTRL_IOC (1 << 24)
|
||||
#define TD_CTRL_ACTIVE (1 << 23)
|
||||
#define TD_CTRL_STALL (1 << 22)
|
||||
#define TD_CTRL_BABBLE (1 << 20)
|
||||
#define TD_CTRL_NAK (1 << 19)
|
||||
#define TD_CTRL_TIMEOUT (1 << 18)
|
||||
|
||||
#define UHCI_PORT_SUSPEND (1 << 12)
|
||||
#define UHCI_PORT_RESET (1 << 9)
|
||||
#define UHCI_PORT_LSDA (1 << 8)
|
||||
#define UHCI_PORT_RSVD1 (1 << 7)
|
||||
#define UHCI_PORT_RD (1 << 6)
|
||||
#define UHCI_PORT_ENC (1 << 3)
|
||||
#define UHCI_PORT_EN (1 << 2)
|
||||
#define UHCI_PORT_CSC (1 << 1)
|
||||
#define UHCI_PORT_CCS (1 << 0)
|
||||
|
||||
#define UHCI_PORT_READ_ONLY (0x1bb)
|
||||
#define UHCI_PORT_WRITE_CLEAR (UHCI_PORT_CSC | UHCI_PORT_ENC)
|
||||
|
||||
#endif /* HW_USB_UHCI_REGS_H */
|
||||
@@ -82,6 +82,8 @@ void do_mouse_set(Monitor *mon, const QDict *qdict);
|
||||
#define QEMU_KEY_CTRL_PAGEDOWN 0xe407
|
||||
|
||||
void kbd_put_keysym_console(QemuConsole *s, int keysym);
|
||||
bool kbd_put_qcode_console(QemuConsole *s, int qcode);
|
||||
void kbd_put_string_console(QemuConsole *s, const char *str, int len);
|
||||
void kbd_put_keysym(int keysym);
|
||||
|
||||
/* consoles */
|
||||
|
||||
@@ -39,6 +39,7 @@ InputEvent *qemu_input_event_new_key(KeyValue *key, bool down);
|
||||
void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down);
|
||||
void qemu_input_event_send_key_number(QemuConsole *src, int num, bool down);
|
||||
void qemu_input_event_send_key_qcode(QemuConsole *src, QKeyCode q, bool down);
|
||||
void qemu_input_event_send_key_delay(uint32_t delay_ms);
|
||||
int qemu_input_key_number_to_qcode(uint8_t nr);
|
||||
int qemu_input_key_value_to_number(const KeyValue *value);
|
||||
int qemu_input_key_value_to_qcode(const KeyValue *value);
|
||||
|
||||
Binary file not shown.
BIN
pc-bios/bios.bin
BIN
pc-bios/bios.bin
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -287,6 +287,7 @@ static int print_block_option_help(const char *filename, const char *fmt)
|
||||
proto_drv = bdrv_find_protocol(filename, true);
|
||||
if (!proto_drv) {
|
||||
error_report("Unknown protocol '%s'", filename);
|
||||
free_option_parameters(create_options);
|
||||
return 1;
|
||||
}
|
||||
create_options = append_option_parameters(create_options,
|
||||
@@ -662,9 +663,7 @@ static int img_check(int argc, char **argv)
|
||||
ret = collect_image_check(bs, check, filename, fmt, fix);
|
||||
|
||||
if (ret == -ENOTSUP) {
|
||||
if (output_format == OFORMAT_HUMAN) {
|
||||
error_report("This image format does not support checks");
|
||||
}
|
||||
error_report("This image format does not support checks");
|
||||
ret = 63;
|
||||
goto fail;
|
||||
}
|
||||
@@ -1454,7 +1453,7 @@ static int img_convert(int argc, char **argv)
|
||||
ret = bdrv_parse_cache_flags(cache, &flags);
|
||||
if (ret < 0) {
|
||||
error_report("Invalid cache option: %s", cache);
|
||||
return -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out_bs = bdrv_new_open("target", out_filename, out_fmt, flags, true, quiet);
|
||||
|
||||
22
qemu-io.c
22
qemu-io.c
@@ -54,6 +54,7 @@ static int openfile(char *name, int flags, int growable, QDict *opts)
|
||||
|
||||
if (qemuio_bs) {
|
||||
fprintf(stderr, "file open already, try 'help close'\n");
|
||||
QDECREF(opts);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -61,7 +62,8 @@ static int openfile(char *name, int flags, int growable, QDict *opts)
|
||||
if (bdrv_open(&qemuio_bs, name, NULL, opts, flags | BDRV_O_PROTOCOL,
|
||||
NULL, &local_err))
|
||||
{
|
||||
fprintf(stderr, "%s: can't open device %s: %s\n", progname, name,
|
||||
fprintf(stderr, "%s: can't open%s%s: %s\n", progname,
|
||||
name ? " device " : "", name ?: "",
|
||||
error_get_pretty(local_err));
|
||||
error_free(local_err);
|
||||
return 1;
|
||||
@@ -72,7 +74,8 @@ static int openfile(char *name, int flags, int growable, QDict *opts)
|
||||
if (bdrv_open(&qemuio_bs, name, NULL, opts, flags, NULL, &local_err)
|
||||
< 0)
|
||||
{
|
||||
fprintf(stderr, "%s: can't open device %s: %s\n", progname, name,
|
||||
fprintf(stderr, "%s: can't open%s%s: %s\n", progname,
|
||||
name ? " device " : "", name ?: "",
|
||||
error_get_pretty(local_err));
|
||||
error_free(local_err);
|
||||
bdrv_unref(qemuio_bs);
|
||||
@@ -118,6 +121,7 @@ static const cmdinfo_t open_cmd = {
|
||||
|
||||
static QemuOptsList empty_opts = {
|
||||
.name = "drive",
|
||||
.merge_lists = true,
|
||||
.head = QTAILQ_HEAD_INITIALIZER(empty_opts.head),
|
||||
.desc = {
|
||||
/* no elements => accept any params */
|
||||
@@ -132,7 +136,7 @@ static int open_f(BlockDriverState *bs, int argc, char **argv)
|
||||
int growable = 0;
|
||||
int c;
|
||||
QemuOpts *qopts;
|
||||
QDict *opts = NULL;
|
||||
QDict *opts;
|
||||
|
||||
while ((c = getopt(argc, argv, "snrgo:")) != EOF) {
|
||||
switch (c) {
|
||||
@@ -149,15 +153,14 @@ static int open_f(BlockDriverState *bs, int argc, char **argv)
|
||||
growable = 1;
|
||||
break;
|
||||
case 'o':
|
||||
qopts = qemu_opts_parse(&empty_opts, optarg, 0);
|
||||
if (qopts == NULL) {
|
||||
if (!qemu_opts_parse(&empty_opts, optarg, 0)) {
|
||||
printf("could not parse option list -- %s\n", optarg);
|
||||
qemu_opts_reset(&empty_opts);
|
||||
return 0;
|
||||
}
|
||||
opts = qemu_opts_to_qdict(qopts, opts);
|
||||
qemu_opts_del(qopts);
|
||||
break;
|
||||
default:
|
||||
qemu_opts_reset(&empty_opts);
|
||||
return qemuio_command_usage(&open_cmd);
|
||||
}
|
||||
}
|
||||
@@ -166,11 +169,16 @@ static int open_f(BlockDriverState *bs, int argc, char **argv)
|
||||
flags |= BDRV_O_RDWR;
|
||||
}
|
||||
|
||||
qopts = qemu_opts_find(&empty_opts, NULL);
|
||||
opts = qopts ? qemu_opts_to_qdict(qopts, NULL) : NULL;
|
||||
qemu_opts_reset(&empty_opts);
|
||||
|
||||
if (optind == argc - 1) {
|
||||
return openfile(argv[optind], flags, growable, opts);
|
||||
} else if (optind == argc) {
|
||||
return openfile(NULL, flags, growable, opts);
|
||||
} else {
|
||||
QDECREF(opts);
|
||||
return qemuio_command_usage(&open_cmd);
|
||||
}
|
||||
}
|
||||
|
||||
Submodule roms/seabios updated: b1d4dc9084...e51488c5f8
@@ -154,6 +154,8 @@ gcov-files-i386-y += hw/pci-bridge/ioh3420.c
|
||||
check-qtest-i386-y += tests/usb-hcd-ehci-test$(EXESUF)
|
||||
gcov-files-i386-y += hw/usb/hcd-ehci.c
|
||||
gcov-files-i386-y += hw/usb/hcd-uhci.c
|
||||
gcov-files-i386-y += hw/usb/dev-hid.c
|
||||
gcov-files-i386-y += hw/usb/dev-storage.c
|
||||
check-qtest-x86_64-y = $(check-qtest-i386-y)
|
||||
gcov-files-i386-y += i386-softmmu/hw/timer/mc146818rtc.c
|
||||
gcov-files-x86_64-y = $(subst i386-softmmu/,x86_64-softmmu/,$(gcov-files-i386-y))
|
||||
@@ -319,7 +321,7 @@ tests/ac97-test$(EXESUF): tests/ac97-test.o
|
||||
tests/es1370-test$(EXESUF): tests/es1370-test.o
|
||||
tests/intel-hda-test$(EXESUF): tests/intel-hda-test.o
|
||||
tests/ioh3420-test$(EXESUF): tests/ioh3420-test.o
|
||||
tests/usb-hcd-ehci-test$(EXESUF): tests/usb-hcd-ehci-test.o
|
||||
tests/usb-hcd-ehci-test$(EXESUF): tests/usb-hcd-ehci-test.o $(libqos-pc-obj-y)
|
||||
tests/qemu-iotests/socket_scm_helper$(EXESUF): tests/qemu-iotests/socket_scm_helper.o
|
||||
tests/test-qemu-opts$(EXESUF): tests/test-qemu-opts.o libqemuutil.a libqemustub.a
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ void qpci_config_writew(QPCIDevice *dev, uint8_t offset, uint16_t value)
|
||||
|
||||
void qpci_config_writel(QPCIDevice *dev, uint8_t offset, uint32_t value)
|
||||
{
|
||||
dev->bus->config_writew(dev->bus, dev->devfn, offset, value);
|
||||
dev->bus->config_writel(dev->bus, dev->devfn, offset, value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -9,12 +9,149 @@
|
||||
|
||||
#include <glib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "libqtest.h"
|
||||
#include "libqos/pci-pc.h"
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/usb/uhci-regs.h"
|
||||
#include "hw/usb/ehci-regs.h"
|
||||
|
||||
/* Tests only initialization so far. TODO: Replace with functional tests */
|
||||
static void pci_nop(void)
|
||||
struct qhc {
|
||||
QPCIDevice *dev;
|
||||
void *base;
|
||||
};
|
||||
|
||||
static QPCIBus *pcibus;
|
||||
static struct qhc uhci1;
|
||||
static struct qhc uhci2;
|
||||
static struct qhc uhci3;
|
||||
static struct qhc ehci1;
|
||||
|
||||
/* helpers */
|
||||
|
||||
static void pci_init_one(struct qhc *hc, uint32_t devfn, int bar)
|
||||
{
|
||||
hc->dev = qpci_device_find(pcibus, devfn);
|
||||
g_assert(hc->dev != NULL);
|
||||
qpci_device_enable(hc->dev);
|
||||
hc->base = qpci_iomap(hc->dev, bar);
|
||||
g_assert(hc->base != NULL);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void uhci_port_update(struct qhc *hc, int port,
|
||||
uint16_t set, uint16_t clear)
|
||||
{
|
||||
void *addr = hc->base + 0x10 + 2 * port;
|
||||
uint16_t value;
|
||||
|
||||
value = qpci_io_readw(hc->dev, addr);
|
||||
value |= set;
|
||||
value &= ~clear;
|
||||
qpci_io_writew(hc->dev, addr, value);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void uhci_port_test(struct qhc *hc, int port, uint16_t expect)
|
||||
{
|
||||
void *addr = hc->base + 0x10 + 2 * port;
|
||||
uint16_t value = qpci_io_readw(hc->dev, addr);
|
||||
uint16_t mask = ~(UHCI_PORT_WRITE_CLEAR | UHCI_PORT_RSVD1);
|
||||
|
||||
#if 0
|
||||
fprintf(stderr, "%s: %d, have 0x%04x, want 0x%04x\n",
|
||||
__func__, port, value & mask, expect & mask);
|
||||
#endif
|
||||
g_assert((value & mask) == (expect & mask));
|
||||
}
|
||||
|
||||
static void ehci_port_test(struct qhc *hc, int port, uint32_t expect)
|
||||
{
|
||||
void *addr = hc->base + 0x64 + 4 * port;
|
||||
uint32_t value = qpci_io_readl(hc->dev, addr);
|
||||
uint16_t mask = ~(PORTSC_CSC | PORTSC_PEDC | PORTSC_OCC);
|
||||
|
||||
#if 0
|
||||
fprintf(stderr, "%s: %d, have 0x%08x, want 0x%08x\n",
|
||||
__func__, port, value & mask, expect & mask);
|
||||
#endif
|
||||
g_assert((value & mask) == (expect & mask));
|
||||
}
|
||||
|
||||
/* tests */
|
||||
|
||||
static void pci_init(void)
|
||||
{
|
||||
if (pcibus) {
|
||||
return;
|
||||
}
|
||||
pcibus = qpci_init_pc();
|
||||
g_assert(pcibus != NULL);
|
||||
|
||||
pci_init_one(&uhci1, QPCI_DEVFN(0x1d, 0), 4);
|
||||
pci_init_one(&uhci2, QPCI_DEVFN(0x1d, 1), 4);
|
||||
pci_init_one(&uhci3, QPCI_DEVFN(0x1d, 2), 4);
|
||||
pci_init_one(&ehci1, QPCI_DEVFN(0x1d, 7), 0);
|
||||
}
|
||||
|
||||
static void pci_uhci_port_1(void)
|
||||
{
|
||||
g_assert(pcibus != NULL);
|
||||
|
||||
uhci_port_test(&uhci1, 0, UHCI_PORT_CCS); /* usb-tablet */
|
||||
uhci_port_test(&uhci1, 1, UHCI_PORT_CCS); /* usb-storage */
|
||||
uhci_port_test(&uhci2, 0, 0);
|
||||
uhci_port_test(&uhci2, 1, 0);
|
||||
uhci_port_test(&uhci3, 0, 0);
|
||||
uhci_port_test(&uhci3, 1, 0);
|
||||
}
|
||||
|
||||
static void pci_ehci_port_1(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
g_assert(pcibus != NULL);
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
ehci_port_test(&ehci1, i, PORTSC_POWNER | PORTSC_PPOWER);
|
||||
}
|
||||
}
|
||||
|
||||
static void pci_ehci_config(void)
|
||||
{
|
||||
/* hands over all ports from companion uhci to ehci */
|
||||
qpci_io_writew(ehci1.dev, ehci1.base + 0x60, 1);
|
||||
}
|
||||
|
||||
static void pci_uhci_port_2(void)
|
||||
{
|
||||
g_assert(pcibus != NULL);
|
||||
|
||||
uhci_port_test(&uhci1, 0, 0); /* usb-tablet, @ehci */
|
||||
uhci_port_test(&uhci1, 1, 0); /* usb-storage, @ehci */
|
||||
uhci_port_test(&uhci2, 0, 0);
|
||||
uhci_port_test(&uhci2, 1, 0);
|
||||
uhci_port_test(&uhci3, 0, 0);
|
||||
uhci_port_test(&uhci3, 1, 0);
|
||||
}
|
||||
|
||||
static void pci_ehci_port_2(void)
|
||||
{
|
||||
static uint32_t expect[] = {
|
||||
PORTSC_PPOWER | PORTSC_CONNECT, /* usb-tablet */
|
||||
PORTSC_PPOWER | PORTSC_CONNECT, /* usb-storage */
|
||||
PORTSC_PPOWER,
|
||||
PORTSC_PPOWER,
|
||||
PORTSC_PPOWER,
|
||||
PORTSC_PPOWER,
|
||||
};
|
||||
int i;
|
||||
|
||||
g_assert(pcibus != NULL);
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
ehci_port_test(&ehci1, i, expect[i]);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
@@ -22,7 +159,12 @@ int main(int argc, char **argv)
|
||||
int ret;
|
||||
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
qtest_add_func("/ehci/pci/nop", pci_nop);
|
||||
qtest_add_func("/ehci/pci/init", pci_init);
|
||||
qtest_add_func("/ehci/pci/uhci-port-1", pci_uhci_port_1);
|
||||
qtest_add_func("/ehci/pci/ehci-port-1", pci_ehci_port_1);
|
||||
qtest_add_func("/ehci/pci/ehci-config", pci_ehci_config);
|
||||
qtest_add_func("/ehci/pci/uhci-port-2", pci_uhci_port_2);
|
||||
qtest_add_func("/ehci/pci/ehci-port-2", pci_ehci_port_2);
|
||||
|
||||
qtest_start("-machine q35 -device ich9-usb-ehci1,bus=pcie.0,addr=1d.7,"
|
||||
"multifunction=on,id=ich9-ehci-1 "
|
||||
@@ -31,7 +173,10 @@ int main(int argc, char **argv)
|
||||
"-device ich9-usb-uhci2,bus=pcie.0,addr=1d.1,"
|
||||
"multifunction=on,masterbus=ich9-ehci-1.0,firstport=2 "
|
||||
"-device ich9-usb-uhci3,bus=pcie.0,addr=1d.2,"
|
||||
"multifunction=on,masterbus=ich9-ehci-1.0,firstport=4");
|
||||
"multifunction=on,masterbus=ich9-ehci-1.0,firstport=4 "
|
||||
"-drive if=none,id=usbcdrom,media=cdrom "
|
||||
"-device usb-tablet,bus=ich9-ehci-1.0,port=1,usb_version=1 "
|
||||
"-device usb-storage,bus=ich9-ehci-1.0,port=2,drive=usbcdrom ");
|
||||
ret = g_test_run();
|
||||
|
||||
qtest_end();
|
||||
|
||||
10
trace-events
10
trace-events
@@ -371,7 +371,7 @@ usb_xhci_irq_msix_use(uint32_t nr) "nr %d"
|
||||
usb_xhci_irq_msix_unuse(uint32_t nr) "nr %d"
|
||||
usb_xhci_queue_event(uint32_t vector, uint32_t idx, const char *trb, const char *evt, uint64_t param, uint32_t status, uint32_t control) "v %d, idx %d, %s, %s, p %016" PRIx64 ", s %08x, c 0x%08x"
|
||||
usb_xhci_fetch_trb(uint64_t addr, const char *name, uint64_t param, uint32_t status, uint32_t control) "addr %016" PRIx64 ", %s, p %016" PRIx64 ", s %08x, c 0x%08x"
|
||||
usb_xhci_port_reset(uint32_t port) "port %d"
|
||||
usb_xhci_port_reset(uint32_t port, bool warm) "port %d, warm %d"
|
||||
usb_xhci_port_link(uint32_t port, uint32_t pls) "port %d, pls %d"
|
||||
usb_xhci_port_notify(uint32_t port, uint32_t pls) "port %d, bits %x"
|
||||
usb_xhci_slot_enable(uint32_t slotid) "slotid %d"
|
||||
@@ -1047,6 +1047,14 @@ gd_update(const char *tab, int x, int y, int w, int h) "tab=%s, x=%d, y=%d, w=%d
|
||||
gd_key_event(const char *tab, int gdk_keycode, int qemu_keycode, const char *action) "tab=%s, translated GDK keycode %d to QEMU keycode %d (%s)"
|
||||
gd_grab(const char *tab, const char *device, bool on) "tab=%s, %s %d"
|
||||
|
||||
# ui/vnc.c
|
||||
vnc_key_guest_leds(bool caps, bool num, bool scroll) "caps %d, num %d, scroll %d"
|
||||
vnc_key_map_init(const char *layout) "%s"
|
||||
vnc_key_event_ext(bool down, int sym, int keycode, const char *name) "down %d, sym 0x%x, keycode 0x%x [%s]"
|
||||
vnc_key_event_map(bool down, int sym, int keycode, const char *name) "down %d, sym 0x%x -> keycode 0x%x [%s]"
|
||||
vnc_key_sync_numlock(bool on) "%d"
|
||||
vnc_key_sync_capslock(bool on) "%d"
|
||||
|
||||
# ui/input.c
|
||||
input_event_key_number(int conidx, int number, const char *qcode, bool down) "con %d, key number 0x%x [%s], down %d"
|
||||
input_event_key_qcode(int conidx, const char *qcode, bool down) "con %d, key qcode %s, down %d"
|
||||
|
||||
33
ui/console.c
33
ui/console.c
@@ -1109,6 +1109,39 @@ void kbd_put_keysym_console(QemuConsole *s, int keysym)
|
||||
}
|
||||
}
|
||||
|
||||
static const int qcode_to_keysym[Q_KEY_CODE_MAX] = {
|
||||
[Q_KEY_CODE_UP] = QEMU_KEY_UP,
|
||||
[Q_KEY_CODE_DOWN] = QEMU_KEY_DOWN,
|
||||
[Q_KEY_CODE_RIGHT] = QEMU_KEY_RIGHT,
|
||||
[Q_KEY_CODE_LEFT] = QEMU_KEY_LEFT,
|
||||
[Q_KEY_CODE_HOME] = QEMU_KEY_HOME,
|
||||
[Q_KEY_CODE_END] = QEMU_KEY_END,
|
||||
[Q_KEY_CODE_PGUP] = QEMU_KEY_PAGEUP,
|
||||
[Q_KEY_CODE_PGDN] = QEMU_KEY_PAGEDOWN,
|
||||
[Q_KEY_CODE_DELETE] = QEMU_KEY_DELETE,
|
||||
};
|
||||
|
||||
bool kbd_put_qcode_console(QemuConsole *s, int qcode)
|
||||
{
|
||||
int keysym;
|
||||
|
||||
keysym = qcode_to_keysym[qcode];
|
||||
if (keysym == 0) {
|
||||
return false;
|
||||
}
|
||||
kbd_put_keysym_console(s, keysym);
|
||||
return true;
|
||||
}
|
||||
|
||||
void kbd_put_string_console(QemuConsole *s, const char *str, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len && str[i]; i++) {
|
||||
kbd_put_keysym_console(s, str[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void kbd_put_keysym(int keysym)
|
||||
{
|
||||
kbd_put_keysym_console(active_console, keysym);
|
||||
|
||||
10
ui/curses.c
10
ui/curses.c
@@ -277,31 +277,41 @@ static void curses_refresh(DisplayChangeListener *dcl)
|
||||
* events, we need to emit both for each key received */
|
||||
if (keycode & SHIFT) {
|
||||
qemu_input_event_send_key_number(NULL, SHIFT_CODE, true);
|
||||
qemu_input_event_send_key_delay(0);
|
||||
}
|
||||
if (keycode & CNTRL) {
|
||||
qemu_input_event_send_key_number(NULL, CNTRL_CODE, true);
|
||||
qemu_input_event_send_key_delay(0);
|
||||
}
|
||||
if (keycode & ALT) {
|
||||
qemu_input_event_send_key_number(NULL, ALT_CODE, true);
|
||||
qemu_input_event_send_key_delay(0);
|
||||
}
|
||||
if (keycode & ALTGR) {
|
||||
qemu_input_event_send_key_number(NULL, GREY | ALT_CODE, true);
|
||||
qemu_input_event_send_key_delay(0);
|
||||
}
|
||||
|
||||
qemu_input_event_send_key_number(NULL, keycode & KEY_MASK, true);
|
||||
qemu_input_event_send_key_delay(0);
|
||||
qemu_input_event_send_key_number(NULL, keycode & KEY_MASK, false);
|
||||
qemu_input_event_send_key_delay(0);
|
||||
|
||||
if (keycode & ALTGR) {
|
||||
qemu_input_event_send_key_number(NULL, GREY | ALT_CODE, false);
|
||||
qemu_input_event_send_key_delay(0);
|
||||
}
|
||||
if (keycode & ALT) {
|
||||
qemu_input_event_send_key_number(NULL, ALT_CODE, false);
|
||||
qemu_input_event_send_key_delay(0);
|
||||
}
|
||||
if (keycode & CNTRL) {
|
||||
qemu_input_event_send_key_number(NULL, CNTRL_CODE, false);
|
||||
qemu_input_event_send_key_delay(0);
|
||||
}
|
||||
if (keycode & SHIFT) {
|
||||
qemu_input_event_send_key_number(NULL, SHIFT_CODE, false);
|
||||
qemu_input_event_send_key_delay(0);
|
||||
}
|
||||
} else {
|
||||
keysym = curses2qemu[chr];
|
||||
|
||||
@@ -74,27 +74,6 @@ int index_from_key(const char *key)
|
||||
return i;
|
||||
}
|
||||
|
||||
static KeyValue **keyvalues;
|
||||
static int keyvalues_size;
|
||||
static QEMUTimer *key_timer;
|
||||
|
||||
static void free_keyvalues(void)
|
||||
{
|
||||
g_free(keyvalues);
|
||||
keyvalues = NULL;
|
||||
keyvalues_size = 0;
|
||||
}
|
||||
|
||||
static void release_keys(void *opaque)
|
||||
{
|
||||
while (keyvalues_size > 0) {
|
||||
qemu_input_event_send_key(NULL, keyvalues[--keyvalues_size],
|
||||
false);
|
||||
}
|
||||
|
||||
free_keyvalues();
|
||||
}
|
||||
|
||||
static KeyValue *copy_key_value(KeyValue *src)
|
||||
{
|
||||
KeyValue *dst = g_new(KeyValue, 1);
|
||||
@@ -107,30 +86,18 @@ void qmp_send_key(KeyValueList *keys, bool has_hold_time, int64_t hold_time,
|
||||
{
|
||||
KeyValueList *p;
|
||||
|
||||
if (!key_timer) {
|
||||
key_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, release_keys, NULL);
|
||||
}
|
||||
|
||||
if (keyvalues != NULL) {
|
||||
timer_del(key_timer);
|
||||
release_keys(NULL);
|
||||
}
|
||||
|
||||
if (!has_hold_time) {
|
||||
hold_time = 100;
|
||||
hold_time = 0; /* use default */
|
||||
}
|
||||
|
||||
for (p = keys; p != NULL; p = p->next) {
|
||||
qemu_input_event_send_key(NULL, copy_key_value(p->value), true);
|
||||
|
||||
keyvalues = g_realloc(keyvalues, sizeof(KeyValue *) *
|
||||
(keyvalues_size + 1));
|
||||
keyvalues[keyvalues_size++] = copy_key_value(p->value);
|
||||
qemu_input_event_send_key_delay(hold_time);
|
||||
}
|
||||
for (p = keys; p != NULL; p = p->next) {
|
||||
qemu_input_event_send_key(NULL, copy_key_value(p->value), false);
|
||||
qemu_input_event_send_key_delay(hold_time);
|
||||
}
|
||||
|
||||
/* delayed key up events */
|
||||
timer_mod(key_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
|
||||
muldiv64(get_ticks_per_sec(), hold_time, 1000));
|
||||
}
|
||||
|
||||
static void legacy_kbd_event(DeviceState *dev, QemuConsole *src,
|
||||
|
||||
108
ui/input.c
108
ui/input.c
@@ -14,11 +14,31 @@ struct QemuInputHandlerState {
|
||||
QemuConsole *con;
|
||||
QTAILQ_ENTRY(QemuInputHandlerState) node;
|
||||
};
|
||||
|
||||
typedef struct QemuInputEventQueue QemuInputEventQueue;
|
||||
struct QemuInputEventQueue {
|
||||
enum {
|
||||
QEMU_INPUT_QUEUE_DELAY = 1,
|
||||
QEMU_INPUT_QUEUE_EVENT,
|
||||
QEMU_INPUT_QUEUE_SYNC,
|
||||
} type;
|
||||
QEMUTimer *timer;
|
||||
uint32_t delay_ms;
|
||||
QemuConsole *src;
|
||||
InputEvent *evt;
|
||||
QTAILQ_ENTRY(QemuInputEventQueue) node;
|
||||
};
|
||||
|
||||
static QTAILQ_HEAD(, QemuInputHandlerState) handlers =
|
||||
QTAILQ_HEAD_INITIALIZER(handlers);
|
||||
static NotifierList mouse_mode_notifiers =
|
||||
NOTIFIER_LIST_INITIALIZER(mouse_mode_notifiers);
|
||||
|
||||
static QTAILQ_HEAD(QemuInputEventQueueHead, QemuInputEventQueue) kbd_queue =
|
||||
QTAILQ_HEAD_INITIALIZER(kbd_queue);
|
||||
static QEMUTimer *kbd_timer;
|
||||
static uint32_t kbd_default_delay_ms = 10;
|
||||
|
||||
QemuInputHandlerState *qemu_input_handler_register(DeviceState *dev,
|
||||
QemuInputHandler *handler)
|
||||
{
|
||||
@@ -171,6 +191,73 @@ static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt)
|
||||
}
|
||||
}
|
||||
|
||||
static void qemu_input_queue_process(void *opaque)
|
||||
{
|
||||
struct QemuInputEventQueueHead *queue = opaque;
|
||||
QemuInputEventQueue *item;
|
||||
|
||||
g_assert(!QTAILQ_EMPTY(queue));
|
||||
item = QTAILQ_FIRST(queue);
|
||||
g_assert(item->type == QEMU_INPUT_QUEUE_DELAY);
|
||||
QTAILQ_REMOVE(queue, item, node);
|
||||
g_free(item);
|
||||
|
||||
while (!QTAILQ_EMPTY(queue)) {
|
||||
item = QTAILQ_FIRST(queue);
|
||||
switch (item->type) {
|
||||
case QEMU_INPUT_QUEUE_DELAY:
|
||||
timer_mod(item->timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL)
|
||||
+ item->delay_ms);
|
||||
return;
|
||||
case QEMU_INPUT_QUEUE_EVENT:
|
||||
qemu_input_event_send(item->src, item->evt);
|
||||
qapi_free_InputEvent(item->evt);
|
||||
break;
|
||||
case QEMU_INPUT_QUEUE_SYNC:
|
||||
qemu_input_event_sync();
|
||||
break;
|
||||
}
|
||||
QTAILQ_REMOVE(queue, item, node);
|
||||
g_free(item);
|
||||
}
|
||||
}
|
||||
|
||||
static void qemu_input_queue_delay(struct QemuInputEventQueueHead *queue,
|
||||
QEMUTimer *timer, uint32_t delay_ms)
|
||||
{
|
||||
QemuInputEventQueue *item = g_new0(QemuInputEventQueue, 1);
|
||||
bool start_timer = QTAILQ_EMPTY(queue);
|
||||
|
||||
item->type = QEMU_INPUT_QUEUE_DELAY;
|
||||
item->delay_ms = delay_ms;
|
||||
item->timer = timer;
|
||||
QTAILQ_INSERT_TAIL(queue, item, node);
|
||||
|
||||
if (start_timer) {
|
||||
timer_mod(item->timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL)
|
||||
+ item->delay_ms);
|
||||
}
|
||||
}
|
||||
|
||||
static void qemu_input_queue_event(struct QemuInputEventQueueHead *queue,
|
||||
QemuConsole *src, InputEvent *evt)
|
||||
{
|
||||
QemuInputEventQueue *item = g_new0(QemuInputEventQueue, 1);
|
||||
|
||||
item->type = QEMU_INPUT_QUEUE_EVENT;
|
||||
item->src = src;
|
||||
item->evt = evt;
|
||||
QTAILQ_INSERT_TAIL(queue, item, node);
|
||||
}
|
||||
|
||||
static void qemu_input_queue_sync(struct QemuInputEventQueueHead *queue)
|
||||
{
|
||||
QemuInputEventQueue *item = g_new0(QemuInputEventQueue, 1);
|
||||
|
||||
item->type = QEMU_INPUT_QUEUE_SYNC;
|
||||
QTAILQ_INSERT_TAIL(queue, item, node);
|
||||
}
|
||||
|
||||
void qemu_input_event_send(QemuConsole *src, InputEvent *evt)
|
||||
{
|
||||
QemuInputHandlerState *s;
|
||||
@@ -230,9 +317,14 @@ void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down)
|
||||
{
|
||||
InputEvent *evt;
|
||||
evt = qemu_input_event_new_key(key, down);
|
||||
qemu_input_event_send(src, evt);
|
||||
qemu_input_event_sync();
|
||||
qapi_free_InputEvent(evt);
|
||||
if (QTAILQ_EMPTY(&kbd_queue)) {
|
||||
qemu_input_event_send(src, evt);
|
||||
qemu_input_event_sync();
|
||||
qapi_free_InputEvent(evt);
|
||||
} else {
|
||||
qemu_input_queue_event(&kbd_queue, src, evt);
|
||||
qemu_input_queue_sync(&kbd_queue);
|
||||
}
|
||||
}
|
||||
|
||||
void qemu_input_event_send_key_number(QemuConsole *src, int num, bool down)
|
||||
@@ -251,6 +343,16 @@ void qemu_input_event_send_key_qcode(QemuConsole *src, QKeyCode q, bool down)
|
||||
qemu_input_event_send_key(src, key, down);
|
||||
}
|
||||
|
||||
void qemu_input_event_send_key_delay(uint32_t delay_ms)
|
||||
{
|
||||
if (!kbd_timer) {
|
||||
kbd_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, qemu_input_queue_process,
|
||||
&kbd_queue);
|
||||
}
|
||||
qemu_input_queue_delay(&kbd_queue, kbd_timer,
|
||||
delay_ms ? delay_ms : kbd_default_delay_ms);
|
||||
}
|
||||
|
||||
InputEvent *qemu_input_event_new_btn(InputButton btn, bool down)
|
||||
{
|
||||
InputEvent *evt = g_new0(InputEvent, 1);
|
||||
|
||||
68
ui/sdl2.c
68
ui/sdl2.c
@@ -49,6 +49,7 @@ static struct sdl2_state {
|
||||
int idx;
|
||||
int last_vm_running; /* per console for caption reasons */
|
||||
int x, y;
|
||||
int hidden;
|
||||
} *sdl2_console;
|
||||
|
||||
static SDL_Surface *guest_sprite_surface;
|
||||
@@ -136,6 +137,9 @@ static void do_sdl_resize(struct sdl2_state *scon, int width, int height,
|
||||
} else {
|
||||
flags |= SDL_WINDOW_RESIZABLE;
|
||||
}
|
||||
if (scon->hidden) {
|
||||
flags |= SDL_WINDOW_HIDDEN;
|
||||
}
|
||||
|
||||
scon->real_window = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED,
|
||||
SDL_WINDOWPOS_UNDEFINED,
|
||||
@@ -210,6 +214,23 @@ static void sdl_process_key(struct sdl2_state *scon,
|
||||
int qcode = sdl2_scancode_to_qcode[ev->keysym.scancode];
|
||||
QemuConsole *con = scon ? scon->dcl.con : NULL;
|
||||
|
||||
if (!qemu_console_is_graphic(con)) {
|
||||
if (ev->type == SDL_KEYDOWN) {
|
||||
switch (ev->keysym.scancode) {
|
||||
case SDL_SCANCODE_RETURN:
|
||||
kbd_put_keysym_console(con, '\n');
|
||||
break;
|
||||
case SDL_SCANCODE_BACKSPACE:
|
||||
kbd_put_keysym_console(con, QEMU_KEY_BACKSPACE);
|
||||
break;
|
||||
default:
|
||||
kbd_put_qcode_console(con, qcode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
switch (ev->keysym.scancode) {
|
||||
#if 0
|
||||
case SDL_SCANCODE_NUMLOCKCLEAR:
|
||||
@@ -305,6 +326,11 @@ static void sdl_show_cursor(void)
|
||||
|
||||
static void sdl_grab_start(struct sdl2_state *scon)
|
||||
{
|
||||
QemuConsole *con = scon ? scon->dcl.con : NULL;
|
||||
|
||||
if (!con || !qemu_console_is_graphic(con)) {
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* If the application is not active, do not try to enter grab state. This
|
||||
* prevents 'SDL_WM_GrabInput(SDL_GRAB_ON)' from blocking all the
|
||||
@@ -458,7 +484,7 @@ static void toggle_full_screen(struct sdl2_state *scon)
|
||||
|
||||
static void handle_keydown(SDL_Event *ev)
|
||||
{
|
||||
int mod_state;
|
||||
int mod_state, win;
|
||||
struct sdl2_state *scon = get_scon_from_window(ev->key.windowID);
|
||||
|
||||
if (alt_grab) {
|
||||
@@ -473,6 +499,27 @@ static void handle_keydown(SDL_Event *ev)
|
||||
|
||||
if (gui_key_modifier_pressed) {
|
||||
switch (ev->key.keysym.scancode) {
|
||||
case SDL_SCANCODE_2:
|
||||
case SDL_SCANCODE_3:
|
||||
case SDL_SCANCODE_4:
|
||||
case SDL_SCANCODE_5:
|
||||
case SDL_SCANCODE_6:
|
||||
case SDL_SCANCODE_7:
|
||||
case SDL_SCANCODE_8:
|
||||
case SDL_SCANCODE_9:
|
||||
win = ev->key.keysym.scancode - SDL_SCANCODE_1;
|
||||
if (win < sdl2_num_outputs) {
|
||||
sdl2_console[win].hidden = !sdl2_console[win].hidden;
|
||||
if (sdl2_console[win].real_window) {
|
||||
if (sdl2_console[win].hidden) {
|
||||
SDL_HideWindow(sdl2_console[win].real_window);
|
||||
} else {
|
||||
SDL_ShowWindow(sdl2_console[win].real_window);
|
||||
}
|
||||
}
|
||||
gui_keysym = 1;
|
||||
}
|
||||
break;
|
||||
case SDL_SCANCODE_F:
|
||||
toggle_full_screen(scon);
|
||||
gui_keysym = 1;
|
||||
@@ -544,6 +591,17 @@ static void handle_keyup(SDL_Event *ev)
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_textinput(SDL_Event *ev)
|
||||
{
|
||||
struct sdl2_state *scon = get_scon_from_window(ev->key.windowID);
|
||||
QemuConsole *con = scon ? scon->dcl.con : NULL;
|
||||
|
||||
if (qemu_console_is_graphic(con)) {
|
||||
return;
|
||||
}
|
||||
kbd_put_string_console(con, ev->text.text, strlen(ev->text.text));
|
||||
}
|
||||
|
||||
static void handle_mousemotion(SDL_Event *ev)
|
||||
{
|
||||
int max_x, max_y;
|
||||
@@ -680,6 +738,9 @@ static void sdl_refresh(DisplayChangeListener *dcl)
|
||||
case SDL_KEYUP:
|
||||
handle_keyup(ev);
|
||||
break;
|
||||
case SDL_TEXTINPUT:
|
||||
handle_textinput(ev);
|
||||
break;
|
||||
case SDL_QUIT:
|
||||
if (!no_quit) {
|
||||
no_shutdown = 0;
|
||||
@@ -808,7 +869,7 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
|
||||
|
||||
for (i = 0;; i++) {
|
||||
QemuConsole *con = qemu_console_lookup_by_index(i);
|
||||
if (!con || !qemu_console_is_graphic(con)) {
|
||||
if (!con) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -816,6 +877,9 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
|
||||
sdl2_console = g_new0(struct sdl2_state, sdl2_num_outputs);
|
||||
for (i = 0; i < sdl2_num_outputs; i++) {
|
||||
QemuConsole *con = qemu_console_lookup_by_index(i);
|
||||
if (!qemu_console_is_graphic(con)) {
|
||||
sdl2_console[i].hidden = true;
|
||||
}
|
||||
sdl2_console[i].dcl.ops = &dcl_ops;
|
||||
sdl2_console[i].dcl.con = con;
|
||||
register_displaychangelistener(&sdl2_console[i].dcl);
|
||||
|
||||
@@ -181,6 +181,10 @@ tight_detect_smooth_image24(VncState *vs, int w, int h)
|
||||
}
|
||||
}
|
||||
|
||||
if (pixels == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 95% smooth or more ... */
|
||||
if (stats[0] * 33 / pixels >= 95) {
|
||||
return 0;
|
||||
@@ -267,7 +271,9 @@ tight_detect_smooth_image24(VncState *vs, int w, int h)
|
||||
y += w; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
if (pixels == 0) { \
|
||||
return 0; \
|
||||
} \
|
||||
if ((stats[0] + stats[1]) * 100 / pixels >= 90) { \
|
||||
return 0; \
|
||||
} \
|
||||
|
||||
63
ui/vnc.c
63
ui/vnc.c
@@ -26,6 +26,7 @@
|
||||
|
||||
#include "vnc.h"
|
||||
#include "vnc-jobs.h"
|
||||
#include "trace.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "qemu/sockets.h"
|
||||
#include "qemu/timer.h"
|
||||
@@ -1552,7 +1553,9 @@ static void press_key(VncState *vs, int keysym)
|
||||
{
|
||||
int keycode = keysym2scancode(vs->vd->kbd_layout, keysym) & SCANCODE_KEYMASK;
|
||||
qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, true);
|
||||
qemu_input_event_send_key_delay(0);
|
||||
qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, false);
|
||||
qemu_input_event_send_key_delay(0);
|
||||
}
|
||||
|
||||
static int current_led_state(VncState *vs)
|
||||
@@ -1597,6 +1600,10 @@ static void kbd_leds(void *opaque, int ledstate)
|
||||
int caps, num, scr;
|
||||
bool has_changed = (ledstate != current_led_state(vs));
|
||||
|
||||
trace_vnc_key_guest_leds((ledstate & QEMU_CAPS_LOCK_LED),
|
||||
(ledstate & QEMU_NUM_LOCK_LED),
|
||||
(ledstate & QEMU_SCROLL_LOCK_LED));
|
||||
|
||||
caps = ledstate & QEMU_CAPS_LOCK_LED ? 1 : 0;
|
||||
num = ledstate & QEMU_NUM_LOCK_LED ? 1 : 0;
|
||||
scr = ledstate & QEMU_SCROLL_LOCK_LED ? 1 : 0;
|
||||
@@ -1659,11 +1666,13 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym)
|
||||
*/
|
||||
if (keysym_is_numlock(vs->vd->kbd_layout, sym & 0xFFFF)) {
|
||||
if (!vs->modifiers_state[0x45]) {
|
||||
trace_vnc_key_sync_numlock(true);
|
||||
vs->modifiers_state[0x45] = 1;
|
||||
press_key(vs, 0xff7f);
|
||||
}
|
||||
} else {
|
||||
if (vs->modifiers_state[0x45]) {
|
||||
trace_vnc_key_sync_numlock(false);
|
||||
vs->modifiers_state[0x45] = 0;
|
||||
press_key(vs, 0xff7f);
|
||||
}
|
||||
@@ -1682,11 +1691,13 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym)
|
||||
int capslock = !!(vs->modifiers_state[0x3a]);
|
||||
if (capslock) {
|
||||
if (uppercase == shift) {
|
||||
trace_vnc_key_sync_capslock(false);
|
||||
vs->modifiers_state[0x3a] = 0;
|
||||
press_key(vs, 0xffe5);
|
||||
}
|
||||
} else {
|
||||
if (uppercase != shift) {
|
||||
trace_vnc_key_sync_capslock(true);
|
||||
vs->modifiers_state[0x3a] = 1;
|
||||
press_key(vs, 0xffe5);
|
||||
}
|
||||
@@ -1819,6 +1830,11 @@ static void vnc_release_modifiers(VncState *vs)
|
||||
}
|
||||
}
|
||||
|
||||
static const char *code2name(int keycode)
|
||||
{
|
||||
return QKeyCode_lookup[qemu_input_key_number_to_qcode(keycode)];
|
||||
}
|
||||
|
||||
static void key_event(VncState *vs, int down, uint32_t sym)
|
||||
{
|
||||
int keycode;
|
||||
@@ -1829,6 +1845,7 @@ static void key_event(VncState *vs, int down, uint32_t sym)
|
||||
}
|
||||
|
||||
keycode = keysym2scancode(vs->vd->kbd_layout, lsym & 0xFFFF) & SCANCODE_KEYMASK;
|
||||
trace_vnc_key_event_map(down, sym, keycode, code2name(keycode));
|
||||
do_key_event(vs, down, keycode, sym);
|
||||
}
|
||||
|
||||
@@ -1836,10 +1853,12 @@ static void ext_key_event(VncState *vs, int down,
|
||||
uint32_t sym, uint16_t keycode)
|
||||
{
|
||||
/* if the user specifies a keyboard layout, always use it */
|
||||
if (keyboard_layout)
|
||||
if (keyboard_layout) {
|
||||
key_event(vs, down, sym);
|
||||
else
|
||||
} else {
|
||||
trace_vnc_key_event_ext(down, sym, keycode, code2name(keycode));
|
||||
do_key_event(vs, down, keycode, sym);
|
||||
}
|
||||
}
|
||||
|
||||
static void framebuffer_update_request(VncState *vs, int incremental,
|
||||
@@ -2929,10 +2948,12 @@ void vnc_display_init(DisplayState *ds)
|
||||
QTAILQ_INIT(&vs->clients);
|
||||
vs->expires = TIME_MAX;
|
||||
|
||||
if (keyboard_layout)
|
||||
if (keyboard_layout) {
|
||||
trace_vnc_key_map_init(keyboard_layout);
|
||||
vs->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
|
||||
else
|
||||
} else {
|
||||
vs->kbd_layout = init_keyboard_layout(name2keysym, "en-us");
|
||||
}
|
||||
|
||||
if (!vs->kbd_layout)
|
||||
exit(1);
|
||||
@@ -2976,26 +2997,6 @@ static void vnc_display_close(DisplayState *ds)
|
||||
#endif
|
||||
}
|
||||
|
||||
static int vnc_display_disable_login(DisplayState *ds)
|
||||
{
|
||||
VncDisplay *vs = vnc_display;
|
||||
|
||||
if (!vs) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (vs->password) {
|
||||
g_free(vs->password);
|
||||
}
|
||||
|
||||
vs->password = NULL;
|
||||
if (vs->auth == VNC_AUTH_NONE) {
|
||||
vs->auth = VNC_AUTH_VNC;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vnc_display_password(DisplayState *ds, const char *password)
|
||||
{
|
||||
VncDisplay *vs = vnc_display;
|
||||
@@ -3003,20 +3004,18 @@ int vnc_display_password(DisplayState *ds, const char *password)
|
||||
if (!vs) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!password) {
|
||||
/* This is not the intention of this interface but err on the side
|
||||
of being safe */
|
||||
return vnc_display_disable_login(ds);
|
||||
if (vs->auth == VNC_AUTH_NONE) {
|
||||
error_printf_unless_qmp("If you want use passwords please enable "
|
||||
"password auth using '-vnc ${dpy},password'.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (vs->password) {
|
||||
g_free(vs->password);
|
||||
vs->password = NULL;
|
||||
}
|
||||
vs->password = g_strdup(password);
|
||||
if (vs->auth == VNC_AUTH_NONE) {
|
||||
vs->auth = VNC_AUTH_VNC;
|
||||
if (password) {
|
||||
vs->password = g_strdup(password);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user