summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefrag.am1
-rw-r--r--device/ds_routines.c56
-rw-r--r--device/intr.c16
-rw-r--r--device/intr.h3
-rw-r--r--include/mach/experimental.defs38
-rw-r--r--vm/vm_user.c14
6 files changed, 119 insertions, 9 deletions
diff --git a/Makefrag.am b/Makefrag.am
index ea612275..9307f7a5 100644
--- a/Makefrag.am
+++ b/Makefrag.am
@@ -363,7 +363,6 @@ include_device_HEADERS = \
include/device/device_types.h \
include/device/disk_status.h \
include/device/net_status.h \
- include/device/notify.defs \
include/device/notify.h \
include/device/tape_status.h \
include/device/tty_status.h
diff --git a/device/ds_routines.c b/device/ds_routines.c
index 78ff51fe..28be3467 100644
--- a/device/ds_routines.c
+++ b/device/ds_routines.c
@@ -340,7 +340,7 @@ ds_device_intr_register (device_t dev, int id,
if (! name_equal(mdev->dev_ops->d_name, 3, "irq"))
return D_INVALID_OPERATION;
- user_intr_t *e = insert_intr_entry (&irqtab, id, receive_port);
+ user_intr_t *e = insert_intr_entry (&irqtab, id, receive_port, 0);
if (!e)
return D_NO_MEMORY;
@@ -357,6 +357,48 @@ ds_device_intr_register (device_t dev, int id,
return err;
}
+static ipc_port_t intr_receive_ports[16];
+io_return_t
+experimental_device_intr_register (ipc_port_t master_port, int line,
+ int id, int flags, ipc_port_t receive_port)
+{
+ io_return_t ret;
+ /* Open must be called on the master device port. */
+ if (master_port != master_device_port)
+ return D_INVALID_OPERATION;
+
+ /* XXX: move to arch-specific */
+ if (line < 0 || line >= 16)
+ return D_INVALID_OPERATION;
+
+ if (flags != 0x04000000)
+ return D_INVALID_OPERATION;
+
+ user_intr_t *user_intr = insert_intr_entry (&irqtab, line, receive_port, 1);
+ if (!user_intr)
+ return D_NO_MEMORY;
+
+ // TODO The original port should be replaced
+ // when the same device driver calls it again,
+ // in order to handle the case that the device driver crashes and restarts.
+ ret = install_user_intr_handler (&irqtab, line, 0, user_intr);
+
+ if (ret == 0)
+ {
+ /* If the port is installed successfully, increase its reference by 1.
+ * Thus, the port won't be destroyed after its task is terminated. */
+ ip_reference (receive_port);
+
+ intr_receive_ports[line] = receive_port;
+ /* For now netdde calls device_intr_enable once after registration. Assume
+ * it does so for now. When we move to IRQ acknowledgment convention we will
+ * change this. */
+ __disable_irq (line);
+ }
+
+ return ret;
+}
+
kern_return_t
ds_device_intr_ack (device_t dev, ipc_port_t receive_port)
{
@@ -373,6 +415,18 @@ ds_device_intr_ack (device_t dev, ipc_port_t receive_port)
return irq_acknowledge(receive_port);
}
+kern_return_t
+experimental_device_intr_enable(ipc_port_t master_port, int line, char status)
+{
+ if (master_port != master_device_port)
+ return D_INVALID_OPERATION;
+
+ if (status != 1)
+ return D_INVALID_OPERATION;
+
+ return irq_acknowledge(intr_receive_ports[line]);
+}
+
boolean_t
ds_notify (mach_msg_header_t *msg)
{
diff --git a/device/intr.c b/device/intr.c
index fbb9f495..17a673b3 100644
--- a/device/intr.c
+++ b/device/intr.c
@@ -24,7 +24,7 @@
#ifndef MACH_XEN
queue_head_t main_intr_queue;
-static boolean_t deliver_intr (int id, ipc_port_t dst_port);
+static boolean_t deliver_intr (int id, mach_msg_id_t msgh_id, ipc_port_t dst_port);
static user_intr_t *
search_intr (struct irqdev *dev, ipc_port_t dst_port)
@@ -113,7 +113,7 @@ deliver_user_intr (struct irqdev *dev, int id, user_intr_t *e)
* This entry exists in the queue until
* the corresponding interrupt port is removed.*/
user_intr_t *
-insert_intr_entry (struct irqdev *dev, int id, ipc_port_t dst_port)
+insert_intr_entry (struct irqdev *dev, int id, ipc_port_t dst_port, int compat)
{
user_intr_t *e, *new, *ret;
int free = 0;
@@ -137,7 +137,11 @@ insert_intr_entry (struct irqdev *dev, int id, ipc_port_t dst_port)
new->id = id;
new->dst_port = dst_port;
new->interrupts = 0;
- new->n_unacked = 0;
+ new->compat = compat;
+ if (compat)
+ new->n_unacked = 1;
+ else
+ new->n_unacked = 0;
queue_enter (dev->intr_queue, new, user_intr_t *, chain);
out:
@@ -208,7 +212,7 @@ intr_thread (void)
irqtab.tot_num_intr--;
splx (s);
- deliver_intr (id, dst_port);
+ deliver_intr (id, e->compat ? 424242 : DEVICE_INTR_NOTIFY, dst_port);
s = splhigh ();
}
}
@@ -237,7 +241,7 @@ intr_thread (void)
}
static boolean_t
-deliver_intr (int id, ipc_port_t dst_port)
+deliver_intr (int id, mach_msg_id_t msgh_id, ipc_port_t dst_port)
{
ipc_kmsg_t kmsg;
device_intr_notification_t *n;
@@ -261,7 +265,7 @@ deliver_intr (int id, ipc_port_t dst_port)
m->msgh_seqno = DEVICE_NOTIFY_MSGH_SEQNO;
m->msgh_local_port = MACH_PORT_NULL;
m->msgh_remote_port = MACH_PORT_NULL;
- m->msgh_id = DEVICE_INTR_NOTIFY;
+ m->msgh_id = msgh_id;
t->msgt_name = MACH_MSG_TYPE_INTEGER_32;
t->msgt_size = 32;
diff --git a/device/intr.h b/device/intr.h
index cd3e0bce..bd639910 100644
--- a/device/intr.h
+++ b/device/intr.h
@@ -36,6 +36,7 @@ typedef struct {
int n_unacked; /* Number of times irqs were disabled for this */
ipc_port_t dst_port; /* Notification port */
int id; /* Mapping to machine dependent irq_t array elem */
+ int compat;
} user_intr_t;
struct irqdev {
@@ -52,7 +53,7 @@ struct irqdev {
extern queue_head_t main_intr_queue;
extern int install_user_intr_handler (struct irqdev *dev, int id, unsigned long flags, user_intr_t *e);
extern int deliver_user_intr (struct irqdev *dev, int id, user_intr_t *e);
-extern user_intr_t *insert_intr_entry (struct irqdev *dev, int id, ipc_port_t receive_port);
+extern user_intr_t *insert_intr_entry (struct irqdev *dev, int id, ipc_port_t receive_port, int compat);
void intr_thread (void);
kern_return_t irq_acknowledge (ipc_port_t receive_port);
diff --git a/include/mach/experimental.defs b/include/mach/experimental.defs
index ddcbea5f..9a2f28db 100644
--- a/include/mach/experimental.defs
+++ b/include/mach/experimental.defs
@@ -13,3 +13,41 @@ subsystem
serverprefix experimental_;
/* This is free for experimenting RPCs, with no backward compatibility guarantees. */
+
+type notify_port_t = MACH_MSG_TYPE_MOVE_SEND_ONCE
+ ctype: mach_port_t;
+
+skip; /*simpleroutine mach_intr_notify(
+ notify : notify_port_t;
+ name : int);*/
+
+routine device_intr_register(
+ master_port : mach_port_t;
+ in line : int;
+ in id : int;
+ in flags : int;
+ in receive_port : mach_port_send_t
+ );
+
+/*
+ * enable/disable the specified line.
+ */
+/* XXX: Naming a function taht can disable something "xxx_enable" is confusing. */
+/* Is the disable part actually used at all? AIUI, the kernel IRQ handler
+should always disable the line; and the userspace driver only has to
+reenable it, after acknowledging and handling the interrupt...
+*/
+routine device_intr_enable(
+ master_port : mach_port_t;
+ line : int;
+ status : char);
+
+/*
+ * This routine is for compatibility with old userland drivers.
+ */
+routine vm_allocate_contiguous(
+ host_priv : host_priv_t;
+ target_task : vm_task_t;
+ out vaddr : vm_address_t;
+ out paddr : vm_address_t;
+ size : vm_size_t);
diff --git a/vm/vm_user.c b/vm/vm_user.c
index 4d5728c8..b13ba8dc 100644
--- a/vm/vm_user.c
+++ b/vm/vm_user.c
@@ -659,3 +659,17 @@ kern_return_t vm_allocate_contiguous(
return KERN_SUCCESS;
}
+
+kern_return_t experimental_vm_allocate_contiguous(host_priv, map, result_vaddr, result_paddr, size)
+ host_t host_priv;
+ vm_map_t map;
+ vm_address_t *result_vaddr;
+ vm_address_t *result_paddr;
+ vm_size_t size;
+{
+ rpc_phys_addr_t paddr;
+ kern_return_t ret;
+ ret = vm_allocate_contiguous(host_priv, map, result_vaddr, &paddr, size, 0, ~0ULL, 0);
+ *result_paddr = paddr;
+ return ret;
+}