46,26 → 46,98 |
#include <ipc/ipc.h> |
#include <as.h> |
#include <assert.h> |
#include <futex.h> |
#include <libadt/list.h> |
|
static int dev_phone = -1; /* FIXME */ |
static void *dev_buffer = NULL; /* FIXME */ |
static size_t dev_buffer_len = 0; /* FIXME */ |
static void *bblock = NULL; /* FIXME */ |
/** Lock protecting the device connection list */ |
static futex_t dcl_lock = FUTEX_INITIALIZER; |
/** Device connection list head. */ |
static LIST_INITIALIZE(dcl_head); |
|
typedef struct { |
link_t link; |
int dev_handle; |
int dev_phone; |
void *com_area; |
size_t com_size; |
void *bb_buf; |
off_t bb_off; |
size_t bb_size; |
} devcon_t; |
|
static devcon_t *devcon_search(dev_handle_t dev_handle) |
{ |
link_t *cur; |
|
futex_down(&dcl_lock); |
for (cur = dcl_head.next; cur != &dcl_head; cur = cur->next) { |
devcon_t *devcon = list_get_instance(cur, devcon_t, link); |
if (devcon->dev_handle == dev_handle) { |
futex_up(&dcl_lock); |
return devcon; |
} |
} |
futex_up(&dcl_lock); |
return NULL; |
} |
|
static int devcon_add(dev_handle_t dev_handle, int dev_phone, void *com_area, |
size_t com_size, void *bb_buf, off_t bb_off, size_t bb_size) |
{ |
link_t *cur; |
devcon_t *devcon; |
|
devcon = malloc(sizeof(devcon_t)); |
if (!devcon) |
return ENOMEM; |
|
link_initialize(&devcon->link); |
devcon->dev_handle = dev_handle; |
devcon->dev_phone = dev_phone; |
devcon->com_area = com_area; |
devcon->com_size = com_size; |
devcon->bb_buf = bb_buf; |
devcon->bb_off = bb_off; |
devcon->bb_size = bb_size; |
|
futex_down(&dcl_lock); |
for (cur = dcl_head.next; cur != &dcl_head; cur = cur->next) { |
devcon_t *d = list_get_instance(cur, devcon_t, link); |
if (d->dev_handle == dev_handle) { |
futex_up(&dcl_lock); |
free(devcon); |
return EEXIST; |
} |
} |
list_append(&devcon->link, &dcl_head); |
futex_up(&dcl_lock); |
return EOK; |
} |
|
static void devcon_remove(devcon_t *devcon) |
{ |
futex_down(&dcl_lock); |
list_remove(&devcon->link); |
futex_up(&dcl_lock); |
} |
|
int |
block_init(dev_handle_t dev_handle, size_t com_size, off_t bb_off, |
size_t bb_size) |
{ |
int rc; |
|
bblock = malloc(bb_size); |
if (!bblock) |
int dev_phone; |
void *com_area; |
void *bb_buf; |
|
bb_buf = malloc(bb_size); |
if (!bb_buf) |
return ENOMEM; |
dev_buffer_len = com_size; |
dev_buffer = mmap(NULL, com_size, PROTO_READ | PROTO_WRITE, |
|
com_area = mmap(NULL, com_size, PROTO_READ | PROTO_WRITE, |
MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); |
if (!dev_buffer) { |
free(bblock); |
if (!com_area) { |
free(bb_buf); |
return ENOMEM; |
} |
dev_phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAP, |
72,43 → 144,59 |
DEVMAP_CONNECT_TO_DEVICE, dev_handle); |
|
if (dev_phone < 0) { |
free(bblock); |
munmap(dev_buffer, com_size); |
free(bb_buf); |
munmap(com_area, com_size); |
return dev_phone; |
} |
|
rc = ipc_share_out_start(dev_phone, dev_buffer, |
rc = ipc_share_out_start(dev_phone, com_area, |
AS_AREA_READ | AS_AREA_WRITE); |
if (rc != EOK) { |
free(bb_buf); |
munmap(com_area, com_size); |
ipc_hangup(dev_phone); |
free(bblock); |
munmap(dev_buffer, com_size); |
return rc; |
} |
|
rc = devcon_add(dev_handle, dev_phone, com_area, com_size, bb_buf, |
bb_off, bb_size); |
if (rc != EOK) { |
free(bb_buf); |
munmap(com_area, com_size); |
ipc_hangup(dev_phone); |
return rc; |
} |
|
off_t bufpos = 0; |
size_t buflen = 0; |
if (!block_read(dev_handle, &bufpos, &buflen, &bb_off, |
bblock, bb_size, bb_size)) { |
ipc_hangup(dev_phone); |
free(bblock); |
munmap(dev_buffer, com_size); |
bb_buf, bb_size, bb_size)) { |
block_fini(dev_handle); |
return EIO; /* XXX real error code */ |
} |
|
return EOK; |
} |
|
void block_fini(dev_handle_t dev_handle) |
{ |
/* XXX */ |
free(bblock); |
munmap(dev_buffer, dev_buffer_len); |
ipc_hangup(dev_phone); |
devcon_t *devcon = devcon_search(dev_handle); |
assert(devcon); |
|
devcon_remove(devcon); |
|
free(devcon->bb_buf); |
munmap(devcon->com_area, devcon->com_size); |
ipc_hangup(devcon->dev_phone); |
|
free(devcon); |
} |
|
void *block_bb_get(dev_handle_t dev_handle) |
{ |
/* XXX */ |
return bblock; |
devcon_t *devcon = devcon_search(dev_handle); |
assert(devcon); |
return devcon->bb_buf; |
} |
|
/** Read data from a block device. |
131,6 → 219,8 |
{ |
off_t offset = 0; |
size_t left = size; |
devcon_t *devcon = devcon_search(dev_handle); |
assert(devcon); |
|
while (left > 0) { |
size_t rd; |
145,7 → 235,7 |
* Copy the contents of the communication buffer to the |
* destination buffer. |
*/ |
memcpy(dst + offset, dev_buffer + *bufpos, rd); |
memcpy(dst + offset, devcon->com_area + *bufpos, rd); |
offset += rd; |
*bufpos += rd; |
*pos += rd; |
155,7 → 245,7 |
if (*bufpos == *buflen) { |
/* Refill the communication buffer with a new block. */ |
ipcarg_t retval; |
int rc = async_req_2_1(dev_phone, RD_READ_BLOCK, |
int rc = async_req_2_1(devcon->dev_phone, RD_READ_BLOCK, |
*pos / block_size, block_size, &retval); |
if ((rc != EOK) || (retval != EOK)) |
return false; |
176,9 → 266,6 |
size_t buflen = 0; |
off_t pos = offset * bs; |
|
assert(dev_phone != -1); |
assert(dev_buffer); |
|
b = malloc(sizeof(block_t)); |
if (!b) |
return NULL; |