summaryrefslogtreecommitdiff
path: root/libmachdev
diff options
context:
space:
mode:
Diffstat (limited to 'libmachdev')
-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
5 files changed, 284 insertions, 18 deletions
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);