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)) +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)) { - 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)) -{ - 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; + 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; - } + r = sys_safecopyto(endpt, grant, 0, + (vir_bytes)(buffer + (size_t)position), size); - 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; - } - - 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; + + if (minor < 0 || minor >= FB_DEV_NR) return ENXIO; + assert(open_counter[minor] > 0); arch_get_device(minor, &dev); - if (pos >= dev.dv_size) return EINVAL; + if (size == 0 || pos >= dev.dv_size) return 0; + if (pos + size > dev.dv_size) + size = (size_t)(dev.dv_size - pos); - if (dev.dv_size - pos < iov->iov_size) { - *io_bytes = dev.dv_size - pos; - } else { - *io_bytes = iov->iov_size; - } + r = sys_safecopyto(ep, gid, 0, (vir_bytes)(dev.dv_base + (size_t)pos), + size); - if (*io_bytes <= 0) { - return OK; - } - - 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; + + if (minor < 0 || minor >= FB_DEV_NR) return ENXIO; + assert(open_counter[minor] > 0); + + if (has_restarted && keep_displaying_restarted()) + return EAGAIN; arch_get_device(minor, &dev); - if (pos >= dev.dv_size) { - return EINVAL; - } + if (size == 0 || pos >= dev.dv_size) return 0; + if (pos + size > dev.dv_size) + size = (size_t)(dev.dv_size - pos); - if (dev.dv_size - pos < iov->iov_size) { - *io_bytes = dev.dv_size - pos; - } else { - *io_bytes = iov->iov_size; - } + r = sys_safecopyfrom(ep, gid, 0, + (vir_bytes)(dev.dv_base + (size_t)pos), size); - if (*io_bytes <= 0) { - return OK; - } - - if (has_restarted && keep_displaying_restarted()) { - return EAGAIN; - } - - 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); + r = offset; /* this will be the return value upon success */ + } - 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_source != NONE) { + /* Someone who was suspended on read can now be revived. */ + r = subread(log, log->log_iosize, log->log_source, log->log_grant); - if(log->log_size > 0) - log->log_select_ready_ops |= SEL_RD; + chardriver_reply_task(log->log_source, log->log_id, r); - 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; + 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; - } - } + chardriver_reply_select(log->log_select_proc, minor, SEL_RD); + log->log_selected &= ~SEL_RD; + } - return count; + 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; + int 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(count < 1) return; + if(count > LOG_SIZE) skip = count - LOG_SIZE; + count -= skip; + buf += skip; - if(w > 0 && w < count) - subwrite(&logdevices[0], count-w, SELF, GRANT_INVALID, 0, - buf + w); - return; + 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; + int r; - if(log_device < 0 || log_device >= NR_DEVS) - return EIO; + if (minor < 0 || minor >= NR_DEVS) return EIO; + log = &logdevices[minor]; - /* Get minor device number and check for /dev/null. */ - log = &logdevices[log_device]; + /* If there's already someone hanging to read, don't accept new work. */ + if (log->log_source != NONE) return OK; - while (nr_req > 0) { - /* How much to transfer and where to / from. */ - count = iov->iov_size; - grant = iov->iov_addr; + if (!log->log_size && size > 0) { + if (flags & FLG_OP_NONBLOCK) return EAGAIN; - 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; + /* 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) + + /* 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; - if ((cp_grant_id_t) m_ptr->IO_GRANT != logdevices[d].log_user_grant) - 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; - ops = m_ptr->DEV_SEL_OPS & (SEL_RD|SEL_WR|SEL_ERR); + if (minor < 0 || minor >= NR_DEVS) + return ENXIO; + + 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; + if (want_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; + /* 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; - - return(&m_geom[device]); -} - -/*===========================================================================* - * m_transfer * - *===========================================================================*/ -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) -) -{ -/* Read or write one the driver's character devices. */ - unsigned count; - vir_bytes vir_offset = 0; - struct device *dv; - 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; - - /* 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]; - - 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) { - - /* No copying; ignore request. */ - case NULL_DEV: - if (opcode == DEV_GATHER_S) return(OK); /* always at EOF */ - break; - - /* 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"); - 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; - - break; - - } - - /* Book the number of bytes transferred. */ - position += count; - vir_offset += count; - if ((iov->iov_size -= count) == 0) { iov++; nr_req--; vir_offset = 0; } - - } - return(OK); -} - -/*===========================================================================* - * m_do_open * - *===========================================================================*/ -static int m_do_open(message *m_ptr) -{ -/* Open a memory character device. */ +/* Transfer from or to the KMEM device. */ + u64_t dv_size, dev_vaddr; int r; -/* Check device number on open. */ - if (m_prepare(m_ptr->DEVICE) == NULL) return(ENXIO); + dv_size = m_geom[minor].dv_size; + dev_vaddr = m_vaddrs[minor]; + + 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_mem * + *===========================================================================*/ +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) +{ +/* 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 r; + + 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; + + /* 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; + + page_off = (size_t) (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) { + printf("memory: vm_map_phys failed\n"); + return ENOMEM; + } + any_mapped = 1; + pagestart_mapped = pagestart; + } + + /* how much to be done within this page. */ + subcount = PAGE_SIZE - page_off; + if (subcount > size) + subcount = size; + + 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; + + position += subcount; + off += subcount; + } + + 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; + + /* 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 r; +} + +/*===========================================================================* + * m_char_write * + *===========================================================================*/ +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. */ + + /* 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. */ - - if (device >= NR_DEVS) return(NULL); - m_device = device; - - return(&m_geom[device]); -} - -/*===========================================================================* - * r_transfer * - *===========================================================================*/ -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) -) -{ -/* Read or write one the driver's minor devices. */ - unsigned count, left, chunk; - cp_grant_id_t grant; - struct device *dv; +/* Read from 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]; + if (minor != RANDOM_DEV) return(EIO); - while (nr_req > 0) { + if (!random_isseeded()) return(EAGAIN); - /* 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); + 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; } - - /* Book the number of bytes transferred. */ - position += count; - if ((iov->iov_size -= count) == 0) { iov++; nr_req--; vir_offset = 0; } - } - return(OK); + + return size; } /*===========================================================================* - * r_do_open * + * r_write * *===========================================================================*/ -static int r_do_open(message *m_ptr) +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)) +{ +/* Write to one of the driver's minor devices. */ + size_t offset, chunk; + int r; + + 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 size; +} + +/*===========================================================================* + * r_open * + *===========================================================================*/ +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; + 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; - } + r = sys_safecopyto(endpt, grant, 0, + (vir_bytes)(buffer + (size_t)position), size); - 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; - } - - 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; - } + r = sys_safecopyto(endpt, grant, 0, + (vir_bytes)(buffer + (size_t)position), size); - 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; - } - - 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,193 +257,266 @@ 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); - - if (r != OK) - printf("send_reply: unable to send reply to %d: %d\n", - mess->m_source, r); + send_reply(mess->m_source, &reply_mess, ipc_status); } /*===========================================================================* - * do_rdwt * + * do_open * *===========================================================================*/ -static int do_rdwt(struct chardriver *cdp, message *mp) +static int do_open(struct chardriver *cdp, message *m_ptr, int is_reopen) { -/* Carry out a single read or write request. */ - iovec_t iovec1; - int r, opcode; - u64_t position; +/* Open a minor device. */ + endpoint_t user_endpt; + devminor_t minor; + int r, access; - /* Disk address? Address and length of the user buffer? */ - if (mp->COUNT < 0) return(EINVAL); + /* Default action if no open hook is in place. */ + if (cdp->cdr_open == NULL) + return OK; - /* Prepare for I/O. */ - if ((*cdp->cdr_prepare)(mp->DEVICE) == NULL) return(ENXIO); + /* Call the open hook. */ + minor = m_ptr->DEVICE; + access = m_ptr->COUNT; + user_endpt = is_reopen ? NONE : m_ptr->USER_ENDPT; /* XXX FIXME */ - /* 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; + r = cdp->cdr_open(minor, access, user_endpt); - iovec1.iov_addr = (vir_bytes) mp->IO_GRANT; - iovec1.iov_size = mp->COUNT; - - /* 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 the number of bytes transferred or an error code. */ - return(r == OK ? (int) (mp->COUNT - iovec1.iov_size) : r); -} - -/*===========================================================================* - * do_vrdwt * - *===========================================================================*/ -static int do_vrdwt(struct chardriver *cdp, message *mp) -{ -/* 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. - */ - iovec_t iovec[NR_IOREQS]; - phys_bytes iovec_size; - unsigned nr_req; - int r, opcode; - u64_t position; - - nr_req = mp->COUNT; /* Length of I/O vector */ - - /* 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])); - - 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); - } - - /* Prepare for I/O. */ - if ((*cdp->cdr_prepare)(mp->DEVICE) == NULL) return(ENXIO); - - /* 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); - - /* 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); - } - - return(r); -} - -/*===========================================================================* - * handle_notify * - *===========================================================================*/ -static void handle_notify(struct chardriver *cdp, message *m_ptr) -{ -/* Take care of the notifications (interrupt and clock messages) by calling the - * appropiate callback functions. Never send a 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; - - default: - if (cdp->cdr_other) - (void) cdp->cdr_other(m_ptr); - } -} - -/*===========================================================================* - * handle_request * - *===========================================================================*/ -static int handle_request(struct chardriver *cdp, message *m_ptr) -{ -/* 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. - */ - int r; - - /* 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. - */ - 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; - - /* 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; - default: - if (cdp->cdr_other) - r = cdp->cdr_other(m_ptr); - else - r = EINVAL; - } - - /* Let the driver perform any cleanup. */ - if (cdp->cdr_cleanup) - (*cdp->cdr_cleanup)(); + /* 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_close * + *===========================================================================*/ +static int do_close(struct chardriver *cdp, message *m_ptr) +{ +/* Close a minor device. */ + devminor_t minor; + + /* Default action if no close hook is in place. */ + if (cdp->cdr_close == NULL) + return OK; + + /* Call the close hook. */ + minor = m_ptr->DEVICE; + + return cdp->cdr_close(minor); +} + +/*===========================================================================* + * 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. */ + + return 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_cancel * + *===========================================================================*/ +static int do_cancel(struct chardriver *cdp, message *m_ptr) +{ +/* Cancel a suspended (read, write, ioctl) task request. The original request + * may already have finished, in which case no reply should be sent. + */ + devminor_t minor; + endpoint_t endpt; + cdev_id_t id; + + /* Default action if no cancel hook is in place: let the request finish. */ + if (cdp->cdr_cancel == NULL) + return EDONTREPLY; + + /* Call the cancel hook. */ + minor = m_ptr->DEVICE; + endpt = m_ptr->m_source; + id = (cdev_id_t) m_ptr->IO_GRANT; + + return cdp->cdr_cancel(minor, endpt, id); +} + +/*===========================================================================* + * 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; + + /* Default action if no select hook is in place. */ + if (cdp->cdr_select == NULL) + return EBADF; + + /* Call the select hook. */ + minor = m_ptr->DEV_MINOR; + ops = m_ptr->DEV_SEL_OPS; + endpt = m_ptr->m_source; + + return cdp->cdr_select(minor, ops, endpt); +} + +/*===========================================================================* + * do_block_open * + *===========================================================================*/ +static void do_block_open(message *m_ptr, int ipc_status) +{ +/* Reply to a block driver open request stating there is no such device. */ + message m_reply; + + memset(&m_reply, 0, sizeof(m_reply)); + + 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); +} + /*===========================================================================* * chardriver_process * *===========================================================================*/ void chardriver_process(struct chardriver *cdp, message *m_ptr, int ipc_status) { -/* Handle the given received message. */ - int r; +/* Call the appropiate driver function, based on the type of request. Send a + * reply to the caller if necessary. + */ + int r, reply; - /* Process the notification or request. */ + /* Check for notifications first. We never reply to notifications. */ if (is_ipc_notify(ipc_status)) { - handle_notify(cdp, m_ptr); + switch (_ENDPOINT_P(m_ptr->m_source)) { + case HARDWARE: + if (cdp->cdr_intr) + cdp->cdr_intr(m_ptr->NOTIFY_ARG); + break; - /* Do not reply to notifications. */ - } else { - r = handle_request(cdp, m_ptr); + case CLOCK: + if (cdp->cdr_alarm) + cdp->cdr_alarm(m_ptr->NOTIFY_TIMESTAMP); + break; - send_reply(m_ptr, ipc_status, r); + 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. + */ + if (IS_DEV_RQ(m_ptr->m_type) && !is_open_dev(m_ptr->DEVICE)) { + /* 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 = 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) + cdp->cdr_other(m_ptr, ipc_status); + return; /* do not send a reply */ + } + + chardriver_reply(m_ptr, ipc_status, r); +} + +/*===========================================================================* + * chardriver_terminate * + *===========================================================================*/ +void chardriver_terminate(void) +{ +/* Break out of the main loop after finishing the current request. */ + + running = FALSE; + + 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); -}