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