From: David van Moolenbroek Date: Mon, 2 Sep 2013 23:49:38 +0000 (+0200) Subject: libchardriver: full API rewrite X-Git-Tag: v3.3.0~588 X-Git-Url: http://zhaoyanbai.com/repos/%22http:/www.isc.org/icons/zlib_tech.html?a=commitdiff_plain;h=597151d9634e6bd7808674489a8ed96176b4e9b9;p=minix.git libchardriver: full API rewrite The new API now covers the entire character driver protocol, while hiding all the message details. It should therefore be used by all new character drivers. All existing drivers that already made use of libchardriver have been changed to use the new API. As one of the most important API changes, support for scatter and gather transfers has been removed, as several key drivers already did not support this, and it could be supported at the safecopy level instead (for a future readv/writev). Additional changes include: - respond to block device open requests to avoid hanging VFS threads; - add support for sef_cancel. Change-Id: I1bab6c1cb66916c71b87aeb1db54a9bdf171fe6b --- diff --git a/drivers/bmp085/bmp085.c b/drivers/bmp085/bmp085.c index bbc46b49d..7782fbf25 100644 --- a/drivers/bmp085/bmp085.c +++ b/drivers/bmp085/bmp085.c @@ -151,11 +151,9 @@ static int read_cal_coef(void); 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); @@ -165,21 +163,8 @@ static void sef_local_startup(void); /* 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 }; /* @@ -438,18 +423,12 @@ measure(int32_t * temperature, int32_t * pressure) 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); @@ -464,48 +443,33 @@ bmp085_transfer(endpoint_t endpt, int opcode, u64_t position, 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 diff --git a/drivers/fb/arch/earm/fb_arch.c b/drivers/fb/arch/earm/fb_arch.c index d324ed16a..6e3e58a1c 100644 --- a/drivers/fb/arch/earm/fb_arch.c +++ b/drivers/fb/arch/earm/fb_arch.c @@ -312,7 +312,7 @@ arch_pan_display(int minor, struct fb_var_screeninfo *fbvsp) } 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; @@ -320,13 +320,9 @@ arch_fb_init(int minor, struct device *dev, struct edid_info *info) 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"); @@ -403,8 +399,6 @@ arch_fb_init(int minor, struct device *dev, struct edid_info *info) 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); diff --git a/drivers/fb/fb.c b/drivers/fb/fb.c index 07038006b..d8d271d33 100644 --- a/drivers/fb/fb.c +++ b/drivers/fb/fb.c @@ -23,17 +23,14 @@ /* * 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); @@ -52,143 +49,90 @@ static int lu_state_restore(void); /* 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: @@ -205,7 +149,7 @@ fb_ioctl(message *m) return r; } - return EINVAL; + return ENOTTY; } static int @@ -270,34 +214,29 @@ do_get_fixscreeninfo(int minor, endpoint_t ep, cp_grant_id_t gid) 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 diff --git a/drivers/fb/fb.h b/drivers/fb/fb.h index cf9da112d..1eba57fae 100644 --- a/drivers/fb/fb.h +++ b/drivers/fb/fb.h @@ -3,7 +3,7 @@ #include -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); diff --git a/drivers/hello/hello.c b/drivers/hello/hello.c index fb1b4acf0..6eae09998 100644 --- a/drivers/hello/hello.c +++ b/drivers/hello/hello.c @@ -8,12 +8,10 @@ /* * 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); @@ -24,77 +22,54 @@ static int lu_state_restore(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)) { diff --git a/drivers/i2c/i2c.c b/drivers/i2c/i2c.c index 23a41a3a1..264407526 100644 --- a/drivers/i2c/i2c.c +++ b/drivers/i2c/i2c.c @@ -39,11 +39,9 @@ static int do_i2c_ioctl_exec(endpoint_t caller, cp_grant_id_t grant_nr); 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); @@ -69,8 +67,6 @@ static struct i2cdev */ 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", @@ -82,16 +78,8 @@ static struct log log = { * 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 }; /* @@ -233,14 +221,14 @@ validate_ioctl_exec(minix_i2c_ioctl_exec_t * ioctl_exec) } 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; @@ -298,30 +286,40 @@ do_i2c_ioctl_exec(endpoint_t caller, cp_grant_id_t grant_nr) 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 */ @@ -331,12 +329,6 @@ i2c_other(message * m) /* 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; @@ -345,32 +337,12 @@ i2c_other(message * m) 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; } /* diff --git a/drivers/log/log.c b/drivers/log/log.c index 7c6cbf228..67c466053 100644 --- a/drivers/log/log.c +++ b/drivers/log/log.c @@ -19,31 +19,24 @@ #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. */ @@ -100,15 +93,10 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info)) /* 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); @@ -125,29 +113,24 @@ static void sef_cb_signal_handler(int signo) 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; @@ -155,75 +138,49 @@ subwrite(struct logdevice *log, int count, endpoint_t endpt, 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; } /*===========================================================================* @@ -232,189 +189,156 @@ subwrite(struct logdevice *log, int count, endpoint_t endpt, 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 @@ -426,4 +350,3 @@ static int log_select(message *m_ptr) return(ready_ops); } - diff --git a/drivers/log/log.h b/drivers/log/log.h index 98129c2d8..a4170aaba 100644 --- a/drivers/log/log.h +++ b/drivers/log/log.h @@ -10,24 +10,18 @@ /* 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. */ diff --git a/drivers/memory/memory.c b/drivers/memory/memory.c index ec9cf5e63..77f1c8953 100644 --- a/drivers/memory/memory.c +++ b/drivers/memory/memory.c @@ -41,19 +41,18 @@ 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); @@ -62,16 +61,10 @@ static int m_block_ioctl(devminor_t minor, unsigned long request, endpoint_t /* 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. */ @@ -84,14 +77,10 @@ static struct blockdriver m_bdtab = { .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 * *===========================================================================*/ @@ -151,8 +140,8 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info)) } /* 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."); @@ -160,16 +149,16 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info)) #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. */ @@ -196,206 +185,218 @@ static int m_is_block(devminor_t minor) } /*===========================================================================* - * 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); } @@ -417,7 +418,7 @@ static struct device *m_block_part(devminor_t minor) 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 */ @@ -430,7 +431,6 @@ static int m_block_transfer( 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; @@ -440,9 +440,8 @@ static int m_block_transfer( 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) { @@ -547,7 +546,7 @@ static int m_block_ioctl(devminor_t minor, unsigned long request, 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(). */ @@ -595,7 +594,7 @@ static int m_block_ioctl(devminor_t minor, unsigned long request, m_vaddrs[minor] = (vir_bytes) mem; - dv->dv_size = ((u64_t)(ramdev_size)); + dv->dv_size = ramdev_size; return(OK); } diff --git a/drivers/random/main.c b/drivers/random/main.c index fb152b498..1ded6f37e 100644 --- a/drivers/random/main.c +++ b/drivers/random/main.c @@ -21,25 +21,20 @@ static dev_t m_device; /* current device */ 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. */ @@ -92,7 +87,7 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info)) 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))) { @@ -120,103 +115,71 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info)) } /*===========================================================================* - * 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); } @@ -265,7 +228,7 @@ static void r_updatebin(int source, struct k_randomness_bin *rb) /*===========================================================================* * 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; diff --git a/drivers/sht21/sht21.c b/drivers/sht21/sht21.c index 78cf3971f..c6f585c43 100644 --- a/drivers/sht21/sht21.c +++ b/drivers/sht21/sht21.c @@ -114,11 +114,9 @@ static uint8_t crc8(uint8_t crc, uint8_t byte); 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); @@ -128,21 +126,8 @@ static void sef_local_startup(void); /* 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 }; /* @@ -342,17 +327,11 @@ checksum(uint8_t * bytes, int nbytes, uint8_t expected_crc) } } -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(); @@ -367,48 +346,33 @@ sht21_transfer(endpoint_t endpt, int opcode, u64_t position, 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 diff --git a/drivers/tsl2550/tsl2550.c b/drivers/tsl2550/tsl2550.c index 8c6f6c794..82637b2ba 100644 --- a/drivers/tsl2550/tsl2550.c +++ b/drivers/tsl2550/tsl2550.c @@ -65,11 +65,9 @@ static int adc_read(int adc, uint8_t * val); 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); @@ -79,21 +77,8 @@ static void sef_local_startup(void); /* 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 }; /* @@ -294,17 +279,11 @@ tsl2550_init(void) 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; @@ -316,48 +295,33 @@ tsl2550_transfer(endpoint_t endpt, int opcode, u64_t position, 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 diff --git a/include/minix/chardriver.h b/include/minix/chardriver.h index c2146d1a8..880ab824b 100644 --- a/include/minix/chardriver.h +++ b/include/minix/chardriver.h @@ -3,20 +3,23 @@ #include +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. */ @@ -26,11 +29,7 @@ void chardriver_process(struct chardriver *cdp, message *m_ptr, 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 */ diff --git a/lib/libchardriver/chardriver.c b/lib/libchardriver/chardriver.c index 178ff1394..4e723e6e1 100644 --- a/lib/libchardriver/chardriver.c +++ b/lib/libchardriver/chardriver.c @@ -23,12 +23,9 @@ * | 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) @@ -44,7 +41,7 @@ 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; /*===========================================================================* @@ -59,13 +56,13 @@ static void clear_open_devs(void) /*===========================================================================* * 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; @@ -74,14 +71,14 @@ static int is_open_dev(int device) /*===========================================================================* * 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++; } @@ -117,16 +114,103 @@ void chardriver_announce(void) 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 @@ -144,6 +228,12 @@ static void send_reply(message *mess, int ipc_status, int r) 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; @@ -153,20 +243,13 @@ static void send_reply(message *mess, int ipc_status, int r) 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; @@ -174,145 +257,232 @@ static void send_reply(message *mess, int ipc_status, int r) 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); @@ -320,47 +490,33 @@ static int handle_request(struct chardriver *cdp, message *m_ptr) /* 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(); } /*===========================================================================* @@ -378,59 +534,13 @@ void chardriver_task(struct chardriver *cdp) * 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); -}