minix/drivers/hello/hello.c
David van Moolenbroek 597151d963 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
2014-03-01 09:04:50 +01:00

163 lines
4.1 KiB
C

#include <minix/drivers.h>
#include <minix/chardriver.h>
#include <stdio.h>
#include <stdlib.h>
#include <minix/ds.h>
#include "hello.h"
/*
* Function prototypes for the hello driver.
*/
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);
static int sef_cb_init(int type, sef_init_info_t *info);
static int sef_cb_lu_state_save(int);
static int lu_state_restore(void);
/* Entry points to the hello driver. */
static struct chardriver hello_tab =
{
.cdr_open = hello_open,
.cdr_close = hello_close,
.cdr_read = hello_read,
};
/** 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(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(devminor_t UNUSED(minor))
{
printf("hello_close()\n");
return OK;
}
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))
{
u64_t dev_size;
char *ptr;
int ret;
printf("hello_read()\n");
/* This is the total size of our device. */
dev_size = (u64_t) strlen(HELLO_MESSAGE);
/* 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 */
/* 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;
/* Return the number of bytes read. */
return size;
}
static int sef_cb_lu_state_save(int UNUSED(state)) {
/* Save the state. */
ds_publish_u32("open_counter", open_counter, DSF_OVERWRITE);
return OK;
}
static int lu_state_restore() {
/* Restore the state. */
u32_t value;
ds_retrieve_u32("open_counter", &value);
ds_delete_u32("open_counter");
open_counter = (int) value;
return OK;
}
static void sef_local_startup()
{
/*
* Register init callbacks. Use the same function for all event types
*/
sef_setcb_init_fresh(sef_cb_init);
sef_setcb_init_lu(sef_cb_init);
sef_setcb_init_restart(sef_cb_init);
/*
* Register live update callbacks.
*/
/* - Agree to update immediately when LU is requested in a valid state. */
sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready);
/* - Support live update starting from any standard state. */
sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_standard);
/* - Register a custom routine to save the state. */
sef_setcb_lu_state_save(sef_cb_lu_state_save);
/* Let SEF perform startup. */
sef_startup();
}
static int sef_cb_init(int type, sef_init_info_t *UNUSED(info))
{
/* Initialize the hello driver. */
int do_announce_driver = TRUE;
open_counter = 0;
switch(type) {
case SEF_INIT_FRESH:
printf("%s", HELLO_MESSAGE);
break;
case SEF_INIT_LU:
/* Restore the state. */
lu_state_restore();
do_announce_driver = FALSE;
printf("%sHey, I'm a new version!\n", HELLO_MESSAGE);
break;
case SEF_INIT_RESTART:
printf("%sHey, I've just been restarted!\n", HELLO_MESSAGE);
break;
}
/* Announce we are up when necessary. */
if (do_announce_driver) {
chardriver_announce();
}
/* Initialization completed successfully. */
return OK;
}
int main(void)
{
/*
* Perform initialization.
*/
sef_local_startup();
/*
* Run the main loop.
*/
chardriver_task(&hello_tab);
return OK;
}