1 /* $NetBSD: shmif_busops.c,v 1.12 2014/09/17 04:20:58 ozaki-r Exp $ */ 2 3 /* 4 * Copyright (c) 2009, 2010 Antti Kantee. All Rights Reserved. 5 * 6 * Development of this software was supported by The Nokia Foundation. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 18 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #ifdef _KERNEL 31 #include <sys/cdefs.h> 32 __KERNEL_RCSID(0, "$NetBSD: shmif_busops.c,v 1.12 2014/09/17 04:20:58 ozaki-r Exp $"); 33 #else 34 #include <rump/rumpuser_port.h> 35 __RCSID("$NetBSD: shmif_busops.c,v 1.12 2014/09/17 04:20:58 ozaki-r Exp $"); 36 #endif 37 38 #include <sys/param.h> 39 40 #ifndef _KERNEL 41 #include <assert.h> 42 #include <inttypes.h> 43 #include <stdbool.h> 44 #include <string.h> 45 46 #define KASSERT(a) assert(a) 47 #endif 48 49 #include "shmifvar.h" 50 51 uint32_t 52 shmif_advance(uint32_t oldoff, uint32_t delta) 53 { 54 uint32_t newoff; 55 56 newoff = oldoff + delta; 57 if (newoff >= BUSMEM_DATASIZE) 58 newoff -= BUSMEM_DATASIZE; 59 return newoff; 60 } 61 62 uint32_t 63 shmif_busread(struct shmif_mem *busmem, void *dest, uint32_t off, size_t len, 64 bool *wrap) 65 { 66 size_t chunk; 67 68 KASSERT(len < (BUSMEM_DATASIZE/2) && off <= BUSMEM_DATASIZE); 69 chunk = MIN(len, BUSMEM_DATASIZE - off); 70 memcpy(dest, busmem->shm_data + off, chunk); 71 len -= chunk; 72 73 if (off + chunk == BUSMEM_DATASIZE) 74 *wrap = true; 75 76 if (len == 0) { 77 return (off + chunk) % BUSMEM_DATASIZE; 78 } 79 80 /* finish reading */ 81 memcpy((uint8_t *)dest + chunk, busmem->shm_data, len); 82 return len; 83 } 84 85 void 86 shmif_advancefirst(struct shmif_mem *busmem, uint32_t off, size_t len) 87 { 88 89 while (off <= busmem->shm_first + sizeof(struct shmif_pkthdr) 90 && off+len > busmem->shm_first) { 91 DPRINTF(("advancefirst: old offset %d, ", busmem->shm_first)); 92 busmem->shm_first = shmif_nextpktoff(busmem, busmem->shm_first); 93 DPRINTF(("new offset: %d\n", busmem->shm_first)); 94 } 95 } 96 97 uint32_t 98 shmif_buswrite(struct shmif_mem *busmem, uint32_t off, void *data, size_t len, 99 bool *wrap) 100 { 101 size_t chunk; 102 bool filledbus; 103 104 KASSERT(len < (BUSMEM_DATASIZE/2) && off <= BUSMEM_DATASIZE); 105 106 chunk = MIN(len, BUSMEM_DATASIZE - off); 107 len -= chunk; 108 filledbus = (off+chunk == BUSMEM_DATASIZE); 109 110 shmif_advancefirst(busmem, off, chunk + (filledbus ? 1 : 0)); 111 112 memcpy(busmem->shm_data + off, data, chunk); 113 114 DPRINTF(("buswrite: wrote %zu bytes to %d", chunk, off)); 115 116 if (filledbus) { 117 *wrap = true; 118 } 119 120 if (len == 0) { 121 DPRINTF(("\n")); 122 return (off + chunk) % BUSMEM_DATASIZE; 123 } 124 125 DPRINTF((", wrapped bytes %zu to 0\n", len)); 126 127 shmif_advancefirst(busmem, 0, len); 128 129 /* finish writing */ 130 memcpy(busmem->shm_data, (uint8_t *)data + chunk, len); 131 return len; 132 } 133 134 uint32_t 135 shmif_nextpktoff(struct shmif_mem *busmem, uint32_t oldoff) 136 { 137 struct shmif_pkthdr sp; 138 bool dummy; 139 140 shmif_busread(busmem, &sp, oldoff, sizeof(sp), &dummy); 141 KASSERT(sp.sp_len < BUSMEM_DATASIZE); 142 143 return shmif_advance(oldoff, sizeof(sp) + sp.sp_len); 144 } 145