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 <stdio.h> 36 #include <stdlib.h> 37 #include <unistd.h> 38 39 #include "bus.h" 40 41 #include "../../sys/dev/proto/proto_dev.h" 42 43 struct resource { 44 int rid; 45 int fd; 46 long addr; 47 long size; 48 off_t ofs; 49 caddr_t ptr; 50 }; 51 52 static struct resource *ridtbl = NULL; 53 static int nrids = 0; 54 55 static int 56 rid_alloc(void) 57 { 58 void *newtbl; 59 int rid; 60 61 for (rid = 0; rid < nrids; rid++) { 62 if (ridtbl[rid].fd == -1) 63 break; 64 } 65 if (rid == nrids) { 66 nrids++; 67 newtbl = realloc(ridtbl, sizeof(struct resource) * nrids); 68 if (newtbl == NULL) { 69 nrids--; 70 return (-1); 71 } else 72 ridtbl = newtbl; 73 } 74 ridtbl[rid].fd = INT_MAX; 75 return (rid); 76 } 77 78 static struct resource * 79 rid_lookup(int rid) 80 { 81 struct resource *r; 82 83 if (rid < 0 || rid >= nrids) { 84 errno = EINVAL; 85 return (NULL); 86 } 87 r = ridtbl + rid; 88 if (r->fd == -1) { 89 errno = ENXIO; 90 return (NULL); 91 } 92 return (r); 93 } 94 95 int 96 bs_map(const char *dev, const char *res) 97 { 98 char path[PATH_MAX]; 99 struct proto_ioc_region region; 100 struct resource *r; 101 int len, rid; 102 103 len = snprintf(path, PATH_MAX, "/dev/proto/%s/%s", dev, res); 104 if (len >= PATH_MAX) { 105 errno = EINVAL; 106 return (-1); 107 } 108 rid = rid_alloc(); 109 if (rid == -1) 110 return (-1); 111 r = rid_lookup(rid); 112 if (r == NULL) 113 return (-1); 114 r->fd = open(path, O_RDWR); 115 if (r->fd == -1) 116 return (-1); 117 r->rid = -1; 118 if (ioctl(r->fd, PROTO_IOC_REGION, ®ion) == -1) { 119 close(r->fd); 120 r->fd = -1; 121 return (-1); 122 } 123 r->addr = region.address; 124 r->size = region.size; 125 r->ofs = 0; 126 r->ptr = mmap(NULL, r->size, PROT_READ | PROT_WRITE, 127 MAP_NOCORE | MAP_SHARED, r->fd, r->ofs); 128 return (rid); 129 } 130 131 int 132 bs_read(int rid, off_t ofs, void *buf, ssize_t bufsz) 133 { 134 struct resource *r; 135 volatile void *ptr; 136 off_t o; 137 ssize_t s; 138 139 r = rid_lookup(rid); 140 if (r == NULL) 141 return (0); 142 if (ofs < 0 || ofs > r->size - bufsz) { 143 errno = ESPIPE; 144 return (0); 145 } 146 ofs += r->ofs; 147 if (r->ptr != MAP_FAILED) { 148 ptr = r->ptr + ofs; 149 switch (bufsz) { 150 case 1: 151 *((uint8_t *)buf) = *((volatile uint8_t *)ptr); 152 break; 153 case 2: 154 *((uint16_t *)buf) = *((volatile uint16_t *)ptr); 155 break; 156 case 4: 157 *((uint32_t *)buf) = *((volatile uint32_t *)ptr); 158 break; 159 default: 160 errno = EIO; 161 return (0); 162 } 163 } else { 164 o = lseek(r->fd, ofs, SEEK_SET); 165 if (o != ofs) 166 return (0); 167 s = read(r->fd, buf, bufsz); 168 if (s != bufsz) 169 return (0); 170 } 171 return (1); 172 } 173 174 int 175 bs_subregion(int rid0, long ofs, long sz) 176 { 177 struct resource *r; 178 void *ptr0; 179 long addr0, ofs0; 180 int fd0, rid; 181 182 r = rid_lookup(rid0); 183 if (r == NULL) 184 return (-1); 185 if (ofs < 0 || sz < 1) { 186 errno = EINVAL; 187 return (-1); 188 } 189 if (ofs + sz > r->size) { 190 errno = ENOSPC; 191 return (-1); 192 } 193 fd0 = r->fd; 194 addr0 = r->addr; 195 ofs0 = r->ofs; 196 ptr0 = r->ptr; 197 rid = rid_alloc(); 198 if (rid == -1) 199 return (-1); 200 r = rid_lookup(rid); 201 if (r == NULL) 202 return (-1); 203 r->rid = rid0; 204 r->fd = fd0; 205 r->addr = addr0 + ofs; 206 r->size = sz; 207 r->ofs = ofs0 + ofs; 208 r->ptr = ptr0; 209 return (rid); 210 } 211 212 int 213 bs_unmap(int rid) 214 { 215 struct resource *r; 216 217 r = rid_lookup(rid); 218 if (r == NULL) 219 return (0); 220 if (r->rid == -1) { 221 if (r->ptr != MAP_FAILED) 222 munmap(r->ptr, r->size); 223 close(r->fd); 224 } 225 r->fd = -1; 226 return (1); 227 } 228 229 int 230 bs_write(int rid, off_t ofs, void *buf, ssize_t bufsz) 231 { 232 struct resource *r; 233 volatile void *ptr; 234 off_t o; 235 ssize_t s; 236 237 r = rid_lookup(rid); 238 if (r == NULL) 239 return (0); 240 if (ofs < 0 || ofs > r->size - bufsz) { 241 errno = ESPIPE; 242 return (0); 243 } 244 ofs += r->ofs; 245 if (r->ptr != MAP_FAILED) { 246 ptr = r->ptr + ofs; 247 switch (bufsz) { 248 case 1: 249 *((volatile uint8_t *)ptr) = *((uint8_t *)buf); 250 break; 251 case 2: 252 *((volatile uint16_t *)ptr) = *((uint16_t *)buf); 253 break; 254 case 4: 255 *((volatile uint32_t *)ptr) = *((uint32_t *)buf); 256 break; 257 default: 258 errno = EIO; 259 return (0); 260 } 261 } else { 262 o = lseek(r->fd, ofs, SEEK_SET); 263 if (o != ofs) 264 return (0); 265 s = write(r->fd, buf, bufsz); 266 if (s != bufsz) 267 return (0); 268 } 269 return (1); 270 } 271