]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tools/bus_space/bus.c
MFV: file 5.45.
[FreeBSD/FreeBSD.git] / tools / bus_space / bus.c
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, &region) == -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 }