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
rid_alloc(void)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 *
rid_lookup(int rid)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
bs_map(const char * dev,const char * res)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
bs_read(int rid,off_t ofs,void * buf,ssize_t bufsz)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
bs_subregion(int rid0,long ofs,long sz)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
bs_unmap(int rid)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
bs_write(int rid,off_t ofs,void * buf,ssize_t bufsz)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