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