static int measure(int32_t * temperature, int32_t * pressure);
/* libchardriver callbacks */
-static struct device *bmp085_prepare(dev_t UNUSED(dev));
-static int bmp085_transfer(endpoint_t endpt, int opcode, u64_t position,
- iovec_t * iov, unsigned nr_req, endpoint_t UNUSED(user_endpt),
- unsigned int UNUSED(flags));
-static int bmp085_other(message * m);
+static ssize_t bmp085_read(devminor_t minor, u64_t position, endpoint_t endpt,
+ cp_grant_id_t grant, size_t size, int flags, cdev_id_t id);
+static void bmp085_other(message * m, int ipc_status);
/* SEF Function */
static int sef_cb_lu_state_save(int);
/* Entry points to this driver from libchardriver. */
static struct chardriver bmp085_tab = {
- .cdr_open = do_nop,
- .cdr_close = do_nop,
- .cdr_ioctl = nop_ioctl,
- .cdr_prepare = bmp085_prepare,
- .cdr_transfer = bmp085_transfer,
- .cdr_cleanup = nop_cleanup,
- .cdr_alarm = nop_alarm,
- .cdr_cancel = nop_cancel,
- .cdr_select = nop_select,
- .cdr_other = bmp085_other
-};
-
-static struct device bmp085_device = {
- .dv_base = 0,
- .dv_size = 0
+ .cdr_read = bmp085_read,
+ .cdr_other = bmp085_other
};
/*
return OK;
}
-static struct device *
-bmp085_prepare(dev_t UNUSED(dev))
-{
- return &bmp085_device;
-}
-
-static int
-bmp085_transfer(endpoint_t endpt, int opcode, u64_t position,
- iovec_t * iov, unsigned nr_req, endpoint_t UNUSED(user_endpt),
- unsigned int UNUSED(flags))
+static ssize_t
+bmp085_read(devminor_t UNUSED(minor), u64_t position, endpoint_t endpt,
+ cp_grant_id_t grant, size_t size, int UNUSED(flags), cdev_id_t UNUSED(id))
{
- int bytes, r;
+ u64_t dev_size;
+ int r;
uint32_t temperature, pressure;
r = measure(&temperature, &pressure);
log_trace(&log, "%s", buffer);
- bytes = strlen(buffer) - position < iov->iov_size ?
- strlen(buffer) - position : iov->iov_size;
-
- if (bytes <= 0) {
- return OK;
- }
+ dev_size = (u64_t)strlen(buffer);
+ if (position >= dev_size) return 0;
+ if (position + size > dev_size)
+ size = (size_t)(dev_size - position);
- switch (opcode) {
- case DEV_GATHER_S:
- r = sys_safecopyto(endpt, (cp_grant_id_t) iov->iov_addr, 0,
- (vir_bytes) (buffer + position), bytes);
- iov->iov_size -= bytes;
- break;
- default:
- return EINVAL;
- }
+ r = sys_safecopyto(endpt, grant, 0,
+ (vir_bytes)(buffer + (size_t)position), size);
- return r;
+ return (r != OK) ? r : size;
}
-static int
-bmp085_other(message * m)
+static void
+bmp085_other(message * m, int ipc_status)
{
int r;
- switch (m->m_type) {
- case NOTIFY_MESSAGE:
+ if (is_ipc_notify(ipc_status)) {
if (m->m_source == DS_PROC_NR) {
log_debug(&log,
"bus driver changed state, update endpoint\n");
i2cdriver_handle_bus_update(&bus_endpoint, bus,
address);
}
- r = OK;
- break;
- default:
- log_warn(&log, "Invalid message type (0x%x)\n", m->m_type);
- r = EINVAL;
- break;
+ return;
}
- return r;
+ log_warn(&log, "Invalid message type (0x%x)\n", m->m_type);
}
static int
}
int
-arch_fb_init(int minor, struct device *dev, struct edid_info *info)
+arch_fb_init(int minor, struct edid_info *info)
{
int r;
u32_t rdispc;
const struct panel_config *panel_cfg = &omap_cfg[minor];
- assert(dev != NULL);
if (minor != 0) return ENXIO; /* We support only one minor */
-
if (initialized) {
- dev->dv_base = fb_vir;
- dev->dv_size = fb_size;
return OK;
} else if (info != NULL) {
log_debug(&log, "Configuring Settings based on EDID...\n");
if (fb_vir == (vir_bytes) MAP_FAILED) {
panic("Unable to allocate contiguous memory\n");
}
- dev->dv_base = fb_vir;
- dev->dv_size = fb_size;
/* Configure buffer settings and turn on LCD/Digital */
arch_configure_display(minor);
/*
* Function prototypes for the fb driver.
*/
-static int fb_open(message *m);
-static int fb_close(message *m);
-static struct device * fb_prepare(dev_t device);
-static int fb_transfer(endpoint_t endpt, int opcode, u64_t position,
- iovec_t *iov, unsigned int nr_req, endpoint_t user_endpt, unsigned int
- flags);
-static int fb_do_read(endpoint_t ep, iovec_t *iov, int minor, u64_t pos,
- size_t *io_bytes);
-static int fb_do_write(endpoint_t ep, iovec_t *iov, int minor, u64_t pos,
- size_t *io_bytes);
-static int fb_ioctl(message *m);
+static int fb_open(devminor_t minor, int access, endpoint_t user_endpt);
+static int fb_close(devminor_t minor);
+static ssize_t fb_read(devminor_t minor, u64_t pos, endpoint_t ep,
+ cp_grant_id_t gid, size_t size, int flags, cdev_id_t id);
+static ssize_t fb_write(devminor_t minor, u64_t pos, endpoint_t ep,
+ cp_grant_id_t gid, size_t size, int flags, cdev_id_t id);
+static int fb_ioctl(devminor_t minor, unsigned long request, endpoint_t ep,
+ cp_grant_id_t gid, int flags, endpoint_t user_ep, cdev_id_t id);
static void paint_bootlogo(int minor);
static void paint_restartlogo(int minor);
static void paint_centered(int minor, char *data, int width, int height);
/* Entry points to the fb driver. */
static struct chardriver fb_tab =
{
- fb_open,
- fb_close,
- fb_ioctl,
- fb_prepare,
- fb_transfer,
- nop_cleanup,
- nop_alarm,
- nop_cancel,
- nop_select,
- NULL
+ .cdr_open = fb_open,
+ .cdr_close = fb_close,
+ .cdr_read = fb_read,
+ .cdr_write = fb_write,
+ .cdr_ioctl = fb_ioctl
};
/** Represents the /dev/fb device. */
-static struct device fb_device[FB_DEV_NR];
-static int fb_minor, has_restarted = 0;
+static int has_restarted = 0;
static u64_t has_restarted_t1, has_restarted_t2;
static int open_counter[FB_DEV_NR]; /* Open count */
static int
-fb_open(message *m)
+fb_open(devminor_t minor, int UNUSED(access), endpoint_t UNUSED(user_endpt))
{
int r;
static int initialized = 0;
static struct edid_info info;
static struct edid_info *infop = NULL;
- if (m->DEVICE < 0 || m->DEVICE >= FB_DEV_NR) return ENXIO;
+ if (minor < 0 || minor >= FB_DEV_NR) return ENXIO;
if (!initialized) {
- r = fb_edid_read(m->DEVICE, &info);
+ r = fb_edid_read(minor, &info);
infop = (r == 0) ? &info : NULL;
}
- if (arch_fb_init(m->DEVICE, &fb_device[m->DEVICE], infop) == OK) {
- open_counter[m->DEVICE]++;
+ if (arch_fb_init(minor, infop) == OK) {
+ open_counter[minor]++;
if (!initialized) {
if (has_restarted) {
read_frclock_64(&has_restarted_t1);
- paint_restartlogo(m->DEVICE);
+ paint_restartlogo(minor);
} else {
- paint_bootlogo(m->DEVICE);
+ paint_bootlogo(minor);
}
initialized = 1;
}
return OK;
}
- return ENXIO ;
+ return ENXIO;
}
static int
-fb_close(message *m)
+fb_close(devminor_t minor)
{
- if (m->DEVICE < 0 || m->DEVICE >= FB_DEV_NR) return ENXIO;
- assert(open_counter[m->DEVICE] > 0);
- open_counter[m->DEVICE]--;
+ if (minor < 0 || minor >= FB_DEV_NR) return ENXIO;
+ assert(open_counter[minor] > 0);
+ open_counter[minor]--;
return OK;
}
-static struct device *
-fb_prepare(dev_t dev)
-{
- if (dev < 0 || dev >= FB_DEV_NR) return NULL;
- assert(open_counter[dev] > 0);
- fb_minor = dev;
- return &fb_device[dev];
-}
-
-static int
-fb_transfer(endpoint_t endpt, int opcode, u64_t position,
- iovec_t *iov, unsigned nr_req, endpoint_t UNUSED(user_endpt),
- unsigned int UNUSED(flags))
-{
- size_t io_bytes = 0, ret;
-
- if (nr_req != 1) {
- /* This should never trigger for char drivers at the moment. */
- printf("fb: vectored transfer, using first element only\n");
- }
-
- switch (opcode) {
- case DEV_GATHER_S:
- /* Userland read operation */
- ret = fb_do_read(endpt, iov, fb_minor, position, &io_bytes);
- iov->iov_size -= io_bytes;
- break;
- case DEV_SCATTER_S:
- /* Userland write operation */
- ret = fb_do_write(endpt, iov, fb_minor, position, &io_bytes);
- iov->iov_size -= io_bytes;
- break;
- default:
- return EINVAL;
- }
- return ret;
-}
-
-static int
-fb_do_read(endpoint_t ep, iovec_t *iov, int minor, u64_t pos, size_t *io_bytes)
+static ssize_t
+fb_read(devminor_t minor, u64_t pos, endpoint_t ep, cp_grant_id_t gid,
+ size_t size, int UNUSED(flags), cdev_id_t UNUSED(id))
{
struct device dev;
+ int r;
- arch_get_device(minor, &dev);
+ if (minor < 0 || minor >= FB_DEV_NR) return ENXIO;
+ assert(open_counter[minor] > 0);
- if (pos >= dev.dv_size) return EINVAL;
+ arch_get_device(minor, &dev);
- if (dev.dv_size - pos < iov->iov_size) {
- *io_bytes = dev.dv_size - pos;
- } else {
- *io_bytes = iov->iov_size;
- }
+ if (size == 0 || pos >= dev.dv_size) return 0;
+ if (pos + size > dev.dv_size)
+ size = (size_t)(dev.dv_size - pos);
- if (*io_bytes <= 0) {
- return OK;
- }
+ r = sys_safecopyto(ep, gid, 0, (vir_bytes)(dev.dv_base + (size_t)pos),
+ size);
- return sys_safecopyto(ep, (cp_grant_id_t) iov->iov_addr, 0,
- (vir_bytes) (dev.dv_base + ex64lo(pos)),
- *io_bytes);
+ return (r != OK) ? r : size;
}
static int
-fb_ioctl(message *m)
+fb_ioctl(devminor_t minor, unsigned long request, endpoint_t ep,
+ cp_grant_id_t gid, int UNUSED(flags), endpoint_t UNUSED(user_ep),
+ cdev_id_t UNUSED(id))
{
/* Process I/O control requests */
- endpoint_t ep;
- cp_grant_id_t gid;
- int minor;
- unsigned int request;
int r;
- minor = m->DEVICE;
- request = m->COUNT;
- ep = (endpoint_t) m->USER_ENDPT;
- gid = (cp_grant_id_t) m->IO_GRANT;
-
- if (minor != 0) return EINVAL;
+ if (minor < 0 || minor >= FB_DEV_NR) return ENXIO;
switch(request) {
case FBIOGET_VSCREENINFO:
return r;
}
- return EINVAL;
+ return ENOTTY;
}
static int
return r;
}
-static int
-fb_do_write(endpoint_t ep, iovec_t *iov, int minor, u64_t pos, size_t *io_bytes)
+static ssize_t
+fb_write(devminor_t minor, u64_t pos, endpoint_t ep, cp_grant_id_t gid,
+ size_t size, int UNUSED(flags), cdev_id_t UNUSED(id))
{
struct device dev;
+ int r;
- arch_get_device(minor, &dev);
+ if (minor < 0 || minor >= FB_DEV_NR) return ENXIO;
+ assert(open_counter[minor] > 0);
- if (pos >= dev.dv_size) {
- return EINVAL;
- }
+ if (has_restarted && keep_displaying_restarted())
+ return EAGAIN;
- if (dev.dv_size - pos < iov->iov_size) {
- *io_bytes = dev.dv_size - pos;
- } else {
- *io_bytes = iov->iov_size;
- }
+ arch_get_device(minor, &dev);
- if (*io_bytes <= 0) {
- return OK;
- }
+ if (size == 0 || pos >= dev.dv_size) return 0;
+ if (pos + size > dev.dv_size)
+ size = (size_t)(dev.dv_size - pos);
- if (has_restarted && keep_displaying_restarted()) {
- return EAGAIN;
- }
+ r = sys_safecopyfrom(ep, gid, 0,
+ (vir_bytes)(dev.dv_base + (size_t)pos), size);
- return sys_safecopyfrom(ep, (cp_grant_id_t) iov->iov_addr, 0,
- (vir_bytes) (dev.dv_base + ex64lo(pos)),
- *io_bytes);
+ return (r != OK) ? r : size;
}
static int
#include <minix/fb.h>
-int arch_fb_init(int minor, struct device *dev, struct edid_info *info);
+int arch_fb_init(int minor, struct edid_info *info);
int arch_get_device(int minor, struct device *dev);
int arch_get_varscreeninfo(int minor, struct fb_var_screeninfo *fbvsp);
int arch_put_varscreeninfo(int minor, struct fb_var_screeninfo *fbvs_copy);
/*
* Function prototypes for the hello driver.
*/
-static int hello_open(message *m);
-static int hello_close(message *m);
-static struct device * hello_prepare(dev_t device);
-static int hello_transfer(endpoint_t endpt, int opcode, u64_t position,
- iovec_t *iov, unsigned int nr_req, endpoint_t user_endpt, unsigned int
- flags);
+static int hello_open(devminor_t minor, int access, endpoint_t user_endpt);
+static int hello_close(devminor_t minor);
+static ssize_t hello_read(devminor_t minor, u64_t position, endpoint_t endpt,
+ cp_grant_id_t grant, size_t size, int flags, cdev_id_t id);
/* SEF functions and variables. */
static void sef_local_startup(void);
/* Entry points to the hello driver. */
static struct chardriver hello_tab =
{
- hello_open,
- hello_close,
- nop_ioctl,
- hello_prepare,
- hello_transfer,
- nop_cleanup,
- nop_alarm,
- nop_cancel,
- nop_select,
- NULL
+ .cdr_open = hello_open,
+ .cdr_close = hello_close,
+ .cdr_read = hello_read,
};
-/** Represents the /dev/hello device. */
-static struct device hello_device;
-
-/** State variable to count the number of times the device has been opened. */
+/** State variable to count the number of times the device has been opened.
+ * Note that this is not the regular type of open counter: it never decreases.
+ */
static int open_counter;
-static int hello_open(message *UNUSED(m))
+static int hello_open(devminor_t UNUSED(minor), int UNUSED(access),
+ endpoint_t UNUSED(user_endpt))
{
printf("hello_open(). Called %d time(s).\n", ++open_counter);
return OK;
}
-static int hello_close(message *UNUSED(m))
+static int hello_close(devminor_t UNUSED(minor))
{
printf("hello_close()\n");
return OK;
}
-static struct device * hello_prepare(dev_t UNUSED(dev))
+static ssize_t hello_read(devminor_t UNUSED(minor), u64_t position,
+ endpoint_t endpt, cp_grant_id_t grant, size_t size, int UNUSED(flags),
+ cdev_id_t UNUSED(id))
{
- hello_device.dv_base = make64(0, 0);
- hello_device.dv_size = make64(strlen(HELLO_MESSAGE), 0);
- return &hello_device;
-}
+ u64_t dev_size;
+ char *ptr;
+ int ret;
-static int hello_transfer(endpoint_t endpt, int opcode, u64_t position,
- iovec_t *iov, unsigned nr_req, endpoint_t UNUSED(user_endpt),
- unsigned int UNUSED(flags))
-{
- int bytes, ret;
+ printf("hello_read()\n");
- printf("hello_transfer()\n");
+ /* This is the total size of our device. */
+ dev_size = (u64_t) strlen(HELLO_MESSAGE);
- if (nr_req != 1)
- {
- /* This should never trigger for character drivers at the moment. */
- printf("HELLO: vectored transfer request, using first element only\n");
- }
+ /* Check for EOF, and possibly limit the read size. */
+ if (position >= dev_size) return 0; /* EOF */
+ if (position + size > dev_size)
+ size = (size_t)(dev_size - position); /* limit size */
- bytes = strlen(HELLO_MESSAGE) - ex64lo(position) < iov->iov_size ?
- strlen(HELLO_MESSAGE) - ex64lo(position) : iov->iov_size;
+ /* Copy the requested part to the caller. */
+ ptr = HELLO_MESSAGE + (size_t)position;
+ if ((ret = sys_safecopyto(endpt, grant, 0, (vir_bytes) ptr, size)) != OK)
+ return ret;
- if (bytes <= 0)
- {
- return OK;
- }
- switch (opcode)
- {
- case DEV_GATHER_S:
- ret = sys_safecopyto(endpt, (cp_grant_id_t) iov->iov_addr, 0,
- (vir_bytes) (HELLO_MESSAGE + ex64lo(position)),
- bytes);
- iov->iov_size -= bytes;
- break;
-
- default:
- return EINVAL;
- }
- return ret;
+ /* Return the number of bytes read. */
+ return size;
}
static int sef_cb_lu_state_save(int UNUSED(state)) {
static int env_parse_instance(void);
/* libchardriver callbacks */
-int i2c_ioctl(message * m);
-struct device *i2c_prepare(dev_t dev);
-int i2c_transfer(endpoint_t endpt, int opcode, u64_t position,
- iovec_t * iov, unsigned nr_req, endpoint_t user_endpt, unsigned int flags);
-int i2c_other(message * m);
+static int i2c_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt,
+ cp_grant_id_t grant, int flags, endpoint_t user_endpt, cdev_id_t id);
+static void i2c_other(message * m, int ipc_status);
/* SEF callbacks and driver state management */
static int sef_cb_lu_state_save(int);
*/
int (*process) (minix_i2c_ioctl_exec_t * ioctl_exec);
-struct device i2c_device;
-
/* logging - use with log_warn(), log_info(), log_debug(), log_trace() */
static struct log log = {
.name = "i2c",
* Only i2c_ioctl() and i2c_other() are implemented. The rest are no-op.
*/
static struct chardriver i2c_tab = {
- .cdr_open = do_nop,
- .cdr_close = do_nop,
- .cdr_ioctl = i2c_ioctl,
- .cdr_prepare = i2c_prepare,
- .cdr_transfer = i2c_transfer,
- .cdr_cleanup = nop_cleanup,
- .cdr_alarm = nop_alarm,
- .cdr_cancel = nop_cancel,
- .cdr_select = nop_select,
- .cdr_other = i2c_other
+ .cdr_ioctl = i2c_ioctl,
+ .cdr_other = i2c_other
};
/*
}
len = ioctl_exec->iie_cmdlen;
- if (len < 0 || len > I2C_EXEC_MAX_CMDLEN) {
+ if (len > I2C_EXEC_MAX_CMDLEN) {
log_warn(&log,
"iie_cmdlen out of range 0-I2C_EXEC_MAX_CMDLEN\n");
return EINVAL;
}
len = ioctl_exec->iie_buflen;
- if (len < 0 || len > I2C_EXEC_MAX_BUFLEN) {
+ if (len > I2C_EXEC_MAX_BUFLEN) {
log_warn(&log,
"iie_buflen out of range 0-I2C_EXEC_MAX_BUFLEN\n");
return EINVAL;
return OK;
}
-int
-i2c_ioctl(message * m)
+static int
+i2c_ioctl(devminor_t UNUSED(minor), unsigned long request, endpoint_t endpt,
+ cp_grant_id_t grant, int UNUSED(flags), endpoint_t UNUSED(user_endpt),
+ cdev_id_t UNUSED(id))
{
int r;
- switch (m->COUNT) {
+ switch (request) {
case MINIX_I2C_IOCTL_EXEC:
- r = do_i2c_ioctl_exec(m->m_source, (cp_grant_id_t)m->IO_GRANT);
+ r = do_i2c_ioctl_exec(endpt, grant);
break;
default:
- log_warn(&log, "Invalid ioctl() 0x%x\n", m->COUNT);
- r = EINVAL;
+ log_warn(&log, "Invalid ioctl() 0x%x\n", request);
+ r = ENOTTY;
break;
}
return r;
}
-int
-i2c_other(message * m)
+static void
+i2c_other(message * m, int ipc_status)
{
message m_reply;
int r;
+ if (is_ipc_notify(ipc_status)) {
+ /* handle notifications about drivers changing state */
+ if (m->m_source == DS_PROC_NR) {
+ ds_event();
+ }
+ return;
+ }
+
switch (m->m_type) {
case BUSC_I2C_RESERVE:
/* reserve a device on the bus for exclusive access */
/* handle request from another driver */
r = do_i2c_ioctl_exec(m->m_source, m->BUSC_I2C_GRANT);
break;
- case NOTIFY_MESSAGE:
- /* handle notifications about drivers changing state */
- if (m->m_source == DS_PROC_NR) {
- ds_event();
- }
- return EDONTREPLY;
default:
log_warn(&log, "Invalid message type (0x%x)\n", m->m_type);
r = EINVAL;
log_trace(&log, "i2c_other() returning r=%d\n", r);
- /* We cannot use libchardriver to reply, as it will send DEV_REVIVE. */
+ /* Send a reply. */
memset(&m_reply, 0, sizeof(m_reply));
m_reply.m_type = r;
if ((r = send(m->m_source, &m_reply)) != OK)
log_warn(&log, "send() to %d failed: %d\n", m->m_source, r);
-
- return EDONTREPLY;
-}
-
-struct device *
-i2c_prepare(dev_t dev)
-{
- /* NOP */
- i2c_device.dv_base = make64(0, 0);
- i2c_device.dv_size = make64(0, 0);
-
- return &i2c_device;
-}
-
-int
-i2c_transfer(endpoint_t endpt, int opcode, u64_t position,
- iovec_t * iov, unsigned nr_req, endpoint_t user_endpt, unsigned int flags)
-{
- /* NOP */
- return OK;
}
/*
#define LOGINC(n, i) do { (n) = (((n) + (i)) % LOG_SIZE); } while(0)
struct logdevice logdevices[NR_DEVS];
-static struct device log_geom[NR_DEVS]; /* base and size of devices */
-static int log_device = -1; /* current device */
-
-static struct device *log_prepare(dev_t device);
-static int log_transfer(endpoint_t endpt, int opcode, u64_t position,
- iovec_t *iov, unsigned int nr_req, endpoint_t user_endpt, unsigned int
- flags);
-static int log_do_open(message *m_ptr);
-static int log_cancel(message *m_ptr);
-static int log_select(message *m_ptr);
-static int subread(struct logdevice *log, int count, endpoint_t endpt,
- cp_grant_id_t grant, size_t);
+
+static ssize_t log_read(devminor_t minor, u64_t position, endpoint_t endpt,
+ cp_grant_id_t grant, size_t size, int flags, cdev_id_t id);
+static ssize_t log_write(devminor_t minor, u64_t position, endpoint_t endpt,
+ cp_grant_id_t grant, size_t size, int flags, cdev_id_t id);
+static int log_open(devminor_t minor, int access, endpoint_t user_endpt);
+static int log_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id);
+static int log_select(devminor_t minor, unsigned int ops, endpoint_t endpt);
+static int subread(struct logdevice *log, size_t size, endpoint_t endpt,
+ cp_grant_id_t grant);
/* Entry points to this driver. */
static struct chardriver log_dtab = {
- log_do_open, /* open or mount */
- do_nop, /* nothing on a close */
- nop_ioctl, /* ioctl nop */
- log_prepare, /* prepare for I/O on a given minor device */
- log_transfer, /* do the I/O */
- nop_cleanup, /* no need to clean up */
- nop_alarm, /* no alarm */
- log_cancel, /* CANCEL request */
- log_select, /* DEV_SELECT request */
- NULL /* Unrecognized messages */
+ .cdr_open = log_open,
+ .cdr_read = log_read,
+ .cdr_write = log_write,
+ .cdr_cancel = log_cancel,
+ .cdr_select = log_select
};
/* SEF functions and variables. */
/* Initialize log devices. */
for(i = 0; i < NR_DEVS; i++) {
- log_geom[i].dv_size = ((u64_t)(LOG_SIZE));
- log_geom[i].dv_base = ((u64_t)((long)logdevices[i].log_buffer));
logdevices[i].log_size = logdevices[i].log_read =
logdevices[i].log_write =
- logdevices[i].log_select_alerted =
- logdevices[i].log_selected =
- logdevices[i].log_select_ready_ops = 0;
+ logdevices[i].log_selected = 0;
logdevices[i].log_source = NONE;
- logdevices[i].log_revive_alerted = 0;
}
return(OK);
do_new_kmess();
}
-/*===========================================================================*
- * log_prepare *
- *===========================================================================*/
-static struct device *log_prepare(dev_t device)
-{
-/* Prepare for I/O on a device: check if the minor device number is ok. */
-
- if (device >= NR_DEVS) return(NULL);
- log_device = (int) device;
-
- return(&log_geom[device]);
-}
-
/*===========================================================================*
* subwrite *
*===========================================================================*/
static int
-subwrite(struct logdevice *log, int count, endpoint_t endpt,
- cp_grant_id_t grant, size_t offset, char *localbuf)
+subwrite(struct logdevice *log, size_t size, endpoint_t endpt,
+ cp_grant_id_t grant, char *localbuf)
{
- int d, r;
- char *buf;
- message m;
+ size_t count, offset;
+ int overflow, r;
+ devminor_t minor;
+ char *buf;
+ message m;
+
+ /* With a sufficiently large input size, we might wrap around the ring buffer
+ * multiple times.
+ */
+ for (offset = 0; offset < size; offset += count) {
+ count = size - offset;
if (log->log_write + count > LOG_SIZE)
count = LOG_SIZE - log->log_write;
if(localbuf != NULL) {
memcpy(buf, localbuf, count);
+ localbuf += count;
}
else {
if((r=sys_safecopyfrom(endpt, grant, offset,
(vir_bytes)buf, count)) != OK)
- return r;
+ break; /* do process partial write upon error */
}
LOGINC(log->log_write, count);
log->log_size += count;
if(log->log_size > LOG_SIZE) {
- int overflow;
overflow = log->log_size - LOG_SIZE;
log->log_size -= overflow;
LOGINC(log->log_read, overflow);
}
- if(log->log_size > 0 && log->log_source != NONE &&
- !log->log_revive_alerted) {
- /* Someone who was suspended on read can now
- * be revived.
- */
- log->log_status = subread(log, log->log_iosize,
- log->log_source, log->log_user_grant,
- log->log_user_offset);
-
- m.m_type = DEV_REVIVE;
- m.REP_ENDPT = log->log_proc_nr;
- m.REP_STATUS = log->log_status;
- m.REP_IO_GRANT = log->log_user_grant;
- r= send(log->log_source, &m);
- if (r != OK)
- {
- printf("log`subwrite: send to %d failed: %d\n",
- log->log_source, r);
- }
- log->log_source = NONE;
- }
-
- if(log->log_size > 0)
- log->log_select_ready_ops |= SEL_RD;
-
- if(log->log_size > 0 && log->log_selected &&
- !(log->log_select_alerted)) {
- /* 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).
- */
- if(log->log_selected & SEL_RD) {
- d= log-logdevices;
- m.m_type = DEV_SEL_REPL2;
- m.DEV_SEL_OPS = log->log_select_ready_ops;
- m.DEV_MINOR = d;
+ r = offset; /* this will be the return value upon success */
+ }
+
+ if (log->log_size > 0 && log->log_source != NONE) {
+ /* Someone who was suspended on read can now be revived. */
+ r = subread(log, log->log_iosize, log->log_source, log->log_grant);
+
+ chardriver_reply_task(log->log_source, log->log_id, r);
+
+ log->log_source = NONE;
+ }
+
+ if (log->log_size > 0 && (log->log_selected & SEL_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 DEV_SEL_REPL2\n");
#endif
- r= send(log->log_select_proc, &m);
- if (r != OK)
- {
- printf(
- "log`subwrite: send to %d failed: %d\n",
- log->log_select_proc, r);
- }
- log->log_selected &= ~log->log_select_ready_ops;
- }
- }
-
- return count;
+ chardriver_reply_select(log->log_select_proc, minor, SEL_RD);
+ log->log_selected &= ~SEL_RD;
+ }
+
+ return r;
}
/*===========================================================================*
void
log_append(char *buf, int count)
{
- int w = 0, skip = 0;
-
- if(count < 1) return;
- if(count > LOG_SIZE) skip = count - LOG_SIZE;
- count -= skip;
- buf += skip;
- w = subwrite(&logdevices[0], count, SELF, GRANT_INVALID, 0, buf);
-
- if(w > 0 && w < count)
- subwrite(&logdevices[0], count-w, SELF, GRANT_INVALID, 0,
- buf + w);
- return;
+ int skip = 0;
+
+ if(count < 1) return;
+ if(count > LOG_SIZE) skip = count - LOG_SIZE;
+ count -= skip;
+ buf += skip;
+
+ subwrite(&logdevices[0], count, SELF, GRANT_INVALID, buf);
}
/*===========================================================================*
* subread *
*===========================================================================*/
static int
-subread(struct logdevice *log, int count, endpoint_t endpt,
- cp_grant_id_t grant, size_t offset)
+subread(struct logdevice *log, size_t size, endpoint_t endpt,
+ cp_grant_id_t grant)
{
- char *buf;
- int r;
+ size_t offset, count;
+ char *buf;
+ int r;
+
+ for (offset = 0; log->log_size > 0 && offset < size; offset += count) {
+ count = size - offset;
+
if (count > log->log_size)
count = log->log_size;
if (log->log_read + count > LOG_SIZE)
count = LOG_SIZE - log->log_read;
buf = log->log_buffer + log->log_read;
- if((r=sys_safecopyto(endpt, grant, offset,
- (vir_bytes)buf, count)) != OK)
+ if((r=sys_safecopyto(endpt, grant, offset, (vir_bytes)buf,
+ count)) != OK)
return r;
LOGINC(log->log_read, count);
log->log_size -= count;
+ }
- return count;
+ return offset;
}
/*===========================================================================*
- * log_transfer *
+ * log_read *
*===========================================================================*/
-static int log_transfer(
- endpoint_t endpt, /* endpoint of grant owner */
- int opcode, /* DEV_GATHER_S or DEV_SCATTER_S */
- u64_t UNUSED(position), /* offset on device to read or write */
- iovec_t *iov, /* pointer to read or write request vector */
- unsigned int nr_req, /* length of request vector */
- endpoint_t user_endpt, /* endpoint of user process */
- unsigned int flags
-)
+static ssize_t log_read(devminor_t minor, u64_t UNUSED(position),
+ endpoint_t endpt, cp_grant_id_t grant, size_t size, int flags,
+ cdev_id_t id)
{
-/* Read or write one the driver's minor devices. */
- int count;
- cp_grant_id_t grant;
- int accumulated_read = 0;
+/* Read from one of the driver's minor devices. */
struct logdevice *log;
- size_t vir_offset = 0;
-
- if(log_device < 0 || log_device >= NR_DEVS)
- return EIO;
-
- /* Get minor device number and check for /dev/null. */
- log = &logdevices[log_device];
-
- while (nr_req > 0) {
- /* How much to transfer and where to / from. */
- count = iov->iov_size;
- grant = iov->iov_addr;
-
- switch (log_device) {
-
- case MINOR_KLOG:
- if (opcode == DEV_GATHER_S) {
- if (log->log_source != NONE || count < 1) {
- /* There's already someone hanging to read, or
- * no real I/O requested.
- */
- return(OK);
- }
-
- if (!log->log_size) {
- if(accumulated_read)
- return OK;
- if (flags & FLG_OP_NONBLOCK)
- return EAGAIN;
- /* No data available; let caller block. */
- log->log_source = endpt;
- log->log_iosize = count;
- log->log_user_grant = grant;
- log->log_user_offset = 0;
- log->log_revive_alerted = 0;
- log->log_proc_nr = user_endpt;
+ int r;
+
+ if (minor < 0 || minor >= NR_DEVS) return EIO;
+ log = &logdevices[minor];
+
+ /* If there's already someone hanging to read, don't accept new work. */
+ if (log->log_source != NONE) return OK;
+
+ if (!log->log_size && size > 0) {
+ if (flags & FLG_OP_NONBLOCK) return EAGAIN;
+
+ /* No data available; let caller block. */
+ log->log_source = endpt;
+ log->log_iosize = size;
+ log->log_grant = grant;
+ log->log_id = id;
#if LOG_DEBUG
- printf("blocked %d (%d)\n",
- log->log_source, log->log_proc_nr);
+ printf("blocked %d (%d)\n", log->log_source, id);
#endif
- return(EDONTREPLY);
- }
- count = subread(log, count, endpt, grant, vir_offset);
- if(count < 0) {
- return count;
- }
- accumulated_read += count;
- } else {
- count = subwrite(log, count, endpt, grant, vir_offset, NULL);
- if(count < 0)
- return count;
- }
- break;
- /* Unknown (illegal) minor device. */
- default:
- return(EINVAL);
- }
-
- /* Book the number of bytes transferred. */
- vir_offset += count;
- if ((iov->iov_size -= count) == 0) { iov++; nr_req--; vir_offset = 0; }
+ return EDONTREPLY;
}
- return(OK);
+
+ return subread(log, size, endpt, grant);
+}
+
+/*===========================================================================*
+ * log_write *
+ *===========================================================================*/
+static ssize_t log_write(devminor_t minor, u64_t UNUSED(position),
+ endpoint_t endpt, cp_grant_id_t grant, size_t size, int UNUSED(flags),
+ cdev_id_t UNUSED(id))
+{
+/* Write to one of the driver's minor devices. */
+ struct logdevice *log;
+ int r;
+
+ if (minor < 0 || minor >= NR_DEVS) return EIO;
+ log = &logdevices[minor];
+
+ return subwrite(log, size, endpt, grant, NULL);
}
/*============================================================================*
- * log_do_open *
+ * log_open *
*============================================================================*/
-static int log_do_open(message *m_ptr)
+static int log_open(devminor_t minor, int UNUSED(access),
+ endpoint_t UNUSED(user_endpt))
{
- if (log_prepare(m_ptr->DEVICE) == NULL) return(ENXIO);
+ if (minor < 0 || minor >= NR_DEVS) return(ENXIO);
+
return(OK);
}
/*============================================================================*
* log_cancel *
*============================================================================*/
-static int log_cancel(message *m_ptr)
+static int log_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id)
{
- int d;
- d = m_ptr->DEVICE;
- if(d < 0 || d >= NR_DEVS)
+ if (minor < 0 || minor >= NR_DEVS)
return EINVAL;
- if (m_ptr->USER_ENDPT != logdevices[d].log_proc_nr)
- return EDONTREPLY;
- if ((cp_grant_id_t) m_ptr->IO_GRANT != logdevices[d].log_user_grant)
+
+ /* Not for the suspended request? Must be a stale cancel request. Ignore. */
+ if (logdevices[minor].log_source != endpt || logdevices[minor].log_id != id)
return EDONTREPLY;
- logdevices[d].log_proc_nr = NONE;
- logdevices[d].log_revive_alerted = 0;
- return(OK);
+
+ logdevices[minor].log_source = NONE;
+
+ return EINTR; /* this is the reply to the original, interrupted request */
}
/*============================================================================*
* log_select *
*============================================================================*/
-static int log_select(message *m_ptr)
+static int log_select(devminor_t minor, unsigned int ops, endpoint_t endpt)
{
- int d, ready_ops = 0, ops = 0;
- d = m_ptr->DEV_MINOR;
- if(d < 0 || d >= NR_DEVS) {
-#if LOG_DEBUG
- printf("line %d? EINVAL\n", d);
-#endif
- return EINVAL;
- }
+ int want_ops, ready_ops = 0;
+
+ if (minor < 0 || minor >= NR_DEVS)
+ return ENXIO;
- ops = m_ptr->DEV_SEL_OPS & (SEL_RD|SEL_WR|SEL_ERR);
+ want_ops = ops & (SEL_RD|SEL_WR|SEL_ERR);
/* Read blocks when there is no log. */
- if((m_ptr->DEV_SEL_OPS & SEL_RD) && logdevices[d].log_size > 0) {
+ if ((want_ops & SEL_RD) && logdevices[minor].log_size > 0) {
#if LOG_DEBUG
- printf("log can read; size %d\n", logdevices[d].log_size);
+ printf("log can read; size %d\n", logdevices[minor].log_size);
#endif
- ready_ops |= SEL_RD; /* writes never block */
+ ready_ops |= SEL_RD;
}
/* Write never blocks. */
- if(m_ptr->DEV_SEL_OPS & SEL_WR) ready_ops |= SEL_WR;
-
- /* Enable select calback if no operations were
- * ready to go, but operations were requested,
- * and notify was enabled.
- */
- if((m_ptr->DEV_SEL_OPS & SEL_NOTIFY) && ops && !ready_ops) {
- logdevices[d].log_selected |= ops;
- logdevices[d].log_select_proc = m_ptr->m_source;
+ if (want_ops & SEL_WR) ready_ops |= SEL_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) {
+ logdevices[minor].log_selected |= want_ops;
+ logdevices[minor].log_select_proc = endpt;
#if LOG_DEBUG
printf("log setting selector.\n");
#endif
return(ready_ops);
}
-
/* Constants and types. */
#define LOG_SIZE (50*1024)
-#define SUSPENDABLE 1
struct logdevice {
char log_buffer[LOG_SIZE];
int log_size, /* no. of bytes in log buffer */
log_read, /* read mark */
log_write; /* write mark */
-#if SUSPENDABLE
- endpoint_t log_proc_nr,
- log_source;
+ endpoint_t log_source;
+ cdev_id_t log_id;
int log_iosize,
- log_revive_alerted,
log_status;
- cp_grant_id_t log_user_grant;
- vir_bytes log_user_offset;
-#endif
- int log_selected, log_select_proc,
- log_select_alerted, log_select_ready_ops;
+ cp_grant_id_t log_grant;
+ int log_selected, log_select_proc;
};
/* Function prototypes. */
static struct device m_geom[NR_DEVS]; /* base and size of each device */
static vir_bytes m_vaddrs[NR_DEVS];
-static dev_t m_device; /* current minor character device */
static int openct[NR_DEVS];
-static struct device *m_prepare(dev_t device);
-static int m_transfer(endpoint_t endpt, int opcode, u64_t position,
- iovec_t *iov, unsigned int nr_req, endpoint_t user_endpt, unsigned int
- flags);
-static int m_do_open(message *m_ptr);
-static int m_do_close(message *m_ptr);
+static ssize_t m_char_read(devminor_t minor, u64_t position, endpoint_t endpt,
+ cp_grant_id_t grant, size_t size, int flags, cdev_id_t id);
+static ssize_t m_char_write(devminor_t minor, u64_t position, endpoint_t endpt,
+ cp_grant_id_t grant, size_t size, int flags, cdev_id_t id);
+static int m_char_open(devminor_t minor, int access, endpoint_t user_endpt);
+static int m_char_close(devminor_t minor);
static struct device *m_block_part(devminor_t minor);
-static int m_block_transfer(devminor_t minor, int do_write, u64_t position,
+static ssize_t m_block_transfer(devminor_t minor, int do_write, u64_t position,
endpoint_t endpt, iovec_t *iov, unsigned int nr_req, int flags);
static int m_block_open(devminor_t minor, int access);
static int m_block_close(devminor_t minor);
/* Entry points to the CHARACTER part of this driver. */
static struct chardriver m_cdtab = {
- m_do_open, /* open or mount */
- m_do_close, /* nothing on a close */
- nop_ioctl, /* no I/O control */
- m_prepare, /* prepare for I/O on a given minor device */
- m_transfer, /* do the I/O */
- nop_cleanup, /* no need to clean up */
- nop_alarm, /* no alarms */
- nop_cancel, /* no blocking operations */
- nop_select, /* select not supported */
- NULL /* other messages not supported */
+ .cdr_open = m_char_open, /* open device */
+ .cdr_close = m_char_close, /* close device */
+ .cdr_read = m_char_read, /* read from device */
+ .cdr_write = m_char_write /* write to device */
};
/* Entry points to the BLOCK part of this driver. */
.bdr_part = m_block_part /* return partition information */
};
-#define click_to_round_k(n) \
- ((unsigned) ((((unsigned long) (n) << CLICK_SHIFT) + 512) / 1024))
-
/* SEF functions and variables. */
static void sef_local_startup(void);
static int sef_cb_init_fresh(int type, sef_init_info_t *info);
-
/*===========================================================================*
* main *
*===========================================================================*/
}
/* Map in kernel memory for /dev/kmem. */
- m_geom[KMEM_DEV].dv_base = cvul64(kinfo.kmem_base);
- m_geom[KMEM_DEV].dv_size = cvul64(kinfo.kmem_size);
+ m_geom[KMEM_DEV].dv_base = kinfo.kmem_base;
+ m_geom[KMEM_DEV].dv_size = kinfo.kmem_size;
if((m_vaddrs[KMEM_DEV] = vm_map_phys(SELF, (void *) kinfo.kmem_base,
kinfo.kmem_size)) == MAP_FAILED) {
printf("MEM: Couldn't map in /dev/kmem.");
#endif
/* Ramdisk image built into the memory driver */
- m_geom[IMGRD_DEV].dv_base= ((u64_t)(0));
- m_geom[IMGRD_DEV].dv_size= ((u64_t)(imgrd_size));
+ m_geom[IMGRD_DEV].dv_base= 0;
+ m_geom[IMGRD_DEV].dv_size= imgrd_size;
m_vaddrs[IMGRD_DEV] = (vir_bytes) imgrd;
for(i = 0; i < NR_DEVS; i++)
openct[i] = 0;
/* Set up memory range for /dev/mem. */
- m_geom[MEM_DEV].dv_base = ((u64_t)(0));
- m_geom[MEM_DEV].dv_size = ((u64_t)(0xffffffff));
+ m_geom[MEM_DEV].dv_base = 0;
+ m_geom[MEM_DEV].dv_size = 0xffffffffULL;
m_vaddrs[MEM_DEV] = (vir_bytes) MAP_FAILED; /* we are not mapping this in. */
}
/*===========================================================================*
- * m_prepare *
+ * m_transfer_kmem *
*===========================================================================*/
-static struct device *m_prepare(dev_t device)
+static ssize_t m_transfer_kmem(devminor_t minor, int do_write, u64_t position,
+ endpoint_t endpt, cp_grant_id_t grant, size_t size)
{
-/* Prepare for I/O on a device: check if the minor device number is ok. */
- if (device >= NR_DEVS || m_is_block(device)) return(NULL);
- m_device = device;
+/* Transfer from or to the KMEM device. */
+ u64_t dv_size, dev_vaddr;
+ int r;
+
+ dv_size = m_geom[minor].dv_size;
+ dev_vaddr = m_vaddrs[minor];
- return(&m_geom[device]);
+ if (!dev_vaddr || dev_vaddr == (vir_bytes) MAP_FAILED) {
+ printf("MEM: dev %d not initialized\n", minor);
+ return EIO;
+ }
+
+ if (position >= dv_size) return 0; /* check for EOF */
+ if (position + size > dv_size) size = dv_size - position;
+
+ if (!do_write) /* copy actual data */
+ r = sys_safecopyto(endpt, grant, 0, dev_vaddr + position, size);
+ else
+ r = sys_safecopyfrom(endpt, grant, 0, dev_vaddr + position, size);
+
+ return (r != OK) ? r : size;
}
/*===========================================================================*
- * m_transfer *
+ * m_transfer_mem *
*===========================================================================*/
-static int m_transfer(
- endpoint_t endpt, /* endpoint of grant owner */
- int opcode, /* DEV_GATHER_S or DEV_SCATTER_S */
- u64_t pos64, /* offset on device to read or write */
- iovec_t *iov, /* pointer to read or write request vector */
- unsigned int nr_req, /* length of request vector */
- endpoint_t UNUSED(user_endpt),/* endpoint of user process */
- unsigned int UNUSED(flags)
-)
+static ssize_t m_transfer_mem(devminor_t minor, int do_write, u64_t position,
+ endpoint_t endpt, cp_grant_id_t grant, size_t size)
{
-/* Read or write one the driver's character devices. */
- unsigned count;
- vir_bytes vir_offset = 0;
- struct device *dv;
+/* Transfer from or to the MEM device. */
+ static int any_mapped = 0;
+ static phys_bytes pagestart_mapped;
+ static char *vaddr;
+ phys_bytes mem_phys, pagestart;
+ size_t off, page_off, subcount;
u64_t dv_size;
- int s, r;
- u64_t position;
- cp_grant_id_t grant;
- vir_bytes dev_vaddr;
-
- /* ZERO_DEV and NULL_DEV are infinite in size. */
- if (m_device != ZERO_DEV && m_device != NULL_DEV && ex64hi(pos64) != 0)
- return OK; /* Beyond EOF */
- position= pos64;
+ int r;
- /* Get minor device number and check for /dev/null. */
- dv = &m_geom[m_device];
- dv_size = dv->dv_size;
- dev_vaddr = m_vaddrs[m_device];
+ dv_size = m_geom[minor].dv_size;
+ if (position >= dv_size) return 0; /* check for EOF */
+ if (position + size > dv_size) size = dv_size - position;
- while (nr_req > 0) {
+ /* Physical copying. Only used to access entire memory.
+ * Transfer one 'page window' at a time.
+ */
+ off = 0;
+ while (off < size) {
+ mem_phys = (phys_bytes) position;
- /* How much to transfer and where to / from. */
- count = iov->iov_size;
- grant = (cp_grant_id_t) iov->iov_addr;
+ page_off = (size_t) (mem_phys % PAGE_SIZE);
+ pagestart = mem_phys - page_off;
- switch (m_device) {
+ /* All memory to the map call has to be page-aligned.
+ * Don't have to map same page over and over.
+ */
+ if (!any_mapped || pagestart_mapped != pagestart) {
+ if (any_mapped) {
+ if (vm_unmap_phys(SELF, vaddr, PAGE_SIZE) != OK)
+ panic("vm_unmap_phys failed");
+ any_mapped = 0;
+ }
+
+ vaddr = vm_map_phys(SELF, (void *) pagestart, PAGE_SIZE);
+ if (vaddr == MAP_FAILED) {
+ printf("memory: vm_map_phys failed\n");
+ return ENOMEM;
+ }
+ any_mapped = 1;
+ pagestart_mapped = pagestart;
+ }
- /* No copying; ignore request. */
- case NULL_DEV:
- if (opcode == DEV_GATHER_S) return(OK); /* always at EOF */
- break;
+ /* how much to be done within this page. */
+ subcount = PAGE_SIZE - page_off;
+ if (subcount > size)
+ subcount = size;
- /* Virtual copying. For kernel memory. */
- default:
- case KMEM_DEV:
- if(!dev_vaddr || dev_vaddr == (vir_bytes) MAP_FAILED) {
- printf("MEM: dev %d not initialized\n", m_device);
- return EIO;
- }
- if (position >= dv_size) return(OK); /* check for EOF */
- if (position + count > dv_size) count = dv_size - position;
- if (opcode == DEV_GATHER_S) { /* copy actual data */
- r=sys_safecopyto(endpt, grant, vir_offset,
- dev_vaddr + position, count);
- } else {
- r=sys_safecopyfrom(endpt, grant, vir_offset,
- dev_vaddr + position, count);
- }
- if(r != OK) {
- panic("I/O copy failed: %d", r);
- }
- break;
-
- /* Physical copying. Only used to access entire memory.
- * Transfer one 'page window' at a time.
- */
- case MEM_DEV:
- {
- u32_t pagestart, page_off;
- static u32_t pagestart_mapped;
- static int any_mapped = 0;
- static char *vaddr;
- int r;
- u32_t subcount;
- phys_bytes mem_phys;
-
- if (position >= dv_size)
- return(OK); /* check for EOF */
- if (position + count > dv_size)
- count = dv_size - position;
- mem_phys = position;
-
- page_off = mem_phys % PAGE_SIZE;
- pagestart = mem_phys - page_off;
-
- /* All memory to the map call has to be page-aligned.
- * Don't have to map same page over and over.
- */
- if(!any_mapped || pagestart_mapped != pagestart) {
- if(any_mapped) {
- if(vm_unmap_phys(SELF, vaddr, PAGE_SIZE) != OK)
- panic("vm_unmap_phys failed");
- any_mapped = 0;
- }
- vaddr = vm_map_phys(SELF, (void *) pagestart, PAGE_SIZE);
- if(vaddr == MAP_FAILED)
- r = ENOMEM;
- else
- r = OK;
- if(r != OK) {
- printf("memory: vm_map_phys failed\n");
+ if (!do_write) /* copy data */
+ r = sys_safecopyto(endpt, grant, off,
+ (vir_bytes) vaddr + page_off, subcount);
+ else
+ r = sys_safecopyfrom(endpt, grant, off,
+ (vir_bytes) vaddr + page_off, subcount);
+ if (r != OK)
return r;
- }
- any_mapped = 1;
- pagestart_mapped = pagestart;
- }
-
- /* how much to be done within this page. */
- subcount = PAGE_SIZE-page_off;
- if(subcount > count)
- subcount = count;
-
- if (opcode == DEV_GATHER_S) { /* copy data */
- s=sys_safecopyto(endpt, grant,
- vir_offset, (vir_bytes) vaddr+page_off, subcount);
- } else {
- s=sys_safecopyfrom(endpt, grant,
- vir_offset, (vir_bytes) vaddr+page_off, subcount);
- }
- if(s != OK)
- return s;
- count = subcount;
- break;
- }
- /* Null byte stream generator. */
- case ZERO_DEV:
- if (opcode == DEV_GATHER_S)
- if ((s = sys_safememset(endpt, grant, 0, '\0', count)) != OK)
- return s;
+ position += subcount;
+ off += subcount;
+ }
- break;
+ return off;
+}
- }
+/*===========================================================================*
+ * m_char_read *
+ *===========================================================================*/
+static ssize_t m_char_read(devminor_t minor, u64_t position, endpoint_t endpt,
+ cp_grant_id_t grant, size_t size, int UNUSED(flags),
+ cdev_id_t UNUSED(id))
+{
+/* Read from one of the driver's character devices. */
+ ssize_t r;
- /* Book the number of bytes transferred. */
- position += count;
- vir_offset += count;
- if ((iov->iov_size -= count) == 0) { iov++; nr_req--; vir_offset = 0; }
+ /* Check if the minor device number is ok. */
+ if (minor < 0 || minor >= NR_DEVS || m_is_block(minor)) return ENXIO;
+
+ switch (minor) {
+ case NULL_DEV:
+ r = 0; /* always at EOF */
+ break;
+
+ case ZERO_DEV:
+ /* Fill the target area with zeroes. In fact, let the kernel do it! */
+ if ((r = sys_safememset(endpt, grant, 0, '\0', size)) == OK)
+ r = size;
+ break;
+ case KMEM_DEV:
+ r = m_transfer_kmem(minor, FALSE, position, endpt, grant, size);
+ break;
+
+ case MEM_DEV:
+ r = m_transfer_mem(minor, FALSE, position, endpt, grant, size);
+ break;
+
+ default:
+ panic("unknown character device %d", minor);
}
- return(OK);
+
+ return r;
}
/*===========================================================================*
- * m_do_open *
+ * m_char_write *
*===========================================================================*/
-static int m_do_open(message *m_ptr)
+static ssize_t m_char_write(devminor_t minor, u64_t position, endpoint_t endpt,
+ cp_grant_id_t grant, size_t size, int UNUSED(flags),
+ cdev_id_t UNUSED(id))
+{
+/* Write to one of the driver's character devices. */
+ ssize_t r;
+
+ /* Check if the minor device number is ok. */
+ if (minor < 0 || minor >= NR_DEVS || m_is_block(minor)) return ENXIO;
+
+ switch (minor) {
+ case NULL_DEV:
+ case ZERO_DEV:
+ r = size; /* just eat everything */
+ break;
+
+ case KMEM_DEV:
+ r = m_transfer_kmem(minor, TRUE, position, endpt, grant, size);
+ break;
+
+ case MEM_DEV:
+ r = m_transfer_mem(minor, TRUE, position, endpt, grant, size);
+ break;
+
+ default:
+ panic("unknown character device %d", minor);
+ }
+
+ return r;
+}
+
+/*===========================================================================*
+ * m_char_open *
+ *===========================================================================*/
+static int m_char_open(devminor_t minor, int access, endpoint_t user_endpt)
{
/* Open a memory character device. */
- int r;
-/* Check device number on open. */
- if (m_prepare(m_ptr->DEVICE) == NULL) return(ENXIO);
+ /* Check if the minor device number is ok. */
+ if (minor < 0 || minor >= NR_DEVS || m_is_block(minor)) return ENXIO;
+
#if defined(__i386__)
- if (m_device == MEM_DEV)
+ if (minor == MEM_DEV)
{
- r = sys_enable_iop(m_ptr->USER_ENDPT);
+ int r = sys_enable_iop(user_endpt);
if (r != OK)
{
- printf("m_do_open: sys_enable_iop failed for %d: %d\n",
- m_ptr->USER_ENDPT, r);
+ printf("m_char_open: sys_enable_iop failed for %d: %d\n",
+ user_endpt, r);
return r;
}
}
#endif
- openct[m_device]++;
+ openct[minor]++;
return(OK);
}
/*===========================================================================*
- * m_do_close *
+ * m_char_close *
*===========================================================================*/
-static int m_do_close(message *m_ptr)
+static int m_char_close(devminor_t minor)
{
/* Close a memory character device. */
- if (m_prepare(m_ptr->DEVICE) == NULL) return(ENXIO);
- if(openct[m_device] < 1) {
- printf("MEMORY: closing unopened device %d\n", m_device);
+ if (minor < 0 || minor >= NR_DEVS || m_is_block(minor)) return ENXIO;
+
+ if(openct[minor] < 1) {
+ printf("MEMORY: closing unopened device %d\n", minor);
return(EINVAL);
}
- openct[m_device]--;
+ openct[minor]--;
return(OK);
}
static int m_block_transfer(
devminor_t minor, /* minor device number */
int do_write, /* read or write? */
- u64_t pos64, /* offset on device to read or write */
+ u64_t position, /* offset on device to read or write */
endpoint_t endpt, /* process doing the request */
iovec_t *iov, /* pointer to read or write request vector */
unsigned int nr_req, /* length of request vector */
struct device *dv;
u64_t dv_size;
int r;
- u64_t position;
vir_bytes dev_vaddr;
cp_grant_id_t grant;
ssize_t total = 0;
dv_size = dv->dv_size;
dev_vaddr = m_vaddrs[minor];
- if (ex64hi(pos64) != 0)
+ if (ex64hi(position) != 0)
return OK; /* Beyond EOF */
- position= pos64;
while (nr_req > 0) {
return s;
if(is_imgrd)
ramdev_size = 0;
- if(m_vaddrs[minor] && !cmp64(dv->dv_size, ((u64_t)(ramdev_size)))) {
+ if(m_vaddrs[minor] && dv->dv_size == (u64_t) ramdev_size) {
return(OK);
}
/* openct is 1 for the ioctl(). */
m_vaddrs[minor] = (vir_bytes) mem;
- dv->dv_size = ((u64_t)(ramdev_size));
+ dv->dv_size = ramdev_size;
return(OK);
}
extern int errno; /* error number for PM calls */
static struct device *r_prepare(dev_t device);
-static int r_transfer(endpoint_t endpt, int opcode, u64_t position,
- iovec_t *iov, unsigned int nr_req, endpoint_t user_endpt, unsigned int
- flags);
-static int r_do_open(message *m_ptr);
-static void r_random(message *m_ptr);
+static ssize_t r_read(devminor_t minor, u64_t position, endpoint_t endpt,
+ cp_grant_id_t grant, size_t size, int flags, cdev_id_t id);
+static ssize_t r_write(devminor_t minor, u64_t position, endpoint_t endpt,
+ cp_grant_id_t grant, size_t size, int flags, cdev_id_t id);
+static int r_open(devminor_t minor, int access, endpoint_t user_endpt);
+static void r_random(clock_t stamp);
static void r_updatebin(int source, struct k_randomness_bin *rb);
/* Entry points to this driver. */
static struct chardriver r_dtab = {
- r_do_open, /* open or mount */
- do_nop, /* nothing on a close */
- nop_ioctl, /* no I/O controls supported */
- r_prepare, /* prepare for I/O on a given minor device */
- r_transfer, /* do the I/O */
- nop_cleanup, /* no need to clean up */
- r_random, /* get randomness from kernel (alarm) */
- nop_cancel, /* cancel not supported */
- nop_select, /* select not supported */
- NULL, /* other messages not supported */
+ .cdr_open = r_open, /* open device */
+ .cdr_read = r_read, /* read from device */
+ .cdr_write = r_write, /* write to device (seeding it) */
+ .cdr_alarm = r_random /* get randomness from kernel (alarm) */
};
/* Buffer for the /dev/random number generator. */
int i, s;
random_init();
- r_random(NULL); /* also set periodic timer */
+ r_random(0); /* also set periodic timer */
/* Retrieve first randomness buffer with parameters. */
if (OK != (s=sys_getrandomness(&krandom))) {
}
/*===========================================================================*
- * r_prepare *
+ * r_read *
*===========================================================================*/
-static struct device *r_prepare(dev_t device)
+static ssize_t r_read(devminor_t minor, u64_t UNUSED(position),
+ endpoint_t endpt, cp_grant_id_t grant, size_t size, int UNUSED(flags),
+ cdev_id_t UNUSED(id))
{
-/* Prepare for I/O on a device: check if the minor device number is ok. */
+/* Read from one of the driver's minor devices. */
+ size_t offset, chunk;
+ int r;
+
+ if (minor != RANDOM_DEV) return(EIO);
+
+ if (!random_isseeded()) return(EAGAIN);
- if (device >= NR_DEVS) return(NULL);
- m_device = device;
+ for (offset = 0; offset < size; offset += chunk) {
+ chunk = MIN(size - offset, RANDOM_BUF_SIZE);
+ random_getbytes(random_buf, chunk);
+ r = sys_safecopyto(endpt, grant, offset, (vir_bytes)random_buf, chunk);
+ if (r != OK) {
+ printf("random: sys_safecopyto failed for proc %d, grant %d\n",
+ endpt, grant);
+ return r;
+ }
+ }
- return(&m_geom[device]);
+ return size;
}
/*===========================================================================*
- * r_transfer *
+ * r_write *
*===========================================================================*/
-static int r_transfer(
- endpoint_t endpt, /* endpoint of grant owner */
- int opcode, /* DEV_GATHER or DEV_SCATTER */
- u64_t position, /* offset on device to read or write */
- iovec_t *iov, /* pointer to read or write request vector */
- unsigned int nr_req, /* length of request vector */
- endpoint_t UNUSED(user_endpt),/* endpoint of user process */
- unsigned int UNUSED(flags)
-)
+static ssize_t r_write(devminor_t minor, u64_t UNUSED(position),
+ endpoint_t endpt, cp_grant_id_t grant, size_t size, int UNUSED(flags),
+ cdev_id_t UNUSED(id))
{
-/* Read or write one the driver's minor devices. */
- unsigned count, left, chunk;
- cp_grant_id_t grant;
- struct device *dv;
+/* Write to one of the driver's minor devices. */
+ size_t offset, chunk;
int r;
- size_t vir_offset = 0;
-
- /* Get minor device number and check for /dev/null. */
- dv = &m_geom[m_device];
-
- while (nr_req > 0) {
-
- /* How much to transfer and where to / from. */
- count = iov->iov_size;
- grant = (cp_grant_id_t) iov->iov_addr;
-
- switch (m_device) {
-
- /* Random number generator. Character instead of block device. */
- case RANDOM_DEV:
- if (opcode == DEV_GATHER_S && !random_isseeded())
- return(EAGAIN);
- left = count;
- while (left > 0) {
- chunk = (left > RANDOM_BUF_SIZE) ? RANDOM_BUF_SIZE : left;
- if (opcode == DEV_GATHER_S) {
- random_getbytes(random_buf, chunk);
- r= sys_safecopyto(endpt, grant, vir_offset,
- (vir_bytes) random_buf, chunk);
- if (r != OK)
- {
- printf("random: sys_safecopyto failed for proc %d, "
- "grant %d\n", endpt, grant);
- return r;
- }
- } else if (opcode == DEV_SCATTER_S) {
- r= sys_safecopyfrom(endpt, grant, vir_offset,
- (vir_bytes) random_buf, chunk);
- if (r != OK)
- {
- printf("random: sys_safecopyfrom failed for proc %d, "
- "grant %d\n", endpt, grant);
- return r;
- }
- random_putbytes(random_buf, chunk);
- }
- vir_offset += chunk;
- left -= chunk;
- }
- break;
-
- /* Unknown (illegal) minor device. */
- default:
- return(EINVAL);
- }
- /* Book the number of bytes transferred. */
- position += count;
- if ((iov->iov_size -= count) == 0) { iov++; nr_req--; vir_offset = 0; }
+ if (minor != RANDOM_DEV) return(EIO);
+ for (offset = 0; offset < size; offset += chunk) {
+ chunk = MIN(size - offset, RANDOM_BUF_SIZE);
+ r = sys_safecopyfrom(endpt, grant, offset, (vir_bytes)random_buf,
+ chunk);
+ if (r != OK) {
+ printf("random: sys_safecopyfrom failed for proc %d,"
+ " grant %d\n", endpt, grant);
+ return r;
+ }
+ random_putbytes(random_buf, chunk);
}
- return(OK);
+
+ return size;
}
/*===========================================================================*
- * r_do_open *
+ * r_open *
*===========================================================================*/
-static int r_do_open(message *m_ptr)
+static int r_open(devminor_t minor, int access, endpoint_t UNUSED(user_endpt))
{
/* Check device number on open.
*/
- if (r_prepare(m_ptr->DEVICE) == NULL) return(ENXIO);
+
+ if (minor < 0 || minor >= NR_DEVS) return(ENXIO);
return(OK);
}
/*===========================================================================*
* r_random *
*===========================================================================*/
-static void r_random(message *UNUSED(m_ptr))
+static void r_random(clock_t UNUSED(stamp))
{
/* Fetch random information from the kernel to update /dev/random. */
int s;
static int checksum(uint8_t * bytes, int nbytes, uint8_t expected_crc);
/* libchardriver callbacks */
-static struct device *sht21_prepare(dev_t UNUSED(dev));
-static int sht21_transfer(endpoint_t endpt, int opcode, u64_t position,
- iovec_t * iov, unsigned nr_req, endpoint_t UNUSED(user_endpt),
- unsigned int UNUSED(flags));
-static int sht21_other(message * m);
+static ssize_t sht21_read(devminor_t minor, u64_t position, endpoint_t endpt,
+ cp_grant_id_t grant, size_t size, int flags, cdev_id_t id);
+static void sht21_other(message * m, int ipc_status);
/* SEF functions */
static int sef_cb_lu_state_save(int);
/* Entry points to this driver from libchardriver. */
static struct chardriver sht21_tab = {
- .cdr_open = do_nop,
- .cdr_close = do_nop,
- .cdr_ioctl = nop_ioctl,
- .cdr_prepare = sht21_prepare,
- .cdr_transfer = sht21_transfer,
- .cdr_cleanup = nop_cleanup,
- .cdr_alarm = nop_alarm,
- .cdr_cancel = nop_cancel,
- .cdr_select = nop_select,
- .cdr_other = sht21_other
-};
-
-static struct device sht21_device = {
- .dv_base = 0,
- .dv_size = 0
+ .cdr_read = sht21_read,
+ .cdr_other = sht21_other
};
/*
}
}
-static struct device *
-sht21_prepare(dev_t UNUSED(dev))
-{
- return &sht21_device;
-}
-
-static int
-sht21_transfer(endpoint_t endpt, int opcode, u64_t position,
- iovec_t * iov, unsigned nr_req, endpoint_t UNUSED(user_endpt),
- unsigned int UNUSED(flags))
+static ssize_t
+sht21_read(devminor_t UNUSED(minor), u64_t position, endpoint_t endpt,
+ cp_grant_id_t grant, size_t size, int UNUSED(flags), cdev_id_t UNUSED(id))
{
+ u64_t dev_size;
int bytes, r;
r = measure();
log_trace(&log, "%s", buffer);
- bytes = strlen(buffer) - position < iov->iov_size ?
- strlen(buffer) - position : iov->iov_size;
-
- if (bytes <= 0) {
- return OK;
- }
+ dev_size = (u64_t)strlen(buffer);
+ if (position >= dev_size) return 0;
+ if (position + size > dev_size)
+ size = (size_t)(dev_size - position);
- switch (opcode) {
- case DEV_GATHER_S:
- r = sys_safecopyto(endpt, (cp_grant_id_t) iov->iov_addr, 0,
- (vir_bytes) (buffer + position), bytes);
- iov->iov_size -= bytes;
- break;
- default:
- return EINVAL;
- }
+ r = sys_safecopyto(endpt, grant, 0,
+ (vir_bytes)(buffer + (size_t)position), size);
- return r;
+ return (r != OK) ? r : size;
}
-static int
-sht21_other(message * m)
+static void
+sht21_other(message * m, int ipc_status)
{
int r;
- switch (m->m_type) {
- case NOTIFY_MESSAGE:
+ if (is_ipc_notify(ipc_status)) {
if (m->m_source == DS_PROC_NR) {
log_debug(&log,
"bus driver changed state, update endpoint\n");
i2cdriver_handle_bus_update(&bus_endpoint, bus,
address);
}
- r = OK;
- break;
- default:
- log_warn(&log, "Invalid message type (0x%x)\n", m->m_type);
- r = EINVAL;
- break;
+ return;
}
- return r;
+ log_warn(&log, "Invalid message type (0x%x)\n", m->m_type);
}
static int
static int measure_lux(uint32_t * lux);
/* libchardriver callbacks */
-static struct device *tsl2550_prepare(dev_t UNUSED(dev));
-static int tsl2550_transfer(endpoint_t endpt, int opcode, u64_t position,
- iovec_t * iov, unsigned nr_req, endpoint_t UNUSED(user_endpt),
- unsigned int UNUSED(flags));
-static int tsl2550_other(message * m);
+static ssize_t tsl2550_read(devminor_t minor, u64_t position, endpoint_t endpt,
+ cp_grant_id_t grant, size_t size, int flags, cdev_id_t id);
+static void tsl2550_other(message * m, int ipc_status);
/* SEF functions */
static int sef_cb_lu_state_save(int);
/* Entry points to this driver from libchardriver. */
static struct chardriver tsl2550_tab = {
- .cdr_open = do_nop,
- .cdr_close = do_nop,
- .cdr_ioctl = nop_ioctl,
- .cdr_prepare = tsl2550_prepare,
- .cdr_transfer = tsl2550_transfer,
- .cdr_cleanup = nop_cleanup,
- .cdr_alarm = nop_alarm,
- .cdr_cancel = nop_cancel,
- .cdr_select = nop_select,
- .cdr_other = tsl2550_other
-};
-
-static struct device tsl2550_device = {
- .dv_base = 0,
- .dv_size = 0
+ .cdr_read = tsl2550_read,
+ .cdr_other = tsl2550_other
};
/*
return OK;
}
-static struct device *
-tsl2550_prepare(dev_t UNUSED(dev))
-{
- return &tsl2550_device;
-}
-
-static int
-tsl2550_transfer(endpoint_t endpt, int opcode, u64_t position,
- iovec_t * iov, unsigned nr_req, endpoint_t UNUSED(user_endpt),
- unsigned int UNUSED(flags))
+static ssize_t
+tsl2550_read(devminor_t UNUSED(minor), u64_t position, endpoint_t endpt,
+ cp_grant_id_t grant, size_t size, int UNUSED(flags), cdev_id_t UNUSED(id))
{
+ u64_t dev_size;
int bytes, r;
uint32_t lux;
memset(buffer, '\0', BUFFER_LEN + 1);
snprintf(buffer, BUFFER_LEN, "%-16s: %d\n", "ILLUMINANCE", lux);
- bytes = strlen(buffer) - position < iov->iov_size ?
- strlen(buffer) - position : iov->iov_size;
+ dev_size = (u64_t)strlen(buffer);
+ if (position >= dev_size) return 0;
+ if (position + size > dev_size)
+ size = (size_t)(dev_size - position);
- if (bytes <= 0) {
- return OK;
- }
-
- switch (opcode) {
- case DEV_GATHER_S:
- r = sys_safecopyto(endpt, (cp_grant_id_t) iov->iov_addr, 0,
- (vir_bytes) (buffer + position), bytes);
- iov->iov_size -= bytes;
- break;
- default:
- return EINVAL;
- }
+ r = sys_safecopyto(endpt, grant, 0,
+ (vir_bytes)(buffer + (size_t)position), size);
- return r;
+ return (r != OK) ? r : size;
}
-static int
-tsl2550_other(message * m)
+static void
+tsl2550_other(message * m, int ipc_status)
{
int r;
- switch (m->m_type) {
- case NOTIFY_MESSAGE:
+ if (is_ipc_notify(ipc_status)) {
if (m->m_source == DS_PROC_NR) {
log_debug(&log,
"bus driver changed state, update endpoint\n");
i2cdriver_handle_bus_update(&bus_endpoint, bus,
address);
}
- r = OK;
- break;
- default:
- log_warn(&log, "Invalid message type (0x%x)\n", m->m_type);
- r = EINVAL;
- break;
+ return;
}
- return r;
+ log_warn(&log, "Invalid message type (0x%x)\n", m->m_type);
}
static int
#include <minix/driver.h>
+typedef unsigned int cdev_id_t;
+
/* Entry points into the device dependent code of character drivers. */
struct chardriver {
- int(*cdr_open) (message *m_ptr);
- int(*cdr_close) (message *m_ptr);
- int(*cdr_ioctl) (message *m_ptr);
- struct device *(*cdr_prepare)(dev_t device);
- int(*cdr_transfer) (endpoint_t endpt, int opcode, u64_t position,
- iovec_t *iov, unsigned int nr_req, endpoint_t user_endpt, unsigned int
- flags);
- void(*cdr_cleanup) (void);
- void(*cdr_alarm) (message *m_ptr);
- int(*cdr_cancel) (message *m_ptr);
- int(*cdr_select) (message *m_ptr);
- int(*cdr_other) (message *m_ptr);
+ int (*cdr_open)(devminor_t minor, int access, endpoint_t user_endpt);
+ int (*cdr_close)(devminor_t minor);
+ ssize_t (*cdr_read)(devminor_t minor, u64_t position, endpoint_t endpt,
+ cp_grant_id_t grant, size_t size, int flags, cdev_id_t id);
+ ssize_t (*cdr_write)(devminor_t minor, u64_t position, endpoint_t endpt,
+ cp_grant_id_t grant, size_t size, int flags, cdev_id_t id);
+ int (*cdr_ioctl)(devminor_t minor, unsigned long request, endpoint_t endpt,
+ cp_grant_id_t grant, int flags, endpoint_t user_endpt, cdev_id_t id);
+ int (*cdr_cancel)(devminor_t minor, endpoint_t endpt, cdev_id_t id);
+ int (*cdr_select)(devminor_t minor, unsigned int ops, endpoint_t endpt);
+ void (*cdr_intr)(unsigned int mask);
+ void (*cdr_alarm)(clock_t stamp);
+ void (*cdr_other)(message *m_ptr, int ipc_status);
};
/* Functions defined by libchardriver. */
void chardriver_terminate(void);
void chardriver_task(struct chardriver *cdp);
-int do_nop(message *m_ptr);
-void nop_cleanup(void);
-void nop_alarm(message *m_ptr);
-int nop_cancel(message *m_ptr);
-int nop_select(message *m_ptr);
-int nop_ioctl(message *m_ptr);
+void chardriver_reply_task(endpoint_t endpt, cdev_id_t id, int r);
+void chardriver_reply_select(endpoint_t endpt, devminor_t minor, int ops);
#endif /* _MINIX_CHARDRIVER_H */
* | DEV_SELECT | device | ops | | | | |
* ----------------------------------------------------------------------------
*
- * The entry points into this file are:
- * driver_task: the main message loop of the driver
- * driver_receive: message receive interface for drivers
- *
* Changes:
- * Oct 20, 2013 retire synchronous protocol (D.C. van Moolenbroek)
+ * Sep 01, 2013 complete rewrite of the API (D.C. van Moolenboek)
+ * Aug 20, 2013 retire synchronous protocol (D.C. van Moolenbroek)
* Oct 16, 2011 split character and block protocol (D.C. van Moolenbroek)
* Aug 27, 2011 move common functions into driver.c (A. Welzel)
* Jul 25, 2005 added SYS_SIG type for signals (Jorrit N. Herder)
static int running;
/* Management data for opened devices. */
-static int open_devs[MAX_NR_OPEN_DEVICES];
+static devminor_t open_devs[MAX_NR_OPEN_DEVICES];
static int next_open_devs_slot = 0;
/*===========================================================================*
/*===========================================================================*
* is_open_dev *
*===========================================================================*/
-static int is_open_dev(int device)
+static int is_open_dev(devminor_t minor)
{
/* Check whether the given minor device has previously been opened. */
int i;
for (i = 0; i < next_open_devs_slot; i++)
- if (open_devs[i] == device)
+ if (open_devs[i] == minor)
return TRUE;
return FALSE;
/*===========================================================================*
* set_open_dev *
*===========================================================================*/
-static void set_open_dev(int device)
+static void set_open_dev(devminor_t minor)
{
/* Mark the given minor device as having been opened. */
if (next_open_devs_slot >= MAX_NR_OPEN_DEVICES)
panic("out of slots for open devices");
- open_devs[next_open_devs_slot] = device;
+ open_devs[next_open_devs_slot] = minor;
next_open_devs_slot++;
}
clear_open_devs();
}
+/*===========================================================================*
+ * chardriver_reply_task *
+ *===========================================================================*/
+void chardriver_reply_task(endpoint_t endpt, cdev_id_t id, int r)
+{
+/* Reply to a (read, write, ioctl) task request that was suspended earlier.
+ * Not-so-well-written drivers may use this function to send a reply to a
+ * request that is being processed right now, and then return EDONTREPLY later.
+ */
+ message m_reply;
+
+ if (r == EDONTREPLY || r == SUSPEND)
+ panic("chardriver: bad task reply: %d", r);
+
+ 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;
+
+ if ((r = asynsend3(endpt, &m_reply, AMF_NOREPLY)) != OK)
+ printf("chardriver_reply_task: send to %d failed: %d\n", endpt, r);
+}
+
+/*===========================================================================*
+ * chardriver_reply_select *
+ *===========================================================================*/
+void chardriver_reply_select(endpoint_t endpt, devminor_t minor, int r)
+{
+/* Reply to a select request with a status update. This must not be used to
+ * reply to a select request that is being processed right now.
+ */
+ message m_reply;
+
+ /* Replying with an error is allowed (if unusual). */
+ if (r == EDONTREPLY || r == SUSPEND)
+ panic("chardriver: bad select reply: %d", 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;
+
+ if ((r = asynsend3(endpt, &m_reply, AMF_NOREPLY)) != OK)
+ printf("chardriver_reply_select: send to %d failed: %d\n", endpt, r);
+}
+
/*===========================================================================*
* send_reply *
*===========================================================================*/
-static void send_reply(message *mess, int ipc_status, int r)
+static void send_reply(endpoint_t endpt, message *m_ptr, int ipc_status)
+{
+/* Send a reply message to a request. */
+ int r;
+
+ /* If we would block sending the message, send it asynchronously. */
+ if (IPC_STATUS_CALL(ipc_status) == SENDREC)
+ r = sendnb(endpt, m_ptr);
+ else
+ r = asynsend3(endpt, m_ptr, AMF_NOREPLY);
+
+ if (r != OK)
+ printf("chardriver: unable to send reply to %d: %d\n", endpt, r);
+}
+
+/*===========================================================================*
+ * chardriver_reply *
+ *===========================================================================*/
+static void chardriver_reply(message *mess, int ipc_status, int r)
{
/* Prepare and send a reply message. */
message reply_mess;
- if (r == EDONTREPLY)
- return;
+ /* If the EDONTREPLY pseudo-reply is given, we do not reply. This is however
+ * allowed only for blocking task calls. Perform a sanity check.
+ */
+ 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)
+ panic("chardriver: cannot suspend nonblocking I/O");
+#endif
+ /*fall-through*/
+ case CANCEL:
+ return; /* alright */
+ default:
+ panic("chardriver: cannot suspend request %d", mess->m_type);
+ }
+ }
+
+ if (r == SUSPEND)
+ panic("chardriver: SUSPEND should not be used anymore");
/* Do not reply with ERESTART. The only possible caller, VFS, will find out
* through other means when we have restarted, and is not (fully) ready to
reply_mess.REP_STATUS = r;
break;
+ case DEV_REOPEN:
+ reply_mess.m_type = DEV_REOPEN_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;
case DEV_READ_S:
case DEV_WRITE_S:
case DEV_IOCTL_S:
- if (r == SUSPEND)
- printf("chardriver_task: reviving %d (%d) with SUSPEND\n",
- mess->m_source, mess->USER_ENDPT);
-
+ 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 CANCEL:
- /* The original request should send a reply. */
- return;
-
case DEV_SELECT:
reply_mess.m_type = DEV_SEL_REPL1;
reply_mess.DEV_MINOR = mess->DEVICE;
break;
default:
- reply_mess.m_type = DEV_REVIVE;
- reply_mess.REP_ENDPT = mess->USER_ENDPT;
- /* Status is # of bytes transferred or error code. */
- reply_mess.REP_STATUS = r;
- break;
+ panic("chardriver: unknown request %d", mess->m_type);
}
- /* If we would block sending the message, send it asynchronously. */
- if (IPC_STATUS_CALL(ipc_status) == SENDREC)
- r = sendnb(mess->m_source, &reply_mess);
- else
- r = asynsend3(mess->m_source, &reply_mess, AMF_NOREPLY);
+ send_reply(mess->m_source, &reply_mess, ipc_status);
+}
- if (r != OK)
- printf("send_reply: unable to send reply to %d: %d\n",
- mess->m_source, r);
+/*===========================================================================*
+ * do_open *
+ *===========================================================================*/
+static int do_open(struct chardriver *cdp, message *m_ptr, int is_reopen)
+{
+/* Open a minor device. */
+ endpoint_t user_endpt;
+ devminor_t minor;
+ int r, access;
+
+ /* Default action if no open hook is in place. */
+ if (cdp->cdr_open == NULL)
+ return OK;
+
+ /* Call the open hook. */
+ minor = m_ptr->DEVICE;
+ access = m_ptr->COUNT;
+ user_endpt = is_reopen ? NONE : m_ptr->USER_ENDPT; /* XXX FIXME */
+
+ 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);
+
+ return r;
}
/*===========================================================================*
- * do_rdwt *
+ * do_close *
*===========================================================================*/
-static int do_rdwt(struct chardriver *cdp, message *mp)
+static int do_close(struct chardriver *cdp, message *m_ptr)
{
-/* Carry out a single read or write request. */
- iovec_t iovec1;
- int r, opcode;
- u64_t position;
+/* Close a minor device. */
+ devminor_t minor;
- /* Disk address? Address and length of the user buffer? */
- if (mp->COUNT < 0) return(EINVAL);
+ /* Default action if no close hook is in place. */
+ if (cdp->cdr_close == NULL)
+ return OK;
- /* Prepare for I/O. */
- if ((*cdp->cdr_prepare)(mp->DEVICE) == NULL) return(ENXIO);
+ /* Call the close hook. */
+ minor = m_ptr->DEVICE;
- /* Create a one element scatter/gather vector for the buffer. */
- if(mp->m_type == DEV_READ_S)
- opcode = DEV_GATHER_S;
- else
- opcode = DEV_SCATTER_S;
+ return cdp->cdr_close(minor);
+}
- iovec1.iov_addr = (vir_bytes) mp->IO_GRANT;
- iovec1.iov_size = mp->COUNT;
+/*===========================================================================*
+ * do_trasnfer *
+ *===========================================================================*/
+static int do_transfer(struct chardriver *cdp, message *m_ptr, int do_write)
+{
+/* Carry out a read or write task request. */
+ devminor_t minor;
+ u64_t position;
+ endpoint_t endpt;
+ cp_grant_id_t grant;
+ size_t size;
+ int flags;
+ cdev_id_t id;
+ ssize_t r;
+
+ minor = m_ptr->DEVICE;
+ position = make64(m_ptr->POSITION, m_ptr->HIGHPOS);
+ 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;
+
+ /* Call the read/write hook, if the appropriate one is in place. */
+ if (!do_write && cdp->cdr_read != NULL)
+ r = cdp->cdr_read(minor, position, endpt, grant, size, flags, id);
+ else if (do_write && cdp->cdr_write != NULL)
+ r = cdp->cdr_write(minor, position, endpt, grant, size, flags, id);
+ else
+ r = EIO; /* Default action if no read/write hook is in place. */
- /* Transfer bytes from/to the device. */
- position= make64(mp->POSITION, mp->HIGHPOS);
- r = (*cdp->cdr_transfer)(mp->m_source, opcode, position, &iovec1, 1,
- mp->USER_ENDPT, mp->FLAGS);
+ return r;
+}
- /* Return the number of bytes transferred or an error code. */
- return(r == OK ? (int) (mp->COUNT - iovec1.iov_size) : r);
+/*===========================================================================*
+ * do_ioctl *
+ *===========================================================================*/
+static int do_ioctl(struct chardriver *cdp, message *m_ptr)
+{
+/* Carry out an I/O control task request. */
+ devminor_t minor;
+ unsigned long request;
+ cp_grant_id_t grant;
+ endpoint_t endpt, user_endpt;
+ int flags;
+ cdev_id_t id;
+
+ /* Default action if no ioctl hook is in place. */
+ if (cdp->cdr_ioctl == NULL)
+ return ENOTTY;
+
+ /* Call the ioctl hook. */
+ minor = m_ptr->DEVICE;
+ request = m_ptr->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;
+
+ return cdp->cdr_ioctl(minor, request, endpt, grant, flags, user_endpt, id);
}
/*===========================================================================*
- * do_vrdwt *
+ * do_cancel *
*===========================================================================*/
-static int do_vrdwt(struct chardriver *cdp, message *mp)
+static int do_cancel(struct chardriver *cdp, message *m_ptr)
{
-/* Carry out an device read or write to/from a vector of user addresses.
- * The "user addresses" are assumed to be safe, i.e. FS transferring to/from
- * its own buffers, so they are not checked.
+/* Cancel a suspended (read, write, ioctl) task request. The original request
+ * may already have finished, in which case no reply should be sent.
*/
- iovec_t iovec[NR_IOREQS];
- phys_bytes iovec_size;
- unsigned nr_req;
- int r, opcode;
- u64_t position;
+ devminor_t minor;
+ endpoint_t endpt;
+ cdev_id_t id;
- nr_req = mp->COUNT; /* Length of I/O vector */
+ /* Default action if no cancel hook is in place: let the request finish. */
+ if (cdp->cdr_cancel == NULL)
+ return EDONTREPLY;
- /* Copy the vector from the caller to kernel space. */
- if (nr_req > NR_IOREQS) nr_req = NR_IOREQS;
- iovec_size = (phys_bytes) (nr_req * sizeof(iovec[0]));
+ /* Call the cancel hook. */
+ minor = m_ptr->DEVICE;
+ endpt = m_ptr->m_source;
+ id = (cdev_id_t) m_ptr->IO_GRANT;
- if (OK != sys_safecopyfrom(mp->m_source, (vir_bytes) mp->IO_GRANT,
- 0, (vir_bytes) iovec, iovec_size)) {
- printf("bad I/O vector by: %d\n", mp->m_source);
- return(EINVAL);
- }
+ return cdp->cdr_cancel(minor, endpt, id);
+}
- /* Prepare for I/O. */
- if ((*cdp->cdr_prepare)(mp->DEVICE) == NULL) return(ENXIO);
+/*===========================================================================*
+ * do_select *
+ *===========================================================================*/
+static int do_select(struct chardriver *cdp, message *m_ptr)
+{
+/* Perform a select query on a minor device. */
+ devminor_t minor;
+ unsigned int ops;
+ endpoint_t endpt;
- /* Transfer bytes from/to the device. */
- opcode = mp->m_type;
- position= make64(mp->POSITION, mp->HIGHPOS);
- r = (*cdp->cdr_transfer)(mp->m_source, opcode, position, iovec, nr_req,
- mp->USER_ENDPT, mp->FLAGS);
+ /* Default action if no select hook is in place. */
+ if (cdp->cdr_select == NULL)
+ return EBADF;
- /* Copy the I/O vector back to the caller. */
- if (OK != sys_safecopyto(mp->m_source, (vir_bytes) mp->IO_GRANT,
- 0, (vir_bytes) iovec, iovec_size)) {
- printf("couldn't return I/O vector: %d\n", mp->m_source);
- return(EINVAL);
- }
+ /* Call the select hook. */
+ minor = m_ptr->DEV_MINOR;
+ ops = m_ptr->DEV_SEL_OPS;
+ endpt = m_ptr->m_source;
- return(r);
+ return cdp->cdr_select(minor, ops, endpt);
}
/*===========================================================================*
- * handle_notify *
+ * do_block_open *
*===========================================================================*/
-static void handle_notify(struct chardriver *cdp, message *m_ptr)
+static void do_block_open(message *m_ptr, int ipc_status)
{
-/* Take care of the notifications (interrupt and clock messages) by calling the
- * appropiate callback functions. Never send a reply.
- */
+/* Reply to a block driver open request stating there is no such device. */
+ message m_reply;
- /* Call the appropriate function for this notification. */
- switch (_ENDPOINT_P(m_ptr->m_source)) {
- case CLOCK:
- if (cdp->cdr_alarm)
- cdp->cdr_alarm(m_ptr);
- break;
+ memset(&m_reply, 0, sizeof(m_reply));
- default:
- if (cdp->cdr_other)
- (void) cdp->cdr_other(m_ptr);
- }
+ m_reply.m_type = BDEV_REPLY;
+ m_reply.BDEV_STATUS = ENXIO;
+ m_reply.BDEV_ID = m_ptr->BDEV_ID;
+
+ send_reply(m_ptr->m_source, &m_reply, ipc_status);
}
/*===========================================================================*
- * handle_request *
+ * chardriver_process *
*===========================================================================*/
-static int handle_request(struct chardriver *cdp, message *m_ptr)
+void chardriver_process(struct chardriver *cdp, message *m_ptr, int ipc_status)
{
-/* Call the appropiate driver function, based on the type of request. Return
- * the result code that is to be sent back to the caller, or EDONTREPLY if no
- * reply is to be sent.
+/* Call the appropiate driver function, based on the type of request. Send a
+ * reply to the caller if necessary.
*/
- int r;
+ int r, reply;
+
+ /* Check for notifications first. We never reply to notifications. */
+ if (is_ipc_notify(ipc_status)) {
+ switch (_ENDPOINT_P(m_ptr->m_source)) {
+ case HARDWARE:
+ if (cdp->cdr_intr)
+ cdp->cdr_intr(m_ptr->NOTIFY_ARG);
+ break;
+
+ case CLOCK:
+ if (cdp->cdr_alarm)
+ cdp->cdr_alarm(m_ptr->NOTIFY_TIMESTAMP);
+ break;
+
+ default:
+ if (cdp->cdr_other)
+ cdp->cdr_other(m_ptr, ipc_status);
+ }
+
+ return; /* do not send a reply */
+ }
+
+ /* Reply to block driver open requests with an error code. Otherwise, if
+ * someone creates a block device node for a character driver, opening that
+ * device node will cause the corresponding VFS thread to block forever.
+ */
+ if (m_ptr->m_type == BDEV_OPEN) {
+ do_block_open(m_ptr, ipc_status);
+
+ return;
+ }
/* We might get spurious requests if the driver has been restarted. Deny any
- * requests on devices that have not previously been opened, signaling the
- * caller that something went wrong.
+ * requests on devices that have not previously been opened.
*/
if (IS_DEV_RQ(m_ptr->m_type) && !is_open_dev(m_ptr->DEVICE)) {
- /* Reply ERESTART to spurious requests for unopened devices. */
- if (m_ptr->m_type != DEV_OPEN)
- return ERESTART;
+ /* Ignore spurious requests for unopened devices. */
+ if (m_ptr->m_type != DEV_OPEN && m_ptr->m_type != DEV_REOPEN)
+ return; /* do not send a reply */
/* Mark the device as opened otherwise. */
set_open_dev(m_ptr->DEVICE);
/* Call the appropriate function(s) for this request. */
switch (m_ptr->m_type) {
- case DEV_OPEN: r = (*cdp->cdr_open)(m_ptr); break;
- case DEV_CLOSE: r = (*cdp->cdr_close)(m_ptr); break;
- case DEV_IOCTL_S: r = (*cdp->cdr_ioctl)(m_ptr); break;
- case CANCEL: r = (*cdp->cdr_cancel)(m_ptr); break;
- case DEV_SELECT: r = (*cdp->cdr_select)(m_ptr); break;
- case DEV_READ_S:
- case DEV_WRITE_S: r = do_rdwt(cdp, m_ptr); break;
- case DEV_GATHER_S:
- case DEV_SCATTER_S: r = do_vrdwt(cdp, m_ptr); break;
+ case DEV_OPEN: r = do_open(cdp, m_ptr, FALSE); break;
+ case DEV_REOPEN: r = do_open(cdp, m_ptr, TRUE); 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;
default:
if (cdp->cdr_other)
- r = cdp->cdr_other(m_ptr);
- else
- r = EINVAL;
+ cdp->cdr_other(m_ptr, ipc_status);
+ return; /* do not send a reply */
}
- /* Let the driver perform any cleanup. */
- if (cdp->cdr_cleanup)
- (*cdp->cdr_cleanup)();
-
- return r;
+ chardriver_reply(m_ptr, ipc_status, r);
}
/*===========================================================================*
- * chardriver_process *
+ * chardriver_terminate *
*===========================================================================*/
-void chardriver_process(struct chardriver *cdp, message *m_ptr, int ipc_status)
+void chardriver_terminate(void)
{
-/* Handle the given received message. */
- int r;
-
- /* Process the notification or request. */
- if (is_ipc_notify(ipc_status)) {
- handle_notify(cdp, m_ptr);
+/* Break out of the main loop after finishing the current request. */
- /* Do not reply to notifications. */
- } else {
- r = handle_request(cdp, m_ptr);
+ running = FALSE;
- send_reply(m_ptr, ipc_status, r);
- }
+ sef_cancel();
}
/*===========================================================================*
* it out, and sends a reply.
*/
while (running) {
- if ((r = sef_receive_status(ANY, &mess, &ipc_status)) != OK)
+ if ((r = sef_receive_status(ANY, &mess, &ipc_status)) != OK) {
+ if (r == EINTR && !running)
+ break;
+
panic("driver_receive failed: %d", r);
+ }
chardriver_process(cdp, &mess, ipc_status);
}
}
-
-/*===========================================================================*
- * do_nop *
- *===========================================================================*/
-int do_nop(message *UNUSED(mp))
-{
- return(OK);
-}
-
-/*===========================================================================*
- * nop_ioctl *
- *===========================================================================*/
-int nop_ioctl(message *UNUSED(mp))
-{
- return(ENOTTY);
-}
-
-/*===========================================================================*
- * nop_alarm *
- *===========================================================================*/
-void nop_alarm(message *UNUSED(mp))
-{
-/* Ignore the leftover alarm. */
-}
-
-/*===========================================================================*
- * nop_cleanup *
- *===========================================================================*/
-void nop_cleanup(void)
-{
-/* Nothing to clean up. */
-}
-
-/*===========================================================================*
- * nop_cancel *
- *===========================================================================*/
-int nop_cancel(message *UNUSED(m))
-{
-/* Nothing to do for cancel. */
- return(OK);
-}
-
-/*===========================================================================*
- * nop_select *
- *===========================================================================*/
-int nop_select(message *UNUSED(m))
-{
-/* Nothing to do for select. */
- return(OK);
-}