diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2016-05-31 09:29:23 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2016-05-31 09:29:23 +0100 |
commit | 07e070aac4eeb186905148461f331e43f2b828aa (patch) | |
tree | 725db4314abc3e4975ec17d427d560cc0c1bbc13 /hw/bt/hci-csr.c | |
parent | d6550e9ed2e1a60d889dfb721de00d9a4e3bafbe (diff) | |
parent | 0878d0e11ba8013dd759c6921cbf05ba6a41bd71 (diff) |
Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging
* docs/atomics fixes and atomic_rcu_* optimization (Emilio)
* NBD bugfix (Eric)
* Memory fixes and cleanups (Paolo, Paul)
* scsi-block support for SCSI status, including persistent
reservations (Paolo)
* kvm_stat moves to the Linux repository
* SCSI bug fixes (Peter, Prasad)
* Killing qemu_char_get_next_serial, non-ARM parts (Xiaoqiang)
# gpg: Signature made Sun 29 May 2016 08:11:20 BST using RSA key ID 78C7AE83
# gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>"
# gpg: aka "Paolo Bonzini <pbonzini@redhat.com>"
* remotes/bonzini/tags/for-upstream: (30 commits)
exec: hide mr->ram_addr from qemu_get_ram_ptr users
memory: split memory_region_from_host from qemu_ram_addr_from_host
exec: remove ram_addr argument from qemu_ram_block_from_host
memory: remove qemu_get_ram_fd, qemu_set_ram_fd, qemu_ram_block_host_ptr
scsi-generic: Merge block max xfer len in INQUIRY response
scsi-block: always use SG_IO
scsi-disk: introduce scsi_disk_req_check_error
scsi-disk: add need_fua_emulation to SCSIDiskClass
scsi-disk: introduce dma_readv and dma_writev
scsi-disk: introduce a common base class
xen-hvm: ignore background I/O sections
docs/atomics: update comparison with Linux
atomics: do not emit consume barrier for atomic_rcu_read
atomics: emit an smp_read_barrier_depends() barrier only for Alpha and Thread Sanitizer
docs/atomics: update atomic_read/set comparison with Linux
bt: rewrite csrhci_write to avoid out-of-bounds writes
block/iscsi: avoid potential overflow of acb->task->cdb
scsi: megasas: check 'read_queue_head' index value
scsi: megasas: initialise local configuration data buffer
scsi: megasas: use appropriate property buffer size
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/bt/hci-csr.c')
-rw-r--r-- | hw/bt/hci-csr.c | 67 |
1 files changed, 46 insertions, 21 deletions
diff --git a/hw/bt/hci-csr.c b/hw/bt/hci-csr.c index e6b8998253..d688372ca3 100644 --- a/hw/bt/hci-csr.c +++ b/hw/bt/hci-csr.c @@ -39,9 +39,14 @@ struct csrhci_s { int out_size; uint8_t outfifo[FIFO_LEN * 2]; uint8_t inpkt[FIFO_LEN]; + enum { + CSR_HDR_LEN, + CSR_DATA_LEN, + CSR_DATA + } in_state; int in_len; int in_hdr; - int in_data; + int in_needed; QEMUTimer *out_tm; int64_t baud_delay; @@ -296,38 +301,60 @@ static int csrhci_data_len(const uint8_t *pkt) exit(-1); } +static void csrhci_ready_for_next_inpkt(struct csrhci_s *s) +{ + s->in_state = CSR_HDR_LEN; + s->in_len = 0; + s->in_needed = 2; + s->in_hdr = INT_MAX; +} + static int csrhci_write(struct CharDriverState *chr, const uint8_t *buf, int len) { struct csrhci_s *s = (struct csrhci_s *) chr->opaque; - int plen = s->in_len; + int total = 0; if (!s->enable) return 0; - s->in_len += len; - memcpy(s->inpkt + plen, buf, len); + for (;;) { + int cnt = MIN(len, s->in_needed - s->in_len); + if (cnt) { + memcpy(s->inpkt + s->in_len, buf, cnt); + s->in_len += cnt; + buf += cnt; + len -= cnt; + total += cnt; + } + + if (s->in_len < s->in_needed) { + break; + } - while (1) { - if (s->in_len >= 2 && plen < 2) + if (s->in_state == CSR_HDR_LEN) { s->in_hdr = csrhci_header_len(s->inpkt) + 1; + assert(s->in_hdr >= s->in_needed); + s->in_needed = s->in_hdr; + s->in_state = CSR_DATA_LEN; + continue; + } - if (s->in_len >= s->in_hdr && plen < s->in_hdr) - s->in_data = csrhci_data_len(s->inpkt) + s->in_hdr; + if (s->in_state == CSR_DATA_LEN) { + s->in_needed += csrhci_data_len(s->inpkt); + /* hci_acl_hdr could specify more than 4096 bytes, so assert. */ + assert(s->in_needed <= sizeof(s->inpkt)); + s->in_state = CSR_DATA; + continue; + } - if (s->in_len >= s->in_data) { + if (s->in_state == CSR_DATA) { csrhci_in_packet(s, s->inpkt); - - memmove(s->inpkt, s->inpkt + s->in_len, s->in_len - s->in_data); - s->in_len -= s->in_data; - s->in_hdr = INT_MAX; - s->in_data = INT_MAX; - plen = 0; - } else - break; + csrhci_ready_for_next_inpkt(s); + } } - return len; + return total; } static void csrhci_out_hci_packet_event(void *opaque, @@ -389,11 +416,9 @@ static void csrhci_reset(struct csrhci_s *s) { s->out_len = 0; s->out_size = FIFO_LEN; - s->in_len = 0; + csrhci_ready_for_next_inpkt(s); s->baud_delay = NANOSECONDS_PER_SECOND; s->enable = 0; - s->in_hdr = INT_MAX; - s->in_data = INT_MAX; s->modem_state = 0; /* After a while... (but sooner than 10ms) */ |