source: mainline/uspace/lib/libblock/libblock.c@ 0c243b4

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 0c243b4 was 0c243b4, checked in by Jakub Jermar <jakub@…>, 17 years ago

block_read() should return the real error code.

  • Property mode set to 100644
File size: 7.0 KB
Line 
1/*
2 * Copyright (c) 2008 Jakub Jermar
3 * Copyright (c) 2008 Martin Decky
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup libblock
31 * @{
32 */
33/**
34 * @file
35 * @brief
36 */
37
38#include "libblock.h"
39#include "../../srv/vfs/vfs.h"
40#include "../../srv/rd/rd.h"
41#include <ipc/devmap.h>
42#include <ipc/services.h>
43#include <errno.h>
44#include <sys/mman.h>
45#include <async.h>
46#include <ipc/ipc.h>
47#include <as.h>
48#include <assert.h>
49#include <futex.h>
50#include <libadt/list.h>
51
52/** Lock protecting the device connection list */
53static futex_t dcl_lock = FUTEX_INITIALIZER;
54/** Device connection list head. */
55static LIST_INITIALIZE(dcl_head);
56
57typedef struct {
58 link_t link;
59 int dev_handle;
60 int dev_phone;
61 void *com_area;
62 size_t com_size;
63 void *bb_buf;
64 off_t bb_off;
65 size_t bb_size;
66} devcon_t;
67
68static devcon_t *devcon_search(dev_handle_t dev_handle)
69{
70 link_t *cur;
71
72 futex_down(&dcl_lock);
73 for (cur = dcl_head.next; cur != &dcl_head; cur = cur->next) {
74 devcon_t *devcon = list_get_instance(cur, devcon_t, link);
75 if (devcon->dev_handle == dev_handle) {
76 futex_up(&dcl_lock);
77 return devcon;
78 }
79 }
80 futex_up(&dcl_lock);
81 return NULL;
82}
83
84static int devcon_add(dev_handle_t dev_handle, int dev_phone, void *com_area,
85 size_t com_size)
86{
87 link_t *cur;
88 devcon_t *devcon;
89
90 devcon = malloc(sizeof(devcon_t));
91 if (!devcon)
92 return ENOMEM;
93
94 link_initialize(&devcon->link);
95 devcon->dev_handle = dev_handle;
96 devcon->dev_phone = dev_phone;
97 devcon->com_area = com_area;
98 devcon->com_size = com_size;
99 devcon->bb_buf = NULL;
100 devcon->bb_off = 0;
101 devcon->bb_size = 0;
102
103 futex_down(&dcl_lock);
104 for (cur = dcl_head.next; cur != &dcl_head; cur = cur->next) {
105 devcon_t *d = list_get_instance(cur, devcon_t, link);
106 if (d->dev_handle == dev_handle) {
107 futex_up(&dcl_lock);
108 free(devcon);
109 return EEXIST;
110 }
111 }
112 list_append(&devcon->link, &dcl_head);
113 futex_up(&dcl_lock);
114 return EOK;
115}
116
117static void devcon_remove(devcon_t *devcon)
118{
119 futex_down(&dcl_lock);
120 list_remove(&devcon->link);
121 futex_up(&dcl_lock);
122}
123
124int block_init(dev_handle_t dev_handle, size_t com_size)
125{
126 int rc;
127 int dev_phone;
128 void *com_area;
129
130 com_area = mmap(NULL, com_size, PROTO_READ | PROTO_WRITE,
131 MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
132 if (!com_area) {
133 return ENOMEM;
134 }
135 dev_phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAP,
136 DEVMAP_CONNECT_TO_DEVICE, dev_handle);
137
138 if (dev_phone < 0) {
139 munmap(com_area, com_size);
140 return dev_phone;
141 }
142
143 rc = ipc_share_out_start(dev_phone, com_area,
144 AS_AREA_READ | AS_AREA_WRITE);
145 if (rc != EOK) {
146 munmap(com_area, com_size);
147 ipc_hangup(dev_phone);
148 return rc;
149 }
150
151 rc = devcon_add(dev_handle, dev_phone, com_area, com_size);
152 if (rc != EOK) {
153 munmap(com_area, com_size);
154 ipc_hangup(dev_phone);
155 return rc;
156 }
157
158 return EOK;
159}
160
161void block_fini(dev_handle_t dev_handle)
162{
163 devcon_t *devcon = devcon_search(dev_handle);
164 assert(devcon);
165
166 devcon_remove(devcon);
167
168 if (devcon->bb_buf)
169 free(devcon->bb_buf);
170 munmap(devcon->com_area, devcon->com_size);
171 ipc_hangup(devcon->dev_phone);
172
173 free(devcon);
174}
175
176int block_bb_read(dev_handle_t dev_handle, off_t off, size_t size)
177{
178 void *bb_buf;
179 int rc;
180
181 devcon_t *devcon = devcon_search(dev_handle);
182 if (!devcon)
183 return ENOENT;
184 if (devcon->bb_buf)
185 return EEXIST;
186 bb_buf = malloc(size);
187 if (!bb_buf)
188 return ENOMEM;
189
190 off_t bufpos = 0;
191 size_t buflen = 0;
192 rc = block_read(dev_handle, &bufpos, &buflen, &off,
193 bb_buf, size, size);
194 if (rc != EOK) {
195 free(bb_buf);
196 return rc;
197 }
198 devcon->bb_buf = bb_buf;
199 devcon->bb_off = off;
200 devcon->bb_size = size;
201
202 return EOK;
203}
204
205void *block_bb_get(dev_handle_t dev_handle)
206{
207 devcon_t *devcon = devcon_search(dev_handle);
208 assert(devcon);
209 return devcon->bb_buf;
210}
211
212/** Read data from a block device.
213 *
214 * @param dev_handle Device handle of the block device.
215 * @param bufpos Pointer to the first unread valid offset within the
216 * communication buffer.
217 * @param buflen Pointer to the number of unread bytes that are ready in
218 * the communication buffer.
219 * @param pos Device position to be read.
220 * @param dst Destination buffer.
221 * @param size Size of the destination buffer.
222 * @param block_size Block size to be used for the transfer.
223 *
224 * @return EOK on success or a negative return code on failure.
225 */
226int
227block_read(int dev_handle, off_t *bufpos, size_t *buflen, off_t *pos, void *dst,
228 size_t size, size_t block_size)
229{
230 off_t offset = 0;
231 size_t left = size;
232 devcon_t *devcon = devcon_search(dev_handle);
233 assert(devcon);
234
235 while (left > 0) {
236 size_t rd;
237
238 if (*bufpos + left < *buflen)
239 rd = left;
240 else
241 rd = *buflen - *bufpos;
242
243 if (rd > 0) {
244 /*
245 * Copy the contents of the communication buffer to the
246 * destination buffer.
247 */
248 memcpy(dst + offset, devcon->com_area + *bufpos, rd);
249 offset += rd;
250 *bufpos += rd;
251 *pos += rd;
252 left -= rd;
253 }
254
255 if (*bufpos == *buflen) {
256 /* Refill the communication buffer with a new block. */
257 ipcarg_t retval;
258 int rc = async_req_2_1(devcon->dev_phone, RD_READ_BLOCK,
259 *pos / block_size, block_size, &retval);
260 if ((rc != EOK) || (retval != EOK))
261 return (rc != EOK ? rc : retval);
262
263 *bufpos = 0;
264 *buflen = block_size;
265 }
266 }
267
268 return EOK;
269}
270
271block_t *block_get(dev_handle_t dev_handle, off_t offset, size_t bs)
272{
273 /* FIXME */
274 block_t *b;
275 off_t bufpos = 0;
276 size_t buflen = 0;
277 off_t pos = offset * bs;
278
279 b = malloc(sizeof(block_t));
280 if (!b)
281 return NULL;
282
283 b->data = malloc(bs);
284 if (!b->data) {
285 free(b);
286 return NULL;
287 }
288 b->size = bs;
289
290 if (block_read(dev_handle, &bufpos, &buflen, &pos, b->data,
291 bs, bs) != EOK) {
292 free(b->data);
293 free(b);
294 return NULL;
295 }
296
297 return b;
298}
299
300void block_put(block_t *block)
301{
302 /* FIXME */
303 free(block->data);
304 free(block);
305}
306
307/** @}
308 */
Note: See TracBrowser for help on using the repository browser.