summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZheng Da <zhengda1936@gmail.com>2010-06-04 16:51:24 +0200
committerZheng Da <zhengda1936@gmail.com>2010-06-04 16:51:24 +0200
commit21bf6f025d94c2987dfe30a0b327b6dfab7a8bff (patch)
treeca347da12bdeaf33ae9db843df3943791d2db84b
parent2d2c99a2d22d53343e3ea39368201d2e316c5aa8 (diff)
support block devices in the DDE library.
-rw-r--r--libdde_linux26/lib/src/Makefile3
-rw-r--r--libdde_linux26/lib/src/mach_glue/block.c77
-rw-r--r--libdde_linux26/lib/src/mach_glue/net.c (renamed from libdde_linux26/lib/src/arch/l4/mach_glue.c)0
-rw-r--r--libmachdev/Makefile2
-rw-r--r--libmachdev/block.c250
-rw-r--r--libmachdev/mach_glue.h30
-rw-r--r--libmachdev/machdev.h1
-rw-r--r--libmachdev/net.c19
-rw-r--r--windhoek/Makefile4
-rw-r--r--windhoek/main.c1
10 files changed, 366 insertions, 21 deletions
diff --git a/libdde_linux26/lib/src/Makefile b/libdde_linux26/lib/src/Makefile
index 3743f91b..947f11b9 100644
--- a/libdde_linux26/lib/src/Makefile
+++ b/libdde_linux26/lib/src/Makefile
@@ -150,7 +150,7 @@ SRC_C_libdde_linux26.o.a += \
##################################################################
SRC_C_libdde_linux26_net.a += \
arch/l4/net.c \
- arch/l4/mach_glue.c \
+ mach_glue/net.c \
drivers/net/mii.c \
net/core/dev.c \
net/core/dev_mcast.c \
@@ -180,6 +180,7 @@ SRC_C_libdde_linux26_sound.a += \
#
SRC_C_libdde_linux26_block.a += \
arch/l4/inodes.c \
+ mach_glue/block.c \
block/blk-barrier.c \
block/blk-core.c \
block/blk-exec.c \
diff --git a/libdde_linux26/lib/src/mach_glue/block.c b/libdde_linux26/lib/src/mach_glue/block.c
new file mode 100644
index 00000000..7eac7e46
--- /dev/null
+++ b/libdde_linux26/lib/src/mach_glue/block.c
@@ -0,0 +1,77 @@
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/bio.h>
+#include <ddekit/assert.h>
+
+struct gendisk *find_disk_by_name (char *);
+void dde_page_cache_add (struct page *);
+
+struct block_device *open_block_dev (char *name, int part, fmode_t mode)
+{
+ struct gendisk *disk = find_disk_by_name (name);
+ dev_t devid = MKDEV (disk->major, disk->first_minor + part);
+ return open_by_devnum (devid, 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 err = 0;
+ struct bio *bio;
+ struct page *page;
+ int i;
+
+ void end_bio (struct bio *bio, int err)
+ {
+ write_done (err);
+ }
+
+ assert (count <= PAGE_SIZE);
+ bio = bio_alloc (GFP_NOIO, 1);
+ if (bio == NULL)
+ {
+ err = ENOMEM;
+ goto out;
+ }
+
+ page = kmalloc (sizeof (*page), GFP_KERNEL);
+ if (page == NULL)
+ {
+ err = ENOMEM;
+ goto out;
+ }
+
+ bio->bi_sector = sectornr;
+ bio->bi_bdev = dev;
+ page->virtual = data;
+ dde_page_cache_add (page);
+ bio->bi_io_vec[0].bv_page = page;
+ bio->bi_io_vec[0].bv_len = count;
+ bio->bi_io_vec[0].bv_offset = (int) data & ~PAGE_MASK;
+
+ bio->bi_vcnt = 1;
+ bio->bi_idx = 0;
+ bio->bi_size = count;
+
+ bio->bi_end_io = end_bio;
+ bio->bi_private = NULL;
+ bio_get (bio);
+ submit_bio (WRITE, bio);
+ if (bio_flagged (bio, BIO_EOPNOTSUPP))
+ {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+ bio_put (bio);
+out:
+ if (err)
+ {
+ if (bio)
+ bio_put (bio);
+ kfree (page);
+ }
+ return err;
+}
diff --git a/libdde_linux26/lib/src/arch/l4/mach_glue.c b/libdde_linux26/lib/src/mach_glue/net.c
index 48373a90..48373a90 100644
--- a/libdde_linux26/lib/src/arch/l4/mach_glue.c
+++ b/libdde_linux26/lib/src/mach_glue/net.c
diff --git a/libmachdev/Makefile b/libmachdev/Makefile
index 2bd294ad..7475d041 100644
--- a/libmachdev/Makefile
+++ b/libmachdev/Makefile
@@ -20,7 +20,7 @@ makemode := library
libname = libmachdev
SRCS = deviceUser.c machUser.c net.c ds_routines.c queue.c trivfs_server.c \
- device_replyUser.c deviceServer.c notifyServer.c misc.c
+ device_replyUser.c deviceServer.c notifyServer.c misc.c block.c
LCLHDRS = dev_hdr.h device_emul.h ds_routines.h vm_param.h \
util.h queue.h io_req.h if_ether.h machdev.h linux-errno.h \
errno-base.h
diff --git a/libmachdev/block.c b/libmachdev/block.c
new file mode 100644
index 00000000..54048fde
--- /dev/null
+++ b/libmachdev/block.c
@@ -0,0 +1,250 @@
+/*
+ * Linux block driver support.
+ *
+ * Copyright (C) 1996 The University of Utah and the Computer Systems
+ * Laboratory at the University of Utah (CSL)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Shantanu Goel, University of Utah CSL
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "mach_U.h"
+
+#include <mach.h>
+#include <hurd.h>
+
+#define MACH_INCLUDE
+
+#include <ddekit/printf.h>
+
+#include "vm_param.h"
+#include "device_reply_U.h"
+#include "dev_hdr.h"
+#include "util.h"
+#include "mach_glue.h"
+
+/* One of these is associated with each open instance of a device. */
+struct block_data
+{
+ struct port_info port; /* device port */
+ struct emul_device device; /* generic device structure */
+ dev_mode_t mode;
+ struct block_device *dev;
+};
+
+/* Return a send right associated with network device ND. */
+static mach_port_t
+dev_to_port (void *nd)
+{
+ return (nd
+ ? ports_get_send_right (nd)
+ : MACH_PORT_NULL);
+}
+
+extern struct device_emulation_ops linux_block_emulation_ops;
+
+#define DISK_NAME_LEN 32
+
+/* Parse the device NAME.
+ Set *SLICE to be the DOS partition and
+ *PART the BSD/Mach partition, if any. */
+static char *
+translate_name (char *name, int *slice, int *part)
+{
+ char *p, *q, *end;
+ char *ret;
+ int disk_num;
+
+ /* Parse name into name, unit, DOS partition (slice) and partition. */
+ for (*slice = 0, *part = -1, p = name; isalpha (*p); p++)
+ ;
+ if (p == name || ! isdigit (*p))
+ return NULL;
+ end = p;
+ disk_num = strtol (p, &p, 0);
+ if (disk_num < 0 || disk_num > 26)
+ return NULL;
+// do
+// p++;
+// while (isdigit (*p));
+ if (*p)
+ {
+ q = p;
+ if (*q == 's' && isdigit (*(q + 1)))
+ {
+ q++;
+ do
+ *slice = *slice * 10 + *q++ - '0';
+ while (isdigit (*q));
+ if (! *q)
+ goto find_major;
+ }
+ if (! isalpha (*q) || *(q + 1))
+ return NULL;
+ *part = *q - 'a';
+ }
+
+find_major:
+ ret = malloc (DISK_NAME_LEN);
+ sprintf (ret, "hd%c", 'a' + disk_num);
+ return ret;
+}
+
+static io_return_t
+device_open (mach_port_t reply_port, mach_msg_type_name_t reply_port_type,
+ dev_mode_t mode, char *name, device_t *devp)
+{
+ io_return_t err = D_SUCCESS;
+ struct block_data *bd = NULL;
+ int slice, part;
+ char *dev_name = NULL;
+
+ dev_name = translate_name (name, &slice, &part);
+
+ // TODO when the port isn't used by clients, it should be destroyed.
+ err = create_device_port (sizeof (*bd), &bd);
+ if (err)
+ {
+ ddekit_printf ("after create_device_port: cannot create a port\n");
+ goto out;
+ }
+ bd->dev = open_block_dev (dev_name, slice, mode);
+ if (bd->dev < 0)
+ {
+ ddekit_printf ("open_block_dev fails with %d\n", bd->dev);
+ err = linux_to_mach_error (err);
+ goto out;
+ }
+ bd->device.emul_data = bd;
+ bd->device.emul_ops = &linux_block_emulation_ops;
+ bd->mode = mode;
+
+out:
+ free (dev_name);
+ if (err)
+ {
+ if (bd)
+ {
+ ports_destroy_right (bd);
+ bd = NULL;
+ }
+ }
+ else
+ *devp = ports_get_right (bd);
+ return err;
+}
+
+static io_return_t
+device_write (void *d, mach_port_t reply_port,
+ mach_msg_type_name_t reply_port_type, dev_mode_t mode,
+ recnum_t bn, io_buf_ptr_t data, unsigned int count,
+ int *bytes_written)
+{
+ struct block_data *bd = d;
+ /* the number of pages that contain DATA. */
+ int npages = (((int) data + count) - ((int) data & ~PAGE_MASK)
+ + PAGE_MASK) / PAGE_SIZE;
+ io_return_t err = D_SUCCESS;
+ int i;
+ int writes = 0;
+
+ void write_done (int err)
+ {
+ int len = err ? 0 : count;
+ writes--;
+ if (writes == 0)
+ {
+ err = linux_to_mach_error (err);
+ ds_device_write_reply (reply_port, reply_port_type, err, len);
+ }
+ }
+
+ /* the data is at the beginning of a page. */
+ if ((int) data & ~PAGE_MASK)
+ return D_INVALID_OPERATION;
+
+ if ((bd->mode & D_WRITE) == 0)
+ return D_INVALID_OPERATION;
+
+ for (i = 0; i < npages; i++)
+ {
+ int size = PAGE_SIZE - ((int) data &~PAGE_MASK) > count ?
+ PAGE_SIZE - ((int) data &~PAGE_MASK) : count;
+
+ err = block_dev_write (bd->dev, bn, data, count, write_done);
+ if (err)
+ break;
+ bn += count >> 9;
+ data += size;
+ count -= size;
+ writes++;
+ }
+ if (writes)
+ return MIG_NO_REPLY;
+ return linux_to_mach_error (err);
+}
+
+static io_return_t
+device_read (void *d, mach_port_t reply_port,
+ mach_msg_type_name_t reply_port_type, dev_mode_t mode,
+ recnum_t bn, int count, io_buf_ptr_t *data,
+ unsigned *bytes_read)
+{
+ struct block_data *bd = d;
+
+ if ((bd->mode & D_READ) == 0)
+ return D_INVALID_OPERATION;
+ *bytes_read = 0;
+ return D_SUCCESS;
+}
+
+static io_return_t
+device_get_status (void *d, dev_flavor_t flavor, dev_status_t status,
+ mach_msg_type_number_t *count)
+{
+ struct block_data *bd = (struct block_data *) d;
+ return D_SUCCESS;
+}
+
+struct device_emulation_ops linux_block_emulation_ops =
+{
+ NULL,
+ NULL,
+ dev_to_port,
+ device_open,
+ NULL,
+ device_write,
+ NULL,
+ device_read,
+ NULL,
+ NULL,
+ device_get_status,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+void register_block()
+{
+ extern void reg_dev_emul (struct device_emulation_ops *ops);
+ reg_dev_emul (&linux_block_emulation_ops);
+}
diff --git a/libmachdev/mach_glue.h b/libmachdev/mach_glue.h
new file mode 100644
index 00000000..6d0870ed
--- /dev/null
+++ b/libmachdev/mach_glue.h
@@ -0,0 +1,30 @@
+#ifndef __MACH_GLUE_H__
+#define __MACH_GLUE_H__
+
+/* network */
+#include <arpa/inet.h>
+
+struct sk_buff;
+struct net_device;
+void skb_done_queue(struct sk_buff *skb);
+struct sk_buff *skb_done_dequeue();
+void *skb_reply(struct sk_buff *skb);
+int netdev_flags(struct net_device *dev);
+char *netdev_addr(struct net_device *dev);
+int dev_change_flags (struct net_device *dev, short flags);
+int linux_pkg_xmit (char *pkg_data, int len, void *del_data,
+ int (*del_func) (struct sk_buff *, void *),
+ struct net_device *dev);
+struct net_device *search_netdev (char *name);
+void kfree_skb (struct sk_buff *skb);
+int dev_open(struct net_device *dev);
+void *l4dde26_register_rx_callback(void *cb);
+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));
+
+#endif
diff --git a/libmachdev/machdev.h b/libmachdev/machdev.h
index 27c488a5..cfa4b2d4 100644
--- a/libmachdev/machdev.h
+++ b/libmachdev/machdev.h
@@ -26,6 +26,7 @@
void ds_server(void);
void mach_device_init(void);
void register_net(void);
+void register_block(void);
void trivfs_server(void);
int trivfs_init(void);
diff --git a/libmachdev/net.c b/libmachdev/net.c
index b21d6333..8c435b4b 100644
--- a/libmachdev/net.c
+++ b/libmachdev/net.c
@@ -74,6 +74,7 @@
#include "dev_hdr.h"
#include "if_ether.h"
#include "util.h"
+#include "mach_glue.h"
#define ether_header ethhdr
@@ -99,22 +100,6 @@ struct skb_reply
int pkglen;
};
-struct sk_buff;
-void skb_done_queue(struct sk_buff *skb);
-struct sk_buff *skb_done_dequeue();
-void *skb_reply(struct sk_buff *skb);
-int netdev_flags(struct net_device *dev);
-char *netdev_addr(struct net_device *dev);
-int dev_change_flags (struct net_device *dev, short flags);
-int linux_pkg_xmit (char *pkg_data, int len, void *del_data,
- int (*del_func) (struct sk_buff *, void *),
- struct net_device *dev);
-struct net_device *search_netdev (char *name);
-void kfree_skb (struct sk_buff *skb);
-int dev_open(struct net_device *dev);
-void *l4dde26_register_rx_callback(void *cb);
-void skb_done_head_init();
-
static struct net_data *nd_head;
/* Forward declarations. */
@@ -337,7 +322,7 @@ device_open (mach_port_t reply_port, mach_msg_type_name_t reply_port_type,
if_init_queues (ifp);
#endif
- if (err = dev_open(dev) < 0)
+ if ((err = dev_open(dev)) < 0)
{
fprintf (stderr, "after dev_open: cannot open the device\n");
err = linux_to_mach_error (err);
diff --git a/windhoek/Makefile b/windhoek/Makefile
index 6f355bb9..803e8dba 100644
--- a/windhoek/Makefile
+++ b/windhoek/Makefile
@@ -27,8 +27,8 @@ SRC_C += $(IDEFILES) \
$(CDROMFILES) \
$(PARTITIONFILES)
-LIBS += --whole-archive -ldde_linux26_block --no-whole-archive \
- -ldde_linux26.o -lddekit ../libmachdev/libmachdev.a \
+LIBS += --whole-archive --no-whole-archive ../libmachdev/libmachdev.a \
+ -ldde_linux26_block -ldde_linux26.o -lddekit \
-lfshelp -ltrivfs -lpciaccess -lthreads -lshouldbeinlibc \
-lports -lhurd-slab
diff --git a/windhoek/main.c b/windhoek/main.c
index 6c3cdb89..c4e88666 100644
--- a/windhoek/main.c
+++ b/windhoek/main.c
@@ -66,6 +66,7 @@ int main(int argc, const char **argv)
printk("| ready to rumble.... |\n");
printk("+----------------------------------------+\n");
+ register_block ();
mach_device_init();
trivfs_init();