Compare commits
10 Commits
pull-conso
...
pull-usb-7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8d1bd3c901 | ||
|
|
56a9f18051 | ||
|
|
b664b80f19 | ||
|
|
19e8393170 | ||
|
|
22513a9b44 | ||
|
|
68206d7342 | ||
|
|
36084d7e31 | ||
|
|
f995523582 | ||
|
|
058fdcf52c | ||
|
|
463c534db5 |
@@ -46,6 +46,7 @@ enum mtp_code {
|
|||||||
|
|
||||||
/* response codes */
|
/* response codes */
|
||||||
RES_OK = 0x2001,
|
RES_OK = 0x2001,
|
||||||
|
RES_GENERAL_ERROR = 0x2002,
|
||||||
RES_SESSION_NOT_OPEN = 0x2003,
|
RES_SESSION_NOT_OPEN = 0x2003,
|
||||||
RES_INVALID_TRANSACTION_ID = 0x2004,
|
RES_INVALID_TRANSACTION_ID = 0x2004,
|
||||||
RES_OPERATION_NOT_SUPPORTED = 0x2005,
|
RES_OPERATION_NOT_SUPPORTED = 0x2005,
|
||||||
@@ -109,7 +110,8 @@ struct MTPObject {
|
|||||||
struct stat stat;
|
struct stat stat;
|
||||||
MTPObject *parent;
|
MTPObject *parent;
|
||||||
MTPObject **children;
|
MTPObject **children;
|
||||||
int32_t nchildren;
|
uint32_t nchildren;
|
||||||
|
bool have_children;
|
||||||
QTAILQ_ENTRY(MTPObject) next;
|
QTAILQ_ENTRY(MTPObject) next;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -273,7 +275,6 @@ static MTPObject *usb_mtp_object_alloc(MTPState *s, uint32_t handle,
|
|||||||
o->handle = handle;
|
o->handle = handle;
|
||||||
o->parent = parent;
|
o->parent = parent;
|
||||||
o->name = g_strdup(name);
|
o->name = g_strdup(name);
|
||||||
o->nchildren = -1;
|
|
||||||
if (parent == NULL) {
|
if (parent == NULL) {
|
||||||
o->path = g_strdup(name);
|
o->path = g_strdup(name);
|
||||||
} else {
|
} else {
|
||||||
@@ -340,7 +341,11 @@ static void usb_mtp_object_readdir(MTPState *s, MTPObject *o)
|
|||||||
struct dirent *entry;
|
struct dirent *entry;
|
||||||
DIR *dir;
|
DIR *dir;
|
||||||
|
|
||||||
o->nchildren = 0;
|
if (o->have_children) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
o->have_children = true;
|
||||||
|
|
||||||
dir = opendir(o->path);
|
dir = opendir(o->path);
|
||||||
if (!dir) {
|
if (!dir) {
|
||||||
return;
|
return;
|
||||||
@@ -698,7 +703,10 @@ static MTPData *usb_mtp_get_partial_object(MTPState *s, MTPControl *c,
|
|||||||
if (offset > o->stat.st_size) {
|
if (offset > o->stat.st_size) {
|
||||||
offset = o->stat.st_size;
|
offset = o->stat.st_size;
|
||||||
}
|
}
|
||||||
lseek(d->fd, offset, SEEK_SET);
|
if (lseek(d->fd, offset, SEEK_SET) < 0) {
|
||||||
|
usb_mtp_data_free(d);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
d->length = c->argv[2];
|
d->length = c->argv[2];
|
||||||
if (d->length > o->stat.st_size - offset) {
|
if (d->length > o->stat.st_size - offset) {
|
||||||
@@ -789,9 +797,7 @@ static void usb_mtp_command(MTPState *s, MTPControl *c)
|
|||||||
c->trans, 0, 0, 0);
|
c->trans, 0, 0, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (o->nchildren == -1) {
|
usb_mtp_object_readdir(s, o);
|
||||||
usb_mtp_object_readdir(s, o);
|
|
||||||
}
|
|
||||||
if (c->code == CMD_GET_NUM_OBJECTS) {
|
if (c->code == CMD_GET_NUM_OBJECTS) {
|
||||||
trace_usb_mtp_op_get_num_objects(s->dev.addr, o->handle, o->path);
|
trace_usb_mtp_op_get_num_objects(s->dev.addr, o->handle, o->path);
|
||||||
nres = 1;
|
nres = 1;
|
||||||
@@ -823,7 +829,9 @@ static void usb_mtp_command(MTPState *s, MTPControl *c)
|
|||||||
}
|
}
|
||||||
data_in = usb_mtp_get_object(s, c, o);
|
data_in = usb_mtp_get_object(s, c, o);
|
||||||
if (NULL == data_in) {
|
if (NULL == data_in) {
|
||||||
fprintf(stderr, "%s: TODO: handle error\n", __func__);
|
usb_mtp_queue_result(s, RES_GENERAL_ERROR,
|
||||||
|
c->trans, 0, 0, 0);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CMD_GET_PARTIAL_OBJECT:
|
case CMD_GET_PARTIAL_OBJECT:
|
||||||
@@ -840,7 +848,9 @@ static void usb_mtp_command(MTPState *s, MTPControl *c)
|
|||||||
}
|
}
|
||||||
data_in = usb_mtp_get_partial_object(s, c, o);
|
data_in = usb_mtp_get_partial_object(s, c, o);
|
||||||
if (NULL == data_in) {
|
if (NULL == data_in) {
|
||||||
fprintf(stderr, "%s: TODO: handle error\n", __func__);
|
usb_mtp_queue_result(s, RES_GENERAL_ERROR,
|
||||||
|
c->trans, 0, 0, 0);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
nres = 1;
|
nres = 1;
|
||||||
res0 = data_in->length;
|
res0 = data_in->length;
|
||||||
|
|||||||
@@ -621,6 +621,11 @@ static const char *ep_state_name(uint32_t state)
|
|||||||
ARRAY_SIZE(ep_state_names));
|
ARRAY_SIZE(ep_state_names));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool xhci_get_flag(XHCIState *xhci, enum xhci_flags bit)
|
||||||
|
{
|
||||||
|
return xhci->flags & (1 << bit);
|
||||||
|
}
|
||||||
|
|
||||||
static uint64_t xhci_mfindex_get(XHCIState *xhci)
|
static uint64_t xhci_mfindex_get(XHCIState *xhci)
|
||||||
{
|
{
|
||||||
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||||
@@ -3435,7 +3440,7 @@ static void xhci_child_detach(USBPort *uport, USBDevice *child)
|
|||||||
USBBus *bus = usb_bus_from_device(child);
|
USBBus *bus = usb_bus_from_device(child);
|
||||||
XHCIState *xhci = container_of(bus, XHCIState, bus);
|
XHCIState *xhci = container_of(bus, XHCIState, bus);
|
||||||
|
|
||||||
xhci_detach_slot(xhci, uport);
|
xhci_detach_slot(xhci, child->port);
|
||||||
}
|
}
|
||||||
|
|
||||||
static USBPortOps xhci_uport_ops = {
|
static USBPortOps xhci_uport_ops = {
|
||||||
@@ -3594,13 +3599,15 @@ static int usb_xhci_initfn(struct PCIDevice *dev)
|
|||||||
PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64,
|
PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64,
|
||||||
&xhci->mem);
|
&xhci->mem);
|
||||||
|
|
||||||
ret = pcie_endpoint_cap_init(dev, 0xa0);
|
if (pci_bus_is_express(dev->bus)) {
|
||||||
assert(ret >= 0);
|
ret = pcie_endpoint_cap_init(dev, 0xa0);
|
||||||
|
assert(ret >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (xhci->flags & (1 << XHCI_FLAG_USE_MSI)) {
|
if (xhci_get_flag(xhci, XHCI_FLAG_USE_MSI)) {
|
||||||
msi_init(dev, 0x70, xhci->numintrs, true, false);
|
msi_init(dev, 0x70, xhci->numintrs, true, false);
|
||||||
}
|
}
|
||||||
if (xhci->flags & (1 << XHCI_FLAG_USE_MSI_X)) {
|
if (xhci_get_flag(xhci, XHCI_FLAG_USE_MSI_X)) {
|
||||||
msix_init(dev, xhci->numintrs,
|
msix_init(dev, xhci->numintrs,
|
||||||
&xhci->mem, 0, OFF_MSIX_TABLE,
|
&xhci->mem, 0, OFF_MSIX_TABLE,
|
||||||
&xhci->mem, 0, OFF_MSIX_PBA,
|
&xhci->mem, 0, OFF_MSIX_PBA,
|
||||||
|
|||||||
@@ -720,6 +720,9 @@ static void usb_host_ep_update(USBHostDevice *s)
|
|||||||
struct libusb_config_descriptor *conf;
|
struct libusb_config_descriptor *conf;
|
||||||
const struct libusb_interface_descriptor *intf;
|
const struct libusb_interface_descriptor *intf;
|
||||||
const struct libusb_endpoint_descriptor *endp;
|
const struct libusb_endpoint_descriptor *endp;
|
||||||
|
#if LIBUSBX_API_VERSION >= 0x01000103
|
||||||
|
struct libusb_ss_endpoint_companion_descriptor *endp_ss_comp;
|
||||||
|
#endif
|
||||||
uint8_t devep, type;
|
uint8_t devep, type;
|
||||||
int pid, ep;
|
int pid, ep;
|
||||||
int rc, i, e;
|
int rc, i, e;
|
||||||
@@ -765,6 +768,15 @@ static void usb_host_ep_update(USBHostDevice *s)
|
|||||||
usb_ep_set_type(udev, pid, ep, type);
|
usb_ep_set_type(udev, pid, ep, type);
|
||||||
usb_ep_set_ifnum(udev, pid, ep, i);
|
usb_ep_set_ifnum(udev, pid, ep, i);
|
||||||
usb_ep_set_halted(udev, pid, ep, 0);
|
usb_ep_set_halted(udev, pid, ep, 0);
|
||||||
|
#if LIBUSBX_API_VERSION >= 0x01000103
|
||||||
|
if (type == LIBUSB_TRANSFER_TYPE_BULK &&
|
||||||
|
libusb_get_ss_endpoint_companion_descriptor(ctx, endp,
|
||||||
|
&endp_ss_comp) == LIBUSB_SUCCESS) {
|
||||||
|
usb_ep_set_max_streams(udev, pid, ep,
|
||||||
|
endp_ss_comp->bmAttributes);
|
||||||
|
libusb_free_ss_endpoint_companion_descriptor(endp_ss_comp);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1202,10 +1214,23 @@ static void usb_host_handle_data(USBDevice *udev, USBPacket *p)
|
|||||||
usb_packet_copy(p, r->buffer, size);
|
usb_packet_copy(p, r->buffer, size);
|
||||||
}
|
}
|
||||||
ep = p->ep->nr | (r->in ? USB_DIR_IN : 0);
|
ep = p->ep->nr | (r->in ? USB_DIR_IN : 0);
|
||||||
libusb_fill_bulk_transfer(r->xfer, s->dh, ep,
|
if (p->stream) {
|
||||||
r->buffer, size,
|
#if LIBUSBX_API_VERSION >= 0x01000103
|
||||||
usb_host_req_complete_data, r,
|
libusb_fill_bulk_stream_transfer(r->xfer, s->dh, ep, p->stream,
|
||||||
BULK_TIMEOUT);
|
r->buffer, size,
|
||||||
|
usb_host_req_complete_data, r,
|
||||||
|
BULK_TIMEOUT);
|
||||||
|
#else
|
||||||
|
usb_host_req_free(r);
|
||||||
|
p->status = USB_RET_STALL;
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
libusb_fill_bulk_transfer(r->xfer, s->dh, ep,
|
||||||
|
r->buffer, size,
|
||||||
|
usb_host_req_complete_data, r,
|
||||||
|
BULK_TIMEOUT);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case USB_ENDPOINT_XFER_INT:
|
case USB_ENDPOINT_XFER_INT:
|
||||||
r = usb_host_req_alloc(s, p, p->pid == USB_TOKEN_IN, p->iov.size);
|
r = usb_host_req_alloc(s, p, p->pid == USB_TOKEN_IN, p->iov.size);
|
||||||
@@ -1268,6 +1293,54 @@ 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
|
||||||
|
USBHostDevice *s = USB_HOST_DEVICE(udev);
|
||||||
|
unsigned char endpoints[30];
|
||||||
|
int i, rc;
|
||||||
|
|
||||||
|
for (i = 0; i < nr_eps; i++) {
|
||||||
|
endpoints[i] = eps[i]->nr;
|
||||||
|
if (eps[i]->pid == USB_TOKEN_IN) {
|
||||||
|
endpoints[i] |= 0x80;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rc = libusb_alloc_streams(s->dh, streams, endpoints, nr_eps);
|
||||||
|
if (rc < 0) {
|
||||||
|
usb_host_libusb_error("libusb_alloc_streams", rc);
|
||||||
|
} else if (rc != streams) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"libusb_alloc_streams: got less streams then requested %d < %d\n",
|
||||||
|
rc, streams);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (rc == streams) ? 0 : -1;
|
||||||
|
#else
|
||||||
|
fprintf(stderr, "libusb_alloc_streams: error not implemented\n");
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usb_host_free_streams(USBDevice *udev, USBEndpoint **eps,
|
||||||
|
int nr_eps)
|
||||||
|
{
|
||||||
|
#if LIBUSBX_API_VERSION >= 0x01000103
|
||||||
|
USBHostDevice *s = USB_HOST_DEVICE(udev);
|
||||||
|
unsigned char endpoints[30];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < nr_eps; i++) {
|
||||||
|
endpoints[i] = eps[i]->nr;
|
||||||
|
if (eps[i]->pid == USB_TOKEN_IN) {
|
||||||
|
endpoints[i] |= 0x80;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
libusb_free_streams(s->dh, endpoints, nr_eps);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is *NOT* about restoring state. We have absolutely no idea
|
* This is *NOT* about restoring state. We have absolutely no idea
|
||||||
* what state the host device is in at the moment and whenever it is
|
* what state the host device is in at the moment and whenever it is
|
||||||
@@ -1349,6 +1422,8 @@ static void usb_host_class_initfn(ObjectClass *klass, void *data)
|
|||||||
uc->handle_reset = usb_host_handle_reset;
|
uc->handle_reset = usb_host_handle_reset;
|
||||||
uc->handle_destroy = usb_host_handle_destroy;
|
uc->handle_destroy = usb_host_handle_destroy;
|
||||||
uc->flush_ep_queue = usb_host_flush_ep_queue;
|
uc->flush_ep_queue = usb_host_flush_ep_queue;
|
||||||
|
uc->alloc_streams = usb_host_alloc_streams;
|
||||||
|
uc->free_streams = usb_host_free_streams;
|
||||||
dc->vmsd = &vmstate_usb_host;
|
dc->vmsd = &vmstate_usb_host;
|
||||||
dc->props = usb_host_dev_properties;
|
dc->props = usb_host_dev_properties;
|
||||||
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
|
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
|
||||||
|
|||||||
@@ -50,6 +50,10 @@
|
|||||||
((i) & 0x10) ? USB_TOKEN_IN : USB_TOKEN_OUT, \
|
((i) & 0x10) ? USB_TOKEN_IN : USB_TOKEN_OUT, \
|
||||||
(i) & 0x0f))
|
(i) & 0x0f))
|
||||||
|
|
||||||
|
#ifndef USBREDIR_VERSION /* This is not defined in older usbredir versions */
|
||||||
|
#define USBREDIR_VERSION 0
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct USBRedirDevice USBRedirDevice;
|
typedef struct USBRedirDevice USBRedirDevice;
|
||||||
|
|
||||||
/* Struct to hold buffered packets */
|
/* Struct to hold buffered packets */
|
||||||
@@ -68,6 +72,7 @@ struct endp_data {
|
|||||||
uint8_t interval;
|
uint8_t interval;
|
||||||
uint8_t interface; /* bInterfaceNumber this ep belongs to */
|
uint8_t interface; /* bInterfaceNumber this ep belongs to */
|
||||||
uint16_t max_packet_size; /* In bytes, not wMaxPacketSize format !! */
|
uint16_t max_packet_size; /* In bytes, not wMaxPacketSize format !! */
|
||||||
|
uint32_t max_streams;
|
||||||
uint8_t iso_started;
|
uint8_t iso_started;
|
||||||
uint8_t iso_error; /* For reporting iso errors to the HC */
|
uint8_t iso_error; /* For reporting iso errors to the HC */
|
||||||
uint8_t interrupt_started;
|
uint8_t interrupt_started;
|
||||||
@@ -106,8 +111,9 @@ struct USBRedirDevice {
|
|||||||
int read_buf_size;
|
int read_buf_size;
|
||||||
/* Active chardev-watch-tag */
|
/* Active chardev-watch-tag */
|
||||||
guint watch;
|
guint watch;
|
||||||
/* For async handling of close */
|
/* For async handling of close / reject */
|
||||||
QEMUBH *chardev_close_bh;
|
QEMUBH *chardev_close_bh;
|
||||||
|
QEMUBH *device_reject_bh;
|
||||||
/* To delay the usb attach in case of quick chardev close + open */
|
/* To delay the usb attach in case of quick chardev close + open */
|
||||||
QEMUTimer *attach_timer;
|
QEMUTimer *attach_timer;
|
||||||
int64_t next_attach_time;
|
int64_t next_attach_time;
|
||||||
@@ -780,11 +786,12 @@ static void usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p,
|
|||||||
dev->endpoint[EP2I(ep)].bulk_receiving_enabled = 0;
|
dev->endpoint[EP2I(ep)].bulk_receiving_enabled = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
DPRINTF("bulk-out ep %02X len %zd id %"PRIu64"\n", ep, size, p->id);
|
DPRINTF("bulk-out ep %02X stream %u len %zd id %"PRIu64"\n",
|
||||||
|
ep, p->stream, size, p->id);
|
||||||
|
|
||||||
bulk_packet.endpoint = ep;
|
bulk_packet.endpoint = ep;
|
||||||
bulk_packet.length = size;
|
bulk_packet.length = size;
|
||||||
bulk_packet.stream_id = 0;
|
bulk_packet.stream_id = p->stream;
|
||||||
bulk_packet.length_high = size >> 16;
|
bulk_packet.length_high = size >> 16;
|
||||||
assert(bulk_packet.length_high == 0 ||
|
assert(bulk_packet.length_high == 0 ||
|
||||||
usbredirparser_peer_has_cap(dev->parser,
|
usbredirparser_peer_has_cap(dev->parser,
|
||||||
@@ -1091,6 +1098,66 @@ static void usbredir_handle_control(USBDevice *udev, USBPacket *p,
|
|||||||
p->status = USB_RET_ASYNC;
|
p->status = USB_RET_ASYNC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int usbredir_alloc_streams(USBDevice *udev, USBEndpoint **eps,
|
||||||
|
int nr_eps, int streams)
|
||||||
|
{
|
||||||
|
USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
|
||||||
|
#if USBREDIR_VERSION >= 0x000700
|
||||||
|
struct usb_redir_alloc_bulk_streams_header alloc_streams;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!usbredirparser_peer_has_cap(dev->parser,
|
||||||
|
usb_redir_cap_bulk_streams)) {
|
||||||
|
ERROR("peer does not support streams\n");
|
||||||
|
goto reject;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (streams == 0) {
|
||||||
|
ERROR("request to allocate 0 streams\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
alloc_streams.no_streams = streams;
|
||||||
|
alloc_streams.endpoints = 0;
|
||||||
|
for (i = 0; i < nr_eps; i++) {
|
||||||
|
alloc_streams.endpoints |= 1 << USBEP2I(eps[i]);
|
||||||
|
}
|
||||||
|
usbredirparser_send_alloc_bulk_streams(dev->parser, 0, &alloc_streams);
|
||||||
|
usbredirparser_do_write(dev->parser);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
#else
|
||||||
|
ERROR("usbredir_alloc_streams not implemented\n");
|
||||||
|
goto reject;
|
||||||
|
#endif
|
||||||
|
reject:
|
||||||
|
ERROR("streams are not available, disconnecting\n");
|
||||||
|
qemu_bh_schedule(dev->device_reject_bh);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usbredir_free_streams(USBDevice *udev, USBEndpoint **eps,
|
||||||
|
int nr_eps)
|
||||||
|
{
|
||||||
|
#if USBREDIR_VERSION >= 0x000700
|
||||||
|
USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
|
||||||
|
struct usb_redir_free_bulk_streams_header free_streams;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!usbredirparser_peer_has_cap(dev->parser,
|
||||||
|
usb_redir_cap_bulk_streams)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
free_streams.endpoints = 0;
|
||||||
|
for (i = 0; i < nr_eps; i++) {
|
||||||
|
free_streams.endpoints |= 1 << USBEP2I(eps[i]);
|
||||||
|
}
|
||||||
|
usbredirparser_send_free_bulk_streams(dev->parser, 0, &free_streams);
|
||||||
|
usbredirparser_do_write(dev->parser);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Close events can be triggered by usbredirparser_do_write which gets called
|
* Close events can be triggered by usbredirparser_do_write which gets called
|
||||||
* from within the USBDevice data / control packet callbacks and doing a
|
* from within the USBDevice data / control packet callbacks and doing a
|
||||||
@@ -1102,6 +1169,7 @@ static void usbredir_chardev_close_bh(void *opaque)
|
|||||||
{
|
{
|
||||||
USBRedirDevice *dev = opaque;
|
USBRedirDevice *dev = opaque;
|
||||||
|
|
||||||
|
qemu_bh_cancel(dev->device_reject_bh);
|
||||||
usbredir_device_disconnect(dev);
|
usbredir_device_disconnect(dev);
|
||||||
|
|
||||||
if (dev->parser) {
|
if (dev->parser) {
|
||||||
@@ -1153,6 +1221,9 @@ static void usbredir_create_parser(USBRedirDevice *dev)
|
|||||||
usbredirparser_caps_set_cap(caps, usb_redir_cap_64bits_ids);
|
usbredirparser_caps_set_cap(caps, usb_redir_cap_64bits_ids);
|
||||||
usbredirparser_caps_set_cap(caps, usb_redir_cap_32bits_bulk_length);
|
usbredirparser_caps_set_cap(caps, usb_redir_cap_32bits_bulk_length);
|
||||||
usbredirparser_caps_set_cap(caps, usb_redir_cap_bulk_receiving);
|
usbredirparser_caps_set_cap(caps, usb_redir_cap_bulk_receiving);
|
||||||
|
#if USBREDIR_VERSION >= 0x000700
|
||||||
|
usbredirparser_caps_set_cap(caps, usb_redir_cap_bulk_streams);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (runstate_check(RUN_STATE_INMIGRATE)) {
|
if (runstate_check(RUN_STATE_INMIGRATE)) {
|
||||||
flags |= usbredirparser_fl_no_hello;
|
flags |= usbredirparser_fl_no_hello;
|
||||||
@@ -1171,6 +1242,17 @@ static void usbredir_reject_device(USBRedirDevice *dev)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We may need to reject the device when the hcd calls alloc_streams, doing
|
||||||
|
* an usb_detach from within a hcd call is not a good idea, hence this bh.
|
||||||
|
*/
|
||||||
|
static void usbredir_device_reject_bh(void *opaque)
|
||||||
|
{
|
||||||
|
USBRedirDevice *dev = opaque;
|
||||||
|
|
||||||
|
usbredir_reject_device(dev);
|
||||||
|
}
|
||||||
|
|
||||||
static void usbredir_do_attach(void *opaque)
|
static void usbredir_do_attach(void *opaque)
|
||||||
{
|
{
|
||||||
USBRedirDevice *dev = opaque;
|
USBRedirDevice *dev = opaque;
|
||||||
@@ -1297,6 +1379,7 @@ static int usbredir_initfn(USBDevice *udev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
dev->chardev_close_bh = qemu_bh_new(usbredir_chardev_close_bh, dev);
|
dev->chardev_close_bh = qemu_bh_new(usbredir_chardev_close_bh, dev);
|
||||||
|
dev->device_reject_bh = qemu_bh_new(usbredir_device_reject_bh, dev);
|
||||||
dev->attach_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, usbredir_do_attach, dev);
|
dev->attach_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, usbredir_do_attach, dev);
|
||||||
|
|
||||||
packet_id_queue_init(&dev->cancelled, dev, "cancelled");
|
packet_id_queue_init(&dev->cancelled, dev, "cancelled");
|
||||||
@@ -1337,6 +1420,7 @@ static void usbredir_handle_destroy(USBDevice *udev)
|
|||||||
dev->cs = NULL;
|
dev->cs = NULL;
|
||||||
/* Note must be done after qemu_chr_close, as that causes a close event */
|
/* Note must be done after qemu_chr_close, as that causes a close event */
|
||||||
qemu_bh_delete(dev->chardev_close_bh);
|
qemu_bh_delete(dev->chardev_close_bh);
|
||||||
|
qemu_bh_delete(dev->device_reject_bh);
|
||||||
|
|
||||||
timer_del(dev->attach_timer);
|
timer_del(dev->attach_timer);
|
||||||
timer_free(dev->attach_timer);
|
timer_free(dev->attach_timer);
|
||||||
@@ -1628,6 +1712,7 @@ static void usbredir_setup_usb_eps(USBRedirDevice *dev)
|
|||||||
usb_ep->type = dev->endpoint[i].type;
|
usb_ep->type = dev->endpoint[i].type;
|
||||||
usb_ep->ifnum = dev->endpoint[i].interface;
|
usb_ep->ifnum = dev->endpoint[i].interface;
|
||||||
usb_ep->max_packet_size = dev->endpoint[i].max_packet_size;
|
usb_ep->max_packet_size = dev->endpoint[i].max_packet_size;
|
||||||
|
usb_ep->max_streams = dev->endpoint[i].max_streams;
|
||||||
usbredir_set_pipeline(dev, usb_ep);
|
usbredir_set_pipeline(dev, usb_ep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1646,6 +1731,12 @@ static void usbredir_ep_info(void *priv,
|
|||||||
usb_redir_cap_ep_info_max_packet_size)) {
|
usb_redir_cap_ep_info_max_packet_size)) {
|
||||||
dev->endpoint[i].max_packet_size = ep_info->max_packet_size[i];
|
dev->endpoint[i].max_packet_size = ep_info->max_packet_size[i];
|
||||||
}
|
}
|
||||||
|
#if USBREDIR_VERSION >= 0x000700
|
||||||
|
if (usbredirparser_peer_has_cap(dev->parser,
|
||||||
|
usb_redir_cap_bulk_streams)) {
|
||||||
|
dev->endpoint[i].max_streams = ep_info->max_streams[i];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
switch (dev->endpoint[i].type) {
|
switch (dev->endpoint[i].type) {
|
||||||
case usb_redir_type_invalid:
|
case usb_redir_type_invalid:
|
||||||
break;
|
break;
|
||||||
@@ -1779,6 +1870,20 @@ static void usbredir_interrupt_receiving_status(void *priv, uint64_t id,
|
|||||||
static void usbredir_bulk_streams_status(void *priv, uint64_t id,
|
static void usbredir_bulk_streams_status(void *priv, uint64_t id,
|
||||||
struct usb_redir_bulk_streams_status_header *bulk_streams_status)
|
struct usb_redir_bulk_streams_status_header *bulk_streams_status)
|
||||||
{
|
{
|
||||||
|
#if USBREDIR_VERSION >= 0x000700
|
||||||
|
USBRedirDevice *dev = priv;
|
||||||
|
|
||||||
|
if (bulk_streams_status->status == usb_redir_success) {
|
||||||
|
DPRINTF("bulk streams status %d eps %08x\n",
|
||||||
|
bulk_streams_status->status, bulk_streams_status->endpoints);
|
||||||
|
} else {
|
||||||
|
ERROR("bulk streams %s failed status %d eps %08x\n",
|
||||||
|
(bulk_streams_status->no_streams == 0) ? "free" : "alloc",
|
||||||
|
bulk_streams_status->status, bulk_streams_status->endpoints);
|
||||||
|
ERROR("usb-redir-host does not provide streams, disconnecting\n");
|
||||||
|
usbredir_reject_device(dev);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void usbredir_bulk_receiving_status(void *priv, uint64_t id,
|
static void usbredir_bulk_receiving_status(void *priv, uint64_t id,
|
||||||
@@ -1850,8 +1955,8 @@ static void usbredir_bulk_packet(void *priv, uint64_t id,
|
|||||||
int len = (bulk_packet->length_high << 16) | bulk_packet->length;
|
int len = (bulk_packet->length_high << 16) | bulk_packet->length;
|
||||||
USBPacket *p;
|
USBPacket *p;
|
||||||
|
|
||||||
DPRINTF("bulk-in status %d ep %02X len %d id %"PRIu64"\n",
|
DPRINTF("bulk-in status %d ep %02X stream %u len %d id %"PRIu64"\n",
|
||||||
bulk_packet->status, ep, len, id);
|
bulk_packet->status, ep, bulk_packet->stream_id, len, id);
|
||||||
|
|
||||||
p = usbredir_find_packet_by_id(dev, ep, id);
|
p = usbredir_find_packet_by_id(dev, ep, id);
|
||||||
if (p) {
|
if (p) {
|
||||||
@@ -2165,6 +2270,23 @@ static bool usbredir_bulk_receiving_needed(void *priv)
|
|||||||
return endp->bulk_receiving_started;
|
return endp->bulk_receiving_started;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const VMStateDescription usbredir_stream_vmstate = {
|
||||||
|
.name = "usb-redir-ep/stream-state",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_UINT32(max_streams, struct endp_data),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool usbredir_stream_needed(void *priv)
|
||||||
|
{
|
||||||
|
struct endp_data *endp = priv;
|
||||||
|
|
||||||
|
return endp->max_streams;
|
||||||
|
}
|
||||||
|
|
||||||
static const VMStateDescription usbredir_ep_vmstate = {
|
static const VMStateDescription usbredir_ep_vmstate = {
|
||||||
.name = "usb-redir-ep",
|
.name = "usb-redir-ep",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
@@ -2196,6 +2318,9 @@ static const VMStateDescription usbredir_ep_vmstate = {
|
|||||||
{
|
{
|
||||||
.vmsd = &usbredir_bulk_receiving_vmstate,
|
.vmsd = &usbredir_bulk_receiving_vmstate,
|
||||||
.needed = usbredir_bulk_receiving_needed,
|
.needed = usbredir_bulk_receiving_needed,
|
||||||
|
}, {
|
||||||
|
.vmsd = &usbredir_stream_vmstate,
|
||||||
|
.needed = usbredir_stream_needed,
|
||||||
}, {
|
}, {
|
||||||
/* empty */
|
/* empty */
|
||||||
}
|
}
|
||||||
@@ -2361,6 +2486,8 @@ static void usbredir_class_initfn(ObjectClass *klass, void *data)
|
|||||||
uc->handle_control = usbredir_handle_control;
|
uc->handle_control = usbredir_handle_control;
|
||||||
uc->flush_ep_queue = usbredir_flush_ep_queue;
|
uc->flush_ep_queue = usbredir_flush_ep_queue;
|
||||||
uc->ep_stopped = usbredir_ep_stopped;
|
uc->ep_stopped = usbredir_ep_stopped;
|
||||||
|
uc->alloc_streams = usbredir_alloc_streams;
|
||||||
|
uc->free_streams = usbredir_free_streams;
|
||||||
dc->vmsd = &usbredir_vmstate;
|
dc->vmsd = &usbredir_vmstate;
|
||||||
dc->props = usbredir_properties;
|
dc->props = usbredir_properties;
|
||||||
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ void do_mouse_set(Monitor *mon, const QDict *qdict);
|
|||||||
#define QEMU_KEY_CTRL_PAGEUP 0xe406
|
#define QEMU_KEY_CTRL_PAGEUP 0xe406
|
||||||
#define QEMU_KEY_CTRL_PAGEDOWN 0xe407
|
#define QEMU_KEY_CTRL_PAGEDOWN 0xe407
|
||||||
|
|
||||||
void kbd_put_keysym_console(QemuConsole *s, int keysym);
|
|
||||||
void kbd_put_keysym(int keysym);
|
void kbd_put_keysym(int keysym);
|
||||||
|
|
||||||
/* consoles */
|
/* consoles */
|
||||||
|
|||||||
233
ui/console.c
233
ui/console.c
@@ -143,6 +143,8 @@ struct QemuConsole {
|
|||||||
TextCell *cells;
|
TextCell *cells;
|
||||||
int text_x[2], text_y[2], cursor_invalidate;
|
int text_x[2], text_y[2], cursor_invalidate;
|
||||||
int echo;
|
int echo;
|
||||||
|
bool cursor_visible_phase;
|
||||||
|
QEMUTimer *cursor_timer;
|
||||||
|
|
||||||
int update_x0;
|
int update_x0;
|
||||||
int update_y0;
|
int update_y0;
|
||||||
@@ -175,14 +177,10 @@ static DisplayState *display_state;
|
|||||||
static QemuConsole *active_console;
|
static QemuConsole *active_console;
|
||||||
static QemuConsole *consoles[MAX_CONSOLES];
|
static QemuConsole *consoles[MAX_CONSOLES];
|
||||||
static int nb_consoles = 0;
|
static int nb_consoles = 0;
|
||||||
static bool cursor_visible_phase;
|
|
||||||
static QEMUTimer *cursor_timer;
|
|
||||||
|
|
||||||
static void text_console_do_init(CharDriverState *chr, DisplayState *ds);
|
static void text_console_do_init(CharDriverState *chr, DisplayState *ds);
|
||||||
static void dpy_refresh(DisplayState *s);
|
static void dpy_refresh(DisplayState *s);
|
||||||
static DisplayState *get_alloc_displaystate(void);
|
static DisplayState *get_alloc_displaystate(void);
|
||||||
static void text_console_update_cursor_timer(void);
|
|
||||||
static void text_console_update_cursor(void *opaque);
|
|
||||||
|
|
||||||
static void gui_update(void *opaque)
|
static void gui_update(void *opaque)
|
||||||
{
|
{
|
||||||
@@ -477,9 +475,6 @@ static inline void text_update_xy(QemuConsole *s, int x, int y)
|
|||||||
|
|
||||||
static void invalidate_xy(QemuConsole *s, int x, int y)
|
static void invalidate_xy(QemuConsole *s, int x, int y)
|
||||||
{
|
{
|
||||||
if (!qemu_console_is_visible(s)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (s->update_x0 > x * FONT_WIDTH)
|
if (s->update_x0 > x * FONT_WIDTH)
|
||||||
s->update_x0 = x * FONT_WIDTH;
|
s->update_x0 = x * FONT_WIDTH;
|
||||||
if (s->update_y0 > y * FONT_HEIGHT)
|
if (s->update_y0 > y * FONT_HEIGHT)
|
||||||
@@ -495,20 +490,25 @@ static void update_xy(QemuConsole *s, int x, int y)
|
|||||||
TextCell *c;
|
TextCell *c;
|
||||||
int y1, y2;
|
int y1, y2;
|
||||||
|
|
||||||
|
if (!qemu_console_is_visible(s)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (s->ds->have_text) {
|
if (s->ds->have_text) {
|
||||||
text_update_xy(s, x, y);
|
text_update_xy(s, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
y1 = (s->y_base + y) % s->total_height;
|
if (s->ds->have_gfx) {
|
||||||
y2 = y1 - s->y_displayed;
|
y1 = (s->y_base + y) % s->total_height;
|
||||||
if (y2 < 0) {
|
y2 = y1 - s->y_displayed;
|
||||||
y2 += s->total_height;
|
if (y2 < 0)
|
||||||
}
|
y2 += s->total_height;
|
||||||
if (y2 < s->height) {
|
if (y2 < s->height) {
|
||||||
c = &s->cells[y1 * s->width + x];
|
c = &s->cells[y1 * s->width + x];
|
||||||
vga_putcharxy(s, x, y2, c->ch,
|
vga_putcharxy(s, x, y2, c->ch,
|
||||||
&(c->t_attrib));
|
&(c->t_attrib));
|
||||||
invalidate_xy(s, x, y2);
|
invalidate_xy(s, x, y2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -518,28 +518,33 @@ static void console_show_cursor(QemuConsole *s, int show)
|
|||||||
int y, y1;
|
int y, y1;
|
||||||
int x = s->x;
|
int x = s->x;
|
||||||
|
|
||||||
|
if (!qemu_console_is_visible(s)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (s->ds->have_text) {
|
if (s->ds->have_text) {
|
||||||
s->cursor_invalidate = 1;
|
s->cursor_invalidate = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (x >= s->width) {
|
if (s->ds->have_gfx) {
|
||||||
x = s->width - 1;
|
if (x >= s->width) {
|
||||||
}
|
x = s->width - 1;
|
||||||
y1 = (s->y_base + s->y) % s->total_height;
|
}
|
||||||
y = y1 - s->y_displayed;
|
y1 = (s->y_base + s->y) % s->total_height;
|
||||||
if (y < 0) {
|
y = y1 - s->y_displayed;
|
||||||
y += s->total_height;
|
if (y < 0)
|
||||||
}
|
y += s->total_height;
|
||||||
if (y < s->height) {
|
if (y < s->height) {
|
||||||
c = &s->cells[y1 * s->width + x];
|
c = &s->cells[y1 * s->width + x];
|
||||||
if (show && cursor_visible_phase) {
|
if (show && s->cursor_visible_phase) {
|
||||||
TextAttributes t_attrib = s->t_attrib_default;
|
TextAttributes t_attrib = s->t_attrib_default;
|
||||||
t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
|
t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
|
||||||
vga_putcharxy(s, x, y, c->ch, &t_attrib);
|
vga_putcharxy(s, x, y, c->ch, &t_attrib);
|
||||||
} else {
|
} else {
|
||||||
vga_putcharxy(s, x, y, c->ch, &(c->t_attrib));
|
vga_putcharxy(s, x, y, c->ch, &(c->t_attrib));
|
||||||
|
}
|
||||||
|
invalidate_xy(s, x, y);
|
||||||
}
|
}
|
||||||
invalidate_xy(s, x, y);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -549,6 +554,10 @@ static void console_refresh(QemuConsole *s)
|
|||||||
TextCell *c;
|
TextCell *c;
|
||||||
int x, y, y1;
|
int x, y, y1;
|
||||||
|
|
||||||
|
if (!qemu_console_is_visible(s)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (s->ds->have_text) {
|
if (s->ds->have_text) {
|
||||||
s->text_x[0] = 0;
|
s->text_x[0] = 0;
|
||||||
s->text_y[0] = 0;
|
s->text_y[0] = 0;
|
||||||
@@ -557,23 +566,25 @@ static void console_refresh(QemuConsole *s)
|
|||||||
s->cursor_invalidate = 1;
|
s->cursor_invalidate = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
vga_fill_rect(s, 0, 0, surface_width(surface), surface_height(surface),
|
if (s->ds->have_gfx) {
|
||||||
color_table_rgb[0][COLOR_BLACK]);
|
vga_fill_rect(s, 0, 0, surface_width(surface), surface_height(surface),
|
||||||
y1 = s->y_displayed;
|
color_table_rgb[0][COLOR_BLACK]);
|
||||||
for (y = 0; y < s->height; y++) {
|
y1 = s->y_displayed;
|
||||||
c = s->cells + y1 * s->width;
|
for (y = 0; y < s->height; y++) {
|
||||||
for (x = 0; x < s->width; x++) {
|
c = s->cells + y1 * s->width;
|
||||||
vga_putcharxy(s, x, y, c->ch,
|
for (x = 0; x < s->width; x++) {
|
||||||
&(c->t_attrib));
|
vga_putcharxy(s, x, y, c->ch,
|
||||||
c++;
|
&(c->t_attrib));
|
||||||
}
|
c++;
|
||||||
if (++y1 == s->total_height) {
|
}
|
||||||
y1 = 0;
|
if (++y1 == s->total_height) {
|
||||||
|
y1 = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
console_show_cursor(s, 1);
|
||||||
|
dpy_gfx_update(s, 0, 0,
|
||||||
|
surface_width(surface), surface_height(surface));
|
||||||
}
|
}
|
||||||
console_show_cursor(s, 1);
|
|
||||||
dpy_gfx_update(s, 0, 0,
|
|
||||||
surface_width(surface), surface_height(surface));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void console_scroll(QemuConsole *s, int ydelta)
|
static void console_scroll(QemuConsole *s, int ydelta)
|
||||||
@@ -629,7 +640,7 @@ static void console_put_lf(QemuConsole *s)
|
|||||||
c->t_attrib = s->t_attrib_default;
|
c->t_attrib = s->t_attrib_default;
|
||||||
c++;
|
c++;
|
||||||
}
|
}
|
||||||
if (s->y_displayed == s->y_base) {
|
if (qemu_console_is_visible(s) && s->y_displayed == s->y_base) {
|
||||||
if (s->ds->have_text) {
|
if (s->ds->have_text) {
|
||||||
s->text_x[0] = 0;
|
s->text_x[0] = 0;
|
||||||
s->text_y[0] = 0;
|
s->text_y[0] = 0;
|
||||||
@@ -637,16 +648,18 @@ static void console_put_lf(QemuConsole *s)
|
|||||||
s->text_y[1] = s->height - 1;
|
s->text_y[1] = s->height - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
vga_bitblt(s, 0, FONT_HEIGHT, 0, 0,
|
if (s->ds->have_gfx) {
|
||||||
s->width * FONT_WIDTH,
|
vga_bitblt(s, 0, FONT_HEIGHT, 0, 0,
|
||||||
(s->height - 1) * FONT_HEIGHT);
|
s->width * FONT_WIDTH,
|
||||||
vga_fill_rect(s, 0, (s->height - 1) * FONT_HEIGHT,
|
(s->height - 1) * FONT_HEIGHT);
|
||||||
s->width * FONT_WIDTH, FONT_HEIGHT,
|
vga_fill_rect(s, 0, (s->height - 1) * FONT_HEIGHT,
|
||||||
color_table_rgb[0][s->t_attrib_default.bgcol]);
|
s->width * FONT_WIDTH, FONT_HEIGHT,
|
||||||
s->update_x0 = 0;
|
color_table_rgb[0][s->t_attrib_default.bgcol]);
|
||||||
s->update_y0 = 0;
|
s->update_x0 = 0;
|
||||||
s->update_x1 = s->width * FONT_WIDTH;
|
s->update_y0 = 0;
|
||||||
s->update_y1 = s->height * FONT_HEIGHT;
|
s->update_x1 = s->width * FONT_WIDTH;
|
||||||
|
s->update_y1 = s->height * FONT_HEIGHT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -991,6 +1004,9 @@ void console_select(unsigned int index)
|
|||||||
if (s) {
|
if (s) {
|
||||||
DisplayState *ds = s->ds;
|
DisplayState *ds = s->ds;
|
||||||
|
|
||||||
|
if (active_console && active_console->cursor_timer) {
|
||||||
|
timer_del(active_console->cursor_timer);
|
||||||
|
}
|
||||||
active_console = s;
|
active_console = s;
|
||||||
if (ds->have_gfx) {
|
if (ds->have_gfx) {
|
||||||
QLIST_FOREACH(dcl, &ds->listeners, next) {
|
QLIST_FOREACH(dcl, &ds->listeners, next) {
|
||||||
@@ -1007,7 +1023,10 @@ void console_select(unsigned int index)
|
|||||||
if (ds->have_text) {
|
if (ds->have_text) {
|
||||||
dpy_text_resize(s, s->width, s->height);
|
dpy_text_resize(s, s->width, s->height);
|
||||||
}
|
}
|
||||||
text_console_update_cursor(NULL);
|
if (s->cursor_timer) {
|
||||||
|
timer_mod(s->cursor_timer,
|
||||||
|
qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + CONSOLE_CURSOR_PERIOD / 2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1056,11 +1075,13 @@ static void kbd_send_chars(void *opaque)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* called when an ascii key is pressed */
|
/* called when an ascii key is pressed */
|
||||||
void kbd_put_keysym_console(QemuConsole *s, int keysym)
|
void kbd_put_keysym(int keysym)
|
||||||
{
|
{
|
||||||
|
QemuConsole *s;
|
||||||
uint8_t buf[16], *q;
|
uint8_t buf[16], *q;
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
|
s = active_console;
|
||||||
if (!s || (s->console_type == GRAPHIC_CONSOLE))
|
if (!s || (s->console_type == GRAPHIC_CONSOLE))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -1109,11 +1130,6 @@ void kbd_put_keysym_console(QemuConsole *s, int keysym)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void kbd_put_keysym(int keysym)
|
|
||||||
{
|
|
||||||
kbd_put_keysym_console(active_console, keysym);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void text_console_invalidate(void *opaque)
|
static void text_console_invalidate(void *opaque)
|
||||||
{
|
{
|
||||||
QemuConsole *s = (QemuConsole *) opaque;
|
QemuConsole *s = (QemuConsole *) opaque;
|
||||||
@@ -1151,9 +1167,9 @@ static void text_console_update(void *opaque, console_ch_t *chardata)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static QemuConsole *new_console(DisplayState *ds, console_type_t console_type,
|
static QemuConsole *new_console(DisplayState *ds, console_type_t console_type)
|
||||||
uint32_t head)
|
|
||||||
{
|
{
|
||||||
|
Error *local_err = NULL;
|
||||||
Object *obj;
|
Object *obj;
|
||||||
QemuConsole *s;
|
QemuConsole *s;
|
||||||
int i;
|
int i;
|
||||||
@@ -1163,14 +1179,13 @@ static QemuConsole *new_console(DisplayState *ds, console_type_t console_type,
|
|||||||
|
|
||||||
obj = object_new(TYPE_QEMU_CONSOLE);
|
obj = object_new(TYPE_QEMU_CONSOLE);
|
||||||
s = QEMU_CONSOLE(obj);
|
s = QEMU_CONSOLE(obj);
|
||||||
s->head = head;
|
|
||||||
object_property_add_link(obj, "device", TYPE_DEVICE,
|
object_property_add_link(obj, "device", TYPE_DEVICE,
|
||||||
(Object **)&s->device,
|
(Object **)&s->device,
|
||||||
object_property_allow_set_link,
|
object_property_allow_set_link,
|
||||||
OBJ_PROP_LINK_UNREF_ON_RELEASE,
|
OBJ_PROP_LINK_UNREF_ON_RELEASE,
|
||||||
&error_abort);
|
&local_err);
|
||||||
object_property_add_uint32_ptr(obj, "head",
|
object_property_add_uint32_ptr(obj, "head",
|
||||||
&s->head, &error_abort);
|
&s->head, &local_err);
|
||||||
|
|
||||||
if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
|
if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
|
||||||
(console_type == GRAPHIC_CONSOLE))) {
|
(console_type == GRAPHIC_CONSOLE))) {
|
||||||
@@ -1255,18 +1270,19 @@ DisplaySurface *qemu_create_displaysurface_from(int width, int height, int bpp,
|
|||||||
return surface;
|
return surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DisplaySurface *qemu_create_message_surface(int w, int h,
|
static DisplaySurface *qemu_create_dummy_surface(void)
|
||||||
const char *msg)
|
|
||||||
{
|
{
|
||||||
DisplaySurface *surface = qemu_create_displaysurface(w, h);
|
static const char msg[] =
|
||||||
|
"This VM has no graphic display device.";
|
||||||
|
DisplaySurface *surface = qemu_create_displaysurface(640, 480);
|
||||||
pixman_color_t bg = color_table_rgb[0][COLOR_BLACK];
|
pixman_color_t bg = color_table_rgb[0][COLOR_BLACK];
|
||||||
pixman_color_t fg = color_table_rgb[0][COLOR_WHITE];
|
pixman_color_t fg = color_table_rgb[0][COLOR_WHITE];
|
||||||
pixman_image_t *glyph;
|
pixman_image_t *glyph;
|
||||||
int len, x, y, i;
|
int len, x, y, i;
|
||||||
|
|
||||||
len = strlen(msg);
|
len = strlen(msg);
|
||||||
x = (w / FONT_WIDTH - len) / 2;
|
x = (640/FONT_WIDTH - len) / 2;
|
||||||
y = (h / FONT_HEIGHT - 1) / 2;
|
y = (480/FONT_HEIGHT - 1) / 2;
|
||||||
for (i = 0; i < len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
glyph = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, msg[i]);
|
glyph = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, msg[i]);
|
||||||
qemu_pixman_glyph_render(glyph, surface->image, &fg, &bg,
|
qemu_pixman_glyph_render(glyph, surface->image, &fg, &bg,
|
||||||
@@ -1288,8 +1304,6 @@ void qemu_free_displaysurface(DisplaySurface *surface)
|
|||||||
|
|
||||||
void register_displaychangelistener(DisplayChangeListener *dcl)
|
void register_displaychangelistener(DisplayChangeListener *dcl)
|
||||||
{
|
{
|
||||||
static const char nodev[] =
|
|
||||||
"This VM has no graphic display device.";
|
|
||||||
static DisplaySurface *dummy;
|
static DisplaySurface *dummy;
|
||||||
QemuConsole *con;
|
QemuConsole *con;
|
||||||
|
|
||||||
@@ -1308,12 +1322,11 @@ void register_displaychangelistener(DisplayChangeListener *dcl)
|
|||||||
dcl->ops->dpy_gfx_switch(dcl, con->surface);
|
dcl->ops->dpy_gfx_switch(dcl, con->surface);
|
||||||
} else {
|
} else {
|
||||||
if (!dummy) {
|
if (!dummy) {
|
||||||
dummy = qemu_create_message_surface(640, 480, nodev);
|
dummy = qemu_create_dummy_surface();
|
||||||
}
|
}
|
||||||
dcl->ops->dpy_gfx_switch(dcl, dummy);
|
dcl->ops->dpy_gfx_switch(dcl, dummy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
text_console_update_cursor(NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_displaychangelistener(DisplayChangeListener *dcl,
|
void update_displaychangelistener(DisplayChangeListener *dcl,
|
||||||
@@ -1537,8 +1550,6 @@ static DisplayState *get_alloc_displaystate(void)
|
|||||||
{
|
{
|
||||||
if (!display_state) {
|
if (!display_state) {
|
||||||
display_state = g_new0(DisplayState, 1);
|
display_state = g_new0(DisplayState, 1);
|
||||||
cursor_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
|
|
||||||
text_console_update_cursor, NULL);
|
|
||||||
}
|
}
|
||||||
return display_state;
|
return display_state;
|
||||||
}
|
}
|
||||||
@@ -1549,6 +1560,7 @@ static DisplayState *get_alloc_displaystate(void)
|
|||||||
*/
|
*/
|
||||||
DisplayState *init_displaystate(void)
|
DisplayState *init_displaystate(void)
|
||||||
{
|
{
|
||||||
|
Error *local_err = NULL;
|
||||||
gchar *name;
|
gchar *name;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -1567,7 +1579,7 @@ DisplayState *init_displaystate(void)
|
|||||||
* doesn't change any more */
|
* doesn't change any more */
|
||||||
name = g_strdup_printf("console[%d]", i);
|
name = g_strdup_printf("console[%d]", i);
|
||||||
object_property_add_child(container_get(object_get_root(), "/backend"),
|
object_property_add_child(container_get(object_get_root(), "/backend"),
|
||||||
name, OBJECT(consoles[i]), &error_abort);
|
name, OBJECT(consoles[i]), &local_err);
|
||||||
g_free(name);
|
g_free(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1578,8 +1590,7 @@ QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head,
|
|||||||
const GraphicHwOps *hw_ops,
|
const GraphicHwOps *hw_ops,
|
||||||
void *opaque)
|
void *opaque)
|
||||||
{
|
{
|
||||||
static const char noinit[] =
|
Error *local_err = NULL;
|
||||||
"Guest has not initialized the display (yet).";
|
|
||||||
int width = 640;
|
int width = 640;
|
||||||
int height = 480;
|
int height = 480;
|
||||||
QemuConsole *s;
|
QemuConsole *s;
|
||||||
@@ -1587,15 +1598,17 @@ QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head,
|
|||||||
|
|
||||||
ds = get_alloc_displaystate();
|
ds = get_alloc_displaystate();
|
||||||
trace_console_gfx_new();
|
trace_console_gfx_new();
|
||||||
s = new_console(ds, GRAPHIC_CONSOLE, head);
|
s = new_console(ds, GRAPHIC_CONSOLE);
|
||||||
s->hw_ops = hw_ops;
|
s->hw_ops = hw_ops;
|
||||||
s->hw = opaque;
|
s->hw = opaque;
|
||||||
if (dev) {
|
if (dev) {
|
||||||
object_property_set_link(OBJECT(s), OBJECT(dev), "device",
|
object_property_set_link(OBJECT(s), OBJECT(dev),
|
||||||
&error_abort);
|
"device", &local_err);
|
||||||
|
object_property_set_int(OBJECT(s), head,
|
||||||
|
"head", &local_err);
|
||||||
}
|
}
|
||||||
|
|
||||||
s->surface = qemu_create_message_surface(width, height, noinit);
|
s->surface = qemu_create_displaysurface(width, height);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1609,6 +1622,7 @@ QemuConsole *qemu_console_lookup_by_index(unsigned int index)
|
|||||||
|
|
||||||
QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head)
|
QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head)
|
||||||
{
|
{
|
||||||
|
Error *local_err = NULL;
|
||||||
Object *obj;
|
Object *obj;
|
||||||
uint32_t h;
|
uint32_t h;
|
||||||
int i;
|
int i;
|
||||||
@@ -1618,12 +1632,12 @@ QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
obj = object_property_get_link(OBJECT(consoles[i]),
|
obj = object_property_get_link(OBJECT(consoles[i]),
|
||||||
"device", &error_abort);
|
"device", &local_err);
|
||||||
if (DEVICE(obj) != dev) {
|
if (DEVICE(obj) != dev) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
h = object_property_get_int(OBJECT(consoles[i]),
|
h = object_property_get_int(OBJECT(consoles[i]),
|
||||||
"head", &error_abort);
|
"head", &local_err);
|
||||||
if (h != head) {
|
if (h != head) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -1698,32 +1712,14 @@ static void text_console_set_echo(CharDriverState *chr, bool echo)
|
|||||||
s->echo = echo;
|
s->echo = echo;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void text_console_update_cursor_timer(void)
|
|
||||||
{
|
|
||||||
timer_mod(cursor_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME)
|
|
||||||
+ CONSOLE_CURSOR_PERIOD / 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void text_console_update_cursor(void *opaque)
|
static void text_console_update_cursor(void *opaque)
|
||||||
{
|
{
|
||||||
QemuConsole *s;
|
QemuConsole *s = opaque;
|
||||||
int i, count = 0;
|
|
||||||
|
|
||||||
cursor_visible_phase = !cursor_visible_phase;
|
s->cursor_visible_phase = !s->cursor_visible_phase;
|
||||||
|
graphic_hw_invalidate(s);
|
||||||
for (i = 0; i < nb_consoles; i++) {
|
timer_mod(s->cursor_timer,
|
||||||
s = consoles[i];
|
qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + CONSOLE_CURSOR_PERIOD / 2);
|
||||||
if (qemu_console_is_graphic(s) ||
|
|
||||||
!qemu_console_is_visible(s)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
count++;
|
|
||||||
graphic_hw_invalidate(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count) {
|
|
||||||
text_console_update_cursor_timer();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const GraphicHwOps text_console_ops = {
|
static const GraphicHwOps text_console_ops = {
|
||||||
@@ -1759,6 +1755,9 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
|
|||||||
s->surface = qemu_create_displaysurface(g_width, g_height);
|
s->surface = qemu_create_displaysurface(g_width, g_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s->cursor_timer =
|
||||||
|
timer_new_ms(QEMU_CLOCK_REALTIME, text_console_update_cursor, s);
|
||||||
|
|
||||||
s->hw_ops = &text_console_ops;
|
s->hw_ops = &text_console_ops;
|
||||||
s->hw = s;
|
s->hw = s;
|
||||||
|
|
||||||
@@ -1812,9 +1811,9 @@ static CharDriverState *text_console_init(ChardevVC *vc)
|
|||||||
|
|
||||||
trace_console_txt_new(width, height);
|
trace_console_txt_new(width, height);
|
||||||
if (width == 0 || height == 0) {
|
if (width == 0 || height == 0) {
|
||||||
s = new_console(NULL, TEXT_CONSOLE, 0);
|
s = new_console(NULL, TEXT_CONSOLE);
|
||||||
} else {
|
} else {
|
||||||
s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE, 0);
|
s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE);
|
||||||
s->surface = qemu_create_displaysurface(width, height);
|
s->surface = qemu_create_displaysurface(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user