]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tools/bus_space/bus.c
Remove spurious newline
[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 __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, &region) == -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 }