Rewrite character driver protocol

As a side effect, remove the clone style, as the normal device style
supports device cloning now.

Change-Id: Ie82d1ef0385514a04a8faa139129a617895780b5
This commit is contained in:
David van Moolenbroek
2014-03-01 09:04:52 +01:00
committed by sambuc
parent 87337273e4
commit 665198b4c2
38 changed files with 515 additions and 661 deletions
-17
View File
@@ -5,23 +5,6 @@
* extra buffer space beside the dma buffer.
* This driver also support sub devices, which can be independently
* opened and closed.
*
* The driver supports the following operations:
*
* m_type DEVICE USER_ENDPT COUNT POSITION ADRRESS
* -----------------------------------------------------------------
* | DEV_OPEN | device | proc nr | | | |
* |-------------+---------+---------+---------+---------+---------|
* | DEV_CLOSE | device | proc nr | | | |
* |-------------+---------+---------+---------+---------+---------|
* | DEV_READ_S | device | proc nr | bytes | | buf ptr |
* |-------------+---------+---------+---------+---------+---------|
* | DEV_WRITE_S | device | proc nr | bytes | | buf ptr |
* |-------------+---------+---------+---------+---------+---------|
* | DEV_IOCTL_S | device | proc nr |func code| | buf ptr |
* |-------------+---------+---------+---------+---------+---------|
* | HARD_INT | | | | | |
* -----------------------------------------------------------------
*
* The file contains one entry point:
*
+4 -4
View File
@@ -369,9 +369,9 @@ static void do_char_open(message *m_ptr, int ipc_status)
memset(&m_reply, 0, sizeof(m_reply));
m_reply.m_type = DEV_OPEN_REPL;
m_reply.REP_ENDPT = m_ptr->USER_ENDPT;
m_reply.REP_STATUS = ENXIO;
m_reply.m_type = CDEV_REPLY;
m_reply.CDEV_STATUS = ENXIO;
m_reply.CDEV_ID = m_ptr->CDEV_ID;
send_reply(m_ptr->m_source, &m_reply, ipc_status);
}
@@ -413,7 +413,7 @@ void blockdriver_process_on_thread(struct blockdriver *bdp, message *m_ptr,
* someone creates a character device node for a block driver, opening that
* device node will cause the corresponding VFS thread to block forever.
*/
if (m_ptr->m_type == DEV_OPEN) {
if (m_ptr->m_type == CDEV_OPEN) {
do_char_open(m_ptr, ipc_status);
return;
+96 -91
View File
@@ -1,27 +1,36 @@
/* This file contains the device independent character driver interface.
*
* The drivers support the following operations (using message format m2):
* Charaxter drivers support the following requests. Message format m10 is
* used. Field names are prefixed with CDEV_. Separate field names are used for
* the "access", "ops", "user", and "request" fields.
*
* m_type DEVICE USER_ENDPT COUNT POSITION HIGHPOS IO_GRANT
* ----------------------------------------------------------------------------
* | DEV_OPEN | device | proc nr | mode | | | |
* |---------------+--------+---------+---------+--------+--------+-----------|
* | DEV_CLOSE | device | proc nr | | | | |
* |---------------+--------+---------+---------+--------+--------+-----------|
* | DEV_READ_S | device | proc nr | bytes | off lo | off hi i buf grant |
* |---------------+--------+---------+---------+--------+--------+-----------|
* | DEV_WRITE_S | device | proc nr | bytes | off lo | off hi | buf grant |
* |---------------+--------+---------+---------+--------+--------+-----------|
* | DEV_GATHER_S | device | proc nr | iov len | off lo | off hi | iov grant |
* |---------------+--------+---------+---------+--------+--------+-----------|
* | DEV_SCATTER_S | device | proc nr | iov len | off lo | off hi | iov grant |
* |---------------+--------+---------+---------+--------+--------+-----------|
* | DEV_IOCTL_S | device | proc nr | request | | | buf grant |
* |---------------+--------+---------+---------+--------+--------+-----------|
* | CANCEL | device | proc nr | r/w | | | grant |
* |---------------+--------+---------+---------+--------+--------+-----------|
* | DEV_SELECT | device | ops | | | | |
* ----------------------------------------------------------------------------
* m_type MINOR GRANT COUNT FLAGS ID POS_LO POS_HI
* +-------------+-------+--------+-------+-------+------+---------+--------+
* | CDEV_OPEN | minor | access | user | | id | | |
* |-------------+-------+--------+-------+-------+------+---------+--------|
* | CDEV_CLOSE | minor | | | | id | | |
* |-------------+-------+--------+-------+-------+------+---------+--------|
* | CDEV_READ | minor | grant | bytes | flags | id | position |
* |-------------+-------+--------+-------+-------+------+---------+--------|
* | CDEV_WRITE | minor | grant | bytes | flags | id | position |
* |-------------+-------+--------+-------+-------+------+---------+--------|
* | CDEV_IOCTL | minor | grant | user | flags | id | request | |
* |-------------+-------+--------+-------+-------+------+---------+--------|
* | CDEV_CANCEL | minor | | | | id | | |
* |-------------+-------+--------+-------+-------+------+---------+--------|
* | CDEV_SELECT | minor | ops | | | | | |
* --------------------------------------------------------------------------
*
* The following reply messages are used.
*
* m_type MINOR STATUS ID
* +-----------------+-------+--------+-----+-----+------+---------+--------+
* | CDEV_REPLY | | status | | | id | | |
* |-----------------+-------+--------+-----+-----+------+---------+--------|
* | CDEV_SEL1_REPLY | minor | status | | | | | |
* |-----------------+-------+--------+-----+-----+------+---------+--------|
* | CDEV_SEL2_REPLY | minor | status | | | | | |
* --------------------------------------------------------------------------
*
* Changes:
* Sep 01, 2013 complete rewrite of the API (D.C. van Moolenboek)
@@ -110,7 +119,7 @@ void chardriver_announce(void)
if ((r = ds_publish_u32(key, DS_DRIVER_UP, DSF_OVERWRITE)) != OK)
panic("chardriver_init: unable to publish driver up event: %d", r);
/* Expect a DEV_OPEN for any device before serving regular driver requests. */
/* Expect an open for any device before serving regular driver requests. */
clear_open_devs();
}
@@ -130,10 +139,9 @@ void chardriver_reply_task(endpoint_t endpt, cdev_id_t id, int 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;
m_reply.m_type = CDEV_REPLY;
m_reply.CDEV_STATUS = r;
m_reply.CDEV_ID = id;
if ((r = asynsend3(endpt, &m_reply, AMF_NOREPLY)) != OK)
printf("chardriver_reply_task: send to %d failed: %d\n", endpt, r);
@@ -155,9 +163,9 @@ void chardriver_reply_select(endpoint_t endpt, devminor_t minor, int r)
memset(&m_reply, 0, sizeof(m_reply));
m_reply.m_type = DEV_SEL_REPL2;
m_reply.DEV_MINOR = minor;
m_reply.DEV_SEL_OPS = r;
m_reply.m_type = CDEV_SEL2_REPLY;
m_reply.CDEV_MINOR = minor;
m_reply.CDEV_STATUS = r;
if ((r = asynsend3(endpt, &m_reply, AMF_NOREPLY)) != OK)
printf("chardriver_reply_select: send to %d failed: %d\n", endpt, r);
@@ -194,15 +202,20 @@ static void chardriver_reply(message *mess, int ipc_status, int r)
*/
if (r == EDONTREPLY) {
switch (mess->m_type) {
case DEV_READ_S:
case DEV_WRITE_S:
case DEV_IOCTL_S:
#if 0 /* XXX doesn't match lwip's model, disabled for now */
if (mess->FLAGS & FLG_OP_NONBLOCK)
case CDEV_READ:
case CDEV_WRITE:
case CDEV_IOCTL:
/* FIXME: we should be able to check CDEV_FLAGS against
* CDEV_NONBLOCK here, but in practice, several drivers do not
* send a reply through this path (eg TTY) or simply do not
* implement nonblocking calls properly (eg audio, LWIP).
*/
#if 0
if (mess->CDEV_FLAGS & CDEV_NONBLOCK)
panic("chardriver: cannot suspend nonblocking I/O");
#endif
/*fall-through*/
case CANCEL:
case CDEV_CANCEL:
return; /* alright */
default:
panic("chardriver: cannot suspend request %d", mess->m_type);
@@ -222,32 +235,21 @@ static void chardriver_reply(message *mess, int ipc_status, int r)
memset(&reply_mess, 0, sizeof(reply_mess));
switch (mess->m_type) {
case DEV_OPEN:
reply_mess.m_type = DEV_OPEN_REPL;
reply_mess.REP_ENDPT = mess->USER_ENDPT;
reply_mess.REP_STATUS = r;
case CDEV_OPEN:
case CDEV_CLOSE:
case CDEV_READ:
case CDEV_WRITE:
case CDEV_IOCTL:
case CDEV_CANCEL: /* For cancel, this is a reply to the original request! */
reply_mess.m_type = CDEV_REPLY;
reply_mess.CDEV_STATUS = r;
reply_mess.CDEV_ID = mess->CDEV_ID;
break;
case DEV_CLOSE:
reply_mess.m_type = DEV_CLOSE_REPL;
reply_mess.REP_ENDPT = mess->USER_ENDPT;
reply_mess.REP_STATUS = r;
break;
case DEV_READ_S:
case DEV_WRITE_S:
case DEV_IOCTL_S:
case CANCEL: /* For CANCEL, this is a reply to the original request! */
reply_mess.m_type = DEV_REVIVE;
reply_mess.REP_ENDPT = mess->USER_ENDPT;
reply_mess.REP_IO_GRANT = (cp_grant_id_t) mess->IO_GRANT;
reply_mess.REP_STATUS = r;
break;
case DEV_SELECT:
reply_mess.m_type = DEV_SEL_REPL1;
reply_mess.DEV_MINOR = mess->DEVICE;
reply_mess.DEV_SEL_OPS = r;
case CDEV_SELECT:
reply_mess.m_type = CDEV_SEL1_REPLY;
reply_mess.CDEV_MINOR = mess->CDEV_MINOR;
reply_mess.CDEV_STATUS = r;
break;
default:
@@ -272,15 +274,18 @@ static int do_open(struct chardriver *cdp, message *m_ptr)
return OK;
/* Call the open hook. */
minor = m_ptr->DEVICE;
access = m_ptr->COUNT;
user_endpt = m_ptr->USER_ENDPT;
minor = m_ptr->CDEV_MINOR;
access = m_ptr->CDEV_ACCESS;
user_endpt = m_ptr->CDEV_USER;
r = cdp->cdr_open(minor, access, user_endpt);
/* If the device has been cloned, mark the new minor as open too. */
if (r >= 0 && !is_open_dev(r)) /* XXX FIXME */
set_open_dev(r);
if (r >= 0 && (r & CDEV_CLONED)) {
minor = r & ~(CDEV_CLONED | CDEV_CTTY);
if (!is_open_dev(minor))
set_open_dev(minor);
}
return r;
}
@@ -298,7 +303,7 @@ static int do_close(struct chardriver *cdp, message *m_ptr)
return OK;
/* Call the close hook. */
minor = m_ptr->DEVICE;
minor = m_ptr->CDEV_MINOR;
return cdp->cdr_close(minor);
}
@@ -318,13 +323,13 @@ static int do_transfer(struct chardriver *cdp, message *m_ptr, int do_write)
cdev_id_t id;
ssize_t r;
minor = m_ptr->DEVICE;
position = make64(m_ptr->POSITION, m_ptr->HIGHPOS);
minor = m_ptr->CDEV_MINOR;
position = make64(m_ptr->CDEV_POS_LO, m_ptr->CDEV_POS_HI);
endpt = m_ptr->m_source;
grant = (cp_grant_id_t) m_ptr->IO_GRANT;
size = m_ptr->COUNT;
flags = m_ptr->FLAGS;
id = (cdev_id_t) m_ptr->IO_GRANT;
grant = (cp_grant_id_t) m_ptr->CDEV_GRANT;
size = m_ptr->CDEV_COUNT;
flags = m_ptr->CDEV_FLAGS;
id = m_ptr->CDEV_ID;
/* Call the read/write hook, if the appropriate one is in place. */
if (!do_write && cdp->cdr_read != NULL)
@@ -355,13 +360,13 @@ static int do_ioctl(struct chardriver *cdp, message *m_ptr)
return ENOTTY;
/* Call the ioctl hook. */
minor = m_ptr->DEVICE;
request = m_ptr->REQUEST;
minor = m_ptr->CDEV_MINOR;
request = m_ptr->CDEV_REQUEST;
endpt = m_ptr->m_source;
grant = (cp_grant_id_t) m_ptr->IO_GRANT;
flags = m_ptr->FLAGS;
user_endpt = (endpoint_t) m_ptr->POSITION;
id = (cdev_id_t) m_ptr->IO_GRANT;
grant = m_ptr->CDEV_GRANT;
flags = m_ptr->CDEV_FLAGS;
user_endpt = m_ptr->CDEV_USER;
id = m_ptr->CDEV_ID;
return cdp->cdr_ioctl(minor, request, endpt, grant, flags, user_endpt, id);
}
@@ -383,9 +388,9 @@ static int do_cancel(struct chardriver *cdp, message *m_ptr)
return EDONTREPLY;
/* Call the cancel hook. */
minor = m_ptr->DEVICE;
minor = m_ptr->CDEV_MINOR;
endpt = m_ptr->m_source;
id = (cdev_id_t) m_ptr->IO_GRANT;
id = m_ptr->CDEV_ID;
return cdp->cdr_cancel(minor, endpt, id);
}
@@ -405,8 +410,8 @@ static int do_select(struct chardriver *cdp, message *m_ptr)
return EBADF;
/* Call the select hook. */
minor = m_ptr->DEV_MINOR;
ops = m_ptr->DEV_SEL_OPS;
minor = m_ptr->CDEV_MINOR;
ops = m_ptr->CDEV_OPS;
endpt = m_ptr->m_source;
return cdp->cdr_select(minor, ops, endpt);
@@ -473,24 +478,24 @@ void chardriver_process(struct chardriver *cdp, message *m_ptr, int ipc_status)
/* We might get spurious requests if the driver has been restarted. Deny any
* requests on devices that have not previously been opened.
*/
if (IS_DEV_RQ(m_ptr->m_type) && !is_open_dev(m_ptr->DEVICE)) {
if (IS_CDEV_RQ(m_ptr->m_type) && !is_open_dev(m_ptr->CDEV_MINOR)) {
/* Ignore spurious requests for unopened devices. */
if (m_ptr->m_type != DEV_OPEN)
if (m_ptr->m_type != CDEV_OPEN)
return; /* do not send a reply */
/* Mark the device as opened otherwise. */
set_open_dev(m_ptr->DEVICE);
set_open_dev(m_ptr->CDEV_MINOR);
}
/* Call the appropriate function(s) for this request. */
switch (m_ptr->m_type) {
case DEV_OPEN: r = do_open(cdp, m_ptr); break;
case DEV_CLOSE: r = do_close(cdp, m_ptr); break;
case DEV_READ_S: r = do_transfer(cdp, m_ptr, FALSE); break;
case DEV_WRITE_S: r = do_transfer(cdp, m_ptr, TRUE); break;
case DEV_IOCTL_S: r = do_ioctl(cdp, m_ptr); break;
case CANCEL: r = do_cancel(cdp, m_ptr); break;
case DEV_SELECT: r = do_select(cdp, m_ptr); break;
case CDEV_OPEN: r = do_open(cdp, m_ptr); break;
case CDEV_CLOSE: r = do_close(cdp, m_ptr); break;
case CDEV_READ: r = do_transfer(cdp, m_ptr, FALSE); break;
case CDEV_WRITE: r = do_transfer(cdp, m_ptr, TRUE); break;
case CDEV_IOCTL: r = do_ioctl(cdp, m_ptr); break;
case CDEV_CANCEL: r = do_cancel(cdp, m_ptr); break;
case CDEV_SELECT: r = do_select(cdp, m_ptr); break;
default:
if (cdp->cdr_other)
cdp->cdr_other(m_ptr, ipc_status);
+17 -12
View File
@@ -261,7 +261,7 @@ struct socket * get_unused_sock(void)
static int socket_request_socket(struct socket * sock, struct sock_req * req)
{
int r, blocking = req->flags & FLG_OP_NONBLOCK ? 0 : 1;
int r, blocking = (req->flags & CDEV_NONBLOCK) ? 0 : 1;
switch (req->type) {
case SOCK_REQ_READ:
@@ -292,7 +292,12 @@ static int socket_request_socket(struct socket * sock, struct sock_req * req)
static int netsock_open(devminor_t minor, int UNUSED(access),
endpoint_t UNUSED(user_endpt))
{
return socket_open(minor);
int r;
if ((r = socket_open(minor)) < 0)
return r;
return CDEV_CLONED | r;
}
static int netsock_close(devminor_t minor)
@@ -505,26 +510,26 @@ int generic_op_select(struct socket * sock, unsigned int sel)
/* in this case any operation would block, no error */
if (sock->flags & SOCK_FLG_OP_PENDING) {
if (sel & SEL_NOTIFY) {
if (sel & SEL_RD)
if (sel & CDEV_NOTIFY) {
if (sel & CDEV_OP_RD)
sock->flags |= SOCK_FLG_SEL_READ;
if (sel & SEL_WR)
if (sel & CDEV_OP_WR)
sock->flags |= SOCK_FLG_SEL_WRITE;
/* FIXME we do not monitor error */
}
return 0;
}
if (sel & SEL_RD) {
if (sel & CDEV_OP_RD) {
if (sock->recv_head)
retsel |= SEL_RD;
else if (sel & SEL_NOTIFY)
retsel |= CDEV_OP_RD;
else if (sel & CDEV_NOTIFY)
sock->flags |= SOCK_FLG_SEL_READ;
}
/* FIXME generic packet socket never blocks on write */
if (sel & SEL_WR)
retsel |= SEL_WR;
/* FIXME SEL_ERR is ignored, we do not generate exceptions */
if (sel & CDEV_OP_WR)
retsel |= CDEV_OP_WR;
/* FIXME CDEV_OP_ERR is ignored, we do not generate exceptions */
return retsel;
}
@@ -545,7 +550,7 @@ int generic_op_select_reply(struct socket * sock)
}
if (sock->flags & SOCK_FLG_SEL_READ && sock->recv_head)
sel |= SEL_RD;
sel |= CDEV_OP_RD;
if (sel)
sock->flags &= ~(SOCK_FLG_SEL_WRITE | SOCK_FLG_SEL_READ |