1 /*- 2 * Copyright (c) 2014 Marcel Moolenaar 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/ioctl.h> 31 #include <sys/mman.h> 32 #include <errno.h> 33 #include <fcntl.h> 34 #include <limits.h> 35 #include <stdlib.h> 36 #include <unistd.h> 37 38 #include "bus.h" 39 40 #include "../../sys/dev/proto/proto_dev.h" 41 42 struct resource { 43 int rid; 44 int fd; 45 long addr; 46 long size; 47 off_t ofs; 48 caddr_t ptr; 49 }; 50 51 static struct resource *ridtbl = NULL; 52 static int nrids = 0; 53 54 static int 55 rid_alloc(void) 56 { 57 void *newtbl; 58 int rid; 59 60 for (rid = 0; rid < nrids; rid++) { 61 if (ridtbl[rid].fd == -1) 62 break; 63 } 64 if (rid == nrids) { 65 nrids++; 66 newtbl = realloc(ridtbl, sizeof(struct resource) * nrids); 67 if (newtbl == NULL) { 68 nrids--; 69 return (-1); 70 } else 71 ridtbl = newtbl; 72 } 73 ridtbl[rid].fd = INT_MAX; 74 return (rid); 75 } 76 77 static struct resource * 78 rid_lookup(int rid) 79 { 80 struct resource *r; 81 82 if (rid < 0 || rid >= nrids) { 83 errno = EINVAL; 84 return (NULL); 85 } 86 r = ridtbl + rid; 87 if (r->fd == -1) { 88 errno = ENXIO; 89 return (NULL); 90 } 91 return (r); 92 } 93 94 int 95 bs_map(const char *dev) 96 { 97 struct proto_ioc_region region; 98 struct resource *r; 99 int rid; 100 101 rid = rid_alloc(); 102 if (rid == -1) 103 return (-1); 104 r = rid_lookup(rid); 105 if (r == NULL) 106 return (-1); 107 r->fd = open(dev, O_RDWR); 108 if (r->fd == -1) 109 return (-1); 110 r->rid = -1; 111 if (ioctl(r->fd, PROTO_IOC_REGION, ®ion) == -1) { 112 close(r->fd); 113 r->fd = -1; 114 return (-1); 115 } 116 r->addr = region.address; 117 r->size = region.size; 118 r->ofs = 0; 119 r->ptr = mmap(NULL, r->size, PROT_READ | PROT_WRITE, 120 MAP_NOCORE | MAP_SHARED, r->fd, r->ofs); 121 return (rid); 122 } 123 124 int 125 bs_read(int rid, off_t ofs, void *buf, ssize_t bufsz) 126 { 127 struct resource *r; 128 volatile void *ptr; 129 off_t o; 130 ssize_t s; 131 132 r = rid_lookup(rid); 133 if (r == NULL) 134 return (0); 135 if (ofs < 0 || ofs > r->size - bufsz) { 136 errno = ESPIPE; 137 return (0); 138 } 139 ofs += r->ofs; 140 if (r->ptr != MAP_FAILED) { 141 ptr = r->ptr + ofs; 142 switch (bufsz) { 143 case 1: 144 *((uint8_t *)buf) = *((volatile uint8_t *)ptr); 145 break; 146 case 2: 147 *((uint16_t *)buf) = *((volatile uint16_t *)ptr); 148 break; 149 case 4: 150 *((uint32_t *)buf) = *((volatile uint32_t *)ptr); 151 break; 152 default: 153 errno = EIO; 154 return (0); 155 } 156 } else { 157 o = lseek(r->fd, ofs, SEEK_SET); 158 if (o != ofs) 159 return (0); 160 s = read(r->fd, buf, bufsz); 161 if (s != bufsz) 162 return (0); 163 } 164 return (1); 165 } 166 167 int 168 bs_subregion(int rid0, long ofs, long sz) 169 { 170 struct resource *r; 171 void *ptr0; 172 long addr0, ofs0; 173 int fd0, rid; 174 175 r = rid_lookup(rid0); 176 if (r == NULL) 177 return (-1); 178 if (ofs < 0 || sz < 1) { 179 errno = EINVAL; 180 return (-1); 181 } 182 if (ofs + sz > r->size) { 183 errno = ENOSPC; 184 return (-1); 185 } 186 fd0 = r->fd; 187 addr0 = r->addr; 188 ofs0 = r->ofs; 189 ptr0 = r->ptr; 190 rid = rid_alloc(); 191 if (rid == -1) 192 return (-1); 193 r = rid_lookup(rid); 194 if (r == NULL) 195 return (-1); 196 r->rid = rid0; 197 r->fd = fd0; 198 r->addr = addr0 + ofs; 199 r->size = sz; 200 r->ofs = ofs0 + ofs; 201 r->ptr = ptr0; 202 return (rid); 203 } 204 205 int 206 bs_unmap(int rid) 207 { 208 struct resource *r; 209 210 r = rid_lookup(rid); 211 if (r == NULL) 212 return (0); 213 if (r->rid == -1) { 214 if (r->ptr != MAP_FAILED) 215 munmap(r->ptr, r->size); 216 close(r->fd); 217 } 218 r->fd = -1; 219 return (1); 220 } 221 222 int 223 bs_write(int rid, off_t ofs, void *buf, ssize_t bufsz) 224 { 225 struct resource *r; 226 volatile void *ptr; 227 off_t o; 228 ssize_t s; 229 230 r = rid_lookup(rid); 231 if (r == NULL) 232 return (0); 233 if (ofs < 0 || ofs > r->size - bufsz) { 234 errno = ESPIPE; 235 return (0); 236 } 237 ofs += r->ofs; 238 if (r->ptr != MAP_FAILED) { 239 ptr = r->ptr + ofs; 240 switch (bufsz) { 241 case 1: 242 *((volatile uint8_t *)ptr) = *((uint8_t *)buf); 243 break; 244 case 2: 245 *((volatile uint16_t *)ptr) = *((uint16_t *)buf); 246 break; 247 case 4: 248 *((volatile uint32_t *)ptr) = *((uint32_t *)buf); 249 break; 250 default: 251 errno = EIO; 252 return (0); 253 } 254 } else { 255 o = lseek(r->fd, ofs, SEEK_SET); 256 if (o != ofs) 257 return (0); 258 s = write(r->fd, buf, bufsz); 259 if (s != bufsz) 260 return (0); 261 } 262 return (1); 263 } 264