source: mainline/uspace/lib/libblock/libblock.c@ 916bf1a

lfn serial ticket/834-toolchain-update topic/fix-logger-deadlock topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 916bf1a was 916bf1a, checked in by Jakub Jermar <jakub@…>, 18 years ago

libblock is now ready to handle connections to multiple device instances.

  • Property mode set to 100644
File size: 6.9 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, void *bb_buf, off_t bb_off, size_t bb_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 = bb_buf;
100 devcon->bb_off = bb_off;
101 devcon->bb_size = bb_size;
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
125block_init(dev_handle_t dev_handle, size_t com_size, off_t bb_off,
126 size_t bb_size)
127{
128 int rc;
129 int dev_phone;
130 void *com_area;
131 void *bb_buf;
132
133 bb_buf = malloc(bb_size);
134 if (!bb_buf)
135 return ENOMEM;
136
137 com_area = mmap(NULL, com_size, PROTO_READ | PROTO_WRITE,
138 MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
139 if (!com_area) {
140 free(bb_buf);
141 return ENOMEM;
142 }
143 dev_phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAP,
144 DEVMAP_CONNECT_TO_DEVICE, dev_handle);
145
146 if (dev_phone < 0) {
147 free(bb_buf);
148 munmap(com_area, com_size);
149 return dev_phone;
150 }
151
152 rc = ipc_share_out_start(dev_phone, com_area,
153 AS_AREA_READ | AS_AREA_WRITE);
154 if (rc != EOK) {
155 free(bb_buf);
156 munmap(com_area, com_size);
157 ipc_hangup(dev_phone);
158 return rc;
159 }
160
161 rc = devcon_add(dev_handle, dev_phone, com_area, com_size, bb_buf,
162 bb_off, bb_size);
163 if (rc != EOK) {
164 free(bb_buf);
165 munmap(com_area, com_size);
166 ipc_hangup(dev_phone);
167 return rc;
168 }
169
170 off_t bufpos = 0;
171 size_t buflen = 0;
172 if (!block_read(dev_handle, &bufpos, &buflen, &bb_off,
173 bb_buf, bb_size, bb_size)) {
174 block_fini(dev_handle);
175 return EIO; /* XXX real error code */
176 }
177
178 return EOK;
179}
180
181void block_fini(dev_handle_t dev_handle)
182{
183 devcon_t *devcon = devcon_search(dev_handle);
184 assert(devcon);
185
186 devcon_remove(devcon);
187
188 free(devcon->bb_buf);
189 munmap(devcon->com_area, devcon->com_size);
190 ipc_hangup(devcon->dev_phone);
191
192 free(devcon);
193}
194
195void *block_bb_get(dev_handle_t dev_handle)
196{
197 devcon_t *devcon = devcon_search(dev_handle);
198 assert(devcon);
199 return devcon->bb_buf;
200}
201
202/** Read data from a block device.
203 *
204 * @param dev_handle Device handle of the block device.
205 * @param bufpos Pointer to the first unread valid offset within the
206 * communication buffer.
207 * @param buflen Pointer to the number of unread bytes that are ready in
208 * the communication buffer.
209 * @param pos Device position to be read.
210 * @param dst Destination buffer.
211 * @param size Size of the destination buffer.
212 * @param block_size Block size to be used for the transfer.
213 *
214 * @return True on success, false on failure.
215 */
216bool
217block_read(int dev_handle, off_t *bufpos, size_t *buflen, off_t *pos, void *dst,
218 size_t size, size_t block_size)
219{
220 off_t offset = 0;
221 size_t left = size;
222 devcon_t *devcon = devcon_search(dev_handle);
223 assert(devcon);
224
225 while (left > 0) {
226 size_t rd;
227
228 if (*bufpos + left < *buflen)
229 rd = left;
230 else
231 rd = *buflen - *bufpos;
232
233 if (rd > 0) {
234 /*
235 * Copy the contents of the communication buffer to the
236 * destination buffer.
237 */
238 memcpy(dst + offset, devcon->com_area + *bufpos, rd);
239 offset += rd;
240 *bufpos += rd;
241 *pos += rd;
242 left -= rd;
243 }
244
245 if (*bufpos == *buflen) {
246 /* Refill the communication buffer with a new block. */
247 ipcarg_t retval;
248 int rc = async_req_2_1(devcon->dev_phone, RD_READ_BLOCK,
249 *pos / block_size, block_size, &retval);
250 if ((rc != EOK) || (retval != EOK))
251 return false;
252
253 *bufpos = 0;
254 *buflen = block_size;
255 }
256 }
257
258 return true;
259}
260
261block_t *block_get(dev_handle_t dev_handle, off_t offset, size_t bs)
262{
263 /* FIXME */
264 block_t *b;
265 off_t bufpos = 0;
266 size_t buflen = 0;
267 off_t pos = offset * bs;
268
269 b = malloc(sizeof(block_t));
270 if (!b)
271 return NULL;
272
273 b->data = malloc(bs);
274 if (!b->data) {
275 free(b);
276 return NULL;
277 }
278 b->size = bs;
279
280 if (!block_read(dev_handle, &bufpos, &buflen, &pos, b->data,
281 bs, bs)) {
282 free(b->data);
283 free(b);
284 return NULL;
285 }
286
287 return b;
288}
289
290void block_put(block_t *block)
291{
292 /* FIXME */
293 free(block->data);
294 free(block);
295}
296
297/** @}
298 */
Note: See TracBrowser for help on using the repository browser.