diff options
| author | Zheng Da <zhengda1936@gmail.com> | 2010-08-08 08:10:25 +0200 |
|---|---|---|
| committer | Zheng Da <zhengda1936@gmail.com> | 2010-08-08 08:10:25 +0200 |
| commit | 793af51f505adfa1ea138dc76be731faab58b1a6 (patch) | |
| tree | 1bae3b7bfc003c7893e8b0504a1c0e4394924536 | |
| parent | e30a817d6d2a1d71223caa238781a76104a54840 (diff) | |
implement device_read for block devices.
| -rw-r--r-- | libdde_linux26/lib/src/mach_glue/block.c | 6 | ||||
| -rw-r--r-- | libmachdev/block.c | 55 | ||||
| -rw-r--r-- | libmachdev/mach_glue.h | 4 |
3 files changed, 57 insertions, 8 deletions
diff --git a/libdde_linux26/lib/src/mach_glue/block.c b/libdde_linux26/lib/src/mach_glue/block.c index a856cc9b..ea44d87f 100644 --- a/libdde_linux26/lib/src/mach_glue/block.c +++ b/libdde_linux26/lib/src/mach_glue/block.c @@ -20,8 +20,8 @@ struct block_device *open_block_dev (char *name, int part, fmode_t mode) /* write a piece of data to a block device. * DATA must be in one page. * SECTORNR: the writing location in sectors. */ -int block_dev_write (struct block_device *dev, int sectornr, - char *data, int count, void (*write_done (int err))) +int block_dev_rw (struct block_device *dev, int sectornr, + char *data, int count, int rw, void (*write_done (int err))) { int err = 0; struct bio *bio; @@ -63,7 +63,7 @@ int block_dev_write (struct block_device *dev, int sectornr, bio->bi_end_io = end_bio; bio->bi_private = NULL; bio_get (bio); - submit_bio (WRITE, bio); + submit_bio (rw, bio); if (bio_flagged (bio, BIO_EOPNOTSUPP)) { err = -EOPNOTSUPP; diff --git a/libmachdev/block.c b/libmachdev/block.c index 48fe6cd6..2a4b9ae2 100644 --- a/libmachdev/block.c +++ b/libmachdev/block.c @@ -24,6 +24,7 @@ #include <ctype.h> #include <stdio.h> #include <unistd.h> +#include <sys/mman.h> #include "mach_U.h" @@ -40,6 +41,11 @@ #include "util.h" #include "mach_glue.h" +/* for submit_bio(). But it might not be very proper to keep + * my own definitions of these macros. */ +#define READ 0 +#define WRITE 1 + /* One of these is associated with each open instance of a device. */ struct block_data { @@ -180,6 +186,7 @@ device_write (void *d, mach_port_t reply_port, void write_done (int err) { int len = err ? 0 : count; + // TODO maybe I should send the reply as long as there is an error. writes--; if (writes == 0) { @@ -200,7 +207,7 @@ device_write (void *d, mach_port_t reply_port, int size = PAGE_SIZE - ((int) data &~PAGE_MASK) > count ? count : PAGE_SIZE - ((int) data &~PAGE_MASK); - err = block_dev_write (bd->dev, bn, data, size, write_done); + err = block_dev_rw (bd->dev, bn, data, size, WRITE, write_done); if (err) break; bn += size >> 9; @@ -220,11 +227,53 @@ device_read (void *d, mach_port_t reply_port, unsigned *bytes_read) { struct block_data *bd = d; + io_return_t err = D_SUCCESS; + int i; + int reads = 0; + char *buf; + int npages = (count + PAGE_SIZE - 1) / PAGE_SIZE; + + void read_done (int err) + { + int len = err ? 0 : count; + reads--; + if (reads == 0) + { + err = linux_to_mach_error (err); + ds_device_read_reply (reply_port, reply_port_type, err, buf, len); + } + } if ((bd->mode & D_READ) == 0) return D_INVALID_OPERATION; - *bytes_read = 0; - return D_SUCCESS; + + if (count == 0) + return 0; + + *data = 0; + buf = mmap (NULL, npages * PAGE_SIZE, PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); + if (buf == MAP_FAILED) + return errno; + + ddekit_printf ("read %d pages.\n", npages); + for (i = 0; i < npages; i++) + { + int size = count > PAGE_SIZE ? PAGE_SIZE : count; + ddekit_printf ("read %d bytes starting from %d\n", size, bn); + + err = block_dev_rw (bd->dev, bn, buf + i * PAGE_SIZE, + size, READ, read_done); + if (err) + break; + bn += size >> 9; + count -= size; + reads++; + } + // TODO when should I deallocate the buffer? + if (reads) + return MIG_NO_REPLY; + return linux_to_mach_error (err); } static io_return_t diff --git a/libmachdev/mach_glue.h b/libmachdev/mach_glue.h index 770ea51b..7b122583 100644 --- a/libmachdev/mach_glue.h +++ b/libmachdev/mach_glue.h @@ -33,8 +33,8 @@ void skb_done_head_init(); /* block device */ struct block_device; struct block_device *open_block_dev (char *name, int part, dev_mode_t mode); -int block_dev_write (struct block_device *dev, int sectornr, - char *data, int count, void (*write_done) (int err)); +int block_dev_rw (struct block_device *dev, int sectornr, + char *data, int count, int rw, void (*write_done) (int err)); int l4dde26_process_from_ddekit(ddekit_thread_t *t); |
