aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS1
-rw-r--r--hw/sd/core.c13
-rw-r--r--hw/sd/sd.c149
-rw-r--r--hw/sd/sdhci.c7
-rw-r--r--hw/sd/ssi-sd.c136
-rw-r--r--include/hw/sd/sd.h2
-rw-r--r--include/ui/gtk.h1
-rw-r--r--ui/cocoa.m126
-rw-r--r--ui/gtk-gl-area.c5
-rw-r--r--ui/spice-app.c8
-rw-r--r--ui/spice-display.c2
11 files changed, 268 insertions, 182 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index c6f83ecd35..da10756abf 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1754,6 +1754,7 @@ F: hw/ssi/xilinx_*
SD (Secure Card)
M: Philippe Mathieu-Daudé <f4bug@amsat.org>
+M: Bin Meng <bin.meng@windriver.com>
L: qemu-block@nongnu.org
S: Odd Fixes
F: include/hw/sd/sd*
diff --git a/hw/sd/core.c b/hw/sd/core.c
index 08c93b5903..30ee62c510 100644
--- a/hw/sd/core.c
+++ b/hw/sd/core.c
@@ -160,6 +160,19 @@ void sdbus_read_data(SDBus *sdbus, void *buf, size_t length)
}
}
+bool sdbus_receive_ready(SDBus *sdbus)
+{
+ SDState *card = get_card(sdbus);
+
+ if (card) {
+ SDCardClass *sc = SD_CARD_GET_CLASS(card);
+
+ return sc->receive_ready(card);
+ }
+
+ return false;
+}
+
bool sdbus_data_ready(SDBus *sdbus)
{
SDState *card = get_card(sdbus);
diff --git a/hw/sd/sd.c b/hw/sd/sd.c
index 8517dbce8b..8b397effbc 100644
--- a/hw/sd/sd.c
+++ b/hw/sd/sd.c
@@ -739,11 +739,33 @@ void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert)
qemu_set_irq(insert, sd->blk ? blk_is_inserted(sd->blk) : 0);
}
+static void sd_blk_read(SDState *sd, uint64_t addr, uint32_t len)
+{
+ trace_sdcard_read_block(addr, len);
+ if (!sd->blk || blk_pread(sd->blk, addr, sd->data, len) < 0) {
+ fprintf(stderr, "sd_blk_read: read error on host side\n");
+ }
+}
+
+static void sd_blk_write(SDState *sd, uint64_t addr, uint32_t len)
+{
+ trace_sdcard_write_block(addr, len);
+ if (!sd->blk || blk_pwrite(sd->blk, addr, sd->data, len, 0) < 0) {
+ fprintf(stderr, "sd_blk_write: write error on host side\n");
+ }
+}
+
+#define BLK_READ_BLOCK(a, len) sd_blk_read(sd, a, len)
+#define BLK_WRITE_BLOCK(a, len) sd_blk_write(sd, a, len)
+#define APP_READ_BLOCK(a, len) memset(sd->data, 0xec, len)
+#define APP_WRITE_BLOCK(a, len)
+
static void sd_erase(SDState *sd)
{
int i;
uint64_t erase_start = sd->erase_start;
uint64_t erase_end = sd->erase_end;
+ bool sdsc = true;
trace_sdcard_erase(sd->erase_start, sd->erase_end);
if (sd->erase_start == INVALID_ADDRESS
@@ -758,25 +780,30 @@ static void sd_erase(SDState *sd)
/* High capacity memory card: erase units are 512 byte blocks */
erase_start *= 512;
erase_end *= 512;
+ sdsc = false;
}
- if (sd->erase_start > sd->size || sd->erase_end > sd->size) {
+ if (erase_start > sd->size || erase_end > sd->size) {
sd->card_status |= OUT_OF_RANGE;
sd->erase_start = INVALID_ADDRESS;
sd->erase_end = INVALID_ADDRESS;
return;
}
- erase_start = sd_addr_to_wpnum(erase_start);
- erase_end = sd_addr_to_wpnum(erase_end);
sd->erase_start = INVALID_ADDRESS;
sd->erase_end = INVALID_ADDRESS;
sd->csd[14] |= 0x40;
- for (i = erase_start; i <= erase_end; i++) {
- assert(i < sd->wpgrps_size);
- if (test_bit(i, sd->wp_groups)) {
- sd->card_status |= WP_ERASE_SKIP;
+ /* Only SDSC cards support write protect groups */
+ if (sdsc) {
+ erase_start = sd_addr_to_wpnum(erase_start);
+ erase_end = sd_addr_to_wpnum(erase_end);
+
+ for (i = erase_start; i <= erase_end; i++) {
+ assert(i < sd->wpgrps_size);
+ if (test_bit(i, sd->wp_groups)) {
+ sd->card_status |= WP_ERASE_SKIP;
+ }
}
}
}
@@ -1136,8 +1163,9 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
case 13: /* CMD13: SEND_STATUS */
switch (sd->mode) {
case sd_data_transfer_mode:
- if (sd->rca != rca)
+ if (!sd->spi && sd->rca != rca) {
return sd_r0;
+ }
return sd_r1;
@@ -1181,24 +1209,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
break;
case 17: /* CMD17: READ_SINGLE_BLOCK */
- switch (sd->state) {
- case sd_transfer_state:
-
- if (addr + sd->blk_len > sd->size) {
- sd->card_status |= ADDRESS_ERROR;
- return sd_r1;
- }
-
- sd->state = sd_sendingdata_state;
- sd->data_start = addr;
- sd->data_offset = 0;
- return sd_r1;
-
- default:
- break;
- }
- break;
-
case 18: /* CMD18: READ_MULTIPLE_BLOCK */
switch (sd->state) {
case sd_transfer_state:
@@ -1245,41 +1255,9 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
/* Block write commands (Class 4) */
case 24: /* CMD24: WRITE_SINGLE_BLOCK */
- switch (sd->state) {
- case sd_transfer_state:
- /* Writing in SPI mode not implemented. */
- if (sd->spi)
- break;
-
- if (addr + sd->blk_len > sd->size) {
- sd->card_status |= ADDRESS_ERROR;
- return sd_r1;
- }
-
- sd->state = sd_receivingdata_state;
- sd->data_start = addr;
- sd->data_offset = 0;
- sd->blk_written = 0;
-
- if (sd_wp_addr(sd, sd->data_start)) {
- sd->card_status |= WP_VIOLATION;
- }
- if (sd->csd[14] & 0x30) {
- sd->card_status |= WP_VIOLATION;
- }
- return sd_r1;
-
- default:
- break;
- }
- break;
-
case 25: /* CMD25: WRITE_MULTIPLE_BLOCK */
switch (sd->state) {
case sd_transfer_state:
- /* Writing in SPI mode not implemented. */
- if (sd->spi)
- break;
if (addr + sd->blk_len > sd->size) {
sd->card_status |= ADDRESS_ERROR;
@@ -1291,8 +1269,10 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
sd->data_offset = 0;
sd->blk_written = 0;
- if (sd_wp_addr(sd, sd->data_start)) {
- sd->card_status |= WP_VIOLATION;
+ if (sd->size <= SDSC_MAX_CAPACITY) {
+ if (sd_wp_addr(sd, sd->data_start)) {
+ sd->card_status |= WP_VIOLATION;
+ }
}
if (sd->csd[14] & 0x30) {
sd->card_status |= WP_VIOLATION;
@@ -1334,6 +1314,10 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
/* Write protection (Class 6) */
case 28: /* CMD28: SET_WRITE_PROT */
+ if (sd->size > SDSC_MAX_CAPACITY) {
+ return sd_illegal;
+ }
+
switch (sd->state) {
case sd_transfer_state:
if (addr >= sd->size) {
@@ -1353,6 +1337,10 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
break;
case 29: /* CMD29: CLR_WRITE_PROT */
+ if (sd->size > SDSC_MAX_CAPACITY) {
+ return sd_illegal;
+ }
+
switch (sd->state) {
case sd_transfer_state:
if (addr >= sd->size) {
@@ -1372,13 +1360,17 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
break;
case 30: /* CMD30: SEND_WRITE_PROT */
+ if (sd->size > SDSC_MAX_CAPACITY) {
+ return sd_illegal;
+ }
+
switch (sd->state) {
case sd_transfer_state:
sd->state = sd_sendingdata_state;
*(uint32_t *) sd->data = sd_wpbits(sd, req.arg);
sd->data_start = addr;
sd->data_offset = 0;
- return sd_r1b;
+ return sd_r1;
default:
break;
@@ -1792,27 +1784,6 @@ send_response:
return rsplen;
}
-static void sd_blk_read(SDState *sd, uint64_t addr, uint32_t len)
-{
- trace_sdcard_read_block(addr, len);
- if (!sd->blk || blk_pread(sd->blk, addr, sd->data, len) < 0) {
- fprintf(stderr, "sd_blk_read: read error on host side\n");
- }
-}
-
-static void sd_blk_write(SDState *sd, uint64_t addr, uint32_t len)
-{
- trace_sdcard_write_block(addr, len);
- if (!sd->blk || blk_pwrite(sd->blk, addr, sd->data, len, 0) < 0) {
- fprintf(stderr, "sd_blk_write: write error on host side\n");
- }
-}
-
-#define BLK_READ_BLOCK(a, len) sd_blk_read(sd, a, len)
-#define BLK_WRITE_BLOCK(a, len) sd_blk_write(sd, a, len)
-#define APP_READ_BLOCK(a, len) memset(sd->data, 0xec, len)
-#define APP_WRITE_BLOCK(a, len)
-
void sd_write_byte(SDState *sd, uint8_t value)
{
int i;
@@ -1853,9 +1824,11 @@ void sd_write_byte(SDState *sd, uint8_t value)
sd->card_status |= ADDRESS_ERROR;
break;
}
- if (sd_wp_addr(sd, sd->data_start)) {
- sd->card_status |= WP_VIOLATION;
- break;
+ if (sd->size <= SDSC_MAX_CAPACITY) {
+ if (sd_wp_addr(sd, sd->data_start)) {
+ sd->card_status |= WP_VIOLATION;
+ break;
+ }
}
}
sd->data[sd->data_offset++] = value;
@@ -2087,6 +2060,11 @@ uint8_t sd_read_byte(SDState *sd)
return ret;
}
+static bool sd_receive_ready(SDState *sd)
+{
+ return sd->state == sd_receivingdata_state;
+}
+
static bool sd_data_ready(SDState *sd)
{
return sd->state == sd_sendingdata_state;
@@ -2197,6 +2175,7 @@ static void sd_class_init(ObjectClass *klass, void *data)
sc->do_command = sd_do_command;
sc->write_byte = sd_write_byte;
sc->read_byte = sd_read_byte;
+ sc->receive_ready = sd_receive_ready;
sc->data_ready = sd_data_ready;
sc->enable = sd_enable;
sc->get_inserted = sd_get_inserted;
diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
index 8ffa53999d..9acf4467a3 100644
--- a/hw/sd/sdhci.c
+++ b/hw/sd/sdhci.c
@@ -596,9 +596,9 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s)
page_aligned = true;
}
+ s->prnsts |= SDHC_DATA_INHIBIT | SDHC_DAT_LINE_ACTIVE;
if (s->trnmod & SDHC_TRNS_READ) {
- s->prnsts |= SDHC_DOING_READ | SDHC_DATA_INHIBIT |
- SDHC_DAT_LINE_ACTIVE;
+ s->prnsts |= SDHC_DOING_READ;
while (s->blkcnt) {
if (s->data_count == 0) {
sdbus_read_data(&s->sdbus, s->fifo_buffer, block_size);
@@ -625,8 +625,7 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s)
}
}
} else {
- s->prnsts |= SDHC_DOING_WRITE | SDHC_DATA_INHIBIT |
- SDHC_DAT_LINE_ACTIVE;
+ s->prnsts |= SDHC_DOING_WRITE;
while (s->blkcnt) {
begin = s->data_count;
if (((boundary_count + begin) < block_size) && page_aligned) {
diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c
index be1bb10164..97ee58e20c 100644
--- a/hw/sd/ssi-sd.c
+++ b/hw/sd/ssi-sd.c
@@ -4,6 +4,11 @@
* Copyright (c) 2007-2009 CodeSourcery.
* Written by Paul Brook
*
+ * Copyright (c) 2021 Wind River Systems, Inc.
+ * Improved by Bin Meng <bin.meng@windriver.com>
+ *
+ * Validated with U-Boot v2021.01 and Linux v5.10 mmc_spi driver
+ *
* This code is licensed under the GNU GPL v2.
*
* Contributions after 2012-01-13 are licensed under the terms of the
@@ -43,6 +48,8 @@ typedef enum {
SSI_SD_DATA_START,
SSI_SD_DATA_READ,
SSI_SD_DATA_CRC16,
+ SSI_SD_DATA_WRITE,
+ SSI_SD_SKIP_CRC16,
} ssi_sd_mode;
struct ssi_sd_state {
@@ -52,6 +59,8 @@ struct ssi_sd_state {
uint8_t cmdarg[4];
uint8_t response[5];
uint16_t crc16;
+ int32_t read_bytes;
+ int32_t write_bytes;
int32_t arglen;
int32_t response_pos;
int32_t stopping;
@@ -78,37 +87,86 @@ OBJECT_DECLARE_SIMPLE_TYPE(ssi_sd_state, SSI_SD)
#define SSI_SDR_ADDRESS_ERROR 0x2000
#define SSI_SDR_PARAMETER_ERROR 0x4000
+/* multiple block write */
+#define SSI_TOKEN_MULTI_WRITE 0xfc
+/* terminate multiple block write */
+#define SSI_TOKEN_STOP_TRAN 0xfd
/* single block read/write, multiple block read */
#define SSI_TOKEN_SINGLE 0xfe
/* dummy value - don't care */
#define SSI_DUMMY 0xff
+/* data accepted */
+#define DATA_RESPONSE_ACCEPTED 0x05
+
static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val)
{
ssi_sd_state *s = SSI_SD(dev);
+ SDRequest request;
+ uint8_t longresp[16];
- /* Special case: allow CMD12 (STOP TRANSMISSION) while reading data. */
- if (s->mode == SSI_SD_DATA_READ && val == 0x4c) {
- s->mode = SSI_SD_CMD;
- /* There must be at least one byte delay before the card responds. */
- s->stopping = 1;
+ /*
+ * Special case: allow CMD12 (STOP TRANSMISSION) while reading data.
+ *
+ * See "Physical Layer Specification Version 8.00" chapter 7.5.2.2,
+ * to avoid conflict between CMD12 response and next data block,
+ * timing of CMD12 should be controlled as follows:
+ *
+ * - CMD12 issued at the timing that end bit of CMD12 and end bit of
+ * data block is overlapped
+ * - CMD12 issued after one clock cycle after host receives a token
+ * (either Start Block token or Data Error token)
+ *
+ * We need to catch CMD12 in all of the data read states.
+ */
+ if (s->mode >= SSI_SD_PREP_DATA && s->mode <= SSI_SD_DATA_CRC16) {
+ if (val == 0x4c) {
+ s->mode = SSI_SD_CMD;
+ /* There must be at least one byte delay before the card responds */
+ s->stopping = 1;
+ }
}
switch (s->mode) {
case SSI_SD_CMD:
- if (val == SSI_DUMMY) {
+ switch (val) {
+ case SSI_DUMMY:
DPRINTF("NULL command\n");
return SSI_DUMMY;
+ break;
+ case SSI_TOKEN_SINGLE:
+ case SSI_TOKEN_MULTI_WRITE:
+ DPRINTF("Start write block\n");
+ s->mode = SSI_SD_DATA_WRITE;
+ return SSI_DUMMY;
+ case SSI_TOKEN_STOP_TRAN:
+ DPRINTF("Stop multiple write\n");
+
+ /* manually issue cmd12 to stop the transfer */
+ request.cmd = 12;
+ request.arg = 0;
+ s->arglen = sdbus_do_command(&s->sdbus, &request, longresp);
+ if (s->arglen <= 0) {
+ s->arglen = 1;
+ /* a zero value indicates the card is busy */
+ s->response[0] = 0;
+ DPRINTF("SD card busy\n");
+ } else {
+ s->arglen = 1;
+ /* a non-zero value indicates the card is ready */
+ s->response[0] = SSI_DUMMY;
+ }
+
+ return SSI_DUMMY;
}
+
s->cmd = val & 0x3f;
s->mode = SSI_SD_CMDARG;
s->arglen = 0;
return SSI_DUMMY;
case SSI_SD_CMDARG:
if (s->arglen == 4) {
- SDRequest request;
- uint8_t longresp[16];
/* FIXME: Check CRC. */
request.cmd = s->cmd;
request.arg = ldl_be_p(s->cmdarg);
@@ -118,9 +176,9 @@ static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val)
s->arglen = 1;
s->response[0] = 4;
DPRINTF("SD command failed\n");
- } else if (s->cmd == 58) {
- /* CMD58 returns R3 response (OCR) */
- DPRINTF("Returned OCR\n");
+ } else if (s->cmd == 8 || s->cmd == 58) {
+ /* CMD8/CMD58 returns R3/R7 response */
+ DPRINTF("Returned R3/R7\n");
s->arglen = 5;
s->response[0] = 1;
memcpy(&s->response[1], longresp, 4);
@@ -136,6 +194,12 @@ static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val)
/* CMD13 returns a 2-byte statuse work. Other commands
only return the first byte. */
s->arglen = (s->cmd == 13) ? 2 : 1;
+
+ /* handle R1b */
+ if (s->cmd == 28 || s->cmd == 29 || s->cmd == 38) {
+ s->stopping = 1;
+ }
+
cardstatus = ldl_be_p(longresp);
status = 0;
if (((cardstatus >> 9) & 0xf) < 4)
@@ -185,14 +249,15 @@ static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val)
s->mode = SSI_SD_RESPONSE;
return SSI_DUMMY;
case SSI_SD_RESPONSE:
- if (s->stopping) {
- s->stopping = 0;
- return SSI_DUMMY;
- }
if (s->response_pos < s->arglen) {
DPRINTF("Response 0x%02x\n", s->response[s->response_pos]);
return s->response[s->response_pos++];
}
+ if (s->stopping) {
+ s->stopping = 0;
+ s->mode = SSI_SD_CMD;
+ return SSI_DUMMY;
+ }
if (sdbus_data_ready(&s->sdbus)) {
DPRINTF("Data read\n");
s->mode = SSI_SD_DATA_START;
@@ -212,8 +277,9 @@ static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val)
return SSI_TOKEN_SINGLE;
case SSI_SD_DATA_READ:
val = sdbus_read_byte(&s->sdbus);
+ s->read_bytes++;
s->crc16 = crc_ccitt_false(s->crc16, (uint8_t *)&val, 1);
- if (!sdbus_data_ready(&s->sdbus)) {
+ if (!sdbus_data_ready(&s->sdbus) || s->read_bytes == 512) {
DPRINTF("Data read end\n");
s->mode = SSI_SD_DATA_CRC16;
}
@@ -224,10 +290,36 @@ static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val)
s->response_pos++;
if (s->response_pos == 2) {
DPRINTF("CRC16 read end\n");
- s->mode = SSI_SD_CMD;
+ if (s->read_bytes == 512 && s->cmd != 17) {
+ s->mode = SSI_SD_PREP_DATA;
+ } else {
+ s->mode = SSI_SD_CMD;
+ }
+ s->read_bytes = 0;
s->response_pos = 0;
}
return val;
+ case SSI_SD_DATA_WRITE:
+ sdbus_write_byte(&s->sdbus, val);
+ s->write_bytes++;
+ if (!sdbus_receive_ready(&s->sdbus) || s->write_bytes == 512) {
+ DPRINTF("Data write end\n");
+ s->mode = SSI_SD_SKIP_CRC16;
+ s->response_pos = 0;
+ }
+ return val;
+ case SSI_SD_SKIP_CRC16:
+ /* we don't verify the crc16 */
+ s->response_pos++;
+ if (s->response_pos == 2) {
+ DPRINTF("CRC16 receive end\n");
+ s->mode = SSI_SD_RESPONSE;
+ s->write_bytes = 0;
+ s->arglen = 1;
+ s->response[0] = DATA_RESPONSE_ACCEPTED;
+ s->response_pos = 0;
+ }
+ return SSI_DUMMY;
}
/* Should never happen. */
return SSI_DUMMY;
@@ -237,7 +329,7 @@ static int ssi_sd_post_load(void *opaque, int version_id)
{
ssi_sd_state *s = (ssi_sd_state *)opaque;
- if (s->mode > SSI_SD_DATA_CRC16) {
+ if (s->mode > SSI_SD_SKIP_CRC16) {
return -EINVAL;
}
if (s->mode == SSI_SD_CMDARG &&
@@ -255,8 +347,8 @@ static int ssi_sd_post_load(void *opaque, int version_id)
static const VMStateDescription vmstate_ssi_sd = {
.name = "ssi_sd",
- .version_id = 5,
- .minimum_version_id = 5,
+ .version_id = 7,
+ .minimum_version_id = 7,
.post_load = ssi_sd_post_load,
.fields = (VMStateField []) {
VMSTATE_UINT32(mode, ssi_sd_state),
@@ -264,6 +356,8 @@ static const VMStateDescription vmstate_ssi_sd = {
VMSTATE_UINT8_ARRAY(cmdarg, ssi_sd_state, 4),
VMSTATE_UINT8_ARRAY(response, ssi_sd_state, 5),
VMSTATE_UINT16(crc16, ssi_sd_state),
+ VMSTATE_INT32(read_bytes, ssi_sd_state),
+ VMSTATE_INT32(write_bytes, ssi_sd_state),
VMSTATE_INT32(arglen, ssi_sd_state),
VMSTATE_INT32(response_pos, ssi_sd_state),
VMSTATE_INT32(stopping, ssi_sd_state),
@@ -316,6 +410,8 @@ static void ssi_sd_reset(DeviceState *dev)
memset(s->cmdarg, 0, sizeof(s->cmdarg));
memset(s->response, 0, sizeof(s->response));
s->crc16 = 0;
+ s->read_bytes = 0;
+ s->write_bytes = 0;
s->arglen = 0;
s->response_pos = 0;
s->stopping = 0;
diff --git a/include/hw/sd/sd.h b/include/hw/sd/sd.h
index 05ef9b73e5..47360ba4ee 100644
--- a/include/hw/sd/sd.h
+++ b/include/hw/sd/sd.h
@@ -116,6 +116,7 @@ struct SDCardClass {
* Return: byte value read
*/
uint8_t (*read_byte)(SDState *sd);
+ bool (*receive_ready)(SDState *sd);
bool (*data_ready)(SDState *sd);
void (*set_voltage)(SDState *sd, uint16_t millivolts);
uint8_t (*get_dat_lines)(SDState *sd);
@@ -187,6 +188,7 @@ void sdbus_write_data(SDBus *sdbus, const void *buf, size_t length);
* Read multiple bytes of data on the data lines of a SD bus.
*/
void sdbus_read_data(SDBus *sdbus, void *buf, size_t length);
+bool sdbus_receive_ready(SDBus *sd);
bool sdbus_data_ready(SDBus *sd);
bool sdbus_get_inserted(SDBus *sd);
bool sdbus_get_readonly(SDBus *sd);
diff --git a/include/ui/gtk.h b/include/ui/gtk.h
index 3c1cd98db8..5ae0ad60a6 100644
--- a/include/ui/gtk.h
+++ b/include/ui/gtk.h
@@ -147,7 +147,6 @@ void gd_gl_area_scanout_disable(DisplayChangeListener *dcl);
void gd_gl_area_scanout_flush(DisplayChangeListener *dcl,
uint32_t x, uint32_t y, uint32_t w, uint32_t h);
void gtk_gl_area_init(void);
-QEMUGLContext gd_gl_area_get_current_context(DisplayChangeListener *dcl);
int gd_gl_area_make_current(DisplayChangeListener *dcl,
QEMUGLContext ctx);
diff --git a/ui/cocoa.m b/ui/cocoa.m
index 13fba8103e..0ef5fdf3b7 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -70,12 +70,26 @@
typedef struct {
int width;
int height;
- int bitsPerComponent;
- int bitsPerPixel;
} QEMUScreen;
+static void cocoa_update(DisplayChangeListener *dcl,
+ int x, int y, int w, int h);
+
+static void cocoa_switch(DisplayChangeListener *dcl,
+ DisplaySurface *surface);
+
+static void cocoa_refresh(DisplayChangeListener *dcl);
+
NSWindow *normalWindow, *about_window;
-static DisplayChangeListener *dcl;
+static const DisplayChangeListenerOps dcl_ops = {
+ .dpy_name = "cocoa",
+ .dpy_gfx_update = cocoa_update,
+ .dpy_gfx_switch = cocoa_switch,
+ .dpy_refresh = cocoa_refresh,
+};
+static DisplayChangeListener dcl = {
+ .ops = &dcl_ops,
+};
static int last_buttons;
static int cursor_hide = 1;
@@ -240,6 +254,13 @@ const int mac_to_qkeycode_map[] = {
[kVK_F14] = Q_KEY_CODE_SCROLL_LOCK,
[kVK_F15] = Q_KEY_CODE_PAUSE,
+ // JIS keyboards only
+ [kVK_JIS_Yen] = Q_KEY_CODE_YEN,
+ [kVK_JIS_Underscore] = Q_KEY_CODE_RO,
+ [kVK_JIS_KeypadComma] = Q_KEY_CODE_KP_COMMA,
+ [kVK_JIS_Eisu] = Q_KEY_CODE_MUHENKAN,
+ [kVK_JIS_Kana] = Q_KEY_CODE_HENKAN,
+
/*
* The eject and volume keys can't be used here because they are handled at
* a lower level than what an Application can see.
@@ -284,7 +305,6 @@ static void handleAnyDeviceErrors(Error * err)
QEMUScreen screen;
NSWindow *fullScreenWindow;
float cx,cy,cw,ch,cdx,cdy;
- CGDataProviderRef dataProviderRef;
pixman_image_t *pixman_image;
BOOL modifiers_state[256];
BOOL isMouseGrabbed;
@@ -331,8 +351,6 @@ QemuCocoaView *cocoaView;
self = [super initWithFrame:frameRect];
if (self) {
- screen.bitsPerComponent = 8;
- screen.bitsPerPixel = 32;
screen.width = frameRect.size.width;
screen.height = frameRect.size.height;
@@ -344,8 +362,7 @@ QemuCocoaView *cocoaView;
{
COCOA_DEBUG("QemuCocoaView: dealloc\n");
- if (dataProviderRef) {
- CGDataProviderRelease(dataProviderRef);
+ if (pixman_image) {
pixman_image_unref(pixman_image);
}
@@ -424,18 +441,28 @@ QemuCocoaView *cocoaView;
CGContextSetShouldAntialias (viewContextRef, NO);
// draw screen bitmap directly to Core Graphics context
- if (!dataProviderRef) {
+ if (!pixman_image) {
// Draw request before any guest device has set up a framebuffer:
// just draw an opaque black rectangle
CGContextSetRGBFillColor(viewContextRef, 0, 0, 0, 1.0);
CGContextFillRect(viewContextRef, NSRectToCGRect(rect));
} else {
+ int w = pixman_image_get_width(pixman_image);
+ int h = pixman_image_get_height(pixman_image);
+ int bitsPerPixel = PIXMAN_FORMAT_BPP(pixman_image_get_format(pixman_image));
+ int bitsPerComponent = DIV_ROUND_UP(bitsPerPixel, 8) * 2;
+ CGDataProviderRef dataProviderRef = CGDataProviderCreateWithData(
+ NULL,
+ pixman_image_get_data(pixman_image),
+ w * 4 * h,
+ NULL
+ );
CGImageRef imageRef = CGImageCreate(
- screen.width, //width
- screen.height, //height
- screen.bitsPerComponent, //bitsPerComponent
- screen.bitsPerPixel, //bitsPerPixel
- (screen.width * (screen.bitsPerComponent/2)), //bytesPerRow
+ w, //width
+ h, //height
+ bitsPerComponent, //bitsPerComponent
+ bitsPerPixel, //bitsPerPixel
+ (w * (bitsPerComponent/2)), //bytesPerRow
#ifdef __LITTLE_ENDIAN__
CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB), //colorspace for OS X >= 10.4
kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst,
@@ -458,7 +485,7 @@ QemuCocoaView *cocoaView;
[self getRectsBeingDrawn:&rectList count:&rectCount];
for (i = 0; i < rectCount; i++) {
clipRect.origin.x = rectList[i].origin.x / cdx;
- clipRect.origin.y = (float)screen.height - (rectList[i].origin.y + rectList[i].size.height) / cdy;
+ clipRect.origin.y = (float)h - (rectList[i].origin.y + rectList[i].size.height) / cdy;
clipRect.size.width = rectList[i].size.width / cdx;
clipRect.size.height = rectList[i].size.height / cdy;
clipImageRef = CGImageCreateWithImageInRect(
@@ -469,6 +496,7 @@ QemuCocoaView *cocoaView;
CGImageRelease (clipImageRef);
}
CGImageRelease (imageRef);
+ CGDataProviderRelease(dataProviderRef);
}
}
@@ -511,7 +539,6 @@ QemuCocoaView *cocoaView;
int w = pixman_image_get_width(image);
int h = pixman_image_get_height(image);
- pixman_format_code_t image_format = pixman_image_get_format(image);
/* cdx == 0 means this is our very first surface, in which case we need
* to recalculate the content dimensions even if it happens to be the size
* of the initial empty window.
@@ -529,17 +556,11 @@ QemuCocoaView *cocoaView;
}
// update screenBuffer
- if (dataProviderRef) {
- CGDataProviderRelease(dataProviderRef);
+ if (pixman_image) {
pixman_image_unref(pixman_image);
}
- //sync host window color space with guests
- screen.bitsPerPixel = PIXMAN_FORMAT_BPP(image_format);
- screen.bitsPerComponent = DIV_ROUND_UP(screen.bitsPerPixel, 8) * 2;
-
pixman_image = image;
- dataProviderRef = CGDataProviderCreateWithData(NULL, pixman_image_get_data(image), w * 4 * h, NULL);
// update windows
if (isFullscreen) {
@@ -602,15 +623,15 @@ QemuCocoaView *cocoaView;
// Toggle the stored state.
modifiers_state[keycode] = !modifiers_state[keycode];
// Send a keyup or keydown depending on the state.
- qemu_input_event_send_key_qcode(dcl->con, keycode, modifiers_state[keycode]);
+ qemu_input_event_send_key_qcode(dcl.con, keycode, modifiers_state[keycode]);
}
- (void) toggleStatefulModifier: (int)keycode {
// Toggle the stored state.
modifiers_state[keycode] = !modifiers_state[keycode];
// Generate keydown and keyup.
- qemu_input_event_send_key_qcode(dcl->con, keycode, true);
- qemu_input_event_send_key_qcode(dcl->con, keycode, false);
+ qemu_input_event_send_key_qcode(dcl.con, keycode, true);
+ qemu_input_event_send_key_qcode(dcl.con, keycode, false);
}
// Does the work of sending input to the monitor
@@ -794,7 +815,7 @@ QemuCocoaView *cocoaView;
}
if (qemu_console_is_graphic(NULL)) {
- qemu_input_event_send_key_qcode(dcl->con, keycode, true);
+ qemu_input_event_send_key_qcode(dcl.con, keycode, true);
} else {
[self handleMonitorInput: event];
}
@@ -809,7 +830,7 @@ QemuCocoaView *cocoaView;
}
if (qemu_console_is_graphic(NULL)) {
- qemu_input_event_send_key_qcode(dcl->con, keycode, false);
+ qemu_input_event_send_key_qcode(dcl.con, keycode, false);
}
break;
case NSEventTypeMouseMoved:
@@ -830,11 +851,7 @@ QemuCocoaView *cocoaView;
mouse_event = true;
break;
case NSEventTypeLeftMouseDown:
- if ([event modifierFlags] & NSEventModifierFlagCommand) {
- buttons |= MOUSE_EVENT_RBUTTON;
- } else {
- buttons |= MOUSE_EVENT_LBUTTON;
- }
+ buttons |= MOUSE_EVENT_LBUTTON;
mouse_event = true;
break;
case NSEventTypeRightMouseDown:
@@ -846,11 +863,7 @@ QemuCocoaView *cocoaView;
mouse_event = true;
break;
case NSEventTypeLeftMouseDragged:
- if ([event modifierFlags] & NSEventModifierFlagCommand) {
- buttons |= MOUSE_EVENT_RBUTTON;
- } else {
- buttons |= MOUSE_EVENT_LBUTTON;
- }
+ buttons |= MOUSE_EVENT_LBUTTON;
mouse_event = true;
break;
case NSEventTypeRightMouseDragged:
@@ -895,9 +908,9 @@ QemuCocoaView *cocoaView;
/* Determine if this is a scroll up or scroll down event */
buttons = ([event deltaY] > 0) ?
INPUT_BUTTON_WHEEL_UP : INPUT_BUTTON_WHEEL_DOWN;
- qemu_input_queue_btn(dcl->con, buttons, true);
+ qemu_input_queue_btn(dcl.con, buttons, true);
qemu_input_event_sync();
- qemu_input_queue_btn(dcl->con, buttons, false);
+ qemu_input_queue_btn(dcl.con, buttons, false);
qemu_input_event_sync();
}
/*
@@ -925,7 +938,7 @@ QemuCocoaView *cocoaView;
[INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON,
[INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON
};
- qemu_input_update_buttons(dcl->con, bmap, last_buttons, buttons);
+ qemu_input_update_buttons(dcl.con, bmap, last_buttons, buttons);
last_buttons = buttons;
}
if (isMouseGrabbed) {
@@ -935,12 +948,12 @@ QemuCocoaView *cocoaView;
* clicks in the titlebar.
*/
if ([self screenContainsPoint:p]) {
- qemu_input_queue_abs(dcl->con, INPUT_AXIS_X, p.x, 0, screen.width);
- qemu_input_queue_abs(dcl->con, INPUT_AXIS_Y, screen.height - p.y, 0, screen.height);
+ qemu_input_queue_abs(dcl.con, INPUT_AXIS_X, p.x, 0, screen.width);
+ qemu_input_queue_abs(dcl.con, INPUT_AXIS_Y, screen.height - p.y, 0, screen.height);
}
} else {
- qemu_input_queue_rel(dcl->con, INPUT_AXIS_X, (int)[event deltaX]);
- qemu_input_queue_rel(dcl->con, INPUT_AXIS_Y, (int)[event deltaY]);
+ qemu_input_queue_rel(dcl.con, INPUT_AXIS_X, (int)[event deltaX]);
+ qemu_input_queue_rel(dcl.con, INPUT_AXIS_Y, (int)[event deltaY]);
}
} else {
return false;
@@ -1009,7 +1022,7 @@ QemuCocoaView *cocoaView;
for (index = 0; index < max_index; index++) {
if (modifiers_state[index]) {
modifiers_state[index] = 0;
- qemu_input_event_send_key_qcode(dcl->con, index, false);
+ qemu_input_event_send_key_qcode(dcl.con, index, false);
}
}
});
@@ -1836,19 +1849,6 @@ static void cocoa_refresh(DisplayChangeListener *dcl)
[pool release];
}
-static void cocoa_cleanup(void)
-{
- COCOA_DEBUG("qemu_cocoa: cocoa_cleanup\n");
- g_free(dcl);
-}
-
-static const DisplayChangeListenerOps dcl_ops = {
- .dpy_name = "cocoa",
- .dpy_gfx_update = cocoa_update,
- .dpy_gfx_switch = cocoa_switch,
- .dpy_refresh = cocoa_refresh,
-};
-
static void cocoa_display_init(DisplayState *ds, DisplayOptions *opts)
{
COCOA_DEBUG("qemu_cocoa: cocoa_display_init\n");
@@ -1869,14 +1869,8 @@ static void cocoa_display_init(DisplayState *ds, DisplayOptions *opts)
cursor_hide = 0;
}
- dcl = g_malloc0(sizeof(DisplayChangeListener));
-
// register vga output callbacks
- dcl->ops = &dcl_ops;
- register_displaychangelistener(dcl);
-
- // register cleanup function
- atexit(cocoa_cleanup);
+ register_displaychangelistener(&dcl);
}
static QemuDisplay qemu_display_cocoa = {
diff --git a/ui/gtk-gl-area.c b/ui/gtk-gl-area.c
index e7ca73c7b1..4e8ee88b9b 100644
--- a/ui/gtk-gl-area.c
+++ b/ui/gtk-gl-area.c
@@ -239,11 +239,6 @@ void gtk_gl_area_init(void)
display_opengl = 1;
}
-QEMUGLContext gd_gl_area_get_current_context(DisplayChangeListener *dcl)
-{
- return gdk_gl_context_get_current();
-}
-
int gd_gl_area_make_current(DisplayChangeListener *dcl,
QEMUGLContext ctx)
{
diff --git a/ui/spice-app.c b/ui/spice-app.c
index 026124ef56..4325ac2d9c 100644
--- a/ui/spice-app.c
+++ b/ui/spice-app.c
@@ -129,6 +129,7 @@ static void spice_app_atexit(void)
static void spice_app_display_early_init(DisplayOptions *opts)
{
QemuOpts *qopts;
+ QemuOptsList *list;
GError *err = NULL;
if (opts->has_full_screen) {
@@ -159,11 +160,16 @@ static void spice_app_display_early_init(DisplayOptions *opts)
exit(1);
}
}
+ list = qemu_find_opts("spice");
+ if (list == NULL) {
+ error_report("spice-app missing spice support");
+ exit(1);
+ }
type_register(&char_vc_type_info);
sock_path = g_strjoin("", app_dir, "/", "spice.sock", NULL);
- qopts = qemu_opts_create(qemu_find_opts("spice"), NULL, 0, &error_abort);
+ qopts = qemu_opts_create(list, NULL, 0, &error_abort);
qemu_opt_set(qopts, "disable-ticketing", "on", &error_abort);
qemu_opt_set(qopts, "unix", "on", &error_abort);
qemu_opt_set(qopts, "addr", sock_path, &error_abort);
diff --git a/ui/spice-display.c b/ui/spice-display.c
index 6f32b66a6e..ad93b953a9 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -846,6 +846,7 @@ static void spice_gl_refresh(DisplayChangeListener *dcl)
graphic_hw_update(dcl->con);
if (ssd->gl_updates && ssd->have_surface) {
qemu_spice_gl_block(ssd, true);
+ glFlush();
cookie = (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_GL_DRAW_DONE, 0);
spice_qxl_gl_draw_async(&ssd->qxl, 0, 0,
surface_width(ssd->ds),
@@ -1087,6 +1088,7 @@ static void qemu_spice_gl_update(DisplayChangeListener *dcl,
trace_qemu_spice_gl_update(ssd->qxl.id, w, h, x, y);
qemu_spice_gl_block(ssd, true);
+ glFlush();
cookie = (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_GL_DRAW_DONE, 0);
spice_qxl_gl_draw_async(&ssd->qxl, x, y, w, h, cookie);
}