}
else if (strcmp(argv[i], ARG_DEVSTYLE)==0) {
char* dev_style_keys[] = { "STYLE_DEV", "STYLE_TTY",
- "STYLE_CTTY", "STYLE_CLONE", NULL };
+ "STYLE_CTTY", NULL };
int dev_style_values[] = { STYLE_DEV, STYLE_TTY,
- STYLE_CTTY, STYLE_CLONE };
+ STYLE_CTTY };
for(j=0;dev_style_keys[j]!=NULL;j++) {
if(!strcmp(dev_style_keys[j], argv[i+1])) {
break;
log->log_source = NONE;
}
- if (log->log_size > 0 && (log->log_selected & SEL_RD)) {
+ if (log->log_size > 0 && (log->log_selected & CDEV_OP_RD)) {
/* Someone(s) who was/were select()ing can now be awoken. If there was
* a blocking read (above), this can only happen if the blocking read
* didn't swallow all the data (log_size > 0).
*/
minor = log-logdevices;
#if LOG_DEBUG
- printf("select sending DEV_SEL_REPL2\n");
+ printf("select sending CDEV_SEL2_REPLY\n");
#endif
- chardriver_reply_select(log->log_select_proc, minor, SEL_RD);
- log->log_selected &= ~SEL_RD;
+ chardriver_reply_select(log->log_select_proc, minor, CDEV_OP_RD);
+ log->log_selected &= ~CDEV_OP_RD;
}
return r;
if (log->log_source != NONE) return OK;
if (!log->log_size && size > 0) {
- if (flags & FLG_OP_NONBLOCK) return EAGAIN;
+ if (flags & CDEV_NONBLOCK) return EAGAIN;
/* No data available; let caller block. */
log->log_source = endpt;
if (minor < 0 || minor >= NR_DEVS)
return ENXIO;
- want_ops = ops & (SEL_RD|SEL_WR|SEL_ERR);
+ want_ops = ops & (CDEV_OP_RD | CDEV_OP_WR | CDEV_OP_ERR);
/* Read blocks when there is no log. */
- if ((want_ops & SEL_RD) && logdevices[minor].log_size > 0) {
+ if ((want_ops & CDEV_OP_RD) && logdevices[minor].log_size > 0) {
#if LOG_DEBUG
printf("log can read; size %d\n", logdevices[minor].log_size);
#endif
- ready_ops |= SEL_RD;
+ ready_ops |= CDEV_OP_RD;
}
/* Write never blocks. */
- if (want_ops & SEL_WR) ready_ops |= SEL_WR;
+ if (want_ops & CDEV_OP_WR) ready_ops |= CDEV_OP_WR;
/* Enable select calback if not all requested operations were ready to go,
* and notify was enabled.
*/
want_ops &= ~ready_ops;
- if ((ops & SEL_NOTIFY) && want_ops) {
+ if ((ops & CDEV_NOTIFY) && want_ops) {
logdevices[minor].log_selected |= want_ops;
logdevices[minor].log_select_proc = endpt;
#if LOG_DEBUG
* Changes:
* May 07, 2004 fix: wait until printer is ready (Jorrit N. Herder)
* May 06, 2004 printer driver moved to user-space (Jorrit N. Herder)
- *
- * The valid messages and their parameters are:
- *
- * DEV_OPEN: initializes the printer
- * DEV_CLOSE: does nothing
- * HARD_INT: interrupt handler has finished current chunk of output
- * DEV_WRITE: a process wants to write on a terminal
- * CANCEL: terminate a previous incomplete system call immediately
- *
- * m_type DEVICE USER_ENDPT COUNT ADDRESS
- * |-------------+---------+---------+---------+---------|
- * | DEV_OPEN | | | | |
- * |-------------+---------+---------+---------+---------|
- * | DEV_CLOSE | | proc nr | | |
- * |-------------+---------+---------+---------+---------|
- * | HARD_INT | | | | |
- * |-------------+---------+---------+---------+---------|
- * | DEV_WRITE |minor dev| proc nr | count | buf ptr |
- * |-------------+---------+---------+---------+---------|
- * | CANCEL |minor dev| proc nr | | |
- * -------------------------------------------------------
*
* Note: since only 1 printer is supported, minor dev is not used at present.
*/
*/
if (writing) return EIO;
if (size <= 0) return EINVAL;
- if (flags & FLG_OP_NONBLOCK) return EAGAIN; /* not supported */
+ if (flags & CDEV_NONBLOCK) return EAGAIN; /* not supported */
/* If no errors occurred, continue printing with the caller.
* First wait until the printer is online to prevent stupid errors.
/* If no data is available, suspend the caller. */
if (kbdp->avail == 0) {
- if (flags & FLG_OP_NONBLOCK)
+ if (flags & CDEV_NONBLOCK)
return EAGAIN;
kbdp->req_size = size;
kbdp->req_id = id;
if ((kbdp = line2kbd(minor)) == NULL)
return ENXIO;
- watch = (ops & SEL_NOTIFY);
- ops &= (SEL_RD | SEL_WR | SEL_ERR);
+ watch = (ops & CDEV_NOTIFY);
+ ops &= (CDEV_OP_RD | CDEV_OP_WR | CDEV_OP_ERR);
ready_ops = 0;
- if (kbdp->avail && (ops & SEL_RD))
- ready_ops |= SEL_RD;
- if (ops & SEL_WR)
- ready_ops |= SEL_WR; /* writes never block */
+ if (kbdp->avail && (ops & CDEV_OP_RD))
+ ready_ops |= CDEV_OP_RD;
+ if (ops & CDEV_OP_WR)
+ ready_ops |= CDEV_OP_WR; /* writes never block */
ops &= ~ready_ops;
if (ops && watch) {
kbdp->req_caller = NONE;
}
/* Only satisfy pending select if characters weren't just read. */
- if (kbdp->avail && (kbdp->select_ops & SEL_RD)) {
+ if (kbdp->avail && (kbdp->select_ops & CDEV_OP_RD)) {
chardriver_reply_select(kbdp->select_proc, kbdp->minor,
- SEL_RD);
- kbdp->select_ops &= ~SEL_RD;
+ CDEV_OP_RD);
+ kbdp->select_ops &= ~CDEV_OP_RD;
}
return;
}
if (ihead == ibuf + KB_IN_BYTES) ihead = ibuf;
icount++;
tty_table[ccurrent].tty_events = 1;
- if (tty_table[ccurrent].tty_select_ops & SEL_RD) {
+ if (tty_table[ccurrent].tty_select_ops & CDEV_OP_RD) {
select_retry(&tty_table[ccurrent]);
}
}
if (injhead == injbuf + KB_IN_BYTES) injhead = injbuf;
injcount++;
tty_table[ccurrent].tty_events = 1;
- if (tty_table[ccurrent].tty_select_ops & SEL_RD) {
+ if (tty_table[ccurrent].tty_select_ops & CDEV_OP_RD) {
select_retry(&tty_table[ccurrent]);
}
}
return EDONTREPLY; /* already done */
}
- if (flags & FLG_OP_NONBLOCK) {
+ if (flags & CDEV_NONBLOCK) {
r = pp->rdcum > 0 ? pp->rdcum : EAGAIN;
pp->rdleft = pp->rdcum = 0;
pp->rdcaller = NONE;
return EDONTREPLY; /* already done */
}
- if (flags & FLG_OP_NONBLOCK) {
+ if (flags & CDEV_NONBLOCK) {
r = pp->wrcum > 0 ? pp->wrcum : EAGAIN;
pp->wrleft = pp->wrcum = 0;
pp->wrcaller = NONE;
pty_t *pp = tp->tty_priv;
int r = 0;
- if (ops & SEL_WR) {
+ if (ops & CDEV_OP_WR) {
/* Write won't block on error. */
- if (pp->state & TTY_CLOSED) r |= SEL_WR;
- else if (pp->wrleft != 0 || pp->wrcum != 0) r |= SEL_WR;
- else if (tp->tty_inleft > 0) r |= SEL_WR; /* There's a reader. */
+ if (pp->state & TTY_CLOSED) r |= CDEV_OP_WR;
+ else if (pp->wrleft != 0 || pp->wrcum != 0) r |= CDEV_OP_WR;
+ else if (tp->tty_inleft > 0) r |= CDEV_OP_WR; /* There's a reader. */
}
- if (ops & SEL_RD) {
+ if (ops & CDEV_OP_RD) {
/* Read won't block on error. */
- if (pp->state & TTY_CLOSED) r |= SEL_RD;
- else if (pp->rdleft != 0 || pp->rdcum != 0) r |= SEL_RD;
- else if (pp->ocount > 0) r |= SEL_RD; /* Actual data. */
+ if (pp->state & TTY_CLOSED) r |= CDEV_OP_RD;
+ else if (pp->rdleft != 0 || pp->rdcum != 0) r |= CDEV_OP_RD;
+ else if (pp->ocount > 0) r |= CDEV_OP_RD; /* Actual data. */
}
return r;
return ENXIO;
pp = tp->tty_priv;
- watch = (ops & SEL_NOTIFY);
- ops &= (SEL_RD | SEL_WR | SEL_ERR);
+ watch = (ops & CDEV_NOTIFY);
+ ops &= (CDEV_OP_RD | CDEV_OP_WR | CDEV_OP_ERR);
ready_ops = select_try_pty(tp, ops);
* to, you guessed it, wake up the TTY to check if input or output can
* continue.
*
- * The valid messages and their parameters are:
- *
- * notify from HARDWARE: output has been completed or input has arrived
- * notify from SYSTEM : e.g., MINIX wants to shutdown; run code to
- * cleanly stop
- * DEV_READ: a process wants to read from a terminal
- * DEV_WRITE: a process wants to write on a terminal
- * DEV_IOCTL: a process wants to change a terminal's parameters
- * DEV_OPEN: a tty line has been opened
- * DEV_CLOSE: a tty line has been closed
- * DEV_SELECT: start select notification request
- * CANCEL: terminate a previous incomplete system call immediately
- *
- * m_type DEVICE USER_ENDPT COUNT POSITION IO_GRANT
- * -----------------------------------------------------------------
- * | HARD_INT | | | | | |
- * |-------------+---------+---------+---------+---------+---------|
- * | DEV_READ |minor dev| proc nr | count | | grant |
- * |-------------+---------+---------+---------+---------+---------|
- * | DEV_WRITE |minor dev| proc nr | count | | grant |
- * |-------------+---------+---------+---------+---------+---------|
- * | DEV_IOCTL |minor dev| proc nr |func code|user proc| |
- * |-------------+---------+---------+---------+---------+---------|
- * | DEV_OPEN |minor dev| proc nr | O_NOCTTY| | |
- * |-------------+---------+---------+---------+---------+---------|
- * | DEV_CLOSE |minor dev| proc nr | | | |
- * |-------------+---------+---------+---------+---------+---------|
- * | CANCEL |minor dev| proc nr | | | |
- * |-------------+---------+---------+---------+---------+---------|
- * | DEV_SELECT |minor dev| sel ops | | | |
- * -----------------------------------------------------------------
- *
* Changes:
* Jan 20, 2004 moved TTY driver to user-space (Jorrit N. Herder)
* Sep 20, 2004 local timer management/ sync alarms (Jorrit N. Herder)
; /* do nothing; end switch */
}
- if (!IS_DEV_RQ(tty_mess.m_type)) {
+ if (!IS_CDEV_RQ(tty_mess.m_type)) {
chardriver_process(&tty_tab, &tty_mess, ipc_status);
continue;
}
/* Only device requests should get to this point.
* All requests have a minor device number.
*/
- line = tty_mess.DEVICE;
+ line = tty_mess.CDEV_MINOR;
if (line == KBD_MINOR || line == KBDAUX_MINOR) {
do_kbd(&tty_mess, ipc_status);
continue;
do_video(&tty_mess, ipc_status);
continue;
} else if (line - PTYPX_MINOR < NR_PTYS &&
- tty_mess.m_type != DEV_IOCTL_S) {
+ tty_mess.m_type != CDEV_IOCTL) {
/* Terminals and pseudo terminals belong together. We can only
* make a distinction between the two based on position in the
* tty_table and not on minor number (i.e., use ispty macro).
buf[0] = '\033';
snprintf(&buf[1], sizeof(buf) - 1, "[1;%dm", color);
do_write(tp->tty_minor, 0, KERNEL, (cp_grant_id_t) buf, sizeof(buf),
- FLG_OP_NONBLOCK, 0);
+ CDEV_NONBLOCK, 0);
}
static void
buf[0] = '\033';
snprintf(&buf[1], sizeof(buf) - 1, "[0;%dm", SGR_COLOR_RESET);
do_write(tp->tty_minor, 0, KERNEL, (cp_grant_id_t) buf, sizeof(buf),
- FLG_OP_NONBLOCK, 0);
+ CDEV_NONBLOCK, 0);
}
tty_t *
set_color(tp, kernel_msg_color);
do_write(tp->tty_minor, 0, KERNEL,
(cp_grant_id_t) kernel_buf_copy, bytes,
- FLG_OP_NONBLOCK, 0);
+ CDEV_NONBLOCK, 0);
if (kernel_msg_color != 0)
reset_color(tp);
if (restore) {
return EDONTREPLY; /* already done */
/* There were no bytes in the input queue available. */
- if (flags & FLG_OP_NONBLOCK) {
+ if (flags & CDEV_NONBLOCK) {
tty_icancel(tp);
r = tp->tty_incum > 0 ? tp->tty_incum : EAGAIN;
tp->tty_inleft = tp->tty_incum = 0;
return EDONTREPLY; /* already done */
/* None or not all the bytes could be written. */
- if (flags & FLG_OP_NONBLOCK) {
+ if (flags & CDEV_NONBLOCK) {
r = tp->tty_outcum > 0 ? tp->tty_outcum : EAGAIN;
tp->tty_outleft = tp->tty_outcum = 0;
tp->tty_outcaller = NONE;
case TCSETSF:
case TCDRAIN:
if (tp->tty_outleft > 0) {
- if (flags & FLG_OP_NONBLOCK)
+ if (flags & CDEV_NONBLOCK)
return EAGAIN;
/* Wait for all ongoing output processing to finish. */
tp->tty_iocaller = endpt;
static int do_open(devminor_t minor, int access, endpoint_t user_endpt)
{
/* A tty line has been opened. Make it the callers controlling tty if
- * O_NOCTTY is *not* set and it is not the log device. 1 is returned if
- * the tty is made the controlling tty, otherwise OK or an error code.
+ * CDEV_NOCTTY is *not* set and it is not the log device. CDEV_CTTY is returned
+ * if the tty is made the controlling tty, otherwise OK or an error code.
*/
tty_t *tp;
int r = OK;
if (minor == LOG_MINOR && isconsole(tp)) {
/* The log device is a write-only diagnostics device. */
- if (access & R_BIT) return EACCES;
+ if (access & CDEV_R_BIT) return EACCES;
} else {
- if (!(access & O_NOCTTY)) {
+ if (!(access & CDEV_NOCTTY)) {
tp->tty_pgrp = user_endpt;
- r = 1;
+ r = CDEV_CTTY;
}
tp->tty_openct++;
if (tp->tty_openct == 1) {
ready_ops |= ops;
}
- if (ops & SEL_RD) {
+ if (ops & CDEV_OP_RD) {
/* will i/o not block on read? */
if (tp->tty_inleft > 0) {
- ready_ops |= SEL_RD; /* EIO - no blocking */
+ ready_ops |= CDEV_OP_RD; /* EIO - no blocking */
} else if (tp->tty_incount > 0) {
/* Is a regular read possible? tty_incount
* says there is data. But a read will only succeed
*/
if (!(tp->tty_termios.c_lflag & ICANON) ||
tp->tty_eotct > 0) {
- ready_ops |= SEL_RD;
+ ready_ops |= CDEV_OP_RD;
}
}
}
- if (ops & SEL_WR) {
- if (tp->tty_outleft > 0) ready_ops |= SEL_WR;
- else if ((*tp->tty_devwrite)(tp, 1)) ready_ops |= SEL_WR;
+ if (ops & CDEV_OP_WR) {
+ if (tp->tty_outleft > 0) ready_ops |= CDEV_OP_WR;
+ else if ((*tp->tty_devwrite)(tp, 1)) ready_ops |= CDEV_OP_WR;
}
return ready_ops;
}
if (tp->tty_minor != minor)
return EBADF;
- watch = (ops & SEL_NOTIFY);
- ops &= (SEL_RD | SEL_WR | SEL_ERR);
+ watch = (ops & CDEV_NOTIFY);
+ ops &= (CDEV_OP_RD | CDEV_OP_WR | CDEV_OP_ERR);
ready_ops = select_try(tp, ops);
#define ESC '\33' /* escape */
-#define O_NOCTTY 00400 /* from <fcntl.h>, or cc will choke */
-#define O_NONBLOCK 04000
-
struct tty;
typedef int(*devfun_t) (struct tty *tp, int try_only);
typedef void(*devfunarg_t) (struct tty *tp, int c);
sleep 3
if [ X`/bin/sysenv lwip` = Xyes ]
then
- service up /usr/sbin/lwip -script /etc/rs.inet -dev /dev/ip -devstyle STYLE_CLONE
+ service up /usr/sbin/lwip -script /etc/rs.inet -dev /dev/ip
dhcpd --lwip &
else
- service up /usr/sbin/inet -script /etc/rs.inet -dev /dev/ip -devstyle STYLE_CLONE
+ service up /usr/sbin/inet -script /etc/rs.inet -dev /dev/ip
daemonize dhcpd
fi
daemonize nonamed -L
done
if [ X`/bin/sysenv lwip` = Xyes ]
then
- up lwip -script /etc/rs.inet -dev /dev/ip -devstyle STYLE_CLONE
+ up lwip -script /etc/rs.inet -dev /dev/ip
else
- up inet -script /etc/rs.inet -dev /dev/ip -devstyle STYLE_CLONE
+ up inet -script /etc/rs.inet -dev /dev/ip
fi
up -n ipc
* 1 - 0xFF POSIX requests (see callnr.h)
* 0x200 - 0x2FF Data link layer requests and responses
* 0x300 - 0x3FF Bus controller requests and responses
- * 0x400 - 0x4FF Character device requests
- * 0x500 - 0x5FF Character device responses
+ * 0x400 - 0x4FF Character device requests and responses
+ * 0x500 - 0x5FF Block device requests and responses
* 0x600 - 0x6FF Kernel calls to SYSTEM task
* 0x700 - 0x7FF Reincarnation Server (RS) requests
* 0x800 - 0x8FF Data Store (DS) requests
* 0x1200 - 0x12FF Devman
* 0x1300 - 0x13FF TTY Requests
* 0x1400 - 0x14FF VFS-FS transaction IDs
- * 0x1500 - 0x15FF Block device requests and responses
+ * 0x1500 - 0x15FF (unused)
* 0x1600 - 0x16FF VirtualBox (VBOX) requests (see vboxif.h)
* 0x1700 - 0x17FF Real Time Clock requests and responses
*
#define BUSC_I2C_EXEC (BUSC_RQ_BASE + 65) /* perform i2c action */
#define BUSC_I2C_GRANT m2_i1 /* grant for request */
-/*===========================================================================*
- * Messages for CHARACTER device drivers *
- *===========================================================================*/
-
-/* Message types for character device drivers. */
-#define DEV_RQ_BASE 0x400 /* base for character device request types */
-#define DEV_RS_BASE 0x500 /* base for character device response types */
-
-#define CANCEL (DEV_RQ_BASE + 0) /* force a task to cancel */
-#define DEV_OPEN (DEV_RQ_BASE + 6) /* open a minor device */
-#define DEV_CLOSE (DEV_RQ_BASE + 7) /* close a minor device */
-#define DEV_SELECT (DEV_RQ_BASE + 12) /* request select() attention */
-
-#define DEV_READ_S (DEV_RQ_BASE + 20) /* (safecopy) read from minor */
-#define DEV_WRITE_S (DEV_RQ_BASE + 21) /* (safecopy) write to minor */
-#define DEV_SCATTER_S (DEV_RQ_BASE + 22) /* (safecopy) write from a vector */
-#define DEV_GATHER_S (DEV_RQ_BASE + 23) /* (safecopy) read into a vector */
-#define DEV_IOCTL_S (DEV_RQ_BASE + 24) /* (safecopy) I/O control code */
-
-#define IS_DEV_RQ(type) (((type) & ~0xff) == DEV_RQ_BASE)
-
-#define DEV_REVIVE (DEV_RS_BASE + 2) /* driver revives process */
-#define DEV_CLOSE_REPL (DEV_RS_BASE + 6) /* reply to DEV_CLOSE */
-#define DEV_SEL_REPL1 (DEV_RS_BASE + 7) /* first reply to DEV_SELECT */
-#define DEV_SEL_REPL2 (DEV_RS_BASE + 8) /* (opt) second reply to DEV_SELECT */
-#define DEV_OPEN_REPL (DEV_RS_BASE + 9) /* reply to DEV_OPEN */
-
-#define IS_DEV_RS(type) (((type) & ~0xff) == DEV_RS_BASE)
-
-/* Field names for messages to character device drivers. */
-#define DEVICE m2_i1 /* major-minor device */
-#define USER_ENDPT m2_i2 /* which endpoint initiated this call? */
-#define COUNT m2_i3 /* how many bytes to transfer */
-#define REQUEST m2_i3 /* ioctl request code */
-#define POSITION m2_l1 /* file offset (low 4 bytes) */
-#define HIGHPOS m2_l2 /* file offset (high 4 bytes) */
-#define ADDRESS m2_p1 /* core buffer address */
-#define IO_GRANT m2_p1 /* grant id (for DEV_*_S variants) */
-#define FLAGS m2_s1 /* operation flags */
-
-#define FLG_OP_NONBLOCK 0x1 /* operation is non blocking */
-
-/* Field names for DEV_SELECT messages to character device drivers. */
-#define DEV_MINOR m2_i1 /* minor device */
-#define DEV_SEL_OPS m2_i2 /* which select operations are requested */
-
-/* Field names used in reply messages from tasks. */
-#define REP_ENDPT m2_i1 /* # of proc on whose behalf I/O was done */
-#define REP_STATUS m2_i2 /* bytes transferred or error number */
-#define REP_IO_GRANT m2_i3 /* DEV_REVIVE: grant by which I/O was done */
-# define SUSPEND -998 /* status to suspend caller, reply later */
-
/*===========================================================================*
* Messages for networking layer *
*===========================================================================*/
#define VFS_PFS_FD m2_i3
#define VFS_PFS_FILP m2_p1
+/* Field names for GETRUSAGE related calls */
+#define RU_ENDPT m1_i1 /* indicates a process for sys_getrusage */
+#define RU_WHO m1_i1 /* who argument in getrusage call */
+#define RU_RUSAGE_ADDR m1_p1 /* pointer to struct rusage */
+
/*===========================================================================*
* Messages for VM server *
*===========================================================================*/
#define VFS_TRANSID (VFS_TRANSACTION_BASE + 1)
#define IS_VFS_FS_TRANSID(type) (((type) & ~0xff) == VFS_TRANSACTION_BASE)
+/*===========================================================================*
+ * Messages for character devices *
+ *===========================================================================*/
+
+/* Base type for character device requests and responses. */
+#define CDEV_RQ_BASE 0x400
+#define CDEV_RS_BASE 0x480
+
+#define IS_CDEV_RQ(type) (((type) & ~0x7f) == CDEV_RQ_BASE)
+#define IS_CDEV_RS(type) (((type) & ~0x7f) == CDEV_RS_BASE)
+
+/* Message types for character device requests. */
+#define CDEV_OPEN (CDEV_RQ_BASE + 0) /* open a minor device */
+#define CDEV_CLOSE (CDEV_RQ_BASE + 1) /* close a minor device */
+#define CDEV_READ (CDEV_RQ_BASE + 2) /* read into a buffer */
+#define CDEV_WRITE (CDEV_RQ_BASE + 3) /* write from a buffer */
+#define CDEV_IOCTL (CDEV_RQ_BASE + 4) /* I/O control operation */
+#define CDEV_CANCEL (CDEV_RQ_BASE + 5) /* cancel suspended request */
+#define CDEV_SELECT (CDEV_RQ_BASE + 6) /* test for ready operations */
+
+/* Message types for character device responses. */
+#define CDEV_REPLY (CDEV_RS_BASE + 0) /* general reply code */
+#define CDEV_SEL1_REPLY (CDEV_RS_BASE + 1) /* immediate select reply */
+#define CDEV_SEL2_REPLY (CDEV_RS_BASE + 2) /* select notification reply */
+
+/* Field names for block device messages. */
+#define CDEV_MINOR m10_i1 /* minor device number */
+#define CDEV_STATUS m10_i2 /* OK, error code, minor device, operations */
+#define CDEV_ACCESS m10_i2 /* access bits for open requests */
+#define CDEV_GRANT m10_i2 /* grant ID of buffer */
+#define CDEV_OPS m10_i2 /* requested select operations */
+#define CDEV_COUNT m10_i3 /* number of bytes to transfer */
+#define CDEV_USER m10_i3 /* endpoint of user process */
+#define CDEV_FLAGS m10_i4 /* transfer flags */
+#define CDEV_ID m10_l1 /* opaque request ID */
+#define CDEV_REQUEST m10_l2 /* I/O control request */
+#define CDEV_POS_LO m10_l2 /* transfer position (low bits) */
+#define CDEV_POS_HI m10_l3 /* transfer position (high bits) */
+
+/* Bits in 'CDEV_ACCESS' field of block device open requests. */
+# define CDEV_R_BIT 0x01 /* open with read access */
+# define CDEV_W_BIT 0x02 /* open with write access */
+# define CDEV_NOCTTY 0x04 /* not to become the controlling TTY */
+
+/* Bits in 'CDEV_FLAGS' field of block device transfer requests. */
+# define CDEV_NOFLAGS 0x00 /* no flags are set */
+# define CDEV_NONBLOCK 0x01 /* do not suspend I/O request */
+
+/* Bits in 'CDEV_OPS', 'CDEV_STATUS' fields of block device select messages. */
+# define CDEV_OP_RD 0x01 /* selected for read operation */
+# define CDEV_OP_WR 0x02 /* selected for write operation */
+# define CDEV_OP_ERR 0x04 /* selected for error operation */
+# define CDEV_NOTIFY 0x08 /* notification requested */
+
+/* Bits in 'CDEV_STATUS' field of block device open responses. */
+# define CDEV_CLONED 0x20000000 /* device is cloned */
+# define CDEV_CTTY 0x40000000 /* device is controlling TTY */
+
/*===========================================================================*
* Messages for block devices *
*===========================================================================*/
/* Base type for block device requests and responses. */
-#define BDEV_RQ_BASE 0x1500
-#define BDEV_RS_BASE 0x1580
+#define BDEV_RQ_BASE 0x500
+#define BDEV_RS_BASE 0x580
#define IS_BDEV_RQ(type) (((type) & ~0x7f) == BDEV_RQ_BASE)
#define IS_BDEV_RS(type) (((type) & ~0x7f) == BDEV_RS_BASE)
# define BDEV_FORCEWRITE 0x01 /* force write to disk immediately */
# define BDEV_NOPAGE 0x02 /* eeprom: don't send page address */
-/* Field names for GETRUSAGE related calls */
-#define RU_ENDPT m1_i1 /* indicates a process for sys_getrusage */
-#define RU_WHO m1_i1 /* who argument in getrusage call */
-#define RU_RUSAGE_ADDR m1_p1 /* pointer to struct rusage */
-
/*===========================================================================*
* Messages for Real Time Clocks *
*===========================================================================*/
#define RTCDEV_Y2KBUG 0x01 /* Interpret 1980 as 2000 for RTC w/Y2K bug */
#define RTCDEV_CMOSREG 0x02 /* Also set the CMOS clock register bits. */
+/*===========================================================================*
+ * Internal codes used by several services *
+ *===========================================================================*/
+
+#define SUSPEND -998 /* status to suspend caller, reply later */
+
/* _MINIX_COM_H */
#include <minix/sys_config.h>
#include <minix/ipc.h>
-enum dev_style { STYLE_NDEV, STYLE_DEV, STYLE_TTY, STYLE_CTTY, STYLE_CLONE };
-#define IS_DEV_STYLE(s) (s>=STYLE_NDEV && s<=STYLE_CLONE)
+enum dev_style { STYLE_NDEV, STYLE_DEV, STYLE_TTY, STYLE_CTTY };
+#define IS_DEV_STYLE(s) (s>=STYLE_NDEV && s<=STYLE_CTTY)
/*===========================================================================*
* Major and minor device numbers *
* extra buffer space beside the dma buffer.
* This driver also support sub devices, which can be independently
* opened and closed.
- *
- * The driver supports the following operations:
- *
- * m_type DEVICE USER_ENDPT COUNT POSITION ADRRESS
- * -----------------------------------------------------------------
- * | DEV_OPEN | device | proc nr | | | |
- * |-------------+---------+---------+---------+---------+---------|
- * | DEV_CLOSE | device | proc nr | | | |
- * |-------------+---------+---------+---------+---------+---------|
- * | DEV_READ_S | device | proc nr | bytes | | buf ptr |
- * |-------------+---------+---------+---------+---------+---------|
- * | DEV_WRITE_S | device | proc nr | bytes | | buf ptr |
- * |-------------+---------+---------+---------+---------+---------|
- * | DEV_IOCTL_S | device | proc nr |func code| | buf ptr |
- * |-------------+---------+---------+---------+---------+---------|
- * | HARD_INT | | | | | |
- * -----------------------------------------------------------------
*
* The file contains one entry point:
*
memset(&m_reply, 0, sizeof(m_reply));
- m_reply.m_type = DEV_OPEN_REPL;
- m_reply.REP_ENDPT = m_ptr->USER_ENDPT;
- m_reply.REP_STATUS = ENXIO;
+ m_reply.m_type = CDEV_REPLY;
+ m_reply.CDEV_STATUS = ENXIO;
+ m_reply.CDEV_ID = m_ptr->CDEV_ID;
send_reply(m_ptr->m_source, &m_reply, ipc_status);
}
* someone creates a character device node for a block driver, opening that
* device node will cause the corresponding VFS thread to block forever.
*/
- if (m_ptr->m_type == DEV_OPEN) {
+ if (m_ptr->m_type == CDEV_OPEN) {
do_char_open(m_ptr, ipc_status);
return;
/* This file contains the device independent character driver interface.
*
- * The drivers support the following operations (using message format m2):
+ * Charaxter drivers support the following requests. Message format m10 is
+ * used. Field names are prefixed with CDEV_. Separate field names are used for
+ * the "access", "ops", "user", and "request" fields.
*
- * m_type DEVICE USER_ENDPT COUNT POSITION HIGHPOS IO_GRANT
- * ----------------------------------------------------------------------------
- * | DEV_OPEN | device | proc nr | mode | | | |
- * |---------------+--------+---------+---------+--------+--------+-----------|
- * | DEV_CLOSE | device | proc nr | | | | |
- * |---------------+--------+---------+---------+--------+--------+-----------|
- * | DEV_READ_S | device | proc nr | bytes | off lo | off hi i buf grant |
- * |---------------+--------+---------+---------+--------+--------+-----------|
- * | DEV_WRITE_S | device | proc nr | bytes | off lo | off hi | buf grant |
- * |---------------+--------+---------+---------+--------+--------+-----------|
- * | DEV_GATHER_S | device | proc nr | iov len | off lo | off hi | iov grant |
- * |---------------+--------+---------+---------+--------+--------+-----------|
- * | DEV_SCATTER_S | device | proc nr | iov len | off lo | off hi | iov grant |
- * |---------------+--------+---------+---------+--------+--------+-----------|
- * | DEV_IOCTL_S | device | proc nr | request | | | buf grant |
- * |---------------+--------+---------+---------+--------+--------+-----------|
- * | CANCEL | device | proc nr | r/w | | | grant |
- * |---------------+--------+---------+---------+--------+--------+-----------|
- * | DEV_SELECT | device | ops | | | | |
- * ----------------------------------------------------------------------------
+ * m_type MINOR GRANT COUNT FLAGS ID POS_LO POS_HI
+ * +-------------+-------+--------+-------+-------+------+---------+--------+
+ * | CDEV_OPEN | minor | access | user | | id | | |
+ * |-------------+-------+--------+-------+-------+------+---------+--------|
+ * | CDEV_CLOSE | minor | | | | id | | |
+ * |-------------+-------+--------+-------+-------+------+---------+--------|
+ * | CDEV_READ | minor | grant | bytes | flags | id | position |
+ * |-------------+-------+--------+-------+-------+------+---------+--------|
+ * | CDEV_WRITE | minor | grant | bytes | flags | id | position |
+ * |-------------+-------+--------+-------+-------+------+---------+--------|
+ * | CDEV_IOCTL | minor | grant | user | flags | id | request | |
+ * |-------------+-------+--------+-------+-------+------+---------+--------|
+ * | CDEV_CANCEL | minor | | | | id | | |
+ * |-------------+-------+--------+-------+-------+------+---------+--------|
+ * | CDEV_SELECT | minor | ops | | | | | |
+ * --------------------------------------------------------------------------
+ *
+ * The following reply messages are used.
+ *
+ * m_type MINOR STATUS ID
+ * +-----------------+-------+--------+-----+-----+------+---------+--------+
+ * | CDEV_REPLY | | status | | | id | | |
+ * |-----------------+-------+--------+-----+-----+------+---------+--------|
+ * | CDEV_SEL1_REPLY | minor | status | | | | | |
+ * |-----------------+-------+--------+-----+-----+------+---------+--------|
+ * | CDEV_SEL2_REPLY | minor | status | | | | | |
+ * --------------------------------------------------------------------------
*
* Changes:
* Sep 01, 2013 complete rewrite of the API (D.C. van Moolenboek)
if ((r = ds_publish_u32(key, DS_DRIVER_UP, DSF_OVERWRITE)) != OK)
panic("chardriver_init: unable to publish driver up event: %d", r);
- /* Expect a DEV_OPEN for any device before serving regular driver requests. */
+ /* Expect an open for any device before serving regular driver requests. */
clear_open_devs();
}
memset(&m_reply, 0, sizeof(m_reply));
- m_reply.m_type = DEV_REVIVE;
- m_reply.REP_STATUS = r;
- m_reply.REP_ENDPT = endpt; /* XXX FIXME: hack */
- m_reply.REP_IO_GRANT = (cp_grant_id_t) id;
+ m_reply.m_type = CDEV_REPLY;
+ m_reply.CDEV_STATUS = r;
+ m_reply.CDEV_ID = id;
if ((r = asynsend3(endpt, &m_reply, AMF_NOREPLY)) != OK)
printf("chardriver_reply_task: send to %d failed: %d\n", endpt, r);
memset(&m_reply, 0, sizeof(m_reply));
- m_reply.m_type = DEV_SEL_REPL2;
- m_reply.DEV_MINOR = minor;
- m_reply.DEV_SEL_OPS = r;
+ m_reply.m_type = CDEV_SEL2_REPLY;
+ m_reply.CDEV_MINOR = minor;
+ m_reply.CDEV_STATUS = r;
if ((r = asynsend3(endpt, &m_reply, AMF_NOREPLY)) != OK)
printf("chardriver_reply_select: send to %d failed: %d\n", endpt, r);
*/
if (r == EDONTREPLY) {
switch (mess->m_type) {
- case DEV_READ_S:
- case DEV_WRITE_S:
- case DEV_IOCTL_S:
-#if 0 /* XXX doesn't match lwip's model, disabled for now */
- if (mess->FLAGS & FLG_OP_NONBLOCK)
+ case CDEV_READ:
+ case CDEV_WRITE:
+ case CDEV_IOCTL:
+ /* FIXME: we should be able to check CDEV_FLAGS against
+ * CDEV_NONBLOCK here, but in practice, several drivers do not
+ * send a reply through this path (eg TTY) or simply do not
+ * implement nonblocking calls properly (eg audio, LWIP).
+ */
+#if 0
+ if (mess->CDEV_FLAGS & CDEV_NONBLOCK)
panic("chardriver: cannot suspend nonblocking I/O");
#endif
/*fall-through*/
- case CANCEL:
+ case CDEV_CANCEL:
return; /* alright */
default:
panic("chardriver: cannot suspend request %d", mess->m_type);
memset(&reply_mess, 0, sizeof(reply_mess));
switch (mess->m_type) {
- case DEV_OPEN:
- reply_mess.m_type = DEV_OPEN_REPL;
- reply_mess.REP_ENDPT = mess->USER_ENDPT;
- reply_mess.REP_STATUS = r;
- break;
-
- case DEV_CLOSE:
- reply_mess.m_type = DEV_CLOSE_REPL;
- reply_mess.REP_ENDPT = mess->USER_ENDPT;
- reply_mess.REP_STATUS = r;
+ case CDEV_OPEN:
+ case CDEV_CLOSE:
+ case CDEV_READ:
+ case CDEV_WRITE:
+ case CDEV_IOCTL:
+ case CDEV_CANCEL: /* For cancel, this is a reply to the original request! */
+ reply_mess.m_type = CDEV_REPLY;
+ reply_mess.CDEV_STATUS = r;
+ reply_mess.CDEV_ID = mess->CDEV_ID;
break;
- case DEV_READ_S:
- case DEV_WRITE_S:
- case DEV_IOCTL_S:
- case CANCEL: /* For CANCEL, this is a reply to the original request! */
- reply_mess.m_type = DEV_REVIVE;
- reply_mess.REP_ENDPT = mess->USER_ENDPT;
- reply_mess.REP_IO_GRANT = (cp_grant_id_t) mess->IO_GRANT;
- reply_mess.REP_STATUS = r;
- break;
-
- case DEV_SELECT:
- reply_mess.m_type = DEV_SEL_REPL1;
- reply_mess.DEV_MINOR = mess->DEVICE;
- reply_mess.DEV_SEL_OPS = r;
+ case CDEV_SELECT:
+ reply_mess.m_type = CDEV_SEL1_REPLY;
+ reply_mess.CDEV_MINOR = mess->CDEV_MINOR;
+ reply_mess.CDEV_STATUS = r;
break;
default:
return OK;
/* Call the open hook. */
- minor = m_ptr->DEVICE;
- access = m_ptr->COUNT;
- user_endpt = m_ptr->USER_ENDPT;
+ minor = m_ptr->CDEV_MINOR;
+ access = m_ptr->CDEV_ACCESS;
+ user_endpt = m_ptr->CDEV_USER;
r = cdp->cdr_open(minor, access, user_endpt);
/* If the device has been cloned, mark the new minor as open too. */
- if (r >= 0 && !is_open_dev(r)) /* XXX FIXME */
- set_open_dev(r);
+ if (r >= 0 && (r & CDEV_CLONED)) {
+ minor = r & ~(CDEV_CLONED | CDEV_CTTY);
+ if (!is_open_dev(minor))
+ set_open_dev(minor);
+ }
return r;
}
return OK;
/* Call the close hook. */
- minor = m_ptr->DEVICE;
+ minor = m_ptr->CDEV_MINOR;
return cdp->cdr_close(minor);
}
cdev_id_t id;
ssize_t r;
- minor = m_ptr->DEVICE;
- position = make64(m_ptr->POSITION, m_ptr->HIGHPOS);
+ minor = m_ptr->CDEV_MINOR;
+ position = make64(m_ptr->CDEV_POS_LO, m_ptr->CDEV_POS_HI);
endpt = m_ptr->m_source;
- grant = (cp_grant_id_t) m_ptr->IO_GRANT;
- size = m_ptr->COUNT;
- flags = m_ptr->FLAGS;
- id = (cdev_id_t) m_ptr->IO_GRANT;
+ grant = (cp_grant_id_t) m_ptr->CDEV_GRANT;
+ size = m_ptr->CDEV_COUNT;
+ flags = m_ptr->CDEV_FLAGS;
+ id = m_ptr->CDEV_ID;
/* Call the read/write hook, if the appropriate one is in place. */
if (!do_write && cdp->cdr_read != NULL)
return ENOTTY;
/* Call the ioctl hook. */
- minor = m_ptr->DEVICE;
- request = m_ptr->REQUEST;
+ minor = m_ptr->CDEV_MINOR;
+ request = m_ptr->CDEV_REQUEST;
endpt = m_ptr->m_source;
- grant = (cp_grant_id_t) m_ptr->IO_GRANT;
- flags = m_ptr->FLAGS;
- user_endpt = (endpoint_t) m_ptr->POSITION;
- id = (cdev_id_t) m_ptr->IO_GRANT;
+ grant = m_ptr->CDEV_GRANT;
+ flags = m_ptr->CDEV_FLAGS;
+ user_endpt = m_ptr->CDEV_USER;
+ id = m_ptr->CDEV_ID;
return cdp->cdr_ioctl(minor, request, endpt, grant, flags, user_endpt, id);
}
return EDONTREPLY;
/* Call the cancel hook. */
- minor = m_ptr->DEVICE;
+ minor = m_ptr->CDEV_MINOR;
endpt = m_ptr->m_source;
- id = (cdev_id_t) m_ptr->IO_GRANT;
+ id = m_ptr->CDEV_ID;
return cdp->cdr_cancel(minor, endpt, id);
}
return EBADF;
/* Call the select hook. */
- minor = m_ptr->DEV_MINOR;
- ops = m_ptr->DEV_SEL_OPS;
+ minor = m_ptr->CDEV_MINOR;
+ ops = m_ptr->CDEV_OPS;
endpt = m_ptr->m_source;
return cdp->cdr_select(minor, ops, endpt);
/* We might get spurious requests if the driver has been restarted. Deny any
* requests on devices that have not previously been opened.
*/
- if (IS_DEV_RQ(m_ptr->m_type) && !is_open_dev(m_ptr->DEVICE)) {
+ if (IS_CDEV_RQ(m_ptr->m_type) && !is_open_dev(m_ptr->CDEV_MINOR)) {
/* Ignore spurious requests for unopened devices. */
- if (m_ptr->m_type != DEV_OPEN)
+ if (m_ptr->m_type != CDEV_OPEN)
return; /* do not send a reply */
/* Mark the device as opened otherwise. */
- set_open_dev(m_ptr->DEVICE);
+ set_open_dev(m_ptr->CDEV_MINOR);
}
/* Call the appropriate function(s) for this request. */
switch (m_ptr->m_type) {
- case DEV_OPEN: r = do_open(cdp, m_ptr); break;
- case DEV_CLOSE: r = do_close(cdp, m_ptr); break;
- case DEV_READ_S: r = do_transfer(cdp, m_ptr, FALSE); break;
- case DEV_WRITE_S: r = do_transfer(cdp, m_ptr, TRUE); break;
- case DEV_IOCTL_S: r = do_ioctl(cdp, m_ptr); break;
- case CANCEL: r = do_cancel(cdp, m_ptr); break;
- case DEV_SELECT: r = do_select(cdp, m_ptr); break;
+ case CDEV_OPEN: r = do_open(cdp, m_ptr); break;
+ case CDEV_CLOSE: r = do_close(cdp, m_ptr); break;
+ case CDEV_READ: r = do_transfer(cdp, m_ptr, FALSE); break;
+ case CDEV_WRITE: r = do_transfer(cdp, m_ptr, TRUE); break;
+ case CDEV_IOCTL: r = do_ioctl(cdp, m_ptr); break;
+ case CDEV_CANCEL: r = do_cancel(cdp, m_ptr); break;
+ case CDEV_SELECT: r = do_select(cdp, m_ptr); break;
default:
if (cdp->cdr_other)
cdp->cdr_other(m_ptr, ipc_status);
static int socket_request_socket(struct socket * sock, struct sock_req * req)
{
- int r, blocking = req->flags & FLG_OP_NONBLOCK ? 0 : 1;
+ int r, blocking = (req->flags & CDEV_NONBLOCK) ? 0 : 1;
switch (req->type) {
case SOCK_REQ_READ:
static int netsock_open(devminor_t minor, int UNUSED(access),
endpoint_t UNUSED(user_endpt))
{
- return socket_open(minor);
+ int r;
+
+ if ((r = socket_open(minor)) < 0)
+ return r;
+
+ return CDEV_CLONED | r;
}
static int netsock_close(devminor_t minor)
/* in this case any operation would block, no error */
if (sock->flags & SOCK_FLG_OP_PENDING) {
- if (sel & SEL_NOTIFY) {
- if (sel & SEL_RD)
+ if (sel & CDEV_NOTIFY) {
+ if (sel & CDEV_OP_RD)
sock->flags |= SOCK_FLG_SEL_READ;
- if (sel & SEL_WR)
+ if (sel & CDEV_OP_WR)
sock->flags |= SOCK_FLG_SEL_WRITE;
/* FIXME we do not monitor error */
}
return 0;
}
- if (sel & SEL_RD) {
+ if (sel & CDEV_OP_RD) {
if (sock->recv_head)
- retsel |= SEL_RD;
- else if (sel & SEL_NOTIFY)
+ retsel |= CDEV_OP_RD;
+ else if (sel & CDEV_NOTIFY)
sock->flags |= SOCK_FLG_SEL_READ;
}
/* FIXME generic packet socket never blocks on write */
- if (sel & SEL_WR)
- retsel |= SEL_WR;
- /* FIXME SEL_ERR is ignored, we do not generate exceptions */
+ if (sel & CDEV_OP_WR)
+ retsel |= CDEV_OP_WR;
+ /* FIXME CDEV_OP_ERR is ignored, we do not generate exceptions */
return retsel;
}
}
if (sock->flags & SOCK_FLG_SEL_READ && sock->recv_head)
- sel |= SEL_RD;
+ sel |= CDEV_OP_RD;
if (sel)
sock->flags &= ~(SOCK_FLG_SEL_WRITE | SOCK_FLG_SEL_READ |
return fd;
}
sr_fd->srf_fd= fd;
- return i; /* cloned! */
+ return CDEV_CLONED | i;
}
static int sr_close(devminor_t minor)
assert(sr_fd->srf_flags & susp_flag);
assert(*q_head_ptr);
- if (m->mq_req.srr_flags & FLG_OP_NONBLOCK) {
+ if (m->mq_req.srr_flags & CDEV_NONBLOCK) {
mq_free(m);
return EAGAIN;
}
(printf("r= %d\n", r), 0));
if (r == SUSPEND) {
sr_fd->srf_flags |= susp_flag;
- if (m->mq_req.srr_flags & FLG_OP_NONBLOCK) {
+ if (m->mq_req.srr_flags & CDEV_NONBLOCK) {
r= sr_cancel(m->mq_req.srr_minor, m->mq_req.srr_endpt,
m->mq_req.srr_id);
assert(r == EDONTREPLY); /* head of the queue */
sr_fd->srf_select_proc= endpt;
i_ops= 0;
- if (ops & SEL_RD) i_ops |= SR_SELECT_READ;
- if (ops & SEL_WR) i_ops |= SR_SELECT_WRITE;
- if (ops & SEL_ERR) i_ops |= SR_SELECT_EXCEPTION;
- if (!(ops & SEL_NOTIFY)) i_ops |= SR_SELECT_POLL;
+ if (ops & CDEV_OP_RD) i_ops |= SR_SELECT_READ;
+ if (ops & CDEV_OP_WR) i_ops |= SR_SELECT_WRITE;
+ if (ops & CDEV_OP_ERR) i_ops |= SR_SELECT_EXCEPTION;
+ if (!(ops & CDEV_NOTIFY)) i_ops |= SR_SELECT_POLL;
r= (*sr_fd->srf_select)(sr_fd->srf_fd, i_ops);
if (r < 0) {
m_ops= r;
} else {
m_ops= 0;
- if (r & SR_SELECT_READ) m_ops |= SEL_RD;
- if (r & SR_SELECT_WRITE) m_ops |= SEL_WR;
- if (r & SR_SELECT_EXCEPTION) m_ops |= SEL_ERR;
+ if (r & SR_SELECT_READ) m_ops |= CDEV_OP_RD;
+ if (r & SR_SELECT_WRITE) m_ops |= CDEV_OP_WR;
+ if (r & SR_SELECT_EXCEPTION) m_ops |= CDEV_OP_ERR;
}
return m_ops;
sr_fd= &sr_fd_table[fd];
m_ops= 0;
- if (ops & SR_SELECT_READ) m_ops |= SEL_RD;
- if (ops & SR_SELECT_WRITE) m_ops |= SEL_WR;
- if (ops & SR_SELECT_EXCEPTION) m_ops |= SEL_ERR;
+ if (ops & SR_SELECT_READ) m_ops |= CDEV_OP_RD;
+ if (ops & SR_SELECT_WRITE) m_ops |= CDEV_OP_WR;
+ if (ops & SR_SELECT_EXCEPTION) m_ops |= CDEV_OP_ERR;
chardriver_reply_select(sr_fd->srf_select_proc, fd, m_ops);
}
case STYLE_DEV: return "STYLE_DEV";
case STYLE_TTY: return "STYLE_TTY";
case STYLE_CTTY: return "STYLE_CTTY";
- case STYLE_CLONE: return "STYLE_CLONE";
default: return "UNKNOWN";
}
}
/* in this case any operation would block, no error */
if (sock->flags & SOCK_FLG_OP_PENDING) {
debug_tcp_print("SOCK_FLG_OP_PENDING");
- if (sel & SEL_NOTIFY) {
- if (sel & SEL_RD) {
+ if (sel & CDEV_NOTIFY) {
+ if (sel & CDEV_OP_RD) {
sock->flags |= SOCK_FLG_SEL_READ;
debug_tcp_print("monitor read");
}
- if (sel & SEL_WR) {
+ if (sel & CDEV_OP_WR) {
sock->flags |= SOCK_FLG_SEL_WRITE;
debug_tcp_print("monitor write");
}
- if (sel & SEL_ERR)
+ if (sel & CDEV_OP_ERR)
sock->flags |= SOCK_FLG_SEL_ERROR;
}
return 0;
}
- if (sel & SEL_RD) {
+ if (sel & CDEV_OP_RD) {
/*
* If recv_head is not NULL we can either read or accept a
* connection which is the same for select()
if (sock->pcb) {
if (sock->recv_head &&
!(sock->flags & SOCK_FLG_OP_WRITING))
- retsel |= SEL_RD;
+ retsel |= CDEV_OP_RD;
else if (!(sock->flags & SOCK_FLG_OP_LISTENING) &&
((struct tcp_pcb *) sock->pcb)->state != ESTABLISHED)
- retsel |= SEL_RD;
- else if (sel & SEL_NOTIFY) {
+ retsel |= CDEV_OP_RD;
+ else if (sel & CDEV_NOTIFY) {
sock->flags |= SOCK_FLG_SEL_READ;
debug_tcp_print("monitor read");
}
- } else
- retsel |= SEL_RD; /* not connected read does not block */
+ } else /* not connected read does not block */
+ retsel |= CDEV_OP_RD;
}
- if (sel & SEL_WR) {
+ if (sel & CDEV_OP_WR) {
if (sock->pcb) {
if (((struct tcp_pcb *) sock->pcb)->state == ESTABLISHED)
- retsel |= SEL_WR;
- else if (sel & SEL_NOTIFY) {
+ retsel |= CDEV_OP_WR;
+ else if (sel & CDEV_NOTIFY) {
sock->flags |= SOCK_FLG_SEL_WRITE;
debug_tcp_print("monitor write");
}
- } else
- retsel |= SEL_WR; /* not connected write does not block */
+ } else /* not connected write does not block */
+ retsel |= CDEV_OP_WR;
}
- if (retsel & SEL_RD) {
+ if (retsel & CDEV_OP_RD) {
debug_tcp_print("read won't block");
}
- if (retsel & SEL_WR) {
+ if (retsel & CDEV_OP_WR) {
debug_tcp_print("write won't block");
}
/* we only monitor if errors will happen in the future */
- if (sel & SEL_ERR && sel & SEL_NOTIFY)
+ if (sel & CDEV_OP_ERR && sel & CDEV_NOTIFY)
sock->flags |= SOCK_FLG_SEL_ERROR;
return retsel;
(!(sock->flags & SOCK_FLG_OP_LISTENING) &&
((struct tcp_pcb *) sock->pcb)->state !=
ESTABLISHED)) {
- sel |= SEL_RD;
+ sel |= CDEV_OP_RD;
debug_tcp_print("read won't block");
}
}
(sock->pcb == NULL ||
((struct tcp_pcb *) sock->pcb)->state ==
ESTABLISHED)) {
- sel |= SEL_WR;
+ sel |= CDEV_OP_WR;
debug_tcp_print("write won't block");
}
*
* Overview
*
- * The interface to unix domain sockets is similar to the
- * the interface to network sockets. There is a character
- * device (/dev/uds) that uses STYLE_CLONE and this server
- * is a 'driver' for that device.
+ * The interface to unix domain sockets is similar to the interface to network
+ * sockets. There is a character device (/dev/uds) and this server is a
+ * 'driver' for that device.
*/
#define DEBUG 0
/* Process the response */
uds_fd_table[minor].inode_nr = fs_m_out.RES_INODE_NR;
- return minor; /* cloned! */
+ return CDEV_CLONED | minor;
}
static int uds_close(devminor_t minor)
return EINVAL;
}
- watch = (ops & SEL_NOTIFY);
- ops &= (SEL_RD | SEL_WR | SEL_ERR);
+ watch = (ops & CDEV_NOTIFY);
+ ops &= (CDEV_OP_RD | CDEV_OP_WR | CDEV_OP_ERR);
ready_ops = 0;
/* check if there is data available to read */
- if (ops & SEL_RD) {
+ if (ops & CDEV_OP_RD) {
bytes = uds_perform_read(minor, NONE, GRANT_INVALID, 1, 1);
if (bytes > 0) {
/* there is data in the pipe for us to read */
- ready_ops |= SEL_RD;
+ ready_ops |= CDEV_OP_RD;
} else if (uds_fd_table[minor].listening == 1) {
/* check for pending connections */
for (i = 0; i < uds_fd_table[minor].backlog_size; i++)
{
if (uds_fd_table[minor].backlog[i] != -1) {
- ready_ops |= SEL_RD;
+ ready_ops |= CDEV_OP_RD;
break;
}
}
} else if (bytes != SUSPEND) {
- ready_ops |= SEL_RD;
+ ready_ops |= CDEV_OP_RD;
}
}
/* check if we can write without blocking */
- if (ops & SEL_WR) {
+ if (ops & CDEV_OP_WR) {
bytes = uds_perform_write(minor, NONE, GRANT_INVALID, PIPE_BUF,
1);
if (bytes != 0 && bytes != SUSPEND) {
/* There is room to write or there is an error
* condition.
*/
- ready_ops |= SEL_WR;
+ ready_ops |= CDEV_OP_WR;
}
}
* peer to minor); if the peer wants to know about write being possible
* and it doesn't know about it already, then let the peer know.
*/
- if (peer != -1 && (uds_fd_table[peer].sel_ops & SEL_WR) &&
+ if (peer != -1 && (uds_fd_table[peer].sel_ops & CDEV_OP_WR) &&
(uds_fd_table[minor].size+uds_fd_table[minor].pos + 1 < PIPE_BUF)){
/* a write on peer is possible now */
chardriver_reply_select(uds_fd_table[peer].sel_endpt, peer,
- SEL_WR);
- uds_fd_table[peer].sel_ops &= ~SEL_WR;
+ CDEV_OP_WR);
+ uds_fd_table[peer].sel_ops &= ~CDEV_OP_WR;
}
return fs_m_out.RES_NBYTES; /* return number of bytes read */
* data ready to read and it doesn't know about it already, then let
* the peer know we have data for it.
*/
- if ((uds_fd_table[peer].sel_ops & SEL_RD) && fs_m_out.RES_NBYTES > 0) {
+ if ((uds_fd_table[peer].sel_ops & CDEV_OP_RD) &&
+ fs_m_out.RES_NBYTES > 0) {
/* a read on peer is possible now */
chardriver_reply_select(uds_fd_table[peer].sel_endpt, peer,
- SEL_RD);
- uds_fd_table[peer].sel_ops &= ~SEL_RD;
+ CDEV_OP_RD);
+ uds_fd_table[peer].sel_ops &= ~CDEV_OP_RD;
}
return fs_m_out.RES_NBYTES; /* return number of bytes written */
uds_fd_table[minor].susp_id = id;
/* If the call wasn't supposed to block, cancel immediately. */
- if (flags & FLG_OP_NONBLOCK) {
+ if (flags & CDEV_NONBLOCK) {
uds_cancel(minor, endpt, id);
rc = EAGAIN;
uds_fd_table[minor].susp_id = id;
/* If the call wasn't supposed to block, cancel immediately. */
- if (flags & FLG_OP_NONBLOCK) {
+ if (flags & CDEV_NONBLOCK) {
uds_cancel(minor, endpt, id);
rc = EAGAIN;
uds_fd_table[minor].susp_id = id;
/* If the call wasn't supposed to block, cancel immediately. */
- if (flags & FLG_OP_NONBLOCK) {
+ if (flags & CDEV_NONBLOCK) {
uds_cancel(minor, endpt, id);
rc = EAGAIN;
get_work(&pfs_m_in, &ipc_status);
/* If this is a UDS device request, process it and continue. */
- if (IS_DEV_RQ(pfs_m_in.m_type)) {
+ if (IS_CDEV_RQ(pfs_m_in.m_type)) {
uds_request(&pfs_m_in, ipc_status);
continue;
}
/* see if the server is blocked on select() */
- if (uds_fd_table[i].sel_ops & SEL_RD) {
+ if (uds_fd_table[i].sel_ops & CDEV_OP_RD) {
/* if the server wants to know about
* data ready to read and it doesn't
* doesn't know about it already, then
*/
chardriver_reply_select(
uds_fd_table[i].sel_endpt, i,
- SEL_RD);
+ CDEV_OP_RD);
- uds_fd_table[i].sel_ops &= ~SEL_RD;
+ uds_fd_table[i].sel_ops &= ~CDEV_OP_RD;
}
/* we found our server */
*/
endpoint_t sel_endpt;
- /* Options (SEL_RD, SEL_WR, SEL_ERR) that are requested. */
+ /* Options (CDEV_OP_RD,WR,ERR) that are requested. */
unsigned int sel_ops;
};
{ TTY_PROC_NR, SRV_DF, TTY_MAJOR, STYLE_TTY, STYLE_CTTY },
{ MEM_PROC_NR, SRV_DF, MEMORY_MAJOR, STYLE_DEV, STYLE_NDEV },
{ LOG_PROC_NR, SRV_DF, LOG_MAJOR, STYLE_DEV, STYLE_NDEV },
- { PFS_PROC_NR, SRV_DF, UDS_MAJOR, STYLE_CLONE,STYLE_NDEV },
+ { PFS_PROC_NR, SRV_DF, UDS_MAJOR, STYLE_DEV, STYLE_NDEV },
{ DEFAULT_BOOT_NR, SRV_DF, 0, STYLE_NDEV, STYLE_NDEV } /* default
* entry
*/
panic("driver endpoint %d invalid", drv_e);
lock_dmap(dp);
- if (dp->dmap_servicing != NONE)
+ if (dp->dmap_servicing != INVALID_THREAD)
panic("driver locking inconsistency");
dp->dmap_servicing = self->w_tid;
self->w_task = drv_e;
util_stacktrace();
}
- dp->dmap_servicing = NONE;
+ dp->dmap_servicing = INVALID_THREAD;
self->w_task = NONE;
self->w_drv_sendrec = NULL;
unlock_dmap(dp);
/* test if the process is blocked on something */
#define fp_is_blocked(fp) ((fp)->fp_blocked_on != FP_BLOCKED_ON_NONE)
-/* test if reply is a driver reply */
-#define IS_DRV_REPLY(x) (IS_DEV_RS(x) || IS_BDEV_RS(x))
-#define DUP_MASK 0100 /* mask to distinguish dup2 from dup */
-
-#define LOOK_UP 0 /* tells search_dir to lookup string */
-#define ENTER 1 /* tells search_dir to make dir entry */
-#define DELETE 2 /* tells search_dir to delete entry */
-#define IS_EMPTY 3 /* tells search_dir to ret. OK or ENOTEMPTY */
+#define INVALID_THREAD ((thread_t) -1) /* known-invalid thread ID */
#define SYMLOOP 16
*/
#define FSTYPE_MAX VFS_NAMELEN /* maximum file system type size */
+/* possible select() operation types; read, write, errors */
+#define SEL_RD CDEV_OP_RD
+#define SEL_WR CDEV_OP_WR
+#define SEL_ERR CDEV_OP_ERR
+#define SEL_NOTIFY CDEV_NOTIFY /* not a real select operation */
+
#endif
* Special character files also require I/O. The routines for these are here.
*
* The entry points in this file are:
- * dev_open: open a character device
- * dev_close: close a character device
- * cdev_reply: process the result of a character driver request
- * bdev_open: open a block device
- * bdev_close: close a block device
- * bdev_reply: process the result of a block driver request
- * dev_io: FS does a read or write on a device
- * gen_opcl: generic call to a character driver to perform an open/close
- * gen_io: generic call to a character driver to initiate I/O
- * no_dev: open/close processing for devices that don't exist
- * no_dev_io: i/o processing for devices that don't exist
- * tty_opcl: perform tty-specific processing for open/close
- * ctty_opcl: perform controlling-tty-specific processing for open/close
- * ctty_io: perform controlling-tty-specific processing for I/O
- * pm_setsid: perform VFS's side of setsid system call
- * do_ioctl: perform the IOCTL system call
- * dev_select: initiate a select call on a device
- * dev_cancel: cancel an I/O request, blocking until it has been cancelled
+ * cdev_open: open a character device
+ * cdev_close: close a character device
+ * cdev_io: initiate a read, write, or ioctl to a character device
+ * cdev_select: initiate a select call on a device
+ * cdev_cancel: cancel an I/O request, blocking until it has been cancelled
+ * cdev_reply: process the result of a character driver request
+ * bdev_open: open a block device
+ * bdev_close: close a block device
+ * bdev_reply: process the result of a block driver request
+ * bdev_up: a block driver has been mapped in
+ * gen_opcl: generic call to a character driver to perform an open/close
+ * gen_io: generic call to a character driver to initiate I/O
+ * no_dev: open/close processing for devices that don't exist
+ * no_dev_io: i/o processing for devices that don't exist
+ * tty_opcl: perform tty-specific processing for open/close
+ * ctty_opcl: perform controlling-tty-specific processing for open/close
+ * ctty_io: perform controlling-tty-specific processing for I/O
+ * pm_setsid: perform VFS's side of setsid system call
+ * do_ioctl: perform the IOCTL system call
*/
#include "fs.h"
static cp_grant_id_t make_grant(endpoint_t driver_e, endpoint_t user_e, int op,
void *buf, unsigned long size);
-static int dummyproc;
-
/*===========================================================================*
- * dev_open *
+ * cdev_open *
*===========================================================================*/
-int dev_open(
- dev_t dev, /* device to open */
- int flags /* mode bits and flags */
-)
+int cdev_open(dev_t dev, int flags)
{
/* Open a character device. */
devmajor_t major_dev;
major_dev = major(dev);
if (major_dev < 0 || major_dev >= NR_DEVICES) return(ENXIO);
if (dmap[major_dev].dmap_driver == NONE) return(ENXIO);
- r = (*dmap[major_dev].dmap_opcl)(DEV_OPEN, dev, fp->fp_endpoint, flags);
+ r = (*dmap[major_dev].dmap_opcl)(CDEV_OPEN, dev, fp->fp_endpoint, flags);
return(r);
}
/*===========================================================================*
- * dev_close *
+ * cdev_close *
*===========================================================================*/
-int dev_close(
- dev_t dev /* device to close */
-)
+int cdev_close(dev_t dev)
{
/* Close a character device. */
devmajor_t major_dev;
major_dev = major(dev);
if (major_dev < 0 || major_dev >= NR_DEVICES) return(ENXIO);
if (dmap[major_dev].dmap_driver == NONE) return(ENXIO);
- r = (*dmap[major_dev].dmap_opcl)(DEV_CLOSE, dev, fp->fp_endpoint, 0);
+ r = (*dmap[major_dev].dmap_opcl)(CDEV_CLOSE, dev, fp->fp_endpoint, 0);
return(r);
}
}
-/*===========================================================================*
- * find_suspended_ep *
- *===========================================================================*/
-static endpoint_t find_suspended_ep(endpoint_t driver, cp_grant_id_t g)
-{
-/* A process is suspended on a driver for which VFS issued a grant. Find out
- * which process it was.
- */
- struct fproc *rfp;
- for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) {
- if(rfp->fp_pid == PID_FREE)
- continue;
-
- if (rfp->fp_task == driver && rfp->fp_grant == g) {
- assert(!fp_is_blocked(rfp) ||
- rfp->fp_blocked_on == FP_BLOCKED_ON_OTHER);
- return(rfp->fp_endpoint);
- }
- }
-
- return(NONE);
-}
-
-
/*===========================================================================*
* make_grant *
*===========================================================================*/
size_t size;
switch (op) {
- case DEV_READ_S:
- case DEV_WRITE_S:
+ case CDEV_READ:
+ case CDEV_WRITE:
gid = cpf_grant_magic(driver_e, user_e, (vir_bytes) buf,
- (size_t) bytes, op == DEV_READ_S ? CPF_WRITE : CPF_READ);
+ (size_t) bytes, op == CDEV_READ ? CPF_WRITE : CPF_READ);
break;
- case DEV_IOCTL_S:
+ case CDEV_IOCTL:
case BDEV_IOCTL:
/* For IOCTLs, the bytes parameter contains the IOCTL request.
* This request encodes the requested access method and buffer size.
else
size = _MINIX_IOCTL_SIZE(bytes);
- /* Grant access to the buffer even if no I/O happens with the ioctl, in
- * order to disambiguate requests with DEV_IOCTL_S.
+ /* Grant access to the buffer even if no I/O happens with the ioctl,
+ * although now that we no longer identify responses based on grants,
+ * this is not strictly necessary.
*/
gid = cpf_grant_magic(driver_e, user_e, (vir_bytes) buf, size, access);
break;
/*===========================================================================*
- * dev_io *
+ * cdev_io *
*===========================================================================*/
-int dev_io(
- int op, /* DEV_READ_S, DEV_WRITE_S, or DEV_IOCTL_S */
+int cdev_io(
+ int op, /* CDEV_READ, CDEV_WRITE, or CDEV_IOCTL */
dev_t dev, /* major-minor device number */
endpoint_t proc_e, /* in whose address space is buf? */
void *buf, /* virtual address of the buffer */
off_t pos, /* byte position */
- size_t bytes, /* how many bytes to transfer */
+ unsigned long bytes, /* how many bytes to transfer, or request */
int flags /* special flags, like O_NONBLOCK */
)
{
-/* Initiate a read, write, or ioctl to a device. */
+/* Initiate a read, write, or ioctl to a character device. */
struct dmap *dp;
message dev_mess;
cp_grant_id_t gid;
devmajor_t major_dev;
devminor_t minor_dev;
- int r;
+ int r, slot;
- assert(op == DEV_READ_S || op == DEV_WRITE_S || op == DEV_IOCTL_S);
+ assert(op == CDEV_READ || op == CDEV_WRITE || op == CDEV_IOCTL);
/* Determine task dmap. */
major_dev = major(dev);
/* See if driver is roughly valid. */
if (dp->dmap_driver == NONE) return(ENXIO);
- if(isokendpt(dp->dmap_driver, &dummyproc) != OK) {
+ if(isokendpt(dp->dmap_driver, &slot) != OK) {
printf("VFS: dev_io: old driver for major %x (%d)\n", major_dev,
dp->dmap_driver);
return(ENXIO);
/* Set up the rest of the message that will be sent to the driver. */
memset(&dev_mess, 0, sizeof(dev_mess));
- dev_mess.m_type = op;
- dev_mess.DEVICE = minor_dev;
- if (op == DEV_IOCTL_S) {
- dev_mess.REQUEST = bytes;
- dev_mess.POSITION = proc_e;
+ dev_mess.m_type = op;
+ dev_mess.CDEV_MINOR = minor_dev;
+ if (op == CDEV_IOCTL) {
+ dev_mess.CDEV_REQUEST = bytes;
+ dev_mess.CDEV_USER = proc_e;
} else {
- dev_mess.POSITION = ex64lo(pos);
- dev_mess.COUNT = bytes;
+ dev_mess.CDEV_POS_LO = ex64lo(pos);
+ dev_mess.CDEV_POS_HI = ex64hi(pos);
+ dev_mess.CDEV_COUNT = (size_t) bytes;
}
- dev_mess.HIGHPOS = ex64hi(pos);
- dev_mess.USER_ENDPT = VFS_PROC_NR;
- dev_mess.IO_GRANT = (void *) gid;
- dev_mess.FLAGS = 0;
+ dev_mess.CDEV_ID = proc_e;
+ dev_mess.CDEV_GRANT = gid;
+ dev_mess.CDEV_FLAGS = 0;
if (flags & O_NONBLOCK)
- dev_mess.FLAGS |= FLG_OP_NONBLOCK;
+ dev_mess.CDEV_FLAGS |= CDEV_NONBLOCK;
/* Send the request to the driver. */
r = (*dp->dmap_io)(dp->dmap_driver, &dev_mess);
wait_for(dp->dmap_driver);
assert(!GRANT_VALID(fp->fp_grant));
fp->fp_grant = gid; /* revoke this when unsuspended. */
- fp->fp_ioproc = VFS_PROC_NR;
return SUSPEND;
}
r = req_newnode(PFS_PROC_NR, fp->fp_effuid, fp->fp_effgid,
ALL_MODES | I_CHAR_SPECIAL, dev, &res);
if (r != OK) {
- (void) gen_opcl(DEV_CLOSE, dev, proc_e, 0);
+ (void) gen_opcl(CDEV_CLOSE, dev, proc_e, 0);
return r;
}
/* Drop old node and use the new values */
if ((vp = get_free_vnode()) == NULL) {
req_putnode(PFS_PROC_NR, res.inode_nr, 1); /* is this right? */
- (void) gen_opcl(DEV_CLOSE, dev, proc_e, 0);
+ (void) gen_opcl(CDEV_CLOSE, dev, proc_e, 0);
return(err_code);
}
lock_vnode(vp, VNODE_OPCL);
* gen_opcl *
*===========================================================================*/
int gen_opcl(
- int op, /* operation, DEV_OPEN or DEV_CLOSE */
+ int op, /* operation, CDEV_OPEN or CDEV_CLOSE */
dev_t dev, /* device to open or close */
endpoint_t proc_e, /* process to open/close for */
int flags /* mode bits and flags */
{
/* Called from the dmap struct on opens & closes of special files.*/
devmajor_t major_dev;
- devminor_t minor_dev;
+ devminor_t minor_dev, new_minor;
struct dmap *dp;
message dev_mess;
- int r;
+ int r, r2;
/* Determine task dmap. */
major_dev = major(dev);
memset(&dev_mess, 0, sizeof(dev_mess));
dev_mess.m_type = op;
- dev_mess.DEVICE = minor_dev;
- dev_mess.USER_ENDPT = proc_e;
- dev_mess.COUNT = flags;
+ dev_mess.CDEV_MINOR = minor_dev;
+ dev_mess.CDEV_ID = proc_e;
+ if (op == CDEV_OPEN) {
+ dev_mess.CDEV_USER = proc_e;
+ dev_mess.CDEV_ACCESS = 0;
+ if (flags & R_BIT) dev_mess.CDEV_ACCESS |= CDEV_R_BIT;
+ if (flags & W_BIT) dev_mess.CDEV_ACCESS |= CDEV_W_BIT;
+ if (flags & O_NOCTTY) dev_mess.CDEV_ACCESS |= CDEV_NOCTTY;
+ }
/* Call the task. */
r = (*dp->dmap_io)(dp->dmap_driver, &dev_mess);
self->w_task = NONE;
self->w_drv_sendrec = NULL;
+ r = dev_mess.CDEV_STATUS;
+
+ /* Some devices need special processing upon open. Such a device is "cloned",
+ * i.e. on a succesful open it is replaced by a new device with a new unique
+ * minor device number. This new device number identifies a new object (such
+ * as a new network connection) that has been allocated within a task.
+ */
+ if (op == CDEV_OPEN && r >= 0) {
+ if (r & CDEV_CLONED) {
+ new_minor = r & ~(CDEV_CLONED | CDEV_CTTY);
+ r &= CDEV_CTTY;
+ if ((r2 = cdev_clone(dev, proc_e, new_minor)) < 0)
+ r = r2;
+ } else
+ r &= CDEV_CTTY;
+ /* Upon success, we now return either OK or CDEV_CTTY. */
+ }
+
/* Return the result from the driver. */
- return(dev_mess.REP_STATUS);
+ return(r);
}
/*===========================================================================*
* tty_opcl *
*===========================================================================*/
int tty_opcl(
- int op, /* operation, DEV_OPEN or DEV_CLOSE */
+ int op, /* operation, CDEV_OPEN or CDEV_CLOSE */
dev_t dev, /* device to open or close */
endpoint_t proc_e, /* process to open/close for */
int flags /* mode bits and flags */
r = gen_opcl(op, dev, proc_e, flags);
/* Did this call make the tty the controlling tty? */
- if (r == 1) {
+ if (r >= 0 && (r & CDEV_CTTY)) {
fp->fp_tty = dev;
r = OK;
}
* ctty_opcl *
*===========================================================================*/
int ctty_opcl(
- int op, /* operation, DEV_OPEN or DEV_CLOSE */
+ int op, /* operation, CDEV_OPEN or CDEV_CLOSE */
dev_t UNUSED(dev), /* device to open or close */
endpoint_t UNUSED(proc_e), /* process to open/close for */
int UNUSED(flags) /* mode bits and flags */
if (S_ISBLK(vp->v_mode))
r = bdev_ioctl(dev, who_e, ioctlrequest, argx);
else
- r = dev_io(DEV_IOCTL_S, dev, who_e, argx, 0,
- ioctlrequest, f->filp_flags);
+ r = cdev_io(CDEV_IOCTL, dev, who_e, argx, 0, ioctlrequest,
+ f->filp_flags);
}
unlock_filp(f);
/*===========================================================================*
- * dev_select *
+ * cdev_select *
*===========================================================================*/
-int dev_select(dev_t dev, int ops)
+int cdev_select(dev_t dev, int ops)
{
/* Initiate a select call on a device. Return OK iff the request was sent. */
devmajor_t major_dev;
memset(&dev_mess, 0, sizeof(dev_mess));
- dev_mess.m_type = DEV_SELECT;
- dev_mess.DEV_MINOR = minor_dev;
- dev_mess.DEV_SEL_OPS = ops;
+ dev_mess.m_type = CDEV_SELECT;
+ dev_mess.CDEV_MINOR = minor_dev;
+ dev_mess.CDEV_OPS = ops;
/* Call the task. */
return (*dp->dmap_io)(dp->dmap_driver, &dev_mess);
/*===========================================================================*
- * dev_cancel *
+ * cdev_cancel *
*===========================================================================*/
-int dev_cancel(dev_t dev)
+int cdev_cancel(dev_t dev)
{
/* Cancel an I/O request, blocking until it has been cancelled. */
devmajor_t major_dev;
memset(&dev_mess, 0, sizeof(dev_mess));
- dev_mess.m_type = CANCEL;
- dev_mess.DEVICE = minor_dev;
- dev_mess.USER_ENDPT = fp->fp_ioproc;
- dev_mess.IO_GRANT = (char *) fp->fp_grant;
-
- /* Tell driver R or W. Mode is from current call, not open. */
- /* FIXME: ioctls also pass through here! */
- dev_mess.COUNT = fp->fp_block_callnr == READ ? R_BIT : W_BIT;
+ dev_mess.m_type = CDEV_CANCEL;
+ dev_mess.CDEV_MINOR = minor_dev;
+ dev_mess.CDEV_ID = fp->fp_endpoint;
r = (*dp->dmap_io)(fp->fp_task, &dev_mess);
if (r != OK) return r; /* ctty_io returned an error? should be impossible */
fp->fp_grant = GRANT_INVALID;
}
- r = dev_mess.REP_STATUS;
+ r = dev_mess.CDEV_STATUS;
return (r == EAGAIN) ? EINTR : r;
}
if (r != OK) panic("VFS: asynsend in gen_io failed: %d", r);
- /* Fake a SUSPEND */
- mess_ptr->REP_STATUS = SUSPEND;
return(OK);
}
* major/minor pair for /dev/tty itself.
*/
struct dmap *dp;
+ int slot;
if (fp->fp_tty == 0) {
/* No controlling tty present anymore, return an I/O error. */
} else {
/* Substitute the controlling terminal device. */
dp = &dmap[major(fp->fp_tty)];
- mess_ptr->DEVICE = minor(fp->fp_tty);
+ mess_ptr->CDEV_MINOR = minor(fp->fp_tty);
if (dp->dmap_driver == NONE) {
printf("FS: ctty_io: no driver for dev\n");
return(EIO);
}
- if (isokendpt(dp->dmap_driver, &dummyproc) != OK) {
+ if (isokendpt(dp->dmap_driver, &slot) != OK) {
printf("VFS: ctty_io: old driver %d\n", dp->dmap_driver);
return(EIO);
}
* no_dev *
*===========================================================================*/
int no_dev(
- int UNUSED(op), /* operation, DEV_OPEN or DEV_CLOSE */
+ int UNUSED(op), /* operation, CDEV_OPEN or CDEV_CLOSE */
dev_t UNUSED(dev), /* device to open or close */
endpoint_t UNUSED(proc), /* process to open/close for */
int UNUSED(flags) /* mode bits and flags */
return(EIO);
}
-/*===========================================================================*
- * clone_opcl *
- *===========================================================================*/
-int clone_opcl(
- int op, /* operation, DEV_OPEN or DEV_CLOSE */
- dev_t dev, /* device to open or close */
- endpoint_t proc_e, /* process to open/close for */
- int flags /* mode bits and flags */
-)
-{
-/* Some devices need special processing upon open. Such a device is "cloned",
- * i.e. on a succesful open it is replaced by a new device with a new unique
- * minor device number. This new device number identifies a new object (such
- * as a new network connection) that has been allocated within a task.
- */
- int r;
-
- r = gen_opcl(op, dev, proc_e, flags);
-
- if (op == DEV_OPEN && r >= 0) {
- if (r != minor(dev))
- r = cdev_clone(dev, proc_e, r);
- else
- r = OK;
- }
-
- return r;
-}
-
/*===========================================================================*
* bdev_up *
/*===========================================================================*
- * opcl_reply *
+ * cdev_generic_reply *
*===========================================================================*/
-static void opcl_reply(message *m_ptr)
+static void cdev_generic_reply(message *m_ptr)
{
-/* A character driver has replied to an open or close request. This function
- * MUST NOT block its calling thread.
+/* A character driver has results for an open, close, read, write, or ioctl
+ * call (i.e., everything except select). There may be a thread waiting for
+ * these results as part of an ongoing open, close, or (for read/write/ioctl)
+ * cancel call. If so, wake up that thread; if not, send a reply to the
+ * requesting process. This function MUST NOT block its calling thread.
*/
struct fproc *rfp;
struct worker_thread *wp;
endpoint_t proc_e;
int slot;
- proc_e = m_ptr->REP_ENDPT;
- if (isokendpt(proc_e, &slot) != OK) return;
- rfp = &fproc[slot];
- wp = rfp->fp_worker;
- if (wp == NULL || wp->w_task != who_e) {
- printf("VFS: no worker thread waiting for a reply from %d\n", who_e);
+ proc_e = m_ptr->CDEV_ID;
+
+ if (m_ptr->CDEV_STATUS == SUSPEND) {
+ printf("VFS: got SUSPEND from %d, not reviving\n", m_ptr->m_source);
return;
}
- *wp->w_drv_sendrec = *m_ptr;
- worker_signal(wp); /* Continue open/close */
-}
-
-
-/*===========================================================================*
- * task_reply *
- *===========================================================================*/
-static void task_reply(message *m_ptr)
-{
-/* A character driver has results for a read, write, or ioctl call. There may
- * be a thread waiting for these results as part of an ongoing dev_cancel call.
- * If so, wake up that thread; if not, send a reply to the requesting process.
- * This function MUST NOT block its calling thread.
- */
- struct fproc *rfp;
- struct worker_thread *wp;
- endpoint_t proc_e;
- int slot;
- proc_e = m_ptr->REP_ENDPT;
- if (proc_e == VFS_PROC_NR)
- proc_e = find_suspended_ep(m_ptr->m_source, m_ptr->REP_IO_GRANT);
- else
- printf("VFS: endpoint %u from %u is not VFS\n",
- proc_e, m_ptr->m_source);
-
- if (proc_e == NONE) {
- printf("VFS: proc with grant %d from %d not found\n",
- m_ptr->REP_IO_GRANT, m_ptr->m_source);
- } else if (m_ptr->REP_STATUS == SUSPEND) {
- printf("VFS: got SUSPEND on DEV_REVIVE: not reviving proc\n");
- } else {
- /* If there is a thread active for this process, we assume that this
- * thread aims to cancel the ongoing operation. In that case, wake up
- * the thread to let it finish unpausing the process. Otherwise, revive
- * the process as usual.
+ if (isokendpt(proc_e, &slot) != OK) {
+ printf("VFS: proc %d from %d not found\n", proc_e, m_ptr->m_source);
+ return;
+ }
+ rfp = &fproc[slot];
+ wp = rfp->fp_worker;
+ if (wp != NULL && wp->w_task == who_e) {
+ assert(!fp_is_blocked(rfp));
+ *wp->w_drv_sendrec = *m_ptr;
+ worker_signal(wp); /* Continue open/close/cancel */
+ } else if (rfp->fp_blocked_on != FP_BLOCKED_ON_OTHER ||
+ rfp->fp_task != m_ptr->m_source) {
+ /* This would typically be caused by a protocol error, i.e. a driver
+ * not properly following the character driver protocol rules.
*/
- if (isokendpt(proc_e, &slot) != OK) return;
- rfp = &fproc[slot];
- wp = rfp->fp_worker;
- if (wp != NULL && wp->w_task == who_e) {
- assert(!fp_is_blocked(rfp));
- *wp->w_drv_sendrec = *m_ptr;
- worker_signal(wp); /* Continue cancel */
- } else {
- revive(proc_e, m_ptr->REP_STATUS);
- }
+ printf("VFS: proc %d not blocked on %d\n", proc_e, m_ptr->m_source);
+ } else {
+ revive(proc_e, m_ptr->CDEV_STATUS);
}
}
{
/* A character driver has results for us. */
+ if (get_dmap(who_e) == NULL) {
+ printf("VFS: ignoring char dev reply from unknown driver %d\n", who_e);
+ return;
+ }
+
switch (call_nr) {
- case DEV_OPEN_REPL:
- case DEV_CLOSE_REPL: opcl_reply(&m_in); break;
- case DEV_REVIVE: task_reply(&m_in); break;
- case DEV_SEL_REPL1:
- select_reply1(m_in.m_source, m_in.DEV_MINOR, m_in.DEV_SEL_OPS);
+ case CDEV_REPLY:
+ cdev_generic_reply(&m_in);
+ break;
+ case CDEV_SEL1_REPLY:
+ select_reply1(m_in.m_source, m_in.CDEV_MINOR, m_in.CDEV_STATUS);
break;
- case DEV_SEL_REPL2:
- select_reply2(m_in.m_source, m_in.DEV_MINOR, m_in.DEV_SEL_OPS);
+ case CDEV_SEL2_REPLY:
+ select_reply2(m_in.m_source, m_in.CDEV_MINOR, m_in.CDEV_STATUS);
break;
default:
printf("VFS: char driver %u sent unknown reply %x\n", who_e, call_nr);
/*===========================================================================*
* bdev_reply *
*===========================================================================*/
-void bdev_reply(struct dmap *dp)
+void bdev_reply(void)
{
/* A block driver has results for a call. There must be a thread waiting for
* these results - wake it up. This function MUST NOT block its calling thread.
*/
struct worker_thread *wp;
+ struct dmap *dp;
- assert(dp != NULL);
- assert(dp->dmap_servicing != NONE);
+ if ((dp = get_dmap(who_e)) == NULL) {
+ printf("VFS: ignoring block dev reply from unknown driver %d\n",
+ who_e);
+ return;
+ }
+
+ if (dp->dmap_servicing == INVALID_THREAD) {
+ printf("VFS: ignoring spurious block dev reply from %d\n", who_e);
+ return;
+ }
wp = worker_get(dp->dmap_servicing);
if (wp == NULL || wp->w_task != who_e) {
dp->dmap_opcl = ctty_opcl;
dp->dmap_io = ctty_io;
break;
- case STYLE_CLONE:
- dp->dmap_opcl = clone_opcl;
- dp->dmap_io = gen_io;
break;
default:
return(EINVAL);
dmap[i].dmap_io = no_dev_io;
dmap[i].dmap_driver = NONE;
dmap[i].dmap_style = STYLE_NDEV;
- dmap[i].dmap_servicing = NONE;
+ dmap[i].dmap_servicing = INVALID_THREAD;
}
}
if (dp->dmap_recovering) {
printf("VFS: driver recovery failure for"
" major %d\n", major);
- if (dp->dmap_servicing != NONE) {
+ if (dp->dmap_servicing != INVALID_THREAD) {
worker = worker_get(dp->dmap_servicing);
worker_stop(worker);
}
bdev_up(major);
dp->dmap_recovering = 0;
} else {
- if (dp->dmap_servicing != NONE) {
+ if (dp->dmap_servicing != INVALID_THREAD) {
worker = worker_get(dp->dmap_servicing);
worker_stop(worker);
}
int dmap_style;
int dmap_sel_busy;
struct filp *dmap_sel_filp;
- endpoint_t dmap_servicing;
+ thread_t dmap_servicing;
mutex_t dmap_lock;
mutex_t *dmap_lock_ref;
int dmap_recovering;
(void) bdev_close(dev); /* Ignore errors */
} else {
- (void) dev_close(dev); /* Ignore errors */
+ (void) cdev_close(dev); /* Ignore errors */
}
f->filp_mode = FILP_CLOSED;
int fp_block_callnr; /* blocked call if rd/wr can't finish */
int fp_cum_io_partial; /* partial byte count if rd/wr can't finish */
endpoint_t fp_task; /* which task is proc suspended on */
- endpoint_t fp_ioproc; /* proc no. in suspended-on i/o message */
-
cp_grant_id_t fp_grant; /* revoke this grant on unsuspend if > -1 */
uid_t fp_realuid; /* real user id */
continue;
}
- /* At this point we either have results from an asynchronous device
- * or a new system call. In both cases a new worker thread has to be
- * started and there might not be one available from the pool. This is
- * not a problem (requests/replies are simply queued), except when
- * they're from an FS endpoint, because these can cause a deadlock.
- * handle_work() takes care of the details. */
- if (IS_DRV_REPLY(call_nr)) {
- /* We've got results for a device request */
-
- struct dmap *dp;
-
- dp = get_dmap(who_e);
- if (dp != NULL) {
- if (!IS_BDEV_RS(call_nr)) {
- cdev_reply();
-
- } else {
- if (dp->dmap_servicing == NONE) {
- printf("Got spurious dev reply from %d",
- who_e);
- } else {
- bdev_reply(dp);
- }
- }
- continue;
- }
- printf("VFS: ignoring dev reply from unknown driver %d\n",
- who_e);
+ if (IS_BDEV_RS(call_nr)) {
+ /* We've got results for a block device request. */
+ bdev_reply();
+ } else if (IS_CDEV_RS(call_nr)) {
+ /* We've got results for a character device request. */
+ cdev_reply();
} else {
- /* Normal syscall. */
+ /* Normal syscall. This spawns a new thread. */
handle_work(do_work);
}
}
if (!S_ISCHR(vp->v_mode)) continue;
if ((dev_t) vp->v_sdev != dev) continue;
lock_filp(rfilp, VNODE_READ);
- (void) dev_close(dev); /* Ignore any errors. */
+ (void) cdev_close(dev); /* Ignore any errors. */
rfilp->filp_mode = FILP_CLOSED;
unlock_filp(rfilp);
/* Invoke the driver for special processing. */
dev = (dev_t) vp->v_sdev;
/* TTY needs to know about the O_NOCTTY flag. */
- r = dev_open(dev, bits | (oflags & O_NOCTTY));
+ r = cdev_open(dev, bits | (oflags & O_NOCTTY));
vp = filp->filp_vno; /* Might be updated by
- * dev_open/clone_opcl */
+ * cdev_open after cloning */
break;
case S_IFBLK:
blocked_on = fp->fp_blocked_on;
/* Clear the block status now. The procedure below might make blocking calls
- * and it is imperative that while at least dev_cancel() is executing, other
+ * and it is imperative that while at least cdev_cancel() is executing, other
* parts of VFS do not perceive this process as blocked on something.
*/
fp->fp_blocked_on = FP_BLOCKED_ON_NONE;
}
dev = (dev_t) f->filp_vno->v_sdev; /* device hung on */
- status = dev_cancel(dev);
+ status = cdev_cancel(dev);
break;
default :
void send_work(void);
/* device.c */
-int dev_open(dev_t dev, int flags);
-int dev_close(dev_t dev);
+int cdev_open(dev_t dev, int flags);
+int cdev_close(dev_t dev);
+int cdev_io(int op, dev_t dev, endpoint_t proc_e, void *buf, off_t pos,
+ unsigned long bytes, int flags);
+int cdev_select(dev_t dev, int ops);
+int cdev_cancel(dev_t dev);
void cdev_reply(void);
int bdev_open(dev_t dev, int access);
int bdev_close(dev_t dev);
-void bdev_reply(struct dmap *dp);
-int dev_io(int op, dev_t dev, endpoint_t proc_e, void *buf, off_t pos,
- size_t bytes, int flags);
+void bdev_reply(void);
+void bdev_up(int major);
int gen_opcl(int op, dev_t dev, endpoint_t task_nr, int flags);
int gen_io(endpoint_t drv_e, message *mess_ptr);
int no_dev(int op, dev_t dev, endpoint_t proc, int flags);
int clone_opcl(int op, dev_t dev, endpoint_t proc, int flags);
int ctty_io(endpoint_t task_nr, message *mess_ptr);
int do_ioctl(message *m_out);
-int dev_select(dev_t dev, int ops);
-int dev_cancel(dev_t dev);
void pm_setsid(endpoint_t proc_e);
-void bdev_up(int major);
/* dmap.c */
void lock_dmap(struct dmap *dp);
off_t position, res_pos;
unsigned int cum_io, cum_io_incr, res_cum_io;
int op, r;
+ dev_t dev;
position = f->filp_pos;
vp = f->filp_vno;
if (size > SSIZE_MAX) return(EINVAL);
- op = (rw_flag == READING ? DEV_READ_S : DEV_WRITE_S);
+ op = (rw_flag == READING ? CDEV_READ : CDEV_WRITE);
if (S_ISFIFO(vp->v_mode)) { /* Pipes */
if (rfp->fp_cum_io_partial != 0) {
}
r = rw_pipe(rw_flag, for_e, f, buf, size);
} else if (S_ISCHR(vp->v_mode)) { /* Character special files. */
- dev_t dev;
- int op = (rw_flag == READING ? DEV_READ_S : DEV_WRITE_S);
-
if(rw_flag == PEEKING) {
printf("read_write: peek on char device makes no sense\n");
return EINVAL;
dev = (dev_t) vp->v_sdev;
- r = dev_io(op, dev, for_e, buf, position, size, f->filp_flags);
+ r = cdev_io(op, dev, for_e, buf, position, size, f->filp_flags);
if (r >= 0) {
/* This should no longer happen: all calls are asynchronous. */
printf("VFS: I/O to device %x succeeded immediately!?\n", dev);
return(SUSPEND);
f->filp_select_flags &= ~FSF_UPDATE;
- r = dev_select(f->filp_vno->v_sdev, rops);
+ r = cdev_select(f->filp_vno->v_sdev, rops);
if (r != OK)
return(r);
if (se->requestor == NULL) return;
if (se->expiry <= 0) return; /* Strange, did we even ask for a timeout? */
se->expiry = 0;
- if (is_deferred(se)) return; /* Wait for initial replies to DEV_SELECT */
+ if (is_deferred(se)) return; /* Wait for initial replies to CDEV_SELECT */
select_return(se);
}
int minor;
int status;
{
-/* Handle the initial reply to DEV_SELECT request. This function MUST NOT
+/* Handle the initial reply to CDEV_SELECT request. This function MUST NOT
* block its calling thread.
*/
int major;
/* Get filp belonging to character special file */
if (!dp->dmap_sel_busy) {
- printf("VFS (%s:%d): major %d was not expecting a DEV_SELECT reply\n",
+ printf("VFS (%s:%d): major %d was not expecting a CDEV_SELECT reply\n",
__FILE__, __LINE__, major);
return;
}
__END_DECLS
#endif /* _KERNEL */
-#if defined(__minix) && defined(_NETBSD_SOURCE)
-/* possible select() operation types; read, write, errors */
-/* (FS/driver internal use only) */
-#define SEL_RD (1 << 0)
-#define SEL_WR (1 << 1)
-#define SEL_ERR (1 << 2)
-#define SEL_NOTIFY (1 << 3) /* not a real select operation */
-#endif /* defined(__minix) && defined(_NETBSD_SOURCE) */
-
#endif /* !_SYS_SELECT_H_ */