summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZheng Da <zhengda1936@gmail.com>2010-08-08 08:10:25 +0200
committerZheng Da <zhengda1936@gmail.com>2010-08-08 08:10:25 +0200
commit793af51f505adfa1ea138dc76be731faab58b1a6 (patch)
tree1bae3b7bfc003c7893e8b0504a1c0e4394924536
parente30a817d6d2a1d71223caa238781a76104a54840 (diff)
implement device_read for block devices.
-rw-r--r--libdde_linux26/lib/src/mach_glue/block.c6
-rw-r--r--libmachdev/block.c55
-rw-r--r--libmachdev/mach_glue.h4
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);